-
Notifications
You must be signed in to change notification settings - Fork 15
Enforce real time difficulty for mod combinations which are not stored in the database #274
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 8 commits
2563d86
9d2cd87
3b159d5
435a1f5
749f505
8aae8a2
927af4e
59ca627
9835e52
8480823
b540e7b
5e1b1d9
f514a3c
26636d0
0ec8c96
12217e7
be5a334
c03acf1
ff2aa59
7bbb452
b3ed260
fc5e32a
ffb1b48
2f562cd
808dc5f
19f72cb
2abc9b2
09efc44
327669a
8b57913
68f0ce1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,6 +4,7 @@ | |
| using System; | ||
| using System.Collections.Concurrent; | ||
| using System.Collections.Generic; | ||
| using System.Diagnostics; | ||
| using System.Diagnostics.CodeAnalysis; | ||
| using System.Linq; | ||
| using System.Threading.Tasks; | ||
|
|
@@ -13,10 +14,15 @@ | |
| using osu.Game.Beatmaps; | ||
| using osu.Game.Beatmaps.Legacy; | ||
| using osu.Game.Rulesets; | ||
| using osu.Game.Rulesets.Catch.Mods; | ||
| using osu.Game.Rulesets.Difficulty; | ||
| using osu.Game.Rulesets.Mania.Mods; | ||
| using osu.Game.Rulesets.Mods; | ||
| using osu.Game.Rulesets.Osu.Mods; | ||
| using osu.Game.Rulesets.Taiko.Mods; | ||
| using osu.Server.Queues.ScoreStatisticsProcessor.Helpers; | ||
| using osu.Server.Queues.ScoreStatisticsProcessor.Models; | ||
| using StatsdClient; | ||
| using Beatmap = osu.Server.Queues.ScoreStatisticsProcessor.Models.Beatmap; | ||
|
|
||
| namespace osu.Server.Queues.ScoreStatisticsProcessor.Stores | ||
|
|
@@ -26,7 +32,7 @@ namespace osu.Server.Queues.ScoreStatisticsProcessor.Stores | |
| /// </summary> | ||
| public class BeatmapStore | ||
| { | ||
| private static readonly bool use_realtime_difficulty_calculation = Environment.GetEnvironmentVariable("REALTIME_DIFFICULTY") != "0"; | ||
| private static readonly bool always_use_realtime_difficulty_calculation = Environment.GetEnvironmentVariable("ALWAYS_REALTIME_DIFFICULTY") != "0"; | ||
| private static readonly string beatmap_download_path = Environment.GetEnvironmentVariable("BEATMAP_DOWNLOAD_PATH") ?? "https://osu.ppy.sh/osu/{0}"; | ||
|
|
||
| private readonly ConcurrentDictionary<uint, Beatmap?> beatmapCache = new ConcurrentDictionary<uint, Beatmap?>(); | ||
|
|
@@ -65,8 +71,16 @@ public static async Task<BeatmapStore> CreateAsync(MySqlConnection connection, M | |
| /// <returns>The difficulty attributes or <c>null</c> if not existing.</returns> | ||
| public async Task<DifficultyAttributes?> GetDifficultyAttributesAsync(Beatmap beatmap, Ruleset ruleset, Mod[] mods, MySqlConnection connection, MySqlTransaction? transaction = null) | ||
| { | ||
| if (use_realtime_difficulty_calculation) | ||
| // database attributes are stored using the default mod configurations | ||
| // if we want to support mods with non-default configurations (i.e non-1.5x rates on DT/NC) | ||
| // or non-legacy mods which aren't populated into the database (with exception to CL) | ||
| // then we must calculate difficulty attributes in real-time. | ||
| bool mustUseRealtimeDifficulty = mods.Any(m => !m.UsesDefaultConfiguration || (!isRankedLegacyMod(m) && m is not ModClassic)); | ||
|
|
||
| if (always_use_realtime_difficulty_calculation || mustUseRealtimeDifficulty) | ||
| { | ||
| var stopwatch = Stopwatch.StartNew(); | ||
|
|
||
| using var req = new WebRequest(string.Format(beatmap_download_path, beatmap.beatmap_id)); | ||
|
|
||
| req.AllowInsecureRequests = true; | ||
|
|
@@ -79,7 +93,17 @@ public static async Task<BeatmapStore> CreateAsync(MySqlConnection connection, M | |
| var workingBeatmap = new StreamedWorkingBeatmap(req.ResponseStream); | ||
| var calculator = ruleset.CreateDifficultyCalculator(workingBeatmap); | ||
|
|
||
| return calculator.Calculate(mods); | ||
| var attributes = calculator.Calculate(mods); | ||
|
|
||
| string[] tags = | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Have to make sure to turn off indexing on these as soon as it goes live or we'll rack up a $1000 bill in no time |
||
| { | ||
| $"ruleset:{ruleset.RulesetInfo.OnlineID}", | ||
| $"mods:{string.Join("", mods.Select(x => x.Acronym))}" | ||
| }; | ||
|
|
||
| DogStatsd.Timer("calculate-realtime-difficulty-attributes", stopwatch.ElapsedMilliseconds, tags: tags); | ||
|
|
||
| return attributes; | ||
| } | ||
|
|
||
| BeatmapDifficultyAttribute[]? rawDifficultyAttributes; | ||
|
|
@@ -107,12 +131,40 @@ public static async Task<BeatmapStore> CreateAsync(MySqlConnection connection, M | |
| return difficultyAttributes; | ||
| } | ||
|
|
||
| /// <remarks> | ||
| /// This method attempts to create a simple solution to deciding if a <see cref="Mod"/> can be considered a ranked "legacy" mod. | ||
| /// Used by <see cref="GetDifficultyAttributesAsync"/> to decide if the current mod combination's difficulty attributes | ||
| /// can be fetched from the database. | ||
| /// </remarks> | ||
| private static bool isRankedLegacyMod(Mod mod) => | ||
|
||
| mod is ModNoFail | ||
| or ModEasy | ||
| or ModHidden // this also catches ManiaModFadeIn | ||
tsunyoku marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| or ModPerfect | ||
| or ModSuddenDeath | ||
| or ModNightcore | ||
| or ModDoubleTime | ||
| or ModHalfTime | ||
| or ModFlashlight | ||
| or ModTouchDevice | ||
| or OsuModHardRock | ||
| or OsuModSpunOut | ||
| or TaikoModHardRock | ||
| or CatchModHardRock | ||
| or ManiaModKey4 | ||
| or ManiaModKey5 | ||
| or ManiaModKey6 | ||
| or ManiaModKey7 | ||
| or ManiaModKey8 | ||
| or ManiaModKey9 | ||
| or ManiaModMirror; | ||
|
|
||
| /// <remarks> | ||
| /// This method attempts to choose the best possible set of <see cref="LegacyMods"/> to use for looking up stored difficulty attributes. | ||
| /// The match is not always exact; for some mods that award pp but do not exist in stable | ||
| /// (such as <see cref="ModHalfTime"/>) the closest available approximation is used. | ||
| /// Moreover, the set of <see cref="LegacyMods"/> returned is constrained to mods that actually affect difficulty in the legacy sense. | ||
| /// The entirety of this workaround is not used / unnecessary if <see cref="use_realtime_difficulty_calculation"/> is <see langword="true"/>. | ||
| /// The entirety of this workaround is not used / unnecessary if <see cref="always_use_realtime_difficulty_calculation"/> is <see langword="true"/>. | ||
| /// </remarks> | ||
| private static LegacyMods getLegacyModsForAttributeLookup(Beatmap beatmap, Ruleset ruleset, Mod[] mods) | ||
| { | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.