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/BsGameObject.h" |
8 | #include "Scene/BsSceneObject.h" |
9 | #include "Scene/BsGameObjectManager.h" |
10 | |
11 | namespace bs |
12 | { |
13 | /** @cond RTTI */ |
14 | /** @addtogroup RTTI-Impl-Core |
15 | * @{ |
16 | */ |
17 | |
18 | /** Provides temporary storage for data used during GameObject deserialization. */ |
19 | struct GODeserializationData |
20 | { |
21 | SPtr<GameObject> ptr; |
22 | UINT64 originalId = 0; |
23 | }; |
24 | |
25 | class BS_CORE_EXPORT GameObjectRTTI : public RTTIType<GameObject, IReflectable, GameObjectRTTI> |
26 | { |
27 | private: |
28 | BS_BEGIN_RTTI_MEMBERS |
29 | BS_RTTI_MEMBER_PLAIN(mName, 1) |
30 | BS_RTTI_MEMBER_PLAIN(mLinkId, 2) |
31 | BS_RTTI_MEMBER_PLAIN(mUUID, 3) |
32 | BS_END_RTTI_MEMBERS |
33 | |
34 | UINT64& getInstanceID(GameObject* obj) { return obj->mInstanceData->mInstanceId; } |
35 | void setInstanceID(GameObject* obj, UINT64& instanceId) |
36 | { |
37 | // We record the ID for later use. Any child RTTI of GameObject must call GameObjectManager::registerObject |
38 | // with this ID, so we know how to map deserialized GO handles to live objects, otherwise the handle |
39 | // references will get broken. |
40 | GameObject* go = static_cast<GameObject*>(obj); |
41 | GODeserializationData& deserializationData = any_cast_ref<GODeserializationData>(go->mRTTIData); |
42 | |
43 | deserializationData.originalId = instanceId; |
44 | } |
45 | |
46 | public: |
47 | GameObjectRTTI() |
48 | { |
49 | addPlainField("mInstanceID" , 0, &GameObjectRTTI::getInstanceID, &GameObjectRTTI::setInstanceID); |
50 | } |
51 | |
52 | void onDeserializationStarted(IReflectable* obj, SerializationContext* context) override |
53 | { |
54 | GameObject* gameObject = static_cast<GameObject*>(obj); |
55 | |
56 | // It's possible we're just accessing the game object fields, in which case the process below is not needed |
57 | // (it's only required for new game objects). |
58 | if (gameObject->mRTTIData.empty()) |
59 | return; |
60 | |
61 | SPtr<GameObject> gameObjectPtr = any_cast<SPtr<GameObject>>(gameObject->mRTTIData); |
62 | |
63 | // Every GameObject must store GODeserializationData in its RTTI data field during deserialization |
64 | gameObject->mRTTIData = GODeserializationData(); |
65 | GODeserializationData& deserializationData = any_cast_ref<GODeserializationData>(gameObject->mRTTIData); |
66 | |
67 | // Store shared pointer since the system only provides us with raw ones |
68 | deserializationData.ptr = gameObjectPtr; |
69 | } |
70 | |
71 | const String& getRTTIName() override |
72 | { |
73 | static String name = "GameObject" ; |
74 | return name; |
75 | } |
76 | |
77 | UINT32 getRTTIId() override |
78 | { |
79 | return TID_GameObject; |
80 | } |
81 | |
82 | SPtr<IReflectable> newRTTIObject() override |
83 | { |
84 | BS_EXCEPT(InternalErrorException, "Cannot instantiate an abstract class." ); |
85 | return nullptr; |
86 | } |
87 | }; |
88 | |
89 | /** @} */ |
90 | /** @endcond */ |
91 | } |