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 "Reflection/BsRTTIType.h"
7#include "Scene/BsSceneObject.h"
8#include "Scene/BsGameObjectHandle.h"
9#include "Scene/BsGameObjectManager.h"
10#include "Scene/BsComponent.h"
11#include "Private/RTTI/BsGameObjectRTTI.h"
12#include "Scene/BsPrefabDiff.h"
13#include "Utility/BsUtility.h"
14
15namespace bs
16{
17 /** @cond RTTI */
18 /** @addtogroup RTTI-Impl-Core
19 * @{
20 */
21
22 class BS_CORE_EXPORT SceneObjectRTTI : public RTTIType<SceneObject, GameObject, SceneObjectRTTI>
23 {
24 private:
25 Transform& getTransform(SceneObject* obj) { return obj->mWorldTfrm; }
26 void setTransform(SceneObject* obj, Transform& value) { obj->mWorldTfrm = value; }
27
28 Transform& getLocalTransform(SceneObject* obj) { return obj->mLocalTfrm; }
29 void setLocalTransform(SceneObject* obj, Transform& value) { obj->mLocalTfrm = value; }
30
31 bool& getActive(SceneObject* obj) { return obj->mActiveSelf; }
32 void setActive(SceneObject* obj, bool& value) { obj->mActiveSelf = value; }
33
34 SPtr<SceneObject> getChild(SceneObject* obj, UINT32 idx) { return obj->mChildren[idx].getInternalPtr(); }
35 void setChild(SceneObject* obj, UINT32 idx, SPtr<SceneObject> param)
36 {
37 // It's important that child indices remain the same after deserialization, as some systems (like SO
38 // record/restore) depend on it
39 if(idx >= mChildren.size())
40 mChildren.resize(idx + 1);
41
42 mChildren[idx] = param;
43 }
44
45 UINT32 getNumChildren(SceneObject* obj) { return (UINT32)obj->mChildren.size(); }
46 void setNumChildren(SceneObject* obj, UINT32 size) { /* DO NOTHING */ }
47
48 // NOTE - These can only be set sequentially, specific array index is ignored
49 SPtr<Component> getComponent(SceneObject* obj, UINT32 idx) { return obj->mComponents[idx].getInternalPtr(); }
50 void setComponent(SceneObject* obj, UINT32 idx, SPtr<Component> param)
51 {
52 // It's important that child indices remain the same after deserialization, as some systems (like SO
53 // record/restore) depend on it
54 if(idx >= mComponents.size())
55 mComponents.resize(idx + 1);
56
57 mComponents[idx] = param;
58 }
59 UINT32 getNumComponents(SceneObject* obj) { return (UINT32)obj->mComponents.size(); }
60 void setNumComponents(SceneObject* obj, UINT32 size) { /* DO NOTHING */ }
61
62 UUID& getPrefabLink(SceneObject* obj) { return obj->mPrefabLinkUUID; }
63 void setPrefabLink(SceneObject* obj, UUID& value) { obj->mPrefabLinkUUID = value; }
64
65 SPtr<PrefabDiff> getPrefabDiff(SceneObject* obj) { return obj->mPrefabDiff; }
66 void setPrefabDiff(SceneObject* obj, SPtr<PrefabDiff> value) { obj->mPrefabDiff = value; }
67
68 UINT32& getFlags(SceneObject* obj) { return obj->mFlags; }
69 void setFlags(SceneObject* obj, UINT32& value) { obj->mFlags = value; }
70
71 UINT32& getPrefabHash(SceneObject* obj) { return obj->mPrefabHash; }
72 void setPrefabHash(SceneObject* obj, UINT32& value) { obj->mPrefabHash = value; }
73
74 ObjectMobility& getMobility(SceneObject* obj) { return obj->mMobility; }
75 void setMobility(SceneObject* obj, ObjectMobility& value) { obj->mMobility = value; }
76 public:
77 SceneObjectRTTI()
78 {
79 addReflectablePtrArrayField("mChildren", 0, &SceneObjectRTTI::getChild,
80 &SceneObjectRTTI::getNumChildren, &SceneObjectRTTI::setChild, &SceneObjectRTTI::setNumChildren);
81 addReflectablePtrArrayField("mComponents", 1, &SceneObjectRTTI::getComponent,
82 &SceneObjectRTTI::getNumComponents, &SceneObjectRTTI::setComponent, &SceneObjectRTTI::setNumComponents);
83 addPlainField("mPrefabLink", 2, &SceneObjectRTTI::getPrefabLink, &SceneObjectRTTI::setPrefabLink);
84 addPlainField("mFlags", 3, &SceneObjectRTTI::getFlags, &SceneObjectRTTI::setFlags);
85 addReflectablePtrField("mPrefabDiff", 4, &SceneObjectRTTI::getPrefabDiff, &SceneObjectRTTI::setPrefabDiff);
86 addPlainField("mPrefabHash", 5, &SceneObjectRTTI::getPrefabHash, &SceneObjectRTTI::setPrefabHash);
87 addPlainField("mActiveSelf", 9, &SceneObjectRTTI::getActive, &SceneObjectRTTI::setActive);
88 addPlainField("mMobility", 10, &SceneObjectRTTI::getMobility, &SceneObjectRTTI::setMobility);
89
90 addReflectableField("mWorldTfrm", 11, &SceneObjectRTTI::getTransform, &SceneObjectRTTI::setTransform);
91 addReflectableField("mLocalTfrm", 12, &SceneObjectRTTI::getLocalTransform, &SceneObjectRTTI::setLocalTransform);
92 }
93
94 void onDeserializationStarted(IReflectable* obj, SerializationContext* context) override
95 {
96 // If this is the root scene object we're deserializing, activate game object deserialization so the system
97 // can resolve deserialized handles to the newly created objects
98 SceneObject* so = static_cast<SceneObject*>(obj);
99
100 // It's possible we're just accessing the game object fields, in which case the process below is not needed
101 // (it's only required for new scene objects).
102 if (so->mRTTIData.empty())
103 return;
104
105 if(context == nullptr || !rtti_is_of_type<CoreSerializationContext>(context))
106 return;
107
108 auto coreContext = static_cast<CoreSerializationContext*>(context);
109 if(!coreContext->goDeserializationActive)
110 {
111 if (!coreContext->goState)
112 coreContext->goState = bs_shared_ptr_new<GameObjectDeserializationState>();
113
114 mIsDeserializationParent = true;
115 coreContext->goDeserializationActive = true;
116 }
117 }
118
119 void onDeserializationEnded(IReflectable* obj, SerializationContext* context) override
120 {
121 SceneObject* so = static_cast<SceneObject*>(obj);
122
123 // It's possible we're just accessing the game object fields, in which case the process below is not needed
124 // (it's only required for new scene objects).
125 if (so->mRTTIData.empty())
126 return;
127
128 BS_ASSERT(context != nullptr && rtti_is_of_type<CoreSerializationContext>(context));
129 auto coreContext = static_cast<CoreSerializationContext*>(context);
130
131 GODeserializationData& goDeserializationData = any_cast_ref<GODeserializationData>(so->mRTTIData);
132
133 // Register the newly created SO with the GameObjectManager and provide it with the original ID so that
134 // deserialized handles pointing to this object can be resolved.
135 SPtr<SceneObject> soPtr = std::static_pointer_cast<SceneObject>(goDeserializationData.ptr);
136
137 HSceneObject soHandle = SceneObject::createInternal(soPtr);
138 coreContext->goState->registerObject(goDeserializationData.originalId, soHandle);
139
140 // We stored all components and children in a temporary structure because they rely on the SceneObject being
141 // initialized with the GameObjectManager. Now that it is, we add them.
142 for (auto& component : mComponents)
143 so->addComponentInternal(component);
144
145 for (auto& child : mChildren)
146 {
147 if(child != nullptr)
148 child->_setParent(so->mThisHandle, false);
149 }
150
151 if(so->mUUID.empty() || ((coreContext->flags & GODM_UseNewUUID) != 0))
152 so->mUUID = UUIDGenerator::generateRandom();
153
154 // If this is the deserialization parent, end deserialization (which resolves all game object handles, if we
155 // provided valid IDs), and instantiate (i.e. activate) the deserialized hierarchy.
156 if (mIsDeserializationParent)
157 {
158 coreContext->goState->resolve();
159 coreContext->goDeserializationActive = false;
160
161 bool parentActive = true;
162 if (so->getParent() != nullptr)
163 parentActive = so->getParent()->getActive();
164
165 so->setActiveHierarchy(parentActive, false);
166
167 if ((so->mFlags & SOF_DontInstantiate) == 0)
168 so->_instantiate();
169 }
170
171 so->mRTTIData = nullptr;
172 }
173
174 const String& getRTTIName() override
175 {
176 static String name = "SceneObject";
177 return name;
178 }
179
180 UINT32 getRTTIId() override
181 {
182 return TID_SceneObject;
183 }
184
185 SPtr<IReflectable> newRTTIObject() override
186 {
187 SPtr<SceneObject> sceneObject = SPtr<SceneObject>(new (bs_alloc<SceneObject>()) SceneObject("", SOF_DontInstantiate),
188 &bs_delete<SceneObject>, StdAlloc<SceneObject>());
189 sceneObject->mRTTIData = sceneObject;
190
191 return sceneObject;
192 }
193
194 private:
195 bool mIsDeserializationParent = false;
196 Vector<SPtr<SceneObject>> mChildren;
197 Vector<SPtr<Component>> mComponents;
198 };
199
200 /** @} */
201 /** @endcond */
202}
203