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