From e82bb639edf845e86059e2ae48c08eedfd6be0ff Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Mon, 3 Mar 2025 19:12:29 +0100 Subject: [PATCH] Fix objects creation to ensure managed object ctor is always executed #3245 --- Source/Engine/Content/Content.cpp | 2 ++ Source/Engine/Level/Level.cpp | 6 ++++-- Source/Engine/Scripting/BinaryModule.cpp | 11 +++++++++++ Source/Engine/Scripting/ScriptingObject.cpp | 22 +++++++-------------- Source/Engine/Scripting/ScriptingType.h | 6 ++++++ 5 files changed, 30 insertions(+), 17 deletions(-) diff --git a/Source/Engine/Content/Content.cpp b/Source/Engine/Content/Content.cpp index 37e77fa64..98cb1a737 100644 --- a/Source/Engine/Content/Content.cpp +++ b/Source/Engine/Content/Content.cpp @@ -874,6 +874,7 @@ Asset* Content::CreateVirtualAsset(const ScriptingTypeHandle& type) LOG(Error, "Cannot create virtual asset object."); return nullptr; } + asset->RegisterObject(); // Call initializer function asset->InitAsVirtual(); @@ -1041,6 +1042,7 @@ Asset* Content::LoadAsync(const Guid& id, const ScriptingTypeHandle& type) LOAD_FAILED(); } #endif + result->RegisterObject(); // Register asset AssetsLocker.Lock(); diff --git a/Source/Engine/Level/Level.cpp b/Source/Engine/Level/Level.cpp index ccbe7a59a..cb565f651 100644 --- a/Source/Engine/Level/Level.cpp +++ b/Source/Engine/Level/Level.cpp @@ -956,10 +956,12 @@ bool Level::loadScene(rapidjson_flax::Value& data, int32 engineBuild, Scene** ou objects[i] = obj; if (obj) { - obj->RegisterObject(); + if (!obj->IsRegistered()) + obj->RegisterObject(); #if USE_EDITOR // Auto-create C# objects for all actors in Editor during scene load when running in async (so main thread already has all of them) - obj->CreateManaged(); + if (!obj->GetManagedInstance()) + obj->CreateManaged(); #endif } else diff --git a/Source/Engine/Scripting/BinaryModule.cpp b/Source/Engine/Scripting/BinaryModule.cpp index 689010116..dd493d2de 100644 --- a/Source/Engine/Scripting/BinaryModule.cpp +++ b/Source/Engine/Scripting/BinaryModule.cpp @@ -796,6 +796,17 @@ ScriptingObject* ManagedBinaryModule::ManagedObjectSpawn(const ScriptingObjectSp // Mark as managed type object->Flags |= ObjectFlags::IsManagedType; + // Initialize managed instance + if (params.Managed) + { + object->SetManagedInstance((MObject*)params.Managed); + } + else + { + // Invoke managed ctor (to match C++ logic) + object->CreateManaged(); + } + return object; } diff --git a/Source/Engine/Scripting/ScriptingObject.cpp b/Source/Engine/Scripting/ScriptingObject.cpp index 7f9d92369..14ce087cf 100644 --- a/Source/Engine/Scripting/ScriptingObject.cpp +++ b/Source/Engine/Scripting/ScriptingObject.cpp @@ -412,7 +412,8 @@ void ScriptingObject::DestroyManaged() void ScriptingObject::RegisterObject() { - ASSERT(!IsRegistered()); + if (IsRegistered()) + return; Flags |= ObjectFlags::IsRegistered; Scripting::RegisterObject(this); } @@ -532,10 +533,6 @@ bool ManagedScriptingObject::CreateManaged() } #endif - // Ensure to be registered - if (!IsRegistered()) - RegisterObject(); - return false; } @@ -598,8 +595,7 @@ DEFINE_INTERNAL_CALL(MObject*) ObjectInternal_Create1(MTypeObject* type) } // Create managed object - obj->CreateManaged(); - MObject* managedInstance = obj->GetManagedInstance(); + MObject* managedInstance = obj->GetOrCreateManagedInstance(); if (managedInstance == nullptr) { LOG(Error, "Cannot create managed instance for type \'{0}\'.", String(typeClass->GetFullName())); @@ -636,8 +632,7 @@ DEFINE_INTERNAL_CALL(MObject*) ObjectInternal_Create2(MString* typeNameObj) } // Create managed object - obj->CreateManaged(); - MObject* managedInstance = obj->GetManagedInstance(); + MObject* managedInstance = obj->GetOrCreateManagedInstance(); if (managedInstance == nullptr) { LOG(Error, "Cannot create managed instance for type \'{0}\'.", String(typeName)); @@ -667,7 +662,8 @@ DEFINE_INTERNAL_CALL(void) ObjectInternal_ManagedInstanceCreated(MObject* manage const ScriptingType& scriptingType = module->Types[typeIndex]; // Create unmanaged object - const ScriptingObjectSpawnParams params(Guid::New(), ScriptingTypeHandle(module, typeIndex)); + ScriptingObjectSpawnParams params(Guid::New(), ScriptingTypeHandle(module, typeIndex)); + params.Managed = managedInstance; // Link created managed instance to the unmanaged object ScriptingObject* obj = scriptingType.Script.Spawn(params); if (obj == nullptr) { @@ -675,9 +671,6 @@ DEFINE_INTERNAL_CALL(void) ObjectInternal_ManagedInstanceCreated(MObject* manage return; } - // Link created managed instance to the unmanaged object - obj->SetManagedInstance(managedInstance); - // Set default name for actors if (auto* actor = dynamic_cast(obj)) { @@ -689,8 +682,7 @@ DEFINE_INTERNAL_CALL(void) ObjectInternal_ManagedInstanceCreated(MObject* manage MCore::ScriptingObject::SetInternalValues(klass, managedInstance, obj, &id); // Register object - if (!obj->IsRegistered()) - obj->RegisterObject(); + obj->RegisterObject(); } DEFINE_INTERNAL_CALL(void) ObjectInternal_ManagedInstanceDeleted(ScriptingObject* obj) diff --git a/Source/Engine/Scripting/ScriptingType.h b/Source/Engine/Scripting/ScriptingType.h index f53778401..72cbaaac9 100644 --- a/Source/Engine/Scripting/ScriptingType.h +++ b/Source/Engine/Scripting/ScriptingType.h @@ -355,9 +355,15 @@ struct ScriptingObjectSpawnParams /// const ScriptingTypeHandle Type; + /// + /// Optional C# object instance to use for unmanaged object. + /// + void* Managed; + FORCE_INLINE ScriptingObjectSpawnParams(const Guid& id, const ScriptingTypeHandle& typeHandle) : ID(id) , Type(typeHandle) + , Managed(nullptr) { } };