diff --git a/osu.Game/Rulesets/UI/DrawableRuleset.cs b/osu.Game/Rulesets/UI/DrawableRuleset.cs
index f6cf836fe7..8c6db661b5 100644
--- a/osu.Game/Rulesets/UI/DrawableRuleset.cs
+++ b/osu.Game/Rulesets/UI/DrawableRuleset.cs
@@ -15,7 +15,9 @@ using System.Linq;
using System.Threading;
using JetBrains.Annotations;
using osu.Framework.Bindables;
+using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Graphics.Cursor;
+using osu.Framework.Graphics.Pooling;
using osu.Framework.Input;
using osu.Framework.Input.Events;
using osu.Game.Configuration;
@@ -92,11 +94,8 @@ namespace osu.Game.Rulesets.UI
protected IRulesetConfigManager Config { get; private set; }
- ///
- /// The mods which are to be applied.
- ///
[Cached(typeof(IReadOnlyList))]
- protected readonly IReadOnlyList Mods;
+ protected override IReadOnlyList Mods { get; }
private FrameStabilityContainer frameStabilityContainer;
@@ -284,12 +283,15 @@ namespace osu.Game.Rulesets.UI
}
}
+ public sealed override DrawableHitObject GetDrawableRepresentation(HitObject hitObject)
+ => base.GetDrawableRepresentation(hitObject) ?? CreateDrawableRepresentation((TObject)hitObject);
+
///
/// Creates a DrawableHitObject from a HitObject.
///
/// The HitObject to make drawable.
/// The DrawableHitObject.
- public abstract DrawableHitObject CreateDrawableRepresentation(TObject h);
+ public virtual DrawableHitObject CreateDrawableRepresentation(TObject h) => null;
public void Attach(KeyCounterDisplay keyCounter) =>
(KeyBindingInputManager as ICanAttachKeyCounter)?.Attach(keyCounter);
@@ -406,6 +408,11 @@ namespace osu.Game.Rulesets.UI
///
public abstract IFrameStableClock FrameStableClock { get; }
+ ///
+ /// The mods which are to be applied.
+ ///
+ protected abstract IReadOnlyList Mods { get; }
+
/// ~
/// The associated ruleset.
///
@@ -500,6 +507,66 @@ namespace osu.Game.Rulesets.UI
/// Invoked when the user requests to pause while the resume overlay is active.
///
public abstract void CancelResume();
+
+ ///
+ /// Whether this should retrieve pooled s.
+ ///
+ ///
+ /// Pools must be registered with this via in order for s to be retrieved.
+ ///
+ /// If true, hitobjects will be added to the via .
+ /// If false, will be used instead.
+ ///
+ ///
+ protected virtual bool PoolHitObjects => false;
+
+ private readonly Dictionary pools = new Dictionary();
+
+ protected void RegisterPool(int initialSize, int? maximumSize = null)
+ where TObject : HitObject
+ where TDrawable : DrawableHitObject, new()
+ {
+ var pool = CreatePool(initialSize, maximumSize);
+ pools[typeof(TObject)] = pool;
+ AddInternal(pool);
+ }
+
+ ///
+ /// Creates the to retrieve s of the given type from.
+ ///
+ /// The number of hitobject to be prepared for initial consumption.
+ /// An optional maximum size after which the pool will no longer be expanded.
+ /// The type of retrievable from this pool.
+ /// The .
+ protected virtual DrawablePool CreatePool(int initialSize, int? maximumSize = null)
+ where TDrawable : DrawableHitObject, new()
+ => new DrawablePool(initialSize, maximumSize);
+
+ ///
+ /// Retrieves the drawable representation of a .
+ ///
+ /// The to retrieve the drawable representation of.
+ /// The representing .
+ public virtual DrawableHitObject GetDrawableRepresentation(HitObject hitObject)
+ {
+ if (!pools.TryGetValue(hitObject.GetType(), out var pool))
+ return null;
+
+ return (DrawableHitObject)pool.Get(d =>
+ {
+ 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)
+ {
+ foreach (var m in Mods.OfType())
+ m.ApplyToDrawableHitObjects(dho.Yield());
+ }
+
+ dho.Apply(hitObject);
+ });
+ }
}
public class BeatmapInvalidForRulesetException : ArgumentException