ccl4/blueberryPeak/Assets/Wwise/API/Runtime/Handwritten/Common/AkUtilities.cs
2025-06-12 10:36:40 +02:00

1217 lines
35 KiB
C#

/*******************************************************************************
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) 2025 Audiokinetic Inc.
*******************************************************************************/
#if !(UNITY_DASHBOARD_WIDGET || UNITY_WEBPLAYER || UNITY_WII || UNITY_WIIU || UNITY_NACL || UNITY_FLASH || UNITY_BLACKBERRY) // Disable under unsupported platforms.
using System;
using System.Linq;
#if UNITY_EDITOR
using System.IO;
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,
AutoDefinedSoundBanks_v2023_1_0 = 19,
/// <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;
private static bool s_AutoBankEnabled = true;
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; }
public static bool IsSoundbankGenerationAvailable()
{
return GetWwiseConsole() != null && !GeneratingSoundBanks;
}
/// 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;
}
private static string GetWwiseConsole()
{
string result = null;
var settings = AkWwiseEditorSettings.Instance;
#if UNITY_EDITOR_WIN
if (!string.IsNullOrEmpty(settings.WwiseInstallationPathWindows))
{
result = System.IO.Path.Combine(settings.WwiseInstallationPathWindows, @"Authoring\x64\Release\bin\WwiseConsole.exe");
if (!System.IO.File.Exists(result))
{
result = System.IO.Path.Combine(settings.WwiseInstallationPathWindows, @"Authoring\Win32\Release\bin\WwiseConsole.exe");
}
}
#elif UNITY_EDITOR_OSX
if (!string.IsNullOrEmpty(settings.WwiseInstallationPathMac))
{
result = System.IO.Path.Combine(settings.WwiseInstallationPathMac, "Contents/Tools/WwiseConsole.sh");
}
#endif
if (result != null && System.IO.File.Exists(result))
{
return result;
}
return null;
}
public static bool GeneratingSoundBanks = false;
// 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.
public static void GenerateSoundbanks(System.Collections.Generic.List<string> platforms = null)
{
GeneratingSoundBanks = true;
#if AK_WWISE_ADDRESSABLES && UNITY_ADDRESSABLES
AkWwiseEditorSettings.Instance.CheckGeneratedBanksPath();
#endif
var wwiseProjectFullPath = AkWwiseEditorSettings.WwiseProjectAbsolutePath;
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.");
}
var wwiseConsole = GetWwiseConsole();
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))
{
arguments += " " + platform;
}
}
}
System.Threading.Tasks.Task.Run(() => RunSoundBankGeneration(command, arguments));
}
private static void RunSoundBankGeneration(string command, string arguments)
{
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);
}
GeneratingSoundBanks = false;
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))
{
return false;
}
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;
}
public static bool IsAutoBankEnabled()
{
return s_AutoBankEnabled;
}
public static System.Collections.Generic.IDictionary<string, System.Collections.Generic.List<string>> PlatformMapping
{
get { return s_BaseToCustomPF; }
}
public static System.Collections.Generic.IDictionary<string, string> GetAllBankPaths(string xmlFilePath)
{
UpdateSoundbanksDestinationFolders(xmlFilePath);
return s_ProjectBankPaths;
}
public static System.Collections.Generic.IDictionary<string, string> GetAllBankPaths()
{
UpdateSoundbanksDestinationFolders(AkWwiseEditorSettings.WwiseProjectAbsolutePath);
return s_ProjectBankPaths;
}
// Parses the .wproj to find out where SoundBanks are generated for the given path.
public static string GetWwiseSoundBankDestinationFolder(string Platform)
{
try
{
UpdateSoundbanksDestinationFolders(AkWwiseEditorSettings.WwiseProjectAbsolutePath);
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)
{
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 void 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;
AkWwiseInitializationSettings.Instance.IsAutoBankEnabled = s_AutoBankEnabled;
}
public static string GetRootOutputPath(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}']", "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)
{
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='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))
{
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 pf = node.GetAttribute("Platform", "");
var path = $"{destinationPath}/{pf}";
FixSlashes(ref path);
node.SetValue(path);
s_ProjectBankPaths[pf] = path;
}
doc.Save(WwiseProjectPath);
}
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)
{
return;
}
if (!System.IO.File.Exists(WwiseProjectPath))
{
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 pf = node.GetAttribute("Platform", "");
var path = $"{destinationPath}/{pf}";
FixSlashes(ref path);
node.SetValue(path);
s_ProjectBankPaths[pf] = path;
}
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;
}
doc.Save(WwiseProjectPath);
}
catch (System.Exception ex)
{
UnityEngine.Debug.LogError("WwiseUnity: Error while reading project " + WwiseProjectPath + ". Exception: " + ex.Message);
}
}
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)
{
CheckWwiseProjectUpdate(WwiseProjectPath);
}
// Set SoundBank-related bool settings in the wproj file.
public static bool ToggleBoolSoundbankSettingInWproj(string[] SettingName, string WwiseProjectPath, bool Enable = true)
{
try
{
if (WwiseProjectPath.Length == 0)
{
return true;
}
var doc = new System.Xml.XmlDocument { PreserveWhitespace = true };
doc.Load(WwiseProjectPath);
var Navigator = doc.CreateNavigator();
bool WprojWasEdited = false;
foreach (var name in SettingName)
{
// 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);
if (node == null)
{
// 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;
}
else if (node.GetAttribute("Value", "") == (Enable ? "False" : "True"))
{
// Value is present, we simply have to modify it.
if (!node.MoveToAttribute("Value", ""))
{
return false;
}
// Modify the value to true
node.SetValue(Enable ? "True" : "False");
WprojWasEdited = true;
}
}
if (WprojWasEdited)
{
doc.Save(WwiseProjectPath);
}
return true;
}
catch
{
return false;
}
}
public static bool SetSoundbankHeaderFilePath(string WwiseProjectPath, string SoundbankPath)
{
try
{
if (WwiseProjectPath.Length == 0)
{
return true;
}
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", ""))
{
return false;
}
node.SetValue(SoundbankPath);
doc.Save(WwiseProjectPath);
return true;
}
catch
{
return false;
}
}
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";
}
// 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))
{
return toPath;
}
if (string.IsNullOrEmpty(toPath))
{
return "";
}
var fromUri = new System.Uri(fromPath);
var toUri = new System.Uri(toPath);
if (fromUri.Scheme != toUri.Scheme)
{
return toPath;
}
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))
{
return "";
}
var wrongSeparatorChar = System.IO.Path.DirectorySeparatorChar == '/' ? '\\' : '/';
if (string.IsNullOrEmpty(RelativePath))
{
return BasePath.Replace(wrongSeparatorChar, System.IO.Path.DirectorySeparatorChar);
}
if (System.IO.Path.GetPathRoot(RelativePath) != "")
{
return RelativePath.Replace(wrongSeparatorChar, System.IO.Path.DirectorySeparatorChar);
}
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))
{
System.IO.Directory.CreateDirectory(destDirName);
}
var files = dir.GetFiles();
foreach (var file in files)
{
var destFilePath = System.IO.Path.Combine(destDirName, file.Name);
if (System.IO.File.Exists(destFilePath))
{
UnityEngine.Debug.LogWarningFormat("WwiseUnity: Destination file path will be overwritten: {0}", destFilePath);
}
file.CopyTo(destFilePath, true);
}
if (!copySubDirs)
{
return true;
}
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))
{
AssetDatabase.CreateFolder(System.IO.Path.GetDirectoryName(destDirName), System.IO.Path.GetFileName(destDirName));
}
var files = dir.GetFiles();
string error, source, destFilePath;
foreach (var file in files)
{
if (file.Extension == ".meta")
{
continue;
}
destFilePath = System.IO.Path.Combine(destDirName, file.Name);
if (System.IO.File.Exists(destFilePath))
{
UnityEngine.Debug.LogWarningFormat("WwiseUnity: Destination file path will be overwritten: {0}", destFilePath);
}
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))
{
UnityEngine.Debug.LogErrorFormat("WwiseUnity: Error while attempting to move <{0}> to <{1}>: {2}", source, destFilePath, error);
}
}
if (!copySubDirs)
{
return true;
}
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))
{
UnityEngine.Debug.LogErrorFormat("WwiseUnity: Error while attempting to move <{0}> to <{1}>: {2}", source, destSubDirName, error);
}
}
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))
{
UnityEngine.Debug.LogFormat("WwiseUnity: Created folder <{0}> in <{0}>", folders[i], parentFolder);
created = true;
continue;
}
return false;
}
if (created)
{
UnityEditor.AssetDatabase.SaveAssets();
}
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);
if (oldPath.Equals(newPath, System.StringComparison.OrdinalIgnoreCase))
{
return false;
}
if (!AssetDatabase.IsValidFolder(oldPath))
{
UnityEngine.Debug.LogWarningFormat("WwiseUnity: Refusing to move nonexistent folder <{0}>", oldPath);
return false;
}
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))
{
return true;
}
UnityEngine.Debug.LogErrorFormat("WwiseUnity: Error while attempting to rename folder <{0}> to <{1}>: {2}", oldPath, newPath, error);
return false;
}
if (!CreateFolder(newParentFolder))
{
return false;
}
error = UnityEditor.AssetDatabase.MoveAsset(oldPath, newPath);
if (string.IsNullOrEmpty(error))
{
return true;
}
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")
{
win.Repaint();
}
}
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)
{
return null;
}
var monoScript = serializedProperty.objectReferenceValue as UnityEditor.MonoScript;
if (monoScript == null)
{
return null;
}
var scriptTypeFromProperty = monoScript.GetClass();
if (scriptTypeFromProperty == null)
{
return null;
}
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)
{
type = type.GetElementType();
}
else if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(System.Collections.Generic.List<>))
{
type = type.GetGenericArguments()[0];
}
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)
{
return null;
}
}
}
}
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)
{
return attributes[0].tooltip;
}
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))
{
return;
}
path = path.Trim().Replace(badChar, separatorChar).TrimStart('\\');
// Append a trailing slash to play nicely with Wwise
if (addTrailingSlash && !path.EndsWith(separatorChar.ToString()))
{
path += separatorChar;
}
}
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)
{
return hval;
}
// 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.