// Protocol_1_11.cpp /* Implements the 1.11 protocol classes: - cProtocol_1_11_0 - release 1.11 protocol (#315) (others may be added later in the future for the 1.11 release series) */ #include "Globals.h" #include "Protocol_1_11.h" #include "ProtocolRecognizer.h" #include "Packetizer.h" #include "../Root.h" #include "../Server.h" #include "../ClientHandle.h" #include "../CompositeChat.h" #include "../Bindings/PluginManager.h" #include "../Entities/Player.h" #include "../Mobs/Monster.h" #define HANDLE_READ(ByteBuf, Proc, Type, Var) \ Type Var; \ if (!ByteBuf.Proc(Var))\ {\ return;\ } cProtocol_1_11_0::cProtocol_1_11_0(cClientHandle * a_Client, const AString & a_ServerAddress, UInt16 a_ServerPort, UInt32 a_State) : super(a_Client, a_ServerAddress, a_ServerPort, a_State) { } void cProtocol_1_11_0::SendCollectEntity(const cEntity & a_Entity, const cPlayer & a_Player, int a_Count) { ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x48); // Collect Item packet Pkt.WriteVarInt32(a_Entity.GetUniqueID()); Pkt.WriteVarInt32(a_Player.GetUniqueID()); Pkt.WriteVarInt32(static_cast(a_Count)); } void cProtocol_1_11_0::SendHideTitle(void) { ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x45); // Title packet Pkt.WriteVarInt32(4); // Hide title } void cProtocol_1_11_0::SendResetTitle(void) { ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x45); // Title packet Pkt.WriteVarInt32(5); // Reset title } void cProtocol_1_11_0::SendSpawnMob(const cMonster & a_Mob) { ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x03); // Spawn Mob packet Pkt.WriteVarInt32(a_Mob.GetUniqueID()); // TODO: Bad way to write a UUID, and it's not a true UUID, but this is functional for now. Pkt.WriteBEUInt64(0); Pkt.WriteBEUInt64(a_Mob.GetUniqueID()); Pkt.WriteVarInt32(static_cast(a_Mob.GetMobType())); Pkt.WriteBEDouble(a_Mob.GetPosX()); Pkt.WriteBEDouble(a_Mob.GetPosY()); Pkt.WriteBEDouble(a_Mob.GetPosZ()); Pkt.WriteByteAngle(a_Mob.GetPitch()); Pkt.WriteByteAngle(a_Mob.GetHeadYaw()); Pkt.WriteByteAngle(a_Mob.GetYaw()); Pkt.WriteBEInt16(static_cast(a_Mob.GetSpeedX() * 400)); Pkt.WriteBEInt16(static_cast(a_Mob.GetSpeedY() * 400)); Pkt.WriteBEInt16(static_cast(a_Mob.GetSpeedZ() * 400)); WriteEntityMetadata(Pkt, a_Mob); Pkt.WriteBEUInt8(0xff); // Metadata terminator } void cProtocol_1_11_0::SendTitleTimes(int a_FadeInTicks, int a_DisplayTicks, int a_FadeOutTicks) { ASSERT(m_State == 3); // In game mode? cPacketizer Pkt(*this, 0x45); // Title packet Pkt.WriteVarInt32(3); // Set title display times Pkt.WriteBEInt32(a_FadeInTicks); Pkt.WriteBEInt32(a_DisplayTicks); Pkt.WriteBEInt32(a_FadeOutTicks); } void cProtocol_1_11_0::HandlePacketBlockPlace(cByteBuffer & a_ByteBuffer) { int BlockX, BlockY, BlockZ; if (!a_ByteBuffer.ReadPosition64(BlockX, BlockY, BlockZ)) { return; } HANDLE_READ(a_ByteBuffer, ReadVarInt, Int32, Face); HANDLE_READ(a_ByteBuffer, ReadVarInt, Int32, Hand); HANDLE_READ(a_ByteBuffer, ReadBEFloat, float, CursorX); HANDLE_READ(a_ByteBuffer, ReadBEFloat, float, CursorY); HANDLE_READ(a_ByteBuffer, ReadBEFloat, float, CursorZ); m_Client->HandleRightClick(BlockX, BlockY, BlockZ, FaceIntToBlockFace(Face), FloorC(CursorX * 16), FloorC(CursorY * 16), FloorC(CursorZ * 16), m_Client->GetPlayer()->GetEquippedItem()); } void cProtocol_1_11_0::HandlePacketStatusRequest(cByteBuffer & a_ByteBuffer) { cServer * Server = cRoot::Get()->GetServer(); AString ServerDescription = Server->GetDescription(); int NumPlayers = Server->GetNumPlayers(); int MaxPlayers = Server->GetMaxPlayers(); AString Favicon = Server->GetFaviconData(); cRoot::Get()->GetPluginManager()->CallHookServerPing(*m_Client, ServerDescription, NumPlayers, MaxPlayers, Favicon); // Version: Json::Value Version; Version["name"] = "Cuberite 1.11"; Version["protocol"] = cProtocolRecognizer::PROTO_VERSION_1_11_0; // Players: Json::Value Players; Players["online"] = NumPlayers; Players["max"] = MaxPlayers; // TODO: Add "sample" // Description: Json::Value Description; Description["text"] = ServerDescription.c_str(); // Create the response: Json::Value ResponseValue; ResponseValue["version"] = Version; ResponseValue["players"] = Players; ResponseValue["description"] = Description; if (!Favicon.empty()) { ResponseValue["favicon"] = Printf("data:image/png;base64,%s", Favicon.c_str()); } // Serialize the response into a packet: Json::FastWriter Writer; cPacketizer Pkt(*this, 0x00); // Response packet Pkt.WriteString(Writer.write(ResponseValue)); } cProtocol_1_11_1::cProtocol_1_11_1(cClientHandle * a_Client, const AString & a_ServerAddress, UInt16 a_ServerPort, UInt32 a_State) : super(a_Client, a_ServerAddress, a_ServerPort, a_State) { } void cProtocol_1_11_1::HandlePacketStatusRequest(cByteBuffer & a_ByteBuffer) { cServer * Server = cRoot::Get()->GetServer(); AString ServerDescription = Server->GetDescription(); int NumPlayers = Server->GetNumPlayers(); int MaxPlayers = Server->GetMaxPlayers(); AString Favicon = Server->GetFaviconData(); cRoot::Get()->GetPluginManager()->CallHookServerPing(*m_Client, ServerDescription, NumPlayers, MaxPlayers, Favicon); // Version: Json::Value Version; Version["name"] = "Cuberite 1.11.1"; Version["protocol"] = cProtocolRecognizer::PROTO_VERSION_1_11_1; // Players: Json::Value Players; Players["online"] = NumPlayers; Players["max"] = MaxPlayers; // TODO: Add "sample" // Description: Json::Value Description; Description["text"] = ServerDescription.c_str(); // Create the response: Json::Value ResponseValue; ResponseValue["version"] = Version; ResponseValue["players"] = Players; ResponseValue["description"] = Description; if (!Favicon.empty()) { ResponseValue["favicon"] = Printf("data:image/png;base64,%s", Favicon.c_str()); } // Serialize the response into a packet: Json::FastWriter Writer; cPacketizer Pkt(*this, 0x00); // Response packet Pkt.WriteString(Writer.write(ResponseValue)); }