Просмотр исходного кода

Serializing Lists works
Added untested code for Dictionary serialization

Marko Pintera 12 лет назад
Родитель
Сommit
4c3a45ae74

+ 1 - 0
BansheeMono/Include/BsMonoClass.h

@@ -64,6 +64,7 @@ namespace BansheeEngine
 
 		MonoObject* createInstance(bool construct = true) const;
 		MonoObject* createInstance(void** params, CM::UINT32 numParams);
+		MonoObject* createInstance(const CM::String& ctorSignature, void** params);
 	private:
 		friend class MonoAssembly;
 

+ 3 - 0
BansheeMono/Include/BsMonoMethod.h

@@ -20,6 +20,8 @@ namespace BansheeEngine
 
 		CM::String getName() const;
 
+		MonoClass* getReturnType();
+
 	private:
 		friend class MonoClass;
 		friend class MonoProperty;
@@ -27,6 +29,7 @@ namespace BansheeEngine
 		MonoMethod(::MonoMethod* method);
 
 		::MonoMethod* mMethod;
+		MonoClass* mReturnType;
 		void* mThunk;
 	};
 }

+ 5 - 2
BansheeMono/Include/BsMonoProperty.h

@@ -9,7 +9,10 @@ namespace BansheeEngine
 	{
 	public:
 		MonoObject* get(MonoObject* instance) const;
-		void set(MonoObject* instance, MonoObject* value) const;
+		void set(MonoObject* instance, void* value) const;
+
+		MonoObject* getIndexed(MonoObject* instance, void* index) const;
+		void setIndexed(MonoObject* instance, void* index, void* value) const;
 
 		MonoClass* getReturnType();
 	private:
@@ -20,6 +23,6 @@ namespace BansheeEngine
 		::MonoProperty* mProperty;
 		::MonoMethod* mGetMethod;
 		::MonoMethod* mSetMethod;
-		MonoClass* mPropertyType;
+		MonoClass* mGetReturnType;
 	};
 }

+ 8 - 0
BansheeMono/Source/BsMonoClass.cpp

@@ -213,6 +213,14 @@ namespace BansheeEngine
 		return obj;
 	}
 
+	MonoObject* MonoClass::createInstance(const CM::String& ctorSignature, void** params)
+	{
+		MonoObject* obj = mono_object_new(MonoManager::instance().getDomain(), mClass);
+		getMethodExact(".ctor", ctorSignature)->invoke(obj, params);
+
+		return obj;
+	}
+
 	bool MonoClass::hasAttribute(MonoClass* monoClass) const
 	{
 		// TODO - Consider caching custom attributes or just initializing them all at load

+ 19 - 1
BansheeMono/Source/BsMonoMethod.cpp

@@ -1,11 +1,12 @@
 #include "BsMonoMethod.h"
+#include "BsMonoManager.h"
 
 using namespace CamelotFramework;
 
 namespace BansheeEngine
 {
 	MonoMethod::MonoMethod(::MonoMethod* method)
-		:mMethod(method)
+		:mMethod(method), mReturnType(nullptr)
 	{
 		mThunk = mono_method_get_unmanaged_thunk(mMethod);
 	}
@@ -24,4 +25,21 @@ namespace BansheeEngine
 	{
 		return String(mono_method_get_name(mMethod));
 	}
+
+	MonoClass* MonoMethod::getReturnType()
+	{
+		if(mReturnType != nullptr)
+			return mReturnType;
+
+		MonoType* returnType = mono_signature_get_return_type(mono_method_signature(mMethod));
+		if(returnType == nullptr)
+			return nullptr;
+
+		::MonoClass* returnClass = mono_class_from_mono_type(returnType);
+		if(returnClass == nullptr)
+			return nullptr;	
+
+		mReturnType = MonoManager::instance().findClass(returnClass);
+		return mReturnType;
+	}
 }

+ 21 - 6
BansheeMono/Source/BsMonoProperty.cpp

@@ -7,7 +7,7 @@ using namespace CamelotFramework;
 namespace BansheeEngine
 {
 	MonoProperty::MonoProperty(::MonoProperty* monoProp)
-		:mProperty(monoProp), mPropertyType(nullptr)
+		:mProperty(monoProp), mGetReturnType(nullptr)
 	{
 		mGetMethod = mono_property_get_get_method(mProperty);
 		mSetMethod = mono_property_get_set_method(mProperty);
@@ -18,17 +18,32 @@ namespace BansheeEngine
 		return mono_runtime_invoke(mGetMethod, instance, nullptr, nullptr);
 	}
 
-	void MonoProperty::set(MonoObject* instance, MonoObject* value) const
+	void MonoProperty::set(MonoObject* instance, void* value) const
 	{
 		void* args[1];
 		args[0] = value;
 		mono_runtime_invoke(mSetMethod, instance, args, nullptr);
 	}	
 
+	MonoObject* MonoProperty::getIndexed(MonoObject* instance, void* index) const
+	{
+		void* args[1];
+		args[0] = index;
+		return mono_runtime_invoke(mGetMethod, instance, args, nullptr);
+	}
+
+	void MonoProperty::setIndexed(MonoObject* instance, void* index, void* value) const
+	{
+		void* args[2];
+		args[0] = index;
+		args[1] = value;
+		mono_runtime_invoke(mSetMethod, instance, args, nullptr);
+	}	
+
 	MonoClass* MonoProperty::getReturnType()
 	{
-		if(mPropertyType != nullptr)
-			return mPropertyType;
+		if(mGetReturnType != nullptr)
+			return mGetReturnType;
 
 		MonoType* returnType = mono_signature_get_return_type(mono_method_signature(mGetMethod));
 		if(returnType == nullptr)
@@ -38,7 +53,7 @@ namespace BansheeEngine
 		if(returnClass == nullptr)
 			return nullptr;	
 
-		mPropertyType = MonoManager::instance().findClass(returnClass);
-		return mPropertyType;
+		mGetReturnType = MonoManager::instance().findClass(returnClass);
+		return mGetReturnType;
 	}
 }

+ 1 - 53
GameObjectSerialization.txt

@@ -5,51 +5,20 @@ TODO
  ---------------------------------------
 
 IMMEDIATE:
-
-Create a wrapper around MonoArray to make it easier to use?
- - With support for multirank
-Create a similar wrapper for ICollection
- - Expose mono_class_bind_generic_parameters
- - Expose mono_reflection_bind_generic_method_parameters
-   - MonoReflectionMethod->method to get MonoMethod
-
-
+Implement TODO ScriptSerializableList.cpp & ScriptSerializableDictionary.cpp methods
 setValue in ScriptSerializableObject & ScriptSerializableArray should check if value is null and if the field type isn't a value type (can't be null)
 
 LOW PRIORITY
-- Add Multi-dimensional arrays / Lists / Dictionaries
-  - (To get array lengths per rank I probably need to cast to System.Array and then call GetLength)
-  - For List/Dictionary I will probably want to do it though ICollection interface
-  - Use mono_object_get_virtual_method() to get virtual method
-  - Getting a generic type: Try mono_reflection_type_from_name
 - Ensure that unknown components retain their field data so when they are no longer unknown their data may be restored
 - Get rid of ScriptObject::createInstance and replace it with parameter in constructor
 - A way to serialize any object into a Resource (and deserialize it from Resource)
 
-----------------------------------------
-
-I attempt to resolve SceneObject handle during deserialization, while it should only be done after deserialization is done
- - Issue happens in ScriptSerializableFieldDataGameObjectRef::getValue
-
-HACKY WAY: <- THE RIGHT WAY
- - I can add a callback to GameObject that gets triggered when deserialization for a GameObject is fully done
- - Then I perform ManagedComponent deserilization there
- - SerializableSceneObject & SerializableSceneArray would have to be modified so that they don't resolve fields on deserialization
-
-In ScriptSerializableObject & ScriptSerializableArray add:
- serializeManagedInstance <- Called when serialization starts and recursively
- deserializeManagedInstance <- Called by the deserialization callback in ManagedComponent and recursively
-
  ---------------------------------------
 
  Testing:
-Test arrays
-Test arrays of arrays
 Test how structs work
 Test how things work when class gets removed
 
-Test and implement multi-rank arrays
-
  ------------------------------------------------------
  General C# component management
 
@@ -64,24 +33,3 @@ Test and implement multi-rank arrays
 TODO - When reloading scripts how to handle restoring references?
 TODO - When I destroy a Component, how will I refresh the inspector to let it know that something has changed
   - Can happen from C# and C++
-
-  -------------------------------------------------------
-
-  Other:
-  Instantiating mono generic classes: http://stackoverflow.com/questions/17628411/get-generic-type-using-mono-embedded
-
- * 		/*MonoClass* kvpClass = mscorlib->getClass("System.Collections.Generic", "KeyValuePair`2");
-*
-*		MonoType* kvpTypes[2];
-*		kvpTypes[0] = mono_class_get_type(mono_get_string_class());
-*		kvpTypes[1] = mono_class_get_type(mono_get_int32_class());
-*		::MonoClass* kvpStrIntClass = mono_class_bind_generic_parameters(kvpClass->_getInternalClass(), 2, kvpTypes, false);
-*
-*		MonoObject* kvpStrIntInstance = mono_object_new(MonoManager::instance().getDomain(), kvpStrIntClass);
-*		::MonoProperty* prop = mono_class_get_property_from_name(kvpStrIntClass, "Key");
-*
-*		int propDummy = 7;
-*		void* propParams[1] = { &propDummy };
-*		mono_property_set_value(prop, kvpStrIntInstance, propParams, nullptr);
-*
-*		int propVal = *(int*)mono_property_get_value(prop, kvpStrIntInstance, nullptr, nullptr);*/

+ 1 - 0
MBansheeEngine/DbgComponent.cs

@@ -12,5 +12,6 @@ namespace BansheeEngine
         public DbgComponent2 otherComponent;
         public SceneObject otherSO;
         public int[][][] zeArray;
+        public List<int> zeList;
     }
 }

+ 7 - 1
MBansheeEngine/Program.cs

@@ -23,6 +23,12 @@ namespace BansheeEngine
             dbgComponent.otherComponent = dbgComponent2;
             dbgComponent.otherSO = otherSO;
             dbgComponent.zeArray = new int[5][][];
+            dbgComponent.zeList = new List<int>();
+
+            dbgComponent.zeList.Add(0);
+            dbgComponent.zeList.Add(0);
+            dbgComponent.zeList.Add(99);
+            dbgComponent.zeList.Add(0);
 
             for (int i = 0; i < dbgComponent.zeArray.Length; i++)
             {
@@ -39,7 +45,7 @@ namespace BansheeEngine
             for (int i = 0; i < so.GetNumChildren(); i++)
             {
                 SceneObject childSO = so.GetChild(i);
-                reportDbgValue(childSO.GetComponent<DbgComponent>().otherComponent.a2, childSO.GetComponent<DbgComponent>().zeArray[4][1][3], typeof(DbgComponent));
+                reportDbgValue(childSO.GetComponent<DbgComponent>().zeList[2], childSO.GetComponent<DbgComponent>().zeArray[4][1][3], typeof(DbgComponent));
             }
 
             //Color newColor = Color.red;

+ 29 - 11
SBansheeEngine/Include/BsScriptSerializableDictionary.h

@@ -9,6 +9,22 @@ namespace BansheeEngine
 	class BS_SCR_BE_EXPORT ScriptSerializableDictionary : public CM::IReflectable
 	{
 	private:
+		class Enumerator
+		{
+		public:
+			Enumerator(MonoObject* instance, const ScriptSerializableDictionary* parent);
+
+			ScriptSerializableFieldDataPtr getKey() const;
+			ScriptSerializableFieldDataPtr getValue() const;
+
+			bool moveNext();
+
+		private:
+			MonoObject* mInstance;
+			MonoObject* mCurrent;
+			const ScriptSerializableDictionary* mParent;
+		};
+
 		struct ConstructPrivately {};
 
 	public:
@@ -22,10 +38,18 @@ namespace BansheeEngine
 	protected:
 		MonoObject* mManagedInstance;
 
+		MonoMethod* mAddMethod;
+		MonoMethod* mGetEnumerator;
+		MonoMethod* mEnumMoveNext;
+		MonoProperty* mEnumCurrentProp;
+		MonoProperty* mKeyProp;
+		MonoProperty* mValueProp;
+
 		ScriptSerializableTypeInfoDictionaryPtr mDictionaryTypeInfo;
-		CM::Vector<ScriptSerializableFieldDataPtr>::type mDictionaryEntries;
-		
-		CM::UINT32 mNumElements;
+		CM::Vector<ScriptSerializableFieldDataPtr>::type mKeyEntries;
+		CM::Vector<ScriptSerializableFieldDataPtr>::type mValueEntries;
+
+		void initMonoObjects(MonoClass* dictionaryClass);
 
 		/**
 		 * @brief	Populates internal field data based on currently active managed instance.
@@ -37,14 +61,8 @@ namespace BansheeEngine
 		 */
 		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);
+		void setFieldData(const ScriptSerializableFieldDataPtr& key, const ScriptSerializableFieldDataPtr& val);
+		Enumerator getEnumerator() const;
 
 		/************************************************************************/
 		/* 								RTTI		                     		*/

+ 14 - 40
SBansheeEngine/Include/BsScriptSerializableDictionaryRTTI.h

@@ -13,53 +13,27 @@ namespace BansheeEngine
 	class BS_SCR_BE_EXPORT ScriptSerializableDictionaryRTTI : public CM::RTTIType<ScriptSerializableDictionary, CM::IReflectable, ScriptSerializableDictionaryRTTI>
 	{
 	private:
-		ScriptSerializableTypeInfoDictionaryPtr getTypeInfo(ScriptSerializableDictionary* obj)
-		{
-			return obj->mDictionaryTypeInfo;
-		}
+		ScriptSerializableTypeInfoDictionaryPtr getTypeInfo(ScriptSerializableDictionary* obj) { return obj->mDictionaryTypeInfo; }
+		void setTypeInfo(ScriptSerializableDictionary* obj, ScriptSerializableTypeInfoDictionaryPtr val) { obj->mDictionaryTypeInfo = val; }
 
-		void setTypeInfo(ScriptSerializableDictionary* obj, ScriptSerializableTypeInfoDictionaryPtr val)
-		{
-			obj->mDictionaryTypeInfo = val;
-		}
+		ScriptSerializableFieldDataPtr getKeyEntry(ScriptSerializableDictionary* obj, CM::UINT32 arrayIdx) { return obj->mKeyEntries[arrayIdx]; }
+		void setKeyEntry(ScriptSerializableDictionary* obj, CM::UINT32 arrayIdx, ScriptSerializableFieldDataPtr val) { obj->mKeyEntries[arrayIdx] = val; }
+		CM::UINT32 getNumKeyEntries(ScriptSerializableDictionary* obj) { return (CM::UINT32)obj->mKeyEntries.size(); }
+		void setNumKeyEntries(ScriptSerializableDictionary* obj, CM::UINT32 numEntries) { obj->mKeyEntries.resize(numEntries); }
 
-		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);
-		}
+		ScriptSerializableFieldDataPtr getValueEntry(ScriptSerializableDictionary* obj, CM::UINT32 arrayIdx) { return obj->mKeyEntries[arrayIdx]; }
+		void setValueEntry(ScriptSerializableDictionary* obj, CM::UINT32 arrayIdx, ScriptSerializableFieldDataPtr val) { obj->mKeyEntries[arrayIdx] = val; }
+		CM::UINT32 getNumValueEntries(ScriptSerializableDictionary* obj) { return (CM::UINT32)obj->mKeyEntries.size(); }
+		void setNumValueEntries(ScriptSerializableDictionary* obj, CM::UINT32 numEntries) { obj->mKeyEntries.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);
+			addReflectablePtrArrayField("mKeyEntries", 1, &ScriptSerializableDictionaryRTTI::getKeyEntry, &ScriptSerializableDictionaryRTTI::getNumKeyEntries, 
+				&ScriptSerializableDictionaryRTTI::setKeyEntry, &ScriptSerializableDictionaryRTTI::setNumKeyEntries);
+			addReflectablePtrArrayField("mValueEntries", 2, &ScriptSerializableDictionaryRTTI::getValueEntry, &ScriptSerializableDictionaryRTTI::getNumValueEntries, 
+				&ScriptSerializableDictionaryRTTI::setValueEntry, &ScriptSerializableDictionaryRTTI::setNumValueEntries);
 		}
 
 		virtual void onSerializationStarted(CM::IReflectable* obj)

+ 7 - 4
SBansheeEngine/Include/BsScriptSerializableList.h

@@ -22,11 +22,17 @@ namespace BansheeEngine
 	protected:
 		MonoObject* mManagedInstance;
 
+		MonoMethod* mAddMethod;
+		MonoProperty* mItemProp;
+		MonoProperty* mCountProp;
+
 		ScriptSerializableTypeInfoListPtr mListTypeInfo;
 		CM::Vector<ScriptSerializableFieldDataPtr>::type mListEntries;
 		
 		CM::UINT32 mNumElements;
 
+		void initMonoObjects(MonoClass* listClass);
+
 		/**
 		 * @brief	Populates internal field data based on currently active managed instance.
 		 */
@@ -38,13 +44,10 @@ namespace BansheeEngine
 		void deserializeManagedInstance();
 
 		void setFieldData(CM::UINT32 arrayIdx, const ScriptSerializableFieldDataPtr& val);
+		void addFieldData(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		                     		*/

+ 30 - 28
SBansheeEngine/Source/BsRuntimeScriptObjects.cpp

@@ -258,10 +258,37 @@ namespace BansheeEngine
 				typeInfo->mType = ScriptPrimitiveType::ComponentRef;
 				return typeInfo;
 			}
-			else if(monoClass->isSubClassOf(mSystemGenericListClass))
+			else
+			{
+				if(hasSerializableObjectInfo(monoClass->getNamespace(), monoClass->getTypeName()))
+				{
+					std::shared_ptr<ScriptSerializableTypeInfoObject> typeInfo = cm_shared_ptr<ScriptSerializableTypeInfoObject>();
+					typeInfo->mTypeNamespace = monoClass->getNamespace();
+					typeInfo->mTypeName = monoClass->getTypeName();
+					typeInfo->mValueType = false;
+
+					return typeInfo;
+				}
+			}
+
+			break;
+		case MONO_TYPE_VALUETYPE:
+			if(hasSerializableObjectInfo(monoClass->getNamespace(), monoClass->getTypeName()))
+			{
+				std::shared_ptr<ScriptSerializableTypeInfoObject> typeInfo = cm_shared_ptr<ScriptSerializableTypeInfoObject>();
+				typeInfo->mTypeNamespace = monoClass->getNamespace();
+				typeInfo->mTypeName = monoClass->getTypeName();
+				typeInfo->mValueType = true;
+
+				return typeInfo;
+			}
+
+			break;
+		case MONO_TYPE_GENERICINST:
+			if(monoClass->getFullName() == mSystemGenericListClass->getFullName()) // Full name is part of CIL spec, so it is just fine to compare like this
 			{
 				std::shared_ptr<ScriptSerializableTypeInfoList> typeInfo = cm_shared_ptr<ScriptSerializableTypeInfoList>();
-				
+
 				MonoProperty& itemProperty = monoClass->getProperty("Item");
 				MonoClass* itemClass = itemProperty.getReturnType();
 
@@ -270,7 +297,7 @@ namespace BansheeEngine
 
 				return typeInfo;
 			}
-			else if(monoClass->isSubClassOf(mSystemGenericDictionaryClass))
+			else if(monoClass->getFullName() == mSystemGenericDictionaryClass->getFullName())
 			{
 				std::shared_ptr<ScriptSerializableTypeInfoDictionary> typeInfo = cm_shared_ptr<ScriptSerializableTypeInfoDictionary>();
 
@@ -287,31 +314,6 @@ namespace BansheeEngine
 
 				return typeInfo;
 			}
-			else
-			{
-				if(hasSerializableObjectInfo(monoClass->getNamespace(), monoClass->getTypeName()))
-				{
-					std::shared_ptr<ScriptSerializableTypeInfoObject> typeInfo = cm_shared_ptr<ScriptSerializableTypeInfoObject>();
-					typeInfo->mTypeNamespace = monoClass->getNamespace();
-					typeInfo->mTypeName = monoClass->getTypeName();
-					typeInfo->mValueType = false;
-
-					return typeInfo;
-				}
-			}
-
-			break;
-		case MONO_TYPE_VALUETYPE:
-			if(hasSerializableObjectInfo(monoClass->getNamespace(), monoClass->getTypeName()))
-			{
-				std::shared_ptr<ScriptSerializableTypeInfoObject> typeInfo = cm_shared_ptr<ScriptSerializableTypeInfoObject>();
-				typeInfo->mTypeNamespace = monoClass->getNamespace();
-				typeInfo->mTypeName = monoClass->getTypeName();
-				typeInfo->mValueType = true;
-
-				return typeInfo;
-			}
-
 			break;
 		case MONO_TYPE_SZARRAY:
 		case MONO_TYPE_ARRAY:

+ 3 - 0
SBansheeEngine/Source/BsScriptSerializableArray.cpp

@@ -29,6 +29,9 @@ namespace BansheeEngine
 
 	ScriptSerializableArrayPtr ScriptSerializableArray::create(MonoObject* managedInstance, const ScriptSerializableTypeInfoArrayPtr& typeInfo)
 	{
+		if(managedInstance == nullptr)
+			return nullptr;
+
 		if(!RuntimeScriptObjects::instance().getSystemArrayClass()->isInstanceOfType(managedInstance))
 			return nullptr;
 

+ 82 - 53
SBansheeEngine/Source/BsScriptSerializableDictionary.cpp

@@ -5,26 +5,66 @@
 #include "BsScriptSerializableField.h"
 #include "BsMonoClass.h"
 #include "BsMonoMethod.h"
+#include "BsMonoProperty.h"
 
 using namespace CamelotFramework;
 
 namespace BansheeEngine
 {
-	ScriptSerializableDictionary::ScriptSerializableDictionary(const ConstructPrivately& dummy)
-		:mManagedInstance(nullptr), mNumElements(0)
+	ScriptSerializableDictionary::Enumerator::Enumerator(MonoObject* instance, const ScriptSerializableDictionary* parent)
+		:mInstance(instance), mParent(parent), mCurrent(nullptr)
+	{ }
+
+	ScriptSerializableFieldDataPtr ScriptSerializableDictionary::Enumerator::getKey() const
+	{
+		MonoObject* obj = mParent->mKeyProp->get(mCurrent);
+
+		if(mono_class_is_valuetype(mono_object_get_class(obj)))
+			return ScriptSerializableFieldData::create(mParent->mDictionaryTypeInfo->mKeyType, mono_object_unbox(obj));
+		else
+			return ScriptSerializableFieldData::create(mParent->mDictionaryTypeInfo->mKeyType, obj);
+	}
+
+	ScriptSerializableFieldDataPtr ScriptSerializableDictionary::Enumerator::getValue() const
 	{
+		MonoObject* obj = mParent->mValueProp->get(mCurrent);
 
+		if(mono_class_is_valuetype(mono_object_get_class(obj)))
+			return ScriptSerializableFieldData::create(mParent->mDictionaryTypeInfo->mValueType, mono_object_unbox(obj));
+		else
+			return ScriptSerializableFieldData::create(mParent->mDictionaryTypeInfo->mValueType, obj);
 	}
 
+	bool ScriptSerializableDictionary::Enumerator::moveNext()
+	{
+		mCurrent = mParent->mEnumMoveNext->invoke(mInstance, nullptr);
+
+		return mCurrent != nullptr;
+	}
+
+	ScriptSerializableDictionary::ScriptSerializableDictionary(const ConstructPrivately& dummy)
+		:mManagedInstance(nullptr), mAddMethod(nullptr), mGetEnumerator(nullptr), mEnumMoveNext(nullptr),
+		mEnumCurrentProp(nullptr), mKeyProp(nullptr), mValueProp(nullptr)
+	{ }
+
 	ScriptSerializableDictionary::ScriptSerializableDictionary(const ConstructPrivately& dummy, const ScriptSerializableTypeInfoDictionaryPtr& typeInfo, MonoObject* managedInstance)
-		:mDictionaryTypeInfo(typeInfo), mManagedInstance(managedInstance), mNumElements(0)
+		:mDictionaryTypeInfo(typeInfo), mManagedInstance(managedInstance), mAddMethod(nullptr), mGetEnumerator(nullptr), mEnumMoveNext(nullptr),
+		mEnumCurrentProp(nullptr), mKeyProp(nullptr), mValueProp(nullptr)
 	{
-		mNumElements = getLength();
+
 	}
 
 	ScriptSerializableDictionaryPtr ScriptSerializableDictionary::create(MonoObject* managedInstance, const ScriptSerializableTypeInfoDictionaryPtr& typeInfo)
 	{
-		if(!RuntimeScriptObjects::instance().getSystemGenericDictionaryClass()->isInstanceOfType(managedInstance))
+		if(managedInstance == nullptr)
+			return nullptr;
+
+		::MonoClass* monoClass = mono_object_get_class(managedInstance);
+		String elementNs = mono_class_get_namespace(monoClass);
+		String elementTypeName = mono_class_get_name(monoClass);
+		String fullName = elementNs + "." + elementTypeName;
+
+		if(RuntimeScriptObjects::instance().getSystemGenericDictionaryClass()->getFullName() != fullName)
 			return nullptr;
 
 		return cm_shared_ptr<ScriptSerializableDictionary>(ConstructPrivately(), typeInfo, managedInstance);
@@ -37,10 +77,21 @@ namespace BansheeEngine
 
 	void ScriptSerializableDictionary::serializeManagedInstance()
 	{
-		mDictionaryEntries.resize(mNumElements * 2);
-		for(UINT32 i = 0; i < mNumElements; i++)
+		MonoClass* dictionaryClass = MonoManager::instance().findClass(mono_object_get_class(mManagedInstance));
+		if(dictionaryClass == nullptr)
+			return;
+
+		initMonoObjects(dictionaryClass);
+
+		mKeyEntries.clear();
+		mValueEntries.clear();
+
+		Enumerator enumerator = getEnumerator();
+
+		while(enumerator.moveNext())
 		{
-			mDictionaryEntries[i] = getFieldData(i);
+			mKeyEntries.push_back(enumerator.getKey());
+			mValueEntries.push_back(enumerator.getValue());
 		}
 	}
 
@@ -54,69 +105,47 @@ namespace BansheeEngine
 		if(dictionaryClass == nullptr)
 			return;
 
+		initMonoObjects(dictionaryClass);
+
 		mManagedInstance = dictionaryClass->createInstance();
-		setLength(mNumElements);
+		assert(mKeyEntries.size() == mValueEntries.size());
 
-		CM::UINT32 idx = 0;
-		for(auto& arrayEntry : mDictionaryEntries)
+		for(UINT32 i = 0; i < (UINT32)mKeyEntries.size(); i++)
 		{
-			setFieldData(idx, arrayEntry);
-			idx++;
+			setFieldData(mKeyEntries[i], mValueEntries[i]);
 		}
 	}
 
-	void ScriptSerializableDictionary::setFieldData(CM::UINT32 arrayIdx, const ScriptSerializableFieldDataPtr& val)
+	void ScriptSerializableDictionary::setFieldData(const ScriptSerializableFieldDataPtr& key, 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);
-		}
-	}
+		void* params[2];
+		params[0] = key->getValue(mDictionaryTypeInfo->mKeyType);
+		params[1] = val->getValue(mDictionaryTypeInfo->mValueType);
 
-	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));
+		mAddMethod->invoke(mManagedInstance, params);
 	}
 
-	void ScriptSerializableDictionary::setValue(CM::UINT32 arrayIdx, void* val)
+	ScriptSerializableDictionary::Enumerator ScriptSerializableDictionary::getEnumerator() const
 	{
-		// TODO
+		return Enumerator(mGetEnumerator->invoke(mManagedInstance, nullptr), this);
 	}
 
-	void* ScriptSerializableDictionary::getValue(CM::UINT32 arrayIdx)
+	void ScriptSerializableDictionary::initMonoObjects(MonoClass* dictionaryClass)
 	{
-		// TODO
+		mAddMethod = &dictionaryClass->getMethod("Add", 2);
+		mGetEnumerator = &dictionaryClass->getMethod("GetEnumerator");
 
-		return nullptr;
-	}
+		MonoClass* enumeratorClass = mGetEnumerator->getReturnType();
+		assert(enumeratorClass != nullptr);
 
-	UINT32 ScriptSerializableDictionary::getLength() const
-	{
-		// TODO
+		mEnumMoveNext = &enumeratorClass->getMethod("MoveNext");
+		mEnumCurrentProp = &enumeratorClass->getProperty("Current");
 
-		return 0;
-	}
+		MonoClass* keyValuePairClass = mEnumCurrentProp->getReturnType();
+		assert(keyValuePairClass != nullptr);
 
-	void ScriptSerializableDictionary::setLength(UINT32 length)
-	{
-		// TODO
+		mKeyProp = &keyValuePairClass->getProperty("Key");
+		mValueProp = &keyValuePairClass->getProperty("Value");
 	}
 
 	RTTITypeBase* ScriptSerializableDictionary::getRTTIStatic()

+ 47 - 30
SBansheeEngine/Source/BsScriptSerializableList.cpp

@@ -5,26 +5,42 @@
 #include "BsScriptSerializableField.h"
 #include "BsMonoClass.h"
 #include "BsMonoMethod.h"
+#include "BsMonoProperty.h"
 
 using namespace CamelotFramework;
 
 namespace BansheeEngine
 {
 	ScriptSerializableList::ScriptSerializableList(const ConstructPrivately& dummy)
-		:mManagedInstance(nullptr), mNumElements(0)
+		:mManagedInstance(nullptr), mNumElements(0), mItemProp(nullptr), mCountProp(nullptr), mAddMethod(nullptr)
 	{
 
 	}
 
 	ScriptSerializableList::ScriptSerializableList(const ConstructPrivately& dummy, const ScriptSerializableTypeInfoListPtr& typeInfo, MonoObject* managedInstance)
-		:mListTypeInfo(typeInfo), mManagedInstance(managedInstance), mNumElements(0)
+		:mListTypeInfo(typeInfo), mManagedInstance(managedInstance), mNumElements(0), mItemProp(nullptr),
+		mCountProp(nullptr), mAddMethod(nullptr)
 	{
+		MonoClass* listClass = MonoManager::instance().findClass(mono_object_get_class(managedInstance));
+		if(listClass == nullptr)
+			return;
+
+		initMonoObjects(listClass);
+
 		mNumElements = getLength();
 	}
 
 	ScriptSerializableListPtr ScriptSerializableList::create(MonoObject* managedInstance, const ScriptSerializableTypeInfoListPtr& typeInfo)
 	{
-		if(!RuntimeScriptObjects::instance().getSystemGenericListClass()->isInstanceOfType(managedInstance))
+		if(managedInstance == nullptr)
+			return nullptr;
+
+		::MonoClass* monoClass = mono_object_get_class(managedInstance);
+		String elementNs = mono_class_get_namespace(monoClass);
+		String elementTypeName = mono_class_get_name(monoClass);
+		String fullName = elementNs + "." + elementTypeName;
+
+		if(RuntimeScriptObjects::instance().getSystemGenericListClass()->getFullName() != fullName)
 			return nullptr;
 
 		return cm_shared_ptr<ScriptSerializableList>(ConstructPrivately(), typeInfo, managedInstance);
@@ -54,55 +70,56 @@ namespace BansheeEngine
 		if(listClass == nullptr)
 			return;
 
-		mManagedInstance = listClass->createInstance();
-		setLength(mNumElements);
+		initMonoObjects(listClass);
+
+		void* params[1] = { &mNumElements };
+		mManagedInstance = listClass->createInstance("int", params);
 
-		CM::UINT32 idx = 0;
 		for(auto& arrayEntry : mListEntries)
 		{
-			setFieldData(idx, arrayEntry);
-			idx++;
+			addFieldData(arrayEntry);
 		}
 	}
 
 	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);
-		}
+		mItemProp->setIndexed(mManagedInstance, &arrayIdx, val->getValue(mListTypeInfo->mElementType));
 	}
 
-	ScriptSerializableFieldDataPtr ScriptSerializableList::getFieldData(CM::UINT32 arrayIdx)
-	{
-		return ScriptSerializableFieldData::create(mListTypeInfo->mElementType, getValue(arrayIdx));
-	}
 
-	void ScriptSerializableList::setValue(CM::UINT32 arrayIdx, void* val)
+	void ScriptSerializableList::addFieldData(const ScriptSerializableFieldDataPtr& val)
 	{
-		// TODO
+		void* params[1];
+		params[0] = val->getValue(mListTypeInfo->mElementType);
+
+		mAddMethod->invoke(mManagedInstance, params);
 	}
 
-	void* ScriptSerializableList::getValue(CM::UINT32 arrayIdx)
+	ScriptSerializableFieldDataPtr ScriptSerializableList::getFieldData(CM::UINT32 arrayIdx)
 	{
-		// TODO
-		
-		return nullptr;
+		MonoObject* obj = mItemProp->getIndexed(mManagedInstance, &arrayIdx);
+
+		if(mono_class_is_valuetype(mono_object_get_class(obj)))
+			return ScriptSerializableFieldData::create(mListTypeInfo->mElementType, mono_object_unbox(obj));
+		else
+			return ScriptSerializableFieldData::create(mListTypeInfo->mElementType, obj);
 	}
 
 	UINT32 ScriptSerializableList::getLength() const
 	{
-		// TODO
-		
-		return 0;
+		MonoObject* length = mCountProp->get(mManagedInstance);
+
+		if(length == nullptr)
+			return 0;
+
+		return *(UINT32*)mono_object_unbox(length);
 	}
 
-	void ScriptSerializableList::setLength(UINT32 length)
+	void ScriptSerializableList::initMonoObjects(MonoClass* listClass)
 	{
-		// TODO
+		mItemProp = &listClass->getProperty("Item");
+		mCountProp = &listClass->getProperty("Count");
+		mAddMethod = &listClass->getMethod("Add", 1);
 	}
 
 	RTTITypeBase* ScriptSerializableList::getRTTIStatic()

+ 3 - 0
SBansheeEngine/Source/BsScriptSerializableObject.cpp

@@ -23,6 +23,9 @@ namespace BansheeEngine
 
 	ScriptSerializableObjectPtr ScriptSerializableObject::create(MonoObject* managedInstance)
 	{
+		if(managedInstance == nullptr)
+			return nullptr;
+
 		::MonoClass* monoClass = mono_object_get_class(managedInstance);
 		String elementNs = mono_class_get_namespace(monoClass);
 		String elementTypeName = mono_class_get_name(monoClass);