Browse Source

Refactored managed serialization so objects can be in serialized format without a backing managed instance

Marko Pintera 10 years ago
parent
commit
6e07e7bd02
32 changed files with 989 additions and 741 deletions
  1. 30 10
      README.md
  2. 3 10
      SBansheeEngine/Include/BsManagedComponent.h
  3. 3 14
      SBansheeEngine/Include/BsManagedComponentRTTI.h
  4. 2 8
      SBansheeEngine/Include/BsManagedResource.h
  5. 1 0
      SBansheeEngine/Include/BsManagedResourceRTTI.h
  6. 20 8
      SBansheeEngine/Include/BsManagedSerializableArray.h
  7. 5 43
      SBansheeEngine/Include/BsManagedSerializableArrayRTTI.h
  8. 52 13
      SBansheeEngine/Include/BsManagedSerializableDictionary.h
  9. 64 74
      SBansheeEngine/Include/BsManagedSerializableDictionaryRTTI.h
  10. 37 0
      SBansheeEngine/Include/BsManagedSerializableField.h
  11. 20 7
      SBansheeEngine/Include/BsManagedSerializableList.h
  12. 4 42
      SBansheeEngine/Include/BsManagedSerializableListRTTI.h
  13. 30 9
      SBansheeEngine/Include/BsManagedSerializableObject.h
  14. 0 23
      SBansheeEngine/Include/BsManagedSerializableObjectData.h
  15. 0 56
      SBansheeEngine/Include/BsManagedSerializableObjectDataRTTI.h
  16. 2 15
      SBansheeEngine/Include/BsManagedSerializableObjectInfo.h
  17. 26 20
      SBansheeEngine/Include/BsManagedSerializableObjectInfoRTTI.h
  18. 32 39
      SBansheeEngine/Include/BsManagedSerializableObjectRTTI.h
  19. 2 2
      SBansheeEngine/Include/BsScriptEnginePrerequisites.h
  20. 0 3
      SBansheeEngine/SBansheeEngine.vcxproj
  21. 0 9
      SBansheeEngine/SBansheeEngine.vcxproj.filters
  22. 12 40
      SBansheeEngine/Source/BsManagedComponent.cpp
  23. 7 22
      SBansheeEngine/Source/BsManagedResource.cpp
  24. 101 47
      SBansheeEngine/Source/BsManagedSerializableArray.cpp
  25. 154 49
      SBansheeEngine/Source/BsManagedSerializableDictionary.cpp
  26. 190 39
      SBansheeEngine/Source/BsManagedSerializableField.cpp
  27. 76 33
      SBansheeEngine/Source/BsManagedSerializableList.cpp
  28. 90 57
      SBansheeEngine/Source/BsManagedSerializableObject.cpp
  29. 0 15
      SBansheeEngine/Source/BsManagedSerializableObjectData.cpp
  30. 1 18
      SBansheeEngine/Source/BsManagedSerializableObjectInfo.cpp
  31. 4 11
      SBansheeEngine/Source/BsScriptAssemblyManager.cpp
  32. 21 5
      TODO.txt

+ 30 - 10
README.md

@@ -34,16 +34,30 @@ To compile DirectX render systems you will also need a separately installed Dire
     * Simple drag and drop interface
 	* Traditional set of tools
     * Custom 2D and 3D tool support
+  * Prefab system
+    * Pre-built templates for level design
+	* Easy to create and maintain complex levels
+	* Hierarchical prefabs and instance specialization
   * Play in editor
     * Compile in editor
     * Immediately test changes
+	* Pause and frame-step
+	* Analyze and modify scene while playing
   * Fully extensible for game-specific needs
-    * Custom editor windows, tool handles and more
+    * Easy to extend using scripting
+    * Comprehensive extension scripting API
+	* Extend almost anything
+	  * Editor windows
+	  * Object inspectors
+	  * 2D/3D tools
+	  * Automate common tasks
   * Game publishing
-    * One click build process	
-  * Customizable GUI
+    * One click build process
+	* Automatically detect required resources
+	* Automatically package and output an executable
+  * Customizable frontend
     * Dockable layout and floating windows
-    * Skinnable and localizable
+	* Custom skin & localization support
    
 * Core
   * Design
@@ -57,13 +71,14 @@ To compile DirectX render systems you will also need a separately installed Dire
     * Multi-threaded rendering
     * Flexible material system
       * Easy to control and set up
+	  * BansheeFX language for material definitions
       * Shader parsing for HLSL9, HLSL11 and GLSL
   * Asset pipeline
     * Easy to use
     * Asynchronous resource loading
     * Extensible importer system
     * Available importer plugins for:
-      * FXB,OBJ, DAE meshes
+      * FXB, OBJ, DAE meshes
       * PNG, PSD, BMP, JPG, ... images
       * OTF, TTF fonts
       * HLSL9, HLSL11, GLSL shaders
@@ -72,16 +87,20 @@ To compile DirectX render systems you will also need a separately installed Dire
     * Easy to use layout based system
     * Many common GUI controls
     * Fully skinnable
-    * Automatch batching
+    * Automatic batching
     * Support for texture atlases
     * Localization
   * Scripting
     * C# via Mono
-    * Great performance, safe code, fast compile and iteration times
+	* Separate high level engine API
+	* Integrated runtime for maximum performance
     * Full access to .NET framework
-    * High level C# engine API
-    * Editor-only C# API for editor extensions
-    * Support for Visual Studio
+	* Integration with Visual Studio
+	* Automatic serialization
+	  * Custom components
+	  * Custom resources
+	  * No additional code
+	  * Handles complex types and references
   * Other
     * CPU & GPU profiler
     * Virtual input
@@ -99,6 +118,7 @@ To compile DirectX render systems you will also need a separately installed Dire
  * Networking system integration
  * Animation
  * GUI animation
+ * Mac & Linux support
 
 ## Development state
 

+ 3 - 10
SBansheeEngine/Include/BsManagedComponent.h

@@ -42,8 +42,7 @@ namespace BansheeEngine
 
 		// We store data of a missing component type in hope it will be restored later
 		bool mMissingType;
-		ManagedSerializableObjectInfoPtr mMissingTypeObjectInfo;
-		ManagedSerializableObjectDataPtr mMissingTypeObjectData;
+		ManagedSerializableObjectPtr mMissingTypeObjectData;
 
 		OnInitializedThunkDef mOnInitializedThunk;
 		UpdateThunkDef mUpdateThunk;
@@ -83,13 +82,7 @@ namespace BansheeEngine
 
 	struct ComponentBackupData
 	{
-		struct DataBlock
-		{
-			UINT8* data;
-			UINT32 size;
-		};
-
-		DataBlock mTypeInfo;
-		DataBlock mObjectData;
+		UINT8* data;
+		UINT32 size;
 	};
 }

+ 3 - 14
SBansheeEngine/Include/BsManagedComponentRTTI.h

@@ -7,7 +7,6 @@
 #include "BsMonoManager.h"
 #include "BsManagedSerializableObject.h"
 #include "BsGameObjectManager.h"
-#include "BsScriptGameObjectManager.h"
 #include "BsScriptComponent.h"
 
 namespace BansheeEngine
@@ -55,22 +54,12 @@ namespace BansheeEngine
 			obj->mMissingType = val;
 		}
 
-		ManagedSerializableObjectInfoPtr getMissingTypeObjectInfo(ManagedComponent* obj)
-		{
-			return obj->mMissingTypeObjectInfo;
-		}
-
-		void setMissingTypeObjectInfo(ManagedComponent* obj, ManagedSerializableObjectInfoPtr val)
-		{
-			obj->mMissingTypeObjectInfo = val;
-		}
-
-		ManagedSerializableObjectDataPtr getMissingTypeObjectData(ManagedComponent* obj)
+		ManagedSerializableObjectPtr getMissingTypeObjectData(ManagedComponent* obj)
 		{
 			return obj->mMissingTypeObjectData;
 		}
 
-		void setMissingTypeObjectData(ManagedComponent* obj, ManagedSerializableObjectDataPtr val)
+		void setMissingTypeObjectData(ManagedComponent* obj, ManagedSerializableObjectPtr val)
 		{
 			obj->mMissingTypeObjectData = val;
 		}
@@ -82,7 +71,6 @@ namespace BansheeEngine
 			addPlainField("mTypename", 1, &ManagedComponentRTTI::getTypename, &ManagedComponentRTTI::setTypename);
 			addReflectablePtrField("mObjectData", 2, &ManagedComponentRTTI::getObjectData, &ManagedComponentRTTI::setObjectData);
 			addPlainField("mMissingType", 3, &ManagedComponentRTTI::getMissingType, &ManagedComponentRTTI::setMissingType);
-			addReflectablePtrField("mMissingTypeObjectInfo", 4, &ManagedComponentRTTI::getMissingTypeObjectInfo, &ManagedComponentRTTI::setMissingTypeObjectInfo);
 			addReflectablePtrField("mMissingTypeObjectData", 5, &ManagedComponentRTTI::getMissingTypeObjectData, &ManagedComponentRTTI::setMissingTypeObjectData);
 		}
 
@@ -103,6 +91,7 @@ namespace BansheeEngine
 		static void finalizeDeserialization(ManagedComponent* mc)
 		{
 			ManagedSerializableObjectPtr serializableObject = any_cast<ManagedSerializableObjectPtr>(mc->mRTTIData);
+			serializableObject->deserialize();
 			MonoObject* managedInstance = serializableObject->getManagedInstance();
 
 			// Note: This callback must be triggered before any child ManagedSerializable* object's callbacks.

+ 2 - 8
SBansheeEngine/Include/BsManagedResource.h

@@ -46,13 +46,7 @@ namespace BansheeEngine
 
 	struct ResourceBackupData
 	{
-		struct DataBlock
-		{
-			UINT8* data;
-			UINT32 size;
-		};
-
-		DataBlock mTypeInfo;
-		DataBlock mObjectData;
+		UINT8* data;
+		UINT32 size;
 	};
 }

+ 1 - 0
SBansheeEngine/Include/BsManagedResourceRTTI.h

@@ -40,6 +40,7 @@ namespace BansheeEngine
 		{
 			ManagedResource* mr = static_cast<ManagedResource*>(obj);
 			ManagedSerializableObjectPtr serializableObject = any_cast<ManagedSerializableObjectPtr>(mr->mRTTIData);
+			serializableObject->deserialize();
 
 			ResourcePtr mrPtr = std::static_pointer_cast<Resource>(mr->getThisPtr());
 			HManagedResource handle = static_resource_cast<ManagedResource>(gResources()._createResourceHandle(mrPtr));

+ 20 - 8
SBansheeEngine/Include/BsManagedSerializableArray.h

@@ -6,6 +6,21 @@
 
 namespace BansheeEngine
 {
+	/**
+	 * @brief	TODO
+	 *
+	 * @note	This class can be in two states:
+	 *			 - Linked - When the object has a link to a managed object. This is the default 
+	 *                      state when a new instance of ManagedSerializableObject is created.
+	 *						Any operations during this state will operate directly on the linked
+	 *						managed object.
+	 *			 - Serialized - When the object has no link to the managed object but instead just
+	 *							contains cached object and field data that may be used for initializing
+	 *							a managed object. Any operations during this state will operate
+	 *							only on the cached internal data.
+	 *			You can transfer between these states by calling serialize(linked->serialized) &
+	 *	
+	 */
 	class BS_SCR_BE_EXPORT ManagedSerializableArray : public IReflectable
 	{
 	private:
@@ -16,6 +31,7 @@ namespace BansheeEngine
 		ManagedSerializableArray(const ConstructPrivately& dummy);
 
 		MonoObject* getManagedInstance() const { return mManagedInstance; }
+		ManagedSerializableTypeInfoArrayPtr getTypeInfo() const { return mArrayTypeInfo; }
 
 		void resize(const Vector<UINT32>& newSizes);
 		UINT32 getLength(UINT32 dimension) const { return mNumElements[dimension]; }
@@ -25,7 +41,8 @@ namespace BansheeEngine
 		void setFieldData(UINT32 arrayIdx, const ManagedSerializableFieldDataPtr& val);
 		ManagedSerializableFieldDataPtr getFieldData(UINT32 arrayIdx);
 
-		ManagedSerializableTypeInfoArrayPtr getTypeInfo() const { return mArrayTypeInfo; }
+		void serialize();
+		void deserialize();
 
 		static ManagedSerializableArrayPtr createFromExisting(MonoObject* managedInstance, const ManagedSerializableTypeInfoArrayPtr& typeInfo);
 		static ManagedSerializableArrayPtr createNew(const ManagedSerializableTypeInfoArrayPtr& typeInfo, const Vector<UINT32>& sizes);
@@ -37,19 +54,14 @@ namespace BansheeEngine
 		MonoMethod* mCopyMethod;
 
 		ManagedSerializableTypeInfoArrayPtr mArrayTypeInfo;
-
+		Vector<ManagedSerializableFieldDataPtr> mCachedEntries;
 		Vector<UINT32> mNumElements;
 		UINT32 mElemSize;
 
 		void initMonoObjects();
 		UINT32 getLengthInternal(UINT32 dimension) const;
 
-		/**
-		 * @brief	Creates a new managed instance and populates it with provided entries.
-		 */
-		void deserializeManagedInstance(const Vector<ManagedSerializableFieldDataPtr>& entries);
-
-		void setValue(UINT32 arrayIdx, void* val);
+		void setValueInternal(UINT32 arrayIdx, void* val);
 		UINT32 toSequentialIdx(const Vector<UINT32>& idx) const;
 
 		/************************************************************************/

+ 5 - 43
SBansheeEngine/Include/BsManagedSerializableArrayRTTI.h

@@ -13,12 +13,6 @@ namespace BansheeEngine
 	class BS_SCR_BE_EXPORT ManagedSerializableArrayRTTI : public RTTIType<ManagedSerializableArray, IReflectable, ManagedSerializableArrayRTTI>
 	{
 	private:
-		struct DeserializationInfo
-		{
-			Vector<ManagedSerializableFieldDataPtr> fields;
-			bool isGameObjectDeserialization;
-		};
-
 		ManagedSerializableTypeInfoArrayPtr getTypeInfo(ManagedSerializableArray* obj)
 		{
 			return obj->mArrayTypeInfo;
@@ -31,7 +25,7 @@ namespace BansheeEngine
 
 		UINT32& getElementSize(ManagedSerializableArray* obj)
 		{
-			return (UINT32)obj->mElemSize;
+			return (UINT32&)obj->mElemSize;
 		}
 
 		void setElementSize(ManagedSerializableArray* obj, UINT32& numElements)
@@ -41,7 +35,7 @@ namespace BansheeEngine
 
 		UINT32& getNumElements(ManagedSerializableArray* obj, UINT32 arrayIdx)
 		{
-			return (UINT32)obj->mNumElements[arrayIdx];
+			return (UINT32&)obj->mNumElements[arrayIdx];
 		}
 
 		void setNumElements(ManagedSerializableArray* obj, UINT32 arrayIdx, UINT32& numElements)
@@ -66,23 +60,17 @@ namespace BansheeEngine
 
 		void setArrayEntry(ManagedSerializableArray* obj, UINT32 arrayIdx, ManagedSerializableFieldDataPtr val)
 		{
-			SPtr<DeserializationInfo> info = any_cast<SPtr<DeserializationInfo>>(obj->mRTTIData);
-			info->fields[arrayIdx] = val;
+			obj->setFieldData(arrayIdx, val);
 		}
 
 		UINT32 getNumArrayEntries(ManagedSerializableArray* obj)
 		{
-			UINT32 totalNumElements = 1;
-			for (auto& numElems : obj->mNumElements)
-				totalNumElements *= numElems;
-
-			return totalNumElements;
+			return obj->getTotalLength();
 		}
 
 		void setNumArrayEntries(ManagedSerializableArray* obj, UINT32 numEntries)
 		{
-			SPtr<DeserializationInfo> info = any_cast<SPtr<DeserializationInfo>>(obj->mRTTIData);
-			info->fields = Vector<ManagedSerializableFieldDataPtr>(numEntries);
+			obj->mCachedEntries = Vector<ManagedSerializableFieldDataPtr>(numEntries);
 		}
 
 	public:
@@ -96,32 +84,6 @@ namespace BansheeEngine
 				&ManagedSerializableArrayRTTI::setArrayEntry, &ManagedSerializableArrayRTTI::setNumArrayEntries);
 		}
 
-		virtual void onDeserializationStarted(IReflectable* obj)
-		{
-			ManagedSerializableArray* serializableObject = static_cast<ManagedSerializableArray*>(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
-			// 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 onDeserializationEnded(IReflectable* obj)
-		{
-			ManagedSerializableArray* serializableObject = static_cast<ManagedSerializableArray*>(obj);
-			SPtr<DeserializationInfo> info = any_cast<SPtr<DeserializationInfo>>(serializableObject->mRTTIData);
-			
-			if (!info->isGameObjectDeserialization)
-				serializableObject->deserializeManagedInstance(info->fields);
-
-			serializableObject->mRTTIData = nullptr;
-		}
-
 		virtual const String& getRTTIName()
 		{
 			static String name = "ScriptSerializableArray";

+ 52 - 13
SBansheeEngine/Include/BsManagedSerializableDictionary.h

@@ -6,12 +6,57 @@
 
 namespace BansheeEngine
 {
+	/**
+	 * @brief	TODO
+	 *
+	 * @note	This class can be in two states:
+	 *			 - Linked - When the object has a link to a managed object. This is the default 
+	 *                      state when a new instance of ManagedSerializableObject is created.
+	 *						Any operations during this state will operate directly on the linked
+	 *						managed object.
+	 *			 - Serialized - When the object has no link to the managed object but instead just
+	 *							contains cached object and field data that may be used for initializing
+	 *							a managed object. Any operations during this state will operate
+	 *							only on the cached internal data.
+	 *			You can transfer between these states by calling serialize(linked->serialized) &
+	 *	
+	 */
+	struct BS_SCR_BE_EXPORT ManagedSerializableDictionaryKeyValue : public IReflectable
+	{
+		ManagedSerializableDictionaryKeyValue() {}
+		ManagedSerializableDictionaryKeyValue(const ManagedSerializableFieldDataPtr& key,
+			const ManagedSerializableFieldDataPtr& value);
+
+		ManagedSerializableFieldDataPtr key;
+		ManagedSerializableFieldDataPtr value;
+
+		/************************************************************************/
+		/* 								RTTI		                     		*/
+		/************************************************************************/
+	public:
+		friend class ManagedSerializableDictionaryKeyValueRTTI;
+		static RTTITypeBase* getRTTIStatic();
+		virtual RTTITypeBase* getRTTI() const;
+	};
+
 	class BS_SCR_BE_EXPORT ManagedSerializableDictionary : public IReflectable
 	{
 	private:
 		struct ConstructPrivately {};
+		
+		struct BS_SCR_BE_EXPORT Hash
+		{
+			inline size_t operator()(const ManagedSerializableFieldDataPtr& x) const;
+		};
+
+		struct BS_SCR_BE_EXPORT Equals
+		{
+			inline bool operator()(const ManagedSerializableFieldDataPtr& a, const ManagedSerializableFieldDataPtr& b) const;
+		};
 
 	public:
+		typedef UnorderedMap<ManagedSerializableFieldDataPtr, ManagedSerializableFieldDataPtr> CachedEntriesMap;
+
 		class Enumerator
 		{
 		public:
@@ -25,6 +70,9 @@ namespace BansheeEngine
 		private:
 			MonoObject* mInstance;
 			MonoObject* mCurrent;
+			CachedEntriesMap::const_iterator mCachedIter;
+			bool mIteratorInitialized;
+
 			const ManagedSerializableDictionary* mParent;
 		};
 
@@ -33,7 +81,6 @@ namespace BansheeEngine
 		ManagedSerializableDictionary(const ConstructPrivately& dummy);
 
 		MonoObject* getManagedInstance() const { return mManagedInstance; }
-
 		ManagedSerializableTypeInfoDictionaryPtr getTypeInfo() const { return mDictionaryTypeInfo; }
 
 		ManagedSerializableFieldDataPtr getFieldData(const ManagedSerializableFieldDataPtr& key);
@@ -42,6 +89,9 @@ namespace BansheeEngine
 		bool contains(const ManagedSerializableFieldDataPtr& key) const;
 		Enumerator getEnumerator() const;
 
+		void serialize();
+		void deserialize();
+
 		static ManagedSerializableDictionaryPtr createFromExisting(MonoObject* managedInstance, const ManagedSerializableTypeInfoDictionaryPtr& typeInfo);
 		static ManagedSerializableDictionaryPtr createNew(const ManagedSerializableTypeInfoDictionaryPtr& typeInfo);
 		static MonoObject* createManagedInstance(const ManagedSerializableTypeInfoDictionaryPtr& typeInfo);
@@ -60,21 +110,10 @@ namespace BansheeEngine
 		MonoProperty* mValueProp;
 
 		ManagedSerializableTypeInfoDictionaryPtr mDictionaryTypeInfo;
+		CachedEntriesMap mCachedEntries;
 
 		void initMonoObjects(MonoClass* dictionaryClass);
 
-		/**
-		 * @brief	Populates provided field data arrays based on currently active managed instance.
-		 */
-		void serializeManagedInstance(Vector<ManagedSerializableFieldDataPtr>& keyEntries, 
-			Vector<ManagedSerializableFieldDataPtr>& valueEntries);
-
-		/**
-		 * @brief	Creates a new managed instance and populates it with provided field data.
-		 */
-		void deserializeManagedInstance(const Vector<ManagedSerializableFieldDataPtr>& keyEntries, 
-			const Vector<ManagedSerializableFieldDataPtr>& valueEntries);
-
 		/************************************************************************/
 		/* 								RTTI		                     		*/
 		/************************************************************************/

+ 64 - 74
SBansheeEngine/Include/BsManagedSerializableDictionaryRTTI.h

@@ -2,124 +2,114 @@
 
 #include "BsScriptEnginePrerequisites.h"
 #include "BsRTTIType.h"
-#include "BsGameObjectManager.h"
 #include "BsManagedSerializableDictionary.h"
-#include "BsScriptAssemblyManager.h"
-#include "BsMonoManager.h"
-#include "BsMonoClass.h"
 
 namespace BansheeEngine
 {
-	class BS_SCR_BE_EXPORT ManagedSerializableDictionaryRTTI : public RTTIType<ManagedSerializableDictionary, IReflectable, ManagedSerializableDictionaryRTTI>
+	class BS_SCR_BE_EXPORT ManagedSerializableDictionaryKeyValueRTTI : 
+		public RTTIType <ManagedSerializableDictionaryKeyValue, IReflectable, ManagedSerializableDictionaryKeyValueRTTI>
 	{
 	private:
-		struct SerializationData
+		ManagedSerializableFieldDataPtr getKey(ManagedSerializableDictionaryKeyValue* obj)
 		{
-			Vector<ManagedSerializableFieldDataPtr> keyEntries;
-			Vector<ManagedSerializableFieldDataPtr> valueEntries;
-			bool isGameObjectDeserialization;
-		};
+			return obj->key;
+		}
 
-		ManagedSerializableTypeInfoDictionaryPtr getTypeInfo(ManagedSerializableDictionary* obj) { return obj->mDictionaryTypeInfo; }
-		void setTypeInfo(ManagedSerializableDictionary* obj, ManagedSerializableTypeInfoDictionaryPtr val) { obj->mDictionaryTypeInfo = val; }
+		void setKey(ManagedSerializableDictionaryKeyValue* obj, ManagedSerializableFieldDataPtr val)
+		{
+			obj->key = val;
+		}
 
-		ManagedSerializableFieldDataPtr getKeyEntry(ManagedSerializableDictionary* obj, UINT32 arrayIdx) 
-		{ 
-			SPtr<SerializationData> data = any_cast<SPtr<SerializationData>>(obj->mRTTIData);
-			return data->keyEntries[arrayIdx];
+		ManagedSerializableFieldDataPtr getValue(ManagedSerializableDictionaryKeyValue* obj)
+		{
+			return obj->value;
 		}
 
-		void setKeyEntry(ManagedSerializableDictionary* obj, UINT32 arrayIdx, ManagedSerializableFieldDataPtr val) 
-		{ 
-			SPtr<SerializationData> data = any_cast<SPtr<SerializationData>>(obj->mRTTIData);
-			data->keyEntries[arrayIdx] = val;
+		void setValue(ManagedSerializableDictionaryKeyValue* obj, ManagedSerializableFieldDataPtr val)
+		{
+			obj->value = val;
 		}
 
-		UINT32 getNumKeyEntries(ManagedSerializableDictionary* obj) 
-		{ 
-			SPtr<SerializationData> data = any_cast<SPtr<SerializationData>>(obj->mRTTIData);
-			return (UINT32)data->keyEntries.size();
+	public:
+		ManagedSerializableDictionaryKeyValueRTTI()
+		{
+			addReflectablePtrField("key", 0, &ManagedSerializableDictionaryKeyValueRTTI::getKey, &ManagedSerializableDictionaryKeyValueRTTI::setKey);
+			addReflectablePtrField("value", 1, &ManagedSerializableDictionaryKeyValueRTTI::getValue, &ManagedSerializableDictionaryKeyValueRTTI::setValue);
+		}
+		
+		virtual const String& getRTTIName()
+		{
+			static String name = "ManagedSerializableDictionaryKeyValue";
+			return name;
 		}
 
-		void setNumKeyEntries(ManagedSerializableDictionary* obj, UINT32 numEntries) 
-		{ 
-			SPtr<SerializationData> data = any_cast<SPtr<SerializationData>>(obj->mRTTIData);
-			data->keyEntries.resize(numEntries);
+		virtual UINT32 getRTTIId()
+		{
+			return TID_ScriptSerializableDictionaryKeyValue;
 		}
 
-		ManagedSerializableFieldDataPtr getValueEntry(ManagedSerializableDictionary* obj, UINT32 arrayIdx) 
-		{ 
-			SPtr<SerializationData> data = any_cast<SPtr<SerializationData>>(obj->mRTTIData);
-			return data->valueEntries[arrayIdx];
+		virtual std::shared_ptr<IReflectable> newRTTIObject()
+		{
+			return bs_shared_ptr<ManagedSerializableDictionaryKeyValue>();
 		}
+	};
 
-		void setValueEntry(ManagedSerializableDictionary* obj, UINT32 arrayIdx, ManagedSerializableFieldDataPtr val) 
+	class BS_SCR_BE_EXPORT ManagedSerializableDictionaryRTTI : public RTTIType<ManagedSerializableDictionary, IReflectable, ManagedSerializableDictionaryRTTI>
+	{
+	private:
+		ManagedSerializableTypeInfoDictionaryPtr getTypeInfo(ManagedSerializableDictionary* obj) { return obj->mDictionaryTypeInfo; }
+		void setTypeInfo(ManagedSerializableDictionary* obj, ManagedSerializableTypeInfoDictionaryPtr val) { obj->mDictionaryTypeInfo = val; }
+
+		ManagedSerializableDictionaryKeyValue& getEntry(ManagedSerializableDictionary* obj, UINT32 arrayIdx)
 		{ 
-			SPtr<SerializationData> data = any_cast<SPtr<SerializationData>>(obj->mRTTIData);
-			data->valueEntries[arrayIdx] = val;
+			ManagedSerializableDictionaryPtr data = any_cast<ManagedSerializableDictionaryPtr>(obj->mRTTIData);
+			Vector<ManagedSerializableDictionaryKeyValue>& sequentialData = any_cast_ref<Vector<ManagedSerializableDictionaryKeyValue>>(data->mRTTIData);
+
+			return sequentialData[arrayIdx];
 		}
 
-		UINT32 getNumValueEntries(ManagedSerializableDictionary* obj) 
+		void setEntry(ManagedSerializableDictionary* obj, UINT32 arrayIdx, ManagedSerializableDictionaryKeyValue& val)
 		{ 
-			SPtr<SerializationData> data = any_cast<SPtr<SerializationData>>(obj->mRTTIData);
-			return (UINT32)data->valueEntries.size();
+			obj->setFieldData(val.key, val.value);
 		}
 
-		void setNumValueEntries(ManagedSerializableDictionary* obj, UINT32 numEntries) 
+		UINT32 getNumEntries(ManagedSerializableDictionary* obj) 
 		{ 
-			SPtr<SerializationData> data = any_cast<SPtr<SerializationData>>(obj->mRTTIData);
-			data->valueEntries.resize(numEntries);
+			ManagedSerializableDictionaryPtr data = any_cast<ManagedSerializableDictionaryPtr>(obj->mRTTIData);
+			Vector<ManagedSerializableDictionaryKeyValue>& sequentialData = any_cast_ref<Vector<ManagedSerializableDictionaryKeyValue>>(data->mRTTIData);
+
+			return (UINT32)sequentialData.size();
 		}
 
+		void setNumEntries(ManagedSerializableDictionary* obj, UINT32 numEntries) 
+		{ 
+			// Do nothing
+		}
+		
 	public:
 		ManagedSerializableDictionaryRTTI()
 		{
 			addReflectablePtrField("mListTypeInfo", 0, &ManagedSerializableDictionaryRTTI::getTypeInfo, &ManagedSerializableDictionaryRTTI::setTypeInfo);
-			addReflectablePtrArrayField("mKeyEntries", 1, &ManagedSerializableDictionaryRTTI::getKeyEntry, &ManagedSerializableDictionaryRTTI::getNumKeyEntries, 
-				&ManagedSerializableDictionaryRTTI::setKeyEntry, &ManagedSerializableDictionaryRTTI::setNumKeyEntries);
-			addReflectablePtrArrayField("mValueEntries", 2, &ManagedSerializableDictionaryRTTI::getValueEntry, &ManagedSerializableDictionaryRTTI::getNumValueEntries, 
-				&ManagedSerializableDictionaryRTTI::setValueEntry, &ManagedSerializableDictionaryRTTI::setNumValueEntries);
+			addReflectableArrayField("mEntries", 1, &ManagedSerializableDictionaryRTTI::getEntry, &ManagedSerializableDictionaryRTTI::getNumEntries,
+				&ManagedSerializableDictionaryRTTI::setEntry, &ManagedSerializableDictionaryRTTI::setNumEntries);
 		}
 
 		virtual void onSerializationStarted(IReflectable* obj)
 		{
 			ManagedSerializableDictionary* serializableObject = static_cast<ManagedSerializableDictionary*>(obj);
 
-			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)
-		{
-			ManagedSerializableDictionary* serializableObject = static_cast<ManagedSerializableDictionary*>(obj);
-
-			serializableObject->mRTTIData = bs_shared_ptr<SerializationData>();
-			SPtr<SerializationData> data = any_cast<SPtr<SerializationData>>(serializableObject->mRTTIData);
+			Vector<ManagedSerializableDictionaryKeyValue> sequentialData;
+			auto enumerator = serializableObject->getEnumerator();
 
-			// 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)
-			data->isGameObjectDeserialization = GameObjectManager::instance().isGameObjectDeserializationActive();
+			while (enumerator.moveNext())
+				sequentialData.push_back(ManagedSerializableDictionaryKeyValue(enumerator.getKey(), enumerator.getValue()));
 
-			if (data->isGameObjectDeserialization)
-				GameObjectManager::instance().registerOnDeserializationEndCallback([=]() { serializableObject->deserializeManagedInstance(data->keyEntries, data->valueEntries); });
+			serializableObject->mRTTIData = sequentialData;
 		}
 
-		virtual void onDeserializationEnded(IReflectable* obj)
+		virtual void onSerializationEnded(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;
 		}
 

+ 37 - 0
SBansheeEngine/Include/BsManagedSerializableField.h

@@ -9,6 +9,8 @@ namespace BansheeEngine
 	class BS_SCR_BE_EXPORT ManagedSerializableFieldKey : public IReflectable
 	{
 	public:
+		ManagedSerializableFieldKey();
+		ManagedSerializableFieldKey(UINT16 typeId, UINT16 fieldId);
 		static ManagedSerializableFieldKeyPtr create(UINT16 typeId, UINT16 fieldId);
 
 		UINT16 mTypeId;
@@ -33,6 +35,10 @@ namespace BansheeEngine
 		virtual void* getValue(const ManagedSerializableTypeInfoPtr& typeInfo) = 0;
 		virtual MonoObject* getValueBoxed(const ManagedSerializableTypeInfoPtr& typeInfo) = 0;
 		virtual bool equals(const ManagedSerializableFieldDataPtr& other) = 0;
+		virtual size_t getHash() = 0;
+
+		virtual void serialize() { }
+		virtual void deserialize() { }
 
 		/************************************************************************/
 		/* 								RTTI		                     		*/
@@ -70,6 +76,7 @@ namespace BansheeEngine
 		void* getValue(const ManagedSerializableTypeInfoPtr& typeInfo) override;
 		MonoObject* getValueBoxed(const ManagedSerializableTypeInfoPtr& typeInfo) override;
 		bool equals(const ManagedSerializableFieldDataPtr& other) override;
+		size_t getHash() override;
 
 		/************************************************************************/
 		/* 								RTTI		                     		*/
@@ -89,6 +96,7 @@ namespace BansheeEngine
 		void* getValue(const ManagedSerializableTypeInfoPtr& typeInfo) override;
 		MonoObject* getValueBoxed(const ManagedSerializableTypeInfoPtr& typeInfo) override;
 		bool equals(const ManagedSerializableFieldDataPtr& other) override;
+		size_t getHash() override;
 
 		/************************************************************************/
 		/* 								RTTI		                     		*/
@@ -108,6 +116,7 @@ namespace BansheeEngine
 		void* getValue(const ManagedSerializableTypeInfoPtr& typeInfo) override;
 		MonoObject* getValueBoxed(const ManagedSerializableTypeInfoPtr& typeInfo) override;
 		bool equals(const ManagedSerializableFieldDataPtr& other) override;
+		size_t getHash() override;
 
 		/************************************************************************/
 		/* 								RTTI		                     		*/
@@ -127,6 +136,7 @@ namespace BansheeEngine
 		void* getValue(const ManagedSerializableTypeInfoPtr& typeInfo) override;
 		MonoObject* getValueBoxed(const ManagedSerializableTypeInfoPtr& typeInfo) override;
 		bool equals(const ManagedSerializableFieldDataPtr& other) override;
+		size_t getHash() override;
 
 		/************************************************************************/
 		/* 								RTTI		                     		*/
@@ -146,6 +156,7 @@ namespace BansheeEngine
 		void* getValue(const ManagedSerializableTypeInfoPtr& typeInfo) override;
 		MonoObject* getValueBoxed(const ManagedSerializableTypeInfoPtr& typeInfo) override;
 		bool equals(const ManagedSerializableFieldDataPtr& other) override;
+		size_t getHash() override;
 
 		/************************************************************************/
 		/* 								RTTI		                     		*/
@@ -165,6 +176,7 @@ namespace BansheeEngine
 		void* getValue(const ManagedSerializableTypeInfoPtr& typeInfo) override;
 		MonoObject* getValueBoxed(const ManagedSerializableTypeInfoPtr& typeInfo) override;
 		bool equals(const ManagedSerializableFieldDataPtr& other) override;
+		size_t getHash() override;
 
 		/************************************************************************/
 		/* 								RTTI		                     		*/
@@ -184,6 +196,7 @@ namespace BansheeEngine
 		void* getValue(const ManagedSerializableTypeInfoPtr& typeInfo) override;
 		MonoObject* getValueBoxed(const ManagedSerializableTypeInfoPtr& typeInfo) override;
 		bool equals(const ManagedSerializableFieldDataPtr& other) override;
+		size_t getHash() override;
 
 		/************************************************************************/
 		/* 								RTTI		                     		*/
@@ -203,6 +216,7 @@ namespace BansheeEngine
 		void* getValue(const ManagedSerializableTypeInfoPtr& typeInfo) override;
 		MonoObject* getValueBoxed(const ManagedSerializableTypeInfoPtr& typeInfo) override;
 		bool equals(const ManagedSerializableFieldDataPtr& other) override;
+		size_t getHash() override;
 
 		/************************************************************************/
 		/* 								RTTI		                     		*/
@@ -222,6 +236,7 @@ namespace BansheeEngine
 		void* getValue(const ManagedSerializableTypeInfoPtr& typeInfo) override;
 		MonoObject* getValueBoxed(const ManagedSerializableTypeInfoPtr& typeInfo) override;
 		bool equals(const ManagedSerializableFieldDataPtr& other) override;
+		size_t getHash() override;
 
 		/************************************************************************/
 		/* 								RTTI		                     		*/
@@ -241,6 +256,7 @@ namespace BansheeEngine
 		void* getValue(const ManagedSerializableTypeInfoPtr& typeInfo) override;
 		MonoObject* getValueBoxed(const ManagedSerializableTypeInfoPtr& typeInfo) override;
 		bool equals(const ManagedSerializableFieldDataPtr& other) override;
+		size_t getHash() override;
 
 		/************************************************************************/
 		/* 								RTTI		                     		*/
@@ -260,6 +276,7 @@ namespace BansheeEngine
 		void* getValue(const ManagedSerializableTypeInfoPtr& typeInfo) override;
 		MonoObject* getValueBoxed(const ManagedSerializableTypeInfoPtr& typeInfo) override;
 		bool equals(const ManagedSerializableFieldDataPtr& other) override;
+		size_t getHash() override;
 
 		/************************************************************************/
 		/* 								RTTI		                     		*/
@@ -280,6 +297,7 @@ namespace BansheeEngine
 		void* getValue(const ManagedSerializableTypeInfoPtr& typeInfo) override;
 		MonoObject* getValueBoxed(const ManagedSerializableTypeInfoPtr& typeInfo) override;
 		bool equals(const ManagedSerializableFieldDataPtr& other) override;
+		size_t getHash() override;
 
 		/************************************************************************/
 		/* 								RTTI		                     		*/
@@ -299,6 +317,7 @@ namespace BansheeEngine
 		void* getValue(const ManagedSerializableTypeInfoPtr& typeInfo) override;
 		MonoObject* getValueBoxed(const ManagedSerializableTypeInfoPtr& typeInfo) override;
 		bool equals(const ManagedSerializableFieldDataPtr& other) override;
+		size_t getHash() override;
 
 		/************************************************************************/
 		/* 								RTTI		                     		*/
@@ -318,6 +337,7 @@ namespace BansheeEngine
 		void* getValue(const ManagedSerializableTypeInfoPtr& typeInfo) override;
 		MonoObject* getValueBoxed(const ManagedSerializableTypeInfoPtr& typeInfo) override;
 		bool equals(const ManagedSerializableFieldDataPtr& other) override;
+		size_t getHash() override;
 
 		/************************************************************************/
 		/* 								RTTI		                     		*/
@@ -337,6 +357,7 @@ namespace BansheeEngine
 		void* getValue(const ManagedSerializableTypeInfoPtr& typeInfo) override;
 		MonoObject* getValueBoxed(const ManagedSerializableTypeInfoPtr& typeInfo) override;
 		bool equals(const ManagedSerializableFieldDataPtr& other) override;
+		size_t getHash() override;
 
 		/************************************************************************/
 		/* 								RTTI		                     		*/
@@ -356,6 +377,10 @@ namespace BansheeEngine
 		void* getValue(const ManagedSerializableTypeInfoPtr& typeInfo) override;
 		MonoObject* getValueBoxed(const ManagedSerializableTypeInfoPtr& typeInfo) override;
 		bool equals(const ManagedSerializableFieldDataPtr& other) override;
+		size_t getHash() override;
+
+		virtual void serialize() override;
+		virtual void deserialize() override;
 
 		/************************************************************************/
 		/* 								RTTI		                     		*/
@@ -375,6 +400,10 @@ namespace BansheeEngine
 		void* getValue(const ManagedSerializableTypeInfoPtr& typeInfo) override;
 		MonoObject* getValueBoxed(const ManagedSerializableTypeInfoPtr& typeInfo) override;
 		bool equals(const ManagedSerializableFieldDataPtr& other) override;
+		size_t getHash() override;
+
+		virtual void serialize() override;
+		virtual void deserialize() override;
 
 		/************************************************************************/
 		/* 								RTTI		                     		*/
@@ -394,6 +423,10 @@ namespace BansheeEngine
 		void* getValue(const ManagedSerializableTypeInfoPtr& typeInfo) override;
 		MonoObject* getValueBoxed(const ManagedSerializableTypeInfoPtr& typeInfo) override;
 		bool equals(const ManagedSerializableFieldDataPtr& other) override;
+		size_t getHash() override;
+
+		virtual void serialize() override;
+		virtual void deserialize() override;
 
 		/************************************************************************/
 		/* 								RTTI		                     		*/
@@ -413,6 +446,10 @@ namespace BansheeEngine
 		void* getValue(const ManagedSerializableTypeInfoPtr& typeInfo) override;
 		MonoObject* getValueBoxed(const ManagedSerializableTypeInfoPtr& typeInfo) override;
 		bool equals(const ManagedSerializableFieldDataPtr& other) override;
+		size_t getHash() override;
+
+		virtual void serialize() override;
+		virtual void deserialize() override;
 
 		/************************************************************************/
 		/* 								RTTI		                     		*/

+ 20 - 7
SBansheeEngine/Include/BsManagedSerializableList.h

@@ -6,6 +6,21 @@
 
 namespace BansheeEngine
 {
+	/**
+	 * @brief	TODO
+	 *
+	 * @note	This class can be in two states:
+	 *			 - Linked - When the object has a link to a managed object. This is the default 
+	 *                      state when a new instance of ManagedSerializableObject is created.
+	 *						Any operations during this state will operate directly on the linked
+	 *						managed object.
+	 *			 - Serialized - When the object has no link to the managed object but instead just
+	 *							contains cached object and field data that may be used for initializing
+	 *							a managed object. Any operations during this state will operate
+	 *							only on the cached internal data.
+	 *			You can transfer between these states by calling serialize(linked->serialized) &
+	 *	
+	 */
 	class BS_SCR_BE_EXPORT ManagedSerializableList : public IReflectable
 	{
 	private:
@@ -16,14 +31,15 @@ namespace BansheeEngine
 		ManagedSerializableList(const ConstructPrivately& dummy);
 
 		MonoObject* getManagedInstance() const { return mManagedInstance; }
+		ManagedSerializableTypeInfoListPtr getTypeInfo() const { return mListTypeInfo; }
 
 		void resize(UINT32 newSize);
 		void setFieldData(UINT32 arrayIdx, const ManagedSerializableFieldDataPtr& val);
-		void addFieldData(const ManagedSerializableFieldDataPtr& val);
 		ManagedSerializableFieldDataPtr getFieldData(UINT32 arrayIdx);
 		UINT32 getLength() const { return mNumElements; }
 
-		ManagedSerializableTypeInfoListPtr getTypeInfo() const { return mListTypeInfo; }
+		void serialize();
+		void deserialize();
 
 		static ManagedSerializableListPtr createFromExisting(MonoObject* managedInstance, const ManagedSerializableTypeInfoListPtr& typeInfo);
 		static ManagedSerializableListPtr createNew(const ManagedSerializableTypeInfoListPtr& typeInfo, UINT32 size);
@@ -40,15 +56,12 @@ namespace BansheeEngine
 		MonoProperty* mCountProp;
 
 		ManagedSerializableTypeInfoListPtr mListTypeInfo;
+		Vector<ManagedSerializableFieldDataPtr> mCachedEntries;
 		UINT32 mNumElements;
 
 		void initMonoObjects(MonoClass* listClass);
 		UINT32 getLengthInternal() const;
-
-		/**
-		 * @brief	Creates a new managed instance and populates it with stored field data.
-		 */
-		void deserializeManagedInstance(const Vector<ManagedSerializableFieldDataPtr>& entries);
+		void addFieldDataInternal(const ManagedSerializableFieldDataPtr& val);
 
 		/************************************************************************/
 		/* 								RTTI		                     		*/

+ 4 - 42
SBansheeEngine/Include/BsManagedSerializableListRTTI.h

@@ -2,23 +2,13 @@
 
 #include "BsScriptEnginePrerequisites.h"
 #include "BsRTTIType.h"
-#include "BsGameObjectManager.h"
 #include "BsManagedSerializableList.h"
-#include "BsScriptAssemblyManager.h"
-#include "BsMonoManager.h"
-#include "BsMonoClass.h"
 
 namespace BansheeEngine
 {
 	class BS_SCR_BE_EXPORT ManagedSerializableListRTTI : public RTTIType<ManagedSerializableList, IReflectable, ManagedSerializableListRTTI>
 	{
 	private:
-		struct DeserializationInfo
-		{
-			Vector<ManagedSerializableFieldDataPtr> fields;
-			bool isGameObjectDeserialization;
-		};
-
 		ManagedSerializableTypeInfoListPtr getTypeInfo(ManagedSerializableList* obj)
 		{
 			return obj->mListTypeInfo;
@@ -31,7 +21,7 @@ namespace BansheeEngine
 
 		UINT32& getNumElements(ManagedSerializableList* obj)
 		{
-			return (UINT32)obj->mNumElements;
+			return (UINT32&)obj->mNumElements;
 		}
 
 		void setNumElements(ManagedSerializableList* obj, UINT32& numElements)
@@ -46,19 +36,17 @@ namespace BansheeEngine
 
 		void setListEntry(ManagedSerializableList* obj, UINT32 arrayIdx, ManagedSerializableFieldDataPtr val)
 		{
-			SPtr<DeserializationInfo> info = any_cast<SPtr<DeserializationInfo>>(obj->mRTTIData);
-			info->fields[arrayIdx] = val;
+			obj->setFieldData(arrayIdx, val);
 		}
 
 		UINT32 getNumListEntries(ManagedSerializableList* obj)
 		{
-			return obj->mNumElements;
+			return (UINT32)obj->mNumElements;
 		}
 
 		void setNumListEntries(ManagedSerializableList* obj, UINT32 numEntries)
 		{
-			SPtr<DeserializationInfo> info = any_cast<SPtr<DeserializationInfo>>(obj->mRTTIData);
-			info->fields = Vector<ManagedSerializableFieldDataPtr>(numEntries);
+			obj->mCachedEntries = Vector<ManagedSerializableFieldDataPtr>(numEntries);
 		}
 
 	public:
@@ -70,32 +58,6 @@ namespace BansheeEngine
 				&ManagedSerializableListRTTI::setListEntry, &ManagedSerializableListRTTI::setNumListEntries);
 		}
 
-		virtual void onDeserializationStarted(IReflectable* obj)
-		{
-			ManagedSerializableList* serializableObject = static_cast<ManagedSerializableList*>(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
-			// 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 onDeserializationEnded(IReflectable* obj)
-		{
-			ManagedSerializableList* serializableObject = static_cast<ManagedSerializableList*>(obj);
-			SPtr<DeserializationInfo> info = any_cast<SPtr<DeserializationInfo>>(serializableObject->mRTTIData);
-
-			if (!info->isGameObjectDeserialization)
-				serializableObject->deserializeManagedInstance(info->fields);
-
-			serializableObject->mRTTIData = nullptr;
-		}
-
 		virtual const String& getRTTIName()
 		{
 			static String name = "ScriptSerializableList";

+ 30 - 9
SBansheeEngine/Include/BsManagedSerializableObject.h

@@ -2,15 +2,41 @@
 
 #include "BsScriptEnginePrerequisites.h"
 #include "BsIReflectable.h"
+#include "BsManagedSerializableField.h"
 #include <mono/jit/jit.h>
 
 namespace BansheeEngine
 {
+	/**
+	 * @brief	TODO
+	 *
+	 * @note	This class can be in two states:
+	 *			 - Linked - When the object has a link to a managed object. This is the default 
+	 *                      state when a new instance of ManagedSerializableObject is created.
+	 *						Any operations during this state will operate directly on the linked
+	 *						managed object.
+	 *			 - Serialized - When the object has no link to the managed object but instead just
+	 *							contains cached object and field data that may be used for initializing
+	 *							a managed object. Any operations during this state will operate
+	 *							only on the cached internal data.
+	 *			You can transfer between these states by calling serialize(linked->serialized) &
+	 *			deserialize(serialized->linked).
+	 */
 	class BS_SCR_BE_EXPORT ManagedSerializableObject : public IReflectable
 	{
 	private:
 		struct ConstructPrivately {};
 
+		struct BS_SCR_BE_EXPORT Hash
+		{
+			inline size_t operator()(const ManagedSerializableFieldKey& x) const;
+		};
+
+		struct BS_SCR_BE_EXPORT Equals
+		{
+			inline bool operator()(const ManagedSerializableFieldKey& a, const ManagedSerializableFieldKey& b) const;
+		};
+
 	public:
 		ManagedSerializableObject(const ConstructPrivately& dummy, ManagedSerializableObjectInfoPtr objInfo, MonoObject* managedInstance);
 		ManagedSerializableObject(const ConstructPrivately& dummy);
@@ -21,22 +47,17 @@ namespace BansheeEngine
 		void setFieldData(const ManagedSerializableFieldInfoPtr& fieldInfo, const ManagedSerializableFieldDataPtr& val);
 		ManagedSerializableFieldDataPtr getFieldData(const ManagedSerializableFieldInfoPtr& fieldInfo) const;
 
-		void setObjectData(const ManagedSerializableObjectDataPtr& objectData, const ManagedSerializableObjectInfoPtr& originalEntriesType);
-		ManagedSerializableObjectDataPtr getObjectData() const;
+		void serialize();
+		void deserialize();
 
 		static ManagedSerializableObjectPtr createFromExisting(MonoObject* managedInstance);
 		static ManagedSerializableObjectPtr createNew(const ManagedSerializableTypeInfoObjectPtr& type);
 		static MonoObject* createManagedInstance(const ManagedSerializableTypeInfoObjectPtr& type);
 	protected:
-		ManagedSerializableObjectInfoPtr mObjInfo;
 		MonoObject* mManagedInstance;
 
-		/**
-		 * @brief	Creates a new managed instance and populates it with provided field data.
-		 */
-		void deserializeManagedInstance(const Vector<ManagedSerializableFieldDataEntryPtr>& data);
-
-		void setFieldEntries(const Vector<ManagedSerializableFieldDataEntryPtr>& data, const ManagedSerializableObjectInfoPtr& originalEntriesType);
+		ManagedSerializableObjectInfoPtr mObjInfo;
+		UnorderedMap<ManagedSerializableFieldKey, ManagedSerializableFieldDataPtr, Hash, Equals> mCachedData;
 
 		/************************************************************************/
 		/* 								RTTI		                     		*/

+ 0 - 23
SBansheeEngine/Include/BsManagedSerializableObjectData.h

@@ -1,23 +0,0 @@
-#pragma once
-
-#include "BsScriptEnginePrerequisites.h"
-#include "BsIReflectable.h"
-#include <mono/jit/jit.h>
-
-namespace BansheeEngine
-{
-	class BS_SCR_BE_EXPORT ManagedSerializableObjectData : public IReflectable
-	{
-	public:
-		Vector<ManagedSerializableFieldDataEntryPtr> mFieldData;
-
-		/************************************************************************/
-		/* 								RTTI		                     		*/
-		/************************************************************************/
-
-	public:
-		friend class ManagedSerializableObjectDataRTTI;
-		static RTTITypeBase* getRTTIStatic();
-		virtual RTTITypeBase* getRTTI() const;
-	};
-}

+ 0 - 56
SBansheeEngine/Include/BsManagedSerializableObjectDataRTTI.h

@@ -1,56 +0,0 @@
-#pragma once
-
-#include "BsScriptEnginePrerequisites.h"
-#include "BsRTTIType.h"
-#include "BsManagedSerializableObjectData.h"
-#include "BsManagedSerializableField.h"
-
-namespace BansheeEngine
-{
-	class BS_SCR_BE_EXPORT ManagedSerializableObjectDataRTTI : public RTTIType <ManagedSerializableObjectData, IReflectable, ManagedSerializableObjectDataRTTI>
-	{
-	private:
-		ManagedSerializableFieldDataEntryPtr getFieldEntry(ManagedSerializableObjectData* obj, UINT32 arrayIdx)
-		{
-			return obj->mFieldData[arrayIdx];
-		}
-
-		void setFieldsEntry(ManagedSerializableObjectData* obj, UINT32 arrayIdx, ManagedSerializableFieldDataEntryPtr val)
-		{
-			obj->mFieldData[arrayIdx] = val;
-		}
-
-		UINT32 getNumFieldEntries(ManagedSerializableObjectData* obj)
-		{
-			return (UINT32)obj->mFieldData.size();
-		}
-
-		void setNumFieldEntries(ManagedSerializableObjectData* obj, UINT32 numEntries)
-		{
-			obj->mFieldData = Vector<ManagedSerializableFieldDataEntryPtr>(numEntries);
-		}
-
-	public:
-		ManagedSerializableObjectDataRTTI()
-		{
-			addReflectablePtrArrayField("mFieldEntries", 0, &ManagedSerializableObjectDataRTTI::getFieldEntry, &ManagedSerializableObjectDataRTTI::getNumFieldEntries,
-				&ManagedSerializableObjectDataRTTI::setFieldsEntry, &ManagedSerializableObjectDataRTTI::setNumFieldEntries);
-		}
-
-		virtual const String& getRTTIName()
-		{
-			static String name = "ScriptSerializableObjectData";
-			return name;
-		}
-
-		virtual UINT32 getRTTIId()
-		{
-			return TID_ScriptSerializableObjectData;
-		}
-
-		virtual std::shared_ptr<IReflectable> newRTTIObject()
-		{
-			return bs_shared_ptr<ManagedSerializableObjectData>();;
-		}
-	};
-}

+ 2 - 15
SBansheeEngine/Include/BsManagedSerializableObjectInfo.h

@@ -85,6 +85,7 @@ namespace BansheeEngine
 		String mTypeNamespace;
 		String mTypeName;
 		bool mValueType;
+		UINT32 mTypeId;
 
 		bool matches(const ManagedSerializableTypeInfoPtr& typeInfo) const;
 		bool isTypeLoaded() const;
@@ -166,6 +167,7 @@ namespace BansheeEngine
 
 		String mName;
 		UINT32 mFieldId;
+		UINT32 mParentTypeId;
 
 		ManagedSerializableTypeInfoPtr mTypeInfo;
 		ScriptFieldFlags mFlags;
@@ -186,26 +188,13 @@ namespace BansheeEngine
 	class BS_SCR_BE_EXPORT ManagedSerializableObjectInfo : public IReflectable
 	{
 	public:
-		struct CachedField
-		{
-			CachedField(const SPtr<ManagedSerializableFieldInfo>& info, UINT32 typeId)
-				:info(info), parentTypeId(typeId)
-			{ }
-
-			SPtr<ManagedSerializableFieldInfo> info;
-			UINT32 parentTypeId;
-		};
-
 		ManagedSerializableObjectInfo();
-		void initialize();
 
 		String getFullTypeName() const { return mTypeInfo->mTypeNamespace + "." + mTypeInfo->mTypeName; }
 		ManagedSerializableFieldInfoPtr findMatchingField(const ManagedSerializableFieldInfoPtr& fieldInfo,
 			const ManagedSerializableTypeInfoPtr& fieldTypeInfo) const;
 
 		ManagedSerializableTypeInfoObjectPtr mTypeInfo;
-		UINT32 mTypeId;
-
 		MonoClass* mMonoClass;
 
 		UnorderedMap<String, UINT32> mFieldNameToId;
@@ -214,8 +203,6 @@ namespace BansheeEngine
 		std::shared_ptr<ManagedSerializableObjectInfo> mBaseClass;
 		Vector<std::weak_ptr<ManagedSerializableObjectInfo>> mDerivedClasses;
 
-		Vector<CachedField> mCachedAllFields;
-
 		/************************************************************************/
 		/* 								RTTI		                     		*/
 		/************************************************************************/

+ 26 - 20
SBansheeEngine/Include/BsManagedSerializableObjectInfoRTTI.h

@@ -31,8 +31,8 @@ namespace BansheeEngine
 
 		void setSerializableObjectInfo(ManagedSerializableAssemblyInfo* obj, UINT32 idx, ManagedSerializableObjectInfoPtr val) 
 		{ 
-			obj->mTypeNameToId[val->getFullTypeName()] = val->mTypeId;
-			obj->mObjectInfos[val->mTypeId] = val;
+			obj->mTypeNameToId[val->getFullTypeName()] = val->mTypeInfo->mTypeId;
+			obj->mObjectInfos[val->mTypeInfo->mTypeId] = val;
 		}
 		
 		UINT32 getSerializableObjectInfoArraySize(ManagedSerializableAssemblyInfo* obj) { return (UINT32)obj->mObjectInfos.size(); }
@@ -77,16 +77,6 @@ namespace BansheeEngine
 			obj->mTypeInfo = val;
 		}
 
-		UINT32& getTypeId(ManagedSerializableObjectInfo* obj)
-		{
-			return obj->mTypeId;
-		}
-
-		void setTypeId(ManagedSerializableObjectInfo* obj, UINT32& val)
-		{
-			obj->mTypeId = val;
-		}
-
 		ManagedSerializableObjectInfoPtr getBaseClass(ManagedSerializableObjectInfo* obj)
 		{
 			return obj->mBaseClass;
@@ -119,7 +109,6 @@ namespace BansheeEngine
 		ManagedSerializableObjectInfoRTTI()
 		{
 			addReflectablePtrField("mTypeInfo", 0, &ManagedSerializableObjectInfoRTTI::getTypeInfo, &ManagedSerializableObjectInfoRTTI::setTypeInfo);
-			addPlainField("mTypeId", 1, &ManagedSerializableObjectInfoRTTI::getTypeId, &ManagedSerializableObjectInfoRTTI::setTypeId);
 			addReflectablePtrField("mBaseClass", 2, &ManagedSerializableObjectInfoRTTI::getBaseClass, &ManagedSerializableObjectInfoRTTI::setBaseClass);
 
 			addReflectablePtrArrayField("mFields", 3, &ManagedSerializableObjectInfoRTTI::getSerializableFieldInfo, 
@@ -127,12 +116,6 @@ namespace BansheeEngine
 				&ManagedSerializableObjectInfoRTTI::setSerializableFieldInfoArraySize);
 		}
 
-		void onDeserializationEnded(IReflectable* obj)
-		{
-			ManagedSerializableObjectInfo* objInfo = static_cast<ManagedSerializableObjectInfo*>(obj);
-			objInfo->initialize();
-		}
-
 		virtual const String& getRTTIName()
 		{
 			static String name = "ScriptSerializableObjectInfo";
@@ -183,6 +166,16 @@ namespace BansheeEngine
 			obj->mFieldId = val;
 		}
 
+		UINT32& getParentTypeId(ManagedSerializableFieldInfo* obj)
+		{
+			return obj->mParentTypeId;
+		}
+
+		void setParentTypeId(ManagedSerializableFieldInfo* obj, UINT32& val)
+		{
+			obj->mParentTypeId = val;
+		}
+
 		UINT32& getFlags(ManagedSerializableFieldInfo* obj)
 		{
 			return (UINT32&)obj->mFlags;
@@ -200,6 +193,7 @@ namespace BansheeEngine
 			addReflectablePtrField("mTypeInfo", 1, &ManagedSerializableFieldInfoRTTI::getTypeInfo, &ManagedSerializableFieldInfoRTTI::setTypeInfo);
 			addPlainField("mFieldId", 2, &ManagedSerializableFieldInfoRTTI::getFieldId, &ManagedSerializableFieldInfoRTTI::setFieldId);
 			addPlainField("mFlags", 3, &ManagedSerializableFieldInfoRTTI::getFlags, &ManagedSerializableFieldInfoRTTI::setFlags);
+			addPlainField("mParentTypeId", 4, &ManagedSerializableFieldInfoRTTI::getParentTypeId, &ManagedSerializableFieldInfoRTTI::setParentTypeId);
 		}
 
 		virtual const String& getRTTIName()
@@ -214,7 +208,8 @@ namespace BansheeEngine
 		}
 
 		virtual std::shared_ptr<IReflectable> newRTTIObject()
-		{return bs_shared_ptr<ManagedSerializableFieldInfo>();
+		{
+			return bs_shared_ptr<ManagedSerializableFieldInfo>();
 		}
 	};
 
@@ -314,12 +309,23 @@ namespace BansheeEngine
 			obj->mValueType = val;
 		}
 
+		UINT32& getTypeId(ManagedSerializableTypeInfoObject* obj)
+		{
+			return obj->mTypeId;
+		}
+
+		void setTypeId(ManagedSerializableTypeInfoObject* obj, UINT32& val)
+		{
+			obj->mTypeId = val;
+		}
+
 	public:
 		ManagedSerializableTypeInfoObjectRTTI()
 		{
 			addPlainField("mTypeName", 0, &ManagedSerializableTypeInfoObjectRTTI::getTypeName, &ManagedSerializableTypeInfoObjectRTTI::setTypeName);
 			addPlainField("mTypeNamespace", 1, &ManagedSerializableTypeInfoObjectRTTI::getTypeNamespace, &ManagedSerializableTypeInfoObjectRTTI::setTypeNamespace);
 			addPlainField("mValueType", 2, &ManagedSerializableTypeInfoObjectRTTI::getIsValueType, &ManagedSerializableTypeInfoObjectRTTI::setIsValueType);
+			addPlainField("mTypeId", 3, &ManagedSerializableTypeInfoObjectRTTI::getIsValueType, &ManagedSerializableTypeInfoObjectRTTI::setIsValueType);
 		}
 
 		virtual const String& getRTTIName()

+ 32 - 39
SBansheeEngine/Include/BsManagedSerializableObjectRTTI.h

@@ -5,20 +5,12 @@
 #include "BsScriptAssemblyManager.h"
 #include "BsManagedSerializableObject.h"
 #include "BsManagedSerializableField.h"
-#include "BsGameObjectManager.h"
-#include "BsMonoClass.h"
 
 namespace BansheeEngine
 {
 	class BS_SCR_BE_EXPORT ManagedSerializableObjectRTTI : public RTTIType<ManagedSerializableObject, IReflectable, ManagedSerializableObjectRTTI>
 	{
 	private:
-		struct DeserializationInfo
-		{
-			Vector<ManagedSerializableFieldDataEntryPtr> fields;
-			bool isGameObjectDeserialization;
-		};
-
 		ManagedSerializableObjectInfoPtr getInfo(ManagedSerializableObject* obj)
 		{
 			return obj->mObjInfo;
@@ -31,29 +23,33 @@ namespace BansheeEngine
 
 		ManagedSerializableFieldDataEntryPtr getFieldEntry(ManagedSerializableObject* obj, UINT32 arrayIdx)
 		{
-			ManagedSerializableObjectInfo::CachedField field = obj->mObjInfo->mCachedAllFields[arrayIdx];
+			Vector<ManagedSerializableFieldInfoPtr>& sequentialFields =
+				any_cast_ref<Vector<ManagedSerializableFieldInfoPtr>>(obj->mRTTIData);
+
+			ManagedSerializableFieldInfoPtr field = sequentialFields[arrayIdx];
 
-			ManagedSerializableFieldKeyPtr fieldKey = ManagedSerializableFieldKey::create(field.parentTypeId, field.info->mFieldId);
-			ManagedSerializableFieldDataPtr fieldData = obj->getFieldData(field.info);
+			ManagedSerializableFieldKeyPtr fieldKey = ManagedSerializableFieldKey::create(field->mParentTypeId, field->mFieldId);
+			ManagedSerializableFieldDataPtr fieldData = obj->getFieldData(field);
 
 			return ManagedSerializableFieldDataEntry::create(fieldKey, fieldData);
 		}
 
 		void setFieldsEntry(ManagedSerializableObject* obj, UINT32 arrayIdx, ManagedSerializableFieldDataEntryPtr val)
 		{
-			SPtr<DeserializationInfo> info = any_cast<SPtr<DeserializationInfo>>(obj->mRTTIData);
-			info->fields[arrayIdx] = val;
+			obj->mCachedData[*val->mKey] = val->mValue;
 		}
 
 		UINT32 getNumFieldEntries(ManagedSerializableObject* obj)
 		{
-			return (UINT32)obj->mObjInfo->mCachedAllFields.size();
+			Vector<ManagedSerializableFieldInfoPtr>& sequentialFields =
+				any_cast_ref<Vector<ManagedSerializableFieldInfoPtr>>(obj->mRTTIData);
+
+			return (UINT32)sequentialFields.size();
 		}
 
 		void setNumFieldEntries(ManagedSerializableObject* obj, UINT32 numEntries)
 		{
-			SPtr<DeserializationInfo> info = any_cast<SPtr<DeserializationInfo>>(obj->mRTTIData);
-			info->fields = Vector<ManagedSerializableFieldDataEntryPtr>(numEntries);
+			// Do nothing
 		}
 
 	public:
@@ -64,47 +60,44 @@ namespace BansheeEngine
 				&ManagedSerializableObjectRTTI::setFieldsEntry, &ManagedSerializableObjectRTTI::setNumFieldEntries);
 		}
 
-		virtual void onDeserializationStarted(IReflectable* obj)
+		virtual void onSerializationStarted(IReflectable* obj) override
 		{
-			ManagedSerializableObject* serializableObject = static_cast<ManagedSerializableObject*>(obj);
-			serializableObject->mRTTIData = bs_shared_ptr<DeserializationInfo>();
-
-			SPtr<DeserializationInfo> info = any_cast<SPtr<DeserializationInfo>>(serializableObject->mRTTIData);
+			ManagedSerializableObject* castObj = static_cast<ManagedSerializableObject*>(obj);
 
-			// 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())
+			Vector<ManagedSerializableFieldInfoPtr> sequentialFields;
+			ManagedSerializableObjectInfoPtr curType = castObj->mObjInfo;
+			while (curType != nullptr)
 			{
-				GameObjectManager::instance().registerOnDeserializationEndCallback([=]() { serializableObject->deserializeManagedInstance(info->fields); });
-				info->isGameObjectDeserialization = true;
+				for (auto& field : curType->mFields)
+				{
+					if (field.second->isSerializable())
+						sequentialFields.push_back(field.second);
+				}
+
+				curType = curType->mBaseClass;
 			}
-			else
-				info->isGameObjectDeserialization = false;
+
+			castObj->mRTTIData = sequentialFields;
 		}
 
-		virtual void onDeserializationEnded(IReflectable* obj)
+		virtual void onSerializationEnded(IReflectable* obj) override
 		{
-			ManagedSerializableObject* serializableObject = static_cast<ManagedSerializableObject*>(obj);
-			SPtr<DeserializationInfo> info = any_cast<SPtr<DeserializationInfo>>(serializableObject->mRTTIData);
-
-			if (!info->isGameObjectDeserialization)
-				serializableObject->deserializeManagedInstance(info->fields);
-
-			serializableObject->mRTTIData = nullptr;
+			ManagedSerializableObject* castObj = static_cast<ManagedSerializableObject*>(obj);
+			castObj->mRTTIData = nullptr;
 		}
 
-		virtual const String& getRTTIName()
+		virtual const String& getRTTIName() override
 		{
 			static String name = "ScriptSerializableObject";
 			return name;
 		}
 
-		virtual UINT32 getRTTIId()
+		virtual UINT32 getRTTIId() override
 		{
 			return TID_ScriptSerializableObject;
 		}
 
-		virtual std::shared_ptr<IReflectable> newRTTIObject()
+		virtual std::shared_ptr<IReflectable> newRTTIObject() override
 		{
 			return ManagedSerializableObject::createEmpty();
 		}

+ 2 - 2
SBansheeEngine/Include/BsScriptEnginePrerequisites.h

@@ -122,7 +122,8 @@ namespace BansheeEngine
 		TID_ScriptModifiedEntry = 50045,
 		TID_ScriptModifiedField = 50046,
 		TID_ScriptModifiedArrayEntry = 50047,
-		TID_ScriptModifiedDictionaryEntry = 50048
+		TID_ScriptModifiedDictionaryEntry = 50048,
+		TID_ScriptSerializableDictionaryKeyValue = 50049
 	};
 
 	typedef std::shared_ptr<ManagedSerializableFieldData> ManagedSerializableFieldDataPtr;
@@ -140,7 +141,6 @@ namespace BansheeEngine
 	typedef std::shared_ptr<ManagedSerializableTypeInfoArray> ManagedSerializableTypeInfoArrayPtr;
 	typedef std::shared_ptr<ManagedSerializableTypeInfoList> ManagedSerializableTypeInfoListPtr;
 	typedef std::shared_ptr<ManagedSerializableTypeInfoDictionary> ManagedSerializableTypeInfoDictionaryPtr;
-	typedef std::shared_ptr<ManagedSerializableObjectData> ManagedSerializableObjectDataPtr;
 	typedef std::shared_ptr<ManagedSerializableDiff> ManagedSerializableDiffPtr;
 	typedef std::shared_ptr<ManagedResource> ManagedResourcePtr;
 	typedef std::shared_ptr<ManagedResourceMetaData> ManagedResourceMetaDataPtr;

+ 0 - 3
SBansheeEngine/SBansheeEngine.vcxproj

@@ -250,8 +250,6 @@
     <ClInclude Include="Include\BsManagedSerializableList.h" />
     <ClInclude Include="Include\BsManagedSerializableListRTTI.h" />
     <ClInclude Include="Include\BsManagedSerializableObject.h" />
-    <ClInclude Include="Include\BsManagedSerializableObjectData.h" />
-    <ClInclude Include="Include\BsManagedSerializableObjectDataRTTI.h" />
     <ClInclude Include="Include\BsScriptAssemblyManager.h" />
     <ClInclude Include="Include\BsScriptAsyncOp.h" />
     <ClInclude Include="Include\BsScriptBoneWeight.h" />
@@ -335,7 +333,6 @@
     <ClCompile Include="Source\BsManagedResourceManager.cpp" />
     <ClCompile Include="Source\BsManagedResourceMetaData.cpp" />
     <ClCompile Include="Source\BsManagedSerializableDiff.cpp" />
-    <ClCompile Include="Source\BsManagedSerializableObjectData.cpp" />
     <ClCompile Include="Source\BsScriptAssemblyManager.cpp" />
     <ClCompile Include="Source\BsScriptAsyncOp.cpp" />
     <ClCompile Include="Source\BsScriptBoneWeight.cpp" />

+ 0 - 9
SBansheeEngine/SBansheeEngine.vcxproj.filters

@@ -270,12 +270,6 @@
     <ClInclude Include="Include\BsScriptAssemblyManager.h">
       <Filter>Header Files\Serialization</Filter>
     </ClInclude>
-    <ClInclude Include="Include\BsManagedSerializableObjectData.h">
-      <Filter>Header Files\Serialization</Filter>
-    </ClInclude>
-    <ClInclude Include="Include\BsManagedSerializableObjectDataRTTI.h">
-      <Filter>Header Files\Serialization\RTTI</Filter>
-    </ClInclude>
     <ClInclude Include="Include\BsScriptGUISlider.h">
       <Filter>Header Files\GUI</Filter>
     </ClInclude>
@@ -530,9 +524,6 @@
     <ClCompile Include="Source\BsScriptAssemblyManager.cpp">
       <Filter>Source Files\Serialization</Filter>
     </ClCompile>
-    <ClCompile Include="Source\BsManagedSerializableObjectData.cpp">
-      <Filter>Source Files\Serialization</Filter>
-    </ClCompile>
     <ClCompile Include="Source\BsScriptGUISlider.cpp">
       <Filter>Source Files\GUI</Filter>
     </ClCompile>

+ 12 - 40
SBansheeEngine/Source/BsManagedComponent.cpp

@@ -5,10 +5,8 @@
 #include "BsMonoUtil.h"
 #include "BsMonoMethod.h"
 #include "BsMemorySerializer.h"
-#include "BsManagedSerializableField.h"
 #include "BsManagedSerializableObject.h"
-#include "BsManagedSerializableObjectInfo.h"
-#include "BsManagedSerializableObjectData.h"
+#include "BsScriptGameObjectManager.h"
 #include "BsDebug.h"
 
 namespace BansheeEngine
@@ -60,43 +58,27 @@ namespace BansheeEngine
 			
 			if (serializableObject != nullptr)
 			{
-				ManagedSerializableObjectInfoPtr objectInfo = serializableObject->getObjectInfo();
-				ManagedSerializableObjectDataPtr objectData = serializableObject->getObjectData();
-
 				MemorySerializer ms;
 
-				backupData.mTypeInfo.size = 0;
-				backupData.mTypeInfo.data = ms.encode(objectInfo.get(), backupData.mTypeInfo.size);
-
-				backupData.mObjectData.size = 0;
-				backupData.mObjectData.data = ms.encode(objectData.get(), backupData.mObjectData.size);
+				backupData.size = 0;
+				backupData.data = ms.encode(serializableObject.get(), backupData.size);
 			}
 			else
 			{
-				backupData.mTypeInfo.size = 0;
-				backupData.mTypeInfo.data = nullptr;
-
-				backupData.mObjectData.size = 0;
-				backupData.mObjectData.data = nullptr;
+				backupData.size = 0;
+				backupData.data = nullptr;
 			}
 		}
 		else
 		{
 			MemorySerializer ms;
 
-			backupData.mTypeInfo.size = 0;
-
-			if (mMissingTypeObjectInfo != nullptr)
-				backupData.mTypeInfo.data = ms.encode(mMissingTypeObjectInfo.get(), backupData.mTypeInfo.size);
-			else
-				backupData.mTypeInfo.data = nullptr;
-
-			backupData.mObjectData.size = 0;
+			backupData.size = 0;
 
 			if (mMissingTypeObjectData != nullptr)
-				backupData.mObjectData.data = ms.encode(mMissingTypeObjectData.get(), backupData.mObjectData.size);
+				backupData.data = ms.encode(mMissingTypeObjectData.get(), backupData.size);
 			else
-				backupData.mObjectData.data = nullptr;
+				backupData.data = nullptr;
 		}
 
 		if (clearExisting)
@@ -121,32 +103,22 @@ namespace BansheeEngine
 	{
 		initialize(instance);
 
-		if (instance != nullptr && data.mTypeInfo.data != nullptr && data.mObjectData.data != nullptr)
+		if (instance != nullptr && data.data != nullptr)
 		{
 			MemorySerializer ms;
-			ManagedSerializableObjectInfoPtr objectInfo = std::static_pointer_cast<ManagedSerializableObjectInfo>(ms.decode(data.mTypeInfo.data, data.mTypeInfo.size));
 
 			GameObjectManager::instance().startDeserialization();
-			ManagedSerializableObjectDataPtr objectData = std::static_pointer_cast<ManagedSerializableObjectData>(ms.decode(data.mObjectData.data, data.mObjectData.size));
+			ManagedSerializableObjectPtr serializableObject = std::static_pointer_cast<ManagedSerializableObject>(ms.decode(data.data, data.size));
 			GameObjectManager::instance().endDeserialization();
 
 			if (!missingType)
-			{
-				ManagedSerializableObjectPtr serializableObject = ManagedSerializableObject::createFromExisting(instance);
-				serializableObject->setObjectData(objectData, objectInfo);
-			}
+				serializableObject->deserialize();
 			else
-			{
-				mMissingTypeObjectInfo = objectInfo;
-				mMissingTypeObjectData = objectData;
-			}
+				mMissingTypeObjectData = serializableObject;
 		}
 
 		if (!missingType)
-		{
-			mMissingTypeObjectInfo = nullptr;
 			mMissingTypeObjectData = nullptr;
-		}
 
 		mMissingType = missingType;
 		mRequiresReset = true;

+ 7 - 22
SBansheeEngine/Source/BsManagedResource.cpp

@@ -5,10 +5,7 @@
 #include "BsMonoClass.h"
 #include "BsResources.h"
 #include "BsManagedResourceManager.h"
-#include "BsManagedSerializableField.h"
 #include "BsManagedSerializableObject.h"
-#include "BsManagedSerializableObjectInfo.h"
-#include "BsManagedSerializableObjectData.h"
 #include "BsMemorySerializer.h"
 #include "BsScriptResourceManager.h"
 #include "BsMonoUtil.h"
@@ -45,24 +42,15 @@ namespace BansheeEngine
 		ResourceBackupData backupData;
 		if (serializableObject != nullptr)
 		{
-			ManagedSerializableObjectInfoPtr objectInfo = serializableObject->getObjectInfo();
-			ManagedSerializableObjectDataPtr objectData = serializableObject->getObjectData();
-
 			MemorySerializer ms;
 
-			backupData.mTypeInfo.size = 0;
-			backupData.mTypeInfo.data = ms.encode(objectInfo.get(), backupData.mTypeInfo.size);
-
-			backupData.mObjectData.size = 0;
-			backupData.mObjectData.data = ms.encode(objectData.get(), backupData.mObjectData.size);
+			backupData.size = 0;
+			backupData.data = ms.encode(serializableObject.get(), backupData.size);
 		}
 		else
 		{
-			backupData.mTypeInfo.size = 0;
-			backupData.mTypeInfo.data = nullptr;
-
-			backupData.mObjectData.size = 0;
-			backupData.mObjectData.data = nullptr;
+			backupData.size = 0;
+			backupData.data = nullptr;
 		}
 
 		if (clearExisting)
@@ -86,14 +74,11 @@ namespace BansheeEngine
 		{
 			mManagedHandle = mono_gchandle_new(mManagedInstance, false);
 
-			if (data.mTypeInfo.data != nullptr && data.mObjectData.data != nullptr)
+			if (data.data != nullptr)
 			{
 				MemorySerializer ms;
-				ManagedSerializableObjectInfoPtr objectInfo = std::static_pointer_cast<ManagedSerializableObjectInfo>(ms.decode(data.mTypeInfo.data, data.mTypeInfo.size));
-				ManagedSerializableObjectDataPtr objectData = std::static_pointer_cast<ManagedSerializableObjectData>(ms.decode(data.mObjectData.data, data.mObjectData.size));
-
-				ManagedSerializableObjectPtr serializableObject = ManagedSerializableObject::createFromExisting(instance);
-				serializableObject->setObjectData(objectData, objectInfo);
+				ManagedSerializableObjectPtr serializableObject = std::static_pointer_cast<ManagedSerializableObject>(ms.decode(data.data, data.size));
+				serializableObject->deserialize();
 			}
 		}
 		else

+ 101 - 47
SBansheeEngine/Source/BsManagedSerializableArray.cpp

@@ -71,57 +71,103 @@ namespace BansheeEngine
 		return createInstance->invoke(nullptr, params);
 	}
 
-	void ManagedSerializableArray::deserializeManagedInstance(const Vector<ManagedSerializableFieldDataPtr>& entries)
+	void ManagedSerializableArray::setFieldData(UINT32 arrayIdx, const ManagedSerializableFieldDataPtr& val)
 	{
-		mManagedInstance = createManagedInstance(mArrayTypeInfo, mNumElements);
-
-		if (mManagedInstance == nullptr)
-			return;
-
-		initMonoObjects();
-
-		UINT32 idx = 0;
-		for (auto& arrayEntry : entries)
+		if (mManagedInstance != nullptr)
 		{
-			setFieldData(idx, arrayEntry);
-			idx++;
+			if (mono_class_is_valuetype(mElementMonoClass))
+				setValueInternal(arrayIdx, val->getValue(mArrayTypeInfo->mElementType));
+			else
+			{
+				MonoObject* ptrToObj = (MonoObject*)val->getValue(mArrayTypeInfo->mElementType);
+				setValueInternal(arrayIdx, &ptrToObj);
+			}
+		}
+		else
+		{
+			mCachedEntries[arrayIdx] = val;
 		}
 	}
 
-	void ManagedSerializableArray::setFieldData(UINT32 arrayIdx, const ManagedSerializableFieldDataPtr& val)
+	ManagedSerializableFieldDataPtr ManagedSerializableArray::getFieldData(UINT32 arrayIdx)
 	{
-		if(mono_class_is_valuetype(mElementMonoClass))
-			setValue(arrayIdx, val->getValue(mArrayTypeInfo->mElementType));
-		else
+		if (mManagedInstance != nullptr)
 		{
-			MonoObject* ptrToObj = (MonoObject*)val->getValue(mArrayTypeInfo->mElementType);
-			setValue(arrayIdx, &ptrToObj);
+			MonoArray* array = (MonoArray*)mManagedInstance;
+
+			UINT32 numElems = (UINT32)mono_array_length(array);
+			assert(arrayIdx < numElems);
+
+			void* arrayValue = mono_array_addr_with_size(array, mElemSize, arrayIdx);
+
+			if (mono_class_is_valuetype(mElementMonoClass))
+			{
+				MonoObject* boxedObj = nullptr;
+
+				if (arrayValue != nullptr)
+					boxedObj = mono_value_box(MonoManager::instance().getDomain(), mElementMonoClass, arrayValue);
+
+				return ManagedSerializableFieldData::create(mArrayTypeInfo->mElementType, boxedObj);
+			}
+			else
+				return ManagedSerializableFieldData::create(mArrayTypeInfo->mElementType, *(MonoObject**)arrayValue);
 		}
+		else
+			return mCachedEntries[arrayIdx];
 	}
 
-	ManagedSerializableFieldDataPtr ManagedSerializableArray::getFieldData(UINT32 arrayIdx)
+	void ManagedSerializableArray::serialize()
 	{
-		MonoArray* array = (MonoArray*)mManagedInstance;
+		if (mManagedInstance == nullptr)
+			return;
 
-		UINT32 numElems = (UINT32)mono_array_length(array);
-		assert(arrayIdx < numElems);
+		mNumElements.resize(mArrayTypeInfo->mRank);
+		for (UINT32 i = 0; i < mArrayTypeInfo->mRank; i++)
+			mNumElements[i] = getLengthInternal(i);
+
+		UINT32 numElements = getTotalLength();
+		mCachedEntries = Vector<ManagedSerializableFieldDataPtr>(numElements);
+
+		for (UINT32 i = 0; i < numElements; i++)
+			mCachedEntries[i] = getFieldData(i);
+
+		// Serialize children
+		for (auto& fieldEntry : mCachedEntries)
+			fieldEntry->serialize();
 
-		void* arrayValue = mono_array_addr_with_size(array, mElemSize, arrayIdx);
+		mManagedInstance = nullptr;
+	}
+
+	void ManagedSerializableArray::deserialize()
+	{
+		mManagedInstance = createManagedInstance(mArrayTypeInfo, mNumElements);
 
-		if(mono_class_is_valuetype(mElementMonoClass))
+		if (mManagedInstance == nullptr)
 		{
-			MonoObject* boxedObj = nullptr;
+			mCachedEntries.clear();
+			return;
+		}
+
+		::MonoClass* monoClass = mono_object_get_class(mManagedInstance);
+		mElemSize = mono_array_element_size(monoClass);
 
-			if (arrayValue != nullptr)
-				boxedObj = mono_value_box(MonoManager::instance().getDomain(), mElementMonoClass, arrayValue);
+		initMonoObjects();
+
+		// Deserialize children
+		for (auto& fieldEntry : mCachedEntries)
+			fieldEntry->deserialize();
 
-			return ManagedSerializableFieldData::create(mArrayTypeInfo->mElementType, boxedObj);
+		UINT32 idx = 0;
+		for (auto& arrayEntry : mCachedEntries)
+		{
+			setFieldData(idx, arrayEntry);
+			idx++;
 		}
-		else
-			return ManagedSerializableFieldData::create(mArrayTypeInfo->mElementType, *(MonoObject**)arrayValue);
+
+		mCachedEntries.clear();
 	}
 	
-	void ManagedSerializableArray::setValue(UINT32 arrayIdx, void* val)
+	void ManagedSerializableArray::setValueInternal(UINT32 arrayIdx, void* val)
 	{
 		MonoArray* array = (MonoArray*)mManagedInstance;
 
@@ -165,29 +211,37 @@ namespace BansheeEngine
 
 	void ManagedSerializableArray::resize(const Vector<UINT32>& newSizes)
 	{
-		assert(mArrayTypeInfo->mRank == (UINT32)newSizes.size());
+		if (mManagedInstance != nullptr)
+		{
+			assert(mArrayTypeInfo->mRank == (UINT32)newSizes.size());
 
-		UINT32 srcCount = 1;
-		for (auto& numElems : mNumElements)
-			srcCount *= numElems;
+			UINT32 srcCount = 1;
+			for (auto& numElems : mNumElements)
+				srcCount *= numElems;
 
-		UINT32 dstCount = 1;
-		for (auto& numElems : newSizes)
-			dstCount *= numElems;
+			UINT32 dstCount = 1;
+			for (auto& numElems : newSizes)
+				dstCount *= numElems;
 
-		UINT32 copyCount = std::min(srcCount, dstCount);
+			UINT32 copyCount = std::min(srcCount, dstCount);
 
-		MonoObject* newArray = createManagedInstance(mArrayTypeInfo, newSizes);
+			MonoObject* newArray = createManagedInstance(mArrayTypeInfo, newSizes);
 
-		void* params[3];
-		params[0] = getManagedInstance();;
-		params[1] = newArray;
-		params[2] = &copyCount;
+			void* params[3];
+			params[0] = getManagedInstance();;
+			params[1] = newArray;
+			params[2] = &copyCount;
 
-		mCopyMethod->invoke(nullptr, params);
+			mCopyMethod->invoke(nullptr, params);
 
-		mManagedInstance = newArray;
-		mNumElements = newSizes;
+			mManagedInstance = newArray;
+			mNumElements = newSizes;
+		}
+		else
+		{
+			mNumElements = newSizes;
+			mCachedEntries.resize(getTotalLength());
+		}
 	}
 
 	UINT32 ManagedSerializableArray::getLengthInternal(UINT32 dimension) const

+ 154 - 49
SBansheeEngine/Source/BsManagedSerializableDictionary.cpp

@@ -10,35 +10,91 @@
 
 namespace BansheeEngine
 {
+	ManagedSerializableDictionaryKeyValue::ManagedSerializableDictionaryKeyValue(const ManagedSerializableFieldDataPtr& key,
+		const ManagedSerializableFieldDataPtr& value)
+		:key(key), value(value)
+	{
+		
+	}
+
+	RTTITypeBase* ManagedSerializableDictionaryKeyValue::getRTTIStatic()
+	{
+		return ManagedSerializableDictionaryKeyValueRTTI::instance();
+	}
+
+	RTTITypeBase* ManagedSerializableDictionaryKeyValue::getRTTI() const
+	{
+		return ManagedSerializableDictionaryKeyValue::getRTTIStatic();
+	}
+
+	inline size_t ManagedSerializableDictionary::Hash::operator()(const ManagedSerializableFieldDataPtr& x) const
+	{
+		return x->getHash();
+	}
+
+	inline bool ManagedSerializableDictionary::Equals::operator()(const ManagedSerializableFieldDataPtr& a, const ManagedSerializableFieldDataPtr& b) const
+	{
+		return a->equals(b);
+	}
+
 	ManagedSerializableDictionary::Enumerator::Enumerator(MonoObject* instance, const ManagedSerializableDictionary* parent)
-		:mInstance(instance), mParent(parent), mCurrent(nullptr)
+		:mInstance(instance), mParent(parent), mCurrent(nullptr), mIteratorInitialized(false)
 	{ }
 
 	ManagedSerializableFieldDataPtr ManagedSerializableDictionary::Enumerator::getKey() const
 	{
-		MonoObject* obj = mParent->mKeyProp->get(mCurrent);
+		if (mInstance != nullptr)
+		{
+			MonoObject* obj = mParent->mKeyProp->get(mCurrent);
 
-		return ManagedSerializableFieldData::create(mParent->mDictionaryTypeInfo->mKeyType, obj);
+			return ManagedSerializableFieldData::create(mParent->mDictionaryTypeInfo->mKeyType, obj);
+		}
+		else
+		{
+			return mCachedIter->first;
+		}
 	}
 
 	ManagedSerializableFieldDataPtr ManagedSerializableDictionary::Enumerator::getValue() const
 	{
-		MonoObject* obj = mParent->mValueProp->get(mCurrent);
+		if (mInstance != nullptr)
+		{
+			MonoObject* obj = mParent->mValueProp->get(mCurrent);
 
-		return ManagedSerializableFieldData::create(mParent->mDictionaryTypeInfo->mValueType, obj);
+			return ManagedSerializableFieldData::create(mParent->mDictionaryTypeInfo->mValueType, obj);
+		}
+		else
+		{
+			return mCachedIter->second;
+		}
 	}
 
 	bool ManagedSerializableDictionary::Enumerator::moveNext()
 	{
-		MonoObject* returnVal = mParent->mEnumMoveNext->invoke(mInstance, nullptr);
-		bool isValid = *(bool*)mono_object_unbox(returnVal);
+		if (mInstance != nullptr)
+		{
+			MonoObject* returnVal = mParent->mEnumMoveNext->invoke(mInstance, nullptr);
+			bool isValid = *(bool*)mono_object_unbox(returnVal);
 
-		if(isValid)
-			mCurrent = (MonoObject*)mono_object_unbox(mParent->mEnumCurrentProp->get(mInstance));
-		else
-			mCurrent = nullptr;
+			if (isValid)
+				mCurrent = (MonoObject*)mono_object_unbox(mParent->mEnumCurrentProp->get(mInstance));
+			else
+				mCurrent = nullptr;
 
-		return isValid;
+			return isValid;
+		}
+		else
+		{
+			if (!mIteratorInitialized)
+			{
+				mCachedIter = mParent->mCachedEntries.begin();
+				mIteratorInitialized = true;
+			}
+			else
+				++mCachedIter;
+
+			return mCachedIter != mParent->mCachedEntries.end();
+		}
 	}
 
 	ManagedSerializableDictionary::ManagedSerializableDictionary(const ConstructPrivately& dummy)
@@ -97,33 +153,45 @@ namespace BansheeEngine
 		return bs_shared_ptr<ManagedSerializableDictionary>(ConstructPrivately());
 	}
 
-	void ManagedSerializableDictionary::serializeManagedInstance(Vector<ManagedSerializableFieldDataPtr>& keyEntries,
-		Vector<ManagedSerializableFieldDataPtr>& valueEntries)
+	void ManagedSerializableDictionary::serialize()
 	{
+		if (mManagedInstance == nullptr)
+			return;
+
 		MonoClass* dictionaryClass = MonoManager::instance().findClass(mono_object_get_class(mManagedInstance));
-		if(dictionaryClass == nullptr)
+		if (dictionaryClass == nullptr)
 			return;
 
 		initMonoObjects(dictionaryClass);
-
-		keyEntries.clear();
-		valueEntries.clear();
+		mCachedEntries.clear();
 
 		Enumerator enumerator = getEnumerator();
 
-		while(enumerator.moveNext())
+		while (enumerator.moveNext())
 		{
-			keyEntries.push_back(enumerator.getKey());
-			valueEntries.push_back(enumerator.getValue());
+			ManagedSerializableFieldDataPtr key = enumerator.getKey();
+			mCachedEntries.insert(std::make_pair(key, enumerator.getValue()));
 		}
+
+		// Serialize children
+		for (auto& fieldEntry : mCachedEntries)
+		{
+			fieldEntry.first->serialize();
+			fieldEntry.second->serialize();
+		}
+
+		mManagedInstance = nullptr;
 	}
 
-	void ManagedSerializableDictionary::deserializeManagedInstance(const Vector<ManagedSerializableFieldDataPtr>& keyEntries,
-		const Vector<ManagedSerializableFieldDataPtr>& valueEntries)
+	void ManagedSerializableDictionary::deserialize()
 	{
 		mManagedInstance = createManagedInstance(mDictionaryTypeInfo);
+
 		if (mManagedInstance == nullptr)
+		{
+			mCachedEntries.clear();
 			return;
+		}
 
 		::MonoClass* dictionaryMonoClass = mDictionaryTypeInfo->getMonoClass();
 		MonoClass* dictionaryClass = MonoManager::instance().findClass(dictionaryMonoClass);
@@ -132,59 +200,96 @@ namespace BansheeEngine
 
 		initMonoObjects(dictionaryClass);
 
-		assert(keyEntries.size() == valueEntries.size());
+		// Deserialize children
+		for (auto& fieldEntry : mCachedEntries)
+		{
+			fieldEntry.first->deserialize();
+			fieldEntry.second->deserialize();
+		}
 
-		for (UINT32 i = 0; i < (UINT32)keyEntries.size(); i++)
+		UINT32 idx = 0;
+		for (auto& entry : mCachedEntries)
 		{
-			setFieldData(keyEntries[i], valueEntries[i]);
+			setFieldData(entry.first, entry.second);
+			idx++;
 		}
+
+		mCachedEntries.clear();
 	}
 
 	ManagedSerializableFieldDataPtr ManagedSerializableDictionary::getFieldData(const ManagedSerializableFieldDataPtr& key)
 	{
-		MonoObject* value = nullptr;
+		if (mManagedInstance != nullptr)
+		{
+			MonoObject* value = nullptr;
+
+			void* params[2];
+			params[0] = key->getValue(mDictionaryTypeInfo->mKeyType);
+			params[1] = &value;
 
-		void* params[2];
-		params[0] = key->getValue(mDictionaryTypeInfo->mKeyType);
-		params[1] = &value;
+			mTryGetValueMethod->invoke(mManagedInstance, params);
 
-		mTryGetValueMethod->invoke(mManagedInstance, params);
+			MonoObject* boxedValue = value;
+			::MonoClass* valueTypeClass = mDictionaryTypeInfo->mValueType->getMonoClass();
+			if (mono_class_is_valuetype(valueTypeClass))
+			{
+				if (value != nullptr)
+					boxedValue = mono_value_box(MonoManager::instance().getDomain(), valueTypeClass, &value);
+			}
 
-		MonoObject* boxedValue = value;
-		::MonoClass* valueTypeClass = mDictionaryTypeInfo->mValueType->getMonoClass();
-		if (mono_class_is_valuetype(valueTypeClass))
+			return ManagedSerializableFieldData::create(mDictionaryTypeInfo->mValueType, boxedValue);
+		}
+		else
 		{
-			if (value != nullptr)
-				boxedValue = mono_value_box(MonoManager::instance().getDomain(), valueTypeClass, &value);
+			return mCachedEntries[key];
 		}
-
-		return ManagedSerializableFieldData::create(mDictionaryTypeInfo->mValueType, boxedValue);
 	}
 
 	void ManagedSerializableDictionary::setFieldData(const ManagedSerializableFieldDataPtr& key, const ManagedSerializableFieldDataPtr& val)
 	{
-		void* params[2];
-		params[0] = key->getValue(mDictionaryTypeInfo->mKeyType);
-		params[1] = val->getValue(mDictionaryTypeInfo->mValueType);
+		if (mManagedInstance != nullptr)
+		{
+			void* params[2];
+			params[0] = key->getValue(mDictionaryTypeInfo->mKeyType);
+			params[1] = val->getValue(mDictionaryTypeInfo->mValueType);
 
-		mAddMethod->invoke(mManagedInstance, params);
+			mAddMethod->invoke(mManagedInstance, params);
+		}
+		else
+		{
+			mCachedEntries[key] = val;
+		}
 	}
 
 	void ManagedSerializableDictionary::removeFieldData(const ManagedSerializableFieldDataPtr& key)
 	{
-		void* params[1];
-		params[0] = key->getValue(mDictionaryTypeInfo->mKeyType);
+		if (mManagedInstance != nullptr)
+		{
+			void* params[1];
+			params[0] = key->getValue(mDictionaryTypeInfo->mKeyType);
 
-		mRemoveMethod->invoke(mManagedInstance, params);
+			mRemoveMethod->invoke(mManagedInstance, params);
+		}
+		else
+		{
+			auto findIter = mCachedEntries.find(key);
+			if (findIter != mCachedEntries.end())
+				mCachedEntries.erase(findIter);
+		}
 	}
 
 	bool ManagedSerializableDictionary::contains(const ManagedSerializableFieldDataPtr& key) const
 	{
-		void* params[1];
-		params[0] = key->getValue(mDictionaryTypeInfo->mKeyType);
+		if (mManagedInstance != nullptr)
+		{
+			void* params[1];
+			params[0] = key->getValue(mDictionaryTypeInfo->mKeyType);
 
-		MonoObject* returnVal = mContainsKeyMethod->invoke(mManagedInstance, params);
-		return *(bool*)mono_object_unbox(returnVal);
+			MonoObject* returnVal = mContainsKeyMethod->invoke(mManagedInstance, params);
+			return *(bool*)mono_object_unbox(returnVal);
+		}
+		else
+			return mCachedEntries.find(key) != mCachedEntries.end();
 	}
 
 	ManagedSerializableDictionary::Enumerator ManagedSerializableDictionary::getEnumerator() const

+ 190 - 39
SBansheeEngine/Source/BsManagedSerializableField.cpp

@@ -25,39 +25,28 @@
 namespace BansheeEngine
 {
 	template<class T>
-	bool compareObjectFieldData(const T* a, const ManagedSerializableFieldDataPtr& b)
+	bool compareFieldData(const T* a, const ManagedSerializableFieldDataPtr& b)
 	{
 		if (rtti_is_of_type<T>(b))
 		{
 			auto castObj = std::static_pointer_cast<T>(b);
-
-			if (a->value != nullptr && castObj->value != nullptr)
-				return a->value->getManagedInstance() == castObj->value->getManagedInstance();
-			else
-				return a->value == nullptr && castObj->value == nullptr;
+			return a->value == castObj->value;
 		}
 
 		return false;
 	}
 
-	template<class T>
-	bool comparePrimitiveFieldData(const T* a, const ManagedSerializableFieldDataPtr& b)
-	{
-		if (rtti_is_of_type<T>(b))
-		{
-			auto castObj = std::static_pointer_cast<T>(b);
-			return a->value == castObj->value;
-		}
+	ManagedSerializableFieldKey::ManagedSerializableFieldKey()
+		:mTypeId(0), mFieldId(0)
+	{ }
 
-		return false;
-	}
+	ManagedSerializableFieldKey::ManagedSerializableFieldKey(UINT16 typeId, UINT16 fieldId)
+		:mTypeId(typeId), mFieldId(fieldId)
+	{ }
 
 	ManagedSerializableFieldKeyPtr ManagedSerializableFieldKey::create(UINT16 typeId, UINT16 fieldId)
 	{
-		ManagedSerializableFieldKeyPtr fieldKey = bs_shared_ptr<ManagedSerializableFieldKey>();
-		fieldKey->mTypeId = typeId;
-		fieldKey->mFieldId = fieldId;
-
+		ManagedSerializableFieldKeyPtr fieldKey = bs_shared_ptr<ManagedSerializableFieldKey>(typeId, fieldId);
 		return fieldKey;
 	}
 
@@ -972,97 +961,259 @@ namespace BansheeEngine
 
 	bool ManagedSerializableFieldDataBool::equals(const ManagedSerializableFieldDataPtr& other)
 	{
-		return comparePrimitiveFieldData(this, other);
+		return compareFieldData(this, other);
 	}
 
 	bool ManagedSerializableFieldDataChar::equals(const ManagedSerializableFieldDataPtr& other)
 	{
-		return comparePrimitiveFieldData(this, other);
+		return compareFieldData(this, other);
 	}
 
 	bool ManagedSerializableFieldDataI8::equals(const ManagedSerializableFieldDataPtr& other)
 	{
-		return comparePrimitiveFieldData(this, other);
+		return compareFieldData(this, other);
 	}
 
 	bool ManagedSerializableFieldDataU8::equals(const ManagedSerializableFieldDataPtr& other)
 	{
-		return comparePrimitiveFieldData(this, other);
+		return compareFieldData(this, other);
 	}
 
 	bool ManagedSerializableFieldDataI16::equals(const ManagedSerializableFieldDataPtr& other)
 	{
-		return comparePrimitiveFieldData(this, other);
+		return compareFieldData(this, other);
 	}
 
 	bool ManagedSerializableFieldDataU16::equals(const ManagedSerializableFieldDataPtr& other)
 	{
-		return comparePrimitiveFieldData(this, other);
+		return compareFieldData(this, other);
 	}
 
 	bool ManagedSerializableFieldDataI32::equals(const ManagedSerializableFieldDataPtr& other)
 	{
-		return comparePrimitiveFieldData(this, other);
+		return compareFieldData(this, other);
 	}
 
 	bool ManagedSerializableFieldDataU32::equals(const ManagedSerializableFieldDataPtr& other)
 	{
-		return comparePrimitiveFieldData(this, other);
+		return compareFieldData(this, other);
 	}
 
 	bool ManagedSerializableFieldDataI64::equals(const ManagedSerializableFieldDataPtr& other)
 	{
-		return comparePrimitiveFieldData(this, other);
+		return compareFieldData(this, other);
 	}
 
 	bool ManagedSerializableFieldDataU64::equals(const ManagedSerializableFieldDataPtr& other)
 	{
-		return comparePrimitiveFieldData(this, other);
+		return compareFieldData(this, other);
 	}
 
 	bool ManagedSerializableFieldDataFloat::equals(const ManagedSerializableFieldDataPtr& other)
 	{
-		return comparePrimitiveFieldData(this, other);
+		return compareFieldData(this, other);
 	}
 
 	bool ManagedSerializableFieldDataDouble::equals(const ManagedSerializableFieldDataPtr& other)
 	{
-		return comparePrimitiveFieldData(this, other);
+		return compareFieldData(this, other);
 	}
 
 	bool ManagedSerializableFieldDataString::equals(const ManagedSerializableFieldDataPtr& other)
 	{
-		return comparePrimitiveFieldData(this, other);
+		return compareFieldData(this, other);
 	}
 
 	bool ManagedSerializableFieldDataResourceRef::equals(const ManagedSerializableFieldDataPtr& other)
 	{
-		return comparePrimitiveFieldData(this, other);
+		return compareFieldData(this, other);
 	}
 
 	bool ManagedSerializableFieldDataGameObjectRef::equals(const ManagedSerializableFieldDataPtr& other)
 	{
-		return comparePrimitiveFieldData(this, other);
+		return compareFieldData(this, other);
 	}
 
 	bool ManagedSerializableFieldDataObject::equals(const ManagedSerializableFieldDataPtr& other)
 	{
-		return compareObjectFieldData(this, other);
+		return compareFieldData(this, other);
 	}
 
 	bool ManagedSerializableFieldDataArray::equals(const ManagedSerializableFieldDataPtr& other)
 	{
-		return compareObjectFieldData(this, other);
+		return compareFieldData(this, other);
 	}
 
 	bool ManagedSerializableFieldDataList::equals(const ManagedSerializableFieldDataPtr& other)
 	{
-		return compareObjectFieldData(this, other);
+		return compareFieldData(this, other);
 	}
 
 	bool ManagedSerializableFieldDataDictionary::equals(const ManagedSerializableFieldDataPtr& other)
 	{
-		return compareObjectFieldData(this, other);
+		return compareFieldData(this, other);
+	}
+
+	size_t ManagedSerializableFieldDataBool::getHash()
+	{
+		std::hash<bool> hasher;
+		return hasher(value);
+	}
+
+	size_t ManagedSerializableFieldDataChar::getHash()
+	{
+		std::hash<wchar_t> hasher;
+		return hasher(value);
+	}
+
+	size_t ManagedSerializableFieldDataI8::getHash()
+	{
+		std::hash<INT8> hasher;
+		return hasher(value);
+	}
+
+	size_t ManagedSerializableFieldDataU8::getHash()
+	{
+		std::hash<UINT8> hasher;
+		return hasher(value);
+	}
+
+	size_t ManagedSerializableFieldDataI16::getHash()
+	{
+		std::hash<INT16> hasher;
+		return hasher(value);
+	}
+
+	size_t ManagedSerializableFieldDataU16::getHash()
+	{
+		std::hash<UINT16> hasher;
+		return hasher(value);
+	}
+
+	size_t ManagedSerializableFieldDataI32::getHash()
+	{
+		std::hash<INT32> hasher;
+		return hasher(value);
+	}
+
+	size_t ManagedSerializableFieldDataU32::getHash()
+	{
+		std::hash<UINT32> hasher;
+		return hasher(value);
+	}
+
+	size_t ManagedSerializableFieldDataI64::getHash()
+	{
+		std::hash<INT64> hasher;
+		return hasher(value);
+	}
+
+	size_t ManagedSerializableFieldDataU64::getHash()
+	{
+		std::hash<UINT64> hasher;
+		return hasher(value);
+	}
+
+	size_t ManagedSerializableFieldDataFloat::getHash()
+	{
+		std::hash<float> hasher;
+		return hasher(value);
+	}
+
+	size_t ManagedSerializableFieldDataDouble::getHash()
+	{
+		std::hash<double> hasher;
+		return hasher(value);
+	}
+
+	size_t ManagedSerializableFieldDataString::getHash()
+	{
+		std::hash<WString> hasher;
+		return hasher(value);
+	}
+
+	size_t ManagedSerializableFieldDataResourceRef::getHash()
+	{
+		std::hash<String> hasher;
+		return hasher(value.getUUID());
+	}
+
+	size_t ManagedSerializableFieldDataGameObjectRef::getHash()
+	{
+		std::hash<UINT64> hasher;
+		return hasher(value.getInstanceId());
+	}
+
+	size_t ManagedSerializableFieldDataObject::getHash()
+	{
+		std::hash<std::shared_ptr<ManagedSerializableObject>> hasher;
+		return hasher(value);
+	}
+
+	size_t ManagedSerializableFieldDataArray::getHash()
+	{
+		std::hash<std::shared_ptr<ManagedSerializableArray>> hasher;
+		return hasher(value);
+	}
+
+	size_t ManagedSerializableFieldDataList::getHash()
+	{
+		std::hash<std::shared_ptr<ManagedSerializableList>> hasher;
+		return hasher(value);
+	}
+
+	size_t ManagedSerializableFieldDataDictionary::getHash()
+	{
+		std::hash<std::shared_ptr<ManagedSerializableDictionary>> hasher;
+		return hasher(value);
+	}
+
+	void ManagedSerializableFieldDataObject::serialize()
+	{
+		if (value != nullptr)
+			value->serialize();
+	}
+
+	void ManagedSerializableFieldDataObject::deserialize()
+	{
+		if (value != nullptr)
+			value->deserialize();
+	}
+
+	void ManagedSerializableFieldDataArray::serialize()
+	{
+		if (value != nullptr)
+			value->serialize();
+	}
+
+	void ManagedSerializableFieldDataArray::deserialize()
+	{
+		if (value != nullptr)
+			value->deserialize();
+	}
+
+	void ManagedSerializableFieldDataList::serialize()
+	{
+		if (value != nullptr)
+			value->serialize();
+	}
+
+	void ManagedSerializableFieldDataList::deserialize()
+	{
+		if (value != nullptr)
+			value->deserialize();
+	}
+
+	void ManagedSerializableFieldDataDictionary::serialize()
+	{
+		if (value != nullptr)
+			value->serialize();
+	}
+
+	void ManagedSerializableFieldDataDictionary::deserialize()
+	{
+		if (value != nullptr)
+			value->deserialize();
 	}
 
 	RTTITypeBase* ManagedSerializableFieldKey::getRTTIStatic()

+ 76 - 33
SBansheeEngine/Source/BsManagedSerializableList.cpp

@@ -71,29 +71,15 @@ namespace BansheeEngine
 		return bs_shared_ptr<ManagedSerializableList>(ConstructPrivately());
 	}
 
-	void ManagedSerializableList::deserializeManagedInstance(const Vector<ManagedSerializableFieldDataPtr>& entries)
-	{
-		mManagedInstance = createManagedInstance(mListTypeInfo, mNumElements);
-
-		if (mManagedInstance == nullptr)
-			return;
-
-		MonoClass* listClass = MonoManager::instance().findClass(mListTypeInfo->getMonoClass());
-		initMonoObjects(listClass);
-
-		for(auto& arrayEntry : entries)
-		{
-			addFieldData(arrayEntry);
-		}
-	}
-
 	void ManagedSerializableList::setFieldData(UINT32 arrayIdx, const ManagedSerializableFieldDataPtr& val)
 	{
-		mItemProp->setIndexed(mManagedInstance, arrayIdx, val->getValue(mListTypeInfo->mElementType));
+		if (mManagedInstance != nullptr)
+			mItemProp->setIndexed(mManagedInstance, arrayIdx, val->getValue(mListTypeInfo->mElementType));
+		else
+			mCachedEntries[arrayIdx] = val;
 	}
 
-
-	void ManagedSerializableList::addFieldData(const ManagedSerializableFieldDataPtr& val)
+	void ManagedSerializableList::addFieldDataInternal(const ManagedSerializableFieldDataPtr& val)
 	{
 		void* params[1];
 		params[0] = val->getValue(mListTypeInfo->mElementType);
@@ -102,33 +88,90 @@ namespace BansheeEngine
 
 	ManagedSerializableFieldDataPtr ManagedSerializableList::getFieldData(UINT32 arrayIdx)
 	{
-		MonoObject* obj = mItemProp->getIndexed(mManagedInstance, arrayIdx);
+		if (mManagedInstance != nullptr)
+		{
+			MonoObject* obj = mItemProp->getIndexed(mManagedInstance, arrayIdx);
 
-		return ManagedSerializableFieldData::create(mListTypeInfo->mElementType, obj);
+			return ManagedSerializableFieldData::create(mListTypeInfo->mElementType, obj);
+		}
+		else
+			return mCachedEntries[arrayIdx];
 	}
 
 	void ManagedSerializableList::resize(UINT32 newSize)
 	{
-		ScriptArray tempArray(mListTypeInfo->mElementType->getMonoClass(), newSize);
+		if (mManagedInstance != nullptr)
+		{
+			ScriptArray tempArray(mListTypeInfo->mElementType->getMonoClass(), newSize);
 
-		UINT32 minSize = std::min(mNumElements, newSize);
-		UINT32 dummy = 0;
+			UINT32 minSize = std::min(mNumElements, newSize);
+			UINT32 dummy = 0;
 
-		void* params[4];
-		params[0] = &dummy;;
-		params[1] = tempArray.getInternal();
-		params[2] = &dummy;
-		params[3] = &minSize;
+			void* params[4];
+			params[0] = &dummy;;
+			params[1] = tempArray.getInternal();
+			params[2] = &dummy;
+			params[3] = &minSize;
 
-		mCopyToMethod->invoke(getManagedInstance(), params);
-		mClearMethod->invoke(getManagedInstance(), nullptr);
+			mCopyToMethod->invoke(getManagedInstance(), params);
+			mClearMethod->invoke(getManagedInstance(), nullptr);
 
-		params[0] = tempArray.getInternal();
-		mAddRangeMethod->invoke(getManagedInstance(), params);
+			params[0] = tempArray.getInternal();
+			mAddRangeMethod->invoke(getManagedInstance(), params);
+		}
+		else
+		{
+			mCachedEntries.resize(newSize);
+		}
 
 		mNumElements = newSize;
 	}
 
+	void ManagedSerializableList::serialize()
+	{
+		if (mManagedInstance == nullptr)
+			return;
+
+		mNumElements = getLengthInternal();
+		mCachedEntries = Vector<ManagedSerializableFieldDataPtr>(mNumElements);
+
+		for (UINT32 i = 0; i < mNumElements; i++)
+			mCachedEntries[i] = getFieldData(i);
+
+		// Serialize children
+		for (auto& fieldEntry : mCachedEntries)
+			fieldEntry->serialize();
+
+		mManagedInstance = nullptr;
+	}
+
+	void ManagedSerializableList::deserialize()
+	{
+		mManagedInstance = createManagedInstance(mListTypeInfo, mNumElements);
+
+		if (mManagedInstance == nullptr)
+		{
+			mCachedEntries.clear();
+			return;
+		}
+
+		MonoClass* listClass = MonoManager::instance().findClass(mListTypeInfo->getMonoClass());
+		initMonoObjects(listClass);
+
+		// Deserialize children
+		for (auto& fieldEntry : mCachedEntries)
+			fieldEntry->deserialize();
+
+		UINT32 idx = 0;
+		for (auto& entry : mCachedEntries)
+		{
+			addFieldDataInternal(entry);
+			idx++;
+		}
+
+		mCachedEntries.clear();
+	}
+
 	UINT32 ManagedSerializableList::getLengthInternal() const
 	{
 		MonoObject* length = mCountProp->get(mManagedInstance);

+ 90 - 57
SBansheeEngine/Source/BsManagedSerializableObject.cpp

@@ -3,12 +3,26 @@
 #include "BsManagedSerializableObjectInfo.h"
 #include "BsManagedSerializableField.h"
 #include "BsScriptAssemblyManager.h"
-#include "BsManagedSerializableObjectData.h"
 #include "BsMonoField.h"
+#include "BsMonoClass.h"
 #include "BsMonoUtil.h"
 
 namespace BansheeEngine
 {
+	inline size_t ManagedSerializableObject::Hash::operator()(const ManagedSerializableFieldKey& x) const
+	{
+		size_t seed = 0;
+		hash_combine(seed, (UINT32)x.mFieldId);
+		hash_combine(seed, (UINT32)x.mTypeId);
+
+		return seed;
+	}
+
+	inline bool ManagedSerializableObject::Equals::operator()(const ManagedSerializableFieldKey& a, const ManagedSerializableFieldKey& b) const
+	{
+		return a.mFieldId == b.mFieldId && a.mTypeId == b.mTypeId;
+	}
+
 	ManagedSerializableObject::ManagedSerializableObject(const ConstructPrivately& dummy)
 		:mManagedInstance(nullptr)
 	{
@@ -67,97 +81,116 @@ namespace BansheeEngine
 		return bs_shared_ptr<ManagedSerializableObject>(ConstructPrivately());
 	}
 
-	void ManagedSerializableObject::deserializeManagedInstance(const Vector<ManagedSerializableFieldDataEntryPtr>& entries)
+	void ManagedSerializableObject::serialize()
 	{
-		mManagedInstance = createManagedInstance(mObjInfo->mTypeInfo);
-
 		if (mManagedInstance == nullptr)
 			return;
 
-		setFieldEntries(entries, mObjInfo);
-	}
+		mCachedData.clear();
 
-	void ManagedSerializableObject::setFieldEntries(const Vector<ManagedSerializableFieldDataEntryPtr>& entries, const ManagedSerializableObjectInfoPtr& originalEntriesType)
-	{
-		auto findFieldInfoFromKey = [&](UINT16 typeId, UINT16 fieldId, ManagedSerializableObjectInfoPtr objInfo,
-			ManagedSerializableFieldInfoPtr& outFieldInfo, ManagedSerializableObjectInfoPtr &outObjInfo) -> bool
+		ManagedSerializableObjectInfoPtr curType = mObjInfo;
+		while (curType != nullptr)
 		{
-			while (objInfo != nullptr)
+			for (auto& field : curType->mFields)
 			{
-				if (objInfo->mTypeId == typeId)
+				if (field.second->isSerializable())
 				{
-					auto iterFind = objInfo->mFields.find(fieldId);
-					if (iterFind != objInfo->mFields.end())
-					{
-						outFieldInfo = iterFind->second;
-						outObjInfo = objInfo;
+					ManagedSerializableFieldKey key(field.second->mParentTypeId, field.second->mFieldId);
+					mCachedData[key] = getFieldData(field.second);
+				}
+			}
 
-						return true;
-					}
+			curType = curType->mBaseClass;
+		}
 
-					return false;
-				}
+		// Serialize children
+		for (auto& fieldEntry : mCachedData)
+			fieldEntry.second->serialize();
 
-				objInfo = objInfo->mBaseClass;
-			}
+		mManagedInstance = nullptr;
+	}
 
-			return false;
-		};
+	void ManagedSerializableObject::deserialize()
+	{
+		mManagedInstance = createManagedInstance(mObjInfo->mTypeInfo);
+
+		if (mManagedInstance == nullptr)
+		{
+			mCachedData.clear();
+			return;
+		}
 
 		ManagedSerializableObjectInfoPtr currentObjInfo = nullptr;
 
 		// See if this type even still exists
-		if (!ScriptAssemblyManager::instance().getSerializableObjectInfo(originalEntriesType->mTypeInfo->mTypeNamespace, originalEntriesType->mTypeInfo->mTypeName, currentObjInfo))
+		if (!ScriptAssemblyManager::instance().getSerializableObjectInfo(mObjInfo->mTypeInfo->mTypeNamespace, mObjInfo->mTypeInfo->mTypeName, currentObjInfo))
+		{
+			mCachedData.clear();
 			return;
+		}
+
+		// Deserialize children
+		for (auto& fieldEntry : mCachedData)
+			fieldEntry.second->deserialize();
 
 		// Scan all fields and ensure the fields still exist
-		for (auto& fieldEntry : entries)
+		UINT32 i = 0;
+		ManagedSerializableObjectInfoPtr curType = mObjInfo;
+		while (curType != nullptr)
 		{
-			ManagedSerializableFieldInfoPtr storedFieldEntry;
-			ManagedSerializableObjectInfoPtr storedFieldObjEntry;
+			for (auto& field : curType->mFields)
+			{
+				if (field.second->isSerializable())
+				{
+					UINT32 fieldId = field.second->mFieldId;
+					UINT32 typeID = field.second->mParentTypeId;
 
-			if (!findFieldInfoFromKey(fieldEntry->mKey->mTypeId, fieldEntry->mKey->mFieldId, originalEntriesType, storedFieldEntry, storedFieldObjEntry))
-				continue;
+					ManagedSerializableFieldKey key(typeID, fieldId);
 
-			ManagedSerializableFieldInfoPtr matchingFieldInfo = currentObjInfo->findMatchingField(storedFieldEntry, storedFieldObjEntry->mTypeInfo);
-			if (matchingFieldInfo != nullptr)
-				setFieldData(matchingFieldInfo, fieldEntry->mValue);
-		}
-	}
+					ManagedSerializableFieldInfoPtr matchingFieldInfo = currentObjInfo->findMatchingField(field.second, curType->mTypeInfo);
+					if (matchingFieldInfo != nullptr)
+						setFieldData(matchingFieldInfo, mCachedData[key]);
 
-	void ManagedSerializableObject::setFieldData(const ManagedSerializableFieldInfoPtr& fieldInfo, const ManagedSerializableFieldDataPtr& val)
-	{
-		fieldInfo->mMonoField->setValue(mManagedInstance, val->getValue(fieldInfo->mTypeInfo));
-	}
+					i++;
+				}
+			}
 
-	ManagedSerializableFieldDataPtr ManagedSerializableObject::getFieldData(const ManagedSerializableFieldInfoPtr& fieldInfo) const
-	{
-		MonoObject* fieldValue = fieldInfo->mMonoField->getValueBoxed(mManagedInstance);
+			curType = curType->mBaseClass;
+		}
 
-		return ManagedSerializableFieldData::create(fieldInfo->mTypeInfo, fieldValue);
+		mObjInfo = currentObjInfo;
+		mCachedData.clear();
 	}
 
-	void ManagedSerializableObject::setObjectData(const ManagedSerializableObjectDataPtr& objectData, const ManagedSerializableObjectInfoPtr& originalEntriesType)
+	void ManagedSerializableObject::setFieldData(const ManagedSerializableFieldInfoPtr& fieldInfo, const ManagedSerializableFieldDataPtr& val)
 	{
-		setFieldEntries(objectData->mFieldData, originalEntriesType);
+		if (mManagedInstance != nullptr)
+			fieldInfo->mMonoField->setValue(mManagedInstance, val->getValue(fieldInfo->mTypeInfo));
+		else
+		{
+			ManagedSerializableFieldKey key(fieldInfo->mParentTypeId, fieldInfo->mFieldId);
+			mCachedData[key] = val;
+		}
 	}
 
-	ManagedSerializableObjectDataPtr ManagedSerializableObject::getObjectData() const
+	ManagedSerializableFieldDataPtr ManagedSerializableObject::getFieldData(const ManagedSerializableFieldInfoPtr& fieldInfo) const
 	{
-		ManagedSerializableObjectDataPtr objectData = bs_shared_ptr<ManagedSerializableObjectData>();
-		objectData->mFieldData = Vector<ManagedSerializableFieldDataEntryPtr>(mObjInfo->mCachedAllFields.size());
-
-		UINT32 i = 0;
-		for (auto& field : mObjInfo->mCachedAllFields)
+		if (mManagedInstance != nullptr)
 		{
-			ManagedSerializableFieldKeyPtr fieldKey = ManagedSerializableFieldKey::create(field.parentTypeId, field.info->mFieldId);
-			ManagedSerializableFieldDataPtr fieldData = getFieldData(field.info);
+			MonoObject* fieldValue = fieldInfo->mMonoField->getValueBoxed(mManagedInstance);
 
-			objectData->mFieldData[i] = ManagedSerializableFieldDataEntry::create(fieldKey, fieldData);
-			i++;
+			return ManagedSerializableFieldData::create(fieldInfo->mTypeInfo, fieldValue);
 		}
+		else
+		{
+			ManagedSerializableFieldKey key(fieldInfo->mParentTypeId, fieldInfo->mFieldId);
+			auto iterFind = mCachedData.find(key);
 
-		return objectData;
+			if (iterFind != mCachedData.end())
+				return iterFind->second;
+
+			return nullptr;
+		}
 	}
 
 	RTTITypeBase* ManagedSerializableObject::getRTTIStatic()

+ 0 - 15
SBansheeEngine/Source/BsManagedSerializableObjectData.cpp

@@ -1,15 +0,0 @@
-#include "BsManagedSerializableObjectData.h"
-#include "BsManagedSerializableObjectDataRTTI.h"
-
-namespace BansheeEngine
-{
-	RTTITypeBase* ManagedSerializableObjectData::getRTTIStatic()
-	{
-		return ManagedSerializableObjectDataRTTI::instance();
-	}
-
-	RTTITypeBase* ManagedSerializableObjectData::getRTTI() const
-	{
-		return ManagedSerializableObjectData::getRTTIStatic();
-	}
-}

+ 1 - 18
SBansheeEngine/Source/BsManagedSerializableObjectInfo.cpp

@@ -26,28 +26,11 @@ namespace BansheeEngine
 	}
 
 	ManagedSerializableObjectInfo::ManagedSerializableObjectInfo()
-		:mMonoClass(nullptr), mTypeId(0)
+		:mMonoClass(nullptr)
 	{
 
 	}
 
-	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();
-		}
-	}
-
 	ManagedSerializableFieldInfoPtr ManagedSerializableObjectInfo::findMatchingField(const ManagedSerializableFieldInfoPtr& fieldInfo,
 		const ManagedSerializableTypeInfoPtr& fieldTypeInfo) const
 	{

+ 4 - 11
SBansheeEngine/Source/BsScriptAssemblyManager.cpp

@@ -65,6 +65,7 @@ namespace BansheeEngine
 				std::shared_ptr<ManagedSerializableTypeInfoObject> typeInfo = bs_shared_ptr<ManagedSerializableTypeInfoObject>();
 				typeInfo->mTypeNamespace = curClass->getNamespace();
 				typeInfo->mTypeName = curClass->getTypeName();
+				typeInfo->mTypeId = mUniqueTypeId++;
 
 				MonoType* monoType = mono_class_get_type(curClass->_getInternalClass());
 				int monoPrimitiveType = mono_type_get_type(monoType);
@@ -76,13 +77,11 @@ namespace BansheeEngine
 
 				std::shared_ptr<ManagedSerializableObjectInfo> objInfo = bs_shared_ptr<ManagedSerializableObjectInfo>();
 
-				objInfo->mTypeId = mUniqueTypeId++;
-
 				objInfo->mTypeInfo = typeInfo;
 				objInfo->mMonoClass = curClass;
 
-				assemblyInfo->mTypeNameToId[objInfo->getFullTypeName()] = objInfo->mTypeId;
-				assemblyInfo->mObjectInfos[objInfo->mTypeId] = objInfo;
+				assemblyInfo->mTypeNameToId[objInfo->getFullTypeName()] = typeInfo->mTypeId;
+				assemblyInfo->mObjectInfos[typeInfo->mTypeId] = objInfo;
 			}
 		}
 
@@ -108,6 +107,7 @@ namespace BansheeEngine
 				fieldInfo->mName = field->getName();
 				fieldInfo->mMonoField = field;
 				fieldInfo->mTypeInfo = typeInfo;
+				fieldInfo->mParentTypeId = objInfo->mTypeInfo->mTypeId;
 				
 				MonoFieldVisibility visibility = field->getVisibility();
 				if (visibility == MonoFieldVisibility::Public)
@@ -147,13 +147,6 @@ namespace BansheeEngine
 				base = base->getBaseClass();
 			}
 		}
-
-		// Finish object info initialization
-		for (auto& curClassInfo : assemblyInfo->mObjectInfos)
-		{
-			std::shared_ptr<ManagedSerializableObjectInfo> objInfo = curClassInfo.second;
-			objInfo->initialize();
-		}
 	}
 
 	void ScriptAssemblyManager::refreshAssemblyInfo()

+ 21 - 5
TODO.txt

@@ -27,11 +27,6 @@ return them in checkForModifications?
 ---------------------------------------------------------------------
 Prefab diff
 
-IMMEDIATE:
- - Compile and test managed diff (ignoring game object handles for now)
- - Create a unit test for managed diff
- - Consider cleaning up ManagedSerializableDiff by moving the smaller classes to a different file
-
 Consider adding prefab support without diffs first (add dummy methods in place)
  - This might make it easier to understand how will it all fit together
 
@@ -45,10 +40,31 @@ GameObjectHandle compare in managed serializable diff won't work for prefabs (wi
  - Handle comparison compares instanceIDs which will be different between prefab and its instance
  - Best solution is probably to add a flag that tells the diff system how to deal with game object handles
    (i.e. compare using instance IDs or use the prefab link IDs)
+ - But since I know I will be using serialized data (and not actual objects) to compare with
+   I could do a pre-processing step and replace all the handle IDs before compare
 
 When I'm saving a prefab instance I need to generate the diff, therefore I need to load the prefab (ManagedSerializable stuff automatically created managed instance on load)
  - Will there be problems if I load the prefab objects? (e.g. a renderable, or some object might trigger some action on load)
   - It MIGHT be better to be able to load compare the serialized data, without actually instantiating any objects
+    - ManagedSerializableObjectRTTI (and probably others) return the serialized field data
+      but it references other ManagedSerializableObject fields that I cannot get deserialized data from
+ - THIS will also be a problem with native serialization!!!
+  - I'll probably have to do it using raw bytes
+  - Then when performing diff on native bytes if I detect a ManagedSerializableObject I should deserialize it 
+    (without creating a managed instance) and do the managed diff on it
+
+MIGHT need to adjust managed serializable object RTTI but I think it needs to retain ability to read its data directly from the 
+serialized object since I don't want to serialize the entire object hierarchy when all I need is a single field (like in some cases like searching for dependencies)
+
+Managed serialization is used in:
+ - Save/Load of managed components and resources 
+   - Created when serialization starts manually, and automatically when deserializing
+     - After deserilization ends a special method is called to actually construct the managed instances from the loaded data
+ - Used for assembly refresh, level save/load, undo/redo, clone, finding resource dependencies & diff
+ - Used by SerializableProperty for cloning and creating new instances of objects/arrays/etc
+
+Consider making array/list/dictionary method/field references static (right now each instance has its own instance
+ but they're identical)
 
 ----------------------------------------------------------------------
 Polish stage 1