Browse Source

Deferred destruction of game objects
Managed Component Update() methods gets called

Marko Pintera 11 years ago
parent
commit
734f25c36c

+ 4 - 1
BansheeCore/Include/BsComponent.h

@@ -33,8 +33,11 @@ namespace BansheeEngine
 		 * @brief	Removes the component from parent SceneObject and deletes it. All
 		 * @brief	Removes the component from parent SceneObject and deletes it. All
 		 * 			the references to this component will be marked as destroyed and you
 		 * 			the references to this component will be marked as destroyed and you
 		 * 			will get an exception if you try to use them.
 		 * 			will get an exception if you try to use them.
+		 *
+		 * @param	[in] immediate	If true the destruction will be performed immediately, otherwise
+		 *							it will be delayed until the end of the current frame (preferred option).
 		 */
 		 */
-		void destroy();
+		void destroy(bool immediate = false);
 
 
 	protected:
 	protected:
 		friend class SceneObject;
 		friend class SceneObject;

+ 5 - 0
BansheeCore/Include/BsCoreSceneManager.h

@@ -23,6 +23,11 @@ namespace BansheeEngine
 		 */
 		 */
 		HSceneObject getRootNode() const { return mRootNode; }
 		HSceneObject getRootNode() const { return mRootNode; }
 
 
+		/**
+		 * @brief	Destroys all scene objects in the scene.
+		 */
+		void clearScene();
+
 		/**
 		/**
 		 * @brief	Called every frame.
 		 * @brief	Called every frame.
 		 *
 		 *

+ 11 - 0
BansheeCore/Include/BsGameObjectManager.h

@@ -69,6 +69,16 @@ namespace BansheeEngine
 		 */
 		 */
 		void remapId(UINT64 oldId, UINT64 newId);
 		void remapId(UINT64 oldId, UINT64 newId);
 
 
+		/**
+		 * @brief	Queues the object to be destroyed at the end of a GameObject update cycle.
+		 */
+		void queueForDestroy(const GameObjectHandleBase& object);
+
+		/**
+		 * @brief	Destroys any GameObjects that were queued for destruction.
+		 */
+		void destroyQueuedObjects();
+
 		/************************************************************************/
 		/************************************************************************/
 		/* 							DESERIALIZATION                      		*/
 		/* 							DESERIALIZATION                      		*/
 		/************************************************************************/
 		/************************************************************************/
@@ -123,6 +133,7 @@ namespace BansheeEngine
 	private:
 	private:
 		UINT64 mNextAvailableID; // 0 is not a valid ID
 		UINT64 mNextAvailableID; // 0 is not a valid ID
 		Map<UINT64, GameObjectHandleBase> mObjects;
 		Map<UINT64, GameObjectHandleBase> mObjects;
+		Map<UINT64, GameObjectHandleBase> mQueuedForDestroy;
 
 
 		GameObject* mActiveDeserializedObject;
 		GameObject* mActiveDeserializedObject;
 		bool mIsDeserializationActive;
 		bool mIsDeserializationActive;

+ 24 - 4
BansheeCore/Include/BsSceneObject.h

@@ -38,8 +38,12 @@ namespace BansheeEngine
 
 
 		/**
 		/**
 		 * @brief	Destroys this object and any of its held components.
 		 * @brief	Destroys this object and any of its held components.
+		 *
+		 * @param [in]	immediate	If true, the object will be deallocated and become unusable
+		 *							right away. Otherwise the deallocation will be delayed to the end of
+		 *							frame (preferred method).
 		 */
 		 */
-		void destroy();
+		void destroy(bool immediate = false);
 
 
 		/**
 		/**
 		 * @copydoc	GameObject::_setInstanceData
 		 * @copydoc	GameObject::_setInstanceData
@@ -54,7 +58,17 @@ namespace BansheeEngine
 		SceneObject(const String& name);
 		SceneObject(const String& name);
 
 
 		static HSceneObject createInternal(const String& name);
 		static HSceneObject createInternal(const String& name);
-		void destroyInternal();
+
+		/**
+		 * @brief	Destroys this object and any of its held components.
+		 *
+		 * @param [in]	immediate	If true, the object will be deallocated and become unusable
+		 *							right away. Otherwise the deallocation will be delayed to the end of
+		 *							frame (preferred method).
+		 *
+		 * @note	Unlike "destroy", does not remove the object from its parent.
+		 */
+		void destroyInternal(bool immediate = false);
 
 
 	private:
 	private:
 		HSceneObject mThisHandle;
 		HSceneObject mThisHandle;
@@ -468,15 +482,21 @@ namespace BansheeEngine
 		 * @brief	Removes the component from this object, and deallocates it.
 		 * @brief	Removes the component from this object, and deallocates it.
 		 *
 		 *
 		 * @param [in]	component	The component to destroy.
 		 * @param [in]	component	The component to destroy.
+		 * @param [in]	immediate	If true, the component will be deallocated and become unusable
+		 *							right away. Otherwise the deallocation will be delayed to the end of
+		 *							frame (preferred method).
 		 */
 		 */
-		void destroyComponent(const HComponent& component);
+		void destroyComponent(const HComponent& component, bool immediate = false);
 
 
 		/**
 		/**
 		 * @brief	Removes the component from this object, and deallocates it.
 		 * @brief	Removes the component from this object, and deallocates it.
 		 *
 		 *
 		 * @param [in]	component	The component to destroy.
 		 * @param [in]	component	The component to destroy.
+		 * @param [in]	immediate	If true, the component will be deallocated and become unusable
+		 *							right away. Otherwise the deallocation will be delayed to the end of
+		 *							frame (preferred method).
 		 */
 		 */
-		void destroyComponent(Component* component);
+		void destroyComponent(Component* component, bool immediate = false);
 
 
 		/**
 		/**
 		 * @brief	Returns all components on this object.
 		 * @brief	Returns all components on this object.

+ 2 - 2
BansheeCore/Source/BsComponent.cpp

@@ -15,9 +15,9 @@ namespace BansheeEngine
 
 
 	}
 	}
 
 
-	void Component::destroy()
+	void Component::destroy(bool immediate)
 	{
 	{
-		SO()->destroyComponent(this);
+		SO()->destroyComponent(this, immediate);
 	}
 	}
 
 
 	RTTITypeBase* Component::getRTTIStatic()
 	RTTITypeBase* Component::getRTTIStatic()

+ 11 - 2
BansheeCore/Source/BsCoreSceneManager.cpp

@@ -1,6 +1,7 @@
 #include "BsCoreSceneManager.h"
 #include "BsCoreSceneManager.h"
 #include "BsSceneObject.h"
 #include "BsSceneObject.h"
 #include "BsComponent.h"
 #include "BsComponent.h"
+#include "BsGameObjectManager.h"
 
 
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
@@ -11,8 +12,14 @@ namespace BansheeEngine
 
 
 	CoreSceneManager::~CoreSceneManager()
 	CoreSceneManager::~CoreSceneManager()
 	{
 	{
-		if(mRootNode != nullptr)
-			mRootNode->destroy();
+		if (mRootNode != nullptr && !mRootNode.isDestroyed())
+			mRootNode->destroy(true);
+	}
+
+	void CoreSceneManager::clearScene()
+	{
+		GameObjectManager::instance().destroyQueuedObjects();
+		mRootNode->destroy(true);
 	}
 	}
 
 
 	void CoreSceneManager::_update()
 	void CoreSceneManager::_update()
@@ -35,6 +42,8 @@ namespace BansheeEngine
 			for(UINT32 i = 0; i < currentGO->getNumChildren(); i++)
 			for(UINT32 i = 0; i < currentGO->getNumChildren(); i++)
 				todo.push(currentGO->getChild(i));
 				todo.push(currentGO->getChild(i));
 		}
 		}
+
+		GameObjectManager::instance().destroyQueuedObjects();
 	}
 	}
 
 
 	void CoreSceneManager::registerNewSO(const HSceneObject& node) 
 	void CoreSceneManager::registerNewSO(const HSceneObject& node) 

+ 23 - 1
BansheeCore/Source/BsGameObjectManager.cpp

@@ -10,7 +10,9 @@ namespace BansheeEngine
 	}
 	}
 
 
 	GameObjectManager::~GameObjectManager()
 	GameObjectManager::~GameObjectManager()
-	{ }
+	{
+		destroyQueuedObjects();
+	}
 
 
 	GameObjectHandleBase GameObjectManager::getObject(UINT64 id) const 
 	GameObjectHandleBase GameObjectManager::getObject(UINT64 id) const 
 	{ 
 	{ 
@@ -49,6 +51,26 @@ namespace BansheeEngine
 		mObjects.erase(oldId);
 		mObjects.erase(oldId);
 	}
 	}
 
 
+	void GameObjectManager::queueForDestroy(const GameObjectHandleBase& object)
+	{
+		if (object.isDestroyed())
+			return;
+
+		UINT64 instanceId = object->getInstanceId();
+		mQueuedForDestroy[instanceId] = object;
+	}
+
+	void GameObjectManager::destroyQueuedObjects()
+	{
+		for (auto& objPair : mQueuedForDestroy)
+		{
+			unregisterObject(objPair.second);
+			objPair.second.destroy();
+		}
+
+		mQueuedForDestroy.clear();
+	}
+
 	GameObjectHandleBase GameObjectManager::registerObject(const std::shared_ptr<GameObject>& object)
 	GameObjectHandleBase GameObjectManager::registerObject(const std::shared_ptr<GameObject>& object)
 	{
 	{
 		object->initialize(object, mNextAvailableID);
 		object->initialize(object, mNextAvailableID);

+ 35 - 15
BansheeCore/Source/BsSceneObject.cpp

@@ -23,7 +23,7 @@ namespace BansheeEngine
 		if(!mThisHandle.isDestroyed())
 		if(!mThisHandle.isDestroyed())
 		{
 		{
 			LOGWRN("Object is being deleted without being destroyed first?");
 			LOGWRN("Object is being deleted without being destroyed first?");
-			destroyInternal();
+			destroyInternal(true);
 		}
 		}
 	}
 	}
 
 
@@ -47,7 +47,7 @@ namespace BansheeEngine
 		return sceneObject;
 		return sceneObject;
 	}
 	}
 
 
-	void SceneObject::destroy()
+	void SceneObject::destroy(bool immediate)
 	{
 	{
 		// Parent is our owner, so when his reference to us is removed, delete might be called.
 		// Parent is our owner, so when his reference to us is removed, delete might be called.
 		// So make sure this is the last thing we do.
 		// So make sure this is the last thing we do.
@@ -57,27 +57,39 @@ namespace BansheeEngine
 				mParent->removeChild(mThisHandle);
 				mParent->removeChild(mThisHandle);
 		}
 		}
 
 
-		destroyInternal();
+		destroyInternal(immediate);
 	}
 	}
 
 
-	void SceneObject::destroyInternal()
+	void SceneObject::destroyInternal(bool immediate)
 	{
 	{
 		for(auto iter = mChildren.begin(); iter != mChildren.end(); ++iter)
 		for(auto iter = mChildren.begin(); iter != mChildren.end(); ++iter)
-			(*iter)->destroyInternal();
+			(*iter)->destroyInternal(immediate);
 
 
 		mChildren.clear();
 		mChildren.clear();
 
 
 		for(auto iter = mComponents.begin(); iter != mComponents.end(); ++iter)
 		for(auto iter = mComponents.begin(); iter != mComponents.end(); ++iter)
 		{
 		{
 			gCoreSceneManager().notifyComponentRemoved((*iter));
 			gCoreSceneManager().notifyComponentRemoved((*iter));
-			GameObjectManager::instance().unregisterObject(*iter);
-			(*iter).destroy();
+			(*iter)->onDestroyed();
+
+			if (immediate)
+			{
+				GameObjectManager::instance().unregisterObject(*iter);
+				(*iter).destroy();
+			}
+			else
+				GameObjectManager::instance().queueForDestroy(*iter);
 		}
 		}
 
 
 		mComponents.clear();
 		mComponents.clear();
 
 
-		GameObjectManager::instance().unregisterObject(mThisHandle);
-		mThisHandle.destroy();
+		if (immediate)
+		{
+			GameObjectManager::instance().unregisterObject(mThisHandle);
+			mThisHandle.destroy();
+		}
+		else
+			GameObjectManager::instance().queueForDestroy(mThisHandle);
 	}
 	}
 
 
 	void SceneObject::_setInstanceData(GameObjectInstanceDataPtr& other)
 	void SceneObject::_setInstanceData(GameObjectInstanceDataPtr& other)
@@ -447,7 +459,7 @@ namespace BansheeEngine
 		return HComponent();
 		return HComponent();
 	}
 	}
 
 
-	void SceneObject::destroyComponent(const HComponent& component)
+	void SceneObject::destroyComponent(const HComponent& component, bool immediate)
 	{
 	{
 		if(component == nullptr)
 		if(component == nullptr)
 		{
 		{
@@ -460,17 +472,25 @@ namespace BansheeEngine
 		if(iter != mComponents.end())
 		if(iter != mComponents.end())
 		{
 		{
 			gCoreSceneManager().notifyComponentRemoved((*iter));
 			gCoreSceneManager().notifyComponentRemoved((*iter));
-			GameObjectManager::instance().unregisterObject(component);
-
 			(*iter)->onDestroyed();
 			(*iter)->onDestroyed();
-			(*iter).destroy();
+			
 			mComponents.erase(iter);
 			mComponents.erase(iter);
+
+			if (immediate)
+			{
+				GameObjectManager::instance().unregisterObject(component);
+				(*iter).destroy();
+			}
+			else
+			{
+				GameObjectManager::instance().queueForDestroy(component);
+			}
 		}
 		}
 		else
 		else
 			LOGDBG("Trying to remove a component that doesn't exist on this SceneObject.");
 			LOGDBG("Trying to remove a component that doesn't exist on this SceneObject.");
 	}
 	}
 
 
-	void SceneObject::destroyComponent(Component* component)
+	void SceneObject::destroyComponent(Component* component, bool immediate)
 	{
 	{
 		auto iterFind = std::find_if(mComponents.begin(), mComponents.end(), 
 		auto iterFind = std::find_if(mComponents.begin(), mComponents.end(), 
 			[component](const HComponent& x) 
 			[component](const HComponent& x) 
@@ -483,7 +503,7 @@ namespace BansheeEngine
 
 
 		if(iterFind != mComponents.end())
 		if(iterFind != mComponents.end())
 		{
 		{
-			destroyComponent(*iterFind);
+			destroyComponent(*iterFind, immediate);
 		}
 		}
 	}
 	}
 
 

+ 1 - 1
BansheeEditor/Source/BsCmdRecordSO.cpp

@@ -59,7 +59,7 @@ namespace BansheeEngine
 		GameObjectManager::instance().setDeserializationMode(GODM_RestoreExternal | GODM_UseNewIds);
 		GameObjectManager::instance().setDeserializationMode(GODM_RestoreExternal | GODM_UseNewIds);
 
 
 		if (!mSceneObject.isDestroyed())
 		if (!mSceneObject.isDestroyed())
-			mSceneObject->destroy();
+			mSceneObject->destroy(true);
 
 
 		MemorySerializer serializer;
 		MemorySerializer serializer;
 		std::shared_ptr<SceneObject> restored = std::static_pointer_cast<SceneObject>(serializer.decode(mSerializedObject, mSerializedObjectSize));
 		std::shared_ptr<SceneObject> restored = std::static_pointer_cast<SceneObject>(serializer.decode(mSerializedObject, mSerializedObjectSize));

+ 1 - 1
BansheeEngine/Include/BsGUIMaterialManager.h

@@ -72,7 +72,7 @@ namespace BansheeEngine
 		/**
 		/**
 		 * @brief	Releases all internal materials, whether they are used or not.
 		 * @brief	Releases all internal materials, whether they are used or not.
 		 */
 		 */
-		void forceReleaseAllMaterials();
+		void clearMaterials();
 	private:
 	private:
 		/**
 		/**
 		 * @brief	Contains data about a GUI material and its usage count.
 		 * @brief	Contains data about a GUI material and its usage count.

+ 5 - 0
BansheeEngine/Include/BsGUIWidget.h

@@ -154,6 +154,11 @@ namespace BansheeEngine
 		 * @copydoc	Component::update
 		 * @copydoc	Component::update
 		 */
 		 */
 		virtual void update();
 		virtual void update();
+
+		/**
+		 * @copydoc	Component::onDestroyed
+		 */
+		virtual void onDestroyed();
 	private:
 	private:
 		GUIWidget(const GUIWidget& other) { }
 		GUIWidget(const GUIWidget& other) { }
 
 

+ 7 - 1
BansheeEngine/Source/BsApplication.cpp

@@ -8,6 +8,8 @@
 #include "BsScriptManager.h"
 #include "BsScriptManager.h"
 #include "BsProfilingManager.h"
 #include "BsProfilingManager.h"
 #include "BsVirtualInput.h"
 #include "BsVirtualInput.h"
+#include "BsSceneManager.h"
+#include "BsSceneObject.h"
 #include "BsCursor.h"
 #include "BsCursor.h"
 
 
 namespace BansheeEngine
 namespace BansheeEngine
@@ -49,6 +51,10 @@ namespace BansheeEngine
 
 
 	Application::~Application()
 	Application::~Application()
 	{
 	{
+		// Need to clear all objects before I unload any plugins, as they
+		// could have allocated parts or all of those objects.
+		SceneManager::instance().clearScene(); 
+
 #if BS_VER == BS_VER_DEV
 #if BS_VER == BS_VER_DEV
 		shutdownPlugin(mSBansheeEnginePlugin);
 		shutdownPlugin(mSBansheeEnginePlugin);
 		unloadPlugin(mSBansheeEnginePlugin);
 		unloadPlugin(mSBansheeEnginePlugin);
@@ -59,7 +65,7 @@ namespace BansheeEngine
 
 
 		Cursor::shutDown();
 		Cursor::shutDown();
 
 
-		GUIMaterialManager::instance().forceReleaseAllMaterials();
+		GUIMaterialManager::instance().clearMaterials();
 
 
 		OverlayManager::shutDown();
 		OverlayManager::shutDown();
 		GUIManager::shutDown();
 		GUIManager::shutDown();

+ 1 - 1
BansheeEngine/Source/BsGUIMaterialManager.cpp

@@ -164,7 +164,7 @@ namespace BansheeEngine
 		}
 		}
 	}
 	}
 
 
-	void GUIMaterialManager::forceReleaseAllMaterials()
+	void GUIMaterialManager::clearMaterials()
 	{
 	{
 		mTextMaterials.clear();
 		mTextMaterials.clear();
 		mImageMaterials.clear();
 		mImageMaterials.clear();

+ 6 - 3
BansheeEngine/Source/BsGUIWidget.cpp

@@ -39,8 +39,11 @@ namespace BansheeEngine
 	}
 	}
 
 
 	GUIWidget::~GUIWidget()
 	GUIWidget::~GUIWidget()
+	{ }
+
+	void GUIWidget::onDestroyed()
 	{
 	{
-		if(mTarget != nullptr)
+		if (mTarget != nullptr)
 		{
 		{
 			GUIManager::instance().unregisterWidget(this);
 			GUIManager::instance().unregisterWidget(this);
 
 
@@ -50,12 +53,12 @@ namespace BansheeEngine
 		// Iterate over all elements in this way because each
 		// Iterate over all elements in this way because each
 		// GUIElement::destroy call internally unregisters the element
 		// GUIElement::destroy call internally unregisters the element
 		// from the widget, and modifies the mElements array
 		// from the widget, and modifies the mElements array
-		while(mElements.size() > 0)
+		while (mElements.size() > 0)
 		{
 		{
 			GUIElement::destroy(mElements[0]);
 			GUIElement::destroy(mElements[0]);
 		}
 		}
 
 
-		for(auto& area : mAreas)
+		for (auto& area : mAreas)
 		{
 		{
 			GUIArea::destroyInternal(area);
 			GUIArea::destroyInternal(area);
 		}
 		}

+ 7 - 3
SBansheeEngine/Include/BsManagedComponent.h

@@ -17,6 +17,8 @@ namespace BansheeEngine
 		const String& getManagedFullTypeName() const { return mFullTypeName; }
 		const String& getManagedFullTypeName() const { return mFullTypeName; }
 
 
 	private:
 	private:
+		typedef void(__stdcall *UpdateThunkDef) (MonoObject*, MonoException**);
+
 		MonoObject* mManagedInstance;
 		MonoObject* mManagedInstance;
 		MonoReflectionType* mRuntimeType;
 		MonoReflectionType* mRuntimeType;
 		uint32_t mManagedHandle;
 		uint32_t mManagedHandle;
@@ -25,6 +27,8 @@ namespace BansheeEngine
 		String mTypeName;
 		String mTypeName;
 		String mFullTypeName;
 		String mFullTypeName;
 
 
+		UpdateThunkDef mUpdateThunk;
+
 		/************************************************************************/
 		/************************************************************************/
 		/* 							COMPONENT OVERRIDES                    		*/
 		/* 							COMPONENT OVERRIDES                    		*/
 		/************************************************************************/
 		/************************************************************************/
@@ -35,12 +39,12 @@ namespace BansheeEngine
 		/** Standard constructor.
 		/** Standard constructor.
         */
         */
 		ManagedComponent(const HSceneObject& parent, MonoReflectionType* runtimeType);
 		ManagedComponent(const HSceneObject& parent, MonoReflectionType* runtimeType);
-		void construct(MonoObject* object, MonoReflectionType* runtimeType);
+		void construct(MonoObject* object, MonoReflectionType* runtimeType, MonoClass* monoClass);
 
 
 		void onDestroyed();
 		void onDestroyed();
 
 
 	public:
 	public:
-		virtual void update() {}
+		virtual void update();
 
 
 		/************************************************************************/
 		/************************************************************************/
 		/* 								RTTI		                     		*/
 		/* 								RTTI		                     		*/
@@ -51,6 +55,6 @@ namespace BansheeEngine
 		virtual RTTITypeBase* getRTTI() const;
 		virtual RTTITypeBase* getRTTI() const;
 
 
 	protected:
 	protected:
-		ManagedComponent() {} // Serialization only
+		ManagedComponent(); // Serialization only
 	};
 	};
 }
 }

+ 3 - 1
SBansheeEngine/Include/BsManagedComponentRTTI.h

@@ -91,7 +91,9 @@ namespace BansheeEngine
 
 
 			assert(componentHandle != nullptr); // It must exist as every component belongs to its parent SO
 			assert(componentHandle != nullptr); // It must exist as every component belongs to its parent SO
 
 
-			mc->construct(serializableObject->getManagedInstance(), runtimeType);
+			MonoClass* managedClass = MonoManager::instance().findClass(monoClass);
+
+			mc->construct(serializableObject->getManagedInstance(), runtimeType, managedClass);
 			ScriptComponent* nativeInstance = ScriptGameObjectManager::instance().createScriptComponent(componentHandle);
 			ScriptComponent* nativeInstance = ScriptGameObjectManager::instance().createScriptComponent(componentHandle);
 		}
 		}
 
 

+ 30 - 3
SBansheeEngine/Source/BsManagedComponent.cpp

@@ -2,12 +2,18 @@
 #include "BsManagedComponentRTTI.h"
 #include "BsManagedComponentRTTI.h"
 #include "BsMonoManager.h"
 #include "BsMonoManager.h"
 #include "BsMonoClass.h"
 #include "BsMonoClass.h"
+#include "BsMonoUtil.h"
+#include "BsMonoMethod.h"
 #include "BsDebug.h"
 #include "BsDebug.h"
 
 
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
+	ManagedComponent::ManagedComponent()
+		:mUpdateThunk(nullptr)
+	{ }
+
 	ManagedComponent::ManagedComponent(const HSceneObject& parent, MonoReflectionType* runtimeType)
 	ManagedComponent::ManagedComponent(const HSceneObject& parent, MonoReflectionType* runtimeType)
-		:Component(parent), mManagedInstance(nullptr), mRuntimeType(runtimeType)
+		:Component(parent), mManagedInstance(nullptr), mRuntimeType(runtimeType), mUpdateThunk(nullptr)
 	{
 	{
 		MonoType* monoType = mono_reflection_type_get_type(mRuntimeType);
 		MonoType* monoType = mono_reflection_type_get_type(mRuntimeType);
 		::MonoClass* monoClass = mono_type_get_class(monoType);
 		::MonoClass* monoClass = mono_type_get_class(monoType);
@@ -24,16 +30,37 @@ namespace BansheeEngine
 
 
 		setName(mTypeName);
 		setName(mTypeName);
 
 
-		construct(managedClass->createInstance(), runtimeType);
+		construct(managedClass->createInstance(), runtimeType, managedClass);
 	}
 	}
 
 
-	void ManagedComponent::construct(MonoObject* object, MonoReflectionType* runtimeType)
+	void ManagedComponent::construct(MonoObject* object, MonoReflectionType* runtimeType, MonoClass* monoClass)
 	{
 	{
 		mFullTypeName = mNamespace + "." + mTypeName;
 		mFullTypeName = mNamespace + "." + mTypeName;
 
 
 		mManagedInstance = object;
 		mManagedInstance = object;
 		mRuntimeType = runtimeType;
 		mRuntimeType = runtimeType;
 		mManagedHandle = mono_gchandle_new(mManagedInstance, false);
 		mManagedHandle = mono_gchandle_new(mManagedInstance, false);
+
+		if (monoClass != nullptr)
+		{
+			MonoMethod* updateMethod = monoClass->getMethod("Update", 0);
+			if (updateMethod != nullptr)
+				mUpdateThunk = (UpdateThunkDef)updateMethod->getThunk();
+		}
+	}
+
+	void ManagedComponent::update()
+	{
+		if (mUpdateThunk != 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.
+			mUpdateThunk(mManagedInstance, &exception); 
+
+			MonoUtil::throwIfException(exception);
+		}
 	}
 	}
 
 
 	void ManagedComponent::onDestroyed()
 	void ManagedComponent::onDestroyed()

+ 1 - 0
SBansheeEngine/Source/BsScriptComponent.cpp

@@ -3,6 +3,7 @@
 #include "BsScriptMeta.h"
 #include "BsScriptMeta.h"
 #include "BsMonoField.h"
 #include "BsMonoField.h"
 #include "BsMonoClass.h"
 #include "BsMonoClass.h"
+#include "BsMonoMethod.h"
 #include "BsMonoManager.h"
 #include "BsMonoManager.h"
 #include "BsMonoUtil.h"
 #include "BsMonoUtil.h"
 #include "BsScriptSceneObject.h"
 #include "BsScriptSceneObject.h"

+ 5 - 5
SBansheeEngine/Source/BsScriptGameObjectManager.cpp

@@ -46,19 +46,19 @@ namespace BansheeEngine
 
 
 	ScriptSceneObject* ScriptGameObjectManager::createScriptSceneObject(MonoObject* existingInstance, const HSceneObject& sceneObject)
 	ScriptSceneObject* ScriptGameObjectManager::createScriptSceneObject(MonoObject* existingInstance, const HSceneObject& sceneObject)
 	{
 	{
-		auto findIter = mScriptGameObjects.find(sceneObject->getInstanceId());
+		auto findIter = mScriptGameObjects.find(sceneObject.getInstanceId());
 		if(findIter != mScriptGameObjects.end())
 		if(findIter != mScriptGameObjects.end())
 			BS_EXCEPT(InvalidStateException, "Script SceneObject for this SceneObject already exists.");
 			BS_EXCEPT(InvalidStateException, "Script SceneObject for this SceneObject already exists.");
 
 
 		ScriptSceneObject* nativeInstance = new (bs_alloc<ScriptSceneObject>()) ScriptSceneObject(existingInstance, sceneObject);
 		ScriptSceneObject* nativeInstance = new (bs_alloc<ScriptSceneObject>()) ScriptSceneObject(existingInstance, sceneObject);
-		mScriptGameObjects[sceneObject->getInstanceId()] = nativeInstance;
+		mScriptGameObjects[sceneObject.getInstanceId()] = nativeInstance;
 
 
 		return nativeInstance;
 		return nativeInstance;
 	}
 	}
 
 
 	ScriptComponent* ScriptGameObjectManager::getScriptComponent(const GameObjectHandle<ManagedComponent>& component) const
 	ScriptComponent* ScriptGameObjectManager::getScriptComponent(const GameObjectHandle<ManagedComponent>& component) const
 	{
 	{
-		auto findIter = mScriptGameObjects.find(component->getInstanceId());
+		auto findIter = mScriptGameObjects.find(component.getInstanceId());
 		if(findIter != mScriptGameObjects.end())
 		if(findIter != mScriptGameObjects.end())
 			return static_cast<ScriptComponent*>(findIter->second);
 			return static_cast<ScriptComponent*>(findIter->second);
 
 
@@ -67,7 +67,7 @@ namespace BansheeEngine
 
 
 	ScriptSceneObject* ScriptGameObjectManager::getScriptSceneObject(const HSceneObject& sceneObject) const
 	ScriptSceneObject* ScriptGameObjectManager::getScriptSceneObject(const HSceneObject& sceneObject) const
 	{
 	{
-		auto findIter = mScriptGameObjects.find(sceneObject->getInstanceId());
+		auto findIter = mScriptGameObjects.find(sceneObject.getInstanceId());
 		if(findIter != mScriptGameObjects.end())
 		if(findIter != mScriptGameObjects.end())
 			return static_cast<ScriptSceneObject*>(findIter->second);
 			return static_cast<ScriptSceneObject*>(findIter->second);
 
 
@@ -85,7 +85,7 @@ namespace BansheeEngine
 
 
 	void ScriptGameObjectManager::destroyScriptGameObject(ScriptGameObjectBase* gameObject)
 	void ScriptGameObjectManager::destroyScriptGameObject(ScriptGameObjectBase* gameObject)
 	{
 	{
-		UINT64 idx = gameObject->getNativeHandle()->getInstanceId();
+		UINT64 idx = gameObject->getNativeHandle().getInstanceId();
 		mScriptGameObjects.erase(idx);
 		mScriptGameObjects.erase(idx);
 
 
 		bs_delete(gameObject);
 		bs_delete(gameObject);

+ 23 - 17
SceneView.txt

@@ -2,26 +2,30 @@
  GIZMO TODO:
  GIZMO TODO:
   - Make a C# wrapper for Renderable
   - Make a C# wrapper for Renderable
 
 
-The bounds I retrieve from GUIUtility are relative to the entire window, not just the current widget. Another reason to move editor widgets to their own GUIWidget.
-Passing a Vector2I (and I'm assuming any script) through a thunk crashes the runtime
-
-Set up Application::getPrimaryViewport so it returns a valid viewport otherwise C# Camera won't work properly
-
-REFACTOR material getParams* and related classes. Those params should update all gpu program params that share that variable, not just the first found
+Need to defer destruction of Components until all component updates have finished. Otherwise I risk destroying a component referenced by some
+other script since the order to Update() methods isn't clearly defined.
+ - Add [ExecPriority] attribute for Update() method
+ - Make sure Component update is called
+ - Do I handle it gracefully if user tries to access destroyed component or scene object?
+  - I don't, at least not with SceneObject. I will try to access HSceneObject handle even if its
+    destroyed. Add a check.
+
+Refactor GizmoManager and HandleManager so they accept a CameraHandler
+Port SceneCameraController to C#
+ - Will need a C# Cursor and SceneObject C# interface will also likely need to be completed (SceneObject doesn't have Destroy() among other things)
+Port RenderTexture to C# and likely extend Texture2D so it accepts renderable flags. While at it add TextureCube and Texture3D as well.
+Ensure that EditorWindow resize callback works properly.
+ - Perhaps add OnResizeEnd callback that can be used for updating the render texture
+Create a C# wrapper around ProjectSettings
+Make a Script version of SceneEditorWindow
+ - This would replace SceneEditorWidget so it would initialize scene grid and call
+    update on handle manager and scene grid, as well as apply ProjectSettings to them.
+ 
+Move handle is buggy as hell - It moves in wrong direction sometimes, sometimes it skips, other times collision seems to be wrong
 Need a way to drag and drop items from Scene tree view to Scene view
 Need a way to drag and drop items from Scene tree view to Scene view
 When dragging a handle make sure it works when cursor leaves the scene view
 When dragging a handle make sure it works when cursor leaves the scene view
 Also make sure that handle manager receives mouse up event if its done outside of scene view
 Also make sure that handle manager receives mouse up event if its done outside of scene view
-When selecting/deselecting stuff handle display is delayed
-
-Create the scene widget completely in C#?
- - Port RenderTexture, SceneCameraController, ProjectSettings, SceneGrid
- - Will need to track when widget resizes so I can resize the render target
- - Handle manager update will originate from the widget
-  - Actually it could still be done from C++
- - How will scene grid rendering be handled? Currently it's done from a render() callback
-  - It's still going to have a C++ representation, just call the callback there
- - I will still need a C++ version of scene widget (not in script code but in editor code) because handle/gizmo manager reference it
- 
+
 AFTER I have scene widget in C#:
 AFTER I have scene widget in C#:
  - Finish up C# Handles class so it returns proper values
  - Finish up C# Handles class so it returns proper values
  - Ensure fixed handle size and handle snapping works
  - Ensure fixed handle size and handle snapping works
@@ -38,6 +42,8 @@ LATER:
  - Need a way to render text for gizmos and handles, and in scene in general
  - Need a way to render text for gizmos and handles, and in scene in general
  - Add drag to select
  - Add drag to select
  - Need a better system to catch broken shaders. DX11 just draws nothing with depth, DX9 draws all white.
  - Need a better system to catch broken shaders. DX11 just draws nothing with depth, DX9 draws all white.
+ - The bounds I retrieve from GUIUtility are relative to the entire window, not just the current widget. Another reason to move editor widgets to their own GUIWidget.
+ - Set up Application::getPrimaryViewport so it returns a valid viewport otherwise C# Camera won't work properly
 
 
 ---------------------------------------------------------------------
 ---------------------------------------------------------------------
 Render textures in C#:
 Render textures in C#: