|
3 | 3 |
|
4 | 4 | using System;
|
5 | 5 | using System.Collections.Generic;
|
| 6 | +using System.Diagnostics; |
6 | 7 | using System.Linq;
|
7 | 8 | using System.Threading;
|
8 | 9 | using Newtonsoft.Json;
|
|
16 | 17 | using osu.Game.Online.API;
|
17 | 18 | using osu.Game.Online.API.Requests;
|
18 | 19 | using osu.Game.Online.API.Requests.Responses;
|
| 20 | +using osu.Game.Rulesets.Judgements; |
| 21 | +using osu.Game.Rulesets.Scoring; |
19 | 22 | using Realms;
|
20 | 23 |
|
21 | 24 | namespace osu.Game.Scoring
|
@@ -71,13 +74,77 @@ protected override void Populate(ScoreInfo model, ArchiveReader? archive, Realm
|
71 | 74 | if (model.BeatmapInfo == null) throw new ArgumentNullException(nameof(model.BeatmapInfo));
|
72 | 75 | if (model.Ruleset == null) throw new ArgumentNullException(nameof(model.Ruleset));
|
73 | 76 |
|
| 77 | + PopulateMaximumStatistics(model); |
| 78 | + |
74 | 79 | if (string.IsNullOrEmpty(model.StatisticsJson))
|
75 | 80 | model.StatisticsJson = JsonConvert.SerializeObject(model.Statistics);
|
76 | 81 |
|
77 | 82 | if (string.IsNullOrEmpty(model.MaximumStatisticsJson))
|
78 | 83 | model.MaximumStatisticsJson = JsonConvert.SerializeObject(model.MaximumStatistics);
|
79 | 84 | }
|
80 | 85 |
|
| 86 | + /// <summary> |
| 87 | + /// Populates the <see cref="ScoreInfo.MaximumStatistics"/> for a given <see cref="ScoreInfo"/>. |
| 88 | + /// </summary> |
| 89 | + /// <param name="score">The score to populate the statistics of.</param> |
| 90 | + public void PopulateMaximumStatistics(ScoreInfo score) |
| 91 | + { |
| 92 | + if (score.MaximumStatistics.Select(kvp => kvp.Value).Sum() > 0) |
| 93 | + return; |
| 94 | + |
| 95 | + var beatmap = score.BeatmapInfo.Detach(); |
| 96 | + var ruleset = score.Ruleset.Detach(); |
| 97 | + var rulesetInstance = ruleset.CreateInstance(); |
| 98 | + |
| 99 | + Debug.Assert(rulesetInstance != null); |
| 100 | + |
| 101 | + // Populate the maximum statistics. |
| 102 | + HitResult maxBasicResult = rulesetInstance.GetHitResults() |
| 103 | + .Select(h => h.result) |
| 104 | + .Where(h => h.IsBasic()) |
| 105 | + .OrderByDescending(Judgement.ToNumericResult).First(); |
| 106 | + |
| 107 | + foreach ((HitResult result, int count) in score.Statistics) |
| 108 | + { |
| 109 | + switch (result) |
| 110 | + { |
| 111 | + case HitResult.LargeTickHit: |
| 112 | + case HitResult.LargeTickMiss: |
| 113 | + score.MaximumStatistics[HitResult.LargeTickHit] = score.MaximumStatistics.GetValueOrDefault(HitResult.LargeTickHit) + count; |
| 114 | + break; |
| 115 | + |
| 116 | + case HitResult.SmallTickHit: |
| 117 | + case HitResult.SmallTickMiss: |
| 118 | + score.MaximumStatistics[HitResult.SmallTickHit] = score.MaximumStatistics.GetValueOrDefault(HitResult.SmallTickHit) + count; |
| 119 | + break; |
| 120 | + |
| 121 | + case HitResult.IgnoreHit: |
| 122 | + case HitResult.IgnoreMiss: |
| 123 | + case HitResult.SmallBonus: |
| 124 | + case HitResult.LargeBonus: |
| 125 | + break; |
| 126 | + |
| 127 | + default: |
| 128 | + score.MaximumStatistics[maxBasicResult] = score.MaximumStatistics.GetValueOrDefault(maxBasicResult) + count; |
| 129 | + break; |
| 130 | + } |
| 131 | + } |
| 132 | + |
| 133 | + if (!score.IsLegacyScore) |
| 134 | + return; |
| 135 | + |
| 136 | +#pragma warning disable CS0618 |
| 137 | + // In osu! and osu!mania, some judgements affect combo but aren't stored to scores. |
| 138 | + // A special hit result is used to pad out the combo value to match, based on the max combo from the difficulty attributes. |
| 139 | + var calculator = rulesetInstance.CreateDifficultyCalculator(beatmaps().GetWorkingBeatmap(beatmap)); |
| 140 | + var attributes = calculator.Calculate(score.Mods); |
| 141 | + |
| 142 | + int maxComboFromStatistics = score.MaximumStatistics.Where(kvp => kvp.Key.AffectsCombo()).Select(kvp => kvp.Value).DefaultIfEmpty(0).Sum(); |
| 143 | + if (attributes.MaxCombo > maxComboFromStatistics) |
| 144 | + score.MaximumStatistics[HitResult.LegacyComboIncrease] = attributes.MaxCombo - maxComboFromStatistics; |
| 145 | +#pragma warning restore CS0618 |
| 146 | + } |
| 147 | + |
81 | 148 | protected override void PostImport(ScoreInfo model, Realm realm, bool batchImport)
|
82 | 149 | {
|
83 | 150 | base.PostImport(model, realm, batchImport);
|
|
0 commit comments