From c7d5c00a17c8e4d79f6b0e855d88cc42876f63a9 Mon Sep 17 00:00:00 2001 From: "madmaxoft@gmail.com" Date: Sun, 2 Sep 2012 12:09:58 +0000 Subject: [PATCH] Next iteration on the 1.3.2 protocol. Still no good, but sometimes it just gets through. For your testing pleasures ;) git-svn-id: http://mc-server.googlecode.com/svn/trunk@819 0a769ca7-a7f5-676a-18bf-c427514a06d6 --- source/Protocol.h | 3 +- source/Protocol125.cpp | 3 +- source/Protocol125.h | 2 +- source/Protocol132.cpp | 124 ++++++++++++++++++++++++++++------ source/Protocol132.h | 7 +- source/ProtocolRecognizer.cpp | 4 +- source/ProtocolRecognizer.h | 2 +- source/cClientHandle.cpp | 2 +- source/cWorld.cpp | 9 --- source/cWorld.h | 6 +- 10 files changed, 120 insertions(+), 42 deletions(-) diff --git a/source/Protocol.h b/source/Protocol.h index f3e688afb..e01afa9cc 100644 --- a/source/Protocol.h +++ b/source/Protocol.h @@ -24,6 +24,7 @@ class cPawn; class cPickup; class cMonster; class cChunkDataSerializer; +class cWorld; @@ -60,7 +61,7 @@ public: 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) = 0; + virtual void SendLogin (const cPlayer & a_Player, const cWorld & a_World) = 0; virtual void SendMetadata (const cEntity & a_Entity) = 0; virtual void SendPickupSpawn (const cPickup & a_Pickup) = 0; virtual void SendPlayerAnimation (const cPlayer & a_Player, char a_Animation) = 0; diff --git a/source/Protocol125.cpp b/source/Protocol125.cpp index 2adb68fa0..41a64f24b 100644 --- a/source/Protocol125.cpp +++ b/source/Protocol125.cpp @@ -417,8 +417,9 @@ void cProtocol125::SendKeepAlive(int a_PingID) -void cProtocol125::SendLogin(const cPlayer & a_Player) +void cProtocol125::SendLogin(const cPlayer & a_Player, const cWorld & a_World) { + UNUSED(a_World); cCSLock Lock(m_CSPacket); WriteByte (PACKET_LOGIN); diff --git a/source/Protocol125.h b/source/Protocol125.h index 2d6696c85..e787f462f 100644 --- a/source/Protocol125.h +++ b/source/Protocol125.h @@ -46,7 +46,7 @@ public: 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) override; + virtual void SendLogin (const cPlayer & a_Player, const cWorld & a_World) override; virtual void SendMetadata (const cEntity & a_Entity) override; virtual void SendPickupSpawn (const cPickup & a_Pickup) override; virtual void SendPlayerAnimation (const cPlayer & a_Player, char a_Animation) override; diff --git a/source/Protocol132.cpp b/source/Protocol132.cpp index 5949776d3..43aedc934 100644 --- a/source/Protocol132.cpp +++ b/source/Protocol132.cpp @@ -52,11 +52,12 @@ enum { PACKET_KEEP_ALIVE = 0x00, PACKET_LOGIN = 0x01, + PACKET_COMPASS = 0x06, PACKET_PLAYER_SPAWN = 0x14, PACKET_SPAWN_MOB = 0x18, PACKET_DESTROY_ENTITIES = 0x1d, PACKET_CHUNK_DATA = 0x33, - PACKET_BLOCK_CHANGE = 0x34, + PACKET_BLOCK_CHANGE = 0x35, PACKET_BLOCK_ACTION = 0x36, } ; @@ -156,11 +157,11 @@ void cProtocol132::SendBlockChange(int a_BlockX, int a_BlockY, int a_BlockZ, BLO 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); @@ -169,7 +170,9 @@ void cProtocol132::SendChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSerialize WriteInt (a_ChunkZ); SendData(Serialized.data(), Serialized.size()); Flush(); - //*/ + } + // Enabling the sleep here sometimes makes the client accept us and spawn us in the world. But it makes the connection lag behind, ultimately timing out + // cSleep::MilliSleep(500); } @@ -201,7 +204,7 @@ void cProtocol132::SendKeepAlive(int a_PingID) -void cProtocol132::SendLogin(const cPlayer & a_Player) +void cProtocol132::SendLogin(const cPlayer & a_Player, const cWorld & a_World) { cCSLock Lock(m_CSPacket); WriteByte (PACKET_LOGIN); @@ -213,6 +216,8 @@ void cProtocol132::SendLogin(const cPlayer & a_Player) WriteByte (0); // Unused, used to be world height WriteByte (8); // Client list width or something Flush(); + + SendCompass(a_World); } @@ -278,7 +283,7 @@ void cProtocol132::SendUnloadChunk(int a_ChunkX, int a_ChunkZ) int cProtocol132::ParsePacket(unsigned char a_PacketType) { // DEBUG: - LOGD("Received packet 0x%02x, current bytecount %d, enc %d", a_PacketType, m_CurrentIn, m_EncIn); + LOGD("Received packet 0x%02x, %d B avail; BM %d, enc %d", a_PacketType, m_ReceivedData.GetReadableSpace(), m_CurrentIn, m_EncIn); switch (a_PacketType) { @@ -327,18 +332,12 @@ int cProtocol132::ParseHandshake(void) HANDLE_PACKET_READ(ReadBEInt, int, ServerPort); m_Username = Username; + // Send a 0xFD Encryption Key Request http://wiki.vg/Protocol#0xFD AString key; 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#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(); + SendEncryptionKeyRequest(key); + return PARSE_OK; } @@ -440,22 +439,30 @@ void cProtocol132::SendData(const char * a_Data, int a_Size) void cProtocol132::Flush(void) { // DEBUG + ASSERT(m_CSPacket.IsLockedByCurrentThread()); // Did all packets lock the CS properly? + 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); + LOGD("Flushing packet 0x%02x, %d B; %d B 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) { m_EncOut += a_Size; - byte Encrypted[4096]; // Larger buffer, we may be sending lots of data (chunks) + byte Encrypted[8192]; // Larger buffer, we may be sending lots of data (chunks) while (a_Size > 0) { int NumBytes = (a_Size > sizeof(Encrypted)) ? sizeof(Encrypted) : a_Size; m_Encryptor.ProcessData(Encrypted, (byte *)a_Data, NumBytes); + + // DEBUG: decrypt the data to check if encryption works: + byte Decrypted[sizeof(Encrypted)]; + m_Decryptor2.ProcessData(Decrypted, Encrypted, NumBytes); + ASSERT(memcmp(Decrypted, a_Data, NumBytes) == 0); + super::SendData((const char *)Encrypted, NumBytes); a_Size -= NumBytes; a_Data += NumBytes; @@ -466,7 +473,7 @@ void cProtocol132::Flush(void) super::SendData(a_Data, a_Size); } m_DataToSend.clear(); - // cSleep::MilliSleep(300); + // cSleep::MilliSleep(400); } @@ -500,6 +507,75 @@ void cProtocol132::WriteItem(const cItem & a_Item) +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, EnchantNumBytes); + if (EnchantNumBytes <= 0) + { + return PARSE_OK; + } + + // TODO: Enchantment not implemented yet! + if (!m_ReceivedData.SkipRead(EnchantNumBytes)) + { + return PARSE_INCOMPLETE; + } + + 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(const AString & a_Key) +{ + cCSLock Lock(m_CSPacket); + WriteByte((char)0xfd); + WriteString("MCServer"); + WriteShort((short)a_Key.size()); + SendData(a_Key.data(), a_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(); +} + + + + + void cProtocol132::HandleEncryptionKeyResponse(const AString & a_EncKey, const AString & a_EncNonce) { // Decrypt EncNonce using privkey @@ -530,11 +606,14 @@ void cProtocol132::HandleEncryptionKeyResponse(const AString & a_EncKey, const A return; } - // Send encryption key response: - WriteByte((char)0xfc); - WriteShort(0); - WriteShort(0); - Flush(); + { + // Send encryption key response: + cCSLock Lock(m_CSPacket); + WriteByte((char)0xfc); + WriteShort(0); + WriteShort(0); + Flush(); + } StartEncryption(DecryptedKey); return; @@ -548,6 +627,7 @@ 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_Decryptor2.SetKey(a_Key, 16, MakeParameters(Name::IV(), ConstByteArrayParameter(a_Key, 16))(Name::FeedbackSize(), 1)); m_IsEncrypted = true; } diff --git a/source/Protocol132.h b/source/Protocol132.h index 2373693b7..d1f1ccbd3 100644 --- a/source/Protocol132.h +++ b/source/Protocol132.h @@ -36,7 +36,7 @@ public: 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 SendLogin (const cPlayer & a_Player, const cWorld & a_World) 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; @@ -64,6 +64,7 @@ protected: CryptoPP::CFB_Mode::Encryption m_Encryptor; // DEBUG: + CryptoPP::CFB_Mode::Decryption m_Decryptor2; AString m_DataToSend; int m_CurrentIn, m_CurrentOut; int m_EncIn, m_EncOut; @@ -75,6 +76,10 @@ protected: // Items in slots are sent differently virtual void WriteItem(const cItem & a_Item) override; + virtual int ParseItem(cItem & a_Item) override; + + virtual void SendCompass(const cWorld & a_World); + virtual void SendEncryptionKeyRequest(const AString & a_Key); /// 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 6570b29e0..736694f5d 100644 --- a/source/ProtocolRecognizer.cpp +++ b/source/ProtocolRecognizer.cpp @@ -238,10 +238,10 @@ void cProtocolRecognizer::SendKeepAlive(int a_PingID) -void cProtocolRecognizer::SendLogin(const cPlayer & a_Player) +void cProtocolRecognizer::SendLogin(const cPlayer & a_Player, const cWorld & a_World) { ASSERT(m_Protocol != NULL); - m_Protocol->SendLogin(a_Player); + m_Protocol->SendLogin(a_Player, a_World); } diff --git a/source/ProtocolRecognizer.h b/source/ProtocolRecognizer.h index 681c31bb5..0a5c5a61a 100644 --- a/source/ProtocolRecognizer.h +++ b/source/ProtocolRecognizer.h @@ -48,7 +48,7 @@ public: 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) override; + virtual void SendLogin (const cPlayer & a_Player, const cWorld & a_World) override; virtual void SendMetadata (const cEntity & a_Entity) override; virtual void SendPickupSpawn (const cPickup & a_Pickup) override; virtual void SendPlayerAnimation (const cPlayer & a_Player, char a_Animation) override; diff --git a/source/cClientHandle.cpp b/source/cClientHandle.cpp index 6bd7610c9..f4f5125c2 100644 --- a/source/cClientHandle.cpp +++ b/source/cClientHandle.cpp @@ -244,7 +244,7 @@ void cClientHandle::Authenticate(void) cRoot::Get()->GetPluginManager()->CallHook(cPluginManager::HOOK_PLAYER_SPAWN, 1, m_Player); // Return a server login packet - m_Protocol->SendLogin(*m_Player); + m_Protocol->SendLogin(*m_Player, *World); // Send Weather if raining: if ((World->GetWeather() == 1) || (World->GetWeather() == 2)) diff --git a/source/cWorld.cpp b/source/cWorld.cpp index 7b40275ca..5e2317cbe 100644 --- a/source/cWorld.cpp +++ b/source/cWorld.cpp @@ -1205,15 +1205,6 @@ int cWorld::GetHeight( int a_X, int a_Z ) -const double & cWorld::GetSpawnY(void) -{ - return m_SpawnY; -} - - - - - void cWorld::BroadcastChat(const AString & a_Message, const cClientHandle * a_Exclude) { cCSLock Lock(m_CSPlayers); diff --git a/source/cWorld.h b/source/cWorld.h index 7d4eb0e0e..6a1058d5c 100644 --- a/source/cWorld.h +++ b/source/cWorld.h @@ -263,9 +263,9 @@ public: bool DigBlock (int a_X, int a_Y, int a_Z); //tolua_export void SendBlockTo(int a_X, int a_Y, int a_Z, cPlayer * a_Player ); //tolua_export - const double & GetSpawnX() { return m_SpawnX; } //tolua_export - const double & GetSpawnY(); //tolua_export - const double & GetSpawnZ() { return m_SpawnZ; } //tolua_export + const double & GetSpawnX(void) const { return m_SpawnX; } // tolua_export + const double & GetSpawnY(void) const { return m_SpawnY; } // tolua_export + const double & GetSpawnZ(void) const { return m_SpawnZ; } // tolua_export inline cSimulatorManager *GetSimulatorManager() { return m_SimulatorManager; } inline cWaterSimulator *GetWaterSimulator() { return m_WaterSimulator; }