AkAssetMigrationManager.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517
  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 "AkAssetMigrationManager.h"
  16. #include "AkAudioStyle.h"
  17. #include "AkSettings.h"
  18. #include "AkUnrealEditorHelper.h"
  19. #include "AkAssetMigrationHelper.h"
  20. #include "AkAudioBank.h"
  21. #include "AkAudioEvent.h"
  22. #include "AkAudioModule.h"
  23. #include "AkInitBank.h"
  24. #include "AkWaapiClient.h"
  25. #include "ContentBrowserModule.h"
  26. #include "Editor.h"
  27. #include "Framework/Notifications/NotificationManager.h"
  28. #if UE_5_0_OR_LATER
  29. #include "HAL/PlatformFileManager.h"
  30. #else
  31. #include "HAL/PlatformFilemanager.h"
  32. #endif
  33. #include "IAudiokineticTools.h"
  34. #include "Misc/FileHelper.h"
  35. #include "Misc/MessageDialog.h"
  36. #include "Widgets/Notifications/SNotificationList.h"
  37. #include "Settings/ProjectPackagingSettings.h"
  38. #include "WwiseUnrealHelper.h"
  39. #include "ToolMenus.h"
  40. #include "FileHelpers.h"
  41. #define LOCTEXT_NAMESPACE "AkAudio"
  42. bool AkAssetMigrationManager::IsProjectMigrated()
  43. {
  44. UAkSettings* AkSettings = GetMutableDefault<UAkSettings>();
  45. if (!AkSettings)
  46. {
  47. UE_LOG(LogAudiokineticTools, Display, TEXT("AkAssetMigrationManager::IsProjectMigrated: Could not get AkSettings. Cannot determine whether the project is migrated."));
  48. return false;
  49. }
  50. return AkSettings->bAssetsMigrated && AkSettings->bProjectMigrated && AkSettings->bSoundBanksTransfered;
  51. }
  52. bool AkAssetMigrationManager::IsMigrationRequired(AkAssetMigration::FMigrationContext& MigrationOptions )
  53. {
  54. UAkSettings* AkSettings = GetMutableDefault<UAkSettings>();
  55. if (!AkSettings)
  56. {
  57. UE_LOG(LogAudiokineticTools, Display, TEXT("AkAssetMigrationManager::IsMigrationRequired: Could not getAkSettings. Cannot determine whether the project should be migrated."));
  58. return false;
  59. }
  60. auto& AssetRegistryModule = FModuleManager::LoadModuleChecked<FAssetRegistryModule>("AssetRegistry");
  61. auto& AssetRegistry = AssetRegistryModule.Get();
  62. bool bUpdateAkSettings = false;
  63. if (!AkSettings->bAssetsMigrated)
  64. {
  65. TArray<FAssetData> WwiseAssetsInProject;
  66. AkAssetMigration::FindWwiseAssetsInProject(WwiseAssetsInProject);
  67. if (WwiseAssetsInProject.Num() == 0)
  68. {
  69. MigrationOptions.bAssetsNeedMigration = false;
  70. AkSettings->bAssetsMigrated = true;
  71. bUpdateAkSettings = true;
  72. }
  73. else if (WwiseAssetsInProject.Num() == 1)
  74. {
  75. //Init bank asset is automatically created by the integration
  76. if (WwiseAssetsInProject[0].GetClass() == UAkInitBank::StaticClass())
  77. {
  78. AkSettings->bAssetsMigrated = true;
  79. MigrationOptions.bAssetsNeedMigration = false;
  80. bUpdateAkSettings= true;
  81. }
  82. else
  83. {
  84. MigrationOptions.bAssetsNeedMigration = true;
  85. }
  86. }
  87. else
  88. {
  89. MigrationOptions.bAssetsNeedMigration = true;
  90. }
  91. }
  92. else
  93. {
  94. MigrationOptions.bAssetsNeedMigration = false;
  95. }
  96. //Check if project migration is needed
  97. if (!AkSettings->bProjectMigrated)
  98. {
  99. if (AkSettings->UseEventBasedPackaging || AkSettings->SplitMediaPerFolder || IsSoundDataPathInDirectoriesToAlwaysStage(AkUnrealEditorHelper::GetLegacySoundBankDirectory()) )
  100. {
  101. // project migration needed
  102. MigrationOptions.bProjectSettingsNotUpToDate = true;
  103. }
  104. else
  105. {
  106. MigrationOptions.bProjectSettingsNotUpToDate = false;
  107. AkSettings->bProjectMigrated = true;
  108. bUpdateAkSettings = true;
  109. }
  110. }
  111. else
  112. {
  113. MigrationOptions.bProjectSettingsNotUpToDate = false;
  114. }
  115. TArray<FAssetData> Banks;
  116. #if UE_5_1_OR_LATER
  117. AssetRegistry.GetAssetsByClass(UAkAudioBank::StaticClass()->GetClassPathName(), Banks);
  118. #else
  119. AssetRegistry.GetAssetsByClass(UAkAudioBank::StaticClass()->GetFName(), Banks);
  120. #endif
  121. if (Banks.Num() > 0)
  122. {
  123. MigrationOptions.bBanksInProject = true;
  124. }
  125. else
  126. {
  127. MigrationOptions.bBanksInProject = false;
  128. if (!AkSettings->bSoundBanksTransfered)
  129. {
  130. AkSettings->bSoundBanksTransfered = true;
  131. bUpdateAkSettings = true;
  132. }
  133. }
  134. TArray<FAssetData> DeprecatedAssetsInProject;
  135. AkAssetMigration::FindDeprecatedAssets(DeprecatedAssetsInProject);
  136. MigrationOptions.NumDeprecatedAssetsInProject = DeprecatedAssetsInProject.Num();
  137. if (DeprecatedAssetsInProject.Num() > 0)
  138. {
  139. MigrationOptions.bDeprecatedAssetsInProject = true;
  140. }
  141. else
  142. {
  143. MigrationOptions.bDeprecatedAssetsInProject = false;
  144. }
  145. if (bUpdateAkSettings)
  146. {
  147. if(!AkUnrealEditorHelper::SaveConfigFile(AkSettings))
  148. {
  149. const FString Message = TEXT("Unable to checkout settings file for Wwise integration settings (DefaultGame.ini). Please revert all changes done, and restart the migration process.");
  150. if (FApp::CanEverRender())
  151. {
  152. FMessageDialog::Open(EAppMsgType::Ok, FText::FromString(Message));
  153. }
  154. else
  155. {
  156. UE_LOG(LogAudiokineticTools, Error, TEXT("AkAssetMigrationManager: %s"), *Message);
  157. }
  158. }
  159. }
  160. if ((MigrationOptions.bBanksInProject || !AkSettings->bSoundBanksTransfered) || MigrationOptions.bDeprecatedAssetsInProject || MigrationOptions.bAssetsNeedMigration || MigrationOptions.bProjectSettingsNotUpToDate)
  161. {
  162. return true;
  163. }
  164. return false;
  165. }
  166. void AkAssetMigrationManager::EditorTryMigration()
  167. {
  168. //This should only be done with the editor open
  169. if (!FApp::CanEverRender())
  170. {
  171. return;
  172. }
  173. AkAssetMigration::FMigrationContext MigrationOptions;
  174. if (!IsMigrationRequired(MigrationOptions))
  175. {
  176. RemoveMigrationMenuOption();
  177. return;
  178. }
  179. AkAssetMigration::FMigrationOperations MigrationOperations;
  180. AkAssetMigration::PromptMigration(MigrationOptions, MigrationOperations);
  181. if (MigrationOperations.bCancelled)
  182. {
  183. return;
  184. }
  185. PerformMigration(MigrationOperations);
  186. }
  187. AkAssetMigrationManager::MigrationResult AkAssetMigrationManager::PerformMigration(AkAssetMigration::FMigrationOperations MigrationOperations)
  188. {
  189. UAkSettings* AkSettings = GetMutableDefault<UAkSettings>();
  190. bool bShouldUpdateConfig = false;
  191. const bool bWasUsingEBP = AkSettings->UseEventBasedPackaging;
  192. MigrationResult Result;
  193. // Do bank migration first as users may back out at this point and modifying Wwise settings can lock the Wwise project for WAAPI
  194. bool bContinue= true;
  195. if (MigrationOperations.BankTransferMethod != AkAssetMigration::EBankTransferMode::NoTransfer || MigrationOperations.bDoBankCleanup || MigrationOperations.bTransferAutoload)
  196. {
  197. UE_LOG(LogAudiokineticTools, Display, TEXT("AkAssetMigrationManager: Migrating SoundBanks."));
  198. const bool bSuccess = AkAssetMigration::MigrateAudioBanks(MigrationOperations, MigrationOperations.bDoBankCleanup, bWasUsingEBP, MigrationOperations.bTransferAutoload, MigrationOperations.DefinitionFilePath);
  199. Result.bBankTransferSucceeded = bSuccess;
  200. if (bSuccess)
  201. {
  202. AkSettings->bSoundBanksTransfered = true;
  203. bShouldUpdateConfig = true;
  204. }
  205. else
  206. {
  207. bContinue = false;
  208. if (MigrationOperations.bDoAssetMigration)
  209. {
  210. Result.bAssetMigrationSucceeded = false;
  211. }
  212. if (MigrationOperations.bDoDeprecatedAssetCleanup)
  213. {
  214. Result.bAssetCleanupSucceeded = false;
  215. }
  216. }
  217. }
  218. if (MigrationOperations.bDoAssetMigration && bContinue)
  219. {
  220. UE_LOG(LogAudiokineticTools, Display, TEXT("AkAssetMigrationManager: Migrating Wwise assets."));
  221. TArray<FAssetData> WwiseAssetsInProject;
  222. AkAssetMigration::FindWwiseAssetsInProject(WwiseAssetsInProject);
  223. if (AkAssetMigration::MigrateWwiseAssets(WwiseAssetsInProject, AkSettings->SplitSwitchContainerMedia))
  224. {
  225. AkSettings->bAssetsMigrated = true;
  226. bShouldUpdateConfig = true;
  227. }
  228. else
  229. {
  230. Result.bAssetMigrationSucceeded = false;
  231. }
  232. }
  233. if (MigrationOperations.bDoDeprecatedAssetCleanup && bContinue)
  234. {
  235. UE_LOG(LogAudiokineticTools, Display, TEXT("AkAssetMigrationManager: Deleting deprecated assets."));
  236. TArray<FAssetData> DeprecatedAssetsInProject;
  237. AkAssetMigration::FindDeprecatedAssets(DeprecatedAssetsInProject);
  238. Result.bAssetCleanupSucceeded = AkAssetMigration::DeleteDeprecatedAssets(DeprecatedAssetsInProject);
  239. DeprecatedAssetsInProject.Empty();
  240. }
  241. if (MigrationOperations.bDoProjectUpdate && bContinue)
  242. {
  243. UE_LOG(LogAudiokineticTools, Display, TEXT("AkAssetMigrationManager: Updating project settings."));
  244. if (!bWasUsingEBP)
  245. {
  246. AkSettings->RemoveSoundDataFromAlwaysStageAsUFS(AkSettings->WwiseSoundDataFolder.Path);
  247. AkUnrealEditorHelper::DeleteLegacySoundBanks();
  248. }
  249. else
  250. {
  251. AkSettings->RemoveSoundDataFromAlwaysCook(FString::Printf(TEXT("/Game/%s"), *AkSettings->WwiseSoundDataFolder.Path));
  252. }
  253. Result.bProjectMigrationSucceeded = MigrateProjectSettings(bWasUsingEBP, AkSettings->SplitMediaPerFolder, MigrationOperations.GeneratedSoundBankDirectory);
  254. AkSettings->UpdateGeneratedSoundBanksPath(MigrationOperations.GeneratedSoundBankDirectory);
  255. AkSettings->SplitMediaPerFolder = false;
  256. AkSettings->UseEventBasedPackaging = false;
  257. AkSettings->bProjectMigrated = true;
  258. bShouldUpdateConfig = true;
  259. }
  260. if (bShouldUpdateConfig)
  261. {
  262. if(!AkUnrealEditorHelper::SaveConfigFile(AkSettings))
  263. {
  264. const FString Message = TEXT("Unable to checkout settings file for Wwise integration settings (DefaultGame.ini). Please revert all changes done, and restart the migration process.");
  265. if (FApp::CanEverRender())
  266. {
  267. FMessageDialog::Open(EAppMsgType::Ok, FText::FromString(Message));
  268. }
  269. else
  270. {
  271. UE_LOG(LogAudiokineticTools, Error, TEXT("AkAssetMigrationManager: %s"), *Message);
  272. }
  273. }
  274. }
  275. //Any of these operations may have dirtied some assets, asset migration should handle saving on its own, but might as well be safe.
  276. if ( MigrationOperations.bDoAssetMigration || MigrationOperations.bDoBankCleanup || MigrationOperations.bTransferAutoload || MigrationOperations.bDoDeprecatedAssetCleanup)
  277. {
  278. UE_LOG(LogAudiokineticTools, Display, TEXT("AkAssetMigrationManager: Saving all dirty assets in the project."));
  279. if (!UEditorLoadingAndSavingUtils::SaveDirtyPackages(true, true))
  280. {
  281. UE_LOG(LogAudiokineticTools, Warning, TEXT("AkAssetMigrationManager: Failed to save all dirty packages. Please inspect the log for more details."));
  282. }
  283. }
  284. if (!Result.bAssetCleanupSucceeded || !Result.bAssetMigrationSucceeded || (!Result.bBankTransferSucceeded && !MigrationOperations.bIgnoreBankTransferErrors) || !Result.bProjectMigrationSucceeded)
  285. {
  286. Result.bSuccess = false;
  287. }
  288. if (!FApp::CanEverRender())
  289. {
  290. return Result;
  291. }
  292. FString ResultString = Result.bSuccess ? "Success" : "Failure";
  293. FNotificationInfo Info(FText::Format(LOCTEXT("AkAssetManagementManagerResult", "Migration completed - {0}"), FText::FromString(ResultString)));
  294. Info.Image = FAkAudioStyle::GetBrush(TEXT("AudiokineticTools.AkBrowserTabIcon"));
  295. Info.bFireAndForget = true;
  296. Info.FadeOutDuration = 0.6f;
  297. Info.ExpireDuration = 4.6f;
  298. FSlateNotificationManager::Get().AddNotification(Info);
  299. if (Result.bSuccess)
  300. {
  301. GEditor->PlayEditorSound(TEXT("/Engine/EditorSounds/Notifications/CompileSuccess_Cue.CompileSuccess_Cue"));
  302. }
  303. else
  304. {
  305. GEditor->PlayEditorSound(TEXT("/Engine/EditorSounds/Notifications/CompileFailed_Cue.CompileFailed_Cue"));
  306. }
  307. return Result;
  308. }
  309. bool AkAssetMigrationManager::IsSoundDataPathInDirectoriesToAlwaysStage(const FString& SoundDataPath)
  310. {
  311. UProjectPackagingSettings* PackagingSettings = GetMutableDefault<UProjectPackagingSettings>();
  312. for (int32 i = PackagingSettings->DirectoriesToAlwaysStageAsUFS.Num() - 1; i >= 0; --i)
  313. {
  314. if (PackagingSettings->DirectoriesToAlwaysStageAsUFS[i].Path == SoundDataPath)
  315. {
  316. return true;
  317. }
  318. }
  319. for (int32 i = PackagingSettings->DirectoriesToAlwaysCook.Num() - 1; i >= 0; --i)
  320. {
  321. if (PackagingSettings->DirectoriesToAlwaysCook[i].Path == SoundDataPath)
  322. {
  323. return true;
  324. }
  325. }
  326. return false;
  327. }
  328. void AkAssetMigrationManager::CreateMigrationMenuOption()
  329. {
  330. // Extend the build menu to handle Audiokinetic-specific entries
  331. #if UE_5_0_OR_LATER
  332. {
  333. UToolMenu* BuildMenu = UToolMenus::Get()->ExtendMenu("LevelEditor.MainMenu.Build");
  334. FToolMenuSection& WwiseBuildSection = BuildMenu->AddSection(MigrationMenuSectionName, LOCTEXT("AkBuildLabel", "Audiokinetic Migration"), FToolMenuInsert("LevelEditorGeometry", EToolMenuInsertType::Default));
  335. FUIAction MigrationUIAction;
  336. MigrationUIAction.ExecuteAction.BindRaw(this, &AkAssetMigrationManager::EditorTryMigration);
  337. WwiseBuildSection.AddMenuEntry(
  338. NAME_None,
  339. LOCTEXT("AKAudioBank_PostMigration", "Finish Project Migration"),
  340. LOCTEXT("AkAudioBank_PostMigrationTooltip", "Transfer Bank hierarchy to Wwise, clean up bank files, delete Wwise media assets, clean up Wwise assets"),
  341. FSlateIcon(),
  342. MigrationUIAction
  343. );
  344. }
  345. #else
  346. FLevelEditorModule& LevelEditorModule = FModuleManager::GetModuleChecked<FLevelEditorModule>(TEXT("LevelEditor"));
  347. LevelViewportToolbarBuildMenuExtenderAkMigration = FLevelEditorModule::FLevelEditorMenuExtender::CreateLambda([this](const TSharedRef<FUICommandList> CommandList)
  348. {
  349. TSharedPtr<FExtender> Extender = MakeShared<FExtender>();
  350. Extender->AddMenuExtension("LevelEditorGeometry", EExtensionHook::After, CommandList, FMenuExtensionDelegate::CreateLambda([this](FMenuBuilder& MenuBuilder)
  351. {
  352. MenuBuilder.BeginSection("Audiokinetic Migration", LOCTEXT("AudiokineticMigration", "Audiokinetic Migration"));
  353. {
  354. FUIAction MigrationAction;
  355. MigrationAction.ExecuteAction.BindRaw(this, &AkAssetMigrationManager::EditorTryMigration);
  356. MenuBuilder.AddMenuEntry(
  357. LOCTEXT("AKAudioBank_PostMigration", "Finish Project Migration"),
  358. LOCTEXT("AkAudioBank_PostMigrationTooltip", "Transfer Bank hierarchy to Wwise, clean up bank files, delete Wwise media assets, clean up Wwise assets"),
  359. FSlateIcon(),
  360. MigrationAction
  361. );
  362. }
  363. MenuBuilder.EndSection();
  364. }));
  365. return Extender.ToSharedRef();
  366. });
  367. LevelEditorModule.GetAllLevelEditorToolbarBuildMenuExtenders().Add(LevelViewportToolbarBuildMenuExtenderAkMigration);
  368. LevelViewportToolbarBuildMenuExtenderAkMigrationHandle = LevelEditorModule.GetAllLevelEditorToolbarBuildMenuExtenders().Last().GetHandle();
  369. #endif
  370. }
  371. void AkAssetMigrationManager::RemoveMigrationMenuOption()
  372. {
  373. #if UE_5_0_OR_LATER
  374. UToolMenu* BuildMenu = UToolMenus::Get()->ExtendMenu("LevelEditor.MainMenu.Build");
  375. BuildMenu->RemoveSection(MigrationMenuSectionName);
  376. #else
  377. if (LevelViewportToolbarBuildMenuExtenderAkMigrationHandle.IsValid())
  378. {
  379. if (FModuleManager::Get().IsModuleLoaded("LevelEditor"))
  380. {
  381. auto& LevelEditorModule = FModuleManager::GetModuleChecked<FLevelEditorModule>("LevelEditor");
  382. LevelEditorModule.GetAllLevelEditorToolbarBuildMenuExtenders().RemoveAll([=](const FLevelEditorModule::FLevelEditorMenuExtender& Extender)
  383. {
  384. return Extender.GetHandle() == LevelViewportToolbarBuildMenuExtenderAkMigrationHandle;
  385. });
  386. }
  387. LevelViewportToolbarBuildMenuExtenderAkMigrationHandle.Reset();
  388. }
  389. #endif
  390. }
  391. void AkAssetMigrationManager::ClearSoundBanksForMigration()
  392. {
  393. auto soundBankDirectory = AkUnrealEditorHelper::GetLegacySoundBankDirectory();
  394. TArray<FString> foundFiles;
  395. auto& platformFile = FPlatformFileManager::Get().GetPlatformFile();
  396. platformFile.FindFilesRecursively(foundFiles, *soundBankDirectory, TEXT(".bnk"));
  397. platformFile.FindFilesRecursively(foundFiles, *soundBankDirectory, TEXT(".json"));
  398. if (foundFiles.Num() > 0)
  399. {
  400. platformFile.DeleteDirectoryRecursively(*AkUnrealEditorHelper::GetLegacySoundBankDirectory());
  401. }
  402. }
  403. bool AkAssetMigrationManager::MigrateProjectSettings(const bool bWasUsingEBP, const bool bUseGeneratedSubFolders, const FString& GeneratedSoundBanksFolder)
  404. {
  405. const auto ProjectPath = WwiseUnrealHelper::GetWwiseProjectPath();
  406. FString ProjectContent;
  407. bool bSuccess = FFileHelper::LoadFileToString(ProjectContent, *ProjectPath);
  408. if (bSuccess)
  409. {
  410. bool bModified = AkAssetMigration::MigrateProjectSettings(ProjectContent, bWasUsingEBP, bUseGeneratedSubFolders, GeneratedSoundBanksFolder);
  411. bModified |= AkAssetMigration::SetStandardSettings(ProjectContent);
  412. if (bModified)
  413. {
  414. bSuccess = FFileHelper::SaveStringToFile(ProjectContent, *ProjectPath, FFileHelper::EEncodingOptions::ForceUTF8WithoutBOM);
  415. }
  416. }
  417. return bSuccess;
  418. }
  419. bool AkAssetMigrationManager::SetStandardProjectSettings()
  420. {
  421. const auto ProjectPath = WwiseUnrealHelper::GetWwiseProjectPath();
  422. FString ProjectContent;
  423. bool bSuccess = FFileHelper::LoadFileToString(ProjectContent, *ProjectPath);
  424. if (bSuccess)
  425. {
  426. const bool bModified = AkAssetMigration::SetStandardSettings(ProjectContent);
  427. if (bModified)
  428. {
  429. bSuccess = FFileHelper::SaveStringToFile(ProjectContent, *ProjectPath, FFileHelper::EEncodingOptions::ForceUTF8WithoutBOM);
  430. }
  431. }
  432. return bSuccess;
  433. }
  434. // This whole hack is because Unreal XML classes doesn't
  435. // handle <!CDATA[]> which the Wwise project file use.
  436. // Doing it the dirty way instead.
  437. bool AkAssetMigrationManager::SetGeneratedSoundBanksPath(const FString& ProjectContent, const FString& GeneratedSoundBanksFolder)
  438. {
  439. const auto SoundBankPathPosition = ProjectContent.Find(TEXT("SoundBankHeaderFilePath"));
  440. if (SoundBankPathPosition != INDEX_NONE)
  441. {
  442. const FString ValueDelimiter = TEXT("Value=\"");
  443. const auto SoundBankPathValueStartPosition = ProjectContent.Find(*ValueDelimiter, ESearchCase::IgnoreCase, ESearchDir::FromStart, SoundBankPathPosition) + ValueDelimiter.Len();
  444. if (SoundBankPathValueStartPosition != INDEX_NONE)
  445. {
  446. const auto SoundBankPathValueEndPosition = ProjectContent.Find(TEXT("\""), ESearchCase::IgnoreCase, ESearchDir::FromStart, SoundBankPathValueStartPosition);
  447. if (SoundBankPathValueEndPosition != INDEX_NONE)
  448. {
  449. auto GeneratedPath = ProjectContent.Mid(SoundBankPathValueStartPosition, SoundBankPathValueEndPosition - SoundBankPathValueStartPosition);
  450. if(FPaths::IsRelative(GeneratedPath))
  451. {
  452. auto WwiseProjectDirectory = FPaths::GetPath(WwiseUnrealHelper::GetWwiseProjectPath());
  453. GeneratedPath = FPaths::Combine(WwiseProjectDirectory, GeneratedPath);
  454. }
  455. FPaths::MakePathRelativeTo(GeneratedPath, *FPaths::ProjectContentDir());
  456. UAkSettings* AkSettings = GetMutableDefault<UAkSettings>();
  457. if (AkSettings)
  458. {
  459. AkSettings->UpdateGeneratedSoundBanksPath(GeneratedPath);
  460. return true;
  461. }
  462. }
  463. }
  464. }
  465. return false;
  466. }
  467. #undef LOCTEXT_NAMESPACE