Bläddra i källkod

Added clone method to SerializedProperty (untested)
Added range to int fields

Marko Pintera 11 år sedan
förälder
incheckning
5796d726b7
27 ändrade filer med 633 tillägg och 94 borttagningar
  1. 33 33
      BansheeCore/Include/BsCoreThread.h
  2. 3 0
      BansheeEditor/Include/BsGUIIntField.h
  3. 10 1
      BansheeEditor/Source/BsGUIIntField.cpp
  4. 6 3
      Inspector.txt
  5. 8 0
      MBansheeEditor/GUI/GUIIntField.cs
  6. 147 5
      MBansheeEditor/Inspector/InspectableArray.cs
  7. 33 0
      MBansheeEngine/SerializableProperty.cs
  8. 1 0
      SBansheeEditor/Include/BsScriptGUIIntField.h
  9. 8 0
      SBansheeEditor/Source/BsScriptGUIIntField.cpp
  10. 1 1
      SBansheeEngine/Include/BsManagedComponentRTTI.h
  11. 1 1
      SBansheeEngine/Include/BsManagedResourceRTTI.h
  12. 4 2
      SBansheeEngine/Include/BsManagedSerializableArray.h
  13. 1 1
      SBansheeEngine/Include/BsManagedSerializableArrayRTTI.h
  14. 3 1
      SBansheeEngine/Include/BsManagedSerializableDictionary.h
  15. 20 0
      SBansheeEngine/Include/BsManagedSerializableField.h
  16. 3 1
      SBansheeEngine/Include/BsManagedSerializableList.h
  17. 3 1
      SBansheeEngine/Include/BsManagedSerializableObject.h
  18. 1 1
      SBansheeEngine/Include/BsManagedSerializableObjectInfo.h
  19. 2 2
      SBansheeEngine/Include/BsManagedSerializableObjectInfoRTTI.h
  20. 1 1
      SBansheeEngine/Include/BsScriptEnginePrerequisites.h
  21. 5 0
      SBansheeEngine/Include/BsScriptSerializableProperty.h
  22. 32 18
      SBansheeEngine/Source/BsManagedSerializableArray.cpp
  23. 22 4
      SBansheeEngine/Source/BsManagedSerializableDictionary.cpp
  24. 193 4
      SBansheeEngine/Source/BsManagedSerializableField.cpp
  25. 23 9
      SBansheeEngine/Source/BsManagedSerializableList.cpp
  26. 30 5
      SBansheeEngine/Source/BsManagedSerializableObject.cpp
  27. 39 0
      SBansheeEngine/Source/BsScriptSerializableProperty.cpp

+ 33 - 33
BansheeCore/Include/BsCoreThread.h

@@ -37,30 +37,30 @@ public:
 	BS_CORE_EXPORT ~CoreThread();
 
 	/**
-		* @brief	Returns the id of the core thread. 
-		*/
+	 * @brief	Returns the id of the core thread. 
+	 */
 	BS_CORE_EXPORT BS_THREAD_ID_TYPE getCoreThreadId() { return mCoreThreadId; }
 
 	/**
-		* @brief	Creates or retrieves an accessor that you can use for executing commands on the core thread from 
-		* 			a non-core thread. The accessor will be bound to the thread you call this method on.
-		* 			
-		* @note		Accessors contain their own command queue and their commands will only start to get executed once that queue is submitted
-		* 			to the core thread via "submitAccessors" method.
-		*/
+	 * @brief	Creates or retrieves an accessor that you can use for executing commands on the core thread from 
+	 * 			a non-core thread. The accessor will be bound to the thread you call this method on.
+	 * 			
+	 * @note		Accessors contain their own command queue and their commands will only start to get executed once that queue is submitted
+	 * 			to the core thread via "submitAccessors" method.
+	 */
 	BS_CORE_EXPORT CoreAccessorPtr getAccessor();
 
 	/**
-	* @brief	Retrieves an accessor that you can use for executing commands on the core thread from
-	* 			a non-core thread. There is only one synchronized accessor and you may access it from any thread you wish.
-	* 			Note however that it is much more efficient to retrieve a separate non-synchronized accessor using
-	* 			"getAccessor" for each thread you will be using it on.
-	* 			
-	* @note		Accessors contain their own command queue and their commands will only start to get executed once that queue is submitted
-	* 			to the core thread via "submitAccessors" method.
-	* 			
-	*			Synced accessor commands are sent after all non-synced accessor commands are sent.
-	*/
+	 * @brief	Retrieves an accessor that you can use for executing commands on the core thread from
+	 * 			a non-core thread. There is only one synchronized accessor and you may access it from any thread you wish.
+	 * 			Note however that it is much more efficient to retrieve a separate non-synchronized accessor using
+	 * 			"getAccessor" for each thread you will be using it on.
+	 * 			
+	 * @note		Accessors contain their own command queue and their commands will only start to get executed once that queue is submitted
+	 * 			to the core thread via "submitAccessors" method.
+	 * 			
+	 *			Synced accessor commands are sent after all non-synced accessor commands are sent.
+	 */
 	BS_CORE_EXPORT SyncedCoreAccessor& getSyncedAccessor();
 
 	/**
@@ -69,24 +69,24 @@ public:
 	BS_CORE_EXPORT void submitAccessors(bool blockUntilComplete = false);
 
 	/**
-		* @brief	Queues a new command that will be added to the global command queue. You are allowed to call this from any thread,
-		* 			however be aware that it involves possibly slow synchronization primitives, so limit your usage.
-		* 			
-		* @param	blockUntilComplete If true the thread will be blocked until the command executes. Be aware that there may be many commands queued before it
-		* 							   and they all need to be executed in order before the current command is reached, which might take a long time.
-		* 	
-		* @see		CommandQueue::queueReturn
-		*/
+	 * @brief	Queues a new command that will be added to the global command queue. You are allowed to call this from any thread,
+	 * 			however be aware that it involves possibly slow synchronization primitives, so limit your usage.
+	 * 			
+	 * @param	blockUntilComplete If true the thread will be blocked until the command executes. Be aware that there may be many commands queued before it
+	 * 							   and they all need to be executed in order before the current command is reached, which might take a long time.
+	 * 	
+	 * @see		CommandQueue::queueReturn
+	 */
 	BS_CORE_EXPORT AsyncOp queueReturnCommand(std::function<void(AsyncOp&)> commandCallback, bool blockUntilComplete = false);
 
 	/**
-	* @brief	Queues a new command that will be added to the global command queue.You are allowed to call this from any thread,
-		* 			however be aware that it involves possibly slow synchronization primitives, so limit your usage.
-		* 	
-		* @param	blockUntilComplete If true the thread will be blocked until the command executes. Be aware that there may be many commands queued before it
-		* 							   and they all need to be executed in order before the current command is reached, which might take a long time.
-		* @see		CommandQueue::queue
-		*/
+	 * @brief	Queues a new command that will be added to the global command queue.You are allowed to call this from any thread,
+	 * 			however be aware that it involves possibly slow synchronization primitives, so limit your usage.
+	 * 	
+	 * @param	blockUntilComplete If true the thread will be blocked until the command executes. Be aware that there may be many commands queued before it
+	 * 							   and they all need to be executed in order before the current command is reached, which might take a long time.
+	 * @see		CommandQueue::queue
+	 */
 	BS_CORE_EXPORT void queueCommand(std::function<void()> commandCallback, bool blockUntilComplete = false);
 
 	/**

+ 3 - 0
BansheeEditor/Include/BsGUIIntField.h

@@ -16,6 +16,7 @@ namespace BansheeEngine
 
 		INT32 getValue() const { return mValue; }
 		void setValue(INT32 value);
+		void setRange(INT32 min, INT32 max);
 
 		bool hasInputFocus() const { return mHasInputFocus; }
 
@@ -40,6 +41,8 @@ namespace BansheeEngine
 		GUIInputBox* mInputBox;
 		INT32 mValue;
 		INT32 mLastDragPos;
+		INT32 mMinValue;
+		INT32 mMaxValue;
 		bool mIsDragging;
 		bool mIsDragCursorSet;
 		bool mHasInputFocus;

+ 10 - 1
BansheeEditor/Source/BsGUIIntField.cpp

@@ -23,7 +23,8 @@ namespace BansheeEngine
 	GUIIntField::GUIIntField(const PrivatelyConstruct& dummy, const GUIContent& labelContent, UINT32 labelWidth,
 		const String& style, const GUILayoutOptions& layoutOptions, bool withLabel)
 		:TGUIField(dummy, labelContent, labelWidth, style, layoutOptions, withLabel), mInputBox(nullptr), mIsDragging(false),
-		mLastDragPos(0), mIsDragCursorSet(false), mHasInputFocus(false)
+		mLastDragPos(0), mIsDragCursorSet(false), mHasInputFocus(false), mMinValue(std::numeric_limits<INT32>::lowest()), 
+		mMaxValue(std::numeric_limits<INT32>::max())
 	{
 		mInputBox = GUIInputBox::create(false, GUIOptions(GUIOption::flexibleWidth()), getSubStyleName(getInputStyleType()));
 		mInputBox->setFilter(&GUIIntField::intFilter);
@@ -149,10 +150,18 @@ namespace BansheeEngine
 
 	void GUIIntField::setValue(INT32 value)
 	{
+		value = Math::clamp(value, mMinValue, mMaxValue);
+
 		mValue = value;
 		mInputBox->setText(toWString(value));
 	}
 
+	void GUIIntField::setRange(INT32 min, INT32 max)
+	{
+		mMinValue = min;
+		mMaxValue = max;
+	}
+
 	void GUIIntField::updateClippedBounds()
 	{
 		Vector2I offset = _getOffset();

+ 6 - 3
Inspector.txt

@@ -18,10 +18,10 @@ ARRAY TODO:
  - Add Delete/Clone/MoveUp/MoveDown buttons
  - Ensure that case when array is null is handled properly. Will likely need a [Create] button
  - Need a GUIFoldout that doesn't have BG and is just a single button.
+ - Add IntField that has min/max limits so it cannot go below 0 for array size
 
-Inspectable Refresh/Refactor TODO:
-Parent layout element destruction should be automatic
-Child Inspectable element destruction should also probably be automatic
+Need code for cloning an array element (or pretty much any element)
+Hook up array buttons
 
 TODO:
  - Hook up int field set/get callbacks
@@ -88,6 +88,9 @@ KEEP IN MIND:
 
 ----------------------------------------------
 
+Various trivial fixes:
+ - Add icons to array clone/delete/up/down buttons
+
 LATER:
  - Add support for list, dictionary and multi-rank array types
  - Add tabbing between fields

+ 8 - 0
MBansheeEditor/GUI/GUIIntField.cs

@@ -39,6 +39,11 @@ namespace BansheeEditor
             return value;
         }
 
+        public void SetRange(int min, int max)
+        {
+            Internal_SetRange(mCachedPtr, min, max);
+        }
+
         private void DoOnChanged(int newValue)
         {
             if (OnChanged != null)
@@ -57,5 +62,8 @@ namespace BansheeEditor
 
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern void Internal_HasInputFocus(IntPtr nativeInstance, out bool value);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetRange(IntPtr nativeInstance, int min, int max);
     }
 }

+ 147 - 5
MBansheeEditor/Inspector/InspectableArray.cs

@@ -9,14 +9,56 @@ namespace BansheeEditor
 {
     public class InspectableArray : InspectableObjectBase
     {
+        private class EntryRow
+        {
+            public GUILayoutX rowLayout;
+            public GUILayoutY contentLayout;
+            public GUIButton cloneBtn;
+            public GUIButton deleteBtn;
+            public GUIButton moveUpBtn;
+            public GUIButton moveDownBtn;
+
+            public EntryRow(GUILayout parentLayout)
+            {
+                rowLayout = parentLayout.AddLayoutX();
+                contentLayout = rowLayout.AddLayoutY();
+                cloneBtn = new GUIButton("C");
+                deleteBtn = new GUIButton("X");
+                moveUpBtn = new GUIButton("Up");
+                moveDownBtn = new GUIButton("Down");
+
+                rowLayout.AddElement(cloneBtn);
+                rowLayout.AddElement(deleteBtn);
+                rowLayout.AddElement(moveUpBtn);
+                rowLayout.AddElement(moveDownBtn);
+            }
+
+            public void Destroy()
+            {
+                rowLayout.Destroy();
+                contentLayout.Destroy();
+                cloneBtn.Destroy();
+                deleteBtn.Destroy();
+                moveUpBtn.Destroy();
+                moveDownBtn.Destroy();
+            }
+        }
+
         private const int IndentAmount = 15;
 
         private object oldPropertyValue; // TODO - This will unnecessarily hold references to the object
         private int numArrayElements;
 
         private GUILabel guiLabel;
+        private GUIIntField guiSizeField;
+        private GUIButton guiResizeBtn;
+
+        private GUILayout guiTitleLayout;
         private GUILayout guiChildLayout;
         private GUILayoutY guiContentLayout;
+
+        private List<EntryRow> rows = new List<EntryRow>();
+
         private bool isInitialized;
 
         public InspectableArray(string title, InspectableFieldLayout layout, SerializableProperty property)
@@ -31,7 +73,15 @@ namespace BansheeEditor
                 return;
 
             guiLabel = new GUILabel(title); // TODO - Add foldout and hook up its callbacks
-            layout.AddElement(layoutIndex, guiLabel);
+            guiSizeField = new GUIIntField();
+            guiSizeField.SetRange(0, int.MaxValue);
+            guiResizeBtn = new GUIButton("Resize");
+            guiResizeBtn.OnClick += OnResizeButtonClicked;
+
+            guiTitleLayout = layout.AddLayoutX(layoutIndex);
+            guiTitleLayout.AddElement(guiLabel);
+            guiTitleLayout.AddElement(guiSizeField);
+            guiTitleLayout.AddElement(guiResizeBtn);
 
             guiChildLayout = layout.AddLayoutX(layoutIndex);
 
@@ -68,17 +118,109 @@ namespace BansheeEditor
             if (!isInitialized)
                 Initialize(layoutIndex);
 
+            foreach (var row in rows)
+                row.Destroy();
+
+            rows.Clear();
+
             SerializableArray array = property.GetArray();
 
-            int childLayoutIndex = 0;
             numArrayElements = array.GetLength();
             for (int i = 0; i < numArrayElements; i++)
             {
-                InspectableObjectBase childObj = CreateDefaultInspectable(i + ".", new InspectableFieldLayout(guiContentLayout), array.GetProperty(i));
+                EntryRow newRow = new EntryRow(guiContentLayout);
+                rows.Add(newRow);
+
+                InspectableObjectBase childObj = CreateDefaultInspectable(i + ".", new InspectableFieldLayout(newRow.contentLayout), array.GetProperty(i));
                 AddChild(childObj);
 
-                childObj.Refresh(childLayoutIndex);
-                childLayoutIndex += childObj.GetNumLayoutElements();
+                childObj.Refresh(0);
+            }
+        }
+
+        private void OnResizeButtonClicked()
+        {
+            int size = guiSizeField.Value; // TODO - Support multi-rank arrays
+
+            Array newArray = property.CreateArrayInstance(new int[] {size});
+            SerializableArray array = property.GetArray();
+
+            int maxSize = MathEx.Min(size, array.GetLength());
+
+            for (int i = 0; i < maxSize; i++)
+                newArray.SetValue(array.GetProperty(i).GetValue<object>(), i);
+
+            property.SetValue(newArray);
+        }
+
+        private void OnDeleteButtonClicked(int index)
+        {
+            SerializableArray array = property.GetArray();
+
+            int size = MathEx.Max(0, array.GetLength() - 1);
+            Array newArray = property.CreateArrayInstance(new int[] { size });
+
+            int destIdx = 0;
+            for (int i = 0; i < array.GetLength(); i++)
+            {
+                if (i == index)
+                    continue;
+
+                newArray.SetValue(array.GetProperty(i).GetValue<object>(), destIdx);
+                destIdx++;
+            }
+
+            property.SetValue(newArray);
+        }
+
+        private void OnCloneButtonClicked(int index)
+        {
+            SerializableArray array = property.GetArray();
+
+            int size = array.GetLength() + 1;
+            Array newArray = property.CreateArrayInstance(new int[] { size });
+
+            object clonedEntry = null;
+            for (int i = 0; i < array.GetLength(); i++)
+            {
+                object value = array.GetProperty(i).GetValue<object>();
+
+                newArray.SetValue(value, i);
+
+                if (i == index)
+                {
+                    // TODO - Clone
+                }
+            }
+
+            newArray.SetValue(clonedEntry, size - 1);
+
+            property.SetValue(newArray);
+        }
+
+        private void OnMoveUpButtonClicked(int index)
+        {
+            SerializableArray array = property.GetArray();
+
+            if ((index - 1) >= 0)
+            {
+                object previousEntry = array.GetProperty(index - 1).GetValue<object>();
+
+                array.GetProperty(index - 1).SetValue(array.GetProperty(index).GetValue<object>());
+                array.GetProperty(index).SetValue(previousEntry);
+            }
+        }
+
+        private void OnMoveDownButtonClicked(int index)
+        {
+            SerializableArray array = property.GetArray();
+
+            if ((index + 1) < array.GetLength())
+            {
+                object nextEntry = array.GetProperty(index + 1).GetValue<object>();
+
+                array.GetProperty(index + 1).SetValue(array.GetProperty(index).GetValue<object>());
+                array.GetProperty(index).SetValue(nextEntry);
             }
         }
     }

+ 33 - 0
MBansheeEngine/SerializableProperty.cs

@@ -59,6 +59,14 @@ namespace BansheeEngine
             return (T)getter();
         }
 
+        public T GetValueCopy<T>()
+        {
+            if (!typeof(T).IsAssignableFrom(internalType))
+                throw new Exception("Attempted to retrieve a serializable value using an invalid type. Provided type: " + typeof(T) + ". Needed type: " + internalType);
+
+            return (T)Internal_CloneManagedInstance(mCachedPtr, getter());
+        }
+
         public void SetValue<T>(T value)
         {
             if (!typeof(T).IsAssignableFrom(internalType))
@@ -83,12 +91,37 @@ namespace BansheeEngine
             return Internal_CreateArray(mCachedPtr, GetValue<Array>());
         }
 
+        public T CreateObjectInstance<T>()
+        {
+            if (type != FieldType.Object)
+                throw new Exception("Attempting to retrieve object information from a field that doesn't contain an object.");
+
+            return (T) Internal_CreateMangedObjectInstance(mCachedPtr);
+        }
+
+        public Array CreateArrayInstance(int[] lengths)
+        {
+            if (type != FieldType.Array)
+                throw new Exception("Attempting to retrieve array information from a field that doesn't contain an array.");
+
+            return Internal_CreateManagedArrayInstance(mCachedPtr, lengths);
+        }
+
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern SerializableObject Internal_CreateObject(IntPtr nativeInstance, object instance);
 
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern SerializableArray Internal_CreateArray(IntPtr nativeInstance, Array instance);
 
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern object Internal_CreateMangedObjectInstance(IntPtr nativeInstance);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern Array Internal_CreateManagedArrayInstance(IntPtr nativeInstance, int[] lengths);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern object Internal_CloneManagedInstance(IntPtr nativeInstance, object original);
+
         public static FieldType DetermineFieldType(Type internalType)
         {
             if (!internalType.IsArray)

+ 1 - 0
SBansheeEditor/Include/BsScriptGUIIntField.h

@@ -17,6 +17,7 @@ namespace BansheeEngine
 		static void internal_getValue(ScriptGUIIntField* nativeInstance, INT32* output);
 		static void internal_setValue(ScriptGUIIntField* nativeInstance, INT32 value);
 		static void internal_hasInputFocus(ScriptGUIIntField* nativeInstance, bool* output);
+		static void internal_setRange(ScriptGUIIntField* nativeInstance, INT32 min, INT32 max);
 
 		static void onChanged(MonoObject* instance, INT32 newValue);
 

+ 8 - 0
SBansheeEditor/Source/BsScriptGUIIntField.cpp

@@ -34,6 +34,7 @@ namespace BansheeEngine
 		metaData.scriptClass->addInternalCall("Internal_GetValue", &ScriptGUIIntField::internal_getValue);
 		metaData.scriptClass->addInternalCall("Internal_SetValue", &ScriptGUIIntField::internal_setValue);
 		metaData.scriptClass->addInternalCall("Internal_HasInputFocus", &ScriptGUIIntField::internal_hasInputFocus);
+		metaData.scriptClass->addInternalCall("Internal_SetRange", &ScriptGUIIntField::internal_setRange);
 
 		onChangedThunk = (OnChangedThunkDef)metaData.scriptClass->getMethod("DoOnChanged", 1).getThunk();
 	}
@@ -86,6 +87,13 @@ namespace BansheeEngine
 		*output = intField->hasInputFocus();
 	}
 
+	void ScriptGUIIntField::internal_setRange(ScriptGUIIntField* nativeInstance, INT32 min, INT32 max)
+	{
+		GUIIntField* intField = static_cast<GUIIntField*>(nativeInstance->getGUIElement());
+
+		intField->setRange(min, max);
+	}
+
 	void ScriptGUIIntField::onChanged(MonoObject* instance, INT32 newValue)
 	{
 		MonoException* exception = nullptr;

+ 1 - 1
SBansheeEngine/Include/BsManagedComponentRTTI.h

@@ -55,7 +55,7 @@ namespace BansheeEngine
 		{
 			ManagedComponent* mc = static_cast<ManagedComponent*>(obj);
 
-			mc->mRTTIData = ManagedSerializableObject::create(mc->getManagedInstance());
+			mc->mRTTIData = ManagedSerializableObject::createFromExisting(mc->getManagedInstance());
 		}
 
 		virtual void onDeserializationStarted(IReflectable* obj)

+ 1 - 1
SBansheeEngine/Include/BsManagedResourceRTTI.h

@@ -32,7 +32,7 @@ namespace BansheeEngine
 		{
 			ManagedResource* mc = static_cast<ManagedResource*>(obj);
 
-			mc->mRTTIData = ManagedSerializableObject::create(mc->getManagedInstance());
+			mc->mRTTIData = ManagedSerializableObject::createFromExisting(mc->getManagedInstance());
 		}
 
 		virtual void onDeserializationEnded(IReflectable* obj)

+ 4 - 2
SBansheeEngine/Include/BsManagedSerializableArray.h

@@ -17,7 +17,9 @@ namespace BansheeEngine
 
 		MonoObject* getManagedInstance() const { return mManagedInstance; }
 
-		static ManagedSerializableArrayPtr create(MonoObject* managedInstance, const ManagedSerializableTypeInfoArrayPtr& typeInfo);
+		static ManagedSerializableArrayPtr createFromExisting(MonoObject* managedInstance, const ManagedSerializableTypeInfoArrayPtr& typeInfo);
+		static ManagedSerializableArrayPtr createFromNew(const ManagedSerializableTypeInfoArrayPtr& typeInfo, const Vector<UINT32>& sizes);
+		static MonoObject* createManagedInstance(const ManagedSerializableTypeInfoArrayPtr& typeInfo, const Vector<UINT32>& sizes);
 
 	protected:
 		MonoObject* mManagedInstance;
@@ -53,7 +55,7 @@ namespace BansheeEngine
 		/* 								RTTI		                     		*/
 		/************************************************************************/
 		
-		static ManagedSerializableArrayPtr createEmpty();
+		static ManagedSerializableArrayPtr createFromNew();
 
 	public:
 		friend class ManagedSerializableArrayRTTI;

+ 1 - 1
SBansheeEngine/Include/BsManagedSerializableArrayRTTI.h

@@ -115,7 +115,7 @@ namespace BansheeEngine
 
 		virtual std::shared_ptr<IReflectable> newRTTIObject()
 		{
-			return ManagedSerializableArray::createEmpty();
+			return ManagedSerializableArray::createFromNew();
 		}
 	};
 }

+ 3 - 1
SBansheeEngine/Include/BsManagedSerializableDictionary.h

@@ -33,7 +33,9 @@ namespace BansheeEngine
 
 		MonoObject* getManagedInstance() const { return mManagedInstance; }
 
-		static ManagedSerializableDictionaryPtr create(MonoObject* managedInstance, const ManagedSerializableTypeInfoDictionaryPtr& typeInfo);
+		static ManagedSerializableDictionaryPtr createFromExisting(MonoObject* managedInstance, const ManagedSerializableTypeInfoDictionaryPtr& typeInfo);
+		static ManagedSerializableDictionaryPtr createFromNew(const ManagedSerializableTypeInfoDictionaryPtr& typeInfo);
+		static MonoObject* createManagedInstance(const ManagedSerializableTypeInfoDictionaryPtr& typeInfo);
 
 	protected:
 		MonoObject* mManagedInstance;

+ 20 - 0
SBansheeEngine/Include/BsManagedSerializableField.h

@@ -29,6 +29,7 @@ namespace BansheeEngine
 	public:
 		static ManagedSerializableFieldDataPtr create(const ManagedSerializableTypeInfoPtr& typeInfo, MonoObject* value);
 		virtual void* getValue(const ManagedSerializableTypeInfoPtr& typeInfo) = 0;
+		virtual MonoObject* getValueBoxed(const ManagedSerializableTypeInfoPtr& typeInfo) = 0;
 
 		/************************************************************************/
 		/* 								RTTI		                     		*/
@@ -64,6 +65,7 @@ namespace BansheeEngine
 		bool value;
 
 		void* getValue(const ManagedSerializableTypeInfoPtr& typeInfo);
+		MonoObject* getValueBoxed(const ManagedSerializableTypeInfoPtr& typeInfo);
 
 		/************************************************************************/
 		/* 								RTTI		                     		*/
@@ -81,6 +83,7 @@ namespace BansheeEngine
 		wchar_t value;
 
 		void* getValue(const ManagedSerializableTypeInfoPtr& typeInfo);
+		MonoObject* getValueBoxed(const ManagedSerializableTypeInfoPtr& typeInfo);
 
 		/************************************************************************/
 		/* 								RTTI		                     		*/
@@ -98,6 +101,7 @@ namespace BansheeEngine
 		INT8 value;
 
 		void* getValue(const ManagedSerializableTypeInfoPtr& typeInfo);
+		MonoObject* getValueBoxed(const ManagedSerializableTypeInfoPtr& typeInfo);
 
 		/************************************************************************/
 		/* 								RTTI		                     		*/
@@ -115,6 +119,7 @@ namespace BansheeEngine
 		UINT8 value;
 
 		void* getValue(const ManagedSerializableTypeInfoPtr& typeInfo);
+		MonoObject* getValueBoxed(const ManagedSerializableTypeInfoPtr& typeInfo);
 
 		/************************************************************************/
 		/* 								RTTI		                     		*/
@@ -132,6 +137,7 @@ namespace BansheeEngine
 		INT16 value;
 
 		void* getValue(const ManagedSerializableTypeInfoPtr& typeInfo);
+		MonoObject* getValueBoxed(const ManagedSerializableTypeInfoPtr& typeInfo);
 
 		/************************************************************************/
 		/* 								RTTI		                     		*/
@@ -149,6 +155,7 @@ namespace BansheeEngine
 		UINT16 value;
 
 		void* getValue(const ManagedSerializableTypeInfoPtr& typeInfo);
+		MonoObject* getValueBoxed(const ManagedSerializableTypeInfoPtr& typeInfo);
 
 		/************************************************************************/
 		/* 								RTTI		                     		*/
@@ -166,6 +173,7 @@ namespace BansheeEngine
 		INT32 value;
 
 		void* getValue(const ManagedSerializableTypeInfoPtr& typeInfo);
+		MonoObject* getValueBoxed(const ManagedSerializableTypeInfoPtr& typeInfo);
 
 		/************************************************************************/
 		/* 								RTTI		                     		*/
@@ -183,6 +191,7 @@ namespace BansheeEngine
 		UINT32 value;
 
 		void* getValue(const ManagedSerializableTypeInfoPtr& typeInfo);
+		MonoObject* getValueBoxed(const ManagedSerializableTypeInfoPtr& typeInfo);
 
 		/************************************************************************/
 		/* 								RTTI		                     		*/
@@ -200,6 +209,7 @@ namespace BansheeEngine
 		INT64 value;
 
 		void* getValue(const ManagedSerializableTypeInfoPtr& typeInfo);
+		MonoObject* getValueBoxed(const ManagedSerializableTypeInfoPtr& typeInfo);
 
 		/************************************************************************/
 		/* 								RTTI		                     		*/
@@ -217,6 +227,7 @@ namespace BansheeEngine
 		UINT64 value;
 
 		void* getValue(const ManagedSerializableTypeInfoPtr& typeInfo);
+		MonoObject* getValueBoxed(const ManagedSerializableTypeInfoPtr& typeInfo);
 
 		/************************************************************************/
 		/* 								RTTI		                     		*/
@@ -234,6 +245,7 @@ namespace BansheeEngine
 		float value;
 
 		void* getValue(const ManagedSerializableTypeInfoPtr& typeInfo);
+		MonoObject* getValueBoxed(const ManagedSerializableTypeInfoPtr& typeInfo);
 
 		/************************************************************************/
 		/* 								RTTI		                     		*/
@@ -252,6 +264,7 @@ namespace BansheeEngine
 		double value;
 
 		void* getValue(const ManagedSerializableTypeInfoPtr& typeInfo);
+		MonoObject* getValueBoxed(const ManagedSerializableTypeInfoPtr& typeInfo);
 
 		/************************************************************************/
 		/* 								RTTI		                     		*/
@@ -269,6 +282,7 @@ namespace BansheeEngine
 		WString value;
 
 		void* getValue(const ManagedSerializableTypeInfoPtr& typeInfo);
+		MonoObject* getValueBoxed(const ManagedSerializableTypeInfoPtr& typeInfo);
 
 		/************************************************************************/
 		/* 								RTTI		                     		*/
@@ -286,6 +300,7 @@ namespace BansheeEngine
 		HResource value;
 
 		void* getValue(const ManagedSerializableTypeInfoPtr& typeInfo);
+		MonoObject* getValueBoxed(const ManagedSerializableTypeInfoPtr& typeInfo);
 
 		/************************************************************************/
 		/* 								RTTI		                     		*/
@@ -303,6 +318,7 @@ namespace BansheeEngine
 		HGameObject value;
 
 		void* getValue(const ManagedSerializableTypeInfoPtr& typeInfo);
+		MonoObject* getValueBoxed(const ManagedSerializableTypeInfoPtr& typeInfo);
 
 		/************************************************************************/
 		/* 								RTTI		                     		*/
@@ -320,6 +336,7 @@ namespace BansheeEngine
 		ManagedSerializableObjectPtr value;
 
 		void* getValue(const ManagedSerializableTypeInfoPtr& typeInfo);
+		MonoObject* getValueBoxed(const ManagedSerializableTypeInfoPtr& typeInfo);
 
 		/************************************************************************/
 		/* 								RTTI		                     		*/
@@ -337,6 +354,7 @@ namespace BansheeEngine
 		ManagedSerializableArrayPtr value;
 
 		void* getValue(const ManagedSerializableTypeInfoPtr& typeInfo);
+		MonoObject* getValueBoxed(const ManagedSerializableTypeInfoPtr& typeInfo);
 
 		/************************************************************************/
 		/* 								RTTI		                     		*/
@@ -354,6 +372,7 @@ namespace BansheeEngine
 		ManagedSerializableListPtr value;
 
 		void* getValue(const ManagedSerializableTypeInfoPtr& typeInfo);
+		MonoObject* getValueBoxed(const ManagedSerializableTypeInfoPtr& typeInfo);
 
 		/************************************************************************/
 		/* 								RTTI		                     		*/
@@ -371,6 +390,7 @@ namespace BansheeEngine
 		ManagedSerializableDictionaryPtr value;
 
 		void* getValue(const ManagedSerializableTypeInfoPtr& typeInfo);
+		MonoObject* getValueBoxed(const ManagedSerializableTypeInfoPtr& typeInfo);
 
 		/************************************************************************/
 		/* 								RTTI		                     		*/

+ 3 - 1
SBansheeEngine/Include/BsManagedSerializableList.h

@@ -17,7 +17,9 @@ namespace BansheeEngine
 
 		MonoObject* getManagedInstance() const { return mManagedInstance; }
 
-		static ManagedSerializableListPtr create(MonoObject* managedInstance, const ManagedSerializableTypeInfoListPtr& typeInfo);
+		static ManagedSerializableListPtr createFromExisting(MonoObject* managedInstance, const ManagedSerializableTypeInfoListPtr& typeInfo);
+		static ManagedSerializableListPtr createFromNew(const ManagedSerializableTypeInfoListPtr& typeInfo, UINT32 size);
+		static MonoObject* createManagedInstance(const ManagedSerializableTypeInfoListPtr& typeInfo, UINT32 size);
 
 	protected:
 		MonoObject* mManagedInstance;

+ 3 - 1
SBansheeEngine/Include/BsManagedSerializableObject.h

@@ -18,7 +18,9 @@ namespace BansheeEngine
 		MonoObject* getManagedInstance() const { return mManagedInstance; }
 		ManagedSerializableObjectInfoPtr getObjectInfo() const { return mObjInfo; }
 
-		static ManagedSerializableObjectPtr create(MonoObject* managedInstance);
+		static ManagedSerializableObjectPtr createFromExisting(MonoObject* managedInstance);
+		static ManagedSerializableObjectPtr createFromNew(const ManagedSerializableTypeInfoObjectPtr& type);
+		static MonoObject* createManagedInstance(const ManagedSerializableTypeInfoObjectPtr& type);
 
 	protected:
 		ManagedSerializableObjectInfoPtr mObjInfo;

+ 1 - 1
SBansheeEngine/Include/BsManagedSerializableObjectInfo.h

@@ -181,7 +181,7 @@ namespace BansheeEngine
 	public:
 		ManagedSerializableObjectInfo();
 
-		ScriptSerializableTypeInfoObjectPtr mTypeInfo;
+		ManagedSerializableTypeInfoObjectPtr mTypeInfo;
 		UINT32 mTypeId;
 
 		MonoClass* mMonoClass;

+ 2 - 2
SBansheeEngine/Include/BsManagedSerializableObjectInfoRTTI.h

@@ -67,12 +67,12 @@ namespace BansheeEngine
 	class BS_SCR_BE_EXPORT ManagedSerializableObjectInfoRTTI : public RTTIType<ManagedSerializableObjectInfo, IReflectable, ManagedSerializableObjectInfoRTTI>
 	{
 	private:
-		ScriptSerializableTypeInfoObjectPtr getTypeInfo(ManagedSerializableObjectInfo* obj)
+		ManagedSerializableTypeInfoObjectPtr getTypeInfo(ManagedSerializableObjectInfo* obj)
 		{
 			return obj->mTypeInfo;
 		}
 
-		void setTypeInfo(ManagedSerializableObjectInfo* obj, ScriptSerializableTypeInfoObjectPtr val)
+		void setTypeInfo(ManagedSerializableObjectInfo* obj, ManagedSerializableTypeInfoObjectPtr val)
 		{
 			obj->mTypeInfo = val;
 		}

+ 1 - 1
SBansheeEngine/Include/BsScriptEnginePrerequisites.h

@@ -106,7 +106,7 @@ namespace BansheeEngine
 	typedef std::shared_ptr<ManagedSerializableFieldKey> ManagedSerializableFieldKeyPtr;
 	typedef std::shared_ptr<ManagedSerializableFieldDataEntry> ManagedSerializableFieldDataEntryPtr;
 	typedef std::shared_ptr<ManagedSerializableTypeInfo> ManagedSerializableTypeInfoPtr;
-	typedef std::shared_ptr<ManagedSerializableTypeInfoObject> ScriptSerializableTypeInfoObjectPtr;
+	typedef std::shared_ptr<ManagedSerializableTypeInfoObject> ManagedSerializableTypeInfoObjectPtr;
 	typedef std::shared_ptr<ManagedSerializableObject> ManagedSerializableObjectPtr;
 	typedef std::shared_ptr<ManagedSerializableArray> ManagedSerializableArrayPtr;
 	typedef std::shared_ptr<ManagedSerializableList> ManagedSerializableListPtr;

+ 5 - 0
SBansheeEngine/Include/BsScriptSerializableProperty.h

@@ -18,6 +18,11 @@ namespace BansheeEngine
 		static MonoObject* internal_createObject(ScriptSerializableProperty* nativeInstance, MonoObject* object);
 		static MonoObject* internal_createArray(ScriptSerializableProperty* nativeInstance, MonoObject* object);
 
+		static MonoObject* internal_createManagedObjectInstance(ScriptSerializableProperty* nativeInstance);
+		static MonoObject* internal_createManagedArrayInstance(ScriptSerializableProperty* nativeInstance, MonoArray* sizes);
+
+		static MonoObject* internal_cloneManagedInstance(ScriptSerializableProperty* nativeInstance, MonoObject* original);
+
 		ScriptSerializableProperty(MonoObject* instance, const ManagedSerializableTypeInfoPtr& typeInfo);
 
 		ManagedSerializableTypeInfoPtr mTypeInfo;

+ 32 - 18
SBansheeEngine/Source/BsManagedSerializableArray.cpp

@@ -27,7 +27,7 @@ namespace BansheeEngine
 			mNumElements[i] = getLength(i);
 	}
 
-	ManagedSerializableArrayPtr ManagedSerializableArray::create(MonoObject* managedInstance, const ManagedSerializableTypeInfoArrayPtr& typeInfo)
+	ManagedSerializableArrayPtr ManagedSerializableArray::createFromExisting(MonoObject* managedInstance, const ManagedSerializableTypeInfoArrayPtr& typeInfo)
 	{
 		if(managedInstance == nullptr)
 			return nullptr;
@@ -38,11 +38,38 @@ namespace BansheeEngine
 		return bs_shared_ptr<ManagedSerializableArray>(ConstructPrivately(), typeInfo, managedInstance);
 	}
 
-	ManagedSerializableArrayPtr ManagedSerializableArray::createEmpty()
+	ManagedSerializableArrayPtr ManagedSerializableArray::createFromNew(const ManagedSerializableTypeInfoArrayPtr& typeInfo, const Vector<UINT32>& sizes)
+	{
+		return bs_shared_ptr<ManagedSerializableArray>(ConstructPrivately(), typeInfo, createManagedInstance(typeInfo, sizes));
+	}
+
+	ManagedSerializableArrayPtr ManagedSerializableArray::createFromNew()
 	{
 		return bs_shared_ptr<ManagedSerializableArray>(ConstructPrivately());
 	}
 
+	MonoObject* ManagedSerializableArray::createManagedInstance(const ManagedSerializableTypeInfoArrayPtr& typeInfo, const Vector<UINT32>& sizes)
+	{
+		if (!typeInfo->isTypeLoaded())
+			return nullptr;
+
+		MonoClass* arrayClass = RuntimeScriptObjects::instance().getSystemArrayClass();
+
+		MonoMethod* createInstance = arrayClass->getMethodExact("CreateInstance", "Type,int[]");
+		MonoArray* lengthArray = mono_array_new(MonoManager::instance().getDomain(), mono_get_int32_class(), (UINT32)sizes.size());
+
+		for (UINT32 i = 0; i < (UINT32)sizes.size(); i++)
+		{
+			void* elemAddr = mono_array_addr_with_size(lengthArray, sizeof(int), i);
+			memcpy(elemAddr, &sizes[i], sizeof(int));
+		}
+
+		void* params[2] = {
+			mono_type_get_object(MonoManager::instance().getDomain(), mono_class_get_type(typeInfo->getMonoClass())), lengthArray };
+
+		return createInstance->invoke(nullptr, params);
+	}
+
 	void ManagedSerializableArray::serializeManagedInstance()
 	{
 		UINT32 totalNumElements = 1;
@@ -60,24 +87,11 @@ namespace BansheeEngine
 
 	void ManagedSerializableArray::deserializeManagedInstance()
 	{
-		if(!mArrayTypeInfo->isTypeLoaded())
-			return;
+		mManagedInstance = createManagedInstance(mArrayTypeInfo, mNumElements);
 
-		MonoClass* arrayClass = RuntimeScriptObjects::instance().getSystemArrayClass();
-
-		MonoMethod* createInstance = arrayClass->getMethodExact("CreateInstance", "Type,int[]");
-		MonoArray* lengthArray = mono_array_new(MonoManager::instance().getDomain(), mono_get_int32_class(), (UINT32)mNumElements.size());
-
-		for(UINT32 i = 0; i < (UINT32)mNumElements.size(); i++)
-		{
-			void* elemAddr = mono_array_addr_with_size(lengthArray, sizeof(int), i);
-			memcpy(elemAddr, &mNumElements[i], sizeof(int));
-		}
-
-		void* params[2] = { 
-			mono_type_get_object(MonoManager::instance().getDomain(), mono_class_get_type(mArrayTypeInfo->getMonoClass())), lengthArray };
+		if (mManagedInstance == nullptr)
+			return;
 
-		mManagedInstance = createInstance->invoke(nullptr, params);
 		initMonoObjects();
 
 		UINT32 idx = 0;

+ 22 - 4
SBansheeEngine/Source/BsManagedSerializableDictionary.cpp

@@ -52,7 +52,7 @@ namespace BansheeEngine
 
 	}
 
-	ManagedSerializableDictionaryPtr ManagedSerializableDictionary::create(MonoObject* managedInstance, const ManagedSerializableTypeInfoDictionaryPtr& typeInfo)
+	ManagedSerializableDictionaryPtr ManagedSerializableDictionary::createFromExisting(MonoObject* managedInstance, const ManagedSerializableTypeInfoDictionaryPtr& typeInfo)
 	{
 		if(managedInstance == nullptr)
 			return nullptr;
@@ -68,6 +68,24 @@ namespace BansheeEngine
 		return bs_shared_ptr<ManagedSerializableDictionary>(ConstructPrivately(), typeInfo, managedInstance);
 	}
 
+	ManagedSerializableDictionaryPtr ManagedSerializableDictionary::createFromNew(const ManagedSerializableTypeInfoDictionaryPtr& typeInfo)
+	{
+		return bs_shared_ptr<ManagedSerializableDictionary>(ConstructPrivately(), typeInfo, createManagedInstance(typeInfo));
+	}
+
+	MonoObject* ManagedSerializableDictionary::createManagedInstance(const ManagedSerializableTypeInfoDictionaryPtr& typeInfo)
+	{
+		if (!typeInfo->isTypeLoaded())
+			return nullptr;
+
+		::MonoClass* dictionaryMonoClass = typeInfo->getMonoClass();
+		MonoClass* dictionaryClass = MonoManager::instance().findClass(dictionaryMonoClass);
+		if (dictionaryClass == nullptr)
+			return nullptr;
+
+		return dictionaryClass->createInstance();
+	}
+
 	ManagedSerializableDictionaryPtr ManagedSerializableDictionary::createEmpty()
 	{
 		return bs_shared_ptr<ManagedSerializableDictionary>(ConstructPrivately());
@@ -95,17 +113,17 @@ namespace BansheeEngine
 
 	void ManagedSerializableDictionary::deserializeManagedInstance()
 	{
-		if(!mDictionaryTypeInfo->isTypeLoaded())
+		mManagedInstance = createManagedInstance(mDictionaryTypeInfo);
+		if (mManagedInstance == nullptr)
 			return;
 
 		::MonoClass* dictionaryMonoClass = mDictionaryTypeInfo->getMonoClass();
 		MonoClass* dictionaryClass = MonoManager::instance().findClass(dictionaryMonoClass);
-		if(dictionaryClass == nullptr)
+		if (dictionaryClass == nullptr)
 			return;
 
 		initMonoObjects(dictionaryClass);
 
-		mManagedInstance = dictionaryClass->createInstance();
 		assert(mKeyEntries.size() == mValueEntries.size());
 
 		for(UINT32 i = 0; i < (UINT32)mKeyEntries.size(); i++)

+ 193 - 4
SBansheeEngine/Source/BsManagedSerializableField.cpp

@@ -203,7 +203,7 @@ namespace BansheeEngine
 			auto fieldData = bs_shared_ptr<ManagedSerializableFieldDataObject>();
 			if(value != nullptr)
 			{
-				fieldData->value = ManagedSerializableObject::create(value);
+				fieldData->value = ManagedSerializableObject::createFromExisting(value);
 			}
 
 			return fieldData;
@@ -213,7 +213,7 @@ namespace BansheeEngine
 			auto fieldData = bs_shared_ptr<ManagedSerializableFieldDataArray>();
 			if(value != nullptr)
 			{
-				fieldData->value = ManagedSerializableArray::create(value, std::static_pointer_cast<ManagedSerializableTypeInfoArray>(typeInfo));
+				fieldData->value = ManagedSerializableArray::createFromExisting(value, std::static_pointer_cast<ManagedSerializableTypeInfoArray>(typeInfo));
 			}
 
 			return fieldData;
@@ -223,7 +223,7 @@ namespace BansheeEngine
 			auto fieldData = bs_shared_ptr<ManagedSerializableFieldDataList>();
 			if(value != nullptr)
 			{
-				fieldData->value = ManagedSerializableList::create(value, std::static_pointer_cast<ManagedSerializableTypeInfoList>(typeInfo));
+				fieldData->value = ManagedSerializableList::createFromExisting(value, std::static_pointer_cast<ManagedSerializableTypeInfoList>(typeInfo));
 			}
 
 			return fieldData;
@@ -233,7 +233,7 @@ namespace BansheeEngine
 			auto fieldData = bs_shared_ptr<ManagedSerializableFieldDataDictionary>();
 			if(value != nullptr)
 			{
-				fieldData->value = ManagedSerializableDictionary::create(value, std::static_pointer_cast<ManagedSerializableTypeInfoDictionary>(typeInfo));
+				fieldData->value = ManagedSerializableDictionary::createFromExisting(value, std::static_pointer_cast<ManagedSerializableTypeInfoDictionary>(typeInfo));
 			}
 
 			return fieldData;
@@ -557,6 +557,195 @@ namespace BansheeEngine
 		BS_EXCEPT(InvalidParametersException, "Requesting an invalid type in serializable field.");
 	}
 
+	MonoObject* ManagedSerializableFieldDataBool::getValueBoxed(const ManagedSerializableTypeInfoPtr& typeInfo)
+	{
+		if (typeInfo->getTypeId() == TID_SerializableTypeInfoPrimitive)
+		{
+			auto primitiveTypeInfo = std::static_pointer_cast<ManagedSerializableTypeInfoPrimitive>(typeInfo);
+			if (primitiveTypeInfo->mType == ScriptPrimitiveType::Bool)
+				return mono_value_box(MonoManager::instance().getDomain(), mono_get_boolean_class(), &value);
+		}
+
+		BS_EXCEPT(InvalidParametersException, "Requesting an invalid type in serializable field.");
+	}
+
+	MonoObject* ManagedSerializableFieldDataChar::getValueBoxed(const ManagedSerializableTypeInfoPtr& typeInfo)
+	{
+		if (typeInfo->getTypeId() == TID_SerializableTypeInfoPrimitive)
+		{
+			auto primitiveTypeInfo = std::static_pointer_cast<ManagedSerializableTypeInfoPrimitive>(typeInfo);
+			if (primitiveTypeInfo->mType == ScriptPrimitiveType::Char)
+				return mono_value_box(MonoManager::instance().getDomain(), mono_get_char_class(), &value);
+		}
+
+		BS_EXCEPT(InvalidParametersException, "Requesting an invalid type in serializable field.");
+	}
+
+	MonoObject* ManagedSerializableFieldDataI8::getValueBoxed(const ManagedSerializableTypeInfoPtr& typeInfo)
+	{
+		if (typeInfo->getTypeId() == TID_SerializableTypeInfoPrimitive)
+		{
+			auto primitiveTypeInfo = std::static_pointer_cast<ManagedSerializableTypeInfoPrimitive>(typeInfo);
+			if (primitiveTypeInfo->mType == ScriptPrimitiveType::I8)
+				return mono_value_box(MonoManager::instance().getDomain(), mono_get_sbyte_class(), &value);
+		}
+
+		BS_EXCEPT(InvalidParametersException, "Requesting an invalid type in serializable field.");
+	}
+
+	MonoObject* ManagedSerializableFieldDataU8::getValueBoxed(const ManagedSerializableTypeInfoPtr& typeInfo)
+	{
+		if (typeInfo->getTypeId() == TID_SerializableTypeInfoPrimitive)
+		{
+			auto primitiveTypeInfo = std::static_pointer_cast<ManagedSerializableTypeInfoPrimitive>(typeInfo);
+			if (primitiveTypeInfo->mType == ScriptPrimitiveType::U8)
+				return mono_value_box(MonoManager::instance().getDomain(), mono_get_byte_class(), &value);
+		}
+
+		BS_EXCEPT(InvalidParametersException, "Requesting an invalid type in serializable field.");
+	}
+
+	MonoObject* ManagedSerializableFieldDataI16::getValueBoxed(const ManagedSerializableTypeInfoPtr& typeInfo)
+	{
+		if (typeInfo->getTypeId() == TID_SerializableTypeInfoPrimitive)
+		{
+			auto primitiveTypeInfo = std::static_pointer_cast<ManagedSerializableTypeInfoPrimitive>(typeInfo);
+			if (primitiveTypeInfo->mType == ScriptPrimitiveType::I16)
+				return mono_value_box(MonoManager::instance().getDomain(), mono_get_int16_class(), &value);
+		}
+
+		BS_EXCEPT(InvalidParametersException, "Requesting an invalid type in serializable field.");
+	}
+
+	MonoObject* ManagedSerializableFieldDataU16::getValueBoxed(const ManagedSerializableTypeInfoPtr& typeInfo)
+	{
+		if (typeInfo->getTypeId() == TID_SerializableTypeInfoPrimitive)
+		{
+			auto primitiveTypeInfo = std::static_pointer_cast<ManagedSerializableTypeInfoPrimitive>(typeInfo);
+			if (primitiveTypeInfo->mType == ScriptPrimitiveType::U16)
+				return mono_value_box(MonoManager::instance().getDomain(), mono_get_uint16_class(), &value);
+		}
+
+		BS_EXCEPT(InvalidParametersException, "Requesting an invalid type in serializable field.");
+	}
+
+	MonoObject* ManagedSerializableFieldDataI32::getValueBoxed(const ManagedSerializableTypeInfoPtr& typeInfo)
+	{
+		if (typeInfo->getTypeId() == TID_SerializableTypeInfoPrimitive)
+		{
+			auto primitiveTypeInfo = std::static_pointer_cast<ManagedSerializableTypeInfoPrimitive>(typeInfo);
+			if (primitiveTypeInfo->mType == ScriptPrimitiveType::I32)
+				return mono_value_box(MonoManager::instance().getDomain(), mono_get_int32_class(), &value);
+		}
+
+		BS_EXCEPT(InvalidParametersException, "Requesting an invalid type in serializable field.");
+	}
+
+	MonoObject* ManagedSerializableFieldDataU32::getValueBoxed(const ManagedSerializableTypeInfoPtr& typeInfo)
+	{
+		if (typeInfo->getTypeId() == TID_SerializableTypeInfoPrimitive)
+		{
+			auto primitiveTypeInfo = std::static_pointer_cast<ManagedSerializableTypeInfoPrimitive>(typeInfo);
+			if (primitiveTypeInfo->mType == ScriptPrimitiveType::U32)
+				return mono_value_box(MonoManager::instance().getDomain(), mono_get_uint32_class(), &value);
+		}
+
+		BS_EXCEPT(InvalidParametersException, "Requesting an invalid type in serializable field.");
+	}
+
+	MonoObject* ManagedSerializableFieldDataI64::getValueBoxed(const ManagedSerializableTypeInfoPtr& typeInfo)
+	{
+		if (typeInfo->getTypeId() == TID_SerializableTypeInfoPrimitive)
+		{
+			auto primitiveTypeInfo = std::static_pointer_cast<ManagedSerializableTypeInfoPrimitive>(typeInfo);
+			if (primitiveTypeInfo->mType == ScriptPrimitiveType::I64)
+				return mono_value_box(MonoManager::instance().getDomain(), mono_get_int64_class(), &value);
+		}
+
+		BS_EXCEPT(InvalidParametersException, "Requesting an invalid type in serializable field.");
+	}
+
+	MonoObject* ManagedSerializableFieldDataU64::getValueBoxed(const ManagedSerializableTypeInfoPtr& typeInfo)
+	{
+		if (typeInfo->getTypeId() == TID_SerializableTypeInfoPrimitive)
+		{
+			auto primitiveTypeInfo = std::static_pointer_cast<ManagedSerializableTypeInfoPrimitive>(typeInfo);
+			if (primitiveTypeInfo->mType == ScriptPrimitiveType::U64)
+				return mono_value_box(MonoManager::instance().getDomain(), mono_get_uint64_class(), &value);
+		}
+
+		BS_EXCEPT(InvalidParametersException, "Requesting an invalid type in serializable field.");
+	}
+
+	MonoObject* ManagedSerializableFieldDataFloat::getValueBoxed(const ManagedSerializableTypeInfoPtr& typeInfo)
+	{
+		if (typeInfo->getTypeId() == TID_SerializableTypeInfoPrimitive)
+		{
+			auto primitiveTypeInfo = std::static_pointer_cast<ManagedSerializableTypeInfoPrimitive>(typeInfo);
+			if (primitiveTypeInfo->mType == ScriptPrimitiveType::Float)
+				return mono_value_box(MonoManager::instance().getDomain(), mono_get_single_class(), &value);
+		}
+
+		BS_EXCEPT(InvalidParametersException, "Requesting an invalid type in serializable field.");
+	}
+
+	MonoObject* ManagedSerializableFieldDataDouble::getValueBoxed(const ManagedSerializableTypeInfoPtr& typeInfo)
+	{
+		if (typeInfo->getTypeId() == TID_SerializableTypeInfoPrimitive)
+		{
+			auto primitiveTypeInfo = std::static_pointer_cast<ManagedSerializableTypeInfoPrimitive>(typeInfo);
+			if (primitiveTypeInfo->mType == ScriptPrimitiveType::Double)
+				return mono_value_box(MonoManager::instance().getDomain(), mono_get_double_class(), &value);
+		}
+
+		BS_EXCEPT(InvalidParametersException, "Requesting an invalid type in serializable field.");
+	}
+
+	MonoObject* ManagedSerializableFieldDataString::getValueBoxed(const ManagedSerializableTypeInfoPtr& typeInfo)
+	{
+		return (MonoObject*)getValue(typeInfo);
+	}
+
+	MonoObject* ManagedSerializableFieldDataResourceRef::getValueBoxed(const ManagedSerializableTypeInfoPtr& typeInfo)
+	{
+		return (MonoObject*)getValue(typeInfo);
+	}
+
+	MonoObject* ManagedSerializableFieldDataGameObjectRef::getValueBoxed(const ManagedSerializableTypeInfoPtr& typeInfo)
+	{
+		return (MonoObject*)getValue(typeInfo);
+	}
+
+	MonoObject* ManagedSerializableFieldDataObject::getValueBoxed(const ManagedSerializableTypeInfoPtr& typeInfo)
+	{
+		if (typeInfo->getTypeId() == TID_SerializableTypeInfoObject)
+		{
+			auto objectTypeInfo = std::static_pointer_cast<ManagedSerializableTypeInfoObject>(typeInfo);
+
+			if (value != nullptr)
+				return value->getManagedInstance();
+
+			return nullptr;
+		}
+
+		BS_EXCEPT(InvalidParametersException, "Requesting an invalid type in serializable field.");
+	}
+
+	MonoObject* ManagedSerializableFieldDataArray::getValueBoxed(const ManagedSerializableTypeInfoPtr& typeInfo)
+	{
+		return (MonoObject*)getValue(typeInfo);
+	}
+
+	MonoObject* ManagedSerializableFieldDataList::getValueBoxed(const ManagedSerializableTypeInfoPtr& typeInfo)
+	{
+		return (MonoObject*)getValue(typeInfo);
+	}
+
+	MonoObject* ManagedSerializableFieldDataDictionary::getValueBoxed(const ManagedSerializableTypeInfoPtr& typeInfo)
+	{
+		return (MonoObject*)getValue(typeInfo);
+	}
+
 	RTTITypeBase* ManagedSerializableFieldKey::getRTTIStatic()
 	{
 		return ManagedSerializableFieldKeyRTTI::instance();

+ 23 - 9
SBansheeEngine/Source/BsManagedSerializableList.cpp

@@ -28,7 +28,7 @@ namespace BansheeEngine
 		mNumElements = getLength();
 	}
 
-	ManagedSerializableListPtr ManagedSerializableList::create(MonoObject* managedInstance, const ManagedSerializableTypeInfoListPtr& typeInfo)
+	ManagedSerializableListPtr ManagedSerializableList::createFromExisting(MonoObject* managedInstance, const ManagedSerializableTypeInfoListPtr& typeInfo)
 	{
 		if(managedInstance == nullptr)
 			return nullptr;
@@ -44,6 +44,25 @@ namespace BansheeEngine
 		return bs_shared_ptr<ManagedSerializableList>(ConstructPrivately(), typeInfo, managedInstance);
 	}
 
+	ManagedSerializableListPtr ManagedSerializableList::createFromNew(const ManagedSerializableTypeInfoListPtr& typeInfo, UINT32 size)
+	{
+		return bs_shared_ptr<ManagedSerializableList>(ConstructPrivately(), typeInfo, createManagedInstance(typeInfo, size));
+	}
+
+	MonoObject* ManagedSerializableList::createManagedInstance(const ManagedSerializableTypeInfoListPtr& typeInfo, UINT32 size)
+	{
+		if (!typeInfo->isTypeLoaded())
+			return nullptr;
+
+		::MonoClass* listMonoClass = typeInfo->getMonoClass();
+		MonoClass* listClass = MonoManager::instance().findClass(listMonoClass);
+		if (listClass == nullptr)
+			return nullptr;
+
+		void* params[1] = { &size };
+		return listClass->createInstance("int", params);
+	}
+
 	ManagedSerializableListPtr ManagedSerializableList::createEmpty()
 	{
 		return bs_shared_ptr<ManagedSerializableList>(ConstructPrivately());
@@ -60,19 +79,14 @@ namespace BansheeEngine
 
 	void ManagedSerializableList::deserializeManagedInstance()
 	{
-		if(!mListTypeInfo->isTypeLoaded())
-			return;
+		mManagedInstance = createManagedInstance(mListTypeInfo, mNumElements);
 
-		::MonoClass* listMonoClass = mListTypeInfo->getMonoClass();
-		MonoClass* listClass = MonoManager::instance().findClass(listMonoClass);
-		if(listClass == nullptr)
+		if (mManagedInstance == nullptr)
 			return;
 
+		MonoClass* listClass = MonoManager::instance().findClass(mListTypeInfo->getMonoClass());
 		initMonoObjects(listClass);
 
-		void* params[1] = { &mNumElements };
-		mManagedInstance = listClass->createInstance("int", params);
-
 		for(auto& arrayEntry : mListEntries)
 		{
 			addFieldData(arrayEntry);

+ 30 - 5
SBansheeEngine/Source/BsManagedSerializableObject.cpp

@@ -19,7 +19,7 @@ namespace BansheeEngine
 
 	}
 
-	ManagedSerializableObjectPtr ManagedSerializableObject::create(MonoObject* managedInstance)
+	ManagedSerializableObjectPtr ManagedSerializableObject::createFromExisting(MonoObject* managedInstance)
 	{
 		if(managedInstance == nullptr)
 			return nullptr;
@@ -35,6 +35,31 @@ namespace BansheeEngine
 		return bs_shared_ptr<ManagedSerializableObject>(ConstructPrivately(), objInfo, managedInstance);
 	}
 
+	ManagedSerializableObjectPtr ManagedSerializableObject::createFromNew(const ManagedSerializableTypeInfoObjectPtr& type)
+	{
+		ManagedSerializableObjectInfoPtr currentObjInfo = nullptr;
+
+		// See if this type even still exists
+		if (!RuntimeScriptObjects::instance().getSerializableObjectInfo(type->mTypeNamespace, type->mTypeName, currentObjInfo))
+			return nullptr;
+
+		return bs_shared_ptr<ManagedSerializableObject>(ConstructPrivately(), currentObjInfo, createManagedInstance(type));
+	}
+
+	MonoObject* ManagedSerializableObject::createManagedInstance(const ManagedSerializableTypeInfoObjectPtr& type)
+	{
+		ManagedSerializableObjectInfoPtr currentObjInfo = nullptr;
+
+		// See if this type even still exists
+		if (!RuntimeScriptObjects::instance().getSerializableObjectInfo(type->mTypeNamespace, type->mTypeName, currentObjInfo))
+			return nullptr;
+
+		if (type->mValueType)
+			return currentObjInfo->mMonoClass->createInstance(false);
+		else
+			return currentObjInfo->mMonoClass->createInstance();
+	}
+
 	ManagedSerializableObjectPtr ManagedSerializableObject::createEmpty()
 	{
 		return bs_shared_ptr<ManagedSerializableObject>(ConstructPrivately());
@@ -85,10 +110,10 @@ namespace BansheeEngine
 		if(!RuntimeScriptObjects::instance().getSerializableObjectInfo(storedObjInfo->mTypeInfo->mTypeNamespace, storedObjInfo->mTypeInfo->mTypeName, currentObjInfo))
 			return;
 
-		if(storedObjInfo->mTypeInfo->mValueType)
-			mManagedInstance = currentObjInfo->mMonoClass->createInstance(false);
-		else
-			mManagedInstance = currentObjInfo->mMonoClass->createInstance();
+		mManagedInstance = createManagedInstance(storedObjInfo->mTypeInfo);
+
+		if (mManagedInstance == nullptr)
+			return;
 
 		auto findFieldInfoFromKey = [&] (UINT16 typeId, UINT16 fieldId, ManagedSerializableObjectInfoPtr objInfo, 
 			ManagedSerializableFieldInfoPtr& outFieldInfo, ManagedSerializableObjectInfoPtr &outObjInfo) -> bool

+ 39 - 0
SBansheeEngine/Source/BsScriptSerializableProperty.cpp

@@ -7,6 +7,10 @@
 #include "BsManagedSerializableObjectInfo.h"
 #include "BsScriptSerializableObject.h"
 #include "BsScriptSerializableArray.h"
+#include "BsManagedSerializableObject.h"
+#include "BsManagedSerializableArray.h"
+#include "BsManagedSerializableField.h"
+#include "BsMemorySerializer.h"
 
 namespace BansheeEngine
 {
@@ -20,6 +24,9 @@ namespace BansheeEngine
 	{
 		metaData.scriptClass->addInternalCall("Internal_CreateObject", &ScriptSerializableProperty::internal_createObject);
 		metaData.scriptClass->addInternalCall("Internal_CreateArray", &ScriptSerializableProperty::internal_createArray);
+		metaData.scriptClass->addInternalCall("Internal_CreateManagedObjectInstance", &ScriptSerializableProperty::internal_createManagedObjectInstance);
+		metaData.scriptClass->addInternalCall("Internal_CreateManagedArrayInstance", &ScriptSerializableProperty::internal_createManagedArrayInstance);
+		metaData.scriptClass->addInternalCall("Internal_CloneManagedInstance", &ScriptSerializableProperty::internal_cloneManagedInstance);
 	}
 
 	ScriptSerializableProperty* ScriptSerializableProperty::create(const ManagedSerializableTypeInfoPtr& typeInfo)
@@ -45,4 +52,36 @@ namespace BansheeEngine
 
 		return newObject->getManagedInstance();
 	}
+
+	MonoObject* ScriptSerializableProperty::internal_createManagedObjectInstance(ScriptSerializableProperty* nativeInstance)
+	{
+		ManagedSerializableTypeInfoObjectPtr objectTypeInfo = std::static_pointer_cast<ManagedSerializableTypeInfoObject>(nativeInstance->mTypeInfo);
+		return ManagedSerializableObject::createManagedInstance(objectTypeInfo);
+	}
+
+	MonoObject* ScriptSerializableProperty::internal_createManagedArrayInstance(ScriptSerializableProperty* nativeInstance, MonoArray* sizes)
+	{
+		Vector<UINT32> nativeSizes;
+		UINT32 arrayLen = (UINT32)mono_array_length(sizes);
+		for (UINT32 i = 0; i < arrayLen; i++)
+			nativeSizes.push_back(mono_array_get(sizes, UINT32, i));
+
+		ManagedSerializableTypeInfoArrayPtr arrayTypeInfo = std::static_pointer_cast<ManagedSerializableTypeInfoArray>(nativeInstance->mTypeInfo);
+		return ManagedSerializableArray::createManagedInstance(arrayTypeInfo, nativeSizes);
+	}
+
+	MonoObject* ScriptSerializableProperty::internal_cloneManagedInstance(ScriptSerializableProperty* nativeInstance, MonoObject* original)
+	{
+		ManagedSerializableFieldDataPtr data = ManagedSerializableFieldData::create(nativeInstance->mTypeInfo, original);
+
+		MemorySerializer ms;
+
+		// Note: This code unnecessarily encodes to binary and decodes from it. I could have added a specialized clone method that does it directly,
+		// but didn't feel the extra code was justified.
+		UINT32 size = 0;
+		UINT8* encodedData = ms.encode(data.get(), size);
+		ManagedSerializableFieldDataPtr clonedData = std::static_pointer_cast<ManagedSerializableFieldData>(ms.decode(encodedData, size));
+
+		return clonedData->getValueBoxed(nativeInstance->mTypeInfo);
+	}
 }