AssetDatabase.cpp 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380
  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::GetAssetByGUID(const String& guid)
  65. {
  66. List<SharedPtr<Asset>>::ConstIterator itr = assets_.Begin();
  67. while (itr != assets_.End())
  68. {
  69. if (guid == (*itr)->GetGUID())
  70. return *itr;
  71. itr++;
  72. }
  73. return 0;
  74. }
  75. Asset* AssetDatabase::GetAssetByPath(const String& path)
  76. {
  77. List<SharedPtr<Asset>>::ConstIterator itr = assets_.Begin();
  78. while (itr != assets_.End())
  79. {
  80. if (path == (*itr)->GetPath())
  81. return *itr;
  82. itr++;
  83. }
  84. return 0;
  85. }
  86. void AssetDatabase::PruneOrphanedDotAssetFiles()
  87. {
  88. FileSystem* fs = GetSubsystem<FileSystem>();
  89. const String& resourcePath = project_->GetResourcePath();
  90. Vector<String> allResults;
  91. fs->ScanDir(allResults, resourcePath, "*.asset", SCAN_FILES, true);
  92. for (unsigned i = 0; i < allResults.Size(); i++)
  93. {
  94. String dotAssetFilename = resourcePath + allResults[i];
  95. String assetFilename = ReplaceExtension(dotAssetFilename, "");
  96. // remove orphaned asset files
  97. if (!fs->FileExists(assetFilename) && !fs->DirExists(assetFilename))
  98. {
  99. LOGINFOF("Removing orphaned asset file: %s", dotAssetFilename.CString());
  100. fs->Delete(dotAssetFilename);
  101. }
  102. }
  103. }
  104. String AssetDatabase::GetDotAssetFilename(const String& path)
  105. {
  106. FileSystem* fs = GetSubsystem<FileSystem>();
  107. String assetFilename = path + ".asset";
  108. if (fs->DirExists(path)) {
  109. assetFilename = RemoveTrailingSlash(path) + ".asset";
  110. }
  111. return assetFilename;
  112. }
  113. void AssetDatabase::AddAsset(SharedPtr<Asset>& asset)
  114. {
  115. assert(asset->GetGUID().Length());
  116. assets_.Push(asset);
  117. VariantMap eventData;
  118. eventData[ResourceAdded::P_GUID] = asset->GetGUID();
  119. SendEvent(E_RESOURCEADDED, eventData);
  120. }
  121. void AssetDatabase::DeleteAsset(Asset* asset)
  122. {
  123. SharedPtr<Asset> assetPtr(asset);
  124. List<SharedPtr<Asset>>::Iterator itr = assets_.Find(assetPtr);
  125. if (itr == assets_.End())
  126. return;
  127. assets_.Erase(itr);
  128. const String& resourcePath = asset->GetPath();
  129. FileSystem* fs = GetSubsystem<FileSystem>();
  130. if (fs->DirExists(resourcePath))
  131. {
  132. fs->RemoveDir(resourcePath, true);
  133. }
  134. else if (fs->FileExists(resourcePath))
  135. {
  136. fs->Delete(resourcePath);
  137. }
  138. String dotAsset = resourcePath + ".asset";
  139. if (fs->FileExists(dotAsset))
  140. {
  141. fs->Delete(dotAsset);
  142. }
  143. VariantMap eventData;
  144. eventData[ResourceRemoved::P_GUID] = asset->GetGUID();
  145. SendEvent(E_RESOURCEREMOVED, eventData);
  146. }
  147. void AssetDatabase::ImportDirtyAssets()
  148. {
  149. PODVector<Asset*> assets;
  150. GetDirtyAssets(assets);
  151. for (unsigned i = 0; i < assets.Size(); i++)
  152. {
  153. assets[i]->Import();
  154. assets[i]->Save();
  155. }
  156. }
  157. void AssetDatabase::PreloadAssets()
  158. {
  159. List<SharedPtr<Asset>>::ConstIterator itr = assets_.Begin();
  160. while (itr != assets_.End())
  161. {
  162. (*itr)->Preload();
  163. itr++;
  164. }
  165. }
  166. void AssetDatabase::Scan()
  167. {
  168. PruneOrphanedDotAssetFiles();
  169. FileSystem* fs = GetSubsystem<FileSystem>();
  170. const String& resourcePath = project_->GetResourcePath();
  171. Vector<String> allResults;
  172. fs->ScanDir(allResults, resourcePath, "", SCAN_FILES | SCAN_DIRS, true);
  173. Vector<String> filteredResults;
  174. for (unsigned i = 0; i < allResults.Size(); i++)
  175. {
  176. allResults[i] = resourcePath + allResults[i];
  177. const String& path = allResults[i];
  178. if (path.StartsWith(".") || path.EndsWith("."))
  179. continue;
  180. String ext = GetExtension(path);
  181. if (ext == ".asset")
  182. continue;
  183. filteredResults.Push(path);
  184. }
  185. for (unsigned i = 0; i < filteredResults.Size(); i++)
  186. {
  187. const String& path = filteredResults[i];
  188. String dotAssetFilename = GetDotAssetFilename(path);
  189. if (!fs->FileExists(dotAssetFilename))
  190. {
  191. // new asset
  192. SharedPtr<Asset> asset(new Asset(context_));
  193. if (asset->SetPath(path))
  194. AddAsset(asset);
  195. }
  196. else
  197. {
  198. SharedPtr<File> file(new File(context_, dotAssetFilename));
  199. SharedPtr<JSONFile> json(new JSONFile(context_));
  200. json->Load(*file);
  201. file->Close();
  202. JSONValue root = json->GetRoot();
  203. assert(root.GetInt("version") == ASSET_VERSION);
  204. String guid = root.GetString("guid");
  205. if (!GetAssetByGUID(guid))
  206. {
  207. SharedPtr<Asset> asset(new Asset(context_));
  208. asset->SetPath(path);
  209. AddAsset(asset);
  210. }
  211. }
  212. }
  213. PreloadAssets();
  214. ImportDirtyAssets();
  215. }
  216. void AssetDatabase::GetFolderAssets(String folder, PODVector<Asset*>& assets) const
  217. {
  218. if (project_.Null())
  219. return;
  220. List<SharedPtr<Asset>>::ConstIterator itr = assets_.Begin();
  221. if (!folder.Length())
  222. {
  223. folder = project_->GetResourcePath();
  224. }
  225. folder = AddTrailingSlash(folder);
  226. while (itr != assets_.End())
  227. {
  228. String path = GetPath((*itr)->GetPath());
  229. if (path == folder)
  230. assets.Push(*itr);
  231. itr++;
  232. }
  233. }
  234. void AssetDatabase::GetAssetsByImporterType(StringHash type, PODVector<Asset*>& assets) const
  235. {
  236. assets.Clear();
  237. List<SharedPtr<Asset>>::ConstIterator itr = assets_.Begin();
  238. while (itr != assets_.End())
  239. {
  240. Asset* asset = *itr;
  241. if (asset->GetImporterType() == type)
  242. assets.Push(asset);
  243. itr++;
  244. }
  245. }
  246. void AssetDatabase::GetDirtyAssets(PODVector<Asset*>& assets)
  247. {
  248. assets.Clear();
  249. List<SharedPtr<Asset>>::ConstIterator itr = assets_.Begin();
  250. while (itr != assets_.End())
  251. {
  252. if ((*itr)->IsDirty())
  253. assets.Push(*itr);
  254. itr++;
  255. }
  256. }
  257. void AssetDatabase::HandleProjectLoaded(StringHash eventType, VariantMap& eventData)
  258. {
  259. project_ = GetSubsystem<ToolSystem>()->GetProject();
  260. ResourceCache* cache = GetSubsystem<ResourceCache>();
  261. cache->AddResourceDir(GetCachePath());
  262. Scan();
  263. }
  264. }