From 4a3be5a743732a497843be7b5227d572e7614a66 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Wed, 6 Dec 2023 00:30:37 +0100 Subject: [PATCH] Fix crash when updating prefabs from async thread --- Source/Engine/Level/Prefabs/Prefab.Apply.cpp | 35 +++++++++++++------- 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/Source/Engine/Level/Prefabs/Prefab.Apply.cpp b/Source/Engine/Level/Prefabs/Prefab.Apply.cpp index c10ea532d..569a7ce9b 100644 --- a/Source/Engine/Level/Prefabs/Prefab.Apply.cpp +++ b/Source/Engine/Level/Prefabs/Prefab.Apply.cpp @@ -22,6 +22,7 @@ #include "Engine/ContentImporters/CreateJson.h" #include "Engine/Debug/Exceptions/ArgumentNullException.h" #include "Engine/Profiler/ProfilerCPU.h" +#include "Engine/Threading/MainThreadTask.h" #include "Editor/Editor.h" // Apply flow: @@ -174,6 +175,12 @@ public: /// Collection with ids of the objects (actors and scripts) from the prefab after changes apply. Used to find new objects or old objects and use this information during changes sync (eg. generate ids for the new objects to prevent ids collisions). /// True if failed, otherwise false. static bool SynchronizePrefabInstances(PrefabInstancesData& prefabInstancesData, Actor* defaultInstance, SceneObjectsListCacheType& sceneObjects, const Guid& prefabId, rapidjson_flax::StringBuffer& tmpBuffer, const Array& oldObjectsIds, const Array& newObjectIds); + + static void DeletePrefabObject(SceneObject* obj) + { + obj->SetParent(nullptr); + obj->DeleteObject(); + } }; void PrefabInstanceData::CollectPrefabInstances(PrefabInstancesData& prefabInstancesData, const Guid& prefabId, Actor* defaultInstance, Actor* targetActor) @@ -302,14 +309,10 @@ bool PrefabInstanceData::SynchronizePrefabInstances(PrefabInstancesData& prefabI { // Remove object LOG(Info, "Removing object {0} from instance {1} (prefab: {2})", obj->GetSceneObjectId(), instance.TargetActor->ToString(), prefabId); - - obj->DeleteObject(); - obj->SetParent(nullptr); - + DeletePrefabObject(obj); sceneObjects.Value->RemoveAtKeepOrder(i); existingObjectsCount--; i--; - continue; } @@ -358,10 +361,7 @@ bool PrefabInstanceData::SynchronizePrefabInstances(PrefabInstancesData& prefabI { // Remove object removed from the prefab LOG(Info, "Removing prefab instance object {0} from instance {1} (prefab object: {2}, prefab: {3})", obj->GetSceneObjectId(), instance.TargetActor->ToString(), obj->GetPrefabObjectID(), prefabId); - - obj->DeleteObject(); - obj->SetParent(nullptr); - + DeletePrefabObject(obj); sceneObjects.Value->RemoveAtKeepOrder(i); deserializeSceneObjectIndex--; existingObjectsCount--; @@ -633,6 +633,19 @@ bool Prefab::ApplyAll(Actor* targetActor) } } } + if (!IsInMainThread()) + { + // Prefabs cannot be updated on async thread so sync it with a Main Thread + bool result = true; + Function action = [&] + { + result = ApplyAll(targetActor); + }; + const auto task = Task::StartNew(New(action)); + if (task->Wait(TimeSpan::FromSeconds(10))) + result = true; + return result; + } // Prevent cyclic references { @@ -921,9 +934,7 @@ bool Prefab::ApplyAllInternal(Actor* targetActor, bool linkTargetActorObjectToPr { // Remove object removed from the prefab LOG(Info, "Removing object {0} from prefab default instance", obj->GetSceneObjectId()); - - obj->DeleteObject(); - obj->SetParent(nullptr); + PrefabInstanceData::DeletePrefabObject(obj); sceneObjects->At(i) = nullptr; } }