Browse Source

C# object serialization WIP

Marko Pintera 11 years ago
parent
commit
be6adc683d
40 changed files with 915 additions and 220 deletions
  1. 11 25
      GameObjectSerialization.txt
  2. 1 1
      MBansheeEngine/Component.cs
  3. 6 0
      MBansheeEngine/GameObject.cs
  4. 1 0
      MBansheeEngine/MBansheeEngine.csproj
  5. 7 1
      MBansheeEngine/SpriteTexture.cs
  6. 6 0
      MBansheeEngine/Texture2D.cs
  7. 0 1
      SBansheeEditor/Source/BsScriptEditorGUI.cpp
  8. 0 1
      SBansheeEditor/Source/BsScriptEditorWindow.cpp
  9. 56 35
      SBansheeEngine/Include/BsRuntimeScriptObjects.h
  10. 3 0
      SBansheeEngine/Include/BsScriptEnginePrerequisites.h
  11. 33 0
      SBansheeEngine/Include/BsScriptGameObjectManager.h
  12. 0 8
      SBansheeEngine/Include/BsScriptObject.h
  13. 6 0
      SBansheeEngine/Include/BsScriptResource.h
  14. 62 0
      SBansheeEngine/Include/BsScriptResourceManager.h
  15. 3 0
      SBansheeEngine/Include/BsScriptSpriteTexture.h
  16. 3 0
      SBansheeEngine/Include/BsScriptTexture2D.h
  17. 4 0
      SBansheeEngine/SBansheeEngine.vcxproj
  18. 12 0
      SBansheeEngine/SBansheeEngine.vcxproj.filters
  19. 564 119
      SBansheeEngine/Source/BsRuntimeScriptObjects.cpp
  20. 0 1
      SBansheeEngine/Source/BsScriptComponent.cpp
  21. 0 1
      SBansheeEngine/Source/BsScriptFont.cpp
  22. 0 1
      SBansheeEngine/Source/BsScriptGUIArea.cpp
  23. 0 1
      SBansheeEngine/Source/BsScriptGUIButton.cpp
  24. 0 1
      SBansheeEngine/Source/BsScriptGUIElementStateStyle.cpp
  25. 0 1
      SBansheeEngine/Source/BsScriptGUIElementStyle.cpp
  26. 0 1
      SBansheeEngine/Source/BsScriptGUIFixedSpace.cpp
  27. 0 1
      SBansheeEngine/Source/BsScriptGUIFlexibleSpace.cpp
  28. 0 1
      SBansheeEngine/Source/BsScriptGUIInputBox.cpp
  29. 0 1
      SBansheeEngine/Source/BsScriptGUILabel.cpp
  30. 0 1
      SBansheeEngine/Source/BsScriptGUILayout.cpp
  31. 0 1
      SBansheeEngine/Source/BsScriptGUIListBox.cpp
  32. 0 1
      SBansheeEngine/Source/BsScriptGUIScrollArea.cpp
  33. 0 1
      SBansheeEngine/Source/BsScriptGUITexture.cpp
  34. 0 1
      SBansheeEngine/Source/BsScriptGUIToggle.cpp
  35. 0 1
      SBansheeEngine/Source/BsScriptGUIToggleGroup.cpp
  36. 6 0
      SBansheeEngine/Source/BsScriptGameObjectManager.cpp
  37. 0 1
      SBansheeEngine/Source/BsScriptHString.cpp
  38. 125 0
      SBansheeEngine/Source/BsScriptResourceManager.cpp
  39. 3 6
      SBansheeEngine/Source/BsScriptSpriteTexture.cpp
  40. 3 6
      SBansheeEngine/Source/BsScriptTexture2D.cpp

+ 11 - 25
GameObjectSerialization.txt

@@ -4,24 +4,16 @@ TODO
  ---------------------------------------
  C# component serialization
 
- RuntimeScriptObjects
- - enumerateSerializable()
-   - Goes through all (non-C++) Components and non-Component classes marked with [Serializable]
-    - Using C++ it finds all fields in those classes. Fields and their references are stored in C++ classes.
-	  - Need to enumerate value type fields, or fields holding other [Serializable] structures, references to other Components, SceneObjects or Resources
-        - Plus arrays, and possibly C# List
-        - Considers attributes
-            - [Serialized] - Forces field to be serialized (If valid type)
-            - [NotSerialized] - Forced field not to be serialized
-            - By default all public members are serialized and private ones are not
-	  - Something like SerializableComponentInfo (per-component), SerializableObjectInfo(per-non-component), SerializablePlainField,
-	    SerializableArrayField, SerializableResourceField, SerializableGameObjectField, SerializableObjectField, etc.
- - Internally it holds a Map with name -> Serializable*Info mapping for every supported type
-   - User can query if type is supported or not, and retrieve the serialization info if needed
-   - Using the serialization info user can retrieve actual values from an instance easily
-   - Serializable*Info classes contain findField method that accepts a name and a type
-     - This is used for deserialization
- - Using Serializable*Info you can create a brand new instance of a Component or a [Serializable] non-component
+ TODO:
+  - Add support for generic Lists, and potentially dictionaries
+   - Be careful with current field array support, lists should probably be handled completely differently and shouldn't share that code
+ - Implement set/get methods for strings/resourceRefs/gameObjectRefs/serializableObjects
+ - Make SerializableObjectInfo IReflectable and create its RTTI
+ - In BsScriptEnginePlugin.cpp I create RuntimeScriptObjects class but never destroy it, for debug purposes. Remember to remove that.
+ - Need a class that will keep track of all instances of ScriptResource and ScriptGameObject
+   - Need to update existing createInstance methods
+ - Need a way to create SerializableObject - likely createInstance() method in SerializableObjectField
+
 
 ScriptComponent
  - C++ half of the C# component
@@ -44,6 +36,7 @@ ScriptComponentRTTI
     - Returns FieldId -> HGameObject
   - GetResourceFields
     - Returns FieldID -> HResource
+ - Make sure to scan all base classes as well
  - When serializing all those arrays are prepared in OnSerializatioStarted
  - When deserializing they are send to the object in OnDeserializationEnded
    - However existance for the fields is first checked by getting new copy of SerializableComponentInfo and seeing
@@ -77,13 +70,6 @@ TODO - Possibly flesh out and example with Resources or Gameobject references a
 	     so hopefully this will only matter when enumerating all components which shouldn't be during performance
 		 critical moments.
 
-Inspector
- - RuntimeScriptObjects::enumerateInspectable creates a list of all inspectable classes (Components and others marked with [Serializable]
-  - Returns a hierarchy very similar to Serializable*Info and their children (Likely re-use the same hierarchy but with different flags?)
-  - This information is then used to generate needed fields
-
- - Importer inspectors are special and custom-built and shouldn't be considered here
-
 TODO - When reloading scripts how to handle restoring references?
 TODO - When I destroy a Component, how will I refresh the inspector to let it know that something has changed
   - Can happen from C# and C++

+ 1 - 1
MBansheeEngine/Component.cs

@@ -3,7 +3,7 @@ using System.Runtime.CompilerServices;
 
 namespace BansheeEngine
 {
-    public class Component : ScriptObject
+    public class Component : GameObject
     {
         public Component()
         {

+ 6 - 0
MBansheeEngine/GameObject.cs

@@ -0,0 +1,6 @@
+namespace BansheeEngine
+{
+    public class GameObject : ScriptObject
+    {
+    }
+}

+ 1 - 0
MBansheeEngine/MBansheeEngine.csproj

@@ -47,6 +47,7 @@
     <Compile Include="Component.cs" />
     <Compile Include="DbgComponent.cs" />
     <Compile Include="Font.cs" />
+    <Compile Include="GameObject.cs" />
     <Compile Include="GUI\GUI.cs" />
     <Compile Include="GUI\GUIArea.cs" />
     <Compile Include="GUI\GUIBase.cs" />

+ 7 - 1
MBansheeEngine/SpriteTexture.cs

@@ -4,7 +4,13 @@ namespace BansheeEngine
 {
     public sealed class SpriteTexture : Resource // TODO - Dummy class
     {
-        public SpriteTexture()
+        // For internal use by the runtime
+        private SpriteTexture()
+        {
+            
+        }
+
+        public SpriteTexture(int dummyParam)
         {
             Internal_CreateInstance(this);
         }

+ 6 - 0
MBansheeEngine/Texture2D.cs

@@ -5,6 +5,12 @@ namespace BansheeEngine
 {
     public sealed class Texture2D : Resource
     {
+        // For internal use by the runtime
+        private Texture2D()
+        {
+
+        }
+
         public Texture2D(TextureFormat format, int width, int height, bool hasMipmaps = false, bool gammaCorrection = false)
         {
             Internal_CreateInstance(this, format, width, height, hasMipmaps, gammaCorrection);

+ 0 - 1
SBansheeEditor/Source/BsScriptEditorGUI.cpp

@@ -46,7 +46,6 @@ namespace BansheeEditor
 
 	void ScriptEditorGUI::internal_destroyInstance(ScriptEditorGUI* nativeInstance)
 	{
-		nativeInstance->destroyInstance();
 		cm_delete(nativeInstance);
 	}
 

+ 0 - 1
SBansheeEditor/Source/BsScriptEditorWindow.cpp

@@ -69,7 +69,6 @@ namespace BansheeEditor
 		assert(iterFind == OpenScriptEditorWindows.end());
 #endif
 
-		nativeInstance->destroyInstance();
 		cm_delete(nativeInstance);
 	}
 

+ 56 - 35
SBansheeEngine/Include/BsRuntimeScriptObjects.h

@@ -2,6 +2,7 @@
 
 #include "BsScriptEnginePrerequisites.h"
 #include "CmModule.h"
+#include <mono/jit/jit.h>
 
 namespace BansheeEngine
 {
@@ -20,9 +21,12 @@ namespace BansheeEngine
 		Float,
 		Double,
 		String,
-		SerializableObject,
-		ResourceRef,
-		GameObjectRef,
+		SerializableObjectValue,
+		SerializableObjectRef,
+		TextureRef,
+		SpriteTextureRef,
+		SceneObjectRef,
+		ComponentRef,
 		Other
 	};
 
@@ -48,55 +52,71 @@ namespace BansheeEngine
 
 		MonoField* mMonoField;
 
-		CM::UINT32 getNumArrayElement(MonoObject* obj);
-		void setNumArrayElements(MonoObject* obj, CM::UINT32 numElements);
+		bool isArray();
+		bool isReferenceType();
+		bool isNull(MonoObject* obj);
+		void setNull(MonoObject* obj);
+
+		CM::UINT32 getNumArrayElements(MonoObject* obj);
+		void setNumArrayElements(MonoObject* obj, CM::UINT32 numElements, bool discardExisting = true);
 
 		void setU8(MonoObject* obj, CM::UINT8 val, CM::UINT32 arrayIdx = 0);
-		CM::UINT8 getU8(MonoObject* obj,CM::UINT32 arrayIdx = 0);
+		CM::UINT8 getU8(MonoObject* obj, CM::UINT32 arrayIdx = 0);
+
+		void setI8(MonoObject* obj, CM::INT8 val, CM::UINT32 arrayIdx = 0);
+		CM::INT8 getI8(MonoObject* obj, CM::UINT32 arrayIdx = 0);
+
+		void setU16(MonoObject* obj, CM::UINT16 val, CM::UINT32 arrayIdx = 0);
+		CM::UINT16 getU16(MonoObject* obj, CM::UINT32 arrayIdx = 0);
 
-		void setI8(MonoObject* obj,CM::INT8 val, CM::UINT32 arrayIdx = 0);
-		CM::INT8 getI8(MonoObject* obj,CM::UINT32 arrayIdx = 0);
+		void setI16(MonoObject* obj, CM::INT16 val, CM::UINT32 arrayIdx = 0);
+		CM::INT16 getI16(MonoObject* obj, CM::UINT32 arrayIdx = 0);
 
-		void setU16(MonoObject* obj,CM::UINT16 val, CM::UINT32 arrayIdx = 0);
-		CM::UINT16 getU16(MonoObject* obj,CM::UINT32 arrayIdx = 0);
+		void setU32(MonoObject* obj, CM::UINT32 val, CM::UINT32 arrayIdx = 0);
+		CM::UINT32 getU32(MonoObject* obj, CM::UINT32 arrayIdx = 0);
 
-		void setI16(MonoObject* obj,CM::INT16 val, CM::UINT32 arrayIdx = 0);
-		CM::INT16 getI16(MonoObject* obj,CM::UINT32 arrayIdx = 0);
+		void setI32(MonoObject* obj, CM::INT32 val, CM::UINT32 arrayIdx = 0);
+		CM::INT32 getI32(MonoObject* obj, CM::UINT32 arrayIdx = 0);
 
-		void setU32(MonoObject* obj,CM::UINT32 val, CM::UINT32 arrayIdx = 0);
-		CM::UINT32 getU32(MonoObject* obj,CM::UINT32 arrayIdx = 0);
+		void setU64(MonoObject* obj, CM::UINT64 val, CM::UINT32 arrayIdx = 0);
+		CM::UINT64 getU64(MonoObject* obj, CM::UINT32 arrayIdx = 0);
 
-		void setI32(MonoObject* obj,CM::INT32 val, CM::UINT32 arrayIdx = 0);
-		CM::INT32 getI32(MonoObject* obj,CM::UINT32 arrayIdx = 0);
+		void setI64(MonoObject* obj, CM::INT64 val, CM::UINT32 arrayIdx = 0);
+		CM::INT64 getI64(MonoObject* obj, CM::UINT32 arrayIdx = 0);
 
-		void setU64(MonoObject* obj,CM::UINT64 val, CM::UINT32 arrayIdx = 0);
-		CM::UINT64 getU64(MonoObject* obj,CM::UINT32 arrayIdx = 0);
+		void setBool(MonoObject* obj, bool val, CM::UINT32 arrayIdx = 0);
+		bool getBool(MonoObject* obj, CM::UINT32 arrayIdx = 0);
 
-		void setI64(MonoObject* obj,CM::INT64 val, CM::UINT32 arrayIdx = 0);
-		CM::INT64 getI64(MonoObject* obj,CM::UINT32 arrayIdx = 0);
+		void setChar(MonoObject* obj, wchar_t val, CM::UINT32 arrayIdx = 0);
+		wchar_t getChar(MonoObject* obj, CM::UINT32 arrayIdx = 0);
 
-		void setBool(MonoObject* obj,bool val, CM::UINT32 arrayIdx = 0);
-		bool getBool(MonoObject* obj,CM::UINT32 arrayIdx = 0);
+		void setFloat(MonoObject* obj, float val, CM::UINT32 arrayIdx = 0);
+		float getFloat(MonoObject* obj, CM::UINT32 arrayIdx = 0);
 
-		void setChar(MonoObject* obj,wchar_t val, CM::UINT32 arrayIdx = 0);
-		wchar_t getChar(MonoObject* obj,CM::UINT32 arrayIdx = 0);
+		void setDouble(MonoObject* obj, double val, CM::UINT32 arrayIdx = 0);
+		double getDouble(MonoObject* obj, CM::UINT32 arrayIdx = 0);
 
-		void setFloat(MonoObject* obj,float val, CM::UINT32 arrayIdx = 0);
-		float getFloat(MonoObject* obj,CM::UINT32 arrayIdx = 0);
+		void setString(MonoObject* obj, const CM::WString& val, CM::UINT32 arrayIdx = 0);
+		CM::WString getString(MonoObject* obj, CM::UINT32 arrayIdx = 0);
 
-		void setDouble(MonoObject* obj,double val, CM::UINT32 arrayIdx = 0);
-		double getDouble(MonoObject* obj,CM::UINT32 arrayIdx = 0);
+		void setTexture(MonoObject* obj, const CM::HTexture& resource, CM::UINT32 arrayIdx = 0);
+		CM::HTexture getTexture(MonoObject* obj, CM::UINT32 arrayIdx = 0);
 
-		void setString(MonoObject* obj,const CM::WString& val, CM::UINT32 arrayIdx = 0);
-		CM::WString getString(MonoObject* obj,CM::UINT32 arrayIdx = 0);
+		void setSpriteTexture(MonoObject* obj, const HSpriteTexture& resource, CM::UINT32 arrayIdx = 0);
+		HSpriteTexture getSpriteTexture(MonoObject* obj, CM::UINT32 arrayIdx = 0);
 
-		void setResource(MonoObject* obj,const CM::HResource& resource, CM::UINT32 arrayIdx = 0);
-		CM::HResource getResource(MonoObject* obj,CM::UINT32 arrayIdx = 0);
+		void setSceneObject(MonoObject* obj, const CM::HSceneObject& sceneObject, CM::UINT32 arrayIdx = 0);
+		CM::HSceneObject getSceneObject(MonoObject* obj, CM::UINT32 arrayIdx = 0);
 
-		void setGameObject(MonoObject* obj,const CM::HGameObject& gameObject, CM::UINT32 arrayIdx = 0);
-		CM::HGameObject getGameObject(MonoObject* obj,CM::UINT32 arrayIdx = 0);
+		void setComponent(MonoObject* obj, const CM::HComponent& component, CM::UINT32 arrayIdx = 0);
+		CM::HComponent getComponent(MonoObject* obj, CM::UINT32 arrayIdx = 0);
 
-		// TODO - Set/Get for SerializableObject
+		void setSerializableObject(MonoObject* obj, const MonoObject* value, CM::UINT32 arrayIdx = 0);
+		MonoObject* getSerializableObject(MonoObject* obj, CM::UINT32 arrayIdx = 0);
+
+	private:
+		void setValue(MonoObject* obj, void* val, CM::UINT32 arrayIdx = 0);
+		void* getValue(MonoObject* obj, CM::UINT32 arrayIdx = 0);
 	};
 
 	struct BS_SCR_BE_EXPORT SerializableObjectInfo
@@ -130,6 +150,7 @@ namespace BansheeEngine
 
 		void refreshScriptObjects(const CM::String& assemblyName);
 		bool getSerializableObjectInfo(const CM::String& ns, const CM::String& typeName, std::shared_ptr<SerializableObjectInfo>& outInfo);
+		bool hasSerializableObjectInfo(const CM::String& ns, const CM::String& typeName);
 	private:
 		CM::UnorderedMap<CM::String, std::shared_ptr<SerializableAssemblyInfo>>::type mAssemblyInfos;
 

+ 3 - 0
SBansheeEngine/Include/BsScriptEnginePrerequisites.h

@@ -20,6 +20,8 @@
 
 namespace BansheeEngine
 {
+	class ScriptResourceManager;
+	class ScriptResource;
 	class ScriptFont;
 	class ScriptSpriteTexture;
 	class ScriptTexture2D;
@@ -29,6 +31,7 @@ namespace BansheeEngine
 	class ScriptGUIArea;
 	class ScriptGUILayout;
 	class ScriptGUILabel;
+	class ScriptGameObject;
 	class ScriptComponent;
 	class ManagedComponent;
 

+ 33 - 0
SBansheeEngine/Include/BsScriptGameObjectManager.h

@@ -0,0 +1,33 @@
+#pragma once
+
+#include "BsScriptEnginePrerequisites.h"
+#include "CmModule.h"
+
+namespace BansheeEngine
+{
+	class BS_SCR_BE_EXPORT ScriptGameObjectManager : public CM::Module<ScriptGameObjectManager>
+	{
+	public:
+		// TODO - Add create methods
+
+		/**
+		 * @note Returns nullptr if script SceneObject doesn't exist.
+		 */
+		//ScriptSceneObject* getScriptSceneObject(CM::UINT64 id);
+
+		/**
+		 * @note Returns nullptr if script Component doesn't exist.
+		 */
+		//ScriptComponent* getScriptComponent(CM::UINT64 id);
+
+		/**
+		 * @note Returns nullptr if script GameObject doesn't exist.
+		 */
+		//ScriptGameObject* getScriptGameObject(CM::UINT64 id);
+
+		//void destroyScriptGameObject(ScriptGameObject* gameObject);
+
+	private:
+		CM::UnorderedMap<CM::UINT64, ScriptGameObject*>::type mScriptResources;
+	};
+}

+ 0 - 8
SBansheeEngine/Include/BsScriptObject.h

@@ -63,14 +63,6 @@ namespace BansheeEngine
 			mManagedInstance = instance;
 		}
 
-		void destroyInstance()
-		{
-			if(mManagedInstance == nullptr)
-				return;
-
-			mManagedInstance = nullptr;
-		}
-
 		template <class Type2>
 		static void throwIfInstancesDontMatch(ScriptObject<Type2>* lhs, void* rhs)
 		{

+ 6 - 0
SBansheeEngine/Include/BsScriptResource.h

@@ -9,5 +9,11 @@ namespace BansheeEngine
 	public:
 		virtual CM::HResource getNativeHandle() const = 0;
 		virtual void setNativeHandle(const CM::HResource& resource) = 0;
+
+	protected:
+		friend class ScriptResourceManager;
+
+		ScriptResource() {}
+		virtual ~ScriptResource() {}
 	};
 }

+ 62 - 0
SBansheeEngine/Include/BsScriptResourceManager.h

@@ -0,0 +1,62 @@
+#pragma once
+
+#include "BsScriptEnginePrerequisites.h"
+#include "CmModule.h"
+#include <mono/jit/jit.h>
+
+namespace BansheeEngine
+{
+	class BS_SCR_BE_EXPORT ScriptResourceManager : public CM::Module<ScriptResourceManager>
+	{
+	public:
+		ScriptResourceManager();
+
+		/**
+		 * @note Throws an exception if resource for the handle already exists.
+		 * 		 Creates a new managed instance of the object.
+		 */
+		ScriptTexture2D* createScriptTexture(const CM::HTexture& resourceHandle);
+
+		/**
+		 * @note Throws an exception if resource for the handle already exists.
+		 * 		 Initializes the ScriptResource with an existing managed instance.
+		 */
+		ScriptTexture2D* createScriptTexture(MonoObject* existingInstance, const CM::HTexture& resourceHandle);
+
+		/**
+		 * @note Throws an exception if resource for the handle already exists.
+		 * 		 Creates a new managed instance of the object.
+		 */
+		ScriptSpriteTexture* createScriptSpriteTexture(const HSpriteTexture& resourceHandle);
+
+		/**
+		 * @note Throws an exception if resource for the handle already exists.
+		 * 		 Initializes the ScriptResource with an existing managed instance.
+		 */
+		ScriptSpriteTexture* createScriptSpriteTexture(MonoObject* existingInstance, const HSpriteTexture& resourceHandle);
+
+		/**
+		 * @note Returns nullptr if script resource doesn't exist.
+		 */
+		ScriptTexture2D* getScriptTexture(const CM::HTexture& resourceHandle);
+
+		/**
+		 * @note Returns nullptr if script resource doesn't exist.
+		 */
+		ScriptSpriteTexture* getScriptSpriteTexture(const HSpriteTexture& resourceHandle);
+
+		/**
+		 * @note Returns nullptr if script resource doesn't exist.
+		 */
+		ScriptResource* getScriptResource(const CM::HResource& resourceHandle);
+
+		void destroyScriptResource(ScriptResource* resource);
+
+	private:
+		CM::UnorderedMap<CM::String, ScriptResource*>::type mScriptResources;
+		MonoClass* mTextureClass;
+		MonoClass* mSpriteTextureClass;
+
+		void throwExceptionIfInvalidOrDuplicate(const CM::String& uuid) const;
+	};
+}

+ 3 - 0
SBansheeEngine/Include/BsScriptSpriteTexture.h

@@ -17,12 +17,15 @@ namespace BansheeEngine
 		void setNativeHandle(const CM::HResource& resource);
 
 	private:
+		friend class ScriptResourceManager;
+
 		static void internal_createInstance(MonoObject* instance);
 		static void internal_destroyInstance(ScriptSpriteTexture* nativeInstance);
 
 		static void initRuntimeData();
 
 		ScriptSpriteTexture(const HSpriteTexture& texture);
+		~ScriptSpriteTexture() {}
 
 		HSpriteTexture mTexture;
 	};

+ 3 - 0
SBansheeEngine/Include/BsScriptTexture2D.h

@@ -17,12 +17,15 @@ namespace BansheeEngine
 		CM::HResource getNativeHandle() const { return mTexture; }
 		void setNativeHandle(const CM::HResource& resource);
 	private:
+		friend class ScriptResourceManager;
+
 		static void internal_createInstance(MonoObject* instance, CM::UINT32 format, CM::UINT32 width, CM::UINT32 height, bool hasMipmaps, bool gammaCorrection);
 		static void internal_destroyInstance(ScriptTexture2D* nativeInstance);
 
 		static void initRuntimeData();
 
 		ScriptTexture2D(const CM::HTexture& texture);
+		~ScriptTexture2D() {}
 
 		CM::HTexture mTexture;
 	};

+ 4 - 0
SBansheeEngine/SBansheeEngine.vcxproj

@@ -232,6 +232,7 @@
     <ClInclude Include="Include\BsScriptComponent.h" />
     <ClInclude Include="Include\BsScriptEnginePrerequisites.h" />
     <ClInclude Include="Include\BsScriptGameObject.h" />
+    <ClInclude Include="Include\BsScriptGameObjectManager.h" />
     <ClInclude Include="Include\BsScriptGUIButton.h" />
     <ClInclude Include="Include\BsScriptGUIFixedSpace.h" />
     <ClInclude Include="Include\BsScriptGUIFlexibleSpace.h" />
@@ -252,6 +253,7 @@
     <ClInclude Include="Include\BsScriptMacros.h" />
     <ClInclude Include="Include\BsScriptObject.h" />
     <ClInclude Include="Include\BsScriptResource.h" />
+    <ClInclude Include="Include\BsScriptResourceManager.h" />
     <ClInclude Include="Include\BsScriptSpriteTexture.h" />
     <ClInclude Include="Include\BsScriptStringTable.h" />
     <ClInclude Include="Include\BsScriptTexture2D.h" />
@@ -262,6 +264,7 @@
     <ClCompile Include="Source\BsRuntimeScriptObjects.cpp" />
     <ClCompile Include="Source\BsScriptComponent.cpp" />
     <ClCompile Include="Source\BsScriptEnginePlugin.cpp" />
+    <ClCompile Include="Source\BsScriptGameObjectManager.cpp" />
     <ClCompile Include="Source\BsScriptGUIButton.cpp" />
     <ClCompile Include="Source\BsScriptGUIFixedSpace.cpp" />
     <ClCompile Include="Source\BsScriptGUIFlexibleSpace.cpp" />
@@ -279,6 +282,7 @@
     <ClCompile Include="Source\BsScriptGUIToggleGroup.cpp" />
     <ClCompile Include="Source\BsScriptHString.cpp" />
     <ClCompile Include="Source\BsScriptGUIInputBox.cpp" />
+    <ClCompile Include="Source\BsScriptResourceManager.cpp" />
     <ClCompile Include="Source\BsScriptSpriteTexture.cpp" />
     <ClCompile Include="Source\BsScriptStringTable.cpp" />
     <ClCompile Include="Source\BsScriptTexture2D.cpp" />

+ 12 - 0
SBansheeEngine/SBansheeEngine.vcxproj.filters

@@ -105,6 +105,12 @@
     <ClInclude Include="Include\BsScriptGameObject.h">
       <Filter>Header Files</Filter>
     </ClInclude>
+    <ClInclude Include="Include\BsScriptResourceManager.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="Include\BsScriptGameObjectManager.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\BsScriptTexture2D.cpp">
@@ -182,5 +188,11 @@
     <ClCompile Include="Source\BsScriptComponent.cpp">
       <Filter>Source Files</Filter>
     </ClCompile>
+    <ClCompile Include="Source\BsScriptResourceManager.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="Source\BsScriptGameObjectManager.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
 </Project>

+ 564 - 119
SBansheeEngine/Source/BsRuntimeScriptObjects.cpp

@@ -1,8 +1,13 @@
 #include "BsRuntimeScriptObjects.h"
+#include "BsScriptResourceManager.h"
+#include "BsScriptGameObjectManager.h"
 #include "BsMonoManager.h"
 #include "BsMonoAssembly.h"
 #include "BsMonoClass.h"
 #include "BsMonoField.h"
+#include "BsMonoUtil.h"
+#include "BsScriptTexture2D.h"
+#include "BsScriptSpriteTexture.h"
 
 using namespace CamelotFramework;
 
@@ -33,6 +38,405 @@ namespace BansheeEngine
 
 	}
 
+	bool SerializableFieldInfo::isArray()
+	{
+		return ((UINT32)mFlags & (UINT32)ScriptFieldFlags::Array) != 0;
+	}
+
+	bool SerializableFieldInfo::isReferenceType()
+	{
+		return (isArray() || mType == ScriptFieldType::TextureRef || mType == ScriptFieldType::SpriteTextureRef || 
+			mType == ScriptFieldType::SceneObjectRef || mType == ScriptFieldType::ComponentRef || mType == ScriptFieldType::SerializableObjectRef);
+	}
+
+	bool SerializableFieldInfo::isNull(MonoObject* obj)
+	{
+		assert(isReferenceType());
+
+		void* val = mMonoField->getValue(obj);
+
+		return val == nullptr;
+	}
+
+	void SerializableFieldInfo::setNull(MonoObject* obj)
+	{
+		assert(isReferenceType());
+
+		mMonoField->setValue(obj, nullptr);
+	}
+
+	UINT32 SerializableFieldInfo::getNumArrayElements(MonoObject* obj)
+	{
+		assert(((UINT32)mFlags & (UINT32)ScriptFieldFlags::Array) != 0);
+
+		MonoArray* array = reinterpret_cast<MonoArray*>(mMonoField->getValue(obj));
+		return (UINT32)mono_array_length(array);
+	}
+
+	void SerializableFieldInfo::setNumArrayElements(MonoObject* obj, UINT32 numElements, bool discardExisting)
+	{
+		assert(((UINT32)mFlags & (UINT32)ScriptFieldFlags::Array) != 0);
+
+		uint32_t lengths[1] = { numElements };
+
+		MonoArray* newArray = mono_array_new_full(MonoManager::instance().getDomain(), 
+			mMonoField->getType()->_getInternalClass(), (uintptr_t*)lengths, nullptr);
+
+		if(!discardExisting)
+		{
+			MonoArray* existingArray = reinterpret_cast<MonoArray*>(mMonoField->getValue(obj));
+			UINT32 existingArrayLength = (UINT32)mono_array_length(existingArray);
+
+			UINT32 elemsToCopy = std::min(existingArrayLength, numElements);
+			int32_t elemSize = mono_array_element_size(mMonoField->getType()->_getInternalClass());
+
+			for(UINT32 i = 0; i < elemsToCopy; i++)
+			{
+				void* existingValAddr = (void*)mono_array_addr_with_size(existingArray, elemSize, (uintptr_t)i);
+				void* newValAddr = (void*)mono_array_addr_with_size(newArray, elemSize, (uintptr_t)i);
+
+				memcpy(newValAddr, existingValAddr, elemSize);
+			}
+		}
+
+		mMonoField->setValue(obj, newArray);
+	}
+
+	void SerializableFieldInfo::setU8(MonoObject* obj, UINT8 val, UINT32 arrayIdx)
+	{
+		assert(mType == ScriptFieldType::U8);
+
+		setValue(obj, &val, arrayIdx);
+	}
+
+	UINT8 SerializableFieldInfo::getU8(MonoObject* obj, UINT32 arrayIdx)
+	{
+		assert(mType == ScriptFieldType::U8);
+
+		return *(UINT8*)getValue(obj, arrayIdx);
+	}
+
+	void SerializableFieldInfo::setI8(MonoObject* obj, INT8 val, UINT32 arrayIdx)
+	{
+		assert(mType == ScriptFieldType::I8);
+
+		setValue(obj, &val, arrayIdx);
+	}
+
+	INT8 SerializableFieldInfo::getI8(MonoObject* obj, UINT32 arrayIdx)
+	{
+		assert(mType == ScriptFieldType::I8);
+
+		return *(INT8*)getValue(obj, arrayIdx);
+	}
+
+	void SerializableFieldInfo::setU16(MonoObject* obj, UINT16 val, UINT32 arrayIdx)
+	{
+		assert(mType == ScriptFieldType::U16);
+
+		setValue(obj, &val, arrayIdx);
+	}
+
+	UINT16 SerializableFieldInfo::getU16(MonoObject* obj, UINT32 arrayIdx)
+	{
+		assert(mType == ScriptFieldType::U16);
+
+		return *(UINT16*)getValue(obj, arrayIdx);
+	}
+
+	void SerializableFieldInfo::setI16(MonoObject* obj, INT16 val, UINT32 arrayIdx)
+	{
+		assert(mType == ScriptFieldType::I16);
+
+		setValue(obj, &val, arrayIdx);
+	}
+
+	INT16 SerializableFieldInfo::getI16(MonoObject* obj, UINT32 arrayIdx)
+	{
+		assert(mType == ScriptFieldType::I16);
+
+		return *(INT16*)getValue(obj, arrayIdx);
+	}
+
+	void SerializableFieldInfo::setU32(MonoObject* obj, UINT32 val, UINT32 arrayIdx)
+	{
+		assert(mType == ScriptFieldType::U32);
+
+		setValue(obj, &val, arrayIdx);
+	}
+
+	UINT32 SerializableFieldInfo::getU32(MonoObject* obj, UINT32 arrayIdx)
+	{
+		assert(mType == ScriptFieldType::U32);
+
+		return *(UINT32*)getValue(obj, arrayIdx);
+	}
+
+	void SerializableFieldInfo::setI32(MonoObject* obj, INT32 val, UINT32 arrayIdx)
+	{
+		assert(mType == ScriptFieldType::I32);
+
+		setValue(obj, &val, arrayIdx);
+	}
+
+	INT32 SerializableFieldInfo::getI32(MonoObject* obj, UINT32 arrayIdx)
+	{
+		assert(mType == ScriptFieldType::I32);
+
+		return *(INT32*)getValue(obj, arrayIdx);
+	}
+
+	void SerializableFieldInfo::setU64(MonoObject* obj, UINT64 val, UINT32 arrayIdx)
+	{
+		assert(mType == ScriptFieldType::U64);
+
+		setValue(obj, &val, arrayIdx);
+	}
+
+	UINT64 SerializableFieldInfo::getU64(MonoObject* obj, UINT32 arrayIdx)
+	{
+		assert(mType == ScriptFieldType::U64);
+
+		return *(UINT64*)getValue(obj, arrayIdx);
+	}
+
+	void SerializableFieldInfo::setI64(MonoObject* obj, INT64 val, UINT32 arrayIdx)
+	{
+		assert(mType == ScriptFieldType::I64);
+
+		setValue(obj, &val, arrayIdx);
+	}
+
+	INT64 SerializableFieldInfo::getI64(MonoObject* obj, UINT32 arrayIdx)
+	{
+		assert(mType == ScriptFieldType::I64);
+
+		return *(INT64*)getValue(obj, arrayIdx);
+	}
+
+	void SerializableFieldInfo::setBool(MonoObject* obj, bool val, UINT32 arrayIdx)
+	{
+		assert(mType == ScriptFieldType::Bool);
+
+		setValue(obj, &val, arrayIdx);
+	}
+
+	bool SerializableFieldInfo::getBool(MonoObject* obj, UINT32 arrayIdx)
+	{
+		assert(mType == ScriptFieldType::Bool);
+
+		return *(bool*)getValue(obj, arrayIdx);
+	}
+
+	void SerializableFieldInfo::setChar(MonoObject* obj, wchar_t val, UINT32 arrayIdx)
+	{
+		assert(mType == ScriptFieldType::Char);
+
+		setValue(obj, &val, arrayIdx);
+	}
+
+	wchar_t SerializableFieldInfo::getChar(MonoObject* obj, UINT32 arrayIdx)
+	{
+		assert(mType == ScriptFieldType::Char);
+
+		return *(wchar_t*)getValue(obj, arrayIdx);
+	}
+
+	void SerializableFieldInfo::setFloat(MonoObject* obj, float val, UINT32 arrayIdx)
+	{
+		assert(mType == ScriptFieldType::Float);
+
+		setValue(obj, &val, arrayIdx);
+	}
+
+	float SerializableFieldInfo::getFloat(MonoObject* obj, UINT32 arrayIdx)
+	{
+		assert(mType == ScriptFieldType::Float);
+
+		return *(float*)getValue(obj, arrayIdx);
+	}
+
+	void SerializableFieldInfo::setDouble(MonoObject* obj, double val, UINT32 arrayIdx)
+	{
+		assert(mType == ScriptFieldType::Double);
+
+		setValue(obj, &val, arrayIdx);
+	}
+
+	double SerializableFieldInfo::getDouble(MonoObject* obj, UINT32 arrayIdx)
+	{
+		assert(mType == ScriptFieldType::Double);
+
+		return *(double*)getValue(obj, arrayIdx);
+	}
+
+	void SerializableFieldInfo::setString(MonoObject* obj, const WString& val, UINT32 arrayIdx)
+	{
+		assert(mType == ScriptFieldType::String);
+
+		MonoString* str = MonoUtil::wstringToMono(MonoManager::instance().getDomain(), val);
+		setValue(obj, str, arrayIdx);
+	}
+
+	WString SerializableFieldInfo::getString(MonoObject* obj, UINT32 arrayIdx)
+	{
+		assert(mType == ScriptFieldType::String);
+
+		MonoString* str = (MonoString*)getValue(obj, arrayIdx);
+		if(str == nullptr)
+			return L"";
+
+		return MonoUtil::monoToWString(str);
+	}
+
+	void SerializableFieldInfo::setTexture(MonoObject* obj, const HTexture& resource, UINT32 arrayIdx)
+	{
+		assert(mType == ScriptFieldType::TextureRef);
+
+		if(resource == nullptr)
+		{
+			setValue(obj, nullptr, arrayIdx);
+		}
+		else
+		{
+			ScriptTexture2D* scriptResource = ScriptResourceManager::instance().getScriptTexture(resource);
+			if(scriptResource == nullptr)
+				scriptResource = ScriptResourceManager::instance().createScriptTexture(resource);
+
+			MonoObject* managedInstance = scriptResource->getManagedInstance();
+			setValue(obj, (void*)managedInstance, arrayIdx);
+		}
+	}
+
+	CM::HTexture SerializableFieldInfo::getTexture(MonoObject* obj, UINT32 arrayIdx)
+	{
+		assert(mType == ScriptFieldType::TextureRef);
+
+		MonoObject* managedInstance = (MonoObject*)getValue(obj, arrayIdx);
+		if(managedInstance == nullptr)
+			return HTexture();
+
+		ScriptTexture2D* scriptResource = ScriptTexture2D::toNative(managedInstance);
+		return static_resource_cast<Texture>(scriptResource->getNativeHandle());
+	}
+
+	void SerializableFieldInfo::setSpriteTexture(MonoObject* obj, const HSpriteTexture& resource, UINT32 arrayIdx)
+	{
+		if(resource == nullptr)
+		{
+			setValue(obj, nullptr, arrayIdx);
+		}
+		else
+		{
+			assert(mType == ScriptFieldType::SpriteTextureRef);
+
+			ScriptSpriteTexture* scriptResource = ScriptResourceManager::instance().getScriptSpriteTexture(resource);
+			if(scriptResource == nullptr)
+				scriptResource = ScriptResourceManager::instance().createScriptSpriteTexture(resource);
+
+			MonoObject* managedInstance = scriptResource->getManagedInstance();
+			setValue(obj, (void*)managedInstance, arrayIdx);
+		}
+	}
+
+	HSpriteTexture SerializableFieldInfo::getSpriteTexture(MonoObject* obj, UINT32 arrayIdx)
+	{
+		assert(mType == ScriptFieldType::SpriteTextureRef);
+
+		MonoObject* managedInstance = (MonoObject*)getValue(obj, arrayIdx);
+		if(managedInstance == nullptr)
+			return HTexture();
+
+		ScriptSpriteTexture* scriptResource = ScriptSpriteTexture::toNative(managedInstance);
+		return static_resource_cast<SpriteTexture>(scriptResource->getNativeHandle());
+	}
+
+	void SerializableFieldInfo::setSceneObject(MonoObject* obj, const HSceneObject& sceneObject, UINT32 arrayIdx)
+	{
+		assert(mType == ScriptFieldType::SceneObjectRef);
+
+		// TODO
+	}
+
+	HSceneObject SerializableFieldInfo::getSceneObject(MonoObject* obj, UINT32 arrayIdx)
+	{
+		assert(mType == ScriptFieldType::SceneObjectRef);
+
+		// TODO
+		return HSceneObject();
+	}
+
+	void SerializableFieldInfo::setComponent(MonoObject* obj, const HComponent& component, UINT32 arrayIdx)
+	{
+		assert(mType == ScriptFieldType::ComponentRef);
+
+		// TODO
+	}
+
+	HComponent SerializableFieldInfo::getComponent(MonoObject* obj, UINT32 arrayIdx)
+	{
+		assert(mType == ScriptFieldType::ComponentRef);
+
+		// TODO
+		return HComponent();
+	}
+
+
+	void SerializableFieldInfo::setSerializableObject(MonoObject* obj, const MonoObject* value, UINT32 arrayIdx)
+	{
+		assert(mType == ScriptFieldType::SerializableObjectRef || mType == ScriptFieldType::SerializableObjectValue);
+
+		setValue(obj, (void*)value, arrayIdx);
+	}
+
+	MonoObject* SerializableFieldInfo::getSerializableObject(MonoObject* obj, UINT32 arrayIdx)
+	{
+		assert(mType == ScriptFieldType::SerializableObjectRef || mType == ScriptFieldType::SerializableObjectValue);
+
+		return (MonoObject*)getValue(obj, arrayIdx);
+	}
+
+	void SerializableFieldInfo::setValue(MonoObject* obj, void* val, CM::UINT32 arrayIdx)
+	{
+		if(isArray())
+		{
+			MonoArray* array = (MonoArray*)mMonoField->getValue(obj);
+			UINT32 elemSize = mono_array_element_size(mMonoField->getType()->_getInternalClass());
+
+			UINT32 numElems = (UINT32)mono_array_length(array);
+			assert(arrayIdx < numElems);
+
+			void* elemAddr = mono_array_addr_with_size(array, elemSize, arrayIdx);
+			memcpy(elemAddr, val, elemSize);
+		}
+		else
+		{
+			assert(arrayIdx == 0);
+
+			mMonoField->setValue(obj, val);
+		}
+	}
+
+	void* SerializableFieldInfo::getValue(MonoObject* obj, CM::UINT32 arrayIdx)
+	{
+		if(isArray())
+		{
+			MonoArray* array = (MonoArray*)mMonoField->getValue(obj);
+			UINT32 elemSize = mono_array_element_size(mMonoField->getType()->_getInternalClass());
+
+			UINT32 numElems = (UINT32)mono_array_length(array);
+			assert(arrayIdx < numElems);
+
+			return mono_array_addr_with_size(array, elemSize, arrayIdx);
+		}
+		else
+		{
+			assert(arrayIdx == 0);
+
+			return mMonoField->getValue(obj);
+		}
+	}
+
 	RuntimeScriptObjects::~RuntimeScriptObjects()
 	{
 
@@ -59,10 +463,26 @@ namespace BansheeEngine
 		if(nonSerializedAttribute == nullptr)
 			CM_EXCEPT(InvalidStateException, "Cannot find NonSerializedAttribute managed class.");
 
+		MonoClass* genericListClass = mscorlib->getClass("System", "List`1");
+		if(genericListClass == nullptr)
+			CM_EXCEPT(InvalidStateException, "Cannot find List<T> managed class.");
+
 		MonoClass* componentClass = bansheeEngineAssembly->getClass("BansheeEngine", "Component");
 		if(componentClass == nullptr)
 			CM_EXCEPT(InvalidStateException, "Cannot find Component managed class.");
 
+		MonoClass* sceneObjectClass = bansheeEngineAssembly->getClass("BansheeEngine", "SceneObject");
+		if(sceneObjectClass == nullptr)
+			CM_EXCEPT(InvalidStateException, "Cannot find SceneObject managed class.");
+
+		MonoClass* textureClass = bansheeEngineAssembly->getClass("BansheeEngine", "Texture2D");
+		if(textureClass == nullptr)
+			CM_EXCEPT(InvalidStateException, "Cannot find Texture2D managed class.");
+
+		MonoClass* spriteTextureClass = bansheeEngineAssembly->getClass("BansheeEngine", "SpriteTexture");
+		if(spriteTextureClass == nullptr)
+			CM_EXCEPT(InvalidStateException, "Cannot find SpriteTexture managed class.");
+
 		MonoClass* serializeFieldAttribute = bansheeEngineAssembly->getClass("BansheeEngine", "SerializeField");
 		if(serializeFieldAttribute == nullptr)
 			CM_EXCEPT(InvalidStateException, "Cannot find SerializeField managed class.");
@@ -70,7 +490,7 @@ namespace BansheeEngine
 		MonoClass* hideInInspectorAttribute = bansheeEngineAssembly->getClass("BansheeEngine", "HideInInspector");
 		if(hideInInspectorAttribute == nullptr)
 			CM_EXCEPT(InvalidStateException, "Cannot find HideInInspector managed class.");
-
+		
 		// Process all classes and fields
 		CM::UINT32 mUniqueTypeId = 1;
 
@@ -81,8 +501,8 @@ namespace BansheeEngine
 		std::shared_ptr<SerializableAssemblyInfo> assemblyInfo = cm_shared_ptr<SerializableAssemblyInfo>();
 		mAssemblyInfos[assemblyName] = assemblyInfo;
 
+		// Populate class data
 		const Vector<MonoClass*>::type& allClasses = curAssembly->getAllClasses();
-
 		for(auto& curClass : allClasses)
 		{
 			if((curClass->isSubClassOf(componentClass) || curClass->hasAttribute(serializableAttribute)) && curClass != componentClass)
@@ -94,122 +514,148 @@ namespace BansheeEngine
 				objInfo->mNamespace = curClass->getNamespace();
 				objInfo->mMonoClass = curClass;
 
-				::MonoClass* baseClass = mono_class_get_parent(curClass->_getInternalClass());
-				if(baseClass != nullptr)
-				{
-					String dbgName = mono_class_get_name(baseClass);
-				}
-
 				String fullTypeName = objInfo->mNamespace + "." + objInfo->mTypeName;
 				assemblyInfo->mTypeNameToId[fullTypeName] = objInfo->mTypeId;
 				assemblyInfo->mObjectInfos[objInfo->mTypeId] = objInfo;
+			}
+		}
+
+		// Populate field data
+		for(auto& curClassInfo : assemblyInfo->mObjectInfos)
+		{
+			std::shared_ptr<SerializableObjectInfo> objInfo = curClassInfo.second;
 
-				CM::UINT32 mUniqueFieldId = 1;
-				const CM::Vector<MonoField*>::type& fields = curClass->getAllFields();
+			String fullTypeName = objInfo->mNamespace + "." + objInfo->mTypeName;
+			assemblyInfo->mTypeNameToId[fullTypeName] = objInfo->mTypeId;
+			assemblyInfo->mObjectInfos[objInfo->mTypeId] = objInfo;
 
-				for(auto& field : fields)
+			CM::UINT32 mUniqueFieldId = 1;
+			const CM::Vector<MonoField*>::type& fields = objInfo->mMonoClass->getAllFields();
+
+			for(auto& field : fields)
+			{
+				if(field->isStatic())
+					continue;
+
+				SerializableFieldInfo* fieldInfo = cm_new<SerializableFieldInfo>();
+				fieldInfo->mFieldId = mUniqueFieldId++;
+				fieldInfo->mMonoField = field;
+				fieldInfo->mName = field->getName();
+
+				MonoClass* fieldType = field->getType();
+				fieldInfo->mTypeNamespace = fieldType->getNamespace();
+				fieldInfo->mTypeName = fieldType->getTypeName();
+
+				MonoClass* fieldElementClass = fieldType;
+				MonoType* monoType = mono_class_get_type(fieldType->_getInternalClass());
+				int monoPrimitiveType = mono_type_get_type(monoType);
+
+				// TODO - We don't support nested arrays or multi-dimensional arrays
+				bool isSupportedType = true;
+				if(monoPrimitiveType == MONO_TYPE_ARRAY) 
 				{
-					if(field->isStatic())
-						continue;
-
-					SerializableFieldInfo* fieldInfo = cm_new<SerializableFieldInfo>();
-					fieldInfo->mFieldId = mUniqueFieldId++;
-					fieldInfo->mMonoField = field;
-					fieldInfo->mName = field->getName();
-
-					MonoClass* fieldType = field->getType();
-					fieldInfo->mTypeNamespace = fieldType->getNamespace();
-					fieldInfo->mTypeName = fieldType->getTypeName();
-					
-					MonoType* monoType = mono_class_get_type(fieldType->_getInternalClass());
-					int monoPrimitiveType = mono_type_get_type(monoType);
-					
-					// TODO - We don't support nested arrays or multi-dimensional arrays
-					bool isSupportedType = true;
-					if(monoPrimitiveType == MONO_TYPE_ARRAY) 
+					::MonoClass* elementClass = mono_class_get_element_class(fieldType->_getInternalClass());
+					if(elementClass != nullptr)
+					{
+						monoType = mono_class_get_type(elementClass);
+						monoPrimitiveType = mono_type_get_type(monoType);
+
+						::MonoClass* elementClass = mono_type_get_class(monoType);
+						String elementNs = mono_class_get_namespace(elementClass);
+						String elementTypeName = mono_class_get_name(elementClass);
+
+						fieldElementClass = MonoManager::instance().findClass(elementNs, elementTypeName);
+					}
+
+					fieldInfo->mFlags = (ScriptFieldFlags)((UINT32)fieldInfo->mFlags | (UINT32)ScriptFieldFlags::Array);
+				}
+				// TODO - Also check for List and get its generic primitive
+
+				//  Determine field type
+				switch(monoPrimitiveType) // TODO - If array I need to get underlying type
+				{
+				case MONO_TYPE_BOOLEAN:
+					fieldInfo->mType = ScriptFieldType::Bool;
+					break;
+				case MONO_TYPE_CHAR:
+					fieldInfo->mType = ScriptFieldType::Char;
+					break;
+				case MONO_TYPE_I1:
+					fieldInfo->mType = ScriptFieldType::I8;
+					break;
+				case MONO_TYPE_U1:
+					fieldInfo->mType = ScriptFieldType::U8;
+					break;
+				case MONO_TYPE_I2:
+					fieldInfo->mType = ScriptFieldType::I16;
+					break;
+				case MONO_TYPE_U2:
+					fieldInfo->mType = ScriptFieldType::U16;
+					break;
+				case MONO_TYPE_I4:
+					fieldInfo->mType = ScriptFieldType::I32;
+					break;
+				case MONO_TYPE_U4:
+					fieldInfo->mType = ScriptFieldType::U32;
+					break;
+				case MONO_TYPE_I8:
+					fieldInfo->mType = ScriptFieldType::U64;
+					break;
+				case MONO_TYPE_U8:
+					fieldInfo->mType = ScriptFieldType::U64;
+					break;
+				case MONO_TYPE_STRING:
+					fieldInfo->mType = ScriptFieldType::String;
+					break;
+				case MONO_TYPE_R4:
+					fieldInfo->mType = ScriptFieldType::Float;
+					break;
+				case MONO_TYPE_R8:
+					fieldInfo->mType = ScriptFieldType::Double;
+					break;
+				case MONO_TYPE_CLASS:
+					if(fieldElementClass->isSubClassOf(textureClass))
+						fieldInfo->mType = ScriptFieldType::TextureRef;
+					else if(fieldElementClass->isSubClassOf(spriteTextureClass))
+						fieldInfo->mType = ScriptFieldType::SpriteTextureRef;
+					else if(fieldElementClass->isSubClassOf(sceneObjectClass))
+						fieldInfo->mType = ScriptFieldType::SceneObjectRef;
+					else if(fieldElementClass->isSubClassOf(componentClass))
+						fieldInfo->mType = ScriptFieldType::ComponentRef;
+					else
 					{
-						::MonoClass* elementClass = mono_class_get_element_class(fieldType->_getInternalClass());
-						if(elementClass != nullptr)
-						{
-							monoType = mono_class_get_type(elementClass);
-							monoPrimitiveType = mono_type_get_type(monoType);
-						}
-
-						fieldInfo->mFlags = (ScriptFieldFlags)((UINT32)fieldInfo->mFlags | (UINT32)ScriptFieldFlags::Array);
+						if(hasSerializableObjectInfo(fieldElementClass->getNamespace(), fieldElementClass->getTypeName()))
+							fieldInfo->mType = ScriptFieldType::SerializableObjectRef;
 					}
-					// TODO - Also check for List and get its generic primitive
 
-					//  Determine field type
-					switch(monoPrimitiveType) // TODO - If array I need to get underlying type
+					break;
+				case MONO_TYPE_VALUETYPE:
+					if(hasSerializableObjectInfo(fieldElementClass->getNamespace(), fieldElementClass->getTypeName()))
+						fieldInfo->mType = ScriptFieldType::SerializableObjectValue;
+
+					break;
+				}
+
+				if(fieldInfo->mType != ScriptFieldType::Other)
+				{
+					MonoFieldVisibility visibility = field->getVisibility();
+					if(visibility == MonoFieldVisibility::Public)
 					{
-					case MONO_TYPE_BOOLEAN:
-						fieldInfo->mType = ScriptFieldType::Bool;
-						break;
-					case MONO_TYPE_CHAR:
-						fieldInfo->mType = ScriptFieldType::Char;
-						break;
-					case MONO_TYPE_I1:
-						fieldInfo->mType = ScriptFieldType::I8;
-						break;
-					case MONO_TYPE_U1:
-						fieldInfo->mType = ScriptFieldType::U8;
-						break;
-					case MONO_TYPE_I2:
-						fieldInfo->mType = ScriptFieldType::I16;
-						break;
-					case MONO_TYPE_U2:
-						fieldInfo->mType = ScriptFieldType::U16;
-						break;
-					case MONO_TYPE_I4:
-						fieldInfo->mType = ScriptFieldType::I32;
-						break;
-					case MONO_TYPE_U4:
-						fieldInfo->mType = ScriptFieldType::U32;
-						break;
-					case MONO_TYPE_I8:
-						fieldInfo->mType = ScriptFieldType::U64;
-						break;
-					case MONO_TYPE_U8:
-						fieldInfo->mType = ScriptFieldType::U64;
-						break;
-					case MONO_TYPE_STRING:
-						fieldInfo->mType = ScriptFieldType::String;
-						break;
-					case MONO_TYPE_R4:
-						fieldInfo->mType = ScriptFieldType::Float;
-						break;
-					case MONO_TYPE_R8:
-						fieldInfo->mType = ScriptFieldType::Double;
-						break;
-					case MONO_TYPE_CLASS:
-						// TODO - Check for Resource or GameObject ref, or SerializableObject
-						break;
-					case MONO_TYPE_VALUETYPE:
-						// TODO - Check for SerializableObject
-						break;
+						if(!field->hasAttribute(nonSerializedAttribute))
+							fieldInfo->mFlags = (ScriptFieldFlags)((UINT32)fieldInfo->mFlags | (UINT32)ScriptFieldFlags::Serializable);
+
+						if(!field->hasAttribute(hideInInspectorAttribute))
+							fieldInfo->mFlags = (ScriptFieldFlags)((UINT32)fieldInfo->mFlags | (UINT32)ScriptFieldFlags::Inspectable);
 					}
-					
-					if(fieldInfo->mType != ScriptFieldType::Other)
+					else
 					{
-						MonoFieldVisibility visibility = field->getVisibility();
-						if(visibility == MonoFieldVisibility::Public)
-						{
-							if(!field->hasAttribute(nonSerializedAttribute))
-								fieldInfo->mFlags = (ScriptFieldFlags)((UINT32)fieldInfo->mFlags | (UINT32)ScriptFieldFlags::Serializable);
-
-							if(!field->hasAttribute(hideInInspectorAttribute))
-								fieldInfo->mFlags = (ScriptFieldFlags)((UINT32)fieldInfo->mFlags | (UINT32)ScriptFieldFlags::Inspectable);
-						}
-						else
-						{
-							if(field->hasAttribute(serializeFieldAttribute))
-								fieldInfo->mFlags = (ScriptFieldFlags)((UINT32)fieldInfo->mFlags | (UINT32)ScriptFieldFlags::Serializable);
-						}
+						if(field->hasAttribute(serializeFieldAttribute))
+							fieldInfo->mFlags = (ScriptFieldFlags)((UINT32)fieldInfo->mFlags | (UINT32)ScriptFieldFlags::Serializable);
 					}
-
-					objInfo->mFieldNameToId[fieldInfo->mName] = fieldInfo->mFieldId;
-					objInfo->mFields[fieldInfo->mFieldId] = fieldInfo;
 				}
+
+				objInfo->mFieldNameToId[fieldInfo->mName] = fieldInfo->mFieldId;
+				objInfo->mFields[fieldInfo->mFieldId] = fieldInfo;
 			}
 		}
 
@@ -231,20 +677,6 @@ namespace BansheeEngine
 				base = base->getBaseClass();
 			}
 		}
-	
-		// TODO - How to handle arrays and/or Lists (or collections in general?)
-
-		// TODO - In BsScriptEnginePlugin.cpp I create RuntimeScriptObjects class but never destroy it, for debug purposes. Remember to remove that.
-
-		// TODO - Figure our field type (primitive, gameobject ref, etc.) - Should I do this here or while serializing? Probably here.
-		//    - Add easy way to modify those fields (depending on their type) - Maybe make them virtual
-		//  Detect field type:
-		//   - Primitive - straightforward just check for primitive types
-		//   - GameObjectHandle - check if object is SceneObject or derives from Component
-		//   - SerializableObject - check if object is SerializableObject
-		//   - ResourceHandle - derives from Resource
-
-		// TOOD - Make SerializableObjectInfo IReflectable and create its RTTI
 	}
 
 	void RuntimeScriptObjects::clearScriptObjects(const CM::String& assemblyName)
@@ -260,7 +692,7 @@ namespace BansheeEngine
 			auto iterFind = curAssembly.second->mTypeNameToId.find(fullName);
 			if(iterFind != curAssembly.second->mTypeNameToId.end())
 			{
-				outInfo = curAssembly.second->mObjectInfos[iterFind->first];
+				outInfo = curAssembly.second->mObjectInfos[iterFind->second];
 
 				return true;
 			}
@@ -268,4 +700,17 @@ namespace BansheeEngine
 
 		return false;
 	}
+
+	bool RuntimeScriptObjects::hasSerializableObjectInfo(const CM::String& ns, const CM::String& typeName)
+	{
+		String fullName = ns + "." + typeName;
+		for(auto& curAssembly : mAssemblyInfos)
+		{
+			auto iterFind = curAssembly.second->mTypeNameToId.find(fullName);
+			if(iterFind != curAssembly.second->mTypeNameToId.end())
+				return true;
+		}
+
+		return false;
+	}
 }

+ 0 - 1
SBansheeEngine/Source/BsScriptComponent.cpp

@@ -40,7 +40,6 @@ namespace BansheeEngine
 
 	void ScriptComponent::internal_destroyInstance(ScriptComponent* nativeInstance)
 	{
-		nativeInstance->destroyInstance();
 		cm_delete(nativeInstance);
 	}
 

+ 0 - 1
SBansheeEngine/Source/BsScriptFont.cpp

@@ -42,7 +42,6 @@ namespace BansheeEngine
 
 	void ScriptFont::internal_destroyInstance(ScriptFont* nativeInstance)
 	{
-		nativeInstance->destroyInstance();
 		cm_delete(nativeInstance);
 	}
 }

+ 0 - 1
SBansheeEngine/Source/BsScriptGUIArea.cpp

@@ -91,7 +91,6 @@ namespace BansheeEngine
 
 	void ScriptGUIArea::internal_destroyInstance(ScriptGUIArea* nativeInstance)
 	{
-		nativeInstance->destroyInstance();
 		cm_delete(nativeInstance);
 	}
 

+ 0 - 1
SBansheeEngine/Source/BsScriptGUIButton.cpp

@@ -83,7 +83,6 @@ namespace BansheeEngine
 
 	void ScriptGUIButton::internal_destroyInstance(ScriptGUIButton* nativeInstance)
 	{
-		nativeInstance->destroyInstance();
 		cm_delete(nativeInstance);
 	}
 

+ 0 - 1
SBansheeEngine/Source/BsScriptGUIElementStateStyle.cpp

@@ -63,7 +63,6 @@ namespace BansheeEngine
 
 	void ScriptGUIElementStateStyle::internal_destroyInstance(ScriptGUIElementStateStyle* nativeInstance)
 	{
-		nativeInstance->destroyInstance();
 		cm_delete(nativeInstance);
 	}
 }

+ 0 - 1
SBansheeEngine/Source/BsScriptGUIElementStyle.cpp

@@ -65,7 +65,6 @@ namespace BansheeEngine
 
 	void ScriptGUIElementStyle::internal_destroyInstance(ScriptGUIElementStyle* nativeInstance)
 	{
-		nativeInstance->destroyInstance();
 		cm_delete(nativeInstance);
 	}
 }

+ 0 - 1
SBansheeEngine/Source/BsScriptGUIFixedSpace.cpp

@@ -50,7 +50,6 @@ namespace BansheeEngine
 
 	void ScriptGUIFixedSpace::internal_destroyInstance(ScriptGUIFixedSpace* nativeInstance)
 	{
-		nativeInstance->destroyInstance();
 		cm_delete(nativeInstance);
 	}
 

+ 0 - 1
SBansheeEngine/Source/BsScriptGUIFlexibleSpace.cpp

@@ -50,7 +50,6 @@ namespace BansheeEngine
 
 	void ScriptGUIFlexibleSpace::internal_destroyInstance(ScriptGUIFlexibleSpace* nativeInstance)
 	{
-		nativeInstance->destroyInstance();
 		cm_delete(nativeInstance);
 	}
 

+ 0 - 1
SBansheeEngine/Source/BsScriptGUIInputBox.cpp

@@ -70,7 +70,6 @@ namespace BansheeEngine
 
 	void ScriptGUIInputBox::internal_destroyInstance(ScriptGUIInputBox* nativeInstance)
 	{
-		nativeInstance->destroyInstance();
 		cm_delete(nativeInstance);
 	}
 

+ 0 - 1
SBansheeEngine/Source/BsScriptGUILabel.cpp

@@ -68,7 +68,6 @@ namespace BansheeEngine
 
 	void ScriptGUILabel::internal_destroyInstance(ScriptGUILabel* nativeInstance)
 	{
-		nativeInstance->destroyInstance();
 		cm_delete(nativeInstance);
 	}
 

+ 0 - 1
SBansheeEngine/Source/BsScriptGUILayout.cpp

@@ -91,7 +91,6 @@ namespace BansheeEngine
 
 	void ScriptGUILayout::internal_destroyInstance(ScriptGUILayout* nativeInstance)
 	{
-		nativeInstance->destroyInstance();
 		cm_delete(nativeInstance);
 	}
 

+ 0 - 1
SBansheeEngine/Source/BsScriptGUIListBox.cpp

@@ -89,7 +89,6 @@ namespace BansheeEngine
 
 	void ScriptGUIListBox::internal_destroyInstance(ScriptGUIListBox* nativeInstance)
 	{
-		nativeInstance->destroyInstance();
 		cm_delete(nativeInstance);
 	}
 

+ 0 - 1
SBansheeEngine/Source/BsScriptGUIScrollArea.cpp

@@ -79,7 +79,6 @@ namespace BansheeEngine
 
 	void ScriptGUIScrollArea::internal_destroyInstance(ScriptGUIScrollArea* nativeInstance)
 	{
-		nativeInstance->destroyInstance();
 		cm_delete(nativeInstance);
 	}
 

+ 0 - 1
SBansheeEngine/Source/BsScriptGUITexture.cpp

@@ -74,7 +74,6 @@ namespace BansheeEngine
 
 	void ScriptGUITexture::internal_destroyInstance(ScriptGUITexture* nativeInstance)
 	{
-		nativeInstance->destroyInstance();
 		cm_delete(nativeInstance);
 	}
 

+ 0 - 1
SBansheeEngine/Source/BsScriptGUIToggle.cpp

@@ -94,7 +94,6 @@ namespace BansheeEngine
 
 	void ScriptGUIToggle::internal_destroyInstance(ScriptGUIToggle* nativeInstance)
 	{
-		nativeInstance->destroyInstance();
 		cm_delete(nativeInstance);
 	}
 

+ 0 - 1
SBansheeEngine/Source/BsScriptGUIToggleGroup.cpp

@@ -42,7 +42,6 @@ namespace BansheeEngine
 
 	void ScriptGUIToggleGroup::internal_destroyInstance(ScriptGUIToggleGroup* nativeInstance)
 	{
-		nativeInstance->destroyInstance();
 		cm_delete(nativeInstance);
 	}
 }

+ 6 - 0
SBansheeEngine/Source/BsScriptGameObjectManager.cpp

@@ -0,0 +1,6 @@
+#include "BsScriptGameObjectManager.h"
+
+namespace BansheeEngine
+{
+
+}

+ 0 - 1
SBansheeEngine/Source/BsScriptHString.cpp

@@ -40,7 +40,6 @@ namespace BansheeEngine
 
 	void ScriptHString::internal_destroyInstance(ScriptHString* nativeInstance)
 	{
-		nativeInstance->destroyInstance();
 		cm_delete(nativeInstance);
 	}
 

+ 125 - 0
SBansheeEngine/Source/BsScriptResourceManager.cpp

@@ -0,0 +1,125 @@
+#include "BsScriptResourceManager.h"
+#include "BsMonoManager.h"
+#include "BsMonoAssembly.h"
+#include "BsMonoClass.h"
+#include "BsScriptTexture2D.h"
+#include "BsScriptSpriteTexture.h"
+
+using namespace CamelotFramework;
+
+namespace BansheeEngine
+{
+	ScriptResourceManager::ScriptResourceManager()
+		:mTextureClass(nullptr), mSpriteTextureClass(nullptr)
+	{
+		MonoAssembly* assembly = MonoManager::instance().getAssembly(BansheeEngineAssemblyName);
+		if(assembly == nullptr)
+			CM_EXCEPT(InternalErrorException, "Cannot find \"" + String(BansheeEngineAssemblyName) + "\" assembly.");
+
+		mTextureClass = assembly->getClass("BansheeEngine", "Texture2D");
+		mSpriteTextureClass = assembly->getClass("BansheeEngine", "SpriteTexture");
+
+		if(mTextureClass == nullptr)
+			CM_EXCEPT(InternalErrorException, "Cannot find managed Texture2D class.");
+
+		if(mSpriteTextureClass == nullptr)
+			CM_EXCEPT(InternalErrorException, "Cannot find managed SpriteTexture class.");
+	}
+
+	ScriptTexture2D* ScriptResourceManager::createScriptTexture(const HTexture& resourceHandle)
+	{
+		MonoObject* monoInstance = mTextureClass->createInstance();
+
+		return createScriptTexture(monoInstance, resourceHandle);
+	}
+
+	ScriptTexture2D* ScriptResourceManager::createScriptTexture(MonoObject* instance, const HTexture& resourceHandle)
+	{
+		const String& uuid = resourceHandle.getUUID();
+		throwExceptionIfInvalidOrDuplicate(uuid);
+
+		ScriptTexture2D* scriptResource = new (cm_alloc<ScriptTexture2D>()) ScriptTexture2D(resourceHandle);
+		mScriptResources[uuid] = scriptResource;
+
+		scriptResource->createInstance(instance);
+		scriptResource->metaData.thisPtrField->setValue(instance, scriptResource);
+
+		return scriptResource;
+	}
+
+	ScriptSpriteTexture* ScriptResourceManager::createScriptSpriteTexture(const HSpriteTexture& resourceHandle)
+	{
+		MonoObject* monoInstance = mSpriteTextureClass->createInstance();
+
+		return createScriptSpriteTexture(monoInstance, resourceHandle);
+	}
+
+	ScriptSpriteTexture* ScriptResourceManager::createScriptSpriteTexture(MonoObject* instance, const HSpriteTexture& resourceHandle)
+	{
+		const String& uuid = resourceHandle.getUUID();
+		throwExceptionIfInvalidOrDuplicate(uuid);
+
+		ScriptSpriteTexture* scriptResource = new (cm_alloc<ScriptSpriteTexture>()) ScriptSpriteTexture(resourceHandle);
+		mScriptResources[uuid] = scriptResource;
+
+		scriptResource->createInstance(instance);
+		scriptResource->metaData.thisPtrField->setValue(instance, scriptResource);
+
+		return scriptResource;
+	}
+
+	ScriptTexture2D* ScriptResourceManager::getScriptTexture(const CM::HTexture& resourceHandle)
+	{
+		return static_cast<ScriptTexture2D*>(getScriptResource(resourceHandle));
+	}
+
+	ScriptSpriteTexture* ScriptResourceManager::getScriptSpriteTexture(const HSpriteTexture& resourceHandle)
+	{
+		return static_cast<ScriptSpriteTexture*>(getScriptResource(resourceHandle));
+	}
+
+	ScriptResource* ScriptResourceManager::getScriptResource(const CM::HResource& resourceHandle)
+	{
+		const String& uuid = resourceHandle.getUUID();
+
+		if(uuid == "")
+			CM_EXCEPT(InvalidParametersException, "Provided resource handle has an undefined resource UUID.");
+
+		auto findIter = mScriptResources.find(uuid);
+		if(findIter != mScriptResources.end())
+			return findIter->second;
+
+		return nullptr;
+	}
+
+	void ScriptResourceManager::destroyScriptResource(ScriptResource* resource)
+	{
+		HResource resourceHandle = resource->getNativeHandle();
+		const String& uuid = resourceHandle.getUUID();
+
+		if(uuid == "")
+			CM_EXCEPT(InvalidParametersException, "Provided resource handle has an undefined resource UUID.");
+
+		auto findIter = mScriptResources.find(uuid);
+		if(findIter != mScriptResources.end())
+		{
+			(resource)->~ScriptResource();
+			MemoryAllocator<GenAlloc>::free(resource);
+
+			mScriptResources.erase(findIter);
+		}
+	}
+
+	void ScriptResourceManager::throwExceptionIfInvalidOrDuplicate(const CM::String& uuid) const
+	{
+		if(uuid == "")
+			CM_EXCEPT(InvalidParametersException, "Provided resource handle has an undefined resource UUID.");
+
+		auto findIter = mScriptResources.find(uuid);
+		if(findIter != mScriptResources.end())
+		{
+			CM_EXCEPT(InvalidStateException, "Provided resource handle already has a script resource. \
+											 Retrieve the existing instance instead of creating a new one.");
+		}
+	}
+}

+ 3 - 6
SBansheeEngine/Source/BsScriptSpriteTexture.cpp

@@ -1,4 +1,5 @@
 #include "BsScriptSpriteTexture.h"
+#include "BsScriptResourceManager.h"
 #include "BsScriptMeta.h"
 #include "BsMonoField.h"
 #include "BsMonoClass.h"
@@ -30,16 +31,12 @@ namespace BansheeEngine
 
 	void ScriptSpriteTexture::internal_createInstance(MonoObject* instance)
 	{
-		ScriptSpriteTexture* nativeInstance = new (cm_alloc<ScriptSpriteTexture>()) ScriptSpriteTexture(SpriteTexture::dummy()); // TODO - DUMMY CODE!
-		nativeInstance->createInstance(instance);
-
-		metaData.thisPtrField->setValue(instance, nativeInstance);
+		ScriptResourceManager::instance().createScriptSpriteTexture(instance, SpriteTexture::dummy()); // TODO - DUMMY CODE!
 	}
 
 	void ScriptSpriteTexture::internal_destroyInstance(ScriptSpriteTexture* nativeInstance)
 	{
-		nativeInstance->destroyInstance();
-		cm_delete(nativeInstance);
+		ScriptResourceManager::instance().destroyScriptResource(nativeInstance);
 	}
 
 	void ScriptSpriteTexture::setNativeHandle(const HResource& resource) 

+ 3 - 6
SBansheeEngine/Source/BsScriptTexture2D.cpp

@@ -1,4 +1,5 @@
 #include "BsScriptTexture2D.h"
+#include "BsScriptResourceManager.h"
 #include "BsScriptMeta.h"
 #include "BsMonoField.h"
 #include "BsMonoClass.h"
@@ -51,16 +52,12 @@ namespace BansheeEngine
 
 		HTexture texture = Texture::create(TEX_TYPE_2D, width, height, numMips, texFormat, TU_STATIC, gammaCorrection);
 
-		ScriptTexture2D* nativeInstance = new (cm_alloc<ScriptTexture2D>()) ScriptTexture2D(texture);
-		nativeInstance->createInstance(instance);
-
-		metaData.thisPtrField->setValue(instance, nativeInstance);
+		ScriptResourceManager::instance().createScriptTexture(instance, texture);
 	}
 
 	void ScriptTexture2D::internal_destroyInstance(ScriptTexture2D* nativeInstance)
 	{
-		nativeInstance->destroyInstance();
-		cm_delete(nativeInstance);
+		ScriptResourceManager::instance().destroyScriptResource(nativeInstance);
 	}
 
 	void ScriptTexture2D::setNativeHandle(const HResource& resource)