Skip to content

Commit

Permalink
Merge pull request #512 from ExtendRealityLtd/feat/registered-consume…
Browse files Browse the repository at this point in the history
…r-container

feat(Tracking): add container for successful published consumers
  • Loading branch information
thestonefox authored Aug 13, 2020
2 parents 13f7956 + b8fd689 commit dccfe54
Show file tree
Hide file tree
Showing 18 changed files with 918 additions and 18 deletions.
21 changes: 16 additions & 5 deletions Runtime/Tracking/Collision/Active/ActiveCollisionConsumer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,10 @@ public class UnityEvent : UnityEvent<EventData> { }
/// The current active collision data from the broadcaster.
/// </summary>
public CollisionNotifier.EventData ActiveCollision { get; protected set; }
/// <summary>
/// The current highest level container of the consumer to allow for nested consumers.
/// </summary>
public GameObject ConsumerContainer { get; protected set; }

/// <summary>
/// Emitted when the publisher call has been consumed.
Expand All @@ -101,19 +105,22 @@ public class UnityEvent : UnityEvent<EventData> { }
/// <summary>
/// Consumes data from a from a <see cref="ActiveCollisionPublisher"/>.
/// </summary>
/// <param name="publisher">The publisher payload data.</param>
/// <param name="publisherPayload">The publisher payload data.</param>
/// <param name="currentCollision">The current collision within published data.</param>
/// <returns>Whether the consumption was allowed and successful.</returns>
[RequiresBehaviourState]
public virtual void Consume(ActiveCollisionPublisher.PayloadData publisher, CollisionNotifier.EventData currentCollision)
public virtual bool Consume(ActiveCollisionPublisher.PayloadData publisherPayload, CollisionNotifier.EventData currentCollision)
{
if (!PublisherValidity.Accepts(publisher.PublisherContainer))
if (!PublisherValidity.Accepts(publisherPayload.PublisherContainer))
{
return;
return false;
}

PublisherSource = publisher;
PublisherSource = publisherPayload;
ActiveCollision = currentCollision;
ConsumerContainer = currentCollision != null ? currentCollision.ColliderData.GetContainingTransform().TryGetGameObject() : null;
Consumed?.Invoke(eventData.Set(PublisherSource, currentCollision));
return true;
}

/// <summary>
Expand All @@ -122,6 +129,10 @@ public virtual void Consume(ActiveCollisionPublisher.PayloadData publisher, Coll
[RequiresBehaviourState]
public virtual void Clear()
{
if (PublisherSource != null && PublisherSource.Publisher != null)
{
PublisherSource.Publisher.UnregisterRegisteredConsumer(this);
}
Cleared?.Invoke(eventData.Set(PublisherSource, ActiveCollision));
PublisherSource = null;
ActiveCollision = null;
Expand Down
42 changes: 40 additions & 2 deletions Runtime/Tracking/Collision/Active/ActiveCollisionPublisher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,15 @@ public List<CollisionNotifier.EventData> ActiveCollisions
/// <summary>
/// The <see cref="GameObject"/> that this is residing on.
/// </summary>
/// <remarks>
/// This is a legacy reference as this can be obtained via <see cref="Publisher.gameObject"/>.
/// </remarks>
public GameObject PublisherContainer { get; set; }

/// <summary>
/// The <see cref="ActiveCollisionPublisher"/> that is doing the publishing.
/// </summary>
public ActiveCollisionPublisher Publisher { get; set; }
}

/// <summary>
Expand All @@ -55,9 +63,15 @@ public class UnityEvent : UnityEvent<PayloadData> { }
[Serialized, Cleared]
[field: DocumentedByXml]
public PayloadData Payload { get; set; } = new PayloadData();
/// <summary>
/// A collection of <see cref="ActiveCollisionConsumer"/> components that has been successfully published to.
/// </summary>
[Serialized, Cleared]
[field: DocumentedByXml]
public ActiveCollisionRegisteredConsumerContainer RegisteredConsumerContainer { get; set; }

/// <summary>
/// Emitted the collision data is published.
/// Emitted when the payload data is published.
/// </summary>
[DocumentedByXml]
public UnityEvent Published = new UnityEvent();
Expand Down Expand Up @@ -135,22 +149,46 @@ public virtual void Publish()
public virtual void ForcePublish()
{
Payload.PublisherContainer = gameObject;
Payload.Publisher = this;
activeCollisions.Clear();
activeCollisions.AddRange(Payload.ActiveCollisions);
if (RegisteredConsumerContainer != null)
{
RegisteredConsumerContainer.ClearIgnoredRegisteredConsumers();
}

foreach (CollisionNotifier.EventData currentCollision in activeCollisions)
{
Transform reference = currentCollision.ColliderData.GetContainingTransform();
foreach (ActiveCollisionConsumer consumer in GetConsumers(reference))
{
if (consumer.Container == null || consumer.Container == reference.gameObject)
{
consumer.Consume(Payload, currentCollision);
if (consumer.Consume(Payload, currentCollision) && RegisteredConsumerContainer != null)
{
RegisteredConsumerContainer.IgnoredRegisteredConsumers.Add(consumer);
RegisteredConsumerContainer.Register(consumer, Payload);
}
}
}
}
Published?.Invoke(Payload);
}

/// <summary>
/// Unregisters a registered <see cref="ActiveCollisionConsumer"/> from this <see cref="ActiveCollisionPublisher"/>.
/// </summary>
/// <param name="consumer">The consumer being unregistered.</param>
public virtual void UnregisterRegisteredConsumer(ActiveCollisionConsumer consumer)
{
if (RegisteredConsumerContainer == null)
{
return;
}

RegisteredConsumerContainer.Unregister(consumer);
}

/// <summary>
/// Gets a valid <see cref="ActiveCollisionConsumer"/> collection.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
namespace Zinnia.Tracking.Collision.Active
{
using Malimbe.BehaviourStateRequirementMethod;
using Malimbe.MemberClearanceMethod;
using Malimbe.PropertySerializationAttribute;
using Malimbe.XmlDocumentationAttribute;
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;

/// <summary>
/// Holds a <see cref="ActiveCollisionConsumer"/> collection of consumers that have successfully been published to by a <see cref="ActiveCollisionPublisher"/>.
/// </summary>
public class ActiveCollisionRegisteredConsumerContainer : MonoBehaviour
{
/// <summary>
/// Holds data about a <see cref="ActiveCollisionRegisteredConsumerContainer"/> payload.
/// </summary>
[Serializable]
public class EventData
{
/// <summary>
/// The registered <see cref="ActiveCollisionConsumer"/>.
/// </summary>
[Serialized, Cleared]
[field: DocumentedByXml]
public ActiveCollisionConsumer Consumer { get; set; }

/// <summary>
/// The payload data sent to the <see cref="ActiveCollisionConsumer"/>.
/// </summary>
[Serialized, Cleared]
[field: DocumentedByXml]
public ActiveCollisionPublisher.PayloadData Payload { get; set; }

public EventData Set(EventData source)
{
return Set(source.Consumer, source.Payload);
}

public EventData Set(ActiveCollisionConsumer consumer, ActiveCollisionPublisher.PayloadData payload)
{
Consumer = consumer;
Payload = payload;
return this;
}

public void Clear()
{
Set(default, default);
}
}

/// <summary>
/// Defines the event for the output <see cref="EventData"/>.
/// </summary>
[Serializable]
public class UnityEvent : UnityEvent<EventData> { }

/// <summary>
/// Emitted when each registered consumer payload data is published.
/// </summary>
[DocumentedByXml]
public ActiveCollisionPublisher.UnityEvent Published = new ActiveCollisionPublisher.UnityEvent();
/// <summary>
/// Emitted when a consumer is registered.
/// </summary>
[DocumentedByXml]
public UnityEvent Registered = new UnityEvent();
/// <summary>
/// Emitted when a consumer is unregistered.
/// </summary>
[DocumentedByXml]
public UnityEvent Unregistered = new UnityEvent();

/// <summary>
/// A collection of registered consumers to ignore when publishing.
/// </summary>
public List<ActiveCollisionConsumer> IgnoredRegisteredConsumers { get; set; } = new List<ActiveCollisionConsumer>();
/// <summary>
/// The consumers that have successfully consumed the published payload from the <see cref="ActiveCollisionPublisher"/> linked to this.
/// </summary>
public Dictionary<ActiveCollisionConsumer, ActiveCollisionPublisher.PayloadData> RegisteredConsumers { get; protected set; } = new Dictionary<ActiveCollisionConsumer, ActiveCollisionPublisher.PayloadData>();

/// <summary>
/// The event data emitted when collisions are consumed.
/// </summary>
protected readonly EventData eventData = new EventData();

/// <summary>
/// Publishes the registered <see cref="ActiveCollisionConsumer"/> components as the component is active and enabled.
/// Any <see cref="ActiveCollisionConsumer"/> that is in the <see cref="IgnoredRegisteredConsumers"/> will not be published to and the <see cref="IgnoredRegisteredConsumers"/> collection is cleared at the end of the <see cref="Publish"/> operation.
/// </summary>
[RequiresBehaviourState]
public virtual void Publish()
{
foreach (ActiveCollisionConsumer registeredConsumer in new List<ActiveCollisionConsumer>(RegisteredConsumers.Keys))
{
if (IgnoredRegisteredConsumers.Contains(registeredConsumer))
{
continue;
}

if (RegisteredConsumers.TryGetValue(registeredConsumer, out ActiveCollisionPublisher.PayloadData payload))
{
registeredConsumer.Consume(payload, registeredConsumer.ActiveCollision);
Published?.Invoke(payload);
}
}

ClearIgnoredRegisteredConsumers();
}

/// <summary>
/// Registers an <see cref="ActiveCollisionConsumer"/>.
/// </summary>
/// <param name="consumer">The consumer to register.</param>
/// <param name="payload">The payload that the consumer successfully consumed.</param>
[RequiresBehaviourState]
public virtual void Register(ActiveCollisionConsumer consumer, ActiveCollisionPublisher.PayloadData payload)
{
if (consumer == null)
{
return;
}

RegisteredConsumers[consumer] = payload;
Registered?.Invoke(eventData.Set(consumer, payload));
}

/// <summary>
/// Unregisters an <see cref="ActiveCollisionConsumer"/>.
/// </summary>
/// <param name="consumer">The consumer to unregister.</param>
public virtual void Unregister(ActiveCollisionConsumer consumer)
{
if (consumer == null)
{
return;
}

RegisteredConsumers.Remove(consumer);
IgnoredRegisteredConsumers.Remove(consumer);
Unregistered?.Invoke(eventData.Set(consumer, null));
}

/// <summary>
/// Unregisters all <see cref="ActiveCollisionConsumer"/> components that exist on the given container.
/// </summary>
/// <param name="container">The container to unregister the consumers from.</param>
public virtual void UnregisterConsumersOnContainer(GameObject container)
{
foreach (ActiveCollisionConsumer registeredConsumer in new List<ActiveCollisionConsumer>(RegisteredConsumers.Keys))
{
if (registeredConsumer.ConsumerContainer == container)
{
Unregister(registeredConsumer);
}
}
}

/// <summary>
/// Clears the <see cref="IgnoredRegisteredConsumers"/> collection.
/// </summary>
public virtual void ClearIgnoredRegisteredConsumers()
{
IgnoredRegisteredConsumers.Clear();
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
namespace Zinnia.Tracking.Collision.Active.Event.Proxy
{
using System;
using UnityEngine.Events;
using Zinnia.Event.Proxy;
using Zinnia.Tracking.Collision.Active;

/// <summary>
/// Emits a UnityEvent with a <see cref="ActiveCollisionPublisher.PayloadData"/> payload whenever the Receive method is called.
/// </summary>
public class ActiveCollisionPublisherEventProxyEmitter : SingleEventProxyEmitter<ActiveCollisionPublisher.PayloadData, ActiveCollisionPublisherEventProxyEmitter.UnityEvent>
{
/// <summary>
/// Defines the event with the specified state.
/// </summary>
[Serializable]
public class UnityEvent : UnityEvent<ActiveCollisionPublisher.PayloadData> { }
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
namespace Zinnia.Tracking.Collision.Active.Event.Proxy
{
using System;
using UnityEngine.Events;
using Zinnia.Event.Proxy;
using Zinnia.Tracking.Collision.Active;

/// <summary>
/// Emits a UnityEvent with a <see cref="ActiveCollisionRegisteredConsumerContainer.EventData"/> payload whenever the Receive method is called.
/// </summary>
public class ActiveCollisionRegisteredConsumerContainerEventProxyEmitter : SingleEventProxyEmitter<ActiveCollisionRegisteredConsumerContainer.EventData, ActiveCollisionRegisteredConsumerContainerEventProxyEmitter.UnityEvent>
{
/// <summary>
/// Defines the event with the specified state.
/// </summary>
[Serializable]
public class UnityEvent : UnityEvent<ActiveCollisionRegisteredConsumerContainer.EventData> { }
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit dccfe54

Please sign in to comment.