1
0
Fork 0

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
This commit is contained in:
Tiger Wang 2020-05-04 09:10:47 +01:00 committed by GitHub
parent 258318ab98
commit 07ca095740
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 294 additions and 404 deletions

View File

@ -32,7 +32,7 @@ public:
virtual void BroadcastChatFatal (const AString & a_Message, const cClientHandle * a_Exclude = nullptr) = 0;
virtual void BroadcastChatDeath (const AString & a_Message, const cClientHandle * a_Exclude = nullptr) = 0;
virtual void BroadcastChat (const cCompositeChat & a_Message, const cClientHandle * a_Exclude = nullptr) = 0;
virtual void BroadcastCollectEntity (const cEntity & a_Pickup, const cPlayer & a_Player, int a_Count, const cClientHandle * a_Exclude = nullptr) = 0;
virtual void BroadcastCollectEntity (const cEntity & a_Collected, const cEntity & a_Collector, unsigned a_Count, const cClientHandle * a_Exclude = nullptr) = 0;
virtual void BroadcastDestroyEntity (const cEntity & a_Entity, const cClientHandle * a_Exclude = nullptr) = 0;
virtual void BroadcastDetachEntity (const cEntity & a_Entity, const cEntity & a_PreviousVehicle) = 0;
virtual void BroadcastEntityEffect (const cEntity & a_Entity, int a_EffectID, int a_Amplifier, int a_Duration, const cClientHandle * a_Exclude = nullptr) = 0;
@ -40,8 +40,7 @@ public:
virtual void BroadcastEntityHeadLook (const cEntity & a_Entity, const cClientHandle * a_Exclude = nullptr) = 0;
virtual void BroadcastEntityLook (const cEntity & a_Entity, const cClientHandle * a_Exclude = nullptr) = 0;
virtual void BroadcastEntityMetadata (const cEntity & a_Entity, const cClientHandle * a_Exclude = nullptr) = 0;
virtual void BroadcastEntityRelMove (const cEntity & a_Entity, Vector3<Int8> a_RelMove, const cClientHandle * a_Exclude = nullptr) = 0;
virtual void BroadcastEntityRelMoveLook (const cEntity & a_Entity, Vector3<Int8> a_RelMove, const cClientHandle * a_Exclude = nullptr) = 0;
virtual void BroadcastEntityPosition (const cEntity & a_Entity, const cClientHandle * a_Exclude = nullptr) = 0;
virtual void BroadcastEntityStatus (const cEntity & a_Entity, Int8 a_Status, const cClientHandle * a_Exclude = nullptr) = 0;
virtual void BroadcastEntityVelocity (const cEntity & a_Entity, const cClientHandle * a_Exclude = nullptr) = 0;
virtual void BroadcastEntityAnimation (const cEntity & a_Entity, Int8 a_Animation, const cClientHandle * a_Exclude = nullptr) = 0;
@ -60,7 +59,6 @@ public:
virtual void BroadcastSoundEffect (const AString & a_SoundName, Vector3d a_Position, float a_Volume, float a_Pitch, const cClientHandle * a_Exclude = nullptr) = 0;
virtual void BroadcastSoundParticleEffect (const EffectID a_EffectID, Vector3i a_SrcPos, int a_Data, const cClientHandle * a_Exclude = nullptr) = 0;
virtual void BroadcastSpawnEntity (cEntity & a_Entity, const cClientHandle * a_Exclude = nullptr) = 0;
virtual void BroadcastTeleportEntity (const cEntity & a_Entity, const cClientHandle * a_Exclude = nullptr) = 0;
virtual void BroadcastThunderbolt (Vector3i a_BlockPos, const cClientHandle * a_Exclude = nullptr) = 0;
virtual void BroadcastTimeUpdate (const cClientHandle * a_Exclude = nullptr) = 0;
virtual void BroadcastUnleashEntity (const cEntity & a_Entity) = 0;

View File

@ -197,11 +197,11 @@ void cWorld::BroadcastChat(const cCompositeChat & a_Message, const cClientHandle
void cWorld::BroadcastCollectEntity(const cEntity & a_Entity, const cPlayer & a_Player, int a_Count, const cClientHandle * a_Exclude)
void cWorld::BroadcastCollectEntity(const cEntity & a_Collected, const cEntity & a_Collector, unsigned a_Count, const cClientHandle * a_Exclude)
{
ForClientsWithEntity(a_Entity, *this, a_Exclude, [&](cClientHandle & a_Client)
ForClientsWithEntity(a_Collected, *this, a_Exclude, [&](cClientHandle & a_Client)
{
a_Client.SendCollectEntity(a_Entity, a_Player, a_Count);
a_Client.SendCollectEntity(a_Collected, a_Collector, a_Count);
}
);
}
@ -314,24 +314,11 @@ void cWorld::BroadcastEntityMetadata(const cEntity & a_Entity, const cClientHand
void cWorld::BroadcastEntityRelMove(const cEntity & a_Entity, Vector3<Int8> a_RelMove, const cClientHandle * a_Exclude)
void cWorld::BroadcastEntityPosition(const cEntity & a_Entity, const cClientHandle * a_Exclude)
{
ForClientsWithEntity(a_Entity, *this, a_Exclude, [&](cClientHandle & a_Client)
ForClientsInWorld(*this, a_Exclude, [&](cClientHandle & a_Client)
{
a_Client.SendEntityRelMove(a_Entity, a_RelMove.x, a_RelMove.y, a_RelMove.z);
}
);
}
void cWorld::BroadcastEntityRelMoveLook(const cEntity & a_Entity, Vector3<Int8> a_RelMove, const cClientHandle * a_Exclude)
{
ForClientsWithEntity(a_Entity, *this, a_Exclude, [&](cClientHandle & a_Client)
{
a_Client.SendEntityRelMoveLook(a_Entity, a_RelMove.x, a_RelMove.y, a_RelMove.z);
a_Client.SendEntityPosition(a_Entity);
}
);
}
@ -561,19 +548,6 @@ void cWorld::BroadcastSpawnEntity(cEntity & a_Entity, const cClientHandle * a_Ex
void cWorld::BroadcastTeleportEntity(const cEntity & a_Entity, const cClientHandle * a_Exclude)
{
ForClientsInWorld(*this, a_Exclude, [&](cClientHandle & a_Client)
{
a_Client.SendTeleportEntity(a_Entity);
}
);
}
void cWorld::BroadcastThunderbolt(Vector3i a_BlockPos, const cClientHandle * a_Exclude)
{
ForClientsWithChunkAtPos(a_BlockPos, *this, a_Exclude, [&](cClientHandle & a_Client)

View File

@ -2497,9 +2497,9 @@ void cClientHandle::SendChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSerializ
void cClientHandle::SendCollectEntity(const cEntity & a_Entity, const cPlayer & a_Player, int a_Count)
void cClientHandle::SendCollectEntity(const cEntity & a_Collected, const cEntity & a_Collector, unsigned a_Count)
{
m_Protocol->SendCollectEntity(a_Entity, a_Player, a_Count);
m_Protocol->SendCollectEntity(a_Collected, a_Collector, a_Count);
}
@ -2603,22 +2603,9 @@ void cClientHandle::SendEntityMetadata(const cEntity & a_Entity)
void cClientHandle::SendEntityRelMove(const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ)
void cClientHandle::SendEntityPosition(const cEntity & a_Entity)
{
ASSERT(a_Entity.GetUniqueID() != m_Player->GetUniqueID()); // Must not send for self
m_Protocol->SendEntityRelMove(a_Entity, a_RelX, a_RelY, a_RelZ);
}
void cClientHandle::SendEntityRelMoveLook(const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ)
{
ASSERT(a_Entity.GetUniqueID() != m_Player->GetUniqueID()); // Must not send for self
m_Protocol->SendEntityRelMoveLook(a_Entity, a_RelX, a_RelY, a_RelZ);
m_Protocol->SendEntityPosition(a_Entity);
}
@ -3058,15 +3045,6 @@ void cClientHandle::SendTabCompletionResults(const AStringVector & a_Results)
void cClientHandle::SendTeleportEntity(const cEntity & a_Entity)
{
m_Protocol->SendTeleportEntity(a_Entity);
}
void cClientHandle::SendThunderbolt(int a_BlockX, int a_BlockY, int a_BlockZ)
{
m_Protocol->SendThunderbolt(a_BlockX, a_BlockY, a_BlockZ);

View File

@ -154,7 +154,7 @@ public: // tolua_export
void SendChatSystem (const AString & a_Message, eMessageType a_ChatPrefix, const AString & a_AdditionalData = "");
void SendChatSystem (const cCompositeChat & a_Message);
void SendChunkData (int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer);
void SendCollectEntity (const cEntity & a_Entity, const cPlayer & a_Player, int a_Count);
void SendCollectEntity (const cEntity & a_Collected, const cEntity & a_Collector, unsigned a_Count);
void SendDestroyEntity (const cEntity & a_Entity);
void SendDetachEntity (const cEntity & a_Entity, const cEntity & a_PreviousVehicle);
void SendDisconnect (const AString & a_Reason);
@ -166,8 +166,7 @@ public: // tolua_export
void SendEntityHeadLook (const cEntity & a_Entity);
void SendEntityLook (const cEntity & a_Entity);
void SendEntityMetadata (const cEntity & a_Entity);
void SendEntityRelMove (const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ);
void SendEntityRelMoveLook (const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ);
void SendEntityPosition (const cEntity & a_Entity);
void SendEntityStatus (const cEntity & a_Entity, char a_Status);
void SendEntityVelocity (const cEntity & a_Entity);
void SendExperience (void);
@ -211,7 +210,6 @@ public: // tolua_export
void SendSpawnMob (const cMonster & a_Mob);
void SendStatistics (const cStatManager & a_Manager);
void SendTabCompletionResults (const AStringVector & a_Results);
void SendTeleportEntity (const cEntity & a_Entity);
void SendThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ);
void SendTitleTimes (int a_FadeInTicks, int a_DisplayTicks, int a_FadeOutTicks); // tolua_export
void SendTimeUpdate (Int64 a_WorldAge, Int64 a_TimeOfDay, bool a_DoDaylightCycle); // tolua_export

View File

@ -15,8 +15,6 @@ cArrowEntity::cArrowEntity(cEntity * a_Creator, Vector3d a_Pos, Vector3d a_Speed
m_DamageCoeff(2),
m_IsCritical(false),
m_Timer(0),
m_HitGroundTimer(0),
m_HasTeleported(false),
m_bIsCollected(false)
{
SetMass(0.1);
@ -191,19 +189,6 @@ void cArrowEntity::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
if (m_IsInGround)
{
if (!m_HasTeleported) // Sent a teleport already, don't do again
{
if (m_HitGroundTimer > std::chrono::milliseconds(500))
{
m_World->BroadcastTeleportEntity(*this);
m_HasTeleported = true;
}
else
{
m_HitGroundTimer += a_Dt;
}
}
if (m_World->GetBlock(m_HitBlockPos) == E_BLOCK_AIR) // Block attached to was destroyed?
{
m_IsInGround = false; // Yes, begin simulating physics again

View File

@ -92,12 +92,6 @@ protected:
/** Timer for pickup collection animation or five minute timeout */
std::chrono::milliseconds m_Timer;
/** Timer for client arrow position confirmation via TeleportEntity */
std::chrono::milliseconds m_HitGroundTimer;
// Whether the arrow has already been teleported into the proper position in the ground.
bool m_HasTeleported;
/** If true, the arrow is in the process of being collected - don't go to anyone else */
bool m_bIsCollected;

View File

@ -49,19 +49,11 @@ void cBoat::BroadcastMovementUpdate(const cClientHandle * a_Exclude)
}
Vector3i Diff = (GetPosition() * 32.0).Floor() - (m_LastSentPosition * 32.0).Floor();
if (Diff.HasNonZeroLength()) // Have we moved?
{
if ((abs(Diff.x) <= 127) && (abs(Diff.y) <= 127) && (abs(Diff.z) <= 127)) // Limitations of a Byte
{
m_World->BroadcastEntityRelMove(*this, Vector3<Int8>(Diff), a_Exclude);
}
else
{
// Too big a movement, do a teleport
m_World->BroadcastTeleportEntity(*this, a_Exclude);
}
m_World->BroadcastEntityPosition(*this, a_Exclude);
m_LastSentPosition = GetPosition();
m_bDirtyOrientation = false;
}
}

View File

@ -1917,12 +1917,7 @@ void cEntity::TeleportToCoords(double a_PosX, double a_PosY, double a_PosZ)
// ask the plugins to allow teleport to the new position.
if (!cRoot::Get()->GetPluginManager()->CallHookEntityTeleport(*this, m_LastPosition, Vector3d(a_PosX, a_PosY, a_PosZ)))
{
ResetPosition({a_PosX, a_PosY, a_PosZ});
auto world = m_World;
if (world != nullptr) // The entity might not be in a world yet (just spawned, in cWorld::m_EntitiesToAdd)
{
world->BroadcastTeleportEntity(*this);
}
SetPosition({a_PosX, a_PosY, a_PosZ});
}
}
@ -1938,51 +1933,31 @@ void cEntity::BroadcastMovementUpdate(const cClientHandle * a_Exclude)
return;
}
if (GetSpeed().HasNonZeroLength())
if (GetSpeed().SqrLength() > 0.001)
{
// Movin'
m_World->BroadcastEntityVelocity(*this, a_Exclude);
m_bHasSentNoSpeed = false;
}
else
else if (!m_bHasSentNoSpeed)
{
// Speed is zero, send this to clients once only as well as an absolute position
if (!m_bHasSentNoSpeed)
{
m_World->BroadcastEntityVelocity(*this, a_Exclude);
m_World->BroadcastTeleportEntity(*this, a_Exclude);
m_LastSentPosition = GetPosition();
m_bHasSentNoSpeed = true;
}
m_World->BroadcastEntityVelocity(*this, a_Exclude);
m_World->BroadcastEntityPosition(*this, a_Exclude);
m_LastSentPosition = GetPosition();
m_bDirtyOrientation = false;
m_bHasSentNoSpeed = true;
}
// TODO: Pickups move disgracefully if relative move packets are sent as opposed to just velocity. Have a system to send relmove only when SetPosXXX() is called with a large difference in position
Vector3i Diff = (GetPosition() * 32.0).Floor() - (m_LastSentPosition * 32.0).Floor();
if (Diff.HasNonZeroLength()) // Have we moved?
{
if ((abs(Diff.x) <= 127) && (abs(Diff.y) <= 127) && (abs(Diff.z) <= 127)) // Limitations of a Byte
{
// Difference within Byte limitations, use a relative move packet
if (m_bDirtyOrientation)
{
m_World->BroadcastEntityRelMoveLook(*this, Vector3<Int8>(Diff), a_Exclude);
m_bDirtyOrientation = false;
}
else
{
m_World->BroadcastEntityRelMove(*this, Vector3<Int8>(Diff), a_Exclude);
}
// Clients seem to store two positions, one for the velocity packet and one for the teleport / relmove packet
// The latter is only changed with a relmove / teleport, and m_LastSentPosition stores this position
m_LastSentPosition = GetPosition();
}
else
{
// Too big a movement, do a teleport
m_World->BroadcastTeleportEntity(*this, a_Exclude);
m_LastSentPosition = GetPosition(); // See above
m_bDirtyOrientation = false;
}
m_World->BroadcastEntityPosition(*this, a_Exclude);
// Clients seem to store two positions, one for the velocity packet and one for the teleport / relmove packet
// The latter is only changed with a relmove / teleport, and m_LastSentPosition stores this position
m_LastSentPosition = GetPosition();
m_bDirtyOrientation = false;
}
if (m_bDirtyHead)
@ -1990,6 +1965,7 @@ void cEntity::BroadcastMovementUpdate(const cClientHandle * a_Exclude)
m_World->BroadcastEntityHeadLook(*this, a_Exclude);
m_bDirtyHead = false;
}
if (m_bDirtyOrientation)
{
// Send individual update in case above (sending with rel-move packet) wasn't done
@ -2076,6 +2052,15 @@ bool cEntity::IsAttachedTo(const cEntity * a_Entity) const
bool cEntity::IsOrientationDirty() const
{
return m_bDirtyOrientation;
}
void cEntity::SetHeadYaw(double a_HeadYaw)
{
m_HeadYaw = a_HeadYaw;

View File

@ -338,7 +338,7 @@ public:
/** Returns the last position we sent to all the clients. Use this to
initialize clients with our position. */
Vector3d GetLastSentPos(void) const { return m_LastSentPosition; }
Vector3d GetLastSentPosition(void) const { return m_LastSentPosition; }
/** Destroy the entity without scheduling memory freeing. This should only be used by cChunk or cClientHandle for internal memory management. */
void DestroyNoScheduling(bool a_ShouldBroadcast);
@ -511,6 +511,10 @@ public:
/** Returns true if this entity is attached to the specified entity */
bool IsAttachedTo(const cEntity * a_Entity) const;
/** Returns whether the entity's orientation has been set manually.
Primarily inteded for protocol use. */
bool IsOrientationDirty() const;
/** Makes sure head yaw is not over the specified range. */
void WrapHeadYaw();

View File

@ -59,10 +59,7 @@ public:
if (Item.m_ItemCount <= 0)
{
/* Experimental: show animation pickups getting together */
auto Diff = (m_Pickup->GetPosition() * 32.0).Floor() - (EntityPos * 32.0).Floor();
a_Entity.GetWorld()->BroadcastEntityRelMove(a_Entity, Vector3<char>(Diff));
/* End of experimental animation */
a_Entity.GetWorld()->BroadcastCollectEntity(a_Entity, *m_Pickup, static_cast<unsigned>(CombineCount));
a_Entity.Destroy();
// Reset the timer
@ -253,7 +250,7 @@ bool cPickup::CollectedBy(cPlayer & a_Dest)
}
m_Item.m_ItemCount -= NumAdded;
m_World->BroadcastCollectEntity(*this, a_Dest, NumAdded);
m_World->BroadcastCollectEntity(*this, a_Dest, static_cast<unsigned>(NumAdded));
// Also send the "pop" sound effect with a somewhat random pitch (fast-random using EntityID ;)
m_World->BroadcastSoundEffect("entity.item.pickup", GetPosition(), 0.3f, (1.2f + (static_cast<float>((GetUniqueID() * 23) % 32)) / 64));

View File

@ -681,6 +681,24 @@ void cPlayer::AddFoodExhaustion(double a_Exhaustion)
void cPlayer::TossItems(const cItems & a_Items)
{
if (IsGameModeSpectator()) // Players can't toss items in spectator
{
return;
}
m_Stats.AddValue(statItemsDropped, static_cast<StatValue>(a_Items.Size()));
const auto Speed = (GetLookVector() + Vector3d(0, 0.2, 0)) * 6; // A dash of height and a dollop of speed
const auto Position = GetEyePosition() - Vector3d(0, 0.2, 0); // Correct for eye-height weirdness
m_World->SpawnItemPickups(a_Items, Position, Speed, true); // 'true' because created by player
}
void cPlayer::StartEating(void)
{
// Set the timer:
@ -1647,11 +1665,10 @@ void cPlayer::TeleportToCoords(double a_PosX, double a_PosY, double a_PosZ)
// ask plugins to allow teleport to the new position.
if (!cRoot::Get()->GetPluginManager()->CallHookEntityTeleport(*this, m_LastPosition, Vector3d(a_PosX, a_PosY, a_PosZ)))
{
ResetPosition({a_PosX, a_PosY, a_PosZ});
SetPosition({a_PosX, a_PosY, a_PosZ});
FreezeInternal(GetPosition(), false);
m_bIsTeleporting = true;
m_World->BroadcastTeleportEntity(*this, GetClientHandle());
m_ClientHandle->SendPlayerMoveLook();
}
}
@ -2017,25 +2034,6 @@ void cPlayer::TossPickup(const cItem & a_Item)
void cPlayer::TossItems(const cItems & a_Items)
{
if (IsGameModeSpectator()) // Players can't toss items in spectator
{
return;
}
m_Stats.AddValue(statItemsDropped, static_cast<StatValue>(a_Items.Size()));
double vX = 0, vY = 0, vZ = 0;
EulerToVector(-GetYaw(), GetPitch(), vZ, vX, vY);
vY = -vY * 2 + 1.f;
m_World->SpawnItemPickups(a_Items, GetPosX(), GetEyeHeight(), GetPosZ(), vX * 3, vY * 3, vZ * 3, true); // 'true' because created by player
}
void cPlayer::DoMoveToWorld(const cEntity::sWorldChangeInfo & a_WorldChangeInfo)
{
ASSERT(a_WorldChangeInfo.m_NewWorld != nullptr);

View File

@ -372,6 +372,9 @@ public:
// tolua_end
/** Tosses a list of items. */
void TossItems(const cItems & a_Items);
/** Sets a player's in-bed state
We can't be sure plugins will keep this value updated, so no exporting
If value is false (not in bed), will update players of the fact that they have been ejected from the bed
@ -769,9 +772,6 @@ protected:
/** Called in each tick if the player is fishing to make sure the floater dissapears when the player doesn't have a fishing rod as equipped item. */
void HandleFloater(void);
/** Tosses a list of items. */
void TossItems(const cItems & a_Items);
/** Returns the filename for the player data based on the UUID given.
This can be used both for online and offline UUIDs. */
AString GetUUIDFileName(const cUUID & a_UUID);

View File

@ -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<int, 2> 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;

View File

@ -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,6 +351,16 @@ void cProtocolRecognizer::SendEntityMetadata(const cEntity & a_Entity)
void cProtocolRecognizer::SendEntityPosition(const cEntity & a_Entity)
{
ASSERT(m_Protocol != nullptr);
m_Protocol->SendEntityPosition(a_Entity);
}
void cProtocolRecognizer::SendEntityProperties(const cEntity & a_Entity)
{
ASSERT(m_Protocol != nullptr);
@ -351,26 +371,6 @@ void cProtocolRecognizer::SendEntityProperties(const cEntity & a_Entity)
void cProtocolRecognizer::SendEntityRelMove(const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ)
{
ASSERT(m_Protocol != nullptr);
m_Protocol->SendEntityRelMove(a_Entity, a_RelX, a_RelY, a_RelZ);
}
void cProtocolRecognizer::SendEntityRelMoveLook(const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ)
{
ASSERT(m_Protocol != nullptr);
m_Protocol->SendEntityRelMoveLook(a_Entity, a_RelX, a_RelY, a_RelZ);
}
void cProtocolRecognizer::SendEntityStatus(const cEntity & a_Entity, char a_Status)
{
ASSERT(m_Protocol != nullptr);
@ -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);

View File

@ -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<int, 2> 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;

View File

@ -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<UInt32>(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);

View File

@ -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;

View File

@ -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,6 +515,52 @@ void cProtocol_1_8_0::SendEntityMetadata(const cEntity & a_Entity)
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;
// Limitations of a byte
static const auto Max = std::numeric_limits<Int8>::max();
if ((std::abs(Delta.x) <= Max) && (std::abs(Delta.y) <= Max) && (std::abs(Delta.z) <= Max))
{
const auto Move = static_cast<Vector3<Int8>>(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());
}
return;
}
// Too big a movement, do a teleport
SendEntityTeleport(a_Entity);
}
void cProtocol_1_8_0::SendEntityProperties(const cEntity & a_Entity)
{
ASSERT(m_State == 3); // In game mode?
@ -515,40 +574,6 @@ void cProtocol_1_8_0::SendEntityProperties(const cEntity & a_Entity)
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?
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());
}
void cProtocol_1_8_0::SendEntityRelMoveLook(const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ)
{
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, pktEntityRelMoveLook);
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());
}
void cProtocol_1_8_0::SendEntityStatus(const cEntity & a_Entity, char a_Status)
{
ASSERT(m_State == 3); // In game mode?
@ -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<Byte>(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<Int16>(a_Entity.GetSpeedX() * 400));
Pkt.WriteBEInt16(static_cast<Int16>(a_Entity.GetSpeedY() * 400));
Pkt.WriteBEInt16(static_cast<Int16>(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<Int16>(a_Entity.GetSpeedX() * 400));
a_Pkt.WriteBEInt16(static_cast<Int16>(a_Entity.GetSpeedY() * 400));
a_Pkt.WriteBEInt16(static_cast<Int16>(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());
}

View File

@ -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<int, 2> 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);

View File

@ -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);
const auto Delta = (a_Entity.GetPosition() - a_Entity.GetLastSentPosition()) * 32 * 128;
// Limitations of a short
static const auto Max = std::numeric_limits<Int16>::max();
if ((std::abs(Delta.x) <= Max) && (std::abs(Delta.y) <= Max) && (std::abs(Delta.z) <= Max))
{
const auto Move = static_cast<Vector3<Int16>>(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());
}
return;
}
// 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.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?
cPacketizer Pkt(*this, pktEntityRelMoveLook);
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<Byte>(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<Int16>(a_Entity.GetSpeedX() * 400));
Pkt.WriteBEInt16(static_cast<Int16>(a_Entity.GetSpeedY() * 400));
Pkt.WriteBEInt16(static_cast<Int16>(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<Int16>(a_Entity.GetSpeedX() * 400));
a_Pkt.WriteBEInt16(static_cast<Int16>(a_Entity.GetSpeedY() * 400));
a_Pkt.WriteBEInt16(static_cast<Int16>(a_Entity.GetSpeedZ() * 400));
}
////////////////////////////////////////////////////////////////////////////////
// cProtocol_1_9_1:

View File

@ -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;

View File

@ -2620,10 +2620,7 @@ void cSlotAreaTemporary::TossItems(cPlayer & a_Player, int a_Begin, int a_End)
Item.Empty();
} // for i - itr->second[]
double vX = 0, vY = 0, vZ = 0;
EulerToVector(-a_Player.GetYaw(), a_Player.GetPitch(), vZ, vX, vY);
vY = -vY * 2 + 1.f;
a_Player.GetWorld()->SpawnItemPickups(Drops, a_Player.GetPosX(), a_Player.GetPosY() + 1.6f, a_Player.GetPosZ(), vX * 3, vY * 3, vZ * 3, true); // 'true' because player created
a_Player.TossItems(Drops);
}

View File

@ -182,7 +182,7 @@ public:
virtual void BroadcastChat (const cCompositeChat & a_Message, const cClientHandle * a_Exclude = nullptr) override;
// tolua_end
virtual void BroadcastCollectEntity (const cEntity & a_Pickup, const cPlayer & a_Player, int a_Count, const cClientHandle * a_Exclude = nullptr) override;
virtual void BroadcastCollectEntity (const cEntity & a_Collected, const cEntity & a_Collector, unsigned a_Count, const cClientHandle * a_Exclude = nullptr) override;
virtual void BroadcastDestroyEntity (const cEntity & a_Entity, const cClientHandle * a_Exclude = nullptr) override;
virtual void BroadcastDetachEntity (const cEntity & a_Entity, const cEntity & a_PreviousVehicle) override;
virtual void BroadcastEntityEffect (const cEntity & a_Entity, int a_EffectID, int a_Amplifier, int a_Duration, const cClientHandle * a_Exclude = nullptr) override;
@ -190,8 +190,7 @@ public:
virtual void BroadcastEntityHeadLook (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 BroadcastEntityRelMove (const cEntity & a_Entity, Vector3<Int8> a_RelMove, const cClientHandle * a_Exclude = nullptr) override;
virtual void BroadcastEntityRelMoveLook (const cEntity & a_Entity, Vector3<Int8> a_RelMove, const cClientHandle * a_Exclude = nullptr) override;
virtual void BroadcastEntityPosition (const cEntity & a_Entity, 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 BroadcastEntityAnimation (const cEntity & a_Entity, Int8 a_Animation, const cClientHandle * a_Exclude = nullptr) override; // tolua_export
@ -210,7 +209,6 @@ public:
virtual void BroadcastSoundEffect (const AString & a_SoundName, Vector3d a_Position, float a_Volume, float a_Pitch, const cClientHandle * a_Exclude = nullptr) override; // Exported in ManualBindings_World.cpp
virtual void BroadcastSoundParticleEffect (const EffectID a_EffectID, Vector3i a_SrcPos, int a_Data, const cClientHandle * a_Exclude = nullptr) override; // Exported in ManualBindings_World.cpp
virtual void BroadcastSpawnEntity (cEntity & a_Entity, const cClientHandle * a_Exclude = nullptr) override;
virtual void BroadcastTeleportEntity (const cEntity & a_Entity, const cClientHandle * a_Exclude = nullptr) override;
virtual void BroadcastThunderbolt (Vector3i a_BlockPos, const cClientHandle * a_Exclude = nullptr) override;
virtual void BroadcastTimeUpdate (const cClientHandle * a_Exclude = nullptr) override;
virtual void BroadcastUnleashEntity (const cEntity & a_Entity) override;