Revert the change of not adding non-pooled DHO to HOC until alive

This commit is contained in:
ekrctb
2021-05-04 16:44:48 +09:00
parent 36438175a0
commit 913fc8c3bc

View File

@ -27,7 +27,7 @@ namespace osu.Game.Rulesets.UI
/// <summary> /// <summary>
/// All alive entries and <see cref="DrawableHitObject"/>s used by the entries. /// All alive entries and <see cref="DrawableHitObject"/>s used by the entries.
/// </summary> /// </summary>
public IEnumerable<(HitObjectLifetimeEntry Entry, DrawableHitObject Drawable)> AliveEntries => drawableMap.Select(x => (x.Key, x.Value)); public IEnumerable<(HitObjectLifetimeEntry Entry, DrawableHitObject Drawable)> AliveEntries => aliveDrawableMap.Select(x => (x.Key, x.Value));
public IEnumerable<DrawableHitObject> Objects => InternalChildren.Cast<DrawableHitObject>().OrderBy(h => h.HitObject.StartTime); public IEnumerable<DrawableHitObject> Objects => InternalChildren.Cast<DrawableHitObject>().OrderBy(h => h.HitObject.StartTime);
@ -71,7 +71,7 @@ namespace osu.Game.Rulesets.UI
private readonly Dictionary<DrawableHitObject, IBindable> startTimeMap = new Dictionary<DrawableHitObject, IBindable>(); private readonly Dictionary<DrawableHitObject, IBindable> startTimeMap = new Dictionary<DrawableHitObject, IBindable>();
private readonly Dictionary<HitObjectLifetimeEntry, DrawableHitObject> drawableMap = new Dictionary<HitObjectLifetimeEntry, DrawableHitObject>(); private readonly Dictionary<HitObjectLifetimeEntry, DrawableHitObject> aliveDrawableMap = new Dictionary<HitObjectLifetimeEntry, DrawableHitObject>();
private readonly Dictionary<HitObjectLifetimeEntry, DrawableHitObject> nonPooledDrawableMap = new Dictionary<HitObjectLifetimeEntry, DrawableHitObject>(); private readonly Dictionary<HitObjectLifetimeEntry, DrawableHitObject> nonPooledDrawableMap = new Dictionary<HitObjectLifetimeEntry, DrawableHitObject>();
private readonly LifetimeEntryManager lifetimeManager = new LifetimeEntryManager(); private readonly LifetimeEntryManager lifetimeManager = new LifetimeEntryManager();
@ -108,55 +108,70 @@ namespace osu.Game.Rulesets.UI
public bool Remove(HitObjectLifetimeEntry entry) public bool Remove(HitObjectLifetimeEntry entry)
{ {
if (!lifetimeManager.RemoveEntry(entry)) return false; if (!lifetimeManager.RemoveEntry(entry)) return false;
// The entry has to be removed from the non-pooled map here because non-pooled entry may be removed by specifying its entry.
nonPooledDrawableMap.Remove(entry); // This logic is not in `Remove(DrawableHitObject)` because a non-pooled drawable may be removed by specifying its entry.
if (nonPooledDrawableMap.Remove(entry, out var drawable))
removeDrawable(drawable);
allEntries.Remove(entry); allEntries.Remove(entry);
return true; return true;
} }
private void entryBecameAlive(LifetimeEntry entry) => addDrawable((HitObjectLifetimeEntry)entry); private void entryBecameAlive(LifetimeEntry lifetimeEntry)
private void entryBecameDead(LifetimeEntry entry) => removeDrawable((HitObjectLifetimeEntry)entry);
private void addDrawable(HitObjectLifetimeEntry entry)
{ {
Debug.Assert(!drawableMap.ContainsKey(entry)); var entry = (HitObjectLifetimeEntry)lifetimeEntry;
Debug.Assert(!aliveDrawableMap.ContainsKey(entry));
nonPooledDrawableMap.TryGetValue(entry, out var drawable); bool isNonPooled = nonPooledDrawableMap.TryGetValue(entry, out var drawable);
drawable ??= pooledObjectProvider?.GetPooledDrawableRepresentation(entry.HitObject, null); drawable ??= pooledObjectProvider?.GetPooledDrawableRepresentation(entry.HitObject, null);
if (drawable == null) if (drawable == null)
throw new InvalidOperationException($"A drawable representation could not be retrieved for hitobject type: {entry.HitObject.GetType().ReadableName()}."); throw new InvalidOperationException($"A drawable representation could not be retrieved for hitobject type: {entry.HitObject.GetType().ReadableName()}.");
aliveDrawableMap[entry] = drawable;
OnAdd(drawable);
if (isNonPooled) return;
addDrawable(drawable);
HitObjectUsageBegan?.Invoke(entry.HitObject);
}
private void entryBecameDead(LifetimeEntry lifetimeEntry)
{
var entry = (HitObjectLifetimeEntry)lifetimeEntry;
Debug.Assert(aliveDrawableMap.ContainsKey(entry));
var drawable = aliveDrawableMap[entry];
bool isNonPooled = nonPooledDrawableMap.ContainsKey(entry);
drawable.OnKilled();
aliveDrawableMap.Remove(entry);
OnRemove(drawable);
if (isNonPooled) return;
removeDrawable(drawable);
// The hit object is not freed when the DHO was not pooled.
HitObjectUsageFinished?.Invoke(entry.HitObject);
}
private void addDrawable(DrawableHitObject drawable)
{
drawable.OnNewResult += onNewResult; drawable.OnNewResult += onNewResult;
drawable.OnRevertResult += onRevertResult; drawable.OnRevertResult += onRevertResult;
bindStartTime(drawable); bindStartTime(drawable);
AddInternal(drawableMap[entry] = drawable); AddInternal(drawable);
OnAdd(drawable);
HitObjectUsageBegan?.Invoke(entry.HitObject);
} }
private void removeDrawable(HitObjectLifetimeEntry entry) private void removeDrawable(DrawableHitObject drawable)
{ {
Debug.Assert(drawableMap.ContainsKey(entry));
var drawable = drawableMap[entry];
// OnKilled can potentially change the hitobject's result, so it needs to run first before unbinding.
drawable.OnKilled();
drawable.OnNewResult -= onNewResult; drawable.OnNewResult -= onNewResult;
drawable.OnRevertResult -= onRevertResult; drawable.OnRevertResult -= onRevertResult;
drawableMap.Remove(entry);
OnRemove(drawable);
unbindStartTime(drawable); unbindStartTime(drawable);
RemoveInternal(drawable);
// The hit object is not freed when the DHO was not pooled. RemoveInternal(drawable);
if (!nonPooledDrawableMap.ContainsKey(entry))
HitObjectUsageFinished?.Invoke(entry.HitObject);
} }
#endregion #endregion
@ -169,6 +184,7 @@ namespace osu.Game.Rulesets.UI
throw new InvalidOperationException($"May not add a {nameof(DrawableHitObject)} without {nameof(HitObject)} associated"); throw new InvalidOperationException($"May not add a {nameof(DrawableHitObject)} without {nameof(HitObject)} associated");
nonPooledDrawableMap.Add(drawable.Entry, drawable); nonPooledDrawableMap.Add(drawable.Entry, drawable);
addDrawable(drawable);
Add(drawable.Entry); Add(drawable.Entry);
} }
@ -217,8 +233,10 @@ namespace osu.Game.Rulesets.UI
public virtual void Clear() public virtual void Clear()
{ {
lifetimeManager.ClearEntries(); lifetimeManager.ClearEntries();
foreach (var drawable in nonPooledDrawableMap.Values)
removeDrawable(drawable);
nonPooledDrawableMap.Clear(); nonPooledDrawableMap.Clear();
Debug.Assert(InternalChildren.Count == 0 && startTimeMap.Count == 0 && drawableMap.Count == 0, "All hit objects should have been removed"); Debug.Assert(InternalChildren.Count == 0 && startTimeMap.Count == 0 && aliveDrawableMap.Count == 0, "All hit objects should have been removed");
} }
protected override bool CheckChildrenLife() protected override bool CheckChildrenLife()