diff --git a/dGame/Entity.cpp b/dGame/Entity.cpp index 04f42550a..959b180ad 100644 --- a/dGame/Entity.cpp +++ b/dGame/Entity.cpp @@ -1133,6 +1133,12 @@ void Entity::SetGMLevel(eGameMasterLevel value) { } } +bool Entity::IsVarSentToClient(const std::u16string& name) const { + if (GetComponent() && !GetComponent()) return m_Settings.values.contains(name); + const auto& syncLDF = GetVar>(u"syncLDF"); + return std::ranges::find(syncLDF, name) != syncLDF.end(); +} + void Entity::WriteLDFData(const LwoNameValue& ldf, RakNet::BitStream& outBitStream) const { RakNet::BitStream settingStream; int32_t numberOfValidKeys = ldf.values.size(); diff --git a/dGame/Entity.h b/dGame/Entity.h index e9618867c..2d28368ec 100644 --- a/dGame/Entity.h +++ b/dGame/Entity.h @@ -353,6 +353,9 @@ public: */ std::string GetVarAsString(const std::u16string& name) const; + // Whether the construction sends this level config key to the client (a model's settings, or syncLDF) + bool IsVarSentToClient(const std::u16string& name) const; + /* * Collision */ diff --git a/dGame/dComponents/ScriptComponent.cpp b/dGame/dComponents/ScriptComponent.cpp index 287b4cba0..d13922e41 100644 --- a/dGame/dComponents/ScriptComponent.cpp +++ b/dGame/dComponents/ScriptComponent.cpp @@ -51,6 +51,15 @@ void ScriptComponent::LoadConfigData() { m_Client = client && m_ScriptName.empty(); SetScript(m_ScriptName); + + // Sent only when the client makes a script component too: its registry script (not one with id 0), or a custom + // script in the config the client gets (ApplyScriptComponentIfHasScript 0x01031460, LOT 176 never; the + // allocator 0x0104d710). A character's and a server-only custom script stay on the server. + const auto clientCustomScript = [this](const std::u16string& key) { + return m_Parent->IsVarSentToClient(key) && !m_Parent->GetVarAsString(key).empty(); + }; + m_Serialized = (m_ComponentID > 0 && !isCharacter) + || (m_Parent->GetLOT() != 176 && (clientCustomScript(u"custom_script_server") || clientCustomScript(u"custom_script_client"))); } void ScriptComponent::Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) {