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

Merge pull request #27747 from smoogipoo/mania-key-count-mod-query

Consider keymods in beatmap filtering + panel display
This commit is contained in:
Bartłomiej Dach 2024-04-03 09:49:35 +02:00 committed by GitHub
commit fd9b890a94
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
20 changed files with 143 additions and 109 deletions

View File

@ -22,11 +22,6 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
/// </summary> /// </summary>
public int TotalColumns => Stages.Sum(g => g.Columns); public int TotalColumns => Stages.Sum(g => g.Columns);
/// <summary>
/// The total number of columns that were present in this <see cref="ManiaBeatmap"/> before any user adjustments.
/// </summary>
public readonly int OriginalTotalColumns;
/// <summary> /// <summary>
/// Creates a new <see cref="ManiaBeatmap"/>. /// Creates a new <see cref="ManiaBeatmap"/>.
/// </summary> /// </summary>
@ -35,7 +30,6 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
public ManiaBeatmap(StageDefinition defaultStage, int? originalTotalColumns = null) public ManiaBeatmap(StageDefinition defaultStage, int? originalTotalColumns = null)
{ {
Stages.Add(defaultStage); Stages.Add(defaultStage);
OriginalTotalColumns = originalTotalColumns ?? defaultStage.Columns;
} }
public override IEnumerable<BeatmapStatistic> GetStatistics() public override IEnumerable<BeatmapStatistic> GetStatistics()

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
#nullable disable
using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mania.Objects;
using System; using System;
using System.Linq; using System.Linq;
@ -14,6 +12,7 @@ using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.Mania.Beatmaps.Patterns; using osu.Game.Rulesets.Mania.Beatmaps.Patterns;
using osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy; using osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Scoring.Legacy; using osu.Game.Rulesets.Scoring.Legacy;
using osu.Game.Utils; using osu.Game.Utils;
using osuTK; using osuTK;
@ -27,24 +26,42 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
/// </summary> /// </summary>
private const int max_notes_for_density = 7; private const int max_notes_for_density = 7;
/// <summary>
/// The total number of columns.
/// </summary>
public int TotalColumns => TargetColumns * (Dual ? 2 : 1);
/// <summary>
/// The number of columns per-stage.
/// </summary>
public int TargetColumns; public int TargetColumns;
/// <summary>
/// Whether to double the number of stages.
/// </summary>
public bool Dual; public bool Dual;
/// <summary>
/// Whether the beatmap instantiated with is for the mania ruleset.
/// </summary>
public readonly bool IsForCurrentRuleset; public readonly bool IsForCurrentRuleset;
private readonly int originalTargetColumns;
// Internal for testing purposes // Internal for testing purposes
internal LegacyRandom Random { get; private set; } internal readonly LegacyRandom Random;
private Pattern lastPattern = new Pattern(); private Pattern lastPattern = new Pattern();
private ManiaBeatmap beatmap;
public ManiaBeatmapConverter(IBeatmap beatmap, Ruleset ruleset) public ManiaBeatmapConverter(IBeatmap beatmap, Ruleset ruleset)
: base(beatmap, ruleset) : this(beatmap, LegacyBeatmapConversionDifficultyInfo.FromBeatmap(beatmap), ruleset)
{ {
IsForCurrentRuleset = beatmap.BeatmapInfo.Ruleset.Equals(ruleset.RulesetInfo); }
TargetColumns = GetColumnCount(LegacyBeatmapConversionDifficultyInfo.FromBeatmap(beatmap));
private ManiaBeatmapConverter(IBeatmap? beatmap, LegacyBeatmapConversionDifficultyInfo difficulty, Ruleset ruleset)
: base(beatmap!, ruleset)
{
IsForCurrentRuleset = difficulty.SourceRuleset.Equals(ruleset.RulesetInfo);
Random = new LegacyRandom((int)MathF.Round(difficulty.DrainRate + difficulty.CircleSize) * 20 + (int)(difficulty.OverallDifficulty * 41.2) + (int)MathF.Round(difficulty.ApproachRate));
TargetColumns = getColumnCount(difficulty);
if (IsForCurrentRuleset && TargetColumns > ManiaRuleset.MAX_STAGE_KEYS) if (IsForCurrentRuleset && TargetColumns > ManiaRuleset.MAX_STAGE_KEYS)
{ {
@ -52,10 +69,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
Dual = true; Dual = true;
} }
originalTargetColumns = TargetColumns; static int getColumnCount(LegacyBeatmapConversionDifficultyInfo difficulty)
}
public static int GetColumnCount(LegacyBeatmapConversionDifficultyInfo difficulty)
{ {
double roundedCircleSize = Math.Round(difficulty.CircleSize); double roundedCircleSize = Math.Round(difficulty.CircleSize);
@ -82,22 +96,26 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
return Math.Max(4, Math.Min((int)roundedOverallDifficulty + 1, 7)); return Math.Max(4, Math.Min((int)roundedOverallDifficulty + 1, 7));
} }
}
public static int GetColumnCount(LegacyBeatmapConversionDifficultyInfo difficulty, IReadOnlyList<Mod>? mods = null)
{
var converter = new ManiaBeatmapConverter(null, difficulty, new ManiaRuleset());
if (mods != null)
{
foreach (var m in mods.OfType<IApplicableToBeatmapConverter>())
m.ApplyToBeatmapConverter(converter);
}
return converter.TotalColumns;
}
public override bool CanConvert() => Beatmap.HitObjects.All(h => h is IHasXPosition); public override bool CanConvert() => Beatmap.HitObjects.All(h => h is IHasXPosition);
protected override Beatmap<ManiaHitObject> ConvertBeatmap(IBeatmap original, CancellationToken cancellationToken)
{
IBeatmapDifficultyInfo difficulty = original.Difficulty;
int seed = (int)MathF.Round(difficulty.DrainRate + difficulty.CircleSize) * 20 + (int)(difficulty.OverallDifficulty * 41.2) + (int)MathF.Round(difficulty.ApproachRate);
Random = new LegacyRandom(seed);
return base.ConvertBeatmap(original, cancellationToken);
}
protected override Beatmap<ManiaHitObject> CreateBeatmap() protected override Beatmap<ManiaHitObject> CreateBeatmap()
{ {
beatmap = new ManiaBeatmap(new StageDefinition(TargetColumns), originalTargetColumns); ManiaBeatmap beatmap = new ManiaBeatmap(new StageDefinition(TargetColumns));
if (Dual) if (Dual)
beatmap.Stages.Add(new StageDefinition(TargetColumns)); beatmap.Stages.Add(new StageDefinition(TargetColumns));
@ -115,10 +133,6 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
} }
var objects = IsForCurrentRuleset ? generateSpecific(original, beatmap) : generateConverted(original, beatmap); var objects = IsForCurrentRuleset ? generateSpecific(original, beatmap) : generateConverted(original, beatmap);
if (objects == null)
yield break;
foreach (ManiaHitObject obj in objects) foreach (ManiaHitObject obj in objects)
yield return obj; yield return obj;
} }
@ -152,7 +166,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
/// <returns>The hit objects generated.</returns> /// <returns>The hit objects generated.</returns>
private IEnumerable<ManiaHitObject> generateSpecific(HitObject original, IBeatmap originalBeatmap) private IEnumerable<ManiaHitObject> generateSpecific(HitObject original, IBeatmap originalBeatmap)
{ {
var generator = new SpecificBeatmapPatternGenerator(Random, original, beatmap, lastPattern, originalBeatmap); var generator = new SpecificBeatmapPatternGenerator(Random, original, originalBeatmap, TotalColumns, lastPattern);
foreach (var newPattern in generator.Generate()) foreach (var newPattern in generator.Generate())
{ {
@ -171,13 +185,13 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
/// <returns>The hit objects generated.</returns> /// <returns>The hit objects generated.</returns>
private IEnumerable<ManiaHitObject> generateConverted(HitObject original, IBeatmap originalBeatmap) private IEnumerable<ManiaHitObject> generateConverted(HitObject original, IBeatmap originalBeatmap)
{ {
Patterns.PatternGenerator conversion = null; Patterns.PatternGenerator? conversion = null;
switch (original) switch (original)
{ {
case IHasPath: case IHasPath:
{ {
var generator = new PathObjectPatternGenerator(Random, original, beatmap, lastPattern, originalBeatmap); var generator = new PathObjectPatternGenerator(Random, original, originalBeatmap, TotalColumns, lastPattern);
conversion = generator; conversion = generator;
var positionData = original as IHasPosition; var positionData = original as IHasPosition;
@ -195,7 +209,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
case IHasDuration endTimeData: case IHasDuration endTimeData:
{ {
conversion = new EndTimeObjectPatternGenerator(Random, original, beatmap, lastPattern, originalBeatmap); conversion = new EndTimeObjectPatternGenerator(Random, original, originalBeatmap, TotalColumns, lastPattern);
recordNote(endTimeData.EndTime, new Vector2(256, 192)); recordNote(endTimeData.EndTime, new Vector2(256, 192));
computeDensity(endTimeData.EndTime); computeDensity(endTimeData.EndTime);
@ -206,7 +220,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
{ {
computeDensity(original.StartTime); computeDensity(original.StartTime);
conversion = new HitObjectPatternGenerator(Random, original, beatmap, lastPattern, lastTime, lastPosition, density, lastStair, originalBeatmap); conversion = new HitObjectPatternGenerator(Random, original, originalBeatmap, TotalColumns, lastPattern, lastTime, lastPosition, density, lastStair);
recordNote(original.StartTime, positionData.Position); recordNote(original.StartTime, positionData.Position);
break; break;
@ -231,8 +245,8 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
/// </summary> /// </summary>
private class SpecificBeatmapPatternGenerator : Patterns.Legacy.PatternGenerator private class SpecificBeatmapPatternGenerator : Patterns.Legacy.PatternGenerator
{ {
public SpecificBeatmapPatternGenerator(LegacyRandom random, HitObject hitObject, ManiaBeatmap beatmap, Pattern previousPattern, IBeatmap originalBeatmap) public SpecificBeatmapPatternGenerator(LegacyRandom random, HitObject hitObject, IBeatmap beatmap, int totalColumns, Pattern previousPattern)
: base(random, hitObject, beatmap, previousPattern, originalBeatmap) : base(random, hitObject, beatmap, previousPattern, totalColumns)
{ {
} }

View File

@ -17,8 +17,8 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
private readonly int endTime; private readonly int endTime;
private readonly PatternType convertType; private readonly PatternType convertType;
public EndTimeObjectPatternGenerator(LegacyRandom random, HitObject hitObject, ManiaBeatmap beatmap, Pattern previousPattern, IBeatmap originalBeatmap) public EndTimeObjectPatternGenerator(LegacyRandom random, HitObject hitObject, IBeatmap beatmap, int totalColumns, Pattern previousPattern)
: base(random, hitObject, beatmap, previousPattern, originalBeatmap) : base(random, hitObject, beatmap, previousPattern, totalColumns)
{ {
endTime = (int)((HitObject as IHasDuration)?.EndTime ?? 0); endTime = (int)((HitObject as IHasDuration)?.EndTime ?? 0);

View File

@ -23,9 +23,9 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
private readonly PatternType convertType; private readonly PatternType convertType;
public HitObjectPatternGenerator(LegacyRandom random, HitObject hitObject, ManiaBeatmap beatmap, Pattern previousPattern, double previousTime, Vector2 previousPosition, double density, public HitObjectPatternGenerator(LegacyRandom random, HitObject hitObject, IBeatmap beatmap, int totalColumns, Pattern previousPattern, double previousTime, Vector2 previousPosition,
PatternType lastStair, IBeatmap originalBeatmap) double density, PatternType lastStair)
: base(random, hitObject, beatmap, previousPattern, originalBeatmap) : base(random, hitObject, beatmap, previousPattern, totalColumns)
{ {
StairType = lastStair; StairType = lastStair;

View File

@ -31,8 +31,8 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
private PatternType convertType; private PatternType convertType;
public PathObjectPatternGenerator(LegacyRandom random, HitObject hitObject, ManiaBeatmap beatmap, Pattern previousPattern, IBeatmap originalBeatmap) public PathObjectPatternGenerator(LegacyRandom random, HitObject hitObject, IBeatmap beatmap, int totalColumns, Pattern previousPattern)
: base(random, hitObject, beatmap, previousPattern, originalBeatmap) : base(random, hitObject, beatmap, previousPattern, totalColumns)
{ {
convertType = PatternType.None; convertType = PatternType.None;
if (!Beatmap.ControlPointInfo.EffectPointAt(hitObject.StartTime).KiaiMode) if (!Beatmap.ControlPointInfo.EffectPointAt(hitObject.StartTime).KiaiMode)

View File

@ -27,20 +27,12 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
/// </summary> /// </summary>
protected readonly LegacyRandom Random; protected readonly LegacyRandom Random;
/// <summary> protected PatternGenerator(LegacyRandom random, HitObject hitObject, IBeatmap beatmap, Pattern previousPattern, int totalColumns)
/// The beatmap which <see cref="HitObject"/> is being converted from. : base(hitObject, beatmap, totalColumns, previousPattern)
/// </summary>
protected readonly IBeatmap OriginalBeatmap;
protected PatternGenerator(LegacyRandom random, HitObject hitObject, ManiaBeatmap beatmap, Pattern previousPattern, IBeatmap originalBeatmap)
: base(hitObject, beatmap, previousPattern)
{ {
ArgumentNullException.ThrowIfNull(random); ArgumentNullException.ThrowIfNull(random);
ArgumentNullException.ThrowIfNull(originalBeatmap);
Random = random; Random = random;
OriginalBeatmap = originalBeatmap;
RandomStart = TotalColumns == 8 ? 1 : 0; RandomStart = TotalColumns == 8 ? 1 : 0;
} }
@ -104,17 +96,17 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
if (conversionDifficulty != null) if (conversionDifficulty != null)
return conversionDifficulty.Value; return conversionDifficulty.Value;
HitObject lastObject = OriginalBeatmap.HitObjects.LastOrDefault(); HitObject lastObject = Beatmap.HitObjects.LastOrDefault();
HitObject firstObject = OriginalBeatmap.HitObjects.FirstOrDefault(); HitObject firstObject = Beatmap.HitObjects.FirstOrDefault();
// Drain time in seconds // Drain time in seconds
int drainTime = (int)(((lastObject?.StartTime ?? 0) - (firstObject?.StartTime ?? 0) - OriginalBeatmap.TotalBreakTime) / 1000); int drainTime = (int)(((lastObject?.StartTime ?? 0) - (firstObject?.StartTime ?? 0) - Beatmap.TotalBreakTime) / 1000);
if (drainTime == 0) if (drainTime == 0)
drainTime = 10000; drainTime = 10000;
IBeatmapDifficultyInfo difficulty = OriginalBeatmap.Difficulty; IBeatmapDifficultyInfo difficulty = Beatmap.Difficulty;
conversionDifficulty = ((difficulty.DrainRate + Math.Clamp(difficulty.ApproachRate, 4, 7)) / 1.5 + (double)OriginalBeatmap.HitObjects.Count / drainTime * 9f) / 38f * 5f / 1.15; conversionDifficulty = ((difficulty.DrainRate + Math.Clamp(difficulty.ApproachRate, 4, 7)) / 1.5 + (double)Beatmap.HitObjects.Count / drainTime * 9f) / 38f * 5f / 1.15;
conversionDifficulty = Math.Min(conversionDifficulty.Value, 12); conversionDifficulty = Math.Min(conversionDifficulty.Value, 12);
return conversionDifficulty.Value; return conversionDifficulty.Value;

View File

@ -3,6 +3,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects;
namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns
@ -25,11 +26,11 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns
/// <summary> /// <summary>
/// The beatmap which <see cref="HitObject"/> is a part of. /// The beatmap which <see cref="HitObject"/> is a part of.
/// </summary> /// </summary>
protected readonly ManiaBeatmap Beatmap; protected readonly IBeatmap Beatmap;
protected readonly int TotalColumns; protected readonly int TotalColumns;
protected PatternGenerator(HitObject hitObject, ManiaBeatmap beatmap, Pattern previousPattern) protected PatternGenerator(HitObject hitObject, IBeatmap beatmap, int totalColumns, Pattern previousPattern)
{ {
ArgumentNullException.ThrowIfNull(hitObject); ArgumentNullException.ThrowIfNull(hitObject);
ArgumentNullException.ThrowIfNull(beatmap); ArgumentNullException.ThrowIfNull(beatmap);
@ -38,8 +39,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns
HitObject = hitObject; HitObject = hitObject;
Beatmap = beatmap; Beatmap = beatmap;
PreviousPattern = previousPattern; PreviousPattern = previousPattern;
TotalColumns = totalColumns;
TotalColumns = Beatmap.TotalColumns;
} }
/// <summary> /// <summary>

View File

@ -51,13 +51,8 @@ namespace osu.Game.Rulesets.Mania.Difficulty
return multiplier; return multiplier;
// Apply key mod multipliers. // Apply key mod multipliers.
int originalColumns = ManiaBeatmapConverter.GetColumnCount(difficulty); int originalColumns = ManiaBeatmapConverter.GetColumnCount(difficulty);
int actualColumns = originalColumns; int actualColumns = ManiaBeatmapConverter.GetColumnCount(difficulty, mods);
actualColumns = mods.OfType<ManiaKeyMod>().SingleOrDefault()?.KeyCount ?? actualColumns;
if (mods.Any(m => m is ManiaModDualStages))
actualColumns *= 2;
if (actualColumns > originalColumns) if (actualColumns > originalColumns)
multiplier *= 0.9; multiplier *= 0.9;

View File

@ -14,9 +14,9 @@ namespace osu.Game.Rulesets.Mania
{ {
private FilterCriteria.OptionalRange<float> keys; private FilterCriteria.OptionalRange<float> keys;
public bool Matches(BeatmapInfo beatmapInfo) public bool Matches(BeatmapInfo beatmapInfo, FilterCriteria criteria)
{ {
return !keys.HasFilter || keys.IsInRange(ManiaBeatmapConverter.GetColumnCount(LegacyBeatmapConversionDifficultyInfo.FromBeatmapInfo(beatmapInfo))); return !keys.HasFilter || keys.IsInRange(ManiaBeatmapConverter.GetColumnCount(LegacyBeatmapConversionDifficultyInfo.FromBeatmapInfo(beatmapInfo), criteria.Mods));
} }
public bool TryParseCustomKeywordCriteria(string key, Operator op, string value) public bool TryParseCustomKeywordCriteria(string key, Operator op, string value)

View File

@ -423,8 +423,8 @@ namespace osu.Game.Rulesets.Mania
public override DifficultySection CreateEditorDifficultySection() => new ManiaDifficultySection(); public override DifficultySection CreateEditorDifficultySection() => new ManiaDifficultySection();
public int GetKeyCount(IBeatmapInfo beatmapInfo) public int GetKeyCount(IBeatmapInfo beatmapInfo, IReadOnlyList<Mod>? mods = null)
=> ManiaBeatmapConverter.GetColumnCount(LegacyBeatmapConversionDifficultyInfo.FromBeatmapInfo(beatmapInfo)); => ManiaBeatmapConverter.GetColumnCount(LegacyBeatmapConversionDifficultyInfo.FromBeatmapInfo(beatmapInfo), mods);
} }
public enum PlayfieldType public enum PlayfieldType

View File

@ -309,7 +309,7 @@ namespace osu.Game.Tests.NonVisual.Filtering
match = shouldMatch; match = shouldMatch;
} }
public bool Matches(BeatmapInfo beatmapInfo) => match; public bool Matches(BeatmapInfo beatmapInfo, FilterCriteria criteria) => match;
public bool TryParseCustomKeywordCriteria(string key, Operator op, string value) => false; public bool TryParseCustomKeywordCriteria(string key, Operator op, string value) => false;
} }
} }

View File

@ -502,7 +502,7 @@ namespace osu.Game.Tests.NonVisual.Filtering
{ {
public string? CustomValue { get; set; } public string? CustomValue { get; set; }
public bool Matches(BeatmapInfo beatmapInfo) => true; public bool Matches(BeatmapInfo beatmapInfo, FilterCriteria criteria) => true;
public bool TryParseCustomKeywordCriteria(string key, Operator op, string value) public bool TryParseCustomKeywordCriteria(string key, Operator op, string value)
{ {

View File

@ -18,11 +18,12 @@ namespace osu.Game.Rulesets.Filter
/// in addition to the ones mandated by song select. /// in addition to the ones mandated by song select.
/// </summary> /// </summary>
/// <param name="beatmapInfo">The beatmap to test the criteria against.</param> /// <param name="beatmapInfo">The beatmap to test the criteria against.</param>
/// <param name="criteria">The filter criteria.</param>
/// <returns> /// <returns>
/// <c>true</c> if the beatmap matches the ruleset-specific custom filtering criteria, /// <c>true</c> if the beatmap matches the ruleset-specific custom filtering criteria,
/// <c>false</c> otherwise. /// <c>false</c> otherwise.
/// </returns> /// </returns>
bool Matches(BeatmapInfo beatmapInfo); bool Matches(BeatmapInfo beatmapInfo, FilterCriteria criteria);
/// <summary> /// <summary>
/// Attempts to parse a single custom keyword criterion, given by the user via the song select search box. /// Attempts to parse a single custom keyword criterion, given by the user via the song select search box.

View File

@ -1,7 +1,9 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using System.Collections.Generic;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Scoring.Legacy; using osu.Game.Rulesets.Scoring.Legacy;
namespace osu.Game.Rulesets namespace osu.Game.Rulesets
@ -18,8 +20,7 @@ namespace osu.Game.Rulesets
/// <summary> /// <summary>
/// Retrieves the number of mania keys required to play the beatmap. /// Retrieves the number of mania keys required to play the beatmap.
/// </summary> /// </summary>
/// <returns></returns> int GetKeyCount(IBeatmapInfo beatmapInfo, IReadOnlyList<Mod>? mods = null) => 0;
int GetKeyCount(IBeatmapInfo beatmapInfo) => 0;
ILegacyScoreSimulator CreateLegacyScoreSimulator(); ILegacyScoreSimulator CreateLegacyScoreSimulator();
} }

View File

@ -18,6 +18,16 @@ namespace osu.Game.Rulesets.Scoring.Legacy
/// </summary> /// </summary>
public IRulesetInfo SourceRuleset { get; set; } = new RulesetInfo(); public IRulesetInfo SourceRuleset { get; set; } = new RulesetInfo();
/// <summary>
/// The beatmap drain rate.
/// </summary>
public float DrainRate { get; set; }
/// <summary>
/// The beatmap approach rate.
/// </summary>
public float ApproachRate { get; set; }
/// <summary> /// <summary>
/// The beatmap circle size. /// The beatmap circle size.
/// </summary> /// </summary>
@ -41,8 +51,6 @@ namespace osu.Game.Rulesets.Scoring.Legacy
/// </summary> /// </summary>
public int TotalObjectCount { get; set; } public int TotalObjectCount { get; set; }
float IBeatmapDifficultyInfo.DrainRate => 0;
float IBeatmapDifficultyInfo.ApproachRate => 0;
double IBeatmapDifficultyInfo.SliderMultiplier => 0; double IBeatmapDifficultyInfo.SliderMultiplier => 0;
double IBeatmapDifficultyInfo.SliderTickRate => 0; double IBeatmapDifficultyInfo.SliderTickRate => 0;
@ -51,6 +59,8 @@ namespace osu.Game.Rulesets.Scoring.Legacy
public static LegacyBeatmapConversionDifficultyInfo FromBeatmap(IBeatmap beatmap) => new LegacyBeatmapConversionDifficultyInfo public static LegacyBeatmapConversionDifficultyInfo FromBeatmap(IBeatmap beatmap) => new LegacyBeatmapConversionDifficultyInfo
{ {
SourceRuleset = beatmap.BeatmapInfo.Ruleset, SourceRuleset = beatmap.BeatmapInfo.Ruleset,
DrainRate = beatmap.Difficulty.DrainRate,
ApproachRate = beatmap.Difficulty.ApproachRate,
CircleSize = beatmap.Difficulty.CircleSize, CircleSize = beatmap.Difficulty.CircleSize,
OverallDifficulty = beatmap.Difficulty.OverallDifficulty, OverallDifficulty = beatmap.Difficulty.OverallDifficulty,
EndTimeObjectCount = beatmap.HitObjects.Count(h => h is IHasDuration), EndTimeObjectCount = beatmap.HitObjects.Count(h => h is IHasDuration),
@ -60,6 +70,8 @@ namespace osu.Game.Rulesets.Scoring.Legacy
public static LegacyBeatmapConversionDifficultyInfo FromBeatmapInfo(IBeatmapInfo beatmapInfo) => new LegacyBeatmapConversionDifficultyInfo public static LegacyBeatmapConversionDifficultyInfo FromBeatmapInfo(IBeatmapInfo beatmapInfo) => new LegacyBeatmapConversionDifficultyInfo
{ {
SourceRuleset = beatmapInfo.Ruleset, SourceRuleset = beatmapInfo.Ruleset,
DrainRate = beatmapInfo.Difficulty.DrainRate,
ApproachRate = beatmapInfo.Difficulty.ApproachRate,
CircleSize = beatmapInfo.Difficulty.CircleSize, CircleSize = beatmapInfo.Difficulty.CircleSize,
OverallDifficulty = beatmapInfo.Difficulty.OverallDifficulty, OverallDifficulty = beatmapInfo.Difficulty.OverallDifficulty,
EndTimeObjectCount = beatmapInfo.EndTimeObjectCount, EndTimeObjectCount = beatmapInfo.EndTimeObjectCount,

View File

@ -85,7 +85,7 @@ namespace osu.Game.Screens.Select.Carousel
match &= criteria.CollectionBeatmapMD5Hashes?.Contains(BeatmapInfo.MD5Hash) ?? true; match &= criteria.CollectionBeatmapMD5Hashes?.Contains(BeatmapInfo.MD5Hash) ?? true;
if (match && criteria.RulesetCriteria != null) if (match && criteria.RulesetCriteria != null)
match &= criteria.RulesetCriteria.Matches(BeatmapInfo); match &= criteria.RulesetCriteria.Matches(BeatmapInfo, criteria);
return match; return match;
} }

View File

@ -28,6 +28,7 @@ using osu.Game.Graphics.UserInterface;
using osu.Game.Overlays; using osu.Game.Overlays;
using osu.Game.Resources.Localisation.Web; using osu.Game.Resources.Localisation.Web;
using osu.Game.Rulesets; using osu.Game.Rulesets;
using osu.Game.Rulesets.Mods;
using osuTK; using osuTK;
using osuTK.Graphics; using osuTK.Graphics;
@ -75,6 +76,9 @@ namespace osu.Game.Screens.Select.Carousel
[Resolved] [Resolved]
private IBindable<RulesetInfo> ruleset { get; set; } = null!; private IBindable<RulesetInfo> ruleset { get; set; } = null!;
[Resolved]
private IBindable<IReadOnlyList<Mod>> mods { get; set; } = null!;
private IBindable<StarDifficulty?> starDifficultyBindable = null!; private IBindable<StarDifficulty?> starDifficultyBindable = null!;
private CancellationTokenSource? starDifficultyCancellationSource; private CancellationTokenSource? starDifficultyCancellationSource;
@ -185,6 +189,7 @@ namespace osu.Game.Screens.Select.Carousel
base.LoadComplete(); base.LoadComplete();
ruleset.BindValueChanged(_ => updateKeyCount()); ruleset.BindValueChanged(_ => updateKeyCount());
mods.BindValueChanged(_ => updateKeyCount());
} }
protected override void Selected() protected override void Selected()
@ -255,7 +260,7 @@ namespace osu.Game.Screens.Select.Carousel
ILegacyRuleset legacyRuleset = (ILegacyRuleset)ruleset.Value.CreateInstance(); ILegacyRuleset legacyRuleset = (ILegacyRuleset)ruleset.Value.CreateInstance();
keyCountText.Alpha = 1; keyCountText.Alpha = 1;
keyCountText.Text = $"[{legacyRuleset.GetKeyCount(beatmapInfo)}K]"; keyCountText.Text = $"[{legacyRuleset.GetKeyCount(beatmapInfo, mods.Value)}K]";
} }
else else
keyCountText.Alpha = 0; keyCountText.Alpha = 0;

View File

@ -199,7 +199,7 @@ namespace osu.Game.Screens.Select.Details
// For the time being, the key count is static no matter what, because: // For the time being, the key count is static no matter what, because:
// a) The method doesn't have knowledge of the active keymods. Doing so may require considerations for filtering. // a) The method doesn't have knowledge of the active keymods. Doing so may require considerations for filtering.
// b) Using the difficulty adjustment mod to adjust OD doesn't have an effect on conversion. // b) Using the difficulty adjustment mod to adjust OD doesn't have an effect on conversion.
int keyCount = baseDifficulty == null ? 0 : legacyRuleset.GetKeyCount(BeatmapInfo); int keyCount = baseDifficulty == null ? 0 : legacyRuleset.GetKeyCount(BeatmapInfo, mods.Value);
FirstValue.Title = BeatmapsetsStrings.ShowStatsCsMania; FirstValue.Title = BeatmapsetsStrings.ShowStatsCsMania;
FirstValue.Value = (keyCount, keyCount); FirstValue.Value = (keyCount, keyCount);

View File

@ -4,7 +4,9 @@
#nullable disable #nullable disable
using System; using System;
using System.Collections.Generic;
using System.Collections.Immutable; using System.Collections.Immutable;
using System.Linq;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Graphics; using osu.Framework.Graphics;
@ -22,6 +24,7 @@ using osu.Game.Graphics.UserInterface;
using osu.Game.Localisation; using osu.Game.Localisation;
using osu.Game.Resources.Localisation.Web; using osu.Game.Resources.Localisation.Web;
using osu.Game.Rulesets; using osu.Game.Rulesets;
using osu.Game.Rulesets.Mods;
using osu.Game.Screens.Select.Filter; using osu.Game.Screens.Select.Filter;
using osuTK; using osuTK;
using osuTK.Graphics; using osuTK.Graphics;
@ -65,6 +68,7 @@ namespace osu.Game.Screens.Select
Sort = sortMode.Value, Sort = sortMode.Value,
AllowConvertedBeatmaps = showConverted.Value, AllowConvertedBeatmaps = showConverted.Value,
Ruleset = ruleset.Value, Ruleset = ruleset.Value,
Mods = mods.Value,
CollectionBeatmapMD5Hashes = collectionDropdown.Current.Value?.Collection?.PerformRead(c => c.BeatmapMD5Hashes).ToImmutableHashSet() CollectionBeatmapMD5Hashes = collectionDropdown.Current.Value?.Collection?.PerformRead(c => c.BeatmapMD5Hashes).ToImmutableHashSet()
}; };
@ -84,7 +88,7 @@ namespace osu.Game.Screens.Select
base.ReceivePositionalInputAt(screenSpacePos) || sortTabs.ReceivePositionalInputAt(screenSpacePos); base.ReceivePositionalInputAt(screenSpacePos) || sortTabs.ReceivePositionalInputAt(screenSpacePos);
[BackgroundDependencyLoader(permitNulls: true)] [BackgroundDependencyLoader(permitNulls: true)]
private void load(OsuColour colours, IBindable<RulesetInfo> parentRuleset, OsuConfigManager config) private void load(OsuColour colours, OsuConfigManager config)
{ {
sortMode = config.GetBindable<SortMode>(OsuSetting.SongSelectSortingMode); sortMode = config.GetBindable<SortMode>(OsuSetting.SongSelectSortingMode);
groupMode = config.GetBindable<GroupMode>(OsuSetting.SongSelectGroupingMode); groupMode = config.GetBindable<GroupMode>(OsuSetting.SongSelectGroupingMode);
@ -214,8 +218,18 @@ namespace osu.Game.Screens.Select
config.BindWith(OsuSetting.DisplayStarsMaximum, maximumStars); config.BindWith(OsuSetting.DisplayStarsMaximum, maximumStars);
maximumStars.ValueChanged += _ => updateCriteria(); maximumStars.ValueChanged += _ => updateCriteria();
ruleset.BindTo(parentRuleset);
ruleset.BindValueChanged(_ => updateCriteria()); ruleset.BindValueChanged(_ => updateCriteria());
mods.BindValueChanged(m =>
{
// Mods are updated once by the mod select overlay when song select is entered,
// regardless of if there are any mods or any changes have taken place.
// Updating the criteria here so early triggers a re-ordering of panels on song select, via... some mechanism.
// Todo: Investigate/fix and potentially remove this.
if (m.NewValue.SequenceEqual(m.OldValue))
return;
updateCriteria();
});
groupMode.BindValueChanged(_ => updateCriteria()); groupMode.BindValueChanged(_ => updateCriteria());
sortMode.BindValueChanged(_ => updateCriteria()); sortMode.BindValueChanged(_ => updateCriteria());
@ -239,7 +253,11 @@ namespace osu.Game.Screens.Select
searchTextBox.HoldFocus = true; searchTextBox.HoldFocus = true;
} }
private readonly IBindable<RulesetInfo> ruleset = new Bindable<RulesetInfo>(); [Resolved]
private IBindable<RulesetInfo> ruleset { get; set; } = null!;
[Resolved]
private IBindable<IReadOnlyList<Mod>> mods { get; set; } = null!;
private readonly Bindable<bool> showConverted = new Bindable<bool>(); private readonly Bindable<bool> showConverted = new Bindable<bool>();
private readonly Bindable<double> minimumStars = new BindableDouble(); private readonly Bindable<double> minimumStars = new BindableDouble();

View File

@ -10,6 +10,7 @@ using osu.Game.Beatmaps;
using osu.Game.Collections; using osu.Game.Collections;
using osu.Game.Rulesets; using osu.Game.Rulesets;
using osu.Game.Rulesets.Filter; using osu.Game.Rulesets.Filter;
using osu.Game.Rulesets.Mods;
using osu.Game.Screens.Select.Filter; using osu.Game.Screens.Select.Filter;
namespace osu.Game.Screens.Select namespace osu.Game.Screens.Select
@ -50,6 +51,7 @@ namespace osu.Game.Screens.Select
public OptionalTextFilter[] SearchTerms = Array.Empty<OptionalTextFilter>(); public OptionalTextFilter[] SearchTerms = Array.Empty<OptionalTextFilter>();
public RulesetInfo? Ruleset; public RulesetInfo? Ruleset;
public IReadOnlyList<Mod>? Mods;
public bool AllowConvertedBeatmaps; public bool AllowConvertedBeatmaps;
private string searchText = string.Empty; private string searchText = string.Empty;