Exemple #1
0
        /// <summary>
        ///     Creates and caches score containers for
        /// </summary>
        private void CacheMultiplayerScoreContainers()
        {
            if (MultiplayerScores == null)
            {
                return;
            }

            CachedScoreContainers = new Dictionary <ScoreboardUser, ResultScoreContainer>();

            var self = MultiplayerScores.Find(x => x.Type == ScoreboardUserType.Self);

            var view = (ResultScreenView)View;

            CachedScoreContainers.Add(self, view.ScoreContainer);

            foreach (var s in MultiplayerScores)
            {
                if (s.Type == ScoreboardUserType.Self)
                {
                    continue;
                }

                ScoreProcessor = s.Processor;
                CachedScoreContainers.Add(s, new ResultScoreContainer(this)
                {
                    Parent  = view.MainContainer,
                    Visible = s.Type == ScoreboardUserType.Self
                });
            }

            ScoreProcessor = self.Processor;
        }
 private void addCursor(MultiplayerScores scores)
 {
     scores.Cursor = new Cursor
     {
         Properties = new Dictionary <string, JToken>
         {
             { "total_score", JToken.FromObject(scores.Scores[^ 1].TotalScore) },
        /// <summary>
        /// Creates a <see cref="IndexPlaylistScoresRequest"/> with an optional score pivot.
        /// </summary>
        /// <remarks>Does not queue the request.</remarks>
        /// <param name="scoresCallback">The callback to perform with the resulting scores.</param>
        /// <param name="pivot">An optional score pivot to retrieve scores around. Can be null to retrieve scores from the highest score.</param>
        /// <returns>The indexing <see cref="APIRequest"/>.</returns>
        private APIRequest createIndexRequest(Action <IEnumerable <ScoreInfo> > scoresCallback, [CanBeNull] MultiplayerScores pivot = null)
        {
            var indexReq = pivot != null
                ? new IndexPlaylistScoresRequest(roomId, playlistItem.ID, pivot.Cursor, pivot.Params)
                : new IndexPlaylistScoresRequest(roomId, playlistItem.ID);

            indexReq.Success += r =>
            {
                if (pivot == lowerScores)
                {
                    lowerScores = r;
                    setPositions(r, pivot, 1);
                }
                else
                {
                    higherScores = r;
                    setPositions(r, pivot, -1);
                }

                performSuccessCallback(scoresCallback, r.Scores, r);
            };

            indexReq.Failure += _ => hideLoadingSpinners(pivot);

            return(indexReq);
        }
        private void hideLoadingSpinners([CanBeNull] MultiplayerScores pivot = null)
        {
            CentreSpinner.Hide();

            if (pivot == lowerScores)
            {
                RightSpinner.Hide();
            }
            else if (pivot == higherScores)
            {
                LeftSpinner.Hide();
            }
        }
Exemple #5
0
        protected override APIRequest FetchScores(Action <IEnumerable <ScoreInfo> > scoresCallback)
        {
            // This performs two requests:
            // 1. A request to show the user's score (and scores around).
            // 2. If that fails, a request to index the room starting from the highest score.

            var userScoreReq = new ShowPlaylistUserScoreRequest(roomId, playlistItem.ID, api.LocalUser.Value.Id);

            userScoreReq.Success += userScore =>
            {
                var allScores = new List <MultiplayerScore> {
                    userScore
                };

                // Other scores could have arrived between score submission and entering the results screen. Ensure the local player score position is up to date.
                if (Score != null)
                {
                    Score.Position = userScore.Position;
                    ScorePanelList.GetPanelForScore(Score).ScorePosition.Value = userScore.Position;
                }

                if (userScore.ScoresAround?.Higher != null)
                {
                    allScores.AddRange(userScore.ScoresAround.Higher.Scores);
                    higherScores = userScore.ScoresAround.Higher;

                    Debug.Assert(userScore.Position != null);
                    setPositions(higherScores, userScore.Position.Value, -1);
                }

                if (userScore.ScoresAround?.Lower != null)
                {
                    allScores.AddRange(userScore.ScoresAround.Lower.Scores);
                    lowerScores = userScore.ScoresAround.Lower;

                    Debug.Assert(userScore.Position != null);
                    setPositions(lowerScores, userScore.Position.Value, 1);
                }

                performSuccessCallback(scoresCallback, allScores);
            };

            // On failure, fallback to a normal index.
            userScoreReq.Failure += _ => api.Queue(createIndexRequest(scoresCallback));

            return(userScoreReq);
        }
Exemple #6
0
        /// <summary>
        ///     Changes discord rich presence to show results.
        /// </summary>
        private void ChangeDiscordPresence()
        {
            DiscordHelper.Presence.EndTimestamp = 0;

            // Don't change if we're loading in from a replay file.
            if (ResultsType == ResultScreenType.Replay || Gameplay.InReplayMode)
            {
                DiscordHelper.Presence.Details = "Idle";
                DiscordHelper.Presence.State   = "In the Menus";
                DiscordRpc.UpdatePresence(ref DiscordHelper.Presence);
                return;
            }

            var state = Gameplay.Failed ? "Fail" : "Pass";
            var score = $"{ScoreProcessor.Score / 1000}k";
            var acc   = $"{StringHelper.AccuracyToString(ScoreProcessor.Accuracy)}";
            var grade = Gameplay.Failed ? "F" : GradeHelper.GetGradeFromAccuracy(ScoreProcessor.Accuracy).ToString();
            var combo = $"{ScoreProcessor.MaxCombo}x";

            if (OnlineManager.CurrentGame == null)
            {
                DiscordHelper.Presence.State = $"{state}: {grade} {score} {acc} {combo}";
            }
            else
            {
                if (OnlineManager.CurrentGame.Ruleset == MultiplayerGameRuleset.Team)
                {
                    var redTeamAverage  = GetTeamAverage(MultiplayerTeam.Red);
                    var blueTeamAverage = GetTeamAverage(MultiplayerTeam.Blue);

                    DiscordHelper.Presence.State = $"Red: {redTeamAverage:0.00} vs. Blue: {blueTeamAverage:0.00}";
                }
                else
                {
                    DiscordHelper.Presence.State = $"{StringHelper.AddOrdinal(MultiplayerScores.First().Rank)} " +
                                                   $"Place: {MultiplayerScores.First().RatingProcessor.CalculateRating(ScoreProcessor):0.00} {acc} {grade}";
                }
            }

            DiscordRpc.UpdatePresence(ref DiscordHelper.Presence);
        }
Exemple #7
0
        /// <summary>
        ///     Gets the average rating of an individual team
        /// </summary>
        /// <param name="team"></param>
        /// <returns></returns>
        /// <exception cref="ArgumentOutOfRangeException"></exception>
        public double GetTeamAverage(MultiplayerTeam team)
        {
            List <ScoreboardUser> users;

            switch (team)
            {
            case MultiplayerTeam.Red:
                users = MultiplayerScores.FindAll(x => x.Scoreboard.Team == MultiplayerTeam.Red && !x.HasQuit);
                break;

            case MultiplayerTeam.Blue:
                users = MultiplayerScores.FindAll(x => x.Scoreboard.Team == MultiplayerTeam.Blue && !x.HasQuit);
                break;

            default:
                throw new ArgumentOutOfRangeException(nameof(team), team, null);
            }

            if (users.Count == 0)
            {
                return(0);
            }

            var sum = 0d;

            users.ForEach(x =>
            {
                var rating = x.RatingProcessor.CalculateRating(x.Processor);

                if (x.Processor.MultiplayerProcessor.IsEliminated || x.Processor.MultiplayerProcessor.IsRegeneratingHealth)
                {
                    rating = 0;
                }

                sum += rating;
            });

            return(sum / users.Count);
        }
        protected override APIRequest FetchNextPage(int direction, Action <IEnumerable <ScoreInfo> > scoresCallback)
        {
            Debug.Assert(direction == 1 || direction == -1);

            MultiplayerScores pivot = direction == -1 ? higherScores : lowerScores;

            if (pivot?.Cursor == null)
            {
                return(null);
            }

            if (pivot == higherScores)
            {
                LeftSpinner.Show();
            }
            else
            {
                RightSpinner.Show();
            }

            return(createIndexRequest(scoresCallback, pivot));
        }
 /// <summary>
 /// Applies positions to all <see cref="MultiplayerScore"/>s referenced to a given pivot.
 /// </summary>
 /// <param name="scores">The <see cref="MultiplayerScores"/> to set positions on.</param>
 /// <param name="pivot">The pivot.</param>
 /// <param name="increment">The amount to increment the pivot position by for each <see cref="MultiplayerScore"/> in <paramref name="scores"/>.</param>
 private void setPositions([NotNull] MultiplayerScores scores, [CanBeNull] MultiplayerScores pivot, int increment)
 => setPositions(scores, pivot?.Scores[^ 1].Position ?? 0, increment);
        /// <summary>
        /// Transforms returned <see cref="MultiplayerScores"/> into <see cref="ScoreInfo"/>s, ensure the <see cref="ScorePanelList"/> is put into a sane state, and invokes a given success callback.
        /// </summary>
        /// <param name="callback">The callback to invoke with the final <see cref="ScoreInfo"/>s.</param>
        /// <param name="scores">The <see cref="MultiplayerScore"/>s that were retrieved from <see cref="APIRequest"/>s.</param>
        /// <param name="pivot">An optional pivot around which the scores were retrieved.</param>
        private void performSuccessCallback([NotNull] Action <IEnumerable <ScoreInfo> > callback, [NotNull] List <MultiplayerScore> scores, [CanBeNull] MultiplayerScores pivot = null)
        {
            var scoreInfos = scores.Select(s => s.CreateScoreInfo(playlistItem)).ToArray();

            // Score panels calculate total score before displaying, which can take some time. In order to count that calculation as part of the loading spinner display duration,
            // calculate the total scores locally before invoking the success callback.
            scoreManager.OrderByTotalScoreAsync(scoreInfos).ContinueWith(_ => Schedule(() =>
            {
                // Select a score if we don't already have one selected.
                // Note: This is done before the callback so that the panel list centres on the selected score before panels are added (eliminating initial scroll).
                if (SelectedScore.Value == null)
                {
                    Schedule(() =>
                    {
                        // Prefer selecting the local user's score, or otherwise default to the first visible score.
                        SelectedScore.Value = scoreInfos.FirstOrDefault(s => s.User.Id == api.LocalUser.Value.Id) ?? scoreInfos.FirstOrDefault();
                    });
                }

                // Invoke callback to add the scores. Exclude the user's current score which was added previously.
                callback.Invoke(scoreInfos.Where(s => s.OnlineScoreID != Score?.OnlineScoreID));

                hideLoadingSpinners(pivot);
            }));
        }
        /// <summary>
        /// Transforms returned <see cref="MultiplayerScores"/> into <see cref="ScoreInfo"/>s, ensure the <see cref="ScorePanelList"/> is put into a sane state, and invokes a given success callback.
        /// </summary>
        /// <param name="callback">The callback to invoke with the final <see cref="ScoreInfo"/>s.</param>
        /// <param name="scores">The <see cref="MultiplayerScore"/>s that were retrieved from <see cref="APIRequest"/>s.</param>
        /// <param name="pivot">An optional pivot around which the scores were retrieved.</param>
        private void performSuccessCallback([NotNull] Action <IEnumerable <ScoreInfo> > callback, [NotNull] List <MultiplayerScore> scores, [CanBeNull] MultiplayerScores pivot = null)
        {
            var scoreInfos = new List <ScoreInfo>(scores.Select(s => s.CreateScoreInfo(playlistItem)));

            // Select a score if we don't already have one selected.
            // Note: This is done before the callback so that the panel list centres on the selected score before panels are added (eliminating initial scroll).
            if (SelectedScore.Value == null)
            {
                Schedule(() =>
                {
                    // Prefer selecting the local user's score, or otherwise default to the first visible score.
                    SelectedScore.Value = scoreInfos.FirstOrDefault(s => s.User.Id == api.LocalUser.Value.Id) ?? scoreInfos.FirstOrDefault();
                });
            }

            // Invoke callback to add the scores. Exclude the user's current score which was added previously.
            callback.Invoke(scoreInfos.Where(s => s.OnlineScoreID != Score?.OnlineScoreID));

            hideLoadingSpinners(pivot);
        }