summaryrefslogtreecommitdiffstats
path: root/src/Protocol/Protocol17x.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/Protocol/Protocol17x.cpp')
-rw-r--r--src/Protocol/Protocol17x.cpp214
1 files changed, 175 insertions, 39 deletions
diff --git a/src/Protocol/Protocol17x.cpp b/src/Protocol/Protocol17x.cpp
index 8ec5dec29..5b3a79555 100644
--- a/src/Protocol/Protocol17x.cpp
+++ b/src/Protocol/Protocol17x.cpp
@@ -121,7 +121,7 @@ void cProtocol172::SendBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, cha
void cProtocol172::SendBlockBreakAnim(int a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage)
{
- cPacketizer Pkt(*this, 0x24); // Block Break Animation packet
+ cPacketizer Pkt(*this, 0x25); // Block Break Animation packet
Pkt.WriteInt(a_EntityID);
Pkt.WriteInt(a_BlockX);
Pkt.WriteInt(a_BlockY);
@@ -216,8 +216,23 @@ void cProtocol172::SendDestroyEntity(const cEntity & a_Entity)
void cProtocol172::SendDisconnect(const AString & a_Reason)
{
- cPacketizer Pkt(*this, 0x40);
- Pkt.WriteString(Printf("{\"text\":\"%s\"}", EscapeString(a_Reason).c_str()));
+ switch (m_State)
+ {
+ case 2:
+ {
+ // During login:
+ cPacketizer Pkt(*this, 0);
+ Pkt.WriteString(Printf("{\"text\":\"%s\"}", EscapeString(a_Reason).c_str()));
+ break;
+ }
+ case 3:
+ {
+ // In-game:
+ cPacketizer Pkt(*this, 0x40);
+ Pkt.WriteString(Printf("{\"text\":\"%s\"}", EscapeString(a_Reason).c_str()));
+ break;
+ }
+ }
}
@@ -628,6 +643,18 @@ void cProtocol172::SendPlayerSpawn(const cPlayer & a_Player)
+void cProtocol172::SendPluginMessage(const AString & a_Channel, const AString & a_Message)
+{
+ cPacketizer Pkt(*this, 0x3f);
+ Pkt.WriteString(a_Channel);
+ Pkt.WriteShort((short)a_Message.size());
+ Pkt.WriteBuf(a_Message.data(), a_Message.size());
+}
+
+
+
+
+
void cProtocol172::SendRemoveEntityEffect(const cEntity & a_Entity, int a_EffectID)
{
cPacketizer Pkt(*this, 0x1E);
@@ -1010,11 +1037,31 @@ void cProtocol172::AddReceivedData(const char * a_Data, int a_Size)
return;
}
- HandlePacket(bb, PacketType);
+ if (!HandlePacket(bb, PacketType))
+ {
+ // Unknown packet, already been reported, but without the length. Log the length here:
+ LOGWARNING("Unhandled packet: type 0x%x, state %d, length %u", PacketType, m_State, PacketLen);
+
+ #ifdef _DEBUG
+ // Dump the packet contents into the log:
+ bb.ResetRead();
+ AString Packet;
+ bb.ReadAll(Packet);
+ Packet.resize(Packet.size() - 1); // Drop the final NUL pushed there for over-read detection
+ AString Out;
+ CreateHexDump(Out, Packet.data(), (int)Packet.size(), 24);
+ LOGD("Packet contents:\n%s", Out.c_str());
+ #endif // _DEBUG
+
+ return;
+ }
if (bb.GetReadableSpace() != 1)
{
// Read more or less than packet length, report as error
+ LOGWARNING("Protocol 1.7: Wrong number of bytes read for packet 0x%x, state %d. Read %u bytes, packet contained %u bytes",
+ PacketType, m_State, bb.GetUsedSpace() - bb.GetReadableSpace(), PacketLen
+ );
ASSERT(!"Read wrong number of bytes!");
m_Client->PacketError(PacketType);
}
@@ -1024,7 +1071,7 @@ void cProtocol172::AddReceivedData(const char * a_Data, int a_Size)
-void cProtocol172::HandlePacket(cByteBuffer & a_ByteBuffer, UInt32 a_PacketType)
+bool cProtocol172::HandlePacket(cByteBuffer & a_ByteBuffer, UInt32 a_PacketType)
{
switch (m_State)
{
@@ -1033,8 +1080,8 @@ void cProtocol172::HandlePacket(cByteBuffer & a_ByteBuffer, UInt32 a_PacketType)
// Status
switch (a_PacketType)
{
- case 0x00: HandlePacketStatusRequest(a_ByteBuffer); return;
- case 0x01: HandlePacketStatusPing (a_ByteBuffer); return;
+ case 0x00: HandlePacketStatusRequest(a_ByteBuffer); return true;
+ case 0x01: HandlePacketStatusPing (a_ByteBuffer); return true;
}
break;
}
@@ -1044,8 +1091,8 @@ void cProtocol172::HandlePacket(cByteBuffer & a_ByteBuffer, UInt32 a_PacketType)
// Login
switch (a_PacketType)
{
- case 0x00: HandlePacketLoginStart (a_ByteBuffer); return;
- case 0x01: HandlePacketLoginEncryptionResponse(a_ByteBuffer); return;
+ case 0x00: HandlePacketLoginStart (a_ByteBuffer); return true;
+ case 0x01: HandlePacketLoginEncryptionResponse(a_ByteBuffer); return true;
}
break;
}
@@ -1055,36 +1102,54 @@ void cProtocol172::HandlePacket(cByteBuffer & a_ByteBuffer, UInt32 a_PacketType)
// Game
switch (a_PacketType)
{
- case 0x00: HandlePacketKeepAlive (a_ByteBuffer); return;
- case 0x01: HandlePacketChatMessage (a_ByteBuffer); return;
- case 0x02: HandlePacketUseEntity (a_ByteBuffer); return;
- case 0x03: HandlePacketPlayer (a_ByteBuffer); return;
- case 0x04: HandlePacketPlayerPos (a_ByteBuffer); return;
- case 0x05: HandlePacketPlayerLook (a_ByteBuffer); return;
- case 0x06: HandlePacketPlayerPosLook (a_ByteBuffer); return;
- case 0x07: HandlePacketBlockDig (a_ByteBuffer); return;
- case 0x08: HandlePacketBlockPlace (a_ByteBuffer); return;
- case 0x09: HandlePacketSlotSelect (a_ByteBuffer); return;
- case 0x0a: HandlePacketAnimation (a_ByteBuffer); return;
- case 0x0b: HandlePacketEntityAction (a_ByteBuffer); return;
- case 0x0c: HandlePacketSteerVehicle (a_ByteBuffer); return;
- case 0x0d: HandlePacketWindowClose (a_ByteBuffer); return;
- case 0x0e: HandlePacketWindowClick (a_ByteBuffer); return;
+ case 0x00: HandlePacketKeepAlive (a_ByteBuffer); return true;
+ case 0x01: HandlePacketChatMessage (a_ByteBuffer); return true;
+ case 0x02: HandlePacketUseEntity (a_ByteBuffer); return true;
+ case 0x03: HandlePacketPlayer (a_ByteBuffer); return true;
+ case 0x04: HandlePacketPlayerPos (a_ByteBuffer); return true;
+ case 0x05: HandlePacketPlayerLook (a_ByteBuffer); return true;
+ case 0x06: HandlePacketPlayerPosLook (a_ByteBuffer); return true;
+ case 0x07: HandlePacketBlockDig (a_ByteBuffer); return true;
+ case 0x08: HandlePacketBlockPlace (a_ByteBuffer); return true;
+ case 0x09: HandlePacketSlotSelect (a_ByteBuffer); return true;
+ case 0x0a: HandlePacketAnimation (a_ByteBuffer); return true;
+ case 0x0b: HandlePacketEntityAction (a_ByteBuffer); return true;
+ case 0x0c: HandlePacketSteerVehicle (a_ByteBuffer); return true;
+ case 0x0d: HandlePacketWindowClose (a_ByteBuffer); return true;
+ case 0x0e: HandlePacketWindowClick (a_ByteBuffer); return true;
case 0x0f: // Confirm transaction - not used in MCS
- case 0x10: HandlePacketCreativeInventoryAction(a_ByteBuffer); return;
- case 0x12: HandlePacketUpdateSign (a_ByteBuffer); return;
- case 0x13: HandlePacketPlayerAbilities (a_ByteBuffer); return;
- case 0x14: HandlePacketTabComplete (a_ByteBuffer); return;
- case 0x15: HandlePacketClientSettings (a_ByteBuffer); return;
- case 0x16: HandlePacketClientStatus (a_ByteBuffer); return;
- case 0x17: HandlePacketPluginMessage (a_ByteBuffer); return;
+ case 0x10: HandlePacketCreativeInventoryAction(a_ByteBuffer); return true;
+ case 0x12: HandlePacketUpdateSign (a_ByteBuffer); return true;
+ case 0x13: HandlePacketPlayerAbilities (a_ByteBuffer); return true;
+ case 0x14: HandlePacketTabComplete (a_ByteBuffer); return true;
+ case 0x15: HandlePacketClientSettings (a_ByteBuffer); return true;
+ case 0x16: HandlePacketClientStatus (a_ByteBuffer); return true;
+ case 0x17: HandlePacketPluginMessage (a_ByteBuffer); return true;
}
break;
}
+ default:
+ {
+ // Received a packet in an unknown state, report:
+ LOGWARNING("Received a packet in an unknown protocol state %d. Ignoring further packets.", m_State);
+
+ // Cannot kick the client - we don't know this state and thus the packet number for the kick packet
+
+ // Switch to a state when all further packets are silently ignored:
+ m_State = 255;
+ return false;
+ }
+ case 255:
+ {
+ // This is the state used for "not processing packets anymore" when we receive a bad packet from a client.
+ // Do not output anything (the caller will do that for us), just return failure
+ return false;
+ }
} // switch (m_State)
- // Unknown packet type, report to the client:
+ // Unknown packet type, report to the ClientHandle:
m_Client->PacketUnknown(a_PacketType);
+ return false;
}
@@ -1144,6 +1209,12 @@ void cProtocol172::HandlePacketLoginStart(cByteBuffer & a_ByteBuffer)
// TODO: Protocol encryption should be set up here if not localhost / auth
+ if (!m_Client->HandleHandshake(Username))
+ {
+ // The client is not welcome here, they have been sent a Kick packet already
+ return;
+ }
+
// Send login success:
{
cPacketizer Pkt(*this, 0x02); // Login success packet
@@ -1614,7 +1685,7 @@ void cProtocol172::ParseItemMetadata(cItem & a_Item, const AString & a_Metadata)
return;
}
- // Load enchantments from the NBT:
+ // Load enchantments and custom display names from the NBT data:
for (int tag = NBT.GetFirstChild(NBT.GetRoot()); tag >= 0; tag = NBT.GetNextSibling(tag))
{
if (
@@ -1627,6 +1698,27 @@ void cProtocol172::ParseItemMetadata(cItem & a_Item, const AString & a_Metadata)
{
a_Item.m_Enchantments.ParseFromNBT(NBT, tag);
}
+ else if ((NBT.GetType(tag) == TAG_Compound) && (NBT.GetName(tag) == "display")) // Custom name and lore tag
+ {
+ for (int displaytag = NBT.GetFirstChild(tag); displaytag >= 0; displaytag = NBT.GetNextSibling(displaytag))
+ {
+ if ((NBT.GetType(displaytag) == TAG_String) && (NBT.GetName(displaytag) == "Name")) // Custon name tag
+ {
+ a_Item.m_CustomName = NBT.GetString(displaytag);
+ }
+ else if ((NBT.GetType(displaytag) == TAG_List) && (NBT.GetName(displaytag) == "Lore")) // Lore tag
+ {
+ AString Lore;
+
+ for (int loretag = NBT.GetFirstChild(displaytag); loretag >= 0; loretag = NBT.GetNextSibling(loretag)) // Loop through array of strings
+ {
+ AppendPrintf(Lore, "%s`", NBT.GetString(loretag).c_str()); // Append the lore with a newline, used internally by MCS to display a new line in the client; don't forget to c_str ;)
+ }
+
+ a_Item.m_Lore = Lore;
+ }
+ }
+ }
}
}
@@ -1678,16 +1770,45 @@ void cProtocol172::cPacketizer::WriteItem(const cItem & a_Item)
WriteByte (a_Item.m_ItemCount);
WriteShort(a_Item.m_ItemDamage);
- if (a_Item.m_Enchantments.IsEmpty())
+ if (a_Item.m_Enchantments.IsEmpty() && a_Item.IsBothNameAndLoreEmpty())
{
WriteShort(-1);
return;
}
- // Send the enchantments:
+ // Send the enchantments and custom names:
cFastNBTWriter Writer;
- const char * TagName = (a_Item.m_ItemType == E_ITEM_BOOK) ? "StoredEnchantments" : "ench";
- a_Item.m_Enchantments.WriteToNBTCompound(Writer, TagName);
+ if (!a_Item.m_Enchantments.IsEmpty())
+ {
+ const char * TagName = (a_Item.m_ItemType == E_ITEM_BOOK) ? "StoredEnchantments" : "ench";
+ a_Item.m_Enchantments.WriteToNBTCompound(Writer, TagName);
+ }
+ if (!a_Item.IsBothNameAndLoreEmpty())
+ {
+ Writer.BeginCompound("display");
+ if (!a_Item.IsCustomNameEmpty())
+ {
+ Writer.AddString("Name", a_Item.m_CustomName.c_str());
+ }
+ if (!a_Item.IsLoreEmpty())
+ {
+ Writer.BeginList("Lore", TAG_String);
+
+ AStringVector Decls = StringSplit(a_Item.m_Lore, "`");
+ for (AStringVector::const_iterator itr = Decls.begin(), end = Decls.end(); itr != end; ++itr)
+ {
+ if (itr->empty())
+ {
+ // The decl is empty (two `s), ignore
+ continue;
+ }
+ Writer.AddString("", itr->c_str());
+ }
+
+ Writer.EndList();
+ }
+ Writer.EndCompound();
+ }
Writer.Finish();
AString Compressed;
CompressStringGZIP(Writer.GetResult().data(), Writer.GetResult().size(), Compressed);
@@ -1769,8 +1890,23 @@ void cProtocol172::cPacketizer::WriteEntityMetadata(const cEntity & a_Entity)
WriteInt(1); // Shaking direction, doesn't seem to affect anything
WriteByte(0x73);
WriteFloat((float)(((const cMinecart &)a_Entity).LastDamage() + 10)); // Damage taken / shake effect multiplyer
-
- if (((cMinecart &)a_Entity).GetPayload() == cMinecart::mpFurnace)
+
+ if (((cMinecart &)a_Entity).GetPayload() == cMinecart::mpNone)
+ {
+ cRideableMinecart & RideableMinecart = ((cRideableMinecart &)a_Entity);
+ if (!RideableMinecart.GetContent().IsEmpty())
+ {
+ WriteByte(0x54);
+ int Content = RideableMinecart.GetContent().m_ItemType;
+ Content |= RideableMinecart.GetContent().m_ItemDamage << 8;
+ WriteInt(Content);
+ WriteByte(0x55);
+ WriteInt(RideableMinecart.GetBlockHeight());
+ WriteByte(0x56);
+ WriteByte(1);
+ }
+ }
+ else if (((cMinecart &)a_Entity).GetPayload() == cMinecart::mpFurnace)
{
WriteByte(0x10);
WriteByte(((const cMinecartWithFurnace &)a_Entity).IsFueled() ? 1 : 0);