From 27fdda8b91c070838c9a8d7f0a4d0092b53f59df Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 13 Jun 2019 12:21:49 +0900 Subject: [PATCH 1/6] Don't update hitobject results when rewinding --- osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index ec7e6dc303..fe9f6f9e51 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -243,6 +243,10 @@ namespace osu.Game.Rulesets.Objects.Drawables /// Whether a scoring result has occurred from this or any nested . protected bool UpdateResult(bool userTriggered) { + // It's possible for input to get into a bad state when rewinding gameplay, so results should not be processed + if (Time.Elapsed < 0) + return false; + judgementOccurred = false; if (AllJudged) From 44d2514f1a94b5aa49a36e9966d0d65bf8af9b72 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 13 Jun 2019 14:41:10 +0900 Subject: [PATCH 2/6] Add test scene --- .../Gameplay/TestSceneGameplayRewinding.cs | 101 ++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 osu.Game.Tests/Visual/Gameplay/TestSceneGameplayRewinding.cs diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayRewinding.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayRewinding.cs new file mode 100644 index 0000000000..b3c98c9aaa --- /dev/null +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayRewinding.cs @@ -0,0 +1,101 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Collections.Generic; +using System.Linq; +using NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Audio; +using osu.Framework.MathUtils; +using osu.Framework.Timing; +using osu.Game.Beatmaps; +using osu.Game.Rulesets; +using osu.Game.Rulesets.Judgements; +using osu.Game.Rulesets.Osu; +using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.UI; +using osu.Game.Screens.Play; +using osuTK; + +namespace osu.Game.Tests.Visual.Gameplay +{ + public class TestSceneGameplayRewinding : PlayerTestScene + { + private RulesetExposingPlayer player => (RulesetExposingPlayer)Player; + + [Resolved] + private AudioManager audioManager { get; set; } + + public TestSceneGameplayRewinding() + : base(new OsuRuleset()) + { + } + + protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap) + => new ClockBackedTestWorkingBeatmap(beatmap, new FramedClock(new ManualClock { Rate = 1 }), audioManager); + + [Test] + public void TestNotJudgementsOnRewind() + { + addSeekStep(3000); + AddAssert("all judged", () => player.DrawableRuleset.Playfield.AllHitObjects.All(h => h.Judged)); + AddStep("clear results", () => player.AppliedResults.Clear()); + addSeekStep(0); + AddAssert("none judged", () => player.DrawableRuleset.Playfield.AllHitObjects.All(h => !h.Judged)); + AddAssert("no results triggered", () => player.AppliedResults.Count == 0); + } + + private void addSeekStep(double time) + { + AddStep($"seek to {time}", () => player.GameplayClockContainer.Seek(time)); + + // Allow 2 frames of lenience + AddUntilStep("wait for seek to finish", () => Precision.AlmostEquals(time, player.DrawableRuleset.FrameStableClock.CurrentTime, 32)); + } + + protected override Player CreatePlayer(Ruleset ruleset) + { + Mods.Value = Mods.Value.Concat(new[] { ruleset.GetAutoplayMod() }).ToArray(); + return new RulesetExposingPlayer(); + } + + protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) + { + var beatmap = new Beatmap + { + BeatmapInfo = { BaseDifficulty = { ApproachRate = 9 } }, + }; + + for (int i = 0; i < 15; i++) + { + beatmap.HitObjects.Add(new HitCircle + { + Position = new Vector2(256, 192), + StartTime = 1000 + 30 * i + }); + } + + return beatmap; + } + + private class RulesetExposingPlayer : Player + { + public readonly List AppliedResults = new List(); + + public new GameplayClockContainer GameplayClockContainer => base.GameplayClockContainer; + + public new DrawableRuleset DrawableRuleset => base.DrawableRuleset; + + public RulesetExposingPlayer() + : base(false, false) + { + } + + [BackgroundDependencyLoader] + private void load() + { + ScoreProcessor.NewJudgement += r => AppliedResults.Add(r); + } + } + } +} From f12caaf9079126123b3eeb44f7d96de49c471a33 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 13 Jun 2019 15:47:21 +0900 Subject: [PATCH 3/6] Increase leniency --- osu.Game.Tests/Visual/Gameplay/TestSceneGameplayRewinding.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayRewinding.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayRewinding.cs index b3c98c9aaa..0176301c03 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayRewinding.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayRewinding.cs @@ -49,8 +49,8 @@ namespace osu.Game.Tests.Visual.Gameplay { AddStep($"seek to {time}", () => player.GameplayClockContainer.Seek(time)); - // Allow 2 frames of lenience - AddUntilStep("wait for seek to finish", () => Precision.AlmostEquals(time, player.DrawableRuleset.FrameStableClock.CurrentTime, 32)); + // Allow a few frames of lenience + AddUntilStep("wait for seek to finish", () => Precision.AlmostEquals(time, player.DrawableRuleset.FrameStableClock.CurrentTime, 100)); } protected override Player CreatePlayer(Ruleset ruleset) From 4972f862e64ca302c7294e698822dd2727b01d7d Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 14 Jun 2019 19:35:31 +0900 Subject: [PATCH 4/6] Seek track instead --- .../Visual/Gameplay/TestSceneGameplayRewinding.cs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayRewinding.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayRewinding.cs index 0176301c03..787b8ddfed 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayRewinding.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayRewinding.cs @@ -6,6 +6,7 @@ using System.Linq; using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Audio; +using osu.Framework.Audio.Track; using osu.Framework.MathUtils; using osu.Framework.Timing; using osu.Game.Beatmaps; @@ -31,8 +32,14 @@ namespace osu.Game.Tests.Visual.Gameplay { } + private Track track; + protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap) - => new ClockBackedTestWorkingBeatmap(beatmap, new FramedClock(new ManualClock { Rate = 1 }), audioManager); + { + var working = new ClockBackedTestWorkingBeatmap(beatmap, new FramedClock(new ManualClock { Rate = 1 }), audioManager); + track = working.Track; + return working; + } [Test] public void TestNotJudgementsOnRewind() @@ -47,7 +54,7 @@ namespace osu.Game.Tests.Visual.Gameplay private void addSeekStep(double time) { - AddStep($"seek to {time}", () => player.GameplayClockContainer.Seek(time)); + AddStep($"seek to {time}", () => track.Seek(time)); // Allow a few frames of lenience AddUntilStep("wait for seek to finish", () => Precision.AlmostEquals(time, player.DrawableRuleset.FrameStableClock.CurrentTime, 100)); From 95082d2fccb0f709ac4f3978f15a1cf8796f4daa Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 14 Jun 2019 19:35:47 +0900 Subject: [PATCH 5/6] Rename testcase --- osu.Game.Tests/Visual/Gameplay/TestSceneGameplayRewinding.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayRewinding.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayRewinding.cs index 787b8ddfed..a1746084a3 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayRewinding.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayRewinding.cs @@ -42,7 +42,7 @@ namespace osu.Game.Tests.Visual.Gameplay } [Test] - public void TestNotJudgementsOnRewind() + public void TestNoJudgementsOnRewind() { addSeekStep(3000); AddAssert("all judged", () => player.DrawableRuleset.Playfield.AllHitObjects.All(h => h.Judged)); From 0c293be89cccbd1d12f0e22cf4997aee49520cf3 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 14 Jun 2019 19:51:31 +0900 Subject: [PATCH 6/6] Wait for track to start running before seeking --- osu.Game.Tests/Visual/Gameplay/TestSceneGameplayRewinding.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayRewinding.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayRewinding.cs index a1746084a3..237fee1594 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayRewinding.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayRewinding.cs @@ -44,6 +44,7 @@ namespace osu.Game.Tests.Visual.Gameplay [Test] public void TestNoJudgementsOnRewind() { + AddUntilStep("wait for track to start running", () => track.IsRunning); addSeekStep(3000); AddAssert("all judged", () => player.DrawableRuleset.Playfield.AllHitObjects.All(h => h.Judged)); AddStep("clear results", () => player.AppliedResults.Clear());