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).",
},
IsVisible =
{
Returns =
{
{
Type = "boolean",
},
},
Notes = "Returns true if the player is visible to other players",
},
LoadRank =
{
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)
{
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)
{
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)
{
/*

View File

@ -169,6 +169,7 @@ public: // tolua_export
void SendEntityLook (const cEntity & a_Entity);
void SendEntityMetadata (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 SendEntityVelocity (const cEntity & a_Entity);
void SendExperience (void);
@ -191,7 +192,6 @@ public: // tolua_export
void SendPlayerListUpdateDisplayName(const cPlayer & a_Player, const AString & a_CustomName);
void SendPlayerListUpdateGameMode (const cPlayer & a_Player);
void SendPlayerListUpdatePing ();
void SendPlayerMaxSpeed (void); ///< Informs the client of the maximum player speed (1.6.1+)
void SendPlayerMoveLook (void);
void SendPlayerPosition (void);
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);
SetWorld(&a_EntityWorld);
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);
m_Health = MAX_HEALTH;
cWorld * World = nullptr;
LoadFromDisk(World);
LoadFromDisk();
UpdateCapabilities();
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)
{
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
m_ClientHandle->SendPlayerMaxSpeed();
m_World->BroadcastEntityProperties(*this);
}
}
@ -628,10 +609,11 @@ void cPlayer::SetNormalMaxSpeed(double a_Speed)
void cPlayer::SetSprintingMaxSpeed(double 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
m_ClientHandle->SendPlayerMaxSpeed();
m_World->BroadcastEntityProperties(*this);
}
}
@ -643,7 +625,6 @@ void cPlayer::SetFlyingMaxSpeed(double a_Speed)
{
m_FlyingMaxSpeed = a_Speed;
// Update the flying speed, always:
if (!m_IsFrozen)
{
// 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->BroadcastEntityProperties(*this);
}
@ -1325,49 +1307,38 @@ void cPlayer::SetGameMode(eGameMode a_GameMode)
}
m_GameMode = a_GameMode;
UpdateCapabilities();
m_ClientHandle->SendGameMode(a_GameMode);
SetCapabilities();
m_ClientHandle->SendInventorySlot(-1, -1, m_DraggingItem);
m_World->BroadcastPlayerListUpdateGameMode(*this);
m_World->BroadcastEntityMetadata(*this);
}
void cPlayer::SetCapabilities()
void cPlayer::UpdateCapabilities()
{
// Fly ability
// Fly ability:
if (IsGameModeCreative() || IsGameModeSpectator())
{
SetCanFly(true);
m_IsFlightCapable = true;
}
else
{
SetFlying(false);
SetCanFly(false);
m_IsFlying = false;
m_IsFlightCapable = false;
}
// Visible
if (IsGameModeSpectator())
{
SetVisible(false);
}
else
{
SetVisible(true);
}
// Visible:
m_IsVisible = !IsGameModeSpectator();
// Set for spectator
// Clear the current dragging item of spectators:
if (IsGameModeSpectator())
{
// Clear the current dragging item of the player
if (GetWindow() != nullptr)
{
m_DraggingItem.Empty();
GetClientHandle()->SendInventorySlot(-1, -1, m_DraggingItem);
}
m_DraggingItem.Empty();
}
}
@ -1449,8 +1420,8 @@ void cPlayer::Unfreeze()
m_World->BroadcastEntityMetadata(*this);
}
GetClientHandle()->SendPlayerAbilities();
GetClientHandle()->SendPlayerMaxSpeed();
m_ClientHandle->SendPlayerAbilities();
m_World->BroadcastEntityProperties(*this);
m_IsFrozen = false;
BroadcastMovementUpdate(m_ClientHandle.get());
@ -1521,21 +1492,7 @@ Vector3d cPlayer::GetThrowSpeed(double a_SpeedCoeff) const
eGameMode cPlayer::GetEffectiveGameMode(void) const
{
// Since entities' m_World aren't set until Initialize, but cClientHandle sends the player's gamemode early
// 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;
return (m_GameMode == gmNotSet) ? m_World->GetGameMode() : m_GameMode;
}
@ -1553,17 +1510,16 @@ void cPlayer::ForceSetSpeed(const Vector3d & a_Speed)
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) // Make visible
if (a_bVisible && !m_IsVisible)
{
m_IsVisible = true;
m_World->BroadcastSpawnEntity(*this);
}
if (!a_bVisible && m_IsVisible)
{
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();
const auto & UUID = GetUUID();
// Load from the UUID file:
if (LoadFromFile(GetUUIDFileName(UUID), a_World))
if (LoadFromFile(GetUUIDFileName(UUID)))
{
return;
}
// 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());
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);
SetBedPos(WorldSpawn, a_World);
SetBedPos(WorldSpawn, m_World);
m_Inventory.Clear();
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;
@ -1925,16 +1881,15 @@ bool cPlayer::LoadFromFile(const AString & a_FileName, cWorldPtr & a_World)
cEnderChestEntity::LoadFromJson(Root["enderchestinventory"], m_EnderChestContents);
m_CurrentWorldName = Root.get("world", "world").asString();
a_World = cRoot::Get()->GetWorld(GetLoadedWorldName());
if (a_World == nullptr)
m_World = cRoot::Get()->GetWorld(m_CurrentWorldName);
if (m_World == nullptr)
{
a_World = cRoot::Get()->GetDefaultWorld();
m_World = cRoot::Get()->GetDefaultWorld();
}
m_LastBedPos.x = Root.get("SpawnX", a_World->GetSpawnX()).asInt();
m_LastBedPos.y = Root.get("SpawnY", a_World->GetSpawnY()).asInt();
m_LastBedPos.z = Root.get("SpawnZ", a_World->GetSpawnZ()).asInt();
m_LastBedPos.x = Root.get("SpawnX", m_World->GetSpawnX()).asInt();
m_LastBedPos.y = Root.get("SpawnY", m_World->GetSpawnY()).asInt();
m_LastBedPos.z = Root.get("SpawnZ", m_World->GetSpawnZ()).asInt();
m_SpawnWorldName = Root.get("SpawnWorld", cRoot::Get()->GetDefaultWorld()->GetName()).asString();
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}\"",
GetName(), a_FileName, GetPosition(), a_World->GetName()
GetName(), a_FileName, GetPosition(), m_World->GetName()
);
return true;
@ -2689,10 +2644,10 @@ void cPlayer::FreezeInternal(const Vector3d & a_Location, bool a_ManuallyFrozen)
m_IsFlying = true;
// Send the client its fake speed and max speed of 0
GetClientHandle()->SendPlayerMoveLook();
GetClientHandle()->SendPlayerAbilities();
GetClientHandle()->SendPlayerMaxSpeed();
GetClientHandle()->SendEntityVelocity(*this);
m_ClientHandle->SendPlayerMoveLook();
m_ClientHandle->SendPlayerAbilities();
m_ClientHandle->SendEntityVelocity(*this);
m_World->BroadcastEntityProperties(*this);
// Keep the server side speed variables as they were in the first place
m_NormalMaxSpeed = NormalMaxSpeed;
@ -3050,6 +3005,15 @@ float cPlayer::GetEnchantmentBlastKnockbackReduction()
bool cPlayer::IsInvisible() const
{
return !m_IsVisible || Super::IsInvisible();
}
bool cPlayer::IsCrouched(void) const
{
return std::holds_alternative<BodyStanceCrouching>(m_BodyStance);
@ -3079,6 +3043,7 @@ bool cPlayer::IsSprinting(void) const
void cPlayer::OnAddToWorld(cWorld & a_World)
{
// Sends player spawn:
Super::OnAddToWorld(a_World);
// 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:
FreezeInternal(GetPosition(), false);
// Set capabilities based on new world:
SetCapabilities();
// UpdateCapabilities was called in the constructor, and in OnRemoveFromWorld, possibly changing our visibility.
// 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:
m_ClientHandle->SendWholeInventory(*m_CurrentWindow);
@ -3168,8 +3135,13 @@ void cPlayer::OnRemoveFromWorld(cWorld & a_World)
AwardAchievement(Statistic::AchPortal);
}
// Set capabilities based on new world:
UpdateCapabilities();
// Clientside warp start:
m_ClientHandle->SendRespawn(DestinationDimension, false);
m_ClientHandle->SendPlayerListUpdateGameMode(*this);
m_World->BroadcastPlayerListUpdateGameMode(*this);
// Clear sent chunk lists from the clienthandle:
m_ClientHandle->RemoveFromWorld();
@ -3184,7 +3156,7 @@ void cPlayer::OnRemoveFromWorld(cWorld & a_World)
void cPlayer::SpawnOn(cClientHandle & a_Client)
{
if (!m_IsVisible || (m_ClientHandle.get() == (&a_Client)))
if (m_ClientHandle.get() == &a_Client)
{
return;
}

View File

@ -163,8 +163,8 @@ public:
virtual void TeleportToCoords(double a_PosX, double a_PosY, double a_PosZ) override;
// Updates player's capabilities - flying, visibility, etc. from their gamemode.
void SetCapabilities();
/** Updates player's capabilities - flying, visibility, etc. from their gamemode. */
void UpdateCapabilities();
// tolua_begin
@ -412,21 +412,18 @@ public:
void Respawn(void); // 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. */
void SaveToDisk(void);
typedef cWorld * cWorldPtr;
/** 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(). */
void LoadFromDisk(cWorldPtr & a_World);
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();
/** 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. */
bool LoadFromFile(const AString & a_FileName, cWorldPtr & a_World);
bool LoadFromFile(const AString & a_FileName);
const AString & GetLoadedWorldName() const { return m_CurrentWorldName; }
@ -805,6 +802,7 @@ private:
virtual bool DoTakeDamage(TakeDamageInfo & TDI) override;
virtual float GetEnchantmentBlastKnockbackReduction() override;
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 void OnAddToWorld(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::pktPlayerList: return "pktPlayerList";
case cProtocol::pktPlayerListHeaderFooter: return "pktPlayerListHeaderFooter";
case cProtocol::pktPlayerMaxSpeed: return "pktPlayerMaxSpeed";
case cProtocol::pktPlayerMoveLook: return "pktPlayerMoveLook";
case cProtocol::pktPluginMessage: return "pktPluginMessage";
case cProtocol::pktRemoveEntityEffect: return "pktRemoveEntityEffect";

View File

@ -105,7 +105,6 @@ public:
pktPlayerAbilities,
pktPlayerList,
pktPlayerListHeaderFooter,
pktPlayerMaxSpeed,
pktPlayerMoveLook,
pktPluginMessage,
pktRemoveEntityEffect,
@ -412,7 +411,6 @@ public:
virtual void SendPlayerListUpdateGameMode (const cPlayer & a_Player) = 0;
virtual void SendPlayerListUpdatePing () = 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 SendPlayerPosition (void) = 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 pktHeldItemChange: return 0x39;
case pktLeashEntity: return 0x3c;
case pktPlayerMaxSpeed: return 0x4d;
case pktRemoveEntityEffect: return 0x32;
case pktResourcePack: return 0x33;
case pktRespawn: return 0x34;
@ -1184,7 +1183,6 @@ UInt32 cProtocol_1_12_1::GetPacketID(ePacketType a_Packet)
case pktPlayerList: return 0x2e;
case pktPlayerListHeaderFooter: return 0x4a;
case pktPlayerAbilities: return 0x2c;
case pktPlayerMaxSpeed: return 0x4e;
case pktPlayerMoveLook: return 0x2f;
case pktRemoveEntityEffect: return 0x33;
case pktResourcePack: return 0x34;

View File

@ -372,8 +372,7 @@ UInt32 cProtocol_1_13::GetPacketID(ePacketType a_PacketType)
case pktParticleEffect: return 0x24;
case pktPlayerAbilities: return 0x2e;
case pktPlayerList: return 0x30;
case pktPlayerListHeaderFooter: return 0x4E;
case pktPlayerMaxSpeed: return 0x52;
case pktPlayerListHeaderFooter: return 0x4e;
case pktPlayerMoveLook: return 0x32;
case pktPluginMessage: return 0x19;
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);
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)
{
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.WriteByteAngle(a_Player.GetYaw());
Pkt.WriteByteAngle(a_Player.GetPitch());
short ItemType = a_Player.GetEquippedItem().IsEmpty() ? 0 : a_Player.GetEquippedItem().m_ItemType;
Pkt.WriteBEInt16(ItemType);
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.WriteBEInt16(a_Player.GetEquippedItem().IsEmpty() ? 0 : a_Player.GetEquippedItem().m_ItemType);
WriteEntityMetadata(Pkt, a_Player);
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);
// 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.WriteBEFloat(static_cast<float>(Player.GetHealth()));
// Skin flags
// Skin flags:
a_Pkt.WriteBEUInt8(0x0A);
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)
{
if (!a_Entity.IsMob())
if (a_Entity.IsPlayer())
{
// No properties for anything else than mobs
a_Pkt.WriteBEInt32(0);
return;
const auto & Player = static_cast<const cPlayer &>(a_Entity);
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); // NumProperties
a_Pkt.WriteBEInt32(0);
}
}

View File

@ -95,7 +95,6 @@ public:
virtual void SendPlayerListUpdateDisplayName(const cPlayer & a_Player, const AString & a_CustomName) override;
virtual void SendPlayerListUpdateGameMode (const cPlayer & a_Player) override;
virtual void SendPlayerListUpdatePing () override;
virtual void SendPlayerMaxSpeed (void) override;
virtual void SendPlayerMoveLook (void) override;
virtual void SendPlayerPosition (void) 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)
{
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 pktPlayerList: return 0x2d;
case pktPlayerListHeaderFooter: return 0x48;
case pktPlayerMaxSpeed: return 0x4b;
case pktPlayerMoveLook: return 0x2e;
case pktPluginMessage: return 0x18;
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:
@ -2320,9 +2270,6 @@ void cProtocol_1_9_1::SendLogin(const cPlayer & a_Player, const cWorld & a_World
cPacketizer Pkt(*this, pktDifficulty);
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 pktEntityEffect: return 0x4b;
case pktEntityProperties: return 0x4a;
case pktPlayerMaxSpeed: return 0x4a;
case pktPlayerListHeaderFooter: return 0x47;
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 SendMapData (const cMap & a_Map, int a_DataStartX, int a_DataStartY) override;
virtual void SendPaintingSpawn (const cPainting & a_Painting) override;
virtual void SendPlayerMaxSpeed (void) override;
virtual void SendPlayerMoveLook (void) 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;
@ -125,9 +124,6 @@ protected:
/** Writes the mob-specific metadata for the specified mob */
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 */
enum eMetadataType
{

View File

@ -184,6 +184,7 @@ public:
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 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 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