BsProjectLibrary.cpp 21 KB

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