From afd377a94171d277b340e3381ed26de2d55ed421 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Mon, 20 Apr 2020 01:37:23 +0100 Subject: Unify 1.8 and 1.9 - Deleted ridiculous amount of duplicated code --- src/Protocol/Protocol_1_8.cpp | 137 ++- src/Protocol/Protocol_1_8.h | 84 +- src/Protocol/Protocol_1_9.cpp | 2720 +++++------------------------------------ src/Protocol/Protocol_1_9.h | 184 +-- 4 files changed, 461 insertions(+), 2664 deletions(-) diff --git a/src/Protocol/Protocol_1_8.cpp b/src/Protocol/Protocol_1_8.cpp index 4b982562c..d402a41ec 100644 --- a/src/Protocol/Protocol_1_8.cpp +++ b/src/Protocol/Protocol_1_8.cpp @@ -115,22 +115,55 @@ cProtocol_1_8_0::cProtocol_1_8_0(cClientHandle * a_Client, const AString & a_Ser m_ReceivedData(32 KiB), m_IsEncrypted(false) { - - // BungeeCord handling: - // If BC is setup with ip_forward == true, it sends additional data in the login packet's ServerAddress field: - // hostname\00ip-address\00uuid\00profile-properties-as-json AStringVector Params; - if (cRoot::Get()->GetServer()->ShouldAllowBungeeCord() && SplitZeroTerminatedStrings(a_ServerAddress, Params) && (Params.size() == 4)) + SplitZeroTerminatedStrings(a_ServerAddress, Params); + + if (Params.size() >= 2) { - LOGD("Player at %s connected via BungeeCord", Params[1].c_str()); m_ServerAddress = Params[0]; - m_Client->SetIPString(Params[1]); - cUUID UUID; - UUID.FromString(Params[2]); - m_Client->SetUUID(UUID); + if (Params[1] == "FML") + { + LOGD("Forge client connected!"); + m_Client->SetIsForgeClient(); + } + else if (Params.size() == 4) + { + if (cRoot::Get()->GetServer()->ShouldAllowBungeeCord()) + { + // BungeeCord handling: + // If BC is setup with ip_forward == true, it sends additional data in the login packet's ServerAddress field: + // hostname\00ip-address\00uuid\00profile-properties-as-json - m_Client->SetProperties(Params[3]); + LOGD("Player at %s connected via BungeeCord", Params[1].c_str()); + + m_Client->SetIPString(Params[1]); + + cUUID UUID; + UUID.FromString(Params[2]); + m_Client->SetUUID(UUID); + + Json::Value root; + Json::Reader reader; + if (!reader.parse(Params[3], root)) + { + LOGERROR("Unable to parse player properties: '%s'", Params[3]); + } + else + { + m_Client->SetProperties(root); + } + } + else + { + LOG("BungeeCord is disabled, but client sent additional data, set AllowBungeeCord=1 if you want to allow it"); + } + } + else + { + LOG("Unknown additional data sent in server address (BungeeCord/FML?): %zu parameters", Params.size()); + // TODO: support FML + BungeeCord? (what parameters does it send in that case?) https://github.com/SpigotMC/BungeeCord/issues/899 + } } // Create the comm log file, if so requested: @@ -544,6 +577,37 @@ void cProtocol_1_8_0::SendEntityVelocity(const cEntity & a_Entity) +void cProtocol_1_8_0::SendExperience(void) +{ + ASSERT(m_State == 3); // In game mode? + + cPacketizer Pkt(*this, pktExperience); + cPlayer * Player = m_Client->GetPlayer(); + Pkt.WriteBEFloat(Player->GetXpPercentage()); + Pkt.WriteVarInt32(static_cast(Player->GetXpLevel())); + Pkt.WriteVarInt32(static_cast(Player->GetCurrentXp())); +} + + + + + +void cProtocol_1_8_0::SendExperienceOrb(const cExpOrb & a_ExpOrb) +{ + ASSERT(m_State == 3); // In game mode? + + cPacketizer Pkt(*this, pktSpawnExperienceOrb); + Pkt.WriteVarInt32(a_ExpOrb.GetUniqueID()); + Pkt.WriteFPInt(a_ExpOrb.GetPosX()); + Pkt.WriteFPInt(a_ExpOrb.GetPosY()); + Pkt.WriteFPInt(a_ExpOrb.GetPosZ()); + Pkt.WriteBEInt16(static_cast(a_ExpOrb.GetReward())); +} + + + + + void cProtocol_1_8_0::SendExplosion(double a_BlockX, double a_BlockY, double a_BlockZ, float a_Radius, const cVector3iArray & a_BlocksAffected, const Vector3d & a_PlayerMotion) { ASSERT(m_State == 3); // In game mode? @@ -1168,7 +1232,6 @@ void cProtocol_1_8_0::SendResourcePack(const AString & a_ResourcePackUrl) void cProtocol_1_8_0::SendRespawn(eDimension a_Dimension) { - cPacketizer Pkt(*this, pktRespawn); cPlayer * Player = m_Client->GetPlayer(); Pkt.WriteBEInt32(static_cast(a_Dimension)); @@ -1181,37 +1244,6 @@ void cProtocol_1_8_0::SendRespawn(eDimension a_Dimension) -void cProtocol_1_8_0::SendExperience(void) -{ - ASSERT(m_State == 3); // In game mode? - - cPacketizer Pkt(*this, pktExperience); - cPlayer * Player = m_Client->GetPlayer(); - Pkt.WriteBEFloat(Player->GetXpPercentage()); - Pkt.WriteVarInt32(static_cast(Player->GetXpLevel())); - Pkt.WriteVarInt32(static_cast(Player->GetCurrentXp())); -} - - - - - -void cProtocol_1_8_0::SendExperienceOrb(const cExpOrb & a_ExpOrb) -{ - ASSERT(m_State == 3); // In game mode? - - cPacketizer Pkt(*this, pktSpawnExperienceOrb); - Pkt.WriteVarInt32(a_ExpOrb.GetUniqueID()); - Pkt.WriteFPInt(a_ExpOrb.GetPosX()); - Pkt.WriteFPInt(a_ExpOrb.GetPosY()); - Pkt.WriteFPInt(a_ExpOrb.GetPosZ()); - Pkt.WriteBEInt16(static_cast(a_ExpOrb.GetReward())); -} - - - - - void cProtocol_1_8_0::SendScoreboardObjective(const AString & a_Name, const AString & a_DisplayName, Byte a_Mode) { ASSERT(m_State == 3); // In game mode? @@ -1521,9 +1553,8 @@ void cProtocol_1_8_0::SendTitleTimes(int a_FadeInTicks, int a_DisplayTicks, int { ASSERT(m_State == 3); // In game mode? - cPacketizer Pkt(*this, pktTitle); // Title packet + cPacketizer Pkt(*this, pktTitle); Pkt.WriteVarInt32(2); // Set title display times - Pkt.WriteBEInt32(a_FadeInTicks); Pkt.WriteBEInt32(a_DisplayTicks); Pkt.WriteBEInt32(a_FadeOutTicks); @@ -3240,10 +3271,22 @@ void cProtocol_1_8_0::SendPacket(cPacketizer & a_Pkt) AString Hex; ASSERT(PacketData.size() > 0); CreateHexDump(Hex, PacketData.data(), PacketData.size(), 16); - m_CommLogFile.Printf("Outgoing packet: type %s (0x%02x), length %u (0x%04x), state %d. Payload (incl. type):\n%s\n", - cPacketizer::PacketTypeToStr(a_Pkt.GetPacketType()), a_Pkt.GetPacketType(), PacketLen, PacketLen, m_State, Hex + m_CommLogFile.Printf("Outgoing packet: type %s (translated to 0x%02x), length %u (0x%04x), state %d. Payload (incl. type):\n%s\n", + cPacketizer::PacketTypeToStr(a_Pkt.GetPacketType()), GetPacketID(a_Pkt.GetPacketType()), + PacketLen, PacketLen, m_State, Hex + ); + /* + // Useful for debugging a new protocol: + LOGD("Outgoing packet: type %s (translated to 0x%02x), length %u (0x%04x), state %d. Payload (incl. type):\n%s\n", + cPacketizer::PacketTypeToStr(a_Pkt.GetPacketType()), GetPacketID(a_Pkt.GetPacketType()), + PacketLen, PacketLen, m_State, Hex ); + //*/ } + /* + // Useful for debugging a new protocol: + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + */ } diff --git a/src/Protocol/Protocol_1_8.h b/src/Protocol/Protocol_1_8.h index 8177ec34e..7934b7038 100644 --- a/src/Protocol/Protocol_1_8.h +++ b/src/Protocol/Protocol_1_8.h @@ -62,6 +62,8 @@ public: 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; + virtual void SendExperienceOrb (const cExpOrb & a_ExpOrb) 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; virtual void SendGameMode (eGameMode a_GameMode) override; virtual void SendHealth (void) override; @@ -94,8 +96,6 @@ public: virtual void SendResourcePack (const AString & a_ResourcePackUrl) override; virtual void SendRespawn (eDimension a_Dimension) 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 SendExperience (void) override; - virtual void SendExperienceOrb (const cExpOrb & a_ExpOrb) override; virtual void SendScoreboardObjective (const AString & a_Name, const AString & a_DisplayName, Byte a_Mode) override; virtual void SendScoreUpdate (const AString & a_Objective, const AString & a_Player, cObjective::Score a_Score, Byte a_Mode) override; virtual void SendDisplayObjective (const AString & a_Objective, cScoreboard::eDisplaySlot a_Display) override; @@ -161,7 +161,7 @@ protected: cFile m_CommLogFile; /** Adds the received (unencrypted) data to m_ReceivedData, parses complete packets */ - void AddReceivedData(const char * a_Data, size_t a_Size); + virtual void AddReceivedData(const char * a_Data, size_t a_Size); /** Nobody inherits 1.8, so it doesn't use this method */ virtual UInt32 GetPacketID(ePacketType a_Packet) override; @@ -172,46 +172,46 @@ protected: /** Reads and handles the packet. The packet length and type have already been read. Returns true if the packet was understood, false if it was an unknown packet */ - bool HandlePacket(cByteBuffer & a_ByteBuffer, UInt32 a_PacketType); + virtual bool HandlePacket(cByteBuffer & a_ByteBuffer, UInt32 a_PacketType); // Packet handlers while in the Status state (m_State == 1): - void HandlePacketStatusPing(cByteBuffer & a_ByteBuffer); - void HandlePacketStatusRequest(cByteBuffer & a_ByteBuffer); + virtual void HandlePacketStatusPing(cByteBuffer & a_ByteBuffer); + virtual void HandlePacketStatusRequest(cByteBuffer & a_ByteBuffer); // Packet handlers while in the Login state (m_State == 2): - void HandlePacketLoginEncryptionResponse(cByteBuffer & a_ByteBuffer); - void HandlePacketLoginStart(cByteBuffer & a_ByteBuffer); + virtual void HandlePacketLoginEncryptionResponse(cByteBuffer & a_ByteBuffer); + virtual void HandlePacketLoginStart(cByteBuffer & a_ByteBuffer); // Packet handlers while in the Game state (m_State == 3): - void HandlePacketAnimation (cByteBuffer & a_ByteBuffer); - void HandlePacketBlockDig (cByteBuffer & a_ByteBuffer); - void HandlePacketBlockPlace (cByteBuffer & a_ByteBuffer); - void HandlePacketChatMessage (cByteBuffer & a_ByteBuffer); - void HandlePacketClientSettings (cByteBuffer & a_ByteBuffer); - void HandlePacketClientStatus (cByteBuffer & a_ByteBuffer); - void HandlePacketCreativeInventoryAction(cByteBuffer & a_ByteBuffer); - void HandlePacketEntityAction (cByteBuffer & a_ByteBuffer); - void HandlePacketKeepAlive (cByteBuffer & a_ByteBuffer); - void HandlePacketPlayer (cByteBuffer & a_ByteBuffer); - void HandlePacketPlayerAbilities (cByteBuffer & a_ByteBuffer); - void HandlePacketPlayerLook (cByteBuffer & a_ByteBuffer); - void HandlePacketPlayerPos (cByteBuffer & a_ByteBuffer); - void HandlePacketPlayerPosLook (cByteBuffer & a_ByteBuffer); - void HandlePacketPluginMessage (cByteBuffer & a_ByteBuffer); - void HandlePacketResourcePackStatus (cByteBuffer & a_ByteBuffer); - void HandlePacketSlotSelect (cByteBuffer & a_ByteBuffer); - void HandlePacketSpectate (cByteBuffer & a_ByteBuffer); - void HandlePacketSteerVehicle (cByteBuffer & a_ByteBuffer); - void HandlePacketTabComplete (cByteBuffer & a_ByteBuffer); - void HandlePacketUpdateSign (cByteBuffer & a_ByteBuffer); - void HandlePacketUseEntity (cByteBuffer & a_ByteBuffer); - void HandlePacketEnchantItem (cByteBuffer & a_ByteBuffer); - void HandlePacketWindowClick (cByteBuffer & a_ByteBuffer); - void HandlePacketWindowClose (cByteBuffer & a_ByteBuffer); + virtual void HandlePacketAnimation (cByteBuffer & a_ByteBuffer); + virtual void HandlePacketBlockDig (cByteBuffer & a_ByteBuffer); + virtual void HandlePacketBlockPlace (cByteBuffer & a_ByteBuffer); + virtual void HandlePacketChatMessage (cByteBuffer & a_ByteBuffer); + virtual void HandlePacketClientSettings (cByteBuffer & a_ByteBuffer); + virtual void HandlePacketClientStatus (cByteBuffer & a_ByteBuffer); + virtual void HandlePacketCreativeInventoryAction(cByteBuffer & a_ByteBuffer); + virtual void HandlePacketEntityAction (cByteBuffer & a_ByteBuffer); + virtual void HandlePacketKeepAlive (cByteBuffer & a_ByteBuffer); + virtual void HandlePacketPlayer (cByteBuffer & a_ByteBuffer); + virtual void HandlePacketPlayerAbilities (cByteBuffer & a_ByteBuffer); + virtual void HandlePacketPlayerLook (cByteBuffer & a_ByteBuffer); + virtual void HandlePacketPlayerPos (cByteBuffer & a_ByteBuffer); + virtual void HandlePacketPlayerPosLook (cByteBuffer & a_ByteBuffer); + virtual void HandlePacketPluginMessage (cByteBuffer & a_ByteBuffer); + virtual void HandlePacketResourcePackStatus (cByteBuffer & a_ByteBuffer); + virtual void HandlePacketSlotSelect (cByteBuffer & a_ByteBuffer); + virtual void HandlePacketSpectate (cByteBuffer & a_ByteBuffer); + virtual void HandlePacketSteerVehicle (cByteBuffer & a_ByteBuffer); + virtual void HandlePacketTabComplete (cByteBuffer & a_ByteBuffer); + virtual void HandlePacketUpdateSign (cByteBuffer & a_ByteBuffer); + virtual void HandlePacketUseEntity (cByteBuffer & a_ByteBuffer); + virtual void HandlePacketEnchantItem (cByteBuffer & a_ByteBuffer); + virtual void HandlePacketWindowClick (cByteBuffer & a_ByteBuffer); + virtual void HandlePacketWindowClose (cByteBuffer & a_ByteBuffer); /** Parses Vanilla plugin messages into specific ClientHandle calls. The message payload is still in the bytebuffer, the handler reads it specifically for each handled channel */ - void HandleVanillaPluginMessage(cByteBuffer & a_ByteBuffer, const AString & a_Channel); + virtual void HandleVanillaPluginMessage(cByteBuffer & a_ByteBuffer, const AString & a_Channel); /** Sends the data to the client, encrypting them if needed. */ @@ -220,34 +220,32 @@ protected: /** Sends the packet to the client. Called by the cPacketizer's destructor. */ virtual void SendPacket(cPacketizer & a_Packet) override; - void SendCompass(const cWorld & a_World); - /** Reads an item out of the received data, sets a_Item to the values read. Returns false if not enough received data. a_KeepRemainingBytes tells the function to keep that many bytes at the end of the buffer. */ virtual bool ReadItem(cByteBuffer & a_ByteBuffer, cItem & a_Item, size_t a_KeepRemainingBytes = 0); /** Parses item metadata as read by ReadItem(), into the item enchantments. */ - void ParseItemMetadata(cItem & a_Item, const AString & a_Metadata); + virtual void ParseItemMetadata(cItem & a_Item, const AString & a_Metadata); - void StartEncryption(const Byte * a_Key); + virtual void StartEncryption(const Byte * a_Key); /** Converts the BlockFace received by the protocol into eBlockFace constants. If the received value doesn't match any of our eBlockFace constants, BLOCK_FACE_NONE is returned. */ eBlockFace FaceIntToBlockFace(Int8 a_FaceInt); /** Writes the item data into a packet. */ - void WriteItem(cPacketizer & a_Pkt, const cItem & a_Item); + virtual void WriteItem(cPacketizer & a_Pkt, const cItem & a_Item); /** Writes the metadata for the specified entity, not including the terminating 0x7f. */ - void WriteEntityMetadata(cPacketizer & a_Pkt, const cEntity & a_Entity); + virtual void WriteEntityMetadata(cPacketizer & a_Pkt, const cEntity & a_Entity); /** Writes the mob-specific metadata for the specified mob */ - void WriteMobMetadata(cPacketizer & a_Pkt, const cMonster & a_Mob); + virtual void WriteMobMetadata(cPacketizer & a_Pkt, const cMonster & a_Mob); /** Writes the entity properties for the specified entity, including the Count field. */ - void WriteEntityProperties(cPacketizer & a_Pkt, const cEntity & a_Entity); + virtual void WriteEntityProperties(cPacketizer & a_Pkt, const cEntity & a_Entity); /** Writes the block entity data for the specified block entity into the packet. */ - void WriteBlockEntity(cPacketizer & a_Pkt, const cBlockEntity & a_BlockEntity); + virtual void WriteBlockEntity(cPacketizer & a_Pkt, const cBlockEntity & a_BlockEntity); } ; diff --git a/src/Protocol/Protocol_1_9.cpp b/src/Protocol/Protocol_1_9.cpp index ae5948f94..91bc43d03 100644 --- a/src/Protocol/Protocol_1_9.cpp +++ b/src/Protocol/Protocol_1_9.cpp @@ -82,143 +82,14 @@ static const UInt32 OFF_HAND = 1; -#define HANDLE_PACKET_READ(ByteBuf, Proc, Type, Var) \ - Type Var; \ - do { \ - { \ - if (!ByteBuf.Proc(Var)) \ - { \ - ByteBuf.CheckValid(); \ - return false; \ - } \ - ByteBuf.CheckValid(); \ - } \ - } while (false) - - - - - -const int MAX_ENC_LEN = 512; // Maximum size of the encrypted message; should be 128, but who knows... -const uLongf MAX_COMPRESSED_PACKET_LEN = 200 KiB; // Maximum size of compressed packets. - - - - - -// fwd: main.cpp: -extern bool g_ShouldLogCommIn, g_ShouldLogCommOut; - - - - - //////////////////////////////////////////////////////////////////////////////// // cProtocol_1_9_0: cProtocol_1_9_0::cProtocol_1_9_0(cClientHandle * a_Client, const AString & a_ServerAddress, UInt16 a_ServerPort, UInt32 a_State) : - Super(a_Client), - m_ServerAddress(a_ServerAddress), - m_ServerPort(a_ServerPort), - m_State(a_State), + Super(a_Client, a_ServerAddress, a_ServerPort, a_State), m_IsTeleportIdConfirmed(true), - m_OutstandingTeleportId(0), - m_ReceivedData(32 KiB), - m_IsEncrypted(false) -{ - - AStringVector Params; - SplitZeroTerminatedStrings(a_ServerAddress, Params); - - if (Params.size() >= 2) - { - m_ServerAddress = Params[0]; - - if (Params[1] == "FML") - { - LOGD("Forge client connected!"); - m_Client->SetIsForgeClient(); - } - else if (Params.size() == 4) - { - if (cRoot::Get()->GetServer()->ShouldAllowBungeeCord()) - { - // BungeeCord handling: - // If BC is setup with ip_forward == true, it sends additional data in the login packet's ServerAddress field: - // hostname\00ip-address\00uuid\00profile-properties-as-json - - LOGD("Player at %s connected via BungeeCord", Params[1].c_str()); - - m_Client->SetIPString(Params[1]); - - cUUID UUID; - UUID.FromString(Params[2]); - m_Client->SetUUID(UUID); - - Json::Value root; - Json::Reader reader; - if (!reader.parse(Params[3], root)) - { - LOGERROR("Unable to parse player properties: '%s'", Params[3]); - } - else - { - m_Client->SetProperties(root); - } - } - else - { - LOG("BungeeCord is disabled, but client sent additional data, set AllowBungeeCord=1 if you want to allow it"); - } - } - else - { - LOG("Unknown additional data sent in server address (BungeeCord/FML?): %zu parameters", Params.size()); - // TODO: support FML + BungeeCord? (what parameters does it send in that case?) https://github.com/SpigotMC/BungeeCord/issues/899 - } - } - - // Create the comm log file, if so requested: - if (g_ShouldLogCommIn || g_ShouldLogCommOut) - { - static int sCounter = 0; - cFile::CreateFolder("CommLogs"); - AString IP(a_Client->GetIPString()); - ReplaceString(IP, ":", "_"); - AString FileName = Printf("CommLogs/%x_%d__%s.log", - static_cast(time(nullptr)), - sCounter++, - IP.c_str() - ); - if (!m_CommLogFile.Open(FileName, cFile::fmWrite)) - { - LOG("Cannot log communication to file, the log file \"%s\" cannot be opened for writing.", FileName.c_str()); - } - } -} - - - - - -void cProtocol_1_9_0::DataReceived(const char * a_Data, size_t a_Size) + m_OutstandingTeleportId(0) { - if (m_IsEncrypted) - { - Byte Decrypted[512]; - while (a_Size > 0) - { - size_t NumBytes = (a_Size > sizeof(Decrypted)) ? sizeof(Decrypted) : a_Size; - m_Decryptor.ProcessData(Decrypted, reinterpret_cast(a_Data), NumBytes); - AddReceivedData(reinterpret_cast(Decrypted), NumBytes); - a_Size -= NumBytes; - a_Data += NumBytes; - } - } - else - { - AddReceivedData(a_Data, a_Size); - } } @@ -238,187 +109,219 @@ void cProtocol_1_9_0::SendAttachEntity(const cEntity & a_Entity, const cEntity & -void cProtocol_1_9_0::SendBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType) +void cProtocol_1_9_0::SendChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer) { ASSERT(m_State == 3); // In game mode? - cPacketizer Pkt(*this, pktBlockAction); - Pkt.WritePosition64(a_BlockX, a_BlockY, a_BlockZ); - Pkt.WriteBEInt8(a_Byte1); - Pkt.WriteBEInt8(a_Byte2); - Pkt.WriteVarInt32(a_BlockType); + // Serialize first, before creating the Packetizer (the packetizer locks a CS) + // This contains the flags and bitmasks, too + const AString & ChunkData = a_Serializer.Serialize(cChunkDataSerializer::RELEASE_1_9_0, a_ChunkX, a_ChunkZ, {}); + + cCSLock Lock(m_CSPacket); + SendData(ChunkData.data(), ChunkData.size()); } -void cProtocol_1_9_0::SendBlockBreakAnim(UInt32 a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage) +void cProtocol_1_9_0::SendDetachEntity(const cEntity & a_Entity, const cEntity & a_PreviousVehicle) { ASSERT(m_State == 3); // In game mode? - - cPacketizer Pkt(*this, pktBlockBreakAnim); - Pkt.WriteVarInt32(a_EntityID); - Pkt.WritePosition64(a_BlockX, a_BlockY, a_BlockZ); - Pkt.WriteBEInt8(a_Stage); + cPacketizer Pkt(*this, pktAttachEntity); + Pkt.WriteVarInt32(a_PreviousVehicle.GetUniqueID()); + Pkt.WriteVarInt32(0); // No passangers } -void cProtocol_1_9_0::SendBlockChange(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) +void cProtocol_1_9_0::SendEntityEquipment(const cEntity & a_Entity, short a_SlotNum, const cItem & a_Item) { ASSERT(m_State == 3); // In game mode? - cPacketizer Pkt(*this, pktBlockChange); - Pkt.WritePosition64(a_BlockX, a_BlockY, a_BlockZ); - Pkt.WriteVarInt32((static_cast(a_BlockType) << 4) | (static_cast(a_BlockMeta) & 15)); + cPacketizer Pkt(*this, pktEntityEquipment); + Pkt.WriteVarInt32(a_Entity.GetUniqueID()); + // Needs to be adjusted due to the insertion of offhand at slot 1 + if (a_SlotNum > 0) + { + a_SlotNum++; + } + Pkt.WriteVarInt32(static_cast(a_SlotNum)); + WriteItem(Pkt, a_Item); } -void cProtocol_1_9_0::SendBlockChanges(int a_ChunkX, int a_ChunkZ, const sSetBlockVector & a_Changes) +void cProtocol_1_9_0::SendEntityMetadata(const cEntity & a_Entity) { ASSERT(m_State == 3); // In game mode? - cPacketizer Pkt(*this, pktBlockChanges); - Pkt.WriteBEInt32(a_ChunkX); - Pkt.WriteBEInt32(a_ChunkZ); - Pkt.WriteVarInt32(static_cast(a_Changes.size())); - for (sSetBlockVector::const_iterator itr = a_Changes.begin(), end = a_Changes.end(); itr != end; ++itr) - { - Int16 Coords = static_cast(itr->m_RelY | (itr->m_RelZ << 8) | (itr->m_RelX << 12)); - Pkt.WriteBEInt16(Coords); - Pkt.WriteVarInt32(static_cast(itr->m_BlockType & 0xFFF) << 4 | (itr->m_BlockMeta & 0xF)); - } // for itr - a_Changes[] + cPacketizer Pkt(*this, pktEntityMeta); + Pkt.WriteVarInt32(a_Entity.GetUniqueID()); + WriteEntityMetadata(Pkt, a_Entity); + Pkt.WriteBEUInt8(0xff); // The termination byte } -void cProtocol_1_9_0::SendCameraSetTo(const cEntity & a_Entity) +void cProtocol_1_9_0::SendEntityRelMove(const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ) { - cPacketizer Pkt(*this, pktCameraSetTo); + 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()); } -void cProtocol_1_9_0::SendChat(const AString & a_Message, eChatType a_Type) +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? - SendChatRaw(Printf("{\"text\":\"%s\"}", EscapeString(a_Message).c_str()), a_Type); + 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.WriteByteAngle(a_Entity.GetYaw()); + Pkt.WriteByteAngle(a_Entity.GetPitch()); + Pkt.WriteBool(a_Entity.IsOnGround()); } -void cProtocol_1_9_0::SendChat(const cCompositeChat & a_Message, eChatType a_Type, bool a_ShouldUseChatPrefixes) +void cProtocol_1_9_0::SendEntityStatus(const cEntity & a_Entity, char a_Status) { ASSERT(m_State == 3); // In game mode? - SendChatRaw(a_Message.CreateJsonString(a_ShouldUseChatPrefixes), a_Type); + cPacketizer Pkt(*this, pktEntityStatus); + Pkt.WriteBEUInt32(a_Entity.GetUniqueID()); + Pkt.WriteBEInt8(a_Status); } -void cProtocol_1_9_0::SendChatRaw(const AString & a_MessageRaw, eChatType a_Type) +void cProtocol_1_9_0::SendExperienceOrb(const cExpOrb & a_ExpOrb) { ASSERT(m_State == 3); // In game mode? - // Send the json string to the client: - cPacketizer Pkt(*this, pktChatRaw); - Pkt.WriteString(a_MessageRaw); - Pkt.WriteBEInt8(a_Type); + cPacketizer Pkt(*this, pktSpawnExperienceOrb); + Pkt.WriteVarInt32(a_ExpOrb.GetUniqueID()); + Pkt.WriteBEDouble(a_ExpOrb.GetPosX()); + Pkt.WriteBEDouble(a_ExpOrb.GetPosY()); + Pkt.WriteBEDouble(a_ExpOrb.GetPosZ()); + Pkt.WriteBEInt16(static_cast(a_ExpOrb.GetReward())); } -void cProtocol_1_9_0::SendChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer) +void cProtocol_1_9_0::SendKeepAlive(UInt32 a_PingID) { - ASSERT(m_State == 3); // In game mode? - - // Serialize first, before creating the Packetizer (the packetizer locks a CS) - // This contains the flags and bitmasks, too - const AString & ChunkData = a_Serializer.Serialize(cChunkDataSerializer::RELEASE_1_9_0, a_ChunkX, a_ChunkZ, {}); + // Drop the packet if the protocol is not in the Game state yet (caused a client crash): + if (m_State != 3) + { + LOG("Trying to send a KeepAlive packet to a player who's not yet fully logged in (%d). The protocol class prevented the packet.", m_State); + return; + } - cCSLock Lock(m_CSPacket); - SendData(ChunkData.data(), ChunkData.size()); + cPacketizer Pkt(*this, pktKeepAlive); + Pkt.WriteVarInt32(a_PingID); } -void cProtocol_1_9_0::SendCollectEntity(const cEntity & a_Entity, const cPlayer & a_Player, int a_Count) +void cProtocol_1_9_0::SendLeashEntity(const cEntity & a_Entity, const cEntity & a_EntityLeashedTo) { - UNUSED(a_Count); ASSERT(m_State == 3); // In game mode? - - cPacketizer Pkt(*this, pktCollectEntity); - Pkt.WriteVarInt32(a_Entity.GetUniqueID()); - Pkt.WriteVarInt32(a_Player.GetUniqueID()); + cPacketizer Pkt(*this, pktLeashEntity); + Pkt.WriteBEUInt32(a_Entity.GetUniqueID()); + Pkt.WriteBEUInt32(a_EntityLeashedTo.GetUniqueID()); } -void cProtocol_1_9_0::SendDestroyEntity(const cEntity & a_Entity) +void cProtocol_1_9_0::SendUnleashEntity(const cEntity & a_Entity) { ASSERT(m_State == 3); // In game mode? - - cPacketizer Pkt(*this, pktDestroyEntity); - Pkt.WriteVarInt32(1); - Pkt.WriteVarInt32(a_Entity.GetUniqueID()); + cPacketizer Pkt(*this, pktLeashEntity); + Pkt.WriteBEUInt32(a_Entity.GetUniqueID()); + Pkt.WriteBEInt32(-1); // Unleash a_Entity } -void cProtocol_1_9_0::SendDetachEntity(const cEntity & a_Entity, const cEntity & a_PreviousVehicle) +void cProtocol_1_9_0::SendPaintingSpawn(const cPainting & a_Painting) { ASSERT(m_State == 3); // In game mode? - cPacketizer Pkt(*this, pktAttachEntity); - Pkt.WriteVarInt32(a_PreviousVehicle.GetUniqueID()); - Pkt.WriteVarInt32(0); // No passangers + double PosX = a_Painting.GetPosX(); + double PosY = a_Painting.GetPosY(); + double PosZ = a_Painting.GetPosZ(); + + cPacketizer Pkt(*this, pktSpawnPainting); + Pkt.WriteVarInt32(a_Painting.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_Painting.GetUniqueID()); + Pkt.WriteString(a_Painting.GetName().c_str()); + Pkt.WritePosition64(static_cast(PosX), static_cast(PosY), static_cast(PosZ)); + Pkt.WriteBEInt8(static_cast(a_Painting.GetProtocolFacing())); } -void cProtocol_1_9_0::SendDisconnect(const AString & a_Reason) +void cProtocol_1_9_0::SendMapData(const cMap & a_Map, int a_DataStartX, int a_DataStartY) { - switch (m_State) + ASSERT(m_State == 3); // In game mode? + + cPacketizer Pkt(*this, pktMapData); + Pkt.WriteVarInt32(a_Map.GetID()); + Pkt.WriteBEUInt8(static_cast(a_Map.GetScale())); + + Pkt.WriteBool(true); + Pkt.WriteVarInt32(static_cast(a_Map.GetDecorators().size())); + for (const auto & Decorator : a_Map.GetDecorators()) { - case 2: - { - // During login: - cPacketizer Pkt(*this, pktDisconnectDuringLogin); - Pkt.WriteString(Printf("{\"text\":\"%s\"}", EscapeString(a_Reason).c_str())); - break; - } - case 3: - { - // In-game: - cPacketizer Pkt(*this, pktDisconnectDuringGame); - Pkt.WriteString(Printf("{\"text\":\"%s\"}", EscapeString(a_Reason).c_str())); - break; - } + Pkt.WriteBEUInt8(static_cast((static_cast(Decorator.GetType()) << 4) | (Decorator.GetRot() & 0xF))); + Pkt.WriteBEUInt8(static_cast(Decorator.GetPixelX())); + Pkt.WriteBEUInt8(static_cast(Decorator.GetPixelZ())); + } + + Pkt.WriteBEUInt8(128); + Pkt.WriteBEUInt8(128); + Pkt.WriteBEUInt8(static_cast(a_DataStartX)); + Pkt.WriteBEUInt8(static_cast(a_DataStartY)); + Pkt.WriteVarInt32(static_cast(a_Map.GetData().size())); + for (auto itr = a_Map.GetData().cbegin(); itr != a_Map.GetData().cend(); ++itr) + { + Pkt.WriteBEUInt8(*itr); } } @@ -426,1755 +329,277 @@ void cProtocol_1_9_0::SendDisconnect(const AString & a_Reason) -void cProtocol_1_9_0::SendEditSign(int a_BlockX, int a_BlockY, int a_BlockZ) +void cProtocol_1_9_0::SendPickupSpawn(const cPickup & a_Pickup) { ASSERT(m_State == 3); // In game mode? - cPacketizer Pkt(*this, pktEditSign); - Pkt.WritePosition64(a_BlockX, a_BlockY, a_BlockZ); + { // TODO Use SendSpawnObject + cPacketizer Pkt(*this, pktSpawnObject); + Pkt.WriteVarInt32(a_Pickup.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_Pickup.GetUniqueID()); + Pkt.WriteBEUInt8(2); // Type = Pickup + Pkt.WriteBEDouble(a_Pickup.GetPosX()); + Pkt.WriteBEDouble(a_Pickup.GetPosY()); + Pkt.WriteBEDouble(a_Pickup.GetPosZ()); + Pkt.WriteByteAngle(a_Pickup.GetYaw()); + Pkt.WriteByteAngle(a_Pickup.GetPitch()); + Pkt.WriteBEInt32(0); // No object data + Pkt.WriteBEInt16(0); // No velocity + Pkt.WriteBEInt16(0); + Pkt.WriteBEInt16(0); + } + + SendEntityMetadata(a_Pickup); } -void cProtocol_1_9_0::SendEntityEffect(const cEntity & a_Entity, int a_EffectID, int a_Amplifier, int a_Duration) +void cProtocol_1_9_0::SendPlayerMaxSpeed(void) { ASSERT(m_State == 3); // In game mode? - cPacketizer Pkt(*this, pktEntityEffect); - Pkt.WriteVarInt32(a_Entity.GetUniqueID()); - Pkt.WriteBEUInt8(static_cast(a_EffectID)); - Pkt.WriteBEUInt8(static_cast(a_Amplifier)); - Pkt.WriteVarInt32(static_cast(a_Duration)); - Pkt.WriteBool(false); // Hide particles + cPacketizer Pkt(*this, pktPlayerMaxSpeed); + cPlayer * Player = m_Client->GetPlayer(); + Pkt.WriteVarInt32(Player->GetUniqueID()); + Pkt.WriteBEInt32(1); // Count + Pkt.WriteString("generic.movementSpeed"); + // The default game speed is 0.1, multiply that value by the relative speed: + Pkt.WriteBEDouble(0.1 * Player->GetNormalMaxSpeed()); + if (Player->IsSprinting()) + { + Pkt.WriteVarInt32(1); // Modifier count + Pkt.WriteBEUInt64(0x662a6b8dda3e4c1c); + Pkt.WriteBEUInt64(0x881396ea6097278d); // UUID of the modifier + Pkt.WriteBEDouble(Player->GetSprintingMaxSpeed() - Player->GetNormalMaxSpeed()); + Pkt.WriteBEUInt8(2); + } + else + { + Pkt.WriteVarInt32(0); // Modifier count + } } -void cProtocol_1_9_0::SendEntityEquipment(const cEntity & a_Entity, short a_SlotNum, const cItem & a_Item) +void cProtocol_1_9_0::SendPlayerMoveLook(void) { ASSERT(m_State == 3); // In game mode? - cPacketizer Pkt(*this, pktEntityEquipment); - Pkt.WriteVarInt32(a_Entity.GetUniqueID()); - // Needs to be adjusted due to the insertion of offhand at slot 1 - if (a_SlotNum > 0) - { - a_SlotNum++; - } - Pkt.WriteVarInt32(static_cast(a_SlotNum)); - WriteItem(Pkt, a_Item); -} - - - - - -void cProtocol_1_9_0::SendEntityHeadLook(const cEntity & a_Entity) -{ - ASSERT(m_State == 3); // In game mode? - - cPacketizer Pkt(*this, pktEntityHeadLook); - Pkt.WriteVarInt32(a_Entity.GetUniqueID()); - Pkt.WriteByteAngle(a_Entity.GetHeadYaw()); -} - - - - - -void cProtocol_1_9_0::SendEntityLook(const cEntity & a_Entity) -{ - ASSERT(m_State == 3); // In game mode? - - cPacketizer Pkt(*this, pktEntityLook); - Pkt.WriteVarInt32(a_Entity.GetUniqueID()); - Pkt.WriteByteAngle(a_Entity.GetYaw()); - Pkt.WriteByteAngle(a_Entity.GetPitch()); - Pkt.WriteBool(a_Entity.IsOnGround()); -} - - - - - -void cProtocol_1_9_0::SendEntityMetadata(const cEntity & a_Entity) -{ - ASSERT(m_State == 3); // In game mode? - - cPacketizer Pkt(*this, pktEntityMeta); - Pkt.WriteVarInt32(a_Entity.GetUniqueID()); - WriteEntityMetadata(Pkt, a_Entity); - Pkt.WriteBEUInt8(0xff); // The termination byte -} - - - - - -void cProtocol_1_9_0::SendEntityProperties(const cEntity & a_Entity) -{ - ASSERT(m_State == 3); // In game mode? - - cPacketizer Pkt(*this, pktEntityProperties); - Pkt.WriteVarInt32(a_Entity.GetUniqueID()); - WriteEntityProperties(Pkt, a_Entity); -} - - - - - -void cProtocol_1_9_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()); - // 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.WriteByteAngle(a_Entity.GetYaw()); - Pkt.WriteByteAngle(a_Entity.GetPitch()); - Pkt.WriteBool(a_Entity.IsOnGround()); -} - - - - - -void cProtocol_1_9_0::SendEntityStatus(const cEntity & a_Entity, char a_Status) -{ - ASSERT(m_State == 3); // In game mode? - - cPacketizer Pkt(*this, pktEntityStatus); - Pkt.WriteBEUInt32(a_Entity.GetUniqueID()); - Pkt.WriteBEInt8(a_Status); -} - - - - - -void cProtocol_1_9_0::SendEntityVelocity(const cEntity & a_Entity) -{ - ASSERT(m_State == 3); // In game mode? - - cPacketizer Pkt(*this, pktEntityVelocity); - Pkt.WriteVarInt32(a_Entity.GetUniqueID()); - // 400 = 8000 / 20 ... Conversion from our speed in m / s to 8000 m / tick - 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::SendExperience(void) -{ - ASSERT(m_State == 3); // In game mode? - - cPacketizer Pkt(*this, pktExperience); - cPlayer * Player = m_Client->GetPlayer(); - Pkt.WriteBEFloat(Player->GetXpPercentage()); - Pkt.WriteVarInt32(static_cast(Player->GetXpLevel())); - Pkt.WriteVarInt32(static_cast(Player->GetCurrentXp())); -} - - - - - -void cProtocol_1_9_0::SendExperienceOrb(const cExpOrb & a_ExpOrb) -{ - ASSERT(m_State == 3); // In game mode? - - cPacketizer Pkt(*this, pktSpawnExperienceOrb); - Pkt.WriteVarInt32(a_ExpOrb.GetUniqueID()); - Pkt.WriteBEDouble(a_ExpOrb.GetPosX()); - Pkt.WriteBEDouble(a_ExpOrb.GetPosY()); - Pkt.WriteBEDouble(a_ExpOrb.GetPosZ()); - Pkt.WriteBEInt16(static_cast(a_ExpOrb.GetReward())); -} - - - - - -void cProtocol_1_9_0::SendExplosion(double a_BlockX, double a_BlockY, double a_BlockZ, float a_Radius, const cVector3iArray & a_BlocksAffected, const Vector3d & a_PlayerMotion) -{ - ASSERT(m_State == 3); // In game mode? - - cPacketizer Pkt(*this, pktExplosion); - Pkt.WriteBEFloat(static_cast(a_BlockX)); - Pkt.WriteBEFloat(static_cast(a_BlockY)); - Pkt.WriteBEFloat(static_cast(a_BlockZ)); - Pkt.WriteBEFloat(static_cast(a_Radius)); - Pkt.WriteBEUInt32(static_cast(a_BlocksAffected.size())); - for (cVector3iArray::const_iterator itr = a_BlocksAffected.begin(), end = a_BlocksAffected.end(); itr != end; ++itr) - { - Pkt.WriteBEInt8(static_cast(itr->x)); - Pkt.WriteBEInt8(static_cast(itr->y)); - Pkt.WriteBEInt8(static_cast(itr->z)); - } // for itr - a_BlockAffected[] - Pkt.WriteBEFloat(static_cast(a_PlayerMotion.x)); - Pkt.WriteBEFloat(static_cast(a_PlayerMotion.y)); - Pkt.WriteBEFloat(static_cast(a_PlayerMotion.z)); -} - - - - - -void cProtocol_1_9_0::SendGameMode(eGameMode a_GameMode) -{ - ASSERT(m_State == 3); // In game mode? - - cPacketizer Pkt(*this, pktGameMode); - Pkt.WriteBEUInt8(3); // Reason: Change game mode - Pkt.WriteBEFloat(static_cast(a_GameMode)); // The protocol really represents the value with a float! -} - - - - - -void cProtocol_1_9_0::SendHealth(void) -{ - ASSERT(m_State == 3); // In game mode? - - cPacketizer Pkt(*this, pktUpdateHealth); - cPlayer * Player = m_Client->GetPlayer(); - Pkt.WriteBEFloat(static_cast(Player->GetHealth())); - Pkt.WriteVarInt32(static_cast(Player->GetFoodLevel())); - Pkt.WriteBEFloat(static_cast(Player->GetFoodSaturationLevel())); -} - - - - - -void cProtocol_1_9_0::SendHeldItemChange(int a_ItemIndex) -{ - ASSERT((a_ItemIndex >= 0) && (a_ItemIndex <= 8)); // Valid check - - cPacketizer Pkt(*this, pktHeldItemChange); - cPlayer * Player = m_Client->GetPlayer(); - Pkt.WriteBEInt8(static_cast(Player->GetInventory().GetEquippedSlotNum())); -} - - - - - -void cProtocol_1_9_0::SendHideTitle(void) -{ - ASSERT(m_State == 3); // In game mode? - - cPacketizer Pkt(*this, pktTitle); - Pkt.WriteVarInt32(3); // Hide title -} - - - - - -void cProtocol_1_9_0::SendInventorySlot(char a_WindowID, short a_SlotNum, const cItem & a_Item) -{ - ASSERT(m_State == 3); // In game mode? - - cPacketizer Pkt(*this, pktInventorySlot); - Pkt.WriteBEInt8(a_WindowID); - Pkt.WriteBEInt16(a_SlotNum); - WriteItem(Pkt, a_Item); -} - - - - - -void cProtocol_1_9_0::SendKeepAlive(UInt32 a_PingID) -{ - // Drop the packet if the protocol is not in the Game state yet (caused a client crash): - if (m_State != 3) - { - LOG("Trying to send a KeepAlive packet to a player who's not yet fully logged in (%d). The protocol class prevented the packet.", m_State); - return; - } - - cPacketizer Pkt(*this, pktKeepAlive); - Pkt.WriteVarInt32(a_PingID); -} - - - - - -void cProtocol_1_9_0::SendLeashEntity(const cEntity & a_Entity, const cEntity & a_EntityLeashedTo) -{ - ASSERT(m_State == 3); // In game mode? - cPacketizer Pkt(*this, pktLeashEntity); - Pkt.WriteBEUInt32(a_Entity.GetUniqueID()); - Pkt.WriteBEUInt32(a_EntityLeashedTo.GetUniqueID()); -} - - - - - -void cProtocol_1_9_0::SendUnleashEntity(const cEntity & a_Entity) -{ - ASSERT(m_State == 3); // In game mode? - cPacketizer Pkt(*this, pktLeashEntity); - Pkt.WriteBEUInt32(a_Entity.GetUniqueID()); - Pkt.WriteBEInt32(-1); // Unleash a_Entity -} - - - - - -void cProtocol_1_9_0::SendLogin(const cPlayer & a_Player, const cWorld & a_World) -{ - // Send the Join Game packet: - { - cServer * Server = cRoot::Get()->GetServer(); - cPacketizer Pkt(*this, pktJoinGame); - Pkt.WriteBEUInt32(a_Player.GetUniqueID()); - Pkt.WriteBEUInt8(static_cast(a_Player.GetEffectiveGameMode()) | (Server->IsHardcore() ? 0x08 : 0)); // Hardcore flag bit 4 - Pkt.WriteBEInt8(static_cast(a_World.GetDimension())); - Pkt.WriteBEUInt8(2); // TODO: Difficulty (set to Normal) - Pkt.WriteBEUInt8(static_cast(Clamp(Server->GetMaxPlayers(), 0, 255))); - Pkt.WriteString("default"); // Level type - wtf? - Pkt.WriteBool(false); // Reduced Debug Info - wtf? - } - - // Send the spawn position: - { - cPacketizer Pkt(*this, pktSpawnPosition); - Pkt.WritePosition64(FloorC(a_World.GetSpawnX()), FloorC(a_World.GetSpawnY()), FloorC(a_World.GetSpawnZ())); - } - - // Send the server difficulty: - { - cPacketizer Pkt(*this, pktDifficulty); - Pkt.WriteBEInt8(1); - } - - // Send player abilities: - SendPlayerAbilities(); -} - - - - - -void cProtocol_1_9_0::SendLoginSuccess(void) -{ - ASSERT(m_State == 2); // State: login? - - // Enable compression: - { - cPacketizer Pkt(*this, pktStartCompression); - Pkt.WriteVarInt32(256); - } - - m_State = 3; // State = Game - - { - cPacketizer Pkt(*this, pktLoginSuccess); - Pkt.WriteString(m_Client->GetUUID().ToLongString()); - Pkt.WriteString(m_Client->GetUsername()); - } -} - - - - - -void cProtocol_1_9_0::SendPaintingSpawn(const cPainting & a_Painting) -{ - ASSERT(m_State == 3); // In game mode? - double PosX = a_Painting.GetPosX(); - double PosY = a_Painting.GetPosY(); - double PosZ = a_Painting.GetPosZ(); - - cPacketizer Pkt(*this, pktSpawnPainting); - Pkt.WriteVarInt32(a_Painting.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_Painting.GetUniqueID()); - Pkt.WriteString(a_Painting.GetName().c_str()); - Pkt.WritePosition64(static_cast(PosX), static_cast(PosY), static_cast(PosZ)); - Pkt.WriteBEInt8(static_cast(a_Painting.GetProtocolFacing())); -} - - - - - -void cProtocol_1_9_0::SendMapData(const cMap & a_Map, int a_DataStartX, int a_DataStartY) -{ - ASSERT(m_State == 3); // In game mode? - - cPacketizer Pkt(*this, pktMapData); - Pkt.WriteVarInt32(a_Map.GetID()); - Pkt.WriteBEUInt8(static_cast(a_Map.GetScale())); - - Pkt.WriteBool(true); - Pkt.WriteVarInt32(static_cast(a_Map.GetDecorators().size())); - for (const auto & Decorator : a_Map.GetDecorators()) - { - Pkt.WriteBEUInt8(static_cast((static_cast(Decorator.GetType()) << 4) | (Decorator.GetRot() & 0xF))); - Pkt.WriteBEUInt8(static_cast(Decorator.GetPixelX())); - Pkt.WriteBEUInt8(static_cast(Decorator.GetPixelZ())); - } - - Pkt.WriteBEUInt8(128); - Pkt.WriteBEUInt8(128); - Pkt.WriteBEUInt8(static_cast(a_DataStartX)); - Pkt.WriteBEUInt8(static_cast(a_DataStartY)); - Pkt.WriteVarInt32(static_cast(a_Map.GetData().size())); - for (auto itr = a_Map.GetData().cbegin(); itr != a_Map.GetData().cend(); ++itr) - { - Pkt.WriteBEUInt8(*itr); - } -} - - - - - -void cProtocol_1_9_0::SendPickupSpawn(const cPickup & a_Pickup) -{ - ASSERT(m_State == 3); // In game mode? - - { // TODO Use SendSpawnObject - cPacketizer Pkt(*this, pktSpawnObject); - Pkt.WriteVarInt32(a_Pickup.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_Pickup.GetUniqueID()); - Pkt.WriteBEUInt8(2); // Type = Pickup - Pkt.WriteBEDouble(a_Pickup.GetPosX()); - Pkt.WriteBEDouble(a_Pickup.GetPosY()); - Pkt.WriteBEDouble(a_Pickup.GetPosZ()); - Pkt.WriteByteAngle(a_Pickup.GetYaw()); - Pkt.WriteByteAngle(a_Pickup.GetPitch()); - Pkt.WriteBEInt32(0); // No object data - Pkt.WriteBEInt16(0); // No velocity - Pkt.WriteBEInt16(0); - Pkt.WriteBEInt16(0); - } - - SendEntityMetadata(a_Pickup); -} - - - - - -void cProtocol_1_9_0::SendPlayerAbilities(void) -{ - ASSERT(m_State == 3); // In game mode? - - cPacketizer Pkt(*this, pktPlayerAbilities); - Byte Flags = 0; - cPlayer * Player = m_Client->GetPlayer(); - if (Player->IsGameModeCreative()) - { - Flags |= 0x01; - Flags |= 0x08; // Godmode, used for creative - } - if (Player->IsFlying()) - { - Flags |= 0x02; - } - if (Player->CanFly()) - { - Flags |= 0x04; - } - Pkt.WriteBEUInt8(Flags); - Pkt.WriteBEFloat(static_cast(0.05 * Player->GetFlyingMaxSpeed())); - Pkt.WriteBEFloat(static_cast(0.1 * Player->GetNormalMaxSpeed())); -} - - - - - -void cProtocol_1_9_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_9_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? - int ParticleID = GetParticleID(a_ParticleName); - - cPacketizer Pkt(*this, pktParticleEffect); - Pkt.WriteBEInt32(ParticleID); - Pkt.WriteBool(false); - Pkt.WriteBEFloat(a_SrcX); - Pkt.WriteBEFloat(a_SrcY); - Pkt.WriteBEFloat(a_SrcZ); - Pkt.WriteBEFloat(a_OffsetX); - Pkt.WriteBEFloat(a_OffsetY); - Pkt.WriteBEFloat(a_OffsetZ); - Pkt.WriteBEFloat(a_ParticleData); - Pkt.WriteBEInt32(a_ParticleAmount); -} - - - - - -void cProtocol_1_9_0::SendParticleEffect(const AString & a_ParticleName, Vector3f a_Src, Vector3f a_Offset, float a_ParticleData, int a_ParticleAmount, std::array a_Data) -{ - ASSERT(m_State == 3); // In game mode? - int ParticleID = GetParticleID(a_ParticleName); - - cPacketizer Pkt(*this, pktParticleEffect); - Pkt.WriteBEInt32(ParticleID); - Pkt.WriteBool(false); - Pkt.WriteBEFloat(a_Src.x); - Pkt.WriteBEFloat(a_Src.y); - Pkt.WriteBEFloat(a_Src.z); - Pkt.WriteBEFloat(a_Offset.x); - Pkt.WriteBEFloat(a_Offset.y); - Pkt.WriteBEFloat(a_Offset.z); - Pkt.WriteBEFloat(a_ParticleData); - Pkt.WriteBEInt32(a_ParticleAmount); - switch (ParticleID) - { - // iconcrack - case 36: - { - Pkt.WriteVarInt32(static_cast(a_Data[0])); - Pkt.WriteVarInt32(static_cast(a_Data[1])); - break; - } - // blockcrack - // blockdust - case 37: - case 38: - { - Pkt.WriteVarInt32(static_cast(a_Data[0])); - break; - } - default: - { - break; - } - } -} - - - - - -void cProtocol_1_9_0::SendPlayerListAddPlayer(const cPlayer & a_Player) -{ - ASSERT(m_State == 3); // In game mode? - - cPacketizer Pkt(*this, pktPlayerList); - Pkt.WriteVarInt32(0); - Pkt.WriteVarInt32(1); - Pkt.WriteUUID(a_Player.GetUUID()); - Pkt.WriteString(a_Player.GetPlayerListName()); - - const Json::Value & Properties = a_Player.GetClientHandle()->GetProperties(); - Pkt.WriteVarInt32(Properties.size()); - for (auto & Node : Properties) - { - Pkt.WriteString(Node.get("name", "").asString()); - Pkt.WriteString(Node.get("value", "").asString()); - AString Signature = Node.get("signature", "").asString(); - if (Signature.empty()) - { - Pkt.WriteBool(false); - } - else - { - Pkt.WriteBool(true); - Pkt.WriteString(Signature); - } - } - - Pkt.WriteVarInt32(static_cast(a_Player.GetEffectiveGameMode())); - Pkt.WriteVarInt32(static_cast(a_Player.GetClientHandle()->GetPing())); - Pkt.WriteBool(false); -} - - - - - -void cProtocol_1_9_0::SendPlayerListRemovePlayer(const cPlayer & a_Player) -{ - ASSERT(m_State == 3); // In game mode? - - cPacketizer Pkt(*this, pktPlayerList); - Pkt.WriteVarInt32(4); - Pkt.WriteVarInt32(1); - Pkt.WriteUUID(a_Player.GetUUID()); -} - - - - - -void cProtocol_1_9_0::SendPlayerListUpdateGameMode(const cPlayer & a_Player) -{ - ASSERT(m_State == 3); // In game mode? - - cPacketizer Pkt(*this, pktPlayerList); - Pkt.WriteVarInt32(1); - Pkt.WriteVarInt32(1); - Pkt.WriteUUID(a_Player.GetUUID()); - Pkt.WriteVarInt32(static_cast(a_Player.GetEffectiveGameMode())); -} - - - - - -void cProtocol_1_9_0::SendPlayerListUpdatePing(const cPlayer & a_Player) -{ - ASSERT(m_State == 3); // In game mode? - - auto ClientHandle = a_Player.GetClientHandlePtr(); - if (ClientHandle != nullptr) - { - cPacketizer Pkt(*this, pktPlayerList); - Pkt.WriteVarInt32(2); - Pkt.WriteVarInt32(1); - Pkt.WriteUUID(a_Player.GetUUID()); - Pkt.WriteVarInt32(static_cast(ClientHandle->GetPing())); - } -} - - - - - -void cProtocol_1_9_0::SendPlayerListUpdateDisplayName(const cPlayer & a_Player, const AString & a_CustomName) -{ - ASSERT(m_State == 3); // In game mode? - - cPacketizer Pkt(*this, pktPlayerList); - Pkt.WriteVarInt32(3); - Pkt.WriteVarInt32(1); - Pkt.WriteUUID(a_Player.GetUUID()); - - if (a_CustomName.empty()) - { - Pkt.WriteBool(false); - } - else - { - Pkt.WriteBool(true); - Pkt.WriteString(Printf("{\"text\":\"%s\"}", a_CustomName.c_str())); - } -} - - - - - -void cProtocol_1_9_0::SendPlayerMaxSpeed(void) -{ - ASSERT(m_State == 3); // In game mode? - - cPacketizer Pkt(*this, pktPlayerMaxSpeed); - cPlayer * Player = m_Client->GetPlayer(); - Pkt.WriteVarInt32(Player->GetUniqueID()); - Pkt.WriteBEInt32(1); // Count - Pkt.WriteString("generic.movementSpeed"); - // The default game speed is 0.1, multiply that value by the relative speed: - Pkt.WriteBEDouble(0.1 * Player->GetNormalMaxSpeed()); - if (Player->IsSprinting()) - { - Pkt.WriteVarInt32(1); // Modifier count - Pkt.WriteBEUInt64(0x662a6b8dda3e4c1c); - Pkt.WriteBEUInt64(0x881396ea6097278d); // UUID of the modifier - Pkt.WriteBEDouble(Player->GetSprintingMaxSpeed() - Player->GetNormalMaxSpeed()); - Pkt.WriteBEUInt8(2); - } - else - { - Pkt.WriteVarInt32(0); // Modifier count - } -} - - - - - -void cProtocol_1_9_0::SendPlayerMoveLook(void) -{ - ASSERT(m_State == 3); // In game mode? - - cPacketizer Pkt(*this, pktPlayerMoveLook); - cPlayer * Player = m_Client->GetPlayer(); - Pkt.WriteBEDouble(Player->GetPosX()); - Pkt.WriteBEDouble(Player->GetPosY()); - Pkt.WriteBEDouble(Player->GetPosZ()); - Pkt.WriteBEFloat(static_cast(Player->GetYaw())); - Pkt.WriteBEFloat(static_cast(Player->GetPitch())); - Pkt.WriteBEUInt8(0); - Pkt.WriteVarInt32(++m_OutstandingTeleportId); - - // This teleport ID hasn't been confirmed yet - m_IsTeleportIdConfirmed = false; -} - - - - - -void cProtocol_1_9_0::SendPlayerPosition(void) -{ - // There is no dedicated packet for this, send the whole thing: - SendPlayerMoveLook(); -} - - - - - -void cProtocol_1_9_0::SendPlayerSpawn(const cPlayer & a_Player) -{ - // Called to spawn another player for the client - cPacketizer Pkt(*this, pktSpawnOtherPlayer); - Pkt.WriteVarInt32(a_Player.GetUniqueID()); - Pkt.WriteUUID(a_Player.GetUUID()); - Vector3d LastSentPos = a_Player.GetLastSentPos(); - 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); - Pkt.WriteByteAngle(a_Player.GetYaw()); - Pkt.WriteByteAngle(a_Player.GetPitch()); - WriteEntityMetadata(Pkt, a_Player); - Pkt.WriteBEUInt8(0xff); // Metadata: end -} - - - - - -void cProtocol_1_9_0::SendPluginMessage(const AString & a_Channel, const AString & a_Message) -{ - ASSERT(m_State == 3); // In game mode? - - cPacketizer Pkt(*this, pktPluginMessage); - Pkt.WriteString(a_Channel); - Pkt.WriteBuf(a_Message.data(), a_Message.size()); -} - - - - - -void cProtocol_1_9_0::SendRemoveEntityEffect(const cEntity & a_Entity, int a_EffectID) -{ - ASSERT(m_State == 3); // In game mode? - - cPacketizer Pkt(*this, pktRemoveEntityEffect); - Pkt.WriteVarInt32(a_Entity.GetUniqueID()); - Pkt.WriteBEUInt8(static_cast(a_EffectID)); -} - - - - - -void cProtocol_1_9_0::SendResetTitle(void) -{ - ASSERT(m_State == 3); // In game mode? - - cPacketizer Pkt(*this, pktTitle); - Pkt.WriteVarInt32(4); // Reset title -} - - - - - -void cProtocol_1_9_0::SendResourcePack(const AString & a_ResourcePackUrl) -{ - cPacketizer Pkt(*this, pktResourcePack); - - cSha1Checksum Checksum; - Checksum.Update(reinterpret_cast(a_ResourcePackUrl.c_str()), a_ResourcePackUrl.size()); - Byte Digest[20]; - Checksum.Finalize(Digest); - AString Sha1Output; - cSha1Checksum::DigestToHex(Digest, Sha1Output); - - Pkt.WriteString(a_ResourcePackUrl); - Pkt.WriteString(Sha1Output); -} - - - - - -void cProtocol_1_9_0::SendRespawn(eDimension a_Dimension) -{ - cPacketizer Pkt(*this, pktRespawn); - cPlayer * Player = m_Client->GetPlayer(); - Pkt.WriteBEInt32(static_cast(a_Dimension)); - Pkt.WriteBEUInt8(2); // TODO: Difficulty (set to Normal) - Pkt.WriteBEUInt8(static_cast(Player->GetEffectiveGameMode())); - Pkt.WriteString("default"); -} - - - - - -void cProtocol_1_9_0::SendScoreboardObjective(const AString & a_Name, const AString & a_DisplayName, Byte a_Mode) -{ - ASSERT(m_State == 3); // In game mode? - - cPacketizer Pkt(*this, pktScoreboardObjective); - Pkt.WriteString(a_Name); - Pkt.WriteBEUInt8(a_Mode); - if ((a_Mode == 0) || (a_Mode == 2)) - { - Pkt.WriteString(a_DisplayName); - Pkt.WriteString("integer"); - } -} - - - - - -void cProtocol_1_9_0::SendScoreUpdate(const AString & a_Objective, const AString & a_Player, cObjective::Score a_Score, Byte a_Mode) -{ - ASSERT(m_State == 3); // In game mode? - - cPacketizer Pkt(*this, pktUpdateScore); - Pkt.WriteString(a_Player); - Pkt.WriteBEUInt8(a_Mode); - Pkt.WriteString(a_Objective); - - if (a_Mode != 1) - { - Pkt.WriteVarInt32(static_cast(a_Score)); - } -} - - - - - -void cProtocol_1_9_0::SendDisplayObjective(const AString & a_Objective, cScoreboard::eDisplaySlot a_Display) -{ - ASSERT(m_State == 3); // In game mode? - - cPacketizer Pkt(*this, pktDisplayObjective); - Pkt.WriteBEUInt8(static_cast(a_Display)); - Pkt.WriteString(a_Objective); -} - - - - - -void cProtocol_1_9_0::SendSetSubTitle(const cCompositeChat & a_SubTitle) -{ - SendSetRawSubTitle(a_SubTitle.CreateJsonString(false)); -} - - - - - -void cProtocol_1_9_0::SendSetRawSubTitle(const AString & a_SubTitle) -{ - ASSERT(m_State == 3); // In game mode? - - cPacketizer Pkt(*this, pktTitle); - Pkt.WriteVarInt32(1); // Set subtitle - Pkt.WriteString(a_SubTitle); -} - - - - - -void cProtocol_1_9_0::SendSetTitle(const cCompositeChat & a_Title) -{ - SendSetRawTitle(a_Title.CreateJsonString(false)); -} - - - - - -void cProtocol_1_9_0::SendSetRawTitle(const AString & a_Title) -{ - ASSERT(m_State == 3); // In game mode? - - cPacketizer Pkt(*this, pktTitle); - Pkt.WriteVarInt32(0); // Set title - Pkt.WriteString(a_Title); -} - - - - - -void cProtocol_1_9_0::SendSoundEffect(const AString & a_SoundName, double a_X, double a_Y, double a_Z, float a_Volume, float a_Pitch) -{ - ASSERT(m_State == 3); // In game mode? - - cPacketizer Pkt(*this, pktSoundEffect); - Pkt.WriteString(a_SoundName); - Pkt.WriteVarInt32(0); // Master sound category (may want to be changed to a parameter later) - Pkt.WriteBEInt32(static_cast(a_X * 8.0)); - Pkt.WriteBEInt32(static_cast(a_Y * 8.0)); - Pkt.WriteBEInt32(static_cast(a_Z * 8.0)); - Pkt.WriteBEFloat(a_Volume); - Pkt.WriteBEUInt8(static_cast(a_Pitch * 63)); -} - - - - - -void cProtocol_1_9_0::SendSoundParticleEffect(const EffectID a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data) -{ - ASSERT(m_State == 3); // In game mode? - - cPacketizer Pkt(*this, pktSoundParticleEffect); - Pkt.WriteBEInt32(static_cast(a_EffectID)); - Pkt.WritePosition64(a_SrcX, a_SrcY, a_SrcZ); - Pkt.WriteBEInt32(a_Data); - Pkt.WriteBool(false); -} - - - - - -void cProtocol_1_9_0::SendSpawnFallingBlock(const cFallingBlock & a_FallingBlock) -{ - ASSERT(m_State == 3); // In game mode? - - cPacketizer Pkt(*this, pktSpawnObject); - Pkt.WriteVarInt32(a_FallingBlock.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_FallingBlock.GetUniqueID()); - Pkt.WriteBEUInt8(70); // Falling block - Vector3d LastSentPos = a_FallingBlock.GetLastSentPos(); - Pkt.WriteBEDouble(LastSentPos.x); - Pkt.WriteBEDouble(LastSentPos.y); - Pkt.WriteBEDouble(LastSentPos.z); - Pkt.WriteByteAngle(a_FallingBlock.GetYaw()); - Pkt.WriteByteAngle(a_FallingBlock.GetPitch()); - Pkt.WriteBEInt32(static_cast(a_FallingBlock.GetBlockType()) | (static_cast(a_FallingBlock.GetBlockMeta()) << 12)); - Pkt.WriteBEInt16(static_cast(a_FallingBlock.GetSpeedX() * 400)); - Pkt.WriteBEInt16(static_cast(a_FallingBlock.GetSpeedY() * 400)); - Pkt.WriteBEInt16(static_cast(a_FallingBlock.GetSpeedZ() * 400)); -} - - - - - -void cProtocol_1_9_0::SendSpawnMob(const cMonster & a_Mob) -{ - ASSERT(m_State == 3); // In game mode? - - cPacketizer Pkt(*this, pktSpawnMob); - Pkt.WriteVarInt32(a_Mob.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_Mob.GetUniqueID()); - Pkt.WriteBEUInt8(static_cast(GetProtocolMobType(a_Mob.GetMobType()))); - Vector3d LastSentPos = a_Mob.GetLastSentPos(); - Pkt.WriteBEDouble(LastSentPos.x); - Pkt.WriteBEDouble(LastSentPos.y); - Pkt.WriteBEDouble(LastSentPos.z); - Pkt.WriteByteAngle(a_Mob.GetPitch()); - Pkt.WriteByteAngle(a_Mob.GetHeadYaw()); - Pkt.WriteByteAngle(a_Mob.GetYaw()); - Pkt.WriteBEInt16(static_cast(a_Mob.GetSpeedX() * 400)); - Pkt.WriteBEInt16(static_cast(a_Mob.GetSpeedY() * 400)); - Pkt.WriteBEInt16(static_cast(a_Mob.GetSpeedZ() * 400)); - WriteEntityMetadata(Pkt, a_Mob); - Pkt.WriteBEUInt8(0xff); // Metadata terminator -} - - - - - -void cProtocol_1_9_0::SendSpawnObject(const cEntity & a_Entity, char a_ObjectType, int a_ObjectData) -{ - ASSERT(m_State == 3); // In game mode? - double PosX = a_Entity.GetPosX(); - double PosZ = a_Entity.GetPosZ(); - double Yaw = a_Entity.GetYaw(); - if (a_ObjectType == 71) - { - FixItemFramePositions(a_ObjectData, PosX, PosZ, Yaw); - } + cPacketizer Pkt(*this, pktPlayerMoveLook); + cPlayer * Player = m_Client->GetPlayer(); + Pkt.WriteBEDouble(Player->GetPosX()); + Pkt.WriteBEDouble(Player->GetPosY()); + Pkt.WriteBEDouble(Player->GetPosZ()); + Pkt.WriteBEFloat(static_cast(Player->GetYaw())); + Pkt.WriteBEFloat(static_cast(Player->GetPitch())); + Pkt.WriteBEUInt8(0); + Pkt.WriteVarInt32(++m_OutstandingTeleportId); - 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(static_cast(a_ObjectType)); - Pkt.WriteBEDouble(PosX); - Pkt.WriteBEDouble(a_Entity.GetPosY()); - Pkt.WriteBEDouble(PosZ); - Pkt.WriteByteAngle(a_Entity.GetPitch()); - Pkt.WriteByteAngle(Yaw); - 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)); + // This teleport ID hasn't been confirmed yet + m_IsTeleportIdConfirmed = false; } -void cProtocol_1_9_0::SendSpawnVehicle(const cEntity & a_Vehicle, char a_VehicleType, char a_VehicleSubType) +void cProtocol_1_9_0::SendPlayerSpawn(const cPlayer & a_Player) { - ASSERT(m_State == 3); // In game mode? - - cPacketizer Pkt(*this, pktSpawnObject); - Pkt.WriteVarInt32(a_Vehicle.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_Vehicle.GetUniqueID()); - Pkt.WriteBEUInt8(static_cast(a_VehicleType)); - Vector3d LastSentPos = a_Vehicle.GetLastSentPos(); + // Called to spawn another player for the client + cPacketizer Pkt(*this, pktSpawnOtherPlayer); + Pkt.WriteVarInt32(a_Player.GetUniqueID()); + Pkt.WriteUUID(a_Player.GetUUID()); + Vector3d LastSentPos = a_Player.GetLastSentPos(); Pkt.WriteBEDouble(LastSentPos.x); - Pkt.WriteBEDouble(LastSentPos.y); + 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); - Pkt.WriteByteAngle(a_Vehicle.GetPitch()); - Pkt.WriteByteAngle(a_Vehicle.GetYaw()); - Pkt.WriteBEInt32(a_VehicleSubType); - Pkt.WriteBEInt16(static_cast(a_Vehicle.GetSpeedX() * 400)); - Pkt.WriteBEInt16(static_cast(a_Vehicle.GetSpeedY() * 400)); - Pkt.WriteBEInt16(static_cast(a_Vehicle.GetSpeedZ() * 400)); -} - - - - - -void cProtocol_1_9_0::SendStatistics(const cStatManager & a_Manager) -{ - ASSERT(m_State == 3); // In game mode? - - cPacketizer Pkt(*this, pktStatistics); - Pkt.WriteVarInt32(statCount); // TODO 2014-05-11 xdot: Optimization: Send "dirty" statistics only - - size_t Count = static_cast(statCount); - for (size_t i = 0; i < Count; ++i) - { - StatValue Value = a_Manager.GetValue(static_cast(i)); - const AString & StatName = cStatInfo::GetName(static_cast(i)); - - Pkt.WriteString(StatName); - Pkt.WriteVarInt32(static_cast(Value)); - } -} - - - - - -void cProtocol_1_9_0::SendTabCompletionResults(const AStringVector & a_Results) -{ - ASSERT(m_State == 3); // In game mode? - - cPacketizer Pkt(*this, pktTabCompletionResults); - Pkt.WriteVarInt32(static_cast(a_Results.size())); - - for (AStringVector::const_iterator itr = a_Results.begin(), end = a_Results.end(); itr != end; ++itr) - { - Pkt.WriteString(*itr); - } -} - - - - - -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? - - cPacketizer Pkt(*this, pktSpawnGlobalEntity); - Pkt.WriteVarInt32(0); // EntityID = 0, always - Pkt.WriteBEUInt8(1); // Type = Thunderbolt - Pkt.WriteBEDouble(a_BlockX); - Pkt.WriteBEDouble(a_BlockY); - Pkt.WriteBEDouble(a_BlockZ); -} - - - - - -void cProtocol_1_9_0::SendTitleTimes(int a_FadeInTicks, int a_DisplayTicks, int a_FadeOutTicks) -{ - ASSERT(m_State == 3); // In game mode? - - cPacketizer Pkt(*this, pktTitle); - Pkt.WriteVarInt32(2); // Set title display times - Pkt.WriteBEInt32(a_FadeInTicks); - Pkt.WriteBEInt32(a_DisplayTicks); - Pkt.WriteBEInt32(a_FadeOutTicks); -} - - - - - -void cProtocol_1_9_0::SendTimeUpdate(Int64 a_WorldAge, Int64 a_TimeOfDay, bool a_DoDaylightCycle) -{ - ASSERT(m_State == 3); // In game mode? - if (!a_DoDaylightCycle) - { - // When writing a "-" before the number the client ignores it but it will stop the client-side time expiration. - a_TimeOfDay = std::min(-a_TimeOfDay, -1LL); - } - - cPacketizer Pkt(*this, pktTimeUpdate); - Pkt.WriteBEInt64(a_WorldAge); - Pkt.WriteBEInt64(a_TimeOfDay); -} - - - - - -void cProtocol_1_9_0::SendUnloadChunk(int a_ChunkX, int a_ChunkZ) -{ - ASSERT(m_State == 3); // In game mode? - - cPacketizer Pkt(*this, pktUnloadChunk); - Pkt.WriteBEInt32(a_ChunkX); - Pkt.WriteBEInt32(a_ChunkZ); -} - - - - - -void cProtocol_1_9_0::SendUpdateBlockEntity(cBlockEntity & a_BlockEntity) -{ - ASSERT(m_State == 3); // In game mode? - - cPacketizer Pkt(*this, pktUpdateBlockEntity); - Pkt.WritePosition64(a_BlockEntity.GetPosX(), a_BlockEntity.GetPosY(), a_BlockEntity.GetPosZ()); - Byte Action = 0; - switch (a_BlockEntity.GetBlockType()) - { - case E_BLOCK_MOB_SPAWNER: Action = 1; break; // Update mob spawner spinny mob thing - case E_BLOCK_COMMAND_BLOCK: Action = 2; break; // Update command block text - case E_BLOCK_BEACON: Action = 3; break; // Update beacon entity - case E_BLOCK_HEAD: Action = 4; break; // Update Mobhead entity - case E_BLOCK_FLOWER_POT: Action = 5; break; // Update flower pot - case E_BLOCK_BED: Action = 11; break; // Update bed color - default: ASSERT(!"Unhandled or unimplemented BlockEntity update request!"); break; - } - Pkt.WriteBEUInt8(Action); - - WriteBlockEntity(Pkt, a_BlockEntity); -} - - - - - -void cProtocol_1_9_0::SendUpdateSign(int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4) -{ - ASSERT(m_State == 3); // In game mode? - - cPacketizer Pkt(*this, pktUpdateSign); - Pkt.WritePosition64(a_BlockX, a_BlockY, a_BlockZ); - - Json::StyledWriter JsonWriter; - AString Lines[] = { a_Line1, a_Line2, a_Line3, a_Line4 }; - for (size_t i = 0; i < ARRAYCOUNT(Lines); i++) - { - Json::Value RootValue; - RootValue["text"] = Lines[i]; - Pkt.WriteString(JsonWriter.write(RootValue).c_str()); - } -} - - - - - -void cProtocol_1_9_0::SendUseBed(const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ) -{ - ASSERT(m_State == 3); // In game mode? - - cPacketizer Pkt(*this, pktUseBed); - Pkt.WriteVarInt32(a_Entity.GetUniqueID()); - Pkt.WritePosition64(a_BlockX, a_BlockY, a_BlockZ); -} - - - - - -void cProtocol_1_9_0::SendWeather(eWeather a_Weather) -{ - ASSERT(m_State == 3); // In game mode? - - { - cPacketizer Pkt(*this, pktWeather); - Pkt.WriteBEUInt8((a_Weather == wSunny) ? 1 : 2); // End rain / begin rain - Pkt.WriteBEFloat(0); // Unused for weather - } - - // TODO: Fade effect, somehow -} - - - - - -void cProtocol_1_9_0::SendWholeInventory(const cWindow & a_Window) -{ - ASSERT(m_State == 3); // In game mode? - - cPacketizer Pkt(*this, pktWindowItems); - Pkt.WriteBEUInt8(static_cast(a_Window.GetWindowID())); - Pkt.WriteBEInt16(static_cast(a_Window.GetNumSlots())); - cItems Slots; - a_Window.GetSlots(*(m_Client->GetPlayer()), Slots); - for (cItems::const_iterator itr = Slots.begin(), end = Slots.end(); itr != end; ++itr) - { - WriteItem(Pkt, *itr); - } // for itr - Slots[] -} - - - - - -void cProtocol_1_9_0::SendWindowClose(const cWindow & a_Window) -{ - ASSERT(m_State == 3); // In game mode? - - cPacketizer Pkt(*this, pktWindowClose); - Pkt.WriteBEUInt8(static_cast(a_Window.GetWindowID())); -} - - - - - -void cProtocol_1_9_0::SendWindowOpen(const cWindow & a_Window) -{ - ASSERT(m_State == 3); // In game mode? - - if (a_Window.GetWindowType() < 0) - { - // Do not send this packet for player inventory windows - return; - } - - cPacketizer Pkt(*this, pktWindowOpen); - Pkt.WriteBEUInt8(static_cast(a_Window.GetWindowID())); - Pkt.WriteString(a_Window.GetWindowTypeName()); - Pkt.WriteString(Printf("{\"text\":\"%s\"}", a_Window.GetWindowTitle().c_str())); - - switch (a_Window.GetWindowType()) - { - case cWindow::wtWorkbench: - case cWindow::wtEnchantment: - case cWindow::wtAnvil: - { - Pkt.WriteBEUInt8(0); - break; - } - default: - { - Pkt.WriteBEUInt8(static_cast(a_Window.GetNumNonInventorySlots())); - break; - } - } - - if (a_Window.GetWindowType() == cWindow::wtAnimalChest) - { - UInt32 HorseID = static_cast(a_Window).GetHorseID(); - Pkt.WriteBEInt32(static_cast(HorseID)); - } + Pkt.WriteByteAngle(a_Player.GetYaw()); + Pkt.WriteByteAngle(a_Player.GetPitch()); + WriteEntityMetadata(Pkt, a_Player); + Pkt.WriteBEUInt8(0xff); // Metadata: end } -void cProtocol_1_9_0::SendWindowProperty(const cWindow & a_Window, short a_Property, short a_Value) +void cProtocol_1_9_0::SendSoundEffect(const AString & a_SoundName, double a_X, double a_Y, double a_Z, float a_Volume, float a_Pitch) { ASSERT(m_State == 3); // In game mode? - cPacketizer Pkt(*this, pktWindowProperty); - Pkt.WriteBEUInt8(static_cast(a_Window.GetWindowID())); - Pkt.WriteBEInt16(a_Property); - Pkt.WriteBEInt16(a_Value); + cPacketizer Pkt(*this, pktSoundEffect); + Pkt.WriteString(a_SoundName); + Pkt.WriteVarInt32(0); // Master sound category (may want to be changed to a parameter later) + Pkt.WriteBEInt32(static_cast(a_X * 8.0)); + Pkt.WriteBEInt32(static_cast(a_Y * 8.0)); + Pkt.WriteBEInt32(static_cast(a_Z * 8.0)); + Pkt.WriteBEFloat(a_Volume); + Pkt.WriteBEUInt8(static_cast(a_Pitch * 63)); } -bool cProtocol_1_9_0::CompressPacket(const AString & a_Packet, AString & a_CompressedData) +void cProtocol_1_9_0::SendSpawnFallingBlock(const cFallingBlock & a_FallingBlock) { - // Compress the data: - char CompressedData[MAX_COMPRESSED_PACKET_LEN]; - - uLongf CompressedSize = compressBound(static_cast(a_Packet.size())); - if (CompressedSize >= MAX_COMPRESSED_PACKET_LEN) - { - ASSERT(!"Too high packet size."); - return false; - } - - int Status = compress2( - reinterpret_cast(CompressedData), &CompressedSize, - reinterpret_cast(a_Packet.data()), static_cast(a_Packet.size()), Z_DEFAULT_COMPRESSION - ); - if (Status != Z_OK) - { - return false; - } + ASSERT(m_State == 3); // In game mode? - AString LengthData; - cByteBuffer Buffer(20); - Buffer.WriteVarInt32(static_cast(a_Packet.size())); - Buffer.ReadAll(LengthData); - Buffer.CommitRead(); - - Buffer.WriteVarInt32(static_cast(CompressedSize + LengthData.size())); - Buffer.WriteVarInt32(static_cast(a_Packet.size())); - Buffer.ReadAll(LengthData); - Buffer.CommitRead(); - - a_CompressedData.clear(); - a_CompressedData.reserve(LengthData.size() + CompressedSize); - a_CompressedData.append(LengthData.data(), LengthData.size()); - a_CompressedData.append(CompressedData, CompressedSize); - return true; + cPacketizer Pkt(*this, pktSpawnObject); + Pkt.WriteVarInt32(a_FallingBlock.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_FallingBlock.GetUniqueID()); + Pkt.WriteBEUInt8(70); // Falling block + Vector3d LastSentPos = a_FallingBlock.GetLastSentPos(); + Pkt.WriteBEDouble(LastSentPos.x); + Pkt.WriteBEDouble(LastSentPos.y); + Pkt.WriteBEDouble(LastSentPos.z); + Pkt.WriteByteAngle(a_FallingBlock.GetYaw()); + Pkt.WriteByteAngle(a_FallingBlock.GetPitch()); + Pkt.WriteBEInt32(static_cast(a_FallingBlock.GetBlockType()) | (static_cast(a_FallingBlock.GetBlockMeta()) << 12)); + Pkt.WriteBEInt16(static_cast(a_FallingBlock.GetSpeedX() * 400)); + Pkt.WriteBEInt16(static_cast(a_FallingBlock.GetSpeedY() * 400)); + Pkt.WriteBEInt16(static_cast(a_FallingBlock.GetSpeedZ() * 400)); } -int cProtocol_1_9_0::GetParticleID(const AString & a_ParticleName) +void cProtocol_1_9_0::SendSpawnMob(const cMonster & a_Mob) { - static std::map ParticleMap; - if (ParticleMap.empty()) - { - // Initialize the ParticleMap: - ParticleMap["explode"] = 0; - ParticleMap["largeexplode"] = 1; - ParticleMap["hugeexplosion"] = 2; - ParticleMap["fireworksspark"] = 3; - ParticleMap["bubble"] = 4; - ParticleMap["splash"] = 5; - ParticleMap["wake"] = 6; - ParticleMap["suspended"] = 7; - ParticleMap["depthsuspend"] = 8; - ParticleMap["crit"] = 9; - ParticleMap["magiccrit"] = 10; - ParticleMap["smoke"] = 11; - ParticleMap["largesmoke"] = 12; - ParticleMap["spell"] = 13; - ParticleMap["instantspell"] = 14; - ParticleMap["mobspell"] = 15; - ParticleMap["mobspellambient"] = 16; - ParticleMap["witchmagic"] = 17; - ParticleMap["dripwater"] = 18; - ParticleMap["driplava"] = 19; - ParticleMap["angryvillager"] = 20; - ParticleMap["happyvillager"] = 21; - ParticleMap["townaura"] = 22; - ParticleMap["note"] = 23; - ParticleMap["portal"] = 24; - ParticleMap["enchantmenttable"] = 25; - ParticleMap["flame"] = 26; - ParticleMap["lava"] = 27; - ParticleMap["footstep"] = 28; - ParticleMap["cloud"] = 29; - ParticleMap["reddust"] = 30; - ParticleMap["snowballpoof"] = 31; - ParticleMap["snowshovel"] = 32; - ParticleMap["slime"] = 33; - ParticleMap["heart"] = 34; - ParticleMap["barrier"] = 35; - ParticleMap["iconcrack"] = 36; - ParticleMap["blockcrack"] = 37; - ParticleMap["blockdust"] = 38; - ParticleMap["droplet"] = 39; - ParticleMap["take"] = 40; - ParticleMap["mobappearance"] = 41; - ParticleMap["dragonbreath"] = 42; - ParticleMap["endrod"] = 43; - ParticleMap["damageindicator"] = 44; - ParticleMap["sweepattack"] = 45; - ParticleMap["fallingdust"] = 46; - ParticleMap["totem"] = 47; - ParticleMap["spit"] = 48; - } - - AString ParticleName = StrToLower(a_ParticleName); - if (ParticleMap.find(ParticleName) == ParticleMap.end()) - { - LOGWARNING("Unknown particle: %s", a_ParticleName.c_str()); - ASSERT(!"Unknown particle"); - return 0; - } + ASSERT(m_State == 3); // In game mode? - return ParticleMap[ParticleName]; + cPacketizer Pkt(*this, pktSpawnMob); + Pkt.WriteVarInt32(a_Mob.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_Mob.GetUniqueID()); + Pkt.WriteBEUInt8(static_cast(GetProtocolMobType(a_Mob.GetMobType()))); + Vector3d LastSentPos = a_Mob.GetLastSentPos(); + Pkt.WriteBEDouble(LastSentPos.x); + Pkt.WriteBEDouble(LastSentPos.y); + Pkt.WriteBEDouble(LastSentPos.z); + Pkt.WriteByteAngle(a_Mob.GetPitch()); + Pkt.WriteByteAngle(a_Mob.GetHeadYaw()); + Pkt.WriteByteAngle(a_Mob.GetYaw()); + Pkt.WriteBEInt16(static_cast(a_Mob.GetSpeedX() * 400)); + Pkt.WriteBEInt16(static_cast(a_Mob.GetSpeedY() * 400)); + Pkt.WriteBEInt16(static_cast(a_Mob.GetSpeedZ() * 400)); + WriteEntityMetadata(Pkt, a_Mob); + Pkt.WriteBEUInt8(0xff); // Metadata terminator } -UInt32 cProtocol_1_9_0::GetProtocolMobType(eMonsterType a_MobType) +void cProtocol_1_9_0::SendSpawnObject(const cEntity & a_Entity, char a_ObjectType, int a_ObjectData) { - switch (a_MobType) + ASSERT(m_State == 3); // In game mode? + double PosX = a_Entity.GetPosX(); + double PosZ = a_Entity.GetPosZ(); + double Yaw = a_Entity.GetYaw(); + if (a_ObjectType == 71) { - // Map invalid type to Giant for easy debugging (if this ever spawns, something has gone very wrong) - case mtInvalidType: return 52; - case mtBat: return 65; - case mtBlaze: return 61; - case mtCaveSpider: return 59; - case mtChicken: return 93; - case mtCow: return 92; - case mtCreeper: return 50; - case mtEnderDragon: return 63; - case mtEnderman: return 58; - case mtGhast: return 56; - case mtGiant: return 53; - case mtGuardian: return 68; - case mtHorse: return 100; - case mtIronGolem: return 99; - case mtMagmaCube: return 62; - case mtMooshroom: return 96; - case mtOcelot: return 98; - case mtPig: return 90; - case mtRabbit: return 101; - case mtSheep: return 91; - case mtSilverfish: return 60; - case mtSkeleton: return 51; - case mtSlime: return 55; - case mtSnowGolem: return 97; - case mtSpider: return 52; - case mtSquid: return 94; - case mtVillager: return 120; - case mtWitch: return 66; - case mtWither: return 64; - case mtWitherSkeleton: return 51; - case mtWolf: return 95; - case mtZombie: return 54; - case mtZombiePigman: return 57; - case mtZombieVillager: return 27; + FixItemFramePositions(a_ObjectData, PosX, PosZ, Yaw); } - UNREACHABLE("Unsupported mob type"); + + 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(static_cast(a_ObjectType)); + Pkt.WriteBEDouble(PosX); + Pkt.WriteBEDouble(a_Entity.GetPosY()); + Pkt.WriteBEDouble(PosZ); + Pkt.WriteByteAngle(a_Entity.GetPitch()); + Pkt.WriteByteAngle(Yaw); + 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::FixItemFramePositions(int a_ObjectData, double & a_PosX, double & a_PosZ, double & a_Yaw) +void cProtocol_1_9_0::SendSpawnVehicle(const cEntity & a_Vehicle, char a_VehicleType, char a_VehicleSubType) { - switch (a_ObjectData) - { - case 0: - { - a_PosZ += 1; - a_Yaw = 0; - break; - } - case 1: - { - a_PosX -= 1; - a_Yaw = 90; - break; - } - case 2: - { - a_PosZ -= 1; - a_Yaw = 180; - break; - } - case 3: - { - a_PosX += 1; - a_Yaw = 270; - break; - } - } + ASSERT(m_State == 3); // In game mode? + + cPacketizer Pkt(*this, pktSpawnObject); + Pkt.WriteVarInt32(a_Vehicle.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_Vehicle.GetUniqueID()); + Pkt.WriteBEUInt8(static_cast(a_VehicleType)); + Vector3d LastSentPos = a_Vehicle.GetLastSentPos(); + Pkt.WriteBEDouble(LastSentPos.x); + Pkt.WriteBEDouble(LastSentPos.y); + Pkt.WriteBEDouble(LastSentPos.z); + Pkt.WriteByteAngle(a_Vehicle.GetPitch()); + Pkt.WriteByteAngle(a_Vehicle.GetYaw()); + Pkt.WriteBEInt32(a_VehicleSubType); + Pkt.WriteBEInt16(static_cast(a_Vehicle.GetSpeedX() * 400)); + Pkt.WriteBEInt16(static_cast(a_Vehicle.GetSpeedY() * 400)); + Pkt.WriteBEInt16(static_cast(a_Vehicle.GetSpeedZ() * 400)); } -void cProtocol_1_9_0::AddReceivedData(const char * a_Data, size_t a_Size) +void cProtocol_1_9_0::SendTeleportEntity(const cEntity & a_Entity) { - // Write the incoming data into the comm log file: - if (g_ShouldLogCommIn && m_CommLogFile.IsOpen()) - { - if (m_ReceivedData.GetReadableSpace() > 0) - { - AString AllData; - size_t OldReadableSpace = m_ReceivedData.GetReadableSpace(); - m_ReceivedData.ReadAll(AllData); - m_ReceivedData.ResetRead(); - m_ReceivedData.SkipRead(m_ReceivedData.GetReadableSpace() - OldReadableSpace); - ASSERT(m_ReceivedData.GetReadableSpace() == OldReadableSpace); - AString Hex; - CreateHexDump(Hex, AllData.data(), AllData.size(), 16); - m_CommLogFile.Printf("Incoming data, %zu (0x%zx) unparsed bytes already present in buffer:\n%s\n", - AllData.size(), AllData.size(), Hex.c_str() - ); - } - AString Hex; - CreateHexDump(Hex, a_Data, a_Size, 16); - m_CommLogFile.Printf("Incoming data: %u (0x%x) bytes: \n%s\n", - static_cast(a_Size), static_cast(a_Size), Hex.c_str() - ); - m_CommLogFile.Flush(); - } - - if (!m_ReceivedData.Write(a_Data, a_Size)) - { - // Too much data in the incoming queue, report to caller: - m_Client->PacketBufferFull(); - return; - } - - // Handle all complete packets: - for (;;) - { - UInt32 PacketLen; - if (!m_ReceivedData.ReadVarInt(PacketLen)) - { - // Not enough data - m_ReceivedData.ResetRead(); - break; - } - if (!m_ReceivedData.CanReadBytes(PacketLen)) - { - // The full packet hasn't been received yet - m_ReceivedData.ResetRead(); - break; - } - - // Check packet for compression: - UInt32 UncompressedSize = 0; - AString UncompressedData; - if (m_State == 3) - { - UInt32 NumBytesRead = static_cast(m_ReceivedData.GetReadableSpace()); + ASSERT(m_State == 3); // In game mode? - if (!m_ReceivedData.ReadVarInt(UncompressedSize)) - { - m_Client->Kick("Compression packet incomplete"); - return; - } + 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()); +} - NumBytesRead -= static_cast(m_ReceivedData.GetReadableSpace()); // How many bytes has the UncompressedSize taken up? - ASSERT(PacketLen > NumBytesRead); - PacketLen -= NumBytesRead; - if (UncompressedSize > 0) - { - // Decompress the data: - AString CompressedData; - VERIFY(m_ReceivedData.ReadString(CompressedData, PacketLen)); - if (InflateString(CompressedData.data(), PacketLen, UncompressedData) != Z_OK) - { - m_Client->Kick("Compression failure"); - return; - } - PacketLen = static_cast(UncompressedData.size()); - if (PacketLen != UncompressedSize) - { - m_Client->Kick("Wrong uncompressed packet size given"); - return; - } - } - } - // Move the packet payload to a separate cByteBuffer, bb: - cByteBuffer bb(PacketLen + 1); - if (UncompressedSize == 0) - { - // No compression was used, move directly - VERIFY(m_ReceivedData.ReadToByteBuffer(bb, static_cast(PacketLen))); - } - else - { - // Compression was used, move the uncompressed data: - VERIFY(bb.Write(UncompressedData.data(), UncompressedData.size())); - } - m_ReceivedData.CommitRead(); - UInt32 PacketType; - if (!bb.ReadVarInt(PacketType)) - { - // Not enough data - break; - } - // Write one NUL extra, so that we can detect over-reads - bb.Write("\0", 1); +void cProtocol_1_9_0::SendThunderbolt(int a_BlockX, int a_BlockY, int a_BlockZ) +{ + ASSERT(m_State == 3); // In game mode? - // Log the packet info into the comm log file: - if (g_ShouldLogCommIn && m_CommLogFile.IsOpen()) - { - AString PacketData; - bb.ReadAll(PacketData); - bb.ResetRead(); - bb.ReadVarInt(PacketType); // We have already read the packet type once, it will be there again - ASSERT(PacketData.size() > 0); // We have written an extra NUL, so there had to be at least one byte read - PacketData.resize(PacketData.size() - 1); - AString PacketDataHex; - CreateHexDump(PacketDataHex, PacketData.data(), PacketData.size(), 16); - m_CommLogFile.Printf("Next incoming packet is type %u (0x%x), length %u (0x%x) at state %d. Payload:\n%s\n", - PacketType, PacketType, PacketLen, PacketLen, m_State, PacketDataHex.c_str() - ); - } + cPacketizer Pkt(*this, pktSpawnGlobalEntity); + Pkt.WriteVarInt32(0); // EntityID = 0, always + Pkt.WriteBEUInt8(1); // Type = Thunderbolt + Pkt.WriteBEDouble(a_BlockX); + Pkt.WriteBEDouble(a_BlockY); + Pkt.WriteBEDouble(a_BlockZ); +} - if (!HandlePacket(bb, PacketType)) - { - // Unknown packet, already been reported, but without the length. Log the length here: - LOGWARNING("Protocol 1.9: Unhandled packet: type 0x%x, state %d, length %u", PacketType, m_State, PacketLen); - - #ifdef _DEBUG - // Dump the packet contents into the log: - bb.ResetRead(); - AString Packet; - bb.ReadAll(Packet); - Packet.resize(Packet.size() - 1); // Drop the final NUL pushed there for over-read detection - AString Out; - CreateHexDump(Out, Packet.data(), Packet.size(), 24); - LOGD("Packet contents:\n%s", Out.c_str()); - #endif // _DEBUG - - // Put a message in the comm log: - if (g_ShouldLogCommIn && m_CommLogFile.IsOpen()) - { - m_CommLogFile.Printf("^^^^^^ Unhandled packet ^^^^^^\n\n\n"); - } - return; - } - // The packet should have 1 byte left in the buffer - the NUL we had added - if (bb.GetReadableSpace() != 1) - { - // Read more or less than packet length, report as error - LOGWARNING("Protocol 1.9: Wrong number of bytes read for packet 0x%x, state %d. Read %zu bytes, packet contained %u bytes", - PacketType, m_State, bb.GetUsedSpace() - bb.GetReadableSpace(), PacketLen - ); - // Put a message in the comm log: - if (g_ShouldLogCommIn && m_CommLogFile.IsOpen()) - { - m_CommLogFile.Printf("^^^^^^ Wrong number of bytes read for this packet (exp %d left, got %zu left) ^^^^^^\n\n\n", - 1, bb.GetReadableSpace() - ); - m_CommLogFile.Flush(); - } - ASSERT(!"Read wrong number of bytes!"); - m_Client->PacketError(PacketType); - } - } // for (ever) +void cProtocol_1_9_0::SendUnloadChunk(int a_ChunkX, int a_ChunkZ) +{ + ASSERT(m_State == 3); // In game mode? - // Log any leftover bytes into the logfile: - if (g_ShouldLogCommIn && (m_ReceivedData.GetReadableSpace() > 0) && m_CommLogFile.IsOpen()) - { - AString AllData; - size_t OldReadableSpace = m_ReceivedData.GetReadableSpace(); - m_ReceivedData.ReadAll(AllData); - m_ReceivedData.ResetRead(); - m_ReceivedData.SkipRead(m_ReceivedData.GetReadableSpace() - OldReadableSpace); - ASSERT(m_ReceivedData.GetReadableSpace() == OldReadableSpace); - AString Hex; - CreateHexDump(Hex, AllData.data(), AllData.size(), 16); - m_CommLogFile.Printf("Protocol 1.9: There are %zu (0x%zx) bytes of non-parse-able data left in the buffer:\n%s", - m_ReceivedData.GetReadableSpace(), m_ReceivedData.GetReadableSpace(), Hex.c_str() - ); - m_CommLogFile.Flush(); - } + cPacketizer Pkt(*this, pktUnloadChunk); + Pkt.WriteBEInt32(a_ChunkX); + Pkt.WriteBEInt32(a_ChunkZ); } @@ -2359,18 +784,6 @@ bool cProtocol_1_9_0::HandlePacket(cByteBuffer & a_ByteBuffer, UInt32 a_PacketTy -void cProtocol_1_9_0::HandlePacketStatusPing(cByteBuffer & a_ByteBuffer) -{ - HANDLE_READ(a_ByteBuffer, ReadBEInt64, Int64, Timestamp); - - cPacketizer Pkt(*this, pktPingResponse); - Pkt.WriteBEInt64(Timestamp); -} - - - - - void cProtocol_1_9_0::HandlePacketStatusRequest(cByteBuffer & a_ByteBuffer) { cServer * Server = cRoot::Get()->GetServer(); @@ -2388,129 +801,29 @@ void cProtocol_1_9_0::HandlePacketStatusRequest(cByteBuffer & a_ByteBuffer) // Players: Json::Value Players; Players["online"] = NumPlayers; - Players["max"] = MaxPlayers; - // TODO: Add "sample" - - // Description: - Json::Value Description; - Description["text"] = ServerDescription.c_str(); - - // Create the response: - Json::Value ResponseValue; - ResponseValue["version"] = Version; - ResponseValue["players"] = Players; - ResponseValue["description"] = Description; - m_Client->ForgeAugmentServerListPing(ResponseValue); - if (!Favicon.empty()) - { - ResponseValue["favicon"] = Printf("data:image/png;base64,%s", Favicon.c_str()); - } - - Json::FastWriter Writer; - AString Response = Writer.write(ResponseValue); - - cPacketizer Pkt(*this, pktStatusResponse); - Pkt.WriteString(Response); -} - - - - - -void cProtocol_1_9_0::HandlePacketLoginEncryptionResponse(cByteBuffer & a_ByteBuffer) -{ - UInt32 EncKeyLength, EncNonceLength; - if (!a_ByteBuffer.ReadVarInt(EncKeyLength)) - { - return; - } - AString EncKey; - if (!a_ByteBuffer.ReadString(EncKey, EncKeyLength)) - { - return; - } - if (!a_ByteBuffer.ReadVarInt(EncNonceLength)) - { - return; - } - AString EncNonce; - if (!a_ByteBuffer.ReadString(EncNonce, EncNonceLength)) - { - return; - } - if ((EncKeyLength > MAX_ENC_LEN) || (EncNonceLength > MAX_ENC_LEN)) - { - LOGD("Too long encryption"); - m_Client->Kick("Hacked client"); - return; - } - - // Decrypt EncNonce using privkey - cRsaPrivateKey & rsaDecryptor = cRoot::Get()->GetServer()->GetPrivateKey(); - UInt32 DecryptedNonce[MAX_ENC_LEN / sizeof(Int32)]; - int res = rsaDecryptor.Decrypt(reinterpret_cast(EncNonce.data()), EncNonce.size(), reinterpret_cast(DecryptedNonce), sizeof(DecryptedNonce)); - if (res != 4) - { - LOGD("Bad nonce length: got %d, exp %d", res, 4); - m_Client->Kick("Hacked client"); - return; - } - if (ntohl(DecryptedNonce[0]) != static_cast(reinterpret_cast(this))) - { - LOGD("Bad nonce value"); - m_Client->Kick("Hacked client"); - return; - } - - // Decrypt the symmetric encryption key using privkey: - Byte DecryptedKey[MAX_ENC_LEN]; - res = rsaDecryptor.Decrypt(reinterpret_cast(EncKey.data()), EncKey.size(), DecryptedKey, sizeof(DecryptedKey)); - if (res != 16) - { - LOGD("Bad key length"); - m_Client->Kick("Hacked client"); - return; - } - - StartEncryption(DecryptedKey); - m_Client->HandleLogin(m_Client->GetUsername()); -} - - - - + Players["max"] = MaxPlayers; + // TODO: Add "sample" -void cProtocol_1_9_0::HandlePacketLoginStart(cByteBuffer & a_ByteBuffer) -{ - AString Username; - if (!a_ByteBuffer.ReadVarUTF8String(Username)) - { - m_Client->Kick("Bad username"); - return; - } + // Description: + Json::Value Description; + Description["text"] = ServerDescription.c_str(); - if (!m_Client->HandleHandshake(Username)) + // Create the response: + Json::Value ResponseValue; + ResponseValue["version"] = Version; + ResponseValue["players"] = Players; + ResponseValue["description"] = Description; + m_Client->ForgeAugmentServerListPing(ResponseValue); + if (!Favicon.empty()) { - // The client is not welcome here, they have been sent a Kick packet already - return; + ResponseValue["favicon"] = Printf("data:image/png;base64,%s", Favicon.c_str()); } - cServer * Server = cRoot::Get()->GetServer(); - // If auth is required, then send the encryption request: - if (Server->ShouldAuthenticate()) - { - cPacketizer Pkt(*this, pktEncryptionRequest); - Pkt.WriteString(Server->GetServerID()); - const AString & PubKeyDer = Server->GetPublicKeyDER(); - Pkt.WriteVarInt32(static_cast(PubKeyDer.size())); - Pkt.WriteBuf(PubKeyDer.data(), PubKeyDer.size()); - Pkt.WriteVarInt32(4); - Pkt.WriteBEInt32(static_cast(reinterpret_cast(this))); // Using 'this' as the cryptographic nonce, so that we don't have to generate one each time :) - m_Client->SetUsername(Username); - return; - } + Json::FastWriter Writer; + AString Response = Writer.write(ResponseValue); - m_Client->HandleLogin(Username); + cPacketizer Pkt(*this, pktStatusResponse); + Pkt.WriteString(Response); } @@ -2589,16 +902,6 @@ void cProtocol_1_9_0::HandlePacketBoatSteer(cByteBuffer & a_ByteBuffer) -void cProtocol_1_9_0::HandlePacketChatMessage(cByteBuffer & a_ByteBuffer) -{ - HANDLE_READ(a_ByteBuffer, ReadVarUTF8String, AString, Message); - m_Client->HandleChat(Message); -} - - - - - void cProtocol_1_9_0::HandlePacketClientSettings(cByteBuffer & a_ByteBuffer) { HANDLE_READ(a_ByteBuffer, ReadVarUTF8String, AString, Locale); @@ -2619,38 +922,6 @@ void cProtocol_1_9_0::HandlePacketClientSettings(cByteBuffer & a_ByteBuffer) -void cProtocol_1_9_0::HandlePacketClientStatus(cByteBuffer & a_ByteBuffer) -{ - HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, ActionID); - switch (ActionID) - { - case 0: - { - // Respawn - m_Client->HandleRespawn(); - break; - } - case 1: - { - // Request stats - const cStatManager & Manager = m_Client->GetPlayer()->GetStatManager(); - SendStatistics(Manager); - - break; - } - case 2: - { - // Open Inventory achievement - m_Client->GetPlayer()->AwardAchievement(achOpenInv); - break; - } - } -} - - - - - void cProtocol_1_9_0::HandleConfirmTeleport(cByteBuffer & a_ByteBuffer) { HANDLE_READ(a_ByteBuffer, ReadVarInt32, UInt32, TeleportID); @@ -2666,21 +937,6 @@ void cProtocol_1_9_0::HandleConfirmTeleport(cByteBuffer & a_ByteBuffer) -void cProtocol_1_9_0::HandlePacketCreativeInventoryAction(cByteBuffer & a_ByteBuffer) -{ - HANDLE_READ(a_ByteBuffer, ReadBEInt16, Int16, SlotNum); - cItem Item; - if (!ReadItem(a_ByteBuffer, Item)) - { - return; - } - m_Client->HandleCreativeInventory(SlotNum, Item, (SlotNum == -1) ? caLeftClickOutside : caLeftClick); -} - - - - - void cProtocol_1_9_0::HandlePacketEntityAction(cByteBuffer & a_ByteBuffer) { HANDLE_READ(a_ByteBuffer, ReadVarInt, UInt32, PlayerID); @@ -2702,62 +958,6 @@ void cProtocol_1_9_0::HandlePacketEntityAction(cByteBuffer & a_ByteBuffer) -void cProtocol_1_9_0::HandlePacketKeepAlive(cByteBuffer & a_ByteBuffer) -{ - HANDLE_READ(a_ByteBuffer, ReadVarInt, UInt32, KeepAliveID); - m_Client->HandleKeepAlive(KeepAliveID); -} - - - - - -void cProtocol_1_9_0::HandlePacketPlayer(cByteBuffer & a_ByteBuffer) -{ - HANDLE_READ(a_ByteBuffer, ReadBool, bool, IsOnGround); - // TODO: m_Client->HandlePlayerOnGround(IsOnGround); -} - - - - - -void cProtocol_1_9_0::HandlePacketPlayerAbilities(cByteBuffer & a_ByteBuffer) -{ - HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, Flags); - HANDLE_READ(a_ByteBuffer, ReadBEFloat, float, FlyingSpeed); - HANDLE_READ(a_ByteBuffer, ReadBEFloat, float, WalkingSpeed); - - // COnvert the bitfield into individual boolean flags: - bool IsFlying = false, CanFly = false; - if ((Flags & 2) != 0) - { - IsFlying = true; - } - if ((Flags & 4) != 0) - { - CanFly = true; - } - - m_Client->HandlePlayerAbilities(CanFly, IsFlying, FlyingSpeed, WalkingSpeed); -} - - - - - -void cProtocol_1_9_0::HandlePacketPlayerLook(cByteBuffer & a_ByteBuffer) -{ - HANDLE_READ(a_ByteBuffer, ReadBEFloat, float, Yaw); - HANDLE_READ(a_ByteBuffer, ReadBEFloat, float, Pitch); - HANDLE_READ(a_ByteBuffer, ReadBool, bool, IsOnGround); - m_Client->HandlePlayerLook(Yaw, Pitch, IsOnGround); -} - - - - - void cProtocol_1_9_0::HandlePacketPlayerPos(cByteBuffer & a_ByteBuffer) { HANDLE_READ(a_ByteBuffer, ReadBEDouble, double, PosX); @@ -2794,72 +994,6 @@ void cProtocol_1_9_0::HandlePacketPlayerPosLook(cByteBuffer & a_ByteBuffer) -void cProtocol_1_9_0::HandlePacketPluginMessage(cByteBuffer & a_ByteBuffer) -{ - HANDLE_READ(a_ByteBuffer, ReadVarUTF8String, AString, Channel); - - // If the plugin channel is recognized vanilla, handle it directly: - if (Channel.substr(0, 3) == "MC|") - { - HandleVanillaPluginMessage(a_ByteBuffer, Channel); - - // Skip any unread data (vanilla sometimes sends garbage at the end of a packet; #1692): - if (a_ByteBuffer.GetReadableSpace() > 1) - { - LOGD("Protocol 1.8: Skipping garbage data at the end of a vanilla PluginMessage packet, %u bytes", - static_cast(a_ByteBuffer.GetReadableSpace() - 1) - ); - a_ByteBuffer.SkipRead(a_ByteBuffer.GetReadableSpace() - 1); - } - - return; - } - - // Read the plugin message and relay to clienthandle: - AString Data; - VERIFY(a_ByteBuffer.ReadString(Data, a_ByteBuffer.GetReadableSpace() - 1)); // Always succeeds - m_Client->HandlePluginMessage(Channel, Data); -} - - - - - -void cProtocol_1_9_0::HandlePacketResourcePackStatus(cByteBuffer & a_ByteBuffer) -{ - HANDLE_READ(a_ByteBuffer, ReadVarUTF8String, AString, Hash); - HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, Status); -} - - - - - -void cProtocol_1_9_0::HandlePacketSlotSelect(cByteBuffer & a_ByteBuffer) -{ - HANDLE_READ(a_ByteBuffer, ReadBEInt16, Int16, SlotNum); - m_Client->HandleSlotSelected(SlotNum); -} - - - - - -void cProtocol_1_9_0::HandlePacketSpectate(cByteBuffer & a_ByteBuffer) -{ - cUUID playerUUID; - if (!a_ByteBuffer.ReadUUID(playerUUID)) - { - return; - } - - m_Client->HandleSpectate(playerUUID); -} - - - - - void cProtocol_1_9_0::HandlePacketSteerVehicle(cByteBuffer & a_ByteBuffer) { HANDLE_READ(a_ByteBuffer, ReadBEFloat, float, Sideways); @@ -2978,18 +1112,6 @@ void cProtocol_1_9_0::HandlePacketUseItem(cByteBuffer & a_ByteBuffer) -void cProtocol_1_9_0::HandlePacketEnchantItem(cByteBuffer & a_ByteBuffer) -{ - HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, WindowID); - HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, Enchantment); - - m_Client->HandleEnchantItem(WindowID, Enchantment); -} - - - - - void cProtocol_1_9_0::HandlePacketVehicleMove(cByteBuffer & a_ByteBuffer) { // This handles updating the vehicles location server side @@ -3071,140 +1193,6 @@ void cProtocol_1_9_0::HandlePacketWindowClick(cByteBuffer & a_ByteBuffer) -void cProtocol_1_9_0::HandlePacketWindowClose(cByteBuffer & a_ByteBuffer) -{ - HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, WindowID); - m_Client->HandleWindowClose(WindowID); -} - - - - - -void cProtocol_1_9_0::HandleVanillaPluginMessage(cByteBuffer & a_ByteBuffer, const AString & a_Channel) -{ - if (a_Channel == "MC|AdvCdm") - { - HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, Mode); - switch (Mode) - { - case 0x00: - { - HANDLE_READ(a_ByteBuffer, ReadBEInt32, Int32, BlockX); - HANDLE_READ(a_ByteBuffer, ReadBEInt32, Int32, BlockY); - HANDLE_READ(a_ByteBuffer, ReadBEInt32, Int32, BlockZ); - HANDLE_READ(a_ByteBuffer, ReadVarUTF8String, AString, Command); - m_Client->HandleCommandBlockBlockChange(BlockX, BlockY, BlockZ, Command); - break; - } - - default: - { - m_Client->SendChat(Printf("Failure setting command block command; unhandled mode %u (0x%02x)", Mode, Mode), mtFailure); - LOG("Unhandled MC|AdvCdm packet mode."); - return; - } - } // switch (Mode) - return; - } - else if (a_Channel == "MC|Brand") - { - HANDLE_READ(a_ByteBuffer, ReadVarUTF8String, AString, Brand); - m_Client->SetClientBrand(Brand); - // Send back our brand, including the length: - SendPluginMessage("MC|Brand", "\x08""Cuberite"); - return; - } - else if (a_Channel == "MC|Beacon") - { - HANDLE_READ(a_ByteBuffer, ReadBEInt32, Int32, Effect1); - HANDLE_READ(a_ByteBuffer, ReadBEInt32, Int32, Effect2); - m_Client->HandleBeaconSelection(Effect1, Effect2); - return; - } - else if (a_Channel == "MC|ItemName") - { - HANDLE_READ(a_ByteBuffer, ReadVarUTF8String, AString, ItemName); - m_Client->HandleAnvilItemName(ItemName); - return; - } - else if (a_Channel == "MC|TrSel") - { - HANDLE_READ(a_ByteBuffer, ReadBEInt32, Int32, SlotNum); - m_Client->HandleNPCTrade(SlotNum); - return; - } - LOG("Unhandled vanilla plugin channel: \"%s\".", a_Channel.c_str()); - - // Read the payload and send it through to the clienthandle: - AString Message; - VERIFY(a_ByteBuffer.ReadString(Message, a_ByteBuffer.GetReadableSpace() - 1)); - m_Client->HandlePluginMessage(a_Channel, Message); -} - - - - - -void cProtocol_1_9_0::SendData(const char * a_Data, size_t a_Size) -{ - if (m_IsEncrypted) - { - Byte Encrypted[8192]; // Larger buffer, we may be sending lots of data (chunks) - while (a_Size > 0) - { - size_t NumBytes = (a_Size > sizeof(Encrypted)) ? sizeof(Encrypted) : a_Size; - m_Encryptor.ProcessData(Encrypted, reinterpret_cast(a_Data), NumBytes); - m_Client->SendData(reinterpret_cast(Encrypted), NumBytes); - a_Size -= NumBytes; - a_Data += NumBytes; - } - } - else - { - m_Client->SendData(a_Data, a_Size); - } -} - - - - - -bool cProtocol_1_9_0::ReadItem(cByteBuffer & a_ByteBuffer, cItem & a_Item, size_t a_KeepRemainingBytes) -{ - HANDLE_PACKET_READ(a_ByteBuffer, ReadBEInt16, Int16, ItemType); - if (ItemType == -1) - { - // The item is empty, no more data follows - a_Item.Empty(); - return true; - } - a_Item.m_ItemType = ItemType; - - HANDLE_PACKET_READ(a_ByteBuffer, ReadBEInt8, Int8, ItemCount); - HANDLE_PACKET_READ(a_ByteBuffer, ReadBEInt16, Int16, ItemDamage); - a_Item.m_ItemCount = ItemCount; - a_Item.m_ItemDamage = ItemDamage; - if (ItemCount <= 0) - { - a_Item.Empty(); - } - - AString Metadata; - if (!a_ByteBuffer.ReadString(Metadata, a_ByteBuffer.GetReadableSpace() - a_KeepRemainingBytes - 1) || (Metadata.size() == 0) || (Metadata[0] == 0)) - { - // No metadata - return true; - } - - ParseItemMetadata(a_Item, Metadata); - return true; -} - - - - - void cProtocol_1_9_0::ParseItemMetadata(cItem & a_Item, const AString & a_Metadata) { // Parse into NBT: @@ -3409,28 +1397,6 @@ void cProtocol_1_9_0::ParseItemMetadata(cItem & a_Item, const AString & a_Metada -void cProtocol_1_9_0::StartEncryption(const Byte * a_Key) -{ - m_Encryptor.Init(a_Key, a_Key); - m_Decryptor.Init(a_Key, a_Key); - m_IsEncrypted = true; - - // Prepare the m_AuthServerID: - cSha1Checksum Checksum; - cServer * Server = cRoot::Get()->GetServer(); - const AString & ServerID = Server->GetServerID(); - Checksum.Update(reinterpret_cast(ServerID.c_str()), ServerID.length()); - Checksum.Update(a_Key, 16); - Checksum.Update(reinterpret_cast(Server->GetPublicKeyDER().data()), Server->GetPublicKeyDER().size()); - Byte Digest[20]; - Checksum.Finalize(Digest); - cSha1Checksum::DigestToJava(Digest, m_AuthServerID); -} - - - - - eBlockFace cProtocol_1_9_0::FaceIntToBlockFace(Int32 a_BlockFace) { // Normalize the blockface values returned from the protocol @@ -3470,78 +1436,6 @@ eHand cProtocol_1_9_0::HandIntToEnum(Int32 a_Hand) -void cProtocol_1_9_0::SendPacket(cPacketizer & a_Pkt) -{ - UInt32 PacketLen = static_cast(m_OutPacketBuffer.GetUsedSpace()); - AString PacketData, CompressedPacket; - m_OutPacketBuffer.ReadAll(PacketData); - m_OutPacketBuffer.CommitRead(); - - if ((m_State == 3) && (PacketLen >= 256)) - { - // Compress the packet payload: - if (!cProtocol_1_9_0::CompressPacket(PacketData, CompressedPacket)) - { - return; - } - } - else if (m_State == 3) - { - // The packet is not compressed, indicate this in the packet header: - m_OutPacketLenBuffer.WriteVarInt32(PacketLen + 1); - m_OutPacketLenBuffer.WriteVarInt32(0); - AString LengthData; - m_OutPacketLenBuffer.ReadAll(LengthData); - SendData(LengthData.data(), LengthData.size()); - } - else - { - // Compression doesn't apply to this state, send raw data: - m_OutPacketLenBuffer.WriteVarInt32(PacketLen); - AString LengthData; - m_OutPacketLenBuffer.ReadAll(LengthData); - SendData(LengthData.data(), LengthData.size()); - } - - // Send the packet's payload, either direct or compressed: - if (CompressedPacket.empty()) - { - m_OutPacketLenBuffer.CommitRead(); - SendData(PacketData.data(), PacketData.size()); - } - else - { - SendData(CompressedPacket.data(), CompressedPacket.size()); - } - - // Log the comm into logfile: - if (g_ShouldLogCommOut && m_CommLogFile.IsOpen()) - { - AString Hex; - ASSERT(PacketData.size() > 0); - CreateHexDump(Hex, PacketData.data(), PacketData.size(), 16); - m_CommLogFile.Printf("Outgoing packet: type %s (translated to 0x%02x), length %u (0x%04x), state %d. Payload (incl. type):\n%s\n", - cPacketizer::PacketTypeToStr(a_Pkt.GetPacketType()), GetPacketID(a_Pkt.GetPacketType()), - PacketLen, PacketLen, m_State, Hex - ); - /* - // Useful for debugging a new protocol: - LOGD("Outgoing packet: type %s (translated to 0x%02x), length %u (0x%04x), state %d. Payload (incl. type):\n%s\n", - cPacketizer::PacketTypeToStr(a_Pkt.GetPacketType()), GetPacketID(a_Pkt.GetPacketType()), - PacketLen, PacketLen, m_State, Hex - ); - //*/ - } - /* - // Useful for debugging a new protocol: - std::this_thread::sleep_for(std::chrono::milliseconds(100)); - */ -} - - - - - void cProtocol_1_9_0::WriteItem(cPacketizer & a_Pkt, const cItem & a_Item) { short ItemType = a_Item.m_ItemType; diff --git a/src/Protocol/Protocol_1_9.h b/src/Protocol/Protocol_1_9.h index 2fb59887c..d5b5d1f5a 100644 --- a/src/Protocol/Protocol_1_9.h +++ b/src/Protocol/Protocol_1_9.h @@ -20,6 +20,7 @@ Declares the 1.9 protocol classes: #pragma once #include "Protocol.h" +#include "Protocol_1_8.h" #include "../ByteBuffer.h" #include "../World.h" @@ -31,219 +32,80 @@ Declares the 1.9 protocol classes: class cProtocol_1_9_0: - public cProtocol + public cProtocol_1_8_0 { - using Super = cProtocol; + using Super = cProtocol_1_8_0; public: cProtocol_1_9_0(cClientHandle * a_Client, const AString & a_ServerAddress, UInt16 a_ServerPort, UInt32 a_State); - /** Called when client sends some data: */ - virtual void DataReceived(const char * a_Data, size_t a_Size) override; - /** Sending stuff to clients (alphabetically sorted): */ virtual void SendAttachEntity (const cEntity & a_Entity, const cEntity & a_Vehicle) override; - virtual void SendBlockAction (int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType) override; - virtual void SendBlockBreakAnim (UInt32 a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage) override; - virtual void SendBlockChange (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) override; - virtual void SendBlockChanges (int a_ChunkX, int a_ChunkZ, const sSetBlockVector & a_Changes) override; - virtual void SendCameraSetTo (const cEntity & a_Entity) override; - virtual void SendChat (const AString & a_Message, eChatType a_Type) override; - 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 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 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 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; virtual void SendExperienceOrb (const cExpOrb & a_ExpOrb) 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; - virtual void SendGameMode (eGameMode a_GameMode) override; - virtual void SendHealth (void) override; - virtual void SendHeldItemChange (int a_ItemIndex) override; - virtual void SendHideTitle (void) override; - virtual void SendInventorySlot (char a_WindowID, short a_SlotNum, const cItem & a_Item) override; virtual void SendKeepAlive (UInt32 a_PingID) override; virtual void SendLeashEntity (const cEntity & a_Entity, const cEntity & a_EntityLeashedTo) override; - virtual void SendLogin (const cPlayer & a_Player, const cWorld & a_World) override; - virtual void SendLoginSuccess (void) override; virtual void SendMapData (const cMap & a_Map, int a_DataStartX, int a_DataStartY) override; virtual void SendPaintingSpawn (const cPainting & a_Painting) override; virtual void SendPickupSpawn (const cPickup & a_Pickup) 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; - virtual void SendPlayerListRemovePlayer (const cPlayer & a_Player) override; - virtual void SendPlayerListUpdateGameMode (const cPlayer & a_Player) override; - virtual void SendPlayerListUpdatePing (const cPlayer & a_Player) override; - virtual void SendPlayerListUpdateDisplayName(const cPlayer & a_Player, const AString & a_CustomName) override; virtual void SendPlayerMaxSpeed (void) override; virtual void SendPlayerMoveLook (void) override; - virtual void SendPlayerPosition (void) override; virtual void SendPlayerSpawn (const cPlayer & a_Player) override; - virtual void SendPluginMessage (const AString & a_Channel, const AString & a_Message) override; - virtual void SendRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID) override; - virtual void SendResetTitle (void) override; - virtual void SendResourcePack (const AString & a_ResourcePackUrl) override; - virtual void SendRespawn (eDimension a_Dimension) 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 SendScoreboardObjective (const AString & a_Name, const AString & a_DisplayName, Byte a_Mode) override; - virtual void SendScoreUpdate (const AString & a_Objective, const AString & a_Player, cObjective::Score a_Score, Byte a_Mode) override; - virtual void SendDisplayObjective (const AString & a_Objective, cScoreboard::eDisplaySlot a_Display) override; - virtual void SendSetSubTitle (const cCompositeChat & a_SubTitle) override; - virtual void SendSetRawSubTitle (const AString & a_SubTitle) override; - virtual void SendSetTitle (const cCompositeChat & a_Title) override; - virtual void SendSetRawTitle (const AString & a_Title) override; - virtual void SendSoundParticleEffect (const EffectID a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data) override; virtual void SendSpawnFallingBlock (const cFallingBlock & a_FallingBlock) override; virtual void SendSpawnMob (const cMonster & a_Mob) override; virtual void SendSpawnObject (const cEntity & a_Entity, char a_ObjectType, int a_ObjectData) override; virtual void SendSpawnVehicle (const cEntity & a_Vehicle, char a_VehicleType, char a_VehicleSubType) 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; virtual void SendUnleashEntity (const cEntity & a_Entity) override; virtual void SendUnloadChunk (int a_ChunkX, int a_ChunkZ) override; - virtual void SendUpdateBlockEntity (cBlockEntity & a_BlockEntity) override; - virtual void SendUpdateSign (int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4) override; - virtual void SendUseBed (const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ) override; - virtual void SendWeather (eWeather a_Weather) override; - virtual void SendWholeInventory (const cWindow & a_Window) override; - virtual void SendWindowClose (const cWindow & a_Window) override; - virtual void SendWindowOpen (const cWindow & a_Window) override; - virtual void SendWindowProperty (const cWindow & a_Window, short a_Property, short a_Value) override; virtual AString GetAuthServerID(void) override { return m_AuthServerID; } - /** Compress the packet. a_Packet must be without packet length. - a_Compressed will be set to the compressed packet includes packet length and data length. - If compression fails, the function returns false. */ - static bool CompressPacket(const AString & a_Packet, AString & a_Compressed); - - /** The 1.8 protocol use a particle id instead of a string. This function converts the name to the id. If the name is incorrect, it returns 0. */ - static int GetParticleID(const AString & a_ParticleName); - - /** Minecraft 1.8 use other locations to spawn the item frame. This function converts the 1.7 positions to 1.8 positions. */ - static void FixItemFramePositions(int a_ObjectData, double & a_PosX, double & a_PosZ, double & a_Yaw); - protected: - AString m_ServerAddress; - - UInt16 m_ServerPort; - - AString m_AuthServerID; - - /** State of the protocol. 1 = status, 2 = login, 3 = game */ - UInt32 m_State; - /** The current teleport ID, and whether it has been confirmed by the client */ bool m_IsTeleportIdConfirmed; UInt32 m_OutstandingTeleportId; - /** Buffer for the received data */ - cByteBuffer m_ReceivedData; - - bool m_IsEncrypted; - - cAesCfb128Decryptor m_Decryptor; - cAesCfb128Encryptor m_Encryptor; - - /** The logfile where the comm is logged, when g_ShouldLogComm is true */ - cFile m_CommLogFile; - - /** Adds the received (unencrypted) data to m_ReceivedData, parses complete packets */ - void AddReceivedData(const char * a_Data, size_t a_Size); - /** Get the packet ID for a given packet */ virtual UInt32 GetPacketID(ePacketType a_Packet) override; - /** Converts eMonsterType to protocol-specific mob IDs */ - virtual UInt32 GetProtocolMobType(eMonsterType a_MobType) override; - /** Reads and handles the packet. The packet length and type have already been read. Returns true if the packet was understood, false if it was an unknown packet. */ - virtual bool HandlePacket(cByteBuffer & a_ByteBuffer, UInt32 a_PacketType); + virtual bool HandlePacket(cByteBuffer & a_ByteBuffer, UInt32 a_PacketType) override; // Packet handlers while in the Status state (m_State == 1): - virtual void HandlePacketStatusPing(cByteBuffer & a_ByteBuffer); - virtual void HandlePacketStatusRequest(cByteBuffer & a_ByteBuffer); - - // Packet handlers while in the Login state (m_State == 2): - virtual void HandlePacketLoginEncryptionResponse(cByteBuffer & a_ByteBuffer); - virtual void HandlePacketLoginStart(cByteBuffer & a_ByteBuffer); + virtual void HandlePacketStatusRequest(cByteBuffer & a_ByteBuffer) override; // Packet handlers while in the Game state (m_State == 3): - virtual void HandlePacketAnimation (cByteBuffer & a_ByteBuffer); - virtual void HandlePacketBlockDig (cByteBuffer & a_ByteBuffer); - virtual void HandlePacketBlockPlace (cByteBuffer & a_ByteBuffer); + virtual void HandlePacketAnimation (cByteBuffer & a_ByteBuffer) override; + virtual void HandlePacketBlockDig (cByteBuffer & a_ByteBuffer) override; + virtual void HandlePacketBlockPlace (cByteBuffer & a_ByteBuffer) override; virtual void HandlePacketBoatSteer (cByteBuffer & a_ByteBuffer); - virtual void HandlePacketChatMessage (cByteBuffer & a_ByteBuffer); - virtual void HandlePacketClientSettings (cByteBuffer & a_ByteBuffer); - virtual void HandlePacketClientStatus (cByteBuffer & a_ByteBuffer); + virtual void HandlePacketClientSettings (cByteBuffer & a_ByteBuffer) override; virtual void HandleConfirmTeleport (cByteBuffer & a_ByteBuffer); - virtual void HandlePacketCreativeInventoryAction(cByteBuffer & a_ByteBuffer); - virtual void HandlePacketEntityAction (cByteBuffer & a_ByteBuffer); - virtual void HandlePacketKeepAlive (cByteBuffer & a_ByteBuffer); - virtual void HandlePacketPlayer (cByteBuffer & a_ByteBuffer); - virtual void HandlePacketPlayerAbilities (cByteBuffer & a_ByteBuffer); - virtual void HandlePacketPlayerLook (cByteBuffer & a_ByteBuffer); - virtual void HandlePacketPlayerPos (cByteBuffer & a_ByteBuffer); - virtual void HandlePacketPlayerPosLook (cByteBuffer & a_ByteBuffer); - virtual void HandlePacketPluginMessage (cByteBuffer & a_ByteBuffer); - virtual void HandlePacketResourcePackStatus (cByteBuffer & a_ByteBuffer); - virtual void HandlePacketSlotSelect (cByteBuffer & a_ByteBuffer); - virtual void HandlePacketSteerVehicle (cByteBuffer & a_ByteBuffer); - virtual void HandlePacketSpectate (cByteBuffer & a_ByteBuffer); - virtual void HandlePacketTabComplete (cByteBuffer & a_ByteBuffer); - virtual void HandlePacketUpdateSign (cByteBuffer & a_ByteBuffer); - virtual void HandlePacketUseEntity (cByteBuffer & a_ByteBuffer); + virtual void HandlePacketEntityAction (cByteBuffer & a_ByteBuffer) override; + virtual void HandlePacketPlayerPos (cByteBuffer & a_ByteBuffer) override; + virtual void HandlePacketPlayerPosLook (cByteBuffer & a_ByteBuffer) override; + virtual void HandlePacketSteerVehicle (cByteBuffer & a_ByteBuffer) override; + virtual void HandlePacketTabComplete (cByteBuffer & a_ByteBuffer) override; + virtual void HandlePacketUpdateSign (cByteBuffer & a_ByteBuffer) override; + virtual void HandlePacketUseEntity (cByteBuffer & a_ByteBuffer) override; virtual void HandlePacketUseItem (cByteBuffer & a_ByteBuffer); - virtual void HandlePacketEnchantItem (cByteBuffer & a_ByteBuffer); virtual void HandlePacketVehicleMove (cByteBuffer & a_ByteBuffer); - virtual void HandlePacketWindowClick (cByteBuffer & a_ByteBuffer); - virtual void HandlePacketWindowClose (cByteBuffer & a_ByteBuffer); - - /** Parses Vanilla plugin messages into specific ClientHandle calls. - The message payload is still in the bytebuffer, the handler reads it specifically for each handled channel */ - virtual void HandleVanillaPluginMessage(cByteBuffer & a_ByteBuffer, const AString & a_Channel); - - - /** Sends the data to the client, encrypting them if needed. */ - virtual void SendData(const char * a_Data, size_t a_Size) override; - - /** Sends the packet to the client. Called by the cPacketizer's destructor. */ - virtual void SendPacket(cPacketizer & a_Packet) override; - - void SendCompass(const cWorld & a_World); - - /** Reads an item out of the received data, sets a_Item to the values read. - Returns false if not enough received data. - a_KeepRemainingBytes tells the function to keep that many bytes at the end of the buffer. */ - virtual bool ReadItem(cByteBuffer & a_ByteBuffer, cItem & a_Item, size_t a_KeepRemainingBytes = 0); + virtual void HandlePacketWindowClick (cByteBuffer & a_ByteBuffer) override; /** Parses item metadata as read by ReadItem(), into the item enchantments. */ - void ParseItemMetadata(cItem & a_Item, const AString & a_Metadata); - - void StartEncryption(const Byte * a_Key); + virtual void ParseItemMetadata(cItem & a_Item, const AString & a_Metadata) override; /** Converts the BlockFace received by the protocol into eBlockFace constants. If the received value doesn't match any of our eBlockFace constants, BLOCK_FACE_NONE is returned. */ @@ -254,19 +116,19 @@ protected: eHand HandIntToEnum(Int32 a_Hand); /** Writes the item data into a packet. */ - virtual void WriteItem(cPacketizer & a_Pkt, const cItem & a_Item); + virtual void WriteItem(cPacketizer & a_Pkt, const cItem & a_Item) override; /** Writes the metadata for the specified entity, not including the terminating 0xff. */ - virtual void WriteEntityMetadata(cPacketizer & a_Pkt, const cEntity & a_Entity); + virtual void WriteEntityMetadata(cPacketizer & a_Pkt, const cEntity & a_Entity) override; /** Writes the mob-specific metadata for the specified mob */ - virtual void WriteMobMetadata(cPacketizer & a_Pkt, const cMonster & a_Mob); + virtual void WriteMobMetadata(cPacketizer & a_Pkt, const cMonster & a_Mob) override; /** Writes the entity properties for the specified entity, including the Count field. */ - void WriteEntityProperties(cPacketizer & a_Pkt, const cEntity & a_Entity); + virtual void WriteEntityProperties(cPacketizer & a_Pkt, const cEntity & a_Entity) override; /** Writes the block entity data for the specified block entity into the packet. */ - virtual void WriteBlockEntity(cPacketizer & a_Pkt, const cBlockEntity & a_BlockEntity); + virtual void WriteBlockEntity(cPacketizer & a_Pkt, const cBlockEntity & a_BlockEntity) override; /** Types used within metadata */ enum eMetadataType -- cgit v1.2.3