Explorar el Código

Added remaining missing Inspectable and Serializable types

Marko Pintera hace 11 años
padre
commit
698ae1d284
Se han modificado 29 ficheros con 1306 adiciones y 36 borrados
  1. 1 3
      Inspector.txt
  2. 16 16
      MBansheeEditor/Inspector/InspectableArray.cs
  3. 67 0
      MBansheeEditor/Inspector/InspectableBool.cs
  4. 69 0
      MBansheeEditor/Inspector/InspectableColor.cs
  5. 69 0
      MBansheeEditor/Inspector/InspectableFloat.cs
  6. 67 0
      MBansheeEditor/Inspector/InspectableGameObjectRef.cs
  7. 1 1
      MBansheeEditor/Inspector/InspectableInt.cs
  8. 210 0
      MBansheeEditor/Inspector/InspectableList.cs
  9. 38 15
      MBansheeEditor/Inspector/InspectableObject.cs
  10. 20 1
      MBansheeEditor/Inspector/InspectableObjectBase.cs
  11. 67 0
      MBansheeEditor/Inspector/InspectableResourceRef.cs
  12. 69 0
      MBansheeEditor/Inspector/InspectableString.cs
  13. 69 0
      MBansheeEditor/Inspector/InspectableVector2.cs
  14. 69 0
      MBansheeEditor/Inspector/InspectableVector3.cs
  15. 69 0
      MBansheeEditor/Inspector/InspectableVector4.cs
  16. 10 0
      MBansheeEditor/MBansheeEditor.csproj
  17. 27 0
      MBansheeEngine/Color.cs
  18. 2 0
      MBansheeEngine/MBansheeEngine.csproj
  19. 74 0
      MBansheeEngine/SerializableDictionary.cs
  20. 46 0
      MBansheeEngine/SerializableList.cs
  21. 50 0
      MBansheeEngine/SerializableProperty.cs
  22. 23 0
      SBansheeEngine/Include/BsScriptSerializableDictionary.h
  23. 22 0
      SBansheeEngine/Include/BsScriptSerializableList.h
  24. 4 0
      SBansheeEngine/Include/BsScriptSerializableProperty.h
  25. 4 0
      SBansheeEngine/SBansheeEngine.vcxproj
  26. 12 0
      SBansheeEngine/SBansheeEngine.vcxproj.filters
  27. 53 0
      SBansheeEngine/Source/BsScriptSerializableDictionary.cpp
  28. 42 0
      SBansheeEngine/Source/BsScriptSerializableList.cpp
  29. 36 0
      SBansheeEngine/Source/BsScriptSerializableProperty.cpp

+ 1 - 3
Inspector.txt

@@ -4,9 +4,6 @@ Update GUIFoldout with sub styles
 Test if drag and dropping scene objects works with object and resource fields. Especially custom resources and components.
 
 Transient meshes don't seem to be released properly in 100% of the cases
-Finalizers get called from a different thread
- - This is especially noticeable in ScriptManagedResource where I call gResources().unload from that thread. I should probably not be doing that and instead queuing that for later on main thread.
- - I added some code for handling this. It needs testing
 
 Test custom resources:
  - Can I load them? (Will likely need ProjectLIbrary::load)
@@ -15,6 +12,7 @@ Test custom resources:
 ARRAY TODO:
  - Ensure that case when array is null is handled properly. Will likely need a [Create] button. And a [Clear] button?
  - Need a GUIFoldout that doesn't have BG and is just a single button.
+ - Don't render inspector if array is multi-rank
 
 TODO:
  - Add inspector support for lists and objects

+ 16 - 16
MBansheeEditor/Inspector/InspectableArray.cs

@@ -150,30 +150,30 @@ namespace BansheeEditor
             int size = guiSizeField.Value; // TODO - Support multi-rank arrays
 
             Array newArray = property.CreateArrayInstance(new int[] {size});
-            SerializableArray array = property.GetArray();
+            Array array = property.GetValue<Array>();
 
-            int maxSize = MathEx.Min(size, array.GetLength());
+            int maxSize = MathEx.Min(size, array.Length);
 
             for (int i = 0; i < maxSize; i++)
-                newArray.SetValue(array.GetProperty(i).GetValue<object>(), i);
+                newArray.SetValue(array.GetValue(i), i);
 
             property.SetValue(newArray);
         }
 
         private void OnDeleteButtonClicked(int index)
         {
-            SerializableArray array = property.GetArray();
+            Array array = property.GetValue<Array>();
 
-            int size = MathEx.Max(0, array.GetLength() - 1);
+            int size = MathEx.Max(0, array.Length - 1);
             Array newArray = property.CreateArrayInstance(new int[] { size });
 
             int destIdx = 0;
-            for (int i = 0; i < array.GetLength(); i++)
+            for (int i = 0; i < array.Length; i++)
             {
                 if (i == index)
                     continue;
 
-                newArray.SetValue(array.GetProperty(i).GetValue<object>(), destIdx);
+                newArray.SetValue(array.GetValue(i), destIdx);
                 destIdx++;
             }
 
@@ -207,27 +207,27 @@ namespace BansheeEditor
 
         private void OnMoveUpButtonClicked(int index)
         {
-            SerializableArray array = property.GetArray();
+            Array array = property.GetValue<Array>();
 
             if ((index - 1) >= 0)
             {
-                object previousEntry = array.GetProperty(index - 1).GetValue<object>();
+                object previousEntry = array.GetValue(index - 1);
 
-                array.GetProperty(index - 1).SetValue(array.GetProperty(index).GetValue<object>());
-                array.GetProperty(index).SetValue(previousEntry);
+                array.SetValue(array.GetValue(index), index - 1);
+                array.SetValue(previousEntry, index);
             }
         }
 
         private void OnMoveDownButtonClicked(int index)
         {
-            SerializableArray array = property.GetArray();
+            Array array = property.GetValue<Array>();
 
-            if ((index + 1) < array.GetLength())
+            if ((index + 1) < array.Length)
             {
-                object nextEntry = array.GetProperty(index + 1).GetValue<object>();
+                object nextEntry = array.GetValue(index + 1);
 
-                array.GetProperty(index + 1).SetValue(array.GetProperty(index).GetValue<object>());
-                array.GetProperty(index).SetValue(nextEntry);
+                array.SetValue(array.GetValue(index), index + 1);
+                array.SetValue(nextEntry, index);
             }
         }
     }

+ 67 - 0
MBansheeEditor/Inspector/InspectableBool.cs

@@ -0,0 +1,67 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using BansheeEngine;
+
+namespace BansheeEditor
+{
+    public class InspectableBool : InspectableObjectBase
+    {
+        private bool oldPropertyValue;
+        private GUIToggleField guiField;
+        private bool isInitialized;
+
+        public InspectableBool(string title, InspectableFieldLayout layout, SerializableProperty property)
+            : base(title, layout, property)
+        {
+
+        }
+
+        private void Initialize(int layoutIndex)
+        {
+            if (property.Type == SerializableProperty.FieldType.Bool)
+            {
+                guiField = new GUIToggleField(new GUIContent(title));
+                guiField.OnChanged += OnFieldValueChanged;
+
+                layout.AddElement(layoutIndex, guiField);
+            }
+
+            isInitialized = true;
+        }
+
+        protected override bool IsModified()
+        {
+            if (!isInitialized)
+                return true;
+
+            bool newPropertyValue = property.GetValue<bool>();
+            if (oldPropertyValue != newPropertyValue)
+            {
+                oldPropertyValue = newPropertyValue;
+
+                return true;
+            }
+
+            return base.IsModified();
+        }
+
+        protected override void Update(int layoutIndex)
+        {
+            base.Update(layoutIndex);
+
+            if (!isInitialized)
+                Initialize(layoutIndex);
+
+            if (guiField != null)
+                guiField.Value = property.GetValue<bool>();
+        }
+
+        private void OnFieldValueChanged(bool newValue)
+        {
+            property.SetValue(newValue);
+        }
+    }
+}

+ 69 - 0
MBansheeEditor/Inspector/InspectableColor.cs

@@ -0,0 +1,69 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using BansheeEngine;
+
+namespace BansheeEditor
+{
+    public class InspectableColor : InspectableObjectBase
+    {
+        private Color oldPropertyValue;
+        private GUIColorField guiField;
+        private bool isInitialized;
+
+        public InspectableColor(string title, InspectableFieldLayout layout, SerializableProperty property)
+            : base(title, layout, property)
+        {
+
+        }
+
+        private void Initialize(int layoutIndex)
+        {
+            if (property.Type == SerializableProperty.FieldType.Color)
+            {
+                guiField = new GUIColorField(new GUIContent(title));
+                guiField.OnChanged += OnFieldValueChanged;
+
+                layout.AddElement(layoutIndex, guiField);
+            }
+
+            isInitialized = true;
+        }
+
+        protected override bool IsModified()
+        {
+            if (!isInitialized)
+                return true;
+
+            Color newPropertyValue = property.GetValue<Color>();
+            if (oldPropertyValue != newPropertyValue)
+            {
+                oldPropertyValue = newPropertyValue;
+
+                return true;
+            }
+
+            return base.IsModified();
+        }
+
+        protected override void Update(int layoutIndex)
+        {
+            base.Update(layoutIndex);
+
+            if (!isInitialized)
+                Initialize(layoutIndex);
+
+            // TODO - Skip update if it currently has input focus so user can modify the value in peace
+
+            if (guiField != null)
+                guiField.Value = property.GetValue<Color>();
+        }
+
+        private void OnFieldValueChanged(Color newValue)
+        {
+            property.SetValue(newValue);
+        }
+    }
+}

+ 69 - 0
MBansheeEditor/Inspector/InspectableFloat.cs

@@ -0,0 +1,69 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using BansheeEngine;
+
+namespace BansheeEditor
+{
+    public class InspectableFloat : InspectableObjectBase
+    {
+        private float oldPropertyValue;
+        private GUIFloatField guiFloatField;
+        private bool isInitialized;
+
+        public InspectableFloat(string title, InspectableFieldLayout layout, SerializableProperty property)
+            : base(title, layout, property)
+        {
+
+        }
+
+        private void Initialize(int layoutIndex)
+        {
+            if (property.Type == SerializableProperty.FieldType.Float)
+            {
+                guiFloatField = new GUIFloatField(new GUIContent(title));
+                guiFloatField.OnChanged += OnFieldValueChanged;
+
+                layout.AddElement(layoutIndex, guiFloatField);
+            }
+
+            isInitialized = true;
+        }
+
+        protected override bool IsModified()
+        {
+            if (!isInitialized)
+                return true;
+
+            float newPropertyValue = property.GetValue<float>();
+            if (oldPropertyValue != newPropertyValue)
+            {
+                oldPropertyValue = newPropertyValue;
+
+                return true;
+            }
+
+            return base.IsModified();
+        }
+
+        protected override void Update(int layoutIndex)
+        {
+            base.Update(layoutIndex);
+
+            if (!isInitialized)
+                Initialize(layoutIndex);
+
+            // TODO - Skip update if it currently has input focus so user can modify the value in peace
+
+            if (guiFloatField != null)
+                guiFloatField.Value = property.GetValue<float>();
+        }
+
+        private void OnFieldValueChanged(float newValue)
+        {
+            property.SetValue(newValue);
+        }
+    }
+}

+ 67 - 0
MBansheeEditor/Inspector/InspectableGameObjectRef.cs

@@ -0,0 +1,67 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using BansheeEngine;
+
+namespace BansheeEditor
+{
+    public class InspectableGameObjectRef : InspectableObjectBase
+    {
+        private GameObject oldPropertyValue;
+        private GUIGameObjectField guiField;
+        private bool isInitialized;
+
+        public InspectableGameObjectRef(string title, InspectableFieldLayout layout, SerializableProperty property)
+            : base(title, layout, property)
+        {
+
+        }
+
+        private void Initialize(int layoutIndex)
+        {
+            if (property.Type == SerializableProperty.FieldType.GameObjectRef)
+            {
+                guiField = new GUIGameObjectField(property.InternalType, new GUIContent(title));
+                guiField.OnChanged += OnFieldValueChanged;
+
+                layout.AddElement(layoutIndex, guiField);
+            }
+
+            isInitialized = true;
+        }
+
+        protected override bool IsModified()
+        {
+            if (!isInitialized)
+                return true;
+
+            GameObject newPropertyValue = property.GetValue<GameObject>();
+            if (oldPropertyValue != newPropertyValue)
+            {
+                oldPropertyValue = newPropertyValue;
+
+                return true;
+            }
+
+            return base.IsModified();
+        }
+
+        protected override void Update(int layoutIndex)
+        {
+            base.Update(layoutIndex);
+
+            if (!isInitialized)
+                Initialize(layoutIndex);
+
+            if (guiField != null)
+                guiField.Value = property.GetValue<GameObject>();
+        }
+
+        private void OnFieldValueChanged(GameObject newValue)
+        {
+            property.SetValue(newValue);
+        }
+    }
+}

+ 1 - 1
MBansheeEditor/Inspector/InspectableInt.cs

@@ -63,7 +63,7 @@ namespace BansheeEditor
 
         private void OnFieldValueChanged(int newValue)
         {
-            property.SetValue<int>(newValue);
+            property.SetValue(newValue);
         }
     }
 }

+ 210 - 0
MBansheeEditor/Inspector/InspectableList.cs

@@ -0,0 +1,210 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using BansheeEngine;
+
+namespace BansheeEditor
+{
+    public class InspectableList : 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, int seqIndex, InspectableList parent)
+            {
+                rowLayout = parentLayout.AddLayoutX();
+                contentLayout = rowLayout.AddLayoutY();
+                cloneBtn = new GUIButton("C");
+                deleteBtn = new GUIButton("X");
+                moveUpBtn = new GUIButton("Up");
+                moveDownBtn = new GUIButton("Down");
+
+                cloneBtn.OnClick += () => parent.OnCloneButtonClicked(seqIndex);
+                deleteBtn.OnClick += () => parent.OnDeleteButtonClicked(seqIndex);
+                moveUpBtn.OnClick += () => parent.OnMoveUpButtonClicked(seqIndex);
+                moveDownBtn.OnClick += () => parent.OnMoveDownButtonClicked(seqIndex);
+
+                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 InspectableList(string title, InspectableFieldLayout layout, SerializableProperty property)
+            : base(title, layout, property)
+        {
+
+        }
+
+        private void Initialize(int layoutIndex)
+        {
+            if (property.Type != SerializableProperty.FieldType.List)
+                return;
+
+            guiLabel = new GUILabel(title); // TODO - Add foldout and hook up its callbacks
+            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);
+
+            guiChildLayout.AddSpace(IndentAmount);
+            guiContentLayout = guiChildLayout.AddLayoutY();
+
+            isInitialized = true;
+        }
+
+        protected override bool IsModified()
+        {
+            if (!isInitialized)
+                return true;
+
+            object newPropertyValue = property.GetValue<object>();
+            if (oldPropertyValue != newPropertyValue)
+            {
+                oldPropertyValue = newPropertyValue;
+
+                return true;
+            }
+
+            SerializableList list = property.GetList();
+            if (list.GetLength() != numArrayElements)
+                return true;
+
+            return base.IsModified();
+        }
+
+        protected override void Update(int layoutIndex)
+        {
+            base.Update(layoutIndex);
+
+            if (!isInitialized)
+                Initialize(layoutIndex);
+
+            foreach (var row in rows)
+                row.Destroy();
+
+            rows.Clear();
+
+            SerializableList list = property.GetList();
+
+            numArrayElements = list.GetLength();
+            for (int i = 0; i < numArrayElements; i++)
+            {
+                EntryRow newRow = new EntryRow(guiContentLayout, i, this);
+                rows.Add(newRow);
+
+                InspectableObjectBase childObj = CreateDefaultInspectable(i + ".", new InspectableFieldLayout(newRow.contentLayout), list.GetProperty(i));
+                AddChild(childObj);
+
+                childObj.Refresh(0);
+            }
+
+            guiSizeField.Value = numArrayElements;
+        }
+
+        private void OnResizeButtonClicked()
+        {
+            int size = guiSizeField.Value;
+
+            IList newList = property.CreateListInstance(size);
+            IList list = property.GetValue<IList>();
+
+            int maxSize = MathEx.Min(size, list.Count);
+
+            for (int i = 0; i < maxSize; i++)
+                newList[i] = list[i];
+
+            property.SetValue(newList);
+        }
+
+        private void OnDeleteButtonClicked(int index)
+        {
+            IList list = property.GetValue<IList>();
+
+            if (index >= 0 && index < list.Count)
+                list.RemoveAt(index);
+        }
+
+        private void OnCloneButtonClicked(int index)
+        {
+            SerializableList serializableList = property.GetList();
+            IList list = property.GetValue<IList>();
+
+            int size = serializableList.GetLength() + 1;
+
+            if (index >= 0 && index < list.Count)
+            {
+                list.Add(serializableList.GetProperty(index).GetValueCopy<object>());
+            }
+        }
+
+        private void OnMoveUpButtonClicked(int index)
+        {
+            IList list = property.GetValue<IList>();
+
+            if ((index - 1) >= 0)
+            {
+                object previousEntry = list[index - 1];
+
+                list[index - 1] = list[index];
+                list[index] = previousEntry;
+            }
+        }
+
+        private void OnMoveDownButtonClicked(int index)
+        {
+            IList list = property.GetValue<IList>();
+
+            if ((index + 1) < list.Count)
+            {
+                object nextEntry = list[index + 1];
+
+                list[index + 1] = list[index];
+                list[index] = nextEntry;
+            }
+        }
+    }
+}

+ 38 - 15
MBansheeEditor/Inspector/InspectableObject.cs

@@ -9,6 +9,21 @@ namespace BansheeEditor
 {
     public class InspectableObject : InspectableObjectBase
     {
+        private class FieldRow
+        {
+            public GUILayoutY layout;
+
+            public FieldRow(GUILayout parentLayout)
+            {
+                layout = parentLayout.AddLayoutY();
+            }
+
+            public void Destroy()
+            {
+                layout.Destroy();
+            }
+        }
+
         private const int IndentAmount = 15;
 
         private object oldPropertyValue;
@@ -18,6 +33,8 @@ namespace BansheeEditor
         private GUILayoutY guiContentLayout;
         private bool isInitialized;
 
+        private List<FieldRow> rows = new List<FieldRow>();
+
         public InspectableObject(string title, InspectableFieldLayout layout, SerializableProperty property)
             : base(title, layout, property)
         {
@@ -29,7 +46,7 @@ namespace BansheeEditor
             if (property.Type != SerializableProperty.FieldType.Object)
                 return;
 
-            guiLabel = new GUILabel(title);
+            guiLabel = new GUILabel(title); // TODO - Use foldout
             layout.AddElement(layoutIndex, guiLabel);
 
             guiChildLayout = layout.AddLayoutX(layoutIndex);
@@ -37,19 +54,6 @@ namespace BansheeEditor
 
             guiContentLayout = guiChildLayout.AddLayoutY();
 
-            SerializableObject serializableObject = property.GetObject();
-
-            foreach (var field in serializableObject.fields)
-            {
-                if (!field.Inspectable)
-                    continue;
-
-                if (field.HasCustomInspector)
-                    AddChild(CreateCustomInspectable(field.CustomInspectorType, field.Name, new InspectableFieldLayout(guiContentLayout), field.GetProperty()));
-                else
-                    AddChild(CreateDefaultInspectable(field.Name, new InspectableFieldLayout(guiContentLayout), field.GetProperty()));
-            }
-
             isInitialized = true;
         }
 
@@ -76,7 +80,26 @@ namespace BansheeEditor
             if (!isInitialized)
                 Initialize(index);
 
-            // TODO - Update GUI element(s) with value from property
+            foreach (var row in rows)
+                row.Destroy();
+
+            rows.Clear();
+
+            SerializableObject serializableObject = property.GetObject();
+
+            foreach (var field in serializableObject.fields)
+            {
+                if (!field.Inspectable)
+                    continue;
+
+                FieldRow newRow = new FieldRow(guiContentLayout);
+                rows.Add(newRow);
+
+                if (field.HasCustomInspector)
+                    AddChild(CreateCustomInspectable(field.CustomInspectorType, field.Name, new InspectableFieldLayout(newRow.layout), field.GetProperty()));
+                else
+                    AddChild(CreateDefaultInspectable(field.Name, new InspectableFieldLayout(newRow.layout), field.GetProperty()));
+            }
         }
     }
 }

+ 20 - 1
MBansheeEditor/Inspector/InspectableObjectBase.cs

@@ -103,11 +103,30 @@ namespace BansheeEditor
             {
                 case SerializableProperty.FieldType.Int:
                     return new InspectableInt(title, layout, property);
+                case SerializableProperty.FieldType.Float:
+                    return new InspectableFloat(title, layout, property);
+                case SerializableProperty.FieldType.Bool:
+                    return new InspectableBool(title, layout, property);
+                case SerializableProperty.FieldType.Color:
+                    return new InspectableColor(title, layout, property);
+                case SerializableProperty.FieldType.String:
+                    return new InspectableString(title, layout, property);
+                case SerializableProperty.FieldType.Vector2:
+                    return new InspectableVector2(title, layout, property);
+                case SerializableProperty.FieldType.Vector3:
+                    return new InspectableVector3(title, layout, property);
+                case SerializableProperty.FieldType.Vector4:
+                    return new InspectableVector4(title, layout, property);
+                case SerializableProperty.FieldType.ResourceRef:
+                    return new InspectableResourceRef(title, layout, property);
+                case SerializableProperty.FieldType.GameObjectRef:
+                    return new InspectableGameObjectRef(title, layout, property);
                 case SerializableProperty.FieldType.Object:
                     return new InspectableObject(title, layout, property);
                 case SerializableProperty.FieldType.Array:
                     return new InspectableArray(title, layout, property);
-                // TODO - Add all other types
+                case SerializableProperty.FieldType.List:
+                    return new InspectableList(title, layout, property);
             }
 
             throw new Exception("No inspector exists for the provided field type.");

+ 67 - 0
MBansheeEditor/Inspector/InspectableResourceRef.cs

@@ -0,0 +1,67 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using BansheeEngine;
+
+namespace BansheeEditor
+{
+    public class InspectableResourceRef : InspectableObjectBase
+    {
+        private Resource oldPropertyValue;
+        private GUIResourceField guiField;
+        private bool isInitialized;
+
+        public InspectableResourceRef(string title, InspectableFieldLayout layout, SerializableProperty property)
+            : base(title, layout, property)
+        {
+
+        }
+
+        private void Initialize(int layoutIndex)
+        {
+            if (property.Type == SerializableProperty.FieldType.ResourceRef)
+            {
+                guiField = new GUIResourceField(property.InternalType, new GUIContent(title));
+                guiField.OnChanged += OnFieldValueChanged;
+
+                layout.AddElement(layoutIndex, guiField);
+            }
+
+            isInitialized = true;
+        }
+
+        protected override bool IsModified()
+        {
+            if (!isInitialized)
+                return true;
+
+            Resource newPropertyValue = property.GetValue<Resource>();
+            if (oldPropertyValue != newPropertyValue)
+            {
+                oldPropertyValue = newPropertyValue;
+
+                return true;
+            }
+
+            return base.IsModified();
+        }
+
+        protected override void Update(int layoutIndex)
+        {
+            base.Update(layoutIndex);
+
+            if (!isInitialized)
+                Initialize(layoutIndex);
+
+            if (guiField != null)
+                guiField.Value = property.GetValue<Resource>();
+        }
+
+        private void OnFieldValueChanged(Resource newValue)
+        {
+            property.SetValue(newValue);
+        }
+    }
+}

+ 69 - 0
MBansheeEditor/Inspector/InspectableString.cs

@@ -0,0 +1,69 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using BansheeEngine;
+
+namespace BansheeEditor
+{
+    public class InspectableString : InspectableObjectBase
+    {
+        private string oldPropertyValue;
+        private GUITextField guiField;
+        private bool isInitialized;
+
+        public InspectableString(string title, InspectableFieldLayout layout, SerializableProperty property)
+            : base(title, layout, property)
+        {
+
+        }
+
+        private void Initialize(int layoutIndex)
+        {
+            if (property.Type == SerializableProperty.FieldType.String)
+            {
+                guiField = new GUITextField(new GUIContent(title));
+                guiField.OnChanged += OnFieldValueChanged;
+
+                layout.AddElement(layoutIndex, guiField);
+            }
+
+            isInitialized = true;
+        }
+
+        protected override bool IsModified()
+        {
+            if (!isInitialized)
+                return true;
+
+            string newPropertyValue = property.GetValue<string>();
+            if (oldPropertyValue != newPropertyValue)
+            {
+                oldPropertyValue = newPropertyValue;
+
+                return true;
+            }
+
+            return base.IsModified();
+        }
+
+        protected override void Update(int layoutIndex)
+        {
+            base.Update(layoutIndex);
+
+            if (!isInitialized)
+                Initialize(layoutIndex);
+
+            // TODO - Skip update if it currently has input focus so user can modify the value in peace
+
+            if (guiField != null)
+                guiField.Value = property.GetValue<string>();
+        }
+
+        private void OnFieldValueChanged(string newValue)
+        {
+            property.SetValue(newValue);
+        }
+    }
+}

+ 69 - 0
MBansheeEditor/Inspector/InspectableVector2.cs

@@ -0,0 +1,69 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using BansheeEngine;
+
+namespace BansheeEditor
+{
+    public class InspectableVector2 : InspectableObjectBase
+    {
+        private Vector2 oldPropertyValue;
+        private GUIVector2Field guiField;
+        private bool isInitialized;
+
+        public InspectableVector2(string title, InspectableFieldLayout layout, SerializableProperty property)
+            : base(title, layout, property)
+        {
+
+        }
+
+        private void Initialize(int layoutIndex)
+        {
+            if (property.Type == SerializableProperty.FieldType.Vector2)
+            {
+                guiField = new GUIVector2Field(new GUIContent(title));
+                guiField.OnChanged += OnFieldValueChanged;
+
+                layout.AddElement(layoutIndex, guiField);
+            }
+
+            isInitialized = true;
+        }
+
+        protected override bool IsModified()
+        {
+            if (!isInitialized)
+                return true;
+
+            Vector2 newPropertyValue = property.GetValue<Vector2>();
+            if (oldPropertyValue != newPropertyValue)
+            {
+                oldPropertyValue = newPropertyValue;
+
+                return true;
+            }
+
+            return base.IsModified();
+        }
+
+        protected override void Update(int layoutIndex)
+        {
+            base.Update(layoutIndex);
+
+            if (!isInitialized)
+                Initialize(layoutIndex);
+
+            // TODO - Skip update if it currently has input focus so user can modify the value in peace
+
+            if (guiField != null)
+                guiField.Value = property.GetValue<Vector2>();
+        }
+
+        private void OnFieldValueChanged(Vector2 newValue)
+        {
+            property.SetValue(newValue);
+        }
+    }
+}

+ 69 - 0
MBansheeEditor/Inspector/InspectableVector3.cs

@@ -0,0 +1,69 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using BansheeEngine;
+
+namespace BansheeEditor
+{
+    public class InspectableVector3 : InspectableObjectBase
+    {
+        private Vector3 oldPropertyValue;
+        private GUIVector3Field guiField;
+        private bool isInitialized;
+
+        public InspectableVector3(string title, InspectableFieldLayout layout, SerializableProperty property)
+            : base(title, layout, property)
+        {
+
+        }
+
+        private void Initialize(int layoutIndex)
+        {
+            if (property.Type == SerializableProperty.FieldType.Vector3)
+            {
+                guiField = new GUIVector3Field(new GUIContent(title));
+                guiField.OnChanged += OnFieldValueChanged;
+
+                layout.AddElement(layoutIndex, guiField);
+            }
+
+            isInitialized = true;
+        }
+
+        protected override bool IsModified()
+        {
+            if (!isInitialized)
+                return true;
+
+            Vector3 newPropertyValue = property.GetValue<Vector3>();
+            if (oldPropertyValue != newPropertyValue)
+            {
+                oldPropertyValue = newPropertyValue;
+
+                return true;
+            }
+
+            return base.IsModified();
+        }
+
+        protected override void Update(int layoutIndex)
+        {
+            base.Update(layoutIndex);
+
+            if (!isInitialized)
+                Initialize(layoutIndex);
+
+            // TODO - Skip update if it currently has input focus so user can modify the value in peace
+
+            if (guiField != null)
+                guiField.Value = property.GetValue<Vector3>();
+        }
+
+        private void OnFieldValueChanged(Vector3 newValue)
+        {
+            property.SetValue(newValue);
+        }
+    }
+}

+ 69 - 0
MBansheeEditor/Inspector/InspectableVector4.cs

@@ -0,0 +1,69 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using BansheeEngine;
+
+namespace BansheeEditor
+{
+    public class InspectableVector4 : InspectableObjectBase
+    {
+        private Vector4 oldPropertyValue;
+        private GUIVector4Field guiField;
+        private bool isInitialized;
+
+        public InspectableVector4(string title, InspectableFieldLayout layout, SerializableProperty property)
+            : base(title, layout, property)
+        {
+
+        }
+
+        private void Initialize(int layoutIndex)
+        {
+            if (property.Type == SerializableProperty.FieldType.Vector4)
+            {
+                guiField = new GUIVector4Field(new GUIContent(title));
+                guiField.OnChanged += OnFieldValueChanged;
+
+                layout.AddElement(layoutIndex, guiField);
+            }
+
+            isInitialized = true;
+        }
+
+        protected override bool IsModified()
+        {
+            if (!isInitialized)
+                return true;
+
+            Vector4 newPropertyValue = property.GetValue<Vector4>();
+            if (oldPropertyValue != newPropertyValue)
+            {
+                oldPropertyValue = newPropertyValue;
+
+                return true;
+            }
+
+            return base.IsModified();
+        }
+
+        protected override void Update(int layoutIndex)
+        {
+            base.Update(layoutIndex);
+
+            if (!isInitialized)
+                Initialize(layoutIndex);
+
+            // TODO - Skip update if it currently has input focus so user can modify the value in peace
+
+            if (guiField != null)
+                guiField.Value = property.GetValue<Vector4>();
+        }
+
+        private void OnFieldValueChanged(Vector4 newValue)
+        {
+            property.SetValue(newValue);
+        }
+    }
+}

+ 10 - 0
MBansheeEditor/MBansheeEditor.csproj

@@ -61,10 +61,20 @@
     <Compile Include="Inspector\CustomInspector.cs" />
     <Compile Include="Inspector\GenericInspector.cs" />
     <Compile Include="Inspector\InspectableArray.cs" />
+    <Compile Include="Inspector\InspectableBool.cs" />
+    <Compile Include="Inspector\InspectableColor.cs" />
     <Compile Include="Inspector\InspectableFieldLayout.cs" />
+    <Compile Include="Inspector\InspectableFloat.cs" />
+    <Compile Include="Inspector\InspectableGameObjectRef.cs" />
+    <Compile Include="Inspector\InspectableList.cs" />
     <Compile Include="Inspector\InspectableObject.cs" />
     <Compile Include="Inspector\InspectableObjectBase.cs" />
     <Compile Include="Inspector\InspectableInt.cs" />
+    <Compile Include="Inspector\InspectableResourceRef.cs" />
+    <Compile Include="Inspector\InspectableString.cs" />
+    <Compile Include="Inspector\InspectableVector2.cs" />
+    <Compile Include="Inspector\InspectableVector3.cs" />
+    <Compile Include="Inspector\InspectableVector4.cs" />
     <Compile Include="Inspector\Inspector.cs" />
     <Compile Include="Inspector\InspectorWindow.cs" />
     <Compile Include="Program.cs" />

+ 27 - 0
MBansheeEngine/Color.cs

@@ -136,5 +136,32 @@ namespace BansheeEngine
         {
             return new Color(a.r / b, a.g / b, a.b / b, a.a / b);
         }
+
+        public static bool operator ==(Color lhs, Color rhs)
+        {
+            return lhs.r == rhs.r && lhs.g == rhs.g && lhs.b == rhs.b && lhs.a == rhs.a;
+        }
+
+        public static bool operator !=(Color lhs, Color rhs)
+        {
+            return !(lhs == rhs);
+        }
+
+        public override int GetHashCode()
+        {
+            return r.GetHashCode() ^ g.GetHashCode() << 2 ^ b.GetHashCode() >> 2 ^ a.GetHashCode() >> 1;
+        }
+
+        public override bool Equals(object other)
+        {
+            if (!(other is Color))
+                return false;
+
+            Color color = (Color)other;
+            if (r.Equals(color.r) && g.Equals(color.g) && b.Equals(color.b) && a.Equals(color.a))
+                return true;
+
+            return false;
+        }
     }
 }

+ 2 - 0
MBansheeEngine/MBansheeEngine.csproj

@@ -89,7 +89,9 @@
     <Compile Include="SceneObject.cs" />
     <Compile Include="ScriptObject.cs" />
     <Compile Include="SerializableArray.cs" />
+    <Compile Include="SerializableDictionary.cs" />
     <Compile Include="SerializableField.cs" />
+    <Compile Include="SerializableList.cs" />
     <Compile Include="SerializableObject.cs" />
     <Compile Include="SerializableProperty.cs" />
     <Compile Include="SerializeObject.cs" />

+ 74 - 0
MBansheeEngine/SerializableDictionary.cs

@@ -0,0 +1,74 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Runtime.CompilerServices;
+
+namespace BansheeEngine
+{
+#pragma warning disable 649
+    public sealed class SerializableDictionary : ScriptObject
+    {
+        private SerializableProperty.FieldType keyType;
+        private SerializableProperty.FieldType valueType;
+        private Type internalKeyType;
+        private Type internalValueType;
+        private IDictionary referencedDict;
+
+        public SerializableProperty.FieldType KeyType
+        {
+            get { return keyType; }
+        }
+
+        public SerializableProperty.FieldType ValueType
+        {
+            get { return valueType; }
+        }
+
+        // Constructed from native code
+        private SerializableDictionary(IDictionary dict, Type internalKeyType, Type internalValueType)
+        {
+            referencedDict = dict;
+            this.internalKeyType = internalKeyType;
+            this.internalValueType = internalValueType;
+            keyType = SerializableProperty.DetermineFieldType(internalKeyType);
+            valueType = SerializableProperty.DetermineFieldType(internalValueType);
+        }
+
+        public KeyValuePair<SerializableProperty, SerializableProperty> GetProperty(object key)
+        {
+            if (!referencedDict.Contains(key))
+                return new KeyValuePair<SerializableProperty, SerializableProperty>(null, null);
+
+            SerializableProperty keyProperty;
+            {
+                SerializableProperty.Getter getter = () => key;
+                SerializableProperty.Setter setter = (object value) => {};
+
+                keyProperty = Internal_CreateKeyProperty(mCachedPtr);
+                keyProperty.Construct(KeyType, internalKeyType, getter, setter);
+            }
+
+            SerializableProperty valueProperty;
+            {
+                SerializableProperty.Getter getter = () => referencedDict[key];
+                SerializableProperty.Setter setter = (object value) => referencedDict[key] = value;
+
+                valueProperty = Internal_CreateValueProperty(mCachedPtr);
+                valueProperty.Construct(ValueType, internalValueType, getter, setter);
+            }
+
+            return new KeyValuePair<SerializableProperty, SerializableProperty>(keyProperty, valueProperty);
+        }
+
+        public int GetLength()
+        {
+            return referencedDict.Count;
+        }
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern SerializableProperty Internal_CreateKeyProperty(IntPtr nativeInstance);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern SerializableProperty Internal_CreateValueProperty(IntPtr nativeInstance);
+    }
+}

+ 46 - 0
MBansheeEngine/SerializableList.cs

@@ -0,0 +1,46 @@
+using System;
+using System.Collections;
+using System.Runtime.CompilerServices;
+
+namespace BansheeEngine
+{
+#pragma warning disable 649
+    public sealed class SerializableList : ScriptObject
+    {
+        private SerializableProperty.FieldType elementType;
+        private Type internalElementType;
+        private IList referencedList;
+
+        public SerializableProperty.FieldType ElementType
+        {
+            get { return elementType; }
+        }
+
+        // Constructed from native code
+        private SerializableList(IList list, Type internalElementType)
+        {
+            referencedList = list;
+            this.internalElementType = internalElementType;
+            elementType = SerializableProperty.DetermineFieldType(internalElementType);
+        }
+
+        public SerializableProperty GetProperty(int elementIdx)
+        {
+            SerializableProperty.Getter getter = () => referencedList[elementIdx];
+            SerializableProperty.Setter setter = (object value) => referencedList[elementIdx] = value;
+
+            SerializableProperty property = Internal_CreateProperty(mCachedPtr);
+            property.Construct(ElementType, internalElementType, getter, setter);
+
+            return property;
+        }
+
+        public int GetLength()
+        {
+            return referencedList.Count;
+        }
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern SerializableProperty Internal_CreateProperty(IntPtr nativeInstance);
+    }
+}

+ 50 - 0
MBansheeEngine/SerializableProperty.cs

@@ -1,4 +1,5 @@
 using System;
+using System.Collections;
 using System.Collections.Generic;
 using System.Linq;
 using System.Runtime.CompilerServices;
@@ -51,6 +52,11 @@ namespace BansheeEngine
             get { return type; }
         }
 
+        public Type InternalType
+        {
+            get { return internalType; }
+        }
+
         public T GetValue<T>()
         {
             if (!typeof(T).IsAssignableFrom(internalType))
@@ -91,6 +97,22 @@ namespace BansheeEngine
             return Internal_CreateArray(mCachedPtr, GetValue<Array>());
         }
 
+        public SerializableList GetList()
+        {
+            if (type != FieldType.List)
+                throw new Exception("Attempting to retrieve array information from a field that doesn't contain a list.");
+
+            return Internal_CreateList(mCachedPtr, GetValue<IList>());
+        }
+
+        public SerializableDictionary GetDictionary()
+        {
+            if (type != FieldType.Dictionary)
+                throw new Exception("Attempting to retrieve array information from a field that doesn't contain a dictionary.");
+
+            return Internal_CreateDictionary(mCachedPtr, GetValue<IDictionary>());
+        }
+
         public T CreateObjectInstance<T>()
         {
             if (type != FieldType.Object)
@@ -107,18 +129,46 @@ namespace BansheeEngine
             return Internal_CreateManagedArrayInstance(mCachedPtr, lengths);
         }
 
+        public IList CreateListInstance(int length)
+        {
+            if (type != FieldType.List)
+                throw new Exception("Attempting to retrieve array information from a field that doesn't contain a list.");
+
+            return Internal_CreateManagedListInstance(mCachedPtr, length);
+        }
+
+        public IDictionary CreateDictionaryInstance()
+        {
+            if (type != FieldType.Dictionary)
+                throw new Exception("Attempting to retrieve array information from a field that doesn't contain a dictionary.");
+
+            return Internal_CreateManagedDictionaryInstance(mCachedPtr);
+        }
+
         [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 SerializableList Internal_CreateList(IntPtr nativeInstance, IList instance);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern SerializableDictionary Internal_CreateDictionary(IntPtr nativeInstance, IDictionary 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 IList Internal_CreateManagedListInstance(IntPtr nativeInstance, int length);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern IDictionary Internal_CreateManagedDictionaryInstance(IntPtr nativeInstance);
+
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern object Internal_CloneManagedInstance(IntPtr nativeInstance, object original);
 

+ 23 - 0
SBansheeEngine/Include/BsScriptSerializableDictionary.h

@@ -0,0 +1,23 @@
+#pragma once
+
+#include "BsScriptEnginePrerequisites.h"
+#include "BsScriptObject.h"
+
+namespace BansheeEngine
+{
+	class BS_SCR_BE_EXPORT ScriptSerializableDictionary : public ScriptObject<ScriptSerializableDictionary>
+	{
+	public:
+		SCRIPT_OBJ(BansheeEngineAssemblyName, "BansheeEngine", "SerializableDictionary")
+
+		static ScriptSerializableDictionary* create(const ManagedSerializableTypeInfoDictionaryPtr& typeInfo, MonoObject* object);
+
+	private:
+		static MonoObject* internal_createKeyProperty(ScriptSerializableDictionary* nativeInstance);
+		static MonoObject* internal_createValueProperty(ScriptSerializableDictionary* nativeInstance);
+
+		ScriptSerializableDictionary(MonoObject* instance, const ManagedSerializableTypeInfoDictionaryPtr& typeInfo);
+
+		ManagedSerializableTypeInfoDictionaryPtr mTypeInfo;
+	};
+}

+ 22 - 0
SBansheeEngine/Include/BsScriptSerializableList.h

@@ -0,0 +1,22 @@
+#pragma once
+
+#include "BsScriptEnginePrerequisites.h"
+#include "BsScriptObject.h"
+
+namespace BansheeEngine
+{
+	class BS_SCR_BE_EXPORT ScriptSerializableList : public ScriptObject<ScriptSerializableList>
+	{
+	public:
+		SCRIPT_OBJ(BansheeEngineAssemblyName, "BansheeEngine", "SerializableList")
+
+			static ScriptSerializableList* create(const ManagedSerializableTypeInfoListPtr& typeInfo, MonoObject* object);
+
+	private:
+		static MonoObject* internal_createProperty(ScriptSerializableList* nativeInstance);
+
+		ScriptSerializableList(MonoObject* instance, const ManagedSerializableTypeInfoListPtr& typeInfo);
+
+		ManagedSerializableTypeInfoListPtr mTypeInfo;
+	};
+}

+ 4 - 0
SBansheeEngine/Include/BsScriptSerializableProperty.h

@@ -17,9 +17,13 @@ namespace BansheeEngine
 	private:
 		static MonoObject* internal_createObject(ScriptSerializableProperty* nativeInstance, MonoObject* object);
 		static MonoObject* internal_createArray(ScriptSerializableProperty* nativeInstance, MonoObject* object);
+		static MonoObject* internal_createList(ScriptSerializableProperty* nativeInstance, MonoObject* object);
+		static MonoObject* internal_createDictionary(ScriptSerializableProperty* nativeInstance, MonoObject* object);
 
 		static MonoObject* internal_createManagedObjectInstance(ScriptSerializableProperty* nativeInstance);
 		static MonoObject* internal_createManagedArrayInstance(ScriptSerializableProperty* nativeInstance, MonoArray* sizes);
+		static MonoObject* internal_createManagedListInstance(ScriptSerializableProperty* nativeInstance, int size);
+		static MonoObject* internal_createManagedDictionaryInstance(ScriptSerializableProperty* nativeInstance);
 
 		static MonoObject* internal_cloneManagedInstance(ScriptSerializableProperty* nativeInstance, MonoObject* original);
 

+ 4 - 0
SBansheeEngine/SBansheeEngine.vcxproj

@@ -277,7 +277,9 @@
     <ClInclude Include="Include\BsManagedSerializableObjectInfoRTTI.h" />
     <ClInclude Include="Include\BsManagedSerializableObjectRTTI.h" />
     <ClInclude Include="Include\BsScriptSerializableArray.h" />
+    <ClInclude Include="Include\BsScriptSerializableDictionary.h" />
     <ClInclude Include="Include\BsScriptSerializableField.h" />
+    <ClInclude Include="Include\BsScriptSerializableList.h" />
     <ClInclude Include="Include\BsScriptSerializableObject.h" />
     <ClInclude Include="Include\BsScriptSerializableProperty.h" />
     <ClInclude Include="Include\BsScriptSpriteTexture.h" />
@@ -327,7 +329,9 @@
     <ClCompile Include="Source\BsManagedSerializableObject.cpp" />
     <ClCompile Include="Source\BsManagedSerializableObjectInfo.cpp" />
     <ClCompile Include="Source\BsScriptSerializableArray.cpp" />
+    <ClCompile Include="Source\BsScriptSerializableDictionary.cpp" />
     <ClCompile Include="Source\BsScriptSerializableField.cpp" />
+    <ClCompile Include="Source\BsScriptSerializableList.cpp" />
     <ClCompile Include="Source\BsScriptSerializableObject.cpp" />
     <ClCompile Include="Source\BsScriptSerializableProperty.cpp" />
     <ClCompile Include="Source\BsScriptSpriteTexture.cpp" />

+ 12 - 0
SBansheeEngine/SBansheeEngine.vcxproj.filters

@@ -210,6 +210,12 @@
     <ClInclude Include="Include\BsManagedResourceManager.h">
       <Filter>Header Files</Filter>
     </ClInclude>
+    <ClInclude Include="Include\BsScriptSerializableList.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="Include\BsScriptSerializableDictionary.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\BsScriptTexture2D.cpp">
@@ -353,5 +359,11 @@
     <ClCompile Include="Source\BsManagedResourceManager.cpp">
       <Filter>Source Files</Filter>
     </ClCompile>
+    <ClCompile Include="Source\BsScriptSerializableList.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="Source\BsScriptSerializableDictionary.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
 </Project>

+ 53 - 0
SBansheeEngine/Source/BsScriptSerializableDictionary.cpp

@@ -0,0 +1,53 @@
+#include "BsScriptSerializableDictionary.h"
+#include "BsScriptMeta.h"
+#include "BsMonoField.h"
+#include "BsMonoClass.h"
+#include "BsMonoManager.h"
+#include "BsRuntimeScriptObjects.h"
+#include "BsManagedSerializableObjectInfo.h"
+#include "BsScriptSerializableProperty.h"
+
+namespace BansheeEngine
+{
+	ScriptSerializableDictionary::ScriptSerializableDictionary(MonoObject* instance, const ManagedSerializableTypeInfoDictionaryPtr& typeInfo)
+		:ScriptObject(instance), mTypeInfo(typeInfo)
+	{
+
+	}
+
+	void ScriptSerializableDictionary::initRuntimeData()
+	{
+		metaData.scriptClass->addInternalCall("Internal_CreateKeyProperty", &ScriptSerializableDictionary::internal_createKeyProperty);
+		metaData.scriptClass->addInternalCall("Internal_CreateValueProperty", &ScriptSerializableDictionary::internal_createValueProperty);
+	}
+
+	ScriptSerializableDictionary* ScriptSerializableDictionary::create(const ManagedSerializableTypeInfoDictionaryPtr& typeInfo, MonoObject* object)
+	{
+		MonoType* monoInternalKeyType = mono_class_get_type(typeInfo->mKeyType->getMonoClass());
+		MonoReflectionType* internalKeyType = mono_type_get_object(MonoManager::instance().getDomain(), monoInternalKeyType);
+
+		MonoType* monoInternalValueType = mono_class_get_type(typeInfo->mValueType->getMonoClass());
+		MonoReflectionType* internalValueType = mono_type_get_object(MonoManager::instance().getDomain(), monoInternalValueType);
+
+		void* params[3] = { object, internalKeyType, internalValueType };
+		MonoObject* managedInstance = metaData.scriptClass->createInstance(params, 3);
+
+		ScriptSerializableDictionary* nativeInstance = new (bs_alloc<ScriptSerializableDictionary>()) ScriptSerializableDictionary(managedInstance, typeInfo);
+
+		return nativeInstance;
+	}
+
+	MonoObject* ScriptSerializableDictionary::internal_createKeyProperty(ScriptSerializableDictionary* nativeInstance)
+	{
+		ScriptSerializableProperty* newProperty = ScriptSerializableProperty::create(nativeInstance->mTypeInfo->mKeyType);
+
+		return newProperty->getManagedInstance();
+	}
+
+	MonoObject* ScriptSerializableDictionary::internal_createValueProperty(ScriptSerializableDictionary* nativeInstance)
+	{
+		ScriptSerializableProperty* newProperty = ScriptSerializableProperty::create(nativeInstance->mTypeInfo->mValueType);
+
+		return newProperty->getManagedInstance();
+	}
+}

+ 42 - 0
SBansheeEngine/Source/BsScriptSerializableList.cpp

@@ -0,0 +1,42 @@
+#include "BsScriptSerializableList.h"
+#include "BsScriptMeta.h"
+#include "BsMonoField.h"
+#include "BsMonoClass.h"
+#include "BsMonoManager.h"
+#include "BsRuntimeScriptObjects.h"
+#include "BsManagedSerializableObjectInfo.h"
+#include "BsScriptSerializableProperty.h"
+
+namespace BansheeEngine
+{
+	ScriptSerializableList::ScriptSerializableList(MonoObject* instance, const ManagedSerializableTypeInfoListPtr& typeInfo)
+		:ScriptObject(instance), mTypeInfo(typeInfo)
+	{
+
+	}
+
+	void ScriptSerializableList::initRuntimeData()
+	{
+		metaData.scriptClass->addInternalCall("Internal_CreateProperty", &ScriptSerializableList::internal_createProperty);
+	}
+
+	ScriptSerializableList* ScriptSerializableList::create(const ManagedSerializableTypeInfoListPtr& typeInfo, MonoObject* object)
+	{
+		MonoType* monoInternalElementType = mono_class_get_type(typeInfo->mElementType->getMonoClass());
+		MonoReflectionType* internalElementType = mono_type_get_object(MonoManager::instance().getDomain(), monoInternalElementType);
+
+		void* params[2] = { object, internalElementType };
+		MonoObject* managedInstance = metaData.scriptClass->createInstance(params, 2);
+
+		ScriptSerializableList* nativeInstance = new (bs_alloc<ScriptSerializableList>()) ScriptSerializableList(managedInstance, typeInfo);
+
+		return nativeInstance;
+	}
+
+	MonoObject* ScriptSerializableList::internal_createProperty(ScriptSerializableList* nativeInstance)
+	{
+		ScriptSerializableProperty* newProperty = ScriptSerializableProperty::create(nativeInstance->mTypeInfo->mElementType);
+
+		return newProperty->getManagedInstance();
+	}
+}

+ 36 - 0
SBansheeEngine/Source/BsScriptSerializableProperty.cpp

@@ -7,8 +7,12 @@
 #include "BsManagedSerializableObjectInfo.h"
 #include "BsScriptSerializableObject.h"
 #include "BsScriptSerializableArray.h"
+#include "BsScriptSerializableList.h"
+#include "BsScriptSerializableDictionary.h"
 #include "BsManagedSerializableObject.h"
 #include "BsManagedSerializableArray.h"
+#include "BsManagedSerializableList.h"
+#include "BsManagedSerializableDictionary.h"
 #include "BsManagedSerializableField.h"
 #include "BsMemorySerializer.h"
 
@@ -24,8 +28,12 @@ namespace BansheeEngine
 	{
 		metaData.scriptClass->addInternalCall("Internal_CreateObject", &ScriptSerializableProperty::internal_createObject);
 		metaData.scriptClass->addInternalCall("Internal_CreateArray", &ScriptSerializableProperty::internal_createArray);
+		metaData.scriptClass->addInternalCall("Internal_CreateList", &ScriptSerializableProperty::internal_createList);
+		metaData.scriptClass->addInternalCall("Internal_CreateDictionary", &ScriptSerializableProperty::internal_createDictionary);
 		metaData.scriptClass->addInternalCall("Internal_CreateManagedObjectInstance", &ScriptSerializableProperty::internal_createManagedObjectInstance);
 		metaData.scriptClass->addInternalCall("Internal_CreateManagedArrayInstance", &ScriptSerializableProperty::internal_createManagedArrayInstance);
+		metaData.scriptClass->addInternalCall("Internal_CreateManagedListInstance", &ScriptSerializableProperty::internal_createManagedListInstance);
+		metaData.scriptClass->addInternalCall("Internal_CreateManagedDictionaryInstance", &ScriptSerializableProperty::internal_createManagedDictionaryInstance);
 		metaData.scriptClass->addInternalCall("Internal_CloneManagedInstance", &ScriptSerializableProperty::internal_cloneManagedInstance);
 	}
 
@@ -53,6 +61,22 @@ namespace BansheeEngine
 		return newObject->getManagedInstance();
 	}
 
+	MonoObject* ScriptSerializableProperty::internal_createList(ScriptSerializableProperty* nativeInstance, MonoObject* object)
+	{
+		ManagedSerializableTypeInfoListPtr listTypeInfo = std::static_pointer_cast<ManagedSerializableTypeInfoList>(nativeInstance->mTypeInfo);
+		ScriptSerializableList* newObject = ScriptSerializableList::create(listTypeInfo, object);
+
+		return newObject->getManagedInstance();
+	}
+
+	MonoObject* ScriptSerializableProperty::internal_createDictionary(ScriptSerializableProperty* nativeInstance, MonoObject* object)
+	{
+		ManagedSerializableTypeInfoDictionaryPtr dictTypeInfo = std::static_pointer_cast<ManagedSerializableTypeInfoDictionary>(nativeInstance->mTypeInfo);
+		ScriptSerializableDictionary* newObject = ScriptSerializableDictionary::create(dictTypeInfo, object);
+
+		return newObject->getManagedInstance();
+	}
+
 	MonoObject* ScriptSerializableProperty::internal_createManagedObjectInstance(ScriptSerializableProperty* nativeInstance)
 	{
 		ManagedSerializableTypeInfoObjectPtr objectTypeInfo = std::static_pointer_cast<ManagedSerializableTypeInfoObject>(nativeInstance->mTypeInfo);
@@ -70,6 +94,18 @@ namespace BansheeEngine
 		return ManagedSerializableArray::createManagedInstance(arrayTypeInfo, nativeSizes);
 	}
 
+	MonoObject* ScriptSerializableProperty::internal_createManagedListInstance(ScriptSerializableProperty* nativeInstance, int size)
+	{
+		ManagedSerializableTypeInfoListPtr listTypeInfo = std::static_pointer_cast<ManagedSerializableTypeInfoList>(nativeInstance->mTypeInfo);
+		return ManagedSerializableList::createManagedInstance(listTypeInfo, size);
+	}
+
+	MonoObject* ScriptSerializableProperty::internal_createManagedDictionaryInstance(ScriptSerializableProperty* nativeInstance)
+	{
+		ManagedSerializableTypeInfoDictionaryPtr dictTypeInfo = std::static_pointer_cast<ManagedSerializableTypeInfoDictionary>(nativeInstance->mTypeInfo);
+		return ManagedSerializableDictionary::createManagedInstance(dictTypeInfo);
+	}
+
 	MonoObject* ScriptSerializableProperty::internal_cloneManagedInstance(ScriptSerializableProperty* nativeInstance, MonoObject* original)
 	{
 		ManagedSerializableFieldDataPtr data = ManagedSerializableFieldData::create(nativeInstance->mTypeInfo, original);