using UnityEngine; #if UNITY_EDITOR /******************************************************************************* 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. *******************************************************************************/ [UnityEditor.CanEditMultipleObjects] [UnityEditor.CustomEditor(typeof(AkAmbient), true)] public class AkAmbientInspector : AkEventInspector { public enum AttenuationSphereOptions { Dont_Show, Current_Event_Only, All_Events } public static System.Collections.Generic.Dictionary attSphereProperties = new System.Collections.Generic.Dictionary(); public AttenuationSphereOptions currentAttSphereOp; private AkAmbient m_AkAmbient; private UnityEditor.SerializedProperty multiPositionTypeProperty; private UnityEditor.SerializedProperty largeModePositionArrayProperty; private UnityEditor.SerializedProperty sphereColorProperty; private System.Collections.Generic.List triggerList; public new void OnEnable() { base.OnEnable(); m_AkAmbient = target as AkAmbient; multiPositionTypeProperty = serializedObject.FindProperty("multiPositionTypeLabel"); largeModePositionArrayProperty = serializedObject.FindProperty("LargeModePositions"); sphereColorProperty = serializedObject.FindProperty("attenuationSphereColor"); if (!attSphereProperties.ContainsKey(target)) attSphereProperties.Add(target, AttenuationSphereOptions.Dont_Show); currentAttSphereOp = attSphereProperties[target]; WwiseProjectDatabase.SoundBankDirectoryUpdated += PopulateMaxAttenuation; } public new void OnDisable() { base.OnDisable(); DefaultHandles.Hidden = false; WwiseProjectDatabase.SoundBankDirectoryUpdated -= PopulateMaxAttenuation; } public override void OnChildInspectorGUI() { //Save trigger mask to know when it changes triggerList = m_AkAmbient.triggerList; base.OnChildInspectorGUI(); if (UnityEngine.Event.current.type == UnityEngine.EventType.ExecuteCommand && UnityEngine.Event.current.commandName == "ObjectSelectorClosed") { var pickedObject = UnityEditor.EditorGUIUtility.GetObjectPickerObject(); if (pickedObject != null) { int insertIndex = largeModePositionArrayProperty.arraySize; largeModePositionArrayProperty.InsertArrayElementAtIndex(insertIndex); var newElement = largeModePositionArrayProperty.GetArrayElementAtIndex(insertIndex); newElement.objectReferenceValue = pickedObject; return; } } UnityEngine.GUILayout.Space(UnityEditor.EditorGUIUtility.standardVerticalSpacing); using (new UnityEditor.EditorGUILayout.VerticalScope("box")) { UnityEditor.EditorGUILayout.PropertyField(multiPositionTypeProperty, new UnityEngine.GUIContent("Position Type: ", "Simple Mode: Only one position is used.\nLarge Mode: Children of AkAmbient with AkAmbientLargeModePositioner component will be used as position source for multi-positioning.\nMultiple Position Mode: Every AkAmbient using the same event will be used as position source for multi-positioning.")); var multiPositionType = (MultiPositionTypeLabel)multiPositionTypeProperty.intValue; if (multiPositionType == MultiPositionTypeLabel.Large_Mode || multiPositionType == MultiPositionTypeLabel.MultiPosition_Mode) { foreach (AkAmbient ambient in targets) { if (!ambient.gameObject.isStatic) { UnityEngine.GUILayout.Space(UnityEditor.EditorGUIUtility.standardVerticalSpacing); UnityEditor.EditorGUILayout.HelpBox(string.Format("Position Type <{0}> requires an AkGameObj that does not move. Consider setting the associated GameObject to static.", multiPositionType), UnityEditor.MessageType.Warning); break; } } } UnityEngine.GUILayout.Space(UnityEditor.EditorGUIUtility.standardVerticalSpacing); currentAttSphereOp = (AttenuationSphereOptions) UnityEditor.EditorGUILayout.EnumPopup("Show Attenuation Sphere: ", currentAttSphereOp); attSphereProperties[target] = currentAttSphereOp; UnityEditor.EditorGUI.BeginChangeCheck(); if (currentAttSphereOp != AttenuationSphereOptions.Dont_Show) { UnityEditor.EditorGUILayout.PropertyField(sphereColorProperty, new UnityEngine.GUIContent("Attenuation Sphere Color") ); } if (UnityEditor.EditorGUI.EndChangeCheck()) { serializedObject.ApplyModifiedProperties(); } if (multiPositionType == MultiPositionTypeLabel.Large_Mode) { UnityEngine.GUILayout.BeginHorizontal(); if (UnityEngine.GUILayout.Button("Add Large Mode position object")) { int insertIndex = largeModePositionArrayProperty.arraySize; largeModePositionArrayProperty.InsertArrayElementAtIndex(insertIndex); var newPoint = new UnityEngine.GameObject(string.Format("AkAmbientPoint{0}", insertIndex)); UnityEditor.Undo.RegisterCreatedObjectUndo(newPoint, "CreateNewLargeModePositionObject"); UnityEditor.Undo.AddComponent(newPoint); UnityEditor.Undo.SetTransformParent(newPoint.transform, m_AkAmbient.transform, "CreateNewLargeModePositionObjectSetParent"); newPoint.transform.position = m_AkAmbient.transform.TransformPoint(UnityEngine.Vector3.zero); newPoint.transform.localScale = new UnityEngine.Vector3(1f, 1f, 1f); var newElement = largeModePositionArrayProperty.GetArrayElementAtIndex(insertIndex); newElement.objectReferenceValue = newPoint.GetComponent(); } if (UnityEngine.GUILayout.Button("Pick existing position object")) { int controlID = UnityEngine.GUIUtility.GetControlID(UnityEngine.FocusType.Passive); UnityEditor.EditorGUIUtility.ShowObjectPicker(null, true, string.Empty, controlID); } UnityEngine.GUILayout.EndHorizontal(); ++UnityEditor.EditorGUI.indentLevel; UnityEditor.EditorGUI.BeginChangeCheck(); for (int i = 0; i < largeModePositionArrayProperty.arraySize; ++i) { UnityEditor.EditorGUILayout.PropertyField(largeModePositionArrayProperty.GetArrayElementAtIndex(i), true); } if (UnityEditor.EditorGUI.EndChangeCheck()) { serializedObject.ApplyModifiedProperties(); } --UnityEditor.EditorGUI.indentLevel; } } //Save multi-position type to know if it has changed var multiPosType = m_AkAmbient.multiPositionTypeLabel; if (m_AkAmbient.multiPositionTypeLabel == MultiPositionTypeLabel.MultiPosition_Mode) { UpdateTriggers(multiPosType); } } private void UpdateTriggers(MultiPositionTypeLabel in_multiPosType) { //if we just switched to MultiPosition_Mode if (in_multiPosType != m_AkAmbient.multiPositionTypeLabel) { //Get all AkAmbients in the scene #if UNITY_6000_0_OR_NEWER var akAmbients = FindObjectsByType(FindObjectsSortMode.None); #else var akAmbients = FindObjectsOfType(); #endif //Find the first AkAmbient that is in multiPosition_Mode and that has the same event as the current AkAmbient for (var i = 0; i < akAmbients.Length; i++) { if (akAmbients[i] != m_AkAmbient && akAmbients[i].multiPositionTypeLabel == MultiPositionTypeLabel.MultiPosition_Mode && akAmbients[i].data.Id == m_AkAmbient.data.Id) { //if the current AkAmbient doesn't have the same trigger as the others, we ask the user which one he wants to keep if (!HasSameTriggers(akAmbients[i].triggerList)) { if (UnityEditor.EditorUtility.DisplayDialog("AkAmbient Trigger Mismatch", "All ambients in multi-position mode with the same event must have the same triggers.\n" + "Which triggers would you like to keep?", "Current AkAmbient Triggers", "Other AkAmbients Triggers")) SetMultiPosTrigger(akAmbients); else m_AkAmbient.triggerList = akAmbients[i].triggerList; } break; } } } //if the trigger changed or there was an undo/redo operation, we update the triggers of all the AkAmbients in the same group as the current one else if (!HasSameTriggers(triggerList) || UnityEngine.Event.current.type == UnityEngine.EventType.ValidateCommand && UnityEngine.Event.current.commandName == "UndoRedoPerformed") { #if UNITY_6000_0_OR_NEWER var akAmbients = FindObjectsByType(FindObjectsSortMode.None); #else var akAmbients = FindObjectsOfType(); #endif SetMultiPosTrigger(akAmbients); } } private bool HasSameTriggers(System.Collections.Generic.List other) { return other.Count == m_AkAmbient.triggerList.Count && System.Linq.Enumerable.Count(System.Linq.Enumerable.Except(m_AkAmbient.triggerList, other)) == 0; } private void SetMultiPosTrigger(AkAmbient[] akAmbients) { for (var i = 0; i < akAmbients.Length; i++) { if (akAmbients[i].multiPositionTypeLabel == MultiPositionTypeLabel.MultiPosition_Mode && akAmbients[i].data.Id == m_AkAmbient.data.Id) akAmbients[i].triggerList = m_AkAmbient.triggerList; } } private void OnSceneGUI() { RenderAttenuationSpheres(); } public void RenderAttenuationSpheres() { if (currentAttSphereOp == AttenuationSphereOptions.Dont_Show) return; if (currentAttSphereOp == AttenuationSphereOptions.Current_Event_Only) { // Get the max attenuation for the event (if available) var radius = AkWwiseProjectInfo.GetData().GetEventMaxAttenuation(m_AkAmbient.data.Id) * m_AkAmbient.gameObject.GetComponent().ScalingFactor; if (m_AkAmbient.multiPositionTypeLabel == MultiPositionTypeLabel.Simple_Mode) { DrawSphere(m_AkAmbient.gameObject.transform.position, radius, sphereColorProperty.colorValue); } else if (m_AkAmbient.multiPositionTypeLabel == MultiPositionTypeLabel.Large_Mode) { var positionComponents = m_AkAmbient.GetComponentsInChildren(); for (int i = 0; i < positionComponents.Length; i++) { DrawSphere(positionComponents[i].transform.position, radius, sphereColorProperty.colorValue); } } else { #if UNITY_6000_0_OR_NEWER var akAmbients = FindObjectsByType(FindObjectsSortMode.None); #else var akAmbients = FindObjectsOfType(); #endif for (var i = 0; i < akAmbients.Length; i++) { if (akAmbients[i].multiPositionTypeLabel == MultiPositionTypeLabel.MultiPosition_Mode && akAmbients[i].data.Id == m_AkAmbient.data.Id) { DrawSphere(akAmbients[i].gameObject.transform.position, radius, akAmbients[i].attenuationSphereColor); } } } } else { #if UNITY_6000_0_OR_NEWER var akAmbients = FindObjectsByType(FindObjectsSortMode.None); #else var akAmbients = FindObjectsOfType(); #endif for (var i = 0; i < akAmbients.Length; i++) { // Get the max attenuation for the event (if available) var radius = AkWwiseProjectInfo.GetData().GetEventMaxAttenuation(akAmbients[i].data.Id); if (akAmbients[i].multiPositionTypeLabel == MultiPositionTypeLabel.Large_Mode) { var positionComponents = m_AkAmbient.GetComponentsInChildren(); for (int j = 0; j < positionComponents.Length; j++) { DrawSphere(positionComponents[j].transform.position, radius, akAmbients[i].attenuationSphereColor); } } else { DrawSphere(akAmbients[i].gameObject.transform.position, radius, akAmbients[i].attenuationSphereColor); } } } } private void DrawSphere(UnityEngine.Vector3 in_position, float in_radius, UnityEngine.Color in_sphereColor) { UnityEngine.Color wireColor = in_sphereColor; wireColor.a = 0.9f; if ((UnityEditor.SceneView.lastActiveSceneView.camera.transform.position - in_position).sqrMagnitude > in_radius * in_radius) { UnityEditor.Handles.color = wireColor; DrawWireDiscs(UnityEngine.Vector3.left, UnityEngine.Vector3.right, 2, in_position, in_radius); UnityEditor.Handles.color = in_sphereColor; UnityEditor.Handles.SphereHandleCap(0, in_position, UnityEngine.Quaternion.identity, in_radius * 2.0f, UnityEngine.EventType.Repaint); } else { UnityEditor.Handles.color = wireColor; DrawWireDiscs(UnityEngine.Vector3.left, UnityEngine.Vector3.right, 6, in_position, in_radius); UnityEditor.Handles.color = in_sphereColor; UnityEditor.Handles.DrawSolidDisc(in_position, UnityEngine.Vector3.up, in_radius); } } private void DrawWireDiscs(UnityEngine.Vector3 in_startNormal, UnityEngine.Vector3 in_endNormal, uint in_nbDiscs, UnityEngine.Vector3 in_position, float in_radius) { var f = 1.0f / in_nbDiscs; for (var i = 0; i < in_nbDiscs; i++) { UnityEditor.Handles.DrawWireDisc(in_position, UnityEngine.Vector3.Slerp(in_startNormal, in_endNormal, f * i), in_radius); } var orthogonalVector = UnityEngine.Vector3.Cross(in_startNormal, in_endNormal); //Handle edge case where vectors are parallel if (orthogonalVector.magnitude == 0.0f) { orthogonalVector = UnityEngine.Vector3.Cross(UnityEngine.Vector3.Slerp(in_startNormal, in_endNormal, 0.5f), in_startNormal); } UnityEditor.Handles.DrawWireDisc(in_position, orthogonalVector, in_radius); } public static void PopulateMaxAttenuation() { UnityEditor.SceneView.RepaintAll(); } } #endif