// MIT License - Copyright (c) 2025 wallstop // Full license text: https://github.com/wallstop/unity-helpers/blob/main/LICENSE namespace WallstopStudios.UnityHelpers.Tags { using System; using System.Threading; using Core.Extension; /// /// Opaque identifier for a specific effect application instance. /// Use to remove or refresh one instance without affecting others. /// /// /// /// Lifecycle: Handles are only created for and /// effects. effects /// apply permanently and do not produce a handle. /// /// /// Problem solved: Distinguishes concurrent applications of the same . /// You can remove a single stack while leaving others intact, and systems can track/refresh durations /// per instance using the handle ID. /// /// /// Contains: /// - A monotonically increasing unique /// - A reference to the applied /// Equality and ordering are based solely on the ID. /// /// /// Usage patterns: /// /// // Apply and store for later removal /// EffectHandle? maybe = target.ApplyEffect(slow); /// if (maybe.HasValue) _activeSlows.Add(maybe.Value); /// /// // Remove one instance (e.g., dispel one stack) /// if (_activeSlows.Count > 0) { /// target.RemoveEffect(_activeSlows[0]); /// _activeSlows.RemoveAt(0); /// } /// /// // Refreshing timed effects (EffectHandler already supports resetDurationOnReapplication) /// target.ApplyEffect(slow); // Reapplying can reset duration (if enabled) /// /// /// [Serializable] public readonly struct EffectHandle : IEquatable, IComparable, IComparable { internal static long Id; /// /// The AttributeEffect associated with this handle. /// public readonly AttributeEffect effect; /// /// The unique identifier for this effect instance. /// This ID is globally unique and monotonically increasing. /// public readonly long id; /// /// Creates a new EffectHandle instance with a unique ID for the specified effect. /// /// The AttributeEffect to create a handle for. /// A new EffectHandle with a unique ID. public static EffectHandle CreateInstance(AttributeEffect effect) { return new EffectHandle(Interlocked.Increment(ref Id), effect); } internal static EffectHandle CreateInstanceInternal() { return new EffectHandle(Interlocked.Increment(ref Id), null); } private EffectHandle(long id, AttributeEffect effect) { this.id = id; this.effect = effect; } /// /// Compares this handle to another handle based on their IDs. /// /// The handle to compare with. /// /// A value less than 0 if this handle's ID is less than ; /// 0 if they are equal; /// a value greater than 0 if this handle's ID is greater than . /// public int CompareTo(EffectHandle other) { return id.CompareTo(other.id); } /// /// Compares this handle to an object. /// /// The object to compare with. /// /// The comparison result if is an EffectHandle; otherwise, -1. /// public int CompareTo(object obj) { if (obj is EffectHandle other) { return CompareTo(other); } return -1; } /// /// Determines whether this handle equals the specified object. /// /// The object to compare with. /// true if the object is an EffectHandle with the same ID; otherwise, false. public override bool Equals(object obj) { return obj is EffectHandle other && Equals(other); } /// /// Determines whether this handle equals another handle by comparing their IDs. /// /// The handle to compare with. /// true if the IDs are equal; otherwise, false. public bool Equals(EffectHandle other) { return id == other.id; } /// /// Returns the hash code for this handle based on its ID. /// /// The hash code of the ID. public override int GetHashCode() { return id.GetHashCode(); } /// /// Converts this handle to a JSON string representation. /// /// A JSON string representing this handle. public override string ToString() { return this.ToJson(); } } }