diff options
Diffstat (limited to 'src/Protocol/Protocol17x.cpp')
-rw-r--r-- | src/Protocol/Protocol17x.cpp | 214 |
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); |