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;
}
}
}