12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169 |
- /*******************************************************************************
- 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 "WaapiDataSource.h"
- #include "AkSettings.h"
- #include "AkSettingsPerUser.h"
- #include "AkWaapiUtils.h"
- #include "IAudiokineticTools.h"
- #include "PackageTools.h"
- #include "WwiseItemType.h"
- #include "Async/Async.h"
- #include "Dom/JsonObject.h"
- #include "Misc/Paths.h"
- #include "WaapiPicker/WwiseTreeItem.h"
- FWaapiDataSource::~FWaapiDataSource()
- {
- TearDown();
- }
- bool FWaapiDataSource::Init()
- {
- auto WaapiClient = FAkWaapiClient::Get();
- if (!WaapiClient)
- {
- UE_LOG(LogAudiokineticTools, Log, TEXT("Failed to get the Waapi client."));
- return false;
- }
- ProjectLoadedHandle = WaapiClient->OnProjectLoaded.AddRaw(
- this, &FWaapiDataSource::OnProjectLoadedCallback);
- ConnectionLostHandle = WaapiClient->OnConnectionLost.AddRaw(
- this, &FWaapiDataSource::OnConnectionLostCallback);
- ClientBeginDestroyHandle = WaapiClient->OnClientBeginDestroy.AddRaw(
- this, &FWaapiDataSource::OnWaapiClientBeginDestroyCallback);
- SubscribeWaapiCallbacks();
- return true;
- }
- bool FWaapiDataSource::TearDown()
- {
- auto WaapiClient = FAkWaapiClient::Get();
- if (!WaapiClient)
- {
- UE_LOG(LogAudiokineticTools, Log, TEXT("Failed to get the Waapi client."));
- return false;
- }
- if (ProjectLoadedHandle.IsValid())
- {
- WaapiClient->OnProjectLoaded.Remove(ProjectLoadedHandle);
- ProjectLoadedHandle.Reset();
- }
- if (ConnectionLostHandle.IsValid())
- {
- WaapiClient->OnConnectionLost.Remove(ConnectionLostHandle);
- ConnectionLostHandle.Reset();
- }
- RemoveClientCallbacks();
- WaapiClient->OnClientBeginDestroy.Remove(ClientBeginDestroyHandle);
- return true;
- }
- void FWaapiDataSource::ConstructTree(bool bShouldRefresh)
- {
- if (IsProjectLoaded() != EWwiseConnectionStatus::Connected)
- {
- UE_LOG(LogAudiokineticTools, Log, TEXT("Failed to construct Waapi Tree. The Wwise project is not connected."));
- return;
- }
- {
- FScopeLock AutoLock(&WaapiRootItemsLock);
- RootItems.Empty();
- NodesByPath.Empty();
- }
- for (int i = EWwiseItemType::Event; i <= EWwiseItemType::LastWwiseBrowserType; ++i)
- {
- FWwiseTreeItemPtr TreeRoot = ConstructTreeRoot(static_cast<EWwiseItemType::Type>(i));
- {
- FScopeLock AutoLock(&WaapiRootItemsLock);
- RootItems.Add(TreeRoot);
- NodesByPath.Add(TreeRoot->FolderPath, TreeRoot);
- LoadChildren(TreeRoot);
- }
- }
- if(bShouldRefresh)
- {
- WaapiDataSourceRefreshed.ExecuteIfBound();
- }
- }
- FWwiseTreeItemPtr FWaapiDataSource::ConstructTreeRoot(EWwiseItemType::Type Type)
- {
- FGuid InItemGuid = FGuid();
- uint32 ShortId = 0;
- TSharedPtr<FJsonObject> Result;
- uint32_t ItemChildrenCount = 0;
- FString Path = WwiseWaapiHelper::BACK_SLASH + EWwiseItemType::FolderNames[static_cast<int>(Type)];
- if (IsProjectLoaded() != EWwiseConnectionStatus::Connected)
- {
- UE_LOG(LogAudiokineticTools, Log, TEXT("Failed to construct Waapi Root Items. The Wwise project is not connected."));
- return nullptr;
- }
- // Get the root item of the given hierarchy using its path
- if (LoadWaapiInfo(WwiseWaapiHelper::PATH, Path, Result, {}))
- {
- const TSharedPtr<FJsonObject> ItemInfoObj = Result->GetArrayField(WwiseWaapiHelper::RETURN)[0]->AsObject();
- const FString ItemIdString = ItemInfoObj->GetStringField(WwiseWaapiHelper::ID);
- Path = ItemInfoObj->GetStringField(WwiseWaapiHelper::PATH);
- ItemChildrenCount = ItemInfoObj->GetNumberField(WwiseWaapiHelper::CHILDREN_COUNT);
- FGuid::ParseExact(ItemIdString, EGuidFormats::DigitsWithHyphensInBraces, InItemGuid);
- }
- else
- {
- UE_LOG(LogAudiokineticTools, Log, TEXT("Failed to get information for Waapi items at : %s"), *Path);
-
- if (Result && Result->GetStringField(TEXT("uri")) == TEXT("ak.wwise.locked"))
- {
- UE_LOG(LogAudiokineticTools, Error, TEXT("Failed to get information for Waapi items. The item is locked."));
- }
- }
- // Create the new tree item
- FWwiseTreeItemPtr NewRootParent = MakeShared<FWwiseTreeItem>(EWwiseItemType::BrowserDisplayNames[static_cast<int>(Type)], Path, nullptr, EWwiseItemType::Folder, InItemGuid);
- NewRootParent->ShortId = ShortId;
- NewRootParent->bWaapiRefExists = true;
- NewRootParent->ChildCountInWwise = ItemChildrenCount;
- return NewRootParent;
- }
- FWwiseTreeItemPtr FWaapiDataSource::ConstructWwiseTreeItem(const TSharedPtr<FJsonObject>& InItemInfoObj)
- {
- static const FString ValidPaths[] = {
- EWwiseItemType::FolderNames[EWwiseItemType::Event],
- EWwiseItemType::FolderNames[EWwiseItemType::AuxBus],
- EWwiseItemType::FolderNames[EWwiseItemType::ActorMixer],
- EWwiseItemType::FolderNames[EWwiseItemType::GameParameter],
- EWwiseItemType::FolderNames[EWwiseItemType::State],
- EWwiseItemType::FolderNames[EWwiseItemType::Switch],
- EWwiseItemType::FolderNames[EWwiseItemType::Trigger],
- EWwiseItemType::FolderNames[EWwiseItemType::AcousticTexture],
- EWwiseItemType::FolderNames[EWwiseItemType::EffectShareSet]
- };
- static auto IsValidPath = [](const FString& Input, const auto& Source) -> bool {
- for (const auto& Item : Source)
- {
- if (Input.StartsWith(WwiseWaapiHelper::BACK_SLASH + Item))
- {
- return true;
- }
- }
- return false;
- };
- const FString ItemTypeString = InItemInfoObj->GetStringField(WwiseWaapiHelper::TYPE);
- auto ItemType = EWwiseItemType::FromString(ItemTypeString);
- if (ItemType == EWwiseItemType::None)
- {
- return {};
- }
- const FString ItemPath = InItemInfoObj->GetStringField(WwiseWaapiHelper::PATH);
- if (IsValidPath(ItemPath, ValidPaths))
- {
- const FString ItemIdString = InItemInfoObj->GetStringField(WwiseWaapiHelper::ID);
- FGuid InItemId = FGuid::NewGuid();
- FGuid::ParseExact(ItemIdString, EGuidFormats::DigitsWithHyphensInBraces, InItemId);
- const FString ItemName = InItemInfoObj->GetStringField(WwiseWaapiHelper::NAME);
- if (ItemName.IsEmpty())
- {
- return {};
- }
- const uint32_t ItemChildrenCount = InItemInfoObj->GetNumberField(WwiseWaapiHelper::CHILDREN_COUNT);
- if (ItemType == EWwiseItemType::StandaloneWorkUnit)
- {
- FString WorkUnitType;
- if (InItemInfoObj->TryGetStringField(WwiseWaapiHelper::WORKUNIT_TYPE, WorkUnitType) && WorkUnitType == "FOLDER")
- {
- ItemType = EWwiseItemType::PhysicalFolder;
- }
- }
- FWwiseTreeItemPtr TreeItem = MakeShared<FWwiseTreeItem>(ItemName, ItemPath, nullptr, ItemType, InItemId);
- TreeItem->WaapiName = ItemName;
- TreeItem->bWaapiRefExists = true;
- if (TreeItem->IsFolder())
- {
- NodesByPath.Add(TreeItem->FolderPath, TreeItem);
- }
- if ((ItemType != EWwiseItemType::Event) && (ItemType != EWwiseItemType::Sound))
- {
- TreeItem->ChildCountInWwise = ItemChildrenCount;
- }
- return TreeItem;
- }
- return {};
- }
- FWwiseTreeItemPtr FWaapiDataSource::ConstructWwiseTreeItem(const TSharedPtr<FJsonValue>& InJsonItem)
- {
- return ConstructWwiseTreeItem(InJsonItem->AsObject());
- }
- FWwiseTreeItemPtr FWaapiDataSource::FindItemFromPath(const FWwiseTreeItemPtr& InParentItem,
- const FString& InCurrentItemPath)
- {
- return InParentItem->FindItemRecursive(InCurrentItemPath);
- }
- FWwiseTreeItemPtr FWaapiDataSource::FindItemFromPath(const FString& InCurrentItemPath)
- {
- auto FoundItem = NodesByPath.Find(InCurrentItemPath);
- if (FoundItem)
- {
- return *FoundItem;
- }
- return nullptr;
- }
- FWwiseTreeItemPtr FWaapiDataSource::FindOrConstructTreeItemFromJsonObject(
- const TSharedPtr<FJsonObject>& ObjectJson)
- {
- FString objectPath;
- if (!ObjectJson->TryGetStringField(WwiseWaapiHelper::PATH, objectPath))
- {
- return {};
- }
- FString stringId;
- if (!ObjectJson->TryGetStringField(WwiseWaapiHelper::ID, stringId))
- {
- return {};
- }
- FGuid id;
- FGuid::ParseExact(stringId, EGuidFormats::DigitsWithHyphensInBraces, id);
- TArray<FString> pathParts;
- objectPath.ParseIntoArray(pathParts, *WwiseWaapiHelper::BACK_SLASH);
- if (pathParts.Num() == 0)
- {
- return {};
- }
- TSharedPtr<FWwiseTreeItem> treeItem;
- TArray<TSharedPtr<FWwiseTreeItem>>* children = &RootItems;
- TArray<TSharedPtr<FWwiseTreeItem>> itemsToExpand;
- FString folderPath;
-
- for (auto& part : pathParts)
- {
- folderPath += FString::Printf(TEXT("%s%s"), *WwiseWaapiHelper::BACK_SLASH, *part);
- bool found = false;
- for (auto& item : *children)
- {
- if (item->ItemId == id)
- {
- treeItem = item;
- break;
- }
- if (item->FolderPath == folderPath)
- {
- if (!item->IsExpanded)
- {
- const FString itemIdStringField = item->ItemId.ToString(EGuidFormats::DigitsWithHyphensInBraces);
- TSharedPtr<FJsonObject> Result;
- // Request data from Wwise UI using WAAPI and use them to create a Wwise tree item, getting the informations from a specific "ID".
- if (!CallWaapiGetInfoFrom(WwiseWaapiHelper::ID, itemIdStringField, Result, { { WwiseWaapiHelper::SELECT, { WwiseWaapiHelper::CHILDREN }, {} } }))
- {
- // Folders do not have a specific "ID". Search with the "PATH" instead.
- if (!CallWaapiGetInfoFrom(WwiseWaapiHelper::PATH, item->FolderPath, Result, { { WwiseWaapiHelper::SELECT, { WwiseWaapiHelper::CHILDREN }, {} } }))
- {
- UE_LOG(LogAudiokineticTools, Log, TEXT("Failed to get information from id : %s"), *itemIdStringField);
- return {};
- }
- }
- itemsToExpand.Add(item);
- }
- treeItem = item;
- children = treeItem->GetChildrenMutable();
- found = true;
- }
- }
- if (treeItem && treeItem->ItemId == id)
- {
- break;
- }
- if (!found)
- {
- return {};
- }
- }
- if (treeItem.IsValid() && treeItem->ItemId != id)
- {
- return {};
- }
- WwiseExpansionChange.ExecuteIfBound(itemsToExpand);
- return treeItem;
- }
- void FWaapiDataSource::FindAndCreateItems(FWwiseTreeItemPtr CurrentItem)
- {
- FString LastPathVisited = CurrentItem->FolderPath;
- LastPathVisited.RemoveFromEnd(WwiseWaapiHelper::BACK_SLASH + CurrentItem->DisplayName);
- FWwiseTreeItemPtr RootItem = GetRootItem(CurrentItem->FolderPath);
- if (!RootItem || CurrentItem->FolderPath == RootItem->FolderPath)
- {
- return;
- }
- if (LastPathVisited == RootItem->FolderPath)
- {
- RootItem->AddChild(CurrentItem);
- return;
- }
- FWwiseTreeItemPtr ParentItem = FindItemFromPath(RootItem, LastPathVisited);
- if (ParentItem.IsValid())
- {
- ParentItem->AddChild(CurrentItem);
- }
- else
- {
- TSharedPtr<FJsonObject> Result;
- // Request data from Wwise UI using WAAPI and use them to create a Wwise tree item, getting the informations from a specific "PATH".
- if (LoadWaapiInfo(WwiseWaapiHelper::PATH, LastPathVisited, Result, {}))
- {
- // Recover the information from the Json object Result and use it to construct the tree item.
- FWwiseTreeItemPtr NewRootItem = ConstructWwiseTreeItem(Result->GetArrayField(WwiseWaapiHelper::RETURN)[0]);
- CurrentItem->Parent = NewRootItem;
- NewRootItem->AddChild(CurrentItem);
- FindAndCreateItems(NewRootItem);
- }
- else
- {
- UE_LOG(LogAudiokineticTools, Log, TEXT("Failed to get information from Waapi path : %s"), *LastPathVisited);
- }
- }
- }
- FString FWaapiDataSource::GetItemWorkUnitPath(FWwiseTreeItemPtr InItem)
- {
- auto WaapiClient = FAkWaapiClient::Get();
- if (!WaapiClient)
- {
- UE_LOG(LogAudiokineticTools, Log, TEXT("Unable to connect to localhost"));
- return {};
- }
- TSharedRef<FJsonObject> Args = MakeShared<FJsonObject>();
- {
- TSharedPtr<FJsonObject> From = MakeShared<FJsonObject>();
- From->SetArrayField(WwiseWaapiHelper::PATH, TArray<TSharedPtr<FJsonValue>> { MakeShared<FJsonValueString>(InItem->FolderPath) });
- Args->SetObjectField(WwiseWaapiHelper::FROM, From);
- }
- TSharedRef<FJsonObject> Options = MakeShared<FJsonObject>();
- Options->SetArrayField(WwiseWaapiHelper::RETURN, TArray<TSharedPtr<FJsonValue>> { MakeShared<FJsonValueString>(WwiseWaapiHelper::FILEPATH) });
- #if AK_SUPPORT_WAAPI
- TSharedPtr<FJsonObject> outJsonResult;
- if (!WaapiClient->Call(ak::wwise::core::object::get, Args, Options, outJsonResult))
- {
- UE_LOG(LogAudiokineticTools, Log, TEXT("Call Failed to get %s's Work Unit Path"), *InItem->DisplayName);
- return {};
- }
- #endif
- FString Path = outJsonResult->GetArrayField(WwiseWaapiHelper::RETURN)[0]->AsObject()->GetStringField(
- WwiseWaapiHelper::FILEPATH);
- return Path;
- }
- FWwiseTreeItemPtr FWaapiDataSource::GetRootItem(EWwiseItemType::Type RootType)
- {
- if (IsProjectLoaded() != EWwiseConnectionStatus::Connected)
- {
- UE_LOG(LogAudiokineticTools, Log, TEXT("Failed to get Waapi Root Items. The Wwise project is not connected."));
- return nullptr;
- }
- check(RootType <= EWwiseItemType::LastWwiseBrowserType)
- if (RootType > RootItems.Num() - 1)
- {
- UE_LOG(LogAudiokineticTools, Error, TEXT("Failed to get Waapi Root Items. Index out of range."));
- return nullptr;
- }
- return RootItems[RootType];
- }
- FWwiseTreeItemPtr FWaapiDataSource::GetRootItem(const FString& InFullPath)
- {
- for (int i = EWwiseItemType::Event; i <= EWwiseItemType::LastWwiseBrowserType; ++i)
- {
- if (InFullPath.StartsWith(RootItems[i]->FolderPath))
- {
- return RootItems[i];
- }
- }
- return {};
- }
- FWwiseTreeItemPtr FWaapiDataSource::LoadFilteredRootItem(EWwiseItemType::Type RootType, TSharedPtr<StringFilter> CurrentFilter)
- {
- check(CurrentFilter.IsValid())
- if (RootType > RootItems.Num() - 1)
- {
- UE_LOG(LogAudiokineticTools, Error, TEXT("Failed to get Waapi Root Items. Index out of range."));
- return nullptr;
- }
- FString CurrentFilterText = CurrentFilter->GetRawFilterText().ToString();
- FString Path = WwiseWaapiHelper::BACK_SLASH + EWwiseItemType::FolderNames[static_cast<int>(RootType)];
- FScopeLock Autolock(&WaapiRootItemsLock);
- for (int i = EWwiseItemType::Event; i <= EWwiseItemType::LastWwiseBrowserType; ++i)
- {
- RootItems[i]->EmptyChildren();
- }
- TSharedPtr<FJsonObject> Result;
- if (LoadWaapiInfo(WwiseWaapiHelper::PATH, Path, Result,
- {
- { WwiseWaapiHelper::SELECT , { WwiseWaapiHelper::DESCENDANTS }, {} },
- { WwiseWaapiHelper::WHERE, { WwiseWaapiHelper::NAMECONTAINS, CurrentFilterText}, {} }
- }))
- {
- // Recover the information from the Json object Result and use it to construct the tree item.
- TArray<TSharedPtr<FJsonValue>> SearchResultArray = Result->GetArrayField(WwiseWaapiHelper::RETURN);
- if (SearchResultArray.Num())
- {
- // The map contains each path and the correspondent object of the search result.
- TMap < FString, FWwiseTreeItemPtr> SearchedResultTreeItem;
- for (int i = 0; i < SearchResultArray.Num(); i++)
- {
- // Fill the map with the path-object elements.
- FWwiseTreeItemPtr NewRootChild = ConstructWwiseTreeItem(SearchResultArray[i]);
- if (NewRootChild.IsValid())
- {
- FindAndCreateItems(NewRootChild);
- }
- }
- }
- }
- else
- {
- UE_LOG(LogAudiokineticTools, Log, TEXT("Failed to get information from Waapi item search : %s"), *CurrentFilterText);
- }
- return GetRootItem(RootType);
- }
- bool FWaapiDataSource::LoadWaapiInfo(const FString& InFromField, const FString& InFromString,
- TSharedPtr<FJsonObject>& OutJsonResult, const TArray<WaapiTransformStringField>& TransformFields)
- {
- auto WaapiClient = FAkWaapiClient::Get();
- if (!WaapiClient)
- {
- UE_LOG(LogAudiokineticTools, Log, TEXT("Unable to connect to localhost"));
- return false;
- }
- #if AK_SUPPORT_WAAPI
- // Construct the Json arguments from a specific id/path
- TSharedRef<FJsonObject> Args = MakeShared<FJsonObject>();
- {
- TSharedPtr<FJsonObject> From = MakeShared<FJsonObject>();
- From->SetArrayField(InFromField, TArray<TSharedPtr<FJsonValue>> {MakeShared<FJsonValueString>(InFromString)});
- Args->SetObjectField(WwiseWaapiHelper::FROM, From);
- }
- if (TransformFields.Num())
- {
- TArray<TSharedPtr<FJsonValue>> Transform;
- for (const auto& TransformValue : TransformFields)
- {
- TSharedPtr<FJsonObject> InsideTransform = MakeShared<FJsonObject>();
- TArray<TSharedPtr<FJsonValue>> JsonArray;
- for (auto TransformStringValueArg : TransformValue.valueStringArgs)
- {
- JsonArray.Add(MakeShared<FJsonValueString>(TransformStringValueArg));
- }
- for (auto TransformNumberValueArg : TransformValue.valueNumberArgs)
- {
- JsonArray.Add(MakeShared<FJsonValueNumber>(TransformNumberValueArg));
- }
- InsideTransform->SetArrayField(TransformValue.keyArg, JsonArray);
- Transform.Add(MakeShared<FJsonValueObject>(InsideTransform));
- }
- Args->SetArrayField(WwiseWaapiHelper::TRANSFORM, Transform);
- }
- // Construct the Options Json object : Getting specific infos to construct the WwiseTreeItem "id - name - type - childrenCount - path - parent"
- TSharedRef<FJsonObject> Options = MakeShared<FJsonObject>();
- Options->SetArrayField(WwiseWaapiHelper::RETURN, TArray<TSharedPtr<FJsonValue>>
- {
- MakeShared<FJsonValueString>(WwiseWaapiHelper::ID),
- MakeShared<FJsonValueString>(WwiseWaapiHelper::NAME),
- MakeShared<FJsonValueString>(WwiseWaapiHelper::TYPE),
- MakeShared<FJsonValueString>(WwiseWaapiHelper::CHILDREN_COUNT),
- MakeShared<FJsonValueString>(WwiseWaapiHelper::PATH),
- MakeShared<FJsonValueString>(WwiseWaapiHelper::WORKUNIT_TYPE),
- });
- return WaapiClient->Call(ak::wwise::core::object::get, Args, Options, OutJsonResult);
- #else
- return false;
- #endif
- }
- bool FWaapiDataSource::IsTreeDirty()
- {
- return false;
- }
- void FWaapiDataSource::Tick(const double InCurrentTime, const float InDeltaTime)
- {
- }
- int32 FWaapiDataSource::LoadChildren(const FGuid& InParentId, const FString& InParentPath, TArray<FWwiseTreeItemPtr>& OutChildren)
- {
- UE_LOG(LogAudiokineticTools, VeryVerbose, TEXT("Loading Children for Waapi item %s, id: %s"), *InParentPath, *InParentId.ToString())
- FString InFromField;
- FString InStringField;
- OutChildren = {};
- if (InParentId.IsValid())
- {
- InFromField = WwiseWaapiHelper::ID;
- InStringField = InParentId.ToString(EGuidFormats::DigitsWithHyphensInBraces);
- }
- else
- {
- InFromField = WwiseWaapiHelper::PATH;
- InStringField = InParentPath;
- }
- TSharedPtr<FJsonObject> Result;
- // Request data from Wwise UI using WAAPI and use them to create a Wwise tree item, getting the informations from a specific "ID".
- if (!LoadWaapiInfo(WwiseWaapiHelper::PATH, InParentPath, Result,
- {
- { WwiseWaapiHelper::SELECT , { WwiseWaapiHelper::DESCENDANTS }, {} },
- { WwiseWaapiHelper::WHERE, { WwiseWaapiHelper::NAMECONTAINS, ""}, {}}
- }))
- {
- UE_LOG(LogAudiokineticTools, Error, TEXT("Failed to load Waapi information for %s."), *InStringField);
- return 0;
- }
- TArray<TSharedPtr<FJsonValue>> StructJsonArray = Result->GetArrayField(WwiseWaapiHelper::RETURN);
- if (StructJsonArray.Num() == 0)
- {
- return 0;
- }
- FWwiseTreeItemPtr ExistingParent = nullptr;
- if (auto ParentPtr = NodesByPath.Find(InParentPath))
- {
- ExistingParent = *ParentPtr;
- }
- if(!ExistingParent)
- {
- UE_LOG(LogAudiokineticTools, Error, TEXT("No Parent found at %s."), *InParentPath)
- return 0;
- }
- ExistingParent->EmptyChildren();
- for (int i = 0; i < StructJsonArray.Num(); i++)
- {
- FWwiseTreeItemPtr NewChild = ConstructWwiseTreeItem(StructJsonArray[i]);
- if (NewChild)
- {
- FindAndCreateItems(NewChild);
- }
- }
- return OutChildren.Num();
- }
- int32 FWaapiDataSource::LoadChildren(FWwiseTreeItemPtr ParentTreeItem)
- {
- if (!ParentTreeItem)
- {
- return 0;
- }
- TArray<FWwiseTreeItemPtr> OutChildren;
- LoadChildren(ParentTreeItem->ItemId, ParentTreeItem->FolderPath, OutChildren);
- return ParentTreeItem->GetChildren().Num();
- }
- int32 FWaapiDataSource::GetChildItemCount(const FWwiseTreeItemPtr& InParentItem)
- {
- return InParentItem->ChildCountInWwise;
- }
- FString FWaapiDataSource::LoadProjectName()
- {
- auto WaapiClient = FAkWaapiClient::Get();
- if (!WaapiClient)
- {
- return {};
- }
- TSharedRef<FJsonObject> Args = MakeShared<FJsonObject>();
- {
- TSharedPtr<FJsonObject> OfType = MakeShared<FJsonObject>();
- OfType->SetArrayField(WwiseWaapiHelper::OF_TYPE, TArray<TSharedPtr<FJsonValue>> { MakeShared<FJsonValueString>(WwiseWaapiHelper::PROJECT) });
- Args->SetObjectField(WwiseWaapiHelper::FROM, OfType);
- }
- TSharedRef<FJsonObject> Options = MakeShared<FJsonObject>();
- {
- Options->SetArrayField(WwiseWaapiHelper::RETURN, TArray<TSharedPtr<FJsonValue>>
- {
- MakeShared<FJsonValueString>(WwiseWaapiHelper::NAME),
- MakeShared<FJsonValueString>(WwiseWaapiHelper::FILEPATH),
- });
- }
- #if AK_SUPPORT_WAAPI
- TSharedPtr<FJsonObject> outJsonResult;
- if (WaapiClient->Call(ak::wwise::core::object::get, Args, Options, outJsonResult))
- {
- // Recover the information from the Json object Result and use it to get the item id.
- TArray<TSharedPtr<FJsonValue>> StructJsonArray = outJsonResult->GetArrayField(WwiseWaapiHelper::RETURN);
- if (StructJsonArray.Num())
- {
- FString Path = StructJsonArray[0]->AsObject()->GetStringField(WwiseWaapiHelper::FILEPATH);
- return FPaths::GetCleanFilename(Path);
- }
- else
- {
- UE_LOG(LogAudiokineticTools, Log, TEXT("Unable to get the project name"));
- return {};
- }
- }
- return {};
- #endif
- }
- void FWaapiDataSource::HandleFindWwiseItemInProjectExplorerCommandExecute(
- const TArray<FWwiseTreeItemPtr>& SelectedItems) const
- {
- auto waapiClient = FAkWaapiClient::Get();
- if (!waapiClient)
- {
- UE_LOG(LogAudiokineticTools, Log, TEXT("Unable to connect to localhost"));
- return;
- }
- if (SelectedItems.Num() == 0)
- return;
- TSharedRef<FJsonObject> Args = MakeShared<FJsonObject>();
- Args->SetStringField(WwiseWaapiHelper::COMMAND, WwiseWaapiHelper::FIND_IN_PROJECT_EXPLORER);
- TArray<TSharedPtr<FJsonValue>> SelectedObjects;
- for (auto SelectedItem : SelectedItems)
- {
- SelectedObjects.Add(MakeShared<FJsonValueString>(SelectedItem->ItemId.ToString(EGuidFormats::DigitsWithHyphensInBraces)));
- }
- Args->SetArrayField(WwiseWaapiHelper::OBJECTS, SelectedObjects);
- #if AK_SUPPORT_WAAPI
- TSharedPtr<FJsonObject> Result;
- TSharedRef<FJsonObject> Options = MakeShared<FJsonObject>();
- if (!waapiClient->Call(ak::wwise::ui::commands::execute, Args, Options, Result))
- {
- UE_LOG(LogAudiokineticTools, Log, TEXT("Call Failed"));
- }
- #endif
- }
- void FWaapiDataSource::OnProjectLoadedCallback()
- {
- SubscribeWaapiCallbacks();
- ConstructTree(true);
- }
- void FWaapiDataSource::OnConnectionLostCallback()
- {
- {
- FScopeLock AutoLock(&WaapiRootItemsLock);
- RootItems.Empty();
- NodesByPath.Empty();
- }
- WaapiDataSourceRefreshed.ExecuteIfBound();
- UnsubscribeWaapiCallbacks();
- }
- void FWaapiDataSource::OnWaapiClientBeginDestroyCallback()
- {
- auto waapiClient = FAkWaapiClient::Get();
- if (waapiClient == nullptr)
- return;
- if (ProjectLoadedHandle.IsValid())
- {
- waapiClient->OnProjectLoaded.Remove(ProjectLoadedHandle);
- ProjectLoadedHandle.Reset();
- }
- if (ConnectionLostHandle.IsValid())
- {
- waapiClient->OnConnectionLost.Remove(ConnectionLostHandle);
- ConnectionLostHandle.Reset();
- }
- UnsubscribeWaapiCallbacks();
- }
- void FWaapiDataSource::OnWaapiRenamed(uint64_t Id, TSharedPtr<FJsonObject> Response)
- {
- FString OldName;
- if (Response->TryGetStringField(WwiseWaapiHelper::OLD_NAME, OldName) && OldName.IsEmpty())
- {
- return;
- }
-
- FString NewName;
- if (Response->TryGetStringField(WwiseWaapiHelper::NEW_NAME, NewName) && NewName.IsEmpty())
- {
- return;
- }
- const TSharedPtr<FJsonObject>* ObjectJsonPtr = nullptr;
- if (!Response->TryGetObjectField(WwiseWaapiHelper::OBJECT, ObjectJsonPtr))
- {
- return;
- }
- FString ObjectPath;
- if (!ObjectJsonPtr->Get()->TryGetStringField(WwiseWaapiHelper::PATH, ObjectPath))
- {
- return;
- }
- FString OldPath(ObjectPath);
- OldPath.RemoveFromEnd(WwiseWaapiHelper::BACK_SLASH + NewName);
- auto TreeItem = FindItemFromPath(OldPath);
- OldPath += WwiseWaapiHelper::BACK_SLASH + OldName;
- NodesByPath.Remove(OldPath);
- if(TreeItem)
- {
- for(auto& Child : TreeItem->GetChildren())
- {
- if(Child->DisplayName == OldName)
- {
- Child->DisplayName = UPackageTools::SanitizePackageName(NewName);
- Child->WaapiName = NewName;
- break;
- }
- }
- }
- WaapiDataSourceRefreshed.ExecuteIfBound();
- }
- void FWaapiDataSource::OnWaapiChildAdded(uint64_t Id, TSharedPtr<FJsonObject> Response)
- {
- const TSharedPtr<FJsonObject>* ChildJsonPtr = nullptr;
- if (!Response->TryGetObjectField(WwiseWaapiHelper::CHILD, ChildJsonPtr))
- {
- UE_LOG(LogAudiokineticTools, Error, TEXT("Failed to get Child Object field."));
- return;
- }
- FString ChildName;
- if (!ChildJsonPtr->Get()->TryGetStringField(WwiseWaapiHelper::NAME, ChildName))
- {
- return;
- }
- FString ChildPath;
- if (!ChildJsonPtr->Get()->TryGetStringField(WwiseWaapiHelper::PATH, ChildPath))
- {
- return;
- }
- const TSharedPtr<FJsonObject>* ParentJsonPtr = nullptr;
- if (!Response->TryGetObjectField(WwiseWaapiHelper::PARENT, ParentJsonPtr))
- {
- UE_LOG(LogAudiokineticTools, Error, TEXT("Failed to get Parent Object field."));
- return;
- }
- FString TreeItemParentPath;
- if (!ParentJsonPtr->Get()->TryGetStringField(WwiseWaapiHelper::PATH, TreeItemParentPath))
- {
- return;
- }
- bool bChildAdded = false;
- if (auto ParentItem = NodesByPath.Find(TreeItemParentPath))
- {
- if (!ParentItem->Get()->FindItemRecursive(ChildPath))
- {
- auto ChildItem = ConstructWwiseTreeItem(*ChildJsonPtr);
- if (ChildItem)
- {
- ParentItem->Get()->AddChild(ChildItem);
- if(ChildItem->IsFolder())
- {
- NodesByPath.Add(ChildItem->FolderPath, ChildItem);
- }
- bChildAdded = true;
- }
- }
- }
- if(bChildAdded)
- {
- WaapiDataSourceRefreshed.ExecuteIfBound();
- }
- }
- void FWaapiDataSource::OnWaapiChildRemoved(uint64_t Id, TSharedPtr<FJsonObject> Response)
- {
- const TSharedPtr<FJsonObject>* ChildJsonPtr = nullptr;
- if (!Response->TryGetObjectField(WwiseWaapiHelper::CHILD, ChildJsonPtr))
- {
- UE_LOG(LogAudiokineticTools, Error, TEXT("Failed to get Child Object field."));
- return;
- }
- const TSharedPtr<FJsonObject>* ParentJsonPtr = nullptr;
- if (!Response->TryGetObjectField(WwiseWaapiHelper::PARENT, ParentJsonPtr))
- {
- UE_LOG(LogAudiokineticTools, Error, TEXT("Failed to get Parent Object field."));
- return;
- }
- FString ItemIdString;
- FString ItemName;
-
- if (!ChildJsonPtr->Get()->TryGetStringField(WwiseWaapiHelper::ID, ItemIdString))
- {
- return;
- }
- if (!ChildJsonPtr->Get()->TryGetStringField(WwiseWaapiHelper::NAME, ItemName))
- {
- return;
- }
-
- FString TreeItemParentPath;
- if (!ParentJsonPtr->Get()->TryGetStringField(WwiseWaapiHelper::PATH, TreeItemParentPath))
- {
- return;
- }
- // This seems to be the path to the removed item, and not its parent?
- if (auto ParentTreeItem = NodesByPath.Find(TreeItemParentPath))
- {
- FGuid ItemId = FGuid(ItemIdString);
- NodesByPath.Remove(TreeItemParentPath / ItemName);
- (*ParentTreeItem)->RemoveChild(ItemId);
- }
- WaapiDataSourceRefreshed.ExecuteIfBound();
- }
- void FWaapiDataSource::OnWwiseSelectionChanged(uint64_t Id, TSharedPtr<FJsonObject> Response)
- {
- AsyncTask(ENamedThreads::GameThread, [this, Response]()
- {
- const UAkSettingsPerUser* AkSettingsPerUser = GetDefault<UAkSettingsPerUser>();
- if (AkSettingsPerUser && AkSettingsPerUser->AutoSyncSelection)
- {
- const TArray<TSharedPtr<FJsonValue>>* objectsJsonArray = nullptr;
- if (Response->TryGetArrayField(WwiseWaapiHelper::OBJECTS, objectsJsonArray))
- {
- TArray<TSharedPtr<FWwiseTreeItem>> TreeItems;
- for (auto JsonObject : *objectsJsonArray)
- {
- auto TreeItem = FindOrConstructTreeItemFromJsonObject(JsonObject->AsObject());
- if (TreeItem)
- {
- TreeItems.Add(TreeItem);
- }
- }
- WwiseSelectionChange.ExecuteIfBound(TreeItems);
- }
- }
- });
- }
- void FWaapiDataSource::SubscribeWaapiCallbacks()
- {
- struct SubscriptionData
- {
- const char* Uri;
- WampEventCallback Callback;
- uint64* SubscriptionId;
- };
- #if AK_SUPPORT_WAAPI
- const SubscriptionData Subscriptions[] = {
- {ak::wwise::core::object::nameChanged, WampEventCallback::CreateRaw(this, &FWaapiDataSource::OnWaapiRenamed), &WaapiSubscriptionIds.Renamed},
- {ak::wwise::core::object::childAdded, WampEventCallback::CreateRaw(this, &FWaapiDataSource::OnWaapiChildAdded), &WaapiSubscriptionIds.ChildAdded},
- {ak::wwise::core::object::childRemoved, WampEventCallback::CreateRaw(this, &FWaapiDataSource::OnWaapiChildRemoved), &WaapiSubscriptionIds.ChildRemoved},
- {ak::wwise::ui::selectionChanged, WampEventCallback::CreateRaw(this, &FWaapiDataSource::OnWwiseSelectionChanged), &WaapiSubscriptionIds.SelectionChanged},
- };
- #endif
- auto waapiClient = FAkWaapiClient::Get();
- if (!waapiClient)
- {
- return;
- }
- TSharedRef<FJsonObject> Options = MakeShared<FJsonObject>();
- Options->SetArrayField(WwiseWaapiHelper::RETURN, TArray<TSharedPtr<FJsonValue>>
- {
- MakeShared<FJsonValueString>(WwiseWaapiHelper::ID),
- MakeShared<FJsonValueString>(WwiseWaapiHelper::NAME),
- MakeShared<FJsonValueString>(WwiseWaapiHelper::TYPE),
- MakeShared<FJsonValueString>(WwiseWaapiHelper::CHILDREN_COUNT),
- MakeShared<FJsonValueString>(WwiseWaapiHelper::PATH),
- MakeShared<FJsonValueString>(WwiseWaapiHelper::PARENT),
- MakeShared<FJsonValueString>(WwiseWaapiHelper::WORKUNIT_TYPE),
- });
- TSharedPtr<FJsonObject> Result;
- #if AK_SUPPORT_WAAPI
- for (auto& Subscription : Subscriptions)
- {
- if (*Subscription.SubscriptionId == 0)
- {
- waapiClient->Subscribe(Subscription.Uri,
- Options,
- Subscription.Callback,
- *Subscription.SubscriptionId,
- Result
- );
- }
- }
- #endif
- }
- EWwiseConnectionStatus FWaapiDataSource::IsProjectLoaded()
- {
- if(UAkSettingsPerUser* AkUserSettings = GetMutableDefault<UAkSettingsPerUser>())
- {
- if(!AkUserSettings->bAutoConnectToWAAPI)
- {
- return EWwiseConnectionStatus::SettingDisabled;
- }
- }
- if(FAkWaapiClient::IsProjectLoaded())
- {
- return EWwiseConnectionStatus::Connected;
- }
- if(FAkWaapiClient::Get()->bIsWrongProjectLoaded)
- {
- return EWwiseConnectionStatus::WrongProjectOpened;
- }
- return EWwiseConnectionStatus::WwiseNotOpen;
- }
- void FWaapiDataSource::SelectInProjectExplorer(TArray<FWwiseTreeItemPtr>& InTreeItems)
- {
- auto WaapiClient = FAkWaapiClient::Get();
- if (!WaapiClient)
- {
- UE_LOG(LogAudiokineticTools, Log, TEXT("Unable to connect to localhost"));
- return;
- }
- TSharedRef<FJsonObject> Args = MakeShared<FJsonObject>();
- Args->SetStringField(WwiseWaapiHelper::COMMAND, WwiseWaapiHelper::FIND_IN_PROJECT_EXPLORER);
- TArray<TSharedPtr<FJsonValue>> SelectedObjects;
- for (const auto TreeItem : InTreeItems)
- {
- SelectedObjects.Add(MakeShared<FJsonValueString>(TreeItem->ItemId.ToString(EGuidFormats::DigitsWithHyphensInBraces)));
- }
- Args->SetArrayField(WwiseWaapiHelper::OBJECTS, SelectedObjects);
- #if AK_SUPPORT_WAAPI
- TSharedPtr<FJsonObject> Result;
- TSharedRef<FJsonObject> Options = MakeShared<FJsonObject>();
- if (!WaapiClient->Call(ak::wwise::ui::commands::execute, Args, Options, Result))
- {
- UE_LOG(LogAudiokineticTools, Log, TEXT("Call Failed to Select Items in Project Explorer."));
- }
- #endif
- }
- bool FWaapiDataSource::CallWaapiGetInfoFrom(const FString& inFromField, const FString& inFromString, TSharedPtr<FJsonObject>& outJsonResult, const TArray<TransformStringField>& TransformFields)
- {
- auto waapiClient = FAkWaapiClient::Get();
- if (!waapiClient)
- {
- return false;
- }
- #if AK_SUPPORT_WAAPI
- // Construct the arguments Json object : Getting infos "from - a specific id/path"
- TSharedRef<FJsonObject> Args = MakeShared<FJsonObject>();
- {
- TSharedPtr<FJsonObject> from = MakeShared<FJsonObject>();
- from->SetArrayField(inFromField, TArray<TSharedPtr<FJsonValue>> { MakeShared<FJsonValueString>(inFromString) });
- Args->SetObjectField(WwiseWaapiHelper::FROM, from);
- // In case we would recover the children of the object that have the id : ID or the path : PATH, then we set isGetChildren to true.
- if (TransformFields.Num())
- {
- TArray<TSharedPtr<FJsonValue>> transform;
- for (auto TransformValue : TransformFields)
- {
- TSharedPtr<FJsonObject> insideTransform = MakeShared<FJsonObject>();
- TArray<TSharedPtr<FJsonValue>> JsonArray;
- for (auto TransformStringValueArg : TransformValue.valueStringArgs)
- {
- JsonArray.Add(MakeShared<FJsonValueString>(TransformStringValueArg));
- }
- for (auto TransformNumberValueArg : TransformValue.valueNumberArgs)
- {
- JsonArray.Add(MakeShared<FJsonValueNumber>(TransformNumberValueArg));
- }
- insideTransform->SetArrayField(TransformValue.keyArg, JsonArray);
- transform.Add(MakeShared<FJsonValueObject>(insideTransform));
- }
- Args->SetArrayField(WwiseWaapiHelper::TRANSFORM, transform);
- }
- }
- // Construct the Options Json object : Getting specific infos to construct the wwise tree item "id - name - type - childrenCount - path - parent"
- TSharedRef<FJsonObject> Options = MakeShared<FJsonObject>();
- Options->SetArrayField(WwiseWaapiHelper::RETURN, TArray<TSharedPtr<FJsonValue>>
- {
- MakeShared<FJsonValueString>(WwiseWaapiHelper::ID),
- MakeShared<FJsonValueString>(WwiseWaapiHelper::NAME),
- MakeShared<FJsonValueString>(WwiseWaapiHelper::TYPE),
- MakeShared<FJsonValueString>(WwiseWaapiHelper::CHILDREN_COUNT),
- MakeShared<FJsonValueString>(WwiseWaapiHelper::PATH),
- MakeShared<FJsonValueString>(WwiseWaapiHelper::WORKUNIT_TYPE),
- });
- // Request data from Wwise using WAAPI
- return waapiClient->Call(ak::wwise::core::object::get, Args, Options, outJsonResult);
- #endif
- return false;
- }
- void FWaapiDataSource::UnsubscribeWaapiCallbacks()
- {
- auto WaapiClient = FAkWaapiClient::Get();
- if (!WaapiClient)
- {
- return;
- }
- auto DoUnsubscribe = [WaapiClient](uint64& subscriptionId) {
- if (subscriptionId > 0)
- {
- TSharedPtr<FJsonObject> Result;
- WaapiClient->Unsubscribe(subscriptionId, Result);
- subscriptionId = 0;
- }
- };
- DoUnsubscribe(WaapiSubscriptionIds.Renamed);
- DoUnsubscribe(WaapiSubscriptionIds.ChildAdded);
- DoUnsubscribe(WaapiSubscriptionIds.ChildRemoved);
- DoUnsubscribe(WaapiSubscriptionIds.SelectionChanged);
- }
- void FWaapiDataSource::RemoveClientCallbacks()
- {
- auto WaapiClient = FAkWaapiClient::Get();
- if (WaapiClient == nullptr)
- {
- return;
- }
- if (ProjectLoadedHandle.IsValid())
- {
- WaapiClient->OnProjectLoaded.Remove(ProjectLoadedHandle);
- ProjectLoadedHandle.Reset();
- }
- if (ConnectionLostHandle.IsValid())
- {
- WaapiClient->OnConnectionLost.Remove(ConnectionLostHandle);
- ConnectionLostHandle.Reset();
- }
- UnsubscribeWaapiCallbacks();
- }
|