public async Task <ScoreInfo[]> OrderByTotalScoreAsync(ScoreInfo[] scores, CancellationToken cancellationToken = default) { if (difficultyCache != null) { // Compute difficulties asynchronously first to prevent blocking via the GetTotalScore() call below. foreach (var s in scores) { await difficultyCache.GetDifficultyAsync(s.BeatmapInfo, s.Ruleset, s.Mods, cancellationToken).ConfigureAwait(false); cancellationToken.ThrowIfCancellationRequested(); } } long[] totalScores = await Task.WhenAll(scores.Select(s => GetTotalScoreAsync(s, cancellationToken: cancellationToken))).ConfigureAwait(false); return(scores.Select((score, index) => (score, totalScore: totalScores[index])) .OrderByDescending(g => g.totalScore) .ThenBy(g => g.score.OnlineID) .Select(g => g.score) .ToArray()); }
private void load(BeatmapDifficultyCache beatmapDifficultyCache) { var beatmap = score.Beatmap; var metadata = beatmap.BeatmapSet?.Metadata ?? beatmap.Metadata; var creator = metadata.Author?.Username; var topStatistics = new List <StatisticDisplay> { new AccuracyStatistic(score.Accuracy), new ComboStatistic(score.MaxCombo, !score.Statistics.TryGetValue(HitResult.Miss, out var missCount) || missCount == 0), new PerformanceStatistic(score), }; var bottomStatistics = new List <HitResultStatistic>(); foreach (var result in score.GetStatisticsForDisplay()) { bottomStatistics.Add(new HitResultStatistic(result)); } statisticDisplays.AddRange(topStatistics); statisticDisplays.AddRange(bottomStatistics); var starDifficulty = beatmapDifficultyCache.GetDifficultyAsync(beatmap, score.Ruleset, score.Mods).Result; InternalChildren = new Drawable[] { new FillFlowContainer { RelativeSizeAxes = Axes.Both, Direction = FillDirection.Vertical, Spacing = new Vector2(20), Children = new Drawable[] { new FillFlowContainer { Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, Direction = FillDirection.Vertical, Children = new Drawable[] { new OsuSpriteText { Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, Text = new LocalisedString((metadata.TitleUnicode, metadata.Title)), Font = OsuFont.Torus.With(size: 20, weight: FontWeight.SemiBold), MaxWidth = ScorePanel.EXPANDED_WIDTH - padding * 2, Truncate = true, },
private Task <PerformanceAttributes> getPerfectPerformance(ScoreInfo score, CancellationToken cancellationToken = default) { return(Task.Run(async() => { Ruleset ruleset = score.Ruleset.CreateInstance(); ScoreInfo perfectPlay = score.DeepClone(); perfectPlay.Accuracy = 1; perfectPlay.Passed = true; // calculate max combo // todo: Get max combo from difficulty calculator instead when diffcalc properly supports lazer-first scores perfectPlay.MaxCombo = calculateMaxCombo(playableBeatmap); // create statistics assuming all hit objects have perfect hit result var statistics = playableBeatmap.HitObjects .SelectMany(getPerfectHitResults) .GroupBy(hr => hr, (hr, list) => (hitResult: hr, count: list.Count())) .ToDictionary(pair => pair.hitResult, pair => pair.count); perfectPlay.Statistics = statistics; // calculate total score ScoreProcessor scoreProcessor = ruleset.CreateScoreProcessor(); scoreProcessor.HighestCombo.Value = perfectPlay.MaxCombo; scoreProcessor.Mods.Value = perfectPlay.Mods; perfectPlay.TotalScore = (long)scoreProcessor.GetImmediateScore(ScoringMode.Standardised, perfectPlay.MaxCombo, statistics); // compute rank achieved // default to SS, then adjust the rank with mods perfectPlay.Rank = ScoreRank.X; foreach (IApplicableToScoreProcessor mod in perfectPlay.Mods.OfType <IApplicableToScoreProcessor>()) { perfectPlay.Rank = mod.AdjustRank(perfectPlay.Rank, 1); } // calculate performance for this perfect score var difficulty = await difficultyCache.GetDifficultyAsync( playableBeatmap.BeatmapInfo, score.Ruleset, score.Mods, cancellationToken ).ConfigureAwait(false); // ScorePerformanceCache is not used to avoid caching multiple copies of essentially identical perfect performance attributes return difficulty == null ? null : ruleset.CreatePerformanceCalculator(difficulty.Value.Attributes, perfectPlay)?.Calculate(); }, cancellationToken)); }
private void load(BeatmapDifficultyCache beatmapDifficultyCache) { var beatmap = score.BeatmapInfo; var metadata = beatmap.BeatmapSet?.Metadata ?? beatmap.Metadata; string creator = metadata.Author.Username; var topStatistics = new List <StatisticDisplay> { new AccuracyStatistic(score.Accuracy), new ComboStatistic(score.MaxCombo, !score.Statistics.TryGetValue(HitResult.Miss, out int missCount) || missCount == 0), new PerformanceStatistic(score), }; var bottomStatistics = new List <HitResultStatistic>(); foreach (var result in score.GetStatisticsForDisplay()) { bottomStatistics.Add(new HitResultStatistic(result)); } statisticDisplays.AddRange(topStatistics); statisticDisplays.AddRange(bottomStatistics); var starDifficulty = beatmapDifficultyCache.GetDifficultyAsync(beatmap, score.Ruleset, score.Mods).GetResultSafely(); AddInternal(new FillFlowContainer { RelativeSizeAxes = Axes.Both, Direction = FillDirection.Vertical, Spacing = new Vector2(20), Children = new Drawable[] { new FillFlowContainer { Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, Direction = FillDirection.Vertical, Children = new Drawable[] { new OsuSpriteText { Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, Text = new RomanisableString(metadata.TitleUnicode, metadata.Title), Font = OsuFont.Torus.With(size: 20, weight: FontWeight.SemiBold), MaxWidth = ScorePanel.EXPANDED_WIDTH - padding * 2, Truncate = true, }, new OsuSpriteText { Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, Text = new RomanisableString(metadata.ArtistUnicode, metadata.Artist), Font = OsuFont.Torus.With(size: 14, weight: FontWeight.SemiBold), MaxWidth = ScorePanel.EXPANDED_WIDTH - padding * 2, Truncate = true, }, new Container { Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, Margin = new MarginPadding { Top = 40 }, RelativeSizeAxes = Axes.X, Height = 230, Child = new AccuracyCircle(score, withFlair) { Anchor = Anchor.Centre, Origin = Anchor.Centre, RelativeSizeAxes = Axes.Both, FillMode = FillMode.Fit, } }, scoreCounter = new TotalScoreCounter { Margin = new MarginPadding { Top = 0, Bottom = 5 }, Current = { Value = 0 }, Alpha = 0, AlwaysPresent = true }, starAndModDisplay = new FillFlowContainer { Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, AutoSizeAxes = Axes.Both, Spacing = new Vector2(5, 0), }, new FillFlowContainer { Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, Direction = FillDirection.Vertical, AutoSizeAxes = Axes.Both, Children = new Drawable[] { new OsuSpriteText { Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, Text = beatmap.DifficultyName, Font = OsuFont.Torus.With(size: 16, weight: FontWeight.SemiBold), }, new OsuTextFlowContainer(s => s.Font = OsuFont.Torus.With(size: 12)) { Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, AutoSizeAxes = Axes.Both, Direction = FillDirection.Horizontal, }.With(t => { if (!string.IsNullOrEmpty(creator)) { t.AddText("mapped by "); t.AddText(creator, s => s.Font = s.Font.With(weight: FontWeight.SemiBold)); } }) } }, } }, new FillFlowContainer { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, Direction = FillDirection.Vertical, Spacing = new Vector2(0, 5), Children = new Drawable[] { new GridContainer { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, Content = new[] { topStatistics.Cast <Drawable>().ToArray() }, RowDimensions = new[] { new Dimension(GridSizeMode.AutoSize), } }, new GridContainer { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, Content = new[] { bottomStatistics.Where(s => s.Result <= HitResult.Perfect).ToArray() }, RowDimensions = new[] { new Dimension(GridSizeMode.AutoSize), } }, new GridContainer { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, Content = new[] { bottomStatistics.Where(s => s.Result > HitResult.Perfect).ToArray() }, RowDimensions = new[] { new Dimension(GridSizeMode.AutoSize), } } } } } }); if (score.Date != default) { AddInternal(new PlayedOnText(score.Date)); } if (starDifficulty != null) { starAndModDisplay.Add(new StarRatingDisplay(starDifficulty.Value) { Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft }); } if (score.Mods.Any()) { starAndModDisplay.Add(new ModDisplay { Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, ExpansionMode = ExpansionMode.AlwaysExpanded, Scale = new Vector2(0.5f), Current = { Value = score.Mods } }); } }