2
0

BsResources.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753
  1. //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
  2. //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
  3. #include "BsResources.h"
  4. #include "BsResource.h"
  5. #include "BsResourceManifest.h"
  6. #include "BsException.h"
  7. #include "BsFileSerializer.h"
  8. #include "BsFileSystem.h"
  9. #include "BsTaskScheduler.h"
  10. #include "BsUUID.h"
  11. #include "BsDebug.h"
  12. #include "BsUtility.h"
  13. #include "BsSavedResourceData.h"
  14. #include "BsResourceListenerManager.h"
  15. namespace BansheeEngine
  16. {
  17. Resources::Resources()
  18. {
  19. mDefaultResourceManifest = ResourceManifest::create("Default");
  20. mResourceManifests.push_back(mDefaultResourceManifest);
  21. }
  22. Resources::~Resources()
  23. {
  24. // Unload and invalidate all resources
  25. UnorderedMap<String, LoadedResourceData> loadedResourcesCopy = mLoadedResources;
  26. for (auto& loadedResourcePair : loadedResourcesCopy)
  27. destroy(loadedResourcePair.second.resource);
  28. }
  29. HResource Resources::load(const Path& filePath, bool loadDependencies, bool keepInternalReference)
  30. {
  31. if (!FileSystem::isFile(filePath))
  32. {
  33. LOGWRN_VERBOSE("Cannot load resource. Specified file: " + filePath.toString() + " doesn't exist.");
  34. return HResource();
  35. }
  36. String uuid;
  37. bool foundUUID = getUUIDFromFilePath(filePath, uuid);
  38. if (!foundUUID)
  39. uuid = UUIDGenerator::generateRandom();
  40. return loadInternal(uuid, filePath, true, loadDependencies, keepInternalReference);
  41. }
  42. HResource Resources::load(const WeakResourceHandle<Resource>& handle, bool loadDependencies, bool keepInternalReference)
  43. {
  44. if (handle.mData == nullptr)
  45. return HResource();
  46. String uuid = handle.getUUID();
  47. return loadFromUUID(uuid, false, loadDependencies, keepInternalReference);
  48. }
  49. HResource Resources::loadAsync(const Path& filePath, bool loadDependencies, bool keepInternalReference)
  50. {
  51. if (!FileSystem::isFile(filePath))
  52. {
  53. LOGWRN_VERBOSE("Cannot load resource. Specified file: " + filePath.toString() + " doesn't exist.");
  54. return HResource();
  55. }
  56. String uuid;
  57. bool foundUUID = getUUIDFromFilePath(filePath, uuid);
  58. if (!foundUUID)
  59. uuid = UUIDGenerator::generateRandom();
  60. return loadInternal(uuid, filePath, false, loadDependencies, keepInternalReference);
  61. }
  62. HResource Resources::loadFromUUID(const String& uuid, bool async, bool loadDependencies, bool keepInternalReference)
  63. {
  64. Path filePath;
  65. // Default manifest is at 0th index but all other take priority since Default manifest could
  66. // contain obsolete data.
  67. for (auto iter = mResourceManifests.rbegin(); iter != mResourceManifests.rend(); ++iter)
  68. {
  69. if ((*iter)->uuidToFilePath(uuid, filePath))
  70. break;
  71. }
  72. return loadInternal(uuid, filePath, !async, loadDependencies, keepInternalReference);
  73. }
  74. HResource Resources::loadInternal(const String& UUID, const Path& filePath, bool synchronous, bool loadDependencies, bool keepInternalReference)
  75. {
  76. HResource outputResource;
  77. bool alreadyLoading = false;
  78. bool loadInProgress = false;
  79. {
  80. // Check if resource is already being loaded on a worker thread
  81. BS_LOCK_MUTEX(mInProgressResourcesMutex);
  82. auto iterFind2 = mInProgressResources.find(UUID);
  83. if (iterFind2 != mInProgressResources.end())
  84. {
  85. LoadedResourceData& resData = iterFind2->second->resData;
  86. outputResource = resData.resource.lock();
  87. if (keepInternalReference)
  88. {
  89. resData.numInternalRefs++;
  90. outputResource.addInternalRef();
  91. }
  92. alreadyLoading = true;
  93. loadInProgress = true;
  94. }
  95. // Previously being loaded as async but now we want it synced, so we wait
  96. if (loadInProgress && synchronous)
  97. outputResource.blockUntilLoaded();
  98. if (!alreadyLoading)
  99. {
  100. BS_LOCK_MUTEX(mLoadedResourceMutex);
  101. auto iterFind = mLoadedResources.find(UUID);
  102. if (iterFind != mLoadedResources.end()) // Resource is already loaded
  103. {
  104. LoadedResourceData& resData = iterFind->second;
  105. outputResource = resData.resource.lock();
  106. if (keepInternalReference)
  107. {
  108. resData.numInternalRefs++;
  109. outputResource.addInternalRef();
  110. }
  111. alreadyLoading = true;
  112. }
  113. }
  114. }
  115. // Not loaded and not in progress, start loading of new resource
  116. // (or if already loaded or in progress, load any dependencies)
  117. if (!alreadyLoading)
  118. {
  119. // Check if the handle already exists
  120. BS_LOCK_MUTEX(mLoadedResourceMutex);
  121. auto iterFind = mHandles.find(UUID);
  122. if (iterFind != mHandles.end())
  123. outputResource = iterFind->second.lock();
  124. else
  125. {
  126. outputResource = HResource(UUID);
  127. mHandles[UUID] = outputResource.getWeak();
  128. }
  129. }
  130. // We have nowhere to load from, warn and complete load if a file path was provided,
  131. // otherwise pass through as we might just want to load from memory.
  132. if (filePath.isEmpty())
  133. {
  134. if (!alreadyLoading)
  135. {
  136. LOGWRN_VERBOSE("Cannot load resource. Resource with UUID '" + UUID + "' doesn't exist.");
  137. // Complete the load as that the depedency counter is properly reduced, in case this
  138. // is a dependency of some other resource.
  139. loadComplete(outputResource);
  140. return outputResource;
  141. }
  142. }
  143. else if (!FileSystem::isFile(filePath))
  144. {
  145. LOGWRN_VERBOSE("Cannot load resource. Specified file: " + filePath.toString() + " doesn't exist.");
  146. // Complete the load as that the depedency counter is properly reduced, in case this
  147. // is a dependency of some other resource.
  148. loadComplete(outputResource);
  149. assert(!loadInProgress); // Resource already being loaded but we can't find its path now?
  150. return outputResource;
  151. }
  152. // Load dependency data if a file path is provided
  153. SPtr<SavedResourceData> savedResourceData;
  154. if (!filePath.isEmpty())
  155. {
  156. FileDecoder fs(filePath);
  157. savedResourceData = std::static_pointer_cast<SavedResourceData>(fs.decode());
  158. }
  159. // If already loading keep the old load operation active, otherwise create a new one
  160. if (!alreadyLoading)
  161. {
  162. {
  163. BS_LOCK_MUTEX(mInProgressResourcesMutex);
  164. ResourceLoadData* loadData = bs_new<ResourceLoadData>(outputResource.getWeak(), 0);
  165. mInProgressResources[UUID] = loadData;
  166. loadData->resData = outputResource.getWeak();
  167. if (keepInternalReference)
  168. {
  169. loadData->resData.numInternalRefs++;
  170. outputResource.addInternalRef();
  171. }
  172. loadData->remainingDependencies = 1;
  173. loadData->notifyImmediately = synchronous; // Make resource listener trigger before exit if loading synchronously
  174. // Register dependencies and count them so we know when the resource is fully loaded
  175. if (loadDependencies && savedResourceData != nullptr)
  176. {
  177. for (auto& dependency : savedResourceData->getDependencies())
  178. {
  179. if (dependency != UUID)
  180. {
  181. mDependantLoads[dependency].push_back(loadData);
  182. loadData->remainingDependencies++;
  183. }
  184. }
  185. }
  186. }
  187. if (loadDependencies && savedResourceData != nullptr)
  188. {
  189. const Vector<String>& dependencyUUIDs = savedResourceData->getDependencies();
  190. UINT32 numDependencies = (UINT32)dependencyUUIDs.size();
  191. Vector<HResource> dependencies(numDependencies);
  192. for (UINT32 i = 0; i < numDependencies; i++)
  193. dependencies[i] = loadFromUUID(dependencyUUIDs[i], !synchronous, true, false);
  194. // Keep dependencies alive until the parent is done loading
  195. {
  196. BS_LOCK_MUTEX(mInProgressResourcesMutex);
  197. // At this point the resource is guaranteed to still be in-progress, so it's safe to update its dependency list
  198. mInProgressResources[UUID]->dependencies = dependencies;
  199. }
  200. }
  201. }
  202. else if (loadDependencies && savedResourceData != nullptr) // Queue dependencies in case they aren't already loaded
  203. {
  204. const Vector<String>& dependencies = savedResourceData->getDependencies();
  205. if (!dependencies.empty())
  206. {
  207. {
  208. BS_LOCK_MUTEX(mInProgressResourcesMutex);
  209. ResourceLoadData* loadData = nullptr;
  210. auto iterFind = mInProgressResources.find(UUID);
  211. if (iterFind == mInProgressResources.end()) // Fully loaded
  212. {
  213. loadData = bs_new<ResourceLoadData>(outputResource.getWeak(), 0);
  214. loadData->resData = outputResource.getWeak();
  215. loadData->remainingDependencies = 0;
  216. loadData->notifyImmediately = synchronous; // Make resource listener trigger before exit if loading synchronously
  217. mInProgressResources[UUID] = loadData;
  218. }
  219. else
  220. {
  221. loadData = iterFind->second;
  222. }
  223. // Register dependencies and count them so we know when the resource is fully loaded
  224. for (auto& dependency : dependencies)
  225. {
  226. if (dependency != UUID)
  227. {
  228. bool registerDependency = true;
  229. auto iterFind2 = mDependantLoads.find(dependency);
  230. if (iterFind2 != mDependantLoads.end())
  231. {
  232. Vector<ResourceLoadData*>& dependantData = iterFind2->second;
  233. auto iterFind3 = std::find_if(dependantData.begin(), dependantData.end(),
  234. [&](ResourceLoadData* x)
  235. {
  236. return x->resData.resource.getUUID() == outputResource.getUUID();
  237. });
  238. registerDependency = iterFind3 == dependantData.end();
  239. }
  240. if (registerDependency)
  241. {
  242. mDependantLoads[dependency].push_back(loadData);
  243. loadData->remainingDependencies++;
  244. loadData->dependencies.push_back(_getResourceHandle(dependency));
  245. }
  246. }
  247. }
  248. }
  249. for (auto& dependency : dependencies)
  250. loadFromUUID(dependency, !synchronous, true, false);
  251. }
  252. }
  253. // Actually start the file read operation if not already loaded or in progress
  254. if (!alreadyLoading && !filePath.isEmpty())
  255. {
  256. // Synchronous or the resource doesn't support async, read the file immediately
  257. if (synchronous || !savedResourceData->allowAsyncLoading())
  258. {
  259. loadCallback(filePath, outputResource);
  260. }
  261. else // Asynchronous, read the file on a worker thread
  262. {
  263. String fileName = filePath.getFilename();
  264. String taskName = "Resource load: " + fileName;
  265. TaskPtr task = Task::create(taskName, std::bind(&Resources::loadCallback, this, filePath, outputResource));
  266. TaskScheduler::instance().addTask(task);
  267. }
  268. }
  269. else // File already loaded or in progress
  270. {
  271. // Complete the load unless its in progress in which case we wait for its worker thread to complete it.
  272. // In case file is already loaded this will only decrement dependency count in case this resource is a dependency.
  273. if (!loadInProgress)
  274. loadComplete(outputResource);
  275. else
  276. {
  277. // In case loading finished in the meantime we cannot be sure at what point ::loadComplete was triggered,
  278. // so trigger it manually so that the dependency count is properly decremented in case this resource
  279. // is a dependency.
  280. BS_LOCK_MUTEX(mLoadedResourceMutex);
  281. auto iterFind = mLoadedResources.find(UUID);
  282. if (iterFind != mLoadedResources.end())
  283. loadComplete(outputResource);
  284. }
  285. }
  286. return outputResource;
  287. }
  288. ResourcePtr Resources::loadFromDiskAndDeserialize(const Path& filePath)
  289. {
  290. FileDecoder fs(filePath);
  291. fs.skip(); // Skipped over saved resource data
  292. std::shared_ptr<IReflectable> loadedData = fs.decode();
  293. if (loadedData == nullptr)
  294. {
  295. LOGERR("Unable to load resource at path \"" + filePath.toString() + "\"");
  296. }
  297. else
  298. {
  299. if (!loadedData->isDerivedFrom(Resource::getRTTIStatic()))
  300. BS_EXCEPT(InternalErrorException, "Loaded class doesn't derive from Resource.");
  301. }
  302. ResourcePtr resource = std::static_pointer_cast<Resource>(loadedData);
  303. return resource;
  304. }
  305. void Resources::release(ResourceHandleBase& resource)
  306. {
  307. const String& UUID = resource.getUUID();
  308. {
  309. bool loadInProgress = false;
  310. BS_LOCK_MUTEX(mInProgressResourcesMutex);
  311. auto iterFind2 = mInProgressResources.find(UUID);
  312. if (iterFind2 != mInProgressResources.end())
  313. loadInProgress = true;
  314. // Technically we should be able to just cancel a load in progress instead of blocking until it finishes.
  315. // However that would mean the last reference could get lost on whatever thread did the loading, which
  316. // isn't something that's supported. If this ends up being a problem either make handle counting atomic
  317. // or add a separate queue for objects destroyed from the load threads.
  318. if (loadInProgress)
  319. resource.blockUntilLoaded();
  320. {
  321. BS_LOCK_MUTEX(mLoadedResourceMutex);
  322. auto iterFind = mLoadedResources.find(UUID);
  323. if (iterFind != mLoadedResources.end()) // Resource is already loaded
  324. {
  325. LoadedResourceData& resData = iterFind->second;
  326. assert(resData.numInternalRefs > 0);
  327. resData.numInternalRefs--;
  328. resource.removeInternalRef();
  329. return;
  330. }
  331. }
  332. }
  333. }
  334. void Resources::unloadAllUnused()
  335. {
  336. Vector<HResource> resourcesToUnload;
  337. {
  338. BS_LOCK_MUTEX(mLoadedResourceMutex);
  339. for(auto iter = mLoadedResources.begin(); iter != mLoadedResources.end(); ++iter)
  340. {
  341. const LoadedResourceData& resData = iter->second;
  342. if (resData.resource.mData->mRefCount == resData.numInternalRefs) // Only internal references exist, free it
  343. resourcesToUnload.push_back(resData.resource.lock());
  344. }
  345. }
  346. // Note: When unloading multiple resources it's possible that unloading one will also unload
  347. // another resource in "resourcesToUnload". This is fine because "unload" deals with invalid
  348. // handles gracefully.
  349. for(auto iter = resourcesToUnload.begin(); iter != resourcesToUnload.end(); ++iter)
  350. {
  351. release(*iter);
  352. }
  353. }
  354. void Resources::destroy(ResourceHandleBase& resource)
  355. {
  356. if (resource.mData == nullptr)
  357. return;
  358. const String& uuid = resource.getUUID();
  359. if (!resource.isLoaded(false))
  360. {
  361. bool loadInProgress = false;
  362. {
  363. BS_LOCK_MUTEX(mInProgressResourcesMutex);
  364. auto iterFind2 = mInProgressResources.find(uuid);
  365. if (iterFind2 != mInProgressResources.end())
  366. loadInProgress = true;
  367. }
  368. if (loadInProgress) // If it's still loading wait until that finishes
  369. resource.blockUntilLoaded();
  370. else
  371. return; // Already unloaded
  372. }
  373. // Notify external systems before we actually destroy it
  374. onResourceDestroyed(uuid);
  375. resource.mData->mPtr->destroy();
  376. {
  377. BS_LOCK_MUTEX(mLoadedResourceMutex);
  378. auto iterFind = mLoadedResources.find(uuid);
  379. if (iterFind != mLoadedResources.end())
  380. {
  381. LoadedResourceData& resData = iterFind->second;
  382. while (resData.numInternalRefs > 0)
  383. {
  384. resData.numInternalRefs--;
  385. resData.resource.removeInternalRef();
  386. }
  387. mLoadedResources.erase(iterFind);
  388. }
  389. else
  390. {
  391. assert(false); // This should never happen but in case it does fail silently in release mode
  392. }
  393. }
  394. resource.setHandleData(nullptr, uuid);
  395. }
  396. void Resources::save(const HResource& resource, const Path& filePath, bool overwrite)
  397. {
  398. if (resource == nullptr)
  399. return;
  400. if (!resource.isLoaded(false))
  401. {
  402. bool loadInProgress = false;
  403. {
  404. BS_LOCK_MUTEX(mInProgressResourcesMutex);
  405. auto iterFind2 = mInProgressResources.find(resource.getUUID());
  406. if (iterFind2 != mInProgressResources.end())
  407. loadInProgress = true;
  408. }
  409. if (loadInProgress) // If it's still loading wait until that finishes
  410. resource.blockUntilLoaded();
  411. else
  412. return; // Nothing to save
  413. }
  414. bool fileExists = FileSystem::isFile(filePath);
  415. if(fileExists)
  416. {
  417. if(overwrite)
  418. FileSystem::remove(filePath);
  419. else
  420. BS_EXCEPT(InvalidParametersException, "Another file exists at the specified location.");
  421. }
  422. mDefaultResourceManifest->registerResource(resource.getUUID(), filePath);
  423. Vector<ResourceDependency> dependencyList = Utility::findResourceDependencies(*resource.get());
  424. Vector<String> dependencyUUIDs(dependencyList.size());
  425. for (UINT32 i = 0; i < (UINT32)dependencyList.size(); i++)
  426. dependencyUUIDs[i] = dependencyList[i].resource.getUUID();
  427. SPtr<SavedResourceData> resourceData = bs_shared_ptr_new<SavedResourceData>(dependencyUUIDs, resource->allowAsyncLoading());
  428. FileEncoder fs(filePath);
  429. fs.encode(resourceData.get());
  430. fs.encode(resource.get());
  431. }
  432. void Resources::save(const HResource& resource)
  433. {
  434. if (resource == nullptr)
  435. return;
  436. Path path;
  437. if (getFilePathFromUUID(resource.getUUID(), path))
  438. save(resource, path, true);
  439. }
  440. void Resources::update(HResource& handle, const ResourcePtr& resource)
  441. {
  442. const String& uuid = handle.getUUID();
  443. handle.setHandleData(resource, uuid);
  444. {
  445. BS_LOCK_MUTEX(mLoadedResourceMutex);
  446. auto iterFind = mLoadedResources.find(uuid);
  447. if (iterFind == mLoadedResources.end())
  448. {
  449. LoadedResourceData& resData = mLoadedResources[uuid];
  450. resData.resource = handle.getWeak();
  451. }
  452. }
  453. onResourceModified(handle);
  454. }
  455. Vector<String> Resources::getDependencies(const Path& filePath)
  456. {
  457. SPtr<SavedResourceData> savedResourceData;
  458. if (!filePath.isEmpty())
  459. {
  460. FileDecoder fs(filePath);
  461. savedResourceData = std::static_pointer_cast<SavedResourceData>(fs.decode());
  462. }
  463. return savedResourceData->getDependencies();
  464. }
  465. void Resources::registerResourceManifest(const ResourceManifestPtr& manifest)
  466. {
  467. if(manifest->getName() == "Default")
  468. return;
  469. auto findIter = std::find(mResourceManifests.begin(), mResourceManifests.end(), manifest);
  470. if(findIter == mResourceManifests.end())
  471. mResourceManifests.push_back(manifest);
  472. else
  473. *findIter = manifest;
  474. }
  475. void Resources::unregisterResourceManifest(const ResourceManifestPtr& manifest)
  476. {
  477. if (manifest->getName() == "Default")
  478. return;
  479. auto findIter = std::find(mResourceManifests.begin(), mResourceManifests.end(), manifest);
  480. if (findIter != mResourceManifests.end())
  481. mResourceManifests.erase(findIter);
  482. }
  483. ResourceManifestPtr Resources::getResourceManifest(const String& name) const
  484. {
  485. for(auto iter = mResourceManifests.rbegin(); iter != mResourceManifests.rend(); ++iter)
  486. {
  487. if(name == (*iter)->getName())
  488. return (*iter);
  489. }
  490. return nullptr;
  491. }
  492. bool Resources::isLoaded(const String& uuid, bool checkInProgress)
  493. {
  494. if (checkInProgress)
  495. {
  496. BS_LOCK_MUTEX(mInProgressResourcesMutex);
  497. auto iterFind2 = mInProgressResources.find(uuid);
  498. if (iterFind2 != mInProgressResources.end())
  499. {
  500. return true;
  501. }
  502. {
  503. BS_LOCK_MUTEX(mLoadedResourceMutex);
  504. auto iterFind = mLoadedResources.find(uuid);
  505. if (iterFind != mLoadedResources.end())
  506. {
  507. return true;
  508. }
  509. }
  510. }
  511. return false;
  512. }
  513. HResource Resources::_createResourceHandle(const ResourcePtr& obj)
  514. {
  515. String uuid = UUIDGenerator::generateRandom();
  516. HResource newHandle(obj, uuid);
  517. {
  518. BS_LOCK_MUTEX(mLoadedResourceMutex);
  519. LoadedResourceData& resData = mLoadedResources[uuid];
  520. resData.resource = newHandle.getWeak();
  521. mHandles[uuid] = newHandle.getWeak();
  522. }
  523. return newHandle;
  524. }
  525. HResource Resources::_getResourceHandle(const String& uuid)
  526. {
  527. BS_LOCK_MUTEX(mLoadedResourceMutex);
  528. auto iterFind3 = mHandles.find(uuid);
  529. if (iterFind3 != mHandles.end()) // Not loaded, but handle does exist
  530. {
  531. return iterFind3->second.lock();
  532. }
  533. // Create new handle
  534. HResource handle(uuid);
  535. mHandles[uuid] = handle.getWeak();
  536. return handle;
  537. }
  538. bool Resources::getFilePathFromUUID(const String& uuid, Path& filePath) const
  539. {
  540. for(auto iter = mResourceManifests.rbegin(); iter != mResourceManifests.rend(); ++iter)
  541. {
  542. if((*iter)->uuidToFilePath(uuid, filePath))
  543. return true;
  544. }
  545. return false;
  546. }
  547. bool Resources::getUUIDFromFilePath(const Path& path, String& uuid) const
  548. {
  549. Path manifestPath = path;
  550. if (!manifestPath.isAbsolute())
  551. manifestPath.makeAbsolute(FileSystem::getWorkingDirectoryPath());
  552. for(auto iter = mResourceManifests.rbegin(); iter != mResourceManifests.rend(); ++iter)
  553. {
  554. if ((*iter)->filePathToUUID(manifestPath, uuid))
  555. return true;
  556. }
  557. return false;
  558. }
  559. void Resources::loadComplete(HResource& resource)
  560. {
  561. String uuid = resource.getUUID();
  562. ResourceLoadData* myLoadData = nullptr;
  563. bool finishLoad = true;
  564. Vector<ResourceLoadData*> dependantLoads;
  565. {
  566. BS_LOCK_MUTEX(mInProgressResourcesMutex);
  567. auto iterFind = mInProgressResources.find(uuid);
  568. if (iterFind != mInProgressResources.end())
  569. {
  570. myLoadData = iterFind->second;
  571. finishLoad = myLoadData->remainingDependencies == 0;
  572. if (finishLoad)
  573. mInProgressResources.erase(iterFind);
  574. }
  575. auto iterFind2 = mDependantLoads.find(uuid);
  576. if (iterFind2 != mDependantLoads.end())
  577. dependantLoads = iterFind2->second;
  578. if (finishLoad)
  579. {
  580. mDependantLoads.erase(uuid);
  581. // If loadedData is null then we're probably completing load on an already loaded resource, triggered
  582. // by its dependencies.
  583. if (myLoadData != nullptr && myLoadData->loadedData != nullptr)
  584. {
  585. BS_LOCK_MUTEX(mLoadedResourceMutex);
  586. mLoadedResources[uuid] = myLoadData->resData;
  587. resource.setHandleData(myLoadData->loadedData, uuid);
  588. }
  589. for (auto& dependantLoad : dependantLoads)
  590. dependantLoad->remainingDependencies--;
  591. }
  592. }
  593. for (auto& dependantLoad : dependantLoads)
  594. {
  595. HResource dependant = dependantLoad->resData.resource.lock();
  596. loadComplete(dependant);
  597. }
  598. if (finishLoad && myLoadData != nullptr)
  599. {
  600. onResourceLoaded(resource);
  601. // This should only ever be true on the main thread
  602. if (myLoadData->notifyImmediately)
  603. ResourceListenerManager::instance().notifyListeners(uuid);
  604. bs_delete(myLoadData);
  605. }
  606. }
  607. void Resources::loadCallback(const Path& filePath, HResource& resource)
  608. {
  609. ResourcePtr rawResource = loadFromDiskAndDeserialize(filePath);
  610. {
  611. BS_LOCK_MUTEX(mInProgressResourcesMutex);
  612. // Check if all my dependencies are loaded
  613. ResourceLoadData* myLoadData = mInProgressResources[resource.getUUID()];
  614. myLoadData->loadedData = rawResource;
  615. myLoadData->remainingDependencies--;
  616. }
  617. loadComplete(resource);
  618. }
  619. BS_CORE_EXPORT Resources& gResources()
  620. {
  621. return Resources::instance();
  622. }
  623. }