// Copyright (c) ppy Pty Ltd . 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 { /// /// Represents a score shown on a gameplay leaderboard. /// The score is expected to update itself as gameplay progresses. /// public class GameplayLeaderboardScore { /// /// The user playing. /// public IUser User { get; } /// /// Whether the score is being tracked. /// Generally understood as true when this score is the score of the local user currently playing. /// public bool Tracked { get; } /// /// The current total of the score. /// public BindableLong TotalScore { get; } = new BindableLong(); /// /// The current accuracy of the score. /// public BindableDouble Accuracy { get; } = new BindableDouble(); /// /// The combo of the score to display. /// Can be either highest combo or current combo, depending on constructor parameters. /// public BindableInt Combo { get; } = new BindableInt(); /// /// Whether the user playing has quit. /// public BindableBool HasQuit { get; } = new BindableBool(); /// /// An optional value to guarantee stable ordering. /// Lower numbers will appear higher in cases of ties. /// public long TotalScoreTiebreaker { get; init; } /// /// A custom function which handles converting a score to a display score using a provided . /// /// /// If no function is provided, will be used verbatim. /// public Func GetDisplayScore { get; set; } /// /// The colour of the team that the user playing is on, if any. /// public Colour4? TeamColour { get; init; } /// /// 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). /// public int? InitialPosition { get; init; } /// /// The displayed rank of the score on the leaderboard. /// public Bindable Position { get; } = new Bindable(); /// /// The index of the score on the leaderboard. /// This differs from 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 . /// public Bindable 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; } /// /// Used for testing. /// internal GameplayLeaderboardScore(IUser user, bool tracked, Bindable displayScore) { User = user; Tracked = tracked; TotalScore.BindTarget = displayScore; GetDisplayScore = _ => displayScore.Value; } public enum ComboDisplayMode { Current, Highest, } } }