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