Sfoglia il codice sorgente

Refactored managed object serialization so fields are serialized on demand instead of in a pre-process step

Marko Pintera 11 anni fa
parent
commit
2db66e5efb

+ 2 - 2
BansheeCore/Source/BsUtility.cpp

@@ -22,7 +22,7 @@ namespace BansheeEngine
 	void Utility::findResourceDependenciesInternal(IReflectable& obj, bool recursive, Map<String, HResource>& dependencies)
 	void Utility::findResourceDependenciesInternal(IReflectable& obj, bool recursive, Map<String, HResource>& dependencies)
 	{
 	{
 		RTTITypeBase* rtti = obj.getRTTI();
 		RTTITypeBase* rtti = obj.getRTTI();
-		rtti->onDeserializationStarted(&obj);
+		rtti->onSerializationStarted(&obj);
 
 
 		UINT32 numFields = rtti->getNumFields();
 		UINT32 numFields = rtti->getNumFields();
 		for (UINT32 i = 0; i < numFields; i++)
 		for (UINT32 i = 0; i < numFields; i++)
@@ -91,6 +91,6 @@ namespace BansheeEngine
 			}
 			}
 		}
 		}
 
 
-		rtti->onDeserializationEnded(&obj);
+		rtti->onSerializationEnded(&obj);
 	}
 	}
 }
 }

+ 1 - 1
BansheeUtility/Include/BsAny.h

@@ -199,7 +199,7 @@ namespace BansheeEngine
 	template <typename ValueType>
 	template <typename ValueType>
 	ValueType& any_cast_ref(Any& operand)
 	ValueType& any_cast_ref(Any& operand)
 	{
 	{
-		ValueType* result = anyCast<ValueType>(&operand);
+		ValueType* result = any_cast<ValueType>(&operand);
 
 
 		if (result == nullptr)
 		if (result == nullptr)
 			BS_EXCEPT(InvalidStateException, "Failed to cast between Any types.");
 			BS_EXCEPT(InvalidStateException, "Failed to cast between Any types.");

+ 3 - 9
SBansheeEngine/Include/BsManagedSerializableArray.h

@@ -26,22 +26,16 @@ namespace BansheeEngine
 		::MonoClass* mElementMonoClass;
 		::MonoClass* mElementMonoClass;
 
 
 		ManagedSerializableTypeInfoArrayPtr mArrayTypeInfo;
 		ManagedSerializableTypeInfoArrayPtr mArrayTypeInfo;
-		Vector<ManagedSerializableFieldDataPtr> mArrayEntries;
-		
+
 		Vector<UINT32> mNumElements;
 		Vector<UINT32> mNumElements;
 		UINT32 mElemSize;
 		UINT32 mElemSize;
 
 
 		void initMonoObjects();
 		void initMonoObjects();
 
 
 		/**
 		/**
-		 * @brief	Populates internal field data based on currently active managed instance.
-		 */
-		void serializeManagedInstance();
-
-		/**
-		 * @brief	Creates a new managed instance and populates it with stored field data.
+		 * @brief	Creates a new managed instance and populates it with provided entries.
 		 */
 		 */
-		void deserializeManagedInstance();
+		void deserializeManagedInstance(const Vector<ManagedSerializableFieldDataPtr>& entries);
 
 
 		void setFieldData(UINT32 arrayIdx, const ManagedSerializableFieldDataPtr& val);
 		void setFieldData(UINT32 arrayIdx, const ManagedSerializableFieldDataPtr& val);
 		ManagedSerializableFieldDataPtr getFieldData(UINT32 arrayIdx);
 		ManagedSerializableFieldDataPtr getFieldData(UINT32 arrayIdx);

+ 33 - 13
SBansheeEngine/Include/BsManagedSerializableArrayRTTI.h

@@ -13,6 +13,12 @@ namespace BansheeEngine
 	class BS_SCR_BE_EXPORT ManagedSerializableArrayRTTI : public RTTIType<ManagedSerializableArray, IReflectable, ManagedSerializableArrayRTTI>
 	class BS_SCR_BE_EXPORT ManagedSerializableArrayRTTI : public RTTIType<ManagedSerializableArray, IReflectable, ManagedSerializableArrayRTTI>
 	{
 	{
 	private:
 	private:
+		struct DeserializationInfo
+		{
+			Vector<ManagedSerializableFieldDataPtr> fields;
+			bool isGameObjectDeserialization;
+		};
+
 		ManagedSerializableTypeInfoArrayPtr getTypeInfo(ManagedSerializableArray* obj)
 		ManagedSerializableTypeInfoArrayPtr getTypeInfo(ManagedSerializableArray* obj)
 		{
 		{
 			return obj->mArrayTypeInfo;
 			return obj->mArrayTypeInfo;
@@ -55,22 +61,28 @@ namespace BansheeEngine
 
 
 		ManagedSerializableFieldDataPtr getArrayEntry(ManagedSerializableArray* obj, UINT32 arrayIdx)
 		ManagedSerializableFieldDataPtr getArrayEntry(ManagedSerializableArray* obj, UINT32 arrayIdx)
 		{
 		{
-			return obj->mArrayEntries[arrayIdx];
+			return obj->getFieldData(arrayIdx);
 		}
 		}
 
 
 		void setArrayEntry(ManagedSerializableArray* obj, UINT32 arrayIdx, ManagedSerializableFieldDataPtr val)
 		void setArrayEntry(ManagedSerializableArray* obj, UINT32 arrayIdx, ManagedSerializableFieldDataPtr val)
 		{
 		{
-			obj->mArrayEntries[arrayIdx] = val;
+			SPtr<DeserializationInfo> info = any_cast<SPtr<DeserializationInfo>>(obj->mRTTIData);
+			info->fields[arrayIdx] = val;
 		}
 		}
 
 
 		UINT32 getNumArrayEntries(ManagedSerializableArray* obj)
 		UINT32 getNumArrayEntries(ManagedSerializableArray* obj)
 		{
 		{
-			return (UINT32)obj->mArrayEntries.size();
+			UINT32 totalNumElements = 1;
+			for (auto& numElems : obj->mNumElements)
+				totalNumElements *= numElems;
+
+			return totalNumElements;
 		}
 		}
 
 
 		void setNumArrayEntries(ManagedSerializableArray* obj, UINT32 numEntries)
 		void setNumArrayEntries(ManagedSerializableArray* obj, UINT32 numEntries)
 		{
 		{
-			obj->mArrayEntries.resize(numEntries);
+			SPtr<DeserializationInfo> info = any_cast<SPtr<DeserializationInfo>>(obj->mRTTIData);
+			info->fields = Vector<ManagedSerializableFieldDataPtr>(numEntries);
 		}
 		}
 
 
 	public:
 	public:
@@ -84,22 +96,30 @@ namespace BansheeEngine
 				&ManagedSerializableArrayRTTI::setArrayEntry, &ManagedSerializableArrayRTTI::setNumArrayEntries);
 				&ManagedSerializableArrayRTTI::setArrayEntry, &ManagedSerializableArrayRTTI::setNumArrayEntries);
 		}
 		}
 
 
-		virtual void onSerializationStarted(IReflectable* obj)
+		virtual void onDeserializationStarted(IReflectable* obj)
 		{
 		{
 			ManagedSerializableArray* serializableObject = static_cast<ManagedSerializableArray*>(obj);
 			ManagedSerializableArray* serializableObject = static_cast<ManagedSerializableArray*>(obj);
-			serializableObject->serializeManagedInstance();
+
+			serializableObject->mRTTIData = bs_shared_ptr<DeserializationInfo>();
+			SPtr<DeserializationInfo> info = any_cast<SPtr<DeserializationInfo>>(serializableObject->mRTTIData);
+
+			// If we are deserializing a GameObject we need to defer deserializing actual field values
+			// to ensure GameObject handles instances have been fixed up (which only happens after deserialization is done)
+			info->isGameObjectDeserialization = GameObjectManager::instance().isGameObjectDeserializationActive();
+
+			if (info->isGameObjectDeserialization)
+				GameObjectManager::instance().registerOnDeserializationEndCallback([=]() { serializableObject->deserializeManagedInstance(info->fields); });
 		}
 		}
 
 
-		virtual void onDeserializationStarted(IReflectable* obj)
+		virtual void onDeserializationEnded(IReflectable* obj)
 		{
 		{
 			ManagedSerializableArray* serializableObject = static_cast<ManagedSerializableArray*>(obj);
 			ManagedSerializableArray* serializableObject = static_cast<ManagedSerializableArray*>(obj);
+			SPtr<DeserializationInfo> info = any_cast<SPtr<DeserializationInfo>>(serializableObject->mRTTIData);
+			
+			if (!info->isGameObjectDeserialization)
+				serializableObject->deserializeManagedInstance(info->fields);
 
 
-			// If we are deserializing a GameObject we need to defer deserializing actual field values
-			// to ensure GameObject handles instances have been fixed up (which only happens after deserialization is done)
-			if(GameObjectManager::instance().isGameObjectDeserializationActive())
-				GameObjectManager::instance().registerOnDeserializationEndCallback([=] () { serializableObject->deserializeManagedInstance(); });
-			else
-				serializableObject->deserializeManagedInstance();
+			serializableObject->mRTTIData = nullptr;
 		}
 		}
 
 
 		virtual const String& getRTTIName()
 		virtual const String& getRTTIName()

+ 6 - 6
SBansheeEngine/Include/BsManagedSerializableDictionary.h

@@ -48,20 +48,20 @@ namespace BansheeEngine
 		MonoProperty* mValueProp;
 		MonoProperty* mValueProp;
 
 
 		ManagedSerializableTypeInfoDictionaryPtr mDictionaryTypeInfo;
 		ManagedSerializableTypeInfoDictionaryPtr mDictionaryTypeInfo;
-		Vector<ManagedSerializableFieldDataPtr> mKeyEntries;
-		Vector<ManagedSerializableFieldDataPtr> mValueEntries;
 
 
 		void initMonoObjects(MonoClass* dictionaryClass);
 		void initMonoObjects(MonoClass* dictionaryClass);
 
 
 		/**
 		/**
-		 * @brief	Populates internal field data based on currently active managed instance.
+		 * @brief	Populates provided field data arrays based on currently active managed instance.
 		 */
 		 */
-		void serializeManagedInstance();
+		void serializeManagedInstance(Vector<ManagedSerializableFieldDataPtr>& keyEntries, 
+			Vector<ManagedSerializableFieldDataPtr>& valueEntries);
 
 
 		/**
 		/**
-		 * @brief	Creates a new managed instance and populates it with stored field data.
+		 * @brief	Creates a new managed instance and populates it with provided field data.
 		 */
 		 */
-		void deserializeManagedInstance();
+		void deserializeManagedInstance(const Vector<ManagedSerializableFieldDataPtr>& keyEntries, 
+			const Vector<ManagedSerializableFieldDataPtr>& valueEntries);
 
 
 		void setFieldData(const ManagedSerializableFieldDataPtr& key, const ManagedSerializableFieldDataPtr& val);
 		void setFieldData(const ManagedSerializableFieldDataPtr& key, const ManagedSerializableFieldDataPtr& val);
 		Enumerator getEnumerator() const;
 		Enumerator getEnumerator() const;

+ 82 - 13
SBansheeEngine/Include/BsManagedSerializableDictionaryRTTI.h

@@ -13,18 +13,63 @@ namespace BansheeEngine
 	class BS_SCR_BE_EXPORT ManagedSerializableDictionaryRTTI : public RTTIType<ManagedSerializableDictionary, IReflectable, ManagedSerializableDictionaryRTTI>
 	class BS_SCR_BE_EXPORT ManagedSerializableDictionaryRTTI : public RTTIType<ManagedSerializableDictionary, IReflectable, ManagedSerializableDictionaryRTTI>
 	{
 	{
 	private:
 	private:
+		struct SerializationData
+		{
+			Vector<ManagedSerializableFieldDataPtr> keyEntries;
+			Vector<ManagedSerializableFieldDataPtr> valueEntries;
+			bool isGameObjectDeserialization;
+		};
+
 		ManagedSerializableTypeInfoDictionaryPtr getTypeInfo(ManagedSerializableDictionary* obj) { return obj->mDictionaryTypeInfo; }
 		ManagedSerializableTypeInfoDictionaryPtr getTypeInfo(ManagedSerializableDictionary* obj) { return obj->mDictionaryTypeInfo; }
 		void setTypeInfo(ManagedSerializableDictionary* obj, ManagedSerializableTypeInfoDictionaryPtr val) { obj->mDictionaryTypeInfo = val; }
 		void setTypeInfo(ManagedSerializableDictionary* obj, ManagedSerializableTypeInfoDictionaryPtr val) { obj->mDictionaryTypeInfo = val; }
 
 
-		ManagedSerializableFieldDataPtr getKeyEntry(ManagedSerializableDictionary* obj, UINT32 arrayIdx) { return obj->mKeyEntries[arrayIdx]; }
-		void setKeyEntry(ManagedSerializableDictionary* obj, UINT32 arrayIdx, ManagedSerializableFieldDataPtr val) { obj->mKeyEntries[arrayIdx] = val; }
-		UINT32 getNumKeyEntries(ManagedSerializableDictionary* obj) { return (UINT32)obj->mKeyEntries.size(); }
-		void setNumKeyEntries(ManagedSerializableDictionary* obj, UINT32 numEntries) { obj->mKeyEntries.resize(numEntries); }
+		ManagedSerializableFieldDataPtr getKeyEntry(ManagedSerializableDictionary* obj, UINT32 arrayIdx) 
+		{ 
+			SPtr<SerializationData> data = any_cast<SPtr<SerializationData>>(obj->mRTTIData);
+			return data->keyEntries[arrayIdx];
+		}
+
+		void setKeyEntry(ManagedSerializableDictionary* obj, UINT32 arrayIdx, ManagedSerializableFieldDataPtr val) 
+		{ 
+			SPtr<SerializationData> data = any_cast<SPtr<SerializationData>>(obj->mRTTIData);
+			data->keyEntries[arrayIdx] = val;
+		}
+
+		UINT32 getNumKeyEntries(ManagedSerializableDictionary* obj) 
+		{ 
+			SPtr<SerializationData> data = any_cast<SPtr<SerializationData>>(obj->mRTTIData);
+			return (UINT32)data->keyEntries.size();
+		}
+
+		void setNumKeyEntries(ManagedSerializableDictionary* obj, UINT32 numEntries) 
+		{ 
+			SPtr<SerializationData> data = any_cast<SPtr<SerializationData>>(obj->mRTTIData);
+			data->keyEntries.resize(numEntries);
+		}
+
+		ManagedSerializableFieldDataPtr getValueEntry(ManagedSerializableDictionary* obj, UINT32 arrayIdx) 
+		{ 
+			SPtr<SerializationData> data = any_cast<SPtr<SerializationData>>(obj->mRTTIData);
+			return data->valueEntries[arrayIdx];
+		}
+
+		void setValueEntry(ManagedSerializableDictionary* obj, UINT32 arrayIdx, ManagedSerializableFieldDataPtr val) 
+		{ 
+			SPtr<SerializationData> data = any_cast<SPtr<SerializationData>>(obj->mRTTIData);
+			data->valueEntries[arrayIdx] = val;
+		}
+
+		UINT32 getNumValueEntries(ManagedSerializableDictionary* obj) 
+		{ 
+			SPtr<SerializationData> data = any_cast<SPtr<SerializationData>>(obj->mRTTIData);
+			return (UINT32)data->valueEntries.size();
+		}
 
 
-		ManagedSerializableFieldDataPtr getValueEntry(ManagedSerializableDictionary* obj, UINT32 arrayIdx) { return obj->mValueEntries[arrayIdx]; }
-		void setValueEntry(ManagedSerializableDictionary* obj, UINT32 arrayIdx, ManagedSerializableFieldDataPtr val) { obj->mValueEntries[arrayIdx] = val; }
-		UINT32 getNumValueEntries(ManagedSerializableDictionary* obj) { return (UINT32)obj->mValueEntries.size(); }
-		void setNumValueEntries(ManagedSerializableDictionary* obj, UINT32 numEntries) { obj->mValueEntries.resize(numEntries); }
+		void setNumValueEntries(ManagedSerializableDictionary* obj, UINT32 numEntries) 
+		{ 
+			SPtr<SerializationData> data = any_cast<SPtr<SerializationData>>(obj->mRTTIData);
+			data->valueEntries.resize(numEntries);
+		}
 
 
 	public:
 	public:
 		ManagedSerializableDictionaryRTTI()
 		ManagedSerializableDictionaryRTTI()
@@ -39,19 +84,43 @@ namespace BansheeEngine
 		virtual void onSerializationStarted(IReflectable* obj)
 		virtual void onSerializationStarted(IReflectable* obj)
 		{
 		{
 			ManagedSerializableDictionary* serializableObject = static_cast<ManagedSerializableDictionary*>(obj);
 			ManagedSerializableDictionary* serializableObject = static_cast<ManagedSerializableDictionary*>(obj);
-			serializableObject->serializeManagedInstance();
+
+			serializableObject->mRTTIData = bs_shared_ptr<SerializationData>();
+			SPtr<SerializationData> data = any_cast<SPtr<SerializationData>>(serializableObject->mRTTIData);
+
+			serializableObject->serializeManagedInstance(data->keyEntries, data->valueEntries);
+		}
+
+		virtual void onSerializationEnded(IReflectable* obj)
+		{
+			ManagedSerializableDictionary* serializableObject = static_cast<ManagedSerializableDictionary*>(obj);
+			serializableObject->mRTTIData = nullptr;
 		}
 		}
 
 
 		virtual void onDeserializationStarted(IReflectable* obj)
 		virtual void onDeserializationStarted(IReflectable* obj)
 		{
 		{
 			ManagedSerializableDictionary* serializableObject = static_cast<ManagedSerializableDictionary*>(obj);
 			ManagedSerializableDictionary* serializableObject = static_cast<ManagedSerializableDictionary*>(obj);
 
 
+			serializableObject->mRTTIData = bs_shared_ptr<SerializationData>();
+			SPtr<SerializationData> data = any_cast<SPtr<SerializationData>>(serializableObject->mRTTIData);
+
 			// If we are deserializing a GameObject we need to defer deserializing actual field values
 			// If we are deserializing a GameObject we need to defer deserializing actual field values
 			// to ensure GameObject handles instances have been fixed up (which only happens after deserialization is done)
 			// to ensure GameObject handles instances have been fixed up (which only happens after deserialization is done)
-			if(GameObjectManager::instance().isGameObjectDeserializationActive())
-				GameObjectManager::instance().registerOnDeserializationEndCallback([=] () { serializableObject->deserializeManagedInstance(); });
-			else
-				serializableObject->deserializeManagedInstance();
+			data->isGameObjectDeserialization = GameObjectManager::instance().isGameObjectDeserializationActive();
+
+			if (data->isGameObjectDeserialization)
+				GameObjectManager::instance().registerOnDeserializationEndCallback([=]() { serializableObject->deserializeManagedInstance(data->keyEntries, data->valueEntries); });
+		}
+
+		virtual void onDeserializationEnded(IReflectable* obj)
+		{
+			ManagedSerializableDictionary* serializableObject = static_cast<ManagedSerializableDictionary*>(obj);
+			SPtr<SerializationData> data = any_cast<SPtr<SerializationData>>(serializableObject->mRTTIData);
+
+			if (data->isGameObjectDeserialization)
+				serializableObject->deserializeManagedInstance(data->keyEntries, data->valueEntries);
+
+			serializableObject->mRTTIData = nullptr;
 		}
 		}
 
 
 		virtual const String& getRTTIName()
 		virtual const String& getRTTIName()

+ 1 - 8
SBansheeEngine/Include/BsManagedSerializableList.h

@@ -29,21 +29,14 @@ namespace BansheeEngine
 		MonoProperty* mCountProp;
 		MonoProperty* mCountProp;
 
 
 		ManagedSerializableTypeInfoListPtr mListTypeInfo;
 		ManagedSerializableTypeInfoListPtr mListTypeInfo;
-		Vector<ManagedSerializableFieldDataPtr> mListEntries;
-		
 		UINT32 mNumElements;
 		UINT32 mNumElements;
 
 
 		void initMonoObjects(MonoClass* listClass);
 		void initMonoObjects(MonoClass* listClass);
 
 
-		/**
-		 * @brief	Populates internal field data based on currently active managed instance.
-		 */
-		void serializeManagedInstance();
-
 		/**
 		/**
 		 * @brief	Creates a new managed instance and populates it with stored field data.
 		 * @brief	Creates a new managed instance and populates it with stored field data.
 		 */
 		 */
-		void deserializeManagedInstance();
+		void deserializeManagedInstance(const Vector<ManagedSerializableFieldDataPtr>& entries);
 
 
 		void setFieldData(UINT32 arrayIdx, const ManagedSerializableFieldDataPtr& val);
 		void setFieldData(UINT32 arrayIdx, const ManagedSerializableFieldDataPtr& val);
 		void addFieldData(const ManagedSerializableFieldDataPtr& val);
 		void addFieldData(const ManagedSerializableFieldDataPtr& val);

+ 29 - 13
SBansheeEngine/Include/BsManagedSerializableListRTTI.h

@@ -13,6 +13,12 @@ namespace BansheeEngine
 	class BS_SCR_BE_EXPORT ManagedSerializableListRTTI : public RTTIType<ManagedSerializableList, IReflectable, ManagedSerializableListRTTI>
 	class BS_SCR_BE_EXPORT ManagedSerializableListRTTI : public RTTIType<ManagedSerializableList, IReflectable, ManagedSerializableListRTTI>
 	{
 	{
 	private:
 	private:
+		struct DeserializationInfo
+		{
+			Vector<ManagedSerializableFieldDataPtr> fields;
+			bool isGameObjectDeserialization;
+		};
+
 		ManagedSerializableTypeInfoListPtr getTypeInfo(ManagedSerializableList* obj)
 		ManagedSerializableTypeInfoListPtr getTypeInfo(ManagedSerializableList* obj)
 		{
 		{
 			return obj->mListTypeInfo;
 			return obj->mListTypeInfo;
@@ -35,22 +41,24 @@ namespace BansheeEngine
 
 
 		ManagedSerializableFieldDataPtr getListEntry(ManagedSerializableList* obj, UINT32 arrayIdx)
 		ManagedSerializableFieldDataPtr getListEntry(ManagedSerializableList* obj, UINT32 arrayIdx)
 		{
 		{
-			return obj->mListEntries[arrayIdx];
+			return obj->getFieldData(arrayIdx);
 		}
 		}
 
 
 		void setListEntry(ManagedSerializableList* obj, UINT32 arrayIdx, ManagedSerializableFieldDataPtr val)
 		void setListEntry(ManagedSerializableList* obj, UINT32 arrayIdx, ManagedSerializableFieldDataPtr val)
 		{
 		{
-			obj->mListEntries[arrayIdx] = val;
+			SPtr<DeserializationInfo> info = any_cast<SPtr<DeserializationInfo>>(obj->mRTTIData);
+			info->fields[arrayIdx] = val;
 		}
 		}
 
 
 		UINT32 getNumListEntries(ManagedSerializableList* obj)
 		UINT32 getNumListEntries(ManagedSerializableList* obj)
 		{
 		{
-			return (UINT32)obj->mListEntries.size();
+			return obj->mNumElements;
 		}
 		}
 
 
 		void setNumListEntries(ManagedSerializableList* obj, UINT32 numEntries)
 		void setNumListEntries(ManagedSerializableList* obj, UINT32 numEntries)
 		{
 		{
-			obj->mListEntries.resize(numEntries);
+			SPtr<DeserializationInfo> info = any_cast<SPtr<DeserializationInfo>>(obj->mRTTIData);
+			info->fields = Vector<ManagedSerializableFieldDataPtr>(numEntries);
 		}
 		}
 
 
 	public:
 	public:
@@ -62,22 +70,30 @@ namespace BansheeEngine
 				&ManagedSerializableListRTTI::setListEntry, &ManagedSerializableListRTTI::setNumListEntries);
 				&ManagedSerializableListRTTI::setListEntry, &ManagedSerializableListRTTI::setNumListEntries);
 		}
 		}
 
 
-		virtual void onSerializationStarted(IReflectable* obj)
+		virtual void onDeserializationStarted(IReflectable* obj)
 		{
 		{
 			ManagedSerializableList* serializableObject = static_cast<ManagedSerializableList*>(obj);
 			ManagedSerializableList* serializableObject = static_cast<ManagedSerializableList*>(obj);
-			serializableObject->serializeManagedInstance();
+
+			serializableObject->mRTTIData = bs_shared_ptr<DeserializationInfo>();
+			SPtr<DeserializationInfo> info = any_cast<SPtr<DeserializationInfo>>(serializableObject->mRTTIData);
+
+			// If we are deserializing a GameObject we need to defer deserializing actual field values
+			// to ensure GameObject handles instances have been fixed up (which only happens after deserialization is done)
+			info->isGameObjectDeserialization = GameObjectManager::instance().isGameObjectDeserializationActive();
+
+			if (info->isGameObjectDeserialization)
+				GameObjectManager::instance().registerOnDeserializationEndCallback([=]() { serializableObject->deserializeManagedInstance(info->fields); });
 		}
 		}
 
 
-		virtual void onDeserializationStarted(IReflectable* obj)
+		virtual void onDeserializationEnded(IReflectable* obj)
 		{
 		{
 			ManagedSerializableList* serializableObject = static_cast<ManagedSerializableList*>(obj);
 			ManagedSerializableList* serializableObject = static_cast<ManagedSerializableList*>(obj);
+			SPtr<DeserializationInfo> info = any_cast<SPtr<DeserializationInfo>>(serializableObject->mRTTIData);
 
 
-			// If we are deserializing a GameObject we need to defer deserializing actual field values
-			// to ensure GameObject handles instances have been fixed up (which only happens after deserialization is done)
-			if(GameObjectManager::instance().isGameObjectDeserializationActive())
-				GameObjectManager::instance().registerOnDeserializationEndCallback([=] () { serializableObject->deserializeManagedInstance(); });
-			else
-				serializableObject->deserializeManagedInstance();
+			if (!info->isGameObjectDeserialization)
+				serializableObject->deserializeManagedInstance(info->fields);
+
+			serializableObject->mRTTIData = nullptr;
 		}
 		}
 
 
 		virtual const String& getRTTIName()
 		virtual const String& getRTTIName()

+ 2 - 8
SBansheeEngine/Include/BsManagedSerializableObject.h

@@ -25,17 +25,11 @@ namespace BansheeEngine
 	protected:
 	protected:
 		ManagedSerializableObjectInfoPtr mObjInfo;
 		ManagedSerializableObjectInfoPtr mObjInfo;
 		MonoObject* mManagedInstance;
 		MonoObject* mManagedInstance;
-		Vector<ManagedSerializableFieldDataEntryPtr> mFieldEntries;
 
 
 		/**
 		/**
-		 * @brief	Populates internal field data based on currently active managed instance.
+		 * @brief	Creates a new managed instance and populates it with provided field data.
 		 */
 		 */
-		void serializeManagedInstance();
-
-		/**
-		 * @brief	Creates a new managed instance and populates it with stored field data.
-		 */
-		void deserializeManagedInstance();
+		void deserializeManagedInstance(const Vector<ManagedSerializableFieldDataEntryPtr>& data);
 
 
 		void setFieldData(const ManagedSerializableFieldInfoPtr& fieldInfo, const ManagedSerializableFieldDataPtr& val);
 		void setFieldData(const ManagedSerializableFieldInfoPtr& fieldInfo, const ManagedSerializableFieldDataPtr& val);
 		ManagedSerializableFieldDataPtr getFieldData(const ManagedSerializableFieldInfoPtr& fieldInfo);
 		ManagedSerializableFieldDataPtr getFieldData(const ManagedSerializableFieldInfoPtr& fieldInfo);

+ 14 - 1
SBansheeEngine/Include/BsManagedSerializableObjectInfo.h

@@ -179,7 +179,20 @@ namespace BansheeEngine
 	class BS_SCR_BE_EXPORT ManagedSerializableObjectInfo : public IReflectable
 	class BS_SCR_BE_EXPORT ManagedSerializableObjectInfo : public IReflectable
 	{
 	{
 	public:
 	public:
+		struct CachedField
+		{
+			CachedField(const SPtr<ManagedSerializableFieldInfo>& info, UINT32 typeId)
+				:info(info), parentTypeId(typeId)
+			{ }
+
+			SPtr<ManagedSerializableFieldInfo> info;
+			UINT32 parentTypeId;
+		};
+
 		ManagedSerializableObjectInfo();
 		ManagedSerializableObjectInfo();
+		void initialize();
+
+		String getFullTypeName() const { return mTypeInfo->mTypeNamespace + "." + mTypeInfo->mTypeName; }
 
 
 		ManagedSerializableTypeInfoObjectPtr mTypeInfo;
 		ManagedSerializableTypeInfoObjectPtr mTypeInfo;
 		UINT32 mTypeId;
 		UINT32 mTypeId;
@@ -192,7 +205,7 @@ namespace BansheeEngine
 		std::shared_ptr<ManagedSerializableObjectInfo> mBaseClass;
 		std::shared_ptr<ManagedSerializableObjectInfo> mBaseClass;
 		Vector<std::weak_ptr<ManagedSerializableObjectInfo>> mDerivedClasses;
 		Vector<std::weak_ptr<ManagedSerializableObjectInfo>> mDerivedClasses;
 
 
-		String getFullTypeName() const { return mTypeInfo->mTypeNamespace + "." + mTypeInfo->mTypeName; }
+		Vector<CachedField> mCachedAllFields;
 
 
 		/************************************************************************/
 		/************************************************************************/
 		/* 								RTTI		                     		*/
 		/* 								RTTI		                     		*/

+ 6 - 0
SBansheeEngine/Include/BsManagedSerializableObjectInfoRTTI.h

@@ -127,6 +127,12 @@ namespace BansheeEngine
 				&ManagedSerializableObjectInfoRTTI::setSerializableFieldInfoArraySize);
 				&ManagedSerializableObjectInfoRTTI::setSerializableFieldInfoArraySize);
 		}
 		}
 
 
+		void onDeserializationEnded(IReflectable* obj)
+		{
+			ManagedSerializableObjectInfo* objInfo = static_cast<ManagedSerializableObjectInfo*>(obj);
+			objInfo->initialize();
+		}
+
 		virtual const String& getRTTIName()
 		virtual const String& getRTTIName()
 		{
 		{
 			static String name = "ScriptSerializableObjectInfo";
 			static String name = "ScriptSerializableObjectInfo";

+ 29 - 17
SBansheeEngine/Include/BsManagedSerializableObjectRTTI.h

@@ -13,6 +13,12 @@ namespace BansheeEngine
 	class BS_SCR_BE_EXPORT ManagedSerializableObjectRTTI : public RTTIType<ManagedSerializableObject, IReflectable, ManagedSerializableObjectRTTI>
 	class BS_SCR_BE_EXPORT ManagedSerializableObjectRTTI : public RTTIType<ManagedSerializableObject, IReflectable, ManagedSerializableObjectRTTI>
 	{
 	{
 	private:
 	private:
+		struct DeserializationInfo
+		{
+			Vector<ManagedSerializableFieldDataEntryPtr> fields;
+			bool isGameObjectDeserialization;
+		};
+
 		ManagedSerializableObjectInfoPtr getInfo(ManagedSerializableObject* obj)
 		ManagedSerializableObjectInfoPtr getInfo(ManagedSerializableObject* obj)
 		{
 		{
 			return obj->mObjInfo;
 			return obj->mObjInfo;
@@ -25,22 +31,29 @@ namespace BansheeEngine
 
 
 		ManagedSerializableFieldDataEntryPtr getFieldEntry(ManagedSerializableObject* obj, UINT32 arrayIdx)
 		ManagedSerializableFieldDataEntryPtr getFieldEntry(ManagedSerializableObject* obj, UINT32 arrayIdx)
 		{
 		{
-			return obj->mFieldEntries[arrayIdx];
+			ManagedSerializableObjectInfo::CachedField field = obj->mObjInfo->mCachedAllFields[arrayIdx];
+
+			ManagedSerializableFieldKeyPtr fieldKey = ManagedSerializableFieldKey::create(field.parentTypeId, field.info->mFieldId);
+			ManagedSerializableFieldDataPtr fieldData = obj->getFieldData(field.info);
+
+			return ManagedSerializableFieldDataEntry::create(fieldKey, fieldData);
 		}
 		}
 
 
 		void setFieldsEntry(ManagedSerializableObject* obj, UINT32 arrayIdx, ManagedSerializableFieldDataEntryPtr val)
 		void setFieldsEntry(ManagedSerializableObject* obj, UINT32 arrayIdx, ManagedSerializableFieldDataEntryPtr val)
 		{
 		{
-			obj->mFieldEntries[arrayIdx] = val;
+			SPtr<DeserializationInfo> info = any_cast<SPtr<DeserializationInfo>>(obj->mRTTIData);
+			info->fields[arrayIdx] = val;
 		}
 		}
 
 
 		UINT32 getNumFieldEntries(ManagedSerializableObject* obj)
 		UINT32 getNumFieldEntries(ManagedSerializableObject* obj)
 		{
 		{
-			return (UINT32)obj->mFieldEntries.size();
+			return (UINT32)obj->mObjInfo->mCachedAllFields.size();
 		}
 		}
 
 
 		void setNumFieldEntries(ManagedSerializableObject* obj, UINT32 numEntries)
 		void setNumFieldEntries(ManagedSerializableObject* obj, UINT32 numEntries)
 		{
 		{
-			obj->mFieldEntries.resize(numEntries);
+			SPtr<DeserializationInfo> info = any_cast<SPtr<DeserializationInfo>>(obj->mRTTIData);
+			info->fields = Vector<ManagedSerializableFieldDataEntryPtr>(numEntries);
 		}
 		}
 
 
 	public:
 	public:
@@ -51,34 +64,33 @@ namespace BansheeEngine
 				&ManagedSerializableObjectRTTI::setFieldsEntry, &ManagedSerializableObjectRTTI::setNumFieldEntries);
 				&ManagedSerializableObjectRTTI::setFieldsEntry, &ManagedSerializableObjectRTTI::setNumFieldEntries);
 		}
 		}
 
 
-		virtual void onSerializationStarted(IReflectable* obj)
-		{
-			ManagedSerializableObject* serializableObject = static_cast<ManagedSerializableObject*>(obj);
-			serializableObject->serializeManagedInstance();
-		}
-
 		virtual void onDeserializationStarted(IReflectable* obj)
 		virtual void onDeserializationStarted(IReflectable* obj)
 		{
 		{
 			ManagedSerializableObject* serializableObject = static_cast<ManagedSerializableObject*>(obj);
 			ManagedSerializableObject* serializableObject = static_cast<ManagedSerializableObject*>(obj);
-			
+			serializableObject->mRTTIData = bs_shared_ptr<DeserializationInfo>();
+
+			SPtr<DeserializationInfo> info = any_cast<SPtr<DeserializationInfo>>(serializableObject->mRTTIData);
+
 			// If we are deserializing a GameObject we need to defer deserializing actual field values
 			// If we are deserializing a GameObject we need to defer deserializing actual field values
 			// to ensure GameObject handles instances have been fixed up (which only happens after deserialization is done)
 			// to ensure GameObject handles instances have been fixed up (which only happens after deserialization is done)
 			if (GameObjectManager::instance().isGameObjectDeserializationActive())
 			if (GameObjectManager::instance().isGameObjectDeserializationActive())
 			{
 			{
-				GameObjectManager::instance().registerOnDeserializationEndCallback([=]() { serializableObject->deserializeManagedInstance(); });
-				serializableObject->mRTTIData = true;
+				GameObjectManager::instance().registerOnDeserializationEndCallback([=]() { serializableObject->deserializeManagedInstance(info->fields); });
+				info->isGameObjectDeserialization = true;
 			}
 			}
 			else
 			else
-				serializableObject->mRTTIData = false;
+				info->isGameObjectDeserialization = false;
 		}
 		}
 
 
 		virtual void onDeserializationEnded(IReflectable* obj)
 		virtual void onDeserializationEnded(IReflectable* obj)
 		{
 		{
 			ManagedSerializableObject* serializableObject = static_cast<ManagedSerializableObject*>(obj);
 			ManagedSerializableObject* serializableObject = static_cast<ManagedSerializableObject*>(obj);
+			SPtr<DeserializationInfo> info = any_cast<SPtr<DeserializationInfo>>(serializableObject->mRTTIData);
+
+			if (!info->isGameObjectDeserialization)
+				serializableObject->deserializeManagedInstance(info->fields);
 
 
-			bool isGameObjectDeserialization = any_cast<bool>(serializableObject->mRTTIData);
-			if (!isGameObjectDeserialization)
-				serializableObject->deserializeManagedInstance();
+			serializableObject->mRTTIData = nullptr;
 		}
 		}
 
 
 		virtual const String& getRTTIName()
 		virtual const String& getRTTIName()

+ 2 - 17
SBansheeEngine/Source/BsManagedSerializableArray.cpp

@@ -70,22 +70,7 @@ namespace BansheeEngine
 		return createInstance->invoke(nullptr, params);
 		return createInstance->invoke(nullptr, params);
 	}
 	}
 
 
-	void ManagedSerializableArray::serializeManagedInstance()
-	{
-		UINT32 totalNumElements = 1;
-		for(auto& numElems : mNumElements)
-		{
-			totalNumElements *= numElems;
-		}
-
-		mArrayEntries.resize(totalNumElements);
-		for(UINT32 i = 0; i < totalNumElements; i++)
-		{
-			mArrayEntries[i] = getFieldData(i);
-		}
-	}
-
-	void ManagedSerializableArray::deserializeManagedInstance()
+	void ManagedSerializableArray::deserializeManagedInstance(const Vector<ManagedSerializableFieldDataPtr>& entries)
 	{
 	{
 		mManagedInstance = createManagedInstance(mArrayTypeInfo, mNumElements);
 		mManagedInstance = createManagedInstance(mArrayTypeInfo, mNumElements);
 
 
@@ -95,7 +80,7 @@ namespace BansheeEngine
 		initMonoObjects();
 		initMonoObjects();
 
 
 		UINT32 idx = 0;
 		UINT32 idx = 0;
-		for(auto& arrayEntry : mArrayEntries)
+		for (auto& arrayEntry : entries)
 		{
 		{
 			setFieldData(idx, arrayEntry);
 			setFieldData(idx, arrayEntry);
 			idx++;
 			idx++;

+ 11 - 9
SBansheeEngine/Source/BsManagedSerializableDictionary.cpp

@@ -91,7 +91,8 @@ namespace BansheeEngine
 		return bs_shared_ptr<ManagedSerializableDictionary>(ConstructPrivately());
 		return bs_shared_ptr<ManagedSerializableDictionary>(ConstructPrivately());
 	}
 	}
 
 
-	void ManagedSerializableDictionary::serializeManagedInstance()
+	void ManagedSerializableDictionary::serializeManagedInstance(Vector<ManagedSerializableFieldDataPtr>& keyEntries,
+		Vector<ManagedSerializableFieldDataPtr>& valueEntries)
 	{
 	{
 		MonoClass* dictionaryClass = MonoManager::instance().findClass(mono_object_get_class(mManagedInstance));
 		MonoClass* dictionaryClass = MonoManager::instance().findClass(mono_object_get_class(mManagedInstance));
 		if(dictionaryClass == nullptr)
 		if(dictionaryClass == nullptr)
@@ -99,19 +100,20 @@ namespace BansheeEngine
 
 
 		initMonoObjects(dictionaryClass);
 		initMonoObjects(dictionaryClass);
 
 
-		mKeyEntries.clear();
-		mValueEntries.clear();
+		keyEntries.clear();
+		valueEntries.clear();
 
 
 		Enumerator enumerator = getEnumerator();
 		Enumerator enumerator = getEnumerator();
 
 
 		while(enumerator.moveNext())
 		while(enumerator.moveNext())
 		{
 		{
-			mKeyEntries.push_back(enumerator.getKey());
-			mValueEntries.push_back(enumerator.getValue());
+			keyEntries.push_back(enumerator.getKey());
+			valueEntries.push_back(enumerator.getValue());
 		}
 		}
 	}
 	}
 
 
-	void ManagedSerializableDictionary::deserializeManagedInstance()
+	void ManagedSerializableDictionary::deserializeManagedInstance(const Vector<ManagedSerializableFieldDataPtr>& keyEntries,
+		const Vector<ManagedSerializableFieldDataPtr>& valueEntries)
 	{
 	{
 		mManagedInstance = createManagedInstance(mDictionaryTypeInfo);
 		mManagedInstance = createManagedInstance(mDictionaryTypeInfo);
 		if (mManagedInstance == nullptr)
 		if (mManagedInstance == nullptr)
@@ -124,11 +126,11 @@ namespace BansheeEngine
 
 
 		initMonoObjects(dictionaryClass);
 		initMonoObjects(dictionaryClass);
 
 
-		assert(mKeyEntries.size() == mValueEntries.size());
+		assert(keyEntries.size() == valueEntries.size());
 
 
-		for(UINT32 i = 0; i < (UINT32)mKeyEntries.size(); i++)
+		for (UINT32 i = 0; i < (UINT32)keyEntries.size(); i++)
 		{
 		{
-			setFieldData(mKeyEntries[i], mValueEntries[i]);
+			setFieldData(keyEntries[i], valueEntries[i]);
 		}
 		}
 	}
 	}
 
 

+ 2 - 11
SBansheeEngine/Source/BsManagedSerializableList.cpp

@@ -68,16 +68,7 @@ namespace BansheeEngine
 		return bs_shared_ptr<ManagedSerializableList>(ConstructPrivately());
 		return bs_shared_ptr<ManagedSerializableList>(ConstructPrivately());
 	}
 	}
 
 
-	void ManagedSerializableList::serializeManagedInstance()
-	{
-		mListEntries.resize(mNumElements);
-		for(UINT32 i = 0; i < mNumElements; i++)
-		{
-			mListEntries[i] = getFieldData(i);
-		}
-	}
-
-	void ManagedSerializableList::deserializeManagedInstance()
+	void ManagedSerializableList::deserializeManagedInstance(const Vector<ManagedSerializableFieldDataPtr>& entries)
 	{
 	{
 		mManagedInstance = createManagedInstance(mListTypeInfo, mNumElements);
 		mManagedInstance = createManagedInstance(mListTypeInfo, mNumElements);
 
 
@@ -87,7 +78,7 @@ namespace BansheeEngine
 		MonoClass* listClass = MonoManager::instance().findClass(mListTypeInfo->getMonoClass());
 		MonoClass* listClass = MonoManager::instance().findClass(mListTypeInfo->getMonoClass());
 		initMonoObjects(listClass);
 		initMonoObjects(listClass);
 
 
-		for(auto& arrayEntry : mListEntries)
+		for(auto& arrayEntry : entries)
 		{
 		{
 			addFieldData(arrayEntry);
 			addFieldData(arrayEntry);
 		}
 		}

+ 2 - 38
SBansheeEngine/Source/BsManagedSerializableObject.cpp

@@ -65,43 +65,7 @@ namespace BansheeEngine
 		return bs_shared_ptr<ManagedSerializableObject>(ConstructPrivately());
 		return bs_shared_ptr<ManagedSerializableObject>(ConstructPrivately());
 	}
 	}
 
 
-	void ManagedSerializableObject::serializeManagedInstance()
-	{
-		ManagedSerializableObjectInfoPtr curType = mObjInfo;
-
-		UINT32 numFields = 0;
-		while(curType != nullptr)
-		{
-			for(auto& field : mObjInfo->mFields)
-			{
-				if(field.second->isSerializable())
-					numFields++;
-			}
-			curType = curType->mBaseClass;
-		}
-
-		mFieldEntries.resize(numFields);
-		curType = mObjInfo;
-		UINT32 curIdx = 0;
-		while(curType != nullptr)
-		{
-			for(auto& field : mObjInfo->mFields)
-			{
-				if(!field.second->isSerializable())
-					continue;
-
-				ManagedSerializableFieldKeyPtr fieldKey = ManagedSerializableFieldKey::create(curType->mTypeId, field.second->mFieldId);
-				ManagedSerializableFieldDataPtr fieldData = getFieldData(field.second);
-
-				mFieldEntries[curIdx] = ManagedSerializableFieldDataEntry::create(fieldKey, fieldData);
-				curIdx++;
-			}
-
-			curType = curType->mBaseClass;
-		}
-	}
-
-	void ManagedSerializableObject::deserializeManagedInstance()
+	void ManagedSerializableObject::deserializeManagedInstance(const Vector<ManagedSerializableFieldDataEntryPtr>& entries)
 	{
 	{
 		ManagedSerializableObjectInfoPtr storedObjInfo = mObjInfo;
 		ManagedSerializableObjectInfoPtr storedObjInfo = mObjInfo;
 		ManagedSerializableObjectInfoPtr currentObjInfo = nullptr;
 		ManagedSerializableObjectInfoPtr currentObjInfo = nullptr;
@@ -172,7 +136,7 @@ namespace BansheeEngine
 		};
 		};
 
 
 		// Scan all fields and ensure the fields still exist
 		// Scan all fields and ensure the fields still exist
-		for(auto& fieldEntry : mFieldEntries)
+		for(auto& fieldEntry : entries)
 		{
 		{
 			ManagedSerializableFieldInfoPtr storedFieldEntry;
 			ManagedSerializableFieldInfoPtr storedFieldEntry;
 			ManagedSerializableObjectInfoPtr storedFieldObjEntry;
 			ManagedSerializableObjectInfoPtr storedFieldObjEntry;

+ 17 - 0
SBansheeEngine/Source/BsManagedSerializableObjectInfo.cpp

@@ -31,6 +31,23 @@ namespace BansheeEngine
 
 
 	}
 	}
 
 
+	void ManagedSerializableObjectInfo::initialize()
+	{
+		mCachedAllFields.clear();
+
+		ManagedSerializableObjectInfo* curType = this;
+		while (curType != nullptr)
+		{
+			for (auto& field : mFields)
+			{
+				if (field.second->isSerializable())
+					mCachedAllFields.push_back(CachedField(field.second, curType->mTypeId));
+			}
+
+			curType = curType->mBaseClass.get();
+		}
+	}
+
 	RTTITypeBase* ManagedSerializableObjectInfo::getRTTIStatic()
 	RTTITypeBase* ManagedSerializableObjectInfo::getRTTIStatic()
 	{
 	{
 		return ManagedSerializableObjectInfoRTTI::instance();
 		return ManagedSerializableObjectInfoRTTI::instance();

+ 7 - 0
SBansheeEngine/Source/BsRuntimeScriptObjects.cpp

@@ -148,6 +148,13 @@ namespace BansheeEngine
 			}
 			}
 		}
 		}
 
 
+		// Finish object info initialization
+		for (auto& curClassInfo : assemblyInfo->mObjectInfos)
+		{
+			std::shared_ptr<ManagedSerializableObjectInfo> objInfo = curClassInfo.second;
+			objInfo->initialize();
+		}
+
 		onAssemblyRefreshed(curAssembly);
 		onAssemblyRefreshed(curAssembly);
 	}
 	}
 
 

+ 13 - 16
TODO.txt

@@ -7,22 +7,19 @@ TODO - Material waits to Shader to be loaded but doesn't wait for shader GpuProg
 
 
 Make RenderTexture accept a HTexture
 Make RenderTexture accept a HTexture
 
 
-ManagedComponent deserialization IS WRONG
- - I register the component with ScriptGameObjectManager during deserialization when its ID is wrong
-
-Add a special mode to GameObjectManager that is active during deserialization
- - Any handle or GameObject deserialized when its active will use a special mapping for resolving/updating IDs
-  - THIS doesn't really work because I might need to resolve a handle before the object is deserialized
-  - But could I add entries to the map from both handle and object regardless of which is resolved first?
-    - YES - This gets rid of the need for post-processing of GameObject, solves my ScriptComponent deserialization issue and allows me to deserialize managed fields on demand
-
-Modify managed serialization so that deserialization/serialization happens per field instead of in deserialize/serialize methods during pre- and post-processing step.
- - Make sure to fix the GameObjectManager delayed deserialization issue first
- - When generating SerializableFieldInfo generate mFieldGlobalIdx (index that takes into consideration any base classes)
-   - Then when de/serializing use that index to get field info and call get/setFieldData accordingly in RTTI getter/setter directly
-   - How to use it when deserializing though?
-     - Ensure that ManagedObjectInfo is deserialized first. Since this is an unclear dependency make sure to add asserts so when it fails it is clear why.
-     - Then use that to look up field during runtime
+When resource loading starts synchonously read all dependencies (and recurse over their dependencies too)
+ - Create a ResourceLoadGroup that contains all the non-loaded resources
+ - Cue async loads for all resources
+ - Perform sync loads for resources that don't support async
+ - return an unloaded handle
+
+Each time an async load completes check if the resource is part of a resource load group
+ - If all resources in the load group are done (or there was just one resource), resolve all of their handles at once
+   and trigger resource listener events.
+
+TODO
+ - Pay special care in case a resource in resource load group gets unloaded. I should ignore it to avoid a deadlock that never finishes the resource load.
+ - Allow for a situation if resource is part of multiple load groups.
 
 
 I can get mono errors by checking g_print calls in goutput.c
 I can get mono errors by checking g_print calls in goutput.c
  - Calling thunks incorrectly can cause those weird errors with no real callstack
  - Calling thunks incorrectly can cause those weird errors with no real callstack