2025-06-03 02:42:28 -04:00
/ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
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 .
2026-03-14 03:13:10 -04:00
Copyright ( c ) 2025 Audiokinetic Inc .
2025-06-03 02:42:28 -04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /
#if ! ( UNITY_DASHBOARD_WIDGET | | UNITY_WEBPLAYER | | UNITY_WII | | UNITY_WIIU | | UNITY_NACL | | UNITY_FLASH | | UNITY_BLACKBERRY ) // Disable under unsupported platforms.
2026-03-14 03:13:10 -04:00
using System ;
2025-06-03 02:42:28 -04:00
using System.Linq ;
#if UNITY_EDITOR
2026-03-14 03:13:10 -04:00
using System.IO ;
2025-06-03 02:42:28 -04:00
using UnityEditor ;
public enum AkWwiseMenuOrder
{
ConvertIDs = 200
}
public enum AkWwiseWindowOrder
{
WwiseSettings = 305 ,
WwiseInitializationSettings = 306 ,
WwisePicker = 2300
}
public enum AkWwiseHelpOrder
{
WwiseHelpOrder = 200
}
public partial class AkUtilities
{
#region Migration
/// <summary>
/// These values represent the maximum value of the "Unity Integration Version" number in the Version.txt file that will migrated.
/// For example, in Wwise v2019.1.0, "Unity Integration Version" is 18 which means that all migrations up until this version are required.
/// </summary>
public enum MigrationStep
{
AkGameObjListenerMask_v2016_1_0 = 9 ,
AkGameObjPositionOffsetData_v2016_2_0 = 10 ,
AkAudioListener_v2017_1_0 = 14 ,
InitializationSettings_v2018_1_0 = 15 ,
WwiseTypes_v2018_1_6 = 16 ,
AkEventCallback_v2018_1_6 = 16 ,
AkAmbient_v2019_1_0 = 17 ,
NewScriptableObjectFolder_v2019_2_0 = 18 ,
2026-03-14 03:13:10 -04:00
AutoDefinedSoundBanks_v2023_1_0 = 19 ,
2025-06-03 02:42:28 -04:00
/// <summary>
/// The value that is currently in the Version.txt file.
/// </summary>
Current
}
public static bool IsMigrationRequired ( MigrationStep step )
{
return MigrationStartIndex < = ( int ) step ;
}
public static bool IsMigrating
{
get { return MigrationStartIndex < MigrationStopIndex ; }
}
public static void BeginMigration ( int startIndex )
{
if ( startIndex < MigrationStopIndex )
MigrationStartIndex = startIndex ;
}
public static void EndMigration ( )
{
MigrationStartIndex = MigrationStopIndex ;
}
public const int MigrationStopIndex = ( int ) MigrationStep . Current ;
public static int MigrationStartIndex
{
private set { migrationStartIndex = value ; }
get { return migrationStartIndex ; }
}
private static int migrationStartIndex = MigrationStopIndex ;
#endregion
private static readonly System . Collections . Generic . Dictionary < string , string > s_ProjectBankPaths =
new System . Collections . Generic . Dictionary < string , string > ( ) ;
private static System . DateTime s_LastBankPathUpdate = System . DateTime . MinValue ;
2026-03-14 03:13:10 -04:00
private static bool s_AutoBankEnabled = true ;
2025-06-03 02:42:28 -04:00
private static readonly System . Collections . Generic . Dictionary < string , System . Collections . Generic . List < string > >
s_BaseToCustomPF = new System . Collections . Generic . Dictionary < string , System . Collections . Generic . List < string > > ( ) ;
public static bool IsWwiseProjectAvailable { set ; get ; }
2026-03-14 03:13:10 -04:00
public static bool IsSoundbankGenerationAvailable ( string wwiseInstallationPath )
2025-06-03 02:42:28 -04:00
{
2026-03-14 03:13:10 -04:00
return GetWwiseConsole ( wwiseInstallationPath ) ! = null & & ! GeneratingSoundBanks ;
2025-06-03 02:42:28 -04:00
}
/// Executes a command-line. Blocks the calling thread until the new process has completed. Returns the logged stdout in one big string.
public static string ExecuteCommandLine ( string command , string arguments )
{
var process = new System . Diagnostics . Process ( ) ;
process . StartInfo . FileName = command ;
process . StartInfo . UseShellExecute = false ;
process . StartInfo . RedirectStandardOutput = true ;
process . StartInfo . CreateNoWindow = true ;
process . StartInfo . Arguments = arguments ;
process . Start ( ) ;
// Synchronously read the standard output of the spawned process.
var reader = process . StandardOutput ;
var output = reader . ReadToEnd ( ) ;
// Waiting for the process to exit directly in the UI thread. Similar cases are working that way too.
// TODO: Is it better to provide a timeout avoid any issues of forever blocking the UI thread? If so, what is
// a relevant timeout value for SoundBank generation?
process . WaitForExit ( ) ;
process . Close ( ) ;
return output ;
}
2026-03-14 03:13:10 -04:00
private static string GetWwiseConsole ( string wwiseInstallationPath )
2025-06-03 02:42:28 -04:00
{
string result = null ;
#if UNITY_EDITOR_WIN
2026-03-14 03:13:10 -04:00
if ( ! string . IsNullOrEmpty ( wwiseInstallationPath ) )
2025-06-03 02:42:28 -04:00
{
2026-03-14 03:13:10 -04:00
result = System . IO . Path . Combine ( wwiseInstallationPath , @"Authoring\x64\Release\bin\WwiseConsole.exe" ) ;
2025-06-03 02:42:28 -04:00
if ( ! System . IO . File . Exists ( result ) )
2026-03-14 03:13:10 -04:00
{
result = System . IO . Path . Combine ( wwiseInstallationPath , @"Authoring\Win32\Release\bin\WwiseConsole.exe" ) ;
}
2025-06-03 02:42:28 -04:00
}
#elif UNITY_EDITOR_OSX
2026-03-14 03:13:10 -04:00
if ( ! string . IsNullOrEmpty ( wwiseInstallationPath ) )
{
result = System . IO . Path . Combine ( wwiseInstallationPath , "Contents/Tools/WwiseConsole.sh" ) ;
}
2025-06-03 02:42:28 -04:00
#endif
if ( result ! = null & & System . IO . File . Exists ( result ) )
2026-03-14 03:13:10 -04:00
{
2025-06-03 02:42:28 -04:00
return result ;
2026-03-14 03:13:10 -04:00
}
2025-06-03 02:42:28 -04:00
return null ;
}
2026-03-14 03:13:10 -04:00
public static bool GeneratingSoundBanks = false ;
2025-06-03 02:42:28 -04:00
// Generate all the SoundBanks for all the supported platforms in the Wwise project. This effectively calls Wwise for the project
// that is configured in the UnityWwise integration.
2026-03-14 03:13:10 -04:00
public static void GenerateSoundbanks ( string wwiseInstallationPath , string wwiseProjectFullPath , System . Collections . Generic . List < string > platforms = null )
2025-06-03 02:42:28 -04:00
{
2026-03-14 03:13:10 -04:00
GeneratingSoundBanks = true ;
2025-06-03 02:42:28 -04:00
#if AK_WWISE_ADDRESSABLES & & UNITY_ADDRESSABLES
AkWwiseEditorSettings . Instance . CheckGeneratedBanksPath ( ) ;
#endif
if ( IsSoundbankOverrideEnabled ( wwiseProjectFullPath ) )
{
UnityEngine . Debug . LogWarning (
"The SoundBank generation process ignores the SoundBank Settings' Overrides currently enabled in the User settings. The project's SoundBank settings will be used." ) ;
}
2026-03-14 03:13:10 -04:00
var wwiseConsole = GetWwiseConsole ( wwiseInstallationPath ) ;
2025-06-03 02:42:28 -04:00
if ( wwiseConsole = = null )
{
UnityEngine . Debug . LogError ( "Couldn't locate WwiseConsole, unable to generate SoundBanks." ) ;
return ;
}
#if UNITY_EDITOR_WIN
var command = wwiseConsole ;
var arguments = "" ;
#elif UNITY_EDITOR_OSX
var command = "/bin/sh" ;
var arguments = "\"" + wwiseConsole + "\"" ;
#else
var command = "" ;
var arguments = "" ;
#endif
arguments + = " generate-soundbank" ;
arguments + = " \"" + wwiseProjectFullPath . Replace ( "\"" , "" ) + "\"" ;
if ( platforms ! = null & & platforms . Count ( ) > 0 )
{
arguments + = " --platform" ;
foreach ( var platform in platforms )
{
if ( ! string . IsNullOrEmpty ( platform ) )
2026-03-14 03:13:10 -04:00
{
2025-06-03 02:42:28 -04:00
arguments + = " " + platform ;
2026-03-14 03:13:10 -04:00
}
2025-06-03 02:42:28 -04:00
}
}
2026-03-14 03:13:10 -04:00
System . Threading . Tasks . Task . Run ( ( ) = > RunSoundBankGeneration ( command , arguments ) ) ;
}
private static void RunSoundBankGeneration ( string command , string arguments )
{
2025-06-03 02:42:28 -04:00
var output = ExecuteCommandLine ( command , arguments ) ;
if ( output . Contains ( "Process completed successfully." ) )
{
UnityEngine . Debug . LogFormat ( "WwiseUnity: SoundBanks generation successful:\n{0}" , output ) ;
}
else if ( output . Contains ( "Process completed with warning" ) )
{
UnityEngine . Debug . LogWarningFormat ( "WwiseUnity: SoundBanks generation has warning(s):\n{0}" , output ) ;
}
else
{
UnityEngine . Debug . LogErrorFormat ( "WwiseUnity: SoundBanks generation error:\n{0}" , output ) ;
}
2026-03-14 03:13:10 -04:00
GeneratingSoundBanks = false ;
2025-06-03 02:42:28 -04:00
UnityEditor . AssetDatabase . Refresh ( ) ;
}
/// Reads the user settings (not the project settings) to check if there is an override currently defined for the SoundBank generation folders.
public static bool IsSoundbankOverrideEnabled ( string wwiseProjectPath )
{
var userConfigFile = System . IO . Path . Combine ( System . IO . Path . GetDirectoryName ( wwiseProjectPath ) ,
System . IO . Path . GetFileNameWithoutExtension ( wwiseProjectPath ) + "." + System . Environment . UserName + ".wsettings" ) ;
if ( ! System . IO . File . Exists ( userConfigFile ) )
2026-03-14 03:13:10 -04:00
{
2025-06-03 02:42:28 -04:00
return false ;
2026-03-14 03:13:10 -04:00
}
2025-06-03 02:42:28 -04:00
var userConfigDoc = new System . Xml . XmlDocument ( ) ;
userConfigDoc . Load ( userConfigFile ) ;
var userConfigNavigator = userConfigDoc . CreateNavigator ( ) ;
var userConfigNode = userConfigNavigator . SelectSingleNode (
System . Xml . XPath . XPathExpression . Compile ( "//Property[@Name='SoundBankPathUserOverride' and @Value = 'True']" ) ) ;
return userConfigNode ! = null ;
}
2026-03-14 03:13:10 -04:00
public static bool IsAutoBankEnabled ( )
2025-06-03 02:42:28 -04:00
{
2026-03-14 03:13:10 -04:00
return s_AutoBankEnabled ;
2025-06-03 02:42:28 -04:00
}
2026-03-14 03:13:10 -04:00
public static System . Collections . Generic . IDictionary < string , System . Collections . Generic . List < string > > PlatformMapping
2025-06-03 02:42:28 -04:00
{
2026-03-14 03:13:10 -04:00
get { return s_BaseToCustomPF ; }
2025-06-03 02:42:28 -04:00
}
2026-03-14 03:13:10 -04:00
public static System . Collections . Generic . IDictionary < string , string > GetAllBankPaths ( string wwiseProjectPath )
2025-06-03 02:42:28 -04:00
{
2026-03-14 03:13:10 -04:00
UpdateSoundbanksDestinationFolders ( wwiseProjectPath ) ;
2025-06-03 02:42:28 -04:00
return s_ProjectBankPaths ;
}
2026-03-14 03:13:10 -04:00
2025-06-03 02:42:28 -04:00
// Parses the .wproj to find out where SoundBanks are generated for the given path.
2026-03-14 03:13:10 -04:00
public static string GetWwiseSoundBankDestinationFolder ( string Platform , string wwiseProjectAbsolutePath )
2025-06-03 02:42:28 -04:00
{
try
{
2026-03-14 03:13:10 -04:00
UpdateSoundbanksDestinationFolders ( wwiseProjectAbsolutePath ) ;
2025-06-03 02:42:28 -04:00
return s_ProjectBankPaths [ Platform ] ;
}
catch
{
return "" ;
}
}
public delegate void GetEventDurationsFunc ( uint eventID , ref float maximum , ref float minimum ) ;
public static GetEventDurationsFunc GetEventDurations = ( uint eventID , ref float maximum , ref float minimum ) = > { maximum = minimum = - 1.0f ; } ;
private static void UpdateSoundbanksDestinationFolders ( string WwiseProjectPath )
{
try
{
if ( WwiseProjectPath . Length = = 0 )
2026-03-14 03:13:10 -04:00
{
return ;
}
if ( ! AkUtilities . IsWwiseProjectAvailable )
{
IsWwiseProjectAvailable = System . IO . File . Exists ( WwiseProjectPath ) ;
if ( ! IsWwiseProjectAvailable )
{
return ;
}
}
s_ProjectBankPaths . Clear ( ) ;
var doc = new System . Xml . XmlDocument ( ) ;
doc . Load ( WwiseProjectPath ) ;
var Navigator = doc . CreateNavigator ( ) ;
// Gather the mapping of Custom platform to Base platform
var itpf = Navigator . Select ( "//Platform" ) ;
s_BaseToCustomPF . Clear ( ) ;
foreach ( System . Xml . XPath . XPathNavigator node in itpf )
{
System . Collections . Generic . List < string > customList = null ;
var basePF = node . GetAttribute ( "ReferencePlatform" , "" ) ;
if ( ! s_BaseToCustomPF . TryGetValue ( basePF , out customList ) )
{
customList = new System . Collections . Generic . List < string > ( ) ;
s_BaseToCustomPF [ basePF ] = customList ;
}
customList . Add ( node . GetAttribute ( "Name" , "" ) ) ;
}
// Navigate the wproj file (XML format) to where generated SoundBank paths are stored
var it = Navigator . Select ( "//Property[@Name='SoundBankPaths']/ValueList/Value" ) ;
foreach ( System . Xml . XPath . XPathNavigator node in it )
{
var path = node . Value ;
FixSlashes ( ref path ) ;
var pf = node . GetAttribute ( "Platform" , "" ) ;
s_ProjectBankPaths [ pf ] = path ;
}
}
catch ( System . Exception ex )
{
UnityEngine . Debug . LogError ( "WwiseUnity: Error while reading project " + WwiseProjectPath + ". Exception: " + ex . Message ) ;
}
}
private static bool UpdateAutoBankSetting ( string WwiseProjectPath )
{
var doc = new System . Xml . XmlDocument { PreserveWhitespace = true } ;
doc . Load ( WwiseProjectPath ) ;
var Navigator = doc . CreateNavigator ( ) ;
// Navigate the wproj file (XML format) to where our setting should be
var pathInXml = string . Format ( "/WwiseDocument/ProjectInfo/Project/PropertyList/Property[@Name='{0}']" , "AutoSoundBankEnabled" ) ;
var expression = System . Xml . XPath . XPathExpression . Compile ( pathInXml ) ;
var node = Navigator . SelectSingleNode ( expression ) ;
s_AutoBankEnabled = node ! = null ;
return s_AutoBankEnabled ;
}
public static string GetRootOutputPath ( string WwiseProjectPath )
{
if ( ! System . IO . File . Exists ( WwiseProjectPath ) )
{
return "" ;
}
var doc = new System . Xml . XmlDocument { PreserveWhitespace = true } ;
doc . Load ( WwiseProjectPath ) ;
var Navigator = doc . CreateNavigator ( ) ;
// Navigate the wproj file (XML format) to where our setting should be
var pathInXml = string . Format ( "/WwiseDocument/ProjectInfo/Project/PropertyList/Property[@Name='{0}']" , "SoundBankHeaderFilePath" ) ;
var expression = System . Xml . XPath . XPathExpression . Compile ( pathInXml ) ;
var rootOutputPath = Navigator . SelectSingleNode ( expression ) . GetAttribute ( "Value" , "" ) ;
#if UNITY_EDITOR_OSX
rootOutputPath = ParseOsxPathFromWinePath ( rootOutputPath ) ;
if ( ! Path . IsPathRooted ( rootOutputPath ) )
{
string projectPath = Path . GetDirectoryName ( WwiseProjectPath ) ;
projectPath = ParseOsxPathFromWinePath ( projectPath ) ;
rootOutputPath = GetFullPath ( projectPath , rootOutputPath ) ;
}
#endif
return rootOutputPath ;
}
public static void SetWwiseRootOutputPath ( string WwiseProjectPath , string destinationPath )
{
try
{
if ( WwiseProjectPath . Length = = 0 )
{
2025-06-03 02:42:28 -04:00
return ;
2026-03-14 03:13:10 -04:00
}
2025-06-03 02:42:28 -04:00
if ( ! System . IO . File . Exists ( WwiseProjectPath ) )
2026-03-14 03:13:10 -04:00
{
2025-06-03 02:42:28 -04:00
return ;
2026-03-14 03:13:10 -04:00
}
2025-06-03 02:42:28 -04:00
2026-03-14 03:13:10 -04:00
s_ProjectBankPaths . Clear ( ) ;
var doc = new System . Xml . XmlDocument ( ) ;
doc . Load ( WwiseProjectPath ) ;
var Navigator = doc . CreateNavigator ( ) ;
// Navigate the wproj file (XML format) to where generated SoundBank paths are stored
var it = Navigator . Select ( "//Property[@Name='SoundBankHeaderFilePath']" ) ;
foreach ( System . Xml . XPath . XPathNavigator node in it )
{
if ( node . MoveToAttribute ( "Value" , "" ) )
{
var path = $"{destinationPath}" ;
FixSlashes ( ref path ) ;
node . SetValue ( path ) ;
}
}
doc . Save ( WwiseProjectPath ) ;
}
catch ( System . Exception ex )
{
UnityEngine . Debug . LogError ( "WwiseUnity: Error while reading project " + WwiseProjectPath + ". Exception: " + ex . Message ) ;
}
}
public static void SetPlatformsSoundBankPath ( string WwiseProjectPath , string destinationPath )
{
try
{
if ( WwiseProjectPath . Length = = 0 )
{
return ;
}
if ( ! System . IO . File . Exists ( WwiseProjectPath ) )
{
2025-06-03 02:42:28 -04:00
return ;
2026-03-14 03:13:10 -04:00
}
2025-06-03 02:42:28 -04:00
s_ProjectBankPaths . Clear ( ) ;
2026-03-14 03:13:10 -04:00
2025-06-03 02:42:28 -04:00
var doc = new System . Xml . XmlDocument ( ) ;
doc . Load ( WwiseProjectPath ) ;
var Navigator = doc . CreateNavigator ( ) ;
// Gather the mapping of Custom platform to Base platform
var itpf = Navigator . Select ( "//Platform" ) ;
s_BaseToCustomPF . Clear ( ) ;
foreach ( System . Xml . XPath . XPathNavigator node in itpf )
{
System . Collections . Generic . List < string > customList = null ;
var basePF = node . GetAttribute ( "ReferencePlatform" , "" ) ;
if ( ! s_BaseToCustomPF . TryGetValue ( basePF , out customList ) )
{
customList = new System . Collections . Generic . List < string > ( ) ;
s_BaseToCustomPF [ basePF ] = customList ;
}
2026-03-14 03:13:10 -04:00
2025-06-03 02:42:28 -04:00
customList . Add ( node . GetAttribute ( "Name" , "" ) ) ;
}
// Navigate the wproj file (XML format) to where generated SoundBank paths are stored
var it = Navigator . Select ( "//Property[@Name='SoundBankPaths']/ValueList/Value" ) ;
foreach ( System . Xml . XPath . XPathNavigator node in it )
{
var pf = node . GetAttribute ( "Platform" , "" ) ;
2026-03-14 03:13:10 -04:00
var path = $"{destinationPath}/{pf}" ;
FixSlashes ( ref path ) ;
node . SetValue ( path ) ;
2025-06-03 02:42:28 -04:00
s_ProjectBankPaths [ pf ] = path ;
}
2026-03-14 03:13:10 -04:00
doc . Save ( WwiseProjectPath ) ;
2025-06-03 02:42:28 -04:00
}
catch ( System . Exception ex )
{
UnityEngine . Debug . LogError ( "WwiseUnity: Error while reading project " + WwiseProjectPath + ". Exception: " + ex . Message ) ;
}
}
public static void SetSoundbanksDestinationFoldersInWproj ( string WwiseProjectPath , string destinationPath )
{
try
{
if ( WwiseProjectPath . Length = = 0 )
2026-03-14 03:13:10 -04:00
{
2025-06-03 02:42:28 -04:00
return ;
2026-03-14 03:13:10 -04:00
}
2025-06-03 02:42:28 -04:00
if ( ! System . IO . File . Exists ( WwiseProjectPath ) )
2026-03-14 03:13:10 -04:00
{
2025-06-03 02:42:28 -04:00
return ;
2026-03-14 03:13:10 -04:00
}
2025-06-03 02:42:28 -04:00
s_ProjectBankPaths . Clear ( ) ;
var doc = new System . Xml . XmlDocument ( ) ;
doc . Load ( WwiseProjectPath ) ;
var Navigator = doc . CreateNavigator ( ) ;
// Gather the mapping of Custom platform to Base platform
var itpf = Navigator . Select ( "//Platform" ) ;
s_BaseToCustomPF . Clear ( ) ;
foreach ( System . Xml . XPath . XPathNavigator node in itpf )
{
System . Collections . Generic . List < string > customList = null ;
var basePF = node . GetAttribute ( "ReferencePlatform" , "" ) ;
if ( ! s_BaseToCustomPF . TryGetValue ( basePF , out customList ) )
{
customList = new System . Collections . Generic . List < string > ( ) ;
s_BaseToCustomPF [ basePF ] = customList ;
}
customList . Add ( node . GetAttribute ( "Name" , "" ) ) ;
}
// Navigate the wproj file (XML format) to where generated SoundBank paths are stored
var it = Navigator . Select ( "//Property[@Name='SoundBankPaths']/ValueList/Value" ) ;
foreach ( System . Xml . XPath . XPathNavigator node in it )
{
var pf = node . GetAttribute ( "Platform" , "" ) ;
var path = $"{destinationPath}/{pf}" ;
FixSlashes ( ref path ) ;
node . SetValue ( path ) ;
s_ProjectBankPaths [ pf ] = path ;
}
2026-03-14 03:13:10 -04:00
it = Navigator . Select ( "//Property[@Name='SoundBankHeaderFilePath']" ) ;
foreach ( System . Xml . XPath . XPathNavigator node in it )
{
if ( node . MoveToAttribute ( "Value" , "" ) )
{
var path = $"{destinationPath}" ;
FixSlashes ( ref path ) ;
node . SetValue ( path ) ;
}
}
doc . Save ( WwiseProjectPath ) ;
}
catch ( System . Exception ex )
{
UnityEngine . Debug . LogError ( "WwiseUnity: Error while reading project " + WwiseProjectPath + ". Exception: " + ex . Message ) ;
}
}
public static void SetExternalSourceDestinationFolderInWproj ( string WwiseProjectPath , string destinationPath )
{
try
{
if ( WwiseProjectPath . Length = = 0 )
{
return ;
}
if ( ! System . IO . File . Exists ( WwiseProjectPath ) )
{
return ;
}
s_ProjectBankPaths . Clear ( ) ;
var doc = new System . Xml . XmlDocument ( ) ;
doc . Load ( WwiseProjectPath ) ;
var navigator = doc . CreateNavigator ( ) ;
// Navigate the wproj file (XML format) to where generated SoundBank paths are stored
var it = navigator . Select ( "//Property[@Name='ExternalSourcesOutputPath']/ValueList/Value" ) ;
foreach ( System . Xml . XPath . XPathNavigator node in it )
{
var pf = node . GetAttribute ( "Platform" , "" ) ;
var path = $"{destinationPath}/{pf}" ;
FixSlashes ( ref path ) ;
node . SetValue ( path ) ;
s_ProjectBankPaths [ pf ] = path ;
}
2025-06-03 02:42:28 -04:00
doc . Save ( WwiseProjectPath ) ;
}
catch ( System . Exception ex )
{
UnityEngine . Debug . LogError ( "WwiseUnity: Error while reading project " + WwiseProjectPath + ". Exception: " + ex . Message ) ;
}
}
2026-03-14 03:13:10 -04:00
private static void CheckWwiseProjectUpdate ( string WwiseProjectPath )
{
try
{
if ( WwiseProjectPath . Length = = 0 )
return ;
if ( ! AkUtilities . IsWwiseProjectAvailable )
return ;
var t = System . IO . File . GetLastWriteTime ( WwiseProjectPath ) ;
if ( t < = s_LastBankPathUpdate )
return ;
s_LastBankPathUpdate = t ;
UpdateSoundbanksDestinationFolders ( WwiseProjectPath ) ;
UpdateAutoBankSetting ( WwiseProjectPath ) ;
}
catch ( System . Exception ex )
{
UnityEngine . Debug . LogError ( "WwiseUnity: Error while reading project " + WwiseProjectPath + ". Exception: " + ex . Message ) ;
}
}
public static void WwiseProjectUpdated ( string WwiseProjectPath )
2025-06-03 02:42:28 -04:00
{
2026-03-14 03:13:10 -04:00
CheckWwiseProjectUpdate ( WwiseProjectPath ) ;
2025-06-03 02:42:28 -04:00
}
// Set SoundBank-related bool settings in the wproj file.
2026-03-14 03:13:10 -04:00
public static bool ToggleBoolSoundbankSettingInWproj ( string [ ] SettingName , string WwiseProjectPath , bool Enable = true )
2025-06-03 02:42:28 -04:00
{
try
{
if ( WwiseProjectPath . Length = = 0 )
2026-03-14 03:13:10 -04:00
{
2025-06-03 02:42:28 -04:00
return true ;
2026-03-14 03:13:10 -04:00
}
2025-06-03 02:42:28 -04:00
var doc = new System . Xml . XmlDocument { PreserveWhitespace = true } ;
doc . Load ( WwiseProjectPath ) ;
var Navigator = doc . CreateNavigator ( ) ;
2026-03-14 03:13:10 -04:00
bool WprojWasEdited = false ;
2025-06-03 02:42:28 -04:00
2026-03-14 03:13:10 -04:00
foreach ( var name in SettingName )
2025-06-03 02:42:28 -04:00
{
2026-03-14 03:13:10 -04:00
// Navigate the wproj file (XML format) to where our setting should be
var pathInXml = string . Format ( "/WwiseDocument/ProjectInfo/Project/PropertyList/Property[@Name='{0}']" ,
name ) ;
var expression = System . Xml . XPath . XPathExpression . Compile ( pathInXml ) ;
var node = Navigator . SelectSingleNode ( expression ) ;
2025-06-03 02:42:28 -04:00
if ( node = = null )
{
2026-03-14 03:13:10 -04:00
// Setting isn't in the wproj, add it
// Navigate to the SoundBankHeaderFilePath property (it is always there)
expression =
System . Xml . XPath . XPathExpression . Compile (
"/WwiseDocument/ProjectInfo/Project/PropertyList/Property[@Name='SoundBankHeaderFilePath']" ) ;
node = Navigator . SelectSingleNode ( expression ) ;
if ( node = = null )
{
// SoundBankHeaderFilePath not in wproj, invalid wproj file
UnityEngine . Debug . LogError (
"WwiseUnity: Could not find SoundBankHeaderFilePath property in Wwise project file. File is invalid." ) ;
return false ;
}
// Add the setting right above SoundBankHeaderFilePath
var propertyToInsert = string . Format ( "<Property Name=\"{0}\" Type=\"bool\" Value=\"{1}\"/>" , name , Enable ? "True" : "False" ) ;
node . InsertBefore ( propertyToInsert ) ;
WprojWasEdited = true ;
2025-06-03 02:42:28 -04:00
}
2026-03-14 03:13:10 -04:00
else if ( node . GetAttribute ( "Value" , "" ) = = ( Enable ? "False" : "True" ) )
{
// Value is present, we simply have to modify it.
if ( ! node . MoveToAttribute ( "Value" , "" ) )
{
return false ;
}
2025-06-03 02:42:28 -04:00
2026-03-14 03:13:10 -04:00
// Modify the value to true
node . SetValue ( Enable ? "True" : "False" ) ;
WprojWasEdited = true ;
}
2025-06-03 02:42:28 -04:00
}
2026-03-14 03:13:10 -04:00
if ( WprojWasEdited )
2025-06-03 02:42:28 -04:00
{
2026-03-14 03:13:10 -04:00
doc . Save ( WwiseProjectPath ) ;
2025-06-03 02:42:28 -04:00
}
return true ;
}
catch
{
return false ;
}
}
public static bool SetSoundbankHeaderFilePath ( string WwiseProjectPath , string SoundbankPath )
{
try
{
if ( WwiseProjectPath . Length = = 0 )
2026-03-14 03:13:10 -04:00
{
2025-06-03 02:42:28 -04:00
return true ;
2026-03-14 03:13:10 -04:00
}
2025-06-03 02:42:28 -04:00
var doc = new System . Xml . XmlDocument { PreserveWhitespace = true } ;
doc . Load ( WwiseProjectPath ) ;
var Navigator = doc . CreateNavigator ( ) ;
// Navigate to where the header file path is saved. The node has to be there, or else the wproj is invalid.
var expression =
System . Xml . XPath . XPathExpression . Compile (
"/WwiseDocument/ProjectInfo/Project/PropertyList/Property[@Name='SoundBankHeaderFilePath']" ) ;
var node = Navigator . SelectSingleNode ( expression ) ;
if ( node = = null )
{
UnityEngine . Debug . LogError (
"Could not find SoundBankHeaderFilePath property in Wwise project file. File is invalid." ) ;
return false ;
}
// Change the "Value" attribute
if ( ! node . MoveToAttribute ( "Value" , "" ) )
2026-03-14 03:13:10 -04:00
{
2025-06-03 02:42:28 -04:00
return false ;
2026-03-14 03:13:10 -04:00
}
2025-06-03 02:42:28 -04:00
node . SetValue ( SoundbankPath ) ;
doc . Save ( WwiseProjectPath ) ;
return true ;
}
catch
{
return false ;
}
}
2026-03-14 03:13:10 -04:00
public static bool IsSettingEnabled ( string wProjPath , string settingName )
{
var doc = new System . Xml . XmlDocument { PreserveWhitespace = true } ;
doc . Load ( wProjPath ) ;
var Navigator = doc . CreateNavigator ( ) ;
// Navigate the wproj file (XML format) to where or setting should be
var pathInXml = string . Format ( "/WwiseDocument/ProjectInfo/Project/PropertyList/Property[@Name='{0}']" , settingName ) ;
var expression = System . Xml . XPath . XPathExpression . Compile ( pathInXml ) ;
var node = Navigator . SelectSingleNode ( expression ) ;
var IsJsonFileGenerationEnabled = node ! = null ? node . GetAttribute ( "Value" , "" ) : "False" ;
return IsJsonFileGenerationEnabled = = "True" ;
}
2025-06-03 02:42:28 -04:00
// Make two paths relative to each other
public static string MakeRelativePath ( string fromPath , string toPath )
{
// MONO BUG: https://github.com/mono/mono/pull/471
// In the editor, Application.dataPath returns <Project Folder>/Assets. There is a bug in
// mono for method Uri.GetRelativeUri where if the path ends in a folder, it will
// ignore the last part of the path. Thus, we need to add fake depth to get the "real"
// relative path.
fromPath + = "/fake_depth" ;
try
{
if ( string . IsNullOrEmpty ( fromPath ) )
2026-03-14 03:13:10 -04:00
{
2025-06-03 02:42:28 -04:00
return toPath ;
2026-03-14 03:13:10 -04:00
}
2025-06-03 02:42:28 -04:00
if ( string . IsNullOrEmpty ( toPath ) )
2026-03-14 03:13:10 -04:00
{
2025-06-03 02:42:28 -04:00
return "" ;
2026-03-14 03:13:10 -04:00
}
2025-06-03 02:42:28 -04:00
var fromUri = new System . Uri ( fromPath ) ;
var toUri = new System . Uri ( toPath ) ;
if ( fromUri . Scheme ! = toUri . Scheme )
2026-03-14 03:13:10 -04:00
{
2025-06-03 02:42:28 -04:00
return toPath ;
2026-03-14 03:13:10 -04:00
}
2025-06-03 02:42:28 -04:00
var relativeUri = fromUri . MakeRelativeUri ( toUri ) ;
var relativePath = System . Uri . UnescapeDataString ( relativeUri . ToString ( ) ) ;
return relativePath ;
}
catch
{
return toPath ;
}
}
// Reconcile a base path and a relative path to give a full path without any ".."
public static string GetFullPath ( string BasePath , string RelativePath )
{
if ( string . IsNullOrEmpty ( BasePath ) )
2026-03-14 03:13:10 -04:00
{
2025-06-03 02:42:28 -04:00
return "" ;
2026-03-14 03:13:10 -04:00
}
2025-06-03 02:42:28 -04:00
var wrongSeparatorChar = System . IO . Path . DirectorySeparatorChar = = '/' ? '\\' : '/' ;
if ( string . IsNullOrEmpty ( RelativePath ) )
2026-03-14 03:13:10 -04:00
{
2025-06-03 02:42:28 -04:00
return BasePath . Replace ( wrongSeparatorChar , System . IO . Path . DirectorySeparatorChar ) ;
2026-03-14 03:13:10 -04:00
}
2025-06-03 02:42:28 -04:00
if ( System . IO . Path . GetPathRoot ( RelativePath ) ! = "" )
2026-03-14 03:13:10 -04:00
{
2025-06-03 02:42:28 -04:00
return RelativePath . Replace ( wrongSeparatorChar , System . IO . Path . DirectorySeparatorChar ) ;
2026-03-14 03:13:10 -04:00
}
2025-06-03 02:42:28 -04:00
return System . IO . Path . GetFullPath ( System . IO . Path . Combine ( BasePath , RelativePath ) ) ;
}
public static bool DirectoryCopy ( string sourceDirName , string destDirName , bool copySubDirs )
{
var dir = new System . IO . DirectoryInfo ( sourceDirName ) ;
if ( ! dir . Exists )
{
UnityEngine . Debug . LogError ( "WwiseUnity: Source directory doesn't exist" ) ;
return false ;
}
if ( ! System . IO . Directory . Exists ( destDirName ) )
2026-03-14 03:13:10 -04:00
{
2025-06-03 02:42:28 -04:00
System . IO . Directory . CreateDirectory ( destDirName ) ;
2026-03-14 03:13:10 -04:00
}
2025-06-03 02:42:28 -04:00
var files = dir . GetFiles ( ) ;
foreach ( var file in files )
{
var destFilePath = System . IO . Path . Combine ( destDirName , file . Name ) ;
if ( System . IO . File . Exists ( destFilePath ) )
2026-03-14 03:13:10 -04:00
{
2025-06-03 02:42:28 -04:00
UnityEngine . Debug . LogWarningFormat ( "WwiseUnity: Destination file path will be overwritten: {0}" , destFilePath ) ;
2026-03-14 03:13:10 -04:00
}
2025-06-03 02:42:28 -04:00
file . CopyTo ( destFilePath , true ) ;
}
if ( ! copySubDirs )
2026-03-14 03:13:10 -04:00
{
2025-06-03 02:42:28 -04:00
return true ;
2026-03-14 03:13:10 -04:00
}
2025-06-03 02:42:28 -04:00
var dirs = dir . GetDirectories ( ) ;
foreach ( var subdir in dirs )
{
var destSubDirName = System . IO . Path . Combine ( destDirName , subdir . Name ) ;
DirectoryCopy ( subdir . FullName , destSubDirName , copySubDirs ) ;
}
return true ;
}
public static bool MoveAssetsFromDirectory ( string sourceDirName , string destDirName , bool copySubDirs )
{
var dir = new System . IO . DirectoryInfo ( sourceDirName ) ;
if ( ! dir . Exists )
{
UnityEngine . Debug . LogError ( "WwiseUnity: Source directory doesn't exist" ) ;
return false ;
}
if ( ! System . IO . Directory . Exists ( destDirName ) )
2026-03-14 03:13:10 -04:00
{
2025-06-03 02:42:28 -04:00
AssetDatabase . CreateFolder ( System . IO . Path . GetDirectoryName ( destDirName ) , System . IO . Path . GetFileName ( destDirName ) ) ;
2026-03-14 03:13:10 -04:00
}
2025-06-03 02:42:28 -04:00
var files = dir . GetFiles ( ) ;
string error , source , destFilePath ;
foreach ( var file in files )
{
2026-03-14 03:13:10 -04:00
if ( file . Extension = = ".meta" )
{
continue ;
}
2025-06-03 02:42:28 -04:00
destFilePath = System . IO . Path . Combine ( destDirName , file . Name ) ;
if ( System . IO . File . Exists ( destFilePath ) )
2026-03-14 03:13:10 -04:00
{
2025-06-03 02:42:28 -04:00
UnityEngine . Debug . LogWarningFormat ( "WwiseUnity: Destination file path will be overwritten: {0}" , destFilePath ) ;
2026-03-14 03:13:10 -04:00
}
2025-06-03 02:42:28 -04:00
source = System . IO . Path . Combine ( "Assets" , AkUtilities . MakeRelativePath ( UnityEngine . Application . dataPath , file . FullName ) ) ;
source = source . Replace ( System . IO . Path . AltDirectorySeparatorChar , System . IO . Path . DirectorySeparatorChar ) ;
error = AssetDatabase . MoveAsset ( source , destFilePath ) ;
if ( ! string . IsNullOrEmpty ( error ) )
2026-03-14 03:13:10 -04:00
{
2025-06-03 02:42:28 -04:00
UnityEngine . Debug . LogErrorFormat ( "WwiseUnity: Error while attempting to move <{0}> to <{1}>: {2}" , source , destFilePath , error ) ;
2026-03-14 03:13:10 -04:00
}
2025-06-03 02:42:28 -04:00
}
if ( ! copySubDirs )
2026-03-14 03:13:10 -04:00
{
2025-06-03 02:42:28 -04:00
return true ;
2026-03-14 03:13:10 -04:00
}
2025-06-03 02:42:28 -04:00
var dirs = dir . GetDirectories ( ) ;
foreach ( var subdir in dirs )
{
source = System . IO . Path . Combine ( "Assets" , AkUtilities . MakeRelativePath ( UnityEngine . Application . dataPath , subdir . FullName ) ) ;
source = source . Replace ( System . IO . Path . AltDirectorySeparatorChar , System . IO . Path . DirectorySeparatorChar ) ;
var destSubDirName = System . IO . Path . Combine ( destDirName , subdir . Name ) ;
error = UnityEditor . AssetDatabase . MoveAsset ( source , destSubDirName ) ;
if ( ! string . IsNullOrEmpty ( error ) )
2026-03-14 03:13:10 -04:00
{
2025-06-03 02:42:28 -04:00
UnityEngine . Debug . LogErrorFormat ( "WwiseUnity: Error while attempting to move <{0}> to <{1}>: {2}" , source , destSubDirName , error ) ;
2026-03-14 03:13:10 -04:00
}
2025-06-03 02:42:28 -04:00
}
return true ;
}
public static bool CreateFolder ( string folderToCreate )
{
var created = false ;
var folder = string . Empty ;
var folders = folderToCreate . Split ( System . IO . Path . AltDirectorySeparatorChar , System . IO . Path . DirectorySeparatorChar ) ;
for ( int i = 0 ; i < folders . Length ; + + i )
{
var parentFolder = folder ;
folder = string . IsNullOrEmpty ( parentFolder ) ? folders [ i ] : System . IO . Path . Combine ( parentFolder , folders [ i ] ) ;
if ( UnityEditor . AssetDatabase . IsValidFolder ( folder ) )
{
continue ;
}
var error = UnityEditor . AssetDatabase . CreateFolder ( parentFolder , folders [ i ] ) ;
if ( string . IsNullOrEmpty ( error ) )
{
2026-03-14 03:13:10 -04:00
UnityEngine . Debug . LogFormat ( "WwiseUnity: Created folder <{0}> in <{0}>" , folders [ i ] , parentFolder ) ;
2025-06-03 02:42:28 -04:00
created = true ;
continue ;
}
return false ;
}
if ( created )
2026-03-14 03:13:10 -04:00
{
2025-06-03 02:42:28 -04:00
UnityEditor . AssetDatabase . SaveAssets ( ) ;
2026-03-14 03:13:10 -04:00
}
2025-06-03 02:42:28 -04:00
return true ;
}
/// <summary>
/// Renames or moves a folder using UnityEditor.Database API.
/// </summary>
/// <param name="oldPath"></param>
/// <param name="newPath"></param>
/// <returns>Returns true if the operation was successful.</returns>
public static bool MoveFolder ( string oldPath , string newPath )
{
oldPath = oldPath . Replace ( System . IO . Path . AltDirectorySeparatorChar , System . IO . Path . DirectorySeparatorChar ) ;
newPath = newPath . Replace ( System . IO . Path . AltDirectorySeparatorChar , System . IO . Path . DirectorySeparatorChar ) ;
2026-03-14 03:13:10 -04:00
2025-06-03 02:42:28 -04:00
if ( oldPath . Equals ( newPath , System . StringComparison . OrdinalIgnoreCase ) )
2026-03-14 03:13:10 -04:00
{
return false ;
}
if ( ! AssetDatabase . IsValidFolder ( oldPath ) )
{
UnityEngine . Debug . LogWarningFormat ( "WwiseUnity: Refusing to move nonexistent folder <{0}>" , oldPath ) ;
2025-06-03 02:42:28 -04:00
return false ;
2026-03-14 03:13:10 -04:00
}
2025-06-03 02:42:28 -04:00
var error = string . Empty ;
var newParentFolder = System . IO . Path . GetDirectoryName ( newPath ) ;
if ( System . IO . Path . GetDirectoryName ( oldPath ) = = newParentFolder )
{
error = UnityEditor . AssetDatabase . RenameAsset ( oldPath , newPath . Substring ( newParentFolder . Length + 1 ) ) ;
if ( string . IsNullOrEmpty ( error ) )
2026-03-14 03:13:10 -04:00
{
2025-06-03 02:42:28 -04:00
return true ;
2026-03-14 03:13:10 -04:00
}
2025-06-03 02:42:28 -04:00
UnityEngine . Debug . LogErrorFormat ( "WwiseUnity: Error while attempting to rename folder <{0}> to <{1}>: {2}" , oldPath , newPath , error ) ;
return false ;
}
if ( ! CreateFolder ( newParentFolder ) )
2026-03-14 03:13:10 -04:00
{
2025-06-03 02:42:28 -04:00
return false ;
2026-03-14 03:13:10 -04:00
}
2025-06-03 02:42:28 -04:00
error = UnityEditor . AssetDatabase . MoveAsset ( oldPath , newPath ) ;
if ( string . IsNullOrEmpty ( error ) )
2026-03-14 03:13:10 -04:00
{
2025-06-03 02:42:28 -04:00
return true ;
2026-03-14 03:13:10 -04:00
}
2025-06-03 02:42:28 -04:00
UnityEngine . Debug . LogWarningFormat ( "WwiseUnity: Error while attempting to move folder <{0}> to <{1}>: {2}" , oldPath , newPath , error ) ;
return false ;
}
public static void RepaintInspector ( )
{
var windows = UnityEngine . Resources . FindObjectsOfTypeAll < UnityEditor . EditorWindow > ( ) ;
foreach ( var win in windows )
if ( win . titleContent . text = = "Inspector" )
2026-03-14 03:13:10 -04:00
{
2025-06-03 02:42:28 -04:00
win . Repaint ( ) ;
2026-03-14 03:13:10 -04:00
}
2025-06-03 02:42:28 -04:00
}
public static string ParseOsxPathFromWinePath ( string path )
{
string ret = path . Replace ( "Y:" , System . Environment . GetEnvironmentVariable ( "HOME" ) ) ;
ret = ret . Replace ( "Z:" , "" ) ;
ret = ret . Replace ( '\\' , '/' ) ;
return ret ;
}
#region Tooltip Workaround
private static System . Reflection . FieldInfo GetFieldInfoFromProperty ( UnityEditor . SerializedProperty property )
{
var serializedProperty = property . serializedObject . FindProperty ( "m_Script" ) ;
if ( serializedProperty = = null )
2026-03-14 03:13:10 -04:00
{
2025-06-03 02:42:28 -04:00
return null ;
2026-03-14 03:13:10 -04:00
}
2025-06-03 02:42:28 -04:00
var monoScript = serializedProperty . objectReferenceValue as UnityEditor . MonoScript ;
if ( monoScript = = null )
2026-03-14 03:13:10 -04:00
{
2025-06-03 02:42:28 -04:00
return null ;
2026-03-14 03:13:10 -04:00
}
2025-06-03 02:42:28 -04:00
var scriptTypeFromProperty = monoScript . GetClass ( ) ;
if ( scriptTypeFromProperty = = null )
2026-03-14 03:13:10 -04:00
{
2025-06-03 02:42:28 -04:00
return null ;
2026-03-14 03:13:10 -04:00
}
2025-06-03 02:42:28 -04:00
return GetFieldInfoFromPropertyPath ( scriptTypeFromProperty , property . propertyPath ) ;
}
private static System . Reflection . FieldInfo GetFieldInfoFromPropertyPath ( System . Type host , string path )
{
System . Reflection . FieldInfo fieldInfo = null ;
var type = host ;
var array = path . Split ( '.' ) ;
for ( int i = 0 ; i < array . Length ; + + i )
{
string text = array [ i ] ;
if ( i < array . Length - 1 & & text = = "Array" & & array [ i + 1 ] . StartsWith ( "data[" ) )
{
if ( type . IsArray )
2026-03-14 03:13:10 -04:00
{
2025-06-03 02:42:28 -04:00
type = type . GetElementType ( ) ;
2026-03-14 03:13:10 -04:00
}
2025-06-03 02:42:28 -04:00
else if ( type . IsGenericType & & type . GetGenericTypeDefinition ( ) = = typeof ( System . Collections . Generic . List < > ) )
2026-03-14 03:13:10 -04:00
{
2025-06-03 02:42:28 -04:00
type = type . GetGenericArguments ( ) [ 0 ] ;
2026-03-14 03:13:10 -04:00
}
2025-06-03 02:42:28 -04:00
i + + ;
}
else
{
var type2 = type ;
while ( type2 ! = null )
{
fieldInfo = type2 . GetField ( text , System . Reflection . BindingFlags . Instance | System . Reflection . BindingFlags . Public | System . Reflection . BindingFlags . NonPublic ) ;
if ( fieldInfo ! = null )
{
type = fieldInfo . FieldType ;
break ;
}
type2 = type2 . BaseType ;
if ( type2 = = null )
2026-03-14 03:13:10 -04:00
{
2025-06-03 02:42:28 -04:00
return null ;
2026-03-14 03:13:10 -04:00
}
2025-06-03 02:42:28 -04:00
}
}
}
return fieldInfo ;
}
private static string GetTooltip ( System . Reflection . FieldInfo field , bool inherit )
{
var attributes = field . GetCustomAttributes ( typeof ( UnityEngine . TooltipAttribute ) , inherit ) as UnityEngine . TooltipAttribute [ ] ;
if ( attributes ! = null & & attributes . Length > 0 )
2026-03-14 03:13:10 -04:00
{
2025-06-03 02:42:28 -04:00
return attributes [ 0 ] . tooltip ;
2026-03-14 03:13:10 -04:00
}
2025-06-03 02:42:28 -04:00
return string . Empty ;
}
public static string GetTooltip ( UnityEditor . SerializedProperty property )
{
return GetTooltip ( GetFieldInfoFromProperty ( property ) , true ) ;
}
#endregion
}
#endif // UNITY_EDITOR
public partial class AkUtilities
{
public static void FixSlashes ( ref string path , char separatorChar , char badChar , bool addTrailingSlash )
{
if ( string . IsNullOrEmpty ( path ) )
2026-03-14 03:13:10 -04:00
{
2025-06-03 02:42:28 -04:00
return ;
2026-03-14 03:13:10 -04:00
}
2025-06-03 02:42:28 -04:00
path = path . Trim ( ) . Replace ( badChar , separatorChar ) . TrimStart ( '\\' ) ;
// Append a trailing slash to play nicely with Wwise
if ( addTrailingSlash & & ! path . EndsWith ( separatorChar . ToString ( ) ) )
2026-03-14 03:13:10 -04:00
{
2025-06-03 02:42:28 -04:00
path + = separatorChar ;
2026-03-14 03:13:10 -04:00
}
2025-06-03 02:42:28 -04:00
}
2026-03-14 03:13:10 -04:00
2025-06-03 02:42:28 -04:00
public static void FixSlashes ( ref string path )
{
var separatorChar = System . IO . Path . DirectorySeparatorChar ;
var badChar = separatorChar = = '\\' ? '/' : '\\' ;
FixSlashes ( ref path , separatorChar , badChar , true ) ;
}
public static string GetPathInPackage ( string relativePath )
{
const string AssetWwisePathParent = "Assets/Wwise/API/" ;
const string PackageWwisePathParent = "Packages/com.audiokinetic.wwise.api/" ;
string rootpath = "" ;
if ( System . IO . Directory . Exists ( System . IO . Path . GetFullPath ( PackageWwisePathParent ) ) )
{
rootpath = PackageWwisePathParent ;
}
else if ( System . IO . Directory . Exists ( System . IO . Path . GetFullPath ( AssetWwisePathParent ) ) )
{
rootpath = AssetWwisePathParent ;
}
else
{
return string . Empty ;
}
var relativePathFolders = new System . Collections . Generic . List < string > ( relativePath . Split ( '/' ) ) ;
var rootPathFolders = new System . Collections . Generic . List < string > ( rootpath . Split ( '/' ) ) ;
var overlap = relativePathFolders . Intersect ( rootPathFolders ) ;
if ( overlap . Count ( ) > 0 )
{
UnityEngine . Debug . LogWarning ( "AkUtilities.GetPathInPackage(): relativePath contains overlapping folder names with root path.\nrelativePath: "
+ relativePath
+ "\nroot path: "
+ rootpath
+ "\n This could cause issues with plugins activation and packaging." ) ;
}
return System . IO . Path . Combine ( rootpath , relativePath ) ;
}
/// <summary>
/// This is based on FNVHash as used by the DataManager
/// to assign short IDs to objects. Be sure to keep them both in sync
/// when making changes!
/// </summary>
public class ShortIDGenerator
{
private const uint s_prime32 = 16777619 ;
private const uint s_offsetBasis32 = 2166136261 ;
private static byte s_hashSize ;
private static uint s_mask ;
static ShortIDGenerator ( )
{
HashSize = 32 ;
}
public static byte HashSize
{
get { return s_hashSize ; }
set
{
s_hashSize = value ;
s_mask = ( uint ) ( ( 1 < < s_hashSize ) - 1 ) ;
}
}
public static uint Compute ( string in_name )
{
var buffer = System . Text . Encoding . UTF8 . GetBytes ( in_name . ToLower ( ) ) ;
// Start with the basis value
var hval = s_offsetBasis32 ;
for ( var i = 0 ; i < buffer . Length ; i + + )
{
// multiply by the 32 bit FNV magic prime mod 2^32
hval * = s_prime32 ;
// xor the bottom with the current octet
hval ^ = buffer [ i ] ;
}
if ( s_hashSize = = 32 )
2026-03-14 03:13:10 -04:00
{
2025-06-03 02:42:28 -04:00
return hval ;
2026-03-14 03:13:10 -04:00
}
2025-06-03 02:42:28 -04:00
// XOR-Fold to the required number of bits
return ( hval > > s_hashSize ) ^ ( hval & s_mask ) ;
}
}
}
#endif // #if ! (UNITY_DASHBOARD_WIDGET || UNITY_WEBPLAYER || UNITY_WII || UNITY_WIIU || UNITY_NACL || UNITY_FLASH || UNITY_BLACKBERRY) // Disable under unsupported platforms.