diff options
Diffstat (limited to '')
-rw-r--r-- | source/Protocol/ChunkDataSerializer.cpp | 352 | ||||
-rw-r--r-- | source/Protocol/ChunkDataSerializer.h | 96 | ||||
-rw-r--r-- | source/Protocol/Protocol.h | 384 | ||||
-rw-r--r-- | source/Protocol/Protocol125.cpp | 3272 | ||||
-rw-r--r-- | source/Protocol/Protocol125.h | 304 | ||||
-rw-r--r-- | source/Protocol/Protocol132.cpp | 1804 | ||||
-rw-r--r-- | source/Protocol/Protocol132.h | 200 | ||||
-rw-r--r-- | source/Protocol/Protocol14x.cpp | 506 | ||||
-rw-r--r-- | source/Protocol/Protocol14x.h | 126 | ||||
-rw-r--r-- | source/Protocol/Protocol15x.cpp | 274 | ||||
-rw-r--r-- | source/Protocol/Protocol15x.h | 76 | ||||
-rw-r--r-- | source/Protocol/Protocol16x.cpp | 490 | ||||
-rw-r--r-- | source/Protocol/Protocol16x.h | 146 | ||||
-rw-r--r-- | source/Protocol/ProtocolRecognizer.cpp | 1542 | ||||
-rw-r--r-- | source/Protocol/ProtocolRecognizer.h | 260 |
15 files changed, 4916 insertions, 4916 deletions
diff --git a/source/Protocol/ChunkDataSerializer.cpp b/source/Protocol/ChunkDataSerializer.cpp index 7af07f331..2a9230fee 100644 --- a/source/Protocol/ChunkDataSerializer.cpp +++ b/source/Protocol/ChunkDataSerializer.cpp @@ -1,176 +1,176 @@ -
-// ChunkDataSerializer.cpp
-
-// Implements the cChunkDataSerializer class representing the object that can:
-// - serialize chunk data to different protocol versions
-// - cache such serialized data for multiple clients
-
-#include "Globals.h"
-#include "ChunkDataSerializer.h"
-#include "zlib.h"
-
-
-
-
-cChunkDataSerializer::cChunkDataSerializer(
- const cChunkDef::BlockTypes & a_BlockTypes,
- const cChunkDef::BlockNibbles & a_BlockMetas,
- const cChunkDef::BlockNibbles & a_BlockLight,
- const cChunkDef::BlockNibbles & a_BlockSkyLight,
- const unsigned char * a_BiomeData
-) :
- m_BlockTypes(a_BlockTypes),
- m_BlockMetas(a_BlockMetas),
- m_BlockLight(a_BlockLight),
- m_BlockSkyLight(a_BlockSkyLight),
- m_BiomeData(a_BiomeData)
-{
-}
-
-
-
-
-const AString & cChunkDataSerializer::Serialize(int a_Version)
-{
- Serializations::const_iterator itr = m_Serializations.find(a_Version);
- if (itr != m_Serializations.end())
- {
- return itr->second;
- }
-
- AString data;
- switch (a_Version)
- {
- case RELEASE_1_2_5: Serialize29(data); break;
- case RELEASE_1_3_2: Serialize39(data); break;
- // TODO: Other protocol versions may serialize the data differently; implement here
-
- default:
- {
- LOGERROR("cChunkDataSerializer::Serialize(): Unknown version: %d", a_Version);
- ASSERT(!"Unknown chunk data serialization version");
- break;
- }
- }
- m_Serializations[a_Version] = data;
- return m_Serializations[a_Version];
-}
-
-
-
-
-
-void cChunkDataSerializer::Serialize29(AString & a_Data)
-{
- // TODO: Do not copy data and then compress it; rather, compress partial blocks of data (zlib *can* stream)
-
- const int BiomeDataSize = cChunkDef::Width * cChunkDef::Width;
- const int MetadataOffset = sizeof(m_BlockTypes);
- const int BlockLightOffset = MetadataOffset + sizeof(m_BlockMetas);
- const int SkyLightOffset = BlockLightOffset + sizeof(m_BlockLight);
- const int BiomeOffset = SkyLightOffset + sizeof(m_BlockSkyLight);
- const int DataSize = BiomeOffset + BiomeDataSize;
-
- // Temporary buffer for the composed data:
- char AllData [DataSize];
-
- memcpy(AllData, m_BlockTypes, sizeof(m_BlockTypes));
- memcpy(AllData + MetadataOffset, m_BlockMetas, sizeof(m_BlockMetas));
- memcpy(AllData + BlockLightOffset, m_BlockLight, sizeof(m_BlockLight));
- memcpy(AllData + SkyLightOffset, m_BlockSkyLight, sizeof(m_BlockSkyLight));
- memcpy(AllData + BiomeOffset, m_BiomeData, BiomeDataSize);
-
- // Compress the data:
- // In order not to use allocation, use a fixed-size buffer, with the size
- // that uses the same calculation as compressBound():
- const uLongf CompressedMaxSize = DataSize + (DataSize >> 12) + (DataSize >> 14) + (DataSize >> 25) + 16;
- char CompressedBlockData[CompressedMaxSize];
-
- uLongf CompressedSize = compressBound(DataSize);
-
- // Run-time check that our compile-time guess about CompressedMaxSize was enough:
- ASSERT(CompressedSize <= CompressedMaxSize);
-
- compress2((Bytef*)CompressedBlockData, &CompressedSize, (const Bytef*)AllData, sizeof(AllData), Z_DEFAULT_COMPRESSION);
-
- // Now put all those data into a_Data:
-
- // "Ground-up continuous", or rather, "biome data present" flag:
- a_Data.push_back('\x01');
-
- // Two bitmaps; we're aways sending the full chunk with no additional data, so the bitmaps are 0xffff and 0, respectively
- // Also, no endian flipping is needed because of the const values
- unsigned short BitMap1 = 0xffff;
- unsigned short BitMap2 = 0;
- a_Data.append((const char *)&BitMap1, sizeof(short));
- a_Data.append((const char *)&BitMap2, sizeof(short));
-
- Int32 CompressedSizeBE = htonl(CompressedSize);
- a_Data.append((const char *)&CompressedSizeBE, sizeof(CompressedSizeBE));
-
- Int32 UnusedInt32 = 0;
- a_Data.append((const char *)&UnusedInt32, sizeof(UnusedInt32));
-
- a_Data.append(CompressedBlockData, CompressedSize);
-}
-
-
-
-
-
-void cChunkDataSerializer::Serialize39(AString & a_Data)
-{
- // TODO: Do not copy data and then compress it; rather, compress partial blocks of data (zlib *can* stream)
-
- const int BiomeDataSize = cChunkDef::Width * cChunkDef::Width;
- const int MetadataOffset = sizeof(m_BlockTypes);
- const int BlockLightOffset = MetadataOffset + sizeof(m_BlockMetas);
- const int SkyLightOffset = BlockLightOffset + sizeof(m_BlockLight);
- const int BiomeOffset = SkyLightOffset + sizeof(m_BlockSkyLight);
- const int DataSize = BiomeOffset + BiomeDataSize;
-
- // Temporary buffer for the composed data:
- char AllData [DataSize];
-
- memcpy(AllData, m_BlockTypes, sizeof(m_BlockTypes));
- memcpy(AllData + MetadataOffset, m_BlockMetas, sizeof(m_BlockMetas));
- memcpy(AllData + BlockLightOffset, m_BlockLight, sizeof(m_BlockLight));
- memcpy(AllData + SkyLightOffset, m_BlockSkyLight, sizeof(m_BlockSkyLight));
- memcpy(AllData + BiomeOffset, m_BiomeData, BiomeDataSize);
-
- // Compress the data:
- // In order not to use allocation, use a fixed-size buffer, with the size
- // that uses the same calculation as compressBound():
- const uLongf CompressedMaxSize = DataSize + (DataSize >> 12) + (DataSize >> 14) + (DataSize >> 25) + 16;
- char CompressedBlockData[CompressedMaxSize];
-
- uLongf CompressedSize = compressBound(DataSize);
-
- // Run-time check that our compile-time guess about CompressedMaxSize was enough:
- ASSERT(CompressedSize <= CompressedMaxSize);
-
- compress2((Bytef*)CompressedBlockData, &CompressedSize, (const Bytef*)AllData, sizeof(AllData), Z_DEFAULT_COMPRESSION);
-
- // Now put all those data into a_Data:
-
- // "Ground-up continuous", or rather, "biome data present" flag:
- a_Data.push_back('\x01');
-
- // Two bitmaps; we're aways sending the full chunk with no additional data, so the bitmaps are 0xffff and 0, respectively
- // Also, no endian flipping is needed because of the const values
- unsigned short BitMap1 = 0xffff;
- unsigned short BitMap2 = 0;
- a_Data.append((const char *)&BitMap1, sizeof(short));
- a_Data.append((const char *)&BitMap2, sizeof(short));
-
- Int32 CompressedSizeBE = htonl(CompressedSize);
- a_Data.append((const char *)&CompressedSizeBE, sizeof(CompressedSizeBE));
-
- // Unlike 29, 39 doesn't have the "unused" int
-
- a_Data.append(CompressedBlockData, CompressedSize);
-}
-
-
-
-
+ +// ChunkDataSerializer.cpp + +// Implements the cChunkDataSerializer class representing the object that can: +// - serialize chunk data to different protocol versions +// - cache such serialized data for multiple clients + +#include "Globals.h" +#include "ChunkDataSerializer.h" +#include "zlib.h" + + + + +cChunkDataSerializer::cChunkDataSerializer( + const cChunkDef::BlockTypes & a_BlockTypes, + const cChunkDef::BlockNibbles & a_BlockMetas, + const cChunkDef::BlockNibbles & a_BlockLight, + const cChunkDef::BlockNibbles & a_BlockSkyLight, + const unsigned char * a_BiomeData +) : + m_BlockTypes(a_BlockTypes), + m_BlockMetas(a_BlockMetas), + m_BlockLight(a_BlockLight), + m_BlockSkyLight(a_BlockSkyLight), + m_BiomeData(a_BiomeData) +{ +} + + + + +const AString & cChunkDataSerializer::Serialize(int a_Version) +{ + Serializations::const_iterator itr = m_Serializations.find(a_Version); + if (itr != m_Serializations.end()) + { + return itr->second; + } + + AString data; + switch (a_Version) + { + case RELEASE_1_2_5: Serialize29(data); break; + case RELEASE_1_3_2: Serialize39(data); break; + // TODO: Other protocol versions may serialize the data differently; implement here + + default: + { + LOGERROR("cChunkDataSerializer::Serialize(): Unknown version: %d", a_Version); + ASSERT(!"Unknown chunk data serialization version"); + break; + } + } + m_Serializations[a_Version] = data; + return m_Serializations[a_Version]; +} + + + + + +void cChunkDataSerializer::Serialize29(AString & a_Data) +{ + // TODO: Do not copy data and then compress it; rather, compress partial blocks of data (zlib *can* stream) + + const int BiomeDataSize = cChunkDef::Width * cChunkDef::Width; + const int MetadataOffset = sizeof(m_BlockTypes); + const int BlockLightOffset = MetadataOffset + sizeof(m_BlockMetas); + const int SkyLightOffset = BlockLightOffset + sizeof(m_BlockLight); + const int BiomeOffset = SkyLightOffset + sizeof(m_BlockSkyLight); + const int DataSize = BiomeOffset + BiomeDataSize; + + // Temporary buffer for the composed data: + char AllData [DataSize]; + + memcpy(AllData, m_BlockTypes, sizeof(m_BlockTypes)); + memcpy(AllData + MetadataOffset, m_BlockMetas, sizeof(m_BlockMetas)); + memcpy(AllData + BlockLightOffset, m_BlockLight, sizeof(m_BlockLight)); + memcpy(AllData + SkyLightOffset, m_BlockSkyLight, sizeof(m_BlockSkyLight)); + memcpy(AllData + BiomeOffset, m_BiomeData, BiomeDataSize); + + // Compress the data: + // In order not to use allocation, use a fixed-size buffer, with the size + // that uses the same calculation as compressBound(): + const uLongf CompressedMaxSize = DataSize + (DataSize >> 12) + (DataSize >> 14) + (DataSize >> 25) + 16; + char CompressedBlockData[CompressedMaxSize]; + + uLongf CompressedSize = compressBound(DataSize); + + // Run-time check that our compile-time guess about CompressedMaxSize was enough: + ASSERT(CompressedSize <= CompressedMaxSize); + + compress2((Bytef*)CompressedBlockData, &CompressedSize, (const Bytef*)AllData, sizeof(AllData), Z_DEFAULT_COMPRESSION); + + // Now put all those data into a_Data: + + // "Ground-up continuous", or rather, "biome data present" flag: + a_Data.push_back('\x01'); + + // Two bitmaps; we're aways sending the full chunk with no additional data, so the bitmaps are 0xffff and 0, respectively + // Also, no endian flipping is needed because of the const values + unsigned short BitMap1 = 0xffff; + unsigned short BitMap2 = 0; + a_Data.append((const char *)&BitMap1, sizeof(short)); + a_Data.append((const char *)&BitMap2, sizeof(short)); + + Int32 CompressedSizeBE = htonl(CompressedSize); + a_Data.append((const char *)&CompressedSizeBE, sizeof(CompressedSizeBE)); + + Int32 UnusedInt32 = 0; + a_Data.append((const char *)&UnusedInt32, sizeof(UnusedInt32)); + + a_Data.append(CompressedBlockData, CompressedSize); +} + + + + + +void cChunkDataSerializer::Serialize39(AString & a_Data) +{ + // TODO: Do not copy data and then compress it; rather, compress partial blocks of data (zlib *can* stream) + + const int BiomeDataSize = cChunkDef::Width * cChunkDef::Width; + const int MetadataOffset = sizeof(m_BlockTypes); + const int BlockLightOffset = MetadataOffset + sizeof(m_BlockMetas); + const int SkyLightOffset = BlockLightOffset + sizeof(m_BlockLight); + const int BiomeOffset = SkyLightOffset + sizeof(m_BlockSkyLight); + const int DataSize = BiomeOffset + BiomeDataSize; + + // Temporary buffer for the composed data: + char AllData [DataSize]; + + memcpy(AllData, m_BlockTypes, sizeof(m_BlockTypes)); + memcpy(AllData + MetadataOffset, m_BlockMetas, sizeof(m_BlockMetas)); + memcpy(AllData + BlockLightOffset, m_BlockLight, sizeof(m_BlockLight)); + memcpy(AllData + SkyLightOffset, m_BlockSkyLight, sizeof(m_BlockSkyLight)); + memcpy(AllData + BiomeOffset, m_BiomeData, BiomeDataSize); + + // Compress the data: + // In order not to use allocation, use a fixed-size buffer, with the size + // that uses the same calculation as compressBound(): + const uLongf CompressedMaxSize = DataSize + (DataSize >> 12) + (DataSize >> 14) + (DataSize >> 25) + 16; + char CompressedBlockData[CompressedMaxSize]; + + uLongf CompressedSize = compressBound(DataSize); + + // Run-time check that our compile-time guess about CompressedMaxSize was enough: + ASSERT(CompressedSize <= CompressedMaxSize); + + compress2((Bytef*)CompressedBlockData, &CompressedSize, (const Bytef*)AllData, sizeof(AllData), Z_DEFAULT_COMPRESSION); + + // Now put all those data into a_Data: + + // "Ground-up continuous", or rather, "biome data present" flag: + a_Data.push_back('\x01'); + + // Two bitmaps; we're aways sending the full chunk with no additional data, so the bitmaps are 0xffff and 0, respectively + // Also, no endian flipping is needed because of the const values + unsigned short BitMap1 = 0xffff; + unsigned short BitMap2 = 0; + a_Data.append((const char *)&BitMap1, sizeof(short)); + a_Data.append((const char *)&BitMap2, sizeof(short)); + + Int32 CompressedSizeBE = htonl(CompressedSize); + a_Data.append((const char *)&CompressedSizeBE, sizeof(CompressedSizeBE)); + + // Unlike 29, 39 doesn't have the "unused" int + + a_Data.append(CompressedBlockData, CompressedSize); +} + + + + diff --git a/source/Protocol/ChunkDataSerializer.h b/source/Protocol/ChunkDataSerializer.h index 513a232b9..a42856356 100644 --- a/source/Protocol/ChunkDataSerializer.h +++ b/source/Protocol/ChunkDataSerializer.h @@ -1,48 +1,48 @@ -
-// ChunkDataSerializer.h
-
-// Interfaces to the cChunkDataSerializer class representing the object that can:
-// - serialize chunk data to different protocol versions
-// - cache such serialized data for multiple clients
-
-
-
-
-
-class cChunkDataSerializer
-{
-protected:
- const cChunkDef::BlockTypes & m_BlockTypes;
- const cChunkDef::BlockNibbles & m_BlockMetas;
- const cChunkDef::BlockNibbles & m_BlockLight;
- const cChunkDef::BlockNibbles & m_BlockSkyLight;
- const unsigned char * m_BiomeData;
-
- typedef std::map<int, AString> Serializations;
-
- Serializations m_Serializations;
-
- void Serialize29(AString & a_Data); // Release 1.2.4 and 1.2.5
- void Serialize39(AString & a_Data); // Release 1.3.1 and 1.3.2
-
-public:
- enum
- {
- RELEASE_1_2_5 = 29,
- RELEASE_1_3_2 = 39,
- } ;
-
- cChunkDataSerializer(
- const cChunkDef::BlockTypes & a_BlockTypes,
- const cChunkDef::BlockNibbles & a_BlockMetas,
- const cChunkDef::BlockNibbles & a_BlockLight,
- const cChunkDef::BlockNibbles & a_BlockSkyLight,
- const unsigned char * a_BiomeData
- );
-
- const AString & Serialize(int a_Version); // Returns one of the internal m_Serializations[]
-} ;
-
-
-
-
+ +// ChunkDataSerializer.h + +// Interfaces to the cChunkDataSerializer class representing the object that can: +// - serialize chunk data to different protocol versions +// - cache such serialized data for multiple clients + + + + + +class cChunkDataSerializer +{ +protected: + const cChunkDef::BlockTypes & m_BlockTypes; + const cChunkDef::BlockNibbles & m_BlockMetas; + const cChunkDef::BlockNibbles & m_BlockLight; + const cChunkDef::BlockNibbles & m_BlockSkyLight; + const unsigned char * m_BiomeData; + + typedef std::map<int, AString> Serializations; + + Serializations m_Serializations; + + void Serialize29(AString & a_Data); // Release 1.2.4 and 1.2.5 + void Serialize39(AString & a_Data); // Release 1.3.1 and 1.3.2 + +public: + enum + { + RELEASE_1_2_5 = 29, + RELEASE_1_3_2 = 39, + } ; + + cChunkDataSerializer( + const cChunkDef::BlockTypes & a_BlockTypes, + const cChunkDef::BlockNibbles & a_BlockMetas, + const cChunkDef::BlockNibbles & a_BlockLight, + const cChunkDef::BlockNibbles & a_BlockSkyLight, + const unsigned char * a_BiomeData + ); + + const AString & Serialize(int a_Version); // Returns one of the internal m_Serializations[] +} ; + + + + diff --git a/source/Protocol/Protocol.h b/source/Protocol/Protocol.h index fe9d4d10e..ab1b632ff 100644 --- a/source/Protocol/Protocol.h +++ b/source/Protocol/Protocol.h @@ -1,192 +1,192 @@ -
-// Protocol.h
-
-// Interfaces to the cProtocol class representing the generic interface that a protocol
-// parser and serializer must implement
-
-
-
-
-
-#pragma once
-
-#include "../Defines.h"
-#include "../Endianness.h"
-
-
-
-
-class cPlayer;
-class cEntity;
-class cWindow;
-class cInventory;
-class cPawn;
-class cPickup;
-class cMonster;
-class cChunkDataSerializer;
-class cWorld;
-class cFallingBlock;
-
-
-
-
-
-typedef unsigned char Byte;
-
-
-
-
-
-class cProtocol
-{
-public:
- cProtocol(cClientHandle * a_Client) :
- m_Client(a_Client)
- {
- }
- virtual ~cProtocol() {}
-
- /// Called when client sends some data
- virtual void DataReceived(const char * a_Data, int a_Size) = 0;
-
- // Sending stuff to clients (alphabetically sorted):
- virtual void SendAttachEntity (const cEntity & a_Entity, const cEntity * a_Vehicle) = 0;
- virtual void SendBlockAction (int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType) = 0;
- virtual void SendBlockBreakAnim (int a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage) = 0;
- 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 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;
- virtual void SendDisconnect (const AString & a_Reason) = 0;
- virtual void SendEntityEquipment (const cEntity & a_Entity, short a_SlotNum, const cItem & a_Item) = 0;
- virtual void SendEntityHeadLook (const cEntity & a_Entity) = 0;
- virtual void SendEntityLook (const cEntity & a_Entity) = 0;
- virtual void SendEntityMetadata (const cEntity & a_Entity) = 0;
- virtual void SendEntityProperties (const cEntity & a_Entity) = 0;
- virtual void SendEntityRelMove (const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ) = 0;
- virtual void SendEntityRelMoveLook (const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ) = 0;
- virtual void SendEntityStatus (const cEntity & a_Entity, char a_Status) = 0;
- virtual void SendEntityVelocity (const cEntity & a_Entity) = 0;
- virtual void SendExplosion (double a_BlockX, double a_BlockY, double a_BlockZ, float a_Radius, const cVector3iArray & a_BlocksAffected, const Vector3d & a_PlayerMotion) = 0;
- virtual void SendGameMode (eGameMode a_GameMode) = 0;
- virtual void SendHealth (void) = 0;
- virtual void SendInventoryProgress (char a_WindowID, short a_Progressbar, short a_Value) = 0;
- 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 SendPickupSpawn (const cPickup & a_Pickup) = 0;
- virtual void SendPlayerAnimation (const cPlayer & a_Player, char a_Animation) = 0;
- virtual void SendPlayerListItem (const cPlayer & a_Player, bool a_IsOnline) = 0;
- virtual void SendPlayerMaxSpeed (void) = 0; ///< Informs the client of the maximum player speed (1.6.1+)
- virtual void SendPlayerMoveLook (void) = 0;
- virtual void SendPlayerPosition (void) = 0;
- virtual void SendPlayerSpawn (const cPlayer & a_Player) = 0;
- virtual void SendRespawn (void) = 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;
- virtual void SendSpawnMob (const cMonster & a_Mob) = 0;
- virtual void SendSpawnObject (const cEntity & a_Entity, char a_ObjectType, int a_ObjectData, Byte a_Yaw, Byte a_Pitch) = 0;
- virtual void SendSpawnVehicle (const cEntity & a_Vehicle, char a_VehicleType) = 0;
- virtual void SendTeleportEntity (const cEntity & a_Entity) = 0;
- virtual void SendThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ) = 0;
- virtual void SendTimeUpdate (Int64 a_WorldAge, Int64 a_TimeOfDay) = 0;
- virtual void SendUnloadChunk (int a_ChunkX, int a_ChunkZ) = 0;
- 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) = 0;
- virtual void SendUseBed (const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ ) = 0;
- virtual void SendWeather (eWeather a_Weather) = 0;
- virtual void SendWholeInventory (const cInventory & a_Inventory) = 0;
- virtual void SendWholeInventory (const cWindow & a_Window) = 0;
- virtual void SendWindowClose (const cWindow & a_Window) = 0;
- virtual void SendWindowOpen (char a_WindowID, char a_WindowType, const AString & a_WindowTitle, char a_NumSlots) = 0;
-
- /// Returns the ServerID used for authentication through session.minecraft.net
- virtual AString GetAuthServerID(void) = 0;
-
-protected:
- cClientHandle * m_Client;
- 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;
-
- /// Called after writing each packet, enables descendants to flush their buffers
- virtual void Flush(void) {};
-
- // Helpers for writing partial packet data, write using SendData()
- void WriteByte(Byte a_Value)
- {
- SendData((const char *)&a_Value, 1);
- }
-
- void WriteShort(short a_Value)
- {
- a_Value = htons(a_Value);
- SendData((const char *)&a_Value, 2);
- }
-
- /*
- void WriteShort(unsigned short a_Value)
- {
- a_Value = htons(a_Value);
- SendData((const char *)&a_Value, 2);
- }
- */
-
- void WriteInt(int a_Value)
- {
- a_Value = htonl(a_Value);
- SendData((const char *)&a_Value, 4);
- }
-
- void WriteUInt(unsigned int a_Value)
- {
- a_Value = htonl(a_Value);
- SendData((const char *)&a_Value, 4);
- }
-
- void WriteInt64 (Int64 a_Value)
- {
- a_Value = HostToNetwork8(&a_Value);
- SendData((const char *)&a_Value, 8);
- }
-
- void WriteFloat (float a_Value)
- {
- unsigned int val = HostToNetwork4(&a_Value);
- SendData((const char *)&val, 4);
- }
-
- void WriteDouble(double a_Value)
- {
- unsigned long long val = HostToNetwork8(&a_Value);
- SendData((const char *)&val, 8);
- }
-
- void WriteString(const AString & a_Value)
- {
- AString UTF16;
- UTF8ToRawBEUTF16(a_Value.c_str(), a_Value.length(), UTF16);
- WriteShort((unsigned short)(UTF16.size() / 2));
- SendData(UTF16.data(), UTF16.size());
- }
-
- void WriteBool(bool a_Value)
- {
- WriteByte(a_Value ? 1 : 0);
- }
-
- void WriteVectorI(const Vector3i & a_Vector)
- {
- WriteInt(a_Vector.x);
- WriteInt(a_Vector.y);
- WriteInt(a_Vector.z);
- }
-} ;
-
-
-
-
-
+ +// Protocol.h + +// Interfaces to the cProtocol class representing the generic interface that a protocol +// parser and serializer must implement + + + + + +#pragma once + +#include "../Defines.h" +#include "../Endianness.h" + + + + +class cPlayer; +class cEntity; +class cWindow; +class cInventory; +class cPawn; +class cPickup; +class cMonster; +class cChunkDataSerializer; +class cWorld; +class cFallingBlock; + + + + + +typedef unsigned char Byte; + + + + + +class cProtocol +{ +public: + cProtocol(cClientHandle * a_Client) : + m_Client(a_Client) + { + } + virtual ~cProtocol() {} + + /// Called when client sends some data + virtual void DataReceived(const char * a_Data, int a_Size) = 0; + + // Sending stuff to clients (alphabetically sorted): + virtual void SendAttachEntity (const cEntity & a_Entity, const cEntity * a_Vehicle) = 0; + virtual void SendBlockAction (int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType) = 0; + virtual void SendBlockBreakAnim (int a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage) = 0; + 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 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; + virtual void SendDisconnect (const AString & a_Reason) = 0; + virtual void SendEntityEquipment (const cEntity & a_Entity, short a_SlotNum, const cItem & a_Item) = 0; + virtual void SendEntityHeadLook (const cEntity & a_Entity) = 0; + virtual void SendEntityLook (const cEntity & a_Entity) = 0; + virtual void SendEntityMetadata (const cEntity & a_Entity) = 0; + virtual void SendEntityProperties (const cEntity & a_Entity) = 0; + virtual void SendEntityRelMove (const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ) = 0; + virtual void SendEntityRelMoveLook (const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ) = 0; + virtual void SendEntityStatus (const cEntity & a_Entity, char a_Status) = 0; + virtual void SendEntityVelocity (const cEntity & a_Entity) = 0; + virtual void SendExplosion (double a_BlockX, double a_BlockY, double a_BlockZ, float a_Radius, const cVector3iArray & a_BlocksAffected, const Vector3d & a_PlayerMotion) = 0; + virtual void SendGameMode (eGameMode a_GameMode) = 0; + virtual void SendHealth (void) = 0; + virtual void SendInventoryProgress (char a_WindowID, short a_Progressbar, short a_Value) = 0; + 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 SendPickupSpawn (const cPickup & a_Pickup) = 0; + virtual void SendPlayerAnimation (const cPlayer & a_Player, char a_Animation) = 0; + virtual void SendPlayerListItem (const cPlayer & a_Player, bool a_IsOnline) = 0; + virtual void SendPlayerMaxSpeed (void) = 0; ///< Informs the client of the maximum player speed (1.6.1+) + virtual void SendPlayerMoveLook (void) = 0; + virtual void SendPlayerPosition (void) = 0; + virtual void SendPlayerSpawn (const cPlayer & a_Player) = 0; + virtual void SendRespawn (void) = 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; + virtual void SendSpawnMob (const cMonster & a_Mob) = 0; + virtual void SendSpawnObject (const cEntity & a_Entity, char a_ObjectType, int a_ObjectData, Byte a_Yaw, Byte a_Pitch) = 0; + virtual void SendSpawnVehicle (const cEntity & a_Vehicle, char a_VehicleType) = 0; + virtual void SendTeleportEntity (const cEntity & a_Entity) = 0; + virtual void SendThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ) = 0; + virtual void SendTimeUpdate (Int64 a_WorldAge, Int64 a_TimeOfDay) = 0; + virtual void SendUnloadChunk (int a_ChunkX, int a_ChunkZ) = 0; + 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) = 0; + virtual void SendUseBed (const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ ) = 0; + virtual void SendWeather (eWeather a_Weather) = 0; + virtual void SendWholeInventory (const cInventory & a_Inventory) = 0; + virtual void SendWholeInventory (const cWindow & a_Window) = 0; + virtual void SendWindowClose (const cWindow & a_Window) = 0; + virtual void SendWindowOpen (char a_WindowID, char a_WindowType, const AString & a_WindowTitle, char a_NumSlots) = 0; + + /// Returns the ServerID used for authentication through session.minecraft.net + virtual AString GetAuthServerID(void) = 0; + +protected: + cClientHandle * m_Client; + 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; + + /// Called after writing each packet, enables descendants to flush their buffers + virtual void Flush(void) {}; + + // Helpers for writing partial packet data, write using SendData() + void WriteByte(Byte a_Value) + { + SendData((const char *)&a_Value, 1); + } + + void WriteShort(short a_Value) + { + a_Value = htons(a_Value); + SendData((const char *)&a_Value, 2); + } + + /* + void WriteShort(unsigned short a_Value) + { + a_Value = htons(a_Value); + SendData((const char *)&a_Value, 2); + } + */ + + void WriteInt(int a_Value) + { + a_Value = htonl(a_Value); + SendData((const char *)&a_Value, 4); + } + + void WriteUInt(unsigned int a_Value) + { + a_Value = htonl(a_Value); + SendData((const char *)&a_Value, 4); + } + + void WriteInt64 (Int64 a_Value) + { + a_Value = HostToNetwork8(&a_Value); + SendData((const char *)&a_Value, 8); + } + + void WriteFloat (float a_Value) + { + unsigned int val = HostToNetwork4(&a_Value); + SendData((const char *)&val, 4); + } + + void WriteDouble(double a_Value) + { + unsigned long long val = HostToNetwork8(&a_Value); + SendData((const char *)&val, 8); + } + + void WriteString(const AString & a_Value) + { + AString UTF16; + UTF8ToRawBEUTF16(a_Value.c_str(), a_Value.length(), UTF16); + WriteShort((unsigned short)(UTF16.size() / 2)); + SendData(UTF16.data(), UTF16.size()); + } + + void WriteBool(bool a_Value) + { + WriteByte(a_Value ? 1 : 0); + } + + void WriteVectorI(const Vector3i & a_Vector) + { + WriteInt(a_Vector.x); + WriteInt(a_Vector.y); + WriteInt(a_Vector.z); + } +} ; + + + + + diff --git a/source/Protocol/Protocol125.cpp b/source/Protocol/Protocol125.cpp index fddf7d324..5ecb5b172 100644 --- a/source/Protocol/Protocol125.cpp +++ b/source/Protocol/Protocol125.cpp @@ -1,1636 +1,1636 @@ -
-// Protocol125.cpp
-
-// Implements the cProtocol125 class representing the release 1.2.5 protocol (#29)
-/*
-Documentation:
- - protocol: http://wiki.vg/wiki/index.php?title=Protocol&oldid=2513
- - session handling: http://wiki.vg/wiki/index.php?title=Session&oldid=2262
- - slot format: http://wiki.vg/wiki/index.php?title=Slot_Data&oldid=2152
-*/
-
-#include "Globals.h"
-
-#include "Protocol125.h"
-
-#include "../ClientHandle.h"
-#include "ChunkDataSerializer.h"
-#include "../Entity.h"
-#include "../Mobs/Monster.h"
-#include "../Pickup.h"
-#include "../Player.h"
-#include "../ChatColor.h"
-#include "../UI/Window.h"
-#include "../Root.h"
-#include "../Server.h"
-#include "../FallingBlock.h"
-
-
-
-
-
-enum
-{
- PACKET_KEEP_ALIVE = 0x00,
- PACKET_LOGIN = 0x01,
- PACKET_HANDSHAKE = 0x02,
- PACKET_CHAT = 0x03,
- PACKET_UPDATE_TIME = 0x04,
- PACKET_ENTITY_EQUIPMENT = 0x05,
- PACKET_USE_ENTITY = 0x07,
- PACKET_UPDATE_HEALTH = 0x08,
- PACKET_RESPAWN = 0x09,
- PACKET_PLAYER_ON_GROUND = 0x0a,
- PACKET_PLAYER_POS = 0x0b,
- PACKET_PLAYER_LOOK = 0x0c,
- PACKET_PLAYER_MOVE_LOOK = 0x0d,
- PACKET_BLOCK_DIG = 0x0e,
- PACKET_BLOCK_PLACE = 0x0f,
- PACKET_SLOT_SELECTED = 0x10,
- PACKET_USE_BED = 0x11,
- PACKET_ANIMATION = 0x12,
- PACKET_PACKET_ENTITY_ACTION = 0x13,
- PACKET_PLAYER_SPAWN = 0x14,
- PACKET_PICKUP_SPAWN = 0x15,
- PACKET_COLLECT_PICKUP = 0x16,
- PACKET_SPAWN_OBJECT = 0x17,
- PACKET_SPAWN_MOB = 0x18,
- PACKET_ENTITY_VELOCITY = 0x1c,
- PACKET_DESTROY_ENTITY = 0x1d,
- PACKET_ENTITY = 0x1e,
- PACKET_ENT_REL_MOVE = 0x1f,
- PACKET_ENT_LOOK = 0x20,
- PACKET_ENT_REL_MOVE_LOOK = 0x21,
- PACKET_ENT_TELEPORT = 0x22,
- PACKET_ENT_HEAD_LOOK = 0x23,
- PACKET_ENT_STATUS = 0x26,
- PACKET_ATTACH_ENTITY = 0x27,
- PACKET_METADATA = 0x28,
- PACKET_PRE_CHUNK = 0x32,
- PACKET_MAP_CHUNK = 0x33,
- PACKET_MULTI_BLOCK = 0x34,
- PACKET_BLOCK_CHANGE = 0x35,
- PACKET_BLOCK_ACTION = 0x36,
- PACKET_EXPLOSION = 0x3C,
- PACKET_SOUND_EFFECT = 0x3e,
- PACKET_SOUND_PARTICLE_EFFECT = 0x3d,
- PACKET_CHANGE_GAME_STATE = 0x46,
- PACKET_THUNDERBOLT = 0x47,
- PACKET_WINDOW_OPEN = 0x64,
- PACKET_WINDOW_CLOSE = 0x65,
- PACKET_WINDOW_CLICK = 0x66,
- PACKET_INVENTORY_SLOT = 0x67,
- PACKET_INVENTORY_WHOLE = 0x68,
- PACKET_INVENTORY_PROGRESS = 0x69,
- PACKET_CREATIVE_INVENTORY_ACTION = 0x6B,
- PACKET_UPDATE_SIGN = 0x82,
- PACKET_PLAYER_LIST_ITEM = 0xC9,
- PACKET_PLAYER_ABILITIES = 0xca,
- PACKET_PLUGIN_MESSAGE = 0xfa,
- PACKET_PING = 0xfe,
- PACKET_DISCONNECT = 0xff
-} ;
-
-
-
-
-
-#define HANDLE_PACKET_READ(Proc, Type, Var) \
- Type Var; \
- { \
- if (!m_ReceivedData.Proc(Var)) \
- { \
- m_ReceivedData.CheckValid(); \
- return PARSE_INCOMPLETE; \
- } \
- m_ReceivedData.CheckValid(); \
- }
-
-
-
-
-typedef unsigned char Byte;
-
-
-
-
-
-cProtocol125::cProtocol125(cClientHandle * a_Client) :
- super(a_Client),
- m_ReceivedData(32 KiB)
-{
-}
-
-
-
-
-
-void cProtocol125::SendAttachEntity(const cEntity & a_Entity, const cEntity * a_Vehicle)
-{
- cCSLock Lock(m_CSPacket);
- WriteByte(PACKET_ATTACH_ENTITY);
- WriteInt(a_Entity.GetUniqueID());
- WriteInt((a_Vehicle == NULL) ? -1 : a_Vehicle->GetUniqueID());
- Flush();
-}
-
-
-
-
-
-void cProtocol125::SendBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType)
-{
- UNUSED(a_BlockType);
-
- cCSLock Lock(m_CSPacket);
- WriteByte (PACKET_BLOCK_ACTION);
- WriteInt (a_BlockX);
- WriteShort((short)a_BlockY);
- WriteInt (a_BlockZ);
- WriteByte (a_Byte1);
- WriteByte (a_Byte2);
- Flush();
-}
-
-
-
-
-
-void cProtocol125::SendBlockBreakAnim(int a_entityID, int a_BlockX, int a_BlockY, int a_BlockZ, char stage)
-{
- // Not supported in this protocol version
-}
-
-
-
-
-
-void cProtocol125::SendBlockChange(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
-{
- cCSLock Lock(m_CSPacket);
- WriteByte(PACKET_BLOCK_CHANGE);
- WriteInt (a_BlockX);
- WriteByte((unsigned char)a_BlockY);
- WriteInt (a_BlockZ);
- WriteByte(a_BlockType);
- WriteByte(a_BlockMeta);
- Flush();
-}
-
-
-
-
-
-void cProtocol125::SendBlockChanges(int a_ChunkX, int a_ChunkZ, const sSetBlockVector & a_Changes)
-{
- cCSLock Lock(m_CSPacket);
- if (a_Changes.size() == 1)
- {
- // Special packet for single-block changes
- const sSetBlock & blk = a_Changes.front();
- SendBlockChange(a_ChunkX * cChunkDef::Width + blk.x, blk.y, a_ChunkZ * cChunkDef::Width + blk.z, blk.BlockType, blk.BlockMeta);
- return;
- }
-
- WriteByte (PACKET_MULTI_BLOCK);
- WriteInt (a_ChunkX);
- WriteInt (a_ChunkZ);
- WriteShort((unsigned short)a_Changes.size());
- WriteUInt (sizeof(int) * 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);
- WriteUInt(Coords << 16 | Blocks);
- }
- Flush();
-}
-
-
-
-
-
-void cProtocol125::SendChat(const AString & a_Message)
-{
- cCSLock Lock(m_CSPacket);
- WriteByte (PACKET_CHAT);
- WriteString(a_Message);
- Flush();
-}
-
-
-
-
-
-void cProtocol125::SendChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer)
-{
- cCSLock Lock(m_CSPacket);
-
- // Send the pre-chunk:
- SendPreChunk(a_ChunkX, a_ChunkZ, true);
-
- // Send the chunk data:
- AString Serialized = a_Serializer.Serialize(cChunkDataSerializer::RELEASE_1_2_5);
- WriteByte(PACKET_MAP_CHUNK);
- WriteInt (a_ChunkX);
- WriteInt (a_ChunkZ);
- SendData(Serialized.data(), Serialized.size());
- Flush();
-}
-
-
-
-
-
-void cProtocol125::SendCollectPickup(const cPickup & a_Pickup, const cPlayer & a_Player)
-{
- cCSLock Lock(m_CSPacket);
- WriteByte(PACKET_COLLECT_PICKUP);
- WriteInt (a_Pickup.GetUniqueID());
- WriteInt (a_Player.GetUniqueID());
- Flush();
-}
-
-
-
-
-
-void cProtocol125::SendDestroyEntity(const cEntity & a_Entity)
-{
- cCSLock Lock(m_CSPacket);
- WriteByte(PACKET_DESTROY_ENTITY);
- WriteInt (a_Entity.GetUniqueID());
- Flush();
-}
-
-
-
-
-
-void cProtocol125::SendDisconnect(const AString & a_Reason)
-{
- cCSLock Lock(m_CSPacket);
- WriteByte ((unsigned char)PACKET_DISCONNECT);
- WriteString(a_Reason);
- Flush();
-}
-
-
-
-
-void cProtocol125::SendEntityEquipment(const cEntity & a_Entity, short a_SlotNum, const cItem & a_Item)
-{
- cCSLock Lock(m_CSPacket);
- WriteByte (PACKET_ENTITY_EQUIPMENT);
- WriteInt (a_Entity.GetUniqueID());
- WriteShort(a_SlotNum);
- WriteShort(a_Item.m_ItemType);
- WriteShort(a_Item.m_ItemDamage);
- Flush();
-}
-
-
-
-
-
-void cProtocol125::SendEntityHeadLook(const cEntity & a_Entity)
-{
- ASSERT(a_Entity.GetUniqueID() != m_Client->GetPlayer()->GetUniqueID()); // Must not send for self
-
- cCSLock Lock(m_CSPacket);
- WriteByte(PACKET_ENT_HEAD_LOOK);
- WriteInt (a_Entity.GetUniqueID());
- WriteByte((char)((a_Entity.GetHeadYaw() / 360.f) * 256));
- Flush();
-}
-
-
-
-
-
-void cProtocol125::SendEntityLook(const cEntity & a_Entity)
-{
- ASSERT(a_Entity.GetUniqueID() != m_Client->GetPlayer()->GetUniqueID()); // Must not send for self
-
- cCSLock Lock(m_CSPacket);
- WriteByte(PACKET_ENT_LOOK);
- WriteInt (a_Entity.GetUniqueID());
- WriteByte((char)((a_Entity.GetRotation() / 360.f) * 256));
- WriteByte((char)((a_Entity.GetPitch() / 360.f) * 256));
- Flush();
-}
-
-
-
-
-
-void cProtocol125::SendEntityMetadata(const cEntity & a_Entity)
-{
- cCSLock Lock(m_CSPacket);
- WriteByte(PACKET_METADATA);
- WriteInt (a_Entity.GetUniqueID());
- AString MetaData = GetEntityMetaData(a_Entity);
- SendData(MetaData.data(), MetaData.size());
- Flush();
-}
-
-
-
-
-
-void cProtocol125::SendEntityProperties(const cEntity & a_Entity)
-{
- // Not supported in this protocol version
-}
-
-
-
-
-
-void cProtocol125::SendEntityRelMove(const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ)
-{
- ASSERT(a_Entity.GetUniqueID() != m_Client->GetPlayer()->GetUniqueID()); // Must not send for self
-
- cCSLock Lock(m_CSPacket);
- WriteByte(PACKET_ENT_REL_MOVE);
- WriteInt (a_Entity.GetUniqueID());
- WriteByte(a_RelX);
- WriteByte(a_RelY);
- WriteByte(a_RelZ);
- Flush();
-}
-
-
-
-
-
-void cProtocol125::SendEntityRelMoveLook(const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ)
-{
- ASSERT(a_Entity.GetUniqueID() != m_Client->GetPlayer()->GetUniqueID()); // Must not send for self
-
- 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.GetRotation() / 360.f) * 256));
- WriteByte((char)((a_Entity.GetPitch() / 360.f) * 256));
- Flush();
-}
-
-
-
-
-
-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);
- Flush();
-}
-
-
-
-
-
-void cProtocol125::SendEntityVelocity(const cEntity & a_Entity)
-{
- ASSERT(a_Entity.GetUniqueID() != m_Client->GetPlayer()->GetUniqueID()); // Must not send for self
-
- cCSLock Lock(m_CSPacket);
- WriteByte(PACKET_ENTITY_VELOCITY);
- WriteInt (a_Entity.GetUniqueID());
- WriteShort((short) (a_Entity.GetSpeedX() * 400)); //400 = 8000 / 20
- WriteShort((short) (a_Entity.GetSpeedY() * 400));
- WriteShort((short) (a_Entity.GetSpeedZ() * 400));
- Flush();
-}
-
-
-
-
-
-void cProtocol125::SendExplosion(double a_BlockX, double a_BlockY, double a_BlockZ, float a_Radius, const cVector3iArray & a_BlocksAffected, const Vector3d & a_PlayerMotion)
-{
- cCSLock Lock(m_CSPacket);
- WriteByte(PACKET_EXPLOSION);
- WriteDouble (a_BlockX);
- WriteDouble (a_BlockY);
- WriteDouble (a_BlockZ);
- WriteFloat (a_Radius);
- WriteInt (a_BlocksAffected.size());
- for (cVector3iArray::const_iterator itr = a_BlocksAffected.begin(); itr != a_BlocksAffected.end(); ++itr)
- {
- WriteByte ((Byte)(itr->x - a_BlockX));
- WriteByte ((Byte)(itr->y - a_BlockY));
- WriteByte ((Byte)(itr->z - a_BlockZ));
- }
- WriteFloat ((float)a_PlayerMotion.x);
- WriteFloat ((float)a_PlayerMotion.y);
- WriteFloat ((float)a_PlayerMotion.z);
- Flush();
-}
-
-
-
-
-
-void cProtocol125::SendGameMode(eGameMode a_GameMode)
-{
- cCSLock Lock(m_CSPacket);
- WriteByte(PACKET_CHANGE_GAME_STATE);
- WriteByte(3);
- WriteByte((char)a_GameMode);
- Flush();
-}
-
-
-
-
-
-void cProtocol125::SendHandshake(const AString & a_ConnectionHash)
-{
- cCSLock Lock(m_CSPacket);
- WriteByte (PACKET_HANDSHAKE);
- WriteString(a_ConnectionHash);
- Flush();
-}
-
-
-
-
-
-void cProtocol125::SendHealth(void)
-{
- cCSLock Lock(m_CSPacket);
- WriteByte (PACKET_UPDATE_HEALTH);
- WriteShort((short)m_Client->GetPlayer()->GetHealth());
- WriteShort(m_Client->GetPlayer()->GetFoodLevel());
- WriteFloat((float)m_Client->GetPlayer()->GetFoodSaturationLevel());
- Flush();
-}
-
-
-
-
-
-void cProtocol125::SendInventoryProgress(char a_WindowID, short a_ProgressBar, short a_Value)
-{
- cCSLock Lock(m_CSPacket);
- WriteByte (PACKET_INVENTORY_PROGRESS);
- WriteByte (a_WindowID);
- WriteShort(a_ProgressBar);
- WriteShort(a_Value);
- Flush();
-}
-
-
-
-
-
-void cProtocol125::SendInventorySlot(char a_WindowID, short a_SlotNum, const cItem & a_Item)
-{
- cCSLock Lock(m_CSPacket);
- WriteByte (PACKET_INVENTORY_SLOT);
- WriteByte (a_WindowID);
- WriteShort(a_SlotNum);
- WriteItem (a_Item);
- Flush();
-}
-
-
-
-
-
-void cProtocol125::SendKeepAlive(int a_PingID)
-{
- cCSLock Lock(m_CSPacket);
- WriteByte(PACKET_KEEP_ALIVE);
- WriteInt (a_PingID);
- Flush();
-}
-
-
-
-
-
-void cProtocol125::SendLogin(const cPlayer & a_Player, const cWorld & a_World)
-{
- UNUSED(a_World);
- cCSLock Lock(m_CSPacket);
-
- WriteByte (PACKET_LOGIN);
- WriteInt (a_Player.GetUniqueID()); // EntityID of the player
- WriteString(""); // Username, not used
- WriteString("default"); // Level type
- WriteInt ((int)a_Player.GetGameMode());
- WriteInt ((int)(a_World.GetDimension()));
- WriteByte (2); // TODO: Difficulty
- WriteByte (0); // Unused
- WriteByte (60); // Client list width or something
- 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);
- WriteShort (a_Pickup.GetItem().m_ItemDamage);
- 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));
- Flush();
-}
-
-
-
-
-
-void cProtocol125::SendPlayerAnimation(const cPlayer & a_Player, char a_Animation)
-{
- cCSLock Lock(m_CSPacket);
- WriteByte(PACKET_ANIMATION);
- WriteInt (a_Player.GetUniqueID());
- WriteByte(a_Animation);
- Flush();
-}
-
-
-
-
-
-void cProtocol125::SendPlayerListItem(const cPlayer & a_Player, bool a_IsOnline)
-{
- cCSLock Lock(m_CSPacket);
- AString PlayerName(a_Player.GetColor());
- PlayerName.append(a_Player.GetName());
- if (PlayerName.length() > 14)
- {
- PlayerName.erase(14);
- }
- PlayerName += cChatColor::White;
-
- WriteByte ((unsigned char)PACKET_PLAYER_LIST_ITEM);
- WriteString(PlayerName);
- WriteBool (a_IsOnline);
- WriteShort (a_Player.GetClientHandle()->GetPing());
- Flush();
-}
-
-
-
-
-
-void cProtocol125::SendPlayerMaxSpeed(void)
-{
- // Not supported by this protocol version
-}
-
-
-
-
-
-void cProtocol125::SendPlayerMoveLook(void)
-{
- cCSLock Lock(m_CSPacket);
-
- /*
- LOGD("Sending PlayerMoveLook: {%0.2f, %0.2f, %0.2f}, stance %0.2f, OnGround: %d",
- m_Player->GetPosX(), m_Player->GetPosY(), m_Player->GetPosZ(), m_Player->GetStance(), m_Player->IsOnGround() ? 1 : 0
- );
- */
-
- WriteByte (PACKET_PLAYER_MOVE_LOOK);
- cPlayer * Player = m_Client->GetPlayer();
- WriteDouble(Player->GetPosX());
- WriteDouble(Player->GetStance() + 0.03); // Add a small amount so that the player doesn't start inside a block
- WriteDouble(Player->GetPosY() + 0.03); // Add a small amount so that the player doesn't start inside a block
- WriteDouble(Player->GetPosZ());
- WriteFloat ((float)(Player->GetRotation()));
- WriteFloat ((float)(Player->GetPitch()));
- WriteBool (Player->IsOnGround());
- Flush();
-}
-
-
-
-
-
-void cProtocol125::SendPlayerPosition(void)
-{
- cCSLock Lock(m_CSPacket);
- LOGD("Ignore send PlayerPos"); // PlayerPos is a C->S packet only now
-}
-
-
-
-
-
-void cProtocol125::SendPlayerSpawn(const cPlayer & a_Player)
-{
- const cItem & HeldItem = a_Player.GetEquippedItem();
- cCSLock Lock(m_CSPacket);
- WriteByte (PACKET_PLAYER_SPAWN);
- WriteInt (a_Player.GetUniqueID());
- WriteString(a_Player.GetName());
- WriteInt ((int)(a_Player.GetPosX() * 32));
- WriteInt ((int)(a_Player.GetPosY() * 32));
- WriteInt ((int)(a_Player.GetPosZ() * 32));
- WriteByte ((char)((a_Player.GetRot().x / 360.f) * 256));
- WriteByte ((char)((a_Player.GetRot().y / 360.f) * 256));
- WriteShort (HeldItem.IsEmpty() ? 0 : HeldItem.m_ItemType);
- Flush();
-}
-
-
-
-
-
-void cProtocol125::SendRespawn(void)
-{
- cCSLock Lock(m_CSPacket);
- WriteByte (PACKET_RESPAWN);
- WriteInt ((int)(m_Client->GetPlayer()->GetWorld()->GetDimension()));
- WriteByte (2); // TODO: Difficulty; 2 = Normal
- WriteByte ((char)m_Client->GetPlayer()->GetGameMode());
- WriteShort (256); // Current world height
- WriteString("default");
-}
-
-
-
-
-
-void cProtocol125::SendSoundEffect(const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch)
-{
- // Not needed in this protocol version
-}
-
-
-
-
-
-void cProtocol125::SendSoundParticleEffect(int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data)
-{
- // Not implemented in this protocol version
-}
-
-
-
-
-
-void cProtocol125::SendSpawnFallingBlock(const cFallingBlock & a_FallingBlock)
-{
- // This protocol version implements falling blocks using the spawn object / vehicle packet:
- SendSpawnObject(a_FallingBlock, 70, a_FallingBlock.GetBlockType(), 0, 0);
-}
-
-
-
-
-
-void cProtocol125::SendSpawnMob(const cMonster & a_Mob)
-{
- cCSLock Lock(m_CSPacket);
- WriteByte (PACKET_SPAWN_MOB);
- WriteInt (a_Mob.GetUniqueID());
- WriteByte (a_Mob.GetMobType());
- WriteVectorI((Vector3i)(a_Mob.GetPosition() * 32));
- WriteByte (0);
- WriteByte (0);
- WriteByte (0);
- AString MetaData = GetEntityMetaData(a_Mob);
- SendData (MetaData.data(), MetaData.size());
- Flush();
-}
-
-
-
-
-
-void cProtocol125::SendSpawnObject(const cEntity & a_Entity, char a_ObjectType, int a_ObjectData, Byte a_Yaw, Byte a_Pitch)
-{
- UNUSED(a_Yaw);
- UNUSED(a_Pitch);
-
- cCSLock Lock(m_CSPacket);
- WriteByte(PACKET_SPAWN_OBJECT);
- WriteInt (a_Entity.GetUniqueID());
- WriteByte(a_ObjectType);
- WriteInt ((int)(a_Entity.GetPosX() * 32));
- WriteInt ((int)(a_Entity.GetPosY() * 32));
- WriteInt ((int)(a_Entity.GetPosZ() * 32));
- WriteByte(a_Pitch);
- WriteByte(a_Yaw);
- WriteInt (a_ObjectData);
- if (a_ObjectData != 0)
- {
- WriteShort((short)(a_Entity.GetSpeedX() * 400));
- WriteShort((short)(a_Entity.GetSpeedY() * 400));
- WriteShort((short)(a_Entity.GetSpeedZ() * 400));
- }
- Flush();
-}
-
-
-
-
-
-void cProtocol125::SendSpawnVehicle(const cEntity & a_Vehicle, char a_VehicleType)
-{
- cCSLock Lock(m_CSPacket);
- WriteByte (PACKET_SPAWN_OBJECT);
- WriteInt (a_Vehicle.GetUniqueID());
- WriteByte (a_VehicleType);
- WriteInt ((int)(a_Vehicle.GetPosX() * 32));
- WriteInt ((int)(a_Vehicle.GetPosY() * 32));
- WriteInt ((int)(a_Vehicle.GetPosZ() * 32));
- WriteByte ((Byte)((a_Vehicle.GetPitch() / 360.f) * 256));
- WriteByte ((Byte)((a_Vehicle.GetRotation() / 360.f) * 256));
- WriteInt (1);
- WriteShort((short)(a_Vehicle.GetSpeedX() * 400));
- WriteShort((short)(a_Vehicle.GetSpeedY() * 400));
- WriteShort((short)(a_Vehicle.GetSpeedZ() * 400));
- Flush();
-}
-
-
-
-
-
-void cProtocol125::SendTeleportEntity(const cEntity & a_Entity)
-{
- cCSLock Lock(m_CSPacket);
- WriteByte (PACKET_ENT_TELEPORT);
- WriteInt (a_Entity.GetUniqueID());
- 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.GetRotation() / 360.f) * 256));
- WriteByte ((char)((a_Entity.GetPitch() / 360.f) * 256));
- Flush();
-}
-
-
-
-
-
-void cProtocol125::SendThunderbolt(int a_BlockX, int a_BlockY, int a_BlockZ)
-{
- cCSLock Lock(m_CSPacket);
- WriteByte(PACKET_THUNDERBOLT);
- WriteInt (0x7fffffff); // Entity ID of the thunderbolt; we use a constant one
- WriteBool(true); // Unknown bool
- WriteInt (a_BlockX * 32);
- WriteInt (a_BlockY * 32);
- WriteInt (a_BlockZ * 32);
- Flush();
-}
-
-
-
-
-
-void cProtocol125::SendTimeUpdate(Int64 a_WorldAge, Int64 a_TimeOfDay)
-{
- cCSLock Lock(m_CSPacket);
- WriteByte (PACKET_UPDATE_TIME);
- // Use a_WorldAge for daycount, and a_TimeOfDay for the proper time of day:
- WriteInt64((24000 * (a_WorldAge / 24000)) + (a_TimeOfDay % 24000));
- Flush();
-}
-
-
-
-
-
-void cProtocol125::SendUnloadChunk(int a_ChunkX, int a_ChunkZ)
-{
- cCSLock Lock(m_CSPacket);
- SendPreChunk(a_ChunkX, a_ChunkZ, false);
-}
-
-
-
-
-
-void cProtocol125::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
-)
-{
- cCSLock Lock(m_CSPacket);
- WriteByte ((unsigned char)PACKET_UPDATE_SIGN);
- WriteInt (a_BlockX);
- WriteShort ((short)a_BlockY);
- WriteInt (a_BlockZ);
- WriteString(a_Line1);
- WriteString(a_Line2);
- WriteString(a_Line3);
- WriteString(a_Line4);
- Flush();
-}
-
-
-
-
-
-void cProtocol125::SendUseBed(const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ )
-{
- cCSLock Lock(m_CSPacket);
- WriteByte(PACKET_USE_BED);
- WriteInt (a_Entity.GetUniqueID());
- WriteByte(0); // Unknown byte only 0 has been observed
- WriteInt (a_BlockX);
- WriteByte(a_BlockY);
- WriteInt (a_BlockZ);
- Flush();
-}
-
-
-
-
-
-void cProtocol125::SendWeather(eWeather a_Weather)
-{
- cCSLock Lock(m_CSPacket);
- switch( a_Weather )
- {
- case eWeather_Sunny:
- {
- WriteByte(PACKET_CHANGE_GAME_STATE);
- WriteByte(2); // Stop rain
- WriteByte(0); // Unused
- Flush();
- break;
- }
-
- case eWeather_Rain:
- case eWeather_ThunderStorm:
- {
- WriteByte(PACKET_CHANGE_GAME_STATE);
- WriteByte(1); // Begin rain
- WriteByte(0); // Unused
- Flush();
- break;
- }
- }
-}
-
-
-
-
-
-void cProtocol125::SendWholeInventory(const cInventory & a_Inventory)
-{
- SendWholeInventory(*(a_Inventory.GetOwner().GetWindow()));
-}
-
-
-
-
-
-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]));
-}
-
-
-
-
-
-void cProtocol125::SendWindowClose(const cWindow & a_Window)
-{
- if (a_Window.GetWindowType() == cWindow::Inventory)
- {
- // Do not send inventory-window-close
- return;
- }
-
- cCSLock Lock(m_CSPacket);
- WriteByte(PACKET_WINDOW_CLOSE);
- WriteByte(a_Window.GetWindowID());
- Flush();
-}
-
-
-
-
-
-void cProtocol125::SendWindowOpen(char a_WindowID, char a_WindowType, const AString & a_WindowTitle, char a_NumSlots)
-{
- if (a_WindowType < 0)
- {
- // Do not send for inventory windows
- return;
- }
- cCSLock Lock(m_CSPacket);
- WriteByte (PACKET_WINDOW_OPEN);
- WriteByte (a_WindowID);
- WriteByte (a_WindowType);
- WriteString(a_WindowTitle);
- WriteByte (a_NumSlots);
- Flush();
-}
-
-
-
-
-
-AString cProtocol125::GetAuthServerID(void)
-{
- // http://wiki.vg/wiki/index.php?title=Session&oldid=2262
- // The server generates a random hash and that is used for all clients, unmodified
- return cRoot::Get()->GetServer()->GetServerID();
-}
-
-
-
-
-
-void cProtocol125::SendData(const char * a_Data, int a_Size)
-{
- m_Client->SendData(a_Data, a_Size);
-}
-
-
-
-
-
-void cProtocol125::DataReceived(const char * a_Data, int a_Size)
-{
- if (!m_ReceivedData.Write(a_Data, a_Size))
- {
- // Too much data in the incoming queue, report to caller:
- m_Client->PacketBufferFull();
- return;
- }
-
- // Parse and handle all complete packets in m_ReceivedData:
- while (m_ReceivedData.CanReadBytes(1))
- {
- unsigned char PacketType;
- m_ReceivedData.ReadByte(PacketType);
- switch (ParsePacket(PacketType))
- {
- case PARSE_UNKNOWN:
- {
- // An unknown packet has been received, notify the client and abort:
- m_Client->PacketUnknown(PacketType);
- return;
- }
- case PARSE_ERROR:
- {
- // An error occurred while parsing a known packet, notify the client and abort:
- m_Client->PacketError(PacketType);
- return;
- }
- case PARSE_INCOMPLETE:
- {
- // Incomplete packet, bail out and process with the next batch of data
- m_ReceivedData.ResetRead();
- return;
- }
- default:
- {
- // Packet successfully parsed, commit the read data and try again one more packet
- m_ReceivedData.CommitRead();
- break;
- }
- }
- }
-}
-
-
-
-
-
-int cProtocol125::ParsePacket(unsigned char a_PacketType)
-{
- switch (a_PacketType)
- {
- default: return PARSE_UNKNOWN;
- case PACKET_ANIMATION: return ParseArmAnim();
- case PACKET_BLOCK_DIG: return ParseBlockDig();
- case PACKET_BLOCK_PLACE: return ParseBlockPlace();
- case PACKET_CHAT: return ParseChat();
- case PACKET_CREATIVE_INVENTORY_ACTION: return ParseCreativeInventoryAction();
- case PACKET_DISCONNECT: return ParseDisconnect();
- case PACKET_HANDSHAKE: return ParseHandshake();
- case PACKET_KEEP_ALIVE: return ParseKeepAlive();
- case PACKET_LOGIN: return ParseLogin();
- case PACKET_PACKET_ENTITY_ACTION: return ParseEntityAction();
- case PACKET_PING: return ParsePing();
- case PACKET_PLAYER_ABILITIES: return ParsePlayerAbilities();
- case PACKET_PLAYER_LOOK: return ParsePlayerLook();
- case PACKET_PLAYER_MOVE_LOOK: return ParsePlayerMoveLook();
- case PACKET_PLAYER_ON_GROUND: return ParsePlayerOnGround();
- case PACKET_PLAYER_POS: return ParsePlayerPosition();
- case PACKET_PLUGIN_MESSAGE: return ParsePluginMessage();
- case PACKET_RESPAWN: return ParseRespawn();
- case PACKET_SLOT_SELECTED: return ParseSlotSelected();
- case PACKET_UPDATE_SIGN: return ParseUpdateSign();
- case PACKET_USE_ENTITY: return ParseUseEntity();
- case PACKET_WINDOW_CLICK: return ParseWindowClick();
- case PACKET_WINDOW_CLOSE: return ParseWindowClose();
- }
-}
-
-
-
-
-
-#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);
- HANDLE_PACKET_READ(ReadChar, char, Animation);
- m_Client->HandleAnimation(Animation);
- return PARSE_OK;
-}
-
-
-
-
-
-int cProtocol125::ParseBlockDig(void)
-{
- HANDLE_PACKET_READ(ReadChar, char, Status);
- HANDLE_PACKET_READ(ReadBEInt, int, PosX);
- 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);
- return PARSE_OK;
-}
-
-
-
-
-
-int cProtocol125::ParseBlockPlace(void)
-{
- HANDLE_PACKET_READ(ReadBEInt, int, PosX);
- HANDLE_PACKET_READ(ReadByte, Byte, PosY);
- HANDLE_PACKET_READ(ReadBEInt, int, PosZ);
- HANDLE_PACKET_READ(ReadChar, char, BlockFace);
-
- cItem HeldItem;
- int res = ParseItem(HeldItem);
- if (res < 0)
- {
- return res;
- }
-
- // 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);
- return PARSE_OK;
-}
-
-
-
-
-
-int cProtocol125::ParseChat(void)
-{
- HANDLE_PACKET_READ(ReadBEUTF16String16, AString, Message);
- m_Client->HandleChat(Message);
- return PARSE_OK;
-}
-
-
-
-
-
-int cProtocol125::ParseCreativeInventoryAction(void)
-{
- HANDLE_PACKET_READ(ReadBEShort, short, SlotNum);
- cItem HeldItem;
- int res = ParseItem(HeldItem);
- if (res < 0)
- {
- return res;
- }
- m_Client->HandleCreativeInventory(SlotNum, HeldItem);
- return PARSE_OK;
-}
-
-
-
-
-
-int cProtocol125::ParseDisconnect(void)
-{
- HANDLE_PACKET_READ(ReadBEUTF16String16, AString, Reason);
- m_Client->HandleDisconnect(Reason);
- return PARSE_OK;
-}
-
-
-
-
-
-int cProtocol125::ParseEntityAction(void)
-{
- HANDLE_PACKET_READ(ReadBEInt, int, EntityID);
- HANDLE_PACKET_READ(ReadChar, char, ActionID);
- m_Client->HandleEntityAction(EntityID, ActionID);
- return PARSE_OK;
-}
-
-
-
-
-
-int cProtocol125::ParseHandshake(void)
-{
- HANDLE_PACKET_READ(ReadBEUTF16String16, AString, Username);
-
- AStringVector UserData = StringSplit(Username, ";"); // "FakeTruth;localhost:25565"
- if (UserData.empty())
- {
- m_Client->Kick("Did not receive username");
- return PARSE_OK;
- }
- m_Username = UserData[0];
-
- LOGD("HANDSHAKE %s", Username.c_str());
-
- if (!m_Client->HandleHandshake( m_Username ))
- {
- return PARSE_OK; // Player is not allowed into the server
- }
-
- SendHandshake(cRoot::Get()->GetServer()->GetServerID());
- LOGD("User \"%s\" was sent a handshake response", m_Username.c_str());
-
- return PARSE_OK;
-}
-
-
-
-
-
-int cProtocol125::ParseKeepAlive(void)
-{
- HANDLE_PACKET_READ(ReadBEInt, int, KeepAliveID);
- m_Client->HandleKeepAlive(KeepAliveID);
- return PARSE_OK;
-}
-
-
-
-
-
-int cProtocol125::ParseLogin(void)
-{
- HANDLE_PACKET_READ(ReadBEInt, int, ProtocolVersion);
- HANDLE_PACKET_READ(ReadBEUTF16String16, AString, Username);
- HANDLE_PACKET_READ(ReadBEUTF16String16, AString, LevelType);
- HANDLE_PACKET_READ(ReadBEInt, int, ServerMode);
- HANDLE_PACKET_READ(ReadBEInt, int, Dimension);
- HANDLE_PACKET_READ(ReadChar, char, Difficulty);
- HANDLE_PACKET_READ(ReadByte, Byte, WorldHeight);
- HANDLE_PACKET_READ(ReadByte, Byte, MaxPlayers);
-
- if (ProtocolVersion < 29)
- {
- m_Client->Kick("Your client is outdated!");
- return PARSE_OK;
- }
- else if (ProtocolVersion > 29)
- {
- m_Client->Kick("Your client version is higher than the server!");
- return PARSE_OK;
- }
-
- if (m_Username.compare(Username) != 0)
- {
- LOGWARNING("Login Username (\"%s\") does not match Handshake username (\"%s\") for client @ \"%s\", kicking",
- Username.c_str(),
- m_Username.c_str(),
- m_Client->GetIPString().c_str()
- );
- m_Client->Kick("Hacked client"); // Don't tell them why we don't want them
- return PARSE_OK;
- }
-
- m_Client->HandleLogin(ProtocolVersion, Username);
- return PARSE_OK;
-}
-
-
-
-
-
-int cProtocol125::ParsePing(void)
-{
- // Packet has no more data
- m_Client->HandlePing();
- return PARSE_OK;
-}
-
-
-
-
-
-
-int cProtocol125::ParsePlayerAbilities(void)
-{
- HANDLE_PACKET_READ(ReadBool, bool, Invulnerable);
- HANDLE_PACKET_READ(ReadBool, bool, IsFlying);
- HANDLE_PACKET_READ(ReadBool, bool, CanFly);
- HANDLE_PACKET_READ(ReadBool, bool, InstaMine);
- // TODO: m_Client->HandlePlayerAbilities(...);
- return PARSE_OK;
-}
-
-
-
-
-
-int cProtocol125::ParsePlayerLook(void)
-{
- HANDLE_PACKET_READ(ReadBEFloat, float, Rotation);
- HANDLE_PACKET_READ(ReadBEFloat, float, Pitch);
- HANDLE_PACKET_READ(ReadBool, bool, IsOnGround);
- m_Client->HandlePlayerLook(Rotation, Pitch, IsOnGround);
- return PARSE_OK;
-}
-
-
-
-
-
-int cProtocol125::ParsePlayerMoveLook(void)
-{
- HANDLE_PACKET_READ(ReadBEDouble, double, PosX);
- HANDLE_PACKET_READ(ReadBEDouble, double, PosY);
- HANDLE_PACKET_READ(ReadBEDouble, double, Stance);
- HANDLE_PACKET_READ(ReadBEDouble, double, PosZ);
- HANDLE_PACKET_READ(ReadBEFloat, float, Rotation);
- HANDLE_PACKET_READ(ReadBEFloat, float, Pitch);
- HANDLE_PACKET_READ(ReadBool, bool, IsOnGround);
- // LOGD("Recv PML: {%0.2f, %0.2f, %0.2f}, Stance %0.2f, Gnd: %d", PosX, PosY, PosZ, Stance, IsOnGround ? 1 : 0);
- m_Client->HandlePlayerMoveLook(PosX, PosY, PosZ, Stance, Rotation, Pitch, IsOnGround);
- return PARSE_OK;
-}
-
-
-
-
-
-int cProtocol125::ParsePlayerOnGround(void)
-{
- HANDLE_PACKET_READ(ReadBool, bool, IsOnGround);
- // TODO: m_Client->HandleFlying(IsOnGround);
- return PARSE_OK;
-}
-
-
-
-
-
-int cProtocol125::ParsePlayerPosition(void)
-{
- HANDLE_PACKET_READ(ReadBEDouble, double, PosX);
- HANDLE_PACKET_READ(ReadBEDouble, double, PosY);
- HANDLE_PACKET_READ(ReadBEDouble, double, Stance);
- HANDLE_PACKET_READ(ReadBEDouble, double, PosZ);
- HANDLE_PACKET_READ(ReadBool, bool, IsOnGround);
- m_Client->HandlePlayerPos(PosX, PosY, PosZ, Stance, IsOnGround);
- return PARSE_OK;
-}
-
-
-
-
-
-int cProtocol125::ParsePluginMessage(void)
-{
- HANDLE_PACKET_READ(ReadBEUTF16String16, AString, ChannelName);
- HANDLE_PACKET_READ(ReadBEShort, short, Length);
- AString Data;
- if (!m_ReceivedData.ReadString(Data, Length))
- {
- m_ReceivedData.CheckValid();
- return PARSE_INCOMPLETE;
- }
- m_ReceivedData.CheckValid();
-
- // TODO: Process the data
- LOGD("Received %d bytes of plugin data on channel \"%s\".", Length, ChannelName.c_str());
-
- return PARSE_OK;
-}
-
-
-
-
-
-int cProtocol125::ParseRespawn(void)
-{
- HANDLE_PACKET_READ(ReadBEInt, int, Dimension);
- HANDLE_PACKET_READ(ReadChar, char, Difficulty);
- HANDLE_PACKET_READ(ReadChar, char, CreativeMode);
- HANDLE_PACKET_READ(ReadBEShort, short, WorldHeight);
- HANDLE_PACKET_READ(ReadBEUTF16String16, AString, LevelType);
- m_Client->HandleRespawn();
- return PARSE_OK;
-}
-
-
-
-
-
-int cProtocol125::ParseSlotSelected(void)
-{
- HANDLE_PACKET_READ(ReadBEShort, short, SlotNum);
- m_Client->HandleSlotSelected(SlotNum);
- return PARSE_OK;
-}
-
-
-
-
-
-int cProtocol125::ParseUpdateSign(void)
-{
- HANDLE_PACKET_READ(ReadBEInt, int, BlockX);
- HANDLE_PACKET_READ(ReadBEShort, short, BlockY);
- HANDLE_PACKET_READ(ReadBEInt, int, BlockZ);
- HANDLE_PACKET_READ(ReadBEUTF16String16, AString, Line1);
- HANDLE_PACKET_READ(ReadBEUTF16String16, AString, Line2);
- HANDLE_PACKET_READ(ReadBEUTF16String16, AString, Line3);
- HANDLE_PACKET_READ(ReadBEUTF16String16, AString, Line4);
- m_Client->HandleUpdateSign(BlockX, BlockY, BlockZ, Line1, Line2, Line3, Line4);
- return PARSE_OK;
-}
-
-
-
-
-
-int cProtocol125::ParseUseEntity(void)
-{
- HANDLE_PACKET_READ(ReadBEInt, int, SourceEntityID);
- HANDLE_PACKET_READ(ReadBEInt, int, TargetEntityID);
- HANDLE_PACKET_READ(ReadBool, bool, IsLeftClick);
- m_Client->HandleUseEntity(TargetEntityID, IsLeftClick);
- return PARSE_OK;
-}
-
-
-
-
-
-int cProtocol125::ParseWindowClick(void)
-{
- HANDLE_PACKET_READ(ReadChar, char, WindowID);
- HANDLE_PACKET_READ(ReadBEShort, short, SlotNum);
- HANDLE_PACKET_READ(ReadBool, bool, IsRightClick);
- HANDLE_PACKET_READ(ReadBEShort, short, TransactionID);
- HANDLE_PACKET_READ(ReadBool, bool, IsShiftPressed);
- cItem HeldItem;
- int res = ParseItem(HeldItem);
- if (res < 0)
- {
- return res;
- }
-
- // Convert IsShiftPressed, IsRightClick, SlotNum and HeldItem into eClickAction used in the newer protocols:
- eClickAction Action;
- if (IsRightClick)
- {
- if (IsShiftPressed)
- {
- Action = caShiftRightClick;
- }
- else
- {
- if (SlotNum == -999)
- {
- Action = (HeldItem.IsEmpty()) ? caRightClickOutsideHoldNothing : caRightClickOutside;
- }
- else
- {
- Action = caRightClick;
- }
- }
- }
- else
- {
- // IsLeftClick
- if (IsShiftPressed)
- {
- Action = caShiftLeftClick;
- }
- else
- {
- if (SlotNum == -999)
- {
- Action = (HeldItem.IsEmpty()) ? caLeftClickOutsideHoldNothing : caRightClickOutside;
- }
- else
- {
- Action = caLeftClick;
- }
- }
- }
- m_Client->HandleWindowClick(WindowID, SlotNum, Action, HeldItem);
- return PARSE_OK;
-}
-
-
-
-
-
-int cProtocol125::ParseWindowClose(void)
-{
- HANDLE_PACKET_READ(ReadChar, char, WindowID);
- m_Client->HandleWindowClose(WindowID);
- return PARSE_OK;
-}
-
-
-
-
-
-void cProtocol125::SendPreChunk(int a_ChunkX, int a_ChunkZ, bool a_ShouldLoad)
-{
- WriteByte(PACKET_PRE_CHUNK);
- WriteInt (a_ChunkX);
- WriteInt (a_ChunkZ);
- WriteBool(a_ShouldLoad);
- Flush();
-}
-
-
-
-
-
-void cProtocol125::SendWindowSlots(char a_WindowID, int a_NumItems, const cItem * a_Items)
-{
- WriteByte (PACKET_INVENTORY_WHOLE);
- WriteByte (a_WindowID);
- WriteShort((short)a_NumItems);
-
- for (int j = 0; j < a_NumItems; j++)
- {
- WriteItem(a_Items[j]);
- }
- Flush();
-}
-
-
-
-
-
-void cProtocol125::WriteItem(const cItem & a_Item)
-{
- short ItemType = a_Item.m_ItemType;
- ASSERT(ItemType >= -1); // Check validity of packets in debug runtime
- if (ItemType <= 0)
- {
- // Fix, to make sure no invalid values are sent.
- ItemType = -1;
- }
-
- WriteShort(ItemType);
- if (a_Item.IsEmpty())
- {
- return;
- }
-
- WriteByte (a_Item.m_ItemCount);
- WriteShort(a_Item.m_ItemDamage);
-
- if (cItem::IsEnchantable(a_Item.m_ItemType))
- {
- // TODO: Implement enchantments
- WriteShort(-1);
- }
-}
-
-
-
-
-
-int cProtocol125::ParseItem(cItem & a_Item)
-{
- HANDLE_PACKET_READ(ReadBEShort, short, ItemType);
-
- if (ItemType <= -1)
- {
- a_Item.Empty();
- return PARSE_OK;
- }
- a_Item.m_ItemType = ItemType;
-
- HANDLE_PACKET_READ(ReadChar, char, ItemCount);
- HANDLE_PACKET_READ(ReadBEShort, short, ItemDamage);
- a_Item.m_ItemCount = ItemCount;
- a_Item.m_ItemDamage = ItemDamage;
- if (ItemCount <= 0)
- {
- a_Item.Empty();
- }
-
- if (!cItem::IsEnchantable(ItemType))
- {
- return PARSE_OK;
- }
-
- HANDLE_PACKET_READ(ReadBEShort, short, EnchantNumBytes);
-
- if (EnchantNumBytes <= 0)
- {
- return PARSE_OK;
- }
-
- // TODO: Enchantment not implemented yet!
- if (!m_ReceivedData.SkipRead(EnchantNumBytes))
- {
- return PARSE_INCOMPLETE;
- }
-
- return PARSE_OK;
-}
-
-
-
-
-
-AString cProtocol125::GetEntityMetaData(const cEntity & a_Entity)
-{
- // We should send all the metadata here
- AString MetaData;
- // Common metadata (index 0, byte):
- MetaData.push_back(0);
- MetaData.push_back(GetEntityMetadataFlags(a_Entity));
-
- // TODO: Add more entity-specific metadata
-
- MetaData.push_back(0x7f); // End metadata
- return MetaData;
-}
-
-
-
-
-
-char cProtocol125::GetEntityMetadataFlags(const cEntity & a_Entity)
-{
- char Flags = 0;
- if (a_Entity.IsOnFire())
- {
- Flags |= 1;
- }
- if (a_Entity.IsCrouched())
- {
- Flags |= 2;
- }
- if (a_Entity.IsRiding())
- {
- Flags |= 4;
- }
- if (a_Entity.IsSprinting())
- {
- Flags |= 8;
- }
- if (a_Entity.IsRclking())
- {
- Flags |= 16;
- }
- return Flags;
-}
-
-
-
-
+ +// Protocol125.cpp + +// Implements the cProtocol125 class representing the release 1.2.5 protocol (#29) +/* +Documentation: + - protocol: http://wiki.vg/wiki/index.php?title=Protocol&oldid=2513 + - session handling: http://wiki.vg/wiki/index.php?title=Session&oldid=2262 + - slot format: http://wiki.vg/wiki/index.php?title=Slot_Data&oldid=2152 +*/ + +#include "Globals.h" + +#include "Protocol125.h" + +#include "../ClientHandle.h" +#include "ChunkDataSerializer.h" +#include "../Entity.h" +#include "../Mobs/Monster.h" +#include "../Pickup.h" +#include "../Player.h" +#include "../ChatColor.h" +#include "../UI/Window.h" +#include "../Root.h" +#include "../Server.h" +#include "../FallingBlock.h" + + + + + +enum +{ + PACKET_KEEP_ALIVE = 0x00, + PACKET_LOGIN = 0x01, + PACKET_HANDSHAKE = 0x02, + PACKET_CHAT = 0x03, + PACKET_UPDATE_TIME = 0x04, + PACKET_ENTITY_EQUIPMENT = 0x05, + PACKET_USE_ENTITY = 0x07, + PACKET_UPDATE_HEALTH = 0x08, + PACKET_RESPAWN = 0x09, + PACKET_PLAYER_ON_GROUND = 0x0a, + PACKET_PLAYER_POS = 0x0b, + PACKET_PLAYER_LOOK = 0x0c, + PACKET_PLAYER_MOVE_LOOK = 0x0d, + PACKET_BLOCK_DIG = 0x0e, + PACKET_BLOCK_PLACE = 0x0f, + PACKET_SLOT_SELECTED = 0x10, + PACKET_USE_BED = 0x11, + PACKET_ANIMATION = 0x12, + PACKET_PACKET_ENTITY_ACTION = 0x13, + PACKET_PLAYER_SPAWN = 0x14, + PACKET_PICKUP_SPAWN = 0x15, + PACKET_COLLECT_PICKUP = 0x16, + PACKET_SPAWN_OBJECT = 0x17, + PACKET_SPAWN_MOB = 0x18, + PACKET_ENTITY_VELOCITY = 0x1c, + PACKET_DESTROY_ENTITY = 0x1d, + PACKET_ENTITY = 0x1e, + PACKET_ENT_REL_MOVE = 0x1f, + PACKET_ENT_LOOK = 0x20, + PACKET_ENT_REL_MOVE_LOOK = 0x21, + PACKET_ENT_TELEPORT = 0x22, + PACKET_ENT_HEAD_LOOK = 0x23, + PACKET_ENT_STATUS = 0x26, + PACKET_ATTACH_ENTITY = 0x27, + PACKET_METADATA = 0x28, + PACKET_PRE_CHUNK = 0x32, + PACKET_MAP_CHUNK = 0x33, + PACKET_MULTI_BLOCK = 0x34, + PACKET_BLOCK_CHANGE = 0x35, + PACKET_BLOCK_ACTION = 0x36, + PACKET_EXPLOSION = 0x3C, + PACKET_SOUND_EFFECT = 0x3e, + PACKET_SOUND_PARTICLE_EFFECT = 0x3d, + PACKET_CHANGE_GAME_STATE = 0x46, + PACKET_THUNDERBOLT = 0x47, + PACKET_WINDOW_OPEN = 0x64, + PACKET_WINDOW_CLOSE = 0x65, + PACKET_WINDOW_CLICK = 0x66, + PACKET_INVENTORY_SLOT = 0x67, + PACKET_INVENTORY_WHOLE = 0x68, + PACKET_INVENTORY_PROGRESS = 0x69, + PACKET_CREATIVE_INVENTORY_ACTION = 0x6B, + PACKET_UPDATE_SIGN = 0x82, + PACKET_PLAYER_LIST_ITEM = 0xC9, + PACKET_PLAYER_ABILITIES = 0xca, + PACKET_PLUGIN_MESSAGE = 0xfa, + PACKET_PING = 0xfe, + PACKET_DISCONNECT = 0xff +} ; + + + + + +#define HANDLE_PACKET_READ(Proc, Type, Var) \ + Type Var; \ + { \ + if (!m_ReceivedData.Proc(Var)) \ + { \ + m_ReceivedData.CheckValid(); \ + return PARSE_INCOMPLETE; \ + } \ + m_ReceivedData.CheckValid(); \ + } + + + + +typedef unsigned char Byte; + + + + + +cProtocol125::cProtocol125(cClientHandle * a_Client) : + super(a_Client), + m_ReceivedData(32 KiB) +{ +} + + + + + +void cProtocol125::SendAttachEntity(const cEntity & a_Entity, const cEntity * a_Vehicle) +{ + cCSLock Lock(m_CSPacket); + WriteByte(PACKET_ATTACH_ENTITY); + WriteInt(a_Entity.GetUniqueID()); + WriteInt((a_Vehicle == NULL) ? -1 : a_Vehicle->GetUniqueID()); + Flush(); +} + + + + + +void cProtocol125::SendBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType) +{ + UNUSED(a_BlockType); + + cCSLock Lock(m_CSPacket); + WriteByte (PACKET_BLOCK_ACTION); + WriteInt (a_BlockX); + WriteShort((short)a_BlockY); + WriteInt (a_BlockZ); + WriteByte (a_Byte1); + WriteByte (a_Byte2); + Flush(); +} + + + + + +void cProtocol125::SendBlockBreakAnim(int a_entityID, int a_BlockX, int a_BlockY, int a_BlockZ, char stage) +{ + // Not supported in this protocol version +} + + + + + +void cProtocol125::SendBlockChange(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) +{ + cCSLock Lock(m_CSPacket); + WriteByte(PACKET_BLOCK_CHANGE); + WriteInt (a_BlockX); + WriteByte((unsigned char)a_BlockY); + WriteInt (a_BlockZ); + WriteByte(a_BlockType); + WriteByte(a_BlockMeta); + Flush(); +} + + + + + +void cProtocol125::SendBlockChanges(int a_ChunkX, int a_ChunkZ, const sSetBlockVector & a_Changes) +{ + cCSLock Lock(m_CSPacket); + if (a_Changes.size() == 1) + { + // Special packet for single-block changes + const sSetBlock & blk = a_Changes.front(); + SendBlockChange(a_ChunkX * cChunkDef::Width + blk.x, blk.y, a_ChunkZ * cChunkDef::Width + blk.z, blk.BlockType, blk.BlockMeta); + return; + } + + WriteByte (PACKET_MULTI_BLOCK); + WriteInt (a_ChunkX); + WriteInt (a_ChunkZ); + WriteShort((unsigned short)a_Changes.size()); + WriteUInt (sizeof(int) * 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); + WriteUInt(Coords << 16 | Blocks); + } + Flush(); +} + + + + + +void cProtocol125::SendChat(const AString & a_Message) +{ + cCSLock Lock(m_CSPacket); + WriteByte (PACKET_CHAT); + WriteString(a_Message); + Flush(); +} + + + + + +void cProtocol125::SendChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer) +{ + cCSLock Lock(m_CSPacket); + + // Send the pre-chunk: + SendPreChunk(a_ChunkX, a_ChunkZ, true); + + // Send the chunk data: + AString Serialized = a_Serializer.Serialize(cChunkDataSerializer::RELEASE_1_2_5); + WriteByte(PACKET_MAP_CHUNK); + WriteInt (a_ChunkX); + WriteInt (a_ChunkZ); + SendData(Serialized.data(), Serialized.size()); + Flush(); +} + + + + + +void cProtocol125::SendCollectPickup(const cPickup & a_Pickup, const cPlayer & a_Player) +{ + cCSLock Lock(m_CSPacket); + WriteByte(PACKET_COLLECT_PICKUP); + WriteInt (a_Pickup.GetUniqueID()); + WriteInt (a_Player.GetUniqueID()); + Flush(); +} + + + + + +void cProtocol125::SendDestroyEntity(const cEntity & a_Entity) +{ + cCSLock Lock(m_CSPacket); + WriteByte(PACKET_DESTROY_ENTITY); + WriteInt (a_Entity.GetUniqueID()); + Flush(); +} + + + + + +void cProtocol125::SendDisconnect(const AString & a_Reason) +{ + cCSLock Lock(m_CSPacket); + WriteByte ((unsigned char)PACKET_DISCONNECT); + WriteString(a_Reason); + Flush(); +} + + + + +void cProtocol125::SendEntityEquipment(const cEntity & a_Entity, short a_SlotNum, const cItem & a_Item) +{ + cCSLock Lock(m_CSPacket); + WriteByte (PACKET_ENTITY_EQUIPMENT); + WriteInt (a_Entity.GetUniqueID()); + WriteShort(a_SlotNum); + WriteShort(a_Item.m_ItemType); + WriteShort(a_Item.m_ItemDamage); + Flush(); +} + + + + + +void cProtocol125::SendEntityHeadLook(const cEntity & a_Entity) +{ + ASSERT(a_Entity.GetUniqueID() != m_Client->GetPlayer()->GetUniqueID()); // Must not send for self + + cCSLock Lock(m_CSPacket); + WriteByte(PACKET_ENT_HEAD_LOOK); + WriteInt (a_Entity.GetUniqueID()); + WriteByte((char)((a_Entity.GetHeadYaw() / 360.f) * 256)); + Flush(); +} + + + + + +void cProtocol125::SendEntityLook(const cEntity & a_Entity) +{ + ASSERT(a_Entity.GetUniqueID() != m_Client->GetPlayer()->GetUniqueID()); // Must not send for self + + cCSLock Lock(m_CSPacket); + WriteByte(PACKET_ENT_LOOK); + WriteInt (a_Entity.GetUniqueID()); + WriteByte((char)((a_Entity.GetRotation() / 360.f) * 256)); + WriteByte((char)((a_Entity.GetPitch() / 360.f) * 256)); + Flush(); +} + + + + + +void cProtocol125::SendEntityMetadata(const cEntity & a_Entity) +{ + cCSLock Lock(m_CSPacket); + WriteByte(PACKET_METADATA); + WriteInt (a_Entity.GetUniqueID()); + AString MetaData = GetEntityMetaData(a_Entity); + SendData(MetaData.data(), MetaData.size()); + Flush(); +} + + + + + +void cProtocol125::SendEntityProperties(const cEntity & a_Entity) +{ + // Not supported in this protocol version +} + + + + + +void cProtocol125::SendEntityRelMove(const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ) +{ + ASSERT(a_Entity.GetUniqueID() != m_Client->GetPlayer()->GetUniqueID()); // Must not send for self + + cCSLock Lock(m_CSPacket); + WriteByte(PACKET_ENT_REL_MOVE); + WriteInt (a_Entity.GetUniqueID()); + WriteByte(a_RelX); + WriteByte(a_RelY); + WriteByte(a_RelZ); + Flush(); +} + + + + + +void cProtocol125::SendEntityRelMoveLook(const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ) +{ + ASSERT(a_Entity.GetUniqueID() != m_Client->GetPlayer()->GetUniqueID()); // Must not send for self + + 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.GetRotation() / 360.f) * 256)); + WriteByte((char)((a_Entity.GetPitch() / 360.f) * 256)); + Flush(); +} + + + + + +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); + Flush(); +} + + + + + +void cProtocol125::SendEntityVelocity(const cEntity & a_Entity) +{ + ASSERT(a_Entity.GetUniqueID() != m_Client->GetPlayer()->GetUniqueID()); // Must not send for self + + cCSLock Lock(m_CSPacket); + WriteByte(PACKET_ENTITY_VELOCITY); + WriteInt (a_Entity.GetUniqueID()); + WriteShort((short) (a_Entity.GetSpeedX() * 400)); //400 = 8000 / 20 + WriteShort((short) (a_Entity.GetSpeedY() * 400)); + WriteShort((short) (a_Entity.GetSpeedZ() * 400)); + Flush(); +} + + + + + +void cProtocol125::SendExplosion(double a_BlockX, double a_BlockY, double a_BlockZ, float a_Radius, const cVector3iArray & a_BlocksAffected, const Vector3d & a_PlayerMotion) +{ + cCSLock Lock(m_CSPacket); + WriteByte(PACKET_EXPLOSION); + WriteDouble (a_BlockX); + WriteDouble (a_BlockY); + WriteDouble (a_BlockZ); + WriteFloat (a_Radius); + WriteInt (a_BlocksAffected.size()); + for (cVector3iArray::const_iterator itr = a_BlocksAffected.begin(); itr != a_BlocksAffected.end(); ++itr) + { + WriteByte ((Byte)(itr->x - a_BlockX)); + WriteByte ((Byte)(itr->y - a_BlockY)); + WriteByte ((Byte)(itr->z - a_BlockZ)); + } + WriteFloat ((float)a_PlayerMotion.x); + WriteFloat ((float)a_PlayerMotion.y); + WriteFloat ((float)a_PlayerMotion.z); + Flush(); +} + + + + + +void cProtocol125::SendGameMode(eGameMode a_GameMode) +{ + cCSLock Lock(m_CSPacket); + WriteByte(PACKET_CHANGE_GAME_STATE); + WriteByte(3); + WriteByte((char)a_GameMode); + Flush(); +} + + + + + +void cProtocol125::SendHandshake(const AString & a_ConnectionHash) +{ + cCSLock Lock(m_CSPacket); + WriteByte (PACKET_HANDSHAKE); + WriteString(a_ConnectionHash); + Flush(); +} + + + + + +void cProtocol125::SendHealth(void) +{ + cCSLock Lock(m_CSPacket); + WriteByte (PACKET_UPDATE_HEALTH); + WriteShort((short)m_Client->GetPlayer()->GetHealth()); + WriteShort(m_Client->GetPlayer()->GetFoodLevel()); + WriteFloat((float)m_Client->GetPlayer()->GetFoodSaturationLevel()); + Flush(); +} + + + + + +void cProtocol125::SendInventoryProgress(char a_WindowID, short a_ProgressBar, short a_Value) +{ + cCSLock Lock(m_CSPacket); + WriteByte (PACKET_INVENTORY_PROGRESS); + WriteByte (a_WindowID); + WriteShort(a_ProgressBar); + WriteShort(a_Value); + Flush(); +} + + + + + +void cProtocol125::SendInventorySlot(char a_WindowID, short a_SlotNum, const cItem & a_Item) +{ + cCSLock Lock(m_CSPacket); + WriteByte (PACKET_INVENTORY_SLOT); + WriteByte (a_WindowID); + WriteShort(a_SlotNum); + WriteItem (a_Item); + Flush(); +} + + + + + +void cProtocol125::SendKeepAlive(int a_PingID) +{ + cCSLock Lock(m_CSPacket); + WriteByte(PACKET_KEEP_ALIVE); + WriteInt (a_PingID); + Flush(); +} + + + + + +void cProtocol125::SendLogin(const cPlayer & a_Player, const cWorld & a_World) +{ + UNUSED(a_World); + cCSLock Lock(m_CSPacket); + + WriteByte (PACKET_LOGIN); + WriteInt (a_Player.GetUniqueID()); // EntityID of the player + WriteString(""); // Username, not used + WriteString("default"); // Level type + WriteInt ((int)a_Player.GetGameMode()); + WriteInt ((int)(a_World.GetDimension())); + WriteByte (2); // TODO: Difficulty + WriteByte (0); // Unused + WriteByte (60); // Client list width or something + 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); + WriteShort (a_Pickup.GetItem().m_ItemDamage); + 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)); + Flush(); +} + + + + + +void cProtocol125::SendPlayerAnimation(const cPlayer & a_Player, char a_Animation) +{ + cCSLock Lock(m_CSPacket); + WriteByte(PACKET_ANIMATION); + WriteInt (a_Player.GetUniqueID()); + WriteByte(a_Animation); + Flush(); +} + + + + + +void cProtocol125::SendPlayerListItem(const cPlayer & a_Player, bool a_IsOnline) +{ + cCSLock Lock(m_CSPacket); + AString PlayerName(a_Player.GetColor()); + PlayerName.append(a_Player.GetName()); + if (PlayerName.length() > 14) + { + PlayerName.erase(14); + } + PlayerName += cChatColor::White; + + WriteByte ((unsigned char)PACKET_PLAYER_LIST_ITEM); + WriteString(PlayerName); + WriteBool (a_IsOnline); + WriteShort (a_Player.GetClientHandle()->GetPing()); + Flush(); +} + + + + + +void cProtocol125::SendPlayerMaxSpeed(void) +{ + // Not supported by this protocol version +} + + + + + +void cProtocol125::SendPlayerMoveLook(void) +{ + cCSLock Lock(m_CSPacket); + + /* + LOGD("Sending PlayerMoveLook: {%0.2f, %0.2f, %0.2f}, stance %0.2f, OnGround: %d", + m_Player->GetPosX(), m_Player->GetPosY(), m_Player->GetPosZ(), m_Player->GetStance(), m_Player->IsOnGround() ? 1 : 0 + ); + */ + + WriteByte (PACKET_PLAYER_MOVE_LOOK); + cPlayer * Player = m_Client->GetPlayer(); + WriteDouble(Player->GetPosX()); + WriteDouble(Player->GetStance() + 0.03); // Add a small amount so that the player doesn't start inside a block + WriteDouble(Player->GetPosY() + 0.03); // Add a small amount so that the player doesn't start inside a block + WriteDouble(Player->GetPosZ()); + WriteFloat ((float)(Player->GetRotation())); + WriteFloat ((float)(Player->GetPitch())); + WriteBool (Player->IsOnGround()); + Flush(); +} + + + + + +void cProtocol125::SendPlayerPosition(void) +{ + cCSLock Lock(m_CSPacket); + LOGD("Ignore send PlayerPos"); // PlayerPos is a C->S packet only now +} + + + + + +void cProtocol125::SendPlayerSpawn(const cPlayer & a_Player) +{ + const cItem & HeldItem = a_Player.GetEquippedItem(); + cCSLock Lock(m_CSPacket); + WriteByte (PACKET_PLAYER_SPAWN); + WriteInt (a_Player.GetUniqueID()); + WriteString(a_Player.GetName()); + WriteInt ((int)(a_Player.GetPosX() * 32)); + WriteInt ((int)(a_Player.GetPosY() * 32)); + WriteInt ((int)(a_Player.GetPosZ() * 32)); + WriteByte ((char)((a_Player.GetRot().x / 360.f) * 256)); + WriteByte ((char)((a_Player.GetRot().y / 360.f) * 256)); + WriteShort (HeldItem.IsEmpty() ? 0 : HeldItem.m_ItemType); + Flush(); +} + + + + + +void cProtocol125::SendRespawn(void) +{ + cCSLock Lock(m_CSPacket); + WriteByte (PACKET_RESPAWN); + WriteInt ((int)(m_Client->GetPlayer()->GetWorld()->GetDimension())); + WriteByte (2); // TODO: Difficulty; 2 = Normal + WriteByte ((char)m_Client->GetPlayer()->GetGameMode()); + WriteShort (256); // Current world height + WriteString("default"); +} + + + + + +void cProtocol125::SendSoundEffect(const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch) +{ + // Not needed in this protocol version +} + + + + + +void cProtocol125::SendSoundParticleEffect(int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data) +{ + // Not implemented in this protocol version +} + + + + + +void cProtocol125::SendSpawnFallingBlock(const cFallingBlock & a_FallingBlock) +{ + // This protocol version implements falling blocks using the spawn object / vehicle packet: + SendSpawnObject(a_FallingBlock, 70, a_FallingBlock.GetBlockType(), 0, 0); +} + + + + + +void cProtocol125::SendSpawnMob(const cMonster & a_Mob) +{ + cCSLock Lock(m_CSPacket); + WriteByte (PACKET_SPAWN_MOB); + WriteInt (a_Mob.GetUniqueID()); + WriteByte (a_Mob.GetMobType()); + WriteVectorI((Vector3i)(a_Mob.GetPosition() * 32)); + WriteByte (0); + WriteByte (0); + WriteByte (0); + AString MetaData = GetEntityMetaData(a_Mob); + SendData (MetaData.data(), MetaData.size()); + Flush(); +} + + + + + +void cProtocol125::SendSpawnObject(const cEntity & a_Entity, char a_ObjectType, int a_ObjectData, Byte a_Yaw, Byte a_Pitch) +{ + UNUSED(a_Yaw); + UNUSED(a_Pitch); + + cCSLock Lock(m_CSPacket); + WriteByte(PACKET_SPAWN_OBJECT); + WriteInt (a_Entity.GetUniqueID()); + WriteByte(a_ObjectType); + WriteInt ((int)(a_Entity.GetPosX() * 32)); + WriteInt ((int)(a_Entity.GetPosY() * 32)); + WriteInt ((int)(a_Entity.GetPosZ() * 32)); + WriteByte(a_Pitch); + WriteByte(a_Yaw); + WriteInt (a_ObjectData); + if (a_ObjectData != 0) + { + WriteShort((short)(a_Entity.GetSpeedX() * 400)); + WriteShort((short)(a_Entity.GetSpeedY() * 400)); + WriteShort((short)(a_Entity.GetSpeedZ() * 400)); + } + Flush(); +} + + + + + +void cProtocol125::SendSpawnVehicle(const cEntity & a_Vehicle, char a_VehicleType) +{ + cCSLock Lock(m_CSPacket); + WriteByte (PACKET_SPAWN_OBJECT); + WriteInt (a_Vehicle.GetUniqueID()); + WriteByte (a_VehicleType); + WriteInt ((int)(a_Vehicle.GetPosX() * 32)); + WriteInt ((int)(a_Vehicle.GetPosY() * 32)); + WriteInt ((int)(a_Vehicle.GetPosZ() * 32)); + WriteByte ((Byte)((a_Vehicle.GetPitch() / 360.f) * 256)); + WriteByte ((Byte)((a_Vehicle.GetRotation() / 360.f) * 256)); + WriteInt (1); + WriteShort((short)(a_Vehicle.GetSpeedX() * 400)); + WriteShort((short)(a_Vehicle.GetSpeedY() * 400)); + WriteShort((short)(a_Vehicle.GetSpeedZ() * 400)); + Flush(); +} + + + + + +void cProtocol125::SendTeleportEntity(const cEntity & a_Entity) +{ + cCSLock Lock(m_CSPacket); + WriteByte (PACKET_ENT_TELEPORT); + WriteInt (a_Entity.GetUniqueID()); + 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.GetRotation() / 360.f) * 256)); + WriteByte ((char)((a_Entity.GetPitch() / 360.f) * 256)); + Flush(); +} + + + + + +void cProtocol125::SendThunderbolt(int a_BlockX, int a_BlockY, int a_BlockZ) +{ + cCSLock Lock(m_CSPacket); + WriteByte(PACKET_THUNDERBOLT); + WriteInt (0x7fffffff); // Entity ID of the thunderbolt; we use a constant one + WriteBool(true); // Unknown bool + WriteInt (a_BlockX * 32); + WriteInt (a_BlockY * 32); + WriteInt (a_BlockZ * 32); + Flush(); +} + + + + + +void cProtocol125::SendTimeUpdate(Int64 a_WorldAge, Int64 a_TimeOfDay) +{ + cCSLock Lock(m_CSPacket); + WriteByte (PACKET_UPDATE_TIME); + // Use a_WorldAge for daycount, and a_TimeOfDay for the proper time of day: + WriteInt64((24000 * (a_WorldAge / 24000)) + (a_TimeOfDay % 24000)); + Flush(); +} + + + + + +void cProtocol125::SendUnloadChunk(int a_ChunkX, int a_ChunkZ) +{ + cCSLock Lock(m_CSPacket); + SendPreChunk(a_ChunkX, a_ChunkZ, false); +} + + + + + +void cProtocol125::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 +) +{ + cCSLock Lock(m_CSPacket); + WriteByte ((unsigned char)PACKET_UPDATE_SIGN); + WriteInt (a_BlockX); + WriteShort ((short)a_BlockY); + WriteInt (a_BlockZ); + WriteString(a_Line1); + WriteString(a_Line2); + WriteString(a_Line3); + WriteString(a_Line4); + Flush(); +} + + + + + +void cProtocol125::SendUseBed(const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ ) +{ + cCSLock Lock(m_CSPacket); + WriteByte(PACKET_USE_BED); + WriteInt (a_Entity.GetUniqueID()); + WriteByte(0); // Unknown byte only 0 has been observed + WriteInt (a_BlockX); + WriteByte(a_BlockY); + WriteInt (a_BlockZ); + Flush(); +} + + + + + +void cProtocol125::SendWeather(eWeather a_Weather) +{ + cCSLock Lock(m_CSPacket); + switch( a_Weather ) + { + case eWeather_Sunny: + { + WriteByte(PACKET_CHANGE_GAME_STATE); + WriteByte(2); // Stop rain + WriteByte(0); // Unused + Flush(); + break; + } + + case eWeather_Rain: + case eWeather_ThunderStorm: + { + WriteByte(PACKET_CHANGE_GAME_STATE); + WriteByte(1); // Begin rain + WriteByte(0); // Unused + Flush(); + break; + } + } +} + + + + + +void cProtocol125::SendWholeInventory(const cInventory & a_Inventory) +{ + SendWholeInventory(*(a_Inventory.GetOwner().GetWindow())); +} + + + + + +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])); +} + + + + + +void cProtocol125::SendWindowClose(const cWindow & a_Window) +{ + if (a_Window.GetWindowType() == cWindow::Inventory) + { + // Do not send inventory-window-close + return; + } + + cCSLock Lock(m_CSPacket); + WriteByte(PACKET_WINDOW_CLOSE); + WriteByte(a_Window.GetWindowID()); + Flush(); +} + + + + + +void cProtocol125::SendWindowOpen(char a_WindowID, char a_WindowType, const AString & a_WindowTitle, char a_NumSlots) +{ + if (a_WindowType < 0) + { + // Do not send for inventory windows + return; + } + cCSLock Lock(m_CSPacket); + WriteByte (PACKET_WINDOW_OPEN); + WriteByte (a_WindowID); + WriteByte (a_WindowType); + WriteString(a_WindowTitle); + WriteByte (a_NumSlots); + Flush(); +} + + + + + +AString cProtocol125::GetAuthServerID(void) +{ + // http://wiki.vg/wiki/index.php?title=Session&oldid=2262 + // The server generates a random hash and that is used for all clients, unmodified + return cRoot::Get()->GetServer()->GetServerID(); +} + + + + + +void cProtocol125::SendData(const char * a_Data, int a_Size) +{ + m_Client->SendData(a_Data, a_Size); +} + + + + + +void cProtocol125::DataReceived(const char * a_Data, int a_Size) +{ + if (!m_ReceivedData.Write(a_Data, a_Size)) + { + // Too much data in the incoming queue, report to caller: + m_Client->PacketBufferFull(); + return; + } + + // Parse and handle all complete packets in m_ReceivedData: + while (m_ReceivedData.CanReadBytes(1)) + { + unsigned char PacketType; + m_ReceivedData.ReadByte(PacketType); + switch (ParsePacket(PacketType)) + { + case PARSE_UNKNOWN: + { + // An unknown packet has been received, notify the client and abort: + m_Client->PacketUnknown(PacketType); + return; + } + case PARSE_ERROR: + { + // An error occurred while parsing a known packet, notify the client and abort: + m_Client->PacketError(PacketType); + return; + } + case PARSE_INCOMPLETE: + { + // Incomplete packet, bail out and process with the next batch of data + m_ReceivedData.ResetRead(); + return; + } + default: + { + // Packet successfully parsed, commit the read data and try again one more packet + m_ReceivedData.CommitRead(); + break; + } + } + } +} + + + + + +int cProtocol125::ParsePacket(unsigned char a_PacketType) +{ + switch (a_PacketType) + { + default: return PARSE_UNKNOWN; + case PACKET_ANIMATION: return ParseArmAnim(); + case PACKET_BLOCK_DIG: return ParseBlockDig(); + case PACKET_BLOCK_PLACE: return ParseBlockPlace(); + case PACKET_CHAT: return ParseChat(); + case PACKET_CREATIVE_INVENTORY_ACTION: return ParseCreativeInventoryAction(); + case PACKET_DISCONNECT: return ParseDisconnect(); + case PACKET_HANDSHAKE: return ParseHandshake(); + case PACKET_KEEP_ALIVE: return ParseKeepAlive(); + case PACKET_LOGIN: return ParseLogin(); + case PACKET_PACKET_ENTITY_ACTION: return ParseEntityAction(); + case PACKET_PING: return ParsePing(); + case PACKET_PLAYER_ABILITIES: return ParsePlayerAbilities(); + case PACKET_PLAYER_LOOK: return ParsePlayerLook(); + case PACKET_PLAYER_MOVE_LOOK: return ParsePlayerMoveLook(); + case PACKET_PLAYER_ON_GROUND: return ParsePlayerOnGround(); + case PACKET_PLAYER_POS: return ParsePlayerPosition(); + case PACKET_PLUGIN_MESSAGE: return ParsePluginMessage(); + case PACKET_RESPAWN: return ParseRespawn(); + case PACKET_SLOT_SELECTED: return ParseSlotSelected(); + case PACKET_UPDATE_SIGN: return ParseUpdateSign(); + case PACKET_USE_ENTITY: return ParseUseEntity(); + case PACKET_WINDOW_CLICK: return ParseWindowClick(); + case PACKET_WINDOW_CLOSE: return ParseWindowClose(); + } +} + + + + + +#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); + HANDLE_PACKET_READ(ReadChar, char, Animation); + m_Client->HandleAnimation(Animation); + return PARSE_OK; +} + + + + + +int cProtocol125::ParseBlockDig(void) +{ + HANDLE_PACKET_READ(ReadChar, char, Status); + HANDLE_PACKET_READ(ReadBEInt, int, PosX); + 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); + return PARSE_OK; +} + + + + + +int cProtocol125::ParseBlockPlace(void) +{ + HANDLE_PACKET_READ(ReadBEInt, int, PosX); + HANDLE_PACKET_READ(ReadByte, Byte, PosY); + HANDLE_PACKET_READ(ReadBEInt, int, PosZ); + HANDLE_PACKET_READ(ReadChar, char, BlockFace); + + cItem HeldItem; + int res = ParseItem(HeldItem); + if (res < 0) + { + return res; + } + + // 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); + return PARSE_OK; +} + + + + + +int cProtocol125::ParseChat(void) +{ + HANDLE_PACKET_READ(ReadBEUTF16String16, AString, Message); + m_Client->HandleChat(Message); + return PARSE_OK; +} + + + + + +int cProtocol125::ParseCreativeInventoryAction(void) +{ + HANDLE_PACKET_READ(ReadBEShort, short, SlotNum); + cItem HeldItem; + int res = ParseItem(HeldItem); + if (res < 0) + { + return res; + } + m_Client->HandleCreativeInventory(SlotNum, HeldItem); + return PARSE_OK; +} + + + + + +int cProtocol125::ParseDisconnect(void) +{ + HANDLE_PACKET_READ(ReadBEUTF16String16, AString, Reason); + m_Client->HandleDisconnect(Reason); + return PARSE_OK; +} + + + + + +int cProtocol125::ParseEntityAction(void) +{ + HANDLE_PACKET_READ(ReadBEInt, int, EntityID); + HANDLE_PACKET_READ(ReadChar, char, ActionID); + m_Client->HandleEntityAction(EntityID, ActionID); + return PARSE_OK; +} + + + + + +int cProtocol125::ParseHandshake(void) +{ + HANDLE_PACKET_READ(ReadBEUTF16String16, AString, Username); + + AStringVector UserData = StringSplit(Username, ";"); // "FakeTruth;localhost:25565" + if (UserData.empty()) + { + m_Client->Kick("Did not receive username"); + return PARSE_OK; + } + m_Username = UserData[0]; + + LOGD("HANDSHAKE %s", Username.c_str()); + + if (!m_Client->HandleHandshake( m_Username )) + { + return PARSE_OK; // Player is not allowed into the server + } + + SendHandshake(cRoot::Get()->GetServer()->GetServerID()); + LOGD("User \"%s\" was sent a handshake response", m_Username.c_str()); + + return PARSE_OK; +} + + + + + +int cProtocol125::ParseKeepAlive(void) +{ + HANDLE_PACKET_READ(ReadBEInt, int, KeepAliveID); + m_Client->HandleKeepAlive(KeepAliveID); + return PARSE_OK; +} + + + + + +int cProtocol125::ParseLogin(void) +{ + HANDLE_PACKET_READ(ReadBEInt, int, ProtocolVersion); + HANDLE_PACKET_READ(ReadBEUTF16String16, AString, Username); + HANDLE_PACKET_READ(ReadBEUTF16String16, AString, LevelType); + HANDLE_PACKET_READ(ReadBEInt, int, ServerMode); + HANDLE_PACKET_READ(ReadBEInt, int, Dimension); + HANDLE_PACKET_READ(ReadChar, char, Difficulty); + HANDLE_PACKET_READ(ReadByte, Byte, WorldHeight); + HANDLE_PACKET_READ(ReadByte, Byte, MaxPlayers); + + if (ProtocolVersion < 29) + { + m_Client->Kick("Your client is outdated!"); + return PARSE_OK; + } + else if (ProtocolVersion > 29) + { + m_Client->Kick("Your client version is higher than the server!"); + return PARSE_OK; + } + + if (m_Username.compare(Username) != 0) + { + LOGWARNING("Login Username (\"%s\") does not match Handshake username (\"%s\") for client @ \"%s\", kicking", + Username.c_str(), + m_Username.c_str(), + m_Client->GetIPString().c_str() + ); + m_Client->Kick("Hacked client"); // Don't tell them why we don't want them + return PARSE_OK; + } + + m_Client->HandleLogin(ProtocolVersion, Username); + return PARSE_OK; +} + + + + + +int cProtocol125::ParsePing(void) +{ + // Packet has no more data + m_Client->HandlePing(); + return PARSE_OK; +} + + + + + + +int cProtocol125::ParsePlayerAbilities(void) +{ + HANDLE_PACKET_READ(ReadBool, bool, Invulnerable); + HANDLE_PACKET_READ(ReadBool, bool, IsFlying); + HANDLE_PACKET_READ(ReadBool, bool, CanFly); + HANDLE_PACKET_READ(ReadBool, bool, InstaMine); + // TODO: m_Client->HandlePlayerAbilities(...); + return PARSE_OK; +} + + + + + +int cProtocol125::ParsePlayerLook(void) +{ + HANDLE_PACKET_READ(ReadBEFloat, float, Rotation); + HANDLE_PACKET_READ(ReadBEFloat, float, Pitch); + HANDLE_PACKET_READ(ReadBool, bool, IsOnGround); + m_Client->HandlePlayerLook(Rotation, Pitch, IsOnGround); + return PARSE_OK; +} + + + + + +int cProtocol125::ParsePlayerMoveLook(void) +{ + HANDLE_PACKET_READ(ReadBEDouble, double, PosX); + HANDLE_PACKET_READ(ReadBEDouble, double, PosY); + HANDLE_PACKET_READ(ReadBEDouble, double, Stance); + HANDLE_PACKET_READ(ReadBEDouble, double, PosZ); + HANDLE_PACKET_READ(ReadBEFloat, float, Rotation); + HANDLE_PACKET_READ(ReadBEFloat, float, Pitch); + HANDLE_PACKET_READ(ReadBool, bool, IsOnGround); + // LOGD("Recv PML: {%0.2f, %0.2f, %0.2f}, Stance %0.2f, Gnd: %d", PosX, PosY, PosZ, Stance, IsOnGround ? 1 : 0); + m_Client->HandlePlayerMoveLook(PosX, PosY, PosZ, Stance, Rotation, Pitch, IsOnGround); + return PARSE_OK; +} + + + + + +int cProtocol125::ParsePlayerOnGround(void) +{ + HANDLE_PACKET_READ(ReadBool, bool, IsOnGround); + // TODO: m_Client->HandleFlying(IsOnGround); + return PARSE_OK; +} + + + + + +int cProtocol125::ParsePlayerPosition(void) +{ + HANDLE_PACKET_READ(ReadBEDouble, double, PosX); + HANDLE_PACKET_READ(ReadBEDouble, double, PosY); + HANDLE_PACKET_READ(ReadBEDouble, double, Stance); + HANDLE_PACKET_READ(ReadBEDouble, double, PosZ); + HANDLE_PACKET_READ(ReadBool, bool, IsOnGround); + m_Client->HandlePlayerPos(PosX, PosY, PosZ, Stance, IsOnGround); + return PARSE_OK; +} + + + + + +int cProtocol125::ParsePluginMessage(void) +{ + HANDLE_PACKET_READ(ReadBEUTF16String16, AString, ChannelName); + HANDLE_PACKET_READ(ReadBEShort, short, Length); + AString Data; + if (!m_ReceivedData.ReadString(Data, Length)) + { + m_ReceivedData.CheckValid(); + return PARSE_INCOMPLETE; + } + m_ReceivedData.CheckValid(); + + // TODO: Process the data + LOGD("Received %d bytes of plugin data on channel \"%s\".", Length, ChannelName.c_str()); + + return PARSE_OK; +} + + + + + +int cProtocol125::ParseRespawn(void) +{ + HANDLE_PACKET_READ(ReadBEInt, int, Dimension); + HANDLE_PACKET_READ(ReadChar, char, Difficulty); + HANDLE_PACKET_READ(ReadChar, char, CreativeMode); + HANDLE_PACKET_READ(ReadBEShort, short, WorldHeight); + HANDLE_PACKET_READ(ReadBEUTF16String16, AString, LevelType); + m_Client->HandleRespawn(); + return PARSE_OK; +} + + + + + +int cProtocol125::ParseSlotSelected(void) +{ + HANDLE_PACKET_READ(ReadBEShort, short, SlotNum); + m_Client->HandleSlotSelected(SlotNum); + return PARSE_OK; +} + + + + + +int cProtocol125::ParseUpdateSign(void) +{ + HANDLE_PACKET_READ(ReadBEInt, int, BlockX); + HANDLE_PACKET_READ(ReadBEShort, short, BlockY); + HANDLE_PACKET_READ(ReadBEInt, int, BlockZ); + HANDLE_PACKET_READ(ReadBEUTF16String16, AString, Line1); + HANDLE_PACKET_READ(ReadBEUTF16String16, AString, Line2); + HANDLE_PACKET_READ(ReadBEUTF16String16, AString, Line3); + HANDLE_PACKET_READ(ReadBEUTF16String16, AString, Line4); + m_Client->HandleUpdateSign(BlockX, BlockY, BlockZ, Line1, Line2, Line3, Line4); + return PARSE_OK; +} + + + + + +int cProtocol125::ParseUseEntity(void) +{ + HANDLE_PACKET_READ(ReadBEInt, int, SourceEntityID); + HANDLE_PACKET_READ(ReadBEInt, int, TargetEntityID); + HANDLE_PACKET_READ(ReadBool, bool, IsLeftClick); + m_Client->HandleUseEntity(TargetEntityID, IsLeftClick); + return PARSE_OK; +} + + + + + +int cProtocol125::ParseWindowClick(void) +{ + HANDLE_PACKET_READ(ReadChar, char, WindowID); + HANDLE_PACKET_READ(ReadBEShort, short, SlotNum); + HANDLE_PACKET_READ(ReadBool, bool, IsRightClick); + HANDLE_PACKET_READ(ReadBEShort, short, TransactionID); + HANDLE_PACKET_READ(ReadBool, bool, IsShiftPressed); + cItem HeldItem; + int res = ParseItem(HeldItem); + if (res < 0) + { + return res; + } + + // Convert IsShiftPressed, IsRightClick, SlotNum and HeldItem into eClickAction used in the newer protocols: + eClickAction Action; + if (IsRightClick) + { + if (IsShiftPressed) + { + Action = caShiftRightClick; + } + else + { + if (SlotNum == -999) + { + Action = (HeldItem.IsEmpty()) ? caRightClickOutsideHoldNothing : caRightClickOutside; + } + else + { + Action = caRightClick; + } + } + } + else + { + // IsLeftClick + if (IsShiftPressed) + { + Action = caShiftLeftClick; + } + else + { + if (SlotNum == -999) + { + Action = (HeldItem.IsEmpty()) ? caLeftClickOutsideHoldNothing : caRightClickOutside; + } + else + { + Action = caLeftClick; + } + } + } + m_Client->HandleWindowClick(WindowID, SlotNum, Action, HeldItem); + return PARSE_OK; +} + + + + + +int cProtocol125::ParseWindowClose(void) +{ + HANDLE_PACKET_READ(ReadChar, char, WindowID); + m_Client->HandleWindowClose(WindowID); + return PARSE_OK; +} + + + + + +void cProtocol125::SendPreChunk(int a_ChunkX, int a_ChunkZ, bool a_ShouldLoad) +{ + WriteByte(PACKET_PRE_CHUNK); + WriteInt (a_ChunkX); + WriteInt (a_ChunkZ); + WriteBool(a_ShouldLoad); + Flush(); +} + + + + + +void cProtocol125::SendWindowSlots(char a_WindowID, int a_NumItems, const cItem * a_Items) +{ + WriteByte (PACKET_INVENTORY_WHOLE); + WriteByte (a_WindowID); + WriteShort((short)a_NumItems); + + for (int j = 0; j < a_NumItems; j++) + { + WriteItem(a_Items[j]); + } + Flush(); +} + + + + + +void cProtocol125::WriteItem(const cItem & a_Item) +{ + short ItemType = a_Item.m_ItemType; + ASSERT(ItemType >= -1); // Check validity of packets in debug runtime + if (ItemType <= 0) + { + // Fix, to make sure no invalid values are sent. + ItemType = -1; + } + + WriteShort(ItemType); + if (a_Item.IsEmpty()) + { + return; + } + + WriteByte (a_Item.m_ItemCount); + WriteShort(a_Item.m_ItemDamage); + + if (cItem::IsEnchantable(a_Item.m_ItemType)) + { + // TODO: Implement enchantments + WriteShort(-1); + } +} + + + + + +int cProtocol125::ParseItem(cItem & a_Item) +{ + HANDLE_PACKET_READ(ReadBEShort, short, ItemType); + + if (ItemType <= -1) + { + a_Item.Empty(); + return PARSE_OK; + } + a_Item.m_ItemType = ItemType; + + HANDLE_PACKET_READ(ReadChar, char, ItemCount); + HANDLE_PACKET_READ(ReadBEShort, short, ItemDamage); + a_Item.m_ItemCount = ItemCount; + a_Item.m_ItemDamage = ItemDamage; + if (ItemCount <= 0) + { + a_Item.Empty(); + } + + if (!cItem::IsEnchantable(ItemType)) + { + return PARSE_OK; + } + + HANDLE_PACKET_READ(ReadBEShort, short, EnchantNumBytes); + + if (EnchantNumBytes <= 0) + { + return PARSE_OK; + } + + // TODO: Enchantment not implemented yet! + if (!m_ReceivedData.SkipRead(EnchantNumBytes)) + { + return PARSE_INCOMPLETE; + } + + return PARSE_OK; +} + + + + + +AString cProtocol125::GetEntityMetaData(const cEntity & a_Entity) +{ + // We should send all the metadata here + AString MetaData; + // Common metadata (index 0, byte): + MetaData.push_back(0); + MetaData.push_back(GetEntityMetadataFlags(a_Entity)); + + // TODO: Add more entity-specific metadata + + MetaData.push_back(0x7f); // End metadata + return MetaData; +} + + + + + +char cProtocol125::GetEntityMetadataFlags(const cEntity & a_Entity) +{ + char Flags = 0; + if (a_Entity.IsOnFire()) + { + Flags |= 1; + } + if (a_Entity.IsCrouched()) + { + Flags |= 2; + } + if (a_Entity.IsRiding()) + { + Flags |= 4; + } + if (a_Entity.IsSprinting()) + { + Flags |= 8; + } + if (a_Entity.IsRclking()) + { + Flags |= 16; + } + return Flags; +} + + + + diff --git a/source/Protocol/Protocol125.h b/source/Protocol/Protocol125.h index 2f769f362..2e4f80902 100644 --- a/source/Protocol/Protocol125.h +++ b/source/Protocol/Protocol125.h @@ -1,152 +1,152 @@ -
-// Protocol125.h
-
-// Interfaces to the cProtocol125 class representing the release 1.2.5 protocol (#29)
-
-
-
-
-
-#pragma once
-
-#include "Protocol.h"
-#include "../ByteBuffer.h"
-
-
-
-
-
-class cProtocol125 :
- public cProtocol
-{
- typedef cProtocol super;
-public:
- cProtocol125(cClientHandle * a_Client);
-
- /// Called when client sends some data:
- virtual void DataReceived(const char * a_Data, int a_Size) override;
-
- /// Sending stuff to clients (alphabetically sorted):
- virtual void SendAttachEntity (const cEntity & a_Entity, const cEntity * a_Vehicle) override;
- virtual void SendBlockAction (int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType) override;
- virtual void SendBlockBreakAnim (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 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;
- virtual void SendDisconnect (const AString & a_Reason) override;
- virtual void SendEntityEquipment (const cEntity & a_Entity, short a_SlotNum, const cItem & a_Item) override;
- virtual void SendEntityHeadLook (const cEntity & a_Entity) override;
- virtual void SendEntityLook (const cEntity & a_Entity) override;
- virtual void SendEntityMetadata (const cEntity & a_Entity) override;
- virtual void SendEntityProperties (const cEntity & a_Entity) override;
- virtual void SendEntityRelMove (const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ) override;
- virtual void SendEntityRelMoveLook (const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ) override;
- virtual void SendEntityStatus (const cEntity & a_Entity, char a_Status) override;
- virtual void SendEntityVelocity (const cEntity & a_Entity) override;
- virtual void SendExplosion (double a_BlockX, double a_BlockY, double a_BlockZ, float a_Radius, const cVector3iArray & a_BlocksAffected, const Vector3d & a_PlayerMotion) override;
- virtual void SendGameMode (eGameMode a_GameMode) override;
- virtual void SendHealth (void) override;
- virtual void SendInventoryProgress (char a_WindowID, short a_Progressbar, short a_Value) override;
- 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 SendPickupSpawn (const cPickup & a_Pickup) override;
- virtual void SendPlayerAnimation (const cPlayer & a_Player, char a_Animation) override;
- virtual void SendPlayerListItem (const cPlayer & a_Player, bool a_IsOnline) override;
- virtual void SendPlayerMaxSpeed (void) override;
- virtual void SendPlayerMoveLook (void) override;
- virtual void SendPlayerPosition (void) override;
- virtual void SendPlayerSpawn (const cPlayer & a_Player) override;
- virtual void SendRespawn (void) override;
- 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;
- virtual void SendSpawnMob (const cMonster & a_Mob) override;
- virtual void SendSpawnObject (const cEntity & a_Entity, char a_ObjectType, int a_ObjectData, Byte a_Yaw, Byte a_Pitch) override;
- virtual void SendSpawnVehicle (const cEntity & a_Vehicle, char a_VehicleType) override;
- virtual void SendTeleportEntity (const cEntity & a_Entity) override;
- virtual void SendThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ) override;
- virtual void SendTimeUpdate (Int64 a_WorldAge, Int64 a_TimeOfDay) override;
- virtual void SendUnloadChunk (int a_ChunkX, int a_ChunkZ) override;
- virtual void SendUpdateSign (int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4) override;
- virtual void SendUseBed (const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ ) override;
- virtual void SendWeather (eWeather a_Weather) override;
- virtual void SendWholeInventory (const cInventory & a_Inventory) override;
- virtual void SendWholeInventory (const cWindow & a_Window) override;
- virtual void SendWindowClose (const cWindow & a_Window) override;
- virtual void SendWindowOpen (char a_WindowID, char a_WindowType, const AString & a_WindowTitle, char a_NumSlots) override;
-
- virtual AString GetAuthServerID(void) override;
-
-protected:
- /// Results of packet-parsing:
- enum {
- PARSE_OK = 1,
- PARSE_ERROR = -1,
- PARSE_UNKNOWN = -2,
- PARSE_INCOMPLETE = -3,
- } ;
-
- cByteBuffer m_ReceivedData; //< Buffer for the received data
-
- AString m_Username; //< Stored in ParseHandshake(), compared to Login username
-
- virtual void SendData(const char * a_Data, int a_Size) override;
-
- /// Sends the Handshake packet
- void SendHandshake(const AString & a_ConnectionHash);
-
- /// Parse the packet of the specified type from m_ReceivedData (switch into ParseXYZ() )
- virtual int ParsePacket(unsigned char a_PacketType);
-
- // Specific packet parsers:
- virtual int ParseArmAnim (void);
- virtual int ParseBlockDig (void);
- virtual int ParseBlockPlace (void);
- virtual int ParseChat (void);
- virtual int ParseCreativeInventoryAction(void);
- virtual int ParseDisconnect (void);
- virtual int ParseEntityAction (void);
- virtual int ParseHandshake (void);
- virtual int ParseKeepAlive (void);
- virtual int ParseLogin (void);
- virtual int ParsePing (void);
- virtual int ParsePlayerAbilities (void);
- virtual int ParsePlayerLook (void);
- virtual int ParsePlayerMoveLook (void);
- virtual int ParsePlayerOnGround (void);
- virtual int ParsePlayerPosition (void);
- virtual int ParsePluginMessage (void);
- virtual int ParseRespawn (void);
- virtual int ParseSlotSelected (void);
- virtual int ParseUpdateSign (void);
- virtual int ParseUseEntity (void);
- virtual int ParseWindowClick (void);
- virtual int ParseWindowClose (void);
-
- // Utility functions:
- /// Writes a "pre-chunk" packet
- void SendPreChunk(int a_ChunkX, int a_ChunkZ, bool a_ShouldLoad);
-
- /// Writes a "set window items" packet with the specified params
- void SendWindowSlots(char a_WindowID, int a_NumItems, const cItem * a_Items);
-
- /// Writes one item, "slot" as the protocol wiki calls it
- virtual void WriteItem(const cItem & a_Item);
-
- /// Parses one item, "slot" as the protocol wiki calls it, from m_ReceivedData; returns the usual ParsePacket() codes
- virtual int ParseItem(cItem & a_Item);
-
- /// Returns the entity metadata representation
- AString GetEntityMetaData(const cEntity & a_Entity);
-
- /// Returns the entity common metadata, index 0 (generic flags)
- char GetEntityMetadataFlags(const cEntity & a_Entity);
-} ;
-
-
-
-
+ +// Protocol125.h + +// Interfaces to the cProtocol125 class representing the release 1.2.5 protocol (#29) + + + + + +#pragma once + +#include "Protocol.h" +#include "../ByteBuffer.h" + + + + + +class cProtocol125 : + public cProtocol +{ + typedef cProtocol super; +public: + cProtocol125(cClientHandle * a_Client); + + /// Called when client sends some data: + virtual void DataReceived(const char * a_Data, int a_Size) override; + + /// Sending stuff to clients (alphabetically sorted): + virtual void SendAttachEntity (const cEntity & a_Entity, const cEntity * a_Vehicle) override; + virtual void SendBlockAction (int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType) override; + virtual void SendBlockBreakAnim (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 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; + virtual void SendDisconnect (const AString & a_Reason) override; + virtual void SendEntityEquipment (const cEntity & a_Entity, short a_SlotNum, const cItem & a_Item) override; + virtual void SendEntityHeadLook (const cEntity & a_Entity) override; + virtual void SendEntityLook (const cEntity & a_Entity) override; + virtual void SendEntityMetadata (const cEntity & a_Entity) override; + virtual void SendEntityProperties (const cEntity & a_Entity) override; + virtual void SendEntityRelMove (const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ) override; + virtual void SendEntityRelMoveLook (const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ) override; + virtual void SendEntityStatus (const cEntity & a_Entity, char a_Status) override; + virtual void SendEntityVelocity (const cEntity & a_Entity) override; + virtual void SendExplosion (double a_BlockX, double a_BlockY, double a_BlockZ, float a_Radius, const cVector3iArray & a_BlocksAffected, const Vector3d & a_PlayerMotion) override; + virtual void SendGameMode (eGameMode a_GameMode) override; + virtual void SendHealth (void) override; + virtual void SendInventoryProgress (char a_WindowID, short a_Progressbar, short a_Value) override; + 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 SendPickupSpawn (const cPickup & a_Pickup) override; + virtual void SendPlayerAnimation (const cPlayer & a_Player, char a_Animation) override; + virtual void SendPlayerListItem (const cPlayer & a_Player, bool a_IsOnline) override; + virtual void SendPlayerMaxSpeed (void) override; + virtual void SendPlayerMoveLook (void) override; + virtual void SendPlayerPosition (void) override; + virtual void SendPlayerSpawn (const cPlayer & a_Player) override; + virtual void SendRespawn (void) override; + 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; + virtual void SendSpawnMob (const cMonster & a_Mob) override; + virtual void SendSpawnObject (const cEntity & a_Entity, char a_ObjectType, int a_ObjectData, Byte a_Yaw, Byte a_Pitch) override; + virtual void SendSpawnVehicle (const cEntity & a_Vehicle, char a_VehicleType) override; + virtual void SendTeleportEntity (const cEntity & a_Entity) override; + virtual void SendThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ) override; + virtual void SendTimeUpdate (Int64 a_WorldAge, Int64 a_TimeOfDay) override; + virtual void SendUnloadChunk (int a_ChunkX, int a_ChunkZ) override; + virtual void SendUpdateSign (int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4) override; + virtual void SendUseBed (const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ ) override; + virtual void SendWeather (eWeather a_Weather) override; + virtual void SendWholeInventory (const cInventory & a_Inventory) override; + virtual void SendWholeInventory (const cWindow & a_Window) override; + virtual void SendWindowClose (const cWindow & a_Window) override; + virtual void SendWindowOpen (char a_WindowID, char a_WindowType, const AString & a_WindowTitle, char a_NumSlots) override; + + virtual AString GetAuthServerID(void) override; + +protected: + /// Results of packet-parsing: + enum { + PARSE_OK = 1, + PARSE_ERROR = -1, + PARSE_UNKNOWN = -2, + PARSE_INCOMPLETE = -3, + } ; + + cByteBuffer m_ReceivedData; //< Buffer for the received data + + AString m_Username; //< Stored in ParseHandshake(), compared to Login username + + virtual void SendData(const char * a_Data, int a_Size) override; + + /// Sends the Handshake packet + void SendHandshake(const AString & a_ConnectionHash); + + /// Parse the packet of the specified type from m_ReceivedData (switch into ParseXYZ() ) + virtual int ParsePacket(unsigned char a_PacketType); + + // Specific packet parsers: + virtual int ParseArmAnim (void); + virtual int ParseBlockDig (void); + virtual int ParseBlockPlace (void); + virtual int ParseChat (void); + virtual int ParseCreativeInventoryAction(void); + virtual int ParseDisconnect (void); + virtual int ParseEntityAction (void); + virtual int ParseHandshake (void); + virtual int ParseKeepAlive (void); + virtual int ParseLogin (void); + virtual int ParsePing (void); + virtual int ParsePlayerAbilities (void); + virtual int ParsePlayerLook (void); + virtual int ParsePlayerMoveLook (void); + virtual int ParsePlayerOnGround (void); + virtual int ParsePlayerPosition (void); + virtual int ParsePluginMessage (void); + virtual int ParseRespawn (void); + virtual int ParseSlotSelected (void); + virtual int ParseUpdateSign (void); + virtual int ParseUseEntity (void); + virtual int ParseWindowClick (void); + virtual int ParseWindowClose (void); + + // Utility functions: + /// Writes a "pre-chunk" packet + void SendPreChunk(int a_ChunkX, int a_ChunkZ, bool a_ShouldLoad); + + /// Writes a "set window items" packet with the specified params + void SendWindowSlots(char a_WindowID, int a_NumItems, const cItem * a_Items); + + /// Writes one item, "slot" as the protocol wiki calls it + virtual void WriteItem(const cItem & a_Item); + + /// Parses one item, "slot" as the protocol wiki calls it, from m_ReceivedData; returns the usual ParsePacket() codes + virtual int ParseItem(cItem & a_Item); + + /// Returns the entity metadata representation + AString GetEntityMetaData(const cEntity & a_Entity); + + /// Returns the entity common metadata, index 0 (generic flags) + char GetEntityMetadataFlags(const cEntity & a_Entity); +} ; + + + + diff --git a/source/Protocol/Protocol132.cpp b/source/Protocol/Protocol132.cpp index f34401b55..9a985ec1f 100644 --- a/source/Protocol/Protocol132.cpp +++ b/source/Protocol/Protocol132.cpp @@ -1,902 +1,902 @@ -
-// Protocol132.cpp
-
-// Implements the cProtocol132 class representing the release 1.3.2 protocol (#39)
-
-#include "Globals.h"
-#include "Protocol132.h"
-#include "../Root.h"
-#include "../Server.h"
-#include "../ClientHandle.h"
-#include "../../CryptoPP/randpool.h"
-#include "../Item.h"
-#include "ChunkDataSerializer.h"
-#include "../Player.h"
-#include "../Mobs/Monster.h"
-#include "../UI/Window.h"
-#include "../Pickup.h"
-#include "../WorldStorage/FastNBT.h"
-#include "../StringCompression.h"
-
-
-
-
-
-#define HANDLE_PACKET_READ(Proc, Type, Var) \
- Type Var; \
- { \
- if (!m_ReceivedData.Proc(Var)) \
- { \
- m_ReceivedData.CheckValid(); \
- return PARSE_INCOMPLETE; \
- } \
- m_ReceivedData.CheckValid(); \
- }
-
-
-
-
-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...
-
-
-
-
-
-enum
-{
- PACKET_KEEP_ALIVE = 0x00,
- PACKET_LOGIN = 0x01,
- PACKET_ENTITY_EQUIPMENT = 0x05,
- PACKET_COMPASS = 0x06,
- PACKET_PLAYER_SPAWN = 0x14,
- PACKET_COLLECT_PICKUP = 0x16,
- PACKET_SPAWN_MOB = 0x18,
- PACKET_DESTROY_ENTITIES = 0x1d,
- PACKET_CHUNK_DATA = 0x33,
- PACKET_BLOCK_CHANGE = 0x35,
- PACKET_BLOCK_ACTION = 0x36,
- PACKET_BLOCK_BREAK_ANIM = 0x37,
- PACKET_SOUND_EFFECT = 0x3e,
- PACKET_SOUND_PARTICLE_EFFECT = 0x3d,
- PACKET_LOCALE_VIEW_DISTANCE = 0xcc,
- PACKET_CLIENT_STATUSES = 0xcd,
- PACKET_ENCRYPTION_KEY_RESP = 0xfc,
-} ;
-
-
-
-
-
-// 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:
-
-cProtocol132::cProtocol132(cClientHandle * a_Client) :
- super(a_Client),
- m_IsEncrypted(false)
-{
-}
-
-
-
-
-
-cProtocol132::~cProtocol132()
-{
- if (!m_DataToSend.empty())
- {
- LOGD("There are %d unsent bytes while deleting cProtocol132", m_DataToSend.size());
- }
-}
-
-
-
-
-
-void cProtocol132::DataReceived(const char * a_Data, int a_Size)
-{
- if (m_IsEncrypted)
- {
- 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);
- super::DataReceived((const char *)Decrypted, NumBytes);
- a_Size -= NumBytes;
- a_Data += NumBytes;
- }
- }
- else
- {
- super::DataReceived(a_Data, a_Size);
- }
-}
-
-
-
-
-
-void cProtocol132::SendBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType)
-{
- cCSLock Lock(m_CSPacket);
- WriteByte (PACKET_BLOCK_ACTION);
- WriteInt (a_BlockX);
- WriteShort((short)a_BlockY);
- WriteInt (a_BlockZ);
- WriteByte (a_Byte1);
- WriteByte (a_Byte2);
- WriteShort(a_BlockType);
- Flush();
-}
-
-
-
-
-
-void cProtocol132::SendBlockBreakAnim(int a_entityID, int a_BlockX, int a_BlockY, int a_BlockZ, char stage)
-{
- cCSLock Lock(m_CSPacket);
- WriteByte (PACKET_BLOCK_BREAK_ANIM);
- WriteInt (a_entityID);
- WriteInt (a_BlockX);
- WriteInt (a_BlockY);
- WriteInt (a_BlockZ);
- WriteByte (stage);
- Flush();
-}
-
-
-
-
-
-void cProtocol132::SendBlockChange(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
-{
- cCSLock Lock(m_CSPacket);
- WriteByte (PACKET_BLOCK_CHANGE);
- WriteInt (a_BlockX);
- WriteByte ((unsigned char)a_BlockY);
- WriteInt (a_BlockZ);
- WriteShort(a_BlockType);
- WriteByte (a_BlockMeta);
- Flush();
-}
-
-
-
-
-
-void cProtocol132::SendChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer)
-{
- cCSLock Lock(m_CSPacket);
-
- // Pre-chunk not used in 1.3.2. Finally.
-
- // Send the chunk data:
- AString Serialized = a_Serializer.Serialize(cChunkDataSerializer::RELEASE_1_3_2);
- WriteByte(PACKET_CHUNK_DATA);
- WriteInt (a_ChunkX);
- WriteInt (a_ChunkZ);
- SendData(Serialized.data(), Serialized.size());
- Flush();
-}
-
-
-
-
-
-void cProtocol132::SendCollectPickup(const cPickup & a_Pickup, const cPlayer & a_Player)
-{
- cCSLock Lock(m_CSPacket);
- WriteByte(PACKET_COLLECT_PICKUP);
- WriteInt (a_Pickup.GetUniqueID());
- WriteInt (a_Player.GetUniqueID());
- Flush();
-
- // Also send the "pop" sound effect with a somewhat random pitch (fast-random using EntityID ;)
- SendSoundEffect(
- "random.pop",
- (int)(a_Pickup.GetPosX() * 8), (int)(a_Pickup.GetPosY() * 8), (int)(a_Pickup.GetPosZ() * 8),
- 0.5, (float)(0.75 + ((float)((a_Pickup.GetUniqueID() * 23) % 32)) / 64)
- );
-}
-
-
-
-
-
-void cProtocol132::SendDestroyEntity(const cEntity & a_Entity)
-{
- if (a_Entity.GetUniqueID() == m_Client->GetPlayer()->GetUniqueID())
- {
- // Do not send "destroy self" to the client, the client would crash (FS #254)
- return;
- }
-
- cCSLock Lock(m_CSPacket);
- WriteByte(PACKET_DESTROY_ENTITIES);
- WriteByte(1); // entity count
- WriteInt (a_Entity.GetUniqueID());
- Flush();
-}
-
-
-
-
-
-void cProtocol132::SendEntityEquipment(const cEntity & a_Entity, short a_SlotNum, const cItem & a_Item)
-{
- cCSLock Lock(m_CSPacket);
- WriteByte (PACKET_ENTITY_EQUIPMENT);
- WriteInt (a_Entity.GetUniqueID());
- WriteShort(a_SlotNum);
- WriteItem (a_Item);
- Flush();
-}
-
-
-
-
-
-void cProtocol132::SendLogin(const cPlayer & a_Player, const cWorld & a_World)
-{
- cCSLock Lock(m_CSPacket);
- WriteByte (PACKET_LOGIN);
- WriteInt (a_Player.GetUniqueID()); // EntityID of the player
- WriteString("default"); // Level type
- WriteByte ((int)a_Player.GetGameMode());
- WriteByte ((Byte)(a_World.GetDimension()));
- WriteByte (2); // TODO: Difficulty
- WriteByte (0); // Unused, used to be world height
- WriteByte (8); // Client list width or something
- Flush();
-
- SendCompass(a_World);
-
- // Send the initial position (so that confirmation works, FS #245):
- SendPlayerMoveLook();
-}
-
-
-
-
-
-void cProtocol132::SendPlayerSpawn(const cPlayer & a_Player)
-{
- const cItem & HeldItem = a_Player.GetEquippedItem();
- cCSLock Lock(m_CSPacket);
- WriteByte (PACKET_PLAYER_SPAWN);
- WriteInt (a_Player.GetUniqueID());
- WriteString(a_Player.GetName());
- WriteInt ((int)(a_Player.GetPosX() * 32));
- WriteInt ((int)(a_Player.GetPosY() * 32));
- WriteInt ((int)(a_Player.GetPosZ() * 32));
- WriteByte ((char)((a_Player.GetRot().x / 360.f) * 256));
- WriteByte ((char)((a_Player.GetRot().y / 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)
- WriteByte (0); // Flags, empty
- WriteByte (0x7f); // End of metadata
- Flush();
-}
-
-
-
-
-
-void cProtocol132::SendSoundEffect(const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch)
-{
- cCSLock Lock(m_CSPacket);
- WriteByte (PACKET_SOUND_EFFECT);
- WriteString (a_SoundName);
- WriteInt (a_SrcX);
- WriteInt (a_SrcY);
- WriteInt (a_SrcZ);
- WriteFloat (a_Volume);
- WriteByte ((char)(a_Pitch * 63.0f));
- Flush();
-}
-
-
-
-
-
-void cProtocol132::SendSoundParticleEffect(int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data)
-{
- cCSLock Lock(m_CSPacket);
- WriteByte(PACKET_SOUND_PARTICLE_EFFECT);
- WriteInt (a_EffectID);
- WriteInt (a_SrcX / 8);
- WriteByte(a_SrcY / 8);
- WriteInt (a_SrcZ / 8);
- WriteInt (a_Data);
- Flush();
-}
-
-
-
-
-
-void cProtocol132::SendSpawnMob(const cMonster & a_Mob)
-{
- cCSLock Lock(m_CSPacket);
- WriteByte (PACKET_SPAWN_MOB);
- WriteInt (a_Mob.GetUniqueID());
- WriteByte (a_Mob.GetMobType());
- WriteVectorI((Vector3i)(a_Mob.GetPosition() * 32));
- WriteByte ((Byte)((a_Mob.GetRotation() / 360.f) * 256));
- WriteByte ((Byte)((a_Mob.GetPitch() / 360.f) * 256));
- WriteByte ((Byte)((a_Mob.GetHeadYaw() / 360.f) * 256));
- WriteShort ((short)(a_Mob.GetSpeedX() * 400));
- WriteShort ((short)(a_Mob.GetSpeedY() * 400));
- WriteShort ((short)(a_Mob.GetSpeedZ() * 400));
- AString MetaData = GetEntityMetaData(a_Mob);
- SendData (MetaData.data(), MetaData.size());
- Flush();
-}
-
-
-
-
-
-void cProtocol132::SendUnloadChunk(int a_ChunkX, int a_ChunkZ)
-{
- // Not used in 1.3.2
- // Does it unload chunks on its own?
-}
-
-
-
-
-
-void cProtocol132::SendWholeInventory(const cWindow & a_Window)
-{
- // 1.3.2 requires player inventory slots to be sent as SetSlot packets,
- // otherwise it sometimes fails to update the window
-
- // Send the entire window:
- super::SendWholeInventory(a_Window);
-
- // Send the player inventory and hotbar:
- 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++)
- {
- SendInventorySlot(WindowID, BaseOffset + i, Inventory.GetInventorySlot(i));
- } // for i - Inventory[]
- BaseOffset += cInventory::invInventoryCount;
- for (int i = 0; i < cInventory::invHotbarCount; i++)
- {
- SendInventorySlot(WindowID, BaseOffset + i, Inventory.GetHotbarSlot(i));
- } // for i - Hotbar[]
-
- // Send even the item being dragged:
- SendInventorySlot(-1, -1, m_Client->GetPlayer()->GetDraggingItem());
-}
-
-
-
-
-
-AString cProtocol132::GetAuthServerID(void)
-{
- // http://wiki.vg/wiki/index.php?title=Session&oldid=2615
- // Server uses SHA1 to mix ServerID, Client secret and server public key together
- // The mixing is done in StartEncryption, the result is in m_AuthServerID
-
- return m_AuthServerID;
-}
-
-
-
-
-
-int cProtocol132::ParsePacket(unsigned char a_PacketType)
-{
- switch (a_PacketType)
- {
- default: return super::ParsePacket(a_PacketType); // off-load previously known packets into cProtocol125
- case PACKET_LOCALE_VIEW_DISTANCE: return ParseLocaleViewDistance();
- case PACKET_CLIENT_STATUSES: return ParseClientStatuses();
- case PACKET_ENCRYPTION_KEY_RESP: return ParseEncryptionKeyResponse();
- }
-}
-
-
-
-
-
-int cProtocol132::ParseBlockPlace(void)
-{
- HANDLE_PACKET_READ(ReadBEInt, int, PosX);
- HANDLE_PACKET_READ(ReadByte, Byte, PosY);
- HANDLE_PACKET_READ(ReadBEInt, int, PosZ);
- HANDLE_PACKET_READ(ReadChar, char, BlockFace);
-
- cItem HeldItem;
- int res = ParseItem(HeldItem);
- if (res < 0)
- {
- return res;
- }
-
- HANDLE_PACKET_READ(ReadChar, char, CursorX);
- HANDLE_PACKET_READ(ReadChar, char, CursorY);
- HANDLE_PACKET_READ(ReadChar, char, CursorZ);
-
- m_Client->HandleRightClick(PosX, PosY, PosZ, BlockFace, CursorX, CursorY, CursorZ, HeldItem);
- return PARSE_OK;
-}
-
-
-
-
-
-int cProtocol132::ParseHandshake(void)
-{
- HANDLE_PACKET_READ(ReadByte, Byte, ProtocolVersion);
- HANDLE_PACKET_READ(ReadBEUTF16String16, AString, Username);
- HANDLE_PACKET_READ(ReadBEUTF16String16, AString, ServerHost);
- HANDLE_PACKET_READ(ReadBEInt, int, ServerPort);
- m_Username = Username;
-
- if (!m_Client->HandleHandshake( m_Username ))
- {
- 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);
- SendEncryptionKeyRequest();
-
- return PARSE_OK;
-}
-
-
-
-
-
-int cProtocol132::ParseClientStatuses(void)
-{
- HANDLE_PACKET_READ(ReadByte, byte, Status);
- if ((Status & 1) == 0)
- {
- m_Client->HandleLogin(39, m_Username);
- }
- else
- {
- m_Client->HandleRespawn();
- }
- return PARSE_OK;
-}
-
-
-
-
-
-int cProtocol132::ParseEncryptionKeyResponse(void)
-{
- HANDLE_PACKET_READ(ReadBEShort, short, EncKeyLength);
- AString EncKey;
- if (!m_ReceivedData.ReadString(EncKey, EncKeyLength))
- {
- return PARSE_INCOMPLETE;
- }
- HANDLE_PACKET_READ(ReadBEShort, short, EncNonceLength);
- AString EncNonce;
- if (!m_ReceivedData.ReadString(EncNonce, EncNonceLength))
- {
- return PARSE_INCOMPLETE;
- }
- if ((EncKeyLength > MAX_ENC_LEN) || (EncNonceLength > MAX_ENC_LEN))
- {
- LOGD("Too long encryption");
- m_Client->Kick("Hacked client");
- return PARSE_OK;
- }
-
- HandleEncryptionKeyResponse(EncKey, EncNonce);
- return PARSE_OK;
-}
-
-
-
-
-
-int cProtocol132::ParseLocaleViewDistance(void)
-{
- HANDLE_PACKET_READ(ReadBEUTF16String16, AString, Locale);
- HANDLE_PACKET_READ(ReadChar, char, ViewDistance);
- HANDLE_PACKET_READ(ReadChar, char, ChatFlags);
- HANDLE_PACKET_READ(ReadChar, char, ClientDifficulty);
- // TODO: m_Client->HandleLocale(Locale);
- // TODO: m_Client->HandleViewDistance(ViewDistance);
- // TODO: m_Client->HandleChatFlags(ChatFlags);
- // Ignoring client difficulty
- return PARSE_OK;
-}
-
-
-
-
-
-int cProtocol132::ParseLogin(void)
-{
- // Login packet not used in 1.3.2
- return PARSE_ERROR;
-}
-
-
-
-
-
-int cProtocol132::ParsePlayerAbilities(void)
-{
- HANDLE_PACKET_READ(ReadBool, bool, Flags);
- HANDLE_PACKET_READ(ReadChar, char, FlyingSpeed);
- HANDLE_PACKET_READ(ReadChar, char, WalkingSpeed);
- // TODO: m_Client->HandlePlayerAbilities(...);
- return PARSE_OK;
-}
-
-
-
-
-
-void cProtocol132::SendData(const char * a_Data, int a_Size)
-{
- m_DataToSend.append(a_Data, a_Size);
-}
-
-
-
-
-
-void cProtocol132::Flush(void)
-{
- ASSERT(m_CSPacket.IsLockedByCurrentThread()); // Did all packets lock the CS properly?
-
- if (m_DataToSend.empty())
- {
- LOGD("Flushing empty");
- return;
- }
- const char * a_Data = m_DataToSend.data();
- int a_Size = m_DataToSend.size();
- if (m_IsEncrypted)
- {
- 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);
- super::SendData((const char *)Encrypted, NumBytes);
- a_Size -= NumBytes;
- a_Data += NumBytes;
- }
- }
- else
- {
- super::SendData(a_Data, a_Size);
- }
- m_DataToSend.clear();
-}
-
-
-
-
-
-void cProtocol132::WriteItem(const cItem & a_Item)
-{
- short ItemType = a_Item.m_ItemType;
- ASSERT(ItemType >= -1); // Check validity of packets in debug runtime
- if (ItemType <= 0)
- {
- // Fix, to make sure no invalid values are sent.
- ItemType = -1;
- }
-
- if (a_Item.IsEmpty())
- {
- WriteShort(-1);
- return;
- }
-
- WriteShort(ItemType);
- WriteByte (a_Item.m_ItemCount);
- WriteShort(a_Item.m_ItemDamage);
-
- if (a_Item.m_Enchantments.IsEmpty())
- {
- WriteShort(-1);
- return;
- }
-
- // Send the enchantments:
- cFastNBTWriter Writer;
- const char * TagName = (a_Item.m_ItemType == E_ITEM_BOOK) ? "StoredEnchantments" : "ench";
- a_Item.m_Enchantments.WriteToNBTCompound(Writer, TagName);
- Writer.Finish();
- AString Compressed;
- CompressStringGZIP(Writer.GetResult().data(), Writer.GetResult().size(), Compressed);
- WriteShort(Compressed.size());
- SendData(Compressed.data(), Compressed.size());
-}
-
-
-
-
-
-int cProtocol132::ParseItem(cItem & a_Item)
-{
- HANDLE_PACKET_READ(ReadBEShort, short, ItemType);
-
- if (ItemType <= -1)
- {
- a_Item.Empty();
- return PARSE_OK;
- }
- a_Item.m_ItemType = ItemType;
-
- HANDLE_PACKET_READ(ReadChar, char, ItemCount);
- HANDLE_PACKET_READ(ReadBEShort, short, ItemDamage);
- a_Item.m_ItemCount = ItemCount;
- a_Item.m_ItemDamage = ItemDamage;
- if (ItemCount <= 0)
- {
- a_Item.Empty();
- }
-
- HANDLE_PACKET_READ(ReadBEShort, short, MetadataLength);
- if (MetadataLength <= 0)
- {
- return PARSE_OK;
- }
-
- // Read the metadata
- AString Metadata;
- Metadata.resize(MetadataLength);
- if (!m_ReceivedData.ReadBuf((void *)Metadata.data(), MetadataLength))
- {
- return PARSE_INCOMPLETE;
- }
-
- return ParseItemMetadata(a_Item, Metadata);
-}
-
-
-
-
-
-int cProtocol132::ParseItemMetadata(cItem & a_Item, const AString & a_Metadata)
-{
- // Uncompress the GZIPped data:
- AString Uncompressed;
- if (UncompressStringGZIP(a_Metadata.data(), a_Metadata.size(), Uncompressed) != Z_OK)
- {
- AString HexDump;
- CreateHexDump(HexDump, a_Metadata.data(), a_Metadata.size(), 16);
- LOG("Cannot unGZIP item metadata:\n%s", HexDump.c_str());
- return PARSE_ERROR;
- }
-
- // Parse into NBT:
- cParsedNBT NBT(Uncompressed.data(), Uncompressed.size());
- if (!NBT.IsValid())
- {
- AString HexDump;
- CreateHexDump(HexDump, Uncompressed.data(), Uncompressed.size(), 16);
- LOG("Cannot parse NBT item metadata:\n%s", HexDump.c_str());
- return PARSE_ERROR;
- }
-
- // Load enchantments from the NBT:
- 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")
- )
- )
- {
- a_Item.m_Enchantments.ParseFromNBT(NBT, tag);
- }
- }
-
- return PARSE_OK;
-}
-
-
-
-
-
-void cProtocol132::SendCompass(const cWorld & a_World)
-{
- cCSLock Lock(m_CSPacket);
- WriteByte(PACKET_COMPASS);
- WriteInt((int)(a_World.GetSpawnX()));
- WriteInt((int)(a_World.GetSpawnY()));
- WriteInt((int)(a_World.GetSpawnZ()));
- Flush();
-}
-
-
-
-
-
-void cProtocol132::SendEncryptionKeyRequest(void)
-{
- cCSLock Lock(m_CSPacket);
- WriteByte((char)0xfd);
- WriteString(cRoot::Get()->GetServer()->GetServerID());
- WriteShort((short)m_ServerPublicKey.size());
- SendData(m_ServerPublicKey.data(), m_ServerPublicKey.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();
-}
-
-
-
-
-
-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));
- byte DecryptedNonce[MAX_ENC_LEN];
- DecodingResult res = rsaDecryptor.Decrypt(rng, (const byte *)a_EncNonce.data(), a_EncNonce.size(), DecryptedNonce);
- if (!res.isValidCoding || (res.messageLength != 4))
- {
- LOGD("Bad nonce length");
- m_Client->Kick("Hacked client");
- return;
- }
- if (ntohl(*((int *)DecryptedNonce)) != (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(rng, (const byte *)a_EncKey.data(), a_EncKey.size(), DecryptedKey);
- if (!res.isValidCoding || (res.messageLength != 16))
- {
- LOGD("Bad key length");
- m_Client->Kick("Hacked client");
- return;
- }
-
- {
- // Send encryption key response:
- cCSLock Lock(m_CSPacket);
- WriteByte((char)0xfc);
- WriteShort(0);
- WriteShort(0);
- Flush();
- }
-
- StartEncryption(DecryptedKey);
- return;
-}
-
-
-
-
-
-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_IsEncrypted = true;
-
- // Prepare the m_AuthServerID:
- CryptoPP::SHA1 Checksum;
- AString ServerID = cRoot::Get()->GetServer()->GetServerID();
- 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);
-}
-
-
-
-
+ +// Protocol132.cpp + +// Implements the cProtocol132 class representing the release 1.3.2 protocol (#39) + +#include "Globals.h" +#include "Protocol132.h" +#include "../Root.h" +#include "../Server.h" +#include "../ClientHandle.h" +#include "../../CryptoPP/randpool.h" +#include "../Item.h" +#include "ChunkDataSerializer.h" +#include "../Player.h" +#include "../Mobs/Monster.h" +#include "../UI/Window.h" +#include "../Pickup.h" +#include "../WorldStorage/FastNBT.h" +#include "../StringCompression.h" + + + + + +#define HANDLE_PACKET_READ(Proc, Type, Var) \ + Type Var; \ + { \ + if (!m_ReceivedData.Proc(Var)) \ + { \ + m_ReceivedData.CheckValid(); \ + return PARSE_INCOMPLETE; \ + } \ + m_ReceivedData.CheckValid(); \ + } + + + + +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... + + + + + +enum +{ + PACKET_KEEP_ALIVE = 0x00, + PACKET_LOGIN = 0x01, + PACKET_ENTITY_EQUIPMENT = 0x05, + PACKET_COMPASS = 0x06, + PACKET_PLAYER_SPAWN = 0x14, + PACKET_COLLECT_PICKUP = 0x16, + PACKET_SPAWN_MOB = 0x18, + PACKET_DESTROY_ENTITIES = 0x1d, + PACKET_CHUNK_DATA = 0x33, + PACKET_BLOCK_CHANGE = 0x35, + PACKET_BLOCK_ACTION = 0x36, + PACKET_BLOCK_BREAK_ANIM = 0x37, + PACKET_SOUND_EFFECT = 0x3e, + PACKET_SOUND_PARTICLE_EFFECT = 0x3d, + PACKET_LOCALE_VIEW_DISTANCE = 0xcc, + PACKET_CLIENT_STATUSES = 0xcd, + PACKET_ENCRYPTION_KEY_RESP = 0xfc, +} ; + + + + + +// 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: + +cProtocol132::cProtocol132(cClientHandle * a_Client) : + super(a_Client), + m_IsEncrypted(false) +{ +} + + + + + +cProtocol132::~cProtocol132() +{ + if (!m_DataToSend.empty()) + { + LOGD("There are %d unsent bytes while deleting cProtocol132", m_DataToSend.size()); + } +} + + + + + +void cProtocol132::DataReceived(const char * a_Data, int a_Size) +{ + if (m_IsEncrypted) + { + 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); + super::DataReceived((const char *)Decrypted, NumBytes); + a_Size -= NumBytes; + a_Data += NumBytes; + } + } + else + { + super::DataReceived(a_Data, a_Size); + } +} + + + + + +void cProtocol132::SendBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType) +{ + cCSLock Lock(m_CSPacket); + WriteByte (PACKET_BLOCK_ACTION); + WriteInt (a_BlockX); + WriteShort((short)a_BlockY); + WriteInt (a_BlockZ); + WriteByte (a_Byte1); + WriteByte (a_Byte2); + WriteShort(a_BlockType); + Flush(); +} + + + + + +void cProtocol132::SendBlockBreakAnim(int a_entityID, int a_BlockX, int a_BlockY, int a_BlockZ, char stage) +{ + cCSLock Lock(m_CSPacket); + WriteByte (PACKET_BLOCK_BREAK_ANIM); + WriteInt (a_entityID); + WriteInt (a_BlockX); + WriteInt (a_BlockY); + WriteInt (a_BlockZ); + WriteByte (stage); + Flush(); +} + + + + + +void cProtocol132::SendBlockChange(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) +{ + cCSLock Lock(m_CSPacket); + WriteByte (PACKET_BLOCK_CHANGE); + WriteInt (a_BlockX); + WriteByte ((unsigned char)a_BlockY); + WriteInt (a_BlockZ); + WriteShort(a_BlockType); + WriteByte (a_BlockMeta); + Flush(); +} + + + + + +void cProtocol132::SendChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer) +{ + cCSLock Lock(m_CSPacket); + + // Pre-chunk not used in 1.3.2. Finally. + + // Send the chunk data: + AString Serialized = a_Serializer.Serialize(cChunkDataSerializer::RELEASE_1_3_2); + WriteByte(PACKET_CHUNK_DATA); + WriteInt (a_ChunkX); + WriteInt (a_ChunkZ); + SendData(Serialized.data(), Serialized.size()); + Flush(); +} + + + + + +void cProtocol132::SendCollectPickup(const cPickup & a_Pickup, const cPlayer & a_Player) +{ + cCSLock Lock(m_CSPacket); + WriteByte(PACKET_COLLECT_PICKUP); + WriteInt (a_Pickup.GetUniqueID()); + WriteInt (a_Player.GetUniqueID()); + Flush(); + + // Also send the "pop" sound effect with a somewhat random pitch (fast-random using EntityID ;) + SendSoundEffect( + "random.pop", + (int)(a_Pickup.GetPosX() * 8), (int)(a_Pickup.GetPosY() * 8), (int)(a_Pickup.GetPosZ() * 8), + 0.5, (float)(0.75 + ((float)((a_Pickup.GetUniqueID() * 23) % 32)) / 64) + ); +} + + + + + +void cProtocol132::SendDestroyEntity(const cEntity & a_Entity) +{ + if (a_Entity.GetUniqueID() == m_Client->GetPlayer()->GetUniqueID()) + { + // Do not send "destroy self" to the client, the client would crash (FS #254) + return; + } + + cCSLock Lock(m_CSPacket); + WriteByte(PACKET_DESTROY_ENTITIES); + WriteByte(1); // entity count + WriteInt (a_Entity.GetUniqueID()); + Flush(); +} + + + + + +void cProtocol132::SendEntityEquipment(const cEntity & a_Entity, short a_SlotNum, const cItem & a_Item) +{ + cCSLock Lock(m_CSPacket); + WriteByte (PACKET_ENTITY_EQUIPMENT); + WriteInt (a_Entity.GetUniqueID()); + WriteShort(a_SlotNum); + WriteItem (a_Item); + Flush(); +} + + + + + +void cProtocol132::SendLogin(const cPlayer & a_Player, const cWorld & a_World) +{ + cCSLock Lock(m_CSPacket); + WriteByte (PACKET_LOGIN); + WriteInt (a_Player.GetUniqueID()); // EntityID of the player + WriteString("default"); // Level type + WriteByte ((int)a_Player.GetGameMode()); + WriteByte ((Byte)(a_World.GetDimension())); + WriteByte (2); // TODO: Difficulty + WriteByte (0); // Unused, used to be world height + WriteByte (8); // Client list width or something + Flush(); + + SendCompass(a_World); + + // Send the initial position (so that confirmation works, FS #245): + SendPlayerMoveLook(); +} + + + + + +void cProtocol132::SendPlayerSpawn(const cPlayer & a_Player) +{ + const cItem & HeldItem = a_Player.GetEquippedItem(); + cCSLock Lock(m_CSPacket); + WriteByte (PACKET_PLAYER_SPAWN); + WriteInt (a_Player.GetUniqueID()); + WriteString(a_Player.GetName()); + WriteInt ((int)(a_Player.GetPosX() * 32)); + WriteInt ((int)(a_Player.GetPosY() * 32)); + WriteInt ((int)(a_Player.GetPosZ() * 32)); + WriteByte ((char)((a_Player.GetRot().x / 360.f) * 256)); + WriteByte ((char)((a_Player.GetRot().y / 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) + WriteByte (0); // Flags, empty + WriteByte (0x7f); // End of metadata + Flush(); +} + + + + + +void cProtocol132::SendSoundEffect(const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch) +{ + cCSLock Lock(m_CSPacket); + WriteByte (PACKET_SOUND_EFFECT); + WriteString (a_SoundName); + WriteInt (a_SrcX); + WriteInt (a_SrcY); + WriteInt (a_SrcZ); + WriteFloat (a_Volume); + WriteByte ((char)(a_Pitch * 63.0f)); + Flush(); +} + + + + + +void cProtocol132::SendSoundParticleEffect(int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data) +{ + cCSLock Lock(m_CSPacket); + WriteByte(PACKET_SOUND_PARTICLE_EFFECT); + WriteInt (a_EffectID); + WriteInt (a_SrcX / 8); + WriteByte(a_SrcY / 8); + WriteInt (a_SrcZ / 8); + WriteInt (a_Data); + Flush(); +} + + + + + +void cProtocol132::SendSpawnMob(const cMonster & a_Mob) +{ + cCSLock Lock(m_CSPacket); + WriteByte (PACKET_SPAWN_MOB); + WriteInt (a_Mob.GetUniqueID()); + WriteByte (a_Mob.GetMobType()); + WriteVectorI((Vector3i)(a_Mob.GetPosition() * 32)); + WriteByte ((Byte)((a_Mob.GetRotation() / 360.f) * 256)); + WriteByte ((Byte)((a_Mob.GetPitch() / 360.f) * 256)); + WriteByte ((Byte)((a_Mob.GetHeadYaw() / 360.f) * 256)); + WriteShort ((short)(a_Mob.GetSpeedX() * 400)); + WriteShort ((short)(a_Mob.GetSpeedY() * 400)); + WriteShort ((short)(a_Mob.GetSpeedZ() * 400)); + AString MetaData = GetEntityMetaData(a_Mob); + SendData (MetaData.data(), MetaData.size()); + Flush(); +} + + + + + +void cProtocol132::SendUnloadChunk(int a_ChunkX, int a_ChunkZ) +{ + // Not used in 1.3.2 + // Does it unload chunks on its own? +} + + + + + +void cProtocol132::SendWholeInventory(const cWindow & a_Window) +{ + // 1.3.2 requires player inventory slots to be sent as SetSlot packets, + // otherwise it sometimes fails to update the window + + // Send the entire window: + super::SendWholeInventory(a_Window); + + // Send the player inventory and hotbar: + 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++) + { + SendInventorySlot(WindowID, BaseOffset + i, Inventory.GetInventorySlot(i)); + } // for i - Inventory[] + BaseOffset += cInventory::invInventoryCount; + for (int i = 0; i < cInventory::invHotbarCount; i++) + { + SendInventorySlot(WindowID, BaseOffset + i, Inventory.GetHotbarSlot(i)); + } // for i - Hotbar[] + + // Send even the item being dragged: + SendInventorySlot(-1, -1, m_Client->GetPlayer()->GetDraggingItem()); +} + + + + + +AString cProtocol132::GetAuthServerID(void) +{ + // http://wiki.vg/wiki/index.php?title=Session&oldid=2615 + // Server uses SHA1 to mix ServerID, Client secret and server public key together + // The mixing is done in StartEncryption, the result is in m_AuthServerID + + return m_AuthServerID; +} + + + + + +int cProtocol132::ParsePacket(unsigned char a_PacketType) +{ + switch (a_PacketType) + { + default: return super::ParsePacket(a_PacketType); // off-load previously known packets into cProtocol125 + case PACKET_LOCALE_VIEW_DISTANCE: return ParseLocaleViewDistance(); + case PACKET_CLIENT_STATUSES: return ParseClientStatuses(); + case PACKET_ENCRYPTION_KEY_RESP: return ParseEncryptionKeyResponse(); + } +} + + + + + +int cProtocol132::ParseBlockPlace(void) +{ + HANDLE_PACKET_READ(ReadBEInt, int, PosX); + HANDLE_PACKET_READ(ReadByte, Byte, PosY); + HANDLE_PACKET_READ(ReadBEInt, int, PosZ); + HANDLE_PACKET_READ(ReadChar, char, BlockFace); + + cItem HeldItem; + int res = ParseItem(HeldItem); + if (res < 0) + { + return res; + } + + HANDLE_PACKET_READ(ReadChar, char, CursorX); + HANDLE_PACKET_READ(ReadChar, char, CursorY); + HANDLE_PACKET_READ(ReadChar, char, CursorZ); + + m_Client->HandleRightClick(PosX, PosY, PosZ, BlockFace, CursorX, CursorY, CursorZ, HeldItem); + return PARSE_OK; +} + + + + + +int cProtocol132::ParseHandshake(void) +{ + HANDLE_PACKET_READ(ReadByte, Byte, ProtocolVersion); + HANDLE_PACKET_READ(ReadBEUTF16String16, AString, Username); + HANDLE_PACKET_READ(ReadBEUTF16String16, AString, ServerHost); + HANDLE_PACKET_READ(ReadBEInt, int, ServerPort); + m_Username = Username; + + if (!m_Client->HandleHandshake( m_Username )) + { + 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); + SendEncryptionKeyRequest(); + + return PARSE_OK; +} + + + + + +int cProtocol132::ParseClientStatuses(void) +{ + HANDLE_PACKET_READ(ReadByte, byte, Status); + if ((Status & 1) == 0) + { + m_Client->HandleLogin(39, m_Username); + } + else + { + m_Client->HandleRespawn(); + } + return PARSE_OK; +} + + + + + +int cProtocol132::ParseEncryptionKeyResponse(void) +{ + HANDLE_PACKET_READ(ReadBEShort, short, EncKeyLength); + AString EncKey; + if (!m_ReceivedData.ReadString(EncKey, EncKeyLength)) + { + return PARSE_INCOMPLETE; + } + HANDLE_PACKET_READ(ReadBEShort, short, EncNonceLength); + AString EncNonce; + if (!m_ReceivedData.ReadString(EncNonce, EncNonceLength)) + { + return PARSE_INCOMPLETE; + } + if ((EncKeyLength > MAX_ENC_LEN) || (EncNonceLength > MAX_ENC_LEN)) + { + LOGD("Too long encryption"); + m_Client->Kick("Hacked client"); + return PARSE_OK; + } + + HandleEncryptionKeyResponse(EncKey, EncNonce); + return PARSE_OK; +} + + + + + +int cProtocol132::ParseLocaleViewDistance(void) +{ + HANDLE_PACKET_READ(ReadBEUTF16String16, AString, Locale); + HANDLE_PACKET_READ(ReadChar, char, ViewDistance); + HANDLE_PACKET_READ(ReadChar, char, ChatFlags); + HANDLE_PACKET_READ(ReadChar, char, ClientDifficulty); + // TODO: m_Client->HandleLocale(Locale); + // TODO: m_Client->HandleViewDistance(ViewDistance); + // TODO: m_Client->HandleChatFlags(ChatFlags); + // Ignoring client difficulty + return PARSE_OK; +} + + + + + +int cProtocol132::ParseLogin(void) +{ + // Login packet not used in 1.3.2 + return PARSE_ERROR; +} + + + + + +int cProtocol132::ParsePlayerAbilities(void) +{ + HANDLE_PACKET_READ(ReadBool, bool, Flags); + HANDLE_PACKET_READ(ReadChar, char, FlyingSpeed); + HANDLE_PACKET_READ(ReadChar, char, WalkingSpeed); + // TODO: m_Client->HandlePlayerAbilities(...); + return PARSE_OK; +} + + + + + +void cProtocol132::SendData(const char * a_Data, int a_Size) +{ + m_DataToSend.append(a_Data, a_Size); +} + + + + + +void cProtocol132::Flush(void) +{ + ASSERT(m_CSPacket.IsLockedByCurrentThread()); // Did all packets lock the CS properly? + + if (m_DataToSend.empty()) + { + LOGD("Flushing empty"); + return; + } + const char * a_Data = m_DataToSend.data(); + int a_Size = m_DataToSend.size(); + if (m_IsEncrypted) + { + 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); + super::SendData((const char *)Encrypted, NumBytes); + a_Size -= NumBytes; + a_Data += NumBytes; + } + } + else + { + super::SendData(a_Data, a_Size); + } + m_DataToSend.clear(); +} + + + + + +void cProtocol132::WriteItem(const cItem & a_Item) +{ + short ItemType = a_Item.m_ItemType; + ASSERT(ItemType >= -1); // Check validity of packets in debug runtime + if (ItemType <= 0) + { + // Fix, to make sure no invalid values are sent. + ItemType = -1; + } + + if (a_Item.IsEmpty()) + { + WriteShort(-1); + return; + } + + WriteShort(ItemType); + WriteByte (a_Item.m_ItemCount); + WriteShort(a_Item.m_ItemDamage); + + if (a_Item.m_Enchantments.IsEmpty()) + { + WriteShort(-1); + return; + } + + // Send the enchantments: + cFastNBTWriter Writer; + const char * TagName = (a_Item.m_ItemType == E_ITEM_BOOK) ? "StoredEnchantments" : "ench"; + a_Item.m_Enchantments.WriteToNBTCompound(Writer, TagName); + Writer.Finish(); + AString Compressed; + CompressStringGZIP(Writer.GetResult().data(), Writer.GetResult().size(), Compressed); + WriteShort(Compressed.size()); + SendData(Compressed.data(), Compressed.size()); +} + + + + + +int cProtocol132::ParseItem(cItem & a_Item) +{ + HANDLE_PACKET_READ(ReadBEShort, short, ItemType); + + if (ItemType <= -1) + { + a_Item.Empty(); + return PARSE_OK; + } + a_Item.m_ItemType = ItemType; + + HANDLE_PACKET_READ(ReadChar, char, ItemCount); + HANDLE_PACKET_READ(ReadBEShort, short, ItemDamage); + a_Item.m_ItemCount = ItemCount; + a_Item.m_ItemDamage = ItemDamage; + if (ItemCount <= 0) + { + a_Item.Empty(); + } + + HANDLE_PACKET_READ(ReadBEShort, short, MetadataLength); + if (MetadataLength <= 0) + { + return PARSE_OK; + } + + // Read the metadata + AString Metadata; + Metadata.resize(MetadataLength); + if (!m_ReceivedData.ReadBuf((void *)Metadata.data(), MetadataLength)) + { + return PARSE_INCOMPLETE; + } + + return ParseItemMetadata(a_Item, Metadata); +} + + + + + +int cProtocol132::ParseItemMetadata(cItem & a_Item, const AString & a_Metadata) +{ + // Uncompress the GZIPped data: + AString Uncompressed; + if (UncompressStringGZIP(a_Metadata.data(), a_Metadata.size(), Uncompressed) != Z_OK) + { + AString HexDump; + CreateHexDump(HexDump, a_Metadata.data(), a_Metadata.size(), 16); + LOG("Cannot unGZIP item metadata:\n%s", HexDump.c_str()); + return PARSE_ERROR; + } + + // Parse into NBT: + cParsedNBT NBT(Uncompressed.data(), Uncompressed.size()); + if (!NBT.IsValid()) + { + AString HexDump; + CreateHexDump(HexDump, Uncompressed.data(), Uncompressed.size(), 16); + LOG("Cannot parse NBT item metadata:\n%s", HexDump.c_str()); + return PARSE_ERROR; + } + + // Load enchantments from the NBT: + 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") + ) + ) + { + a_Item.m_Enchantments.ParseFromNBT(NBT, tag); + } + } + + return PARSE_OK; +} + + + + + +void cProtocol132::SendCompass(const cWorld & a_World) +{ + cCSLock Lock(m_CSPacket); + WriteByte(PACKET_COMPASS); + WriteInt((int)(a_World.GetSpawnX())); + WriteInt((int)(a_World.GetSpawnY())); + WriteInt((int)(a_World.GetSpawnZ())); + Flush(); +} + + + + + +void cProtocol132::SendEncryptionKeyRequest(void) +{ + cCSLock Lock(m_CSPacket); + WriteByte((char)0xfd); + WriteString(cRoot::Get()->GetServer()->GetServerID()); + WriteShort((short)m_ServerPublicKey.size()); + SendData(m_ServerPublicKey.data(), m_ServerPublicKey.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(); +} + + + + + +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)); + byte DecryptedNonce[MAX_ENC_LEN]; + DecodingResult res = rsaDecryptor.Decrypt(rng, (const byte *)a_EncNonce.data(), a_EncNonce.size(), DecryptedNonce); + if (!res.isValidCoding || (res.messageLength != 4)) + { + LOGD("Bad nonce length"); + m_Client->Kick("Hacked client"); + return; + } + if (ntohl(*((int *)DecryptedNonce)) != (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(rng, (const byte *)a_EncKey.data(), a_EncKey.size(), DecryptedKey); + if (!res.isValidCoding || (res.messageLength != 16)) + { + LOGD("Bad key length"); + m_Client->Kick("Hacked client"); + return; + } + + { + // Send encryption key response: + cCSLock Lock(m_CSPacket); + WriteByte((char)0xfc); + WriteShort(0); + WriteShort(0); + Flush(); + } + + StartEncryption(DecryptedKey); + return; +} + + + + + +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_IsEncrypted = true; + + // Prepare the m_AuthServerID: + CryptoPP::SHA1 Checksum; + AString ServerID = cRoot::Get()->GetServer()->GetServerID(); + 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); +} + + + + diff --git a/source/Protocol/Protocol132.h b/source/Protocol/Protocol132.h index cf559f1ca..bf8b4ff0e 100644 --- a/source/Protocol/Protocol132.h +++ b/source/Protocol/Protocol132.h @@ -1,100 +1,100 @@ -
-// Protocol132.h
-
-// Interfaces to the cProtocol132 class representing the release 1.3.2 protocol (#39)
-
-
-
-
-
-#pragma once
-
-#include "Protocol125.h"
-#include "../../CryptoPP/modes.h"
-#include "../../CryptoPP/aes.h"
-
-
-
-
-
-class cProtocol132 :
- public cProtocol125
-{
- typedef cProtocol125 super;
-public:
-
- cProtocol132(cClientHandle * a_Client);
- virtual ~cProtocol132();
-
- /// Called when client sends some data:
- virtual void DataReceived(const char * a_Data, int 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;
- 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 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;
- virtual void SendEntityEquipment (const cEntity & a_Entity, short a_SlotNum, const cItem & a_Item) override;
- virtual void SendLogin (const cPlayer & a_Player, const cWorld & a_World) override;
- virtual void SendPlayerSpawn (const cPlayer & a_Player) override;
- 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 SendSpawnMob (const cMonster & a_Mob) override;
- virtual void SendUnloadChunk (int a_ChunkX, int a_ChunkZ) override;
- virtual void SendWholeInventory (const cWindow & a_Window) override;
-
- virtual AString GetAuthServerID(void) override;
-
- /// Handling of the additional packets:
- virtual int ParsePacket(unsigned char a_PacketType) override;
-
- // Modified packets:
- virtual int ParseBlockPlace (void) override;
- virtual int ParseHandshake (void) override;
- virtual int ParseLogin (void) override;
- virtual int ParsePlayerAbilities(void) override;
-
- // New packets:
- virtual int ParseClientStatuses (void);
- virtual int ParseEncryptionKeyResponse(void);
- virtual int ParseLocaleViewDistance (void);
-
-protected:
- bool m_IsEncrypted;
- CryptoPP::CFB_Mode<CryptoPP::AES>::Decryption m_Decryptor;
- CryptoPP::CFB_Mode<CryptoPP::AES>::Encryption 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;
-
- // DEBUG:
- virtual void Flush(void) override;
-
- // Items in slots are sent differently
- virtual void WriteItem(const cItem & a_Item) override;
- virtual int ParseItem(cItem & a_Item) override;
-
- /// Parses the metadata that may come with the item.
- int ParseItemMetadata(cItem & a_Item, const AString & a_Metadata);
-
- virtual void SendCompass(const cWorld & a_World);
- virtual void SendEncryptionKeyRequest(void);
-
- /// Decrypts the key and nonce, checks nonce, starts the symmetric encryption
- 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);
-} ;
-
-
-
-
+ +// Protocol132.h + +// Interfaces to the cProtocol132 class representing the release 1.3.2 protocol (#39) + + + + + +#pragma once + +#include "Protocol125.h" +#include "../../CryptoPP/modes.h" +#include "../../CryptoPP/aes.h" + + + + + +class cProtocol132 : + public cProtocol125 +{ + typedef cProtocol125 super; +public: + + cProtocol132(cClientHandle * a_Client); + virtual ~cProtocol132(); + + /// Called when client sends some data: + virtual void DataReceived(const char * a_Data, int 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; + 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 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; + virtual void SendEntityEquipment (const cEntity & a_Entity, short a_SlotNum, const cItem & a_Item) override; + virtual void SendLogin (const cPlayer & a_Player, const cWorld & a_World) override; + virtual void SendPlayerSpawn (const cPlayer & a_Player) override; + 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 SendSpawnMob (const cMonster & a_Mob) override; + virtual void SendUnloadChunk (int a_ChunkX, int a_ChunkZ) override; + virtual void SendWholeInventory (const cWindow & a_Window) override; + + virtual AString GetAuthServerID(void) override; + + /// Handling of the additional packets: + virtual int ParsePacket(unsigned char a_PacketType) override; + + // Modified packets: + virtual int ParseBlockPlace (void) override; + virtual int ParseHandshake (void) override; + virtual int ParseLogin (void) override; + virtual int ParsePlayerAbilities(void) override; + + // New packets: + virtual int ParseClientStatuses (void); + virtual int ParseEncryptionKeyResponse(void); + virtual int ParseLocaleViewDistance (void); + +protected: + bool m_IsEncrypted; + CryptoPP::CFB_Mode<CryptoPP::AES>::Decryption m_Decryptor; + CryptoPP::CFB_Mode<CryptoPP::AES>::Encryption 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; + + // DEBUG: + virtual void Flush(void) override; + + // Items in slots are sent differently + virtual void WriteItem(const cItem & a_Item) override; + virtual int ParseItem(cItem & a_Item) override; + + /// Parses the metadata that may come with the item. + int ParseItemMetadata(cItem & a_Item, const AString & a_Metadata); + + virtual void SendCompass(const cWorld & a_World); + virtual void SendEncryptionKeyRequest(void); + + /// Decrypts the key and nonce, checks nonce, starts the symmetric encryption + 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); +} ; + + + + diff --git a/source/Protocol/Protocol14x.cpp b/source/Protocol/Protocol14x.cpp index b7d3c91df..35fe0ce1c 100644 --- a/source/Protocol/Protocol14x.cpp +++ b/source/Protocol/Protocol14x.cpp @@ -1,253 +1,253 @@ -
-// Protocol14x.cpp
-
-/*
-Implements the 1.4.x protocol classes representing these protocols:
-- cProtocol142:
- - release 1.4.2 protocol (#47)
- - release 1.4.4 protocol (#49) - the same protocol class is used, because the only difference is in a packet that MCServer doesn't implement yet (ITEM_DATA)
- - release 1.4.5 protocol (same as 1.4.4)
-- cProtocol146:
- - release 1.4.6 protocol (#51)
-*/
-
-#include "Globals.h"
-#include "Protocol14x.h"
-#include "../Root.h"
-#include "../Server.h"
-#include "../ClientHandle.h"
-#include "../../CryptoPP/randpool.h"
-#include "../Item.h"
-#include "ChunkDataSerializer.h"
-#include "../Player.h"
-#include "../Mobs/Monster.h"
-#include "../UI/Window.h"
-#include "../Pickup.h"
-#include "../FallingBlock.h"
-
-
-
-
-
-#define HANDLE_PACKET_READ(Proc, Type, Var) \
- Type Var; \
- { \
- if (!m_ReceivedData.Proc(Var)) \
- { \
- m_ReceivedData.CheckValid(); \
- return PARSE_INCOMPLETE; \
- } \
- m_ReceivedData.CheckValid(); \
- }
-
-
-
-
-
-enum
-{
- PACKET_UPDATE_TIME = 0x04,
- PACKET_PICKUP_SPAWN = 0x15,
- PACKET_SPAWN_OBJECT = 0x17,
- PACKET_ENTITY_METADATA = 0x28,
- PACKET_SOUND_PARTICLE_EFFECT = 0x3d
-} ;
-
-
-
-
-
-///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// cProtocol142:
-
-cProtocol142::cProtocol142(cClientHandle * a_Client) :
- super(a_Client)
-{
-}
-
-
-
-
-
-int cProtocol142::ParseLocaleViewDistance(void)
-{
- HANDLE_PACKET_READ(ReadBEUTF16String16, AString, Locale);
- HANDLE_PACKET_READ(ReadChar, char, ViewDistance);
- 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);
- // TODO: m_Client->HandleViewDistance(ViewDistance);
- // TODO: m_Client->HandleChatFlags(ChatFlags);
- // Ignoring client difficulty
- return PARSE_OK;
-}
-
-
-
-
-
-void cProtocol142::SendPickupSpawn(const cPickup & a_Pickup)
-{
- cCSLock Lock(m_CSPacket);
- WriteByte (PACKET_PICKUP_SPAWN);
- 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));
- Flush();
-}
-
-
-
-
-
-void cProtocol142::SendSoundParticleEffect(int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data)
-{
- cCSLock Lock(m_CSPacket);
- WriteByte(PACKET_SOUND_PARTICLE_EFFECT);
- WriteInt (a_EffectID);
- WriteInt (a_SrcX / 8);
- WriteByte(a_SrcY / 8);
- WriteInt (a_SrcZ / 8);
- WriteInt (a_Data);
- WriteBool(0);
- Flush();
-}
-
-
-
-
-
-void cProtocol142::SendTimeUpdate(Int64 a_WorldAge, Int64 a_TimeOfDay)
-{
- cCSLock Lock(m_CSPacket);
- WriteByte (PACKET_UPDATE_TIME);
- WriteInt64(a_WorldAge);
- WriteInt64(a_TimeOfDay);
- Flush();
-}
-
-
-
-
-
-
-///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// cProtocol146:
-
-cProtocol146::cProtocol146(cClientHandle * a_Client) :
- super(a_Client)
-{
-}
-
-
-
-
-
-void cProtocol146::SendPickupSpawn(const cPickup & a_Pickup)
-{
- ASSERT(!a_Pickup.GetItem().IsEmpty());
-
- cCSLock Lock(m_CSPacket);
-
- // Send a SPAWN_OBJECT packet for the base entity:
- WriteByte(PACKET_SPAWN_OBJECT);
- WriteInt (a_Pickup.GetUniqueID());
- WriteByte(0x02);
- WriteInt ((int)(a_Pickup.GetPosX() * 32));
- WriteInt ((int)(a_Pickup.GetPosY() * 32));
- WriteInt ((int)(a_Pickup.GetPosZ() * 32));
- WriteInt (1);
- WriteShort((short)(a_Pickup.GetSpeed().x * 32));
- WriteShort((short)(a_Pickup.GetSpeed().y * 32));
- WriteShort((short)(a_Pickup.GetSpeed().z * 32));
- WriteByte(0);
- WriteByte(0);
-
- // Send a ENTITY_METADATA packet with the slot info:
- WriteByte(PACKET_ENTITY_METADATA);
- WriteInt(a_Pickup.GetUniqueID());
- WriteByte(0xaa); // a slot value at index 10
- WriteItem(a_Pickup.GetItem());
- WriteByte(0x7f); // End of metadata
- Flush();
-}
-
-
-
-
-
-void cProtocol146::SendSpawnFallingBlock(const cFallingBlock & a_FallingBlock)
-{
- // Send a spawn object / vehicle packet
- cCSLock Lock(m_CSPacket);
-
- WriteByte(PACKET_SPAWN_OBJECT);
- WriteInt (a_FallingBlock.GetUniqueID());
- WriteByte(70);
- WriteInt ((int)(a_FallingBlock.GetPosX() * 32));
- WriteInt ((int)(a_FallingBlock.GetPosY() * 32));
- WriteInt ((int)(a_FallingBlock.GetPosZ() * 32));
- WriteByte (0); // Pitch
- WriteByte (0); // Yaw
- WriteInt (a_FallingBlock.GetBlockType()); // data indicator = blocktype
- WriteShort((short)(a_FallingBlock.GetSpeedX() * 400));
- WriteShort((short)(a_FallingBlock.GetSpeedY() * 400));
- WriteShort((short)(a_FallingBlock.GetSpeedZ() * 400));
- Flush();
-}
-
-
-
-
-
-void cProtocol146::SendSpawnObject(const cEntity & a_Entity, char a_ObjectType, int a_ObjectData, Byte a_Yaw, Byte a_Pitch)
-{
- cCSLock Lock(m_CSPacket);
- WriteByte(PACKET_SPAWN_OBJECT);
- WriteInt (a_Entity.GetUniqueID());
- WriteByte(a_ObjectType);
- WriteInt ((int)(a_Entity.GetPosX() * 32));
- WriteInt ((int)(a_Entity.GetPosY() * 32));
- WriteInt ((int)(a_Entity.GetPosZ() * 32));
- WriteByte(a_Pitch);
- WriteByte(a_Yaw);
- WriteInt (a_ObjectData);
- if (a_ObjectData != 0)
- {
- WriteShort((short)(a_Entity.GetSpeedX() * 400));
- WriteShort((short)(a_Entity.GetSpeedY() * 400));
- WriteShort((short)(a_Entity.GetSpeedZ() * 400));
- }
- Flush();
-}
-
-
-
-
-
-void cProtocol146::SendSpawnVehicle(const cEntity & a_Vehicle, char a_VehicleType)
-{
- cCSLock Lock(m_CSPacket);
- WriteByte(PACKET_SPAWN_OBJECT);
- WriteInt (a_Vehicle.GetUniqueID());
- WriteByte(a_VehicleType);
- WriteInt ((int)(a_Vehicle.GetPosX() * 32));
- WriteInt ((int)(a_Vehicle.GetPosY() * 32));
- WriteInt ((int)(a_Vehicle.GetPosZ() * 32));
- WriteByte ((Byte)((a_Vehicle.GetPitch() / 360.f) * 256));
- WriteByte ((Byte)((a_Vehicle.GetRotation() / 360.f) * 256));
- WriteInt (1);
- WriteShort((short)(a_Vehicle.GetSpeedX() * 400));
- WriteShort((short)(a_Vehicle.GetSpeedY() * 400));
- WriteShort((short)(a_Vehicle.GetSpeedZ() * 400));
- Flush();
-}
-
-
-
-
-
+ +// Protocol14x.cpp + +/* +Implements the 1.4.x protocol classes representing these protocols: +- cProtocol142: + - release 1.4.2 protocol (#47) + - release 1.4.4 protocol (#49) - the same protocol class is used, because the only difference is in a packet that MCServer doesn't implement yet (ITEM_DATA) + - release 1.4.5 protocol (same as 1.4.4) +- cProtocol146: + - release 1.4.6 protocol (#51) +*/ + +#include "Globals.h" +#include "Protocol14x.h" +#include "../Root.h" +#include "../Server.h" +#include "../ClientHandle.h" +#include "../../CryptoPP/randpool.h" +#include "../Item.h" +#include "ChunkDataSerializer.h" +#include "../Player.h" +#include "../Mobs/Monster.h" +#include "../UI/Window.h" +#include "../Pickup.h" +#include "../FallingBlock.h" + + + + + +#define HANDLE_PACKET_READ(Proc, Type, Var) \ + Type Var; \ + { \ + if (!m_ReceivedData.Proc(Var)) \ + { \ + m_ReceivedData.CheckValid(); \ + return PARSE_INCOMPLETE; \ + } \ + m_ReceivedData.CheckValid(); \ + } + + + + + +enum +{ + PACKET_UPDATE_TIME = 0x04, + PACKET_PICKUP_SPAWN = 0x15, + PACKET_SPAWN_OBJECT = 0x17, + PACKET_ENTITY_METADATA = 0x28, + PACKET_SOUND_PARTICLE_EFFECT = 0x3d +} ; + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cProtocol142: + +cProtocol142::cProtocol142(cClientHandle * a_Client) : + super(a_Client) +{ +} + + + + + +int cProtocol142::ParseLocaleViewDistance(void) +{ + HANDLE_PACKET_READ(ReadBEUTF16String16, AString, Locale); + HANDLE_PACKET_READ(ReadChar, char, ViewDistance); + 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); + // TODO: m_Client->HandleViewDistance(ViewDistance); + // TODO: m_Client->HandleChatFlags(ChatFlags); + // Ignoring client difficulty + return PARSE_OK; +} + + + + + +void cProtocol142::SendPickupSpawn(const cPickup & a_Pickup) +{ + cCSLock Lock(m_CSPacket); + WriteByte (PACKET_PICKUP_SPAWN); + 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)); + Flush(); +} + + + + + +void cProtocol142::SendSoundParticleEffect(int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data) +{ + cCSLock Lock(m_CSPacket); + WriteByte(PACKET_SOUND_PARTICLE_EFFECT); + WriteInt (a_EffectID); + WriteInt (a_SrcX / 8); + WriteByte(a_SrcY / 8); + WriteInt (a_SrcZ / 8); + WriteInt (a_Data); + WriteBool(0); + Flush(); +} + + + + + +void cProtocol142::SendTimeUpdate(Int64 a_WorldAge, Int64 a_TimeOfDay) +{ + cCSLock Lock(m_CSPacket); + WriteByte (PACKET_UPDATE_TIME); + WriteInt64(a_WorldAge); + WriteInt64(a_TimeOfDay); + Flush(); +} + + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cProtocol146: + +cProtocol146::cProtocol146(cClientHandle * a_Client) : + super(a_Client) +{ +} + + + + + +void cProtocol146::SendPickupSpawn(const cPickup & a_Pickup) +{ + ASSERT(!a_Pickup.GetItem().IsEmpty()); + + cCSLock Lock(m_CSPacket); + + // Send a SPAWN_OBJECT packet for the base entity: + WriteByte(PACKET_SPAWN_OBJECT); + WriteInt (a_Pickup.GetUniqueID()); + WriteByte(0x02); + WriteInt ((int)(a_Pickup.GetPosX() * 32)); + WriteInt ((int)(a_Pickup.GetPosY() * 32)); + WriteInt ((int)(a_Pickup.GetPosZ() * 32)); + WriteInt (1); + WriteShort((short)(a_Pickup.GetSpeed().x * 32)); + WriteShort((short)(a_Pickup.GetSpeed().y * 32)); + WriteShort((short)(a_Pickup.GetSpeed().z * 32)); + WriteByte(0); + WriteByte(0); + + // Send a ENTITY_METADATA packet with the slot info: + WriteByte(PACKET_ENTITY_METADATA); + WriteInt(a_Pickup.GetUniqueID()); + WriteByte(0xaa); // a slot value at index 10 + WriteItem(a_Pickup.GetItem()); + WriteByte(0x7f); // End of metadata + Flush(); +} + + + + + +void cProtocol146::SendSpawnFallingBlock(const cFallingBlock & a_FallingBlock) +{ + // Send a spawn object / vehicle packet + cCSLock Lock(m_CSPacket); + + WriteByte(PACKET_SPAWN_OBJECT); + WriteInt (a_FallingBlock.GetUniqueID()); + WriteByte(70); + WriteInt ((int)(a_FallingBlock.GetPosX() * 32)); + WriteInt ((int)(a_FallingBlock.GetPosY() * 32)); + WriteInt ((int)(a_FallingBlock.GetPosZ() * 32)); + WriteByte (0); // Pitch + WriteByte (0); // Yaw + WriteInt (a_FallingBlock.GetBlockType()); // data indicator = blocktype + WriteShort((short)(a_FallingBlock.GetSpeedX() * 400)); + WriteShort((short)(a_FallingBlock.GetSpeedY() * 400)); + WriteShort((short)(a_FallingBlock.GetSpeedZ() * 400)); + Flush(); +} + + + + + +void cProtocol146::SendSpawnObject(const cEntity & a_Entity, char a_ObjectType, int a_ObjectData, Byte a_Yaw, Byte a_Pitch) +{ + cCSLock Lock(m_CSPacket); + WriteByte(PACKET_SPAWN_OBJECT); + WriteInt (a_Entity.GetUniqueID()); + WriteByte(a_ObjectType); + WriteInt ((int)(a_Entity.GetPosX() * 32)); + WriteInt ((int)(a_Entity.GetPosY() * 32)); + WriteInt ((int)(a_Entity.GetPosZ() * 32)); + WriteByte(a_Pitch); + WriteByte(a_Yaw); + WriteInt (a_ObjectData); + if (a_ObjectData != 0) + { + WriteShort((short)(a_Entity.GetSpeedX() * 400)); + WriteShort((short)(a_Entity.GetSpeedY() * 400)); + WriteShort((short)(a_Entity.GetSpeedZ() * 400)); + } + Flush(); +} + + + + + +void cProtocol146::SendSpawnVehicle(const cEntity & a_Vehicle, char a_VehicleType) +{ + cCSLock Lock(m_CSPacket); + WriteByte(PACKET_SPAWN_OBJECT); + WriteInt (a_Vehicle.GetUniqueID()); + WriteByte(a_VehicleType); + WriteInt ((int)(a_Vehicle.GetPosX() * 32)); + WriteInt ((int)(a_Vehicle.GetPosY() * 32)); + WriteInt ((int)(a_Vehicle.GetPosZ() * 32)); + WriteByte ((Byte)((a_Vehicle.GetPitch() / 360.f) * 256)); + WriteByte ((Byte)((a_Vehicle.GetRotation() / 360.f) * 256)); + WriteInt (1); + WriteShort((short)(a_Vehicle.GetSpeedX() * 400)); + WriteShort((short)(a_Vehicle.GetSpeedY() * 400)); + WriteShort((short)(a_Vehicle.GetSpeedZ() * 400)); + Flush(); +} + + + + + diff --git a/source/Protocol/Protocol14x.h b/source/Protocol/Protocol14x.h index a9ff14d84..c3193a3e7 100644 --- a/source/Protocol/Protocol14x.h +++ b/source/Protocol/Protocol14x.h @@ -1,63 +1,63 @@ -
-// Protocol14x.h
-
-/*
-Interfaces to the 1.4.x protocol classes representing these protocols:
-- cProtocol142:
- - release 1.4.2 protocol (#47)
- - release 1.4.4 protocol (#49) - the same protocol class is used, because the only difference is in a packet that MCServer doesn't implement yet (ITEM_DATA)
- - release 1.4.5 protocol (same as 1.4.4)
-- cProtocol146:
- - release 1.4.6 protocol (#51)
-*/
-
-
-
-
-
-#pragma once
-
-#include "Protocol132.h"
-
-
-
-
-
-class cProtocol142 :
- public cProtocol132
-{
- typedef cProtocol132 super;
-
-public:
- cProtocol142(cClientHandle * a_Client);
-
- // Sending commands (alphabetically sorted):
- virtual void SendPickupSpawn (const cPickup & a_Pickup) override;
- virtual void SendSoundParticleEffect(int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data) override;
- virtual void SendTimeUpdate (Int64 a_WorldAge, Int64 a_TimeOfDay) override;
-
- // Specific packet parsers:
- virtual int ParseLocaleViewDistance(void) override;
-} ;
-
-
-
-
-
-class cProtocol146 :
- public cProtocol142
-{
- typedef cProtocol142 super;
-
-public:
- cProtocol146(cClientHandle * a_Client);
-
- virtual void SendPickupSpawn (const cPickup & a_Pickup) override;
- virtual void SendSpawnFallingBlock(const cFallingBlock & a_FallingBlock) override;
- virtual void SendSpawnObject (const cEntity & a_Entity, char a_ObjectType, int a_ObjectData, Byte a_Yaw, Byte a_Pitch) override;
- virtual void SendSpawnVehicle (const cEntity & a_Vehicle, char a_VehicleType) override;
-} ;
-
-
-
-
+ +// Protocol14x.h + +/* +Interfaces to the 1.4.x protocol classes representing these protocols: +- cProtocol142: + - release 1.4.2 protocol (#47) + - release 1.4.4 protocol (#49) - the same protocol class is used, because the only difference is in a packet that MCServer doesn't implement yet (ITEM_DATA) + - release 1.4.5 protocol (same as 1.4.4) +- cProtocol146: + - release 1.4.6 protocol (#51) +*/ + + + + + +#pragma once + +#include "Protocol132.h" + + + + + +class cProtocol142 : + public cProtocol132 +{ + typedef cProtocol132 super; + +public: + cProtocol142(cClientHandle * a_Client); + + // Sending commands (alphabetically sorted): + virtual void SendPickupSpawn (const cPickup & a_Pickup) override; + virtual void SendSoundParticleEffect(int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data) override; + virtual void SendTimeUpdate (Int64 a_WorldAge, Int64 a_TimeOfDay) override; + + // Specific packet parsers: + virtual int ParseLocaleViewDistance(void) override; +} ; + + + + + +class cProtocol146 : + public cProtocol142 +{ + typedef cProtocol142 super; + +public: + cProtocol146(cClientHandle * a_Client); + + virtual void SendPickupSpawn (const cPickup & a_Pickup) override; + virtual void SendSpawnFallingBlock(const cFallingBlock & a_FallingBlock) override; + virtual void SendSpawnObject (const cEntity & a_Entity, char a_ObjectType, int a_ObjectData, Byte a_Yaw, Byte a_Pitch) override; + virtual void SendSpawnVehicle (const cEntity & a_Vehicle, char a_VehicleType) override; +} ; + + + + diff --git a/source/Protocol/Protocol15x.cpp b/source/Protocol/Protocol15x.cpp index cb7fc9fb6..cbae0700e 100644 --- a/source/Protocol/Protocol15x.cpp +++ b/source/Protocol/Protocol15x.cpp @@ -1,137 +1,137 @@ -
-// Protocol15x.cpp
-
-/*
-Implements the 1.5.x protocol classes:
- - cProtocol150
- - release 1.5 protocol (#60)
- - release 1.5.2 protocol (#61, no relevant changes found)
-*/
-
-#include "Globals.h"
-#include "Protocol15x.h"
-#include "../ClientHandle.h"
-#include "../Item.h"
-
-
-
-
-
-#define HANDLE_PACKET_READ(Proc, Type, Var) \
- Type Var; \
- { \
- if (!m_ReceivedData.Proc(Var)) \
- { \
- m_ReceivedData.CheckValid(); \
- return PARSE_INCOMPLETE; \
- } \
- m_ReceivedData.CheckValid(); \
- }
-
-
-
-
-
-enum
-{
- PACKET_WINDOW_OPEN = 0x64,
-} ;
-
-
-
-
-
-
-///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// cProtocol150:
-
-cProtocol150::cProtocol150(cClientHandle * a_Client) :
- super(a_Client)
-{
-}
-
-
-
-
-
-void cProtocol150::SendWindowOpen(char a_WindowID, char a_WindowType, const AString & a_WindowTitle, char a_NumSlots)
-{
- if (a_WindowType < 0)
- {
- // Do not send for inventory windows
- return;
- }
- cCSLock Lock(m_CSPacket);
- WriteByte (PACKET_WINDOW_OPEN);
- WriteByte (a_WindowID);
- WriteByte (a_WindowType);
- WriteString(a_WindowTitle);
- WriteByte (a_NumSlots);
- WriteByte (1); // Use title
- Flush();
-}
-
-
-
-
-
-int cProtocol150::ParseWindowClick(void)
-{
- HANDLE_PACKET_READ(ReadChar, char, WindowID);
- HANDLE_PACKET_READ(ReadBEShort, short, SlotNum);
- HANDLE_PACKET_READ(ReadByte, Byte, Button);
- HANDLE_PACKET_READ(ReadBEShort, short, TransactionID);
- HANDLE_PACKET_READ(ReadByte, Byte, Mode);
- cItem HeldItem;
- int res = ParseItem(HeldItem);
- if (res < 0)
- {
- return res;
- }
-
- // Convert Button, Mode, SlotNum and HeldItem into eClickAction:
- eClickAction Action;
- switch ((Mode << 8) | Button)
- {
- case 0x0000: Action = (SlotNum != -999) ? caLeftClick : caLeftClickOutside; break;
- case 0x0001: Action = (SlotNum != -999) ? caRightClick : caRightClickOutside; break;
- case 0x0100: Action = caShiftLeftClick; break;
- case 0x0101: Action = caShiftRightClick; break;
- case 0x0200: Action = caNumber1; break;
- case 0x0201: Action = caNumber2; break;
- case 0x0202: Action = caNumber3; break;
- case 0x0203: Action = caNumber4; break;
- case 0x0204: Action = caNumber5; break;
- case 0x0205: Action = caNumber6; break;
- case 0x0206: Action = caNumber7; break;
- case 0x0207: Action = caNumber8; break;
- case 0x0208: Action = caNumber9; break;
- case 0x0300: Action = caMiddleClick; break;
- case 0x0400: Action = (SlotNum == -999) ? caLeftClickOutsideHoldNothing : caDropKey; break;
- case 0x0401: Action = (SlotNum == -999) ? caRightClickOutsideHoldNothing : caCtrlDropKey; break;
- case 0x0500: Action = (SlotNum == -999) ? caLeftPaintBegin : caUnknown; break;
- case 0x0501: Action = (SlotNum != -999) ? caLeftPaintProgress : caUnknown; break;
- case 0x0502: Action = (SlotNum == -999) ? caLeftPaintEnd : caUnknown; break;
- case 0x0504: Action = (SlotNum == -999) ? caRightPaintBegin : caUnknown; break;
- case 0x0505: Action = (SlotNum != -999) ? caRightPaintProgress : caUnknown; break;
- case 0x0506: Action = (SlotNum == -999) ? caRightPaintEnd : caUnknown; break;
- case 0x0600: Action = caDblClick; break;
- }
-
- if (Action == caUnknown)
- {
- LOGWARNING("Received an unknown click action combination: Mode = %d, Button = %d, Slot = %d, HeldItem = %s. Ignoring packet.",
- Mode, Button, SlotNum, ItemToFullString(HeldItem).c_str()
- );
- ASSERT(!"Unknown click action");
- return PARSE_OK;
- }
-
- m_Client->HandleWindowClick(WindowID, SlotNum, Action, HeldItem);
- return PARSE_OK;
-}
-
-
-
-
-
+ +// Protocol15x.cpp + +/* +Implements the 1.5.x protocol classes: + - cProtocol150 + - release 1.5 protocol (#60) + - release 1.5.2 protocol (#61, no relevant changes found) +*/ + +#include "Globals.h" +#include "Protocol15x.h" +#include "../ClientHandle.h" +#include "../Item.h" + + + + + +#define HANDLE_PACKET_READ(Proc, Type, Var) \ + Type Var; \ + { \ + if (!m_ReceivedData.Proc(Var)) \ + { \ + m_ReceivedData.CheckValid(); \ + return PARSE_INCOMPLETE; \ + } \ + m_ReceivedData.CheckValid(); \ + } + + + + + +enum +{ + PACKET_WINDOW_OPEN = 0x64, +} ; + + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cProtocol150: + +cProtocol150::cProtocol150(cClientHandle * a_Client) : + super(a_Client) +{ +} + + + + + +void cProtocol150::SendWindowOpen(char a_WindowID, char a_WindowType, const AString & a_WindowTitle, char a_NumSlots) +{ + if (a_WindowType < 0) + { + // Do not send for inventory windows + return; + } + cCSLock Lock(m_CSPacket); + WriteByte (PACKET_WINDOW_OPEN); + WriteByte (a_WindowID); + WriteByte (a_WindowType); + WriteString(a_WindowTitle); + WriteByte (a_NumSlots); + WriteByte (1); // Use title + Flush(); +} + + + + + +int cProtocol150::ParseWindowClick(void) +{ + HANDLE_PACKET_READ(ReadChar, char, WindowID); + HANDLE_PACKET_READ(ReadBEShort, short, SlotNum); + HANDLE_PACKET_READ(ReadByte, Byte, Button); + HANDLE_PACKET_READ(ReadBEShort, short, TransactionID); + HANDLE_PACKET_READ(ReadByte, Byte, Mode); + cItem HeldItem; + int res = ParseItem(HeldItem); + if (res < 0) + { + return res; + } + + // Convert Button, Mode, SlotNum and HeldItem into eClickAction: + eClickAction Action; + switch ((Mode << 8) | Button) + { + case 0x0000: Action = (SlotNum != -999) ? caLeftClick : caLeftClickOutside; break; + case 0x0001: Action = (SlotNum != -999) ? caRightClick : caRightClickOutside; break; + case 0x0100: Action = caShiftLeftClick; break; + case 0x0101: Action = caShiftRightClick; break; + case 0x0200: Action = caNumber1; break; + case 0x0201: Action = caNumber2; break; + case 0x0202: Action = caNumber3; break; + case 0x0203: Action = caNumber4; break; + case 0x0204: Action = caNumber5; break; + case 0x0205: Action = caNumber6; break; + case 0x0206: Action = caNumber7; break; + case 0x0207: Action = caNumber8; break; + case 0x0208: Action = caNumber9; break; + case 0x0300: Action = caMiddleClick; break; + case 0x0400: Action = (SlotNum == -999) ? caLeftClickOutsideHoldNothing : caDropKey; break; + case 0x0401: Action = (SlotNum == -999) ? caRightClickOutsideHoldNothing : caCtrlDropKey; break; + case 0x0500: Action = (SlotNum == -999) ? caLeftPaintBegin : caUnknown; break; + case 0x0501: Action = (SlotNum != -999) ? caLeftPaintProgress : caUnknown; break; + case 0x0502: Action = (SlotNum == -999) ? caLeftPaintEnd : caUnknown; break; + case 0x0504: Action = (SlotNum == -999) ? caRightPaintBegin : caUnknown; break; + case 0x0505: Action = (SlotNum != -999) ? caRightPaintProgress : caUnknown; break; + case 0x0506: Action = (SlotNum == -999) ? caRightPaintEnd : caUnknown; break; + case 0x0600: Action = caDblClick; break; + } + + if (Action == caUnknown) + { + LOGWARNING("Received an unknown click action combination: Mode = %d, Button = %d, Slot = %d, HeldItem = %s. Ignoring packet.", + Mode, Button, SlotNum, ItemToFullString(HeldItem).c_str() + ); + ASSERT(!"Unknown click action"); + return PARSE_OK; + } + + m_Client->HandleWindowClick(WindowID, SlotNum, Action, HeldItem); + return PARSE_OK; +} + + + + + diff --git a/source/Protocol/Protocol15x.h b/source/Protocol/Protocol15x.h index 73d73780d..3e1547df8 100644 --- a/source/Protocol/Protocol15x.h +++ b/source/Protocol/Protocol15x.h @@ -1,38 +1,38 @@ -
-// Protocol15x.h
-
-/*
-Declares the 1.5.x protocol classes:
- - cProtocol150
- - release 1.5 and 1.5.1 protocol (#60)
- - release 1.5.2 protocol (#61; no relevant changes found)
-*/
-
-
-
-
-
-#pragma once
-
-#include "Protocol14x.h"
-
-
-
-
-
-class cProtocol150 :
- public cProtocol146
-{
- typedef cProtocol146 super;
-
-public:
- cProtocol150(cClientHandle * a_Client);
-
- virtual void SendWindowOpen(char a_WindowID, char a_WindowType, const AString & a_WindowTitle, char a_NumSlots) override;
-
- virtual int ParseWindowClick(void);
-} ;
-
-
-
-
+ +// Protocol15x.h + +/* +Declares the 1.5.x protocol classes: + - cProtocol150 + - release 1.5 and 1.5.1 protocol (#60) + - release 1.5.2 protocol (#61; no relevant changes found) +*/ + + + + + +#pragma once + +#include "Protocol14x.h" + + + + + +class cProtocol150 : + public cProtocol146 +{ + typedef cProtocol146 super; + +public: + cProtocol150(cClientHandle * a_Client); + + virtual void SendWindowOpen(char a_WindowID, char a_WindowType, const AString & a_WindowTitle, char a_NumSlots) override; + + virtual int ParseWindowClick(void); +} ; + + + + diff --git a/source/Protocol/Protocol16x.cpp b/source/Protocol/Protocol16x.cpp index d06980228..820e71cd9 100644 --- a/source/Protocol/Protocol16x.cpp +++ b/source/Protocol/Protocol16x.cpp @@ -1,245 +1,245 @@ -
-// Protocol16x.cpp
-
-/*
-Implements the 1.6.x protocol classes:
- - cProtocol161
- - release 1.6.1 protocol (#73)
- - cProtocol162
- - release 1.6.2 protocol (#74)
-(others may be added later in the future for the 1.6 release series)
-*/
-
-#include "Globals.h"
-#include "Protocol16x.h"
-#include "../ClientHandle.h"
-#include "../Entity.h"
-#include "../Player.h"
-
-
-
-
-
-#define HANDLE_PACKET_READ(Proc, Type, Var) \
- Type Var; \
- { \
- if (!m_ReceivedData.Proc(Var)) \
- { \
- m_ReceivedData.CheckValid(); \
- return PARSE_INCOMPLETE; \
- } \
- m_ReceivedData.CheckValid(); \
- }
-
-
-
-
-
-enum
-{
- PACKET_CHAT = 0x03,
- PACKET_UPDATE_HEALTH = 0x08,
- PACKET_STEER_VEHICLE = 0x1b,
- PACKET_ATTACH_ENTITY = 0x27,
- PACKET_ENTITY_PROPERTIES = 0x2c,
- PACKET_WINDOW_OPEN = 0x64,
- PACKET_PLAYER_ABILITIES = 0xca,
-} ;
-
-
-
-
-
-///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// cProtocol161:
-
-cProtocol161::cProtocol161(cClientHandle * a_Client) :
- super(a_Client)
-{
-}
-
-
-
-
-
-void cProtocol161::SendAttachEntity(const cEntity & a_Entity, const cEntity * a_Vehicle)
-{
- cCSLock Lock(m_CSPacket);
- WriteByte(PACKET_ATTACH_ENTITY);
- WriteInt(a_Entity.GetUniqueID());
- WriteInt((a_Vehicle == NULL) ? -1 : a_Vehicle->GetUniqueID());
- WriteBool(false); // TODO: "Should use leash?" -> no
- Flush();
-}
-
-
-
-
-
-void cProtocol161::SendChat(const AString & a_Message)
-{
- super::SendChat(Printf("{\"text\":\"%s\"}", EscapeString(a_Message).c_str()));
-}
-
-
-
-
-void cProtocol161::SendGameMode(eGameMode a_GameMode)
-{
- super::SendGameMode(a_GameMode);
- SendPlayerMaxSpeed();
-}
-
-
-
-
-
-void cProtocol161::SendHealth(void)
-{
- cCSLock Lock(m_CSPacket);
- WriteByte (PACKET_UPDATE_HEALTH);
- WriteFloat((float)m_Client->GetPlayer()->GetHealth());
- WriteShort(m_Client->GetPlayer()->GetFoodLevel());
- WriteFloat((float)m_Client->GetPlayer()->GetFoodSaturationLevel());
- Flush();
-}
-
-
-
-
-
-void cProtocol161::SendPlayerMaxSpeed(void)
-{
- cCSLock Lock(m_CSPacket);
- WriteByte(PACKET_ENTITY_PROPERTIES);
- WriteInt(m_Client->GetPlayer()->GetUniqueID());
- WriteInt(1);
- WriteString("generic.movementSpeed");
- WriteDouble(m_Client->GetPlayer()->GetMaxSpeed());
- Flush();
-}
-
-
-
-
-
-void cProtocol161::SendRespawn(void)
-{
- // Besides sending the respawn, we need to also send the player max speed, otherwise the client reverts to super-fast
- super::SendRespawn();
- SendPlayerMaxSpeed();
-}
-
-
-
-
-
-void cProtocol161::SendWindowOpen(char a_WindowID, char a_WindowType, const AString & a_WindowTitle, char a_NumSlots)
-{
- if (a_WindowType < 0)
- {
- // Do not send for inventory windows
- return;
- }
- cCSLock Lock(m_CSPacket);
- WriteByte (PACKET_WINDOW_OPEN);
- WriteByte (a_WindowID);
- WriteByte (a_WindowType);
- WriteString(a_WindowTitle);
- WriteByte (a_NumSlots);
- WriteByte (1); // Use title
- if (a_WindowType == 11) // horse / donkey
- {
- WriteInt(0); // Unknown value sent only when window type is 11 (horse / donkey)
- }
- Flush();
-}
-
-
-
-
-
-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);
- return PARSE_OK;
-}
-
-
-
-
-
-int cProtocol161::ParsePlayerAbilities(void)
-{
- HANDLE_PACKET_READ(ReadByte, Byte, Flags);
- HANDLE_PACKET_READ(ReadBEFloat, float, FlyingSpeed);
- HANDLE_PACKET_READ(ReadBEFloat, float, WalkingSpeed);
- // TODO: m_Client->HandlePlayerAbilities(...);
- return PARSE_OK;
-}
-
-
-
-
-
-int cProtocol161::ParseSteerVehicle(void)
-{
- HANDLE_PACKET_READ(ReadBEFloat, float, Sideways);
- HANDLE_PACKET_READ(ReadBEFloat, float, Forward);
- HANDLE_PACKET_READ(ReadBool, bool, Jump);
- HANDLE_PACKET_READ(ReadBool, bool, Unmount);
- // TODO: m_Client->HandleSteerVehicle(...);
- if (Unmount)
- {
- m_Client->HandleUnmount();
- }
- return PARSE_OK;
-}
-
-
-
-
-
-int cProtocol161::ParsePacket(unsigned char a_PacketType)
-{
- switch (a_PacketType)
- {
- case PACKET_STEER_VEHICLE: return ParseSteerVehicle();
- default: return super::ParsePacket(a_PacketType);
- }
-}
-
-
-
-
-
-///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// cProtocol162:
-
-cProtocol162::cProtocol162(cClientHandle * a_Client) :
- super(a_Client)
-{
-}
-
-
-
-
-
-void cProtocol162::SendPlayerMaxSpeed(void)
-{
- cCSLock Lock(m_CSPacket);
- WriteByte(PACKET_ENTITY_PROPERTIES);
- WriteInt(m_Client->GetPlayer()->GetUniqueID());
- WriteInt(1);
- WriteString("generic.movementSpeed");
- WriteDouble(m_Client->GetPlayer()->GetMaxSpeed());
- WriteShort(0);
- Flush();
-}
-
-
-
-
+ +// Protocol16x.cpp + +/* +Implements the 1.6.x protocol classes: + - cProtocol161 + - release 1.6.1 protocol (#73) + - cProtocol162 + - release 1.6.2 protocol (#74) +(others may be added later in the future for the 1.6 release series) +*/ + +#include "Globals.h" +#include "Protocol16x.h" +#include "../ClientHandle.h" +#include "../Entity.h" +#include "../Player.h" + + + + + +#define HANDLE_PACKET_READ(Proc, Type, Var) \ + Type Var; \ + { \ + if (!m_ReceivedData.Proc(Var)) \ + { \ + m_ReceivedData.CheckValid(); \ + return PARSE_INCOMPLETE; \ + } \ + m_ReceivedData.CheckValid(); \ + } + + + + + +enum +{ + PACKET_CHAT = 0x03, + PACKET_UPDATE_HEALTH = 0x08, + PACKET_STEER_VEHICLE = 0x1b, + PACKET_ATTACH_ENTITY = 0x27, + PACKET_ENTITY_PROPERTIES = 0x2c, + PACKET_WINDOW_OPEN = 0x64, + PACKET_PLAYER_ABILITIES = 0xca, +} ; + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cProtocol161: + +cProtocol161::cProtocol161(cClientHandle * a_Client) : + super(a_Client) +{ +} + + + + + +void cProtocol161::SendAttachEntity(const cEntity & a_Entity, const cEntity * a_Vehicle) +{ + cCSLock Lock(m_CSPacket); + WriteByte(PACKET_ATTACH_ENTITY); + WriteInt(a_Entity.GetUniqueID()); + WriteInt((a_Vehicle == NULL) ? -1 : a_Vehicle->GetUniqueID()); + WriteBool(false); // TODO: "Should use leash?" -> no + Flush(); +} + + + + + +void cProtocol161::SendChat(const AString & a_Message) +{ + super::SendChat(Printf("{\"text\":\"%s\"}", EscapeString(a_Message).c_str())); +} + + + + +void cProtocol161::SendGameMode(eGameMode a_GameMode) +{ + super::SendGameMode(a_GameMode); + SendPlayerMaxSpeed(); +} + + + + + +void cProtocol161::SendHealth(void) +{ + cCSLock Lock(m_CSPacket); + WriteByte (PACKET_UPDATE_HEALTH); + WriteFloat((float)m_Client->GetPlayer()->GetHealth()); + WriteShort(m_Client->GetPlayer()->GetFoodLevel()); + WriteFloat((float)m_Client->GetPlayer()->GetFoodSaturationLevel()); + Flush(); +} + + + + + +void cProtocol161::SendPlayerMaxSpeed(void) +{ + cCSLock Lock(m_CSPacket); + WriteByte(PACKET_ENTITY_PROPERTIES); + WriteInt(m_Client->GetPlayer()->GetUniqueID()); + WriteInt(1); + WriteString("generic.movementSpeed"); + WriteDouble(m_Client->GetPlayer()->GetMaxSpeed()); + Flush(); +} + + + + + +void cProtocol161::SendRespawn(void) +{ + // Besides sending the respawn, we need to also send the player max speed, otherwise the client reverts to super-fast + super::SendRespawn(); + SendPlayerMaxSpeed(); +} + + + + + +void cProtocol161::SendWindowOpen(char a_WindowID, char a_WindowType, const AString & a_WindowTitle, char a_NumSlots) +{ + if (a_WindowType < 0) + { + // Do not send for inventory windows + return; + } + cCSLock Lock(m_CSPacket); + WriteByte (PACKET_WINDOW_OPEN); + WriteByte (a_WindowID); + WriteByte (a_WindowType); + WriteString(a_WindowTitle); + WriteByte (a_NumSlots); + WriteByte (1); // Use title + if (a_WindowType == 11) // horse / donkey + { + WriteInt(0); // Unknown value sent only when window type is 11 (horse / donkey) + } + Flush(); +} + + + + + +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); + return PARSE_OK; +} + + + + + +int cProtocol161::ParsePlayerAbilities(void) +{ + HANDLE_PACKET_READ(ReadByte, Byte, Flags); + HANDLE_PACKET_READ(ReadBEFloat, float, FlyingSpeed); + HANDLE_PACKET_READ(ReadBEFloat, float, WalkingSpeed); + // TODO: m_Client->HandlePlayerAbilities(...); + return PARSE_OK; +} + + + + + +int cProtocol161::ParseSteerVehicle(void) +{ + HANDLE_PACKET_READ(ReadBEFloat, float, Sideways); + HANDLE_PACKET_READ(ReadBEFloat, float, Forward); + HANDLE_PACKET_READ(ReadBool, bool, Jump); + HANDLE_PACKET_READ(ReadBool, bool, Unmount); + // TODO: m_Client->HandleSteerVehicle(...); + if (Unmount) + { + m_Client->HandleUnmount(); + } + return PARSE_OK; +} + + + + + +int cProtocol161::ParsePacket(unsigned char a_PacketType) +{ + switch (a_PacketType) + { + case PACKET_STEER_VEHICLE: return ParseSteerVehicle(); + default: return super::ParsePacket(a_PacketType); + } +} + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cProtocol162: + +cProtocol162::cProtocol162(cClientHandle * a_Client) : + super(a_Client) +{ +} + + + + + +void cProtocol162::SendPlayerMaxSpeed(void) +{ + cCSLock Lock(m_CSPacket); + WriteByte(PACKET_ENTITY_PROPERTIES); + WriteInt(m_Client->GetPlayer()->GetUniqueID()); + WriteInt(1); + WriteString("generic.movementSpeed"); + WriteDouble(m_Client->GetPlayer()->GetMaxSpeed()); + WriteShort(0); + Flush(); +} + + + + diff --git a/source/Protocol/Protocol16x.h b/source/Protocol/Protocol16x.h index e012585d1..4dba5eab6 100644 --- a/source/Protocol/Protocol16x.h +++ b/source/Protocol/Protocol16x.h @@ -1,73 +1,73 @@ -
-// Protocol16x.h
-
-/*
-Declares the 1.6.x protocol classes:
- - cProtocol161
- - release 1.6.1 protocol (#73)
- - cProtocol162
- - release 1.6.2 protocol (#74)
-(others may be added later in the future for the 1.6 release series)
-*/
-
-
-
-
-
-#pragma once
-
-#include "Protocol15x.h"
-
-
-
-
-
-class cProtocol161 :
- public cProtocol150
-{
- typedef cProtocol150 super;
-
-public:
- cProtocol161(cClientHandle * a_Client);
-
-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 SendGameMode (eGameMode a_GameMode) override;
- virtual void SendHealth (void) override;
- virtual void SendPlayerMaxSpeed(void) override;
- virtual void SendRespawn (void) override;
- virtual void SendWindowOpen (char a_WindowID, char a_WindowType, const AString & a_WindowTitle, char a_NumSlots) override;
-
- virtual int ParseEntityAction (void) override;
- virtual int ParsePlayerAbilities(void) override;
-
- // New packets:
- virtual int ParseSteerVehicle(void);
-
- // Enable new packets' handling
- virtual int ParsePacket(unsigned char a_PacketType) override;
-} ;
-
-
-
-
-
-class cProtocol162 :
- public cProtocol161
-{
- typedef cProtocol161 super;
-
-public:
- cProtocol162(cClientHandle * a_Client);
-
-protected:
- // cProtocol161 overrides:
- virtual void SendPlayerMaxSpeed(void) override;
-} ;
-
-
-
-
+ +// Protocol16x.h + +/* +Declares the 1.6.x protocol classes: + - cProtocol161 + - release 1.6.1 protocol (#73) + - cProtocol162 + - release 1.6.2 protocol (#74) +(others may be added later in the future for the 1.6 release series) +*/ + + + + + +#pragma once + +#include "Protocol15x.h" + + + + + +class cProtocol161 : + public cProtocol150 +{ + typedef cProtocol150 super; + +public: + cProtocol161(cClientHandle * a_Client); + +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 SendGameMode (eGameMode a_GameMode) override; + virtual void SendHealth (void) override; + virtual void SendPlayerMaxSpeed(void) override; + virtual void SendRespawn (void) override; + virtual void SendWindowOpen (char a_WindowID, char a_WindowType, const AString & a_WindowTitle, char a_NumSlots) override; + + virtual int ParseEntityAction (void) override; + virtual int ParsePlayerAbilities(void) override; + + // New packets: + virtual int ParseSteerVehicle(void); + + // Enable new packets' handling + virtual int ParsePacket(unsigned char a_PacketType) override; +} ; + + + + + +class cProtocol162 : + public cProtocol161 +{ + typedef cProtocol161 super; + +public: + cProtocol162(cClientHandle * a_Client); + +protected: + // cProtocol161 overrides: + virtual void SendPlayerMaxSpeed(void) override; +} ; + + + + diff --git a/source/Protocol/ProtocolRecognizer.cpp b/source/Protocol/ProtocolRecognizer.cpp index ec10eeb12..de4ccc03e 100644 --- a/source/Protocol/ProtocolRecognizer.cpp +++ b/source/Protocol/ProtocolRecognizer.cpp @@ -1,771 +1,771 @@ -
-// ProtocolRecognizer.cpp
-
-// Implements the cProtocolRecognizer class representing the meta-protocol that recognizes possibly multiple
-// protocol versions and redirects everything to them
-
-#include "Globals.h"
-
-#include "ProtocolRecognizer.h"
-#include "Protocol125.h"
-#include "Protocol132.h"
-#include "Protocol14x.h"
-#include "Protocol15x.h"
-#include "Protocol16x.h"
-#include "../ClientHandle.h"
-#include "../Root.h"
-#include "../World.h"
-#include "../ChatColor.h"
-
-
-
-
-
-cProtocolRecognizer::cProtocolRecognizer(cClientHandle * a_Client) :
- super(a_Client),
- m_Protocol(NULL),
- m_Buffer(512)
-{
-}
-
-
-
-
-
-cProtocolRecognizer::~cProtocolRecognizer()
-{
- delete m_Protocol;
-}
-
-
-
-
-
-AString cProtocolRecognizer::GetVersionTextFromInt(int a_ProtocolVersion)
-{
- switch (a_ProtocolVersion)
- {
- case PROTO_VERSION_1_2_5: return "1.2.5";
- case PROTO_VERSION_1_3_2: return "1.3.2";
- case PROTO_VERSION_1_4_2: return "1.4.2";
- case PROTO_VERSION_1_4_4: return "1.4.4";
- case PROTO_VERSION_1_4_6: return "1.4.6";
- case PROTO_VERSION_1_5_0: return "1.5";
- case PROTO_VERSION_1_5_2: return "1.5.2";
- case PROTO_VERSION_1_6_1: return "1.6.1";
- case PROTO_VERSION_1_6_2: return "1.6.2";
- }
- ASSERT(!"Unknown protocol version");
- return Printf("Unknown protocol (%d)", a_ProtocolVersion);
-}
-
-
-
-
-
-void cProtocolRecognizer::DataReceived(const char * a_Data, int a_Size)
-{
- if (m_Protocol == NULL)
- {
- if (!m_Buffer.Write(a_Data, a_Size))
- {
- m_Client->Kick("Unsupported protocol version");
- return;
- }
-
- if (!TryRecognizeProtocol())
- {
- return;
- }
-
- // The protocol has just been recognized, dump the whole m_Buffer contents into it for parsing:
- AString Dump;
- m_Buffer.ResetRead();
- m_Buffer.ReadAll(Dump);
- m_Protocol->DataReceived(Dump.data(), Dump.size());
- }
- else
- {
- m_Protocol->DataReceived(a_Data, a_Size);
- }
-}
-
-
-
-
-
-void cProtocolRecognizer::SendAttachEntity(const cEntity & a_Entity, const cEntity * a_Vehicle)
-{
- ASSERT(m_Protocol != NULL);
- m_Protocol->SendAttachEntity(a_Entity, a_Vehicle);
-}
-
-
-
-
-
-void cProtocolRecognizer::SendBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType)
-{
- ASSERT(m_Protocol != NULL);
- m_Protocol->SendBlockAction(a_BlockX, a_BlockY, a_BlockZ, a_Byte1, a_Byte2, a_BlockType);
-}
-
-
-
-
-
-void cProtocolRecognizer::SendBlockBreakAnim(int a_entityID, int a_BlockX, int a_BlockY, int a_BlockZ, char stage)
-{
- ASSERT(m_Protocol != NULL);
- m_Protocol->SendBlockBreakAnim(a_entityID, a_BlockX, a_BlockY, a_BlockZ, stage);
-}
-
-
-
-
-
-void cProtocolRecognizer::SendBlockChange(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
-{
- ASSERT(m_Protocol != NULL);
- m_Protocol->SendBlockChange(a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta);
-}
-
-
-
-
-
-void cProtocolRecognizer::SendBlockChanges(int a_ChunkX, int a_ChunkZ, const sSetBlockVector & a_Changes)
-{
- ASSERT(m_Protocol != NULL);
- m_Protocol->SendBlockChanges(a_ChunkX, a_ChunkZ, a_Changes);
-}
-
-
-
-
-
-void cProtocolRecognizer::SendChat(const AString & 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);
- m_Protocol->SendChunkData(a_ChunkX, a_ChunkZ, a_Serializer);
-}
-
-
-
-
-
-void cProtocolRecognizer::SendCollectPickup(const cPickup & a_Pickup, const cPlayer & a_Player)
-{
- ASSERT(m_Protocol != NULL);
- m_Protocol->SendCollectPickup(a_Pickup, a_Player);
-}
-
-
-
-
-
-void cProtocolRecognizer::SendDestroyEntity(const cEntity & a_Entity)
-{
- ASSERT(m_Protocol != NULL);
- m_Protocol->SendDestroyEntity(a_Entity);
-}
-
-
-
-
-
-void cProtocolRecognizer::SendDisconnect(const AString & a_Reason)
-{
- if (m_Protocol != NULL)
- {
- m_Protocol->SendDisconnect(a_Reason);
- }
- else
- {
- // This is used when the client sends a server-ping, respond with the default packet:
- WriteByte ((char)0xff); // PACKET_DISCONNECT
- WriteString(a_Reason);
- }
-}
-
-
-
-
-void cProtocolRecognizer::SendEntityEquipment(const cEntity & a_Entity, short a_SlotNum, const cItem & a_Item)
-{
- ASSERT(m_Protocol != NULL);
- m_Protocol->SendEntityEquipment(a_Entity, a_SlotNum, a_Item);
-}
-
-
-
-
-
-void cProtocolRecognizer::SendEntityHeadLook(const cEntity & a_Entity)
-{
- ASSERT(m_Protocol != NULL);
- m_Protocol->SendEntityHeadLook(a_Entity);
-}
-
-
-
-
-
-void cProtocolRecognizer::SendEntityLook(const cEntity & a_Entity)
-{
- ASSERT(m_Protocol != NULL);
- m_Protocol->SendEntityLook(a_Entity);
-}
-
-
-
-
-
-void cProtocolRecognizer::SendEntityMetadata(const cEntity & a_Entity)
-{
- ASSERT(m_Protocol != NULL);
- m_Protocol->SendEntityMetadata(a_Entity);
-}
-
-
-
-
-
-void cProtocolRecognizer::SendEntityProperties(const cEntity & a_Entity)
-{
- ASSERT(m_Protocol != NULL);
- m_Protocol->SendEntityProperties(a_Entity);
-}
-
-
-
-
-
-void cProtocolRecognizer::SendEntityRelMove(const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ)
-{
- ASSERT(m_Protocol != NULL);
- m_Protocol->SendEntityRelMove(a_Entity, a_RelX, a_RelY, a_RelZ);
-}
-
-
-
-
-
-void cProtocolRecognizer::SendEntityRelMoveLook(const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ)
-{
- ASSERT(m_Protocol != NULL);
- m_Protocol->SendEntityRelMoveLook(a_Entity, a_RelX, a_RelY, a_RelZ);
-}
-
-
-
-
-
-void cProtocolRecognizer::SendEntityStatus(const cEntity & a_Entity, char a_Status)
-{
- ASSERT(m_Protocol != NULL);
- m_Protocol->SendEntityStatus(a_Entity, a_Status);
-}
-
-
-
-
-
-void cProtocolRecognizer::SendEntityVelocity(const cEntity & a_Entity)
-{
- ASSERT(m_Protocol != NULL);
- m_Protocol->SendEntityVelocity(a_Entity);
-}
-
-
-
-
-
-void cProtocolRecognizer::SendExplosion(double a_BlockX, double a_BlockY, double a_BlockZ, float a_Radius, const cVector3iArray & a_BlocksAffected, const Vector3d & a_PlayerMotion)
-{
- ASSERT(m_Protocol != NULL);
- m_Protocol->SendExplosion(a_BlockX,a_BlockY,a_BlockZ,a_Radius, a_BlocksAffected, a_PlayerMotion);
-}
-
-
-
-
-
-void cProtocolRecognizer::SendGameMode(eGameMode a_GameMode)
-{
- ASSERT(m_Protocol != NULL);
- m_Protocol->SendGameMode(a_GameMode);
-}
-
-
-
-
-
-void cProtocolRecognizer::SendHealth(void)
-{
- ASSERT(m_Protocol != NULL);
- m_Protocol->SendHealth();
-}
-
-
-
-
-
-void cProtocolRecognizer::SendInventoryProgress(char a_WindowID, short a_Progressbar, short a_Value)
-{
- ASSERT(m_Protocol != NULL);
- m_Protocol->SendInventoryProgress(a_WindowID, a_Progressbar, a_Value);
-}
-
-
-
-
-
-void cProtocolRecognizer::SendInventorySlot(char a_WindowID, short a_SlotNum, const cItem & a_Item)
-{
- ASSERT(m_Protocol != NULL);
- m_Protocol->SendInventorySlot(a_WindowID, a_SlotNum, a_Item);
-}
-
-
-
-
-
-void cProtocolRecognizer::SendKeepAlive(int a_PingID)
-{
- ASSERT(m_Protocol != NULL);
- m_Protocol->SendKeepAlive(a_PingID);
-}
-
-
-
-
-
-void cProtocolRecognizer::SendLogin(const cPlayer & a_Player, const cWorld & a_World)
-{
- ASSERT(m_Protocol != NULL);
- m_Protocol->SendLogin(a_Player, a_World);
-}
-
-
-
-
-
-void cProtocolRecognizer::SendPickupSpawn(const cPickup & a_Pickup)
-{
- ASSERT(m_Protocol != NULL);
- m_Protocol->SendPickupSpawn(a_Pickup);
-}
-
-
-
-
-
-void cProtocolRecognizer::SendPlayerAnimation(const cPlayer & a_Player, char a_Animation)
-{
- ASSERT(m_Protocol != NULL);
- m_Protocol->SendPlayerAnimation(a_Player, a_Animation);
-}
-
-
-
-
-
-void cProtocolRecognizer::SendPlayerListItem(const cPlayer & a_Player, bool a_IsOnline)
-{
- ASSERT(m_Protocol != NULL);
- m_Protocol->SendPlayerListItem(a_Player, a_IsOnline);
-}
-
-
-
-
-
-void cProtocolRecognizer::SendPlayerMaxSpeed(void)
-{
- ASSERT(m_Protocol != NULL);
- m_Protocol->SendPlayerMaxSpeed();
-}
-
-
-
-
-
-void cProtocolRecognizer::SendPlayerMoveLook(void)
-{
- ASSERT(m_Protocol != NULL);
- m_Protocol->SendPlayerMoveLook();
-}
-
-
-
-
-
-void cProtocolRecognizer::SendPlayerPosition(void)
-{
- ASSERT(m_Protocol != NULL);
- m_Protocol->SendPlayerPosition();
-}
-
-
-
-
-
-void cProtocolRecognizer::SendPlayerSpawn(const cPlayer & a_Player)
-{
- ASSERT(m_Protocol != NULL);
- m_Protocol->SendPlayerSpawn(a_Player);
-}
-
-
-
-
-
-void cProtocolRecognizer::SendRespawn(void)
-{
- ASSERT(m_Protocol != NULL);
- m_Protocol->SendRespawn();
-}
-
-
-
-
-
-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);
- m_Protocol->SendSoundEffect(a_SoundName, a_SrcX, a_SrcY, a_SrcZ, a_Volume, a_Pitch);
-}
-
-
-
-
-
-void cProtocolRecognizer::SendSoundParticleEffect(int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data)
-{
- ASSERT(m_Protocol != NULL);
- m_Protocol->SendSoundParticleEffect(a_EffectID, a_SrcX, a_SrcY, a_SrcZ, a_Data);
-}
-
-
-
-
-
-void cProtocolRecognizer::SendSpawnFallingBlock(const cFallingBlock & a_FallingBlock)
-{
- ASSERT(m_Protocol != NULL);
- m_Protocol->SendSpawnFallingBlock(a_FallingBlock);
-}
-
-
-
-
-
-void cProtocolRecognizer::SendSpawnMob(const cMonster & a_Mob)
-{
- ASSERT(m_Protocol != NULL);
- m_Protocol->SendSpawnMob(a_Mob);
-}
-
-
-
-
-
-void cProtocolRecognizer::SendSpawnObject(const cEntity & a_Entity, char a_ObjectType, int a_ObjectData, Byte a_Yaw, Byte a_Pitch)
-{
- ASSERT(m_Protocol != NULL);
- m_Protocol->SendSpawnObject(a_Entity, a_ObjectType, a_ObjectData, a_Yaw, a_Pitch);
-}
-
-
-
-
-
-void cProtocolRecognizer::SendSpawnVehicle(const cEntity & a_Vehicle, char a_VehicleType)
-{
- ASSERT(m_Protocol != NULL);
- m_Protocol->SendSpawnVehicle(a_Vehicle, a_VehicleType);
-}
-
-
-
-
-
-void cProtocolRecognizer::SendTeleportEntity(const cEntity & a_Entity)
-{
- ASSERT(m_Protocol != NULL);
- m_Protocol->SendTeleportEntity(a_Entity);
-}
-
-
-
-
-
-void cProtocolRecognizer::SendThunderbolt(int a_BlockX, int a_BlockY, int a_BlockZ)
-{
- ASSERT(m_Protocol != NULL);
- m_Protocol->SendThunderbolt(a_BlockX, a_BlockY, a_BlockZ);
-}
-
-
-
-
-
-void cProtocolRecognizer::SendTimeUpdate(Int64 a_WorldAge, Int64 a_TimeOfDay)
-{
- ASSERT(m_Protocol != NULL);
- m_Protocol->SendTimeUpdate(a_WorldAge, a_TimeOfDay);
-}
-
-
-
-
-
-void cProtocolRecognizer::SendUnloadChunk(int a_ChunkX, int a_ChunkZ)
-{
- ASSERT(m_Protocol != NULL);
- m_Protocol->SendUnloadChunk(a_ChunkX, a_ChunkZ);
-}
-
-
-
-
-
-void cProtocolRecognizer::SendUpdateSign(int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4)
-{
- ASSERT(m_Protocol != NULL);
- m_Protocol->SendUpdateSign(a_BlockX, a_BlockY, a_BlockZ, a_Line1, a_Line2, a_Line3, a_Line4);
-}
-
-
-
-
-
-void cProtocolRecognizer::SendUseBed(const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ )
-{
- ASSERT(m_Protocol != NULL);
- m_Protocol->SendUseBed(a_Entity, a_BlockX, a_BlockY, a_BlockZ);
-}
-
-
-
-
-
-void cProtocolRecognizer::SendWeather(eWeather a_Weather)
-{
- ASSERT(m_Protocol != NULL);
- m_Protocol->SendWeather(a_Weather);
-}
-
-
-
-
-
-void cProtocolRecognizer::SendWholeInventory(const cInventory & a_Inventory)
-{
- ASSERT(m_Protocol != NULL);
- m_Protocol->SendWholeInventory(a_Inventory);
-}
-
-
-
-
-
-void cProtocolRecognizer::SendWholeInventory(const cWindow & a_Window)
-{
- ASSERT(m_Protocol != NULL);
- m_Protocol->SendWholeInventory(a_Window);
-}
-
-
-
-
-
-void cProtocolRecognizer::SendWindowClose(const cWindow & a_Window)
-{
- ASSERT(m_Protocol != NULL);
- m_Protocol->SendWindowClose(a_Window);
-}
-
-
-
-
-
-void cProtocolRecognizer::SendWindowOpen(char a_WindowID, char a_WindowType, const AString & a_WindowTitle, char a_NumSlots)
-{
- ASSERT(m_Protocol != NULL);
- m_Protocol->SendWindowOpen(a_WindowID, a_WindowType, a_WindowTitle, a_NumSlots);
-}
-
-
-
-
-
-AString cProtocolRecognizer::GetAuthServerID(void)
-{
- ASSERT(m_Protocol != NULL);
- return m_Protocol->GetAuthServerID();
-}
-
-
-
-
-
-void cProtocolRecognizer::SendData(const char * a_Data, int a_Size)
-{
- // This is used only when handling the server ping
- m_Client->SendData(a_Data, a_Size);
-}
-
-
-
-
-
-bool cProtocolRecognizer::TryRecognizeProtocol(void)
-{
- // NOTE: If a new protocol is added or an old one is removed, adjust MCS_CLIENT_VERSIONS and
- // MCS_PROTOCOL_VERSIONS macros in the header file, as well as PROTO_VERSION_LATEST macro
-
- // The first packet should be a Handshake, 0x02:
- unsigned char PacketType;
- if (!m_Buffer.ReadByte(PacketType))
- {
- return false;
- }
- switch (PacketType)
- {
- case 0x02: break; // Handshake, continue recognizing
- case 0xfe: HandleServerPing(); return false;
- default: return false;
- }
-
- // 1.3.2 starts with 0x02 0x39 <name-length-short>
- // 1.2.5 starts with 0x02 <name-length-short> and name is expected to less than 0x3900 long :)
- char ch;
- if (!m_Buffer.ReadChar(ch))
- {
- return false;
- }
- switch (ch)
- {
- case PROTO_VERSION_1_3_2:
- {
- m_Protocol = new cProtocol132(m_Client);
- return true;
- }
- case PROTO_VERSION_1_4_2:
- case PROTO_VERSION_1_4_4:
- {
- m_Protocol = new cProtocol142(m_Client);
- return true;
- }
- case PROTO_VERSION_1_4_6:
- {
- m_Protocol = new cProtocol146(m_Client);
- return true;
- }
- case PROTO_VERSION_1_5_0:
- case PROTO_VERSION_1_5_2:
- {
- m_Protocol = new cProtocol150(m_Client);
- return true;
- }
- case PROTO_VERSION_1_6_1:
- {
- m_Protocol = new cProtocol161(m_Client);
- return true;
- }
- case PROTO_VERSION_1_6_2:
- {
- m_Protocol = new cProtocol162(m_Client);
- return true;
- }
- }
- m_Protocol = new cProtocol125(m_Client);
- return true;
-}
-
-
-
-
-
-void cProtocolRecognizer::HandleServerPing(void)
-{
- AString Reply;
- switch (cRoot::Get()->m_PrimaryServerVersion)
- {
- case PROTO_VERSION_1_2_5:
- case PROTO_VERSION_1_3_2:
- {
- // http://wiki.vg/wiki/index.php?title=Protocol&oldid=3099#Server_List_Ping_.280xFE.29
- Printf(Reply, "%s%s%i%s%i",
- cRoot::Get()->GetDefaultWorld()->GetDescription().c_str(),
- cChatColor::Delimiter.c_str(),
- cRoot::Get()->GetDefaultWorld()->GetNumPlayers(),
- cChatColor::Delimiter.c_str(),
- cRoot::Get()->GetDefaultWorld()->GetMaxPlayers()
- );
- break;
- }
-
- case PROTO_VERSION_1_4_2:
- case PROTO_VERSION_1_4_4:
- case PROTO_VERSION_1_4_6:
- case PROTO_VERSION_1_5_0:
- case PROTO_VERSION_1_5_2:
- case PROTO_VERSION_1_6_1:
- case PROTO_VERSION_1_6_2:
- {
- // The server list ping now has 1 more byte of "magic". Mojang just loves to complicate stuff.
- // http://wiki.vg/wiki/index.php?title=Protocol&oldid=3101#Server_List_Ping_.280xFE.29
- // _X 2012_10_31: I know that this needn't eat the byte, since it still may be in transit.
- // Who cares? We're disconnecting anyway.
- if (m_Buffer.CanReadBytes(1))
- {
- byte val;
- m_Buffer.ReadByte(val);
- ASSERT(val == 0x01);
- }
-
- // http://wiki.vg/wiki/index.php?title=Server_List_Ping&oldid=3100
- AString NumPlayers;
- Printf(NumPlayers, "%d", cRoot::Get()->GetDefaultWorld()->GetNumPlayers());
- AString MaxPlayers;
- Printf(MaxPlayers, "%d", cRoot::Get()->GetDefaultWorld()->GetMaxPlayers());
-
- AString ProtocolVersionNum;
- Printf(ProtocolVersionNum, "%d", cRoot::Get()->m_PrimaryServerVersion);
- AString ProtocolVersionTxt(GetVersionTextFromInt(cRoot::Get()->m_PrimaryServerVersion));
-
- // Cannot use Printf() because of in-string NUL bytes.
- Reply = cChatColor::Delimiter;
- Reply.append("1");
- Reply.push_back(0);
- Reply.append(ProtocolVersionNum);
- Reply.push_back(0);
- Reply.append(ProtocolVersionTxt);
- Reply.push_back(0);
- Reply.append(cRoot::Get()->GetDefaultWorld()->GetDescription());
- Reply.push_back(0);
- Reply.append(NumPlayers);
- Reply.push_back(0);
- Reply.append(MaxPlayers);
- break;
- }
- } // switch (m_PrimaryServerVersion)
- m_Client->Kick(Reply);
-}
-
-
-
-
+ +// ProtocolRecognizer.cpp + +// Implements the cProtocolRecognizer class representing the meta-protocol that recognizes possibly multiple +// protocol versions and redirects everything to them + +#include "Globals.h" + +#include "ProtocolRecognizer.h" +#include "Protocol125.h" +#include "Protocol132.h" +#include "Protocol14x.h" +#include "Protocol15x.h" +#include "Protocol16x.h" +#include "../ClientHandle.h" +#include "../Root.h" +#include "../World.h" +#include "../ChatColor.h" + + + + + +cProtocolRecognizer::cProtocolRecognizer(cClientHandle * a_Client) : + super(a_Client), + m_Protocol(NULL), + m_Buffer(512) +{ +} + + + + + +cProtocolRecognizer::~cProtocolRecognizer() +{ + delete m_Protocol; +} + + + + + +AString cProtocolRecognizer::GetVersionTextFromInt(int a_ProtocolVersion) +{ + switch (a_ProtocolVersion) + { + case PROTO_VERSION_1_2_5: return "1.2.5"; + case PROTO_VERSION_1_3_2: return "1.3.2"; + case PROTO_VERSION_1_4_2: return "1.4.2"; + case PROTO_VERSION_1_4_4: return "1.4.4"; + case PROTO_VERSION_1_4_6: return "1.4.6"; + case PROTO_VERSION_1_5_0: return "1.5"; + case PROTO_VERSION_1_5_2: return "1.5.2"; + case PROTO_VERSION_1_6_1: return "1.6.1"; + case PROTO_VERSION_1_6_2: return "1.6.2"; + } + ASSERT(!"Unknown protocol version"); + return Printf("Unknown protocol (%d)", a_ProtocolVersion); +} + + + + + +void cProtocolRecognizer::DataReceived(const char * a_Data, int a_Size) +{ + if (m_Protocol == NULL) + { + if (!m_Buffer.Write(a_Data, a_Size)) + { + m_Client->Kick("Unsupported protocol version"); + return; + } + + if (!TryRecognizeProtocol()) + { + return; + } + + // The protocol has just been recognized, dump the whole m_Buffer contents into it for parsing: + AString Dump; + m_Buffer.ResetRead(); + m_Buffer.ReadAll(Dump); + m_Protocol->DataReceived(Dump.data(), Dump.size()); + } + else + { + m_Protocol->DataReceived(a_Data, a_Size); + } +} + + + + + +void cProtocolRecognizer::SendAttachEntity(const cEntity & a_Entity, const cEntity * a_Vehicle) +{ + ASSERT(m_Protocol != NULL); + m_Protocol->SendAttachEntity(a_Entity, a_Vehicle); +} + + + + + +void cProtocolRecognizer::SendBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType) +{ + ASSERT(m_Protocol != NULL); + m_Protocol->SendBlockAction(a_BlockX, a_BlockY, a_BlockZ, a_Byte1, a_Byte2, a_BlockType); +} + + + + + +void cProtocolRecognizer::SendBlockBreakAnim(int a_entityID, int a_BlockX, int a_BlockY, int a_BlockZ, char stage) +{ + ASSERT(m_Protocol != NULL); + m_Protocol->SendBlockBreakAnim(a_entityID, a_BlockX, a_BlockY, a_BlockZ, stage); +} + + + + + +void cProtocolRecognizer::SendBlockChange(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) +{ + ASSERT(m_Protocol != NULL); + m_Protocol->SendBlockChange(a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta); +} + + + + + +void cProtocolRecognizer::SendBlockChanges(int a_ChunkX, int a_ChunkZ, const sSetBlockVector & a_Changes) +{ + ASSERT(m_Protocol != NULL); + m_Protocol->SendBlockChanges(a_ChunkX, a_ChunkZ, a_Changes); +} + + + + + +void cProtocolRecognizer::SendChat(const AString & 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); + m_Protocol->SendChunkData(a_ChunkX, a_ChunkZ, a_Serializer); +} + + + + + +void cProtocolRecognizer::SendCollectPickup(const cPickup & a_Pickup, const cPlayer & a_Player) +{ + ASSERT(m_Protocol != NULL); + m_Protocol->SendCollectPickup(a_Pickup, a_Player); +} + + + + + +void cProtocolRecognizer::SendDestroyEntity(const cEntity & a_Entity) +{ + ASSERT(m_Protocol != NULL); + m_Protocol->SendDestroyEntity(a_Entity); +} + + + + + +void cProtocolRecognizer::SendDisconnect(const AString & a_Reason) +{ + if (m_Protocol != NULL) + { + m_Protocol->SendDisconnect(a_Reason); + } + else + { + // This is used when the client sends a server-ping, respond with the default packet: + WriteByte ((char)0xff); // PACKET_DISCONNECT + WriteString(a_Reason); + } +} + + + + +void cProtocolRecognizer::SendEntityEquipment(const cEntity & a_Entity, short a_SlotNum, const cItem & a_Item) +{ + ASSERT(m_Protocol != NULL); + m_Protocol->SendEntityEquipment(a_Entity, a_SlotNum, a_Item); +} + + + + + +void cProtocolRecognizer::SendEntityHeadLook(const cEntity & a_Entity) +{ + ASSERT(m_Protocol != NULL); + m_Protocol->SendEntityHeadLook(a_Entity); +} + + + + + +void cProtocolRecognizer::SendEntityLook(const cEntity & a_Entity) +{ + ASSERT(m_Protocol != NULL); + m_Protocol->SendEntityLook(a_Entity); +} + + + + + +void cProtocolRecognizer::SendEntityMetadata(const cEntity & a_Entity) +{ + ASSERT(m_Protocol != NULL); + m_Protocol->SendEntityMetadata(a_Entity); +} + + + + + +void cProtocolRecognizer::SendEntityProperties(const cEntity & a_Entity) +{ + ASSERT(m_Protocol != NULL); + m_Protocol->SendEntityProperties(a_Entity); +} + + + + + +void cProtocolRecognizer::SendEntityRelMove(const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ) +{ + ASSERT(m_Protocol != NULL); + m_Protocol->SendEntityRelMove(a_Entity, a_RelX, a_RelY, a_RelZ); +} + + + + + +void cProtocolRecognizer::SendEntityRelMoveLook(const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ) +{ + ASSERT(m_Protocol != NULL); + m_Protocol->SendEntityRelMoveLook(a_Entity, a_RelX, a_RelY, a_RelZ); +} + + + + + +void cProtocolRecognizer::SendEntityStatus(const cEntity & a_Entity, char a_Status) +{ + ASSERT(m_Protocol != NULL); + m_Protocol->SendEntityStatus(a_Entity, a_Status); +} + + + + + +void cProtocolRecognizer::SendEntityVelocity(const cEntity & a_Entity) +{ + ASSERT(m_Protocol != NULL); + m_Protocol->SendEntityVelocity(a_Entity); +} + + + + + +void cProtocolRecognizer::SendExplosion(double a_BlockX, double a_BlockY, double a_BlockZ, float a_Radius, const cVector3iArray & a_BlocksAffected, const Vector3d & a_PlayerMotion) +{ + ASSERT(m_Protocol != NULL); + m_Protocol->SendExplosion(a_BlockX,a_BlockY,a_BlockZ,a_Radius, a_BlocksAffected, a_PlayerMotion); +} + + + + + +void cProtocolRecognizer::SendGameMode(eGameMode a_GameMode) +{ + ASSERT(m_Protocol != NULL); + m_Protocol->SendGameMode(a_GameMode); +} + + + + + +void cProtocolRecognizer::SendHealth(void) +{ + ASSERT(m_Protocol != NULL); + m_Protocol->SendHealth(); +} + + + + + +void cProtocolRecognizer::SendInventoryProgress(char a_WindowID, short a_Progressbar, short a_Value) +{ + ASSERT(m_Protocol != NULL); + m_Protocol->SendInventoryProgress(a_WindowID, a_Progressbar, a_Value); +} + + + + + +void cProtocolRecognizer::SendInventorySlot(char a_WindowID, short a_SlotNum, const cItem & a_Item) +{ + ASSERT(m_Protocol != NULL); + m_Protocol->SendInventorySlot(a_WindowID, a_SlotNum, a_Item); +} + + + + + +void cProtocolRecognizer::SendKeepAlive(int a_PingID) +{ + ASSERT(m_Protocol != NULL); + m_Protocol->SendKeepAlive(a_PingID); +} + + + + + +void cProtocolRecognizer::SendLogin(const cPlayer & a_Player, const cWorld & a_World) +{ + ASSERT(m_Protocol != NULL); + m_Protocol->SendLogin(a_Player, a_World); +} + + + + + +void cProtocolRecognizer::SendPickupSpawn(const cPickup & a_Pickup) +{ + ASSERT(m_Protocol != NULL); + m_Protocol->SendPickupSpawn(a_Pickup); +} + + + + + +void cProtocolRecognizer::SendPlayerAnimation(const cPlayer & a_Player, char a_Animation) +{ + ASSERT(m_Protocol != NULL); + m_Protocol->SendPlayerAnimation(a_Player, a_Animation); +} + + + + + +void cProtocolRecognizer::SendPlayerListItem(const cPlayer & a_Player, bool a_IsOnline) +{ + ASSERT(m_Protocol != NULL); + m_Protocol->SendPlayerListItem(a_Player, a_IsOnline); +} + + + + + +void cProtocolRecognizer::SendPlayerMaxSpeed(void) +{ + ASSERT(m_Protocol != NULL); + m_Protocol->SendPlayerMaxSpeed(); +} + + + + + +void cProtocolRecognizer::SendPlayerMoveLook(void) +{ + ASSERT(m_Protocol != NULL); + m_Protocol->SendPlayerMoveLook(); +} + + + + + +void cProtocolRecognizer::SendPlayerPosition(void) +{ + ASSERT(m_Protocol != NULL); + m_Protocol->SendPlayerPosition(); +} + + + + + +void cProtocolRecognizer::SendPlayerSpawn(const cPlayer & a_Player) +{ + ASSERT(m_Protocol != NULL); + m_Protocol->SendPlayerSpawn(a_Player); +} + + + + + +void cProtocolRecognizer::SendRespawn(void) +{ + ASSERT(m_Protocol != NULL); + m_Protocol->SendRespawn(); +} + + + + + +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); + m_Protocol->SendSoundEffect(a_SoundName, a_SrcX, a_SrcY, a_SrcZ, a_Volume, a_Pitch); +} + + + + + +void cProtocolRecognizer::SendSoundParticleEffect(int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data) +{ + ASSERT(m_Protocol != NULL); + m_Protocol->SendSoundParticleEffect(a_EffectID, a_SrcX, a_SrcY, a_SrcZ, a_Data); +} + + + + + +void cProtocolRecognizer::SendSpawnFallingBlock(const cFallingBlock & a_FallingBlock) +{ + ASSERT(m_Protocol != NULL); + m_Protocol->SendSpawnFallingBlock(a_FallingBlock); +} + + + + + +void cProtocolRecognizer::SendSpawnMob(const cMonster & a_Mob) +{ + ASSERT(m_Protocol != NULL); + m_Protocol->SendSpawnMob(a_Mob); +} + + + + + +void cProtocolRecognizer::SendSpawnObject(const cEntity & a_Entity, char a_ObjectType, int a_ObjectData, Byte a_Yaw, Byte a_Pitch) +{ + ASSERT(m_Protocol != NULL); + m_Protocol->SendSpawnObject(a_Entity, a_ObjectType, a_ObjectData, a_Yaw, a_Pitch); +} + + + + + +void cProtocolRecognizer::SendSpawnVehicle(const cEntity & a_Vehicle, char a_VehicleType) +{ + ASSERT(m_Protocol != NULL); + m_Protocol->SendSpawnVehicle(a_Vehicle, a_VehicleType); +} + + + + + +void cProtocolRecognizer::SendTeleportEntity(const cEntity & a_Entity) +{ + ASSERT(m_Protocol != NULL); + m_Protocol->SendTeleportEntity(a_Entity); +} + + + + + +void cProtocolRecognizer::SendThunderbolt(int a_BlockX, int a_BlockY, int a_BlockZ) +{ + ASSERT(m_Protocol != NULL); + m_Protocol->SendThunderbolt(a_BlockX, a_BlockY, a_BlockZ); +} + + + + + +void cProtocolRecognizer::SendTimeUpdate(Int64 a_WorldAge, Int64 a_TimeOfDay) +{ + ASSERT(m_Protocol != NULL); + m_Protocol->SendTimeUpdate(a_WorldAge, a_TimeOfDay); +} + + + + + +void cProtocolRecognizer::SendUnloadChunk(int a_ChunkX, int a_ChunkZ) +{ + ASSERT(m_Protocol != NULL); + m_Protocol->SendUnloadChunk(a_ChunkX, a_ChunkZ); +} + + + + + +void cProtocolRecognizer::SendUpdateSign(int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4) +{ + ASSERT(m_Protocol != NULL); + m_Protocol->SendUpdateSign(a_BlockX, a_BlockY, a_BlockZ, a_Line1, a_Line2, a_Line3, a_Line4); +} + + + + + +void cProtocolRecognizer::SendUseBed(const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ ) +{ + ASSERT(m_Protocol != NULL); + m_Protocol->SendUseBed(a_Entity, a_BlockX, a_BlockY, a_BlockZ); +} + + + + + +void cProtocolRecognizer::SendWeather(eWeather a_Weather) +{ + ASSERT(m_Protocol != NULL); + m_Protocol->SendWeather(a_Weather); +} + + + + + +void cProtocolRecognizer::SendWholeInventory(const cInventory & a_Inventory) +{ + ASSERT(m_Protocol != NULL); + m_Protocol->SendWholeInventory(a_Inventory); +} + + + + + +void cProtocolRecognizer::SendWholeInventory(const cWindow & a_Window) +{ + ASSERT(m_Protocol != NULL); + m_Protocol->SendWholeInventory(a_Window); +} + + + + + +void cProtocolRecognizer::SendWindowClose(const cWindow & a_Window) +{ + ASSERT(m_Protocol != NULL); + m_Protocol->SendWindowClose(a_Window); +} + + + + + +void cProtocolRecognizer::SendWindowOpen(char a_WindowID, char a_WindowType, const AString & a_WindowTitle, char a_NumSlots) +{ + ASSERT(m_Protocol != NULL); + m_Protocol->SendWindowOpen(a_WindowID, a_WindowType, a_WindowTitle, a_NumSlots); +} + + + + + +AString cProtocolRecognizer::GetAuthServerID(void) +{ + ASSERT(m_Protocol != NULL); + return m_Protocol->GetAuthServerID(); +} + + + + + +void cProtocolRecognizer::SendData(const char * a_Data, int a_Size) +{ + // This is used only when handling the server ping + m_Client->SendData(a_Data, a_Size); +} + + + + + +bool cProtocolRecognizer::TryRecognizeProtocol(void) +{ + // NOTE: If a new protocol is added or an old one is removed, adjust MCS_CLIENT_VERSIONS and + // MCS_PROTOCOL_VERSIONS macros in the header file, as well as PROTO_VERSION_LATEST macro + + // The first packet should be a Handshake, 0x02: + unsigned char PacketType; + if (!m_Buffer.ReadByte(PacketType)) + { + return false; + } + switch (PacketType) + { + case 0x02: break; // Handshake, continue recognizing + case 0xfe: HandleServerPing(); return false; + default: return false; + } + + // 1.3.2 starts with 0x02 0x39 <name-length-short> + // 1.2.5 starts with 0x02 <name-length-short> and name is expected to less than 0x3900 long :) + char ch; + if (!m_Buffer.ReadChar(ch)) + { + return false; + } + switch (ch) + { + case PROTO_VERSION_1_3_2: + { + m_Protocol = new cProtocol132(m_Client); + return true; + } + case PROTO_VERSION_1_4_2: + case PROTO_VERSION_1_4_4: + { + m_Protocol = new cProtocol142(m_Client); + return true; + } + case PROTO_VERSION_1_4_6: + { + m_Protocol = new cProtocol146(m_Client); + return true; + } + case PROTO_VERSION_1_5_0: + case PROTO_VERSION_1_5_2: + { + m_Protocol = new cProtocol150(m_Client); + return true; + } + case PROTO_VERSION_1_6_1: + { + m_Protocol = new cProtocol161(m_Client); + return true; + } + case PROTO_VERSION_1_6_2: + { + m_Protocol = new cProtocol162(m_Client); + return true; + } + } + m_Protocol = new cProtocol125(m_Client); + return true; +} + + + + + +void cProtocolRecognizer::HandleServerPing(void) +{ + AString Reply; + switch (cRoot::Get()->m_PrimaryServerVersion) + { + case PROTO_VERSION_1_2_5: + case PROTO_VERSION_1_3_2: + { + // http://wiki.vg/wiki/index.php?title=Protocol&oldid=3099#Server_List_Ping_.280xFE.29 + Printf(Reply, "%s%s%i%s%i", + cRoot::Get()->GetDefaultWorld()->GetDescription().c_str(), + cChatColor::Delimiter.c_str(), + cRoot::Get()->GetDefaultWorld()->GetNumPlayers(), + cChatColor::Delimiter.c_str(), + cRoot::Get()->GetDefaultWorld()->GetMaxPlayers() + ); + break; + } + + case PROTO_VERSION_1_4_2: + case PROTO_VERSION_1_4_4: + case PROTO_VERSION_1_4_6: + case PROTO_VERSION_1_5_0: + case PROTO_VERSION_1_5_2: + case PROTO_VERSION_1_6_1: + case PROTO_VERSION_1_6_2: + { + // The server list ping now has 1 more byte of "magic". Mojang just loves to complicate stuff. + // http://wiki.vg/wiki/index.php?title=Protocol&oldid=3101#Server_List_Ping_.280xFE.29 + // _X 2012_10_31: I know that this needn't eat the byte, since it still may be in transit. + // Who cares? We're disconnecting anyway. + if (m_Buffer.CanReadBytes(1)) + { + byte val; + m_Buffer.ReadByte(val); + ASSERT(val == 0x01); + } + + // http://wiki.vg/wiki/index.php?title=Server_List_Ping&oldid=3100 + AString NumPlayers; + Printf(NumPlayers, "%d", cRoot::Get()->GetDefaultWorld()->GetNumPlayers()); + AString MaxPlayers; + Printf(MaxPlayers, "%d", cRoot::Get()->GetDefaultWorld()->GetMaxPlayers()); + + AString ProtocolVersionNum; + Printf(ProtocolVersionNum, "%d", cRoot::Get()->m_PrimaryServerVersion); + AString ProtocolVersionTxt(GetVersionTextFromInt(cRoot::Get()->m_PrimaryServerVersion)); + + // Cannot use Printf() because of in-string NUL bytes. + Reply = cChatColor::Delimiter; + Reply.append("1"); + Reply.push_back(0); + Reply.append(ProtocolVersionNum); + Reply.push_back(0); + Reply.append(ProtocolVersionTxt); + Reply.push_back(0); + Reply.append(cRoot::Get()->GetDefaultWorld()->GetDescription()); + Reply.push_back(0); + Reply.append(NumPlayers); + Reply.push_back(0); + Reply.append(MaxPlayers); + break; + } + } // switch (m_PrimaryServerVersion) + m_Client->Kick(Reply); +} + + + + diff --git a/source/Protocol/ProtocolRecognizer.h b/source/Protocol/ProtocolRecognizer.h index 96d03082d..2179f3b05 100644 --- a/source/Protocol/ProtocolRecognizer.h +++ b/source/Protocol/ProtocolRecognizer.h @@ -1,130 +1,130 @@ -
-// ProtocolRecognizer.h
-
-// Interfaces to the cProtocolRecognizer class representing the meta-protocol that recognizes possibly multiple
-// protocol versions and redirects everything to them
-
-
-
-
-
-#pragma once
-
-#include "Protocol.h"
-#include "../ByteBuffer.h"
-
-
-
-
-
-// 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"
-#define MCS_PROTOCOL_VERSIONS "29, 39, 47, 49, 51, 60, 61, 73, 74"
-
-
-
-
-
-class cProtocolRecognizer :
- public cProtocol
-{
- typedef cProtocol super;
-
-public:
- enum
- {
- PROTO_VERSION_1_2_5 = 29,
- PROTO_VERSION_1_3_2 = 39,
- PROTO_VERSION_1_4_2 = 47,
- PROTO_VERSION_1_4_4 = 49,
- PROTO_VERSION_1_4_6 = 51,
- PROTO_VERSION_1_5_0 = 60,
- PROTO_VERSION_1_5_2 = 61,
- PROTO_VERSION_1_6_1 = 73,
- PROTO_VERSION_1_6_2 = 74,
-
- PROTO_VERSION_NEXT,
- PROTO_VERSION_LATEST = PROTO_VERSION_NEXT - 1, ///< Automatically assigned to the last protocol version, this serves as the default for PrimaryServerVersion
- } ;
-
- cProtocolRecognizer(cClientHandle * a_Client);
- virtual ~cProtocolRecognizer();
-
- /// Translates protocol version number into protocol version text: 49 -> "1.4.4"
- static AString GetVersionTextFromInt(int a_ProtocolVersion);
-
- /// Called when client sends some data:
- virtual void DataReceived(const char * a_Data, int a_Size) override;
-
- /// Sending stuff to clients (alphabetically sorted):
- virtual void SendAttachEntity (const cEntity & a_Entity, const cEntity * a_Vehicle) override;
- virtual void SendBlockAction (int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType) override;
- virtual void SendBlockBreakAnim (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 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;
- virtual void SendDisconnect (const AString & a_Reason) override;
- virtual void SendEntityEquipment (const cEntity & a_Entity, short a_SlotNum, const cItem & a_Item) override;
- virtual void SendEntityHeadLook (const cEntity & a_Entity) override;
- virtual void SendEntityLook (const cEntity & a_Entity) override;
- virtual void SendEntityMetadata (const cEntity & a_Entity) override;
- virtual void SendEntityProperties (const cEntity & a_Entity) override;
- virtual void SendEntityRelMove (const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ) override;
- virtual void SendEntityRelMoveLook (const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ) override;
- virtual void SendEntityStatus (const cEntity & a_Entity, char a_Status) override;
- virtual void SendEntityVelocity (const cEntity & a_Entity) override;
- virtual void SendExplosion (double a_BlockX, double a_BlockY, double a_BlockZ, float a_Radius, const cVector3iArray & a_BlocksAffected, const Vector3d & a_PlayerMotion) override;
- virtual void SendGameMode (eGameMode a_GameMode) override;
- virtual void SendHealth (void) override;
- virtual void SendInventoryProgress (char a_WindowID, short a_Progressbar, short a_Value) override;
- 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 SendPickupSpawn (const cPickup & a_Pickup) override;
- virtual void SendPlayerAnimation (const cPlayer & a_Player, char a_Animation) override;
- virtual void SendPlayerListItem (const cPlayer & a_Player, bool a_IsOnline) override;
- virtual void SendPlayerMaxSpeed (void) override;
- virtual void SendPlayerMoveLook (void) override;
- virtual void SendPlayerPosition (void) override;
- virtual void SendPlayerSpawn (const cPlayer & a_Player) override;
- virtual void SendRespawn (void) 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;
- virtual void SendSpawnMob (const cMonster & a_Mob) override;
- virtual void SendSpawnObject (const cEntity & a_Entity, char a_ObjectType, int a_ObjectData, Byte a_Yaw, Byte a_Pitch) override;
- virtual void SendSpawnVehicle (const cEntity & a_Vehicle, char a_VehicleType) override;
- virtual void SendTeleportEntity (const cEntity & a_Entity) override;
- virtual void SendThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ) override;
- virtual void SendTimeUpdate (Int64 a_WorldAge, Int64 a_TimeOfDay) override;
- virtual void SendUnloadChunk (int a_ChunkX, int a_ChunkZ) override;
- virtual void SendUpdateSign (int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4) override;
- virtual void SendUseBed (const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ ) override;
- virtual void SendWeather (eWeather a_Weather) override;
- virtual void SendWholeInventory (const cInventory & a_Inventory) override;
- virtual void SendWholeInventory (const cWindow & a_Window) override;
- virtual void SendWindowClose (const cWindow & a_Window) override;
- virtual void SendWindowOpen (char a_WindowID, char a_WindowType, const AString & a_WindowTitle, char a_NumSlots) override;
-
- virtual AString GetAuthServerID(void) override;
-
- virtual void SendData(const char * a_Data, int a_Size) override;
-
-protected:
- cProtocol * m_Protocol; //< The recognized protocol
- cByteBuffer m_Buffer; //< Buffer for the incoming data until we recognize the protocol
-
- /// Tries to recognize protocol based on m_Buffer contents; returns true if recognized
- bool TryRecognizeProtocol(void);
-
- /// Called when the recognizer gets a server ping packet; responds with server stats and destroys the client
- void HandleServerPing(void);
-} ;
-
-
-
-
-
+ +// ProtocolRecognizer.h + +// Interfaces to the cProtocolRecognizer class representing the meta-protocol that recognizes possibly multiple +// protocol versions and redirects everything to them + + + + + +#pragma once + +#include "Protocol.h" +#include "../ByteBuffer.h" + + + + + +// 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" +#define MCS_PROTOCOL_VERSIONS "29, 39, 47, 49, 51, 60, 61, 73, 74" + + + + + +class cProtocolRecognizer : + public cProtocol +{ + typedef cProtocol super; + +public: + enum + { + PROTO_VERSION_1_2_5 = 29, + PROTO_VERSION_1_3_2 = 39, + PROTO_VERSION_1_4_2 = 47, + PROTO_VERSION_1_4_4 = 49, + PROTO_VERSION_1_4_6 = 51, + PROTO_VERSION_1_5_0 = 60, + PROTO_VERSION_1_5_2 = 61, + PROTO_VERSION_1_6_1 = 73, + PROTO_VERSION_1_6_2 = 74, + + PROTO_VERSION_NEXT, + PROTO_VERSION_LATEST = PROTO_VERSION_NEXT - 1, ///< Automatically assigned to the last protocol version, this serves as the default for PrimaryServerVersion + } ; + + cProtocolRecognizer(cClientHandle * a_Client); + virtual ~cProtocolRecognizer(); + + /// Translates protocol version number into protocol version text: 49 -> "1.4.4" + static AString GetVersionTextFromInt(int a_ProtocolVersion); + + /// Called when client sends some data: + virtual void DataReceived(const char * a_Data, int a_Size) override; + + /// Sending stuff to clients (alphabetically sorted): + virtual void SendAttachEntity (const cEntity & a_Entity, const cEntity * a_Vehicle) override; + virtual void SendBlockAction (int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType) override; + virtual void SendBlockBreakAnim (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 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; + virtual void SendDisconnect (const AString & a_Reason) override; + virtual void SendEntityEquipment (const cEntity & a_Entity, short a_SlotNum, const cItem & a_Item) override; + virtual void SendEntityHeadLook (const cEntity & a_Entity) override; + virtual void SendEntityLook (const cEntity & a_Entity) override; + virtual void SendEntityMetadata (const cEntity & a_Entity) override; + virtual void SendEntityProperties (const cEntity & a_Entity) override; + virtual void SendEntityRelMove (const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ) override; + virtual void SendEntityRelMoveLook (const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ) override; + virtual void SendEntityStatus (const cEntity & a_Entity, char a_Status) override; + virtual void SendEntityVelocity (const cEntity & a_Entity) override; + virtual void SendExplosion (double a_BlockX, double a_BlockY, double a_BlockZ, float a_Radius, const cVector3iArray & a_BlocksAffected, const Vector3d & a_PlayerMotion) override; + virtual void SendGameMode (eGameMode a_GameMode) override; + virtual void SendHealth (void) override; + virtual void SendInventoryProgress (char a_WindowID, short a_Progressbar, short a_Value) override; + 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 SendPickupSpawn (const cPickup & a_Pickup) override; + virtual void SendPlayerAnimation (const cPlayer & a_Player, char a_Animation) override; + virtual void SendPlayerListItem (const cPlayer & a_Player, bool a_IsOnline) override; + virtual void SendPlayerMaxSpeed (void) override; + virtual void SendPlayerMoveLook (void) override; + virtual void SendPlayerPosition (void) override; + virtual void SendPlayerSpawn (const cPlayer & a_Player) override; + virtual void SendRespawn (void) 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; + virtual void SendSpawnMob (const cMonster & a_Mob) override; + virtual void SendSpawnObject (const cEntity & a_Entity, char a_ObjectType, int a_ObjectData, Byte a_Yaw, Byte a_Pitch) override; + virtual void SendSpawnVehicle (const cEntity & a_Vehicle, char a_VehicleType) override; + virtual void SendTeleportEntity (const cEntity & a_Entity) override; + virtual void SendThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ) override; + virtual void SendTimeUpdate (Int64 a_WorldAge, Int64 a_TimeOfDay) override; + virtual void SendUnloadChunk (int a_ChunkX, int a_ChunkZ) override; + virtual void SendUpdateSign (int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4) override; + virtual void SendUseBed (const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ ) override; + virtual void SendWeather (eWeather a_Weather) override; + virtual void SendWholeInventory (const cInventory & a_Inventory) override; + virtual void SendWholeInventory (const cWindow & a_Window) override; + virtual void SendWindowClose (const cWindow & a_Window) override; + virtual void SendWindowOpen (char a_WindowID, char a_WindowType, const AString & a_WindowTitle, char a_NumSlots) override; + + virtual AString GetAuthServerID(void) override; + + virtual void SendData(const char * a_Data, int a_Size) override; + +protected: + cProtocol * m_Protocol; //< The recognized protocol + cByteBuffer m_Buffer; //< Buffer for the incoming data until we recognize the protocol + + /// Tries to recognize protocol based on m_Buffer contents; returns true if recognized + bool TryRecognizeProtocol(void); + + /// Called when the recognizer gets a server ping packet; responds with server stats and destroys the client + void HandleServerPing(void); +} ; + + + + + |