From e0edaf996fa36c5ca15414739d34431de878da55 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 18 Aug 2022 16:03:37 +0900 Subject: [PATCH] Test ruleset compatibility during initial startup to avoid runtime errors As we continue to break the ruleset API, it makes more sense to proactively check known changes and bail early during ruleset loading to avoid a user experiencing a crash at a random point during execution. This is a RFC and needs to be tested against known broken rulesets. There might be some other calls we want to add in addition to the ones I've listed. --- osu.Game/Rulesets/RealmRulesetStore.cs | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/RealmRulesetStore.cs b/osu.Game/Rulesets/RealmRulesetStore.cs index 62a7a13c07..c014b2d095 100644 --- a/osu.Game/Rulesets/RealmRulesetStore.cs +++ b/osu.Game/Rulesets/RealmRulesetStore.cs @@ -7,6 +7,7 @@ using System.Linq; using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Logging; using osu.Framework.Platform; +using osu.Game.Beatmaps; using osu.Game.Database; namespace osu.Game.Rulesets @@ -83,17 +84,36 @@ namespace osu.Game.Rulesets r.InstantiationInfo = instanceInfo.InstantiationInfo; r.Available = true; + testRulesetCompatibility(r); + detachedRulesets.Add(r.Clone()); } catch (Exception ex) { r.Available = false; - Logger.Log($"Could not load ruleset {r}: {ex.Message}"); + Logger.Log($"Could not load ruleset {r.Name}. Please check for an update from the developer.", level: LogLevel.Error); + Logger.Log($"Ruleset load failed with {ex.Message}"); } } availableRulesets.AddRange(detachedRulesets.OrderBy(r => r)); }); } + + private void testRulesetCompatibility(RulesetInfo rulesetInfo) + { + // do various operations to ensure that we are in a good state. + // if we can avoid loading the ruleset at this point (rather than erroring later in runtime) then that is preferred. + var instance = rulesetInfo.CreateInstance(); + + instance.CreateAllMods(); + instance.CreateIcon(); + instance.CreateResourceStore(); + + var beatmap = new Beatmap(); + var converter = instance.CreateBeatmapConverter(beatmap); + + instance.CreateBeatmapProcessor(converter.Convert()); + } } }