From d7066f43d3fd592457e69a46f0fed098c80b3190 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Tue, 30 Sep 2014 13:33:57 +0200 Subject: Rewritten plugin messages, vanilla are being parsed directly. This should finally fix the compatibility problems between 1.7 and 1.8 protocols with the changes in the vanilla plugin messages. --- src/Protocol/Protocol17x.cpp | 92 ++++++++++++++++++++++++++++++++++++++++++++ src/Protocol/Protocol17x.h | 3 ++ src/Protocol/Protocol18x.cpp | 86 ++++++++++++++++++++++++++++++++++------- src/Protocol/Protocol18x.h | 4 ++ 4 files changed, 172 insertions(+), 13 deletions(-) (limited to 'src/Protocol') diff --git a/src/Protocol/Protocol17x.cpp b/src/Protocol/Protocol17x.cpp index e4c33908a..07338f395 100644 --- a/src/Protocol/Protocol17x.cpp +++ b/src/Protocol/Protocol17x.cpp @@ -2064,6 +2064,22 @@ void cProtocol172::HandlePacketPluginMessage(cByteBuffer & a_ByteBuffer) { HANDLE_READ(a_ByteBuffer, ReadVarUTF8String, AString, Channel); HANDLE_READ(a_ByteBuffer, ReadBEShort, short, Length); + if (Length + 1 != (int)a_ByteBuffer.GetReadableSpace()) + { + LOGD("Invalid plugin message packet, payload length doesn't match packet length (exp %d, got %d)", + (int)a_ByteBuffer.GetReadableSpace() - 1, Length + ); + return; + } + + // If the plugin channel is recognized vanilla, handle it directly: + if (Channel.substr(0, 3) == "MC|") + { + HandleVanillaPluginMessage(a_ByteBuffer, Channel, Length); + return; + } + + // Read the plugin message and relay to clienthandle: AString Data; if (!a_ByteBuffer.ReadString(Data, Length)) { @@ -2217,6 +2233,82 @@ void cProtocol172::HandlePacketWindowClose(cByteBuffer & a_ByteBuffer) +void cProtocol172::HandleVanillaPluginMessage(cByteBuffer & a_ByteBuffer, const AString & a_Channel, short a_PayloadLength) +{ + if (a_Channel == "MC|AdvCdm") + { + HANDLE_READ(a_ByteBuffer, ReadByte, Byte, Mode) + switch (Mode) + { + case 0x00: + { + // Block-based commandblock update: + HANDLE_READ(a_ByteBuffer, ReadBEInt, int, BlockX); + HANDLE_READ(a_ByteBuffer, ReadBEInt, int, BlockY); + HANDLE_READ(a_ByteBuffer, ReadBEInt, int, BlockZ); + HANDLE_READ(a_ByteBuffer, ReadVarUTF8String, AString, Command); + m_Client->HandleCommandBlockBlockChange(BlockX, BlockY, BlockZ, Command); + break; + } + + // TODO: Entity-based commandblock update + + default: + { + m_Client->SendChat(Printf("Failure setting command block command; unhandled mode %d", Mode), mtFailure); + LOG("Unhandled MC|AdvCdm packet mode."); + return; + } + } // switch (Mode) + return; + } + else if (a_Channel == "MC|Brand") + { + // Read the client's brand: + AString Brand; + if (a_ByteBuffer.ReadString(Brand, a_PayloadLength)) + { + m_Client->SetClientBrand(Brand); + } + + // Send back our brand: + SendPluginMessage("MC|Brand", "MCServer"); + return; + } + else if (a_Channel == "MC|Beacon") + { + HANDLE_READ(a_ByteBuffer, ReadBEInt, int, Effect1); + HANDLE_READ(a_ByteBuffer, ReadBEInt, int, Effect2); + m_Client->HandleBeaconSelection(Effect1, Effect2); + return; + } + else if (a_Channel == "MC|ItemName") + { + AString ItemName; + if (a_ByteBuffer.ReadString(ItemName, a_PayloadLength)) + { + m_Client->HandleAnvilItemName(ItemName); + } + return; + } + else if (a_Channel == "MC|TrSel") + { + HANDLE_READ(a_ByteBuffer, ReadBEInt, int, SlotNum); + m_Client->HandleNPCTrade(SlotNum); + return; + } + LOG("Unhandled vanilla plugin channel: \"%s\".", a_Channel.c_str()); + + // Read the payload and send it through to the clienthandle: + AString Message; + VERIFY(a_ByteBuffer.ReadString(Message, a_PayloadLength)); + m_Client->HandlePluginMessage(a_Channel, Message); +} + + + + + void cProtocol172::SendData(const char * a_Data, size_t a_Size) { if (m_IsEncrypted) diff --git a/src/Protocol/Protocol17x.h b/src/Protocol/Protocol17x.h index 0bc86a72a..7709df59d 100644 --- a/src/Protocol/Protocol17x.h +++ b/src/Protocol/Protocol17x.h @@ -295,6 +295,9 @@ protected: void HandlePacketWindowClick (cByteBuffer & a_ByteBuffer); void HandlePacketWindowClose (cByteBuffer & a_ByteBuffer); + /** Parses Vanilla plugin messages into specific ClientHandle calls. + The message payload is still in the bytebuffer, to be read by this function. */ + void HandleVanillaPluginMessage(cByteBuffer & a_ByteBuffer, const AString & a_Channel, short a_PayloadLength); /** Sends the data to the client, encrypting them if needed. */ virtual void SendData(const char * a_Data, size_t a_Size) override; diff --git a/src/Protocol/Protocol18x.cpp b/src/Protocol/Protocol18x.cpp index 1070a8434..acdb48cf7 100644 --- a/src/Protocol/Protocol18x.cpp +++ b/src/Protocol/Protocol18x.cpp @@ -989,10 +989,6 @@ void cProtocol180::SendPluginMessage(const AString & a_Channel, const AString & cPacketizer Pkt(*this, 0x3f); Pkt.WriteString(a_Channel); - if (a_Channel.substr(0, 3) == "MC|") - { - Pkt.WriteVarInt((UInt32)a_Message.size()); - } Pkt.WriteBuf(a_Message.data(), a_Message.size()); } @@ -2324,18 +2320,17 @@ void cProtocol180::HandlePacketPlayerPosLook(cByteBuffer & a_ByteBuffer) void cProtocol180::HandlePacketPluginMessage(cByteBuffer & a_ByteBuffer) { HANDLE_READ(a_ByteBuffer, ReadVarUTF8String, AString, Channel); - AString Data; + + // If the plugin channel is recognized vanilla, handle it directly: if (Channel.substr(0, 3) == "MC|") { - // Vanilla sends the payload length within the payload itself, so skip it: - HANDLE_READ(a_ByteBuffer, ReadVarInt, UInt32, DataLen); - if (DataLen != a_ByteBuffer.GetReadableSpace() - 1) - { - ASSERT(!"Bad plugin message payload length"); - return; - } + HandleVanillaPluginMessage(a_ByteBuffer, Channel); + return; } - a_ByteBuffer.ReadString(Data, a_ByteBuffer.GetReadableSpace() - 1); // Always succeeds + + // Read the plugin message and relay to clienthandle: + AString Data; + VERIFY(a_ByteBuffer.ReadString(Data, a_ByteBuffer.GetReadableSpace() - 1)); // Always succeeds m_Client->HandlePluginMessage(Channel, Data); } @@ -2524,6 +2519,71 @@ void cProtocol180::HandlePacketWindowClose(cByteBuffer & a_ByteBuffer) +void cProtocol180::HandleVanillaPluginMessage(cByteBuffer & a_ByteBuffer, const AString & a_Channel) +{ + if (a_Channel == "MC|AdvCdm") + { + HANDLE_READ(a_ByteBuffer, ReadByte, Byte, Mode) + switch (Mode) + { + case 0x00: + { + HANDLE_READ(a_ByteBuffer, ReadBEInt, int, BlockX); + HANDLE_READ(a_ByteBuffer, ReadBEInt, int, BlockY); + HANDLE_READ(a_ByteBuffer, ReadBEInt, int, BlockZ); + HANDLE_READ(a_ByteBuffer, ReadVarUTF8String, AString, Command); + m_Client->HandleCommandBlockBlockChange(BlockX, BlockY, BlockZ, Command); + break; + } + + default: + { + m_Client->SendChat(Printf("Failure setting command block command; unhandled mode %d", Mode), mtFailure); + LOG("Unhandled MC|AdvCdm packet mode."); + return; + } + } // switch (Mode) + return; + } + else if (a_Channel == "MC|Brand") + { + HANDLE_READ(a_ByteBuffer, ReadVarUTF8String, AString, Brand); + m_Client->SetClientBrand(Brand); + // Send back our brand, including the length: + SendPluginMessage("MC|Brand", "\x08MCServer"); + return; + } + else if (a_Channel == "MC|Beacon") + { + HANDLE_READ(a_ByteBuffer, ReadBEInt, int, Effect1); + HANDLE_READ(a_ByteBuffer, ReadBEInt, int, Effect2); + m_Client->HandleBeaconSelection(Effect1, Effect2); + return; + } + else if (a_Channel == "MC|ItemName") + { + HANDLE_READ(a_ByteBuffer, ReadVarUTF8String, AString, ItemName); + m_Client->HandleAnvilItemName(ItemName); + return; + } + else if (a_Channel == "MC|TrSel") + { + HANDLE_READ(a_ByteBuffer, ReadBEInt, int, SlotNum); + m_Client->HandleNPCTrade(SlotNum); + return; + } + LOG("Unhandled vanilla plugin channel: \"%s\".", a_Channel.c_str()); + + // Read the payload and send it through to the clienthandle: + AString Message; + VERIFY(a_ByteBuffer.ReadString(Message, a_ByteBuffer.GetReadableSpace() - 1)); + m_Client->HandlePluginMessage(a_Channel, Message); +} + + + + + void cProtocol180::SendData(const char * a_Data, size_t a_Size) { if (m_IsEncrypted) diff --git a/src/Protocol/Protocol18x.h b/src/Protocol/Protocol18x.h index acc167a6d..8c0b77a21 100644 --- a/src/Protocol/Protocol18x.h +++ b/src/Protocol/Protocol18x.h @@ -312,6 +312,10 @@ protected: void HandlePacketWindowClick (cByteBuffer & a_ByteBuffer); void HandlePacketWindowClose (cByteBuffer & a_ByteBuffer); + /** Parses Vanilla plugin messages into specific ClientHandle calls. + The message payload is still in the bytebuffer, the handler reads it specifically for each handled channel */ + void HandleVanillaPluginMessage(cByteBuffer & a_ByteBuffer, const AString & a_Channel); + /** Sends the data to the client, encrypting them if needed. */ virtual void SendData(const char * a_Data, size_t a_Size) override; -- cgit v1.2.3