public void AfterRollbackAwareFrame(IAudioDefinitions definitions) { Debug.Assert(rollbackAware); if (doingPrediction) { if (activeFrame == liveFrame) // Completed re-simulation of rollback frames { doingPrediction = false; foreach (var pending in pendingCues) { if (!TryKillCueFuzzy(pending.cue, activeFrame, pending.position)) { if (!doingStartupPrediction) { SoundEffectManager.PlayCueSkipMissingCheck(definitions, pending.cue, pending.parameters, pending.fpp); } AddLiveCueNow(pending.cue, pending.position); } } pendingCues.Clear(); } } }
/// <summary>Potentially gameplay-mutating logic for cue playback (modifies `random` and `cueStates`)</summary> public static PlayCueParameters GetParameters(IAudioDefinitions definitions, Cue cue, XorShift random, ushort[] cueStates) { if (cue == null) { return new PlayCueParameters { soundIndex = PlayCueParameters.NO_SOUND } } ; if (ReferenceEquals(cue, Cue.missingCue)) { return new PlayCueParameters { soundIndex = PlayCueParameters.MISSING_CUE } } ; if (cue.SoundCount == 0) { return new PlayCueParameters { soundIndex = PlayCueParameters.NO_SOUND } } ; PlayCueParameters result; result.cuePitch = cue.SelectPitch(random); result.soundIndex = cue.SelectSound(random, cueStates); Debug.Assert(result.soundIndex >= 0); return(result); } } }
/// <summary>Call this only when PlayCueParameters have been validated</summary> public static void PlayCueSkipMissingCheck(IAudioDefinitions definitions, Cue cue, PlayCueParameters parameters, FadePitchPan fpp, bool loop = false) { fpp.fade = AudioMath.Clamp(fpp.fade * cue.volume, 0, 1); fpp.pitch = AudioMath.Clamp(fpp.pitch + parameters.cuePitch, -1, 1); fpp.pan = AudioMath.Clamp(fpp.pan + cue.pan, -1, 1); if (fpp.fade < 0.01f) { return; // too quiet to care about } if (cue.SoundCount == 0) { return; // <- nothing to play } lock (lockObject) { switch (cue.type) { case CueType.Parallel: { for (var i = 0; i < cue.SoundCount; i++) { AddAndStartPlaying(definitions.GetSound(cue, i), fpp, loop); } } break; case CueType.Serial: { // Build the queue for the cue: var queueHead = -1; for (var i = cue.SoundCount - 1; i >= 1; i--) { var q = AllocateQueuedSound(); queuedSounds[q].sound = definitions.GetSound(cue, i); queuedSounds[q].next = queueHead; queueHead = q; } AddAndStartPlaying(definitions.GetSound(cue, 0), fpp, loop, queueHead); } break; default: { AddAndStartPlaying(definitions.GetSound(cue, parameters.soundIndex), fpp, loop); } break; } } }
/// <param name="random">IMPORTANT: This may be part of the game state</param> /// <param name="cueStates">IMPORTANT: This may be part of the game state</param> /// <param name="playLocally">True if this sound should be played, false if the sound is for a remote player (not for us). Allows for local-only UI sounds.</param> public void PlayCue(IAudioDefinitions definitions, Cue cue, Position?worldPosition, FadePitchPan fpp, PlayCueParameters parameters, bool playsLocally) { if (parameters.soundIndex == PlayCueParameters.MISSING_CUE) { if (!doingPrediction) // <- poor man's "first time simulated" (Missing music doesn't get rollback-aware sound handling) { MissingAudio.TriedToPlayMissingCue(fpp); } return; } PlayCueSkipMissingCheck(definitions, cue, worldPosition, fpp, parameters, playsLocally); }
public static void PlayCue(IAudioDefinitions definitions, Cue cue, PlayCueParameters parameters, FadePitchPan fpp, bool loop = false) { if (parameters.soundIndex == PlayCueParameters.MISSING_CUE) { MissingAudio.TriedToPlayMissingCue(fpp); return; } if (parameters.soundIndex < 0) { return; } PlayCueSkipMissingCheck(definitions, cue, parameters, fpp, loop); }
public void PlayCueSkipMissingCheck(IAudioDefinitions definitions, Cue cue, Position?worldPosition, FadePitchPan fpp, PlayCueParameters parameters, bool playsLocally) { if (parameters.soundIndex < 0) { return; } if (!playsLocally || !AudioDevice.Available) { return; // <- nothing to do! } if (doingPrediction) // Re-prediction following rollback { if (activeFrame >= liveFrame - DontCareLimit) // <- new enough that we could still be tracking it { if (!TryKillCueExact(cue, activeFrame, worldPosition)) { if (activeFrame >= liveFrame - MaximumSoundShift) // <- new enough that we may play it { PendingCue pending; pending.cue = cue; pending.parameters = parameters; pending.frame = activeFrame; pending.position = worldPosition; pending.fpp = fpp; pendingCues.Add(pending); } } } } else // Standard playback { Debug.Assert(activeFrame == liveFrame); if (!rollbackAware || !TryKillCueFuzzy(cue, activeFrame, worldPosition)) { if (!doingStartupPrediction) { SoundEffectManager.PlayCueSkipMissingCheck(definitions, cue, parameters, fpp); } AddLiveCueNow(cue, worldPosition); } } }