Skip to content

Commit

Permalink
feat: adding more ComputeContext APIs (#350)
Browse files Browse the repository at this point in the history
  • Loading branch information
bdunderscore authored Aug 26, 2024
1 parent 2dcca76 commit baa238c
Show file tree
Hide file tree
Showing 12 changed files with 251 additions and 65 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]

### Added
- [#350] Added additional ComputeContext-related APIs.
- `ComputeContext.Invalidate`, the `ComputeContext(string)` constructor, `ComputeContext.Invalidates`, and
`ComputeContext.InvokeOnInvalidate` are now public.
- Added the `GetAvatarRoots(this ComputeContext)` and `GetAvatarRoot(this ComputeContext, GameObject)` extension methods.

### Fixed

Expand Down
93 changes: 73 additions & 20 deletions Editor/ChangeStream/ListenerSet.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,41 +13,63 @@ internal class Listener<T> : IDisposable
{
internal Listener<T> _next, _prev;

private readonly ListenerSet<T> _owner;
private readonly ListenerSet<T>.Filter _filter;
private readonly WeakReference<ComputeContext> _ctx;
private readonly WeakReference<object> _target;
private readonly Action<object> _receiver;

internal Listener(
ListenerSet<T> owner,
ListenerSet<T>.Filter filter,
ComputeContext ctx
) : this(owner, filter, ctx, InvalidateContext)
{
}

private static void InvalidateContext(object ctx)
{
((ComputeContext) ctx).Invalidate();
}

internal Listener(
ListenerSet<T> owner,
ListenerSet<T>.Filter filter,
object target,
Action<object> receiver
)
{
_owner = owner;
_next = _prev = this;
_filter = filter;
_ctx = ctx == null ? null : new WeakReference<ComputeContext>(ctx);
_target = new WeakReference<object>(target);
_receiver = receiver;
}

public override string ToString()
{
if (_ctx.TryGetTarget(out var target))
if (_target.TryGetTarget(out var target))
return $"Listener for {target}";
return "Listener (GC'd)";
}

public void Dispose()
{
if (_next != null)
lock (_owner)
{
_next._prev = _prev;
_prev._next = _next;
if (_next != null)
{
_next._prev = _prev;
_prev._next = _next;
}

_next = _prev = null;
_target.SetTarget(null);
}

_next = _prev = null;
_ctx.SetTarget(null);
}

internal void MaybePrune()
{
if (!_ctx.TryGetTarget(out var ctx) || ctx.IsInvalidated)
if (!_target.TryGetTarget(out _))
{
#if NDMF_DEBUG
System.Diagnostics.Debug.WriteLine($"{this} is invalid, disposing");
Expand All @@ -59,7 +81,7 @@ internal void MaybePrune()
// Invoked under lock(_owner)
internal void MaybeFire(T info)
{
if (!_ctx.TryGetTarget(out var ctx) || ctx.IsInvalidated)
if (!_target.TryGetTarget(out var target))
{
#if NDMF_DEBUG
System.Diagnostics.Debug.WriteLine($"{this} is invalid, disposing");
Expand All @@ -71,8 +93,8 @@ internal void MaybeFire(T info)
#if NDMF_DEBUG
System.Diagnostics.Debug.WriteLine($"{this} is firing");
#endif
ctx.Invalidate();

_receiver(target);
// We need to wait two frames before repainting: One to process task callbacks, then one to actually
// repaint (and update previews).
EditorApplication.delayCall += Delay2Repaint;
Expand All @@ -87,7 +109,8 @@ private void Delay2Repaint()

public void ForceFire()
{
if (_ctx.TryGetTarget(out var ctx) && !ctx.IsInvalidated) ctx.Invalidate();
if (_target.TryGetTarget(out var ctx)) _receiver(ctx);
_target.SetTarget(null);
}
}

Expand All @@ -99,7 +122,7 @@ internal class ListenerSet<T>

public ListenerSet()
{
_head = new Listener<T>(_ => false, null);
_head = new Listener<T>(this, _ => false, null);
_head._next = _head._prev = _head;
}

Expand All @@ -110,15 +133,45 @@ public bool HasListeners()

public IDisposable Register(Filter filter, ComputeContext ctx)
{
var listener = new Listener<T>(filter, ctx);
var listener = new Listener<T>(this, filter, ctx);

listener._next = _head._next;
listener._prev = _head;
_head._next._prev = listener;
_head._next = listener;
lock (this)
{
listener._next = _head._next;
listener._prev = _head;
_head._next._prev = listener;
_head._next = listener;
}

return listener;
}

public IDisposable Register(Filter filter, object target, Action<object> receiver)
{
var listener = new Listener<T>(this, filter, target, receiver);

lock (this)
{
listener._next = _head._next;
listener._prev = _head;
_head._next._prev = listener;
_head._next = listener;
}

return listener;
}

public IDisposable Register(ComputeContext ctx)
{
return Register(PassAll, ctx);
}

public IDisposable Register(object target, Action<object> receiver)
{
return Register(PassAll, target, receiver);
}

private static bool PassAll(T _) => true;

public void Fire(T info)
{
Expand Down
28 changes: 14 additions & 14 deletions Editor/ChangeStream/ShadowGameObject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ void DumpListenerSet<T>(ListenerSet<T> set)

internal IDisposable RegisterRootSetListener(ListenerSet<HierarchyEvent>.Filter filter, ComputeContext ctx)
{
#if NDMF_DEBUG
#if NDMF_TRACE
Debug.WriteLine("[ShadowHierarchy] RegisterRootSetListener()");
#endif

Expand All @@ -161,7 +161,7 @@ internal IDisposable RegisterGameObjectListener(
ComputeContext ctx
)
{
#if NDMF_DEBUG
#if NDMF_TRACE
Debug.WriteLine($"[ShadowHierarchy] RegisterGameObjectListener({targetObject.GetInstanceID()})");
#endif

Expand All @@ -177,7 +177,7 @@ internal IDisposable RegisterObjectListener(UnityObject targetComponent,
ComputeContext ctx
)
{
#if NDMF_DEBUG
#if NDMF_TRACE
Debug.WriteLine($"[ShadowHierarchy] RegisterObjectListener({targetComponent.GetInstanceID()})");
#endif

Expand Down Expand Up @@ -207,7 +207,7 @@ public void Dispose()
/// <param name="root"></param>
internal void EnableComponentMonitoring(GameObject root)
{
#if NDMF_DEBUG
#if NDMF_TRACE
Debug.WriteLine($"[ShadowHierarchy] EnableComponentMonitoring({root.GetInstanceID()})");
#endif

Expand All @@ -231,7 +231,7 @@ private void EnableComponentMonitoring(ShadowGameObject obj)

internal void EnablePathMonitoring(GameObject root)
{
#if NDMF_DEBUG
#if NDMF_TRACE
Debug.WriteLine($"[ShadowHierarchy] EnablePathMonitoring({root.GetInstanceID()})");
#endif

Expand Down Expand Up @@ -285,7 +285,7 @@ private ShadowGameObject ActivateShadowObject(GameObject targetObject)
/// <param name="instanceId"></param>
internal void FireObjectChangeNotification(int instanceId)
{
#if NDMF_DEBUG
#if NDMF_TRACE
Debug.WriteLine($"[ShadowHierarchy] FireObjectChangeNotification({instanceId})");
#endif

Expand Down Expand Up @@ -320,7 +320,7 @@ internal void FireObjectChangeNotification(int instanceId)
/// <param name="instanceId"></param>
internal void FireReparentNotification(int instanceId)
{
#if NDMF_DEBUG
#if NDMF_TRACE
Debug.WriteLine($"[ShadowHierarchy] FireReparentNotification({instanceId})");
#endif

Expand Down Expand Up @@ -397,7 +397,7 @@ private void FireParentComponentChangeNotifications(ShadowGameObject obj)

internal void FireDestroyNotification(int instanceId)
{
#if NDMF_DEBUG
#if NDMF_TRACE
Debug.WriteLine($"[ShadowHierarchy] FireDestroyNotification({instanceId})");
#endif

Expand All @@ -410,7 +410,7 @@ internal void FireDestroyNotification(int instanceId)

void ForceInvalidateHierarchy(ShadowGameObject obj)
{
#if NDMF_DEBUG
#if NDMF_TRACE
var resolvedName = obj.GameObject == null ? "<null>" : obj.GameObject.name;
Debug.WriteLine($"[ShadowHierarchy] ForceInvalidateHierarchy({obj.InstanceID}:{resolvedName})");
#endif
Expand All @@ -426,7 +426,7 @@ void ForceInvalidateHierarchy(ShadowGameObject obj)

internal void FireReorderNotification(int parentInstanceId)
{
#if NDMF_DEBUG
#if NDMF_TRACE
Debug.WriteLine($"[ShadowHierarchy] FireReorderNotification({parentInstanceId})");
#endif

Expand All @@ -440,7 +440,7 @@ internal void FireReorderNotification(int parentInstanceId)

internal void FireStructureChangeEvent(int instanceId)
{
#if NDMF_DEBUG
#if NDMF_TRACE
Debug.WriteLine($"[ShadowHierarchy] FireStructureChangeEvent({instanceId})");
#endif

Expand All @@ -455,7 +455,7 @@ internal void FireStructureChangeEvent(int instanceId)

internal void InvalidateAll()
{
#if NDMF_DEBUG
#if NDMF_TRACE
Debug.WriteLine("[ShadowHierarchy] InvalidateAll()");
#endif

Expand Down Expand Up @@ -486,7 +486,7 @@ internal void InvalidateAll()
/// <exception cref="NotImplementedException"></exception>
public void InvalidateTree(int instanceId)
{
#if NDMF_DEBUG
#if NDMF_TRACE
Debug.WriteLine($"[ShadowHierarchy] InvalidateTree({instanceId})");
#endif

Expand Down Expand Up @@ -524,7 +524,7 @@ public void InvalidateTree(int instanceId)

public void FireGameObjectCreate(int instanceId)
{
#if NDMF_DEBUG
#if NDMF_TRACE
Debug.WriteLine($"[ShadowHierarchy] FireGameObjectCreate({instanceId})");
#endif

Expand Down
Loading

0 comments on commit baa238c

Please sign in to comment.