瀏覽代碼

Reintroduced circular reference search for RTTI

BearishSun 10 年之前
父節點
當前提交
3bd0a6c6a0

+ 261 - 259
BansheeCore/Include/BsPrefabDiffRTTI.h

@@ -1,260 +1,262 @@
-#pragma once
-
-#include "BsCorePrerequisites.h"
-#include "BsRTTIType.h"
-#include "BsPrefabDiff.h"
-#include "BsSerializedObject.h"
-#include "BsGameObjectManager.h"
-#include "BsBinarySerializer.h"
-
-namespace BansheeEngine
-{
-	class BS_CORE_EXPORT PrefabComponentDiffRTTI : public RTTIType < PrefabComponentDiff, IReflectable, PrefabComponentDiffRTTI >
-	{
-	private:
-		BS_PLAIN_MEMBER(id)
-		BS_REFLPTR_MEMBER(data);
-	public:
-		PrefabComponentDiffRTTI()
-		{
-			BS_ADD_PLAIN_FIELD(id, 0);
-			BS_ADD_REFLPTR_FIELD(data, 1);
-		}
-
-		virtual const String& getRTTIName() override
-		{
-			static String name = "PrefabComponentDiff";
-			return name;
-		}
-
-		virtual UINT32 getRTTIId() override
-		{
-			return TID_PrefabComponentDiff;
-		}
-
-		virtual std::shared_ptr<IReflectable> newRTTIObject() override
-		{
-			return bs_shared_ptr_new<PrefabComponentDiff>();
-		}
-	};
-
-	class BS_CORE_EXPORT PrefabObjectDiffRTTI : public RTTIType < PrefabObjectDiff, IReflectable, PrefabObjectDiffRTTI >
-	{
-	private:
-		BS_PLAIN_MEMBER(id)
-
-		BS_PLAIN_MEMBER(name)
-		BS_PLAIN_MEMBER(position);
-		BS_PLAIN_MEMBER(rotation);
-		BS_PLAIN_MEMBER(scale);
-		BS_PLAIN_MEMBER(isActive);
-		BS_PLAIN_MEMBER(soFlags);
-
-		BS_REFLPTR_MEMBER_VEC(componentDiffs)
-		BS_PLAIN_MEMBER_VEC(removedComponents)
-		BS_REFLPTR_MEMBER_VEC(addedComponents)
-
-		BS_REFLPTR_MEMBER_VEC(childDiffs)
-		BS_PLAIN_MEMBER_VEC(removedChildren)
-		BS_REFLPTR_MEMBER_VEC(addedChildren)
-	public:
-		PrefabObjectDiffRTTI()
-		{
-			BS_ADD_PLAIN_FIELD(id, 0);
-			BS_ADD_PLAIN_FIELD(name, 1);
-
-			BS_ADD_REFLPTR_FIELD_ARR(componentDiffs, 2);
-			BS_ADD_PLAIN_FIELD_ARR(removedComponents, 3);
-			BS_ADD_REFLPTR_FIELD_ARR(addedComponents, 4);
-
-			BS_ADD_REFLPTR_FIELD_ARR(childDiffs, 5);
-			BS_ADD_PLAIN_FIELD_ARR(removedChildren, 6);
-			BS_ADD_REFLPTR_FIELD_ARR(addedChildren, 7);
-
-			BS_ADD_PLAIN_FIELD(position, 8);
-			BS_ADD_PLAIN_FIELD(rotation, 9);
-			BS_ADD_PLAIN_FIELD(scale, 10);
-			BS_ADD_PLAIN_FIELD(isActive, 11);
-			BS_ADD_PLAIN_FIELD(soFlags, 12);
-		}
-
-		virtual const String& getRTTIName() override
-		{
-			static String name = "PrefabObjectDiff";
-			return name;
-		}
-
-		virtual UINT32 getRTTIId() override
-		{
-			return TID_PrefabObjectDiff;
-		}
-
-		virtual std::shared_ptr<IReflectable> newRTTIObject() override
-		{
-			return bs_shared_ptr_new<PrefabObjectDiff>();
-		}
-	};
-
-	class BS_CORE_EXPORT PrefabDiffRTTI : public RTTIType < PrefabDiff, IReflectable, PrefabDiffRTTI >
-	{
-		/**
-		 * @brief	Contains data about a game object handle serialized in a prefab diff. 
-		 */
-		struct SerializedHandle
-		{
-			SPtr<SerializedObject> object;
-			SPtr<GameObjectHandleBase> handle;
-		};
-
-	private:
-		BS_REFLPTR_MEMBER(mRoot);
-	public:
-		PrefabDiffRTTI()
-		{
-			BS_ADD_REFLPTR_FIELD(mRoot, 0);
-		}
-
-		virtual void onDeserializationStarted(IReflectable* obj) override
-		{
-			PrefabDiff* prefabDiff = static_cast<PrefabDiff*>(obj);
-
-			if (GameObjectManager::instance().isGameObjectDeserializationActive())
-				GameObjectManager::instance().registerOnDeserializationEndCallback(std::bind(&PrefabDiffRTTI::delayedOnDeserializationEnded, prefabDiff));
-		}
-
-		virtual void onDeserializationEnded(IReflectable* obj) override
-		{
-			assert(GameObjectManager::instance().isGameObjectDeserializationActive());
-
-			// Make sure to deserialize all game object handles since their IDs need to be updated. Normally they are
-			// updated automatically upon deserialization but since we store them in intermediate form we need to manually
-			// deserialize and reserialize them in order to update their IDs.
-			PrefabDiff* prefabDiff = static_cast<PrefabDiff*>(obj);
-
-			Stack<SPtr<PrefabObjectDiff>> todo;
-
-			if (prefabDiff->mRoot != nullptr)
-				todo.push(prefabDiff->mRoot);
-
-			UnorderedSet<SPtr<SerializedObject>> handleObjects;
-
-			while (!todo.empty())
-			{
-				SPtr<PrefabObjectDiff> current = todo.top();
-				todo.pop();
-
-				for (auto& component : current->addedComponents)
-					findGameObjectHandles(component, handleObjects);
-
-				for (auto& child : current->addedChildren)
-					findGameObjectHandles(child, handleObjects);
-
-				for (auto& component : current->componentDiffs)
-					findGameObjectHandles(component->data, handleObjects);
-
-				for (auto& child : current->childDiffs)
-					todo.push(child);
-			}
-
-			Vector<SerializedHandle> handleData(handleObjects.size());
-
-			UINT32 idx = 0;
-			BinarySerializer bs;
-			for (auto& handleObject : handleObjects)
-			{
-				SerializedHandle& handle = handleData[idx];
-
-				handle.object = handleObject;
-				handle.handle = std::static_pointer_cast<GameObjectHandleBase>(bs._decodeIntermediate(handleObject));
-
-				idx++;
-			}
-
-			prefabDiff->mRTTIData = handleData;
-		}
-
-		/**
-		 * @brief	Decodes GameObjectHandles from their binary format, because during deserialization GameObjectManager
-		 *			will update all object IDs and we want to keep the handles up to date.So we deserialize them
-		 *			and allow them to be updated before storing them back into binary format.
-		 */
-		static void delayedOnDeserializationEnded(PrefabDiff* prefabDiff)
-		{
-			Vector<SerializedHandle>& handleData = any_cast_ref<Vector<SerializedHandle>>(prefabDiff->mRTTIData);
-
-			BinarySerializer bs;
-			for (auto& serializedHandle : handleData)
-			{
-				if (serializedHandle.handle != nullptr)
-					*serializedHandle.object = *bs._encodeIntermediate(serializedHandle.handle.get());
-			}
-
-			prefabDiff->mRTTIData = nullptr;
-		}
-
-		/**
-		 * @brief	Scans the entire hierarchy and find all serialized GameObjectHandle objects.
-		 */
-		static void findGameObjectHandles(const SPtr<SerializedObject>& serializedObject, UnorderedSet<SPtr<SerializedObject>>& handleObjects)
-		{
-			for (auto& subObject : serializedObject->subObjects)
-			{
-				RTTITypeBase* rtti = IReflectable::_getRTTIfromTypeId(subObject.typeId);
-				if (rtti == nullptr)
-					continue;
-
-				if (rtti->getRTTIId() == TID_GameObjectHandleBase)
-				{
-					handleObjects.insert(serializedObject);
-					return;
-				}
-
-				for (auto& child : subObject.entries)
-				{
-					RTTIField* curGenericField = rtti->findField(child.second.fieldId);
-					if (curGenericField == nullptr)
-						continue;
-
-					SPtr<SerializedInstance> entryData = child.second.serialized;
-					if (entryData == nullptr)
-						continue;
-
-					if (rtti_is_of_type<SerializedArray>(entryData))
-					{
-						SPtr<SerializedArray> arrayData = std::static_pointer_cast<SerializedArray>(entryData);
-						
-						for (auto& arrayElem : arrayData->entries)
-						{
-							if (arrayElem.second.serialized != nullptr && rtti_is_of_type<SerializedObject>(arrayElem.second.serialized))
-							{
-								SPtr<SerializedObject> arrayElemData = std::static_pointer_cast<SerializedObject>(arrayElem.second.serialized);
-								findGameObjectHandles(arrayElemData, handleObjects);
-							}
-						}
-					}
-					else if(rtti_is_of_type<SerializedObject>(entryData))
-					{
-						SPtr<SerializedObject> fieldObjectData = std::static_pointer_cast<SerializedObject>(entryData);
-						findGameObjectHandles(fieldObjectData, handleObjects);
-					}
-				}
-			}
-		}
-
-		virtual const String& getRTTIName() override
-		{
-			static String name = "PrefabDiff";
-			return name;
-		}
-
-		virtual UINT32 getRTTIId() override
-		{
-			return TID_PrefabDiff;
-		}
-
-		virtual std::shared_ptr<IReflectable> newRTTIObject() override
-		{
-			return bs_shared_ptr_new<PrefabDiff>();
-		}
-	};
+#pragma once
+
+#include "BsCorePrerequisites.h"
+#include "BsRTTIType.h"
+#include "BsPrefabDiff.h"
+#include "BsSerializedObject.h"
+#include "BsGameObjectManager.h"
+#include "BsBinarySerializer.h"
+
+namespace BansheeEngine
+{
+	class BS_CORE_EXPORT PrefabComponentDiffRTTI : public RTTIType < PrefabComponentDiff, IReflectable, PrefabComponentDiffRTTI >
+	{
+	private:
+		BS_PLAIN_MEMBER(id)
+		BS_REFLPTR_MEMBER(data);
+	public:
+		PrefabComponentDiffRTTI()
+		{
+			BS_ADD_PLAIN_FIELD(id, 0);
+			BS_ADD_REFLPTR_FIELD(data, 1);
+		}
+
+		virtual const String& getRTTIName() override
+		{
+			static String name = "PrefabComponentDiff";
+			return name;
+		}
+
+		virtual UINT32 getRTTIId() override
+		{
+			return TID_PrefabComponentDiff;
+		}
+
+		virtual std::shared_ptr<IReflectable> newRTTIObject() override
+		{
+			return bs_shared_ptr_new<PrefabComponentDiff>();
+		}
+	};
+
+	class BS_CORE_EXPORT PrefabObjectDiffRTTI : public RTTIType < PrefabObjectDiff, IReflectable, PrefabObjectDiffRTTI >
+	{
+	private:
+		BS_PLAIN_MEMBER(id)
+
+		BS_PLAIN_MEMBER(name)
+		BS_PLAIN_MEMBER(position);
+		BS_PLAIN_MEMBER(rotation);
+		BS_PLAIN_MEMBER(scale);
+		BS_PLAIN_MEMBER(isActive);
+		BS_PLAIN_MEMBER(soFlags);
+
+		BS_REFLPTR_MEMBER_VEC(componentDiffs)
+		BS_PLAIN_MEMBER_VEC(removedComponents)
+		BS_REFLPTR_MEMBER_VEC(addedComponents)
+
+		BS_REFLPTR_MEMBER_VEC(childDiffs)
+		BS_PLAIN_MEMBER_VEC(removedChildren)
+		BS_REFLPTR_MEMBER_VEC(addedChildren)
+	public:
+		PrefabObjectDiffRTTI()
+		{
+			BS_ADD_PLAIN_FIELD(id, 0);
+			BS_ADD_PLAIN_FIELD(name, 1);
+
+			BS_ADD_REFLPTR_FIELD_ARR(componentDiffs, 2);
+			BS_ADD_PLAIN_FIELD_ARR(removedComponents, 3);
+			BS_ADD_REFLPTR_FIELD_ARR(addedComponents, 4);
+
+			addReflectablePtrArrayField("childDiffs", 5, &MyType::getchildDiffs, &MyType::getSizechildDiffs,
+				&MyType::setchildDiffs, &MyType::setSizechildDiffs, RTTI_Flag_WeakRef);
+
+			BS_ADD_PLAIN_FIELD_ARR(removedChildren, 6);
+			BS_ADD_REFLPTR_FIELD_ARR(addedChildren, 7);
+
+			BS_ADD_PLAIN_FIELD(position, 8);
+			BS_ADD_PLAIN_FIELD(rotation, 9);
+			BS_ADD_PLAIN_FIELD(scale, 10);
+			BS_ADD_PLAIN_FIELD(isActive, 11);
+			BS_ADD_PLAIN_FIELD(soFlags, 12);
+		}
+
+		virtual const String& getRTTIName() override
+		{
+			static String name = "PrefabObjectDiff";
+			return name;
+		}
+
+		virtual UINT32 getRTTIId() override
+		{
+			return TID_PrefabObjectDiff;
+		}
+
+		virtual std::shared_ptr<IReflectable> newRTTIObject() override
+		{
+			return bs_shared_ptr_new<PrefabObjectDiff>();
+		}
+	};
+
+	class BS_CORE_EXPORT PrefabDiffRTTI : public RTTIType < PrefabDiff, IReflectable, PrefabDiffRTTI >
+	{
+		/**
+		 * @brief	Contains data about a game object handle serialized in a prefab diff. 
+		 */
+		struct SerializedHandle
+		{
+			SPtr<SerializedObject> object;
+			SPtr<GameObjectHandleBase> handle;
+		};
+
+	private:
+		BS_REFLPTR_MEMBER(mRoot);
+	public:
+		PrefabDiffRTTI()
+		{
+			BS_ADD_REFLPTR_FIELD(mRoot, 0);
+		}
+
+		virtual void onDeserializationStarted(IReflectable* obj) override
+		{
+			PrefabDiff* prefabDiff = static_cast<PrefabDiff*>(obj);
+
+			if (GameObjectManager::instance().isGameObjectDeserializationActive())
+				GameObjectManager::instance().registerOnDeserializationEndCallback(std::bind(&PrefabDiffRTTI::delayedOnDeserializationEnded, prefabDiff));
+		}
+
+		virtual void onDeserializationEnded(IReflectable* obj) override
+		{
+			assert(GameObjectManager::instance().isGameObjectDeserializationActive());
+
+			// Make sure to deserialize all game object handles since their IDs need to be updated. Normally they are
+			// updated automatically upon deserialization but since we store them in intermediate form we need to manually
+			// deserialize and reserialize them in order to update their IDs.
+			PrefabDiff* prefabDiff = static_cast<PrefabDiff*>(obj);
+
+			Stack<SPtr<PrefabObjectDiff>> todo;
+
+			if (prefabDiff->mRoot != nullptr)
+				todo.push(prefabDiff->mRoot);
+
+			UnorderedSet<SPtr<SerializedObject>> handleObjects;
+
+			while (!todo.empty())
+			{
+				SPtr<PrefabObjectDiff> current = todo.top();
+				todo.pop();
+
+				for (auto& component : current->addedComponents)
+					findGameObjectHandles(component, handleObjects);
+
+				for (auto& child : current->addedChildren)
+					findGameObjectHandles(child, handleObjects);
+
+				for (auto& component : current->componentDiffs)
+					findGameObjectHandles(component->data, handleObjects);
+
+				for (auto& child : current->childDiffs)
+					todo.push(child);
+			}
+
+			Vector<SerializedHandle> handleData(handleObjects.size());
+
+			UINT32 idx = 0;
+			BinarySerializer bs;
+			for (auto& handleObject : handleObjects)
+			{
+				SerializedHandle& handle = handleData[idx];
+
+				handle.object = handleObject;
+				handle.handle = std::static_pointer_cast<GameObjectHandleBase>(bs._decodeIntermediate(handleObject));
+
+				idx++;
+			}
+
+			prefabDiff->mRTTIData = handleData;
+		}
+
+		/**
+		 * @brief	Decodes GameObjectHandles from their binary format, because during deserialization GameObjectManager
+		 *			will update all object IDs and we want to keep the handles up to date.So we deserialize them
+		 *			and allow them to be updated before storing them back into binary format.
+		 */
+		static void delayedOnDeserializationEnded(PrefabDiff* prefabDiff)
+		{
+			Vector<SerializedHandle>& handleData = any_cast_ref<Vector<SerializedHandle>>(prefabDiff->mRTTIData);
+
+			BinarySerializer bs;
+			for (auto& serializedHandle : handleData)
+			{
+				if (serializedHandle.handle != nullptr)
+					*serializedHandle.object = *bs._encodeIntermediate(serializedHandle.handle.get());
+			}
+
+			prefabDiff->mRTTIData = nullptr;
+		}
+
+		/**
+		 * @brief	Scans the entire hierarchy and find all serialized GameObjectHandle objects.
+		 */
+		static void findGameObjectHandles(const SPtr<SerializedObject>& serializedObject, UnorderedSet<SPtr<SerializedObject>>& handleObjects)
+		{
+			for (auto& subObject : serializedObject->subObjects)
+			{
+				RTTITypeBase* rtti = IReflectable::_getRTTIfromTypeId(subObject.typeId);
+				if (rtti == nullptr)
+					continue;
+
+				if (rtti->getRTTIId() == TID_GameObjectHandleBase)
+				{
+					handleObjects.insert(serializedObject);
+					return;
+				}
+
+				for (auto& child : subObject.entries)
+				{
+					RTTIField* curGenericField = rtti->findField(child.second.fieldId);
+					if (curGenericField == nullptr)
+						continue;
+
+					SPtr<SerializedInstance> entryData = child.second.serialized;
+					if (entryData == nullptr)
+						continue;
+
+					if (rtti_is_of_type<SerializedArray>(entryData))
+					{
+						SPtr<SerializedArray> arrayData = std::static_pointer_cast<SerializedArray>(entryData);
+						
+						for (auto& arrayElem : arrayData->entries)
+						{
+							if (arrayElem.second.serialized != nullptr && rtti_is_of_type<SerializedObject>(arrayElem.second.serialized))
+							{
+								SPtr<SerializedObject> arrayElemData = std::static_pointer_cast<SerializedObject>(arrayElem.second.serialized);
+								findGameObjectHandles(arrayElemData, handleObjects);
+							}
+						}
+					}
+					else if(rtti_is_of_type<SerializedObject>(entryData))
+					{
+						SPtr<SerializedObject> fieldObjectData = std::static_pointer_cast<SerializedObject>(entryData);
+						findGameObjectHandles(fieldObjectData, handleObjects);
+					}
+				}
+			}
+		}
+
+		virtual const String& getRTTIName() override
+		{
+			static String name = "PrefabDiff";
+			return name;
+		}
+
+		virtual UINT32 getRTTIId() override
+		{
+			return TID_PrefabDiff;
+		}
+
+		virtual std::shared_ptr<IReflectable> newRTTIObject() override
+		{
+			return bs_shared_ptr_new<PrefabDiff>();
+		}
+	};
 }

+ 365 - 367
BansheeCore/Source/BsCoreApplication.cpp

@@ -1,368 +1,366 @@
-#include "BsCoreApplication.h"
-
-#include "BsRenderAPI.h"
-#include "BsRenderAPIManager.h"
-
-#include "BsPlatform.h"
-#include "BsHardwareBufferManager.h"
-#include "BsRenderWindow.h"
-#include "BsViewport.h"
-#include "BsVector2.h"
-#include "BsGpuProgram.h"
-#include "BsCoreObjectManager.h"
-#include "BsGameObjectManager.h"
-#include "BsDynLib.h"
-#include "BsDynLibManager.h"
-#include "BsCoreSceneManager.h"
-#include "BsImporter.h"
-#include "BsResources.h"
-#include "BsMesh.h"
-#include "BsSceneObject.h"
-#include "BsTime.h"
-#include "BsInput.h"
-#include "BsRendererManager.h"
-#include "BsGpuProgramManager.h"
-#include "BsMeshManager.h"
-#include "BsMaterialManager.h"
-#include "BsFontManager.h"
-#include "BsRenderWindowManager.h"
-#include "BsCoreRenderer.h"
-#include "BsDeferredCallManager.h"
-#include "BsCoreThread.h"
-#include "BsStringTableManager.h"
-#include "BsProfilingManager.h"
-#include "BsProfilerCPU.h"
-#include "BsProfilerGPU.h"
-#include "BsQueryManager.h"
-#include "BsThreadPool.h"
-#include "BsTaskScheduler.h"
-#include "BsRenderStats.h"
-#include "BsMessageHandler.h"
-#include "BsResourceListenerManager.h"
-#include "BsRenderStateManager.h"
-#include "BsShaderManager.h"
-
-#include "BsMaterial.h"
-#include "BsShader.h"
-#include "BsTechnique.h"
-#include "BsPass.h"
-#include "BsRendererManager.h"
-
-namespace BansheeEngine
-{
-	CoreApplication::CoreApplication(START_UP_DESC desc)
-		:mPrimaryWindow(nullptr), mIsFrameRenderingFinished(true), mRunMainLoop(false), 
-		mRendererPlugin(nullptr), mSimThreadId(BS_THREAD_CURRENT_ID), mStartUpDesc(desc)
-	{ }
-
-	CoreApplication::~CoreApplication()
-	{
-		mPrimaryWindow->destroy();
-		mPrimaryWindow = nullptr;
-
-		Importer::shutDown();
-		FontManager::shutDown();
-		MaterialManager::shutDown();
-		MeshManager::shutDown();
-		ProfilerGPU::shutDown();
-
-		CoreSceneManager::shutDown();
-		
-		Input::shutDown();
-
-		StringTableManager::shutDown();
-		Resources::shutDown();
-		ResourceListenerManager::shutDown();
-		GameObjectManager::shutDown();
-		RenderStateManager::shutDown();
-
-		RendererManager::shutDown();
-
-		// All CoreObject related modules should be shut down now. They have likely queued CoreObjects for destruction, so
-		// we need to wait for those objects to get destroyed before continuing.
-		CoreObjectManager::instance().clearDirty();
-		gCoreThread().update();
-		gCoreThread().submitAccessors(true);
-
-		unloadPlugin(mRendererPlugin);
-
-		RenderAPIManager::shutDown();
-		GpuProgramCoreManager::shutDown();
-		GpuProgramManager::shutDown();
-
-		CoreObjectManager::shutDown(); // Must shut down before DynLibManager to ensure all objects are destroyed before unloading their libraries
-		DynLibManager::shutDown();
-		Time::shutDown();
-		DeferredCallManager::shutDown();
-
-		CoreThread::shutDown();
-		RenderStats::shutDown();
-		TaskScheduler::shutDown();
-		ThreadPool::shutDown();
-		ProfilingManager::shutDown();
-		ProfilerCPU::shutDown();
-		MessageHandler::shutDown();
-		ShaderManager::shutDown();
-
-		MemStack::endThread();
-		Platform::_shutDown();
-	}
-
-	void CoreApplication::onStartUp()
-	{
-		UINT32 numWorkerThreads = BS_THREAD_HARDWARE_CONCURRENCY - 1; // Number of cores while excluding current thread.
-
-		Platform::_startUp();
-		MemStack::beginThread();
-
-		ShaderManager::startUp(getShaderIncludeHandler());
-		MessageHandler::startUp();
-		ProfilerCPU::startUp();
-		ProfilingManager::startUp();
-		ThreadPool::startUp<TThreadPool<ThreadBansheePolicy>>((numWorkerThreads));
-		TaskScheduler::startUp();
-		TaskScheduler::instance().removeWorker();
-		RenderStats::startUp();
-		CoreThread::startUp();
-		StringTableManager::startUp();
-		DeferredCallManager::startUp();
-		Time::startUp();
-		DynLibManager::startUp();
-		CoreObjectManager::startUp();
-		GameObjectManager::startUp();
-		Resources::startUp();
-		ResourceListenerManager::startUp();
-		GpuProgramManager::startUp();
-		RenderStateManager::startUp();
-		GpuProgramCoreManager::startUp();
-		RenderAPIManager::startUp();
-
-		mPrimaryWindow = RenderAPIManager::instance().initialize(mStartUpDesc.renderAPI, mStartUpDesc.primaryWindowDesc);
-
-		Input::startUp();
-		RendererManager::startUp();
-
-		loadPlugin(mStartUpDesc.renderer, &mRendererPlugin);
-
-		SceneManagerFactory::create();
-		RendererManager::instance().setActive(mStartUpDesc.renderer);
-		startUpRenderer();
-
-		ProfilerGPU::startUp();
-		MeshManager::startUp();
-		MaterialManager::startUp();
-		FontManager::startUp();
-
-		Importer::startUp();
-
-		for (auto& importerName : mStartUpDesc.importers)
-			loadPlugin(importerName);
-
-		loadPlugin(mStartUpDesc.input, nullptr, mPrimaryWindow.get());
-	}
-
-	void CoreApplication::runMainLoop()
-	{
-		mRunMainLoop = true;
-
-		while(mRunMainLoop)
-		{
-			gProfilerCPU().beginThread("Sim");
-
-			Platform::_update();
-			DeferredCallManager::instance()._update();
-			gTime().update();
-			gInput()._update();
-			// RenderWindowManager::update needs to happen after Input::update and before Input::_triggerCallbacks,
-			// so that all input is properly captured in case there is a focus change, and so that
-			// focus change is registered before input events are sent out (mouse press can result in code
-			// checking if a window is in focus, so it has to be up to date)
-			RenderWindowManager::instance()._update(); 
-			gInput()._triggerCallbacks();
-			gDebug()._triggerCallbacks();
-
-			preUpdate();
-
-			PROFILE_CALL(gCoreSceneManager()._update(), "SceneManager");
-
-			gCoreThread().queueCommand(std::bind(&CoreApplication::beginCoreProfiling, this));
-			gCoreThread().queueCommand(std::bind(&RenderWindowCoreManager::_update, RenderWindowCoreManager::instancePtr()));
-			gCoreThread().queueCommand(std::bind(&QueryManager::_update, QueryManager::instancePtr()));
-
-			// Update plugins
-			for (auto& pluginUpdateFunc : mPluginUpdateFunctions)
-				pluginUpdateFunc.second();
-
-			postUpdate();
-
-			// Send out resource events in case any were loaded/destroyed/modified
-			ResourceListenerManager::instance().update();
-
-			gCoreSceneManager()._updateCoreObjectTransforms();
-			PROFILE_CALL(RendererManager::instance().getActive()->renderAll(), "Render");
-
-			// Core and sim thread run in lockstep. This will result in a larger input latency than if I was 
-			// running just a single thread. Latency becomes worse if the core thread takes longer than sim 
-			// thread, in which case sim thread needs to wait. Optimal solution would be to get an average 
-			// difference between sim/core thread and start the sim thread a bit later so they finish at nearly the same time.
-			{
-				BS_LOCK_MUTEX_NAMED(mFrameRenderingFinishedMutex, lock);
-
-				while(!mIsFrameRenderingFinished)
-				{
-					TaskScheduler::instance().addWorker();
-					BS_THREAD_WAIT(mFrameRenderingFinishedCondition, mFrameRenderingFinishedMutex, lock);
-					TaskScheduler::instance().removeWorker();
-				}
-
-				mIsFrameRenderingFinished = false;
-			}
-
-			gCoreThread().queueCommand(&Platform::_coreUpdate);
-
-			gCoreThread().update(); 
-			gCoreThread().submitAccessors(); 
-
-			gCoreThread().queueCommand(std::bind(&CoreApplication::endCoreProfiling, this));
-			gCoreThread().queueCommand(std::bind(&CoreApplication::frameRenderingFinishedCallback, this));
-
-			gProfilerCPU().endThread();
-			gProfiler()._update();
-		}
-
-		// Wait until last core frame is finished before exiting
-		{
-			BS_LOCK_MUTEX_NAMED(mFrameRenderingFinishedMutex, lock);
-
-			while (!mIsFrameRenderingFinished)
-			{
-				TaskScheduler::instance().addWorker();
-				BS_THREAD_WAIT(mFrameRenderingFinishedCondition, mFrameRenderingFinishedMutex, lock);
-				TaskScheduler::instance().removeWorker();
-			}
-		}
-	}
-
-	void CoreApplication::preUpdate()
-	{
-		// Do nothing
-	}
-
-	void CoreApplication::postUpdate()
-	{
-		// Do nothing
-	}
-
-	void CoreApplication::stopMainLoop()
-	{
-		mRunMainLoop = false; // No sync primitives needed, in that rare case of 
-		// a race condition we might run the loop one extra iteration which is acceptable
-	}
-
-	void CoreApplication::quitRequested()
-	{
-		stopMainLoop();
-	}
-
-	void CoreApplication::frameRenderingFinishedCallback()
-	{
-		BS_LOCK_MUTEX(mFrameRenderingFinishedMutex);
-
-		mIsFrameRenderingFinished = true;
-		BS_THREAD_NOTIFY_ONE(mFrameRenderingFinishedCondition);
-	}
-
-	void CoreApplication::startUpRenderer()
-	{
-		RendererManager::instance().initialize();
-	}
-
-	void CoreApplication::beginCoreProfiling()
-	{
-		gProfilerCPU().beginThread("Core");
-		ProfilerGPU::instance().beginFrame();
-	}
-
-	void CoreApplication::endCoreProfiling()
-	{
-		ProfilerGPU::instance().endFrame();
-		ProfilerGPU::instance()._update();
-
-		gProfilerCPU().endThread();
-		gProfiler()._updateCore();
-	}
-
-	void* CoreApplication::loadPlugin(const String& pluginName, DynLib** library, void* passThrough)
-	{
-		String name = pluginName;
-#if BS_PLATFORM == BS_PLATFORM_LINUX
-		if (name.substr(name.length() - 3, 3) != ".so")
-			name += ".so";
-#elif BS_PLATFORM == BS_PLATFORM_APPLE
-		if (name.substr(name.length() - 6, 6) != ".dylib")
-			name += ".dylib";
-#elif BS_PLATFORM == BS_PLATFORM_WIN32
-		// Although LoadLibraryEx will add .dll itself when you only specify the library name,
-		// if you include a relative path then it does not. So, add it to be sure.
-		if (name.substr(name.length() - 4, 4) != ".dll")
-			name += ".dll";
-#endif
-
-		DynLib* loadedLibrary = gDynLibManager().load(name);
-		if(library != nullptr)
-			*library = loadedLibrary;
-
-		void* retVal = nullptr;
-		if(loadedLibrary != nullptr)
-		{
-			if (passThrough == nullptr)
-			{
-				typedef void* (*LoadPluginFunc)();
-
-				LoadPluginFunc loadPluginFunc = (LoadPluginFunc)loadedLibrary->getSymbol("loadPlugin");
-
-				if (loadPluginFunc != nullptr)
-					retVal = loadPluginFunc();
-			}
-			else
-			{
-				typedef void* (*LoadPluginFunc)(void*);
-
-				LoadPluginFunc loadPluginFunc = (LoadPluginFunc)loadedLibrary->getSymbol("loadPlugin");
-
-				if (loadPluginFunc != nullptr)
-					retVal = loadPluginFunc(passThrough);
-			}
-
-			UpdatePluginFunc loadPluginFunc = (UpdatePluginFunc)loadedLibrary->getSymbol("updatePlugin");
-
-			if (loadPluginFunc != nullptr)
-				mPluginUpdateFunctions[loadedLibrary] = loadPluginFunc;
-		}
-
-		return retVal;
-	}
-
-	void CoreApplication::unloadPlugin(DynLib* library)
-	{
-		typedef void (*UnloadPluginFunc)();
-
-		UnloadPluginFunc unloadPluginFunc = (UnloadPluginFunc)library->getSymbol("unloadPlugin");
-
-		if(unloadPluginFunc != nullptr)
-			unloadPluginFunc();
-
-		mPluginUpdateFunctions.erase(library);
-		gDynLibManager().unload(library);
-	}
-
-	ShaderIncludeHandlerPtr CoreApplication::getShaderIncludeHandler() const
-	{
-		return bs_shared_ptr_new<DefaultShaderIncludeHandler>();
-	}
-
-	CoreApplication& gCoreApplication()
-	{
-		return CoreApplication::instance();
-	}
+#include "BsCoreApplication.h"
+
+#include "BsRenderAPI.h"
+#include "BsRenderAPIManager.h"
+
+#include "BsPlatform.h"
+#include "BsHardwareBufferManager.h"
+#include "BsRenderWindow.h"
+#include "BsViewport.h"
+#include "BsVector2.h"
+#include "BsGpuProgram.h"
+#include "BsCoreObjectManager.h"
+#include "BsGameObjectManager.h"
+#include "BsDynLib.h"
+#include "BsDynLibManager.h"
+#include "BsCoreSceneManager.h"
+#include "BsImporter.h"
+#include "BsResources.h"
+#include "BsMesh.h"
+#include "BsSceneObject.h"
+#include "BsTime.h"
+#include "BsInput.h"
+#include "BsRendererManager.h"
+#include "BsGpuProgramManager.h"
+#include "BsMeshManager.h"
+#include "BsMaterialManager.h"
+#include "BsFontManager.h"
+#include "BsRenderWindowManager.h"
+#include "BsCoreRenderer.h"
+#include "BsDeferredCallManager.h"
+#include "BsCoreThread.h"
+#include "BsStringTableManager.h"
+#include "BsProfilingManager.h"
+#include "BsProfilerCPU.h"
+#include "BsProfilerGPU.h"
+#include "BsQueryManager.h"
+#include "BsThreadPool.h"
+#include "BsTaskScheduler.h"
+#include "BsRenderStats.h"
+#include "BsMessageHandler.h"
+#include "BsResourceListenerManager.h"
+#include "BsRenderStateManager.h"
+#include "BsShaderManager.h"
+
+namespace BansheeEngine
+{
+	CoreApplication::CoreApplication(START_UP_DESC desc)
+		:mPrimaryWindow(nullptr), mIsFrameRenderingFinished(true), mRunMainLoop(false), 
+		mRendererPlugin(nullptr), mSimThreadId(BS_THREAD_CURRENT_ID), mStartUpDesc(desc)
+	{
+#if BS_DEBUG_MODE
+		IReflectable::_checkForCircularReferences();
+#endif
+	}
+
+	CoreApplication::~CoreApplication()
+	{
+		mPrimaryWindow->destroy();
+		mPrimaryWindow = nullptr;
+
+		Importer::shutDown();
+		FontManager::shutDown();
+		MaterialManager::shutDown();
+		MeshManager::shutDown();
+		ProfilerGPU::shutDown();
+
+		CoreSceneManager::shutDown();
+		
+		Input::shutDown();
+
+		StringTableManager::shutDown();
+		Resources::shutDown();
+		ResourceListenerManager::shutDown();
+		GameObjectManager::shutDown();
+		RenderStateManager::shutDown();
+
+		RendererManager::shutDown();
+
+		// All CoreObject related modules should be shut down now. They have likely queued CoreObjects for destruction, so
+		// we need to wait for those objects to get destroyed before continuing.
+		CoreObjectManager::instance().clearDirty();
+		gCoreThread().update();
+		gCoreThread().submitAccessors(true);
+
+		unloadPlugin(mRendererPlugin);
+
+		RenderAPIManager::shutDown();
+		GpuProgramCoreManager::shutDown();
+		GpuProgramManager::shutDown();
+
+		CoreObjectManager::shutDown(); // Must shut down before DynLibManager to ensure all objects are destroyed before unloading their libraries
+		DynLibManager::shutDown();
+		Time::shutDown();
+		DeferredCallManager::shutDown();
+
+		CoreThread::shutDown();
+		RenderStats::shutDown();
+		TaskScheduler::shutDown();
+		ThreadPool::shutDown();
+		ProfilingManager::shutDown();
+		ProfilerCPU::shutDown();
+		MessageHandler::shutDown();
+		ShaderManager::shutDown();
+
+		MemStack::endThread();
+		Platform::_shutDown();
+	}
+
+	void CoreApplication::onStartUp()
+	{
+		UINT32 numWorkerThreads = BS_THREAD_HARDWARE_CONCURRENCY - 1; // Number of cores while excluding current thread.
+
+		Platform::_startUp();
+		MemStack::beginThread();
+
+		ShaderManager::startUp(getShaderIncludeHandler());
+		MessageHandler::startUp();
+		ProfilerCPU::startUp();
+		ProfilingManager::startUp();
+		ThreadPool::startUp<TThreadPool<ThreadBansheePolicy>>((numWorkerThreads));
+		TaskScheduler::startUp();
+		TaskScheduler::instance().removeWorker();
+		RenderStats::startUp();
+		CoreThread::startUp();
+		StringTableManager::startUp();
+		DeferredCallManager::startUp();
+		Time::startUp();
+		DynLibManager::startUp();
+		CoreObjectManager::startUp();
+		GameObjectManager::startUp();
+		Resources::startUp();
+		ResourceListenerManager::startUp();
+		GpuProgramManager::startUp();
+		RenderStateManager::startUp();
+		GpuProgramCoreManager::startUp();
+		RenderAPIManager::startUp();
+
+		mPrimaryWindow = RenderAPIManager::instance().initialize(mStartUpDesc.renderAPI, mStartUpDesc.primaryWindowDesc);
+
+		Input::startUp();
+		RendererManager::startUp();
+
+		loadPlugin(mStartUpDesc.renderer, &mRendererPlugin);
+
+		SceneManagerFactory::create();
+		RendererManager::instance().setActive(mStartUpDesc.renderer);
+		startUpRenderer();
+
+		ProfilerGPU::startUp();
+		MeshManager::startUp();
+		MaterialManager::startUp();
+		FontManager::startUp();
+
+		Importer::startUp();
+
+		for (auto& importerName : mStartUpDesc.importers)
+			loadPlugin(importerName);
+
+		loadPlugin(mStartUpDesc.input, nullptr, mPrimaryWindow.get());
+	}
+
+	void CoreApplication::runMainLoop()
+	{
+		mRunMainLoop = true;
+
+		while(mRunMainLoop)
+		{
+			gProfilerCPU().beginThread("Sim");
+
+			Platform::_update();
+			DeferredCallManager::instance()._update();
+			gTime().update();
+			gInput()._update();
+			// RenderWindowManager::update needs to happen after Input::update and before Input::_triggerCallbacks,
+			// so that all input is properly captured in case there is a focus change, and so that
+			// focus change is registered before input events are sent out (mouse press can result in code
+			// checking if a window is in focus, so it has to be up to date)
+			RenderWindowManager::instance()._update(); 
+			gInput()._triggerCallbacks();
+			gDebug()._triggerCallbacks();
+
+			preUpdate();
+
+			PROFILE_CALL(gCoreSceneManager()._update(), "SceneManager");
+
+			gCoreThread().queueCommand(std::bind(&CoreApplication::beginCoreProfiling, this));
+			gCoreThread().queueCommand(std::bind(&RenderWindowCoreManager::_update, RenderWindowCoreManager::instancePtr()));
+			gCoreThread().queueCommand(std::bind(&QueryManager::_update, QueryManager::instancePtr()));
+
+			// Update plugins
+			for (auto& pluginUpdateFunc : mPluginUpdateFunctions)
+				pluginUpdateFunc.second();
+
+			postUpdate();
+
+			// Send out resource events in case any were loaded/destroyed/modified
+			ResourceListenerManager::instance().update();
+
+			gCoreSceneManager()._updateCoreObjectTransforms();
+			PROFILE_CALL(RendererManager::instance().getActive()->renderAll(), "Render");
+
+			// Core and sim thread run in lockstep. This will result in a larger input latency than if I was 
+			// running just a single thread. Latency becomes worse if the core thread takes longer than sim 
+			// thread, in which case sim thread needs to wait. Optimal solution would be to get an average 
+			// difference between sim/core thread and start the sim thread a bit later so they finish at nearly the same time.
+			{
+				BS_LOCK_MUTEX_NAMED(mFrameRenderingFinishedMutex, lock);
+
+				while(!mIsFrameRenderingFinished)
+				{
+					TaskScheduler::instance().addWorker();
+					BS_THREAD_WAIT(mFrameRenderingFinishedCondition, mFrameRenderingFinishedMutex, lock);
+					TaskScheduler::instance().removeWorker();
+				}
+
+				mIsFrameRenderingFinished = false;
+			}
+
+			gCoreThread().queueCommand(&Platform::_coreUpdate);
+
+			gCoreThread().update(); 
+			gCoreThread().submitAccessors(); 
+
+			gCoreThread().queueCommand(std::bind(&CoreApplication::endCoreProfiling, this));
+			gCoreThread().queueCommand(std::bind(&CoreApplication::frameRenderingFinishedCallback, this));
+
+			gProfilerCPU().endThread();
+			gProfiler()._update();
+		}
+
+		// Wait until last core frame is finished before exiting
+		{
+			BS_LOCK_MUTEX_NAMED(mFrameRenderingFinishedMutex, lock);
+
+			while (!mIsFrameRenderingFinished)
+			{
+				TaskScheduler::instance().addWorker();
+				BS_THREAD_WAIT(mFrameRenderingFinishedCondition, mFrameRenderingFinishedMutex, lock);
+				TaskScheduler::instance().removeWorker();
+			}
+		}
+	}
+
+	void CoreApplication::preUpdate()
+	{
+		// Do nothing
+	}
+
+	void CoreApplication::postUpdate()
+	{
+		// Do nothing
+	}
+
+	void CoreApplication::stopMainLoop()
+	{
+		mRunMainLoop = false; // No sync primitives needed, in that rare case of 
+		// a race condition we might run the loop one extra iteration which is acceptable
+	}
+
+	void CoreApplication::quitRequested()
+	{
+		stopMainLoop();
+	}
+
+	void CoreApplication::frameRenderingFinishedCallback()
+	{
+		BS_LOCK_MUTEX(mFrameRenderingFinishedMutex);
+
+		mIsFrameRenderingFinished = true;
+		BS_THREAD_NOTIFY_ONE(mFrameRenderingFinishedCondition);
+	}
+
+	void CoreApplication::startUpRenderer()
+	{
+		RendererManager::instance().initialize();
+	}
+
+	void CoreApplication::beginCoreProfiling()
+	{
+		gProfilerCPU().beginThread("Core");
+		ProfilerGPU::instance().beginFrame();
+	}
+
+	void CoreApplication::endCoreProfiling()
+	{
+		ProfilerGPU::instance().endFrame();
+		ProfilerGPU::instance()._update();
+
+		gProfilerCPU().endThread();
+		gProfiler()._updateCore();
+	}
+
+	void* CoreApplication::loadPlugin(const String& pluginName, DynLib** library, void* passThrough)
+	{
+		String name = pluginName;
+#if BS_PLATFORM == BS_PLATFORM_LINUX
+		if (name.substr(name.length() - 3, 3) != ".so")
+			name += ".so";
+#elif BS_PLATFORM == BS_PLATFORM_APPLE
+		if (name.substr(name.length() - 6, 6) != ".dylib")
+			name += ".dylib";
+#elif BS_PLATFORM == BS_PLATFORM_WIN32
+		// Although LoadLibraryEx will add .dll itself when you only specify the library name,
+		// if you include a relative path then it does not. So, add it to be sure.
+		if (name.substr(name.length() - 4, 4) != ".dll")
+			name += ".dll";
+#endif
+
+		DynLib* loadedLibrary = gDynLibManager().load(name);
+		if(library != nullptr)
+			*library = loadedLibrary;
+
+		void* retVal = nullptr;
+		if(loadedLibrary != nullptr)
+		{
+			if (passThrough == nullptr)
+			{
+				typedef void* (*LoadPluginFunc)();
+
+				LoadPluginFunc loadPluginFunc = (LoadPluginFunc)loadedLibrary->getSymbol("loadPlugin");
+
+				if (loadPluginFunc != nullptr)
+					retVal = loadPluginFunc();
+			}
+			else
+			{
+				typedef void* (*LoadPluginFunc)(void*);
+
+				LoadPluginFunc loadPluginFunc = (LoadPluginFunc)loadedLibrary->getSymbol("loadPlugin");
+
+				if (loadPluginFunc != nullptr)
+					retVal = loadPluginFunc(passThrough);
+			}
+
+			UpdatePluginFunc loadPluginFunc = (UpdatePluginFunc)loadedLibrary->getSymbol("updatePlugin");
+
+			if (loadPluginFunc != nullptr)
+				mPluginUpdateFunctions[loadedLibrary] = loadPluginFunc;
+		}
+
+		return retVal;
+	}
+
+	void CoreApplication::unloadPlugin(DynLib* library)
+	{
+		typedef void (*UnloadPluginFunc)();
+
+		UnloadPluginFunc unloadPluginFunc = (UnloadPluginFunc)library->getSymbol("unloadPlugin");
+
+		if(unloadPluginFunc != nullptr)
+			unloadPluginFunc();
+
+		mPluginUpdateFunctions.erase(library);
+		gDynLibManager().unload(library);
+	}
+
+	ShaderIncludeHandlerPtr CoreApplication::getShaderIncludeHandler() const
+	{
+		return bs_shared_ptr_new<DefaultShaderIncludeHandler>();
+	}
+
+	CoreApplication& gCoreApplication()
+	{
+		return CoreApplication::instance();
+	}
 }

+ 10 - 0
BansheeUtility/Include/BsIReflectable.h

@@ -74,6 +74,16 @@ namespace BansheeEngine
 		 */
 		static bool _isTypeIdDuplicate(UINT32 typeId);
 
+		/**
+		 * Iterates over all RTTI types and reports any circular references (e.g. one type having a field referencing
+		 * another type, and that type having a field referencing the first type). Circular references are problematic
+		 * because when serializing the system cannot determine in which order they should be resolved. In that case user
+		 * should use RTTI_Flag_WeakRef to mark one of the references as weak. This flags tells the system that the reference
+		 * may be resolved in an undefined order, but also no longer guarantees that object assigned to that field during
+		 * deserialization will be fully deserialized itself, as that might be delayed to a later time.
+		 */
+		static void _checkForCircularReferences();
+
 	protected:
 		Any mRTTIData; /**< Temporary per-instance data storage used during various RTTI operations.
 					    Needed since there is one RTTI class instance per type and sometimes we need per-instance data. */

+ 1 - 42
BansheeUtility/Include/BsRTTIType.h

@@ -140,7 +140,7 @@ namespace BansheeEngine
 		 * Called by the serializers when deserialization for this object has ended. At this point you can be sure the 
 		 * instance has been fully deserialized and you may safely use it.
 		 *
-		 * One exception being are fields you marked with "WeakRef" flag, as they might be resolved only after 
+		 * One exception being are fields you marked with RTTI_Flag_WeakRef, as they might be resolved only after 
 		 * deserialization has fully completed for all objects.
 		 */
 		virtual void onDeserializationEnded(IReflectable* obj) {}
@@ -486,41 +486,6 @@ namespace BansheeEngine
 		 */
 		void addNewField(RTTIField* field);
 
-		/**
-		 * Checks if the templated DataType has any references back to us, that aren't weak.
-		 * 			
-		 * @note	
-		 * This method assumes this class holds a non-weak reference to DataType. DataType must derive from IReflectable 
-		 * and implement getRTTIStatic method.
-		 */
-		template<class DataType>
-		void checkForCircularReferences()
-		{
-			RTTITypeBase* type = DataType::getRTTIStatic();
-
-			for(UINT32 i = 0; i < type->getNumFields(); i++)
-			{
-				RTTIField* field = type->getField(i);
-
-				if(!field->isReflectablePtrType())
-					continue;
-
-				RTTIReflectablePtrFieldBase* reflectablePtrField = static_cast<RTTIReflectablePtrFieldBase*>(field);
-
-				if(reflectablePtrField->getRTTIId() == getRTTIId() && ((reflectablePtrField->getFlags() & RTTI_Flag_WeakRef) == 0))
-				{
-					throwCircularRefException(getRTTIName(), reflectablePtrField->getRTTIName());
-				}
-			}
-		}
-
-		/**
-		 * Throws an exception warning the user that a circular reference was found. 
-		 *
-		 * @note Only a separate function so I don't need to include BsException header.
-		 */
-		void throwCircularRefException(const String& myType, const String& otherType) const;
-
 	private:
 		Vector<RTTIField*> mFields;
 	};
@@ -978,9 +943,6 @@ namespace BansheeEngine
 			static_assert((std::is_base_of<BansheeEngine::IReflectable, DataType>::value), 
 				"Invalid data type for complex field. It needs to derive from BansheeEngine::IReflectable.");
 
-			//if((flags & RTTI_Flag_WeakRef) == 0)
-			//	checkForCircularReferences<DataType>();
-
 			RTTIReflectablePtrField<DataType, ObjectType>* newField = 
 				bs_new<RTTIReflectablePtrField<DataType, ObjectType>>();
 			newField->initSingle(name, uniqueId, getter, setter, flags);
@@ -1017,9 +979,6 @@ namespace BansheeEngine
 			static_assert((std::is_base_of<BansheeEngine::IReflectable, DataType>::value), 
 				"Invalid data type for complex field. It needs to derive from BansheeEngine::IReflectable.");
 
-			//if((flags & RTTI_Flag_WeakRef) == 0)
-			//	checkForCircularReferences<DataType>();
-
 			RTTIReflectablePtrField<DataType, ObjectType>* newField = 
 				bs_new<RTTIReflectablePtrField<DataType, ObjectType>>();
 			newField->initArray(name, uniqueId, getter, getSize, setter, setSize, flags);

+ 123 - 73
BansheeUtility/Source/BsIReflectable.cpp

@@ -1,74 +1,124 @@
-#include "BsIReflectable.h"
-#include "BsRTTIType.h"
-#include "BsException.h"
-
-namespace BansheeEngine
-{
-	void IReflectable::_registerDerivedClass(RTTITypeBase* derivedClass)
-	{
-		if(_isTypeIdDuplicate(derivedClass->getRTTIId()))
-		{
-			BS_EXCEPT(InternalErrorException, "RTTI type \"" + derivedClass->getRTTIName() + 
-				"\" has a duplicate ID: " + toString(derivedClass->getRTTIId()));
-		}
-
-		getDerivedClasses().push_back(derivedClass);
-	}
-
-	std::shared_ptr<IReflectable> IReflectable::createInstanceFromTypeId(UINT32 rttiTypeId)
-	{
-		RTTITypeBase* type = _getRTTIfromTypeId(rttiTypeId);
-
-		if(type != nullptr)
-			return type->newRTTIObject();
-		
-		return nullptr;
-	}
-
-	RTTITypeBase* IReflectable::_getRTTIfromTypeId(UINT32 rttiTypeId)
-	{
-		Stack<RTTITypeBase*> todo;
-		Vector<RTTITypeBase*>& rootClasses = getDerivedClasses();
-
-		for(auto iter = rootClasses.begin(); iter != rootClasses.end(); ++iter)
-			todo.push(*iter);
-
-		while(!todo.empty())
-		{
-			RTTITypeBase* curType = todo.top();
-			todo.pop();
-
-			if(curType->getRTTIId() == rttiTypeId)
-				return curType;
-
-			Vector<RTTITypeBase*>& derivedClasses = curType->getDerivedClasses();
-			for(auto iter = derivedClasses.begin(); iter != derivedClasses.end(); ++iter)
-				todo.push(*iter);
-		}
-
-		return nullptr;
-	}
-
-	bool IReflectable::_isTypeIdDuplicate(UINT32 typeId)
-	{
-		if(typeId == TID_Abstract)
-			return false;
-
-		return IReflectable::_getRTTIfromTypeId(typeId) != nullptr;
-	}
-
-	bool IReflectable::isDerivedFrom(RTTITypeBase* base)
-	{
-		return getRTTI()->isDerivedFrom(base);
-	}
-
-	UINT32 IReflectable::getTypeId() const
-	{ 
-		return getRTTI()->getRTTIId(); 
-	}
-
-	const String& IReflectable::getTypeName() const
-	{
-		return getRTTI()->getRTTIName();
-	}
+#include "BsIReflectable.h"
+#include "BsRTTIType.h"
+#include "BsException.h"
+
+namespace BansheeEngine
+{
+	void IReflectable::_registerDerivedClass(RTTITypeBase* derivedClass)
+	{
+		if(_isTypeIdDuplicate(derivedClass->getRTTIId()))
+		{
+			BS_EXCEPT(InternalErrorException, "RTTI type \"" + derivedClass->getRTTIName() + 
+				"\" has a duplicate ID: " + toString(derivedClass->getRTTIId()));
+		}
+
+		getDerivedClasses().push_back(derivedClass);
+	}
+
+	std::shared_ptr<IReflectable> IReflectable::createInstanceFromTypeId(UINT32 rttiTypeId)
+	{
+		RTTITypeBase* type = _getRTTIfromTypeId(rttiTypeId);
+
+		if(type != nullptr)
+			return type->newRTTIObject();
+		
+		return nullptr;
+	}
+
+	RTTITypeBase* IReflectable::_getRTTIfromTypeId(UINT32 rttiTypeId)
+	{
+		Stack<RTTITypeBase*> todo;
+		Vector<RTTITypeBase*>& rootClasses = getDerivedClasses();
+
+		for(auto iter = rootClasses.begin(); iter != rootClasses.end(); ++iter)
+			todo.push(*iter);
+
+		while(!todo.empty())
+		{
+			RTTITypeBase* curType = todo.top();
+			todo.pop();
+
+			if(curType->getRTTIId() == rttiTypeId)
+				return curType;
+
+			Vector<RTTITypeBase*>& derivedClasses = curType->getDerivedClasses();
+			for(auto iter = derivedClasses.begin(); iter != derivedClasses.end(); ++iter)
+				todo.push(*iter);
+		}
+
+		return nullptr;
+	}
+
+	bool IReflectable::_isTypeIdDuplicate(UINT32 typeId)
+	{
+		if(typeId == TID_Abstract)
+			return false;
+
+		return IReflectable::_getRTTIfromTypeId(typeId) != nullptr;
+	}
+
+	bool IReflectable::isDerivedFrom(RTTITypeBase* base)
+	{
+		return getRTTI()->isDerivedFrom(base);
+	}
+
+	void IReflectable::_checkForCircularReferences()
+	{
+		Stack<RTTITypeBase*> todo;
+
+		Vector<RTTITypeBase*> rootTypes = getDerivedClasses();
+		for (auto& entry : rootTypes)
+			todo.push(entry);
+
+		while(!todo.empty())
+		{
+			RTTITypeBase* myType = todo.top();
+			todo.pop();
+
+			UINT32 myNumFields = myType->getNumFields();
+			for (UINT32 i = 0; i < myNumFields; i++)
+			{
+				RTTIField* myField = myType->getField(i);
+
+				if (!myField->isReflectablePtrType())
+					continue;
+
+				RTTIReflectablePtrFieldBase* myReflectablePtrField = static_cast<RTTIReflectablePtrFieldBase*>(myField);
+				
+				RTTITypeBase* otherType = myReflectablePtrField->getType();
+				UINT32 otherNumFields = otherType->getNumFields();
+				for (UINT32 j = 0; j < otherNumFields; j++)
+				{
+					RTTIField* otherField = otherType->getField(j);
+
+					if (!otherField->isReflectablePtrType())
+						continue;
+
+					RTTIReflectablePtrFieldBase* otherReflectablePtrField = static_cast<RTTIReflectablePtrFieldBase*>(otherField);
+
+					RTTITypeBase* a = myReflectablePtrField->getType();
+					RTTITypeBase* b = otherReflectablePtrField->getType();
+
+					if (myType->getRTTIId() == otherReflectablePtrField->getType()->getRTTIId() &&
+						(myReflectablePtrField->getFlags() & RTTI_Flag_WeakRef) == 0 &&
+						(otherReflectablePtrField->getFlags() & RTTI_Flag_WeakRef) == 0)
+					{
+						BS_EXCEPT(InternalErrorException, "Found circular reference on RTTI type: " + myType->getRTTIName()
+							+ " to type: " + otherType->getRTTIName() + ". Either remove one of the references or mark it" 
+							+ " as a weak reference when defining the RTTI field.");
+					}
+				}
+			}
+		}
+	}
+
+	UINT32 IReflectable::getTypeId() const
+	{ 
+		return getRTTI()->getRTTIId(); 
+	}
+
+	const String& IReflectable::getTypeName() const
+	{
+		return getRTTI()->getRTTIName();
+	}
 }

+ 72 - 78
BansheeUtility/Source/BsRTTIType.cpp

@@ -1,79 +1,73 @@
-#include "BsRTTIType.h"
-#include "BsException.h"
-
-namespace BansheeEngine
-{
-	RTTITypeBase::RTTITypeBase()
-	{ }
-
-	RTTITypeBase::~RTTITypeBase() 
-	{
-		for(auto iter = mFields.begin(); iter != mFields.end(); ++iter)
-			bs_delete(*iter);
-
-		mFields.clear();
-	}
-
-	RTTIField* RTTITypeBase::findField(const String& name)
-	{
-		auto foundElement = std::find_if(mFields.begin(), mFields.end(), [&name](RTTIField* x) { return x->mName == name; });
-
-		if(foundElement == mFields.end())
-		{
-			BS_EXCEPT(InternalErrorException, 
-				"Cannot find a field with the specified name: " + name);
-		}
-
-		return *foundElement;
-	}
-
-	RTTIField* RTTITypeBase::findField(int uniqueFieldId)
-	{
-		auto foundElement = std::find_if(mFields.begin(), mFields.end(), [&uniqueFieldId](RTTIField* x) { return x->mUniqueId == uniqueFieldId; });
-
-		if(foundElement == mFields.end())
-			return nullptr;
-
-		return *foundElement;
-	}
-
-	void RTTITypeBase::addNewField(RTTIField* field)
-	{
-		if(field == nullptr)
-		{
-			BS_EXCEPT(InvalidParametersException, 
-				"Field argument can't be null.");
-		}
-
-		int uniqueId = field->mUniqueId;
-		auto foundElementById = std::find_if(mFields.begin(), mFields.end(), [uniqueId](RTTIField* x) { return x->mUniqueId == uniqueId; });
-
-		if(foundElementById != mFields.end())
-		{
-			BS_EXCEPT(InternalErrorException, 
-				"Field with the same ID already exists.");
-		}
-
-		String& name = field->mName;
-		auto foundElementByName = std::find_if(mFields.begin(), mFields.end(), [&name](RTTIField* x) { return x->mName == name; });
-
-		if(foundElementByName != mFields.end())
-		{
-			BS_EXCEPT(InternalErrorException, 
-				"Field with the same name already exists.");
-		}
-
-		mFields.push_back(field);
-	}
-
-	void RTTITypeBase::throwCircularRefException(const String& myType, const String& otherType) const
-	{
-		BS_EXCEPT(InternalErrorException, "Found circular reference on RTTI type: " + myType + " to type: " + otherType + "."
-			+ " Either remove one of the references or mark it as a weak reference when defining the RTTI field.");
-	}
-
-	std::shared_ptr<IReflectable> rtti_create(UINT32 rttiId)
-	{
-		return IReflectable::createInstanceFromTypeId(rttiId);
-	}
+#include "BsRTTIType.h"
+#include "BsException.h"
+
+namespace BansheeEngine
+{
+	RTTITypeBase::RTTITypeBase()
+	{ }
+
+	RTTITypeBase::~RTTITypeBase() 
+	{
+		for(auto iter = mFields.begin(); iter != mFields.end(); ++iter)
+			bs_delete(*iter);
+
+		mFields.clear();
+	}
+
+	RTTIField* RTTITypeBase::findField(const String& name)
+	{
+		auto foundElement = std::find_if(mFields.begin(), mFields.end(), [&name](RTTIField* x) { return x->mName == name; });
+
+		if(foundElement == mFields.end())
+		{
+			BS_EXCEPT(InternalErrorException, 
+				"Cannot find a field with the specified name: " + name);
+		}
+
+		return *foundElement;
+	}
+
+	RTTIField* RTTITypeBase::findField(int uniqueFieldId)
+	{
+		auto foundElement = std::find_if(mFields.begin(), mFields.end(), [&uniqueFieldId](RTTIField* x) { return x->mUniqueId == uniqueFieldId; });
+
+		if(foundElement == mFields.end())
+			return nullptr;
+
+		return *foundElement;
+	}
+
+	void RTTITypeBase::addNewField(RTTIField* field)
+	{
+		if(field == nullptr)
+		{
+			BS_EXCEPT(InvalidParametersException, 
+				"Field argument can't be null.");
+		}
+
+		int uniqueId = field->mUniqueId;
+		auto foundElementById = std::find_if(mFields.begin(), mFields.end(), [uniqueId](RTTIField* x) { return x->mUniqueId == uniqueId; });
+
+		if(foundElementById != mFields.end())
+		{
+			BS_EXCEPT(InternalErrorException, 
+				"Field with the same ID already exists.");
+		}
+
+		String& name = field->mName;
+		auto foundElementByName = std::find_if(mFields.begin(), mFields.end(), [&name](RTTIField* x) { return x->mName == name; });
+
+		if(foundElementByName != mFields.end())
+		{
+			BS_EXCEPT(InternalErrorException, 
+				"Field with the same name already exists.");
+		}
+
+		mFields.push_back(field);
+	}
+
+	std::shared_ptr<IReflectable> rtti_create(UINT32 rttiId)
+	{
+		return IReflectable::createInstanceFromTypeId(rttiId);
+	}
 }