WwiseResourceLoaderImpl.cpp 112 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655
  1. /*******************************************************************************
  2. The content of this file includes portions of the proprietary AUDIOKINETIC Wwise
  3. Technology released in source code form as part of the game integration package.
  4. The content of this file may not be used without valid licenses to the
  5. AUDIOKINETIC Wwise Technology.
  6. Note that the use of the game engine is subject to the Unreal(R) Engine End User
  7. License Agreement at https://www.unrealengine.com/en-US/eula/unreal
  8. License Usage
  9. Licensees holding valid licenses to the AUDIOKINETIC Wwise Technology may use
  10. this file in accordance with the end user license agreement provided with the
  11. software or, alternatively, in accordance with the terms contained
  12. in a written agreement between you and Audiokinetic Inc.
  13. Copyright (c) 2023 Audiokinetic Inc.
  14. *******************************************************************************/
  15. #include "Wwise/WwiseResourceLoaderImpl.h"
  16. #include "Wwise/CookedData/WwiseInitBankCookedData.h"
  17. #include "Wwise/CookedData/WwiseLocalizedAuxBusCookedData.h"
  18. #include "Wwise/CookedData/WwiseLocalizedSoundBankCookedData.h"
  19. #include "Wwise/CookedData/WwiseLocalizedEventCookedData.h"
  20. #include "Wwise/CookedData/WwiseLocalizedShareSetCookedData.h"
  21. #include "Wwise/API/WwiseSoundEngineAPI.h"
  22. #include "Wwise/Stats/AsyncStats.h"
  23. #include "Wwise/WwiseExternalSourceManager.h"
  24. #include "Wwise/WwiseGlobalCallbacks.h"
  25. #include "Wwise/WwiseMediaManager.h"
  26. #include "Wwise/WwiseResourceLoader.h"
  27. #include "Wwise/WwiseSoundBankManager.h"
  28. #include "Async/Async.h"
  29. #include <inttypes.h>
  30. #include "Wwise/WwiseTask.h"
  31. FWwiseSwitchContainerLeafGroupValueUsageCount::FLoadedData::FLoadedData()
  32. {
  33. }
  34. bool FWwiseSwitchContainerLeafGroupValueUsageCount::FLoadedData::IsLoaded() const
  35. {
  36. return LoadedSoundBanks.Num() > 0 || LoadedExternalSources.Num() > 0 || LoadedMedia.Num() > 0;
  37. }
  38. FWwiseSwitchContainerLeafGroupValueUsageCount::FWwiseSwitchContainerLeafGroupValueUsageCount(
  39. const FWwiseSwitchContainerLeafCookedData& InKey):
  40. Key(InKey)
  41. {}
  42. bool FWwiseSwitchContainerLeafGroupValueUsageCount::HaveAllKeys() const
  43. {
  44. if (UNLIKELY(Key.GroupValueSet.Num() < LoadedGroupValues.Num()))
  45. {
  46. UE_LOG(LogWwiseResourceLoader, Error, TEXT("Have more keys loaded (%d) than existing in key (%d) @ %p for key %s"),
  47. LoadedGroupValues.Num(), Key.GroupValueSet.Num(), &LoadedData, *Key.GetDebugString());
  48. return true;
  49. }
  50. return Key.GroupValueSet.Num() == LoadedGroupValues.Num();
  51. }
  52. WWISE_RESOURCELOADERIMPL_TEST_CONST bool FWwiseResourceLoaderImpl::Test::bMockSleepOnMediaLoad{ false };
  53. FWwiseResourceLoaderImpl::FWwiseResourceLoaderImpl() :
  54. ExecutionQueue(WWISE_EQ_NAME("FWwiseResourceLoaderImpl::ExecutionQueue"))
  55. {
  56. }
  57. FWwiseResourceLoaderImpl::FWwiseResourceLoaderImpl(
  58. IWwiseExternalSourceManager& ExternalSourceManager,
  59. IWwiseMediaManager& MediaManager,
  60. IWwiseSoundBankManager& SoundBankManager) :
  61. ExecutionQueue(WWISE_EQ_NAME("FWwiseResourceLoaderImpl::ExecutionQueue")),
  62. ExternalSourceManager(&ExternalSourceManager),
  63. MediaManager(&MediaManager),
  64. SoundBankManager(&SoundBankManager)
  65. {
  66. #if WITH_EDITORONLY_DATA
  67. GeneratedSoundBanksPath.Path = TEXT("/");
  68. #endif
  69. }
  70. FName FWwiseResourceLoaderImpl::GetUnrealExternalSourcePath() const
  71. {
  72. #if WITH_EDITORONLY_DATA
  73. return FName(GeneratedSoundBanksPath.Path / CurrentPlatform.Platform->PathRelativeToGeneratedSoundBanks.ToString() / CurrentPlatform.Platform->ExternalSourceRootPath.ToString());
  74. #else
  75. if (UNLIKELY(!ExternalSourceManager))
  76. {
  77. ExternalSourceManager = IWwiseExternalSourceManager::Get();
  78. if (UNLIKELY(!ExternalSourceManager))
  79. {
  80. UE_LOG(LogWwiseResourceLoader, Error, TEXT("Failed to retrieve External Source Manager"));
  81. return {};
  82. }
  83. }
  84. return FName(FPaths::ProjectContentDir() / ExternalSourceManager->GetStagingDirectory());
  85. #endif
  86. }
  87. FString FWwiseResourceLoaderImpl::GetUnrealPath() const
  88. {
  89. #if WITH_EDITOR
  90. return GeneratedSoundBanksPath.Path / CurrentPlatform.Platform->PathRelativeToGeneratedSoundBanks.ToString();
  91. #elif WITH_EDITORONLY_DATA
  92. UE_LOG(LogWwiseResourceLoader, Error, TEXT("GetUnrealPath should not be used in WITH_EDITORONLY_DATA (Getting path for %s)"), *InPath);
  93. return GeneratedSoundBanksPath.Path / CurrentPlatform.Platform->PathRelativeToGeneratedSoundBanks;
  94. #else
  95. return StagePath;
  96. #endif
  97. }
  98. FString FWwiseResourceLoaderImpl::GetUnrealPath(const FString& InPath) const
  99. {
  100. #if WITH_EDITOR
  101. return GetUnrealGeneratedSoundBanksPath(InPath);
  102. #elif WITH_EDITORONLY_DATA
  103. UE_LOG(LogWwiseResourceLoader, Error, TEXT("GetUnrealPath should not be used in WITH_EDITORONLY_DATA (Getting path for %s)"), *InPath);
  104. return GetUnrealGeneratedSoundBanksPath(InPath);
  105. #else
  106. return GetUnrealStagePath(InPath);
  107. #endif
  108. }
  109. FString FWwiseResourceLoaderImpl::GetUnrealStagePath(const FString& InPath) const
  110. {
  111. if (UNLIKELY(StagePath.IsEmpty()))
  112. {
  113. UE_LOG(LogWwiseResourceLoader, Error, TEXT("StagePath not set up (GetUnrealStagePath for %s)"), *InPath);
  114. }
  115. return StagePath / InPath;
  116. }
  117. #if WITH_EDITORONLY_DATA
  118. FString FWwiseResourceLoaderImpl::GetUnrealGeneratedSoundBanksPath(const FString& InPath) const
  119. {
  120. if (UNLIKELY(GeneratedSoundBanksPath.Path.IsEmpty()))
  121. {
  122. UE_LOG(LogWwiseResourceLoader, Error, TEXT("GeneratedSoundBanksPath not set up (GetUnrealGeneratedSoundBanksPath for %s)"), *InPath);
  123. }
  124. return GeneratedSoundBanksPath.Path / CurrentPlatform.Platform->PathRelativeToGeneratedSoundBanks.ToString() / InPath;
  125. }
  126. #endif
  127. EWwiseResourceLoaderState FWwiseResourceLoaderImpl::GetResourceLoaderState()
  128. {
  129. return WwiseResourceLoaderState;
  130. }
  131. void FWwiseResourceLoaderImpl::SetResourceLoaderState(EWwiseResourceLoaderState State)
  132. {
  133. WwiseResourceLoaderState = State;
  134. }
  135. bool FWwiseResourceLoaderImpl::IsEnabled()
  136. {
  137. return WwiseResourceLoaderState == EWwiseResourceLoaderState::Enabled;
  138. }
  139. void FWwiseResourceLoaderImpl::Disable()
  140. {
  141. SetResourceLoaderState(EWwiseResourceLoaderState::AlwaysDisabled);
  142. }
  143. void FWwiseResourceLoaderImpl::Enable()
  144. {
  145. SetResourceLoaderState(EWwiseResourceLoaderState::Enabled);
  146. }
  147. void FWwiseResourceLoaderImpl::SetLanguageAsync(FWwiseSetLanguagePromise&& Promise, const FWwiseLanguageCookedData& InLanguage, EWwiseReloadLanguage InReloadLanguage)
  148. {
  149. SCOPED_WWISERESOURCELOADER_EVENT(TEXT("FWwiseResourceLoaderImpl::SetLanguageAsync"));
  150. SCOPE_CYCLE_COUNTER(STAT_WwiseResourceLoaderTiming);
  151. auto OldLanguage = CurrentLanguage;
  152. auto NewLanguage = InLanguage;
  153. if (OldLanguage == NewLanguage)
  154. {
  155. return Promise.EmplaceValue();
  156. }
  157. UE_CLOG(!OldLanguage.GetLanguageName().IsValid(), LogWwiseResourceLoader, Log, TEXT("[SetLanguage] To %s"), *NewLanguage.GetLanguageName().ToString());
  158. UE_CLOG(OldLanguage.GetLanguageName().IsValid(), LogWwiseResourceLoader, Log, TEXT("[SetLanguage] from %s to %s"), *OldLanguage.GetLanguageName().ToString(), *NewLanguage.GetLanguageName().ToString());
  159. FCompletionFuture Future = MakeFulfilledWwisePromise<void>().GetFuture();
  160. if (InReloadLanguage == EWwiseReloadLanguage::Safe)
  161. {
  162. UE_LOG(LogWwiseResourceLoader, Verbose, TEXT("SetLanguage: Stopping all sounds"));
  163. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  164. if (UNLIKELY(!SoundEngine))
  165. {
  166. UE_LOG(LogWwiseResourceLoader, Error, TEXT("SetLanguage: SoundEngine not available to stop all sounds"));
  167. }
  168. else
  169. {
  170. SoundEngine->StopAll();
  171. // Wait two audio processing passes to make sure our StopAll was processed.
  172. FCompletionPromise EndPromise;
  173. auto EndFuture = EndPromise.GetFuture();
  174. Future.Next([Promise = MoveTemp(EndPromise)](int) mutable
  175. {
  176. if(auto* WwiseGlobalCallbacks = FWwiseGlobalCallbacks::Get())
  177. {
  178. FWwiseGlobalCallbacks::FCompletionPromise WaitPromise;
  179. auto WaitFuture = WaitPromise.GetFuture();
  180. WwiseGlobalCallbacks->EndCompletion(MoveTemp(WaitPromise), 2);
  181. WaitFuture.Next([Promise = MoveTemp(Promise)](int) mutable
  182. {
  183. Promise.EmplaceValue();
  184. });
  185. }
  186. else
  187. {
  188. Promise.EmplaceValue();
  189. }
  190. });
  191. Future = MoveTemp(EndFuture);
  192. }
  193. }
  194. CurrentLanguage = NewLanguage;
  195. if (InReloadLanguage == EWwiseReloadLanguage::Manual)
  196. {
  197. Future.Next([Promise = MoveTemp(Promise)](int) mutable
  198. {
  199. UE_LOG(LogWwiseResourceLoader, Verbose, TEXT("SetLanguage: Done (Manual)"));
  200. Promise.EmplaceValue();
  201. });
  202. return;
  203. }
  204. Future.Next([this, OldLanguage = MoveTemp(OldLanguage), NewLanguage = MoveTemp(NewLanguage), Promise = MoveTemp(Promise)](int) mutable
  205. {
  206. ExecutionQueue.Async(WWISERESOURCELOADER_ASYNC_NAME("FWwiseResourceLoaderImpl::SetLanguageAsync Unloading"), [this, OldLanguage = MoveTemp(OldLanguage), NewLanguage = MoveTemp(NewLanguage), Promise = MoveTemp(Promise)]() mutable
  207. {
  208. // Note: these are written as "Log" since it's more dangerous to do loading and unloading operations while the
  209. // asynchronous SetLanguage is executed. This allows for better debugging.
  210. UE_LOG(LogWwiseResourceLoader, Log, TEXT("SetLanguage: Switching languages. Unloading old language %s."),
  211. *OldLanguage.GetLanguageName().ToString());
  212. TArray<FWwiseLoadedSoundBankInfo*> AffectedSoundBanks;
  213. TArray<FWwiseLoadedAuxBusInfo*> AffectedAuxBusses;
  214. TArray<FWwiseLoadedShareSetInfo*> AffectedShareSets;
  215. TArray<FWwiseLoadedEventInfo*> AffectedEvents;
  216. // Unload all objects with a language equal to the old language
  217. FCompletionFutureArray UnloadFutureArray;
  218. for (auto& LoadedSoundBank : LoadedSoundBankList)
  219. {
  220. if (LoadedSoundBank.LanguageRef != OldLanguage)
  221. {
  222. UE_LOG(LogWwiseResourceLoader, VeryVerbose, TEXT("SetLanguage: Skipping SoundBank %s with language %s"),
  223. *LoadedSoundBank.LocalizedSoundBankCookedData.DebugName.ToString(), *LoadedSoundBank.LanguageRef.GetLanguageName().ToString());
  224. continue;
  225. }
  226. auto* SoundBank = LoadedSoundBank.LocalizedSoundBankCookedData.SoundBankLanguageMap.Find(LoadedSoundBank.LanguageRef);
  227. if (LIKELY(SoundBank))
  228. {
  229. AffectedSoundBanks.Add(&LoadedSoundBank);
  230. FCompletionPromise UnloadPromise;
  231. UnloadFutureArray.Add(UnloadPromise.GetFuture());
  232. UnloadSoundBankResources(MoveTemp(UnloadPromise), LoadedSoundBank.LoadedData, *SoundBank);
  233. }
  234. else
  235. {
  236. UE_LOG(LogWwiseResourceLoader, Error, TEXT("SetLanguage: Could not find SoundBank %s with language %s"),
  237. *LoadedSoundBank.LocalizedSoundBankCookedData.DebugName.ToString(), *LoadedSoundBank.LanguageRef.GetLanguageName().ToString());
  238. }
  239. }
  240. for (auto& LoadedAuxBus : LoadedAuxBusList)
  241. {
  242. if (LoadedAuxBus.LanguageRef != OldLanguage)
  243. {
  244. UE_LOG(LogWwiseResourceLoader, VeryVerbose, TEXT("SetLanguage: Skipping AuxBus %s with language %s"),
  245. *LoadedAuxBus.LocalizedAuxBusCookedData.DebugName.ToString(), *LoadedAuxBus.LanguageRef.GetLanguageName().ToString());
  246. continue;
  247. }
  248. auto* AuxBus = LoadedAuxBus.LocalizedAuxBusCookedData.AuxBusLanguageMap.Find(LoadedAuxBus.LanguageRef);
  249. if (LIKELY(AuxBus))
  250. {
  251. AffectedAuxBusses.Add(&LoadedAuxBus);
  252. FCompletionPromise UnloadPromise;
  253. UnloadFutureArray.Add(UnloadPromise.GetFuture());
  254. UnloadAuxBusResources(MoveTemp(UnloadPromise), LoadedAuxBus.LoadedData, *AuxBus);
  255. }
  256. else
  257. {
  258. UE_LOG(LogWwiseResourceLoader, Error, TEXT("SetLanguage: Could not find AuxBus %s with language %s"),
  259. *LoadedAuxBus.LocalizedAuxBusCookedData.DebugName.ToString(), *LoadedAuxBus.LanguageRef.GetLanguageName().ToString());
  260. }
  261. }
  262. for (auto& LoadedShareSet : LoadedShareSetList)
  263. {
  264. if (LoadedShareSet.LanguageRef != OldLanguage)
  265. {
  266. UE_LOG(LogWwiseResourceLoader, VeryVerbose, TEXT("SetLanguage: Skipping ShareSet %s with language %s"),
  267. *LoadedShareSet.LocalizedShareSetCookedData.DebugName.ToString(), *LoadedShareSet.LanguageRef.GetLanguageName().ToString());
  268. continue;
  269. }
  270. auto* ShareSet = LoadedShareSet.LocalizedShareSetCookedData.ShareSetLanguageMap.Find(LoadedShareSet.LanguageRef);
  271. if (LIKELY(ShareSet))
  272. {
  273. AffectedShareSets.Add(&LoadedShareSet);
  274. FCompletionPromise UnloadPromise;
  275. UnloadFutureArray.Add(UnloadPromise.GetFuture());
  276. UnloadShareSetResources(MoveTemp(UnloadPromise), LoadedShareSet.LoadedData, *ShareSet);
  277. }
  278. else
  279. {
  280. UE_LOG(LogWwiseResourceLoader, Error, TEXT("SetLanguage: Could not find ShareSet %s with language %s"),
  281. *LoadedShareSet.LocalizedShareSetCookedData.DebugName.ToString(), *LoadedShareSet.LanguageRef.GetLanguageName().ToString());
  282. }
  283. }
  284. for (auto& LoadedEvent : LoadedEventList)
  285. {
  286. if (LoadedEvent.LanguageRef != OldLanguage)
  287. {
  288. UE_LOG(LogWwiseResourceLoader, VeryVerbose, TEXT("SetLanguage: Skipping Event %s with language %s"),
  289. *LoadedEvent.LocalizedEventCookedData.DebugName.ToString(), *LoadedEvent.LanguageRef.GetLanguageName().ToString());
  290. continue;
  291. }
  292. auto* Event = LoadedEvent.LocalizedEventCookedData.EventLanguageMap.Find(LoadedEvent.LanguageRef);
  293. if (LIKELY(Event))
  294. {
  295. AffectedEvents.Add(&LoadedEvent);
  296. FCompletionPromise UnloadPromise;
  297. UnloadFutureArray.Add(UnloadPromise.GetFuture());
  298. UnloadEventResources(MoveTemp(UnloadPromise), LoadedEvent.LoadedData, *Event);
  299. }
  300. else
  301. {
  302. UE_LOG(LogWwiseResourceLoader, Error, TEXT("SetLanguage: Could not find Event %s with language %s"),
  303. *LoadedEvent.LocalizedEventCookedData.DebugName.ToString(), *LoadedEvent.LanguageRef.GetLanguageName().ToString());
  304. }
  305. }
  306. WaitForFutures(MoveTemp(UnloadFutureArray), [this,
  307. OldLanguage = MoveTemp(OldLanguage),
  308. NewLanguage = MoveTemp(NewLanguage),
  309. Promise = MoveTemp(Promise),
  310. AffectedAuxBusses = MoveTemp(AffectedAuxBusses),
  311. AffectedEvents = MoveTemp(AffectedEvents),
  312. AffectedShareSets = MoveTemp(AffectedShareSets),
  313. AffectedSoundBanks = MoveTemp(AffectedSoundBanks)]() mutable
  314. {
  315. SCOPED_WWISERESOURCELOADER_EVENT_2(TEXT("FWwiseResourceLoaderImpl::SetLanguageAsync Loading"));
  316. UE_LOG(LogWwiseResourceLoader, Log, TEXT("SetLanguage: Loading new language %s."),
  317. *NewLanguage.GetLanguageName().ToString());
  318. FCompletionFutureArray LoadFutureArray;
  319. // Note: The results are ignored. Reloading Wwise objects can individually fail for any given reasons, and it's Out Of Scope
  320. // for the end product to know SetLanguage wasn't totally successful, since there's no real recourse at that point.
  321. for (auto* LoadedSoundBank : AffectedSoundBanks)
  322. {
  323. LoadedSoundBank->LanguageRef = NewLanguage;
  324. auto* SoundBank = LoadedSoundBank->LocalizedSoundBankCookedData.SoundBankLanguageMap.Find(LoadedSoundBank->LanguageRef);
  325. if (LIKELY(SoundBank))
  326. {
  327. FCompletionPromise LoadPromise;
  328. LoadFutureArray.Add(LoadPromise.GetFuture());
  329. FWwiseResourceLoadPromise ResourceLoadPromise;
  330. ResourceLoadPromise.GetFuture().Next([LoadPromise = MoveTemp(LoadPromise)](int) mutable
  331. {
  332. LoadPromise.EmplaceValue();
  333. });
  334. LoadSoundBankResources(MoveTemp(ResourceLoadPromise), LoadedSoundBank->LoadedData, *SoundBank);
  335. }
  336. else
  337. {
  338. UE_LOG(LogWwiseResourceLoader, Error, TEXT("SetLanguage: Could not find SoundBank %s with language %s"),
  339. *LoadedSoundBank->LocalizedSoundBankCookedData.DebugName.ToString(), *LoadedSoundBank->LanguageRef.GetLanguageName().ToString());
  340. }
  341. }
  342. for (auto* LoadedAuxBus : AffectedAuxBusses)
  343. {
  344. LoadedAuxBus->LanguageRef = NewLanguage;
  345. auto* AuxBus = LoadedAuxBus->LocalizedAuxBusCookedData.AuxBusLanguageMap.Find(LoadedAuxBus->LanguageRef);
  346. if (LIKELY(AuxBus))
  347. {
  348. FCompletionPromise LoadPromise;
  349. LoadFutureArray.Add(LoadPromise.GetFuture());
  350. FWwiseResourceLoadPromise ResourceLoadPromise;
  351. ResourceLoadPromise.GetFuture().Next([LoadPromise = MoveTemp(LoadPromise)](int) mutable
  352. {
  353. LoadPromise.EmplaceValue();
  354. });
  355. LoadAuxBusResources(MoveTemp(ResourceLoadPromise), LoadedAuxBus->LoadedData, *AuxBus);
  356. }
  357. else
  358. {
  359. UE_LOG(LogWwiseResourceLoader, Error, TEXT("SetLanguage: Could not find AuxBus %s with language %s"),
  360. *LoadedAuxBus->LocalizedAuxBusCookedData.DebugName.ToString(), *LoadedAuxBus->LanguageRef.GetLanguageName().ToString());
  361. }
  362. }
  363. for (auto* LoadedShareSet : AffectedShareSets)
  364. {
  365. LoadedShareSet->LanguageRef = NewLanguage;
  366. auto* ShareSet = LoadedShareSet->LocalizedShareSetCookedData.ShareSetLanguageMap.Find(LoadedShareSet->LanguageRef);
  367. if (LIKELY(ShareSet))
  368. {
  369. FCompletionPromise LoadPromise;
  370. LoadFutureArray.Add(LoadPromise.GetFuture());
  371. FWwiseResourceLoadPromise ResourceLoadPromise;
  372. ResourceLoadPromise.GetFuture().Next([LoadPromise = MoveTemp(LoadPromise)](int) mutable
  373. {
  374. LoadPromise.EmplaceValue();
  375. });
  376. LoadShareSetResources(MoveTemp(ResourceLoadPromise), LoadedShareSet->LoadedData, *ShareSet);
  377. }
  378. else
  379. {
  380. UE_LOG(LogWwiseResourceLoader, Error, TEXT("SetLanguage: Could not find ShareSet %s with language %s"),
  381. *LoadedShareSet->LocalizedShareSetCookedData.DebugName.ToString(), *LoadedShareSet->LanguageRef.GetLanguageName().ToString());
  382. }
  383. }
  384. for (auto* LoadedEvent : AffectedEvents)
  385. {
  386. LoadedEvent->LanguageRef = NewLanguage;
  387. auto* Event = LoadedEvent->LocalizedEventCookedData.EventLanguageMap.Find(LoadedEvent->LanguageRef);
  388. if (LIKELY(Event))
  389. {
  390. FCompletionPromise LoadPromise;
  391. LoadFutureArray.Add(LoadPromise.GetFuture());
  392. FWwiseResourceLoadPromise ResourceLoadPromise;
  393. ResourceLoadPromise.GetFuture().Next([LoadPromise = MoveTemp(LoadPromise)](int) mutable
  394. {
  395. LoadPromise.EmplaceValue();
  396. });
  397. LoadEventResources(MoveTemp(ResourceLoadPromise), LoadedEvent->LoadedData, *Event);
  398. }
  399. else
  400. {
  401. UE_LOG(LogWwiseResourceLoader, Error, TEXT("SetLanguage: Could not find Event %s with language %s"),
  402. *LoadedEvent->LocalizedEventCookedData.DebugName.ToString(), *LoadedEvent->LanguageRef.GetLanguageName().ToString());
  403. }
  404. }
  405. WaitForFutures(MoveTemp(LoadFutureArray), [
  406. OldLanguage = MoveTemp(OldLanguage),
  407. NewLanguage = MoveTemp(NewLanguage),
  408. Promise = MoveTemp(Promise)]() mutable
  409. {
  410. UE_LOG(LogWwiseResourceLoader, Log, TEXT("SetLanguage: Done switching assets from language %s to language %s."),
  411. *OldLanguage.GetLanguageName().ToString(), *NewLanguage.GetLanguageName().ToString());
  412. Promise.EmplaceValue();
  413. });
  414. });
  415. });
  416. });
  417. }
  418. void FWwiseResourceLoaderImpl::SetPlatform(const FWwiseSharedPlatformId& InPlatform)
  419. {
  420. UE_LOG(LogWwiseResourceLoader, Log, TEXT("SetPlatform: Updating platform from %s (%s) to %s (%s)."),
  421. *CurrentPlatform.GetPlatformName().ToString(), *CurrentPlatform.GetPlatformGuid().ToString(),
  422. *InPlatform.GetPlatformName().ToString(), *InPlatform.GetPlatformGuid().ToString());
  423. CurrentPlatform = InPlatform;
  424. }
  425. FWwiseLoadedAuxBusPtr FWwiseResourceLoaderImpl::CreateAuxBusNode(
  426. const FWwiseLocalizedAuxBusCookedData& InAuxBusCookedData, const FWwiseLanguageCookedData* InLanguageOverride)
  427. {
  428. const auto* LanguageKey = GetLanguageMapKey(InAuxBusCookedData.AuxBusLanguageMap, InLanguageOverride, InAuxBusCookedData.DebugName);
  429. if (UNLIKELY(!LanguageKey))
  430. {
  431. UE_LOG(LogWwiseResourceLoader, Error, TEXT("CreateAuxBusNode: Could not find language for Aux Bus %s"), *InAuxBusCookedData.DebugName.ToString());
  432. return nullptr;
  433. }
  434. return new FWwiseLoadedAuxBusListNode(FWwiseLoadedAuxBusInfo(InAuxBusCookedData, *LanguageKey));
  435. }
  436. void FWwiseResourceLoaderImpl::LoadAuxBusAsync(FWwiseLoadedAuxBusPromise&& Promise, FWwiseLoadedAuxBusPtr&& InAuxBusListNode)
  437. {
  438. SCOPED_WWISERESOURCELOADER_EVENT_2(TEXT("FWwiseResourceLoaderImpl::LoadAuxBusAsync"));
  439. FWwiseAsyncCycleCounter Timing(GET_STATID(STAT_WwiseResourceLoaderTiming));
  440. auto& LoadedAuxBus = InAuxBusListNode->GetValue();
  441. LogLoad(LoadedAuxBus);
  442. const FWwiseAuxBusCookedData* AuxBus = LoadedAuxBus.LocalizedAuxBusCookedData.AuxBusLanguageMap.Find(LoadedAuxBus.LanguageRef);
  443. if (UNLIKELY(!AuxBus))
  444. {
  445. UE_LOG(LogWwiseResourceLoader, Error, TEXT("LoadAuxBusAsync: Could not find AuxBus %s (%" PRIu32 ") in language %s (%" PRIu32 ")"),
  446. *LoadedAuxBus.LocalizedAuxBusCookedData.DebugName.ToString(), LoadedAuxBus.LocalizedAuxBusCookedData.AuxBusId, *LoadedAuxBus.LanguageRef.LanguageName.ToString(), LoadedAuxBus.LanguageRef.LanguageId);
  447. delete InAuxBusListNode;
  448. Timing.Stop();
  449. Promise.EmplaceValue(nullptr);
  450. return;
  451. }
  452. FWwiseResourceLoadPromise ResourceLoadPromise;
  453. auto Future = ResourceLoadPromise.GetFuture();
  454. LoadAuxBusResources(MoveTemp(ResourceLoadPromise), LoadedAuxBus.LoadedData, *AuxBus);
  455. Future.Next([this, &LoadedAuxBus, AuxBus, InAuxBusListNode = MoveTemp(InAuxBusListNode), Promise = MoveTemp(Promise), Timing = MoveTemp(Timing)](bool bResult) mutable
  456. {
  457. if (UNLIKELY(!bResult))
  458. {
  459. UE_LOG(LogWwiseResourceLoader, Error, TEXT("LoadAuxBusAsync: Could not load AuxBus %s (%" PRIu32 ") in language %s (%" PRIu32 ")"),
  460. *LoadedAuxBus.LocalizedAuxBusCookedData.DebugName.ToString(), LoadedAuxBus.LocalizedAuxBusCookedData.AuxBusId, *LoadedAuxBus.LanguageRef.LanguageName.ToString(), LoadedAuxBus.LanguageRef.LanguageId);
  461. delete InAuxBusListNode;
  462. Timing.Stop();
  463. Promise.EmplaceValue(nullptr);
  464. return;
  465. }
  466. AttachAuxBusNode(InAuxBusListNode);
  467. Timing.Stop();
  468. Promise.EmplaceValue(InAuxBusListNode);
  469. });
  470. }
  471. void FWwiseResourceLoaderImpl::UnloadAuxBusAsync(FWwiseResourceUnloadPromise&& Promise, FWwiseLoadedAuxBusPtr&& InAuxBusListNode)
  472. {
  473. SCOPED_WWISERESOURCELOADER_EVENT_2(TEXT("FWwiseResourceLoaderImpl::UnloadAuxBusAsync"));
  474. FWwiseAsyncCycleCounter Timing(GET_STATID(STAT_WwiseResourceLoaderTiming));
  475. auto& LoadedAuxBus = InAuxBusListNode->GetValue();
  476. LogUnload(LoadedAuxBus);
  477. const FWwiseAuxBusCookedData* AuxBus = LoadedAuxBus.LocalizedAuxBusCookedData.AuxBusLanguageMap.Find(LoadedAuxBus.LanguageRef);
  478. if (UNLIKELY(!AuxBus))
  479. {
  480. UE_LOG(LogWwiseResourceLoader, Error, TEXT("UnloadAuxBusAsync: Could not find AuxBus %s (%" PRIu32 ") in language %s (%" PRIu32 "). Leaking!"),
  481. *LoadedAuxBus.LocalizedAuxBusCookedData.DebugName.ToString(), LoadedAuxBus.LocalizedAuxBusCookedData.AuxBusId, *LoadedAuxBus.LanguageRef.LanguageName.ToString(), LoadedAuxBus.LanguageRef.LanguageId);
  482. Timing.Stop();
  483. Promise.EmplaceValue();
  484. return;
  485. }
  486. DetachAuxBusNode(InAuxBusListNode);
  487. FWwiseResourceUnloadPromise ResourceUnloadPromise;
  488. auto Future = ResourceUnloadPromise.GetFuture();
  489. UnloadAuxBusResources(MoveTemp(ResourceUnloadPromise), LoadedAuxBus.LoadedData, *AuxBus);
  490. Future.Next([this, &LoadedAuxBus, AuxBus, InAuxBusListNode = MoveTemp(InAuxBusListNode), Promise = MoveTemp(Promise), Timing = MoveTemp(Timing)](int) mutable
  491. {
  492. delete InAuxBusListNode;
  493. Timing.Stop();
  494. Promise.EmplaceValue();
  495. });
  496. }
  497. FWwiseLoadedEventPtr FWwiseResourceLoaderImpl::CreateEventNode(
  498. const FWwiseLocalizedEventCookedData& InEventCookedData, const FWwiseLanguageCookedData* InLanguageOverride)
  499. {
  500. const auto* LanguageKey = GetLanguageMapKey(InEventCookedData.EventLanguageMap, InLanguageOverride, InEventCookedData.DebugName);
  501. if (UNLIKELY(!LanguageKey))
  502. {
  503. UE_LOG(LogWwiseResourceLoader, Error, TEXT("CreateEventNode: Could not find language for Event %s"), *InEventCookedData.DebugName.ToString());
  504. return nullptr;
  505. }
  506. return new FWwiseLoadedEventListNode(FWwiseLoadedEventInfo(InEventCookedData, *LanguageKey));
  507. }
  508. void FWwiseResourceLoaderImpl::LoadEventAsync(FWwiseLoadedEventPromise&& Promise, FWwiseLoadedEventPtr&& InEventListNode)
  509. {
  510. SCOPED_WWISERESOURCELOADER_EVENT_2(TEXT("FWwiseResourceLoaderImpl::LoadEventAsync"));
  511. FWwiseAsyncCycleCounter Timing(GET_STATID(STAT_WwiseResourceLoaderTiming));
  512. auto& LoadedEvent = InEventListNode->GetValue();
  513. LogLoad(LoadedEvent);
  514. const FWwiseEventCookedData* Event = LoadedEvent.LocalizedEventCookedData.EventLanguageMap.Find(LoadedEvent.LanguageRef);
  515. if (UNLIKELY(!Event))
  516. {
  517. UE_LOG(LogWwiseResourceLoader, Error, TEXT("LoadEventAsync: Could not find Event %s (%" PRIu32 ") in language %s (%" PRIu32 ")"),
  518. *LoadedEvent.LocalizedEventCookedData.DebugName.ToString(), LoadedEvent.LocalizedEventCookedData.EventId, *LoadedEvent.LanguageRef.LanguageName.ToString(), LoadedEvent.LanguageRef.LanguageId);
  519. delete InEventListNode;
  520. Timing.Stop();
  521. Promise.EmplaceValue(nullptr);
  522. return;
  523. }
  524. FWwiseResourceLoadPromise ResourceLoadPromise;
  525. auto Future = ResourceLoadPromise.GetFuture();
  526. LoadEventResources(MoveTemp(ResourceLoadPromise), LoadedEvent.LoadedData, *Event);
  527. Future.Next([this, &LoadedEvent, Event, InEventListNode = MoveTemp(InEventListNode), Promise = MoveTemp(Promise), Timing = MoveTemp(Timing)](bool bResult) mutable
  528. {
  529. if (UNLIKELY(!bResult))
  530. {
  531. UE_LOG(LogWwiseResourceLoader, Error, TEXT("LoadEventAsync: Could not load Event %s (%" PRIu32 ") in language %s (%" PRIu32 ")"),
  532. *LoadedEvent.LocalizedEventCookedData.DebugName.ToString(), LoadedEvent.LocalizedEventCookedData.EventId, *LoadedEvent.LanguageRef.LanguageName.ToString(), LoadedEvent.LanguageRef.LanguageId);
  533. delete InEventListNode;
  534. Timing.Stop();
  535. Promise.EmplaceValue(nullptr);
  536. return;
  537. }
  538. AttachEventNode(InEventListNode);
  539. Timing.Stop();
  540. Promise.EmplaceValue(InEventListNode);
  541. });
  542. }
  543. void FWwiseResourceLoaderImpl::UnloadEventAsync(FWwiseResourceUnloadPromise&& Promise, FWwiseLoadedEventPtr&& InEventListNode)
  544. {
  545. SCOPED_WWISERESOURCELOADER_EVENT_2(TEXT("FWwiseResourceLoaderImpl::UnloadEventAsync"));
  546. FWwiseAsyncCycleCounter Timing(GET_STATID(STAT_WwiseResourceLoaderTiming));
  547. auto& LoadedEvent = InEventListNode->GetValue();
  548. LogUnload(LoadedEvent);
  549. const FWwiseEventCookedData* Event = LoadedEvent.LocalizedEventCookedData.EventLanguageMap.Find(LoadedEvent.LanguageRef);
  550. if (UNLIKELY(!Event))
  551. {
  552. UE_LOG(LogWwiseResourceLoader, Error, TEXT("UnloadEventAsync: Could not find Event %s (%" PRIu32 ") in language %s (%" PRIu32 "). Leaking!"),
  553. *LoadedEvent.LocalizedEventCookedData.DebugName.ToString(), LoadedEvent.LocalizedEventCookedData.EventId, *LoadedEvent.LanguageRef.LanguageName.ToString(), LoadedEvent.LanguageRef.LanguageId);
  554. Timing.Stop();
  555. Promise.EmplaceValue();
  556. return;
  557. }
  558. DetachEventNode(InEventListNode);
  559. FWwiseResourceUnloadPromise ResourceUnloadPromise;
  560. auto Future = ResourceUnloadPromise.GetFuture();
  561. UnloadEventResources(MoveTemp(ResourceUnloadPromise), LoadedEvent.LoadedData, *Event);
  562. Future.Next([this, &LoadedEvent, Event, InEventListNode = MoveTemp(InEventListNode), Promise = MoveTemp(Promise), Timing = MoveTemp(Timing)](int) mutable
  563. {
  564. delete InEventListNode;
  565. Timing.Stop();
  566. Promise.EmplaceValue();
  567. });
  568. }
  569. FWwiseLoadedExternalSourcePtr FWwiseResourceLoaderImpl::CreateExternalSourceNode(
  570. const FWwiseExternalSourceCookedData& InExternalSourceCookedData)
  571. {
  572. return new FWwiseLoadedExternalSourceListNode(FWwiseLoadedExternalSourceInfo(InExternalSourceCookedData));
  573. }
  574. void FWwiseResourceLoaderImpl::LoadExternalSourceAsync(FWwiseLoadedExternalSourcePromise&& Promise, FWwiseLoadedExternalSourcePtr&& InExternalSourceListNode)
  575. {
  576. SCOPED_WWISERESOURCELOADER_EVENT_2(TEXT("FWwiseResourceLoaderImpl::LoadExternalSourceAsync"));
  577. FWwiseAsyncCycleCounter Timing(GET_STATID(STAT_WwiseResourceLoaderTiming));
  578. auto& LoadedExternalSource = InExternalSourceListNode->GetValue();
  579. LogLoad(LoadedExternalSource);
  580. const FWwiseExternalSourceCookedData* ExternalSource = &LoadedExternalSource.ExternalSourceCookedData;
  581. FWwiseResourceLoadPromise ResourceLoadPromise;
  582. auto Future = ResourceLoadPromise.GetFuture();
  583. LoadExternalSourceResources(MoveTemp(ResourceLoadPromise), LoadedExternalSource.LoadedData, *ExternalSource);
  584. Future.Next([this, &LoadedExternalSource, ExternalSource, InExternalSourceListNode = MoveTemp(InExternalSourceListNode), Promise = MoveTemp(Promise), Timing = MoveTemp(Timing)](bool bResult) mutable
  585. {
  586. if (UNLIKELY(!bResult))
  587. {
  588. UE_LOG(LogWwiseResourceLoader, Error, TEXT("LoadExternalSourceAsync: Could not load ExternalSource %s (%" PRIu32 ")"),
  589. *LoadedExternalSource.ExternalSourceCookedData.DebugName.ToString(), LoadedExternalSource.ExternalSourceCookedData.Cookie);
  590. delete InExternalSourceListNode;
  591. Timing.Stop();
  592. Promise.EmplaceValue(nullptr);
  593. return;
  594. }
  595. AttachExternalSourceNode(InExternalSourceListNode);
  596. Timing.Stop();
  597. Promise.EmplaceValue(InExternalSourceListNode);
  598. });
  599. }
  600. void FWwiseResourceLoaderImpl::UnloadExternalSourceAsync(FWwiseResourceUnloadPromise&& Promise, FWwiseLoadedExternalSourcePtr&& InExternalSourceListNode)
  601. {
  602. SCOPED_WWISERESOURCELOADER_EVENT_2(TEXT("FWwiseResourceLoaderImpl::UnloadExternalSourceAsync"));
  603. FWwiseAsyncCycleCounter Timing(GET_STATID(STAT_WwiseResourceLoaderTiming));
  604. auto& LoadedExternalSource = InExternalSourceListNode->GetValue();
  605. LogUnload(LoadedExternalSource);
  606. const FWwiseExternalSourceCookedData* ExternalSource = &LoadedExternalSource.ExternalSourceCookedData;
  607. DetachExternalSourceNode(InExternalSourceListNode);
  608. FWwiseResourceUnloadPromise ResourceUnloadPromise;
  609. auto Future = ResourceUnloadPromise.GetFuture();
  610. UnloadExternalSourceResources(MoveTemp(ResourceUnloadPromise), LoadedExternalSource.LoadedData, *ExternalSource);
  611. Future.Next([this, &LoadedExternalSource, ExternalSource, InExternalSourceListNode = MoveTemp(InExternalSourceListNode), Promise = MoveTemp(Promise), Timing = MoveTemp(Timing)](int) mutable
  612. {
  613. delete InExternalSourceListNode;
  614. Timing.Stop();
  615. Promise.EmplaceValue();
  616. });
  617. }
  618. FWwiseLoadedGroupValuePtr FWwiseResourceLoaderImpl::CreateGroupValueNode(
  619. const FWwiseGroupValueCookedData& InGroupValueCookedData)
  620. {
  621. return new FWwiseLoadedGroupValueListNode(FWwiseLoadedGroupValueInfo(InGroupValueCookedData));
  622. }
  623. void FWwiseResourceLoaderImpl::LoadGroupValueAsync(FWwiseLoadedGroupValuePromise&& Promise, FWwiseLoadedGroupValuePtr&& InGroupValueListNode)
  624. {
  625. SCOPED_WWISERESOURCELOADER_EVENT_2(TEXT("FWwiseResourceLoaderImpl::LoadGroupValueAsync"));
  626. FWwiseAsyncCycleCounter Timing(GET_STATID(STAT_WwiseResourceLoaderTiming));
  627. auto& LoadedGroupValue = InGroupValueListNode->GetValue();
  628. LogLoad(LoadedGroupValue);
  629. const FWwiseGroupValueCookedData* GroupValue = &LoadedGroupValue.GroupValueCookedData;
  630. FWwiseResourceLoadPromise ResourceLoadPromise;
  631. auto Future = ResourceLoadPromise.GetFuture();
  632. LoadGroupValueResources(MoveTemp(ResourceLoadPromise), LoadedGroupValue.LoadedData, *GroupValue);
  633. Future.Next([this, &LoadedGroupValue, GroupValue, InGroupValueListNode = MoveTemp(InGroupValueListNode), Promise = MoveTemp(Promise), Timing = MoveTemp(Timing)](bool bResult) mutable
  634. {
  635. if (UNLIKELY(!bResult))
  636. {
  637. UE_LOG(LogWwiseResourceLoader, Error, TEXT("LoadGroupValueAsync: Could not load GroupValue %s (%s %" PRIu32 ":%" PRIu32 ")"),
  638. *LoadedGroupValue.GroupValueCookedData.DebugName.ToString(), *LoadedGroupValue.GroupValueCookedData.GetTypeName(), LoadedGroupValue.GroupValueCookedData.GroupId, LoadedGroupValue.GroupValueCookedData.Id);
  639. delete InGroupValueListNode;
  640. Timing.Stop();
  641. Promise.EmplaceValue(nullptr);
  642. return;
  643. }
  644. AttachGroupValueNode(InGroupValueListNode);
  645. Timing.Stop();
  646. Promise.EmplaceValue(InGroupValueListNode);
  647. });
  648. }
  649. void FWwiseResourceLoaderImpl::UnloadGroupValueAsync(FWwiseResourceUnloadPromise&& Promise, FWwiseLoadedGroupValuePtr&& InGroupValueListNode)
  650. {
  651. SCOPED_WWISERESOURCELOADER_EVENT_2(TEXT("FWwiseResourceLoaderImpl::UnloadGroupValueAsync"));
  652. FWwiseAsyncCycleCounter Timing(GET_STATID(STAT_WwiseResourceLoaderTiming));
  653. auto& LoadedGroupValue = InGroupValueListNode->GetValue();
  654. LogUnload(LoadedGroupValue);
  655. const FWwiseGroupValueCookedData* GroupValue = &LoadedGroupValue.GroupValueCookedData;
  656. DetachGroupValueNode(InGroupValueListNode);
  657. FWwiseResourceUnloadPromise ResourceUnloadPromise;
  658. auto Future = ResourceUnloadPromise.GetFuture();
  659. UnloadGroupValueResources(MoveTemp(ResourceUnloadPromise), LoadedGroupValue.LoadedData, *GroupValue);
  660. Future.Next([this, &LoadedGroupValue, GroupValue, InGroupValueListNode = MoveTemp(InGroupValueListNode), Promise = MoveTemp(Promise), Timing = MoveTemp(Timing)](int) mutable
  661. {
  662. delete InGroupValueListNode;
  663. Timing.Stop();
  664. Promise.EmplaceValue();
  665. });
  666. }
  667. FWwiseLoadedInitBankPtr FWwiseResourceLoaderImpl::CreateInitBankNode(
  668. const FWwiseInitBankCookedData& InInitBankCookedData)
  669. {
  670. return new FWwiseLoadedInitBankListNode(FWwiseLoadedInitBankInfo(InInitBankCookedData));
  671. }
  672. void FWwiseResourceLoaderImpl::LoadInitBankAsync(FWwiseLoadedInitBankPromise&& Promise, FWwiseLoadedInitBankPtr&& InInitBankListNode)
  673. {
  674. SCOPED_WWISERESOURCELOADER_EVENT_2(TEXT("FWwiseResourceLoaderImpl::LoadInitBankAsync"));
  675. FWwiseAsyncCycleCounter Timing(GET_STATID(STAT_WwiseResourceLoaderTiming));
  676. auto& LoadedInitBank = InInitBankListNode->GetValue();
  677. LogLoad(LoadedInitBank);
  678. const FWwiseInitBankCookedData* InitBank = &LoadedInitBank.InitBankCookedData;
  679. FWwiseResourceLoadPromise ResourceLoadPromise;
  680. auto Future = ResourceLoadPromise.GetFuture();
  681. LoadInitBankResources(MoveTemp(ResourceLoadPromise), LoadedInitBank.LoadedData, *InitBank);
  682. Future.Next([this, &LoadedInitBank, InitBank, InInitBankListNode = MoveTemp(InInitBankListNode), Promise = MoveTemp(Promise), Timing = MoveTemp(Timing)](bool bResult) mutable
  683. {
  684. if (UNLIKELY(!bResult))
  685. {
  686. UE_LOG(LogWwiseResourceLoader, Error, TEXT("LoadInitBankAsync: Could not load InitBank %s (%" PRIu32 ")"),
  687. *LoadedInitBank.InitBankCookedData.DebugName.ToString(), LoadedInitBank.InitBankCookedData.SoundBankId);
  688. delete InInitBankListNode;
  689. Timing.Stop();
  690. Promise.EmplaceValue(nullptr);
  691. return;
  692. }
  693. AttachInitBankNode(InInitBankListNode);
  694. Timing.Stop();
  695. Promise.EmplaceValue(InInitBankListNode);
  696. });
  697. }
  698. void FWwiseResourceLoaderImpl::UnloadInitBankAsync(FWwiseResourceUnloadPromise&& Promise, FWwiseLoadedInitBankPtr&& InInitBankListNode)
  699. {
  700. SCOPED_WWISERESOURCELOADER_EVENT_2(TEXT("FWwiseResourceLoaderImpl::UnloadInitBankAsync"));
  701. FWwiseAsyncCycleCounter Timing(GET_STATID(STAT_WwiseResourceLoaderTiming));
  702. auto& LoadedInitBank = InInitBankListNode->GetValue();
  703. LogUnload(LoadedInitBank);
  704. const FWwiseInitBankCookedData* InitBank = &LoadedInitBank.InitBankCookedData;
  705. DetachInitBankNode(InInitBankListNode);
  706. FWwiseResourceUnloadPromise ResourceUnloadPromise;
  707. auto Future = ResourceUnloadPromise.GetFuture();
  708. UnloadInitBankResources(MoveTemp(ResourceUnloadPromise), LoadedInitBank.LoadedData, *InitBank);
  709. Future.Next([this, &LoadedInitBank, InitBank, InInitBankListNode = MoveTemp(InInitBankListNode), Promise = MoveTemp(Promise), Timing = MoveTemp(Timing)](int) mutable
  710. {
  711. delete InInitBankListNode;
  712. Timing.Stop();
  713. Promise.EmplaceValue();
  714. });
  715. }
  716. FWwiseLoadedMediaPtr FWwiseResourceLoaderImpl::CreateMediaNode(const FWwiseMediaCookedData& InMediaCookedData)
  717. {
  718. return new FWwiseLoadedMediaListNode(FWwiseLoadedMediaInfo(InMediaCookedData));
  719. }
  720. void FWwiseResourceLoaderImpl::LoadMediaAsync(FWwiseLoadedMediaPromise&& Promise, FWwiseLoadedMediaPtr&& InMediaListNode)
  721. {
  722. SCOPED_WWISERESOURCELOADER_EVENT_2(TEXT("FWwiseResourceLoaderImpl::LoadMediaAsync"));
  723. FWwiseAsyncCycleCounter Timing(GET_STATID(STAT_WwiseResourceLoaderTiming));
  724. auto& LoadedMedia = InMediaListNode->GetValue();
  725. LogLoad(LoadedMedia);
  726. const FWwiseMediaCookedData* Media = &LoadedMedia.MediaCookedData;
  727. FWwiseResourceLoadPromise ResourceLoadPromise;
  728. auto Future = ResourceLoadPromise.GetFuture();
  729. LoadMediaResources(MoveTemp(ResourceLoadPromise), LoadedMedia.LoadedData, *Media);
  730. Future.Next([this, &LoadedMedia, Media, InMediaListNode = MoveTemp(InMediaListNode), Promise = MoveTemp(Promise), Timing = MoveTemp(Timing)](bool bResult) mutable
  731. {
  732. if (UNLIKELY(!bResult))
  733. {
  734. UE_LOG(LogWwiseResourceLoader, Error, TEXT("LoadMediaAsync: Could not load Media %s (%" PRIu32 ")"),
  735. *LoadedMedia.MediaCookedData.DebugName.ToString(), LoadedMedia.MediaCookedData.MediaId);
  736. delete InMediaListNode;
  737. Timing.Stop();
  738. Promise.EmplaceValue(nullptr);
  739. return;
  740. }
  741. AttachMediaNode(InMediaListNode);
  742. Timing.Stop();
  743. Promise.EmplaceValue(InMediaListNode);
  744. });
  745. }
  746. void FWwiseResourceLoaderImpl::UnloadMediaAsync(FWwiseResourceUnloadPromise&& Promise, FWwiseLoadedMediaPtr&& InMediaListNode)
  747. {
  748. SCOPED_WWISERESOURCELOADER_EVENT_2(TEXT("FWwiseResourceLoaderImpl::UnloadMediaAsync"));
  749. FWwiseAsyncCycleCounter Timing(GET_STATID(STAT_WwiseResourceLoaderTiming));
  750. auto& LoadedMedia = InMediaListNode->GetValue();
  751. LogUnload(LoadedMedia);
  752. const FWwiseMediaCookedData* Media = &LoadedMedia.MediaCookedData;
  753. DetachMediaNode(InMediaListNode);
  754. FWwiseResourceUnloadPromise ResourceUnloadPromise;
  755. auto Future = ResourceUnloadPromise.GetFuture();
  756. UnloadMediaResources(MoveTemp(ResourceUnloadPromise), LoadedMedia.LoadedData, *Media);
  757. Future.Next([this, &LoadedMedia, Media, InMediaListNode = MoveTemp(InMediaListNode), Promise = MoveTemp(Promise), Timing = MoveTemp(Timing)](int) mutable
  758. {
  759. delete InMediaListNode;
  760. Timing.Stop();
  761. Promise.EmplaceValue();
  762. });
  763. }
  764. FWwiseLoadedShareSetPtr FWwiseResourceLoaderImpl::CreateShareSetNode(
  765. const FWwiseLocalizedShareSetCookedData& InShareSetCookedData, const FWwiseLanguageCookedData* InLanguageOverride)
  766. {
  767. const auto* LanguageKey = GetLanguageMapKey(InShareSetCookedData.ShareSetLanguageMap, InLanguageOverride, InShareSetCookedData.DebugName);
  768. if (UNLIKELY(!LanguageKey))
  769. {
  770. UE_LOG(LogWwiseResourceLoader, Error, TEXT("CreateShareSetNode: Could not find language for ShareSet %s"), *InShareSetCookedData.DebugName.ToString());
  771. return nullptr;
  772. }
  773. return new FWwiseLoadedShareSetListNode(FWwiseLoadedShareSetInfo(InShareSetCookedData, *LanguageKey));
  774. }
  775. void FWwiseResourceLoaderImpl::LoadShareSetAsync(FWwiseLoadedShareSetPromise&& Promise, FWwiseLoadedShareSetPtr&& InShareSetListNode)
  776. {
  777. SCOPED_WWISERESOURCELOADER_EVENT_2(TEXT("FWwiseResourceLoaderImpl::LoadShareSetAsync"));
  778. FWwiseAsyncCycleCounter Timing(GET_STATID(STAT_WwiseResourceLoaderTiming));
  779. auto& LoadedShareSet = InShareSetListNode->GetValue();
  780. LogLoad(LoadedShareSet);
  781. const FWwiseShareSetCookedData* ShareSet = LoadedShareSet.LocalizedShareSetCookedData.ShareSetLanguageMap.Find(LoadedShareSet.LanguageRef);
  782. if (UNLIKELY(!ShareSet))
  783. {
  784. UE_LOG(LogWwiseResourceLoader, Error, TEXT("LoadShareSetAsync: Could not find ShareSet %s (%" PRIu32 ") in language %s (%" PRIu32 ")"),
  785. *LoadedShareSet.LocalizedShareSetCookedData.DebugName.ToString(), LoadedShareSet.LocalizedShareSetCookedData.ShareSetId, *LoadedShareSet.LanguageRef.LanguageName.ToString(), LoadedShareSet.LanguageRef.LanguageId);
  786. delete InShareSetListNode;
  787. Timing.Stop();
  788. Promise.EmplaceValue(nullptr);
  789. return;
  790. }
  791. FWwiseResourceLoadPromise ResourceLoadPromise;
  792. auto Future = ResourceLoadPromise.GetFuture();
  793. LoadShareSetResources(MoveTemp(ResourceLoadPromise), LoadedShareSet.LoadedData, *ShareSet);
  794. Future.Next([this, &LoadedShareSet, ShareSet, InShareSetListNode = MoveTemp(InShareSetListNode), Promise = MoveTemp(Promise), Timing = MoveTemp(Timing)](bool bResult) mutable
  795. {
  796. if (UNLIKELY(!bResult))
  797. {
  798. UE_LOG(LogWwiseResourceLoader, Error, TEXT("LoadShareSetAsync: Could not load ShareSet %s (%" PRIu32 ") in language %s (%" PRIu32 ")"),
  799. *LoadedShareSet.LocalizedShareSetCookedData.DebugName.ToString(), LoadedShareSet.LocalizedShareSetCookedData.ShareSetId, *LoadedShareSet.LanguageRef.LanguageName.ToString(), LoadedShareSet.LanguageRef.LanguageId);
  800. delete InShareSetListNode;
  801. Timing.Stop();
  802. Promise.EmplaceValue(nullptr);
  803. return;
  804. }
  805. AttachShareSetNode(InShareSetListNode);
  806. Timing.Stop();
  807. Promise.EmplaceValue(InShareSetListNode);
  808. });
  809. }
  810. void FWwiseResourceLoaderImpl::UnloadShareSetAsync(FWwiseResourceUnloadPromise&& Promise, FWwiseLoadedShareSetPtr&& InShareSetListNode)
  811. {
  812. SCOPED_WWISERESOURCELOADER_EVENT_2(TEXT("FWwiseResourceLoaderImpl::UnloadShareSetAsync"));
  813. FWwiseAsyncCycleCounter Timing(GET_STATID(STAT_WwiseResourceLoaderTiming));
  814. auto& LoadedShareSet = InShareSetListNode->GetValue();
  815. LogUnload(LoadedShareSet);
  816. const FWwiseShareSetCookedData* ShareSet = LoadedShareSet.LocalizedShareSetCookedData.ShareSetLanguageMap.Find(LoadedShareSet.LanguageRef);
  817. if (UNLIKELY(!ShareSet))
  818. {
  819. UE_LOG(LogWwiseResourceLoader, Error, TEXT("UnloadShareSetAsync: Could not find ShareSet %s (%" PRIu32 ") in language %s (%" PRIu32 "). Leaking!"),
  820. *LoadedShareSet.LocalizedShareSetCookedData.DebugName.ToString(), LoadedShareSet.LocalizedShareSetCookedData.ShareSetId, *LoadedShareSet.LanguageRef.LanguageName.ToString(), LoadedShareSet.LanguageRef.LanguageId);
  821. Timing.Stop();
  822. Promise.EmplaceValue();
  823. return;
  824. }
  825. DetachShareSetNode(InShareSetListNode);
  826. FWwiseResourceUnloadPromise ResourceUnloadPromise;
  827. auto Future = ResourceUnloadPromise.GetFuture();
  828. UnloadShareSetResources(MoveTemp(ResourceUnloadPromise), LoadedShareSet.LoadedData, *ShareSet);
  829. Future.Next([this, &LoadedShareSet, ShareSet, InShareSetListNode = MoveTemp(InShareSetListNode), Promise = MoveTemp(Promise), Timing = MoveTemp(Timing)](int) mutable
  830. {
  831. delete InShareSetListNode;
  832. Timing.Stop();
  833. Promise.EmplaceValue();
  834. });
  835. }
  836. FWwiseLoadedSoundBankPtr FWwiseResourceLoaderImpl::CreateSoundBankNode(
  837. const FWwiseLocalizedSoundBankCookedData& InSoundBankCookedData, const FWwiseLanguageCookedData* InLanguageOverride)
  838. {
  839. const auto* LanguageKey = GetLanguageMapKey(InSoundBankCookedData.SoundBankLanguageMap, InLanguageOverride, InSoundBankCookedData.DebugName);
  840. if (UNLIKELY(!LanguageKey))
  841. {
  842. UE_LOG(LogWwiseResourceLoader, Error, TEXT("CreateSoundBankNode: Could not find language for SoundBank %s"), *InSoundBankCookedData.DebugName.ToString());
  843. return nullptr;
  844. }
  845. return new FWwiseLoadedSoundBankListNode(FWwiseLoadedSoundBankInfo(InSoundBankCookedData, *LanguageKey));
  846. }
  847. void FWwiseResourceLoaderImpl::LoadSoundBankAsync(FWwiseLoadedSoundBankPromise&& Promise, FWwiseLoadedSoundBankPtr&& InSoundBankListNode)
  848. {
  849. SCOPED_WWISERESOURCELOADER_EVENT_2(TEXT("FWwiseResourceLoaderImpl::LoadSoundBankAsync"));
  850. FWwiseAsyncCycleCounter Timing(GET_STATID(STAT_WwiseResourceLoaderTiming));
  851. auto& LoadedSoundBank = InSoundBankListNode->GetValue();
  852. LogLoad(LoadedSoundBank);
  853. const FWwiseSoundBankCookedData* SoundBank = LoadedSoundBank.LocalizedSoundBankCookedData.SoundBankLanguageMap.Find(LoadedSoundBank.LanguageRef);
  854. if (UNLIKELY(!SoundBank))
  855. {
  856. UE_LOG(LogWwiseResourceLoader, Error, TEXT("LoadSoundBankAsync: Could not find SoundBank %s (%" PRIu32 ") in language %s (%" PRIu32 ")"),
  857. *LoadedSoundBank.LocalizedSoundBankCookedData.DebugName.ToString(), LoadedSoundBank.LocalizedSoundBankCookedData.SoundBankId, *LoadedSoundBank.LanguageRef.LanguageName.ToString(), LoadedSoundBank.LanguageRef.LanguageId);
  858. delete InSoundBankListNode;
  859. Timing.Stop();
  860. Promise.EmplaceValue(nullptr);
  861. return;
  862. }
  863. FWwiseResourceLoadPromise ResourceLoadPromise;
  864. auto Future = ResourceLoadPromise.GetFuture();
  865. LoadSoundBankResources(MoveTemp(ResourceLoadPromise), LoadedSoundBank.LoadedData, *SoundBank);
  866. Future.Next([this, &LoadedSoundBank, SoundBank, InSoundBankListNode = MoveTemp(InSoundBankListNode), Promise = MoveTemp(Promise), Timing = MoveTemp(Timing)](bool bResult) mutable
  867. {
  868. if (UNLIKELY(!bResult))
  869. {
  870. UE_LOG(LogWwiseResourceLoader, Error, TEXT("LoadSoundBankAsync: Could not load SoundBank %s (%" PRIu32 ") in language %s (%" PRIu32 ")"),
  871. *LoadedSoundBank.LocalizedSoundBankCookedData.DebugName.ToString(), LoadedSoundBank.LocalizedSoundBankCookedData.SoundBankId, *LoadedSoundBank.LanguageRef.LanguageName.ToString(), LoadedSoundBank.LanguageRef.LanguageId);
  872. delete InSoundBankListNode;
  873. Timing.Stop();
  874. Promise.EmplaceValue(nullptr);
  875. return;
  876. }
  877. AttachSoundBankNode(InSoundBankListNode);
  878. Timing.Stop();
  879. Promise.EmplaceValue(InSoundBankListNode);
  880. });
  881. }
  882. void FWwiseResourceLoaderImpl::UnloadSoundBankAsync(FWwiseResourceUnloadPromise&& Promise, FWwiseLoadedSoundBankPtr&& InSoundBankListNode)
  883. {
  884. SCOPED_WWISERESOURCELOADER_EVENT_2(TEXT("FWwiseResourceLoaderImpl::UnloadSoundBankAsync"));
  885. FWwiseAsyncCycleCounter Timing(GET_STATID(STAT_WwiseResourceLoaderTiming));
  886. auto& LoadedSoundBank = InSoundBankListNode->GetValue();
  887. LogUnload(LoadedSoundBank);
  888. const FWwiseSoundBankCookedData* SoundBank = LoadedSoundBank.LocalizedSoundBankCookedData.SoundBankLanguageMap.Find(LoadedSoundBank.LanguageRef);
  889. if (UNLIKELY(!SoundBank))
  890. {
  891. UE_LOG(LogWwiseResourceLoader, Error, TEXT("UnloadSoundBankAsync: Could not find SoundBank %s (%" PRIu32 ") in language %s (%" PRIu32 "). Leaking!"),
  892. *LoadedSoundBank.LocalizedSoundBankCookedData.DebugName.ToString(), LoadedSoundBank.LocalizedSoundBankCookedData.SoundBankId, *LoadedSoundBank.LanguageRef.LanguageName.ToString(), LoadedSoundBank.LanguageRef.LanguageId);
  893. Timing.Stop();
  894. Promise.EmplaceValue();
  895. return;
  896. }
  897. DetachSoundBankNode(InSoundBankListNode);
  898. FWwiseResourceUnloadPromise ResourceUnloadPromise;
  899. auto Future = ResourceUnloadPromise.GetFuture();
  900. UnloadSoundBankResources(MoveTemp(ResourceUnloadPromise), LoadedSoundBank.LoadedData, *SoundBank);
  901. Future.Next([this, &LoadedSoundBank, SoundBank, InSoundBankListNode = MoveTemp(InSoundBankListNode), Promise = MoveTemp(Promise), Timing = MoveTemp(Timing)](int) mutable
  902. {
  903. delete InSoundBankListNode;
  904. Timing.Stop();
  905. Promise.EmplaceValue();
  906. });
  907. }
  908. bool FWwiseResourceLoaderImpl::TrimGroupValueInfo()
  909. {
  910. TSet<FWwiseSwitchContainerLoadedGroupValueInfo> Result;
  911. for (auto Info : LoadedGroupValueInfo)
  912. {
  913. if (Info.LoadCount >= 0 || Info.ShouldBeLoaded())
  914. {
  915. Result.Add(Info);
  916. }
  917. }
  918. LoadedGroupValueInfo = MoveTemp(Result);
  919. return Result.Num() == 0;
  920. }
  921. void FWwiseResourceLoaderImpl::LoadAuxBusResources(FWwiseResourceLoadPromise&& Promise, FWwiseLoadedAuxBusInfo::FLoadedData& LoadedData, const FWwiseAuxBusCookedData& InCookedData)
  922. {
  923. SCOPED_WWISERESOURCELOADER_EVENT_2(TEXT("FWwiseResourceLoaderImpl::LoadAuxBusResources"));
  924. if (LoadedData.IsProcessing)
  925. {
  926. ExecutionQueue.Async(WWISERESOURCELOADER_ASYNC_NAME("FWwiseResourceLoaderImpl::LoadAuxBusResources IsProcessing"), [this, Promise = MoveTemp(Promise), &LoadedData, &InCookedData]() mutable
  927. {
  928. LoadAuxBusResources(MoveTemp(Promise), LoadedData, InCookedData);
  929. });
  930. return;
  931. }
  932. LogLoadResources(InCookedData);
  933. auto& LoadedSoundBanks = LoadedData.LoadedSoundBanks;
  934. auto& LoadedMedia = LoadedData.LoadedMedia;
  935. if (UNLIKELY(LoadedData.IsLoaded()))
  936. {
  937. UE_LOG(LogWwiseResourceLoader, Error, TEXT("LoadAuxBusResources: AuxBus %s (%" PRIu32 ") is already loaded."),
  938. *InCookedData.DebugName.ToString(), (uint32)InCookedData.AuxBusId);
  939. return Promise.EmplaceValue(false);
  940. }
  941. ++LoadedData.IsProcessing;
  942. FCompletionFutureArray FutureArray;
  943. AddLoadMediaFutures(FutureArray, LoadedMedia, InCookedData.Media, TEXT("AuxBus"), InCookedData.DebugName.ToString(), InCookedData.AuxBusId);
  944. AddLoadSoundBankFutures(FutureArray, LoadedSoundBanks, InCookedData.SoundBanks, TEXT("AuxBus"), InCookedData.DebugName.ToString(), InCookedData.AuxBusId);
  945. WaitForFutures(MoveTemp(FutureArray), [this, Promise = MoveTemp(Promise), &LoadedData, &LoadedSoundBanks, &InCookedData]() mutable
  946. {
  947. --LoadedData.IsProcessing;
  948. if (UNLIKELY(LoadedSoundBanks.Num() != InCookedData.SoundBanks.Num()))
  949. {
  950. UE_LOG(LogWwiseResourceLoader, Error, TEXT("FWwiseResourceLoaderImpl::LoadAuxBusResources: Could not load %d prerequisites for AuxBus %s (%" PRIu32 "). Unloading and failing."),
  951. InCookedData.SoundBanks.Num() - LoadedSoundBanks.Num(), *InCookedData.DebugName.ToString(), (uint32)InCookedData.AuxBusId);
  952. FWwiseResourceUnloadPromise UnloadPromise;
  953. auto UnloadFuture = UnloadPromise.GetFuture();
  954. ExecutionQueue.Async(WWISERESOURCELOADER_ASYNC_NAME("FWwiseResourceLoaderImpl::LoadAuxBusResources Error"), [this, UnloadPromise = MoveTemp(UnloadPromise), &LoadedData, &InCookedData]() mutable
  955. {
  956. UnloadAuxBusResources(MoveTemp(UnloadPromise), LoadedData, InCookedData);
  957. });
  958. UnloadFuture.Next([Promise = MoveTemp(Promise)](int) mutable
  959. {
  960. SCOPED_WWISERESOURCELOADER_EVENT_3(TEXT("FWwiseResourceLoaderImpl::LoadAuxBusResources UnloadFuture.Done"));
  961. return Promise.EmplaceValue(false);
  962. });
  963. }
  964. else
  965. {
  966. return Promise.EmplaceValue(true);
  967. }
  968. });
  969. }
  970. void FWwiseResourceLoaderImpl::LoadEventResources(FWwiseResourceLoadPromise&& Promise, FWwiseLoadedEventInfo::FLoadedData& LoadedData, const FWwiseEventCookedData& InCookedData)
  971. {
  972. SCOPED_WWISERESOURCELOADER_EVENT_2(TEXT("FWwiseResourceLoaderImpl::LoadEventResources"));
  973. if (LoadedData.IsProcessing)
  974. {
  975. ExecutionQueue.Async(WWISERESOURCELOADER_ASYNC_NAME("FWwiseResourceLoaderImpl::LoadEventResources IsProcessing"), [this, Promise = MoveTemp(Promise), &LoadedData, &InCookedData]() mutable
  976. {
  977. LoadEventResources(MoveTemp(Promise), LoadedData, InCookedData);
  978. });
  979. return;
  980. }
  981. LogLoadResources(InCookedData);
  982. auto& LoadedSoundBanks = LoadedData.LoadedSoundBanks;
  983. auto& LoadedExternalSources = LoadedData.LoadedExternalSources;
  984. auto& LoadedMedia = LoadedData.LoadedMedia;
  985. if (UNLIKELY(LoadedData.IsLoaded()))
  986. {
  987. UE_LOG(LogWwiseResourceLoader, Error, TEXT("LoadEventResources: Event %s (%" PRIu32 ") is already loaded."),
  988. *InCookedData.DebugName.ToString(), (uint32)InCookedData.EventId);
  989. return Promise.EmplaceValue(false);
  990. }
  991. ++LoadedData.IsProcessing;
  992. FCompletionFutureArray FutureArray;
  993. if (InCookedData.RequiredGroupValueSet.Num() > 0 || InCookedData.SwitchContainerLeaves.Num() > 0)
  994. {
  995. FCompletionPromise CompletionPromise;
  996. FutureArray.Add(CompletionPromise.GetFuture());
  997. FWwiseResourceLoadPromise SwitchContainerPromise;
  998. auto SwitchContainerFuture = SwitchContainerPromise.GetFuture();
  999. LoadEventSwitchContainerResources(MoveTemp(SwitchContainerPromise), LoadedData, InCookedData);
  1000. SwitchContainerFuture.Next([CompletionPromise = MoveTemp(CompletionPromise)](bool bResult) mutable
  1001. {
  1002. CompletionPromise.EmplaceValue();
  1003. });
  1004. }
  1005. AddLoadExternalSourceFutures(FutureArray, LoadedExternalSources, InCookedData.ExternalSources, TEXT("Event"), InCookedData.DebugName.ToString(), InCookedData.EventId);
  1006. AddLoadMediaFutures(FutureArray, LoadedMedia, InCookedData.Media, TEXT("Event"), InCookedData.DebugName.ToString(), InCookedData.EventId);
  1007. AddLoadSoundBankFutures(FutureArray, LoadedSoundBanks, InCookedData.SoundBanks, TEXT("Event"), InCookedData.DebugName.ToString(), InCookedData.EventId);
  1008. WaitForFutures(MoveTemp(FutureArray), [this, Promise = MoveTemp(Promise), &LoadedData, &LoadedSoundBanks, &InCookedData]() mutable
  1009. {
  1010. SCOPED_WWISERESOURCELOADER_EVENT_3(TEXT("FWwiseResourceLoaderImpl::LoadEventResources WaitForFutures"));
  1011. --LoadedData.IsProcessing;
  1012. if (UNLIKELY(LoadedSoundBanks.Num() != InCookedData.SoundBanks.Num()))
  1013. {
  1014. UE_LOG(LogWwiseResourceLoader, Error, TEXT("LoadEventResources: Could not load %d prerequisites for Event %s (%" PRIu32 "). Unloading and failing."),
  1015. InCookedData.SoundBanks.Num() - LoadedSoundBanks.Num(), *InCookedData.DebugName.ToString(), (uint32)InCookedData.EventId);
  1016. FWwiseResourceUnloadPromise UnloadPromise;
  1017. auto UnloadFuture = UnloadPromise.GetFuture();
  1018. ExecutionQueue.Async(WWISERESOURCELOADER_ASYNC_NAME("FWwiseResourceLoaderImpl::LoadEventResources Error UnloadEventResource"), [this, UnloadPromise = MoveTemp(UnloadPromise), &LoadedData, &InCookedData]() mutable
  1019. {
  1020. UnloadEventResources(MoveTemp(UnloadPromise), LoadedData, InCookedData);
  1021. });
  1022. UnloadFuture.Next([Promise = MoveTemp(Promise)](int) mutable
  1023. {
  1024. SCOPED_WWISERESOURCELOADER_EVENT_3(TEXT("FWwiseResourceLoaderImpl::LoadEventResources UnloadFuture.Done"));
  1025. return Promise.EmplaceValue(false);
  1026. });
  1027. }
  1028. else
  1029. {
  1030. SCOPED_WWISERESOURCELOADER_EVENT_3(TEXT("FWwiseResourceLoaderImpl::LoadEventResources Done"));
  1031. return Promise.EmplaceValue(true);
  1032. }
  1033. });
  1034. }
  1035. void FWwiseResourceLoaderImpl::LoadEventSwitchContainerResources(FWwiseResourceLoadPromise&& Promise, FWwiseLoadedEventInfo::FLoadedData& LoadedData, const FWwiseEventCookedData& InCookedData)
  1036. {
  1037. SCOPED_WWISERESOURCELOADER_EVENT_2(TEXT("FWwiseResourceLoaderImpl::LoadEventSwitchContainerResources"));
  1038. // Load required GroupValues
  1039. UE_LOG(LogWwiseResourceLoader, VeryVerbose, TEXT("Loading %d GroupValues for Event %s (%" PRIu32 ")"),
  1040. (int)InCookedData.RequiredGroupValueSet.Num(), *InCookedData.DebugName.ToString(), (uint32)InCookedData.EventId);
  1041. FWwiseLoadedGroupValueList& LoadedRequiredGroupValues = LoadedData.LoadedRequiredGroupValues;
  1042. bool& bLoadedSwitchContainerLeaves = LoadedData.bLoadedSwitchContainerLeaves;
  1043. FCompletionFutureArray FutureArray;
  1044. for (const auto& GroupValue : InCookedData.RequiredGroupValueSet)
  1045. {
  1046. FCompletionPromise GroupValuePromise;
  1047. FutureArray.Add(GroupValuePromise.GetFuture());
  1048. ExecutionQueue.Async(WWISERESOURCELOADER_ASYNC_NAME("FWwiseResourceLoaderImpl::LoadEventSwitchContainerResources GroupValue"), [this, &LoadedRequiredGroupValues, &InCookedData, &GroupValue, GroupValuePromise = MoveTemp(GroupValuePromise)]() mutable
  1049. {
  1050. UE_LOG(LogWwiseResourceLoader, VeryVerbose, TEXT("Loading GroupValue %s for Event %s (%" PRIu32 ")"),
  1051. *GroupValue.GetDebugString(), *InCookedData.DebugName.ToString(), (uint32)InCookedData.EventId);
  1052. auto* LoadedNode = new FWwiseLoadedGroupValueListNode(FWwiseLoadedGroupValueInfo(GroupValue));
  1053. auto& GroupValueLoadedData = LoadedNode->GetValue().LoadedData;
  1054. FWwiseResourceLoadPromise GroupValueResourcePromise;
  1055. auto GroupValueResourceFuture = GroupValueResourcePromise.GetFuture();
  1056. LoadGroupValueResources(MoveTemp(GroupValueResourcePromise), GroupValueLoadedData, GroupValue);
  1057. GroupValueResourceFuture.Next([this, &LoadedRequiredGroupValues, &InCookedData, &GroupValue, GroupValuePromise = MoveTemp(GroupValuePromise), LoadedNode](bool bResult) mutable
  1058. {
  1059. SCOPED_WWISERESOURCELOADER_EVENT_3(TEXT("FWwiseResourceLoaderImpl::LoadEventSwitchContainerResources GroupValue.SwitchContainer ResourceFuture.Next"));
  1060. const auto& GroupValueLoadedData = LoadedNode->GetValue().LoadedData;
  1061. if (UNLIKELY(!bResult || !GroupValueLoadedData.IsLoaded()))
  1062. {
  1063. UE_LOG(LogWwiseResourceLoader, Error, TEXT("Could not load required GroupValue %s for Event %s (%" PRIu32 ")"),
  1064. *GroupValue.DebugName.ToString(), *InCookedData.DebugName.ToString(), (uint32)InCookedData.EventId);
  1065. delete LoadedNode;
  1066. GroupValuePromise.EmplaceValue();
  1067. }
  1068. else
  1069. {
  1070. ExecutionQueue.Async(WWISERESOURCELOADER_ASYNC_NAME("FWwiseResourceLoaderImpl::LoadEventSwitchContainerResources GroupValue Emplace"), [this, &LoadedRequiredGroupValues, LoadedNode, GroupValuePromise = MoveTemp(GroupValuePromise)]() mutable
  1071. {
  1072. LoadedRequiredGroupValues.AddTail(LoadedNode);
  1073. GroupValuePromise.EmplaceValue();
  1074. });
  1075. }
  1076. });
  1077. });
  1078. }
  1079. // Load Switch Container Leaves
  1080. UE_LOG(LogWwiseResourceLoader, VeryVerbose, TEXT("Loading %d Leaves for Event %s (%" PRIu32 ")"),
  1081. (int)InCookedData.SwitchContainerLeaves.Num(), *InCookedData.DebugName.ToString(), (uint32)InCookedData.EventId);
  1082. for (const auto& SwitchContainerLeaf : InCookedData.SwitchContainerLeaves)
  1083. {
  1084. check(SwitchContainerLeaf.GroupValueSet.Num() > 0);
  1085. auto UsageCount = MakeShared<FWwiseSwitchContainerLeafGroupValueUsageCount, ESPMode::ThreadSafe>(SwitchContainerLeaf);
  1086. UE_LOG(LogWwiseResourceLoader, VeryVerbose, TEXT("FWwiseResourceLoaderImpl::LoadEventSwitchContainerResources UsageCount[%p]: Created %s for Event %s (%" PRIu32 ")"),
  1087. &UsageCount.Get(), *UsageCount->Key.GetDebugString(),
  1088. *InCookedData.DebugName.ToString(), (uint32)InCookedData.EventId);
  1089. for (const auto& GroupValue : SwitchContainerLeaf.GroupValueSet)
  1090. {
  1091. FCompletionPromise SwitchContainerLeafPromise;
  1092. FutureArray.Add(SwitchContainerLeafPromise.GetFuture());
  1093. ExecutionQueue.Async(WWISERESOURCELOADER_ASYNC_NAME("FWwiseResourceLoaderImpl::LoadEventSwitchContainerResources SwitchContainerLeaf"), [this, &bLoadedSwitchContainerLeaves, &InCookedData, &GroupValue, UsageCount, SwitchContainerLeafPromise = MoveTemp(SwitchContainerLeafPromise)]() mutable
  1094. {
  1095. UE_LOG(LogWwiseResourceLoader, VeryVerbose, TEXT("Adding optional %s for %s in Event %s (%" PRIu32 ")"),
  1096. *GroupValue.GetDebugString(), *UsageCount->Key.GetDebugString(), *InCookedData.DebugName.ToString(), (uint32)InCookedData.EventId);
  1097. auto FoundInfoId = LoadedGroupValueInfo.FindId(FWwiseSwitchContainerLoadedGroupValueInfo(GroupValue));
  1098. auto InfoId = FoundInfoId.IsValidId() ? FoundInfoId : LoadedGroupValueInfo.Add(FWwiseSwitchContainerLoadedGroupValueInfo(GroupValue), nullptr);
  1099. FWwiseSwitchContainerLoadedGroupValueInfo& Info = LoadedGroupValueInfo[InfoId];
  1100. bool bIsAlreadyCreated = false;
  1101. auto UsageCountId = Info.Leaves.Add(UsageCount, &bIsAlreadyCreated);
  1102. if (UNLIKELY(bIsAlreadyCreated))
  1103. {
  1104. UE_LOG(LogWwiseResourceLoader, Error, TEXT("Creating already created Switch Container Leaf Usage Count @ %p for %s"),
  1105. &UsageCount->LoadedData, *UsageCount->Key.GetDebugString());
  1106. return SwitchContainerLeafPromise.EmplaceValue();
  1107. }
  1108. bLoadedSwitchContainerLeaves = true;
  1109. UE_CLOG(!Info.ShouldBeLoaded(), LogWwiseResourceLoader, VeryVerbose, TEXT("Don't have referencing GroupValues yet: %d for key %s"), Info.LoadCount, *UsageCount->Key.GetDebugString());
  1110. UE_CLOG(Info.ShouldBeLoaded(), LogWwiseResourceLoader, VeryVerbose, TEXT("Have referencing GroupValues: %d for key %s"), Info.LoadCount, *UsageCount->Key.GetDebugString());
  1111. if (Info.ShouldBeLoaded())
  1112. {
  1113. UE_LOG(LogWwiseResourceLoader, VeryVerbose, TEXT("Number of GroupValues required for this leaf: %d/%d @ %p for key %s (+1 in Event)"),
  1114. (int)UsageCount->LoadedGroupValues.Num() + 1, UsageCount->Key.GroupValueSet.Num(), &UsageCount->LoadedData, *UsageCount->Key.GetDebugString());
  1115. bIsAlreadyCreated = false;
  1116. UsageCount->LoadedGroupValues.Add(GroupValue, &bIsAlreadyCreated);
  1117. if (UNLIKELY(bIsAlreadyCreated))
  1118. {
  1119. UE_LOG(LogWwiseResourceLoader, Error, TEXT("Loading already created Switch Container Leaf LoadedGoupValueCount %d @ %p for %s"),
  1120. (int)UsageCount->LoadedGroupValues.Num(), &UsageCount->LoadedData, *UsageCount->Key.GetDebugString());
  1121. SCOPED_WWISERESOURCELOADER_EVENT_3(TEXT("FWwiseResourceLoaderImpl::LoadEventSwitchContainerResources Leaf.SwitchContainer AlreadyLoaded Done"));
  1122. return SwitchContainerLeafPromise.EmplaceValue();
  1123. }
  1124. LoadSwitchContainerLeafResources(MoveTemp(SwitchContainerLeafPromise), UsageCount);
  1125. }
  1126. else
  1127. {
  1128. SCOPED_WWISERESOURCELOADER_EVENT_3(TEXT("FWwiseResourceLoaderImpl::LoadEventSwitchContainerResources Leaf.SwitchContainer !ShouldBeLoaded.Done"));
  1129. SwitchContainerLeafPromise.EmplaceValue();
  1130. }
  1131. });
  1132. }
  1133. }
  1134. WaitForFutures(MoveTemp(FutureArray), [Promise = MoveTemp(Promise)]() mutable
  1135. {
  1136. SCOPED_WWISERESOURCELOADER_EVENT_3(TEXT("FWwiseResourceLoaderImpl::LoadEventSwitchContainerResources Wait.Done"));
  1137. Promise.EmplaceValue(true);
  1138. });
  1139. }
  1140. void FWwiseResourceLoaderImpl::LoadExternalSourceResources(FWwiseResourceLoadPromise&& Promise, FWwiseLoadedExternalSourceInfo::FLoadedData& LoadedData, const FWwiseExternalSourceCookedData& InCookedData)
  1141. {
  1142. SCOPED_WWISERESOURCELOADER_EVENT_2(TEXT("FWwiseResourceLoaderImpl::LoadExternalSourceResources"));
  1143. if (LoadedData.IsProcessing)
  1144. {
  1145. ExecutionQueue.Async(WWISERESOURCELOADER_ASYNC_NAME("FWwiseResourceLoaderImpl::LoadExternalSourceResources IsProcessing"), [this, Promise = MoveTemp(Promise), &LoadedData, &InCookedData]() mutable
  1146. {
  1147. LoadExternalSourceResources(MoveTemp(Promise), LoadedData, InCookedData);
  1148. });
  1149. return;
  1150. }
  1151. LogLoadResources(InCookedData);
  1152. if (UNLIKELY(LoadedData.IsLoaded()))
  1153. {
  1154. UE_LOG(LogWwiseResourceLoader, Error, TEXT("LoadExternalSourceResources: ExternalSource %s (%" PRIu32 ") is already loaded."),
  1155. *InCookedData.DebugName.ToString(), (uint32)InCookedData.Cookie);
  1156. return Promise.EmplaceValue(false);
  1157. }
  1158. ++LoadedData.IsProcessing;
  1159. LoadExternalSourceFile(InCookedData, [Promise = MoveTemp(Promise), &LoadedData, &InCookedData](bool bResult) mutable
  1160. {
  1161. LoadedData.bLoaded = bResult;
  1162. --LoadedData.IsProcessing;
  1163. if (UNLIKELY(!bResult))
  1164. {
  1165. UE_LOG(LogWwiseResourceLoader, Error, TEXT("LoadExternalSourceResources: Could not load ExternalSource %s (%" PRIu32 ")"),
  1166. *InCookedData.DebugName.ToString(), (uint32)InCookedData.Cookie);
  1167. }
  1168. Promise.EmplaceValue(bResult);
  1169. });
  1170. }
  1171. void FWwiseResourceLoaderImpl::LoadGroupValueResources(FWwiseResourceLoadPromise&& Promise, FWwiseLoadedGroupValueInfo::FLoadedData& LoadedData, const FWwiseGroupValueCookedData& InCookedData)
  1172. {
  1173. SCOPED_WWISERESOURCELOADER_EVENT_2(TEXT("FWwiseResourceLoaderImpl::LoadGroupValueResources"));
  1174. if (LoadedData.IsProcessing)
  1175. {
  1176. ExecutionQueue.Async(WWISERESOURCELOADER_ASYNC_NAME("FWwiseResourceLoaderImpl::LoadGroupValueResources IsProcessing"), [this, Promise = MoveTemp(Promise), &LoadedData, &InCookedData]() mutable
  1177. {
  1178. LoadGroupValueResources(MoveTemp(Promise), LoadedData, InCookedData);
  1179. });
  1180. return;
  1181. }
  1182. LogLoadResources(InCookedData);
  1183. ++LoadedData.IsProcessing;
  1184. ExecutionQueue.Async(WWISERESOURCELOADER_ASYNC_NAME("WwiseResourceLoaderImpl::LoadGroupValueResources GroupValue.SwitchContainer"), [this, &LoadedData, &InCookedData, Promise = MoveTemp(Promise)]() mutable
  1185. {
  1186. auto FoundInfoId = LoadedGroupValueInfo.FindId(FWwiseSwitchContainerLoadedGroupValueInfo(InCookedData));
  1187. auto InfoId = FoundInfoId.IsValidId() ? FoundInfoId : LoadedGroupValueInfo.Add(FWwiseSwitchContainerLoadedGroupValueInfo(InCookedData), nullptr);
  1188. FWwiseSwitchContainerLoadedGroupValueInfo& Info = LoadedGroupValueInfo[InfoId];
  1189. const bool bWasLoaded = Info.ShouldBeLoaded();
  1190. ++Info.LoadCount;
  1191. FCompletionFutureArray FutureArray;
  1192. if (!bWasLoaded && Info.ShouldBeLoaded())
  1193. {
  1194. UE_LOG(LogWwiseResourceLoader, VeryVerbose, TEXT("First GroupValue %s (%s %" PRIu32 ":%" PRIu32 ") load. Loading %d leaves."),
  1195. *InCookedData.DebugName.ToString(), *InCookedData.GetTypeName(), (uint32)InCookedData.GroupId, (uint32)InCookedData.Id, (int)Info.Leaves.Num());
  1196. for (const auto& UsageCount : Info.Leaves)
  1197. {
  1198. UE_LOG(LogWwiseResourceLoader, VeryVerbose, TEXT("Number of GroupValues required for a leaf: %d/%d @ %p for key %s (+1 in GroupValue)"),
  1199. (int)UsageCount->LoadedGroupValues.Num() + 1, UsageCount->Key.GroupValueSet.Num(), &UsageCount->LoadedData, *UsageCount->Key.GetDebugString());
  1200. bool bIsAlreadyCreated = false;
  1201. UsageCount->LoadedGroupValues.Add(InCookedData, &bIsAlreadyCreated);
  1202. if (UNLIKELY(bIsAlreadyCreated))
  1203. {
  1204. UE_LOG(LogWwiseResourceLoader, Error, TEXT("Loading already created LoadedGroupValue @ %p for key %s"),
  1205. &UsageCount->LoadedData, *UsageCount->Key.GetDebugString());
  1206. continue;
  1207. }
  1208. FCompletionPromise CompletionPromise;
  1209. FutureArray.Add(CompletionPromise.GetFuture());
  1210. LoadSwitchContainerLeafResources(MoveTemp(CompletionPromise), UsageCount);
  1211. }
  1212. }
  1213. else
  1214. {
  1215. UE_LOG(LogWwiseResourceLoader, VeryVerbose, TEXT("GroupValue %s (%s %" PRIu32 ":%" PRIu32 ") already loaded (Count: %d times)."),
  1216. *InCookedData.DebugName.ToString(), *InCookedData.GetTypeName(), (uint32)InCookedData.GroupId, (uint32)InCookedData.Id, (int)Info.LoadCount);
  1217. }
  1218. WaitForFutures(MoveTemp(FutureArray), [&LoadedData, Promise = MoveTemp(Promise)]() mutable
  1219. {
  1220. SCOPED_WWISERESOURCELOADER_EVENT_3(TEXT("FWwiseResourceLoaderImpl::LoadGroupValueResources GroupValue.SwitchContainer WaitForFutures.Done"));
  1221. LoadedData.bLoaded = true;
  1222. --LoadedData.IsProcessing;
  1223. // We always return success, as GroupValues are not complete deal-breaks and we cannot do anything if they fail.
  1224. return Promise.EmplaceValue(true);
  1225. });
  1226. });
  1227. }
  1228. void FWwiseResourceLoaderImpl::LoadInitBankResources(FWwiseResourceLoadPromise&& Promise, FWwiseLoadedInitBankInfo::FLoadedData& LoadedData, const FWwiseInitBankCookedData& InCookedData)
  1229. {
  1230. SCOPED_WWISERESOURCELOADER_EVENT_2(TEXT("FWwiseResourceLoaderImpl::LoadInitBankResources"));
  1231. if (LoadedData.IsProcessing)
  1232. {
  1233. ExecutionQueue.Async(WWISERESOURCELOADER_ASYNC_NAME("FWwiseResourceLoaderImpl::LoadInitBankResources IsProcessing"), [this, Promise = MoveTemp(Promise), &LoadedData, &InCookedData]() mutable
  1234. {
  1235. LoadInitBankResources(MoveTemp(Promise), LoadedData, InCookedData);
  1236. });
  1237. return;
  1238. }
  1239. LogLoadResources(InCookedData);
  1240. auto& LoadedMedia = LoadedData.LoadedMedia;
  1241. if (UNLIKELY(LoadedData.IsLoaded()))
  1242. {
  1243. UE_LOG(LogWwiseResourceLoader, Error, TEXT("LoadInitBankResources: InitBank %s (%" PRIu32 ") is already loaded."),
  1244. *InCookedData.DebugName.ToString(), (uint32)InCookedData.SoundBankId);
  1245. return Promise.EmplaceValue(false);
  1246. }
  1247. ++LoadedData.IsProcessing;
  1248. FCompletionFutureArray FutureArray;
  1249. AddLoadMediaFutures(FutureArray, LoadedMedia, InCookedData.Media, TEXT("InitBank"), InCookedData.DebugName.ToString(), InCookedData.SoundBankId);
  1250. WaitForFutures(MoveTemp(FutureArray), [this, Promise = MoveTemp(Promise), &LoadedData, &InCookedData]() mutable
  1251. {
  1252. TPromise<bool> SoundBankPromise;
  1253. auto Future = SoundBankPromise.GetFuture();
  1254. LoadSoundBankFile(InCookedData, [SoundBankPromise = MoveTemp(SoundBankPromise)](bool bInResult) mutable
  1255. {
  1256. SoundBankPromise.EmplaceValue(bInResult);
  1257. });
  1258. Future.Next([this, Promise = MoveTemp(Promise), &LoadedData, &InCookedData](bool bLoaded) mutable
  1259. {
  1260. LoadedData.bLoaded = bLoaded;
  1261. --LoadedData.IsProcessing;
  1262. if (UNLIKELY(!bLoaded))
  1263. {
  1264. UE_LOG(LogWwiseResourceLoader, Error, TEXT("LoadInitBankResources: Could not load InitBank %s (%" PRIu32 ")"),
  1265. *InCookedData.DebugName.ToString(), (uint32)InCookedData.SoundBankId);
  1266. }
  1267. return Promise.EmplaceValue(bLoaded);
  1268. });
  1269. });
  1270. }
  1271. void FWwiseResourceLoaderImpl::LoadMediaResources(FWwiseResourceLoadPromise&& Promise, FWwiseLoadedMediaInfo::FLoadedData& LoadedData, const FWwiseMediaCookedData& InCookedData)
  1272. {
  1273. SCOPED_WWISERESOURCELOADER_EVENT_2(TEXT("FWwiseResourceLoaderImpl::LoadMediaResources"));
  1274. if (LoadedData.IsProcessing)
  1275. {
  1276. ExecutionQueue.Async(WWISERESOURCELOADER_ASYNC_NAME("FWwiseResourceLoaderImpl::LoadMediaResources IsProcessing"), [this, Promise = MoveTemp(Promise), &LoadedData, &InCookedData]() mutable
  1277. {
  1278. LoadMediaResources(MoveTemp(Promise), LoadedData, InCookedData);
  1279. });
  1280. return;
  1281. }
  1282. LogLoadResources(InCookedData);
  1283. if (UNLIKELY(LoadedData.IsLoaded()))
  1284. {
  1285. UE_LOG(LogWwiseResourceLoader, Error, TEXT("LoadMediaResources: Media %s (%" PRIu32 ") is already loaded."),
  1286. *InCookedData.DebugName.ToString(), (uint32)InCookedData.MediaId);
  1287. return Promise.EmplaceValue(false);
  1288. }
  1289. ++LoadedData.IsProcessing;
  1290. LoadMediaFile(InCookedData, [Promise = MoveTemp(Promise), &LoadedData, &InCookedData](bool bResult) mutable
  1291. {
  1292. LoadedData.bLoaded = bResult;
  1293. --LoadedData.IsProcessing;
  1294. if (UNLIKELY(!bResult))
  1295. {
  1296. UE_LOG(LogWwiseResourceLoader, Error, TEXT("LoadMediaResources: Could not load Media %s (%" PRIu32 ")"),
  1297. *InCookedData.DebugName.ToString(), (uint32)InCookedData.MediaId);
  1298. }
  1299. Promise.EmplaceValue(bResult);
  1300. });
  1301. }
  1302. void FWwiseResourceLoaderImpl::LoadShareSetResources(FWwiseResourceLoadPromise&& Promise, FWwiseLoadedShareSetInfo::FLoadedData& LoadedData, const FWwiseShareSetCookedData& InCookedData)
  1303. {
  1304. SCOPED_WWISERESOURCELOADER_EVENT_2(TEXT("FWwiseResourceLoaderImpl::LoadShareSetResources"));
  1305. if (LoadedData.IsProcessing)
  1306. {
  1307. ExecutionQueue.Async(WWISERESOURCELOADER_ASYNC_NAME("FWwiseResourceLoaderImpl::LoadShareSetResources IsProcessing"), [this, Promise = MoveTemp(Promise), &LoadedData, &InCookedData]() mutable
  1308. {
  1309. LoadShareSetResources(MoveTemp(Promise), LoadedData, InCookedData);
  1310. });
  1311. return;
  1312. }
  1313. LogLoadResources(InCookedData);
  1314. auto& LoadedSoundBanks = LoadedData.LoadedSoundBanks;
  1315. auto& LoadedMedia = LoadedData.LoadedMedia;
  1316. if (UNLIKELY(LoadedData.IsLoaded()))
  1317. {
  1318. UE_LOG(LogWwiseResourceLoader, Error, TEXT("LoadShareSetResources: ShareSet %s (%" PRIu32 ") is already loaded."),
  1319. *InCookedData.DebugName.ToString(), (uint32)InCookedData.ShareSetId);
  1320. return Promise.EmplaceValue(false);
  1321. }
  1322. ++LoadedData.IsProcessing;
  1323. FCompletionFutureArray FutureArray;
  1324. AddLoadMediaFutures(FutureArray, LoadedMedia, InCookedData.Media, TEXT("ShareSet"), InCookedData.DebugName.ToString(), InCookedData.ShareSetId);
  1325. AddLoadSoundBankFutures(FutureArray, LoadedSoundBanks, InCookedData.SoundBanks, TEXT("ShareSet"), InCookedData.DebugName.ToString(), InCookedData.ShareSetId);
  1326. WaitForFutures(MoveTemp(FutureArray), [this, Promise = MoveTemp(Promise), &LoadedData, &LoadedSoundBanks, &InCookedData]() mutable
  1327. {
  1328. --LoadedData.IsProcessing;
  1329. if (UNLIKELY(LoadedSoundBanks.Num() != InCookedData.SoundBanks.Num()))
  1330. {
  1331. UE_LOG(LogWwiseResourceLoader, Error, TEXT("FWwiseResourceLoaderImpl::LoadShareSetResources: Could not load %d prerequisites for ShareSet %s (%" PRIu32 "). Unloading and failing."),
  1332. InCookedData.SoundBanks.Num() - LoadedSoundBanks.Num(), *InCookedData.DebugName.ToString(), (uint32)InCookedData.ShareSetId);
  1333. FWwiseResourceUnloadPromise UnloadPromise;
  1334. auto UnloadFuture = UnloadPromise.GetFuture();
  1335. ExecutionQueue.Async(WWISERESOURCELOADER_ASYNC_NAME("FWwiseResourceLoaderImpl::LoadShareSetResources Error"), [this, UnloadPromise = MoveTemp(UnloadPromise), &LoadedData, &InCookedData]() mutable
  1336. {
  1337. UnloadShareSetResources(MoveTemp(UnloadPromise), LoadedData, InCookedData);
  1338. });
  1339. UnloadFuture.Next([Promise = MoveTemp(Promise)](int) mutable
  1340. {
  1341. SCOPED_WWISERESOURCELOADER_EVENT_3(TEXT("FWwiseResourceLoaderImpl::LoadShareSetResources UnloadFuture.Done"));
  1342. return Promise.EmplaceValue(false);
  1343. });
  1344. }
  1345. else
  1346. {
  1347. return Promise.EmplaceValue(true);
  1348. }
  1349. });
  1350. }
  1351. void FWwiseResourceLoaderImpl::LoadSoundBankResources(FWwiseResourceLoadPromise&& Promise, FWwiseLoadedSoundBankInfo::FLoadedData& LoadedData, const FWwiseSoundBankCookedData& InCookedData)
  1352. {
  1353. SCOPED_WWISERESOURCELOADER_EVENT_2(TEXT("FWwiseResourceLoaderImpl::LoadSoundBankResources"));
  1354. if (LoadedData.IsProcessing)
  1355. {
  1356. ExecutionQueue.Async(WWISERESOURCELOADER_ASYNC_NAME("FWwiseResourceLoaderImpl::LoadSoundBankResources IsProcessing"), [this, Promise = MoveTemp(Promise), &LoadedData, &InCookedData]() mutable
  1357. {
  1358. LoadSoundBankResources(MoveTemp(Promise), LoadedData, InCookedData);
  1359. });
  1360. return;
  1361. }
  1362. LogLoadResources(InCookedData);
  1363. if (UNLIKELY(LoadedData.IsLoaded()))
  1364. {
  1365. UE_LOG(LogWwiseResourceLoader, Error, TEXT("LoadSoundBankResources: SoundBank %s (%" PRIu32 ") is already loaded."),
  1366. *InCookedData.DebugName.ToString(), (uint32)InCookedData.SoundBankId);
  1367. return Promise.EmplaceValue(false);
  1368. }
  1369. ++LoadedData.IsProcessing;
  1370. LoadSoundBankFile(InCookedData, [Promise = MoveTemp(Promise), &LoadedData, &InCookedData](bool bResult) mutable
  1371. {
  1372. LoadedData.bLoaded = bResult;
  1373. --LoadedData.IsProcessing;
  1374. if (UNLIKELY(!bResult))
  1375. {
  1376. UE_LOG(LogWwiseResourceLoader, Error, TEXT("LoadSoundBankResources: Could not load SoundBank %s (%" PRIu32 ")"),
  1377. *InCookedData.DebugName.ToString(), (uint32)InCookedData.SoundBankId);
  1378. }
  1379. Promise.EmplaceValue(bResult);
  1380. });
  1381. }
  1382. void FWwiseResourceLoaderImpl::LoadSwitchContainerLeafResources(FCompletionPromise&& Promise, TSharedRef<FWwiseSwitchContainerLeafGroupValueUsageCount, ESPMode::ThreadSafe> UsageCount)
  1383. {
  1384. SCOPED_WWISERESOURCELOADER_EVENT_2(TEXT("FWwiseResourceLoaderImpl::LoadSwitchContainerLeafResources"));
  1385. check(ExecutionQueue.IsRunningInThisThread());
  1386. auto& LoadedData = UsageCount->LoadedData;
  1387. const auto& CookedData = UsageCount->Key;
  1388. if (LoadedData.IsProcessing)
  1389. {
  1390. ExecutionQueue.Async(WWISERESOURCELOADER_ASYNC_NAME("FWwiseResourceLoaderImpl::LoadSwitchContainerLeafResources IsProcessing"), [this, Promise = MoveTemp(Promise), UsageCount]() mutable
  1391. {
  1392. LoadSwitchContainerLeafResources(MoveTemp(Promise), UsageCount);
  1393. });
  1394. return;
  1395. }
  1396. if (UNLIKELY(LoadedData.IsLoaded()))
  1397. {
  1398. SCOPED_WWISERESOURCELOADER_EVENT_2(TEXT("FWwiseResourceLoaderImpl::LoadSwitchContainerLeafResources AlreadyLoaded.Done"));
  1399. UE_LOG(LogWwiseResourceLoader, VeryVerbose, TEXT("FWwiseResourceLoaderImpl::LoadSwitchContainerLeafResources[%p]: Loading Switch Container Leaf %s that's already loaded. Skipping."), &UsageCount.Get(), *UsageCount->Key.GetDebugString())
  1400. return Promise.EmplaceValue();
  1401. }
  1402. if (!UsageCount->HaveAllKeys())
  1403. {
  1404. SCOPED_WWISERESOURCELOADER_EVENT_2(TEXT("FWwiseResourceLoaderImpl::LoadSwitchContainerLeafResources !HaveAllKeys.Done"));
  1405. UE_LOG(LogWwiseResourceLoader, VeryVerbose, TEXT("FWwiseResourceLoaderImpl::LoadSwitchContainerLeafResources[%p]: Loading Switch Container Leaf %s that don't have all the keys anymore. Skipping."), &UsageCount.Get(), *UsageCount->Key.GetDebugString())
  1406. return Promise.EmplaceValue();
  1407. }
  1408. LogLoadResources(CookedData, &LoadedData);
  1409. auto& LoadedSoundBanks = LoadedData.LoadedSoundBanks;
  1410. auto& LoadedExternalSources = LoadedData.LoadedExternalSources;
  1411. auto& LoadedMedia = LoadedData.LoadedMedia;
  1412. ++LoadedData.IsProcessing;
  1413. FCompletionFutureArray FutureArray;
  1414. AddLoadExternalSourceFutures(FutureArray, LoadedExternalSources, CookedData.ExternalSources, TEXT("Switch Container Leaf"), CookedData.GetDebugString(), 0);
  1415. AddLoadMediaFutures(FutureArray, LoadedMedia, CookedData.Media, TEXT("Switch Container Leaf"), CookedData.GetDebugString(), 0);
  1416. AddLoadSoundBankFutures(FutureArray, LoadedSoundBanks, CookedData.SoundBanks, TEXT("Switch Container Leaf"), CookedData.GetDebugString(), 0);
  1417. WaitForFutures(MoveTemp(FutureArray), [this, UsageCount, &LoadedData, Promise = MoveTemp(Promise)]() mutable
  1418. {
  1419. SCOPED_WWISERESOURCELOADER_EVENT_3(TEXT("FWwiseResourceLoaderImpl::LoadSwitchContainerLeafResources WaitForFutures.Done"));
  1420. INC_DWORD_STAT(STAT_WwiseResourceLoaderSwitchContainerCombinations);
  1421. --LoadedData.IsProcessing;
  1422. Promise.EmplaceValue();
  1423. });
  1424. }
  1425. void FWwiseResourceLoaderImpl::UnloadAuxBusResources(FWwiseResourceUnloadPromise&& Promise, FWwiseLoadedAuxBusInfo::FLoadedData& LoadedData, const FWwiseAuxBusCookedData& InCookedData)
  1426. {
  1427. SCOPED_WWISERESOURCELOADER_EVENT_2(TEXT("FWwiseResourceLoaderImpl::UnloadAuxBusResources"));
  1428. if (LoadedData.IsProcessing)
  1429. {
  1430. ExecutionQueue.Async(WWISERESOURCELOADER_ASYNC_NAME("FWwiseResourceLoaderImpl::UnloadAuxBusResources IsProcessing"), [this, Promise = MoveTemp(Promise), &LoadedData, &InCookedData]() mutable
  1431. {
  1432. UnloadAuxBusResources(MoveTemp(Promise), LoadedData, InCookedData);
  1433. });
  1434. return;
  1435. }
  1436. LogUnloadResources(InCookedData);
  1437. auto& LoadedSoundBanks = LoadedData.LoadedSoundBanks;
  1438. auto& LoadedMedia = LoadedData.LoadedMedia;
  1439. ++LoadedData.IsProcessing;
  1440. FCompletionFutureArray FutureArray;
  1441. AddUnloadSoundBankFutures(FutureArray, LoadedSoundBanks, TEXT("AuxBus"), InCookedData.DebugName.ToString(), InCookedData.AuxBusId);
  1442. AddUnloadMediaFutures(FutureArray, LoadedMedia, TEXT("AuxBus"), InCookedData.DebugName.ToString(), InCookedData.AuxBusId);
  1443. WaitForFutures(MoveTemp(FutureArray), [Promise = MoveTemp(Promise), &LoadedData]() mutable
  1444. {
  1445. --LoadedData.IsProcessing;
  1446. Promise.EmplaceValue();
  1447. });
  1448. }
  1449. void FWwiseResourceLoaderImpl::UnloadEventResources(FWwiseResourceUnloadPromise&& Promise, FWwiseLoadedEventInfo::FLoadedData& LoadedData, const FWwiseEventCookedData& InCookedData)
  1450. {
  1451. SCOPED_WWISERESOURCELOADER_EVENT_2(TEXT("FWwiseResourceLoaderImpl::UnloadEventResources"));
  1452. if (LoadedData.IsProcessing)
  1453. {
  1454. ExecutionQueue.Async(WWISERESOURCELOADER_ASYNC_NAME("FWwiseResourceLoaderImpl::UnloadEventResources IsProcessing"), [this, Promise = MoveTemp(Promise), &LoadedData, &InCookedData]() mutable
  1455. {
  1456. UnloadEventResources(MoveTemp(Promise), LoadedData, InCookedData);
  1457. });
  1458. return;
  1459. }
  1460. LogUnloadResources(InCookedData);
  1461. auto& LoadedSoundBanks = LoadedData.LoadedSoundBanks;
  1462. ++LoadedData.IsProcessing;
  1463. FCompletionFutureArray FutureArray;
  1464. AddUnloadSoundBankFutures(FutureArray, LoadedSoundBanks, TEXT("Event"), InCookedData.DebugName.ToString(), InCookedData.EventId);
  1465. auto& LoadedExternalSources = LoadedData.LoadedExternalSources;
  1466. auto& LoadedMedia = LoadedData.LoadedMedia;
  1467. if (LoadedData.bLoadedSwitchContainerLeaves || LoadedData.LoadedRequiredGroupValues.Num() > 0)
  1468. {
  1469. FCompletionPromise SwitchContainerLeavesPromise;
  1470. FutureArray.Add(SwitchContainerLeavesPromise.GetFuture());
  1471. UnloadEventSwitchContainerResources(MoveTemp(SwitchContainerLeavesPromise), LoadedData, InCookedData);
  1472. }
  1473. AddUnloadExternalSourceFutures(FutureArray, LoadedExternalSources, TEXT("Event"), InCookedData.DebugName.ToString(), InCookedData.EventId);
  1474. AddUnloadMediaFutures(FutureArray, LoadedMedia, TEXT("Event"), InCookedData.DebugName.ToString(), InCookedData.EventId);
  1475. WaitForFutures(MoveTemp(FutureArray), [Promise = MoveTemp(Promise), &LoadedData]() mutable
  1476. {
  1477. SCOPED_WWISERESOURCELOADER_EVENT_2(TEXT("FWwiseResourceLoaderImpl::UnloadEventResources SoundBank.Done Async WaitForFutures.Done"));
  1478. --LoadedData.IsProcessing;
  1479. Promise.EmplaceValue();
  1480. });
  1481. }
  1482. void FWwiseResourceLoaderImpl::UnloadEventSwitchContainerResources(FWwiseResourceUnloadPromise&& Promise, FWwiseLoadedEventInfo::FLoadedData& LoadedData, const FWwiseEventCookedData& InCookedData)
  1483. {
  1484. SCOPED_WWISERESOURCELOADER_EVENT_2(TEXT("FWwiseResourceLoaderImpl::UnloadEventSwitchContainerResources"));
  1485. // Unload required GroupValues
  1486. FWwiseLoadedGroupValueList& LoadedRequiredGroupValues = LoadedData.LoadedRequiredGroupValues;
  1487. bool& bLoadedSwitchContainerLeaves = LoadedData.bLoadedSwitchContainerLeaves;
  1488. UE_LOG(LogWwiseResourceLoader, VeryVerbose, TEXT("Unloading %d GroupValues for Event %s (%" PRIu32 ")"),
  1489. (int)LoadedRequiredGroupValues.Num(), *InCookedData.DebugName.ToString(), (uint32)InCookedData.EventId);
  1490. FCompletionFutureArray FutureArray;
  1491. for (auto& GroupValue : LoadedRequiredGroupValues)
  1492. {
  1493. FCompletionPromise GroupValuePromise;
  1494. FutureArray.Add(GroupValuePromise.GetFuture());
  1495. ExecutionQueue.Async(WWISERESOURCELOADER_ASYNC_NAME("FWwiseResourceLoaderImpl::UnloadEventSwitchContainerResources GroupValue"), [this, &InCookedData, &GroupValue, GroupValuePromise = MoveTemp(GroupValuePromise)]() mutable
  1496. {
  1497. UE_LOG(LogWwiseResourceLoader, VeryVerbose, TEXT("Unloading GroupValue %s for Event %s (%" PRIu32 ")"),
  1498. *GroupValue.GroupValueCookedData.DebugName.ToString(), *InCookedData.DebugName.ToString(), (uint32)InCookedData.EventId);
  1499. UnloadGroupValueResources(MoveTemp(GroupValuePromise), GroupValue.LoadedData, GroupValue.GroupValueCookedData);
  1500. });
  1501. }
  1502. // Unload Switch Container Leaves
  1503. UE_LOG(LogWwiseResourceLoader, VeryVerbose, TEXT("Unloading %d Leaves for Event %s (%" PRIu32 ")"),
  1504. (int)InCookedData.SwitchContainerLeaves.Num(), *InCookedData.DebugName.ToString(), (uint32)InCookedData.EventId);
  1505. if (bLoadedSwitchContainerLeaves) for (const auto& SwitchContainerLeaf : InCookedData.SwitchContainerLeaves)
  1506. {
  1507. FCompletionPromise SwitchContainerLeavesPromise;
  1508. FutureArray.Add(SwitchContainerLeavesPromise.GetFuture());
  1509. ExecutionQueue.Async(WWISERESOURCELOADER_ASYNC_NAME("FWwiseResourceLoaderImpl::UnloadEventSwitchContainerResources Leaf.SwitchContainer"), [this, &SwitchContainerLeaf, &InCookedData, SwitchContainerLeavesPromise = MoveTemp(SwitchContainerLeavesPromise)]() mutable
  1510. {
  1511. TSharedPtr<FWwiseSwitchContainerLeafGroupValueUsageCount, ESPMode::ThreadSafe> UsageCountPtr;
  1512. for (const auto& GroupValue : SwitchContainerLeaf.GroupValueSet)
  1513. {
  1514. FWwiseSwitchContainerLoadedGroupValueInfo* Info = LoadedGroupValueInfo.Find(FWwiseSwitchContainerLoadedGroupValueInfo(GroupValue));
  1515. if (UNLIKELY(!Info))
  1516. {
  1517. UE_LOG(LogWwiseResourceLoader, Error, TEXT("FWwiseResourceLoaderImpl::UnloadEventSwitchContainerResources Info[%p]: Could not find requested GroupValue %s for Leaf in Event %s (%" PRIu32 ")"),
  1518. Info,
  1519. *GroupValue.DebugName.ToString(), *InCookedData.DebugName.ToString(), (uint32)InCookedData.EventId);
  1520. continue;
  1521. }
  1522. if (!UsageCountPtr)
  1523. {
  1524. for (auto& Leaf : Info->Leaves)
  1525. {
  1526. if (Leaf->Key == SwitchContainerLeaf)
  1527. {
  1528. UsageCountPtr = Leaf;
  1529. break;
  1530. }
  1531. }
  1532. if (UNLIKELY(!UsageCountPtr))
  1533. {
  1534. UE_LOG(LogWwiseResourceLoader, Error, TEXT("FWwiseResourceLoaderImpl::UnloadEventSwitchContainerResources Info[%p]: Could not find requested Leaf in GroupValue %s in Event %s (%" PRIu32 ")"),
  1535. Info,
  1536. *GroupValue.DebugName.ToString(), *InCookedData.DebugName.ToString(), (uint32)InCookedData.EventId);
  1537. continue;
  1538. }
  1539. }
  1540. auto UsageCount = UsageCountPtr.ToSharedRef();
  1541. UE_LOG(LogWwiseResourceLoader, VeryVerbose, TEXT("FWwiseResourceLoaderImpl::UnloadEventSwitchContainerResources Info[%p] UsageCount[%p]: Removing requested GroupValue %s for %s in Event %s (%" PRIu32 ")"),
  1542. Info, &UsageCount.Get(),
  1543. *GroupValue.DebugName.ToString(), *UsageCount->Key.GetDebugString(), *InCookedData.DebugName.ToString(), (uint32)InCookedData.EventId);
  1544. UE_CLOG(!Info->ShouldBeLoaded(), LogWwiseResourceLoader, VeryVerbose, TEXT("FWwiseResourceLoaderImpl::UnloadEventSwitchContainerResources Info[%p] UsageCount[%p]: Don't have referencing GroupValues yet: %d for key %s"), Info, &UsageCount.Get(), Info->LoadCount, *UsageCount->Key.GetDebugString());
  1545. UE_CLOG(Info->ShouldBeLoaded(), LogWwiseResourceLoader, VeryVerbose, TEXT("FWwiseResourceLoaderImpl::UnloadEventSwitchContainerResources Info[%p] UsageCount[%p]: Have referencing GroupValues: %d for key %s"), Info, &UsageCount.Get(), Info->LoadCount, *UsageCount->Key.GetDebugString());
  1546. if (Info->ShouldBeLoaded())
  1547. {
  1548. UE_LOG(LogWwiseResourceLoader, VeryVerbose, TEXT("FWwiseResourceLoaderImpl::UnloadEventSwitchContainerResources Info[%p] UsageCount[%p]: Number of GroupValues required for this leaf: %d/%d @ %p for key %s (-1 in SwitchContainer)"),
  1549. Info, &UsageCount.Get(), (int)UsageCount->LoadedGroupValues.Num() - 1, UsageCount->Key.GroupValueSet.Num(), &UsageCount->LoadedData, *UsageCount->Key.GetDebugString());
  1550. UsageCount->LoadedGroupValues.Remove(GroupValue);
  1551. }
  1552. }
  1553. if (LIKELY(UsageCountPtr))
  1554. {
  1555. auto UsageCount = UsageCountPtr.ToSharedRef();
  1556. if (UNLIKELY(UsageCount->LoadedGroupValues.Num() > 0))
  1557. {
  1558. UE_LOG(LogWwiseResourceLoader, Error, TEXT("FWwiseResourceLoaderImpl::UnloadEventSwitchContainerResources UsageCount[%p]: There are still %d loaded elements for %s in Event %s (%" PRIu32 ")"),
  1559. &UsageCount.Get(), *UsageCount->Key.GetDebugString(),
  1560. (int)UsageCount->LoadedGroupValues.Num(), *InCookedData.DebugName.ToString(), (uint32)InCookedData.EventId);
  1561. }
  1562. UnloadSwitchContainerLeafResources(MoveTemp(SwitchContainerLeavesPromise), UsageCount);
  1563. }
  1564. else
  1565. {
  1566. SCOPED_WWISERESOURCELOADER_EVENT_3(TEXT("FWwiseResourceLoaderImpl::UnloadEventSwitchContainerResources Leaf.SwitchContainer !Unload.Done"));
  1567. SwitchContainerLeavesPromise.EmplaceValue();
  1568. }
  1569. });
  1570. }
  1571. WaitForFutures(MoveTemp(FutureArray), [Promise = MoveTemp(Promise), &LoadedRequiredGroupValues, &bLoadedSwitchContainerLeaves]() mutable
  1572. {
  1573. SCOPED_WWISERESOURCELOADER_EVENT_3(TEXT("FWwiseResourceLoaderImpl::UnloadEventSwitchContainerResources Leaf.SwitchContainer WaitForFutures.Done"));
  1574. LoadedRequiredGroupValues.Empty();
  1575. bLoadedSwitchContainerLeaves = false;
  1576. Promise.EmplaceValue();
  1577. });
  1578. }
  1579. void FWwiseResourceLoaderImpl::UnloadExternalSourceResources(FWwiseResourceUnloadPromise&& Promise, FWwiseLoadedExternalSourceInfo::FLoadedData& LoadedData, const FWwiseExternalSourceCookedData& InCookedData)
  1580. {
  1581. SCOPED_WWISERESOURCELOADER_EVENT_2(TEXT("FWwiseResourceLoaderImpl::UnloadExternalSourceResources"));
  1582. if (LoadedData.IsProcessing)
  1583. {
  1584. ExecutionQueue.Async(WWISERESOURCELOADER_ASYNC_NAME("FWwiseResourceLoaderImpl::UnloadExternalSourceResources IsProcessing"), [this, Promise = MoveTemp(Promise), &LoadedData, &InCookedData]() mutable
  1585. {
  1586. UnloadExternalSourceResources(MoveTemp(Promise), LoadedData, InCookedData);
  1587. });
  1588. return;
  1589. }
  1590. LogUnloadResources(InCookedData);
  1591. if (LoadedData.IsLoaded())
  1592. {
  1593. ++LoadedData.IsProcessing;
  1594. UnloadExternalSourceFile(InCookedData, [&LoadedData, Promise = MoveTemp(Promise)]() mutable
  1595. {
  1596. --LoadedData.IsProcessing;
  1597. LoadedData.bLoaded = false;
  1598. Promise.EmplaceValue();
  1599. });
  1600. }
  1601. else
  1602. {
  1603. Promise.EmplaceValue();
  1604. }
  1605. }
  1606. void FWwiseResourceLoaderImpl::UnloadGroupValueResources(FWwiseResourceUnloadPromise&& Promise, FWwiseLoadedGroupValueInfo::FLoadedData& LoadedData, const FWwiseGroupValueCookedData& InCookedData)
  1607. {
  1608. SCOPED_WWISERESOURCELOADER_EVENT_2(TEXT("FWwiseResourceLoaderImpl::UnloadGroupValueResources"));
  1609. if (LoadedData.IsProcessing)
  1610. {
  1611. ExecutionQueue.Async(WWISERESOURCELOADER_ASYNC_NAME("FWwiseResourceLoaderImpl::UnloadGroupValueResources IsProcessing"), [this, Promise = MoveTemp(Promise), &LoadedData, &InCookedData]() mutable
  1612. {
  1613. UnloadGroupValueResources(MoveTemp(Promise), LoadedData, InCookedData);
  1614. });
  1615. return;
  1616. }
  1617. LogUnloadResources(InCookedData);
  1618. ++LoadedData.IsProcessing;
  1619. ExecutionQueue.Async(WWISERESOURCELOADER_ASYNC_NAME("FWwiseResourceLoaderImpl::UnloadGroupValueResources Async"), [this, &LoadedData, &InCookedData, Promise = MoveTemp(Promise)]() mutable
  1620. {
  1621. FWwiseSwitchContainerLoadedGroupValueInfo* Info = LoadedGroupValueInfo.Find(FWwiseSwitchContainerLoadedGroupValueInfo(InCookedData));
  1622. if (UNLIKELY(!Info))
  1623. {
  1624. UE_LOG(LogWwiseResourceLoader, Error, TEXT("FWwiseResourceLoaderImpl::UnloadGroupValueResources: Could not find requested GroupValue %s (%s %" PRIu32 ":%" PRIu32 ")"),
  1625. *InCookedData.DebugName.ToString(), *InCookedData.GetTypeName(), (uint32)InCookedData.GroupId, (uint32)InCookedData.Id);
  1626. return Promise.EmplaceValue();
  1627. }
  1628. check(Info->ShouldBeLoaded());
  1629. --Info->LoadCount;
  1630. FCompletionFutureArray FutureArray;
  1631. if (!Info->ShouldBeLoaded())
  1632. {
  1633. UE_LOG(LogWwiseResourceLoader, VeryVerbose, TEXT("FWwiseResourceLoaderImpl::UnloadGroupValueResources Info[%p]: Last GroupValue %s (%s %" PRIu32 ":%" PRIu32 ") unload. Unloading %d leaves."),
  1634. Info,
  1635. *InCookedData.DebugName.ToString(), *InCookedData.GetTypeName(), (uint32)InCookedData.GroupId, (uint32)InCookedData.Id, (int)Info->Leaves.Num());
  1636. for (auto UsageCount : Info->Leaves)
  1637. {
  1638. UE_LOG(LogWwiseResourceLoader, VeryVerbose, TEXT("FWwiseResourceLoaderImpl::UnloadGroupValueResources Info[%p] UsageCount[%p]: Number of GroupValues required for leaf: %d/%d @ %p for %s (-1 in GroupValue)"), Info, &UsageCount.Get(),
  1639. (int)UsageCount->LoadedGroupValues.Num() - 1, UsageCount->Key.GroupValueSet.Num(), &UsageCount->LoadedData, *UsageCount->Key.GetDebugString());
  1640. UsageCount->LoadedGroupValues.Remove(InCookedData);
  1641. FWwiseResourceUnloadPromise UnloadPromise;
  1642. FutureArray.Add(UnloadPromise.GetFuture());
  1643. UnloadSwitchContainerLeafResources(MoveTemp(UnloadPromise), UsageCount);
  1644. }
  1645. }
  1646. else
  1647. {
  1648. UE_LOG(LogWwiseResourceLoader, VeryVerbose, TEXT("FWwiseResourceLoaderImpl::UnloadGroupValueResources Info[%p]: GroupValue %s (%s %" PRIu32 ":%" PRIu32 ") still loaded (Count: %d times)."),
  1649. Info, *InCookedData.DebugName.ToString(), *InCookedData.GetTypeName(), (uint32)InCookedData.GroupId, (uint32)InCookedData.Id, (int)Info->LoadCount);
  1650. }
  1651. WaitForFutures(MoveTemp(FutureArray), [&LoadedData, Promise = MoveTemp(Promise)]() mutable
  1652. {
  1653. SCOPED_WWISERESOURCELOADER_EVENT_3(TEXT("FWwiseResourceLoaderImpl::UnloadGroupValueResources SwitchContainer.Done"));
  1654. --LoadedData.IsProcessing;
  1655. Promise.EmplaceValue();
  1656. });
  1657. });
  1658. }
  1659. void FWwiseResourceLoaderImpl::UnloadInitBankResources(FWwiseResourceUnloadPromise&& Promise, FWwiseLoadedInitBankInfo::FLoadedData& LoadedData, const FWwiseInitBankCookedData& InCookedData)
  1660. {
  1661. SCOPED_WWISERESOURCELOADER_EVENT_2(TEXT("FWwiseResourceLoaderImpl::UnloadInitBankResources"));
  1662. if (LoadedData.IsProcessing)
  1663. {
  1664. ExecutionQueue.Async(WWISERESOURCELOADER_ASYNC_NAME("FWwiseResourceLoaderImpl::UnloadInitBankResources IsProcessing"), [this, Promise = MoveTemp(Promise), &LoadedData, &InCookedData]() mutable
  1665. {
  1666. UnloadInitBankResources(MoveTemp(Promise), LoadedData, InCookedData);
  1667. });
  1668. return;
  1669. }
  1670. LogUnloadResources(InCookedData);
  1671. ++LoadedData.IsProcessing;
  1672. auto& LoadedMedia = LoadedData.LoadedMedia;
  1673. FCompletionPromise SoundBankPromise;
  1674. auto Future = SoundBankPromise.GetFuture();
  1675. if (LoadedData.bLoaded)
  1676. {
  1677. UnloadSoundBankFile(InCookedData, [&LoadedData, SoundBankPromise = MoveTemp(SoundBankPromise)]() mutable
  1678. {
  1679. LoadedData.bLoaded = false;
  1680. SoundBankPromise.EmplaceValue();
  1681. });
  1682. }
  1683. else
  1684. {
  1685. SoundBankPromise.EmplaceValue();
  1686. }
  1687. Future.Next([this, Promise = MoveTemp(Promise), &LoadedMedia, &InCookedData, &LoadedData](int) mutable
  1688. {
  1689. FCompletionFutureArray FutureArray;
  1690. AddUnloadMediaFutures(FutureArray, LoadedMedia, TEXT("InitBank"), InCookedData.DebugName.ToString(), InCookedData.SoundBankId);
  1691. WaitForFutures(MoveTemp(FutureArray), [Promise = MoveTemp(Promise), &LoadedData]() mutable
  1692. {
  1693. --LoadedData.IsProcessing;
  1694. Promise.EmplaceValue();
  1695. });
  1696. });
  1697. }
  1698. void FWwiseResourceLoaderImpl::UnloadMediaResources(FWwiseResourceUnloadPromise&& Promise, FWwiseLoadedMediaInfo::FLoadedData& LoadedData, const FWwiseMediaCookedData& InCookedData)
  1699. {
  1700. SCOPED_WWISERESOURCELOADER_EVENT_2(TEXT("FWwiseResourceLoaderImpl::UnloadMediaResources"));
  1701. if (LoadedData.IsProcessing)
  1702. {
  1703. ExecutionQueue.Async(WWISERESOURCELOADER_ASYNC_NAME("FWwiseResourceLoaderImpl::UnloadMediaResources IsProcessing"), [this, Promise = MoveTemp(Promise), &LoadedData, &InCookedData]() mutable
  1704. {
  1705. UnloadMediaResources(MoveTemp(Promise), LoadedData, InCookedData);
  1706. });
  1707. return;
  1708. }
  1709. LogUnloadResources(InCookedData);
  1710. if (LoadedData.IsLoaded())
  1711. {
  1712. ++LoadedData.IsProcessing;
  1713. UnloadMediaFile(InCookedData, [Promise = MoveTemp(Promise), &LoadedData]() mutable
  1714. {
  1715. LoadedData.bLoaded = false;
  1716. --LoadedData.IsProcessing;
  1717. Promise.EmplaceValue();
  1718. });
  1719. }
  1720. else
  1721. {
  1722. Promise.EmplaceValue();
  1723. }
  1724. }
  1725. void FWwiseResourceLoaderImpl::UnloadShareSetResources(FWwiseResourceUnloadPromise&& Promise, FWwiseLoadedShareSetInfo::FLoadedData& LoadedData, const FWwiseShareSetCookedData& InCookedData)
  1726. {
  1727. SCOPED_WWISERESOURCELOADER_EVENT_2(TEXT("FWwiseResourceLoaderImpl::UnloadShareSetResources"));
  1728. if (LoadedData.IsProcessing)
  1729. {
  1730. ExecutionQueue.Async(WWISERESOURCELOADER_ASYNC_NAME("FWwiseResourceLoaderImpl::UnloadShareSetResources IsProcessing"), [this, Promise = MoveTemp(Promise), &LoadedData, &InCookedData]() mutable
  1731. {
  1732. UnloadShareSetResources(MoveTemp(Promise), LoadedData, InCookedData);
  1733. });
  1734. return;
  1735. }
  1736. LogUnloadResources(InCookedData);
  1737. auto& LoadedSoundBanks = LoadedData.LoadedSoundBanks;
  1738. auto& LoadedMedia = LoadedData.LoadedMedia;
  1739. ++LoadedData.IsProcessing;
  1740. FCompletionFutureArray FutureArray;
  1741. AddUnloadSoundBankFutures(FutureArray, LoadedSoundBanks, TEXT("ShareSet"), InCookedData.DebugName.ToString(), InCookedData.ShareSetId);
  1742. AddUnloadMediaFutures(FutureArray, LoadedMedia, TEXT("ShareSet"), InCookedData.DebugName.ToString(), InCookedData.ShareSetId);
  1743. WaitForFutures(MoveTemp(FutureArray), [Promise = MoveTemp(Promise), &LoadedData]() mutable
  1744. {
  1745. --LoadedData.IsProcessing;
  1746. Promise.EmplaceValue();
  1747. });
  1748. }
  1749. void FWwiseResourceLoaderImpl::UnloadSoundBankResources(FWwiseResourceUnloadPromise&& Promise, FWwiseLoadedSoundBankInfo::FLoadedData& LoadedData, const FWwiseSoundBankCookedData& InCookedData)
  1750. {
  1751. SCOPED_WWISERESOURCELOADER_EVENT_2(TEXT("FWwiseResourceLoaderImpl::UnloadSoundBankResources"));
  1752. if (LoadedData.IsProcessing)
  1753. {
  1754. ExecutionQueue.Async(WWISERESOURCELOADER_ASYNC_NAME("FWwiseResourceLoaderImpl::UnloadSoundBankResources IsProcessing"), [this, Promise = MoveTemp(Promise), &LoadedData, &InCookedData]() mutable
  1755. {
  1756. UnloadSoundBankResources(MoveTemp(Promise), LoadedData, InCookedData);
  1757. });
  1758. return;
  1759. }
  1760. LogUnloadResources(InCookedData);
  1761. if (LoadedData.IsLoaded())
  1762. {
  1763. ++LoadedData.IsProcessing;
  1764. UnloadSoundBankFile(InCookedData, [Promise = MoveTemp(Promise), &LoadedData]() mutable
  1765. {
  1766. LoadedData.bLoaded = false;
  1767. --LoadedData.IsProcessing;
  1768. Promise.EmplaceValue();
  1769. });
  1770. }
  1771. else
  1772. {
  1773. Promise.EmplaceValue();
  1774. }
  1775. }
  1776. void FWwiseResourceLoaderImpl::UnloadSwitchContainerLeafResources(FWwiseResourceUnloadPromise&& Promise, TSharedRef<FWwiseSwitchContainerLeafGroupValueUsageCount, ESPMode::ThreadSafe> UsageCount)
  1777. {
  1778. SCOPED_WWISERESOURCELOADER_EVENT_2(TEXT("FWwiseResourceLoaderImpl::UnloadSwitchContainerLeafResources"));
  1779. check(ExecutionQueue.IsRunningInThisThread());
  1780. auto& LoadedData = UsageCount->LoadedData;
  1781. const auto& CookedData = UsageCount->Key;
  1782. if (LoadedData.IsProcessing)
  1783. {
  1784. ExecutionQueue.Async(WWISERESOURCELOADER_ASYNC_NAME("FWwiseResourceLoaderImpl::UnloadSwitchContainerLeafResources IsProcessing"), [this, Promise = MoveTemp(Promise), UsageCount]() mutable
  1785. {
  1786. UnloadSwitchContainerLeafResources(MoveTemp(Promise), UsageCount);
  1787. });
  1788. return;
  1789. }
  1790. if (UNLIKELY(UsageCount->HaveAllKeys()))
  1791. {
  1792. SCOPED_WWISERESOURCELOADER_EVENT_2(TEXT("FWwiseResourceLoaderImpl::UnloadSwitchContainerLeafResources LoadedGroupValues.Done"));
  1793. UE_LOG(LogWwiseResourceLoader, VeryVerbose, TEXT("FWwiseResourceLoaderImpl::UnloadSwitchContainerLeafResources[%p]: Unloading Switch Container Leaf %s that is still fully in use. Skipping unload."), &UsageCount.Get(), *UsageCount->Key.GetDebugString())
  1794. return Promise.EmplaceValue();
  1795. }
  1796. LogUnloadResources(CookedData, &LoadedData);
  1797. auto& LoadedSoundBanks = LoadedData.LoadedSoundBanks;
  1798. auto& LoadedExternalSources = LoadedData.LoadedExternalSources;
  1799. auto& LoadedMedia = LoadedData.LoadedMedia;
  1800. UE_LOG(LogWwiseResourceLoader, VeryVerbose, TEXT("FWwiseResourceLoaderImpl::UnloadSwitchContainerLeafResources UsageCount[%p]: Unloading Switch Container Leaf %s"), &UsageCount.Get(), *CookedData.GetDebugString());
  1801. ++LoadedData.IsProcessing;
  1802. FCompletionFutureArray FutureArray;
  1803. AddUnloadSoundBankFutures(FutureArray, LoadedSoundBanks, TEXT("Switch Container Leaf"), CookedData.GetDebugString(), 0);
  1804. AddUnloadExternalSourceFutures(FutureArray, LoadedExternalSources, TEXT("Switch Container Leaf"), CookedData.GetDebugString(), 0);
  1805. AddUnloadMediaFutures(FutureArray, LoadedMedia, TEXT("Switch Container Leaf"), CookedData.GetDebugString(), 0);
  1806. WaitForFutures(MoveTemp(FutureArray), [Promise = MoveTemp(Promise), &LoadedData]() mutable
  1807. {
  1808. SCOPED_WWISERESOURCELOADER_EVENT_3(TEXT("FWwiseResourceLoaderImpl::UnloadSwitchContainerLeafResources Done"));
  1809. DEC_DWORD_STAT(STAT_WwiseResourceLoaderSwitchContainerCombinations);
  1810. UE_LOG(LogWwiseResourceLoader, VeryVerbose, TEXT("Done unloading Switch Container Leaf @ %p"), &LoadedData);
  1811. --LoadedData.IsProcessing;
  1812. Promise.EmplaceValue();
  1813. });
  1814. }
  1815. void FWwiseResourceLoaderImpl::AttachAuxBusNode(FWwiseLoadedAuxBusPtr AuxBusListNode)
  1816. {
  1817. {
  1818. FScopeLock Lock(&ListUpdateCriticalSection);
  1819. LoadedAuxBusList.AddTail(AuxBusListNode);
  1820. }
  1821. INC_DWORD_STAT(STAT_WwiseResourceLoaderAuxBusses);
  1822. }
  1823. void FWwiseResourceLoaderImpl::AttachEventNode(FWwiseLoadedEventPtr EventListNode)
  1824. {
  1825. {
  1826. FScopeLock Lock(&ListUpdateCriticalSection);
  1827. LoadedEventList.AddTail(EventListNode);
  1828. }
  1829. INC_DWORD_STAT(STAT_WwiseResourceLoaderEvents);
  1830. }
  1831. void FWwiseResourceLoaderImpl::AttachExternalSourceNode(FWwiseLoadedExternalSourcePtr ExternalSourceListNode)
  1832. {
  1833. {
  1834. FScopeLock Lock(&ListUpdateCriticalSection);
  1835. LoadedExternalSourceList.AddTail(ExternalSourceListNode);
  1836. }
  1837. INC_DWORD_STAT(STAT_WwiseResourceLoaderExternalSources);
  1838. }
  1839. void FWwiseResourceLoaderImpl::AttachGroupValueNode(FWwiseLoadedGroupValuePtr GroupValueListNode)
  1840. {
  1841. {
  1842. FScopeLock Lock(&ListUpdateCriticalSection);
  1843. LoadedGroupValueList.AddTail(GroupValueListNode);
  1844. }
  1845. INC_DWORD_STAT(STAT_WwiseResourceLoaderGroupValues);
  1846. }
  1847. void FWwiseResourceLoaderImpl::AttachInitBankNode(FWwiseLoadedInitBankPtr InitBankListNode)
  1848. {
  1849. {
  1850. FScopeLock Lock(&ListUpdateCriticalSection);
  1851. LoadedInitBankList.AddTail(InitBankListNode);
  1852. }
  1853. INC_DWORD_STAT(STAT_WwiseResourceLoaderInitBanks);
  1854. }
  1855. void FWwiseResourceLoaderImpl::AttachMediaNode(FWwiseLoadedMediaPtr MediaListNode)
  1856. {
  1857. {
  1858. FScopeLock Lock(&ListUpdateCriticalSection);
  1859. LoadedMediaList.AddTail(MediaListNode);
  1860. }
  1861. INC_DWORD_STAT(STAT_WwiseResourceLoaderMedia);
  1862. }
  1863. void FWwiseResourceLoaderImpl::AttachShareSetNode(FWwiseLoadedShareSetPtr ShareSetListNode)
  1864. {
  1865. {
  1866. FScopeLock Lock(&ListUpdateCriticalSection);
  1867. LoadedShareSetList.AddTail(ShareSetListNode);
  1868. }
  1869. INC_DWORD_STAT(STAT_WwiseResourceLoaderShareSets);
  1870. }
  1871. void FWwiseResourceLoaderImpl::AttachSoundBankNode(FWwiseLoadedSoundBankPtr SoundBankListNode)
  1872. {
  1873. {
  1874. FScopeLock Lock(&ListUpdateCriticalSection);
  1875. LoadedSoundBankList.AddTail(SoundBankListNode);
  1876. }
  1877. INC_DWORD_STAT(STAT_WwiseResourceLoaderSoundBanks);
  1878. }
  1879. void FWwiseResourceLoaderImpl::DetachAuxBusNode(FWwiseLoadedAuxBusPtr AuxBusListNode)
  1880. {
  1881. {
  1882. FScopeLock Lock(&ListUpdateCriticalSection);
  1883. LoadedAuxBusList.RemoveNode(AuxBusListNode, false);
  1884. }
  1885. DEC_DWORD_STAT(STAT_WwiseResourceLoaderAuxBusses);
  1886. }
  1887. void FWwiseResourceLoaderImpl::DetachEventNode(FWwiseLoadedEventPtr EventListNode)
  1888. {
  1889. {
  1890. FScopeLock Lock(&ListUpdateCriticalSection);
  1891. LoadedEventList.RemoveNode(EventListNode, false);
  1892. }
  1893. DEC_DWORD_STAT(STAT_WwiseResourceLoaderEvents);
  1894. }
  1895. void FWwiseResourceLoaderImpl::DetachExternalSourceNode(FWwiseLoadedExternalSourcePtr ExternalSourceListNode)
  1896. {
  1897. {
  1898. FScopeLock Lock(&ListUpdateCriticalSection);
  1899. LoadedExternalSourceList.RemoveNode(ExternalSourceListNode, false);
  1900. }
  1901. DEC_DWORD_STAT(STAT_WwiseResourceLoaderExternalSources);
  1902. }
  1903. void FWwiseResourceLoaderImpl::DetachGroupValueNode(FWwiseLoadedGroupValuePtr GroupValueListNode)
  1904. {
  1905. {
  1906. FScopeLock Lock(&ListUpdateCriticalSection);
  1907. LoadedGroupValueList.RemoveNode(GroupValueListNode, false);
  1908. }
  1909. DEC_DWORD_STAT(STAT_WwiseResourceLoaderGroupValues);
  1910. }
  1911. void FWwiseResourceLoaderImpl::DetachInitBankNode(FWwiseLoadedInitBankPtr InitBankListNode)
  1912. {
  1913. {
  1914. FScopeLock Lock(&ListUpdateCriticalSection);
  1915. LoadedInitBankList.RemoveNode(InitBankListNode, false);
  1916. }
  1917. DEC_DWORD_STAT(STAT_WwiseResourceLoaderInitBanks);
  1918. }
  1919. void FWwiseResourceLoaderImpl::DetachMediaNode(FWwiseLoadedMediaPtr MediaListNode)
  1920. {
  1921. {
  1922. FScopeLock Lock(&ListUpdateCriticalSection);
  1923. LoadedMediaList.RemoveNode(MediaListNode, false);
  1924. }
  1925. DEC_DWORD_STAT(STAT_WwiseResourceLoaderMedia);
  1926. }
  1927. void FWwiseResourceLoaderImpl::DetachShareSetNode(FWwiseLoadedShareSetPtr ShareSetListNode)
  1928. {
  1929. {
  1930. FScopeLock Lock(&ListUpdateCriticalSection);
  1931. LoadedShareSetList.RemoveNode(ShareSetListNode, false);
  1932. }
  1933. DEC_DWORD_STAT(STAT_WwiseResourceLoaderShareSets);
  1934. }
  1935. void FWwiseResourceLoaderImpl::DetachSoundBankNode(FWwiseLoadedSoundBankPtr SoundBankListNode)
  1936. {
  1937. {
  1938. FScopeLock Lock(&ListUpdateCriticalSection);
  1939. LoadedSoundBankList.RemoveNode(SoundBankListNode, false);
  1940. }
  1941. DEC_DWORD_STAT(STAT_WwiseResourceLoaderSoundBanks);
  1942. }
  1943. void FWwiseResourceLoaderImpl::AddLoadExternalSourceFutures(FCompletionFutureArray& FutureArray, TArray<const FWwiseExternalSourceCookedData*>& LoadedExternalSources,
  1944. const TArray<FWwiseExternalSourceCookedData>& InExternalSources, const TCHAR* InType, const FString& InDebugName, uint32 InShortId) const
  1945. {
  1946. for (const auto& ExternalSource : InExternalSources)
  1947. {
  1948. TWwisePromise<void> Promise;
  1949. FutureArray.Add(Promise.GetFuture());
  1950. LoadExternalSourceFile(ExternalSource, [this, &ExternalSource, &LoadedExternalSources, InType, InDebugName, InShortId, Promise = MoveTemp(Promise)](bool bInResult) mutable
  1951. {
  1952. if (UNLIKELY(!bInResult))
  1953. {
  1954. UE_LOG(LogWwiseResourceLoader, Warning, TEXT("Load%sResources: Could not load External Source %s (%" PRIu32 ") for %s %s (%" PRIu32 ")"),
  1955. InType,
  1956. *ExternalSource.DebugName.ToString(), (uint32)ExternalSource.Cookie,
  1957. InType, *InDebugName, (uint32)InShortId);
  1958. Promise.EmplaceValue();
  1959. }
  1960. else
  1961. {
  1962. ExecutionQueue.Async(WWISERESOURCELOADER_ASYNC_NAME("FWwiseResourceLoaderImpl::AddLoadExternalSourceFutures EmplaceValue"), [&ExternalSource, &LoadedExternalSources, Promise = MoveTemp(Promise), InType, InDebugName, InShortId]() mutable
  1963. {
  1964. UE_LOG(LogWwiseResourceLoader, VeryVerbose, TEXT("AddLoadExternalSourceFutures: Adding SoundBank %s (%" PRIu32 ") to %s %s (%" PRIu32 ")"),
  1965. *ExternalSource.DebugName.ToString(), (uint32)ExternalSource.Cookie,
  1966. InType, *InDebugName, (uint32)InShortId);
  1967. LoadedExternalSources.Add(&ExternalSource);
  1968. Promise.EmplaceValue();
  1969. });
  1970. }
  1971. });
  1972. }
  1973. }
  1974. void FWwiseResourceLoaderImpl::AddUnloadExternalSourceFutures(FCompletionFutureArray& FutureArray,
  1975. TArray<const FWwiseExternalSourceCookedData*>& LoadedExternalSources,
  1976. const TCHAR* InType, const FString& InDebugName, uint32 InShortId) const
  1977. {
  1978. if (LoadedExternalSources.Num() == 0) return;
  1979. const auto ToUnload(MoveTemp(LoadedExternalSources));
  1980. LoadedExternalSources.Empty();
  1981. UE_LOG(LogWwiseResourceLoader, VeryVerbose, TEXT("AddUnloadExternalSourceFutures: Unloading all %d External Sources from %s %s (%" PRIu32 ")"),
  1982. (int)ToUnload.Num(),
  1983. InType, *InDebugName, (uint32)InShortId);
  1984. for (const auto* ExternalSource : ToUnload)
  1985. {
  1986. TWwisePromise<void> Promise;
  1987. FutureArray.Add(Promise.GetFuture());
  1988. UnloadExternalSourceFile(*ExternalSource, [Promise = MoveTemp(Promise)]() mutable
  1989. {
  1990. Promise.EmplaceValue();
  1991. });
  1992. }
  1993. }
  1994. void FWwiseResourceLoaderImpl::AddLoadMediaFutures(FCompletionFutureArray& FutureArray, TArray<const FWwiseMediaCookedData*>& LoadedMedia,
  1995. const TArray<FWwiseMediaCookedData>& InMedia, const TCHAR* InType, const FString& InDebugName, uint32 InShortId) const
  1996. {
  1997. for (const auto& Media : InMedia)
  1998. {
  1999. TWwisePromise<void> Promise;
  2000. FutureArray.Add(Promise.GetFuture());
  2001. LoadMediaFile(Media, [this, &Media, &LoadedMedia, InType, InDebugName, InShortId, Promise = MoveTemp(Promise)](bool bInResult) mutable
  2002. {
  2003. if (UNLIKELY(!bInResult))
  2004. {
  2005. UE_LOG(LogWwiseResourceLoader, Warning, TEXT("Load%sResources: Could not load Media %s (%" PRIu32 ") for %s %s (%" PRIu32 ")"),
  2006. InType,
  2007. *Media.DebugName.ToString(), (uint32)Media.MediaId,
  2008. InType, *InDebugName, (uint32)InShortId);
  2009. Promise.EmplaceValue();
  2010. }
  2011. else
  2012. {
  2013. if (UNLIKELY(Test::bMockSleepOnMediaLoad))
  2014. {
  2015. FPlatformProcess::Sleep(0.001f);
  2016. }
  2017. ExecutionQueue.Async(WWISERESOURCELOADER_ASYNC_NAME("FWwiseResourceLoaderImpl::AddLoadMediaFutures EmplaceValue"), [&Media, &LoadedMedia, Promise = MoveTemp(Promise), InType, InDebugName, InShortId]() mutable
  2018. {
  2019. UE_LOG(LogWwiseResourceLoader, VeryVerbose, TEXT("AddLoadMediaFutures: Adding Media %s (%" PRIu32 ") to %s %s (%" PRIu32 ")"),
  2020. *Media.DebugName.ToString(), (uint32)Media.MediaId,
  2021. InType, *InDebugName, (uint32)InShortId);
  2022. LoadedMedia.Add(&Media);
  2023. Promise.EmplaceValue();
  2024. });
  2025. }
  2026. });
  2027. }
  2028. }
  2029. void FWwiseResourceLoaderImpl::AddUnloadMediaFutures(FCompletionFutureArray& FutureArray,
  2030. TArray<const FWwiseMediaCookedData*>& LoadedMedia,
  2031. const TCHAR* InType, const FString& InDebugName, uint32 InShortId) const
  2032. {
  2033. if (LoadedMedia.Num() == 0) return;
  2034. const auto ToUnload(MoveTemp(LoadedMedia));
  2035. LoadedMedia.Empty();
  2036. UE_LOG(LogWwiseResourceLoader, VeryVerbose, TEXT("AddUnloadMediaFutures: Unloading all %d Media from %s %s (%" PRIu32 ")"),
  2037. (int)ToUnload.Num(),
  2038. InType, *InDebugName, (uint32)InShortId);
  2039. for (const auto* Media : ToUnload)
  2040. {
  2041. TWwisePromise<void> Promise;
  2042. FutureArray.Add(Promise.GetFuture());
  2043. UnloadMediaFile(*Media, [Promise = MoveTemp(Promise)]() mutable
  2044. {
  2045. Promise.EmplaceValue();
  2046. });
  2047. }
  2048. }
  2049. void FWwiseResourceLoaderImpl::AddLoadSoundBankFutures(FCompletionFutureArray& FutureArray, TArray<const FWwiseSoundBankCookedData*>& LoadedSoundBanks,
  2050. const TArray<FWwiseSoundBankCookedData>& InSoundBank, const TCHAR* InType, const FString& InDebugName, uint32 InShortId) const
  2051. {
  2052. for (const auto& SoundBank : InSoundBank)
  2053. {
  2054. TWwisePromise<void> Promise;
  2055. FutureArray.Add(Promise.GetFuture());
  2056. LoadSoundBankFile(SoundBank, [this, &SoundBank, &LoadedSoundBanks, InType, InDebugName, InShortId, Promise = MoveTemp(Promise)](bool bInResult) mutable
  2057. {
  2058. if (UNLIKELY(!bInResult))
  2059. {
  2060. UE_LOG(LogWwiseResourceLoader, Warning, TEXT("Load%sResources: Could not load SoundBank %s (%" PRIu32 ") for %s %s (%" PRIu32 ")"),
  2061. InType,
  2062. *SoundBank.DebugName.ToString(), (uint32)SoundBank.SoundBankId,
  2063. InType, *InDebugName, (uint32)InShortId);
  2064. Promise.EmplaceValue();
  2065. }
  2066. else
  2067. {
  2068. ExecutionQueue.Async(WWISERESOURCELOADER_ASYNC_NAME("FWwiseResourceLoaderImpl::AddLoadSoundBankFutures EmplaceValue"), [&SoundBank, &LoadedSoundBanks, Promise = MoveTemp(Promise), InType, InDebugName, InShortId]() mutable
  2069. {
  2070. UE_LOG(LogWwiseResourceLoader, VeryVerbose, TEXT("AddLoadSoundBankFutures: Adding SoundBank %s (%" PRIu32 ") to %s %s (%" PRIu32 ")"),
  2071. *SoundBank.DebugName.ToString(), (uint32)SoundBank.SoundBankId,
  2072. InType, *InDebugName, (uint32)InShortId);
  2073. LoadedSoundBanks.Add(&SoundBank);
  2074. Promise.EmplaceValue();
  2075. });
  2076. }
  2077. });
  2078. }
  2079. }
  2080. void FWwiseResourceLoaderImpl::AddUnloadSoundBankFutures(FCompletionFutureArray& FutureArray,
  2081. TArray<const FWwiseSoundBankCookedData*>& LoadedSoundBanks,
  2082. const TCHAR* InType, const FString& InDebugName, uint32 InShortId) const
  2083. {
  2084. if (LoadedSoundBanks.Num() == 0) return;
  2085. const auto ToUnload(MoveTemp(LoadedSoundBanks));
  2086. LoadedSoundBanks.Empty();
  2087. UE_LOG(LogWwiseResourceLoader, VeryVerbose, TEXT("AddUnloadSoundBankFutures: Unloading all %d SoundBanks from %s %s (%" PRIu32 ")"),
  2088. (int)ToUnload.Num(),
  2089. InType, *InDebugName, (uint32)InShortId);
  2090. for (const auto* SoundBank : ToUnload)
  2091. {
  2092. TWwisePromise<void> Promise;
  2093. FutureArray.Add(Promise.GetFuture());
  2094. UnloadSoundBankFile(*SoundBank, [Promise = MoveTemp(Promise)]() mutable
  2095. {
  2096. Promise.EmplaceValue();
  2097. });
  2098. }
  2099. }
  2100. void FWwiseResourceLoaderImpl::WaitForFutures(FCompletionFutureArray&& FutureArray, FCompletionCallback&& Callback, int NextId) const
  2101. {
  2102. {
  2103. SCOPED_WWISERESOURCELOADER_EVENT_4(TEXT("FWwiseResourceLoaderImpl::WaitForFutures"));
  2104. while (FutureArray.Num() > NextId)
  2105. {
  2106. auto Future = MoveTemp(FutureArray[NextId]);
  2107. if (Future.IsReady())
  2108. {
  2109. ++NextId;
  2110. }
  2111. else
  2112. {
  2113. Future.Next([this, FutureArray = MoveTemp(FutureArray), Callback = MoveTemp(Callback), NextId = NextId + 1](int) mutable
  2114. {
  2115. WaitForFutures(MoveTemp(FutureArray), MoveTemp(Callback), NextId);
  2116. });
  2117. return;
  2118. }
  2119. }
  2120. }
  2121. return Callback();
  2122. }
  2123. void FWwiseResourceLoaderImpl::LoadSoundBankFile(const FWwiseSoundBankCookedData& InSoundBank, FLoadFileCallback&& InCallback) const
  2124. {
  2125. UE_LOG(LogWwiseResourceLoader, VeryVerbose, TEXT("[LoadSoundBankAsync: %" PRIu32 "] %s at %s"),
  2126. (uint32)InSoundBank.SoundBankId, *InSoundBank.DebugName.ToString(), *InSoundBank.SoundBankPathName.ToString());
  2127. if (UNLIKELY(!SoundBankManager))
  2128. {
  2129. SoundBankManager = IWwiseSoundBankManager::Get();
  2130. if (UNLIKELY(!SoundBankManager))
  2131. {
  2132. UE_LOG(LogWwiseResourceLoader, Error, TEXT("Failed to retrieve SoundBank Manager"));
  2133. InCallback(false);
  2134. return;
  2135. }
  2136. }
  2137. SoundBankManager->LoadSoundBank(InSoundBank, GetUnrealPath(), [&InSoundBank, InCallback = MoveTemp(InCallback)](bool bInResult)
  2138. {
  2139. UE_LOG(LogWwiseResourceLoader, VeryVerbose, TEXT("[LoadSoundBankAsync: %" PRIu32 "] %s: Done."),
  2140. (uint32)InSoundBank.SoundBankId, *InSoundBank.DebugName.ToString());
  2141. InCallback(bInResult);
  2142. });
  2143. }
  2144. void FWwiseResourceLoaderImpl::UnloadSoundBankFile(const FWwiseSoundBankCookedData& InSoundBank, FUnloadFileCallback&& InCallback) const
  2145. {
  2146. auto Path = GetUnrealPath(InSoundBank.SoundBankPathName);
  2147. UE_LOG(LogWwiseResourceLoader, VeryVerbose, TEXT("[UnloadSoundBankAsync: %" PRIu32 "] %s at %s"),
  2148. (uint32)InSoundBank.SoundBankId, *InSoundBank.DebugName.ToString(), *InSoundBank.SoundBankPathName.ToString());
  2149. if (UNLIKELY(!SoundBankManager))
  2150. {
  2151. UE_CLOG(!IsEngineExitRequested(), LogWwiseResourceLoader, Error, TEXT("Failed to retrieve SoundBank Manager"));
  2152. InCallback();
  2153. return;
  2154. }
  2155. SoundBankManager->UnloadSoundBank(InSoundBank, GetUnrealPath(), [&InSoundBank, InCallback = MoveTemp(InCallback)]()
  2156. {
  2157. UE_LOG(LogWwiseResourceLoader, VeryVerbose, TEXT("[UnloadSoundBankAsync: %" PRIu32 "] %s: Done."),
  2158. (uint32)InSoundBank.SoundBankId, *InSoundBank.DebugName.ToString());
  2159. InCallback();
  2160. });
  2161. }
  2162. void FWwiseResourceLoaderImpl::LoadMediaFile(const FWwiseMediaCookedData& InMedia, FLoadFileCallback&& InCallback) const
  2163. {
  2164. auto Path = GetUnrealPath(InMedia.MediaPathName);
  2165. UE_LOG(LogWwiseResourceLoader, VeryVerbose, TEXT("[LoadMediaAsync: %" PRIu32 "] %s at %s"),
  2166. (uint32)InMedia.MediaId, *InMedia.DebugName.ToString(), *InMedia.MediaPathName.ToString());
  2167. if (UNLIKELY(!MediaManager))
  2168. {
  2169. MediaManager = IWwiseMediaManager::Get();
  2170. if (UNLIKELY(!MediaManager))
  2171. {
  2172. UE_LOG(LogWwiseResourceLoader, Error, TEXT("Failed to retrieve Media Manager"));
  2173. InCallback(false);
  2174. return;
  2175. }
  2176. }
  2177. MediaManager->LoadMedia(InMedia, GetUnrealPath(), [&InMedia, InCallback = MoveTemp(InCallback)](bool bInResult)
  2178. {
  2179. UE_LOG(LogWwiseResourceLoader, VeryVerbose, TEXT("[LoadMediaAsync: %" PRIu32 "] %s: Done."),
  2180. (uint32)InMedia.MediaId, *InMedia.DebugName.ToString());
  2181. InCallback(bInResult);
  2182. });
  2183. }
  2184. void FWwiseResourceLoaderImpl::UnloadMediaFile(const FWwiseMediaCookedData& InMedia, FUnloadFileCallback&& InCallback) const
  2185. {
  2186. auto Path = GetUnrealPath(InMedia.MediaPathName);
  2187. UE_LOG(LogWwiseResourceLoader, VeryVerbose, TEXT("[UnloadMediaAsync: %" PRIu32 "] %s at %s"),
  2188. (uint32)InMedia.MediaId, *InMedia.DebugName.ToString(), *InMedia.MediaPathName.ToString());
  2189. if (UNLIKELY(!MediaManager))
  2190. {
  2191. UE_CLOG(!IsEngineExitRequested(), LogWwiseResourceLoader, Error, TEXT("Failed to retrieve Media Manager"));
  2192. InCallback();
  2193. return;
  2194. }
  2195. MediaManager->UnloadMedia(InMedia, GetUnrealPath(), [&InMedia, InCallback = MoveTemp(InCallback)]()
  2196. {
  2197. UE_LOG(LogWwiseResourceLoader, VeryVerbose, TEXT("[UnloadMediaAsync: %" PRIu32 "] %s: Done."),
  2198. (uint32)InMedia.MediaId, *InMedia.DebugName.ToString());
  2199. InCallback();
  2200. });
  2201. }
  2202. void FWwiseResourceLoaderImpl::LoadExternalSourceFile(const FWwiseExternalSourceCookedData& InExternalSource, FLoadFileCallback&& InCallback) const
  2203. {
  2204. UE_LOG(LogWwiseResourceLoader, VeryVerbose, TEXT("[LoadExternalSourceAsync: %" PRIu32 "] %s"),
  2205. (uint32)InExternalSource.Cookie, *InExternalSource.DebugName.ToString());
  2206. if (UNLIKELY(!ExternalSourceManager))
  2207. {
  2208. ExternalSourceManager = IWwiseExternalSourceManager::Get();
  2209. if (UNLIKELY(!ExternalSourceManager))
  2210. {
  2211. UE_LOG(LogWwiseResourceLoader, Error, TEXT("Failed to retrieve External Source Manager"));
  2212. InCallback(false);
  2213. return;
  2214. }
  2215. }
  2216. ExternalSourceManager->LoadExternalSource(InExternalSource, GetUnrealExternalSourcePath(), CurrentLanguage, [&InExternalSource, InCallback = MoveTemp(InCallback)](bool bInResult)
  2217. {
  2218. UE_LOG(LogWwiseResourceLoader, VeryVerbose, TEXT("[LoadExternalSourceAsync: %" PRIu32 "] %s: Done."),
  2219. (uint32)InExternalSource.Cookie, *InExternalSource.DebugName.ToString());
  2220. InCallback(bInResult);
  2221. });
  2222. }
  2223. void FWwiseResourceLoaderImpl::UnloadExternalSourceFile(const FWwiseExternalSourceCookedData& InExternalSource, FUnloadFileCallback&& InCallback) const
  2224. {
  2225. UE_LOG(LogWwiseResourceLoader, VeryVerbose, TEXT("[UnloadExternalSourceAsync: %" PRIu32 "] %s"),
  2226. (uint32)InExternalSource.Cookie, *InExternalSource.DebugName.ToString());
  2227. if (UNLIKELY(!ExternalSourceManager))
  2228. {
  2229. UE_CLOG(!IsEngineExitRequested(), LogWwiseResourceLoader, Error, TEXT("Failed to retrieve External Source Manager"));
  2230. InCallback();
  2231. return;
  2232. }
  2233. ExternalSourceManager->UnloadExternalSource(InExternalSource, GetUnrealExternalSourcePath(), CurrentLanguage, [&InExternalSource, InCallback = MoveTemp(InCallback)]()
  2234. {
  2235. UE_LOG(LogWwiseResourceLoader, VeryVerbose, TEXT("[UnloadExternalSourceAsync: %" PRIu32 "] %s: Done."),
  2236. (uint32)InExternalSource.Cookie, *InExternalSource.DebugName.ToString());
  2237. InCallback();
  2238. });
  2239. }