Pārlūkot izejas kodu

Fixed an issue where event connections weren being properly released in some cases
Script shutdown now works properly
Saving/Loading build data now uses a valid path

BearishSun 10 gadi atpakaļ
vecāks
revīzija
c369197bb8

+ 9 - 2
BansheeEditor/Source/BsEditorApplication.cpp

@@ -284,7 +284,10 @@ namespace BansheeEngine
 		if (!isProjectLoaded())
 			return;
 
-		BuildManager::instance().save(BUILD_DATA_PATH);
+		Path buildDataPath = getProjectPath();
+		buildDataPath.append(BUILD_DATA_PATH);
+
+		BuildManager::instance().save(buildDataPath);
 		saveWidgetLayout(EditorWidgetManager::instance().getLayout());
 		saveEditorSettings();
 		saveProjectSettings();
@@ -317,7 +320,11 @@ namespace BansheeEngine
 		mIsProjectLoaded = true;
 
 		loadProjectSettings();
-		BuildManager::instance().load(BUILD_DATA_PATH);
+
+		Path buildDataPath = getProjectPath();
+		buildDataPath.append(BUILD_DATA_PATH);
+
+		BuildManager::instance().load(buildDataPath);
 
 		// Do this before restoring windows and loading library to ensure types are loaded
 		ScriptManager::instance().reload();

+ 4 - 0
BansheeMono/Include/BsMonoManager.h

@@ -90,6 +90,10 @@ namespace BansheeEngine
 		 */
 		static void registerScriptType(ScriptMeta* metaData);
 
+		/**  
+		 * @brief	Triggered when the assembly domain and all relevant assemblies are about to be unloaded.
+		 */
+		Event<void()> onDomainUnload;
 	private:
 		/**
 		 * @brief	Initializes a previous loaded assembly.

+ 2 - 0
BansheeMono/Source/BsMonoManager.cpp

@@ -194,6 +194,8 @@ namespace BansheeEngine
 	{
 		if (mScriptDomain != nullptr)
 		{
+			onDomainUnload();
+
 			mono_domain_set(mono_get_root_domain(), false);
 			mono_domain_finalize(mScriptDomain, 2000);
 

+ 4 - 4
BansheeUtility/Include/BsEvent.h

@@ -181,6 +181,7 @@ namespace BansheeEngine
 			{
 				mEventData->disconnect(mConnection);
 				mConnection = nullptr;
+				mEventData = nullptr;
 			}
 		}
 
@@ -268,7 +269,6 @@ namespace BansheeEngine
 					connData->next->prev = nullptr;
 
 				connData->isActive = true;
-				connData->handleLinks = true;
 			}
 
 			if (connData == nullptr)
@@ -298,14 +298,14 @@ namespace BansheeEngine
 
 			// Hidden dependency: If any new connections are made during these callbacks they must be
 			// inserted at the start of the linked list so that we don't trigger them here.
-			ConnectionData* conn = static_cast<ConnectionData*>(mInternalData->mConnections);
+			ConnectionData* conn = static_cast<ConnectionData*>(internalData->mConnections);
 			while (conn != nullptr)
 			{
 				// Save next here in case the callback itself disconnects this connection
 				ConnectionData* next = static_cast<ConnectionData*>(conn->next);
 				
 				if (conn->func != nullptr)
-					conn->func(args...);
+					conn->func(std::forward<Args>(args)...);
 
 				conn = next;
 			}
@@ -324,7 +324,7 @@ namespace BansheeEngine
 		 *
 		 * @note	It is safe to trigger an event even if no callbacks are registered.
 		 */
-		bool empty()
+		bool empty() const
 		{
 			BS_LOCK_RECURSIVE_MUTEX(mInternalData->mMutex);
 

+ 15 - 34
MBansheeEditor/EditorApplication.cs

@@ -126,7 +126,18 @@ namespace BansheeEditor
             ProjectLibrary.Update();
         }
 
-        [MenuItem("File/Save Scene", ButtonModifier.Ctrl, ButtonCode.S, 50, true)]
+        [MenuItem("File/Open Scene", ButtonModifier.Ctrl, ButtonCode.L, 50, true)]
+        private static void LoadScene()
+        {
+            string[] scenePaths;
+            if (BrowseDialog.OpenFile(ProjectLibrary.ResourceFolder, "", false, out scenePaths))
+            {
+                if (scenePaths.Length > 0)
+                    LoadScene(scenePaths[0]);
+            }
+        }
+
+        [MenuItem("File/Save Scene", ButtonModifier.Ctrl, ButtonCode.S, 49)]
         private static void SaveScene()
         {
             if (!string.IsNullOrEmpty(Scene.ActiveSceneUUID))
@@ -138,7 +149,7 @@ namespace BansheeEditor
                 SaveSceneAs();
         }
 
-        [MenuItem("File/Save Scene As", 50)]
+        [MenuItem("File/Save Scene As", 48)]
         private static void SaveSceneAs()
         {
             string scenePath = "";
@@ -157,17 +168,6 @@ namespace BansheeEditor
             }
         }
 
-        [MenuItem("File/Load Scene", ButtonModifier.Ctrl, ButtonCode.L, 50)]
-        private static void LoadScene()
-        {
-            string[] scenePaths;
-            if (BrowseDialog.OpenFile(ProjectLibrary.ResourceFolder, "", false, out scenePaths))
-            {
-                if (scenePaths.Length > 0)
-                    LoadScene(scenePaths[0]);
-            }
-        }
-
         public static void LoadScene(string path)
         {
             Action<string> continueLoad =
@@ -205,27 +205,12 @@ namespace BansheeEditor
             return Internal_IsValidProject(path);
         }
 
-        [MenuItem("File/Create Project", 0)]
-        public static void CreateProject()
-        {
-            string projectPath = EditorSettings.LastOpenProject;
-            if (!Directory.Exists(projectPath))
-                projectPath = Directory.GetCurrentDirectory();
-
-            string selectedPath;
-            if (BrowseDialog.OpenFolder(projectPath, "", out selectedPath))
-            {
-                CreateProject(selectedPath);
-                LoadProject(selectedPath);
-            }
-        }
-
         public static void CreateProject(string path)
         {
             Internal_CreateProject(path);
         }
 
-        [MenuItem("File/Load Project", 0)]
+        [MenuItem("File/Open Project", 100)]
         public static void BrowseForProject()
         {
             string projectPath = EditorSettings.LastOpenProject;
@@ -237,7 +222,7 @@ namespace BansheeEditor
                 LoadProject(selectedPath);
         }
 
-        [MenuItem("File/Save Project", 0)]
+        [MenuItem("File/Save Project", 99)]
         public static void SaveProject()
         {
             // TODO - Save dirty resources
@@ -274,10 +259,6 @@ namespace BansheeEditor
                 return;
             }
 
-            Debug.Log("PRE COLLECT 0");
-            GC.Collect();
-            Debug.Log("POST COLLECT 0");
-
             string projectPath = ProjectPath;
 
             RecentProject[] recentProjects = EditorSettings.RecentProjects;

+ 9 - 2
SBansheeEditor/Include/BsScriptHandleManager.h

@@ -67,11 +67,17 @@ namespace BansheeEngine
 		 */
 		void queueDrawCommands() override;
 
+		/**   
+		 * @brief	 Clears references to all managed types and objects. Must be called before loadAssemblyData if 
+		 * 			 loadAssemblyData was called previously.
+		 */
+		void clearAssemblyData();
+
 		/**
-		 * @brief	Reloads internal managed assembly types and finds all custom handle classes.
+		 * @brief	Loads internal managed assembly types and finds all custom handle classes.
 		 *			Must be called after construction and after assembly reload.
 		 */
-		void reloadAssemblyData();
+		void loadAssemblyData();
 
 		/**
 		 * @brief	Checks is the provided type a valid custom handle class. Custom handles
@@ -113,6 +119,7 @@ namespace BansheeEngine
 		void callDestroy(MonoObject* instance);
 
 		ScriptAssemblyManager& mScriptObjectManager;
+		HEvent mDomainUnloadConn;
 		HEvent mDomainLoadConn;
 
 		Map<String, CustomHandleData> mHandles;

+ 2 - 2
SBansheeEditor/Source/BsEditorScriptLibrary.cpp

@@ -80,8 +80,8 @@ namespace BansheeEngine
 
 	void EditorScriptLibrary::destroy()
 	{
+		unloadAssemblies();
 		EditorScriptManager::shutDown();
-
-		EngineScriptLibrary::destroy();
+		shutdownModules();
 	}
 }

+ 27 - 22
SBansheeEditor/Source/BsScriptHandleManager.cpp

@@ -18,24 +18,16 @@ namespace BansheeEngine
 	ScriptHandleManager::ScriptHandleManager(ScriptAssemblyManager& scriptObjectManager)
 		:mScriptObjectManager(scriptObjectManager)
 	{
-		mDomainLoadConn = ScriptObjectManager::instance().onRefreshDomainLoaded.connect(std::bind(&ScriptHandleManager::reloadAssemblyData, this));
-		reloadAssemblyData();
+		mDomainLoadConn = ScriptObjectManager::instance().onRefreshDomainLoaded.connect(std::bind(&ScriptHandleManager::loadAssemblyData, this));
+		mDomainUnloadConn = MonoManager::instance().onDomainUnload.connect(std::bind(&ScriptHandleManager::clearAssemblyData, this));
+		loadAssemblyData();
 	}
 
 	ScriptHandleManager::~ScriptHandleManager()
 	{
-		for (auto& handle : mActiveHandleData.handles)
-		{
-			callDestroy(handle.object);
-			mono_gchandle_free(handle.gcHandle);
-		}
-
-		if (mDefaultHandleManager != nullptr)
-		{
-			callDestroy(mDefaultHandleManager);
-			mono_gchandle_free(mDefaultHandleManagerGCHandle);
-		}
+		clearAssemblyData();
 
+		mDomainUnloadConn.disconnect();
 		mDomainLoadConn.disconnect();
 	}
 
@@ -125,9 +117,29 @@ namespace BansheeEngine
 		}
 	}
 
-	void ScriptHandleManager::reloadAssemblyData()
+	void ScriptHandleManager::clearAssemblyData()
+	{
+		for (auto& handle : mActiveHandleData.handles)
+		{
+			callDestroy(handle.object);
+			mono_gchandle_free(handle.gcHandle);
+		}
+
+		mActiveHandleData.selectedObject = HSceneObject();
+		mActiveHandleData.handles.clear();
+
+		if (mDefaultHandleManager != nullptr)
+		{
+			callDestroy(mDefaultHandleManager);
+			mono_gchandle_free(mDefaultHandleManagerGCHandle);
+		}
+
+		mDefaultHandleManager = nullptr;
+		mDefaultHandleManagerGCHandle = 0;
+	}
+
+	void ScriptHandleManager::loadAssemblyData()
 	{
-		// Reload types from editor assembly
 		MonoAssembly* editorAssembly = MonoManager::instance().getAssembly(EDITOR_ASSEMBLY);
 		mCustomHandleAttribute = editorAssembly->getClass("BansheeEditor", "CustomHandle");
 		if (mCustomHandleAttribute == nullptr)
@@ -148,9 +160,6 @@ namespace BansheeEngine
 		mDrawMethod = mHandleBaseClass->getMethod("Draw", 0);
 		mDestroyThunk = (DestroyThunkDef)mHandleBaseClass->getMethod("Destroy", 0)->getThunk();
 
-		mDefaultHandleManager = nullptr; // Freed on assembly unload, so not valid anymore
-		mDefaultHandleManagerGCHandle = 0;
-
 		Vector<String> scriptAssemblyNames = mScriptObjectManager.getScriptAssemblies();
 		for (auto& assemblyName : scriptAssemblyNames)
 		{
@@ -175,10 +184,6 @@ namespace BansheeEngine
 				}
 			}
 		}
-
-		// Clear selection data
-		mActiveHandleData.selectedObject = HSceneObject();
-		mActiveHandleData.handles.clear();
 	}
 
 	bool ScriptHandleManager::isValidHandleType(MonoClass* type, MonoClass*& componentType, MonoMethod*& ctor)

+ 11 - 0
SBansheeEngine/Include/BsEngineScriptLibrary.h

@@ -29,6 +29,17 @@ namespace BansheeEngine
 		 */
 		void destroy() override;
 
+	protected:
+		/**   
+		 *	@brief	Unloads all manages assemblies and the mono domain. 
+		 */
+		void unloadAssemblies();
+
+		/**   
+		 *	@brief	Shutd down all script engine modules.
+		 */
+		void shutdownModules();
+
 	private:
 		bool mScriptAssembliesLoaded;
 	};

+ 5 - 0
SBansheeEngine/Include/BsManagedResourceManager.h

@@ -14,6 +14,11 @@ namespace BansheeEngine
 		ManagedResourceManager();
 		~ManagedResourceManager();
 
+		/**   
+		 * @brief	 Unloads all managed resources.
+		 */
+		void clear();
+
 		/**
 		 * @brief	Register a newly created managed resource.
 		 */

+ 13 - 2
SBansheeEngine/Source/BsEngineScriptLibrary.cpp

@@ -72,13 +72,24 @@ namespace BansheeEngine
 	}
 
 	void EngineScriptLibrary::destroy()
+	{
+		unloadAssemblies();
+		shutdownModules();
+	}
+
+	void EngineScriptLibrary::unloadAssemblies()
+	{
+		ManagedResourceManager::instance().clear();
+		MonoManager::instance().unloadScriptDomain();
+		ScriptObjectManager::instance().processFinalizedObjects();
+	}
+
+	void EngineScriptLibrary::shutdownModules()
 	{
 		ScriptVirtualInput::shutDown();
 		ScriptInput::shutDown();
 		ManagedResourceManager::shutDown();
 		MonoManager::shutDown();
-		ScriptObjectManager::instance().processFinalizedObjects();
-
 		ScriptGameObjectManager::shutDown();
 		ScriptResourceManager::shutDown();
 		ScriptAssemblyManager::shutDown();

+ 5 - 0
SBansheeEngine/Source/BsManagedResourceManager.cpp

@@ -9,6 +9,11 @@ namespace BansheeEngine
 	}
 
 	ManagedResourceManager::~ManagedResourceManager()
+	{
+		clear();
+	}
+
+	void ManagedResourceManager::clear()
 	{
 		UnorderedMap<String, HManagedResource> resourceCopy = mResources;
 		for (auto& resourcePair : resourceCopy)

+ 0 - 3
TODO.txt

@@ -57,13 +57,10 @@ Move data folder within current repo
  - Store data generated by editor runtime at Data/Runtime
 
  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
 
 Test and fix project unload