Skip to content

Commit

Permalink
Merge pull request #216 from minisbett/fix-mods-masking
Browse files Browse the repository at this point in the history
Reconsider mods filtering in `PerformanceCalculator` looking forward to Lazer
  • Loading branch information
smoogipoo authored Oct 13, 2024
2 parents 856c911 + bdc154b commit e387265
Show file tree
Hide file tree
Showing 10 changed files with 58 additions and 84 deletions.
6 changes: 1 addition & 5 deletions PerformanceCalculator/Difficulty/DifficultyCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,6 @@ public class DifficultyCommand : ProcessorCommand
+ "Values: hr, dt, hd, fl, ez, 4k, 5k, etc...")]
public string[] Mods { get; }

[UsedImplicitly]
[Option(Template = "-nc|--no-classic", Description = "Excludes the classic mod.")]
public bool NoClassicMod { get; }

public override void Execute()
{
var resultSet = new ResultSet();
Expand Down Expand Up @@ -124,7 +120,7 @@ private Result processBeatmap(WorkingBeatmap beatmap)
{
// Get the ruleset
var ruleset = LegacyHelper.GetRulesetFromLegacyID(Ruleset ?? beatmap.BeatmapInfo.Ruleset.OnlineID);
var mods = NoClassicMod ? getMods(ruleset) : LegacyHelper.FilterDifficultyAdjustmentMods(beatmap.BeatmapInfo, ruleset, getMods(ruleset));
var mods = getMods(ruleset);
var attributes = ruleset.CreateDifficultyCalculator(beatmap).Calculate(mods);

return new Result
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,11 +115,8 @@ public override void Execute()

private Result processBeatmap(WorkingBeatmap beatmap)
{
// Get the ruleset
var ruleset = LegacyHelper.GetRulesetFromLegacyID(Ruleset ?? beatmap.BeatmapInfo.Ruleset.OnlineID);

// bit of a hack to discard non-legacy mods.
var mods = ruleset.ConvertFromLegacyMods(ruleset.ConvertToLegacyMods(getMods(ruleset))).ToList();
var mods = getMods(ruleset);

var legacyRuleset = (ILegacyRuleset)ruleset;
var simulator = legacyRuleset.CreateLegacyScoreSimulator();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,8 @@ public virtual void OnExecute(CommandLineApplication app, IConsole console)
var ruleset = LegacyHelper.GetRulesetFromLegacyID(Ruleset);

var workingBeatmap = ProcessorWorkingBeatmap.FromFileOrId(Beatmap);
// bit of a hack to discard non-legacy mods.
var mods = ruleset.ConvertFromLegacyMods(ruleset.ConvertToLegacyMods(getMods(ruleset)))
.Append(ruleset.CreateMod<ModClassic>())
.ToArray();
Mod[] mods = [ruleset.CreateMod<ModClassic>(), .. getMods(ruleset)];

var beatmap = workingBeatmap.GetPlayableBeatmap(ruleset.RulesetInfo, mods);

var scoreInfo = new ScoreInfo(beatmap.BeatmapInfo, ruleset.RulesetInfo)
Expand Down
2 changes: 1 addition & 1 deletion PerformanceCalculator/Leaderboard/LeaderboardCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ public override void Execute()
var score = new ProcessorScoreDecoder(working).Parse(scoreInfo);

var difficultyCalculator = ruleset.CreateDifficultyCalculator(working);
var difficultyAttributes = difficultyCalculator.Calculate(LegacyHelper.FilterDifficultyAdjustmentMods(working.BeatmapInfo, ruleset, scoreInfo.Mods).ToArray());
var difficultyAttributes = difficultyCalculator.Calculate(scoreInfo.Mods);
var performanceCalculator = ruleset.CreatePerformanceCalculator();

plays.Add((performanceCalculator?.Calculate(score.ScoreInfo, difficultyAttributes).Total ?? 0, play.PP ?? 0.0));
Expand Down
52 changes: 0 additions & 52 deletions PerformanceCalculator/LegacyHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,12 @@
// See the LICENCE file in the repository root for full licence text.

using System;
using System.Linq;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Legacy;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Catch;
using osu.Game.Rulesets.Catch.Difficulty;
using osu.Game.Rulesets.Difficulty;
using osu.Game.Rulesets.Mania;
using osu.Game.Rulesets.Mania.Difficulty;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Osu.Difficulty;
using osu.Game.Rulesets.Taiko;
Expand Down Expand Up @@ -63,54 +59,6 @@ public static string GetRulesetShortNameFromId(int id)
}
}

public const LegacyMods KEY_MODS = LegacyMods.Key1 | LegacyMods.Key2 | LegacyMods.Key3 | LegacyMods.Key4 | LegacyMods.Key5 | LegacyMods.Key6 | LegacyMods.Key7 | LegacyMods.Key8
| LegacyMods.Key9 | LegacyMods.KeyCoop;

// See: https://github.com/ppy/osu-queue-score-statistics/blob/2264bfa68e14bb16ec71a7cac2072bdcfaf565b6/osu.Server.Queues.ScoreStatisticsProcessor/Helpers/LegacyModsHelper.cs
public static LegacyMods MaskRelevantMods(LegacyMods mods, bool isConvertedBeatmap, int rulesetId)
{
LegacyMods relevantMods = LegacyMods.DoubleTime | LegacyMods.HalfTime | LegacyMods.HardRock | LegacyMods.Easy;

switch (rulesetId)
{
case 0:
if ((mods & LegacyMods.Flashlight) > 0)
relevantMods |= LegacyMods.Flashlight | LegacyMods.Hidden | LegacyMods.TouchDevice;
else
relevantMods |= LegacyMods.Flashlight | LegacyMods.TouchDevice;
break;

case 3:
if (isConvertedBeatmap)
relevantMods |= KEY_MODS;
break;
}

return mods & relevantMods;
}

/// <summary>
/// Transforms a given <see cref="Mod"/> combination into one which is applicable to legacy scores.
/// This is used to match osu!stable/osu!web calculations for the time being, until such a point that these mods do get considered.
/// </summary>
public static LegacyMods ConvertToLegacyDifficultyAdjustmentMods(BeatmapInfo beatmapInfo, Ruleset ruleset, Mod[] mods)
{
var legacyMods = ruleset.ConvertToLegacyMods(mods);

// mods that are not represented in `LegacyMods` (but we can approximate them well enough with others)
if (mods.Any(mod => mod is ModDaycore))
legacyMods |= LegacyMods.HalfTime;

return MaskRelevantMods(legacyMods, ruleset.RulesetInfo.OnlineID != beatmapInfo.Ruleset.OnlineID, ruleset.RulesetInfo.OnlineID);
}

/// <summary>
/// Transforms a given <see cref="Mod"/> combination into one which is applicable to legacy scores.
/// This is used to match osu!stable/osu!web calculations for the time being, until such a point that these mods do get considered.
/// </summary>
public static Mod[] FilterDifficultyAdjustmentMods(BeatmapInfo beatmapInfo, Ruleset ruleset, Mod[] mods)
=> ruleset.ConvertFromLegacyMods(ConvertToLegacyDifficultyAdjustmentMods(beatmapInfo, ruleset, mods)).ToArray();

public static DifficultyAttributes CreateDifficultyAttributes(int legacyId)
{
switch (legacyId)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
using osu.Game.Database;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Scoring.Legacy;
using osu.Game.Scoring;
using osu.Game.Scoring.Legacy;
Expand Down Expand Up @@ -38,11 +37,8 @@ public override void Execute()
var workingBeatmap = ProcessorWorkingBeatmap.FromFileOrId(score.ScoreInfo.BeatmapInfo!.OnlineID.ToString());
var playableBeatmap = workingBeatmap.GetPlayableBeatmap(ruleset.RulesetInfo, score.ScoreInfo.Mods);

Mod[] difficultyMods = score.ScoreInfo.Mods;

if (score.ScoreInfo.IsLegacyScore)
{
difficultyMods = LegacyHelper.FilterDifficultyAdjustmentMods(workingBeatmap.BeatmapInfo, ruleset, difficultyMods);
score.ScoreInfo.LegacyTotalScore = (int)score.ScoreInfo.TotalScore;
LegacyScoreDecoder.PopulateMaximumStatistics(score.ScoreInfo, workingBeatmap);
StandardisedScoreMigrationTools.UpdateFromLegacy(
Expand All @@ -52,7 +48,7 @@ public override void Execute()
((ILegacyRuleset)ruleset).CreateLegacyScoreSimulator().Simulate(workingBeatmap, playableBeatmap));
}

var difficultyAttributes = ruleset.CreateDifficultyCalculator(workingBeatmap).Calculate(difficultyMods);
var difficultyAttributes = ruleset.CreateDifficultyCalculator(workingBeatmap).Calculate(score.ScoreInfo.Mods);
var performanceCalculator = score.ScoreInfo.Ruleset.CreateInstance().CreatePerformanceCalculator();
var performanceAttributes = performanceCalculator?.Calculate(score.ScoreInfo, difficultyAttributes);

Expand Down
46 changes: 44 additions & 2 deletions PerformanceCalculator/Performance/ScorePerformanceCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
using osu.Game.Rulesets.Catch.Difficulty;
using osu.Game.Rulesets.Difficulty;
using osu.Game.Rulesets.Mania.Difficulty;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu.Difficulty;
using osu.Game.Rulesets.Taiko.Difficulty;
using osu.Game.Scoring;
Expand Down Expand Up @@ -46,13 +47,13 @@ public override void Execute()

if (OnlineAttributes)
{
LegacyMods legacyMods = LegacyHelper.ConvertToLegacyDifficultyAdjustmentMods(workingBeatmap.BeatmapInfo, ruleset, score.Mods);
LegacyMods legacyMods = convertToLegacyMods(workingBeatmap.BeatmapInfo, ruleset, score.Mods);
attributes = queryApiAttributes(apiScore.BeatmapID, apiScore.RulesetID, legacyMods);
}
else
{
var difficultyCalculator = ruleset.CreateDifficultyCalculator(workingBeatmap);
attributes = difficultyCalculator.Calculate(LegacyHelper.FilterDifficultyAdjustmentMods(workingBeatmap.BeatmapInfo, ruleset, score.Mods));
attributes = difficultyCalculator.Calculate(score.Mods);
}

var performanceCalculator = ruleset.CreatePerformanceCalculator();
Expand Down Expand Up @@ -121,6 +122,47 @@ DifficultyAttributes getMergedAttributes<TAttributes>(APIBeatmap apiBeatmap)
}
}

/// <summary>
/// Transforms a given <see cref="Mod"/> combination into one which is applicable to legacy scores.
/// This should only be used to match performance calculations using databased attributes.
/// </summary>
private static LegacyMods convertToLegacyMods(BeatmapInfo beatmapInfo, Ruleset ruleset, Mod[] mods)
{
var legacyMods = ruleset.ConvertToLegacyMods(mods);

// mods that are not represented in `LegacyMods` (but we can approximate them well enough with others)
if (mods.Any(mod => mod is ModDaycore))
legacyMods |= LegacyMods.HalfTime;

// See: https://github.com/ppy/osu-queue-score-statistics/blob/2264bfa68e14bb16ec71a7cac2072bdcfaf565b6/osu.Server.Queues.ScoreStatisticsProcessor/Helpers/LegacyModsHelper.cs
static LegacyMods maskRelevantMods(LegacyMods mods, bool isConvertedBeatmap, int rulesetId)
{
const LegacyMods key_mods = LegacyMods.Key1 | LegacyMods.Key2 | LegacyMods.Key3 | LegacyMods.Key4 | LegacyMods.Key5 | LegacyMods.Key6 | LegacyMods.Key7 | LegacyMods.Key8
| LegacyMods.Key9 | LegacyMods.KeyCoop;

LegacyMods relevantMods = LegacyMods.DoubleTime | LegacyMods.HalfTime | LegacyMods.HardRock | LegacyMods.Easy;

switch (rulesetId)
{
case 0:
if ((mods & LegacyMods.Flashlight) > 0)
relevantMods |= LegacyMods.Flashlight | LegacyMods.Hidden | LegacyMods.TouchDevice;
else
relevantMods |= LegacyMods.Flashlight | LegacyMods.TouchDevice;
break;

case 3:
if (isConvertedBeatmap)
relevantMods |= key_mods;
break;
}

return mods & relevantMods;
}

return maskRelevantMods(legacyMods, ruleset.RulesetInfo.OnlineID != beatmapInfo.Ruleset.OnlineID, ruleset.RulesetInfo.OnlineID);
}

[JsonObject(MemberSerialization.OptIn)]
private class AttributesResponse<T>
where T : DifficultyAttributes
Expand Down
11 changes: 6 additions & 5 deletions PerformanceCalculator/PerformanceCalculator.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<LangVersion>12.0</LangVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Alba.CsConsoleFormat" Version="1.0.0" />
<PackageReference Include="McMaster.Extensions.CommandLineUtils" Version="4.1.0" />
<PackageReference Include="ppy.osu.Game" Version="2024.130.2" />
<PackageReference Include="ppy.osu.Game.Rulesets.Osu" Version="2024.130.2" />
<PackageReference Include="ppy.osu.Game.Rulesets.Taiko" Version="2024.130.2" />
<PackageReference Include="ppy.osu.Game.Rulesets.Catch" Version="2024.130.2" />
<PackageReference Include="ppy.osu.Game.Rulesets.Mania" Version="2024.130.2" />
<PackageReference Include="ppy.osu.Game" Version="2024.1009.1" />
<PackageReference Include="ppy.osu.Game.Rulesets.Osu" Version="2024.1009.1" />
<PackageReference Include="ppy.osu.Game.Rulesets.Taiko" Version="2024.1009.1" />
<PackageReference Include="ppy.osu.Game.Rulesets.Catch" Version="2024.1009.1" />
<PackageReference Include="ppy.osu.Game.Rulesets.Mania" Version="2024.1009.1" />
</ItemGroup>
</Project>
2 changes: 1 addition & 1 deletion PerformanceCalculator/Profile/ProfileCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ public override void Execute()
var score = new ProcessorScoreDecoder(working).Parse(scoreInfo);

var difficultyCalculator = ruleset.CreateDifficultyCalculator(working);
var difficultyAttributes = difficultyCalculator.Calculate(LegacyHelper.FilterDifficultyAdjustmentMods(working.BeatmapInfo, ruleset, scoreInfo.Mods).ToArray());
var difficultyAttributes = difficultyCalculator.Calculate(scoreInfo.Mods);
var performanceCalculator = ruleset.CreatePerformanceCalculator();

var ppAttributes = performanceCalculator?.Calculate(score.ScoreInfo, difficultyAttributes);
Expand Down
6 changes: 1 addition & 5 deletions PerformanceCalculator/Simulate/SimulateCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,16 +48,12 @@ public abstract class SimulateCommand : ProcessorCommand
[UsedImplicitly]
public virtual int? Goods { get; }

[UsedImplicitly]
[Option(Template = "-nc|--no-classic", Description = "Excludes the classic mod.")]
public bool NoClassicMod { get; }

public override void Execute()
{
var ruleset = Ruleset;

var workingBeatmap = ProcessorWorkingBeatmap.FromFileOrId(Beatmap);
var mods = NoClassicMod ? GetMods(ruleset) : LegacyHelper.FilterDifficultyAdjustmentMods(workingBeatmap.BeatmapInfo, ruleset, GetMods(ruleset));
var mods = GetMods(ruleset);
var beatmap = workingBeatmap.GetPlayableBeatmap(ruleset.RulesetInfo, mods);

var beatmapMaxCombo = GetMaxCombo(beatmap);
Expand Down

0 comments on commit e387265

Please sign in to comment.