1
0
mirror of https://github.com/ppy/osu.git synced 2024-11-07 16:07:25 +08:00

Merge pull request #15582 from bdach/editor-gameplay-test

Add method of testing gameplay from editor
This commit is contained in:
Dean Herbert 2021-11-12 15:11:04 +09:00 committed by GitHub
commit 1458aa6092
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 306 additions and 13 deletions

View File

@ -0,0 +1,123 @@
// 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.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Screens;
using osu.Framework.Testing;
using osu.Game.Beatmaps;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Osu;
using osu.Game.Screens.Edit;
using osu.Game.Screens.Edit.Components.Timelines.Summary;
using osu.Game.Tests.Beatmaps.IO;
using osuTK.Input;
namespace osu.Game.Tests.Visual.Editing
{
public class TestSceneEditorTestGameplay : EditorTestScene
{
protected override bool IsolateSavingFromDatabase => false;
protected override Ruleset CreateEditorRuleset() => new OsuRuleset();
[Resolved]
private OsuGameBase game { get; set; }
[Resolved]
private BeatmapManager beatmaps { get; set; }
private BeatmapSetInfo importedBeatmapSet;
public override void SetUpSteps()
{
AddStep("import test beatmap", () => importedBeatmapSet = ImportBeatmapTest.LoadOszIntoOsu(game).Result);
base.SetUpSteps();
}
protected override void LoadEditor()
{
Beatmap.Value = beatmaps.GetWorkingBeatmap(importedBeatmapSet.Beatmaps.First(b => b.RulesetID == 0));
base.LoadEditor();
}
[Test]
public void TestBasicGameplayTest()
{
AddStep("click test gameplay button", () =>
{
var button = Editor.ChildrenOfType<TestGameplayButton>().Single();
InputManager.MoveMouseTo(button);
InputManager.Click(MouseButton.Left);
});
EditorPlayer editorPlayer = null;
AddUntilStep("player pushed", () => (editorPlayer = Stack.CurrentScreen as EditorPlayer) != null);
AddStep("exit player", () => editorPlayer.Exit());
AddUntilStep("current screen is editor", () => Stack.CurrentScreen is Editor);
}
[Test]
public void TestCancelGameplayTestWithUnsavedChanges()
{
AddStep("delete all but first object", () => EditorBeatmap.RemoveRange(EditorBeatmap.HitObjects.Skip(1).ToList()));
AddStep("click test gameplay button", () =>
{
var button = Editor.ChildrenOfType<TestGameplayButton>().Single();
InputManager.MoveMouseTo(button);
InputManager.Click(MouseButton.Left);
});
AddUntilStep("save prompt shown", () => DialogOverlay.CurrentDialog is SaveBeforeGameplayTestDialog);
AddStep("dismiss prompt", () =>
{
var button = DialogOverlay.CurrentDialog.Buttons.Last();
InputManager.MoveMouseTo(button);
InputManager.Click(MouseButton.Left);
});
AddWaitStep("wait some", 3);
AddAssert("stayed in editor", () => Stack.CurrentScreen is Editor);
}
[Test]
public void TestSaveChangesBeforeGameplayTest()
{
AddStep("delete all but first object", () => EditorBeatmap.RemoveRange(EditorBeatmap.HitObjects.Skip(1).ToList()));
// bit of a hack to ensure this test can be ran multiple times without running into UNIQUE constraint failures
AddStep("set unique difficulty name", () => EditorBeatmap.BeatmapInfo.DifficultyName = Guid.NewGuid().ToString());
AddStep("click test gameplay button", () =>
{
var button = Editor.ChildrenOfType<TestGameplayButton>().Single();
InputManager.MoveMouseTo(button);
InputManager.Click(MouseButton.Left);
});
AddUntilStep("save prompt shown", () => DialogOverlay.CurrentDialog is SaveBeforeGameplayTestDialog);
AddStep("save changes", () => DialogOverlay.CurrentDialog.PerformOkAction());
EditorPlayer editorPlayer = null;
AddUntilStep("player pushed", () => (editorPlayer = Stack.CurrentScreen as EditorPlayer) != null);
AddAssert("beatmap has 1 object", () => editorPlayer.Beatmap.Value.Beatmap.HitObjects.Count == 1);
AddUntilStep("wait for return to editor", () => Stack.CurrentScreen is Editor);
AddAssert("track stopped", () => !Beatmap.Value.Track.IsRunning);
}
public override void TearDownSteps()
{
base.TearDownSteps();
AddStep("delete imported", () =>
{
beatmaps.Delete(importedBeatmapSet);
});
}
}
}

View File

@ -4,6 +4,7 @@
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Graphics.Containers;
using osu.Game.Overlays;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Catch;
using osu.Game.Rulesets.Edit;
@ -23,6 +24,9 @@ namespace osu.Game.Tests.Visual.Editing
[Cached(typeof(IBeatSnapProvider))]
private readonly EditorBeatmap editorBeatmap;
[Cached]
private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue);
public TestSceneSetupScreen()
{
editorBeatmap = new EditorBeatmap(new OsuBeatmap());

View File

@ -4,6 +4,7 @@
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Graphics.Containers;
using osu.Game.Overlays;
using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Osu;
using osu.Game.Screens.Edit;
@ -18,6 +19,9 @@ namespace osu.Game.Tests.Visual.Editing
[Cached(typeof(IBeatSnapProvider))]
private readonly EditorBeatmap editorBeatmap;
[Cached]
private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue);
protected override bool ScrollUsingMouseWheel => false;
public TestSceneTimingScreen()

View File

@ -76,6 +76,7 @@ namespace osu.Game.Input.Bindings
new KeyBinding(new[] { InputKey.J }, GlobalAction.EditorNudgeLeft),
new KeyBinding(new[] { InputKey.K }, GlobalAction.EditorNudgeRight),
new KeyBinding(new[] { InputKey.G }, GlobalAction.EditorCycleGridDisplayMode),
new KeyBinding(new[] { InputKey.F5 }, GlobalAction.EditorTestGameplay),
};
public IEnumerable<KeyBinding> InGameKeyBindings => new[]
@ -288,6 +289,9 @@ namespace osu.Game.Input.Bindings
ToggleChatFocus,
[LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.EditorCycleGridDisplayMode))]
EditorCycleGridDisplayMode
EditorCycleGridDisplayMode,
[LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.EditorTestGameplay))]
EditorTestGameplay
}
}

View File

@ -169,6 +169,11 @@ namespace osu.Game.Localisation
/// </summary>
public static LocalisableString EditorCycleGridDisplayMode => new TranslatableString(getKey(@"editor_cycle_grid_display_mode"), @"Cycle grid display mode");
/// <summary>
/// "Test gameplay"
/// </summary>
public static LocalisableString EditorTestGameplay => new TranslatableString(getKey(@"editor_test_gameplay"), @"Test gameplay");
/// <summary>
/// "Hold for HUD"
/// </summary>

View File

@ -0,0 +1,34 @@
// 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 osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface;
using osu.Game.Overlays;
namespace osu.Game.Screens.Edit.Components.Timelines.Summary
{
public class TestGameplayButton : OsuButton
{
protected override SpriteText CreateText() => new OsuSpriteText
{
Depth = -1,
Origin = Anchor.Centre,
Anchor = Anchor.Centre,
Font = OsuFont.TorusAlternate.With(weight: FontWeight.Light, size: 24),
Shadow = false
};
[BackgroundDependencyLoader]
private void load(OsuColour colours, OverlayColourProvider colourProvider)
{
BackgroundColour = colours.Orange1;
SpriteText.Colour = colourProvider.Background6;
Text = "Test!";
}
}
}

View File

@ -36,6 +36,7 @@ using osu.Game.Screens.Edit.Timing;
using osu.Game.Screens.Edit.Verify;
using osu.Game.Screens.Play;
using osu.Game.Users;
using osuTK;
using osuTK.Graphics;
using osuTK.Input;
@ -90,6 +91,8 @@ namespace osu.Game.Screens.Edit
private DependencyContainer dependencies;
private TestGameplayButton testGameplayButton;
private bool isNewBeatmap;
protected override UserActivity InitialActivity => new UserActivity.Editing(Beatmap.Value.BeatmapInfo);
@ -106,6 +109,9 @@ namespace osu.Game.Screens.Edit
[Cached]
public readonly EditorClipboard Clipboard = new EditorClipboard();
[Cached]
private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue);
public Editor(EditorLoader loader = null)
{
this.loader = loader;
@ -262,7 +268,8 @@ namespace osu.Game.Screens.Edit
{
new Dimension(GridSizeMode.Absolute, 220),
new Dimension(),
new Dimension(GridSizeMode.Absolute, 220)
new Dimension(GridSizeMode.Absolute, 220),
new Dimension(GridSizeMode.Absolute, 120),
},
Content = new[]
{
@ -283,6 +290,13 @@ namespace osu.Game.Screens.Edit
RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding { Left = 10 },
Child = new PlaybackControl { RelativeSizeAxes = Axes.Both },
},
testGameplayButton = new TestGameplayButton
{
RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding { Left = 10 },
Size = new Vector2(1),
Action = testGameplay
}
},
}
@ -456,6 +470,10 @@ namespace osu.Game.Screens.Edit
menuBar.Mode.Value = EditorScreenMode.Verify;
return true;
case GlobalAction.EditorTestGameplay:
testGameplayButton.TriggerClick();
return true;
default:
return false;
}
@ -510,7 +528,21 @@ namespace osu.Game.Screens.Edit
ApplyToBackground(b => b.FadeColour(Color4.White, 500));
resetTrack();
// To update the game-wide beatmap with any changes, perform a re-fetch on exit.
refetchBeatmap();
return base.OnExiting(next);
}
public override void OnSuspending(IScreen next)
{
refetchBeatmap();
base.OnSuspending(next);
}
private void refetchBeatmap()
{
// To update the game-wide beatmap with any changes, perform a re-fetch on exit/suspend.
// This is required as the editor makes its local changes via EditorBeatmap
// (which are not propagated outwards to a potentially cached WorkingBeatmap).
var refetchedBeatmap = beatmapManager.GetWorkingBeatmap(Beatmap.Value.BeatmapInfo);
@ -520,8 +552,6 @@ namespace osu.Game.Screens.Edit
Logger.Log("Editor providing re-fetched beatmap post edit session");
Beatmap.Value = refetchedBeatmap;
}
return base.OnExiting(next);
}
private void confirmExitWithSave()
@ -752,6 +782,24 @@ namespace osu.Game.Screens.Edit
loader?.CancelPendingDifficultySwitch();
}
private void testGameplay()
{
if (HasUnsavedChanges)
{
dialogOverlay.Push(new SaveBeforeGameplayTestDialog(() =>
{
Save();
pushEditorPlayer();
}));
}
else
{
pushEditorPlayer();
}
void pushEditorPlayer() => this.Push(new PlayerLoader(() => new EditorPlayer()));
}
public double SnapTime(double time, double? referenceTime) => editorBeatmap.SnapTime(time, referenceTime);
public double GetBeatLengthAtTime(double referenceTime) => editorBeatmap.GetBeatLengthAtTime(referenceTime);

View File

@ -0,0 +1,44 @@
// 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 osu.Framework.Allocation;
using osu.Framework.Screens;
using osu.Game.Overlays;
using osu.Game.Screens.Play;
namespace osu.Game.Screens.Edit
{
public class EditorPlayer : Player
{
public EditorPlayer()
: base(new PlayerConfiguration { ShowResults = false })
{
}
[Resolved]
private MusicController musicController { get; set; }
protected override void LoadComplete()
{
base.LoadComplete();
ScoreProcessor.HasCompleted.BindValueChanged(completed =>
{
if (completed.NewValue)
Scheduler.AddDelayed(this.Exit, RESULTS_DISPLAY_DELAY);
});
}
protected override void PrepareReplay()
{
// don't record replays.
}
protected override bool CheckModsAllowFailure() => false; // never fail.
public override bool OnExiting(IScreen next)
{
musicController.Stop();
return base.OnExiting(next);
}
}
}

View File

@ -6,6 +6,7 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics;
using osu.Game.Overlays;
namespace osu.Game.Screens.Edit
{
@ -26,7 +27,7 @@ namespace osu.Game.Screens.Edit
}
[BackgroundDependencyLoader]
private void load()
private void load(OverlayColourProvider colourProvider)
{
base.Content.Add(new Container
{
@ -41,7 +42,7 @@ namespace osu.Game.Screens.Edit
{
new Box
{
Colour = ColourProvider.Background3,
Colour = colourProvider.Background3,
RelativeSizeAxes = Axes.Both,
},
roundedContent = new Container

View File

@ -6,7 +6,6 @@ using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor;
using osu.Game.Overlays;
namespace osu.Game.Screens.Edit
{
@ -18,9 +17,6 @@ namespace osu.Game.Screens.Edit
[Resolved]
protected EditorBeatmap EditorBeatmap { get; private set; }
[Cached]
protected readonly OverlayColourProvider ColourProvider;
protected override Container<Drawable> Content => content;
private readonly Container content;
@ -34,8 +30,6 @@ namespace osu.Game.Screens.Edit
Origin = Anchor.Centre;
RelativeSizeAxes = Axes.Both;
ColourProvider = new OverlayColourProvider(OverlayColourScheme.Blue);
InternalChild = content = new PopoverContainer { RelativeSizeAxes = Axes.Both };
}

View File

@ -0,0 +1,32 @@
// 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 osu.Framework.Graphics.Sprites;
using osu.Game.Overlays.Dialog;
namespace osu.Game.Screens.Edit
{
public class SaveBeforeGameplayTestDialog : PopupDialog
{
public SaveBeforeGameplayTestDialog(Action saveAndPreview)
{
HeaderText = "The beatmap will be saved in order to test it.";
Icon = FontAwesome.Regular.Save;
Buttons = new PopupDialogButton[]
{
new PopupDialogOkButton
{
Text = "Sounds good, let's go!",
Action = saveAndPreview
},
new PopupDialogCancelButton
{
Text = "Oops, continue editing",
},
};
}
}
}