diff --git a/Source/Editor/Managed/ManagedEditor.cpp b/Source/Editor/Managed/ManagedEditor.cpp index 7a9e55b88..c4c71bdfd 100644 --- a/Source/Editor/Managed/ManagedEditor.cpp +++ b/Source/Editor/Managed/ManagedEditor.cpp @@ -16,6 +16,7 @@ #include "Engine/Engine/CommandLine.h" #include "Engine/Renderer/ProbesRenderer.h" #include "Engine/Animations/Graph/AnimGraph.h" +#include "Engine/Core/ObjectsRemovalService.h" ManagedEditor::InternalOptions ManagedEditor::ManagedEditorOptions; @@ -572,6 +573,29 @@ bool ManagedEditor::EvaluateVisualScriptLocal(VisualScript* script, VisualScript return false; } +void ManagedEditor::WipeOutLeftoverSceneObjects() +{ + Array objects = Scripting::GetObjects(); + bool removedAny = false; + for (ScriptingObject* object : objects) + { + if (EnumHasAllFlags(object->Flags, ObjectFlags::IsDuringPlay) && EnumHasNoneFlags(object->Flags, ObjectFlags::WasMarkedToDelete)) + { + if (auto* sceneObject = Cast(object)) + { + if (sceneObject->HasParent()) + continue; // Skip sub-objects + + LOG(Error, "Object '{}' (ID={}, Type={}) is still in memory after play end but should be destroyed (memory leak).", sceneObject->GetNamePath(), sceneObject->GetID(), sceneObject->GetType().ToString()); + sceneObject->DeleteObject(); + removedAny = true; + } + } + } + if (removedAny) + ObjectsRemovalService::Flush(); +} + void ManagedEditor::OnEditorAssemblyLoaded(MAssembly* assembly) { ASSERT(!HasManagedInstance()); diff --git a/Source/Editor/Managed/ManagedEditor.h b/Source/Editor/Managed/ManagedEditor.h index 601b4f2cf..e51749e5f 100644 --- a/Source/Editor/Managed/ManagedEditor.h +++ b/Source/Editor/Managed/ManagedEditor.h @@ -241,6 +241,7 @@ public: API_FUNCTION(Internal) static VisualScriptStackFrame GetVisualScriptPreviousScopeFrame(); API_FUNCTION(Internal) static Array GetVisualScriptLocals(); API_FUNCTION(Internal) static bool EvaluateVisualScriptLocal(VisualScript* script, API_PARAM(Ref) VisualScriptLocal& local); + API_FUNCTION(Internal) static void WipeOutLeftoverSceneObjects(); private: void OnEditorAssemblyLoaded(MAssembly* assembly); diff --git a/Source/Editor/States/PlayingState.cs b/Source/Editor/States/PlayingState.cs index b2654f3d9..69a11cf1b 100644 --- a/Source/Editor/States/PlayingState.cs +++ b/Source/Editor/States/PlayingState.cs @@ -194,7 +194,7 @@ namespace FlaxEditor.States // Restore editor scene SceneRestoring?.Invoke(); - _duplicateScenes.DeletedScenes(); + _duplicateScenes.UnloadScenes(); PluginManager.Internal_DeinitializeGamePlugins(); Editor.Internal_SetPlayMode(false); _duplicateScenes.RestoreSceneData(); diff --git a/Source/Editor/Utilities/DuplicateScenes.cs b/Source/Editor/Utilities/DuplicateScenes.cs index 20979940e..7902633b2 100644 --- a/Source/Editor/Utilities/DuplicateScenes.cs +++ b/Source/Editor/Utilities/DuplicateScenes.cs @@ -120,9 +120,9 @@ namespace FlaxEditor.Utilities /// /// Deletes the creates scenes for the simulation. /// - public void DeletedScenes() + public void UnloadScenes() { - Profiler.BeginEvent("DuplicateScenes.DeletedScenes"); + Profiler.BeginEvent("DuplicateScenes.UnloadScenes"); Editor.Log("Restoring scene data"); // TODO: here we can keep changes for actors marked to keep their state after simulation @@ -134,6 +134,8 @@ namespace FlaxEditor.Utilities throw new Exception("Failed to unload scenes."); } FlaxEngine.Scripting.FlushRemovedObjects(); + Editor.WipeOutLeftoverSceneObjects(); + Profiler.EndEvent(); } diff --git a/Source/Engine/Scripting/Scripting.cpp b/Source/Engine/Scripting/Scripting.cpp index 279e4d986..35b90a9ad 100644 --- a/Source/Engine/Scripting/Scripting.cpp +++ b/Source/Engine/Scripting/Scripting.cpp @@ -721,6 +721,15 @@ void Scripting::Reload(bool canTriggerSceneReload) #endif +Array Scripting::GetObjects() +{ + Array objects; + _objectsLocker.Lock(); + _objectsDictionary.GetValues(objects); + _objectsLocker.Unlock(); + return objects; +} + MClass* Scripting::FindClass(const StringAnsiView& fullname) { if (fullname.IsEmpty()) diff --git a/Source/Engine/Scripting/Scripting.h b/Source/Engine/Scripting/Scripting.h index d9f2c5b4d..dad5a02fb 100644 --- a/Source/Engine/Scripting/Scripting.h +++ b/Source/Engine/Scripting/Scripting.h @@ -79,6 +79,13 @@ public: public: + /// + /// Gets all registered scripting objects. + /// + /// Use with caution due to potentially large memory allocation. + /// The collection of the objects. + static Array GetObjects(); + /// /// Finds the class with given fully qualified name within whole assembly. ///