123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878 |
- /*******************************************************************************
- The content of this file includes portions of the proprietary AUDIOKINETIC Wwise
- Technology released in source code form as part of the game integration package.
- The content of this file may not be used without valid licenses to the
- AUDIOKINETIC Wwise Technology.
- Note that the use of the game engine is subject to the Unreal(R) Engine End User
- License Agreement at https://www.unrealengine.com/en-US/eula/unreal
-
- License Usage
-
- Licensees holding valid licenses to the AUDIOKINETIC Wwise Technology may use
- this file in accordance with the end user license agreement provided with the
- software or, alternatively, in accordance with the terms contained
- in a written agreement between you and Audiokinetic Inc.
- Copyright (c) 2023 Audiokinetic Inc.
- *******************************************************************************/
- #include "AkAssetMigrationHelper.h"
- #include "AkAssetDatabase.h"
- #include "AkAudioEvent.h"
- #include "AkAuxBus.h"
- #include "AkDeprecated.h"
- #include "AkAudioBank.h"
- #include "AkWaapiClient.h"
- #include "AkWaapiUtils.h"
- #include "AkMigrationWidgets.h"
- #include "AkCustomVersion.h"
- #include "AkUnrealEditorHelper.h"
- #include "WwiseUnrealHelper.h"
- #include "WwiseDefines.h"
- #include "IAudiokineticTools.h"
- #include "AssetRegistry/AssetRegistryModule.h"
- #include "AssetToolsModule.h"
- #include "WwiseUnrealDefines.h"
- #include "GenericPlatform/GenericPlatformFile.h"
- #if UE_5_0_OR_LATER
- #include "HAL/PlatformFileManager.h"
- #else
- #include "HAL/PlatformFilemanager.h"
- #endif
- #include "ObjectTools.h"
- #include "FileHelpers.h"
- #include "Misc/FileHelper.h"
- #include "IDesktopPlatform.h"
- #include "DesktopPlatformModule.h"
- #include "Interfaces/IMainFrameModule.h"
- #include "Mathematics/APConversion.h"
- #include "Misc/App.h"
- #define LOCTEXT_NAMESPACE "AkAudio"
- namespace AkAssetMigration
- {
- void PromptMigration(const FMigrationContext& MigrationOptions, FMigrationOperations& OutMigrationOperations)
- {
- if (!FApp::CanEverRender())
- {
- OutMigrationOperations.bCancelled =true;
- return;
- }
- TSharedPtr<SWindow> Dialog = SNew(SWindow)
- .Title(LOCTEXT("BankMigrationDialog", "Wwise Integration Migration"))
- .SupportsMaximize(false)
- .SupportsMinimize(false)
- .FocusWhenFirstShown(true)
- .HasCloseButton(false)
- .SizingRule(ESizingRule::Autosized);
- TSharedPtr<SMigrationWidget> MigrationWidget;
- Dialog->SetContent(
- SAssignNew(MigrationWidget, SMigrationWidget)
- .Dialog(Dialog)
- .ShowBankTransfer(MigrationOptions.bBanksInProject)
- .ShowDeprecatedAssetCleanup(MigrationOptions.bDeprecatedAssetsInProject)
- .ShowAssetMigration(MigrationOptions.bAssetsNeedMigration)
- .ShowProjectMigration(MigrationOptions.bProjectSettingsNotUpToDate)
- .NumDeprecatedAssets(MigrationOptions.NumDeprecatedAssetsInProject)
- );
- FSlateApplication::Get().AddModalWindow(Dialog.ToSharedRef(), nullptr);
-
- if (MigrationOptions.bBanksInProject)
- {
- OutMigrationOperations.BankTransferMethod = MigrationWidget->BankTransferWidget->BankTransferMethod;
- OutMigrationOperations.bDoBankCleanup = MigrationWidget->BankTransferWidget->DeleteSoundBanksCheckBox->IsChecked();
- OutMigrationOperations.bTransferAutoload = MigrationWidget->BankTransferWidget->TransferAutoLoadCheckBox->IsChecked();
- OutMigrationOperations.DefinitionFilePath = MigrationWidget->BankTransferWidget->SoundBankDefinitionFilePath;
- }
- if (MigrationOptions.bDeprecatedAssetsInProject)
- {
- OutMigrationOperations.bDoDeprecatedAssetCleanup = MigrationWidget->DeprecatedAssetCleanupWidget->DeleteAssetsCheckBox->IsChecked();
- }
- if (MigrationOptions.bAssetsNeedMigration)
- {
- OutMigrationOperations.bDoAssetMigration = MigrationWidget->AssetMigrationWidget->MigrateAssetsCheckBox->IsChecked();
- }
- if (MigrationOptions.bProjectSettingsNotUpToDate)
- {
- OutMigrationOperations.bDoProjectUpdate = MigrationWidget->ProjectMigrationWidget->AutoMigrateCheckbox->IsChecked();
- OutMigrationOperations.GeneratedSoundBankDirectory = MigrationWidget->ProjectMigrationWidget->GeneratedSoundBanksFolderPickerWidget->GetDirectory();
- }
- OutMigrationOperations.bCancelled = MigrationWidget->bCancel;
- }
- bool PromptFailedBankTransfer(const FString& ErrorMessage)
- {
- if (!FApp::CanEverRender())
- {
- return false;
- }
- TSharedPtr<SWindow> Dialog = SNew(SWindow)
- .Title(LOCTEXT("BankTransfer", "Bank Transfer Failure"))
- .SupportsMaximize(false)
- .SupportsMinimize(false)
- .FocusWhenFirstShown(true)
- .HasCloseButton(false)
- .SizingRule(ESizingRule::Autosized);
- TSharedPtr<SBankMigrationFailureWidget> FailedBankTransferWidget;
- Dialog->SetContent(
- SAssignNew(FailedBankTransferWidget, SBankMigrationFailureWidget)
- .Dialog(Dialog)
- .ErrorMessage(FText::Format( LOCTEXT("BankTransferErrorMessage", "{0}"), FText::FromString(ErrorMessage)))
- );
- FSlateApplication::Get().AddModalWindow(Dialog.ToSharedRef(), nullptr);
- return !FailedBankTransferWidget->bCancel;
- }
-
- FString FormatWaapiErrorMessage(const TArray<FBankTransferError>& ErrorMessages)
- {
- FString CombinedErrors;
- for (auto BankErrors : ErrorMessages)
- {
- if (BankErrors.bHasBankEntry)
- {
- CombinedErrors += "SoundBank: " + BankErrors.BankEntry.BankAssetData.AssetName.ToString() + "\n";
- }
- CombinedErrors += "Error: " + BankErrors.ErrorMessage + "\n";
- if (BankErrors.bHasBankEntry)
- {
- CombinedErrors += "Wwise Assets in SoundBank : \n";
- for (auto LinkedAsset : BankErrors.BankEntry.LinkedEvents)
- {
- CombinedErrors += FString::Format(TEXT("GUID: {0} - Name: {1}\n"), { LinkedAsset.WwiseGuid.ToString(), LinkedAsset.AssetName });
- }
- for (auto LinkedAsset : BankErrors.BankEntry.LinkedAuxBusses)
- {
- CombinedErrors += FString::Format(TEXT("GUID: {0} - Name: {1}\n"), { LinkedAsset.WwiseGuid.ToString(), LinkedAsset.AssetName });
- }
- }
- }
- return CombinedErrors;
- }
- void FindDeprecatedAssets(TArray<FAssetData>& OutDeprecatedAssets)
- {
- OutDeprecatedAssets.Empty();
- FARFilter Filter;
- #if UE_5_1_OR_LATER
- Filter.ClassPaths.Add(UAkMediaAsset::StaticClass()->GetClassPathName());
- Filter.ClassPaths.Add(UAkLocalizedMediaAsset::StaticClass()->GetClassPathName());
- Filter.ClassPaths.Add(UAkExternalMediaAsset::StaticClass()->GetClassPathName());
- Filter.ClassPaths.Add(UAkFolder::StaticClass()->GetClassPathName());
- Filter.ClassPaths.Add(UAkAssetPlatformData::StaticClass()->GetClassPathName());
- #else
- Filter.ClassNames.Add(UAkMediaAsset::StaticClass()->GetFName());
- Filter.ClassNames.Add(UAkLocalizedMediaAsset::StaticClass()->GetFName());
- Filter.ClassNames.Add(UAkExternalMediaAsset::StaticClass()->GetFName());
- Filter.ClassNames.Add(UAkFolder::StaticClass()->GetFName());
- Filter.ClassNames.Add(UAkAssetPlatformData::StaticClass()->GetFName());
- #endif
- auto& AssetRegistryModule = FModuleManager::LoadModuleChecked<FAssetRegistryModule>("AssetRegistry");
- AssetRegistryModule.Get().GetAssets(Filter, OutDeprecatedAssets);
- }
- bool DeleteAssets(const TArray<FAssetData>& InAssetsToDelete)
- {
- /*
- *Deleting an Asset that is referenced somewhere needs a confirmation which is impossible using a commandlet.
- *Calling ForceDelete on the UObjects of the Assets will ignore the confirmation and delete the assets.
- */
- if(!FApp::CanEverRender())
- {
- TArray<UObject*> Objects;
- for(auto Asset : InAssetsToDelete)
- {
- Objects.Add(Asset.GetAsset());
- }
- int DeletedObjects = ObjectTools::ForceDeleteObjects(Objects, false);
- return DeletedObjects == Objects.Num();
- }
- else
- {
- int DeletedObjects = ObjectTools::DeleteAssets(InAssetsToDelete, true);
- return DeletedObjects == InAssetsToDelete.Num();
- }
- }
- bool DeleteDeprecatedAssets(const TArray<FAssetData>& InAssetsToDelete)
- {
- bool bSuccess = true;
- bSuccess &= DeleteAssets(InAssetsToDelete);
-
- const FString MediaFolderPath = FPaths::Combine(AkUnrealEditorHelper::GetLegacySoundBankDirectory(), WwiseUnrealHelper::MediaFolderName);
- IPlatformFile& PlatformFile = FPlatformFileManager::Get().GetPlatformFile();
- PlatformFile.DeleteDirectoryRecursively(*MediaFolderPath);
- const FString LocalizedFolderPath = FPaths::Combine(AkUnrealEditorHelper::GetLegacySoundBankDirectory(), AkUnrealEditorHelper::LocalizedFolderName);
- PlatformFile.DeleteDirectoryRecursively(*LocalizedFolderPath);
- return bSuccess;
- }
- void FindWwiseAssetsInProject(TArray<FAssetData>& OutWwiseAssets)
- {
- FARFilter Filter;
- Filter.bRecursiveClasses = true;
- #if UE_5_1_OR_LATER
- Filter.ClassPaths.Add(UAkAudioType::StaticClass()->GetClassPathName());
- //We want to delete these asset types during cleanup so no need to dirty them
- Filter.RecursiveClassPathsExclusionSet.Add(UAkAudioBank::StaticClass()->GetClassPathName());
- Filter.RecursiveClassPathsExclusionSet.Add(UAkFolder::StaticClass()->GetClassPathName());
- #else
- Filter.ClassNames.Add(UAkAudioType::StaticClass()->GetFName());
- Filter.RecursiveClassesExclusionSet.Add(UAkAudioBank::StaticClass()->GetFName());
- Filter.RecursiveClassesExclusionSet.Add(UAkFolder::StaticClass()->GetFName());
- #endif
- FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked<FAssetRegistryModule>("AssetRegistry");
- AssetRegistryModule.Get().GetAssets(Filter, OutWwiseAssets);
- }
- bool MigrateWwiseAssets(const TArray<FAssetData> & WwiseAssets, bool bShouldSplitSwitchContainerMedia)
- {
- TArray<UPackage*> WwisePackagesToSave;
- EWwiseEventSwitchContainerLoading SwitchContainerShouldLoad = bShouldSplitSwitchContainerMedia
- ? EWwiseEventSwitchContainerLoading::LoadOnReference
- : EWwiseEventSwitchContainerLoading::AlwaysLoad;
- for (auto& Asset : WwiseAssets)
- {
- UAkAudioType* AssetPtr = Cast<UAkAudioType>(Asset.GetAsset());
- if (AssetPtr)
- {
- AssetPtr->MigrateWwiseObjectInfo();
- if (AssetPtr->GetClass() == UAkAudioEvent::StaticClass())
- {
- UAkAudioEvent* Event = Cast<UAkAudioEvent>(AssetPtr);
- Event->EventInfo.SwitchContainerLoading = SwitchContainerShouldLoad;
- }
- if (!AssetPtr->MarkPackageDirty())
- {
- UE_LOG(LogAudiokineticTools, Warning, TEXT("Could not dirty asset %s during migration, will still try to save it."), *AssetPtr->GetFullName());
- }
- WwisePackagesToSave.Add(AssetPtr->GetPackage());
- }
- else
- {
- UE_LOG(LogAudiokineticTools, Error, TEXT("Could not get asset '%s' in order to migrate it."), *Asset.AssetName.ToString());
- }
- }
- if (WwisePackagesToSave.Num() > 0)
- {
- if (!UEditorLoadingAndSavingUtils::SavePackages(WwisePackagesToSave, false))
- {
- UE_LOG(LogAudiokineticTools, Warning, TEXT("MigrateWwiseAssets: Could not save assets during asset migration. Please save them manually, or run the migration operation again."));
- return false;
- }
- }
- return true;
- }
- bool MigrateAudioBanks(const FMigrationOperations& MigrationOperations, const bool bCleanupAssets, const bool bWasUsingEBP, const bool bTransferAutoLoad, const FString DefinitionFile)
- {
- TSet<FAssetData> FailedBanks;
- TMap<FString, FBankEntry> BanksToTransfer;
- FillBanksToTransfer(BanksToTransfer);
- const bool bIncludeMedia = !bWasUsingEBP;
- bool bContinueMigration = true;
- bool bTransferSuccess = true;
- FString ErrorMessage;
- if (MigrationOperations.BankTransferMethod == EBankTransferMode::WAAPI)
- {
- TArray<FBankTransferError> ErrorMessages = TransferUserBanksWaapi( BanksToTransfer, FailedBanks, bIncludeMedia);
- ErrorMessage = FormatWaapiErrorMessage(ErrorMessages);
- bTransferSuccess = FailedBanks.Num() == 0;
- }
- else if (MigrationOperations.BankTransferMethod == EBankTransferMode::DefinitionFile)
- {
- auto Result = WriteBankDefinitionFile( BanksToTransfer, bIncludeMedia, DefinitionFile);
- bTransferSuccess = Result == Success;
- if (!bTransferSuccess)
- {
- switch (Result)
- {
- case OpenFailure:
- ErrorMessage = FString::Format(TEXT("Failed to open bank definition file for write '{0}'."), {DefinitionFile});
- break;
- case WriteFailure:
- ErrorMessage = FString::Format(TEXT("Failed to write to bank definition file '{0}'."), {DefinitionFile});
- break;
- default:
- break;
- }
- }
- }
- if (!bTransferSuccess)
- {
- if (!FApp::CanEverRender())
- {
- bContinueMigration = MigrationOperations.bIgnoreBankTransferErrors;
- }
- else //Migrating in Unreal Editor
- {
- bContinueMigration = PromptFailedBankTransfer(ErrorMessage);
- }
- }
- if (!bContinueMigration)
- {
- UE_LOG(LogAudiokineticTools, Error, TEXT("MigrateAudioBanks : Errors encountered while transferring SoundBanks: \n%s"), *ErrorMessage);
- UE_LOG(LogAudiokineticTools, Error, TEXT("MigrateAudioBanks : Migration aborted due to SoundBank transfer errors."));
- return false;
- }
- if (!ErrorMessage.IsEmpty())
- {
- UE_LOG(LogAudiokineticTools, Warning, TEXT("MigrateAudioBanks : Errors encountered while transferring SoundBanks: \n%s"), *ErrorMessage);
- UE_LOG(LogAudiokineticTools, Display, TEXT("MigrateAudioBanks : Migration will continue and ignore SoundBank transfer errors."));
- }
- if (bTransferAutoLoad)
- {
- UE_LOG(LogAudiokineticTools, Display, TEXT("MigrateAudioBanks: Transferring AutoLoad setting from AkAudioBank assets to Event and Aux Bus assets."));
- for (auto& Bank : BanksToTransfer)
- {
- UAkAudioBank* BankAsset = Cast<UAkAudioBank>(Bank.Value.BankAssetData.GetAsset());
- if (!BankAsset)
- {
- #if UE_5_1_OR_LATER
- UE_LOG(LogAudiokineticTools, Warning, TEXT("MigrateAudioBanks: Could not load UAkAudioBank Asset '%s'. AutoLoad property will not be transferred. "),
- *Bank.Value.BankAssetData.GetObjectPathString());
- #else
- UE_LOG(LogAudiokineticTools, Warning, TEXT("MigrateAudioBanks: Could not load UAkAudioBank Asset '%s'. AutoLoad property will not be transferred. "),
- *Bank.Value.BankAssetData.ObjectPath.ToString());
- #endif
- continue;
- }
- if (!BankAsset->AutoLoad_DEPRECATED)
- {
- TArray<FLinkedAssetEntry>& LinkedAuxBusses = Bank.Value.LinkedAuxBusses;
- TArray<FLinkedAssetEntry>& LinkedEvents = Bank.Value.LinkedEvents;
- for (auto& LinkedAuxBus : LinkedAuxBusses)
- {
- bool MigrateSuccess = false;
- auto FoundAssetData = AkAssetDatabase::Get().FindAssetByObjectPath(LinkedAuxBus.AssetPath);
- if (FoundAssetData.IsValid())
- {
- if (auto* BusAsset = Cast<UAkAuxBus>(FoundAssetData.GetAsset()))
- {
- BusAsset->bAutoLoad = false;
- MigrateSuccess = BusAsset->MarkPackageDirty();
- }
- }
- if(!MigrateSuccess)
- {
- UE_LOG(LogAudiokineticTools, Warning, TEXT("MigrateAudioBanks: Could not successfully disable AutoLoad on AuxBus asset %s during migration. It will be automatically loaded."), *LinkedAuxBus.AssetPath);
- }
- }
- for (auto& LinkedEvent : LinkedEvents)
- {
- bool MigrateSuccess = false;
- auto FoundAssetData = AkAssetDatabase::Get().FindAssetByObjectPath(LinkedEvent.AssetPath);
- if (FoundAssetData.IsValid())
- {
- if (auto* EventAsset = Cast<UAkAudioEvent>(FoundAssetData.GetAsset()))
- {
- EventAsset->bAutoLoad = false;
- MigrateSuccess = EventAsset->MarkPackageDirty();
- }
- }
- if (!MigrateSuccess)
- {
- UE_LOG(LogAudiokineticTools, Warning, TEXT("MigrateAudioBanks: Could not successfully disable AutoLoad on Event asset %s during migration. It will be automatically loaded."), *LinkedEvent.AssetPath);
- }
- }
- }
- }
- }
- if (bCleanupAssets)
- {
- UE_LOG(LogAudiokineticTools, Display, TEXT("MigrateAudioBanks: Deleting deprecated AkAudioBank assets."));
- TSet<FAssetData> ProjectBanks;
- for (auto Bank : BanksToTransfer)
- {
- ProjectBanks.Add(Bank.Value.BankAssetData);
- }
- TArray<FAssetData> BanksToDelete = ProjectBanks.Array();
- DeleteAssets(BanksToDelete);
- }
- return true;
- }
- void FillBanksToTransfer(TMap<FString, FBankEntry>& BanksToTransfer)
- {
- auto& AssetRegistryModule = FModuleManager::LoadModuleChecked<FAssetRegistryModule>("AssetRegistry");
- auto& AssetRegistry = AssetRegistryModule.Get();
- TArray<FAssetData> Banks;
- #if UE_5_1_OR_LATER
- AssetRegistry.GetAssetsByClass(UAkAudioBank::StaticClass()->GetClassPathName(), Banks);
- #else
- AssetRegistry.GetAssetsByClass(UAkAudioBank::StaticClass()->GetFName(), Banks);
- #endif
- for (FAssetData& BankData : Banks)
- {
- FString BankName = BankData.AssetName.ToString();
- BanksToTransfer.Add(BankName, { BankData, {}, {} });
- }
- TArray< FAssetData> Events;
- #if UE_5_1_OR_LATER
- AssetRegistry.GetAssetsByClass(UAkAudioEvent::StaticClass()->GetClassPathName(), Events);
- #else
- AssetRegistry.GetAssetsByClass(UAkAudioEvent::StaticClass()->GetFName(), Events);
- #endif
- for (FAssetData EventData : Events)
- {
- if (UAkAudioEvent* Event = Cast<UAkAudioEvent>(EventData.GetAsset()))
- {
- if (Event->RequiredBank_DEPRECATED != nullptr)
- {
- FString BankName = Event->RequiredBank_DEPRECATED->GetName();
- FLinkedAssetEntry EventEntry = { Event->GetName(), Event->EventInfo.WwiseGuid, Event->GetPathName() };
- if (BanksToTransfer.Contains(BankName))
- {
- BanksToTransfer[BankName].LinkedEvents.Add(EventEntry);
- }
- else
- {
- FAssetData BankAssetData = FAssetData(Event->RequiredBank_DEPRECATED);
- BanksToTransfer.Add(BankName, { BankAssetData, {EventEntry}, {} });
- }
- }
- }
- }
- TArray< FAssetData> AuxBusses;
- #if UE_5_1_OR_LATER
- AssetRegistry.GetAssetsByClass(UAkAuxBus::StaticClass()->GetClassPathName(), AuxBusses);
- #else
- AssetRegistry.GetAssetsByClass(UAkAuxBus::StaticClass()->GetFName(), AuxBusses);
- #endif
- for (FAssetData AuxBusData : AuxBusses)
- {
- if (UAkAuxBus* AuxBus = Cast<UAkAuxBus>(AuxBusData.GetAsset()))
- {
- if (AuxBus->RequiredBank_DEPRECATED != nullptr)
- {
- FString BankName = AuxBus->RequiredBank_DEPRECATED->GetName();
- FLinkedAssetEntry AuxBusEntry = { AuxBus->GetName(), AuxBus->AuxBusInfo.WwiseGuid, AuxBus->GetPathName() };
- if (BanksToTransfer.Contains(BankName))
- {
- BanksToTransfer[BankName].LinkedAuxBusses.Add(AuxBusEntry);
- }
- else
- {
- FAssetData BankAssetData = FAssetData(AuxBus->RequiredBank_DEPRECATED);
- BanksToTransfer.Add(BankName, { BankAssetData, {}, {AuxBusEntry} });
- }
- }
- }
- }
- UE_LOG(LogAudiokineticTools, Display, TEXT("MigrateAudioBanks: Found %d SoundBank assets in project."), BanksToTransfer.Num());
- }
- TArray<FBankTransferError> TransferUserBanksWaapi(const TMap<FString, FBankEntry>& InBanksToTransfer, TSet<FAssetData>& OutFailedBanks, const bool bIncludeMedia)
- {
- UE_LOG(LogAudiokineticTools, Display, TEXT("MigrateAudioBanks: Transfering SoundBanks with WAAPI."));
- TArray<FBankTransferError> ErrorMessages;
- for (TPair<FString, FBankEntry > BankEntry : InBanksToTransfer)
- {
- FGuid BankID;
- if (!CreateBankWaapi(BankEntry.Key, BankEntry.Value, BankID, ErrorMessages))
- {
- OutFailedBanks.Add(BankEntry.Value.BankAssetData);
- continue;
- }
- if (!SetBankIncludesWaapi(BankEntry.Value, BankID, bIncludeMedia, ErrorMessages))
- {
- OutFailedBanks.Add(BankEntry.Value.BankAssetData);
- }
- }
- SaveProjectWaapi(ErrorMessages);
- return ErrorMessages;
- }
- EDefinitionFileCreationResult WriteBankDefinitionFile(const TMap<FString, FBankEntry>& InBanksToTransfer, const bool bIncludeMedia, const FString DefinitionFilePath)
- {
- UE_LOG(LogAudiokineticTools, Display, TEXT("MigrateAudioBanks: Writing SoundBanks Definition File to '%s'."), *DefinitionFilePath);
- // open file to start writing
- IPlatformFile* PlatformFile = &FPlatformFileManager::Get().GetPlatformFile();;
- FString FileLocation = IFileManager::Get().ConvertToRelativePath(*DefinitionFilePath);
- TUniquePtr<IFileHandle> FileWriter = TUniquePtr<IFileHandle>(PlatformFile->OpenWrite(*FileLocation));
- if (!FileWriter.IsValid())
- {
- return OpenFailure;
- }
- bool bWriteSuccess = true;
- for (TPair<FString, FBankEntry > BankEntry : InBanksToTransfer)
- {
- bWriteSuccess &= WriteBankDefinition(BankEntry.Value, FileWriter, bIncludeMedia);
- }
- if (!bWriteSuccess)
- {
- return WriteFailure;
- }
- FileWriter->Flush();
- return Success;
- }
- bool WriteBankDefinition(const FBankEntry& BankEntry, TUniquePtr<IFileHandle>& FileWriter, const bool bIncludeMedia)
- {
- bool bWriteSuccess = true;
- FString MediaString = bIncludeMedia? "\tMedia": "";
- for (FLinkedAssetEntry Event : BankEntry.LinkedEvents)
- {
- auto Line = BankEntry.BankAssetData.AssetName.ToString() + TEXT("\t\"") + Event.AssetName + TEXT("\"") + TEXT("\tEvent") + MediaString + TEXT("\tStructure") + LINE_TERMINATOR;
- FTCHARToUTF8 Utf8Formatted(*Line);
- bWriteSuccess &= FileWriter->Write(reinterpret_cast<const uint8*>(Utf8Formatted.Get()), Utf8Formatted.Length());
- }
- for (FLinkedAssetEntry Bus : BankEntry.LinkedAuxBusses)
- {
- auto Line = BankEntry.BankAssetData.AssetName.ToString() + TEXT("\t-AuxBus\t\"") + Bus.AssetName + TEXT("\"") + MediaString + TEXT("\tStructure") + LINE_TERMINATOR;
- FTCHARToUTF8 Utf8Formatted(*Line);
- bWriteSuccess &= FileWriter->Write(reinterpret_cast<const uint8*>(Utf8Formatted.Get()), Utf8Formatted.Length());
- }
- return bWriteSuccess;
- }
- bool CreateBankWaapi(const FString& BankName, const FBankEntry& BankEntry, FGuid& OutBankGuid, TArray<FBankTransferError>& ErrorMessages)
- {
- #if AK_SUPPORT_WAAPI
- FAkWaapiClient* WaapiClient = FAkWaapiClient::Get();
- if (!WaapiClient)
- {
- UE_LOG(LogAudiokineticTools, Warning, TEXT("Failed to create SoundBank for <%s>. \nCould not get WAAPI Client."), *BankEntry.BankAssetData.PackageName.ToString());
- ErrorMessages.Add({"Could not get WAAPI Client", true, BankEntry});
- return false;
- }
- else if (!WaapiClient->IsConnected())
- {
- UE_LOG(LogAudiokineticTools, Warning, TEXT("Failed to create SoundBank for <%s>. \nWAAPI Client not connected."), *BankEntry.BankAssetData.PackageName.ToString());
- ErrorMessages.Add({"WAAPI Client not connected", true, BankEntry});
- return false;
- }
- TSharedRef<FJsonObject> Args = MakeShared<FJsonObject>();
- Args->SetStringField(WwiseWaapiHelper::PARENT, TEXT("\\SoundBanks\\Default Work Unit"));
- Args->SetStringField(WwiseWaapiHelper::ON_NAME_CONFLICT, WwiseWaapiHelper::RENAME);
- Args->SetStringField(WwiseWaapiHelper::TYPE, WwiseWaapiHelper::SOUNDBANK_TYPE);
- Args->SetStringField(WwiseWaapiHelper::NAME, BankName);
- TSharedRef<FJsonObject> Options = MakeShared<FJsonObject>();
- TSharedPtr<FJsonObject> Result;
- FString IdString;
- if (!WaapiClient->Call(ak::wwise::core::object::create, Args, Options, Result))
- {
- FString ErrorMessage;
- if (Result.IsValid())
- {
- Result->TryGetStringField(TEXT("message"), ErrorMessage);
- }
- UE_LOG(LogAudiokineticTools, Warning, TEXT("Failed to create SoundBank for <%s>.\nMessage : <%s>."), *BankEntry.BankAssetData.PackageName.ToString(), *ErrorMessage);
- ErrorMessages.Add({ErrorMessage, true, BankEntry});
- return false;
- }
- if (Result.IsValid() && !Result->TryGetStringField(WwiseWaapiHelper::ID, IdString))
- {
- FString ErrorMessage;
- if (Result.IsValid())
- {
- Result->TryGetStringField(TEXT("message"), ErrorMessage);
- }
- UE_LOG(LogAudiokineticTools, Warning, TEXT("Failed to create SoundBank for <%s>.\nMessage : <%s>."), *BankEntry.BankAssetData.PackageName.ToString(), *ErrorMessage);
- ErrorMessages.Add({ErrorMessage, true, BankEntry});
- return false; // error parsing Json
- }
- FGuid::ParseExact(IdString, EGuidFormats::DigitsWithHyphensInBraces, OutBankGuid);
- return true;
- #else
- UE_LOG(LogAudiokineticTools, Error, TEXT("SetBankIncludesWaapi: WAAPI not supported"));
- ErrorMessages.Add({TEXT("WAAPI not supported"), false, {}});
- return false;
- #endif
- }
- bool SetBankIncludesWaapi(const FBankEntry& BankEntry, const FGuid& BankId, const bool bIncludeMedia, TArray<FBankTransferError>& ErrorMessages)
- {
- #if AK_SUPPORT_WAAPI
- FAkWaapiClient* WaapiClient = FAkWaapiClient::Get();
- if (!WaapiClient)
- {
- UE_LOG(LogAudiokineticTools, Warning, TEXT("WAAPI command to add Wwise objects to SoundBank '%s' failed. \nCould not get WAAPI Client."), *BankEntry.BankAssetData.PackageName.ToString());
- ErrorMessages.Add({"Could not get WAAPI Client", true, BankEntry});
- return false;
- }
- else if (!WaapiClient->IsConnected())
- {
- UE_LOG(LogAudiokineticTools, Warning, TEXT("WAAPI command to add Wwise objects to SoundBank '%s' failed. \nWAAPI Client not connected."), *BankEntry.BankAssetData.PackageName.ToString());
- ErrorMessages.Add({"WAAPI Client not connected", true, BankEntry});
- return false;
- }
- TSet<FString> IncludeIds;
- for (FLinkedAssetEntry Event : BankEntry.LinkedEvents)
- {
- if (Event.WwiseGuid.IsValid())
- {
- IncludeIds.Add(Event.WwiseGuid.ToString(EGuidFormats::DigitsWithHyphensInBraces));
- }
- else
- {
- IncludeIds.Add(TEXT("Event:") + Event.AssetName);
- }
- }
- for (FLinkedAssetEntry AuxBus : BankEntry.LinkedAuxBusses)
- {
- if (AuxBus.WwiseGuid.IsValid())
- {
- IncludeIds.Add(AuxBus.WwiseGuid.ToString(EGuidFormats::DigitsWithHyphensInBraces));
- }
- else
- {
- IncludeIds.Add(TEXT("AuxBus:") + AuxBus.AssetName);
- }
- }
- if (IncludeIds.Num() < 0)
- {
- return true;
- }
- TArray<TSharedPtr<FJsonValue>> Filters;
- Filters.Add(MakeShared< FJsonValueString>(TEXT("events")));
- Filters.Add(MakeShared< FJsonValueString>(TEXT("structures")));
- if (bIncludeMedia)
- {
- Filters.Add(MakeShared< FJsonValueString>(TEXT("media")));
- }
- TArray<TSharedPtr<FJsonValue>> IncludeIdJson;
- for (const FString IncludedId : IncludeIds)
- {
- TSharedPtr<FJsonObject> IncludedObject = MakeShared< FJsonObject>();
- IncludedObject->SetStringField(WwiseWaapiHelper::OBJECT, IncludedId);
- IncludedObject->SetArrayField(WwiseWaapiHelper::FILTER, Filters);
- IncludeIdJson.Add(MakeShared< FJsonValueObject>(IncludedObject));
- }
- TSharedRef<FJsonObject> Args = MakeShared<FJsonObject>();
- Args->SetStringField(WwiseWaapiHelper::SOUNDBANK_FIELD, BankId.ToString(EGuidFormats::DigitsWithHyphensInBraces));
- Args->SetStringField(WwiseWaapiHelper::OPERATION, TEXT("add"));
- Args->SetArrayField(WwiseWaapiHelper::INCLUSIONS, IncludeIdJson);
- TSharedRef<FJsonObject> Options = MakeShared<FJsonObject>();
- TSharedPtr<FJsonObject> Result;
- if (!WaapiClient->Call(ak::wwise::core::soundbank::setInclusions, Args, Options, Result))
- {
- FString ErrorMessage;
- if (Result.IsValid())
- {
- Result->TryGetStringField(TEXT("message"), ErrorMessage);
- }
- UE_LOG(LogAudiokineticTools, Warning, TEXT("WAAPI command to add Wwise objects to SoundBank '%s' failed. \nError Message : <%s>."), *BankEntry.BankAssetData.PackageName.ToString(), *ErrorMessage);
- ErrorMessages.Add({ErrorMessage, true, BankEntry});
- return false;
- }
- return true;
- #else
- UE_LOG(LogAudiokineticTools, Error, TEXT("SetBankIncludesWaapi: WAAPI not supported"));
- ErrorMessages.Add({TEXT("WAAPI not supported"), false, {}});
- return false;
- #endif
- }
-
- bool SaveProjectWaapi(TArray<FBankTransferError>& ErrorMessages)
- {
- #if AK_SUPPORT_WAAPI
- FAkWaapiClient* WaapiClient = FAkWaapiClient::Get();
- if (!WaapiClient)
- {
- UE_LOG(LogAudiokineticTools, Warning, TEXT("Failed to save Wwise project.\n Could not get Waapi Client."));
- ErrorMessages.Add({TEXT("Failed to save Wwise project over WAAPI. Please save the project manually."), false, {}});
- return false;
- }
- else if (!WaapiClient->IsConnected())
- {
- UE_LOG(LogAudiokineticTools, Warning, TEXT("Failed to save Wwise project.\n Waapi Client not connected."));
- ErrorMessages.Add({TEXT("Failed to save Wwise project over WAAPI. Please save the project manually."), false, {}});
- return false;
- }
- TSharedRef<FJsonObject> Args = MakeShared<FJsonObject>();
- TSharedRef<FJsonObject> Options = MakeShared<FJsonObject>();
- TSharedPtr<FJsonObject> Result;
- FString IdString;
- if (!WaapiClient->Call(ak::wwise::core::project::save, Args, Options, Result))
- {
- FString ErrorMessage;
- if (Result.IsValid())
- {
- Result->TryGetStringField(TEXT("message"), ErrorMessage);
- }
- UE_LOG(LogAudiokineticTools, Warning, TEXT("Failed to save Wwise project.\nMessage : <%s>."), *ErrorMessage);
- ErrorMessages.Add({TEXT("Failed to save Wwise project over WAAPI. Please save the project manually."), false, {}});
- ErrorMessages.Add({ErrorMessage, false, {}});
- return false;
- }
- return true;
- #else
- UE_LOG(LogAudiokineticTools, Error, TEXT("SetBankIncludesWaapi: WAAPI not supported"));
- ErrorMessages.Add({TEXT("WAAPI not supported"), false, {}});
- return false;
- #endif
- }
- bool MigrateProjectSettings(FString& ProjectContent, const bool bWasUsingEBP, const bool bUseGeneratedSubFolders, const FString& GeneratedSoundBanksFolder )
- {
- //migrate split media per id
- TArray<PropertyToChange> PropertiesToAdd;
- if (bWasUsingEBP)
- {
- PropertiesToAdd.Add({ TEXT("AutoSoundBankEnabled"), TEXT("True"), TEXT("<Property Name=\"AutoSoundBankEnabled\" Type=\"bool\" Value=\"True\"/>") });
- }
- if (bUseGeneratedSubFolders)
- {
- PropertiesToAdd.Add({ TEXT("MediaAutoBankSubFolders"), TEXT("True"), TEXT("<Property Name=\"MediaAutoBankSubFolders\" Type=\"bool\" Value=\"True\"/>") });
- }
- static const TArray<FString> LogCentralItemsToRemove =
- {
- TEXT("<IgnoreItem MessageId=\"MediaDuplicated\"/>"),
- TEXT("<IgnoreItem MessageId=\"MediaNotFound\"/>")
- };
- bool bModified = false;
- if (PropertiesToAdd.Num() >0)
- {
- bModified = InsertProperties(PropertiesToAdd, ProjectContent);
- }
- for (const FString& LogItemToRemove : LogCentralItemsToRemove)
- {
- if (ProjectContent.Contains(LogItemToRemove))
- {
- ProjectContent.ReplaceInline(*LogItemToRemove, TEXT(""));
- bModified = true;
- }
- }
- return bModified;
- }
-
- bool SetStandardSettings(FString& ProjectContent)
- {
- static const TArray<PropertyToChange> PropertiesToAdd = {
- { TEXT("GenerateMultipleBanks"), TEXT("True"), TEXT("<Property Name=\"GenerateMultipleBanks\" Type=\"bool\" Value=\"True\"/>") },
- { TEXT("GenerateSoundBankJSON"), TEXT("True"), TEXT("<Property Name=\"GenerateSoundBankJSON\" Type=\"bool\" Value=\"True\"/>") },
- { TEXT("SoundBankGenerateEstimatedDuration"), TEXT("True"), TEXT("<Property Name=\"SoundBankGenerateEstimatedDuration\" Type=\"bool\" Value=\"True\"/>") },
- { TEXT("SoundBankGenerateMaxAttenuationInfo"), TEXT("True"), TEXT("<Property Name=\"SoundBankGenerateMaxAttenuationInfo\" Type=\"bool\" Value=\"True\"/>") },
- { TEXT("SoundBankGeneratePrintGUID"), TEXT("True"), TEXT("<Property Name=\"SoundBankGeneratePrintGUID\" Type=\"bool\" Value=\"True\"/>") },
- { TEXT("SoundBankGeneratePrintPath"), TEXT("True"), TEXT("<Property Name=\"SoundBankGeneratePrintPath\" Type=\"bool\" Value=\"True\"/>") },
- { TEXT("CopyLooseStreamedMedia"), TEXT("True"), TEXT("<Property Name=\"CopyLooseStreamedMedia\" Type=\"bool\" Value=\"True\"/>") },
- { TEXT("RemoveUnusedGeneratedFiles"), TEXT("True"), TEXT("<Property Name=\"RemoveUnusedGeneratedFiles\" Type=\"bool\" Value=\"True\"/>") },
- };
- return InsertProperties(PropertiesToAdd, ProjectContent);
- }
- bool InsertProperties(const TArray<PropertyToChange>& PropertiesToChange, FString& ProjectContent)
- {
- static const auto PropertyListStart = TEXT("<PropertyList>");
- static const FString EndTag = TEXT(">");
- static const TCHAR EmptyElementEndChar = '/';
- static const FString ValueTag = TEXT("<Value>");
- static const FString EndValueTag = TEXT("</Value>");
- static const FString ValueAttribute = TEXT("Value=\"");
- static const FString EndValueAttribute = TEXT("\"");
- bool bModified = false;
- int32 PropertyListPosition = ProjectContent.Find(PropertyListStart);
- if (PropertyListPosition != -1)
- {
- int32 InsertPosition = PropertyListPosition + FCString::Strlen(PropertyListStart);
- for (PropertyToChange ItemToAdd : PropertiesToChange)
- {
- auto idx = ProjectContent.Find(ItemToAdd.Name);
- if (idx == -1)
- {
- ProjectContent.InsertAt(InsertPosition, FString::Printf(TEXT("\n\t\t\t\t%s"), *ItemToAdd.Xml));
- bModified = true;
- }
- else
- {
- FString ValueText;
- FString EndValueText;
- int32 EndTagIdx = ProjectContent.Find(EndTag, ESearchCase::IgnoreCase, ESearchDir::FromStart, idx);
- if (ProjectContent[EndTagIdx - 1] == EmptyElementEndChar)
- {
- // The property is an empty element, the value will be in an attribute
- ValueText = ValueAttribute;
- EndValueText = EndValueAttribute;
- }
- else
- {
- // We are in a ValueList
- ValueText = ValueTag;
- EndValueText = EndValueTag;
- }
- int32 ValueIdx = ProjectContent.Find(ValueText, ESearchCase::IgnoreCase, ESearchDir::FromStart, idx);
- int32 EndValueIdx = ProjectContent.Find(EndValueText, ESearchCase::IgnoreCase, ESearchDir::FromStart, ValueIdx);
- if (ValueIdx != -1 && ValueIdx > idx && ValueIdx < EndValueIdx)
- {
- ValueIdx += ValueText.Len();
- auto ValueEndIdx = ProjectContent.Find(EndValueText, ESearchCase::IgnoreCase, ESearchDir::FromStart, ValueIdx);
- if (ValueEndIdx != -1)
- {
- FString value = ProjectContent.Mid(ValueIdx, ValueEndIdx - ValueIdx);
- if (value != ItemToAdd.Value)
- {
- ProjectContent.RemoveAt(ValueIdx, ValueEndIdx - ValueIdx, false);
- ProjectContent.InsertAt(ValueIdx, ItemToAdd.Value);
- bModified = true;
- }
- }
- }
- else
- {
- UE_LOG(LogAudiokineticTools, Warning, TEXT("Could not change value for %s in Wwise project. Some features might not work properly."), *ItemToAdd.Name);
- }
- }
- }
- }
- return bModified;
- }
- }
- #undef LOCTEXT_NAMESPACE
|