From f932b8b9cc03b6471d963693a2de8fbb4dfb8763 Mon Sep 17 00:00:00 2001 From: elexis Date: Mon, 30 Dec 2024 11:31:07 +0100 Subject: [PATCH] Fix subscription time of script component wrapper Script component wrapper attempted to subscribe to messages before the script component has been registered. This defect existed since 7c2e9027c2 but was never noticed since there is no script component wrapper which subscribes to messages. (Only the script component it wrapps does.) --- source/simulation2/scripting/ScriptComponent.h | 7 ++++--- source/simulation2/system/ComponentManager.cpp | 13 +++++++++---- source/simulation2/system/ComponentManager.h | 7 +++++-- source/simulation2/system/IComponent.cpp | 8 +++++--- source/simulation2/system/IComponent.h | 7 +++++-- 5 files changed, 28 insertions(+), 14 deletions(-) diff --git a/source/simulation2/scripting/ScriptComponent.h b/source/simulation2/scripting/ScriptComponent.h index fb9ece0096..845d052a2e 100644 --- a/source/simulation2/scripting/ScriptComponent.h +++ b/source/simulation2/scripting/ScriptComponent.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 Wildfire Games. +/* Copyright (C) 2025 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -82,8 +82,9 @@ private: #define REGISTER_COMPONENT_SCRIPT_WRAPPER(cname) \ void RegisterComponentType_##cname(CComponentManager& mgr) \ { \ - IComponent::RegisterComponentTypeScriptWrapper(mgr, CCmp##cname::GetInterfaceId(), CID_##cname, CCmp##cname::Allocate, CCmp##cname::Deallocate, #cname, CCmp##cname::GetSchema()); \ - CCmp##cname::ClassInit(mgr); \ + IComponent::RegisterComponentTypeScriptWrapper(mgr, CCmp##cname::GetInterfaceId(), \ + CID_##cname, CCmp##cname::Allocate, CCmp##cname::Deallocate, #cname, \ + CCmp##cname::GetSchema(), CCmp##cname::ClassInit); \ } diff --git a/source/simulation2/system/ComponentManager.cpp b/source/simulation2/system/ComponentManager.cpp index 3f15d08522..152e6b135a 100644 --- a/source/simulation2/system/ComponentManager.cpp +++ b/source/simulation2/system/ComponentManager.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2023 Wildfire Games. +/* Copyright (C) 2025 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -267,6 +267,9 @@ void CComponentManager::Script_RegisterComponentType_Common(int iid, const std:: m_CurrentComponent = cid; // needed by Subscribe + // Only now that we have constructed the CT_Script for this CT_ScriptWrapper, we can subscribe the CT_Script + ctWrapper.classInit(*this); + // Find all the ctor prototype's On* methods, and subscribe to the appropriate messages: std::vector methods; @@ -528,10 +531,12 @@ void CComponentManager::RegisterComponentType(InterfaceId iid, ComponentTypeId c m_ComponentTypeIdsByName[name] = cid; } -void CComponentManager::RegisterComponentTypeScriptWrapper(InterfaceId iid, ComponentTypeId cid, AllocFunc alloc, - DeallocFunc dealloc, const char* name, const std::string& schema) +void CComponentManager::RegisterComponentTypeScriptWrapper(InterfaceId iid, ComponentTypeId cid, + AllocFunc alloc, DeallocFunc dealloc, const char* name, const std::string& schema, + ClassInitFunc classInit) { - ComponentType c{ CT_ScriptWrapper, iid, alloc, dealloc, name, schema, std::unique_ptr() }; + ComponentType c{ CT_ScriptWrapper, iid, alloc, dealloc, name, schema, + std::unique_ptr(), classInit }; m_ComponentTypesById.insert(std::make_pair(cid, std::move(c))); m_ComponentTypeIdsByName[name] = cid; // TODO: merge with RegisterComponentType diff --git a/source/simulation2/system/ComponentManager.h b/source/simulation2/system/ComponentManager.h index ce0d4cb8a8..8efa35a57e 100644 --- a/source/simulation2/system/ComponentManager.h +++ b/source/simulation2/system/ComponentManager.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2023 Wildfire Games. +/* Copyright (C) 2025 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -49,6 +49,7 @@ public: private: using AllocFunc = IComponent::AllocFunc; using DeallocFunc = IComponent::DeallocFunc; + using ClassInitFunc = IComponent::ClassInitFunc; // ComponentTypes come in three types: // Native: normal C++ component @@ -71,6 +72,7 @@ private: std::string name; std::string schema; // RelaxNG fragment std::unique_ptr ctor; // only valid if type == CT_Script + ClassInitFunc classInit; }; public: @@ -90,7 +92,8 @@ public: void RegisterMessageType(MessageTypeId mtid, const char* name); void RegisterComponentType(InterfaceId, ComponentTypeId, AllocFunc, DeallocFunc, const char*, const std::string& schema); - void RegisterComponentTypeScriptWrapper(InterfaceId, ComponentTypeId, AllocFunc, DeallocFunc, const char*, const std::string& schema); + void RegisterComponentTypeScriptWrapper(InterfaceId, ComponentTypeId, AllocFunc, DeallocFunc, + const char*, const std::string& schema, ClassInitFunc classInit); void MarkScriptedComponentForSystemEntity(CComponentManager::ComponentTypeId cid); diff --git a/source/simulation2/system/IComponent.cpp b/source/simulation2/system/IComponent.cpp index 76c63483bf..3c26399ddf 100644 --- a/source/simulation2/system/IComponent.cpp +++ b/source/simulation2/system/IComponent.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2025 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -38,9 +38,11 @@ void IComponent::RegisterComponentType(CComponentManager& mgr, EInterfaceId iid, mgr.RegisterComponentType(iid, cid, alloc, dealloc, name, schema); } -void IComponent::RegisterComponentTypeScriptWrapper(CComponentManager& mgr, EInterfaceId iid, EComponentTypeId cid, AllocFunc alloc, DeallocFunc dealloc, const char* name, const std::string& schema) +void IComponent::RegisterComponentTypeScriptWrapper(CComponentManager& mgr, EInterfaceId iid, + EComponentTypeId cid, AllocFunc alloc, DeallocFunc dealloc, const char* name, + const std::string& schema, ClassInitFunc classInit) { - mgr.RegisterComponentTypeScriptWrapper(iid, cid, alloc, dealloc, name, schema); + mgr.RegisterComponentTypeScriptWrapper(iid, cid, alloc, dealloc, name, schema, classInit); } void IComponent::HandleMessage(const CMessage& UNUSED(msg), bool UNUSED(global)) diff --git a/source/simulation2/system/IComponent.h b/source/simulation2/system/IComponent.h index 63a887573c..9c46c47f02 100644 --- a/source/simulation2/system/IComponent.h +++ b/source/simulation2/system/IComponent.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2025 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -35,13 +35,16 @@ public: // Component allocation types using AllocFunc = IComponent* (*)(const ScriptInterface& scriptInterface, JS::HandleValue ctor); using DeallocFunc = void (*)(IComponent*); + using ClassInitFunc = void (*)(CComponentManager& componentManager); virtual ~IComponent(); static std::string GetSchema(); static void RegisterComponentType(CComponentManager& mgr, EInterfaceId iid, EComponentTypeId cid, AllocFunc alloc, DeallocFunc dealloc, const char* name, const std::string& schema); - static void RegisterComponentTypeScriptWrapper(CComponentManager& mgr, EInterfaceId iid, EComponentTypeId cid, AllocFunc alloc, DeallocFunc dealloc, const char* name, const std::string& schema); + static void RegisterComponentTypeScriptWrapper(CComponentManager& mgr, EInterfaceId iid, + EComponentTypeId cid, AllocFunc alloc, DeallocFunc dealloc, const char* name, + const std::string& schema, ClassInitFunc classInit); virtual void Init(const CParamNode& paramNode) = 0; virtual void Deinit() = 0;