From 63e0768207752f674a44ada84acfc61be63f508c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 22 Mar 2023 14:44:52 +0900 Subject: [PATCH 01/26] Show count of beatmaps in collections in manage dialog --- .../Collections/DrawableCollectionListItem.cs | 65 +++++++++++++++++-- 1 file changed, 59 insertions(+), 6 deletions(-) diff --git a/osu.Game/Collections/DrawableCollectionListItem.cs b/osu.Game/Collections/DrawableCollectionListItem.cs index 23156b1ad5..efeb066869 100644 --- a/osu.Game/Collections/DrawableCollectionListItem.cs +++ b/osu.Game/Collections/DrawableCollectionListItem.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Collections.Generic; using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; @@ -13,6 +14,7 @@ using osu.Framework.Input.Events; using osu.Game.Database; using osu.Game.Graphics; using osu.Game.Graphics.Containers; +using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; using osu.Game.Overlays; using osuTK; @@ -25,7 +27,7 @@ namespace osu.Game.Collections /// public partial class DrawableCollectionListItem : OsuRearrangeableListItem> { - private const float item_height = 35; + private const float item_height = 45; private const float button_width = item_height * 0.75f; /// @@ -81,12 +83,10 @@ namespace osu.Game.Collections Padding = new MarginPadding { Right = collection.IsManaged ? button_width : 0 }, Children = new Drawable[] { - textBox = new ItemTextBox + textBox = new ItemTextBox(collection) { - RelativeSizeAxes = Axes.Both, - Size = Vector2.One, - CornerRadius = item_height / 2, - PlaceholderText = collection.IsManaged ? string.Empty : "Create a new collection" + RelativeSizeAxes = Axes.X, + Height = item_height }, } }, @@ -117,11 +117,64 @@ namespace osu.Game.Collections { protected override float LeftRightPadding => item_height / 2; + private const float count_text_size = 12; + + [Resolved] + private RealmAccess realm { get; set; } = null!; + + private readonly Live collection; + + private OsuSpriteText countText = null!; + + private IDisposable? itemCountSubscription; + + public ItemTextBox(Live collection) + { + this.collection = collection; + + CornerRadius = item_height / 2; + } + [BackgroundDependencyLoader] private void load(OsuColour colours) { BackgroundUnfocused = colours.GreySeaFoamDarker.Darken(0.5f); BackgroundFocused = colours.GreySeaFoam; + + if (collection.IsManaged) + { + TextContainer.Height *= (Height - count_text_size) / Height; + TextContainer.Margin = new MarginPadding { Bottom = count_text_size }; + + TextContainer.Add(countText = new OsuSpriteText + { + Anchor = Anchor.BottomLeft, + Origin = Anchor.TopLeft, + Depth = float.MinValue, + Font = OsuFont.Default.With(size: count_text_size, weight: FontWeight.SemiBold), + Margin = new MarginPadding { Top = 2, Left = 2 }, + Colour = colours.Yellow + }); + + itemCountSubscription = realm.SubscribeToPropertyChanged>(r => r.Find(collection.ID), c => c.BeatmapMD5Hashes, items => + { + countText.Text = items.Count == 1 + // Intentionally not localised until we have proper support for this (see https://github.com/ppy/osu-framework/pull/4918 + // but also in this case we want support for formatting a number within a string). + ? $"{items.Count:#,0} beatmap" + : $"{items.Count:#,0} beatmaps"; + }); + } + else + { + PlaceholderText = "Create a new collection"; + } + } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + itemCountSubscription?.Dispose(); } } From 954be126922a63458dff577917ebf46e3ac72b75 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 22 Mar 2023 14:46:13 +0900 Subject: [PATCH 02/26] Debounce updates to ensure event isn't fired too often after much collection management --- .../Collections/DrawableCollectionListItem.cs | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/osu.Game/Collections/DrawableCollectionListItem.cs b/osu.Game/Collections/DrawableCollectionListItem.cs index efeb066869..87cc14ecb9 100644 --- a/osu.Game/Collections/DrawableCollectionListItem.cs +++ b/osu.Game/Collections/DrawableCollectionListItem.cs @@ -156,14 +156,17 @@ namespace osu.Game.Collections Colour = colours.Yellow }); - itemCountSubscription = realm.SubscribeToPropertyChanged>(r => r.Find(collection.ID), c => c.BeatmapMD5Hashes, items => - { - countText.Text = items.Count == 1 - // Intentionally not localised until we have proper support for this (see https://github.com/ppy/osu-framework/pull/4918 - // but also in this case we want support for formatting a number within a string). - ? $"{items.Count:#,0} beatmap" - : $"{items.Count:#,0} beatmaps"; - }); + itemCountSubscription = realm.SubscribeToPropertyChanged>(r => r.Find(collection.ID), c => c.BeatmapMD5Hashes, _ => + Scheduler.AddOnce(() => + { + int count = collection.PerformRead(c => c.BeatmapMD5Hashes.Count); + + countText.Text = count == 1 + // Intentionally not localised until we have proper support for this (see https://github.com/ppy/osu-framework/pull/4918 + // but also in this case we want support for formatting a number within a string). + ? $"{count:#,0} beatmap" + : $"{count:#,0} beatmaps"; + })); } else { From 256789193f7d99d6e1dd5ca00f23a82830d195a2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 3 Apr 2023 15:28:01 +0900 Subject: [PATCH 03/26] Remove redundant type specification --- osu.Game/Collections/DrawableCollectionListItem.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game/Collections/DrawableCollectionListItem.cs b/osu.Game/Collections/DrawableCollectionListItem.cs index 87cc14ecb9..31b127ef2a 100644 --- a/osu.Game/Collections/DrawableCollectionListItem.cs +++ b/osu.Game/Collections/DrawableCollectionListItem.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using System; -using System.Collections.Generic; using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; @@ -156,7 +155,7 @@ namespace osu.Game.Collections Colour = colours.Yellow }); - itemCountSubscription = realm.SubscribeToPropertyChanged>(r => r.Find(collection.ID), c => c.BeatmapMD5Hashes, _ => + itemCountSubscription = realm.SubscribeToPropertyChanged(r => r.Find(collection.ID), c => c.BeatmapMD5Hashes, _ => Scheduler.AddOnce(() => { int count = collection.PerformRead(c => c.BeatmapMD5Hashes.Count); From 4a164b7b149ff7c8f78d15f904fcb61673ac9ff8 Mon Sep 17 00:00:00 2001 From: Joppe27 Date: Sun, 11 Dec 2022 02:17:50 +0100 Subject: [PATCH 04/26] Add legacy taiko swell --- .../Objects/Drawables/DrawableSwell.cs | 113 ++------------ .../Objects/ISkinnableSwell.cs | 22 +++ .../Argon/TaikoArgonSkinTransformer.cs | 2 +- .../Skinning/Default/DefaultSwell.cs | 142 ++++++++++++++++++ .../Skinning/Legacy/LegacySwell.cs | 136 +++++++++++++++++ .../Skinning/Legacy/LegacySwellCirclePiece.cs | 23 +++ .../Legacy/TaikoLegacySkinTransformer.cs | 10 +- .../TaikoSkinComponents.cs | 1 + 8 files changed, 348 insertions(+), 101 deletions(-) create mode 100644 osu.Game.Rulesets.Taiko/Objects/ISkinnableSwell.cs create mode 100644 osu.Game.Rulesets.Taiko/Skinning/Default/DefaultSwell.cs create mode 100644 osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacySwell.cs create mode 100644 osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacySwellCirclePiece.cs diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs index 28617b35f6..cba044959c 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs @@ -6,14 +6,9 @@ using System; using System.Linq; using JetBrains.Annotations; -using osu.Framework.Allocation; -using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Game.Graphics; using osu.Game.Rulesets.Objects.Drawables; -using osuTK.Graphics; -using osu.Framework.Graphics.Shapes; using osu.Framework.Input.Events; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Taiko.Skinning.Default; @@ -25,11 +20,6 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables { public partial class DrawableSwell : DrawableTaikoHitObject { - private const float target_ring_thick_border = 1.4f; - private const float target_ring_thin_border = 1f; - private const float target_ring_scale = 5f; - private const float inner_ring_alpha = 0.65f; - /// /// Offset away from the start time of the swell at which the ring starts appearing. /// @@ -37,10 +27,9 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables private Vector2 baseSize; + private readonly SkinnableDrawable spinnerBody; + private readonly Container ticks; - private readonly Container bodyContainer; - private readonly CircularContainer targetRing; - private readonly CircularContainer expandingRing; private double? lastPressHandleTime; @@ -61,82 +50,17 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables { FillMode = FillMode.Fit; - Content.Add(bodyContainer = new Container + Content.Add(spinnerBody = new SkinnableDrawable(new TaikoSkinComponentLookup(TaikoSkinComponents.Swell), _ => new DefaultSwell()) { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, RelativeSizeAxes = Axes.Both, - Depth = 1, - Children = new Drawable[] - { - expandingRing = new CircularContainer - { - Name = "Expanding ring", - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Alpha = 0, - RelativeSizeAxes = Axes.Both, - Blending = BlendingParameters.Additive, - Masking = true, - Children = new[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Alpha = inner_ring_alpha, - } - } - }, - targetRing = new CircularContainer - { - Name = "Target ring (thick border)", - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - Masking = true, - BorderThickness = target_ring_thick_border, - Blending = BlendingParameters.Additive, - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Alpha = 0, - AlwaysPresent = true - }, - new CircularContainer - { - Name = "Target ring (thin border)", - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - Masking = true, - BorderThickness = target_ring_thin_border, - BorderColour = Color4.White, - Children = new[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Alpha = 0, - AlwaysPresent = true - } - } - } - } - } - } }); AddInternal(ticks = new Container { RelativeSizeAxes = Axes.Both }); } - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - expandingRing.Colour = colours.YellowLight; - targetRing.BorderColour = colours.YellowDark.Opacity(0.25f); - } - - protected override SkinnableDrawable CreateMainPiece() => new SkinnableDrawable(new TaikoSkinComponentLookup(TaikoSkinComponents.Swell), + protected override SkinnableDrawable CreateMainPiece() => new SkinnableDrawable(new TaikoSkinComponentLookup(TaikoSkinComponents.SwellCirclePiece), _ => new SwellCirclePiece { // to allow for rotation transform @@ -208,16 +132,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables int numHits = ticks.Count(r => r.IsHit); - float completion = (float)numHits / HitObject.RequiredHits; - - expandingRing - .FadeTo(expandingRing.Alpha + Math.Clamp(completion / 16, 0.1f, 0.6f), 50) - .Then() - .FadeTo(completion / 8, 2000, Easing.OutQuint); - - MainPiece.Drawable.RotateTo((float)(completion * HitObject.Duration / 8), 4000, Easing.OutQuint); - - expandingRing.ScaleTo(1f + Math.Min(target_ring_scale - 1f, (target_ring_scale - 1f) * completion * 1.3f), 260, Easing.OutQuint); + (spinnerBody.Drawable as ISkinnableSwell)?.OnUserInput(this, numHits, MainPiece); if (numHits == HitObject.RequiredHits) ApplyMaxResult(); @@ -252,24 +167,24 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables { base.UpdateStartTimeStateTransforms(); - using (BeginDelayedSequence(-ring_appear_offset)) - targetRing.ScaleTo(target_ring_scale, 400, Easing.OutQuint); + (spinnerBody.Drawable as ISkinnableSwell)?.ApplyPassiveTransforms(this, MainPiece); } protected override void UpdateHitStateTransforms(ArmedState state) { - const double transition_duration = 300; - switch (state) { case ArmedState.Idle: - expandingRing.FadeTo(0); + HandleUserInput = true; break; case ArmedState.Miss: case ArmedState.Hit: - this.FadeOut(transition_duration, Easing.Out); - bodyContainer.ScaleTo(1.4f, transition_duration); + // Postpone drawable hitobject expiration until it has animated/faded out. Inputs on the object are disallowed during this delay. + LifetimeEnd = Time.Current + 1200; + HandleUserInput = false; + + (spinnerBody.Drawable as ISkinnableSwell)?.OnHitObjectEnd(state, MainPiece); break; } } diff --git a/osu.Game.Rulesets.Taiko/Objects/ISkinnableSwell.cs b/osu.Game.Rulesets.Taiko/Objects/ISkinnableSwell.cs new file mode 100644 index 0000000000..18feff5bb9 --- /dev/null +++ b/osu.Game.Rulesets.Taiko/Objects/ISkinnableSwell.cs @@ -0,0 +1,22 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.Taiko.Objects.Drawables; +using osu.Game.Skinning; + +namespace osu.Game.Rulesets.Taiko.Objects +{ + public interface ISkinnableSwell + { + void OnUserInput(DrawableTaikoHitObject swell, int numHits, SkinnableDrawable mainPiece); + + void OnHitObjectEnd(ArmedState state, SkinnableDrawable mainPiece); + + /// + /// Applies passive transforms on HitObject start. Gets called every time DrawableTaikoHitobject + /// changes state. This happens on creation, and when the object is completed (as in hit or missed). + /// + void ApplyPassiveTransforms(DrawableTaikoHitObject swell, SkinnableDrawable mainPiece); + } +} diff --git a/osu.Game.Rulesets.Taiko/Skinning/Argon/TaikoArgonSkinTransformer.cs b/osu.Game.Rulesets.Taiko/Skinning/Argon/TaikoArgonSkinTransformer.cs index bfc9e8648d..cfd30dd628 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Argon/TaikoArgonSkinTransformer.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Argon/TaikoArgonSkinTransformer.cs @@ -68,7 +68,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Argon case TaikoSkinComponents.TaikoExplosionOk: return new ArgonHitExplosion(taikoComponent.Component); - case TaikoSkinComponents.Swell: + case TaikoSkinComponents.SwellCirclePiece: return new ArgonSwellCirclePiece(); } diff --git a/osu.Game.Rulesets.Taiko/Skinning/Default/DefaultSwell.cs b/osu.Game.Rulesets.Taiko/Skinning/Default/DefaultSwell.cs new file mode 100644 index 0000000000..e525e9873d --- /dev/null +++ b/osu.Game.Rulesets.Taiko/Skinning/Default/DefaultSwell.cs @@ -0,0 +1,142 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using osu.Framework.Allocation; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Game.Graphics; +using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.Taiko.Objects; +using osu.Game.Rulesets.Taiko.Objects.Drawables; +using osu.Game.Skinning; +using osuTK.Graphics; + +namespace osu.Game.Rulesets.Taiko.Skinning.Default +{ + public partial class DefaultSwell : Container, ISkinnableSwell + { + private const float target_ring_thick_border = 1.4f; + private const float target_ring_thin_border = 1f; + private const float target_ring_scale = 5f; + private const float inner_ring_alpha = 0.65f; + + private readonly Container bodyContainer; + private readonly CircularContainer targetRing; + private readonly CircularContainer expandingRing; + + public DefaultSwell() + { + Anchor = Anchor.Centre; + Origin = Anchor.Centre; + RelativeSizeAxes = Axes.Both; + + Content.Add(bodyContainer = new Container + { + RelativeSizeAxes = Axes.Both, + Depth = 1, + Children = new Drawable[] + { + expandingRing = new CircularContainer + { + Name = "Expanding ring", + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Alpha = 0, + RelativeSizeAxes = Axes.Both, + Blending = BlendingParameters.Additive, + Masking = true, + Children = new[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Alpha = inner_ring_alpha, + } + } + }, + targetRing = new CircularContainer + { + Name = "Target ring (thick border)", + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Masking = true, + BorderThickness = target_ring_thick_border, + Blending = BlendingParameters.Additive, + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Alpha = 0, + AlwaysPresent = true + }, + new CircularContainer + { + Name = "Target ring (thin border)", + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Masking = true, + BorderThickness = target_ring_thin_border, + BorderColour = Color4.White, + Children = new[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Alpha = 0, + AlwaysPresent = true + } + } + } + } + } + } + }); + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + expandingRing.Colour = colours.YellowLight; + targetRing.BorderColour = colours.YellowDark.Opacity(0.25f); + } + + public void OnUserInput(DrawableTaikoHitObject swell, int numHits, SkinnableDrawable mainPiece) + { + float completion = (float)numHits / swell.HitObject.RequiredHits; + + mainPiece.Drawable.RotateTo((float)(completion * swell.HitObject.Duration / 8), 4000, Easing.OutQuint); + + expandingRing.ScaleTo(1f + Math.Min(target_ring_scale - 1f, (target_ring_scale - 1f) * completion * 1.3f), 260, Easing.OutQuint); + + expandingRing + .FadeTo(expandingRing.Alpha + Math.Clamp(completion / 16, 0.1f, 0.6f), 50) + .Then() + .FadeTo(completion / 8, 2000, Easing.OutQuint); + } + + public void OnHitObjectEnd(ArmedState state, SkinnableDrawable mainPiece) + { + const double transition_duration = 300; + + bodyContainer.FadeOut(transition_duration, Easing.OutQuad); + bodyContainer.ScaleTo(1.4f, transition_duration); + mainPiece.FadeOut(transition_duration, Easing.OutQuad); + } + + public void ApplyPassiveTransforms(DrawableTaikoHitObject swell, SkinnableDrawable mainPiece) + { + if (swell.IsHit == false) + expandingRing.FadeTo(0); + + const double ring_appear_offset = 100; + + targetRing.Delay(ring_appear_offset).ScaleTo(target_ring_scale, 400, Easing.OutQuint); + } + } +} diff --git a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacySwell.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacySwell.cs new file mode 100644 index 0000000000..240ec71f94 --- /dev/null +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacySwell.cs @@ -0,0 +1,136 @@ +// 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.Graphics; +using osu.Framework.Allocation; +using osu.Framework.Graphics.Containers; +using osu.Game.Skinning; +using osu.Framework.Graphics.Sprites; +using osu.Game.Rulesets.Taiko.Objects.Drawables; +using osu.Game.Rulesets.Taiko.Objects; +using osu.Framework.Audio.Sample; +using osu.Game.Audio; +using osuTK; +using osu.Game.Rulesets.Objects.Drawables; + +namespace osu.Game.Rulesets.Taiko.Skinning.Legacy +{ + public partial class LegacySwell : Container, ISkinnableSwell + { + private Container bodyContainer = null!; + private Sprite spinnerCircle = null!; + private Sprite shrinkingRing = null!; + private Sprite clearAnimation = null!; + private ISample? clearSample; + private LegacySpriteText remainingHitsCountdown = null!; + + private bool samplePlayed; + + public LegacySwell() + { + Anchor = Anchor.Centre; + Origin = Anchor.Centre; + RelativeSizeAxes = Axes.Both; + } + + [BackgroundDependencyLoader] + private void load(ISkinSource skin, SkinManager skinManager) + { + Child = new Container + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Position = new Vector2(200f, 100f), + + Children = new Drawable[] + { + bodyContainer = new Container + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Alpha = 0, + + Children = new Drawable[] + { + spinnerCircle = new Sprite + { + Texture = skin.GetTexture("spinner-circle"), + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Scale = new Vector2(0.8f), + }, + shrinkingRing = new Sprite + { + Texture = skin.GetTexture("spinner-approachcircle") ?? skinManager.DefaultClassicSkin.GetTexture("spinner-approachcircle"), + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Scale = Vector2.One, + }, + remainingHitsCountdown = new LegacySpriteText(LegacyFont.Combo) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Position = new Vector2(0f, 165f), + Scale = Vector2.One, + }, + } + }, + clearAnimation = new Sprite + { + // File extension is included here because of a GetTexture limitation, see #21543 + Texture = skin.GetTexture("spinner-osu.png"), + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Position = new Vector2(0f, -165f), + Scale = new Vector2(0.3f), + Alpha = 0, + }, + } + }; + + clearSample = skin.GetSample(new SampleInfo("spinner-osu")); + } + + public void OnUserInput(DrawableTaikoHitObject swell, int numHits, SkinnableDrawable mainPiece) + { + remainingHitsCountdown.Text = $"{swell.HitObject.RequiredHits - numHits}"; + spinnerCircle.RotateTo(180f * numHits, 1000, Easing.OutQuint); + } + + public void OnHitObjectEnd(ArmedState state, SkinnableDrawable mainPiece) + { + const double clear_transition_duration = 300; + + bodyContainer.FadeOut(clear_transition_duration, Easing.OutQuad); + + if (state == ArmedState.Hit) + { + if (!samplePlayed) + { + clearSample?.Play(); + samplePlayed = true; + } + + clearAnimation + .FadeIn(clear_transition_duration, Easing.InQuad) + .ScaleTo(0.8f, clear_transition_duration, Easing.InQuad) + .Delay(700).FadeOut(200, Easing.OutQuad); + } + } + + public void ApplyPassiveTransforms(DrawableTaikoHitObject swell, SkinnableDrawable mainPiece) + { + if (swell.IsHit == false) + { + remainingHitsCountdown.Text = $"{swell.HitObject.RequiredHits}"; + samplePlayed = false; + } + + const double body_transition_duration = 100; + + mainPiece.FadeOut(body_transition_duration); + bodyContainer.FadeIn(body_transition_duration); + shrinkingRing.ResizeTo(0.1f, swell.HitObject.Duration); + } + } +} diff --git a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacySwellCirclePiece.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacySwellCirclePiece.cs new file mode 100644 index 0000000000..40501d1d40 --- /dev/null +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacySwellCirclePiece.cs @@ -0,0 +1,23 @@ +// 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.Game.Skinning; +using osuTK; + +namespace osu.Game.Rulesets.Taiko.Skinning.Legacy +{ + internal partial class LegacySwellCirclePiece : Sprite + { + [BackgroundDependencyLoader] + private void load(ISkinSource skin, SkinManager skinManager) + { + Texture = skin.GetTexture("spinner-warning") ?? skinManager.DefaultClassicSkin.GetTexture("spinner-circle"); + Anchor = Anchor.Centre; + Origin = Anchor.Centre; + Scale = skin.GetTexture("spinner-warning") != null ? Vector2.One : new Vector2(0.18f); + } + } +} diff --git a/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacySkinTransformer.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacySkinTransformer.cs index 5bdb824f1c..243d975216 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacySkinTransformer.cs @@ -66,7 +66,15 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy return this.GetAnimation("sliderscorepoint", false, false); case TaikoSkinComponents.Swell: - // todo: support taiko legacy swell (https://github.com/ppy/osu/issues/13601). + if (GetTexture("spinner-circle") != null) + return new LegacySwell(); + + return null; + + case TaikoSkinComponents.SwellCirclePiece: + if (GetTexture("spinner-circle") != null) + return new LegacySwellCirclePiece(); + return null; case TaikoSkinComponents.HitTarget: diff --git a/osu.Game.Rulesets.Taiko/TaikoSkinComponents.cs b/osu.Game.Rulesets.Taiko/TaikoSkinComponents.cs index 28133ffcb2..aa7e4686d8 100644 --- a/osu.Game.Rulesets.Taiko/TaikoSkinComponents.cs +++ b/osu.Game.Rulesets.Taiko/TaikoSkinComponents.cs @@ -11,6 +11,7 @@ namespace osu.Game.Rulesets.Taiko DrumRollBody, DrumRollTick, Swell, + SwellCirclePiece, HitTarget, PlayfieldBackgroundLeft, PlayfieldBackgroundRight, From fe84e6e5f53d5a3264b1fcbe68fb698b7c039f48 Mon Sep 17 00:00:00 2001 From: Joppe27 Date: Sun, 11 Dec 2022 02:19:06 +0100 Subject: [PATCH 05/26] Adjust existing test to accommodate swell size --- osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableSwell.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableSwell.cs b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableSwell.cs index c130b5f366..286b16aa34 100644 --- a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableSwell.cs +++ b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableSwell.cs @@ -20,6 +20,7 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning { Anchor = Anchor.Centre, Origin = Anchor.Centre, + Scale = new osuTK.Vector2(0.5f), })); } From 988450a2c4f8244d1ef1bc572d711ee781eaaa09 Mon Sep 17 00:00:00 2001 From: Joppe27 Date: Sun, 11 Dec 2022 02:23:48 +0100 Subject: [PATCH 06/26] Add test for expire delay Delaying the expiry of the drawable hitobject can potentially be dangerous and gameplay-altering when user inputs are accidentally handled. This is why I found a test necessary. --- .../TestSceneDrawableSwellExpireDelay.cs | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableSwellExpireDelay.cs diff --git a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableSwellExpireDelay.cs b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableSwellExpireDelay.cs new file mode 100644 index 0000000000..ad78ed3b20 --- /dev/null +++ b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableSwellExpireDelay.cs @@ -0,0 +1,41 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Collections.Generic; +using NUnit.Framework; +using osu.Game.Rulesets.Replays; +using osu.Game.Rulesets.Scoring; +using osu.Game.Rulesets.Taiko.Objects; +using osu.Game.Rulesets.Taiko.Replays; +using osu.Game.Rulesets.Taiko.Tests.Judgements; + +namespace osu.Game.Rulesets.Taiko.Tests.Skinning +{ + public partial class TestSceneDrawableSwellExpireDelay : JudgementTest + { + [Test] + public void TestExpireDelay() + { + const double swell_start = 1000; + const double swell_duration = 1000; + + Swell swell = new Swell + { + StartTime = swell_start, + Duration = swell_duration, + }; + + Hit hit = new Hit { StartTime = swell_start + swell_duration + 50 }; + + List frames = new List + { + new TaikoReplayFrame(0), + new TaikoReplayFrame(2100, TaikoAction.LeftCentre), + }; + + PerformTest(frames, CreateBeatmap(swell, hit)); + + AssertResult(0, HitResult.Ok); + } + } +} From e2196e8b9b97f447863b61124f7bd3454a505e60 Mon Sep 17 00:00:00 2001 From: Joppe27 Date: Tue, 13 Dec 2022 19:32:05 +0100 Subject: [PATCH 07/26] Rename methods and skin component + add comments --- .../Objects/Drawables/DrawableSwell.cs | 13 ++++++++----- osu.Game.Rulesets.Taiko/Objects/ISkinnableSwell.cs | 10 +++------- .../Skinning/Default/DefaultSwell.cs | 6 +++--- .../Skinning/Legacy/LegacySwell.cs | 6 +++--- .../Skinning/Legacy/TaikoLegacySkinTransformer.cs | 2 +- osu.Game.Rulesets.Taiko/TaikoSkinComponents.cs | 2 +- 6 files changed, 19 insertions(+), 20 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs index cba044959c..54a609f7d3 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs @@ -50,7 +50,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables { FillMode = FillMode.Fit; - Content.Add(spinnerBody = new SkinnableDrawable(new TaikoSkinComponentLookup(TaikoSkinComponents.Swell), _ => new DefaultSwell()) + Content.Add(spinnerBody = new SkinnableDrawable(new TaikoSkinComponentLookup(TaikoSkinComponents.SwellBody), _ => new DefaultSwell()) { Anchor = Anchor.Centre, Origin = Anchor.Centre, @@ -132,7 +132,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables int numHits = ticks.Count(r => r.IsHit); - (spinnerBody.Drawable as ISkinnableSwell)?.OnUserInput(this, numHits, MainPiece); + (spinnerBody.Drawable as ISkinnableSwell)?.AnimateSwellProgress(this, numHits, MainPiece); if (numHits == HitObject.RequiredHits) ApplyMaxResult(); @@ -167,7 +167,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables { base.UpdateStartTimeStateTransforms(); - (spinnerBody.Drawable as ISkinnableSwell)?.ApplyPassiveTransforms(this, MainPiece); + (spinnerBody.Drawable as ISkinnableSwell)?.AnimateSwellStart(this, MainPiece); } protected override void UpdateHitStateTransforms(ArmedState state) @@ -175,16 +175,19 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables switch (state) { case ArmedState.Idle: + // Only for rewind support. Reallows user inputs if swell is rewound from being hit/missed to being idle. HandleUserInput = true; break; case ArmedState.Miss: case ArmedState.Hit: + const int clear_animation_duration = 1200; + // Postpone drawable hitobject expiration until it has animated/faded out. Inputs on the object are disallowed during this delay. - LifetimeEnd = Time.Current + 1200; + LifetimeEnd = Time.Current + clear_animation_duration; HandleUserInput = false; - (spinnerBody.Drawable as ISkinnableSwell)?.OnHitObjectEnd(state, MainPiece); + (spinnerBody.Drawable as ISkinnableSwell)?.AnimateSwellCompletion(state, MainPiece); break; } } diff --git a/osu.Game.Rulesets.Taiko/Objects/ISkinnableSwell.cs b/osu.Game.Rulesets.Taiko/Objects/ISkinnableSwell.cs index 18feff5bb9..3cdb3566fb 100644 --- a/osu.Game.Rulesets.Taiko/Objects/ISkinnableSwell.cs +++ b/osu.Game.Rulesets.Taiko/Objects/ISkinnableSwell.cs @@ -9,14 +9,10 @@ namespace osu.Game.Rulesets.Taiko.Objects { public interface ISkinnableSwell { - void OnUserInput(DrawableTaikoHitObject swell, int numHits, SkinnableDrawable mainPiece); + void AnimateSwellProgress(DrawableTaikoHitObject swell, int numHits, SkinnableDrawable mainPiece); - void OnHitObjectEnd(ArmedState state, SkinnableDrawable mainPiece); + void AnimateSwellCompletion(ArmedState state, SkinnableDrawable mainPiece); - /// - /// Applies passive transforms on HitObject start. Gets called every time DrawableTaikoHitobject - /// changes state. This happens on creation, and when the object is completed (as in hit or missed). - /// - void ApplyPassiveTransforms(DrawableTaikoHitObject swell, SkinnableDrawable mainPiece); + void AnimateSwellStart(DrawableTaikoHitObject swell, SkinnableDrawable mainPiece); } } diff --git a/osu.Game.Rulesets.Taiko/Skinning/Default/DefaultSwell.cs b/osu.Game.Rulesets.Taiko/Skinning/Default/DefaultSwell.cs index e525e9873d..cec07d8769 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Default/DefaultSwell.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Default/DefaultSwell.cs @@ -106,7 +106,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Default targetRing.BorderColour = colours.YellowDark.Opacity(0.25f); } - public void OnUserInput(DrawableTaikoHitObject swell, int numHits, SkinnableDrawable mainPiece) + public void AnimateSwellProgress(DrawableTaikoHitObject swell, int numHits, SkinnableDrawable mainPiece) { float completion = (float)numHits / swell.HitObject.RequiredHits; @@ -120,7 +120,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Default .FadeTo(completion / 8, 2000, Easing.OutQuint); } - public void OnHitObjectEnd(ArmedState state, SkinnableDrawable mainPiece) + public void AnimateSwellCompletion(ArmedState state, SkinnableDrawable mainPiece) { const double transition_duration = 300; @@ -129,7 +129,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Default mainPiece.FadeOut(transition_duration, Easing.OutQuad); } - public void ApplyPassiveTransforms(DrawableTaikoHitObject swell, SkinnableDrawable mainPiece) + public void AnimateSwellStart(DrawableTaikoHitObject swell, SkinnableDrawable mainPiece) { if (swell.IsHit == false) expandingRing.FadeTo(0); diff --git a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacySwell.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacySwell.cs index 240ec71f94..fdddea2df5 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacySwell.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacySwell.cs @@ -91,13 +91,13 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy clearSample = skin.GetSample(new SampleInfo("spinner-osu")); } - public void OnUserInput(DrawableTaikoHitObject swell, int numHits, SkinnableDrawable mainPiece) + public void AnimateSwellProgress(DrawableTaikoHitObject swell, int numHits, SkinnableDrawable mainPiece) { remainingHitsCountdown.Text = $"{swell.HitObject.RequiredHits - numHits}"; spinnerCircle.RotateTo(180f * numHits, 1000, Easing.OutQuint); } - public void OnHitObjectEnd(ArmedState state, SkinnableDrawable mainPiece) + public void AnimateSwellCompletion(ArmedState state, SkinnableDrawable mainPiece) { const double clear_transition_duration = 300; @@ -118,7 +118,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy } } - public void ApplyPassiveTransforms(DrawableTaikoHitObject swell, SkinnableDrawable mainPiece) + public void AnimateSwellStart(DrawableTaikoHitObject swell, SkinnableDrawable mainPiece) { if (swell.IsHit == false) { diff --git a/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacySkinTransformer.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacySkinTransformer.cs index 243d975216..b9ebed6b80 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacySkinTransformer.cs @@ -65,7 +65,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy case TaikoSkinComponents.DrumRollTick: return this.GetAnimation("sliderscorepoint", false, false); - case TaikoSkinComponents.Swell: + case TaikoSkinComponents.SwellBody: if (GetTexture("spinner-circle") != null) return new LegacySwell(); diff --git a/osu.Game.Rulesets.Taiko/TaikoSkinComponents.cs b/osu.Game.Rulesets.Taiko/TaikoSkinComponents.cs index aa7e4686d8..0145fb6482 100644 --- a/osu.Game.Rulesets.Taiko/TaikoSkinComponents.cs +++ b/osu.Game.Rulesets.Taiko/TaikoSkinComponents.cs @@ -10,7 +10,7 @@ namespace osu.Game.Rulesets.Taiko RimHit, DrumRollBody, DrumRollTick, - Swell, + SwellBody, SwellCirclePiece, HitTarget, PlayfieldBackgroundLeft, From 4fd8a4dc5a6f0453767175aa706ea331bbfca7c6 Mon Sep 17 00:00:00 2001 From: Nathan Du Date: Fri, 31 Jan 2025 16:55:39 +0800 Subject: [PATCH 08/26] Merge taiko swell components Per , taking a variation of the "Make all swell main pieces implement ISkinnableSwellPart" path. Should clean the interface up enough for further refactors. --- .../Objects/Drawables/DrawableSwell.cs | 25 ++++-------- .../Objects/ISkinnableSwell.cs | 7 ++-- .../Skinning/Argon/ArgonSwell.cs | 20 ++++++++++ .../Argon/TaikoArgonSkinTransformer.cs | 4 +- .../Skinning/Default/DefaultSwell.cs | 26 +++++++++---- ...wellSymbolPiece.cs => SwellCirclePiece.cs} | 0 .../Skinning/Legacy/LegacySwell.cs | 38 +++++++++++-------- .../Legacy/TaikoLegacySkinTransformer.cs | 6 --- .../TaikoSkinComponents.cs | 1 - 9 files changed, 75 insertions(+), 52 deletions(-) create mode 100644 osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonSwell.cs rename osu.Game.Rulesets.Taiko/Skinning/Default/{SwellSymbolPiece.cs => SwellCirclePiece.cs} (100%) diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs index 54a609f7d3..18d76d02a1 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs @@ -27,8 +27,6 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables private Vector2 baseSize; - private readonly SkinnableDrawable spinnerBody; - private readonly Container ticks; private double? lastPressHandleTime; @@ -50,24 +48,17 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables { FillMode = FillMode.Fit; - Content.Add(spinnerBody = new SkinnableDrawable(new TaikoSkinComponentLookup(TaikoSkinComponents.SwellBody), _ => new DefaultSwell()) + AddInternal(ticks = new Container { RelativeSizeAxes = Axes.Both }); + } + + protected override SkinnableDrawable CreateMainPiece() => new SkinnableDrawable(new TaikoSkinComponentLookup(TaikoSkinComponents.SwellBody), + _ => new DefaultSwell { Anchor = Anchor.Centre, Origin = Anchor.Centre, RelativeSizeAxes = Axes.Both, }); - AddInternal(ticks = new Container { RelativeSizeAxes = Axes.Both }); - } - - protected override SkinnableDrawable CreateMainPiece() => new SkinnableDrawable(new TaikoSkinComponentLookup(TaikoSkinComponents.SwellCirclePiece), - _ => new SwellCirclePiece - { - // to allow for rotation transform - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - }); - protected override void RecreatePieces() { base.RecreatePieces(); @@ -132,7 +123,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables int numHits = ticks.Count(r => r.IsHit); - (spinnerBody.Drawable as ISkinnableSwell)?.AnimateSwellProgress(this, numHits, MainPiece); + (MainPiece.Drawable as ISkinnableSwell)?.AnimateSwellProgress(this, numHits); if (numHits == HitObject.RequiredHits) ApplyMaxResult(); @@ -167,7 +158,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables { base.UpdateStartTimeStateTransforms(); - (spinnerBody.Drawable as ISkinnableSwell)?.AnimateSwellStart(this, MainPiece); + (MainPiece.Drawable as ISkinnableSwell)?.AnimateSwellStart(this); } protected override void UpdateHitStateTransforms(ArmedState state) @@ -187,7 +178,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables LifetimeEnd = Time.Current + clear_animation_duration; HandleUserInput = false; - (spinnerBody.Drawable as ISkinnableSwell)?.AnimateSwellCompletion(state, MainPiece); + (MainPiece.Drawable as ISkinnableSwell)?.AnimateSwellCompletion(state); break; } } diff --git a/osu.Game.Rulesets.Taiko/Objects/ISkinnableSwell.cs b/osu.Game.Rulesets.Taiko/Objects/ISkinnableSwell.cs index 3cdb3566fb..9bd169acd7 100644 --- a/osu.Game.Rulesets.Taiko/Objects/ISkinnableSwell.cs +++ b/osu.Game.Rulesets.Taiko/Objects/ISkinnableSwell.cs @@ -3,16 +3,15 @@ using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Taiko.Objects.Drawables; -using osu.Game.Skinning; namespace osu.Game.Rulesets.Taiko.Objects { public interface ISkinnableSwell { - void AnimateSwellProgress(DrawableTaikoHitObject swell, int numHits, SkinnableDrawable mainPiece); + void AnimateSwellProgress(DrawableTaikoHitObject swell, int numHits); - void AnimateSwellCompletion(ArmedState state, SkinnableDrawable mainPiece); + void AnimateSwellCompletion(ArmedState state); - void AnimateSwellStart(DrawableTaikoHitObject swell, SkinnableDrawable mainPiece); + void AnimateSwellStart(DrawableTaikoHitObject swell); } } diff --git a/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonSwell.cs b/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonSwell.cs new file mode 100644 index 0000000000..65cd936e38 --- /dev/null +++ b/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonSwell.cs @@ -0,0 +1,20 @@ +// 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.Graphics; +using osu.Game.Rulesets.Taiko.Skinning.Default; + +namespace osu.Game.Rulesets.Taiko.Skinning.Argon +{ + public partial class ArgonSwell : DefaultSwell + { + protected override Drawable CreateCentreCircle() + { + return new ArgonSwellCirclePiece() + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }; + } + } +} diff --git a/osu.Game.Rulesets.Taiko/Skinning/Argon/TaikoArgonSkinTransformer.cs b/osu.Game.Rulesets.Taiko/Skinning/Argon/TaikoArgonSkinTransformer.cs index cfd30dd628..b588a22d12 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Argon/TaikoArgonSkinTransformer.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Argon/TaikoArgonSkinTransformer.cs @@ -68,8 +68,8 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Argon case TaikoSkinComponents.TaikoExplosionOk: return new ArgonHitExplosion(taikoComponent.Component); - case TaikoSkinComponents.SwellCirclePiece: - return new ArgonSwellCirclePiece(); + case TaikoSkinComponents.SwellBody: + return new ArgonSwell(); } break; diff --git a/osu.Game.Rulesets.Taiko/Skinning/Default/DefaultSwell.cs b/osu.Game.Rulesets.Taiko/Skinning/Default/DefaultSwell.cs index cec07d8769..bdb444db90 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Default/DefaultSwell.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Default/DefaultSwell.cs @@ -11,7 +11,6 @@ using osu.Game.Graphics; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Taiko.Objects; using osu.Game.Rulesets.Taiko.Objects.Drawables; -using osu.Game.Skinning; using osuTK.Graphics; namespace osu.Game.Rulesets.Taiko.Skinning.Default @@ -26,6 +25,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Default private readonly Container bodyContainer; private readonly CircularContainer targetRing; private readonly CircularContainer expandingRing; + private readonly Drawable centreCircle; public DefaultSwell() { @@ -35,6 +35,8 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Default Content.Add(bodyContainer = new Container { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, RelativeSizeAxes = Axes.Both, Depth = 1, Children = new Drawable[] @@ -94,11 +96,21 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Default } } } - } + }, + centreCircle = CreateCentreCircle(), } }); } + protected virtual Drawable CreateCentreCircle() + { + return new SwellCirclePiece() + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }; + } + [BackgroundDependencyLoader] private void load(OsuColour colours) { @@ -106,11 +118,11 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Default targetRing.BorderColour = colours.YellowDark.Opacity(0.25f); } - public void AnimateSwellProgress(DrawableTaikoHitObject swell, int numHits, SkinnableDrawable mainPiece) + public void AnimateSwellProgress(DrawableTaikoHitObject swell, int numHits) { float completion = (float)numHits / swell.HitObject.RequiredHits; - mainPiece.Drawable.RotateTo((float)(completion * swell.HitObject.Duration / 8), 4000, Easing.OutQuint); + centreCircle.RotateTo((float)(completion * swell.HitObject.Duration / 8), 4000, Easing.OutQuint); expandingRing.ScaleTo(1f + Math.Min(target_ring_scale - 1f, (target_ring_scale - 1f) * completion * 1.3f), 260, Easing.OutQuint); @@ -120,16 +132,16 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Default .FadeTo(completion / 8, 2000, Easing.OutQuint); } - public void AnimateSwellCompletion(ArmedState state, SkinnableDrawable mainPiece) + public void AnimateSwellCompletion(ArmedState state) { const double transition_duration = 300; bodyContainer.FadeOut(transition_duration, Easing.OutQuad); bodyContainer.ScaleTo(1.4f, transition_duration); - mainPiece.FadeOut(transition_duration, Easing.OutQuad); + centreCircle.FadeOut(transition_duration, Easing.OutQuad); } - public void AnimateSwellStart(DrawableTaikoHitObject swell, SkinnableDrawable mainPiece) + public void AnimateSwellStart(DrawableTaikoHitObject swell) { if (swell.IsHit == false) expandingRing.FadeTo(0); diff --git a/osu.Game.Rulesets.Taiko/Skinning/Default/SwellSymbolPiece.cs b/osu.Game.Rulesets.Taiko/Skinning/Default/SwellCirclePiece.cs similarity index 100% rename from osu.Game.Rulesets.Taiko/Skinning/Default/SwellSymbolPiece.cs rename to osu.Game.Rulesets.Taiko/Skinning/Default/SwellCirclePiece.cs diff --git a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacySwell.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacySwell.cs index fdddea2df5..e487c5e051 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacySwell.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacySwell.cs @@ -18,6 +18,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy public partial class LegacySwell : Container, ISkinnableSwell { private Container bodyContainer = null!; + private Sprite warning = null!; private Sprite spinnerCircle = null!; private Sprite shrinkingRing = null!; private Sprite clearAnimation = null!; @@ -40,14 +41,21 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy { Anchor = Anchor.Centre, Origin = Anchor.Centre, - Position = new Vector2(200f, 100f), Children = new Drawable[] { + warning = new Sprite + { + Texture = skin.GetTexture("spinner-warning") ?? skinManager.DefaultClassicSkin.GetTexture("spinner-circle"), + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Scale = skin.GetTexture("spinner-warning") != null ? Vector2.One : new Vector2(0.18f), + }, bodyContainer = new Container { Anchor = Anchor.Centre, Origin = Anchor.Centre, + Position = new Vector2(200f, 100f), Alpha = 0, Children = new Drawable[] @@ -73,31 +81,31 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy Position = new Vector2(0f, 165f), Scale = Vector2.One, }, + clearAnimation = new Sprite + { + // File extension is included here because of a GetTexture limitation, see #21543 + Texture = skin.GetTexture("spinner-osu.png"), + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Position = new Vector2(0f, -165f), + Scale = new Vector2(0.3f), + Alpha = 0, + }, } }, - clearAnimation = new Sprite - { - // File extension is included here because of a GetTexture limitation, see #21543 - Texture = skin.GetTexture("spinner-osu.png"), - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Position = new Vector2(0f, -165f), - Scale = new Vector2(0.3f), - Alpha = 0, - }, } }; clearSample = skin.GetSample(new SampleInfo("spinner-osu")); } - public void AnimateSwellProgress(DrawableTaikoHitObject swell, int numHits, SkinnableDrawable mainPiece) + public void AnimateSwellProgress(DrawableTaikoHitObject swell, int numHits) { remainingHitsCountdown.Text = $"{swell.HitObject.RequiredHits - numHits}"; spinnerCircle.RotateTo(180f * numHits, 1000, Easing.OutQuint); } - public void AnimateSwellCompletion(ArmedState state, SkinnableDrawable mainPiece) + public void AnimateSwellCompletion(ArmedState state) { const double clear_transition_duration = 300; @@ -118,7 +126,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy } } - public void AnimateSwellStart(DrawableTaikoHitObject swell, SkinnableDrawable mainPiece) + public void AnimateSwellStart(DrawableTaikoHitObject swell) { if (swell.IsHit == false) { @@ -128,7 +136,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy const double body_transition_duration = 100; - mainPiece.FadeOut(body_transition_duration); + warning.FadeOut(body_transition_duration); bodyContainer.FadeIn(body_transition_duration); shrinkingRing.ResizeTo(0.1f, swell.HitObject.Duration); } diff --git a/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacySkinTransformer.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacySkinTransformer.cs index b9ebed6b80..8fa4551fd4 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacySkinTransformer.cs @@ -71,12 +71,6 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy return null; - case TaikoSkinComponents.SwellCirclePiece: - if (GetTexture("spinner-circle") != null) - return new LegacySwellCirclePiece(); - - return null; - case TaikoSkinComponents.HitTarget: if (GetTexture("taikobigcircle") != null) return new TaikoLegacyHitTarget(); diff --git a/osu.Game.Rulesets.Taiko/TaikoSkinComponents.cs b/osu.Game.Rulesets.Taiko/TaikoSkinComponents.cs index 0145fb6482..05c6316a05 100644 --- a/osu.Game.Rulesets.Taiko/TaikoSkinComponents.cs +++ b/osu.Game.Rulesets.Taiko/TaikoSkinComponents.cs @@ -11,7 +11,6 @@ namespace osu.Game.Rulesets.Taiko DrumRollBody, DrumRollTick, SwellBody, - SwellCirclePiece, HitTarget, PlayfieldBackgroundLeft, PlayfieldBackgroundRight, From 2a5540b39251c19f46a2965f0226f45d7a085f3e Mon Sep 17 00:00:00 2001 From: Nathan Du Date: Fri, 31 Jan 2025 17:51:35 +0800 Subject: [PATCH 09/26] remove ISkinnableSwell This commit removes ISkinnableSwell for taiko swell animations. In place of it, an event named UpdateHitProgress is added to DrawableSwell, and the skin swells are converted to listen to said event and ApplyCustomUpdateState, like how spinner skinning is implemented for std. --- .../Objects/Drawables/DrawableSwell.cs | 6 +- .../Objects/ISkinnableSwell.cs | 17 ----- .../Skinning/Default/DefaultSwell.cs | 70 +++++++++++------ .../Skinning/Legacy/LegacySwell.cs | 75 ++++++++++++------- 4 files changed, 101 insertions(+), 67 deletions(-) delete mode 100644 osu.Game.Rulesets.Taiko/Objects/ISkinnableSwell.cs diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs index 18d76d02a1..e0276db911 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs @@ -38,6 +38,8 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables /// public bool MustAlternate { get; internal set; } = true; + public event Action UpdateHitProgress; + public DrawableSwell() : this(null) { @@ -123,7 +125,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables int numHits = ticks.Count(r => r.IsHit); - (MainPiece.Drawable as ISkinnableSwell)?.AnimateSwellProgress(this, numHits); + UpdateHitProgress?.Invoke(numHits, HitObject.RequiredHits); if (numHits == HitObject.RequiredHits) ApplyMaxResult(); @@ -158,7 +160,6 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables { base.UpdateStartTimeStateTransforms(); - (MainPiece.Drawable as ISkinnableSwell)?.AnimateSwellStart(this); } protected override void UpdateHitStateTransforms(ArmedState state) @@ -178,7 +179,6 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables LifetimeEnd = Time.Current + clear_animation_duration; HandleUserInput = false; - (MainPiece.Drawable as ISkinnableSwell)?.AnimateSwellCompletion(state); break; } } diff --git a/osu.Game.Rulesets.Taiko/Objects/ISkinnableSwell.cs b/osu.Game.Rulesets.Taiko/Objects/ISkinnableSwell.cs deleted file mode 100644 index 9bd169acd7..0000000000 --- a/osu.Game.Rulesets.Taiko/Objects/ISkinnableSwell.cs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using osu.Game.Rulesets.Objects.Drawables; -using osu.Game.Rulesets.Taiko.Objects.Drawables; - -namespace osu.Game.Rulesets.Taiko.Objects -{ - public interface ISkinnableSwell - { - void AnimateSwellProgress(DrawableTaikoHitObject swell, int numHits); - - void AnimateSwellCompletion(ArmedState state); - - void AnimateSwellStart(DrawableTaikoHitObject swell); - } -} diff --git a/osu.Game.Rulesets.Taiko/Skinning/Default/DefaultSwell.cs b/osu.Game.Rulesets.Taiko/Skinning/Default/DefaultSwell.cs index bdb444db90..852116cbfe 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Default/DefaultSwell.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Default/DefaultSwell.cs @@ -4,6 +4,7 @@ using System; using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; @@ -15,13 +16,15 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Taiko.Skinning.Default { - public partial class DefaultSwell : Container, ISkinnableSwell + public partial class DefaultSwell : Container { private const float target_ring_thick_border = 1.4f; private const float target_ring_thin_border = 1f; private const float target_ring_scale = 5f; private const float inner_ring_alpha = 0.65f; + private DrawableSwell drawableSwell = null!; + private readonly Container bodyContainer; private readonly CircularContainer targetRing; private readonly CircularContainer expandingRing; @@ -102,6 +105,17 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Default }); } + [BackgroundDependencyLoader] + private void load(DrawableHitObject hitObject, OsuColour colours) + { + drawableSwell = (DrawableSwell)hitObject; + drawableSwell.UpdateHitProgress += animateSwellProgress; + drawableSwell.ApplyCustomUpdateState += updateStateTransforms; + + expandingRing.Colour = colours.YellowLight; + targetRing.BorderColour = colours.YellowDark.Opacity(0.25f); + } + protected virtual Drawable CreateCentreCircle() { return new SwellCirclePiece() @@ -111,18 +125,11 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Default }; } - [BackgroundDependencyLoader] - private void load(OsuColour colours) + private void animateSwellProgress(int numHits, int requiredHits) { - expandingRing.Colour = colours.YellowLight; - targetRing.BorderColour = colours.YellowDark.Opacity(0.25f); - } + float completion = (float)numHits / requiredHits; - public void AnimateSwellProgress(DrawableTaikoHitObject swell, int numHits) - { - float completion = (float)numHits / swell.HitObject.RequiredHits; - - centreCircle.RotateTo((float)(completion * swell.HitObject.Duration / 8), 4000, Easing.OutQuint); + centreCircle.RotateTo((float)(completion * drawableSwell.HitObject.Duration / 8), 4000, Easing.OutQuint); expandingRing.ScaleTo(1f + Math.Min(target_ring_scale - 1f, (target_ring_scale - 1f) * completion * 1.3f), 260, Easing.OutQuint); @@ -132,23 +139,42 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Default .FadeTo(completion / 8, 2000, Easing.OutQuint); } - public void AnimateSwellCompletion(ArmedState state) + private void updateStateTransforms(DrawableHitObject drawableHitObject, ArmedState state) { - const double transition_duration = 300; + if (!(drawableHitObject is DrawableSwell drawableSwell)) + return; - bodyContainer.FadeOut(transition_duration, Easing.OutQuad); - bodyContainer.ScaleTo(1.4f, transition_duration); - centreCircle.FadeOut(transition_duration, Easing.OutQuad); + Swell swell = drawableSwell.HitObject; + + using (BeginAbsoluteSequence(swell.StartTime)) + { + if (state == ArmedState.Idle) + expandingRing.FadeTo(0); + + const double ring_appear_offset = 100; + + targetRing.Delay(ring_appear_offset).ScaleTo(target_ring_scale, 400, Easing.OutQuint); + } + + using (BeginAbsoluteSequence(drawableSwell.HitStateUpdateTime)) + { + const double transition_duration = 300; + + bodyContainer.FadeOut(transition_duration, Easing.OutQuad); + bodyContainer.ScaleTo(1.4f, transition_duration); + centreCircle.FadeOut(transition_duration, Easing.OutQuad); + } } - public void AnimateSwellStart(DrawableTaikoHitObject swell) + protected override void Dispose(bool isDisposing) { - if (swell.IsHit == false) - expandingRing.FadeTo(0); + base.Dispose(isDisposing); - const double ring_appear_offset = 100; - - targetRing.Delay(ring_appear_offset).ScaleTo(target_ring_scale, 400, Easing.OutQuint); + if (drawableSwell.IsNotNull()) + { + drawableSwell.UpdateHitProgress -= animateSwellProgress; + drawableSwell.ApplyCustomUpdateState -= updateStateTransforms; + } } } } diff --git a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacySwell.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacySwell.cs index e487c5e051..60a0b1d951 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacySwell.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacySwell.cs @@ -12,11 +12,14 @@ using osu.Framework.Audio.Sample; using osu.Game.Audio; using osuTK; using osu.Game.Rulesets.Objects.Drawables; +using osu.Framework.Extensions.ObjectExtensions; namespace osu.Game.Rulesets.Taiko.Skinning.Legacy { - public partial class LegacySwell : Container, ISkinnableSwell + public partial class LegacySwell : Container { + private DrawableSwell drawableSwell = null!; + private Container bodyContainer = null!; private Sprite warning = null!; private Sprite spinnerCircle = null!; @@ -35,7 +38,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy } [BackgroundDependencyLoader] - private void load(ISkinSource skin, SkinManager skinManager) + private void load(DrawableHitObject hitObject, ISkinSource skin, SkinManager skinManager) { Child = new Container { @@ -96,49 +99,71 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy } }; + drawableSwell = (DrawableSwell)hitObject; + drawableSwell.UpdateHitProgress += animateSwellProgress; + drawableSwell.ApplyCustomUpdateState += updateStateTransforms; clearSample = skin.GetSample(new SampleInfo("spinner-osu")); } - public void AnimateSwellProgress(DrawableTaikoHitObject swell, int numHits) + private void animateSwellProgress(int numHits, int requiredHits) { - remainingHitsCountdown.Text = $"{swell.HitObject.RequiredHits - numHits}"; + remainingHitsCountdown.Text = $"{requiredHits - numHits}"; spinnerCircle.RotateTo(180f * numHits, 1000, Easing.OutQuint); } - public void AnimateSwellCompletion(ArmedState state) + private void updateStateTransforms(DrawableHitObject drawableHitObject, ArmedState state) { - const double clear_transition_duration = 300; + if (!(drawableHitObject is DrawableSwell drawableSwell)) + return; - bodyContainer.FadeOut(clear_transition_duration, Easing.OutQuad); + Swell swell = drawableSwell.HitObject; - if (state == ArmedState.Hit) + using (BeginAbsoluteSequence(swell.StartTime)) { - if (!samplePlayed) + if (state == ArmedState.Idle) { - clearSample?.Play(); - samplePlayed = true; + remainingHitsCountdown.Text = $"{swell.RequiredHits}"; + samplePlayed = false; } - clearAnimation - .FadeIn(clear_transition_duration, Easing.InQuad) - .ScaleTo(0.8f, clear_transition_duration, Easing.InQuad) - .Delay(700).FadeOut(200, Easing.OutQuad); + const double body_transition_duration = 100; + + warning.FadeOut(body_transition_duration); + bodyContainer.FadeIn(body_transition_duration); + shrinkingRing.ResizeTo(0.1f, swell.Duration); + } + + using (BeginAbsoluteSequence(drawableSwell.HitStateUpdateTime)) + { + const double clear_transition_duration = 300; + + bodyContainer.FadeOut(clear_transition_duration, Easing.OutQuad); + + if (state == ArmedState.Hit) + { + if (!samplePlayed) + { + clearSample?.Play(); + samplePlayed = true; + } + + clearAnimation + .FadeIn(clear_transition_duration, Easing.InQuad) + .ScaleTo(0.8f, clear_transition_duration, Easing.InQuad) + .Delay(700).FadeOut(200, Easing.OutQuad); + } } } - public void AnimateSwellStart(DrawableTaikoHitObject swell) + protected override void Dispose(bool isDisposing) { - if (swell.IsHit == false) + base.Dispose(isDisposing); + + if (drawableSwell.IsNotNull()) { - remainingHitsCountdown.Text = $"{swell.HitObject.RequiredHits}"; - samplePlayed = false; + drawableSwell.UpdateHitProgress -= animateSwellProgress; + drawableSwell.ApplyCustomUpdateState -= updateStateTransforms; } - - const double body_transition_duration = 100; - - warning.FadeOut(body_transition_duration); - bodyContainer.FadeIn(body_transition_duration); - shrinkingRing.ResizeTo(0.1f, swell.HitObject.Duration); } } } From ad2b469b143d74da7843a42563fe3e170a53d35c Mon Sep 17 00:00:00 2001 From: Nathan Du Date: Fri, 31 Jan 2025 18:52:19 +0800 Subject: [PATCH 10/26] remove spinner-osu.png workaround https://github.com/ppy/osu/issues/22084 --- osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacySwell.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacySwell.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacySwell.cs index 60a0b1d951..405b0b7692 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacySwell.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacySwell.cs @@ -86,8 +86,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy }, clearAnimation = new Sprite { - // File extension is included here because of a GetTexture limitation, see #21543 - Texture = skin.GetTexture("spinner-osu.png"), + Texture = skin.GetTexture("spinner-osu"), Anchor = Anchor.Centre, Origin = Anchor.Centre, Position = new Vector2(0f, -165f), From ac17b4065f06571cc3bf30cc7536e4746a78e9d3 Mon Sep 17 00:00:00 2001 From: Nathan Du Date: Fri, 31 Jan 2025 19:55:29 +0800 Subject: [PATCH 11/26] change legacy spinner animations to match stable Also removed a few fallbacks pointed out in code review that I don't understand. --- .../Skinning/Legacy/LegacySwell.cs | 46 +++++++++++++------ 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacySwell.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacySwell.cs index 405b0b7692..9ed21b1bb0 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacySwell.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacySwell.cs @@ -13,6 +13,7 @@ using osu.Game.Audio; using osuTK; using osu.Game.Rulesets.Objects.Drawables; using osu.Framework.Extensions.ObjectExtensions; +using System; namespace osu.Game.Rulesets.Taiko.Skinning.Legacy { @@ -23,10 +24,10 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy private Container bodyContainer = null!; private Sprite warning = null!; private Sprite spinnerCircle = null!; - private Sprite shrinkingRing = null!; + private Sprite approachCircle = null!; private Sprite clearAnimation = null!; private ISample? clearSample; - private LegacySpriteText remainingHitsCountdown = null!; + private LegacySpriteText remainingHitsText = null!; private bool samplePlayed; @@ -40,6 +41,8 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy [BackgroundDependencyLoader] private void load(DrawableHitObject hitObject, ISkinSource skin, SkinManager skinManager) { + var spinnerCircleProvider = skin.FindProvider(s => s.GetTexture("spinner-circle") != null); + Child = new Container { Anchor = Anchor.Centre, @@ -49,7 +52,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy { warning = new Sprite { - Texture = skin.GetTexture("spinner-warning") ?? skinManager.DefaultClassicSkin.GetTexture("spinner-circle"), + Texture = skin.GetTexture("spinner-warning"), Anchor = Anchor.Centre, Origin = Anchor.Centre, Scale = skin.GetTexture("spinner-warning") != null ? Vector2.One : new Vector2(0.18f), @@ -70,14 +73,14 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy Origin = Anchor.Centre, Scale = new Vector2(0.8f), }, - shrinkingRing = new Sprite + approachCircle = new Sprite { - Texture = skin.GetTexture("spinner-approachcircle") ?? skinManager.DefaultClassicSkin.GetTexture("spinner-approachcircle"), + Texture = skin.GetTexture("spinner-approachcircle"), Anchor = Anchor.Centre, Origin = Anchor.Centre, - Scale = Vector2.One, + Scale = new Vector2(1.86f * 0.8f), }, - remainingHitsCountdown = new LegacySpriteText(LegacyFont.Combo) + remainingHitsText = new LegacySpriteText(LegacyFont.Combo) { Anchor = Anchor.Centre, Origin = Anchor.Centre, @@ -106,8 +109,14 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy private void animateSwellProgress(int numHits, int requiredHits) { - remainingHitsCountdown.Text = $"{requiredHits - numHits}"; - spinnerCircle.RotateTo(180f * numHits, 1000, Easing.OutQuint); + remainingHitsText.Text = $"{requiredHits - numHits}"; + remainingHitsText.ScaleTo(1.6f - 0.6f * ((float)numHits / requiredHits), 60, Easing.OutQuad); + + spinnerCircle.ClearTransforms(); + spinnerCircle + .RotateTo(180f * numHits, 1000, Easing.OutQuint) + .ScaleTo(Math.Min(0.94f, spinnerCircle.Scale.X + 0.02f)) + .ScaleTo(0.8f, 400, Easing.OutQuad); } private void updateStateTransforms(DrawableHitObject drawableHitObject, ArmedState state) @@ -121,7 +130,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy { if (state == ArmedState.Idle) { - remainingHitsCountdown.Text = $"{swell.RequiredHits}"; + remainingHitsText.Text = $"{swell.RequiredHits}"; samplePlayed = false; } @@ -129,14 +138,17 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy warning.FadeOut(body_transition_duration); bodyContainer.FadeIn(body_transition_duration); - shrinkingRing.ResizeTo(0.1f, swell.Duration); + approachCircle.ResizeTo(0.1f * 0.8f, swell.Duration); } using (BeginAbsoluteSequence(drawableSwell.HitStateUpdateTime)) { const double clear_transition_duration = 300; + const double clear_fade_in = 120; - bodyContainer.FadeOut(clear_transition_duration, Easing.OutQuad); + bodyContainer + .FadeOut(clear_transition_duration, Easing.OutQuad) + .ScaleTo(1.05f, clear_transition_duration, Easing.OutQuad); if (state == ArmedState.Hit) { @@ -147,9 +159,13 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy } clearAnimation - .FadeIn(clear_transition_duration, Easing.InQuad) - .ScaleTo(0.8f, clear_transition_duration, Easing.InQuad) - .Delay(700).FadeOut(200, Easing.OutQuad); + .FadeIn(clear_fade_in) + .MoveTo(new Vector2(320, 240)) + .ScaleTo(0.4f) + .MoveTo(new Vector2(320, 150), clear_fade_in * 2, Easing.OutQuad) + .ScaleTo(1f, clear_fade_in * 2, Easing.Out) + .Delay(clear_fade_in * 3) + .FadeOut(clear_fade_in * 2.5); } } } From a62a84a30f7e92b9a855dfba7ddeb5c42a2bb442 Mon Sep 17 00:00:00 2001 From: Nathan Du Date: Fri, 31 Jan 2025 20:48:29 +0800 Subject: [PATCH 12/26] fix code style --- osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs | 6 ------ osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonSwell.cs | 2 +- osu.Game.Rulesets.Taiko/Skinning/Default/DefaultSwell.cs | 6 +++--- osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacySwell.cs | 2 +- 4 files changed, 5 insertions(+), 11 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs index e0276db911..363a6bf8e1 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs @@ -156,12 +156,6 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables } } - protected override void UpdateStartTimeStateTransforms() - { - base.UpdateStartTimeStateTransforms(); - - } - protected override void UpdateHitStateTransforms(ArmedState state) { switch (state) diff --git a/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonSwell.cs b/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonSwell.cs index 65cd936e38..3b3684d219 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonSwell.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonSwell.cs @@ -10,7 +10,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Argon { protected override Drawable CreateCentreCircle() { - return new ArgonSwellCirclePiece() + return new ArgonSwellCirclePiece { Anchor = Anchor.Centre, Origin = Anchor.Centre, diff --git a/osu.Game.Rulesets.Taiko/Skinning/Default/DefaultSwell.cs b/osu.Game.Rulesets.Taiko/Skinning/Default/DefaultSwell.cs index 852116cbfe..a588f866c6 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Default/DefaultSwell.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Default/DefaultSwell.cs @@ -42,7 +42,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Default Origin = Anchor.Centre, RelativeSizeAxes = Axes.Both, Depth = 1, - Children = new Drawable[] + Children = new[] { expandingRing = new CircularContainer { @@ -118,7 +118,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Default protected virtual Drawable CreateCentreCircle() { - return new SwellCirclePiece() + return new SwellCirclePiece { Anchor = Anchor.Centre, Origin = Anchor.Centre, @@ -141,7 +141,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Default private void updateStateTransforms(DrawableHitObject drawableHitObject, ArmedState state) { - if (!(drawableHitObject is DrawableSwell drawableSwell)) + if (!(drawableHitObject is DrawableSwell)) return; Swell swell = drawableSwell.HitObject; diff --git a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacySwell.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacySwell.cs index 9ed21b1bb0..43b2d5c435 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacySwell.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacySwell.cs @@ -121,7 +121,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy private void updateStateTransforms(DrawableHitObject drawableHitObject, ArmedState state) { - if (!(drawableHitObject is DrawableSwell drawableSwell)) + if (!(drawableHitObject is DrawableSwell)) return; Swell swell = drawableSwell.HitObject; From e794389fe83644323a563a343338e282783b53b1 Mon Sep 17 00:00:00 2001 From: Nathan Du Date: Sat, 1 Feb 2025 13:34:52 +0800 Subject: [PATCH 13/26] further adjust swell behavior The outstanding visual issues of the clear animation is fixed. The HandleUserInput state management is removed as it no longer seems necessary. --- .../Objects/Drawables/DrawableSwell.cs | 14 +-- .../Skinning/Legacy/LegacySwell.cs | 109 +++++++++--------- 2 files changed, 60 insertions(+), 63 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs index 363a6bf8e1..d75fdbc40a 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs @@ -158,21 +158,19 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables protected override void UpdateHitStateTransforms(ArmedState state) { + base.UpdateHitStateTransforms(state); + switch (state) { case ArmedState.Idle: - // Only for rewind support. Reallows user inputs if swell is rewound from being hit/missed to being idle. - HandleUserInput = true; break; case ArmedState.Miss: + this.Delay(300).FadeOut(); + break; + case ArmedState.Hit: - const int clear_animation_duration = 1200; - - // Postpone drawable hitobject expiration until it has animated/faded out. Inputs on the object are disallowed during this delay. - LifetimeEnd = Time.Current + clear_animation_duration; - HandleUserInput = false; - + this.Delay(660).FadeOut(); break; } } diff --git a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacySwell.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacySwell.cs index 43b2d5c435..0eb80d333f 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacySwell.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacySwell.cs @@ -41,64 +41,63 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy [BackgroundDependencyLoader] private void load(DrawableHitObject hitObject, ISkinSource skin, SkinManager skinManager) { - var spinnerCircleProvider = skin.FindProvider(s => s.GetTexture("spinner-circle") != null); - - Child = new Container + Children = new Drawable[] { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - - Children = new Drawable[] + warning = new Sprite { - warning = new Sprite - { - Texture = skin.GetTexture("spinner-warning"), - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Scale = skin.GetTexture("spinner-warning") != null ? Vector2.One : new Vector2(0.18f), - }, - bodyContainer = new Container - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Position = new Vector2(200f, 100f), - Alpha = 0, + Texture = skin.GetTexture("spinner-warning"), + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Scale = skin.GetTexture("spinner-warning") != null ? Vector2.One : new Vector2(0.18f), + }, + new Container + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Position = new Vector2(200f, 100f), - Children = new Drawable[] + Children = new Drawable[] + { + bodyContainer = new Container { - spinnerCircle = new Sprite + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Alpha = 0, + + Children = new Drawable[] { - Texture = skin.GetTexture("spinner-circle"), - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Scale = new Vector2(0.8f), - }, - approachCircle = new Sprite - { - Texture = skin.GetTexture("spinner-approachcircle"), - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Scale = new Vector2(1.86f * 0.8f), - }, - remainingHitsText = new LegacySpriteText(LegacyFont.Combo) - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Position = new Vector2(0f, 165f), - Scale = Vector2.One, - }, - clearAnimation = new Sprite - { - Texture = skin.GetTexture("spinner-osu"), - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Position = new Vector2(0f, -165f), - Scale = new Vector2(0.3f), - Alpha = 0, - }, - } + spinnerCircle = new Sprite + { + Texture = skin.GetTexture("spinner-circle"), + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Scale = new Vector2(0.8f), + }, + approachCircle = new Sprite + { + Texture = skin.GetTexture("spinner-approachcircle"), + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Scale = new Vector2(1.86f * 0.8f), + }, + remainingHitsText = new LegacySpriteText(LegacyFont.Combo) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Position = new Vector2(0f, 165f), + Scale = Vector2.One, + }, + } + }, + clearAnimation = new Sprite + { + Texture = skin.GetTexture("spinner-osu"), + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Alpha = 0, + }, }, - } + }, }; drawableSwell = (DrawableSwell)hitObject; @@ -110,7 +109,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy private void animateSwellProgress(int numHits, int requiredHits) { remainingHitsText.Text = $"{requiredHits - numHits}"; - remainingHitsText.ScaleTo(1.6f - 0.6f * ((float)numHits / requiredHits), 60, Easing.OutQuad); + remainingHitsText.ScaleTo(1.6f - (0.6f * ((float)numHits / requiredHits)), 60, Easing.OutQuad); spinnerCircle.ClearTransforms(); spinnerCircle @@ -160,9 +159,9 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy clearAnimation .FadeIn(clear_fade_in) - .MoveTo(new Vector2(320, 240)) + .MoveTo(new Vector2(0, 0)) .ScaleTo(0.4f) - .MoveTo(new Vector2(320, 150), clear_fade_in * 2, Easing.OutQuad) + .MoveTo(new Vector2(0, -90), clear_fade_in * 2, Easing.OutQuad) .ScaleTo(1f, clear_fade_in * 2, Easing.Out) .Delay(clear_fade_in * 3) .FadeOut(clear_fade_in * 2.5); From 48e30f4ee80af5fd9c0e6e39bfd28d48a5df6ccf Mon Sep 17 00:00:00 2001 From: Nathan Du Date: Mon, 3 Feb 2025 09:49:37 +0800 Subject: [PATCH 14/26] remove skinning section swell delay test Replaced by TestHitSwellThenHitHit in TestSceneSwellJudgements. --- .../TestSceneDrawableSwellExpireDelay.cs | 41 ------------------- 1 file changed, 41 deletions(-) delete mode 100644 osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableSwellExpireDelay.cs diff --git a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableSwellExpireDelay.cs b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableSwellExpireDelay.cs deleted file mode 100644 index ad78ed3b20..0000000000 --- a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableSwellExpireDelay.cs +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using System.Collections.Generic; -using NUnit.Framework; -using osu.Game.Rulesets.Replays; -using osu.Game.Rulesets.Scoring; -using osu.Game.Rulesets.Taiko.Objects; -using osu.Game.Rulesets.Taiko.Replays; -using osu.Game.Rulesets.Taiko.Tests.Judgements; - -namespace osu.Game.Rulesets.Taiko.Tests.Skinning -{ - public partial class TestSceneDrawableSwellExpireDelay : JudgementTest - { - [Test] - public void TestExpireDelay() - { - const double swell_start = 1000; - const double swell_duration = 1000; - - Swell swell = new Swell - { - StartTime = swell_start, - Duration = swell_duration, - }; - - Hit hit = new Hit { StartTime = swell_start + swell_duration + 50 }; - - List frames = new List - { - new TaikoReplayFrame(0), - new TaikoReplayFrame(2100, TaikoAction.LeftCentre), - }; - - PerformTest(frames, CreateBeatmap(swell, hit)); - - AssertResult(0, HitResult.Ok); - } - } -} From ccc446a8ca8d004ff74cba2b11bb0d438861f3ed Mon Sep 17 00:00:00 2001 From: Nathan Du Date: Tue, 4 Feb 2025 17:48:44 +0800 Subject: [PATCH 15/26] code cleanup --- .../Objects/Drawables/DrawableSwell.cs | 2 +- .../Argon/TaikoArgonSkinTransformer.cs | 2 +- .../Skinning/Legacy/LegacySwellCirclePiece.cs | 23 ------------------- .../Legacy/TaikoLegacySkinTransformer.cs | 2 +- .../TaikoSkinComponents.cs | 2 +- 5 files changed, 4 insertions(+), 27 deletions(-) delete mode 100644 osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacySwellCirclePiece.cs diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs index d75fdbc40a..1dde4b6f9c 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs @@ -53,7 +53,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables AddInternal(ticks = new Container { RelativeSizeAxes = Axes.Both }); } - protected override SkinnableDrawable CreateMainPiece() => new SkinnableDrawable(new TaikoSkinComponentLookup(TaikoSkinComponents.SwellBody), + protected override SkinnableDrawable CreateMainPiece() => new SkinnableDrawable(new TaikoSkinComponentLookup(TaikoSkinComponents.Swell), _ => new DefaultSwell { Anchor = Anchor.Centre, diff --git a/osu.Game.Rulesets.Taiko/Skinning/Argon/TaikoArgonSkinTransformer.cs b/osu.Game.Rulesets.Taiko/Skinning/Argon/TaikoArgonSkinTransformer.cs index b588a22d12..26bb1900b9 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Argon/TaikoArgonSkinTransformer.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Argon/TaikoArgonSkinTransformer.cs @@ -68,7 +68,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Argon case TaikoSkinComponents.TaikoExplosionOk: return new ArgonHitExplosion(taikoComponent.Component); - case TaikoSkinComponents.SwellBody: + case TaikoSkinComponents.Swell: return new ArgonSwell(); } diff --git a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacySwellCirclePiece.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacySwellCirclePiece.cs deleted file mode 100644 index 40501d1d40..0000000000 --- a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacySwellCirclePiece.cs +++ /dev/null @@ -1,23 +0,0 @@ -// 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.Game.Skinning; -using osuTK; - -namespace osu.Game.Rulesets.Taiko.Skinning.Legacy -{ - internal partial class LegacySwellCirclePiece : Sprite - { - [BackgroundDependencyLoader] - private void load(ISkinSource skin, SkinManager skinManager) - { - Texture = skin.GetTexture("spinner-warning") ?? skinManager.DefaultClassicSkin.GetTexture("spinner-circle"); - Anchor = Anchor.Centre; - Origin = Anchor.Centre; - Scale = skin.GetTexture("spinner-warning") != null ? Vector2.One : new Vector2(0.18f); - } - } -} diff --git a/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacySkinTransformer.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacySkinTransformer.cs index 8fa4551fd4..c6221e0589 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacySkinTransformer.cs @@ -65,7 +65,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy case TaikoSkinComponents.DrumRollTick: return this.GetAnimation("sliderscorepoint", false, false); - case TaikoSkinComponents.SwellBody: + case TaikoSkinComponents.Swell: if (GetTexture("spinner-circle") != null) return new LegacySwell(); diff --git a/osu.Game.Rulesets.Taiko/TaikoSkinComponents.cs b/osu.Game.Rulesets.Taiko/TaikoSkinComponents.cs index 05c6316a05..28133ffcb2 100644 --- a/osu.Game.Rulesets.Taiko/TaikoSkinComponents.cs +++ b/osu.Game.Rulesets.Taiko/TaikoSkinComponents.cs @@ -10,7 +10,7 @@ namespace osu.Game.Rulesets.Taiko RimHit, DrumRollBody, DrumRollTick, - SwellBody, + Swell, HitTarget, PlayfieldBackgroundLeft, PlayfieldBackgroundRight, From 884fa20b286264482f6e965f946369e42d9fe356 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 11 Feb 2025 09:13:08 +0100 Subject: [PATCH 16/26] Remove completely unnecessary subscriptions per collection --- .../Collections/DrawableCollectionList.cs | 1 - .../Collections/DrawableCollectionListItem.cs | 32 +++++++------------ 2 files changed, 11 insertions(+), 22 deletions(-) diff --git a/osu.Game/Collections/DrawableCollectionList.cs b/osu.Game/Collections/DrawableCollectionList.cs index 85af1d383d..c494b830d1 100644 --- a/osu.Game/Collections/DrawableCollectionList.cs +++ b/osu.Game/Collections/DrawableCollectionList.cs @@ -96,7 +96,6 @@ namespace osu.Game.Collections lastCreated = collections[changes.InsertedIndices[0]].ID; foreach (int i in changes.NewModifiedIndices) - { var updatedItem = collections[i]; diff --git a/osu.Game/Collections/DrawableCollectionListItem.cs b/osu.Game/Collections/DrawableCollectionListItem.cs index 0060dacc01..703def9546 100644 --- a/osu.Game/Collections/DrawableCollectionListItem.cs +++ b/osu.Game/Collections/DrawableCollectionListItem.cs @@ -126,15 +126,10 @@ namespace osu.Game.Collections private const float count_text_size = 12; - [Resolved] - private RealmAccess realm { get; set; } = null!; - private readonly Live collection; private OsuSpriteText countText = null!; - private IDisposable? itemCountSubscription; - public ItemTextBox(Live collection) { this.collection = collection; @@ -163,29 +158,24 @@ namespace osu.Game.Collections Colour = colours.Yellow }); - itemCountSubscription = realm.SubscribeToPropertyChanged(r => r.Find(collection.ID), c => c.BeatmapMD5Hashes, _ => - Scheduler.AddOnce(() => - { - int count = collection.PerformRead(c => c.BeatmapMD5Hashes.Count); + // interestingly, it is not required to subscribe to change notifications on this collection at all for this to work correctly. + // the reasoning for this is that `DrawableCollectionList` already takes out a subscription on the set of all `BeatmapCollection`s - + // but that subscription does not only cover *changes to the set of collections* (i.e. addition/removal/rearrangement of collections), + // but also covers *changes to the properties of collections*, which `BeatmapMD5Hashes` is one. + // when a collection item changes due to `BeatmapMD5Hashes` changing, the list item is deleted and re-inserted, thus guaranteeing this to work correctly. + int count = collection.PerformRead(c => c.BeatmapMD5Hashes.Count); - countText.Text = count == 1 - // Intentionally not localised until we have proper support for this (see https://github.com/ppy/osu-framework/pull/4918 - // but also in this case we want support for formatting a number within a string). - ? $"{count:#,0} beatmap" - : $"{count:#,0} beatmaps"; - })); + countText.Text = count == 1 + // Intentionally not localised until we have proper support for this (see https://github.com/ppy/osu-framework/pull/4918 + // but also in this case we want support for formatting a number within a string). + ? $"{count:#,0} beatmap" + : $"{count:#,0} beatmaps"; } else { PlaceholderText = "Create a new collection"; } } - - protected override void Dispose(bool isDisposing) - { - base.Dispose(isDisposing); - itemCountSubscription?.Dispose(); - } } public partial class DeleteButton : OsuClickableContainer From d8b3c28c2e5cb3c666ae937d4cd13feb7d5475d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 11 Feb 2025 09:17:11 +0100 Subject: [PATCH 17/26] Use more neutral terminology to avoid contentious 'beatmap' term --- osu.Game/Collections/DrawableCollectionListItem.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Collections/DrawableCollectionListItem.cs b/osu.Game/Collections/DrawableCollectionListItem.cs index 703def9546..f2b00004e2 100644 --- a/osu.Game/Collections/DrawableCollectionListItem.cs +++ b/osu.Game/Collections/DrawableCollectionListItem.cs @@ -168,8 +168,8 @@ namespace osu.Game.Collections countText.Text = count == 1 // Intentionally not localised until we have proper support for this (see https://github.com/ppy/osu-framework/pull/4918 // but also in this case we want support for formatting a number within a string). - ? $"{count:#,0} beatmap" - : $"{count:#,0} beatmaps"; + ? $"{count:#,0} item" + : $"{count:#,0} items"; } else { From b9c4e235958796bb4f85b9734b5f685541ea13d3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 11 Feb 2025 20:05:48 +0900 Subject: [PATCH 18/26] Fix potential bad realm access to collection name --- osu.Game/Collections/DrawableCollectionListItem.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Collections/DrawableCollectionListItem.cs b/osu.Game/Collections/DrawableCollectionListItem.cs index f2b00004e2..b0dd70227c 100644 --- a/osu.Game/Collections/DrawableCollectionListItem.cs +++ b/osu.Game/Collections/DrawableCollectionListItem.cs @@ -255,7 +255,7 @@ namespace osu.Game.Collections private void deleteCollection() => collection.PerformWrite(c => c.Realm!.Remove(c)); } - public IEnumerable FilterTerms => [(LocalisableString)Model.Value.Name]; + public IEnumerable FilterTerms => Model.PerformRead(m => m.IsValid ? new[] { (LocalisableString)m.Name } : []); private bool matchingFilter = true; From be035538c241f29ef609c9f73c670b0056278222 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 11 Feb 2025 14:01:32 +0100 Subject: [PATCH 19/26] Fix remaining hit counter scaling in the incorrect direction --- osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacySwell.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacySwell.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacySwell.cs index 0eb80d333f..c819cb7937 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacySwell.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacySwell.cs @@ -108,8 +108,9 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy private void animateSwellProgress(int numHits, int requiredHits) { - remainingHitsText.Text = $"{requiredHits - numHits}"; - remainingHitsText.ScaleTo(1.6f - (0.6f * ((float)numHits / requiredHits)), 60, Easing.OutQuad); + int remainingHits = requiredHits - numHits; + remainingHitsText.Text = remainingHits.ToString(); + remainingHitsText.ScaleTo(1.6f - (0.6f * ((float)remainingHits / requiredHits)), 60, Easing.OutQuad); spinnerCircle.ClearTransforms(); spinnerCircle From 231988bc9de21a5e7cdc0fbd838e6cb20c75990a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 11 Feb 2025 15:20:36 +0100 Subject: [PATCH 20/26] Adjust things to be closer to stable (but not close enough yet) --- .../Skinning/Legacy/LegacySwell.cs | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacySwell.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacySwell.cs index c819cb7937..d3b5d54828 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacySwell.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacySwell.cs @@ -14,6 +14,7 @@ using osuTK; using osu.Game.Rulesets.Objects.Drawables; using osu.Framework.Extensions.ObjectExtensions; using System; +using System.Globalization; namespace osu.Game.Rulesets.Taiko.Skinning.Legacy { @@ -39,7 +40,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy } [BackgroundDependencyLoader] - private void load(DrawableHitObject hitObject, ISkinSource skin, SkinManager skinManager) + private void load(DrawableHitObject hitObject, ISkinSource skin) { Children = new Drawable[] { @@ -54,7 +55,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy { Anchor = Anchor.Centre, Origin = Anchor.Centre, - Position = new Vector2(200f, 100f), + Position = new Vector2(250f, 100f), // ballparked to be horizontally centred on 4:3 resolution Children = new Drawable[] { @@ -109,14 +110,14 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy private void animateSwellProgress(int numHits, int requiredHits) { int remainingHits = requiredHits - numHits; - remainingHitsText.Text = remainingHits.ToString(); - remainingHitsText.ScaleTo(1.6f - (0.6f * ((float)remainingHits / requiredHits)), 60, Easing.OutQuad); + remainingHitsText.Text = remainingHits.ToString(CultureInfo.InvariantCulture); + remainingHitsText.ScaleTo(1.6f - (0.6f * ((float)remainingHits / requiredHits)), 60, Easing.Out); spinnerCircle.ClearTransforms(); spinnerCircle .RotateTo(180f * numHits, 1000, Easing.OutQuint) .ScaleTo(Math.Min(0.94f, spinnerCircle.Scale.X + 0.02f)) - .ScaleTo(0.8f, 400, Easing.OutQuad); + .ScaleTo(0.8f, 400, Easing.Out); } private void updateStateTransforms(DrawableHitObject drawableHitObject, ArmedState state) @@ -134,7 +135,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy samplePlayed = false; } - const double body_transition_duration = 100; + const double body_transition_duration = 200; warning.FadeOut(body_transition_duration); bodyContainer.FadeIn(body_transition_duration); @@ -146,9 +147,8 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy const double clear_transition_duration = 300; const double clear_fade_in = 120; - bodyContainer - .FadeOut(clear_transition_duration, Easing.OutQuad) - .ScaleTo(1.05f, clear_transition_duration, Easing.OutQuad); + bodyContainer.FadeOut(clear_transition_duration, Easing.OutQuad); + spinnerCircle.ScaleTo(spinnerCircle.Scale.X + 0.05f, clear_transition_duration, Easing.OutQuad); if (state == ArmedState.Hit) { @@ -159,11 +159,11 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy } clearAnimation - .FadeIn(clear_fade_in) .MoveTo(new Vector2(0, 0)) + .MoveTo(new Vector2(0, -90), clear_fade_in * 2, Easing.Out) .ScaleTo(0.4f) - .MoveTo(new Vector2(0, -90), clear_fade_in * 2, Easing.OutQuad) .ScaleTo(1f, clear_fade_in * 2, Easing.Out) + .FadeIn(clear_fade_in) .Delay(clear_fade_in * 3) .FadeOut(clear_fade_in * 2.5); } From a8f07ae7b1ebce7579cc97a14264b7132b017f1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marvin=20Sch=C3=BCrz?= Date: Tue, 11 Feb 2025 18:04:23 +0100 Subject: [PATCH 21/26] Add comment warning about enum entry order in `GlobalAction` --- osu.Game/Input/Bindings/GlobalActionContainer.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game/Input/Bindings/GlobalActionContainer.cs b/osu.Game/Input/Bindings/GlobalActionContainer.cs index 599ca6d6c1..e4dc2d503b 100644 --- a/osu.Game/Input/Bindings/GlobalActionContainer.cs +++ b/osu.Game/Input/Bindings/GlobalActionContainer.cs @@ -227,6 +227,10 @@ namespace osu.Game.Input.Bindings }; } + /// + /// IMPORTANT: New entries should always be added at the end of the enum, as key bindings are stored using the enum's numeric value and + /// changes in order would cause key bindings to get associated with the wrong action. + /// public enum GlobalAction { [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.ToggleChat))] From 96db6964df2e1045eacedebae3bfdf95eb250983 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 12 Feb 2025 10:55:57 +0100 Subject: [PATCH 22/26] Adjust things further --- .../Skinning/Legacy/LegacySwell.cs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacySwell.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacySwell.cs index d3b5d54828..5d65ac6058 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacySwell.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacySwell.cs @@ -15,11 +15,14 @@ using osu.Game.Rulesets.Objects.Drawables; using osu.Framework.Extensions.ObjectExtensions; using System; using System.Globalization; +using osu.Framework.Utils; namespace osu.Game.Rulesets.Taiko.Skinning.Legacy { public partial class LegacySwell : Container { + private const float scale_adjust = 768f / 480; + private DrawableSwell drawableSwell = null!; private Container bodyContainer = null!; @@ -80,12 +83,13 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy Anchor = Anchor.Centre, Origin = Anchor.Centre, Scale = new Vector2(1.86f * 0.8f), + Alpha = 0.8f, }, - remainingHitsText = new LegacySpriteText(LegacyFont.Combo) + remainingHitsText = new LegacySpriteText(LegacyFont.Score) { Anchor = Anchor.Centre, Origin = Anchor.Centre, - Position = new Vector2(0f, 165f), + Position = new Vector2(0f, 130f), Scale = Vector2.One, }, } @@ -96,6 +100,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy Anchor = Anchor.Centre, Origin = Anchor.Centre, Alpha = 0, + Y = -40, }, }, }, @@ -159,11 +164,10 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy } clearAnimation - .MoveTo(new Vector2(0, 0)) - .MoveTo(new Vector2(0, -90), clear_fade_in * 2, Easing.Out) + .MoveToOffset(new Vector2(0, -90 * scale_adjust), clear_fade_in * 2, Easing.Out) .ScaleTo(0.4f) .ScaleTo(1f, clear_fade_in * 2, Easing.Out) - .FadeIn(clear_fade_in) + .FadeIn() .Delay(clear_fade_in * 3) .FadeOut(clear_fade_in * 2.5); } From 0ac08158e33867092f76f94b1534ba3bc1ce962c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 12 Feb 2025 11:20:27 +0100 Subject: [PATCH 23/26] Fix transforms from swell progress being cleared on completion by not using transforms --- .../Objects/Drawables/DrawableSwell.cs | 4 +-- .../Skinning/Default/DefaultSwell.cs | 26 +++++++++++------ .../Skinning/Legacy/LegacySwell.cs | 28 +++++++++++++------ 3 files changed, 39 insertions(+), 19 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs index 1dde4b6f9c..6ad14c87d1 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs @@ -38,7 +38,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables /// public bool MustAlternate { get; internal set; } = true; - public event Action UpdateHitProgress; + public event Action UpdateHitProgress; public DrawableSwell() : this(null) @@ -125,7 +125,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables int numHits = ticks.Count(r => r.IsHit); - UpdateHitProgress?.Invoke(numHits, HitObject.RequiredHits); + UpdateHitProgress?.Invoke(numHits); if (numHits == HitObject.RequiredHits) ApplyMaxResult(); diff --git a/osu.Game.Rulesets.Taiko/Skinning/Default/DefaultSwell.cs b/osu.Game.Rulesets.Taiko/Skinning/Default/DefaultSwell.cs index a588f866c6..ac72ba73b8 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Default/DefaultSwell.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Default/DefaultSwell.cs @@ -8,10 +8,12 @@ using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; +using osu.Framework.Utils; using osu.Game.Graphics; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Taiko.Objects; using osu.Game.Rulesets.Taiko.Objects.Drawables; +using osuTK; using osuTK.Graphics; namespace osu.Game.Rulesets.Taiko.Skinning.Default @@ -29,6 +31,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Default private readonly CircularContainer targetRing; private readonly CircularContainer expandingRing; private readonly Drawable centreCircle; + private int numHits; public DefaultSwell() { @@ -125,18 +128,25 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Default }; } - private void animateSwellProgress(int numHits, int requiredHits) + private void animateSwellProgress(int numHits) { - float completion = (float)numHits / requiredHits; + this.numHits = numHits; - centreCircle.RotateTo((float)(completion * drawableSwell.HitObject.Duration / 8), 4000, Easing.OutQuint); + float completion = (float)numHits / drawableSwell.HitObject.RequiredHits; + expandingRing.Alpha += Math.Clamp(completion / 16, 0.1f, 0.6f); + } - expandingRing.ScaleTo(1f + Math.Min(target_ring_scale - 1f, (target_ring_scale - 1f) * completion * 1.3f), 260, Easing.OutQuint); + protected override void Update() + { + base.Update(); - expandingRing - .FadeTo(expandingRing.Alpha + Math.Clamp(completion / 16, 0.1f, 0.6f), 50) - .Then() - .FadeTo(completion / 8, 2000, Easing.OutQuint); + float completion = (float)numHits / drawableSwell.HitObject.RequiredHits; + + centreCircle.Rotation = (float)Interpolation.DampContinuously(centreCircle.Rotation, + (float)(completion * drawableSwell.HitObject.Duration / 8), 500, Math.Abs(Time.Elapsed)); + expandingRing.Scale = new Vector2((float)Interpolation.DampContinuously(expandingRing.Scale.X, + 1f + Math.Min(target_ring_scale - 1f, (target_ring_scale - 1f) * completion * 1.3f), 35, Math.Abs(Time.Elapsed))); + expandingRing.Alpha = (float)Interpolation.DampContinuously(expandingRing.Alpha, completion / 16, 250, Math.Abs(Time.Elapsed)); } private void updateStateTransforms(DrawableHitObject drawableHitObject, ArmedState state) diff --git a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacySwell.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacySwell.cs index 5d65ac6058..62ccd05a06 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacySwell.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacySwell.cs @@ -35,6 +35,8 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy private bool samplePlayed; + private int numHits; + public LegacySwell() { Anchor = Anchor.Centre; @@ -112,17 +114,25 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy clearSample = skin.GetSample(new SampleInfo("spinner-osu")); } - private void animateSwellProgress(int numHits, int requiredHits) + private void animateSwellProgress(int numHits) { - int remainingHits = requiredHits - numHits; - remainingHitsText.Text = remainingHits.ToString(CultureInfo.InvariantCulture); - remainingHitsText.ScaleTo(1.6f - (0.6f * ((float)remainingHits / requiredHits)), 60, Easing.Out); + this.numHits = numHits; + remainingHitsText.Text = (drawableSwell.HitObject.RequiredHits - numHits).ToString(CultureInfo.InvariantCulture); + spinnerCircle.Scale = new Vector2(Math.Min(0.94f, spinnerCircle.Scale.X + 0.02f)); + } - spinnerCircle.ClearTransforms(); - spinnerCircle - .RotateTo(180f * numHits, 1000, Easing.OutQuint) - .ScaleTo(Math.Min(0.94f, spinnerCircle.Scale.X + 0.02f)) - .ScaleTo(0.8f, 400, Easing.Out); + protected override void Update() + { + base.Update(); + + int requiredHits = drawableSwell.HitObject.RequiredHits; + int remainingHits = requiredHits - numHits; + remainingHitsText.Scale = new Vector2((float)Interpolation.DampContinuously( + remainingHitsText.Scale.X, 1.6f - (0.6f * ((float)remainingHits / requiredHits)), 17.5, Math.Abs(Time.Elapsed))); + + spinnerCircle.Rotation = (float)Interpolation.DampContinuously(spinnerCircle.Rotation, 180f * numHits, 130, Math.Abs(Time.Elapsed)); + spinnerCircle.Scale = new Vector2((float)Interpolation.DampContinuously( + spinnerCircle.Scale.X, 0.8f, 120, Math.Abs(Time.Elapsed))); } private void updateStateTransforms(DrawableHitObject drawableHitObject, ArmedState state) From e385848edcbfbab7eaf0618a01ffb98aeed209d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 12 Feb 2025 11:30:30 +0100 Subject: [PATCH 24/26] Add missing animation of warning sprite --- osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacySwell.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacySwell.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacySwell.cs index 62ccd05a06..c9e03d3508 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacySwell.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacySwell.cs @@ -22,6 +22,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy public partial class LegacySwell : Container { private const float scale_adjust = 768f / 480; + private static readonly Vector2 swell_display_position = new Vector2(250f, 100f); private DrawableSwell drawableSwell = null!; @@ -60,7 +61,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy { Anchor = Anchor.Centre, Origin = Anchor.Centre, - Position = new Vector2(250f, 100f), // ballparked to be horizontally centred on 4:3 resolution + Position = swell_display_position, // ballparked to be horizontally centred on 4:3 resolution Children = new Drawable[] { @@ -152,7 +153,10 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy const double body_transition_duration = 200; - warning.FadeOut(body_transition_duration); + warning.MoveTo(swell_display_position, body_transition_duration) + .ScaleTo(3, body_transition_duration, Easing.Out) + .FadeOut(body_transition_duration); + bodyContainer.FadeIn(body_transition_duration); approachCircle.ResizeTo(0.1f * 0.8f, swell.Duration); } From d87a775e716801705b1de47cc4d2776770c348ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 12 Feb 2025 13:19:55 +0100 Subject: [PATCH 25/26] Fix clear sample potentially playing multiple times simultaneously --- osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacySwell.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacySwell.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacySwell.cs index c9e03d3508..9f1b692984 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacySwell.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacySwell.cs @@ -8,7 +8,6 @@ using osu.Game.Skinning; using osu.Framework.Graphics.Sprites; using osu.Game.Rulesets.Taiko.Objects.Drawables; using osu.Game.Rulesets.Taiko.Objects; -using osu.Framework.Audio.Sample; using osu.Game.Audio; using osuTK; using osu.Game.Rulesets.Objects.Drawables; @@ -31,7 +30,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy private Sprite spinnerCircle = null!; private Sprite approachCircle = null!; private Sprite clearAnimation = null!; - private ISample? clearSample; + private SkinnableSound clearSample = null!; private LegacySpriteText remainingHitsText = null!; private bool samplePlayed; @@ -107,12 +106,12 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy }, }, }, + clearSample = new SkinnableSound(new SampleInfo("spinner-osu")), }; drawableSwell = (DrawableSwell)hitObject; drawableSwell.UpdateHitProgress += animateSwellProgress; drawableSwell.ApplyCustomUpdateState += updateStateTransforms; - clearSample = skin.GetSample(new SampleInfo("spinner-osu")); } private void animateSwellProgress(int numHits) @@ -173,7 +172,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy { if (!samplePlayed) { - clearSample?.Play(); + clearSample.Play(); samplePlayed = true; } From ee6dcbd80899c3865803311b372c8f8623092ade Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 12 Feb 2025 14:12:43 +0100 Subject: [PATCH 26/26] Fix android build again Another month, another freak android build failure. From what I can tell, this time the build is broken because the second- -to-last workaround applied to fix it, namely explicitly specifying the version of workloads to install, stopped working, presumably because github pushed a new .NET SDK version to runners, and microsoft didn't actually put up a set of workload packages whose version matches the .NET SDK version 1:1. Thankfully, the fix to the *last* android build breakage (which caused the workload installation to completely and irrecoverably fail), appears to be rolling out this week, and *also* fix that same second-last issue, so both workarounds of specifying the workload version and pinning the image to `windows-2019` appear to no longer be required. Note that the newest image version, 20250209.1.0, is still not fully rolled out yet, thus rather than just fix all builds, this will fix like 20% of builds until the newest image is fully rolled out. But I guess a 20% passing build is better than a 0% passing build, in a sense...? --- .github/workflows/ci.yml | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a88f1320cd..d75f09f184 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -96,7 +96,7 @@ jobs: build-only-android: name: Build only (Android) - runs-on: windows-2019 + runs-on: windows-latest timeout-minutes: 60 steps: - name: Checkout @@ -114,10 +114,7 @@ jobs: dotnet-version: "8.0.x" - name: Install .NET workloads - # since windows image 20241113.3.0, not specifying a version here - # installs the .NET 7 version of android workload for very unknown reasons. - # revisit once we upgrade to .NET 9, it's probably fixed there. - run: dotnet workload install android --version (dotnet --version) + run: dotnet workload install android - name: Compile run: dotnet build -c Debug osu.Android.slnf