ccl4/blueberryPeak/Assets/Wwise/API/Editor/WwiseWindows/AkWwiseWWUBuilder.cs
AgentSchmisch 9144907a10 ANGST
2025-06-12 18:45:34 +02:00

1043 lines
34 KiB
C#

#if UNITY_EDITOR
using System.Collections.Generic;
/*******************************************************************************
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.
*******************************************************************************/
#pragma warning disable 0168
[UnityEditor.InitializeOnLoad]
public class AkWwiseWWUBuilder : UnityEditor.AssetPostprocessor
{
private const string s_progTitle = "Populating Wwise Picker";
private const int s_SecondsBetweenChecks = 3;
private static string s_wwiseProjectPath = System.IO.Path.GetDirectoryName(AkWwiseEditorSettings.WwiseProjectAbsolutePath);
private static System.DateTime s_lastFileCheck = System.DateTime.Now.AddSeconds(-s_SecondsBetweenChecks);
private static readonly FileInfo_CompareByPath s_FileInfo_CompareByPath = new FileInfo_CompareByPath();
private readonly HashSet<string> m_WwuToProcess = new HashSet<string>();
private int m_currentWwuCnt;
private int m_totWwuCnt = 1;
static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths, bool didDomainReload)
{
if (UnityEditor.AssetDatabase.IsAssetImportWorkerProcess())
{
return;
}
if (didDomainReload)
{
// This method gets called from InitializeOnLoad and uses the AkWwiseProjectInfo later on so it needs to check if it can run right now
InitializeWwiseProjectData();
}
}
static AkWwiseWWUBuilder()
{
UnityEditor.EditorApplication.playModeStateChanged += (UnityEditor.PlayModeStateChange playMode) =>
{
if (playMode == UnityEditor.PlayModeStateChange.EnteredEditMode)
{
RestartWWUWatcher();
}
};
}
private static void Tick()
{
if (System.DateTime.Now.Subtract(s_lastFileCheck).Seconds < s_SecondsBetweenChecks)
{
return;
}
if (AkWwiseProjectInfo.GetData() == null)
{
return;
}
if (UnityEditor.EditorApplication.isCompiling)
{
return;
}
if (UnityEditor.EditorApplication.isPlayingOrWillChangePlaymode)
{
return;
}
if (!AkWwiseProjectInfo.GetData().autoPopulateEnabled)
{
return;
}
if (Populate())
{
AkWwiseJSONBuilder.Populate();
//check if WAAPI or not
AkWwisePicker.Refresh(ignoreIfWaapi: true);
//Make sure that the Wwise picker and the inspector are updated
AkUtilities.RepaintInspector();
}
AkUtilities.WwiseProjectUpdated(AkWwiseEditorSettings.WwiseProjectAbsolutePath);
s_lastFileCheck = System.DateTime.Now;
}
public static void InitializeWwiseProjectData()
{
try
{
if (string.IsNullOrEmpty(AkWwiseEditorSettings.Instance.WwiseProjectPath))
{
UnityEngine.Debug.LogError("WwiseUnity: Wwise project needed to populate from Work Units. Aborting.");
return;
}
var fullWwiseProjectPath = AkWwiseEditorSettings.WwiseProjectAbsolutePath;
s_wwiseProjectPath = System.IO.Path.GetDirectoryName(fullWwiseProjectPath);
AkUtilities.IsWwiseProjectAvailable = System.IO.File.Exists(fullWwiseProjectPath);
if (!AkUtilities.IsWwiseProjectAvailable || UnityEditor.EditorApplication.isPlayingOrWillChangePlaymode || string.IsNullOrEmpty(s_wwiseProjectPath) ||
UnityEditor.EditorApplication.isCompiling)
return;
var builder = new AkWwiseWWUBuilder();
builder.GatherModifiedFiles();
builder.UpdateFiles();
}
catch (System.Exception exception)
{
UnityEngine.Debug.LogError("Exception occured while initializing project data : \n" + exception.Message);
}
}
public static bool Populate()
{
try
{
if (string.IsNullOrEmpty(AkWwiseEditorSettings.Instance.WwiseProjectPath))
{
UnityEngine.Debug.LogError("WwiseUnity: Wwise project needed to populate from Work Units. Aborting.");
return false;
}
var fullWwiseProjectPath = AkWwiseEditorSettings.WwiseProjectAbsolutePath;
s_wwiseProjectPath = System.IO.Path.GetDirectoryName(fullWwiseProjectPath);
AkUtilities.IsWwiseProjectAvailable = System.IO.File.Exists(fullWwiseProjectPath);
if (!AkUtilities.IsWwiseProjectAvailable || UnityEditor.EditorApplication.isPlayingOrWillChangePlaymode || string.IsNullOrEmpty(s_wwiseProjectPath) ||
(UnityEditor.EditorApplication.isCompiling && !AkUtilities.IsMigrating))
return false;
AkPluginActivator.Update();
var builder = new AkWwiseWWUBuilder();
if (!builder.GatherModifiedFiles())
return false;
builder.UpdateFiles();
return true;
}
catch (System.Exception e)
{
UnityEngine.Debug.LogError(e.ToString());
UnityEditor.EditorUtility.ClearProgressBar();
return true;
}
}
public static void UpdateWwiseObjectReferenceData()
{
UnityEngine.Debug.Log("WwiseUnity: Updating Wwise Object References");
WwiseObjectReference.ClearWwiseObjectDataMap();
UpdateWwiseObjectReference(WwiseObjectType.AuxBus, AkWwiseProjectInfo.GetData().AuxBusWwu);
UpdateWwiseObjectReference(WwiseObjectType.Event, AkWwiseProjectInfo.GetData().EventWwu);
UpdateWwiseObjectReference(WwiseObjectType.Soundbank, AkWwiseProjectInfo.GetData().BankWwu);
UpdateWwiseObjectReference(WwiseObjectType.GameParameter, AkWwiseProjectInfo.GetData().RtpcWwu);
UpdateWwiseObjectReference(WwiseObjectType.Trigger, AkWwiseProjectInfo.GetData().TriggerWwu);
UpdateWwiseObjectReference(WwiseObjectType.AcousticTexture, AkWwiseProjectInfo.GetData().AcousticTextureWwu);
UpdateWwiseObjectReference(WwiseObjectType.StateGroup, WwiseObjectType.State, AkWwiseProjectInfo.GetData().StateWwu);
UpdateWwiseObjectReference(WwiseObjectType.SwitchGroup, WwiseObjectType.Switch, AkWwiseProjectInfo.GetData().SwitchWwu);
}
private int RecurseWorkUnit(AssetType in_type, System.IO.FileInfo in_workUnit, string in_currentPathInProj,
string in_currentPhysicalPath, LinkedList<AkWwiseProjectData.PathElement> in_pathAndIcons,
string in_parentPath = "")
{
m_WwuToProcess.Remove(in_workUnit.FullName);
var wwuIndex = -1;
try
{
//Progress bar stuff
var msg = "Parsing Work Unit " + in_workUnit.Name;
UnityEditor.EditorUtility.DisplayProgressBar(s_progTitle, msg, m_currentWwuCnt / (float)m_totWwuCnt);
m_currentWwuCnt++;
in_currentPathInProj =
System.IO.Path.Combine(in_currentPathInProj, System.IO.Path.GetFileNameWithoutExtension(in_workUnit.Name));
var WwuPhysicalPath = System.IO.Path.Combine(in_currentPhysicalPath, in_workUnit.Name);
var wwu = ReplaceWwuEntry(WwuPhysicalPath, in_type, out wwuIndex);
wwu.ParentPath = in_currentPathInProj;
wwu.PhysicalPath = WwuPhysicalPath;
wwu.Guid = System.Guid.Empty;
wwu.LastTime = System.IO.File.GetLastWriteTime(in_workUnit.FullName);
using (var reader = System.Xml.XmlReader.Create(in_workUnit.FullName))
{
reader.MoveToContent();
reader.Read();
while (!reader.EOF && reader.ReadState == System.Xml.ReadState.Interactive)
{
if (reader.NodeType == System.Xml.XmlNodeType.Element && reader.Name.Equals("WorkUnit"))
{
if (wwu.Guid.Equals(System.Guid.Empty))
{
var ID = reader.GetAttribute("ID");
try
{
wwu.Guid = new System.Guid(ID);
in_pathAndIcons.AddLast(new AkWwiseProjectData.PathElement(
System.IO.Path.GetFileNameWithoutExtension(in_workUnit.Name), WwiseObjectType.WorkUnit, wwu.Guid));
wwu.PathAndIcons = new List<AkWwiseProjectData.PathElement>(in_pathAndIcons);
}
catch
{
UnityEngine.Debug.LogWarning("WwiseUnity: Error reading ID <" + ID + "> from work unit <" + in_workUnit.FullName + ">.");
throw;
}
}
var persistMode = reader.GetAttribute("PersistMode");
if (persistMode == "Reference")
{
// ReadFrom advances the reader
var matchedElement = System.Xml.Linq.XNode.ReadFrom(reader) as System.Xml.Linq.XElement;
var newWorkUnitPath =
System.IO.Path.Combine(in_workUnit.Directory.FullName, matchedElement.Attribute("Name").Value + ".wwu");
var newWorkUnit = new System.IO.FileInfo(newWorkUnitPath);
if (m_WwuToProcess.Contains(newWorkUnit.FullName))
{
// Parse the referenced Work Unit
RecurseWorkUnit(in_type, newWorkUnit, in_currentPathInProj, in_currentPhysicalPath, in_pathAndIcons,
WwuPhysicalPath);
}
}
else
{
// If the persist mode is "Standalone" or "Nested", it means the current XML tag
// is the one corresponding to the current file. We can ignore it and advance the reader
reader.Read();
}
}
else if (reader.NodeType == System.Xml.XmlNodeType.Element && (reader.Name.Equals("AuxBus") || reader.Name.Equals("Folder") || reader.Name.Equals("Bus")))
{
WwiseObjectType objType;
switch (reader.Name)
{
case "AuxBus":
objType = WwiseObjectType.AuxBus;
break;
case "Bus":
objType = WwiseObjectType.Bus;
break;
case "Folder":
default:
objType = WwiseObjectType.Folder;
break;
}
in_currentPathInProj = System.IO.Path.Combine(in_currentPathInProj, reader.GetAttribute("Name"));
in_pathAndIcons.AddLast(new AkWwiseProjectData.PathElement(reader.GetAttribute("Name"), objType, new System.Guid(reader.GetAttribute("ID"))));
bool IsEmptyElement = reader.IsEmptyElement; // Need to cache this because AddElementToList advances the reader.
AddElementToList(in_currentPathInProj, reader, in_type, in_pathAndIcons, wwu.PhysicalPath, wwuIndex, objType);
if (IsEmptyElement)
{
// This element has no children, step out of it immediately
// Remove the folder/bus from the path
in_currentPathInProj = in_currentPathInProj.Remove(in_currentPathInProj.LastIndexOf(System.IO.Path.DirectorySeparatorChar));
in_pathAndIcons.RemoveLast();
// Reader was already advanced by AddElementToList
}
}
else if (reader.NodeType == System.Xml.XmlNodeType.EndElement &&
(reader.Name.Equals("Folder") || reader.Name.Equals("Bus") || reader.Name.Equals("AuxBus")))
{
// Remove the folder/bus from the path
in_currentPathInProj = in_currentPathInProj.Remove(in_currentPathInProj.LastIndexOf(System.IO.Path.DirectorySeparatorChar));
in_pathAndIcons.RemoveLast();
// Advance the reader
reader.Read();
}
else if (reader.NodeType == System.Xml.XmlNodeType.Element && reader.Name.Equals(in_type.XmlElementName))
{
// Add the element to the list
AddElementToList(in_currentPathInProj, reader, in_type, in_pathAndIcons, wwu.PhysicalPath, wwuIndex);
}
else
{
reader.Read();
}
}
}
// Sort the newly populated Wwu alphabetically
SortWwu(in_type, wwuIndex);
}
catch (System.Exception e)
{
//We have failed to parse a workunit, we can't trust the _WwiseObjectsToRemove will be properly updated
_WwiseObjectsToRemove.Clear();
UnityEngine.Debug.LogError(e.ToString());
wwuIndex = -1;
}
in_pathAndIcons.RemoveLast();
return wwuIndex;
}
private static bool isTicking = false;
public static void StartWWUWatcher()
{
if (isTicking)
return;
if (!AkWwiseProjectInfo.GetData().autoPopulateEnabled || !AkUtilities.IsWwiseProjectAvailable)
{
return;
}
isTicking = true;
Tick();
UnityEditor.EditorApplication.update += Tick;
}
public static void StopWWUWatcher()
{
if (!isTicking)
{
return;
}
UnityEditor.EditorApplication.update -= Tick;
isTicking = false;
}
private static void RestartWWUWatcher()
{
if (AkWwiseProjectInfo.GetData().autoPopulateEnabled)
{
StartWWUWatcher();
}
}
private static Dictionary<WwiseObjectType, Dictionary<System.Guid, AkWwiseProjectData.AkBaseInformation>> _WwiseObjectsToRemove
= new Dictionary<WwiseObjectType, Dictionary<System.Guid, AkWwiseProjectData.AkBaseInformation>>();
private static Dictionary<WwiseObjectType, List<System.Guid>> _WwiseObjectsToKeep = new Dictionary<WwiseObjectType, List<System.Guid>>();
private static HashSet<System.Guid> _ParsedWwiseObjects = new HashSet<System.Guid>();
private static void FlagForRemoval(WwiseObjectType type, int wwuIndex)
{
switch (type)
{
case WwiseObjectType.AuxBus:
foreach (var wwobject in AkWwiseProjectInfo.GetData().AuxBusWwu[wwuIndex].List)
FlagForRemoval(wwobject, type);
break;
case WwiseObjectType.Event:
foreach (var wwobject in AkWwiseProjectInfo.GetData().EventWwu[wwuIndex].List)
FlagForRemoval(wwobject, type);
break;
case WwiseObjectType.Soundbank:
foreach (var wwobject in AkWwiseProjectInfo.GetData().BankWwu[wwuIndex].List)
FlagForRemoval(wwobject, type);
break;
case WwiseObjectType.GameParameter:
foreach (var wwobject in AkWwiseProjectInfo.GetData().RtpcWwu[wwuIndex].List)
FlagForRemoval(wwobject, type);
break;
case WwiseObjectType.Trigger:
foreach (var wwobject in AkWwiseProjectInfo.GetData().TriggerWwu[wwuIndex].List)
FlagForRemoval(wwobject, type);
break;
case WwiseObjectType.AcousticTexture:
foreach (var wwobject in AkWwiseProjectInfo.GetData().AcousticTextureWwu[wwuIndex].List)
FlagForRemoval(wwobject, type);
break;
case WwiseObjectType.StateGroup:
foreach (var wwobject in AkWwiseProjectInfo.GetData().StateWwu[wwuIndex].List)
FlagForRemoval(wwobject, type);
break;
case WwiseObjectType.SwitchGroup:
foreach (var wwobject in AkWwiseProjectInfo.GetData().SwitchWwu[wwuIndex].List)
FlagForRemoval(wwobject, type);
break;
}
}
private static void FlagForInsertion(AkWwiseProjectData.AkBaseInformation info, WwiseObjectType type)
{
if (!_WwiseObjectsToKeep.ContainsKey(type))
{
_WwiseObjectsToKeep.Add(type, new List<System.Guid>());
}
_WwiseObjectsToKeep[type].Add(info.Guid);
if (!AkUtilities.IsMigrating)
{
WwiseObjectReference.UpdateWwiseObject(type, info.Name, info.Guid);
}
}
private static void FlagForRemoval(AkWwiseProjectData.AkBaseInformation info, WwiseObjectType type)
{
if (!_WwiseObjectsToRemove.ContainsKey(type))
{
_WwiseObjectsToRemove.Add(type, new Dictionary<System.Guid, AkWwiseProjectData.AkBaseInformation>());
}
if(!_WwiseObjectsToRemove[type].ContainsKey(info.Guid))
{
_WwiseObjectsToRemove[type].Add(info.Guid, info);
}
}
private bool GatherModifiedFiles()
{
_WwiseObjectsToRemove.Clear();
_WwiseObjectsToKeep.Clear();
var bChanged = false;
var iBasePathLen = s_wwiseProjectPath.Length + 1;
foreach (var scannedAsset in AssetType.ScannedAssets)
{
var dir = scannedAsset.RootDirectoryName;
var deleted = new List<int>();
var knownFiles = AkWwiseProjectInfo.GetData().GetWwuListByString(dir);
var cKnownBefore = knownFiles.Count;
try
{
//Get all Wwus in this folder.
var di = new System.IO.DirectoryInfo(System.IO.Path.Combine(s_wwiseProjectPath, dir));
var files = di.GetFiles("*.wwu", System.IO.SearchOption.AllDirectories);
System.Array.Sort(files, s_FileInfo_CompareByPath);
//Walk both arrays
var iKnown = 0;
var iFound = 0;
while (iFound < files.Length && iKnown < knownFiles.Count)
{
var workunit = knownFiles[iKnown] as AkWwiseProjectData.WorkUnit;
var foundRelPath = files[iFound].FullName.Substring(iBasePathLen);
switch (workunit.PhysicalPath.CompareTo(foundRelPath))
{
case 0:
//File was there and is still there. Check the FileTimes.
try
{
if (files[iFound].LastWriteTime > workunit.LastTime)
{
//File has been changed!
//If this file had a parent, parse recursively the parent itself
m_WwuToProcess.Add(files[iFound].FullName);
FlagForRemoval(scannedAsset.Type, iKnown);
bChanged = true;
}
}
catch
{
//Access denied probably (file does exists since it was picked up by GetFiles).
//Just ignore this file.
}
iFound++;
iKnown++;
break;
case 1:
m_WwuToProcess.Add(files[iFound].FullName);
iFound++;
break;
case -1:
//A file was deleted. Can't process it now, it would change the array indices.
deleted.Add(iKnown);
iKnown++;
break;
}
}
//The remainder from the files found on disk are all new files.
for (; iFound < files.Length; iFound++)
m_WwuToProcess.Add(files[iFound].FullName);
//All the remainder is deleted. From the end, of course.
if (iKnown < knownFiles.Count)
{
for (var i = iKnown; i < knownFiles.Count; ++i)
{
FlagForRemoval(scannedAsset.Type, i);
}
knownFiles.RemoveRange(iKnown, knownFiles.Count - iKnown);
}
//Delete those tagged.
for (var i = deleted.Count - 1; i >= 0; i--)
{
FlagForRemoval(scannedAsset.Type, deleted[i]);
knownFiles.RemoveAt(deleted[i]);
}
bChanged |= cKnownBefore != knownFiles.Count;
}
catch (System.Exception exception)
{
UnityEngine.Debug.Log(exception);
_WwiseObjectsToRemove.Clear();
_WwiseObjectsToKeep.Clear();
return false;
}
}
return bChanged || m_WwuToProcess.Count > 0;
}
private void UpdateFiles()
{
_ParsedWwiseObjects.Clear();
m_totWwuCnt = m_WwuToProcess.Count;
var iBasePathLen = s_wwiseProjectPath.Length + 1;
var iUnprocessed = 0;
while (m_WwuToProcess.Count - iUnprocessed > 0)
{
System.Collections.IEnumerator e = m_WwuToProcess.GetEnumerator();
for (var i = 0; i < iUnprocessed + 1; i++)
e.MoveNext();
var fullPath = e.Current as string;
var relPath = fullPath.Substring(iBasePathLen);
var typeStr = relPath.Remove(relPath.IndexOf(System.IO.Path.DirectorySeparatorChar));
if (!CreateWorkUnit(relPath, typeStr, fullPath))
iUnprocessed++;
}
//Add the unprocessed directly. This can happen if we don't find the parent WorkUnit.
//Normally, it should never happen, this is just a safe guard.
while (m_WwuToProcess.Count > 0)
{
System.Collections.IEnumerator e = m_WwuToProcess.GetEnumerator();
e.MoveNext();
var fullPath = e.Current as string;
var relPath = fullPath.Substring(iBasePathLen);
var typeStr = relPath.Remove(relPath.IndexOf(System.IO.Path.DirectorySeparatorChar));
UpdateWorkUnit(fullPath, typeStr, relPath);
}
if (AkWwiseEditorSettings.Instance.ObjectReferenceAutoCleanup)
{
foreach (KeyValuePair<WwiseObjectType, List<System.Guid>> pair in _WwiseObjectsToKeep)
{
Dictionary<System.Guid, AkWwiseProjectData.AkBaseInformation> removeDict = null;
if (!_WwiseObjectsToRemove.TryGetValue(pair.Key, out removeDict))
continue;
foreach (System.Guid wwiseObjectGuid in pair.Value)
{
removeDict.Remove(wwiseObjectGuid);
}
}
foreach (KeyValuePair<WwiseObjectType, Dictionary<System.Guid, AkWwiseProjectData.AkBaseInformation>> wwiseObjectTypeDictPair in _WwiseObjectsToRemove)
{
var type = wwiseObjectTypeDictPair.Key;
var childType = type == WwiseObjectType.StateGroup ? WwiseObjectType.State : WwiseObjectType.Switch;
foreach (KeyValuePair<System.Guid, AkWwiseProjectData.AkBaseInformation> wwiseObjectInfoPair in wwiseObjectTypeDictPair.Value)
{
var groupValue = wwiseObjectInfoPair.Value as AkWwiseProjectData.GroupValue;
if (groupValue != null)
{
foreach (var childObject in groupValue.values)
{
WwiseObjectReference.DeleteWwiseObject(childType, childObject.Guid);
}
}
WwiseObjectReference.DeleteWwiseObject(type, wwiseObjectInfoPair.Key);
}
}
}
_ParsedWwiseObjects.Clear();
_WwiseObjectsToRemove.Clear();
_WwiseObjectsToKeep.Clear();
UnityEditor.EditorUtility.SetDirty(AkWwiseProjectInfo.GetData());
UnityEditor.EditorUtility.ClearProgressBar();
}
private static void UpdateWwiseObjectReference(WwiseObjectType type, List<AkWwiseProjectData.AkInfoWorkUnit> infoWwus)
{
foreach (var infoWwu in infoWwus)
foreach (var info in infoWwu.List)
WwiseObjectReference.UpdateWwiseObjectDataMap(type, info.Name, info.Guid);
}
private static void UpdateWwiseObjectReference(WwiseObjectType type, List<AkWwiseProjectData.EventWorkUnit> infoWwus)
{
foreach (var infoWwu in infoWwus)
foreach (var info in infoWwu.List)
WwiseObjectReference.UpdateWwiseObjectDataMap(type, info.Name, info.Guid);
}
private static void UpdateWwiseObjectReference(WwiseObjectType groupType, WwiseObjectType type, List<AkWwiseProjectData.GroupValWorkUnit> infoWwus)
{
foreach (var infoWwu in infoWwus)
{
foreach (var info in infoWwu.List)
{
WwiseObjectReference.UpdateWwiseObjectDataMap(groupType, info.Name, info.Guid);
foreach (var subTypeInfo in info.values)
WwiseObjectReference.UpdateWwiseObjectDataMap(type, subTypeInfo.Name, subTypeInfo.Guid);
}
}
}
private static void SortWwu(AssetType in_type, int in_wwuIndex)
{
switch (in_type.Type)
{
case WwiseObjectType.AuxBus:
AkWwiseProjectInfo.GetData().AuxBusWwu[in_wwuIndex].List.Sort();
break;
case WwiseObjectType.Event:
AkWwiseProjectInfo.GetData().EventWwu[in_wwuIndex].List.Sort();
break;
case WwiseObjectType.Soundbank:
AkWwiseProjectInfo.GetData().BankWwu[in_wwuIndex].List.Sort();
break;
case WwiseObjectType.GameParameter:
AkWwiseProjectInfo.GetData().RtpcWwu[in_wwuIndex].List.Sort();
break;
case WwiseObjectType.Trigger:
AkWwiseProjectInfo.GetData().TriggerWwu[in_wwuIndex].List.Sort();
break;
case WwiseObjectType.AcousticTexture:
AkWwiseProjectInfo.GetData().AcousticTextureWwu[in_wwuIndex].List.Sort();
break;
case WwiseObjectType.StateGroup:
var stateList = AkWwiseProjectInfo.GetData().StateWwu[in_wwuIndex].List;
stateList.Sort();
foreach (var group in stateList)
if (group.values.Count > 0)
group.values.Sort();
break;
case WwiseObjectType.SwitchGroup:
var switchList = AkWwiseProjectInfo.GetData().SwitchWwu[in_wwuIndex].List;
switchList.Sort();
foreach (var group in switchList)
if (group.values.Count > 0)
group.values.Sort();
break;
}
}
private static AkWwiseProjectData.WorkUnit ReplaceWwuEntry(string in_currentPhysicalPath, AssetType in_type, out int out_wwuIndex)
{
var list = AkWwiseProjectInfo.GetData().GetWwuListByString(in_type.RootDirectoryName);
out_wwuIndex = list.BinarySearch(new AkWwiseProjectData.WorkUnit { PhysicalPath = in_currentPhysicalPath });
AkWwiseProjectData.WorkUnit out_wwu = null;
switch (in_type.Type)
{
case WwiseObjectType.Event:
out_wwu = new AkWwiseProjectData.EventWorkUnit();
break;
case WwiseObjectType.StateGroup:
case WwiseObjectType.SwitchGroup:
out_wwu = new AkWwiseProjectData.GroupValWorkUnit();
break;
case WwiseObjectType.AuxBus:
case WwiseObjectType.Soundbank:
case WwiseObjectType.GameParameter:
case WwiseObjectType.Trigger:
case WwiseObjectType.AcousticTexture:
out_wwu = new AkWwiseProjectData.AkInfoWorkUnit();
break;
}
if (out_wwuIndex < 0)
{
out_wwuIndex = ~out_wwuIndex;
list.Insert(out_wwuIndex, out_wwu);
}
else
list[out_wwuIndex] = out_wwu;
return out_wwu;
}
private static void AddElementToList(string in_currentPathInProj, System.Xml.XmlReader in_reader, AssetType in_type,
LinkedList<AkWwiseProjectData.PathElement> in_pathAndIcons,string in_wwuPath, int in_wwuIndex, WwiseObjectType in_LeafType = WwiseObjectType.None)
{
switch (in_type.Type)
{
case WwiseObjectType.Folder:
case WwiseObjectType.Bus:
case WwiseObjectType.AuxBus:
case WwiseObjectType.Event:
case WwiseObjectType.Soundbank:
case WwiseObjectType.GameParameter:
case WwiseObjectType.Trigger:
case WwiseObjectType.AcousticTexture:
{
var LeafType = in_LeafType == WwiseObjectType.None ? in_type.Type : in_LeafType;
var name = in_reader.GetAttribute("Name");
var valueToAdd = in_type.Type == WwiseObjectType.Event ? new AkWwiseProjectData.Event() : new AkWwiseProjectData.AkInformation();
valueToAdd.Name = name;
valueToAdd.Guid = new System.Guid(in_reader.GetAttribute("ID"));
valueToAdd.PathAndIcons = new List<AkWwiseProjectData.PathElement>(in_pathAndIcons);
FlagForInsertion(valueToAdd, in_type.Type);
switch (LeafType)
{
case WwiseObjectType.AuxBus:
case WwiseObjectType.Bus:
case WwiseObjectType.Folder:
valueToAdd.Path = in_currentPathInProj;
break;
default:
valueToAdd.Path = System.IO.Path.Combine(in_currentPathInProj, name);
valueToAdd.PathAndIcons.Add(new AkWwiseProjectData.PathElement(name, in_type.Type, valueToAdd.Guid));
break;
}
AddWwiseObjectToProjectData(in_type, in_wwuIndex, valueToAdd, in_wwuPath);
}
in_reader.Read();
break;
case WwiseObjectType.StateGroup:
case WwiseObjectType.SwitchGroup:
{
var valueToAdd = new AkWwiseProjectData.GroupValue();
if (in_LeafType == WwiseObjectType.Folder)
{
valueToAdd.Name = in_reader.GetAttribute("Name");
valueToAdd.Guid = new System.Guid(in_reader.GetAttribute("ID"));
valueToAdd.PathAndIcons = new List<AkWwiseProjectData.PathElement>(in_pathAndIcons);
valueToAdd.Path = in_currentPathInProj;
FlagForInsertion(valueToAdd, in_type.Type);
in_reader.Read();
}
else
{
var XmlElement = System.Xml.Linq.XNode.ReadFrom(in_reader) as System.Xml.Linq.XElement;
var ChildrenList = System.Xml.Linq.XName.Get("ChildrenList");
var ChildrenElement = XmlElement.Element(ChildrenList);
if (ChildrenElement != null)
{
var name = XmlElement.Attribute("Name").Value;
valueToAdd.Name = name;
valueToAdd.Guid = new System.Guid(XmlElement.Attribute("ID").Value);
valueToAdd.Path = System.IO.Path.Combine(in_currentPathInProj, name);
valueToAdd.PathAndIcons = new List<AkWwiseProjectData.PathElement>(in_pathAndIcons);
valueToAdd.PathAndIcons.Add(new AkWwiseProjectData.PathElement(name, in_type.Type, valueToAdd.Guid));
FlagForInsertion(valueToAdd, in_type.Type);
var ChildElem = System.Xml.Linq.XName.Get(in_type.ChildElementName);
foreach (var element in ChildrenElement.Elements(ChildElem))
{
if (element.Name != in_type.ChildElementName)
continue;
var elementName = element.Attribute("Name").Value;
var childValue = new AkWwiseProjectData.AkBaseInformation
{
Name = elementName,
Guid = new System.Guid(element.Attribute("ID").Value),
};
childValue.PathAndIcons = new List<AkWwiseProjectData.PathElement>(valueToAdd.PathAndIcons);
childValue.PathAndIcons.Add(new AkWwiseProjectData.PathElement(elementName, in_type.ChildType, childValue.Guid));
valueToAdd.values.Add(childValue);
FlagForInsertion(childValue, in_type.ChildType);
}
}
else
{
valueToAdd = null;
}
}
if (valueToAdd != null)
{
AddWwiseObjectToProjectData(in_type, in_wwuIndex, valueToAdd, in_wwuPath);
}
}
break;
default:
UnityEngine.Debug.LogError("WwiseUnity: Unknown asset type in WWU parser");
break;
}
}
private static void AddWwiseObjectToProjectData(AssetType in_type, int in_wwuIndex, AkWwiseProjectData.AkInformation valueToAdd, string in_wwuPath)
{
if (!_ParsedWwiseObjects.Add(valueToAdd.Guid))
{
UnityEngine.Debug.LogWarning("While parsing " + in_wwuPath + ", an already parsed Wwise Object with name: " + valueToAdd.Name + " GUID: " + valueToAdd.Guid + " was found. Are all work units up to date?");
return;
}
switch (in_type.Type)
{
case WwiseObjectType.AuxBus:
AkWwiseProjectInfo.GetData().AuxBusWwu[in_wwuIndex].List.Add(valueToAdd);
break;
case WwiseObjectType.Event:
AkWwiseProjectInfo.GetData().EventWwu[in_wwuIndex].List.Add(valueToAdd as AkWwiseProjectData.Event);
break;
case WwiseObjectType.Soundbank:
AkWwiseProjectInfo.GetData().BankWwu[in_wwuIndex].List.Add(valueToAdd);
break;
case WwiseObjectType.GameParameter:
AkWwiseProjectInfo.GetData().RtpcWwu[in_wwuIndex].List.Add(valueToAdd);
break;
case WwiseObjectType.Trigger:
AkWwiseProjectInfo.GetData().TriggerWwu[in_wwuIndex].List.Add(valueToAdd);
break;
case WwiseObjectType.AcousticTexture:
AkWwiseProjectInfo.GetData().AcousticTextureWwu[in_wwuIndex].List.Add(valueToAdd);
break;
case WwiseObjectType.StateGroup:
AkWwiseProjectInfo.GetData().StateWwu[in_wwuIndex].List.Add(valueToAdd as AkWwiseProjectData.GroupValue);
break;
case WwiseObjectType.SwitchGroup:
AkWwiseProjectInfo.GetData().SwitchWwu[in_wwuIndex].List.Add(valueToAdd as AkWwiseProjectData.GroupValue);
break;
}
}
private bool CreateWorkUnit(string in_relativePath, string in_wwuType, string in_fullPath)
{
var ParentID = string.Empty;
try
{
using (var reader = System.Xml.XmlReader.Create(in_fullPath))
{
reader.MoveToContent();
//We check if the current work unit has a parent and save its guid if its the case
while (!reader.EOF && reader.ReadState == System.Xml.ReadState.Interactive)
{
if (reader.NodeType == System.Xml.XmlNodeType.Element && reader.Name.Equals("WorkUnit"))
{
if (reader.GetAttribute("PersistMode").Equals("Nested"))
ParentID = reader.GetAttribute("OwnerID");
break;
}
reader.Read();
}
}
}
catch (System.Exception e)
{
UnityEngine.Debug.Log("WwiseUnity: A changed Work unit wasn't found. It must have been deleted " + in_fullPath);
return false;
}
if (!string.IsNullOrEmpty(ParentID))
{
var parentGuid = System.Guid.Empty;
try
{
parentGuid = new System.Guid(ParentID);
}
catch
{
UnityEngine.Debug.LogWarning("WwiseUnity: \"OwnerID\" in <" + in_fullPath + "> cannot be converted to a GUID (" + ParentID + ")");
return false;
}
var list = AkWwiseProjectInfo.GetData().GetWwuListByString(in_wwuType);
var PathAndIcons = new LinkedList<AkWwiseProjectData.PathElement>();
string PathInProj = string.Empty;
AkWwiseProjectData.WorkUnit wwu = null;
if (parentGuid != System.Guid.Empty)
{
for (var i = 0; i < list.Count; i++)
{
wwu = list[i] as AkWwiseProjectData.WorkUnit;
if (wwu.Guid.Equals(parentGuid))
{
PathInProj = wwu.ParentPath;
PathAndIcons = new LinkedList<AkWwiseProjectData.PathElement>(wwu.PathAndIcons);
break;
}
else
{
var WwuChildren = wwu.GetChildrenArrayList();
foreach (AkWwiseProjectData.AkInformation child in WwuChildren)
{
if (child.Guid.Equals(parentGuid))
{
PathInProj = child.Path;
PathAndIcons = new LinkedList<AkWwiseProjectData.PathElement>(child.PathAndIcons);
break;
}
}
}
}
}
if (!string.IsNullOrEmpty(PathInProj))
{
RecurseWorkUnit(AssetType.Create(in_wwuType), new System.IO.FileInfo(in_fullPath), PathInProj,
in_relativePath.Remove(in_relativePath.LastIndexOf(System.IO.Path.DirectorySeparatorChar)), PathAndIcons,
wwu.PhysicalPath);
return true;
}
//Not found. Wait for it to load
return false;
}
//Root Wwu
UpdateWorkUnit(in_fullPath, in_wwuType, in_relativePath);
return true;
}
private void UpdateWorkUnit(string in_wwuFullPath, string in_wwuType, string in_relativePath)
{
var PathAndIcons = new LinkedList<AkWwiseProjectData.PathElement>();
var currentPathInProj = string.Empty;
//Add physical folders to the hierarchy if the work unit isn't in the root folder
var physicalPath = in_relativePath.Split(System.IO.Path.DirectorySeparatorChar);
for (var i = 0; i < physicalPath.Length -1; i++)
{
PathAndIcons.AddLast(
new AkWwiseProjectData.PathElement(physicalPath[i], WwiseObjectType.PhysicalFolder, System.Guid.Empty));
currentPathInProj = System.IO.Path.Combine(currentPathInProj,physicalPath[i]);
}
//Parse the work unit file
RecurseWorkUnit(AssetType.Create(in_wwuType), new System.IO.FileInfo(in_wwuFullPath), currentPathInProj,
in_relativePath.Remove(in_relativePath.LastIndexOf(System.IO.Path.DirectorySeparatorChar)), PathAndIcons);
}
public class AssetType
{
public string RootDirectoryName { get; set; }
public string XmlElementName;
public string ChildElementName;
public WwiseObjectType Type = WwiseObjectType.None;
public WwiseObjectType ChildType = WwiseObjectType.None;
public static AssetType[] ScannedAssets
{
get { return _ScannedAssets; }
}
public static AssetType Create(string rootDirectoryName)
{
foreach (var asset in ScannedAssets)
if (string.Equals(rootDirectoryName, asset.RootDirectoryName, System.StringComparison.OrdinalIgnoreCase))
return asset;
return null;
}
private AssetType(string RootFolder, string XmlElemName, WwiseObjectType type)
{
RootDirectoryName = RootFolder;
XmlElementName = XmlElemName;
Type = type;
}
private static readonly AssetType[] _ScannedAssets = new AssetType[]
{
new AssetType("Master-Mixer Hierarchy", "AuxBus", WwiseObjectType.AuxBus),
new AssetType("Events", "Event", WwiseObjectType.Event),
new AssetType("SoundBanks", "SoundBank", WwiseObjectType.Soundbank),
new AssetType("States", "StateGroup", WwiseObjectType.StateGroup) { ChildElementName = "State", ChildType = WwiseObjectType.State },
new AssetType("Switches", "SwitchGroup", WwiseObjectType.SwitchGroup) { ChildElementName = "Switch", ChildType = WwiseObjectType.Switch },
new AssetType("Game Parameters", "GameParameter", WwiseObjectType.GameParameter),
new AssetType("Triggers", "Trigger", WwiseObjectType.Trigger),
new AssetType("Virtual Acoustics", "AcousticTexture", WwiseObjectType.AcousticTexture),
};
}
private class FileInfo_CompareByPath : IComparer<System.IO.FileInfo>
{
int IComparer<System.IO.FileInfo>.Compare(System.IO.FileInfo wwuA, System.IO.FileInfo wwuB)
{
return wwuA.FullName.CompareTo(wwuB.FullName);
}
}
}
#endif