Browse Source

Bugfix: Fixing script code crashes related to garbage collection
- Refactored scripting interop code so it uses handles instead of pointers

BearishSun 8 years ago
parent
commit
c4540199ba
98 changed files with 692 additions and 624 deletions
  1. 2 2
      Source/BansheeCore/Components/BsCLight.h
  2. 2 2
      Source/BansheeCore/Renderer/BsLight.cpp
  3. 1 1
      Source/BansheeCore/Renderer/BsLight.h
  4. 1 1
      Source/BansheeCore/Renderer/BsRenderSettings.cpp
  5. 7 2
      Source/BansheeMono/BsMonoUtil.cpp
  6. 20 5
      Source/BansheeMono/BsMonoUtil.h
  7. 4 4
      Source/MBansheeEditor/General/EditorApplication.cs
  8. 8 8
      Source/MBansheeEngine/Serialization/SerializableProperty.cs
  9. 24 7
      Source/SBansheeEditor/BsManagedEditorCommand.cpp
  10. 1 1
      Source/SBansheeEditor/BsManagedEditorCommand.h
  11. 2 1
      Source/SBansheeEditor/Wrappers/BsScriptDropDownWindow.cpp
  12. 33 51
      Source/SBansheeEditor/Wrappers/BsScriptEditorWindow.cpp
  13. 5 7
      Source/SBansheeEditor/Wrappers/BsScriptEditorWindow.h
  14. 12 4
      Source/SBansheeEditor/Wrappers/BsScriptFolderMonitor.cpp
  15. 2 1
      Source/SBansheeEditor/Wrappers/BsScriptFolderMonitor.h
  16. 11 8
      Source/SBansheeEditor/Wrappers/BsScriptOSDropTarget.cpp
  17. 3 2
      Source/SBansheeEditor/Wrappers/BsScriptOSDropTarget.h
  18. 4 5
      Source/SBansheeEditor/Wrappers/GUI/BsScriptGUIColorField.cpp
  19. 2 6
      Source/SBansheeEditor/Wrappers/GUI/BsScriptGUIColorField.h
  20. 9 10
      Source/SBansheeEditor/Wrappers/GUI/BsScriptGUIEnumField.cpp
  21. 1 2
      Source/SBansheeEditor/Wrappers/GUI/BsScriptGUIEnumField.h
  22. 7 7
      Source/SBansheeEditor/Wrappers/GUI/BsScriptGUIFloatField.cpp
  23. 2 5
      Source/SBansheeEditor/Wrappers/GUI/BsScriptGUIFloatField.h
  24. 4 5
      Source/SBansheeEditor/Wrappers/GUI/BsScriptGUIGameObjectField.cpp
  25. 1 2
      Source/SBansheeEditor/Wrappers/GUI/BsScriptGUIGameObjectField.h
  26. 7 7
      Source/SBansheeEditor/Wrappers/GUI/BsScriptGUIIntField.cpp
  27. 3 8
      Source/SBansheeEditor/Wrappers/GUI/BsScriptGUIIntField.h
  28. 4 5
      Source/SBansheeEditor/Wrappers/GUI/BsScriptGUIListBoxField.cpp
  29. 1 2
      Source/SBansheeEditor/Wrappers/GUI/BsScriptGUIListBoxField.h
  30. 4 4
      Source/SBansheeEditor/Wrappers/GUI/BsScriptGUIResourceField.cpp
  31. 1 2
      Source/SBansheeEditor/Wrappers/GUI/BsScriptGUIResourceField.h
  32. 5 5
      Source/SBansheeEditor/Wrappers/GUI/BsScriptGUISliderField.cpp
  33. 1 2
      Source/SBansheeEditor/Wrappers/GUI/BsScriptGUISliderField.h
  34. 7 7
      Source/SBansheeEditor/Wrappers/GUI/BsScriptGUITextField.cpp
  35. 3 8
      Source/SBansheeEditor/Wrappers/GUI/BsScriptGUITextField.h
  36. 4 5
      Source/SBansheeEditor/Wrappers/GUI/BsScriptGUITextureField.cpp
  37. 1 2
      Source/SBansheeEditor/Wrappers/GUI/BsScriptGUITextureField.h
  38. 4 5
      Source/SBansheeEditor/Wrappers/GUI/BsScriptGUIToggleField.cpp
  39. 1 2
      Source/SBansheeEditor/Wrappers/GUI/BsScriptGUIToggleField.h
  40. 8 7
      Source/SBansheeEditor/Wrappers/GUI/BsScriptGUIVector2Field.cpp
  41. 3 8
      Source/SBansheeEditor/Wrappers/GUI/BsScriptGUIVector2Field.h
  42. 7 7
      Source/SBansheeEditor/Wrappers/GUI/BsScriptGUIVector3Field.cpp
  43. 3 8
      Source/SBansheeEditor/Wrappers/GUI/BsScriptGUIVector3Field.h
  44. 8 7
      Source/SBansheeEditor/Wrappers/GUI/BsScriptGUIVector4Field.cpp
  45. 3 8
      Source/SBansheeEditor/Wrappers/GUI/BsScriptGUIVector4Field.h
  46. 51 51
      Source/SBansheeEngine/BsManagedComponent.cpp
  47. 15 16
      Source/SBansheeEngine/BsManagedComponent.h
  48. 19 18
      Source/SBansheeEngine/BsManagedResource.cpp
  49. 2 3
      Source/SBansheeEngine/BsManagedResource.h
  50. 0 5
      Source/SBansheeEngine/BsScriptObject.cpp
  51. 4 22
      Source/SBansheeEngine/BsScriptObject.h
  52. 2 2
      Source/SBansheeEngine/Extensions/BsAsyncOpEx.cpp
  53. 3 3
      Source/SBansheeEngine/Extensions/BsAsyncOpEx.h
  54. 2 3
      Source/SBansheeEngine/Extensions/BsTextureEx.cpp
  55. 1 1
      Source/SBansheeEngine/Serialization/BsManagedSerializableArray.cpp
  56. 1 1
      Source/SBansheeEngine/Serialization/BsManagedSerializableDiff.h
  57. 0 2
      Source/SBansheeEngine/Wrappers/BsScriptComponent.cpp
  58. 14 19
      Source/SBansheeEngine/Wrappers/BsScriptComponent.h
  59. 3 1
      Source/SBansheeEngine/Wrappers/BsScriptContextMenu.cpp
  60. 1 0
      Source/SBansheeEngine/Wrappers/BsScriptContextMenu.h
  61. 30 2
      Source/SBansheeEngine/Wrappers/BsScriptGameObject.cpp
  62. 20 1
      Source/SBansheeEngine/Wrappers/BsScriptGameObject.h
  63. 7 0
      Source/SBansheeEngine/Wrappers/BsScriptInputConfiguration.cpp
  64. 4 0
      Source/SBansheeEngine/Wrappers/BsScriptInputConfiguration.h
  65. 19 5
      Source/SBansheeEngine/Wrappers/BsScriptManagedComponent.cpp
  66. 3 0
      Source/SBansheeEngine/Wrappers/BsScriptManagedComponent.h
  67. 15 11
      Source/SBansheeEngine/Wrappers/BsScriptManagedResource.cpp
  68. 3 3
      Source/SBansheeEngine/Wrappers/BsScriptManagedResource.h
  69. 29 4
      Source/SBansheeEngine/Wrappers/BsScriptResource.cpp
  70. 34 20
      Source/SBansheeEngine/Wrappers/BsScriptResource.h
  71. 11 15
      Source/SBansheeEngine/Wrappers/BsScriptSceneObject.cpp
  72. 3 1
      Source/SBansheeEngine/Wrappers/BsScriptSceneObject.h
  73. 7 8
      Source/SBansheeEngine/Wrappers/BsScriptSerializableArray.cpp
  74. 1 1
      Source/SBansheeEngine/Wrappers/BsScriptSerializableArray.h
  75. 8 12
      Source/SBansheeEngine/Wrappers/BsScriptSerializableDictionary.cpp
  76. 1 1
      Source/SBansheeEngine/Wrappers/BsScriptSerializableDictionary.h
  77. 4 7
      Source/SBansheeEngine/Wrappers/BsScriptSerializableField.cpp
  78. 9 9
      Source/SBansheeEngine/Wrappers/BsScriptSerializableField.h
  79. 7 9
      Source/SBansheeEngine/Wrappers/BsScriptSerializableList.cpp
  80. 1 1
      Source/SBansheeEngine/Wrappers/BsScriptSerializableList.h
  81. 5 8
      Source/SBansheeEngine/Wrappers/BsScriptSerializableObject.cpp
  82. 1 1
      Source/SBansheeEngine/Wrappers/BsScriptSerializableObject.h
  83. 11 20
      Source/SBansheeEngine/Wrappers/BsScriptSerializableProperty.cpp
  84. 5 5
      Source/SBansheeEngine/Wrappers/BsScriptSerializableProperty.h
  85. 13 13
      Source/SBansheeEngine/Wrappers/GUI/BsScriptGUIButton.cpp
  86. 4 4
      Source/SBansheeEngine/Wrappers/GUI/BsScriptGUIButton.h
  87. 12 3
      Source/SBansheeEngine/Wrappers/GUI/BsScriptGUIElement.cpp
  88. 8 4
      Source/SBansheeEngine/Wrappers/GUI/BsScriptGUIElement.h
  89. 7 6
      Source/SBansheeEngine/Wrappers/GUI/BsScriptGUIInputBox.cpp
  90. 2 2
      Source/SBansheeEngine/Wrappers/GUI/BsScriptGUIInputBox.h
  91. 2 2
      Source/SBansheeEngine/Wrappers/GUI/BsScriptGUILayout.cpp
  92. 5 4
      Source/SBansheeEngine/Wrappers/GUI/BsScriptGUIListBox.cpp
  93. 2 2
      Source/SBansheeEngine/Wrappers/GUI/BsScriptGUIListBox.h
  94. 4 4
      Source/SBansheeEngine/Wrappers/GUI/BsScriptGUIScrollBar.cpp
  95. 8 8
      Source/SBansheeEngine/Wrappers/GUI/BsScriptGUISlider.cpp
  96. 2 2
      Source/SBansheeEngine/Wrappers/GUI/BsScriptGUISlider.h
  97. 16 16
      Source/SBansheeEngine/Wrappers/GUI/BsScriptGUIToggle.cpp
  98. 5 5
      Source/SBansheeEngine/Wrappers/GUI/BsScriptGUIToggle.h

+ 2 - 2
Source/BansheeCore/Components/BsCLight.h

@@ -21,7 +21,7 @@ namespace bs
 	{
 	public:
 		CLight(const HSceneObject& parent, LightType type = LightType::Radial, Color color = Color::White, 
-			float intensity = 10000.0f, float range = 1.0f, bool castsShadows = false, Degree spotAngle = Degree(45), 
+			float intensity = 100.0f, float range = 1.0f, bool castsShadows = false, Degree spotAngle = Degree(45), 
 			Degree spotFalloffAngle = Degree(40));
 
 		virtual ~CLight();
@@ -125,7 +125,7 @@ namespace bs
 		// Only valid during construction
 		LightType mType = LightType::Radial;
 		Color mColor = Color::White;
-		float mIntensity = 10000.0f;
+		float mIntensity = 100.0f;
 		float mRange = 1.0f;
 		bool mCastsShadows = false; 
 		Degree mSpotAngle = Degree(45); 

+ 2 - 2
Source/BansheeCore/Renderer/BsLight.cpp

@@ -11,7 +11,7 @@ namespace bs
 {
 	LightBase::LightBase()
 		: mType(LightType::Radial), mCastsShadows(false), mColor(Color::White), mAttRadius(10.0f), mSourceRadius(0.0f)
-		, mIntensity(10000.0f), mSpotAngle(45), mSpotFalloffAngle(35.0f), mAutoAttenuation(true), mShadowBias(0.5f)
+		, mIntensity(100.0f), mSpotAngle(45), mSpotFalloffAngle(35.0f), mAutoAttenuation(false), mShadowBias(0.5f)
 	{
 		updateAttenuationRange();
 	}
@@ -19,7 +19,7 @@ namespace bs
 	LightBase::LightBase(LightType type, Color color, float intensity, float attRadius, float srcRadius, bool castsShadows, 
 		Degree spotAngle, Degree spotFalloffAngle)
 		: mType(type), mCastsShadows(castsShadows), mColor(color), mAttRadius(attRadius), mSourceRadius(srcRadius)
-		, mIntensity(intensity), mSpotAngle(spotAngle), mSpotFalloffAngle(spotFalloffAngle), mAutoAttenuation(true)
+		, mIntensity(intensity), mSpotAngle(spotAngle), mSpotFalloffAngle(spotFalloffAngle), mAutoAttenuation(false)
 		, mShadowBias(0.5f)
 	{
 		updateAttenuationRange();

+ 1 - 1
Source/BansheeCore/Renderer/BsLight.h

@@ -194,7 +194,7 @@ namespace bs
 		 * @param[in]	spotFalloffAngle	Spot light angle at which falloff starts. Must be smaller than total angle.
 		 */
 		static SPtr<Light> create(LightType type = LightType::Radial, Color color = Color::White,
-			float intensity = 10000.0f, float attRadius = 10.0f, bool castsShadows = false,
+			float intensity = 100.0f, float attRadius = 10.0f, bool castsShadows = false,
 			Degree spotAngle = Degree(45), Degree spotFalloffAngle = Degree(40));
 
 	protected:

+ 1 - 1
Source/BansheeCore/Renderer/BsRenderSettings.cpp

@@ -7,7 +7,7 @@ namespace bs
 {
 	AutoExposureSettings::AutoExposureSettings()
 		: histogramLog2Min(-8.0f), histogramLog2Max(4.0f), histogramPctLow(0.8f), histogramPctHigh(0.985f)
-		, minEyeAdaptation(0.3f), maxEyeAdaptation(2.0f), eyeAdaptationSpeedUp(3.0f), eyeAdaptationSpeedDown(3.0f)
+		, minEyeAdaptation(0.003f), maxEyeAdaptation(2.0f), eyeAdaptationSpeedUp(3.0f), eyeAdaptationSpeedDown(3.0f)
 	{ }
 
 	RTTITypeBase* AutoExposureSettings::getRTTIStatic()

+ 7 - 2
Source/BansheeMono/BsMonoUtil.cpp

@@ -123,9 +123,14 @@ namespace bs
 		return mono_type_get_object(MonoManager::instance().getDomain(), monoType);
 	}
 
-	UINT32 MonoUtil::newGCHandle(MonoObject* object)
+	UINT32 MonoUtil::newGCHandle(MonoObject* object, bool pinned)
 	{
-		return mono_gchandle_new(object, true);
+		return mono_gchandle_new(object, pinned);
+	}
+
+	UINT32 MonoUtil::newWeakGCHandle(MonoObject* object)
+	{
+		return mono_gchandle_new_weakref(object, false);
 	}
 
 	void MonoUtil::freeGCHandle(UINT32 handle)

+ 20 - 5
Source/BansheeMono/BsMonoUtil.h

@@ -48,11 +48,26 @@ namespace bs
 		static MonoReflectionType* getType(::MonoClass* klass);
 
 		/**
-		 * Creates a new GC handle for the provided managed object, ensuring it doesn't go out of scope.
-		 * Note that after creating a handle you MUST call getObjectFromGCHandle() to get the latest MonoObject*, as
-		 * GC could have potentially moved the object to a new address.
-		 *  */
-		static UINT32 newGCHandle(MonoObject* object);
+		 * Creates a new GC handle for the provided managed object. The handle can be stored and later used for retrieving
+		 * the MonoObject* related to it by calling getObjectFromGCHandle(). This is a strong handle, meaning it will 
+		 * prevent the garbage collector from collecting the object until it is released by calling freeGCHandle().
+		 * 
+		 * @param[in]	object		Managed object to create the handle for.
+		 * @param[in]	pinned		If true the object will be pinned in memory, meaning you will be allowed to store
+		 *							a reference to the MonoObject directly. Never store MonoObject* unless they have been
+		 *							previously pinned (instead use getObjectFromGCHandle*( to get the current pointer). 
+		 *							Note that pinning can have an impact on memory fragmentation as it prevents the GC from
+		 *							moving the object, so use it sparingly.
+		 */
+		static UINT32 newGCHandle(MonoObject* object, bool pinned = true);
+
+		/**
+		 * Creates a new GC handle for the provided managed object. The handle can be stored and later used for retrieving
+		 * the MonoObject* related to it by calling getObjectFromGCHandle(). This is a weak handle, meaning it will NOT
+		 * prevent the garbage collector from collecting the object. getObjectFromGCHandle() will return null if the GC
+		 * collected the object and handle is no longer valid.
+		 */
+		static UINT32 newWeakGCHandle(MonoObject* object);
 
 		/** Frees a GC handle previously allocated with newGCHandle. */
 		static void freeGCHandle(UINT32 handle);

+ 4 - 4
Source/MBansheeEditor/General/EditorApplication.cs

@@ -195,8 +195,8 @@ namespace BansheeEditor
         /// </summary>
         internal static string CompilerPath { get { return Internal_GetCompilerPath(); } }
 
-		/// <summary>
-		/// Returns the absolute path to the executable capable of executing managed assemblies.
+        /// <summary>
+        /// Returns the absolute path to the executable capable of executing managed assemblies.
         /// </summary>
         internal static string MonoExecPath { get { return Internal_GetMonoExecPath(); } }
 
@@ -1005,8 +1005,8 @@ namespace BansheeEditor
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern string Internal_GetCompilerPath();
 
-		[MethodImpl(MethodImplOptions.InternalCall)]
-		private static extern string Internal_GetMonoExecPath();
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern string Internal_GetMonoExecPath();
 
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern string Internal_GetBuiltinReleaseAssemblyPath();

+ 8 - 8
Source/MBansheeEngine/Serialization/SerializableProperty.cs

@@ -143,7 +143,7 @@ namespace BansheeEngine
             if (type != FieldType.Object)
                 throw new Exception("Attempting to retrieve object information from a field that doesn't contain an object.");
 
-            return Internal_CreateObject(mCachedPtr);
+            return Internal_CreateObject(mCachedPtr, this);
         }
 
         /// <summary>
@@ -156,7 +156,7 @@ namespace BansheeEngine
             if (type != FieldType.Array)
                 throw new Exception("Attempting to retrieve array information from a field that doesn't contain an array.");
 
-            return Internal_CreateArray(mCachedPtr);
+            return Internal_CreateArray(mCachedPtr, this);
         }
 
         /// <summary>
@@ -169,7 +169,7 @@ namespace BansheeEngine
             if (type != FieldType.List)
                 throw new Exception("Attempting to retrieve array information from a field that doesn't contain a list.");
 
-            return Internal_CreateList(mCachedPtr);
+            return Internal_CreateList(mCachedPtr, this);
         }
 
         /// <summary>
@@ -182,7 +182,7 @@ namespace BansheeEngine
             if (type != FieldType.Dictionary)
                 throw new Exception("Attempting to retrieve array information from a field that doesn't contain a dictionary.");
 
-            return Internal_CreateDictionary(mCachedPtr);
+            return Internal_CreateDictionary(mCachedPtr, this);
         }
 
         /// <summary>
@@ -287,16 +287,16 @@ namespace BansheeEngine
         private static extern void Internal_CreateInstance(SerializableProperty instance, Type type);
 
         [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern SerializableObject Internal_CreateObject(IntPtr nativeInstance);
+        private static extern SerializableObject Internal_CreateObject(IntPtr nativeInstance, object managedInstance);
 
         [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern SerializableArray Internal_CreateArray(IntPtr nativeInstance);
+        private static extern SerializableArray Internal_CreateArray(IntPtr nativeInstance, object managedInstance);
 
         [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern SerializableList Internal_CreateList(IntPtr nativeInstance);
+        private static extern SerializableList Internal_CreateList(IntPtr nativeInstance, object managedInstance);
 
         [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern SerializableDictionary Internal_CreateDictionary(IntPtr nativeInstance);
+        private static extern SerializableDictionary Internal_CreateDictionary(IntPtr nativeInstance, object managedInstance);
 
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern object Internal_CreateManagedObjectInstance(IntPtr nativeInstance);

+ 24 - 7
Source/SBansheeEditor/BsManagedEditorCommand.cpp

@@ -17,6 +17,9 @@ namespace bs
 		:ScriptObject(managedInstance), mManagedCommand(nullptr)
 	{
 		mManagedCommand = bs_shared_ptr(new (bs_alloc<CmdManaged>()) CmdManaged(this));
+
+		mGCHandle = MonoUtil::newWeakGCHandle(managedInstance);
+		mWeakHandle = true;
 	}
 
 	ScriptCmdManaged::~ScriptCmdManaged()
@@ -46,7 +49,8 @@ namespace bs
 		if (sCommitMethod == nullptr)
 			return;
 
-		sCommitMethod->invokeVirtual(mManagedInstance, nullptr);
+		MonoObject* obj = MonoUtil::getObjectFromGCHandle(mGCHandle);
+		sCommitMethod->invokeVirtual(obj, nullptr);
 	}
 
 	void ScriptCmdManaged::triggerRevert()
@@ -54,7 +58,8 @@ namespace bs
 		if (sRevertMethod == nullptr)
 			return;
 
-		sRevertMethod->invokeVirtual(mManagedInstance, nullptr);
+		MonoObject* obj = MonoUtil::getObjectFromGCHandle(mGCHandle);
+		sRevertMethod->invokeVirtual(obj, nullptr);
 	}
 
 	void ScriptCmdManaged::notifyCommandDestroyed()
@@ -64,21 +69,33 @@ namespace bs
 
 	void ScriptCmdManaged::allocGCHandle()
 	{
-		if (mGCHandle == 0)
+		if (mWeakHandle)
 		{
-			mGCHandle = MonoUtil::newGCHandle(mManagedInstance);
-			mManagedInstance = MonoUtil::getObjectFromGCHandle(mGCHandle);
+			MonoObject* obj = MonoUtil::getObjectFromGCHandle(mGCHandle);
+			mGCHandle = MonoUtil::newGCHandle(obj);
+			mWeakHandle = false;
 		}
 	}
 
 	void ScriptCmdManaged::freeGCHandle()
 	{
-		if(mGCHandle != 0)
+		MonoObject* obj = nullptr;
+		if (mGCHandle)
+			obj = MonoUtil::getObjectFromGCHandle(mGCHandle);
+
+		if (!mWeakHandle && mGCHandle != 0)
 			MonoUtil::freeGCHandle(mGCHandle);
+
+		// Note: Re-creating the weak handle might not be necessary as the command shouldn't be allowed to be re-added
+		// after it has been removed from the undo-redo stack (which should be the only place this method is called from).
+		if(obj)
+			mGCHandle = MonoUtil::newWeakGCHandle(obj);
+
+		mWeakHandle = true;
 	}
 
 	CmdManaged::CmdManaged(ScriptCmdManaged* scriptObj)
-		: EditorCommand(L""), mScriptObj(scriptObj), mGCHandle(0), mRefCount(0)
+		: EditorCommand(L""), mScriptObj(scriptObj), mRefCount(0)
 	{
 
 	}

+ 1 - 1
Source/SBansheeEditor/BsManagedEditorCommand.h

@@ -50,6 +50,7 @@ namespace bs
 
 		SPtr<CmdManaged> mManagedCommand;
 		UINT32 mGCHandle = 0;
+		bool mWeakHandle = true;
 
 		/************************************************************************/
 		/* 								CLR HOOKS						   		*/
@@ -100,7 +101,6 @@ namespace bs
 		void notifyScriptInstanceDestroyed();
 
 		ScriptCmdManaged* mScriptObj;
-		uint32_t mGCHandle;
 		UINT32 mRefCount;
 
 	};

+ 2 - 1
Source/SBansheeEditor/Wrappers/BsScriptDropDownWindow.cpp

@@ -26,7 +26,8 @@ namespace bs
 	ScriptDropDownWindow::ScriptDropDownWindow(ManagedDropDownWindow* window)
 		:ScriptObject(window->getManagedInstance()), mDropDownWindow(window)
 	{
-		mOnAssemblyRefreshStartedConn = ScriptObjectManager::instance().onRefreshStarted.connect(std::bind(&ScriptDropDownWindow::onAssemblyRefreshStarted, this));
+		mOnAssemblyRefreshStartedConn = ScriptObjectManager::instance().onRefreshStarted.connect(
+			std::bind(&ScriptDropDownWindow::onAssemblyRefreshStarted, this));
 	}
 
 	ScriptDropDownWindow::~ScriptDropDownWindow()

+ 33 - 51
Source/SBansheeEditor/Wrappers/BsScriptEditorWindow.cpp

@@ -23,7 +23,7 @@ using namespace std::placeholders;
 
 namespace bs
 {
-	UnorderedMap<String, ScriptEditorWindow::EditorWindowHandle> ScriptEditorWindow::OpenScriptEditorWindows;
+	UnorderedMap<String, ScriptEditorWindow*> ScriptEditorWindow::OpenScriptEditorWindows;
 	Vector<String> ScriptEditorWindow::AvailableWindowTypes;
 	MonoMethod* ScriptEditorWindow::onResizedMethod = nullptr;
 	MonoMethod* ScriptEditorWindow::onFocusChangedMethod = nullptr;
@@ -31,13 +31,14 @@ namespace bs
 	MonoField* ScriptEditorWindow::undoRedoField = nullptr;
 
 	ScriptEditorWindow::ScriptEditorWindow(ScriptEditorWidget* editorWidget)
-		:ScriptObject(editorWidget->getManagedInstance()), mName(editorWidget->getName()), mEditorWidget(editorWidget), 
-		mRefreshInProgress(false), mIsDestroyed(false)
+		: ScriptObject(editorWidget->getManagedInstance()), mName(editorWidget->getName())
+		, mEditorWidget(editorWidget), mRefreshInProgress(false), mIsDestroyed(false)
 	{
 		mOnWidgetResizedConn = editorWidget->onResized.connect(std::bind(&ScriptEditorWindow::onWidgetResized, this, _1, _2));
 		mOnFocusChangedConn = editorWidget->onFocusChanged.connect(std::bind(&ScriptEditorWindow::onFocusChanged, this, _1));
 
-		mOnAssemblyRefreshStartedConn = ScriptObjectManager::instance().onRefreshStarted.connect(std::bind(&ScriptEditorWindow::onAssemblyRefreshStarted, this));
+		mOnAssemblyRefreshStartedConn = ScriptObjectManager::instance().onRefreshStarted.connect(
+			std::bind(&ScriptEditorWindow::onAssemblyRefreshStarted, this));
 	}
 
 	ScriptEditorWindow::~ScriptEditorWindow()
@@ -81,13 +82,13 @@ namespace bs
 
 		auto findIter = OpenScriptEditorWindows.find(fullName);
 		if(findIter != OpenScriptEditorWindows.end())
-			return findIter->second.nativeObj->mManagedInstance;
+			return findIter->second->mEditorWidget->getManagedInstance();
 
 		EditorWidgetManager::instance().open(fullName); // This will trigger openEditorWidgetCallback and update OpenScriptEditorWindows
 
 		auto findIter2 = OpenScriptEditorWindows.find(fullName);
 		if(findIter2 != OpenScriptEditorWindows.end())
-			return findIter2->second.nativeObj->mManagedInstance;
+			return findIter2->second->mEditorWidget->getManagedInstance();
 
 		return nullptr;
 	}
@@ -100,7 +101,7 @@ namespace bs
 
 		auto findIter = OpenScriptEditorWindows.find(fullName);
 		if (findIter != OpenScriptEditorWindows.end())
-			return findIter->second.nativeObj->mManagedInstance;
+			return findIter->second->mEditorWidget->getManagedInstance();
 
 		return nullptr;
 	}
@@ -112,7 +113,7 @@ namespace bs
 
 		UINT32 idx = 0;
 		for (auto& entry : OpenScriptEditorWindows)
-			output.set(idx++, entry.second.nativeObj->getManagedInstance());
+			output.set(idx++, entry.second->mEditorWidget->getManagedInstance());
 
 		return output.getInternal();
 	}
@@ -127,7 +128,7 @@ namespace bs
 		if (!mRefreshInProgress)
 			ScriptObject::_onManagedInstanceDeleted();
 		else
-			mManagedInstance = nullptr;
+			mEditorWidget->clearManagedInstance(false);
 	}
 
 	ScriptObjectBackup ScriptEditorWindow::beginRefresh()
@@ -136,12 +137,7 @@ namespace bs
 
 		auto iterFind = OpenScriptEditorWindows.find(mName);
 		if (iterFind != OpenScriptEditorWindows.end())
-		{
-			EditorWindowHandle& handle = iterFind->second;
-
-			MonoUtil::freeGCHandle(handle.gcHandle);
-			handle.gcHandle = 0;
-		}
+			iterFind->second->mEditorWidget->clearManagedInstance(true);
 
 		return PersistentScriptObjectBase::beginRefresh();
 	}
@@ -150,23 +146,7 @@ namespace bs
 	{
 		mRefreshInProgress = false;
 
-		if (!isDestroyed())
-			mManagedInstance = mEditorWidget->getManagedInstance();
-		else
-			mManagedInstance = nullptr;
-
-		if (mManagedInstance != nullptr)
-		{
-			auto iterFind = OpenScriptEditorWindows.find(mName);
-			if (iterFind != OpenScriptEditorWindows.end())
-			{
-				EditorWindowHandle& handle = iterFind->second;
-
-				handle.gcHandle = MonoUtil::newGCHandle(mManagedInstance);
-				mManagedInstance = MonoUtil::getObjectFromGCHandle(handle.gcHandle);
-			}
-		}
-		else
+		if (isDestroyed())
 		{
 			// We couldn't restore managed instance because window class cannot be found
 			_onManagedInstanceDeleted();
@@ -302,20 +282,22 @@ namespace bs
 
 	void ScriptEditorWindow::onWidgetResized(UINT32 width, UINT32 height)
 	{
-		if (isDestroyed() || !mEditorWidget->isInitialized() || mManagedInstance == nullptr)
+		MonoObject* managedInstance = mEditorWidget->getManagedInstance();
+		if (isDestroyed() || !mEditorWidget->isInitialized() || managedInstance == nullptr)
 			return;
 
 		void* params[2] = { &width, &height };
-		onResizedMethod->invokeVirtual(mManagedInstance, params);
+		onResizedMethod->invokeVirtual(managedInstance, params);
 	}
 
 	void ScriptEditorWindow::onFocusChanged(bool inFocus)
 	{
-		if (isDestroyed() || mManagedInstance == nullptr)
+		MonoObject* managedInstance = mEditorWidget->getManagedInstance();
+		if (isDestroyed() || managedInstance == nullptr)
 			return;
 
 		void* params[1] = { &inFocus};
-		onFocusChangedMethod->invokeVirtual(mManagedInstance, params);
+		onFocusChangedMethod->invokeVirtual(managedInstance, params);
 	}
 
 	void ScriptEditorWindow::registerManagedEditorWindows()
@@ -395,34 +377,21 @@ namespace bs
 
 		auto findIter = OpenScriptEditorWindows.find(editorWindow->mName);
 		if(findIter == OpenScriptEditorWindows.end())
-		{
-			EditorWindowHandle newHandle;
-			newHandle.nativeObj = editorWindow;
-			newHandle.gcHandle = MonoUtil::newGCHandle(editorWindow->mManagedInstance);
-
-			editorWindow->mManagedInstance = MonoUtil::getObjectFromGCHandle(newHandle.gcHandle);
-
-			OpenScriptEditorWindows[editorWindow->mName] = newHandle;
-		}
+			OpenScriptEditorWindows[editorWindow->mName] = editorWindow;
 	}
 
 	void ScriptEditorWindow::unregisterScriptEditorWindow(const String& windowTypeName)
 	{
 		auto findIter = OpenScriptEditorWindows.find(windowTypeName);
 		if(findIter != OpenScriptEditorWindows.end())
-		{
-			EditorWindowHandle& foundHandle = findIter->second;
-			MonoUtil::freeGCHandle(foundHandle.gcHandle);
-
 			OpenScriptEditorWindows.erase(findIter);
-		}
 	}
 
 	ScriptEditorWidget::ScriptEditorWidget(const String& ns, const String& type, UINT32 defaultWidth, 
 		UINT32 defaultHeight, bool localUndoRedo, EditorWidgetContainer& parentContainer)
 		: EditorWidgetBase(HString(toWString(type)), ns + "." + type, defaultWidth, defaultHeight, parentContainer)
 		, mNamespace(ns), mTypename(type), mOnInitializeThunk(nullptr), mOnDestroyThunk(nullptr), mUpdateThunk(nullptr)
-		, mManagedInstance(nullptr), mGetDisplayName(nullptr), mScriptOwner(nullptr), mContentsPanel(nullptr)
+		, mManagedInstance(nullptr), mGCHandle(0), mGetDisplayName(nullptr), mScriptOwner(nullptr), mContentsPanel(nullptr)
 		, mIsInitialized(false), mHasLocalUndoRedo(localUndoRedo)
 	{
 		if(createManagedInstance())
@@ -450,9 +419,21 @@ namespace bs
 		mContentsPanel = nullptr;
 
 		triggerOnDestroy();
+
+		clearManagedInstance(true);
+
 		ScriptEditorWindow::unregisterScriptEditorWindow(getName());
 	}
 
+	void ScriptEditorWidget::clearManagedInstance(bool freeHandle)
+	{
+		if(freeHandle)
+			MonoUtil::freeGCHandle(mGCHandle);
+
+		mManagedInstance = nullptr;
+		mGCHandle = 0;
+	}
+
 	bool ScriptEditorWidget::createManagedInstance()
 	{
 		const char* assemblies[2] = { EDITOR_ASSEMBLY, SCRIPT_EDITOR_ASSEMBLY };
@@ -469,6 +450,7 @@ namespace bs
 				if (editorWindowClass != nullptr)
 				{
 					mManagedInstance = editorWindowClass->createInstance();
+					mGCHandle = MonoUtil::newGCHandle(mManagedInstance);
 
 					MonoObject* guiPanel = ScriptGUIPanel::createFromExisting(mContent);
 					mContentsPanel = ScriptGUILayout::toNative(guiPanel);

+ 5 - 7
Source/SBansheeEditor/Wrappers/BsScriptEditorWindow.h

@@ -18,12 +18,6 @@ namespace bs
 	/**	Interop class between C++ & CLR for ScriptEditorWidget. */
 	class BS_SCR_BED_EXPORT ScriptEditorWindow : public ScriptObject<ScriptEditorWindow, PersistentScriptObjectBase>
 	{
-		/**	Contains data about the managed handle to an editor window. */
-		struct EditorWindowHandle
-		{
-			uint32_t gcHandle;
-			ScriptEditorWindow* nativeObj;
-		};
 	public:
 		SCRIPT_OBJ(EDITOR_ASSEMBLY, "BansheeEditor", "EditorWindow")
 
@@ -103,7 +97,7 @@ namespace bs
 		static EditorWidgetBase* openEditorWidgetCallback(String ns, String type, UINT32 width, UINT32 height, 
 			bool localUndoRedo, EditorWidgetContainer& parentContainer);
 
-		static UnorderedMap<String, EditorWindowHandle> OpenScriptEditorWindows;
+		static UnorderedMap<String, ScriptEditorWindow*> OpenScriptEditorWindows;
 		static Vector<String> AvailableWindowTypes;
 
 		/************************************************************************/
@@ -187,6 +181,9 @@ namespace bs
 		/**	Returns the managed instance for the editor window represented by this object. */
 		MonoObject* getManagedInstance() const { return mManagedInstance; }
 
+		/** Invalidates the managed instance pointer, and optionally frees the GC handle. */
+		void clearManagedInstance(bool freeHandle);
+
 	private:
 		typedef void(BS_THUNKCALL *OnInitializeThunkDef) (MonoObject*, MonoException**);
 		typedef void(BS_THUNKCALL *OnDestroyThunkDef) (MonoObject*, MonoException**);
@@ -199,6 +196,7 @@ namespace bs
 		OnDestroyThunkDef mOnDestroyThunk;
 		UpdateThunkDef mUpdateThunk;
 		MonoObject* mManagedInstance;
+		UINT32 mGCHandle;
 		MonoMethod* mGetDisplayName;
 
 		ScriptEditorWindow* mScriptOwner;

+ 12 - 4
Source/SBansheeEditor/Wrappers/BsScriptFolderMonitor.cpp

@@ -20,6 +20,8 @@ namespace bs
 	ScriptFolderMonitor::ScriptFolderMonitor(MonoObject* instance, FolderMonitor* monitor)
 		:ScriptObject(instance), mMonitor(monitor)
 	{
+		mGCHandle = MonoUtil::newWeakGCHandle(instance);
+
 		if (mMonitor != nullptr)
 		{
 			ScriptFolderMonitorManager::instance()._registerMonitor(this);
@@ -73,28 +75,32 @@ namespace bs
 
 	void ScriptFolderMonitor::onMonitorFileModified(const Path& path)
 	{
+		MonoObject* instance = MonoUtil::getObjectFromGCHandle(mGCHandle);
 		MonoString* monoPath = MonoUtil::wstringToMono(path.toWString());
-		MonoUtil::invokeThunk(OnModifiedThunk, getManagedInstance(), monoPath);
+		MonoUtil::invokeThunk(OnModifiedThunk, instance, monoPath);
 	}
 
 	void ScriptFolderMonitor::onMonitorFileAdded(const Path& path)
 	{
+		MonoObject* instance = MonoUtil::getObjectFromGCHandle(mGCHandle);
 		MonoString* monoPath = MonoUtil::wstringToMono(path.toWString());
-		MonoUtil::invokeThunk(OnAddedThunk, getManagedInstance(), monoPath);
+		MonoUtil::invokeThunk(OnAddedThunk, instance, monoPath);
 	}
 
 	void ScriptFolderMonitor::onMonitorFileRemoved(const Path& path)
 	{
+		MonoObject* instance = MonoUtil::getObjectFromGCHandle(mGCHandle);
 		MonoString* monoPath = MonoUtil::wstringToMono(path.toWString());
-		MonoUtil::invokeThunk(OnRemovedThunk, getManagedInstance(), monoPath);
+		MonoUtil::invokeThunk(OnRemovedThunk, instance, monoPath);
 	}
 
 	void ScriptFolderMonitor::onMonitorFileRenamed(const Path& from, const Path& to)
 	{
+		MonoObject* instance = MonoUtil::getObjectFromGCHandle(mGCHandle);
 		MonoString* monoPathFrom = MonoUtil::wstringToMono(from.toWString());
 		MonoString* monoPathTo = MonoUtil::wstringToMono(to.toWString());
 
-		MonoUtil::invokeThunk(OnRenamedThunk, getManagedInstance(), monoPathFrom, monoPathTo);
+		MonoUtil::invokeThunk(OnRenamedThunk, instance, monoPathFrom, monoPathTo);
 	}
 
 	void ScriptFolderMonitor::update()
@@ -112,6 +118,8 @@ namespace bs
 
 			ScriptFolderMonitorManager::instance()._unregisterMonitor(this);
 		}
+
+		mGCHandle = 0;
 	}
 
 	void ScriptFolderMonitorManager::update()

+ 2 - 1
Source/SBansheeEditor/Wrappers/BsScriptFolderMonitor.h

@@ -43,7 +43,8 @@ namespace bs
 		/**	Triggered when the native folder monitor detects a file has been renamed. */
 		void onMonitorFileRenamed(const Path& from, const Path& to);
 
-		FolderMonitor* mMonitor;
+		FolderMonitor* mMonitor = nullptr;
+		UINT32 mGCHandle = 0;
 
 		/************************************************************************/
 		/* 								CLR HOOKS						   		*/

+ 11 - 8
Source/SBansheeEditor/Wrappers/BsScriptOSDropTarget.cpp

@@ -25,8 +25,10 @@ namespace bs
 	ScriptOSDropTarget::OnDropThunkDef ScriptOSDropTarget::onDropThunk;
 
 	ScriptOSDropTarget::ScriptOSDropTarget(MonoObject* instance, ScriptEditorWindow* parent)
-		:ScriptObject(instance), mParent(parent), mDropTarget(nullptr), mIsDestroyed(false)
+		:ScriptObject(instance)
 	{
+		mGCHandle = MonoUtil::newWeakGCHandle(instance);
+
 		EditorWidgetBase* parentWidget = getParentWidget();
 
 		if (parentWidget != nullptr)
@@ -174,8 +176,8 @@ namespace bs
 		if (thisPtr->mIsDestroyed)
 			return;
 
-		MonoUtil::invokeThunk(onEnterThunk, thisPtr->getManagedInstance(), 
-			x - thisPtr->mParentArea.x, y - thisPtr->mParentArea.y);
+		MonoObject* instance = MonoUtil::getObjectFromGCHandle(thisPtr->mGCHandle);
+		MonoUtil::invokeThunk(onEnterThunk, instance, x - thisPtr->mParentArea.x, y - thisPtr->mParentArea.y);
 	}
 
 	void ScriptOSDropTarget::dropTargetDragMove(ScriptOSDropTarget* thisPtr, INT32 x, INT32 y)
@@ -183,8 +185,8 @@ namespace bs
 		if (thisPtr->mIsDestroyed)
 			return;
 
-		MonoUtil::invokeThunk(onMoveThunk, thisPtr->getManagedInstance(), 
-			x - thisPtr->mParentArea.x, y - thisPtr->mParentArea.y);
+		MonoObject* instance = MonoUtil::getObjectFromGCHandle(thisPtr->mGCHandle);
+		MonoUtil::invokeThunk(onMoveThunk, instance, x - thisPtr->mParentArea.x, y - thisPtr->mParentArea.y);
 	}
 
 	void ScriptOSDropTarget::dropTargetDragLeave(ScriptOSDropTarget* thisPtr)
@@ -192,7 +194,8 @@ namespace bs
 		if (thisPtr->mIsDestroyed)
 			return;
 
-		MonoUtil::invokeThunk(onLeaveThunk, thisPtr->getManagedInstance());
+		MonoObject* instance = MonoUtil::getObjectFromGCHandle(thisPtr->mGCHandle);
+		MonoUtil::invokeThunk(onLeaveThunk, instance);
 	}
 
 	void ScriptOSDropTarget::dropTargetDragDropped(ScriptOSDropTarget* thisPtr, INT32 x, INT32 y)
@@ -200,8 +203,8 @@ namespace bs
 		if (thisPtr->mIsDestroyed)
 			return;
 
-		MonoUtil::invokeThunk(onDropThunk, thisPtr->getManagedInstance(), 
-			x - thisPtr->mParentArea.x, y - thisPtr->mParentArea.y);
+		MonoObject* instance = MonoUtil::getObjectFromGCHandle(thisPtr->mGCHandle);
+		MonoUtil::invokeThunk(onDropThunk, instance, x - thisPtr->mParentArea.x, y - thisPtr->mParentArea.y);
 	}
 
 	void ScriptOSDropTarget::widgetParentChanged(EditorWidgetContainer* parent)

+ 3 - 2
Source/SBansheeEditor/Wrappers/BsScriptOSDropTarget.h

@@ -103,11 +103,12 @@ namespace bs
 		 */
 		static void dropTargetDragDropped(ScriptOSDropTarget* thisPtr, INT32 x, INT32 y);
 
-		ScriptEditorWindow* mParent;
+		ScriptEditorWindow* mParent = nullptr;
 		SPtr<DropTarget> mDropTarget;
+		UINT32 mGCHandle = 0;
 		Rect2I mParentArea;
 		Rect2I mArea;
-		bool mIsDestroyed;
+		bool mIsDestroyed = false;
 
 		HEvent mDropTargetEnterConn;
 		HEvent mDropTargetMoveConn;

+ 4 - 5
Source/SBansheeEditor/Wrappers/GUI/BsScriptGUIColorField.cpp

@@ -56,9 +56,8 @@ namespace bs
 			guiField = GUIColorField::create(options, styleName);
 		}
 
-		guiField->onClicked.connect(std::bind(&ScriptGUIColorField::onClicked, instance));
-
-		new (bs_alloc<ScriptGUIColorField>()) ScriptGUIColorField(instance, guiField);
+		ScriptGUIColorField* nativeInstance = new (bs_alloc<ScriptGUIColorField>()) ScriptGUIColorField(instance, guiField);
+		guiField->onClicked.connect(std::bind(&ScriptGUIColorField::onClicked, nativeInstance));
 	}
 
 	void ScriptGUIColorField::internal_getValue(ScriptGUIColorField* nativeInstance, Color* output)
@@ -79,8 +78,8 @@ namespace bs
 		colorField->setTint(*color);
 	}
 
-	void ScriptGUIColorField::onClicked(MonoObject* instance)
+	void ScriptGUIColorField::onClicked()
 	{
-		MonoUtil::invokeThunk(onClickedThunk, instance);
+		MonoUtil::invokeThunk(onClickedThunk, getManagedInstance());
 	}
 }

+ 2 - 6
Source/SBansheeEditor/Wrappers/GUI/BsScriptGUIColorField.h

@@ -20,12 +20,8 @@ namespace bs
 	private:
 		ScriptGUIColorField(MonoObject* instance, GUIColorField* colorField);
 
-		/**
-		 * Triggered when the user clicks on the native color field.
-		 *
-		 * @param[in]	instance	Managed GUIColorField instance.
-		 */
-		static void onClicked(MonoObject* instance);
+		/** Triggered when the user clicks on the native color field. */
+		void onClicked();
 
 		/************************************************************************/
 		/* 								CLR HOOKS						   		*/

+ 9 - 10
Source/SBansheeEditor/Wrappers/GUI/BsScriptGUIEnumField.cpp

@@ -67,8 +67,6 @@ namespace bs
 			guiField = GUIListBoxField::create(nativeNames, multiselect, options, styleName);
 		}
 
-		guiField->onSelectionChanged.connect(std::bind(&ScriptGUIEnumField::onSelectionChanged, instance, _1, _2));
-
 		ScriptArray valuesArr(values);
 		UINT32 elemSize = valuesArr.elementSize();
 
@@ -111,7 +109,10 @@ namespace bs
 		}
 			
 
-		new (bs_alloc<ScriptGUIEnumField>()) ScriptGUIEnumField(instance, guiField, nativeValues);
+		auto nativeInstance = new (bs_alloc<ScriptGUIEnumField>()) ScriptGUIEnumField(instance, guiField, nativeValues);
+
+		guiField->onSelectionChanged.connect(std::bind(&ScriptGUIEnumField::onSelectionChanged, nativeInstance, _1, _2));
+
 	}
 
 	UINT64 ScriptGUIEnumField::internal_getValue(ScriptGUIEnumField* nativeInstance)
@@ -197,18 +198,16 @@ namespace bs
 		field->setTint(*color);
 	}
 
-	void ScriptGUIEnumField::onSelectionChanged(MonoObject* instance, UINT64 newIndex, bool enabled)
+	void ScriptGUIEnumField::onSelectionChanged(UINT64 newIndex, bool enabled)
 	{
-		ScriptGUIEnumField* nativeInstance = ScriptGUIEnumField::toNative(instance);
-		GUIListBoxField* field = static_cast<GUIListBoxField*>(nativeInstance->getGUIElement());
+		GUIListBoxField* field = static_cast<GUIListBoxField*>(getGUIElement());
 
 		UINT32 outValue = 0;
 
-		const Vector<UINT64>& values = nativeInstance->mValues;
 		Vector<bool> states = field->getElementStates();
-		for (UINT32 i = 0; i < (UINT32)values.size(); i++)
-			outValue |= states[i] ? values[i] : 0;
+		for (UINT32 i = 0; i < (UINT32)mValues.size(); i++)
+			outValue |= states[i] ? mValues[i] : 0;
 
-		MonoUtil::invokeThunk(onSelectionChangedThunk, instance, outValue);
+		MonoUtil::invokeThunk(onSelectionChangedThunk, getManagedInstance(), outValue);
 	}
 }

+ 1 - 2
Source/SBansheeEditor/Wrappers/GUI/BsScriptGUIEnumField.h

@@ -24,11 +24,10 @@ namespace bs
 		/**
 		 * Triggered when the value in the native list box selection changes.
 		 *
-		 * @param[in]	instance	Managed GUIEnumField instance.
 		 * @param[in]	newIndex	Index of the selected element.
 		 * @param[in]	enabled		Determines whether the element at the selection index was enabled or disabled.
 		 */
-		static void onSelectionChanged(MonoObject* instance, UINT64 newIndex, bool enabled);
+		void onSelectionChanged(UINT64 newIndex, bool enabled);
 
 		ScriptGUIEnumField(MonoObject* instance, GUIListBoxField* listBoxField, const Vector<UINT64>& values);
 

+ 7 - 7
Source/SBansheeEditor/Wrappers/GUI/BsScriptGUIFloatField.cpp

@@ -62,10 +62,10 @@ namespace bs
 			guiFloatField = GUIFloatField::create(options, styleName);
 		}
 
-		guiFloatField->onValueChanged.connect(std::bind(&ScriptGUIFloatField::onChanged, instance, _1));
-		guiFloatField->onConfirm.connect(std::bind(&ScriptGUIFloatField::onConfirmed, instance));
+		auto nativeInstance = new (bs_alloc<ScriptGUIFloatField>()) ScriptGUIFloatField(instance, guiFloatField);
 
-		new (bs_alloc<ScriptGUIFloatField>()) ScriptGUIFloatField(instance, guiFloatField);
+		guiFloatField->onValueChanged.connect(std::bind(&ScriptGUIFloatField::onChanged, nativeInstance, _1));
+		guiFloatField->onConfirm.connect(std::bind(&ScriptGUIFloatField::onConfirmed, nativeInstance));
 	}
 
 	float ScriptGUIFloatField::internal_getValue(ScriptGUIFloatField* nativeInstance)
@@ -110,13 +110,13 @@ namespace bs
 		return floatField->getStep();
 	}
 
-	void ScriptGUIFloatField::onChanged(MonoObject* instance, float newValue)
+	void ScriptGUIFloatField::onChanged(float newValue)
 	{
-		MonoUtil::invokeThunk(onChangedThunk, instance, newValue);
+		MonoUtil::invokeThunk(onChangedThunk, getManagedInstance(), newValue);
 	}
 
-	void ScriptGUIFloatField::onConfirmed(MonoObject* instance)
+	void ScriptGUIFloatField::onConfirmed()
 	{
-		MonoUtil::invokeThunk(onConfirmedThunk, instance);
+		MonoUtil::invokeThunk(onConfirmedThunk, getManagedInstance());
 	}
 }

+ 2 - 5
Source/SBansheeEditor/Wrappers/GUI/BsScriptGUIFloatField.h

@@ -23,17 +23,14 @@ namespace bs
 		/**
 		 * Triggered when the value in the native float field changes.
 		 *
-		 * @param[in]	instance	Managed GUIFloatField instance.
 		 * @param[in]	newValue	New field value.
 		 */
-		static void onChanged(MonoObject* instance, float newValue);
+		void onChanged(float newValue);
 
 		/**
 		 * Triggered when the user confirms input in the native float field.
-		 *
-		 * @param[in]	instance	Managed GUIFloatField instance.
 		 */
-		static void onConfirmed(MonoObject* instance);
+		void onConfirmed();
 
 		/************************************************************************/
 		/* 								CLR HOOKS						   		*/

+ 4 - 5
Source/SBansheeEditor/Wrappers/GUI/BsScriptGUIGameObjectField.cpp

@@ -63,9 +63,8 @@ namespace bs
 			guiGameObjectField = GUIGameObjectField::create(typeNamespace, typeName, options, styleName);
 		}
 
-		guiGameObjectField->onValueChanged.connect(std::bind(&ScriptGUIGameObjectField::onChanged, instance, _1));
-
-		new (bs_alloc<ScriptGUIGameObjectField>()) ScriptGUIGameObjectField(instance, guiGameObjectField);
+		auto nativeInstance = new (bs_alloc<ScriptGUIGameObjectField>()) ScriptGUIGameObjectField(instance, guiGameObjectField);
+		guiGameObjectField->onValueChanged.connect(std::bind(&ScriptGUIGameObjectField::onChanged, nativeInstance, _1));
 	}
 
 	void ScriptGUIGameObjectField::internal_getValue(ScriptGUIGameObjectField* nativeInstance, MonoObject** output)
@@ -95,10 +94,10 @@ namespace bs
 		gameObjectField->setTint(*color);
 	}
 
-	void ScriptGUIGameObjectField::onChanged(MonoObject* instance, const HGameObject& newValue)
+	void ScriptGUIGameObjectField::onChanged(const HGameObject& newValue)
 	{
 		MonoObject* managedObj = nativeToManagedGO(newValue);
-		MonoUtil::invokeThunk(onChangedThunk, instance, managedObj);
+		MonoUtil::invokeThunk(onChangedThunk, getManagedInstance(), managedObj);
 	}
 
 	MonoObject* ScriptGUIGameObjectField::nativeToManagedGO(const HGameObject& instance)

+ 1 - 2
Source/SBansheeEditor/Wrappers/GUI/BsScriptGUIGameObjectField.h

@@ -21,10 +21,9 @@ namespace bs
 		/**
 		 * Triggered when the value in the native game object field changes.
 		 *
-		 * @param[in]	instance	Managed GUIGameObjectField instance.
 		 * @param[in]	newValue	New field value.
 		 */
-		static void onChanged(MonoObject* instance, const HGameObject& newValue);
+		void onChanged(const HGameObject& newValue);
 
 		/** Retrieves a managed instance of the specified native game object. Will return null if one doesn't exist. */
 		static MonoObject* nativeToManagedGO(const HGameObject& instance);

+ 7 - 7
Source/SBansheeEditor/Wrappers/GUI/BsScriptGUIIntField.cpp

@@ -62,10 +62,10 @@ namespace bs
 			guiIntField = GUIIntField::create(options, styleName);
 		}
 
-		guiIntField->onValueChanged.connect(std::bind(&ScriptGUIIntField::onChanged, instance, _1));
-		guiIntField->onConfirm.connect(std::bind(&ScriptGUIIntField::onConfirmed, instance));
+		auto nativeInstance = new (bs_alloc<ScriptGUIIntField>()) ScriptGUIIntField(instance, guiIntField);
 
-		new (bs_alloc<ScriptGUIIntField>()) ScriptGUIIntField(instance, guiIntField);
+		guiIntField->onValueChanged.connect(std::bind(&ScriptGUIIntField::onChanged, nativeInstance, _1));
+		guiIntField->onConfirm.connect(std::bind(&ScriptGUIIntField::onConfirmed, nativeInstance));
 	}
 
 	INT32 ScriptGUIIntField::internal_getValue(ScriptGUIIntField* nativeInstance)
@@ -110,13 +110,13 @@ namespace bs
 		return intField->getStep();
 	}
 
-	void ScriptGUIIntField::onChanged(MonoObject* instance, INT32 newValue)
+	void ScriptGUIIntField::onChanged(INT32 newValue)
 	{
-		MonoUtil::invokeThunk(onChangedThunk, instance, newValue);
+		MonoUtil::invokeThunk(onChangedThunk, getManagedInstance(), newValue);
 	}
 
-	void ScriptGUIIntField::onConfirmed(MonoObject* instance)
+	void ScriptGUIIntField::onConfirmed()
 	{
-		MonoUtil::invokeThunk(onConfirmedThunk, instance);
+		MonoUtil::invokeThunk(onConfirmedThunk, getManagedInstance());
 	}
 }

+ 3 - 8
Source/SBansheeEditor/Wrappers/GUI/BsScriptGUIIntField.h

@@ -21,17 +21,12 @@ namespace bs
 		/**
 		 * Triggered when the value in the native int field changes.
 		 *
-		 * @param[in]	instance	Managed GUIIntField instance.
 		 * @param[in]	newValue	New field value.
 		 */
-		static void onChanged(MonoObject* instance, INT32 newValue);
+		void onChanged(INT32 newValue);
 
-		/**
-		 * Triggered when the user confirms input in the native int field.
-		 *
-		 * @param[in]	instance	Managed GUIIntField instance.
-		 */
-		static void onConfirmed(MonoObject* instance);
+		/** Triggered when the user confirms input in the native int field. */
+		void onConfirmed();
 
 		ScriptGUIIntField(MonoObject* instance, GUIIntField* intField);
 

+ 4 - 5
Source/SBansheeEditor/Wrappers/GUI/BsScriptGUIListBoxField.cpp

@@ -79,9 +79,8 @@ namespace bs
 			guiField = GUIListBoxField::create(nativeElements, multiselect, options, styleName);
 		}
 
-		guiField->onSelectionChanged.connect(std::bind(&ScriptGUIListBoxField::onSelectionChanged, instance, _1));
-
-		new (bs_alloc<ScriptGUIListBoxField>()) ScriptGUIListBoxField(instance, guiField);
+		auto nativeInstance = new (bs_alloc<ScriptGUIListBoxField>()) ScriptGUIListBoxField(instance, guiField);
+		guiField->onSelectionChanged.connect(std::bind(&ScriptGUIListBoxField::onSelectionChanged, nativeInstance, _1));
 	}
 
 	UINT32 ScriptGUIListBoxField::internal_getValue(ScriptGUIListBoxField* nativeInstance)
@@ -188,8 +187,8 @@ namespace bs
 		field->setTint(*color);
 	}
 
-	void ScriptGUIListBoxField::onSelectionChanged(MonoObject* instance, UINT32 newIndex)
+	void ScriptGUIListBoxField::onSelectionChanged(UINT32 newIndex)
 	{
-		MonoUtil::invokeThunk(onSelectionChangedThunk, instance, newIndex);
+		MonoUtil::invokeThunk(onSelectionChangedThunk, getManagedInstance(), newIndex);
 	}
 }

+ 1 - 2
Source/SBansheeEditor/Wrappers/GUI/BsScriptGUIListBoxField.h

@@ -21,10 +21,9 @@ namespace bs
 		/**
 		 * Triggered when the value in the native list box selection changes.
 		 *
-		 * @param[in]	instance	Managed GUIListBoxField instance.
 		 * @param[in]	newIndex	New selection index.
 		 */
-		static void onSelectionChanged(MonoObject* instance, UINT32 newIndex);
+		void onSelectionChanged(UINT32 newIndex);
 
 		ScriptGUIListBoxField(MonoObject* instance, GUIListBoxField* listBoxField);
 

+ 4 - 4
Source/SBansheeEditor/Wrappers/GUI/BsScriptGUIResourceField.cpp

@@ -67,9 +67,9 @@ namespace bs
 			guiResourceField = GUIResourceField::create(typeNamespace, typeName, options, styleName);
 		}
 
-		guiResourceField->onValueChanged.connect(std::bind(&ScriptGUIResourceField::onChanged, instance, _1));
+		auto nativeInstance = new (bs_alloc<ScriptGUIResourceField>()) ScriptGUIResourceField(instance, guiResourceField);
 
-		new (bs_alloc<ScriptGUIResourceField>()) ScriptGUIResourceField(instance, guiResourceField);
+		guiResourceField->onValueChanged.connect(std::bind(&ScriptGUIResourceField::onChanged, nativeInstance, _1));
 	}
 
 	void ScriptGUIResourceField::internal_getValue(ScriptGUIResourceField* nativeInstance, MonoObject** output)
@@ -120,10 +120,10 @@ namespace bs
 		resourceField->setTint(*color);
 	}
 
-	void ScriptGUIResourceField::onChanged(MonoObject* instance, const WeakResourceHandle<Resource>& newHandle)
+	void ScriptGUIResourceField::onChanged(const WeakResourceHandle<Resource>& newHandle)
 	{
 		MonoObject* managedObj = ScriptResourceRef::create(newHandle);
-		MonoUtil::invokeThunk(onChangedThunk, instance, managedObj);
+		MonoUtil::invokeThunk(onChangedThunk, getManagedInstance(), managedObj);
 	}
 
 	MonoObject* ScriptGUIResourceField::nativeToManagedResource(const HResource& instance)

+ 1 - 2
Source/SBansheeEditor/Wrappers/GUI/BsScriptGUIResourceField.h

@@ -21,10 +21,9 @@ namespace bs
 		/**
 		 * Triggered when the value in the native resource field changes.
 		 *
-		 * @param[in]	instance	Managed GUIResourceField instance.
 		 * @param[in]	newHandle	Weak handle of the newly selected resource.
 		 */
-		static void onChanged(MonoObject* instance, const WeakResourceHandle<Resource>& newHandle);
+		void onChanged(const WeakResourceHandle<Resource>& newHandle);
 
 		/** Retrieves a managed instance of the specified native resource. Will return null if one doesn't exist. */
 		static MonoObject* nativeToManagedResource(const HResource& instance);

+ 5 - 5
Source/SBansheeEditor/Wrappers/GUI/BsScriptGUISliderField.cpp

@@ -61,10 +61,10 @@ namespace bs
 			guiSliderField = GUISliderField::create(options, styleName);
 		}
 
-		guiSliderField->setRange(min, max);
-		guiSliderField->onValueChanged.connect(std::bind(&ScriptGUISliderField::onChanged, instance, _1));
+		auto nativeInstance = new (bs_alloc<ScriptGUISliderField>()) ScriptGUISliderField(instance, guiSliderField);
 
-		new (bs_alloc<ScriptGUISliderField>()) ScriptGUISliderField(instance, guiSliderField);
+		guiSliderField->setRange(min, max);
+		guiSliderField->onValueChanged.connect(std::bind(&ScriptGUISliderField::onChanged, nativeInstance, _1));
 	}
 
 	float ScriptGUISliderField::internal_getValue(ScriptGUISliderField* nativeInstance)
@@ -109,8 +109,8 @@ namespace bs
 		sliderField->setStep(step);
 	}
 
-	void ScriptGUISliderField::onChanged(MonoObject* instance, float newValue)
+	void ScriptGUISliderField::onChanged(float newValue)
 	{
-		MonoUtil::invokeThunk(onChangedThunk, instance, newValue);
+		MonoUtil::invokeThunk(onChangedThunk, getManagedInstance(), newValue);
 	}
 }

+ 1 - 2
Source/SBansheeEditor/Wrappers/GUI/BsScriptGUISliderField.h

@@ -23,10 +23,9 @@ namespace bs
 		/**
 		 * Triggered when the value in the native slider field changes.
 		 *
-		 * @param[in]	instance	Managed GUISliderField instance.
 		 * @param[in]	newValue	New field value.
 		 */
-		static void onChanged(MonoObject* instance, float newValue);
+		void onChanged(float newValue);
 
 		/************************************************************************/
 		/* 								CLR HOOKS						   		*/

+ 7 - 7
Source/SBansheeEditor/Wrappers/GUI/BsScriptGUITextField.cpp

@@ -59,10 +59,10 @@ namespace bs
 			guiField = GUITextField::create(multiline, options, styleName);
 		}
 
-		guiField->onValueChanged.connect(std::bind(&ScriptGUITextField::onChanged, instance, _1));
-		guiField->onConfirm.connect(std::bind(&ScriptGUITextField::onConfirmed, instance));
+		auto nativeInstance = new (bs_alloc<ScriptGUITextField>()) ScriptGUITextField(instance, guiField);
 
-		new (bs_alloc<ScriptGUITextField>()) ScriptGUITextField(instance, guiField);
+		guiField->onValueChanged.connect(std::bind(&ScriptGUITextField::onChanged, nativeInstance, _1));
+		guiField->onConfirm.connect(std::bind(&ScriptGUITextField::onConfirmed, nativeInstance));
 	}
 
 	void ScriptGUITextField::internal_getValue(ScriptGUITextField* nativeInstance, MonoString** output)
@@ -101,14 +101,14 @@ namespace bs
 		field->setTint(*color);
 	}
 
-	void ScriptGUITextField::onChanged(MonoObject* instance, const WString& newValue)
+	void ScriptGUITextField::onChanged(const WString& newValue)
 	{
 		MonoString* monoNewValue = MonoUtil::wstringToMono(newValue);
-		MonoUtil::invokeThunk(onChangedThunk, instance, monoNewValue);
+		MonoUtil::invokeThunk(onChangedThunk, getManagedInstance(), monoNewValue);
 	}
 
-	void ScriptGUITextField::onConfirmed(MonoObject* instance)
+	void ScriptGUITextField::onConfirmed()
 	{
-		MonoUtil::invokeThunk(onConfirmedThunk, instance);
+		MonoUtil::invokeThunk(onConfirmedThunk, getManagedInstance());
 	}
 }

+ 3 - 8
Source/SBansheeEditor/Wrappers/GUI/BsScriptGUITextField.h

@@ -21,17 +21,12 @@ namespace bs
 		/**
 		 * Triggered when the value in the native text field changes.
 		 *
-		 * @param[in]	instance	Managed GUITextField instance.
 		 * @param[in]	newValue	New string value.
 		 */
-		static void onChanged(MonoObject* instance, const WString& newValue);
+		void onChanged(const WString& newValue);
 
-		/**
-		 * Triggered when the user confirms input in the native text field.
-		 *
-		 * @param[in]	instance	Managed GUITextField instance.
-		 */
-		static void onConfirmed(MonoObject* instance);
+		/** Triggered when the user confirms input in the native text field. */
+		void onConfirmed();
 
 		ScriptGUITextField(MonoObject* instance, GUITextField* textField);
 

+ 4 - 5
Source/SBansheeEditor/Wrappers/GUI/BsScriptGUITextureField.cpp

@@ -62,9 +62,8 @@ namespace bs
 			guiTextureField = GUITextureField::create(options, styleName);
 		}
 
-		guiTextureField->onValueChanged.connect(std::bind(&ScriptGUITextureField::onChanged, instance, _1));
-
-		new (bs_alloc<ScriptGUITextureField>()) ScriptGUITextureField(instance, guiTextureField);
+		auto nativeInstance = new (bs_alloc<ScriptGUITextureField>()) ScriptGUITextureField(instance, guiTextureField);
+		guiTextureField->onValueChanged.connect(std::bind(&ScriptGUITextureField::onChanged, nativeInstance, _1));
 	}
 
 	void ScriptGUITextureField::internal_getValue(ScriptGUITextureField* nativeInstance, MonoObject** output)
@@ -115,10 +114,10 @@ namespace bs
 		textureField->setTint(*color);
 	}
 
-	void ScriptGUITextureField::onChanged(MonoObject* instance, const WeakResourceHandle<Texture>& newHandle)
+	void ScriptGUITextureField::onChanged(const WeakResourceHandle<Texture>& newHandle)
 	{
 		MonoObject* managedObj = ScriptResourceRef::create(newHandle);
-		MonoUtil::invokeThunk(onChangedThunk, instance, managedObj);
+		MonoUtil::invokeThunk(onChangedThunk, getManagedInstance(), managedObj);
 	}
 
 	MonoObject* ScriptGUITextureField::nativeToManagedResource(const HTexture& instance)

+ 1 - 2
Source/SBansheeEditor/Wrappers/GUI/BsScriptGUITextureField.h

@@ -21,10 +21,9 @@ namespace bs
 		/**
 		 * Triggered when the value in the native texture field changes.
 		 *
-		 * @param[in]	instance	Managed GUITextureField instance.
 		 * @param[in]	newHandle	Handle of the new texture.
 		 */
-		static void onChanged(MonoObject* instance, const WeakResourceHandle<Texture>& newHandle);
+		void onChanged(const WeakResourceHandle<Texture>& newHandle);
 
 		/** Retrieves a managed instance of the specified native texture. Will return null if one doesn't exist. */
 		static MonoObject* nativeToManagedResource(const HTexture& instance);

+ 4 - 5
Source/SBansheeEditor/Wrappers/GUI/BsScriptGUIToggleField.cpp

@@ -56,9 +56,8 @@ namespace bs
 			guiField = GUIToggleField::create(options, styleName);
 		}
 
-		guiField->onValueChanged.connect(std::bind(&ScriptGUIToggleField::onChanged, instance, _1));
-
-		new (bs_alloc<ScriptGUIToggleField>()) ScriptGUIToggleField(instance, guiField);
+		auto nativeInstance = new (bs_alloc<ScriptGUIToggleField>()) ScriptGUIToggleField(instance, guiField);
+		guiField->onValueChanged.connect(std::bind(&ScriptGUIToggleField::onChanged, nativeInstance, _1));
 	}
 
 	void ScriptGUIToggleField::internal_getValue(ScriptGUIToggleField* nativeInstance, bool* output)
@@ -79,8 +78,8 @@ namespace bs
 		toggleField->setTint(*color);
 	}
 
-	void ScriptGUIToggleField::onChanged(MonoObject* instance, bool newValue)
+	void ScriptGUIToggleField::onChanged(bool newValue)
 	{
-		MonoUtil::invokeThunk(onChangedThunk, instance, newValue);
+		MonoUtil::invokeThunk(onChangedThunk, getManagedInstance(), newValue);
 	}
 }

+ 1 - 2
Source/SBansheeEditor/Wrappers/GUI/BsScriptGUIToggleField.h

@@ -21,10 +21,9 @@ namespace bs
 		/**
 		 * Triggered when the value in the native toggle field changes.
 		 *
-		 * @param[in]	instance	Managed GUIToggleField instance.
 		 * @param[in]	newValue	Is the toggle active.
 		 */
-		static void onChanged(MonoObject* instance, bool newValue);
+		void onChanged(bool newValue);
 
 		ScriptGUIToggleField(MonoObject* instance, GUIToggleField* toggleField);
 

+ 8 - 7
Source/SBansheeEditor/Wrappers/GUI/BsScriptGUIVector2Field.cpp

@@ -61,10 +61,11 @@ namespace bs
 			field = GUIVector2Field::create(options, styleName);
 		}
 
-		field->onValueChanged.connect(std::bind(&ScriptGUIVector2Field::onChanged, instance, _1));
-		field->onConfirm.connect(std::bind(&ScriptGUIVector2Field::onConfirmed, instance));
 
-		new (bs_alloc<ScriptGUIVector2Field>()) ScriptGUIVector2Field(instance, field);
+		auto nativeInstance = new (bs_alloc<ScriptGUIVector2Field>()) ScriptGUIVector2Field(instance, field);
+
+		field->onValueChanged.connect(std::bind(&ScriptGUIVector2Field::onChanged, nativeInstance, _1));
+		field->onConfirm.connect(std::bind(&ScriptGUIVector2Field::onConfirmed, nativeInstance));
 	}
 
 	void ScriptGUIVector2Field::internal_getValue(ScriptGUIVector2Field* nativeInstance, Vector2* output)
@@ -91,13 +92,13 @@ namespace bs
 		field->setTint(*color);
 	}
 
-	void ScriptGUIVector2Field::onChanged(MonoObject* instance, const Vector2& newValue)
+	void ScriptGUIVector2Field::onChanged(const Vector2& newValue)
 	{
-		MonoUtil::invokeThunk(onChangedThunk, instance, ScriptVector2::box(newValue));
+		MonoUtil::invokeThunk(onChangedThunk, getManagedInstance(), ScriptVector2::box(newValue));
 	}
 
-	void ScriptGUIVector2Field::onConfirmed(MonoObject* instance)
+	void ScriptGUIVector2Field::onConfirmed()
 	{
-		MonoUtil::invokeThunk(onConfirmedThunk, instance);
+		MonoUtil::invokeThunk(onConfirmedThunk, getManagedInstance());
 	}
 }

+ 3 - 8
Source/SBansheeEditor/Wrappers/GUI/BsScriptGUIVector2Field.h

@@ -21,17 +21,12 @@ namespace bs
 		/**
 		 * Triggered when the value in the native vector field changes.
 		 *
-		 * @param[in]	instance	Managed GUIVector2Field instance.
 		 * @param[in]	newValue	New vector value.
 		 */
-		static void onChanged(MonoObject* instance, const Vector2& newValue);
+		void onChanged(const Vector2& newValue);
 
-		/**
-		 * Triggered when the user confirms input in the native vector field.
-		 *
-		 * @param[in]	instance	Managed GUIVector2Field instance.
-		 */
-		static void onConfirmed(MonoObject* instance);
+		/** Triggered when the user confirms input in the native vector field. */
+		void onConfirmed();
 
 		ScriptGUIVector2Field(MonoObject* instance, GUIVector2Field* vector2Field);
 

+ 7 - 7
Source/SBansheeEditor/Wrappers/GUI/BsScriptGUIVector3Field.cpp

@@ -61,10 +61,10 @@ namespace bs
 			field = GUIVector3Field::create(options, styleName);
 		}
 
-		field->onValueChanged.connect(std::bind(&ScriptGUIVector3Field::onChanged, instance, _1));
-		field->onConfirm.connect(std::bind(&ScriptGUIVector3Field::onConfirmed, instance));
 
-		new (bs_alloc<ScriptGUIVector3Field>()) ScriptGUIVector3Field(instance, field);
+		auto nativeInstance = new (bs_alloc<ScriptGUIVector3Field>()) ScriptGUIVector3Field(instance, field);
+		field->onValueChanged.connect(std::bind(&ScriptGUIVector3Field::onChanged, nativeInstance, _1));
+		field->onConfirm.connect(std::bind(&ScriptGUIVector3Field::onConfirmed, nativeInstance));
 	}
 
 	void ScriptGUIVector3Field::internal_getValue(ScriptGUIVector3Field* nativeInstance, Vector3* output)
@@ -91,13 +91,13 @@ namespace bs
 		field->setTint(*color);
 	}
 
-	void ScriptGUIVector3Field::onChanged(MonoObject* instance, const Vector3& newValue)
+	void ScriptGUIVector3Field::onChanged(const Vector3& newValue)
 	{
-		MonoUtil::invokeThunk(onChangedThunk, instance, ScriptVector3::box(newValue));
+		MonoUtil::invokeThunk(onChangedThunk, getManagedInstance(), ScriptVector3::box(newValue));
 	}
 
-	void ScriptGUIVector3Field::onConfirmed(MonoObject* instance)
+	void ScriptGUIVector3Field::onConfirmed()
 	{
-		MonoUtil::invokeThunk(onConfirmedThunk, instance);
+		MonoUtil::invokeThunk(onConfirmedThunk, getManagedInstance());
 	}
 }

+ 3 - 8
Source/SBansheeEditor/Wrappers/GUI/BsScriptGUIVector3Field.h

@@ -21,17 +21,12 @@ namespace bs
 		/**
 		 * Triggered when the value in the native vector field changes.
 		 *
-		 * @param[in]	instance	Managed GUIVector3Field instance.
 		 * @param[in]	newValue	New vector value.
 		 */
-		static void onChanged(MonoObject* instance, const Vector3& newValue);
+		void onChanged(const Vector3& newValue);
 
-		/**
-		 * Triggered when the user confirms input in the native vector field.
-		 *
-		 * @param[in]	instance	Managed GUIVector3Field instance.
-		 */
-		static void onConfirmed(MonoObject* instance);
+		/** Triggered when the user confirms input in the native vector field. */
+		void onConfirmed();
 
 		ScriptGUIVector3Field(MonoObject* instance, GUIVector3Field* vector3Field);
 

+ 8 - 7
Source/SBansheeEditor/Wrappers/GUI/BsScriptGUIVector4Field.cpp

@@ -60,10 +60,11 @@ namespace bs
 			field = GUIVector4Field::create(options, styleName);
 		}
 
-		field->onValueChanged.connect(std::bind(&ScriptGUIVector4Field::onChanged, instance, _1));
-		field->onConfirm.connect(std::bind(&ScriptGUIVector4Field::onConfirmed, instance));
 
-		new (bs_alloc<ScriptGUIVector4Field>()) ScriptGUIVector4Field(instance, field);
+		auto nativeInstance = new (bs_alloc<ScriptGUIVector4Field>()) ScriptGUIVector4Field(instance, field);
+
+		field->onValueChanged.connect(std::bind(&ScriptGUIVector4Field::onChanged, nativeInstance, _1));
+		field->onConfirm.connect(std::bind(&ScriptGUIVector4Field::onConfirmed, nativeInstance));
 	}
 
 	void ScriptGUIVector4Field::internal_getValue(ScriptGUIVector4Field* nativeInstance, Vector4* output)
@@ -90,13 +91,13 @@ namespace bs
 		field->setTint(*color);
 	}
 
-	void ScriptGUIVector4Field::onChanged(MonoObject* instance, const Vector4& newValue)
+	void ScriptGUIVector4Field::onChanged(const Vector4& newValue)
 	{
-		MonoUtil::invokeThunk(onChangedThunk, instance, ScriptVector4::box(newValue));
+		MonoUtil::invokeThunk(onChangedThunk, getManagedInstance(), ScriptVector4::box(newValue));
 	}
 
-	void ScriptGUIVector4Field::onConfirmed(MonoObject* instance)
+	void ScriptGUIVector4Field::onConfirmed()
 	{
-		MonoUtil::invokeThunk(onConfirmedThunk, instance);
+		MonoUtil::invokeThunk(onConfirmedThunk, getManagedInstance());
 	}
 }

+ 3 - 8
Source/SBansheeEditor/Wrappers/GUI/BsScriptGUIVector4Field.h

@@ -21,17 +21,12 @@ namespace bs
 		/**
 		 * Triggered when the value in the native vector field changes.
 		 *
-		 * @param[in]	instance	Managed GUIVector4Field instance.
 		 * @param[in]	newValue	New vector value.
 		 */
-		static void onChanged(MonoObject* instance, const Vector4& newValue);
+		void onChanged(const Vector4& newValue);
 
-		/**
-		 * Triggered when the user confirms input in the native vector field.
-		 *
-		 * @param[in]	instance	Managed GUIVector4Field instance.
-		 */
-		static void onConfirmed(MonoObject* instance);
+		/** Triggered when the user confirms input in the native vector field. */
+		void onConfirmed();
 
 		ScriptGUIVector4Field(MonoObject* instance, GUIVector4Field* vector4Field);
 

+ 51 - 51
Source/SBansheeEngine/BsManagedComponent.cpp

@@ -17,18 +17,10 @@
 namespace bs
 {
 	ManagedComponent::ManagedComponent()
-		: mManagedInstance(nullptr), mManagedClass(nullptr), mRuntimeType(nullptr), mManagedHandle(0)
-		, mRequiresReset(true), mMissingType(false), mOnCreatedThunk(nullptr), mOnInitializedThunk(nullptr)
-		, mOnUpdateThunk(nullptr), mOnResetThunk(nullptr), mOnDestroyThunk(nullptr), mOnDisabledThunk(nullptr)
-		, mOnEnabledThunk(nullptr), mOnTransformChangedThunk(nullptr), mCalculateBoundsMethod(nullptr)
 	{ }
 
 	ManagedComponent::ManagedComponent(const HSceneObject& parent, MonoReflectionType* runtimeType)
-		: Component(parent), mManagedInstance(nullptr), mManagedClass(nullptr), mRuntimeType(runtimeType)
-		, mManagedHandle(0), mRequiresReset(true), mMissingType(false), mOnCreatedThunk(nullptr)
-		, mOnInitializedThunk(nullptr), mOnUpdateThunk(nullptr), mOnResetThunk(nullptr), mOnDestroyThunk(nullptr)
-		, mOnDisabledThunk(nullptr), mOnEnabledThunk(nullptr), mOnTransformChangedThunk(nullptr)
-		, mCalculateBoundsMethod(nullptr)
+		: Component(parent), mRuntimeType(runtimeType)
 	{
 		MonoUtil::getClassName(mRuntimeType, mNamespace, mTypeName);
 		setName(mTypeName);
@@ -39,6 +31,11 @@ namespace bs
 
 	}
 
+	MonoObject* ManagedComponent::getManagedInstance() const
+	{
+		return MonoUtil::getObjectFromGCHandle(mGCHandle);
+	}
+
 	ComponentBackupData ManagedComponent::backup(bool clearExisting)
 	{
 		ComponentBackupData backupData;
@@ -47,7 +44,8 @@ namespace bs
 		// return the data we backed up before the type was lost
 		if (!mMissingType)
 		{
-			SPtr<ManagedSerializableObject> serializableObject = ManagedSerializableObject::createFromExisting(mManagedInstance);
+			MonoObject* instance = MonoUtil::getObjectFromGCHandle(mGCHandle);
+			SPtr<ManagedSerializableObject> serializableObject = ManagedSerializableObject::createFromExisting(instance);
 
 			// Serialize the object information and its fields. We cannot just serialize the entire object because
 			// the managed instance had to be created in a previous step. So we handle creation of the top level object manually.
@@ -79,11 +77,10 @@ namespace bs
 
 		if (clearExisting)
 		{
-			if (mManagedInstance != nullptr)
+			if (mGCHandle != 0)
 			{
-				mManagedInstance = nullptr;
-				MonoUtil::freeGCHandle(mManagedHandle);
-				mManagedHandle = 0;
+				MonoUtil::freeGCHandle(mGCHandle);
+				mGCHandle = 0;
 			}
 
 			mManagedClass = nullptr;
@@ -131,18 +128,16 @@ namespace bs
 		mRequiresReset = true;
 	}
 
-	void ManagedComponent::initialize(MonoObject* object)
+	void ManagedComponent::initialize(MonoObject* instance)
 	{
 		mFullTypeName = mNamespace + "." + mTypeName;
-		mManagedInstance = object;
 		
 		mManagedClass = nullptr;
-		if (mManagedInstance != nullptr)
+		if (instance != nullptr)
 		{
-			mManagedHandle = MonoUtil::newGCHandle(mManagedInstance);
-			mManagedInstance = MonoUtil::getObjectFromGCHandle(mManagedHandle);
+			mGCHandle = MonoUtil::newGCHandle(instance, false);
 
-			::MonoClass* monoClass = MonoUtil::getClass(mManagedInstance);
+			::MonoClass* monoClass = MonoUtil::getClass(instance);
 			mRuntimeType = MonoUtil::getType(monoClass);
 
 			mManagedClass = MonoManager::instance().findClass(monoClass);
@@ -258,7 +253,8 @@ namespace bs
 
 	bool ManagedComponent::calculateBounds(Bounds& bounds)
 	{
-		if (mManagedInstance != nullptr && mCalculateBoundsMethod != nullptr)
+		MonoObject* instance = MonoUtil::getObjectFromGCHandle(mGCHandle);
+		if (instance != nullptr && mCalculateBoundsMethod != nullptr)
 		{
 			AABox box;
 			Sphere sphere;
@@ -267,7 +263,7 @@ namespace bs
 			params[0] = &box;
 			params[1] = &sphere;
 
-			MonoObject* areBoundsValidObj = mCalculateBoundsMethod->invokeVirtual(mManagedInstance, params);
+			MonoObject* areBoundsValidObj = mCalculateBoundsMethod->invokeVirtual(instance, params);
 
 			bool areBoundsValid;
 			areBoundsValid = *(bool*)MonoUtil::unbox(areBoundsValidObj);
@@ -281,25 +277,25 @@ namespace bs
 
 	void ManagedComponent::update()
 	{
-		assert(mManagedInstance != nullptr);
-
 		if (mOnUpdateThunk != nullptr)
 		{
+			MonoObject* instance = MonoUtil::getObjectFromGCHandle(mGCHandle);
+
 			// Note: Not calling virtual methods. Can be easily done if needed but for now doing this
 			// for some extra speed.
-			MonoUtil::invokeThunk(mOnUpdateThunk, mManagedInstance);
+			MonoUtil::invokeThunk(mOnUpdateThunk, instance);
 		}
 	}
 
 	void ManagedComponent::triggerOnReset()
 	{
-		assert(mManagedInstance != nullptr);
-
 		if (mRequiresReset && mOnResetThunk != nullptr)
 		{
+			MonoObject* instance = MonoUtil::getObjectFromGCHandle(mGCHandle);
+
 			// Note: Not calling virtual methods. Can be easily done if needed but for now doing this
 			// for some extra speed.
-			MonoUtil::invokeThunk(mOnResetThunk, mManagedInstance);
+			MonoUtil::invokeThunk(mOnResetThunk, instance);
 		}
 
 		mRequiresReset = false;
@@ -308,21 +304,23 @@ namespace bs
 	void ManagedComponent::_instantiate()
 	{
 		mObjInfo = nullptr;
+
+		MonoObject* instance;
 		if (!ScriptAssemblyManager::instance().getSerializableObjectInfo(mNamespace, mTypeName, mObjInfo))
 		{
-			MonoObject* instance = ScriptAssemblyManager::instance().getMissingComponentClass()->createInstance(true);
+			instance = ScriptAssemblyManager::instance().getMissingComponentClass()->createInstance(true);
 
 			initialize(instance);
 			mMissingType = true;
 		}
 		else
 		{
-			initialize(mObjInfo->mMonoClass->createInstance());
+			instance = mObjInfo->mMonoClass->createInstance();
+
+			initialize(instance);
 			mMissingType = false;
 		}
 
-		assert(mManagedInstance != nullptr);
-
 		// Find handle to self
 		HManagedComponent componentHandle;
 		if (SO() != nullptr)
@@ -339,16 +337,16 @@ namespace bs
 		}
 
 		assert(componentHandle != nullptr);
-		ScriptGameObjectManager::instance().createManagedScriptComponent(mManagedInstance, componentHandle);
+		ScriptGameObjectManager::instance().createManagedScriptComponent(instance, componentHandle);
 	}
 
 	void ManagedComponent::onCreated()
 	{
-		assert(mManagedInstance != nullptr);
+		MonoObject* instance = MonoUtil::getObjectFromGCHandle(mGCHandle);
 
 		if (mSerializedObjectData != nullptr && !mMissingType)
 		{
-			mSerializedObjectData->deserialize(mManagedInstance, mObjInfo);
+			mSerializedObjectData->deserialize(instance, mObjInfo);
 			mSerializedObjectData = nullptr;
 		}
 
@@ -356,7 +354,7 @@ namespace bs
 		{
 			// Note: Not calling virtual methods. Can be easily done if needed but for now doing this
 			// for some extra speed.
-			MonoUtil::invokeThunk(mOnCreatedThunk, mManagedInstance);
+			MonoUtil::invokeThunk(mOnCreatedThunk, instance);
 		}
 
 		triggerOnReset();
@@ -364,13 +362,13 @@ namespace bs
 
 	void ManagedComponent::onInitialized()
 	{
-		assert(mManagedInstance != nullptr);
-
 		if (mOnInitializedThunk != nullptr)
 		{
+			MonoObject* instance = MonoUtil::getObjectFromGCHandle(mGCHandle);
+
 			// Note: Not calling virtual methods. Can be easily done if needed but for now doing this
 			// for some extra speed.
-			MonoUtil::invokeThunk(mOnInitializedThunk, mManagedInstance);
+			MonoUtil::invokeThunk(mOnInitializedThunk, instance);
 		}
 
 		triggerOnReset();
@@ -378,40 +376,40 @@ namespace bs
 
 	void ManagedComponent::onDestroyed()
 	{
-		assert(mManagedInstance != nullptr);
-
 		if (mOnDestroyThunk != nullptr)
 		{
+			MonoObject* instance = MonoUtil::getObjectFromGCHandle(mGCHandle);
+
 			// Note: Not calling virtual methods. Can be easily done if needed but for now doing this
 			// for some extra speed.
-			MonoUtil::invokeThunk(mOnDestroyThunk, mManagedInstance);
+			MonoUtil::invokeThunk(mOnDestroyThunk, instance);
 		}
 
-		mManagedInstance = nullptr;
-		MonoUtil::freeGCHandle(mManagedHandle);
+		MonoUtil::freeGCHandle(mGCHandle);
+		mGCHandle = 0;
 	}
 
 	void ManagedComponent::onEnabled()
 	{
-		assert(mManagedInstance != nullptr);
-
 		if (mOnEnabledThunk != nullptr)
 		{
+			MonoObject* instance = MonoUtil::getObjectFromGCHandle(mGCHandle);
+
 			// Note: Not calling virtual methods. Can be easily done if needed but for now doing this
 			// for some extra speed.
-			MonoUtil::invokeThunk(mOnEnabledThunk, mManagedInstance);
+			MonoUtil::invokeThunk(mOnEnabledThunk, instance);
 		}
 	}
 
 	void ManagedComponent::onDisabled()
 	{
-		assert(mManagedInstance != nullptr);
-
 		if (mOnDisabledThunk != nullptr)
 		{
+			MonoObject* instance = MonoUtil::getObjectFromGCHandle(mGCHandle);
+
 			// Note: Not calling virtual methods. Can be easily done if needed but for now doing this
 			// for some extra speed.
-			MonoUtil::invokeThunk(mOnDisabledThunk, mManagedInstance);
+			MonoUtil::invokeThunk(mOnDisabledThunk, instance);
 		}
 	}
 
@@ -419,9 +417,11 @@ namespace bs
 	{
 		if(mOnTransformChangedThunk != nullptr)
 		{
+			MonoObject* instance = MonoUtil::getObjectFromGCHandle(mGCHandle);
+
 			// Note: Not calling virtual methods. Can be easily done if needed but for now doing this
 			// for some extra speed.
-			MonoUtil::invokeThunk(mOnTransformChangedThunk, mManagedInstance, flags);
+			MonoUtil::invokeThunk(mOnTransformChangedThunk, instance, flags);
 		}
 	}
 

+ 15 - 16
Source/SBansheeEngine/BsManagedComponent.h

@@ -24,7 +24,7 @@ namespace bs
 		~ManagedComponent();
 
 		/**	Returns managed component object instance. */
-		MonoObject* getManagedInstance() const { return mManagedInstance; }
+		MonoObject* getManagedInstance() const;
 
 		/**	Returns managed class of the component. */
 		MonoClass* getClass() const { return mManagedClass; }
@@ -84,29 +84,28 @@ namespace bs
 		typedef void(BS_THUNKCALL *OnDisabledThunkDef) (MonoObject*, MonoException**);
 		typedef void(BS_THUNKCALL *OnTransformChangedThunkDef) (MonoObject*, TransformChangedFlags, MonoException**);
 
-		MonoObject* mManagedInstance;
-		MonoClass* mManagedClass;
-		MonoReflectionType* mRuntimeType;
-		uint32_t mManagedHandle;
+		MonoClass* mManagedClass = nullptr;
+		MonoReflectionType* mRuntimeType = nullptr;
+		uint32_t mGCHandle = 0;
 
 		String mNamespace;
 		String mTypeName;
 		String mFullTypeName;
-		bool mRequiresReset;
+		bool mRequiresReset = true;
 
-		bool mMissingType;
+		bool mMissingType = false;
 		SPtr<ManagedSerializableObject> mSerializedObjectData;
 		SPtr<ManagedSerializableObjectInfo> mObjInfo; // Transient
 
-		OnCreatedThunkDef mOnCreatedThunk;
-		OnInitializedThunkDef mOnInitializedThunk;
-		OnUpdateThunkDef mOnUpdateThunk;
-		OnResetThunkDef mOnResetThunk;
-		OnDestroyedThunkDef mOnDestroyThunk;
-		OnDestroyedThunkDef mOnDisabledThunk;
-		OnDestroyedThunkDef mOnEnabledThunk;
-		OnTransformChangedThunkDef mOnTransformChangedThunk;
-		MonoMethod* mCalculateBoundsMethod;
+		OnCreatedThunkDef mOnCreatedThunk = nullptr;
+		OnInitializedThunkDef mOnInitializedThunk = nullptr;
+		OnUpdateThunkDef mOnUpdateThunk = nullptr;
+		OnResetThunkDef mOnResetThunk = nullptr;
+		OnDestroyedThunkDef mOnDestroyThunk = nullptr;
+		OnDestroyedThunkDef mOnDisabledThunk = nullptr;
+		OnDestroyedThunkDef mOnEnabledThunk = nullptr;
+		OnTransformChangedThunkDef mOnTransformChangedThunk = nullptr;
+		MonoMethod* mCalculateBoundsMethod = nullptr;
 
 		/************************************************************************/
 		/* 							COMPONENT OVERRIDES                    		*/

+ 19 - 18
Source/SBansheeEngine/BsManagedResource.cpp

@@ -18,11 +18,11 @@
 namespace bs
 {
 	ManagedResource::ManagedResource()
-		:Resource(false), mManagedInstance(nullptr)
+		:Resource(false), mGCHandle(0)
 	{ }
 
 	ManagedResource::ManagedResource(MonoObject* managedInstance)
-		:Resource(false), mManagedInstance(nullptr)
+		:Resource(false), mGCHandle(0)
 	{
 		SPtr<ManagedResourceMetaData> metaData = bs_shared_ptr_new<ManagedResourceMetaData>();
 		mMetaData = metaData;
@@ -37,9 +37,15 @@ namespace bs
 		}
 	}
 
+	MonoObject* ManagedResource::getManagedInstance() const
+	{
+		return MonoUtil::getObjectFromGCHandle(mGCHandle);
+	}
+
 	ResourceBackupData ManagedResource::backup(bool clearExisting)
 	{
-		SPtr<ManagedSerializableObject> serializableObject = ManagedSerializableObject::createFromExisting(mManagedInstance);
+		MonoObject* instance = MonoUtil::getObjectFromGCHandle(mGCHandle);
+		SPtr<ManagedSerializableObject> serializableObject = ManagedSerializableObject::createFromExisting(instance);
 
 		ResourceBackupData backupData;
 		if (serializableObject != nullptr)
@@ -57,11 +63,10 @@ namespace bs
 
 		if (clearExisting)
 		{
-			if (mManagedInstance != nullptr)
+			if (mGCHandle != 0)
 			{
-				mManagedInstance = nullptr;
-				MonoUtil::freeGCHandle(mManagedHandle);
-				mManagedHandle = 0;
+				MonoUtil::freeGCHandle(mGCHandle);
+				mGCHandle = 0;
 			}
 		}
 
@@ -70,12 +75,9 @@ namespace bs
 
 	void ManagedResource::restore(MonoObject* instance, const ResourceBackupData& data)
 	{
-		mManagedInstance = instance;
-
-		if (mManagedInstance != nullptr)
+		if (instance != nullptr)
 		{
-			mManagedHandle = MonoUtil::newGCHandle(mManagedInstance);
-			mManagedInstance = MonoUtil::getObjectFromGCHandle(mManagedHandle);
+			mGCHandle = MonoUtil::newGCHandle(instance, false);
 
 			if (data.data != nullptr)
 			{
@@ -86,7 +88,7 @@ namespace bs
 				SPtr<ManagedSerializableObjectInfo> currentObjInfo = nullptr;
 
 				if (ScriptAssemblyManager::instance().getSerializableObjectInfo(managedResMetaData->typeNamespace, managedResMetaData->typeName, currentObjInfo))
-					serializableObject->deserialize(mManagedInstance, currentObjInfo);
+					serializableObject->deserialize(instance, currentObjInfo);
 			}
 		}
 		else
@@ -119,8 +121,7 @@ namespace bs
 
 	void ManagedResource::setHandle(MonoObject* object, const HManagedResource& myHandle)
 	{
-		mManagedHandle = MonoUtil::newGCHandle(object);
-		mManagedInstance = MonoUtil::getObjectFromGCHandle(mManagedHandle);
+		mGCHandle = MonoUtil::newGCHandle(object, false);
 		mMyHandle = myHandle.getWeak();
 
 		ScriptResourceManager::instance().createManagedScriptResource(myHandle, object);
@@ -131,10 +132,10 @@ namespace bs
 	{
 		Resource::destroy();
 
-		if (mManagedInstance != nullptr)
+		if (mGCHandle != 0)
 		{
-			mManagedInstance = nullptr;
-			MonoUtil::freeGCHandle(mManagedHandle);
+			MonoUtil::freeGCHandle(mGCHandle);
+			mGCHandle = 0;
 		}
 
 		ManagedResourceManager::instance().unregisterManagedResource(mMyHandle);

+ 2 - 3
Source/SBansheeEngine/BsManagedResource.h

@@ -18,7 +18,7 @@ namespace bs
 	{
 	public:
 		/**	Returns the internal managed resource object. */
-		MonoObject* getManagedInstance() const { return mManagedInstance; }
+		MonoObject* getManagedInstance() const;
 
 		/**
 		 * Serializes the internal managed resource.
@@ -69,8 +69,7 @@ namespace bs
 		/** @copydoc Resource::destroy */
 		void destroy() override;
 
-		MonoObject* mManagedInstance;
-		uint32_t mManagedHandle;
+		UINT32 mGCHandle;
 		WeakResourceHandle<ManagedResource> mMyHandle;
 
 		/************************************************************************/

+ 0 - 5
Source/SBansheeEngine/BsScriptObject.cpp

@@ -9,16 +9,12 @@
 namespace bs
 {
 	ScriptObjectBase::ScriptObjectBase(MonoObject* instance)
-		:mManagedInstance(instance)
 	{	
 		ScriptObjectManager::instance().registerScriptObject(this);
 	}
 
 	ScriptObjectBase::~ScriptObjectBase() 
 	{
-		if(mManagedInstance != nullptr)
-			BS_EXCEPT(InvalidStateException, "Script object is being destroyed without its instance previously being released.");
-
 		ScriptObjectManager::instance().unregisterScriptObject(this);
 	}
 
@@ -34,7 +30,6 @@ namespace bs
 
 	void ScriptObjectBase::_onManagedInstanceDeleted()
 	{
-		mManagedInstance = nullptr;
 		bs_delete(this);
 	}
 

+ 4 - 22
Source/SBansheeEngine/BsScriptObject.h

@@ -30,9 +30,6 @@ namespace bs
 		ScriptObjectBase(MonoObject* instance);
 		virtual ~ScriptObjectBase();
 
-		/**	Gets the managed object this interop object represents. */
-		MonoObject* getManagedInstance() const { return mManagedInstance; }
-
 		/**
 		 * Should the interop object persist through assembly reload. If false then the interop object will be destroyed on
 		 * reload.
@@ -59,9 +56,6 @@ namespace bs
 		 * beginRefresh() call.
 		 */
 		virtual void endRefresh(const ScriptObjectBackup& data);
-
-	protected:
-		MonoObject* mManagedInstance;
 	};
 
 	/**	Base class for all persistent interop objects. Persistent objects persist through assembly reload. */
@@ -72,7 +66,7 @@ namespace bs
 		virtual ~PersistentScriptObjectBase();
 
 		/** @copydoc ScriptObjectBase::isPersistent  */
-		virtual bool isPersistent() const override { return true; }
+		bool isPersistent() const override { return true; }
 	};
 
 	template <class Type, class Base>
@@ -110,27 +104,15 @@ namespace bs
 		virtual ~ScriptObject() 
 		{ }
 
-		/**	
-		 * Clears any managed instance references from the interop object. Normally called right after the assemblies are
-		 * unloaded.
-		 */
-		void _clearManagedInstance()
-		{
-			if (metaData.thisPtrField != nullptr && this->mManagedInstance != nullptr)
-				metaData.thisPtrField->set(this->mManagedInstance, nullptr);
-
-			this->mManagedInstance = nullptr;
-		}
-
 		/**	Allows persistent objects to restore their managed instances after assembly reload. */
 		void _restoreManagedInstance()
 		{
-			this->mManagedInstance = _createManagedInstance(true);
+			MonoObject* instance = _createManagedInstance(true);
 
 			Type* param = (Type*)(Base*)this; // Needed due to multiple inheritance. Safe since Type must point to an class derived from this one.
 
-			if (metaData.thisPtrField != nullptr && this->mManagedInstance != nullptr)
-				metaData.thisPtrField->set(this->mManagedInstance, &param);
+			if (metaData.thisPtrField != nullptr && instance != nullptr)
+				metaData.thisPtrField->set(instance, &param);
 		}
 
 		/**	Creates a new managed instance of the type wrapped by this interop object. */

+ 2 - 2
Source/SBansheeEngine/Extensions/BsAsyncOpEx.cpp

@@ -5,7 +5,7 @@
 
 namespace bs
 {
-	AsyncOpEx::AsyncOpEx(const AsyncOp& op, const std::function<ScriptObjectBase*(const AsyncOp&)>& convertCallback)
+	AsyncOpEx::AsyncOpEx(const AsyncOp& op, const std::function<MonoObject*(const AsyncOp&)>& convertCallback)
 		:mAsyncOp(op), mConvertCallback(convertCallback)
 	{ }
 
@@ -14,7 +14,7 @@ namespace bs
 		return mAsyncOp.hasCompleted();
 	}
 
-	ScriptObjectBase* AsyncOpEx::getReturnValue() const
+	MonoObject* AsyncOpEx::getReturnValue() const
 	{
 		if (!mAsyncOp.hasCompleted())
 			return nullptr;

+ 3 - 3
Source/SBansheeEngine/Extensions/BsAsyncOpEx.h

@@ -20,7 +20,7 @@ namespace bs
 	class BS_SCR_BE_EXPORT BS_SCRIPT_EXPORT(n:AsyncOp) AsyncOpEx
 	{
 	public:
-		AsyncOpEx(const AsyncOp& op, const std::function<ScriptObjectBase*(const AsyncOp&)>& convertCallback);
+		AsyncOpEx(const AsyncOp& op, const std::function<MonoObject*(const AsyncOp&)>& convertCallback);
 
 		/** @copydoc AsyncOp::hasCompleted */
 		BS_SCRIPT_EXPORT(n:IsComplete,pr:getter)
@@ -28,7 +28,7 @@ namespace bs
 
 		/** Retrieves the value returned by the async operation. Only valid if IsComplete returns true. */
 		BS_SCRIPT_EXPORT(n:ReturnValue,pr:getter)
-		ScriptObjectBase* getReturnValue() const;
+		MonoObject* getReturnValue() const;
 
 		/** @copydoc AsyncOp::blockUntilComplete */
 		BS_SCRIPT_EXPORT(n:BlockUntilComplete)
@@ -36,7 +36,7 @@ namespace bs
 
 	private:
 		AsyncOp mAsyncOp;
-		std::function<ScriptObjectBase*(const AsyncOp&)> mConvertCallback;
+		std::function<MonoObject*(const AsyncOp&)> mConvertCallback;
 	};
 
 	/** @endcond */

+ 2 - 3
Source/SBansheeEngine/Extensions/BsTextureEx.cpp

@@ -93,11 +93,10 @@ namespace bs
 		SPtr<PixelData> readData = thisPtr->getProperties().allocBuffer(face, mipLevel);
 		AsyncOp asyncOp = thisPtr->readData(readData, face, mipLevel);
 
-		std::function<ScriptObjectBase*(const AsyncOp&)> asyncOpToMono =
+		std::function<MonoObject*(const AsyncOp&)> asyncOpToMono =
 			[&readData](const AsyncOp& op)
 		{
-			MonoObject* obj = ScriptPixelData::create(readData);
-			return ScriptPixelData::toNative(obj);
+			return ScriptPixelData::create(readData);
 		};
 
 		return bs_shared_ptr_new<AsyncOpEx>(asyncOp, asyncOpToMono);

+ 1 - 1
Source/SBansheeEngine/Serialization/BsManagedSerializableArray.cpp

@@ -229,7 +229,7 @@ namespace bs
 			MonoObject* newArray = createManagedInstance(mArrayTypeInfo, newSizes);
 
 			void* params[3];
-			params[0] = getManagedInstance();;
+			params[0] = getManagedInstance();
 			params[1] = newArray;
 			params[2] = &copyCount;
 

+ 1 - 1
Source/SBansheeEngine/Serialization/BsManagedSerializableDiff.h

@@ -264,7 +264,7 @@ namespace bs
 	public:
 		friend class ManagedSerializableDiffRTTI;
 		static RTTITypeBase* getRTTIStatic();
-		virtual RTTITypeBase* getRTTI() const override;
+		RTTITypeBase* getRTTI() const override;
 	};
 
 	/** @} */

+ 0 - 2
Source/SBansheeEngine/Wrappers/BsScriptComponent.cpp

@@ -24,8 +24,6 @@ namespace bs
 
 	void ScriptComponentBase::destroy()
 	{
-		mManagedInstance = nullptr;
-
 		// It's possible that managed component is destroyed but a reference to it is still kept during assembly refresh. 
 		// Such components shouldn't be restored so we delete them.
 

+ 14 - 19
Source/SBansheeEngine/Wrappers/BsScriptComponent.h

@@ -56,25 +56,24 @@ namespace bs
 		TScriptComponent(MonoObject* instance, const GameObjectHandle<CompType>& component)
 			:ScriptObject<ScriptClass, BaseType>(instance), mComponent(component)
 		{
-			mManagedHandle = MonoUtil::newGCHandle(instance);
-			this->mManagedInstance = MonoUtil::getObjectFromGCHandle(mManagedHandle);
-
-			BS_DEBUG_ONLY(mHandleValid = true);
+			this->setManagedInstance(instance);
 		}
 
 		virtual ~TScriptComponent() {}
 
-		/**
-		 * Called after assembly reload starts to give the object a chance to restore the data backed up by the previous
-		 * beginRefresh() call.
-		 */
-		virtual void endRefresh(const ScriptObjectBackup& backupData) override
+		/** @copydoc ScriptObject::_createManagedInstance */
+		MonoObject* _createManagedInstance(bool construct) override
 		{
-			BS_ASSERT(!mHandleValid);
-			mManagedHandle = MonoUtil::newGCHandle(this->mManagedInstance);
-			this->mManagedInstance = MonoUtil::getObjectFromGCHandle(mManagedHandle);
+			MonoObject* managedInstance = ScriptClass::metaData.scriptClass->createInstance(construct);
+			this->setManagedInstance(managedInstance);
 
-			ScriptObject<ScriptClass, BaseType>::endRefresh(backupData);
+			return managedInstance;
+		}
+
+		/** @copydoc ScriptObjectBase::_clearManagedInstance */
+		void _clearManagedInstance() override
+		{
+			this->mGCHandle = 0;
 		}
 
 		/**
@@ -83,22 +82,18 @@ namespace bs
 		 */
 		void _notifyDestroyed() override
 		{
-			MonoUtil::freeGCHandle(mManagedHandle);
-			BS_DEBUG_ONLY(mHandleValid = false);
+			this->freeManagedInstance();
 		}
 
 		/**	Called when the managed instance gets finalized by the CLR. */
 		void _onManagedInstanceDeleted() override
 		{
-			MonoUtil::freeGCHandle(mManagedHandle);
-			BS_DEBUG_ONLY(mHandleValid = false);
+			this->freeManagedInstance();
 
 			this->destroy();
 		}
 
 		GameObjectHandle<CompType> mComponent;
-		uint32_t mManagedHandle;
-		BS_DEBUG_ONLY(bool mHandleValid);
 	};
 
 	/**	Interop class between C++ & CLR for Component. */

+ 3 - 1
Source/SBansheeEngine/Wrappers/BsScriptContextMenu.cpp

@@ -21,6 +21,7 @@ namespace bs
 	ScriptContextMenu::ScriptContextMenu(MonoObject* instance)
 		: ScriptObject(instance)
 	{
+		mGCHandle = MonoUtil::newWeakGCHandle(instance);
 		mContextMenu = bs_shared_ptr_new<GUIContextMenu>();
 	}
 
@@ -85,6 +86,7 @@ namespace bs
 
 	void ScriptContextMenu::onContextMenuItemTriggered(UINT32 idx)
 	{
-		MonoUtil::invokeThunk(onEntryTriggered, getManagedInstance(), idx);
+		MonoObject* instance = MonoUtil::getObjectFromGCHandle(mGCHandle);
+		MonoUtil::invokeThunk(onEntryTriggered, instance, idx);
 	}
 }

+ 1 - 0
Source/SBansheeEngine/Wrappers/BsScriptContextMenu.h

@@ -31,6 +31,7 @@ namespace bs
 		void onContextMenuItemTriggered(UINT32 idx);
 
 		SPtr<GUIContextMenu> mContextMenu;
+		UINT32 mGCHandle = 0;
 
 		/************************************************************************/
 		/* 								CLR HOOKS						   		*/

+ 30 - 2
Source/SBansheeEngine/Wrappers/BsScriptGameObject.cpp

@@ -1,15 +1,22 @@
 //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
 //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
 #include "Wrappers/BsScriptGameObject.h"
+#include "BsMonoUtil.h"
+#include <assert.h>
 
 namespace bs
 {
 	ScriptGameObjectBase::ScriptGameObjectBase(MonoObject* instance)
-		:PersistentScriptObjectBase(instance), mRefreshInProgress(false)
+		:PersistentScriptObjectBase(instance), mRefreshInProgress(false), mGCHandle(0)
 	{
 		
 	}
 
+	ScriptGameObjectBase::~ScriptGameObjectBase()
+	{
+		BS_ASSERT(mGCHandle == 0 && "Object being destroyed without its managed instance being freed first.");
+	}
+	
 	ScriptObjectBackup ScriptGameObjectBase::beginRefresh()
 	{
 		mRefreshInProgress = true;
@@ -24,6 +31,27 @@ namespace bs
 		PersistentScriptObjectBase::endRefresh(backupData);
 	}
 
+	MonoObject* ScriptGameObjectBase::getManagedInstance() const
+	{
+		return MonoUtil::getObjectFromGCHandle(mGCHandle);
+	}
+
+	void ScriptGameObjectBase::setManagedInstance(::MonoObject* instance)
+	{
+		BS_ASSERT(mGCHandle == 0 && "Attempting to set a new managed instance without freeing the old one.");
+
+		mGCHandle = MonoUtil::newGCHandle(instance, false);
+	}
+
+	void ScriptGameObjectBase::freeManagedInstance()
+	{
+		if (mGCHandle != 0)
+		{
+			MonoUtil::freeGCHandle(mGCHandle);
+			mGCHandle = 0;
+		}
+	}
+
 	ScriptGameObject::ScriptGameObject(MonoObject* instance)
 		:ScriptObject(instance)
 	{ }
@@ -37,4 +65,4 @@ namespace bs
 	{
 		return nativeInstance->getNativeHandle().getInstanceId();
 	}
-}
+}

+ 20 - 1
Source/SBansheeEngine/Wrappers/BsScriptGameObject.h

@@ -16,7 +16,7 @@ namespace bs
 	{
 	public:
 		ScriptGameObjectBase(MonoObject* instance);
-		virtual ~ScriptGameObjectBase() { }
+		virtual ~ScriptGameObjectBase();
 
 		/**	Returns the internal native GameObject handle. */
 		virtual HGameObject getNativeHandle() const = 0;
@@ -24,13 +24,32 @@ namespace bs
 		/**	Sets the internal native GameObject handle. */
 		virtual void setNativeHandle(const HGameObject& gameObject) = 0;
 
+		/** Returns the managed version of this game object. */
+		MonoObject* getManagedInstance() const;
+
 		/** @copydoc ScriptObjectBase::beginRefresh */
 		ScriptObjectBackup beginRefresh() override;
 
 		/** @copydoc ScriptObjectBase::endRefresh */
 		void endRefresh(const ScriptObjectBackup& backupData) override;
 	protected:
+		/** 
+		 * Makes the object reference the specific managed instance. Internally this allocates a GC handle that keeps a
+		 * reference to the object and allows getManagedInstance to retrieve the managed instance when requested. Should
+		 * be called on initial creation and whenever the managed instance changes (e.g. after assembly refresh). This
+		 * creates a strong reference to the managed instance, and you need to make sure to release it with
+		 * freeManagedInstance() when no longer required.
+		 */
+		void setManagedInstance(MonoObject* instance);
+
+		/** 
+		 * Frees a managed instace assigned with setManagedInstance(). Should be called before the object is destroyed or 
+		 * when you changing the managed instance it points to (in order to release the previous instance). 
+		 */
+		void freeManagedInstance();
+
 		bool mRefreshInProgress;
+		UINT32 mGCHandle;
 	};
 
 	/**	Interop class between C++ & CLR for GameObject. */

+ 7 - 0
Source/SBansheeEngine/Wrappers/BsScriptInputConfiguration.cpp

@@ -14,6 +14,8 @@ namespace bs
 	ScriptInputConfiguration::ScriptInputConfiguration(MonoObject* instance, const SPtr<InputConfiguration>& inputConfig)
 		:ScriptObject(instance), mInputConfig(inputConfig)
 	{ 
+		mGCHandle = MonoUtil::newWeakGCHandle(instance);
+
 		UINT64 configId = (UINT64)inputConfig.get();
 		ScriptInputConfigurations[configId] = this;
 	}
@@ -29,6 +31,11 @@ namespace bs
 		metaData.scriptClass->addInternalCall("Internal_GetRepeatInterval", (void*)&ScriptInputConfiguration::internal_GetRepeatInterval);
 	}
 
+	MonoObject* ScriptInputConfiguration::getManagedInstance() const
+	{
+		return MonoUtil::getObjectFromGCHandle(mGCHandle);
+	}
+
 	ScriptInputConfiguration* ScriptInputConfiguration::getScriptInputConfig(const SPtr<InputConfiguration>& inputConfig)
 	{
 		UINT64 configId = (UINT64)inputConfig.get();

+ 4 - 0
Source/SBansheeEngine/Wrappers/BsScriptInputConfiguration.h

@@ -18,6 +18,9 @@ namespace bs
 	public:
 		SCRIPT_OBJ(ENGINE_ASSEMBLY, "BansheeEngine", "InputConfiguration")
 
+		/** Returns the managed version of this object. */
+		MonoObject* getManagedInstance() const;
+
 		/**	Returns the internal wrapped InputConfiguration object. */
 		SPtr<InputConfiguration> getInternalValue() const { return mInputConfig; }
 
@@ -40,6 +43,7 @@ namespace bs
 		void _onManagedInstanceDeleted() override;
 
 		SPtr<InputConfiguration> mInputConfig;
+		UINT32 mGCHandle = 0;
 		static Map<UINT64, ScriptInputConfiguration*> ScriptInputConfigurations;
 
 		/************************************************************************/

+ 19 - 5
Source/SBansheeEngine/Wrappers/BsScriptManagedComponent.cpp

@@ -24,6 +24,7 @@ namespace bs
 		assert(instance != nullptr);
 
 		MonoUtil::getClassName(instance, mNamespace, mType);
+		mGCHandle = MonoUtil::newWeakGCHandle(instance);
 	}
 
 	void ScriptManagedComponent::initRuntimeData()
@@ -72,14 +73,25 @@ namespace bs
 		SPtr<ManagedSerializableObjectInfo> currentObjInfo = nullptr;
 
 		// See if this type even still exists
+		MonoObject* instance;
 		if (!ScriptAssemblyManager::instance().getSerializableObjectInfo(mNamespace, mType, currentObjInfo))
 		{
 			mTypeMissing = true;
-			return ScriptAssemblyManager::instance().getMissingComponentClass()->createInstance(true);
+			instance = ScriptAssemblyManager::instance().getMissingComponentClass()->createInstance(true);
 		}
+		else
+		{
+			mTypeMissing = false;
+			instance = currentObjInfo->mMonoClass->createInstance(construct);
+		}
+
+		mGCHandle = MonoUtil::newWeakGCHandle(instance);
+		return instance;
+	}
 
-		mTypeMissing = false;
-		return currentObjInfo->mMonoClass->createInstance(construct);
+	void ScriptManagedComponent::_clearManagedInstance()
+	{
+		mGCHandle = 0;
 	}
 
 	ScriptObjectBackup ScriptManagedComponent::beginRefresh()
@@ -102,14 +114,16 @@ namespace bs
 		HManagedComponent managedComponent = static_object_cast<ManagedComponent>(mComponent);
 
 		ComponentBackupData componentBackup = any_cast<ComponentBackupData>(backupData.data);
-		managedComponent->restore(mManagedInstance, componentBackup, mTypeMissing);
+
+		MonoObject* instance = MonoUtil::getObjectFromGCHandle(mGCHandle);
+		managedComponent->restore(instance, componentBackup, mTypeMissing);
 
 		ScriptGameObjectBase::endRefresh(backupData);
 	}
 
 	void ScriptManagedComponent::_onManagedInstanceDeleted()
 	{
-		mManagedInstance = nullptr;
+		mGCHandle = 0;
 
 		// It's possible that managed component is destroyed but a reference to it
 		// is still kept during assembly refresh. Such components shouldn't be restored

+ 3 - 0
Source/SBansheeEngine/Wrappers/BsScriptManagedComponent.h

@@ -41,6 +41,9 @@ namespace bs
 		/** @copydoc ScriptObjectBase::_createManagedInstance */
 		MonoObject* _createManagedInstance(bool construct) override;
 
+		/** @copydoc ScriptObjectBase::_clearManagedInstance */
+		void _clearManagedInstance() override;
+
 		/** @copydoc ScriptObjectBase::_onManagedInstanceDeleted */
 		void _onManagedInstanceDeleted() override;
 

+ 15 - 11
Source/SBansheeEngine/Wrappers/BsScriptManagedResource.cpp

@@ -20,6 +20,7 @@ namespace bs
 		BS_ASSERT(instance != nullptr);
 
 		MonoUtil::getClassName(instance, mNamespace, mType);
+		mGCHandle = MonoUtil::newWeakGCHandle(instance);
 	}
 
 	void ScriptManagedResource::initRuntimeData()
@@ -40,7 +41,15 @@ namespace bs
 		if (!ScriptAssemblyManager::instance().getSerializableObjectInfo(mNamespace, mType, currentObjInfo))
 			return nullptr;
 
-		return currentObjInfo->mMonoClass->createInstance(construct);
+		MonoObject* instance = currentObjInfo->mMonoClass->createInstance(construct);
+		mGCHandle = MonoUtil::newWeakGCHandle(instance);
+
+		return instance;
+	}
+
+	void ScriptManagedResource::_clearManagedInstance()
+	{
+		mGCHandle = 0;
 	}
 
 	ScriptObjectBackup ScriptManagedResource::beginRefresh()
@@ -55,11 +64,13 @@ namespace bs
 
 	void ScriptManagedResource::endRefresh(const ScriptObjectBackup& backupData)
 	{
+		MonoObject* instance = MonoUtil::getObjectFromGCHandle(mGCHandle);
+
 		ResourceBackupData resourceBackup = any_cast<ResourceBackupData>(backupData.data);
-		mResource->restore(mManagedInstance, resourceBackup);
+		mResource->restore(instance, resourceBackup);
 
 		// If we could not find resource type after refresh, treat it as if it was destroyed
-		if (mManagedInstance == nullptr)
+		if (instance == nullptr)
 			_onManagedInstanceDeleted();
 
 		ScriptResourceBase::endRefresh(backupData);
@@ -67,7 +78,7 @@ namespace bs
 
 	void ScriptManagedResource::_onManagedInstanceDeleted()
 	{
-		mManagedInstance = nullptr;
+		mGCHandle = 0;
 		
 		if (!mRefreshInProgress)
 		{
@@ -86,11 +97,4 @@ namespace bs
 	{
 		mResource = static_resource_cast<ManagedResource>(resource);
 	}
-
-	MonoObject* ScriptManagedResource::createInstance()
-	{
-		// Implementation of this method is only relevant for native resources, this is just here to stop compiler from complaining
-		BS_ASSERT(false);
-		return nullptr;
-	}
 }

+ 3 - 3
Source/SBansheeEngine/Wrappers/BsScriptManagedResource.h

@@ -28,9 +28,6 @@ namespace bs
 
 		/**	Returns a handle to the internal wrapped resource. */
 		const HManagedResource& getHandle() const { return mResource; }
-
-		/**	Creates an empty, uninitialized managed instance of the resource interop object. */
-		static MonoObject* createInstance();
 	private:
 		friend class ScriptResourceManager;
 
@@ -43,6 +40,9 @@ namespace bs
 		/** @copydoc ScriptObjectBase::_createManagedInstance */
 		MonoObject* _createManagedInstance(bool construct) override;
 
+		/** @copydoc ScriptObjectBase::_clearManagedInstance */
+		void _clearManagedInstance() override;
+
 		/** @copydoc ScriptObjectBase::_onManagedInstanceDeleted */
 		void _onManagedInstanceDeleted() override;
 

+ 29 - 4
Source/SBansheeEngine/Wrappers/BsScriptResource.cpp

@@ -4,13 +4,19 @@
 #include "BsScriptResourceManager.h"
 #include "Resources/BsResource.h"
 #include "BsMonoUtil.h"
+#include <assert.h>
 
 namespace bs
 {
 	ScriptResourceBase::ScriptResourceBase(MonoObject* instance)
-		:PersistentScriptObjectBase(instance), mRefreshInProgress(false)
+		:PersistentScriptObjectBase(instance), mRefreshInProgress(false), mGCHandle(0)
 	{ }
 
+	ScriptResourceBase::~ScriptResourceBase()
+	{
+		BS_ASSERT(mGCHandle == 0 && "Object being destroyed without its managed instance being freed first.");
+	}
+
 	ScriptObjectBackup ScriptResourceBase::beginRefresh()
 	{
 		mRefreshInProgress = true;
@@ -25,10 +31,29 @@ namespace bs
 		PersistentScriptObjectBase::endRefresh(backupData);
 	}
 
-	void ScriptResourceBase::destroy()
+	MonoObject* ScriptResourceBase::getManagedInstance() const
+	{
+		return MonoUtil::getObjectFromGCHandle(mGCHandle);
+	}
+
+	void ScriptResourceBase::setManagedInstance(::MonoObject* instance)
 	{
-		mManagedInstance = nullptr;
+		BS_ASSERT(mGCHandle == 0 && "Attempting to set a new managed instance without freeing the old one.");
 
+		mGCHandle = MonoUtil::newGCHandle(instance, false);
+	}
+
+	void ScriptResourceBase::freeManagedInstance()
+	{
+		if (mGCHandle != 0)
+		{
+			MonoUtil::freeGCHandle(mGCHandle);
+			mGCHandle = 0;
+		}
+	}
+
+	void ScriptResourceBase::destroy()
+	{
 		if (!mRefreshInProgress)
 			ScriptResourceManager::instance().destroyScriptResource(this);
 	}
@@ -72,4 +97,4 @@ namespace bs
 	{
 		return *(UUID*)MonoUtil::unbox(obj);
 	}
-}
+}

+ 34 - 20
Source/SBansheeEngine/Wrappers/BsScriptResource.h

@@ -22,6 +22,9 @@ namespace bs
 		/**	Sets the internal resource this object wraps. */
 		virtual void setResource(const HResource& resource) = 0;
 
+		/** Returns the managed version of this resource. */
+		MonoObject* getManagedInstance() const;
+
 		/** @copydoc ScriptObjectBase::beginRefresh */
 		ScriptObjectBackup beginRefresh() override;
 
@@ -32,7 +35,22 @@ namespace bs
 		friend class ScriptResourceManager;
 
 		ScriptResourceBase(MonoObject* instance);
-		virtual ~ScriptResourceBase() {}
+		virtual ~ScriptResourceBase();
+
+		/** 
+		 * Makes the object reference the specific managed instance. Internally this allocates a GC handle that keeps a
+		 * reference to the object and allows getManagedInstance to retrieve the managed instance when requested. Should
+		 * be called on initial creation and whenever the managed instance changes (e.g. after assembly refresh). This
+		 * creates a strong reference to the managed instance, and you need to make sure to release it with
+		 * freeManagedInstance() when no longer required.
+		 */
+		void setManagedInstance(MonoObject* instance);
+
+		/** 
+		 * Frees a managed instace assigned with setManagedInstance(). Should be called before the object is destroyed or 
+		 * when you changing the managed instance it points to (in order to release the previous instance). 
+		 */
+		void freeManagedInstance();
 
 		/**	
 		 * Triggered by the script resource managed when the native resource handle this object point to has been destroyed.
@@ -43,6 +61,7 @@ namespace bs
 		void destroy();
 
 		bool mRefreshInProgress;
+		UINT32 mGCHandle;
 	};
 
 	/**	Base class for a specific resource's interop object. */
@@ -65,25 +84,24 @@ namespace bs
 		TScriptResource(MonoObject* instance, const ResourceHandle<ResType>& resource)
 			:ScriptObject<ScriptClass, BaseType>(instance), mResource(resource)
 		{
-			mManagedHandle = MonoUtil::newGCHandle(instance);
-			this->mManagedInstance = MonoUtil::getObjectFromGCHandle(mManagedHandle);
-
-			BS_DEBUG_ONLY(mHandleValid = true);
+			this->setManagedInstance(instance);
 		}
 
 		virtual ~TScriptResource() {}
 
-		/**
-		 * Called after assembly reload starts to give the object a chance to restore the data backed up by the previous
-		 * beginRefresh() call.
-		 */
-		virtual void endRefresh(const ScriptObjectBackup& backupData) override
+		/** @copydoc ScriptObject::_createManagedInstance */
+		MonoObject* _createManagedInstance(bool construct) override
 		{
-			BS_ASSERT(!mHandleValid);
-			mManagedHandle = MonoUtil::newGCHandle(this->mManagedInstance);
-			this->mManagedInstance = MonoUtil::getObjectFromGCHandle(mManagedHandle);
+			MonoObject* managedInstance = ScriptClass::metaData.scriptClass->createInstance(construct);
+			this->setManagedInstance(managedInstance);
+
+			return managedInstance;
+		}
 
-			ScriptObject<ScriptClass, BaseType>::endRefresh(backupData);
+		/** @copydoc ScriptObjectBase::_clearManagedInstance */
+		void _clearManagedInstance() override
+		{
+			this->mGCHandle = 0;
 		}
 
 		/**	
@@ -91,22 +109,18 @@ namespace bs
 		 */
 		void notifyResourceDestroyed() override
 		{
-			MonoUtil::freeGCHandle(mManagedHandle);
-			BS_DEBUG_ONLY(mHandleValid = false);
+			this->freeManagedInstance();
 		}
 
 		/**	Called when the managed instance gets finalized by the CLR. */
 		void _onManagedInstanceDeleted() override
 		{
-			MonoUtil::freeGCHandle(mManagedHandle);
-			BS_DEBUG_ONLY(mHandleValid = false);
+			this->freeManagedInstance();
 
 			this->destroy();
 		}
 
 		ResourceHandle<ResType> mResource;
-		uint32_t mManagedHandle;
-		BS_DEBUG_ONLY(bool mHandleValid);
 	};
 
 	/**	Interop class between C++ & CLR for Resource. */

+ 11 - 15
Source/SBansheeEngine/Wrappers/BsScriptSceneObject.cpp

@@ -15,8 +15,7 @@ namespace bs
 	ScriptSceneObject::ScriptSceneObject(MonoObject* instance, const HSceneObject& sceneObject)
 		:ScriptObject(instance), mSceneObject(sceneObject)
 	{
-		mManagedHandle = MonoUtil::newGCHandle(instance);
-		mManagedInstance = MonoUtil::getObjectFromGCHandle(mManagedHandle);
+		setManagedInstance(instance);
 	}
 
 	void ScriptSceneObject::initRuntimeData()
@@ -399,31 +398,28 @@ namespace bs
 
 	void ScriptSceneObject::_onManagedInstanceDeleted()
 	{
-		mManagedInstance = nullptr;
-
 		if (!mRefreshInProgress)
 			ScriptGameObjectManager::instance().destroyScriptSceneObject(this);
 		else
-		{
-			if (mManagedHandle != 0)
-			{
-				MonoUtil::freeGCHandle(mManagedHandle);
-				mManagedHandle = 0;
-			}
-		}
+			freeManagedInstance();
 	}
 
 	MonoObject* ScriptSceneObject::_createManagedInstance(bool construct)
 	{
 		MonoObject* managedInstance = metaData.scriptClass->createInstance(construct);
-		mManagedHandle = MonoUtil::newGCHandle(managedInstance);
-		return MonoUtil::getObjectFromGCHandle(mManagedHandle);
+		setManagedInstance(managedInstance);
+
+		return managedInstance;
+	}
+
+	void ScriptSceneObject::_clearManagedInstance()
+	{
+		this->mGCHandle = 0;
 	}
 
 	void ScriptSceneObject::_notifyDestroyed()
 	{
-		MonoUtil::freeGCHandle(mManagedHandle);
-		mManagedHandle = 0;
+		freeManagedInstance();
 	}
 
 	void ScriptSceneObject::setNativeHandle(const HGameObject& gameObject)

+ 3 - 1
Source/SBansheeEngine/Wrappers/BsScriptSceneObject.h

@@ -42,11 +42,13 @@ namespace bs
 		/** @copydoc ScriptObjectBase::_createManagedInstance */
 		MonoObject* _createManagedInstance(bool construct) override;
 
+		/** @copydoc ScriptObjectBase::_clearManagedInstance */
+		void _clearManagedInstance() override;
+
 		/**	Triggered by the script game object manager when the handle this object is referencing is destroyed. */
 		void _notifyDestroyed();
 
 		HSceneObject mSceneObject;
-		uint32_t mManagedHandle;
 
 		/************************************************************************/
 		/* 								CLR HOOKS						   		*/

+ 7 - 8
Source/SBansheeEngine/Wrappers/BsScriptSerializableArray.cpp

@@ -23,24 +23,23 @@ namespace bs
 		metaData.scriptClass->addInternalCall("Internal_CreateProperty", (void*)&ScriptSerializableArray::internal_createProperty);
 	}
 
-	ScriptSerializableArray* ScriptSerializableArray::create(const ScriptSerializableProperty* parentProperty)
+	MonoObject* ScriptSerializableArray::create(const ScriptSerializableProperty* native, MonoObject* managed)
 	{
-		SPtr<ManagedSerializableTypeInfoArray> arrayTypeInfo = std::static_pointer_cast<ManagedSerializableTypeInfoArray>(parentProperty->getTypeInfo());
+		SPtr<ManagedSerializableTypeInfoArray> arrayTypeInfo = 
+			std::static_pointer_cast<ManagedSerializableTypeInfoArray>(native->getTypeInfo());
 
 		MonoReflectionType* internalElementType = MonoUtil::getType(arrayTypeInfo->mElementType->getMonoClass());
 
-		void* params[2] = { internalElementType, parentProperty->getManagedInstance() };
+		void* params[2] = { internalElementType, managed };
 		MonoObject* managedInstance = metaData.scriptClass->createInstance(params, 2);
 
-		ScriptSerializableArray* nativeInstance = new (bs_alloc<ScriptSerializableArray>()) ScriptSerializableArray(managedInstance, arrayTypeInfo);
+		new (bs_alloc<ScriptSerializableArray>()) ScriptSerializableArray(managedInstance, arrayTypeInfo);
 
-		return nativeInstance;
+		return managedInstance;
 	}
 
 	MonoObject* ScriptSerializableArray::internal_createProperty(ScriptSerializableArray* nativeInstance)
 	{
-		ScriptSerializableProperty* newProperty = ScriptSerializableProperty::create(nativeInstance->mTypeInfo->mElementType);
-
-		return newProperty->getManagedInstance();
+		return ScriptSerializableProperty::create(nativeInstance->mTypeInfo->mElementType);
 	}
 }

+ 1 - 1
Source/SBansheeEngine/Wrappers/BsScriptSerializableArray.h

@@ -21,7 +21,7 @@ namespace bs
 		 * Creates a new serializable array interop object from the data in the provided property. Caller must ensure the
 		 * property references an array.
 		 */
-		static ScriptSerializableArray* create(const ScriptSerializableProperty* parentProperty);
+		static MonoObject* create(const ScriptSerializableProperty* native, MonoObject* managed);
 
 	private:
 		ScriptSerializableArray(MonoObject* instance, const SPtr<ManagedSerializableTypeInfoArray>& typeInfo);

+ 8 - 12
Source/SBansheeEngine/Wrappers/BsScriptSerializableDictionary.cpp

@@ -24,32 +24,28 @@ namespace bs
 		metaData.scriptClass->addInternalCall("Internal_CreateValueProperty", (void*)&ScriptSerializableDictionary::internal_createValueProperty);
 	}
 
-	ScriptSerializableDictionary* ScriptSerializableDictionary::create(const ScriptSerializableProperty* parentProperty)
+	MonoObject* ScriptSerializableDictionary::create(const ScriptSerializableProperty* native, MonoObject* managed)
 	{
-		SPtr<ManagedSerializableTypeInfoDictionary> dictTypeInfo = std::static_pointer_cast<ManagedSerializableTypeInfoDictionary>(parentProperty->getTypeInfo());
+		SPtr<ManagedSerializableTypeInfoDictionary> dictTypeInfo = 
+			std::static_pointer_cast<ManagedSerializableTypeInfoDictionary>(native->getTypeInfo());
 
 		MonoReflectionType* internalKeyType = MonoUtil::getType(dictTypeInfo->mKeyType->getMonoClass());
 		MonoReflectionType* internalValueType = MonoUtil::getType(dictTypeInfo->mValueType->getMonoClass());
 
-		void* params[3] = { internalKeyType, internalValueType, parentProperty->getManagedInstance() };
+		void* params[3] = { internalKeyType, internalValueType, managed };
 		MonoObject* managedInstance = metaData.scriptClass->createInstance(params, 3);
 
-		ScriptSerializableDictionary* nativeInstance = new (bs_alloc<ScriptSerializableDictionary>()) ScriptSerializableDictionary(managedInstance, dictTypeInfo);
-
-		return nativeInstance;
+		new (bs_alloc<ScriptSerializableDictionary>()) ScriptSerializableDictionary(managedInstance, dictTypeInfo);
+		return managedInstance;
 	}
 
 	MonoObject* ScriptSerializableDictionary::internal_createKeyProperty(ScriptSerializableDictionary* nativeInstance)
 	{
-		ScriptSerializableProperty* newProperty = ScriptSerializableProperty::create(nativeInstance->mTypeInfo->mKeyType);
-
-		return newProperty->getManagedInstance();
+		return ScriptSerializableProperty::create(nativeInstance->mTypeInfo->mKeyType);
 	}
 
 	MonoObject* ScriptSerializableDictionary::internal_createValueProperty(ScriptSerializableDictionary* nativeInstance)
 	{
-		ScriptSerializableProperty* newProperty = ScriptSerializableProperty::create(nativeInstance->mTypeInfo->mValueType);
-
-		return newProperty->getManagedInstance();
+		return ScriptSerializableProperty::create(nativeInstance->mTypeInfo->mValueType);
 	}
 }

+ 1 - 1
Source/SBansheeEngine/Wrappers/BsScriptSerializableDictionary.h

@@ -21,7 +21,7 @@ namespace bs
 		 * Creates a new serializable dictionary interop object from the data in the provided property. Caller must ensure
 		 * the property references a System.Collections.Generic.Dictionary.
 		 */
-		static ScriptSerializableDictionary* create(const ScriptSerializableProperty* parentProperty);
+		static MonoObject* create(const ScriptSerializableProperty* native, MonoObject* managed);
 
 	private:
 		ScriptSerializableDictionary(MonoObject* instance, const SPtr<ManagedSerializableTypeInfoDictionary>& typeInfo);

+ 4 - 7
Source/SBansheeEngine/Wrappers/BsScriptSerializableField.cpp

@@ -26,7 +26,7 @@ namespace bs
 		metaData.scriptClass->addInternalCall("Internal_GetStyle", (void*)&ScriptSerializableField::internal_getStyle);
 	}
 
-	ScriptSerializableField* ScriptSerializableField::create(MonoObject* parentObject, const SPtr<ManagedSerializableMemberInfo>& fieldInfo)
+	MonoObject* ScriptSerializableField::create(MonoObject* parentObject, const SPtr<ManagedSerializableMemberInfo>& fieldInfo)
 	{
 		MonoString* monoStrName = MonoUtil::wstringToMono(toWString(fieldInfo->mName));
 		MonoReflectionType* internalType = MonoUtil::getType(fieldInfo->mTypeInfo->getMonoClass());
@@ -35,16 +35,13 @@ namespace bs
 		void* params[4] = { parentObject, monoStrName, &fieldFlags, internalType };
 		MonoObject* managedInstance = metaData.scriptClass->createInstance(params, 4);
 
-		ScriptSerializableField* nativeInstance = new (bs_alloc<ScriptSerializableField>()) ScriptSerializableField(managedInstance, fieldInfo);
-
-		return nativeInstance;
+		new (bs_alloc<ScriptSerializableField>()) ScriptSerializableField(managedInstance, fieldInfo);
+		return managedInstance;
 	}
 
 	MonoObject* ScriptSerializableField::internal_createProperty(ScriptSerializableField* nativeInstance)
 	{
-		ScriptSerializableProperty* newProperty = ScriptSerializableProperty::create(nativeInstance->mFieldInfo->mTypeInfo);
-
-		return newProperty->getManagedInstance();
+		return ScriptSerializableProperty::create(nativeInstance->mFieldInfo->mTypeInfo);
 	}
 
 	MonoObject* ScriptSerializableField::internal_getValue(ScriptSerializableField* nativeInstance, MonoObject* instance)

+ 9 - 9
Source/SBansheeEngine/Wrappers/BsScriptSerializableField.h

@@ -12,15 +12,15 @@ namespace bs
 	 */
 
 	/** Contains information about a style of a serializable field. */
-    struct SerializableMemberStyle // Note: Must match C# struct SerializableFieldStyle
-    {
-        bool hasRange; /**< True if the range of the field is limited, false if unlimited. */
-        float rangeMin; /**< Returns the lower bound of the range. Only relevant if @see hasRange is true. */
-        float rangeMax; /**< Returns the upper bound of the range. Only relevant if @see hasRange is true. */
-        bool hasStep; /**< True if the field value can only be incremented in specific increments. */
+	struct SerializableMemberStyle // Note: Must match C# struct SerializableFieldStyle
+	{
+		bool hasRange; /**< True if the range of the field is limited, false if unlimited. */
+		float rangeMin; /**< Returns the lower bound of the range. Only relevant if @see hasRange is true. */
+		float rangeMax; /**< Returns the upper bound of the range. Only relevant if @see hasRange is true. */
+		bool hasStep; /**< True if the field value can only be incremented in specific increments. */
 		/** Minimum increment the field value can be increment/decremented by. Only relevant if @see hasStep is true. */
-        float stepIncrement; 
-        bool displayAsSlider; /**< If true, number fields will be displayed as sliders instead of regular input boxes. */
+		float stepIncrement; 
+		bool displayAsSlider; /**< If true, number fields will be displayed as sliders instead of regular input boxes. */
 	};
 
 	/**	Interop class between C++ & CLR for ManagedSerializableFieldInfo. */
@@ -36,7 +36,7 @@ namespace bs
 		 * @param[in]	fieldInfo		Information about the field. Caller must ensure the type matches the type of the
 		 *								provided parent object.
 		 */
-		static ScriptSerializableField* create(MonoObject* parentObject, const SPtr<ManagedSerializableMemberInfo>& fieldInfo);
+		static MonoObject* create(MonoObject* parentObject, const SPtr<ManagedSerializableMemberInfo>& fieldInfo);
 	private:
 		ScriptSerializableField(MonoObject* instance, const SPtr<ManagedSerializableMemberInfo>& fieldInfo);
 

+ 7 - 9
Source/SBansheeEngine/Wrappers/BsScriptSerializableList.cpp

@@ -23,23 +23,21 @@ namespace bs
 		metaData.scriptClass->addInternalCall("Internal_CreateProperty", (void*)&ScriptSerializableList::internal_createProperty);
 	}
 
-	ScriptSerializableList* ScriptSerializableList::create(const ScriptSerializableProperty* parentProperty)
+	MonoObject* ScriptSerializableList::create(const ScriptSerializableProperty* native, MonoObject* managed)
 	{
-		SPtr<ManagedSerializableTypeInfoList> listTypeInfo = std::static_pointer_cast<ManagedSerializableTypeInfoList>(parentProperty->getTypeInfo());
+		SPtr<ManagedSerializableTypeInfoList> listTypeInfo = 
+			std::static_pointer_cast<ManagedSerializableTypeInfoList>(native->getTypeInfo());
 		MonoReflectionType* internalElementType = MonoUtil::getType(listTypeInfo->mElementType->getMonoClass());
 
-		void* params[2] = { internalElementType, parentProperty->getManagedInstance() };
+		void* params[2] = { internalElementType, managed };
 		MonoObject* managedInstance = metaData.scriptClass->createInstance(params, 2);
 
-		ScriptSerializableList* nativeInstance = new (bs_alloc<ScriptSerializableList>()) ScriptSerializableList(managedInstance, listTypeInfo);
-
-		return nativeInstance;
+		new (bs_alloc<ScriptSerializableList>()) ScriptSerializableList(managedInstance, listTypeInfo);
+		return managedInstance;
 	}
 
 	MonoObject* ScriptSerializableList::internal_createProperty(ScriptSerializableList* nativeInstance)
 	{
-		ScriptSerializableProperty* newProperty = ScriptSerializableProperty::create(nativeInstance->mTypeInfo->mElementType);
-
-		return newProperty->getManagedInstance();
+		return ScriptSerializableProperty::create(nativeInstance->mTypeInfo->mElementType);
 	}
 }

+ 1 - 1
Source/SBansheeEngine/Wrappers/BsScriptSerializableList.h

@@ -21,7 +21,7 @@ namespace bs
 		 * Creates a new serializable list interop object from the data in the provided property. Caller must ensure the
 		 * property references a System.Collections.Generic.List.
 		 */
-		static ScriptSerializableList* create(const ScriptSerializableProperty* parentProperty);
+		static MonoObject* create(const ScriptSerializableProperty* native, MonoObject* managed);
 
 	private:
 		ScriptSerializableList(MonoObject* instance, const SPtr<ManagedSerializableTypeInfoList>& typeInfo);

+ 5 - 8
Source/SBansheeEngine/Wrappers/BsScriptSerializableObject.cpp

@@ -27,16 +27,14 @@ namespace bs
 		FieldsField = metaData.scriptClass->getField("_fields");
 	}
 
-	ScriptSerializableObject* ScriptSerializableObject::create(const ScriptSerializableProperty* property)
+	MonoObject* ScriptSerializableObject::create(const ScriptSerializableProperty* native, MonoObject* managed)
 	{
-		MonoReflectionType* internalElementType = MonoUtil::getType(property->getTypeInfo()->getMonoClass());
+		MonoReflectionType* internalElementType = MonoUtil::getType(native->getTypeInfo()->getMonoClass());
 
-		void* params[2] = { internalElementType, property->getManagedInstance() };
+		void* params[2] = { internalElementType, managed };
 		MonoObject* managedInstance = metaData.scriptClass->createInstance(params, 2);
 
-		// Managed constructor will call back to native which will create ScriptSerializableObject instance,
-		// and we can now just retrieve it.
-		return ScriptSerializableObject::toNative(managedInstance);
+		return managedInstance;
 	}
 
 	void ScriptSerializableObject::internal_createInstance(MonoObject* instance, MonoReflectionType* type)
@@ -86,8 +84,7 @@ namespace bs
 		UINT32 i = 0;
 		for (auto& field : sortedFields)
 		{
-			ScriptSerializableField* serializableField = ScriptSerializableField::create(instance, field);
-			MonoObject* fieldManagedInstance = serializableField->getManagedInstance();
+			MonoObject* fieldManagedInstance = ScriptSerializableField::create(instance, field);
 
 			scriptArray.set(i, fieldManagedInstance);
 			i++;

+ 1 - 1
Source/SBansheeEngine/Wrappers/BsScriptSerializableObject.h

@@ -18,7 +18,7 @@ namespace bs
 		SCRIPT_OBJ(ENGINE_ASSEMBLY, "BansheeEngine", "SerializableObject")
 
 		/**	Creates a new serializable object interop object from the data in the provided property.  */
-		static ScriptSerializableObject* create(const ScriptSerializableProperty* parentProperty);
+		static MonoObject* create(const ScriptSerializableProperty* native, MonoObject* managed);
 
 	private:
 		ScriptSerializableObject(MonoObject* instance, const SPtr<ManagedSerializableTypeInfo>& typeInfo);

+ 11 - 20
Source/SBansheeEngine/Wrappers/BsScriptSerializableProperty.cpp

@@ -40,13 +40,12 @@ namespace bs
 		metaData.scriptClass->addInternalCall("Internal_CreateManagedDictionaryInstance", (void*)&ScriptSerializableProperty::internal_createManagedDictionaryInstance);
 	}
 
-	ScriptSerializableProperty* ScriptSerializableProperty::create(const SPtr<ManagedSerializableTypeInfo>& typeInfo)
+	MonoObject* ScriptSerializableProperty::create(const SPtr<ManagedSerializableTypeInfo>& typeInfo)
 	{
 		MonoObject* managedInstance = metaData.scriptClass->createInstance();
+		new (bs_alloc<ScriptSerializableProperty>()) ScriptSerializableProperty(managedInstance, typeInfo);
 
-		ScriptSerializableProperty* nativeInstance = new (bs_alloc<ScriptSerializableProperty>()) ScriptSerializableProperty(managedInstance, typeInfo);
-
-		return nativeInstance;
+		return managedInstance;
 	}
 
 	void ScriptSerializableProperty::internal_CreateInstance(MonoObject* instance, MonoReflectionType* reflType)
@@ -68,32 +67,24 @@ namespace bs
 		new (bs_alloc<ScriptSerializableProperty>()) ScriptSerializableProperty(instance, typeInfo);
 	}
 
-	MonoObject* ScriptSerializableProperty::internal_createObject(ScriptSerializableProperty* nativeInstance)
+	MonoObject* ScriptSerializableProperty::internal_createObject(ScriptSerializableProperty* nativeInstance, MonoObject* managedInstance)
 	{
-		ScriptSerializableObject* newObject = ScriptSerializableObject::create(nativeInstance);
-
-		return newObject->getManagedInstance();
+		return ScriptSerializableObject::create(nativeInstance, managedInstance);
 	}
 
-	MonoObject* ScriptSerializableProperty::internal_createArray(ScriptSerializableProperty* nativeInstance)
+	MonoObject* ScriptSerializableProperty::internal_createArray(ScriptSerializableProperty* nativeInstance, MonoObject* managedInstance)
 	{
-		ScriptSerializableArray* newObject = ScriptSerializableArray::create(nativeInstance);
-
-		return newObject->getManagedInstance();
+		return ScriptSerializableArray::create(nativeInstance, managedInstance);
 	}
 
-	MonoObject* ScriptSerializableProperty::internal_createList(ScriptSerializableProperty* nativeInstance)
+	MonoObject* ScriptSerializableProperty::internal_createList(ScriptSerializableProperty* nativeInstance, MonoObject* managedInstance)
 	{
-		ScriptSerializableList* newObject = ScriptSerializableList::create(nativeInstance);
-
-		return newObject->getManagedInstance();
+		return ScriptSerializableList::create(nativeInstance, managedInstance);
 	}
 
-	MonoObject* ScriptSerializableProperty::internal_createDictionary(ScriptSerializableProperty* nativeInstance)
+	MonoObject* ScriptSerializableProperty::internal_createDictionary(ScriptSerializableProperty* nativeInstance, MonoObject* managedInstance)
 	{
-		ScriptSerializableDictionary* newObject = ScriptSerializableDictionary::create(nativeInstance);
-
-		return newObject->getManagedInstance();
+		return ScriptSerializableDictionary::create(nativeInstance, managedInstance);
 	}
 
 	MonoObject* ScriptSerializableProperty::internal_createManagedObjectInstance(ScriptSerializableProperty* nativeInstance)

+ 5 - 5
Source/SBansheeEngine/Wrappers/BsScriptSerializableProperty.h

@@ -26,7 +26,7 @@ namespace bs
 		 *
 		 * @param[in]	typeInfo	Data about the type the property references.
 		 */
-		static ScriptSerializableProperty* create(const SPtr<ManagedSerializableTypeInfo>& typeInfo);
+		static MonoObject* create(const SPtr<ManagedSerializableTypeInfo>& typeInfo);
 
 		/**	Returns the data about the type the property is referencing. */
 		SPtr<ManagedSerializableTypeInfo> getTypeInfo() const { return mTypeInfo; }
@@ -43,10 +43,10 @@ namespace bs
 		/************************************************************************/
 		static void internal_CreateInstance(MonoObject* instance, MonoReflectionType* reflType);
 
-		static MonoObject* internal_createObject(ScriptSerializableProperty* nativeInstance);
-		static MonoObject* internal_createArray(ScriptSerializableProperty* nativeInstance);
-		static MonoObject* internal_createList(ScriptSerializableProperty* nativeInstance);
-		static MonoObject* internal_createDictionary(ScriptSerializableProperty* nativeInstance);
+		static MonoObject* internal_createObject(ScriptSerializableProperty* nativeInstance, MonoObject* managedInstance);
+		static MonoObject* internal_createArray(ScriptSerializableProperty* nativeInstance, MonoObject* managedInstance);
+		static MonoObject* internal_createList(ScriptSerializableProperty* nativeInstance, MonoObject* managedInstance);
+		static MonoObject* internal_createDictionary(ScriptSerializableProperty* nativeInstance, MonoObject* managedInstance);
 
 		static MonoObject* internal_createManagedObjectInstance(ScriptSerializableProperty* nativeInstance);
 		static MonoObject* internal_createManagedArrayInstance(ScriptSerializableProperty* nativeInstance, MonoArray* sizes);

+ 13 - 13
Source/SBansheeEngine/Wrappers/GUI/BsScriptGUIButton.cpp

@@ -53,12 +53,12 @@ namespace bs
 		GUIContent nativeContent(ScriptGUIContent::getText(content), ScriptGUIContent::getImage(content), ScriptGUIContent::getTooltip(content));
 		GUIButton* guiButton = GUIButton::create(nativeContent, options, toString(MonoUtil::monoToWString(style)));
 
-		guiButton->onClick.connect(std::bind(&ScriptGUIButton::onClick, instance));
-		guiButton->onDoubleClick.connect(std::bind(&ScriptGUIButton::onDoubleClick, instance));
-		guiButton->onHover.connect(std::bind(&ScriptGUIButton::onHover, instance));
-		guiButton->onOut.connect(std::bind(&ScriptGUIButton::onOut, instance));
+		auto nativeInstance = new (bs_alloc<ScriptGUIButton>()) ScriptGUIButton(instance, guiButton);
 
-		new (bs_alloc<ScriptGUIButton>()) ScriptGUIButton(instance, guiButton);
+		guiButton->onClick.connect(std::bind(&ScriptGUIButton::onClick, nativeInstance));
+		guiButton->onDoubleClick.connect(std::bind(&ScriptGUIButton::onDoubleClick, nativeInstance));
+		guiButton->onHover.connect(std::bind(&ScriptGUIButton::onHover, nativeInstance));
+		guiButton->onOut.connect(std::bind(&ScriptGUIButton::onOut, nativeInstance));
 	}
 
 	void ScriptGUIButton::internal_setContent(ScriptGUIButton* nativeInstance, MonoObject* content)
@@ -75,23 +75,23 @@ namespace bs
 		button->setTint(*color);
 	}
 
-	void ScriptGUIButton::onClick(MonoObject* instance)
+	void ScriptGUIButton::onClick()
 	{
-		MonoUtil::invokeThunk(onClickThunk, instance);
+		MonoUtil::invokeThunk(onClickThunk, getManagedInstance());
 	}
 
-	void ScriptGUIButton::onDoubleClick(MonoObject* instance)
+	void ScriptGUIButton::onDoubleClick()
 	{
-		MonoUtil::invokeThunk(onDoubleClickThunk, instance);
+		MonoUtil::invokeThunk(onDoubleClickThunk, getManagedInstance());
 	}
 
-	void ScriptGUIButton::onHover(MonoObject* instance)
+	void ScriptGUIButton::onHover()
 	{
-		MonoUtil::invokeThunk(onHoverThunk, instance);
+		MonoUtil::invokeThunk(onHoverThunk, getManagedInstance());
 	}
 
-	void ScriptGUIButton::onOut(MonoObject* instance)
+	void ScriptGUIButton::onOut()
 	{
-		MonoUtil::invokeThunk(onOutThunk, instance);
+		MonoUtil::invokeThunk(onOutThunk, getManagedInstance());
 	}
 }

+ 4 - 4
Source/SBansheeEngine/Wrappers/GUI/BsScriptGUIButton.h

@@ -22,16 +22,16 @@ namespace bs
 		ScriptGUIButton(MonoObject* instance, GUIButton* button);
 
 		/**	Triggers when the GUI button is clicked. */
-		static void onClick(MonoObject* instance);
+		void onClick();
 
 		/**	Triggers when the GUI button is double-clicked. */
-		static void onDoubleClick(MonoObject* instance);
+		void onDoubleClick();
 
 		/**	Triggers when the GUI button is hovered over. */
-		static void onHover(MonoObject* instance);
+		void onHover();
 
 		/**	Triggers when the pointer leaves the GUI button. */
-		static void onOut(MonoObject* instance);
+		void onOut();
 
 		/************************************************************************/
 		/* 								CLR HOOKS						   		*/

+ 12 - 3
Source/SBansheeEngine/Wrappers/GUI/BsScriptGUIElement.cpp

@@ -18,7 +18,9 @@ namespace bs
 {
 	ScriptGUIElementBaseTBase::ScriptGUIElementBaseTBase(MonoObject* instance)
 		:ScriptObjectBase(instance), mIsDestroyed(false), mElement(nullptr), mParent(nullptr)
-	{ }
+	{
+		mGCHandle = MonoUtil::newWeakGCHandle(instance);
+	}
 
 	void ScriptGUIElementBaseTBase::initialize(GUIElementBase* element)
 	{
@@ -27,18 +29,25 @@ namespace bs
 		if (mElement != nullptr && mElement->_getType() == GUIElementBase::Type::Element)
 		{
 			GUIElement* guiElem = static_cast<GUIElement*>(element);
-			guiElem->onFocusChanged.connect(std::bind(&ScriptGUIElementBaseTBase::onFocusChanged, mManagedInstance, _1));
+			guiElem->onFocusChanged.connect(std::bind(&ScriptGUIElementBaseTBase::onFocusChanged, this, _1));
 		}
 	}
 
-	void ScriptGUIElementBaseTBase::onFocusChanged(MonoObject* instance, bool focus)
+	void ScriptGUIElementBaseTBase::onFocusChanged(ScriptGUIElementBaseTBase* thisPtr, bool focus)
 	{
+		MonoObject* instance = MonoUtil::getObjectFromGCHandle(thisPtr->mGCHandle);
+
 		if (focus)
 			MonoUtil::invokeThunk(ScriptGUIElement::onFocusGainedThunk, instance);
 		else
 			MonoUtil::invokeThunk(ScriptGUIElement::onFocusLostThunk, instance);
 	}
 
+	MonoObject* ScriptGUIElementBaseTBase::getManagedInstance() const
+	{
+		return MonoUtil::getObjectFromGCHandle(mGCHandle);
+	}
+
 	void ScriptGUIElementBaseTBase::_onManagedInstanceDeleted()
 	{
 		destroy();

+ 8 - 4
Source/SBansheeEngine/Wrappers/GUI/BsScriptGUIElement.h

@@ -20,6 +20,9 @@ namespace bs
 		ScriptGUIElementBaseTBase(MonoObject* instance);
 		virtual ~ScriptGUIElementBaseTBase() {}
 
+		/** Returns the managed version of this game object. */
+		MonoObject* getManagedInstance() const;
+
 		/**	Returns the underlying GUIElementBase wrapped by this object. */
 		GUIElementBase* getGUIElement() const { return (GUIElementBase*)mElement; }
 
@@ -46,11 +49,12 @@ namespace bs
 		void _onManagedInstanceDeleted() override;
 
 		/**	Triggered when the focus changes for the underlying GUIElementBase. */
-		static void onFocusChanged(MonoObject* instance, bool focus);
+		static void onFocusChanged(ScriptGUIElementBaseTBase* thisPtr, bool focus);
 
-		bool mIsDestroyed;
-		GUIElementBase* mElement;
-		ScriptGUILayout* mParent;
+		bool mIsDestroyed = false;
+		GUIElementBase* mElement = nullptr;
+		ScriptGUILayout* mParent = nullptr;
+		UINT32 mGCHandle = 0;
 	};
 
 	/**

+ 7 - 6
Source/SBansheeEngine/Wrappers/GUI/BsScriptGUIInputBox.cpp

@@ -43,9 +43,10 @@ namespace bs
 			options.addOption(scriptArray.get<GUIOption>(i));
 
 		GUIInputBox* guiInputBox = GUIInputBox::create(multiline, options, toString(MonoUtil::monoToWString(style)));
-		guiInputBox->onValueChanged.connect(std::bind(&ScriptGUIInputBox::onChanged, instance, _1));
 
-		new (bs_alloc<ScriptGUIInputBox>()) ScriptGUIInputBox(instance, guiInputBox);
+		auto nativeInstance = new (bs_alloc<ScriptGUIInputBox>()) ScriptGUIInputBox(instance, guiInputBox);
+
+		guiInputBox->onValueChanged.connect(std::bind(&ScriptGUIInputBox::onChanged, nativeInstance, _1));
 	}
 
 	void ScriptGUIInputBox::internal_getText(ScriptGUIInputBox* nativeInstance, MonoString** text)
@@ -66,14 +67,14 @@ namespace bs
 		inputBox->setTint(*color);
 	}
 
-	void ScriptGUIInputBox::onChanged(MonoObject* instance, const WString& newValue)
+	void ScriptGUIInputBox::onChanged(const WString& newValue)
 	{
 		MonoString* monoValue = MonoUtil::wstringToMono(newValue);
-		MonoUtil::invokeThunk(onChangedThunk, instance, monoValue);
+		MonoUtil::invokeThunk(onChangedThunk, getManagedInstance(), monoValue);
 	}
 
-	void ScriptGUIInputBox::onConfirmed(MonoObject* instance)
+	void ScriptGUIInputBox::onConfirmed()
 	{
-		MonoUtil::invokeThunk(onConfirmedThunk, instance);
+		MonoUtil::invokeThunk(onConfirmedThunk, getManagedInstance());
 	}
 }

+ 2 - 2
Source/SBansheeEngine/Wrappers/GUI/BsScriptGUIInputBox.h

@@ -22,10 +22,10 @@ namespace bs
 		ScriptGUIInputBox(MonoObject* instance, GUIInputBox* inputBox);
 
 		/**	Triggered when the value in the native input box changes. */
-		static void onChanged(MonoObject* instance, const WString& newValue);
+		void onChanged(const WString& newValue);
 
 		/**	Triggered when the user confirms input in the native input box. */
-		static void onConfirmed(MonoObject* instance);
+		void onConfirmed();
 
 		/************************************************************************/
 		/* 								CLR HOOKS						   		*/

+ 2 - 2
Source/SBansheeEngine/Wrappers/GUI/BsScriptGUILayout.cpp

@@ -58,7 +58,7 @@ namespace bs
 		ChildInfo childInfo;
 
 		childInfo.element = element;
-		childInfo.gcHandle = MonoUtil::newGCHandle(element->getManagedInstance());
+		childInfo.gcHandle = MonoUtil::newGCHandle(element->getManagedInstance(), false);
 
 		mChildren.push_back(childInfo);
 	}
@@ -68,7 +68,7 @@ namespace bs
 		ChildInfo childInfo;
 
 		childInfo.element = element;
-		childInfo.gcHandle = MonoUtil::newGCHandle(element->getManagedInstance());
+		childInfo.gcHandle = MonoUtil::newGCHandle(element->getManagedInstance(), false);
 
 		mChildren.insert(mChildren.begin() + idx, childInfo);
 	}

+ 5 - 4
Source/SBansheeEngine/Wrappers/GUI/BsScriptGUIListBox.cpp

@@ -67,9 +67,10 @@ namespace bs
 		}
 
 		GUIListBox* guiListBox = GUIListBox::create(nativeElements, multiselect, options, toString(MonoUtil::monoToWString(style)));
-		guiListBox->onSelectionToggled.connect(std::bind(&ScriptGUIListBox::onSelectionChanged, instance, _1, _2));
 
-		new (bs_alloc<ScriptGUIListBox>()) ScriptGUIListBox(instance, guiListBox);
+		auto nativeInstance = new (bs_alloc<ScriptGUIListBox>()) ScriptGUIListBox(instance, guiListBox);
+
+		guiListBox->onSelectionToggled.connect(std::bind(&ScriptGUIListBox::onSelectionChanged, nativeInstance, _1, _2));
 	}
 
 	void ScriptGUIListBox::internal_setElements(ScriptGUIListBox* nativeInstance, MonoArray* elements)
@@ -142,8 +143,8 @@ namespace bs
 		listBox->setElementStates(states);
 	}
 
-	void ScriptGUIListBox::onSelectionChanged(MonoObject* instance, UINT32 index, bool enabled)
+	void ScriptGUIListBox::onSelectionChanged(UINT32 index, bool enabled)
 	{
-		MonoUtil::invokeThunk(onSelectionChangedThunk, instance, index);
+		MonoUtil::invokeThunk(onSelectionChangedThunk, getManagedInstance(), index);
 	}
 }

+ 2 - 2
Source/SBansheeEngine/Wrappers/GUI/BsScriptGUIListBox.h

@@ -12,7 +12,7 @@ namespace bs
 	 *  @{
 	 */
 
-	/**	Interop class between C++ & CLR for GUIListBox.  */
+	/**	Interop class between C++ & CLR for GUIListBox. */
 	class BS_SCR_BE_EXPORT ScriptGUIListBox : public TScriptGUIElement<ScriptGUIListBox>
 	{
 	public:
@@ -22,7 +22,7 @@ namespace bs
 		ScriptGUIListBox(MonoObject* instance, GUIListBox* listBox);
 
 		/**	Triggered when the selected index in the native list box changes. */
-		static void onSelectionChanged(MonoObject* instance, UINT32 index, bool enabled);
+		void onSelectionChanged(UINT32 index, bool enabled);
 
 		/************************************************************************/
 		/* 								CLR HOOKS						   		*/

+ 4 - 4
Source/SBansheeEngine/Wrappers/GUI/BsScriptGUIScrollBar.cpp

@@ -91,7 +91,7 @@ namespace bs
 
 	void ScriptGUIScrollBarH::onScroll(float position, float size)
 	{
-		MonoUtil::invokeThunk(onScrolledThunk, mManagedInstance, position);
+		MonoUtil::invokeThunk(onScrolledThunk, getManagedInstance(), position);
 	}
 
 	ScriptGUIScrollBarV::OnScrolledThunkDef ScriptGUIScrollBarV::onScrolledThunk;
@@ -126,7 +126,7 @@ namespace bs
 
 	void ScriptGUIScrollBarV::onScroll(float position, float size)
 	{
-		MonoUtil::invokeThunk(onScrolledThunk, mManagedInstance, position);
+		MonoUtil::invokeThunk(onScrolledThunk, getManagedInstance(), position);
 	}
 
 	ScriptGUIResizeableScrollBarH::OnScrollOrResizeThunkDef ScriptGUIResizeableScrollBarH::onScrollOrResizeThunk;
@@ -161,7 +161,7 @@ namespace bs
 
 	void ScriptGUIResizeableScrollBarH::onScroll(float position, float size)
 	{
-		MonoUtil::invokeThunk(onScrollOrResizeThunk, mManagedInstance, position, size);
+		MonoUtil::invokeThunk(onScrollOrResizeThunk, getManagedInstance(), position, size);
 	}
 
 	ScriptGUIResizeableScrollBarV::OnScrollOrResizeThunkDef ScriptGUIResizeableScrollBarV::onScrollOrResizeThunk;
@@ -196,6 +196,6 @@ namespace bs
 
 	void ScriptGUIResizeableScrollBarV::onScroll(float position, float size)
 	{
-		MonoUtil::invokeThunk(onScrollOrResizeThunk, mManagedInstance, position, size);
+		MonoUtil::invokeThunk(onScrollOrResizeThunk, getManagedInstance(), position, size);
 	}
 }

+ 8 - 8
Source/SBansheeEngine/Wrappers/GUI/BsScriptGUISlider.cpp

@@ -55,9 +55,9 @@ namespace bs
 			options.addOption(scriptArray.get<GUIOption>(i));
 
 		GUISliderHorz* guiSlider = GUISliderHorz::create(options, toString(MonoUtil::monoToWString(style)));
-		guiSlider->onChanged.connect(std::bind(&ScriptGUISliderH::onChanged, instance, _1));
 
-		new (bs_alloc<ScriptGUISliderH>()) ScriptGUISliderH(instance, guiSlider);
+		auto nativeInstance = new (bs_alloc<ScriptGUISliderH>()) ScriptGUISliderH(instance, guiSlider);
+		guiSlider->onChanged.connect(std::bind(&ScriptGUISliderH::onChanged, nativeInstance, _1));
 	}
 
 	void ScriptGUISliderH::internal_setPercent(ScriptGUISliderH* nativeInstance, float percent)
@@ -120,9 +120,9 @@ namespace bs
 		slider->setTint(*color);
 	}
 
-	void ScriptGUISliderH::onChanged(MonoObject* instance, float percent)
+	void ScriptGUISliderH::onChanged(float percent)
 	{
-		MonoUtil::invokeThunk(onChangedThunk, instance, percent);
+		MonoUtil::invokeThunk(onChangedThunk, getManagedInstance(), percent);
 	}
 
 	ScriptGUISliderV::OnChangedThunkDef ScriptGUISliderV::onChangedThunk;
@@ -160,9 +160,9 @@ namespace bs
 			options.addOption(scriptArray.get<GUIOption>(i));
 
 		GUISliderVert* guiSlider = GUISliderVert::create(options, toString(MonoUtil::monoToWString(style)));
-		guiSlider->onChanged.connect(std::bind(&ScriptGUISliderV::onChanged, instance, _1));
 
-		new (bs_alloc<ScriptGUISliderV>()) ScriptGUISliderV(instance, guiSlider);
+		auto nativeInstance = new (bs_alloc<ScriptGUISliderV>()) ScriptGUISliderV(instance, guiSlider);
+		guiSlider->onChanged.connect(std::bind(&ScriptGUISliderV::onChanged, nativeInstance, _1));
 	}
 
 	void ScriptGUISliderV::internal_setPercent(ScriptGUISliderV* nativeInstance, float percent)
@@ -225,8 +225,8 @@ namespace bs
 		slider->setTint(*color);
 	}
 
-	void ScriptGUISliderV::onChanged(MonoObject* instance, float percent)
+	void ScriptGUISliderV::onChanged(float percent)
 	{
-		MonoUtil::invokeThunk(onChangedThunk, instance, percent);
+		MonoUtil::invokeThunk(onChangedThunk, getManagedInstance(), percent);
 	}
 }

+ 2 - 2
Source/SBansheeEngine/Wrappers/GUI/BsScriptGUISlider.h

@@ -21,7 +21,7 @@ namespace bs
 		ScriptGUISliderH(MonoObject* instance, GUISliderHorz* slider);
 
 		/**	Triggered when the native slider is moved. */
-		static void onChanged(MonoObject* instance, float percent);
+		void onChanged(float percent);
 
 		/************************************************************************/
 		/* 								CLR HOOKS						   		*/
@@ -52,7 +52,7 @@ namespace bs
 		ScriptGUISliderV(MonoObject* instance, GUISliderVert* slider);
 
 		/**	Triggered when the native slider is moved. */
-		static void onChanged(MonoObject* instance, float percent);
+		void onChanged(float percent);
 
 		/************************************************************************/
 		/* 								CLR HOOKS						   		*/

+ 16 - 16
Source/SBansheeEngine/Wrappers/GUI/BsScriptGUIToggle.cpp

@@ -70,13 +70,13 @@ namespace bs
 		GUIContent nativeContent(ScriptGUIContent::getText(content), ScriptGUIContent::getImage(content), ScriptGUIContent::getTooltip(content));
 		GUIToggle* guiToggle = GUIToggle::create(nativeContent, toggleGroup, options, toString(MonoUtil::monoToWString(style)));
 
-		guiToggle->onClick.connect(std::bind(&ScriptGUIToggle::onClick, instance));
-		guiToggle->onHover.connect(std::bind(&ScriptGUIToggle::onHover, instance));
-		guiToggle->onOut.connect(std::bind(&ScriptGUIToggle::onOut, instance));
-		guiToggle->onToggled.connect(std::bind(&ScriptGUIToggle::onToggled, instance, std::placeholders::_1));
-		guiToggle->onDoubleClick.connect(std::bind(&ScriptGUIToggle::onDoubleClick, instance));
+		auto nativeInstance = new (bs_alloc<ScriptGUIToggle>()) ScriptGUIToggle(instance, guiToggle);
 
-		new (bs_alloc<ScriptGUIToggle>()) ScriptGUIToggle(instance, guiToggle);
+		guiToggle->onClick.connect(std::bind(&ScriptGUIToggle::onClick, nativeInstance));
+		guiToggle->onHover.connect(std::bind(&ScriptGUIToggle::onHover, nativeInstance));
+		guiToggle->onOut.connect(std::bind(&ScriptGUIToggle::onOut, nativeInstance));
+		guiToggle->onToggled.connect(std::bind(&ScriptGUIToggle::onToggled, nativeInstance, std::placeholders::_1));
+		guiToggle->onDoubleClick.connect(std::bind(&ScriptGUIToggle::onDoubleClick, nativeInstance));
 	}
 
 	void ScriptGUIToggle::internal_setContent(ScriptGUIToggle* nativeInstance, MonoObject* content)
@@ -109,28 +109,28 @@ namespace bs
 		toggle->setTint(*color);
 	}
 
-	void ScriptGUIToggle::onClick(MonoObject* instance)
+	void ScriptGUIToggle::onClick()
 	{
-		MonoUtil::invokeThunk(onClickThunk, instance);
+		MonoUtil::invokeThunk(onClickThunk, getManagedInstance());
 	}
 
-	void ScriptGUIToggle::onHover(MonoObject* instance)
+	void ScriptGUIToggle::onHover()
 	{
-		MonoUtil::invokeThunk(onHoverThunk, instance);
+		MonoUtil::invokeThunk(onHoverThunk, getManagedInstance());
 	}
 
-	void ScriptGUIToggle::onOut(MonoObject* instance)
+	void ScriptGUIToggle::onOut()
 	{
-		MonoUtil::invokeThunk(onOutThunk, instance);
+		MonoUtil::invokeThunk(onOutThunk, getManagedInstance());
 	}
 
-	void ScriptGUIToggle::onToggled(MonoObject* instance, bool toggled)
+	void ScriptGUIToggle::onToggled(bool toggled)
 	{
-		MonoUtil::invokeThunk(onToggledThunk, instance, toggled);
+		MonoUtil::invokeThunk(onToggledThunk, getManagedInstance(), toggled);
 	}
 
-	void ScriptGUIToggle::onDoubleClick(MonoObject* instance)
+	void ScriptGUIToggle::onDoubleClick()
 	{
-		MonoUtil::invokeThunk(onDoubleClickThunk, instance);
+		MonoUtil::invokeThunk(onDoubleClickThunk, getManagedInstance());
 	}
 }

+ 5 - 5
Source/SBansheeEngine/Wrappers/GUI/BsScriptGUIToggle.h

@@ -21,19 +21,19 @@ namespace bs
 		ScriptGUIToggle(MonoObject* instance, GUIToggle* toggle);
 
 		/**	Triggered when the native toggle button is clicked. */
-		static void onClick(MonoObject* instance);
+		void onClick();
 
 		/**	Triggered when the native toggle button is hover over. */
-		static void onHover(MonoObject* instance);
+		void onHover();
 
 		/**	Triggered when the pointer leaves the native toggle button. */
-		static void onOut(MonoObject* instance);
+		void onOut();
 
 		/**	Triggered when the native toggle button is toggled. */
-		static void onToggled(MonoObject* instance, bool toggled);
+		void onToggled(bool toggled);
 
 		/**	Triggers when the native toggle button is double-clicked. */
-		static void onDoubleClick(MonoObject* instance);
+		void onDoubleClick();
 
 		/************************************************************************/
 		/* 								CLR HOOKS						   		*/