diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs b/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs index 3679425389..31511c01b8 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs @@ -1,4 +1,4 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. using System; @@ -38,12 +38,18 @@ public class OsuModRelax : ModRelax, IUpdatableByPlayfield, IApplicableToDrawabl private ReplayState state = null!; private double lastStateChangeTime; + private DrawableOsuRuleset ruleset = null!; + private IPressHandler pressHandler = null!; + private bool hasReplay; + private bool legacyReplay; public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset) { + ruleset = (DrawableOsuRuleset)drawableRuleset; + // grab the input manager for future use. - osuInputManager = ((DrawableOsuRuleset)drawableRuleset).KeyBindingInputManager; + osuInputManager = ruleset.KeyBindingInputManager; } public void ApplyToPlayer(Player player) @@ -51,15 +57,22 @@ public void ApplyToPlayer(Player player) if (osuInputManager.ReplayInputHandler != null) { hasReplay = true; + + Debug.Assert(ruleset.ReplayScore != null); + legacyReplay = ruleset.ReplayScore.ScoreInfo.IsLegacyScore; + + pressHandler = legacyReplay ? new LegacyReplayPressHandler(this) : new PressHandler(this); + return; } + pressHandler = new PressHandler(this); osuInputManager.AllowGameplayInputs = false; } public void Update(Playfield playfield) { - if (hasReplay) + if (hasReplay && !legacyReplay) return; bool requiresHold = false; @@ -132,11 +145,62 @@ void changeState(bool down) if (down) { - state.PressedActions.Add(wasLeft ? OsuAction.LeftButton : OsuAction.RightButton); + pressHandler.HandlePress(wasLeft); wasLeft = !wasLeft; } + else + { + pressHandler.HandleRelease(wasLeft); + } + } + } - state.Apply(osuInputManager.CurrentState, osuInputManager); + private interface IPressHandler + { + void HandlePress(bool wasLeft); + void HandleRelease(bool wasLeft); + } + + private class PressHandler : IPressHandler + { + private readonly OsuModRelax mod; + + public PressHandler(OsuModRelax mod) + { + this.mod = mod; + } + + public void HandlePress(bool wasLeft) + { + mod.state.PressedActions.Add(wasLeft ? OsuAction.LeftButton : OsuAction.RightButton); + mod.state.Apply(mod.osuInputManager.CurrentState, mod.osuInputManager); + } + + public void HandleRelease(bool wasLeft) + { + mod.state.Apply(mod.osuInputManager.CurrentState, mod.osuInputManager); + } + } + + // legacy replays do not contain key-presses with Relax mod, so they need to be triggered by themselves. + private class LegacyReplayPressHandler : IPressHandler + { + private readonly OsuModRelax mod; + + public LegacyReplayPressHandler(OsuModRelax mod) + { + this.mod = mod; + } + + public void HandlePress(bool wasLeft) + { + mod.osuInputManager.KeyBindingContainer.TriggerPressed(wasLeft ? OsuAction.LeftButton : OsuAction.RightButton); + } + + public void HandleRelease(bool wasLeft) + { + // this intentionally releases right when `wasLeft` is true because `wasLeft` is set at point of press and not at point of release + mod.osuInputManager.KeyBindingContainer.TriggerReleased(wasLeft ? OsuAction.RightButton : OsuAction.LeftButton); } } }