diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index 312fbaa2d1..84b2dd7957 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -146,6 +146,11 @@ namespace osu.Game.Rulesets.Objects.Drawables private Container samplesContainer; + /// + /// Whether the initialization logic in has applied. + /// + internal bool HasInitialized; + /// /// Creates a new . /// diff --git a/osu.Game/Rulesets/UI/Playfield.cs b/osu.Game/Rulesets/UI/Playfield.cs index 8723a8c531..f0b63fd347 100644 --- a/osu.Game/Rulesets/UI/Playfield.cs +++ b/osu.Game/Rulesets/UI/Playfield.cs @@ -16,6 +16,7 @@ using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Objects; using osuTK; +using System.Diagnostics; namespace osu.Game.Rulesets.UI { @@ -95,9 +96,6 @@ namespace osu.Game.Rulesets.UI /// protected Playfield() { - OnNewDrawableHitObject += d => - d.OnNestedDrawableCreated += nested => OnNewDrawableHitObject?.Invoke(nested); - RelativeSizeAxes = Axes.Both; hitObjectContainerLazy = new Lazy(() => CreateHitObjectContainer().With(h => @@ -126,6 +124,16 @@ namespace osu.Game.Rulesets.UI } } + private void onNewDrawableHitObject(DrawableHitObject d) + { + d.OnNestedDrawableCreated += onNewDrawableHitObject; + + OnNewDrawableHitObject?.Invoke(d); + + Debug.Assert(!d.HasInitialized); + d.HasInitialized = true; + } + /// /// Performs post-processing tasks (if any) after all DrawableHitObjects are loaded into this Playfield. /// @@ -137,7 +145,10 @@ namespace osu.Game.Rulesets.UI /// The DrawableHitObject to add. public virtual void Add(DrawableHitObject h) { - OnNewDrawableHitObject?.Invoke(h); + if (h.HasInitialized) + throw new InvalidOperationException($"{nameof(Playfield.Add)} doesn't support {nameof(DrawableHitObject)} reuse. Use pooling instead."); + + onNewDrawableHitObject(h); HitObjectContainer.Add(h); OnHitObjectAdded(h.HitObject); @@ -336,12 +347,12 @@ namespace osu.Game.Rulesets.UI { var dho = (DrawableHitObject)d; - // If this is the first time this DHO is being used (not loaded), then apply the DHO mods. - // This is done before Apply() so that the state is updated once when the hitobject is applied. - if (!dho.IsLoaded) + if (!dho.HasInitialized) { - OnNewDrawableHitObject?.Invoke(dho); + onNewDrawableHitObject(dho); + // If this is the first time this DHO is being used, then apply the DHO mods. + // This is done before Apply() so that the state is updated once when the hitobject is applied. foreach (var m in mods.OfType()) m.ApplyToDrawableHitObjects(dho.Yield()); }