public new static int ToNumericResult(HitResult result) { switch (result) { // Override Ok and Meh case HitResult.Meh: return(100); case HitResult.Ok: return(200); default: return(Judgement.ToNumericResult(result)); } }
private static void applyResult(HitResult result, ref ScoringValues scoringValues) { if (!result.IsScorable()) { return; } if (result.IsBonus()) { scoringValues.BonusScore += result.IsHit() ? Judgement.ToNumericResult(result) : 0; } else { scoringValues.BaseScore += result.IsHit() ? Judgement.ToNumericResult(result) : 0; } if (result.IsBasic()) { scoringValues.CountBasicHitObjects++; } }
private void onScoringModeChanged(ValueChangedEvent <ScoringMode> mode) { difficultyCancellationSource?.Cancel(); difficultyCancellationSource = null; if (score.Beatmap == null) { Value = score.TotalScore; return; } int beatmapMaxCombo; double accuracy = score.Accuracy; if (score.IsLegacyScore) { if (score.RulesetID == 3) { // In osu!stable, a full-GREAT score has 100% accuracy in mania. Along with a full combo, the score becomes indistinguishable from a full-PERFECT score. // To get around this, recalculate accuracy based on the hit statistics. // Note: This cannot be applied universally to all legacy scores, as some rulesets (e.g. catch) group multiple judgements together. double maxBaseScore = score.Statistics.Select(kvp => kvp.Value).Sum() * Judgement.ToNumericResult(HitResult.Perfect); double baseScore = score.Statistics.Select(kvp => Judgement.ToNumericResult(kvp.Key) * kvp.Value).Sum(); if (maxBaseScore > 0) { accuracy = baseScore / maxBaseScore; } } // This score is guaranteed to be an osu!stable score. // The combo must be determined through either the beatmap's max combo value or the difficulty calculator, as lazer's scoring has changed and the score statistics cannot be used. if (score.Beatmap.MaxCombo == null) { if (score.Beatmap.ID == 0 || difficulties == null) { // We don't have enough information (max combo) to compute the score, so use the provided score. Value = score.TotalScore; return; } // We can compute the max combo locally after the async beatmap difficulty computation. difficultyBindable = difficulties().GetBindableDifficulty(score.Beatmap, score.Ruleset, score.Mods, (difficultyCancellationSource = new CancellationTokenSource()).Token); difficultyBindable.BindValueChanged(d => { if (d.NewValue is StarDifficulty diff) { updateScore(diff.MaxCombo, accuracy); } }, true); return; } beatmapMaxCombo = score.Beatmap.MaxCombo.Value; } else { // This score is guaranteed to be an osu!lazer score. // The combo must be determined through the score's statistics, as both the beatmap's max combo and the difficulty calculator will provide osu!stable combo values. beatmapMaxCombo = Enum.GetValues(typeof(HitResult)).OfType <HitResult>().Where(r => r.AffectsCombo()).Select(r => score.Statistics.GetOrDefault(r)).Sum(); } updateScore(beatmapMaxCombo, accuracy); }
/// <summary> /// Retrieves the total score of a <see cref="ScoreInfo"/> in the given <see cref="ScoringMode"/>. /// </summary> /// <param name="score">The <see cref="ScoreInfo"/> to calculate the total score of.</param> /// <param name="mode">The <see cref="ScoringMode"/> to return the total score as.</param> /// <param name="cancellationToken">A <see cref="CancellationToken"/> to cancel the process.</param> /// <returns>The total score.</returns> public async Task <long> GetTotalScoreAsync([NotNull] ScoreInfo score, ScoringMode mode = ScoringMode.Standardised, CancellationToken cancellationToken = default) { // TODO: This is required for playlist aggregate scores. They should likely not be getting here in the first place. if (string.IsNullOrEmpty(score.BeatmapInfo.Hash)) { return(score.TotalScore); } int beatmapMaxCombo; double accuracy = score.Accuracy; if (score.IsLegacyScore) { if (score.RulesetID == 3) { // In osu!stable, a full-GREAT score has 100% accuracy in mania. Along with a full combo, the score becomes indistinguishable from a full-PERFECT score. // To get around this, recalculate accuracy based on the hit statistics. // Note: This cannot be applied universally to all legacy scores, as some rulesets (e.g. catch) group multiple judgements together. double maxBaseScore = score.Statistics.Select(kvp => kvp.Value).Sum() * Judgement.ToNumericResult(HitResult.Perfect); double baseScore = score.Statistics.Select(kvp => Judgement.ToNumericResult(kvp.Key) * kvp.Value).Sum(); if (maxBaseScore > 0) { accuracy = baseScore / maxBaseScore; } } // This score is guaranteed to be an osu!stable score. // The combo must be determined through either the beatmap's max combo value or the difficulty calculator, as lazer's scoring has changed and the score statistics cannot be used. if (score.BeatmapInfo.MaxCombo != null) { beatmapMaxCombo = score.BeatmapInfo.MaxCombo.Value; } else { if (difficulties == null) { return(score.TotalScore); } // We can compute the max combo locally after the async beatmap difficulty computation. var difficulty = await difficulties().GetDifficultyAsync(score.BeatmapInfo, score.Ruleset, score.Mods, cancellationToken).ConfigureAwait(false); // Something failed during difficulty calculation. Fall back to provided score. if (difficulty == null) { return(score.TotalScore); } beatmapMaxCombo = difficulty.Value.MaxCombo; } } else { // This is guaranteed to be a non-legacy score. // The combo must be determined through the score's statistics, as both the beatmap's max combo and the difficulty calculator will provide osu!stable combo values. beatmapMaxCombo = Enum.GetValues(typeof(HitResult)).OfType <HitResult>().Where(r => r.AffectsCombo()).Select(r => score.Statistics.GetValueOrDefault(r)).Sum(); } if (beatmapMaxCombo == 0) { return(0); } var ruleset = score.Ruleset.CreateInstance(); var scoreProcessor = ruleset.CreateScoreProcessor(); scoreProcessor.Mods.Value = score.Mods; return((long)Math.Round(scoreProcessor.GetScore(mode, accuracy, (double)score.MaxCombo / beatmapMaxCombo, score.Statistics))); }