Browse Source

Added ResourceManifest for dealing with resource UUIDs

Marko Pintera 12 years ago
parent
commit
e2e58a800a

+ 1 - 1
BansheeEngine/Include/BsApplication.h

@@ -15,7 +15,7 @@ namespace BansheeEngine
 			 * @brief	Starts the application using the specified options. 
 			 * 			This is how you start the engine.
 			 */
-			void startUp(CM::RENDER_WINDOW_DESC& primaryWindowDesc, const CM::String& renderSystem, const CM::String& renderer, const CM::WString& resourceCacheDir);
+			void startUp(CM::RENDER_WINDOW_DESC& primaryWindowDesc, const CM::String& renderSystem, const CM::String& renderer);
 
 			/**
 			 * @brief	Executes the main loop. This will cause actually rendering to be performed

+ 1 - 2
BansheeEngine/Source/BsApplication.cpp

@@ -23,12 +23,11 @@ namespace BansheeEngine
 
 	}
 
-	void Application::startUp(RENDER_WINDOW_DESC& primaryWindowDesc, const String& renderSystem, const String& renderer, const WString& resourceCacheDir)
+	void Application::startUp(RENDER_WINDOW_DESC& primaryWindowDesc, const String& renderSystem, const String& renderer)
 	{
 		CM::START_UP_DESC desc;
 		desc.renderSystem = renderSystem;
 		desc.renderer= renderer;
-		desc.resourceCacheDirectory = resourceCacheDir;
 		desc.primaryWindowDesc = primaryWindowDesc;
 
 		desc.input = "CamelotOISInput";

+ 6 - 6
CamelotClient/Source/BsEditorApplication.cpp

@@ -40,7 +40,7 @@ namespace BansheeEditor
 		renderWindowDesc.border = WindowBorder::None;
 
 		const String& renderSystemLibraryName = getLibraryNameForRenderSystem(renderSystemPlugin);
-		gBansheeApp().startUp(renderWindowDesc, renderSystemLibraryName, "BansheeForwardRenderer", L"D:\\CamelotResourceMetas"); // TODO - Make renderer and resource cache dir customizable
+		gBansheeApp().startUp(renderWindowDesc, renderSystemLibraryName, "BansheeForwardRenderer"); // TODO - Make renderer and resource cache dir customizable
 		EditorGUI::startUp(cm_new<EditorGUI>());
 
 		{
@@ -140,11 +140,11 @@ namespace BansheeEditor
 
 		HHighLevelGpuProgram vertProgRef = Importer::instance().import(vsLoc, gpuProgImportOptions);
 
-		gResources().create(vertProgRef, L"C:\\vertProgCg.vprog", true);
+		gResources().save(vertProgRef, L"C:\\vertProgCg.vprog", true);
 		gResources().unload(vertProgRef);
 		vertProgRef = gResources().load(L"C:\\vertProgCg.vprog");
 
-		gResources().create(fragProgRef, L"C:\\fragProgCg.vprog", true);
+		gResources().save(fragProgRef, L"C:\\fragProgCg.vprog", true);
 		gResources().unload(fragProgRef);
 		fragProgRef = gResources().load(L"C:\\fragProgCg.vprog");
 
@@ -197,8 +197,8 @@ namespace BansheeEditor
 		HTexture testTexRef = static_resource_cast<Texture>(Importer::instance().import(L"C:\\ArenaTowerDFS.psd"));
 		HMesh dbgMeshRef = static_resource_cast<Mesh>(Importer::instance().import(L"C:\\X_Arena_Tower.FBX"));
 
-		gResources().create(testTexRef, L"C:\\ExportTest.tex", true);
-		gResources().create(dbgMeshRef, L"C:\\ExportMesh.mesh", true);
+		gResources().save(testTexRef, L"C:\\ExportTest.tex", true);
+		gResources().save(dbgMeshRef, L"C:\\ExportMesh.mesh", true);
 
 		gResources().unload(testTexRef);
 		gResources().unload(dbgMeshRef);
@@ -210,7 +210,7 @@ namespace BansheeEditor
 		testTexRef.synchronize();
 
 		testMaterial->setTexture("tex", testTexRef);
-		gResources().create(testMaterial, L"C:\\ExportMaterial.mat", true);
+		gResources().save(testMaterial, L"C:\\ExportMaterial.mat", true);
 
 		gResources().unload(testMaterial);
 

+ 3 - 1
CamelotCore/CamelotCore.vcxproj

@@ -305,6 +305,8 @@
     <ClInclude Include="Include\CmQueryManager.h" />
     <ClInclude Include="Include\CmRenderOperation.h" />
     <ClInclude Include="Include\CmRenderQueue.h" />
+    <ClInclude Include="Include\CmResourceManifest.h" />
+    <ClInclude Include="Include\CmResourceManifestRTTI.h" />
     <ClInclude Include="Include\CmSceneObjectRTTI.h" />
     <ClInclude Include="Include\CmMemAllocCategories.h" />
     <ClInclude Include="Include\CmApplication.h" />
@@ -388,7 +390,6 @@
     <ClInclude Include="Include\CmResourceHandle.h" />
     <ClInclude Include="Include\CmResourceHandleRTTI.h" />
     <ClInclude Include="Include\CmResources.h" />
-    <ClInclude Include="Include\CmResourcesRTTI.h" />
     <ClInclude Include="Include\CmSamplerStateRTTI.h" />
     <ClInclude Include="Include\CmSceneManager.h" />
     <ClInclude Include="Include\CmShaderRTTI.h" />
@@ -476,6 +477,7 @@
     <ClCompile Include="Source\CmQueryManager.cpp" />
     <ClCompile Include="Source\CmRenderer.cpp" />
     <ClCompile Include="Source\CmRenderQueue.cpp" />
+    <ClCompile Include="Source\CmResourceManifest.cpp" />
     <ClCompile Include="Source\CmTextureView.cpp" />
     <ClCompile Include="Source\CmTextData.cpp" />
     <ClCompile Include="Source\CmTimerQuery.cpp" />

+ 9 - 3
CamelotCore/CamelotCore.vcxproj.filters

@@ -234,9 +234,6 @@
     <ClInclude Include="Include\CmCgProgramRTTI.h">
       <Filter>Header Files\RTTI</Filter>
     </ClInclude>
-    <ClInclude Include="Include\CmResourcesRTTI.h">
-      <Filter>Header Files\RTTI</Filter>
-    </ClInclude>
     <ClInclude Include="Include\CmPassRTTI.h">
       <Filter>Header Files\RTTI</Filter>
     </ClInclude>
@@ -531,6 +528,12 @@
     <ClInclude Include="Include\CmGameObjectHandleRTTI.h">
       <Filter>Header Files\RTTI</Filter>
     </ClInclude>
+    <ClInclude Include="Include\CmResourceManifest.h">
+      <Filter>Header Files\Resources</Filter>
+    </ClInclude>
+    <ClInclude Include="Include\CmResourceManifestRTTI.h">
+      <Filter>Header Files\RTTI</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\CmApplication.cpp">
@@ -833,5 +836,8 @@
     <ClCompile Include="Source\CmGameObjectManager.cpp">
       <Filter>Source Files\Scene</Filter>
     </ClCompile>
+    <ClCompile Include="Source\CmResourceManifest.cpp">
+      <Filter>Source Files\Resources</Filter>
+    </ClCompile>
   </ItemGroup>
 </Project>

+ 0 - 2
CamelotCore/Include/CmApplication.h

@@ -27,8 +27,6 @@ namespace CamelotFramework
 		RENDER_WINDOW_DESC primaryWindowDesc;
 
 		Vector<String>::type importers;
-
-		WString resourceCacheDirectory;
 	};
 
 	class CM_EXPORT Application

+ 0 - 2
CamelotCore/Include/CmGpuProgramRTTI.h

@@ -10,7 +10,6 @@ namespace CamelotFramework
 	{
 	private:
 		CM_SETGET_MEMBER(mSize, UINT32, GpuProgram)
-		CM_SETGET_MEMBER(mUUID, String, GpuProgram);
 
 		CM_SETGET_MEMBER(mType, GpuProgramType, GpuProgram);
 		CM_SETGET_MEMBER(mNeedsAdjacencyInfo, bool, GpuProgram);
@@ -23,7 +22,6 @@ namespace CamelotFramework
 		GpuProgramRTTI()
 		{
 			CM_ADD_PLAINFIELD(mSize, 0, GpuProgramRTTI)
-			CM_ADD_PLAINFIELD(mUUID, 1, GpuProgramRTTI)
 
 			CM_ADD_PLAINFIELD(mType, 2, GpuProgramRTTI)
 			CM_ADD_PLAINFIELD(mNeedsAdjacencyInfo, 3, GpuProgramRTTI)

+ 5 - 2
CamelotCore/Include/CmPrerequisites.h

@@ -138,6 +138,7 @@ namespace CamelotFramework
 	// Resources
 	class Resource;
 	class Resources;
+	class ResourceManifest;
 	class Texture;
 	class Mesh;
 	class MeshBase;
@@ -221,6 +222,7 @@ namespace CamelotFramework
 	typedef std::shared_ptr<CoreThreadAccessor<CommandQueueSync>> SyncedCoreAccessorPtr;
 	typedef std::shared_ptr<EventQuery> EventQueryPtr;
 	typedef std::shared_ptr<TimerQuery> TimerQueryPtr;
+	typedef std::shared_ptr<ResourceManifest> ResourceManifestPtr;
 }
 
 /************************************************************************/
@@ -240,7 +242,6 @@ namespace CamelotFramework
 		TID_GpuProgram = 1010,
 		TID_ResourceHandleData = 1011,
 		TID_CgProgram = 1012,
-		TID_ResourceMetaData = 1013,
 		TID_Pass = 1014,
 		TID_Technique = 1015,
 		TID_Shader = 1016,
@@ -282,7 +283,9 @@ namespace CamelotFramework
 		TID_GpuResourceData = 1063,
 		TID_VertexDataDesc = 1064,
 		TID_MeshBase = 1065,
-		TID_GameObjectHandleBase = 1066
+		TID_GameObjectHandleBase = 1066,
+		TID_ResourceManifest = 1067,
+		TID_ResourceManifestEntry = 1068
 	};
 }
 

+ 0 - 3
CamelotCore/Include/CmResource.h

@@ -15,8 +15,6 @@ namespace CamelotFramework
 		Resource(bool requiresGpuInitialization = true);
 		virtual ~Resource() {};
 
-		const String& getUUID() const { return mUUID; }
-
 		/**
 		 * @brief	Creates a new resource handle. Should only be called by internal methods.
 		 */
@@ -25,7 +23,6 @@ namespace CamelotFramework
 	protected:
 		friend class Resources;
 
-		String mUUID; 
 		UINT32 mSize;
 
 	/************************************************************************/

+ 5 - 5
CamelotCore/Include/CmResourceHandle.h

@@ -55,7 +55,7 @@ namespace CamelotFramework
 		 * 			
 		 * @note	Two set construction is sometimes required due to multithreaded nature of resource loading.
 		 */
-		void setResourcePtr(std::shared_ptr<Resource> ptr);
+		void setHandleData(std::shared_ptr<Resource> ptr, const String& uuid);
 
 	private:
 		friend class Resources;
@@ -143,18 +143,18 @@ namespace CamelotFramework
 	private:
 		friend class Resource;
 
-		explicit ResourceHandle(T* ptr)
+		explicit ResourceHandle(T* ptr, const String& uuid)
 			:ResourceHandleBase()
 		{
 			mData = cm_shared_ptr<ResourceHandleData, PoolAlloc>();
-			setResourcePtr(std::shared_ptr<Resource>(ptr));
+			setHandleData(std::shared_ptr<Resource>(ptr, uuid));
 		}
 
-		ResourceHandle(std::shared_ptr<T> ptr)
+		ResourceHandle(std::shared_ptr<T> ptr, const String& uuid)
 			:ResourceHandleBase()
 		{
 			mData = cm_shared_ptr<ResourceHandleData, PoolAlloc>();
-			setResourcePtr(ptr);
+			setHandleData(ptr, uuid);
 		}
 	};
 

+ 1 - 1
CamelotCore/Include/CmResourceHandleRTTI.h

@@ -35,7 +35,7 @@ namespace CamelotFramework
 				HResource loadedResource = gResources().loadFromUUID(resourceHandle->mData->mUUID);
 
 				if(loadedResource)
-					resourceHandle->setResourcePtr(loadedResource.getInternalPtr());
+					resourceHandle->setHandleData(loadedResource.getInternalPtr(), resourceHandle->mData->mUUID);
 			}
 		}
 

+ 40 - 0
CamelotCore/Include/CmResourceManifest.h

@@ -0,0 +1,40 @@
+#pragma once
+
+#include "CmPrerequisites.h"
+#include "CmIReflectable.h"
+
+namespace CamelotFramework
+{
+	/**
+	 * @brief	Serializable class that contains UUID <-> file path mapping for resources.
+	 * 			
+	 * @note	This class allows you to reference resources between sessions. At the end of a session
+	 * 			save the resource manifest, and then restore it at the start of your session. This way
+	 * 			ensures that resource UUIDs stay consistent and anything referencing them can find the
+	 * 			resources.
+	 */
+	class CM_EXPORT ResourceManifest : public IReflectable
+	{
+	public:
+		void registerResource(const String& uuid, const WString& filePath);
+		void unregisterResource(const String& uuid);
+
+		const WString& uuidToFilePath(const String& uuid) const;
+		const String& filePathToUUID(const WString& filePath) const;
+
+		bool uuidExists(const String& uuid) const;
+		bool filePathExists(const WString& filePath) const;
+
+	private:
+		Map<String, WString>::type mUUIDToFilePath;
+		Map<WString, String>::type mFilePathToUUID;
+
+		/************************************************************************/
+		/* 								RTTI		                     		*/
+		/************************************************************************/
+	public:
+		friend class ResourceManifestRTTI;
+		static RTTITypeBase* getRTTIStatic();
+		virtual RTTITypeBase* getRTTI() const;
+	};
+}

+ 95 - 0
CamelotCore/Include/CmResourceManifestRTTI.h

@@ -0,0 +1,95 @@
+#pragma once
+
+#include "CmPrerequisites.h"
+#include "CmRTTIType.h"
+#include "CmResourceManifest.h"
+
+namespace CamelotFramework
+{
+	struct ResourceManifestEntry
+	{
+		String uuid;
+		WString path;
+	};
+
+	template<> struct RTTIPlainType<ResourceManifestEntry>
+	{	
+		enum { id = TID_ResourceManifestEntry }; enum { hasDynamicSize = 1 };
+
+		static void toMemory(const ResourceManifestEntry& data, char* memory)
+		{ 
+			UINT32 size = getDynamicSize(data);
+
+			memcpy(memory, &size, sizeof(UINT32));
+			memory += sizeof(UINT32);
+
+			rttiWriteElem(data.uuid, memory);
+			rttiWriteElem(data.path, memory);
+		}
+
+		static UINT32 fromMemory(ResourceManifestEntry& data, char* memory)
+		{ 
+			UINT32 size;
+			memcpy(&size, memory, sizeof(UINT32)); 
+			memory += sizeof(UINT32);
+
+			rttiReadElem(data.uuid, memory);
+			rttiReadElem(data.path, memory);
+
+			return size;
+		}
+
+		static UINT32 getDynamicSize(const ResourceManifestEntry& data)	
+		{ 
+			UINT64 dataSize = sizeof(UINT32);
+			dataSize += rttiGetElemSize(data.uuid);
+			dataSize += rttiGetElemSize(data.path);
+
+			return (UINT32)dataSize;
+		}	
+	}; 
+
+	class CM_EXPORT ResourceManifestRTTI : public RTTIType<ResourceManifest, IReflectable, ResourceManifestRTTI>
+	{
+	private:
+		Map<String, WString>::type& getUUIDMap(ResourceManifest* obj) 
+		{ 
+			return obj->mUUIDToFilePath;
+		}
+
+		void setUUIDMap(ResourceManifest* obj, Map<String, WString>::type& val) 
+		{ 
+			obj->mUUIDToFilePath = val; 
+
+			obj->mFilePathToUUID.clear();
+
+			for(auto& entry : obj->mUUIDToFilePath)
+			{
+				obj->mFilePathToUUID[entry.second] = entry.first;
+			}
+		} 
+	public:
+		ResourceManifestRTTI()
+		{
+			addPlainField("mUUIDToFilePath", 0, &ResourceManifestRTTI::getUUIDMap, &ResourceManifestRTTI::setUUIDMap);
+		}
+
+		virtual const String& getRTTIName()
+		{
+			static String name = "ResourceManifest";
+			return name;
+		}
+
+		virtual UINT32 getRTTIId()
+		{
+			return TID_ResourceManifest;
+		}
+
+		virtual std::shared_ptr<IReflectable> newRTTIObject()
+		{
+			std::shared_ptr<ResourceManifest> obj = cm_shared_ptr<ResourceManifest>();
+
+			return obj;
+		}
+	};
+}

+ 0 - 3
CamelotCore/Include/CmResourceRTTI.h

@@ -11,14 +11,11 @@ namespace CamelotFramework
 	private:
 		UINT32& getSize(Resource* obj) { return obj->mSize; }
 		void setSize(Resource* obj, UINT32& size) { obj->mSize = size; } 
-		String& getUUID(Resource* obj) { return obj->mUUID; }
-		void setUUID(Resource* obj, String& uuid) { obj->mUUID = uuid; }
 
 	public:
 		ResourceRTTI()
 		{
 			addPlainField("Size", 0, &ResourceRTTI::getSize, &ResourceRTTI::setSize);
-			addPlainField("UUID", 1, &ResourceRTTI::getUUID, &ResourceRTTI::setUUID);
 		}
 
 		virtual const String& getRTTIName()

+ 22 - 41
CamelotCore/Include/CmResources.h

@@ -48,7 +48,7 @@ namespace CamelotFramework
 		 * @param	resMetaPath		Folder where the resource meta-data will be stored. If the folder doesn't exist
 		 * 							it will be created.
 		 */
-		Resources(const WString& metaDataFolder);
+		Resources();
 		~Resources();
 
 		/**
@@ -110,42 +110,36 @@ namespace CamelotFramework
 		void unloadAllUnused();
 
 		/**
-		 * @brief	Saves the resource. Resource must be registered using Resources::create beforehand.
-		 *
-		 * @param	resource   	The resource.
-		 */
-		void save(HResource resource);
-
-		/**
-		 * @brief	Creates a new resource at the specified location. Throws an exception if resource
-		 * 			already exists. Automatically calls Resources::save.
+		 * @brief	Saves the resource at the specified location.
 		 *
 		 * @param	resource 	Handle to the resource.
 		 * @param	filePath 	Full pathname of the file.
 		 * @param	overwrite	(optional) If true, any existing resource at the specified location will
 		 * 						be overwritten.
 		 */
-		void create(HResource resource, const WString& filePath, bool overwrite = false);
+		void save(HResource resource, const WString& filePath, bool overwrite);
 
-	public:
-		struct ResourceMetaData : public IReflectable
-		{
-			String mUUID;
-			WString mPath;
-
-			/************************************************************************/
-			/* 								SERIALIZATION                      		*/
-			/************************************************************************/
-		public:
-			friend class ResourceMetaDataRTTI;
-			static RTTITypeBase* getRTTIStatic();
-			virtual RTTITypeBase* getRTTI() const;
-		};
+		/**
+		 * @brief	Allows you to set a resource manifest containing UUID <-> file path mapping that is
+		 * 			used when resolving resource references.
+		 *
+		 * @note	If you want objects that reference resources (using ResourceHandles) to be able to
+		 * 			find that resource even after application restart, then you must save the resource
+		 * 			manifest before closing the application and restore it upon startup.
+		 * 			Otherwise resources will be assigned brand new UUIDs and references will be broken.
+		 */
+		void setResourceManifest(const ResourceManifestPtr& manifest) { mResourceManifest = manifest; }
+
+		/**
+		 * @brief	Allows you to retrieve resource manifest containing UUID <-> file path mapping that is
+		 * 			used when resolving resource references.
+		 *
+		 * @see		setResourceManifest
+		 */
+		ResourceManifestPtr getResourceManifest() const { return mResourceManifest; }
 
 	private:
-		typedef std::shared_ptr<ResourceMetaData> ResourceMetaDataPtr;
-		Map<String, ResourceMetaDataPtr>::type mResourceMetaData;
-		Map<WString, ResourceMetaDataPtr>::type mResourceMetaData_FilePath;
+		ResourceManifestPtr mResourceManifest;
 
 		CM_MUTEX(mInProgressResourcesMutex);
 		CM_MUTEX(mLoadedResourceMutex);
@@ -162,24 +156,11 @@ namespace CamelotFramework
 		HResource loadInternal(const WString& filePath, bool synchronous); 
 		ResourcePtr loadFromDiskAndDeserialize(const WString& filePath);
 
-		void loadMetaData();
-		void saveMetaData(const ResourceMetaDataPtr metaData);
-
-		void createMetaData(const String& uuid, const WString& filePath);
-		void addMetaData(const String& uuid, const WString& filePath);
-		void updateMetaData(const String& uuid, const WString& newFilePath);
-		void removeMetaData(const String& uuid);
-
-		bool metaExists_UUID(const String& uuid) const;
-		bool metaExists_Path(const WString& path) const;
-
 		const WString& getPathFromUUID(const String& uuid) const;
 		const String& getUUIDFromPath(const WString& path) const;
 
 		void notifyResourceLoadingFinished(HResource& handle);
 		void notifyNewResourceLoaded(HResource& handle);
-
-		WString mMetaDataFolderPath;
 	};
 
 	CM_EXPORT Resources& gResources();

+ 0 - 40
CamelotCore/Include/CmResourcesRTTI.h

@@ -1,40 +0,0 @@
-#pragma once
-
-#include "CmPrerequisites.h"
-#include "CmRTTIType.h"
-#include "CmResources.h"
-
-namespace CamelotFramework
-{
-	class ResourceMetaDataRTTI : public RTTIType<Resources::ResourceMetaData, IReflectable, ResourceMetaDataRTTI>
-	{
-		String& getUUID(Resources::ResourceMetaData* obj) { return obj->mUUID; }
-		void setUUID(Resources::ResourceMetaData* obj, String& val) { obj->mUUID = val; }
-
-		WString& getPath(Resources::ResourceMetaData* obj) { return obj->mPath; }
-		void setPath(Resources::ResourceMetaData* obj, WString& val) { obj->mPath = val; }
-
-	public:
-		ResourceMetaDataRTTI()
-		{
-			addPlainField("mUUID", 0, &ResourceMetaDataRTTI::getUUID, &ResourceMetaDataRTTI::setUUID);
-			addPlainField("mPath", 1, &ResourceMetaDataRTTI::getPath, &ResourceMetaDataRTTI::setPath);
-		}
-
-		virtual std::shared_ptr<IReflectable> newRTTIObject() 
-		{
-			return cm_shared_ptr<Resources::ResourceMetaData, PoolAlloc>();
-		}
-
-		virtual const String& getRTTIName() 
-		{
-			static String name = "ResourceMetaData";
-			throw name;
-		}
-
-		virtual UINT32 getRTTIId() 
-		{
-			return TID_ResourceMetaData;
-		}
-	};
-}

+ 0 - 2
CamelotCore/Include/CmTextureRTTI.h

@@ -17,7 +17,6 @@ namespace CamelotFramework
 	{
 	private:
 		CM_SETGET_MEMBER(mSize, UINT32, Texture)
-		CM_SETGET_MEMBER(mUUID, String, Texture);
 		CM_SETGET_MEMBER(mHeight, UINT32, Texture)
 		CM_SETGET_MEMBER(mWidth, UINT32, Texture)
 		CM_SETGET_MEMBER(mDepth, UINT32, Texture)
@@ -68,7 +67,6 @@ namespace CamelotFramework
 		TextureRTTI()
 		{
 			CM_ADD_PLAINFIELD(mSize, 0, TextureRTTI)
-			CM_ADD_PLAINFIELD(mUUID, 1, TextureRTTI)
 			CM_ADD_PLAINFIELD(mHeight, 2, TextureRTTI)
 			CM_ADD_PLAINFIELD(mWidth, 3, TextureRTTI)
 			CM_ADD_PLAINFIELD(mDepth, 4, TextureRTTI)

+ 1 - 1
CamelotCore/Source/CmApplication.cpp

@@ -60,7 +60,7 @@ namespace CamelotFramework
 		DynLibManager::startUp(cm_new<DynLibManager>());
 		CoreGpuObjectManager::startUp(cm_new<CoreGpuObjectManager>());
 		GameObjectManager::startUp(cm_new<GameObjectManager>());
-		Resources::startUp(cm_new<Resources>(desc.resourceCacheDirectory));
+		Resources::startUp(cm_new<Resources>());
 		HighLevelGpuProgramManager::startUp(cm_new<HighLevelGpuProgramManager>());
 
 		CoreThread::startUp(cm_new<CoreThread>());

+ 2 - 6
CamelotCore/Source/CmResource.cpp

@@ -7,15 +7,11 @@ namespace CamelotFramework
 {
 	Resource::Resource(bool initializeOnRenderThread)
 		:CoreObject(initializeOnRenderThread), mSize(0)
-	{
-		// We always generate a random UUID, and then overwrite it with the actual one 
-		// during loading if one was previously generated and saved.
-		mUUID = UUIDGenerator::generateRandom();
-	}
+	{ }
 
 	HResource Resource::_createResourceHandle(ResourcePtr obj)
 	{
-		return HResource(obj);
+		return HResource(obj, UUIDGenerator::generateRandom());
 	}
 
 	RTTITypeBase* Resource::getRTTIStatic()

+ 2 - 2
CamelotCore/Source/CmResourceHandle.cpp

@@ -36,13 +36,13 @@ namespace CamelotFramework
 		mData->mPtr->synchonize();
 	}
 
-	void ResourceHandleBase::setResourcePtr(std::shared_ptr<Resource> ptr)
+	void ResourceHandleBase::setHandleData(std::shared_ptr<Resource> ptr, const String& uuid)
 	{
 		mData->mPtr = ptr;
 
 		if(mData->mPtr)
 		{
-			mData->mUUID = mData->mPtr->getUUID();
+			mData->mUUID = uuid;
 		
 			if(!mData->mIsCreated)
 			{

+ 81 - 0
CamelotCore/Source/CmResourceManifest.cpp

@@ -0,0 +1,81 @@
+#include "CmResourceManifest.h"
+#include "CmResourceManifestRTTI.h"
+
+namespace CamelotFramework
+{
+	void ResourceManifest::registerResource(const String& uuid, const WString& filePath)
+	{
+		auto iterFind = mUUIDToFilePath.find(uuid);
+
+		if(iterFind != mUUIDToFilePath.end())
+		{
+			if(iterFind->second != filePath)
+			{
+				mFilePathToUUID.erase(iterFind->second);
+
+				mUUIDToFilePath[uuid] = filePath;
+				mFilePathToUUID[filePath] = uuid;
+			}
+		}
+		else
+		{
+			mUUIDToFilePath[uuid] = filePath;
+			mFilePathToUUID[filePath] = uuid;
+		}
+	}
+
+	void ResourceManifest::unregisterResource(const String& uuid)
+	{
+		auto iterFind = mUUIDToFilePath.find(uuid);
+
+		if(iterFind != mUUIDToFilePath.end())
+		{
+			mFilePathToUUID.erase(iterFind->second);
+			mUUIDToFilePath.erase(uuid);
+		}
+	}
+
+	const WString& ResourceManifest::uuidToFilePath(const String& uuid) const
+	{
+		auto iterFind = mUUIDToFilePath.find(uuid);
+
+		if(iterFind != mUUIDToFilePath.end())
+			return iterFind->second;
+		else
+			return StringUtil::WBLANK;
+	}
+
+	const String& ResourceManifest::filePathToUUID(const WString& filePath) const
+	{
+		auto iterFind = mFilePathToUUID.find(filePath);
+
+		if(iterFind != mFilePathToUUID.end())
+			return iterFind->second;
+		else
+			return StringUtil::BLANK;
+	}
+
+	bool ResourceManifest::uuidExists(const String& uuid) const
+	{
+		auto iterFind = mUUIDToFilePath.find(uuid);
+
+		return iterFind != mUUIDToFilePath.end();
+	}
+
+	bool ResourceManifest::filePathExists(const WString& filePath) const
+	{
+		auto iterFind = mFilePathToUUID.find(filePath);
+
+		return iterFind != mFilePathToUUID.end();
+	}
+
+	RTTITypeBase* ResourceManifest::getRTTIStatic()
+	{
+		return ResourceManifestRTTI::instance();
+	}
+
+	RTTITypeBase* ResourceManifest::getRTTI() const
+	{
+		return ResourceManifest::getRTTIStatic();
+	}
+}

+ 22 - 182
CamelotCore/Source/CmResources.cpp

@@ -1,12 +1,12 @@
 #include "CmResources.h"
 #include "CmResource.h"
+#include "CmResourceManifest.h"
 #include "CmException.h"
 #include "CmFileSerializer.h"
 #include "CmFileSystem.h"
 #include "CmUUID.h"
 #include "CmPath.h"
 #include "CmDebug.h"
-#include "CmResourcesRTTI.h"
 
 namespace CamelotFramework
 {
@@ -45,13 +45,7 @@ namespace CamelotFramework
 			
 			// This should be thread safe without any sync primitives, if other threads read a few cycles out of date value
 			// and think this resource isn't created when it really is, it hardly makes any difference
-			resRequest->resource.setResourcePtr(resResponse->rawResource);
-
-			if(!gResources().metaExists_UUID(resResponse->rawResource->getUUID()))
-			{
-				gDebug().logWarning("Loading a resource that doesn't have meta-data. Creating meta-data automatically. Resource path: " + toString(resRequest->filePath));
-				gResources().addMetaData(resResponse->rawResource->getUUID(), resRequest->filePath);
-			}
+			resRequest->resource.setHandleData(resResponse->rawResource, resRequest->resource.getUUID());
 
 			gResources().notifyNewResourceLoaded(resRequest->resource);
 		}
@@ -61,18 +55,10 @@ namespace CamelotFramework
 		}
 	}
 
-	Resources::Resources(const WString& metaDataFolder)
+	Resources::Resources()
 		:mRequestHandler(nullptr), mResponseHandler(nullptr), mWorkQueue(nullptr)
 	{
-		mMetaDataFolderPath = metaDataFolder;
-
-		if(!FileSystem::dirExists(mMetaDataFolderPath))
-		{
-			FileSystem::createDir(mMetaDataFolderPath);
-		}
-
-		loadMetaData();
-
+		mResourceManifest = cm_shared_ptr<ResourceManifest>();
 		mWorkQueue = cm_new<WorkQueue>();
 		mWorkQueueChannel = mWorkQueue->getChannel("Resources");
 		mRequestHandler = cm_new<ResourceRequestHandler>();
@@ -122,43 +108,38 @@ namespace CamelotFramework
 
 	HResource Resources::loadFromUUID(const String& uuid)
 	{
-		if(!metaExists_UUID(uuid))
+		if(!mResourceManifest->uuidExists(uuid))
 		{
 			gDebug().logWarning("Cannot load resource. Resource with UUID '" + uuid + "' doesn't exist.");
 			return HResource();
 		}
 
-		ResourceMetaDataPtr metaEntry = mResourceMetaData[uuid];
-
-		return load(metaEntry->mPath);
+		WString filePath = getPathFromUUID(uuid);
+		return load(filePath);
 	}
 
 	HResource Resources::loadFromUUIDAsync(const String& uuid)
 	{
-		if(!metaExists_UUID(uuid))
+		if(!mResourceManifest->uuidExists(uuid))
 		{
 			gDebug().logWarning("Cannot load resource. Resource with UUID '" + uuid + "' doesn't exist.");
 			return HResource();
 		}
 
-		ResourceMetaDataPtr metaEntry = mResourceMetaData[uuid];
-
-		return loadAsync(metaEntry->mPath);
+		WString filePath = getPathFromUUID(uuid);
+		return loadAsync(filePath);
 	}
 
 	HResource Resources::loadInternal(const WString& filePath, bool synchronous)
 	{
-		// TODO Low priority - Right now I don't allow loading of resources that don't have meta-data, because I need to know resources UUID
-		// at this point. And I can't do that without having meta-data. Other option is to partially load the resource to read the UUID but due to the
-		// nature of the serializer it could complicate things. (But possible if this approach proves troublesome)
-		// The reason I need the UUID is that when resource is loaded Async, the returned ResourceHandle needs to have a valid UUID, in case I assign that
-		// ResourceHandle to something and then save that something. If I didn't assign it, the saved ResourceHandle would have a blank (i.e. invalid) UUID.
-		if(!metaExists_Path(filePath))
+		String uuid;
+		if(!mResourceManifest->filePathExists(filePath))
 		{
-			CM_EXCEPT(InternalErrorException, "Cannot load resource that isn't registered in the meta database. Call Resources::create first.");
+			uuid = UUIDGenerator::generateRandom();
+			mResourceManifest->registerResource(uuid, filePath);
 		}
-
-		String uuid = getUUIDFromPath(filePath);
+		else
+			uuid = getUUIDFromPath(filePath);
 
 		{
 			CM_LOCK_MUTEX(mLoadedResourceMutex);
@@ -268,20 +249,12 @@ namespace CamelotFramework
 		}
 	}
 
-	void Resources::create(HResource resource, const WString& filePath, bool overwrite)
+	void Resources::save(HResource resource, const WString& filePath, bool overwrite)
 	{
-		if(resource == nullptr)
-			CM_EXCEPT(InvalidParametersException, "Trying to save an uninitialized resource.");
-
-		resource.synchronize();
+		if(!resource.isLoaded())
+			resource.synchronize();
 
-		if(metaExists_UUID(resource->getUUID()))
-			CM_EXCEPT(InvalidParametersException, "Specified resource already exists.");
-		
 		bool fileExists = FileSystem::fileExists(filePath);
-		const String& existingUUID = getUUIDFromPath(filePath);
-		bool metaExists = metaExists_UUID(existingUUID);
-
 		if(fileExists)
 		{
 			if(overwrite)
@@ -290,140 +263,20 @@ namespace CamelotFramework
 				CM_EXCEPT(InvalidParametersException, "Another file exists at the specified location.");
 		}
 
-		if(metaExists)
-			removeMetaData(existingUUID);
-
-		addMetaData(resource->getUUID(), filePath);
-
-		save(resource);
-
-		{
-			CM_LOCK_MUTEX(mLoadedResourceMutex);
-
-			mLoadedResources[resource->getUUID()] = resource;
-		}
-	}
-
-	void Resources::save(HResource resource)
-	{
-		if(!resource.isLoaded())
-			resource.synchronize();
-
-		if(!metaExists_UUID(resource->getUUID()))
-			CM_EXCEPT(InvalidParametersException, "Cannot find resource meta-data. Please call Resources::create before trying to save the resource.");
-
-		const WString& filePath = getPathFromUUID(resource->getUUID());
+		mResourceManifest->registerResource(resource.getUUID(), filePath);
 
 		FileSerializer fs;
 		fs.encode(resource.get(), filePath);
 	}
 
-	void Resources::loadMetaData()
-	{
-		Vector<WString>::type allFiles = FileSystem::getFiles(mMetaDataFolderPath);
-
-		for(auto iter = allFiles.begin(); iter != allFiles.end(); ++iter)
-		{
-			WString& path = *iter;
-			if(Path::hasExtension(path, L"resmeta"))
-			{
-				FileSerializer fs;
-				std::shared_ptr<IReflectable> loadedData = fs.decode(path);
-
-				ResourceMetaDataPtr metaData = std::static_pointer_cast<ResourceMetaData>(loadedData);
-				mResourceMetaData[metaData->mUUID] = metaData;
-				mResourceMetaData_FilePath[metaData->mPath] = metaData;
-			}
-		}
-	}
-
-	void Resources::saveMetaData(const ResourceMetaDataPtr metaData)
-	{
-		WString fullPath = Path::combine(mMetaDataFolderPath, toWString(metaData->mUUID + ".resmeta"));
-
-		FileSerializer fs;
-		fs.encode(metaData.get(), fullPath);
-	}
-
-	void Resources::removeMetaData(const String& uuid)
-	{
-		WString fullPath = Path::combine(mMetaDataFolderPath, toWString(uuid + ".resmeta"));
-		FileSystem::remove(fullPath);
-
-		auto iter = mResourceMetaData.find(uuid);
-
-		if(iter != mResourceMetaData.end())
-		{
-			mResourceMetaData.erase(iter);
-			mResourceMetaData_FilePath.erase(iter->second->mPath);
-		}
-		else
-			gDebug().logWarning("Trying to remove meta data that doesn't exist.");
-	}
-
-	void Resources::addMetaData(const String& uuid, const WString& filePath)
-	{
-		if(metaExists_Path(filePath))
-			CM_EXCEPT(InvalidParametersException, "Resource with the path '" + toString(filePath) + "' already exists.");
-
-		if(metaExists_UUID(uuid))
-			CM_EXCEPT(InternalErrorException, "Resource with the same UUID already exists. UUID: " + uuid);
-
-		ResourceMetaDataPtr dbEntry = cm_shared_ptr<ResourceMetaData>();
-		dbEntry->mPath = filePath;
-		dbEntry->mUUID = uuid;
-
-		mResourceMetaData[uuid] = dbEntry;
-		mResourceMetaData_FilePath[filePath] = dbEntry;
-
-		saveMetaData(dbEntry);
-	}
-
-	void Resources::updateMetaData(const String& uuid, const WString& newFilePath)
-	{
-		if(!metaExists_UUID(uuid))
-		{
-			CM_EXCEPT(InvalidParametersException, "Cannot update a resource that doesn't exist. UUID: " + uuid + ". File path: " + toString(newFilePath));
-		}
-
-		ResourceMetaDataPtr dbEntry = mResourceMetaData[uuid];
-		dbEntry->mPath = newFilePath;
-
-		saveMetaData(dbEntry);
-	}
-
 	const WString& Resources::getPathFromUUID(const String& uuid) const
 	{
-		auto findIter = mResourceMetaData.find(uuid);
-
-		if(findIter != mResourceMetaData.end())
-			return findIter->second->mPath;
-		else
-			return StringUtil::WBLANK;
+		return mResourceManifest->uuidToFilePath(uuid);
 	}
 
 	const String& Resources::getUUIDFromPath(const WString& path) const
 	{
-		auto findIter = mResourceMetaData_FilePath.find(path);
-
-		if(findIter != mResourceMetaData_FilePath.end())
-			return findIter->second->mUUID;
-		else
-			return StringUtil::BLANK;
-	}
-
-	bool Resources::metaExists_UUID(const String& uuid) const
-	{
-		auto findIter = mResourceMetaData.find(uuid);
-
-		return findIter != mResourceMetaData.end();
-	}
-
-	bool Resources::metaExists_Path(const WString& path) const
-	{
-		auto findIter = mResourceMetaData_FilePath.find(path);
-
-		return findIter != mResourceMetaData_FilePath.end();
+		return mResourceManifest->filePathToUUID(path);
 	}
 
 	void Resources::notifyResourceLoadingFinished(HResource& handle)
@@ -444,17 +297,4 @@ namespace CamelotFramework
 	{
 		return Resources::instance();
 	}
-
-	/************************************************************************/
-	/* 								SERIALIZATION                      		*/
-	/************************************************************************/
-	RTTITypeBase* Resources::ResourceMetaData::getRTTIStatic()
-	{
-		return ResourceMetaDataRTTI::instance();
-	}
-
-	RTTITypeBase* Resources::ResourceMetaData::getRTTI() const
-	{
-		return Resources::ResourceMetaData::getRTTIStatic();
-	}
 }

+ 3 - 3
CamelotEditor/Source/CmEditorApplication.cpp

@@ -120,7 +120,7 @@ namespace CamelotEditor
 		QString styleSheet;
 		for(auto iter = fileInfos.begin(); iter != fileInfos.end(); ++iter)
 		{
-			DataStreamPtr dataStream = FileSystem::open(iter->absoluteFilePath().toStdString());
+			DataStreamPtr dataStream = FileSystem::openFile(iter->absoluteFilePath().toStdString());
 
 			styleSheet += QString::fromStdString(dataStream->getAsString());
 		}
@@ -164,7 +164,7 @@ namespace CamelotEditor
 
 	bool EditorApplication::isValidProjectName(const QString& name) const
 	{
-		return FileSystem::isValidFileName(name.toStdString());
+		return FileSystem::isValidFilename(name.toStdString());
 	}
 
 	QString EditorApplication::getFullProjectPath(const QString& absProjDir, const QString& projName) const
@@ -191,7 +191,7 @@ namespace CamelotEditor
 
 	QString EditorApplication::getEditorRootPath() const
 	{
-		return QString::fromStdString(FileSystem::getCurrentPath());
+		return QString::fromStdString(FileSystem::getWorkingDirectoryPath());
 	}
 
 	QString EditorApplication::getEditorPrefsPath() const

+ 2 - 2
CamelotEditor/Source/CmPreferences.cpp

@@ -296,7 +296,7 @@ namespace CamelotEditor
 
 		String outputString = strStream.str();
 
-		DataStreamPtr stream = FileSystem::create(path);
+		DataStreamPtr stream = FileSystem::createAndOpenFile(path);
 		stream->write(outputString.data(), outputString.size());
 		stream->close();
 	}
@@ -306,7 +306,7 @@ namespace CamelotEditor
 		if(!FileSystem::fileExists(path))
 			CM_EXCEPT(FileNotFoundException, "Specified file: " + path + " does not exist.");
 
-		DataStreamPtr stream = FileSystem::open(path);
+		DataStreamPtr stream = FileSystem::openFile(path);
 		char buffer[4096];
 
 		String currentGroupName = "Global";

+ 2 - 2
CamelotEditor/Source/CmQtNewProject.cpp

@@ -97,7 +97,7 @@ namespace CamelotEditor
 		if(lastUsedDir.exists())
 			mTxtProjectPath->setText(lastUsedDir.absolutePath());
 		else
-			mTxtProjectPath->setText(QString::fromStdString(FileSystem::getCurrentPath()));
+			mTxtProjectPath->setText(QString::fromStdString(FileSystem::getWorkingDirectoryPath()));
 	}
 
 	void QtNewProject::setObjectNames()
@@ -175,7 +175,7 @@ namespace CamelotEditor
 
 			if(fileNames.size() > 0)
 			{
-				QString dirPath = QString::fromStdString(FileSystem::getDirectoryPath(fileNames[0].toStdString()));
+				QString dirPath = QString::fromStdString(FileSystem::getParentDirectory(fileNames[0].toStdString()));
 				mTxtProjectPath->setText(dirPath);
 
 				gEditorPrefs().setLastUsedProjectDirectory(dirPath);