diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp index 92ed2013f..cb9b83e26 100644 --- a/src/ClientHandle.cpp +++ b/src/ClientHandle.cpp @@ -2929,6 +2929,15 @@ void cClientHandle::SendExperienceOrb(const cExpOrb & a_ExpOrb) +void cClientHandle::SendResourcePack(const AString & a_ResourcePackUrl) +{ + m_Protocol->SendResourcePack(a_ResourcePackUrl); +} + + + + + void cClientHandle::SendScoreboardObjective(const AString & a_Name, const AString & a_DisplayName, Byte a_Mode) { m_Protocol->SendScoreboardObjective(a_Name, a_DisplayName, a_Mode); diff --git a/src/ClientHandle.h b/src/ClientHandle.h index 00f318191..d39e76db8 100644 --- a/src/ClientHandle.h +++ b/src/ClientHandle.h @@ -197,6 +197,7 @@ public: // tolua_export void SendPlayerSpawn (const cPlayer & a_Player); void SendPluginMessage (const AString & a_Channel, const AString & a_Message); // Exported in ManualBindings.cpp void SendRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID); + void SendResourcePack (const AString & a_ResourcePackUrl); void SendResetTitle (void); // tolua_export void SendRespawn (eDimension a_Dimension, bool a_ShouldIgnoreDimensionChecks = false); void SendScoreUpdate (const AString & a_Objective, const AString & a_Player, cObjective::Score a_Score, Byte a_Mode); diff --git a/src/Protocol/Packetizer.cpp b/src/Protocol/Packetizer.cpp index d477148bf..6afea8a36 100644 --- a/src/Protocol/Packetizer.cpp +++ b/src/Protocol/Packetizer.cpp @@ -101,6 +101,7 @@ AString cPacketizer::PacketTypeToStr(cProtocol::ePacketType a_PacketType) case cProtocol::pktPlayerMoveLook: return "pktPlayerMoveLook"; case cProtocol::pktPluginMessage: return "pktPluginMessage"; case cProtocol::pktRemoveEntityEffect: return "pktRemoveEntityEffect"; + case cProtocol::pktResourcePack: return "pktResourcePack"; case cProtocol::pktRespawn: return "pktRespawn"; case cProtocol::pktScoreboardObjective: return "pktScoreboardObjective"; case cProtocol::pktSpawnObject: return "pktSpawnObject"; diff --git a/src/Protocol/Protocol.h b/src/Protocol/Protocol.h index cad007f5c..8622ef8e9 100644 --- a/src/Protocol/Protocol.h +++ b/src/Protocol/Protocol.h @@ -112,6 +112,7 @@ public: pktPlayerMoveLook, pktPluginMessage, pktRemoveEntityEffect, + pktResourcePack, pktRespawn, pktScoreboardObjective, pktSpawnObject, @@ -201,6 +202,7 @@ public: virtual void SendPluginMessage (const AString & a_Channel, const AString & a_Message) = 0; virtual void SendRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID) = 0; virtual void SendResetTitle (void) = 0; + virtual void SendResourcePack (const AString & a_ResourcePackUrl) = 0; virtual void SendRespawn (eDimension a_Dimension) = 0; virtual void SendExperience (void) = 0; virtual void SendExperienceOrb (const cExpOrb & a_ExpOrb) = 0; diff --git a/src/Protocol/ProtocolRecognizer.cpp b/src/Protocol/ProtocolRecognizer.cpp index a572ea9c2..49bab8dfd 100644 --- a/src/Protocol/ProtocolRecognizer.cpp +++ b/src/Protocol/ProtocolRecognizer.cpp @@ -700,6 +700,16 @@ void cProtocolRecognizer::SendResetTitle(void) +void cProtocolRecognizer::SendResourcePack(const AString & a_ResourcePackUrl) +{ + ASSERT(m_Protocol != nullptr); + m_Protocol->SendResourcePack(a_ResourcePackUrl); +} + + + + + void cProtocolRecognizer::SendRespawn(eDimension a_Dimension) { ASSERT(m_Protocol != nullptr); diff --git a/src/Protocol/ProtocolRecognizer.h b/src/Protocol/ProtocolRecognizer.h index da87ba6bd..f1fe59367 100644 --- a/src/Protocol/ProtocolRecognizer.h +++ b/src/Protocol/ProtocolRecognizer.h @@ -104,6 +104,7 @@ public: virtual void SendPluginMessage (const AString & a_Channel, const AString & a_Message) override; virtual void SendRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID) override; virtual void SendResetTitle (void) override; + virtual void SendResourcePack (const AString & a_ResourcePackUrl) override; virtual void SendRespawn (eDimension a_Dimension) override; virtual void SendExperience (void) override; virtual void SendExperienceOrb (const cExpOrb & a_ExpOrb) override; diff --git a/src/Protocol/Protocol_1_10.cpp b/src/Protocol/Protocol_1_10.cpp index 47d27c461..8a23ec09d 100644 --- a/src/Protocol/Protocol_1_10.cpp +++ b/src/Protocol/Protocol_1_10.cpp @@ -45,6 +45,19 @@ Implements the 1.10 protocol classes: +#define HANDLE_READ(ByteBuf, Proc, Type, Var) \ + Type Var; \ + do { \ + if (!ByteBuf.Proc(Var))\ + {\ + return;\ + } \ + } while (false) + + + + + // The disabled error is intended, since the Metadata have overlapping indexes // based on the type of the Entity. // @@ -318,6 +331,15 @@ void cProtocol_1_10_0::SendSoundEffect(const AString & a_SoundName, double a_X, +void cProtocol_1_10_0::HandlePacketResourcePackStatus(cByteBuffer & a_ByteBuffer) +{ + HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, Status); +} + + + + + void cProtocol_1_10_0::HandlePacketStatusRequest(cByteBuffer & a_ByteBuffer) { cServer * Server = cRoot::Get()->GetServer(); diff --git a/src/Protocol/Protocol_1_10.h b/src/Protocol/Protocol_1_10.h index 003a4c9b9..8b1f58364 100644 --- a/src/Protocol/Protocol_1_10.h +++ b/src/Protocol/Protocol_1_10.h @@ -29,6 +29,7 @@ public: virtual void SendSoundEffect(const AString & a_SoundName, double a_X, double a_Y, double a_Z, float a_Volume, float a_Pitch) override; + virtual void HandlePacketResourcePackStatus(cByteBuffer & a_ByteBuffer) override; virtual void HandlePacketStatusRequest(cByteBuffer & a_ByteBuffer) override; protected: diff --git a/src/Protocol/Protocol_1_12.cpp b/src/Protocol/Protocol_1_12.cpp index ee2d7064c..01bbf8104 100644 --- a/src/Protocol/Protocol_1_12.cpp +++ b/src/Protocol/Protocol_1_12.cpp @@ -986,6 +986,7 @@ UInt32 cProtocol_1_12::GetPacketID(cProtocol::ePacketType a_Packet) case pktLeashEntity: return 0x3c; case pktPlayerMaxSpeed: return 0x4d; case pktRemoveEntityEffect: return 0x32; + case pktResourcePack: return 0x33; case pktRespawn: return 0x34; case pktScoreboardObjective: return 0x41; case pktSpawnPosition: return 0x45; @@ -1079,7 +1080,7 @@ bool cProtocol_1_12::HandlePacket(cByteBuffer & a_ByteBuffer, UInt32 a_PacketTyp case 0x15: HandlePacketEntityAction(a_ByteBuffer); return true; case 0x16: HandlePacketSteerVehicle(a_ByteBuffer); return true; case 0x17: HandlePacketCraftingBookData(a_ByteBuffer); return true; - case 0x18: break; // Resource pack status - not yet implemented + case 0x18: HandlePacketResourcePackStatus(a_ByteBuffer); return true; case 0x19: HandlePacketAdvancementTab(a_ByteBuffer); return true; case 0x1a: HandlePacketSlotSelect(a_ByteBuffer); return true; case 0x1b: HandlePacketCreativeInventoryAction(a_ByteBuffer); return true; @@ -1151,6 +1152,7 @@ UInt32 cProtocol_1_12_1::GetPacketID(ePacketType a_Packet) case pktPlayerMaxSpeed: return 0x4e; case pktPlayerMoveLook: return 0x2f; case pktRemoveEntityEffect: return 0x33; + case pktResourcePack: return 0x34; case pktRespawn: return 0x35; case pktScoreboardObjective: return 0x42; case pktSpawnPosition: return 0x46; @@ -1268,7 +1270,7 @@ bool cProtocol_1_12_1::HandlePacket(cByteBuffer & a_ByteBuffer, UInt32 a_PacketT case 0x15: HandlePacketEntityAction(a_ByteBuffer); return true; case 0x16: HandlePacketSteerVehicle(a_ByteBuffer); return true; case 0x17: HandlePacketCraftingBookData(a_ByteBuffer); return true; - case 0x18: break; // Resource pack status - not yet implemented + case 0x18: HandlePacketResourcePackStatus(a_ByteBuffer); return true; case 0x19: HandlePacketAdvancementTab(a_ByteBuffer); return true; case 0x1a: HandlePacketSlotSelect(a_ByteBuffer); return true; case 0x1b: HandlePacketCreativeInventoryAction(a_ByteBuffer); return true; diff --git a/src/Protocol/Protocol_1_8.cpp b/src/Protocol/Protocol_1_8.cpp index 668ca7542..1b3c261f5 100644 --- a/src/Protocol/Protocol_1_8.cpp +++ b/src/Protocol/Protocol_1_8.cpp @@ -1147,6 +1147,25 @@ void cProtocol_1_8_0::SendResetTitle(void) +void cProtocol_1_8_0::SendResourcePack(const AString & a_ResourcePackUrl) +{ + cPacketizer Pkt(*this, pktResourcePack); + + cSha1Checksum Checksum; + Checksum.Update(reinterpret_cast(a_ResourcePackUrl.c_str()), a_ResourcePackUrl.size()); + Byte Digest[20]; + Checksum.Finalize(Digest); + AString Sha1Output; + cSha1Checksum::DigestToHex(Digest, Sha1Output); + + Pkt.WriteString(a_ResourcePackUrl); + Pkt.WriteString(Sha1Output); +} + + + + + void cProtocol_1_8_0::SendRespawn(eDimension a_Dimension) { @@ -2152,6 +2171,7 @@ UInt32 cProtocol_1_8_0::GetPacketID(ePacketType a_PacketType) case pktPlayerMoveLook: return 0x08; case pktPluginMessage: return 0x3f; case pktRemoveEntityEffect: return 0x1e; + case pktResourcePack: return 0x48; case pktRespawn: return 0x07; case pktScoreboardObjective: return 0x3b; case pktSoundEffect: return 0x29; @@ -2250,6 +2270,7 @@ bool cProtocol_1_8_0::HandlePacket(cByteBuffer & a_ByteBuffer, UInt32 a_PacketTy case 0x16: HandlePacketClientStatus (a_ByteBuffer); return true; case 0x17: HandlePacketPluginMessage (a_ByteBuffer); return true; case 0x18: HandlePacketSpectate (a_ByteBuffer); return true; + case 0x19: HandlePacketResourcePackStatus (a_ByteBuffer); return true; } break; } @@ -2708,6 +2729,16 @@ void cProtocol_1_8_0::HandlePacketPluginMessage(cByteBuffer & a_ByteBuffer) +void cProtocol_1_8_0::HandlePacketResourcePackStatus(cByteBuffer & a_ByteBuffer) +{ + HANDLE_READ(a_ByteBuffer, ReadVarUTF8String, AString, Hash); + HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, Status); +} + + + + + void cProtocol_1_8_0::HandlePacketSlotSelect(cByteBuffer & a_ByteBuffer) { HANDLE_READ(a_ByteBuffer, ReadBEInt16, Int16, SlotNum); diff --git a/src/Protocol/Protocol_1_8.h b/src/Protocol/Protocol_1_8.h index 527db15b7..e8e0f01e1 100644 --- a/src/Protocol/Protocol_1_8.h +++ b/src/Protocol/Protocol_1_8.h @@ -91,6 +91,7 @@ public: virtual void SendPluginMessage (const AString & a_Channel, const AString & a_Message) override; virtual void SendRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID) override; virtual void SendResetTitle (void) override; + virtual void SendResourcePack (const AString & a_ResourcePackUrl) override; virtual void SendRespawn (eDimension a_Dimension) override; virtual void SendSoundEffect (const AString & a_SoundName, double a_X, double a_Y, double a_Z, float a_Volume, float a_Pitch) override; virtual void SendExperience (void) override; @@ -197,6 +198,7 @@ protected: void HandlePacketPlayerPos (cByteBuffer & a_ByteBuffer); void HandlePacketPlayerPosLook (cByteBuffer & a_ByteBuffer); void HandlePacketPluginMessage (cByteBuffer & a_ByteBuffer); + void HandlePacketResourcePackStatus (cByteBuffer & a_ByteBuffer); void HandlePacketSlotSelect (cByteBuffer & a_ByteBuffer); void HandlePacketSpectate (cByteBuffer & a_ByteBuffer); void HandlePacketSteerVehicle (cByteBuffer & a_ByteBuffer); diff --git a/src/Protocol/Protocol_1_9.cpp b/src/Protocol/Protocol_1_9.cpp index b6dba378b..9f786b02d 100644 --- a/src/Protocol/Protocol_1_9.cpp +++ b/src/Protocol/Protocol_1_9.cpp @@ -1233,6 +1233,25 @@ void cProtocol_1_9_0::SendResetTitle(void) +void cProtocol_1_9_0::SendResourcePack(const AString & a_ResourcePackUrl) +{ + cPacketizer Pkt(*this, pktResourcePack); + + cSha1Checksum Checksum; + Checksum.Update(reinterpret_cast(a_ResourcePackUrl.c_str()), a_ResourcePackUrl.size()); + Byte Digest[20]; + Checksum.Finalize(Digest); + AString Sha1Output; + cSha1Checksum::DigestToHex(Digest, Sha1Output); + + Pkt.WriteString(a_ResourcePackUrl); + Pkt.WriteString(Sha1Output); +} + + + + + void cProtocol_1_9_0::SendRespawn(eDimension a_Dimension) { cPacketizer Pkt(*this, pktRespawn); @@ -2209,6 +2228,7 @@ UInt32 cProtocol_1_9_0::GetPacketID(cProtocol::ePacketType a_Packet) case pktPlayerMoveLook: return 0x2e; case pktPluginMessage: return 0x18; case pktRemoveEntityEffect: return 0x31; + case pktResourcePack: return 0x32; case pktRespawn: return 0x33; case pktScoreboardObjective: return 0x3f; case pktSpawnExperienceOrb: return 0x01; @@ -2299,7 +2319,7 @@ bool cProtocol_1_9_0::HandlePacket(cByteBuffer & a_ByteBuffer, UInt32 a_PacketTy case 0x13: HandlePacketBlockDig (a_ByteBuffer); return true; case 0x14: HandlePacketEntityAction (a_ByteBuffer); return true; case 0x15: HandlePacketSteerVehicle (a_ByteBuffer); return true; - case 0x16: break; // Resource pack status - not yet implemented + case 0x16: HandlePacketResourcePackStatus (a_ByteBuffer); return true; case 0x17: HandlePacketSlotSelect (a_ByteBuffer); return true; case 0x18: HandlePacketCreativeInventoryAction(a_ByteBuffer); return true; case 0x19: HandlePacketUpdateSign (a_ByteBuffer); return true; @@ -2804,6 +2824,16 @@ void cProtocol_1_9_0::HandlePacketPluginMessage(cByteBuffer & a_ByteBuffer) +void cProtocol_1_9_0::HandlePacketResourcePackStatus(cByteBuffer & a_ByteBuffer) +{ + HANDLE_READ(a_ByteBuffer, ReadVarUTF8String, AString, Hash); + HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, Status); +} + + + + + void cProtocol_1_9_0::HandlePacketSlotSelect(cByteBuffer & a_ByteBuffer) { HANDLE_READ(a_ByteBuffer, ReadBEInt16, Int16, SlotNum); diff --git a/src/Protocol/Protocol_1_9.h b/src/Protocol/Protocol_1_9.h index b6b4ddffa..64619ab11 100644 --- a/src/Protocol/Protocol_1_9.h +++ b/src/Protocol/Protocol_1_9.h @@ -99,6 +99,7 @@ public: virtual void SendPluginMessage (const AString & a_Channel, const AString & a_Message) override; virtual void SendRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID) override; virtual void SendResetTitle (void) override; + virtual void SendResourcePack (const AString & a_ResourcePackUrl) override; virtual void SendRespawn (eDimension a_Dimension) override; virtual void SendSoundEffect (const AString & a_SoundName, double a_X, double a_Y, double a_Z, float a_Volume, float a_Pitch) override; virtual void SendScoreboardObjective (const AString & a_Name, const AString & a_DisplayName, Byte a_Mode) override; @@ -208,6 +209,7 @@ protected: virtual void HandlePacketPlayerPos (cByteBuffer & a_ByteBuffer); virtual void HandlePacketPlayerPosLook (cByteBuffer & a_ByteBuffer); virtual void HandlePacketPluginMessage (cByteBuffer & a_ByteBuffer); + virtual void HandlePacketResourcePackStatus (cByteBuffer & a_ByteBuffer); virtual void HandlePacketSlotSelect (cByteBuffer & a_ByteBuffer); virtual void HandlePacketSteerVehicle (cByteBuffer & a_ByteBuffer); virtual void HandlePacketSpectate (cByteBuffer & a_ByteBuffer); diff --git a/src/Server.cpp b/src/Server.cpp index 65ce3301c..fcafa5713 100644 --- a/src/Server.cpp +++ b/src/Server.cpp @@ -170,6 +170,7 @@ bool cServer::InitServer(cSettingsRepositoryInterface & a_Settings, bool a_Shoul m_MaxPlayers = static_cast(a_Settings.GetValueSetI("Server", "MaxPlayers", 100)); m_bIsHardcore = a_Settings.GetValueSetB("Server", "HardcoreEnabled", false); m_bAllowMultiLogin = a_Settings.GetValueSetB("Server", "AllowMultiLogin", false); + m_ResourcePackUrl = a_Settings.GetValueSet("Server", "ResourcePackUrl", ""); m_FaviconData = Base64Encode(cFile::ReadWholeFile(FILE_IO_PREFIX + AString("favicon.png"))); // Will return empty string if file nonexistant; client doesn't mind diff --git a/src/Server.h b/src/Server.h index ab821c102..28342cfb6 100644 --- a/src/Server.h +++ b/src/Server.h @@ -94,6 +94,8 @@ public: // tolua_end + const AString & GetResourcePackUrl(void) { return m_ResourcePackUrl; } + bool Start(void); bool Command(cClientHandle & a_Client, AString & a_Cmd); @@ -214,6 +216,7 @@ private: AString m_FaviconData; size_t m_MaxPlayers; bool m_bIsHardcore; + AString m_ResourcePackUrl; /** Map of protocol version to Forge mods (map of ModName -> ModVersionString) */ std::map m_ForgeModsByVersion; diff --git a/src/World.cpp b/src/World.cpp index 10cfc2047..ee521f254 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -3561,6 +3561,13 @@ void cWorld::AddQueuedPlayers(void) Client->SendPlayerMoveLook(); Client->SendHealth(); Client->SendWholeInventory(*Player->GetWindow()); + + // Send resource pack + auto ResourcePackUrl = cRoot::Get()->GetServer()->GetResourcePackUrl(); + if (!ResourcePackUrl.empty()) + { + Client->SendResourcePack(ResourcePackUrl); + } } } // for itr - PlayersToAdd[] diff --git a/src/mbedTLS++/Sha1Checksum.cpp b/src/mbedTLS++/Sha1Checksum.cpp index f55df025a..8ed7976ae 100644 --- a/src/mbedTLS++/Sha1Checksum.cpp +++ b/src/mbedTLS++/Sha1Checksum.cpp @@ -85,6 +85,20 @@ void cSha1Checksum::Finalize(cSha1Checksum::Checksum & a_Output) +void cSha1Checksum::DigestToHex(const Checksum & a_Digest, AString & a_Out) +{ + a_Out.clear(); + a_Out.reserve(40); + for (int i = 0; i < 20; i++) + { + AppendPrintf(a_Out, "%x", a_Digest[i]); + } +} + + + + + void cSha1Checksum::DigestToJava(const Checksum & a_Digest, AString & a_Out) { Checksum Digest; diff --git a/src/mbedTLS++/Sha1Checksum.h b/src/mbedTLS++/Sha1Checksum.h index f85f5e8b5..dbe7db567 100644 --- a/src/mbedTLS++/Sha1Checksum.h +++ b/src/mbedTLS++/Sha1Checksum.h @@ -32,10 +32,13 @@ public: /** Returns true if the object is accepts more input data, false if Finalize()-d (need to Restart()) */ bool DoesAcceptInput(void) const { return m_DoesAcceptInput; } + /** Converts a SHA1 digest into hex */ + static void DigestToHex(const Checksum & a_Digest, AString & a_Out); + /** Converts a raw 160-bit SHA1 digest into a Java Hex representation According to http://wiki.vg/Protocol_Encryption */ - static void DigestToJava(const Checksum & a_Digest, AString & a_JavaOut); + static void DigestToJava(const Checksum & a_Digest, AString & a_Out); /** Clears the current context and start a new checksum calculation */ void Restart(void);