From 8318a9c1d033fa5f559fa74cbfdabef5f8e183ae Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Thu, 12 Mar 2026 13:39:01 +0100 Subject: [PATCH] Fix crash when unloading scene during tick of that scene --- Source/Engine/Level/Level.cpp | 3 -- Source/Engine/Level/Scene/Scene.cpp | 3 ++ Source/Engine/Level/Scene/SceneTicking.cpp | 40 +++++++++++----------- Source/Engine/Level/Scene/SceneTicking.h | 8 +++++ 4 files changed, 31 insertions(+), 23 deletions(-) diff --git a/Source/Engine/Level/Level.cpp b/Source/Engine/Level/Level.cpp index 956005f57..a46ee52f6 100644 --- a/Source/Engine/Level/Level.cpp +++ b/Source/Engine/Level/Level.cpp @@ -958,9 +958,6 @@ bool LevelImpl::unloadScene(Scene* scene) // Simple enqueue scene root object to be deleted scene->DeleteObject(); - // Force flush deleted objects so we actually delete unloaded scene objects (prevent from reloading their managed objects, etc.) - ObjectsRemovalService::Flush(); - return false; } diff --git a/Source/Engine/Level/Scene/Scene.cpp b/Source/Engine/Level/Scene/Scene.cpp index f60aa8d2f..b45424a3d 100644 --- a/Source/Engine/Level/Scene/Scene.cpp +++ b/Source/Engine/Level/Scene/Scene.cpp @@ -389,11 +389,14 @@ void Scene::BeginPlay(SceneBeginData* data) if (model == nullptr) CreateCsgModel(); } + + Ticking.SetTicking(true); } void Scene::EndPlay() { // Improve scene cleanup performance by removing all data from scene rendering and ticking containers + Ticking.SetTicking(false); Ticking.Clear(); Rendering.Clear(); Navigation.Clear(); diff --git a/Source/Engine/Level/Scene/SceneTicking.cpp b/Source/Engine/Level/Scene/SceneTicking.cpp index 30a551117..2b0ccc506 100644 --- a/Source/Engine/Level/Scene/SceneTicking.cpp +++ b/Source/Engine/Level/Scene/SceneTicking.cpp @@ -44,7 +44,7 @@ void SceneTicking::TickData::Tick() { TickScripts(Scripts); - for (int32 i = 0; i < Ticks.Count(); i++) + for (int32 i = 0; i < Ticks.Count() && _canTick; i++) Ticks.Get()[i].Call(); } @@ -66,7 +66,7 @@ void SceneTicking::TickData::TickExecuteInEditor() { TickScripts(ScriptsExecuteInEditor); - for (int32 i = 0; i < TicksExecuteInEditor.Count(); i++) + for (int32 i = 0; i < TicksExecuteInEditor.Count() && _canTick; i++) TicksExecuteInEditor.Get()[i].Call(); } @@ -89,10 +89,8 @@ SceneTicking::FixedUpdateTickData::FixedUpdateTickData() void SceneTicking::FixedUpdateTickData::TickScripts(const Array& scripts) { - for (auto* script : scripts) - { - script->OnFixedUpdate(); - } + for (int32 i = 0; i < scripts.Count() && _canTick; i++) + scripts.Get()[i]->OnFixedUpdate(); } SceneTicking::UpdateTickData::UpdateTickData() @@ -102,36 +100,30 @@ SceneTicking::UpdateTickData::UpdateTickData() void SceneTicking::UpdateTickData::TickScripts(const Array& scripts) { - for (auto* script : scripts) - { - script->OnUpdate(); - } + for (int32 i = 0; i < scripts.Count() && _canTick; i++) + scripts.Get()[i]->OnUpdate(); } SceneTicking::LateUpdateTickData::LateUpdateTickData() - : TickData(64) + : TickData(0) { } void SceneTicking::LateUpdateTickData::TickScripts(const Array& scripts) { - for (auto* script : scripts) - { - script->OnLateUpdate(); - } + for (int32 i = 0; i < scripts.Count() && _canTick; i++) + scripts.Get()[i]->OnLateUpdate(); } SceneTicking::LateFixedUpdateTickData::LateFixedUpdateTickData() - : TickData(64) + : TickData(0) { } void SceneTicking::LateFixedUpdateTickData::TickScripts(const Array& scripts) { - for (auto* script : scripts) - { - script->OnLateFixedUpdate(); - } + for (int32 i = 0; i < scripts.Count() && _canTick; i++) + scripts.Get()[i]->OnLateFixedUpdate(); } void SceneTicking::AddScript(Script* obj) @@ -167,3 +159,11 @@ void SceneTicking::Clear() LateUpdate.Clear(); LateFixedUpdate.Clear(); } + +void SceneTicking::SetTicking(bool enable) +{ + FixedUpdate._canTick = enable; + Update._canTick = enable; + LateUpdate._canTick = enable; + LateFixedUpdate._canTick = enable; +} diff --git a/Source/Engine/Level/Scene/SceneTicking.h b/Source/Engine/Level/Scene/SceneTicking.h index 78e028b8e..26040852b 100644 --- a/Source/Engine/Level/Scene/SceneTicking.h +++ b/Source/Engine/Level/Scene/SceneTicking.h @@ -46,6 +46,9 @@ public: /// class FLAXENGINE_API TickData { + protected: + friend SceneTicking; + bool _canTick = true; public: Array Scripts; Array Ticks; @@ -134,6 +137,11 @@ public: /// void Clear(); + /// + /// Changes the ability to tick. When disabled, the ticking functions won't be called. Can be called during ticking (eg. when scene is unloaded) to stp performing any more ticks. + /// + void SetTicking(bool enable); + public: /// /// The fixed update tick function.