Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Delayed tasks

A server mod asks for a call back after some server ticks with schedule_task, the stand-in for vanilla's MinecraftServer.tell(new TickTask(getTickCount() + delay, runnable)). A closure cannot cross into a wasm mod or outlive the host a hook borrows, so the callback is a hook: the mod passes a u64 token and Hooks::scheduled_task hands it back.

const REMINDER: u64 = 1;

impl Hooks for MyMod {
    fn player_logged_in(&self, host: &mut dyn ServerHost, player: u128, name: &str) {
        // 20 server ticks from now: one second at the normal rate.
        if let Ok(id) = host.schedule_task(20, REMINDER) {
            // Keep `id` if the reminder may need to be withdrawn: host.cancel_task(id).
        }
    }

    fn scheduled_task(&self, host: &mut dyn ServerHost, id: TaskId, owner: &str, token: u64) {
        if owner != "mymod" || token != REMINDER {
            return; // every mod is asked about every task
        }
        // The task has fired and its id is spent.
    }
}
CallMeaning
host.schedule_task(delay_ticks, token) -> Result<TaskId, ScheduleError>A task due delay_ticks server ticks from now. 0 and 1 both mean the next tick.
host.cancel_task(id) -> boolWithdraws a task. True only if it is yours and still waiting.
Hooks::scheduled_task(host, id, owner, token)The callback, on the server thread.

Timing. Delays count ticks the server runs: a paused integrated server does not advance them. A task fires at the start of its due tick, right after server_tick's start phase, in the order the tasks were scheduled. A task never fires in the tick that scheduled it, whichever hook scheduled it, the tick's start hook and scheduled_task itself included: it fires on a later tick.

Ownership. The task belongs to the mod whose hook called schedule_task; the game takes that from the running hook, never from an argument. Outside a mod's hook the call returns ScheduleError::NotInMod. cancel_task answers false for another mod's id, an unknown one, and one that has fired or been cancelled. Every mod hears scheduled_task for every due task, so a mod compares owner with its own id and ignores the rest. Ids are never reused in a world.

Limits. A mod may have MAX_PENDING_TASKS (4096) tasks waiting; the next schedule_task returns ScheduleError::TooMany until one fires or is cancelled. A task that panics does not drop the others due on the same tick: they still run, and the panic goes on afterwards as any hook's does.

Lifetime. The queue belongs to the running world. It is dropped when the world opens or closes (including a failed open or close), and is never saved. A mod that must outlive a restart writes its deadline to its own storage and schedules again when the world opens. A mod's tasks are not cancelled when the mod unloads; the world's close is the end of them.