diff --git a/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs b/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs index a25d9cb67e..77d7de989a 100644 --- a/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs +++ b/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs @@ -1,6 +1,7 @@ // 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.Bindables; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Rulesets.Catch.Beatmaps; @@ -37,9 +38,21 @@ namespace osu.Game.Rulesets.Catch.Objects public int ComboOffset { get; set; } - public int IndexInCurrentCombo { get; set; } + public Bindable IndexInCurrentComboBindable { get; } = new Bindable(); - public int ComboIndex { get; set; } + public int IndexInCurrentCombo + { + get => IndexInCurrentComboBindable.Value; + set => IndexInCurrentComboBindable.Value = value; + } + + public Bindable ComboIndexBindable { get; } = new Bindable(); + + public int ComboIndex + { + get => ComboIndexBindable.Value; + set => ComboIndexBindable.Value = value; + } /// /// Difference between the distance to the next object @@ -48,10 +61,16 @@ namespace osu.Game.Rulesets.Catch.Objects /// public float DistanceToHyperDash { get; set; } + public Bindable LastInComboBindable { get; } = new Bindable(); + /// /// The next fruit starts a new combo. Used for explodey. /// - public virtual bool LastInCombo { get; set; } + public virtual bool LastInCombo + { + get => LastInComboBindable.Value; + set => LastInComboBindable.Value = value; + } public float Scale { get; set; } = 1; diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleComboChange.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleComboChange.cs new file mode 100644 index 0000000000..5695462859 --- /dev/null +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleComboChange.cs @@ -0,0 +1,26 @@ +// 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.Bindables; +using osu.Game.Rulesets.Osu.Objects; + +namespace osu.Game.Rulesets.Osu.Tests +{ + public class TestSceneHitCircleComboChange : TestSceneHitCircle + { + private readonly Bindable comboIndex = new Bindable(); + + protected override void LoadComplete() + { + base.LoadComplete(); + Scheduler.AddDelayed(() => comboIndex.Value++, 250, true); + } + + protected override TestDrawableHitCircle CreateDrawableHitCircle(HitCircle circle, bool auto) + { + circle.ComboIndexBindable.BindTo(comboIndex); + circle.IndexInCurrentComboBindable.BindTo(comboIndex); + return base.CreateDrawableHitCircle(circle, auto); + } + } +} diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSlider.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSlider.cs index 29c71a8903..6a4201f84d 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneSlider.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSlider.cs @@ -297,11 +297,7 @@ namespace osu.Game.Rulesets.Osu.Tests slider.ApplyDefaults(cpi, new BeatmapDifficulty { CircleSize = circleSize, SliderTickRate = 3 }); - var drawable = new DrawableSlider(slider) - { - Anchor = Anchor.Centre, - Depth = depthIndex++ - }; + var drawable = CreateDrawableSlider(slider); foreach (var mod in Mods.Value.OfType()) mod.ApplyToDrawableHitObjects(new[] { drawable }); @@ -311,6 +307,12 @@ namespace osu.Game.Rulesets.Osu.Tests return drawable; } + protected virtual DrawableSlider CreateDrawableSlider(Slider slider) => new DrawableSlider(slider) + { + Anchor = Anchor.Centre, + Depth = depthIndex++ + }; + private float judgementOffsetDirection = 1; private void onNewResult(DrawableHitObject judgedObject, JudgementResult result) diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSliderComboChange.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSliderComboChange.cs new file mode 100644 index 0000000000..13ced3019e --- /dev/null +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSliderComboChange.cs @@ -0,0 +1,28 @@ +// 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.Bindables; +using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.Osu.Objects.Drawables; + +namespace osu.Game.Rulesets.Osu.Tests +{ + public class TestSceneSliderComboChange : TestSceneSlider + { + private readonly Bindable comboIndex = new Bindable(); + + protected override void LoadComplete() + { + base.LoadComplete(); + Scheduler.AddDelayed(() => comboIndex.Value++, 250, true); + } + + protected override DrawableSlider CreateDrawableSlider(Slider slider) + { + slider.ComboIndexBindable.BindTo(comboIndex); + slider.IndexInCurrentComboBindable.BindTo(comboIndex); + + return base.CreateDrawableSlider(slider); + } + } +} diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerRotation.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerRotation.cs new file mode 100644 index 0000000000..cded7f0e95 --- /dev/null +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerRotation.cs @@ -0,0 +1,96 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Audio; +using osu.Framework.MathUtils; +using osu.Framework.Testing; +using osu.Framework.Timing; +using osu.Game.Beatmaps; +using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.Osu.Objects.Drawables; +using osu.Game.Tests.Visual; +using osuTK; +using System.Collections.Generic; +using System.Linq; +using static osu.Game.Tests.Visual.OsuTestScene.ClockBackedTestWorkingBeatmap; + +namespace osu.Game.Rulesets.Osu.Tests +{ + public class TestSceneSpinnerRotation : TestSceneOsuPlayer + { + [Resolved] + private AudioManager audioManager { get; set; } + + private TrackVirtualManual track; + + protected override bool Autoplay => true; + + protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap) + { + var working = new ClockBackedTestWorkingBeatmap(beatmap, new FramedClock(new ManualClock { Rate = 1 }), audioManager); + track = (TrackVirtualManual)working.Track; + return working; + } + + private DrawableSpinner drawableSpinner; + + [SetUpSteps] + public override void SetUpSteps() + { + base.SetUpSteps(); + + AddUntilStep("wait for track to start running", () => track.IsRunning); + AddStep("retrieve spinner", () => drawableSpinner = (DrawableSpinner)((TestPlayer)Player).DrawableRuleset.Playfield.AllHitObjects.First()); + } + + [Test] + public void TestSpinnerRewindingRotation() + { + addSeekStep(5000); + AddAssert("is rotation absolute not almost 0", () => !Precision.AlmostEquals(drawableSpinner.Disc.RotationAbsolute, 0, 100)); + + addSeekStep(0); + AddAssert("is rotation absolute almost 0", () => Precision.AlmostEquals(drawableSpinner.Disc.RotationAbsolute, 0, 100)); + } + + [Test] + public void TestSpinnerMiddleRewindingRotation() + { + double estimatedRotation = 0; + + addSeekStep(5000); + AddStep("retrieve rotation", () => estimatedRotation = drawableSpinner.Disc.RotationAbsolute); + + addSeekStep(2500); + addSeekStep(5000); + AddAssert("is rotation absolute almost same", () => Precision.AlmostEquals(drawableSpinner.Disc.RotationAbsolute, estimatedRotation, 100)); + } + + private void addSeekStep(double time) + { + AddStep($"seek to {time}", () => track.Seek(time)); + + AddUntilStep("wait for seek to finish", () => Precision.AlmostEquals(time, ((TestPlayer)Player).DrawableRuleset.FrameStableClock.CurrentTime, 100)); + } + + protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) => new Beatmap + { + HitObjects = new List + { + new Spinner + { + Position = new Vector2(256, 192), + EndTime = 5000, + }, + // placeholder object to avoid hitting the results screen + new HitObject + { + StartTime = 99999, + } + } + }; + } +} diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs index c90f230f93..bb227d76df 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs @@ -59,7 +59,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables return true; }, }, - CirclePiece = new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.HitCircle), _ => new MainCirclePiece(HitObject.IndexInCurrentCombo)), + CirclePiece = new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.HitCircle), _ => new MainCirclePiece()), ApproachCircle = new ApproachCircle { Alpha = 0, diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/MainCirclePiece.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/MainCirclePiece.cs index 944c93bb6d..e364c96426 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/MainCirclePiece.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/MainCirclePiece.cs @@ -20,7 +20,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces private readonly NumberPiece number; private readonly GlowPiece glow; - public MainCirclePiece(int index) + public MainCirclePiece() { Size = new Vector2(OsuHitObject.OBJECT_RADIUS * 2); @@ -31,10 +31,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces { glow = new GlowPiece(), circle = new CirclePiece(), - number = new NumberPiece - { - Text = (index + 1).ToString(), - }, + number = new NumberPiece(), ring = new RingPiece(), flash = new FlashPiece(), explode = new ExplodePiece(), @@ -42,12 +39,14 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces } private readonly IBindable state = new Bindable(); - - private readonly Bindable accentColour = new Bindable(); + private readonly IBindable accentColour = new Bindable(); + private readonly IBindable indexInCurrentCombo = new Bindable(); [BackgroundDependencyLoader] private void load(DrawableHitObject drawableObject) { + OsuHitObject osuObject = (OsuHitObject)drawableObject.HitObject; + state.BindTo(drawableObject.State); state.BindValueChanged(updateState, true); @@ -58,6 +57,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces glow.Colour = colour.NewValue; circle.Colour = colour.NewValue; }, true); + + indexInCurrentCombo.BindTo(osuObject.IndexInCurrentComboBindable); + indexInCurrentCombo.BindValueChanged(index => number.Text = (index.NewValue + 1).ToString(), true); } private void updateState(ValueChangedEvent state) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs index 448a2eada7..c45e98cc76 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs @@ -111,7 +111,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces lastAngle -= 360; currentRotation += thisAngle - lastAngle; - RotationAbsolute += Math.Abs(thisAngle - lastAngle); + RotationAbsolute += Math.Abs(thisAngle - lastAngle) * Math.Sign(Clock.ElapsedFrameTime); } lastAngle = thisAngle; diff --git a/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs b/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs index 2cf877b000..80e013fe68 100644 --- a/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs +++ b/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs @@ -58,13 +58,37 @@ namespace osu.Game.Rulesets.Osu.Objects public virtual bool NewCombo { get; set; } - public int ComboOffset { get; set; } + public readonly Bindable ComboOffsetBindable = new Bindable(); - public virtual int IndexInCurrentCombo { get; set; } + public int ComboOffset + { + get => ComboOffsetBindable.Value; + set => ComboOffsetBindable.Value = value; + } - public virtual int ComboIndex { get; set; } + public Bindable IndexInCurrentComboBindable { get; } = new Bindable(); - public bool LastInCombo { get; set; } + public virtual int IndexInCurrentCombo + { + get => IndexInCurrentComboBindable.Value; + set => IndexInCurrentComboBindable.Value = value; + } + + public Bindable ComboIndexBindable { get; } = new Bindable(); + + public virtual int ComboIndex + { + get => ComboIndexBindable.Value; + set => ComboIndexBindable.Value = value; + } + + public Bindable LastInComboBindable { get; } = new Bindable(); + + public bool LastInCombo + { + get => LastInComboBindable.Value; + set => LastInComboBindable.Value = value; + } protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) { diff --git a/osu.Game.Rulesets.Osu/Objects/Slider.cs b/osu.Game.Rulesets.Osu/Objects/Slider.cs index 2805494021..d8514092bc 100644 --- a/osu.Game.Rulesets.Osu/Objects/Slider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Slider.cs @@ -33,28 +33,6 @@ namespace osu.Game.Rulesets.Osu.Objects public Vector2 StackedPositionAt(double t) => StackedPosition + this.CurvePositionAt(t); - public override int ComboIndex - { - get => base.ComboIndex; - set - { - base.ComboIndex = value; - foreach (var n in NestedHitObjects.OfType()) - n.ComboIndex = value; - } - } - - public override int IndexInCurrentCombo - { - get => base.IndexInCurrentCombo; - set - { - base.IndexInCurrentCombo = value; - foreach (var n in NestedHitObjects.OfType()) - n.IndexInCurrentCombo = value; - } - } - public readonly Bindable PathBindable = new Bindable(); public SliderPath Path @@ -192,8 +170,6 @@ namespace osu.Game.Rulesets.Osu.Objects Position = Position, Samples = getNodeSamples(0), SampleControlPoint = SampleControlPoint, - IndexInCurrentCombo = IndexInCurrentCombo, - ComboIndex = ComboIndex, }); break; @@ -205,8 +181,6 @@ namespace osu.Game.Rulesets.Osu.Objects { StartTime = e.Time, Position = EndPosition, - IndexInCurrentCombo = IndexInCurrentCombo, - ComboIndex = ComboIndex, }); break; diff --git a/osu.Game.Rulesets.Osu/Skinning/LegacyMainCirclePiece.cs b/osu.Game.Rulesets.Osu/Skinning/LegacyMainCirclePiece.cs index 83d507f64b..93ae0371df 100644 --- a/osu.Game.Rulesets.Osu/Skinning/LegacyMainCirclePiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/LegacyMainCirclePiece.cs @@ -9,7 +9,6 @@ using osu.Framework.Graphics.Sprites; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Rulesets.Objects.Drawables; -using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Skinning; using osuTK; @@ -25,13 +24,16 @@ namespace osu.Game.Rulesets.Osu.Skinning } private readonly IBindable state = new Bindable(); - private readonly Bindable accentColour = new Bindable(); + private readonly IBindable indexInCurrentCombo = new Bindable(); [BackgroundDependencyLoader] private void load(DrawableHitObject drawableObject, ISkinSource skin) { + OsuHitObject osuObject = (OsuHitObject)drawableObject.HitObject; + Sprite hitCircleSprite; + SkinnableSpriteText hitCircleText; InternalChildren = new Drawable[] { @@ -42,14 +44,11 @@ namespace osu.Game.Rulesets.Osu.Skinning Anchor = Anchor.Centre, Origin = Anchor.Centre, }, - new SkinnableSpriteText(new OsuSkinComponent(OsuSkinComponents.HitCircleText), _ => new OsuSpriteText + hitCircleText = new SkinnableSpriteText(new OsuSkinComponent(OsuSkinComponents.HitCircleText), _ => new OsuSpriteText { Font = OsuFont.Numeric.With(size: 40), UseFullGlyphHeight = false, - }, confineMode: ConfineMode.NoScaling) - { - Text = (((IHasComboInformation)drawableObject.HitObject).IndexInCurrentCombo + 1).ToString() - }, + }, confineMode: ConfineMode.NoScaling), new Sprite { Texture = skin.GetTexture("hitcircleoverlay"), @@ -63,6 +62,9 @@ namespace osu.Game.Rulesets.Osu.Skinning accentColour.BindTo(drawableObject.AccentColour); accentColour.BindValueChanged(colour => hitCircleSprite.Colour = colour.NewValue, true); + + indexInCurrentCombo.BindTo(osuObject.IndexInCurrentComboBindable); + indexInCurrentCombo.BindValueChanged(index => hitCircleText.Text = (index.NewValue + 1).ToString(), true); } private void updateState(ValueChangedEvent state) diff --git a/osu.Game/Beatmaps/BeatmapProcessor.cs b/osu.Game/Beatmaps/BeatmapProcessor.cs index 7a612893c9..250cc49ad4 100644 --- a/osu.Game/Beatmaps/BeatmapProcessor.cs +++ b/osu.Game/Beatmaps/BeatmapProcessor.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using System.Linq; -using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Types; namespace osu.Game.Beatmaps @@ -45,25 +44,6 @@ namespace osu.Game.Beatmaps public virtual void PostProcess() { - void updateNestedCombo(HitObject obj, int comboIndex, int indexInCurrentCombo) - { - if (obj is IHasComboInformation objectComboInfo) - { - objectComboInfo.ComboIndex = comboIndex; - objectComboInfo.IndexInCurrentCombo = indexInCurrentCombo; - foreach (var nestedObject in obj.NestedHitObjects) - updateNestedCombo(nestedObject, comboIndex, indexInCurrentCombo); - } - } - - foreach (var hitObject in Beatmap.HitObjects) - { - if (hitObject is IHasComboInformation objectComboInfo) - { - foreach (var nested in hitObject.NestedHitObjects) - updateNestedCombo(nested, objectComboInfo.ComboIndex, objectComboInfo.IndexInCurrentCombo); - } - } } } } diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index 8d8f8a419f..f8bc74b2a6 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -76,6 +76,8 @@ namespace osu.Game.Rulesets.Objects.Drawables /// public JudgementResult Result { get; private set; } + private Bindable comboIndexBindable; + public override bool RemoveWhenNotAlive => false; public override bool RemoveCompletedTransforms => false; protected override bool RequiresChildrenUpdate => true; @@ -122,6 +124,13 @@ namespace osu.Game.Rulesets.Objects.Drawables protected override void LoadComplete() { base.LoadComplete(); + + if (HitObject is IHasComboInformation combo) + { + comboIndexBindable = combo.ComboIndexBindable.GetBoundCopy(); + comboIndexBindable.BindValueChanged(_ => updateAccentColour()); + } + updateState(ArmedState.Idle, true); } @@ -244,12 +253,7 @@ namespace osu.Game.Rulesets.Objects.Drawables { base.SkinChanged(skin, allowFallback); - if (HitObject is IHasComboInformation combo) - { - var comboColours = skin.GetConfig>(GlobalSkinConfiguration.ComboColours)?.Value; - - AccentColour.Value = comboColours?.Count > 0 ? comboColours[combo.ComboIndex % comboColours.Count] : Color4.White; - } + updateAccentColour(); ApplySkin(skin, allowFallback); @@ -257,6 +261,15 @@ namespace osu.Game.Rulesets.Objects.Drawables updateState(State.Value, true); } + private void updateAccentColour() + { + if (HitObject is IHasComboInformation combo) + { + var comboColours = CurrentSkin.GetConfig>(GlobalSkinConfiguration.ComboColours)?.Value; + AccentColour.Value = comboColours?.Count > 0 ? comboColours[combo.ComboIndex % comboColours.Count] : Color4.White; + } + } + /// /// Called when a change is made to the skin. /// diff --git a/osu.Game/Rulesets/Objects/HitObject.cs b/osu.Game/Rulesets/Objects/HitObject.cs index 96297ab44f..6c5627c5d2 100644 --- a/osu.Game/Rulesets/Objects/HitObject.cs +++ b/osu.Game/Rulesets/Objects/HitObject.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System.Collections.Generic; +using System.Linq; using JetBrains.Annotations; using Newtonsoft.Json; using osu.Game.Audio; @@ -82,6 +83,15 @@ namespace osu.Game.Rulesets.Objects CreateNestedHitObjects(); + if (this is IHasComboInformation hasCombo) + { + foreach (var n in NestedHitObjects.OfType()) + { + n.ComboIndexBindable.BindTo(hasCombo.ComboIndexBindable); + n.IndexInCurrentComboBindable.BindTo(hasCombo.IndexInCurrentComboBindable); + } + } + nestedHitObjects.Sort((h1, h2) => h1.StartTime.CompareTo(h2.StartTime)); foreach (var h in nestedHitObjects) diff --git a/osu.Game/Rulesets/Objects/Types/IHasComboInformation.cs b/osu.Game/Rulesets/Objects/Types/IHasComboInformation.cs index e07da93a3a..4e3de04278 100644 --- a/osu.Game/Rulesets/Objects/Types/IHasComboInformation.cs +++ b/osu.Game/Rulesets/Objects/Types/IHasComboInformation.cs @@ -1,6 +1,8 @@ // 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.Bindables; + namespace osu.Game.Rulesets.Objects.Types { /// @@ -8,16 +10,22 @@ namespace osu.Game.Rulesets.Objects.Types /// public interface IHasComboInformation : IHasCombo { + Bindable IndexInCurrentComboBindable { get; } + /// /// The offset of this hitobject in the current combo. /// int IndexInCurrentCombo { get; set; } + Bindable ComboIndexBindable { get; } + /// /// The offset of this combo in relation to the beatmap. /// int ComboIndex { get; set; } + Bindable LastInComboBindable { get; } + /// /// Whether this is the last object in the current combo. /// diff --git a/osu.Game/Skinning/SkinReloadableDrawable.cs b/osu.Game/Skinning/SkinReloadableDrawable.cs index 4bbdeafba5..6d0b22dd51 100644 --- a/osu.Game/Skinning/SkinReloadableDrawable.cs +++ b/osu.Game/Skinning/SkinReloadableDrawable.cs @@ -12,13 +12,17 @@ namespace osu.Game.Skinning /// public abstract class SkinReloadableDrawable : CompositeDrawable { + /// + /// The current skin source. + /// + protected ISkinSource CurrentSkin { get; private set; } + private readonly Func allowFallback; - private ISkinSource skin; /// /// Whether fallback to default skin should be allowed if the custom skin is missing this resource. /// - private bool allowDefaultFallback => allowFallback == null || allowFallback.Invoke(skin); + private bool allowDefaultFallback => allowFallback == null || allowFallback.Invoke(CurrentSkin); /// /// Create a new @@ -32,19 +36,19 @@ namespace osu.Game.Skinning [BackgroundDependencyLoader] private void load(ISkinSource source) { - skin = source; - skin.SourceChanged += onChange; + CurrentSkin = source; + CurrentSkin.SourceChanged += onChange; } private void onChange() => // schedule required to avoid calls after disposed. // note that this has the side-effect of components only performing a skin change when they are alive. - Scheduler.AddOnce(() => SkinChanged(skin, allowDefaultFallback)); + Scheduler.AddOnce(() => SkinChanged(CurrentSkin, allowDefaultFallback)); protected override void LoadAsyncComplete() { base.LoadAsyncComplete(); - SkinChanged(skin, allowDefaultFallback); + SkinChanged(CurrentSkin, allowDefaultFallback); } /// @@ -60,8 +64,8 @@ namespace osu.Game.Skinning { base.Dispose(isDisposing); - if (skin != null) - skin.SourceChanged -= onChange; + if (CurrentSkin != null) + CurrentSkin.SourceChanged -= onChange; } } }