diff options
Diffstat (limited to 'src/Protocol')
-rw-r--r-- | src/Protocol/ChunkDataSerializer.cpp | 4 | ||||
-rw-r--r-- | src/Protocol/Protocol.h | 43 | ||||
-rw-r--r-- | src/Protocol/Protocol125.cpp | 220 | ||||
-rw-r--r-- | src/Protocol/Protocol125.h | 30 | ||||
-rw-r--r-- | src/Protocol/Protocol132.cpp | 222 | ||||
-rw-r--r-- | src/Protocol/Protocol132.h | 20 | ||||
-rw-r--r-- | src/Protocol/Protocol14x.cpp | 16 | ||||
-rw-r--r-- | src/Protocol/Protocol15x.cpp | 54 | ||||
-rw-r--r-- | src/Protocol/Protocol15x.h | 3 | ||||
-rw-r--r-- | src/Protocol/Protocol16x.cpp | 36 | ||||
-rw-r--r-- | src/Protocol/Protocol16x.h | 1 | ||||
-rw-r--r-- | src/Protocol/Protocol17x.cpp | 678 | ||||
-rw-r--r-- | src/Protocol/Protocol17x.h | 72 | ||||
-rw-r--r-- | src/Protocol/ProtocolRecognizer.cpp | 92 | ||||
-rw-r--r-- | src/Protocol/ProtocolRecognizer.h | 14 |
15 files changed, 1139 insertions, 366 deletions
diff --git a/src/Protocol/ChunkDataSerializer.cpp b/src/Protocol/ChunkDataSerializer.cpp index 78318a5ee..ebe61631b 100644 --- a/src/Protocol/ChunkDataSerializer.cpp +++ b/src/Protocol/ChunkDataSerializer.cpp @@ -105,7 +105,7 @@ void cChunkDataSerializer::Serialize29(AString & a_Data) a_Data.append((const char *)&BitMap1, sizeof(short)); a_Data.append((const char *)&BitMap2, sizeof(short)); - Int32 CompressedSizeBE = htonl(CompressedSize); + UInt32 CompressedSizeBE = htonl((UInt32)CompressedSize); a_Data.append((const char *)&CompressedSizeBE, sizeof(CompressedSizeBE)); Int32 UnusedInt32 = 0; @@ -163,7 +163,7 @@ void cChunkDataSerializer::Serialize39(AString & a_Data) a_Data.append((const char *)&BitMap1, sizeof(short)); a_Data.append((const char *)&BitMap2, sizeof(short)); - Int32 CompressedSizeBE = htonl(CompressedSize); + UInt32 CompressedSizeBE = htonl((UInt32)CompressedSize); a_Data.append((const char *)&CompressedSizeBE, sizeof(CompressedSizeBE)); // Unlike 29, 39 doesn't have the "unused" int diff --git a/src/Protocol/Protocol.h b/src/Protocol/Protocol.h index 1bc5d528e..939170f0e 100644 --- a/src/Protocol/Protocol.h +++ b/src/Protocol/Protocol.h @@ -12,6 +12,8 @@ #include "../Defines.h" #include "../Endianness.h" +#include "../Scoreboard.h" +#include "../Map.h" @@ -23,10 +25,12 @@ class cWindow; class cInventory; class cPawn; class cPickup; +class cPainting; class cWorld; class cMonster; class cChunkDataSerializer; class cFallingBlock; +class cCompositeChat; @@ -48,7 +52,7 @@ public: virtual ~cProtocol() {} /// Called when client sends some data - virtual void DataReceived(const char * a_Data, int a_Size) = 0; + virtual void DataReceived(const char * a_Data, size_t a_Size) = 0; // Sending stuff to clients (alphabetically sorted): virtual void SendAttachEntity (const cEntity & a_Entity, const cEntity * a_Vehicle) = 0; @@ -57,6 +61,7 @@ public: virtual void SendBlockChange (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) = 0; virtual void SendBlockChanges (int a_ChunkX, int a_ChunkZ, const sSetBlockVector & a_Changes) = 0; virtual void SendChat (const AString & a_Message) = 0; + virtual void SendChat (const cCompositeChat & a_Message) = 0; virtual void SendChunkData (int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer) = 0; virtual void SendCollectPickup (const cPickup & a_Pickup, const cPlayer & a_Player) = 0; virtual void SendDestroyEntity (const cEntity & a_Entity) = 0; @@ -78,6 +83,10 @@ public: virtual void SendInventorySlot (char a_WindowID, short a_SlotNum, const cItem & a_Item) = 0; virtual void SendKeepAlive (int a_PingID) = 0; virtual void SendLogin (const cPlayer & a_Player, const cWorld & a_World) = 0; + virtual void SendMapColumn (int a_ID, int a_X, int a_Y, const Byte * a_Colors, unsigned int a_Length) = 0; + virtual void SendMapDecorators (int a_ID, const cMapDecoratorList & a_Decorators) = 0; + virtual void SendMapInfo (int a_ID, unsigned int a_Scale) = 0; + virtual void SendPaintingSpawn (const cPainting & a_Painting) = 0; virtual void SendPickupSpawn (const cPickup & a_Pickup) = 0; virtual void SendPlayerAbilities (void) = 0; virtual void SendEntityAnimation (const cEntity & a_Entity, char a_Animation) = 0; @@ -92,6 +101,9 @@ public: virtual void SendRespawn (void) = 0; virtual void SendExperience (void) = 0; virtual void SendExperienceOrb (const cExpOrb & a_ExpOrb) = 0; + virtual void SendScoreboardObjective (const AString & a_Name, const AString & a_DisplayName, Byte a_Mode) = 0; + virtual void SendScoreUpdate (const AString & a_Objective, const AString & a_Player, cObjective::Score a_Score, Byte a_Mode) = 0; + virtual void SendDisplayObjective (const AString & a_Objective, cScoreboard::eDisplaySlot a_Display) = 0; virtual void SendSoundEffect (const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch) = 0; // a_Src coords are Block * 8 virtual void SendSoundParticleEffect (int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data) = 0; virtual void SendSpawnFallingBlock (const cFallingBlock & a_FallingBlock) = 0; @@ -120,7 +132,7 @@ protected: cCriticalSection m_CSPacket; //< Each SendXYZ() function must acquire this CS in order to send the whole packet at once /// A generic data-sending routine, all outgoing packet data needs to be routed through this so that descendants may override it - virtual void SendData(const char * a_Data, int a_Size) = 0; + virtual void SendData(const char * a_Data, size_t a_Size) = 0; /// Called after writing each packet, enables descendants to flush their buffers virtual void Flush(void) {}; @@ -131,10 +143,15 @@ protected: SendData((const char *)&a_Value, 1); } + void WriteChar(char a_Value) + { + SendData(&a_Value, 1); + } + void WriteShort(short a_Value) { - a_Value = htons(a_Value); - SendData((const char *)&a_Value, 2); + u_short Value = htons((u_short)a_Value); + SendData((const char *)&Value, 2); } /* @@ -147,8 +164,8 @@ protected: void WriteInt(int a_Value) { - a_Value = htonl(a_Value); - SendData((const char *)&a_Value, 4); + u_long Value = htonl((u_long)a_Value); + SendData((const char *)&Value, 4); } void WriteUInt(unsigned int a_Value) @@ -159,19 +176,19 @@ protected: void WriteInt64 (Int64 a_Value) { - a_Value = HostToNetwork8(&a_Value); - SendData((const char *)&a_Value, 8); + UInt64 Value = HostToNetwork8(&a_Value); + SendData((const char *)&Value, 8); } void WriteFloat (float a_Value) { - unsigned int val = HostToNetwork4(&a_Value); + UInt32 val = HostToNetwork4(&a_Value); SendData((const char *)&val, 4); } void WriteDouble(double a_Value) { - unsigned long long val = HostToNetwork8(&a_Value); + UInt64 val = HostToNetwork8(&a_Value); SendData((const char *)&val, 8); } @@ -179,7 +196,7 @@ protected: { AString UTF16; UTF8ToRawBEUTF16(a_Value.c_str(), a_Value.length(), UTF16); - WriteShort((unsigned short)(UTF16.size() / 2)); + WriteShort((short)(UTF16.size() / 2)); SendData(UTF16.data(), UTF16.size()); } @@ -199,7 +216,7 @@ protected: { // A 32-bit integer can be encoded by at most 5 bytes: unsigned char b[5]; - int idx = 0; + size_t idx = 0; do { b[idx] = (a_Value & 0x7f) | ((a_Value > 0x7f) ? 0x80 : 0x00); @@ -212,7 +229,7 @@ protected: void WriteVarUTF8String(const AString & a_String) { - WriteVarInt(a_String.size()); + WriteVarInt((UInt32)a_String.size()); SendData(a_String.data(), a_String.size()); } } ; diff --git a/src/Protocol/Protocol125.cpp b/src/Protocol/Protocol125.cpp index 2df2a695b..867cf3ef3 100644 --- a/src/Protocol/Protocol125.cpp +++ b/src/Protocol/Protocol125.cpp @@ -32,6 +32,8 @@ Documentation: #include "../Mobs/IncludeAllMonsters.h" +#include "../CompositeChat.h" + @@ -96,6 +98,7 @@ enum PACKET_CREATIVE_INVENTORY_ACTION = 0x6B, PACKET_ENCHANT_ITEM = 0x6C, PACKET_UPDATE_SIGN = 0x82, + PACKET_ITEM_DATA = 0x83, PACKET_PLAYER_LIST_ITEM = 0xC9, PACKET_PLAYER_ABILITIES = 0xca, PACKET_PLUGIN_MESSAGE = 0xfa, @@ -159,8 +162,8 @@ void cProtocol125::SendBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, cha WriteInt (a_BlockX); WriteShort((short)a_BlockY); WriteInt (a_BlockZ); - WriteByte (a_Byte1); - WriteByte (a_Byte2); + WriteChar (a_Byte1); + WriteChar (a_Byte2); Flush(); } @@ -207,12 +210,12 @@ void cProtocol125::SendBlockChanges(int a_ChunkX, int a_ChunkZ, const sSetBlockV WriteByte (PACKET_MULTI_BLOCK); WriteInt (a_ChunkX); WriteInt (a_ChunkZ); - WriteShort((unsigned short)a_Changes.size()); - WriteUInt (sizeof(int) * a_Changes.size()); + WriteShort((short)a_Changes.size()); + WriteUInt ((UInt32)(4 * a_Changes.size())); for (sSetBlockVector::const_iterator itr = a_Changes.begin(), end = a_Changes.end(); itr != end; ++itr) { - unsigned int Coords = itr->y | (itr->z << 8) | (itr->x << 12); - unsigned int Blocks = itr->BlockMeta | (itr->BlockType << 4); + UInt32 Coords = ((UInt32)itr->y) | ((UInt32)(itr->z << 8)) | ((UInt32)(itr->x << 12)); + UInt32 Blocks = ((UInt32)itr->BlockMeta) | ((UInt32)(itr->BlockType << 4)); WriteUInt(Coords << 16 | Blocks); } Flush(); @@ -234,6 +237,21 @@ void cProtocol125::SendChat(const AString & a_Message) +void cProtocol125::SendChat(const cCompositeChat & a_Message) +{ + // This version doesn't support composite messages, just extract each part's text and use it: + + // Send the message: + cCSLock Lock(m_CSPacket); + WriteByte (PACKET_CHAT); + WriteString(a_Message.ExtractText()); + Flush(); +} + + + + + void cProtocol125::SendChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer) { cCSLock Lock(m_CSPacket); @@ -308,8 +326,8 @@ void cProtocol125::SendEntityEffect(const cEntity & a_Entity, int a_EffectID, in cCSLock Lock(m_CSPacket); WriteByte (PACKET_ENTITY_EFFECT); WriteInt (a_Entity.GetUniqueID()); - WriteByte (a_EffectID); - WriteByte (a_Amplifier); + WriteByte ((Byte)a_EffectID); + WriteByte ((Byte)a_Amplifier); WriteShort(a_Duration); Flush(); } @@ -340,7 +358,7 @@ void cProtocol125::SendEntityHeadLook(const cEntity & a_Entity) cCSLock Lock(m_CSPacket); WriteByte(PACKET_ENT_HEAD_LOOK); WriteInt (a_Entity.GetUniqueID()); - WriteByte((char)((a_Entity.GetHeadYaw() / 360.f) * 256)); + WriteChar((char)((a_Entity.GetHeadYaw() / 360.f) * 256)); Flush(); } @@ -355,8 +373,8 @@ void cProtocol125::SendEntityLook(const cEntity & a_Entity) cCSLock Lock(m_CSPacket); WriteByte(PACKET_ENT_LOOK); WriteInt (a_Entity.GetUniqueID()); - WriteByte((char)((a_Entity.GetYaw() / 360.f) * 256)); - WriteByte((char)((a_Entity.GetPitch() / 360.f) * 256)); + WriteChar((char)((a_Entity.GetYaw() / 360.f) * 256)); + WriteChar((char)((a_Entity.GetPitch() / 360.f) * 256)); Flush(); } @@ -404,9 +422,9 @@ void cProtocol125::SendEntityRelMove(const cEntity & a_Entity, char a_RelX, char cCSLock Lock(m_CSPacket); WriteByte(PACKET_ENT_REL_MOVE); WriteInt (a_Entity.GetUniqueID()); - WriteByte(a_RelX); - WriteByte(a_RelY); - WriteByte(a_RelZ); + WriteChar(a_RelX); + WriteChar(a_RelY); + WriteChar(a_RelZ); Flush(); } @@ -421,11 +439,11 @@ void cProtocol125::SendEntityRelMoveLook(const cEntity & a_Entity, char a_RelX, cCSLock Lock(m_CSPacket); WriteByte(PACKET_ENT_REL_MOVE_LOOK); WriteInt (a_Entity.GetUniqueID()); - WriteByte(a_RelX); - WriteByte(a_RelY); - WriteByte(a_RelZ); - WriteByte((char)((a_Entity.GetYaw() / 360.f) * 256)); - WriteByte((char)((a_Entity.GetPitch() / 360.f) * 256)); + WriteChar(a_RelX); + WriteChar(a_RelY); + WriteChar(a_RelZ); + WriteChar((char)((a_Entity.GetYaw() / 360.f) * 256)); + WriteChar((char)((a_Entity.GetPitch() / 360.f) * 256)); Flush(); } @@ -438,7 +456,7 @@ void cProtocol125::SendEntityStatus(const cEntity & a_Entity, char a_Status) cCSLock Lock(m_CSPacket); WriteByte(PACKET_ENT_STATUS); WriteInt (a_Entity.GetUniqueID()); - WriteByte(a_Status); + WriteChar(a_Status); Flush(); } @@ -471,7 +489,7 @@ void cProtocol125::SendExplosion(double a_BlockX, double a_BlockY, double a_Bloc WriteDouble (a_BlockY); WriteDouble (a_BlockZ); WriteFloat (a_Radius); - WriteInt (a_BlocksAffected.size()); + WriteInt ((Int32)a_BlocksAffected.size()); int BlockX = (int)a_BlockX; int BlockY = (int)a_BlockY; int BlockZ = (int)a_BlockZ; @@ -496,7 +514,7 @@ void cProtocol125::SendGameMode(eGameMode a_GameMode) cCSLock Lock(m_CSPacket); WriteByte(PACKET_CHANGE_GAME_STATE); WriteByte(3); - WriteByte((char)a_GameMode); + WriteChar((char)a_GameMode); Flush(); } @@ -521,7 +539,7 @@ void cProtocol125::SendHealth(void) cCSLock Lock(m_CSPacket); WriteByte (PACKET_UPDATE_HEALTH); WriteShort((short)m_Client->GetPlayer()->GetHealth()); - WriteShort(m_Client->GetPlayer()->GetFoodLevel()); + WriteShort((short)m_Client->GetPlayer()->GetFoodLevel()); WriteFloat((float)m_Client->GetPlayer()->GetFoodSaturationLevel()); Flush(); } @@ -534,7 +552,7 @@ void cProtocol125::SendInventorySlot(char a_WindowID, short a_SlotNum, const cIt { cCSLock Lock(m_CSPacket); WriteByte (PACKET_INVENTORY_SLOT); - WriteByte (a_WindowID); + WriteChar (a_WindowID); WriteShort(a_SlotNum); WriteItem (a_Item); Flush(); @@ -577,13 +595,61 @@ void cProtocol125::SendLogin(const cPlayer & a_Player, const cWorld & a_World) +void cProtocol125::SendMapColumn(int a_ID, int a_X, int a_Y, const Byte * a_Colors, unsigned int a_Length) +{ + cCSLock Lock(m_CSPacket); + + WriteByte (PACKET_ITEM_DATA); + WriteShort(E_ITEM_MAP); + WriteShort((short)a_ID); + WriteShort((short)(3 + a_Length)); + + WriteByte(0); + WriteChar((char)a_X); + WriteChar((char)a_Y); + + SendData((const char *)a_Colors, a_Length); + + Flush(); +} + + + + + +void cProtocol125::SendMapDecorators(int a_ID, const cMapDecoratorList & a_Decorators) +{ + cCSLock Lock(m_CSPacket); + + WriteByte (PACKET_ITEM_DATA); + WriteShort(E_ITEM_MAP); + WriteShort((short)a_ID); + WriteShort((short)(1 + (3 * a_Decorators.size()))); + + WriteByte(1); + + for (cMapDecoratorList::const_iterator it = a_Decorators.begin(); it != a_Decorators.end(); ++it) + { + WriteByte((Byte)(it->GetType() << 4) | (it->GetRot() & 0xf)); + WriteByte((Byte)it->GetPixelX()); + WriteByte((Byte)it->GetPixelZ()); + } + + Flush(); +} + + + + + + void cProtocol125::SendPickupSpawn(const cPickup & a_Pickup) { cCSLock Lock(m_CSPacket); WriteByte (PACKET_PICKUP_SPAWN); WriteInt (a_Pickup.GetUniqueID()); WriteShort (a_Pickup.GetItem().m_ItemType); - WriteByte (a_Pickup.GetItem().m_ItemCount); + WriteChar (a_Pickup.GetItem().m_ItemCount); WriteShort (a_Pickup.GetItem().m_ItemDamage); WriteVectorI((Vector3i)(a_Pickup.GetPosition() * 32)); WriteByte ((char)(a_Pickup.GetSpeed().x * 8)); @@ -601,7 +667,7 @@ void cProtocol125::SendEntityAnimation(const cEntity & a_Entity, char a_Animatio cCSLock Lock(m_CSPacket); WriteByte(PACKET_ANIMATION); WriteInt (a_Entity.GetUniqueID()); - WriteByte(a_Animation); + WriteChar(a_Animation); Flush(); } @@ -695,8 +761,8 @@ void cProtocol125::SendPlayerSpawn(const cPlayer & a_Player) WriteInt ((int)(a_Player.GetPosX() * 32)); WriteInt ((int)(a_Player.GetPosY() * 32)); WriteInt ((int)(a_Player.GetPosZ() * 32)); - WriteByte ((char)((a_Player.GetYaw() / 360.f) * 256)); - WriteByte ((char)((a_Player.GetPitch() / 360.f) * 256)); + WriteChar ((char)((a_Player.GetYaw() / 360.f) * 256)); + WriteChar ((char)((a_Player.GetPitch() / 360.f) * 256)); WriteShort (HeldItem.IsEmpty() ? 0 : HeldItem.m_ItemType); Flush(); } @@ -722,9 +788,9 @@ void cProtocol125::SendPluginMessage(const AString & a_Channel, const AString & void cProtocol125::SendRemoveEntityEffect(const cEntity & a_Entity, int a_EffectID) { cCSLock Lock(m_CSPacket); - WriteByte (PACKET_REMOVE_ENTITY_EFFECT); - WriteInt (a_Entity.GetUniqueID()); - WriteByte (a_EffectID); + WriteByte(PACKET_REMOVE_ENTITY_EFFECT); + WriteInt (a_Entity.GetUniqueID()); + WriteChar((char)a_EffectID); Flush(); } @@ -738,7 +804,7 @@ void cProtocol125::SendRespawn(void) WriteByte (PACKET_RESPAWN); WriteInt ((int)(m_Client->GetPlayer()->GetWorld()->GetDimension())); WriteByte (2); // TODO: Difficulty; 2 = Normal - WriteByte ((char)m_Client->GetPlayer()->GetGameMode()); + WriteChar ((char)m_Client->GetPlayer()->GetGameMode()); WriteShort (256); // Current world height WriteString("default"); } @@ -769,7 +835,7 @@ void cProtocol125::SendExperienceOrb(const cExpOrb & a_ExpOrb) WriteInt((int) a_ExpOrb.GetPosX()); WriteInt((int) a_ExpOrb.GetPosY()); WriteInt((int) a_ExpOrb.GetPosZ()); - WriteShort(a_ExpOrb.GetReward()); + WriteShort((short)a_ExpOrb.GetReward()); Flush(); } @@ -810,7 +876,7 @@ void cProtocol125::SendSpawnMob(const cMonster & a_Mob) cCSLock Lock(m_CSPacket); WriteByte (PACKET_SPAWN_MOB); WriteInt (a_Mob.GetUniqueID()); - WriteByte (a_Mob.GetMobType()); + WriteByte ((Byte)a_Mob.GetMobType()); WriteVectorI((Vector3i)(a_Mob.GetPosition() * 32)); WriteByte (0); WriteByte (0); @@ -835,7 +901,7 @@ void cProtocol125::SendSpawnObject(const cEntity & a_Entity, char a_ObjectType, cCSLock Lock(m_CSPacket); WriteByte(PACKET_SPAWN_OBJECT); WriteInt (a_Entity.GetUniqueID()); - WriteByte(a_ObjectType); + WriteChar(a_ObjectType); WriteInt ((int)(a_Entity.GetPosX() * 32)); WriteInt ((int)(a_Entity.GetPosY() * 32)); WriteInt ((int)(a_Entity.GetPosZ() * 32)); @@ -860,7 +926,7 @@ void cProtocol125::SendSpawnVehicle(const cEntity & a_Vehicle, char a_VehicleTyp cCSLock Lock(m_CSPacket); WriteByte (PACKET_SPAWN_OBJECT); WriteInt (a_Vehicle.GetUniqueID()); - WriteByte (a_VehicleType); + WriteChar (a_VehicleType); WriteInt ((int)(a_Vehicle.GetPosX() * 32)); WriteInt ((int)(a_Vehicle.GetPosY() * 32)); WriteInt ((int)(a_Vehicle.GetPosZ() * 32)); @@ -898,8 +964,8 @@ void cProtocol125::SendTeleportEntity(const cEntity & a_Entity) WriteInt ((int)(floor(a_Entity.GetPosX() * 32))); WriteInt ((int)(floor(a_Entity.GetPosY() * 32))); WriteInt ((int)(floor(a_Entity.GetPosZ() * 32))); - WriteByte ((char)((a_Entity.GetYaw() / 360.f) * 256)); - WriteByte ((char)((a_Entity.GetPitch() / 360.f) * 256)); + WriteChar ((char)((a_Entity.GetYaw() / 360.f) * 256)); + WriteChar ((char)((a_Entity.GetPitch() / 360.f) * 256)); Flush(); } @@ -974,7 +1040,7 @@ void cProtocol125::SendUseBed(const cEntity & a_Entity, int a_BlockX, int a_Bloc WriteInt (a_Entity.GetUniqueID()); WriteByte(0); // Unknown byte only 0 has been observed WriteInt (a_BlockX); - WriteByte(a_BlockY); + WriteByte((Byte)a_BlockY); WriteInt (a_BlockZ); Flush(); } @@ -1018,7 +1084,7 @@ void cProtocol125::SendWholeInventory(const cWindow & a_Window) cCSLock Lock(m_CSPacket); cItems Slots; a_Window.GetSlots(*(m_Client->GetPlayer()), Slots); - SendWindowSlots(a_Window.GetWindowID(), Slots.size(), &(Slots[0])); + SendWindowSlots(a_Window.GetWindowID(), (int)Slots.size(), &(Slots[0])); } @@ -1035,7 +1101,7 @@ void cProtocol125::SendWindowClose(const cWindow & a_Window) cCSLock Lock(m_CSPacket); WriteByte(PACKET_WINDOW_CLOSE); - WriteByte(a_Window.GetWindowID()); + WriteChar(a_Window.GetWindowID()); Flush(); } @@ -1052,10 +1118,10 @@ void cProtocol125::SendWindowOpen(const cWindow & a_Window) } cCSLock Lock(m_CSPacket); WriteByte (PACKET_WINDOW_OPEN); - WriteByte (a_Window.GetWindowID()); - WriteByte (a_Window.GetWindowType()); + WriteChar (a_Window.GetWindowID()); + WriteByte ((Byte)a_Window.GetWindowType()); WriteString(a_Window.GetWindowTitle()); - WriteByte (a_Window.GetNumNonInventorySlots()); + WriteByte ((Byte)a_Window.GetNumNonInventorySlots()); Flush(); } @@ -1067,7 +1133,7 @@ void cProtocol125::SendWindowProperty(const cWindow & a_Window, short a_Property { cCSLock Lock(m_CSPacket); WriteByte (PACKET_WINDOW_PROPERTY); - WriteByte (a_Window.GetWindowID()); + WriteChar (a_Window.GetWindowID()); WriteShort(a_Property); WriteShort(a_Value); Flush(); @@ -1088,7 +1154,7 @@ AString cProtocol125::GetAuthServerID(void) -void cProtocol125::SendData(const char * a_Data, int a_Size) +void cProtocol125::SendData(const char * a_Data, size_t a_Size) { m_Client->SendData(a_Data, a_Size); } @@ -1097,7 +1163,7 @@ void cProtocol125::SendData(const char * a_Data, int a_Size) -void cProtocol125::DataReceived(const char * a_Data, int a_Size) +void cProtocol125::DataReceived(const char * a_Data, size_t a_Size) { if (!m_ReceivedData.Write(a_Data, a_Size)) { @@ -1181,19 +1247,6 @@ int cProtocol125::ParsePacket(unsigned char a_PacketType) -#define HANDLE_PACKET_PARSE(Packet) \ - { \ - int res = Packet.Parse(m_ReceivedData); \ - if (res < 0) \ - { \ - return res; \ - } \ - } - - - - - int cProtocol125::ParseArmAnim(void) { HANDLE_PACKET_READ(ReadBEInt, int, EntityID); @@ -1213,7 +1266,7 @@ int cProtocol125::ParseBlockDig(void) HANDLE_PACKET_READ(ReadByte, Byte, PosY); HANDLE_PACKET_READ(ReadBEInt, int, PosZ); HANDLE_PACKET_READ(ReadChar, char, BlockFace); - m_Client->HandleLeftClick(PosX, PosY, PosZ, BlockFace, Status); + m_Client->HandleLeftClick(PosX, PosY, PosZ, static_cast<eBlockFace>(BlockFace), Status); return PARSE_OK; } @@ -1236,7 +1289,7 @@ int cProtocol125::ParseBlockPlace(void) } // 1.2.5 didn't have any cursor position, so use 8, 8, 8, so that halfslabs and stairs work correctly and the special value is recognizable. - m_Client->HandleRightClick(PosX, PosY, PosZ, BlockFace, 8, 8, 8, HeldItem); + m_Client->HandleRightClick(PosX, PosY, PosZ, static_cast<eBlockFace>(BlockFace), 8, 8, 8, HeldItem); return PARSE_OK; } @@ -1287,7 +1340,16 @@ int cProtocol125::ParseEntityAction(void) { HANDLE_PACKET_READ(ReadBEInt, int, EntityID); HANDLE_PACKET_READ(ReadChar, char, ActionID); - m_Client->HandleEntityAction(EntityID, ActionID); + + switch (ActionID) + { + case 1: m_Client->HandleEntityCrouch(EntityID, true); break; // Crouch + case 2: m_Client->HandleEntityCrouch(EntityID, false); break; // Uncrouch + case 3: m_Client->HandleEntityLeaveBed(EntityID); break; // Leave Bed + case 4: m_Client->HandleEntitySprinting(EntityID, true); break; // Start sprinting + case 5: m_Client->HandleEntitySprinting(EntityID, false); break; // Stop sprinting + } + return PARSE_OK; } @@ -1464,7 +1526,7 @@ int cProtocol125::ParsePluginMessage(void) HANDLE_PACKET_READ(ReadBEUTF16String16, AString, ChannelName); HANDLE_PACKET_READ(ReadBEShort, short, Length); AString Data; - if (!m_ReceivedData.ReadString(Data, Length)) + if (!m_ReceivedData.ReadString(Data, (size_t)Length)) { m_ReceivedData.CheckValid(); return PARSE_INCOMPLETE; @@ -1641,7 +1703,7 @@ void cProtocol125::SendPreChunk(int a_ChunkX, int a_ChunkZ, bool a_ShouldLoad) void cProtocol125::SendWindowSlots(char a_WindowID, int a_NumItems, const cItem * a_Items) { WriteByte (PACKET_INVENTORY_WHOLE); - WriteByte (a_WindowID); + WriteChar (a_WindowID); WriteShort((short)a_NumItems); for (int j = 0; j < a_NumItems; j++) @@ -1671,7 +1733,7 @@ void cProtocol125::WriteItem(const cItem & a_Item) return; } - WriteByte (a_Item.m_ItemCount); + WriteChar (a_Item.m_ItemCount); WriteShort(a_Item.m_ItemDamage); if (cItem::IsEnchantable(a_Item.m_ItemType)) @@ -1718,7 +1780,7 @@ int cProtocol125::ParseItem(cItem & a_Item) } // TODO: Enchantment not implemented yet! - if (!m_ReceivedData.SkipRead(EnchantNumBytes)) + if (!m_ReceivedData.SkipRead((size_t)EnchantNumBytes)) { return PARSE_INCOMPLETE; } @@ -1803,7 +1865,7 @@ void cProtocol125::WriteMobMetadata(const cMonster & a_Mob) case cMonster::mtCreeper: { WriteByte(0x10); - WriteByte(((const cCreeper &)a_Mob).IsBlowing() ? 1 : -1); // Blowing up? + WriteChar(((const cCreeper &)a_Mob).IsBlowing() ? 1 : -1); // Blowing up? WriteByte(0x11); WriteByte(((const cCreeper &)a_Mob).IsCharged() ? 1 : 0); // Lightning-charged? break; @@ -1873,9 +1935,9 @@ void cProtocol125::WriteMobMetadata(const cMonster & a_Mob) WriteByte(0x10); Byte SheepMetadata = 0; - SheepMetadata = ((const cSheep &)a_Mob).GetFurColor(); // Fur colour + SheepMetadata = (Byte)((const cSheep &)a_Mob).GetFurColor(); - if (((const cSheep &)a_Mob).IsSheared()) // Is sheared? + if (((const cSheep &)a_Mob).IsSheared()) { SheepMetadata |= 0x16; } @@ -1904,17 +1966,25 @@ void cProtocol125::WriteMobMetadata(const cMonster & a_Mob) WriteByte(((const cWitch &)a_Mob).IsAngry() ? 1 : 0); // Aggravated? Doesn't seem to do anything break; } + case cMonster::mtWither: + { + WriteByte(0x54); // Int at index 20 + WriteInt((Int32)((const cWither &)a_Mob).GetNumInvulnerableTicks()); + WriteByte(0x66); // Float at index 6 + WriteFloat((float)(a_Mob.GetHealth())); + break; + } case cMonster::mtSlime: case cMonster::mtMagmaCube: { WriteByte(0x10); if (a_Mob.GetMobType() == cMonster::mtSlime) { - WriteByte(((const cSlime &)a_Mob).GetSize()); // Size of slime - HEWGE, meh, cute BABBY SLIME + WriteByte((Byte)((const cSlime &)a_Mob).GetSize()); // Size of slime - HEWGE, meh, cute BABBY SLIME } else { - WriteByte(((const cMagmaCube &)a_Mob).GetSize()); // Size of slime - HEWGE, meh, cute BABBY SLIME + WriteByte((Byte)((const cMagmaCube &)a_Mob).GetSize()); // Size of slime - HEWGE, meh, cute BABBY SLIME } break; } @@ -1953,7 +2023,7 @@ void cProtocol125::WriteMobMetadata(const cMonster & a_Mob) WriteInt(Flags); WriteByte(0x13); - WriteByte(((const cHorse &)a_Mob).GetHorseType()); // Type of horse (donkey, chestnut, etc.) + WriteByte((Byte)((const cHorse &)a_Mob).GetHorseType()); // Type of horse (donkey, chestnut, etc.) WriteByte(0x54); int Appearance = 0; @@ -1965,6 +2035,10 @@ void cProtocol125::WriteMobMetadata(const cMonster & a_Mob) WriteInt(((const cHorse &)a_Mob).GetHorseArmour()); // Horshey armour break; } + default: + { + break; + } } } diff --git a/src/Protocol/Protocol125.h b/src/Protocol/Protocol125.h index e3c8765b1..753458ebc 100644 --- a/src/Protocol/Protocol125.h +++ b/src/Protocol/Protocol125.h @@ -11,6 +11,7 @@ #include "Protocol.h" #include "../ByteBuffer.h" +#include "../Entities/Painting.h" @@ -24,7 +25,7 @@ public: cProtocol125(cClientHandle * a_Client); /// Called when client sends some data: - virtual void DataReceived(const char * a_Data, int a_Size) override; + 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; @@ -33,6 +34,7 @@ public: 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 SendChat (const AString & a_Message) override; + virtual void SendChat (const cCompositeChat & a_Message) override; virtual void SendChunkData (int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer) override; virtual void SendCollectPickup (const cPickup & a_Pickup, const cPlayer & a_Player) override; virtual void SendDestroyEntity (const cEntity & a_Entity) override; @@ -54,7 +56,19 @@ public: virtual void SendInventorySlot (char a_WindowID, short a_SlotNum, const cItem & a_Item) override; virtual void SendKeepAlive (int a_PingID) override; virtual void SendLogin (const cPlayer & a_Player, const cWorld & a_World) override; + virtual void SendMapColumn (int a_ID, int a_X, int a_Y, const Byte * a_Colors, unsigned int a_Length) override; + virtual void SendMapDecorators (int a_ID, const cMapDecoratorList & a_Decorators) override; + virtual void SendMapInfo (int a_ID, unsigned int a_Scale) override + { + // This protocol doesn't support such message + UNUSED(a_ID); + UNUSED(a_Scale); + } 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_ParticleAmmount) override; + virtual void SendPaintingSpawn (const cPainting & a_Painting) override + { + UNUSED(a_Painting); + }; virtual void SendPickupSpawn (const cPickup & a_Pickup) override; virtual void SendPlayerAbilities (void) override {} // This protocol doesn't support such message virtual void SendEntityAnimation (const cEntity & a_Entity, char a_Animation) override; @@ -68,6 +82,14 @@ public: virtual void SendRespawn (void) 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 + { + UNUSED(a_Name); + UNUSED(a_DisplayName); + UNUSED(a_Mode); + } // This protocol doesn't support such message + virtual void SendScoreUpdate (const AString & a_Objective, const AString & a_Player, cObjective::Score a_Score, Byte a_Mode) override {} // This protocol doesn't support such message + virtual void SendDisplayObjective (const AString & a_Objective, cScoreboard::eDisplaySlot a_Display) override {} // This protocol doesn't support such message virtual void SendSoundEffect (const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch) override; // a_Src coords are Block * 8 virtual void SendSoundParticleEffect (int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data) override; virtual void SendSpawnFallingBlock (const cFallingBlock & a_FallingBlock) override; @@ -83,8 +105,8 @@ public: 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 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; @@ -103,7 +125,7 @@ protected: AString m_Username; ///< Stored in ParseHandshake(), compared to Login username - virtual void SendData(const char * a_Data, int a_Size) override; + virtual void SendData(const char * a_Data, size_t a_Size) override; /// Sends the Handshake packet void SendHandshake(const AString & a_ConnectionHash); diff --git a/src/Protocol/Protocol132.cpp b/src/Protocol/Protocol132.cpp index b4ca37d37..ce5942a5c 100644 --- a/src/Protocol/Protocol132.cpp +++ b/src/Protocol/Protocol132.cpp @@ -28,13 +28,14 @@ #pragma warning(disable:4702) #endif -#include "cryptopp/randpool.h" - #ifdef _MSC_VER #pragma warning(pop) #endif + + + #define HANDLE_PACKET_READ(Proc, Type, Var) \ Type Var; \ { \ @@ -49,17 +50,6 @@ -typedef unsigned char Byte; - - - - - -using namespace CryptoPP; - - - - const int MAX_ENC_LEN = 512; // Maximum size of the encrypted message; should be 128, but who knows... @@ -93,81 +83,6 @@ enum -// Converts a raw 160-bit SHA1 digest into a Java Hex representation -// According to http://wiki.vg/wiki/index.php?title=Protocol_Encryption&oldid=2802 -static void DigestToJava(byte a_Digest[20], AString & a_Out) -{ - bool IsNegative = (a_Digest[0] >= 0x80); - if (IsNegative) - { - // Two's complement: - bool carry = true; // Add one to the whole number - for (int i = 19; i >= 0; i--) - { - a_Digest[i] = ~a_Digest[i]; - if (carry) - { - carry = (a_Digest[i] == 0xff); - a_Digest[i]++; - } - } - } - a_Out.clear(); - a_Out.reserve(40); - for (int i = 0; i < 20; i++) - { - AppendPrintf(a_Out, "%02x", a_Digest[i]); - } - while ((a_Out.length() > 0) && (a_Out[0] == '0')) - { - a_Out.erase(0, 1); - } - if (IsNegative) - { - a_Out.insert(0, "-"); - } -} - - - - - -/* -// Self-test the hash formatting for known values: -// sha1(Notch) : 4ed1f46bbe04bc756bcb17c0c7ce3e4632f06a48 -// sha1(jeb_) : -7c9d5b0044c130109a5d7b5fb5c317c02b4e28c1 -// sha1(simon) : 88e16a1019277b15d58faf0541e11910eb756f6 - -class Test -{ -public: - Test(void) - { - AString DigestNotch, DigestJeb, DigestSimon; - byte Digest[20]; - CryptoPP::SHA1 Checksum; - Checksum.Update((const byte *)"Notch", 5); - Checksum.Final(Digest); - DigestToJava(Digest, DigestNotch); - Checksum.Restart(); - Checksum.Update((const byte *)"jeb_", 4); - Checksum.Final(Digest); - DigestToJava(Digest, DigestJeb); - Checksum.Restart(); - Checksum.Update((const byte *)"simon", 5); - Checksum.Final(Digest); - DigestToJava(Digest, DigestSimon); - printf("Notch: \"%s\"", DigestNotch.c_str()); - printf("jeb_: \"%s\"", DigestJeb.c_str()); - printf("simon: \"%s\"", DigestSimon.c_str()); - } -} test; -*/ - - - - - /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // cProtocol132: @@ -185,7 +100,7 @@ cProtocol132::~cProtocol132() { if (!m_DataToSend.empty()) { - LOGD("There are %d unsent bytes while deleting cProtocol132", m_DataToSend.size()); + LOGD("There are " SIZE_T_FMT " unsent bytes while deleting cProtocol132", m_DataToSend.size()); } } @@ -193,15 +108,15 @@ cProtocol132::~cProtocol132() -void cProtocol132::DataReceived(const char * a_Data, int a_Size) +void cProtocol132::DataReceived(const char * a_Data, size_t a_Size) { if (m_IsEncrypted) { - byte Decrypted[512]; + Byte Decrypted[512]; while (a_Size > 0) { - int NumBytes = (a_Size > (int)sizeof(Decrypted)) ? (int)sizeof(Decrypted) : a_Size; - m_Decryptor.ProcessData(Decrypted, (byte *)a_Data, NumBytes); + size_t NumBytes = (a_Size > sizeof(Decrypted)) ? sizeof(Decrypted) : a_Size; + m_Decryptor.ProcessData(Decrypted, (Byte *)a_Data, NumBytes); super::DataReceived((const char *)Decrypted, NumBytes); a_Size -= NumBytes; a_Data += NumBytes; @@ -224,8 +139,8 @@ void cProtocol132::SendBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, cha WriteInt (a_BlockX); WriteShort((short)a_BlockY); WriteInt (a_BlockZ); - WriteByte (a_Byte1); - WriteByte (a_Byte2); + WriteChar (a_Byte1); + WriteChar (a_Byte2); WriteShort(a_BlockType); Flush(); } @@ -242,7 +157,7 @@ void cProtocol132::SendBlockBreakAnim(int a_entityID, int a_BlockX, int a_BlockY WriteInt (a_BlockX); WriteInt (a_BlockY); WriteInt (a_BlockZ); - WriteByte (stage); + WriteChar (stage); Flush(); } @@ -344,7 +259,7 @@ void cProtocol132::SendLogin(const cPlayer & a_Player, const cWorld & a_World) WriteByte (PACKET_LOGIN); WriteInt (a_Player.GetUniqueID()); // EntityID of the player WriteString("default"); // Level type - WriteByte ((int)a_Player.GetGameMode()); + WriteByte ((Byte)a_Player.GetGameMode()); WriteByte ((Byte)(a_World.GetDimension())); WriteByte (2); // TODO: Difficulty WriteByte (0); // Unused, used to be world height @@ -368,8 +283,8 @@ void cProtocol132::SendPlayerSpawn(const cPlayer & a_Player) WriteInt ((int)(a_Player.GetPosX() * 32)); WriteInt ((int)(a_Player.GetPosY() * 32)); WriteInt ((int)(a_Player.GetPosZ() * 32)); - WriteByte ((char)((a_Player.GetYaw() / 360.f) * 256)); - WriteByte ((char)((a_Player.GetPitch() / 360.f) * 256)); + WriteChar ((char)((a_Player.GetYaw() / 360.f) * 256)); + WriteChar ((char)((a_Player.GetPitch() / 360.f) * 256)); WriteShort (HeldItem.IsEmpty() ? 0 : HeldItem.m_ItemType); // Player metadata: just use a default metadata value, since the client doesn't like starting without any metadata: WriteByte (0); // Index 0, byte (flags) @@ -391,7 +306,7 @@ void cProtocol132::SendSoundEffect(const AString & a_SoundName, int a_SrcX, int WriteInt (a_SrcY); WriteInt (a_SrcZ); WriteFloat (a_Volume); - WriteByte ((char)(a_Pitch * 63.0f)); + WriteChar ((char)(a_Pitch * 63.0f)); Flush(); } @@ -405,7 +320,7 @@ void cProtocol132::SendSoundParticleEffect(int a_EffectID, int a_SrcX, int a_Src WriteByte(PACKET_SOUND_PARTICLE_EFFECT); WriteInt (a_EffectID); WriteInt (a_SrcX); - WriteByte(a_SrcY); + WriteByte((Byte)a_SrcY); WriteInt (a_SrcZ); WriteInt (a_Data); Flush(); @@ -420,7 +335,7 @@ void cProtocol132::SendSpawnMob(const cMonster & a_Mob) cCSLock Lock(m_CSPacket); WriteByte (PACKET_SPAWN_MOB); WriteInt (a_Mob.GetUniqueID()); - WriteByte (a_Mob.GetMobType()); + WriteByte ((Byte)a_Mob.GetMobType()); WriteVectorI((Vector3i)(a_Mob.GetPosition() * 32)); WriteByte ((Byte)((a_Mob.GetYaw() / 360.f) * 256)); WriteByte ((Byte)((a_Mob.GetPitch() / 360.f) * 256)); @@ -496,12 +411,12 @@ void cProtocol132::SendWholeInventory(const cWindow & a_Window) const cInventory & Inventory = m_Client->GetPlayer()->GetInventory(); int BaseOffset = a_Window.GetNumSlots() - (cInventory::invNumSlots - cInventory::invInventoryOffset); // Number of non-inventory slots char WindowID = a_Window.GetWindowID(); - for (int i = 0; i < cInventory::invInventoryCount; i++) + for (short i = 0; i < cInventory::invInventoryCount; i++) { SendInventorySlot(WindowID, BaseOffset + i, Inventory.GetInventorySlot(i)); } // for i - Inventory[] BaseOffset += cInventory::invInventoryCount; - for (int i = 0; i < cInventory::invHotbarCount; i++) + for (short i = 0; i < cInventory::invHotbarCount; i++) { SendInventorySlot(WindowID, BaseOffset + i, Inventory.GetHotbarSlot(i)); } // for i - Hotbar[] @@ -561,7 +476,7 @@ int cProtocol132::ParseBlockPlace(void) HANDLE_PACKET_READ(ReadChar, char, CursorY); HANDLE_PACKET_READ(ReadChar, char, CursorZ); - m_Client->HandleRightClick(PosX, PosY, PosZ, BlockFace, CursorX, CursorY, CursorZ, HeldItem); + m_Client->HandleRightClick(PosX, PosY, PosZ, static_cast<eBlockFace>(BlockFace), CursorX, CursorY, CursorZ, HeldItem); return PARSE_OK; } @@ -582,9 +497,7 @@ int cProtocol132::ParseHandshake(void) return PARSE_OK; // Player is not allowed into the server } - // Send a 0xFD Encryption Key Request http://wiki.vg/Protocol#0xFD - CryptoPP::StringSink sink(m_ServerPublicKey); // GCC won't allow inline instantiation in the following line, damned temporary refs - cRoot::Get()->GetServer()->GetPublicKey().Save(sink); + // Send a 0xfd Encryption Key Request http://wiki.vg/Protocol#0xFD SendEncryptionKeyRequest(); return PARSE_OK; @@ -596,7 +509,7 @@ int cProtocol132::ParseHandshake(void) int cProtocol132::ParseClientStatuses(void) { - HANDLE_PACKET_READ(ReadByte, byte, Status); + HANDLE_PACKET_READ(ReadByte, Byte, Status); if ((Status & 1) == 0) { m_Client->HandleLogin(39, m_Username); @@ -614,21 +527,30 @@ int cProtocol132::ParseClientStatuses(void) int cProtocol132::ParseEncryptionKeyResponse(void) { + // Read the encryption key: HANDLE_PACKET_READ(ReadBEShort, short, EncKeyLength); + if (EncKeyLength > MAX_ENC_LEN) + { + LOGD("Too long encryption key"); + m_Client->Kick("Hacked client"); + return PARSE_OK; + } AString EncKey; - if (!m_ReceivedData.ReadString(EncKey, EncKeyLength)) + if (!m_ReceivedData.ReadString(EncKey, (size_t)EncKeyLength)) { return PARSE_INCOMPLETE; } + + // Read the encryption nonce: HANDLE_PACKET_READ(ReadBEShort, short, EncNonceLength); AString EncNonce; - if (!m_ReceivedData.ReadString(EncNonce, EncNonceLength)) + if (!m_ReceivedData.ReadString(EncNonce, (size_t)EncNonceLength)) { return PARSE_INCOMPLETE; } - if ((EncKeyLength > MAX_ENC_LEN) || (EncNonceLength > MAX_ENC_LEN)) + if (EncNonceLength > MAX_ENC_LEN) { - LOGD("Too long encryption"); + LOGD("Too long encryption nonce"); m_Client->Kick("Hacked client"); return PARSE_OK; } @@ -647,7 +569,7 @@ int cProtocol132::ParseLocaleViewDistance(void) HANDLE_PACKET_READ(ReadChar, char, ViewDistance); HANDLE_PACKET_READ(ReadChar, char, ChatFlags); HANDLE_PACKET_READ(ReadChar, char, ClientDifficulty); - // TODO: m_Client->HandleLocale(Locale); + m_Client->SetLocale(Locale); // TODO: m_Client->HandleViewDistance(ViewDistance); // TODO: m_Client->HandleChatFlags(ChatFlags); // Ignoring client difficulty @@ -692,7 +614,7 @@ int cProtocol132::ParseTabCompletion(void) -void cProtocol132::SendData(const char * a_Data, int a_Size) +void cProtocol132::SendData(const char * a_Data, size_t a_Size) { m_DataToSend.append(a_Data, a_Size); } @@ -710,23 +632,23 @@ void cProtocol132::Flush(void) LOGD("Flushing empty"); return; } - const char * a_Data = m_DataToSend.data(); - int a_Size = m_DataToSend.size(); + const char * Data = m_DataToSend.data(); + size_t Size = m_DataToSend.size(); if (m_IsEncrypted) { - byte Encrypted[8192]; // Larger buffer, we may be sending lots of data (chunks) - while (a_Size > 0) + Byte Encrypted[8192]; // Larger buffer, we may be sending lots of data (chunks) + while (Size > 0) { - int NumBytes = (a_Size > (int)sizeof(Encrypted)) ? (int)sizeof(Encrypted) : a_Size; - m_Encryptor.ProcessData(Encrypted, (byte *)a_Data, NumBytes); + size_t NumBytes = (Size > sizeof(Encrypted)) ? sizeof(Encrypted) : Size; + m_Encryptor.ProcessData(Encrypted, (Byte *)Data, NumBytes); super::SendData((const char *)Encrypted, NumBytes); - a_Size -= NumBytes; - a_Data += NumBytes; + Size -= NumBytes; + Data += NumBytes; } } else { - super::SendData(a_Data, a_Size); + super::SendData(Data, Size); } m_DataToSend.clear(); } @@ -752,7 +674,7 @@ void cProtocol132::WriteItem(const cItem & a_Item) } WriteShort(ItemType); - WriteByte (a_Item.m_ItemCount); + WriteChar (a_Item.m_ItemCount); WriteShort(a_Item.m_ItemDamage); if (a_Item.m_Enchantments.IsEmpty()) @@ -768,7 +690,7 @@ void cProtocol132::WriteItem(const cItem & a_Item) Writer.Finish(); AString Compressed; CompressStringGZIP(Writer.GetResult().data(), Writer.GetResult().size(), Compressed); - WriteShort(Compressed.size()); + WriteShort((short)Compressed.size()); SendData(Compressed.data(), Compressed.size()); } @@ -804,8 +726,8 @@ int cProtocol132::ParseItem(cItem & a_Item) // Read the metadata AString Metadata; - Metadata.resize(MetadataLength); - if (!m_ReceivedData.ReadBuf((void *)Metadata.data(), MetadataLength)) + Metadata.resize((size_t)MetadataLength); + if (!m_ReceivedData.ReadBuf((void *)Metadata.data(), (size_t)MetadataLength)) { return PARSE_INCOMPLETE; } @@ -880,8 +802,8 @@ void cProtocol132::SendEncryptionKeyRequest(void) cCSLock Lock(m_CSPacket); WriteByte(0xfd); WriteString(cRoot::Get()->GetServer()->GetServerID()); - WriteShort((short)m_ServerPublicKey.size()); - SendData(m_ServerPublicKey.data(), m_ServerPublicKey.size()); + WriteShort((short)(cRoot::Get()->GetServer()->GetPublicKeyDER().size())); + SendData(cRoot::Get()->GetServer()->GetPublicKeyDER().data(), cRoot::Get()->GetServer()->GetPublicKeyDER().size()); WriteShort(4); WriteInt((int)(intptr_t)this); // Using 'this' as the cryptographic nonce, so that we don't have to generate one each time :) Flush(); @@ -894,13 +816,11 @@ void cProtocol132::SendEncryptionKeyRequest(void) void cProtocol132::HandleEncryptionKeyResponse(const AString & a_EncKey, const AString & a_EncNonce) { // Decrypt EncNonce using privkey - RSAES<PKCS1v15>::Decryptor rsaDecryptor(cRoot::Get()->GetServer()->GetPrivateKey()); - time_t CurTime = time(NULL); - CryptoPP::RandomPool rng; - rng.Put((const byte *)&CurTime, sizeof(CurTime)); + cRSAPrivateKey & rsaDecryptor = cRoot::Get()->GetServer()->GetPrivateKey(); + Int32 DecryptedNonce[MAX_ENC_LEN / sizeof(Int32)]; - DecodingResult res = rsaDecryptor.Decrypt(rng, (const byte *)a_EncNonce.data(), a_EncNonce.size(), (byte *)DecryptedNonce); - if (!res.isValidCoding || (res.messageLength != 4)) + int res = rsaDecryptor.Decrypt((const Byte *)a_EncNonce.data(), a_EncNonce.size(), (Byte *)DecryptedNonce, sizeof(DecryptedNonce)); + if (res != 4) { LOGD("Bad nonce length"); m_Client->Kick("Hacked client"); @@ -914,9 +834,9 @@ void cProtocol132::HandleEncryptionKeyResponse(const AString & a_EncKey, const A } // Decrypt the symmetric encryption key using privkey: - byte DecryptedKey[MAX_ENC_LEN]; - res = rsaDecryptor.Decrypt(rng, (const byte *)a_EncKey.data(), a_EncKey.size(), DecryptedKey); - if (!res.isValidCoding || (res.messageLength != 16)) + Byte DecryptedKey[MAX_ENC_LEN]; + res = rsaDecryptor.Decrypt((const Byte *)a_EncKey.data(), a_EncKey.size(), DecryptedKey, sizeof(DecryptedKey)); + if (res != 16) { LOGD("Bad key length"); m_Client->Kick("Hacked client"); @@ -932,6 +852,12 @@ void cProtocol132::HandleEncryptionKeyResponse(const AString & a_EncKey, const A Flush(); } + #ifdef _DEBUG + AString DecryptedKeyHex; + CreateHexDump(DecryptedKeyHex, DecryptedKey, res, 16); + LOGD("Received encryption key, %d bytes:\n%s", res, DecryptedKeyHex.c_str()); + #endif + StartEncryption(DecryptedKey); return; } @@ -940,21 +866,21 @@ void cProtocol132::HandleEncryptionKeyResponse(const AString & a_EncKey, const A -void cProtocol132::StartEncryption(const byte * a_Key) +void cProtocol132::StartEncryption(const Byte * a_Key) { - m_Encryptor.SetKey(a_Key, 16, MakeParameters(Name::IV(), ConstByteArrayParameter(a_Key, 16))(Name::FeedbackSize(), 1)); - m_Decryptor.SetKey(a_Key, 16, MakeParameters(Name::IV(), ConstByteArrayParameter(a_Key, 16))(Name::FeedbackSize(), 1)); + m_Encryptor.Init(a_Key, a_Key); + m_Decryptor.Init(a_Key, a_Key); m_IsEncrypted = true; // Prepare the m_AuthServerID: - CryptoPP::SHA1 Checksum; + cSHA1Checksum Checksum; AString ServerID = cRoot::Get()->GetServer()->GetServerID(); - Checksum.Update((const byte *)ServerID.c_str(), ServerID.length()); + Checksum.Update((const Byte *)ServerID.c_str(), ServerID.length()); Checksum.Update(a_Key, 16); - Checksum.Update((const byte *)m_ServerPublicKey.c_str(), m_ServerPublicKey.length()); - byte Digest[20]; - Checksum.Final(Digest); - DigestToJava(Digest, m_AuthServerID); + Checksum.Update((const Byte *)cRoot::Get()->GetServer()->GetPublicKeyDER().data(), cRoot::Get()->GetServer()->GetPublicKeyDER().size()); + Byte Digest[20]; + Checksum.Finalize(Digest); + cSHA1Checksum::DigestToJava(Digest, m_AuthServerID); } diff --git a/src/Protocol/Protocol132.h b/src/Protocol/Protocol132.h index 80fc8740a..b280c8a41 100644 --- a/src/Protocol/Protocol132.h +++ b/src/Protocol/Protocol132.h @@ -20,13 +20,12 @@ #pragma warning(disable:4702) #endif -#include "cryptopp/modes.h" -#include "cryptopp/aes.h" - #ifdef _MSC_VER #pragma warning(pop) #endif +#include "../Crypto.h" + @@ -41,7 +40,7 @@ public: virtual ~cProtocol132(); /// Called when client sends some data: - virtual void DataReceived(const char * a_Data, int a_Size) override; + virtual void DataReceived(const char * a_Data, size_t a_Size) override; // Sending commands (alphabetically sorted): virtual void SendBlockAction (int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType) override; @@ -79,17 +78,16 @@ public: protected: bool m_IsEncrypted; - CryptoPP::CFB_Mode<CryptoPP::AES>::Decryption m_Decryptor; - CryptoPP::CFB_Mode<CryptoPP::AES>::Encryption m_Encryptor; + + cAESCFBDecryptor m_Decryptor; + cAESCFBEncryptor m_Encryptor; + AString m_DataToSend; /// The ServerID used for session authentication; set in StartEncryption(), used in GetAuthServerID() AString m_AuthServerID; - /// The server's public key, as used by SendEncryptionKeyRequest() and StartEncryption() - AString m_ServerPublicKey; - - virtual void SendData(const char * a_Data, int a_Size) override; + virtual void SendData(const char * a_Data, size_t a_Size) override; // DEBUG: virtual void Flush(void) override; @@ -108,7 +106,7 @@ protected: void HandleEncryptionKeyResponse(const AString & a_EncKey, const AString & a_EncNonce); /// Starts the symmetric encryption with the specified key; also sets m_AuthServerID - void StartEncryption(const byte * a_Key); + void StartEncryption(const Byte * a_Key); } ; diff --git a/src/Protocol/Protocol14x.cpp b/src/Protocol/Protocol14x.cpp index 127ce9d4b..f694af1eb 100644 --- a/src/Protocol/Protocol14x.cpp +++ b/src/Protocol/Protocol14x.cpp @@ -33,8 +33,6 @@ Implements the 1.4.x protocol classes representing these protocols: #pragma warning(disable:4702) #endif -#include "cryptopp/randpool.h" - #ifdef _MSC_VER #pragma warning(pop) #endif @@ -87,7 +85,7 @@ int cProtocol142::ParseLocaleViewDistance(void) HANDLE_PACKET_READ(ReadChar, char, ChatFlags); HANDLE_PACKET_READ(ReadChar, char, ClientDifficulty); HANDLE_PACKET_READ(ReadChar, char, ShouldShowCape); // <-- new in 1.4.2 - // TODO: m_Client->HandleLocale(Locale); + m_Client->SetLocale(Locale); // TODO: m_Client->HandleViewDistance(ViewDistance); // TODO: m_Client->HandleChatFlags(ChatFlags); // Ignoring client difficulty @@ -105,9 +103,9 @@ void cProtocol142::SendPickupSpawn(const cPickup & a_Pickup) WriteInt (a_Pickup.GetUniqueID()); WriteItem (a_Pickup.GetItem()); WriteVectorI((Vector3i)(a_Pickup.GetPosition() * 32)); - WriteByte ((char)(a_Pickup.GetSpeed().x * 8)); - WriteByte ((char)(a_Pickup.GetSpeed().y * 8)); - WriteByte ((char)(a_Pickup.GetSpeed().z * 8)); + WriteChar ((char)(a_Pickup.GetSpeed().x * 8)); + WriteChar ((char)(a_Pickup.GetSpeed().y * 8)); + WriteChar ((char)(a_Pickup.GetSpeed().z * 8)); Flush(); } @@ -121,7 +119,7 @@ void cProtocol142::SendSoundParticleEffect(int a_EffectID, int a_SrcX, int a_Src WriteByte(PACKET_SOUND_PARTICLE_EFFECT); WriteInt (a_EffectID); WriteInt (a_SrcX); - WriteByte(a_SrcY); + WriteByte((Byte)a_SrcY); WriteInt (a_SrcZ); WriteInt (a_Data); WriteBool(0); @@ -220,7 +218,7 @@ void cProtocol146::SendSpawnObject(const cEntity & a_Entity, char a_ObjectType, cCSLock Lock(m_CSPacket); WriteByte(PACKET_SPAWN_OBJECT); WriteInt (a_Entity.GetUniqueID()); - WriteByte(a_ObjectType); + WriteChar(a_ObjectType); WriteInt ((int)(a_Entity.GetPosX() * 32)); WriteInt ((int)(a_Entity.GetPosY() * 32)); WriteInt ((int)(a_Entity.GetPosZ() * 32)); @@ -245,7 +243,7 @@ void cProtocol146::SendSpawnVehicle(const cEntity & a_Vehicle, char a_VehicleTyp cCSLock Lock(m_CSPacket); WriteByte (PACKET_SPAWN_OBJECT); WriteInt (a_Vehicle.GetUniqueID()); - WriteByte (a_VehicleType); + WriteChar (a_VehicleType); WriteInt ((int)(a_Vehicle.GetPosX() * 32)); WriteInt ((int)(a_Vehicle.GetPosY() * 32)); WriteInt ((int)(a_Vehicle.GetPosZ() * 32)); diff --git a/src/Protocol/Protocol15x.cpp b/src/Protocol/Protocol15x.cpp index 0f1e59f10..264a596b9 100644 --- a/src/Protocol/Protocol15x.cpp +++ b/src/Protocol/Protocol15x.cpp @@ -35,8 +35,11 @@ Implements the 1.5.x protocol classes: enum { - PACKET_WINDOW_OPEN = 0x64, - PACKET_PARTICLE_EFFECT = 0x3F, + PACKET_WINDOW_OPEN = 0x64, + PACKET_PARTICLE_EFFECT = 0x3F, + PACKET_SCOREBOARD_OBJECTIVE = 0xCE, + PACKET_SCORE_UPDATE = 0xCF, + PACKET_DISPLAY_OBJECTIVE = 0xD0 } ; @@ -97,6 +100,53 @@ void cProtocol150::SendParticleEffect(const AString & a_ParticleName, float a_Sr +void cProtocol150::SendScoreboardObjective(const AString & a_Name, const AString & a_DisplayName, Byte a_Mode) +{ + cCSLock Lock(m_CSPacket); + WriteByte(PACKET_SCOREBOARD_OBJECTIVE); + WriteString(a_Name); + WriteString(a_DisplayName); + WriteByte(a_Mode); + Flush(); +} + + + + + +void cProtocol150::SendScoreUpdate(const AString & a_Objective, const AString & a_Player, cObjective::Score a_Score, Byte a_Mode) +{ + cCSLock Lock(m_CSPacket); + WriteByte(PACKET_SCORE_UPDATE); + WriteString(a_Player); + WriteByte(a_Mode); + + if (a_Mode != 1) + { + WriteString(a_Objective); + WriteInt((int) a_Score); + } + + Flush(); +} + + + + + +void cProtocol150::SendDisplayObjective(const AString & a_Objective, cScoreboard::eDisplaySlot a_Display) +{ + cCSLock Lock(m_CSPacket); + WriteByte(PACKET_DISPLAY_OBJECTIVE); + WriteByte((int) a_Display); + WriteString(a_Objective); + Flush(); +} + + + + + int cProtocol150::ParseWindowClick(void) { HANDLE_PACKET_READ(ReadChar, char, WindowID); diff --git a/src/Protocol/Protocol15x.h b/src/Protocol/Protocol15x.h index 0074b3a83..0d171a67c 100644 --- a/src/Protocol/Protocol15x.h +++ b/src/Protocol/Protocol15x.h @@ -30,6 +30,9 @@ public: virtual void SendWindowOpen (const cWindow & a_Window) 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_ParticleAmmount) 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 int ParseWindowClick(void); } ; diff --git a/src/Protocol/Protocol16x.cpp b/src/Protocol/Protocol16x.cpp index cfa27b3c4..3da23a1dc 100644 --- a/src/Protocol/Protocol16x.cpp +++ b/src/Protocol/Protocol16x.cpp @@ -18,6 +18,7 @@ Implements the 1.6.x protocol classes: #include "../Entities/Entity.h" #include "../Entities/Player.h" #include "../UI/Window.h" +#include "../CompositeChat.h" @@ -89,6 +90,18 @@ void cProtocol161::SendChat(const AString & a_Message) +void cProtocol161::SendChat(const cCompositeChat & a_Message) +{ + // This protocol version doesn't support composite messages to the full + // Just extract each part's text and use it: + + super::SendChat(Printf("{\"text\":\"%s\"}", EscapeString(a_Message.ExtractText()).c_str())); +} + + + + + void cProtocol161::SendEditSign(int a_BlockX, int a_BlockY, int a_BlockZ) { cCSLock Lock(m_CSPacket); @@ -119,7 +132,7 @@ void cProtocol161::SendHealth(void) cCSLock Lock(m_CSPacket); WriteByte (PACKET_UPDATE_HEALTH); WriteFloat((float)m_Client->GetPlayer()->GetHealth()); - WriteShort(m_Client->GetPlayer()->GetFoodLevel()); + WriteShort((short)m_Client->GetPlayer()->GetFoodLevel()); WriteFloat((float)m_Client->GetPlayer()->GetFoodSaturationLevel()); Flush(); } @@ -135,7 +148,7 @@ void cProtocol161::SendPlayerMaxSpeed(void) WriteInt(m_Client->GetPlayer()->GetUniqueID()); WriteInt(1); WriteString("generic.movementSpeed"); - WriteDouble(m_Client->GetPlayer()->GetMaxSpeed()); + WriteDouble(0.1 * m_Client->GetPlayer()->GetMaxSpeed()); Flush(); } @@ -163,10 +176,10 @@ void cProtocol161::SendWindowOpen(const cWindow & a_Window) } cCSLock Lock(m_CSPacket); WriteByte (PACKET_WINDOW_OPEN); - WriteByte (a_Window.GetWindowID()); - WriteByte (a_Window.GetWindowType()); + WriteChar (a_Window.GetWindowID()); + WriteByte ((Byte)a_Window.GetWindowType()); WriteString(a_Window.GetWindowTitle()); - WriteByte (a_Window.GetNumNonInventorySlots()); + WriteByte ((Byte)a_Window.GetNumNonInventorySlots()); WriteByte (1); // Use title if (a_Window.GetWindowType() == cWindow::wtAnimalChest) { @@ -184,7 +197,16 @@ int cProtocol161::ParseEntityAction(void) HANDLE_PACKET_READ(ReadBEInt, int, EntityID); HANDLE_PACKET_READ(ReadChar, char, ActionID); HANDLE_PACKET_READ(ReadBEInt, int, UnknownHorseVal); - m_Client->HandleEntityAction(EntityID, ActionID); + + switch (ActionID) + { + case 1: m_Client->HandleEntityCrouch(EntityID, true); break; // Crouch + case 2: m_Client->HandleEntityCrouch(EntityID, false); break; // Uncrouch + case 3: m_Client->HandleEntityLeaveBed(EntityID); break; // Leave Bed + case 4: m_Client->HandleEntitySprinting(EntityID, true); break; // Start sprinting + case 5: m_Client->HandleEntitySprinting(EntityID, false); break; // Stop sprinting + } + return PARSE_OK; } @@ -258,7 +280,7 @@ void cProtocol162::SendPlayerMaxSpeed(void) WriteInt(m_Client->GetPlayer()->GetUniqueID()); WriteInt(1); WriteString("generic.movementSpeed"); - WriteDouble(m_Client->GetPlayer()->GetMaxSpeed()); + WriteDouble(0.1 * m_Client->GetPlayer()->GetMaxSpeed()); WriteShort(0); Flush(); } diff --git a/src/Protocol/Protocol16x.h b/src/Protocol/Protocol16x.h index 325e41c5a..ae1388649 100644 --- a/src/Protocol/Protocol16x.h +++ b/src/Protocol/Protocol16x.h @@ -37,6 +37,7 @@ protected: // cProtocol150 overrides: virtual void SendAttachEntity (const cEntity & a_Entity, const cEntity * a_Vehicle) override; virtual void SendChat (const AString & a_Message) override; + virtual void SendChat (const cCompositeChat & a_Message) 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 SendGameMode (eGameMode a_GameMode) override; virtual void SendHealth (void) override; diff --git a/src/Protocol/Protocol17x.cpp b/src/Protocol/Protocol17x.cpp index 05b7ebd45..785dbf935 100644 --- a/src/Protocol/Protocol17x.cpp +++ b/src/Protocol/Protocol17x.cpp @@ -1,4 +1,3 @@ - // Protocol17x.cpp /* @@ -9,6 +8,7 @@ Implements the 1.7.x protocol classes: */ #include "Globals.h" +#include "json/json.h" #include "Protocol17x.h" #include "ChunkDataSerializer.h" #include "../ClientHandle.h" @@ -21,11 +21,16 @@ Implements the 1.7.x protocol classes: #include "../Entities/ExpOrb.h" #include "../Entities/Minecart.h" #include "../Entities/FallingBlock.h" +#include "../Entities/Painting.h" #include "../Entities/Pickup.h" #include "../Entities/Player.h" +#include "../Entities/ItemFrame.h" #include "../Mobs/IncludeAllMonsters.h" #include "../UI/Window.h" #include "../BlockEntities/CommandBlockEntity.h" +#include "../BlockEntities/MobHeadEntity.h" +#include "../BlockEntities/FlowerPotEntity.h" +#include "../CompositeChat.h" @@ -54,6 +59,22 @@ Implements the 1.7.x protocol classes: +const int MAX_ENC_LEN = 512; // Maximum size of the encrypted message; should be 128, but who knows... + + + + + +// fwd: main.cpp: +extern bool g_ShouldLogCommIn, g_ShouldLogCommOut; + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cProtocol172: + cProtocol172::cProtocol172(cClientHandle * a_Client, const AString & a_ServerAddress, UInt16 a_ServerPort, UInt32 a_State) : super(a_Client), m_ServerAddress(a_ServerAddress), @@ -64,21 +85,28 @@ cProtocol172::cProtocol172(cClientHandle * a_Client, const AString & a_ServerAdd m_OutPacketLenBuffer(20), // 20 bytes is more than enough for one VarInt m_IsEncrypted(false) { + // Create the comm log file, if so requested: + if (g_ShouldLogCommIn || g_ShouldLogCommOut) + { + cFile::CreateFolder("CommLogs"); + AString FileName = Printf("CommLogs/%x__%s.log", (unsigned)time(NULL), a_Client->GetIPString().c_str()); + m_CommLogFile.Open(FileName, cFile::fmWrite); + } } -void cProtocol172::DataReceived(const char * a_Data, int a_Size) +void cProtocol172::DataReceived(const char * a_Data, size_t a_Size) { if (m_IsEncrypted) { - byte Decrypted[512]; + Byte Decrypted[512]; while (a_Size > 0) { - int NumBytes = (a_Size > sizeof(Decrypted)) ? sizeof(Decrypted) : a_Size; - m_Decryptor.ProcessData(Decrypted, (byte *)a_Data, NumBytes); + size_t NumBytes = (a_Size > sizeof(Decrypted)) ? sizeof(Decrypted) : a_Size; + m_Decryptor.ProcessData(Decrypted, (Byte *)a_Data, NumBytes); AddReceivedData((const char *)Decrypted, NumBytes); a_Size -= NumBytes; a_Data += NumBytes; @@ -124,7 +152,7 @@ void cProtocol172::SendBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, cha void cProtocol172::SendBlockBreakAnim(int a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage) { cPacketizer Pkt(*this, 0x25); // Block Break Animation packet - Pkt.WriteInt(a_EntityID); + Pkt.WriteVarInt(a_EntityID); Pkt.WriteInt(a_BlockX); Pkt.WriteInt(a_BlockY); Pkt.WriteInt(a_BlockZ); @@ -178,6 +206,78 @@ void cProtocol172::SendChat(const AString & a_Message) +void cProtocol172::SendChat(const cCompositeChat & a_Message) +{ + // Compose the complete Json string to send: + Json::Value msg; + msg["text"] = ""; // The client crashes without this + const cCompositeChat::cParts & Parts = a_Message.GetParts(); + for (cCompositeChat::cParts::const_iterator itr = Parts.begin(), end = Parts.end(); itr != end; ++itr) + { + Json::Value Part; + switch ((*itr)->m_PartType) + { + case cCompositeChat::ptText: + { + Part["text"] = (*itr)->m_Text; + AddChatPartStyle(Part, (*itr)->m_Style); + break; + } + + case cCompositeChat::ptClientTranslated: + { + const cCompositeChat::cClientTranslatedPart & p = (const cCompositeChat::cClientTranslatedPart &)**itr; + Part["translate"] = p.m_Text; + Json::Value With; + for (AStringVector::const_iterator itrW = p.m_Parameters.begin(), endW = p.m_Parameters.end(); itrW != endW; ++itr) + { + With.append(*itrW); + } + if (!p.m_Parameters.empty()) + { + Part["with"] = With; + } + AddChatPartStyle(Part, p.m_Style); + break; + } + + case cCompositeChat::ptUrl: + { + const cCompositeChat::cUrlPart & p = (const cCompositeChat::cUrlPart &)**itr; + Part["text"] = p.m_Text; + Json::Value Url; + Url["action"] = "open_url"; + Url["value"] = p.m_Url; + Part["clickEvent"] = Url; + AddChatPartStyle(Part, p.m_Style); + break; + } + + case cCompositeChat::ptSuggestCommand: + case cCompositeChat::ptRunCommand: + { + const cCompositeChat::cCommandPart & p = (const cCompositeChat::cCommandPart &)**itr; + Part["text"] = p.m_Text; + Json::Value Cmd; + Cmd["action"] = (p.m_PartType == cCompositeChat::ptRunCommand) ? "run_command" : "suggest_command"; + Cmd["value"] = p.m_Command; + Part["clickEvent"] = Cmd; + AddChatPartStyle(Part, p.m_Style); + break; + } + } + msg["extra"].append(Part); + } // for itr - Parts[] + + // Send the message to the client: + cPacketizer Pkt(*this, 0x02); + Pkt.WriteString(msg.toStyledString()); +} + + + + + void cProtocol172::SendChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer) { // Serialize first, before creating the Packetizer (the packetizer locks a CS) @@ -454,7 +554,7 @@ void cProtocol172::SendLogin(const cPlayer & a_Player, const cWorld & a_World) Pkt.WriteByte((Byte)a_Player.GetEffectiveGameMode() | (cRoot::Get()->GetServer()->IsHardcore() ? 0x08 : 0)); // Hardcore flag bit 4 Pkt.WriteChar((char)a_World.GetDimension()); Pkt.WriteByte(2); // TODO: Difficulty (set to Normal) - Pkt.WriteByte(cRoot::Get()->GetServer()->GetMaxPlayers()); + Pkt.WriteByte(std::min(cRoot::Get()->GetServer()->GetMaxPlayers(), 60)); Pkt.WriteString("default"); // Level type - wtf? } @@ -473,6 +573,75 @@ void cProtocol172::SendLogin(const cPlayer & a_Player, const cWorld & a_World) +void cProtocol172::SendPaintingSpawn(const cPainting & a_Painting) +{ + cPacketizer Pkt(*this, 0x10); // Spawn Painting packet + Pkt.WriteVarInt(a_Painting.GetUniqueID()); + Pkt.WriteString(a_Painting.GetName().c_str()); + Pkt.WriteInt((int)a_Painting.GetPosX()); + Pkt.WriteInt((int)a_Painting.GetPosY()); + Pkt.WriteInt((int)a_Painting.GetPosZ()); + Pkt.WriteInt(a_Painting.GetDirection()); +} + + + + + +void cProtocol172::SendMapColumn(int a_ID, int a_X, int a_Y, const Byte * a_Colors, unsigned int a_Length) +{ + cPacketizer Pkt(*this, 0x34); + Pkt.WriteVarInt(a_ID); + Pkt.WriteShort (3 + a_Length); + + Pkt.WriteByte(0); + Pkt.WriteByte(a_X); + Pkt.WriteByte(a_Y); + + for (unsigned int i = 0; i < a_Length; ++i) + { + Pkt.WriteByte(a_Colors[i]); + } +} + + + + + +void cProtocol172::SendMapDecorators(int a_ID, const cMapDecoratorList & a_Decorators) +{ + cPacketizer Pkt(*this, 0x34); + Pkt.WriteVarInt(a_ID); + Pkt.WriteShort (1 + (3 * a_Decorators.size())); + + Pkt.WriteByte(1); + + for (cMapDecoratorList::const_iterator it = a_Decorators.begin(); it != a_Decorators.end(); ++it) + { + Pkt.WriteByte((it->GetType() << 4) | (it->GetRot() & 0xf)); + Pkt.WriteByte(it->GetPixelX()); + Pkt.WriteByte(it->GetPixelZ()); + } +} + + + + + +void cProtocol172::SendMapInfo(int a_ID, unsigned int a_Scale) +{ + cPacketizer Pkt(*this, 0x34); + Pkt.WriteVarInt(a_ID); + Pkt.WriteShort (2); + + Pkt.WriteByte(2); + Pkt.WriteByte(a_Scale); +} + + + + + void cProtocol172::SendPickupSpawn(const cPickup & a_Pickup) { @@ -518,9 +687,8 @@ void cProtocol172::SendPlayerAbilities(void) Flags |= 0x04; } Pkt.WriteByte(Flags); - // TODO: Pkt.WriteFloat(m_Client->GetPlayer()->GetMaxFlyingSpeed()); - Pkt.WriteFloat(0.05f); - Pkt.WriteFloat((float)m_Client->GetPlayer()->GetMaxSpeed()); + Pkt.WriteFloat((float)(0.05 * m_Client->GetPlayer()->GetFlyingMaxSpeed())); + Pkt.WriteFloat((float)(0.1 * m_Client->GetPlayer()->GetMaxSpeed())); } @@ -574,13 +742,14 @@ void cProtocol172::SendPlayerMaxSpeed(void) Pkt.WriteInt(m_Client->GetPlayer()->GetUniqueID()); Pkt.WriteInt(1); // Count Pkt.WriteString("generic.movementSpeed"); - Pkt.WriteDouble(0.1); + // The default game speed is 0.1, multiply that value by the relative speed: + Pkt.WriteDouble(0.1 * m_Client->GetPlayer()->GetNormalMaxSpeed()); if (m_Client->GetPlayer()->IsSprinting()) { Pkt.WriteShort(1); // Modifier count Pkt.WriteInt64(0x662a6b8dda3e4c1c); Pkt.WriteInt64(0x881396ea6097278d); // UUID of the modifier - Pkt.WriteDouble(0.3); + Pkt.WriteDouble(m_Client->GetPlayer()->GetSprintingMaxSpeed() - m_Client->GetPlayer()->GetNormalMaxSpeed()); Pkt.WriteByte(2); } else @@ -707,6 +876,46 @@ void cProtocol172::SendExperienceOrb(const cExpOrb & a_ExpOrb) +void cProtocol172::SendScoreboardObjective(const AString & a_Name, const AString & a_DisplayName, Byte a_Mode) +{ + cPacketizer Pkt(*this, 0x3B); + Pkt.WriteString(a_Name); + Pkt.WriteString(a_DisplayName); + Pkt.WriteByte(a_Mode); +} + + + + + +void cProtocol172::SendScoreUpdate(const AString & a_Objective, const AString & a_Player, cObjective::Score a_Score, Byte a_Mode) +{ + cPacketizer Pkt(*this, 0x3C); + Pkt.WriteString(a_Player); + Pkt.WriteByte(a_Mode); + + if (a_Mode != 1) + { + Pkt.WriteString(a_Objective); + Pkt.WriteInt((int) a_Score); + } +} + + + + + +void cProtocol172::SendDisplayObjective(const AString & a_Objective, cScoreboard::eDisplaySlot a_Display) +{ + cPacketizer Pkt(*this, 0x3D); + Pkt.WriteByte((int) a_Display); + Pkt.WriteString(a_Objective); +} + + + + + void cProtocol172::SendSoundEffect(const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch) // a_Src coords are Block * 8 { cPacketizer Pkt(*this, 0x29); // Sound Effect packet @@ -787,8 +996,8 @@ void cProtocol172::SendSpawnObject(const cEntity & a_Entity, char a_ObjectType, Pkt.WriteFPInt(a_Entity.GetPosX()); Pkt.WriteFPInt(a_Entity.GetPosY()); Pkt.WriteFPInt(a_Entity.GetPosZ()); - Pkt.WriteByteAngle(a_Entity.GetYaw()); Pkt.WriteByteAngle(a_Entity.GetPitch()); + Pkt.WriteByteAngle(a_Entity.GetYaw()); Pkt.WriteInt(a_ObjectData); if (a_ObjectData != 0) { @@ -810,8 +1019,8 @@ void cProtocol172::SendSpawnVehicle(const cEntity & a_Vehicle, char a_VehicleTyp Pkt.WriteFPInt(a_Vehicle.GetPosX()); Pkt.WriteFPInt(a_Vehicle.GetPosY()); Pkt.WriteFPInt(a_Vehicle.GetPosZ()); - Pkt.WriteByteAngle(a_Vehicle.GetYaw()); Pkt.WriteByteAngle(a_Vehicle.GetPitch()); + Pkt.WriteByteAngle(a_Vehicle.GetYaw()); Pkt.WriteInt(a_VehicleSubType); if (a_VehicleSubType != 0) { @@ -906,6 +1115,8 @@ void cProtocol172::SendUpdateBlockEntity(cBlockEntity & a_BlockEntity) { 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_HEAD: Action = 4; break; // Update Mobhead entity + case E_BLOCK_FLOWER_POT: Action = 5; break; // Update flower pot default: ASSERT(!"Unhandled or unimplemented BlockEntity update request!"); break; } Pkt.WriteByte(Action); @@ -923,10 +1134,11 @@ void cProtocol172::SendUpdateSign(int a_BlockX, int a_BlockY, int a_BlockZ, cons Pkt.WriteInt(a_BlockX); Pkt.WriteShort((short)a_BlockY); Pkt.WriteInt(a_BlockZ); - Pkt.WriteString(a_Line1); - Pkt.WriteString(a_Line2); - Pkt.WriteString(a_Line3); - Pkt.WriteString(a_Line4); + // Need to send only up to 15 chars, otherwise the client crashes (#598) + Pkt.WriteString(a_Line1.substr(0, 15)); + Pkt.WriteString(a_Line2.substr(0, 15)); + Pkt.WriteString(a_Line3.substr(0, 15)); + Pkt.WriteString(a_Line4.substr(0, 15)); } @@ -1024,8 +1236,33 @@ void cProtocol172::SendWindowProperty(const cWindow & a_Window, short a_Property -void cProtocol172::AddReceivedData(const char * a_Data, int a_Size) +void cProtocol172::AddReceivedData(const char * a_Data, size_t a_Size) { + // Write the incoming data into the comm log file: + if (g_ShouldLogCommIn) + { + 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, " SIZE_T_FMT " (0x" SIZE_T_FMT_HEX ") 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: %d (0x%x) bytes: \n%s\n", + (unsigned)a_Size, (unsigned)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: @@ -1040,12 +1277,14 @@ void cProtocol172::AddReceivedData(const char * a_Data, int a_Size) if (!m_ReceivedData.ReadVarInt(PacketLen)) { // Not enough data - return; + m_ReceivedData.ResetRead(); + break; } if (!m_ReceivedData.CanReadBytes(PacketLen)) { // The full packet hasn't been received yet - return; + m_ReceivedData.ResetRead(); + break; } cByteBuffer bb(PacketLen + 1); VERIFY(m_ReceivedData.ReadToByteBuffer(bb, (int)PacketLen)); @@ -1058,9 +1297,25 @@ void cProtocol172::AddReceivedData(const char * a_Data, int a_Size) if (!bb.ReadVarInt(PacketType)) { // Not enough data - return; + break; } + // Log the packet info into the comm log file: + if (g_ShouldLogCommIn) + { + AString PacketData; + bb.ReadAll(PacketData); + bb.ResetRead(); + bb.ReadVarInt(PacketType); + ASSERT(PacketData.size() > 0); + 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() + ); + } + if (!HandlePacket(bb, PacketType)) { // Unknown packet, already been reported, but without the length. Log the length here: @@ -1077,19 +1332,52 @@ void cProtocol172::AddReceivedData(const char * a_Data, int a_Size) LOGD("Packet contents:\n%s", Out.c_str()); #endif // _DEBUG + // Put a message in the comm log: + if (g_ShouldLogCommIn) + { + m_CommLogFile.Printf("^^^^^^ Unhandled packet ^^^^^^\n\n\n"); + } + return; } if (bb.GetReadableSpace() != 1) { // Read more or less than packet length, report as error - LOGWARNING("Protocol 1.7: Wrong number of bytes read for packet 0x%x, state %d. Read %u bytes, packet contained %u bytes", + LOGWARNING("Protocol 1.7: Wrong number of bytes read for packet 0x%x, state %d. Read " SIZE_T_FMT " 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.Printf("^^^^^^ Wrong number of bytes read for this packet (exp %d left, got " SIZE_T_FMT " left) ^^^^^^\n\n\n", + 1, bb.GetReadableSpace() + ); + m_CommLogFile.Flush(); + } + ASSERT(!"Read wrong number of bytes!"); m_Client->PacketError(PacketType); } - } // while (true) + } // for(ever) + + // Log any leftover bytes into the logfile: + if (g_ShouldLogCommIn && (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("There are " SIZE_T_FMT " (0x" SIZE_T_FMT_HEX ") bytes of non-parse-able data left in the buffer:\n%s", + m_ReceivedData.GetReadableSpace(), m_ReceivedData.GetReadableSpace(), Hex.c_str() + ); + m_CommLogFile.Flush(); + } } @@ -1220,7 +1508,64 @@ void cProtocol172::HandlePacketStatusRequest(cByteBuffer & a_ByteBuffer) void cProtocol172::HandlePacketLoginEncryptionResponse(cByteBuffer & a_ByteBuffer) { - // TODO: Add protocol encryption + short EncKeyLength, EncNonceLength; + a_ByteBuffer.ReadBEShort(EncKeyLength); + AString EncKey; + if (!a_ByteBuffer.ReadString(EncKey, EncKeyLength)) + { + return; + } + a_ByteBuffer.ReadBEShort(EncNonceLength); + 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(); + Int32 DecryptedNonce[MAX_ENC_LEN / sizeof(Int32)]; + int res = rsaDecryptor.Decrypt((const Byte *)EncNonce.data(), EncNonce.size(), (Byte *)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]) != (unsigned)(uintptr_t)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((const Byte *)EncKey.data(), EncKey.size(), DecryptedKey, sizeof(DecryptedKey)); + if (res != 16) + { + LOGD("Bad key length"); + m_Client->Kick("Hacked client"); + return; + } + + StartEncryption(DecryptedKey); + + // Send login success: + { + cPacketizer Pkt(*this, 0x02); // Login success packet + Pkt.WriteString(Printf("%d", m_Client->GetUniqueID())); // TODO: proper UUID + Pkt.WriteString(m_Client->GetUsername()); + } + + m_State = 3; // State = Game + m_Client->HandleLogin(4, m_Client->GetUsername()); } @@ -1232,14 +1577,26 @@ void cProtocol172::HandlePacketLoginStart(cByteBuffer & a_ByteBuffer) AString Username; a_ByteBuffer.ReadVarUTF8String(Username); - // TODO: Protocol encryption should be set up here if not localhost / auth - if (!m_Client->HandleHandshake(Username)) { // The client is not welcome here, they have been sent a Kick packet already return; } + // If auth is required, then send the encryption request: + if (cRoot::Get()->GetServer()->ShouldAuthenticate()) + { + cPacketizer Pkt(*this, 0x01); + Pkt.WriteString(cRoot::Get()->GetServer()->GetServerID()); + const AString & PubKeyDer = cRoot::Get()->GetServer()->GetPublicKeyDER(); + Pkt.WriteShort(PubKeyDer.size()); + Pkt.WriteBuf(PubKeyDer.data(), PubKeyDer.size()); + Pkt.WriteShort(4); + Pkt.WriteInt((int)(intptr_t)this); // Using 'this' as the cryptographic nonce, so that we don't have to generate one each time :) + m_Client->SetUsername(Username); + return; + } + // Send login success: { cPacketizer Pkt(*this, 0x02); // Login success packet @@ -1272,8 +1629,8 @@ void cProtocol172::HandlePacketBlockDig(cByteBuffer & a_ByteBuffer) HANDLE_READ(a_ByteBuffer, ReadBEInt, int, BlockX); HANDLE_READ(a_ByteBuffer, ReadByte, Byte, BlockY); HANDLE_READ(a_ByteBuffer, ReadBEInt, int, BlockZ); - HANDLE_READ(a_ByteBuffer, ReadByte, Byte, Face); - m_Client->HandleLeftClick(BlockX, BlockY, BlockZ, Face, Status); + HANDLE_READ(a_ByteBuffer, ReadChar, char, Face); + m_Client->HandleLeftClick(BlockX, BlockY, BlockZ, static_cast<eBlockFace>(Face), Status); } @@ -1285,14 +1642,14 @@ void cProtocol172::HandlePacketBlockPlace(cByteBuffer & a_ByteBuffer) HANDLE_READ(a_ByteBuffer, ReadBEInt, int, BlockX); HANDLE_READ(a_ByteBuffer, ReadByte, Byte, BlockY); HANDLE_READ(a_ByteBuffer, ReadBEInt, int, BlockZ); - HANDLE_READ(a_ByteBuffer, ReadByte, Byte, Face); + HANDLE_READ(a_ByteBuffer, ReadChar, char, Face); cItem Item; ReadItem(a_ByteBuffer, Item); HANDLE_READ(a_ByteBuffer, ReadByte, Byte, CursorX); HANDLE_READ(a_ByteBuffer, ReadByte, Byte, CursorY); HANDLE_READ(a_ByteBuffer, ReadByte, Byte, CursorZ); - m_Client->HandleRightClick(BlockX, BlockY, BlockZ, Face, CursorX, CursorY, CursorZ, m_Client->GetPlayer()->GetEquippedItem()); + m_Client->HandleRightClick(BlockX, BlockY, BlockZ, static_cast<eBlockFace>(Face), CursorX, CursorY, CursorZ, m_Client->GetPlayer()->GetEquippedItem()); } @@ -1317,6 +1674,8 @@ void cProtocol172::HandlePacketClientSettings(cByteBuffer & a_ByteBuffer) HANDLE_READ(a_ByteBuffer, ReadByte, Byte, ChatColors); HANDLE_READ(a_ByteBuffer, ReadByte, Byte, Difficulty); HANDLE_READ(a_ByteBuffer, ReadByte, Byte, ShowCape); + + m_Client->SetLocale(Locale); // TODO: handle in m_Client } @@ -1374,7 +1733,15 @@ void cProtocol172::HandlePacketEntityAction(cByteBuffer & a_ByteBuffer) HANDLE_READ(a_ByteBuffer, ReadBEInt, int, PlayerID); HANDLE_READ(a_ByteBuffer, ReadByte, Byte, Action); HANDLE_READ(a_ByteBuffer, ReadBEInt, int, JumpBoost); - m_Client->HandleEntityAction(PlayerID, Action); + + switch (Action) + { + case 1: m_Client->HandleEntityCrouch(PlayerID, true); break; // Crouch + case 2: m_Client->HandleEntityCrouch(PlayerID, false); break; // Uncrouch + case 3: m_Client->HandleEntityLeaveBed(PlayerID); break; // Leave Bed + case 4: m_Client->HandleEntitySprinting(PlayerID, true); break; // Start sprinting + case 5: m_Client->HandleEntitySprinting(PlayerID, false); break; // Stop sprinting + } } @@ -1637,15 +2004,15 @@ void cProtocol172::WritePacket(cByteBuffer & a_Packet) -void cProtocol172::SendData(const char * a_Data, int a_Size) +void cProtocol172::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) + Byte Encrypted[8192]; // Larger buffer, we may be sending lots of data (chunks) while (a_Size > 0) { - int NumBytes = (a_Size > sizeof(Encrypted)) ? sizeof(Encrypted) : a_Size; - m_Encryptor.ProcessData(Encrypted, (byte *)a_Data, NumBytes); + size_t NumBytes = (a_Size > sizeof(Encrypted)) ? sizeof(Encrypted) : a_Size; + m_Encryptor.ProcessData(Encrypted, (Byte *)a_Data, NumBytes); m_Client->SendData((const char *)Encrypted, NumBytes); a_Size -= NumBytes; a_Data += NumBytes; @@ -1711,7 +2078,7 @@ void cProtocol172::ParseItemMetadata(cItem & a_Item, const AString & a_Metadata) { AString HexDump; CreateHexDump(HexDump, a_Metadata.data(), a_Metadata.size(), 16); - LOGWARNING("Cannot unGZIP item metadata (%u bytes):\n%s", a_Metadata.size(), HexDump.c_str()); + LOGWARNING("Cannot unGZIP item metadata (" SIZE_T_FMT " bytes):\n%s", a_Metadata.size(), HexDump.c_str()); return; } @@ -1721,43 +2088,54 @@ void cProtocol172::ParseItemMetadata(cItem & a_Item, const AString & a_Metadata) { AString HexDump; CreateHexDump(HexDump, Uncompressed.data(), Uncompressed.size(), 16); - LOGWARNING("Cannot parse NBT item metadata: (%u bytes)\n%s", Uncompressed.size(), HexDump.c_str()); + LOGWARNING("Cannot parse NBT item metadata: (" SIZE_T_FMT " bytes)\n%s", Uncompressed.size(), HexDump.c_str()); return; } // Load enchantments and custom display names from the NBT data: for (int tag = NBT.GetFirstChild(NBT.GetRoot()); tag >= 0; tag = NBT.GetNextSibling(tag)) { - if ( - (NBT.GetType(tag) == TAG_List) && - ( - (NBT.GetName(tag) == "ench") || - (NBT.GetName(tag) == "StoredEnchantments") - ) - ) - { - EnchantmentSerializer::ParseFromNBT(a_Item.m_Enchantments, NBT, tag); - } - else if ((NBT.GetType(tag) == TAG_Compound) && (NBT.GetName(tag) == "display")) // Custom name and lore tag + AString TagName = NBT.GetName(tag); + switch (NBT.GetType(tag)) { - for (int displaytag = NBT.GetFirstChild(tag); displaytag >= 0; displaytag = NBT.GetNextSibling(displaytag)) + case TAG_List: { - if ((NBT.GetType(displaytag) == TAG_String) && (NBT.GetName(displaytag) == "Name")) // Custon name tag + if ((TagName == "ench") || (TagName == "StoredEnchantments")) // Enchantments tags { - a_Item.m_CustomName = NBT.GetString(displaytag); + EnchantmentSerializer::ParseFromNBT(a_Item.m_Enchantments, NBT, tag); } - else if ((NBT.GetType(displaytag) == TAG_List) && (NBT.GetName(displaytag) == "Lore")) // Lore tag + break; + } + case TAG_Compound: + { + if (TagName == "display") // Custom name and lore tag { - AString Lore; - - for (int loretag = NBT.GetFirstChild(displaytag); loretag >= 0; loretag = NBT.GetNextSibling(loretag)) // Loop through array of strings + for (int displaytag = NBT.GetFirstChild(tag); displaytag >= 0; displaytag = NBT.GetNextSibling(displaytag)) { - AppendPrintf(Lore, "%s`", NBT.GetString(loretag).c_str()); // Append the lore with a newline, used internally by MCS to display a new line in the client; don't forget to c_str ;) + if ((NBT.GetType(displaytag) == TAG_String) && (NBT.GetName(displaytag) == "Name")) // Custon name tag + { + a_Item.m_CustomName = NBT.GetString(displaytag); + } + else if ((NBT.GetType(displaytag) == TAG_List) && (NBT.GetName(displaytag) == "Lore")) // Lore tag + { + AString Lore; + + for (int loretag = NBT.GetFirstChild(displaytag); loretag >= 0; loretag = NBT.GetNextSibling(loretag)) // Loop through array of strings + { + AppendPrintf(Lore, "%s`", NBT.GetString(loretag).c_str()); // Append the lore with a newline, used internally by MCS to display a new line in the client; don't forget to c_str ;) + } + + a_Item.m_Lore = Lore; + } } - - a_Item.m_Lore = Lore; } + else if ((TagName == "Fireworks") || (TagName == "Explosion")) + { + cFireworkItem::ParseFromNBT(a_Item.m_FireworkItem, NBT, tag, (ENUM_ITEM_ID)a_Item.m_ItemType); + } + break; } + default: LOGD("Unimplemented NBT data when parsing!"); break; } } } @@ -1766,6 +2144,106 @@ void cProtocol172::ParseItemMetadata(cItem & a_Item, const AString & a_Metadata) +void cProtocol172::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; + const AString & ServerID = cRoot::Get()->GetServer()->GetServerID(); + Checksum.Update((const Byte *)ServerID.c_str(), ServerID.length()); + Checksum.Update(a_Key, 16); + Checksum.Update((const Byte *)cRoot::Get()->GetServer()->GetPublicKeyDER().data(), cRoot::Get()->GetServer()->GetPublicKeyDER().size()); + Byte Digest[20]; + Checksum.Finalize(Digest); + cSHA1Checksum::DigestToJava(Digest, m_AuthServerID); +} + + + + + +void cProtocol172::AddChatPartStyle(Json::Value & a_Value, const AString & a_PartStyle) +{ + size_t len = a_PartStyle.length(); + for (size_t i = 0; i < len; i++) + { + switch (a_PartStyle[i]) + { + case 'b': + { + // bold + a_Value["bold"] = Json::Value(true); + break; + } + + case 'i': + { + // italic + a_Value["italic"] = Json::Value(true); + break; + } + + case 'u': + { + // Underlined + a_Value["underlined"] = Json::Value(true); + break; + } + + case 's': + { + // strikethrough + a_Value["strikethrough"] = Json::Value(true); + break; + } + + case 'o': + { + // obfuscated + a_Value["obfuscated"] = Json::Value(true); + break; + } + + case '@': + { + // Color, specified by the next char: + i++; + if (i >= len) + { + // String too short, didn't contain a color + break; + } + switch (a_PartStyle[i]) + { + case '0': a_Value["color"] = Json::Value("black"); break; + case '1': a_Value["color"] = Json::Value("dark_blue"); break; + case '2': a_Value["color"] = Json::Value("dark_green"); break; + case '3': a_Value["color"] = Json::Value("dark_aqua"); break; + case '4': a_Value["color"] = Json::Value("dark_red"); break; + case '5': a_Value["color"] = Json::Value("dark_purple"); break; + case '6': a_Value["color"] = Json::Value("gold"); break; + case '7': a_Value["color"] = Json::Value("gray"); break; + case '8': a_Value["color"] = Json::Value("dark_gray"); break; + case '9': a_Value["color"] = Json::Value("blue"); break; + case 'a': a_Value["color"] = Json::Value("green"); break; + case 'b': a_Value["color"] = Json::Value("aqua"); break; + case 'c': a_Value["color"] = Json::Value("red"); break; + case 'd': a_Value["color"] = Json::Value("light_purple"); break; + case 'e': a_Value["color"] = Json::Value("yellow"); break; + case 'f': a_Value["color"] = Json::Value("white"); break; + } // switch (color) + } // case '@' + } // switch (Style[i]) + } // for i - a_PartStyle[] +} + + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // cProtocol172::cPacketizer: @@ -1784,6 +2262,17 @@ cProtocol172::cPacketizer::~cPacketizer() m_Out.ReadAll(DataToSend); m_Protocol.SendData(DataToSend.data(), DataToSend.size()); m_Out.CommitRead(); + + // Log the comm into logfile: + if (g_ShouldLogCommOut) + { + AString Hex; + ASSERT(DataToSend.size() > 0); + CreateHexDump(Hex, DataToSend.data() + 1, DataToSend.size() - 1, 16); + m_Protocol.m_CommLogFile.Printf("Outgoing packet: type %d (0x%x), length %u (0x%x), state %d. Payload:\n%s\n", + DataToSend[0], DataToSend[0], PacketLen, PacketLen, m_Protocol.m_State, Hex.c_str() + ); + } } @@ -1810,7 +2299,7 @@ void cProtocol172::cPacketizer::WriteItem(const cItem & a_Item) WriteByte (a_Item.m_ItemCount); WriteShort(a_Item.m_ItemDamage); - if (a_Item.m_Enchantments.IsEmpty() && a_Item.IsBothNameAndLoreEmpty()) + if (a_Item.m_Enchantments.IsEmpty() && a_Item.IsBothNameAndLoreEmpty() && (a_Item.m_ItemType != E_ITEM_FIREWORK_ROCKET) && (a_Item.m_ItemType != E_ITEM_FIREWORK_STAR)) { WriteShort(-1); return; @@ -1849,6 +2338,10 @@ void cProtocol172::cPacketizer::WriteItem(const cItem & a_Item) } Writer.EndCompound(); } + if ((a_Item.m_ItemType == E_ITEM_FIREWORK_ROCKET) || (a_Item.m_ItemType == E_ITEM_FIREWORK_STAR)) + { + cFireworkItem::WriteToNBTCompound(a_Item.m_FireworkItem, Writer, (ENUM_ITEM_ID)a_Item.m_ItemType); + } Writer.Finish(); AString Compressed; CompressStringGZIP(Writer.GetResult().data(), Writer.GetResult().size(), Compressed); @@ -1890,6 +2383,31 @@ void cProtocol172::cPacketizer::WriteBlockEntity(const cBlockEntity & a_BlockEnt } break; } + case E_BLOCK_HEAD: + { + cMobHeadEntity & MobHeadEntity = (cMobHeadEntity &)a_BlockEntity; + + Writer.AddInt("x", MobHeadEntity.GetPosX()); + Writer.AddInt("y", MobHeadEntity.GetPosY()); + Writer.AddInt("z", MobHeadEntity.GetPosZ()); + Writer.AddByte("SkullType", MobHeadEntity.GetType() & 0xFF); + Writer.AddByte("Rot", MobHeadEntity.GetRotation() & 0xFF); + Writer.AddString("ExtraType", MobHeadEntity.GetOwner().c_str()); + Writer.AddString("id", "Skull"); // "Tile Entity ID" - MC wiki; vanilla server always seems to send this though + break; + } + case E_BLOCK_FLOWER_POT: + { + cFlowerPotEntity & FlowerPotEntity = (cFlowerPotEntity &)a_BlockEntity; + + Writer.AddInt("x", FlowerPotEntity.GetPosX()); + Writer.AddInt("y", FlowerPotEntity.GetPosY()); + Writer.AddInt("z", FlowerPotEntity.GetPosZ()); + Writer.AddInt("Item", (Int32) FlowerPotEntity.GetItem().m_ItemType); + Writer.AddInt("Data", (Int32) FlowerPotEntity.GetItem().m_ItemDamage); + Writer.AddString("id", "FlowerPot"); // "Tile Entity ID" - MC wiki; vanilla server always seems to send this though + break; + } default: break; } @@ -2000,10 +2518,22 @@ void cProtocol172::cPacketizer::WriteEntityMetadata(const cEntity & a_Entity) } case cEntity::etProjectile: { - if (((cProjectileEntity &)a_Entity).GetProjectileKind() == cProjectileEntity::pkArrow) + cProjectileEntity & Projectile = (cProjectileEntity &)a_Entity; + switch (Projectile.GetProjectileKind()) { - WriteByte(0x10); - WriteByte(((const cArrowEntity &)a_Entity).IsCritical() ? 1 : 0); + case cProjectileEntity::pkArrow: + { + WriteByte(0x10); + WriteByte(((const cArrowEntity &)a_Entity).IsCritical() ? 1 : 0); + break; + } + case cProjectileEntity::pkFirework: + { + WriteByte(0xA8); + WriteItem(((const cFireworkEntity &)a_Entity).GetItem()); + break; + } + default: break; } break; } @@ -2012,6 +2542,16 @@ void cProtocol172::cPacketizer::WriteEntityMetadata(const cEntity & a_Entity) WriteMobMetadata((const cMonster &)a_Entity); break; } + case cEntity::etItemFrame: + { + cItemFrame & Frame = (cItemFrame &)a_Entity; + WriteByte(0xA2); + WriteItem(Frame.GetItem()); + WriteByte(0x3); + WriteByte(Frame.GetRotation()); + break; + } + default: break; } } @@ -2136,6 +2676,15 @@ void cProtocol172::cPacketizer::WriteMobMetadata(const cMonster & a_Mob) WriteByte(((const cWitch &)a_Mob).IsAngry() ? 1 : 0); break; } + + case cMonster::mtWither: + { + WriteByte(0x54); // Int at index 20 + WriteInt(((const cWither &)a_Mob).GetNumInvulnerableTicks()); + WriteByte(0x66); // Float at index 6 + WriteFloat((float)(a_Mob.GetHealth())); + break; + } case cMonster::mtSlime: { @@ -2211,7 +2760,8 @@ void cProtocol172::cPacketizer::WriteEntityProperties(const cEntity & a_Entity) WriteInt(0); return; } - const cMonster & Mob = (const cMonster &)a_Entity; + + //const cMonster & Mob = (const cMonster &)a_Entity; // TODO: Send properties and modifiers based on the mob type diff --git a/src/Protocol/Protocol17x.h b/src/Protocol/Protocol17x.h index 1f3039edb..a1ad1f049 100644 --- a/src/Protocol/Protocol17x.h +++ b/src/Protocol/Protocol17x.h @@ -26,36 +26,46 @@ Declares the 1.7.x protocol classes: #pragma warning(disable:4702) #endif -#include "cryptopp/modes.h" -#include "cryptopp/aes.h" - #ifdef _MSC_VER #pragma warning(pop) #endif +#include "../Crypto.h" + + + + + +// fwd: +namespace Json +{ + class Value; +} + class cProtocol172 : - public cProtocol // TODO + public cProtocol { - typedef cProtocol super; // TODO + typedef cProtocol super; public: cProtocol172(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, int a_Size) override; + /** Called when client sends some data: */ + virtual void DataReceived(const char * a_Data, size_t a_Size) override; - /// Sending stuff to clients (alphabetically sorted): + /** 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 (int 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 SendChat (const AString & a_Message) override; + virtual void SendChat (const cCompositeChat & a_Message) override; virtual void SendChunkData (int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer) override; virtual void SendCollectPickup (const cPickup & a_Pickup, const cPlayer & a_Player) override; virtual void SendDestroyEntity (const cEntity & a_Entity) override; @@ -77,6 +87,10 @@ public: virtual void SendInventorySlot (char a_WindowID, short a_SlotNum, const cItem & a_Item) override; virtual void SendKeepAlive (int a_PingID) override; virtual void SendLogin (const cPlayer & a_Player, const cWorld & a_World) override; + virtual void SendMapColumn (int a_ID, int a_X, int a_Y, const Byte * a_Colors, unsigned int a_Length) override; + virtual void SendMapDecorators (int a_ID, const cMapDecoratorList & a_Decorators) override; + virtual void SendMapInfo (int a_ID, unsigned int a_Scale) 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; @@ -92,6 +106,9 @@ public: virtual void SendSoundEffect (const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch) override; // a_Src coords are Block * 8 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; virtual void SendSoundParticleEffect (int 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; @@ -115,7 +132,7 @@ public: protected: - /// Composes individual packets in the protocol's m_OutPacketBuffer; sends them upon being destructed + /** Composes individual packets in the protocol's m_OutPacketBuffer; sends them upon being destructed */ class cPacketizer { public: @@ -179,7 +196,7 @@ protected: m_Out.WriteVarUTF8String(a_Value); } - void WriteBuf(const char * a_Data, int a_Size) + void WriteBuf(const char * a_Data, size_t a_Size) { m_Out.Write(a_Data, a_Size); } @@ -204,25 +221,29 @@ protected: AString m_AuthServerID; - /// State of the protocol. 1 = status, 2 = login, 3 = game + /** State of the protocol. 1 = status, 2 = login, 3 = game */ UInt32 m_State; - /// Buffer for the received data + /** Buffer for the received data */ cByteBuffer m_ReceivedData; - /// Buffer for composing the outgoing packets, through cPacketizer + /** Buffer for composing the outgoing packets, through cPacketizer */ cByteBuffer m_OutPacketBuffer; - /// Buffer for composing packet length (so that each cPacketizer instance doesn't allocate a new cPacketBuffer) + /** Buffer for composing packet length (so that each cPacketizer instance doesn't allocate a new cPacketBuffer) */ cByteBuffer m_OutPacketLenBuffer; bool m_IsEncrypted; - CryptoPP::CFB_Mode<CryptoPP::AES>::Decryption m_Decryptor; - CryptoPP::CFB_Mode<CryptoPP::AES>::Encryption m_Encryptor; + + cAESCFBDecryptor m_Decryptor; + cAESCFBEncryptor 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, int a_Size); + /** Adds the received (unencrypted) data to m_ReceivedData, parses complete packets */ + void AddReceivedData(const char * a_Data, size_t a_Size); /** 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 @@ -263,19 +284,24 @@ protected: void HandlePacketWindowClose (cByteBuffer & a_ByteBuffer); - /// Writes an entire packet into the output stream. a_Packet is expected to start with the packet type; data length is prepended here. + /** Writes an entire packet into the output stream. a_Packet is expected to start with the packet type; data length is prepended here. */ void WritePacket(cByteBuffer & a_Packet); - /// Sends the data to the client, encrypting them if needed. - virtual void SendData(const char * a_Data, int a_Size) override; + /** Sends the data to the client, encrypting them if needed. */ + virtual void SendData(const char * a_Data, size_t a_Size) 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 + /** Reads an item out of the received data, sets a_Item to the values read. Returns false if not enough received data */ bool ReadItem(cByteBuffer & a_ByteBuffer, cItem & a_Item); - /// Parses item metadata as read by ReadItem(), into the item enchantments. + /** 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); + + /** Adds the chat part's style (represented by the part's stylestring) into the Json object. */ + void AddChatPartStyle(Json::Value & a_Value, const AString & a_PartStyle); } ; diff --git a/src/Protocol/ProtocolRecognizer.cpp b/src/Protocol/ProtocolRecognizer.cpp index 5524af136..3f7d7b254 100644 --- a/src/Protocol/ProtocolRecognizer.cpp +++ b/src/Protocol/ProtocolRecognizer.cpp @@ -68,7 +68,7 @@ AString cProtocolRecognizer::GetVersionTextFromInt(int a_ProtocolVersion) -void cProtocolRecognizer::DataReceived(const char * a_Data, int a_Size) +void cProtocolRecognizer::DataReceived(const char * a_Data, size_t a_Size) { if (m_Protocol == NULL) { @@ -159,6 +159,16 @@ void cProtocolRecognizer::SendChat(const AString & a_Message) +void cProtocolRecognizer::SendChat(const cCompositeChat & a_Message) +{ + ASSERT(m_Protocol != NULL); + m_Protocol->SendChat(a_Message); +} + + + + + void cProtocolRecognizer::SendChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer) { ASSERT(m_Protocol != NULL); @@ -386,6 +396,36 @@ void cProtocolRecognizer::SendLogin(const cPlayer & a_Player, const cWorld & a_W +void cProtocolRecognizer::SendMapColumn(int a_ID, int a_X, int a_Y, const Byte * a_Colors, unsigned int a_Length) +{ + ASSERT(m_Protocol != NULL); + m_Protocol->SendMapColumn(a_ID, a_X, a_Y, a_Colors, a_Length); +} + + + + + +void cProtocolRecognizer::SendMapDecorators(int a_ID, const cMapDecoratorList & a_Decorators) +{ + ASSERT(m_Protocol != NULL); + m_Protocol->SendMapDecorators(a_ID, a_Decorators); +} + + + + + +void cProtocolRecognizer::SendMapInfo(int a_ID, unsigned int a_Scale) +{ + ASSERT(m_Protocol != NULL); + m_Protocol->SendMapInfo(a_ID, a_Scale); +} + + + + + void cProtocolRecognizer::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_ParticleAmmount) { ASSERT(m_Protocol != NULL); @@ -395,6 +435,14 @@ void cProtocolRecognizer::SendParticleEffect(const AString & a_ParticleName, flo +void cProtocolRecognizer::SendPaintingSpawn(const cPainting & a_Painting) +{ + m_Protocol->SendPaintingSpawn(a_Painting); +} + + + + void cProtocolRecognizer::SendPickupSpawn(const cPickup & a_Pickup) { @@ -526,6 +574,36 @@ void cProtocolRecognizer::SendExperienceOrb(const cExpOrb & a_ExpOrb) +void cProtocolRecognizer::SendScoreboardObjective(const AString & a_Name, const AString & a_DisplayName, Byte a_Mode) +{ + ASSERT(m_Protocol != NULL); + m_Protocol->SendScoreboardObjective(a_Name, a_DisplayName, a_Mode); +} + + + + + +void cProtocolRecognizer::SendScoreUpdate(const AString & a_Objective, const AString & a_Player, cObjective::Score a_Score, Byte a_Mode) +{ + ASSERT(m_Protocol != NULL); + m_Protocol->SendScoreUpdate(a_Objective, a_Player, a_Score, a_Mode); +} + + + + + +void cProtocolRecognizer::SendDisplayObjective(const AString & a_Objective, cScoreboard::eDisplaySlot a_Display) +{ + ASSERT(m_Protocol != NULL); + m_Protocol->SendDisplayObjective(a_Objective, a_Display); +} + + + + + void cProtocolRecognizer::SendSoundEffect(const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch) { ASSERT(m_Protocol != NULL); @@ -716,7 +794,7 @@ AString cProtocolRecognizer::GetAuthServerID(void) -void cProtocolRecognizer::SendData(const char * a_Data, int a_Size) +void cProtocolRecognizer::SendData(const char * a_Data, size_t a_Size) { // This is used only when handling the server ping m_Client->SendData(a_Data, a_Size); @@ -776,7 +854,7 @@ bool cProtocolRecognizer::TryRecognizeProtocol(void) // This must be a lengthed protocol, try if it has the entire initial handshake packet: m_Buffer.ResetRead(); UInt32 PacketLen; - UInt32 ReadSoFar = m_Buffer.GetReadableSpace(); + UInt32 ReadSoFar = (UInt32)m_Buffer.GetReadableSpace(); if (!m_Buffer.ReadVarInt(PacketLen)) { // Not enough bytes for the packet length, keep waiting @@ -807,7 +885,7 @@ bool cProtocolRecognizer::TryRecognizeLengthlessProtocol(void) } switch (ch) { - case PROTO_VERSION_1_3_2: + case PROTO_VERSION_1_3_2: { m_Protocol = new cProtocol132(m_Client); return true; @@ -853,7 +931,7 @@ bool cProtocolRecognizer::TryRecognizeLengthlessProtocol(void) bool cProtocolRecognizer::TryRecognizeLengthedProtocol(UInt32 a_PacketLengthRemaining) { UInt32 PacketType; - UInt32 NumBytesRead = m_Buffer.GetReadableSpace(); + UInt32 NumBytesRead = (UInt32)m_Buffer.GetReadableSpace(); if (!m_Buffer.ReadVarInt(PacketType)) { return false; @@ -884,7 +962,7 @@ bool cProtocolRecognizer::TryRecognizeLengthedProtocol(UInt32 a_PacketLengthRema m_Buffer.ReadBEShort(ServerPort); m_Buffer.ReadVarInt(NextState); m_Buffer.CommitRead(); - m_Protocol = new cProtocol172(m_Client, ServerAddress, ServerPort, NextState); + m_Protocol = new cProtocol172(m_Client, ServerAddress, (UInt16)ServerPort, NextState); return true; } } @@ -935,7 +1013,7 @@ void cProtocolRecognizer::SendLengthlessServerPing(void) m_Buffer.ResetRead(); if (m_Buffer.CanReadBytes(2)) { - byte val; + Byte val; m_Buffer.ReadByte(val); // Packet type - Serverlist ping m_Buffer.ReadByte(val); // 0x01 magic value ASSERT(val == 0x01); diff --git a/src/Protocol/ProtocolRecognizer.h b/src/Protocol/ProtocolRecognizer.h index 2dccace6e..072d7c2d2 100644 --- a/src/Protocol/ProtocolRecognizer.h +++ b/src/Protocol/ProtocolRecognizer.h @@ -18,7 +18,7 @@ // Adjust these if a new protocol is added or an old one is removed: -#define MCS_CLIENT_VERSIONS "1.2.4, 1.2.5, 1.3.1, 1.3.2, 1.4.2, 1.4.4, 1.4.5, 1.4.6, 1.4.7, 1.5, 1.5.1, 1.5.2, 1.6.1, 1.6.2, 1.6.3, 1.6.4, 1.7.2" +#define MCS_CLIENT_VERSIONS "1.2.4, 1.2.5, 1.3.1, 1.3.2, 1.4.2, 1.4.4, 1.4.5, 1.4.6, 1.4.7, 1.5, 1.5.1, 1.5.2, 1.6.1, 1.6.2, 1.6.3, 1.6.4, 1.7.2, 1.7.4" #define MCS_PROTOCOL_VERSIONS "29, 39, 47, 49, 51, 60, 61, 73, 74, 77, 78, 4" @@ -59,7 +59,7 @@ public: static AString GetVersionTextFromInt(int a_ProtocolVersion); /// Called when client sends some data: - virtual void DataReceived(const char * a_Data, int a_Size) override; + 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; @@ -68,6 +68,7 @@ public: 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 SendChat (const AString & a_Message) override; + virtual void SendChat (const cCompositeChat & a_Message) override; virtual void SendChunkData (int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer) override; virtual void SendCollectPickup (const cPickup & a_Pickup, const cPlayer & a_Player) override; virtual void SendDestroyEntity (const cEntity & a_Entity) override; @@ -89,7 +90,11 @@ public: virtual void SendInventorySlot (char a_WindowID, short a_SlotNum, const cItem & a_Item) override; virtual void SendKeepAlive (int a_PingID) override; virtual void SendLogin (const cPlayer & a_Player, const cWorld & a_World) override; + virtual void SendMapColumn (int a_ID, int a_X, int a_Y, const Byte * a_Colors, unsigned int a_Length) override; + virtual void SendMapDecorators (int a_ID, const cMapDecoratorList & a_Decorators) override; + virtual void SendMapInfo (int a_ID, unsigned int a_Scale) 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_ParticleAmmount) 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; @@ -103,6 +108,9 @@ public: virtual void SendRespawn (void) 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; virtual void SendSoundEffect (const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch) override; virtual void SendSoundParticleEffect (int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data) override; virtual void SendSpawnFallingBlock (const cFallingBlock & a_FallingBlock) override; @@ -125,7 +133,7 @@ public: virtual AString GetAuthServerID(void) override; - virtual void SendData(const char * a_Data, int a_Size) override; + virtual void SendData(const char * a_Data, size_t a_Size) override; protected: cProtocol * m_Protocol; //< The recognized protocol |