diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderHead.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderHead.cs index 3a92938d75..d1928bd4bb 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderHead.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderHead.cs @@ -47,6 +47,11 @@ protected override void OnParentReceived(DrawableHitObject parent) base.OnParentReceived(parent); drawableSlider = (DrawableSlider)parent; + } + + protected override void OnApply() + { + base.OnApply(); pathVersion.BindTo(drawableSlider.PathVersion); diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderRepeat.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderRepeat.cs index 0735d48ae1..f368615e77 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderRepeat.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderRepeat.cs @@ -65,6 +65,11 @@ protected override void OnParentReceived(DrawableHitObject parent) base.OnParentReceived(parent); drawableSlider = (DrawableSlider)parent; + } + + protected override void OnApply() + { + base.OnApply(); Position = HitObject.Position - drawableSlider.Position; } diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTick.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTick.cs index faccf5d4d1..d40b6aea6e 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTick.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTick.cs @@ -23,6 +23,7 @@ public class DrawableSliderTick : DrawableOsuHitObject, IRequireTracking public override bool DisplayResult => false; private SkinnableDrawable scaleContainer; + private DrawableSlider drawableSlider; public DrawableSliderTick() : base(null) @@ -66,7 +67,14 @@ protected override void OnParentReceived(DrawableHitObject parent) { base.OnParentReceived(parent); - Position = HitObject.Position - ((DrawableSlider)parent).HitObject.Position; + drawableSlider = (DrawableSlider)parent; + } + + protected override void OnApply() + { + base.OnApply(); + + Position = HitObject.Position - drawableSlider.HitObject.Position; } protected override void CheckForResult(bool userTriggered, double timeOffset) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinnerTick.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinnerTick.cs index f37d933e11..d10c4f7511 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinnerTick.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinnerTick.cs @@ -24,6 +24,7 @@ public DrawableSpinnerTick(SpinnerTick spinnerTick) protected override void OnParentReceived(DrawableHitObject parent) { base.OnParentReceived(parent); + drawableSpinner = (DrawableSpinner)parent; } diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index a922da0aa9..37c36ace7b 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -230,12 +230,12 @@ public void Apply([NotNull] HitObject hitObject, [CanBeNull] HitObjectLifetimeEn foreach (var h in HitObject.NestedHitObjects) { - var pooledDrawableNested = pooledObjectProvider?.GetPooledDrawableRepresentation(h); + var pooledDrawableNested = pooledObjectProvider?.GetPooledDrawableRepresentation(h, this); var drawableNested = pooledDrawableNested ?? CreateNestedHitObject(h) ?? throw new InvalidOperationException($"{nameof(CreateNestedHitObject)} returned null for {h.GetType().ReadableName()}."); - // Invoke the event only if this nested object is just created by `CreateNestedHitObject`. + // Only invoke the event for non-pooled DHOs, otherwise the event will be fired by the playfield. if (pooledDrawableNested == null) OnNestedDrawableCreated?.Invoke(drawableNested); @@ -243,10 +243,12 @@ public void Apply([NotNull] HitObject hitObject, [CanBeNull] HitObjectLifetimeEn drawableNested.OnRevertResult += onRevertResult; drawableNested.ApplyCustomUpdateState += onApplyCustomUpdateState; + // ApplyParent() should occur before Apply() in all cases, so it's invoked before the nested DHO is added to the hierarchy below, but after its events are initialised. + if (pooledDrawableNested == null) + drawableNested.ApplyParent(this); + nestedHitObjects.Value.Add(drawableNested); AddNestedHitObject(drawableNested); - - drawableNested.OnParentReceived(this); } StartTimeBindable.BindTo(HitObject.StartTimeBindable); @@ -348,6 +350,12 @@ protected virtual void OnFree() { } + /// + /// Applies a parenting to this . + /// + /// The parenting . + public void ApplyParent(DrawableHitObject parent) => OnParentReceived(parent); + /// /// Invoked when this receives a new parenting . /// diff --git a/osu.Game/Rulesets/UI/HitObjectContainer.cs b/osu.Game/Rulesets/UI/HitObjectContainer.cs index ac5d281ddc..12e39d4fbf 100644 --- a/osu.Game/Rulesets/UI/HitObjectContainer.cs +++ b/osu.Game/Rulesets/UI/HitObjectContainer.cs @@ -105,7 +105,7 @@ private void addDrawable(HitObjectLifetimeEntry entry) { Debug.Assert(!drawableMap.ContainsKey(entry)); - var drawable = pooledObjectProvider?.GetPooledDrawableRepresentation(entry.HitObject); + var drawable = pooledObjectProvider?.GetPooledDrawableRepresentation(entry.HitObject, null); if (drawable == null) throw new InvalidOperationException($"A drawable representation could not be retrieved for hitobject type: {entry.HitObject.GetType().ReadableName()}."); diff --git a/osu.Game/Rulesets/UI/IPooledHitObjectProvider.cs b/osu.Game/Rulesets/UI/IPooledHitObjectProvider.cs index 315926dfc6..2d700076d6 100644 --- a/osu.Game/Rulesets/UI/IPooledHitObjectProvider.cs +++ b/osu.Game/Rulesets/UI/IPooledHitObjectProvider.cs @@ -13,8 +13,9 @@ internal interface IPooledHitObjectProvider /// Attempts to retrieve the poolable representation of a . /// /// The to retrieve the representation of. + /// The parenting , if any. /// The representing , or null if no poolable representation exists. [CanBeNull] - DrawableHitObject GetPooledDrawableRepresentation([NotNull] HitObject hitObject); + DrawableHitObject GetPooledDrawableRepresentation([NotNull] HitObject hitObject, [CanBeNull] DrawableHitObject parent); } } diff --git a/osu.Game/Rulesets/UI/Playfield.cs b/osu.Game/Rulesets/UI/Playfield.cs index a2ac234471..01b25c9717 100644 --- a/osu.Game/Rulesets/UI/Playfield.cs +++ b/osu.Game/Rulesets/UI/Playfield.cs @@ -323,7 +323,7 @@ protected void RegisterPool([NotNull] DrawablePool