Compare commits
	
		
			4 Commits
		
	
	
		
			7212094a3d
			...
			bc1c76d746
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| bc1c76d746 | |||
| 8f03628bd6 | |||
| a1feb0bad3 | |||
| 978cba96c8 | 
@@ -3,32 +3,138 @@ using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// Represents a simple event with no parameters.
 | 
			
		||||
/// <para>Example usage:</para> 
 | 
			
		||||
/// <code>
 | 
			
		||||
/// public class MyBehaviour : Behaviour, IUpdate
 | 
			
		||||
/// {
 | 
			
		||||
///     public readonly Event MyEvent = new();
 | 
			
		||||
/// 
 | 
			
		||||
///     public MyBehaviour()
 | 
			
		||||
///     {
 | 
			
		||||
///         MyEvent.AddListener(OnEventTriggered);
 | 
			
		||||
///         MyEvent.AddOneTimeListener(OnEventTriggeredOneTime);
 | 
			
		||||
///     }
 | 
			
		||||
/// 
 | 
			
		||||
///     public void Update()
 | 
			
		||||
///     {
 | 
			
		||||
///         MyEvent.Invoke();
 | 
			
		||||
///     }
 | 
			
		||||
/// 
 | 
			
		||||
///     private void OnEventTriggered()
 | 
			
		||||
///     {
 | 
			
		||||
///         Console.WriteLine($"Event occurred!");
 | 
			
		||||
///     }
 | 
			
		||||
/// 
 | 
			
		||||
///     private static void OnEventTriggeredOneTime()
 | 
			
		||||
///     {
 | 
			
		||||
///         Console.WriteLine($"Event called once!");
 | 
			
		||||
///     }
 | 
			
		||||
/// }
 | 
			
		||||
/// </code>
 | 
			
		||||
/// The output of the example code above would be: 
 | 
			
		||||
/// <code>
 | 
			
		||||
/// Event occurred!
 | 
			
		||||
/// Event called once!
 | 
			
		||||
/// Event occurred!
 | 
			
		||||
/// Event occurred!
 | 
			
		||||
/// Event occurred!
 | 
			
		||||
/// ...
 | 
			
		||||
/// </code>
 | 
			
		||||
/// </summary>
 | 
			
		||||
public class Event
 | 
			
		||||
{
 | 
			
		||||
    private readonly List<EventHandler> listeners = null!;
 | 
			
		||||
    private readonly List<EventHandler> onceListeners = null!;
 | 
			
		||||
    // We use Ascending order because draw calls are running from last to first
 | 
			
		||||
    private static readonly Comparer<ListenerData> SortByAscendingPriority = Comparer<ListenerData>.Create((x, y) => x.Priority.CompareTo(y.Priority));
 | 
			
		||||
 | 
			
		||||
    public void AddListener(EventHandler listener) => listeners.Add(listener);
 | 
			
		||||
    public void AddOnceListener(EventHandler listener) => onceListeners.Add(listener);
 | 
			
		||||
    public void RemoveListener(EventHandler listener) => listeners.Remove(listener);
 | 
			
		||||
    public void RemoveOnceListener(EventHandler listener) => onceListeners.Remove(listener);
 | 
			
		||||
    private readonly List<ListenerData> listeners = null!;
 | 
			
		||||
    private readonly List<ListenerData> onceListeners = null!;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Subscribes the callback to be invoked whenever the event is triggered.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="listener">The callback to be called when the event is triggered.</param>
 | 
			
		||||
    /// <param name="priority">Priority of the callback.</param>
 | 
			
		||||
    public void AddListener(EventHandler listener, int priority = 0)
 | 
			
		||||
    {
 | 
			
		||||
        ListenerData listenerData = new(listener, priority);
 | 
			
		||||
 | 
			
		||||
        int insertIndex = listeners.BinarySearch(listenerData, SortByAscendingPriority);
 | 
			
		||||
        if (insertIndex < 0)
 | 
			
		||||
            insertIndex = ~insertIndex;
 | 
			
		||||
 | 
			
		||||
        listeners.Insert(insertIndex, listenerData);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Subscribes the callback to be invoked the next time the event is triggered. The callback will be called only once.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="listener">The callback to be called the next time the event is triggered.</param>
 | 
			
		||||
    /// <param name="priority">Priority of the callback.</param>
 | 
			
		||||
    public void AddOneTimeListener(EventHandler listener, int priority = 0)
 | 
			
		||||
    {
 | 
			
		||||
        ListenerData listenerData = new(listener, priority);
 | 
			
		||||
 | 
			
		||||
        int insertIndex = onceListeners.BinarySearch(listenerData, SortByAscendingPriority);
 | 
			
		||||
        if (insertIndex < 0)
 | 
			
		||||
            insertIndex = ~insertIndex;
 | 
			
		||||
 | 
			
		||||
        onceListeners.Insert(insertIndex, listenerData);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Unsubscribes the callback that was previously registered by <see cref="AddListener(EventHandler)"/>.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="listener">The callback that was previously registered by <see cref="AddListener(EventHandler)"/></param>
 | 
			
		||||
    public void RemoveListener(EventHandler listener)
 | 
			
		||||
    {
 | 
			
		||||
        for (int i = listeners.Count - 1; i >= 0; i--)
 | 
			
		||||
            if (listeners[i].Callback == listener)
 | 
			
		||||
            {
 | 
			
		||||
                listeners.RemoveAt(i);
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Unsubscribes the callback that was previously registered by <see cref="AddOneTimeListener(EventHandler)"/>.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="listener">The callback that was previously registered by <see cref="AddOneTimeListener(EventHandler)"/></param>
 | 
			
		||||
    public void RemoveOneTimeListener(EventHandler listener)
 | 
			
		||||
    {
 | 
			
		||||
        for (int i = 0; i < onceListeners.Count; i++)
 | 
			
		||||
            if (onceListeners[i].Callback == listener)
 | 
			
		||||
            {
 | 
			
		||||
                onceListeners.RemoveAt(i);
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Unsubscribes all listeners that was previously registered by either <see cref="AddListener(EventHandler)"/> or <see cref="AddOneTimeListener(EventHandler)"/>.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public void Clear() { listeners.Clear(); onceListeners.Clear(); }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Triggers the event.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public void Invoke()
 | 
			
		||||
    {
 | 
			
		||||
        for (int i = 0; i < listeners.Count; i++)
 | 
			
		||||
            try { listeners[i].Invoke(); }
 | 
			
		||||
        for (int i = listeners.Count - 1; i >= 0; i--)
 | 
			
		||||
            try { listeners[i].Callback.Invoke(); }
 | 
			
		||||
            catch (Exception exception)
 | 
			
		||||
            {
 | 
			
		||||
                string methodCallRepresentation = $"{listeners[i].Method.DeclaringType?.FullName}.{listeners[i].Method.Name}()";
 | 
			
		||||
                string methodCallRepresentation = $"{listeners[i].Callback.Method.DeclaringType?.FullName}.{listeners[i].Callback.Method.Name}()";
 | 
			
		||||
                Console.WriteLine($"Unexpected exception on invocation of method {methodCallRepresentation}:{Environment.NewLine}{exception.InnerException}");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        for (int i = onceListeners.Count - 1; i >= 0; i--)
 | 
			
		||||
        {
 | 
			
		||||
            try { onceListeners[i].Invoke(); }
 | 
			
		||||
            try { onceListeners[i].Callback.Invoke(); }
 | 
			
		||||
            catch (Exception exception)
 | 
			
		||||
            {
 | 
			
		||||
                string methodCallRepresentation = $"{onceListeners[i].Method.DeclaringType?.FullName}.{onceListeners[i].Method.Name}()";
 | 
			
		||||
                string methodCallRepresentation = $"{onceListeners[i].Callback.Method.DeclaringType?.FullName}.{onceListeners[i].Callback.Method.Name}()";
 | 
			
		||||
                Console.WriteLine($"Unexpected exception on invocation of method {methodCallRepresentation}:{Environment.NewLine}{exception.InnerException}");
 | 
			
		||||
            }
 | 
			
		||||
            onceListeners.RemoveAt(i);
 | 
			
		||||
@@ -48,34 +154,144 @@ public class Event
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public delegate void EventHandler();
 | 
			
		||||
    private record struct ListenerData(EventHandler Callback, int Priority);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// Represents an event with only sender parameters.
 | 
			
		||||
/// <para>Example usage:</para> 
 | 
			
		||||
/// <code>
 | 
			
		||||
/// public class MyBehaviour : Behaviour, IUpdate
 | 
			
		||||
/// {
 | 
			
		||||
///     public readonly Event<MyBehaviour> MyEvent = new();
 | 
			
		||||
/// 
 | 
			
		||||
///     public MyBehaviour()
 | 
			
		||||
///     {
 | 
			
		||||
///         MyEvent.AddListener(OnEventTriggered);
 | 
			
		||||
///         MyEvent.AddOneTimeListener(OnEventTriggeredOneTime);
 | 
			
		||||
///     }
 | 
			
		||||
/// 
 | 
			
		||||
///     public void Update()
 | 
			
		||||
///     {
 | 
			
		||||
///         MyEvent.Invoke(this);
 | 
			
		||||
///     }
 | 
			
		||||
/// 
 | 
			
		||||
///     private void OnEventTriggered(MyBehaviour sender)
 | 
			
		||||
///     {
 | 
			
		||||
///         Console.WriteLine($"{sender.Id}'s event occurred!");
 | 
			
		||||
///     }
 | 
			
		||||
/// 
 | 
			
		||||
///     private static void OnEventTriggeredOneTime(MyBehaviour sender)
 | 
			
		||||
///     {
 | 
			
		||||
///         Console.WriteLine($"{sender.Id}'s event called once!");
 | 
			
		||||
///     }
 | 
			
		||||
/// }
 | 
			
		||||
/// </code>
 | 
			
		||||
/// The output of the example code above would be: 
 | 
			
		||||
/// <code>
 | 
			
		||||
/// [Id]'s event occurred!
 | 
			
		||||
/// [Id]'s event called once!
 | 
			
		||||
/// [Id]'s event occurred!
 | 
			
		||||
/// [Id]'s event occurred!
 | 
			
		||||
/// [Id]'s event occurred!
 | 
			
		||||
/// ...
 | 
			
		||||
/// </code>
 | 
			
		||||
/// 
 | 
			
		||||
/// </summary>
 | 
			
		||||
/// <typeparam name="TSender">Sender type</typeparam>
 | 
			
		||||
public class Event<TSender>
 | 
			
		||||
{
 | 
			
		||||
    private readonly List<EventHandler> listeners = null!;
 | 
			
		||||
    private readonly List<EventHandler> onceListeners = null!;
 | 
			
		||||
    // We use Ascending order because draw calls are running from last to first
 | 
			
		||||
    private static readonly Comparer<ListenerData> SortByAscendingPriority = Comparer<ListenerData>.Create((x, y) => x.Priority.CompareTo(y.Priority));
 | 
			
		||||
 | 
			
		||||
    public void AddListener(EventHandler listener) => listeners.Add(listener);
 | 
			
		||||
    public void AddOnceListener(EventHandler listener) => onceListeners.Add(listener);
 | 
			
		||||
    public void RemoveListener(EventHandler listener) => listeners.Remove(listener);
 | 
			
		||||
    public void RemoveOnceListener(EventHandler listener) => onceListeners.Remove(listener);
 | 
			
		||||
    private readonly List<ListenerData> listeners = null!;
 | 
			
		||||
    private readonly List<ListenerData> onceListeners = null!;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Subscribes the callback to be invoked whenever the event is triggered.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="listener">The callback to be called when the event is triggered.</param>
 | 
			
		||||
    /// <param name="priority">Priority of the callback.</param>
 | 
			
		||||
    public void AddListener(EventHandler listener, int priority = 0)
 | 
			
		||||
    {
 | 
			
		||||
        ListenerData listenerData = new(listener, priority);
 | 
			
		||||
 | 
			
		||||
        int insertIndex = listeners.BinarySearch(listenerData, SortByAscendingPriority);
 | 
			
		||||
        if (insertIndex < 0)
 | 
			
		||||
            insertIndex = ~insertIndex;
 | 
			
		||||
 | 
			
		||||
        listeners.Insert(insertIndex, listenerData);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Subscribes the callback to be invoked the next time the event is triggered. The callback will be called only once.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="listener">The callback to be called the next time the event is triggered.</param>
 | 
			
		||||
    /// <param name="priority">Priority of the callback.</param>
 | 
			
		||||
    public void AddOneTimeListener(EventHandler listener, int priority = 0)
 | 
			
		||||
    {
 | 
			
		||||
        ListenerData listenerData = new(listener, priority);
 | 
			
		||||
 | 
			
		||||
        int insertIndex = onceListeners.BinarySearch(listenerData, SortByAscendingPriority);
 | 
			
		||||
        if (insertIndex < 0)
 | 
			
		||||
            insertIndex = ~insertIndex;
 | 
			
		||||
 | 
			
		||||
        onceListeners.Insert(insertIndex, listenerData);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Unsubscribes the callback that was previously registered by <see cref="AddListener(EventHandler)"/>.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="listener">The callback that was previously registered by <see cref="AddListener(EventHandler)"/></param>
 | 
			
		||||
    public void RemoveListener(EventHandler listener)
 | 
			
		||||
    {
 | 
			
		||||
        for (int i = listeners.Count - 1; i >= 0; i--)
 | 
			
		||||
            if (listeners[i].Callback == listener)
 | 
			
		||||
            {
 | 
			
		||||
                listeners.RemoveAt(i);
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Unsubscribes the callback that was previously registered by <see cref="AddOneTimeListener(EventHandler)"/>.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="listener">The callback that was previously registered by <see cref="AddOneTimeListener(EventHandler)"/></param>
 | 
			
		||||
    public void RemoveOneTimeListener(EventHandler listener)
 | 
			
		||||
    {
 | 
			
		||||
        for (int i = 0; i < onceListeners.Count; i++)
 | 
			
		||||
            if (onceListeners[i].Callback == listener)
 | 
			
		||||
            {
 | 
			
		||||
                onceListeners.RemoveAt(i);
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Unsubscribes all listeners that was previously registered by either <see cref="AddListener(EventHandler)"/> or <see cref="AddOneTimeListener(EventHandler)"/>.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public void Clear() { listeners.Clear(); onceListeners.Clear(); }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Triggers the event.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="sender">The caller that's triggering this event.</param>
 | 
			
		||||
    public void Invoke(TSender sender)
 | 
			
		||||
    {
 | 
			
		||||
        for (int i = 0; i < listeners.Count; i++)
 | 
			
		||||
            try { listeners[i].Invoke(sender); }
 | 
			
		||||
        for (int i = listeners.Count - 1; i >= 0; i--)
 | 
			
		||||
            try { listeners[i].Callback.Invoke(sender); }
 | 
			
		||||
            catch (Exception exception)
 | 
			
		||||
            {
 | 
			
		||||
                string methodCallRepresentation = $"{listeners[i].Method.DeclaringType?.FullName}.{listeners[i].Method.Name}({sender})";
 | 
			
		||||
                string methodCallRepresentation = $"{listeners[i].Callback.Method.DeclaringType?.FullName}.{listeners[i].Callback.Method.Name}({sender})";
 | 
			
		||||
                Console.WriteLine($"Unexpected exception on invocation of method {methodCallRepresentation}:{Environment.NewLine}{exception.InnerException}");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        for (int i = onceListeners.Count - 1; i >= 0; i--)
 | 
			
		||||
        {
 | 
			
		||||
            try { onceListeners[i].Invoke(sender); }
 | 
			
		||||
            try { onceListeners[i].Callback.Invoke(sender); }
 | 
			
		||||
            catch (Exception exception)
 | 
			
		||||
            {
 | 
			
		||||
                string methodCallRepresentation = $"{onceListeners[i].Method.DeclaringType?.FullName}.{onceListeners[i].Method.Name}({sender})";
 | 
			
		||||
                string methodCallRepresentation = $"{onceListeners[i].Callback.Method.DeclaringType?.FullName}.{onceListeners[i].Callback.Method.Name}({sender})";
 | 
			
		||||
                Console.WriteLine($"Unexpected exception on invocation of method {methodCallRepresentation}:{Environment.NewLine}{exception.InnerException}");
 | 
			
		||||
            }
 | 
			
		||||
            onceListeners.RemoveAt(i);
 | 
			
		||||
@@ -95,34 +311,152 @@ public class Event<TSender>
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public delegate void EventHandler(TSender sender);
 | 
			
		||||
    private record struct ListenerData(EventHandler Callback, int Priority);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// Represents an event with sender and argument parameters.
 | 
			
		||||
/// <para>Example usage:</para> 
 | 
			
		||||
/// <code>
 | 
			
		||||
/// public class MyBehaviour : Behaviour, IUpdate
 | 
			
		||||
/// {
 | 
			
		||||
///     public readonly Event<MyBehaviour, MyArguments> MyEvent = new();
 | 
			
		||||
/// 
 | 
			
		||||
///     private int myInt = 0;
 | 
			
		||||
///     private bool myBool = false;
 | 
			
		||||
/// 
 | 
			
		||||
///     public MyBehaviour()
 | 
			
		||||
///     {
 | 
			
		||||
///         MyEvent.AddOneTimeListener(OnEventTriggeredOneTime);
 | 
			
		||||
///         MyEvent.AddListener(OnEventTriggered);
 | 
			
		||||
///     }
 | 
			
		||||
/// 
 | 
			
		||||
///     public void Update()
 | 
			
		||||
///     {
 | 
			
		||||
///         MyEvent.Invoke(this, new MyArguments(myInt, myBool));
 | 
			
		||||
///         myInt++;
 | 
			
		||||
///         myBool = !myBool;
 | 
			
		||||
///     }
 | 
			
		||||
/// 
 | 
			
		||||
///     private void OnEventTriggered(MyBehaviour sender, MyArguments args)
 | 
			
		||||
///     {
 | 
			
		||||
///         Console.WriteLine($"{sender.Id}'s event occurred with MyInt: {args.MyInt} and MyBool {args.MyBool}!");
 | 
			
		||||
///     }
 | 
			
		||||
/// 
 | 
			
		||||
///     private static void OnEventTriggeredOneTime(MyBehaviour sender, MyArguments args)
 | 
			
		||||
///     {
 | 
			
		||||
///         Console.WriteLine($"{sender.Id}'s event called once with MyInt: {args.MyInt} and MyBool {args.MyBool}!");
 | 
			
		||||
///     }
 | 
			
		||||
/// 
 | 
			
		||||
///     public readonly record struct MyArguments(int MyInt, bool MyBool);
 | 
			
		||||
/// }
 | 
			
		||||
/// </code>
 | 
			
		||||
/// The output of the example code above would be: 
 | 
			
		||||
/// <code>
 | 
			
		||||
/// [Id]'s event occurred with MyInt: 0 and MyBool False!
 | 
			
		||||
/// [Id]'s event called once with MyInt: 0 and MyBool False!
 | 
			
		||||
/// [Id]'s event occurred with MyInt: 1 and MyBool True!
 | 
			
		||||
/// [Id]'s event occurred with MyInt: 2 and MyBool False!
 | 
			
		||||
/// [Id]'s event occurred with MyInt: 3 and MyBool True!
 | 
			
		||||
/// ...
 | 
			
		||||
/// </code>
 | 
			
		||||
/// 
 | 
			
		||||
/// </summary>
 | 
			
		||||
/// <typeparam name="TSender">Sender type</typeparam>
 | 
			
		||||
public class Event<TSender, TArguments>
 | 
			
		||||
{
 | 
			
		||||
    private readonly List<EventHandler> listeners = null!;
 | 
			
		||||
    private readonly List<EventHandler> onceListeners = null!;
 | 
			
		||||
    // We use Ascending order because draw calls are running from last to first
 | 
			
		||||
    private static readonly Comparer<ListenerData> SortByAscendingPriority = Comparer<ListenerData>.Create((x, y) => x.Priority.CompareTo(y.Priority));
 | 
			
		||||
 | 
			
		||||
    public void AddListener(EventHandler listener) => listeners.Add(listener);
 | 
			
		||||
    public void AddOnceListener(EventHandler listener) => onceListeners.Add(listener);
 | 
			
		||||
    public void RemoveListener(EventHandler listener) => listeners.Remove(listener);
 | 
			
		||||
    public void RemoveOnceListener(EventHandler listener) => onceListeners.Remove(listener);
 | 
			
		||||
    private readonly List<ListenerData> listeners = null!;
 | 
			
		||||
    private readonly List<ListenerData> onceListeners = null!;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Subscribes the callback to be invoked whenever the event is triggered.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="listener">The callback to be called when the event is triggered.</param>
 | 
			
		||||
    /// <param name="priority">Priority of the callback.</param>
 | 
			
		||||
    public void AddListener(EventHandler listener, int priority = 0)
 | 
			
		||||
    {
 | 
			
		||||
        ListenerData listenerData = new(listener, priority);
 | 
			
		||||
 | 
			
		||||
        int insertIndex = listeners.BinarySearch(listenerData, SortByAscendingPriority);
 | 
			
		||||
        if (insertIndex < 0)
 | 
			
		||||
            insertIndex = ~insertIndex;
 | 
			
		||||
 | 
			
		||||
        listeners.Insert(insertIndex, listenerData);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Subscribes the callback to be invoked the next time the event is triggered. The callback will be called only once.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="listener">The callback to be called the next time the event is triggered.</param>
 | 
			
		||||
    /// <param name="priority">Priority of the callback.</param>
 | 
			
		||||
    public void AddOneTimeListener(EventHandler listener, int priority = 0)
 | 
			
		||||
    {
 | 
			
		||||
        ListenerData listenerData = new(listener, priority);
 | 
			
		||||
 | 
			
		||||
        int insertIndex = onceListeners.BinarySearch(listenerData, SortByAscendingPriority);
 | 
			
		||||
        if (insertIndex < 0)
 | 
			
		||||
            insertIndex = ~insertIndex;
 | 
			
		||||
 | 
			
		||||
        onceListeners.Insert(insertIndex, listenerData);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Unsubscribes the callback that was previously registered by <see cref="AddListener(EventHandler)"/>.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="listener">The callback that was previously registered by <see cref="AddListener(EventHandler)"/></param>
 | 
			
		||||
    public void RemoveListener(EventHandler listener)
 | 
			
		||||
    {
 | 
			
		||||
        for (int i = listeners.Count - 1; i >= 0; i--)
 | 
			
		||||
            if (listeners[i].Callback == listener)
 | 
			
		||||
            {
 | 
			
		||||
                listeners.RemoveAt(i);
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Unsubscribes the callback that was previously registered by <see cref="AddOneTimeListener(EventHandler)"/>.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="listener">The callback that was previously registered by <see cref="AddOneTimeListener(EventHandler)"/></param>
 | 
			
		||||
    public void RemoveOneTimeListener(EventHandler listener)
 | 
			
		||||
    {
 | 
			
		||||
        for (int i = 0; i < onceListeners.Count; i++)
 | 
			
		||||
            if (onceListeners[i].Callback == listener)
 | 
			
		||||
            {
 | 
			
		||||
                onceListeners.RemoveAt(i);
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Unsubscribes all listeners that was previously registered by either <see cref="AddListener(EventHandler)"/> or <see cref="AddOneTimeListener(EventHandler)"/>.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public void Clear() { listeners.Clear(); onceListeners.Clear(); }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Triggers the event.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="sender">The caller that's triggering this event.</param>
 | 
			
		||||
    /// <param name="args">The arguments provided for this event.</param>
 | 
			
		||||
    public void Invoke(TSender sender, TArguments args)
 | 
			
		||||
    {
 | 
			
		||||
        for (int i = 0; i < listeners.Count; i++)
 | 
			
		||||
            try { listeners[i].Invoke(sender, args); }
 | 
			
		||||
        for (int i = listeners.Count - 1; i >= 0; i--)
 | 
			
		||||
            try { listeners[i].Callback.Invoke(sender, args); }
 | 
			
		||||
            catch (Exception exception)
 | 
			
		||||
            {
 | 
			
		||||
                string methodCallRepresentation = $"{listeners[i].Method.DeclaringType?.FullName}.{listeners[i].Method.Name}({string.Join(", ", sender, args)})";
 | 
			
		||||
                string methodCallRepresentation = $"{listeners[i].Callback.Method.DeclaringType?.FullName}.{listeners[i].Callback.Method.Name}({string.Join(", ", sender, args)})";
 | 
			
		||||
                Console.WriteLine($"Unexpected exception on invocation of method {methodCallRepresentation}:{Environment.NewLine}{exception.InnerException}");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        for (int i = onceListeners.Count - 1; i >= 0; i--)
 | 
			
		||||
        {
 | 
			
		||||
            try { onceListeners[i].Invoke(sender, args); }
 | 
			
		||||
            try { onceListeners[i].Callback.Invoke(sender, args); }
 | 
			
		||||
            catch (Exception exception)
 | 
			
		||||
            {
 | 
			
		||||
                string methodCallRepresentation = $"{onceListeners[i].Method.DeclaringType?.FullName}.{onceListeners[i].Method.Name}({string.Join(", ", sender, args)})";
 | 
			
		||||
                string methodCallRepresentation = $"{onceListeners[i].Callback.Method.DeclaringType?.FullName}.{onceListeners[i].Callback.Method.Name}({string.Join(", ", sender, args)})";
 | 
			
		||||
                Console.WriteLine($"Unexpected exception on invocation of method {methodCallRepresentation}:{Environment.NewLine}{exception.InnerException}");
 | 
			
		||||
            }
 | 
			
		||||
            onceListeners.RemoveAt(i);
 | 
			
		||||
@@ -142,4 +476,5 @@ public class Event<TSender, TArguments>
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public delegate void EventHandler(TSender sender, TArguments args);
 | 
			
		||||
    private record struct ListenerData(EventHandler Callback, int Priority);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user