#if UNITY_EDITOR using System.Collections.Generic; ////////////////////////////////////////////////////////////////////// // // Copyright (c) 2014 Audiokinetic Inc. / All Rights Reserved // ////////////////////////////////////////////////////////////////////// #pragma warning disable 0168 [UnityEditor.InitializeOnLoad] public class AkWwiseWWUBuilder { 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 m_WwuToProcess = new HashSet(); private int m_currentWwuCnt; private int m_totWwuCnt = 1; static AkWwiseWWUBuilder() { // This method gets called from InitializeOnLoad and uses the AkWwiseProjectInfo later on so it needs to check if it can run right now InitializeWwiseProjectData(); UnityEditor.EditorApplication.playModeStateChanged += (UnityEditor.PlayModeStateChange playMode) => { if (playMode == UnityEditor.PlayModeStateChange.EnteredEditMode) { RestartWWUWatcher(); } }; } private static void Tick() { if (AkWwiseProjectInfo.GetData() != null) { if (System.DateTime.Now.Subtract(s_lastFileCheck).Seconds > s_SecondsBetweenChecks && !UnityEditor.EditorApplication.isCompiling && !UnityEditor.EditorApplication.isPlayingOrWillChangePlaymode && AkWwiseProjectInfo.GetData().autoPopulateEnabled) { if (Populate()) { AkWwiseXMLBuilder.Populate(); //check if WAAPI or not AkWwisePicker.Refresh(ignoreIfWaapi: true); //Make sure that the Wwise picker and the inspector are updated AkUtilities.RepaintInspector(); } 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 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(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; 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> _WwiseObjectsToRemove = new Dictionary>(); private static Dictionary> _WwiseObjectsToKeep = new Dictionary>(); private static HashSet _ParsedWwiseObjects = new HashSet(); 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()); } _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()); } 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(); 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> pair in _WwiseObjectsToKeep) { Dictionary removeDict = null; if (!_WwiseObjectsToRemove.TryGetValue(pair.Key, out removeDict)) continue; foreach (System.Guid wwiseObjectGuid in pair.Value) { removeDict.Remove(wwiseObjectGuid); } } foreach (KeyValuePair> wwiseObjectTypeDictPair in _WwiseObjectsToRemove) { var type = wwiseObjectTypeDictPair.Key; var childType = type == WwiseObjectType.StateGroup ? WwiseObjectType.State : WwiseObjectType.Switch; foreach (KeyValuePair 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 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 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 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 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(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(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(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(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(); 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(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(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(); 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 { int IComparer.Compare(System.IO.FileInfo wwuA, System.IO.FileInfo wwuB) { return wwuA.FullName.CompareTo(wwuB.FullName); } } } #endif