BsProjectLibrary.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760
  1. #include "BsProjectLibrary.h"
  2. #include "BsPath.h"
  3. #include "BsFileSystem.h"
  4. #include "BsException.h"
  5. #include "BsResources.h"
  6. #include "BsResourceManifest.h"
  7. #include "BsImporter.h"
  8. #include "BsProjectResourceMeta.h"
  9. #include "BsResources.h"
  10. #include "BsImporter.h"
  11. #include "BsImportOptions.h"
  12. #include "BsFileSerializer.h"
  13. #include "BsFolderMonitor.h"
  14. #include "BsDebug.h"
  15. #include "BsProjectLibraryEntries.h"
  16. #include "BsResource.h"
  17. using namespace std::placeholders;
  18. namespace BansheeEngine
  19. {
  20. const Path ProjectLibrary::RESOURCES_DIR = L"Resources\\";
  21. const Path 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 Path& path, const 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 Path& path, const WString& name, DirectoryEntry* parent)
  34. :LibraryEntry(path, name, parent, LibraryEntryType::File), lastUpdateTime(0)
  35. { }
  36. ProjectLibrary::DirectoryEntry::DirectoryEntry()
  37. { }
  38. ProjectLibrary::DirectoryEntry::DirectoryEntry(const Path& path, const WString& name, DirectoryEntry* parent)
  39. :LibraryEntry(path, name, parent, LibraryEntryType::Directory)
  40. { }
  41. ProjectLibrary::ProjectLibrary(const Path& projectFolder)
  42. :mRootEntry(nullptr), mProjectFolder(projectFolder)
  43. {
  44. mResourcesFolder = mProjectFolder;
  45. mResourcesFolder.append(RESOURCES_DIR);
  46. mMonitor = bs_new<FolderMonitor>();
  47. FolderChange folderChanges = (FolderChange)((UINT32)FolderChange::FileName | (UINT32)FolderChange::DirName |
  48. (UINT32)FolderChange::Creation | (UINT32)FolderChange::LastWrite);
  49. mMonitor->startMonitor(mResourcesFolder, true, folderChanges);
  50. mMonitor->onAdded.connect(std::bind(&ProjectLibrary::onMonitorFileModified, this, _1));
  51. mMonitor->onRemoved.connect(std::bind(&ProjectLibrary::onMonitorFileModified, this, _1));
  52. mMonitor->onModified.connect(std::bind(&ProjectLibrary::onMonitorFileModified, this, _1));
  53. load();
  54. if(mResourceManifest == nullptr)
  55. mResourceManifest = ResourceManifest::create("ProjectLibrary");
  56. gResources().registerResourceManifest(mResourceManifest);
  57. checkForModifications(mResourcesFolder);
  58. }
  59. ProjectLibrary::~ProjectLibrary()
  60. {
  61. save();
  62. mMonitor->stopMonitorAll();
  63. bs_delete(mMonitor);
  64. if(mRootEntry != nullptr)
  65. deleteDirectoryInternal(mRootEntry);
  66. }
  67. void ProjectLibrary::update()
  68. {
  69. mMonitor->_update();
  70. }
  71. void ProjectLibrary::checkForModifications(const Path& fullPath)
  72. {
  73. if (!mResourcesFolder.includes(fullPath))
  74. return; // Folder not part of our resources path, so no modifications
  75. if(mRootEntry == nullptr)
  76. {
  77. mRootEntry = bs_new<DirectoryEntry>(mResourcesFolder, mResourcesFolder.getWTail(), nullptr);
  78. }
  79. Path pathToSearch = fullPath;
  80. LibraryEntry* entry = findEntry(pathToSearch);
  81. if(entry == nullptr) // File could be new, try to find parent directory entry
  82. {
  83. Path parentDirPath = pathToSearch.getParent();
  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*> todo;
  125. todo.push(static_cast<DirectoryEntry*>(entry));
  126. Vector<Path> childFiles;
  127. Vector<Path> childDirectories;
  128. Vector<bool> existingEntries;
  129. Vector<LibraryEntry*> 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. Path sourceFilePath = filePath;
  146. sourceFilePath.setExtension(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 && 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 && 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 Path& filePath)
  219. {
  220. ResourceEntry* newResource = bs_new<ResourceEntry>(filePath, filePath.getWTail(), 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 Path& dirPath)
  228. {
  229. DirectoryEntry* newEntry = bs_new<DirectoryEntry>(dirPath, dirPath.getWTail(), 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. Path 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. bs_delete(resource);
  254. }
  255. void ProjectLibrary::deleteDirectoryInternal(DirectoryEntry* directory)
  256. {
  257. if(directory == mRootEntry)
  258. mRootEntry = nullptr;
  259. Vector<LibraryEntry*> 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. bs_delete(directory);
  277. }
  278. void ProjectLibrary::reimportResourceInternal(ResourceEntry* resource)
  279. {
  280. WString ext = resource->path.getWExtension();
  281. Path metaPath = resource->path;
  282. metaPath.setFilename(metaPath.getWFilename() + L".meta");
  283. ext = ext.substr(1, ext.size() - 1); // Remove the .
  284. if(!Importer::instance().supportsFileType(ext))
  285. return;
  286. if(resource->meta == nullptr)
  287. {
  288. FileSerializer fs;
  289. if(FileSystem::isFile(metaPath))
  290. {
  291. std::shared_ptr<IReflectable> loadedMeta = fs.decode(metaPath);
  292. if(loadedMeta != nullptr && loadedMeta->isDerivedFrom(ProjectResourceMeta::getRTTIStatic()))
  293. {
  294. ProjectResourceMetaPtr resourceMeta = std::static_pointer_cast<ProjectResourceMeta>(loadedMeta);
  295. resource->meta = resourceMeta;
  296. }
  297. }
  298. }
  299. if(!isUpToDate(resource))
  300. {
  301. ImportOptionsPtr importOptions = nullptr;
  302. if(resource->meta != nullptr)
  303. importOptions = resource->meta->getImportOptions();
  304. else
  305. importOptions = Importer::instance().createImportOptions(resource->path);
  306. HResource importedResource;
  307. if(resource->meta == nullptr)
  308. {
  309. importedResource = Importer::instance().import(resource->path, importOptions);
  310. ResourceMetaDataPtr subMeta = importedResource->getMetaData();
  311. UINT32 typeId = importedResource->getTypeId();
  312. resource->meta = ProjectResourceMeta::create(importedResource.getUUID(), typeId, subMeta, importOptions);
  313. FileSerializer fs;
  314. fs.encode(resource->meta.get(), metaPath);
  315. }
  316. else
  317. {
  318. importedResource = HResource(resource->meta->getUUID());
  319. Importer::instance().reimport(importedResource, resource->path, importOptions);
  320. }
  321. Path internalResourcesPath = mProjectFolder;
  322. internalResourcesPath.append(INTERNAL_RESOURCES_DIR);
  323. if(!FileSystem::isDirectory(internalResourcesPath))
  324. FileSystem::createDir(internalResourcesPath);
  325. internalResourcesPath.setFilename(toWString(importedResource.getUUID()) + L".asset");
  326. gResources().save(importedResource, internalResourcesPath, true);
  327. gResources().unload(importedResource);
  328. mResourceManifest->registerResource(importedResource.getUUID(), internalResourcesPath);
  329. resource->lastUpdateTime = std::time(nullptr);
  330. }
  331. }
  332. bool ProjectLibrary::isUpToDate(ResourceEntry* resource) const
  333. {
  334. if(resource->meta == nullptr)
  335. return false;
  336. Path path;
  337. if(!mResourceManifest->uuidToFilePath(resource->meta->getUUID(), path))
  338. return false;
  339. if(!FileSystem::isFile(path))
  340. return false;
  341. std::time_t lastModifiedTime = FileSystem::getLastModifiedTime(path);
  342. return lastModifiedTime <= resource->lastUpdateTime;
  343. }
  344. ProjectLibrary::LibraryEntry* ProjectLibrary::findEntry(const Path& fullPath) const
  345. {
  346. if (!mRootEntry->path.includes(fullPath))
  347. return nullptr;
  348. Path relPath = fullPath.getRelative(mRootEntry->path);
  349. UINT32 numElems = relPath.getNumDirectories() + (relPath.isFile() ? 1 : 0);
  350. UINT32 idx = 0;
  351. LibraryEntry* current = mRootEntry;
  352. while (current != nullptr)
  353. {
  354. if (idx == numElems)
  355. return current;
  356. WString curElem;
  357. if (relPath.isFile() && idx == (numElems - 1))
  358. curElem = relPath.getWFilename();
  359. else
  360. curElem = relPath[idx];
  361. current = nullptr;
  362. if (current->type == LibraryEntryType::Directory)
  363. {
  364. DirectoryEntry* dirEntry = static_cast<DirectoryEntry*>(current);
  365. for (auto& child : dirEntry->mChildren)
  366. {
  367. if (Path::comparePathElem(curElem, child->elementName))
  368. {
  369. idx++;
  370. current = child;
  371. break;
  372. }
  373. }
  374. }
  375. }
  376. return nullptr;
  377. }
  378. ProjectResourceMetaPtr ProjectLibrary::findResourceMeta(const String& uuid) const
  379. {
  380. if (mResourceManifest == nullptr)
  381. return nullptr;
  382. Path filePath;
  383. if (!mResourceManifest->uuidToFilePath(uuid, filePath))
  384. return nullptr;
  385. LibraryEntry* libEntry = findEntry(filePath);
  386. if (libEntry == nullptr || libEntry->type != LibraryEntryType::File)
  387. return nullptr;
  388. ResourceEntry* resEntry = static_cast<ResourceEntry*>(libEntry);
  389. return resEntry->meta;
  390. }
  391. void ProjectLibrary::moveEntry(const Path& oldPath, const Path& newPath)
  392. {
  393. if(FileSystem::isFile(oldPath) || FileSystem::isDirectory(oldPath))
  394. FileSystem::move(oldPath, newPath);
  395. Path oldMetaPath = getMetaPath(oldPath);
  396. Path newMetaPath = getMetaPath(newPath);
  397. LibraryEntry* oldEntry = findEntry(oldPath);
  398. if(oldEntry != nullptr) // Moving from the Resources folder
  399. {
  400. // Moved outside of Resources, delete entry & meta file
  401. if (!mResourcesFolder.includes(newPath))
  402. {
  403. if(oldEntry->type == LibraryEntryType::File)
  404. {
  405. deleteResourceInternal(static_cast<ResourceEntry*>(oldEntry));
  406. if(FileSystem::isFile(oldMetaPath))
  407. FileSystem::remove(oldMetaPath);
  408. }
  409. else if(oldEntry->type == LibraryEntryType::Directory)
  410. deleteDirectoryInternal(static_cast<DirectoryEntry*>(oldEntry));
  411. }
  412. else // Just moving internally
  413. {
  414. if(FileSystem::isFile(oldMetaPath))
  415. FileSystem::move(oldMetaPath, newMetaPath);
  416. DirectoryEntry* parent = oldEntry->parent;
  417. auto findIter = std::find(parent->mChildren.begin(), parent->mChildren.end(), oldEntry);
  418. if(findIter != parent->mChildren.end())
  419. parent->mChildren.erase(findIter);
  420. Path parentPath = newPath.getParent();
  421. DirectoryEntry* newEntryParent = nullptr;
  422. LibraryEntry* newEntryParentLib = findEntry(parentPath);
  423. if(newEntryParentLib != nullptr)
  424. {
  425. assert(newEntryParentLib->type == LibraryEntryType::Directory);
  426. newEntryParent = static_cast<DirectoryEntry*>(newEntryParentLib);
  427. }
  428. DirectoryEntry* newHierarchyParent = nullptr;
  429. if(newEntryParent == nullptr) // New path parent doesn't exist, so we need to create the hierarchy
  430. createInternalParentHierarchy(newPath, &newHierarchyParent, &newEntryParent);
  431. newEntryParent->mChildren.push_back(oldEntry);
  432. oldEntry->parent = newEntryParent;
  433. oldEntry->path = newPath;
  434. oldEntry->elementName = newPath.getWTail();
  435. if(oldEntry->type == LibraryEntryType::Directory) // Update child paths
  436. {
  437. Stack<LibraryEntry*> todo;
  438. todo.push(oldEntry);
  439. while(!todo.empty())
  440. {
  441. LibraryEntry* curEntry = todo.top();
  442. todo.pop();
  443. DirectoryEntry* curDirEntry = static_cast<DirectoryEntry*>(curEntry);
  444. for(auto& child : curDirEntry->mChildren)
  445. {
  446. child->path = child->parent->path;
  447. child->path.append(child->elementName);
  448. if(child->type == LibraryEntryType::Directory)
  449. todo.push(child);
  450. }
  451. }
  452. }
  453. if(!onEntryRemoved.empty())
  454. onEntryRemoved(oldPath);
  455. if(!onEntryAdded.empty())
  456. onEntryAdded(newPath);
  457. if(newHierarchyParent != nullptr)
  458. checkForModifications(newHierarchyParent->path);
  459. }
  460. }
  461. else // Moving from outside of the Resources folder (likely adding a new resource)
  462. {
  463. checkForModifications(newPath);
  464. }
  465. }
  466. void ProjectLibrary::deleteEntry(const Path& path)
  467. {
  468. if(FileSystem::exists(path))
  469. FileSystem::remove(path);
  470. LibraryEntry* entry = findEntry(path);
  471. if(entry != nullptr)
  472. {
  473. if(entry->type == LibraryEntryType::File)
  474. {
  475. deleteResourceInternal(static_cast<ResourceEntry*>(entry));
  476. Path metaPath = getMetaPath(path);
  477. if(FileSystem::isFile(metaPath))
  478. FileSystem::remove(metaPath);
  479. }
  480. else if(entry->type == LibraryEntryType::Directory)
  481. deleteDirectoryInternal(static_cast<DirectoryEntry*>(entry));
  482. }
  483. }
  484. void ProjectLibrary::createInternalParentHierarchy(const Path& fullPath, DirectoryEntry** newHierarchyRoot, DirectoryEntry** newHierarchyLeaf)
  485. {
  486. Path parentPath = fullPath;
  487. DirectoryEntry* newEntryParent = nullptr;
  488. Stack<Path> parentPaths;
  489. do
  490. {
  491. Path newParentPath = parentPath.getParent();
  492. if(newParentPath == parentPath)
  493. break;
  494. LibraryEntry* newEntryParentLib = findEntry(newParentPath);
  495. if(newEntryParentLib != nullptr)
  496. {
  497. assert(newEntryParentLib->type == LibraryEntryType::Directory);
  498. newEntryParent = static_cast<DirectoryEntry*>(newEntryParentLib);
  499. break;
  500. }
  501. parentPaths.push(newParentPath);
  502. parentPath = newParentPath;
  503. } while (true);
  504. assert(newEntryParent != nullptr); // Must exist
  505. if(newHierarchyRoot != nullptr)
  506. *newHierarchyRoot = newEntryParent;
  507. while(!parentPaths.empty())
  508. {
  509. Path curPath = parentPaths.top();
  510. parentPaths.pop();
  511. newEntryParent = addDirectoryInternal(newEntryParent, curPath);
  512. }
  513. if(newHierarchyLeaf != nullptr)
  514. *newHierarchyLeaf = newEntryParent;
  515. }
  516. Path ProjectLibrary::getMetaPath(const Path& path) const
  517. {
  518. Path metaPath = path;
  519. metaPath.setFilename(metaPath.getWFilename() + L".meta");
  520. return metaPath;
  521. }
  522. bool ProjectLibrary::isMeta(const Path& fullPath) const
  523. {
  524. return fullPath.getWExtension() == L".meta";
  525. }
  526. void ProjectLibrary::onMonitorFileModified(const Path& path)
  527. {
  528. if(!isMeta(path))
  529. checkForModifications(path);
  530. else
  531. {
  532. Path resourcePath = path;
  533. resourcePath.setExtension(L"");
  534. checkForModifications(resourcePath);
  535. }
  536. }
  537. void ProjectLibrary::save()
  538. {
  539. std::shared_ptr<ProjectLibraryEntries> libEntries = ProjectLibraryEntries::create(*mRootEntry);
  540. Path libraryEntriesPath = mProjectFolder;
  541. libraryEntriesPath.append(INTERNAL_RESOURCES_DIR);
  542. libraryEntriesPath.append(LIBRARY_ENTRIES_FILENAME);
  543. FileSerializer fs;
  544. fs.encode(libEntries.get(), libraryEntriesPath);
  545. Path resourceManifestPath = mProjectFolder;
  546. resourceManifestPath.append(INTERNAL_RESOURCES_DIR);
  547. resourceManifestPath.append(RESOURCE_MANIFEST_FILENAME);
  548. ResourceManifest::save(mResourceManifest, resourceManifestPath, mProjectFolder);
  549. }
  550. void ProjectLibrary::load()
  551. {
  552. if(mRootEntry != nullptr)
  553. {
  554. deleteDirectoryInternal(mRootEntry);
  555. mRootEntry = nullptr;
  556. }
  557. mRootEntry = bs_new<DirectoryEntry>(mResourcesFolder, mResourcesFolder.getWTail(), nullptr);
  558. Path libraryEntriesPath = mProjectFolder;
  559. libraryEntriesPath.append(INTERNAL_RESOURCES_DIR);
  560. libraryEntriesPath.append(LIBRARY_ENTRIES_FILENAME);
  561. if(FileSystem::exists(libraryEntriesPath))
  562. {
  563. FileSerializer fs;
  564. std::shared_ptr<ProjectLibraryEntries> libEntries = std::static_pointer_cast<ProjectLibraryEntries>(fs.decode(libraryEntriesPath));
  565. *mRootEntry = libEntries->getRootEntry();
  566. for(auto& child : mRootEntry->mChildren)
  567. child->parent = mRootEntry;
  568. mRootEntry->parent = nullptr;
  569. }
  570. // Load all meta files
  571. Stack<DirectoryEntry*> todo;
  572. todo.push(mRootEntry);
  573. while(!todo.empty())
  574. {
  575. DirectoryEntry* curDir = todo.top();
  576. todo.pop();
  577. for(auto& child : curDir->mChildren)
  578. {
  579. if(child->type == LibraryEntryType::File)
  580. {
  581. ResourceEntry* resEntry = static_cast<ResourceEntry*>(child);
  582. if(resEntry->meta == nullptr)
  583. {
  584. Path metaPath = resEntry->path;
  585. metaPath.setFilename(metaPath.getWFilename() + L".meta");
  586. FileSerializer fs;
  587. if(FileSystem::isFile(metaPath))
  588. {
  589. std::shared_ptr<IReflectable> loadedMeta = fs.decode(metaPath);
  590. if(loadedMeta != nullptr && loadedMeta->isDerivedFrom(ProjectResourceMeta::getRTTIStatic()))
  591. {
  592. ProjectResourceMetaPtr resourceMeta = std::static_pointer_cast<ProjectResourceMeta>(loadedMeta);
  593. resEntry->meta = resourceMeta;
  594. }
  595. }
  596. }
  597. }
  598. else if(child->type == LibraryEntryType::Directory)
  599. {
  600. todo.push(static_cast<DirectoryEntry*>(child));
  601. }
  602. }
  603. }
  604. // Load resource manifest
  605. Path resourceManifestPath = mProjectFolder;
  606. resourceManifestPath.append(INTERNAL_RESOURCES_DIR);
  607. resourceManifestPath.append(RESOURCE_MANIFEST_FILENAME);
  608. if(FileSystem::exists(resourceManifestPath))
  609. {
  610. mResourceManifest = ResourceManifest::load(resourceManifestPath, mProjectFolder);
  611. }
  612. }
  613. }