Refactor scene objects initialization to call OnAwake before all OnStart

#520
This commit is contained in:
Wojtek Figat
2022-07-17 17:05:59 +02:00
parent 9aff782907
commit 3239150a61
14 changed files with 59 additions and 114 deletions

View File

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

View File

@@ -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)
{

View File

@@ -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++)
{

View File

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

View File

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

View File

@@ -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;
};

View File

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

View File

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

View File

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

View File

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

View File

@@ -137,8 +137,7 @@ public:
protected:
// [Actor]
void PostLoad() override;
void PostSpawn() override;
void Initialize() override;
void BeginPlay(SceneBeginData* data) override;
void OnTransformChanged() override;
};

View File

@@ -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.

View File

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

View File

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