2023-04-29 01:36:31 +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.
2024-07-19 13:08:05 +08:00
using System ;
2024-07-10 13:51:34 +08:00
using System.IO ;
2023-04-29 01:36:31 +08:00
using System.Linq ;
2024-07-19 13:08:05 +08:00
using System.Threading ;
2023-04-29 01:36:31 +08:00
using NUnit.Framework ;
2024-07-19 13:08:05 +08:00
using osu.Framework.Allocation ;
2023-05-24 22:51:28 +08:00
using osu.Framework.Extensions ;
using osu.Framework.Extensions.IEnumerableExtensions ;
using osu.Framework.Extensions.ObjectExtensions ;
2024-07-19 13:08:05 +08:00
using osu.Framework.Graphics ;
2023-11-07 02:48:47 +08:00
using osu.Framework.Graphics.UserInterface ;
2024-01-26 12:59:28 +08:00
using osu.Framework.Input ;
2023-04-29 01:36:31 +08:00
using osu.Framework.Screens ;
2023-05-24 22:57:37 +08:00
using osu.Framework.Testing ;
2023-04-29 01:36:31 +08:00
using osu.Game.Beatmaps ;
2023-08-28 16:02:05 +08:00
using osu.Game.Configuration ;
2023-05-24 22:51:28 +08:00
using osu.Game.Database ;
2024-07-10 13:51:34 +08:00
using osu.Game.Graphics.UserInterface ;
2023-11-07 02:48:47 +08:00
using osu.Game.Overlays ;
2023-05-24 22:51:28 +08:00
using osu.Game.Rulesets.Mania ;
using osu.Game.Rulesets.Osu ;
2023-04-29 01:36:31 +08:00
using osu.Game.Screens.Edit ;
2023-05-24 22:51:28 +08:00
using osu.Game.Screens.Edit.GameplayTest ;
2024-01-26 12:59:28 +08:00
using osu.Game.Screens.Edit.Setup ;
2023-04-29 01:36:31 +08:00
using osu.Game.Screens.Menu ;
2023-05-24 22:51:28 +08:00
using osu.Game.Screens.Select ;
2023-08-28 16:02:05 +08:00
using osu.Game.Screens.Select.Filter ;
2023-05-24 22:51:28 +08:00
using osu.Game.Tests.Resources ;
2023-05-24 22:57:37 +08:00
using osuTK.Input ;
2023-04-29 01:36:31 +08:00
namespace osu.Game.Tests.Visual.Navigation
{
2023-04-29 09:34:50 +08:00
public partial class TestSceneBeatmapEditorNavigation : OsuGameTestScene
2023-04-29 01:36:31 +08:00
{
2024-07-10 13:34:25 +08:00
private BeatmapSetInfo beatmapSet = null ! ;
2024-07-10 13:51:34 +08:00
[Test]
public void TestExternalEditingNoChange ( )
{
2024-07-10 17:14:54 +08:00
string difficultyName = null ! ;
2024-07-10 13:51:34 +08:00
prepareBeatmap ( ) ;
openEditor ( ) ;
2024-07-10 17:14:54 +08:00
AddStep ( "store difficulty name" , ( ) = > difficultyName = getEditor ( ) . Beatmap . Value . BeatmapInfo . DifficultyName ) ;
2024-07-10 13:51:34 +08:00
AddStep ( "open file menu" , ( ) = > getEditor ( ) . ChildrenOfType < Menu . DrawableMenuItem > ( ) . Single ( m = > m . Item . Text . Value . ToString ( ) = = "File" ) . TriggerClick ( ) ) ;
AddStep ( "click external edit" , ( ) = > getEditor ( ) . ChildrenOfType < Menu . DrawableMenuItem > ( ) . Single ( m = > m . Item . Text . Value . ToString ( ) = = "Edit externally" ) . TriggerClick ( ) ) ;
AddUntilStep ( "wait for external edit screen" , ( ) = > Game . ScreenStack . CurrentScreen is ExternalEditScreen externalEditScreen & & externalEditScreen . IsLoaded ) ;
AddUntilStep ( "wait for button ready" , ( ) = > ( ( ExternalEditScreen ) Game . ScreenStack . CurrentScreen ) . ChildrenOfType < DangerousRoundedButton > ( ) . FirstOrDefault ( ) ? . Enabled . Value = = true ) ;
AddStep ( "finish external edit" , ( ) = > ( ( ExternalEditScreen ) Game . ScreenStack . CurrentScreen ) . ChildrenOfType < DangerousRoundedButton > ( ) . First ( ) . TriggerClick ( ) ) ;
AddUntilStep ( "wait for editor" , ( ) = > Game . ScreenStack . CurrentScreen is Editor editor & & editor . ReadyForUse ) ;
2024-07-10 17:14:54 +08:00
AddAssert ( "beatmapset didn't change" , ( ) = > getEditor ( ) . Beatmap . Value . BeatmapSetInfo , ( ) = > Is . EqualTo ( beatmapSet ) ) ;
AddAssert ( "difficulty didn't change" , ( ) = > getEditor ( ) . Beatmap . Value . BeatmapInfo . DifficultyName , ( ) = > Is . EqualTo ( difficultyName ) ) ;
2024-07-10 13:51:34 +08:00
AddAssert ( "old beatmapset not deleted" , ( ) = > Game . BeatmapManager . QueryBeatmapSet ( s = > s . ID = = beatmapSet . ID ) , ( ) = > Is . Not . Null ) ;
}
[Test]
public void TestExternalEditingWithChange ( )
{
2024-07-10 17:14:54 +08:00
string difficultyName = null ! ;
2024-07-10 13:51:34 +08:00
prepareBeatmap ( ) ;
openEditor ( ) ;
2024-07-10 17:14:54 +08:00
AddStep ( "store difficulty name" , ( ) = > difficultyName = getEditor ( ) . Beatmap . Value . BeatmapInfo . DifficultyName ) ;
2024-07-10 13:51:34 +08:00
AddStep ( "open file menu" , ( ) = > getEditor ( ) . ChildrenOfType < Menu . DrawableMenuItem > ( ) . Single ( m = > m . Item . Text . Value . ToString ( ) = = "File" ) . TriggerClick ( ) ) ;
AddStep ( "click external edit" , ( ) = > getEditor ( ) . ChildrenOfType < Menu . DrawableMenuItem > ( ) . Single ( m = > m . Item . Text . Value . ToString ( ) = = "Edit externally" ) . TriggerClick ( ) ) ;
AddUntilStep ( "wait for external edit screen" , ( ) = > Game . ScreenStack . CurrentScreen is ExternalEditScreen externalEditScreen & & externalEditScreen . IsLoaded ) ;
AddUntilStep ( "wait for button ready" , ( ) = > ( ( ExternalEditScreen ) Game . ScreenStack . CurrentScreen ) . ChildrenOfType < DangerousRoundedButton > ( ) . FirstOrDefault ( ) ? . Enabled . Value = = true ) ;
AddStep ( "add file externally" , ( ) = >
{
var op = ( ( ExternalEditScreen ) Game . ScreenStack . CurrentScreen ) . EditOperation ! ;
File . WriteAllText ( Path . Combine ( op . MountedPath , "test.txt" ) , "test" ) ;
} ) ;
AddStep ( "finish external edit" , ( ) = > ( ( ExternalEditScreen ) Game . ScreenStack . CurrentScreen ) . ChildrenOfType < DangerousRoundedButton > ( ) . First ( ) . TriggerClick ( ) ) ;
AddUntilStep ( "wait for editor" , ( ) = > Game . ScreenStack . CurrentScreen is Editor editor & & editor . ReadyForUse ) ;
2024-07-10 17:14:54 +08:00
AddAssert ( "beatmapset changed" , ( ) = > getEditor ( ) . Beatmap . Value . BeatmapSetInfo , ( ) = > Is . Not . EqualTo ( beatmapSet ) ) ;
2024-07-11 15:43:00 +08:00
AddAssert ( "beatmapset is locally modified" , ( ) = > getEditor ( ) . Beatmap . Value . BeatmapSetInfo . Status , ( ) = > Is . EqualTo ( BeatmapOnlineStatus . LocallyModified ) ) ;
AddAssert ( "all difficulties are locally modified" , ( ) = > getEditor ( ) . Beatmap . Value . BeatmapSetInfo . Beatmaps . All ( b = > b . Status = = BeatmapOnlineStatus . LocallyModified ) ) ;
2024-07-10 17:14:54 +08:00
AddAssert ( "difficulty didn't change" , ( ) = > getEditor ( ) . Beatmap . Value . BeatmapInfo . DifficultyName , ( ) = > Is . EqualTo ( difficultyName ) ) ;
2024-07-10 13:51:34 +08:00
AddAssert ( "old beatmapset deleted" , ( ) = > Game . BeatmapManager . QueryBeatmapSet ( s = > s . ID = = beatmapSet . ID ) , ( ) = > Is . Null ) ;
}
2024-07-09 19:34:44 +08:00
[Test]
public void TestSaveThenDeleteActuallyDeletesAtSongSelect ( )
{
2024-07-10 13:34:25 +08:00
prepareBeatmap ( ) ;
openEditor ( ) ;
2024-07-09 19:34:44 +08:00
makeMetadataChange ( ) ;
2024-07-10 13:34:25 +08:00
AddAssert ( "save" , ( ) = > getEditor ( ) . Save ( ) ) ;
2024-07-09 19:34:44 +08:00
AddStep ( "delete beatmap" , ( ) = > Game . BeatmapManager . Delete ( beatmapSet ) ) ;
2024-07-10 13:34:25 +08:00
AddStep ( "exit" , ( ) = > getEditor ( ) . Exit ( ) ) ;
2024-07-09 19:34:44 +08:00
AddUntilStep ( "wait for song select" , ( ) = > Game . ScreenStack . CurrentScreen is PlaySongSelect songSelect
& & songSelect . Beatmap . Value is DummyWorkingBeatmap ) ;
}
2024-01-26 12:59:28 +08:00
[Test]
public void TestChangeMetadataExitWhileTextboxFocusedPromptsSave ( )
{
AddStep ( "switch ruleset" , ( ) = > Game . Ruleset . Value = new ManiaRuleset ( ) . RulesetInfo ) ;
2024-07-10 13:34:25 +08:00
prepareBeatmap ( ) ;
openEditor ( ) ;
2024-01-26 12:59:28 +08:00
2024-07-09 19:34:44 +08:00
makeMetadataChange ( commit : false ) ;
2024-07-10 13:34:25 +08:00
AddStep ( "exit" , ( ) = > getEditor ( ) . Exit ( ) ) ;
2024-07-09 19:34:44 +08:00
AddUntilStep ( "save dialog displayed" , ( ) = > Game . ChildrenOfType < DialogOverlay > ( ) . SingleOrDefault ( ) ? . CurrentDialog is PromptForSaveDialog ) ;
}
private void makeMetadataChange ( bool commit = true )
{
2024-01-26 12:59:28 +08:00
AddStep ( "change to song setup" , ( ) = > InputManager . Key ( Key . F4 ) ) ;
TextBox textbox = null ! ;
AddUntilStep ( "wait for metadata section" , ( ) = >
{
var t = Game . ChildrenOfType < MetadataSection > ( ) . SingleOrDefault ( ) . ChildrenOfType < TextBox > ( ) . FirstOrDefault ( ) ;
if ( t = = null )
return false ;
textbox = t ;
return true ;
} ) ;
AddStep ( "focus textbox" , ( ) = >
{
InputManager . MoveMouseTo ( textbox ) ;
InputManager . Click ( MouseButton . Left ) ;
} ) ;
AddStep ( "simulate changing textbox" , ( ) = >
{
// Can't simulate text input but this should work.
InputManager . Keys ( PlatformAction . SelectAll ) ;
InputManager . Keys ( PlatformAction . Copy ) ;
InputManager . Keys ( PlatformAction . Paste ) ;
InputManager . Keys ( PlatformAction . Paste ) ;
} ) ;
2024-07-09 19:34:44 +08:00
if ( commit ) AddStep ( "commit" , ( ) = > InputManager . Key ( Key . Enter ) ) ;
2024-01-26 12:59:28 +08:00
}
2023-05-24 22:51:28 +08:00
[Test]
2024-08-28 22:29:32 +08:00
[Solo]
2023-05-24 22:51:28 +08:00
public void TestEditorGameplayTestAlwaysUsesOriginalRuleset ( )
{
2024-07-10 13:34:25 +08:00
prepareBeatmap ( ) ;
2023-05-24 22:51:28 +08:00
2024-08-28 22:29:32 +08:00
AddStep ( "switch ruleset at song select" , ( ) = > Game . Ruleset . Value = new ManiaRuleset ( ) . RulesetInfo ) ;
2023-05-24 22:51:28 +08:00
AddStep ( "open editor" , ( ) = > ( ( PlaySongSelect ) Game . ScreenStack . CurrentScreen ) . Edit ( beatmapSet . Beatmaps . First ( beatmap = > beatmap . Ruleset . OnlineID = = 0 ) ) ) ;
2024-08-28 22:29:32 +08:00
2023-05-24 22:51:28 +08:00
AddUntilStep ( "wait for editor open" , ( ) = > Game . ScreenStack . CurrentScreen is Editor editor & & editor . ReadyForUse ) ;
2024-08-28 22:29:32 +08:00
AddAssert ( "editor ruleset is osu!" , ( ) = > Game . Ruleset . Value , ( ) = > Is . EqualTo ( new OsuRuleset ( ) . RulesetInfo ) ) ;
2023-05-24 22:51:28 +08:00
2024-08-28 22:29:32 +08:00
AddStep ( "test gameplay" , ( ) = > getEditor ( ) . TestGameplay ( ) ) ;
2023-05-24 22:51:28 +08:00
AddUntilStep ( "wait for player" , ( ) = >
{
// notifications may fire at almost any inopportune time and cause annoying test failures.
// relentlessly attempt to dismiss any and all interfering overlays, which includes notifications.
// this is theoretically not foolproof, but it's the best that can be done here.
Game . CloseAllOverlays ( ) ;
return Game . ScreenStack . CurrentScreen is EditorPlayer editorPlayer & & editorPlayer . IsLoaded ;
} ) ;
2024-08-28 22:29:32 +08:00
AddAssert ( "gameplay ruleset is osu!" , ( ) = > Game . Ruleset . Value , ( ) = > Is . EqualTo ( new OsuRuleset ( ) . RulesetInfo ) ) ;
2023-05-24 22:51:28 +08:00
AddStep ( "exit to song select" , ( ) = > Game . PerformFromScreen ( _ = > { } , typeof ( PlaySongSelect ) . Yield ( ) ) ) ;
AddUntilStep ( "wait for song select" , ( ) = > Game . ScreenStack . CurrentScreen is PlaySongSelect ) ;
AddAssert ( "previous ruleset restored" , ( ) = > Game . Ruleset . Value . Equals ( new ManiaRuleset ( ) . RulesetInfo ) ) ;
}
2023-04-29 10:05:10 +08:00
/// <summary>
/// When entering the editor, a new beatmap is created as part of the asynchronous load process.
/// This test ensures that in the case of an early exit from the editor (ie. while it's still loading)
/// doesn't leave a dangling beatmap behind.
///
/// This may not fail 100% due to timing, but has a pretty high chance of hitting a failure so works well enough
/// as a test.
/// </summary>
2023-04-29 01:36:31 +08:00
[Test]
public void TestCancelNavigationToEditor ( )
{
2023-04-29 09:49:25 +08:00
BeatmapSetInfo [ ] beatmapSets = null ! ;
2023-04-29 01:36:31 +08:00
2023-04-29 10:01:29 +08:00
AddStep ( "Fetch initial beatmaps" , ( ) = > beatmapSets = allBeatmapSets ( ) ) ;
2023-04-29 01:36:31 +08:00
2023-04-29 09:49:25 +08:00
AddStep ( "Set current beatmap to default" , ( ) = > Game . Beatmap . SetDefault ( ) ) ;
2023-04-29 01:36:31 +08:00
2024-07-19 13:08:05 +08:00
DelayedLoadEditorLoader loader = null ! ;
AddStep ( "Push editor loader" , ( ) = > Game . ScreenStack . Push ( loader = new DelayedLoadEditorLoader ( ) ) ) ;
2023-04-29 09:49:25 +08:00
AddUntilStep ( "Wait for loader current" , ( ) = > Game . ScreenStack . CurrentScreen is EditorLoader ) ;
2024-07-19 13:08:05 +08:00
AddUntilStep ( "wait for editor load start" , ( ) = > loader . Editor ! = null ) ;
2023-04-29 09:49:25 +08:00
AddStep ( "Close editor while loading" , ( ) = > Game . ScreenStack . CurrentScreen . Exit ( ) ) ;
2024-07-19 13:08:05 +08:00
AddStep ( "allow editor load" , ( ) = > loader . AllowLoad . Set ( ) ) ;
AddUntilStep ( "wait for editor ready" , ( ) = > loader . Editor ! . LoadState > = LoadState . Ready ) ;
2023-04-29 02:23:00 +08:00
2023-04-29 09:49:25 +08:00
AddUntilStep ( "Wait for menu" , ( ) = > Game . ScreenStack . CurrentScreen is MainMenu ) ;
2024-07-18 17:34:08 +08:00
AddAssert ( "Check no new beatmaps were made" , allBeatmapSets , ( ) = > Is . EquivalentTo ( beatmapSets ) ) ;
2023-04-29 01:36:31 +08:00
2023-04-29 10:01:29 +08:00
BeatmapSetInfo [ ] allBeatmapSets ( ) = > Game . Realm . Run ( realm = > realm . All < BeatmapSetInfo > ( ) . Where ( x = > ! x . DeletePending ) . ToArray ( ) ) ;
2023-04-29 01:36:31 +08:00
}
2023-05-24 22:57:37 +08:00
[Test]
public void TestExitEditorWithoutSelection ( )
{
2024-07-10 13:34:25 +08:00
prepareBeatmap ( ) ;
openEditor ( ) ;
2023-05-24 22:57:37 +08:00
AddStep ( "escape once" , ( ) = > InputManager . Key ( Key . Escape ) ) ;
AddUntilStep ( "wait for editor exit" , ( ) = > Game . ScreenStack . CurrentScreen is not Editor ) ;
}
[Test]
public void TestExitEditorWithSelection ( )
{
2024-07-10 13:34:25 +08:00
prepareBeatmap ( ) ;
openEditor ( ) ;
2023-05-24 22:57:37 +08:00
AddStep ( "make selection" , ( ) = >
{
var beatmap = getEditorBeatmap ( ) ;
beatmap . SelectedHitObjects . AddRange ( beatmap . HitObjects . Take ( 5 ) ) ;
} ) ;
AddAssert ( "selection exists" , ( ) = > getEditorBeatmap ( ) . SelectedHitObjects , ( ) = > Has . Count . GreaterThan ( 0 ) ) ;
AddStep ( "escape once" , ( ) = > InputManager . Key ( Key . Escape ) ) ;
2023-05-25 02:18:36 +08:00
AddAssert ( "selection empty" , ( ) = > getEditorBeatmap ( ) . SelectedHitObjects , ( ) = > Has . Count . Zero ) ;
2023-05-24 22:57:37 +08:00
AddStep ( "escape again" , ( ) = > InputManager . Key ( Key . Escape ) ) ;
AddUntilStep ( "wait for editor exit" , ( ) = > Game . ScreenStack . CurrentScreen is not Editor ) ;
}
2023-06-06 14:23:59 +08:00
[Test]
public void TestLastTimestampRememberedOnExit ( )
{
2024-07-10 13:34:25 +08:00
prepareBeatmap ( ) ;
openEditor ( ) ;
2023-06-06 14:23:59 +08:00
AddStep ( "seek to arbitrary time" , ( ) = > getEditor ( ) . ChildrenOfType < EditorClock > ( ) . First ( ) . Seek ( 1234 ) ) ;
AddUntilStep ( "time is correct" , ( ) = > getEditor ( ) . ChildrenOfType < EditorClock > ( ) . First ( ) . CurrentTime , ( ) = > Is . EqualTo ( 1234 ) ) ;
AddStep ( "exit editor" , ( ) = > InputManager . Key ( Key . Escape ) ) ;
AddUntilStep ( "wait for editor exit" , ( ) = > Game . ScreenStack . CurrentScreen is not Editor ) ;
2024-07-10 13:34:25 +08:00
openEditor ( ) ;
2023-06-06 14:23:59 +08:00
AddUntilStep ( "time is correct" , ( ) = > getEditor ( ) . ChildrenOfType < EditorClock > ( ) . First ( ) . CurrentTime , ( ) = > Is . EqualTo ( 1234 ) ) ;
}
2023-07-25 19:19:03 +08:00
[Test]
public void TestAttemptGlobalMusicOperationFromEditor ( )
{
2024-07-10 13:34:25 +08:00
prepareBeatmap ( ) ;
2023-07-25 19:19:03 +08:00
AddUntilStep ( "wait for music playing" , ( ) = > Game . MusicController . IsPlaying ) ;
AddStep ( "user request stop" , ( ) = > Game . MusicController . Stop ( requestedByUser : true ) ) ;
AddUntilStep ( "wait for music stopped" , ( ) = > ! Game . MusicController . IsPlaying ) ;
2024-07-10 13:34:25 +08:00
openEditor ( ) ;
2023-07-25 19:19:03 +08:00
AddUntilStep ( "music still stopped" , ( ) = > ! Game . MusicController . IsPlaying ) ;
AddStep ( "user request play" , ( ) = > Game . MusicController . Play ( requestedByUser : true ) ) ;
AddUntilStep ( "music still stopped" , ( ) = > ! Game . MusicController . IsPlaying ) ;
AddStep ( "exit to song select" , ( ) = > Game . PerformFromScreen ( _ = > { } , typeof ( PlaySongSelect ) . Yield ( ) ) ) ;
AddUntilStep ( "wait for song select" , ( ) = > Game . ScreenStack . CurrentScreen is PlaySongSelect ) ;
AddUntilStep ( "wait for music playing" , ( ) = > Game . MusicController . IsPlaying ) ;
AddStep ( "user request stop" , ( ) = > Game . MusicController . Stop ( requestedByUser : true ) ) ;
AddUntilStep ( "wait for music stopped" , ( ) = > ! Game . MusicController . IsPlaying ) ;
}
2023-08-28 16:02:05 +08:00
[TestCase(SortMode.Title)]
[TestCase(SortMode.Difficulty)]
public void TestSelectionRetainedOnExit ( SortMode sortMode )
{
AddStep ( $"set sort mode to {sortMode}" , ( ) = > Game . LocalConfig . SetValue ( OsuSetting . SongSelectSortingMode , sortMode ) ) ;
2024-07-10 13:34:25 +08:00
prepareBeatmap ( ) ;
openEditor ( ) ;
2023-08-28 16:02:05 +08:00
AddStep ( "exit editor" , ( ) = > InputManager . Key ( Key . Escape ) ) ;
AddUntilStep ( "wait for editor exit" , ( ) = > Game . ScreenStack . CurrentScreen is not Editor ) ;
AddUntilStep ( "selection retained on song select" ,
( ) = > Game . Beatmap . Value . BeatmapInfo . ID ,
( ) = > Is . EqualTo ( beatmapSet . Beatmaps . First ( b = > b . Ruleset . OnlineID = = 0 ) . ID ) ) ;
}
2023-11-07 02:48:47 +08:00
[Test]
public void TestCreateNewDifficultyOnNonExistentBeatmap ( )
{
AddUntilStep ( "wait for dialog overlay" , ( ) = > Game . ChildrenOfType < DialogOverlay > ( ) . SingleOrDefault ( ) ! = null ) ;
2023-11-24 10:00:22 +08:00
AddStep ( "open editor" , ( ) = > Game . ChildrenOfType < ButtonSystem > ( ) . Single ( ) . OnEditBeatmap ? . Invoke ( ) ) ;
2023-11-07 02:48:47 +08:00
AddUntilStep ( "wait for editor" , ( ) = > Game . ScreenStack . CurrentScreen is Editor editor & & editor . IsLoaded ) ;
2024-07-10 13:34:25 +08:00
2023-11-07 02:48:47 +08:00
AddStep ( "click on file" , ( ) = >
{
var item = getEditor ( ) . ChildrenOfType < Menu . DrawableMenuItem > ( ) . Single ( i = > i . Item . Text . Value . ToString ( ) = = "File" ) ;
item . TriggerClick ( ) ;
} ) ;
AddStep ( "click on create new difficulty" , ( ) = >
{
var item = getEditor ( ) . ChildrenOfType < Menu . DrawableMenuItem > ( ) . Single ( i = > i . Item . Text . Value . ToString ( ) = = "Create new difficulty" ) ;
item . TriggerClick ( ) ;
} ) ;
AddStep ( "click on catch" , ( ) = >
{
var item = getEditor ( ) . ChildrenOfType < Menu . DrawableMenuItem > ( ) . Single ( i = > i . Item . Text . Value . ToString ( ) = = "osu!catch" ) ;
item . TriggerClick ( ) ;
} ) ;
2023-11-07 02:55:00 +08:00
AddAssert ( "save dialog displayed" , ( ) = > Game . ChildrenOfType < DialogOverlay > ( ) . Single ( ) . CurrentDialog is SaveRequiredPopupDialog ) ;
2023-11-07 02:48:47 +08:00
2023-11-07 02:55:00 +08:00
AddStep ( "press save" , ( ) = > Game . ChildrenOfType < DialogOverlay > ( ) . Single ( ) . CurrentDialog ! . PerformOkAction ( ) ) ;
AddUntilStep ( "wait for editor" , ( ) = > Game . ScreenStack . CurrentScreen is Editor editor & & editor . IsLoaded ) ;
2023-11-07 02:48:47 +08:00
AddAssert ( "editor beatmap uses catch ruleset" , ( ) = > getEditorBeatmap ( ) . BeatmapInfo . Ruleset . ShortName = = "fruits" ) ;
}
2024-07-10 13:34:25 +08:00
private void prepareBeatmap ( )
{
AddStep ( "import test beatmap" , ( ) = > Game . BeatmapManager . Import ( TestResources . GetTestBeatmapForImport ( ) ) . WaitSafely ( ) ) ;
AddStep ( "retrieve beatmap" , ( ) = > beatmapSet = Game . BeatmapManager . QueryBeatmapSet ( set = > ! set . Protected ) . AsNonNull ( ) . Value . Detach ( ) ) ;
AddStep ( "present beatmap" , ( ) = > Game . PresentBeatmap ( beatmapSet ) ) ;
AddUntilStep ( "wait for song select" ,
( ) = > Game . Beatmap . Value . BeatmapSetInfo . Equals ( beatmapSet )
& & Game . ScreenStack . CurrentScreen is PlaySongSelect songSelect
2024-08-28 22:29:32 +08:00
& & songSelect . BeatmapSetsLoaded ) ;
2024-07-10 13:34:25 +08:00
}
private void openEditor ( )
{
AddStep ( "open editor" , ( ) = > ( ( PlaySongSelect ) Game . ScreenStack . CurrentScreen ) . Edit ( beatmapSet . Beatmaps . First ( beatmap = > beatmap . Ruleset . OnlineID = = 0 ) ) ) ;
AddUntilStep ( "wait for editor open" , ( ) = > Game . ScreenStack . CurrentScreen is Editor editor & & editor . ReadyForUse ) ;
}
2023-06-06 14:23:59 +08:00
private EditorBeatmap getEditorBeatmap ( ) = > getEditor ( ) . ChildrenOfType < EditorBeatmap > ( ) . Single ( ) ;
private Editor getEditor ( ) = > ( Editor ) Game . ScreenStack . CurrentScreen ;
2024-07-19 13:08:05 +08:00
private partial class DelayedLoadEditorLoader : EditorLoader
{
public readonly ManualResetEventSlim AllowLoad = new ManualResetEventSlim ( ) ;
public Editor ? Editor { get ; private set ; }
protected override Editor CreateEditor ( ) = > Editor = new DelayedLoadEditor ( this ) ;
}
private partial class DelayedLoadEditor : Editor
{
private readonly DelayedLoadEditorLoader loader ;
public DelayedLoadEditor ( DelayedLoadEditorLoader loader )
: base ( loader )
{
this . loader = loader ;
}
protected override IReadOnlyDependencyContainer CreateChildDependencies ( IReadOnlyDependencyContainer parent )
{
// Importantly, this occurs before base.load().
if ( ! loader . AllowLoad . Wait ( TimeSpan . FromSeconds ( 10 ) ) )
throw new TimeoutException ( ) ;
return base . CreateChildDependencies ( parent ) ;
}
}
2023-04-29 01:36:31 +08:00
}
}