namespace Zinnia.Tracking.Collision.Active { using System; using System.Collections.Generic; using UnityEngine; using UnityEngine.Events; using Zinnia.Extension; /// /// Publishes itself to all components found within the current collection. /// public class ActiveCollisionPublisher : MonoBehaviour { /// /// Holds data about a payload. /// [Serializable] public class PayloadData { [Tooltip("The container of the source that is initiating the collision.")] [SerializeField] private GameObject sourceContainer; /// /// The container of the source that is initiating the collision. /// public GameObject SourceContainer { get { return sourceContainer; } set { sourceContainer = value; } } /// /// The active collisions. /// public List ActiveCollisions { get; protected set; } = new List(); /// /// The that this is residing on. /// /// /// This is a legacy reference as this can be obtained via . /// public GameObject PublisherContainer { get; set; } /// /// The that is doing the publishing. /// public ActiveCollisionPublisher Publisher { get; set; } /// /// Clears . /// public virtual void ClearSourceContainer() { SourceContainer = default; } /// public override string ToString() { string[] titles = new string[] { "SourceContainer", "PublisherContainer" }; object[] values = new object[] { SourceContainer, PublisherContainer }; return StringExtensions.FormatForToString(titles, values); } } /// /// Defines the event for the output . /// [Serializable] public class UnityEvent : UnityEvent { } [Tooltip("The data to publish to any available consumers.")] [SerializeField] private PayloadData payload = new PayloadData(); /// /// The data to publish to any available consumers. /// public PayloadData Payload { get { return payload; } set { payload = value; } } [Tooltip("A collection of ActiveCollisionConsumer components that has been successfully published to.")] [SerializeField] private ActiveCollisionRegisteredConsumerContainer registeredConsumerContainer; /// /// A collection of components that has been successfully published to. /// public ActiveCollisionRegisteredConsumerContainer RegisteredConsumerContainer { get { return registeredConsumerContainer; } set { registeredConsumerContainer = value; } } /// /// Emitted when the payload data is published. /// public UnityEvent Published = new UnityEvent(); /// /// A reused instance to use when looking up components. /// protected readonly List activeCollisionConsumers = new List(); /// /// A reused instance to use when looking up the Active Collisions in a Payload. /// protected List activeCollisions = new List(); /// /// Clears . /// public virtual void ClearPayload() { if (!this.IsValidState()) { return; } Payload = default; } /// /// Clears . /// public virtual void ClearRegisteredConsumerContainer() { if (!this.IsValidState()) { return; } RegisteredConsumerContainer = default; } /// /// Sets the active collisions by copying it from given . /// /// The data to copy from. public virtual void SetActiveCollisions(ActiveCollisionsContainer.EventData data) { if (!this.IsValidState() || data == null || data.ActiveCollisions == null) { return; } Payload.ActiveCollisions.Clear(); Payload.ActiveCollisions.AddRange(data.ActiveCollisions); } /// /// Sets the active collision data by copying it from given as long as the component is active and enabled. /// /// The data to copy from. public virtual void SetActiveCollisions(PayloadData payload) { if (!this.IsValidState()) { return; } SetActiveCollisionsEvenWhenDisabled(payload); } /// /// Sets the active collision data by copying it from given even if the component is disabled. /// /// The data to copy from. public virtual void SetActiveCollisionsEvenWhenDisabled(PayloadData payload) { if (payload == null) { return; } Payload.ActiveCollisions.Clear(); Payload.ActiveCollisions.AddRange(payload.ActiveCollisions); } /// /// Clears the existing active collision data. /// public virtual void ClearActiveCollisions() { Payload.ActiveCollisions.Clear(); } /// /// Publishes itself and the current collision to all components found on any of the active collisions as long as the component is active and enabled. /// public virtual void Publish() { if (!this.IsValidState()) { return; } ForcePublish(); } /// /// Publishes itself and the current collision to all components found on any of the active collisions as long as the component. /// 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) { if (consumer.Consume(Payload, currentCollision) && RegisteredConsumerContainer != null) { RegisteredConsumerContainer.IgnoredRegisteredConsumers.Add(consumer); RegisteredConsumerContainer.Register(consumer, Payload); } } } } Published?.Invoke(Payload); } /// /// Unregisters a registered from this . /// /// The consumer being unregistered. public virtual void UnregisterRegisteredConsumer(ActiveCollisionConsumer consumer) { if (RegisteredConsumerContainer == null) { return; } RegisteredConsumerContainer.Unregister(consumer); } /// /// Gets a valid collection. /// /// The reference to start searching for components in. /// The obtained collection. protected virtual List GetConsumers(Transform reference) { if (reference == null || transform.IsChildOf(reference)) { activeCollisionConsumers.Clear(); } else { reference.GetComponentsInChildren(activeCollisionConsumers); } return activeCollisionConsumers; } } }