1
0

Streamline player abilities handling

* Update player list gamemode on world change
* Fix invisibility for spectators, use entity metadata
* Populate m_World for cPlayers on load
- Remove SendPlayerMaxSpeed, a duplicate of SendEntityProperties
This commit is contained in:
Tiger Wang 2021-04-06 12:26:43 +01:00
parent 0f9d424427
commit 1394fc8eb5
16 changed files with 134 additions and 237 deletions

View File

@ -10781,16 +10781,6 @@ a_Player:OpenWindow(Window);
}, },
Notes = "Returns true if the player is satiated (cannot eat).", Notes = "Returns true if the player is satiated (cannot eat).",
}, },
IsVisible =
{
Returns =
{
{
Type = "boolean",
},
},
Notes = "Returns true if the player is visible to other players",
},
LoadRank = LoadRank =
{ {
Notes = "Reloads the player's rank, message visuals and permissions from the {{cRankManager}}, based on the player's current rank.", Notes = "Reloads the player's rank, message visuals and permissions from the {{cRankManager}}, based on the player's current rank.",

View File

@ -345,6 +345,19 @@ void cWorld::BroadcastEntityPosition(const cEntity & a_Entity, const cClientHand
void cWorld::BroadcastEntityProperties(const cEntity & a_Entity)
{
ForClientsWithEntity(a_Entity, *this, nullptr, [&](cClientHandle & a_Client)
{
a_Client.SendEntityProperties(a_Entity);
}
);
}
void cWorld::BroadcastEntityStatus(const cEntity & a_Entity, Int8 a_Status, const cClientHandle * a_Exclude) void cWorld::BroadcastEntityStatus(const cEntity & a_Entity, Int8 a_Status, const cClientHandle * a_Exclude)
{ {
ForClientsWithEntity(a_Entity, *this, a_Exclude, [&](cClientHandle & a_Client) ForClientsWithEntity(a_Entity, *this, a_Exclude, [&](cClientHandle & a_Client)

View File

@ -2528,6 +2528,15 @@ void cClientHandle::SendEntityPosition(const cEntity & a_Entity)
void cClientHandle::SendEntityProperties(const cEntity & a_Entity)
{
m_Protocol->SendEntityProperties(a_Entity);
}
void cClientHandle::SendEntityStatus(const cEntity & a_Entity, char a_Status) void cClientHandle::SendEntityStatus(const cEntity & a_Entity, char a_Status)
{ {
m_Protocol->SendEntityStatus(a_Entity, a_Status); m_Protocol->SendEntityStatus(a_Entity, a_Status);
@ -2737,15 +2746,6 @@ void cClientHandle::SendPlayerListUpdatePing()
void cClientHandle::SendPlayerMaxSpeed(void)
{
m_Protocol->SendPlayerMaxSpeed();
}
void cClientHandle::SendPlayerMoveLook(void) void cClientHandle::SendPlayerMoveLook(void)
{ {
/* /*

View File

@ -169,6 +169,7 @@ public: // tolua_export
void SendEntityLook (const cEntity & a_Entity); void SendEntityLook (const cEntity & a_Entity);
void SendEntityMetadata (const cEntity & a_Entity); void SendEntityMetadata (const cEntity & a_Entity);
void SendEntityPosition (const cEntity & a_Entity); void SendEntityPosition (const cEntity & a_Entity);
void SendEntityProperties (const cEntity & a_Entity);
void SendEntityStatus (const cEntity & a_Entity, char a_Status); void SendEntityStatus (const cEntity & a_Entity, char a_Status);
void SendEntityVelocity (const cEntity & a_Entity); void SendEntityVelocity (const cEntity & a_Entity);
void SendExperience (void); void SendExperience (void);
@ -191,7 +192,6 @@ public: // tolua_export
void SendPlayerListUpdateDisplayName(const cPlayer & a_Player, const AString & a_CustomName); void SendPlayerListUpdateDisplayName(const cPlayer & a_Player, const AString & a_CustomName);
void SendPlayerListUpdateGameMode (const cPlayer & a_Player); void SendPlayerListUpdateGameMode (const cPlayer & a_Player);
void SendPlayerListUpdatePing (); void SendPlayerListUpdatePing ();
void SendPlayerMaxSpeed (void); ///< Informs the client of the maximum player speed (1.6.1+)
void SendPlayerMoveLook (void); void SendPlayerMoveLook (void);
void SendPlayerPosition (void); void SendPlayerPosition (void);
void SendPlayerSpawn (const cPlayer & a_Player); void SendPlayerSpawn (const cPlayer & a_Player);

View File

@ -122,7 +122,7 @@ bool cEntity::Initialize(OwnedEntity a_Self, cWorld & a_EntityWorld)
*/ */
ASSERT(m_World == nullptr); ASSERT(a_Self->IsPlayer() || (m_World == nullptr)); // Players' worlds are loaded from disk.
ASSERT(GetParentChunk() == nullptr); ASSERT(GetParentChunk() == nullptr);
SetWorld(&a_EntityWorld); SetWorld(&a_EntityWorld);
a_EntityWorld.AddEntity(std::move(a_Self)); a_EntityWorld.AddEntity(std::move(a_Self));

View File

@ -144,30 +144,10 @@ cPlayer::cPlayer(const std::shared_ptr<cClientHandle> & a_Client) :
SetMaxHealth(MAX_HEALTH); SetMaxHealth(MAX_HEALTH);
m_Health = MAX_HEALTH; m_Health = MAX_HEALTH;
cWorld * World = nullptr; LoadFromDisk();
LoadFromDisk(World); UpdateCapabilities();
m_LastGroundHeight = static_cast<float>(GetPosY()); m_LastGroundHeight = static_cast<float>(GetPosY());
if (m_GameMode == gmNotSet)
{
if (World->IsGameModeCreative())
{
m_IsFlightCapable = true;
}
if (World->IsGameModeSpectator()) // Otherwise Player will fall out of the world on join
{
m_IsFlightCapable = true;
m_IsFlying = true;
}
}
if (m_GameMode == gmSpectator) // If player is reconnecting to the server in spectator mode
{
m_IsFlightCapable = true;
m_IsFlying = true;
m_IsVisible = false;
}
} }
@ -614,10 +594,11 @@ double cPlayer::GetMaxSpeed(void) const
void cPlayer::SetNormalMaxSpeed(double a_Speed) void cPlayer::SetNormalMaxSpeed(double a_Speed)
{ {
m_NormalMaxSpeed = a_Speed; m_NormalMaxSpeed = a_Speed;
if (!IsSprinting() && !IsFlying() && !IsFrozen())
if (!m_IsFrozen)
{ {
// If we are frozen, we do not send this yet. We send when unfreeze() is called // If we are frozen, we do not send this yet. We send when unfreeze() is called
m_ClientHandle->SendPlayerMaxSpeed(); m_World->BroadcastEntityProperties(*this);
} }
} }
@ -628,10 +609,11 @@ void cPlayer::SetNormalMaxSpeed(double a_Speed)
void cPlayer::SetSprintingMaxSpeed(double a_Speed) void cPlayer::SetSprintingMaxSpeed(double a_Speed)
{ {
m_SprintingMaxSpeed = a_Speed; m_SprintingMaxSpeed = a_Speed;
if (IsSprinting() && !m_IsFlying && !m_IsFrozen)
if (!m_IsFrozen)
{ {
// If we are frozen, we do not send this yet. We send when unfreeze() is called // If we are frozen, we do not send this yet. We send when unfreeze() is called
m_ClientHandle->SendPlayerMaxSpeed(); m_World->BroadcastEntityProperties(*this);
} }
} }
@ -643,7 +625,6 @@ void cPlayer::SetFlyingMaxSpeed(double a_Speed)
{ {
m_FlyingMaxSpeed = a_Speed; m_FlyingMaxSpeed = a_Speed;
// Update the flying speed, always:
if (!m_IsFrozen) if (!m_IsFrozen)
{ {
// If we are frozen, we do not send this yet. We send when unfreeze() is called // If we are frozen, we do not send this yet. We send when unfreeze() is called
@ -723,6 +704,7 @@ void cPlayer::SetSprint(const bool a_ShouldSprint)
} }
m_World->BroadcastEntityMetadata(*this); m_World->BroadcastEntityMetadata(*this);
m_World->BroadcastEntityProperties(*this);
} }
@ -1325,49 +1307,38 @@ void cPlayer::SetGameMode(eGameMode a_GameMode)
} }
m_GameMode = a_GameMode; m_GameMode = a_GameMode;
UpdateCapabilities();
m_ClientHandle->SendGameMode(a_GameMode); m_ClientHandle->SendGameMode(a_GameMode);
m_ClientHandle->SendInventorySlot(-1, -1, m_DraggingItem);
SetCapabilities();
m_World->BroadcastPlayerListUpdateGameMode(*this); m_World->BroadcastPlayerListUpdateGameMode(*this);
m_World->BroadcastEntityMetadata(*this);
} }
void cPlayer::SetCapabilities() void cPlayer::UpdateCapabilities()
{ {
// Fly ability // Fly ability:
if (IsGameModeCreative() || IsGameModeSpectator()) if (IsGameModeCreative() || IsGameModeSpectator())
{ {
SetCanFly(true); m_IsFlightCapable = true;
} }
else else
{ {
SetFlying(false); m_IsFlying = false;
SetCanFly(false); m_IsFlightCapable = false;
} }
// Visible // Visible:
if (IsGameModeSpectator()) m_IsVisible = !IsGameModeSpectator();
{
SetVisible(false);
}
else
{
SetVisible(true);
}
// Set for spectator // Clear the current dragging item of spectators:
if (IsGameModeSpectator()) if (IsGameModeSpectator())
{ {
// Clear the current dragging item of the player m_DraggingItem.Empty();
if (GetWindow() != nullptr)
{
m_DraggingItem.Empty();
GetClientHandle()->SendInventorySlot(-1, -1, m_DraggingItem);
}
} }
} }
@ -1449,8 +1420,8 @@ void cPlayer::Unfreeze()
m_World->BroadcastEntityMetadata(*this); m_World->BroadcastEntityMetadata(*this);
} }
GetClientHandle()->SendPlayerAbilities(); m_ClientHandle->SendPlayerAbilities();
GetClientHandle()->SendPlayerMaxSpeed(); m_World->BroadcastEntityProperties(*this);
m_IsFrozen = false; m_IsFrozen = false;
BroadcastMovementUpdate(m_ClientHandle.get()); BroadcastMovementUpdate(m_ClientHandle.get());
@ -1521,21 +1492,7 @@ Vector3d cPlayer::GetThrowSpeed(double a_SpeedCoeff) const
eGameMode cPlayer::GetEffectiveGameMode(void) const eGameMode cPlayer::GetEffectiveGameMode(void) const
{ {
// Since entities' m_World aren't set until Initialize, but cClientHandle sends the player's gamemode early return (m_GameMode == gmNotSet) ? m_World->GetGameMode() : m_GameMode;
// the below block deals with m_World being nullptr when called.
auto World = m_World;
if (World == nullptr)
{
World = cRoot::Get()->GetDefaultWorld();
}
else if (IsWorldChangeScheduled())
{
World = m_WorldChangeInfo.m_NewWorld;
}
return (m_GameMode == gmNotSet) ? World->GetGameMode() : m_GameMode;
} }
@ -1553,17 +1510,16 @@ void cPlayer::ForceSetSpeed(const Vector3d & a_Speed)
void cPlayer::SetVisible(bool a_bVisible) void cPlayer::SetVisible(bool a_bVisible)
{ {
// Need to Check if the player or other players are in gamemode spectator, but will break compatibility if (a_bVisible && !m_IsVisible)
if (a_bVisible && !m_IsVisible) // Make visible
{ {
m_IsVisible = true; m_IsVisible = true;
m_World->BroadcastSpawnEntity(*this);
} }
if (!a_bVisible && m_IsVisible) if (!a_bVisible && m_IsVisible)
{ {
m_IsVisible = false; m_IsVisible = false;
m_World->BroadcastDestroyEntity(*this, m_ClientHandle.get()); // Destroy on all clients
} }
m_World->BroadcastEntityMetadata(*this);
} }
@ -1806,25 +1762,25 @@ void cPlayer::TossPickup(const cItem & a_Item)
void cPlayer::LoadFromDisk(cWorldPtr & a_World) void cPlayer::LoadFromDisk()
{ {
LoadRank(); LoadRank();
const auto & UUID = GetUUID(); const auto & UUID = GetUUID();
// Load from the UUID file: // Load from the UUID file:
if (LoadFromFile(GetUUIDFileName(UUID), a_World)) if (LoadFromFile(GetUUIDFileName(UUID)))
{ {
return; return;
} }
// Player not found: // Player not found:
a_World = cRoot::Get()->GetDefaultWorld(); m_World = cRoot::Get()->GetDefaultWorld();
LOG("Player \"%s\" (%s) data not found, resetting to defaults", GetName().c_str(), UUID.ToShortString().c_str()); LOG("Player \"%s\" (%s) data not found, resetting to defaults", GetName().c_str(), UUID.ToShortString().c_str());
const Vector3i WorldSpawn(static_cast<int>(a_World->GetSpawnX()), static_cast<int>(a_World->GetSpawnY()), static_cast<int>(a_World->GetSpawnZ())); const Vector3i WorldSpawn(static_cast<int>(m_World->GetSpawnX()), static_cast<int>(m_World->GetSpawnY()), static_cast<int>(m_World->GetSpawnZ()));
SetPosition(WorldSpawn); SetPosition(WorldSpawn);
SetBedPos(WorldSpawn, a_World); SetBedPos(WorldSpawn, m_World);
m_Inventory.Clear(); m_Inventory.Clear();
m_EnchantmentSeed = GetRandomProvider().RandInt<unsigned int>(); // Use a random number to seed the enchantment generator m_EnchantmentSeed = GetRandomProvider().RandInt<unsigned int>(); // Use a random number to seed the enchantment generator
@ -1836,7 +1792,7 @@ void cPlayer::LoadFromDisk(cWorldPtr & a_World)
bool cPlayer::LoadFromFile(const AString & a_FileName, cWorldPtr & a_World) bool cPlayer::LoadFromFile(const AString & a_FileName)
{ {
Json::Value Root; Json::Value Root;
@ -1925,16 +1881,15 @@ bool cPlayer::LoadFromFile(const AString & a_FileName, cWorldPtr & a_World)
cEnderChestEntity::LoadFromJson(Root["enderchestinventory"], m_EnderChestContents); cEnderChestEntity::LoadFromJson(Root["enderchestinventory"], m_EnderChestContents);
m_CurrentWorldName = Root.get("world", "world").asString(); m_CurrentWorldName = Root.get("world", "world").asString();
a_World = cRoot::Get()->GetWorld(GetLoadedWorldName()); m_World = cRoot::Get()->GetWorld(m_CurrentWorldName);
if (a_World == nullptr) if (m_World == nullptr)
{ {
a_World = cRoot::Get()->GetDefaultWorld(); m_World = cRoot::Get()->GetDefaultWorld();
} }
m_LastBedPos.x = Root.get("SpawnX", m_World->GetSpawnX()).asInt();
m_LastBedPos.x = Root.get("SpawnX", a_World->GetSpawnX()).asInt(); m_LastBedPos.y = Root.get("SpawnY", m_World->GetSpawnY()).asInt();
m_LastBedPos.y = Root.get("SpawnY", a_World->GetSpawnY()).asInt(); m_LastBedPos.z = Root.get("SpawnZ", m_World->GetSpawnZ()).asInt();
m_LastBedPos.z = Root.get("SpawnZ", a_World->GetSpawnZ()).asInt();
m_SpawnWorldName = Root.get("SpawnWorld", cRoot::Get()->GetDefaultWorld()->GetName()).asString(); m_SpawnWorldName = Root.get("SpawnWorld", cRoot::Get()->GetDefaultWorld()->GetName()).asString();
try try
@ -1949,7 +1904,7 @@ bool cPlayer::LoadFromFile(const AString & a_FileName, cWorldPtr & a_World)
} }
FLOGD("Player {0} was read from file \"{1}\", spawning at {2:.2f} in world \"{3}\"", FLOGD("Player {0} was read from file \"{1}\", spawning at {2:.2f} in world \"{3}\"",
GetName(), a_FileName, GetPosition(), a_World->GetName() GetName(), a_FileName, GetPosition(), m_World->GetName()
); );
return true; return true;
@ -2689,10 +2644,10 @@ void cPlayer::FreezeInternal(const Vector3d & a_Location, bool a_ManuallyFrozen)
m_IsFlying = true; m_IsFlying = true;
// Send the client its fake speed and max speed of 0 // Send the client its fake speed and max speed of 0
GetClientHandle()->SendPlayerMoveLook(); m_ClientHandle->SendPlayerMoveLook();
GetClientHandle()->SendPlayerAbilities(); m_ClientHandle->SendPlayerAbilities();
GetClientHandle()->SendPlayerMaxSpeed(); m_ClientHandle->SendEntityVelocity(*this);
GetClientHandle()->SendEntityVelocity(*this); m_World->BroadcastEntityProperties(*this);
// Keep the server side speed variables as they were in the first place // Keep the server side speed variables as they were in the first place
m_NormalMaxSpeed = NormalMaxSpeed; m_NormalMaxSpeed = NormalMaxSpeed;
@ -3050,6 +3005,15 @@ float cPlayer::GetEnchantmentBlastKnockbackReduction()
bool cPlayer::IsInvisible() const
{
return !m_IsVisible || Super::IsInvisible();
}
bool cPlayer::IsCrouched(void) const bool cPlayer::IsCrouched(void) const
{ {
return std::holds_alternative<BodyStanceCrouching>(m_BodyStance); return std::holds_alternative<BodyStanceCrouching>(m_BodyStance);
@ -3079,6 +3043,7 @@ bool cPlayer::IsSprinting(void) const
void cPlayer::OnAddToWorld(cWorld & a_World) void cPlayer::OnAddToWorld(cWorld & a_World)
{ {
// Sends player spawn:
Super::OnAddToWorld(a_World); Super::OnAddToWorld(a_World);
// Update world name tracking: // Update world name tracking:
@ -3087,8 +3052,10 @@ void cPlayer::OnAddToWorld(cWorld & a_World)
// Fix to stop the player falling through the world, until we get serversided collision detection: // Fix to stop the player falling through the world, until we get serversided collision detection:
FreezeInternal(GetPosition(), false); FreezeInternal(GetPosition(), false);
// Set capabilities based on new world: // UpdateCapabilities was called in the constructor, and in OnRemoveFromWorld, possibly changing our visibility.
SetCapabilities(); // If world is in spectator mode, invisibility will need updating. If we just connected, we might be on fire from a previous game.
// Hence, tell the client by sending metadata:
m_ClientHandle->SendEntityMetadata(*this);
// Send contents of the inventory window: // Send contents of the inventory window:
m_ClientHandle->SendWholeInventory(*m_CurrentWindow); m_ClientHandle->SendWholeInventory(*m_CurrentWindow);
@ -3168,8 +3135,13 @@ void cPlayer::OnRemoveFromWorld(cWorld & a_World)
AwardAchievement(Statistic::AchPortal); AwardAchievement(Statistic::AchPortal);
} }
// Set capabilities based on new world:
UpdateCapabilities();
// Clientside warp start: // Clientside warp start:
m_ClientHandle->SendRespawn(DestinationDimension, false); m_ClientHandle->SendRespawn(DestinationDimension, false);
m_ClientHandle->SendPlayerListUpdateGameMode(*this);
m_World->BroadcastPlayerListUpdateGameMode(*this);
// Clear sent chunk lists from the clienthandle: // Clear sent chunk lists from the clienthandle:
m_ClientHandle->RemoveFromWorld(); m_ClientHandle->RemoveFromWorld();
@ -3184,7 +3156,7 @@ void cPlayer::OnRemoveFromWorld(cWorld & a_World)
void cPlayer::SpawnOn(cClientHandle & a_Client) void cPlayer::SpawnOn(cClientHandle & a_Client)
{ {
if (!m_IsVisible || (m_ClientHandle.get() == (&a_Client))) if (m_ClientHandle.get() == &a_Client)
{ {
return; return;
} }

View File

@ -163,8 +163,8 @@ public:
virtual void TeleportToCoords(double a_PosX, double a_PosY, double a_PosZ) override; virtual void TeleportToCoords(double a_PosX, double a_PosY, double a_PosZ) override;
// Updates player's capabilities - flying, visibility, etc. from their gamemode. /** Updates player's capabilities - flying, visibility, etc. from their gamemode. */
void SetCapabilities(); void UpdateCapabilities();
// tolua_begin // tolua_begin
@ -412,21 +412,18 @@ public:
void Respawn(void); // tolua_export void Respawn(void); // tolua_export
void SetVisible( bool a_bVisible); // tolua_export void SetVisible( bool a_bVisible); // tolua_export
bool IsVisible(void) const { return m_IsVisible; } // tolua_export
/** Saves all player data, such as inventory, to JSON. */ /** Saves all player data, such as inventory, to JSON. */
void SaveToDisk(void); void SaveToDisk(void);
typedef cWorld * cWorldPtr;
/** Loads the player data from the disk file. /** Loads the player data from the disk file.
Sets a_World to the world where the player will spawn, based on the stored world name or the default world by calling LoadFromFile(). */ Sets m_World to the world where the player will spawn, based on the stored world name or the default world by calling LoadFromFile(). */
void LoadFromDisk(cWorldPtr & a_World); void LoadFromDisk();
/** Loads the player data from the specified file. /** Loads the player data from the specified file.
Sets a_World to the world where the player will spawn, based on the stored world name or the default world. Sets m_World to the world where the player will spawn, based on the stored world name or the default world.
Returns true on success, false if the player wasn't found, and excepts with base std::runtime_error if the data couldn't be read or parsed. */ Returns true on success, false if the player wasn't found, and excepts with base std::runtime_error if the data couldn't be read or parsed. */
bool LoadFromFile(const AString & a_FileName, cWorldPtr & a_World); bool LoadFromFile(const AString & a_FileName);
const AString & GetLoadedWorldName() const { return m_CurrentWorldName; } const AString & GetLoadedWorldName() const { return m_CurrentWorldName; }
@ -805,6 +802,7 @@ private:
virtual bool DoTakeDamage(TakeDamageInfo & TDI) override; virtual bool DoTakeDamage(TakeDamageInfo & TDI) override;
virtual float GetEnchantmentBlastKnockbackReduction() override; virtual float GetEnchantmentBlastKnockbackReduction() override;
virtual void HandlePhysics(std::chrono::milliseconds a_Dt, cChunk &) override { UNUSED(a_Dt); } virtual void HandlePhysics(std::chrono::milliseconds a_Dt, cChunk &) override { UNUSED(a_Dt); }
virtual bool IsInvisible() const override;
virtual bool IsRclking(void) const override { return IsEating() || IsChargingBow(); } virtual bool IsRclking(void) const override { return IsEating() || IsChargingBow(); }
virtual void OnAddToWorld(cWorld & a_World) override; virtual void OnAddToWorld(cWorld & a_World) override;
virtual void OnRemoveFromWorld(cWorld & a_World) override; virtual void OnRemoveFromWorld(cWorld & a_World) override;

View File

@ -99,7 +99,6 @@ AString cPacketizer::PacketTypeToStr(cProtocol::ePacketType a_PacketType)
case cProtocol::pktPlayerAbilities: return "pktPlayerAbilities"; case cProtocol::pktPlayerAbilities: return "pktPlayerAbilities";
case cProtocol::pktPlayerList: return "pktPlayerList"; case cProtocol::pktPlayerList: return "pktPlayerList";
case cProtocol::pktPlayerListHeaderFooter: return "pktPlayerListHeaderFooter"; case cProtocol::pktPlayerListHeaderFooter: return "pktPlayerListHeaderFooter";
case cProtocol::pktPlayerMaxSpeed: return "pktPlayerMaxSpeed";
case cProtocol::pktPlayerMoveLook: return "pktPlayerMoveLook"; case cProtocol::pktPlayerMoveLook: return "pktPlayerMoveLook";
case cProtocol::pktPluginMessage: return "pktPluginMessage"; case cProtocol::pktPluginMessage: return "pktPluginMessage";
case cProtocol::pktRemoveEntityEffect: return "pktRemoveEntityEffect"; case cProtocol::pktRemoveEntityEffect: return "pktRemoveEntityEffect";

View File

@ -105,7 +105,6 @@ public:
pktPlayerAbilities, pktPlayerAbilities,
pktPlayerList, pktPlayerList,
pktPlayerListHeaderFooter, pktPlayerListHeaderFooter,
pktPlayerMaxSpeed,
pktPlayerMoveLook, pktPlayerMoveLook,
pktPluginMessage, pktPluginMessage,
pktRemoveEntityEffect, pktRemoveEntityEffect,
@ -412,7 +411,6 @@ public:
virtual void SendPlayerListUpdateGameMode (const cPlayer & a_Player) = 0; virtual void SendPlayerListUpdateGameMode (const cPlayer & a_Player) = 0;
virtual void SendPlayerListUpdatePing () = 0; virtual void SendPlayerListUpdatePing () = 0;
virtual void SendPlayerListUpdateDisplayName(const cPlayer & a_Player, const AString & a_CustomName) = 0; virtual void SendPlayerListUpdateDisplayName(const cPlayer & a_Player, const AString & a_CustomName) = 0;
virtual void SendPlayerMaxSpeed (void) = 0; ///< Informs the client of the maximum player speed (1.6.1+)
virtual void SendPlayerMoveLook (void) = 0; virtual void SendPlayerMoveLook (void) = 0;
virtual void SendPlayerPosition (void) = 0; virtual void SendPlayerPosition (void) = 0;
virtual void SendPlayerSpawn (const cPlayer & a_Player) = 0; virtual void SendPlayerSpawn (const cPlayer & a_Player) = 0;

View File

@ -1003,7 +1003,6 @@ UInt32 cProtocol_1_12::GetPacketID(cProtocol::ePacketType a_Packet)
case pktExperience: return 0x3f; case pktExperience: return 0x3f;
case pktHeldItemChange: return 0x39; case pktHeldItemChange: return 0x39;
case pktLeashEntity: return 0x3c; case pktLeashEntity: return 0x3c;
case pktPlayerMaxSpeed: return 0x4d;
case pktRemoveEntityEffect: return 0x32; case pktRemoveEntityEffect: return 0x32;
case pktResourcePack: return 0x33; case pktResourcePack: return 0x33;
case pktRespawn: return 0x34; case pktRespawn: return 0x34;
@ -1184,7 +1183,6 @@ UInt32 cProtocol_1_12_1::GetPacketID(ePacketType a_Packet)
case pktPlayerList: return 0x2e; case pktPlayerList: return 0x2e;
case pktPlayerListHeaderFooter: return 0x4a; case pktPlayerListHeaderFooter: return 0x4a;
case pktPlayerAbilities: return 0x2c; case pktPlayerAbilities: return 0x2c;
case pktPlayerMaxSpeed: return 0x4e;
case pktPlayerMoveLook: return 0x2f; case pktPlayerMoveLook: return 0x2f;
case pktRemoveEntityEffect: return 0x33; case pktRemoveEntityEffect: return 0x33;
case pktResourcePack: return 0x34; case pktResourcePack: return 0x34;

View File

@ -372,8 +372,7 @@ UInt32 cProtocol_1_13::GetPacketID(ePacketType a_PacketType)
case pktParticleEffect: return 0x24; case pktParticleEffect: return 0x24;
case pktPlayerAbilities: return 0x2e; case pktPlayerAbilities: return 0x2e;
case pktPlayerList: return 0x30; case pktPlayerList: return 0x30;
case pktPlayerListHeaderFooter: return 0x4E; case pktPlayerListHeaderFooter: return 0x4e;
case pktPlayerMaxSpeed: return 0x52;
case pktPlayerMoveLook: return 0x32; case pktPlayerMoveLook: return 0x32;
case pktPluginMessage: return 0x19; case pktPluginMessage: return 0x19;
case pktRemoveEntityEffect: return 0x36; case pktRemoveEntityEffect: return 0x36;

View File

@ -832,9 +832,6 @@ void cProtocol_1_8_0::SendLogin(const cPlayer & a_Player, const cWorld & a_World
cPacketizer Pkt(*this, pktDifficulty); cPacketizer Pkt(*this, pktDifficulty);
Pkt.WriteBEInt8(1); Pkt.WriteBEInt8(1);
} }
// Send player abilities:
SendPlayerAbilities();
} }
@ -1132,35 +1129,6 @@ void cProtocol_1_8_0::SendPlayerListUpdatePing()
void cProtocol_1_8_0::SendPlayerMaxSpeed(void)
{
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, pktEntityProperties);
cPlayer * Player = m_Client->GetPlayer();
Pkt.WriteVarInt32(Player->GetUniqueID());
Pkt.WriteBEInt32(1); // Count
Pkt.WriteString("generic.movementSpeed");
// The default game speed is 0.1, multiply that value by the relative speed:
Pkt.WriteBEDouble(0.1 * Player->GetNormalMaxSpeed());
if (Player->IsSprinting())
{
Pkt.WriteVarInt32(1); // Modifier count
Pkt.WriteBEUInt64(0x662a6b8dda3e4c1c);
Pkt.WriteBEUInt64(0x881396ea6097278d); // UUID of the modifier
Pkt.WriteBEDouble(Player->GetSprintingMaxSpeed() - Player->GetNormalMaxSpeed());
Pkt.WriteBEUInt8(2);
}
else
{
Pkt.WriteVarInt32(0); // Modifier count
}
}
void cProtocol_1_8_0::SendPlayerMoveLook(void) void cProtocol_1_8_0::SendPlayerMoveLook(void)
{ {
ASSERT(m_State == 3); // In game mode? ASSERT(m_State == 3); // In game mode?
@ -1201,12 +1169,8 @@ void cProtocol_1_8_0::SendPlayerSpawn(const cPlayer & a_Player)
Pkt.WriteFPInt(LastSentPos.z); Pkt.WriteFPInt(LastSentPos.z);
Pkt.WriteByteAngle(a_Player.GetYaw()); Pkt.WriteByteAngle(a_Player.GetYaw());
Pkt.WriteByteAngle(a_Player.GetPitch()); Pkt.WriteByteAngle(a_Player.GetPitch());
short ItemType = a_Player.GetEquippedItem().IsEmpty() ? 0 : a_Player.GetEquippedItem().m_ItemType; Pkt.WriteBEInt16(a_Player.GetEquippedItem().IsEmpty() ? 0 : a_Player.GetEquippedItem().m_ItemType);
Pkt.WriteBEInt16(ItemType); WriteEntityMetadata(Pkt, a_Player);
Pkt.WriteBEUInt8((3 << 5) | 6); // Metadata: float + index 6
Pkt.WriteBEFloat(static_cast<float>(a_Player.GetHealth()));
Pkt.WriteBEUInt8((4 << 5 | (2 & 0x1F)) & 0xFF);
Pkt.WriteString(a_Player.GetName());
Pkt.WriteBEUInt8(0x7f); // Metadata: end Pkt.WriteBEUInt8(0x7f); // Metadata: end
} }
@ -3377,11 +3341,15 @@ void cProtocol_1_8_0::WriteEntityMetadata(cPacketizer & a_Pkt, const cEntity & a
{ {
auto & Player = static_cast<const cPlayer &>(a_Entity); auto & Player = static_cast<const cPlayer &>(a_Entity);
// Player health (not handled since players aren't monsters) // Player name:
a_Pkt.WriteBEUInt8(0x82);
a_Pkt.WriteString(Player.GetName());
// Player health:
a_Pkt.WriteBEUInt8(0x66); a_Pkt.WriteBEUInt8(0x66);
a_Pkt.WriteBEFloat(static_cast<float>(Player.GetHealth())); a_Pkt.WriteBEFloat(static_cast<float>(Player.GetHealth()));
// Skin flags // Skin flags:
a_Pkt.WriteBEUInt8(0x0A); a_Pkt.WriteBEUInt8(0x0A);
a_Pkt.WriteBEUInt8(static_cast<UInt8>(Player.GetSkinParts())); a_Pkt.WriteBEUInt8(static_cast<UInt8>(Player.GetSkinParts()));
@ -3815,18 +3783,38 @@ void cProtocol_1_8_0::WriteMobMetadata(cPacketizer & a_Pkt, const cMonster & a_M
void cProtocol_1_8_0::WriteEntityProperties(cPacketizer & a_Pkt, const cEntity & a_Entity) void cProtocol_1_8_0::WriteEntityProperties(cPacketizer & a_Pkt, const cEntity & a_Entity)
{ {
if (!a_Entity.IsMob()) if (a_Entity.IsPlayer())
{ {
// No properties for anything else than mobs const auto & Player = static_cast<const cPlayer &>(a_Entity);
a_Pkt.WriteBEInt32(0);
return; a_Pkt.WriteBEInt32(1); // Count.
a_Pkt.WriteString("generic.movementSpeed");
a_Pkt.WriteBEDouble(0.1 * Player.GetNormalMaxSpeed()); // The default game speed is 0.1, multiply that value by the relative speed.
// It seems the modifiers aren't conditionally activated; their effects are applied immediately!
// We have to keep on re-sending this packet when the client notifies us of sprint start and end, and so on. Strange.
if (Player.IsSprinting())
{
a_Pkt.WriteVarInt32(1); // Modifier count.
a_Pkt.WriteBEUInt64(0x662a6b8dda3e4c1c);
a_Pkt.WriteBEUInt64(0x881396ea6097278d); // UUID of the modifier (sprinting speed boost).
a_Pkt.WriteBEDouble(Player.GetSprintingMaxSpeed() - Player.GetNormalMaxSpeed());
a_Pkt.WriteBEUInt8(2);
}
else
{
a_Pkt.WriteVarInt32(0);
}
} }
else
{
// const cMonster & Mob = (const cMonster &)a_Entity;
// const cMonster & Mob = (const cMonster &)a_Entity; // TODO: Send properties and modifiers based on the mob type
// TODO: Send properties and modifiers based on the mob type a_Pkt.WriteBEInt32(0);
}
a_Pkt.WriteBEInt32(0); // NumProperties
} }

View File

@ -95,7 +95,6 @@ public:
virtual void SendPlayerListUpdateDisplayName(const cPlayer & a_Player, const AString & a_CustomName) override; virtual void SendPlayerListUpdateDisplayName(const cPlayer & a_Player, const AString & a_CustomName) override;
virtual void SendPlayerListUpdateGameMode (const cPlayer & a_Player) override; virtual void SendPlayerListUpdateGameMode (const cPlayer & a_Player) override;
virtual void SendPlayerListUpdatePing () override; virtual void SendPlayerListUpdatePing () override;
virtual void SendPlayerMaxSpeed (void) override;
virtual void SendPlayerMoveLook (void) override; virtual void SendPlayerMoveLook (void) override;
virtual void SendPlayerPosition (void) override; virtual void SendPlayerPosition (void) override;
virtual void SendPlayerSpawn (const cPlayer & a_Player) override; virtual void SendPlayerSpawn (const cPlayer & a_Player) override;

View File

@ -490,35 +490,6 @@ void cProtocol_1_9_0::SendMapData(const cMap & a_Map, int a_DataStartX, int a_Da
void cProtocol_1_9_0::SendPlayerMaxSpeed(void)
{
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, pktPlayerMaxSpeed);
cPlayer * Player = m_Client->GetPlayer();
Pkt.WriteVarInt32(Player->GetUniqueID());
Pkt.WriteBEInt32(1); // Count
Pkt.WriteString("generic.movementSpeed");
// The default game speed is 0.1, multiply that value by the relative speed:
Pkt.WriteBEDouble(0.1 * Player->GetNormalMaxSpeed());
if (Player->IsSprinting())
{
Pkt.WriteVarInt32(1); // Modifier count
Pkt.WriteBEUInt64(0x662a6b8dda3e4c1c);
Pkt.WriteBEUInt64(0x881396ea6097278d); // UUID of the modifier
Pkt.WriteBEDouble(Player->GetSprintingMaxSpeed() - Player->GetNormalMaxSpeed());
Pkt.WriteBEUInt8(2);
}
else
{
Pkt.WriteVarInt32(0); // Modifier count
}
}
void cProtocol_1_9_0::SendPlayerMoveLook(void) void cProtocol_1_9_0::SendPlayerMoveLook(void)
{ {
ASSERT(m_State == 3); // In game mode? ASSERT(m_State == 3); // In game mode?
@ -690,7 +661,6 @@ UInt32 cProtocol_1_9_0::GetPacketID(cProtocol::ePacketType a_Packet)
case pktPlayerAbilities: return 0x2b; case pktPlayerAbilities: return 0x2b;
case pktPlayerList: return 0x2d; case pktPlayerList: return 0x2d;
case pktPlayerListHeaderFooter: return 0x48; case pktPlayerListHeaderFooter: return 0x48;
case pktPlayerMaxSpeed: return 0x4b;
case pktPlayerMoveLook: return 0x2e; case pktPlayerMoveLook: return 0x2e;
case pktPluginMessage: return 0x18; case pktPluginMessage: return 0x18;
case pktRemoveEntityEffect: return 0x31; case pktRemoveEntityEffect: return 0x31;
@ -2271,26 +2241,6 @@ void cProtocol_1_9_0::WriteMobMetadata(cPacketizer & a_Pkt, const cMonster & a_M
void cProtocol_1_9_0::WriteEntityProperties(cPacketizer & a_Pkt, const cEntity & a_Entity)
{
if (!a_Entity.IsMob())
{
// No properties for anything else than mobs
a_Pkt.WriteBEInt32(0);
return;
}
// const cMonster & Mob = (const cMonster &)a_Entity;
// TODO: Send properties and modifiers based on the mob type
a_Pkt.WriteBEInt32(0); // NumProperties
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// cProtocol_1_9_1: // cProtocol_1_9_1:
@ -2320,9 +2270,6 @@ void cProtocol_1_9_1::SendLogin(const cPlayer & a_Player, const cWorld & a_World
cPacketizer Pkt(*this, pktDifficulty); cPacketizer Pkt(*this, pktDifficulty);
Pkt.WriteBEInt8(1); Pkt.WriteBEInt8(1);
} }
// Send player abilities:
SendPlayerAbilities();
} }
@ -2405,7 +2352,6 @@ UInt32 cProtocol_1_9_4::GetPacketID(cProtocol::ePacketType a_Packet)
case pktCollectEntity: return 0x48; case pktCollectEntity: return 0x48;
case pktEntityEffect: return 0x4b; case pktEntityEffect: return 0x4b;
case pktEntityProperties: return 0x4a; case pktEntityProperties: return 0x4a;
case pktPlayerMaxSpeed: return 0x4a;
case pktPlayerListHeaderFooter: return 0x47; case pktPlayerListHeaderFooter: return 0x47;
case pktTeleportEntity: return 0x49; case pktTeleportEntity: return 0x49;

View File

@ -57,7 +57,6 @@ public:
virtual void SendLeashEntity (const cEntity & a_Entity, const cEntity & a_EntityLeashedTo) override; virtual void SendLeashEntity (const cEntity & a_Entity, const cEntity & a_EntityLeashedTo) override;
virtual void SendMapData (const cMap & a_Map, int a_DataStartX, int a_DataStartY) override; virtual void SendMapData (const cMap & a_Map, int a_DataStartX, int a_DataStartY) override;
virtual void SendPaintingSpawn (const cPainting & a_Painting) override; virtual void SendPaintingSpawn (const cPainting & a_Painting) override;
virtual void SendPlayerMaxSpeed (void) override;
virtual void SendPlayerMoveLook (void) override; virtual void SendPlayerMoveLook (void) override;
virtual void SendPlayerSpawn (const cPlayer & a_Player) override; virtual void SendPlayerSpawn (const cPlayer & a_Player) override;
virtual void SendSoundEffect (const AString & a_SoundName, double a_X, double a_Y, double a_Z, float a_Volume, float a_Pitch) override; virtual void SendSoundEffect (const AString & a_SoundName, double a_X, double a_Y, double a_Z, float a_Volume, float a_Pitch) override;
@ -125,9 +124,6 @@ protected:
/** Writes the mob-specific metadata for the specified mob */ /** Writes the mob-specific metadata for the specified mob */
virtual void WriteMobMetadata(cPacketizer & a_Pkt, const cMonster & a_Mob) override; virtual void WriteMobMetadata(cPacketizer & a_Pkt, const cMonster & a_Mob) override;
/** Writes the entity properties for the specified entity, including the Count field. */
virtual void WriteEntityProperties(cPacketizer & a_Pkt, const cEntity & a_Entity) override;
/** Types used within metadata */ /** Types used within metadata */
enum eMetadataType enum eMetadataType
{ {

View File

@ -184,6 +184,7 @@ public:
virtual void BroadcastEntityLook (const cEntity & a_Entity, const cClientHandle * a_Exclude = nullptr) override; virtual void BroadcastEntityLook (const cEntity & a_Entity, const cClientHandle * a_Exclude = nullptr) override;
virtual void BroadcastEntityMetadata (const cEntity & a_Entity, const cClientHandle * a_Exclude = nullptr) override; virtual void BroadcastEntityMetadata (const cEntity & a_Entity, const cClientHandle * a_Exclude = nullptr) override;
virtual void BroadcastEntityPosition (const cEntity & a_Entity, const cClientHandle * a_Exclude = nullptr) override; virtual void BroadcastEntityPosition (const cEntity & a_Entity, const cClientHandle * a_Exclude = nullptr) override;
void BroadcastEntityProperties (const cEntity & a_Entity);
virtual void BroadcastEntityStatus (const cEntity & a_Entity, Int8 a_Status, const cClientHandle * a_Exclude = nullptr) override; virtual void BroadcastEntityStatus (const cEntity & a_Entity, Int8 a_Status, const cClientHandle * a_Exclude = nullptr) override;
virtual void BroadcastEntityVelocity (const cEntity & a_Entity, const cClientHandle * a_Exclude = nullptr) override; virtual void BroadcastEntityVelocity (const cEntity & a_Entity, const cClientHandle * a_Exclude = nullptr) override;
virtual void BroadcastEntityAnimation (const cEntity & a_Entity, Int8 a_Animation, const cClientHandle * a_Exclude = nullptr) override; // tolua_export virtual void BroadcastEntityAnimation (const cEntity & a_Entity, Int8 a_Animation, const cClientHandle * a_Exclude = nullptr) override; // tolua_export