From 9542e77d16ba616d095026718d5049c297984912 Mon Sep 17 00:00:00 2001 From: clayton Date: Sun, 10 Aug 2025 07:12:59 -0700 Subject: [PATCH 01/12] Add sliderpoint10 and sliderpoint30 support --- .../Legacy/LegacySliderTickJudgementPiece.cs | 42 +++++++++++++++++++ .../Legacy/OsuLegacySkinTransformer.cs | 31 ++++++++++++++ osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs | 2 + .../Rulesets/Judgements/DrawableJudgement.cs | 3 ++ .../Judgements/IAppliesJudgementResult.cs | 16 +++++++ 5 files changed, 94 insertions(+) create mode 100644 osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySliderTickJudgementPiece.cs create mode 100644 osu.Game/Rulesets/Judgements/IAppliesJudgementResult.cs diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySliderTickJudgementPiece.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySliderTickJudgementPiece.cs new file mode 100644 index 0000000000..db454bfd19 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySliderTickJudgementPiece.cs @@ -0,0 +1,42 @@ +// Copyright (c) ppy Pty Ltd . 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.Framework.Graphics.Textures; +using osu.Game.Rulesets.Judgements; +using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Skinning; +using osuTK; + +namespace osu.Game.Rulesets.Osu.Skinning.Legacy +{ + public partial class LegacySliderTickJudgementPiece : Sprite, IAnimatableJudgement, IAppliesJudgementResult + { + private Texture? texture10; + private Texture? texture30; + + [BackgroundDependencyLoader] + private void load(ISkinSource skin) + { + texture10 = skin.GetTexture("sliderpoint10"); + texture30 = skin.GetTexture("sliderpoint30"); + } + + public void ApplyJudgementResult(JudgementResult result) + { + Texture = result.HitObject is SliderTick ? texture10 : texture30; + } + + public void PlayAnimation() + { + // https://github.com/peppy/osu-stable-reference/blob/0e91e49bc83fe8b21c3ba5f1eb2d5d06456eae84/osu!/GameModes/Play/Rulesets/Ruleset.cs#L804-L806 + this.MoveToOffset(new Vector2(0, -10), 300, Easing.Out) + .Then() + .FadeOut(60); + } + + public Drawable GetAboveHitObjectsProxiedContent() => CreateProxy(); + } +} diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs index af1df6dc9c..9b86106a2e 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs @@ -6,6 +6,7 @@ using System.Linq; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.Scoring; using osu.Game.Screens.Play.HUD; using osu.Game.Skinning; using osuTK; @@ -115,6 +116,36 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy return null; + case SkinComponentLookup resultComponent: + switch (resultComponent.Component) + { + // osu!stable didn't show slider points on the tail, since that's where the slider judgement was shown. Here, sliderpoint30 will be shown on non-classic tails via SliderTailHit. + case HitResult.LargeTickHit: + case HitResult.SliderTailHit: + if (hasSliderPoints()) + return new LegacySliderTickJudgementPiece(); + + return base.GetDrawableComponent(lookup); + + // If slider points are showing and tick misses aren't provided by this skin, don't look up tick misses from any further skins. + case HitResult.LargeTickMiss: + case HitResult.IgnoreMiss: + if (hasSliderPoints()) + return base.GetDrawableComponent(lookup) ?? Drawable.Empty(); + + return base.GetDrawableComponent(lookup); + + default: + return base.GetDrawableComponent(lookup); + } + + bool hasSliderPoints() => + // https://github.com/peppy/osu-stable-reference/blob/0e91e49bc83fe8b21c3ba5f1eb2d5d06456eae84/osu!/GameModes/Play/Rulesets/Ruleset.cs#L799 + GetConfig(SkinConfiguration.LegacySetting.Version)?.Value < 2m + // Note that osu!stable didn't require both sliderpoint textures to be present like this. There's not enough information in the lookup to decide which of the textures should be used, so we can't handle them separately. The hope is that this won't break many skins because it'd be very odd to customise only one of these textures. + && GetTexture("sliderpoint10") != null + && GetTexture("sliderpoint30") != null; + case OsuSkinComponentLookup osuComponent: switch (osuComponent.Component) { diff --git a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs index 7d9f5eb1a8..e379c44314 100644 --- a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs +++ b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs @@ -81,6 +81,8 @@ namespace osu.Game.Rulesets.Osu.UI HitResult.Ok, HitResult.Meh, HitResult.Miss, + HitResult.LargeTickHit, + HitResult.SliderTailHit, HitResult.LargeTickMiss, HitResult.IgnoreMiss, }, onJudgementLoaded)); diff --git a/osu.Game/Rulesets/Judgements/DrawableJudgement.cs b/osu.Game/Rulesets/Judgements/DrawableJudgement.cs index 3e70f52ee7..36a7183766 100644 --- a/osu.Game/Rulesets/Judgements/DrawableJudgement.cs +++ b/osu.Game/Rulesets/Judgements/DrawableJudgement.cs @@ -89,6 +89,9 @@ namespace osu.Game.Rulesets.Judgements { Result = result; JudgedHitObject = judgedObject?.HitObject; + + if (JudgementBody?.Drawable is IAppliesJudgementResult appliesResult) + appliesResult.ApplyJudgementResult(Result); } protected override void FreeAfterUse() diff --git a/osu.Game/Rulesets/Judgements/IAppliesJudgementResult.cs b/osu.Game/Rulesets/Judgements/IAppliesJudgementResult.cs new file mode 100644 index 0000000000..fc58e95ba5 --- /dev/null +++ b/osu.Game/Rulesets/Judgements/IAppliesJudgementResult.cs @@ -0,0 +1,16 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +namespace osu.Game.Rulesets.Judgements +{ + /// + /// A skinnable judgement element which requires the full . + /// + public interface IAppliesJudgementResult + { + /// + /// Associate a result with this judgement element. + /// + void ApplyJudgementResult(JudgementResult result); + } +} From 18803fbec025e2e095310b90dafbcbd9a6621bb2 Mon Sep 17 00:00:00 2001 From: clayton Date: Sun, 10 Aug 2025 07:13:47 -0700 Subject: [PATCH 02/12] Always show slider head judgement Because it may display sliderpoints in classic behaviour --- .../Objects/Drawables/DrawableSliderHead.cs | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderHead.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderHead.cs index 76b9fdc3ce..55e985c568 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderHead.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderHead.cs @@ -16,17 +16,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables public DrawableSlider DrawableSlider => (DrawableSlider)ParentHitObject; - public override bool DisplayResult - { - get - { - if (HitObject?.ClassicSliderBehaviour == true) - return false; - - return base.DisplayResult; - } - } - private readonly IBindable pathVersion = new Bindable(); protected override OsuSkinComponents CirclePieceComponent => OsuSkinComponents.SliderHeadHitCircle; From 5fc5d0bd5ff229aeaa0cd4cf1bc2c3482d827a9c Mon Sep 17 00:00:00 2001 From: clayton Date: Sun, 10 Aug 2025 07:15:20 -0700 Subject: [PATCH 03/12] Fix tick hits in non-legacy skins --- .../Objects/Drawables/DrawableOsuJudgement.cs | 4 +++- .../Skinning/Argon/OsuArgonSkinTransformer.cs | 4 ++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuJudgement.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuJudgement.cs index 8b3fcb23cd..05c03cb578 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuJudgement.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuJudgement.cs @@ -87,7 +87,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables base.ApplyHitAnimations(); } - protected override Drawable CreateDefaultJudgement(HitResult result) => new OsuJudgementPiece(result); + protected override Drawable CreateDefaultJudgement(HitResult result) => + // Tick hits don't show a judgement by default + result.IsHit() && result.IsTick() ? Empty() : new OsuJudgementPiece(result); private partial class OsuJudgementPiece : DefaultJudgementPiece { diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/OsuArgonSkinTransformer.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/OsuArgonSkinTransformer.cs index 2d1d5826b1..ecc0f3fd0a 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/OsuArgonSkinTransformer.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/OsuArgonSkinTransformer.cs @@ -29,6 +29,10 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon switch (result) { + case HitResult.LargeTickHit: + case HitResult.SliderTailHit: + return null; + case HitResult.IgnoreMiss: case HitResult.LargeTickMiss: return new ArgonJudgementPieceSliderTickMiss(result); From bcc9bc4498ee5c5a4b559670a7b2b0d8acfe0a96 Mon Sep 17 00:00:00 2001 From: clayton Date: Sun, 10 Aug 2025 07:15:37 -0700 Subject: [PATCH 04/12] Remove hit lighting for tick hits --- osu.Game.Rulesets.Osu/Objects/Drawables/SkinnableLighting.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/SkinnableLighting.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/SkinnableLighting.cs index 3776201626..7bb54487c0 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/SkinnableLighting.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/SkinnableLighting.cs @@ -3,6 +3,7 @@ using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.Scoring; using osu.Game.Skinning; using osuTK.Graphics; @@ -42,7 +43,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables if (targetJudgement == null || targetResult == null) Colour = Color4.White; else - Colour = targetResult.IsHit ? targetJudgement.AccentColour : Color4.Transparent; + Colour = targetResult.IsHit && !targetResult.Type.IsTick() ? targetJudgement.AccentColour : Color4.Transparent; } } } From cd7a304640d247fc4abb3075b5ee87c2b97bfc1d Mon Sep 17 00:00:00 2001 From: clayton Date: Sun, 10 Aug 2025 07:16:18 -0700 Subject: [PATCH 05/12] Add tick judgement gallery test scene --- .../Resources/old-skin/sliderpoint10.png | Bin 0 -> 2349 bytes .../Resources/old-skin/sliderpoint30.png | Bin 0 -> 2718 bytes .../TestSceneDrawableJudgementSliderTicks.cs | 173 ++++++++++++++++++ 3 files changed, 173 insertions(+) create mode 100644 osu.Game.Rulesets.Osu.Tests/Resources/old-skin/sliderpoint10.png create mode 100644 osu.Game.Rulesets.Osu.Tests/Resources/old-skin/sliderpoint30.png create mode 100644 osu.Game.Rulesets.Osu.Tests/TestSceneDrawableJudgementSliderTicks.cs diff --git a/osu.Game.Rulesets.Osu.Tests/Resources/old-skin/sliderpoint10.png b/osu.Game.Rulesets.Osu.Tests/Resources/old-skin/sliderpoint10.png new file mode 100644 index 0000000000000000000000000000000000000000..3e2fe66a1c0a91e6f21d9bf670d4515ef8cdb3b6 GIT binary patch literal 2349 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 Y0Sy+ultD$RxBvhE07*qoM6N<$g5gp;DgXcg literal 0 HcmV?d00001 diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneDrawableJudgementSliderTicks.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneDrawableJudgementSliderTicks.cs new file mode 100644 index 0000000000..c03c371015 --- /dev/null +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneDrawableJudgementSliderTicks.cs @@ -0,0 +1,173 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Diagnostics; +using System.Linq; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Graphics.Sprites; +using osu.Game.Rulesets.Osu.Judgements; +using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.Osu.Objects.Drawables; +using osu.Game.Rulesets.Scoring; +using osu.Game.Rulesets.UI; +using osuTK; + +namespace osu.Game.Rulesets.Osu.Tests +{ + public partial class TestSceneDrawableJudgementSliderTicks : OsuSkinnableTestScene + { + private bool classic; + private readonly Container[,,] judgementContainers; + private readonly JudgementPooler[] judgementPools; + + public TestSceneDrawableJudgementSliderTicks() + { + judgementContainers = new Container[Rows * Cols, 5, 2]; + judgementPools = new JudgementPooler[Rows * Cols]; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + int cellIndex = 0; + + SetContents(_ => + { + var container = new Container + { + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] + { + judgementPools[cellIndex] = new JudgementPooler(new[] + { + HitResult.Great, + HitResult.Miss, + HitResult.LargeTickHit, + HitResult.SliderTailHit, + HitResult.LargeTickMiss, + HitResult.IgnoreMiss, + }), + new GridContainer + { + Padding = new MarginPadding { Top = 26f }, + RelativeSizeAxes = Axes.Both, + RowDimensions = new[] { new Dimension(GridSizeMode.AutoSize) }, + ColumnDimensions = new[] { new Dimension(GridSizeMode.AutoSize) }, + Content = + new[] + { + new[] + { + Empty(), + new OsuSpriteText + { + Text = "hit", + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, + }, + new OsuSpriteText + { + Text = "miss", + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, + }, + }, + }.Concat(new[] + { + "head", + "tick", + "repeat", + "tail", + "slider", + }.Select((label, hitObjectIndex) => new Drawable[] + { + new OsuSpriteText + { + Text = label, + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + }, + judgementContainers[cellIndex, hitObjectIndex, 0] = + new Container { RelativeSizeAxes = Axes.Both }, + judgementContainers[cellIndex, hitObjectIndex, 1] = + new Container { RelativeSizeAxes = Axes.Both }, + })).ToArray(), + }, + }, + }; + + cellIndex++; + + return container; + }); + + AddToggleStep("Toggle classic behaviour", c => classic = c); + + AddStep("Show judgements", createAllJudgements); + } + + private void createAllJudgements() + { + for (int cellIndex = 0; cellIndex < Rows * Cols; cellIndex++) + { + for (int hitObjectIndex = 0; hitObjectIndex < 5; hitObjectIndex++) + { + createJudgement(cellIndex, hitObjectIndex, true); + createJudgement(cellIndex, hitObjectIndex, false); + } + } + } + + private void createJudgement(int cellIndex, int hitObjectIndex, bool hit) + { + var container = judgementContainers[cellIndex, hitObjectIndex, hit ? 0 : 1]; + container.Clear(false); + + var slider = new Slider { StartTime = Time.Current, ClassicSliderBehaviour = classic }; + OsuHitObject hitObject = hitObjectIndex switch + { + 0 => new SliderHeadCircle { StartTime = Time.Current, ClassicSliderBehaviour = classic }, + 1 => new SliderTick { StartTime = Time.Current }, + 2 => new SliderRepeat(slider) { StartTime = Time.Current }, + 3 => new SliderTailCircle(slider) { StartTime = Time.Current, ClassicSliderBehaviour = classic }, + 4 => slider, + _ => throw new UnreachableException(), + }; + + DrawableOsuHitObject drawableHitObject = hitObject switch + { + SliderHeadCircle head => new DrawableSliderHead(head), + SliderTick tick => new DrawableSliderTick(tick), + SliderRepeat repeat => new DrawableSliderRepeat(repeat), + SliderTailCircle tail => new DrawableSliderTail(tail), + Slider s => new DrawableSlider(s), + _ => throw new UnreachableException(), + }; + + if (!drawableHitObject.DisplayResult) + return; + + // TODO: This shouldn't be here. Removing it causes a crash on classic behaviour and I don't know why -- it happens any time the slider from above is applied to a DrawableJudgement, but the error comes from something about transforms on the Argon judgement piece, which doesn't seem to be related to the hit object. + if (hitObject is Slider) + return; + + var result = new OsuJudgementResult(hitObject, hitObject.Judgement) + { + Type = hit ? hitObject.Judgement.MaxResult : hitObject.Judgement.MinResult, + }; + + var judgement = judgementPools[cellIndex].Get(result.Type, d => + { + d.Anchor = Anchor.Centre; + d.Origin = Anchor.Centre; + d.Scale = new Vector2(0.7f); + d.Apply(result, null); + }); + + if (judgement != null) + container.Add(judgement); + } + } +} From 375da52a3452b0d932b485c9f5c8c429f6c54967 Mon Sep 17 00:00:00 2001 From: clayton Date: Sun, 10 Aug 2025 07:16:57 -0700 Subject: [PATCH 06/12] Fix judgement position when not supplied a drawable hit object --- .../Objects/Drawables/DrawableOsuJudgement.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuJudgement.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuJudgement.cs index 05c03cb578..0f7812d91a 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuJudgement.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuJudgement.cs @@ -21,7 +21,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables [Resolved] private OsuConfigManager config { get; set; } = null!; - private Vector2 screenSpacePosition; + private Vector2? screenSpacePosition; [BackgroundDependencyLoader] private void load() @@ -65,7 +65,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables Lighting.ResetAnimation(); Lighting.SetColourFrom(this, Result); - Position = Parent!.ToLocalSpace(screenSpacePosition); + + if (screenSpacePosition != null) + Position = Parent!.ToLocalSpace(screenSpacePosition.Value); } protected override void ApplyHitAnimations() From f2839c7b6575b3b52a366411894a8c5c52bf6e12 Mon Sep 17 00:00:00 2001 From: clayton Date: Sat, 16 Aug 2025 04:09:40 -0700 Subject: [PATCH 07/12] Rename class to be more consistent with other skins' judgement pieces --- ...ckJudgementPiece.cs => LegacyJudgementPieceSliderTickHit.cs} | 2 +- .../Skinning/Legacy/OsuLegacySkinTransformer.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename osu.Game.Rulesets.Osu/Skinning/Legacy/{LegacySliderTickJudgementPiece.cs => LegacyJudgementPieceSliderTickHit.cs} (92%) diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySliderTickJudgementPiece.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyJudgementPieceSliderTickHit.cs similarity index 92% rename from osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySliderTickJudgementPiece.cs rename to osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyJudgementPieceSliderTickHit.cs index db454bfd19..81f7ea5d9e 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySliderTickJudgementPiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyJudgementPieceSliderTickHit.cs @@ -12,7 +12,7 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Skinning.Legacy { - public partial class LegacySliderTickJudgementPiece : Sprite, IAnimatableJudgement, IAppliesJudgementResult + public partial class LegacyJudgementPieceSliderTickHit : Sprite, IAnimatableJudgement, IAppliesJudgementResult { private Texture? texture10; private Texture? texture30; diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs index 9b86106a2e..44b2cb484a 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs @@ -123,7 +123,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy case HitResult.LargeTickHit: case HitResult.SliderTailHit: if (hasSliderPoints()) - return new LegacySliderTickJudgementPiece(); + return new LegacyJudgementPieceSliderTickHit(); return base.GetDrawableComponent(lookup); From 4d1ecab4e321c57ade3a2c3a1cfb1c2e63c42a0d Mon Sep 17 00:00:00 2001 From: clayton Date: Sat, 16 Aug 2025 04:54:34 -0700 Subject: [PATCH 08/12] Map sliderpoint textures directly to HitResult types --- .../LegacyJudgementPieceSliderTickHit.cs | 21 +--------------- .../Legacy/OsuLegacySkinTransformer.cs | 25 +++++++++++-------- .../Rulesets/Judgements/DrawableJudgement.cs | 3 --- .../Judgements/IAppliesJudgementResult.cs | 16 ------------ 4 files changed, 16 insertions(+), 49 deletions(-) delete mode 100644 osu.Game/Rulesets/Judgements/IAppliesJudgementResult.cs diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyJudgementPieceSliderTickHit.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyJudgementPieceSliderTickHit.cs index 81f7ea5d9e..8c89f4c9c8 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyJudgementPieceSliderTickHit.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyJudgementPieceSliderTickHit.cs @@ -1,34 +1,15 @@ // Copyright (c) ppy Pty Ltd . 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.Framework.Graphics.Textures; using osu.Game.Rulesets.Judgements; -using osu.Game.Rulesets.Osu.Objects; -using osu.Game.Skinning; using osuTK; namespace osu.Game.Rulesets.Osu.Skinning.Legacy { - public partial class LegacyJudgementPieceSliderTickHit : Sprite, IAnimatableJudgement, IAppliesJudgementResult + public partial class LegacyJudgementPieceSliderTickHit : Sprite, IAnimatableJudgement { - private Texture? texture10; - private Texture? texture30; - - [BackgroundDependencyLoader] - private void load(ISkinSource skin) - { - texture10 = skin.GetTexture("sliderpoint10"); - texture30 = skin.GetTexture("sliderpoint30"); - } - - public void ApplyJudgementResult(JudgementResult result) - { - Texture = result.HitObject is SliderTick ? texture10 : texture30; - } - public void PlayAnimation() { // https://github.com/peppy/osu-stable-reference/blob/0e91e49bc83fe8b21c3ba5f1eb2d5d06456eae84/osu!/GameModes/Play/Rulesets/Ruleset.cs#L804-L806 diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs index 44b2cb484a..69e9cd00d5 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs @@ -5,6 +5,7 @@ using System; using System.Linq; using osu.Framework.Bindables; using osu.Framework.Graphics; +using osu.Framework.Graphics.Textures; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Scoring; using osu.Game.Screens.Play.HUD; @@ -119,18 +120,19 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy case SkinComponentLookup resultComponent: switch (resultComponent.Component) { - // osu!stable didn't show slider points on the tail, since that's where the slider judgement was shown. Here, sliderpoint30 will be shown on non-classic tails via SliderTailHit. case HitResult.LargeTickHit: case HitResult.SliderTailHit: - if (hasSliderPoints()) - return new LegacyJudgementPieceSliderTickHit(); + if (getSliderPointTexture(resultComponent.Component) is Texture texture) + return new LegacyJudgementPieceSliderTickHit { Texture = texture }; return base.GetDrawableComponent(lookup); - // If slider points are showing and tick misses aren't provided by this skin, don't look up tick misses from any further skins. + // If the corresponding hit result displays a judgement and the miss texture isn't provided by this skin, don't look up the miss texture from any further skins. case HitResult.LargeTickMiss: case HitResult.IgnoreMiss: - if (hasSliderPoints()) + if (getSliderPointTexture(resultComponent.Component == HitResult.LargeTickMiss + ? HitResult.LargeTickHit + : HitResult.SliderTailHit) != null) return base.GetDrawableComponent(lookup) ?? Drawable.Empty(); return base.GetDrawableComponent(lookup); @@ -139,12 +141,15 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy return base.GetDrawableComponent(lookup); } - bool hasSliderPoints() => + Texture? getSliderPointTexture(HitResult result) + { // https://github.com/peppy/osu-stable-reference/blob/0e91e49bc83fe8b21c3ba5f1eb2d5d06456eae84/osu!/GameModes/Play/Rulesets/Ruleset.cs#L799 - GetConfig(SkinConfiguration.LegacySetting.Version)?.Value < 2m - // Note that osu!stable didn't require both sliderpoint textures to be present like this. There's not enough information in the lookup to decide which of the textures should be used, so we can't handle them separately. The hope is that this won't break many skins because it'd be very odd to customise only one of these textures. - && GetTexture("sliderpoint10") != null - && GetTexture("sliderpoint30") != null; + if (GetConfig(SkinConfiguration.LegacySetting.Version)?.Value < 2m) + // Note that osu!stable used sliderpoint30 for heads and repeats, and sliderpoint10 for ticks, but the mapping is intentionally changed here so that each texture represents one type of HitResult. + return GetTexture(result == HitResult.LargeTickHit ? "sliderpoint30" : "sliderpoint10"); + + return null; + } case OsuSkinComponentLookup osuComponent: switch (osuComponent.Component) diff --git a/osu.Game/Rulesets/Judgements/DrawableJudgement.cs b/osu.Game/Rulesets/Judgements/DrawableJudgement.cs index 36a7183766..3e70f52ee7 100644 --- a/osu.Game/Rulesets/Judgements/DrawableJudgement.cs +++ b/osu.Game/Rulesets/Judgements/DrawableJudgement.cs @@ -89,9 +89,6 @@ namespace osu.Game.Rulesets.Judgements { Result = result; JudgedHitObject = judgedObject?.HitObject; - - if (JudgementBody?.Drawable is IAppliesJudgementResult appliesResult) - appliesResult.ApplyJudgementResult(Result); } protected override void FreeAfterUse() diff --git a/osu.Game/Rulesets/Judgements/IAppliesJudgementResult.cs b/osu.Game/Rulesets/Judgements/IAppliesJudgementResult.cs deleted file mode 100644 index fc58e95ba5..0000000000 --- a/osu.Game/Rulesets/Judgements/IAppliesJudgementResult.cs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -namespace osu.Game.Rulesets.Judgements -{ - /// - /// A skinnable judgement element which requires the full . - /// - public interface IAppliesJudgementResult - { - /// - /// Associate a result with this judgement element. - /// - void ApplyJudgementResult(JudgementResult result); - } -} From 6a1620031443f37c80db33b033a1199637bcc7cb Mon Sep 17 00:00:00 2001 From: clayton Date: Sat, 16 Aug 2025 04:55:49 -0700 Subject: [PATCH 09/12] Dedupe switch returns --- .../Skinning/Legacy/OsuLegacySkinTransformer.cs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs index 69e9cd00d5..7118b6f95e 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs @@ -125,7 +125,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy if (getSliderPointTexture(resultComponent.Component) is Texture texture) return new LegacyJudgementPieceSliderTickHit { Texture = texture }; - return base.GetDrawableComponent(lookup); + break; // If the corresponding hit result displays a judgement and the miss texture isn't provided by this skin, don't look up the miss texture from any further skins. case HitResult.LargeTickMiss: @@ -135,12 +135,11 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy : HitResult.SliderTailHit) != null) return base.GetDrawableComponent(lookup) ?? Drawable.Empty(); - return base.GetDrawableComponent(lookup); - - default: - return base.GetDrawableComponent(lookup); + break; } + return base.GetDrawableComponent(lookup); + Texture? getSliderPointTexture(HitResult result) { // https://github.com/peppy/osu-stable-reference/blob/0e91e49bc83fe8b21c3ba5f1eb2d5d06456eae84/osu!/GameModes/Play/Rulesets/Ruleset.cs#L799 From a96d00a55fb7069154c34b61ae95312b85a566c4 Mon Sep 17 00:00:00 2001 From: clayton Date: Sat, 16 Aug 2025 04:57:05 -0700 Subject: [PATCH 10/12] Fix Slider case of test --- .../TestSceneDrawableJudgementSliderTicks.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneDrawableJudgementSliderTicks.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneDrawableJudgementSliderTicks.cs index c03c371015..157ac6589e 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneDrawableJudgementSliderTicks.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneDrawableJudgementSliderTicks.cs @@ -5,6 +5,8 @@ using System.Diagnostics; using System.Linq; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Game.Beatmaps; +using osu.Game.Beatmaps.ControlPoints; using osu.Game.Graphics.Sprites; using osu.Game.Rulesets.Osu.Judgements; using osu.Game.Rulesets.Osu.Objects; @@ -126,6 +128,7 @@ namespace osu.Game.Rulesets.Osu.Tests container.Clear(false); var slider = new Slider { StartTime = Time.Current, ClassicSliderBehaviour = classic }; + slider.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); OsuHitObject hitObject = hitObjectIndex switch { 0 => new SliderHeadCircle { StartTime = Time.Current, ClassicSliderBehaviour = classic }, @@ -149,10 +152,6 @@ namespace osu.Game.Rulesets.Osu.Tests if (!drawableHitObject.DisplayResult) return; - // TODO: This shouldn't be here. Removing it causes a crash on classic behaviour and I don't know why -- it happens any time the slider from above is applied to a DrawableJudgement, but the error comes from something about transforms on the Argon judgement piece, which doesn't seem to be related to the hit object. - if (hitObject is Slider) - return; - var result = new OsuJudgementResult(hitObject, hitObject.Judgement) { Type = hit ? hitObject.Judgement.MaxResult : hitObject.Judgement.MinResult, From c4163e33e500d81e0c754e55cb3fa78983320b26 Mon Sep 17 00:00:00 2001 From: clayton Date: Sat, 16 Aug 2025 05:08:30 -0700 Subject: [PATCH 11/12] Don't use switch expression --- .../TestSceneDrawableJudgementSliderTicks.cs | 49 ++++++++++++------- 1 file changed, 32 insertions(+), 17 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneDrawableJudgementSliderTicks.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneDrawableJudgementSliderTicks.cs index 157ac6589e..d5ea0e22ed 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneDrawableJudgementSliderTicks.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneDrawableJudgementSliderTicks.cs @@ -129,25 +129,40 @@ namespace osu.Game.Rulesets.Osu.Tests var slider = new Slider { StartTime = Time.Current, ClassicSliderBehaviour = classic }; slider.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); - OsuHitObject hitObject = hitObjectIndex switch - { - 0 => new SliderHeadCircle { StartTime = Time.Current, ClassicSliderBehaviour = classic }, - 1 => new SliderTick { StartTime = Time.Current }, - 2 => new SliderRepeat(slider) { StartTime = Time.Current }, - 3 => new SliderTailCircle(slider) { StartTime = Time.Current, ClassicSliderBehaviour = classic }, - 4 => slider, - _ => throw new UnreachableException(), - }; - DrawableOsuHitObject drawableHitObject = hitObject switch + OsuHitObject hitObject; + DrawableOsuHitObject drawableHitObject; + + switch (hitObjectIndex) { - SliderHeadCircle head => new DrawableSliderHead(head), - SliderTick tick => new DrawableSliderTick(tick), - SliderRepeat repeat => new DrawableSliderRepeat(repeat), - SliderTailCircle tail => new DrawableSliderTail(tail), - Slider s => new DrawableSlider(s), - _ => throw new UnreachableException(), - }; + case 0: + hitObject = new SliderHeadCircle { StartTime = Time.Current, ClassicSliderBehaviour = classic }; + drawableHitObject = new DrawableSliderHead((SliderHeadCircle)hitObject); + break; + + case 1: + hitObject = new SliderTick { StartTime = Time.Current }; + drawableHitObject = new DrawableSliderTick((SliderTick)hitObject); + break; + + case 2: + hitObject = new SliderRepeat(slider) { StartTime = Time.Current }; + drawableHitObject = new DrawableSliderRepeat((SliderRepeat)hitObject); + break; + + case 3: + hitObject = new SliderTailCircle(slider) { StartTime = Time.Current, ClassicSliderBehaviour = classic }; + drawableHitObject = new DrawableSliderTail((SliderTailCircle)hitObject); + break; + + case 4: + hitObject = slider; + drawableHitObject = new DrawableSlider(slider); + break; + + default: + throw new UnreachableException(); + } if (!drawableHitObject.DisplayResult) return; From e77fb987a9a5c0d77f0c20dd0e6d7e9a8d5792a4 Mon Sep 17 00:00:00 2001 From: clayton Date: Sat, 16 Aug 2025 09:32:31 -0700 Subject: [PATCH 12/12] Don't switch on array index in slidertick test --- .../TestSceneDrawableJudgementSliderTicks.cs | 75 ++++++------------- 1 file changed, 24 insertions(+), 51 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneDrawableJudgementSliderTicks.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneDrawableJudgementSliderTicks.cs index d5ea0e22ed..5843a9233c 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneDrawableJudgementSliderTicks.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneDrawableJudgementSliderTicks.cs @@ -1,10 +1,10 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System.Diagnostics; using System.Linq; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Testing; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Graphics.Sprites; @@ -20,12 +20,10 @@ namespace osu.Game.Rulesets.Osu.Tests public partial class TestSceneDrawableJudgementSliderTicks : OsuSkinnableTestScene { private bool classic; - private readonly Container[,,] judgementContainers; private readonly JudgementPooler[] judgementPools; public TestSceneDrawableJudgementSliderTicks() { - judgementContainers = new Container[Rows * Cols, 5, 2]; judgementPools = new JudgementPooler[Rows * Cols]; } @@ -83,7 +81,7 @@ namespace osu.Game.Rulesets.Osu.Tests "repeat", "tail", "slider", - }.Select((label, hitObjectIndex) => new Drawable[] + }.Select(label => new Drawable[] { new OsuSpriteText { @@ -91,10 +89,8 @@ namespace osu.Game.Rulesets.Osu.Tests Anchor = Anchor.CentreRight, Origin = Anchor.CentreRight, }, - judgementContainers[cellIndex, hitObjectIndex, 0] = - new Container { RelativeSizeAxes = Axes.Both }, - judgementContainers[cellIndex, hitObjectIndex, 1] = - new Container { RelativeSizeAxes = Axes.Both }, + new Container { RelativeSizeAxes = Axes.Both }, + new Container { RelativeSizeAxes = Axes.Both }, })).ToArray(), }, }, @@ -114,65 +110,42 @@ namespace osu.Game.Rulesets.Osu.Tests { for (int cellIndex = 0; cellIndex < Rows * Cols; cellIndex++) { - for (int hitObjectIndex = 0; hitObjectIndex < 5; hitObjectIndex++) + var slider = new Slider { StartTime = Time.Current, ClassicSliderBehaviour = classic }; + slider.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); + + var drawableHitObjects = new DrawableOsuHitObject[] { - createJudgement(cellIndex, hitObjectIndex, true); - createJudgement(cellIndex, hitObjectIndex, false); + new DrawableSliderHead(new SliderHeadCircle { StartTime = Time.Current, ClassicSliderBehaviour = classic }), + new DrawableSliderTick(new SliderTick { StartTime = Time.Current }), + new DrawableSliderRepeat(new SliderRepeat(slider) { StartTime = Time.Current }), + new DrawableSliderTail(new SliderTailCircle(slider) { StartTime = Time.Current, ClassicSliderBehaviour = classic }), + new DrawableSlider(slider), + }; + + var containers = Cell(cellIndex).ChildrenOfType>().ToArray(); + + for (int i = 0; i < drawableHitObjects.Length; i++) + { + createJudgement(judgementPools[cellIndex], containers[i * 2], drawableHitObjects[i], true); + createJudgement(judgementPools[cellIndex], containers[i * 2 + 1], drawableHitObjects[i], false); } } } - private void createJudgement(int cellIndex, int hitObjectIndex, bool hit) + private void createJudgement(JudgementPooler pool, Container container, DrawableOsuHitObject drawableHitObject, bool hit) { - var container = judgementContainers[cellIndex, hitObjectIndex, hit ? 0 : 1]; container.Clear(false); - var slider = new Slider { StartTime = Time.Current, ClassicSliderBehaviour = classic }; - slider.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); - - OsuHitObject hitObject; - DrawableOsuHitObject drawableHitObject; - - switch (hitObjectIndex) - { - case 0: - hitObject = new SliderHeadCircle { StartTime = Time.Current, ClassicSliderBehaviour = classic }; - drawableHitObject = new DrawableSliderHead((SliderHeadCircle)hitObject); - break; - - case 1: - hitObject = new SliderTick { StartTime = Time.Current }; - drawableHitObject = new DrawableSliderTick((SliderTick)hitObject); - break; - - case 2: - hitObject = new SliderRepeat(slider) { StartTime = Time.Current }; - drawableHitObject = new DrawableSliderRepeat((SliderRepeat)hitObject); - break; - - case 3: - hitObject = new SliderTailCircle(slider) { StartTime = Time.Current, ClassicSliderBehaviour = classic }; - drawableHitObject = new DrawableSliderTail((SliderTailCircle)hitObject); - break; - - case 4: - hitObject = slider; - drawableHitObject = new DrawableSlider(slider); - break; - - default: - throw new UnreachableException(); - } - if (!drawableHitObject.DisplayResult) return; + var hitObject = drawableHitObject.HitObject; var result = new OsuJudgementResult(hitObject, hitObject.Judgement) { Type = hit ? hitObject.Judgement.MaxResult : hitObject.Judgement.MinResult, }; - var judgement = judgementPools[cellIndex].Get(result.Type, d => + var judgement = pool.Get(result.Type, d => { d.Anchor = Anchor.Centre; d.Origin = Anchor.Centre;