// UltEvents // Copyright 2020 Kybernetik //
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
using UnityEngine;
using UnityEngine.Events;
namespace UltEvents
{
///
/// Allows you to expose the add and remove methods of an without exposing the rest of its
/// members such as the ability to invoke it.
///
public interface IUltEventBase
{
/************************************************************************************************************************/
/// Adds the specified 'method to the persistent call list.
PersistentCall AddPersistentCall(Delegate method);
/// Removes the specified 'method from the persistent call list.
void RemovePersistentCall(Delegate method);
/************************************************************************************************************************/
}
///
/// A serializable event which can be viewed and configured in the inspector.
///
/// This is a more versatile and user friendly implementation than .
///
[Serializable]
public abstract class UltEventBase : IUltEventBase
{
/************************************************************************************************************************/
#region Fields and Properties
/************************************************************************************************************************/
public abstract int ParameterCount { get; }
/************************************************************************************************************************/
[SerializeField]
internal List _PersistentCalls;
///
/// The serialized method and parameter details of this event.
///
public List PersistentCallsList
{
get { return _PersistentCalls; }
}
/************************************************************************************************************************/
///
/// The non-serialized method and parameter details of this event.
///
protected abstract Delegate DynamicCallsBase { get; set; }
///
/// Clears the cached invocation list of .
///
[System.Diagnostics.Conditional("UNITY_EDITOR")]
protected void OnDynamicCallsChanged()
{
#if UNITY_EDITOR
_DynamicCallInvocationList = null;
#endif
}
/************************************************************************************************************************/
#if UNITY_EDITOR
/************************************************************************************************************************/
internal bool HasAnyDynamicCalls()
{
return DynamicCallsBase != null;
}
/************************************************************************************************************************/
private Delegate[] _DynamicCallInvocationList;
internal Delegate[] GetDynamicCallInvocationList()
{
if (_DynamicCallInvocationList == null && DynamicCallsBase != null)
_DynamicCallInvocationList = DynamicCallsBase.GetInvocationList();
return _DynamicCallInvocationList;
}
internal int GetDynamicCallInvocationListCount()
{
if (DynamicCallsBase == null)
return 0;
else
return GetDynamicCallInvocationList().Length;
}
/************************************************************************************************************************/
#endif
/************************************************************************************************************************/
#endregion
/************************************************************************************************************************/
#region Operators and Call Registration
/************************************************************************************************************************/
/// Ensures that `e` isn't null and adds `method` to its .
public static PersistentCall AddPersistentCall(ref T e, Delegate method) where T : UltEventBase, new()
{
if (e == null)
e = new T();
return e.AddPersistentCall(method);
}
/// Ensures that `e` isn't null and adds `method` to its .
public static PersistentCall AddPersistentCall(ref T e, Action method) where T : UltEventBase, new()
{
if (e == null)
e = new T();
return e.AddPersistentCall(method);
}
/************************************************************************************************************************/
/// If `e` isn't null, this method removes `method` from its .
public static void RemovePersistentCall(ref UltEventBase e, Delegate method)
{
if (e != null)
e.RemovePersistentCall(method);
}
/// If `e` isn't null, this method removes `method` from its .
public static void RemovePersistentCall(ref UltEventBase e, Action method)
{
if (e != null)
e.RemovePersistentCall(method);
}
/************************************************************************************************************************/
///
/// Add the specified 'method to the persistent call list.
///
public PersistentCall AddPersistentCall(Delegate method)
{
if (_PersistentCalls == null)
_PersistentCalls = new List(4);
var call = new PersistentCall(method);
_PersistentCalls.Add(call);
return call;
}
///
/// Remove the specified 'method from the persistent call list.
///
public void RemovePersistentCall(Delegate method)
{
if (_PersistentCalls == null)
return;
for (int i = 0; i < _PersistentCalls.Count; i++)
{
var call = _PersistentCalls[i];
if (call.GetMethodSafe() == method.Method && ReferenceEquals(call.Target, method.Target))
{
_PersistentCalls.RemoveAt(i);
return;
}
}
}
/************************************************************************************************************************/
#endregion
/************************************************************************************************************************/
///
/// Invokes all then all .
///
public void DynamicInvoke(params object[] parameters)
{
// A larger array would actually work fine, but it probably still means something is wrong.
if (parameters.Length != ParameterCount)
throw new ArgumentException("Invalid parameter count " +
parameters.Length + " should be " + ParameterCount);
CacheParameters(parameters);
InvokePersistentCalls();
var dynamicCalls = DynamicCallsBase;
if (dynamicCalls != null)
dynamicCalls.DynamicInvoke(parameters);
}
/************************************************************************************************************************/
/// Invokes all s registered to this event.
protected void InvokePersistentCalls()
{
var originalParameterOffset = _ParameterOffset;
var originalReturnValueOffset = _ReturnValueOffset;
try
{
if (_PersistentCalls != null)
{
for (int i = 0; i < _PersistentCalls.Count; i++)
{
var result = _PersistentCalls[i].Invoke();
LinkedValueCache.Add(result);
_ParameterOffset = originalParameterOffset;
_ReturnValueOffset = originalReturnValueOffset;
}
}
}
finally
{
LinkedValueCache.RemoveRange(originalParameterOffset, LinkedValueCache.Count - originalParameterOffset);
_ParameterOffset = _ReturnValueOffset = originalParameterOffset;
}
}
/************************************************************************************************************************/
#region Linked Value Cache (Parameters and Returned Values)
/************************************************************************************************************************/
private static readonly List