Refactor scene objects initialization to call OnAwake before all OnStart
#520
This commit is contained in:
@@ -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();
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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<byte>& data, Array<Actor*>& 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++)
|
||||
{
|
||||
|
||||
@@ -650,6 +650,11 @@ public:
|
||||
/// </summary>
|
||||
void UnregisterObjectHierarchy();
|
||||
|
||||
/// <summary>
|
||||
/// Calls Initialize for all objects in the actor hierarchy.
|
||||
/// </summary>
|
||||
void InitializeHierarchy();
|
||||
|
||||
public:
|
||||
/// <summary>
|
||||
/// 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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -178,7 +178,7 @@ bool LevelImpl::spawnActor(Actor* actor, Actor* parent)
|
||||
if (actor->Is<Scene>())
|
||||
{
|
||||
// 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -430,7 +430,7 @@ bool PrefabInstanceData::SynchronizePrefabInstances(Array<PrefabInstanceData>& 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<PrefabInstanceData>& p
|
||||
|
||||
if (Script* script = dynamic_cast<Script*>(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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -190,9 +190,7 @@ Actor* PrefabManager::SpawnPrefab(Prefab* prefab, Actor* parent, Dictionary<Guid
|
||||
{
|
||||
auto obj = sceneObjects->At(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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -137,8 +137,7 @@ public:
|
||||
|
||||
protected:
|
||||
// [Actor]
|
||||
void PostLoad() override;
|
||||
void PostSpawn() override;
|
||||
void Initialize() override;
|
||||
void BeginPlay(SceneBeginData* data) override;
|
||||
void OnTransformChanged() override;
|
||||
};
|
||||
|
||||
@@ -97,7 +97,6 @@ public:
|
||||
/// <summary>
|
||||
/// Determines whether object is during play (spawned/loaded and fully initialized).
|
||||
/// </summary>
|
||||
/// <returns><c>true</c> if object is during play; otherwise, <c>false</c>.</returns>
|
||||
FORCE_INLINE bool IsDuringPlay() const
|
||||
{
|
||||
return (Flags & ObjectFlags::IsDuringPlay) != 0;
|
||||
@@ -207,14 +206,9 @@ public:
|
||||
|
||||
public:
|
||||
/// <summary>
|
||||
/// 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).
|
||||
/// </summary>
|
||||
virtual void PostLoad() = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Called after spawning scene object to the level (similar to the PostLoad but only for spawned objects at runtime).
|
||||
/// </summary>
|
||||
virtual void PostSpawn() = 0;
|
||||
virtual void Initialize() = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Called when adding object to the game.
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -10,12 +10,11 @@
|
||||
/// </summary>
|
||||
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:
|
||||
|
||||
/// <summary>
|
||||
/// Gets value indicating if script is active.
|
||||
/// </summary>
|
||||
@@ -54,7 +52,6 @@ public:
|
||||
API_PROPERTY() void SetActor(Actor* value);
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Called after the object is loaded.
|
||||
/// </summary>
|
||||
@@ -77,7 +74,7 @@ public:
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called before the object will be destroyed..
|
||||
/// Called before the object will be destroyed.
|
||||
/// </summary>
|
||||
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;
|
||||
|
||||
Reference in New Issue
Block a user