diff options
author | archshift <admin@archshift.com> | 2014-07-29 22:04:00 +0200 |
---|---|---|
committer | archshift <admin@archshift.com> | 2014-07-29 22:04:00 +0200 |
commit | a9b597087b56b4526a3f6447789ba141568575a1 (patch) | |
tree | a08542d77b5668a25ca5e00492577ed6f4d61a9a /src/Protocol/Protocol17x.cpp | |
parent | Spacing fixes and a few more BLOCK_META constants. (diff) | |
parent | Slight cleanup after portals (diff) | |
download | cuberite-a9b597087b56b4526a3f6447789ba141568575a1.tar cuberite-a9b597087b56b4526a3f6447789ba141568575a1.tar.gz cuberite-a9b597087b56b4526a3f6447789ba141568575a1.tar.bz2 cuberite-a9b597087b56b4526a3f6447789ba141568575a1.tar.lz cuberite-a9b597087b56b4526a3f6447789ba141568575a1.tar.xz cuberite-a9b597087b56b4526a3f6447789ba141568575a1.tar.zst cuberite-a9b597087b56b4526a3f6447789ba141568575a1.zip |
Diffstat (limited to '')
-rw-r--r-- | src/Protocol/Protocol17x.cpp | 244 |
1 files changed, 168 insertions, 76 deletions
diff --git a/src/Protocol/Protocol17x.cpp b/src/Protocol/Protocol17x.cpp index 6fa928215..45d39e0e9 100644 --- a/src/Protocol/Protocol17x.cpp +++ b/src/Protocol/Protocol17x.cpp @@ -11,13 +11,19 @@ Implements the 1.7.x protocol classes: #include "json/json.h" #include "Protocol17x.h" #include "ChunkDataSerializer.h" +#include "PolarSSL++/Sha1Checksum.h" + #include "../ClientHandle.h" #include "../Root.h" #include "../Server.h" #include "../World.h" +#include "../StringCompression.h" +#include "../CompositeChat.h" +#include "../Statistics.h" + #include "../WorldStorage/FastNBT.h" #include "../WorldStorage/EnchantmentSerializer.h" -#include "../StringCompression.h" + #include "../Entities/ExpOrb.h" #include "../Entities/Minecart.h" #include "../Entities/FallingBlock.h" @@ -25,14 +31,15 @@ Implements the 1.7.x protocol classes: #include "../Entities/Pickup.h" #include "../Entities/Player.h" #include "../Entities/ItemFrame.h" +#include "../Entities/ArrowEntity.h" +#include "../Entities/FireworkEntity.h" + #include "../Mobs/IncludeAllMonsters.h" #include "../UI/Window.h" + #include "../BlockEntities/CommandBlockEntity.h" #include "../BlockEntities/MobHeadEntity.h" #include "../BlockEntities/FlowerPotEntity.h" -#include "../CompositeChat.h" -#include "../Entities/ArrowEntity.h" -#include "../Entities/FireworkEntity.h" @@ -74,7 +81,7 @@ extern bool g_ShouldLogCommIn, g_ShouldLogCommOut; -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// // cProtocol172: cProtocol172::cProtocol172(cClientHandle * a_Client, const AString & a_ServerAddress, UInt16 a_ServerPort, UInt32 a_State) : @@ -85,7 +92,8 @@ cProtocol172::cProtocol172(cClientHandle * a_Client, const AString & a_ServerAdd m_ReceivedData(32 KiB), m_OutPacketBuffer(64 KiB), m_OutPacketLenBuffer(20), // 20 bytes is more than enough for one VarInt - m_IsEncrypted(false) + m_IsEncrypted(false), + m_LastSentDimension(dimNotSet) { // Create the comm log file, if so requested: if (g_ShouldLogCommIn || g_ShouldLogCommOut) @@ -196,7 +204,7 @@ void cProtocol172::SendBlockChanges(int a_ChunkX, int a_ChunkZ, const sSetBlockV Pkt.WriteInt(a_ChunkX); Pkt.WriteInt(a_ChunkZ); Pkt.WriteShort((short)a_Changes.size()); - Pkt.WriteInt(a_Changes.size() * 4); + Pkt.WriteInt((int)a_Changes.size() * 4); for (sSetBlockVector::const_iterator itr = a_Changes.begin(), end = a_Changes.end(); itr != end; ++itr) { unsigned int Coords = itr->y | (itr->z << 8) | (itr->x << 12); @@ -227,7 +235,8 @@ void cProtocol172::SendChat(const cCompositeChat & a_Message) // Compose the complete Json string to send: Json::Value msg; - msg["text"] = ""; // The client crashes without this + cWorld * World = m_Client->GetPlayer()->GetWorld(); + msg["text"] = cClientHandle::FormatMessageType((World == NULL) ? false : World->ShouldUseChatPrefixes(), a_Message.GetMessageType(), a_Message.GetAdditionalMessageTypeData()); // The client crashes without this field being present const cCompositeChat::cParts & Parts = a_Message.GetParts(); for (cCompositeChat::cParts::const_iterator itr = Parts.begin(), end = Parts.end(); itr != end; ++itr) { @@ -282,6 +291,35 @@ void cProtocol172::SendChat(const cCompositeChat & a_Message) AddChatPartStyle(Part, p.m_Style); break; } + + case cCompositeChat::ptShowAchievement: + { + const cCompositeChat::cShowAchievementPart & p = (const cCompositeChat::cShowAchievementPart &)**itr; + Part["translate"] = "chat.type.achievement"; + + Json::Value Ach; + Ach["action"] = "show_achievement"; + Ach["value"] = p.m_Text; + + Json::Value AchColourAndName; + AchColourAndName["color"] = "green"; + AchColourAndName["translate"] = p.m_Text; + AchColourAndName["hoverEvent"] = Ach; + + Json::Value Extra; + Extra.append(AchColourAndName); + + Json::Value Name; + Name["text"] = p.m_PlayerName; + + Json::Value With; + With.append(Name); + With.append(Extra); + + Part["with"] = With; + AddChatPartStyle(Part, p.m_Style); + break; + } } msg["extra"].append(Part); } // for itr - Parts[] @@ -313,12 +351,12 @@ void cProtocol172::SendChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSerialize -void cProtocol172::SendCollectPickup(const cPickup & a_Pickup, const cPlayer & a_Player) +void cProtocol172::SendCollectEntity(const cEntity & a_Entity, const cPlayer & a_Player) { ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x0d); // Collect Item packet - Pkt.WriteInt(a_Pickup.GetUniqueID()); + Pkt.WriteInt(a_Entity.GetUniqueID()); Pkt.WriteInt(a_Player.GetUniqueID()); } @@ -531,7 +569,7 @@ void cProtocol172::SendExplosion(double a_BlockX, double a_BlockY, double a_Bloc Pkt.WriteFloat((float)a_BlockY); Pkt.WriteFloat((float)a_BlockZ); Pkt.WriteFloat((float)a_Radius); - Pkt.WriteInt(a_BlocksAffected.size()); + Pkt.WriteInt((int)a_BlocksAffected.size()); for (cVector3iArray::const_iterator itr = a_BlocksAffected.begin(), end = a_BlocksAffected.end(); itr != end; ++itr) { Pkt.WriteChar((char)itr->x); @@ -613,12 +651,13 @@ void cProtocol172::SendLogin(const cPlayer & a_Player, const cWorld & a_World) cServer * Server = cRoot::Get()->GetServer(); cPacketizer Pkt(*this, 0x01); // Join Game packet Pkt.WriteInt(a_Player.GetUniqueID()); - Pkt.WriteByte((Byte)a_Player.GetEffectiveGameMode() | (Server->IsHardcore() ? 0x08 : 0)); // Hardcore flag bit 4 + Pkt.WriteByte((Byte)a_Player.GetEffectiveGameMode() | (Server->IsHardcore() ? 0x08 : 0)); // Hardcore flag bit 4 Pkt.WriteChar((char)a_World.GetDimension()); Pkt.WriteByte(2); // TODO: Difficulty (set to Normal) Pkt.WriteByte(std::min(Server->GetMaxPlayers(), 60)); Pkt.WriteString("default"); // Level type - wtf? } + m_LastSentDimension = a_World.GetDimension(); // Send the spawn position: { @@ -697,7 +736,7 @@ void cProtocol172::SendMapDecorators(int a_ID, const cMapDecoratorList & a_Decor cPacketizer Pkt(*this, 0x34); Pkt.WriteVarInt(a_ID); - Pkt.WriteShort (1 + (3 * a_Decorators.size())); + Pkt.WriteShort ((short)(1 + (3 * a_Decorators.size()))); Pkt.WriteByte(1); @@ -768,7 +807,7 @@ void cProtocol172::SendPlayerAbilities(void) if (Player->IsGameModeCreative()) { Flags |= 0x01; - Flags |= 0x08; // Godmode, used for creative + Flags |= 0x08; // Godmode, used for creative } if (Player->IsFlying()) { @@ -947,14 +986,21 @@ void cProtocol172::SendRemoveEntityEffect(const cEntity & a_Entity, int a_Effect -void cProtocol172::SendRespawn(void) +void cProtocol172::SendRespawn(eDimension a_Dimension, bool a_ShouldIgnoreDimensionChecks) { + if ((m_LastSentDimension == a_Dimension) && !a_ShouldIgnoreDimensionChecks) + { + // Must not send a respawn for the world with the same dimension, the client goes cuckoo if we do (unless we are respawning from death) + return; + } + cPacketizer Pkt(*this, 0x07); // Respawn packet cPlayer * Player = m_Client->GetPlayer(); - Pkt.WriteInt(Player->GetWorld()->GetDimension()); + Pkt.WriteInt((int)a_Dimension); Pkt.WriteByte(2); // TODO: Difficulty (set to Normal) Pkt.WriteByte((Byte)Player->GetEffectiveGameMode()); Pkt.WriteString("default"); + m_LastSentDimension = a_Dimension; } @@ -980,7 +1026,7 @@ void cProtocol172::SendExperienceOrb(const cExpOrb & a_ExpOrb) { ASSERT(m_State == 3); // In game mode? - cPacketizer Pkt(*this, 0x11); + cPacketizer Pkt(*this, 0x11); Pkt.WriteVarInt(a_ExpOrb.GetUniqueID()); Pkt.WriteInt((int) a_ExpOrb.GetPosX()); Pkt.WriteInt((int) a_ExpOrb.GetPosY()); @@ -1038,15 +1084,15 @@ void cProtocol172::SendDisplayObjective(const AString & a_Objective, cScoreboard -void cProtocol172::SendSoundEffect(const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch) // a_Src coords are Block * 8 +void cProtocol172::SendSoundEffect(const AString & a_SoundName, double a_X, double a_Y, double a_Z, float a_Volume, float a_Pitch) { ASSERT(m_State == 3); // In game mode? - + cPacketizer Pkt(*this, 0x29); // Sound Effect packet Pkt.WriteString(a_SoundName); - Pkt.WriteInt(a_SrcX); - Pkt.WriteInt(a_SrcY); - Pkt.WriteInt(a_SrcZ); + Pkt.WriteInt((int)(a_X * 8.0)); + Pkt.WriteInt((int)(a_Y * 8.0)); + Pkt.WriteInt((int)(a_Z * 8.0)); Pkt.WriteFloat(a_Volume); Pkt.WriteByte((Byte)(a_Pitch * 63)); } @@ -1084,7 +1130,7 @@ void cProtocol172::SendSpawnFallingBlock(const cFallingBlock & a_FallingBlock) Pkt.WriteFPInt(a_FallingBlock.GetPosZ()); Pkt.WriteByteAngle(a_FallingBlock.GetYaw()); Pkt.WriteByteAngle(a_FallingBlock.GetPitch()); - Pkt.WriteInt(((int)a_FallingBlock.GetBlockType()) | (((int)a_FallingBlock.GetBlockMeta()) << 16)); // Or 0x10 + Pkt.WriteInt(((int)a_FallingBlock.GetBlockType()) | (((int)a_FallingBlock.GetBlockMeta()) << 16)); // Or 0x10 Pkt.WriteShort((short)(a_FallingBlock.GetSpeedX() * 400)); Pkt.WriteShort((short)(a_FallingBlock.GetSpeedY() * 400)); Pkt.WriteShort((short)(a_FallingBlock.GetSpeedZ() * 400)); @@ -1168,12 +1214,33 @@ void cProtocol172::SendSpawnVehicle(const cEntity & a_Vehicle, char a_VehicleTyp +void cProtocol172::SendStatistics(const cStatManager & a_Manager) +{ + ASSERT(m_State == 3); // In game mode? + + cPacketizer Pkt(*this, 0x37); + Pkt.WriteVarInt(statCount); // TODO 2014-05-11 xdot: Optimization: Send "dirty" statistics only + + for (size_t i = 0; i < (size_t)statCount; ++i) + { + StatValue Value = a_Manager.GetValue((eStatistic) i); + const AString & StatName = cStatInfo::GetName((eStatistic) i); + + Pkt.WriteString(StatName); + Pkt.WriteVarInt(Value); + } +} + + + + + void cProtocol172::SendTabCompletionResults(const AStringVector & a_Results) { ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x3a); // Tab-Complete packet - Pkt.WriteVarInt(a_Results.size()); + Pkt.WriteVarInt((int)a_Results.size()); for (AStringVector::const_iterator itr = a_Results.begin(), end = a_Results.end(); itr != end; ++itr) { @@ -1259,10 +1326,10 @@ void cProtocol172::SendUpdateBlockEntity(cBlockEntity & a_BlockEntity) Byte Action = 0; switch (a_BlockEntity.GetBlockType()) { - case E_BLOCK_MOB_SPAWNER: Action = 1; break; // Update mob spawner spinny mob thing - case E_BLOCK_COMMAND_BLOCK: Action = 2; break; // Update command block text - case E_BLOCK_HEAD: Action = 4; break; // Update Mobhead entity - case E_BLOCK_FLOWER_POT: Action = 5; break; // Update flower pot + case E_BLOCK_MOB_SPAWNER: Action = 1; break; // Update mob spawner spinny mob thing + case E_BLOCK_COMMAND_BLOCK: Action = 2; break; // Update command block text + case E_BLOCK_HEAD: Action = 4; break; // Update Mobhead entity + case E_BLOCK_FLOWER_POT: Action = 5; break; // Update flower pot default: ASSERT(!"Unhandled or unimplemented BlockEntity update request!"); break; } Pkt.WriteByte(Action); @@ -1382,7 +1449,7 @@ void cProtocol172::SendWindowOpen(const cWindow & a_Window) -void cProtocol172::SendWindowProperty(const cWindow & a_Window, short a_Property, short a_Value) +void cProtocol172::SendWindowProperty(const cWindow & a_Window, int a_Property, int a_Value) { ASSERT(m_State == 3); // In game mode? @@ -1520,7 +1587,7 @@ void cProtocol172::AddReceivedData(const char * a_Data, size_t a_Size) ASSERT(!"Read wrong number of bytes!"); m_Client->PacketError(PacketType); } - } // for(ever) + } // for (ever) // Log any leftover bytes into the logfile: if (g_ShouldLogCommIn && (m_ReceivedData.GetReadableSpace() > 0)) @@ -1589,7 +1656,7 @@ bool cProtocol172::HandlePacket(cByteBuffer & a_ByteBuffer, UInt32 a_PacketType) 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 0x0f: // Confirm transaction - not used in MCS case 0x10: HandlePacketCreativeInventoryAction(a_ByteBuffer); return true; case 0x11: HandlePacketEnchantItem (a_ByteBuffer); return true; case 0x12: HandlePacketUpdateSign (a_ByteBuffer); return true; @@ -1645,16 +1712,16 @@ void cProtocol172::HandlePacketStatusPing(cByteBuffer & a_ByteBuffer) void cProtocol172::HandlePacketStatusRequest(cByteBuffer & a_ByteBuffer) { // Send the response: - AString Response = "{\"version\":{\"name\":\"1.7.2\",\"protocol\":4},\"players\":{"; + AString Response = "{\"version\":{\"name\":\"1.7.2\", \"protocol\":4}, \"players\":{"; cServer * Server = cRoot::Get()->GetServer(); - AppendPrintf(Response, "\"max\":%u,\"online\":%u,\"sample\":[]},", + AppendPrintf(Response, "\"max\":%u, \"online\":%u, \"sample\":[]},", Server->GetMaxPlayers(), Server->GetNumPlayers() ); AppendPrintf(Response, "\"description\":{\"text\":\"%s\"},", Server->GetDescription().c_str() ); - AppendPrintf(Response, "\"favicon\":\"data:image/png;base64,%s\"", + AppendPrintf(Response, "\"favicon\": \"data:image/png;base64,%s\"", Server->GetFaviconData().c_str() ); Response.append("}"); @@ -1690,7 +1757,7 @@ void cProtocol172::HandlePacketLoginEncryptionResponse(cByteBuffer & a_ByteBuffe } // Decrypt EncNonce using privkey - cRSAPrivateKey & rsaDecryptor = cRoot::Get()->GetServer()->GetPrivateKey(); + cRsaPrivateKey & rsaDecryptor = cRoot::Get()->GetServer()->GetPrivateKey(); Int32 DecryptedNonce[MAX_ENC_LEN / sizeof(Int32)]; int res = rsaDecryptor.Decrypt((const Byte *)EncNonce.data(), EncNonce.size(), (Byte *)DecryptedNonce, sizeof(DecryptedNonce)); if (res != 4) @@ -1742,7 +1809,7 @@ void cProtocol172::HandlePacketLoginStart(cByteBuffer & a_ByteBuffer) cPacketizer Pkt(*this, 0x01); Pkt.WriteString(Server->GetServerID()); const AString & PubKeyDer = Server->GetPublicKeyDER(); - Pkt.WriteShort(PubKeyDer.size()); + Pkt.WriteShort((short)PubKeyDer.size()); Pkt.WriteBuf(PubKeyDer.data(), PubKeyDer.size()); Pkt.WriteShort(4); Pkt.WriteInt((int)(intptr_t)this); // Using 'this' as the cryptographic nonce, so that we don't have to generate one each time :) @@ -1842,13 +1909,15 @@ void cProtocol172::HandlePacketClientStatus(cByteBuffer & a_ByteBuffer) case 1: { // Request stats - // TODO + const cStatManager & Manager = m_Client->GetPlayer()->GetStatManager(); + SendStatistics(Manager); + break; } case 2: { // Open Inventory achievement - // TODO + m_Client->GetPlayer()->AwardAchievement(achOpenInv); break; } } @@ -1881,11 +1950,11 @@ void cProtocol172::HandlePacketEntityAction(cByteBuffer & a_ByteBuffer) switch (Action) { - case 1: m_Client->HandleEntityCrouch(PlayerID, true); break; // Crouch - case 2: m_Client->HandleEntityCrouch(PlayerID, false); break; // Uncrouch - case 3: m_Client->HandleEntityLeaveBed(PlayerID); break; // Leave Bed - case 4: m_Client->HandleEntitySprinting(PlayerID, true); break; // Start sprinting - case 5: m_Client->HandleEntitySprinting(PlayerID, false); break; // Stop sprinting + case 1: m_Client->HandleEntityCrouch(PlayerID, true); break; // Crouch + case 2: m_Client->HandleEntityCrouch(PlayerID, false); break; // Uncrouch + case 3: m_Client->HandleEntityLeaveBed(PlayerID); break; // Leave Bed + case 4: m_Client->HandleEntitySprinting(PlayerID, true); break; // Start sprinting + case 5: m_Client->HandleEntitySprinting(PlayerID, false); break; // Stop sprinting } } @@ -2137,7 +2206,7 @@ void cProtocol172::WritePacket(cByteBuffer & a_Packet) cCSLock Lock(m_CSPacket); AString Pkt; a_Packet.ReadAll(Pkt); - WriteVarInt(Pkt.size()); + WriteVarInt((UInt32)Pkt.size()); SendData(Pkt.data(), Pkt.size()); Flush(); } @@ -2242,7 +2311,7 @@ void cProtocol172::ParseItemMetadata(cItem & a_Item, const AString & a_Metadata) { case TAG_List: { - if ((TagName == "ench") || (TagName == "StoredEnchantments")) // Enchantments tags + if ((TagName == "ench") || (TagName == "StoredEnchantments")) // Enchantments tags { EnchantmentSerializer::ParseFromNBT(a_Item.m_Enchantments, NBT, tag); } @@ -2250,21 +2319,21 @@ void cProtocol172::ParseItemMetadata(cItem & a_Item, const AString & a_Metadata) } case TAG_Compound: { - if (TagName == "display") // Custom name and lore tag + if (TagName == "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 + 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 + 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 + 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 ;) + AppendPrintf(Lore, "%s`", NBT.GetString(loretag).c_str()); // Append the lore with a grave accent/backtick, used internally by MCS to display a new line in the client; don't forget to c_str ;) } a_Item.m_Lore = Lore; @@ -2277,6 +2346,13 @@ void cProtocol172::ParseItemMetadata(cItem & a_Item, const AString & a_Metadata) } break; } + case TAG_Int: + { + if (TagName == "RepairCost") + { + a_Item.m_RepairCost = NBT.GetInt(tag); + } + } default: LOGD("Unimplemented NBT data when parsing!"); break; } } @@ -2293,7 +2369,7 @@ void cProtocol172::StartEncryption(const Byte * a_Key) m_IsEncrypted = true; // Prepare the m_AuthServerID: - cSHA1Checksum Checksum; + cSha1Checksum Checksum; cServer * Server = cRoot::Get()->GetServer(); const AString & ServerID = Server->GetServerID(); Checksum.Update((const Byte *)ServerID.c_str(), ServerID.length()); @@ -2301,7 +2377,7 @@ void cProtocol172::StartEncryption(const Byte * a_Key) Checksum.Update((const Byte *)Server->GetPublicKeyDER().data(), Server->GetPublicKeyDER().size()); Byte Digest[20]; Checksum.Finalize(Digest); - cSHA1Checksum::DigestToJava(Digest, m_AuthServerID); + cSha1Checksum::DigestToJava(Digest, m_AuthServerID); } @@ -2387,7 +2463,7 @@ void cProtocol172::AddChatPartStyle(Json::Value & a_Value, const AString & a_Par -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// // cProtocol172::cPacketizer: cProtocol172::cPacketizer::~cPacketizer() @@ -2395,7 +2471,7 @@ cProtocol172::cPacketizer::~cPacketizer() AString DataToSend; // Send the packet length - UInt32 PacketLen = m_Out.GetUsedSpace(); + UInt32 PacketLen = (UInt32)m_Out.GetUsedSpace(); m_Protocol.m_OutPacketLenBuffer.WriteVarInt(PacketLen); m_Protocol.m_OutPacketLenBuffer.ReadAll(DataToSend); m_Protocol.SendData(DataToSend.data(), DataToSend.size()); @@ -2450,10 +2526,14 @@ void cProtocol172::cPacketizer::WriteItem(const cItem & a_Item) // Send the enchantments and custom names: cFastNBTWriter Writer; + if (a_Item.m_RepairCost != 0) + { + Writer.AddInt("RepairCost", a_Item.m_RepairCost); + } if (!a_Item.m_Enchantments.IsEmpty()) { const char * TagName = (a_Item.m_ItemType == E_ITEM_BOOK) ? "StoredEnchantments" : "ench"; - EnchantmentSerializer::WriteToNBTCompound(a_Item.m_Enchantments,Writer, TagName); + EnchantmentSerializer::WriteToNBTCompound(a_Item.m_Enchantments, Writer, TagName); } if (!a_Item.IsBothNameAndLoreEmpty()) { @@ -2488,7 +2568,7 @@ void cProtocol172::cPacketizer::WriteItem(const cItem & a_Item) Writer.Finish(); AString Compressed; CompressStringGZIP(Writer.GetResult().data(), Writer.GetResult().size(), Compressed); - WriteShort(Compressed.size()); + WriteShort((short)Compressed.size()); WriteBuf(Compressed.data(), Compressed.size()); } @@ -2505,7 +2585,7 @@ void cProtocol172::cPacketizer::WriteBlockEntity(const cBlockEntity & a_BlockEnt { cCommandBlockEntity & CommandBlockEntity = (cCommandBlockEntity &)a_BlockEntity; - Writer.AddByte("TrackOutput", 1); // Neither I nor the MC wiki has any idea about this + Writer.AddByte("TrackOutput", 1); // Neither I nor the MC wiki has any idea about this Writer.AddInt("SuccessCount", CommandBlockEntity.GetResult()); Writer.AddInt("x", CommandBlockEntity.GetPosX()); Writer.AddInt("y", CommandBlockEntity.GetPosY()); @@ -2515,7 +2595,7 @@ void cProtocol172::cPacketizer::WriteBlockEntity(const cBlockEntity & a_BlockEnt // For a command block, this would be the 'name' prepended to anything it outputs into global chat // MCS doesn't have this, so just leave it @ '@'. (geddit?) Writer.AddString("CustomName", "@"); - Writer.AddString("id", "Control"); // "Tile Entity ID" - MC wiki; vanilla server always seems to send this though + Writer.AddString("id", "Control"); // "Tile Entity ID" - MC wiki; vanilla server always seems to send this though if (!CommandBlockEntity.GetLastOutput().empty()) { @@ -2536,7 +2616,7 @@ void cProtocol172::cPacketizer::WriteBlockEntity(const cBlockEntity & a_BlockEnt Writer.AddByte("SkullType", MobHeadEntity.GetType() & 0xFF); Writer.AddByte("Rot", MobHeadEntity.GetRotation() & 0xFF); Writer.AddString("ExtraType", MobHeadEntity.GetOwner().c_str()); - Writer.AddString("id", "Skull"); // "Tile Entity ID" - MC wiki; vanilla server always seems to send this though + Writer.AddString("id", "Skull"); // "Tile Entity ID" - MC wiki; vanilla server always seems to send this though break; } case E_BLOCK_FLOWER_POT: @@ -2548,7 +2628,7 @@ void cProtocol172::cPacketizer::WriteBlockEntity(const cBlockEntity & a_BlockEnt Writer.AddInt("z", FlowerPotEntity.GetPosZ()); Writer.AddInt("Item", (Int32) FlowerPotEntity.GetItem().m_ItemType); Writer.AddInt("Data", (Int32) FlowerPotEntity.GetItem().m_ItemDamage); - Writer.AddString("id", "FlowerPot"); // "Tile Entity ID" - MC wiki; vanilla server always seems to send this though + Writer.AddString("id", "FlowerPot"); // "Tile Entity ID" - MC wiki; vanilla server always seems to send this though break; } default: break; @@ -2558,7 +2638,7 @@ void cProtocol172::cPacketizer::WriteBlockEntity(const cBlockEntity & a_BlockEnt AString Compressed; CompressStringGZIP(Writer.GetResult().data(), Writer.GetResult().size(), Compressed); - WriteShort(Compressed.size()); + WriteShort((short)Compressed.size()); WriteBuf(Compressed.data(), Compressed.size()); } @@ -2627,15 +2707,16 @@ void cProtocol172::cPacketizer::WriteEntityMetadata(const cEntity & a_Entity) // The following expression makes Minecarts shake more with less health or higher damage taken // It gets half the maximum health, and takes it away from the current health minus the half health: - /* Health: 5 | 3 - (5 - 3) = 1 (shake power) - Health: 3 | 3 - (3 - 3) = 3 - Health: 1 | 3 - (1 - 3) = 5 + /* + Health: 5 | 3 - (5 - 3) = 1 (shake power) + Health: 3 | 3 - (3 - 3) = 3 + Health: 1 | 3 - (1 - 3) = 5 */ WriteInt((((a_Entity.GetMaxHealth() / 2) - (a_Entity.GetHealth() - (a_Entity.GetMaxHealth() / 2))) * ((const cMinecart &)a_Entity).LastDamage()) * 4); WriteByte(0x52); - WriteInt(1); // Shaking direction, doesn't seem to affect anything + 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 + WriteFloat((float)(((const cMinecart &)a_Entity).LastDamage() + 10)); // Damage taken / shake effect multiplyer if (((cMinecart &)a_Entity).GetPayload() == cMinecart::mpNone) { @@ -2823,9 +2904,9 @@ void cProtocol172::cPacketizer::WriteMobMetadata(const cMonster & a_Mob) case cMonster::mtWither: { - WriteByte(0x54); // Int at index 20 - WriteInt(((const cWither &)a_Mob).GetNumInvulnerableTicks()); - WriteByte(0x66); // Float at index 6 + WriteByte(0x54); // Int at index 20 + WriteInt(((const cWither &)a_Mob).GetWitherInvulnerableTicks()); + WriteByte(0x66); // Float at index 6 WriteFloat((float)(a_Mob.GetHealth())); break; } @@ -2905,7 +2986,7 @@ void cProtocol172::cPacketizer::WriteEntityProperties(const cEntity & a_Entity) return; } - //const cMonster & Mob = (const cMonster &)a_Entity; + // const cMonster & Mob = (const cMonster &)a_Entity; // TODO: Send properties and modifiers based on the mob type @@ -2916,7 +2997,7 @@ void cProtocol172::cPacketizer::WriteEntityProperties(const cEntity & a_Entity) -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// // cProtocol176: cProtocol176::cProtocol176(cClientHandle * a_Client, const AString &a_ServerAddress, UInt16 a_ServerPort, UInt32 a_State) : @@ -2935,7 +3016,18 @@ void cProtocol176::SendPlayerSpawn(const cPlayer & a_Player) Pkt.WriteVarInt(a_Player.GetUniqueID()); Pkt.WriteString(a_Player.GetClientHandle()->GetUUID()); Pkt.WriteString(a_Player.GetName()); - Pkt.WriteVarInt(0); // We have no data to send here + + const Json::Value & Properties = m_Client->GetProperties(); + const Json::Value::const_iterator End = Properties.end(); + Pkt.WriteVarInt(Properties.size()); + + for (Json::Value::iterator itr = Properties.begin(); itr != End; ++itr) + { + Pkt.WriteString(((Json::Value)*itr).get("name", "").toStyledString()); + Pkt.WriteString(((Json::Value)*itr).get("value", "").toStyledString()); + Pkt.WriteString(((Json::Value)*itr).get("signature", "").toStyledString()); + } + Pkt.WriteFPInt(a_Player.GetPosX()); Pkt.WriteFPInt(a_Player.GetPosY()); Pkt.WriteFPInt(a_Player.GetPosZ()); @@ -2955,15 +3047,15 @@ void cProtocol176::SendPlayerSpawn(const cPlayer & a_Player) void cProtocol176::HandlePacketStatusRequest(cByteBuffer & a_ByteBuffer) { // Send the response: - AString Response = "{\"version\":{\"name\":\"1.7.6\",\"protocol\":5},\"players\":{"; - AppendPrintf(Response, "\"max\":%u,\"online\":%u,\"sample\":[]},", + AString Response = "{\"version\": {\"name\": \"1.7.6\", \"protocol\":5}, \"players\": {"; + AppendPrintf(Response, "\"max\": %u, \"online\": %u, \"sample\": []},", cRoot::Get()->GetServer()->GetMaxPlayers(), cRoot::Get()->GetServer()->GetNumPlayers() ); - AppendPrintf(Response, "\"description\":{\"text\":\"%s\"},", + AppendPrintf(Response, "\"description\": {\"text\": \"%s\"},", cRoot::Get()->GetServer()->GetDescription().c_str() ); - AppendPrintf(Response, "\"favicon\":\"data:image/png;base64,%s\"", + AppendPrintf(Response, "\"favicon\": \"data:image/png;base64,%s\"", cRoot::Get()->GetServer()->GetFaviconData().c_str() ); Response.append("}"); |