Path: blob/master/osu.Game/Screens/Select/Leaderboards/GameplayLeaderboardScore.cs
4916 views
// Copyright (c) ppy Pty Ltd <[email protected]>. Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. using System; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Game.Online.Rooms; using osu.Game.Online.Spectator; using osu.Game.Rulesets.Scoring; using osu.Game.Scoring; using osu.Game.Scoring.Legacy; using osu.Game.Screens.Play; using osu.Game.Users; namespace osu.Game.Screens.Select.Leaderboards { /// <summary> /// Represents a score shown on a gameplay leaderboard. /// The score is expected to update itself as gameplay progresses. /// </summary> public class GameplayLeaderboardScore { /// <summary> /// The user playing. /// </summary> public IUser User { get; } /// <summary> /// Whether the score is being tracked. /// Generally understood as true when this score is the score of the local user currently playing. /// </summary> public bool Tracked { get; } /// <summary> /// The current total of the score. /// </summary> public BindableLong TotalScore { get; } = new BindableLong(); /// <summary> /// The current accuracy of the score. /// </summary> public BindableDouble Accuracy { get; } = new BindableDouble(); /// <summary> /// The combo of the score to display. /// Can be either highest combo or current combo, depending on constructor parameters. /// </summary> public BindableInt Combo { get; } = new BindableInt(); /// <summary> /// Whether the user playing has quit. /// </summary> public BindableBool HasQuit { get; } = new BindableBool(); /// <summary> /// An optional value to guarantee stable ordering. /// Lower numbers will appear higher in cases of <see cref="TotalScore"/> ties. /// </summary> public long TotalScoreTiebreaker { get; init; } /// <summary> /// A custom function which handles converting a score to a display score using a provided <see cref="ScoringMode"/>. /// </summary> /// <remarks> /// If no function is provided, <see cref="TotalScore"/> will be used verbatim. /// </remarks> public Func<ScoringMode, long> GetDisplayScore { get; set; } /// <summary> /// The colour of the team that the user playing is on, if any. /// </summary> public Colour4? TeamColour { get; init; } /// <summary> /// The initial position of the score on the leaderboard. /// Mostly used for cases like the local user's best score on the global leaderboard (which will not be contiguous with the other scores). /// </summary> public int? InitialPosition { get; init; } /// <summary> /// The displayed rank of the score on the leaderboard. /// </summary> public Bindable<int?> Position { get; } = new Bindable<int?>(); /// <summary> /// The index of the score on the leaderboard. /// This differs from <see cref="Position"/> in that it is required (must always be known) /// and that it doesn't represent the score's position on global leaderboards. /// It's a property completely local to and relative to all scores provided by the managing <see cref="IGameplayLeaderboardProvider"/>. /// </summary> public Bindable<long> DisplayOrder { get; } = new BindableLong(); public GameplayLeaderboardScore(GameplayState gameplayState, bool tracked, ComboDisplayMode comboMode) { User = gameplayState.Score.ScoreInfo.User; Tracked = tracked; var scoreProcessor = gameplayState.ScoreProcessor; TotalScore.BindTarget = scoreProcessor.TotalScore; Accuracy.BindTarget = scoreProcessor.Accuracy; Combo.BindTarget = comboMode == ComboDisplayMode.Current ? scoreProcessor.Combo : scoreProcessor.HighestCombo; GetDisplayScore = scoreProcessor.GetDisplayScore; } public GameplayLeaderboardScore(IUser user, SpectatorScoreProcessor scoreProcessor, bool tracked, ComboDisplayMode comboMode) { User = user; Tracked = tracked; TotalScore.BindTarget = scoreProcessor.TotalScore; Accuracy.BindTarget = scoreProcessor.Accuracy; Combo.BindTarget = comboMode == ComboDisplayMode.Current ? scoreProcessor.Combo : scoreProcessor.HighestCombo; GetDisplayScore = scoreProcessor.GetDisplayScore; } public GameplayLeaderboardScore(ScoreInfo scoreInfo, bool tracked, ComboDisplayMode comboMode) { User = scoreInfo.User; Tracked = tracked; TotalScore.Value = scoreInfo.TotalScore; Accuracy.Value = scoreInfo.Accuracy; Combo.Value = comboMode == ComboDisplayMode.Current ? scoreInfo.Combo : scoreInfo.MaxCombo; TotalScoreTiebreaker = scoreInfo.OnlineID > 0 ? scoreInfo.OnlineID : scoreInfo.Date.ToUnixTimeSeconds(); GetDisplayScore = scoreInfo.GetDisplayScore; InitialPosition = scoreInfo.Position; } public GameplayLeaderboardScore(MultiplayerScore score, bool tracked, ComboDisplayMode comboMode) { User = score.User; Tracked = tracked; TotalScore.Value = score.TotalScore; Accuracy.Value = score.Accuracy; Combo.Value = comboMode == ComboDisplayMode.Highest ? score.MaxCombo : throw new NotSupportedException($"{comboMode} {nameof(comboMode)} is not supported."); TotalScoreTiebreaker = score.ID; GetDisplayScore = score.GetDisplayScore; InitialPosition = score.Position; } /// <remarks> /// Used for testing. /// </remarks> internal GameplayLeaderboardScore(IUser user, bool tracked, Bindable<long> displayScore) { User = user; Tracked = tracked; TotalScore.BindTarget = displayScore; GetDisplayScore = _ => displayScore.Value; } public enum ComboDisplayMode { Current, Highest, } } }