using System; using System.Collections.Generic; namespace Syntriax.Engine.Core; /// /// Represents a simple event with no parameters. /// Example usage: /// /// 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!"); /// } /// } /// /// The output of the example code above would be: /// /// Event occurred! /// Event called once! /// Event occurred! /// Event occurred! /// Event occurred! /// ... /// /// public class Event { private readonly List listeners = null!; private readonly List onceListeners = null!; /// /// Subscribes the callback to be invoked whenever the event is triggered. /// /// The callback to be called when the event is triggered. public void AddListener(EventHandler listener) => listeners.Add(listener); /// /// Subscribes the callback to be invoked the next time the event is triggered. The callback will be called only once. /// /// The callback to be called the next time the event is triggered. public void AddOneTimeListener(EventHandler listener) => onceListeners.Add(listener); /// /// Unsubscribes the callback that was previously registered by . /// /// The callback that was previously registered by public void RemoveListener(EventHandler listener) => listeners.Remove(listener); /// /// Unsubscribes the callback that was previously registered by . /// /// The callback that was previously registered by public void RemoveOneTimeListener(EventHandler listener) => onceListeners.Remove(listener); /// /// Unsubscribes all listeners that was previously registered by either or . /// public void Clear() { listeners.Clear(); onceListeners.Clear(); } /// /// Triggers the event. /// public void Invoke() { for (int i = listeners.Count - 1; i >= 0; i--) try { listeners[i].Invoke(); } catch (Exception exception) { string methodCallRepresentation = $"{listeners[i].Method.DeclaringType?.FullName}.{listeners[i].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(); } catch (Exception exception) { string methodCallRepresentation = $"{onceListeners[i].Method.DeclaringType?.FullName}.{onceListeners[i].Method.Name}()"; Console.WriteLine($"Unexpected exception on invocation of method {methodCallRepresentation}:{Environment.NewLine}{exception.InnerException}"); } onceListeners.RemoveAt(i); } } public Event(int initialListenerCount = 4, int initialOnceListenerCount = 2) { listeners = new(initialListenerCount); onceListeners = new(initialOnceListenerCount); } public Event() { listeners = new(4); onceListeners = new(2); } public delegate void EventHandler(); } /// /// Represents an event with only sender parameters. /// Example usage: /// /// 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!"); /// } /// } /// /// The output of the example code above would be: /// /// [Id]'s event occurred! /// [Id]'s event called once! /// [Id]'s event occurred! /// [Id]'s event occurred! /// [Id]'s event occurred! /// ... /// /// /// /// Sender type public class Event { private readonly List listeners = null!; private readonly List onceListeners = null!; /// /// Subscribes the callback to be invoked whenever the event is triggered. /// /// The callback to be called when the event is triggered. public void AddListener(EventHandler listener) => listeners.Add(listener); /// /// Subscribes the callback to be invoked the next time the event is triggered. The callback will be called only once. /// /// The callback to be called the next time the event is triggered. public void AddOneTimeListener(EventHandler listener) => onceListeners.Add(listener); /// /// Unsubscribes the callback that was previously registered by . /// /// The callback that was previously registered by public void RemoveListener(EventHandler listener) => listeners.Remove(listener); /// /// Unsubscribes the callback that was previously registered by . /// /// The callback that was previously registered by public void RemoveOneTimeListener(EventHandler listener) => onceListeners.Remove(listener); /// /// Unsubscribes all listeners that was previously registered by either or . /// public void Clear() { listeners.Clear(); onceListeners.Clear(); } /// /// Triggers the event. /// /// The caller that's triggering this event. public void Invoke(TSender sender) { for (int i = listeners.Count - 1; i >= 0; i--) try { listeners[i].Invoke(sender); } catch (Exception exception) { string methodCallRepresentation = $"{listeners[i].Method.DeclaringType?.FullName}.{listeners[i].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); } catch (Exception exception) { string methodCallRepresentation = $"{onceListeners[i].Method.DeclaringType?.FullName}.{onceListeners[i].Method.Name}({sender})"; Console.WriteLine($"Unexpected exception on invocation of method {methodCallRepresentation}:{Environment.NewLine}{exception.InnerException}"); } onceListeners.RemoveAt(i); } } public Event(int initialListenerCount = 4, int initialOnceListenerCount = 2) { listeners = new(initialListenerCount); onceListeners = new(initialOnceListenerCount); } public Event() { listeners = new(4); onceListeners = new(2); } public delegate void EventHandler(TSender sender); } /// /// Represents an event with sender and argument parameters. /// Example usage: /// /// 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); /// } /// /// The output of the example code above would be: /// /// [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! /// ... /// /// /// /// Sender type public class Event { private readonly List listeners = null!; private readonly List onceListeners = null!; /// /// Subscribes the callback to be invoked whenever the event is triggered. /// /// The callback to be called when the event is triggered. public void AddListener(EventHandler listener) => listeners.Add(listener); /// /// Subscribes the callback to be invoked the next time the event is triggered. The callback will be called only once. /// /// The callback to be called the next time the event is triggered. public void AddOneTimeListener(EventHandler listener) => onceListeners.Add(listener); /// /// Unsubscribes the callback that was previously registered by . /// /// The callback that was previously registered by public void RemoveListener(EventHandler listener) => listeners.Remove(listener); /// /// Unsubscribes the callback that was previously registered by . /// /// The callback that was previously registered by public void RemoveOneTimeListener(EventHandler listener) => onceListeners.Remove(listener); /// /// Unsubscribes all listeners that was previously registered by either or . /// public void Clear() { listeners.Clear(); onceListeners.Clear(); } /// /// Triggers the event. /// /// The caller that's triggering this event. /// The arguments provided for this event. public void Invoke(TSender sender, TArguments args) { for (int i = listeners.Count - 1; i >= 0; i--) try { listeners[i].Invoke(sender, args); } catch (Exception exception) { string methodCallRepresentation = $"{listeners[i].Method.DeclaringType?.FullName}.{listeners[i].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); } catch (Exception exception) { string methodCallRepresentation = $"{onceListeners[i].Method.DeclaringType?.FullName}.{onceListeners[i].Method.Name}({string.Join(", ", sender, args)})"; Console.WriteLine($"Unexpected exception on invocation of method {methodCallRepresentation}:{Environment.NewLine}{exception.InnerException}"); } onceListeners.RemoveAt(i); } } public Event(int initialListenerCount = 4, int initialOnceListenerCount = 2) { listeners = new(initialListenerCount); onceListeners = new(initialOnceListenerCount); } public Event() { listeners = new(4); onceListeners = new(2); } public delegate void EventHandler(TSender sender, TArguments args); }