/* * SPDX-License-Identifier: AGPL-3.0-or-later * Copyright (C) 2025 Sergej Görzen * This file is part of OmiLAXR. */ using System; using System.Collections.Generic; using UnityEngine.Events; namespace OmiLAXR.TrackingBehaviours { /// /// Common interface for all tracking behavior event types. /// Provides standard lifecycle management methods for event cleanup and state control. /// public interface ITrackingBehaviourEvent { /// /// Removes all Unity Event and Action bindings from this event. /// void UnbindAll(); /// /// Clears all registered action handlers from this event. /// void ClearActions(); /// /// Performs complete cleanup of this event, unbinding all listeners and clearing actions. /// void Dispose(); /// /// Temporarily disables this event, preventing it from triggering. /// void Mute(); /// /// Gets or sets whether this event is currently disabled. /// bool IsDisabled { get; set; } } /// /// Basic tracking behavior event with no additional parameters. /// Supports binding to Unity Events and custom action handlers. /// public class TrackingBehaviourEvent : ITrackingBehaviourEvent { /// /// List of all registered action handlers for debugging and management. /// public readonly List Actions = new List(); /// /// Main event that handlers subscribe to for notifications. /// public event TrackingBehaviourAction Action; /// /// Dictionary tracking Unity Event bindings for proper cleanup. /// private Dictionary _unityBinds = new Dictionary(); /// /// Flag indicating if this event is currently muted/disabled. /// public bool IsDisabled { get; set; } /// /// Registers a new action handler with this event. /// Adds the handler to both the event subscription and tracking list. /// /// Action handler to register public void AddHandler(TrackingBehaviourAction action) { Action += action; Actions.Add(action); } /// /// Triggers this event with the specified owner, unless the event is disabled. /// /// The tracking behavior that owns this event public void Invoke(ITrackingBehaviour owner) { if (IsDisabled) return; Action?.Invoke(owner); } /// /// Removes all registered action handlers from this event. /// Unsubscribes each action and clears the tracking list. /// public void ClearActions() { foreach (var a in Actions) { Action -= a; } Actions.Clear(); } /// /// Performs complete cleanup by unbinding Unity Events and clearing actions. /// public void Dispose() { UnbindAll(); ClearActions(); } /// /// Disables this event, preventing future invocations. /// public void Mute() { IsDisabled = true; } /// /// Re-enables this event after being muted. /// public void Unmute() { IsDisabled = false; } /// /// Convenience method to bind a Unity Event to trigger this event with a specific owner. /// /// Unity Event to bind to /// Owner to pass when the Unity Event triggers public void Bind(UnityEvent unityEvent, ITrackingBehaviour owner) => Bind(unityEvent, () => Invoke(owner)); /// /// Binds a Unity Event to execute a custom action when triggered. /// Tracks the binding for proper cleanup later. /// /// Unity Event to bind to /// Action to execute when Unity Event triggers public void Bind(UnityEvent unityEvent, UnityAction invoker) { // Use version-appropriate dictionary method #if UNITY_2020 || UNITY_2019 if (!_unityBinds.ContainsKey(unityEvent)) _unityBinds.Add(unityEvent, invoker); #else if (!_unityBinds.TryAdd(unityEvent, invoker)) return; #endif unityEvent.AddListener(invoker); } /// /// Removes a previously bound Unity Event listener. /// /// Unity Event to unbind from public void Unbind(UnityEvent unityEvent) { unityEvent.RemoveListener(_unityBinds[unityEvent]); _unityBinds.Remove(unityEvent); } /// /// Removes all Unity Event bindings from this event. /// public void UnbindAll() { foreach (var ev in _unityBinds.Keys) { ev.RemoveListener(_unityBinds[ev]); } _unityBinds.Clear(); } } /// /// Tracking behavior event with one typed parameter. /// Extends the basic event to include strongly-typed data in event notifications. /// /// Type of the event parameter public class TrackingBehaviourEvent : ITrackingBehaviourEvent { /// /// List of all registered typed action handlers. /// public readonly List> Actions = new List>(); /// /// Main typed event that handlers subscribe to. /// public event TrackingBehaviourAction Action; /// /// Dictionary tracking Unity Event bindings for cleanup. /// private Dictionary _unityBinds = new Dictionary(); /// /// Flag indicating if this event is currently disabled. /// public bool IsDisabled { get; set; } /// /// Registers a typed action handler with this event. /// /// Typed action handler to register public void AddHandler(TrackingBehaviourAction action) { Action += action; Actions.Add(action); } /// /// Triggers this event with the specified owner and typed argument. /// /// The tracking behavior that owns this event /// Typed argument to pass to handlers public void Invoke(ITrackingBehaviour owner, T arg) { if (IsDisabled) return; Action?.Invoke(owner, arg); } /// /// Removes all registered action handlers from this event. /// public void ClearActions() { foreach (var a in Actions) { Action -= a; } Actions.Clear(); } /// /// Performs complete cleanup of this event. /// public void Dispose() { ClearActions(); UnbindAll(); } /// /// Convenience method to bind Unity Event with pre-configured owner and argument. /// /// Unity Event to bind to /// Owner to pass when triggered /// Argument to pass when triggered public void Bind(UnityEvent unityEvent, ITrackingBehaviour owner, T arg) => Bind(unityEvent, () => Invoke(owner, arg)); /// /// Binds Unity Event to custom action. /// /// Unity Event to bind to /// Action to execute when triggered public void Bind(UnityEvent unityEvent, UnityAction invoker) { #if UNITY_2020 || UNITY_2019 if (!_unityBinds.ContainsKey(unityEvent)) _unityBinds.Add(unityEvent, invoker); #else if (!_unityBinds.TryAdd(unityEvent, invoker)) return; #endif unityEvent.AddListener(invoker); } /// /// Removes Unity Event binding. /// /// Unity Event to unbind public void Unbind(UnityEvent unityEvent) { unityEvent.RemoveListener(_unityBinds[unityEvent]); _unityBinds.Remove(unityEvent); } /// /// Disables this event. /// public void Mute() { IsDisabled = true; } /// /// Re-enables this event. /// public void Unmute() { IsDisabled = false; } /// /// Removes all Unity Event bindings. /// public void UnbindAll() { foreach (var ev in _unityBinds.Keys) { ev.RemoveListener(_unityBinds[ev]); } _unityBinds.Clear(); } } /// /// Tracking behavior event with sender and value parameters. /// Provides enhanced event data with both the sending component and associated value. /// /// Type of the component that sent the event /// Type of the value associated with the event public class TrackingBehaviourEvent : ITrackingBehaviourEvent { /// /// List of all registered action handlers for this two-parameter event. /// public readonly List> Actions = new List>(); /// /// Main event with sender and value parameters. /// public event TrackingBehaviourAction Action; /// /// Unity Event bindings with typed values for cleanup tracking. /// private Dictionary, UnityAction> _unityBinds = new Dictionary, UnityAction>(); /// /// Action bindings for C# Action delegates. /// private Dictionary, Action> _actionBinds = new Dictionary, Action>(); /// /// Disabled state flag for this event. /// public bool IsDisabled { get; set; } /// /// Gets the number of registered handlers for this event. /// public int HandlerCount => Actions.Count; /// /// Adds a new handler for this two-parameter event. /// /// Handler to register public void AddHandler(TrackingBehaviourAction action) { Action += action; Actions.Add(action); } /// /// Invokes this event with owner, sender, and value parameters. /// /// Tracking behavior that owns this event /// Component that generated the event /// Value associated with the event public void Invoke(ITrackingBehaviour owner, TSender sender, TValue value) { if (IsDisabled) return; Action?.Invoke(owner, sender, value); } /// Disables this event. public void Mute() => IsDisabled = true; /// Re-enables this event. public void Unmute() => IsDisabled = false; /// /// Clears all registered action handlers. /// public void ClearActions() { foreach (var a in Actions) { Action -= a; } Actions.Clear(); } /// /// Performs complete event cleanup. /// public void Dispose() { UnbindAll(); ClearActions(); } /// /// Binds to a typed Unity Event with custom invoker. /// /// Unity Event to bind to /// Custom invoker action public void Bind(UnityEvent unityEvent, UnityAction invoker) { #if !UNITY_2021_1_OR_NEWER if (!_unityBinds.ContainsKey(unityEvent)) _unityBinds.Add(unityEvent, invoker); #else if (!_unityBinds.TryAdd(unityEvent, invoker)) return; #endif unityEvent.AddListener(invoker); } /// /// Removes Unity Event binding. /// /// Unity Event to unbind public void Unbind(UnityEvent unityEvent) { unityEvent.RemoveListener(_unityBinds[unityEvent]); _unityBinds.Remove(unityEvent); } /// /// Binds to a C# Action delegate with custom invoker. /// /// Action to bind to /// Custom invoker public void Bind(Action action, Action invoker) { #if !UNITY_2021_1_OR_NEWER if (!_actionBinds.ContainsKey(action)) _actionBinds.Add(action, invoker); #else if (!_actionBinds.TryAdd(action, invoker)) return; #endif action += invoker; } /// /// Removes Action binding. /// /// Action to unbind public void Unbind(Action action) { action -= _actionBinds[action]; _actionBinds.Remove(action); } /// /// Removes all bindings (Unity Events and Actions). /// public void UnbindAll() { // Clean up Unity Event bindings foreach (var ev in _unityBinds.Keys) { ev.RemoveListener(_unityBinds[ev]); } _unityBinds.Clear(); // Clean up Action bindings void unbind(Action action) { action -= _actionBinds[action]; } foreach (var ev in _actionBinds.Keys) { unbind(ev); } _actionBinds.Clear(); } } /// /// Tracking behavior event with sender, value, and additional arguments. /// Most comprehensive event type supporting three parameters for complex event scenarios. /// /// Type of the sending component /// Type of the primary value /// Type of additional arguments public class TrackingBehaviourEvent : ITrackingBehaviourEvent { /// /// List of registered three-parameter action handlers. /// public readonly List> Actions = new List>(); /// /// Main three-parameter event. /// public event TrackingBehaviourAction Action; /// Unity Event bindings tracking dictionary. private Dictionary, UnityAction> _unityBinds = new Dictionary, UnityAction>(); /// Action bindings tracking dictionary. private Dictionary, Action> _actionBinds = new Dictionary, Action>(); /// Event disabled state flag. public bool IsDisabled { get; set; } /// /// Registers a three-parameter action handler. /// /// Handler to register public void AddHandler(TrackingBehaviourAction action) { Action += action; Actions.Add(action); } /// /// Invokes event with all three parameters. /// /// Tracking behavior owner /// Sending component /// Primary value /// Additional arguments public void Invoke(ITrackingBehaviour owner, TSender sender, TValue value, TArgs args) { if (IsDisabled) return; Action?.Invoke(owner, sender, value, args); } /// Disables the event. public void Mute() => IsDisabled = true; /// Re-enables the event. public void Unmute() => IsDisabled = false; /// Clears all action handlers. public void ClearActions() { foreach (var a in Actions) { Action -= a; } Actions.Clear(); } /// Complete event cleanup. public void Dispose() { UnbindAll(); ClearActions(); } /// Binds to C# Action with invoker. public void Bind(Action action, Action invoker) { #if !UNITY_2021_1_OR_NEWER if (!_actionBinds.ContainsKey(action)) _actionBinds.Add(action, invoker); #else if (!_actionBinds.TryAdd(action, invoker)) return; #endif action += invoker; } /// Removes Action binding. public void Unbind(Action action) { action -= _actionBinds[action]; _actionBinds.Remove(action); } /// Binds to Unity Event with invoker. public void Bind(UnityEvent unityEvent, UnityAction invoker) { #if !UNITY_2021_1_OR_NEWER if (!_unityBinds.ContainsKey(unityEvent)) _unityBinds.Add(unityEvent, invoker); #else if (!_unityBinds.TryAdd(unityEvent, invoker)) return; #endif unityEvent.AddListener(invoker); } /// Removes Unity Event binding. public void Unbind(UnityEvent unityEvent) { unityEvent.RemoveListener(_unityBinds[unityEvent]); _unityBinds.Remove(unityEvent); } /// Removes all bindings (Unity Events and Actions). public void UnbindAll() { // Clean up Unity Events foreach (var ev in _unityBinds.Keys) { ev.RemoveListener(_unityBinds[ev]); } _unityBinds.Clear(); // Clean up Actions void unbind(Action action) { action -= _actionBinds[action]; } foreach (var ev in _actionBinds.Keys) { unbind(ev); } _actionBinds.Clear(); } } }