From 07ca09574072b303064eafb2751f8f83c865f083 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Mon, 4 May 2020 09:10:47 +0100 Subject: Improve entity position updates (#4701) * Make puking pickups fly nicer * Improve entity position updates * Move determination of whether a delta is too big for a packet into the protocol handlers + Less jittery movement + Generalise CollectEntity to take any entity --- src/Protocol/Protocol.h | 8 +- src/Protocol/ProtocolRecognizer.cpp | 52 ++++------- src/Protocol/ProtocolRecognizer.h | 8 +- src/Protocol/Protocol_1_11.cpp | 8 +- src/Protocol/Protocol_1_11.h | 2 +- src/Protocol/Protocol_1_8.cpp | 173 ++++++++++++++++++++---------------- src/Protocol/Protocol_1_8.h | 19 ++-- src/Protocol/Protocol_1_9.cpp | 128 +++++++++++++------------- src/Protocol/Protocol_1_9.h | 10 +-- 9 files changed, 200 insertions(+), 208 deletions(-) (limited to 'src/Protocol') diff --git a/src/Protocol/Protocol.h b/src/Protocol/Protocol.h index fc1a1d9d3..12382b954 100644 --- a/src/Protocol/Protocol.h +++ b/src/Protocol/Protocol.h @@ -158,19 +158,19 @@ public: virtual void SendChat (const cCompositeChat & a_Message, eChatType a_Type, bool a_ShouldUseChatPrefixes) = 0; virtual void SendChatRaw (const AString & a_MessageRaw, eChatType a_Type) = 0; virtual void SendChunkData (int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer) = 0; - virtual void SendCollectEntity (const cEntity & a_Entity, const cPlayer & a_Player, int a_Count) = 0; + virtual void SendCollectEntity (const cEntity & a_Collected, const cEntity & a_Collector, unsigned a_Count) = 0; virtual void SendDestroyEntity (const cEntity & a_Entity) = 0; virtual void SendDetachEntity (const cEntity & a_Entity, const cEntity & a_PreviousVehicle) = 0; virtual void SendDisconnect (const AString & a_Reason) = 0; virtual void SendEditSign (int a_BlockX, int a_BlockY, int a_BlockZ) = 0; ///< Request the client to open up the sign editor for the sign (1.6+) virtual void SendEntityEffect (const cEntity & a_Entity, int a_EffectID, int a_Amplifier, int a_Duration) = 0; + virtual void SendEntityAnimation (const cEntity & a_Entity, char a_Animation) = 0; virtual void SendEntityEquipment (const cEntity & a_Entity, short a_SlotNum, const cItem & a_Item) = 0; virtual void SendEntityHeadLook (const cEntity & a_Entity) = 0; virtual void SendEntityLook (const cEntity & a_Entity) = 0; virtual void SendEntityMetadata (const cEntity & a_Entity) = 0; + virtual void SendEntityPosition (const cEntity & a_Entity) = 0; virtual void SendEntityProperties (const cEntity & a_Entity) = 0; - virtual void SendEntityRelMove (const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ) = 0; - virtual void SendEntityRelMoveLook (const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ) = 0; virtual void SendEntityStatus (const cEntity & a_Entity, char a_Status) = 0; virtual void SendEntityVelocity (const cEntity & a_Entity) = 0; virtual void SendExplosion (double a_BlockX, double a_BlockY, double a_BlockZ, float a_Radius, const cVector3iArray & a_BlocksAffected, const Vector3d & a_PlayerMotion) = 0; @@ -186,7 +186,6 @@ public: virtual void SendMapData (const cMap & a_Map, int a_DataStartX, int a_DataStartY) = 0; virtual void SendPaintingSpawn (const cPainting & a_Painting) = 0; virtual void SendPlayerAbilities (void) = 0; - virtual void SendEntityAnimation (const cEntity & a_Entity, char a_Animation) = 0; virtual void SendParticleEffect (const AString & a_SoundName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmount) = 0; virtual void SendParticleEffect (const AString & a_SoundName, Vector3f a_Src, Vector3f a_Offset, float a_ParticleData, int a_ParticleAmount, std::array a_Data) = 0; virtual void SendPlayerListAddPlayer (const cPlayer & a_Player) = 0; @@ -218,7 +217,6 @@ public: virtual void SendSpawnMob (const cMonster & a_Mob) = 0; virtual void SendStatistics (const cStatManager & a_Manager) = 0; virtual void SendTabCompletionResults (const AStringVector & a_Results) = 0; - virtual void SendTeleportEntity (const cEntity & a_Entity) = 0; virtual void SendThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ) = 0; virtual void SendTitleTimes (int a_FadeInTicks, int a_DisplayTicks, int a_FadeOutTicks) = 0; virtual void SendTimeUpdate (Int64 a_WorldAge, Int64 a_TimeOfDay, bool a_DoDaylightCycle) = 0; diff --git a/src/Protocol/ProtocolRecognizer.cpp b/src/Protocol/ProtocolRecognizer.cpp index d5f40b19b..ddc1aaf93 100644 --- a/src/Protocol/ProtocolRecognizer.cpp +++ b/src/Protocol/ProtocolRecognizer.cpp @@ -233,10 +233,10 @@ void cProtocolRecognizer::SendChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSe -void cProtocolRecognizer::SendCollectEntity(const cEntity & a_Entity, const cPlayer & a_Player, int a_Count) +void cProtocolRecognizer::SendCollectEntity(const cEntity & a_Collected, const cEntity & a_Collector, unsigned a_Count) { ASSERT(m_Protocol != nullptr); - m_Protocol->SendCollectEntity(a_Entity, a_Player, a_Count); + m_Protocol->SendCollectEntity(a_Collected, a_Collector, a_Count); } @@ -291,6 +291,16 @@ void cProtocolRecognizer::SendEditSign(int a_BlockX, int a_BlockY, int a_BlockZ) +void cProtocolRecognizer::SendEntityAnimation(const cEntity & a_Entity, char a_Animation) +{ + ASSERT(m_Protocol != nullptr); + m_Protocol->SendEntityAnimation(a_Entity, a_Animation); +} + + + + + void cProtocolRecognizer::SendEntityEffect(const cEntity & a_Entity, int a_EffectID, int a_Amplifier, int a_Duration) { ASSERT(m_Protocol != nullptr); @@ -341,30 +351,20 @@ void cProtocolRecognizer::SendEntityMetadata(const cEntity & a_Entity) -void cProtocolRecognizer::SendEntityProperties(const cEntity & a_Entity) -{ - ASSERT(m_Protocol != nullptr); - m_Protocol->SendEntityProperties(a_Entity); -} - - - - - -void cProtocolRecognizer::SendEntityRelMove(const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ) +void cProtocolRecognizer::SendEntityPosition(const cEntity & a_Entity) { ASSERT(m_Protocol != nullptr); - m_Protocol->SendEntityRelMove(a_Entity, a_RelX, a_RelY, a_RelZ); + m_Protocol->SendEntityPosition(a_Entity); } -void cProtocolRecognizer::SendEntityRelMoveLook(const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ) +void cProtocolRecognizer::SendEntityProperties(const cEntity & a_Entity) { ASSERT(m_Protocol != nullptr); - m_Protocol->SendEntityRelMoveLook(a_Entity, a_RelX, a_RelY, a_RelZ); + m_Protocol->SendEntityProperties(a_Entity); } @@ -560,16 +560,6 @@ void cProtocolRecognizer::SendPlayerAbilities(void) -void cProtocolRecognizer::SendEntityAnimation(const cEntity & a_Entity, char a_Animation) -{ - ASSERT(m_Protocol != nullptr); - m_Protocol->SendEntityAnimation(a_Entity, a_Animation); -} - - - - - void cProtocolRecognizer::SendPlayerListAddPlayer(const cPlayer & a_Player) { ASSERT(m_Protocol != nullptr); @@ -860,16 +850,6 @@ void cProtocolRecognizer::SendTabCompletionResults(const AStringVector & a_Resul -void cProtocolRecognizer::SendTeleportEntity(const cEntity & a_Entity) -{ - ASSERT(m_Protocol != nullptr); - m_Protocol->SendTeleportEntity(a_Entity); -} - - - - - void cProtocolRecognizer::SendThunderbolt(int a_BlockX, int a_BlockY, int a_BlockZ) { ASSERT(m_Protocol != nullptr); diff --git a/src/Protocol/ProtocolRecognizer.h b/src/Protocol/ProtocolRecognizer.h index a658a95d9..f82dab08a 100644 --- a/src/Protocol/ProtocolRecognizer.h +++ b/src/Protocol/ProtocolRecognizer.h @@ -60,19 +60,19 @@ public: virtual void SendChat (const cCompositeChat & a_Message, eChatType a_Type, bool a_ShouldUseChatPrefixes) override; virtual void SendChatRaw (const AString & a_MessageRaw, eChatType a_Type) override; virtual void SendChunkData (int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer) override; - virtual void SendCollectEntity (const cEntity & a_Entity, const cPlayer & a_Player, int a_Count) override; + virtual void SendCollectEntity (const cEntity & a_Collected, const cEntity & a_Collector, unsigned a_Count) override; virtual void SendDestroyEntity (const cEntity & a_Entity) override; virtual void SendDetachEntity (const cEntity & a_Entity, const cEntity & a_PreviousVehicle) override; virtual void SendDisconnect (const AString & a_Reason) override; + virtual void SendEntityAnimation (const cEntity & a_Entity, char a_Animation) override; virtual void SendEditSign (int a_BlockX, int a_BlockY, int a_BlockZ) override; ///< Request the client to open up the sign editor for the sign (1.6+) virtual void SendEntityEffect (const cEntity & a_Entity, int a_EffectID, int a_Amplifier, int a_Duration) override; virtual void SendEntityEquipment (const cEntity & a_Entity, short a_SlotNum, const cItem & a_Item) override; virtual void SendEntityHeadLook (const cEntity & a_Entity) override; virtual void SendEntityLook (const cEntity & a_Entity) override; virtual void SendEntityMetadata (const cEntity & a_Entity) override; + virtual void SendEntityPosition (const cEntity & a_Entity) override; virtual void SendEntityProperties (const cEntity & a_Entity) override; - virtual void SendEntityRelMove (const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ) override; - virtual void SendEntityRelMoveLook (const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ) override; virtual void SendEntityStatus (const cEntity & a_Entity, char a_Status) override; virtual void SendEntityVelocity (const cEntity & a_Entity) override; virtual void SendExplosion (double a_BlockX, double a_BlockY, double a_BlockZ, float a_Radius, const cVector3iArray & a_BlocksAffected, const Vector3d & a_PlayerMotion) override; @@ -90,7 +90,6 @@ public: virtual void SendParticleEffect (const AString & a_ParticleName, Vector3f a_Src, Vector3f a_Offset, float a_ParticleData, int a_ParticleAmount, std::array a_Data) override; virtual void SendPaintingSpawn (const cPainting & a_Painting) override; virtual void SendPlayerAbilities (void) override; - virtual void SendEntityAnimation (const cEntity & a_Entity, char a_Animation) override; virtual void SendPlayerListAddPlayer (const cPlayer & a_Player) override; virtual void SendPlayerListRemovePlayer (const cPlayer & a_Player) override; virtual void SendPlayerListUpdateGameMode (const cPlayer & a_Player) override; @@ -120,7 +119,6 @@ public: virtual void SendSpawnMob (const cMonster & a_Mob) override; virtual void SendStatistics (const cStatManager & a_Manager) override; virtual void SendTabCompletionResults (const AStringVector & a_Results) override; - virtual void SendTeleportEntity (const cEntity & a_Entity) override; virtual void SendThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ) override; virtual void SendTitleTimes (int a_FadeInTicks, int a_DisplayTicks, int a_FadeOutTicks) override; virtual void SendTimeUpdate (Int64 a_WorldAge, Int64 a_TimeOfDay, bool a_DoDaylightCycle) override; diff --git a/src/Protocol/Protocol_1_11.cpp b/src/Protocol/Protocol_1_11.cpp index 3ccb76d39..677662a6f 100644 --- a/src/Protocol/Protocol_1_11.cpp +++ b/src/Protocol/Protocol_1_11.cpp @@ -341,13 +341,13 @@ cProtocol_1_11_0::cProtocol_1_11_0(cClientHandle * a_Client, const AString & a_S -void cProtocol_1_11_0::SendCollectEntity(const cEntity & a_Entity, const cPlayer & a_Player, int a_Count) +void cProtocol_1_11_0::SendCollectEntity(const cEntity & a_Collected, const cEntity & a_Collector, unsigned a_Count) { ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, pktCollectEntity); - Pkt.WriteVarInt32(a_Entity.GetUniqueID()); - Pkt.WriteVarInt32(a_Player.GetUniqueID()); + Pkt.WriteVarInt32(a_Collected.GetUniqueID()); + Pkt.WriteVarInt32(a_Collector.GetUniqueID()); Pkt.WriteVarInt32(static_cast(a_Count)); } @@ -389,7 +389,7 @@ void cProtocol_1_11_0::SendSpawnMob(const cMonster & a_Mob) Pkt.WriteBEUInt64(0); Pkt.WriteBEUInt64(a_Mob.GetUniqueID()); Pkt.WriteVarInt32(GetProtocolMobType(a_Mob.GetMobType())); - Vector3d LastSentPos = a_Mob.GetLastSentPos(); + Vector3d LastSentPos = a_Mob.GetLastSentPosition(); Pkt.WriteBEDouble(LastSentPos.x); Pkt.WriteBEDouble(LastSentPos.y); Pkt.WriteBEDouble(LastSentPos.z); diff --git a/src/Protocol/Protocol_1_11.h b/src/Protocol/Protocol_1_11.h index b5c0bbeb8..a4d763d47 100644 --- a/src/Protocol/Protocol_1_11.h +++ b/src/Protocol/Protocol_1_11.h @@ -30,7 +30,7 @@ public: cProtocol_1_11_0(cClientHandle * a_Client, const AString &a_ServerAddress, UInt16 a_ServerPort, UInt32 a_State); - virtual void SendCollectEntity(const cEntity & a_Entity, const cPlayer & a_Player, int a_Count) override; + virtual void SendCollectEntity(const cEntity & a_Collected, const cEntity & a_Collector, unsigned a_Count) override; virtual void SendHideTitle (void) override; virtual void SendResetTitle (void) override; virtual void SendSpawnMob (const cMonster & a_Mob) override; diff --git a/src/Protocol/Protocol_1_8.cpp b/src/Protocol/Protocol_1_8.cpp index a2ea4eceb..4aa312fef 100644 --- a/src/Protocol/Protocol_1_8.cpp +++ b/src/Protocol/Protocol_1_8.cpp @@ -352,14 +352,14 @@ void cProtocol_1_8_0::SendChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSerial -void cProtocol_1_8_0::SendCollectEntity(const cEntity & a_Entity, const cPlayer & a_Player, int a_Count) +void cProtocol_1_8_0::SendCollectEntity(const cEntity & a_Collected, const cEntity & a_Collector, unsigned a_Count) { UNUSED(a_Count); ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, pktCollectEntity); - Pkt.WriteVarInt32(a_Entity.GetUniqueID()); - Pkt.WriteVarInt32(a_Player.GetUniqueID()); + Pkt.WriteVarInt32(a_Collected.GetUniqueID()); + Pkt.WriteVarInt32(a_Collector.GetUniqueID()); } @@ -430,6 +430,19 @@ void cProtocol_1_8_0::SendEditSign(int a_BlockX, int a_BlockY, int a_BlockZ) +void cProtocol_1_8_0::SendEntityAnimation(const cEntity & a_Entity, char a_Animation) +{ + ASSERT(m_State == 3); // In game mode? + + cPacketizer Pkt(*this, pktEntityAnimation); + Pkt.WriteVarInt32(a_Entity.GetUniqueID()); + Pkt.WriteBEInt8(a_Animation); +} + + + + + void cProtocol_1_8_0::SendEntityEffect(const cEntity & a_Entity, int a_EffectID, int a_Amplifier, int a_Duration) { ASSERT(m_State == 3); // In game mode? @@ -502,47 +515,59 @@ void cProtocol_1_8_0::SendEntityMetadata(const cEntity & a_Entity) -void cProtocol_1_8_0::SendEntityProperties(const cEntity & a_Entity) +void cProtocol_1_8_0::SendEntityPosition(const cEntity & a_Entity) { ASSERT(m_State == 3); // In game mode? - cPacketizer Pkt(*this, pktEntityProperties); - Pkt.WriteVarInt32(a_Entity.GetUniqueID()); - WriteEntityProperties(Pkt, a_Entity); -} - + const auto Delta = (a_Entity.GetPosition() - a_Entity.GetLastSentPosition()) * 32; + // Limitations of a byte + static const auto Max = std::numeric_limits::max(); + if ((std::abs(Delta.x) <= Max) && (std::abs(Delta.y) <= Max) && (std::abs(Delta.z) <= Max)) + { + const auto Move = static_cast>(Delta); + // Difference within limitations, use a relative move packet + if (a_Entity.IsOrientationDirty()) + { + cPacketizer Pkt(*this, pktEntityRelMoveLook); + Pkt.WriteVarInt32(a_Entity.GetUniqueID()); + Pkt.WriteBEInt8(Move.x); + Pkt.WriteBEInt8(Move.y); + Pkt.WriteBEInt8(Move.z); + Pkt.WriteByteAngle(a_Entity.GetYaw()); + Pkt.WriteByteAngle(a_Entity.GetPitch()); + Pkt.WriteBool(a_Entity.IsOnGround()); + } + else + { + cPacketizer Pkt(*this, pktEntityRelMove); + Pkt.WriteVarInt32(a_Entity.GetUniqueID()); + Pkt.WriteBEInt8(Move.x); + Pkt.WriteBEInt8(Move.y); + Pkt.WriteBEInt8(Move.z); + Pkt.WriteBool(a_Entity.IsOnGround()); + } -void cProtocol_1_8_0::SendEntityRelMove(const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ) -{ - ASSERT(m_State == 3); // In game mode? + return; + } - cPacketizer Pkt(*this, pktEntityRelMove); - Pkt.WriteVarInt32(a_Entity.GetUniqueID()); - Pkt.WriteBEInt8(a_RelX); - Pkt.WriteBEInt8(a_RelY); - Pkt.WriteBEInt8(a_RelZ); - Pkt.WriteBool(a_Entity.IsOnGround()); + // Too big a movement, do a teleport + SendEntityTeleport(a_Entity); } -void cProtocol_1_8_0::SendEntityRelMoveLook(const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ) +void cProtocol_1_8_0::SendEntityProperties(const cEntity & a_Entity) { ASSERT(m_State == 3); // In game mode? - cPacketizer Pkt(*this, pktEntityRelMoveLook); + cPacketizer Pkt(*this, pktEntityProperties); Pkt.WriteVarInt32(a_Entity.GetUniqueID()); - Pkt.WriteBEInt8(a_RelX); - Pkt.WriteBEInt8(a_RelY); - Pkt.WriteBEInt8(a_RelZ); - Pkt.WriteByteAngle(a_Entity.GetYaw()); - Pkt.WriteByteAngle(a_Entity.GetPitch()); - Pkt.WriteBool(a_Entity.IsOnGround()); + WriteEntityProperties(Pkt, a_Entity); } @@ -882,19 +907,6 @@ void cProtocol_1_8_0::SendPlayerAbilities(void) -void cProtocol_1_8_0::SendEntityAnimation(const cEntity & a_Entity, char a_Animation) -{ - ASSERT(m_State == 3); // In game mode? - - cPacketizer Pkt(*this, pktEntityAnimation); - Pkt.WriteVarInt32(a_Entity.GetUniqueID()); - Pkt.WriteBEInt8(a_Animation); -} - - - - - void cProtocol_1_8_0::SendParticleEffect(const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmount) { ASSERT(m_State == 3); // In game mode? @@ -1133,7 +1145,7 @@ void cProtocol_1_8_0::SendPlayerSpawn(const cPlayer & a_Player) cPacketizer Pkt(*this, pktSpawnOtherPlayer); Pkt.WriteVarInt32(a_Player.GetUniqueID()); Pkt.WriteUUID(a_Player.GetUUID()); - Vector3d LastSentPos = a_Player.GetLastSentPos(); + Vector3d LastSentPos = a_Player.GetLastSentPosition(); Pkt.WriteFPInt(LastSentPos.x); Pkt.WriteFPInt(LastSentPos.y + 0.001); // The "+ 0.001" is there because otherwise the player falls through the block they were standing on. Pkt.WriteFPInt(LastSentPos.z); @@ -1386,8 +1398,7 @@ void cProtocol_1_8_0::SendSpawnEntity(const cEntity & a_Entity) } } - cPacketizer Pkt(*this, pktSpawnObject); - WriteEntitySpawn(Pkt, a_Entity, EntityType, EntityData); + SendEntitySpawn(a_Entity, EntityType, EntityData); } @@ -1401,7 +1412,7 @@ void cProtocol_1_8_0::SendSpawnMob(const cMonster & a_Mob) cPacketizer Pkt(*this, pktSpawnMob); Pkt.WriteVarInt32(a_Mob.GetUniqueID()); Pkt.WriteBEUInt8(static_cast(GetProtocolMobType(a_Mob.GetMobType()))); - Vector3d LastSentPos = a_Mob.GetLastSentPos(); + Vector3d LastSentPos = a_Mob.GetLastSentPosition(); Pkt.WriteFPInt(LastSentPos.x); Pkt.WriteFPInt(LastSentPos.y); Pkt.WriteFPInt(LastSentPos.z); @@ -1458,24 +1469,6 @@ void cProtocol_1_8_0::SendTabCompletionResults(const AStringVector & a_Results) -void cProtocol_1_8_0::SendTeleportEntity(const cEntity & a_Entity) -{ - ASSERT(m_State == 3); // In game mode? - - cPacketizer Pkt(*this, pktTeleportEntity); - Pkt.WriteVarInt32(a_Entity.GetUniqueID()); - Pkt.WriteFPInt(a_Entity.GetPosX()); - Pkt.WriteFPInt(a_Entity.GetPosY()); - Pkt.WriteFPInt(a_Entity.GetPosZ()); - Pkt.WriteByteAngle(a_Entity.GetYaw()); - Pkt.WriteByteAngle(a_Entity.GetPitch()); - Pkt.WriteBool(a_Entity.IsOnGround()); -} - - - - - void cProtocol_1_8_0::SendThunderbolt(int a_BlockX, int a_BlockY, int a_BlockZ) { ASSERT(m_State == 3); // In game mode? @@ -3201,6 +3194,37 @@ void cProtocol_1_8_0::SendPacket(cPacketizer & a_Pkt) +void cProtocol_1_8_0::SendEntitySpawn(const cEntity & a_Entity, const UInt8 a_ObjectType, const Int32 a_ObjectData) +{ + ASSERT(m_State == 3); // In game mode? + + { + cPacketizer Pkt(*this, pktSpawnObject); + Pkt.WriteVarInt32(a_Entity.GetUniqueID()); + Pkt.WriteBEUInt8(a_ObjectType); + Pkt.WriteFPInt(a_Entity.GetPosX()); // Position appears to be ignored... + Pkt.WriteFPInt(a_Entity.GetPosY()); + Pkt.WriteFPInt(a_Entity.GetPosY()); + Pkt.WriteByteAngle(a_Entity.GetPitch()); + Pkt.WriteByteAngle(a_Entity.GetYaw()); + Pkt.WriteBEInt32(a_ObjectData); + + if (a_ObjectData != 0) + { + Pkt.WriteBEInt16(static_cast(a_Entity.GetSpeedX() * 400)); + Pkt.WriteBEInt16(static_cast(a_Entity.GetSpeedY() * 400)); + Pkt.WriteBEInt16(static_cast(a_Entity.GetSpeedZ() * 400)); + } + } + + // Otherwise 1.8 clients don't show the entity + SendEntityTeleport(a_Entity); +} + + + + + void cProtocol_1_8_0::WriteItem(cPacketizer & a_Pkt, const cItem & a_Item) { short ItemType = a_Item.m_ItemType; @@ -3831,25 +3855,16 @@ void cProtocol_1_8_0::WriteEntityProperties(cPacketizer & a_Pkt, const cEntity & -void cProtocol_1_8_0::WriteEntitySpawn(cPacketizer & a_Pkt, const cEntity & a_Entity, const UInt8 a_ObjectType, const Int32 a_ObjectData) +void cProtocol_1_8_0::SendEntityTeleport(const cEntity & a_Entity) { - ASSERT(m_State == 3); // In game mode? - - a_Pkt.WriteVarInt32(a_Entity.GetUniqueID()); - a_Pkt.WriteBEUInt8(a_ObjectType); - a_Pkt.WriteFPInt(a_Entity.GetPosX()); - a_Pkt.WriteFPInt(a_Entity.GetPosY()); - a_Pkt.WriteFPInt(a_Entity.GetPosY()); - a_Pkt.WriteByteAngle(a_Entity.GetPitch()); - a_Pkt.WriteByteAngle(a_Entity.GetYaw()); - a_Pkt.WriteBEInt32(a_ObjectData); - - if (a_ObjectData != 0) - { - a_Pkt.WriteBEInt16(static_cast(a_Entity.GetSpeedX() * 400)); - a_Pkt.WriteBEInt16(static_cast(a_Entity.GetSpeedY() * 400)); - a_Pkt.WriteBEInt16(static_cast(a_Entity.GetSpeedZ() * 400)); - } + cPacketizer Pkt(*this, pktTeleportEntity); + Pkt.WriteVarInt32(a_Entity.GetUniqueID()); + Pkt.WriteFPInt(a_Entity.GetPosX()); + Pkt.WriteFPInt(a_Entity.GetPosY()); + Pkt.WriteFPInt(a_Entity.GetPosZ()); + Pkt.WriteByteAngle(a_Entity.GetYaw()); + Pkt.WriteByteAngle(a_Entity.GetPitch()); + Pkt.WriteBool(a_Entity.IsOnGround()); } diff --git a/src/Protocol/Protocol_1_8.h b/src/Protocol/Protocol_1_8.h index 69ac1449a..42903a921 100644 --- a/src/Protocol/Protocol_1_8.h +++ b/src/Protocol/Protocol_1_8.h @@ -47,19 +47,19 @@ public: virtual void SendChat (const cCompositeChat & a_Message, eChatType a_Type, bool a_ShouldUseChatPrefixes) override; virtual void SendChatRaw (const AString & a_MessageRaw, eChatType a_Type) override; virtual void SendChunkData (int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer) override; - virtual void SendCollectEntity (const cEntity & a_Entity, const cPlayer & a_Player, int a_Count) override; + virtual void SendCollectEntity (const cEntity & a_Collected, const cEntity & a_Collector, unsigned a_Count) override; virtual void SendDestroyEntity (const cEntity & a_Entity) override; virtual void SendDetachEntity (const cEntity & a_Entity, const cEntity & a_PreviousVehicle) override; virtual void SendDisconnect (const AString & a_Reason) override; virtual void SendEditSign (int a_BlockX, int a_BlockY, int a_BlockZ) override; ///< Request the client to open up the sign editor for the sign (1.6+) + virtual void SendEntityAnimation (const cEntity & a_Entity, char a_Animation) override; virtual void SendEntityEffect (const cEntity & a_Entity, int a_EffectID, int a_Amplifier, int a_Duration) override; virtual void SendEntityEquipment (const cEntity & a_Entity, short a_SlotNum, const cItem & a_Item) override; virtual void SendEntityHeadLook (const cEntity & a_Entity) override; virtual void SendEntityLook (const cEntity & a_Entity) override; virtual void SendEntityMetadata (const cEntity & a_Entity) override; + virtual void SendEntityPosition (const cEntity & a_Entity) override; virtual void SendEntityProperties (const cEntity & a_Entity) override; - virtual void SendEntityRelMove (const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ) override; - virtual void SendEntityRelMoveLook (const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ) override; virtual void SendEntityStatus (const cEntity & a_Entity, char a_Status) override; virtual void SendEntityVelocity (const cEntity & a_Entity) override; virtual void SendExperience (void) override; @@ -77,7 +77,6 @@ public: virtual void SendMapData (const cMap & a_Map, int a_DataStartX, int a_DataStartY) override; virtual void SendPaintingSpawn (const cPainting & a_Painting) override; virtual void SendPlayerAbilities (void) override; - virtual void SendEntityAnimation (const cEntity & a_Entity, char a_Animation) override; virtual void SendParticleEffect (const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmount) override; virtual void SendParticleEffect (const AString & a_ParticleName, Vector3f a_Src, Vector3f a_Offset, float a_ParticleData, int a_ParticleAmount, std::array a_Data) override; virtual void SendPlayerListAddPlayer (const cPlayer & a_Player) override; @@ -107,7 +106,6 @@ public: virtual void SendSpawnMob (const cMonster & a_Mob) override; virtual void SendStatistics (const cStatManager & a_Manager) override; virtual void SendTabCompletionResults (const AStringVector & a_Results) override; - virtual void SendTeleportEntity (const cEntity & a_Entity) override; virtual void SendThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ) override; virtual void SendTitleTimes (int a_FadeInTicks, int a_DisplayTicks, int a_FadeOutTicks) override; virtual void SendTimeUpdate (Int64 a_WorldAge, Int64 a_TimeOfDay, bool a_DoDaylightCycle) override; @@ -228,6 +226,9 @@ protected: If the received value doesn't match any of our eBlockFace constants, BLOCK_FACE_NONE is returned. */ eBlockFace FaceIntToBlockFace(Int8 a_FaceInt); + /** Sends the entity type and entity-dependent data required for the entity to initially spawn. */ + virtual void SendEntitySpawn(const cEntity & a_Entity, const UInt8 a_ObjectType, const Int32 a_ObjectData); + /** Writes the item data into a packet. */ virtual void WriteItem(cPacketizer & a_Pkt, const cItem & a_Item); @@ -240,14 +241,16 @@ protected: /** Writes the entity properties for the specified entity, including the Count field. */ virtual void WriteEntityProperties(cPacketizer & a_Pkt, const cEntity & a_Entity); - /** Writes the entity type and entity-dependent data into a packet structure required for the entity to initially spawn. */ - virtual void WriteEntitySpawn(cPacketizer & a_Pkt, const cEntity & a_Entity, const UInt8 a_ObjectType, const Int32 a_ObjectData); - /** Writes the block entity data for the specified block entity into the packet. */ virtual void WriteBlockEntity(cPacketizer & a_Pkt, const cBlockEntity & a_BlockEntity); private: + /** Sends an entity teleport packet. + Mitigates a 1.8 bug where the position in the entity spawn packet is ignored, + and so entities don't show up until a teleport is sent. */ + void SendEntityTeleport(const cEntity & a_Entity); + /** Converts an entity to a protocol-specific entity type. Only entities that the Send Spawn Entity packet supports are valid inputs to this method */ UInt8 GetProtocolEntityType(const cEntity & a_Entity); diff --git a/src/Protocol/Protocol_1_9.cpp b/src/Protocol/Protocol_1_9.cpp index 10aed8cc1..150e81339 100644 --- a/src/Protocol/Protocol_1_9.cpp +++ b/src/Protocol/Protocol_1_9.cpp @@ -170,33 +170,50 @@ void cProtocol_1_9_0::SendEntityMetadata(const cEntity & a_Entity) -void cProtocol_1_9_0::SendEntityRelMove(const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ) +void cProtocol_1_9_0::SendEntityPosition(const cEntity & a_Entity) { ASSERT(m_State == 3); // In game mode? - cPacketizer Pkt(*this, pktEntityRelMove); - Pkt.WriteVarInt32(a_Entity.GetUniqueID()); - // TODO: 1.9 changed these from chars to shorts, meaning that there can be more percision and data. Other code needs to be updated for that. - Pkt.WriteBEInt16(a_RelX * 128); - Pkt.WriteBEInt16(a_RelY * 128); - Pkt.WriteBEInt16(a_RelZ * 128); - Pkt.WriteBool(a_Entity.IsOnGround()); -} - + const auto Delta = (a_Entity.GetPosition() - a_Entity.GetLastSentPosition()) * 32 * 128; + // Limitations of a short + static const auto Max = std::numeric_limits::max(); + if ((std::abs(Delta.x) <= Max) && (std::abs(Delta.y) <= Max) && (std::abs(Delta.z) <= Max)) + { + const auto Move = static_cast>(Delta); + // Difference within limitations, use a relative move packet + if (a_Entity.IsOrientationDirty()) + { + cPacketizer Pkt(*this, pktEntityRelMoveLook); + Pkt.WriteVarInt32(a_Entity.GetUniqueID()); + Pkt.WriteBEInt16(Move.x); + Pkt.WriteBEInt16(Move.y); + Pkt.WriteBEInt16(Move.z); + Pkt.WriteByteAngle(a_Entity.GetYaw()); + Pkt.WriteByteAngle(a_Entity.GetPitch()); + Pkt.WriteBool(a_Entity.IsOnGround()); + } + else + { + cPacketizer Pkt(*this, pktEntityRelMove); + Pkt.WriteVarInt32(a_Entity.GetUniqueID()); + Pkt.WriteBEInt16(Move.x); + Pkt.WriteBEInt16(Move.y); + Pkt.WriteBEInt16(Move.z); + Pkt.WriteBool(a_Entity.IsOnGround()); + } -void cProtocol_1_9_0::SendEntityRelMoveLook(const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ) -{ - ASSERT(m_State == 3); // In game mode? + return; + } - cPacketizer Pkt(*this, pktEntityRelMoveLook); + // Too big a movement, do a teleport + cPacketizer Pkt(*this, pktTeleportEntity); Pkt.WriteVarInt32(a_Entity.GetUniqueID()); - // TODO: 1.9 changed these from chars to shorts, meaning that there can be more percision and data. Other code needs to be updated for that. - Pkt.WriteBEInt16(a_RelX * 128); - Pkt.WriteBEInt16(a_RelY * 128); - Pkt.WriteBEInt16(a_RelZ * 128); + Pkt.WriteBEDouble(a_Entity.GetPosX()); + Pkt.WriteBEDouble(a_Entity.GetPosY()); + Pkt.WriteBEDouble(a_Entity.GetPosZ()); Pkt.WriteByteAngle(a_Entity.GetYaw()); Pkt.WriteByteAngle(a_Entity.GetPitch()); Pkt.WriteBool(a_Entity.IsOnGround()); @@ -386,7 +403,7 @@ void cProtocol_1_9_0::SendPlayerSpawn(const cPlayer & a_Player) cPacketizer Pkt(*this, pktSpawnOtherPlayer); Pkt.WriteVarInt32(a_Player.GetUniqueID()); Pkt.WriteUUID(a_Player.GetUUID()); - Vector3d LastSentPos = a_Player.GetLastSentPos(); + Vector3d LastSentPos = a_Player.GetLastSentPosition(); Pkt.WriteBEDouble(LastSentPos.x); Pkt.WriteBEDouble(LastSentPos.y + 0.001); // The "+ 0.001" is there because otherwise the player falls through the block they were standing on. Pkt.WriteBEDouble(LastSentPos.z); @@ -428,7 +445,7 @@ void cProtocol_1_9_0::SendSpawnMob(const cMonster & a_Mob) Pkt.WriteBEUInt64(0); Pkt.WriteBEUInt64(a_Mob.GetUniqueID()); Pkt.WriteBEUInt8(static_cast(GetProtocolMobType(a_Mob.GetMobType()))); - Vector3d LastSentPos = a_Mob.GetLastSentPos(); + Vector3d LastSentPos = a_Mob.GetLastSentPosition(); Pkt.WriteBEDouble(LastSentPos.x); Pkt.WriteBEDouble(LastSentPos.y); Pkt.WriteBEDouble(LastSentPos.z); @@ -446,24 +463,6 @@ void cProtocol_1_9_0::SendSpawnMob(const cMonster & a_Mob) -void cProtocol_1_9_0::SendTeleportEntity(const cEntity & a_Entity) -{ - ASSERT(m_State == 3); // In game mode? - - cPacketizer Pkt(*this, pktTeleportEntity); - Pkt.WriteVarInt32(a_Entity.GetUniqueID()); - Pkt.WriteBEDouble(a_Entity.GetPosX()); - Pkt.WriteBEDouble(a_Entity.GetPosY()); - Pkt.WriteBEDouble(a_Entity.GetPosZ()); - Pkt.WriteByteAngle(a_Entity.GetYaw()); - Pkt.WriteByteAngle(a_Entity.GetPitch()); - Pkt.WriteBool(a_Entity.IsOnGround()); -} - - - - - void cProtocol_1_9_0::SendThunderbolt(int a_BlockX, int a_BlockY, int a_BlockZ) { ASSERT(m_State == 3); // In game mode? @@ -1323,6 +1322,33 @@ eHand cProtocol_1_9_0::HandIntToEnum(Int32 a_Hand) +void cProtocol_1_9_0::SendEntitySpawn(const cEntity & a_Entity, const UInt8 a_ObjectType, const Int32 a_ObjectData) +{ + ASSERT(m_State == 3); // In game mode? + + cPacketizer Pkt(*this, pktSpawnObject); + Pkt.WriteVarInt32(a_Entity.GetUniqueID()); + + // TODO: Bad way to write a UUID, and it's not a true UUID, but this is functional for now. + Pkt.WriteBEUInt64(0); + Pkt.WriteBEUInt64(a_Entity.GetUniqueID()); + + Pkt.WriteBEUInt8(a_ObjectType); + Pkt.WriteBEDouble(a_Entity.GetPosX()); + Pkt.WriteBEDouble(a_Entity.GetPosY()); + Pkt.WriteBEDouble(a_Entity.GetPosZ()); + Pkt.WriteByteAngle(a_Entity.GetPitch()); + Pkt.WriteByteAngle(a_Entity.GetYaw()); + Pkt.WriteBEInt32(a_ObjectData); + Pkt.WriteBEInt16(static_cast(a_Entity.GetSpeedX() * 400)); + Pkt.WriteBEInt16(static_cast(a_Entity.GetSpeedY() * 400)); + Pkt.WriteBEInt16(static_cast(a_Entity.GetSpeedZ() * 400)); +} + + + + + void cProtocol_1_9_0::WriteItem(cPacketizer & a_Pkt, const cItem & a_Item) { short ItemType = a_Item.m_ItemType; @@ -2173,32 +2199,6 @@ void cProtocol_1_9_0::WriteEntityProperties(cPacketizer & a_Pkt, const cEntity & -void cProtocol_1_9_0::WriteEntitySpawn(cPacketizer & a_Pkt, const cEntity & a_Entity, const UInt8 a_ObjectType, const Int32 a_ObjectData) -{ - ASSERT(m_State == 3); // In game mode? - - a_Pkt.WriteVarInt32(a_Entity.GetUniqueID()); - - // TODO: Bad way to write a UUID, and it's not a true UUID, but this is functional for now. - a_Pkt.WriteBEUInt64(0); - a_Pkt.WriteBEUInt64(a_Entity.GetUniqueID()); - - a_Pkt.WriteBEUInt8(a_ObjectType); - a_Pkt.WriteBEDouble(a_Entity.GetPosX()); - a_Pkt.WriteBEDouble(a_Entity.GetPosY()); - a_Pkt.WriteBEDouble(a_Entity.GetPosZ()); - a_Pkt.WriteByteAngle(a_Entity.GetPitch()); - a_Pkt.WriteByteAngle(a_Entity.GetYaw()); - a_Pkt.WriteBEInt32(a_ObjectData); - a_Pkt.WriteBEInt16(static_cast(a_Entity.GetSpeedX() * 400)); - a_Pkt.WriteBEInt16(static_cast(a_Entity.GetSpeedY() * 400)); - a_Pkt.WriteBEInt16(static_cast(a_Entity.GetSpeedZ() * 400)); -} - - - - - //////////////////////////////////////////////////////////////////////////////// // cProtocol_1_9_1: diff --git a/src/Protocol/Protocol_1_9.h b/src/Protocol/Protocol_1_9.h index b4e945c1e..75fff9020 100644 --- a/src/Protocol/Protocol_1_9.h +++ b/src/Protocol/Protocol_1_9.h @@ -46,8 +46,7 @@ public: virtual void SendDetachEntity (const cEntity & a_Entity, const cEntity & a_PreviousVehicle) override; virtual void SendEntityEquipment (const cEntity & a_Entity, short a_SlotNum, const cItem & a_Item) override; virtual void SendEntityMetadata (const cEntity & a_Entity) override; - virtual void SendEntityRelMove (const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ) override; - virtual void SendEntityRelMoveLook (const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ) override; + virtual void SendEntityPosition (const cEntity & a_Entity) override; virtual void SendEntityStatus (const cEntity & a_Entity, char a_Status) override; virtual void SendExperienceOrb (const cExpOrb & a_ExpOrb) override; virtual void SendKeepAlive (UInt32 a_PingID) override; @@ -59,7 +58,6 @@ public: 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 SendSpawnMob (const cMonster & a_Mob) override; - virtual void SendTeleportEntity (const cEntity & a_Entity) override; virtual void SendThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ) override; virtual void SendUnleashEntity (const cEntity & a_Entity) override; virtual void SendUnloadChunk (int a_ChunkX, int a_ChunkZ) override; @@ -111,6 +109,9 @@ protected: If the received value doesn't match any of the know value, raise an assertion fail or return hMain. */ eHand HandIntToEnum(Int32 a_Hand); + /** Sends the entity type and entity-dependent data required for the entity to initially spawn. */ + virtual void SendEntitySpawn(const cEntity & a_Entity, const UInt8 a_ObjectType, const Int32 a_ObjectData) override; + /** Writes the item data into a packet. */ virtual void WriteItem(cPacketizer & a_Pkt, const cItem & a_Item) override; @@ -123,9 +124,6 @@ protected: /** Writes the entity properties for the specified entity, including the Count field. */ virtual void WriteEntityProperties(cPacketizer & a_Pkt, const cEntity & a_Entity) override; - /** Writes the entity type and entity-dependent data into a packet structure required for the entity to initially spawn. */ - virtual void WriteEntitySpawn(cPacketizer & a_Pkt, const cEntity & a_Entity, const UInt8 a_ObjectType, const Int32 a_ObjectData) override; - /** Writes the block entity data for the specified block entity into the packet. */ virtual void WriteBlockEntity(cPacketizer & a_Pkt, const cBlockEntity & a_BlockEntity) override; -- cgit v1.2.3