AssetDatabase.cpp 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. #include <Poco/MD5Engine.h>
  2. #include <Atomic/IO/Log.h>
  3. #include <Atomic/IO/File.h>
  4. #include <Atomic/IO/FileSystem.h>
  5. #include <Atomic/Math/Random.h>
  6. #include <Atomic/Resource/ResourceCache.h>
  7. #include "../ToolEvents.h"
  8. #include "../ToolSystem.h"
  9. #include "../Project/Project.h"
  10. #include "AssetDatabase.h"
  11. namespace ToolCore
  12. {
  13. AssetDatabase::AssetDatabase(Context* context) : Object(context)
  14. {
  15. SubscribeToEvent(E_PROJECTLOADED, HANDLER(AssetDatabase, HandleProjectLoaded));
  16. }
  17. AssetDatabase::~AssetDatabase()
  18. {
  19. }
  20. String AssetDatabase::GetCachePath()
  21. {
  22. if (project_.Null())
  23. return String::EMPTY;
  24. return project_->GetProjectPath() + "Cache/";
  25. }
  26. String AssetDatabase::GenerateAssetGUID()
  27. {
  28. Time* time = GetSubsystem<Time>();
  29. while (true)
  30. {
  31. Poco::MD5Engine md5;
  32. PODVector<unsigned> data;
  33. for (unsigned i = 0; i < 16; i++)
  34. {
  35. data.Push(time->GetTimeSinceEpoch() + Rand());
  36. }
  37. md5.update(&data[0], data.Size() * sizeof(unsigned));
  38. String guid = Poco::MD5Engine::digestToHex(md5.digest()).c_str();
  39. if (!usedGUID_.Contains(guid))
  40. {
  41. RegisterGUID(guid);
  42. return guid;
  43. }
  44. }
  45. assert(0);
  46. return "";
  47. }
  48. void AssetDatabase::RegisterGUID(const String& guid)
  49. {
  50. if (usedGUID_.Contains(guid))
  51. {
  52. assert(0);
  53. }
  54. usedGUID_.Push(guid);
  55. }
  56. void AssetDatabase::Import(const String& path)
  57. {
  58. FileSystem* fs = GetSubsystem<FileSystem>();
  59. // nothing for now
  60. if (fs->DirExists(path))
  61. return;
  62. }
  63. Asset* AssetDatabase::GetAssetByGUID(const String& guid)
  64. {
  65. List<SharedPtr<Asset>>::ConstIterator itr = assets_.Begin();
  66. while (itr != assets_.End())
  67. {
  68. if (guid == (*itr)->GetGUID())
  69. return *itr;
  70. itr++;
  71. }
  72. return 0;
  73. }
  74. Asset* AssetDatabase::GetAssetByPath(const String& path)
  75. {
  76. List<SharedPtr<Asset>>::ConstIterator itr = assets_.Begin();
  77. while (itr != assets_.End())
  78. {
  79. if (path == (*itr)->GetPath())
  80. return *itr;
  81. itr++;
  82. }
  83. return 0;
  84. }
  85. void AssetDatabase::PruneOrphanedDotAssetFiles()
  86. {
  87. FileSystem* fs = GetSubsystem<FileSystem>();
  88. const String& resourcePath = project_->GetResourcePath();
  89. Vector<String> allResults;
  90. fs->ScanDir(allResults, resourcePath, "*.asset", SCAN_FILES, true);
  91. for (unsigned i = 0; i < allResults.Size(); i++)
  92. {
  93. String dotAssetFilename = resourcePath + allResults[i];
  94. String assetFilename = ReplaceExtension(dotAssetFilename, "");
  95. // remove orphaned asset files
  96. if (!fs->FileExists(assetFilename) && !fs->DirExists(assetFilename))
  97. {
  98. LOGINFOF("Removing orphaned asset file: %s", dotAssetFilename.CString());
  99. fs->Delete(dotAssetFilename);
  100. }
  101. }
  102. }
  103. String AssetDatabase::GetDotAssetFilename(const String& path)
  104. {
  105. FileSystem* fs = GetSubsystem<FileSystem>();
  106. String assetFilename = path + ".asset";
  107. if (fs->DirExists(path)) {
  108. assetFilename = RemoveTrailingSlash(path) + ".asset";
  109. }
  110. return assetFilename;
  111. }
  112. void AssetDatabase::AddAsset(SharedPtr<Asset>& asset)
  113. {
  114. assets_.Push(asset);
  115. }
  116. void AssetDatabase::ImportDirtyAssets()
  117. {
  118. PODVector<Asset*> assets;
  119. GetDirtyAssets(assets);
  120. for (unsigned i = 0; i < assets.Size(); i++)
  121. {
  122. assets[i]->Import();
  123. assets[i]->Save();
  124. }
  125. }
  126. void AssetDatabase::PreloadAssets()
  127. {
  128. List<SharedPtr<Asset>>::ConstIterator itr = assets_.Begin();
  129. while (itr != assets_.End())
  130. {
  131. (*itr)->Preload();
  132. itr++;
  133. }
  134. }
  135. void AssetDatabase::Scan()
  136. {
  137. PruneOrphanedDotAssetFiles();
  138. FileSystem* fs = GetSubsystem<FileSystem>();
  139. const String& resourcePath = project_->GetResourcePath();
  140. Vector<String> allResults;
  141. fs->ScanDir(allResults, resourcePath, "", SCAN_FILES | SCAN_DIRS, true);
  142. Vector<String> filteredResults;
  143. for (unsigned i = 0; i < allResults.Size(); i++)
  144. {
  145. allResults[i] = resourcePath + allResults[i];
  146. const String& path = allResults[i];
  147. if (path.StartsWith(".") || path.EndsWith("."))
  148. continue;
  149. String ext = GetExtension(path);
  150. if (ext == ".asset")
  151. continue;
  152. filteredResults.Push(path);
  153. }
  154. for (unsigned i = 0; i < filteredResults.Size(); i++)
  155. {
  156. const String& path = filteredResults[i];
  157. String dotAssetFilename = GetDotAssetFilename(path);
  158. if (!fs->FileExists(dotAssetFilename))
  159. {
  160. // new asset
  161. SharedPtr<Asset> asset(new Asset(context_));
  162. if (asset->SetPath(path))
  163. AddAsset(asset);
  164. }
  165. else
  166. {
  167. SharedPtr<File> file(new File(context_, dotAssetFilename));
  168. SharedPtr<JSONFile> json(new JSONFile(context_));
  169. json->Load(*file);
  170. file->Close();
  171. JSONValue root = json->GetRoot();
  172. assert(root.GetInt("version") == ASSET_VERSION);
  173. String guid = root.GetString("guid");
  174. if (!GetAssetByGUID(guid))
  175. {
  176. SharedPtr<Asset> asset(new Asset(context_));
  177. asset->SetPath(path);
  178. AddAsset(asset);
  179. }
  180. }
  181. }
  182. PreloadAssets();
  183. ImportDirtyAssets();
  184. }
  185. void AssetDatabase::GetFolderAssets(String folder, PODVector<Asset*>& assets) const
  186. {
  187. if (project_.Null())
  188. return;
  189. List<SharedPtr<Asset>>::ConstIterator itr = assets_.Begin();
  190. if (!folder.Length())
  191. {
  192. folder = project_->GetResourcePath();
  193. }
  194. folder = AddTrailingSlash(folder);
  195. while (itr != assets_.End())
  196. {
  197. String path = GetPath((*itr)->GetPath());
  198. if (path == folder)
  199. assets.Push(*itr);
  200. itr++;
  201. }
  202. }
  203. void AssetDatabase::GetAssetsByImporterType(StringHash type, PODVector<Asset*>& assets) const
  204. {
  205. assets.Clear();
  206. List<SharedPtr<Asset>>::ConstIterator itr = assets_.Begin();
  207. while (itr != assets_.End())
  208. {
  209. Asset* asset = *itr;
  210. if (asset->GetImporterType() == type)
  211. assets.Push(asset);
  212. itr++;
  213. }
  214. }
  215. void AssetDatabase::GetDirtyAssets(PODVector<Asset*>& assets)
  216. {
  217. assets.Clear();
  218. List<SharedPtr<Asset>>::ConstIterator itr = assets_.Begin();
  219. while (itr != assets_.End())
  220. {
  221. if ((*itr)->IsDirty())
  222. assets.Push(*itr);
  223. itr++;
  224. }
  225. }
  226. void AssetDatabase::HandleProjectLoaded(StringHash eventType, VariantMap& eventData)
  227. {
  228. project_ = GetSubsystem<ToolSystem>()->GetProject();
  229. ResourceCache* cache = GetSubsystem<ResourceCache>();
  230. cache->AddResourceDir(GetCachePath());
  231. Scan();
  232. }
  233. }