diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs
index dfeb87de88..9b132ea932 100644
--- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs
+++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs
@@ -39,7 +39,12 @@ namespace osu.Game.Rulesets.Objects.Drawables
///
/// The currently represented by this .
///
- public HitObject HitObject { get; private set; }
+ public HitObject HitObject => lifetimeEntry?.HitObject ?? initialHitObject;
+
+ ///
+ /// The given in the constructor that will be applied when loaded.
+ ///
+ private HitObject initialHitObject;
///
/// The parenting , if any.
@@ -108,7 +113,7 @@ namespace osu.Game.Rulesets.Objects.Drawables
///
/// The scoring result of this .
///
- public JudgementResult Result { get; private set; }
+ public JudgementResult Result => lifetimeEntry?.Result;
///
/// The relative X position of this hit object for sample playback balance adjustment.
@@ -140,11 +145,6 @@ namespace osu.Game.Rulesets.Objects.Drawables
///
public IBindable State => state;
- ///
- /// Whether is currently applied.
- ///
- private bool hasHitObjectApplied;
-
///
/// The controlling the lifetime of the currently-attached .
///
@@ -168,7 +168,7 @@ namespace osu.Game.Rulesets.Objects.Drawables
///
protected DrawableHitObject([CanBeNull] HitObject initialHitObject = null)
{
- HitObject = initialHitObject;
+ this.initialHitObject = initialHitObject;
}
[BackgroundDependencyLoader]
@@ -184,8 +184,11 @@ namespace osu.Game.Rulesets.Objects.Drawables
{
base.LoadAsyncComplete();
- if (HitObject != null)
- Apply(HitObject, lifetimeEntry);
+ if (initialHitObject != null)
+ {
+ Apply(initialHitObject, null);
+ initialHitObject = null;
+ }
}
protected override void LoadComplete()
@@ -209,26 +212,36 @@ namespace osu.Game.Rulesets.Objects.Drawables
if (lifetimeEntry != null)
{
- applyEntry(lifetimeEntry);
+ if (lifetimeEntry.HitObject != hitObject)
+ throw new InvalidOperationException($"{nameof(HitObjectLifetimeEntry)} has different {nameof(HitObject)} from the specified one.");
+
+ apply(lifetimeEntry);
}
else
{
- applyHitObject(hitObject);
+ var unmanagedEntry = new UnmanagedHitObjectEntry(hitObject, this);
+ apply(unmanagedEntry);
// Set default lifetime for a non-pooled DHO
LifetimeStart = hitObject.StartTime - InitialLifetimeOffset;
}
}
- private void applyHitObject([NotNull] HitObject hitObject)
+ ///
+ /// Applies a new to be represented by this .
+ ///
+ private void apply([NotNull] HitObjectLifetimeEntry entry)
{
- freeHitObject();
+ free();
- HitObject = hitObject;
+ lifetimeEntry = entry;
+
+ LifetimeStart = entry.LifetimeStart;
+ LifetimeEnd = entry.LifetimeEnd;
// Ensure this DHO has a result.
- Result ??= CreateResult(HitObject.CreateJudgement())
- ?? throw new InvalidOperationException($"{GetType().ReadableName()} must provide a {nameof(JudgementResult)} through {nameof(CreateResult)}.");
+ entry.Result ??= CreateResult(HitObject.CreateJudgement())
+ ?? throw new InvalidOperationException($"{GetType().ReadableName()} must provide a {nameof(JudgementResult)} through {nameof(CreateResult)}.");
// Copy back the result to the entry for potential future retrieval.
if (lifetimeEntry != null)
@@ -281,30 +294,14 @@ namespace osu.Game.Rulesets.Objects.Drawables
else
updateState(ArmedState.Idle, true);
}
-
- hasHitObjectApplied = true;
- }
-
- private void applyEntry([NotNull] HitObjectLifetimeEntry entry)
- {
- freeEntry();
-
- setLifetime(entry.LifetimeStart, entry.LifetimeEnd);
- lifetimeEntry = entry;
-
- // Copy any existing result from the entry (required for rewind / judgement revert).
- Result = entry.Result;
-
- applyHitObject(entry.HitObject);
}
///
- /// Removes the currently applied
+ /// Removes the currently applied
///
- private void freeHitObject()
+ private void free()
{
- if (!hasHitObjectApplied)
- return;
+ if (lifetimeEntry == null) return;
StartTimeBindable.UnbindFrom(HitObject.StartTimeBindable);
if (HitObject is IHasComboInformation combo)
@@ -336,24 +333,10 @@ namespace osu.Game.Rulesets.Objects.Drawables
OnFree();
- HitObject = null;
ParentHitObject = null;
- Result = null;
-
- clearExistingStateTransforms();
-
- hasHitObjectApplied = false;
- }
-
- private void freeEntry()
- {
- freeHitObject();
-
- if (lifetimeEntry == null) return;
-
lifetimeEntry = null;
- setLifetime(double.MaxValue, double.MaxValue);
+ clearExistingStateTransforms();
}
protected sealed override void FreeAfterUse()
@@ -364,7 +347,7 @@ namespace osu.Game.Rulesets.Objects.Drawables
if (!IsInPool)
return;
- freeEntry();
+ free();
}
///
diff --git a/osu.Game/Rulesets/Objects/UnmanagedHitObjectEntry.cs b/osu.Game/Rulesets/Objects/UnmanagedHitObjectEntry.cs
new file mode 100644
index 0000000000..507cad15d3
--- /dev/null
+++ b/osu.Game/Rulesets/Objects/UnmanagedHitObjectEntry.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.Game.Rulesets.Objects.Drawables;
+
+namespace osu.Game.Rulesets.Objects
+{
+ internal class UnmanagedHitObjectEntry : HitObjectLifetimeEntry
+ {
+ public readonly DrawableHitObject DrawableHitObject;
+
+ public UnmanagedHitObjectEntry(HitObject hitObject, DrawableHitObject drawableHitObject)
+ : base(hitObject)
+ {
+ DrawableHitObject = drawableHitObject;
+ LifetimeStart = DrawableHitObject.LifetimeStart;
+ LifetimeEnd = DrawableHitObject.LifetimeEnd;
+ }
+ }
+}