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

Merge branch 'master' into master

This commit is contained in:
Bartłomiej Dach 2023-05-14 19:45:31 +02:00 committed by GitHub
commit a6ddb107cd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 200 additions and 22 deletions

View File

@ -11,7 +11,7 @@
<AndroidManifestMerger>manifestmerger.jar</AndroidManifestMerger>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="ppy.osu.Framework.Android" Version="2023.510.0" />
<PackageReference Include="ppy.osu.Framework.Android" Version="2023.513.0" />
</ItemGroup>
<ItemGroup>
<AndroidManifestOverlay Include="$(MSBuildThisFileDirectory)osu.Android\Properties\AndroidManifestOverlay.xml" />

View File

@ -17,6 +17,8 @@ namespace osu.Game.Rulesets.Catch.Edit.Blueprints
private double placementStartTime;
private double placementEndTime;
protected override bool IsValidForPlacement => HitObject.Duration > 0;
public BananaShowerPlacementBlueprint()
{
InternalChild = outline = new TimeSpanOutline();
@ -49,7 +51,7 @@ namespace osu.Game.Rulesets.Catch.Edit.Blueprints
case PlacementState.Active:
if (e.Button != MouseButton.Right) break;
EndPlacement(HitObject.Duration > 0);
EndPlacement(true);
return true;
}

View File

@ -24,6 +24,8 @@ namespace osu.Game.Rulesets.Catch.Edit.Blueprints
private InputManager inputManager = null!;
protected override bool IsValidForPlacement => HitObject.Duration > 0;
public JuiceStreamPlacementBlueprint()
{
InternalChildren = new Drawable[]
@ -70,7 +72,7 @@ namespace osu.Game.Rulesets.Catch.Edit.Blueprints
return true;
case MouseButton.Right:
EndPlacement(HitObject.Duration > 0);
EndPlacement(true);
return true;
}

View File

@ -25,6 +25,8 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints
[Resolved]
private IScrollingInfo scrollingInfo { get; set; }
protected override bool IsValidForPlacement => HitObject.Duration > 0;
public HoldNotePlacementBlueprint()
: base(new HoldNote())
{
@ -75,7 +77,7 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints
return;
base.OnMouseUp(e);
EndPlacement(HitObject.Duration > 0);
EndPlacement(true);
}
private double originalStartTime;

View File

@ -41,6 +41,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
[Resolved(CanBeNull = true)]
private IDistanceSnapProvider snapProvider { get; set; }
protected override bool IsValidForPlacement => HitObject.Path.HasValidLength;
public SliderPlacementBlueprint()
: base(new Slider())
{
@ -150,7 +152,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
private void endCurve()
{
updateSlider();
EndPlacement(HitObject.Path.HasValidLength);
EndPlacement(true);
}
protected override void Update()

View File

@ -98,6 +98,7 @@ namespace osu.Game.Rulesets.Osu.Mods
ComboOffset = original.ComboOffset;
LegacyLastTickOffset = original.LegacyLastTickOffset;
TickDistanceMultiplier = original.TickDistanceMultiplier;
SliderVelocity = original.SliderVelocity;
}
protected override void CreateNestedHitObjects(CancellationToken cancellationToken)

View File

@ -25,6 +25,8 @@ namespace osu.Game.Rulesets.Taiko.Edit.Blueprints
private readonly IHasDuration spanPlacementObject;
protected override bool IsValidForPlacement => spanPlacementObject.Duration > 0;
public TaikoSpanPlacementBlueprint(HitObject hitObject)
: base(hitObject)
{
@ -73,7 +75,7 @@ namespace osu.Game.Rulesets.Taiko.Edit.Blueprints
return;
base.OnMouseUp(e);
EndPlacement(spanPlacementObject.Duration > 0);
EndPlacement(true);
}
public override void UpdateTimeAndPosition(SnapResult result)

View File

@ -0,0 +1,106 @@
// 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.Linq;
using NUnit.Framework;
using osu.Framework.Screens;
using osu.Framework.Testing;
using osu.Game.Beatmaps;
using osu.Game.Input.Bindings;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.UI;
using osu.Game.Screens.Edit.Compose.Components;
using osu.Game.Tests.Beatmaps;
using osuTK.Input;
namespace osu.Game.Tests.Visual.Editing
{
public partial class TestScenePlacementBlueprint : EditorTestScene
{
protected override Ruleset CreateEditorRuleset() => new OsuRuleset();
protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) => new TestBeatmap(ruleset, false);
private GlobalActionContainer globalActionContainer => this.ChildrenOfType<GlobalActionContainer>().Single();
[Test]
public void TestCommitPlacementViaGlobalAction()
{
Playfield playfield = null!;
AddStep("select slider placement tool", () => InputManager.Key(Key.Number3));
AddStep("move mouse to top left of playfield", () =>
{
playfield = this.ChildrenOfType<Playfield>().Single();
var location = (3 * playfield.ScreenSpaceDrawQuad.TopLeft + playfield.ScreenSpaceDrawQuad.BottomRight) / 4;
InputManager.MoveMouseTo(location);
});
AddStep("begin placement", () => InputManager.Click(MouseButton.Left));
AddStep("move mouse to bottom right of playfield", () =>
{
var location = (playfield.ScreenSpaceDrawQuad.TopLeft + 3 * playfield.ScreenSpaceDrawQuad.BottomRight) / 4;
InputManager.MoveMouseTo(location);
});
AddStep("confirm via global action", () =>
{
globalActionContainer.TriggerPressed(GlobalAction.Select);
globalActionContainer.TriggerReleased(GlobalAction.Select);
});
AddAssert("slider placed", () => EditorBeatmap.HitObjects.Count, () => Is.EqualTo(1));
}
[Test]
public void TestAbortPlacementViaGlobalAction()
{
Playfield playfield = null!;
AddStep("select slider placement tool", () => InputManager.Key(Key.Number3));
AddStep("move mouse to top left of playfield", () =>
{
playfield = this.ChildrenOfType<Playfield>().Single();
var location = (3 * playfield.ScreenSpaceDrawQuad.TopLeft + playfield.ScreenSpaceDrawQuad.BottomRight) / 4;
InputManager.MoveMouseTo(location);
});
AddStep("begin placement", () => InputManager.Click(MouseButton.Left));
AddStep("move mouse to bottom right of playfield", () =>
{
var location = (playfield.ScreenSpaceDrawQuad.TopLeft + 3 * playfield.ScreenSpaceDrawQuad.BottomRight) / 4;
InputManager.MoveMouseTo(location);
});
AddStep("abort via global action", () =>
{
globalActionContainer.TriggerPressed(GlobalAction.Back);
globalActionContainer.TriggerReleased(GlobalAction.Back);
});
AddAssert("editor is still current", () => Editor.IsCurrentScreen());
AddAssert("slider not placed", () => EditorBeatmap.HitObjects.Count, () => Is.EqualTo(0));
AddAssert("no active placement", () => this.ChildrenOfType<ComposeBlueprintContainer>().Single().CurrentPlacement.PlacementActive,
() => Is.EqualTo(PlacementBlueprint.PlacementState.Waiting));
}
[Test]
public void TestCommitPlacementViaToolChange()
{
Playfield playfield = null!;
AddStep("select slider placement tool", () => InputManager.Key(Key.Number3));
AddStep("move mouse to top left of playfield", () =>
{
playfield = this.ChildrenOfType<Playfield>().Single();
var location = (3 * playfield.ScreenSpaceDrawQuad.TopLeft + playfield.ScreenSpaceDrawQuad.BottomRight) / 4;
InputManager.MoveMouseTo(location);
});
AddStep("begin placement", () => InputManager.Click(MouseButton.Left));
AddStep("move mouse to bottom right of playfield", () =>
{
var location = (playfield.ScreenSpaceDrawQuad.TopLeft + 3 * playfield.ScreenSpaceDrawQuad.BottomRight) / 4;
InputManager.MoveMouseTo(location);
});
AddStep("change tool to circle", () => InputManager.Key(Key.Number2));
AddAssert("slider placed", () => EditorBeatmap.HitObjects.Count, () => Is.EqualTo(1));
}
}
}

View File

@ -3,6 +3,7 @@
#nullable disable
using osu.Framework.Bindables;
using osu.Framework.Input;
using osuTK.Input;
@ -10,6 +11,10 @@ namespace osu.Game.Input
{
public partial class OsuUserInputManager : UserInputManager
{
protected override bool AllowRightClickFromLongTouch => !LocalUserPlaying.Value;
public readonly BindableBool LocalUserPlaying = new BindableBool();
internal OsuUserInputManager()
{
}

View File

@ -269,6 +269,13 @@ namespace osu.Game
if (hideToolbar) Toolbar.Hide();
}
protected override UserInputManager CreateUserInputManager()
{
var userInputManager = base.CreateUserInputManager();
(userInputManager as OsuUserInputManager)?.LocalUserPlaying.BindTo(LocalUserPlaying);
return userInputManager;
}
private DependencyContainer dependencies;
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) =>

View File

@ -3,6 +3,8 @@
#nullable disable
using System.Collections.Generic;
using System.Linq;
using osu.Framework;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
@ -23,6 +25,8 @@ namespace osu.Game.Overlays.Settings.Sections.Input
{
public partial class TabletSettings : SettingsSubsection
{
public override IEnumerable<LocalisableString> FilterTerms => base.FilterTerms.Concat(new LocalisableString[] { "area" });
public TabletAreaSelection AreaSelection { get; private set; }
private readonly ITabletHandler tabletHandler;

View File

@ -9,10 +9,12 @@ using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Input.Bindings;
using osu.Framework.Input.Events;
using osu.Game.Audio;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Input.Bindings;
using osu.Game.Rulesets.Objects;
using osu.Game.Screens.Edit;
using osu.Game.Screens.Edit.Compose;
@ -24,7 +26,7 @@ namespace osu.Game.Rulesets.Edit
/// <summary>
/// A blueprint which governs the creation of a new <see cref="HitObject"/> to actualisation.
/// </summary>
public abstract partial class PlacementBlueprint : CompositeDrawable
public abstract partial class PlacementBlueprint : CompositeDrawable, IKeyBindingHandler<GlobalAction>
{
/// <summary>
/// Whether the <see cref="HitObject"/> is currently mid-placement, but has not necessarily finished being placed.
@ -47,6 +49,15 @@ namespace osu.Game.Rulesets.Edit
[Resolved]
private IPlacementHandler placementHandler { get; set; }
/// <summary>
/// Whether this blueprint is currently in a state that can be committed.
/// </summary>
/// <remarks>
/// Override this with any preconditions that should be double-checked on committing.
/// If <c>false</c> is returned and a commit is attempted, the blueprint will be destroyed instead.
/// </remarks>
protected virtual bool IsValidForPlacement => true;
protected PlacementBlueprint(HitObject hitObject)
{
HitObject = hitObject;
@ -88,7 +99,7 @@ namespace osu.Game.Rulesets.Edit
/// Signals that the placement of <see cref="HitObject"/> has finished.
/// This will destroy this <see cref="PlacementBlueprint"/>, and add the HitObject.StartTime to the <see cref="Beatmap"/>.
/// </summary>
/// <param name="commit">Whether the object should be committed.</param>
/// <param name="commit">Whether the object should be committed. Note that a commit may fail if <see cref="IsValidForPlacement"/> is <c>false</c>.</param>
public void EndPlacement(bool commit)
{
switch (PlacementActive)
@ -102,10 +113,34 @@ namespace osu.Game.Rulesets.Edit
break;
}
placementHandler.EndPlacement(HitObject, commit);
placementHandler.EndPlacement(HitObject, IsValidForPlacement && commit);
PlacementActive = PlacementState.Finished;
}
public bool OnPressed(KeyBindingPressEvent<GlobalAction> e)
{
if (PlacementActive == PlacementState.Waiting)
return false;
switch (e.Action)
{
case GlobalAction.Select:
EndPlacement(true);
return true;
case GlobalAction.Back:
EndPlacement(false);
return true;
default:
return false;
}
}
public void OnReleased(KeyBindingReleaseEvent<GlobalAction> e)
{
}
/// <summary>
/// Updates the time and position of this <see cref="PlacementBlueprint"/> based on the provided snap information.
/// </summary>

View File

@ -28,6 +28,8 @@ namespace osu.Game.Rulesets.UI
public abstract partial class RulesetInputManager<T> : PassThroughInputManager, ICanAttachHUDPieces, IHasReplayHandler, IHasRecordingHandler
where T : struct
{
protected override bool AllowRightClickFromLongTouch => false;
public readonly KeyBindingContainer<T> KeyBindingContainer;
[Resolved(CanBeNull = true)]

View File

@ -317,12 +317,16 @@ namespace osu.Game.Screens.Edit.Compose.Components
}
}
private void commitIfPlacementActive()
{
CurrentPlacement?.EndPlacement(CurrentPlacement.PlacementActive == PlacementBlueprint.PlacementState.Active);
removePlacement();
}
private void removePlacement()
{
if (CurrentPlacement == null) return;
CurrentPlacement.EndPlacement(false);
CurrentPlacement.Expire();
CurrentPlacement?.EndPlacement(false);
CurrentPlacement?.Expire();
CurrentPlacement = null;
}
@ -342,7 +346,8 @@ namespace osu.Game.Screens.Edit.Compose.Components
currentTool = value;
refreshTool();
// As per stable editor, when changing tools, we should forcefully commit any pending placement.
commitIfPlacementActive();
}
}
}

View File

@ -15,6 +15,7 @@ using osuTK;
using osuTK.Graphics;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Allocation;
using osu.Framework.Layout;
using osu.Framework.Threading;
namespace osu.Game.Screens.Play
@ -51,7 +52,7 @@ namespace osu.Game.Screens.Play
if (value == values) return;
values = value;
graphNeedsUpdate = true;
layout.Invalidate();
}
}
@ -71,23 +72,25 @@ namespace osu.Game.Screens.Play
private ScheduledDelegate scheduledCreate;
private bool graphNeedsUpdate;
private readonly LayoutValue layout = new LayoutValue(Invalidation.DrawSize | Invalidation.DrawInfo);
private Vector2 previousDrawSize;
public SquareGraph()
{
AddLayout(layout);
}
protected override void Update()
{
base.Update();
if (graphNeedsUpdate || (values != null && DrawSize != previousDrawSize))
if (!layout.IsValid)
{
columns?.FadeOut(500, Easing.OutQuint).Expire();
scheduledCreate?.Cancel();
scheduledCreate = Scheduler.AddDelayed(RecreateGraph, 500);
previousDrawSize = DrawSize;
graphNeedsUpdate = false;
layout.Validate();
}
}

View File

@ -36,7 +36,7 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Realm" Version="10.20.0" />
<PackageReference Include="ppy.osu.Framework" Version="2023.510.0" />
<PackageReference Include="ppy.osu.Framework" Version="2023.513.0" />
<PackageReference Include="ppy.osu.Game.Resources" Version="2023.510.0" />
<PackageReference Include="Sentry" Version="3.28.1" />
<PackageReference Include="SharpCompress" Version="0.32.2" />

View File

@ -16,6 +16,6 @@
<RuntimeIdentifier>iossimulator-x64</RuntimeIdentifier>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="ppy.osu.Framework.iOS" Version="2023.510.0" />
<PackageReference Include="ppy.osu.Framework.iOS" Version="2023.513.0" />
</ItemGroup>
</Project>