Merge pull request #13331 from ekrctb/pdwl-follow-point

Use general lifetime container for follow point container
This commit is contained in:
Dan Balasescu
2021-06-04 20:39:39 +09:00
committed by GitHub
3 changed files with 35 additions and 78 deletions

View File

@ -5,6 +5,7 @@ using System;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Pooling; using osu.Framework.Graphics.Pooling;
using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Pooling;
using osuTK; using osuTK;
namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
@ -12,34 +13,29 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
/// <summary> /// <summary>
/// Visualises the <see cref="FollowPoint"/>s between two <see cref="DrawableOsuHitObject"/>s. /// Visualises the <see cref="FollowPoint"/>s between two <see cref="DrawableOsuHitObject"/>s.
/// </summary> /// </summary>
public class FollowPointConnection : PoolableDrawable public class FollowPointConnection : PoolableDrawableWithLifetime<FollowPointLifetimeEntry>
{ {
// Todo: These shouldn't be constants // Todo: These shouldn't be constants
public const int SPACING = 32; public const int SPACING = 32;
public const double PREEMPT = 800; public const double PREEMPT = 800;
public FollowPointLifetimeEntry Entry;
public DrawablePool<FollowPoint> Pool; public DrawablePool<FollowPoint> Pool;
protected override void PrepareForUse() protected override void OnApply(FollowPointLifetimeEntry entry)
{ {
base.PrepareForUse(); base.OnApply(entry);
Entry.Invalidated += onEntryInvalidated;
entry.Invalidated += onEntryInvalidated;
refreshPoints(); refreshPoints();
} }
protected override void FreeAfterUse() protected override void OnFree(FollowPointLifetimeEntry entry)
{ {
base.FreeAfterUse(); base.OnFree(entry);
Entry.Invalidated -= onEntryInvalidated;
entry.Invalidated -= onEntryInvalidated;
// Return points to the pool. // Return points to the pool.
ClearInternal(false); ClearInternal(false);
Entry = null;
} }
private void onEntryInvalidated() => Scheduler.AddOnce(refreshPoints); private void onEntryInvalidated() => Scheduler.AddOnce(refreshPoints);
@ -48,8 +44,11 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
{ {
ClearInternal(false); ClearInternal(false);
OsuHitObject start = Entry.Start; var entry = Entry;
OsuHitObject end = Entry.End; if (entry?.End == null) return;
OsuHitObject start = entry.Start;
OsuHitObject end = entry.End;
double startTime = start.GetEndTime(); double startTime = start.GetEndTime();
@ -87,14 +86,13 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
fp.FadeIn(end.TimeFadeIn); fp.FadeIn(end.TimeFadeIn);
fp.ScaleTo(end.Scale, end.TimeFadeIn, Easing.Out); fp.ScaleTo(end.Scale, end.TimeFadeIn, Easing.Out);
fp.MoveTo(pointEndPosition, end.TimeFadeIn, Easing.Out); fp.MoveTo(pointEndPosition, end.TimeFadeIn, Easing.Out);
fp.Delay(fadeOutTime - fadeInTime).FadeOut(end.TimeFadeIn); fp.Delay(fadeOutTime - fadeInTime).FadeOut(end.TimeFadeIn).Expire();
finalTransformEndTime = fadeOutTime + end.TimeFadeIn; finalTransformEndTime = fp.LifetimeEnd;
} }
} }
// todo: use Expire() on FollowPoints and take lifetime from them when https://github.com/ppy/osu-framework/issues/3300 is fixed. entry.LifetimeEnd = finalTransformEndTime;
Entry.LifetimeEnd = finalTransformEndTime;
} }
/// <summary> /// <summary>

View File

@ -1,6 +1,8 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
#nullable enable
using System; using System;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Graphics.Performance; using osu.Framework.Graphics.Performance;
@ -11,7 +13,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
{ {
public class FollowPointLifetimeEntry : LifetimeEntry public class FollowPointLifetimeEntry : LifetimeEntry
{ {
public event Action Invalidated; public event Action? Invalidated;
public readonly OsuHitObject Start; public readonly OsuHitObject Start;
public FollowPointLifetimeEntry(OsuHitObject start) public FollowPointLifetimeEntry(OsuHitObject start)
@ -22,9 +24,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
bindEvents(); bindEvents();
} }
private OsuHitObject end; private OsuHitObject? end;
public OsuHitObject End public OsuHitObject? End
{ {
get => end; get => end;
set set
@ -56,11 +58,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
public void UnbindEvents() public void UnbindEvents()
{ {
if (Start != null) Start.DefaultsApplied -= onDefaultsApplied;
{ Start.PositionBindable.ValueChanged -= onPositionChanged;
Start.DefaultsApplied -= onDefaultsApplied;
Start.PositionBindable.ValueChanged -= onPositionChanged;
}
if (End != null) if (End != null)
{ {

View File

@ -6,43 +6,32 @@ using osu.Framework.Allocation;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Extensions; using osu.Framework.Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Performance;
using osu.Framework.Graphics.Pooling; using osu.Framework.Graphics.Pooling;
using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Pooling;
namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
{ {
/// <summary> /// <summary>
/// Visualises connections between <see cref="DrawableOsuHitObject"/>s. /// Visualises connections between <see cref="DrawableOsuHitObject"/>s.
/// </summary> /// </summary>
public class FollowPointRenderer : CompositeDrawable public class FollowPointRenderer : PooledDrawableWithLifetimeContainer<FollowPointLifetimeEntry, FollowPointConnection>
{ {
public override bool RemoveCompletedTransforms => false; public new IReadOnlyList<FollowPointLifetimeEntry> Entries => lifetimeEntries;
public IReadOnlyList<FollowPointLifetimeEntry> Entries => lifetimeEntries;
private DrawablePool<FollowPointConnection> connectionPool; private DrawablePool<FollowPointConnection> connectionPool;
private DrawablePool<FollowPoint> pointPool; private DrawablePool<FollowPoint> pointPool;
private readonly List<FollowPointLifetimeEntry> lifetimeEntries = new List<FollowPointLifetimeEntry>(); private readonly List<FollowPointLifetimeEntry> lifetimeEntries = new List<FollowPointLifetimeEntry>();
private readonly Dictionary<LifetimeEntry, FollowPointConnection> connectionsInUse = new Dictionary<LifetimeEntry, FollowPointConnection>();
private readonly Dictionary<HitObject, IBindable> startTimeMap = new Dictionary<HitObject, IBindable>(); private readonly Dictionary<HitObject, IBindable> startTimeMap = new Dictionary<HitObject, IBindable>();
private readonly LifetimeEntryManager lifetimeManager = new LifetimeEntryManager();
public FollowPointRenderer()
{
lifetimeManager.EntryBecameAlive += onEntryBecameAlive;
lifetimeManager.EntryBecameDead += onEntryBecameDead;
}
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load()
{ {
InternalChildren = new Drawable[] InternalChildren = new Drawable[]
{ {
connectionPool = new DrawablePoolNoLifetime<FollowPointConnection>(1, 200), connectionPool = new DrawablePool<FollowPointConnection>(1, 200),
pointPool = new DrawablePoolNoLifetime<FollowPoint>(50, 1000) pointPool = new DrawablePool<FollowPoint>(50, 1000)
}; };
} }
@ -107,7 +96,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
previousEntry.End = newEntry.Start; previousEntry.End = newEntry.Start;
} }
lifetimeManager.AddEntry(newEntry); Add(newEntry);
} }
private void removeEntry(OsuHitObject hitObject) private void removeEntry(OsuHitObject hitObject)
@ -118,7 +107,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
entry.UnbindEvents(); entry.UnbindEvents();
lifetimeEntries.RemoveAt(index); lifetimeEntries.RemoveAt(index);
lifetimeManager.RemoveEntry(entry); Remove(entry);
if (index > 0) if (index > 0)
{ {
@ -131,30 +120,12 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
} }
} }
protected override bool CheckChildrenLife() protected override FollowPointConnection GetDrawable(FollowPointLifetimeEntry entry)
{ {
bool anyAliveChanged = base.CheckChildrenLife(); var connection = connectionPool.Get();
anyAliveChanged |= lifetimeManager.Update(Time.Current); connection.Pool = pointPool;
return anyAliveChanged; connection.Apply(entry);
} return connection;
private void onEntryBecameAlive(LifetimeEntry entry)
{
var connection = connectionPool.Get(c =>
{
c.Entry = (FollowPointLifetimeEntry)entry;
c.Pool = pointPool;
});
connectionsInUse[entry] = connection;
AddInternal(connection);
}
private void onEntryBecameDead(LifetimeEntry entry)
{
RemoveInternal(connectionsInUse[entry]);
connectionsInUse.Remove(entry);
} }
private void onStartTimeChanged(OsuHitObject hitObject) private void onStartTimeChanged(OsuHitObject hitObject)
@ -171,16 +142,5 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
entry.UnbindEvents(); entry.UnbindEvents();
lifetimeEntries.Clear(); lifetimeEntries.Clear();
} }
private class DrawablePoolNoLifetime<T> : DrawablePool<T>
where T : PoolableDrawable, new()
{
public override bool RemoveWhenNotAlive => false;
public DrawablePoolNoLifetime(int initialSize, int? maximumSize = null)
: base(initialSize, maximumSize)
{
}
}
} }
} }