AudiokineticToolsModule.cpp 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979
  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. /*=============================================================================
  16. AudiokineticToolsModule.cpp
  17. =============================================================================*/
  18. #include "AudiokineticToolsModule.h"
  19. #include "AudiokineticToolsPrivatePCH.h"
  20. #include "AkAudioBankGenerationHelpers.h"
  21. #include "AkAudioDevice.h"
  22. #include "AkAudioStyle.h"
  23. #include "AkComponent.h"
  24. #include "AkEventAssetBroker.h"
  25. #include "AkGeometryComponent.h"
  26. #include "AkLateReverbComponent.h"
  27. #include "AkRoomComponent.h"
  28. #include "AkSettings.h"
  29. #include "AkSettingsPerUser.h"
  30. #include "AkSurfaceReflectorSetComponent.h"
  31. #include "AkReverbZone.h"
  32. #include "WwiseUnrealDefines.h"
  33. #include "AssetManagement/AkAssetDatabase.h"
  34. #include "AssetManagement/AkAssetMigrationManager.h"
  35. #include "AssetManagement/AkGenerateSoundBanksTask.h"
  36. #include "AssetRegistry/AssetRegistryModule.h"
  37. #include "AssetToolsModule.h"
  38. #include "ComponentAssetBroker.h"
  39. #include "ContentBrowserModule.h"
  40. #include "DetailsCustomization/AkGeometryComponentDetailsCustomization.h"
  41. #include "DetailsCustomization/AkLateReverbComponentDetailsCustomization.h"
  42. #include "DetailsCustomization/AkRoomComponentDetailsCustomization.h"
  43. #include "DetailsCustomization/AkPortalComponentDetailsCustomization.h"
  44. #include "DetailsCustomization/AkSurfaceReflectorSetDetailsCustomization.h"
  45. #include "DetailsCustomization/AkSettingsDetailsCustomization.h"
  46. #include "DetailsCustomization/AkReverbZoneDetailsCustomization.h"
  47. #include "LevelEditor.h"
  48. #include "Editor/UnrealEdEngine.h"
  49. #include "Factories/ActorFactoryAkAmbientSound.h"
  50. #include "Factories/AkAssetTypeActions.h"
  51. #include "Framework/Application/SlateApplication.h"
  52. #if UE_5_0_OR_LATER
  53. #include "HAL/PlatformFileManager.h"
  54. #else
  55. #include "HAL/PlatformFilemanager.h"
  56. #endif
  57. #include "Interfaces/IProjectManager.h"
  58. #include "Internationalization/Culture.h"
  59. #include "Internationalization/Internationalization.h"
  60. #include "ISequencerModule.h"
  61. #include "ISettingsModule.h"
  62. #include "ISettingsSection.h"
  63. #include "IAudiokineticTools.h"
  64. #include "Misc/MessageDialog.h"
  65. #include "Modules/ModuleManager.h"
  66. #include "MovieScene.h"
  67. #include "Platforms/AkUEPlatform.h"
  68. #include "ProjectDescriptor.h"
  69. #include "PropertyEditorModule.h"
  70. #include "Sequencer/MovieSceneAkAudioEventTrackEditor.h"
  71. #include "Sequencer/MovieSceneAkAudioRTPCTrackEditor.h"
  72. #include "Settings/ProjectPackagingSettings.h"
  73. #include "AkUnrealEditorHelper.h"
  74. #include "EditorBuildUtils.h"
  75. #include "UnrealEdGlobals.h"
  76. #include "UnrealEdMisc.h"
  77. #include "Visualizer/AkAcousticPortalVisualizer.h"
  78. #include "Visualizer/AkComponentVisualizer.h"
  79. #include "Visualizer/AkSurfaceReflectorSetComponentVisualizer.h"
  80. #include "WaapiPicker/WwiseTreeItem.h"
  81. #include "Widgets/Docking/SDockTab.h"
  82. #include "Widgets/Input/SButton.h"
  83. #include "Widgets/Input/SCheckBox.h"
  84. #include "Widgets/Input/SHyperlink.h"
  85. #include "Widgets/Layout/SSpacer.h"
  86. #include "WorkspaceMenuStructure.h"
  87. #include "WorkspaceMenuStructureModule.h"
  88. #include "AssetManagement/GeneratedSoundBanksDirectoryWatcher.h"
  89. #include "AssetManagement/WwiseProjectInfo.h"
  90. #include "WwiseProject/AcousticTextureParamLookup.h"
  91. #include "ToolMenu.h"
  92. #include "ToolMenus.h"
  93. #include "Wwise/WwiseProjectDatabase.h"
  94. #include "Wwise/WwiseProjectDatabaseDelegates.h"
  95. #include "AkAudioModule.h"
  96. #include "AssetManagement/StaticPluginWriter.h"
  97. #include "WwiseInitBankLoader/WwiseInitBankLoader.h"
  98. #define LOCTEXT_NAMESPACE "AkAudio"
  99. FAudiokineticToolsModule* FAudiokineticToolsModule::AudiokineticToolsModuleInstance = nullptr;
  100. TSharedRef<SDockTab> FAudiokineticToolsModule::CreateWwiseBrowserTab(const FSpawnTabArgs& SpawnTabArgs)
  101. {
  102. const TSharedRef<SDockTab> BrowserTab =
  103. SNew(SDockTab)
  104. .Label(LOCTEXT("AkAudioWwiseBrowserTabTitle", "Wwise Browser"))
  105. .TabRole(ETabRole::NomadTab)
  106. [
  107. SNew(SWwiseBrowser)
  108. ];
  109. return BrowserTab;
  110. }
  111. void FAudiokineticToolsModule::RefreshWwiseProject()
  112. {
  113. SoundBanksDirectoryWatcher.ConditionalRestartWatchers();
  114. if (auto* ProjectDatabase = FWwiseProjectDatabase::Get())
  115. {
  116. ProjectDatabase->UpdateDataStructure();
  117. }
  118. }
  119. void FAudiokineticToolsModule::OpenOnlineHelp()
  120. {
  121. FPlatformProcess::LaunchFileInDefaultExternalApplication(TEXT("https://www.audiokinetic.com/library/?source=UE4&id=index.html"));
  122. }
  123. void FAudiokineticToolsModule::ToggleVisualizeRoomsAndPortals()
  124. {
  125. UAkSettingsPerUser* AkSettingsPerUser = GetMutableDefault<UAkSettingsPerUser>();
  126. if (AkSettingsPerUser != nullptr)
  127. {
  128. AkSettingsPerUser->ToggleVisualizeRoomsAndPortals();
  129. }
  130. }
  131. bool FAudiokineticToolsModule::IsVisualizeRoomsAndPortalsEnabled()
  132. {
  133. const UAkSettingsPerUser* AkSettingsPerUser = GetDefault<UAkSettingsPerUser>();
  134. if (AkSettingsPerUser == nullptr)
  135. return false;
  136. return AkSettingsPerUser->VisualizeRoomsAndPortals;
  137. }
  138. ECheckBoxState FAudiokineticToolsModule::GetVisualizeRoomsAndPortalsCheckBoxState()
  139. {
  140. return IsVisualizeRoomsAndPortalsEnabled() ? ECheckBoxState::Checked : ECheckBoxState::Unchecked;
  141. }
  142. void FAudiokineticToolsModule::ToggleShowReverbInfo()
  143. {
  144. UAkSettingsPerUser* AkSettingsPerUser = GetMutableDefault<UAkSettingsPerUser>();
  145. if (AkSettingsPerUser != nullptr)
  146. {
  147. AkSettingsPerUser->ToggleShowReverbInfo();
  148. }
  149. }
  150. bool FAudiokineticToolsModule::IsReverbInfoEnabled()
  151. {
  152. const UAkSettingsPerUser* AkSettingsPerUser = GetDefault<UAkSettingsPerUser>();
  153. if (AkSettingsPerUser == nullptr)
  154. return false;
  155. return AkSettingsPerUser->bShowReverbInfo;
  156. }
  157. ECheckBoxState FAudiokineticToolsModule::GetReverbInfoCheckBoxState()
  158. {
  159. return IsReverbInfoEnabled() ? ECheckBoxState::Checked : ECheckBoxState::Unchecked;
  160. }
  161. void FAudiokineticToolsModule::CreateAkViewportCommands()
  162. {
  163. // Extend the viewport menu and add the Audiokinetic commands
  164. {
  165. UToolMenu* ViewportMenu = UToolMenus::Get()->ExtendMenu("LevelEditor.LevelViewportToolBar.Options");
  166. FToolMenuSection& AkSection = ViewportMenu->AddSection("Audiokinetic", LOCTEXT("AkLabel", "Audiokinetic"), FToolMenuInsert("Audiokinetic", EToolMenuInsertType::Default));
  167. ToggleVizRoomsPortalsAction.ExecuteAction.BindStatic(&FAudiokineticToolsModule::ToggleVisualizeRoomsAndPortals);
  168. ToggleVizRoomsPortalsAction.GetActionCheckState.BindStatic(&FAudiokineticToolsModule::GetVisualizeRoomsAndPortalsCheckBoxState);
  169. AkSection.AddMenuEntry(
  170. NAME_None,
  171. LOCTEXT("ToggleVizRoomsAndPortals_Label", "Visualize Rooms And Portals"),
  172. LOCTEXT("ToggleVizRoomsAndPortals_Tip", "Toggles the visualization of rooms and portals in the viewport. This requires 'realtime' to be enabled in the viewport."),
  173. FSlateIcon(),
  174. ToggleVizRoomsPortalsAction,
  175. EUserInterfaceActionType::ToggleButton
  176. );
  177. ToggleReverbInfoAction.ExecuteAction.BindStatic(&FAudiokineticToolsModule::ToggleShowReverbInfo);
  178. ToggleReverbInfoAction.GetActionCheckState.BindStatic(&FAudiokineticToolsModule::GetReverbInfoCheckBoxState);
  179. AkSection.AddMenuEntry(
  180. NAME_None,
  181. LOCTEXT("ToggleReverbInfo_Label", "Show Reverb Info"),
  182. LOCTEXT("ToggleReverbInfo_Tip", "When enabled, information about AkReverbComponents will be displayed in viewports, above the component's UPrimitiveComponent parent. This requires 'realtime' to be enabled in the viewport."),
  183. FSlateIcon(),
  184. ToggleReverbInfoAction,
  185. EUserInterfaceActionType::ToggleButton
  186. );
  187. }
  188. }
  189. void FAudiokineticToolsModule::RegisterWwiseMenus()
  190. {
  191. // Extend the build menu to handle Audiokinetic-specific entries
  192. #if UE_5_0_OR_LATER
  193. {
  194. UToolMenu* BuildMenu = UToolMenus::Get()->ExtendMenu("LevelEditor.MainMenu.Build");
  195. FToolMenuSection& WwiseBuildSection = BuildMenu->AddSection("AkBuild", LOCTEXT("AkBuildLabel", "Audiokinetic"), FToolMenuInsert("LevelEditorGeometry", EToolMenuInsertType::Default));
  196. FUIAction GenerateSoundDataUIAction;
  197. GenerateSoundDataUIAction.ExecuteAction.BindStatic(&AkAudioBankGenerationHelper::CreateGenerateSoundDataWindow, false);
  198. WwiseBuildSection.AddMenuEntry(
  199. NAME_None,
  200. LOCTEXT("AkAudioBank_GenerateSoundBanks", "Generate SoundBanks..."),
  201. LOCTEXT("AkAudioBank_GenerateSoundBanksTooltip", "Generates Wwise SoundBanks."),
  202. FSlateIcon(),
  203. GenerateSoundDataUIAction
  204. );
  205. FUIAction RefreshProjectUIAction;
  206. RefreshProjectUIAction.ExecuteAction.BindRaw(this, &FAudiokineticToolsModule::RefreshWwiseProject);
  207. WwiseBuildSection.AddMenuEntry(
  208. NAME_None,
  209. LOCTEXT("RefreshWwiseProject", "Refresh Project Database"),
  210. LOCTEXT("RefreshWwiseProjectTooltip", "Reparse the the Wwise Project in GeneratedSoundBanks and reload Wwise assets."),
  211. FSlateIcon(),
  212. RefreshProjectUIAction
  213. );
  214. }
  215. #else
  216. FLevelEditorModule& LevelEditorModule = FModuleManager::GetModuleChecked<FLevelEditorModule>(TEXT("LevelEditor"));
  217. LevelViewportToolbarBuildMenuExtenderAk = FLevelEditorModule::FLevelEditorMenuExtender::CreateLambda([this](const TSharedRef<FUICommandList> CommandList)
  218. {
  219. TSharedPtr<FExtender> Extender = MakeShared<FExtender>();
  220. Extender->AddMenuExtension("LevelEditorGeometry", EExtensionHook::After, CommandList, FMenuExtensionDelegate::CreateLambda([this](FMenuBuilder& MenuBuilder)
  221. {
  222. MenuBuilder.BeginSection("Audiokinetic", LOCTEXT("Audiokinetic", "Audiokinetic"));
  223. {
  224. FUIAction GenerateSoundDataUIAction;
  225. GenerateSoundDataUIAction.ExecuteAction.BindStatic(&AkAudioBankGenerationHelper::CreateGenerateSoundDataWindow, false);
  226. MenuBuilder.AddMenuEntry(
  227. LOCTEXT("AkAudioBank_GenerateSoundBanks", "Generate SoundBanks..."),
  228. LOCTEXT("AkAudioBank_GenerateSoundBanksTooltip", "Generates Wwise SoundBanks."),
  229. FSlateIcon(),
  230. GenerateSoundDataUIAction
  231. );
  232. FUIAction RefreshProjectUIAction;
  233. RefreshProjectUIAction.ExecuteAction.BindRaw(this, &FAudiokineticToolsModule::RefreshWwiseProject);
  234. MenuBuilder.AddMenuEntry(
  235. LOCTEXT("AkAudioBank_RefreshProject", "Refresh Project"),
  236. LOCTEXT("AkAudioBank_RefreshProjectTooltip", "Refresh the Wwise Project"),
  237. FSlateIcon(),
  238. RefreshProjectUIAction
  239. );
  240. }
  241. MenuBuilder.EndSection();
  242. }));
  243. return Extender.ToSharedRef();
  244. });
  245. LevelEditorModule.GetAllLevelEditorToolbarBuildMenuExtenders().Add(LevelViewportToolbarBuildMenuExtenderAk);
  246. LevelViewportToolbarBuildMenuExtenderAkHandle = LevelEditorModule.GetAllLevelEditorToolbarBuildMenuExtenders().Last().GetHandle();
  247. #endif
  248. // Extend the Help menu to display a link to our documentation
  249. {
  250. UToolMenu* HelpMenu = UToolMenus::Get()->ExtendMenu("LevelEditor.MainMenu.Help");
  251. FToolMenuSection& WwiseHelpSection = HelpMenu->AddSection("AkHelp", LOCTEXT("AkHelpLabel", "Audiokinetic"), FToolMenuInsert("HelpBrowse", EToolMenuInsertType::Default));
  252. WwiseHelpSection.AddEntry(FToolMenuEntry::InitMenuEntry(
  253. NAME_None,
  254. LOCTEXT("AkWwiseHelpEntry", "Wwise Help"),
  255. LOCTEXT("AkWwiseHelpEntryToolTip", "Shows the online Wwise documentation."),
  256. FSlateIcon(),
  257. FUIAction(FExecuteAction::CreateRaw(this, &FAudiokineticToolsModule::OpenOnlineHelp))
  258. ));
  259. }
  260. }
  261. void FAudiokineticToolsModule::UpdateUnrealCultureToWwiseCultureMap(const WwiseProjectInfo& wwiseProjectInfo)
  262. {
  263. if (!wwiseProjectInfo.IsProjectInfoParsed())
  264. {
  265. UE_LOG(LogAudiokineticTools, Verbose, TEXT("AudiokineticToolsModule::UpdateUnrealCultureToWwiseCultureMap: Wwise project not parsed. Unreal culture to Wwise culture map will not be updated."));
  266. return;
  267. }
  268. static constexpr auto InvariantCultureLCID = 0x007F;
  269. UAkSettings* AkSettings = GetMutableDefault<UAkSettings>();
  270. if (!AkSettings)
  271. {
  272. return;
  273. }
  274. TMap<FString, FString> wwiseToUnrealMap;
  275. for (auto& entry : WwiseLanguageToUnrealCultureList)
  276. {
  277. wwiseToUnrealMap.Add(entry.WwiseLanguage, entry.UnrealCulture);
  278. }
  279. TMap<FString, int> languageCountMap;
  280. for (auto& language : wwiseProjectInfo.GetSupportedLanguages())
  281. {
  282. if (auto* foundUnrealCulture = wwiseToUnrealMap.Find(language.Name))
  283. {
  284. auto culturePtr = FInternationalization::Get().GetCulture(*foundUnrealCulture);
  285. if (culturePtr && culturePtr->GetLCID() != InvariantCultureLCID)
  286. {
  287. int& langCount = languageCountMap.FindOrAdd(culturePtr->GetTwoLetterISOLanguageName());
  288. ++langCount;
  289. }
  290. }
  291. }
  292. TSet<FString> foundCultures;
  293. bool modified = false;
  294. for (auto& language : wwiseProjectInfo.GetSupportedLanguages())
  295. {
  296. if (auto* foundUnrealCulture = wwiseToUnrealMap.Find(language.Name))
  297. {
  298. auto culturePtr = FInternationalization::Get().GetCulture(*foundUnrealCulture);
  299. if (culturePtr && culturePtr->GetLCID() != InvariantCultureLCID)
  300. {
  301. int* langCount = languageCountMap.Find(culturePtr->GetTwoLetterISOLanguageName());
  302. if (langCount && *langCount > 1)
  303. {
  304. auto newKey = *foundUnrealCulture;
  305. if (!AkSettings->UnrealCultureToWwiseCulture.Contains(newKey))
  306. {
  307. AkSettings->UnrealCultureToWwiseCulture.Add(newKey, language.Name);
  308. modified = true;
  309. }
  310. foundCultures.Add(newKey);
  311. }
  312. else
  313. {
  314. auto newKey = culturePtr->GetTwoLetterISOLanguageName();
  315. if (!AkSettings->UnrealCultureToWwiseCulture.Contains(newKey))
  316. {
  317. AkSettings->UnrealCultureToWwiseCulture.Add(newKey, language.Name);
  318. modified = true;
  319. }
  320. foundCultures.Add(newKey);
  321. }
  322. }
  323. }
  324. else
  325. {
  326. for (auto& entry : AkSettings->UnrealCultureToWwiseCulture)
  327. {
  328. if (entry.Value == language.Name)
  329. {
  330. foundCultures.Add(entry.Key);
  331. break;
  332. }
  333. }
  334. }
  335. }
  336. TSet<FString> keysToRemove;
  337. for (auto& entry : AkSettings->UnrealCultureToWwiseCulture)
  338. {
  339. if (!foundCultures.Contains(entry.Key))
  340. {
  341. keysToRemove.Add(entry.Key);
  342. }
  343. }
  344. for (auto& keyToRemove : keysToRemove)
  345. {
  346. AkSettings->UnrealCultureToWwiseCulture.Remove(keyToRemove);
  347. modified = true;
  348. }
  349. if (modified)
  350. {
  351. AkSettings->SaveConfig();
  352. }
  353. }
  354. void FAudiokineticToolsModule::VerifyGeneratedSoundBanksPath(UAkSettings* AkSettings, UAkSettingsPerUser* AkSettingsPerUser)
  355. {
  356. if (!AkSettings->GeneratedSoundBanksPathExists())
  357. {
  358. if (!AkSettingsPerUser->SuppressGeneratedSoundBanksPathWarnings && FApp::CanEverRender())
  359. {
  360. if (EAppReturnType::Yes == FMessageDialog::Open(EAppMsgType::YesNo, LOCTEXT("SettingsNotSet", "GeneratedSoundBanks folder does not seem to be set. Would you like to open the settings window to set it?")))
  361. {
  362. FModuleManager::LoadModuleChecked<ISettingsModule>("Settings").ShowViewer(FName("Project"), FName("Wwise"), FName("Integration"));
  363. }
  364. }
  365. else
  366. {
  367. UE_LOG(LogAudiokineticTools, Log, TEXT("GeneratedSoundBanks folder not found. The Wwise Browser will not be usable."));
  368. }
  369. }
  370. else
  371. {
  372. // First-time plugin migration: Project might be relative to Engine path. Fix-up the path to make it relative to the game.
  373. const auto ProjectDir = FPaths::ProjectContentDir();
  374. FString FullGameDir = FPaths::ConvertRelativePathToFull(ProjectDir);
  375. FString TempPath = FPaths::ConvertRelativePathToFull(FullGameDir, AkSettings->RootOutputPath.Path);
  376. if (!FPaths::DirectoryExists(TempPath))
  377. {
  378. if (!AkSettingsPerUser->SuppressGeneratedSoundBanksPathWarnings && FApp::CanEverRender())
  379. {
  380. TSharedPtr<SWindow> Dialog = SNew(SWindow)
  381. .Title(LOCTEXT("ResetWwisePath", "Reset GeneratedSoundBanks Folder Path"))
  382. .SupportsMaximize(false)
  383. .SupportsMinimize(false)
  384. .FocusWhenFirstShown(true)
  385. .SizingRule(ESizingRule::Autosized);
  386. TSharedRef<SWidget> DialogContent = SNew(SVerticalBox)
  387. + SVerticalBox::Slot()
  388. .FillHeight(0.25f)
  389. [
  390. SNew(SSpacer)
  391. ]
  392. + SVerticalBox::Slot()
  393. .AutoHeight()
  394. [
  395. SNew(STextBlock)
  396. .Text(LOCTEXT("AkUpdateWwisePath", "The Wwise Unreal Engine Integration plug-in's update process requires the Wwise GeneratedSoundBanks Folder to be set in the Project Settings dialog. Would you like to open the Project Settings?")) .AutoWrapText(true)
  397. ]
  398. + SVerticalBox::Slot()
  399. .FillHeight(0.75f)
  400. [
  401. SNew(SSpacer)
  402. ]
  403. + SVerticalBox::Slot()
  404. .AutoHeight()
  405. [
  406. SNew(SCheckBox)
  407. .Padding(FMargin(6.0, 2.0))
  408. .OnCheckStateChanged_Lambda([&](ECheckBoxState DontAskState) {
  409. AkSettingsPerUser->SuppressGeneratedSoundBanksPathWarnings = (DontAskState == ECheckBoxState::Checked);
  410. })
  411. [
  412. SNew(STextBlock)
  413. .Text(LOCTEXT("AkDontShowAgain", "Don't show this again"))
  414. ]
  415. ]
  416. + SVerticalBox::Slot()
  417. .AutoHeight()
  418. [
  419. SNew(SHorizontalBox)
  420. + SHorizontalBox::Slot()
  421. .FillWidth(1.0f)
  422. [
  423. SNew(SSpacer)
  424. ]
  425. + SHorizontalBox::Slot()
  426. .AutoWidth()
  427. .Padding(0.0f, 3.0f, 0.0f, 3.0f)
  428. [
  429. SNew(SButton)
  430. .Text(LOCTEXT("Yes", "Yes"))
  431. .OnClicked_Lambda([&]() -> FReply {
  432. FModuleManager::LoadModuleChecked<ISettingsModule>("Settings").ShowViewer(FName("Project"), FName("Plugins"), FName("Wwise"));
  433. Dialog->RequestDestroyWindow();
  434. AkSettingsPerUser->SaveConfig();
  435. return FReply::Handled();
  436. })
  437. ]
  438. + SHorizontalBox::Slot()
  439. .AutoWidth()
  440. .Padding(0.0f, 3.0f, 0.0f, 3.0f)
  441. [
  442. SNew(SButton)
  443. .Text(LOCTEXT("No", "No"))
  444. .OnClicked_Lambda([&]() -> FReply {
  445. Dialog->RequestDestroyWindow();
  446. AkSettingsPerUser->SaveConfig();
  447. return FReply::Handled();
  448. })
  449. ]
  450. ]
  451. ;
  452. Dialog->SetContent(DialogContent);
  453. FSlateApplication::Get().AddModalWindow(Dialog.ToSharedRef(), nullptr);
  454. }
  455. else
  456. {
  457. UE_LOG(LogAudiokineticTools, Log, TEXT("GeneratedSoundBanks folder not found. The Wwise Browser will not be usable."));
  458. }
  459. }
  460. else
  461. {
  462. FPaths::MakePathRelativeTo(TempPath, *ProjectDir);
  463. if (AkSettings->RootOutputPath.Path != TempPath)
  464. {
  465. AkSettings->WwiseProjectPath.FilePath = TempPath;
  466. AkUnrealEditorHelper::SaveConfigFile(AkSettings);
  467. }
  468. }
  469. }
  470. }
  471. void FAudiokineticToolsModule::OnAssetRegistryFilesLoaded()
  472. {
  473. UAkSettings* AkSettings = GetMutableDefault<UAkSettings>();
  474. UAkSettingsPerUser* AkSettingsPerUser = GetMutableDefault<UAkSettingsPerUser>();
  475. auto* CurrentProject = IProjectManager::Get().GetCurrentProject();
  476. bool doModifyProject = true;
  477. WwiseProjectInfo wwiseProjectInfo;
  478. wwiseProjectInfo.Parse();
  479. UpdateUnrealCultureToWwiseCultureMap(wwiseProjectInfo);
  480. if (GUnrealEd != NULL)
  481. {
  482. GUnrealEd->RegisterComponentVisualizer(UAkComponent::StaticClass()->GetFName(), MakeShareable(new FAkComponentVisualizer));
  483. GUnrealEd->RegisterComponentVisualizer(UAkSurfaceReflectorSetComponent::StaticClass()->GetFName(), MakeShareable(new FAkSurfaceReflectorSetComponentVisualizer));
  484. GUnrealEd->RegisterComponentVisualizer(UAkPortalComponent::StaticClass()->GetFName(), MakeShareable(new UAkPortalComponentVisualizer));
  485. }
  486. AkSettings->InitGeometrySurfacePropertiesTable();
  487. AkSettings->InitReverbAssignmentTable();
  488. AkSettings->EnsurePluginContentIsInAlwaysCook();
  489. AkAcousticTextureParamLookup AcousticTextureParamLookup;
  490. AcousticTextureParamLookup.UpdateParamsMap();
  491. if (!IsRunningCommandlet() )
  492. {
  493. if (FApp::CanEverRender())
  494. {
  495. AssetMigrationManager.CreateMigrationMenuOption();
  496. AssetMigrationManager.EditorTryMigration();
  497. }
  498. SoundBanksDirectoryWatcher.Initialize();
  499. SoundBanksDirectoryWatcher.OnSoundBanksGenerated.AddStatic(&FAudiokineticToolsModule::ParseGeneratedSoundBankData);
  500. }
  501. // If we're on the project loader screen, we don't want to display the dialog.
  502. // In that case, CurrentProject is nullptr.
  503. if (CurrentProject && AkSettings && AkSettingsPerUser)
  504. {
  505. VerifyGeneratedSoundBanksPath(AkSettings, AkSettingsPerUser);
  506. if (doModifyProject)
  507. {
  508. AssetMigrationManager.SetStandardProjectSettings();
  509. }
  510. }
  511. }
  512. void FAudiokineticToolsModule::StartupModule()
  513. {
  514. AudiokineticToolsModuleInstance = this;
  515. if (FModuleManager::Get().IsModuleLoaded("AssetTools"))
  516. {
  517. auto& AssetTools = FModuleManager::LoadModuleChecked<FAssetToolsModule>("AssetTools").Get();
  518. auto AudiokineticAssetCategoryBit = AssetTools.RegisterAdvancedAssetCategory(FName(TEXT("Audiokinetic")), LOCTEXT("AudiokineticAssetCategory", "Audiokinetic"));
  519. AkAssetTypeActionsArray =
  520. {
  521. MakeShared<FAssetTypeActions_AkAudioEvent>(AudiokineticAssetCategoryBit),
  522. MakeShared<FAssetTypeActions_AkAcousticTexture>(AudiokineticAssetCategoryBit),
  523. MakeShared<FAssetTypeActions_AkAuxBus>(AudiokineticAssetCategoryBit),
  524. MakeShared<FAssetTypeActions_AkRtpc>(AudiokineticAssetCategoryBit),
  525. MakeShared<FAssetTypeActions_AkTrigger>(AudiokineticAssetCategoryBit),
  526. };
  527. for (auto& AkAssetTypeActions : AkAssetTypeActionsArray)
  528. AssetTools.RegisterAssetTypeActions(AkAssetTypeActions.ToSharedRef());
  529. }
  530. if (FModuleManager::Get().IsModuleLoaded("LevelEditor") && !IsRunningCommandlet() && FApp::CanEverRender())
  531. {
  532. RegisterWwiseMenus();
  533. CreateAkViewportCommands();
  534. }
  535. RegisterSettings();
  536. AkEventBroker = MakeShared<FAkEventAssetBroker>();
  537. FComponentAssetBrokerage::RegisterBroker(AkEventBroker, UAkComponent::StaticClass(), true, true);
  538. auto& TabSpawnerEntry = FGlobalTabmanager::Get()->RegisterNomadTabSpawner(SWwiseBrowser::WwiseBrowserTabName, FOnSpawnTab::CreateRaw(this, &FAudiokineticToolsModule::CreateWwiseBrowserTab))
  539. .SetDisplayName(NSLOCTEXT("FAudiokineticToolsModule", "BrowserTabTitle", "Wwise Browser"))
  540. .SetTooltipText(NSLOCTEXT("FAudiokineticToolsModule", "BrowserTooltipText", "Open the Wwise Browser tab."))
  541. .SetGroup(WorkspaceMenu::GetMenuStructure().GetLevelEditorCategory())
  542. .SetIcon(FSlateIcon(FAkAudioStyle::GetStyleSetName(), "AudiokineticTools.AkBrowserTabIcon"));
  543. FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked<FAssetRegistryModule>(TEXT("AssetRegistry"));
  544. OnAssetRegistryFilesLoadedHandle = AssetRegistryModule.Get().OnFilesLoaded().AddRaw(this, &FAudiokineticToolsModule::OnAssetRegistryFilesLoaded);
  545. ISequencerModule& SequencerModule = FModuleManager::LoadModuleChecked<ISequencerModule>(TEXT("Sequencer"));
  546. RTPCTrackEditorHandle = SequencerModule.RegisterTrackEditor(FOnCreateTrackEditor::CreateStatic(&FMovieSceneAkAudioRTPCTrackEditor::CreateTrackEditor));
  547. EventTrackEditorHandle = SequencerModule.RegisterTrackEditor(FOnCreateTrackEditor::CreateStatic(&FMovieSceneAkAudioEventTrackEditor::CreateTrackEditor));
  548. // Since we are initialized in the PostEngineInit phase, our Ambient Sound actor factory is not registered. We need to register it ourselves.
  549. if (GEditor)
  550. {
  551. if (auto NewFactory = NewObject<UActorFactoryAkAmbientSound>())
  552. {
  553. GEditor->ActorFactories.Add(NewFactory);
  554. }
  555. }
  556. FPropertyEditorModule& PropertyModule = FModuleManager::LoadModuleChecked<FPropertyEditorModule>("PropertyEditor");
  557. PropertyModule.RegisterCustomClassLayout(UAkSurfaceReflectorSetComponent::StaticClass()->GetFName(), FOnGetDetailCustomizationInstance::CreateStatic(&FAkSurfaceReflectorSetDetailsCustomization::MakeInstance));
  558. PropertyModule.RegisterCustomClassLayout(UAkLateReverbComponent::StaticClass()->GetFName(), FOnGetDetailCustomizationInstance::CreateStatic(&FAkLateReverbComponentDetailsCustomization::MakeInstance));
  559. PropertyModule.RegisterCustomClassLayout(UAkRoomComponent::StaticClass()->GetFName(), FOnGetDetailCustomizationInstance::CreateStatic(&FAkRoomComponentDetailsCustomization::MakeInstance));
  560. PropertyModule.RegisterCustomClassLayout(UAkPortalComponent::StaticClass()->GetFName(), FOnGetDetailCustomizationInstance::CreateStatic(&FAkPortalComponentDetailsCustomization::MakeInstance));
  561. PropertyModule.RegisterCustomClassLayout(UAkGeometryComponent::StaticClass()->GetFName(), FOnGetDetailCustomizationInstance::CreateStatic(&FAkGeometryComponentDetailsCustomization::MakeInstance));
  562. PropertyModule.RegisterCustomClassLayout(UAkSettings::StaticClass()->GetFName(), FOnGetDetailCustomizationInstance::CreateStatic(&FAkSettingsDetailsCustomization::MakeInstance));
  563. PropertyModule.RegisterCustomClassLayout(AAkReverbZone::StaticClass()->GetFName(), FOnGetDetailCustomizationInstance::CreateStatic(&FAkReverbZoneDetailsCustomization::MakeInstance));
  564. if (!IWwiseProjectDatabaseModule::ShouldInitializeProjectDatabase())
  565. {
  566. return;
  567. }
  568. if (FAkAudioModule::AkAudioModuleInstance && FAkAudioModule::AkAudioModuleInstance->bModuleInitialized)
  569. {
  570. OnAkAudioInit();
  571. }
  572. else
  573. {
  574. FAkAudioModule::OnModuleInitialized.AddRaw(this, &FAudiokineticToolsModule::OnAkAudioInit);
  575. }
  576. //Project Database initial parse occurs before AudiokineticTools' Initialization. Call it here manually.
  577. SetStaticPluginsInformation();
  578. StaticPluginHandle = FWwiseProjectDatabaseDelegates::Get()->GetOnDatabaseUpdateCompletedDelegate().AddLambda(
  579. [this]()
  580. {
  581. SetStaticPluginsInformation();
  582. }
  583. );
  584. FEditorDelegates::BeginPIE.AddRaw(this, &FAudiokineticToolsModule::BeginPIE);
  585. }
  586. void FAudiokineticToolsModule::OnAkAudioInit()
  587. {
  588. FAkAudioStyle::Initialize();
  589. if (UAkSettings* Settings = GetMutableDefault<UAkSettings>())
  590. {
  591. Settings->OnGeneratedSoundBanksPathChanged.AddRaw(this, &FAudiokineticToolsModule::OnSoundBanksFolderChanged);
  592. OnDatabaseUpdateTextureHandle = FWwiseProjectDatabaseDelegates::Get()->GetOnDatabaseUpdateCompletedDelegate().AddRaw(this, &FAudiokineticToolsModule::RefreshAndUpdateTextureParams);
  593. }
  594. if (UAkSettingsPerUser* UserSettings = GetMutableDefault<UAkSettingsPerUser>())
  595. {
  596. UserSettings->OnGeneratedSoundBanksPathChanged.AddRaw(this, &FAudiokineticToolsModule::OnSoundBanksFolderChanged);
  597. }
  598. OnDatabaseUpdateCompleteHandle = FWwiseProjectDatabaseDelegates::Get()->GetOnDatabaseUpdateCompletedDelegate().AddRaw(this, &FAudiokineticToolsModule::AssetReloadPrompt);
  599. #if AK_SUPPORT_WAAPI
  600. if (!IsRunningCommandlet())
  601. {
  602. FAkWaapiClient::Initialize();
  603. if (UAkSettings* AkSettings = GetMutableDefault<UAkSettings>())
  604. {
  605. AkSettings->InitWaapiSync();
  606. }
  607. }
  608. #endif
  609. }
  610. void FAudiokineticToolsModule::OnSoundBanksFolderChanged()
  611. {
  612. FAkAudioModule::AkAudioModuleInstance->UpdateWwiseResourceLoaderSettings();
  613. ParseGeneratedSoundBankData();
  614. }
  615. void FAudiokineticToolsModule::BeginPIE(const bool bIsSimulating)
  616. {
  617. UAkSettings* Settings = GetMutableDefault<UAkSettings>();
  618. if(Settings && !Settings->GeneratedSoundBanksPathExists() && FAkAudioModule::AkAudioModuleInstance)
  619. {
  620. DisplayGeneratedSoundBanksWarning();
  621. }
  622. UAkSettingsPerUser* UserSettings = GetMutableDefault<UAkSettingsPerUser>();
  623. if(UserSettings && !UserSettings->RootOutputPathOverride.Path.IsEmpty())
  624. {
  625. UE_LOG(LogAkAudio, Warning, TEXT("Using Root Output Path Override: %s"), *WwiseUnrealHelper::GetSoundBankDirectory());
  626. }
  627. }
  628. void FAudiokineticToolsModule::SetStaticPluginsInformation()
  629. {
  630. for(auto& Platform : AkUnrealPlatformHelper::GetAllSupportedWwisePlatforms())
  631. {
  632. StaticPluginWriter::OutputPluginInformation(*Platform);
  633. }
  634. }
  635. void FAudiokineticToolsModule::DisplayGeneratedSoundBanksWarning()
  636. {
  637. if (!FApp::CanEverRender())
  638. {
  639. return;
  640. }
  641. GeneratedSoundBanksWarning.HideGeneratedSoundBanksNotification();
  642. GeneratedSoundBanksWarning.DisplayGeneratedSoundBanksWarning();
  643. }
  644. void FAudiokineticToolsModule::AssetReloadPrompt()
  645. {
  646. const UAkSettingsPerUser* UserSettings = GetDefault<UAkSettingsPerUser>();
  647. if (UserSettings->AskForWwiseAssetReload && FApp::CanEverRender())
  648. {
  649. OpenAssetReloadPopup();
  650. }
  651. else
  652. {
  653. FAkAudioModule::AkAudioModuleInstance->ReloadWwiseAssetData();
  654. }
  655. }
  656. void FAudiokineticToolsModule::OpenAssetReloadPopup()
  657. {
  658. ReloadPopup.HideRefreshNotification();
  659. ReloadPopup.NotifyProjectRefresh();
  660. }
  661. void FAudiokineticToolsModule::ParseGeneratedSoundBankData()
  662. {
  663. FAkAudioModule::ParseGeneratedSoundBankData();
  664. }
  665. void FAudiokineticToolsModule::ShutdownModule()
  666. {
  667. if (FModuleManager::Get().IsModuleLoaded("AssetTools"))
  668. {
  669. auto& AssetTools = FModuleManager::GetModuleChecked<FAssetToolsModule>("AssetTools").Get();
  670. for (auto AkAssetTypeActions : AkAssetTypeActionsArray)
  671. if (AkAssetTypeActions.IsValid())
  672. AssetTools.UnregisterAssetTypeActions(AkAssetTypeActions.ToSharedRef());
  673. }
  674. AkAssetTypeActionsArray.Empty();
  675. if (FModuleManager::Get().IsModuleLoaded("LevelEditor"))
  676. {
  677. auto& LevelEditorModule = FModuleManager::GetModuleChecked<FLevelEditorModule>("LevelEditor");
  678. LevelEditorModule.GetAllLevelEditorToolbarBuildMenuExtenders().RemoveAll([this](const FLevelEditorModule::FLevelEditorMenuExtender& Extender)
  679. {
  680. return Extender.GetHandle() == LevelViewportToolbarBuildMenuExtenderAkHandle;
  681. });
  682. if (MainMenuExtender.IsValid())
  683. {
  684. LevelEditorModule.GetMenuExtensibilityManager()->RemoveExtender(MainMenuExtender);
  685. }
  686. }
  687. LevelViewportToolbarBuildMenuExtenderAkHandle.Reset();
  688. StaticPluginHandle.Reset();
  689. UnregisterSettings();
  690. if (GUnrealEd != NULL)
  691. {
  692. GUnrealEd->UnregisterComponentVisualizer(UAkComponent::StaticClass()->GetFName());
  693. }
  694. FGlobalTabmanager::Get()->UnregisterTabSpawner(SWwiseBrowser::WwiseBrowserTabName);
  695. if (FModuleManager::Get().IsModuleLoaded(TEXT("Sequencer")))
  696. {
  697. auto& SequencerModule = FModuleManager::GetModuleChecked<ISequencerModule>(TEXT("Sequencer"));
  698. SequencerModule.UnRegisterTrackEditor(RTPCTrackEditorHandle);
  699. SequencerModule.UnRegisterTrackEditor(EventTrackEditorHandle);
  700. }
  701. // Only found way to close the tab in the case of a hot-reload. We need a pointer to the DockTab, and the only way of getting it seems to be InvokeTab.
  702. if (IsValid(GUnrealEd))
  703. {
  704. #if UE_4_26_OR_LATER
  705. auto WwiseBrowserTab = FGlobalTabmanager::Get()->TryInvokeTab(SWwiseBrowser::WwiseBrowserTabName);
  706. if (WwiseBrowserTab.IsValid())
  707. {
  708. WwiseBrowserTab->RequestCloseTab();
  709. }
  710. #else
  711. FGlobalTabmanager::Get()->InvokeTab(SWwiseBrowser::WwiseBrowserTabName)->RequestCloseTab();
  712. #endif
  713. }
  714. FGlobalTabmanager::Get()->UnregisterNomadTabSpawner(SWwiseBrowser::WwiseBrowserTabName);
  715. if (UObjectInitialized())
  716. {
  717. FComponentAssetBrokerage::UnregisterBroker(AkEventBroker);
  718. }
  719. if (UObjectInitialized() && !IsEngineExitRequested())
  720. {
  721. FPropertyEditorModule* PropertyModule = FModuleManager::Get().GetModulePtr<FPropertyEditorModule>("PropertyEditor");
  722. if (PropertyModule)
  723. {
  724. PropertyModule->UnregisterCustomClassLayout(UAkSurfaceReflectorSetComponent::StaticClass()->GetFName());
  725. PropertyModule->UnregisterCustomClassLayout(UAkLateReverbComponent::StaticClass()->GetFName());
  726. PropertyModule->UnregisterCustomClassLayout(UAkRoomComponent::StaticClass()->GetFName());
  727. }
  728. }
  729. if (!IWwiseProjectDatabaseModule::ShouldInitializeProjectDatabase())
  730. {
  731. return;
  732. }
  733. if (OnDatabaseUpdateTextureHandle.IsValid())
  734. {
  735. FWwiseProjectDatabaseDelegates::Get()->GetOnDatabaseUpdateCompletedDelegate().Remove(OnDatabaseUpdateTextureHandle);
  736. OnDatabaseUpdateTextureHandle.Reset();
  737. }
  738. #if WITH_EDITOR
  739. FAkAudioStyle::Shutdown();
  740. #if AK_SUPPORT_WAAPI
  741. FAkWaapiClient::DeleteInstance();
  742. #endif
  743. #endif
  744. SoundBanksDirectoryWatcher.Uninitialize(true);
  745. AudiokineticToolsModuleInstance = nullptr;
  746. }
  747. void FAudiokineticToolsModule::RefreshAndUpdateTextureParams()
  748. {
  749. AkAcousticTextureParamLookup AcousticTextureParamLookup;
  750. AcousticTextureParamLookup.UpdateParamsMap();
  751. UAkSettings* AkSettings = GetMutableDefault<UAkSettings>();
  752. if (AkSettings)
  753. {
  754. AkSettings->RefreshAcousticTextureParams();
  755. }
  756. }
  757. EEditorBuildResult FAudiokineticToolsModule::BuildAkEventData(UWorld* world, FName name)
  758. {
  759. if (!AkAssetDatabase::Get().CheckIfLoadingAssets())
  760. {
  761. AkGenerateSoundBanksTask::ExecuteForEditorPlatform();
  762. return EEditorBuildResult::InProgress;
  763. }
  764. else
  765. {
  766. return EEditorBuildResult::Skipped;
  767. }
  768. }
  769. TMap<FString, SettingsRegistrationStruct>& FAudiokineticToolsModule::GetWwisePlatformNameToSettingsRegistrationMap()
  770. {
  771. static TMap<FString, SettingsRegistrationStruct> WwisePlatformNameToWwiseSettingsRegistrationMap;
  772. if (WwisePlatformNameToWwiseSettingsRegistrationMap.Num() == 0)
  773. {
  774. auto RegisterIntegrationSettings = SettingsRegistrationStruct(UAkSettings::StaticClass(),
  775. "Integration",
  776. LOCTEXT("WwiseIntegrationSettingsName", "Integration Settings"),
  777. LOCTEXT("WwiseIntegrationSettingsDescription", "Configure the Wwise Integration"));
  778. auto RegisterPerUserSettings = SettingsRegistrationStruct(UAkSettingsPerUser::StaticClass(),
  779. "User Settings",
  780. LOCTEXT("WwiseRuntimePerUserSettingsName", "User Settings"),
  781. LOCTEXT("WwiseRuntimePerUserSettingsDescription", "Configure the Wwise Integration per user"));
  782. WwisePlatformNameToWwiseSettingsRegistrationMap.Add(FString("Integration"), RegisterIntegrationSettings);
  783. WwisePlatformNameToWwiseSettingsRegistrationMap.Add(FString("User"), RegisterPerUserSettings);
  784. for (const auto& AvailablePlatform : AkUnrealPlatformHelper::GetAllSupportedUnrealPlatforms())
  785. {
  786. FString SettingsClassName = FString::Format(TEXT("/Script/AkAudio.Ak{0}InitializationSettings"), { *AvailablePlatform });
  787. #if UE_5_1_OR_LATER
  788. auto* SettingsClass = UClass::TryFindTypeSlow<UClass>(*SettingsClassName);
  789. #else
  790. auto* SettingsClass = FindObject<UClass>(ANY_PACKAGE, *SettingsClassName);
  791. #endif
  792. if (SettingsClass)
  793. {
  794. FString CategoryNameKey = FString::Format(TEXT("Wwise{0}SettingsName"), { *AvailablePlatform });
  795. FString DescriptionNameKey = FString::Format(TEXT("Wwise{0}SettingsDescription"), { *AvailablePlatform });
  796. FString DescriptionText = FString::Format(TEXT("Configure the Wwise {0} Initialization Settings"), { *AvailablePlatform });
  797. FText PlatformNameText = FText::FromString(*AvailablePlatform);
  798. FString AdditionalDescriptionText = TEXT("");
  799. if (AkUnrealPlatformHelper::IsEditorPlatform(AvailablePlatform))
  800. {
  801. AdditionalDescriptionText = TEXT("\nYou must restart the Unreal Editor for changes to be applied to the Wwise Sound Engine running in the Editor");
  802. }
  803. FText PlatformDescriptionText = FText::Format(LOCTEXT("WwiseSettingsDescription", "Configure the Wwise {0} Initialization Settings{1}"), PlatformNameText, FText::FromString(*AdditionalDescriptionText));
  804. auto RegisterPlatform = SettingsRegistrationStruct(SettingsClass, FName(*AvailablePlatform),
  805. PlatformNameText,
  806. PlatformDescriptionText);
  807. WwisePlatformNameToWwiseSettingsRegistrationMap.Add(*AvailablePlatform, RegisterPlatform);
  808. }
  809. }
  810. }
  811. return WwisePlatformNameToWwiseSettingsRegistrationMap;
  812. }
  813. void FAudiokineticToolsModule::RegisterSettings()
  814. {
  815. if (auto SettingsModule = FModuleManager::GetModulePtr<ISettingsModule>("Settings"))
  816. {
  817. auto UpdatePlatformSettings = [SettingsModule, this]
  818. {
  819. auto SettingsRegistrationMap = GetWwisePlatformNameToSettingsRegistrationMap();
  820. TSet<FString> SettingsThatShouldBeRegistered = { FString("Integration"), FString("User") };
  821. for (const auto& AvailablePlatform : AkUnrealPlatformHelper::GetAllSupportedUnrealPlatformsForProject())
  822. {
  823. if (SettingsRegistrationMap.Contains(AvailablePlatform))
  824. {
  825. SettingsThatShouldBeRegistered.Add(AvailablePlatform);
  826. }
  827. }
  828. auto SettingsToBeUnregistered = RegisteredSettingsNames.Difference(SettingsThatShouldBeRegistered);
  829. for (const auto& SettingsName : SettingsToBeUnregistered)
  830. {
  831. SettingsRegistrationMap[SettingsName].Unregister(SettingsModule);
  832. RegisteredSettingsNames.Remove(SettingsName);
  833. }
  834. auto SettingsToBeRegistered = SettingsThatShouldBeRegistered.Difference(RegisteredSettingsNames);
  835. for (const auto& SettingsName : SettingsToBeRegistered)
  836. {
  837. if (RegisteredSettingsNames.Contains(SettingsName))
  838. continue;
  839. SettingsRegistrationMap[SettingsName].Register(SettingsModule);
  840. RegisteredSettingsNames.Add(SettingsName);
  841. }
  842. };
  843. UpdatePlatformSettings();
  844. IProjectManager& ProjectManager = IProjectManager::Get();
  845. ProjectManager.OnTargetPlatformsForCurrentProjectChanged().AddLambda(UpdatePlatformSettings);
  846. }
  847. }
  848. void FAudiokineticToolsModule::UnregisterSettings()
  849. {
  850. if (auto SettingsModule = FModuleManager::GetModulePtr<ISettingsModule>("Settings"))
  851. {
  852. auto SettingsRegistrationMap = GetWwisePlatformNameToSettingsRegistrationMap();
  853. for (const auto& SettingsName : RegisteredSettingsNames)
  854. {
  855. SettingsRegistrationMap[SettingsName].Unregister(SettingsModule);
  856. }
  857. RegisteredSettingsNames.Empty();
  858. }
  859. }
  860. #undef LOCTEXT_NAMESPACE