// 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;
}
}
}