From bc2e1302818ad77a5e0e874ea413414c8549510a Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Mon, 18 Dec 2023 21:43:13 +0100 Subject: [PATCH] Fix calling script `OnDestroy` when removing actors or scripts from the scene --- Source/Engine/Level/Actor.cpp | 24 ++++++++++++++++++------ Source/Engine/Scripting/Script.cpp | 28 ++++++++++++++++++++++------ Source/Engine/Scripting/Script.h | 1 + 3 files changed, 41 insertions(+), 12 deletions(-) diff --git a/Source/Engine/Level/Actor.cpp b/Source/Engine/Level/Actor.cpp index 00ca485d2..bf544d9ad 100644 --- a/Source/Engine/Level/Actor.cpp +++ b/Source/Engine/Level/Actor.cpp @@ -206,10 +206,18 @@ void Actor::OnDeleteObject() #endif for (int32 i = 0; i < Scripts.Count(); i++) { - auto e = Scripts[i]; - ASSERT(e->_parent == this); - e->_parent = nullptr; - e->DeleteObject(); + auto script = Scripts[i]; + ASSERT(script->_parent == this); + if (script->_wasAwakeCalled) + { + script->_wasAwakeCalled = false; + CHECK_EXECUTE_IN_EDITOR + { + script->OnDestroy(); + } + } + script->_parent = nullptr; + script->DeleteObject(); } #if BUILD_DEBUG ASSERT(callsCheck == Scripts.Count()); @@ -889,9 +897,13 @@ void Actor::EndPlay() for (auto* script : Scripts) { - CHECK_EXECUTE_IN_EDITOR + if (script->_wasAwakeCalled) { - script->OnDestroy(); + script->_wasAwakeCalled = false; + CHECK_EXECUTE_IN_EDITOR + { + script->OnDestroy(); + } } } diff --git a/Source/Engine/Scripting/Script.cpp b/Source/Engine/Scripting/Script.cpp index 8eaff42de..e9cc2a0a8 100644 --- a/Source/Engine/Scripting/Script.cpp +++ b/Source/Engine/Scripting/Script.cpp @@ -27,6 +27,7 @@ Script::Script(const SpawnParams& params) , _tickUpdate(false) , _tickLateUpdate(false) , _tickLateFixedUpdate(false) + , _wasAwakeCalled(false) , _wasStartCalled(false) , _wasEnableCalled(false) { @@ -86,7 +87,7 @@ void Script::SetParent(Actor* value, bool canBreakPrefabLink) // Unlink from the old one if (_parent) { - if (!value && _parent->IsDuringPlay() && _parent->IsActiveInHierarchy() && GetEnabled()) + if (!value && _parent->IsDuringPlay() && _parent->IsActiveInHierarchy() && GetEnabled() && _wasEnableCalled) { // Call disable when script is removed from actor (new actor is null) Disable(); @@ -241,19 +242,31 @@ String Script::ToString() const void Script::OnDeleteObject() { - // Ensure to unlink from the parent (it will call Disable event if required) - SetParent(nullptr); - - // Check if remove object from game - if (IsDuringPlay()) + // Call OnDisable + if (_wasEnableCalled) { + Disable(); + } + + // Call OnDestroy + if (_wasAwakeCalled) + { + _wasAwakeCalled = false; CHECK_EXECUTE_IN_EDITOR { OnDestroy(); } + } + + // End play + if (IsDuringPlay()) + { EndPlay(); } + // Unlink from parent + SetParent(nullptr); + // Base SceneObject::OnDeleteObject(); } @@ -274,6 +287,9 @@ void Script::Initialize() if (!IsRegistered()) RegisterObject(); + // Call OnAwake + ASSERT(!_wasAwakeCalled); + _wasAwakeCalled = true; CHECK_EXECUTE_IN_EDITOR { OnAwake(); diff --git a/Source/Engine/Scripting/Script.h b/Source/Engine/Scripting/Script.h index 8cf1d0670..919f3ecdd 100644 --- a/Source/Engine/Scripting/Script.h +++ b/Source/Engine/Scripting/Script.h @@ -20,6 +20,7 @@ protected: uint16 _tickUpdate : 1; uint16 _tickLateUpdate : 1; uint16 _tickLateFixedUpdate : 1; + uint16 _wasAwakeCalled : 1; uint16 _wasStartCalled : 1; uint16 _wasEnableCalled : 1; #if USE_EDITOR