// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. #nullable disable using System.Linq; using NUnit.Framework; using osu.Game.Audio; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Rulesets; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.UI; using osuTK.Input; namespace osu.Game.Tests.Visual.Gameplay { public class TestSceneGameplaySampleTriggerSource : PlayerTestScene { private TestGameplaySampleTriggerSource sampleTriggerSource; protected override Ruleset CreatePlayerRuleset() => new OsuRuleset(); private Beatmap beatmap; protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) { beatmap = new Beatmap { BeatmapInfo = new BeatmapInfo { Difficulty = new BeatmapDifficulty { CircleSize = 6, SliderMultiplier = 3 }, Ruleset = ruleset } }; const double start_offset = 8000; const double spacing = 2000; double t = start_offset; beatmap.HitObjects.AddRange(new[] { new HitCircle { // intentionally start objects a bit late so we can test the case of no alive objects. StartTime = t += spacing, Samples = new[] { new HitSampleInfo(HitSampleInfo.HIT_NORMAL) } }, new HitCircle { StartTime = t += spacing, Samples = new[] { new HitSampleInfo(HitSampleInfo.HIT_WHISTLE) } }, new HitCircle { StartTime = t += spacing, Samples = new[] { new HitSampleInfo(HitSampleInfo.HIT_NORMAL) }, SampleControlPoint = new SampleControlPoint { SampleBank = HitSampleInfo.BANK_SOFT }, }, new HitCircle { StartTime = t + spacing, Samples = new[] { new HitSampleInfo(HitSampleInfo.HIT_WHISTLE) }, SampleControlPoint = new SampleControlPoint { SampleBank = HitSampleInfo.BANK_SOFT }, }, }); return beatmap; } public override void SetUpSteps() { base.SetUpSteps(); AddStep("Add trigger source", () => Player.HUDOverlay.Add(sampleTriggerSource = new TestGameplaySampleTriggerSource(Player.DrawableRuleset.Playfield.HitObjectContainer))); } [Test] public void TestCorrectHitObject() { HitObjectLifetimeEntry nextObjectEntry = null; AddAssert("no alive objects", () => getNextAliveObject() == null); AddAssert("check initially correct object", () => sampleTriggerSource.GetMostValidObject() == beatmap.HitObjects[0]); AddUntilStep("get next object", () => { var nextDrawableObject = getNextAliveObject(); if (nextDrawableObject != null) { nextObjectEntry = nextDrawableObject.Entry; InputManager.MoveMouseTo(nextDrawableObject.ScreenSpaceDrawQuad.Centre); return true; } return false; }); AddUntilStep("hit first hitobject", () => { InputManager.Click(MouseButton.Left); return nextObjectEntry.Result?.HasResult == true; }); AddAssert("check correct object after hit", () => sampleTriggerSource.GetMostValidObject() == beatmap.HitObjects[1]); AddUntilStep("check correct object after miss", () => sampleTriggerSource.GetMostValidObject() == beatmap.HitObjects[2]); AddUntilStep("check correct object after miss", () => sampleTriggerSource.GetMostValidObject() == beatmap.HitObjects[3]); AddUntilStep("no alive objects", () => getNextAliveObject() == null); AddAssert("check correct object after none alive", () => sampleTriggerSource.GetMostValidObject() == beatmap.HitObjects[3]); } private DrawableHitObject getNextAliveObject() => Player.DrawableRuleset.Playfield.HitObjectContainer.AliveObjects.FirstOrDefault(); [Test] public void TestSampleTriggering() { AddRepeatStep("trigger sample", () => sampleTriggerSource.Play(), 10); } public class TestGameplaySampleTriggerSource : GameplaySampleTriggerSource { public TestGameplaySampleTriggerSource(HitObjectContainer hitObjectContainer) : base(hitObjectContainer) { } public new HitObject GetMostValidObject() => base.GetMostValidObject(); } } }