1
0

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.
This commit is contained in:
madmaxoft 2014-09-30 13:33:57 +02:00
parent 46d3d40493
commit d7066f43d3
6 changed files with 242 additions and 118 deletions

View File

@ -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);
}
}

View File

@ -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

View File

@ -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)

View File

@ -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;

View File

@ -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)

View File

@ -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;