Selaa lähdekoodia

A lot of work on List/Dictionary C# serialization

Marko Pintera 12 vuotta sitten
vanhempi
sitoutus
55f8931e8f

+ 1 - 0
BansheeMono/Include/BsMonoClass.h

@@ -55,6 +55,7 @@ namespace BansheeEngine
 		bool hasAttribute(MonoClass* monoClass) const;
 		bool hasAttribute(MonoClass* monoClass) const;
 		bool hasField(const CM::String& name) const;
 		bool hasField(const CM::String& name) const;
 		bool isSubClassOf(const BS::MonoClass* monoClass) const;
 		bool isSubClassOf(const BS::MonoClass* monoClass) const;
+		bool isInstanceOfType(MonoObject* object) const;
 
 
 		MonoObject* invokeMethod(const CM::String& name, MonoObject* instance = nullptr, void** params = nullptr, CM::UINT32 numParams = 0);
 		MonoObject* invokeMethod(const CM::String& name, MonoObject* instance = nullptr, void** params = nullptr, CM::UINT32 numParams = 0);
 		void addInternalCall(const CM::String& name, const void* method);
 		void addInternalCall(const CM::String& name, const void* method);

+ 2 - 0
BansheeMono/Include/BsMonoProperty.h

@@ -11,6 +11,7 @@ namespace BansheeEngine
 		MonoObject* get(MonoObject* instance) const;
 		MonoObject* get(MonoObject* instance) const;
 		void set(MonoObject* instance, MonoObject* value) const;
 		void set(MonoObject* instance, MonoObject* value) const;
 
 
+		MonoClass* getReturnType();
 	private:
 	private:
 		friend class MonoClass;
 		friend class MonoClass;
 
 
@@ -19,5 +20,6 @@ namespace BansheeEngine
 		::MonoProperty* mProperty;
 		::MonoProperty* mProperty;
 		::MonoMethod* mGetMethod;
 		::MonoMethod* mGetMethod;
 		::MonoMethod* mSetMethod;
 		::MonoMethod* mSetMethod;
+		MonoClass* mPropertyType;
 	};
 	};
 }
 }

+ 9 - 0
BansheeMono/Source/BsMonoClass.cpp

@@ -254,4 +254,13 @@ namespace BansheeEngine
 
 
 		return MonoManager::instance().findClass(ns, typeName);
 		return MonoManager::instance().findClass(ns, typeName);
 	}
 	}
+
+	bool MonoClass::isInstanceOfType(MonoObject* object) const
+	{
+		if(object == nullptr)
+			return false;
+
+		::MonoClass* monoClass = mono_object_get_class(object);
+		return mono_class_is_subclass_of(monoClass, mClass, false) != 0;
+	}
 }
 }

+ 19 - 1
BansheeMono/Source/BsMonoProperty.cpp

@@ -1,12 +1,13 @@
 #include "BsMonoProperty.h"
 #include "BsMonoProperty.h"
 #include "BsMonoMethod.h"
 #include "BsMonoMethod.h"
+#include "BsMonoManager.h"
 
 
 using namespace CamelotFramework;
 using namespace CamelotFramework;
 
 
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
 	MonoProperty::MonoProperty(::MonoProperty* monoProp)
 	MonoProperty::MonoProperty(::MonoProperty* monoProp)
-		:mProperty(monoProp)
+		:mProperty(monoProp), mPropertyType(nullptr)
 	{
 	{
 		mGetMethod = mono_property_get_get_method(mProperty);
 		mGetMethod = mono_property_get_get_method(mProperty);
 		mSetMethod = mono_property_get_set_method(mProperty);
 		mSetMethod = mono_property_get_set_method(mProperty);
@@ -23,4 +24,21 @@ namespace BansheeEngine
 		args[0] = value;
 		args[0] = value;
 		mono_runtime_invoke(mSetMethod, instance, args, nullptr);
 		mono_runtime_invoke(mSetMethod, instance, args, nullptr);
 	}	
 	}	
+
+	MonoClass* MonoProperty::getReturnType()
+	{
+		if(mPropertyType != nullptr)
+			return mPropertyType;
+
+		MonoType* returnType = mono_signature_get_return_type(mono_method_signature(mGetMethod));
+		if(returnType == nullptr)
+			return nullptr;
+
+		::MonoClass* returnClass = mono_class_from_mono_type(returnType);
+		if(returnClass == nullptr)
+			return nullptr;	
+
+		mPropertyType = MonoManager::instance().findClass(returnClass);
+		return mPropertyType;
+	}
 }
 }

+ 4 - 2
SBansheeEngine/Include/BsRuntimeScriptObjects.h

@@ -17,9 +17,9 @@ namespace BansheeEngine
 		bool getSerializableObjectInfo(const CM::String& ns, const CM::String& typeName, std::shared_ptr<ScriptSerializableObjectInfo>& outInfo);
 		bool getSerializableObjectInfo(const CM::String& ns, const CM::String& typeName, std::shared_ptr<ScriptSerializableObjectInfo>& outInfo);
 		bool hasSerializableObjectInfo(const CM::String& ns, const CM::String& typeName);
 		bool hasSerializableObjectInfo(const CM::String& ns, const CM::String& typeName);
 
 
-		bool isArray(MonoObject* object);
-
 		MonoClass* getSystemArrayClass() const { return mSystemArrayClass; }
 		MonoClass* getSystemArrayClass() const { return mSystemArrayClass; }
+		MonoClass* getSystemGenericListClass() const { return mSystemGenericListClass; }
+		MonoClass* getSystemGenericDictionaryClass() const { return mSystemGenericDictionaryClass; }
 		MonoClass* getComponentClass() const { return mComponentClass; }
 		MonoClass* getComponentClass() const { return mComponentClass; }
 		MonoClass* getSceneObjectClass() const { return mSceneObjectClass; }
 		MonoClass* getSceneObjectClass() const { return mSceneObjectClass; }
 		MonoClass* getTextureClass() const { return mTextureClass; }
 		MonoClass* getTextureClass() const { return mTextureClass; }
@@ -29,6 +29,8 @@ namespace BansheeEngine
 		bool mBaseTypesInitialized;
 		bool mBaseTypesInitialized;
 
 
 		MonoClass* mSystemArrayClass;
 		MonoClass* mSystemArrayClass;
+		MonoClass* mSystemGenericListClass;
+		MonoClass* mSystemGenericDictionaryClass;
 
 
 		MonoClass* mComponentClass;
 		MonoClass* mComponentClass;
 		MonoClass* mSceneObjectClass;
 		MonoClass* mSceneObjectClass;

+ 15 - 1
SBansheeEngine/Include/BsScriptEnginePrerequisites.h

@@ -42,8 +42,12 @@ namespace BansheeEngine
 	class ScriptSerializableTypeInfoPrimitive;
 	class ScriptSerializableTypeInfoPrimitive;
 	class ScriptSerializableTypeInfoObject;
 	class ScriptSerializableTypeInfoObject;
 	class ScriptSerializableTypeInfoArray;
 	class ScriptSerializableTypeInfoArray;
+	class ScriptSerializableTypeInfoList;
+	class ScriptSerializableTypeInfoDictionary;
 	class ScriptSerializableObject;
 	class ScriptSerializableObject;
 	class ScriptSerializableArray;
 	class ScriptSerializableArray;
+	class ScriptSerializableList;
+	class ScriptSerializableDictionary;
 	class ScriptSerializableAssemblyInfo;
 	class ScriptSerializableAssemblyInfo;
 	class ScriptSerializableObjectInfo;
 	class ScriptSerializableObjectInfo;
 	class ScriptSerializableFieldInfo;
 	class ScriptSerializableFieldInfo;
@@ -79,7 +83,13 @@ namespace BansheeEngine
 		TID_SerializableFieldDataResourceRef = 50027,
 		TID_SerializableFieldDataResourceRef = 50027,
 		TID_SerializableFieldDataGameObjectRef = 50028,
 		TID_SerializableFieldDataGameObjectRef = 50028,
 		TID_SerializableFieldDataObject = 50029,
 		TID_SerializableFieldDataObject = 50029,
-		TID_SerializableFieldDataArray = 50030
+		TID_SerializableFieldDataArray = 50030,
+		TID_SerializableFieldDataList = 50031,
+		TID_SerializableFieldDataDictionary = 50032,
+		TID_SerializableTypeInfoList = 50033,
+		TID_SerializableTypeInfoDictionary = 50034,
+		TID_ScriptSerializableList = 50035,
+		TID_ScriptSerializableDictionary = 50036,
 	};
 	};
 
 
 	static const char* BansheeEngineAssemblyName = "MBansheeEngine";
 	static const char* BansheeEngineAssemblyName = "MBansheeEngine";
@@ -91,8 +101,12 @@ namespace BansheeEngine
 	typedef std::shared_ptr<ScriptSerializableTypeInfoObject> ScriptSerializableTypeInfoObjectPtr;
 	typedef std::shared_ptr<ScriptSerializableTypeInfoObject> ScriptSerializableTypeInfoObjectPtr;
 	typedef std::shared_ptr<ScriptSerializableObject> ScriptSerializableObjectPtr;
 	typedef std::shared_ptr<ScriptSerializableObject> ScriptSerializableObjectPtr;
 	typedef std::shared_ptr<ScriptSerializableArray> ScriptSerializableArrayPtr;
 	typedef std::shared_ptr<ScriptSerializableArray> ScriptSerializableArrayPtr;
+	typedef std::shared_ptr<ScriptSerializableList> ScriptSerializableListPtr;
+	typedef std::shared_ptr<ScriptSerializableDictionary> ScriptSerializableDictionaryPtr;
 	typedef std::shared_ptr<ScriptSerializableAssemblyInfo> ScriptSerializableAssemblyInfoPtr;
 	typedef std::shared_ptr<ScriptSerializableAssemblyInfo> ScriptSerializableAssemblyInfoPtr;
 	typedef std::shared_ptr<ScriptSerializableObjectInfo> ScriptSerializableObjectInfoPtr;
 	typedef std::shared_ptr<ScriptSerializableObjectInfo> ScriptSerializableObjectInfoPtr;
 	typedef std::shared_ptr<ScriptSerializableFieldInfo> ScriptSerializableFieldInfoPtr;
 	typedef std::shared_ptr<ScriptSerializableFieldInfo> ScriptSerializableFieldInfoPtr;
 	typedef std::shared_ptr<ScriptSerializableTypeInfoArray> ScriptSerializableTypeInfoArrayPtr;
 	typedef std::shared_ptr<ScriptSerializableTypeInfoArray> ScriptSerializableTypeInfoArrayPtr;
+	typedef std::shared_ptr<ScriptSerializableTypeInfoList> ScriptSerializableTypeInfoListPtr;
+	typedef std::shared_ptr<ScriptSerializableTypeInfoDictionary> ScriptSerializableTypeInfoDictionaryPtr;
 }
 }

+ 60 - 0
SBansheeEngine/Include/BsScriptSerializableDictionary.h

@@ -0,0 +1,60 @@
+#pragma once
+
+#include "BsScriptEnginePrerequisites.h"
+#include "CmIReflectable.h"
+#include <mono/jit/jit.h>
+
+namespace BansheeEngine
+{
+	class BS_SCR_BE_EXPORT ScriptSerializableDictionary : public CM::IReflectable
+	{
+	private:
+		struct ConstructPrivately {};
+
+	public:
+		ScriptSerializableDictionary(const ConstructPrivately& dummy, const ScriptSerializableTypeInfoDictionaryPtr& typeInfo, MonoObject* managedInstance);
+		ScriptSerializableDictionary(const ConstructPrivately& dummy);
+
+		MonoObject* getManagedInstance() const { return mManagedInstance; }
+
+		static ScriptSerializableDictionaryPtr create(MonoObject* managedInstance, const ScriptSerializableTypeInfoDictionaryPtr& typeInfo);
+
+	protected:
+		MonoObject* mManagedInstance;
+
+		ScriptSerializableTypeInfoDictionaryPtr mDictionaryTypeInfo;
+		CM::Vector<ScriptSerializableFieldDataPtr>::type mDictionaryEntries;
+		
+		CM::UINT32 mNumElements;
+
+		/**
+		 * @brief	Populates internal field data based on currently active managed instance.
+		 */
+		void serializeManagedInstance();
+
+		/**
+		 * @brief	Creates a new managed instance and populates it with stored field data.
+		 */
+		void deserializeManagedInstance();
+
+		void setFieldData(CM::UINT32 arrayIdx, const ScriptSerializableFieldDataPtr& val);
+		ScriptSerializableFieldDataPtr getFieldData(CM::UINT32 arrayIdx);
+
+		void setValue(CM::UINT32 arrayIdx, void* val);
+		void* getValue(CM::UINT32 arrayIdx);
+
+		CM::UINT32 getLength() const;
+		void setLength(CM::UINT32 length);
+
+		/************************************************************************/
+		/* 								RTTI		                     		*/
+		/************************************************************************/
+		
+		static ScriptSerializableDictionaryPtr createEmpty();
+
+	public:
+		friend class ScriptSerializableDictionaryRTTI;
+		static CM::RTTITypeBase* getRTTIStatic();
+		virtual CM::RTTITypeBase* getRTTI() const;
+	};
+}

+ 99 - 0
SBansheeEngine/Include/BsScriptSerializableDictionaryRTTI.h

@@ -0,0 +1,99 @@
+#pragma once
+
+#include "BsScriptEnginePrerequisites.h"
+#include "CmRTTIType.h"
+#include "CmGameObjectManager.h"
+#include "BsScriptSerializableDictionary.h"
+#include "BsRuntimeScriptObjects.h"
+#include "BsMonoManager.h"
+#include "BsMonoClass.h"
+
+namespace BansheeEngine
+{
+	class BS_SCR_BE_EXPORT ScriptSerializableDictionaryRTTI : public CM::RTTIType<ScriptSerializableDictionary, CM::IReflectable, ScriptSerializableDictionaryRTTI>
+	{
+	private:
+		ScriptSerializableTypeInfoDictionaryPtr getTypeInfo(ScriptSerializableDictionary* obj)
+		{
+			return obj->mDictionaryTypeInfo;
+		}
+
+		void setTypeInfo(ScriptSerializableDictionary* obj, ScriptSerializableTypeInfoDictionaryPtr val)
+		{
+			obj->mDictionaryTypeInfo = val;
+		}
+
+		CM::UINT32& getNumElements(ScriptSerializableDictionary* obj)
+		{
+			return (CM::UINT32)obj->mNumElements;
+		}
+
+		void setNumElements(ScriptSerializableDictionary* obj, CM::UINT32& numElements)
+		{
+			obj->mNumElements = numElements;
+		}
+
+		ScriptSerializableFieldDataPtr getListEntry(ScriptSerializableDictionary* obj, CM::UINT32 arrayIdx)
+		{
+			return obj->mDictionaryEntries[arrayIdx];
+		}
+
+		void setListEntry(ScriptSerializableDictionary* obj, CM::UINT32 arrayIdx, ScriptSerializableFieldDataPtr val)
+		{
+			obj->mDictionaryEntries[arrayIdx] = val;
+		}
+
+		CM::UINT32 getNumListEntries(ScriptSerializableDictionary* obj)
+		{
+			return (CM::UINT32)obj->mDictionaryEntries.size();
+		}
+
+		void setNumListEntries(ScriptSerializableDictionary* obj, CM::UINT32 numEntries)
+		{
+			obj->mDictionaryEntries.resize(numEntries);
+		}
+
+	public:
+		ScriptSerializableDictionaryRTTI()
+		{
+			addReflectablePtrField("mListTypeInfo", 0, &ScriptSerializableDictionaryRTTI::getTypeInfo, &ScriptSerializableDictionaryRTTI::setTypeInfo);
+			addPlainField("mNumElements", 1, &ScriptSerializableDictionaryRTTI::getNumElements, &ScriptSerializableDictionaryRTTI::setNumElements);
+			addReflectablePtrArrayField("mListEntries", 2, &ScriptSerializableDictionaryRTTI::getListEntry, &ScriptSerializableDictionaryRTTI::getNumListEntries, 
+				&ScriptSerializableDictionaryRTTI::setListEntry, &ScriptSerializableDictionaryRTTI::setNumListEntries);
+		}
+
+		virtual void onSerializationStarted(CM::IReflectable* obj)
+		{
+			ScriptSerializableDictionary* serializableObject = static_cast<ScriptSerializableDictionary*>(obj);
+			serializableObject->serializeManagedInstance();
+		}
+
+		virtual void onDeserializationStarted(CM::IReflectable* obj)
+		{
+			ScriptSerializableDictionary* serializableObject = static_cast<ScriptSerializableDictionary*>(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(CM::GameObjectManager::instance().isGameObjectDeserializationActive())
+				CM::GameObjectManager::instance().registerOnDeserializationEndCallback([=] () { serializableObject->deserializeManagedInstance(); });
+			else
+				serializableObject->deserializeManagedInstance();
+		}
+
+		virtual const CM::String& getRTTIName()
+		{
+			static CM::String name = "ScriptSerializableDictionary";
+			return name;
+		}
+
+		virtual CM::UINT32 getRTTIId()
+		{
+			return TID_ScriptSerializableDictionary;
+		}
+
+		virtual std::shared_ptr<CM::IReflectable> newRTTIObject()
+		{
+			return ScriptSerializableDictionary::createEmpty();
+		}
+	};
+}

+ 36 - 0
SBansheeEngine/Include/BsScriptSerializableField.h

@@ -365,4 +365,40 @@ namespace BansheeEngine
 		static CM::RTTITypeBase* getRTTIStatic();
 		static CM::RTTITypeBase* getRTTIStatic();
 		virtual CM::RTTITypeBase* getRTTI() const;
 		virtual CM::RTTITypeBase* getRTTI() const;
 	};
 	};
+
+	class BS_SCR_BE_EXPORT ScriptSerializableFieldDataList : public ScriptSerializableFieldData
+	{
+	public:
+		ScriptSerializableListPtr value;
+
+		void* getValue(const ScriptSerializableTypeInfoPtr& typeInfo);
+		bool isValueType() const { return false; }
+
+		/************************************************************************/
+		/* 								RTTI		                     		*/
+		/************************************************************************/
+
+	public:
+		friend class ScriptSerializableFieldDataListRTTI;
+		static CM::RTTITypeBase* getRTTIStatic();
+		virtual CM::RTTITypeBase* getRTTI() const;
+	};
+
+	class BS_SCR_BE_EXPORT ScriptSerializableFieldDataDictionary : public ScriptSerializableFieldData
+	{
+	public:
+		ScriptSerializableDictionaryPtr value;
+
+		void* getValue(const ScriptSerializableTypeInfoPtr& typeInfo);
+		bool isValueType() const { return false; }
+
+		/************************************************************************/
+		/* 								RTTI		                     		*/
+		/************************************************************************/
+
+	public:
+		friend class ScriptSerializableFieldDataDictionaryRTTI;
+		static CM::RTTITypeBase* getRTTIStatic();
+		virtual CM::RTTITypeBase* getRTTI() const;
+	};
 }
 }

+ 58 - 0
SBansheeEngine/Include/BsScriptSerializableFieldRTTI.h

@@ -592,4 +592,62 @@ namespace BansheeEngine
 			return CM::cm_shared_ptr<ScriptSerializableFieldDataArray>();
 			return CM::cm_shared_ptr<ScriptSerializableFieldDataArray>();
 		}
 		}
 	};
 	};
+
+	class BS_SCR_BE_EXPORT ScriptSerializableFieldDataListRTTI : public CM::RTTIType<ScriptSerializableFieldDataList, ScriptSerializableFieldData, ScriptSerializableFieldDataListRTTI>
+	{
+	private:
+		ScriptSerializableListPtr getValue(ScriptSerializableFieldDataList* obj) { return obj->value; }
+		void setValue(ScriptSerializableFieldDataList* obj, ScriptSerializableListPtr val) { obj->value = val; }
+
+	public:
+		ScriptSerializableFieldDataListRTTI()
+		{
+			addReflectablePtrField("mValue", 0, &ScriptSerializableFieldDataListRTTI::getValue, &ScriptSerializableFieldDataListRTTI::setValue);
+		}
+
+		virtual const CM::String& getRTTIName()
+		{
+			static CM::String name = "SerializableFieldDataList";
+			return name;
+		}
+
+		virtual CM::UINT32 getRTTIId()
+		{
+			return TID_SerializableFieldDataList;
+		}
+
+		virtual std::shared_ptr<CM::IReflectable> newRTTIObject()
+		{
+			return CM::cm_shared_ptr<ScriptSerializableFieldDataList>();
+		}
+	};
+
+	class BS_SCR_BE_EXPORT ScriptSerializableFieldDataDictionaryRTTI : public CM::RTTIType<ScriptSerializableFieldDataDictionary, ScriptSerializableFieldData, ScriptSerializableFieldDataDictionaryRTTI>
+	{
+	private:
+		ScriptSerializableDictionaryPtr getValue(ScriptSerializableFieldDataDictionary* obj) { return obj->value; }
+		void setValue(ScriptSerializableFieldDataDictionary* obj, ScriptSerializableDictionaryPtr val) { obj->value = val; }
+
+	public:
+		ScriptSerializableFieldDataDictionaryRTTI()
+		{
+			addReflectablePtrField("mValue", 0, &ScriptSerializableFieldDataDictionaryRTTI::getValue, &ScriptSerializableFieldDataDictionaryRTTI::setValue);
+		}
+
+		virtual const CM::String& getRTTIName()
+		{
+			static CM::String name = "SerializableFieldDataDictionary";
+			return name;
+		}
+
+		virtual CM::UINT32 getRTTIId()
+		{
+			return TID_SerializableFieldDataDictionary;
+		}
+
+		virtual std::shared_ptr<CM::IReflectable> newRTTIObject()
+		{
+			return CM::cm_shared_ptr<ScriptSerializableFieldDataDictionary>();
+		}
+	};
 }
 }

+ 60 - 0
SBansheeEngine/Include/BsScriptSerializableList.h

@@ -0,0 +1,60 @@
+#pragma once
+
+#include "BsScriptEnginePrerequisites.h"
+#include "CmIReflectable.h"
+#include <mono/jit/jit.h>
+
+namespace BansheeEngine
+{
+	class BS_SCR_BE_EXPORT ScriptSerializableList : public CM::IReflectable
+	{
+	private:
+		struct ConstructPrivately {};
+
+	public:
+		ScriptSerializableList(const ConstructPrivately& dummy, const ScriptSerializableTypeInfoListPtr& typeInfo, MonoObject* managedInstance);
+		ScriptSerializableList(const ConstructPrivately& dummy);
+
+		MonoObject* getManagedInstance() const { return mManagedInstance; }
+
+		static ScriptSerializableListPtr create(MonoObject* managedInstance, const ScriptSerializableTypeInfoListPtr& typeInfo);
+
+	protected:
+		MonoObject* mManagedInstance;
+
+		ScriptSerializableTypeInfoListPtr mListTypeInfo;
+		CM::Vector<ScriptSerializableFieldDataPtr>::type mListEntries;
+		
+		CM::UINT32 mNumElements;
+
+		/**
+		 * @brief	Populates internal field data based on currently active managed instance.
+		 */
+		void serializeManagedInstance();
+
+		/**
+		 * @brief	Creates a new managed instance and populates it with stored field data.
+		 */
+		void deserializeManagedInstance();
+
+		void setFieldData(CM::UINT32 arrayIdx, const ScriptSerializableFieldDataPtr& val);
+		ScriptSerializableFieldDataPtr getFieldData(CM::UINT32 arrayIdx);
+
+		void setValue(CM::UINT32 arrayIdx, void* val);
+		void* getValue(CM::UINT32 arrayIdx);
+
+		CM::UINT32 getLength() const;
+		void setLength(CM::UINT32 length);
+
+		/************************************************************************/
+		/* 								RTTI		                     		*/
+		/************************************************************************/
+		
+		static ScriptSerializableListPtr createEmpty();
+
+	public:
+		friend class ScriptSerializableListRTTI;
+		static CM::RTTITypeBase* getRTTIStatic();
+		virtual CM::RTTITypeBase* getRTTI() const;
+	};
+}

+ 99 - 0
SBansheeEngine/Include/BsScriptSerializableListRTTI.h

@@ -0,0 +1,99 @@
+#pragma once
+
+#include "BsScriptEnginePrerequisites.h"
+#include "CmRTTIType.h"
+#include "CmGameObjectManager.h"
+#include "BsScriptSerializableList.h"
+#include "BsRuntimeScriptObjects.h"
+#include "BsMonoManager.h"
+#include "BsMonoClass.h"
+
+namespace BansheeEngine
+{
+	class BS_SCR_BE_EXPORT ScriptSerializableListRTTI : public CM::RTTIType<ScriptSerializableList, CM::IReflectable, ScriptSerializableListRTTI>
+	{
+	private:
+		ScriptSerializableTypeInfoListPtr getTypeInfo(ScriptSerializableList* obj)
+		{
+			return obj->mListTypeInfo;
+		}
+
+		void setTypeInfo(ScriptSerializableList* obj, ScriptSerializableTypeInfoListPtr val)
+		{
+			obj->mListTypeInfo = val;
+		}
+
+		CM::UINT32& getNumElements(ScriptSerializableList* obj)
+		{
+			return (CM::UINT32)obj->mNumElements;
+		}
+
+		void setNumElements(ScriptSerializableList* obj, CM::UINT32& numElements)
+		{
+			obj->mNumElements = numElements;
+		}
+
+		ScriptSerializableFieldDataPtr getListEntry(ScriptSerializableList* obj, CM::UINT32 arrayIdx)
+		{
+			return obj->mListEntries[arrayIdx];
+		}
+
+		void setListEntry(ScriptSerializableList* obj, CM::UINT32 arrayIdx, ScriptSerializableFieldDataPtr val)
+		{
+			obj->mListEntries[arrayIdx] = val;
+		}
+
+		CM::UINT32 getNumListEntries(ScriptSerializableList* obj)
+		{
+			return (CM::UINT32)obj->mListEntries.size();
+		}
+
+		void setNumListEntries(ScriptSerializableList* obj, CM::UINT32 numEntries)
+		{
+			obj->mListEntries.resize(numEntries);
+		}
+
+	public:
+		ScriptSerializableListRTTI()
+		{
+			addReflectablePtrField("mListTypeInfo", 0, &ScriptSerializableListRTTI::getTypeInfo, &ScriptSerializableListRTTI::setTypeInfo);
+			addPlainField("mNumElements", 1, &ScriptSerializableListRTTI::getNumElements, &ScriptSerializableListRTTI::setNumElements);
+			addReflectablePtrArrayField("mListEntries", 2, &ScriptSerializableListRTTI::getListEntry, &ScriptSerializableListRTTI::getNumListEntries, 
+				&ScriptSerializableListRTTI::setListEntry, &ScriptSerializableListRTTI::setNumListEntries);
+		}
+
+		virtual void onSerializationStarted(CM::IReflectable* obj)
+		{
+			ScriptSerializableList* serializableObject = static_cast<ScriptSerializableList*>(obj);
+			serializableObject->serializeManagedInstance();
+		}
+
+		virtual void onDeserializationStarted(CM::IReflectable* obj)
+		{
+			ScriptSerializableList* serializableObject = static_cast<ScriptSerializableList*>(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(CM::GameObjectManager::instance().isGameObjectDeserializationActive())
+				CM::GameObjectManager::instance().registerOnDeserializationEndCallback([=] () { serializableObject->deserializeManagedInstance(); });
+			else
+				serializableObject->deserializeManagedInstance();
+		}
+
+		virtual const CM::String& getRTTIName()
+		{
+			static CM::String name = "ScriptSerializableList";
+			return name;
+		}
+
+		virtual CM::UINT32 getRTTIId()
+		{
+			return TID_ScriptSerializableList;
+		}
+
+		virtual std::shared_ptr<CM::IReflectable> newRTTIObject()
+		{
+			return ScriptSerializableList::createEmpty();
+		}
+	};
+}

+ 39 - 0
SBansheeEngine/Include/BsScriptSerializableObjectInfo.h

@@ -36,6 +36,8 @@ namespace BansheeEngine
 	class BS_SCR_BE_EXPORT ScriptSerializableTypeInfo : public CM::IReflectable
 	class BS_SCR_BE_EXPORT ScriptSerializableTypeInfo : public CM::IReflectable
 	{
 	{
 	public:
 	public:
+		virtual ~ScriptSerializableTypeInfo() {}
+
 		virtual bool matches(const ScriptSerializableTypeInfoPtr& typeInfo) const = 0;
 		virtual bool matches(const ScriptSerializableTypeInfoPtr& typeInfo) const = 0;
 		virtual bool isTypeLoaded() const = 0;
 		virtual bool isTypeLoaded() const = 0;
 		virtual ::MonoClass* getMonoClass() const = 0;
 		virtual ::MonoClass* getMonoClass() const = 0;
@@ -106,6 +108,43 @@ namespace BansheeEngine
 		virtual CM::RTTITypeBase* getRTTI() const;
 		virtual CM::RTTITypeBase* getRTTI() const;
 	};
 	};
 
 
+	class BS_SCR_BE_EXPORT ScriptSerializableTypeInfoList : public ScriptSerializableTypeInfo
+	{
+	public:
+		ScriptSerializableTypeInfoPtr mElementType;
+
+		bool matches(const ScriptSerializableTypeInfoPtr& typeInfo) const;
+		bool isTypeLoaded() const;
+		::MonoClass* getMonoClass() const;
+
+		/************************************************************************/
+		/* 								RTTI		                     		*/
+		/************************************************************************/
+	public:
+		friend class ScriptSerializableTypeInfoListRTTI;
+		static CM::RTTITypeBase* getRTTIStatic();
+		virtual CM::RTTITypeBase* getRTTI() const;
+	};
+
+	class BS_SCR_BE_EXPORT ScriptSerializableTypeInfoDictionary : public ScriptSerializableTypeInfo
+	{
+	public:
+		ScriptSerializableTypeInfoPtr mKeyType;
+		ScriptSerializableTypeInfoPtr mValueType;
+
+		bool matches(const ScriptSerializableTypeInfoPtr& typeInfo) const;
+		bool isTypeLoaded() const;
+		::MonoClass* getMonoClass() const;
+
+		/************************************************************************/
+		/* 								RTTI		                     		*/
+		/************************************************************************/
+	public:
+		friend class ScriptSerializableTypeInfoDictionaryRTTI;
+		static CM::RTTITypeBase* getRTTIStatic();
+		virtual CM::RTTITypeBase* getRTTI() const;
+	};
+
 	class BS_SCR_BE_EXPORT ScriptSerializableFieldInfo : public CM::IReflectable
 	class BS_SCR_BE_EXPORT ScriptSerializableFieldInfo : public CM::IReflectable
 	{
 	{
 	public:
 	public:

+ 83 - 0
SBansheeEngine/Include/BsScriptSerializableObjectInfoRTTI.h

@@ -379,4 +379,87 @@ namespace BansheeEngine
 			return CM::cm_shared_ptr<ScriptSerializableTypeInfoArray>();
 			return CM::cm_shared_ptr<ScriptSerializableTypeInfoArray>();
 		}
 		}
 	};
 	};
+
+	class BS_SCR_BE_EXPORT ScriptSerializableTypeInfoListRTTI : public CM::RTTIType<ScriptSerializableTypeInfoList, ScriptSerializableTypeInfo, ScriptSerializableTypeInfoListRTTI>
+	{
+	private:
+		ScriptSerializableTypeInfoPtr getElementType(ScriptSerializableTypeInfoList* obj)
+		{
+			return obj->mElementType;
+		}
+
+		void setElementType(ScriptSerializableTypeInfoList* obj, ScriptSerializableTypeInfoPtr val)
+		{
+			obj->mElementType = val;
+		}
+
+	public:
+		ScriptSerializableTypeInfoListRTTI()
+		{
+			addReflectablePtrField("mElementType", 0, &ScriptSerializableTypeInfoListRTTI::getElementType, &ScriptSerializableTypeInfoListRTTI::setElementType);
+		}
+
+		virtual const CM::String& getRTTIName()
+		{
+			static CM::String name = "ScriptSerializableTypeInfoList";
+			return name;
+		}
+
+		virtual CM::UINT32 getRTTIId()
+		{
+			return TID_SerializableTypeInfoList;
+		}
+
+		virtual std::shared_ptr<CM::IReflectable> newRTTIObject()
+		{
+			return CM::cm_shared_ptr<ScriptSerializableTypeInfoList>();
+		}
+	};
+
+	class BS_SCR_BE_EXPORT ScriptSerializableTypeInfoDictionaryRTTI : public CM::RTTIType<ScriptSerializableTypeInfoDictionary, ScriptSerializableTypeInfo, ScriptSerializableTypeInfoDictionaryRTTI>
+	{
+	private:
+		ScriptSerializableTypeInfoPtr getKeyType(ScriptSerializableTypeInfoDictionary* obj)
+		{
+			return obj->mKeyType;
+		}
+
+		void setKeyType(ScriptSerializableTypeInfoDictionary* obj, ScriptSerializableTypeInfoPtr val)
+		{
+			obj->mKeyType = val;
+		}
+
+		ScriptSerializableTypeInfoPtr getValueType(ScriptSerializableTypeInfoDictionary* obj)
+		{
+			return obj->mValueType;
+		}
+
+		void setValueType(ScriptSerializableTypeInfoDictionary* obj, ScriptSerializableTypeInfoPtr val)
+		{
+			obj->mValueType = val;
+		}
+
+	public:
+		ScriptSerializableTypeInfoDictionaryRTTI()
+		{
+			addReflectablePtrField("mKeyType", 0, &ScriptSerializableTypeInfoDictionaryRTTI::getKeyType, &ScriptSerializableTypeInfoDictionaryRTTI::setKeyType);
+			addReflectablePtrField("mValueType", 1, &ScriptSerializableTypeInfoDictionaryRTTI::getValueType, &ScriptSerializableTypeInfoDictionaryRTTI::setValueType);
+		}
+
+		virtual const CM::String& getRTTIName()
+		{
+			static CM::String name = "ScriptSerializableTypeInfoDictionary";
+			return name;
+		}
+
+		virtual CM::UINT32 getRTTIId()
+		{
+			return TID_SerializableTypeInfoDictionary;
+		}
+
+		virtual std::shared_ptr<CM::IReflectable> newRTTIObject()
+		{
+			return CM::cm_shared_ptr<ScriptSerializableTypeInfoDictionary>();
+		}
+	};
 }
 }

+ 6 - 0
SBansheeEngine/SBansheeEngine.vcxproj

@@ -230,8 +230,12 @@
     <ClInclude Include="Include\BsManagedComponentRTTI.h" />
     <ClInclude Include="Include\BsManagedComponentRTTI.h" />
     <ClInclude Include="Include\BsScriptSerializableArray.h" />
     <ClInclude Include="Include\BsScriptSerializableArray.h" />
     <ClInclude Include="Include\BsScriptSerializableArrayRTTI.h" />
     <ClInclude Include="Include\BsScriptSerializableArrayRTTI.h" />
+    <ClInclude Include="Include\BsScriptSerializableDictionary.h" />
+    <ClInclude Include="Include\BsScriptSerializableDictionaryRTTI.h" />
     <ClInclude Include="Include\BsScriptSerializableField.h" />
     <ClInclude Include="Include\BsScriptSerializableField.h" />
     <ClInclude Include="Include\BsScriptSerializableFieldRTTI.h" />
     <ClInclude Include="Include\BsScriptSerializableFieldRTTI.h" />
+    <ClInclude Include="Include\BsScriptSerializableList.h" />
+    <ClInclude Include="Include\BsScriptSerializableListRTTI.h" />
     <ClInclude Include="Include\BsScriptSerializableObject.h" />
     <ClInclude Include="Include\BsScriptSerializableObject.h" />
     <ClInclude Include="Include\BsRuntimeScriptObjects.h" />
     <ClInclude Include="Include\BsRuntimeScriptObjects.h" />
     <ClInclude Include="Include\BsScriptComponent.h" />
     <ClInclude Include="Include\BsScriptComponent.h" />
@@ -294,7 +298,9 @@
     <ClCompile Include="Source\BsScriptResourceManager.cpp" />
     <ClCompile Include="Source\BsScriptResourceManager.cpp" />
     <ClCompile Include="Source\BsScriptSceneObject.cpp" />
     <ClCompile Include="Source\BsScriptSceneObject.cpp" />
     <ClCompile Include="Source\BsScriptSerializableArray.cpp" />
     <ClCompile Include="Source\BsScriptSerializableArray.cpp" />
+    <ClCompile Include="Source\BsScriptSerializableDictionary.cpp" />
     <ClCompile Include="Source\BsScriptSerializableField.cpp" />
     <ClCompile Include="Source\BsScriptSerializableField.cpp" />
+    <ClCompile Include="Source\BsScriptSerializableList.cpp" />
     <ClCompile Include="Source\BsScriptSerializableObject.cpp" />
     <ClCompile Include="Source\BsScriptSerializableObject.cpp" />
     <ClCompile Include="Source\BsScriptSerializableObjectInfo.cpp" />
     <ClCompile Include="Source\BsScriptSerializableObjectInfo.cpp" />
     <ClCompile Include="Source\BsScriptSpriteTexture.cpp" />
     <ClCompile Include="Source\BsScriptSpriteTexture.cpp" />

+ 18 - 0
SBansheeEngine/SBansheeEngine.vcxproj.filters

@@ -138,6 +138,18 @@
     <ClInclude Include="Include\BsScriptSerializableFieldRTTI.h">
     <ClInclude Include="Include\BsScriptSerializableFieldRTTI.h">
       <Filter>Header Files</Filter>
       <Filter>Header Files</Filter>
     </ClInclude>
     </ClInclude>
+    <ClInclude Include="Include\BsScriptSerializableList.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="Include\BsScriptSerializableListRTTI.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="Include\BsScriptSerializableDictionary.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="Include\BsScriptSerializableDictionaryRTTI.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\BsScriptTexture2D.cpp">
     <ClCompile Include="Source\BsScriptTexture2D.cpp">
@@ -236,5 +248,11 @@
     <ClCompile Include="Source\BsScriptSerializableField.cpp">
     <ClCompile Include="Source\BsScriptSerializableField.cpp">
       <Filter>Source Files</Filter>
       <Filter>Source Files</Filter>
     </ClCompile>
     </ClCompile>
+    <ClCompile Include="Source\BsScriptSerializableList.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="Source\BsScriptSerializableDictionary.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
   </ItemGroup>
 </Project>
 </Project>

+ 42 - 14
SBansheeEngine/Source/BsRuntimeScriptObjects.cpp

@@ -6,6 +6,7 @@
 #include "BsMonoAssembly.h"
 #include "BsMonoAssembly.h"
 #include "BsMonoClass.h"
 #include "BsMonoClass.h"
 #include "BsMonoField.h"
 #include "BsMonoField.h"
+#include "BsMonoProperty.h"
 #include "BsMonoUtil.h"
 #include "BsMonoUtil.h"
 #include "CmRTTIType.h"
 #include "CmRTTIType.h"
 
 
@@ -16,7 +17,8 @@ namespace BansheeEngine
 	RuntimeScriptObjects::RuntimeScriptObjects()
 	RuntimeScriptObjects::RuntimeScriptObjects()
 		:mBaseTypesInitialized(false), mSerializableObjectAttribute(nullptr), mDontSerializeFieldAttribute(nullptr), 
 		:mBaseTypesInitialized(false), mSerializableObjectAttribute(nullptr), mDontSerializeFieldAttribute(nullptr), 
 		mComponentClass(nullptr), mSceneObjectClass(nullptr), mTextureClass(nullptr), mSpriteTextureClass(nullptr),
 		mComponentClass(nullptr), mSceneObjectClass(nullptr), mTextureClass(nullptr), mSpriteTextureClass(nullptr),
-		mSerializeFieldAttribute(nullptr), mHideInInspectorAttribute(nullptr), mSystemArrayClass(nullptr)
+		mSerializeFieldAttribute(nullptr), mHideInInspectorAttribute(nullptr), mSystemArrayClass(nullptr), mSystemGenericListClass(nullptr),
+		mSystemGenericDictionaryClass(nullptr)
 	{
 	{
 
 
 	}
 	}
@@ -256,6 +258,35 @@ namespace BansheeEngine
 				typeInfo->mType = ScriptPrimitiveType::ComponentRef;
 				typeInfo->mType = ScriptPrimitiveType::ComponentRef;
 				return typeInfo;
 				return typeInfo;
 			}
 			}
+			else if(monoClass->isSubClassOf(mSystemGenericListClass))
+			{
+				std::shared_ptr<ScriptSerializableTypeInfoList> typeInfo = cm_shared_ptr<ScriptSerializableTypeInfoList>();
+				
+				MonoProperty& itemProperty = monoClass->getProperty("Item");
+				MonoClass* itemClass = itemProperty.getReturnType();
+
+				if(itemClass != nullptr)
+					typeInfo->mElementType = determineType(itemClass);
+
+				return typeInfo;
+			}
+			else if(monoClass->isSubClassOf(mSystemGenericDictionaryClass))
+			{
+				std::shared_ptr<ScriptSerializableTypeInfoDictionary> typeInfo = cm_shared_ptr<ScriptSerializableTypeInfoDictionary>();
+
+				MonoProperty& keyProperty = monoClass->getProperty("Key");
+				MonoProperty& valueProperty = monoClass->getProperty("Value");
+
+				MonoClass* keyClass = keyProperty.getReturnType();
+				if(keyClass != nullptr)
+					typeInfo->mKeyType = determineType(keyClass);
+
+				MonoClass* valueClass = valueProperty.getReturnType();
+				if(valueClass != nullptr)
+					typeInfo->mValueType = determineType(valueClass);
+
+				return typeInfo;
+			}
 			else
 			else
 			{
 			{
 				if(hasSerializableObjectInfo(monoClass->getNamespace(), monoClass->getTypeName()))
 				if(hasSerializableObjectInfo(monoClass->getNamespace(), monoClass->getTypeName()))
@@ -267,10 +298,6 @@ namespace BansheeEngine
 
 
 					return typeInfo;
 					return typeInfo;
 				}
 				}
-				else
-				{
-					// TODO - Later check for List or Dictionary here
-				}
 			}
 			}
 
 
 			break;
 			break;
@@ -315,6 +342,8 @@ namespace BansheeEngine
 		mBaseTypesInitialized = false;
 		mBaseTypesInitialized = false;
 
 
 		mSystemArrayClass = nullptr;
 		mSystemArrayClass = nullptr;
+		mSystemGenericListClass = nullptr;
+		mSystemGenericDictionaryClass = nullptr;
 
 
 		mSerializableObjectAttribute = nullptr;
 		mSerializableObjectAttribute = nullptr;
 		mDontSerializeFieldAttribute = nullptr;
 		mDontSerializeFieldAttribute = nullptr;
@@ -344,6 +373,14 @@ namespace BansheeEngine
 		if(mSystemArrayClass == nullptr)
 		if(mSystemArrayClass == nullptr)
 			CM_EXCEPT(InvalidStateException, "Cannot find System.Array managed class.");
 			CM_EXCEPT(InvalidStateException, "Cannot find System.Array managed class.");
 
 
+		mSystemGenericListClass = mscorlib->getClass("System.Collections.Generic", "List`1");
+		if(mSystemGenericListClass == nullptr)
+			CM_EXCEPT(InvalidStateException, "Cannot find List<T> managed class.");
+
+		mSystemGenericDictionaryClass = mscorlib->getClass("System.Collections.Generic", "Dictionary`2");
+		if(mSystemGenericDictionaryClass == nullptr)
+			CM_EXCEPT(InvalidStateException, "Cannot find Dictionary<TKey, TValue> managed class.");
+
 		mSerializableObjectAttribute = bansheeEngineAssembly->getClass("BansheeEngine", "SerializableObject");
 		mSerializableObjectAttribute = bansheeEngineAssembly->getClass("BansheeEngine", "SerializableObject");
 		if(mSerializableObjectAttribute == nullptr)
 		if(mSerializableObjectAttribute == nullptr)
 			CM_EXCEPT(InvalidStateException, "Cannot find SerializableObject managed class.");
 			CM_EXCEPT(InvalidStateException, "Cannot find SerializableObject managed class.");
@@ -408,13 +445,4 @@ namespace BansheeEngine
 
 
 		return false;
 		return false;
 	}
 	}
-
-	bool RuntimeScriptObjects::isArray(MonoObject* object)
-	{
-		if(!mBaseTypesInitialized)
-			CM_EXCEPT(InvalidStateException, "Calling isArray without previously initializing base types.");
-
-		::MonoClass* monoClass = mono_object_get_class(object);
-		return mono_class_is_subclass_of(monoClass, mSystemArrayClass->_getInternalClass(), false) != 0;
-	}
 }
 }

+ 2 - 9
SBansheeEngine/Source/BsScriptSerializableArray.cpp

@@ -3,15 +3,8 @@
 #include "BsMonoManager.h"
 #include "BsMonoManager.h"
 #include "BsRuntimeScriptObjects.h"
 #include "BsRuntimeScriptObjects.h"
 #include "BsScriptSerializableField.h"
 #include "BsScriptSerializableField.h"
-
-// DEBUG ONLY
-#include "BsMonoAssembly.h"
 #include "BsMonoClass.h"
 #include "BsMonoClass.h"
 #include "BsMonoMethod.h"
 #include "BsMonoMethod.h"
-#include <mono/metadata/object.h>
-#include <mono/metadata/debug-helpers.h>
-#include <mono/metadata/metadata.h>
-#include "CmDebug.h"
 
 
 using namespace CamelotFramework;
 using namespace CamelotFramework;
 
 
@@ -24,7 +17,7 @@ namespace BansheeEngine
 	}
 	}
 
 
 	ScriptSerializableArray::ScriptSerializableArray(const ConstructPrivately& dummy, const ScriptSerializableTypeInfoArrayPtr& typeInfo, MonoObject* managedInstance)
 	ScriptSerializableArray::ScriptSerializableArray(const ConstructPrivately& dummy, const ScriptSerializableTypeInfoArrayPtr& typeInfo, MonoObject* managedInstance)
-		:mArrayTypeInfo(typeInfo), mManagedInstance(managedInstance), mNumElements(0)
+		:mArrayTypeInfo(typeInfo), mManagedInstance(managedInstance), mElemSize(0)
 	{
 	{
 		::MonoClass* monoClass = mono_object_get_class(mManagedInstance);
 		::MonoClass* monoClass = mono_object_get_class(mManagedInstance);
 		mElemSize = mono_array_element_size(monoClass);
 		mElemSize = mono_array_element_size(monoClass);
@@ -36,7 +29,7 @@ namespace BansheeEngine
 
 
 	ScriptSerializableArrayPtr ScriptSerializableArray::create(MonoObject* managedInstance, const ScriptSerializableTypeInfoArrayPtr& typeInfo)
 	ScriptSerializableArrayPtr ScriptSerializableArray::create(MonoObject* managedInstance, const ScriptSerializableTypeInfoArrayPtr& typeInfo)
 	{
 	{
-		if(!RuntimeScriptObjects::instance().isArray(managedInstance))
+		if(!RuntimeScriptObjects::instance().getSystemArrayClass()->isInstanceOfType(managedInstance))
 			return nullptr;
 			return nullptr;
 
 
 		return cm_shared_ptr<ScriptSerializableArray>(ConstructPrivately(), typeInfo, managedInstance);
 		return cm_shared_ptr<ScriptSerializableArray>(ConstructPrivately(), typeInfo, managedInstance);

+ 131 - 0
SBansheeEngine/Source/BsScriptSerializableDictionary.cpp

@@ -0,0 +1,131 @@
+#include "BsScriptSerializableDictionary.h"
+#include "BsScriptSerializableDictionaryRTTI.h"
+#include "BsMonoManager.h"
+#include "BsRuntimeScriptObjects.h"
+#include "BsScriptSerializableField.h"
+#include "BsMonoClass.h"
+#include "BsMonoMethod.h"
+
+using namespace CamelotFramework;
+
+namespace BansheeEngine
+{
+	ScriptSerializableDictionary::ScriptSerializableDictionary(const ConstructPrivately& dummy)
+		:mManagedInstance(nullptr), mNumElements(0)
+	{
+
+	}
+
+	ScriptSerializableDictionary::ScriptSerializableDictionary(const ConstructPrivately& dummy, const ScriptSerializableTypeInfoDictionaryPtr& typeInfo, MonoObject* managedInstance)
+		:mDictionaryTypeInfo(typeInfo), mManagedInstance(managedInstance), mNumElements(0)
+	{
+		mNumElements = getLength();
+	}
+
+	ScriptSerializableDictionaryPtr ScriptSerializableDictionary::create(MonoObject* managedInstance, const ScriptSerializableTypeInfoDictionaryPtr& typeInfo)
+	{
+		if(!RuntimeScriptObjects::instance().getSystemGenericDictionaryClass()->isInstanceOfType(managedInstance))
+			return nullptr;
+
+		return cm_shared_ptr<ScriptSerializableDictionary>(ConstructPrivately(), typeInfo, managedInstance);
+	}
+
+	ScriptSerializableDictionaryPtr ScriptSerializableDictionary::createEmpty()
+	{
+		return cm_shared_ptr<ScriptSerializableDictionary>(ConstructPrivately());
+	}
+
+	void ScriptSerializableDictionary::serializeManagedInstance()
+	{
+		mDictionaryEntries.resize(mNumElements * 2);
+		for(UINT32 i = 0; i < mNumElements; i++)
+		{
+			mDictionaryEntries[i] = getFieldData(i);
+		}
+	}
+
+	void ScriptSerializableDictionary::deserializeManagedInstance()
+	{
+		if(!mDictionaryTypeInfo->isTypeLoaded())
+			return;
+
+		::MonoClass* dictionaryMonoClass = mDictionaryTypeInfo->getMonoClass();
+		MonoClass* dictionaryClass = MonoManager::instance().findClass(dictionaryMonoClass);
+		if(dictionaryClass == nullptr)
+			return;
+
+		mManagedInstance = dictionaryClass->createInstance();
+		setLength(mNumElements);
+
+		CM::UINT32 idx = 0;
+		for(auto& arrayEntry : mDictionaryEntries)
+		{
+			setFieldData(idx, arrayEntry);
+			idx++;
+		}
+	}
+
+	void ScriptSerializableDictionary::setFieldData(CM::UINT32 arrayIdx, const ScriptSerializableFieldDataPtr& val)
+	{
+		if(val->isValueType())
+		{
+			if((arrayIdx % 2) == 0)
+				setValue(arrayIdx, val->getValue(mDictionaryTypeInfo->mKeyType));
+			else
+				setValue(arrayIdx, val->getValue(mDictionaryTypeInfo->mValueType));
+		}
+		else
+		{
+			MonoObject* ptrToObj = nullptr;
+			
+			if((arrayIdx % 2) == 0)
+				ptrToObj = (MonoObject*)val->getValue(mDictionaryTypeInfo->mKeyType);
+			else
+				ptrToObj = (MonoObject*)val->getValue(mDictionaryTypeInfo->mValueType);
+
+			setValue(arrayIdx, &ptrToObj);
+		}
+	}
+
+	ScriptSerializableFieldDataPtr ScriptSerializableDictionary::getFieldData(CM::UINT32 arrayIdx)
+	{
+		if((arrayIdx % 2) == 0)
+			return ScriptSerializableFieldData::create(mDictionaryTypeInfo->mKeyType, getValue(arrayIdx));
+		else
+			return ScriptSerializableFieldData::create(mDictionaryTypeInfo->mValueType, getValue(arrayIdx));
+	}
+
+	void ScriptSerializableDictionary::setValue(CM::UINT32 arrayIdx, void* val)
+	{
+		// TODO
+	}
+
+	void* ScriptSerializableDictionary::getValue(CM::UINT32 arrayIdx)
+	{
+		// TODO
+
+		return nullptr;
+	}
+
+	UINT32 ScriptSerializableDictionary::getLength() const
+	{
+		// TODO
+
+		return 0;
+	}
+
+	void ScriptSerializableDictionary::setLength(UINT32 length)
+	{
+		// TODO
+	}
+
+	RTTITypeBase* ScriptSerializableDictionary::getRTTIStatic()
+	{
+		return ScriptSerializableDictionaryRTTI::instance();
+	}
+
+	RTTITypeBase* ScriptSerializableDictionary::getRTTI() const
+	{
+		return ScriptSerializableDictionary::getRTTIStatic();
+	}
+}

+ 70 - 0
SBansheeEngine/Source/BsScriptSerializableField.cpp

@@ -11,6 +11,8 @@
 #include "BsScriptComponent.h"
 #include "BsScriptComponent.h"
 #include "BsScriptSerializableObject.h"
 #include "BsScriptSerializableObject.h"
 #include "BsScriptSerializableArray.h"
 #include "BsScriptSerializableArray.h"
+#include "BsScriptSerializableList.h"
+#include "BsScriptSerializableDictionary.h"
 
 
 using namespace CamelotFramework;
 using namespace CamelotFramework;
 
 
@@ -200,6 +202,30 @@ namespace BansheeEngine
 
 
 			return fieldData;
 			return fieldData;
 		}
 		}
+		else if(typeInfo->getTypeId() == TID_SerializableTypeInfoList)
+		{
+			MonoObject* objVal = *(MonoObject**)(value);
+
+			auto fieldData = cm_shared_ptr<ScriptSerializableFieldDataList>();
+			if(objVal != nullptr)
+			{
+				fieldData->value = ScriptSerializableList::create(objVal, std::static_pointer_cast<ScriptSerializableTypeInfoList>(typeInfo));
+			}
+
+			return fieldData;
+		}
+		else if(typeInfo->getTypeId() == TID_SerializableTypeInfoDictionary)
+		{
+			MonoObject* objVal = *(MonoObject**)(value);
+
+			auto fieldData = cm_shared_ptr<ScriptSerializableFieldDataDictionary>();
+			if(objVal != nullptr)
+			{
+				fieldData->value = ScriptSerializableDictionary::create(objVal, std::static_pointer_cast<ScriptSerializableTypeInfoDictionary>(typeInfo));
+			}
+
+			return fieldData;
+		}
 
 
 		return nullptr;
 		return nullptr;
 	}
 	}
@@ -440,6 +466,30 @@ namespace BansheeEngine
 		CM_EXCEPT(InvalidParametersException, "Requesting an invalid type in serializable field.");
 		CM_EXCEPT(InvalidParametersException, "Requesting an invalid type in serializable field.");
 	}
 	}
 
 
+	void* ScriptSerializableFieldDataList::getValue(const ScriptSerializableTypeInfoPtr& typeInfo)
+	{
+		if(typeInfo->getTypeId() == TID_SerializableTypeInfoList)
+		{
+			auto listTypeInfo = std::static_pointer_cast<ScriptSerializableTypeInfoList>(typeInfo);
+
+			return value->getManagedInstance();
+		}
+
+		CM_EXCEPT(InvalidParametersException, "Requesting an invalid type in serializable field.");
+	}
+
+	void* ScriptSerializableFieldDataDictionary::getValue(const ScriptSerializableTypeInfoPtr& typeInfo)
+	{
+		if(typeInfo->getTypeId() == TID_SerializableTypeInfoDictionary)
+		{
+			auto dictionaryTypeInfo = std::static_pointer_cast<ScriptSerializableTypeInfoDictionary>(typeInfo);
+
+			return value->getManagedInstance();
+		}
+
+		CM_EXCEPT(InvalidParametersException, "Requesting an invalid type in serializable field.");
+	}
+
 	RTTITypeBase* ScriptSerializableFieldKey::getRTTIStatic()
 	RTTITypeBase* ScriptSerializableFieldKey::getRTTIStatic()
 	{
 	{
 		return ScriptSerializableFieldKeyRTTI::instance();
 		return ScriptSerializableFieldKeyRTTI::instance();
@@ -639,4 +689,24 @@ namespace BansheeEngine
 	{
 	{
 		return ScriptSerializableFieldDataArray::getRTTIStatic();
 		return ScriptSerializableFieldDataArray::getRTTIStatic();
 	}
 	}
+
+	RTTITypeBase* ScriptSerializableFieldDataList::getRTTIStatic()
+	{
+		return ScriptSerializableFieldDataListRTTI::instance();
+	}
+
+	RTTITypeBase* ScriptSerializableFieldDataList::getRTTI() const
+	{
+		return ScriptSerializableFieldDataList::getRTTIStatic();
+	}
+
+	RTTITypeBase* ScriptSerializableFieldDataDictionary::getRTTIStatic()
+	{
+		return ScriptSerializableFieldDataDictionaryRTTI::instance();
+	}
+
+	RTTITypeBase* ScriptSerializableFieldDataDictionary::getRTTI() const
+	{
+		return ScriptSerializableFieldDataDictionary::getRTTIStatic();
+	}
 }
 }

+ 117 - 0
SBansheeEngine/Source/BsScriptSerializableList.cpp

@@ -0,0 +1,117 @@
+#include "BsScriptSerializableList.h"
+#include "BsScriptSerializableListRTTI.h"
+#include "BsMonoManager.h"
+#include "BsRuntimeScriptObjects.h"
+#include "BsScriptSerializableField.h"
+#include "BsMonoClass.h"
+#include "BsMonoMethod.h"
+
+using namespace CamelotFramework;
+
+namespace BansheeEngine
+{
+	ScriptSerializableList::ScriptSerializableList(const ConstructPrivately& dummy)
+		:mManagedInstance(nullptr), mNumElements(0)
+	{
+
+	}
+
+	ScriptSerializableList::ScriptSerializableList(const ConstructPrivately& dummy, const ScriptSerializableTypeInfoListPtr& typeInfo, MonoObject* managedInstance)
+		:mListTypeInfo(typeInfo), mManagedInstance(managedInstance), mNumElements(0)
+	{
+		mNumElements = getLength();
+	}
+
+	ScriptSerializableListPtr ScriptSerializableList::create(MonoObject* managedInstance, const ScriptSerializableTypeInfoListPtr& typeInfo)
+	{
+		if(!RuntimeScriptObjects::instance().getSystemGenericListClass()->isInstanceOfType(managedInstance))
+			return nullptr;
+
+		return cm_shared_ptr<ScriptSerializableList>(ConstructPrivately(), typeInfo, managedInstance);
+	}
+
+	ScriptSerializableListPtr ScriptSerializableList::createEmpty()
+	{
+		return cm_shared_ptr<ScriptSerializableList>(ConstructPrivately());
+	}
+
+	void ScriptSerializableList::serializeManagedInstance()
+	{
+		mListEntries.resize(mNumElements);
+		for(UINT32 i = 0; i < mNumElements; i++)
+		{
+			mListEntries[i] = getFieldData(i);
+		}
+	}
+
+	void ScriptSerializableList::deserializeManagedInstance()
+	{
+		if(!mListTypeInfo->isTypeLoaded())
+			return;
+
+		::MonoClass* listMonoClass = mListTypeInfo->getMonoClass();
+		MonoClass* listClass = MonoManager::instance().findClass(listMonoClass);
+		if(listClass == nullptr)
+			return;
+
+		mManagedInstance = listClass->createInstance();
+		setLength(mNumElements);
+
+		CM::UINT32 idx = 0;
+		for(auto& arrayEntry : mListEntries)
+		{
+			setFieldData(idx, arrayEntry);
+			idx++;
+		}
+	}
+
+	void ScriptSerializableList::setFieldData(CM::UINT32 arrayIdx, const ScriptSerializableFieldDataPtr& val)
+	{
+		if(val->isValueType())
+			setValue(arrayIdx, val->getValue(mListTypeInfo->mElementType));
+		else
+		{
+			MonoObject* ptrToObj = (MonoObject*)val->getValue(mListTypeInfo->mElementType);
+			setValue(arrayIdx, &ptrToObj);
+		}
+	}
+
+	ScriptSerializableFieldDataPtr ScriptSerializableList::getFieldData(CM::UINT32 arrayIdx)
+	{
+		return ScriptSerializableFieldData::create(mListTypeInfo->mElementType, getValue(arrayIdx));
+	}
+
+	void ScriptSerializableList::setValue(CM::UINT32 arrayIdx, void* val)
+	{
+		// TODO
+	}
+
+	void* ScriptSerializableList::getValue(CM::UINT32 arrayIdx)
+	{
+		// TODO
+		
+		return nullptr;
+	}
+
+	UINT32 ScriptSerializableList::getLength() const
+	{
+		// TODO
+		
+		return 0;
+	}
+
+	void ScriptSerializableList::setLength(UINT32 length)
+	{
+		// TODO
+	}
+
+	RTTITypeBase* ScriptSerializableList::getRTTIStatic()
+	{
+		return ScriptSerializableListRTTI::instance();
+	}
+
+	RTTITypeBase* ScriptSerializableList::getRTTI() const
+	{
+		return ScriptSerializableList::getRTTIStatic();
+	}
+}

+ 75 - 0
SBansheeEngine/Source/BsScriptSerializableObjectInfo.cpp

@@ -204,4 +204,79 @@ namespace BansheeEngine
 	{
 	{
 		return ScriptSerializableTypeInfoArray::getRTTIStatic();
 		return ScriptSerializableTypeInfoArray::getRTTIStatic();
 	}
 	}
+
+	bool ScriptSerializableTypeInfoList::matches(const ScriptSerializableTypeInfoPtr& typeInfo) const
+	{
+		if(!rtti_is_of_type<ScriptSerializableTypeInfoList>(typeInfo))
+			return false;
+
+		auto listTypeInfo = std::static_pointer_cast<ScriptSerializableTypeInfoList>(typeInfo);
+
+		return listTypeInfo->mElementType->matches(mElementType);
+	}
+
+	bool ScriptSerializableTypeInfoList::isTypeLoaded() const
+	{
+		return mElementType->isTypeLoaded();
+	}
+
+	::MonoClass* ScriptSerializableTypeInfoList::getMonoClass() const
+	{
+		::MonoClass* elementClass = mElementType->getMonoClass();
+		if(elementClass == nullptr)
+			return nullptr;
+
+		MonoClass* genericListClass = RuntimeScriptObjects::instance().getSystemGenericListClass();
+		MonoType* genParams[1] = { mono_class_get_type(elementClass) };
+
+		return mono_class_bind_generic_parameters(genericListClass->_getInternalClass(), 1, genParams, false);
+	}
+
+	RTTITypeBase* ScriptSerializableTypeInfoList::getRTTIStatic()
+	{
+		return ScriptSerializableTypeInfoListRTTI::instance();
+	}
+
+	RTTITypeBase* ScriptSerializableTypeInfoList::getRTTI() const
+	{
+		return ScriptSerializableTypeInfoList::getRTTIStatic();
+	}
+
+	bool ScriptSerializableTypeInfoDictionary::matches(const ScriptSerializableTypeInfoPtr& typeInfo) const
+	{
+		if(!rtti_is_of_type<ScriptSerializableTypeInfoDictionary>(typeInfo))
+			return false;
+
+		auto dictTypeInfo = std::static_pointer_cast<ScriptSerializableTypeInfoDictionary>(typeInfo);
+
+		return dictTypeInfo->mKeyType->matches(mKeyType) && dictTypeInfo->mValueType->matches(mValueType);
+	}
+
+	bool ScriptSerializableTypeInfoDictionary::isTypeLoaded() const
+	{
+		return mKeyType->isTypeLoaded() && mValueType->isTypeLoaded();
+	}
+
+	::MonoClass* ScriptSerializableTypeInfoDictionary::getMonoClass() const
+	{
+		::MonoClass* keyClass = mKeyType->getMonoClass();
+		::MonoClass* valueClass = mValueType->getMonoClass();
+		if(keyClass == nullptr || valueClass == nullptr)
+			return nullptr;
+
+		MonoClass* genericDictionaryClass = RuntimeScriptObjects::instance().getSystemGenericDictionaryClass();
+		MonoType* genParams[2] = { mono_class_get_type(keyClass), mono_class_get_type(valueClass) };
+
+		return mono_class_bind_generic_parameters(genericDictionaryClass->_getInternalClass(), 2, genParams, false);
+	}
+
+	RTTITypeBase* ScriptSerializableTypeInfoDictionary::getRTTIStatic()
+	{
+		return ScriptSerializableTypeInfoDictionaryRTTI::instance();
+	}
+
+	RTTITypeBase* ScriptSerializableTypeInfoDictionary::getRTTI() const
+	{
+		return ScriptSerializableTypeInfoDictionary::getRTTIStatic();
+	}
 }
 }