From 3239150a610d38bccb9a93f786371ed7227fefda Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Sun, 17 Jul 2022 17:05:59 +0200 Subject: [PATCH] Refactor scene objects initialization to call OnAwake before all OnStart #520 --- Source/Editor/Utilities/EditorScene.cpp | 2 +- Source/Engine/Foliage/Foliage.cpp | 2 +- Source/Engine/Level/Actor.cpp | 56 ++++++------------- Source/Engine/Level/Actor.h | 8 ++- Source/Engine/Level/Actors/Spline.cpp | 4 +- Source/Engine/Level/Actors/Spline.h | 2 +- Source/Engine/Level/Level.cpp | 26 ++++----- Source/Engine/Level/Prefabs/Prefab.Apply.cpp | 6 +- Source/Engine/Level/Prefabs/PrefabManager.cpp | 4 +- Source/Engine/Level/Scene/Scene.cpp | 15 +---- Source/Engine/Level/Scene/Scene.h | 3 +- Source/Engine/Level/SceneObject.h | 10 +--- Source/Engine/Scripting/Script.cpp | 23 +++----- Source/Engine/Scripting/Script.h | 12 +--- 14 files changed, 59 insertions(+), 114 deletions(-) diff --git a/Source/Editor/Utilities/EditorScene.cpp b/Source/Editor/Utilities/EditorScene.cpp index 88dda5680..f06b61f92 100644 --- a/Source/Editor/Utilities/EditorScene.cpp +++ b/Source/Editor/Utilities/EditorScene.cpp @@ -6,7 +6,7 @@ EditorScene::EditorScene(const SpawnParams& params) : Scene(params) { // Mock editor preview scene to be in gameplay - EditorScene::PostSpawn(); + InitializeHierarchy(); SceneBeginData beginData; EditorScene::BeginPlay(&beginData); beginData.OnDone(); diff --git a/Source/Engine/Foliage/Foliage.cpp b/Source/Engine/Foliage/Foliage.cpp index 5c9e2ce67..6e863260f 100644 --- a/Source/Engine/Foliage/Foliage.cpp +++ b/Source/Engine/Foliage/Foliage.cpp @@ -1275,7 +1275,7 @@ void Foliage::OnTransformChanged() // Update instances matrices and cached world bounds Vector3 corners[8]; - Matrix world, matrix; + Matrix world; GetLocalToWorldMatrix(world); for (auto i = Instances.Begin(); i.IsNotEnd(); ++i) { diff --git a/Source/Engine/Level/Actor.cpp b/Source/Engine/Level/Actor.cpp index bc80fdd0a..6ee86c405 100644 --- a/Source/Engine/Level/Actor.cpp +++ b/Source/Engine/Level/Actor.cpp @@ -331,7 +331,7 @@ void Actor::SetParent(Actor* value, bool worldPositionsStays, bool canBreakPrefa ASSERT(_parent != nullptr && GetScene() != nullptr); // Fire events - PostSpawn(); + InitializeHierarchy(); { SceneBeginData beginData; BeginPlay(&beginData); @@ -778,13 +778,13 @@ void Actor::BreakPrefabLink() } } -void Actor::PostLoad() +void Actor::Initialize() { - // Cache scene + ASSERT(!IsDuringPlay()); + + // Cache if (_parent) _scene = _parent->GetScene(); - - // Cache flag _isActiveInHierarchy = _isActive && (_parent == nullptr || _parent->IsActiveInHierarchy()); // Use lazy creation for the managed instance, just register the object @@ -792,32 +792,6 @@ void Actor::PostLoad() RegisterObject(); } -void Actor::PostSpawn() -{ - // Cache scene - if (_parent) - _scene = _parent->GetScene(); - - // Cache flag - _isActiveInHierarchy = _isActive && (_parent == nullptr || _parent->IsActiveInHierarchy()); - - // Create managed object - if (!HasManagedInstance()) - CreateManaged(); - - // Init scripts - for (int32 i = 0; i < Scripts.Count(); i++) - { - Scripts[i]->PostSpawn(); - } - - // Init children - for (int32 i = 0; i < Children.Count(); i++) - { - Children[i]->PostSpawn(); - } -} - void Actor::BeginPlay(SceneBeginData* data) { // Perform additional verification @@ -853,13 +827,6 @@ void Actor::BeginPlay(SceneBeginData* data) } // Fire events for scripting - for (auto* script : Scripts) - { - CHECK_EXECUTE_IN_EDITOR - { - script->OnAwake(); - } - } if (IsActiveInHierarchy() && GetScene() && !_isEnabled) { OnEnable(); @@ -1229,6 +1196,17 @@ void Actor::UnregisterObjectHierarchy() } } +void Actor::InitializeHierarchy() +{ + Initialize(); + + for (int32 i = 0; i < Scripts.Count(); i++) + Scripts[i]->Initialize(); + + for (int32 i = 0; i < Children.Count(); i++) + Children[i]->InitializeHierarchy(); +} + void Actor::Draw(RenderContext& renderContext) { } @@ -1685,7 +1663,7 @@ bool Actor::FromBytes(const Span& data, Array& output, ISerializeM } for (int32 i = 0; i < parents->Count(); i++) { - parents->At(i)->PostSpawn(); + parents->At(i)->InitializeHierarchy(); } for (int32 i = 0; i < parents->Count(); i++) { diff --git a/Source/Engine/Level/Actor.h b/Source/Engine/Level/Actor.h index 70485a8ca..430ad4241 100644 --- a/Source/Engine/Level/Actor.h +++ b/Source/Engine/Level/Actor.h @@ -650,6 +650,11 @@ public: /// void UnregisterObjectHierarchy(); + /// + /// Calls Initialize for all objects in the actor hierarchy. + /// + void InitializeHierarchy(); + public: /// /// Draws this actor. Called by Scene Rendering service. This call is more optimized than generic Draw (eg. geometry is rendered during all pass types but other actors are drawn only during GBufferFill pass). @@ -993,8 +998,7 @@ public: void SetOrderInParent(int32 index) override; void LinkPrefab(const Guid& prefabId, const Guid& prefabObjectId) override; void BreakPrefabLink() override; - void PostLoad() override; - void PostSpawn() override; + void Initialize() override; void BeginPlay(SceneBeginData* data) override; void EndPlay() override; void Serialize(SerializeStream& stream, const void* otherObj) override; diff --git a/Source/Engine/Level/Actors/Spline.cpp b/Source/Engine/Level/Actors/Spline.cpp index 0e1502ecf..4da28d2d2 100644 --- a/Source/Engine/Level/Actors/Spline.cpp +++ b/Source/Engine/Level/Actors/Spline.cpp @@ -514,10 +514,10 @@ void Spline::OnTransformChanged() BoundingSphere::FromBox(_box, _sphere); } -void Spline::PostLoad() +void Spline::Initialize() { // Base - Actor::PostLoad(); + Actor::Initialize(); auto& keyframes = Curve.GetKeyframes(); const int32 count = keyframes.Count(); diff --git a/Source/Engine/Level/Actors/Spline.h b/Source/Engine/Level/Actors/Spline.h index eb72c3efe..86f580075 100644 --- a/Source/Engine/Level/Actors/Spline.h +++ b/Source/Engine/Level/Actors/Spline.h @@ -373,7 +373,7 @@ public: void OnDebugDrawSelected() override; #endif void OnTransformChanged() override; - void PostLoad() override; + void Initialize() override; void Serialize(SerializeStream& stream, const void* otherObj) override; void Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) override; }; diff --git a/Source/Engine/Level/Level.cpp b/Source/Engine/Level/Level.cpp index 983b814e1..c60bf6cc6 100644 --- a/Source/Engine/Level/Level.cpp +++ b/Source/Engine/Level/Level.cpp @@ -178,7 +178,7 @@ bool LevelImpl::spawnActor(Actor* actor, Actor* parent) if (actor->Is()) { // Spawn scene - actor->PostSpawn(); + actor->InitializeHierarchy(); actor->OnTransformChanged(); { SceneBeginData beginData; @@ -1052,26 +1052,24 @@ bool Level::loadScene(rapidjson_flax::Value& data, int32 engineBuild, Scene** ou // TODO: resave and force sync scenes during game cooking so this step could be skipped in game SceneObjectsFactory::SynchronizePrefabInstances(context, prefabSyncData); - // Call post load event to connect all scene actors + // Initialize scene objects { - PROFILE_CPU_NAMED("Post Load"); + PROFILE_CPU_NAMED("Initialize"); for (int32 i = 0; i < sceneObjects->Count(); i++) { SceneObject* obj = sceneObjects->At(i); if (obj) - obj->PostLoad(); - } - } + { + obj->Initialize(); - // Delete objects without parent - for (int32 i = 1; i < objectsCount; i++) - { - SceneObject* obj = sceneObjects->At(i); - if (obj && obj->GetParent() == nullptr) - { - LOG(Warning, "Scene object {0} {1} has missing parent object after load. Removing it.", obj->GetID(), obj->ToString()); - obj->DeleteObject(); + // Delete objects without parent + if (i != 0 && obj->GetParent() == nullptr) + { + LOG(Warning, "Scene object {0} {1} has missing parent object after load. Removing it.", obj->GetID(), obj->ToString()); + obj->DeleteObject(); + } + } } } diff --git a/Source/Engine/Level/Prefabs/Prefab.Apply.cpp b/Source/Engine/Level/Prefabs/Prefab.Apply.cpp index f8740d2a0..30e451105 100644 --- a/Source/Engine/Level/Prefabs/Prefab.Apply.cpp +++ b/Source/Engine/Level/Prefabs/Prefab.Apply.cpp @@ -430,7 +430,7 @@ bool PrefabInstanceData::SynchronizePrefabInstances(Array& p for (int32 i = existingObjectsCount; i < sceneObjects->Count(); i++) { SceneObject* obj = sceneObjects.Value->At(i); - obj->PostLoad(); + obj->Initialize(); } // Synchronize existing objects logic with deserialized state (fire events) @@ -470,8 +470,6 @@ bool PrefabInstanceData::SynchronizePrefabInstances(Array& p if (Script* script = dynamic_cast(obj)) { - if (Editor::IsPlayMode || script->_executeInEditor) - script->OnAwake(); if (script->GetParent() && !script->_wasEnableCalled && script->GetParent()->IsActiveInHierarchy() && script->GetParent()->GetScene()) script->Enable(); } @@ -1010,7 +1008,7 @@ bool Prefab::ApplyAllInternal(Actor* targetActor, bool linkTargetActorObjectToPr auto obj = sceneObjects.Value->At(i); if (obj) { - obj->PostLoad(); + obj->Initialize(); } } diff --git a/Source/Engine/Level/Prefabs/PrefabManager.cpp b/Source/Engine/Level/Prefabs/PrefabManager.cpp index c5aa72611..d0d47926d 100644 --- a/Source/Engine/Level/Prefabs/PrefabManager.cpp +++ b/Source/Engine/Level/Prefabs/PrefabManager.cpp @@ -190,9 +190,7 @@ Actor* PrefabManager::SpawnPrefab(Prefab* prefab, Actor* parent, DictionaryAt(i); if (obj) - { - obj->PostLoad(); - } + obj->Initialize(); } // Synchronize prefab instances (prefab may have new objects added or some removed so deserialized instances need to synchronize with it) diff --git a/Source/Engine/Level/Scene/Scene.cpp b/Source/Engine/Level/Scene/Scene.cpp index 6c25c2f89..410061d16 100644 --- a/Source/Engine/Level/Scene/Scene.cpp +++ b/Source/Engine/Level/Scene/Scene.cpp @@ -339,24 +339,13 @@ void Scene::OnDeleteObject() Actor::OnDeleteObject(); } -void Scene::PostLoad() +void Scene::Initialize() { // Initialize _parent = nullptr; _scene = this; - // Base - Actor::PostLoad(); -} - -void Scene::PostSpawn() -{ - // Initialize - _parent = nullptr; - _scene = this; - - // Base - Actor::PostSpawn(); + Actor::Initialize(); } void Scene::BeginPlay(SceneBeginData* data) diff --git a/Source/Engine/Level/Scene/Scene.h b/Source/Engine/Level/Scene/Scene.h index 27b09a8f9..65108996c 100644 --- a/Source/Engine/Level/Scene/Scene.h +++ b/Source/Engine/Level/Scene/Scene.h @@ -137,8 +137,7 @@ public: protected: // [Actor] - void PostLoad() override; - void PostSpawn() override; + void Initialize() override; void BeginPlay(SceneBeginData* data) override; void OnTransformChanged() override; }; diff --git a/Source/Engine/Level/SceneObject.h b/Source/Engine/Level/SceneObject.h index a69eaada2..438c9b776 100644 --- a/Source/Engine/Level/SceneObject.h +++ b/Source/Engine/Level/SceneObject.h @@ -97,7 +97,6 @@ public: /// /// Determines whether object is during play (spawned/loaded and fully initialized). /// - /// true if object is during play; otherwise, false. FORCE_INLINE bool IsDuringPlay() const { return (Flags & ObjectFlags::IsDuringPlay) != 0; @@ -207,14 +206,9 @@ public: public: /// - /// Called after whole scene or local group of scene objects deserialization. + /// Called after object loading or spawning to initialize the object (eg. call OnAwake for scripts) but before BeginPlay. Initialization should be performed only within a single SceneObject (use BeginPlay to initialize with a scene). /// - virtual void PostLoad() = 0; - - /// - /// Called after spawning scene object to the level (similar to the PostLoad but only for spawned objects at runtime). - /// - virtual void PostSpawn() = 0; + virtual void Initialize() = 0; /// /// Called when adding object to the game. diff --git a/Source/Engine/Scripting/Script.cpp b/Source/Engine/Scripting/Script.cpp index 7f53b8e7a..1bc0448ad 100644 --- a/Source/Engine/Scripting/Script.cpp +++ b/Source/Engine/Scripting/Script.cpp @@ -114,7 +114,7 @@ void Script::SetParent(Actor* value, bool canBreakPrefabLink) if (value && value->IsDuringPlay() && !IsDuringPlay()) { // Prepare for gameplay - PostSpawn(); + Initialize(); { SceneBeginData beginData; BeginPlay(&beginData); @@ -122,10 +122,6 @@ void Script::SetParent(Actor* value, bool canBreakPrefabLink) } // Fire events for scripting - CHECK_EXECUTE_IN_EDITOR - { - OnAwake(); - } if (GetEnabled()) { Start(); @@ -265,24 +261,21 @@ const Guid& Script::GetSceneObjectId() const return GetID(); } -void Script::PostLoad() +void Script::Initialize() { + ASSERT(!IsDuringPlay()); + if (Flags & ObjectFlags::IsManagedType || Flags & ObjectFlags::IsCustomScriptingType) SetupType(); // Use lazy creation for the managed instance, just register the object if (!IsRegistered()) RegisterObject(); -} -void Script::PostSpawn() -{ - if (Flags & ObjectFlags::IsManagedType || Flags & ObjectFlags::IsCustomScriptingType) - SetupType(); - - // Create managed object - if (!HasManagedInstance()) - CreateManaged(); + CHECK_EXECUTE_IN_EDITOR + { + OnAwake(); + } } void Script::BeginPlay(SceneBeginData* data) diff --git a/Source/Engine/Scripting/Script.h b/Source/Engine/Scripting/Script.h index dbf83e50c..3ff0f78d1 100644 --- a/Source/Engine/Scripting/Script.h +++ b/Source/Engine/Scripting/Script.h @@ -10,12 +10,11 @@ /// API_CLASS(Abstract) class FLAXENGINE_API Script : public SceneObject { -DECLARE_SCRIPTING_TYPE(Script); + DECLARE_SCRIPTING_TYPE(Script); friend Actor; friend SceneTicking; friend class PrefabInstanceData; protected: - int32 _enabled : 1; int32 _tickFixedUpdate : 1; int32 _tickUpdate : 1; @@ -27,7 +26,6 @@ protected: #endif public: - /// /// Gets value indicating if script is active. /// @@ -54,7 +52,6 @@ public: API_PROPERTY() void SetActor(Actor* value); public: - /// /// Called after the object is loaded. /// @@ -77,7 +74,7 @@ public: } /// - /// Called before the object will be destroyed.. + /// Called before the object will be destroyed. /// API_FUNCTION(Attributes="NoAnimate") virtual void OnDestroy() { @@ -126,14 +123,12 @@ public: } private: - void SetupType(); void Start(); void Enable(); void Disable(); public: - // [ScriptingObject] String ToString() const override; void OnDeleteObject() override; @@ -143,8 +138,7 @@ public: void SetParent(Actor* value, bool canBreakPrefabLink = true) override; int32 GetOrderInParent() const override; void SetOrderInParent(int32 index) override; - void PostLoad() override; - void PostSpawn() override; + void Initialize() override; void BeginPlay(SceneBeginData* data) override; void EndPlay() override; void Serialize(SerializeStream& stream, const void* otherObj) override;