// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. #nullable disable using System; using System.Threading; using System.Threading.Tasks; using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Game.Beatmaps; using osu.Game.Database; using osu.Game.Rulesets.Difficulty; namespace osu.Game.Scoring { /// <summary> /// A component which performs and acts as a central cache for performance calculations of locally databased scores. /// Currently not persisted between game sessions. /// </summary> public class ScorePerformanceCache : MemoryCachingComponent<ScorePerformanceCache.PerformanceCacheLookup, PerformanceAttributes> { [Resolved] private BeatmapDifficultyCache difficultyCache { get; set; } protected override bool CacheNullValues => false; /// <summary> /// Calculates performance for the given <see cref="ScoreInfo"/>. /// </summary> /// <param name="score">The score to do the calculation on. </param> /// <param name="token">An optional <see cref="CancellationToken"/> to cancel the operation.</param> public Task<PerformanceAttributes> CalculatePerformanceAsync([NotNull] ScoreInfo score, CancellationToken token = default) => GetAsync(new PerformanceCacheLookup(score), token); protected override async Task<PerformanceAttributes> ComputeValueAsync(PerformanceCacheLookup lookup, CancellationToken token = default) { var score = lookup.ScoreInfo; var attributes = await difficultyCache.GetDifficultyAsync(score.BeatmapInfo, score.Ruleset, score.Mods, token).ConfigureAwait(false); // Performance calculation requires the beatmap and ruleset to be locally available. If not, return a default value. if (attributes?.Attributes == null) return null; token.ThrowIfCancellationRequested(); return score.Ruleset.CreateInstance().CreatePerformanceCalculator()?.Calculate(score, attributes.Value.Attributes); } public readonly struct PerformanceCacheLookup { public readonly ScoreInfo ScoreInfo; public PerformanceCacheLookup(ScoreInfo info) { ScoreInfo = info; } public override int GetHashCode() { var hash = new HashCode(); hash.Add(ScoreInfo.Hash); hash.Add(ScoreInfo.ID); return hash.ToHashCode(); } } } }