From 023a5c6e4faef1cd82bde231af6ed481f89d43c8 Mon Sep 17 00:00:00 2001 From: Tav TaOr Date: Fri, 10 May 2019 19:12:32 +0300 Subject: [PATCH 1/9] Add the ability to ignore the user's mouse movement. --- osu.Game.Rulesets.Osu/OsuInputManager.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/osu.Game.Rulesets.Osu/OsuInputManager.cs b/osu.Game.Rulesets.Osu/OsuInputManager.cs index b9e083d35b..b4cc556ff2 100644 --- a/osu.Game.Rulesets.Osu/OsuInputManager.cs +++ b/osu.Game.Rulesets.Osu/OsuInputManager.cs @@ -18,6 +18,8 @@ namespace osu.Game.Rulesets.Osu set => ((OsuKeyBindingContainer)KeyBindingContainer).AllowUserPresses = value; } + public bool AllowUserCursorMovement { get; set; } = true; + protected override RulesetKeyBindingContainer CreateKeyBindingContainer(RulesetInfo ruleset, int variant, SimultaneousBindingMode unique) => new OsuKeyBindingContainer(ruleset, variant, unique); @@ -26,6 +28,16 @@ namespace osu.Game.Rulesets.Osu { } + protected override bool Handle(UIEvent e) + { + if (!AllowUserCursorMovement && e is MouseMoveEvent) + { + return false; + } + + return base.Handle(e); + } + private class OsuKeyBindingContainer : RulesetKeyBindingContainer { public bool AllowUserPresses = true; From bda0b35d849d15e01cf6ba4cd4ddd97d225e06c2 Mon Sep 17 00:00:00 2001 From: Tav TaOr Date: Fri, 10 May 2019 19:46:13 +0300 Subject: [PATCH 2/9] Slight formating change. --- osu.Game.Rulesets.Osu/OsuInputManager.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Osu/OsuInputManager.cs b/osu.Game.Rulesets.Osu/OsuInputManager.cs index b4cc556ff2..58e275ba26 100644 --- a/osu.Game.Rulesets.Osu/OsuInputManager.cs +++ b/osu.Game.Rulesets.Osu/OsuInputManager.cs @@ -30,10 +30,7 @@ namespace osu.Game.Rulesets.Osu protected override bool Handle(UIEvent e) { - if (!AllowUserCursorMovement && e is MouseMoveEvent) - { - return false; - } + if (e is MouseMoveEvent && !AllowUserCursorMovement) return false; return base.Handle(e); } From d229fed1287c3d48878ab7e91981cf123fbd429d Mon Sep 17 00:00:00 2001 From: Tav TaOr Date: Sun, 12 May 2019 14:00:43 +0300 Subject: [PATCH 3/9] Implemented Autopilot --- osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs | 44 ++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs b/osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs index 401bd28d7c..7c423235fa 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs @@ -2,13 +2,19 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Collections.Generic; +using System.Linq; using osu.Framework.Graphics.Sprites; +using osu.Framework.Input.StateChanges; using osu.Game.Graphics; using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.Osu.Replays; +using osu.Game.Rulesets.UI; namespace osu.Game.Rulesets.Osu.Mods { - public class OsuModAutopilot : Mod + public class OsuModAutopilot : Mod, IApplicableFailOverride, IUpdatableByPlayfield, IApplicableToDrawableRuleset { public override string Name => "Autopilot"; public override string Acronym => "AP"; @@ -17,5 +23,41 @@ namespace osu.Game.Rulesets.Osu.Mods public override string Description => @"Automatic cursor movement - just follow the rhythm."; public override double ScoreMultiplier => 1; public override Type[] IncompatibleMods => new[] { typeof(OsuModSpunOut), typeof(ModRelax), typeof(ModSuddenDeath), typeof(ModNoFail), typeof(ModAutoplay) }; + + public bool AllowFail => false; + + private OsuInputManager inputManager; + + private List replayFrames; + private int frameIndex = 0; + + public void Update(Playfield playfield) + { + // If we are on the last replay frame, no need to do anything + if (frameIndex == replayFrames.Count - 1) + { + return; + } + + // Check if we are closer to the next replay frame then the current one + if (Math.Abs(replayFrames[frameIndex].Time - playfield.Time.Current) >= Math.Abs(replayFrames[frameIndex + 1].Time - playfield.Time.Current)) + { + // If we are, move to the next frame, and update the mouse position + frameIndex++; + new MousePositionAbsoluteInput() { Position = playfield.ToScreenSpace(replayFrames[frameIndex].Position) }.Apply(inputManager.CurrentState, inputManager); + } + + // TODO: Implement the functionality to automatically spin spinners + } + + public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset) + { + // Grab the input manager to disable the user's cursor, and for future use + inputManager = (OsuInputManager)drawableRuleset.KeyBindingInputManager; + inputManager.AllowUserCursorMovement = false; + + // Generate the replay frames the cursor should follow + replayFrames = new OsuAutoGenerator(drawableRuleset.Beatmap).Generate().Frames.Cast().ToList(); + } } } From 2051be7453ad5c201f0d6e11ecb737a68df1866e Mon Sep 17 00:00:00 2001 From: Tav TaOr Date: Sun, 12 May 2019 15:00:59 +0300 Subject: [PATCH 4/9] Minor changes to pass the AppVeyor test --- osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs b/osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs index 7c423235fa..a9b99f3afe 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs @@ -29,7 +29,7 @@ namespace osu.Game.Rulesets.Osu.Mods private OsuInputManager inputManager; private List replayFrames; - private int frameIndex = 0; + private int frameIndex; public void Update(Playfield playfield) { @@ -44,7 +44,7 @@ namespace osu.Game.Rulesets.Osu.Mods { // If we are, move to the next frame, and update the mouse position frameIndex++; - new MousePositionAbsoluteInput() { Position = playfield.ToScreenSpace(replayFrames[frameIndex].Position) }.Apply(inputManager.CurrentState, inputManager); + new MousePositionAbsoluteInput { Position = playfield.ToScreenSpace(replayFrames[frameIndex].Position) }.Apply(inputManager.CurrentState, inputManager); } // TODO: Implement the functionality to automatically spin spinners From dfd7b1111492735a7ecd7aead43163edbee439f6 Mon Sep 17 00:00:00 2001 From: Tav TaOr Date: Sun, 12 May 2019 16:04:37 +0300 Subject: [PATCH 5/9] Changed the unimplemented mod test to use OsuModSpunOut instead of OsuModAutopilot since Autopilot is implemented now. --- osu.Game.Tests/Visual/UserInterface/TestCaseMods.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestCaseMods.cs b/osu.Game.Tests/Visual/UserInterface/TestCaseMods.cs index fd003c7ea2..7d1242083e 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestCaseMods.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestCaseMods.cs @@ -90,7 +90,7 @@ namespace osu.Game.Tests.Visual.UserInterface var doubleTimeMod = harderMods.OfType().FirstOrDefault(m => m.Mods.Any(a => a is OsuModDoubleTime)); - var autoPilotMod = assistMods.FirstOrDefault(m => m is OsuModAutopilot); + var spunOutMod = easierMods.FirstOrDefault(m => m is OsuModSpunOut); var easy = easierMods.FirstOrDefault(m => m is OsuModEasy); var hardRock = harderMods.FirstOrDefault(m => m is OsuModHardRock); @@ -102,7 +102,7 @@ namespace osu.Game.Tests.Visual.UserInterface testMultiplierTextColour(noFailMod, modSelect.LowMultiplierColour); testMultiplierTextColour(hiddenMod, modSelect.HighMultiplierColour); - testUnimplementedMod(autoPilotMod); + testUnimplementedMod(spunOutMod); } [Test] From fca1b9325d4800edb79f4a24d4c4a82b500046bb Mon Sep 17 00:00:00 2001 From: Tav TaOr Date: Sun, 12 May 2019 16:18:27 +0300 Subject: [PATCH 6/9] Deleted the assistMods variable since it is never used --- osu.Game.Tests/Visual/UserInterface/TestCaseMods.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestCaseMods.cs b/osu.Game.Tests/Visual/UserInterface/TestCaseMods.cs index 7d1242083e..4fbb12d6df 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestCaseMods.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestCaseMods.cs @@ -83,7 +83,6 @@ namespace osu.Game.Tests.Visual.UserInterface var easierMods = instance.GetModsFor(ModType.DifficultyReduction); var harderMods = instance.GetModsFor(ModType.DifficultyIncrease); - var assistMods = instance.GetModsFor(ModType.Automation); var noFailMod = easierMods.FirstOrDefault(m => m is OsuModNoFail); var hiddenMod = harderMods.FirstOrDefault(m => m is OsuModHidden); From 7c50bdd173ce5c7fbd3cd3d1eaa52725eff372e9 Mon Sep 17 00:00:00 2001 From: Tav TaOr Date: Wed, 15 May 2019 23:48:37 +0300 Subject: [PATCH 7/9] Removed redundant parentheses. --- osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs b/osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs index a9b99f3afe..1853b0228f 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs @@ -34,10 +34,7 @@ namespace osu.Game.Rulesets.Osu.Mods public void Update(Playfield playfield) { // If we are on the last replay frame, no need to do anything - if (frameIndex == replayFrames.Count - 1) - { - return; - } + if (frameIndex == replayFrames.Count - 1) return; // Check if we are closer to the next replay frame then the current one if (Math.Abs(replayFrames[frameIndex].Time - playfield.Time.Current) >= Math.Abs(replayFrames[frameIndex + 1].Time - playfield.Time.Current)) From 45b4fc9201849483d0d08ec770c6c5b89d413d6a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 12 Aug 2019 15:00:32 +0900 Subject: [PATCH 8/9] Add xmldoc --- osu.Game.Rulesets.Osu/OsuInputManager.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game.Rulesets.Osu/OsuInputManager.cs b/osu.Game.Rulesets.Osu/OsuInputManager.cs index 58e275ba26..cdea7276f3 100644 --- a/osu.Game.Rulesets.Osu/OsuInputManager.cs +++ b/osu.Game.Rulesets.Osu/OsuInputManager.cs @@ -18,6 +18,10 @@ namespace osu.Game.Rulesets.Osu set => ((OsuKeyBindingContainer)KeyBindingContainer).AllowUserPresses = value; } + /// + /// Whether the user's cursor movement events should be accepted. + /// Can be used to block only movement while still accepting button input. + /// public bool AllowUserCursorMovement { get; set; } = true; protected override RulesetKeyBindingContainer CreateKeyBindingContainer(RulesetInfo ruleset, int variant, SimultaneousBindingMode unique) From 707911acac196e5c97ce6d6f5b95a0dbeb3dcdbc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 12 Aug 2019 15:05:27 +0900 Subject: [PATCH 9/9] Tidy up code formatting / variable naming --- osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs b/osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs index 1853b0228f..ca72f18e9c 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs @@ -29,19 +29,21 @@ namespace osu.Game.Rulesets.Osu.Mods private OsuInputManager inputManager; private List replayFrames; - private int frameIndex; + + private int currentFrame; public void Update(Playfield playfield) { - // If we are on the last replay frame, no need to do anything - if (frameIndex == replayFrames.Count - 1) return; + if (currentFrame == replayFrames.Count - 1) return; - // Check if we are closer to the next replay frame then the current one - if (Math.Abs(replayFrames[frameIndex].Time - playfield.Time.Current) >= Math.Abs(replayFrames[frameIndex + 1].Time - playfield.Time.Current)) + double time = playfield.Time.Current; + + // Very naive implementation of autopilot based on proximity to replay frames. + // TODO: this needs to be based on user interactions to better match stable (pausing until judgement is registered). + if (Math.Abs(replayFrames[currentFrame + 1].Time - time) <= Math.Abs(replayFrames[currentFrame].Time - time)) { - // If we are, move to the next frame, and update the mouse position - frameIndex++; - new MousePositionAbsoluteInput { Position = playfield.ToScreenSpace(replayFrames[frameIndex].Position) }.Apply(inputManager.CurrentState, inputManager); + currentFrame++; + new MousePositionAbsoluteInput { Position = playfield.ToScreenSpace(replayFrames[currentFrame].Position) }.Apply(inputManager.CurrentState, inputManager); } // TODO: Implement the functionality to automatically spin spinners