From 7c7890c658616222c6aba6dde365f757f75005d6 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Tue, 23 Nov 2021 17:16:25 +0000 Subject: [PATCH] Protocol: modernise plugin message handling (#5325) - Remove handling for garbage data in command block sets + Add correct boolean value read (#1692) * Make better use of namespaced-id and string_view --- src/Protocol/Protocol_1_13.cpp | 32 +++++++--- src/Protocol/Protocol_1_13.h | 1 + src/Protocol/Protocol_1_8.cpp | 113 ++++++++++++++++----------------- src/Protocol/Protocol_1_8.h | 4 +- src/Protocol/Protocol_1_9.cpp | 52 +++++++++++++++ src/Protocol/Protocol_1_9.h | 1 + 6 files changed, 134 insertions(+), 69 deletions(-) diff --git a/src/Protocol/Protocol_1_13.cpp b/src/Protocol/Protocol_1_13.cpp index 5662fc45e..f6919388c 100644 --- a/src/Protocol/Protocol_1_13.cpp +++ b/src/Protocol/Protocol_1_13.cpp @@ -30,6 +30,7 @@ Implements the 1.13 protocol classes: #include "../World.h" #include "../JsonUtils.h" #include "../WorldStorage/FastNBT.h" +#include "WorldStorage/NamespaceSerializer.h" #include "../Bindings/PluginManager.h" @@ -658,24 +659,22 @@ bool cProtocol_1_13::HandlePacket(cByteBuffer & a_ByteBuffer, UInt32 a_PacketTyp void cProtocol_1_13::HandlePacketPluginMessage(cByteBuffer & a_ByteBuffer) { - HANDLE_READ(a_ByteBuffer, ReadVarUTF8String, AString, Channel); + HANDLE_READ(a_ByteBuffer, ReadVarUTF8String, AString, NamespacedChannel); + + const auto & [Namespace, Channel] = NamespaceSerializer::SplitNamespacedID(NamespacedChannel); // If the plugin channel is recognized vanilla, handle it directly: - if (Channel.substr(0, 15) == "minecraft:brand") + if (Namespace == NamespaceSerializer::Namespace::Minecraft) { - HANDLE_READ(a_ByteBuffer, ReadVarUTF8String, AString, Brand); - m_Client->SetClientBrand(Brand); - - // Send back our brand, including the length: - m_Client->SendPluginMessage("minecraft:brand", "\x08""Cuberite"); + HandleVanillaPluginMessage(a_ByteBuffer, Channel); return; } ContiguousByteBuffer Data; // Read the plugin message and relay to clienthandle: - VERIFY(a_ByteBuffer.ReadSome(Data, a_ByteBuffer.GetReadableSpace())); // Always succeeds - m_Client->HandlePluginMessage(Channel, Data); + a_ByteBuffer.ReadSome(Data, a_ByteBuffer.GetReadableSpace()); + m_Client->HandlePluginMessage(NamespacedChannel, Data); } @@ -693,6 +692,21 @@ void cProtocol_1_13::HandlePacketSetBeaconEffect(cByteBuffer & a_ByteBuffer) +void cProtocol_1_13::HandleVanillaPluginMessage(cByteBuffer & a_ByteBuffer, const std::string_view a_Channel) +{ + if (a_Channel == "brand") + { + HANDLE_READ(a_ByteBuffer, ReadVarUTF8String, AString, Brand); + + m_Client->SetClientBrand(Brand); + m_Client->SendPluginMessage("brand", "\x08""Cuberite"); // Send back our brand, including the length. + } +} + + + + + bool cProtocol_1_13::ReadItem(cByteBuffer & a_ByteBuffer, cItem & a_Item, size_t a_KeepRemainingBytes) const { HANDLE_PACKET_READ(a_ByteBuffer, ReadBEInt16, Int16, ItemID); diff --git a/src/Protocol/Protocol_1_13.h b/src/Protocol/Protocol_1_13.h index 53e7cdc91..ca2b49f4c 100644 --- a/src/Protocol/Protocol_1_13.h +++ b/src/Protocol/Protocol_1_13.h @@ -59,6 +59,7 @@ protected: virtual bool HandlePacket(cByteBuffer & a_ByteBuffer, UInt32 a_PacketType) override; virtual void HandlePacketPluginMessage(cByteBuffer & a_ByteBuffer) override; virtual void HandlePacketSetBeaconEffect(cByteBuffer & a_ByteBuffer); + virtual void HandleVanillaPluginMessage(cByteBuffer & a_ByteBuffer, std::string_view a_Channel) override; virtual bool ReadItem(cByteBuffer & a_ByteBuffer, cItem & a_Item, size_t a_KeepRemainingBytes) const override; virtual void WriteEntityMetadata(cPacketizer & a_Pkt, EntityMetadata a_Metadata, EntityMetadataType a_FieldType) const; diff --git a/src/Protocol/Protocol_1_8.cpp b/src/Protocol/Protocol_1_8.cpp index 4bbf5f93e..5bf25f347 100644 --- a/src/Protocol/Protocol_1_8.cpp +++ b/src/Protocol/Protocol_1_8.cpp @@ -2554,28 +2554,23 @@ void cProtocol_1_8_0::HandlePacketPlayerPosLook(cByteBuffer & a_ByteBuffer) void cProtocol_1_8_0::HandlePacketPluginMessage(cByteBuffer & a_ByteBuffer) { + // https://wiki.vg/index.php?title=Plugin_channels&oldid=14089#MC.7CAdvCmd + HANDLE_READ(a_ByteBuffer, ReadVarUTF8String, AString, Channel); + const std::string_view ChannelView = Channel; + // If the plugin channel is recognized vanilla, handle it directly: - if (Channel.substr(0, 3) == "MC|") + if (ChannelView.substr(0, 3) == "MC|") { - HandleVanillaPluginMessage(a_ByteBuffer, Channel); - - // Skip any unread data (vanilla sometimes sends garbage at the end of a packet; #1692): - if (a_ByteBuffer.GetReadableSpace() > 0) - { - LOGD("Protocol 1.8: Skipping garbage data at the end of a vanilla PluginMessage packet, %u bytes", - static_cast(a_ByteBuffer.GetReadableSpace()) - ); - a_ByteBuffer.SkipRead(a_ByteBuffer.GetReadableSpace()); - } - + HandleVanillaPluginMessage(a_ByteBuffer, ChannelView.substr(3)); return; } - // Read the plugin message and relay to clienthandle: ContiguousByteBuffer Data; - VERIFY(a_ByteBuffer.ReadSome(Data, a_ByteBuffer.GetReadableSpace())); // Always succeeds + + // Read the plugin message and relay to clienthandle: + a_ByteBuffer.ReadSome(Data, a_ByteBuffer.GetReadableSpace()); m_Client->HandlePluginMessage(Channel, Data); } @@ -2807,81 +2802,83 @@ void cProtocol_1_8_0::HandlePacketWindowClose(cByteBuffer & a_ByteBuffer) -void cProtocol_1_8_0::HandleVanillaPluginMessage(cByteBuffer & a_ByteBuffer, const AString & a_Channel) +void cProtocol_1_8_0::HandleVanillaPluginMessage(cByteBuffer & a_ByteBuffer, const std::string_view a_Channel) { - if ((a_Channel == "MC|AdvCdm") || (a_Channel == "MC|AdvCmd")) // Spelling was fixed in 15w34 + if ((a_Channel == "AdvCdm") || (a_Channel == "AdvCmd")) // Spelling was fixed in 15w34. { - // https://wiki.vg/index.php?title=Plugin_channels&oldid=14089#MC.7CAdvCmd - HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, Dest); + HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, Type); - switch (Dest) + switch (Type) { case 0x00: { - // Editing a command-block HANDLE_READ(a_ByteBuffer, ReadBEInt32, Int32, BlockX); HANDLE_READ(a_ByteBuffer, ReadBEInt32, Int32, BlockY); HANDLE_READ(a_ByteBuffer, ReadBEInt32, Int32, BlockZ); HANDLE_READ(a_ByteBuffer, ReadVarUTF8String, AString, Command); + HANDLE_READ(a_ByteBuffer, ReadBool, bool, TrackOutput); + + // Editing a command-block: m_Client->HandleCommandBlockBlockChange(BlockX, BlockY, BlockZ, Command); - break; - } - - case 0x01: - { - // Editing a command-block-minecart - HANDLE_READ(a_ByteBuffer, ReadBEUInt32, UInt32, EntityID); - HANDLE_READ(a_ByteBuffer, ReadVarUTF8String, AString, Command); - m_Client->HandleCommandBlockEntityChange(EntityID, Command); - break; - } - - default: - { - m_Client->SendChat(Printf("Failure setting command block command; unhandled destination %u (0x%02x)", Dest, Dest), mtFailure); - LOG("Unhandled MC|AdvCmd packet destination."); return; } - } // switch (Mode) - return; - } - else if (a_Channel == "MC|Brand") - { - HANDLE_READ(a_ByteBuffer, ReadVarUTF8String, AString, Brand); + case 0x01: + { + HANDLE_READ(a_ByteBuffer, ReadBEUInt32, UInt32, EntityID); + HANDLE_READ(a_ByteBuffer, ReadVarUTF8String, AString, Command); + HANDLE_READ(a_ByteBuffer, ReadBool, bool, TrackOutput); - m_Client->SetClientBrand(Brand); - // Send back our brand, including the length: - m_Client->SendPluginMessage("MC|Brand", "\x08""Cuberite"); - return; + // Editing a command-block-minecart: + m_Client->HandleCommandBlockEntityChange(EntityID, Command); + return; + } + default: + { + m_Client->Kick("Unknown command block edit type - hacked client?"); + return; + } + } } - else if (a_Channel == "MC|Beacon") + else if (a_Channel == "Beacon") { HANDLE_READ(a_ByteBuffer, ReadBEUInt32, UInt32, Effect1); HANDLE_READ(a_ByteBuffer, ReadBEUInt32, UInt32, Effect2); m_Client->HandleBeaconSelection(Effect1, Effect2); - return; } - else if (a_Channel == "MC|ItemName") + else if (a_Channel == "BEdit") + { + if (cItem UnsignedBook; ReadItem(a_ByteBuffer, UnsignedBook)) + { + // TODO: m_Client->HandleBookEdit + } + } + else if (a_Channel == "BSign") + { + if (cItem WrittenBook; ReadItem(a_ByteBuffer, WrittenBook)) + { + // TODO: m_Client->HandleBookSign + } + } + else if (a_Channel == "Brand") + { + HANDLE_READ(a_ByteBuffer, ReadVarUTF8String, AString, Brand); + + m_Client->SetClientBrand(Brand); + m_Client->SendPluginMessage("MC|Brand", "\x08""Cuberite"); // Send back our brand, including the length. + } + else if (a_Channel == "ItemName") { HANDLE_READ(a_ByteBuffer, ReadVarUTF8String, AString, ItemName); m_Client->HandleAnvilItemName(ItemName); - return; } - else if (a_Channel == "MC|TrSel") + else if (a_Channel == "TrSel") { HANDLE_READ(a_ByteBuffer, ReadBEInt32, Int32, 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: - ContiguousByteBuffer Message; - VERIFY(a_ByteBuffer.ReadSome(Message, a_ByteBuffer.GetReadableSpace())); - m_Client->HandlePluginMessage(a_Channel, Message); } diff --git a/src/Protocol/Protocol_1_8.h b/src/Protocol/Protocol_1_8.h index 704725bee..7365cd2db 100644 --- a/src/Protocol/Protocol_1_8.h +++ b/src/Protocol/Protocol_1_8.h @@ -201,8 +201,8 @@ protected: virtual 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 */ - virtual void HandleVanillaPluginMessage(cByteBuffer & a_ByteBuffer, const AString & a_Channel); + The message payload is still in the bytebuffer, the handler reads it specifically for each handled channel. */ + virtual void HandleVanillaPluginMessage(cByteBuffer & a_ByteBuffer, std::string_view a_Channel); /** Parses item metadata as read by ReadItem(), into the item enchantments. */ virtual void ParseItemMetadata(cItem & a_Item, ContiguousByteBufferView a_Metadata) const; diff --git a/src/Protocol/Protocol_1_9.cpp b/src/Protocol/Protocol_1_9.cpp index 3b09ada4c..2cc087682 100644 --- a/src/Protocol/Protocol_1_9.cpp +++ b/src/Protocol/Protocol_1_9.cpp @@ -1197,6 +1197,58 @@ void cProtocol_1_9_0::HandlePacketWindowClick(cByteBuffer & a_ByteBuffer) +void cProtocol_1_9_0::HandleVanillaPluginMessage(cByteBuffer & a_ByteBuffer, std::string_view a_Channel) +{ + if (a_Channel == "AutoCmd") + { + HANDLE_READ(a_ByteBuffer, ReadBEInt32, Int32, BlockX); + HANDLE_READ(a_ByteBuffer, ReadBEInt32, Int32, BlockY); + HANDLE_READ(a_ByteBuffer, ReadBEInt32, Int32, BlockZ); + HANDLE_READ(a_ByteBuffer, ReadVarUTF8String, AString, Command); + HANDLE_READ(a_ByteBuffer, ReadBool, bool, TrackOutput); + HANDLE_READ(a_ByteBuffer, ReadVarUTF8String, AString, Mode); + HANDLE_READ(a_ByteBuffer, ReadBool, bool, Conditional); + HANDLE_READ(a_ByteBuffer, ReadBool, bool, Automatic); + + m_Client->HandleCommandBlockBlockChange(BlockX, BlockY, BlockZ, Command); + } + else if (a_Channel == "PickItem") + { + HANDLE_READ(a_ByteBuffer, ReadVarInt32, UInt32, InventorySlotIndex); + } + else if (a_Channel == "Struct") + { + HANDLE_READ(a_ByteBuffer, ReadBEInt32, Int32, BlockX); + HANDLE_READ(a_ByteBuffer, ReadBEInt32, Int32, BlockY); + HANDLE_READ(a_ByteBuffer, ReadBEInt32, Int32, BlockZ); + HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, Action); + HANDLE_READ(a_ByteBuffer, ReadVarUTF8String, AString, Mode); + HANDLE_READ(a_ByteBuffer, ReadVarUTF8String, AString, Name); + HANDLE_READ(a_ByteBuffer, ReadBEInt32, Int32, OffsetX); + HANDLE_READ(a_ByteBuffer, ReadBEInt32, Int32, OffsetY); + HANDLE_READ(a_ByteBuffer, ReadBEInt32, Int32, OffsetZ); + HANDLE_READ(a_ByteBuffer, ReadBEUInt32, UInt32, SizeX); + HANDLE_READ(a_ByteBuffer, ReadBEUInt32, UInt32, SizeY); + HANDLE_READ(a_ByteBuffer, ReadBEUInt32, UInt32, SizeZ); + HANDLE_READ(a_ByteBuffer, ReadVarUTF8String, AString, Mirror); + HANDLE_READ(a_ByteBuffer, ReadVarUTF8String, AString, Rotation); + HANDLE_READ(a_ByteBuffer, ReadVarUTF8String, AString, Metadata); + HANDLE_READ(a_ByteBuffer, ReadBool, bool, IgnoreEntities); + HANDLE_READ(a_ByteBuffer, ReadBool, bool, ShowAir); + HANDLE_READ(a_ByteBuffer, ReadBool, bool, ShowBoundingBox); + HANDLE_READ(a_ByteBuffer, ReadBEFloat, float, Integrity); + HANDLE_READ(a_ByteBuffer, ReadVarInt64, UInt64, Seed); + } + else + { + Super::HandleVanillaPluginMessage(a_ByteBuffer, a_Channel); + } +} + + + + + void cProtocol_1_9_0::ParseItemMetadata(cItem & a_Item, const ContiguousByteBufferView a_Metadata) const { // Parse into NBT: diff --git a/src/Protocol/Protocol_1_9.h b/src/Protocol/Protocol_1_9.h index c2005c4b9..9766646e0 100644 --- a/src/Protocol/Protocol_1_9.h +++ b/src/Protocol/Protocol_1_9.h @@ -90,6 +90,7 @@ protected: virtual void HandlePacketUseItem (cByteBuffer & a_ByteBuffer); virtual void HandlePacketVehicleMove (cByteBuffer & a_ByteBuffer); virtual void HandlePacketWindowClick (cByteBuffer & a_ByteBuffer) override; + virtual void HandleVanillaPluginMessage (cByteBuffer & a_ByteBuffer, std::string_view a_Channel) override; virtual void ParseItemMetadata(cItem & a_Item, ContiguousByteBufferView a_Metadata) const override; virtual void SendEntitySpawn(const cEntity & a_Entity, const UInt8 a_ObjectType, const Int32 a_ObjectData) override;