// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved. #pragma once #include "SceneObject.h" #include "Engine/Core/Collections/Dictionary.h" #include "Engine/Platform/CriticalSection.h" #include "Engine/Threading/ThreadLocal.h" /// /// Helper class for scene objects creation and deserialization utilities. /// class FLAXENGINE_API SceneObjectsFactory { public: struct PrefabInstance { int32 StatIndex; int32 RootIndex; Guid RootId; Prefab* Prefab; bool FixRootParent = false; Dictionary IdsMapping; }; struct Context { ISerializeModifier* Modifier; bool Async = false; Array Instances; Dictionary ObjectToInstance; CriticalSection Locker; ThreadLocal Modifiers; #if USE_EDITOR HashSet DeprecatedPrefabs; #endif Context(ISerializeModifier* modifier); ~Context(); ISerializeModifier* GetModifier(); void SetupIdsMapping(const SceneObject* obj, ISerializeModifier* modifier) const; }; /// /// Creates the scene object from the specified data value. Does not perform deserialization. /// /// The serialization context. /// The serialized data stream. static SceneObject* Spawn(Context& context, const ISerializable::DeserializeStream& stream); /// /// Deserializes the scene object from the specified data value. /// /// The serialization context. /// The instance to deserialize. /// The serialized data stream. static void Deserialize(Context& context, SceneObject* obj, ISerializable::DeserializeStream& stream); /// /// Handles the object deserialization error. /// /// The value. static void HandleObjectDeserializationError(const ISerializable::DeserializeStream& value); /// /// Creates a new actor object of the given type identifier. /// [Deprecated: 18.07.2019 expires 18.07.2020] /// /// The type identifier. /// The actor identifier. /// The created actor, or null if failed. static Actor* CreateActor(int32 typeId, const Guid& id); public: struct PrefabSyncData { friend SceneObjectsFactory; friend class PrefabManager; // The created scene objects. Collection can be modified (eg. for spawning missing objects). Array& SceneObjects; // The scene objects data. const ISerializable::DeserializeStream& Data; // The objects deserialization modifier. Collection will be modified (eg. for spawned objects mapping). ISerializeModifier* Modifier; PrefabSyncData(Array& sceneObjects, const ISerializable::DeserializeStream& data, ISerializeModifier* modifier); void InitNewObjects(); private: struct NewObj { Prefab* Prefab; const ISerializable::DeserializeStream* PrefabData; Guid PrefabObjectId; Guid Id; }; int32 InitialCount; Array NewObjects; }; /// /// Initializes the prefab instances inside the scene objects for proper references deserialization. /// /// /// Should be called after spawning scene objects but before scene objects deserialization. /// /// The serialization context. /// The sync data. static void SetupPrefabInstances(Context& context, const PrefabSyncData& data); /// /// Synchronizes the new prefab instances by spawning missing objects that were added to prefab but were not saved with scene objects collection. /// /// /// Should be called after spawning scene objects but before scene objects deserialization and PostLoad event when scene objects hierarchy is ready (parent-child relation exists). But call it before Init and BeginPlay events. /// /// The serialization context. /// The sync data. static void SynchronizeNewPrefabInstances(Context& context, PrefabSyncData& data); /// /// Synchronizes the prefab instances. Prefabs may have objects removed so deserialized instances need to synchronize with it. Handles also changing prefab object parent in the instance. /// /// /// Should be called after scene objects deserialization and PostLoad event when scene objects hierarchy is ready (parent-child relation exists). But call it before Init and BeginPlay events. /// /// The serialization context. /// The sync data. static void SynchronizePrefabInstances(Context& context, PrefabSyncData& data); private: static void SynchronizeNewPrefabInstances(Context& context, PrefabSyncData& data, Prefab* prefab, Actor* actor, const Guid& actorPrefabObjectId, int32 i, const ISerializable::DeserializeStream& stream); static void SynchronizeNewPrefabInstance(Context& context, PrefabSyncData& data, Prefab* prefab, Actor* actor, const Guid& prefabObjectId); };