// MIT License - Copyright (c) 2025 wallstop // Full license text: https://github.com/wallstop/unity-helpers/blob/main/LICENSE namespace WallstopStudios.UnityHelpers.Tags { using UnityEngine; /// /// Runtime tracking for a single instance. /// Maintains timing and execution counters for periodic ticks while an effect handle is active. /// /// /// /// Each effect handle owns its own runtime states, so multiple handles can execute the same /// periodic definition independently (with unique timers and tick counts). /// /// /// Intervals are clamped to a minimum of 0.01 seconds to prevent zero‑division and busy loops, /// and is initialized using . /// /// internal sealed class PeriodicEffectRuntimeState { /// /// Indicates whether the runtime has executed the maximum allowed ticks for the definition. /// internal bool IsComplete => definition.maxTicks > 0 && ExecutedTicks >= definition.maxTicks; /// /// The absolute timestamp (in seconds) when the next tick should execute. /// internal float NextTickTime { get; private set; } /// /// The number of ticks that have successfully executed so far. /// internal int ExecutedTicks { get; private set; } internal readonly PeriodicEffectDefinition definition; internal readonly float interval; /// /// Creates runtime tracking for a periodic definition, clamping invalid authoring values. /// /// The authoring data that describes cadence and modifications. /// The current time (in seconds) to seed the next tick timestamp. internal PeriodicEffectRuntimeState(PeriodicEffectDefinition definition, float startTime) { this.definition = definition; ExecutedTicks = 0; float clampedInterval = Mathf.Max(0.01f, definition.interval); interval = clampedInterval; NextTickTime = startTime + Mathf.Max(0f, definition.initialDelay); } /// /// Attempts to advance the runtime to the next tick if the current time has passed the scheduled timestamp. /// /// The current time (in seconds). /// true when a tick was consumed and incremented; otherwise, false. internal bool TryConsumeTick(float currentTime) { if (currentTime < NextTickTime || IsComplete) { return false; } ++ExecutedTicks; NextTickTime = currentTime + interval; return true; } } }