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;
}
}