Răsfoiți Sursa

ManagedResource saving/loading mostly finished but untested

Marko Pintera 11 ani în urmă
părinte
comite
0ca3bc9a98
32 a modificat fișierele cu 352 adăugiri și 38 ștergeri
  1. 2 1
      BansheeCore/Include/BsImporter.h
  2. 2 0
      BansheeEditor/BansheeEditor.vcxproj
  3. 6 0
      BansheeEditor/BansheeEditor.vcxproj.filters
  4. 1 0
      BansheeEditor/Include/BsProjectLibrary.h
  5. 32 0
      BansheeEditor/Include/BsResourceImporter.h
  6. 4 0
      BansheeEditor/Source/BsEditorApplication.cpp
  7. 20 0
      BansheeEditor/Source/BsProjectLibrary.cpp
  8. 49 0
      BansheeEditor/Source/BsResourceImporter.cpp
  9. 2 1
      BansheeMono/Source/BsMonoAssembly.cpp
  10. 15 7
      BansheeMono/Source/BsMonoManager.cpp
  11. 6 8
      Inspector.txt
  12. 12 0
      MBansheeEditor/DbgResource.cs
  13. 1 0
      MBansheeEditor/MBansheeEditor.csproj
  14. 1 0
      MBansheeEngine/MBansheeEngine.csproj
  15. 19 0
      MBansheeEngine/ManagedResource.cs
  16. 5 1
      MBansheeEngine/Resource.cs
  17. 1 1
      SBansheeEditor/Source/BsScriptProjectLibrary.cpp
  18. 4 5
      SBansheeEngine/Include/BsManagedResource.h
  19. 1 5
      SBansheeEngine/Include/BsManagedResourceRTTI.h
  20. 1 0
      SBansheeEngine/Include/BsManagedSerializableObjectInfo.h
  21. 2 0
      SBansheeEngine/Include/BsRuntimeScriptObjects.h
  22. 1 0
      SBansheeEngine/Include/BsScriptEnginePrerequisites.h
  23. 29 0
      SBansheeEngine/Include/BsScriptManagedResource.h
  24. 11 0
      SBansheeEngine/Include/BsScriptResourceManager.h
  25. 2 0
      SBansheeEngine/SBansheeEngine.vcxproj
  26. 6 0
      SBansheeEngine/SBansheeEngine.vcxproj.filters
  27. 19 7
      SBansheeEngine/Source/BsManagedResource.cpp
  28. 25 0
      SBansheeEngine/Source/BsManagedSerializableField.cpp
  29. 2 0
      SBansheeEngine/Source/BsManagedSerializableObjectInfo.cpp
  30. 14 2
      SBansheeEngine/Source/BsRuntimeScriptObjects.cpp
  31. 40 0
      SBansheeEngine/Source/BsScriptManagedResource.cpp
  32. 17 0
      SBansheeEngine/Source/BsScriptResourceManager.cpp

+ 2 - 1
BansheeCore/Include/BsImporter.h

@@ -84,7 +84,8 @@ namespace BansheeEngine
 		 * @brief	Adds a new asset importer for the specified file extension. If an asset importer for that extension
 		 * @brief	Adds a new asset importer for the specified file extension. If an asset importer for that extension
 		 * 			already exists, it is removed and replaced with the current one.
 		 * 			already exists, it is removed and replaced with the current one.
 		 * 			
 		 * 			
-		 * @note	Internal method. This method should only be called by asset importers themselves on startup.
+		 * @note	Internal method. This method should only be called by asset importers themselves on startup. Importer takes ownership
+		 *			of the provided pointer and will release it. Assumes it is allocated using the general allocator.
 		 *
 		 *
 		 * @param [in]	importer	The importer that is able to handle files with the specified extension. nullptr if you
 		 * @param [in]	importer	The importer that is able to handle files with the specified extension. nullptr if you
 		 * 							want to remove an asset importer for the extension.
 		 * 							want to remove an asset importer for the extension.

+ 2 - 0
BansheeEditor/BansheeEditor.vcxproj

@@ -312,6 +312,7 @@
     <ClInclude Include="Include\BsProjectResourceMetaRTTI.h" />
     <ClInclude Include="Include\BsProjectResourceMetaRTTI.h" />
     <ClInclude Include="Include\BsGUIVector2Field.h" />
     <ClInclude Include="Include\BsGUIVector2Field.h" />
     <ClInclude Include="Include\BsDebugCamera.h" />
     <ClInclude Include="Include\BsDebugCamera.h" />
+    <ClInclude Include="Include\BsResourceImporter.h" />
     <ClInclude Include="Include\BsTestTextSprite.h" />
     <ClInclude Include="Include\BsTestTextSprite.h" />
     <ClInclude Include="Include\DbgEditorWidget1.h" />
     <ClInclude Include="Include\DbgEditorWidget1.h" />
     <ClInclude Include="Include\DbgEditorWidget2.h" />
     <ClInclude Include="Include\DbgEditorWidget2.h" />
@@ -358,6 +359,7 @@
     <ClCompile Include="Source\BsProjectLibrary.cpp" />
     <ClCompile Include="Source\BsProjectLibrary.cpp" />
     <ClCompile Include="Source\BsProjectLibraryEntries.cpp" />
     <ClCompile Include="Source\BsProjectLibraryEntries.cpp" />
     <ClCompile Include="Source\BsProjectResourceMeta.cpp" />
     <ClCompile Include="Source\BsProjectResourceMeta.cpp" />
+    <ClCompile Include="Source\BsResourceImporter.cpp" />
     <ClCompile Include="Source\BsUndoRedo.cpp" />
     <ClCompile Include="Source\BsUndoRedo.cpp" />
     <ClCompile Include="Source\BsDebugCamera.cpp" />
     <ClCompile Include="Source\BsDebugCamera.cpp" />
     <ClCompile Include="Source\BsEditorApplication.cpp" />
     <ClCompile Include="Source\BsEditorApplication.cpp" />

+ 6 - 0
BansheeEditor/BansheeEditor.vcxproj.filters

@@ -192,6 +192,9 @@
     <ClInclude Include="Include\BsProjectResourceMetaRTTI.h">
     <ClInclude Include="Include\BsProjectResourceMetaRTTI.h">
       <Filter>Header Files\Editor</Filter>
       <Filter>Header Files\Editor</Filter>
     </ClInclude>
     </ClInclude>
+    <ClInclude Include="Include\BsResourceImporter.h">
+      <Filter>Header Files\Editor</Filter>
+    </ClInclude>
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\BsEditorWidgetContainer.cpp">
     <ClCompile Include="Source\BsEditorWidgetContainer.cpp">
@@ -332,5 +335,8 @@
     <ClCompile Include="Source\BsProjectResourceMeta.cpp">
     <ClCompile Include="Source\BsProjectResourceMeta.cpp">
       <Filter>Source Files\Editor</Filter>
       <Filter>Source Files\Editor</Filter>
     </ClCompile>
     </ClCompile>
+    <ClCompile Include="Source\BsResourceImporter.cpp">
+      <Filter>Source Files\Editor</Filter>
+    </ClCompile>
   </ItemGroup>
   </ItemGroup>
 </Project>
 </Project>

+ 1 - 0
BansheeEditor/Include/BsProjectLibrary.h

@@ -60,6 +60,7 @@ namespace BansheeEngine
 
 
 		ProjectResourceMetaPtr findResourceMeta(const String& uuid) const;
 		ProjectResourceMetaPtr findResourceMeta(const String& uuid) const;
 
 
+		void createEntry(const HResource& resource, const Path& path);
 		void moveEntry(const Path& oldPath, const Path& newPath);
 		void moveEntry(const Path& oldPath, const Path& newPath);
 		void deleteEntry(const Path& path);
 		void deleteEntry(const Path& path);
 
 

+ 32 - 0
BansheeEditor/Include/BsResourceImporter.h

@@ -0,0 +1,32 @@
+#pragma once
+
+#include "BsEditorPrerequisites.h"
+#include "BsSpecificImporter.h"
+
+namespace BansheeEngine
+{
+	/**
+	 * @brief	Imports Banshee resources. Essentially just does a pass-through
+	 *			as source asset to import and resulting resource are one and the same.
+	 *
+	 * @note	This is useful in the project library where we sometimes want to save processed
+	 *			resources in the library.
+	 */
+	class BS_ED_EXPORT ResourceImporter : public SpecificImporter
+	{
+	public:
+		ResourceImporter();
+		virtual ~ResourceImporter();
+
+		/** @copydoc SpecificImporter::isExtensionSupported */
+		virtual bool isExtensionSupported(const WString& ext) const;
+
+		/** @copydoc SpecificImporter::isMagicNumberSupported */
+		virtual bool isMagicNumberSupported(const UINT8* magicNumPtr, UINT32 numBytes) const;
+
+		/** @copydoc SpecificImporter::import */
+		virtual ResourcePtr import(const Path& filePath, ConstImportOptionsPtr importOptions);
+
+		static const WString DEFAULT_EXTENSION;
+	};
+}

+ 4 - 0
BansheeEditor/Source/BsEditorApplication.cpp

@@ -8,6 +8,7 @@
 #include "BsFileSerializer.h"
 #include "BsFileSerializer.h"
 #include "BsFileSystem.h"
 #include "BsFileSystem.h"
 #include "BsPath.h"
 #include "BsPath.h"
+#include "BsResourceImporter.h"
 #include "BsEditorWidgetLayout.h"
 #include "BsEditorWidgetLayout.h"
 
 
 // DEBUG ONLY
 // DEBUG ONLY
@@ -68,6 +69,9 @@ namespace BansheeEngine
 			inputConfig->registerButton("Delete", BC_DELETE);
 			inputConfig->registerButton("Delete", BC_DELETE);
 		}
 		}
 
 
+		ResourceImporter* resourceImporter = bs_new<ResourceImporter>();
+		Importer::instance()._registerAssetImporter(resourceImporter);
+
 		ProjectLibrary::startUp(getActiveProjectPath());
 		ProjectLibrary::startUp(getActiveProjectPath());
 
 
 		UndoRedo::startUp();
 		UndoRedo::startUp();

+ 20 - 0
BansheeEditor/Source/BsProjectLibrary.cpp

@@ -14,6 +14,7 @@
 #include "BsDebug.h"
 #include "BsDebug.h"
 #include "BsProjectLibraryEntries.h"
 #include "BsProjectLibraryEntries.h"
 #include "BsResource.h"
 #include "BsResource.h"
+#include "BsResourceImporter.h"
 
 
 using namespace std::placeholders;
 using namespace std::placeholders;
 
 
@@ -481,6 +482,25 @@ namespace BansheeEngine
 		return resEntry->meta;
 		return resEntry->meta;
 	}
 	}
 
 
+	void ProjectLibrary::createEntry(const HResource& resource, const Path& path)
+	{
+		if (resource == nullptr)
+			return;
+
+		if (!mResourcesFolder.includes(path))
+			BS_EXCEPT(InvalidParametersException, "Provided path is not within the project library directory: " + path.toString());
+
+		Path assetPath = path;
+		assetPath.setExtension(assetPath.getWExtension() + L"." + ResourceImporter::DEFAULT_EXTENSION);
+
+		LibraryEntry* existingEntry = findEntry(assetPath);
+		if (existingEntry != nullptr)
+			BS_EXCEPT(InvalidParametersException, "Existing resource already exists at the specified path: " + assetPath.toString());
+
+		Resources::instance().save(resource, assetPath, false);
+		checkForModifications(assetPath);
+	}
+
 	void ProjectLibrary::moveEntry(const Path& oldPath, const Path& newPath)
 	void ProjectLibrary::moveEntry(const Path& oldPath, const Path& newPath)
 	{
 	{
 		if(FileSystem::isFile(oldPath) || FileSystem::isDirectory(oldPath))
 		if(FileSystem::isFile(oldPath) || FileSystem::isDirectory(oldPath))

+ 49 - 0
BansheeEditor/Source/BsResourceImporter.cpp

@@ -0,0 +1,49 @@
+#include "BsResourceImporter.h"
+#include "BsPath.h"
+#include "BsFileSerializer.h"
+#include "BsResource.h"
+
+namespace BansheeEngine
+{
+	const WString ResourceImporter::DEFAULT_EXTENSION = L"asset";
+
+	ResourceImporter::ResourceImporter()
+		:SpecificImporter()
+	{
+
+	}
+
+	ResourceImporter::~ResourceImporter()
+	{
+
+	}
+
+	bool ResourceImporter::isExtensionSupported(const WString& ext) const
+	{
+		WString lowerCaseExt = ext;
+		StringUtil::toLowerCase(lowerCaseExt);
+
+		return lowerCaseExt == DEFAULT_EXTENSION;
+	}
+
+	bool ResourceImporter::isMagicNumberSupported(const UINT8* magicNumPtr, UINT32 numBytes) const
+	{
+		return true; // No magic number of asset files, they must always rely on extension
+	}
+
+	ResourcePtr ResourceImporter::import(const Path& filePath, ConstImportOptionsPtr importOptions)
+	{
+		FileSerializer fs;
+		std::shared_ptr<IReflectable> loadedData = fs.decode(filePath);
+
+		if (loadedData == nullptr)
+			BS_EXCEPT(InternalErrorException, "Unable to import resource.");
+
+		if (!loadedData->isDerivedFrom(Resource::getRTTIStatic()))
+			BS_EXCEPT(InternalErrorException, "Imported object doesn't derive from Resource.");
+
+		ResourcePtr resource = std::static_pointer_cast<Resource>(loadedData);
+
+		return resource;
+	}
+}

+ 2 - 1
BansheeMono/Source/BsMonoAssembly.cpp

@@ -93,7 +93,8 @@ namespace BansheeEngine
 
 
 		if(mMonoImage != nullptr && !mIsDependency)
 		if(mMonoImage != nullptr && !mIsDependency)
 		{
 		{
-			mono_image_close(mMonoImage);
+			//mono_image_close(mMonoImage); // This seems to cause a crash but unloading just the assembly /seems/ to work
+			mono_assembly_close(mMonoAssembly);
 			mMonoImage = nullptr;
 			mMonoImage = nullptr;
 		}
 		}
 
 

+ 15 - 7
BansheeMono/Source/BsMonoManager.cpp

@@ -6,6 +6,7 @@
 
 
 #include <mono/metadata/assembly.h>
 #include <mono/metadata/assembly.h>
 #include <mono/metadata/mono-config.h>
 #include <mono/metadata/mono-config.h>
+#include <mono/metadata/mono-gc.h>
 
 
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
@@ -21,16 +22,25 @@ namespace BansheeEngine
 
 
 	MonoManager::~MonoManager()
 	MonoManager::~MonoManager()
 	{
 	{
-		if(mDomain != nullptr)
+		if (mDomain != nullptr)
 		{
 		{
+			// TODO - Someone suggested I need to GC collect and wait for finalizers before cleanup
+			// I don't see how that would help unless I manually release all references before that as well
+			// BUT that is a good way to debug those errors on exit
+
+			// TODO: This might not be necessary
+			//mono_gc_collect(mono_gc_max_generation());
+			//mono_domain_finalize(mDomain, -1);
+
+			// TODO: Commented out because it crashes for no reason
 			mono_jit_cleanup(mDomain);
 			mono_jit_cleanup(mDomain);
 			mDomain = nullptr;
 			mDomain = nullptr;
 		}
 		}
 
 
 		for (auto& entry : mAssemblies)
 		for (auto& entry : mAssemblies)
 		{
 		{
-			unloadAssembly(*entry.second);
-			bs_delete(entry.second);
+			//unloadAssembly(*entry.second);
+			//bs_delete(entry.second);
 		}
 		}
 
 
 		mAssemblies.clear();
 		mAssemblies.clear();
@@ -105,10 +115,8 @@ namespace BansheeEngine
 		::MonoAssembly* monoAssembly = assembly.mMonoAssembly;
 		::MonoAssembly* monoAssembly = assembly.mMonoAssembly;
 		assembly.unload();
 		assembly.unload();
 
 
-		// TODO: Not calling this because it crashed if called before domain was unloaded. Try calling
-		// it after. I'm not sure if its even necessary to call it.
-		//if(monoAssembly)
-			//mono_assembly_close(monoAssembly);
+		if(monoAssembly)
+			mono_assembly_close(monoAssembly);
 	}
 	}
 
 
 	MonoAssembly* MonoManager::getAssembly(const String& name) const
 	MonoAssembly* MonoManager::getAssembly(const String& name) const

+ 6 - 8
Inspector.txt

@@ -1,14 +1,12 @@
 Update C# GUIElementStyle
 Update C# GUIElementStyle
 Update GUIFoldout with sub styles
 Update GUIFoldout with sub styles
 
 
-ManagedResource class is unfinished. Need to clean up managed instance after resource is released.
-Its getMetaData should return managed type of the stored resource
-Update GUIResourceField so it uses meta data for detecting valid type
-
-How will I create ManagedResource from C#?
- - BansheeEditor::ProjectLibrary::create(obj, path)
- - This call C++ with the managed instance. Object is checked if it is Serializable
- - If so it is serialized using ManagedSerializableObjectPtr
+Finish ProjectLibrary::create
+ - Resource gets serialized directly as .asset (whether its a mesh, texture or custom asset)
+ - When ProjectLibrary encounters such resource it will import it using a dummy pass through importer
+
+Need to add stuff derived from ManagedResource to serializable list in RuntimeScriptObjects
+
 
 
 TODO:
 TODO:
  - Hook up int field set/get callbacks
  - Hook up int field set/get callbacks

+ 12 - 0
MBansheeEditor/DbgResource.cs

@@ -0,0 +1,12 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace BansheeEditor
+{
+    class DbgResource
+    {
+    }
+}

+ 1 - 0
MBansheeEditor/MBansheeEditor.csproj

@@ -41,6 +41,7 @@
   <ItemGroup>
   <ItemGroup>
     <Compile Include="DbgCustomInspector.cs" />
     <Compile Include="DbgCustomInspector.cs" />
     <Compile Include="DbgEditorWindow.cs" />
     <Compile Include="DbgEditorWindow.cs" />
+    <Compile Include="DbgResource.cs" />
     <Compile Include="Debug_Component1.cs" />
     <Compile Include="Debug_Component1.cs" />
     <Compile Include="Debug_Component2.cs" />
     <Compile Include="Debug_Component2.cs" />
     <Compile Include="EditorApplication.cs" />
     <Compile Include="EditorApplication.cs" />

+ 1 - 0
MBansheeEngine/MBansheeEngine.csproj

@@ -76,6 +76,7 @@
     <Compile Include="GUI\GUIToggleGroup.cs" />
     <Compile Include="GUI\GUIToggleGroup.cs" />
     <Compile Include="HideInInspector.cs" />
     <Compile Include="HideInInspector.cs" />
     <Compile Include="LocString.cs" />
     <Compile Include="LocString.cs" />
+    <Compile Include="ManagedResource.cs" />
     <Compile Include="Math\MathEx.cs" />
     <Compile Include="Math\MathEx.cs" />
     <Compile Include="Math\Matrix3.cs" />
     <Compile Include="Math\Matrix3.cs" />
     <Compile Include="Math\Matrix4.cs" />
     <Compile Include="Math\Matrix4.cs" />

+ 19 - 0
MBansheeEngine/ManagedResource.cs

@@ -0,0 +1,19 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.CompilerServices;
+using System.Text;
+
+namespace BansheeEngine
+{
+    public class ManagedResource : Resource
+    {
+        public ManagedResource()
+        {
+            Internal_CreateResource(this);
+        }
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_CreateResource(ManagedResource resource);
+    }
+}

+ 5 - 1
MBansheeEngine/Resource.cs

@@ -1,6 +1,10 @@
-namespace BansheeEngine
+using System;
+using System.Runtime.CompilerServices;
+
+namespace BansheeEngine
 {
 {
     public class Resource : ScriptObject // TODO - Dummy class
     public class Resource : ScriptObject // TODO - Dummy class
     {
     {
+
     }
     }
 }
 }

+ 1 - 1
SBansheeEditor/Source/BsScriptProjectLibrary.cpp

@@ -23,6 +23,6 @@ namespace BansheeEngine
 		ScriptResource* scrResource = ScriptResource::toNative(resource);
 		ScriptResource* scrResource = ScriptResource::toNative(resource);
 		Path resourcePath = MonoUtil::monoToWString(path);
 		Path resourcePath = MonoUtil::monoToWString(path);
 
 
-		//ProjectLibrary::instance().create(scrResource->getNativeHandle(), resourcePath);
+		ProjectLibrary::instance().createEntry(scrResource->getNativeHandle(), resourcePath);
 	}
 	}
 }
 }

+ 4 - 5
SBansheeEngine/Include/BsManagedResource.h

@@ -10,19 +10,18 @@ namespace BansheeEngine
 	class BS_SCR_BE_EXPORT ManagedResource : public Resource
 	class BS_SCR_BE_EXPORT ManagedResource : public Resource
 	{
 	{
 	public:
 	public:
-		ManagedResource(MonoReflectionType* runtimeType);
-		void construct(MonoObject* object, MonoReflectionType* runtimeType);
+		void construct(MonoObject* object);
 
 
 		MonoObject* getManagedInstance() const { return mManagedInstance; }
 		MonoObject* getManagedInstance() const { return mManagedInstance; }
-		MonoReflectionType* getRuntimeType() const { return mRuntimeType; }
 
 
+		static HManagedResource create(MonoObject* managedResource);
 		static ManagedResourcePtr createEmpty();
 		static ManagedResourcePtr createEmpty();
 
 
 	private:
 	private:
+		ManagedResource(MonoObject* managedInstance);
 		void destroy_internal();
 		void destroy_internal();
 
 
 		MonoObject* mManagedInstance;
 		MonoObject* mManagedInstance;
-		MonoReflectionType* mRuntimeType;
 		uint32_t mManagedHandle;
 		uint32_t mManagedHandle;
 
 
 		/************************************************************************/
 		/************************************************************************/
@@ -34,6 +33,6 @@ namespace BansheeEngine
 		virtual RTTITypeBase* getRTTI() const;
 		virtual RTTITypeBase* getRTTI() const;
 
 
 	protected:
 	protected:
-		ManagedResource() {} // Serialization only
+		ManagedResource(); // Serialization only
 	};
 	};
 }
 }

+ 1 - 5
SBansheeEngine/Include/BsManagedResourceRTTI.h

@@ -40,11 +40,7 @@ namespace BansheeEngine
 			ManagedResource* mc = static_cast<ManagedResource*>(obj);
 			ManagedResource* mc = static_cast<ManagedResource*>(obj);
 			ManagedSerializableObjectPtr serializableObject = any_cast<ManagedSerializableObjectPtr>(mc->mRTTIData);
 			ManagedSerializableObjectPtr serializableObject = any_cast<ManagedSerializableObjectPtr>(mc->mRTTIData);
 
 
-			::MonoClass* monoClass = mono_object_get_class(serializableObject->getManagedInstance());
-			MonoType* monoType = mono_class_get_type(monoClass);
-			MonoReflectionType* runtimeType = mono_type_get_object(MonoManager::instance().getDomain(), monoType);
-
-			mc->construct(serializableObject->getManagedInstance(), runtimeType);
+			mc->construct(serializableObject->getManagedInstance());
 		}
 		}
 
 
 		virtual const String& getRTTIName()
 		virtual const String& getRTTIName()

+ 1 - 0
SBansheeEngine/Include/BsManagedSerializableObjectInfo.h

@@ -23,6 +23,7 @@ namespace BansheeEngine
 		String,
 		String,
 		TextureRef,
 		TextureRef,
 		SpriteTextureRef,
 		SpriteTextureRef,
+		ManagedResourceRef,
 		SceneObjectRef,
 		SceneObjectRef,
 		ComponentRef
 		ComponentRef
 	};
 	};

+ 2 - 0
SBansheeEngine/Include/BsRuntimeScriptObjects.h

@@ -22,6 +22,7 @@ namespace BansheeEngine
 		MonoClass* getSystemGenericDictionaryClass() const { return mSystemGenericDictionaryClass; }
 		MonoClass* getSystemGenericDictionaryClass() const { return mSystemGenericDictionaryClass; }
 		MonoClass* getComponentClass() const { return mComponentClass; }
 		MonoClass* getComponentClass() const { return mComponentClass; }
 		MonoClass* getSceneObjectClass() const { return mSceneObjectClass; }
 		MonoClass* getSceneObjectClass() const { return mSceneObjectClass; }
+		MonoClass* getManagedResourceClass() const { return mManagedResourceClass; }
 		MonoClass* getTextureClass() const { return mTextureClass; }
 		MonoClass* getTextureClass() const { return mTextureClass; }
 		MonoClass* getSpriteTextureClass() const { return mSpriteTextureClass; }
 		MonoClass* getSpriteTextureClass() const { return mSpriteTextureClass; }
 
 
@@ -39,6 +40,7 @@ namespace BansheeEngine
 
 
 		MonoClass* mTextureClass;
 		MonoClass* mTextureClass;
 		MonoClass* mSpriteTextureClass;
 		MonoClass* mSpriteTextureClass;
+		MonoClass* mManagedResourceClass;
 
 
 		MonoClass* mSerializeObjectAttribute;
 		MonoClass* mSerializeObjectAttribute;
 		MonoClass* mDontSerializeFieldAttribute;
 		MonoClass* mDontSerializeFieldAttribute;

+ 1 - 0
SBansheeEngine/Include/BsScriptEnginePrerequisites.h

@@ -34,6 +34,7 @@ namespace BansheeEngine
 	class ScriptGameObjectBase;
 	class ScriptGameObjectBase;
 	class ScriptSceneObject;
 	class ScriptSceneObject;
 	class ScriptComponent;
 	class ScriptComponent;
+	class ScriptManagedResource;
 	class ManagedComponent;
 	class ManagedComponent;
 	class ManagedSerializableFieldData;
 	class ManagedSerializableFieldData;
 	class ManagedSerializableFieldKey;
 	class ManagedSerializableFieldKey;

+ 29 - 0
SBansheeEngine/Include/BsScriptManagedResource.h

@@ -0,0 +1,29 @@
+#pragma once
+
+#include "BsScriptEnginePrerequisites.h"
+#include "BsScriptResource.h"
+#include "BsScriptObject.h"
+
+namespace BansheeEngine
+{
+	class BS_SCR_BE_EXPORT ScriptManagedResource : public ScriptObject<ScriptManagedResource, ScriptResourceBase>
+	{
+	public:
+		SCRIPT_OBJ(BansheeEngineAssemblyName, "BansheeEngine", "ManagedResource")
+
+		ScriptManagedResource(MonoObject* instance, const HManagedResource& resource);
+
+		void* getNativeRaw() const { return mResource.get(); }
+
+		HResource getNativeHandle() const { return mResource; }
+		void setNativeHandle(const HResource& resource);
+	private:
+		friend class ScriptResourceManager;
+
+		static void internal_createInstance(MonoObject* instance);
+
+		void _onManagedInstanceDeleted();
+
+		HManagedResource mResource;
+	};
+}

+ 11 - 0
SBansheeEngine/Include/BsScriptResourceManager.h

@@ -35,6 +35,12 @@ namespace BansheeEngine
 		 */
 		 */
 		ScriptSpriteTexture* createScriptSpriteTexture(MonoObject* existingInstance, const HSpriteTexture& resourceHandle);
 		ScriptSpriteTexture* createScriptSpriteTexture(MonoObject* existingInstance, const HSpriteTexture& resourceHandle);
 
 
+		/**
+		* @note  Throws an exception if resource for the handle already exists.
+		* 		 Initializes the ScriptResource with an existing managed instance.
+		*/
+		ScriptManagedResource* createManagedResource(MonoObject* existingInstance, const HManagedResource& resourceHandle);
+
 		/**
 		/**
 		 * @note Returns nullptr if script resource doesn't exist.
 		 * @note Returns nullptr if script resource doesn't exist.
 		 */
 		 */
@@ -45,6 +51,11 @@ namespace BansheeEngine
 		 */
 		 */
 		ScriptSpriteTexture* getScriptSpriteTexture(const HSpriteTexture& resourceHandle);
 		ScriptSpriteTexture* getScriptSpriteTexture(const HSpriteTexture& resourceHandle);
 
 
+		/**
+		 * @note Returns nullptr if script resource doesn't exist.
+		 */
+		ScriptManagedResource* getScriptManagedResource(const HManagedResource& resourceHandle);
+
 		/**
 		/**
 		 * @note Returns nullptr if script resource doesn't exist.
 		 * @note Returns nullptr if script resource doesn't exist.
 		 */
 		 */

+ 2 - 0
SBansheeEngine/SBansheeEngine.vcxproj

@@ -267,6 +267,7 @@
     <ClInclude Include="Include\BsScriptGUIToggleGroup.h" />
     <ClInclude Include="Include\BsScriptGUIToggleGroup.h" />
     <ClInclude Include="Include\BsScriptHString.h" />
     <ClInclude Include="Include\BsScriptHString.h" />
     <ClInclude Include="Include\BsScriptMacros.h" />
     <ClInclude Include="Include\BsScriptMacros.h" />
+    <ClInclude Include="Include\BsScriptManagedResource.h" />
     <ClInclude Include="Include\BsScriptObject.h" />
     <ClInclude Include="Include\BsScriptObject.h" />
     <ClInclude Include="Include\BsScriptObjectImpl.h" />
     <ClInclude Include="Include\BsScriptObjectImpl.h" />
     <ClInclude Include="Include\BsScriptResource.h" />
     <ClInclude Include="Include\BsScriptResource.h" />
@@ -312,6 +313,7 @@
     <ClCompile Include="Source\BsScriptGUIToggleGroup.cpp" />
     <ClCompile Include="Source\BsScriptGUIToggleGroup.cpp" />
     <ClCompile Include="Source\BsScriptHString.cpp" />
     <ClCompile Include="Source\BsScriptHString.cpp" />
     <ClCompile Include="Source\BsScriptGUIInputBox.cpp" />
     <ClCompile Include="Source\BsScriptGUIInputBox.cpp" />
+    <ClCompile Include="Source\BsScriptManagedResource.cpp" />
     <ClCompile Include="Source\BsScriptObject.cpp" />
     <ClCompile Include="Source\BsScriptObject.cpp" />
     <ClCompile Include="Source\BsScriptObjectImpl.cpp" />
     <ClCompile Include="Source\BsScriptObjectImpl.cpp" />
     <ClCompile Include="Source\BsScriptResourceManager.cpp" />
     <ClCompile Include="Source\BsScriptResourceManager.cpp" />

+ 6 - 0
SBansheeEngine/SBansheeEngine.vcxproj.filters

@@ -204,6 +204,9 @@
     <ClInclude Include="Include\BsManagedResourceMetaDataRTTI.h">
     <ClInclude Include="Include\BsManagedResourceMetaDataRTTI.h">
       <Filter>Header Files\RTTI</Filter>
       <Filter>Header Files\RTTI</Filter>
     </ClInclude>
     </ClInclude>
+    <ClInclude Include="Include\BsScriptManagedResource.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\BsScriptTexture2D.cpp">
     <ClCompile Include="Source\BsScriptTexture2D.cpp">
@@ -341,5 +344,8 @@
     <ClCompile Include="Source\BsManagedResourceMetaData.cpp">
     <ClCompile Include="Source\BsManagedResourceMetaData.cpp">
       <Filter>Source Files</Filter>
       <Filter>Source Files</Filter>
     </ClCompile>
     </ClCompile>
+    <ClCompile Include="Source\BsScriptManagedResource.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
   </ItemGroup>
 </Project>
 </Project>

+ 19 - 7
SBansheeEngine/Source/BsManagedResource.cpp

@@ -3,18 +3,22 @@
 #include "BsManagedResourceMetaData.h"
 #include "BsManagedResourceMetaData.h"
 #include "BsMonoManager.h"
 #include "BsMonoManager.h"
 #include "BsMonoClass.h"
 #include "BsMonoClass.h"
+#include "BsResources.h"
 #include "BsDebug.h"
 #include "BsDebug.h"
 
 
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
-	ManagedResource::ManagedResource(MonoReflectionType* runtimeType)
-		:mManagedInstance(nullptr), mRuntimeType(runtimeType)
+	ManagedResource::ManagedResource()
+		:mManagedInstance(nullptr)
+	{ }
+
+	ManagedResource::ManagedResource(MonoObject* managedInstance)
+		:mManagedInstance(nullptr)
 	{
 	{
 		ManagedResourceMetaDataPtr metaData = bs_shared_ptr<ManagedResourceMetaData>();
 		ManagedResourceMetaDataPtr metaData = bs_shared_ptr<ManagedResourceMetaData>();
 		mMetaData = metaData;
 		mMetaData = metaData;
 
 
-		MonoType* monoType = mono_reflection_type_get_type(mRuntimeType);
-		::MonoClass* monoClass = mono_type_get_class(monoType);
+		::MonoClass* monoClass = mono_object_get_class(managedInstance);
 
 
 		metaData->typeNamespace = mono_class_get_namespace(monoClass);
 		metaData->typeNamespace = mono_class_get_namespace(monoClass);
 		metaData->typeName = mono_class_get_name(monoClass);
 		metaData->typeName = mono_class_get_name(monoClass);
@@ -26,7 +30,16 @@ namespace BansheeEngine
 			return;
 			return;
 		}
 		}
 
 
-		construct(managedClass->createInstance(), runtimeType);
+		construct(managedInstance);
+	}
+
+	HManagedResource ManagedResource::create(MonoObject* managedResource)
+	{
+		ManagedResourcePtr newRes = bs_core_ptr<ManagedResource, GenAlloc>(new (bs_alloc<ManagedResource>()) ManagedResource(managedResource));
+		newRes->_setThisPtr(newRes);
+		newRes->initialize();
+
+		return static_resource_cast<ManagedResource>(gResources()._createResourceHandle(newRes));
 	}
 	}
 
 
 	ManagedResourcePtr ManagedResource::createEmpty()
 	ManagedResourcePtr ManagedResource::createEmpty()
@@ -38,10 +51,9 @@ namespace BansheeEngine
 		return newRes;
 		return newRes;
 	}
 	}
 
 
-	void ManagedResource::construct(MonoObject* object, MonoReflectionType* runtimeType)
+	void ManagedResource::construct(MonoObject* object)
 	{
 	{
 		mManagedInstance = object;
 		mManagedInstance = object;
-		mRuntimeType = runtimeType;
 		mManagedHandle = mono_gchandle_new(mManagedInstance, false);
 		mManagedHandle = mono_gchandle_new(mManagedInstance, false);
 	}
 	}
 
 

+ 25 - 0
SBansheeEngine/Source/BsManagedSerializableField.cpp

@@ -7,6 +7,7 @@
 #include "BsScriptGameObjectManager.h"
 #include "BsScriptGameObjectManager.h"
 #include "BsScriptTexture2D.h"
 #include "BsScriptTexture2D.h"
 #include "BsScriptSpriteTexture.h"
 #include "BsScriptSpriteTexture.h"
+#include "BsScriptManagedResource.h"
 #include "BsScriptSceneObject.h"
 #include "BsScriptSceneObject.h"
 #include "BsScriptComponent.h"
 #include "BsScriptComponent.h"
 #include "BsManagedSerializableObject.h"
 #include "BsManagedSerializableObject.h"
@@ -157,6 +158,18 @@ namespace BansheeEngine
 						fieldData->value = static_resource_cast<SpriteTexture>(scriptSpriteTexture->getNativeHandle());
 						fieldData->value = static_resource_cast<SpriteTexture>(scriptSpriteTexture->getNativeHandle());
 					}
 					}
 
 
+					return fieldData;
+				}
+			case ScriptPrimitiveType::ManagedResourceRef:
+				{
+					auto fieldData = bs_shared_ptr<ManagedSerializableFieldDataResourceRef>();
+					
+					if(value != nullptr)
+					{
+						ScriptManagedResource* scriptManagedResource = ScriptManagedResource::toNative(value);
+						fieldData->value = static_resource_cast<ManagedResource>(scriptManagedResource->getNativeHandle());
+					}
+
 					return fieldData;
 					return fieldData;
 				}
 				}
 			case ScriptPrimitiveType::SceneObjectRef:
 			case ScriptPrimitiveType::SceneObjectRef:
@@ -420,6 +433,18 @@ namespace BansheeEngine
 				else
 				else
 					return nullptr;
 					return nullptr;
 			}
 			}
+			else if (primitiveTypeInfo->mType == ScriptPrimitiveType::ManagedResourceRef)
+			{
+				if (value)
+				{
+					ScriptManagedResource* scriptResource = ScriptResourceManager::instance().getScriptManagedResource(value);
+					assert(scriptResource != nullptr); // Managed resource managed instance is created upon creation so it may never be null
+
+					return scriptResource->getManagedInstance();
+				}
+				else
+					return nullptr;
+			}
 		}
 		}
 
 
 		BS_EXCEPT(InvalidParametersException, "Requesting an invalid type in serializable field.");
 		BS_EXCEPT(InvalidParametersException, "Requesting an invalid type in serializable field.");

+ 2 - 0
SBansheeEngine/Source/BsManagedSerializableObjectInfo.cpp

@@ -116,6 +116,8 @@ namespace BansheeEngine
 			return RuntimeScriptObjects::instance().getTextureClass()->_getInternalClass();
 			return RuntimeScriptObjects::instance().getTextureClass()->_getInternalClass();
 		case ScriptPrimitiveType::SpriteTextureRef:
 		case ScriptPrimitiveType::SpriteTextureRef:
 			return RuntimeScriptObjects::instance().getSpriteTextureClass()->_getInternalClass();
 			return RuntimeScriptObjects::instance().getSpriteTextureClass()->_getInternalClass();
+		case ScriptPrimitiveType::ManagedResourceRef:
+			return RuntimeScriptObjects::instance().getManagedResourceClass()->_getInternalClass();
 		case ScriptPrimitiveType::SceneObjectRef:
 		case ScriptPrimitiveType::SceneObjectRef:
 			return RuntimeScriptObjects::instance().getSceneObjectClass()->_getInternalClass();
 			return RuntimeScriptObjects::instance().getSceneObjectClass()->_getInternalClass();
 		case ScriptPrimitiveType::ComponentRef:
 		case ScriptPrimitiveType::ComponentRef:

+ 14 - 2
SBansheeEngine/Source/BsRuntimeScriptObjects.cpp

@@ -17,7 +17,7 @@ namespace BansheeEngine
 		:mBaseTypesInitialized(false), mSerializeObjectAttribute(nullptr), mDontSerializeFieldAttribute(nullptr), 
 		:mBaseTypesInitialized(false), mSerializeObjectAttribute(nullptr), mDontSerializeFieldAttribute(nullptr), 
 		mComponentClass(nullptr), mSceneObjectClass(nullptr), mTextureClass(nullptr), mSpriteTextureClass(nullptr),
 		mComponentClass(nullptr), mSceneObjectClass(nullptr), mTextureClass(nullptr), mSpriteTextureClass(nullptr),
 		mSerializeFieldAttribute(nullptr), mHideInInspectorAttribute(nullptr), mSystemArrayClass(nullptr), mSystemGenericListClass(nullptr),
 		mSerializeFieldAttribute(nullptr), mHideInInspectorAttribute(nullptr), mSystemArrayClass(nullptr), mSystemGenericListClass(nullptr),
-		mSystemGenericDictionaryClass(nullptr)
+		mSystemGenericDictionaryClass(nullptr), mManagedResourceClass(nullptr)
 	{
 	{
 
 
 	}
 	}
@@ -50,7 +50,8 @@ namespace BansheeEngine
 		const Vector<MonoClass*>& allClasses = curAssembly->getAllClasses();
 		const Vector<MonoClass*>& allClasses = curAssembly->getAllClasses();
 		for(auto& curClass : allClasses)
 		for(auto& curClass : allClasses)
 		{
 		{
-			if((curClass->isSubClassOf(mComponentClass) || curClass->hasAttribute(mSerializeObjectAttribute)) && curClass != mComponentClass)
+			if((curClass->isSubClassOf(mComponentClass) || curClass->isSubClassOf(mManagedResourceClass) || 
+				curClass->hasAttribute(mSerializeObjectAttribute)) && curClass != mComponentClass && curClass != mManagedResourceClass)
 			{
 			{
 				std::shared_ptr<ManagedSerializableTypeInfoObject> typeInfo = bs_shared_ptr<ManagedSerializableTypeInfoObject>();
 				std::shared_ptr<ManagedSerializableTypeInfoObject> typeInfo = bs_shared_ptr<ManagedSerializableTypeInfoObject>();
 				typeInfo->mTypeNamespace = curClass->getNamespace();
 				typeInfo->mTypeNamespace = curClass->getNamespace();
@@ -245,6 +246,12 @@ namespace BansheeEngine
 				typeInfo->mType = ScriptPrimitiveType::SpriteTextureRef;
 				typeInfo->mType = ScriptPrimitiveType::SpriteTextureRef;
 				return typeInfo;
 				return typeInfo;
 			}
 			}
+			else if (monoClass->isSubClassOf(mManagedResourceClass))
+			{
+				std::shared_ptr<ManagedSerializableTypeInfoPrimitive> typeInfo = bs_shared_ptr<ManagedSerializableTypeInfoPrimitive>();
+				typeInfo->mType = ScriptPrimitiveType::ManagedResourceRef;
+				return typeInfo;
+			}
 			else if(monoClass->isSubClassOf(mSceneObjectClass))
 			else if(monoClass->isSubClassOf(mSceneObjectClass))
 			{
 			{
 				std::shared_ptr<ManagedSerializableTypeInfoPrimitive> typeInfo = bs_shared_ptr<ManagedSerializableTypeInfoPrimitive>();
 				std::shared_ptr<ManagedSerializableTypeInfoPrimitive> typeInfo = bs_shared_ptr<ManagedSerializableTypeInfoPrimitive>();
@@ -358,6 +365,7 @@ namespace BansheeEngine
 		mComponentClass = nullptr;
 		mComponentClass = nullptr;
 		mSceneObjectClass = nullptr;
 		mSceneObjectClass = nullptr;
 
 
+		mManagedResourceClass = nullptr;
 		mTextureClass = nullptr;
 		mTextureClass = nullptr;
 		mSpriteTextureClass = nullptr;
 		mSpriteTextureClass = nullptr;
 
 
@@ -404,6 +412,10 @@ namespace BansheeEngine
 		if(mSceneObjectClass == nullptr)
 		if(mSceneObjectClass == nullptr)
 			BS_EXCEPT(InvalidStateException, "Cannot find SceneObject managed class.");
 			BS_EXCEPT(InvalidStateException, "Cannot find SceneObject managed class.");
 
 
+		mManagedResourceClass = bansheeEngineAssembly->getClass("BansheeEngine", "ManagedResource");
+		if (mManagedResourceClass == nullptr)
+			BS_EXCEPT(InvalidStateException, "Cannot find ManagedResource managed class.");
+
 		mTextureClass = bansheeEngineAssembly->getClass("BansheeEngine", "Texture2D");
 		mTextureClass = bansheeEngineAssembly->getClass("BansheeEngine", "Texture2D");
 		if(mTextureClass == nullptr)
 		if(mTextureClass == nullptr)
 			BS_EXCEPT(InvalidStateException, "Cannot find Texture2D managed class.");
 			BS_EXCEPT(InvalidStateException, "Cannot find Texture2D managed class.");

+ 40 - 0
SBansheeEngine/Source/BsScriptManagedResource.cpp

@@ -0,0 +1,40 @@
+#include "BsScriptManagedResource.h"
+#include "BsScriptResourceManager.h"
+#include "BsScriptMeta.h"
+#include "BsMonoField.h"
+#include "BsMonoClass.h"
+#include "BsMonoManager.h"
+#include "BsManagedResource.h"
+#include "BsException.h"
+
+namespace BansheeEngine
+{
+	ScriptManagedResource::ScriptManagedResource(MonoObject* instance, const HManagedResource& resource)
+		:ScriptObject(instance), mResource(resource)
+	{
+
+	}
+
+	void ScriptManagedResource::initRuntimeData()
+	{
+		metaData.scriptClass->addInternalCall("Internal_CreateInstance", &ScriptManagedResource::internal_createInstance);
+	}
+
+	void ScriptManagedResource::internal_createInstance(MonoObject* instance)
+	{
+		HManagedResource resource = ManagedResource::create(instance);
+
+		ScriptResourceManager::instance().createManagedResource(instance, resource);
+	}
+
+	void ScriptManagedResource::_onManagedInstanceDeleted()
+	{
+		mManagedInstance = nullptr;
+		ScriptResourceManager::instance().destroyScriptResource(this);
+	}
+
+	void ScriptManagedResource::setNativeHandle(const HResource& resource)
+	{
+		mResource = static_resource_cast<ManagedResource>(resource);
+	}
+}

+ 17 - 0
SBansheeEngine/Source/BsScriptResourceManager.cpp

@@ -4,6 +4,7 @@
 #include "BsMonoClass.h"
 #include "BsMonoClass.h"
 #include "BsScriptTexture2D.h"
 #include "BsScriptTexture2D.h"
 #include "BsScriptSpriteTexture.h"
 #include "BsScriptSpriteTexture.h"
+#include "BsScriptManagedResource.h"
 
 
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
@@ -60,6 +61,17 @@ namespace BansheeEngine
 		return scriptResource;
 		return scriptResource;
 	}
 	}
 
 
+	ScriptManagedResource* ScriptResourceManager::createManagedResource(MonoObject* existingInstance, const HManagedResource& resourceHandle)
+	{
+		const String& uuid = resourceHandle.getUUID();
+		throwExceptionIfInvalidOrDuplicate(uuid);
+
+		ScriptManagedResource* scriptResource = new (bs_alloc<ScriptManagedResource>()) ScriptManagedResource(existingInstance, resourceHandle);
+		mScriptResources[uuid] = scriptResource;
+
+		return scriptResource;
+	}
+
 	ScriptTexture2D* ScriptResourceManager::getScriptTexture(const HTexture& resourceHandle)
 	ScriptTexture2D* ScriptResourceManager::getScriptTexture(const HTexture& resourceHandle)
 	{
 	{
 		return static_cast<ScriptTexture2D*>(getScriptResource(resourceHandle));
 		return static_cast<ScriptTexture2D*>(getScriptResource(resourceHandle));
@@ -70,6 +82,11 @@ namespace BansheeEngine
 		return static_cast<ScriptSpriteTexture*>(getScriptResource(resourceHandle));
 		return static_cast<ScriptSpriteTexture*>(getScriptResource(resourceHandle));
 	}
 	}
 
 
+	ScriptManagedResource* ScriptResourceManager::getScriptManagedResource(const HManagedResource& resourceHandle)
+	{
+		return static_cast<ScriptManagedResource*>(getScriptResource(resourceHandle));
+	}
+
 	ScriptResourceBase* ScriptResourceManager::getScriptResource(const HResource& resourceHandle)
 	ScriptResourceBase* ScriptResourceManager::getScriptResource(const HResource& resourceHandle)
 	{
 	{
 		const String& uuid = resourceHandle.getUUID();
 		const String& uuid = resourceHandle.getUUID();