fix(component): send a script component only when the client makes one

The client makes a script component for a registry script with a non-zero
id, or for a custom script in the config it is sent (LOT 176 never):
ApplyScriptComponentIfHasScript and LWOScriptComponent's allocator. A
character's script and a server-only custom_script_server stay on the
server and send nothing. The 5 LOTs whose registry script id is 0 (e.g. the
AG concert fan, LOT 3002: live sent no config and no script) lose the bit
the client never read.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Aaron Kimbrell
2026-10-01 16:38:56 -05:00
parent c69b26b661
commit 432f4f6ff9
3 changed files with 18 additions and 0 deletions

View File

@@ -1133,6 +1133,12 @@ void Entity::SetGMLevel(eGameMasterLevel value) {
}
}
bool Entity::IsVarSentToClient(const std::u16string& name) const {
if (GetComponent<ModelComponent>() && !GetComponent<PetComponent>()) return m_Settings.values.contains(name);
const auto& syncLDF = GetVar<std::vector<std::u16string>>(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();

View File

@@ -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
*/

View File

@@ -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) {