1
0
mirror of https://github.com/ppy/osu.git synced 2025-01-14 20:03:21 +08:00

Merge pull request #19830 from peppy/test-ruleset-compatibility

Test ruleset compatibility during initial startup to avoid runtime errors
This commit is contained in:
Dan Balasescu 2022-08-22 15:24:46 +09:00 committed by GitHub
commit 2bc0a68911
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 41 additions and 8 deletions

View File

@ -21,8 +21,11 @@ namespace osu.Game.Rulesets.Pippidon.Beatmaps
public PippidonBeatmapConverter(IBeatmap beatmap, Ruleset ruleset)
: base(beatmap, ruleset)
{
minPosition = beatmap.HitObjects.Min(getUsablePosition);
maxPosition = beatmap.HitObjects.Max(getUsablePosition);
if (beatmap.HitObjects.Any())
{
minPosition = beatmap.HitObjects.Min(getUsablePosition);
maxPosition = beatmap.HitObjects.Max(getUsablePosition);
}
}
public override bool CanConvert() => Beatmap.HitObjects.All(h => h is IHasXPosition && h is IHasYPosition);

View File

@ -5,8 +5,8 @@ using System;
using System.Collections.Generic;
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
@ -68,8 +68,14 @@ namespace osu.Game.Rulesets
{
try
{
var resolvedType = Type.GetType(r.InstantiationInfo)
?? throw new RulesetLoadException(@"Type could not be resolved");
var resolvedType = Type.GetType(r.InstantiationInfo);
if (resolvedType == null)
{
// ruleset DLL was probably deleted.
r.Available = false;
continue;
}
var instanceInfo = (Activator.CreateInstance(resolvedType) as Ruleset)?.RulesetInfo
?? throw new RulesetLoadException(@"Instantiation failure");
@ -83,17 +89,35 @@ 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}");
LogFailedLoad(r.Name, ex);
}
}
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());
}
}
}

View File

@ -138,7 +138,7 @@ namespace osu.Game.Rulesets
}
catch (Exception e)
{
Logger.Error(e, $"Failed to load ruleset {filename}");
LogFailedLoad(filename, e);
}
}
@ -158,7 +158,7 @@ namespace osu.Game.Rulesets
}
catch (Exception e)
{
Logger.Error(e, $"Failed to add ruleset {assembly}");
LogFailedLoad(assembly.FullName, e);
}
}
@ -173,6 +173,12 @@ namespace osu.Game.Rulesets
AppDomain.CurrentDomain.AssemblyResolve -= resolveRulesetDependencyAssembly;
}
protected void LogFailedLoad(string name, Exception exception)
{
Logger.Log($"Could not load ruleset {name}. Please check for an update from the developer.", level: LogLevel.Error);
Logger.Log($"Ruleset load failed: {exception}");
}
#region Implementation of IRulesetStore
IRulesetInfo? IRulesetStore.GetRuleset(int id) => GetRuleset(id);