1
0
mirror of https://github.com/ppy/osu.git synced 2025-01-28 06:03:08 +08:00

Merge branch 'master' into fix-exporting-a-skin-with-too-long-file-name

This commit is contained in:
Cootz 2023-02-17 01:51:24 +03:00 committed by GitHub
commit 810712386d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 145 additions and 46 deletions

View File

@ -0,0 +1,31 @@
// 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 NUnit.Framework;
using osu.Game.Rulesets.Osu.Mods;
using osuTK.Input;
namespace osu.Game.Rulesets.Osu.Tests.Mods
{
public partial class TestSceneOsuModAutopilot : OsuModTestScene
{
[Test]
public void TestInstantResume()
{
CreateModTest(new ModTestData
{
Mod = new OsuModAutopilot(),
PassCondition = () => true,
Autoplay = false,
});
AddUntilStep("wait for gameplay start", () => Player.LocalUserPlaying.Value);
AddStep("press pause", () => InputManager.PressKey(Key.Escape));
AddUntilStep("wait until paused", () => Player.GameplayClockContainer.IsPaused.Value);
AddStep("release pause", () => InputManager.ReleaseKey(Key.Escape));
AddStep("press resume", () => InputManager.PressKey(Key.Escape));
AddUntilStep("wait for resume", () => !Player.IsResuming);
AddAssert("resumed", () => !Player.GameplayClockContainer.IsPaused.Value);
}
}
}

View File

@ -60,6 +60,8 @@ namespace osu.Game.Rulesets.Osu.Mods
// Generate the replay frames the cursor should follow // Generate the replay frames the cursor should follow
replayFrames = new OsuAutoGenerator(drawableRuleset.Beatmap, drawableRuleset.Mods).Generate().Frames.Cast<OsuReplayFrame>().ToList(); replayFrames = new OsuAutoGenerator(drawableRuleset.Beatmap, drawableRuleset.Mods).Generate().Frames.Cast<OsuReplayFrame>().ToList();
drawableRuleset.UseResumeOverlay = false;
} }
} }
} }

View File

@ -1,10 +1,12 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // 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. // See the LICENCE file in the repository root for full licence text.
#nullable disable using System.Diagnostics;
using System.Linq; using System.Linq;
using NUnit.Framework; using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Timing;
using osu.Game.Audio; using osu.Game.Audio;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints; using osu.Game.Beatmaps.ControlPoints;
@ -14,16 +16,23 @@ using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI;
using osu.Game.Storyboards;
using osuTK.Input; using osuTK.Input;
namespace osu.Game.Tests.Visual.Gameplay namespace osu.Game.Tests.Visual.Gameplay
{ {
public partial class TestSceneGameplaySampleTriggerSource : PlayerTestScene public partial class TestSceneGameplaySampleTriggerSource : PlayerTestScene
{ {
private TestGameplaySampleTriggerSource sampleTriggerSource; private TestGameplaySampleTriggerSource sampleTriggerSource = null!;
protected override Ruleset CreatePlayerRuleset() => new OsuRuleset(); protected override Ruleset CreatePlayerRuleset() => new OsuRuleset();
private Beatmap beatmap; private Beatmap beatmap = null!;
[Resolved]
private AudioManager audio { get; set; } = null!;
protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap, Storyboard? storyboard = null)
=> new ClockBackedTestWorkingBeatmap(beatmap, storyboard, new FramedClock(new ManualClock { Rate = 1 }), audio);
protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) protected override IBeatmap CreateBeatmap(RulesetInfo ruleset)
{ {
@ -39,12 +48,13 @@ namespace osu.Game.Tests.Visual.Gameplay
const double start_offset = 8000; const double start_offset = 8000;
const double spacing = 2000; const double spacing = 2000;
// intentionally start objects a bit late so we can test the case of no alive objects.
double t = start_offset; double t = start_offset;
beatmap.HitObjects.AddRange(new[] beatmap.HitObjects.AddRange(new[]
{ {
new HitCircle new HitCircle
{ {
// intentionally start objects a bit late so we can test the case of no alive objects.
StartTime = t += spacing, StartTime = t += spacing,
Samples = new[] { new HitSampleInfo(HitSampleInfo.HIT_NORMAL) } Samples = new[] { new HitSampleInfo(HitSampleInfo.HIT_NORMAL) }
}, },
@ -80,42 +90,66 @@ namespace osu.Game.Tests.Visual.Gameplay
[Test] [Test]
public void TestCorrectHitObject() public void TestCorrectHitObject()
{ {
HitObjectLifetimeEntry nextObjectEntry = null; waitForAliveObjectIndex(null);
checkValidObjectIndex(0);
AddAssert("no alive objects", () => getNextAliveObject() == null); seekBeforeIndex(0);
waitForAliveObjectIndex(0);
checkValidObjectIndex(0);
AddAssert("check initially correct object", () => sampleTriggerSource.GetMostValidObject() == beatmap.HitObjects[0]); AddAssert("first object not hit", () => getNextAliveObject()?.Entry?.Result?.HasResult != true);
AddUntilStep("get next object", () => AddStep("hit first object", () =>
{ {
var nextDrawableObject = getNextAliveObject(); var next = getNextAliveObject();
if (nextDrawableObject != null) if (next != null)
{ {
nextObjectEntry = nextDrawableObject.Entry; Debug.Assert(next.Entry?.Result?.HasResult != true);
InputManager.MoveMouseTo(nextDrawableObject.ScreenSpaceDrawQuad.Centre);
return true; InputManager.MoveMouseTo(next.ScreenSpaceDrawQuad.Centre);
InputManager.Click(MouseButton.Left);
} }
return false;
}); });
AddUntilStep("hit first hitobject", () => AddAssert("first object hit", () => getNextAliveObject()?.Entry?.Result?.HasResult == true);
{
InputManager.Click(MouseButton.Left);
return nextObjectEntry.Result?.HasResult == true;
});
AddAssert("check correct object after hit", () => sampleTriggerSource.GetMostValidObject() == beatmap.HitObjects[1]); checkValidObjectIndex(1);
AddUntilStep("check correct object after miss", () => sampleTriggerSource.GetMostValidObject() == beatmap.HitObjects[2]); // Still object 1 as it's not hit yet.
AddUntilStep("check correct object after miss", () => sampleTriggerSource.GetMostValidObject() == beatmap.HitObjects[3]); seekBeforeIndex(1);
waitForAliveObjectIndex(1);
checkValidObjectIndex(1);
AddUntilStep("no alive objects", () => getNextAliveObject() == null); seekBeforeIndex(2);
AddAssert("check correct object after none alive", () => sampleTriggerSource.GetMostValidObject() == beatmap.HitObjects[3]); waitForAliveObjectIndex(2);
checkValidObjectIndex(2);
seekBeforeIndex(3);
waitForAliveObjectIndex(3);
checkValidObjectIndex(3);
AddStep("Seek into future", () => Beatmap.Value.Track.Seek(beatmap.HitObjects.Last().GetEndTime() + 10000));
waitForAliveObjectIndex(null);
checkValidObjectIndex(3);
} }
private DrawableHitObject getNextAliveObject() => private void seekBeforeIndex(int index) =>
AddStep($"seek to just before object {index}", () => Beatmap.Value.Track.Seek(beatmap.HitObjects[index].StartTime - 100));
private void waitForAliveObjectIndex(int? index)
{
if (index == null)
AddUntilStep("wait for no alive objects", getNextAliveObject, () => Is.Null);
else
AddUntilStep($"wait for next alive to be {index}", () => getNextAliveObject()?.HitObject, () => Is.EqualTo(beatmap.HitObjects[index.Value]));
}
private void checkValidObjectIndex(int index) =>
AddAssert($"check valid object is {index}", () => sampleTriggerSource.GetMostValidObject(), () => Is.EqualTo(beatmap.HitObjects[index]));
private DrawableHitObject? getNextAliveObject() =>
Player.DrawableRuleset.Playfield.HitObjectContainer.AliveObjects.FirstOrDefault(); Player.DrawableRuleset.Playfield.HitObjectContainer.AliveObjects.FirstOrDefault();
[Test] [Test]

View File

@ -21,7 +21,7 @@ namespace osu.Game.Graphics.Containers
/// </summary> /// </summary>
public const float BREAK_LIGHTEN_AMOUNT = 0.3f; public const float BREAK_LIGHTEN_AMOUNT = 0.3f;
protected const double BACKGROUND_FADE_DURATION = 800; public const double BACKGROUND_FADE_DURATION = 800;
/// <summary> /// <summary>
/// Whether or not user-configured settings relating to brightness of elements should be ignored /// Whether or not user-configured settings relating to brightness of elements should be ignored

View File

@ -230,7 +230,7 @@ namespace osu.Game.Rulesets.UI
public override void RequestResume(Action continueResume) public override void RequestResume(Action continueResume)
{ {
if (ResumeOverlay != null && (Cursor == null || (Cursor.LastFrameState == Visibility.Visible && Contains(Cursor.ActiveCursor.ScreenSpaceDrawQuad.Centre)))) if (ResumeOverlay != null && UseResumeOverlay && (Cursor == null || (Cursor.LastFrameState == Visibility.Visible && Contains(Cursor.ActiveCursor.ScreenSpaceDrawQuad.Centre))))
{ {
ResumeOverlay.GameplayCursor = Cursor; ResumeOverlay.GameplayCursor = Cursor;
ResumeOverlay.ResumeAction = continueResume; ResumeOverlay.ResumeAction = continueResume;
@ -507,6 +507,15 @@ namespace osu.Game.Rulesets.UI
/// </summary> /// </summary>
public ResumeOverlay ResumeOverlay { get; protected set; } public ResumeOverlay ResumeOverlay { get; protected set; }
/// <summary>
/// Whether the <see cref="ResumeOverlay"/> should be used to return the user's cursor position to its previous location after a pause.
/// </summary>
/// <remarks>
/// Defaults to <c>true</c>.
/// Even if <c>true</c>, will not have any effect if the ruleset does not have a resume overlay (see <see cref="CreateResumeOverlay"/>).
/// </remarks>
public bool UseResumeOverlay { get; set; } = true;
/// <summary> /// <summary>
/// Returns first available <see cref="HitWindows"/> provided by a <see cref="HitObject"/>. /// Returns first available <see cref="HitWindows"/> provided by a <see cref="HitObject"/>.
/// </summary> /// </summary>
@ -531,6 +540,11 @@ namespace osu.Game.Rulesets.UI
} }
} }
/// <summary>
/// Create an optional resume overlay, which is displayed when a player requests to resume gameplay during non-break time.
/// This can be used to force the player to return their hands / cursor to the position they left off, to avoid players
/// using pauses as a means of adjusting their inputs (aka "pause buffering").
/// </summary>
protected virtual ResumeOverlay CreateResumeOverlay() => null; protected virtual ResumeOverlay CreateResumeOverlay() => null;
/// <summary> /// <summary>

View File

@ -417,7 +417,7 @@ namespace osu.Game.Screens.Play
lowPassFilter.CutoffTo(1000, 650, Easing.OutQuint); lowPassFilter.CutoffTo(1000, 650, Easing.OutQuint);
highPassFilter.CutoffTo(300).Then().CutoffTo(0, 1250); // 1250 is to line up with the appearance of MetadataInfo (750 delay + 500 fade-in) highPassFilter.CutoffTo(300).Then().CutoffTo(0, 1250); // 1250 is to line up with the appearance of MetadataInfo (750 delay + 500 fade-in)
ApplyToBackground(b => b?.FadeColour(Color4.White, 800, Easing.OutQuint)); ApplyToBackground(b => b.FadeColour(Color4.White, 800, Easing.OutQuint));
} }
protected virtual void ContentOut() protected virtual void ContentOut()

View File

@ -1,9 +1,9 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // 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. // See the LICENCE file in the repository root for full licence text.
#nullable disable
using System; using System;
using System.Diagnostics;
using osu.Framework.Screens;
using osu.Game.Screens.Backgrounds; using osu.Game.Screens.Backgrounds;
namespace osu.Game.Screens.Play namespace osu.Game.Screens.Play
@ -12,6 +12,11 @@ namespace osu.Game.Screens.Play
{ {
protected override BackgroundScreen CreateBackground() => new BackgroundScreenBeatmap(Beatmap.Value); protected override BackgroundScreen CreateBackground() => new BackgroundScreenBeatmap(Beatmap.Value);
public void ApplyToBackground(Action<BackgroundScreenBeatmap> action) => base.ApplyToBackground(b => action.Invoke((BackgroundScreenBeatmap)b)); public void ApplyToBackground(Action<BackgroundScreenBeatmap> action)
{
Debug.Assert(this.IsCurrentScreen());
base.ApplyToBackground(b => action.Invoke((BackgroundScreenBeatmap)b));
}
} }
} }

View File

@ -31,6 +31,7 @@ using osu.Game.Overlays;
using osu.Game.Overlays.Mods; using osu.Game.Overlays.Mods;
using osu.Game.Rulesets; using osu.Game.Rulesets;
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
using osu.Game.Screens.Backgrounds;
using osu.Game.Screens.Edit; using osu.Game.Screens.Edit;
using osu.Game.Screens.Menu; using osu.Game.Screens.Menu;
using osu.Game.Screens.Play; using osu.Game.Screens.Play;
@ -148,7 +149,7 @@ namespace osu.Game.Screens.Select
if (!this.IsCurrentScreen()) if (!this.IsCurrentScreen())
return; return;
ApplyToBackground(b => b.BlurAmount.Value = e.NewValue ? BACKGROUND_BLUR : 0); ApplyToBackground(applyBlurToBackground);
}); });
LoadComponentAsync(Carousel = new BeatmapCarousel LoadComponentAsync(Carousel = new BeatmapCarousel
@ -194,6 +195,7 @@ namespace osu.Game.Screens.Select
{ {
ParallaxAmount = 0.005f, ParallaxAmount = 0.005f,
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Alpha = 0,
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
Child = new WedgeBackground Child = new WedgeBackground
@ -763,12 +765,18 @@ namespace osu.Game.Screens.Select
/// <param name="beatmap">The working beatmap.</param> /// <param name="beatmap">The working beatmap.</param>
private void updateComponentFromBeatmap(WorkingBeatmap beatmap) private void updateComponentFromBeatmap(WorkingBeatmap beatmap)
{ {
ApplyToBackground(backgroundModeBeatmap => // If not the current screen, this will be applied in OnResuming.
if (this.IsCurrentScreen())
{ {
backgroundModeBeatmap.Beatmap = beatmap; ApplyToBackground(backgroundModeBeatmap =>
backgroundModeBeatmap.BlurAmount.Value = configBackgroundBlur.Value ? BACKGROUND_BLUR : 0f; {
backgroundModeBeatmap.FadeColour(Color4.White, 250); backgroundModeBeatmap.Beatmap = beatmap;
}); backgroundModeBeatmap.IgnoreUserSettings.Value = true;
backgroundModeBeatmap.FadeColour(Color4.White, 250);
applyBlurToBackground(backgroundModeBeatmap);
});
}
beatmapInfoWedge.Beatmap = beatmap; beatmapInfoWedge.Beatmap = beatmap;
@ -785,6 +793,14 @@ namespace osu.Game.Screens.Select
} }
} }
private void applyBlurToBackground(BackgroundScreenBeatmap backgroundModeBeatmap)
{
backgroundModeBeatmap.BlurAmount.Value = configBackgroundBlur.Value ? BACKGROUND_BLUR : 0f;
backgroundModeBeatmap.DimWhenUserSettingsIgnored.Value = configBackgroundBlur.Value ? 0 : 0.4f;
wedgeBackground.FadeTo(configBackgroundBlur.Value ? 0.5f : 0.2f, UserDimContainer.BACKGROUND_FADE_DURATION, Easing.OutQuint);
}
private readonly WeakReference<ITrack?> lastTrack = new WeakReference<ITrack?>(null); private readonly WeakReference<ITrack?> lastTrack = new WeakReference<ITrack?>(null);
/// <summary> /// <summary>

View File

@ -1,14 +1,11 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // 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. // See the LICENCE file in the repository root for full licence text.
#nullable disable
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osuTK; using osuTK;
using osuTK.Graphics; using osuTK.Graphics;
using osu.Framework.Graphics.Shapes;
namespace osu.Game.Screens.Select namespace osu.Game.Screens.Select
{ {
@ -22,7 +19,7 @@ namespace osu.Game.Screens.Select
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Size = new Vector2(1, 0.5f), Size = new Vector2(1, 0.5f),
Colour = Color4.Black.Opacity(0.5f), Colour = Color4.Black,
Shear = new Vector2(0.15f, 0), Shear = new Vector2(0.15f, 0),
EdgeSmoothness = new Vector2(2, 0), EdgeSmoothness = new Vector2(2, 0),
}, },
@ -32,7 +29,7 @@ namespace osu.Game.Screens.Select
RelativePositionAxes = Axes.Y, RelativePositionAxes = Axes.Y,
Size = new Vector2(1, -0.5f), Size = new Vector2(1, -0.5f),
Position = new Vector2(0, 1), Position = new Vector2(0, 1),
Colour = Color4.Black.Opacity(0.5f), Colour = Color4.Black,
Shear = new Vector2(-0.15f, 0), Shear = new Vector2(-0.15f, 0),
EdgeSmoothness = new Vector2(2, 0), EdgeSmoothness = new Vector2(2, 0),
}, },

View File

@ -66,7 +66,7 @@ namespace osu.Game.Tests.Visual
protected override bool CheckModsAllowFailure() => allowFail; protected override bool CheckModsAllowFailure() => allowFail;
public ModTestPlayer(ModTestData data, bool allowFail) public ModTestPlayer(ModTestData data, bool allowFail)
: base(false, false) : base(true, false)
{ {
this.allowFail = allowFail; this.allowFail = allowFail;
currentTestData = data; currentTestData = data;