2019-05-10 14:39:25 +08: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.
2022-06-17 15:37:17 +08:00
#nullable disable
2021-07-01 15:55:33 +08:00
using System ;
2020-03-05 10:25:07 +08:00
using System.Collections.Generic ;
2021-06-01 14:39:02 +08:00
using System.Linq ;
2020-03-05 10:25:07 +08:00
using osu.Framework.Allocation ;
using osu.Framework.Bindables ;
2023-01-15 20:51:18 +08:00
using osu.Framework.Screens ;
2021-07-01 15:55:33 +08:00
using osu.Game.Online.API ;
using osu.Game.Online.Rooms ;
2022-08-09 14:05:05 +08:00
using osu.Game.Online.Spectator ;
2020-03-05 10:25:07 +08:00
using osu.Game.Rulesets.Judgements ;
using osu.Game.Rulesets.Mods ;
using osu.Game.Rulesets.Scoring ;
2019-08-28 18:57:17 +08:00
using osu.Game.Rulesets.UI ;
2021-07-01 15:55:33 +08:00
using osu.Game.Scoring ;
2019-05-10 14:39:25 +08:00
using osu.Game.Screens.Play ;
namespace osu.Game.Tests.Visual
{
2020-03-05 10:25:07 +08:00
/// <summary>
/// A player that exposes many components that would otherwise not be available, for testing purposes.
/// </summary>
2021-07-01 15:55:33 +08:00
public partial class TestPlayer : SoloPlayer
2019-05-10 14:39:25 +08:00
{
2019-12-11 14:24:06 +08:00
protected override bool PauseOnFocusLost { get ; }
2019-05-10 14:39:25 +08:00
2019-08-28 18:57:17 +08:00
public new DrawableRuleset DrawableRuleset = > base . DrawableRuleset ;
2020-03-05 10:25:07 +08:00
public new Bindable < IReadOnlyList < Mod > > Mods = > base . Mods ;
public new HUDOverlay HUDOverlay = > base . HUDOverlay ;
2019-12-11 14:24:06 +08:00
public new GameplayClockContainer GameplayClockContainer = > base . GameplayClockContainer ;
2020-03-05 10:25:07 +08:00
public new ScoreProcessor ScoreProcessor = > base . ScoreProcessor ;
public new HealthProcessor HealthProcessor = > base . HealthProcessor ;
2021-07-01 15:55:33 +08:00
public bool TokenCreationRequested { get ; private set ; }
2021-07-01 16:38:28 +08:00
public Score SubmittedScore { get ; private set ; }
2021-07-01 15:55:33 +08:00
2021-02-19 16:42:30 +08:00
public new bool PauseCooldownActive = > base . PauseCooldownActive ;
2020-03-05 10:25:07 +08:00
public readonly List < JudgementResult > Results = new List < JudgementResult > ( ) ;
2022-08-09 14:05:05 +08:00
[Resolved]
private SpectatorClient spectatorClient { get ; set ; }
2019-12-11 14:24:06 +08:00
public TestPlayer ( bool allowPause = true , bool showResults = true , bool pauseOnFocusLost = false )
2020-12-23 16:39:08 +08:00
: base ( new PlayerConfiguration
{
AllowPause = allowPause ,
ShowResults = showResults
} )
2019-05-10 14:39:25 +08:00
{
2019-12-11 14:24:06 +08:00
PauseOnFocusLost = pauseOnFocusLost ;
2019-05-10 14:39:25 +08:00
}
2020-03-05 10:25:07 +08:00
2024-02-15 17:40:40 +08:00
protected override bool ShouldExitOnTokenRetrievalFailure ( Exception exception ) = > false ;
2021-07-01 15:55:33 +08:00
protected override APIRequest < APIScoreToken > CreateTokenRequest ( )
{
TokenCreationRequested = true ;
return base . CreateTokenRequest ( ) ;
}
protected override APIRequest < MultiplayerScore > CreateSubmissionRequest ( Score score , long token )
{
2021-07-01 16:38:28 +08:00
SubmittedScore = score ;
2021-07-01 15:55:33 +08:00
return base . CreateSubmissionRequest ( score , token ) ;
}
2021-06-01 14:39:02 +08:00
protected override void PrepareReplay ( )
{
2021-06-02 10:10:02 +08:00
// Generally, replay generation is handled by whatever is constructing the player.
// This is implemented locally here to ease migration of test scenes that have some executions
// running with autoplay and some not, but are not written in a way that lends to instantiating
// different `Player` types.
//
// Eventually we will want to remove this and update all test usages which rely on autoplay to use
// a `TestReplayPlayer`.
2021-06-01 15:24:38 +08:00
var autoplayMod = Mods . Value . OfType < ModAutoplay > ( ) . FirstOrDefault ( ) ;
2021-06-01 14:39:02 +08:00
2021-06-01 15:24:38 +08:00
if ( autoplayMod ! = null )
2021-06-01 14:39:02 +08:00
{
2022-03-29 15:45:21 +08:00
DrawableRuleset ? . SetReplayScore ( autoplayMod . CreateScoreFromReplayData ( GameplayState . Beatmap , Mods . Value ) ) ;
2021-06-01 14:39:02 +08:00
return ;
}
base . PrepareReplay ( ) ;
}
2020-03-05 10:25:07 +08:00
[BackgroundDependencyLoader]
private void load ( )
{
2022-01-11 17:33:35 +08:00
if ( ! LoadedBeatmapSuccessfully )
return ;
2020-03-05 10:25:07 +08:00
ScoreProcessor . NewJudgement + = r = > Results . Add ( r ) ;
}
2022-08-09 14:05:05 +08:00
2023-01-15 20:51:18 +08:00
public override bool OnExiting ( ScreenExitEvent e )
{
bool exiting = base . OnExiting ( e ) ;
// SubmittingPlayer performs EndPlaying on a fire-and-forget async task, which allows for the chance of BeginPlaying to be called before EndPlaying is called here.
// Until this is handled properly at game-side, ensure EndPlaying is called before exiting player.
// see: https://github.com/ppy/osu/issues/22220
if ( LoadedBeatmapSuccessfully )
spectatorClient ? . EndPlaying ( GameplayState ) ;
return exiting ;
}
2022-08-09 14:05:05 +08:00
protected override void Dispose ( bool isDisposing )
{
base . Dispose ( isDisposing ) ;
// Specific to tests, the player can be disposed without OnExiting() ever being called.
// We should make sure that the gameplay session has finished even in this case.
if ( LoadedBeatmapSuccessfully )
2022-08-09 17:15:50 +08:00
spectatorClient ? . EndPlaying ( GameplayState ) ;
2022-08-09 14:05:05 +08:00
}
2019-05-10 14:39:25 +08:00
}
}