From f239d03d75aaeb02118f5a316c6febf135b291dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 6 Dec 2023 10:12:25 +0100 Subject: [PATCH] Forcibly change ruleset to correct one before entering gameplay from main menu Closes #25663 (again). As it turns out, in some scenarios it can be the case that the current game-global `Beatmap` is not valid for the current game-global `Ruleset`. The validity of one and the other in conjunction is only really validated by the song select screen; elsewhere there is no guarantee that the global beatmap is playable using the global ruleset. However, this only comes up in very specific circumstances, namely one: when trying to autoplay a catch beatmap with osu! ruleset globally active via the skin editor flow. `Player` is responsible for retrieving the beatmap to be played. It does so by invoking the appropriate beatmap converter and asking it if the beatmap can be converted: https://github.com/ppy/osu/blob/6d64538d7a3130df63574eb75a8ebe044154c799/osu.Game/Beatmaps/WorkingBeatmap.cs#L262-L266 If the code above throws, `Player` actually silently covers for this, by trying the beatmap's default ruleset instead: https://github.com/ppy/osu/blob/6d64538d7a3130df63574eb75a8ebe044154c799/osu.Game/Screens/Play/Player.cs#L529-L536 However, for the pairing of osu! ruleset and catch beatmap, this fails, as `OsuBeatmapConverter`'s condition necessary for permitting conversion is that the objects have a defined position: https://github.com/ppy/osu/blob/6d64538d7a3130df63574eb75a8ebe044154c799/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapConverter.cs#L25 which they will do, due to the fact that all catch beatmaps are really just osu! beatmaps but with conversion steps applied, and thus `Player` succeeds to load the catch beatmap in osu! ruleset. In the skin editor scenario, this would lead to the secondary failure of the skin editor trying to apply `CatchModAutoplay` on top of all of that, which would fail at the hard-cast of the beatmap to `CatchBeatmap`. --- osu.Game/Overlays/SkinEditor/SkinEditorOverlay.cs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/SkinEditor/SkinEditorOverlay.cs b/osu.Game/Overlays/SkinEditor/SkinEditorOverlay.cs index 262ce263bd..bedaf12c9b 100644 --- a/osu.Game/Overlays/SkinEditor/SkinEditorOverlay.cs +++ b/osu.Game/Overlays/SkinEditor/SkinEditorOverlay.cs @@ -17,6 +17,7 @@ using osu.Game.Beatmaps; using osu.Game.Configuration; using osu.Game.Graphics.Containers; using osu.Game.Input.Bindings; +using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osu.Game.Scoring; using osu.Game.Screens; @@ -58,6 +59,9 @@ namespace osu.Game.Overlays.SkinEditor [Resolved] private Bindable> mods { get; set; } = null!; + [Resolved] + private Bindable ruleset { get; set; } = null!; + [Resolved] private IBindable beatmap { get; set; } = null!; @@ -153,7 +157,11 @@ namespace osu.Game.Overlays.SkinEditor if (screen is Player) return; - var replayGeneratingMod = beatmap.Value.BeatmapInfo.Ruleset.CreateInstance().GetAutoplayMod(); + // the validity of the current game-wide beatmap + ruleset combination is enforced by song select. + // if we're anywhere else, the state is unknown and may not make sense, so forcibly set something that does. + if (screen is not PlaySongSelect) + ruleset.Value = beatmap.Value.BeatmapInfo.Ruleset; + var replayGeneratingMod = ruleset.Value.CreateInstance().GetAutoplayMod(); IReadOnlyList usableMods = mods.Value;