From f0f595ca40ab02cd0637a50ce0246d05423fc0c6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 2 Nov 2023 19:52:49 +0900 Subject: [PATCH 1/5] Continue to play spinner bonus sounds when MAX display occurs --- .../Objects/Drawables/DrawableSpinner.cs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs index 2e9a4d92ec..aa43532f65 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs @@ -303,6 +303,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables private static readonly int score_per_tick = new SpinnerBonusTick.OsuSpinnerBonusTickJudgement().MaxNumericResult; + private int lastMaxSamplePlayback; + private void updateBonusScore() { if (ticks.Count == 0) @@ -322,7 +324,15 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables var tick = ticks.FirstOrDefault(t => !t.Result.HasResult); // tick may be null if we've hit the spin limit. - tick?.TriggerResult(true); + if (tick == null) + { + // we still want to play a sound. this will probably be a new sound in the future, but for now let's continue playing the bonus sound. + // round robin to avoid hitting playback concurrency. + tick = ticks.OfType().Skip(lastMaxSamplePlayback++ % HitObject.MaximumBonusSpins).First(); + tick.PlaySamples(); + } + else + tick.TriggerResult(true); completedFullSpins.Value++; } From aa6f14b0247f2fe0768379b9a1ae03f75827ba86 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 6 Nov 2023 18:16:04 +0900 Subject: [PATCH 2/5] Fix spinner test hitting assertion when spinning too fast --- osu.Game.Rulesets.Osu.Tests/TestSceneSpinner.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSpinner.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSpinner.cs index ea57a6a1b5..9980e1a55f 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneSpinner.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSpinner.cs @@ -3,6 +3,7 @@ #nullable disable +using System; using System.Collections.Generic; using System.Linq; using NUnit.Framework; @@ -153,7 +154,7 @@ namespace osu.Game.Rulesets.Osu.Tests { base.Update(); if (auto) - RotationTracker.AddRotation((float)(Clock.ElapsedFrameTime * spinRate.Value)); + RotationTracker.AddRotation((float)Math.Min(180, Clock.ElapsedFrameTime * spinRate.Value)); } } } From 86cf0a36cfb842cf97f074988a28c9958e9b0b81 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 6 Nov 2023 18:16:31 +0900 Subject: [PATCH 3/5] Add test coverage of spinner with no bonus ticks --- .../TestSceneSpinner.cs | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSpinner.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSpinner.cs index 9980e1a55f..77b16dd0c5 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneSpinner.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSpinner.cs @@ -37,6 +37,12 @@ namespace osu.Game.Rulesets.Osu.Tests AddSliderStep("Spin rate", 0.5, 5, 1, val => spinRate.Value = val); } + [SetUpSteps] + public void SetUpSteps() + { + AddStep("Reset rate", () => spinRate.Value = 1); + } + [TestCase(true)] [TestCase(false)] public void TestVariousSpinners(bool autoplay) @@ -47,6 +53,36 @@ namespace osu.Game.Rulesets.Osu.Tests AddStep($"{term} Small", () => SetContents(_ => testSingle(7, autoplay))); } + [Test] + public void TestSpinnerNoBonus() + { + AddStep("Set high spin rate", () => spinRate.Value = 5); + + Spinner spinner; + + AddStep("add spinner", () => SetContents(_ => + { + spinner = new Spinner + { + StartTime = Time.Current, + EndTime = Time.Current + 750, + Samples = new List + { + new HitSampleInfo(HitSampleInfo.HIT_NORMAL) + } + }; + + spinner.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty { OverallDifficulty = 0 }); + + return drawableSpinner = new TestDrawableSpinner(spinner, true, spinRate) + { + Anchor = Anchor.Centre, + Depth = depthIndex++, + Scale = new Vector2(0.75f) + }; + })); + } + [Test] public void TestSpinningSamplePitchShift() { From b219a371a93d82c3638df3b47f51e85d20f1fb94 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 6 Nov 2023 18:29:51 +0900 Subject: [PATCH 4/5] Move sample playback logic local to avoid edge case with no bonus ticks Can't see a better way of doing this. --- .../Objects/Drawables/DrawableSpinner.cs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs index aa43532f65..e159d06a02 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs @@ -45,6 +45,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables private const float spinning_sample_initial_frequency = 1.0f; private const float spinning_sample_modulated_base_frequency = 0.5f; + private SkinnableSound maxBonusSample; + /// /// The amount of bonus score gained from spinning after the required number of spins, for display purposes. /// @@ -109,6 +111,10 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables MinimumSampleVolume = MINIMUM_SAMPLE_VOLUME, Looping = true, Frequency = { Value = spinning_sample_initial_frequency } + }, + maxBonusSample = new SkinnableSound + { + MinimumSampleVolume = MINIMUM_SAMPLE_VOLUME, } }); @@ -128,6 +134,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables base.OnFree(); spinningSample.ClearSamples(); + maxBonusSample.ClearSamples(); } protected override void LoadSamples() @@ -136,6 +143,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables spinningSample.Samples = HitObject.CreateSpinningSamples().Cast().ToArray(); spinningSample.Frequency.Value = spinning_sample_initial_frequency; + + maxBonusSample.Samples = new ISampleInfo[] { HitObject.CreateHitSampleInfo("spinnerbonus") }; } private void updateSpinningSample(ValueChangedEvent tracking) @@ -157,6 +166,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables { base.StopAllSamples(); spinningSample?.Stop(); + maxBonusSample?.Stop(); } protected override void AddNestedHitObject(DrawableHitObject hitObject) @@ -303,8 +313,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables private static readonly int score_per_tick = new SpinnerBonusTick.OsuSpinnerBonusTickJudgement().MaxNumericResult; - private int lastMaxSamplePlayback; - private void updateBonusScore() { if (ticks.Count == 0) @@ -327,9 +335,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables if (tick == null) { // we still want to play a sound. this will probably be a new sound in the future, but for now let's continue playing the bonus sound. - // round robin to avoid hitting playback concurrency. - tick = ticks.OfType().Skip(lastMaxSamplePlayback++ % HitObject.MaximumBonusSpins).First(); - tick.PlaySamples(); + // TODO: this doesn't concurrency. i can't figure out how to make it concurrency. samples are bad and need a refactor. + maxBonusSample.Play(); } else tick.TriggerResult(true); From 92e4a8666def6e4bcc66d008ca0d206ca6c6cbd8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 6 Nov 2023 18:43:47 +0900 Subject: [PATCH 5/5] Add `spinnerbonus-max` support and fallback to `spinnerbonus` --- .../Objects/Drawables/DrawableSpinner.cs | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs index e159d06a02..c0c135d145 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs @@ -4,6 +4,7 @@ #nullable disable using System; +using System.Collections.Generic; using System.Linq; using JetBrains.Annotations; using osu.Framework.Allocation; @@ -144,7 +145,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables spinningSample.Samples = HitObject.CreateSpinningSamples().Cast().ToArray(); spinningSample.Frequency.Value = spinning_sample_initial_frequency; - maxBonusSample.Samples = new ISampleInfo[] { HitObject.CreateHitSampleInfo("spinnerbonus") }; + maxBonusSample.Samples = new ISampleInfo[] { new SpinnerBonusMaxSampleInfo(HitObject.CreateHitSampleInfo()) }; } private void updateSpinningSample(ValueChangedEvent tracking) @@ -344,5 +345,26 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables completedFullSpins.Value++; } } + + public class SpinnerBonusMaxSampleInfo : HitSampleInfo + { + public override IEnumerable LookupNames + { + get + { + foreach (string name in base.LookupNames) + yield return name; + + foreach (string name in base.LookupNames) + yield return name.Replace("-max", string.Empty); + } + } + + public SpinnerBonusMaxSampleInfo(HitSampleInfo sampleInfo) + : base("spinnerbonus-max", sampleInfo.Bank, sampleInfo.Suffix, sampleInfo.Volume) + + { + } + } } }