Add logging and cleaning up leaked scene objects after play mode in Editor

This commit is contained in:
Wojtek Figat
2024-04-22 22:59:38 +02:00
parent d8a1de64d1
commit 890569ea3b
6 changed files with 46 additions and 3 deletions

View File

@@ -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<ScriptingObject*> 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<SceneObject>(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());

View File

@@ -241,6 +241,7 @@ public:
API_FUNCTION(Internal) static VisualScriptStackFrame GetVisualScriptPreviousScopeFrame();
API_FUNCTION(Internal) static Array<VisualScriptLocal> 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);

View File

@@ -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();

View File

@@ -120,9 +120,9 @@ namespace FlaxEditor.Utilities
/// <summary>
/// Deletes the creates scenes for the simulation.
/// </summary>
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();
}

View File

@@ -721,6 +721,15 @@ void Scripting::Reload(bool canTriggerSceneReload)
#endif
Array<ScriptingObject*, HeapAllocation> Scripting::GetObjects()
{
Array<ScriptingObject*> objects;
_objectsLocker.Lock();
_objectsDictionary.GetValues(objects);
_objectsLocker.Unlock();
return objects;
}
MClass* Scripting::FindClass(const StringAnsiView& fullname)
{
if (fullname.IsEmpty())

View File

@@ -79,6 +79,13 @@ public:
public:
/// <summary>
/// Gets all registered scripting objects.
/// </summary>
/// <remarks>Use with caution due to potentially large memory allocation.</remarks>
/// <returns>The collection of the objects.</returns>
static Array<ScriptingObject*, HeapAllocation> GetObjects();
/// <summary>
/// Finds the class with given fully qualified name within whole assembly.
/// </summary>