summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/ClientHandle.cpp120
-rw-r--r--src/ClientHandle.h55
-rw-r--r--src/Protocol/Protocol17x.cpp92
-rw-r--r--src/Protocol/Protocol17x.h3
-rw-r--r--src/Protocol/Protocol18x.cpp86
-rw-r--r--src/Protocol/Protocol18x.h4
6 files changed, 242 insertions, 118 deletions
diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp
index 20e219309..a29bef0c0 100644
--- a/src/ClientHandle.cpp
+++ b/src/ClientHandle.cpp
@@ -551,6 +551,16 @@ void cClientHandle::RemoveFromAllChunks()
+void cClientHandle::HandleNPCTrade(int a_SlotNum)
+{
+ // TODO
+ LOGWARNING("%s: Not implemented yet", __FUNCTION__);
+}
+
+
+
+
+
void cClientHandle::HandlePing(void)
{
// Somebody tries to retrieve information about the server
@@ -573,7 +583,6 @@ void cClientHandle::HandlePing(void)
bool cClientHandle::HandleLogin(int a_ProtocolVersion, const AString & a_Username)
{
- LOGD("LOGIN %s", a_Username.c_str());
m_Username = a_Username;
if (cRoot::Get()->GetPluginManager()->CallHookLogin(this, a_ProtocolVersion, a_Username))
@@ -676,25 +685,7 @@ void cClientHandle::HandlePlayerPos(double a_PosX, double a_PosY, double a_PosZ,
void cClientHandle::HandlePluginMessage(const AString & a_Channel, const AString & a_Message)
{
- if (a_Channel == "MC|AdvCdm")
- {
- // Command block, set text, Client -> Server
- HandleCommandBlockMessage(a_Message.c_str(), a_Message.size());
- }
- else if (a_Channel == "MC|Brand")
- {
- // Client <-> Server branding exchange
- SendPluginMessage("MC|Brand", "MCServer");
- }
- else if (a_Channel == "MC|Beacon")
- {
- HandleBeaconSelection(a_Message.c_str(), a_Message.size());
- }
- else if (a_Channel == "MC|ItemName")
- {
- HandleAnvilItemName(a_Message.c_str(), a_Message.size());
- }
- else if (a_Channel == "REGISTER")
+ if (a_Channel == "REGISTER")
{
if (HasPluginChannel(a_Channel))
{
@@ -777,15 +768,8 @@ void cClientHandle::UnregisterPluginChannels(const AStringVector & a_ChannelList
-void cClientHandle::HandleBeaconSelection(const char * a_Data, size_t a_Length)
+void cClientHandle::HandleBeaconSelection(int a_PrimaryEffect, int a_SecondaryEffect)
{
- if (a_Length < 14)
- {
- SendChat("Failure setting beacon selection; bad request", mtFailure);
- LOGD("Malformed MC|Beacon packet.");
- return;
- }
-
cWindow * Window = m_Player->GetWindow();
if ((Window == NULL) || (Window->GetWindowType() != cWindow::wtBeacon))
{
@@ -798,23 +782,15 @@ void cClientHandle::HandleBeaconSelection(const char * a_Data, size_t a_Length)
return;
}
- cByteBuffer Buffer(a_Length);
- Buffer.Write(a_Data, a_Length);
-
- int PrimaryEffectID, SecondaryEffectID;
- Buffer.ReadBEInt(PrimaryEffectID);
- Buffer.ReadBEInt(SecondaryEffectID);
-
cEntityEffect::eType PrimaryEffect = cEntityEffect::effNoEffect;
- if ((PrimaryEffectID >= 0) && (PrimaryEffectID <= (int)cEntityEffect::effSaturation))
+ if ((a_PrimaryEffect >= 0) && (a_PrimaryEffect <= (int)cEntityEffect::effSaturation))
{
- PrimaryEffect = (cEntityEffect::eType)PrimaryEffectID;
+ PrimaryEffect = (cEntityEffect::eType)a_PrimaryEffect;
}
-
cEntityEffect::eType SecondaryEffect = cEntityEffect::effNoEffect;
- if ((SecondaryEffectID >= 0) && (SecondaryEffectID <= (int)cEntityEffect::effSaturation))
+ if ((a_SecondaryEffect >= 0) && (a_SecondaryEffect <= (int)cEntityEffect::effSaturation))
{
- SecondaryEffect = (cEntityEffect::eType)SecondaryEffectID;
+ SecondaryEffect = (cEntityEffect::eType)a_SecondaryEffect;
}
Window->SetSlot(*m_Player, 0, cItem());
@@ -841,52 +817,12 @@ void cClientHandle::HandleBeaconSelection(const char * a_Data, size_t a_Length)
-void cClientHandle::HandleCommandBlockMessage(const char * a_Data, size_t a_Length)
+void cClientHandle::HandleCommandBlockBlockChange(int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_NewCommand)
{
- if (a_Length < 14)
- {
- SendChat("Failure setting command block command; bad request", mtFailure);
- LOGD("Malformed MC|AdvCdm packet.");
- return;
- }
-
- cByteBuffer Buffer(a_Length);
- Buffer.Write(a_Data, a_Length);
-
- int BlockX, BlockY, BlockZ;
-
- AString Command;
-
- char Mode;
-
- Buffer.ReadChar(Mode);
-
- switch (Mode)
- {
- case 0x00:
- {
- Buffer.ReadBEInt(BlockX);
- Buffer.ReadBEInt(BlockY);
- Buffer.ReadBEInt(BlockZ);
-
- Buffer.ReadVarUTF8String(Command);
- break;
- }
-
- default:
- {
- SendChat("Failure setting command block command; unhandled mode", mtFailure);
- LOGD("Unhandled MC|AdvCdm packet mode.");
- return;
- }
- }
-
cWorld * World = m_Player->GetWorld();
-
if (World->AreCommandBlocksEnabled())
{
- World->SetCommandBlockCommand(BlockX, BlockY, BlockZ, Command);
-
+ World->SetCommandBlockCommand(a_BlockX, a_BlockY, a_BlockZ, a_NewCommand);
SendChat("Successfully set command block command", mtSuccess);
}
else
@@ -899,22 +835,26 @@ void cClientHandle::HandleCommandBlockMessage(const char * a_Data, size_t a_Leng
-void cClientHandle::HandleAnvilItemName(const char * a_Data, size_t a_Length)
+void cClientHandle::HandleCommandBlockEntityChange(int a_EntityID, const AString & a_NewCommand)
{
- if (a_Length < 1)
- {
- return;
- }
+ // TODO
+ LOGWARNING("%s: Not implemented yet", __FUNCTION__);
+}
+
+
+
+
+void cClientHandle::HandleAnvilItemName(const AString & a_ItemName)
+{
if ((m_Player->GetWindow() == NULL) || (m_Player->GetWindow()->GetWindowType() != cWindow::wtAnvil))
{
return;
}
- AString Name(a_Data, a_Length);
- if (Name.length() <= 30)
+ if (a_ItemName.length() <= 30)
{
- ((cAnvilWindow *)m_Player->GetWindow())->SetRepairedItemName(Name, m_Player);
+ ((cAnvilWindow *)m_Player->GetWindow())->SetRepairedItemName(a_ItemName, m_Player);
}
}
diff --git a/src/ClientHandle.h b/src/ClientHandle.h
index 10cf6ae28..1f22762c0 100644
--- a/src/ClientHandle.h
+++ b/src/ClientHandle.h
@@ -222,6 +222,13 @@ public:
bool HasPluginChannel(const AString & a_PluginChannel);
+ /** Called by the protocol when it receives the MC|Brand plugin message. Also callable by plugins.
+ Simply stores the string value. */
+ void SetClientBrand(const AString & a_ClientBrand) { m_ClientBrand = a_ClientBrand; }
+
+ /** Returns the client brand received in the MC|Brand plugin message or set by a plugin. */
+ const AString & GetClientBrand(void) const { return m_ClientBrand; }
+
// tolua_end
/** Returns true if the client wants the chunk specified to be sent (in m_ChunksToSend) */
@@ -236,12 +243,31 @@ public:
void PacketError(unsigned char a_PacketType);
// Calls that cProtocol descendants use for handling packets:
- void HandleAnimation (char a_Animation);
- void HandleChat (const AString & a_Message);
- void HandleCreativeInventory(short a_SlotNum, const cItem & a_HeldItem);
- void HandleEntityCrouch (int a_EntityID, bool a_IsCrouching);
- void HandleEntityLeaveBed (int a_EntityID);
- void HandleEntitySprinting (int a_EntityID, bool a_IsSprinting);
+ void HandleAnimation(char a_Animation);
+
+ /** Called when the protocol receives a MC|ItemName plugin message, indicating that the player named
+ an item in the anvil UI. */
+ void HandleAnvilItemName(const AString & a_ItemName);
+
+ /** Called when the protocol receives a MC|Beacon plugin message, indicating that the player set an effect
+ in the beacon UI. */
+ void HandleBeaconSelection(int a_PrimaryEffect, int a_SecondaryEffect);
+
+ /** Called when the protocol detects a chat packet. */
+ void HandleChat(const AString & a_Message);
+
+ /** Called when the protocol receives a MC|AdvCdm plugin message, indicating that the player set a new
+ command in the command block UI, for a block-based commandblock. */
+ void HandleCommandBlockBlockChange(int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_NewCommand);
+
+ /** Called when the protocol receives a MC|AdvCdm plugin message, indicating that the player set a new
+ command in the command block UI, for an entity-based commandblock (minecart?). */
+ void HandleCommandBlockEntityChange(int a_EntityID, const AString & a_NewCommand);
+
+ void HandleCreativeInventory (short a_SlotNum, const cItem & a_HeldItem);
+ void HandleEntityCrouch (int a_EntityID, bool a_IsCrouching);
+ void HandleEntityLeaveBed (int a_EntityID);
+ void HandleEntitySprinting (int a_EntityID, bool a_IsSprinting);
/** Called when the protocol handshake has been received (for protocol versions that support it;
otherwise the first instant when a username is received).
@@ -251,6 +277,11 @@ public:
void HandleKeepAlive (int a_KeepAliveID);
void HandleLeftClick (int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, char a_Status);
+
+ /** Called when the protocol receives a MC|TrSel packet, indicating that the player used a trade in
+ the NPC UI. */
+ void HandleNPCTrade(int a_SlotNum);
+
void HandlePing (void);
void HandlePlayerAbilities (bool a_CanFly, bool a_IsFlying, float FlyingSpeed, float WalkingSpeed);
void HandlePlayerLook (float a_Rotation, float a_Pitch, bool a_IsOnGround);
@@ -392,6 +423,9 @@ private:
/** The plugin channels that the client has registered. */
cChannels m_PluginChannels;
+
+ /** The brand identification of the client, as received in the MC|Brand plugin message or set from a plugin. */
+ AString m_ClientBrand;
/** Handles the block placing packet when it is a real block placement (not block-using, item-using or eating) */
@@ -421,15 +455,6 @@ private:
/** Removes all of the channels from the list of current plugin channels. Ignores channels that are not found. */
void UnregisterPluginChannels(const AStringVector & a_ChannelList);
- /** Handles the "MC|Beacon" plugin message */
- void HandleBeaconSelection(const char * a_Data, size_t a_Length);
-
- /** Handles the "MC|AdvCdm" plugin message */
- void HandleCommandBlockMessage(const char * a_Data, size_t a_Length);
-
- /** Handles the "MC|ItemName" plugin message */
- void HandleAnvilItemName(const char * a_Data, size_t a_Length);
-
// cSocketThreads::cCallback overrides:
virtual bool DataReceived (const char * a_Data, size_t a_Size) override; // Data is received from the client
virtual void GetOutgoingData(AString & a_Data) override; // Data can be sent to client
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;