From 7824ce9d6352664bd291e57a3084e5c51af5d4a6 Mon Sep 17 00:00:00 2001 From: "madmaxoft@gmail.com" Date: Fri, 31 Aug 2012 21:59:57 +0000 Subject: [PATCH] Progress on the 1.3.2 protocol. Sometimes the client lets the player through, but most of the times the connection breaks for no apparent reason. git-svn-id: http://mc-server.googlecode.com/svn/trunk@812 0a769ca7-a7f5-676a-18bf-c427514a06d6 --- source/ChunkDataSerializer.cpp | 60 +++++- source/ChunkDataSerializer.h | 2 + source/Protocol.h | 2 +- source/Protocol125.cpp | 124 ++++++------ source/Protocol125.h | 2 +- source/Protocol132.cpp | 339 +++++++++++++++++++++++++++++++-- source/Protocol132.h | 40 +++- source/ProtocolRecognizer.cpp | 4 +- source/ProtocolRecognizer.h | 2 +- source/cChestEntity.cpp | 2 +- source/cChunk.cpp | 4 +- source/cChunk.h | 2 +- source/cChunkMap.cpp | 4 +- source/cChunkMap.h | 2 +- source/cClientHandle.cpp | 4 +- source/cClientHandle.h | 2 +- source/cNoteEntity.cpp | 2 +- source/cPiston.cpp | 4 +- source/cPlayer.cpp | 2 +- source/cWorld.cpp | 4 +- source/cWorld.h | 2 +- 21 files changed, 500 insertions(+), 109 deletions(-) diff --git a/source/ChunkDataSerializer.cpp b/source/ChunkDataSerializer.cpp index 1d798beb2..7af07f331 100644 --- a/source/ChunkDataSerializer.cpp +++ b/source/ChunkDataSerializer.cpp @@ -42,6 +42,7 @@ const AString & cChunkDataSerializer::Serialize(int a_Version) 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: @@ -95,7 +96,7 @@ void cChunkDataSerializer::Serialize29(AString & a_Data) // Now put all those data into a_Data: // "Ground-up continuous", or rather, "biome data present" flag: - a_Data.push_back('\xff'); + 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 @@ -116,3 +117,60 @@ void cChunkDataSerializer::Serialize29(AString & a_Data) + +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/ChunkDataSerializer.h b/source/ChunkDataSerializer.h index 4c2f4fb4c..513a232b9 100644 --- a/source/ChunkDataSerializer.h +++ b/source/ChunkDataSerializer.h @@ -23,11 +23,13 @@ protected: 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( diff --git a/source/Protocol.h b/source/Protocol.h index 2b6bdd561..f3e688afb 100644 --- a/source/Protocol.h +++ b/source/Protocol.h @@ -41,7 +41,7 @@ public: virtual void DataReceived(const char * a_Data, int a_Size) = 0; // Sending stuff to clients: - virtual void SendBlockAction (int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2) = 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 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; diff --git a/source/Protocol125.cpp b/source/Protocol125.cpp index ce86e70c4..2adb68fa0 100644 --- a/source/Protocol125.cpp +++ b/source/Protocol125.cpp @@ -112,8 +112,10 @@ cProtocol125::cProtocol125(cClientHandle * a_Client) : -void cProtocol125::SendBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2) +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); @@ -301,6 +303,42 @@ void cProtocol125::SendEntityStatus(const cEntity & a_Entity, char a_Status) +void cProtocol125::SendEntRelMove(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::SendEntRelMoveLook(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::SendGameMode(eGameMode a_GameMode) { cCSLock Lock(m_CSPacket); @@ -386,7 +424,7 @@ void cProtocol125::SendLogin(const cPlayer & a_Player) WriteByte (PACKET_LOGIN); WriteInt (a_Player.GetUniqueID()); // EntityID of the player WriteString(""); // Username, not used - WriteString("DEFAULT"); // Level type + WriteString("default"); // Level type WriteInt ((int)a_Player.GetGameMode()); WriteInt (0); // TODO: Dimension (Nether / Overworld / End) WriteByte (2); // TODO: Difficulty @@ -416,17 +454,15 @@ void cProtocol125::SendMetadata(const cEntity & a_Entity) 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); - WriteInt ((int)(a_Pickup.GetPosX() * 32)); - WriteInt ((int)(a_Pickup.GetPosY() * 32)); - WriteInt ((int)(a_Pickup.GetPosZ() * 32)); - WriteByte ((char)(a_Pickup.GetSpeed().x * 8)); - WriteByte ((char)(a_Pickup.GetSpeed().y * 8)); - WriteByte ((char)(a_Pickup.GetSpeed().z * 8)); + 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(); } @@ -509,7 +545,7 @@ void cProtocol125::SendPlayerSpawn(const cPlayer & a_Player) { const cItem & HeldItem = a_Player.GetEquippedItem(); cCSLock Lock(m_CSPacket); - WriteByte (PACKET_PLAYER_SPAWN); + WriteByte (PACKET_PLAYER_SPAWN); WriteInt (a_Player.GetUniqueID()); WriteString(a_Player.GetName()); WriteInt ((int)(a_Player.GetPosX() * 32)); @@ -525,42 +561,6 @@ void cProtocol125::SendPlayerSpawn(const cPlayer & a_Player) -void cProtocol125::SendEntRelMove(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::SendEntRelMoveLook(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::SendRespawn(void) { cCSLock Lock(m_CSPacket); @@ -569,7 +569,7 @@ void cProtocol125::SendRespawn(void) WriteByte (2); // TODO: Difficulty; 2 = Normal WriteByte ((char)m_Client->GetPlayer()->GetGameMode()); WriteShort (256); // Current world height - WriteString("DEFAULT"); + WriteString("default"); } @@ -579,16 +579,13 @@ void cProtocol125::SendRespawn(void) void cProtocol125::SendSpawnMob(const cMonster & a_Mob) { cCSLock Lock(m_CSPacket); - Vector3i Pos = (Vector3i)(a_Mob.GetPosition() * 32); - WriteByte(PACKET_SPAWN_MOB); - WriteInt (a_Mob.GetUniqueID()); - WriteByte(a_Mob.GetMobType()); - WriteInt (Pos.x); - WriteInt (Pos.y); - WriteInt (Pos.z); - WriteByte(0); - WriteByte(0); - WriteByte(0); + 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(); @@ -740,6 +737,11 @@ void cProtocol125::SendWindowClose(char a_WindowID) 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); diff --git a/source/Protocol125.h b/source/Protocol125.h index 3e0535163..2d6696c85 100644 --- a/source/Protocol125.h +++ b/source/Protocol125.h @@ -27,7 +27,7 @@ public: virtual void DataReceived(const char * a_Data, int a_Size) override; /// Sending stuff to clients: - virtual void SendBlockAction (int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2) 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 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; diff --git a/source/Protocol132.cpp b/source/Protocol132.cpp index 2a4a830c6..5949776d3 100644 --- a/source/Protocol132.cpp +++ b/source/Protocol132.cpp @@ -9,6 +9,10 @@ #include "cServer.h" #include "cClientHandle.h" #include "CryptoPP/osrng.h" +#include "cItem.h" +#include "ChunkDataSerializer.h" +#include "cPlayer.h" +#include "cMonster.h" @@ -44,11 +48,33 @@ const int MAX_ENC_LEN = 512; // Maximum size of the encrypted message; should b +enum +{ + PACKET_KEEP_ALIVE = 0x00, + PACKET_LOGIN = 0x01, + PACKET_PLAYER_SPAWN = 0x14, + PACKET_SPAWN_MOB = 0x18, + PACKET_DESTROY_ENTITIES = 0x1d, + PACKET_CHUNK_DATA = 0x33, + PACKET_BLOCK_CHANGE = 0x34, + PACKET_BLOCK_ACTION = 0x36, +} ; + + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // cProtocol132: cProtocol132::cProtocol132(cClientHandle * a_Client) : super(a_Client), + // DEBUG: + m_CurrentIn(0), + m_CurrentOut(0), + m_EncIn(0), + m_EncOut(0), + m_IsEncrypted(false) { } @@ -57,10 +83,24 @@ cProtocol132::cProtocol132(cClientHandle * a_Client) : +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) { + m_CurrentIn += a_Size; if (m_IsEncrypted) { + m_EncIn += a_Size; byte Decrypted[512]; while (a_Size > 0) { @@ -81,11 +121,169 @@ void cProtocol132::DataReceived(const char * a_Data, int 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::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: + // Chunk data seems to break the connection for some reason; without it, the connection lives indefinitely + 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::SendDestroyEntity(const cEntity & a_Entity) +{ + cCSLock Lock(m_CSPacket); + WriteByte(PACKET_DESTROY_ENTITIES); + WriteByte(1); // entity count + WriteInt (a_Entity.GetUniqueID()); + Flush(); +} + + + + + +void cProtocol132::SendKeepAlive(int a_PingID) +{ + cCSLock Lock(m_CSPacket); + WriteByte(PACKET_KEEP_ALIVE); + WriteInt (a_PingID); + Flush(); +} + + + + + +void cProtocol132::SendLogin(const cPlayer & a_Player) +{ + 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 (0); // TODO: Dimension (Nether / Overworld / End) + WriteByte (2); // TODO: Difficulty + WriteByte (0); // Unused, used to be world height + WriteByte (8); // Client list width or something + Flush(); +} + + + + + +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::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); // yaw + WriteByte (0); // pitch + WriteByte (0); // head yaw + WriteShort (0); // Velocity Z + WriteShort (0); // Velocity X + WriteShort (0); // Velocity Y + 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? +} + + + + + int cProtocol132::ParsePacket(unsigned char a_PacketType) { + // DEBUG: + LOGD("Received packet 0x%02x, current bytecount %d, enc %d", a_PacketType, m_CurrentIn, m_EncIn); + switch (a_PacketType) { default: return super::ParsePacket(a_PacketType); // off-load previously known packets into cProtocol125 + case 0xcc: return ParseLocaleViewDistance(); case 0xcd: return ParseClientStatuses(); case 0xfc: return ParseEncryptionKeyResponse(); } @@ -95,6 +293,32 @@ int cProtocol132::ParsePacket(unsigned char a_PacketType) +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, Direction); + + 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->HandleBlockPlace(PosX, PosY, PosZ, Direction, HeldItem); + return PARSE_OK; +} + + + + + int cProtocol132::ParseHandshake(void) { HANDLE_PACKET_READ(ReadByte, Byte, ProtocolVersion); @@ -107,13 +331,14 @@ int cProtocol132::ParseHandshake(void) CryptoPP::StringSink sink(key); // GCC won't allow inline instantiation in the following line, damned temporary refs cRoot::Get()->GetServer()->GetPublicKey().Save(sink); - // Send a 0xFD Encryption Key Request http://wiki.vg/Protocol#Encryption_Key_Request_.280xFD.29 + // Send a 0xFD Encryption Key Request http://wiki.vg/Protocol#0xFD WriteByte((char)0xfd); WriteString("MCServer"); WriteShort((short)key.size()); SendData(key.data(), key.size()); WriteShort(4); WriteInt((int)this); // Using 'this' as the cryptographic nonce, so that we don't have to generate one each time :) + Flush(); return PARSE_OK; } @@ -121,27 +346,10 @@ int cProtocol132::ParseHandshake(void) -int cProtocol132::ParseLogin(void) -{ - // Login packet not used in 1.3.2 - return PARSE_ERROR; -} - - - - - int cProtocol132::ParseClientStatuses(void) { HANDLE_PACKET_READ(ReadByte, byte, Status); - - // DEBUG: - // Kick the client, we don't have all the packets yet and sending wrong packets makes the client freeze - // m_Client->Kick("I don't speak your language (yet)"); - - // TODO: - // m_Client->HandleLogin(39, m_Username); - + m_Client->HandleLogin(39, m_Username); return PARSE_OK; } @@ -178,11 +386,72 @@ int cProtocol132::ParseEncryptionKeyResponse(void) +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) { + // DEBUG: + m_DataToSend.append(a_Data, a_Size); + m_CurrentOut += a_Size; +} + + + + + +void cProtocol132::Flush(void) +{ + // DEBUG + if (m_DataToSend.empty()) + { + LOGD("Flushing empty"); + return; + } + LOGD("Flushing packet 0x%02x, %d bytes; %d bytes out, %d enc out", (unsigned char)m_DataToSend[0], m_DataToSend.size(), m_CurrentOut, m_EncOut); + const char * a_Data = m_DataToSend.data(); + int a_Size = m_DataToSend.size(); if (m_IsEncrypted) { - byte Encrypted[1024]; // Larger buffer, we may be sending lots of data (chunks) + m_EncOut += a_Size; + byte Encrypted[4096]; // Larger buffer, we may be sending lots of data (chunks) while (a_Size > 0) { int NumBytes = (a_Size > sizeof(Encrypted)) ? sizeof(Encrypted) : a_Size; @@ -196,6 +465,35 @@ void cProtocol132::SendData(const char * a_Data, int a_Size) { super::SendData(a_Data, a_Size); } + m_DataToSend.clear(); + // cSleep::MilliSleep(300); +} + + + + + +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; + } + + WriteShort(ItemType); + if (a_Item.IsEmpty()) + { + return; + } + + WriteByte (a_Item.m_ItemCount); + WriteShort(a_Item.m_ItemDamage); + + // TODO: Implement enchantments + WriteShort(-1); } @@ -236,6 +534,7 @@ void cProtocol132::HandleEncryptionKeyResponse(const AString & a_EncKey, const A WriteByte((char)0xfc); WriteShort(0); WriteShort(0); + Flush(); StartEncryption(DecryptedKey); return; diff --git a/source/Protocol132.h b/source/Protocol132.h index a0e16b585..2373693b7 100644 --- a/source/Protocol132.h +++ b/source/Protocol132.h @@ -24,28 +24,58 @@ class cProtocol132 : public: cProtocol132(cClientHandle * a_Client); + + // DEBUG: + virtual ~cProtocol132(); /// Called when client sends some data: virtual void DataReceived(const char * a_Data, int a_Size) override; + + // Sending commands: + virtual void SendBlockAction (int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType) 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 SendDestroyEntity(const cEntity & a_Entity) override; + virtual void SendLogin (const cPlayer & a_Player) override; + virtual void SendPlayerSpawn (const cPlayer & a_Player) override; + virtual void SendSpawnMob (const cMonster & a_Mob) override; + virtual void SendUnloadChunk (int a_ChunkX, int a_ChunkZ) override; + + // DEBUG: + virtual void SendKeepAlive (int a_PingID) override; /// Handling of the additional packets: virtual int ParsePacket(unsigned char a_PacketType) override; // Modified packets: - virtual int ParseHandshake(void) override; - virtual int ParseLogin (void) override; + 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 void SendData(const char * a_Data, int a_Size); + virtual int ParseLocaleViewDistance (void); protected: bool m_IsEncrypted; - CryptoPP::CFB_Mode::Decryption m_Decryptor; // ((byte*)sDecryptedSharedSecret.c_str(),(unsigned int)16, IV, 1); + CryptoPP::CFB_Mode::Decryption m_Decryptor; CryptoPP::CFB_Mode::Encryption m_Encryptor; + // DEBUG: + AString m_DataToSend; + int m_CurrentIn, m_CurrentOut; + int m_EncIn, m_EncOut; + + 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; + /// Decrypts the key and nonce, checks nonce, starts the symmetric encryption void HandleEncryptionKeyResponse(const AString & a_EncKey, const AString & a_EncNonce); diff --git a/source/ProtocolRecognizer.cpp b/source/ProtocolRecognizer.cpp index d0a3f4637..6570b29e0 100644 --- a/source/ProtocolRecognizer.cpp +++ b/source/ProtocolRecognizer.cpp @@ -60,10 +60,10 @@ void cProtocolRecognizer::DataReceived(const char * a_Data, int a_Size) -void cProtocolRecognizer::SendBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2) +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); + m_Protocol->SendBlockAction(a_BlockX, a_BlockY, a_BlockZ, a_Byte1, a_Byte2, a_BlockType); } diff --git a/source/ProtocolRecognizer.h b/source/ProtocolRecognizer.h index 181c016d9..681c31bb5 100644 --- a/source/ProtocolRecognizer.h +++ b/source/ProtocolRecognizer.h @@ -29,7 +29,7 @@ public: virtual void DataReceived(const char * a_Data, int a_Size) override; /// Sending stuff to clients: - virtual void SendBlockAction (int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2) 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 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; diff --git a/source/cChestEntity.cpp b/source/cChestEntity.cpp index a798eff47..2a69c7bdb 100644 --- a/source/cChestEntity.cpp +++ b/source/cChestEntity.cpp @@ -185,7 +185,7 @@ void cChestEntity::UsedBy(cPlayer * a_Player) GetWindow()->SendWholeWindow( a_Player->GetClientHandle() ); } } - m_World->BroadcastBlockAction(m_PosX, m_PosY, m_PosZ, 1, 1); + m_World->BroadcastBlockAction(m_PosX, m_PosY, m_PosZ, 1, 1, E_BLOCK_CHEST); // This is rather a hack // Instead of marking the chunk as dirty upon chest contents change, we mark it dirty now diff --git a/source/cChunk.cpp b/source/cChunk.cpp index 17b961d3c..4e32b4dad 100644 --- a/source/cChunk.cpp +++ b/source/cChunk.cpp @@ -1715,7 +1715,7 @@ void cChunk::BroadcastEntHeadLook(const cEntity & a_Entity, const cClientHandle -void cChunk::BroadcastBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, const cClientHandle * a_Exclude) +void cChunk::BroadcastBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType, const cClientHandle * a_Exclude) { for (cClientHandleList::const_iterator itr = m_LoadedByClient.begin(); itr != m_LoadedByClient.end(); ++itr ) { @@ -1723,7 +1723,7 @@ void cChunk::BroadcastBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, char { continue; } - (*itr)->SendBlockAction(a_BlockX, a_BlockY, a_BlockZ, a_Byte1, a_Byte2); + (*itr)->SendBlockAction(a_BlockX, a_BlockY, a_BlockZ, a_Byte1, a_Byte2, a_BlockType); } // for itr - LoadedByClient[] } diff --git a/source/cChunk.h b/source/cChunk.h index c63bd8a92..f7d53ee8c 100644 --- a/source/cChunk.h +++ b/source/cChunk.h @@ -179,7 +179,7 @@ public: void BroadcastEntRelMove (const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ, const cClientHandle * a_Exclude = NULL); void BroadcastEntLook (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL); void BroadcastEntHeadLook (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL); - void BroadcastBlockAction (int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, const cClientHandle * a_Exclude = NULL); + void BroadcastBlockAction (int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType, const cClientHandle * a_Exclude = NULL); void BroadcastDestroyEntity (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL); void BroadcastEntityStatus (const cEntity & a_Entity, char a_Status, const cClientHandle * a_Exclude = NULL); void BroadcastMetadata (const cPawn & a_Pawn, const cClientHandle * a_Exclude = NULL); diff --git a/source/cChunkMap.cpp b/source/cChunkMap.cpp index c764a0321..5f9724179 100644 --- a/source/cChunkMap.cpp +++ b/source/cChunkMap.cpp @@ -325,7 +325,7 @@ void cChunkMap::BroadcastEntHeadLook(const cEntity & a_Entity, const cClientHand -void cChunkMap::BroadcastBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, const cClientHandle * a_Exclude) +void cChunkMap::BroadcastBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType, const cClientHandle * a_Exclude) { cCSLock Lock(m_CSLayers); int x, y, z, ChunkX, ChunkZ; @@ -339,7 +339,7 @@ void cChunkMap::BroadcastBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, c return; } // It's perfectly legal to broadcast packets even to invalid chunks! - Chunk->BroadcastBlockAction(a_BlockX, a_BlockY, a_BlockZ, a_Byte1, a_Byte2, a_Exclude); + Chunk->BroadcastBlockAction(a_BlockX, a_BlockY, a_BlockZ, a_Byte1, a_Byte2, a_BlockType, a_Exclude); } diff --git a/source/cChunkMap.h b/source/cChunkMap.h index 36cb704a2..4996e1e04 100644 --- a/source/cChunkMap.h +++ b/source/cChunkMap.h @@ -61,7 +61,7 @@ public: void BroadcastEntHeadLook(const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL); /// Broadcasts a BlockAction packet to all clients who are in the specified chunk - void BroadcastBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, const cClientHandle * a_Exclude = NULL); + void BroadcastBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType, const cClientHandle * a_Exclude = NULL); void BroadcastDestroyEntity(const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL); diff --git a/source/cClientHandle.cpp b/source/cClientHandle.cpp index 29446615f..1b0944c4c 100644 --- a/source/cClientHandle.cpp +++ b/source/cClientHandle.cpp @@ -1158,9 +1158,9 @@ void cClientHandle::SendEntHeadLook(const cEntity & a_Entity) -void cClientHandle::SendBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2) +void cClientHandle::SendBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType) { - m_Protocol->SendBlockAction(a_BlockX, a_BlockY, a_BlockZ, a_Byte1, a_Byte2); + m_Protocol->SendBlockAction(a_BlockX, a_BlockY, a_BlockZ, a_Byte1, a_Byte2, a_BlockType); } diff --git a/source/cClientHandle.h b/source/cClientHandle.h index e6887d752..ba9cde7f5 100644 --- a/source/cClientHandle.h +++ b/source/cClientHandle.h @@ -98,7 +98,7 @@ public: void SendEntRelMove (const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ); void SendEntLook (const cEntity & a_Entity); void SendEntHeadLook (const cEntity & a_Entity); - void SendBlockAction (int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2); + void SendBlockAction (int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType); void SendHealth (void); void SendRespawn(void); void SendGameMode(eGameMode a_GameMode); diff --git a/source/cNoteEntity.cpp b/source/cNoteEntity.cpp index 4feb9223c..44f911dc4 100644 --- a/source/cNoteEntity.cpp +++ b/source/cNoteEntity.cpp @@ -84,7 +84,7 @@ void cNoteEntity::MakeSound( void ) } } - m_World->BroadcastBlockAction(m_PosX, m_PosY, m_PosZ, instrument, m_Pitch); + m_World->BroadcastBlockAction(m_PosX, m_PosY, m_PosZ, instrument, m_Pitch, E_BLOCK_NOTE_BLOCK); } diff --git a/source/cPiston.cpp b/source/cPiston.cpp index 464db8911..dd8541a10 100644 --- a/source/cPiston.cpp +++ b/source/cPiston.cpp @@ -86,7 +86,7 @@ void cPiston::ExtendPiston( int pistx, int pisty, int pistz ) oldy = pisty; oldz = pistz; } - m_World->BroadcastBlockAction(pistx, pisty, pistz, 0, pistonMeta); + m_World->BroadcastBlockAction(pistx, pisty, pistz, 0, pistonMeta, E_BLOCK_PISTON); m_World->FastSetBlock( pistx, pisty, pistz, pistonBlock, pistonMeta | 0x8 ); int extx = pistx; @@ -118,7 +118,7 @@ void cPiston::RetractPiston( int pistx, int pisty, int pistz ) { return; } - m_World->BroadcastBlockAction(pistx, pisty, pistz, 1, pistonMeta & ~(8)); + m_World->BroadcastBlockAction(pistx, pisty, pistz, 1, pistonMeta & ~(8), E_BLOCK_PISTON); m_World->FastSetBlock(pistx, pisty, pistz, pistonBlock, pistonMeta & ~(8)); AddDir(pistx, pisty, pistz, pistonMeta & 7, 1) diff --git a/source/cPlayer.cpp b/source/cPlayer.cpp index d3c0107ec..4605049b3 100644 --- a/source/cPlayer.cpp +++ b/source/cPlayer.cpp @@ -468,7 +468,7 @@ void cPlayer::CloseWindow(char a_WindowType) { int x, y, z; m_CurrentWindow->GetOwner()->GetBlockPos(x, y, z); - m_World->BroadcastBlockAction(x, y, z, 1, 0); + m_World->BroadcastBlockAction(x, y, z, 1, 0, E_BLOCK_CHEST); } m_CurrentWindow->Close( *this ); diff --git a/source/cWorld.cpp b/source/cWorld.cpp index 9348eda7d..776d25732 100644 --- a/source/cWorld.cpp +++ b/source/cWorld.cpp @@ -1304,9 +1304,9 @@ void cWorld::BroadcastEntHeadLook(const cEntity & a_Entity, const cClientHandle -void cWorld::BroadcastBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, const cClientHandle * a_Exclude) +void cWorld::BroadcastBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType, const cClientHandle * a_Exclude) { - m_ChunkMap->BroadcastBlockAction(a_BlockX, a_BlockY, a_BlockZ, a_Byte1, a_Byte2, a_Exclude); + m_ChunkMap->BroadcastBlockAction(a_BlockX, a_BlockY, a_BlockZ, a_Byte1, a_Byte2, a_BlockType, a_Exclude); } diff --git a/source/cWorld.h b/source/cWorld.h index 0751daf5c..df2f3abab 100644 --- a/source/cWorld.h +++ b/source/cWorld.h @@ -81,7 +81,7 @@ public: void BroadcastEntRelMove (const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ, const cClientHandle * a_Exclude = NULL); void BroadcastEntLook (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL); void BroadcastEntHeadLook (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL); - void BroadcastBlockAction (int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, const cClientHandle * a_Exclude = NULL); + void BroadcastBlockAction (int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType, const cClientHandle * a_Exclude = NULL); void BroadcastDestroyEntity (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL); void BroadcastEntityStatus (const cEntity & a_Entity, char a_Status, const cClientHandle * a_Exclude = NULL); void BroadcastMetadata (const cPawn & a_Pawn, const cClientHandle * a_Exclude = NULL);