Sfoglia il codice sorgente

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

Marko Pintera 10 anni fa
parent
commit
6e07e7bd02
32 ha cambiato i file con 989 aggiunte e 741 eliminazioni
  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
     * Simple drag and drop interface
 	* Traditional set of tools
 	* Traditional set of tools
     * Custom 2D and 3D tool support
     * 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
   * Play in editor
     * Compile in editor
     * Compile in editor
     * Immediately test changes
     * Immediately test changes
+	* Pause and frame-step
+	* Analyze and modify scene while playing
   * Fully extensible for game-specific needs
   * 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
   * 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
     * Dockable layout and floating windows
-    * Skinnable and localizable
+	* Custom skin & localization support
    
    
 * Core
 * Core
   * Design
   * Design
@@ -57,13 +71,14 @@ To compile DirectX render systems you will also need a separately installed Dire
     * Multi-threaded rendering
     * Multi-threaded rendering
     * Flexible material system
     * Flexible material system
       * Easy to control and set up
       * Easy to control and set up
+	  * BansheeFX language for material definitions
       * Shader parsing for HLSL9, HLSL11 and GLSL
       * Shader parsing for HLSL9, HLSL11 and GLSL
   * Asset pipeline
   * Asset pipeline
     * Easy to use
     * Easy to use
     * Asynchronous resource loading
     * Asynchronous resource loading
     * Extensible importer system
     * Extensible importer system
     * Available importer plugins for:
     * Available importer plugins for:
-      * FXB,OBJ, DAE meshes
+      * FXB, OBJ, DAE meshes
       * PNG, PSD, BMP, JPG, ... images
       * PNG, PSD, BMP, JPG, ... images
       * OTF, TTF fonts
       * OTF, TTF fonts
       * HLSL9, HLSL11, GLSL shaders
       * 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
     * Easy to use layout based system
     * Many common GUI controls
     * Many common GUI controls
     * Fully skinnable
     * Fully skinnable
-    * Automatch batching
+    * Automatic batching
     * Support for texture atlases
     * Support for texture atlases
     * Localization
     * Localization
   * Scripting
   * Scripting
     * C# via Mono
     * 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
     * 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
   * Other
     * CPU & GPU profiler
     * CPU & GPU profiler
     * Virtual input
     * Virtual input
@@ -99,6 +118,7 @@ To compile DirectX render systems you will also need a separately installed Dire
  * Networking system integration
  * Networking system integration
  * Animation
  * Animation
  * GUI animation
  * GUI animation
+ * Mac & Linux support
 
 
 ## Development state
 ## 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
 		// We store data of a missing component type in hope it will be restored later
 		bool mMissingType;
 		bool mMissingType;
-		ManagedSerializableObjectInfoPtr mMissingTypeObjectInfo;
-		ManagedSerializableObjectDataPtr mMissingTypeObjectData;
+		ManagedSerializableObjectPtr mMissingTypeObjectData;
 
 
 		OnInitializedThunkDef mOnInitializedThunk;
 		OnInitializedThunkDef mOnInitializedThunk;
 		UpdateThunkDef mUpdateThunk;
 		UpdateThunkDef mUpdateThunk;
@@ -83,13 +82,7 @@ namespace BansheeEngine
 
 
 	struct ComponentBackupData
 	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 "BsMonoManager.h"
 #include "BsManagedSerializableObject.h"
 #include "BsManagedSerializableObject.h"
 #include "BsGameObjectManager.h"
 #include "BsGameObjectManager.h"
-#include "BsScriptGameObjectManager.h"
 #include "BsScriptComponent.h"
 #include "BsScriptComponent.h"
 
 
 namespace BansheeEngine
 namespace BansheeEngine
@@ -55,22 +54,12 @@ namespace BansheeEngine
 			obj->mMissingType = val;
 			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;
 			return obj->mMissingTypeObjectData;
 		}
 		}
 
 
-		void setMissingTypeObjectData(ManagedComponent* obj, ManagedSerializableObjectDataPtr val)
+		void setMissingTypeObjectData(ManagedComponent* obj, ManagedSerializableObjectPtr val)
 		{
 		{
 			obj->mMissingTypeObjectData = val;
 			obj->mMissingTypeObjectData = val;
 		}
 		}
@@ -82,7 +71,6 @@ namespace BansheeEngine
 			addPlainField("mTypename", 1, &ManagedComponentRTTI::getTypename, &ManagedComponentRTTI::setTypename);
 			addPlainField("mTypename", 1, &ManagedComponentRTTI::getTypename, &ManagedComponentRTTI::setTypename);
 			addReflectablePtrField("mObjectData", 2, &ManagedComponentRTTI::getObjectData, &ManagedComponentRTTI::setObjectData);
 			addReflectablePtrField("mObjectData", 2, &ManagedComponentRTTI::getObjectData, &ManagedComponentRTTI::setObjectData);
 			addPlainField("mMissingType", 3, &ManagedComponentRTTI::getMissingType, &ManagedComponentRTTI::setMissingType);
 			addPlainField("mMissingType", 3, &ManagedComponentRTTI::getMissingType, &ManagedComponentRTTI::setMissingType);
-			addReflectablePtrField("mMissingTypeObjectInfo", 4, &ManagedComponentRTTI::getMissingTypeObjectInfo, &ManagedComponentRTTI::setMissingTypeObjectInfo);
 			addReflectablePtrField("mMissingTypeObjectData", 5, &ManagedComponentRTTI::getMissingTypeObjectData, &ManagedComponentRTTI::setMissingTypeObjectData);
 			addReflectablePtrField("mMissingTypeObjectData", 5, &ManagedComponentRTTI::getMissingTypeObjectData, &ManagedComponentRTTI::setMissingTypeObjectData);
 		}
 		}
 
 
@@ -103,6 +91,7 @@ namespace BansheeEngine
 		static void finalizeDeserialization(ManagedComponent* mc)
 		static void finalizeDeserialization(ManagedComponent* mc)
 		{
 		{
 			ManagedSerializableObjectPtr serializableObject = any_cast<ManagedSerializableObjectPtr>(mc->mRTTIData);
 			ManagedSerializableObjectPtr serializableObject = any_cast<ManagedSerializableObjectPtr>(mc->mRTTIData);
+			serializableObject->deserialize();
 			MonoObject* managedInstance = serializableObject->getManagedInstance();
 			MonoObject* managedInstance = serializableObject->getManagedInstance();
 
 
 			// Note: This callback must be triggered before any child ManagedSerializable* object's callbacks.
 			// 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 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);
 			ManagedResource* mr = static_cast<ManagedResource*>(obj);
 			ManagedSerializableObjectPtr serializableObject = any_cast<ManagedSerializableObjectPtr>(mr->mRTTIData);
 			ManagedSerializableObjectPtr serializableObject = any_cast<ManagedSerializableObjectPtr>(mr->mRTTIData);
+			serializableObject->deserialize();
 
 
 			ResourcePtr mrPtr = std::static_pointer_cast<Resource>(mr->getThisPtr());
 			ResourcePtr mrPtr = std::static_pointer_cast<Resource>(mr->getThisPtr());
 			HManagedResource handle = static_resource_cast<ManagedResource>(gResources()._createResourceHandle(mrPtr));
 			HManagedResource handle = static_resource_cast<ManagedResource>(gResources()._createResourceHandle(mrPtr));

+ 20 - 8
SBansheeEngine/Include/BsManagedSerializableArray.h

@@ -6,6 +6,21 @@
 
 
 namespace BansheeEngine
 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
 	class BS_SCR_BE_EXPORT ManagedSerializableArray : public IReflectable
 	{
 	{
 	private:
 	private:
@@ -16,6 +31,7 @@ namespace BansheeEngine
 		ManagedSerializableArray(const ConstructPrivately& dummy);
 		ManagedSerializableArray(const ConstructPrivately& dummy);
 
 
 		MonoObject* getManagedInstance() const { return mManagedInstance; }
 		MonoObject* getManagedInstance() const { return mManagedInstance; }
+		ManagedSerializableTypeInfoArrayPtr getTypeInfo() const { return mArrayTypeInfo; }
 
 
 		void resize(const Vector<UINT32>& newSizes);
 		void resize(const Vector<UINT32>& newSizes);
 		UINT32 getLength(UINT32 dimension) const { return mNumElements[dimension]; }
 		UINT32 getLength(UINT32 dimension) const { return mNumElements[dimension]; }
@@ -25,7 +41,8 @@ namespace BansheeEngine
 		void setFieldData(UINT32 arrayIdx, const ManagedSerializableFieldDataPtr& val);
 		void setFieldData(UINT32 arrayIdx, const ManagedSerializableFieldDataPtr& val);
 		ManagedSerializableFieldDataPtr getFieldData(UINT32 arrayIdx);
 		ManagedSerializableFieldDataPtr getFieldData(UINT32 arrayIdx);
 
 
-		ManagedSerializableTypeInfoArrayPtr getTypeInfo() const { return mArrayTypeInfo; }
+		void serialize();
+		void deserialize();
 
 
 		static ManagedSerializableArrayPtr createFromExisting(MonoObject* managedInstance, const ManagedSerializableTypeInfoArrayPtr& typeInfo);
 		static ManagedSerializableArrayPtr createFromExisting(MonoObject* managedInstance, const ManagedSerializableTypeInfoArrayPtr& typeInfo);
 		static ManagedSerializableArrayPtr createNew(const ManagedSerializableTypeInfoArrayPtr& typeInfo, const Vector<UINT32>& sizes);
 		static ManagedSerializableArrayPtr createNew(const ManagedSerializableTypeInfoArrayPtr& typeInfo, const Vector<UINT32>& sizes);
@@ -37,19 +54,14 @@ namespace BansheeEngine
 		MonoMethod* mCopyMethod;
 		MonoMethod* mCopyMethod;
 
 
 		ManagedSerializableTypeInfoArrayPtr mArrayTypeInfo;
 		ManagedSerializableTypeInfoArrayPtr mArrayTypeInfo;
-
+		Vector<ManagedSerializableFieldDataPtr> mCachedEntries;
 		Vector<UINT32> mNumElements;
 		Vector<UINT32> mNumElements;
 		UINT32 mElemSize;
 		UINT32 mElemSize;
 
 
 		void initMonoObjects();
 		void initMonoObjects();
 		UINT32 getLengthInternal(UINT32 dimension) const;
 		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;
 		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>
 	class BS_SCR_BE_EXPORT ManagedSerializableArrayRTTI : public RTTIType<ManagedSerializableArray, IReflectable, ManagedSerializableArrayRTTI>
 	{
 	{
 	private:
 	private:
-		struct DeserializationInfo
-		{
-			Vector<ManagedSerializableFieldDataPtr> fields;
-			bool isGameObjectDeserialization;
-		};
-
 		ManagedSerializableTypeInfoArrayPtr getTypeInfo(ManagedSerializableArray* obj)
 		ManagedSerializableTypeInfoArrayPtr getTypeInfo(ManagedSerializableArray* obj)
 		{
 		{
 			return obj->mArrayTypeInfo;
 			return obj->mArrayTypeInfo;
@@ -31,7 +25,7 @@ namespace BansheeEngine
 
 
 		UINT32& getElementSize(ManagedSerializableArray* obj)
 		UINT32& getElementSize(ManagedSerializableArray* obj)
 		{
 		{
-			return (UINT32)obj->mElemSize;
+			return (UINT32&)obj->mElemSize;
 		}
 		}
 
 
 		void setElementSize(ManagedSerializableArray* obj, UINT32& numElements)
 		void setElementSize(ManagedSerializableArray* obj, UINT32& numElements)
@@ -41,7 +35,7 @@ namespace BansheeEngine
 
 
 		UINT32& getNumElements(ManagedSerializableArray* obj, UINT32 arrayIdx)
 		UINT32& getNumElements(ManagedSerializableArray* obj, UINT32 arrayIdx)
 		{
 		{
-			return (UINT32)obj->mNumElements[arrayIdx];
+			return (UINT32&)obj->mNumElements[arrayIdx];
 		}
 		}
 
 
 		void setNumElements(ManagedSerializableArray* obj, UINT32 arrayIdx, UINT32& numElements)
 		void setNumElements(ManagedSerializableArray* obj, UINT32 arrayIdx, UINT32& numElements)
@@ -66,23 +60,17 @@ namespace BansheeEngine
 
 
 		void setArrayEntry(ManagedSerializableArray* obj, UINT32 arrayIdx, ManagedSerializableFieldDataPtr val)
 		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 getNumArrayEntries(ManagedSerializableArray* obj)
 		{
 		{
-			UINT32 totalNumElements = 1;
-			for (auto& numElems : obj->mNumElements)
-				totalNumElements *= numElems;
-
-			return totalNumElements;
+			return obj->getTotalLength();
 		}
 		}
 
 
 		void setNumArrayEntries(ManagedSerializableArray* obj, UINT32 numEntries)
 		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:
 	public:
@@ -96,32 +84,6 @@ namespace BansheeEngine
 				&ManagedSerializableArrayRTTI::setArrayEntry, &ManagedSerializableArrayRTTI::setNumArrayEntries);
 				&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()
 		virtual const String& getRTTIName()
 		{
 		{
 			static String name = "ScriptSerializableArray";
 			static String name = "ScriptSerializableArray";

+ 52 - 13
SBansheeEngine/Include/BsManagedSerializableDictionary.h

@@ -6,12 +6,57 @@
 
 
 namespace BansheeEngine
 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
 	class BS_SCR_BE_EXPORT ManagedSerializableDictionary : public IReflectable
 	{
 	{
 	private:
 	private:
 		struct ConstructPrivately {};
 		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:
 	public:
+		typedef UnorderedMap<ManagedSerializableFieldDataPtr, ManagedSerializableFieldDataPtr> CachedEntriesMap;
+
 		class Enumerator
 		class Enumerator
 		{
 		{
 		public:
 		public:
@@ -25,6 +70,9 @@ namespace BansheeEngine
 		private:
 		private:
 			MonoObject* mInstance;
 			MonoObject* mInstance;
 			MonoObject* mCurrent;
 			MonoObject* mCurrent;
+			CachedEntriesMap::const_iterator mCachedIter;
+			bool mIteratorInitialized;
+
 			const ManagedSerializableDictionary* mParent;
 			const ManagedSerializableDictionary* mParent;
 		};
 		};
 
 
@@ -33,7 +81,6 @@ namespace BansheeEngine
 		ManagedSerializableDictionary(const ConstructPrivately& dummy);
 		ManagedSerializableDictionary(const ConstructPrivately& dummy);
 
 
 		MonoObject* getManagedInstance() const { return mManagedInstance; }
 		MonoObject* getManagedInstance() const { return mManagedInstance; }
-
 		ManagedSerializableTypeInfoDictionaryPtr getTypeInfo() const { return mDictionaryTypeInfo; }
 		ManagedSerializableTypeInfoDictionaryPtr getTypeInfo() const { return mDictionaryTypeInfo; }
 
 
 		ManagedSerializableFieldDataPtr getFieldData(const ManagedSerializableFieldDataPtr& key);
 		ManagedSerializableFieldDataPtr getFieldData(const ManagedSerializableFieldDataPtr& key);
@@ -42,6 +89,9 @@ namespace BansheeEngine
 		bool contains(const ManagedSerializableFieldDataPtr& key) const;
 		bool contains(const ManagedSerializableFieldDataPtr& key) const;
 		Enumerator getEnumerator() const;
 		Enumerator getEnumerator() const;
 
 
+		void serialize();
+		void deserialize();
+
 		static ManagedSerializableDictionaryPtr createFromExisting(MonoObject* managedInstance, const ManagedSerializableTypeInfoDictionaryPtr& typeInfo);
 		static ManagedSerializableDictionaryPtr createFromExisting(MonoObject* managedInstance, const ManagedSerializableTypeInfoDictionaryPtr& typeInfo);
 		static ManagedSerializableDictionaryPtr createNew(const ManagedSerializableTypeInfoDictionaryPtr& typeInfo);
 		static ManagedSerializableDictionaryPtr createNew(const ManagedSerializableTypeInfoDictionaryPtr& typeInfo);
 		static MonoObject* createManagedInstance(const ManagedSerializableTypeInfoDictionaryPtr& typeInfo);
 		static MonoObject* createManagedInstance(const ManagedSerializableTypeInfoDictionaryPtr& typeInfo);
@@ -60,21 +110,10 @@ namespace BansheeEngine
 		MonoProperty* mValueProp;
 		MonoProperty* mValueProp;
 
 
 		ManagedSerializableTypeInfoDictionaryPtr mDictionaryTypeInfo;
 		ManagedSerializableTypeInfoDictionaryPtr mDictionaryTypeInfo;
+		CachedEntriesMap mCachedEntries;
 
 
 		void initMonoObjects(MonoClass* dictionaryClass);
 		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		                     		*/
 		/* 								RTTI		                     		*/
 		/************************************************************************/
 		/************************************************************************/

+ 64 - 74
SBansheeEngine/Include/BsManagedSerializableDictionaryRTTI.h

@@ -2,124 +2,114 @@
 
 
 #include "BsScriptEnginePrerequisites.h"
 #include "BsScriptEnginePrerequisites.h"
 #include "BsRTTIType.h"
 #include "BsRTTIType.h"
-#include "BsGameObjectManager.h"
 #include "BsManagedSerializableDictionary.h"
 #include "BsManagedSerializableDictionary.h"
-#include "BsScriptAssemblyManager.h"
-#include "BsMonoManager.h"
-#include "BsMonoClass.h"
 
 
 namespace BansheeEngine
 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:
 	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:
 	public:
 		ManagedSerializableDictionaryRTTI()
 		ManagedSerializableDictionaryRTTI()
 		{
 		{
 			addReflectablePtrField("mListTypeInfo", 0, &ManagedSerializableDictionaryRTTI::getTypeInfo, &ManagedSerializableDictionaryRTTI::setTypeInfo);
 			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)
 		virtual void onSerializationStarted(IReflectable* obj)
 		{
 		{
 			ManagedSerializableDictionary* serializableObject = static_cast<ManagedSerializableDictionary*>(obj);
 			ManagedSerializableDictionary* serializableObject = static_cast<ManagedSerializableDictionary*>(obj);
 
 
-			serializableObject->mRTTIData = bs_shared_ptr<SerializationData>();
-			SPtr<SerializationData> data = any_cast<SPtr<SerializationData>>(serializableObject->mRTTIData);
-
-			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);
 			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;
 			serializableObject->mRTTIData = nullptr;
 		}
 		}
 
 

+ 37 - 0
SBansheeEngine/Include/BsManagedSerializableField.h

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

+ 20 - 7
SBansheeEngine/Include/BsManagedSerializableList.h

@@ -6,6 +6,21 @@
 
 
 namespace BansheeEngine
 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
 	class BS_SCR_BE_EXPORT ManagedSerializableList : public IReflectable
 	{
 	{
 	private:
 	private:
@@ -16,14 +31,15 @@ namespace BansheeEngine
 		ManagedSerializableList(const ConstructPrivately& dummy);
 		ManagedSerializableList(const ConstructPrivately& dummy);
 
 
 		MonoObject* getManagedInstance() const { return mManagedInstance; }
 		MonoObject* getManagedInstance() const { return mManagedInstance; }
+		ManagedSerializableTypeInfoListPtr getTypeInfo() const { return mListTypeInfo; }
 
 
 		void resize(UINT32 newSize);
 		void resize(UINT32 newSize);
 		void setFieldData(UINT32 arrayIdx, const ManagedSerializableFieldDataPtr& val);
 		void setFieldData(UINT32 arrayIdx, const ManagedSerializableFieldDataPtr& val);
-		void addFieldData(const ManagedSerializableFieldDataPtr& val);
 		ManagedSerializableFieldDataPtr getFieldData(UINT32 arrayIdx);
 		ManagedSerializableFieldDataPtr getFieldData(UINT32 arrayIdx);
 		UINT32 getLength() const { return mNumElements; }
 		UINT32 getLength() const { return mNumElements; }
 
 
-		ManagedSerializableTypeInfoListPtr getTypeInfo() const { return mListTypeInfo; }
+		void serialize();
+		void deserialize();
 
 
 		static ManagedSerializableListPtr createFromExisting(MonoObject* managedInstance, const ManagedSerializableTypeInfoListPtr& typeInfo);
 		static ManagedSerializableListPtr createFromExisting(MonoObject* managedInstance, const ManagedSerializableTypeInfoListPtr& typeInfo);
 		static ManagedSerializableListPtr createNew(const ManagedSerializableTypeInfoListPtr& typeInfo, UINT32 size);
 		static ManagedSerializableListPtr createNew(const ManagedSerializableTypeInfoListPtr& typeInfo, UINT32 size);
@@ -40,15 +56,12 @@ namespace BansheeEngine
 		MonoProperty* mCountProp;
 		MonoProperty* mCountProp;
 
 
 		ManagedSerializableTypeInfoListPtr mListTypeInfo;
 		ManagedSerializableTypeInfoListPtr mListTypeInfo;
+		Vector<ManagedSerializableFieldDataPtr> mCachedEntries;
 		UINT32 mNumElements;
 		UINT32 mNumElements;
 
 
 		void initMonoObjects(MonoClass* listClass);
 		void initMonoObjects(MonoClass* listClass);
 		UINT32 getLengthInternal() const;
 		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		                     		*/
 		/* 								RTTI		                     		*/

+ 4 - 42
SBansheeEngine/Include/BsManagedSerializableListRTTI.h

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

+ 30 - 9
SBansheeEngine/Include/BsManagedSerializableObject.h

@@ -2,15 +2,41 @@
 
 
 #include "BsScriptEnginePrerequisites.h"
 #include "BsScriptEnginePrerequisites.h"
 #include "BsIReflectable.h"
 #include "BsIReflectable.h"
+#include "BsManagedSerializableField.h"
 #include <mono/jit/jit.h>
 #include <mono/jit/jit.h>
 
 
 namespace BansheeEngine
 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
 	class BS_SCR_BE_EXPORT ManagedSerializableObject : public IReflectable
 	{
 	{
 	private:
 	private:
 		struct ConstructPrivately {};
 		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:
 	public:
 		ManagedSerializableObject(const ConstructPrivately& dummy, ManagedSerializableObjectInfoPtr objInfo, MonoObject* managedInstance);
 		ManagedSerializableObject(const ConstructPrivately& dummy, ManagedSerializableObjectInfoPtr objInfo, MonoObject* managedInstance);
 		ManagedSerializableObject(const ConstructPrivately& dummy);
 		ManagedSerializableObject(const ConstructPrivately& dummy);
@@ -21,22 +47,17 @@ namespace BansheeEngine
 		void setFieldData(const ManagedSerializableFieldInfoPtr& fieldInfo, const ManagedSerializableFieldDataPtr& val);
 		void setFieldData(const ManagedSerializableFieldInfoPtr& fieldInfo, const ManagedSerializableFieldDataPtr& val);
 		ManagedSerializableFieldDataPtr getFieldData(const ManagedSerializableFieldInfoPtr& fieldInfo) const;
 		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 createFromExisting(MonoObject* managedInstance);
 		static ManagedSerializableObjectPtr createNew(const ManagedSerializableTypeInfoObjectPtr& type);
 		static ManagedSerializableObjectPtr createNew(const ManagedSerializableTypeInfoObjectPtr& type);
 		static MonoObject* createManagedInstance(const ManagedSerializableTypeInfoObjectPtr& type);
 		static MonoObject* createManagedInstance(const ManagedSerializableTypeInfoObjectPtr& type);
 	protected:
 	protected:
-		ManagedSerializableObjectInfoPtr mObjInfo;
 		MonoObject* mManagedInstance;
 		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		                     		*/
 		/* 								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 mTypeNamespace;
 		String mTypeName;
 		String mTypeName;
 		bool mValueType;
 		bool mValueType;
+		UINT32 mTypeId;
 
 
 		bool matches(const ManagedSerializableTypeInfoPtr& typeInfo) const;
 		bool matches(const ManagedSerializableTypeInfoPtr& typeInfo) const;
 		bool isTypeLoaded() const;
 		bool isTypeLoaded() const;
@@ -166,6 +167,7 @@ namespace BansheeEngine
 
 
 		String mName;
 		String mName;
 		UINT32 mFieldId;
 		UINT32 mFieldId;
+		UINT32 mParentTypeId;
 
 
 		ManagedSerializableTypeInfoPtr mTypeInfo;
 		ManagedSerializableTypeInfoPtr mTypeInfo;
 		ScriptFieldFlags mFlags;
 		ScriptFieldFlags mFlags;
@@ -186,26 +188,13 @@ namespace BansheeEngine
 	class BS_SCR_BE_EXPORT ManagedSerializableObjectInfo : public IReflectable
 	class BS_SCR_BE_EXPORT ManagedSerializableObjectInfo : public IReflectable
 	{
 	{
 	public:
 	public:
-		struct CachedField
-		{
-			CachedField(const SPtr<ManagedSerializableFieldInfo>& info, UINT32 typeId)
-				:info(info), parentTypeId(typeId)
-			{ }
-
-			SPtr<ManagedSerializableFieldInfo> info;
-			UINT32 parentTypeId;
-		};
-
 		ManagedSerializableObjectInfo();
 		ManagedSerializableObjectInfo();
-		void initialize();
 
 
 		String getFullTypeName() const { return mTypeInfo->mTypeNamespace + "." + mTypeInfo->mTypeName; }
 		String getFullTypeName() const { return mTypeInfo->mTypeNamespace + "." + mTypeInfo->mTypeName; }
 		ManagedSerializableFieldInfoPtr findMatchingField(const ManagedSerializableFieldInfoPtr& fieldInfo,
 		ManagedSerializableFieldInfoPtr findMatchingField(const ManagedSerializableFieldInfoPtr& fieldInfo,
 			const ManagedSerializableTypeInfoPtr& fieldTypeInfo) const;
 			const ManagedSerializableTypeInfoPtr& fieldTypeInfo) const;
 
 
 		ManagedSerializableTypeInfoObjectPtr mTypeInfo;
 		ManagedSerializableTypeInfoObjectPtr mTypeInfo;
-		UINT32 mTypeId;
-
 		MonoClass* mMonoClass;
 		MonoClass* mMonoClass;
 
 
 		UnorderedMap<String, UINT32> mFieldNameToId;
 		UnorderedMap<String, UINT32> mFieldNameToId;
@@ -214,8 +203,6 @@ namespace BansheeEngine
 		std::shared_ptr<ManagedSerializableObjectInfo> mBaseClass;
 		std::shared_ptr<ManagedSerializableObjectInfo> mBaseClass;
 		Vector<std::weak_ptr<ManagedSerializableObjectInfo>> mDerivedClasses;
 		Vector<std::weak_ptr<ManagedSerializableObjectInfo>> mDerivedClasses;
 
 
-		Vector<CachedField> mCachedAllFields;
-
 		/************************************************************************/
 		/************************************************************************/
 		/* 								RTTI		                     		*/
 		/* 								RTTI		                     		*/
 		/************************************************************************/
 		/************************************************************************/

+ 26 - 20
SBansheeEngine/Include/BsManagedSerializableObjectInfoRTTI.h

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

+ 32 - 39
SBansheeEngine/Include/BsManagedSerializableObjectRTTI.h

@@ -5,20 +5,12 @@
 #include "BsScriptAssemblyManager.h"
 #include "BsScriptAssemblyManager.h"
 #include "BsManagedSerializableObject.h"
 #include "BsManagedSerializableObject.h"
 #include "BsManagedSerializableField.h"
 #include "BsManagedSerializableField.h"
-#include "BsGameObjectManager.h"
-#include "BsMonoClass.h"
 
 
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
 	class BS_SCR_BE_EXPORT ManagedSerializableObjectRTTI : public RTTIType<ManagedSerializableObject, IReflectable, ManagedSerializableObjectRTTI>
 	class BS_SCR_BE_EXPORT ManagedSerializableObjectRTTI : public RTTIType<ManagedSerializableObject, IReflectable, ManagedSerializableObjectRTTI>
 	{
 	{
 	private:
 	private:
-		struct DeserializationInfo
-		{
-			Vector<ManagedSerializableFieldDataEntryPtr> fields;
-			bool isGameObjectDeserialization;
-		};
-
 		ManagedSerializableObjectInfoPtr getInfo(ManagedSerializableObject* obj)
 		ManagedSerializableObjectInfoPtr getInfo(ManagedSerializableObject* obj)
 		{
 		{
 			return obj->mObjInfo;
 			return obj->mObjInfo;
@@ -31,29 +23,33 @@ namespace BansheeEngine
 
 
 		ManagedSerializableFieldDataEntryPtr getFieldEntry(ManagedSerializableObject* obj, UINT32 arrayIdx)
 		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);
 			return ManagedSerializableFieldDataEntry::create(fieldKey, fieldData);
 		}
 		}
 
 
 		void setFieldsEntry(ManagedSerializableObject* obj, UINT32 arrayIdx, ManagedSerializableFieldDataEntryPtr val)
 		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)
 		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)
 		void setNumFieldEntries(ManagedSerializableObject* obj, UINT32 numEntries)
 		{
 		{
-			SPtr<DeserializationInfo> info = any_cast<SPtr<DeserializationInfo>>(obj->mRTTIData);
-			info->fields = Vector<ManagedSerializableFieldDataEntryPtr>(numEntries);
+			// Do nothing
 		}
 		}
 
 
 	public:
 	public:
@@ -64,47 +60,44 @@ namespace BansheeEngine
 				&ManagedSerializableObjectRTTI::setFieldsEntry, &ManagedSerializableObjectRTTI::setNumFieldEntries);
 				&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";
 			static String name = "ScriptSerializableObject";
 			return name;
 			return name;
 		}
 		}
 
 
-		virtual UINT32 getRTTIId()
+		virtual UINT32 getRTTIId() override
 		{
 		{
 			return TID_ScriptSerializableObject;
 			return TID_ScriptSerializableObject;
 		}
 		}
 
 
-		virtual std::shared_ptr<IReflectable> newRTTIObject()
+		virtual std::shared_ptr<IReflectable> newRTTIObject() override
 		{
 		{
 			return ManagedSerializableObject::createEmpty();
 			return ManagedSerializableObject::createEmpty();
 		}
 		}

+ 2 - 2
SBansheeEngine/Include/BsScriptEnginePrerequisites.h

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

+ 0 - 3
SBansheeEngine/SBansheeEngine.vcxproj

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

+ 0 - 9
SBansheeEngine/SBansheeEngine.vcxproj.filters

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

+ 12 - 40
SBansheeEngine/Source/BsManagedComponent.cpp

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

+ 7 - 22
SBansheeEngine/Source/BsManagedResource.cpp

@@ -5,10 +5,7 @@
 #include "BsMonoClass.h"
 #include "BsMonoClass.h"
 #include "BsResources.h"
 #include "BsResources.h"
 #include "BsManagedResourceManager.h"
 #include "BsManagedResourceManager.h"
-#include "BsManagedSerializableField.h"
 #include "BsManagedSerializableObject.h"
 #include "BsManagedSerializableObject.h"
-#include "BsManagedSerializableObjectInfo.h"
-#include "BsManagedSerializableObjectData.h"
 #include "BsMemorySerializer.h"
 #include "BsMemorySerializer.h"
 #include "BsScriptResourceManager.h"
 #include "BsScriptResourceManager.h"
 #include "BsMonoUtil.h"
 #include "BsMonoUtil.h"
@@ -45,24 +42,15 @@ namespace BansheeEngine
 		ResourceBackupData backupData;
 		ResourceBackupData backupData;
 		if (serializableObject != nullptr)
 		if (serializableObject != nullptr)
 		{
 		{
-			ManagedSerializableObjectInfoPtr objectInfo = serializableObject->getObjectInfo();
-			ManagedSerializableObjectDataPtr objectData = serializableObject->getObjectData();
-
 			MemorySerializer ms;
 			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
 		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)
 		if (clearExisting)
@@ -86,14 +74,11 @@ namespace BansheeEngine
 		{
 		{
 			mManagedHandle = mono_gchandle_new(mManagedInstance, false);
 			mManagedHandle = mono_gchandle_new(mManagedInstance, false);
 
 
-			if (data.mTypeInfo.data != nullptr && data.mObjectData.data != nullptr)
+			if (data.data != nullptr)
 			{
 			{
 				MemorySerializer ms;
 				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
 		else

+ 101 - 47
SBansheeEngine/Source/BsManagedSerializableArray.cpp

@@ -71,57 +71,103 @@ namespace BansheeEngine
 		return createInstance->invoke(nullptr, params);
 		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;
 		MonoArray* array = (MonoArray*)mManagedInstance;
 
 
@@ -165,29 +211,37 @@ namespace BansheeEngine
 
 
 	void ManagedSerializableArray::resize(const Vector<UINT32>& newSizes)
 	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
 	UINT32 ManagedSerializableArray::getLengthInternal(UINT32 dimension) const

+ 154 - 49
SBansheeEngine/Source/BsManagedSerializableDictionary.cpp

@@ -10,35 +10,91 @@
 
 
 namespace BansheeEngine
 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)
 	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
 	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
 	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()
 	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)
 	ManagedSerializableDictionary::ManagedSerializableDictionary(const ConstructPrivately& dummy)
@@ -97,33 +153,45 @@ namespace BansheeEngine
 		return bs_shared_ptr<ManagedSerializableDictionary>(ConstructPrivately());
 		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));
 		MonoClass* dictionaryClass = MonoManager::instance().findClass(mono_object_get_class(mManagedInstance));
-		if(dictionaryClass == nullptr)
+		if (dictionaryClass == nullptr)
 			return;
 			return;
 
 
 		initMonoObjects(dictionaryClass);
 		initMonoObjects(dictionaryClass);
-
-		keyEntries.clear();
-		valueEntries.clear();
+		mCachedEntries.clear();
 
 
 		Enumerator enumerator = getEnumerator();
 		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);
 		mManagedInstance = createManagedInstance(mDictionaryTypeInfo);
+
 		if (mManagedInstance == nullptr)
 		if (mManagedInstance == nullptr)
+		{
+			mCachedEntries.clear();
 			return;
 			return;
+		}
 
 
 		::MonoClass* dictionaryMonoClass = mDictionaryTypeInfo->getMonoClass();
 		::MonoClass* dictionaryMonoClass = mDictionaryTypeInfo->getMonoClass();
 		MonoClass* dictionaryClass = MonoManager::instance().findClass(dictionaryMonoClass);
 		MonoClass* dictionaryClass = MonoManager::instance().findClass(dictionaryMonoClass);
@@ -132,59 +200,96 @@ namespace BansheeEngine
 
 
 		initMonoObjects(dictionaryClass);
 		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)
 	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 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 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
 	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
 	ManagedSerializableDictionary::Enumerator ManagedSerializableDictionary::getEnumerator() const

+ 190 - 39
SBansheeEngine/Source/BsManagedSerializableField.cpp

@@ -25,39 +25,28 @@
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
 	template<class T>
 	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))
 		if (rtti_is_of_type<T>(b))
 		{
 		{
 			auto castObj = std::static_pointer_cast<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;
 		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 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;
 		return fieldKey;
 	}
 	}
 
 
@@ -972,97 +961,259 @@ namespace BansheeEngine
 
 
 	bool ManagedSerializableFieldDataBool::equals(const ManagedSerializableFieldDataPtr& other)
 	bool ManagedSerializableFieldDataBool::equals(const ManagedSerializableFieldDataPtr& other)
 	{
 	{
-		return comparePrimitiveFieldData(this, other);
+		return compareFieldData(this, other);
 	}
 	}
 
 
 	bool ManagedSerializableFieldDataChar::equals(const ManagedSerializableFieldDataPtr& other)
 	bool ManagedSerializableFieldDataChar::equals(const ManagedSerializableFieldDataPtr& other)
 	{
 	{
-		return comparePrimitiveFieldData(this, other);
+		return compareFieldData(this, other);
 	}
 	}
 
 
 	bool ManagedSerializableFieldDataI8::equals(const ManagedSerializableFieldDataPtr& other)
 	bool ManagedSerializableFieldDataI8::equals(const ManagedSerializableFieldDataPtr& other)
 	{
 	{
-		return comparePrimitiveFieldData(this, other);
+		return compareFieldData(this, other);
 	}
 	}
 
 
 	bool ManagedSerializableFieldDataU8::equals(const ManagedSerializableFieldDataPtr& other)
 	bool ManagedSerializableFieldDataU8::equals(const ManagedSerializableFieldDataPtr& other)
 	{
 	{
-		return comparePrimitiveFieldData(this, other);
+		return compareFieldData(this, other);
 	}
 	}
 
 
 	bool ManagedSerializableFieldDataI16::equals(const ManagedSerializableFieldDataPtr& other)
 	bool ManagedSerializableFieldDataI16::equals(const ManagedSerializableFieldDataPtr& other)
 	{
 	{
-		return comparePrimitiveFieldData(this, other);
+		return compareFieldData(this, other);
 	}
 	}
 
 
 	bool ManagedSerializableFieldDataU16::equals(const ManagedSerializableFieldDataPtr& other)
 	bool ManagedSerializableFieldDataU16::equals(const ManagedSerializableFieldDataPtr& other)
 	{
 	{
-		return comparePrimitiveFieldData(this, other);
+		return compareFieldData(this, other);
 	}
 	}
 
 
 	bool ManagedSerializableFieldDataI32::equals(const ManagedSerializableFieldDataPtr& other)
 	bool ManagedSerializableFieldDataI32::equals(const ManagedSerializableFieldDataPtr& other)
 	{
 	{
-		return comparePrimitiveFieldData(this, other);
+		return compareFieldData(this, other);
 	}
 	}
 
 
 	bool ManagedSerializableFieldDataU32::equals(const ManagedSerializableFieldDataPtr& other)
 	bool ManagedSerializableFieldDataU32::equals(const ManagedSerializableFieldDataPtr& other)
 	{
 	{
-		return comparePrimitiveFieldData(this, other);
+		return compareFieldData(this, other);
 	}
 	}
 
 
 	bool ManagedSerializableFieldDataI64::equals(const ManagedSerializableFieldDataPtr& other)
 	bool ManagedSerializableFieldDataI64::equals(const ManagedSerializableFieldDataPtr& other)
 	{
 	{
-		return comparePrimitiveFieldData(this, other);
+		return compareFieldData(this, other);
 	}
 	}
 
 
 	bool ManagedSerializableFieldDataU64::equals(const ManagedSerializableFieldDataPtr& other)
 	bool ManagedSerializableFieldDataU64::equals(const ManagedSerializableFieldDataPtr& other)
 	{
 	{
-		return comparePrimitiveFieldData(this, other);
+		return compareFieldData(this, other);
 	}
 	}
 
 
 	bool ManagedSerializableFieldDataFloat::equals(const ManagedSerializableFieldDataPtr& other)
 	bool ManagedSerializableFieldDataFloat::equals(const ManagedSerializableFieldDataPtr& other)
 	{
 	{
-		return comparePrimitiveFieldData(this, other);
+		return compareFieldData(this, other);
 	}
 	}
 
 
 	bool ManagedSerializableFieldDataDouble::equals(const ManagedSerializableFieldDataPtr& other)
 	bool ManagedSerializableFieldDataDouble::equals(const ManagedSerializableFieldDataPtr& other)
 	{
 	{
-		return comparePrimitiveFieldData(this, other);
+		return compareFieldData(this, other);
 	}
 	}
 
 
 	bool ManagedSerializableFieldDataString::equals(const ManagedSerializableFieldDataPtr& other)
 	bool ManagedSerializableFieldDataString::equals(const ManagedSerializableFieldDataPtr& other)
 	{
 	{
-		return comparePrimitiveFieldData(this, other);
+		return compareFieldData(this, other);
 	}
 	}
 
 
 	bool ManagedSerializableFieldDataResourceRef::equals(const ManagedSerializableFieldDataPtr& other)
 	bool ManagedSerializableFieldDataResourceRef::equals(const ManagedSerializableFieldDataPtr& other)
 	{
 	{
-		return comparePrimitiveFieldData(this, other);
+		return compareFieldData(this, other);
 	}
 	}
 
 
 	bool ManagedSerializableFieldDataGameObjectRef::equals(const ManagedSerializableFieldDataPtr& other)
 	bool ManagedSerializableFieldDataGameObjectRef::equals(const ManagedSerializableFieldDataPtr& other)
 	{
 	{
-		return comparePrimitiveFieldData(this, other);
+		return compareFieldData(this, other);
 	}
 	}
 
 
 	bool ManagedSerializableFieldDataObject::equals(const ManagedSerializableFieldDataPtr& other)
 	bool ManagedSerializableFieldDataObject::equals(const ManagedSerializableFieldDataPtr& other)
 	{
 	{
-		return compareObjectFieldData(this, other);
+		return compareFieldData(this, other);
 	}
 	}
 
 
 	bool ManagedSerializableFieldDataArray::equals(const ManagedSerializableFieldDataPtr& other)
 	bool ManagedSerializableFieldDataArray::equals(const ManagedSerializableFieldDataPtr& other)
 	{
 	{
-		return compareObjectFieldData(this, other);
+		return compareFieldData(this, other);
 	}
 	}
 
 
 	bool ManagedSerializableFieldDataList::equals(const ManagedSerializableFieldDataPtr& other)
 	bool ManagedSerializableFieldDataList::equals(const ManagedSerializableFieldDataPtr& other)
 	{
 	{
-		return compareObjectFieldData(this, other);
+		return compareFieldData(this, other);
 	}
 	}
 
 
 	bool ManagedSerializableFieldDataDictionary::equals(const ManagedSerializableFieldDataPtr& 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()
 	RTTITypeBase* ManagedSerializableFieldKey::getRTTIStatic()

+ 76 - 33
SBansheeEngine/Source/BsManagedSerializableList.cpp

@@ -71,29 +71,15 @@ namespace BansheeEngine
 		return bs_shared_ptr<ManagedSerializableList>(ConstructPrivately());
 		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)
 	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];
 		void* params[1];
 		params[0] = val->getValue(mListTypeInfo->mElementType);
 		params[0] = val->getValue(mListTypeInfo->mElementType);
@@ -102,33 +88,90 @@ namespace BansheeEngine
 
 
 	ManagedSerializableFieldDataPtr ManagedSerializableList::getFieldData(UINT32 arrayIdx)
 	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)
 	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;
 		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
 	UINT32 ManagedSerializableList::getLengthInternal() const
 	{
 	{
 		MonoObject* length = mCountProp->get(mManagedInstance);
 		MonoObject* length = mCountProp->get(mManagedInstance);

+ 90 - 57
SBansheeEngine/Source/BsManagedSerializableObject.cpp

@@ -3,12 +3,26 @@
 #include "BsManagedSerializableObjectInfo.h"
 #include "BsManagedSerializableObjectInfo.h"
 #include "BsManagedSerializableField.h"
 #include "BsManagedSerializableField.h"
 #include "BsScriptAssemblyManager.h"
 #include "BsScriptAssemblyManager.h"
-#include "BsManagedSerializableObjectData.h"
 #include "BsMonoField.h"
 #include "BsMonoField.h"
+#include "BsMonoClass.h"
 #include "BsMonoUtil.h"
 #include "BsMonoUtil.h"
 
 
 namespace BansheeEngine
 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)
 	ManagedSerializableObject::ManagedSerializableObject(const ConstructPrivately& dummy)
 		:mManagedInstance(nullptr)
 		:mManagedInstance(nullptr)
 	{
 	{
@@ -67,97 +81,116 @@ namespace BansheeEngine
 		return bs_shared_ptr<ManagedSerializableObject>(ConstructPrivately());
 		return bs_shared_ptr<ManagedSerializableObject>(ConstructPrivately());
 	}
 	}
 
 
-	void ManagedSerializableObject::deserializeManagedInstance(const Vector<ManagedSerializableFieldDataEntryPtr>& entries)
+	void ManagedSerializableObject::serialize()
 	{
 	{
-		mManagedInstance = createManagedInstance(mObjInfo->mTypeInfo);
-
 		if (mManagedInstance == nullptr)
 		if (mManagedInstance == nullptr)
 			return;
 			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;
 		ManagedSerializableObjectInfoPtr currentObjInfo = nullptr;
 
 
 		// See if this type even still exists
 		// 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;
 			return;
+		}
+
+		// Deserialize children
+		for (auto& fieldEntry : mCachedData)
+			fieldEntry.second->deserialize();
 
 
 		// Scan all fields and ensure the fields still exist
 		// 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()
 	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()
 	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,
 	ManagedSerializableFieldInfoPtr ManagedSerializableObjectInfo::findMatchingField(const ManagedSerializableFieldInfoPtr& fieldInfo,
 		const ManagedSerializableTypeInfoPtr& fieldTypeInfo) const
 		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>();
 				std::shared_ptr<ManagedSerializableTypeInfoObject> typeInfo = bs_shared_ptr<ManagedSerializableTypeInfoObject>();
 				typeInfo->mTypeNamespace = curClass->getNamespace();
 				typeInfo->mTypeNamespace = curClass->getNamespace();
 				typeInfo->mTypeName = curClass->getTypeName();
 				typeInfo->mTypeName = curClass->getTypeName();
+				typeInfo->mTypeId = mUniqueTypeId++;
 
 
 				MonoType* monoType = mono_class_get_type(curClass->_getInternalClass());
 				MonoType* monoType = mono_class_get_type(curClass->_getInternalClass());
 				int monoPrimitiveType = mono_type_get_type(monoType);
 				int monoPrimitiveType = mono_type_get_type(monoType);
@@ -76,13 +77,11 @@ namespace BansheeEngine
 
 
 				std::shared_ptr<ManagedSerializableObjectInfo> objInfo = bs_shared_ptr<ManagedSerializableObjectInfo>();
 				std::shared_ptr<ManagedSerializableObjectInfo> objInfo = bs_shared_ptr<ManagedSerializableObjectInfo>();
 
 
-				objInfo->mTypeId = mUniqueTypeId++;
-
 				objInfo->mTypeInfo = typeInfo;
 				objInfo->mTypeInfo = typeInfo;
 				objInfo->mMonoClass = curClass;
 				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->mName = field->getName();
 				fieldInfo->mMonoField = field;
 				fieldInfo->mMonoField = field;
 				fieldInfo->mTypeInfo = typeInfo;
 				fieldInfo->mTypeInfo = typeInfo;
+				fieldInfo->mParentTypeId = objInfo->mTypeInfo->mTypeId;
 				
 				
 				MonoFieldVisibility visibility = field->getVisibility();
 				MonoFieldVisibility visibility = field->getVisibility();
 				if (visibility == MonoFieldVisibility::Public)
 				if (visibility == MonoFieldVisibility::Public)
@@ -147,13 +147,6 @@ namespace BansheeEngine
 				base = base->getBaseClass();
 				base = base->getBaseClass();
 			}
 			}
 		}
 		}
-
-		// Finish object info initialization
-		for (auto& curClassInfo : assemblyInfo->mObjectInfos)
-		{
-			std::shared_ptr<ManagedSerializableObjectInfo> objInfo = curClassInfo.second;
-			objInfo->initialize();
-		}
 	}
 	}
 
 
 	void ScriptAssemblyManager::refreshAssemblyInfo()
 	void ScriptAssemblyManager::refreshAssemblyInfo()

+ 21 - 5
TODO.txt

@@ -27,11 +27,6 @@ return them in checkForModifications?
 ---------------------------------------------------------------------
 ---------------------------------------------------------------------
 Prefab diff
 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)
 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
  - 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
  - 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
  - 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)
    (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)
 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)
  - 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
   - 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
 Polish stage 1