Просмотр исходного кода

More fixes to assembly refresh

Marko Pintera 11 лет назад
Родитель
Сommit
3638a07125

+ 2 - 2
MBansheeEditor/Program.cs

@@ -8,11 +8,11 @@ namespace BansheeEditor
     {
         private static EditorApplication app;
 
-        static void Start()
+        static void OnInitialize()
         {
             app = new EditorApplication();
 
-            DbgResource testResource = new DbgResource();
+            DbgResource testResource = ManagedResource.Create<DbgResource>();
             //ProjectLibrary.Create(testResource, @"testResource");
 
 

+ 8 - 0
MBansheeEditor/Scene/SceneWindow.cs

@@ -29,6 +29,14 @@ namespace BansheeEditor
             UpdateRenderTexture(Width, Height);
         }
 
+        private void OnDestroy()
+        {
+            if (camera != null)
+            {
+                camera.sceneObject.Destroy();
+            }
+        }
+
         private bool ScreenToScenePos(Vector2I screenPos, out Vector2I scenePos)
         {
             scenePos = screenPos;

+ 1 - 6
MBansheeEngine/Component.cs

@@ -7,18 +7,13 @@ namespace BansheeEngine
     {
         // Internal use only
         protected Component()
-        {
-            Internal_CreateInstance(this);
-        }
+        { }
 
         public SceneObject sceneObject
         {
             get { return Internal_GetSceneObject(mCachedPtr); }
         }
 
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        internal static extern SceneObject Internal_CreateInstance(Component instance);
-
         [MethodImpl(MethodImplOptions.InternalCall)]
         internal static extern Component Internal_AddComponent(SceneObject parent, Type type);
 

+ 3 - 2
MBansheeEngine/Font.cs

@@ -4,9 +4,10 @@ namespace BansheeEngine
 {
     public sealed class Font : Resource // TODO - Dummy class
     {
-        internal Font()
+        internal Font(bool constructNative)
         {
-            Internal_CreateInstance(this);
+            if (constructNative)
+                Internal_CreateInstance(this);
         }
 
         [MethodImpl(MethodImplOptions.InternalCall)]

+ 9 - 2
MBansheeEngine/ManagedResource.cs

@@ -8,9 +8,16 @@ namespace BansheeEngine
 {
     public class ManagedResource : Resource
     {
-        public ManagedResource()
+        // For internal use by the runtime
+        protected ManagedResource()
+        { }
+
+        static public T Create<T>() where T : ManagedResource, new()
         {
-            Internal_CreateInstance(this);
+            T newResource = new T();
+            Internal_CreateInstance(newResource);
+
+            return newResource;
         }
 
         [MethodImpl(MethodImplOptions.InternalCall)]

+ 1 - 1
MBansheeEngine/SceneObject.cs

@@ -150,7 +150,7 @@ namespace BansheeEngine
             }
         }
 
-        // For internal use
+        // For internal use by the runtime
         private SceneObject()
         {
             

+ 3 - 0
SBansheeEditor/Include/BsEditorScriptManager.h

@@ -14,6 +14,8 @@ namespace BansheeEngine
 		void update();
 
 	private:
+		void triggerOnInitialize();
+		void onAssemblyRefreshDone();
 		void loadMonoTypes();
 		static void debug_refreshAssembly();
 
@@ -26,6 +28,7 @@ namespace BansheeEngine
 		MonoMethod* mUpdateMethod;
 
 		HEvent mOnDomainLoadConn;
+		HEvent mOnAssemblyRefreshDoneConn;
 
 		static bool mDebugRefresh;
 	};

+ 5 - 0
SBansheeEditor/Include/BsScriptEditorWindow.h

@@ -45,6 +45,7 @@ namespace BansheeEngine
 		void onWidgetResized(UINT32 width, UINT32 height);
 		void onWidgetParentChanged(EditorWidgetContainer* newParent);
 		void onFocusChanged(bool inFocus);
+		void onAssemblyRefreshStarted();
 
 		void _onManagedInstanceDeleted();
 		ScriptObjectBackup beginRefresh();
@@ -58,6 +59,7 @@ namespace BansheeEngine
 		HEvent mOnWidgetResizedConn;
 		HEvent mOnParentChangedConn;
 		HEvent mOnFocusChangedConn;
+		HEvent mOnAssemblyRefreshStartedConn;
 		bool mRefreshInProgress;
 
 		static MonoMethod* onResizedMethod;
@@ -84,17 +86,20 @@ namespace BansheeEngine
 		void update();
 		void reloadMonoTypes(MonoClass* windowClass);
 		void triggerOnInitialize();
+		void triggerOnDestroy();
 
 		MonoObject* getManagedInstance() const { return mManagedInstance; }
 
 	private:
 		typedef void(__stdcall *OnInitializeThunkDef) (MonoObject*, MonoException**);
+		typedef void(__stdcall *OnDestroyThunkDef) (MonoObject*, MonoException**);
 		typedef void(__stdcall *UpdateThunkDef) (MonoObject*, MonoException**);
 
 		String mNamespace;
 		String mTypename;
 
 		OnInitializeThunkDef mOnInitializeThunk;
+		OnDestroyThunkDef mOnDestroyThunk;
 		UpdateThunkDef mUpdateThunk;
 		MonoObject* mManagedInstance;
 

+ 14 - 5
SBansheeEditor/Source/BsEditorScriptManager.cpp

@@ -19,8 +19,6 @@ namespace BansheeEngine
 	EditorScriptManager::EditorScriptManager()
 		:mEditorAssembly(nullptr), mProgramEdClass(nullptr), mUpdateMethod(nullptr)
 	{
-		const String ASSEMBLY_ENTRY_POINT = "Program::Start";
-
 		loadMonoTypes();
 		ScriptAssemblyManager::instance().loadAssemblyInfo(BansheeEditorAssemblyName);
 
@@ -28,11 +26,10 @@ namespace BansheeEngine
 		ScriptGizmoManager::startUp(ScriptAssemblyManager::instance());
 		HandleManager::startUp<ScriptHandleManager>(ScriptAssemblyManager::instance());
 
-		
 		mOnDomainLoadConn = ScriptObjectManager::instance().onRefreshDomainLoaded.connect(std::bind(&EditorScriptManager::loadMonoTypes, this));
+		mOnAssemblyRefreshDoneConn = ScriptObjectManager::instance().onRefreshComplete.connect(std::bind(&EditorScriptManager::onAssemblyRefreshDone, this));
+		triggerOnInitialize();
 		
-		mEditorAssembly->invoke(ASSEMBLY_ENTRY_POINT);
-
 		// Initial update
 		mLastUpdateTime = gTime().getTime();
 		mUpdateMethod->invoke(nullptr, nullptr);
@@ -41,6 +38,7 @@ namespace BansheeEngine
 	EditorScriptManager::~EditorScriptManager()
 	{
 		mOnDomainLoadConn.disconnect();
+		mOnAssemblyRefreshDoneConn.disconnect();
 
 		ScriptHandleSliderManager::shutDown();
 		HandleManager::shutDown();
@@ -74,6 +72,17 @@ namespace BansheeEngine
 		mDebugRefresh = true;
 	}
 
+	void EditorScriptManager::triggerOnInitialize()
+	{
+		const String ASSEMBLY_ENTRY_POINT = "Program::OnInitialize";
+		mEditorAssembly->invoke(ASSEMBLY_ENTRY_POINT);
+	}
+
+	void EditorScriptManager::onAssemblyRefreshDone()
+	{
+		triggerOnInitialize();
+	}
+
 	void EditorScriptManager::loadMonoTypes()
 	{
 		const String ENGINE_ASSEMBLY_PATH = "..\\..\\Assemblies\\MBansheeEditor.dll";

+ 35 - 3
SBansheeEditor/Source/BsScriptEditorWindow.cpp

@@ -10,6 +10,7 @@
 #include "BsEditorWidgetManager.h"
 #include "BsEditorWidgetContainer.h"
 #include "BsMonoAssembly.h"
+#include "BsScriptObjectManager.h"
 
 using namespace std::placeholders;
 
@@ -28,6 +29,8 @@ namespace BansheeEngine
 		mOnWidgetResizedConn = editorWidget->onResized.connect(std::bind(&ScriptEditorWindow::onWidgetResized, this, _1, _2));
 		mOnParentChangedConn = editorWidget->onParentChanged.connect(std::bind(&ScriptEditorWindow::onWidgetParentChanged, this, _1));
 		mOnFocusChangedConn = editorWidget->onFocusChanged.connect(std::bind(&ScriptEditorWindow::onFocusChanged, this, _1));
+
+		mOnAssemblyRefreshStartedConn = ScriptObjectManager::instance().onRefreshStarted.connect(std::bind(&ScriptEditorWindow::onAssemblyRefreshStarted, this));
 	}
 
 	ScriptEditorWindow::~ScriptEditorWindow()
@@ -37,6 +40,8 @@ namespace BansheeEngine
 		mOnWidgetResizedConn.disconnect();
 		mOnParentChangedConn.disconnect();
 		mOnFocusChangedConn.disconnect();
+
+		mOnAssemblyRefreshStartedConn.disconnect();
 	}
 
 	void ScriptEditorWindow::initRuntimeData()
@@ -97,7 +102,9 @@ namespace BansheeEngine
 		auto iterFind = OpenScriptEditorWindows.find(mName);
 		if (iterFind != OpenScriptEditorWindows.end())
 		{
-			mono_gchandle_free(iterFind->second.gcHandle);
+			EditorWindowHandle handle = iterFind->second;
+
+			mono_gchandle_free(handle.gcHandle);
 			iterFind->second.gcHandle = 0;
 		}
 
@@ -128,6 +135,11 @@ namespace BansheeEngine
 		PersistentScriptObjectBase::endRefresh(backupData);
 	}
 
+	void ScriptEditorWindow::onAssemblyRefreshStarted()
+	{
+		mEditorWidget->triggerOnDestroy();
+	}
+
 	MonoObject* ScriptEditorWindow::_createManagedInstance(bool construct)
 	{
 		mEditorWidget->createManagedInstance();
@@ -284,13 +296,14 @@ namespace BansheeEngine
 
 	ScriptEditorWidget::ScriptEditorWidget(const String& ns, const String& type, EditorWidgetContainer& parentContainer)
 		:EditorWidgetBase(HString(toWString(type)), ns + "." + type, parentContainer), mNamespace(ns), mTypename(type),
-		mUpdateThunk(nullptr), mManagedInstance(nullptr), mOnInitializeThunk(nullptr)
+		mUpdateThunk(nullptr), mManagedInstance(nullptr), mOnInitializeThunk(nullptr), mOnDestroyThunk(nullptr)
 	{
 		createManagedInstance();
 	}
 
 	ScriptEditorWidget::~ScriptEditorWidget()
 	{
+		triggerOnDestroy();
 		ScriptEditorWindow::unregisterScriptEditorWindow(getName());
 	}
 
@@ -304,7 +317,7 @@ namespace BansheeEngine
 
 			if (editorWindowClass != nullptr)
 			{
-				mManagedInstance = editorWindowClass->createInstance(false);
+				mManagedInstance = editorWindowClass->createInstance();
 
 				reloadMonoTypes(editorWindowClass);
 				return true;
@@ -331,6 +344,20 @@ namespace BansheeEngine
 		}
 	}
 
+	void ScriptEditorWidget::triggerOnDestroy()
+	{
+		if (mOnDestroyThunk != nullptr && mManagedInstance != nullptr)
+		{
+			MonoException* exception = nullptr;
+
+			// Note: Not calling virtual methods. Can be easily done if needed but for now doing this
+			// for some extra speed.
+			mOnDestroyThunk(mManagedInstance, &exception);
+
+			MonoUtil::throwIfException(exception);
+		}
+	}
+
 	void ScriptEditorWidget::update()
 	{
 		if (mUpdateThunk != nullptr && mManagedInstance != nullptr)
@@ -356,5 +383,10 @@ namespace BansheeEngine
 
 		if (onInitializeMethod != nullptr)
 			mOnInitializeThunk = (OnInitializeThunkDef)onInitializeMethod->getThunk();
+
+		MonoMethod* onDestroyMethod = windowClass->getMethod("OnDestroy", 0);
+
+		if (onDestroyMethod != nullptr)
+			mOnDestroyThunk = (OnDestroyThunkDef)onDestroyMethod->getThunk();
 	}
 }

+ 4 - 0
SBansheeEngine/Include/BsManagedComponentRTTI.h

@@ -105,6 +105,10 @@ namespace BansheeEngine
 			ManagedSerializableObjectPtr serializableObject = any_cast<ManagedSerializableObjectPtr>(mc->mRTTIData);
 			MonoObject* managedInstance = serializableObject->getManagedInstance();
 
+			// Note: This callback must be triggered before any child ManagedSerializable* object's callbacks.
+			// This is because their callbacks will try to resolve native GameObject handles to managed objects
+			// but the managed ScriptComponent will only be created in the code below.
+			// I'm noting this specially as it's somewhat of a hidden requirement.
 			mc->initialize(managedInstance);
 			mc->mRTTIData = nullptr;
 		}

+ 2 - 1
SBansheeEngine/Include/BsScriptGameObjectManager.h

@@ -21,11 +21,12 @@ namespace BansheeEngine
 		ScriptGameObjectManager();
 		~ScriptGameObjectManager();
 
-		void registerScriptComponent(ScriptComponent* nativeInstance, const GameObjectHandle<ManagedComponent>& component);
 		ScriptSceneObject* createScriptSceneObject(const HSceneObject& sceneObject);
 		ScriptSceneObject* createScriptSceneObject(MonoObject* existingInstance, const HSceneObject& sceneObject);
+		ScriptComponent* createScriptComponent(MonoObject* existingInstance, const GameObjectHandle<ManagedComponent>& component);
 
 		ScriptComponent* getScriptComponent(const GameObjectHandle<ManagedComponent>& component) const;
+		ScriptComponent* getScriptComponent(UINT64 instanceId) const;
 		ScriptSceneObject* getScriptSceneObject(const HSceneObject& sceneObject) const;
 		ScriptGameObjectBase* getScriptGameObject(UINT64 instanceId) const;
 

+ 1 - 3
SBansheeEngine/Include/BsScriptObject.h

@@ -89,9 +89,7 @@ namespace BansheeEngine
 
 		void _restoreManagedInstance()
 		{
-			// Do not construct as constructor usually calls initialization code we don't need when restoring.
-			// Managed type needs to account for that on a per-type basis.
-			mManagedInstance = _createManagedInstance(false);
+			mManagedInstance = _createManagedInstance(true);
 
 			Type* param = (Type*)(Base*)this; // Needed due to multiple inheritance. Safe since Type must point to an class derived from this one.
 

+ 1 - 0
SBansheeEngine/Include/BsScriptObjectManager.h

@@ -21,6 +21,7 @@ namespace BansheeEngine
 		 */
 		Event<void()> onRefreshDomainLoaded;
 
+		Event<void()> onRefreshStarted;
 		Event<void()> onRefreshComplete;
 	private:
 		Set<ScriptObjectBase*> mScriptObjects;

+ 1 - 3
SBansheeEngine/Source/BsManagedComponent.cpp

@@ -223,8 +223,6 @@ namespace BansheeEngine
 	{
 		assert(mManagedInstance != nullptr);
 
-		ScriptComponent* nativeInstance = ScriptComponent::toNative(mManagedInstance);
-
 		// Find handle to self
 		HManagedComponent componentHandle;
 		if (mParent != nullptr)
@@ -241,7 +239,7 @@ namespace BansheeEngine
 		}
 
 		assert(componentHandle != nullptr);
-		ScriptGameObjectManager::instance().registerScriptComponent(nativeInstance, componentHandle);
+		ScriptComponent* nativeInstance = ScriptGameObjectManager::instance().createScriptComponent(mManagedInstance, componentHandle);
 
 		if (mOnInitializedThunk != nullptr)
 		{

+ 2 - 0
SBansheeEngine/Source/BsManagedResource.cpp

@@ -10,6 +10,7 @@
 #include "BsManagedSerializableObjectInfo.h"
 #include "BsManagedSerializableObjectData.h"
 #include "BsMemorySerializer.h"
+#include "BsScriptResourceManager.h"
 #include "BsMonoUtil.h"
 #include "BsDebug.h"
 
@@ -129,6 +130,7 @@ namespace BansheeEngine
 		mManagedHandle = mono_gchandle_new(mManagedInstance, false);
 		mMyHandle = myHandle;
 
+		ScriptResourceManager::instance().createManagedResource(object, myHandle);
 		ManagedResourceManager::instance().registerManagedResource(mMyHandle);
 	}
 

+ 0 - 6
SBansheeEngine/Source/BsScriptComponent.cpp

@@ -25,7 +25,6 @@ namespace BansheeEngine
 
 	void ScriptComponent::initRuntimeData()
 	{
-		metaData.scriptClass->addInternalCall("Internal_CreateInstance", &ScriptComponent::internal_createInstance);
 		metaData.scriptClass->addInternalCall("Internal_AddComponent", &ScriptComponent::internal_addComponent);
 		metaData.scriptClass->addInternalCall("Internal_GetComponent", &ScriptComponent::internal_getComponent);
 		metaData.scriptClass->addInternalCall("Internal_GetComponents", &ScriptComponent::internal_getComponents);
@@ -38,11 +37,6 @@ namespace BansheeEngine
 		mManagedComponent = managedComponent;
 	}
 
-	void ScriptComponent::internal_createInstance(MonoObject* instance)
-	{
-		ScriptComponent* nativeInstance = new (bs_alloc<ScriptComponent>()) ScriptComponent(instance);
-	}
-
 	MonoObject* ScriptComponent::internal_addComponent(MonoObject* parentSceneObject, MonoReflectionType* type)
 	{
 		ScriptSceneObject* scriptSO = ScriptSceneObject::toNative(parentSceneObject);

+ 22 - 10
SBansheeEngine/Source/BsScriptGameObjectManager.cpp

@@ -34,16 +34,6 @@ namespace BansheeEngine
 		mOnAssemblyReloadDoneConn.disconnect();
 	}
 
-	void ScriptGameObjectManager::registerScriptComponent(ScriptComponent* nativeInstance, const GameObjectHandle<ManagedComponent>& component)
-	{
-		auto findIter = mScriptGameObjects.find(component->getInstanceId());
-		if(findIter != mScriptGameObjects.end())
-			BS_EXCEPT(InvalidStateException, "Script component for this Component already exists.");
-
-		nativeInstance->setManagedComponent(component);
-		mScriptGameObjects[component->getInstanceId()] = ScriptGameObjectEntry(nativeInstance, true);
-	}
-
 	ScriptSceneObject* ScriptGameObjectManager::createScriptSceneObject(const HSceneObject& sceneObject)
 	{
 		MonoClass* sceneObjectClass = ScriptAssemblyManager::instance().getSceneObjectClass();
@@ -64,6 +54,19 @@ namespace BansheeEngine
 		return nativeInstance;
 	}
 
+	ScriptComponent* ScriptGameObjectManager::createScriptComponent(MonoObject* existingInstance, const GameObjectHandle<ManagedComponent>& component)
+	{
+		auto findIter = mScriptGameObjects.find(component->getInstanceId());
+		if(findIter != mScriptGameObjects.end())
+			BS_EXCEPT(InvalidStateException, "Script component for this Component already exists.");
+
+		ScriptComponent* nativeInstance = new (bs_alloc<ScriptComponent>()) ScriptComponent(existingInstance);
+		nativeInstance->setManagedComponent(component);
+		mScriptGameObjects[component->getInstanceId()] = ScriptGameObjectEntry(nativeInstance, true);
+
+		return nativeInstance;
+	}
+
 	ScriptComponent* ScriptGameObjectManager::getScriptComponent(const GameObjectHandle<ManagedComponent>& component) const
 	{
 		auto findIter = mScriptGameObjects.find(component.getInstanceId());
@@ -73,6 +76,15 @@ namespace BansheeEngine
 		return nullptr;
 	}
 
+	ScriptComponent* ScriptGameObjectManager::getScriptComponent(UINT64 instanceId) const
+	{
+		auto findIter = mScriptGameObjects.find(instanceId);
+		if (findIter != mScriptGameObjects.end())
+			return static_cast<ScriptComponent*>(findIter->second.instance);
+
+		return nullptr;
+	}
+
 	ScriptSceneObject* ScriptGameObjectManager::getScriptSceneObject(const HSceneObject& sceneObject) const
 	{
 		auto findIter = mScriptGameObjects.find(sceneObject.getInstanceId());

+ 0 - 2
SBansheeEngine/Source/BsScriptManagedResource.cpp

@@ -28,8 +28,6 @@ namespace BansheeEngine
 	void ScriptManagedResource::internal_createInstance(MonoObject* instance)
 	{
 		HManagedResource resource = ManagedResource::create(instance);
-
-		ScriptResourceManager::instance().createManagedResource(instance, resource);
 	}
 
 	MonoObject* ScriptManagedResource::_createManagedInstance(bool construct)

+ 2 - 0
SBansheeEngine/Source/BsScriptObjectManager.cpp

@@ -24,6 +24,8 @@ namespace BansheeEngine
 	{
 		Map<ScriptObjectBase*, ScriptObjectBackup> backupData;
 
+		onRefreshStarted();
+
 		for (auto& scriptObject : mScriptObjects)
 			backupData[scriptObject] = scriptObject->beginRefresh();
 

+ 3 - 4
TODO.txt

@@ -5,11 +5,10 @@
 When serializing Camera I cannot save the reference to RenderTexture. Make it a Resource?
 Possibly set up automatic refresh in debug mode after initialization? As an ad-hoc unit test
 
-Occasional crash happens in ScriptObjectManager::refreshAssemblies when backupData.data ends up being null (not all the time though)
+I don't think GUI elements are properly cleaned up after assembly refresh
+ - GUIPanelContainer was holding an invalid reference to mGUIPanel
 
-addComponent gets called during end refresh
- - This seems to add another Camera to the scene
- - While the old one contines to exist as well
+Scene grid disappears and scene view doesn't work after refresh
 
 <<<<Multi-resource saving>>>>:
  - Modify Font so it doesn't contain a texture, but instead keeps a handle to it