// Copyright (c) Pixel Crushers. All rights reserved. using UnityEngine; using System.Collections; namespace PixelCrushers.DialogueSystem.SequencerCommands { /// /// Implements sequencer command: AudioWaitOnce(audioClip[, subject[, audioClips...]]) /// This command will check for an internal lua variable of the entrytag/audioclip name, and /// if it exists/is true, the audio will be skipped. after one playback, the variable /// will be created and marked as true. /// Contributed by Franklin Kester. /// [AddComponentMenu("")] // Hide from menu. public class SequencerCommandAudioWaitOnce : SequencerCommand { static private string _VarPrefix = "once_"; private float _stopTime = 0; private AudioSource _audioSource = null; private int _nextClipIndex = 2; private AudioClip _currentClip = null; private AudioClip _originalClip = null; private bool _restoreOriginalClip = false; // Don't restore original; could stop next entry's AudioWait that runs same frame. protected bool isLoadingAudio = false; public IEnumerator Start() { string audioClipName = GetParameter(0); Transform subject = GetSubject(1); _nextClipIndex = 2; if (audioClipName == null || audioClipName.Length < 1) { if (DialogueDebug.logWarnings) { Debug.LogWarningFormat("{0}: Sequencer: AudioWaitOnce(): no audio clip name given", DialogueDebug.Prefix); } if (!this.hasNextClip()) { Stop(); } } if (DialogueDebug.logInfo) { Debug.LogFormat("{0}: Sequencer: AudioWaitOnce({1}) on {2}", DialogueDebug.Prefix, GetParameters(), subject); } if (this.hasPlayedAlready(audioClipName)) { if (DialogueDebug.logInfo) { Debug.LogFormat("{0}: Sequencer: AudioWaitOnce(): clip {1} already played, skipping", DialogueDebug.Prefix, audioClipName); if (!this.hasNextClip()) { Stop(); } } } _audioSource = SequencerTools.GetAudioSource(subject); if (_audioSource == null) { if (DialogueDebug.logWarnings) { Debug.LogWarningFormat("{0}: Sequencer: AudioWaitOnce(): can't find or add AudioSource to {1}.", DialogueDebug.Prefix, subject.name ); } // doesn't matter if we have other clips, no audio source means no play Stop(); } else { _originalClip = _audioSource.clip; _stopTime = DialogueTime.time + 1; // Give time for yield return null. yield return null; _originalClip = _audioSource.clip; TryAudioClip(audioClipName); } } private void TryAudioClip(string audioClipName) { try { if (string.IsNullOrEmpty(audioClipName)) { if (DialogueDebug.logWarnings) Debug.LogWarning(string.Format("{0}: Sequencer: AudioWait() command: Audio clip name is blank.", new System.Object[] { DialogueDebug.Prefix })); _stopTime = 0; } else if (this.hasPlayedAlready(audioClipName)) { Debug.LogFormat("{0}: Sequencer: AudioWaitOnce(): clip {1} already played, skipping", DialogueDebug.Prefix, audioClipName); _stopTime = DialogueTime.time; // this prevents stop time from being overwritten below return; } else { isLoadingAudio = true; DialogueManager.LoadAsset(audioClipName, typeof(AudioClip), (asset) => { isLoadingAudio = false; markAsPlayedAlready(audioClipName); var audioClip = asset as AudioClip; if (audioClip == null) { if (DialogueDebug.logWarnings && Sequencer.reportMissingAudioFiles) Debug.LogWarning(string.Format("{0}: Sequencer: AudioWait() command: Clip '{1}' wasn't found.", new System.Object[] { DialogueDebug.Prefix, audioClipName })); _stopTime = 0; } else { if (IsAudioMuted()) { if (DialogueDebug.logInfo) Debug.Log(string.Format("{0}: Sequencer: AudioWait(): waiting but not playing '{1}'; audio is muted.", new System.Object[] { DialogueDebug.Prefix, audioClipName })); } else if (_audioSource != null) // Check in case AudioSource was destroyed while loading Addressable. { if (DialogueDebug.logInfo) Debug.Log(string.Format("{0}: Sequencer: AudioWait(): playing '{1}'.", new System.Object[] { DialogueDebug.Prefix, audioClipName })); _currentClip = audioClip; _audioSource.clip = audioClip; _audioSource.Play(); } _stopTime = DialogueTime.time + SequencerCommandAudioWait.GetAudioClipLength(_audioSource, audioClip); } }); } } catch (System.Exception) { _stopTime = 0; } } /// /// returns a new string prefixed by the internal _VarPrefix, and appended by given audioClipName /// /// audio clip name to use for append /// private string buildOnceVarName(string audioClipName) { return _VarPrefix + audioClipName; } /// /// checks for an internal lua variable of the given audio clip name to see if it's been played already. /// returns true if yes, false if no or not found /// /// audio clip name to test /// private bool hasPlayedAlready(string audioClipName) { return DialogueLua.GetVariable(this.buildOnceVarName(audioClipName)).asBool; } /// /// sets the internal variable that dictates the given audio clip was already played /// /// private void markAsPlayedAlready(string audioClipName) { DialogueLua.SetVariable(this.buildOnceVarName(audioClipName), true); } /// /// checks to see if the next parameter clip index is valid (ie there's another clip waiting to be played) /// /// private bool hasNextClip() { return _nextClipIndex < parameters.Length; } public void Update() { if (DialogueTime.time >= _stopTime) { DialogueManager.UnloadAsset(_currentClip); _currentClip = null; if (!isLoadingAudio) { if (this.hasNextClip()) { TryAudioClip(GetParameter(_nextClipIndex)); _nextClipIndex++; } else { _currentClip = null; Stop(); } } } } public void OnDialogueSystemPause() { if (_audioSource == null) { return; } _audioSource.Pause(); } public void OnDialogueSystemUnpause() { if (_audioSource == null) { return; } _audioSource.Play(); } public void OnDestroy() { if (_audioSource != null) { if (_audioSource.isPlaying && (_audioSource.clip == _currentClip)) { _audioSource.Stop(); } if (_restoreOriginalClip) _audioSource.clip = _originalClip; DialogueManager.UnloadAsset(_currentClip); } } } }