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 | |
15 | namespace 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 | |