using AppleHills.Core.Settings; using Bootstrap; using Core; using PuzzleS; using UnityEngine; using UnityEngine.Audio; using AppleHills.Core; using AppleHills.Core.Interfaces; using System.Collections.Generic; using AudioSourceEvents; using System; public class AudioManager : MonoBehaviour, IPausable { /// /// Play all audio, just music or no audio at all when the game is paused. /// public enum PauseBehavior { PlayAllAudio, MusicOnly, NoAudio } public PauseBehavior currentPauseBehavior; public AudioMixer audioMixer; private AudioListener _audioListener; public AppleAudioSource currentlyPlayingVO; private static AudioManager _instance; private GameObject _player; public List criticalVOSources; public List VOSources; public List musicSources; public List ambienceSources; public List SFXSources; private IAudioEventSource _eventSource; private bool wasInterrupted; /// /// Singleton instance of the AudioManager. /// public static AudioManager Instance => _instance; void Awake() { _instance = this; // Register for post-boot initialization BootCompletionService.RegisterInitAction(InitializePostBoot); GameManager.Instance.RegisterPausableComponent(this); } private void InitializePostBoot() { } // Start is called once before the first execution of Update after the MonoBehaviour is created void Start() { _player = QuickAccess.Instance.PlayerGameObject; _audioListener = QuickAccess.Instance.MainCamera.GetComponent(); foreach (AppleAudioSource _audioSource in criticalVOSources) { Debug.Log("Found source: " + _audioSource.name); } } public void SetAudioPauseBehavior(PauseBehavior newPauseBehavior) { switch (newPauseBehavior) { case PauseBehavior.PlayAllAudio: audioMixer.updateMode = AudioMixerUpdateMode.UnscaledTime; AudioListener.pause = false; break; case PauseBehavior.MusicOnly: audioMixer.updateMode = AudioMixerUpdateMode.UnscaledTime; break; //TODO: Pause all audio mixers except music mixer case PauseBehavior.NoAudio: audioMixer.updateMode = AudioMixerUpdateMode.Normal; AudioListener.pause = true; break; } } public LevelAudioObject GetCurrentLevelAudioObject() { Debug.Log("Audio objects: " + FindObjectsByType(FindObjectsInactive.Include, FindObjectsSortMode.None).Length); if (FindObjectsByType(FindObjectsInactive.Include, FindObjectsSortMode.None).Length > 1) { Debug.LogWarning("Warning! More than one LevelAudioObject in the level! Using the first one found"); return FindObjectsByType(FindObjectsInactive.Include, FindObjectsSortMode.None)[0]; } if (FindObjectsByType(FindObjectsInactive.Include, FindObjectsSortMode.None).Length == 0) { Debug.LogWarning("Error! No LevelAudioObject found, AudioManager might not function properly!"); return null; } else return FindFirstObjectByType(); } public void Pause() { SetAudioPauseBehavior(PauseBehavior.NoAudio); } public void DoResume() { SetAudioPauseBehavior(PauseBehavior.PlayAllAudio); } public void RegisterNewAudioSource(AppleAudioSource newAudioSource) { switch (newAudioSource.audioSourceType) { case AppleAudioSource.AudioSourceType.CriticalVO: criticalVOSources.Add(newAudioSource); break; case AppleAudioSource.AudioSourceType.VO: VOSources.Add(newAudioSource); break; case AppleAudioSource.AudioSourceType.SFX: SFXSources.Add(newAudioSource); break; case AppleAudioSource.AudioSourceType.Ambience: ambienceSources.Add(newAudioSource); break; case AppleAudioSource.AudioSourceType.Music: musicSources.Add(newAudioSource); break; } } /// /// Request playing a VO line. Returns true if whatever is playing is not critical, or weight of requested VO line is lower. /// public bool RequestPlayVO(AppleAudioSource requestedAudioSource) { //Debug.Log($"[AUDIOMANAGER] CurrentVO source prio: {currentlyPlayingVO.sourcePriority}, clip prio: {currentlyPlayingVO.clipPriority} requested VO prio: {requestedAudioSource.sourcePriority}, clip prio: {clipPriority}"); // If nothing is playing, let the requested audio source play if (currentlyPlayingVO == null) { SetupNewAudioSource(requestedAudioSource); Debug.Log($"[AUDIOMANAGER] Playing {currentlyPlayingVO.name} as nothing is currently playing."); return true; } // If the requested audio source is the same, interrupt and trigger it again if (currentlyPlayingVO == requestedAudioSource) { InterruptAudioSource(requestedAudioSource); SetupNewAudioSource(requestedAudioSource); Debug.Log($"[AUDIOMANAGER] {currentlyPlayingVO.name} is the same as {requestedAudioSource.name}. Triggering it again."); return true; } // if the currently playing audio source is not critical, interrupt it and play the requested audio source if (currentlyPlayingVO.audioSourceType != AppleAudioSource.AudioSourceType.CriticalVO) { InterruptAudioSource(requestedAudioSource); SetupNewAudioSource(requestedAudioSource); Debug.Log($"[AUDIOMANAGER] {currentlyPlayingVO.name} is not critical. Playing {requestedAudioSource.name} instead because it is critical."); return true; } // If the requested audio source has the same priority as currently playing source, check the priority of the requested clip if (currentlyPlayingVO.audioSourceType == AppleAudioSource.AudioSourceType.CriticalVO && currentlyPlayingVO.sourcePriority == requestedAudioSource.sourcePriority) { if (currentlyPlayingVO.clipPriority > requestedAudioSource.clipPriority) { InterruptAudioSource(requestedAudioSource); SetupNewAudioSource(requestedAudioSource); Debug.Log($"[AUDIOMANAGER] Interrupted {currentlyPlayingVO.name} because it has same priority as {requestedAudioSource.name} but the requested clip has higher priority"); return true; } else { return false; } } // If the requested audio source has higher priority than the currently playing source, interrupt the current source and let the requested one play if (currentlyPlayingVO.audioSourceType == AppleAudioSource.AudioSourceType.CriticalVO && currentlyPlayingVO.sourcePriority > requestedAudioSource.sourcePriority) { currentlyPlayingVO.InterruptAudio(requestedAudioSource.name); Debug.Log($"[AUDIOMANAGER] Interrupted {currentlyPlayingVO.name} because {requestedAudioSource.name} has higher priority"); InterruptAudioSource(requestedAudioSource); SetupNewAudioSource(requestedAudioSource); return true; } // If the requested audio source didn't clear any of the above cases, tell it to get rekt. else { Debug.Log($"[AUDIOMANAGER] {currentlyPlayingVO.name} is still playing. {requestedAudioSource.name} has lower priority"); return false; } } private void OnApplicationQuit() { // TODO: Release the handles safely ReleaseAllHandles(); } private void SetupNewAudioSource(AppleAudioSource audioSource) { if (audioSource.audioSource.resource == null) { Debug.Log($"[AUDIOMANAGER] Faled to setup {audioSource.name}. Invalid resource"); } else { currentlyPlayingVO = audioSource; _eventSource = audioSource.audioSource.RequestEventHandlers(); _eventSource.AudioStopped += OnAudioStopped; _eventSource.AudioStarted += OnAudioStarted; } } private void OnAudioStopped(object sender, EventArgs e) { if (wasInterrupted) { ResetAudioSource(); } else { currentlyPlayingVO = null; ResetAudioSource(); } } private void OnAudioStarted(object sender, EventArgs e) { } private void ResetAudioSource() { _eventSource.AudioStopped -= OnAudioStopped; _eventSource.AudioStarted -= OnAudioStarted; wasInterrupted = false; } private void InterruptAudioSource(AppleAudioSource newAudioSource) { wasInterrupted = true; currentlyPlayingVO.InterruptAudio(newAudioSource.name); ResetAudioSource(); currentlyPlayingVO = newAudioSource; } }