Browse Source

Various bug fixes relating to new project loading system:
- Delayed project load so it triggers on the sim thread instead of the Mono thread
- Added background area for the recent projects list in Project Window
- On project unload close all editor widgets
- Project Window size is now initialized before attempting to retrieve GUI element bounds
- ScriptLibrary::reload now only performs assembly refresh if script assemblies were previously loaded, otherwise it just additively loads them
- Fixed a race condition due to compiler variable reordering when initializing core versions of certain systems
- Script interop GUI element objects are now properly deleted when their managed instance goes out of scope
- When inputting characters ignore special char symbols generated by ctrl+key presses
- Fixed an issue where during assembly refresh new script objects were being generated, breaking iterators
- Fixed invalid C++/CLR interop methods for HString
- Fixed static order initialization issue - project library internal path now holds the proper value

Marko Pintera 10 years ago
parent
commit
fedd162d57
34 changed files with 293 additions and 132 deletions
  1. 5 4
      BansheeCore/Source/Win32/BsWin32Platform.cpp
  2. 1 0
      BansheeEditor/Include/BsBuiltinEditorResources.h
  3. 0 2
      BansheeEditor/Include/BsEditorApplication.h
  4. 2 1
      BansheeEditor/Include/BsEditorPrerequisites.h
  5. 1 1
      BansheeEditor/Include/BsEditorWidgetLayout.h
  6. 5 0
      BansheeEditor/Include/BsEditorWidgetManager.h
  7. 1 1
      BansheeEditor/Include/BsGizmoManager.h
  8. 1 1
      BansheeEditor/Include/BsHandleDrawManager.h
  9. 1 1
      BansheeEditor/Include/BsSelectionRenderer.h
  10. 13 0
      BansheeEditor/Source/BsBuiltinEditorResources.cpp
  11. 4 3
      BansheeEditor/Source/BsEditorApplication.cpp
  12. 12 0
      BansheeEditor/Source/BsEditorWidgetManager.cpp
  13. 14 8
      BansheeEditor/Source/BsGizmoManager.cpp
  14. 6 4
      BansheeEditor/Source/BsHandleDrawManager.cpp
  15. 1 1
      BansheeEditor/Source/BsProjectLibrary.cpp
  16. 6 4
      BansheeEditor/Source/BsSelectionRenderer.cpp
  17. 40 33
      MBansheeEditor/EditorApplication.cs
  18. 1 0
      MBansheeEditor/EditorStyles.cs
  19. 22 6
      MBansheeEditor/ProjectWindow.cs
  20. 5 0
      SBansheeEditor/Include/BsEditorScriptLibrary.h
  21. 12 0
      SBansheeEditor/Include/BsScriptEditorApplication.h
  22. 53 15
      SBansheeEditor/Source/BsEditorScriptLibrary.cpp
  23. 2 0
      SBansheeEditor/Source/BsEditorScriptManager.cpp
  24. 23 2
      SBansheeEditor/Source/BsScriptEditorApplication.cpp
  25. 5 0
      SBansheeEngine/Include/BsEngineScriptLibrary.h
  26. 0 26
      SBansheeEngine/Include/BsScriptGUIElement.h
  27. 2 1
      SBansheeEngine/Include/BsScriptGUILayout.h
  28. 2 2
      SBansheeEngine/Include/BsScriptHString.h
  29. 26 5
      SBansheeEngine/Source/BsEngineScriptLibrary.cpp
  30. 2 0
      SBansheeEngine/Source/BsScriptGUIElement.cpp
  31. 5 4
      SBansheeEngine/Source/BsScriptGUILayout.cpp
  32. 4 4
      SBansheeEngine/Source/BsScriptHString.cpp
  33. 8 1
      SBansheeEngine/Source/BsScriptObjectManager.cpp
  34. 8 2
      TODO.txt

+ 5 - 4
BansheeCore/Source/Win32/BsWin32Platform.cpp

@@ -1083,13 +1083,14 @@ namespace BansheeEngine
 			{
 			{
 				// TODO - Not handling IME input
 				// TODO - Not handling IME input
 
 
+				// Ignore rarely used special command characters, usually triggered by ctrl+key
+				// combinations. (We want to keep ctrl+key free for shortcuts instead)
+				if (wParam <= 23)
+					break;
+
 				switch (wParam) 
 				switch (wParam) 
 				{ 
 				{ 
-				case VK_BACK:
-				case 0x0A:  // linefeed 
-				case 0x0D:  // carriage return 
 				case VK_ESCAPE:
 				case VK_ESCAPE:
-				case VK_TAB: 
 					break; 
 					break; 
 				default:    // displayable character 
 				default:    // displayable character 
 					{
 					{

+ 1 - 0
BansheeEditor/Include/BsBuiltinEditorResources.h

@@ -341,6 +341,7 @@ namespace BansheeEngine
 		static const WString XButtonHoverTex;
 		static const WString XButtonHoverTex;
 
 
 		static const WString StatusBarBgTex;
 		static const WString StatusBarBgTex;
+		static const WString ScrollAreaBgTex;
 
 
 		static const WString ShaderDockOverlayFile;
 		static const WString ShaderDockOverlayFile;
 		static const WString ShaderSceneGridFile;
 		static const WString ShaderSceneGridFile;

+ 0 - 2
BansheeEditor/Include/BsEditorApplication.h

@@ -104,8 +104,6 @@ namespace BansheeEngine
 		 * @param	path	Absolute path to the root project folder.
 		 * @param	path	Absolute path to the root project folder.
 		 */
 		 */
 		bool isValidProjectPath(const Path& path);
 		bool isValidProjectPath(const Path& path);
-
-		static const Path PROJECT_INTERNAL_DIR;
 	private:
 	private:
 		/**
 		/**
 		 * @copydoc	Module::onStartUp
 		 * @copydoc	Module::onStartUp

+ 2 - 1
BansheeEditor/Include/BsEditorPrerequisites.h

@@ -77,7 +77,8 @@ namespace BansheeEngine
 
 
 	static const char* EDITOR_ASSEMBLY = "MBansheeEditor";
 	static const char* EDITOR_ASSEMBLY = "MBansheeEditor";
 	static const char* SCRIPT_EDITOR_ASSEMBLY = "MScriptEditor";
 	static const char* SCRIPT_EDITOR_ASSEMBLY = "MScriptEditor";
-	static const Path INTERNAL_ASSEMBLY_PATH = "Internal//Assemblies//";
+	static const Path PROJECT_INTERNAL_DIR = L"Internal\\";
+	static const Path INTERNAL_ASSEMBLY_PATH = PROJECT_INTERNAL_DIR + "Assemblies\\";
 
 
 	/**
 	/**
 	 * @brief	Types of drag and drop operations. Different types specify
 	 * @brief	Types of drag and drop operations. Different types specify

+ 1 - 1
BansheeEditor/Include/BsEditorWidgetLayout.h

@@ -68,6 +68,6 @@ namespace BansheeEngine
 	public:
 	public:
 		friend class EditorWidgetLayoutRTTI;
 		friend class EditorWidgetLayoutRTTI;
 		static RTTITypeBase* getRTTIStatic();
 		static RTTITypeBase* getRTTIStatic();
-		virtual RTTITypeBase* getRTTI() const;	
+		virtual RTTITypeBase* getRTTI() const override;	
 	};
 	};
 }
 }

+ 5 - 0
BansheeEditor/Include/BsEditorWidgetManager.h

@@ -61,6 +61,11 @@ namespace BansheeEngine
 		 */
 		 */
 		void close(EditorWidgetBase* widget);
 		void close(EditorWidgetBase* widget);
 
 
+		/**
+		 * @brief	Closes all open editor widgets.
+		 */
+		void closeAll();
+
 		/**
 		/**
 		 * @brief	Retrieves the layout of all currently active widgets. You may later
 		 * @brief	Retrieves the layout of all currently active widgets. You may later
 		 * 			use this layout to restore exact position of the widgets.
 		 * 			use this layout to restore exact position of the widgets.

+ 1 - 1
BansheeEditor/Include/BsGizmoManager.h

@@ -339,7 +339,7 @@ namespace BansheeEngine
 
 
 		TransientMeshPtr mIconMesh;
 		TransientMeshPtr mIconMesh;
 
 
-		GizmoManagerCore* mCore;
+		std::atomic<GizmoManagerCore*> mCore;
 
 
 		// Immutable
 		// Immutable
 		VertexDataDescPtr mIconVertexDesc;
 		VertexDataDescPtr mIconVertexDesc;

+ 1 - 1
BansheeEditor/Include/BsHandleDrawManager.h

@@ -166,7 +166,7 @@ namespace BansheeEngine
 		static const UINT32 ARC_QUALITY;
 		static const UINT32 ARC_QUALITY;
 
 
 		Matrix4 mTransform;
 		Matrix4 mTransform;
-		HandleDrawManagerCore* mCore;
+		std::atomic<HandleDrawManagerCore*> mCore;
 		DrawHelper* mDrawHelper;
 		DrawHelper* mDrawHelper;
 	};
 	};
 
 

+ 1 - 1
BansheeEditor/Include/BsSelectionRenderer.h

@@ -51,7 +51,7 @@ namespace BansheeEngine
 		 */
 		 */
 		void destroyCore(SelectionRendererCore* core);
 		void destroyCore(SelectionRendererCore* core);
 
 
-		SelectionRendererCore* mCore;
+		std::atomic<SelectionRendererCore*> mCore;
 	};
 	};
 
 
 	/**
 	/**

+ 13 - 0
BansheeEditor/Source/BsBuiltinEditorResources.cpp

@@ -231,6 +231,7 @@ namespace BansheeEngine
 	const WString BuiltinEditorResources::XButtonHoverTex = L"XBtnHover.psd";
 	const WString BuiltinEditorResources::XButtonHoverTex = L"XBtnHover.psd";
 
 
 	const WString BuiltinEditorResources::StatusBarBgTex = L"StatusBarBg.psd";
 	const WString BuiltinEditorResources::StatusBarBgTex = L"StatusBarBg.psd";
+	const WString BuiltinEditorResources::ScrollAreaBgTex = L"ScrollAreaBg.png";
 
 
 	/************************************************************************/
 	/************************************************************************/
 	/* 									SHADERS                      		*/
 	/* 									SHADERS                      		*/
@@ -1406,6 +1407,18 @@ namespace BansheeEngine
 
 
 		skin->setStyle("SelectableLabel", selectableLabelStyle);
 		skin->setStyle("SelectableLabel", selectableLabelStyle);
 
 
+		// Scroll area background
+		GUIElementStyle scrollAreaBg;
+		scrollAreaBg.normal.texture = getGUITexture(ScrollAreaBgTex);
+		scrollAreaBg.minHeight = 6;
+		scrollAreaBg.minWidth = 4;
+		scrollAreaBg.border.left = 2;
+		scrollAreaBg.border.right = 2;
+		scrollAreaBg.border.top = 2;
+		scrollAreaBg.border.bottom = 4;
+		
+		skin->setStyle("ScrollAreaBg", scrollAreaBg);
+
 		return skin;
 		return skin;
 	}
 	}
 
 

+ 4 - 3
BansheeEditor/Source/BsEditorApplication.cpp

@@ -49,7 +49,6 @@
 
 
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
-	const Path EditorApplication::PROJECT_INTERNAL_DIR = L"Internal\\";
 	const Path EditorApplication::WIDGET_LAYOUT_PATH = PROJECT_INTERNAL_DIR + L"Layout.asset";
 	const Path EditorApplication::WIDGET_LAYOUT_PATH = PROJECT_INTERNAL_DIR + L"Layout.asset";
 	const Path EditorApplication::BUILD_DATA_PATH = PROJECT_INTERNAL_DIR + L"BuildData.asset";
 	const Path EditorApplication::BUILD_DATA_PATH = PROJECT_INTERNAL_DIR + L"BuildData.asset";
 	const Path EditorApplication::EDITOR_SETTINGS_PATH = RUNTIME_DATA_PATH + L"Settings.asset";
 	const Path EditorApplication::EDITOR_SETTINGS_PATH = RUNTIME_DATA_PATH + L"Settings.asset";
@@ -304,6 +303,7 @@ namespace BansheeEngine
 		BuildManager::instance().clear();
 		BuildManager::instance().clear();
 		UndoRedo::instance().clear();
 		UndoRedo::instance().clear();
 
 
+		EditorWidgetManager::instance().closeAll();
 		ProjectLibrary::instance().unloadLibrary();
 		ProjectLibrary::instance().unloadLibrary();
 		Resources::instance().unloadAllUnused();
 		Resources::instance().unloadAllUnused();
 	}
 	}
@@ -318,13 +318,14 @@ namespace BansheeEngine
 
 
 		loadProjectSettings();
 		loadProjectSettings();
 		BuildManager::instance().load(BUILD_DATA_PATH);
 		BuildManager::instance().load(BUILD_DATA_PATH);
+
+		// Do this before restoring windows and loading library to ensure types are loaded
+		ScriptManager::instance().reload();
 		ProjectLibrary::instance().loadLibrary();
 		ProjectLibrary::instance().loadLibrary();
 
 
 		EditorWidgetLayoutPtr layout = loadWidgetLayout();
 		EditorWidgetLayoutPtr layout = loadWidgetLayout();
 		if (layout != nullptr)
 		if (layout != nullptr)
 			EditorWidgetManager::instance().setLayout(layout);
 			EditorWidgetManager::instance().setLayout(layout);
-
-		ScriptManager::instance().reload();
 	}
 	}
 
 
 	void EditorApplication::createProject(const Path& path)
 	void EditorApplication::createProject(const Path& path)

+ 12 - 0
BansheeEditor/Source/BsEditorWidgetManager.cpp

@@ -134,6 +134,18 @@ namespace BansheeEngine
 		EditorWidgetBase::destroy(widget);
 		EditorWidgetBase::destroy(widget);
 	}
 	}
 
 
+	void EditorWidgetManager::closeAll()
+	{
+		Vector<EditorWidgetBase*> toClose(mActiveWidgets.size());
+
+		UINT32 idx = 0;
+		for (auto& widget : mActiveWidgets)
+			toClose[idx++] = widget.second;
+
+		for (auto& widget : toClose)
+			widget->close();
+	}
+
 	EditorWidgetBase* EditorWidgetManager::create(const String& name, EditorWidgetContainer& parentContainer)
 	EditorWidgetBase* EditorWidgetManager::create(const String& name, EditorWidgetContainer& parentContainer)
 	{
 	{
 		auto iterFind = mActiveWidgets.find(name);
 		auto iterFind = mActiveWidgets.find(name);

+ 14 - 8
BansheeEditor/Source/BsGizmoManager.cpp

@@ -58,7 +58,7 @@ namespace BansheeEngine
 		initData.pickingMat = pickingMaterial->getCore();
 		initData.pickingMat = pickingMaterial->getCore();
 		initData.alphaPickingMat = alphaPickingMaterial->getCore();
 		initData.alphaPickingMat = alphaPickingMaterial->getCore();
 
 
-		mCore = bs_new<GizmoManagerCore>(GizmoManagerCore::PrivatelyConstuct());
+		mCore.store(bs_new<GizmoManagerCore>(GizmoManagerCore::PrivatelyConstuct()), std::memory_order_release);
 
 
 		gCoreAccessor().queueCommand(std::bind(&GizmoManager::initializeCore, this, initData));
 		gCoreAccessor().queueCommand(std::bind(&GizmoManager::initializeCore, this, initData));
 	}
 	}
@@ -71,12 +71,12 @@ namespace BansheeEngine
 		bs_delete(mDrawHelper);
 		bs_delete(mDrawHelper);
 		bs_delete(mPickingDrawHelper);
 		bs_delete(mPickingDrawHelper);
 
 
-		gCoreAccessor().queueCommand(std::bind(&GizmoManager::destroyCore, this, mCore));
+		gCoreAccessor().queueCommand(std::bind(&GizmoManager::destroyCore, this, mCore.load(std::memory_order_relaxed)));
 	}
 	}
 
 
 	void GizmoManager::initializeCore(const CoreInitData& initData)
 	void GizmoManager::initializeCore(const CoreInitData& initData)
 	{
 	{
-		mCore->initialize(initData);
+		mCore.load(std::memory_order_acquire)->initialize(initData);
 	}
 	}
 
 
 	void GizmoManager::destroyCore(GizmoManagerCore* core)
 	void GizmoManager::destroyCore(GizmoManagerCore* core)
@@ -263,7 +263,9 @@ namespace BansheeEngine
 		mIconMesh = buildIconMesh(camera, mIconData, false, iconRenderData);
 		mIconMesh = buildIconMesh(camera, mIconData, false, iconRenderData);
 		SPtr<MeshCoreBase> iconMesh = mIconMesh->getCore();
 		SPtr<MeshCoreBase> iconMesh = mIconMesh->getCore();
 
 
-		gCoreAccessor().queueCommand(std::bind(&GizmoManagerCore::updateData, mCore, camera->getCore(),
+		GizmoManagerCore* core = mCore.load(std::memory_order_relaxed);
+
+		gCoreAccessor().queueCommand(std::bind(&GizmoManagerCore::updateData, core, camera->getCore(),
 			solidMesh, wireMesh, iconMesh, iconRenderData));
 			solidMesh, wireMesh, iconMesh, iconRenderData));
 	}
 	}
 
 
@@ -360,24 +362,26 @@ namespace BansheeEngine
 		Matrix4 projMat = camera->getProjectionMatrixRS();
 		Matrix4 projMat = camera->getProjectionMatrixRS();
 		ViewportPtr viewport = camera->getViewport();
 		ViewportPtr viewport = camera->getViewport();
 
 
+		GizmoManagerCore* core = mCore.load(std::memory_order_relaxed);
+
 		for (auto& meshData : meshes)
 		for (auto& meshData : meshes)
 		{
 		{
 			if (meshData.type == DrawHelper::MeshType::Solid)
 			if (meshData.type == DrawHelper::MeshType::Solid)
 			{
 			{
 				gCoreAccessor().queueCommand(std::bind(&GizmoManagerCore::renderGizmos,
 				gCoreAccessor().queueCommand(std::bind(&GizmoManagerCore::renderGizmos,
-					mCore, viewMat, projMat, camera->getForward(), meshData.mesh->getCore(), GizmoMaterial::Picking));
+					core, viewMat, projMat, camera->getForward(), meshData.mesh->getCore(), GizmoMaterial::Picking));
 			}
 			}
 			else // Wire
 			else // Wire
 			{
 			{
 				gCoreAccessor().queueCommand(std::bind(&GizmoManagerCore::renderGizmos,
 				gCoreAccessor().queueCommand(std::bind(&GizmoManagerCore::renderGizmos,
-					mCore, viewMat, projMat, camera->getForward(), meshData.mesh->getCore(), GizmoMaterial::Picking));
+					core, viewMat, projMat, camera->getForward(), meshData.mesh->getCore(), GizmoMaterial::Picking));
 			}
 			}
 		}
 		}
 
 
 		Rect2I screenArea = camera->getViewport()->getArea();
 		Rect2I screenArea = camera->getViewport()->getArea();
 
 
 		gCoreAccessor().queueCommand(std::bind(&GizmoManagerCore::renderIconGizmos,
 		gCoreAccessor().queueCommand(std::bind(&GizmoManagerCore::renderIconGizmos,
-			mCore, screenArea, iconMesh->getCore(), iconRenderData, true));
+			core, screenArea, iconMesh->getCore(), iconRenderData, true));
 
 
 		mPickingDrawHelper->clearMeshes();
 		mPickingDrawHelper->clearMeshes();
 		mIconMeshHeap->dealloc(iconMesh);
 		mIconMeshHeap->dealloc(iconMesh);
@@ -408,8 +412,10 @@ namespace BansheeEngine
 
 
 		mIconMesh = nullptr;
 		mIconMesh = nullptr;
 
 
+		GizmoManagerCore* core = mCore.load(std::memory_order_relaxed);
 		IconRenderDataVecPtr iconRenderData = bs_shared_ptr_new<IconRenderDataVec>();
 		IconRenderDataVecPtr iconRenderData = bs_shared_ptr_new<IconRenderDataVec>();
-		gCoreAccessor().queueCommand(std::bind(&GizmoManagerCore::updateData, mCore, nullptr, nullptr, nullptr, nullptr, iconRenderData));
+		
+		gCoreAccessor().queueCommand(std::bind(&GizmoManagerCore::updateData, core, nullptr, nullptr, nullptr, nullptr, iconRenderData));
 	}
 	}
 
 
 	TransientMeshPtr GizmoManager::buildIconMesh(const CameraHandlerPtr& camera, const Vector<IconData>& iconData,
 	TransientMeshPtr GizmoManager::buildIconMesh(const CameraHandlerPtr& camera, const Vector<IconData>& iconData,

+ 6 - 4
BansheeEditor/Source/BsHandleDrawManager.cpp

@@ -29,7 +29,7 @@ namespace BansheeEngine
 		SPtr<MaterialCore> solidMaterialProxy = solidMaterial->getCore();
 		SPtr<MaterialCore> solidMaterialProxy = solidMaterial->getCore();
 		SPtr<MaterialCore> wireMaterialProxy = wireMaterial->getCore();
 		SPtr<MaterialCore> wireMaterialProxy = wireMaterial->getCore();
 
 
-		mCore = bs_new<HandleDrawManagerCore>(HandleDrawManagerCore::PrivatelyConstruct());
+		mCore.store(bs_new<HandleDrawManagerCore>(HandleDrawManagerCore::PrivatelyConstruct()), std::memory_order_release);
 
 
 		gCoreAccessor().queueCommand(std::bind(&HandleDrawManager::initializeCore, this, wireMaterialProxy, solidMaterialProxy));
 		gCoreAccessor().queueCommand(std::bind(&HandleDrawManager::initializeCore, this, wireMaterialProxy, solidMaterialProxy));
 	}
 	}
@@ -38,14 +38,14 @@ namespace BansheeEngine
 	{
 	{
 		bs_delete(mDrawHelper);
 		bs_delete(mDrawHelper);
 
 
-		gCoreAccessor().queueCommand(std::bind(&HandleDrawManager::destroyCore, this, mCore));
+		gCoreAccessor().queueCommand(std::bind(&HandleDrawManager::destroyCore, this, mCore.load(std::memory_order_relaxed)));
 	}
 	}
 
 
 	void HandleDrawManager::initializeCore(const SPtr<MaterialCore>& wireMat, const SPtr<MaterialCore>& solidMat)
 	void HandleDrawManager::initializeCore(const SPtr<MaterialCore>& wireMat, const SPtr<MaterialCore>& solidMat)
 	{
 	{
 		THROW_IF_NOT_CORE_THREAD;
 		THROW_IF_NOT_CORE_THREAD;
 
 
-		mCore->initialize(wireMat, solidMat);
+		mCore.load(std::memory_order_acquire)->initialize(wireMat, solidMat);
 	}
 	}
 
 
 	void HandleDrawManager::destroyCore(HandleDrawManagerCore* core)
 	void HandleDrawManager::destroyCore(HandleDrawManagerCore* core)
@@ -175,7 +175,9 @@ namespace BansheeEngine
 			}
 			}
 		}
 		}
 
 
-		gCoreAccessor().queueCommand(std::bind(&HandleDrawManagerCore::updateData, mCore, 
+		HandleDrawManagerCore* core = mCore.load(std::memory_order_relaxed);
+
+		gCoreAccessor().queueCommand(std::bind(&HandleDrawManagerCore::updateData, core,
 			camera->getCore(), proxyData));
 			camera->getCore(), proxyData));
 
 
 		mDrawHelper->clear();
 		mDrawHelper->clear();

+ 1 - 1
BansheeEditor/Source/BsProjectLibrary.cpp

@@ -22,7 +22,7 @@ using namespace std::placeholders;
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
 	const Path ProjectLibrary::RESOURCES_DIR = L"Resources\\";
 	const Path ProjectLibrary::RESOURCES_DIR = L"Resources\\";
-	const Path ProjectLibrary::INTERNAL_RESOURCES_DIR = EditorApplication::PROJECT_INTERNAL_DIR + L"Resources\\";
+	const Path ProjectLibrary::INTERNAL_RESOURCES_DIR = PROJECT_INTERNAL_DIR + L"Resources\\";
 	const WString ProjectLibrary::LIBRARY_ENTRIES_FILENAME = L"ProjectLibrary.asset";
 	const WString ProjectLibrary::LIBRARY_ENTRIES_FILENAME = L"ProjectLibrary.asset";
 	const WString ProjectLibrary::RESOURCE_MANIFEST_FILENAME = L"ResourceManifest.asset";
 	const WString ProjectLibrary::RESOURCE_MANIFEST_FILENAME = L"ResourceManifest.asset";
 
 

+ 6 - 4
BansheeEditor/Source/BsSelectionRenderer.cpp

@@ -22,18 +22,19 @@ namespace BansheeEngine
 	{
 	{
 		HMaterial selectionMat = BuiltinEditorResources::instance().createSelectionMat();
 		HMaterial selectionMat = BuiltinEditorResources::instance().createSelectionMat();
 			
 			
-		mCore = bs_new<SelectionRendererCore>(SelectionRendererCore::PrivatelyConstuct());
+		mCore.store(bs_new<SelectionRendererCore>(SelectionRendererCore::PrivatelyConstuct()), std::memory_order_release);
+
 		gCoreAccessor().queueCommand(std::bind(&SelectionRenderer::initializeCore, this, selectionMat->getCore()));;
 		gCoreAccessor().queueCommand(std::bind(&SelectionRenderer::initializeCore, this, selectionMat->getCore()));;
 	}
 	}
 
 
 	SelectionRenderer::~SelectionRenderer()
 	SelectionRenderer::~SelectionRenderer()
 	{
 	{
-		gCoreAccessor().queueCommand(std::bind(&SelectionRenderer::destroyCore, this, mCore));
+		gCoreAccessor().queueCommand(std::bind(&SelectionRenderer::destroyCore, this, mCore.load(std::memory_order_relaxed)));
 	}
 	}
 
 
 	void SelectionRenderer::initializeCore(const SPtr<MaterialCore>& initData)
 	void SelectionRenderer::initializeCore(const SPtr<MaterialCore>& initData)
 	{
 	{
-		mCore->initialize(initData);
+		mCore.load(std::memory_order_acquire)->initialize(initData);
 	}
 	}
 
 
 	void SelectionRenderer::destroyCore(SelectionRendererCore* core)
 	void SelectionRenderer::destroyCore(SelectionRendererCore* core)
@@ -59,7 +60,8 @@ namespace BansheeEngine
 			}
 			}
 		}
 		}
 
 
-		gCoreAccessor().queueCommand(std::bind(&SelectionRendererCore::updateData, mCore, camera->getCore(), objects));
+		SelectionRendererCore* core = mCore.load(std::memory_order_relaxed);
+		gCoreAccessor().queueCommand(std::bind(&SelectionRendererCore::updateData, core, camera->getCore(), objects));
 	}
 	}
 
 
 	const Color SelectionRendererCore::SELECTION_COLOR = Color(1.0f, 1.0f, 1.0f, 0.3f);
 	const Color SelectionRendererCore::SELECTION_COLOR = Color(1.0f, 1.0f, 1.0f, 0.3f);

+ 40 - 33
MBansheeEditor/EditorApplication.cs

@@ -110,9 +110,6 @@ namespace BansheeEditor
                 if (Internal_IsValidProject(projectPath))
                 if (Internal_IsValidProject(projectPath))
                     LoadProject(projectPath);
                     LoadProject(projectPath);
             }
             }
-
-            if (!IsProjectLoaded)
-                ProjectWindow.Open();
         }
         }
 
 
         private static void OnAssetModified(string path)
         private static void OnAssetModified(string path)
@@ -244,69 +241,79 @@ namespace BansheeEditor
             Internal_SaveProject();
             Internal_SaveProject();
         }
         }
 
 
+        // Note: Async, runs next frame
         public static void LoadProject(string path)
         public static void LoadProject(string path)
         {
         {
             if (IsProjectLoaded && path == ProjectPath)
             if (IsProjectLoaded && path == ProjectPath)
                 return;
                 return;
 
 
-            if (Internal_IsValidProject(path))
+            if (!Internal_IsValidProject(path))
             {
             {
                 Debug.LogWarning("Provided path: \"" + path + "\" is not a valid project.");
                 Debug.LogWarning("Provided path: \"" + path + "\" is not a valid project.");
                 return;
                 return;
             }
             }
 
 
             if (IsProjectLoaded)
             if (IsProjectLoaded)
+            {
+                SaveProject();
                 UnloadProject();
                 UnloadProject();
+            }
 
 
-            Internal_LoadProject(path);
+            Internal_LoadProject(path); // Triggers OnProjectLoaded when done
+        }
 
 
-            if (IsProjectLoaded)
+        private static void OnProjectLoaded()
+        {
+            if (!IsProjectLoaded)
             {
             {
-                RecentProject[] recentProjects = EditorSettings.RecentProjects;
-                bool foundPath = false;
-                for (int i = 0; i < recentProjects.Length; i++)
-                {
-                    if (PathEx.Compare(recentProjects[i].path, path))
-                    {
-                        recentProjects[i].accessTimestamp = (ulong)DateTime.Now.Ticks;
-                        EditorSettings.RecentProjects = recentProjects;
-                        foundPath = true;
-                        break;
-                    }
-                }
+                ProjectWindow.Open();
+                return;
+            }
+
+            string projectPath = ProjectPath;
 
 
-                if (!foundPath)
+            RecentProject[] recentProjects = EditorSettings.RecentProjects;
+            bool foundPath = false;
+            for (int i = 0; i < recentProjects.Length; i++)
+            {
+                if (PathEx.Compare(recentProjects[i].path, projectPath))
                 {
                 {
-                    List<RecentProject> extendedRecentProjects = new List<RecentProject>();
-                    extendedRecentProjects.AddRange(recentProjects);
+                    recentProjects[i].accessTimestamp = (ulong)DateTime.Now.Ticks;
+                    EditorSettings.RecentProjects = recentProjects;
+                    foundPath = true;
+                    break;
+                }
+            }
 
 
-                    RecentProject newProject = new RecentProject();
-                    newProject.path = path;
-                    newProject.accessTimestamp = (ulong) DateTime.Now.Ticks;
+            if (!foundPath)
+            {
+                List<RecentProject> extendedRecentProjects = new List<RecentProject>();
+                extendedRecentProjects.AddRange(recentProjects);
 
 
-                    extendedRecentProjects.Add(newProject);
+                RecentProject newProject = new RecentProject();
+                newProject.path = projectPath;
+                newProject.accessTimestamp = (ulong)DateTime.Now.Ticks;
 
 
-                    EditorSettings.RecentProjects = extendedRecentProjects.ToArray();
-                }
+                extendedRecentProjects.Add(newProject);
 
 
-                EditorSettings.LastOpenProject = ProjectPath;
-                EditorSettings.Save();
+                EditorSettings.RecentProjects = extendedRecentProjects.ToArray();
             }
             }
 
 
+            EditorSettings.LastOpenProject = projectPath;
+            EditorSettings.Save();
+
             ProjectLibrary.Refresh();
             ProjectLibrary.Refresh();
             monitor = new FolderMonitor(ProjectLibrary.ResourceFolder);
             monitor = new FolderMonitor(ProjectLibrary.ResourceFolder);
             monitor.OnAdded += OnAssetModified;
             monitor.OnAdded += OnAssetModified;
             monitor.OnRemoved += OnAssetModified;
             monitor.OnRemoved += OnAssetModified;
             monitor.OnModified += OnAssetModified;
             monitor.OnModified += OnAssetModified;
 
 
-            if(!string.IsNullOrWhiteSpace(ProjectSettings.LastOpenScene))
+            if (!string.IsNullOrWhiteSpace(ProjectSettings.LastOpenScene))
                 Scene.Load(ProjectSettings.LastOpenScene);
                 Scene.Load(ProjectSettings.LastOpenScene);
         }
         }
 
 
-        public static void UnloadProject()
+        private static void UnloadProject()
         {
         {
-            // TODO - Save dirty assets
-
             Action continueUnload =
             Action continueUnload =
                 () =>
                 () =>
                 {
                 {

+ 1 - 0
MBansheeEditor/EditorStyles.cs

@@ -20,5 +20,6 @@ namespace BansheeEditor
         public const string ColorSlider2DHandle = "ColorSlider2DHandle";
         public const string ColorSlider2DHandle = "ColorSlider2DHandle";
         public const string SelectionArea = "SelectionArea";
         public const string SelectionArea = "SelectionArea";
         public const string SelectableLabel = "SelectableLabel";
         public const string SelectableLabel = "SelectableLabel";
+        public const string ScrollAreaBg = "ScrollAreaBg";
     }
     }
 }
 }

+ 22 - 6
MBansheeEditor/ProjectWindow.cs

@@ -22,16 +22,18 @@ namespace BansheeEditor
         protected ProjectWindow()
         protected ProjectWindow()
             : base(false)
             : base(false)
         {
         {
-            Title = "Project Manager";
 
 
-            Width = 500;
-            Height = 250;
         }
         }
 
 
         private void OnInitialize()
         private void OnInitialize()
         {
         {
-            GUILayout vertLayout = GUI.AddLayoutY();
+            Title = "Project Manager";
 
 
+            Width = 500;
+            Height = 250;
+
+            GUILayout vertLayout = GUI.AddLayoutY();
+            
             vertLayout.AddSpace(5);
             vertLayout.AddSpace(5);
             GUILayout firstRow = vertLayout.AddLayoutX();
             GUILayout firstRow = vertLayout.AddLayoutX();
             vertLayout.AddFlexibleSpace();
             vertLayout.AddFlexibleSpace();
@@ -87,6 +89,20 @@ namespace BansheeEditor
             fourthRow.AddSpace(5);
             fourthRow.AddSpace(5);
 
 
             RefreshRecentProjects();
             RefreshRecentProjects();
+
+            // Add scroll area background
+            GUIPanel scrollAreaBgPanel = GUI.AddPanel(1);
+
+            GUITexture scrollAreaBgTex = new GUITexture(null, true, EditorStyles.ScrollAreaBg);
+            scrollAreaBgPanel.AddElement(scrollAreaBgTex);
+
+            Rect2I bounds = vertLayout.Bounds;
+            Rect2I scrollAreaBounds = recentProjectsArea.Bounds;
+            Debug.Log(scrollAreaBounds + " - " + vertLayout.Bounds);
+            scrollAreaBounds.y += bounds.y;
+            scrollAreaBounds.height += 2;
+
+            scrollAreaBgTex.Bounds = scrollAreaBounds;
         }
         }
 
 
         void OpenProject()
         void OpenProject()
@@ -127,8 +143,8 @@ namespace BansheeEditor
                 }
                 }
 
 
                 // Warn user
                 // Warn user
-                LocString message = new LocEdString("Provided project path \"") + projectPath +
-                                    new LocEdString("\" doesn't contain a valid project.");
+                LocString message = new LocEdString("Provided project path \"{0}\" doesn't contain a valid project.");
+                message.setParameter(0, projectPath);
 
 
                 DialogBox.Open(new LocEdString("Error"), message, DialogBox.Type.OK);
                 DialogBox.Open(new LocEdString("Error"), message, DialogBox.Type.OK);
             }
             }

+ 5 - 0
SBansheeEditor/Include/BsEditorScriptLibrary.h

@@ -12,6 +12,8 @@ namespace BansheeEngine
 	class BS_SCR_BED_EXPORT EditorScriptLibrary : public EngineScriptLibrary
 	class BS_SCR_BED_EXPORT EditorScriptLibrary : public EngineScriptLibrary
 	{
 	{
 	public:
 	public:
+		EditorScriptLibrary();
+
 		/**
 		/**
 		 * @copydoc	ScriptLibrary::initialize
 		 * @copydoc	ScriptLibrary::initialize
 		 */
 		 */
@@ -26,5 +28,8 @@ namespace BansheeEngine
 		 * @copydoc	ScriptLibrary::destroy
 		 * @copydoc	ScriptLibrary::destroy
 		 */
 		 */
 		void destroy() override;
 		void destroy() override;
+
+	private:
+		bool mScriptAssembliesLoaded;
 	};
 	};
 }
 }

+ 12 - 0
SBansheeEditor/Include/BsScriptEditorApplication.h

@@ -13,9 +13,17 @@ namespace BansheeEngine
 	public:
 	public:
 		SCRIPT_OBJ(EDITOR_ASSEMBLY, "BansheeEditor", "EditorApplication")
 		SCRIPT_OBJ(EDITOR_ASSEMBLY, "BansheeEditor", "EditorApplication")
 
 
+		/**
+		 * @brief	Called every frame. Triggers delayed project load.
+		 */
+		 static void update();
+
 	private:
 	private:
 		ScriptEditorApplication(MonoObject* instance);
 		ScriptEditorApplication(MonoObject* instance);
 
 
+		static bool mRequestProjectLoad;
+		static Path mProjectLoadPath;
+
 		/************************************************************************/
 		/************************************************************************/
 		/* 								CLR HOOKS						   		*/
 		/* 								CLR HOOKS						   		*/
 		/************************************************************************/
 		/************************************************************************/
@@ -36,5 +44,9 @@ namespace BansheeEngine
 		static void internal_LoadProject(MonoString* path);
 		static void internal_LoadProject(MonoString* path);
 		static void internal_UnloadProject();
 		static void internal_UnloadProject();
 		static void internal_CreateProject(MonoString* path);
 		static void internal_CreateProject(MonoString* path);
+
+		typedef void(__stdcall *OnProjectLoadedThunkDef)(MonoException**);
+
+		static OnProjectLoadedThunkDef onProjectLoadedThunk;
 	};
 	};
 }
 }

+ 53 - 15
SBansheeEditor/Source/BsEditorScriptLibrary.cpp

@@ -3,9 +3,16 @@
 #include "BsEditorApplication.h"
 #include "BsEditorApplication.h"
 #include "BsScriptObjectManager.h"
 #include "BsScriptObjectManager.h"
 #include "BsFileSystem.h"
 #include "BsFileSystem.h"
+#include "BsMonoManager.h"
+#include "BsScriptAssemblyManager.h"
+#include "BsMonoAssembly.h"
 
 
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
+	EditorScriptLibrary::EditorScriptLibrary()
+		:mScriptAssembliesLoaded(false)
+	{ }
+
 	void EditorScriptLibrary::initialize()
 	void EditorScriptLibrary::initialize()
 	{
 	{
 		EngineScriptLibrary::initialize();
 		EngineScriptLibrary::initialize();
@@ -15,29 +22,60 @@ namespace BansheeEngine
 
 
 	void EditorScriptLibrary::reload()
 	void EditorScriptLibrary::reload()
 	{
 	{
-		Vector<std::pair<String, Path>> assemblies;
-
 		Path engineAssemblyPath = gApplication().getEngineAssemblyPath();
 		Path engineAssemblyPath = gApplication().getEngineAssemblyPath();
-		assemblies.push_back({ ENGINE_ASSEMBLY, engineAssemblyPath });
+		Path gameAssemblyPath = gApplication().getGameAssemblyPath();
+
+		Path editorAssemblyPath = gEditorApplication().getEditorAssemblyPath();
+		Path editorScriptAssemblyPath = gEditorApplication().getEditorScriptAssemblyPath();
+
+#if BS_DEBUG_MODE
+		mScriptAssembliesLoaded = true; // Force assembly refresh as an ad hoc unit test in debug mode
+#endif
 
 
-		if (gEditorApplication().isProjectLoaded())
+		// Do a full refresh if we have already loaded script assemblies
+		if (mScriptAssembliesLoaded)
 		{
 		{
-			Path gameAssemblyPath = gApplication().getGameAssemblyPath();
-			if (FileSystem::exists(gameAssemblyPath))
-				assemblies.push_back({ SCRIPT_GAME_ASSEMBLY, gameAssemblyPath });
-		}
+			Vector<std::pair<String, Path>> assemblies;
+
+			assemblies.push_back({ ENGINE_ASSEMBLY, engineAssemblyPath });
+			if (gEditorApplication().isProjectLoaded())
+			{
+				if (FileSystem::exists(gameAssemblyPath))
+					assemblies.push_back({ SCRIPT_GAME_ASSEMBLY, gameAssemblyPath });
+			}
 
 
-		String editorAssemblyPath = gEditorApplication().getEditorAssemblyPath().toString();
-		assemblies.push_back({ EDITOR_ASSEMBLY, editorAssemblyPath });
+			assemblies.push_back({ EDITOR_ASSEMBLY, editorAssemblyPath });
+			if (gEditorApplication().isProjectLoaded())
+			{
+				
+				if (FileSystem::exists(editorScriptAssemblyPath))
+					assemblies.push_back({ SCRIPT_EDITOR_ASSEMBLY, editorScriptAssemblyPath });
+			}
 
 
-		if (gEditorApplication().isProjectLoaded())
+			ScriptObjectManager::instance().refreshAssemblies(assemblies);
+		}
+		else // Otherwise just additively load them
 		{
 		{
-			Path editorScriptAssemblyPath = gEditorApplication().getEditorScriptAssemblyPath();
+			MonoManager::instance().loadAssembly(engineAssemblyPath.toString(), ENGINE_ASSEMBLY);
+			ScriptAssemblyManager::instance().loadAssemblyInfo(ENGINE_ASSEMBLY);
+
+			if (FileSystem::exists(gameAssemblyPath))
+			{
+				MonoManager::instance().loadAssembly(gameAssemblyPath.toString(), SCRIPT_GAME_ASSEMBLY);
+				ScriptAssemblyManager::instance().loadAssemblyInfo(SCRIPT_GAME_ASSEMBLY);
+			}
+
+			MonoManager::instance().loadAssembly(editorAssemblyPath.toString(), EDITOR_ASSEMBLY);
+			ScriptAssemblyManager::instance().loadAssemblyInfo(EDITOR_ASSEMBLY);
+
 			if (FileSystem::exists(editorScriptAssemblyPath))
 			if (FileSystem::exists(editorScriptAssemblyPath))
-				assemblies.push_back({ SCRIPT_EDITOR_ASSEMBLY, editorScriptAssemblyPath });
-		}
+			{
+				MonoManager::instance().loadAssembly(editorScriptAssemblyPath.toString(), SCRIPT_EDITOR_ASSEMBLY);
+				ScriptAssemblyManager::instance().loadAssemblyInfo(SCRIPT_EDITOR_ASSEMBLY);
+			}
 
 
-		ScriptObjectManager::instance().refreshAssemblies(assemblies);
+			mScriptAssembliesLoaded = true;
+		}
 	}
 	}
 
 
 	void EditorScriptLibrary::destroy()
 	void EditorScriptLibrary::destroy()

+ 2 - 0
SBansheeEditor/Source/BsEditorScriptManager.cpp

@@ -20,6 +20,7 @@
 #include "BsTestOutput.h"
 #include "BsTestOutput.h"
 #include "BsEditorResourceLoader.h"
 #include "BsEditorResourceLoader.h"
 #include "BsScriptManager.h"
 #include "BsScriptManager.h"
+#include "BsScriptEditorApplication.h"
 
 
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
@@ -97,6 +98,7 @@ namespace BansheeEngine
 		ScriptGizmoManager::instance().update();
 		ScriptGizmoManager::instance().update();
 		ScriptDragDropManager::instance().update();
 		ScriptDragDropManager::instance().update();
 		ScriptFolderMonitorManager::instance().update();
 		ScriptFolderMonitorManager::instance().update();
+		ScriptEditorApplication::update();
 	}
 	}
 
 
 	void EditorScriptManager::debug_refreshAssembly()
 	void EditorScriptManager::debug_refreshAssembly()

+ 23 - 2
SBansheeEditor/Source/BsScriptEditorApplication.cpp

@@ -19,6 +19,11 @@
 
 
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
+	bool ScriptEditorApplication::mRequestProjectLoad = false;
+	Path ScriptEditorApplication::mProjectLoadPath;
+
+	ScriptEditorApplication::OnProjectLoadedThunkDef ScriptEditorApplication::onProjectLoadedThunk;
+
 	ScriptEditorApplication::ScriptEditorApplication(MonoObject* instance)
 	ScriptEditorApplication::ScriptEditorApplication(MonoObject* instance)
 		:ScriptObject(instance)
 		:ScriptObject(instance)
 	{ }
 	{ }
@@ -42,6 +47,22 @@ namespace BansheeEngine
 		metaData.scriptClass->addInternalCall("Internal_LoadProject", &ScriptEditorApplication::internal_LoadProject);
 		metaData.scriptClass->addInternalCall("Internal_LoadProject", &ScriptEditorApplication::internal_LoadProject);
 		metaData.scriptClass->addInternalCall("Internal_UnloadProject", &ScriptEditorApplication::internal_UnloadProject);
 		metaData.scriptClass->addInternalCall("Internal_UnloadProject", &ScriptEditorApplication::internal_UnloadProject);
 		metaData.scriptClass->addInternalCall("Internal_CreateProject", &ScriptEditorApplication::internal_CreateProject);
 		metaData.scriptClass->addInternalCall("Internal_CreateProject", &ScriptEditorApplication::internal_CreateProject);
+
+		onProjectLoadedThunk = (OnProjectLoadedThunkDef)metaData.scriptClass->getMethod("OnProjectLoaded")->getThunk();
+	}
+
+	void ScriptEditorApplication::update()
+	{
+		// Project load must be delayed when requested from managed code because it
+		// triggers managed assembly reload, and that can't be performed when called
+		// from the Mono thread.
+		if (mRequestProjectLoad)
+		{
+			gEditorApplication().loadProject(mProjectLoadPath);
+
+			mRequestProjectLoad = false;
+			MonoUtil::invokeThunk(onProjectLoadedThunk);
+		}
 	}
 	}
 
 
 	MonoString* ScriptEditorApplication::internal_GetProjectPath()
 	MonoString* ScriptEditorApplication::internal_GetProjectPath()
@@ -156,8 +177,8 @@ namespace BansheeEngine
 
 
 	void ScriptEditorApplication::internal_LoadProject(MonoString* path)
 	void ScriptEditorApplication::internal_LoadProject(MonoString* path)
 	{
 	{
-		Path nativePath = MonoUtil::monoToWString(path);
-		gEditorApplication().loadProject(nativePath);
+		mRequestProjectLoad = true;
+		mProjectLoadPath = MonoUtil::monoToWString(path);
 	}
 	}
 
 
 	void ScriptEditorApplication::internal_UnloadProject()
 	void ScriptEditorApplication::internal_UnloadProject()

+ 5 - 0
SBansheeEngine/Include/BsEngineScriptLibrary.h

@@ -12,6 +12,8 @@ namespace BansheeEngine
 	class BS_SCR_BE_EXPORT EngineScriptLibrary : public ScriptLibrary
 	class BS_SCR_BE_EXPORT EngineScriptLibrary : public ScriptLibrary
 	{
 	{
 	public:
 	public:
+		EngineScriptLibrary();
+
 		/**
 		/**
 		 * @copydoc	ScriptLibrary::initialize
 		 * @copydoc	ScriptLibrary::initialize
 		 */
 		 */
@@ -26,5 +28,8 @@ namespace BansheeEngine
 		 * @copydoc	ScriptLibrary::destroy
 		 * @copydoc	ScriptLibrary::destroy
 		 */
 		 */
 		void destroy() override;
 		void destroy() override;
+
+	private:
+		bool mScriptAssembliesLoaded;
 	};
 	};
 }
 }

+ 0 - 26
SBansheeEngine/Include/BsScriptGUIElement.h

@@ -80,19 +80,6 @@ namespace BansheeEngine
 		{ 
 		{ 
 			initialize(element);
 			initialize(element);
 		}
 		}
-
-		/**
-		 * @copydoc	ScriptObjectBase::_onManagedInstanceDeleted
-		 */
-		void _onManagedInstanceDeleted()
-		{
-			// Elements with a GUIWidget parent are destroyed automatically when widget is destroyed, but those without one
-			// we need to destroy manually.
-			if (getGUIElement()->_getParentWidget() == nullptr) 
-				destroy();
-
-			ScriptObject::_onManagedInstanceDeleted();
-		}
 	};
 	};
 
 
 	/**
 	/**
@@ -127,19 +114,6 @@ namespace BansheeEngine
 		{
 		{
 			initialize(element);
 			initialize(element);
 		}
 		}
-
-		/**
-		 * @copydoc	ScriptObjectBase::_onManagedInstanceDeleted
-		 */
-		void _onManagedInstanceDeleted()
-		{
-			// Elements with a GUIWidget parent are destroyed automatically when widget is destroyed, but those without one
-			// we need to destroy manually.
-			if (!mIsDestroyed && getGUIElement()->_getParentWidget() == nullptr)
-				destroy();
-
-			ScriptObject::_onManagedInstanceDeleted();
-		}
 	};
 	};
 
 
 	/**
 	/**

+ 2 - 1
SBansheeEngine/Include/BsScriptGUILayout.h

@@ -67,12 +67,13 @@ namespace BansheeEngine
 	private:
 	private:
 		friend class ScriptGUIPanel;
 		friend class ScriptGUIPanel;
 
 
-		ScriptGUILayout(MonoObject* instance, GUILayout* layout);
+		ScriptGUILayout(MonoObject* instance, GUILayout* layout, bool ownsNative = true);
 
 
 		GUILayout* mLayout;
 		GUILayout* mLayout;
 		Vector<ChildInfo> mChildren;
 		Vector<ChildInfo> mChildren;
 
 
 		bool mIsDestroyed;
 		bool mIsDestroyed;
+		bool mOwnsNative;
 
 
 		/************************************************************************/
 		/************************************************************************/
 		/* 								CLR HOOKS						   		*/
 		/* 								CLR HOOKS						   		*/

+ 2 - 2
SBansheeEngine/Include/BsScriptHString.h

@@ -28,7 +28,7 @@ namespace BansheeEngine
 		/* 								CLR HOOKS						   		*/
 		/* 								CLR HOOKS						   		*/
 		/************************************************************************/
 		/************************************************************************/
 		static void internal_createInstance(MonoObject* instance, MonoString* identifier, UINT32 tableId);
 		static void internal_createInstance(MonoObject* instance, MonoString* identifier, UINT32 tableId);
-		static void internal_setParameter(HString* nativeInstance, UINT32 idx, MonoString* value);
-		static void internal_getValue(HString* nativeInstance, MonoString** value);
+		static void internal_setParameter(ScriptHString* nativeInstance, UINT32 idx, MonoString* value);
+		static void internal_getValue(ScriptHString* nativeInstance, MonoString** value);
 	};
 	};
 }
 }

+ 26 - 5
SBansheeEngine/Source/BsEngineScriptLibrary.cpp

@@ -15,6 +15,10 @@
 
 
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
+	EngineScriptLibrary::EngineScriptLibrary()
+		:mScriptAssembliesLoaded(false)
+	{ }
+
 	void EngineScriptLibrary::initialize()
 	void EngineScriptLibrary::initialize()
 	{
 	{
 		Path engineAssemblyPath = gApplication().getEngineAssemblyPath();
 		Path engineAssemblyPath = gApplication().getEngineAssemblyPath();
@@ -41,13 +45,30 @@ namespace BansheeEngine
 		Path engineAssemblyPath = gApplication().getEngineAssemblyPath();
 		Path engineAssemblyPath = gApplication().getEngineAssemblyPath();
 		Path gameAssemblyPath = gApplication().getGameAssemblyPath();
 		Path gameAssemblyPath = gApplication().getGameAssemblyPath();
 
 
-		Vector<std::pair<String, Path>> assemblies;
-		assemblies.push_back({ ENGINE_ASSEMBLY, engineAssemblyPath });
+		// Do a full refresh if we have already loaded script assemblies
+		if (mScriptAssembliesLoaded)
+		{
+			Vector<std::pair<String, Path>> assemblies;
+			assemblies.push_back({ ENGINE_ASSEMBLY, engineAssemblyPath });
+
+			if (FileSystem::exists(gameAssemblyPath))
+				assemblies.push_back({ SCRIPT_GAME_ASSEMBLY, gameAssemblyPath });
+
+			ScriptObjectManager::instance().refreshAssemblies(assemblies);
+		}
+		else // Otherwise just additively load them
+		{
+			MonoManager::instance().loadAssembly(engineAssemblyPath.toString(), ENGINE_ASSEMBLY);
+			ScriptAssemblyManager::instance().loadAssemblyInfo(ENGINE_ASSEMBLY);
 
 
-		if (FileSystem::exists(gameAssemblyPath))
-			assemblies.push_back({ SCRIPT_GAME_ASSEMBLY, gameAssemblyPath });
+			if (FileSystem::exists(gameAssemblyPath))
+			{
+				MonoManager::instance().loadAssembly(gameAssemblyPath.toString(), SCRIPT_GAME_ASSEMBLY);
+				ScriptAssemblyManager::instance().loadAssemblyInfo(SCRIPT_GAME_ASSEMBLY);
+			}
 
 
-		ScriptObjectManager::instance().refreshAssemblies(assemblies);
+			mScriptAssembliesLoaded = true;
+		}
 	}
 	}
 
 
 	void EngineScriptLibrary::destroy()
 	void EngineScriptLibrary::destroy()

+ 2 - 0
SBansheeEngine/Source/BsScriptGUIElement.cpp

@@ -37,6 +37,8 @@ namespace BansheeEngine
 	void ScriptGUIElementBaseTBase::_onManagedInstanceDeleted()
 	void ScriptGUIElementBaseTBase::_onManagedInstanceDeleted()
 	{
 	{
 		destroy();
 		destroy();
+
+		ScriptObjectBase::_onManagedInstanceDeleted();
 	}
 	}
 
 
 	ScriptGUIElementTBase::ScriptGUIElementTBase(MonoObject* instance)
 	ScriptGUIElementTBase::ScriptGUIElementTBase(MonoObject* instance)

+ 5 - 4
SBansheeEngine/Source/BsScriptGUILayout.cpp

@@ -12,8 +12,8 @@
 
 
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
-	ScriptGUILayout::ScriptGUILayout(MonoObject* instance, GUILayout* layout)
-		:TScriptGUIElementBase(instance, layout), mLayout(layout), mIsDestroyed(false)
+	ScriptGUILayout::ScriptGUILayout(MonoObject* instance, GUILayout* layout, bool ownsNative)
+		:TScriptGUIElementBase(instance, layout), mLayout(layout), mIsDestroyed(false), mOwnsNative(ownsNative)
 	{
 	{
 
 
 	}
 	}
@@ -39,7 +39,8 @@ namespace BansheeEngine
 
 
 			destroyChildren();
 			destroyChildren();
 
 
-			GUILayout::destroy(mLayout);
+			if (mOwnsNative)
+				GUILayout::destroy(mLayout);
 
 
 			mLayout = nullptr;
 			mLayout = nullptr;
 			mIsDestroyed = true;
 			mIsDestroyed = true;
@@ -200,7 +201,7 @@ namespace BansheeEngine
 	MonoObject* ScriptGUIPanel::createFromExisting(GUIPanel* panel)
 	MonoObject* ScriptGUIPanel::createFromExisting(GUIPanel* panel)
 	{
 	{
 		MonoObject* managedInstance = metaData.scriptClass->createInstance();
 		MonoObject* managedInstance = metaData.scriptClass->createInstance();
-		ScriptGUILayout* nativeInstance = new (bs_alloc<ScriptGUILayout>()) ScriptGUILayout(managedInstance, panel);
+		ScriptGUILayout* nativeInstance = new (bs_alloc<ScriptGUILayout>()) ScriptGUILayout(managedInstance, panel, false);
 
 
 		return managedInstance;
 		return managedInstance;
 	}
 	}

+ 4 - 4
SBansheeEngine/Source/BsScriptHString.cpp

@@ -25,13 +25,13 @@ namespace BansheeEngine
 		ScriptHString* nativeInstance = new (bs_alloc<ScriptHString>()) ScriptHString(instance, string);
 		ScriptHString* nativeInstance = new (bs_alloc<ScriptHString>()) ScriptHString(instance, string);
 	}
 	}
 
 
-	void ScriptHString::internal_setParameter(HString* nativeInstance, UINT32 idx, MonoString* value)
+	void ScriptHString::internal_setParameter(ScriptHString* nativeInstance, UINT32 idx, MonoString* value)
 	{
 	{
-		nativeInstance->setParameter(idx, MonoUtil::monoToWString(value));
+		nativeInstance->mString.setParameter(idx, MonoUtil::monoToWString(value));
 	}
 	}
 
 
-	void ScriptHString::internal_getValue(HString* nativeInstance, MonoString** value)
+	void ScriptHString::internal_getValue(ScriptHString* nativeInstance, MonoString** value)
 	{
 	{
-		*value = MonoUtil::wstringToMono(MonoManager::instance().getDomain(), nativeInstance->getValue());
+		*value = MonoUtil::wstringToMono(MonoManager::instance().getDomain(), nativeInstance->mString.getValue());
 	}
 	}
 }
 }

+ 8 - 1
SBansheeEngine/Source/BsScriptObjectManager.cpp

@@ -57,10 +57,15 @@ namespace BansheeEngine
 
 
 		onRefreshDomainLoaded();
 		onRefreshDomainLoaded();
 
 
+		Vector<ScriptObjectBase*> scriptObjCopy(mScriptObjects.size()); // Store originals as we could add new objects during the next iteration
+		UINT32 idx = 0;
 		for (auto& scriptObject : mScriptObjects)
 		for (auto& scriptObject : mScriptObjects)
+			scriptObjCopy[idx++] = scriptObject;
+
+		for (auto& scriptObject : scriptObjCopy)
 			scriptObject->_restoreManagedInstance();
 			scriptObject->_restoreManagedInstance();
 
 
-		for (auto& scriptObject : mScriptObjects)
+		for (auto& scriptObject : scriptObjCopy)
 			scriptObject->endRefresh(backupData[scriptObject]);
 			scriptObject->endRefresh(backupData[scriptObject]);
 
 
 		onRefreshComplete();
 		onRefreshComplete();
@@ -68,6 +73,8 @@ namespace BansheeEngine
 
 
 	void ScriptObjectManager::notifyObjectFinalized(ScriptObjectBase* instance)
 	void ScriptObjectManager::notifyObjectFinalized(ScriptObjectBase* instance)
 	{
 	{
+		assert(instance != nullptr);
+
 		BS_LOCK_MUTEX(mMutex);
 		BS_LOCK_MUTEX(mMutex);
 		mFinalizedObjects[mFinalizedQueueIdx].push_back(instance);
 		mFinalizedObjects[mFinalizedQueueIdx].push_back(instance);
 	}
 	}

+ 8 - 2
TODO.txt

@@ -56,8 +56,14 @@ Move data folder within current repo
  - Store default layout asset in Data/Editor folder
  - Store default layout asset in Data/Editor folder
  - Store data generated by editor runtime at Data/Runtime
  - Store data generated by editor runtime at Data/Runtime
 
 
-TODO - Potentially close all windows when unloading project?
-TODO - Test if project loading/unloading/reloading works
+ Test:
+ - Opening a new project initially
+ - Opening a previous project automatically
+ - Browse for project
+ - Create project
+ - See if recent project list is populated and interactable
+ - Finally test if opening/creating a project while another one is open is possible
+  - Also test save project
 
 
 Ribek use:
 Ribek use:
  - Hook up color picker to guicolor field
  - Hook up color picker to guicolor field