Class ScyllaTime
Centralized time management service for the Scylla Framework.
Implements
Inherited Members
Namespace: Scylla.Core.Time
Assembly: ScyllaCore.dll
Syntax
public sealed class ScyllaTime : IClockSource
Remarks
ScyllaTime is a pure C# singleton (not a MonoBehaviour) that owns all
time-related state for the application: the current base time scale, pause state,
a layered modifier stack, an active smooth-transition driver, an in-process
millisecond accumulator, and notifications to registered ITimeListener
objects.
The singleton is created by ScyllaBootstrap during its Awake
phase via the internal Initialize(ScyllaTimeConfiguration) factory method, and destroyed during
application quit via the internal Scylla.Core.Time.ScyllaTime.Shutdown() method. Game code must
never construct or destroy this class directly.
When running in play mode, Initialize(ScyllaTimeConfiguration) spawns a hidden
TimeTickRunner MonoBehaviour that drives Tick(float) from
Update using UnityEngine.Time.unscaledDeltaTime. In EditMode tests
the runner is not spawned and callers may invoke Tick(float) manually.
All time value properties (DeltaTime, TimeSinceStartup,
etc.) are thin pass-throughs to UnityEngine.Time. Setting
TimeScale updates the base scale; the actual
UnityEngine.Time.timeScale applied to the engine is the base scale multiplied
by the current TimeScaleModifierStack multiplier (when not paused).
Configuration: All fields defined in ScyllaTimeConfiguration
are enforced at runtime. MaxTimeScale clamps
all time scale changes, AllowPause guards
Pause(), RestoreTimeScaleOnResume
controls resume behavior, and AdjustFixedTimestep
synchronizes Time.fixedDeltaTime with effective-scale changes.
Access the singleton via Instance:
<pre><code class="lang-csharp">ScyllaTime.Instance.Pause();
float dt = ScyllaTime.Instance.DeltaTime;
Properties
ClockCount
Number of clocks currently registered with this service.
Declaration
public int ClockCount { get; }
Property Value
| Type | Description |
|---|---|
| int |
Configuration
Gets the ScyllaTimeConfiguration asset used to initialize this service instance.
Declaration
public ScyllaTimeConfiguration Configuration { get; }
Property Value
| Type | Description |
|---|---|
| ScyllaTimeConfiguration | The configuration asset supplied to Initialize(ScyllaTimeConfiguration), or |
See Also
CurrentPauseMode
Gets the current pause mode. None when not paused;
Hard or Soft when paused.
Soft pause keeps clocks with RespectsGlobalPause
= false ticking through the pause - useful for UI / menu animation clocks.
Declaration
public PauseMode CurrentPauseMode { get; }
Property Value
| Type | Description |
|---|---|
| PauseMode |
CurrentTickMilliseconds
Gets the in-process millisecond accumulator advanced by Tick(float) from unscaled real time. Used by IClockSource consumers that need a monotonic millisecond reference unaffected by time scale or pause.
Declaration
public long CurrentTickMilliseconds { get; }
Property Value
| Type | Description |
|---|---|
| long |
DeltaTime
Gets the time in seconds that has elapsed since the last frame, scaled by the current TimeScale.
Declaration
public float DeltaTime { get; }
Property Value
| Type | Description |
|---|---|
| float | A pass-through to |
EffectiveTimeScale
Gets the effective time scale applied to UnityEngine.Time.timeScale
after combining the base TimeScale with the active modifier
stack. Returns 0 while paused.
Declaration
public float EffectiveTimeScale { get; }
Property Value
| Type | Description |
|---|---|
| float |
Remarks
When a master clock is registered, Tick(float) writes the master clock's
EffectiveRate to UnityEngine.Time.timeScale
instead of the modifier-derived rate. This property reflects that override so
consumers reading EffectiveTimeScale always see the value actually in
effect on the engine.
Reads do not allocate.
FixedDeltaTime
Gets the interval in seconds at which the physics engine runs fixed-timestep
updates, as set in Project Settings > Time > Fixed Timestep.
Declaration
public float FixedDeltaTime { get; }
Property Value
| Type | Description |
|---|---|
| float | A pass-through to |
FrameCount
Gets the total number of frames that have been rendered since the application started.
Declaration
public int FrameCount { get; }
Property Value
| Type | Description |
|---|---|
| int | A pass-through to |
Instance
Gets the active singleton instance of the ScyllaTime service.
Declaration
public static ScyllaTime Instance { get; }
Property Value
| Type | Description |
|---|---|
| ScyllaTime | The singleton instance, or |
IsPaused
Gets whether the game is currently paused.
Declaration
public bool IsPaused { get; }
Property Value
| Type | Description |
|---|---|
| bool |
|
MasterClock
The clock designated as master, or null when no master clock has been
registered. The master clock's EffectiveRate mirrors to
UnityEngine.Time.timeScale via Tick(float).
Declaration
public ScyllaClock MasterClock { get; }
Property Value
| Type | Description |
|---|---|
| ScyllaClock |
ModifierStack
Gets the active TimeScaleModifierStack. Modifiers can also be pushed and popped via the convenience methods on this class (PushModifier(TimeScaleModifier), PopModifier(TimeScaleModifierHandle), etc.).
Declaration
public TimeScaleModifierStack ModifierStack { get; }
Property Value
| Type | Description |
|---|---|
| TimeScaleModifierStack |
RealTimeSinceStartup
Gets the real-world time in seconds since the application started, measured by the system clock rather than Unity's frame loop.
Declaration
public float RealTimeSinceStartup { get; }
Property Value
| Type | Description |
|---|---|
| float | A pass-through to |
TimeScale
Gets or sets the current base time scale.
Declaration
public float TimeScale { get; set; }
Property Value
| Type | Description |
|---|---|
| float | A non-negative float where |
Remarks
The value returned by this property is the BASE scale, not the effective
applied scale. When modifiers are active (e.g., during hit-stop or
bullet-time), the actual UnityEngine.Time.timeScale equals this base
value multiplied by the modifier-stack multiplier. To read the post-modifier
result, use EffectiveTimeScale.
When the game is not paused, assigning this property immediately
re-applies the effective time scale to UnityEngine.Time.timeScale,
affecting physics simulation, animations, and all scaled time queries on the
same frame.
When the game is paused (IsPaused is true),
assigning this property stores the value internally without touching
UnityEngine.Time.timeScale (which remains at 0 for the
duration of the pause). The stored value is restored to
UnityEngine.Time.timeScale when Resume() is called.
Prefer the higher-level helpers SetNormalSpeed(), SetSlowMotion(float), SetFastForward(float), and SetTimeScale(float) over direct property assignment when you also want listener notifications to fire.
TimeSinceStartup
Gets the total game time in seconds since the application started, scaled by the current TimeScale.
Declaration
public float TimeSinceStartup { get; }
Property Value
| Type | Description |
|---|---|
| float | A pass-through to |
UnscaledDeltaTime
Gets the real-world time in seconds that has elapsed since the last frame, unaffected by TimeScale or pause state.
Declaration
public float UnscaledDeltaTime { get; }
Property Value
| Type | Description |
|---|---|
| float | A pass-through to |
UnscaledTimeSinceStartup
Gets the total real-world time in seconds since the application started, unaffected by TimeScale or pause state.
Declaration
public float UnscaledTimeSinceStartup { get; }
Property Value
| Type | Description |
|---|---|
| float | A pass-through to |
Methods
CaptureState()
Captures a JSON-safe snapshot of the entire time state: global pause + mode, base
time scale, the global modifier stack, and a snapshot of every clock with
PersistOnSnapshot set to true. The result is
suitable for round-trip via ScyllaSerialization.
Declaration
public MasterTimeState CaptureState()
Returns
| Type | Description |
|---|---|
| MasterTimeState |
Remarks
Scheduled callbacks (TickScheduler entries, WaitUntil watchers) are NOT captured because Action cannot be serialized portably. Consumers that need persistent scheduled events should re-register them after RestoreState(MasterTimeState) via the high-level scheduling API.
ClearModifiers()
Removes all active modifiers and re-applies the effective scale.
Declaration
public void ClearModifiers()
ConvertToRealTime(float)
Converts a duration measured in scaled game-time seconds to the equivalent
duration in real (unscaled) seconds at the current EffectiveTimeScale.
Returns 0 when the effective scale is zero (paused or fully attenuated).
Declaration
public float ConvertToRealTime(float scaledTime)
Parameters
| Type | Name | Description |
|---|---|---|
| float | scaledTime |
Returns
| Type | Description |
|---|---|
| float |
ConvertToScaledTime(float)
Converts a duration measured in real (unscaled) seconds to the equivalent duration in scaled game-time seconds at the current EffectiveTimeScale. Uses the effective scale (after modifiers and master-clock override) so consumers get the value actually applied to the engine, not the base value.
Declaration
public float ConvertToScaledTime(float realTime)
Parameters
| Type | Name | Description |
|---|---|---|
| float | realTime |
Returns
| Type | Description |
|---|---|
| float |
GetActiveModifiers()
Read-only view of the active modifiers in priority order. Intended for debug overlays and tests.
Declaration
public IReadOnlyList<TimeScaleModifier> GetActiveModifiers()
Returns
| Type | Description |
|---|---|
| IReadOnlyList<TimeScaleModifier> |
GetAllClocks()
Read-only view of all registered clocks in stable registration order.
Declaration
public IReadOnlyList<ScyllaClock> GetAllClocks()
Returns
| Type | Description |
|---|---|
| IReadOnlyList<ScyllaClock> |
GetClock(string)
Returns the registered clock with the given clockID, or
null when no such clock exists.
Declaration
public ScyllaClock GetClock(string clockID)
Parameters
| Type | Name | Description |
|---|---|---|
| string | clockID |
Returns
| Type | Description |
|---|---|
| ScyllaClock |
GetDebugInfo()
Builds a ScyllaTimeDebugInfo snapshot of every registered clock plus global state. Allocates one fresh array each call (sized to ClockCount); suitable for periodic display from a debug HUD but not the inner-most hot path.
Declaration
public ScyllaTimeDebugInfo GetDebugInfo()
Returns
| Type | Description |
|---|---|
| ScyllaTimeDebugInfo |
GetDebugInfo(ref ClockDebugInfo[])
Allocation-free overload of GetDebugInfo() that fills a caller-supplied buffer with one ClockDebugInfo per registered clock and returns the wrapping ScyllaTimeDebugInfo referencing that same buffer. The buffer is grown only when its current capacity is smaller than the registered clock count.
Declaration
public ScyllaTimeDebugInfo GetDebugInfo(ref ClockDebugInfo[] buffer)
Parameters
| Type | Name | Description |
|---|---|---|
| ClockDebugInfo[] | buffer | Reusable storage. May be |
Returns
| Type | Description |
|---|---|
| ScyllaTimeDebugInfo |
GetEffectiveMultiplier()
Returns the multiplier currently produced by the modifier stack (1 when
empty). The returned value reflects only the modifier contribution, not the
base TimeScale.
Declaration
public float GetEffectiveMultiplier()
Returns
| Type | Description |
|---|---|
| float |
GetTimeInfo()
Returns a human-readable summary of the current time state, suitable for debug overlays or logging.
Declaration
public string GetTimeInfo()
Returns
| Type | Description |
|---|---|
| string |
Pause()
Pauses the game by setting UnityEngine.Time.timeScale to 0 and
preserving the current time scale for later restoration.
Declaration
public void Pause()
Remarks
If the game is already paused (IsPaused is true) this
method is a no-op; it will not re-capture the time scale or fire a second
Paused notification.
After a successful pause, all registered ITimeListener objects
are notified with Paused. The value of
DeltaTime will return 0 on subsequent frames until
Resume() is called. UnscaledDeltaTime and
RealTimeSinceStartup continue to advance normally.
See Also
Pause(PauseMode)
Pauses the game in the supplied mode. Hard
matches the v1.0 behavior; Soft still pins
UnityEngine.Time.timeScale to 0 but clocks with
RespectsGlobalPause set to false keep ticking.
Passing None is treated as a no-op.
Declaration
public void Pause(PauseMode mode)
Parameters
| Type | Name | Description |
|---|---|---|
| PauseMode | mode |
PopModifier(TimeScaleModifierHandle)
Removes a previously pushed modifier identified by handle
and re-applies the effective scale.
Declaration
public bool PopModifier(TimeScaleModifierHandle handle)
Parameters
| Type | Name | Description |
|---|---|---|
| TimeScaleModifierHandle | handle |
Returns
| Type | Description |
|---|---|
| bool |
|
PushModifier(TimeScaleModifier)
Adds a layered TimeScaleModifier on top of the base TimeScale and immediately re-applies the effective scale. Returns a handle the caller may use to PopModifier(TimeScaleModifierHandle) early.
Declaration
public TimeScaleModifierHandle PushModifier(TimeScaleModifier modifier)
Parameters
| Type | Name | Description |
|---|---|---|
| TimeScaleModifier | modifier |
Returns
| Type | Description |
|---|---|
| TimeScaleModifierHandle |
RegisterClock(ClockDefinition)
Registers a ClockDefinition at runtime, instantiating the matching ScyllaClock wrapper and adding it to the registry. The clock begins advancing on the next call to Tick(float).
Declaration
public ScyllaClock RegisterClock(ClockDefinition definition)
Parameters
| Type | Name | Description |
|---|---|---|
| ClockDefinition | definition | The clock definition asset. Must be non-null and have a non-empty ClockID. |
Returns
| Type | Description |
|---|---|
| ScyllaClock | The newly created runtime clock, or the existing clock if one with the same ID was already registered. |
Exceptions
| Type | Condition |
|---|---|
| ArgumentNullException | Thrown when |
| ArgumentException | Thrown when the definition's ClockID is null or whitespace, or when the definition designates itself as master while another master is already registered. |
RegisterListener(ITimeListener)
Registers an ITimeListener to receive time-related event notifications from this service.
Declaration
public void RegisterListener(ITimeListener listener)
Parameters
| Type | Name | Description |
|---|---|---|
| ITimeListener | listener | The listener to register. Must not be |
RemoveModifiersBySourceID(string)
Removes every active modifier whose SourceID
equals sourceID and re-applies the effective scale.
Declaration
public int RemoveModifiersBySourceID(string sourceID)
Parameters
| Type | Name | Description |
|---|---|---|
| string | sourceID |
Returns
| Type | Description |
|---|---|
| int | The number of modifiers removed. |
RestoreState(MasterTimeState)
Restores time-system state from a previously captured MasterTimeState. Clocks listed in the state are looked up by ClockID; if a clock is no longer registered, that entry is logged and skipped without aborting the rest of the restore.
Declaration
public void RestoreState(MasterTimeState state)
Parameters
| Type | Name | Description |
|---|---|---|
| MasterTimeState | state |
Remarks
The snapshot's SchemaVersion is validated against CURRENT_SCHEMA_VERSION; mismatched versions log a warning and abort the restore.
Any in-flight SmoothTimeScaleTransition is cancelled so it does not overwrite the restored time scale on the next tick. Each restored clock has its Scylla.Core.Time.TickScheduler cleared because the scheduler entries are not part of the snapshot and would otherwise fire stale callbacks at incorrect tick values.
Modifier handles obtained before the capture are invalidated by restore: the modifier stack reassigns IDs on push, so callers holding pre-capture handles must reacquire them via RemoveModifiersBySourceID(string) instead of PopModifier(TimeScaleModifierHandle).
Resume()
Resumes the game by restoring UnityEngine.Time.timeScale to the value it
held at the moment Pause() was last called.
Declaration
public void Resume()
Remarks
If the game is not currently paused (IsPaused is false)
this method is a no-op; it will not modify the time scale or fire a
Resumed notification.
After a successful resume, all registered ITimeListener objects
are notified with Resumed. If
RestoreTimeScaleOnResume is false,
the time scale is reset to 1.0 instead of the pre-pause value. Any
active modifier stack is then folded into UnityEngine.Time.timeScale
via EffectiveTimeScale.
See Also
SetFastForward(float)
Sets the time scale to a value greater than or equal to 1.0, effectively
speeding up the passage of game time.
Declaration
public void SetFastForward(float scale = -1)
Parameters
| Type | Name | Description |
|---|---|---|
| float | scale | The desired fast-forward factor. Values less than |
SetNormalSpeed()
Sets the time scale to normal real-time speed (1.0) and notifies
registered listeners if the scale actually changed.
Declaration
public void SetNormalSpeed()
SetSlowMotion(float)
Sets the time scale to a value less than or equal to 1.0, effectively
slowing the passage of game time.
Declaration
public void SetSlowMotion(float scale = -1)
Parameters
| Type | Name | Description |
|---|---|---|
| float | scale | The desired slow-motion factor. Must be in the range |
SetTimeScale(float)
Sets the time scale to an arbitrary non-negative value and notifies all registered ITimeListener objects if the value actually changed.
Declaration
public void SetTimeScale(float scale)
Parameters
| Type | Name | Description |
|---|---|---|
| float | scale |
TogglePause()
Toggles the game between paused and resumed states, delegating to Pause() or Resume() as appropriate.
Declaration
public void TogglePause()
Remarks
Calling this method when the game is already transitioning state (e.g., from within an OnTimeEvent(TimeEvent) callback) is safe; the underlying Pause() and Resume() methods guard against re-entrant no-op calls.
See Also
TransitionTimeScale(float, float, Action, Func<float, float>)
Smoothly transitions the base TimeScale from its current value
to targetScale over realSeconds real-time
seconds, replacing any in-flight transition.
Declaration
public SmoothTimeScaleTransition TransitionTimeScale(float targetScale, float realSeconds, Action onComplete = null, Func<float, float> easing = null)
Parameters
| Type | Name | Description |
|---|---|---|
| float | targetScale | The base scale to reach at the end of the transition. |
| float | realSeconds | Real-time seconds the transition should take. Values |
| Action | onComplete | Optional callback invoked when the transition completes. |
| Func<float, float> | easing | Optional custom easing function; defaults to |
Returns
| Type | Description |
|---|---|
| SmoothTimeScaleTransition | The active SmoothTimeScaleTransition driver. Caller may store it to |
UnregisterClock(string)
Removes the clock identified by clockID from the registry.
Subsequent Tick(float) calls no longer advance it.
Declaration
public bool UnregisterClock(string clockID)
Parameters
| Type | Name | Description |
|---|---|---|
| string | clockID |
Returns
| Type | Description |
|---|---|
| bool |
|
UnregisterListener(ITimeListener)
Unregisters a previously registered ITimeListener so it no longer receives time-related event notifications.
Declaration
public void UnregisterListener(ITimeListener listener)
Parameters
| Type | Name | Description |
|---|---|---|
| ITimeListener | listener |