1
0
mirror of https://github.com/ppy/osu.git synced 2024-12-13 07:43:00 +08:00

Add new methods to ruleset for quicker mod lookups

This commit is contained in:
Dean Herbert 2021-09-09 16:34:49 +09:00
parent e66d76d26e
commit 4d0530ca9d
7 changed files with 51 additions and 5 deletions

View File

@ -39,5 +39,11 @@ namespace osu.Game.Benchmarks
{
ruleset.GetAllMods().Consume(new Consumer());
}
[Benchmark]
public void BenchmarkGetAllModsForReference()
{
ruleset.GetAllModsForReference().Consume(new Consumer());
}
}
}

View File

@ -49,7 +49,7 @@ namespace osu.Game.Tournament.Components
}
var ruleset = rulesets.GetRuleset(ladderInfo.Ruleset.Value?.ID ?? 0);
var modIcon = ruleset?.CreateInstance().GetAllMods().FirstOrDefault(mod => mod.Acronym == modAcronym);
var modIcon = ruleset?.CreateInstance().GetModForAcronym(modAcronym);
if (modIcon == null)
return;

View File

@ -48,7 +48,7 @@ namespace osu.Game.Online.API
public Mod ToMod(Ruleset ruleset)
{
Mod resultMod = ruleset.GetAllMods().FirstOrDefault(m => m.Acronym == Acronym);
Mod resultMod = ruleset.GetModForAcronym(Acronym);
if (resultMod == null)
throw new InvalidOperationException($"There is no mod in the ruleset ({ruleset.ShortName}) matching the acronym {Acronym}.");

View File

@ -23,7 +23,7 @@ namespace osu.Game.Online.API.Requests.Responses
var rulesetInstance = ruleset.CreateInstance();
var mods = Mods != null ? rulesetInstance.GetAllMods().Where(mod => Mods.Contains(mod.Acronym)).ToArray() : Array.Empty<Mod>();
var mods = Mods != null ? Mods.Select(acronym => rulesetInstance.GetModForAcronym(acronym)).Where(m => m != null).ToArray() : Array.Empty<Mod>();
// all API scores provided by this class are considered to be legacy.
mods = mods.Append(rulesetInstance.GetAllMods().OfType<ModClassic>().Single()).ToArray();

View File

@ -54,7 +54,7 @@ namespace osu.Game.Overlays.BeatmapSet
return;
modsContainer.Add(new ModButton(new ModNoMod()));
modsContainer.AddRange(ruleset.NewValue.CreateInstance().GetAllMods().Where(m => m.UserPlayable).Select(m => new ModButton(m)));
modsContainer.AddRange(ruleset.NewValue.CreateInstance().GetAllModsForReference().Where(m => m.UserPlayable).Select(m => new ModButton(m)));
modsContainer.ForEach(button =>
{

View File

@ -107,7 +107,7 @@ namespace osu.Game.Overlays.Mods
var incompatibleTypes = mod.IncompatibleMods;
var allMods = ruleset.Value.CreateInstance().GetAllMods();
var allMods = ruleset.Value.CreateInstance().GetAllModsForReference();
incompatibleMods.Value = allMods.Where(m => m.GetType() != mod.GetType() && incompatibleTypes.Any(t => t.IsInstanceOfType(m))).ToList();
incompatibleText.Text = incompatibleMods.Value.Any() ? "Incompatible with:" : "Compatible with all mods";

View File

@ -2,6 +2,7 @@
// See the LICENCE file in the repository root for full licence text.
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Graphics;
@ -23,6 +24,7 @@ using osu.Game.Scoring;
using osu.Game.Skinning;
using osu.Game.Users;
using JetBrains.Annotations;
using osu.Framework.Bindables;
using osu.Framework.Extensions;
using osu.Framework.Extensions.EnumExtensions;
using osu.Framework.Testing;
@ -38,6 +40,13 @@ namespace osu.Game.Rulesets
{
public RulesetInfo RulesetInfo { get; internal set; }
/// <summary>
/// Returns fresh instances of all mods.
/// </summary>
/// <remarks>
/// This comes with considerable allocation overhead. If only accessing for reference purposes (ie. not changing bindables / settings)
/// use <see cref="GetAllModsForReference"/> instead.
/// </remarks>
public IEnumerable<Mod> GetAllMods() => Enum.GetValues(typeof(ModType)).Cast<ModType>()
// Confine all mods of each mod type into a single IEnumerable<Mod>
.SelectMany(GetModsFor)
@ -46,6 +55,37 @@ namespace osu.Game.Rulesets
// Resolve MultiMods as their .Mods property
.SelectMany(mod => (mod as MultiMod)?.Mods ?? new[] { mod });
private static readonly ConcurrentDictionary<int, Mod[]> mod_reference_cache = new ConcurrentDictionary<int, Mod[]>();
/// <summary>
/// Returns all mods for a query-only purpose.
/// Bindables should not be considered usable when retrieving via this method (use <see cref="GetAllMods"/> instead).
/// </summary>
public IEnumerable<Mod> GetAllModsForReference()
{
if (!(RulesetInfo.ID is int id))
return GetAllMods();
if (!mod_reference_cache.TryGetValue(id, out var mods))
mod_reference_cache[id] = mods = GetAllMods().ToArray();
return mods;
}
/// <summary>
/// Returns a fresh instance of the mod matching the specified acronym.
/// </summary>
/// <param name="acronym">The acronym to query for .</param>
public Mod GetModForAcronym(string acronym)
{
var type = GetAllModsForReference().FirstOrDefault(m => m.Acronym == acronym)?.GetType();
if (type != null)
return (Mod)Activator.CreateInstance(type);
return null;
}
public abstract IEnumerable<Mod> GetModsFor(ModType type);
/// <summary>