Feat : Wwise Integration

This commit is contained in:
Alex
2026-03-23 14:28:21 +01:00
parent 627d787695
commit 004bc328ed
1149 changed files with 226567 additions and 19 deletions
@@ -0,0 +1,204 @@
/*******************************************************************************
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 Unity(R) Terms of
Service at https://unity3d.com/legal/terms-of-service
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) 2026 Audiokinetic Inc.
*******************************************************************************/
#if UNITY_EDITOR
using System.Collections.Generic;
using System.IO;
using AK.Wwise.Unity.Logging;
public partial class AkBuildPreprocessor
{
/// <summary>
/// User hook called to retrieve the custom platform name used to determine the base path. Do not modify platformName
/// to use default platform names.
/// </summary>
/// <param name="platformName">The custom platform name.</param>
public delegate void CustomPlatformNameGetter(ref string platformName, UnityEditor.BuildTarget target);
public static CustomPlatformNameGetter GetCustomPlatformName;
public delegate void OnBuildCallback(string path);
public static void BuildCallbackNoOp(string path)
{
// No-op
}
public class PlatformConfiguration
{
public string WwisePlatformName;
public OnBuildCallback OnPreprocessBuild = BuildCallbackNoOp;
public OnBuildCallback OnPostprocessBuild = BuildCallbackNoOp;
}
private static Dictionary<UnityEditor.BuildTarget, PlatformConfiguration> PlatformConfigurations = new Dictionary<UnityEditor.BuildTarget, PlatformConfiguration>();
public static void RegisterBuildTarget(UnityEditor.BuildTarget target, PlatformConfiguration config)
{
PlatformConfigurations.Add(target, config);
}
public static string GetPlatformName(UnityEditor.BuildTarget target)
{
var platformSubDir = string.Empty;
GetCustomPlatformName?.Invoke(ref platformSubDir, target);
if (!string.IsNullOrEmpty(platformSubDir))
return platformSubDir;
//New way to access target platform name
string platformName = AkBasePathGetter.GetTargetPlatformName(target);
if (platformName != string.Empty)
{
return platformName;
}
//For legacy code compatibility. Should maybe remove in 26.1 or 27.1 to give time to adjust
if (PlatformConfigurations.ContainsKey(target))
{
if (platformName == string.Empty)
{
platformName = PlatformConfigurations[target].WwisePlatformName;
}
return platformName;
}
//Keeping the old fallback of using the Unity target name.
return target.ToString();
}
}
#if UNITY_2018_1_OR_NEWER
public partial class AkBuildPreprocessor : UnityEditor.Build.IPreprocessBuildWithReport, UnityEditor.Build.IPostprocessBuildWithReport
#else
public partial class AkBuildPreprocessor : UnityEditor.Build.IPreprocessBuild, UnityEditor.Build.IPostprocessBuild
#endif
{
public int callbackOrder
{
get { return 0; }
}
private string destinationSoundBankFolder = string.Empty;
public static bool CopySoundbanks(bool generate, string platformName, ref string destinationFolder)
{
if (string.IsNullOrEmpty(platformName))
{
WwiseLogger.ErrorFormat("Could not determine platform name for <{0}> platform", platformName);
return false;
}
if (generate)
{
var platforms = new System.Collections.Generic.List<string> { platformName };
string wwiseInstallationPath = "";
#if UNITY_EDITOR_WIN
wwiseInstallationPath = AkWwiseEditorSettings.Instance.WwiseInstallationPathWindows;
#elif UNITY_EDITOR_OSX
wwiseInstallationPath = AkWwiseEditorSettings.Instance.WwiseInstallationPathMac;
#endif
AkUtilities.GenerateSoundbanks(wwiseInstallationPath, AkWwiseEditorSettings.WwiseProjectAbsolutePath, platforms);
}
string sourceFolder;
if (!AkBasePathGetter.GetSoundBankPaths(platformName, out sourceFolder, out destinationFolder))
return false;
if (!AkUtilities.DirectoryCopy(sourceFolder, destinationFolder, true))
{
destinationFolder = null;
WwiseLogger.ErrorFormat("Could not copy SoundBank folder for <{0}> platform", platformName);
return false;
}
WwiseLogger.Log($"Copied SoundBank folder from <{sourceFolder}> to streaming assets folder <{destinationFolder}> for <{platformName}> platform build");
return true;
}
public static void DeleteSoundbanks(string destinationFolder)
{
if (string.IsNullOrEmpty(destinationFolder))
return;
System.IO.Directory.Delete(destinationFolder, true);
WwiseLogger.LogFormat("Deleting streaming assets folder <{0}>", destinationFolder);
}
public void OnPreprocessBuildInternal(UnityEditor.BuildTarget target, string path)
{
var platformName = GetPlatformName(target);
#if !(AK_WWISE_ADDRESSABLES && UNITY_ADDRESSABLES)
if (AkWwiseEditorSettings.Instance.CopySoundBanksAsPreBuildStep)
{
if (!CopySoundbanks(AkWwiseEditorSettings.Instance.GenerateSoundBanksAsPreBuildStep, platformName, ref destinationSoundBankFolder))
{
WwiseLogger.ErrorFormat("SoundBank folder has not been copied for <{0}> target at <{1}>. This will likely result in a build without sound!!!", target, path);
}
}
#endif
if (PlatformConfigurations.TryGetValue(target, out var config))
{
config.OnPreprocessBuild(path);
}
// Init ProjectDB for platform being built
WwiseProjectDatabase.Init(AkWwiseEditorSettings.GetRootOutputPath(), platformName);
AkPluginActivator.ForceUpdate();
AkPluginActivator.ActivatePluginsForDeployment(target, true);
}
public void OnPostprocessBuildInternal(UnityEditor.BuildTarget target, string path)
{
AkPluginActivator.ActivatePluginsForDeployment(target, false);
if (PlatformConfigurations.TryGetValue(target, out var config))
{
config.OnPostprocessBuild(path);
}
#if !(AK_WWISE_ADDRESSABLES && UNITY_ADDRESSABLES)
DeleteSoundbanks(destinationSoundBankFolder);
#endif
destinationSoundBankFolder = string.Empty;
// Point the ProjectDB back on the current editor platform
WwiseProjectDatabase.Init(AkWwiseEditorSettings.GetRootOutputPath(), AkBasePathGetter.GetPlatformName());
}
#if UNITY_2018_1_OR_NEWER
public void OnPreprocessBuild(UnityEditor.Build.Reporting.BuildReport report)
{
OnPreprocessBuildInternal(report.summary.platform, report.summary.outputPath);
}
public void OnPostprocessBuild(UnityEditor.Build.Reporting.BuildReport report)
{
OnPostprocessBuildInternal(report.summary.platform, report.summary.outputPath);
}
#else
public void OnPreprocessBuild(UnityEditor.BuildTarget target, string path)
{
OnPreprocessBuildInternal(target, path);
}
public void OnPostprocessBuild(UnityEditor.BuildTarget target, string path)
{
OnPostprocessBuildInternal(target, path);
}
#endif
}
#endif // #if UNITY_EDITOR
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 5cf5d16f083391b4a8681b007ca2f85c
@@ -0,0 +1,142 @@
/*******************************************************************************
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 Unity(R) Terms of
Service at https://unity3d.com/legal/terms-of-service
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) 2026 Audiokinetic Inc.
*******************************************************************************/
#if UNITY_EDITOR
// Note, this code was only written to parse the AudioManager.asset file.
// It has been written to try to be as generic as possible, but might not
// work on other .asset settings files.
public class AkUnitySettingsParser
{
public static bool SetBoolValue(string ValueName, bool ValueToSet, string ConfigFileName)
{
try
{
var SettingsPath = UnityEngine.Application.dataPath.Remove(UnityEngine.Application.dataPath.LastIndexOf("/")) +
"/ProjectSettings/" + ConfigFileName + ".asset";
System.IO.FileStream fs;
System.IO.BinaryReader br;
fs = System.IO.File.Open(SettingsPath, System.IO.FileMode.Open);
br = new System.IO.BinaryReader(fs);
// Read the unsigned int at offset 0x0C in the file.
// This contains the offset at which the setting's numerical values are stored.
br.BaseStream.Seek(0x0C, System.IO.SeekOrigin.Begin);
// For some reason, the offset is Big Endian in the file.
var SettingsOffset = GetBigEndianIntFromBinaryReader(br);
// In the file, we start with 0x14 bytes, then a string containing the unity version,
// then 0x0C bytes, then a string containing the base class name, followed by a string containing "base".
string tempStr;
br.BaseStream.Seek(0x14, System.IO.SeekOrigin.Begin);
tempStr = GetStringFromBinaryReader(br); // Unity Version
br.BaseStream.Seek(0x0C, System.IO.SeekOrigin.Current);
tempStr = GetStringFromBinaryReader(br); // Config file Name
if (tempStr != ConfigFileName)
return false;
tempStr = GetStringFromBinaryReader(br); // "Base"
if (tempStr != "Base")
return false;
// This string is then followed by 24 bytes
br.BaseStream.Seek(24, System.IO.SeekOrigin.Current);
// We then have a series of String (type), String (variable name), and 24 bytes
// We can use the type of the settings before the field we are looking for to
// find its offset after SettingsOffset.
while (br.BaseStream.Position < br.BaseStream.Length)
{
var SettingType = GetStringFromBinaryReader(br);
var SettingName = GetStringFromBinaryReader(br);
if (SettingName == ValueName)
break;
br.BaseStream.Seek(24, System.IO.SeekOrigin.Current);
if (GetSizeofTypeByString(SettingType) == -1)
return false;
SettingsOffset += GetSizeofTypeByString(SettingType);
}
// Set the setting in the file
var bw = new System.IO.BinaryWriter(fs);
bw.Seek(SettingsOffset, System.IO.SeekOrigin.Begin);
bw.Write(ValueToSet ? (byte) 1 : (byte) 0);
bw.Close();
fs.Close();
}
catch (System.Exception)
{
// Error happened
return false;
}
// Success!
return true;
}
// Read a big endian Int, and advances the BinaryReader's position
private static int GetBigEndianIntFromBinaryReader(System.IO.BinaryReader br)
{
var tempBytes = new byte[4];
tempBytes = br.ReadBytes(4);
return (tempBytes[0] << 24) | (tempBytes[1] << 16) | (tempBytes[2] << 8) | tempBytes[3];
}
// Reads a zero-terminated string at the BinaryReader's current position, and advances position
private static string GetStringFromBinaryReader(System.IO.BinaryReader br)
{
var list = new System.Collections.Generic.List<byte>();
// Do not add the \0 in the string, because comparison won't work
var currentByte = br.ReadByte();
while (currentByte != 0)
{
list.Add(currentByte);
currentByte = br.ReadByte();
}
return System.Text.Encoding.Default.GetString(list.ToArray());
}
// Returns the size in bytes of a type, as specified in the .asset file
// NOTE: this function only supports types found in AudioManager.asset.
private static int GetSizeofTypeByString(string typeStr)
{
switch (typeStr)
{
case "int":
case "unsigned int":
case "float":
case "UInt32":
case "SInt32":
return 4;
case "bool":
return 1;
default:
return -1;
}
}
}
#endif // UNITY_EDITOR
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: e0e5c350f4eb2c541afb59c6c7203386
@@ -0,0 +1,403 @@
/*******************************************************************************
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 Unity(R) Terms of
Service at https://unity3d.com/legal/terms-of-service
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) 2026 Audiokinetic Inc.
*******************************************************************************/
#if UNITY_EDITOR
using UnityEditor;
using UnityEngine;
using AK.Wwise.Unity.Logging;
[UnityEditor.InitializeOnLoad]
public class AkWwisePostImportCallbackSetup
{
private static int m_scheduledMigrationStart;
private static bool m_scheduledReturnToLauncher;
private static bool m_pendingExecuteMethodCalled;
private static string s_CurrentScene;
static AkWwisePostImportCallbackSetup()
{
if (UnityEditor.AssetDatabase.IsAssetImportWorkerProcess())
{
return;
}
var arguments = System.Environment.GetCommandLineArgs();
if (UnityEngine.Application.isBatchMode
&& System.Array.IndexOf(arguments, "-wwiseEnableWithNoGraphics") == -1)
return;
UnityEditor.EditorApplication.delayCall += CheckMigrationStatus;
AkUtilities.GetEventDurations = (uint eventID, ref float maximum, ref float minimum) =>
{
var eventInfo = AkWwiseProjectInfo.GetData().GetEventInfo(eventID);
if (eventInfo != null)
{
minimum = eventInfo.minDuration;
maximum = eventInfo.maxDuration;
}
};
}
private static void CheckMigrationStatus()
{
try
{
int migrationStart;
bool returnToLauncher;
if (IsMigrationPending(out migrationStart, out returnToLauncher))
{
m_scheduledMigrationStart = migrationStart;
m_scheduledReturnToLauncher = returnToLauncher;
ScheduleMigration();
}
else
{
RefreshCallback();
}
}
catch (System.Exception e)
{
WwiseLogger.Error("Error during migration: " + e);
}
}
private static void ScheduleMigration()
{
// TODO: Is delayCall wiped out during a script reload?
// If not, guard against having a delayCall from a previously loaded code being run after the new loading.
if (UnityEditor.EditorApplication.isPlayingOrWillChangePlaymode || UnityEditor.EditorApplication.isCompiling)
{
// Skip if not in the right mode, wait for the next callback to see if we can proceed then.
UnityEditor.EditorApplication.delayCall += ScheduleMigration;
return;
}
try
{
WwiseSetupWizard.PerformMigration(m_scheduledMigrationStart);
// Force the user to return to the launcher to perform the post-installation process if necessary
if (m_scheduledReturnToLauncher)
{
if (UnityEditor.EditorUtility.DisplayDialog("Wwise Migration Successful!",
"Please close Unity and go back to the Wwise Launcher to complete the installation.", "Quit"))
UnityEditor.EditorApplication.Exit(0);
}
else
UnityEditor.EditorApplication.delayCall += RefreshCallback;
}
catch (System.Exception e)
{
WwiseLogger.Error("Error during migration: " + e);
}
}
private static bool IsMigrationPending(out int migrationStart, out bool returnToLauncher)
{
migrationStart = 0;
returnToLauncher = false;
var filename = UnityEngine.Application.dataPath + "/../.WwiseLauncherLockFile";
if (!System.IO.File.Exists(filename))
return false;
var fileContent = System.IO.File.ReadAllText(filename);
// Instantiate the regular expression object.
var r = new System.Text.RegularExpressions.Regex(
"{\"migrateStart\":(\\d+),\"migrateStop\":(\\d+)(,\"returnToLauncher\":(true|false))?,.*}",
System.Text.RegularExpressions.RegexOptions.IgnoreCase);
// Match the regular expression pattern against a text string.
var m = r.Match(fileContent);
if (!m.Success || m.Groups.Count < 2 || m.Groups[1].Captures.Count < 1 || m.Groups[2].Captures.Count < 1 ||
!int.TryParse(m.Groups[1].Captures[0].ToString(), out migrationStart))
throw new System.Exception("Error in the file format of .WwiseLauncherLockFile.");
// Handle optional properties
if (m.Groups.Count > 3 && m.Groups[4].Captures.Count > 0)
bool.TryParse(m.Groups[4].Captures[0].ToString(), out returnToLauncher);
return true;
}
private static void RefreshCallback()
{
PostImportFunction();
if (WwiseSettings.Exists)
{
AkPluginActivator.Update();
AkPluginActivator.ActivatePluginsForEditor();
}
}
private static void PostImportFunction()
{
#if UNITY_2018_1_OR_NEWER
UnityEditor.EditorApplication.hierarchyChanged += CheckWwiseGlobalExistance;
#else
UnityEditor.EditorApplication.hierarchyWindowChanged += CheckWwiseGlobalExistance;
#endif
UnityEditor.EditorApplication.delayCall += CheckPicker;
if (UnityEditor.EditorApplication.isPlayingOrWillChangePlaymode || UnityEditor.EditorApplication.isCompiling)
return;
try
{
if (!string.IsNullOrEmpty(AkWwiseEditorSettings.Instance.WwiseProjectPath))
{
AkWwiseBrowser.Refresh(ignoreIfWaapi: true);
}
}
catch (System.Exception e)
{
WwiseLogger.Log(e.ToString());
}
//Check if a WwiseGlobal object exists in the current scene
CheckWwiseGlobalExistance();
}
private static void RefreshPlugins()
{
if (string.IsNullOrEmpty(AkWwiseProjectInfo.GetData().CurrentPluginConfig))
AkWwiseProjectInfo.GetData().CurrentPluginConfig = AkPluginActivatorConstants.CONFIG_PROFILE;
AkPluginActivator.ActivatePluginsForEditor();
}
public static void CheckPicker()
{
if (UnityEditor.EditorApplication.isPlayingOrWillChangePlaymode || UnityEditor.EditorApplication.isCompiling)
{
// Skip if not in the right mode, wait for the next callback to see if we can proceed then.
UnityEditor.EditorApplication.delayCall += CheckPicker;
return;
}
var settings = AkWwiseEditorSettings.Instance;
if (!settings.CreatedPicker)
{
// Delete all the ghost tabs (Failed to load).
var windows = UnityEngine.Resources.FindObjectsOfTypeAll<UnityEditor.EditorWindow>();
if (windows != null && windows.Length > 0)
{
foreach (var window in windows)
{
var windowTitle = window.titleContent.text;
if (windowTitle.Equals("Failed to load") || windowTitle.Equals("AkWwisePicker"))
{
try
{
window.Close();
}
catch
{
// Do nothing here, this shouldn't cause any problem, however there has been
// occurrences of Unity crashing on a null reference inside that method.
}
}
}
}
// TODO: If no scene is loaded and we are using the demo scene, automatically load it to display it.
// Populate the picker
AkWwiseProjectInfo.GetData(); // Load data
if (!string.IsNullOrEmpty(settings.WwiseProjectPath))
{
AkWwiseProjectInfo.Populate();
AkWwiseBrowser.InitBrowserWindow();
settings.CreatedPicker = true;
settings.SaveSettings();
}
}
UnityEditor.EditorApplication.delayCall += CheckPendingExecuteMethod;
}
// TODO: Put this in AkUtilities?
private static void ExecuteMethod(string method)
{
string className = null;
string methodName = null;
var regex = new System.Text.RegularExpressions.Regex("(.+)\\.(.+)",
System.Text.RegularExpressions.RegexOptions.IgnoreCase);
var regexMatchResult = regex.Match(method);
if (!regexMatchResult.Success || regexMatchResult.Groups.Count < 3 || regexMatchResult.Groups[1].Captures.Count < 1 || regexMatchResult.Groups[2].Captures.Count < 1)
{
WwiseLogger.Error("Error parsing wwiseExecuteMethod parameter: " + method);
return;
}
className = regexMatchResult.Groups[1].Captures[0].ToString();
methodName = regexMatchResult.Groups[2].Captures[0].ToString();
try
{
System.Reflection.MethodInfo methodToExecute = null;
if (className == "AkTestUtilities")
{
var assembly = System.Reflection.Assembly.Load("Ak.Wwise.IntegrationTestsEditor");
methodToExecute = assembly.GetType(className).GetMethod(methodName,
System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public);
}
else
{
var type = System.Type.GetType(className);
if (type == null)
{
type = System.Type.GetType(className + ", Assembly-CSharp-Editor");
}
methodToExecute = type.GetMethod(methodName,
System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public);
}
if (methodToExecute == null)
{
WwiseLogger.Error("Error in AkWwisePostImportCallbackSetup::ExecuteMethod(): Could not find method: " + method);
return;
}
methodToExecute.Invoke(null, null);
}
catch (System.Exception e)
{
WwiseLogger.Error("Exception caught when calling " + method + ": " + e);
}
}
private static void CheckPendingExecuteMethod()
{
var arguments = System.Environment.GetCommandLineArgs();
var indexOfCommand = System.Array.IndexOf(arguments, "-wwiseExecuteMethod");
if (!m_pendingExecuteMethodCalled && indexOfCommand != -1 && arguments.Length > indexOfCommand + 1)
{
var methodToExecute = arguments[indexOfCommand + 1];
ExecuteMethod(methodToExecute);
m_pendingExecuteMethodCalled = true;
}
}
// Called when changes are made to the scene and when a new scene is created.
public static void CheckWwiseGlobalExistance()
{
var activeSceneName = UnityEngine.SceneManagement.SceneManager.GetActiveScene().name;
if (!string.IsNullOrEmpty(s_CurrentScene) && s_CurrentScene.Equals(activeSceneName))
return;
var settings = AkWwiseEditorSettings.Instance;
// Look for a game object which has the initializer component
#if UNITY_6000_0_OR_NEWER
var AkInitializers = Object.FindObjectsByType<AkInitializer>(FindObjectsSortMode.None);
#else
var AkInitializers = Object.FindObjectsOfType<AkInitializer>();
#endif
if (AkInitializers.Length == 0)
{
if (settings.CreateWwiseGlobal)
{
WwiseLogger.LogFormat("No Wwise object in the scene ({0}), creating one.", s_CurrentScene);
//No Wwise object in this scene, create one so that the sound engine is initialized and terminated properly even if the scenes are loaded
//in the wrong order.
var objWwise = new UnityEngine.GameObject("WwiseGlobal");
//Attach initializer and terminator components
AkInitializer akInitializer;
if (AkUtilities.IsRunningTest())
{
akInitializer = objWwise.AddComponent<AkInitializer>();
}
else
{
akInitializer = UnityEditor.Undo.AddComponent<AkInitializer>(objWwise);
}
akInitializer.InitializeInitializationSettings();
}
}
else if (AkInitializers.Length > 0)
{
foreach(AkInitializer Initializer in AkInitializers)
{
if (!Initializer.InitializationSettings)
{
WwiseLogger.LogFormat("Initializing {0} (GO {1}).", Initializer.name, Initializer.gameObject.name);
Initializer.InitializeInitializationSettings();
}
}
}
else if (settings.CreateWwiseGlobal == false && AkInitializers[0].gameObject.name == "WwiseGlobal")
{
WwiseLogger.LogFormat("CreateWwiseGlobal is false. Removing the AkInitializer in scene ({0}).", s_CurrentScene);
UnityEditor.Undo.DestroyObjectImmediate(AkInitializers[0].gameObject);
}
#if AK_WWISE_ADDRESSABLES && UNITY_ADDRESSABLES
var bankHolder = UnityEngine.Object.FindObjectOfType<AK.Wwise.Unity.WwiseAddressables.InitBankHolder>();
if (bankHolder == null)
{
UnityEngine.GameObject wwiseGlobalObject = UnityEngine.GameObject.Find("WwiseGlobal");
if (wwiseGlobalObject != null)
{
bankHolder = UnityEditor.Undo.AddComponent<AK.Wwise.Unity.WwiseAddressables.InitBankHolder>(wwiseGlobalObject);
}
}
if (bankHolder!=null && bankHolder.InitBank == null)
{
#if WWISE_ADDRESABLES_2022_1_0_OR_NEWER
var initBankPath = System.IO.Path.Combine(AkWwiseEditorSettings.WwiseScriptableObjectRelativePath, "InitBank.asset");
var initbank = UnityEditor.AssetDatabase.LoadAssetAtPath<AK.Wwise.Unity.WwiseAddressables.WwiseInitBankReference>(initBankPath);
if (initbank)
{
bankHolder.InitBank = initbank;
EditorUtility.SetDirty(bankHolder);
}
#else
var initBankPath = System.IO.Path.Combine("Assets",settings.RootOutputPath,"Init.asset");
var initbank = UnityEditor.AssetDatabase.LoadAssetAtPath<AK.Wwise.Unity.WwiseAddressables.WwiseAddressableSoundBank>(initBankPath);
bankHolder.InitBank = initbank;
EditorUtility.SetDirty(bankHolder);
#endif
}
#endif
if (settings.CreateWwiseListener)
{
WwiseSetupWizard.AddAkAudioListenerToMainCamera(true);
}
s_CurrentScene = activeSceneName;
}
}
#endif // UNITY_EDITOR
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 159bb4fd4c40a30499af5da93084cf22
@@ -0,0 +1,858 @@
/*******************************************************************************
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 Unity(R) Terms of
Service at https://unity3d.com/legal/terms-of-service
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) 2026 Audiokinetic Inc.
*******************************************************************************/
#if UNITY_EDITOR
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;
using UnityEditor;
using UnityEditor.PackageManager;
using UnityEngine;
public class WwiseSetupWizard
{
static Dictionary<int, string> WwiseAddressableDefines = new Dictionary<int, string>()
{
{2023, "WWISE_ADDRESSABLES_23_1_OR_LATER"},
{2024, "WWISE_ADDRESSABLES_24_1_OR_LATER"}
};
static Dictionary<int, string> WwiseVersionDefines = new Dictionary<int, string>()
{
{2024, "WWISE_2024_OR_LATER"}
};
//Change this when an API change is introduced that would break older version of the addrerssables package
private static string WwiseAddressableAPIDefine = "ADDRESSABLES_API_BROWSER_TREE_VIEW";
public static void RunModify()
{
try
{
UnityEngine.Debug.Log("WwiseUnity: Running modify setup...");
UnityEditor.SceneManagement.EditorSceneManager.NewScene(UnityEditor.SceneManagement.NewSceneSetup.DefaultGameObjects);
ModifySetup();
UnityEngine.Debug.Log("WwiseUnity: Refreshing asset database.");
UnityEditor.AssetDatabase.Refresh();
// IMPORTANT: This log line is parsed by the Launcher. Do not modify it.
UnityEngine.Debug.Log("WwiseUnity: End of setup, exiting Unity.");
}
catch (System.Exception e)
{
UnityEngine.Debug.LogError("WwiseUnity: Exception caught: " + e);
}
}
public static void RunSetup()
{
try
{
UnityEngine.Debug.Log("WwiseUnity: Running install setup...");
Setup();
UnityEngine.Debug.Log("WwiseUnity: Refreshing asset database.");
UnityEditor.AssetDatabase.Refresh();
// IMPORTANT: This log line is parsed by the Launcher. Do not modify it.
UnityEngine.Debug.Log("WwiseUnity: End of setup, exiting Unity.");
}
catch (System.Exception e)
{
UnityEngine.Debug.LogError("WwiseUnity: Exception caught: " + e);
}
}
public static void RunDemoSceneSetup()
{
try
{
UnityEngine.Debug.Log("WwiseUnity: Running demo scene setup...");
Setup();
UnityEditor.SceneManagement.EditorSceneManager.OpenScene("Assets/WwiseDemoScene/WwiseDemoScene.unity");
UnityEngine.Debug.Log("WwiseUnity: Refreshing asset database.");
UnityEditor.AssetDatabase.Refresh();
UnityEngine.Debug.Log("WwiseUnity: End of demo scene setup, exiting Unity.");
}
catch (System.Exception e)
{
UnityEngine.Debug.LogError("WwiseUnity: Exception caught: " + e);
}
}
private static int TotalNumberOfSections = 3;
private static void UpdateProgressBar(int sectionIndex, int subSectionIndex = 0, int totalSubSections = 1)
{
subSectionIndex = UnityEngine.Mathf.Clamp(subSectionIndex, 0, totalSubSections);
sectionIndex = UnityEngine.Mathf.Clamp(sectionIndex, 0, TotalNumberOfSections);
float progress = ((float)subSectionIndex / totalSubSections + sectionIndex) / TotalNumberOfSections;
UnityEditor.EditorUtility.DisplayProgressBar("Wwise Integration", "Migration in progress - Please wait...", progress);
}
public static void RunMigrate()
{
try
{
UnityEngine.Debug.Log("WwiseUnity: Running migration setup...");
UnityEngine.Debug.Log("WwiseUnity: Reading parameters...");
var arguments = System.Environment.GetCommandLineArgs();
string migrateStartString = null;
var indexMigrateStart = System.Array.IndexOf(arguments, "-wwiseInstallMigrateStart");
if (indexMigrateStart != -1)
migrateStartString = arguments[indexMigrateStart + 1];
else
{
UnityEngine.Debug.LogError("WwiseUnity: ERROR: Missing parameter wwiseInstallMigrateStart.");
return;
}
int migrateStart;
if (!int.TryParse(migrateStartString, out migrateStart))
{
UnityEngine.Debug.LogError("WwiseUnity: ERROR: wwiseInstallMigrateStart is not a number.");
return;
}
PerformMigration(migrateStart - 1);
UnityEditor.AssetDatabase.SaveAssets();
UnityEngine.Debug.Log("WwiseUnity: Refreshing asset database.");
UnityEditor.AssetDatabase.Refresh();
// IMPORTANT: This log line is parsed by the Launcher. Do not modify it.
UnityEngine.Debug.Log("WwiseUnity: End of setup, exiting Unity.");
}
catch (System.Exception e)
{
UnityEngine.Debug.LogError("WwiseUnity: Exception caught: " + e);
}
}
private static void MigrateCurrentScene(System.Type[] wwiseComponentTypes)
{
var objectTypeMap = new System.Collections.Generic.Dictionary<System.Type, UnityEngine.Object[]>();
foreach (var objectType in wwiseComponentTypes)
{
// Get all objects in the scene with the specified type.
#if UNITY_6000_0_OR_NEWER
var objects = UnityEngine.Object.FindObjectsByType(objectType, FindObjectsSortMode.None);
#else
var objects = UnityEngine.Object.FindObjectsOfType(objectType);
#endif
if (objects != null && objects.Length > 0)
objectTypeMap[objectType] = objects;
}
for (var ii = AkUtilities.MigrationStartIndex; ii < AkUtilities.MigrationStopIndex; ++ii)
{
var migrationMethodName = "Migrate" + ii;
var preMigrationMethodName = "PreMigration" + ii;
var postMigrationMethodName = "PostMigration" + ii;
foreach (var objectTypePair in objectTypeMap)
{
var objectType = objectTypePair.Key;
var objects = objectTypePair.Value;
var className = objectType.Name;
var preMigrationMethodInfo = objectType.GetMethod(preMigrationMethodName,
System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static);
if (preMigrationMethodInfo != null)
{
UnityEngine.Debug.Log("WwiseUnity: PreMigration step <" + ii + "> for class <" + className + ">");
preMigrationMethodInfo.Invoke(null, null);
}
var migrationMethodInfo = objectType.GetMethod(migrationMethodName,
System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);
if (migrationMethodInfo != null)
{
UnityEngine.Debug.Log("WwiseUnity: Migration step <" + ii + "> for class <" + className + ">");
// Call the migration method of each object.
foreach (var currentObject in objects)
migrationMethodInfo.Invoke(currentObject, null);
}
var postMigrationMethodInfo = objectType.GetMethod(postMigrationMethodName,
System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static);
if (postMigrationMethodInfo != null)
{
UnityEngine.Debug.Log("WwiseUnity: PostMigration step <" + ii + "> for class <" + className + ">");
postMigrationMethodInfo.Invoke(null, null);
}
}
}
}
private static System.Type[] GetWwiseComponentTypes()
{
var wwiseComponentTypes = new System.Collections.Generic.List<System.Type>();
var wwiseComponentFolder = UnityEngine.Application.dataPath + "/Wwise/MonoBehaviour/Runtime";
if (System.IO.Directory.Exists(wwiseComponentFolder))
{
var files = new System.IO.DirectoryInfo(wwiseComponentFolder).GetFiles("*.cs", System.IO.SearchOption.AllDirectories);
foreach (var file in files)
{
var className = System.IO.Path.GetFileNameWithoutExtension(file.Name);
var objectType = System.Type.GetType(className + ", AK.Wwise.Unity.MonoBehaviour");
if (objectType != null && objectType.IsSubclassOf(typeof(UnityEngine.Object)))
{
wwiseComponentTypes.Add(objectType);
}
}
}
return wwiseComponentTypes.ToArray();
}
private static void MigrateObject(UnityEngine.Object obj)
{
if (obj == null)
{
UnityEngine.Debug.LogWarning("WwiseUnity: Missing script! Please consider resolving the missing scripts before migrating your Unity project. Any WwiseType on this object will NOT be migrated!");
return;
}
var migratable = obj as AK.Wwise.IMigratable;
if (migratable == null && !AkUtilities.IsMigrationRequired(AkUtilities.MigrationStep.WwiseTypes_v2018_1_6))
return;
var hasChanged = false;
var serializedObject = new UnityEditor.SerializedObject(obj);
if (migratable != null)
hasChanged = migratable.Migrate(serializedObject);
else
hasChanged = AK.Wwise.TypeMigration.SearchAndProcessWwiseTypes(serializedObject.GetIterator());
if (hasChanged)
serializedObject.ApplyModifiedPropertiesWithoutUndo();
}
private static void MigratePrefabs()
{
// The only migration operation done in this method is to call MigrateObject on MonoBehaviours attached to prefabs.
// MigrateObject only runs if a migration is required for the "WwiseTypes_v2018_1_6" migration step.
// Add an early return here to avoid lots of potentially slow code if we are in a case where MigrateObject would
// do nothing.
if (!AkUtilities.IsMigrationRequired(AkUtilities.MigrationStep.WwiseTypes_v2018_1_6))
{
return;
}
var guids = UnityEditor.AssetDatabase.FindAssets("t:Prefab", new[] { "Assets" });
for (var i = 0; i < guids.Length; i++)
{
UpdateProgressBar(0, i, guids.Length);
var path = UnityEditor.AssetDatabase.GUIDToAssetPath(guids[i]);
UnityEngine.Debug.Log("WwiseUnity: Migrating prefab: " + path);
var prefabObject = UnityEditor.AssetDatabase.LoadAssetAtPath<UnityEngine.GameObject>(path);
if (prefabObject == null)
{
UnityEngine.Debug.LogWarning("WwiseUnity: Failed to migrate prefab: " + path);
continue;
}
var objects = prefabObject.GetComponents<UnityEngine.MonoBehaviour>();
// The rather convoluted way of iterating through all objects here has a very specific reason.
// The call to MigrateObject ends up calling SerializedObject.ApplyModifiedPropertiesWithoutUndo.
// This function call will invalidate all references that are held by the code that is running
// (the objects array here).
// In order to iterate properly on all MonoBehaviours available, we get their instance IDs,
// which do not change when Applying modified properties. Then, for each iteration of the
// migration loop, we need to get a valid array of MonoBehaviours again, because it might
// have been invalidated by the call to MigrateObject. We then migrate the objects that
// need migration by making sure their InstanceID is in the list of unmigrated MonoBehaviours.
var instanceIds = new System.Collections.Generic.List<int>();
foreach (var obj in objects)
{
if (obj == null)
continue;
var id = obj.GetInstanceID();
if (!instanceIds.Contains(id))
instanceIds.Add(id);
}
for (; instanceIds.Count > 0; instanceIds.RemoveAt(0))
{
var id = instanceIds[0];
var obj = UnityEditor.EditorUtility.InstanceIDToObject(id);
if (obj && obj.GetInstanceID() == id)
{
MigrateObject(obj);
}
}
}
}
private static string[] ScriptableObjectGuids = null;
private static bool ShouldProcessScriptableObject(UnityEngine.Object obj)
{
if (obj == null)
return true;
if (!(obj is UnityEngine.ScriptableObject))
return false;
if (obj is UnityEngine.GUISkin)
return false;
if (obj is AkWwiseInitializationSettings)
return false;
if (obj is AkCommonPlatformSettings)
return false;
if (AkUtilities.IsMigrationRequired(AkUtilities.MigrationStep.AutoDefinedSoundBanks_v2023_1_0) &&
obj is WwiseEventReference)
return true;
if (obj is WwiseObjectReference)
return false;
return true;
}
private static void MigrateScriptableObjects()
{
var guids = ScriptableObjectGuids;
if (guids == null)
return;
var processedGuids = new System.Collections.Generic.HashSet<string>();
for (var i = 0; i < guids.Length; i++)
{
UpdateProgressBar(2, i, guids.Length);
var guid = guids[i];
if (processedGuids.Contains(guid))
continue;
processedGuids.Add(guid);
var path = UnityEditor.AssetDatabase.GUIDToAssetPath(guid);
var objects = UnityEditor.AssetDatabase.LoadAllAssetsAtPath(path);
foreach (var obj in objects)
{
if (ShouldProcessScriptableObject(obj))
{
UnityEngine.Debug.Log("WwiseUnity: Migrating ScriptableObject: " + path);
MigrateObject(obj);
}
}
}
}
private static void MigrateScenes()
{
var wwiseComponentTypes = GetWwiseComponentTypes();
var guids = UnityEditor.AssetDatabase.FindAssets("t:Scene", new[] { "Assets" });
for (var i = 0; i < guids.Length; i++)
{
UpdateProgressBar(1, i, guids.Length);
var path = UnityEditor.AssetDatabase.GUIDToAssetPath(guids[i]);
UnityEngine.Debug.Log("WwiseUnity: Migrating scene: " + path);
UnityEditor.EditorUtility.UnloadUnusedAssetsImmediate();
var scene = UnityEditor.SceneManagement.EditorSceneManager.OpenScene(path);
MigrateCurrentScene(wwiseComponentTypes);
// From this point on, the only migration operation done in this loop is to call MigrateObject on MonoBehaviours.
// MigrateObject only runs if a migration is required for the "WwiseTypes_v2018_1_6" migration step. Simply
// continue the loop here to avoid lots of potentially slow code if we are in a case where MigrateObject would
// do nothing.
if (!AkUtilities.IsMigrationRequired(AkUtilities.MigrationStep.WwiseTypes_v2018_1_6))
{
continue;
}
var objects = UnityEngine.Resources.FindObjectsOfTypeAll<UnityEngine.MonoBehaviour>();
// The rather convoluted way of iterating through all objects here has a very specific reason.
// The call to MigrateObject ends up calling SerializedObject.ApplyModifiedPropertiesWithoutUndo.
// This function call will invalidate all references that are held by the code that is running
// (the objects array here).
// In order to iterate properly on all MonoBehaviours available, we get their instance IDs,
// which do not change when Applying modified properties. Then, for each iteration of the
// migration loop, we need to get a valid array of MonoBehaviours again, because it might
// have been invalidated by the call to MigrateObject. We then migrate the objects that
// need migration by making sure their InstanceID is in the list of unmigrated MonoBehaviours.
var instanceIds = new System.Collections.Generic.List<int>();
foreach (var obj in objects)
{
if (obj == null)
continue;
var id = obj.GetInstanceID();
if (!instanceIds.Contains(id))
instanceIds.Add(id);
}
for (; instanceIds.Count > 0; instanceIds.RemoveAt(0))
{
var id = instanceIds[0];
var obj = UnityEditor.EditorUtility.InstanceIDToObject(id);
if (obj && obj.GetInstanceID() == id)
{
MigrateObject(obj);
}
}
if (UnityEditor.SceneManagement.EditorSceneManager.MarkSceneDirty(scene))
if (!UnityEditor.SceneManagement.EditorSceneManager.SaveScene(scene))
throw new System.Exception("Error occurred while saving migrated scenes.");
UnityEditor.SceneManagement.EditorSceneManager.CloseScene(scene, true);
}
}
public static void PerformMigration(int migrateStart)
{
AkUtilities.BeginMigration(migrateStart);
UpdateProgressBar(0);
UnityEngine.Debug.Log("WwiseUnity: Migrating from Unity Integration Version " + migrateStart + " to " + AkUtilities.MigrationStopIndex);
AkPluginActivator.DeactivateAllPlugins();
AkPluginActivator.Update();
AkPluginActivator.ActivatePluginsForEditor();
// Get the name of the currently opened scene.
var activeScene = UnityEngine.SceneManagement.SceneManager.GetActiveScene();
var loadedScenePath = activeScene.path;
if (!string.IsNullOrEmpty(loadedScenePath))
AkUtilities.FixSlashes(ref loadedScenePath, '\\', '/', false);
UnityEditor.SceneManagement.EditorSceneManager.NewScene(UnityEditor.SceneManagement.NewSceneSetup.DefaultGameObjects);
// obtain a list of ScriptableObjects before any migration is performed
ScriptableObjectGuids = UnityEditor.AssetDatabase.FindAssets("t:ScriptableObject", new[] { "Assets" });
if (AkUtilities.IsMigrationRequired(AkUtilities.MigrationStep.NewScriptableObjectFolder_v2019_2_0))
{
var oldScriptableObjectPath = System.IO.Path.Combine(System.IO.Path.Combine("Assets", "Wwise"), "Resources");
AkUtilities.MoveFolder(oldScriptableObjectPath, AkWwiseEditorSettings.WwiseScriptableObjectRelativePath);
}
if (!UnityEditor.AssetDatabase.IsValidFolder(AkWwiseEditorSettings.WwiseScriptableObjectRelativePath))
{
UnityEngine.Debug.LogFormat("WwiseUnity: Creating ScriptableObjects folder at <{0}>", AkWwiseEditorSettings.WwiseScriptableObjectRelativePath);
AkUtilities.CreateFolder(AkWwiseEditorSettings.WwiseScriptableObjectRelativePath);
}
AkWwiseEditorSettings.GetRootOutputPath();
UnityEngine.Debug.LogFormat("WwiseUnity: Migrating Prefabs...");
MigratePrefabs();
UnityEngine.Debug.LogFormat("WwiseUnity: Done migrating Prefabs");
UnityEngine.Debug.LogFormat("WwiseUnity: Migrating Scenes...");
MigrateScenes();
UnityEngine.Debug.LogFormat("WwiseUnity: Done migrating Scenes");
UnityEngine.Debug.LogFormat("WwiseUnity: Migrating ScriptableObjects...");
MigrateScriptableObjects();
UnityEngine.Debug.LogFormat("WwiseUnity: Done migrating ScriptableObjects");
UnityEditor.EditorUtility.UnloadUnusedAssetsImmediate();
UnityEditor.SceneManagement.EditorSceneManager.NewScene(UnityEditor.SceneManagement.NewSceneSetup.DefaultGameObjects);
AkUtilities.EndMigration();
UpdateProgressBar(TotalNumberOfSections);
// Reopen the scene that was opened before the migration process started.
if (!string.IsNullOrEmpty(loadedScenePath))
{
UnityEditor.SceneManagement.EditorSceneManager.OpenScene(loadedScenePath);
}
SetWwiseVersionDefines(WwiseAddressableDefines, true, "com.audiokinetic.wwise.addressables");
SetWwiseVersionDefines(WwiseVersionDefines);
SetSoundbankSettings();
UnityEngine.Debug.Log("WwiseUnity: Removing lock for launcher.");
// TODO: Moving one folder up is not nice at all. How to find the current project path?
try
{
System.IO.File.Delete(UnityEngine.Application.dataPath + "/../.WwiseLauncherLockFile");
}
catch
{
// Ignore if not present.
}
UnityEditor.EditorUtility.ClearProgressBar();
}
public static void ModifySetup()
{
var currentConfig = AkPluginActivator.GetCurrentConfig();
if (string.IsNullOrEmpty(currentConfig))
currentConfig = AkPluginActivatorConstants.CONFIG_PROFILE;
AkPluginActivator.DeactivateAllPlugins();
AkPluginActivator.Update();
AkPluginActivator.ActivatePluginsForEditor();
SetWwiseVersionDefines(WwiseAddressableDefines, true, "com.audiokinetic.wwise.addressables");
SetWwiseVersionDefines(WwiseVersionDefines);
}
// Perform all necessary steps to use the Wwise Unity integration.
private static void Setup()
{
UnityEditor.SceneManagement.EditorSceneManager.NewScene(UnityEditor.SceneManagement.NewSceneSetup.DefaultGameObjects);
UnityEngine.Debug.Log("WwiseUnity: Deactivating all plugins...");
AkPluginActivator.DeactivateAllPlugins();
// 0. Make sure the SoundBank directory exists
var sbPath = AkWwiseEditorSettings.GetRootOutputPath();
if (!System.IO.Directory.Exists(sbPath))
System.IO.Directory.CreateDirectory(sbPath);
// 1. Disable built-in audio
if (!DisableBuiltInAudio())
{
UnityEngine.Debug.LogWarning(
"WwiseUnity: Could not disable built-in audio. Please disable built-in audio by going to Project->Project Settings->Audio, and check \"Disable Audio\".");
}
// 2. Create a "WwiseGlobal" game object and set the AkSoundEngineInitializer and terminator scripts
// 3. Set the SoundBank path property on AkSoundEngineInitializer
CreateWwiseGlobalObject();
// 5. Disable the built-in audio listener, and add AkAudioListener component to camera
if (AkWwiseEditorSettings.Instance.CreateWwiseListener)
{
AddAkAudioListenerToMainCamera();
}
// 6. Enable "Run In Background" in PlayerSettings (PlayerSettings.runInbackground property)
UnityEditor.PlayerSettings.runInBackground = true;
UnityEngine.Debug.Log("WwiseUnity: Updating PluginActivator...");
AkPluginActivator.Update();
UnityEngine.Debug.Log("WwiseUnity: Activating plugins for editor...");
AkPluginActivator.ActivatePluginsForEditor();
// 9. Activate WwiseIDs file generation, and point Wwise to the Assets/Wwise folder
// 10. Change the SoundBanks options so it adds Max Radius information in the Wwise project
if (!SetSoundbankSettings())
UnityEngine.Debug.LogWarning("WwiseUnity: Could not modify Wwise Project to generate the header file!");
#if !UNITY_2021_1_OR_NEWER
// 11. Activate XboxOne network sockets.
AkXboxOneUtils.EnableXboxOneNetworkSockets();
#endif
// 12. Add addressables version define
SetWwiseVersionDefines(WwiseAddressableDefines, true, "com.audiokinetic.wwise.addressables");
// 13. Set Wwise version defines
SetWwiseVersionDefines(WwiseVersionDefines);
}
private static HashSet<BuildTargetGroup> AvailableBuildTargetGroups = new HashSet<BuildTargetGroup>();
public static void AddBuildTargetGroup(BuildTargetGroup NewGroup)
{
AvailableBuildTargetGroups.Add(NewGroup);
}
private static void SetWwiseVersionDefines(Dictionary<int,string> versionDefines, bool isPackageDependent = false, string packageName ="")
{
string wwiseVersion = AkUnitySoundEngine.WwiseVersion;
string shortWwiseVersion = wwiseVersion.Substring(0, 4);
int wwiseVersionAsInteger = int.Parse(shortWwiseVersion);
int minimalVersion = wwiseVersionAsInteger;
if (isPackageDependent)
{
var listRequest = Client.List();
while (!listRequest.IsCompleted) { }
if (listRequest.Status == StatusCode.Success)
{
foreach (var package in listRequest.Result)
{
if (package.name == packageName)
{
string[] versionParts = package.version.Split('.');
int.TryParse(versionParts[0], out int packageMajorVersion);
if (packageMajorVersion < minimalVersion)
{
minimalVersion = packageMajorVersion;
}
}
}
}
}
//Add version defines with the wwise version as key if a new define is needed.
if (wwiseVersionAsInteger >= 2023)
{
foreach (BuildTargetGroup targetGroup in GetNonObsoleteTargetGroups())
{
#if UNITY_5_4_OR_NEWER
if (targetGroup == BuildTargetGroup.Unknown)
{
continue;
}
#endif
var namedTarget = UnityEditor.Build.NamedBuildTarget.FromBuildTargetGroup(targetGroup);
string defines = PlayerSettings.GetScriptingDefineSymbols(namedTarget);
for (int i = 2023; i <= minimalVersion; ++i)
{
if (versionDefines.ContainsKey(i))
{
Match match = Regex.Match(defines, versionDefines[i]);
if (!match.Success)
{
defines += ";" + versionDefines[i];
}
}
}
PlayerSettings.SetScriptingDefineSymbols(namedTarget, defines);
}
}
SetAddressableAdapterSymbol();
}
// Create a Wwise Global object containing the initializer and terminator scripts. Set the SoundBank path of the initializer script.
// This game object will live for the whole project; there is no need to instanciate one per scene.
private static void CreateWwiseGlobalObject()
{
// Look for a game object which has the initializer component
#if UNITY_6000_0_OR_NEWER
var AkInitializers = UnityEngine.Object.FindObjectsByType<AkInitializer>(FindObjectsSortMode.None);
#else
var AkInitializers = UnityEngine.Object.FindObjectsOfType<AkInitializer>();
#endif
if (AkInitializers.Length > 0)
UnityEditor.Undo.DestroyObjectImmediate(AkInitializers[0].gameObject);
var WwiseGlobalGameObject = new UnityEngine.GameObject("WwiseGlobal");
// attach initializer component
UnityEditor.Undo.AddComponent<AkInitializer>(WwiseGlobalGameObject);
}
private static bool DisableBuiltInAudio()
{
UnityEditor.SerializedObject audioSettingsAsset = null;
UnityEditor.SerializedProperty disableAudioProperty = null;
var assets = UnityEditor.AssetDatabase.LoadAllAssetsAtPath("ProjectSettings/AudioManager.asset");
if (assets.Length > 0)
audioSettingsAsset = new UnityEditor.SerializedObject(assets[0]);
if (audioSettingsAsset != null)
disableAudioProperty = audioSettingsAsset.FindProperty("m_DisableAudio");
if (disableAudioProperty == null)
return false;
disableAudioProperty.boolValue = true;
audioSettingsAsset.ApplyModifiedProperties();
return true;
}
private static void MigrateRootOutputPath(string wprojPath)
{
if (string.IsNullOrEmpty(AkWwiseEditorSettings.Instance.RootOutputPath))
{
var defaultRootOutputPath = AkBasePathGetter.GetDefaultRootOutputPath();
var pathRelativeToApplicationDataPath = AkUtilities.MakeRelativePath(UnityEngine.Application.dataPath, defaultRootOutputPath);
AkWwiseEditorSettings.Instance.RootOutputPath = pathRelativeToApplicationDataPath;
AkWwiseEditorSettings.Instance.SaveSettings();
}
if (AkUtilities.IsMigrationRequired(AkUtilities.MigrationStep.RootOutputPath_v2025_1_0))
{
AkWwiseEditorSettings.MigrateRootOutputPath(wprojPath);
}
}
// Modify the .wproj file to set needed SoundBank settings
private static bool SetSoundbankSettings()
{
var settings = AkWwiseEditorSettings.Instance;
if (string.IsNullOrEmpty(settings.WwiseProjectPath))
return true;
var SoundbankPath = AkBasePathGetter.GetDefaultRootOutputPath();
if (AkWwiseEditorSettings.Instance.RootOutputPath != null)
{
var rootOutputPath = AkWwiseEditorSettings.GetRootOutputPath();
var r = new Regex(Regex.Escape("_WwiseIntegrationTemp"));
SoundbankPath = r.Replace(rootOutputPath, "", 1);
}
if (SoundbankPath == null)
{
Debug.LogWarning("Could not get Default Root Output Path.");
return false;
}
var WprojPath = AkUtilities.GetFullPath(UnityEngine.Application.dataPath, settings.WwiseProjectPath);
#if UNITY_EDITOR_OSX
SoundbankPath = "Z:" + SoundbankPath;
#endif
MigrateRootOutputPath(WprojPath);
string[] settingsToDisable = {"GenerateSoundBankXML"};
string[] settingsToEnable = {"SoundBankGenerateHeaderFile", "SoundBankGenerateMaxAttenuationInfo", "GenerateSoundBankJSON", "SoundBankGeneratePrintGUID", "SoundBankGeneratePrintPath", "AutoSoundBankEnabled"};
if (AkUtilities.SetSoundbankHeaderFilePath(WprojPath, SoundbankPath))
if (AkUtilities.ToggleBoolSoundbankSettingInWproj(settingsToDisable, WprojPath, false))
return AkUtilities.ToggleBoolSoundbankSettingInWproj(settingsToEnable, WprojPath, true);
return false;
}
public static void AddAkAudioListenerToMainCamera(bool logWarning = false)
{
UnityEngine.Camera camera = UnityEngine.Camera.main;
// Workaround for some versions of Unity not setting properly the MainCamera tag
// on the first scene of a new project
if (camera == null)
{
#if UNITY_6000_0_OR_NEWER
var cameraArray = UnityEngine.Object.FindObjectsByType<UnityEngine.Camera>(FindObjectsSortMode.None);
#else
var cameraArray = UnityEngine.Object.FindObjectsOfType<UnityEngine.Camera>();
#endif
if (cameraArray.Length > 0)
{
foreach (var entry in cameraArray)
{
if (entry.name == "Main Camera")
{
camera = entry;
break;
}
}
}
if (camera == null)
{
return;
}
}
if (camera.GetComponentInChildren<AkAudioListener>())
{
return;
}
var oldListener = camera.gameObject.GetComponent<UnityEngine.AudioListener>();
if (oldListener != null)
{
UnityEditor.Undo.DestroyObjectImmediate(oldListener);
}
var akAudioListener = UnityEditor.Undo.AddComponent<AkAudioListener>(camera.gameObject);
if (!akAudioListener)
{
return;
}
var akGameObj = akAudioListener.GetComponentInChildren<AkGameObj>();
if (akGameObj)
{
akGameObj.isEnvironmentAware = false;
}
if (logWarning)
{
UnityEngine.Debug.Log("Automatically added AkAudioListener to Main Camera. Go to \"Edit > Wwise Settings...\" to disable this functionality.");
}
}
public static BuildTargetGroup[] GetNonObsoleteTargetGroups()
{
System.Type enumType = typeof(BuildTargetGroup);
return System.Enum.GetValues(enumType).Cast<BuildTargetGroup>().Where(targetGroup =>
{
string name = targetGroup.ToString();
MemberInfo member = enumType.GetMember(name).FirstOrDefault();
if (member == null) return false;
return member.GetCustomAttribute<System.ObsoleteAttribute>() == null;
}).ToArray();
}
private static void SetAddressableAdapterSymbol()
{
foreach (BuildTargetGroup targetGroup in GetNonObsoleteTargetGroups())
{
#if UNITY_5_4_OR_NEWER
if (targetGroup == BuildTargetGroup.Unknown)
{
continue;
}
#endif
var namedTarget = UnityEditor.Build.NamedBuildTarget.FromBuildTargetGroup(targetGroup);
if (PlayerSettings.GetScriptingDefineSymbols(namedTarget).Contains(WwiseAddressableAPIDefine))
{
continue;
}
string currentDefines = PlayerSettings.GetScriptingDefineSymbols(namedTarget);
var currentDefineList = currentDefines.Split(';').ToList();
const string wwiseAddressablePrefix = "ADDRESSABLES_API";
currentDefineList.RemoveAll(define => define.StartsWith(wwiseAddressablePrefix));
currentDefineList.Add(WwiseAddressableAPIDefine);
string newDefinesString = string.Join(";", currentDefineList.Distinct());
PlayerSettings.SetScriptingDefineSymbols(namedTarget, newDefinesString);
}
}
}
#endif // UNITY_EDITOR
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 90f5790a76fd1f4449499e336513354d
@@ -0,0 +1,56 @@
/*******************************************************************************
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 Unity(R) Terms of
Service at https://unity3d.com/legal/terms-of-service
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) 2026 Audiokinetic Inc.
*******************************************************************************/
#if !UNITY_2021_1_OR_NEWER
public static class AkXboxOneUtils
{
private static readonly int[] Usages = { 0, 1, 4, 7 };
private static readonly int SessionRequirement = 0;
private static readonly int[] DeviceUsages = { 0 };
[UnityEditor.MenuItem("Assets/Wwise/Xbox One/Enable Network Sockets")]
public static void EnableXboxOneNetworkSockets()
{
var definitions = new[]
{
new SocketDefinition("WwiseDiscoverySocket", "24024", 1, "WwiseDiscovery"),
new SocketDefinition("WwiseCommandSocket", "24025", 0, "WwiseCommand")
};
foreach (var def in definitions)
{
UnityEditor.PlayerSettings.XboxOne.SetSocketDefinition(def.Name, def.Port, def.Protocol, Usages, def.TemplateName,
SessionRequirement, DeviceUsages);
}
}
private class SocketDefinition
{
public readonly string Name;
public readonly string Port;
public readonly int Protocol;
public readonly string TemplateName;
public SocketDefinition(string name, string port, int protocol, string templateName)
{
Name = name;
Port = port;
Protocol = protocol;
TemplateName = templateName;
}
}
}
#endif
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 6ff0287eef1770945b7f6cc88ed7ce3e