Wwise Unity Integration Documentation
Wwise Addressable Samples
  1. The Wwise addressable asset metadata preserver
    1. How it works
    2. Sample code

The Wwise addressable asset metadata preserver

When working with addressable Wwise assets, the easiest way to ensure that WwiseAddressableBank assets are up to date is to delete the generated soundbanks folder and regenerate soundbanks. Deleting addressable assets will clear the contents of addressables groups as the assets are deleted, so when they are reimported, their parent group and labels will be lost. This sample script included in the Wwise Unity Addressables package provides the functionality to preserve addressable asset metadata such as parent groups and labels.

How it works

We have added an optional setting that can be enabled to help restore lost groups and labels. It can be found in the Unity project settings, under Wwise Addressables. Once enabled, a target directory for the metadata can be specified. This directory should be within the Unity project's assets folder.

The WwiseAssetMetadataPreserver script adds a menu trigger under Assets/Wwise/Addressables to save the metadata of all Wwise addressable assets in the project. When triggered, an AddressableMetadata asset will be created for each addressable Wwise asset, serializing the name of the parent group and labels. The script also registers itself with the WwiseBankPostProcess.GetAssetMetadataDelegate function. This delegate allows external code to fill in a metadata struct that it used to set the asset's fields when it is imported by the WwiseBankPostProcess custom importer (which imports .bnk and .wem files when they are added to the Unity project).

With these two mechanisms, asset metadata can be serialized before doing a cleanup, and will be reapplied to the assets when they are reimported after generating soundbanks.

Note:

This script is intended as an example of how this can be done. You may find that it is more relevant to implement your own metadata filler that better suits your production requirements.

Sample code

#if AK_WWISE_ADDRESSABLES && UNITY_ADDRESSABLES
using UnityEditor.AddressableAssets;
using UnityEditor.AddressableAssets.Settings;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using System.IO;
namespace AK.Wwise.Unity.WwiseAddressables
{
/*
This class provides the functionality to preserve and restore Wwise addressable asset group and label metadata.
This information is lost when the assets are deleted, and clearing the Wwise addressable asset folder is
the simplest way to repair broken WwiseAddressableSounbanks.
This class should be seen as an example of how to implement this functionality and not a complete solution.
*/
[InitializeOnLoad]
class WwiseAddressableAssetMetadataPreserver
{
static WwiseAddressableAssetMetadataPreserver()
{
if (AkAddressablesEditorSettings.Instance.UseSampleMetadataPreserver)
{
BindMetadataDelegate();
}
}
//Sets the GetAssetMetadataDelegate on the WwiseBankPostProcess AssetPostProcessor (which handles importing of .bnk and .wem files)
public static void BindMetadataDelegate()
{
WwiseBankPostProcess.GetAssetMetadataDelegate += GetMetadata;
}
//Unset the delegate (when the feature is disabled)
public static void UnbindMetaDataDelegate()
{
WwiseBankPostProcess.GetAssetMetadataDelegate -= GetMetadata;
}
//Creates a AddressableMetadata asset for each Addressable wwise asset that keeps track of groups and labels.
//Metadata assets are created in their own folder in a hierarchy matching the wwise assets
//The folder hierarchy and asset name are used to match the assets on import
[UnityEditor.MenuItem("Assets/Wwise/Addressables/Serialize addressable asset metadata")]
public static void PreserveAllWwiseAssetMetadata()
{
AddressableAssetSettings addressableSettings = AddressableAssetSettingsDefaultObject.Settings;
foreach (AddressableAssetGroup group in addressableSettings.groups)
{
foreach (AddressableAssetEntry assetEntry in group.entries)
{
if (assetEntry.MainAsset)
{
if (assetEntry.MainAsset.GetType().IsSubclassOf(typeof(WwiseAsset)))
{
CreateMetadataAsset(assetEntry.AssetPath, assetEntry.labels, group.name);
}
}
}
}
}
[UnityEditor.MenuItem("Assets/Wwise/Addressables/Preserve addressable asset metadata", true)]
public static bool ValidatePreserveAllWwiseAssetMetadata()
{
return AkAddressablesEditorSettings.Instance.UseSampleMetadataPreserver;
}
//Create the necessary subfolders and the metadata asset
public static void CreateMetadataAsset(string assetPath, HashSet<string> assetLabels, string groupName)
{
string soundbankPath = assetPath.Replace(AkAssetUtilities.GetSoundbanksPath(), "");
var splitBankPath = soundbankPath.Split('/');
AddressableMetadata metaDataAsset = ScriptableObject.CreateInstance<AddressableMetadata>();
metaDataAsset.labels = new List<string>(assetLabels);
metaDataAsset.groupName = groupName;
var rootPath = AkAddressablesEditorSettings.Instance.MetadataPath;
if (!Directory.Exists(Path.Combine(Application.dataPath, rootPath)))
{
UnityEditor.AssetDatabase.CreateFolder("Assets", rootPath);
}
for (int i = 1; i < splitBankPath.Length - 1; i++)
{
if (!Directory.Exists(Path.Combine(Application.dataPath, Path.Combine(rootPath, splitBankPath[i]))))
{
AssetDatabase.CreateFolder(Path.Combine("Assets", rootPath), splitBankPath[i]);
}
rootPath = Path.Combine(rootPath, splitBankPath[i]);
}
string assetMetadataPath = Path.Combine("Assets", rootPath, Path.GetFileNameWithoutExtension(assetPath) + ".asset");
AddressableMetadata oldAsset = AssetDatabase.LoadAssetAtPath<AddressableMetadata>(assetMetadataPath);
if (oldAsset)
{
if (!metaDataAsset.IsDifferent(oldAsset))
{
return;
}
}
UnityEditor.AssetDatabase.CreateAsset(metaDataAsset, assetMetadataPath);
}
//We know where the metadata asset should be located based on its platform and language.
public static AddressableMetadata FindMetadataAsset(string assetName, string platformName, string languageName)
{
string MetadataAssetPath;
if (languageName !="SFX")
{
MetadataAssetPath = Path.Combine("Assets", AkAddressablesEditorSettings.Instance.MetadataPath, platformName, languageName, Path.GetFileNameWithoutExtension(assetName) + ".asset");
}
else
{
MetadataAssetPath = Path.Combine("Assets", AkAddressablesEditorSettings.Instance.MetadataPath, platformName, Path.GetFileNameWithoutExtension(assetName) + ".asset");
}
return AssetDatabase.LoadAssetAtPath<AddressableMetadata>(MetadataAssetPath);
}
//Called when importing .bnk and .wem files. Will attempt to find an existing metadata object in the project and load it.
public static bool GetMetadata(string assetName, string platformName, string languageName, ref AddressableMetadata metaData )
{
AddressableMetadata asset = FindMetadataAsset(assetName, platformName, languageName);
if ( asset )
{
metaData = asset;
return true;
}
return false;
}
}
}
#endif