From 7a73fd467cfadfe3b3a5cf43d3eea9392f4c7f34 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Tue, 8 Nov 2022 22:14:45 +0000 Subject: Protocol: Use correct calculation for delta movements (#5455) * Protocol: Use correct calculation for delta movements --- src/ByteBuffer.cpp | 18 ++++++++++++++++++ src/ByteBuffer.h | 9 ++++++++- src/Entities/Entity.cpp | 5 ++--- src/Protocol/Protocol_1_8.cpp | 41 ++++++++++++++++++----------------------- src/Protocol/Protocol_1_8.h | 5 ----- src/Protocol/Protocol_1_9.cpp | 16 ++++++++++------ 6 files changed, 56 insertions(+), 38 deletions(-) diff --git a/src/ByteBuffer.cpp b/src/ByteBuffer.cpp index 46f2ba0d4..8121fc3ef 100644 --- a/src/ByteBuffer.cpp +++ b/src/ByteBuffer.cpp @@ -214,6 +214,24 @@ size_t cByteBuffer::GetReadableSpace(void) const +bool cByteBuffer::CanBEInt8Represent(int a_Value) +{ + return (-128 <= a_Value) && (a_Value <= 127); +} + + + + + +bool cByteBuffer::CanBEInt16Represent(int a_Value) +{ + return (-32768 <= a_Value) && (a_Value <= 32767); +} + + + + + bool cByteBuffer::CanReadBytes(size_t a_Count) const { CHECK_THREAD diff --git a/src/ByteBuffer.h b/src/ByteBuffer.h index 1d108fca2..664887132 100644 --- a/src/ByteBuffer.h +++ b/src/ByteBuffer.h @@ -31,6 +31,7 @@ their own synchronization. class cByteBuffer { public: + cByteBuffer(size_t a_BufferSize); ~cByteBuffer(); @@ -47,7 +48,13 @@ public: size_t GetReadableSpace(void) const; /** Returns the current data start index. For debugging purposes. */ - size_t GetDataStart(void) const { return m_DataStart; } + size_t GetDataStart(void) const { return m_DataStart; } + + /** Returns if the given value can fit in a protocol big-endian 8 bit integer. */ + static bool CanBEInt8Represent(int a_Value); + + /** Returns if the given value can fit in a protocol big-endian 16 bit integer. */ + static bool CanBEInt16Represent(int a_Value); /** Returns true if the specified amount of bytes are available for reading */ bool CanReadBytes(size_t a_Count) const; diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp index 0718da06c..c46f9e644 100644 --- a/src/Entities/Entity.cpp +++ b/src/Entities/Entity.cpp @@ -1970,7 +1970,7 @@ void cEntity::BroadcastMovementUpdate(const cClientHandle * a_Exclude) return; } - if (GetSpeed().SqrLength() > 0.001) + if (m_Speed.HasNonZeroLength()) { // Movin' m_World->BroadcastEntityVelocity(*this, a_Exclude); @@ -1986,8 +1986,7 @@ void cEntity::BroadcastMovementUpdate(const cClientHandle * a_Exclude) m_bHasSentNoSpeed = true; } - Vector3i Diff = (GetPosition() * 32.0).Floor() - (m_LastSentPosition * 32.0).Floor(); - if (Diff.HasNonZeroLength()) // Have we moved? + if ((m_Position - m_LastSentPosition).HasNonZeroLength()) // Have we moved? { m_World->BroadcastEntityPosition(*this, a_Exclude); diff --git a/src/Protocol/Protocol_1_8.cpp b/src/Protocol/Protocol_1_8.cpp index e949d6116..d56375a8d 100644 --- a/src/Protocol/Protocol_1_8.cpp +++ b/src/Protocol/Protocol_1_8.cpp @@ -579,12 +579,15 @@ void cProtocol_1_8_0::SendEntityPosition(const cEntity & a_Entity) { ASSERT(m_State == 3); // In game mode? - const auto Delta = (a_Entity.GetPosition() - a_Entity.GetLastSentPosition()) * 32; + const auto Delta = (a_Entity.GetPosition() * 32).Floor() - (a_Entity.GetLastSentPosition() * 32).Floor(); - // 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)) + // Ensure that the delta has enough precision and is within range of a BEInt8: + if ( + Delta.HasNonZeroLength() && + cByteBuffer::CanBEInt8Represent(Delta.x) && + cByteBuffer::CanBEInt8Represent(Delta.y) && + cByteBuffer::CanBEInt8Represent(Delta.z) + ) { const auto Move = static_cast>(Delta); @@ -613,8 +616,16 @@ void cProtocol_1_8_0::SendEntityPosition(const cEntity & a_Entity) return; } - // Too big a movement, do a teleport - SendEntityTeleport(a_Entity); + // Too big or small a movement, do a teleport. + + 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()); } @@ -4202,22 +4213,6 @@ void cProtocol_1_8_0::HandlePacket(cByteBuffer & a_Buffer) -void cProtocol_1_8_0::SendEntityTeleport(const cEntity & a_Entity) -{ - 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::StartEncryption(const Byte * a_Key) { m_Encryptor.Init(a_Key, a_Key); diff --git a/src/Protocol/Protocol_1_8.h b/src/Protocol/Protocol_1_8.h index eaa8813be..ed13399ef 100644 --- a/src/Protocol/Protocol_1_8.h +++ b/src/Protocol/Protocol_1_8.h @@ -270,10 +270,5 @@ private: /** Handle a complete packet stored in the given buffer. */ void HandlePacket(cByteBuffer & a_Buffer); - /** 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); - void StartEncryption(const Byte * a_Key); } ; diff --git a/src/Protocol/Protocol_1_9.cpp b/src/Protocol/Protocol_1_9.cpp index dd2133f77..9a4bcdc4a 100644 --- a/src/Protocol/Protocol_1_9.cpp +++ b/src/Protocol/Protocol_1_9.cpp @@ -307,12 +307,15 @@ void cProtocol_1_9_0::SendEntityPosition(const cEntity & a_Entity) { ASSERT(m_State == 3); // In game mode? - const auto Delta = (a_Entity.GetPosition() - a_Entity.GetLastSentPosition()) * 32 * 128; + const auto Delta = (a_Entity.GetPosition() * 32 * 128).Floor() - (a_Entity.GetLastSentPosition() * 32 * 128).Floor(); - // 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)) + // Ensure that the delta has enough precision and is within range of a BEInt16: + if ( + Delta.HasNonZeroLength() && + cByteBuffer::CanBEInt16Represent(Delta.x) && + cByteBuffer::CanBEInt16Represent(Delta.y) && + cByteBuffer::CanBEInt16Represent(Delta.z) + ) { const auto Move = static_cast>(Delta); @@ -341,7 +344,8 @@ void cProtocol_1_9_0::SendEntityPosition(const cEntity & a_Entity) return; } - // Too big a movement, do a teleport + // Too big or small a movement, do a teleport. + cPacketizer Pkt(*this, pktTeleportEntity); Pkt.WriteVarInt32(a_Entity.GetUniqueID()); Pkt.WriteBEDouble(a_Entity.GetPosX()); -- cgit v1.2.3