BsProjectLibrary.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727
  1. #include "BsProjectLibrary.h"
  2. #include "BsEditorApplication.h"
  3. #include "CmPath.h"
  4. #include "CmFileSystem.h"
  5. #include "CmException.h"
  6. #include "CmResources.h"
  7. #include "CmResourceManifest.h"
  8. #include "CmImporter.h"
  9. #include "BsResourceMeta.h"
  10. #include "CmResources.h"
  11. #include "CmImporter.h"
  12. #include "CmImportOptions.h"
  13. #include "CmFileSerializer.h"
  14. #include "CmFolderMonitor.h"
  15. #include "CmDebug.h"
  16. #include "BsProjectLibraryEntries.h"
  17. using namespace CamelotFramework;
  18. using namespace BansheeEngine;
  19. namespace BansheeEditor
  20. {
  21. const WString ProjectLibrary::INTERNAL_RESOURCES_DIR = L"Internal\\Resources";
  22. const WString ProjectLibrary::LIBRARY_ENTRIES_FILENAME = L"ProjectLibrary.asset";
  23. const WString ProjectLibrary::RESOURCE_MANIFEST_FILENAME = L"ResourceManifest.asset";
  24. ProjectLibrary::LibraryEntry::LibraryEntry(const CM::WString& path, const CM::WString& name, DirectoryEntry* parent, LibraryEntryType type)
  25. :path(path), parent(parent), type(type), elementName(name)
  26. { }
  27. ProjectLibrary::ResourceEntry::ResourceEntry(const CM::WString& path, const CM::WString& name, DirectoryEntry* parent)
  28. :LibraryEntry(path, name, parent, LibraryEntryType::File), lastUpdateTime(0)
  29. { }
  30. ProjectLibrary::DirectoryEntry::DirectoryEntry(const CM::WString& path, const CM::WString& name, DirectoryEntry* parent)
  31. :LibraryEntry(path, name, parent, LibraryEntryType::Directory)
  32. { }
  33. ProjectLibrary::ProjectLibrary()
  34. :mRootEntry(nullptr)
  35. {
  36. mMonitor = cm_new<FolderMonitor>();
  37. FolderChange folderChanges = (FolderChange)((UINT32)FolderChange::FileName | (UINT32)FolderChange::DirName |
  38. (UINT32)FolderChange::Creation | (UINT32)FolderChange::LastWrite);
  39. mMonitor->startMonitor(EditorApplication::instance().getResourcesFolderPath(), true, folderChanges);
  40. mMonitor->onAdded.connect(boost::bind(&ProjectLibrary::onMonitorFileModified, this, _1));
  41. mMonitor->onRemoved.connect(boost::bind(&ProjectLibrary::onMonitorFileModified, this, _1));
  42. mMonitor->onModified.connect(boost::bind(&ProjectLibrary::onMonitorFileModified, this, _1));
  43. load();
  44. if(mResourceManifest == nullptr)
  45. mResourceManifest = ResourceManifest::create("ProjectLibrary");
  46. gResources().registerResourceManifest(mResourceManifest);
  47. checkForModifications(EditorApplication::instance().getResourcesFolderPath());
  48. }
  49. ProjectLibrary::~ProjectLibrary()
  50. {
  51. save();
  52. mMonitor->stopMonitorAll();
  53. cm_delete(mMonitor);
  54. if(mRootEntry != nullptr)
  55. deleteDirectoryInternal(mRootEntry);
  56. }
  57. void ProjectLibrary::update()
  58. {
  59. mMonitor->update();
  60. }
  61. void ProjectLibrary::checkForModifications(const CM::WString& fullPath)
  62. {
  63. if(!Path::includes(fullPath, EditorApplication::instance().getResourcesFolderPath()))
  64. return; // Folder not part of our resources path, so no modifications
  65. if(mRootEntry == nullptr)
  66. {
  67. WString resPath = EditorApplication::instance().getResourcesFolderPath();
  68. mRootEntry = cm_new<DirectoryEntry>(resPath, Path::getFilename(resPath), nullptr);
  69. }
  70. WString pathToSearch = fullPath;
  71. LibraryEntry* entry = findEntry(pathToSearch);
  72. if(entry == nullptr) // File could be new, try to find parent directory entry
  73. {
  74. WString parentDirPath = Path::parentPath(pathToSearch);
  75. entry = findEntry(parentDirPath);
  76. // Cannot find parent directory. Create the needed hierarchy.
  77. DirectoryEntry* entryParent = nullptr;
  78. DirectoryEntry* newHierarchyParent = nullptr;
  79. if(entry == nullptr)
  80. createInternalParentHierarchy(pathToSearch, &newHierarchyParent, &entryParent);
  81. else
  82. entryParent = static_cast<DirectoryEntry*>(entry);
  83. if(FileSystem::isFile(pathToSearch))
  84. {
  85. addResourceInternal(entryParent, pathToSearch);
  86. }
  87. else if(FileSystem::isDirectory(pathToSearch))
  88. {
  89. addDirectoryInternal(entryParent, pathToSearch);
  90. if(newHierarchyParent == nullptr)
  91. checkForModifications(pathToSearch);
  92. }
  93. if(newHierarchyParent != nullptr)
  94. checkForModifications(newHierarchyParent->path);
  95. }
  96. else if(entry->type == LibraryEntryType::File)
  97. {
  98. if(FileSystem::isFile(entry->path))
  99. {
  100. reimportResourceInternal(static_cast<ResourceEntry*>(entry));
  101. }
  102. else
  103. {
  104. deleteResourceInternal(static_cast<ResourceEntry*>(entry));
  105. }
  106. }
  107. else if(entry->type == LibraryEntryType::Directory) // Check folder and all subfolders for modifications
  108. {
  109. if(!FileSystem::isDirectory(entry->path))
  110. {
  111. deleteDirectoryInternal(static_cast<DirectoryEntry*>(entry));
  112. }
  113. else
  114. {
  115. Stack<DirectoryEntry*>::type todo;
  116. todo.push(static_cast<DirectoryEntry*>(entry));
  117. Vector<WString>::type childFiles;
  118. Vector<WString>::type childDirectories;
  119. Vector<bool>::type existingEntries;
  120. Vector<LibraryEntry*>::type toDelete;
  121. while(!todo.empty())
  122. {
  123. DirectoryEntry* currentDir = todo.top();
  124. todo.pop();
  125. existingEntries.clear();
  126. existingEntries.resize(currentDir->mChildren.size());
  127. for(UINT32 i = 0; i < (UINT32)currentDir->mChildren.size(); i++)
  128. existingEntries[i] = false;
  129. childFiles.clear();
  130. childDirectories.clear();
  131. FileSystem::getChildren(currentDir->path, childFiles, childDirectories);
  132. for(auto& filePath : childFiles)
  133. {
  134. if(isMeta(filePath))
  135. {
  136. WString sourceFilePath = filePath;
  137. Path::replaceExtension(sourceFilePath, L"");
  138. if(!FileSystem::isFile(sourceFilePath))
  139. {
  140. LOGWRN("Found a .meta file without a corresponding resource. Deleting.");
  141. FileSystem::remove(filePath);
  142. }
  143. }
  144. else
  145. {
  146. ResourceEntry* existingEntry = nullptr;
  147. UINT32 idx = 0;
  148. for(auto& child : currentDir->mChildren)
  149. {
  150. if(child->type == LibraryEntryType::File && Path::equals(child->path, filePath))
  151. {
  152. existingEntries[idx] = true;
  153. existingEntry = static_cast<ResourceEntry*>(child);
  154. break;
  155. }
  156. idx++;
  157. }
  158. if(existingEntry != nullptr)
  159. {
  160. reimportResourceInternal(existingEntry);
  161. }
  162. else
  163. {
  164. addResourceInternal(currentDir, filePath);
  165. }
  166. }
  167. }
  168. for(auto& dirPath : childDirectories)
  169. {
  170. DirectoryEntry* existingEntry = nullptr;
  171. UINT32 idx = 0;
  172. for(auto& child : currentDir->mChildren)
  173. {
  174. if(child->type == LibraryEntryType::Directory && Path::equals(child->path, dirPath))
  175. {
  176. existingEntries[idx] = true;
  177. existingEntry = static_cast<DirectoryEntry*>(child);
  178. break;
  179. }
  180. idx++;
  181. }
  182. if(existingEntry == nullptr)
  183. addDirectoryInternal(currentDir, dirPath);
  184. }
  185. {
  186. for(UINT32 i = 0; i < (UINT32)existingEntries.size(); i++)
  187. {
  188. if(existingEntries[i])
  189. continue;
  190. toDelete.push_back(currentDir->mChildren[i]);
  191. }
  192. for(auto& child : toDelete)
  193. {
  194. if(child->type == LibraryEntryType::Directory)
  195. deleteDirectoryInternal(static_cast<DirectoryEntry*>(child));
  196. else if(child->type == LibraryEntryType::File)
  197. deleteResourceInternal(static_cast<ResourceEntry*>(child));
  198. }
  199. }
  200. for(auto& child : currentDir->mChildren)
  201. {
  202. if(child->type == LibraryEntryType::Directory)
  203. todo.push(static_cast<DirectoryEntry*>(child));
  204. }
  205. }
  206. }
  207. }
  208. }
  209. ProjectLibrary::ResourceEntry* ProjectLibrary::addResourceInternal(DirectoryEntry* parent, const CM::WString& filePath)
  210. {
  211. ResourceEntry* newResource = cm_new<ResourceEntry>(filePath, Path::getFilename(filePath), parent);
  212. parent->mChildren.push_back(newResource);
  213. reimportResourceInternal(newResource);
  214. if(!onEntryAdded.empty())
  215. onEntryAdded(filePath);
  216. return newResource;
  217. }
  218. ProjectLibrary::DirectoryEntry* ProjectLibrary::addDirectoryInternal(DirectoryEntry* parent, const CM::WString& dirPath)
  219. {
  220. DirectoryEntry* newEntry = cm_new<DirectoryEntry>(dirPath, Path::getFilename(dirPath), parent);
  221. parent->mChildren.push_back(newEntry);
  222. if(!onEntryAdded.empty())
  223. onEntryAdded(dirPath);
  224. return newEntry;
  225. }
  226. void ProjectLibrary::deleteResourceInternal(ResourceEntry* resource)
  227. {
  228. if(resource->meta != nullptr)
  229. {
  230. WString path;
  231. if(mResourceManifest->uuidToFilePath(resource->meta->getUUID(), path))
  232. {
  233. if(FileSystem::isFile(path))
  234. FileSystem::remove(path);
  235. mResourceManifest->unregisterResource(resource->meta->getUUID());
  236. }
  237. }
  238. DirectoryEntry* parent = resource->parent;
  239. auto findIter = std::find_if(parent->mChildren.begin(), parent->mChildren.end(),
  240. [&] (const LibraryEntry* entry) { return entry == resource; });
  241. parent->mChildren.erase(findIter);
  242. if(!onEntryRemoved.empty())
  243. onEntryRemoved(resource->path);
  244. cm_delete(resource);
  245. }
  246. void ProjectLibrary::deleteDirectoryInternal(DirectoryEntry* directory)
  247. {
  248. if(directory == mRootEntry)
  249. mRootEntry = nullptr;
  250. CM::Vector<LibraryEntry*>::type childrenToDestroy = directory->mChildren;
  251. for(auto& child : childrenToDestroy)
  252. {
  253. if(child->type == LibraryEntryType::Directory)
  254. deleteDirectoryInternal(static_cast<DirectoryEntry*>(child));
  255. else
  256. deleteResourceInternal(static_cast<ResourceEntry*>(child));
  257. }
  258. DirectoryEntry* parent = directory->parent;
  259. if(parent != nullptr)
  260. {
  261. auto findIter = std::find_if(parent->mChildren.begin(), parent->mChildren.end(),
  262. [&] (const LibraryEntry* entry) { return entry == directory; });
  263. parent->mChildren.erase(findIter);
  264. }
  265. if(!onEntryRemoved.empty())
  266. onEntryRemoved(directory->path);
  267. cm_delete(directory);
  268. }
  269. void ProjectLibrary::reimportResourceInternal(ResourceEntry* resource)
  270. {
  271. WString ext = Path::getExtension(resource->path);
  272. WString metaPath = resource->path + L".meta";
  273. ext = ext.substr(1, ext.size() - 1); // Remove the .
  274. if(!Importer::instance().supportsFileType(ext))
  275. return;
  276. if(resource->meta == nullptr)
  277. {
  278. FileSerializer fs;
  279. if(FileSystem::isFile(metaPath))
  280. {
  281. std::shared_ptr<IReflectable> loadedMeta = fs.decode(metaPath);
  282. if(loadedMeta != nullptr && loadedMeta->isDerivedFrom(ResourceMeta::getRTTIStatic()))
  283. {
  284. ResourceMetaPtr resourceMeta = std::static_pointer_cast<ResourceMeta>(loadedMeta);
  285. resource->meta = resourceMeta;
  286. }
  287. }
  288. }
  289. if(!isUpToDate(resource))
  290. {
  291. ImportOptionsPtr importOptions = nullptr;
  292. if(resource->meta != nullptr)
  293. importOptions = resource->meta->getImportOptions();
  294. else
  295. importOptions = Importer::instance().createImportOptions(resource->path);
  296. HResource importedResource;
  297. if(resource->meta == nullptr)
  298. {
  299. importedResource = Importer::instance().import(resource->path, importOptions);
  300. resource->meta = ResourceMeta::create(importedResource.getUUID(), importOptions);
  301. FileSerializer fs;
  302. fs.encode(resource->meta.get(), metaPath);
  303. }
  304. else
  305. {
  306. importedResource = HResource(resource->meta->getUUID());
  307. Importer::instance().reimport(importedResource, resource->path, importOptions);
  308. }
  309. WString internalResourcesPath = Path::combine(EditorApplication::instance().getActiveProjectPath(), INTERNAL_RESOURCES_DIR);
  310. if(!FileSystem::isDirectory(internalResourcesPath))
  311. FileSystem::createDir(internalResourcesPath);
  312. internalResourcesPath = Path::combine(internalResourcesPath, toWString(importedResource.getUUID()) + L".asset");
  313. gResources().save(importedResource, internalResourcesPath, true);
  314. gResources().unload(importedResource);
  315. mResourceManifest->registerResource(importedResource.getUUID(), internalResourcesPath);
  316. resource->lastUpdateTime = std::time(nullptr);
  317. }
  318. }
  319. bool ProjectLibrary::isUpToDate(ResourceEntry* resource) const
  320. {
  321. if(resource->meta == nullptr)
  322. return false;
  323. WString path;
  324. if(!mResourceManifest->uuidToFilePath(resource->meta->getUUID(), path))
  325. return false;
  326. if(!FileSystem::isFile(path))
  327. return false;
  328. std::time_t lastModifiedTime = FileSystem::getLastModifiedTime(path);
  329. return lastModifiedTime <= resource->lastUpdateTime;
  330. }
  331. ProjectLibrary::LibraryEntry* ProjectLibrary::findEntry(const CM::WString& fullPath) const
  332. {
  333. Vector<WString>::type pathElems = Path::split(fullPath);
  334. Vector<WString>::type rootElems = Path::split(mRootEntry->path);
  335. auto pathIter = pathElems.begin();
  336. auto rootIter = rootElems.begin();
  337. while(pathIter != pathElems.end() && rootIter != rootElems.end() && Path::comparePathElements(*pathIter, *rootIter))
  338. {
  339. ++pathIter;
  340. ++rootIter;
  341. }
  342. if(pathIter == pathElems.begin()) // Not a single entry matches Resources path
  343. return nullptr;
  344. --pathIter;
  345. Stack<LibraryEntry*>::type todo;
  346. todo.push(mRootEntry);
  347. while(!todo.empty())
  348. {
  349. LibraryEntry* current = todo.top();
  350. todo.pop();
  351. if(Path::comparePathElements(*pathIter, current->elementName))
  352. {
  353. ++pathIter;
  354. if(pathIter == pathElems.end())
  355. return current;
  356. while(!todo.empty())
  357. todo.pop();
  358. if(current->type == LibraryEntryType::Directory)
  359. {
  360. DirectoryEntry* dirEntry = static_cast<DirectoryEntry*>(current);
  361. for(auto& child : dirEntry->mChildren)
  362. todo.push(child);
  363. }
  364. }
  365. }
  366. return nullptr;
  367. }
  368. void ProjectLibrary::moveEntry(const CM::WString& oldPath, const CM::WString& newPath)
  369. {
  370. if(FileSystem::isFile(oldPath) || FileSystem::isDirectory(oldPath))
  371. FileSystem::move(oldPath, newPath);
  372. WString oldMetaPath = getMetaPath(oldPath);
  373. WString newMetaPath = getMetaPath(newPath);
  374. LibraryEntry* oldEntry = findEntry(oldPath);
  375. if(oldEntry != nullptr) // Moving from the Resources folder
  376. {
  377. // Moved outside of Resources, delete entry & meta file
  378. if(!Path::includes(newPath, EditorApplication::instance().getResourcesFolderPath()))
  379. {
  380. if(oldEntry->type == LibraryEntryType::File)
  381. {
  382. deleteResourceInternal(static_cast<ResourceEntry*>(oldEntry));
  383. if(FileSystem::isFile(oldMetaPath))
  384. FileSystem::remove(oldMetaPath);
  385. }
  386. else if(oldEntry->type == LibraryEntryType::Directory)
  387. deleteDirectoryInternal(static_cast<DirectoryEntry*>(oldEntry));
  388. }
  389. else // Just moving internally
  390. {
  391. if(FileSystem::isFile(oldMetaPath))
  392. FileSystem::move(oldMetaPath, newMetaPath);
  393. DirectoryEntry* parent = oldEntry->parent;
  394. auto findIter = std::find(parent->mChildren.begin(), parent->mChildren.end(), oldEntry);
  395. if(findIter != parent->mChildren.end())
  396. parent->mChildren.erase(findIter);
  397. WString parentPath = Path::parentPath(newPath);
  398. DirectoryEntry* newEntryParent = nullptr;
  399. LibraryEntry* newEntryParentLib = findEntry(parentPath);
  400. if(newEntryParentLib != nullptr)
  401. {
  402. assert(newEntryParentLib->type == LibraryEntryType::Directory);
  403. newEntryParent = static_cast<DirectoryEntry*>(newEntryParentLib);
  404. }
  405. DirectoryEntry* newHierarchyParent = nullptr;
  406. if(newEntryParent == nullptr) // New path parent doesn't exist, so we need to create the hierarchy
  407. createInternalParentHierarchy(newPath, &newHierarchyParent, &newEntryParent);
  408. newEntryParent->mChildren.push_back(oldEntry);
  409. oldEntry->parent = newEntryParent;
  410. oldEntry->path = newPath;
  411. oldEntry->elementName = Path::getFilename(newPath);
  412. if(oldEntry->type == LibraryEntryType::Directory) // Update child paths
  413. {
  414. Stack<LibraryEntry*>::type todo;
  415. todo.push(oldEntry);
  416. while(!todo.empty())
  417. {
  418. LibraryEntry* curEntry = todo.top();
  419. todo.pop();
  420. DirectoryEntry* curDirEntry = static_cast<DirectoryEntry*>(curEntry);
  421. for(auto& child : curDirEntry->mChildren)
  422. {
  423. child->path = Path::combine(child->parent->path, child->elementName);
  424. if(child->type == LibraryEntryType::Directory)
  425. todo.push(child);
  426. }
  427. }
  428. }
  429. if(!onEntryRemoved.empty())
  430. onEntryRemoved(oldPath);
  431. if(!onEntryAdded.empty())
  432. onEntryAdded(newPath);
  433. if(newHierarchyParent != nullptr)
  434. checkForModifications(newHierarchyParent->path);
  435. }
  436. }
  437. else // Moving from outside of the Resources folder (likely adding a new resource)
  438. {
  439. checkForModifications(newPath);
  440. }
  441. }
  442. void ProjectLibrary::deleteEntry(const CM::WString& path)
  443. {
  444. if(FileSystem::isFile(path))
  445. FileSystem::remove(path);
  446. LibraryEntry* entry = findEntry(path);
  447. if(entry != nullptr)
  448. {
  449. if(entry->type == LibraryEntryType::File)
  450. {
  451. deleteResourceInternal(static_cast<ResourceEntry*>(entry));
  452. WString metaPath = getMetaPath(path);
  453. if(FileSystem::isFile(metaPath))
  454. FileSystem::remove(metaPath);
  455. }
  456. else if(entry->type == LibraryEntryType::Directory)
  457. deleteDirectoryInternal(static_cast<DirectoryEntry*>(entry));
  458. }
  459. }
  460. void ProjectLibrary::createInternalParentHierarchy(const CM::WString& fullPath, DirectoryEntry** newHierarchyRoot, DirectoryEntry** newHierarchyLeaf)
  461. {
  462. WString parentPath = fullPath;
  463. DirectoryEntry* newEntryParent = nullptr;
  464. Stack<WString>::type parentPaths;
  465. do
  466. {
  467. WString newParentPath = Path::parentPath(parentPath);
  468. if(newParentPath == parentPath)
  469. break;
  470. LibraryEntry* newEntryParentLib = findEntry(newParentPath);
  471. if(newEntryParentLib != nullptr)
  472. {
  473. assert(newEntryParentLib->type == LibraryEntryType::Directory);
  474. newEntryParent = static_cast<DirectoryEntry*>(newEntryParentLib);
  475. break;
  476. }
  477. parentPaths.push(newParentPath);
  478. parentPath = newParentPath;
  479. } while (true);
  480. assert(newEntryParent != nullptr); // Must exist
  481. if(newHierarchyRoot != nullptr)
  482. *newHierarchyRoot = newEntryParent;
  483. while(!parentPaths.empty())
  484. {
  485. WString curPath = parentPaths.top();
  486. parentPaths.pop();
  487. newEntryParent = addDirectoryInternal(newEntryParent, curPath);
  488. }
  489. if(newHierarchyLeaf != nullptr)
  490. *newHierarchyLeaf = newEntryParent;
  491. }
  492. WString ProjectLibrary::getMetaPath(const CM::WString& path) const
  493. {
  494. WString metaPath = path + L".meta";
  495. return metaPath;
  496. }
  497. bool ProjectLibrary::isMeta(const WString& fullPath) const
  498. {
  499. return Path::getExtension(fullPath) == L".meta";
  500. }
  501. void ProjectLibrary::onMonitorFileModified(const WString& path)
  502. {
  503. if(!isMeta(path))
  504. checkForModifications(path);
  505. else
  506. {
  507. WString resourcePath = path;
  508. Path::replaceExtension(resourcePath, L"");
  509. checkForModifications(resourcePath);
  510. }
  511. }
  512. void ProjectLibrary::save()
  513. {
  514. std::shared_ptr<ProjectLibraryEntries> libEntries = ProjectLibraryEntries::create(*mRootEntry);
  515. WString projectPath = EditorApplication::instance().getActiveProjectPath();
  516. WString libraryEntriesPath = Path::combine(projectPath, INTERNAL_RESOURCES_DIR);
  517. libraryEntriesPath = Path::combine(libraryEntriesPath, LIBRARY_ENTRIES_FILENAME);
  518. FileSerializer fs;
  519. fs.encode(libEntries.get(), libraryEntriesPath);
  520. WString resourceManifestPath = Path::combine(projectPath, INTERNAL_RESOURCES_DIR);
  521. resourceManifestPath = Path::combine(resourceManifestPath, RESOURCE_MANIFEST_FILENAME);
  522. ResourceManifest::save(mResourceManifest, resourceManifestPath, projectPath);
  523. }
  524. void ProjectLibrary::load()
  525. {
  526. if(mRootEntry != nullptr)
  527. {
  528. deleteDirectoryInternal(mRootEntry);
  529. mRootEntry = nullptr;
  530. }
  531. WString projectPath = EditorApplication::instance().getActiveProjectPath();
  532. WString resPath = EditorApplication::instance().getResourcesFolderPath();
  533. mRootEntry = cm_new<DirectoryEntry>(resPath, Path::getFilename(resPath), nullptr);
  534. WString libraryEntriesPath = Path::combine(projectPath, INTERNAL_RESOURCES_DIR);
  535. libraryEntriesPath = Path::combine(libraryEntriesPath, LIBRARY_ENTRIES_FILENAME);
  536. if(FileSystem::exists(libraryEntriesPath))
  537. {
  538. FileSerializer fs;
  539. std::shared_ptr<ProjectLibraryEntries> libEntries = std::static_pointer_cast<ProjectLibraryEntries>(fs.decode(libraryEntriesPath));
  540. *mRootEntry = libEntries->getRootEntry();
  541. }
  542. // Load all meta files
  543. Stack<DirectoryEntry*>::type todo;
  544. todo.push(mRootEntry);
  545. while(!todo.empty())
  546. {
  547. DirectoryEntry* curDir = todo.top();
  548. todo.pop();
  549. for(auto& child : curDir->mChildren)
  550. {
  551. if(child->type == LibraryEntryType::File)
  552. {
  553. ResourceEntry* resEntry = static_cast<ResourceEntry*>(child);
  554. if(resEntry->meta == nullptr)
  555. {
  556. WString metaPath = resEntry->path + L".meta";
  557. FileSerializer fs;
  558. if(FileSystem::isFile(metaPath))
  559. {
  560. std::shared_ptr<IReflectable> loadedMeta = fs.decode(metaPath);
  561. if(loadedMeta != nullptr && loadedMeta->isDerivedFrom(ResourceMeta::getRTTIStatic()))
  562. {
  563. ResourceMetaPtr resourceMeta = std::static_pointer_cast<ResourceMeta>(loadedMeta);
  564. resEntry->meta = resourceMeta;
  565. }
  566. }
  567. }
  568. }
  569. else if(child->type == LibraryEntryType::Directory)
  570. {
  571. todo.push(static_cast<DirectoryEntry*>(child));
  572. }
  573. }
  574. }
  575. // Load resource manifest
  576. WString resourceManifestPath = Path::combine(projectPath, INTERNAL_RESOURCES_DIR);
  577. resourceManifestPath = Path::combine(resourceManifestPath, RESOURCE_MANIFEST_FILENAME);
  578. if(FileSystem::exists(resourceManifestPath))
  579. {
  580. mResourceManifest = ResourceManifest::load(resourceManifestPath, projectPath);
  581. }
  582. }
  583. }