using System.Collections.Generic; using System.Linq; using UnityEngine; using Wwise.Wooduan.Components; using Wwise.Wooduan.Core; using Wwise.Wooduan.Tools; [RequireComponent(typeof(BoxCollider))] public partial class AkRoom : AkSpatialAudioRoom, ICullableAudioObject { public int bottomFloor; public int topFloor; public int cullDistance = 30; internal Vector3 ClosestPointToListener; private AkBuilding _building; private List _subRooms = new List(); private List _connectedPortals = new List(); #region Registration protected override void OnEnable() { IsCulled = SpatialAudioManager.CullByEmitter; base.OnEnable(); } protected override void Init() { var building = transform.parent.parent; if (building) _building = building.GetComponent(); if (_building) _building.RegisterRoom(this); else SpatialAudioManager.RegisterScatteredRoom(this); } protected override void Dispose() { if (_building) _building.UnregisterRoom(this); else SpatialAudioManager.UnregisterScatteredRoom(this); } public void RegisterSubRoom(AkSubRoom subRoom) { if (!_subRooms.Contains(subRoom)) _subRooms.Add(subRoom); } public void UnregisterSubRoom(AkSubRoom subRoom) { if (_subRooms.Contains(subRoom)) _subRooms.Remove(subRoom); } internal override void RegisterPortal(AkRoomPortal portal) { if (!_connectedPortals.Contains(portal)) _connectedPortals.Add(portal); } internal override void UnregisterPortal(AkRoomPortal portal) { if (_connectedPortals.Contains(portal)) _connectedPortals.Remove(portal); } #endregion internal override int GetFloor(Vector3 position) { if (bottomFloor == topFloor || !Collider) return bottomFloor; var roomHeight = Collider.size.y; var roomCenter = transform.position.y; var totalFloors = topFloor - bottomFloor + 1; var relativeFloor = (position.y - (roomCenter - roomHeight / 2f)) / roomHeight * totalFloors; return bottomFloor + Mathf.FloorToInt(relativeFloor); } #region Portal internal override AkRoomPortal FindNearestPortalOpenedToOutdoor(Vector3 position, out float distance) { AkRoomPortal nearestPortal = null; distance = 10f; foreach (var portal in _connectedPortals) { if (!portal.isActiveAndEnabled) continue; if (!portal.isOpened || portal.IsCulled) continue; var otherRoom = portal.frontRoom == this ? portal.backRoom : portal.frontRoom; if (otherRoom is AkRoom) continue; var newDistance = portal.GetDistanceToPosition(position); if (newDistance < distance) { distance = newDistance; nearestPortal = portal; if (distance == 0f) break; } } return nearestPortal; } internal override AkRoomPortal FindPortalAtPosition(Vector3 position, PortalType portalType) { foreach (var portal in _connectedPortals) { if (portal.portalType == portalType || portal.portalType == PortalType.All || portalType == PortalType.All) { var distance = portal.GetDistanceToPosition(position); if (distance < 0.2f) return portal; } } return null; } internal override void OnEmitterEntered(AkGameObj emitter) { if (_emittersInside.Count == 0 && SpatialAudioManager.CullByEmitter) OnReveal(); base.OnEmitterEntered(emitter); } internal override void OnEmitterExited(AkGameObj emitter) { base.OnEmitterExited(emitter); if (_emittersInside.Count == 0 && SpatialAudioManager.CullByEmitter) OnCull(); } #endregion Portal internal override AkSpace FindSpaceAtPosition(Vector3 position) { if (!isActiveAndEnabled) return null; if (GetClosestPointToPosition(position) == position) return this; foreach (var subRoom in _subRooms) { var space = subRoom.FindSpaceAtPosition(position); if (space) return space; } return null; } protected override AkRoomParams GetRoomParams() { var roomParams = new AkRoomParams { Up = transform.up, Front = transform.forward, ReverbAuxBus = SpatialAudioManager.RoomEnabled ? reverbAuxBus.Id : AkSoundEngine.AK_INVALID_AUX_ID, ReverbLevel = SpatialAudioManager.RoomEnabled ? reverbLevel : 0f, RoomGameObj_AuxSendLevelToSelf = SpatialAudioManager.RoomEnabled ? roomToneAuxSend : 0f, TransmissionLoss = SpatialAudioManager.OcclusionEnabled ? transmissionLoss : 0f, RoomGameObj_KeepRegistered = roomToneEvent.IsValid(), }; return roomParams; } public bool IsCulled { get; set; } public void TryCull(Vector3 listenerPosition) { if (cullDistance <= 0f) return; var distance = GetDistanceToPosition(listenerPosition); if (distance > cullDistance) { foreach (var subRoom in _subRooms) { var subRoomDistance = subRoom.GetDistanceToPosition(listenerPosition); if (subRoomDistance < distance) distance = subRoomDistance; } if (distance > cullDistance * 1.1f) OnCull(); } else if (distance < cullDistance * 0.9f) OnReveal(); } public void OnCull() { if (IsCulled) return; IsCulled = true; foreach (var portal in _connectedPortals) { if (SpatialAudioManager.CullByEmitter) portal.RoomsUsing--; else portal.OnCull(); } Refresh(false); AkWooduanHelper.DebugToConsole(AudioLogVerbosity.Notification, AudioObjectType.Room, AudioTriggerSource.AkRoom, AudioAction.Cull, name, gameObject); } public void OnReveal() { if (!IsCulled) return; IsCulled = false; Refresh(true); foreach (var portal in _connectedPortals) { if (SpatialAudioManager.CullByEmitter) portal.RoomsUsing++; else portal.OnReveal(); } AkWooduanHelper.DebugToConsole(AudioLogVerbosity.Notification, AudioObjectType.Room, AudioTriggerSource.AkRoom, AudioAction.Reveal, name, gameObject); } internal override void Refresh(bool active) { if (active) { if (IsCulled) return; RegisterInWwise(); if (IsRegisteredInWwise) { PostRoomTone(); foreach (var portal in _connectedPortals) { if (portal.IsPendingRoom) portal.RegisterInWwise(); } } } else { if (IsRegisteredInWwise) StopRoomTone(); UnregisterInWwise(); } } public override bool IsValid() { return reverbAuxBus.IsValid() || roomToneEvent.IsValid(); } #if UNITY_EDITOR public void AutoRename() { var buildingName = transform.parent.parent.name; var originalName = name.Split('_').Last(); var floor = string.Empty; if (!originalName.EndsWith("F)")) { var adjustedBottomFloor = bottomFloor < 0 ? bottomFloor : bottomFloor + 1; if (bottomFloor == topFloor) floor = $"({adjustedBottomFloor}F)"; else floor = $"({adjustedBottomFloor}F~{topFloor + 1}F)"; } gameObject.name = "AkRoom_" + buildingName + "_" + originalName + floor; } #endif }