WwiseProjectDatabaseSource.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653
  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 "WwiseProjectDatabaseSource.h"
  16. #include "IAudiokineticTools.h"
  17. #include "AssetManagement/AkAssetDatabase.h"
  18. #include "Async/Async.h"
  19. #include "WaapiPicker/WwiseTreeItem.h"
  20. #include "Wwise/WwiseProjectDatabase.h"
  21. #include "Wwise/WwiseProjectDatabaseDelegates.h"
  22. #include "Wwise/Metadata/WwiseMetadataProjectInfo.h"
  23. FWwiseProjectDatabaseDataSource::~FWwiseProjectDatabaseDataSource()
  24. {
  25. if (OnDatabaseUpdateCompleteHandle.IsValid())
  26. {
  27. FWwiseProjectDatabaseDelegates::Get()->GetOnDatabaseUpdateCompletedDelegate().Remove(OnDatabaseUpdateCompleteHandle);
  28. OnDatabaseUpdateCompleteHandle.Reset();
  29. }
  30. }
  31. FText FWwiseProjectDatabaseDataSource::GetProjectName()
  32. {
  33. auto* ProjectDatabase = FWwiseProjectDatabase::Get();
  34. if (UNLIKELY(!ProjectDatabase))
  35. {
  36. return {};
  37. }
  38. const FWwiseDataStructureScopeLock DataStructure(*ProjectDatabase);
  39. const FWwiseRefPlatform Platform = DataStructure.GetPlatform(ProjectDatabase->GetCurrentPlatform());
  40. if (Platform.IsValid())
  41. {
  42. if (const FWwiseMetadataProjectInfo* ProjectInfo = Platform.ProjectInfo.GetProjectInfo())
  43. {
  44. return FText::FromName(ProjectInfo->Project.Name);
  45. }
  46. }
  47. return {};
  48. }
  49. bool FWwiseProjectDatabaseDataSource::Init()
  50. {
  51. OnDatabaseUpdateCompleteHandle = FWwiseProjectDatabaseDelegates::Get()->GetOnDatabaseUpdateCompletedDelegate().AddLambda([this]
  52. {
  53. AsyncTask(ENamedThreads::Type::GameThread, [this]
  54. {
  55. this->ConstructTree(true);
  56. });
  57. });
  58. return true;
  59. }
  60. void FWwiseProjectDatabaseDataSource::ConstructTree(bool bShouldRefresh)
  61. {
  62. UE_LOG(LogAudiokineticTools, Log, TEXT("Rebuilding tree for Wwise Browser"));
  63. FWwiseProjectDatabase* ProjectDatabase = FWwiseProjectDatabase::Get();
  64. if (UNLIKELY(!ProjectDatabase))
  65. {
  66. UE_LOG(LogAudiokineticTools, Error, TEXT("ConstructTree: ProjectDatabase not loaded"));
  67. return;
  68. }
  69. AllValidTreeItemsByGuid.Empty();
  70. {
  71. FScopeLock AutoLock(&RootItemsLock);
  72. RootItems.Empty();
  73. RootItems.SetNum(EWwiseItemType::LastWwiseBrowserType + 1);
  74. }
  75. NodesByPath.Empty();
  76. {
  77. const FWwiseDataStructureScopeLock DataStructure(*ProjectDatabase);
  78. if (DataStructure.GetCurrentPlatformData() == nullptr)
  79. {
  80. return;
  81. }
  82. const WwiseEventGlobalIdsMap& Events = DataStructure.GetEvents();
  83. const WwiseBusGlobalIdsMap& Busses = DataStructure.GetBusses();
  84. const WwiseAuxBusGlobalIdsMap& AuxBusses = DataStructure.GetAuxBusses();
  85. const WwiseAcousticTextureGlobalIdsMap& AcousticTextures = DataStructure.GetAcousticTextures();
  86. const WwiseStateGroupGlobalIdsMap& StateGroups = DataStructure.GetStateGroups();
  87. const WwiseStateGlobalIdsMap& States = DataStructure.GetStates();
  88. const WwiseSwitchGlobalIdsMap& Switches = DataStructure.GetSwitches();
  89. const WwiseGameParameterGlobalIdsMap& GameParameters = DataStructure.GetGameParameters();
  90. const WwiseTriggerGlobalIdsMap& Triggers = DataStructure.GetTriggers();
  91. const WwisePluginShareSetGlobalIdsMap& EffectShareSets = DataStructure.GetPluginShareSets();
  92. const WwiseSwitchGroupGlobalIdsMap SwitchGroups = DataStructure.GetSwitchGroups();
  93. BuildEvents(Events);
  94. BuildBusses(Busses);
  95. BuildAuxBusses(AuxBusses);
  96. BuildAcousticTextures(AcousticTextures);
  97. BuildStateGroups(StateGroups);
  98. BuildStates(States);
  99. BuildSwitchGroups(SwitchGroups);
  100. BuildSwitches(Switches);
  101. BuildGameParameters(GameParameters);
  102. BuildTriggers(Triggers);
  103. BuildEffectShareSets(EffectShareSets);
  104. }
  105. if(bShouldRefresh)
  106. {
  107. ProjectDatabaseDataSourceRefreshed.ExecuteIfBound();
  108. }
  109. }
  110. FWwiseTreeItemPtr FWwiseProjectDatabaseDataSource::ConstructTreeRoot(EWwiseItemType::Type Type)
  111. {
  112. ConstructTree(false);
  113. {
  114. FScopeLock AutoLock(&RootItemsLock);
  115. return RootItems[Type];
  116. }
  117. }
  118. int32 FWwiseProjectDatabaseDataSource::LoadChildren(
  119. const FGuid& InParentId, const FString& InParentPath, TArray<FWwiseTreeItemPtr>& OutChildren)
  120. {
  121. FWwiseTreeItemPtr* TreeItem = NodesByPath.Find(InParentPath);
  122. if (TreeItem && TreeItem->IsValid())
  123. {
  124. OutChildren = TreeItem->Get()->GetChildren();
  125. }
  126. else
  127. {
  128. OutChildren = {};
  129. }
  130. return OutChildren.Num();
  131. }
  132. int32 FWwiseProjectDatabaseDataSource::LoadChildren(FWwiseTreeItemPtr InParentItem)
  133. {
  134. if (!InParentItem)
  135. {
  136. return 0;
  137. }
  138. // For now, we have to construct the whole tree at once, so this can't be individually loaded. So we return what we have.
  139. return InParentItem->GetChildren().Num();
  140. }
  141. int32 FWwiseProjectDatabaseDataSource::GetChildItemCount(const FWwiseTreeItemPtr& InParentItem)
  142. {
  143. return InParentItem->GetChildren().Num();
  144. }
  145. FWwiseTreeItemPtr FWwiseProjectDatabaseDataSource::GetRootItem(EWwiseItemType::Type RootType)
  146. {
  147. check(RootType <= EWwiseItemType::LastWwiseBrowserType)
  148. if (RootType > RootItems.Num() - 1)
  149. {
  150. UE_LOG(LogAudiokineticTools, Error, TEXT("Failed to get the Project Database Root Items. Index out of range."));
  151. return nullptr;
  152. }
  153. return RootItems[RootType];
  154. }
  155. FWwiseTreeItemPtr FWwiseProjectDatabaseDataSource::LoadFilteredRootItem(EWwiseItemType::Type ItemType,
  156. TSharedPtr<StringFilter> CurrentFilter)
  157. {
  158. check(CurrentFilter.IsValid())
  159. FWwiseTreeItemPtr CurrentTreeRootItem;
  160. {
  161. FScopeLock AutoLock(&RootItemsLock);
  162. if (ItemType > RootItems.Num())
  163. {
  164. UE_LOG(LogAudiokineticTools, Error, TEXT("Failed to get the Project Database Root Items. Index out of range."));
  165. return nullptr;
  166. }
  167. CurrentTreeRootItem = RootItems[ItemType];
  168. FString CurrentFilterText = CurrentFilter->GetRawFilterText().ToString();
  169. if (!CurrentFilterText.IsEmpty() && CurrentTreeRootItem.IsValid())
  170. {
  171. FWwiseTreeItemPtr FilteredTreeRootItem = MakeShared<FWwiseTreeItem>(EWwiseItemType::BrowserDisplayNames[ItemType],
  172. CurrentTreeRootItem->FolderPath, nullptr, EWwiseItemType::Folder, FGuid(CurrentTreeRootItem->ItemId));
  173. FilteredTreeRootItem->ChildCountInWwise = CurrentTreeRootItem->ChildCountInWwise;
  174. if (!OldFilterText.IsEmpty() && CurrentFilterText.StartsWith(OldFilterText))
  175. {
  176. CopyTree(CurrentTreeRootItem, FilteredTreeRootItem);
  177. }
  178. else
  179. {
  180. CopyTree(RootItems[ItemType], FilteredTreeRootItem);
  181. }
  182. FilterTree(FilteredTreeRootItem, CurrentFilter);
  183. OldFilterText = CurrentFilterText;
  184. return FilteredTreeRootItem;
  185. }
  186. if (RootItems[ItemType])
  187. {
  188. return RootItems[ItemType];
  189. }
  190. return nullptr;
  191. }
  192. }
  193. FWwiseTreeItemPtr FWwiseProjectDatabaseDataSource::FindItemFromPath(const FString& InCurrentItemPath)
  194. {
  195. FWwiseTreeItemPtr* FoundItem = NodesByPath.Find(InCurrentItemPath);
  196. if (FoundItem)
  197. {
  198. return *FoundItem;
  199. }
  200. return nullptr;
  201. }
  202. FWwiseTreeItemPtr FWwiseProjectDatabaseDataSource::FindItem(const FWwiseTreeItemPtr InItem)
  203. {
  204. FWwiseTreeItemPtr* FoundItem = AllValidTreeItemsByGuid.Find(InItem->ItemId);
  205. if (FoundItem)
  206. {
  207. return *FoundItem;
  208. }
  209. for(auto TreeItem : AllValidTreeItemsByGuid)
  210. {
  211. if (TreeItem.Value->ShortId == InItem->ShortId && InItem->ShortId > 0)
  212. {
  213. return TreeItem.Value;
  214. }
  215. if(TreeItem.Value->DisplayName == InItem->DisplayName)
  216. {
  217. return TreeItem.Value;
  218. }
  219. }
  220. return nullptr;
  221. }
  222. void FWwiseProjectDatabaseDataSource::BuildEvents(const WwiseEventGlobalIdsMap& Events)
  223. {
  224. const auto& FolderItem = MakeShared<FWwiseTreeItem>(EWwiseItemType::EventsBrowserName, TEXT("\\") + EWwiseItemType::FolderNames[EWwiseItemType::Event], nullptr, EWwiseItemType::Folder, FGuid());
  225. NodesByPath.Add(FolderItem->FolderPath, FolderItem);
  226. {
  227. FScopeLock AutoLock(&RootItemsLock);
  228. RootItems[EWwiseItemType::Event] = FolderItem;
  229. }
  230. for (const auto& Event : Events)
  231. {
  232. const auto& WwiseItem = Event.Value.GetEvent();
  233. UE_LOG(LogAudiokineticTools, VeryVerbose, TEXT("Event Name: %s"), *WwiseItem->Name.ToString());
  234. FWwiseMetadataBasicReference EventRef = FWwiseMetadataBasicReference(WwiseItem->Id, WwiseItem->Name, WwiseItem->ObjectPath, WwiseItem->GUID);
  235. if (!BuildFolderHierarchy(EventRef, EWwiseItemType::Event, FolderItem))
  236. {
  237. UE_LOG(LogAudiokineticTools, Error, TEXT("Failed to place %s in the Wwise Browser"), *WwiseItem->ObjectPath.ToString());
  238. }
  239. }
  240. FolderItem->ChildCountInWwise = FolderItem->GetChildren().Num();
  241. }
  242. void FWwiseProjectDatabaseDataSource::BuildBusses(const WwiseBusGlobalIdsMap& Busses)
  243. {
  244. const auto& FolderItem = MakeShared<FWwiseTreeItem>(EWwiseItemType::BussesBrowserName, TEXT("\\") + EWwiseItemType::FolderNames[EWwiseItemType::AuxBus], nullptr, EWwiseItemType::Folder, FGuid());
  245. NodesByPath.Add(FolderItem->FolderPath, FolderItem);
  246. {
  247. FScopeLock AutoLock(&RootItemsLock);
  248. RootItems[EWwiseItemType::AuxBus] = FolderItem;
  249. }
  250. for (auto& Bus : Busses)
  251. {
  252. const auto& WwiseItem = Bus.Value.GetBus();
  253. UE_LOG(LogAudiokineticTools, VeryVerbose, TEXT("Bus Name: %s"), *WwiseItem->Name.ToString());
  254. if (!BuildFolderHierarchy(*WwiseItem, EWwiseItemType::Bus, FolderItem))
  255. {
  256. UE_LOG(LogAudiokineticTools, Error, TEXT("Failed to place %s in the Wwise Browser"), *WwiseItem->ObjectPath.ToString());
  257. }
  258. }
  259. FolderItem->ChildCountInWwise = FolderItem->GetChildren().Num();
  260. }
  261. void FWwiseProjectDatabaseDataSource::BuildAuxBusses(const WwiseAuxBusGlobalIdsMap& AuxBusses)
  262. {
  263. FWwiseTreeItemPtr FolderItem;
  264. {
  265. FScopeLock AutoLock(&RootItemsLock);
  266. FolderItem = RootItems[EWwiseItemType::AuxBus];
  267. }
  268. for (const auto& AuxBus : AuxBusses)
  269. {
  270. const auto& WwiseItem = AuxBus.Value.GetAuxBus();
  271. UE_LOG(LogAudiokineticTools, VeryVerbose, TEXT("Aux Bus Name: %s"), *WwiseItem->Name.ToString());
  272. if (!BuildFolderHierarchy(*WwiseItem, EWwiseItemType::AuxBus, FolderItem))
  273. {
  274. UE_LOG(LogAudiokineticTools, Error, TEXT("Failed to place %s in the Wwise Browser"), *WwiseItem->ObjectPath.ToString());
  275. }
  276. }
  277. }
  278. void FWwiseProjectDatabaseDataSource::BuildAcousticTextures(const WwiseAcousticTextureGlobalIdsMap& AcousticTextures)
  279. {
  280. const auto& FolderItem = MakeShared<FWwiseTreeItem>(EWwiseItemType::AcousticTexturesBrowserName, TEXT("\\") + EWwiseItemType::FolderNames[EWwiseItemType::AcousticTexture], nullptr, EWwiseItemType::Folder, FGuid());
  281. NodesByPath.Add(FolderItem->FolderPath, FolderItem);
  282. {
  283. FScopeLock AutoLock(&RootItemsLock);
  284. RootItems[EWwiseItemType::AcousticTexture] = FolderItem;
  285. }
  286. for (const auto& AcousticTexture : AcousticTextures)
  287. {
  288. const FWwiseMetadataAcousticTexture* WwiseItem = AcousticTexture.Value.GetAcousticTexture();
  289. UE_LOG(LogAudiokineticTools, VeryVerbose, TEXT("Acoustic Texture Name: %s"), *WwiseItem->Name.ToString());
  290. if (!BuildFolderHierarchy(*WwiseItem, EWwiseItemType::AcousticTexture, FolderItem))
  291. {
  292. UE_LOG(LogAudiokineticTools, Error, TEXT("Failed to place %s in the Wwise Browser"), *WwiseItem->ObjectPath.ToString());
  293. }
  294. }
  295. FolderItem->ChildCountInWwise = FolderItem->GetChildren().Num();
  296. }
  297. void FWwiseProjectDatabaseDataSource::BuildStateGroups(const WwiseStateGroupGlobalIdsMap& StateGroups)
  298. {
  299. const auto& FolderItem = MakeShared<FWwiseTreeItem>(EWwiseItemType::StatesBrowserName, TEXT("\\") + EWwiseItemType::FolderNames[EWwiseItemType::State], nullptr, EWwiseItemType::Folder, FGuid());
  300. NodesByPath.Add(FolderItem->FolderPath, FolderItem);
  301. {
  302. FScopeLock AutoLock(&RootItemsLock);
  303. RootItems[EWwiseItemType::State] = FolderItem;
  304. }
  305. for (const auto& StateGroup : StateGroups)
  306. {
  307. const auto& WwiseItem = StateGroup.Value.GetStateGroup();
  308. UE_LOG(LogAudiokineticTools, VeryVerbose, TEXT("State Group Name: %s"), *WwiseItem->Name.ToString());
  309. if (!BuildFolderHierarchy(*WwiseItem, EWwiseItemType::StateGroup, FolderItem))
  310. {
  311. UE_LOG(LogAudiokineticTools, Error, TEXT("Failed to place %s in the Wwise Browser"), *WwiseItem->ObjectPath.ToString());
  312. }
  313. }
  314. FolderItem->ChildCountInWwise = FolderItem->GetChildren().Num();
  315. }
  316. void FWwiseProjectDatabaseDataSource::BuildStates(const WwiseStateGlobalIdsMap& States)
  317. {
  318. FWwiseTreeItemPtr StateGroupFolderItem;
  319. {
  320. FScopeLock AutoLock(&RootItemsLock);
  321. StateGroupFolderItem = RootItems[EWwiseItemType::State];
  322. }
  323. for (const auto& State : States)
  324. {
  325. const auto& WwiseItem = State.Value.GetState();
  326. if (!BuildFolderHierarchy(*WwiseItem, EWwiseItemType::State, StateGroupFolderItem))
  327. {
  328. UE_LOG(LogAudiokineticTools, Error, TEXT("Failed to place %s in the Wwise Browser"), *WwiseItem->ObjectPath.ToString());
  329. }
  330. }
  331. }
  332. void FWwiseProjectDatabaseDataSource::BuildSwitchGroups(const WwiseSwitchGroupGlobalIdsMap& SwitchGroups)
  333. {
  334. const auto& FolderItem = MakeShared<FWwiseTreeItem>(EWwiseItemType::SwitchesBrowserName, TEXT("\\") + EWwiseItemType::FolderNames[EWwiseItemType::Switch], nullptr, EWwiseItemType::Folder, FGuid());
  335. NodesByPath.Add(FolderItem->FolderPath, FolderItem);
  336. {
  337. FScopeLock AutoLock(&RootItemsLock);
  338. RootItems[EWwiseItemType::Switch] = FolderItem;
  339. }
  340. for (const auto& SwitchGroup : SwitchGroups)
  341. {
  342. const auto& WwiseItem = SwitchGroup.Value.GetSwitchGroup();
  343. UE_LOG(LogAudiokineticTools, VeryVerbose, TEXT("Switch Group Name: %s"), *WwiseItem->Name.ToString());
  344. if (!BuildFolderHierarchy(*WwiseItem, EWwiseItemType::SwitchGroup, FolderItem))
  345. {
  346. UE_LOG(LogAudiokineticTools, Error, TEXT("Failed to place %s in the Wwise Browser"), *WwiseItem->ObjectPath.ToString());
  347. }
  348. }
  349. FolderItem->ChildCountInWwise = FolderItem->GetChildren().Num();
  350. }
  351. void FWwiseProjectDatabaseDataSource::BuildSwitches(const WwiseSwitchGlobalIdsMap& Switches)
  352. {
  353. FWwiseTreeItemPtr SwitchGroupFolderItem;
  354. {
  355. FScopeLock AutoLock(&RootItemsLock);
  356. SwitchGroupFolderItem = RootItems[EWwiseItemType::Switch];
  357. }
  358. for (const auto& Switch : Switches)
  359. {
  360. const auto& WwiseItem = Switch.Value.GetSwitch();
  361. if (!BuildFolderHierarchy(*WwiseItem, EWwiseItemType::Switch, SwitchGroupFolderItem))
  362. {
  363. UE_LOG(LogAudiokineticTools, Error, TEXT("Failed to place %s in the Wwise Browser"), *WwiseItem->ObjectPath.ToString());
  364. }
  365. }
  366. }
  367. void FWwiseProjectDatabaseDataSource::BuildGameParameters(const WwiseGameParameterGlobalIdsMap& GameParameters)
  368. {
  369. const auto& FolderItem = MakeShared<FWwiseTreeItem>(EWwiseItemType::GameParametersBrowserName, TEXT("\\") + EWwiseItemType::FolderNames[EWwiseItemType::GameParameter], nullptr, EWwiseItemType::Folder, FGuid());
  370. NodesByPath.Add(FolderItem->FolderPath, FolderItem);
  371. {
  372. FScopeLock AutoLock(&RootItemsLock);
  373. RootItems[EWwiseItemType::GameParameter] = FolderItem;
  374. }
  375. for (const auto& GameParameter : GameParameters)
  376. {
  377. const FWwiseMetadataGameParameter* WwiseItem = GameParameter.Value.GetGameParameter();
  378. UE_LOG(LogAudiokineticTools, VeryVerbose, TEXT("GameParameter Name: %s"), *WwiseItem->Name.ToString());
  379. if (!BuildFolderHierarchy(*WwiseItem, EWwiseItemType::GameParameter, FolderItem))
  380. {
  381. UE_LOG(LogAudiokineticTools, Error, TEXT("Failed to place %s in the Wwise Browser"), *WwiseItem->ObjectPath.ToString());
  382. }
  383. }
  384. FolderItem->ChildCountInWwise = FolderItem->GetChildren().Num();
  385. }
  386. void FWwiseProjectDatabaseDataSource::BuildTriggers(const WwiseTriggerGlobalIdsMap& Triggers)
  387. {
  388. const auto& FolderItem = MakeShared<FWwiseTreeItem>(EWwiseItemType::TriggersBrowserName, TEXT("\\") + EWwiseItemType::FolderNames[EWwiseItemType::Trigger], nullptr, EWwiseItemType::Folder, FGuid());
  389. NodesByPath.Add(FolderItem->FolderPath, FolderItem);
  390. {
  391. FScopeLock AutoLock(&RootItemsLock);
  392. RootItems[EWwiseItemType::Trigger] = FolderItem;
  393. }
  394. for (const auto& Trigger : Triggers)
  395. {
  396. const auto& WwiseItem = Trigger.Value.GetTrigger();
  397. UE_LOG(LogAudiokineticTools, VeryVerbose, TEXT("Trigger Name: %s"), *WwiseItem->Name.ToString());
  398. if (!BuildFolderHierarchy(*WwiseItem, EWwiseItemType::Trigger, FolderItem))
  399. {
  400. UE_LOG(LogAudiokineticTools, Error, TEXT("Failed to place %s in the Wwise Browser"), *WwiseItem->ObjectPath.ToString());
  401. }
  402. }
  403. FolderItem->ChildCountInWwise = FolderItem->GetChildren().Num();
  404. }
  405. void FWwiseProjectDatabaseDataSource::BuildEffectShareSets(const WwisePluginShareSetGlobalIdsMap& EffectShareSets)
  406. {
  407. const auto& FolderItem = MakeShared<FWwiseTreeItem>(EWwiseItemType::ShareSetsBrowserName, TEXT("\\") + EWwiseItemType::FolderNames[EWwiseItemType::EffectShareSet], nullptr, EWwiseItemType::Folder, FGuid());
  408. NodesByPath.Add(FolderItem->FolderPath, FolderItem);
  409. {
  410. FScopeLock AutoLock(&RootItemsLock);
  411. RootItems[EWwiseItemType::EffectShareSet] = FolderItem;
  412. }
  413. for (const auto& EffectShareSet : EffectShareSets)
  414. {
  415. const auto& WwiseItem = EffectShareSet.Value.GetPlugin();
  416. UE_LOG(LogAudiokineticTools, VeryVerbose, TEXT("ShareSet Name: %s"), *WwiseItem->Name.ToString());
  417. if (!BuildFolderHierarchy(*WwiseItem, EWwiseItemType::EffectShareSet, FolderItem))
  418. {
  419. UE_LOG(LogAudiokineticTools, Error, TEXT("Failed to place %s in the Wwise Browser"), *WwiseItem->ObjectPath.ToString());
  420. }
  421. }
  422. FolderItem->ChildCountInWwise = FolderItem->GetChildren().Num();
  423. }
  424. bool FWwiseProjectDatabaseDataSource::ParseTreePath(const FString& ObjectPath, WwiseItemTreePath& OutItemPath)
  425. {
  426. TArray<FString> SwitchPartsArray;
  427. ObjectPath.ParseIntoArray(SwitchPartsArray, TEXT("\\"));
  428. if (SwitchPartsArray.Num() < 3)
  429. {
  430. UE_LOG(LogAudiokineticTools, Warning, TEXT("Failed to determine object hierarchy from path: %s"), *ObjectPath);
  431. return false;
  432. }
  433. OutItemPath.HierarchyName = SwitchPartsArray[0];
  434. OutItemPath.RootFolder = SwitchPartsArray[1];
  435. OutItemPath.ItemName = SwitchPartsArray[SwitchPartsArray.Num() - 1];
  436. for (int i = 2; i < SwitchPartsArray.Num() - 1; ++i)
  437. {
  438. OutItemPath.IntermediateFolders.Add(SwitchPartsArray[i]);
  439. }
  440. return true;
  441. }
  442. bool FWwiseProjectDatabaseDataSource::IsContainer(EWwiseItemType::Type ItemType) const
  443. {
  444. return ItemType == EWwiseItemType::Bus || ItemType == EWwiseItemType::SwitchGroup || ItemType ==
  445. EWwiseItemType::StateGroup || ItemType == EWwiseItemType::AuxBus || ItemType == EWwiseItemType::MotionBus;
  446. }
  447. bool FWwiseProjectDatabaseDataSource::BuildFolderHierarchy(
  448. const FWwiseMetadataBasicReference& WwiseItem, EWwiseItemType::Type
  449. ItemType, const FWwiseTreeItemPtr CurrentRootFolder)
  450. {
  451. const FString ItemPath = WwiseItem.ObjectPath.ToString();
  452. WwiseItemTreePath TreePath;
  453. FWwiseTreeItemPtr ParentItem = CurrentRootFolder;
  454. if (ParseTreePath(ItemPath, TreePath))
  455. {
  456. FString CurrentPath = "\\" + TreePath.HierarchyName;
  457. TArray<FString> AllFolders = TArray<FString>{ TreePath.RootFolder };
  458. AllFolders.Append(TreePath.IntermediateFolders);
  459. for (FString FolderName : AllFolders)
  460. {
  461. CurrentPath.Append("\\").Append(FolderName);
  462. FWwiseTreeItemPtr FolderItem;
  463. FWwiseTreeItemPtr* FolderItemPtr = NodesByPath.Find(CurrentPath);
  464. if (!FolderItemPtr)
  465. {
  466. FolderItem = MakeShared<FWwiseTreeItem>(FolderName, CurrentPath, ParentItem,
  467. EWwiseItemType::Folder, FGuid());
  468. NodesByPath.Add(CurrentPath, FolderItem);
  469. ParentItem->AddChild(FolderItem);
  470. ParentItem->ChildCountInWwise = ParentItem->GetChildren().Num();
  471. }
  472. else
  473. {
  474. FolderItem = *FolderItemPtr;
  475. }
  476. ParentItem = FolderItem;
  477. }
  478. if (!AllValidTreeItemsByGuid.Find(WwiseItem.GUID))
  479. {
  480. if(auto TreeItemPtr = NodesByPath.Find(WwiseItem.ObjectPath.ToString()))
  481. {
  482. auto TreeItem = *TreeItemPtr;
  483. TreeItem->ItemType = ItemType;
  484. TreeItem->ItemId = WwiseItem.GUID;
  485. TreeItem->ShortId = WwiseItem.Id;
  486. }
  487. else
  488. {
  489. const auto& NewWwiseTreeItem = MakeShared<FWwiseTreeItem>(WwiseItem, ParentItem, ItemType);
  490. NewWwiseTreeItem->ShortId = WwiseItem.Id;
  491. ParentItem->AddChild(NewWwiseTreeItem);
  492. AllValidTreeItemsByGuid.Add(NewWwiseTreeItem->ItemId, NewWwiseTreeItem);
  493. if (IsContainer(ItemType))
  494. {
  495. NodesByPath.Add(WwiseItem.ObjectPath.ToString(), NewWwiseTreeItem);
  496. }
  497. }
  498. }
  499. return true;
  500. }
  501. return false;
  502. }
  503. void FWwiseProjectDatabaseDataSource::CopyTree(FWwiseTreeItemPtr SourceTreeItem, FWwiseTreeItemPtr DestTreeItem)
  504. {
  505. for (auto& CurrItem: SourceTreeItem->GetChildren())
  506. {
  507. FWwiseTreeItemPtr NewItem = MakeShared<FWwiseTreeItem>(CurrItem->DisplayName, CurrItem->FolderPath, CurrItem->Parent.Pin(), CurrItem->ItemType, CurrItem->ItemId);
  508. NewItem->WwiseItemRef = CurrItem->WwiseItemRef;
  509. DestTreeItem->AddChild(NewItem);
  510. DestTreeItem->ChildCountInWwise = SourceTreeItem->ChildCountInWwise;
  511. CopyTree(CurrItem, NewItem);
  512. }
  513. }
  514. void FWwiseProjectDatabaseDataSource::FilterTree(FWwiseTreeItemPtr TreeItem, TSharedPtr<StringFilter> SearchFilter)
  515. {
  516. TArray<FWwiseTreeItemPtr> ItemsToRemove;
  517. for (auto& CurrItem: TreeItem->GetChildren())
  518. {
  519. FilterTree(CurrItem, SearchFilter);
  520. if (!SearchFilter->PassesFilter(CurrItem->DisplayName) && CurrItem->GetChildren().Num() == 0)
  521. {
  522. ItemsToRemove.Add(CurrItem);
  523. }
  524. }
  525. for (int32 i = 0; i < ItemsToRemove.Num(); i++)
  526. {
  527. TreeItem->RemoveChild(ItemsToRemove[i]);
  528. }
  529. TreeItem->ChildCountInWwise = TreeItem->GetChildren().Num();
  530. }