AssetDatabase.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817
  1. //
  2. // Copyright (c) 2014-2016 THUNDERBEAST GAMES LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to deal
  6. // in the Software without restriction, including without limitation the rights
  7. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. // copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20. // THE SOFTWARE.
  21. //
  22. #include <Poco/MD5Engine.h>
  23. #include <Atomic/IO/Log.h>
  24. #include <Atomic/IO/File.h>
  25. #include <Atomic/IO/FileSystem.h>
  26. #include <Atomic/Math/Random.h>
  27. #include <Atomic/Resource/ResourceEvents.h>
  28. #include <Atomic/Resource/ResourceCache.h>
  29. #include "../Import/ImportConfig.h"
  30. #include "../ToolEvents.h"
  31. #include "../ToolSystem.h"
  32. #include "../Project/Project.h"
  33. #include "../Project/ProjectEvents.h"
  34. #include "AssetEvents.h"
  35. #include "AssetDatabase.h"
  36. // ATOMIC GLOW HACK BEGIN
  37. #include <Atomic/Resource/ResourceMapRouter.h>
  38. // ATOMIC GLOW HACK END
  39. namespace ToolCore
  40. {
  41. AssetDatabase::AssetDatabase(Context* context) : Object(context),
  42. assetScanDepth_(0),
  43. assetScanImport_(false),
  44. cacheEnabled_(true)
  45. {
  46. SubscribeToEvent(E_LOADFAILED, ATOMIC_HANDLER(AssetDatabase, HandleResourceLoadFailed));
  47. SubscribeToEvent(E_PROJECTLOADED, ATOMIC_HANDLER(AssetDatabase, HandleProjectLoaded));
  48. SubscribeToEvent(E_PROJECTUNLOADED, ATOMIC_HANDLER(AssetDatabase, HandleProjectUnloaded));
  49. }
  50. AssetDatabase::~AssetDatabase()
  51. {
  52. }
  53. String AssetDatabase::GetCachePath()
  54. {
  55. if (project_.Null())
  56. return String::EMPTY;
  57. return project_->GetProjectPath() + "Cache/";
  58. }
  59. String AssetDatabase::GenerateAssetGUID()
  60. {
  61. Time* time = GetSubsystem<Time>();
  62. while (true)
  63. {
  64. Poco::MD5Engine md5;
  65. PODVector<unsigned> data;
  66. for (unsigned i = 0; i < 16; i++)
  67. {
  68. data.Push(time->GetTimeSinceEpoch() + Rand());
  69. }
  70. md5.update(&data[0], data.Size() * sizeof(unsigned));
  71. String guid = Poco::MD5Engine::digestToHex(md5.digest()).c_str();
  72. if (!usedGUID_.Contains(guid))
  73. {
  74. RegisterGUID(guid);
  75. return guid;
  76. }
  77. }
  78. assert(0);
  79. return "";
  80. }
  81. void AssetDatabase::RegisterGUID(const String& guid)
  82. {
  83. if (usedGUID_.Contains(guid))
  84. {
  85. assert(0);
  86. }
  87. usedGUID_.Push(guid);
  88. }
  89. void AssetDatabase::ReadImportConfig()
  90. {
  91. ImportConfig::Clear();
  92. ToolSystem* tsystem = GetSubsystem<ToolSystem>();
  93. Project* project = tsystem->GetProject();
  94. String projectPath = project->GetProjectPath();
  95. String filename = projectPath + "Settings/Import.json";
  96. FileSystem* fileSystem = GetSubsystem<FileSystem>();
  97. if (!fileSystem->FileExists(filename))
  98. return;
  99. ImportConfig::LoadFromFile(context_, filename);
  100. }
  101. void AssetDatabase::Import(const String& path)
  102. {
  103. FileSystem* fs = GetSubsystem<FileSystem>();
  104. // nothing for now
  105. if (fs->DirExists(path))
  106. return;
  107. }
  108. Asset* AssetDatabase::GetAssetByCachePath(const String& cachePath)
  109. {
  110. List<SharedPtr<Asset>>::ConstIterator itr = assets_.Begin();
  111. // This is the GUID
  112. String cacheFilename = GetFileName(cachePath).ToLower();
  113. while (itr != assets_.End())
  114. {
  115. if ((*itr)->GetGUID().ToLower() == cacheFilename)
  116. return *itr;
  117. itr++;
  118. }
  119. return 0;
  120. }
  121. Asset* AssetDatabase::GetAssetByGUID(const String& guid)
  122. {
  123. List<SharedPtr<Asset>>::ConstIterator itr = assets_.Begin();
  124. while (itr != assets_.End())
  125. {
  126. if (guid == (*itr)->GetGUID())
  127. return *itr;
  128. itr++;
  129. }
  130. return 0;
  131. }
  132. Asset* AssetDatabase::GetAssetByPath(const String& path)
  133. {
  134. List<SharedPtr<Asset>>::ConstIterator itr = assets_.Begin();
  135. while (itr != assets_.End())
  136. {
  137. if (path == (*itr)->GetPath())
  138. return *itr;
  139. itr++;
  140. }
  141. return 0;
  142. }
  143. void AssetDatabase::PruneOrphanedDotAssetFiles()
  144. {
  145. if (GetReadOnly())
  146. {
  147. return;
  148. }
  149. if (project_.Null())
  150. {
  151. ATOMIC_LOGDEBUG("AssetDatabase::PruneOrphanedDotAssetFiles - called without project loaded");
  152. return;
  153. }
  154. FileSystem* fs = GetSubsystem<FileSystem>();
  155. const String& resourcePath = project_->GetResourcePath();
  156. Vector<String> allResults;
  157. fs->ScanDir(allResults, resourcePath, "*.asset", SCAN_FILES, true);
  158. for (unsigned i = 0; i < allResults.Size(); i++)
  159. {
  160. String dotAssetFilename = resourcePath + allResults[i];
  161. String assetFilename = ReplaceExtension(dotAssetFilename, "");
  162. // remove orphaned asset files
  163. if (!fs->FileExists(assetFilename) && !fs->DirExists(assetFilename))
  164. {
  165. ATOMIC_LOGINFOF("Removing orphaned asset file: %s", dotAssetFilename.CString());
  166. fs->Delete(dotAssetFilename);
  167. }
  168. }
  169. }
  170. String AssetDatabase::GetDotAssetFilename(const String& path)
  171. {
  172. FileSystem* fs = GetSubsystem<FileSystem>();
  173. String assetFilename = path + ".asset";
  174. if (fs->DirExists(path)) {
  175. assetFilename = RemoveTrailingSlash(path) + ".asset";
  176. }
  177. return assetFilename;
  178. }
  179. void AssetDatabase::AddAsset(SharedPtr<Asset>& asset, bool newAsset)
  180. {
  181. assert(asset->GetGUID().Length());
  182. assert(!GetAssetByGUID(asset->GetGUID()));
  183. assets_.Push(asset);
  184. // set to the current timestamp
  185. asset->UpdateFileTimestamp();
  186. VariantMap eventData;
  187. if (newAsset)
  188. {
  189. eventData[AssetNew::P_GUID] = asset->GetGUID();
  190. SendEvent(E_ASSETNEW, eventData);
  191. }
  192. eventData[ResourceAdded::P_GUID] = asset->GetGUID();
  193. SendEvent(E_RESOURCEADDED, eventData);
  194. }
  195. void AssetDatabase::DeleteAsset(Asset* asset)
  196. {
  197. SharedPtr<Asset> assetPtr(asset);
  198. List<SharedPtr<Asset>>::Iterator itr = assets_.Find(assetPtr);
  199. if (itr == assets_.End())
  200. return;
  201. assets_.Erase(itr);
  202. const String& resourcePath = asset->GetPath();
  203. FileSystem* fs = GetSubsystem<FileSystem>();
  204. if (fs->DirExists(resourcePath))
  205. {
  206. fs->RemoveDir(resourcePath, true);
  207. }
  208. else if (fs->FileExists(resourcePath))
  209. {
  210. fs->Delete(resourcePath);
  211. }
  212. String dotAsset = resourcePath + ".asset";
  213. if (fs->FileExists(dotAsset))
  214. {
  215. fs->Delete(dotAsset);
  216. }
  217. VariantMap eventData;
  218. eventData[ResourceRemoved::P_GUID] = asset->GetGUID();
  219. SendEvent(E_RESOURCEREMOVED, eventData);
  220. }
  221. bool AssetDatabase::ImportDirtyAssets()
  222. {
  223. PODVector<Asset*> assets;
  224. GetDirtyAssets(assets);
  225. for (unsigned i = 0; i < assets.Size(); i++)
  226. {
  227. assetScanImport_ = true;
  228. assets[i]->Import();
  229. assets[i]->Save();
  230. assets[i]->dirty_ = false;
  231. assets[i]->UpdateFileTimestamp();
  232. }
  233. return assets.Size() != 0;
  234. }
  235. void AssetDatabase::PreloadAssets()
  236. {
  237. List<SharedPtr<Asset>>::ConstIterator itr = assets_.Begin();
  238. while (itr != assets_.End())
  239. {
  240. (*itr)->Preload();
  241. itr++;
  242. }
  243. }
  244. void AssetDatabase::UpdateAssetCacheMap()
  245. {
  246. FileSystem* fileSystem = GetSubsystem<FileSystem>();
  247. if (project_.Null())
  248. return;
  249. if (GetReadOnly())
  250. {
  251. return;
  252. }
  253. bool gen = assetScanImport_;
  254. assetScanImport_ = false;
  255. String cachepath = project_->GetProjectPath() + "Cache/__atomic_ResourceCacheMap.json";
  256. if (!gen && !fileSystem->FileExists(cachepath))
  257. gen = true;
  258. if (!gen)
  259. return;
  260. List<SharedPtr<Asset>>::ConstIterator itr = assets_.Begin();
  261. HashMap<String, String> assetMap;
  262. JSONValue jAssetMap;
  263. while (itr != assets_.End())
  264. {
  265. assetMap.Clear();
  266. (*itr)->GetAssetCacheMap(assetMap);
  267. HashMap<String, String>::ConstIterator amitr = assetMap.Begin();
  268. while (amitr != assetMap.End())
  269. {
  270. jAssetMap.Set(amitr->first_, amitr->second_);
  271. amitr++;
  272. }
  273. itr++;
  274. }
  275. SharedPtr<File> file(new File(context_, cachepath, FILE_WRITE));
  276. if (!file->IsOpen())
  277. {
  278. ATOMIC_LOGERRORF("Unable to update ResourceCacheMap: %s", cachepath.CString());
  279. return;
  280. }
  281. SharedPtr<JSONFile> jsonFile(new JSONFile(context_));
  282. jsonFile->GetRoot().Set("assetMap", jAssetMap);
  283. jsonFile->Save(*file);
  284. }
  285. void AssetDatabase::Scan()
  286. {
  287. if (!assetScanDepth_)
  288. {
  289. assert(!assetScanImport_);
  290. SendEvent(E_ASSETSCANBEGIN);
  291. }
  292. assetScanDepth_++;
  293. PruneOrphanedDotAssetFiles();
  294. FileSystem* fs = GetSubsystem<FileSystem>();
  295. const String& resourcePath = project_->GetResourcePath();
  296. Vector<String> allResults;
  297. fs->ScanDir(allResults, resourcePath, "", SCAN_FILES | SCAN_DIRS, true);
  298. Vector<String> filteredResults;
  299. filteredResults.Push(RemoveTrailingSlash(resourcePath));
  300. for (unsigned i = 0; i < allResults.Size(); i++)
  301. {
  302. allResults[i] = resourcePath + allResults[i];
  303. const String& path = allResults[i];
  304. if (path.StartsWith(".") || path.EndsWith("."))
  305. continue;
  306. String ext = GetExtension(path);
  307. if (ext == ".asset")
  308. continue;
  309. filteredResults.Push(path);
  310. }
  311. for (unsigned i = 0; i < filteredResults.Size(); i++)
  312. {
  313. const String& path = filteredResults[i];
  314. String dotAssetFilename = GetDotAssetFilename(path);
  315. if (!fs->FileExists(dotAssetFilename))
  316. {
  317. if (!GetReadOnly())
  318. {
  319. // new asset
  320. SharedPtr<Asset> asset(new Asset(context_));
  321. if (asset->SetPath(path))
  322. {
  323. AddAsset(asset, true);
  324. }
  325. }
  326. }
  327. else
  328. {
  329. SharedPtr<File> file(new File(context_, dotAssetFilename));
  330. SharedPtr<JSONFile> json(new JSONFile(context_));
  331. json->Load(*file);
  332. file->Close();
  333. JSONValue& root = json->GetRoot();
  334. assert(root.Get("version").GetInt() == ASSET_VERSION);
  335. String guid = root.Get("guid").GetString();
  336. if (!GetAssetByGUID(guid))
  337. {
  338. SharedPtr<Asset> asset(new Asset(context_));
  339. asset->SetPath(path);
  340. AddAsset(asset);
  341. }
  342. }
  343. }
  344. PreloadAssets();
  345. if (ImportDirtyAssets())
  346. Scan();
  347. assetScanDepth_--;
  348. if (!assetScanDepth_)
  349. {
  350. UpdateAssetCacheMap();
  351. SendEvent(E_ASSETSCANEND);
  352. }
  353. }
  354. void AssetDatabase::GetFolderAssets(String folder, PODVector<Asset*>& assets) const
  355. {
  356. if (project_.Null())
  357. return;
  358. List<SharedPtr<Asset>>::ConstIterator itr = assets_.Begin();
  359. if (!folder.Length())
  360. {
  361. folder = project_->GetResourcePath();
  362. }
  363. folder = AddTrailingSlash(folder);
  364. while (itr != assets_.End())
  365. {
  366. String path = GetPath((*itr)->GetPath());
  367. if (path == folder)
  368. assets.Push(*itr);
  369. itr++;
  370. }
  371. }
  372. void AssetDatabase::GetAssetsByImporterType(StringHash type, const String &resourceType, PODVector<Asset*>& assets) const
  373. {
  374. assets.Clear();
  375. List<SharedPtr<Asset>>::ConstIterator itr = assets_.Begin();
  376. while (itr != assets_.End())
  377. {
  378. Asset* asset = *itr;
  379. if (asset->GetImporterType() == type)
  380. assets.Push(asset);
  381. itr++;
  382. }
  383. }
  384. void AssetDatabase::GetDirtyAssets(PODVector<Asset*>& assets)
  385. {
  386. assets.Clear();
  387. List<SharedPtr<Asset>>::ConstIterator itr = assets_.Begin();
  388. while (itr != assets_.End())
  389. {
  390. if ((*itr)->IsDirty())
  391. assets.Push(*itr);
  392. itr++;
  393. }
  394. }
  395. void AssetDatabase::HandleProjectLoaded(StringHash eventType, VariantMap& eventData)
  396. {
  397. project_ = GetSubsystem<ToolSystem>()->GetProject();
  398. ReadImportConfig();
  399. if (cacheEnabled_)
  400. {
  401. InitCache();
  402. // ATOMIC GLOW HACK BEGIN
  403. // This is so we get the .mdl files with baked UV2 from from Cache, instead of .mdl in project
  404. // need to look into it, don't land this hack
  405. SharedPtr<ResourceMapRouter> router(new ResourceMapRouter(context_, "__atomic_ResourceCacheMap.json"));
  406. // ATOMIC GLOW HACK END
  407. }
  408. SubscribeToEvent(E_FILECHANGED, ATOMIC_HANDLER(AssetDatabase, HandleFileChanged));
  409. }
  410. void AssetDatabase::HandleProjectUnloaded(StringHash eventType, VariantMap& eventData)
  411. {
  412. ResourceCache* cache = GetSubsystem<ResourceCache>();
  413. cache->RemoveResourceDir(GetCachePath());
  414. assets_.Clear();
  415. usedGUID_.Clear();
  416. assetImportErrorTimes_.Clear();
  417. project_ = 0;
  418. UnsubscribeFromEvent(E_FILECHANGED);
  419. }
  420. void AssetDatabase::HandleResourceLoadFailed(StringHash eventType, VariantMap& eventData)
  421. {
  422. if (project_.Null())
  423. return;
  424. String path = eventData[LoadFailed::P_RESOURCENAME].GetString();
  425. Asset* asset = GetAssetByPath(path);
  426. if (!asset)
  427. asset = GetAssetByPath(project_->GetResourcePath() + path);
  428. if (!asset)
  429. return;
  430. Time* time = GetSubsystem<Time>();
  431. unsigned ctime = time->GetSystemTime();
  432. // if less than 5 seconds since last report, stifle report
  433. if (assetImportErrorTimes_.Contains(asset->guid_))
  434. if (ctime - assetImportErrorTimes_[asset->guid_] < 5000)
  435. return;
  436. assetImportErrorTimes_[asset->guid_] = ctime;
  437. VariantMap evData;
  438. evData[AssetImportError::P_PATH] = asset->path_;
  439. evData[AssetImportError::P_GUID] = asset->guid_;
  440. evData[AssetImportError::P_ERROR] = ToString("Asset %s Failed to Load", asset->path_.CString());
  441. SendEvent(E_ASSETIMPORTERROR, evData);
  442. }
  443. void AssetDatabase::HandleFileChanged(StringHash eventType, VariantMap& eventData)
  444. {
  445. // for now, when in read only mode, early exit
  446. // in the future, it is possible we'll want to
  447. // handle this for read only project loads differently
  448. if (GetReadOnly())
  449. {
  450. return;
  451. }
  452. using namespace FileChanged;
  453. const String& fullPath = eventData[P_FILENAME].GetString();
  454. FileSystem* fs = GetSubsystem<FileSystem>();
  455. String pathName, fileName, ext;
  456. SplitPath(fullPath, pathName, fileName, ext);
  457. // ignore changes in the Cache resource dir
  458. if (fullPath == GetCachePath() || pathName.StartsWith(GetCachePath()))
  459. return;
  460. // don't care about directories and asset file changes
  461. if (fs->DirExists(fullPath) || ext == ".asset")
  462. return;
  463. Asset* asset = GetAssetByPath(fullPath);
  464. if (!asset && fs->FileExists(fullPath))
  465. {
  466. Scan();
  467. return;
  468. }
  469. if (asset)
  470. {
  471. if(!fs->Exists(fullPath))
  472. {
  473. DeleteAsset(asset);
  474. }
  475. else
  476. {
  477. if (asset->GetFileTimestamp() != fs->GetLastModifiedTime(asset->GetPath()))
  478. {
  479. asset->SetDirty(true);
  480. Scan();
  481. }
  482. }
  483. }
  484. }
  485. String AssetDatabase::GetResourceImporterName(const String& resourceTypeName)
  486. {
  487. // TODO: have resource type register themselves
  488. if (resourceTypeToImporterType_.Empty())
  489. {
  490. resourceTypeToImporterType_["Sound"] = "AudioImporter";
  491. resourceTypeToImporterType_["Model"] = "ModelImporter";
  492. resourceTypeToImporterType_["Material"] = "MaterialImporter";
  493. resourceTypeToImporterType_["Texture2D"] = "TextureImporter";
  494. resourceTypeToImporterType_["Sprite2D"] = "TextureImporter";
  495. resourceTypeToImporterType_["Image"] = "TextureImporter";
  496. resourceTypeToImporterType_["AnimatedSprite2D"] = "SpriterImporter";
  497. resourceTypeToImporterType_["JSComponentFile"] = "JavascriptImporter";
  498. resourceTypeToImporterType_["JSONFile"] = "JSONImporter";
  499. resourceTypeToImporterType_["ParticleEffect2D"] = "PEXImporter";
  500. resourceTypeToImporterType_["ParticleEffect"] = "ParticleEffectImporter";
  501. resourceTypeToImporterType_["Animation"] = "ModelImporter";
  502. resourceTypeToImporterType_["CSComponentAssembly"] = "NETAssemblyImporter";
  503. resourceTypeToImporterType_["TmxFile2D"] = "TMXImporter";
  504. }
  505. if (!resourceTypeToImporterType_.Contains(resourceTypeName))
  506. return String::EMPTY;
  507. return resourceTypeToImporterType_[resourceTypeName];
  508. }
  509. void AssetDatabase::ReimportAllAssets()
  510. {
  511. if (GetReadOnly())
  512. {
  513. return;
  514. }
  515. List<SharedPtr<Asset>>::ConstIterator itr = assets_.Begin();
  516. while (itr != assets_.End())
  517. {
  518. (*itr)->SetDirty(true);
  519. itr++;
  520. }
  521. Scan();
  522. }
  523. void AssetDatabase::ReimportAllAssetsInDirectory(const String& directoryPath)
  524. {
  525. if (GetReadOnly())
  526. {
  527. return;
  528. }
  529. List<SharedPtr<Asset>>::ConstIterator itr = assets_.Begin();
  530. while (itr != assets_.End())
  531. {
  532. if ((*itr)->GetPath().StartsWith(directoryPath))
  533. {
  534. (*itr)->SetDirty(true);
  535. }
  536. itr++;
  537. }
  538. Scan();
  539. }
  540. bool AssetDatabase::InitCache()
  541. {
  542. FileSystem* fs = GetSubsystem<FileSystem>();
  543. if (!fs->DirExists(GetCachePath()))
  544. fs->CreateDir(GetCachePath());
  545. ResourceCache* cache = GetSubsystem<ResourceCache>();
  546. cache->AddResourceDir(GetCachePath());
  547. Scan();
  548. return true;
  549. }
  550. bool AssetDatabase::CleanCache()
  551. {
  552. FileSystem* fileSystem = GetSubsystem<FileSystem>();
  553. String cachePath = GetCachePath();
  554. if (fileSystem->DirExists(cachePath))
  555. {
  556. ATOMIC_LOGINFOF("Cleaning cache directory %s", cachePath.CString());
  557. fileSystem->RemoveDir(cachePath, true);
  558. if (fileSystem->DirExists(cachePath))
  559. {
  560. ATOMIC_LOGERRORF("Unable to remove cache directory %s", cachePath.CString());
  561. return false;
  562. }
  563. }
  564. fileSystem->CreateDir(cachePath);
  565. if (!fileSystem->DirExists(cachePath))
  566. {
  567. ATOMIC_LOGERRORF("Unable to create cache directory %s", cachePath.CString());
  568. return false;
  569. }
  570. return true;
  571. }
  572. bool AssetDatabase::GenerateCache(bool clean)
  573. {
  574. ATOMIC_LOGINFO("Generating cache... hold on");
  575. if (clean)
  576. {
  577. if (!CleanCache())
  578. return false;
  579. }
  580. ReimportAllAssets();
  581. ATOMIC_LOGINFO("Cache generated");
  582. return true;
  583. }
  584. void AssetDatabase::SetCacheEnabled(bool cacheEnabled)
  585. {
  586. cacheEnabled_ = cacheEnabled;
  587. }
  588. bool AssetDatabase::GetReadOnly() const
  589. {
  590. return project_.Null() ? false : project_->GetReadOnly();
  591. }
  592. }