AssetDatabase.cpp 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382
  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. filteredResults.Push(RemoveTrailingSlash(resourcePath));
  175. for (unsigned i = 0; i < allResults.Size(); i++)
  176. {
  177. allResults[i] = resourcePath + allResults[i];
  178. const String& path = allResults[i];
  179. if (path.StartsWith(".") || path.EndsWith("."))
  180. continue;
  181. String ext = GetExtension(path);
  182. if (ext == ".asset")
  183. continue;
  184. filteredResults.Push(path);
  185. }
  186. for (unsigned i = 0; i < filteredResults.Size(); i++)
  187. {
  188. const String& path = filteredResults[i];
  189. String dotAssetFilename = GetDotAssetFilename(path);
  190. if (!fs->FileExists(dotAssetFilename))
  191. {
  192. // new asset
  193. SharedPtr<Asset> asset(new Asset(context_));
  194. if (asset->SetPath(path))
  195. AddAsset(asset);
  196. }
  197. else
  198. {
  199. SharedPtr<File> file(new File(context_, dotAssetFilename));
  200. SharedPtr<JSONFile> json(new JSONFile(context_));
  201. json->Load(*file);
  202. file->Close();
  203. JSONValue root = json->GetRoot();
  204. assert(root.GetInt("version") == ASSET_VERSION);
  205. String guid = root.GetString("guid");
  206. if (!GetAssetByGUID(guid))
  207. {
  208. SharedPtr<Asset> asset(new Asset(context_));
  209. asset->SetPath(path);
  210. AddAsset(asset);
  211. }
  212. }
  213. }
  214. PreloadAssets();
  215. ImportDirtyAssets();
  216. }
  217. void AssetDatabase::GetFolderAssets(String folder, PODVector<Asset*>& assets) const
  218. {
  219. if (project_.Null())
  220. return;
  221. List<SharedPtr<Asset>>::ConstIterator itr = assets_.Begin();
  222. if (!folder.Length())
  223. {
  224. folder = project_->GetResourcePath();
  225. }
  226. folder = AddTrailingSlash(folder);
  227. while (itr != assets_.End())
  228. {
  229. String path = GetPath((*itr)->GetPath());
  230. if (path == folder)
  231. assets.Push(*itr);
  232. itr++;
  233. }
  234. }
  235. void AssetDatabase::GetAssetsByImporterType(StringHash type, PODVector<Asset*>& assets) const
  236. {
  237. assets.Clear();
  238. List<SharedPtr<Asset>>::ConstIterator itr = assets_.Begin();
  239. while (itr != assets_.End())
  240. {
  241. Asset* asset = *itr;
  242. if (asset->GetImporterType() == type)
  243. assets.Push(asset);
  244. itr++;
  245. }
  246. }
  247. void AssetDatabase::GetDirtyAssets(PODVector<Asset*>& assets)
  248. {
  249. assets.Clear();
  250. List<SharedPtr<Asset>>::ConstIterator itr = assets_.Begin();
  251. while (itr != assets_.End())
  252. {
  253. if ((*itr)->IsDirty())
  254. assets.Push(*itr);
  255. itr++;
  256. }
  257. }
  258. void AssetDatabase::HandleProjectLoaded(StringHash eventType, VariantMap& eventData)
  259. {
  260. project_ = GetSubsystem<ToolSystem>()->GetProject();
  261. ResourceCache* cache = GetSubsystem<ResourceCache>();
  262. cache->AddResourceDir(GetCachePath());
  263. Scan();
  264. }
  265. }