AssetDatabase.cpp 8.0 KB

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