// Copyright (c) 2015 - 2023 Doozy Entertainment. All Rights Reserved.
// This code can only be used under the standard Unity Asset Store End User License Agreement
// A Copy of the EULA APPENDIX 1 is available at http://unity3d.com/company/legal/as_terms
using System;
using UnityEngine;
using Object = UnityEngine.Object;
// ReSharper disable UnusedAutoPropertyAccessor.Global
// ReSharper disable MemberCanBePrivate.Global
namespace Doozy.Runtime.Signals
{
///
/// Object, used by the Signals system, that is sent from SignalProviders to SignalReceivers
///
public partial class Signal
{
/// The stream this Signal was sent through
public SignalStream stream { get; protected internal set; }
/// Reference to the signal provider that sent this Signal
public SignalProvider signalProvider { get; protected internal set; }
/// Signal provider type
public Type providerType { get; protected internal set; }
/// Returns TRUE if this Signal was sent by a signal provider
public bool hasProvider => signalProvider != null;
/// Reference to the Object that sent this this Signal
public Object signalSenderObject { get; protected internal set; }
/// Sender type
public Type senderType { get; protected internal set; }
/// Returns TRUE if this Signal has a reference to its sender
public bool hasSenderObject => signalSenderObject != null;
/// Source GameObject from where this Signal originates from (can be null)
public GameObject sourceGameObject { get; protected internal set; }
/// Returns TRUE if this Signal has a source gameObject
public bool hasSourceGameObject => sourceGameObject != null;
/// Returns TRUE if this is a MetaSignal (has value)
public bool hasValue { get; protected internal set; }
/// Signal value type (if MetaSignal)
public Type valueType { get; protected internal set; }
/// Signal value boxed as an object (used by MetaSignal)
public object valueAsObject { get; protected internal set; }
/// Was the signal used
public bool used { get; protected internal set; }
/// Timestamp for the signal
public float timestamp { get; protected internal set; }
/// Text message used to pass info about this Signal
public string message { get; protected internal set; }
public Signal()
{
stream = null;
signalProvider = null;
providerType = null;
signalSenderObject = null;
senderType = null;
sourceGameObject = null;
hasValue = false;
valueType = null;
valueAsObject = null;
used = false;
timestamp = Time.time;
message = string.Empty;
}
/// Create a Signal
/// Reference to the SignalStream this Signal is sent through
/// Indicator if a Signal has a value payload (FALSE for Signal and TRUE for MetaSignal)
/// Type of the value (if the Signal has one) - used by MetaSignals
internal Signal(SignalStream stream, bool hasValue = false, Type valueType = default) : this(stream, null, null, null, hasValue, valueType) {}
/// Create a Signal and set a reference to the GameObject from where it is sent
/// Reference to the SignalStream this Signal is sent through
/// Reference to the GameObject from where this Signal is sent
/// Indicator if a Signal has a value payload (FALSE for Signal and TRUE for MetaSignal)
/// Type of the value (if the Signal has one) - used by MetaSignals
internal Signal(SignalStream stream, GameObject signalSource, bool hasValue = false, Type valueType = default) : this(stream, signalSource, null, null, hasValue, valueType) {}
/// Create a Signal and set a reference to the SignalProvider that sends it
/// Reference to the SignalStream this Signal is sent through
/// Reference to the SignalProvider that sends this Signal
/// Indicator if a Signal has a value payload (FALSE for Signal and TRUE for MetaSignal)
/// Type of the value (if the Signal has one) - used by MetaSignals
internal Signal(SignalStream stream, SignalProvider signalProvider, bool hasValue = false, Type valueType = default) : this(stream, null, signalProvider, null, hasValue, valueType) {}
/// Create a Signal and set a reference to the Object that sends it
/// Reference to the SignalStream this Signal is sent through
/// Reference to the Object that sends this Signal
/// Indicator if a Signal has a value payload (FALSE for Signal and TRUE for MetaSignal)
/// Type of the value (if the Signal has one) - used by MetaSignals
internal Signal(SignalStream stream, Object senderObject, bool hasValue = false, Type valueType = default) : this(stream, null, null, senderObject, hasValue, valueType) {}
internal Signal(SignalStream stream, GameObject signalSource, SignalProvider signalProvider, Object signalSender, bool hasValue = false, Type valueType = default)
{
this
.Reset()
.SetStream(stream)
.SetValueType(hasValue, valueType);
if (signalProvider != null)
{
this.SetSignalSource(signalProvider.gameObject);
this.SetSignalProvider(signalProvider);
this.SetSignalSender(signalProvider);
}
if (signalSource != null) this.SetSignalSource(signalSource);
if (signalSender != null) this.SetSignalSender(signalSender);
}
internal void Recycle() =>
this.AddToPool();
/// Mark this signal as used
public void Use() =>
used = true;
/// Try to get the signal value (if this signal is a MetaSignal)
/// Signal value
/// Signal value type
public bool TryGetValue(out T value)
{
if (hasValue)
{
try
{
value = ((MetaSignal)this).value;
return true;
}
catch
{
// ignored
}
}
value = default;
return false;
}
///
/// Get the signal value via a direct cast. Use TryGetValue as a safe option (to perform the operation in a try catch block).
/// This is an unsafe method, so use with care.
///
/// Value type
public T GetValueUnsafe() =>
((MetaSignal)this).value;
/// Try to get the signal value type (if this signal is a MetaSignal)
/// Signal value type
public bool TryGetValueType(out Type type)
{
if (hasValue)
{
type = valueType;
return true;
}
type = default;
return false;
}
#region Static Methods
#region Send Signal - using a stream Category and Name
/// Send a Signal on the stream with the given stream category and name
/// Target stream category
/// Target stream name
/// Text message used to pass info about this Signal
public static bool Send(string streamCategory, string streamName, string message = "") =>
SignalsService.SendSignal(streamCategory, streamName, message);
/// Send a Signal on the stream with the given stream category and name, with a reference to the GameObject from where it is sent
/// Target stream category
/// Target stream name
/// Reference to the GameObject from where this Signal is sent
/// Text message used to pass info about this Signal
public static bool Send(string streamCategory, string streamName, GameObject signalSource, string message = "") =>
SignalsService.SendSignal(streamCategory, streamName, signalSource, message);
/// Send a Signal on the stream with the given stream category and name, with a reference to the SignalProvider that sent it
/// Target stream category
/// Target stream name
/// Reference to the SignalProvider that sends this Signal
/// Text message used to pass info about this Signal
public static bool Send(string streamCategory, string streamName, SignalProvider signalProvider, string message = "") =>
SignalsService.SendSignal(streamCategory, streamName, signalProvider, message);
/// Send a Signal on the stream with the given stream category and name, with a reference to the Object that sent it
/// Target stream category
/// Target stream name
/// Reference to the Object that sends this Signal
/// Text message used to pass info about this Signal
public static bool Send(string streamCategory, string streamName, Object signalSender, string message = "") =>
SignalsService.SendSignal(streamCategory, streamName, signalSender, message);
#endregion
#region Send Signal - using a Guid streamKey
/// Send a Signal on the stream with the given stream key (Guid)
/// Target stream key (Guid)
/// Text message used to pass info about this Signal
public static bool Send(Guid streamKey, string message = "") =>
SignalsService.SendSignal(streamKey, message);
/// Send a Signal on the stream with the given stream key (Guid), with a reference to the GameObject from where it was sent
/// Target stream key (Guid)
/// Reference to the GameObject from where this Signal is sent from
/// Text message used to pass info about this Signal
public static bool Send(Guid streamKey, GameObject signalSource, string message = "") =>
SignalsService.SendSignal(streamKey, signalSource, message);
/// Send a Signal on the stream with the given stream key (Guid), with a reference to the SignalProvider that sent it
/// Target stream key (Guid)
/// Reference to the SignalProvider that sends this Signal
/// Text message used to pass info about this Signal
public static bool Send(Guid streamKey, SignalProvider signalProvider, string message = "") =>
SignalsService.SendSignal(streamKey, signalProvider, message);
/// Send a Signal on the stream with the given stream key (Guid), with a reference to the Object that sent it
/// Target stream key (Guid)
/// Reference to the Object that sends this Signal
/// Text message used to pass info about this Signal
public static bool Send(Guid streamKey, Object signalSender, string message = "") =>
SignalsService.SendSignal(streamKey, signalSender, message);
#endregion
#region Send Signal - using a SignalStream reference
/// Send a Signal on the given stream
/// Target signal stream
/// Text message used to pass info about this Signal
public static bool Send(SignalStream stream, string message = "") =>
SignalsService.SendSignal(stream, message);
/// Send a Signal on the given stream, with a reference to the GameObject from where it was sent
/// Target signal stream
/// Reference to the GameObject from where this Signal is sent from
/// Text message used to pass info about this Signal
public static bool Send(SignalStream stream, GameObject signalSource, string message = "") =>
SignalsService.SendSignal(stream, signalSource, message);
/// Send a Signal on the given stream, with a reference to the SignalProvider that sent it
/// Target signal stream
/// Reference to the SignalProvider that sends this Signal
/// Text message used to pass info about this Signal
public static bool Send(SignalStream stream, SignalProvider signalProvider, string message = "") =>
SignalsService.SendSignal(stream, signalProvider, message);
/// Send a Signal on the given stream, with a reference to the Object that sent it
/// Target signal stream
/// Reference to the Object that sends this Signal
/// Text message used to pass info about this Signal
public static bool Send(SignalStream stream, Object signalSender, string message = "") =>
SignalsService.SendSignal(stream, signalSender, message);
#endregion
#region Send MetaSignal - using a stream Category and Name
/// Send a MetaSignal on the stream with the given stream category and name
/// Target stream category
/// Target stream name
/// Signal value
/// Text message used to pass info about this Signal
public static bool Send(string streamCategory, string streamName, T signalValue, string message = "") =>
SignalsService.SendSignal(streamCategory, streamName, signalValue, message);
/// Send a MetaSignal on the stream with the given stream category and name, with a reference to the GameObject from where it is sent
/// Target stream category
/// Target stream name
/// Signal value
/// Reference to the GameObject from where this Signal is sent
/// Text message used to pass info about this Signal
/// Signal value type
public static bool Send(string streamCategory, string streamName, T signalValue, GameObject signalSource, string message = "") =>
SignalsService.SendSignal(streamCategory, streamName, signalValue, signalSource, message);
/// Send a MetaSignal on the stream with the given stream category and name, with a reference to the SignalProvider that sent it
/// Target stream category
/// Target stream name
/// Signal value
/// Reference to the SignalProvider that sends this Signal
/// Text message used to pass info about this Signal
/// Signal value type
public static bool Send(string streamCategory, string streamName, T signalValue, SignalProvider signalProvider, string message = "") =>
SignalsService.SendSignal(streamCategory, streamName, signalValue, signalProvider, message);
/// Send a MetaSignal on the stream with the given stream category and name, with a reference to the Object that sent it
/// Target stream category
/// Target stream name
/// Signal value
/// Reference to the Object that sends this Signal
/// Text message used to pass info about this Signal
/// Signal value type
public static bool Send(string streamCategory, string streamName, T signalValue, Object signalSender, string message = "") =>
SignalsService.SendSignal(streamCategory, streamName, signalValue, signalSender, message);
#endregion
#region Send MetaSignal - using a Guid streamKey
/// Send a MetaSignal on the stream with the given stream key (Guid)
/// Target stream key (Guid)
/// Signal value
/// Text message used to pass info about this Signal
/// Signal value type
public static bool Send(Guid streamKey, T signalValue, string message = "") =>
SignalsService.SendSignal(streamKey, signalValue, message);
/// Send a MetaSignal on the stream with the given stream key (Guid), with a reference to the GameObject from where it was sent
/// Target stream key (Guid)
/// Signal value
/// Reference to the GameObject from where this Signal is sent from
/// Text message used to pass info about this Signal
/// Signal value type
public static bool Send(Guid streamKey, T signalValue, GameObject signalSource, string message = "") =>
SignalsService.SendSignal(streamKey, signalValue, signalSource, message);
/// Send a MetaSignal on the stream with the given stream key (Guid), with a reference to the SignalProvider that sent it
/// Target stream key (Guid)
/// Signal value
/// Reference to the SignalProvider that sends this Signal
/// Text message used to pass info about this Signal
/// Signal value type
public static bool Send(Guid streamKey, T signalValue, SignalProvider signalProvider, string message = "") =>
SignalsService.SendSignal(streamKey, signalValue, signalProvider, message);
/// Send a MetaSignal on the stream with the given stream key (Guid), with a reference to the Object that sent it
/// Target stream key (Guid)
/// Signal value
/// Reference to the Object that sends this Signal
/// Text message used to pass info about this Signal
/// Signal value type
public static bool Send(Guid streamKey, T signalValue, Object signalSender, string message = "") =>
SignalsService.SendSignal(streamKey, signalValue, signalSender, message);
#endregion
#region Send MetaSignal - using a SignalStream reference
/// Send a MetaSignal on the given stream
/// Target signal stream
/// Signal value
/// Text message used to pass info about this Signal
/// Signal value type
public static bool Send(SignalStream stream, T signalValue, string message = "") =>
SignalsService.SendSignal(stream, signalValue, message);
/// Send a MetaSignal on the given stream, with a reference to the GameObject from where it was sent
/// Target signal stream
/// Signal value
/// Reference to the GameObject from where this Signal is sent from
/// Text message used to pass info about this Signal
/// Signal value type
public static bool Send(SignalStream stream, T signalValue, GameObject signalSource, string message = "") =>
SignalsService.SendSignal(stream, signalValue, signalSource, message);
/// Send a MetaSignal on the given stream, with a reference to the SignalProvider that sent it
/// Target signal stream
/// Signal value
/// Reference to the SignalProvider that sends this Signal
/// Text message used to pass info about this Signal
/// Signal value type
public static bool Send(SignalStream stream, T signalValue, SignalProvider signalProvider, string message = "") =>
SignalsService.SendSignal(stream, signalValue, signalProvider, message);
/// Send a MetaSignal on the given stream, with a reference to the Object that sent it
/// Target signal stream
/// Signal value
/// Reference to the Object that sends this Signal
/// Text message used to pass info about this Signal
/// Signal value type
public static bool Send(SignalStream stream, T signalValue, Object signalSender, string message = "") =>
SignalsService.SendSignal(stream, signalValue, signalSender, message);
#endregion
#endregion
}
public static class SignalExtensions
{
internal static T Reset(this T target) where T : Signal
{
target.stream = null;
target.signalProvider = null;
target.providerType = null;
target.signalSenderObject = null;
target.senderType = null;
target.sourceGameObject = null;
target.used = false;
target.timestamp = Time.time;
target.hasValue = false;
target.valueType = null;
target.valueAsObject = null;
if (target is MetaSignal metaSignal)
metaSignal.ResetValue();
return target;
}
internal static T SetValueType(this T target, bool hasValue = false, Type valueType = default) where T : Signal
{
target.hasValue = hasValue;
target.valueType = valueType;
return target;
}
internal static T SetStream(this T target, SignalStream stream) where T : Signal
{
target.stream = stream;
return target;
}
internal static T SetSignalProvider(this T target, SignalProvider signalProvider) where T : Signal
{
target.signalProvider = signalProvider;
target.providerType = signalProvider != null ? signalProvider.GetType() : null;
return target;
}
internal static T SetSignalSender(this T target, Object signalSender) where T : Signal
{
target.signalSenderObject = signalSender;
target.senderType = signalSender != null ? signalSender.GetType() : null;
return target;
}
internal static T SetSignalSource(this T target, GameObject sourceGameObject) where T : Signal
{
target.sourceGameObject = sourceGameObject;
return target;
}
internal static T SetTimestamp(this T target) where T : Signal
{
target.timestamp = Time.time;
return target;
}
internal static T SetMessage(this T target, string message) where T : Signal
{
target.message = message;
return target;
}
}
}