Skip to content

Scheduler and jobs

Status: Partly implemented. Delayed and repeating tasks on the server tick, delayed tasks on the client tick, cancelling, and Lua coroutines that sleep for ticks. Worker jobs, counters, parallel loops and tasks bound to one level or entity are Planned (The job system).

Function table: sched.

Functions

typedef void (*cl_task_fn)(void* user);

cl_result cl_sched_run_server(int32_t delay_ticks, cl_task_fn fn, void* user, cl_task* out);      // once, on the server tick
cl_result cl_sched_repeat_server(int32_t delay_ticks, int32_t period_ticks, cl_task_fn fn, void* user, cl_task* out);
cl_result cl_sched_run_client(int32_t delay_ticks, cl_task_fn fn, void* user, cl_task* out);      // once, on the client tick
cl_result cl_task_cancel(cl_task t);
bool      cl_task_is_pending(cl_task t);

delay_ticks = 0 runs on the next tick. 20 ticks are one second. These may be called from any thread; the callback always runs on the tick. out may be NULL.

Bindings

C C++ Lua
cl_sched_run_server(20, fn, u, &t) clight::after(20, [=] { ... }) → Expected<Task> (capturing lambdas, freed after the run) cl.sched.run_server(20, function() ... end)
cl_sched_repeat_server(0, 20, fn, u, &t) clight::every(20, [](clight::Task t) { ... }, delay) cl.sched.repeat_server(0, 20, fn)
cl_sched_run_client(1, fn, u, &t) clight::after_client(1, [] { ... }) cl.sched.run_client(1, fn)
cl_task_cancel(t) task.cancel() (also frees the lambda) task:cancel(), cl.task.cancel(task)
cl_task_is_pending(t) task.is_pending() task:is_pending()

Lua coroutines

cl.on("player.join", function(event)
  local p = event.player
  cl.spawn(function()
    p:send_message("Welcome!")
    cl.sleep_ticks(40)                 -- two seconds; the world keeps running
    if p:is_valid() then p:send_message("Type /help for the commands.") end
  end)
end)

cl.spawn(fn, ...) starts a coroutine; cl.sleep_ticks(n) (only inside one) resumes it n ticks later on the server tick (the client tick in a client-only process). Nothing costs a tick while no coroutine sleeps. After a sleep, check handles again: the player may have left.

Example: a countdown (C++)

void start_countdown(clight::Entity player) {
    auto left = std::make_shared<int>(5);
    clight::every(20, [player, left](clight::Task self) {
        if (!player.is_valid() || *left == 0) { self.cancel(); return; }
        player.send_action_bar(std::to_string((*left)--) + "...");
    });
}

Planned

Worker jobs with priority lanes and counters, parallel loops, posting work to the tick of one level or the owner of an entity, and background work on immutable world snapshots.