diff --git a/Assets/Scripts/Gameplay/Audio/AudioService.cs b/Assets/Scripts/Gameplay/Audio/AudioService.cs index 753742bb..aa17de52 100644 --- a/Assets/Scripts/Gameplay/Audio/AudioService.cs +++ b/Assets/Scripts/Gameplay/Audio/AudioService.cs @@ -139,9 +139,9 @@ public AudioClip AudioClip public Dictionary SfxAudioClips => Services.Hitsound.SfxAudioClips; - private int FullOffset => Values.ChartAudioOffset + Mathf.RoundToInt(Settings.GlobalAudioOffset.Value * playbackSpeed); + public int FullOffset => Values.ChartAudioOffset + Mathf.RoundToInt(Settings.GlobalAudioOffset.Value * playbackSpeed); - private int GlobalOffset => Mathf.RoundToInt(Settings.GlobalAudioOffset.Value * playbackSpeed); + public int GlobalOffset => Mathf.RoundToInt(Settings.GlobalAudioOffset.Value * playbackSpeed); public void SetAudioTimingSilent(int timing) { diff --git a/Assets/Scripts/Gameplay/Data/Events/ArcTap.cs b/Assets/Scripts/Gameplay/Data/Events/ArcTap.cs index 674d9ff6..b8d1b646 100644 --- a/Assets/Scripts/Gameplay/Data/Events/ArcTap.cs +++ b/Assets/Scripts/Gameplay/Data/Events/ArcTap.cs @@ -11,7 +11,6 @@ public class ArcTap : Note, INote, IArcTapJudgementReceiver private bool judgementRequestSent = false; private bool isHit = false; private bool isSfx; - private bool sfxPlayed = false; private Texture texture; public HashSet ConnectedTaps { get; } = new HashSet(); @@ -25,6 +24,7 @@ public class ArcTap : Note, INote, IArcTapJudgementReceiver public float WorldY => Arc.WorldYAt(Timing); public string Sfx => Arc.Sfx; + public bool SfxPlayed { get; private set; } = false; public override ArcEvent Clone() { @@ -49,7 +49,7 @@ public void ResetJudgeTo(int timing) { judgementRequestSent = timing > Timing; isHit = timing > Timing; - sfxPlayed = timing > Timing; + SfxPlayed = timing > Timing - Services.Audio.FullOffset; } public void Rebuild() @@ -94,12 +94,12 @@ public void UpdateJudgement(int currentTiming, GroupProperties groupProperties) RequestJudgement(groupProperties); judgementRequestSent = true; } - - if (currentTiming >= Timing && !sfxPlayed) - { - Services.Hitsound.PlayArcTapHitsound(Timing, Sfx, isFromJudgement: false); - sfxPlayed = true; - } + } + + public void PlayMutedSfx() + { + Services.Hitsound.PlayArcTapHitsound(Timing, Sfx, isFromJudgement: false); + SfxPlayed = true; } public void UpdateRender(int currentTiming, double currentFloorPosition, GroupProperties groupProperties) diff --git a/Assets/Scripts/Gameplay/GameplayManager.cs b/Assets/Scripts/Gameplay/GameplayManager.cs index 0587fcbe..3513badd 100644 --- a/Assets/Scripts/Gameplay/GameplayManager.cs +++ b/Assets/Scripts/Gameplay/GameplayManager.cs @@ -149,7 +149,7 @@ private void Update() Services.Camera.UpdateCamera(currentTiming); Services.Chart.UpdateChartRender(currentTiming); Services.Score.UpdateDisplay(); - Services.Hitsound.UpdateHitsoundHistory(currentTiming); + Services.Hitsound.UpdateHitsounds(currentTiming); Services.Render.UpdateRenderers(); gameplayData.NotifyUpdate(currentTiming); diff --git a/Assets/Scripts/Gameplay/Hitsound/HitsoundService.cs b/Assets/Scripts/Gameplay/Hitsound/HitsoundService.cs index a7c3b39c..0168e849 100644 --- a/Assets/Scripts/Gameplay/Hitsound/HitsoundService.cs +++ b/Assets/Scripts/Gameplay/Hitsound/HitsoundService.cs @@ -22,6 +22,7 @@ public class HitsoundService : MonoBehaviour, IHitsoundService private IHitsoundPlayer hitsoundPlayer; private readonly Dictionary sfxClips = new Dictionary(); + private readonly Dictionary> sfxTimings = new Dictionary>(); private readonly UnorderedList playedTapHitsoundTimings = new UnorderedList(30); private readonly UnorderedList playedArcHitsoundTimings = new UnorderedList(30); @@ -88,6 +89,7 @@ public async UniTask LoadCustomSfxs(string parentFolder, IFileAccessWrapper file } sfxClips.Clear(); + sfxTimings.Clear(); List loadTasks = new List(); HashSet sfxs = new HashSet(); @@ -97,7 +99,16 @@ public async UniTask LoadCustomSfxs(string parentFolder, IFileAccessWrapper file { if (!string.IsNullOrEmpty(at.Sfx) && at.Sfx != "none") { - sfxs.Add(at.Sfx); + string sfx = at.Sfx; + sfxs.Add(sfx); + if (sfxTimings.ContainsKey(sfx)) + { + sfxTimings[sfx].Add(at); + } + else + { + sfxTimings.Add(sfx, new List() { at }); + } } } @@ -125,7 +136,35 @@ public async UniTask LoadCustomSfxs(string parentFolder, IFileAccessWrapper file IsLoaded = true; } - public void UpdateHitsoundHistory(int currentTiming) + public void UpdateHitsounds(int currentTiming) + { + PlayMutedSfx(currentTiming); + UpdateHitsoundHistory(currentTiming); + } + + private void PlayMutedSfx(int currentTiming) + { + if (IsMuted) + { + foreach (string sfx in sfxTimings.Keys) + { + int noteIndex = 0; + while (noteIndex < sfxTimings[sfx].Count) + { + ArcTap at = sfxTimings[sfx][noteIndex]; + + int timing = at.Timing - Services.Audio.FullOffset; + if (!at.SfxPlayed && currentTiming >= timing) + { + at.PlayMutedSfx(); + } + noteIndex++; + } + } + } + } + + private void UpdateHitsoundHistory(int currentTiming) { PurgeOldSoundPlayedTimings(currentTiming, playedArcHitsoundTimings, Values.HoldMissLateJudgeWindow); PurgeOldSoundPlayedTimings(currentTiming, playedTapHitsoundTimings, Values.HoldMissLateJudgeWindow); diff --git a/Assets/Scripts/Gameplay/Hitsound/IHitsoundService.cs b/Assets/Scripts/Gameplay/Hitsound/IHitsoundService.cs index c876b012..34312447 100644 --- a/Assets/Scripts/Gameplay/Hitsound/IHitsoundService.cs +++ b/Assets/Scripts/Gameplay/Hitsound/IHitsoundService.cs @@ -58,7 +58,7 @@ public interface IHitsoundService /// Unitask instance. UniTask LoadCustomSfxs(string parentFolder, IFileAccessWrapper fileAccess); - void UpdateHitsoundHistory(int currentTiming); + void UpdateHitsounds(int currentTiming); void ResetHitsoundHistory(); } diff --git a/Assets/Scripts/Gameplay/IAudioControl.cs b/Assets/Scripts/Gameplay/IAudioControl.cs index ab309ed6..93447d81 100644 --- a/Assets/Scripts/Gameplay/IAudioControl.cs +++ b/Assets/Scripts/Gameplay/IAudioControl.cs @@ -7,6 +7,10 @@ namespace ArcCreate.Gameplay { public interface IAudioControl { + int FullOffset { get; } + + int GlobalOffset { get; } + /// /// Gets or sets the audio's actual timing. /// Setting this value will cause score to reset to 0.