2020-05-28 20:08:45 +09:00
// 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.
using System ;
using System.Collections.Generic ;
2020-07-31 21:39:50 +09:00
using System.Linq ;
using System.Net ;
using Newtonsoft.Json.Linq ;
2020-05-28 20:08:45 +09:00
using NUnit.Framework ;
2025-02-26 18:31:06 +09:00
using osu.Framework.Allocation ;
2024-11-27 00:55:02 -05:00
using osu.Framework.Graphics ;
2020-07-31 21:39:50 +09:00
using osu.Framework.Graphics.Containers ;
using osu.Framework.Testing ;
2025-02-26 18:31:06 +09:00
using osu.Framework.Utils ;
using osu.Game.Database ;
2020-07-31 21:39:50 +09:00
using osu.Game.Graphics.Containers ;
using osu.Game.Graphics.UserInterface ;
2020-05-28 20:08:45 +09:00
using osu.Game.Online.API ;
2020-07-31 21:39:50 +09:00
using osu.Game.Online.API.Requests ;
2021-11-04 18:02:44 +09:00
using osu.Game.Online.API.Requests.Responses ;
2024-01-15 18:47:46 +01:00
using osu.Game.Online.Placeholders ;
2020-12-25 13:38:11 +09:00
using osu.Game.Online.Rooms ;
2020-05-28 20:08:45 +09:00
using osu.Game.Rulesets.Osu ;
using osu.Game.Rulesets.Scoring ;
using osu.Game.Scoring ;
2020-12-25 16:50:00 +01:00
using osu.Game.Screens.OnlinePlay.Playlists ;
2020-07-31 21:39:50 +09:00
using osu.Game.Screens.Ranking ;
2020-05-28 20:08:45 +09:00
using osu.Game.Tests.Beatmaps ;
2021-12-13 16:34:48 +09:00
using osu.Game.Tests.Resources ;
2020-05-28 20:08:45 +09:00
2020-12-25 13:20:37 +09:00
namespace osu.Game.Tests.Visual.Playlists
2020-05-28 20:08:45 +09:00
{
2020-12-25 13:11:21 +09:00
public partial class TestScenePlaylistsResultsScreen : ScreenTestScene
2020-05-28 20:08:45 +09:00
{
2020-07-31 21:39:50 +09:00
private const int scores_per_result = 10 ;
2021-12-13 06:54:57 +09:00
private const int real_user_position = 200 ;
2020-07-31 21:39:50 +09:00
2025-02-26 18:31:06 +09:00
[Cached]
private readonly BeatmapLookupCache beatmapLookupCache = new BeatmapLookupCache ( ) ;
2024-11-27 00:55:02 -05:00
private ResultsScreen resultsScreen = null ! ;
2021-12-10 15:28:41 +09:00
2022-03-08 20:11:56 +09:00
private int lowestScoreId ; // Score ID of the lowest score in the list.
private int highestScoreId ; // Score ID of the highest score in the list.
2020-07-31 21:39:50 +09:00
private bool requestComplete ;
2021-10-08 15:18:01 +09:00
private int totalCount ;
2024-11-21 20:26:44 +09:00
private ScoreInfo userScore = null ! ;
2020-06-09 18:53:55 +09:00
2025-02-26 18:31:06 +09:00
public TestScenePlaylistsResultsScreen ( )
{
Add ( beatmapLookupCache ) ;
}
2024-01-09 21:34:40 +09:00
[SetUpSteps]
public override void SetUpSteps ( )
2022-03-15 20:38:04 +00:00
{
base . SetUpSteps ( ) ;
2022-03-15 22:15:35 +00:00
// Previous test instances of the results screen may still exist at this point so wait for
// those screens to be cleaned up by the base SetUpSteps before re-initialising test state.
2023-12-31 22:10:49 +09:00
// The screen also holds a leased Beatmap bindable so reassigning it must happen after
// the screen has been exited.
2022-03-15 22:15:35 +00:00
AddStep ( "initialise user scores and beatmap" , ( ) = >
2022-03-15 20:38:04 +00:00
{
2022-03-15 22:15:35 +00:00
lowestScoreId = 1 ;
highestScoreId = 1 ;
requestComplete = false ;
totalCount = 0 ;
userScore = TestResources . CreateTestScoreInfo ( ) ;
2025-03-03 12:23:52 +01:00
userScore . OnlineID = 1 ;
2022-03-15 22:15:35 +00:00
userScore . TotalScore = 0 ;
userScore . Statistics = new Dictionary < HitResult , int > ( ) ;
2022-08-30 15:42:33 +09:00
userScore . MaximumStatistics = new Dictionary < HitResult , int > ( ) ;
2025-03-03 12:23:52 +01:00
userScore . Position = real_user_position ;
2022-03-15 22:15:35 +00:00
// Beatmap is required to be an actual beatmap so the scores can get their scores correctly
// calculated for standardised scoring, else the tests that rely on ordering will fall over.
2022-03-15 20:38:04 +00:00
Beatmap . Value = CreateWorkingBeatmap ( Ruleset . Value ) ;
} ) ;
}
2020-05-28 20:08:45 +09:00
[Test]
2024-11-27 00:55:02 -05:00
public void TestShowUserScore ( )
2020-05-28 22:25:00 +09:00
{
2022-03-08 20:11:56 +09:00
AddStep ( "bind user score info handler" , ( ) = > bindHandler ( userScore : userScore ) ) ;
2020-07-31 21:39:50 +09:00
2024-11-27 00:55:02 -05:00
createResultsWithScore ( ( ) = > userScore ) ;
2024-01-09 21:28:46 +09:00
waitForDisplay ( ) ;
2020-07-31 21:39:50 +09:00
2021-12-10 15:37:12 +09:00
AddAssert ( "user score selected" , ( ) = > this . ChildrenOfType < ScorePanel > ( ) . Single ( p = > p . Score . OnlineID = = userScore . OnlineID ) . State = = PanelState . Expanded ) ;
2021-12-13 06:54:57 +09:00
AddAssert ( $"score panel position is {real_user_position}" ,
( ) = > this . ChildrenOfType < ScorePanel > ( ) . Single ( p = > p . Score . OnlineID = = userScore . OnlineID ) . ScorePosition . Value = = real_user_position ) ;
2020-05-28 22:25:00 +09:00
}
[Test]
2024-11-27 00:55:02 -05:00
public void TestShowUserBest ( )
{
AddStep ( "bind user score info handler" , ( ) = > bindHandler ( userScore : userScore ) ) ;
createUserBestResults ( ) ;
waitForDisplay ( ) ;
AddAssert ( "user score selected" , ( ) = > this . ChildrenOfType < ScorePanel > ( ) . Single ( p = > p . Score . UserID = = userScore . UserID ) . State = = PanelState . Expanded ) ;
AddAssert ( $"score panel position is {real_user_position}" ,
( ) = > this . ChildrenOfType < ScorePanel > ( ) . Single ( p = > p . Score . UserID = = userScore . UserID ) . ScorePosition . Value = = real_user_position ) ;
}
[Test]
public void TestShowNonUserScores ( )
2020-05-28 22:25:00 +09:00
{
2024-01-09 21:44:05 +09:00
AddStep ( "bind user score info handler" , ( ) = > bindHandler ( ) ) ;
2023-12-31 22:10:49 +09:00
2024-11-27 00:55:02 -05:00
createUserBestResults ( ) ;
2024-01-09 21:28:46 +09:00
waitForDisplay ( ) ;
2020-07-31 21:39:50 +09:00
AddAssert ( "top score selected" , ( ) = > this . ChildrenOfType < ScorePanel > ( ) . OrderByDescending ( p = > p . Score . TotalScore ) . First ( ) . State = = PanelState . Expanded ) ;
2020-06-09 18:53:55 +09:00
}
[Test]
2020-07-31 21:39:50 +09:00
public void TestShowUserScoreWithDelay ( )
{
2022-03-08 20:11:56 +09:00
AddStep ( "bind user score info handler" , ( ) = > bindHandler ( true , userScore ) ) ;
2020-07-31 21:39:50 +09:00
2024-11-27 00:55:02 -05:00
createResultsWithScore ( ( ) = > userScore ) ;
2024-01-09 21:28:46 +09:00
waitForDisplay ( ) ;
2020-07-31 21:39:50 +09:00
AddAssert ( "more than 1 panel displayed" , ( ) = > this . ChildrenOfType < ScorePanel > ( ) . Count ( ) > 1 ) ;
2021-12-10 15:37:12 +09:00
AddAssert ( "user score selected" , ( ) = > this . ChildrenOfType < ScorePanel > ( ) . Single ( p = > p . Score . OnlineID = = userScore . OnlineID ) . State = = PanelState . Expanded ) ;
2020-07-31 21:39:50 +09:00
}
[Test]
2024-11-27 00:55:02 -05:00
public void TestShowNonUserScoresWithDelay ( )
2020-06-09 18:53:55 +09:00
{
2021-02-22 15:43:58 +09:00
AddStep ( "bind delayed handler" , ( ) = > bindHandler ( true ) ) ;
2020-07-31 21:39:50 +09:00
2024-11-27 00:55:02 -05:00
createUserBestResults ( ) ;
2024-01-09 21:28:46 +09:00
waitForDisplay ( ) ;
2020-07-31 21:39:50 +09:00
AddAssert ( "top score selected" , ( ) = > this . ChildrenOfType < ScorePanel > ( ) . OrderByDescending ( p = > p . Score . TotalScore ) . First ( ) . State = = PanelState . Expanded ) ;
2020-05-28 22:25:00 +09:00
}
2020-07-31 21:39:50 +09:00
[Test]
public void TestFetchWhenScrolledToTheRight ( )
{
2024-01-09 21:44:05 +09:00
AddStep ( "bind delayed handler" , ( ) = > bindHandler ( true ) ) ;
2023-12-31 22:10:49 +09:00
2024-11-27 00:55:02 -05:00
createUserBestResults ( ) ;
2024-01-09 21:28:46 +09:00
waitForDisplay ( ) ;
2020-07-31 21:39:50 +09:00
for ( int i = 0 ; i < 2 ; i + + )
{
int beforePanelCount = 0 ;
AddStep ( "get panel count" , ( ) = > beforePanelCount = this . ChildrenOfType < ScorePanel > ( ) . Count ( ) ) ;
2024-11-27 00:55:02 -05:00
AddStep ( "scroll to right" , ( ) = > resultsScreen . ChildrenOfType < ScorePanelList > ( ) . Single ( ) . ChildrenOfType < OsuScrollContainer > ( ) . Single ( ) . ScrollToEnd ( false ) ) ;
2025-03-06 12:55:59 +09:00
AddUntilStep ( "right loading spinner shown" , ( ) = >
2024-11-27 00:55:02 -05:00
resultsScreen . ChildrenOfType < LoadingSpinner > ( ) . Single ( l = > l . Anchor = = Anchor . CentreRight ) . State . Value = = Visibility . Visible ) ;
2020-07-31 21:39:50 +09:00
waitForDisplay ( ) ;
2024-07-25 08:38:20 +03:00
AddAssert ( $"count increased by {scores_per_result}" , ( ) = > this . ChildrenOfType < ScorePanel > ( ) . Count ( ) = = beforePanelCount + scores_per_result ) ;
2025-03-06 12:55:59 +09:00
AddUntilStep ( "right loading spinner hidden" , ( ) = >
2024-11-27 00:55:02 -05:00
resultsScreen . ChildrenOfType < LoadingSpinner > ( ) . Single ( l = > l . Anchor = = Anchor . CentreRight ) . State . Value = = Visibility . Hidden ) ;
2020-07-31 21:39:50 +09:00
}
}
2024-01-15 18:47:46 +01:00
[Test]
public void TestNoMoreScoresToTheRight ( )
{
AddStep ( "bind delayed handler with scores" , ( ) = > bindHandler ( delayed : true ) ) ;
2024-11-27 00:55:02 -05:00
createUserBestResults ( ) ;
2024-01-15 18:47:46 +01:00
waitForDisplay ( ) ;
int beforePanelCount = 0 ;
AddStep ( "get panel count" , ( ) = > beforePanelCount = this . ChildrenOfType < ScorePanel > ( ) . Count ( ) ) ;
2024-11-27 00:55:02 -05:00
AddStep ( "scroll to right" , ( ) = > resultsScreen . ChildrenOfType < ScorePanelList > ( ) . Single ( ) . ChildrenOfType < OsuScrollContainer > ( ) . Single ( ) . ScrollToEnd ( false ) ) ;
2025-03-06 12:55:59 +09:00
AddUntilStep ( "right loading spinner shown" , ( ) = >
2024-11-27 00:55:02 -05:00
resultsScreen . ChildrenOfType < LoadingSpinner > ( ) . Single ( l = > l . Anchor = = Anchor . CentreRight ) . State . Value = = Visibility . Visible ) ;
2024-01-15 18:47:46 +01:00
waitForDisplay ( ) ;
2024-07-25 08:38:20 +03:00
AddAssert ( $"count increased by {scores_per_result}" , ( ) = > this . ChildrenOfType < ScorePanel > ( ) . Count ( ) = = beforePanelCount + scores_per_result ) ;
2025-03-06 12:55:59 +09:00
AddUntilStep ( "right loading spinner hidden" , ( ) = >
2024-11-27 00:55:02 -05:00
resultsScreen . ChildrenOfType < LoadingSpinner > ( ) . Single ( l = > l . Anchor = = Anchor . CentreRight ) . State . Value = = Visibility . Hidden ) ;
2024-01-15 18:47:46 +01:00
AddStep ( "get panel count" , ( ) = > beforePanelCount = this . ChildrenOfType < ScorePanel > ( ) . Count ( ) ) ;
AddStep ( "bind delayed handler with no scores" , ( ) = > bindHandler ( delayed : true , noScores : true ) ) ;
2024-11-27 00:55:02 -05:00
AddStep ( "scroll to right" , ( ) = > resultsScreen . ChildrenOfType < ScorePanelList > ( ) . Single ( ) . ChildrenOfType < OsuScrollContainer > ( ) . Single ( ) . ScrollToEnd ( false ) ) ;
2025-03-06 12:55:59 +09:00
AddUntilStep ( "right loading spinner shown" , ( ) = >
2024-11-27 00:55:02 -05:00
resultsScreen . ChildrenOfType < LoadingSpinner > ( ) . Single ( l = > l . Anchor = = Anchor . CentreRight ) . State . Value = = Visibility . Visible ) ;
2024-01-15 18:47:46 +01:00
waitForDisplay ( ) ;
AddAssert ( "count not increased" , ( ) = > this . ChildrenOfType < ScorePanel > ( ) . Count ( ) = = beforePanelCount ) ;
2025-03-06 12:55:59 +09:00
AddUntilStep ( "right loading spinner hidden" , ( ) = >
2024-11-27 00:55:02 -05:00
resultsScreen . ChildrenOfType < LoadingSpinner > ( ) . Single ( l = > l . Anchor = = Anchor . CentreRight ) . State . Value = = Visibility . Hidden ) ;
2024-01-15 18:47:46 +01:00
AddAssert ( "no placeholders shown" , ( ) = > this . ChildrenOfType < MessagePlaceholder > ( ) . Count ( ) , ( ) = > Is . Zero ) ;
}
2020-07-31 21:39:50 +09:00
[Test]
public void TestFetchWhenScrolledToTheLeft ( )
{
2022-03-08 20:11:56 +09:00
AddStep ( "bind user score info handler" , ( ) = > bindHandler ( userScore : userScore ) ) ;
2020-07-31 21:39:50 +09:00
2024-11-27 00:55:02 -05:00
createResultsWithScore ( ( ) = > userScore ) ;
2024-01-09 21:28:46 +09:00
waitForDisplay ( ) ;
2020-07-31 21:39:50 +09:00
2021-02-22 15:43:58 +09:00
AddStep ( "bind delayed handler" , ( ) = > bindHandler ( true ) ) ;
2020-07-31 21:39:50 +09:00
for ( int i = 0 ; i < 2 ; i + + )
{
int beforePanelCount = 0 ;
AddStep ( "get panel count" , ( ) = > beforePanelCount = this . ChildrenOfType < ScorePanel > ( ) . Count ( ) ) ;
2024-11-27 00:55:02 -05:00
AddStep ( "scroll to left" , ( ) = > resultsScreen . ChildrenOfType < ScorePanelList > ( ) . Single ( ) . ChildrenOfType < OsuScrollContainer > ( ) . Single ( ) . ScrollToStart ( false ) ) ;
2025-03-06 12:55:59 +09:00
AddUntilStep ( "left loading spinner shown" , ( ) = >
2024-11-27 00:55:02 -05:00
resultsScreen . ChildrenOfType < LoadingSpinner > ( ) . Single ( l = > l . Anchor = = Anchor . CentreLeft ) . State . Value = = Visibility . Visible ) ;
2020-07-31 21:39:50 +09:00
waitForDisplay ( ) ;
2024-07-25 08:38:20 +03:00
AddAssert ( $"count increased by {scores_per_result}" , ( ) = > this . ChildrenOfType < ScorePanel > ( ) . Count ( ) = = beforePanelCount + scores_per_result ) ;
2025-03-06 12:55:59 +09:00
AddUntilStep ( "left loading spinner hidden" , ( ) = >
2024-11-27 00:55:02 -05:00
resultsScreen . ChildrenOfType < LoadingSpinner > ( ) . Single ( l = > l . Anchor = = Anchor . CentreLeft ) . State . Value = = Visibility . Hidden ) ;
2020-07-31 21:39:50 +09:00
}
}
2024-11-27 00:55:02 -05:00
/// <summary>
/// Shows the <see cref="TestUserBestResultsScreen"/> with no scores provided by the API.
/// </summary>
2023-12-31 22:10:49 +09:00
[Test]
2024-11-27 00:55:02 -05:00
public void TestShowUserBestWithNoScoresPresent ( )
2023-12-31 22:10:49 +09:00
{
2024-01-09 21:44:05 +09:00
AddStep ( "bind user score info handler" , ( ) = > bindHandler ( noScores : true ) ) ;
2024-11-27 00:55:02 -05:00
createUserBestResults ( ) ;
AddAssert ( "no scores visible" , ( ) = > ! resultsScreen . ChildrenOfType < ScorePanelList > ( ) . Single ( ) . GetScorePanels ( ) . Any ( ) ) ;
2025-03-06 12:55:59 +09:00
AddUntilStep ( "placeholder shown" , ( ) = > this . ChildrenOfType < MessagePlaceholder > ( ) . Count ( ) , ( ) = > Is . EqualTo ( 1 ) ) ;
2023-12-31 22:10:49 +09:00
}
2025-03-03 12:23:52 +01:00
[Test]
public void TestFetchingAllTheWayToFirstNeverDisplaysNegativePosition ( )
{
AddStep ( "set user position" , ( ) = > userScore . Position = 20 ) ;
AddStep ( "bind user score info handler" , ( ) = > bindHandler ( userScore : userScore ) ) ;
createResultsWithScore ( ( ) = > userScore ) ;
waitForDisplay ( ) ;
AddStep ( "bind delayed handler" , ( ) = > bindHandler ( true ) ) ;
for ( int i = 0 ; i < 2 ; i + + )
{
AddStep ( "simulate user falling down ranking" , ( ) = > userScore . Position + = 2 ) ;
AddStep ( "scroll to left" , ( ) = > resultsScreen . ChildrenOfType < ScorePanelList > ( ) . Single ( ) . ChildrenOfType < OsuScrollContainer > ( ) . Single ( ) . ScrollToStart ( false ) ) ;
2025-03-06 12:55:59 +09:00
AddUntilStep ( "left loading spinner shown" , ( ) = >
2025-03-03 12:23:52 +01:00
resultsScreen . ChildrenOfType < LoadingSpinner > ( ) . Single ( l = > l . Anchor = = Anchor . CentreLeft ) . State . Value = = Visibility . Visible ) ;
waitForDisplay ( ) ;
2025-03-06 12:55:59 +09:00
AddUntilStep ( "left loading spinner hidden" , ( ) = >
2025-03-03 12:23:52 +01:00
resultsScreen . ChildrenOfType < LoadingSpinner > ( ) . Single ( l = > l . Anchor = = Anchor . CentreLeft ) . State . Value = = Visibility . Hidden ) ;
}
AddAssert ( "total count is 34" , ( ) = > this . ChildrenOfType < ScorePanel > ( ) . Count ( ) , ( ) = > Is . EqualTo ( 34 ) ) ;
AddUntilStep ( "all panels have non-negative position" , ( ) = > this . ChildrenOfType < ScorePanel > ( ) . All ( p = > p . ScorePosition . Value > 0 ) ) ;
}
2024-11-27 00:55:02 -05:00
private void createResultsWithScore ( Func < ScoreInfo > getScore )
2020-06-09 18:53:55 +09:00
{
AddStep ( "load results" , ( ) = >
{
2024-11-27 00:55:02 -05:00
LoadScreen ( resultsScreen = new TestScoreResultsScreen ( getScore ( ) , 1 , new PlaylistItem ( new TestBeatmap ( new OsuRuleset ( ) . RulesetInfo ) . BeatmapInfo )
2020-06-09 18:53:55 +09:00
{
2022-02-15 16:01:14 +09:00
RulesetID = new OsuRuleset ( ) . RulesetInfo . OnlineID
2020-06-09 18:53:55 +09:00
} ) ) ;
} ) ;
2021-09-06 20:20:52 +09:00
2021-12-20 16:58:16 +09:00
AddUntilStep ( "wait for screen to load" , ( ) = > resultsScreen . IsLoaded ) ;
2020-06-09 18:53:55 +09:00
}
2024-11-27 00:55:02 -05:00
private void createUserBestResults ( )
{
AddStep ( "load results" , ( ) = >
{
LoadScreen ( resultsScreen = new TestUserBestResultsScreen ( 1 , new PlaylistItem ( new TestBeatmap ( new OsuRuleset ( ) . RulesetInfo ) . BeatmapInfo )
{
RulesetID = new OsuRuleset ( ) . RulesetInfo . OnlineID
} , 2 ) ) ;
} ) ;
AddUntilStep ( "wait for screen to load" , ( ) = > resultsScreen . IsLoaded ) ;
}
2024-01-09 21:28:46 +09:00
private void waitForDisplay ( )
2020-05-28 20:08:45 +09:00
{
2021-12-20 16:58:16 +09:00
AddUntilStep ( "wait for scores loaded" , ( ) = >
2021-10-08 15:18:01 +09:00
requestComplete
2022-05-30 19:29:13 +09:00
// request handler may need to fire more than once to get scores.
& & totalCount > 0
2024-11-27 00:55:02 -05:00
& & resultsScreen . ChildrenOfType < ScorePanelList > ( ) . Single ( ) . GetScorePanels ( ) . Count ( ) = = totalCount
& & resultsScreen . ChildrenOfType < ScorePanelList > ( ) . Single ( ) . AllPanelsVisible ) ;
2020-07-31 21:39:50 +09:00
AddWaitStep ( "wait for display" , 5 ) ;
}
2024-11-21 20:26:44 +09:00
private void bindHandler ( bool delayed = false , ScoreInfo ? userScore = null , bool failRequests = false , bool noScores = false ) = > ( ( DummyAPIAccess ) API ) . HandleRequest = request = >
2020-07-31 21:39:50 +09:00
{
2021-03-23 18:08:32 +09:00
// pre-check for requests we should be handling (as they are scheduled below).
switch ( request )
{
2024-11-26 01:01:59 -05:00
case ShowPlaylistScoreRequest :
2024-11-27 00:55:02 -05:00
case ShowPlaylistUserScoreRequest :
2022-06-24 21:25:23 +09:00
case IndexPlaylistScoresRequest :
2021-03-23 18:08:32 +09:00
break ;
2025-02-26 18:31:06 +09:00
case GetBeatmapsRequest getBeatmaps :
getBeatmaps . TriggerSuccess ( new GetBeatmapsResponse
{
Beatmaps = getBeatmaps . BeatmapIds . Select ( id = > new APIBeatmap
{
OnlineID = id ,
StarRating = id ,
DifficultyName = $"Beatmap {id}" ,
BeatmapSet = new APIBeatmapSet
{
Title = $"Title {id}" ,
Artist = $"Artist {id}" ,
AuthorString = $"Author {id}"
}
} ) . ToList ( )
} ) ;
return true ;
2021-03-23 18:08:32 +09:00
default :
return false ;
}
2020-07-31 21:39:50 +09:00
requestComplete = false ;
2021-02-22 15:43:58 +09:00
double delay = delayed ? 3000 : 0 ;
2020-07-31 21:39:50 +09:00
2021-02-22 15:43:58 +09:00
Scheduler . AddDelayed ( ( ) = >
2020-07-31 21:39:50 +09:00
{
2021-02-22 15:43:58 +09:00
if ( failRequests )
{
triggerFail ( request ) ;
return ;
}
switch ( request )
{
2024-11-26 01:01:59 -05:00
case ShowPlaylistScoreRequest s :
2021-02-22 15:43:58 +09:00
if ( userScore = = null )
triggerFail ( s ) ;
else
2025-03-03 12:23:52 +01:00
triggerSuccess ( s , ( ) = > createUserResponse ( userScore ) ) ;
2021-10-08 15:18:01 +09:00
2021-02-22 15:43:58 +09:00
break ;
2024-11-27 00:55:02 -05:00
case ShowPlaylistUserScoreRequest u :
if ( userScore = = null )
triggerFail ( u ) ;
else
2025-03-03 12:23:52 +01:00
triggerSuccess ( u , ( ) = > createUserResponse ( userScore ) ) ;
2024-11-27 00:55:02 -05:00
break ;
2021-02-22 15:43:58 +09:00
case IndexPlaylistScoresRequest i :
2025-03-03 12:23:52 +01:00
triggerSuccess ( i , ( ) = > createIndexResponse ( i , noScores ) ) ;
2021-02-22 15:43:58 +09:00
break ;
}
} , delay ) ;
2021-03-23 18:08:32 +09:00
return true ;
2020-07-31 21:39:50 +09:00
} ;
2020-05-28 20:08:45 +09:00
2025-03-03 12:23:52 +01:00
private void triggerSuccess < T > ( APIRequest < T > req , Func < T > result )
2020-07-31 21:39:50 +09:00
where T : class
{
2021-02-22 15:43:58 +09:00
requestComplete = true ;
2025-03-03 12:23:52 +01:00
req . TriggerSuccess ( result . Invoke ( ) ) ;
2020-07-31 21:39:50 +09:00
}
2021-02-22 15:43:58 +09:00
private void triggerFail ( APIRequest req )
2020-07-31 21:39:50 +09:00
{
2021-02-22 15:43:58 +09:00
requestComplete = true ;
req . TriggerFailure ( new WebException ( "Failed." ) ) ;
2020-07-31 21:39:50 +09:00
}
2024-11-21 20:26:44 +09:00
private MultiplayerScore createUserResponse ( ScoreInfo userScore )
2020-07-31 21:39:50 +09:00
{
2025-03-03 12:23:52 +01:00
var multiplayerUserScore = createMultiplayerUserScore ( userScore ) ;
2020-07-31 21:39:50 +09:00
2021-10-08 15:18:01 +09:00
totalCount + + ;
2020-07-31 21:39:50 +09:00
for ( int i = 1 ; i < = scores_per_result ; i + + )
{
2025-03-03 12:23:52 +01:00
multiplayerUserScore . ScoresAround ! . Lower ! . Scores . Add ( new MultiplayerScore
2020-07-31 21:39:50 +09:00
{
2022-04-11 15:38:11 +09:00
ID = getNextLowestScoreId ( ) ,
2020-07-31 21:39:50 +09:00
Accuracy = userScore . Accuracy ,
Passed = true ,
Rank = userScore . Rank ,
MaxCombo = userScore . MaxCombo ,
2025-02-26 18:31:06 +09:00
BeatmapId = RNG . Next ( 0 , 7 ) ,
2021-11-04 18:02:44 +09:00
User = new APIUser
2020-07-31 21:39:50 +09:00
{
2024-11-27 00:55:02 -05:00
Id = 2 + i ,
2020-07-31 21:39:50 +09:00
Username = $"peppy{i}" ,
CoverUrl = "https://osu.ppy.sh/images/headers/profile-covers/c3.jpg" ,
} ,
} ) ;
2025-03-03 12:23:52 +01:00
multiplayerUserScore . ScoresAround ! . Higher ! . Scores . Add ( new MultiplayerScore
2020-07-31 21:39:50 +09:00
{
2022-04-11 15:38:11 +09:00
ID = getNextHighestScoreId ( ) ,
2020-07-31 21:39:50 +09:00
Accuracy = userScore . Accuracy ,
Passed = true ,
Rank = userScore . Rank ,
MaxCombo = userScore . MaxCombo ,
2025-02-26 18:31:06 +09:00
BeatmapId = RNG . Next ( 0 , 7 ) ,
2021-11-04 18:02:44 +09:00
User = new APIUser
2020-07-31 21:39:50 +09:00
{
2024-11-27 00:55:02 -05:00
Id = 2 + i ,
2020-07-31 21:39:50 +09:00
Username = $"peppy{i}" ,
CoverUrl = "https://osu.ppy.sh/images/headers/profile-covers/c3.jpg" ,
} ,
} ) ;
2021-10-08 15:18:01 +09:00
totalCount + = 2 ;
2020-07-31 21:39:50 +09:00
}
2025-03-03 12:23:52 +01:00
addCursor ( multiplayerUserScore . ScoresAround ! . Lower ! ) ;
addCursor ( multiplayerUserScore . ScoresAround ! . Higher ! ) ;
2020-07-31 21:39:50 +09:00
return multiplayerUserScore ;
}
2025-03-03 12:23:52 +01:00
private MultiplayerScore createMultiplayerUserScore ( ScoreInfo userScore )
{
return new MultiplayerScore
{
ID = highestScoreId ,
Accuracy = userScore . Accuracy ,
Passed = userScore . Passed ,
Rank = userScore . Rank ,
Position = userScore . Position ,
MaxCombo = userScore . MaxCombo ,
User = userScore . User ,
BeatmapId = RNG . Next ( 0 , 7 ) ,
ScoresAround = new MultiplayerScoresAround
{
Higher = new MultiplayerScores ( ) ,
Lower = new MultiplayerScores ( )
}
} ;
}
2025-02-26 18:31:06 +09:00
private IndexedMultiplayerScores createIndexResponse ( IndexPlaylistScoresRequest req , bool noScores )
2020-07-31 21:39:50 +09:00
{
var result = new IndexedMultiplayerScores ( ) ;
2023-12-31 22:10:49 +09:00
if ( noScores ) return result ;
2020-07-31 21:39:50 +09:00
string sort = req . IndexParams ? . Properties [ "sort" ] . ToObject < string > ( ) ? ? "score_desc" ;
2025-03-03 12:23:52 +01:00
bool reachedEnd = false ;
2020-07-31 21:39:50 +09:00
for ( int i = 1 ; i < = scores_per_result ; i + + )
{
2025-03-03 12:23:52 +01:00
int nextId = sort = = "score_asc" ? getNextHighestScoreId ( ) : getNextLowestScoreId ( ) ;
if ( userScore . OnlineID - nextId > = userScore . Position )
{
reachedEnd = true ;
break ;
}
2020-07-31 21:39:50 +09:00
result . Scores . Add ( new MultiplayerScore
{
2025-03-03 12:23:52 +01:00
ID = nextId ,
2020-07-31 21:39:50 +09:00
Accuracy = 1 ,
2020-05-28 20:08:45 +09:00
Passed = true ,
2020-07-31 21:39:50 +09:00
Rank = ScoreRank . X ,
MaxCombo = 1000 ,
2025-02-26 18:31:06 +09:00
BeatmapId = RNG . Next ( 0 , 7 ) ,
2021-11-04 18:02:44 +09:00
User = new APIUser
2020-05-28 20:08:45 +09:00
{
2024-11-27 00:55:02 -05:00
Id = 2 + i ,
2020-05-28 20:08:45 +09:00
Username = $"peppy{i}" ,
CoverUrl = "https://osu.ppy.sh/images/headers/profile-covers/c3.jpg" ,
} ,
} ) ;
2021-10-08 15:18:01 +09:00
totalCount + + ;
2020-05-28 20:08:45 +09:00
}
2025-03-03 12:23:52 +01:00
if ( ! reachedEnd )
addCursor ( result ) ;
result . UserScore = createMultiplayerUserScore ( userScore ) ;
2020-07-31 21:39:50 +09:00
return result ;
}
2022-04-11 15:38:11 +09:00
/// <summary>
/// The next highest score ID to appear at the left of the list. Monotonically decreasing.
/// </summary>
private int getNextHighestScoreId ( ) = > - - highestScoreId ;
/// <summary>
/// The next lowest score ID to appear at the right of the list. Monotonically increasing.
/// </summary>
/// <returns></returns>
private int getNextLowestScoreId ( ) = > + + lowestScoreId ;
2020-07-31 21:39:50 +09:00
private void addCursor ( MultiplayerScores scores )
{
scores . Cursor = new Cursor
{
Properties = new Dictionary < string , JToken >
{
{ "total_score" , JToken . FromObject ( scores . Scores [ ^ 1 ] . TotalScore ) } ,
{ "score_id" , JToken . FromObject ( scores . Scores [ ^ 1 ] . ID ) } ,
}
} ;
scores . Params = new IndexScoresParams
2020-05-28 20:08:45 +09:00
{
2020-07-31 21:39:50 +09:00
Properties = new Dictionary < string , JToken >
2020-05-28 20:08:45 +09:00
{
2022-04-11 15:38:11 +09:00
// [ 1, 2, 3, ... ] => score_desc (will be added to the right of the list)
// [ 3, 2, 1, ... ] => score_asc (will be added to the left of the list)
{ "sort" , JToken . FromObject ( scores . Scores [ ^ 1 ] . ID > scores . Scores [ ^ 2 ] . ID ? "score_desc" : "score_asc" ) }
2020-06-09 18:53:55 +09:00
}
} ;
2020-05-28 20:08:45 +09:00
}
2020-07-31 21:39:50 +09:00
2024-11-27 00:55:02 -05:00
private partial class TestScoreResultsScreen : PlaylistItemScoreResultsScreen
2020-07-31 21:39:50 +09:00
{
2024-11-27 00:55:02 -05:00
public TestScoreResultsScreen ( ScoreInfo score , int roomId , PlaylistItem playlistItem )
2024-02-22 19:15:02 +01:00
: base ( score , roomId , playlistItem )
2020-07-31 21:39:50 +09:00
{
2024-02-22 19:15:02 +01:00
AllowRetry = true ;
2020-07-31 21:39:50 +09:00
}
}
2024-11-27 00:55:02 -05:00
private partial class TestUserBestResultsScreen : PlaylistItemUserBestResultsScreen
{
public TestUserBestResultsScreen ( int roomId , PlaylistItem playlistItem , int userId )
: base ( roomId , playlistItem , userId )
{
AllowRetry = true ;
}
}
2020-05-28 20:08:45 +09:00
}
}