Systems - ActionScheduler
Updated a month agoActionScheduler
ActionScheduler
is a static system for scheduling, executing, and controlling timed actions, supporting single, repeated, delayed, frame-based, or random interval executions. Ideal for game logic, automation, and event sequences.
Overview
using ScarletCore.Systems;
// Schedule an action to run every 5 seconds, 3 times
var id = ActionScheduler.Repeating(() => Log.Info("Running!"), 5f, 3);
// Cancel the action before it completes
ActionScheduler.CancelAction(id);
Features
- Schedule actions by time, frames, or random intervals
- Support for cancellation, pausing, and resuming actions
- Execution of chained action sequences (ActionSequence)
- Control of maximum executions and execution count
- Performance optimizations with cache and reusable lists
- Support for actions with cancellation callback (ActionWithCancel)
Cancellation-Aware Actions
Some scheduling methods accept an Action<Action>
delegate (called ActionWithCancel). This allows your action to receive a callback that, when invoked, cancels the scheduled action immediately.
This is useful for:
- Stopping a repeating or long-running action from inside itself
- Cancelling a sequence step based on custom logic
- Early exit on error or condition
How it works
- The scheduled action receives a callback parameter (commonly named
cancel
orcancelAction
). - If you call this callback, the action will be marked for cancellation and will not run again.
Example: Using ActionWithCancel
// Schedule a repeating action that cancels itself after a condition
ActionScheduler.Repeating((cancel) => {
Log.Info($"Tick: {Time.time}");
if (Time.time > 10f) cancel(); // Stop after 10 seconds
}, 1f);
You can use ActionWithCancel in all scheduling methods:
OncePerFrame(Action<Action> action, int maxExecutions = -1)
NextFrame(Action<Action> action)
Repeating(Action<Action> action, float intervalSeconds, int maxExecutions = -1)
RepeatingFrames(Action<Action> action, int frameInterval, int maxExecutions = -1)
Delayed(Action<Action> action, float delaySeconds)
DelayedFrames(Action<Action> action, int delayFrames)
RepeatingRandom(Action<Action> action, float minIntervalSeconds, float maxIntervalSeconds, int maxExecutions = -1)
Tip: If you don't need cancellation, use the simpler Action
overloads.
Action Sequences
Allows you to create chained sequences of actions and delays:
var seqId = ActionScheduler.CreateSequence()
.Then(() => Log.Info("Step 1"))
.ThenWait(2f)
.Then(() => Log.Info("Step 2"))
.Execute();
Then(Action)
/Then(Action<Action>)
: Adds an action (with or without cancel support)ThenWait(float seconds)
: Adds a delay in secondsThenWaitFrames(int frames)
: Adds a delay in framesThenWaitRandom(float min, float max)
: Random delayCancel()
: Cancels the sequence
Scheduling Methods
OncePerFrame
Executes an action every frame.
var id = ActionScheduler.OncePerFrame(() => Log.Info("Every frame!"));
Or with cancellation support:
var id = ActionScheduler.OncePerFrame(cancel => {
// ...
if (shouldStop) cancel();
});
Parameters:
action
- Action to execute (can beAction
orAction<Action>
)maxExecutions
- Maximum executions (-1 for infinite)
Returns: ActionId
for control
NextFrame
Executes an action on the next frame.
var id = ActionScheduler.NextFrame(() => Log.Info("Next frame!"));
Or with cancellation support:
var id = ActionScheduler.NextFrame(cancel => {
// ...
});
Parameters:
action
- Action to execute (can beAction
orAction<Action>
)
Returns: ActionId
for control
Repeating
Executes repeatedly at time intervals (seconds).
var id = ActionScheduler.Repeating(() => Log.Info("Repeating!"), 2f);
Or with cancellation support:
var id = ActionScheduler.Repeating(cancel => {
// ...
if (shouldStop) cancel();
}, 2f);
Parameters:
action
- Action to execute (can beAction
orAction<Action>
)intervalSeconds
- Interval in secondsmaxExecutions
- Maximum executions (-1 for infinite)
Returns: ActionId
for control
RepeatingFrames
Executes repeatedly at frame intervals.
var id = ActionScheduler.RepeatingFrames(() => Log.Info("Every 10 frames!"), 10);
Or with cancellation support:
var id = ActionScheduler.RepeatingFrames(cancel => {
// ...
if (shouldStop) cancel();
}, 10);
Parameters:
action
- Action to execute (can beAction
orAction<Action>
)frameInterval
- Interval in framesmaxExecutions
- Maximum executions (-1 for infinite)
Returns: ActionId
for control
Delayed
Executes once after a delay in seconds.
ActionScheduler.Delayed(() => Log.Info("3s delay!"), 3f);
Or with cancellation support:
ActionScheduler.Delayed(cancel => {
// ...
}, 3f);
Parameters:
action
- Action to execute (can beAction
orAction<Action>
)delaySeconds
- Delay in seconds
Returns: ActionId
for control
DelayedFrames
Executes once after a delay in frames.
ActionScheduler.DelayedFrames(() => Log.Info("5 frames delay!"), 5);
Or with cancellation support:
ActionScheduler.DelayedFrames(cancel => {
// ...
}, 5);
Parameters:
action
- Action to execute (can beAction
orAction<Action>
)delayFrames
- Delay in frames
Returns: ActionId
for control
RepeatingRandom
Executes repeatedly at random intervals in seconds.
var id = ActionScheduler.RepeatingRandom(() => Log.Info("Random interval!"), 1f, 5f);
Or with cancellation support:
var id = ActionScheduler.RepeatingRandom(cancel => {
// ...
if (shouldStop) cancel();
}, 1f, 5f);
Parameters:
action
- Action to execute (can beAction
orAction<Action>
)minIntervalSeconds
- Minimum intervalmaxIntervalSeconds
- Maximum intervalmaxExecutions
- Maximum executions (-1 for infinite)
Returns: ActionId
for control
Control Methods
CancelAction
Cancels and removes a scheduled action.
ActionScheduler.CancelAction(id);
Parameters:
actionId
- Action ID
Returns: True if the action was found and cancelled
PauseAction / ResumeAction
Pauses or resumes a scheduled action.
ActionScheduler.PauseAction(id);
ActionScheduler.ResumeAction(id);
Parameters:
actionId
- Action ID
ClearAllActions
Removes all scheduled actions.
ActionScheduler.ClearAllActions();
Query Methods
Count
Total number of scheduled actions.
var total = ActionScheduler.Count;
GetExecutionCount / GetMaxExecutions / GetRemainingExecutions
Query executions performed, limit, and remaining executions for an action.
var execs = ActionScheduler.GetExecutionCount(id);
var max = ActionScheduler.GetMaxExecutions(id);
var left = ActionScheduler.GetRemainingExecutions(id);
Usage Examples
Simple scheduling
// Executes an action every second, 5 times
var id = ActionScheduler.Repeating(() => Log.Info("Tick!"), 1f, 5);
ActionWithCancel for early exit
ActionScheduler.Repeating(cancel => {
if (SomeCondition()) cancel();
else Log.Info("Still running");
}, 1f);
Action sequence with cancellation
var seq = ActionScheduler.CreateSequence()
.Then(() => Log.Info("Start"))
.ThenWait(1f)
.Then(cancel => {
if (ShouldStop()) cancel();
else Log.Info("Continue");
})
.Execute();
Cancellation
ActionScheduler.CancelAction(id);
Important Notes
- Do NOT call
ActionScheduler.Execute()
manually – it is called automatically by ScarletCore. You should never call it yourself in your code or game loop. - Actions can be paused and resumed
- Actions with callback receive a cancellation method
- Sequences can be cancelled at any time
- Maximum executions control how many times the action will run
- Actions are identified by a unique, thread-safe
ActionId
When to Use CoroutineHandler Instead
While ActionScheduler
is ideal for most timed, repeated, or delayed actions, there are scenarios where Unity coroutines (managed by CoroutineHandler
) are a better fit:
- Complex asynchronous flows: If you need to yield for custom conditions, wait for Unity events, or perform multi-step logic with multiple yields, use
CoroutineHandler
. - Waiting for Unity objects or events: For example, waiting for a scene to load, an animation to finish, or a physics event.
- Pausing/resuming at arbitrary yield points: Coroutines can be paused and resumed at any yield, not just between executions.
- Integration with Unity's coroutine system: If you need to use
yield return
withWaitForSeconds
,WaitUntil
, or other Unity yield instructions.
Tip: Use
ActionScheduler
for most simple, repeated, or delayed actions. UseCoroutineHandler
when you need full coroutine control, custom yields, or integration with Unity's coroutine system.
Pages
- Data - Database
- Data - PlayerData
- Data - Settings
- Events - CustomEventManager
- Events - EventManager
- Events - OnAnyDeath
- Events - OnChatMessage
- Events - OnDealDamage
- Events - OnOtherDeath
- Events - OnPlayerDeath
- Events - OnServantDeath
- Events - OnVBloodDeath
- Services - AbilityService
- Services - AdminService
- Services - BuffService
- Services - ClanService
- Services - InventoryService
- Services - KickBanService
- Services - MessageService
- Services - PlayerService
- Services - RevealMapService
- Services - TeleportService
- Services - UnitSpawnerService
- Systems - ActionScheduler
- Systems - CoroutineHandler
- Systems - GameSystems
- Utils - Logger
- Utils - MathUtility
- Utils - RichTextFormatter