1//************************************ bs::framework - Copyright 2018 Marko Pintera **************************************//
2//*********** Licensed under the MIT license. See LICENSE.md for full terms. This notice is not to be removed. ***********//
3#pragma once
4
5#include "BsCorePrerequisites.h"
6#include "Utility/BsModule.h"
7#include "Scene/BsGameObject.h"
8
9namespace bs
10{
11 /** @addtogroup Scene-Internal
12 * @{
13 */
14
15 /** Possible modes to use when deserializing game objects. */
16 enum GameObjectDeserializationModeFlags
17 {
18 /** All handles will point to old ID that were restored from the deserialized file. */
19 GODM_UseOriginalIds = 0x01,
20 /** All handles will point to new IDs that were given to the deserialized GameObjects. */
21 GODM_UseNewIds = 0x02,
22 /** Handles pointing to GameObjects outside of the currently deserialized set
23 will attempt to be restored in case those objects are still active. */
24 GODM_RestoreExternal = 0x04,
25 /** Handles pointing to GameObjects outside of the currently deserialized set
26 will be broken. */
27 GODM_BreakExternal = 0x08,
28 /** Handles pointing to GameObjects that cannot be found will not be set to null. */
29 GODM_KeepMissing = 0x10,
30 /** When enabled, new UUIDs will be generated for all deserialized game objects. */
31 GODM_UseNewUUID = 0x20
32 };
33
34 /**
35 * Tracks GameObject creation and destructions. Also resolves GameObject references from GameObject handles.
36 *
37 * @note Sim thread only.
38 */
39 class BS_CORE_EXPORT GameObjectManager : public Module<GameObjectManager>
40 {
41 public:
42 GameObjectManager() = default;
43 ~GameObjectManager();
44
45 /**
46 * Registers a new GameObject and returns the handle to the object.
47 *
48 * @param[in] object Constructed GameObject to wrap in the handle and initialize.
49 * @return Handle to the GameObject.
50 *
51 * @note Thread safe.
52 */
53 GameObjectHandleBase registerObject(const SPtr<GameObject>& object);
54
55 /**
56 * Unregisters a GameObject. Handles to this object will no longer be valid after this call. This should be called
57 * whenever a GameObject is destroyed.
58 *
59 * @note Thread safe.
60 */
61 void unregisterObject(GameObjectHandleBase& object);
62
63 /**
64 * Attempts to find a GameObject handle based on the GameObject instance ID. Returns empty handle if ID cannot be
65 * found.
66 *
67 * @note Thread safe.
68 */
69 GameObjectHandleBase getObject(UINT64 id) const;
70
71 /**
72 * Attempts to find a GameObject handle based on the GameObject instance ID. Returns true if object with the
73 * specified ID is found, false otherwise.
74 *
75 * @note Thread safe.
76 */
77 bool tryGetObject(UINT64 id, GameObjectHandleBase& object) const;
78
79 /**
80 * Checks if the GameObject with the specified instance ID exists.
81 *
82 * @note Thread safe.
83 */
84 bool objectExists(UINT64 id) const;
85
86 /**
87 * Changes the instance ID by which an object can be retrieved by.
88 *
89 * @note Caller is required to update the object itself with the new ID.
90 * @note Thread safe.
91 */
92 void remapId(UINT64 oldId, UINT64 newId);
93
94 /**
95 * Allocates a new unique game object ID.
96 *
97 * @note Thread safe.
98 */
99 UINT64 reserveId();
100
101 /** Queues the object to be destroyed at the end of a GameObject update cycle. */
102 void queueForDestroy(const GameObjectHandleBase& object);
103
104 /** Destroys any GameObjects that were queued for destruction. */
105 void destroyQueuedObjects();
106
107 /** Triggered when a game object is being destroyed. */
108 Event<void(const HGameObject&)> onDestroyed;
109
110 private:
111 std::atomic<UINT64> mNextAvailableID = { 1 } ; // 0 is not a valid ID
112 Map<UINT64, GameObjectHandleBase> mObjects;
113 Map<UINT64, GameObjectHandleBase> mQueuedForDestroy;
114
115 mutable Mutex mMutex;
116 };
117
118 /** Resolves game object handles and ID during deserialization of a game object hierarchy. */
119 class BS_CORE_EXPORT GameObjectDeserializationState
120 {
121 private:
122 /** Contains data for an yet unresolved game object handle. */
123 struct UnresolvedHandle
124 {
125 UINT64 originalInstanceId;
126 GameObjectHandleBase handle;
127 };
128
129 public:
130 /**
131 * Starts game object deserialization.
132 *
133 * @param[in] options One or a combination of GameObjectDeserializationModeFlags, controlling how
134 * are game objects deserialized.
135 */
136 GameObjectDeserializationState(UINT32 options = GODM_UseNewIds | GODM_BreakExternal);
137 ~GameObjectDeserializationState();
138
139 /** Queues the specified handle and resolves it when deserialization ends. */
140 void registerUnresolvedHandle(UINT64 originalId, GameObjectHandleBase& object);
141
142 /** Notifies the system about a new deserialized game object and its original ID. */
143 void registerObject(UINT64 originalId, GameObjectHandleBase& object);
144
145 /** Registers a callback that will be triggered when GameObject serialization ends. */
146 void registerOnDeserializationEndCallback(std::function<void()> callback);
147
148 /** Resolves all registered handles and objects, and triggers end callbacks. */
149 void resolve();
150
151 private:
152 UnorderedMap<UINT64, UINT64> mIdMapping;
153 UnorderedMap<UINT64, SPtr<GameObjectHandleData>> mUnresolvedHandleData;
154 UnorderedMap<UINT64, GameObjectHandleBase> mDeserializedObjects;
155 Vector<UnresolvedHandle> mUnresolvedHandles;
156 Vector<std::function<void()>> mEndCallbacks;
157 UINT32 mOptions;
158 };
159
160 /** @} */
161}