mirror of
https://github.com/ppy/osu
synced 2025-01-01 03:42:19 +00:00
Merge branch 'master' into comment-mapper-pill
This commit is contained in:
commit
3f46e1afc3
@ -1,111 +0,0 @@
|
|||||||
// 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.
|
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using System.Linq;
|
|
||||||
using NUnit.Framework;
|
|
||||||
using osu.Framework.Bindables;
|
|
||||||
using osu.Framework.Graphics;
|
|
||||||
using osu.Framework.Graphics.Containers;
|
|
||||||
using osu.Framework.Testing;
|
|
||||||
using osu.Framework.Utils;
|
|
||||||
using osu.Game.Beatmaps;
|
|
||||||
using osu.Game.Beatmaps.ControlPoints;
|
|
||||||
using osu.Game.Rulesets.Catch.Judgements;
|
|
||||||
using osu.Game.Rulesets.Catch.Objects;
|
|
||||||
using osu.Game.Rulesets.Catch.Objects.Drawables;
|
|
||||||
using osu.Game.Rulesets.Catch.Skinning;
|
|
||||||
using osu.Game.Rulesets.Catch.UI;
|
|
||||||
using osu.Game.Skinning;
|
|
||||||
using osu.Game.Tests.Visual;
|
|
||||||
using Direction = osu.Game.Rulesets.Catch.UI.Direction;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch.Tests
|
|
||||||
{
|
|
||||||
public partial class TestSceneCatchSkinConfiguration : OsuTestScene
|
|
||||||
{
|
|
||||||
private Catcher catcher;
|
|
||||||
|
|
||||||
private readonly Container container;
|
|
||||||
|
|
||||||
public TestSceneCatchSkinConfiguration()
|
|
||||||
{
|
|
||||||
Add(container = new Container { RelativeSizeAxes = Axes.Both });
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestCase(false)]
|
|
||||||
[TestCase(true)]
|
|
||||||
public void TestCatcherPlateFlipping(bool flip)
|
|
||||||
{
|
|
||||||
AddStep("setup catcher", () =>
|
|
||||||
{
|
|
||||||
var skin = new TestSkin { FlipCatcherPlate = flip };
|
|
||||||
container.Child = new SkinProvidingContainer(skin)
|
|
||||||
{
|
|
||||||
Child = catcher = new Catcher(new DroppedObjectContainer())
|
|
||||||
{
|
|
||||||
Anchor = Anchor.Centre
|
|
||||||
}
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
Fruit fruit = new Fruit();
|
|
||||||
|
|
||||||
AddStep("catch fruit", () => catchFruit(fruit, 20));
|
|
||||||
|
|
||||||
float position = 0;
|
|
||||||
|
|
||||||
AddStep("record fruit position", () => position = getCaughtObjectPosition(fruit));
|
|
||||||
|
|
||||||
AddStep("face left", () => catcher.VisualDirection = Direction.Left);
|
|
||||||
|
|
||||||
if (flip)
|
|
||||||
AddAssert("fruit position changed", () => !Precision.AlmostEquals(getCaughtObjectPosition(fruit), position));
|
|
||||||
else
|
|
||||||
AddAssert("fruit position unchanged", () => Precision.AlmostEquals(getCaughtObjectPosition(fruit), position));
|
|
||||||
|
|
||||||
AddStep("face right", () => catcher.VisualDirection = Direction.Right);
|
|
||||||
|
|
||||||
AddAssert("fruit position restored", () => Precision.AlmostEquals(getCaughtObjectPosition(fruit), position));
|
|
||||||
}
|
|
||||||
|
|
||||||
private float getCaughtObjectPosition(Fruit fruit)
|
|
||||||
{
|
|
||||||
var caughtObject = catcher.ChildrenOfType<CaughtObject>().Single(c => c.HitObject == fruit);
|
|
||||||
return caughtObject.Parent!.ToSpaceOfOtherDrawable(caughtObject.Position, catcher).X;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void catchFruit(Fruit fruit, float x)
|
|
||||||
{
|
|
||||||
fruit.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
|
|
||||||
var drawableFruit = new DrawableFruit(fruit) { X = x };
|
|
||||||
var judgement = fruit.CreateJudgement();
|
|
||||||
catcher.OnNewResult(drawableFruit, new CatchJudgementResult(fruit, judgement)
|
|
||||||
{
|
|
||||||
Type = judgement.MaxResult
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private class TestSkin : TrianglesSkin
|
|
||||||
{
|
|
||||||
public bool FlipCatcherPlate { get; set; }
|
|
||||||
|
|
||||||
public TestSkin()
|
|
||||||
: base(null!)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public override IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup)
|
|
||||||
{
|
|
||||||
if (lookup is CatchSkinConfiguration config)
|
|
||||||
{
|
|
||||||
if (config == CatchSkinConfiguration.FlipCatcherPlate)
|
|
||||||
return SkinUtils.As<TValue>(new Bindable<bool>(FlipCatcherPlate));
|
|
||||||
}
|
|
||||||
|
|
||||||
return base.GetConfig<TLookup, TValue>(lookup);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,13 +0,0 @@
|
|||||||
// 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.
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch.Skinning
|
|
||||||
{
|
|
||||||
public enum CatchSkinConfiguration
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Whether the contents of the catcher plate should be visually flipped when the catcher direction is changed.
|
|
||||||
/// </summary>
|
|
||||||
FlipCatcherPlate
|
|
||||||
}
|
|
||||||
}
|
|
@ -122,19 +122,6 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy
|
|||||||
|
|
||||||
result.Value = LegacyColourCompatibility.DisallowZeroAlpha(result.Value);
|
result.Value = LegacyColourCompatibility.DisallowZeroAlpha(result.Value);
|
||||||
return (IBindable<TValue>)result;
|
return (IBindable<TValue>)result;
|
||||||
|
|
||||||
case CatchSkinConfiguration config:
|
|
||||||
switch (config)
|
|
||||||
{
|
|
||||||
case CatchSkinConfiguration.FlipCatcherPlate:
|
|
||||||
// Don't flip catcher plate contents if the catcher is provided by this legacy skin.
|
|
||||||
if (GetDrawableComponent(new CatchSkinComponentLookup(CatchSkinComponents.Catcher)) != null)
|
|
||||||
return (IBindable<TValue>)new Bindable<bool>();
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return base.GetConfig<TLookup, TValue>(lookup);
|
return base.GetConfig<TLookup, TValue>(lookup);
|
||||||
|
@ -112,11 +112,6 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
|
|
||||||
public Vector2 BodyScale => Scale * body.Scale;
|
public Vector2 BodyScale => Scale * body.Scale;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Whether the contents of the catcher plate should be visually flipped when the catcher direction is changed.
|
|
||||||
/// </summary>
|
|
||||||
private bool flipCatcherPlate;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Width of the area that can be used to attempt catches during gameplay.
|
/// Width of the area that can be used to attempt catches during gameplay.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -339,8 +334,6 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
skin.GetConfig<CatchSkinColour, Color4>(CatchSkinColour.HyperDash)?.Value ??
|
skin.GetConfig<CatchSkinColour, Color4>(CatchSkinColour.HyperDash)?.Value ??
|
||||||
DEFAULT_HYPER_DASH_COLOUR;
|
DEFAULT_HYPER_DASH_COLOUR;
|
||||||
|
|
||||||
flipCatcherPlate = skin.GetConfig<CatchSkinConfiguration, bool>(CatchSkinConfiguration.FlipCatcherPlate)?.Value ?? true;
|
|
||||||
|
|
||||||
runHyperDashStateTransition(HyperDashing);
|
runHyperDashStateTransition(HyperDashing);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -352,8 +345,7 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
|
|
||||||
body.Scale = scaleFromDirection;
|
body.Scale = scaleFromDirection;
|
||||||
// Inverse of catcher scale is applied here, as catcher gets scaled by circle size and so do the incoming fruit.
|
// Inverse of catcher scale is applied here, as catcher gets scaled by circle size and so do the incoming fruit.
|
||||||
caughtObjectContainer.Scale = (1 / Scale.X) * (flipCatcherPlate ? scaleFromDirection : Vector2.One);
|
caughtObjectContainer.Scale = new Vector2(1 / Scale.X);
|
||||||
hitExplosionContainer.Scale = flipCatcherPlate ? scaleFromDirection : Vector2.One;
|
|
||||||
|
|
||||||
// Correct overshooting.
|
// Correct overshooting.
|
||||||
if ((hyperDashDirection > 0 && hyperDashTargetPosition < X) ||
|
if ((hyperDashDirection > 0 && hyperDashTargetPosition < X) ||
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// 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.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
@ -38,12 +38,18 @@ namespace osu.Game.Rulesets.Osu.Mods
|
|||||||
private ReplayState<OsuAction> state = null!;
|
private ReplayState<OsuAction> state = null!;
|
||||||
private double lastStateChangeTime;
|
private double lastStateChangeTime;
|
||||||
|
|
||||||
|
private DrawableOsuRuleset ruleset = null!;
|
||||||
|
private IPressHandler pressHandler = null!;
|
||||||
|
|
||||||
private bool hasReplay;
|
private bool hasReplay;
|
||||||
|
private bool legacyReplay;
|
||||||
|
|
||||||
public void ApplyToDrawableRuleset(DrawableRuleset<OsuHitObject> drawableRuleset)
|
public void ApplyToDrawableRuleset(DrawableRuleset<OsuHitObject> drawableRuleset)
|
||||||
{
|
{
|
||||||
|
ruleset = (DrawableOsuRuleset)drawableRuleset;
|
||||||
|
|
||||||
// grab the input manager for future use.
|
// grab the input manager for future use.
|
||||||
osuInputManager = ((DrawableOsuRuleset)drawableRuleset).KeyBindingInputManager;
|
osuInputManager = ruleset.KeyBindingInputManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ApplyToPlayer(Player player)
|
public void ApplyToPlayer(Player player)
|
||||||
@ -51,15 +57,22 @@ namespace osu.Game.Rulesets.Osu.Mods
|
|||||||
if (osuInputManager.ReplayInputHandler != null)
|
if (osuInputManager.ReplayInputHandler != null)
|
||||||
{
|
{
|
||||||
hasReplay = true;
|
hasReplay = true;
|
||||||
|
|
||||||
|
Debug.Assert(ruleset.ReplayScore != null);
|
||||||
|
legacyReplay = ruleset.ReplayScore.ScoreInfo.IsLegacyScore;
|
||||||
|
|
||||||
|
pressHandler = legacyReplay ? new LegacyReplayPressHandler(this) : new PressHandler(this);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pressHandler = new PressHandler(this);
|
||||||
osuInputManager.AllowGameplayInputs = false;
|
osuInputManager.AllowGameplayInputs = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Update(Playfield playfield)
|
public void Update(Playfield playfield)
|
||||||
{
|
{
|
||||||
if (hasReplay)
|
if (hasReplay && !legacyReplay)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
bool requiresHold = false;
|
bool requiresHold = false;
|
||||||
@ -132,11 +145,62 @@ namespace osu.Game.Rulesets.Osu.Mods
|
|||||||
|
|
||||||
if (down)
|
if (down)
|
||||||
{
|
{
|
||||||
state.PressedActions.Add(wasLeft ? OsuAction.LeftButton : OsuAction.RightButton);
|
pressHandler.HandlePress(wasLeft);
|
||||||
wasLeft = !wasLeft;
|
wasLeft = !wasLeft;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pressHandler.HandleRelease(wasLeft);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
state.Apply(osuInputManager.CurrentState, osuInputManager);
|
private interface IPressHandler
|
||||||
|
{
|
||||||
|
void HandlePress(bool wasLeft);
|
||||||
|
void HandleRelease(bool wasLeft);
|
||||||
|
}
|
||||||
|
|
||||||
|
private class PressHandler : IPressHandler
|
||||||
|
{
|
||||||
|
private readonly OsuModRelax mod;
|
||||||
|
|
||||||
|
public PressHandler(OsuModRelax mod)
|
||||||
|
{
|
||||||
|
this.mod = mod;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void HandlePress(bool wasLeft)
|
||||||
|
{
|
||||||
|
mod.state.PressedActions.Add(wasLeft ? OsuAction.LeftButton : OsuAction.RightButton);
|
||||||
|
mod.state.Apply(mod.osuInputManager.CurrentState, mod.osuInputManager);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void HandleRelease(bool wasLeft)
|
||||||
|
{
|
||||||
|
mod.state.Apply(mod.osuInputManager.CurrentState, mod.osuInputManager);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// legacy replays do not contain key-presses with Relax mod, so they need to be triggered by themselves.
|
||||||
|
private class LegacyReplayPressHandler : IPressHandler
|
||||||
|
{
|
||||||
|
private readonly OsuModRelax mod;
|
||||||
|
|
||||||
|
public LegacyReplayPressHandler(OsuModRelax mod)
|
||||||
|
{
|
||||||
|
this.mod = mod;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void HandlePress(bool wasLeft)
|
||||||
|
{
|
||||||
|
mod.osuInputManager.KeyBindingContainer.TriggerPressed(wasLeft ? OsuAction.LeftButton : OsuAction.RightButton);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void HandleRelease(bool wasLeft)
|
||||||
|
{
|
||||||
|
// this intentionally releases right when `wasLeft` is true because `wasLeft` is set at point of press and not at point of release
|
||||||
|
mod.osuInputManager.KeyBindingContainer.TriggerReleased(wasLeft ? OsuAction.RightButton : OsuAction.LeftButton);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,13 +43,13 @@ namespace osu.Game.Tests.Rulesets
|
|||||||
|
|
||||||
AddStep("setup provider", () =>
|
AddStep("setup provider", () =>
|
||||||
{
|
{
|
||||||
var rulesetSkinProvider = new RulesetSkinProvidingContainer(Ruleset.Value.CreateInstance(), Beatmap.Value.Beatmap, Beatmap.Value.Skin);
|
requester = new SkinRequester();
|
||||||
|
|
||||||
rulesetSkinProvider.Add(requester = new SkinRequester());
|
|
||||||
|
|
||||||
requester.OnLoadAsync += () => textureOnLoad = requester.GetTexture("test-image");
|
requester.OnLoadAsync += () => textureOnLoad = requester.GetTexture("test-image");
|
||||||
|
|
||||||
Child = rulesetSkinProvider;
|
Child = new RulesetSkinProvidingContainer(Ruleset.Value.CreateInstance(), Beatmap.Value.Beatmap, Beatmap.Value.Skin)
|
||||||
|
{
|
||||||
|
requester
|
||||||
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
AddAssert("requester got correct initial texture", () => textureOnLoad != null);
|
AddAssert("requester got correct initial texture", () => textureOnLoad != null);
|
||||||
|
Loading…
Reference in New Issue
Block a user