Katton.after and Katton.every

Katton.after(...) and Katton.every(...) both return a task ID as their result. that id you have to assign yourself:

val taskId = Katton.after(5.seconds) {
    Katton.log.info("five seconds passed!")
}

taskId now holds a number that uniquely identifies this specific scheduled task. later, to cancel it:

Katton.cancel(taskId)

if you never store the return value anywhere, you have no way to cancel that task later (unless you do /katton stop)

Katton.after: runs once

Katton.after(duration) {
    // this code runs ONCE, after `duration` has passed
}
@Katton.command(name = "delayedmessage", permission = "all")
function delayedMessage(sender, args) {
    sender.sendMessage("&7message incoming in 3 seconds")

    Katton.after(3.seconds) {
        sender.sendMessage("&ahere it is!")
    }
}

Katton.every: runs repeatedly

Katton.every(duration) {
    // this code runs EVERY `duration`, forever, until cancelled
}
var repeatingTaskId = 0

@Katton.command(name = "startpinging", permission = "admin")
function startPinging(sender, args) {
    repeatingTaskId = Katton.every(10.seconds) {
        sender.sendMessage("&7Ping!")
    }
}

@Katton.command(name = "stoppinging", permission = "admin")
function stopPinging(sender, args) {
    Katton.cancel(repeatingTaskId)
    sender.sendMessage("&cStopped")
}

notice how repeatingTaskId is declared as a top level var, not a local val inside startPinging. if you declared it as val taskId = Katton.every(...) inside startPinging, it would go out of scope the moment startPinging finishes running, and stopPinging would have no way to reach it. top level variables are shared across every function in the script, which is exactly what you need here

duration units

any number gets a .ticks, .seconds, or .minutes suffix:

20.ticks // 1 second (20 ticks = 1 second in minecraft)
5.seconds // 5 seconds
2.minutes // 2 minutes

var delay = 5
delay.seconds // works on variables too, not just literals

self cancelling repeating tasks

a very common need: "repeat something a x of times, then stop automatically." since Katton.every's callback can see the same top level variables the rest of the script can, you can cancel it from inside itself!:

var countdown = 3
var countdownTaskId = 0

@Katton.command(name = "startcountdown", permission = "admin")
function startCountdown(sender, args) {
    countdown = 3

    countdownTaskId = Katton.every(1.seconds) {
        for (player in Katton.players.all()) {
            player.sendTitle("&e" + countdown, "")
        }

        countdown = countdown - 1

        if (countdown < 0) {
            Katton.cancel(countdownTaskId)
        }
    }
}
  1. countdownTaskId = Katton.every(...), the result of the Katton.every call (its task ID) is stored in countdownTaskId immediately, before the callback has even run once
  2. every second, the callback shows the current countdown value as a title, then goes down by 1
  3. once countdown drops below 0, the callback calls Katton.cancel(countdownTaskId), cancelling itself using the ID that was saved in step 1

this works because countdownTaskId is a top level var, so it's still visible and holds the correct value by the time the callback runs and needs it even though the callback runs after the Katton.every(...) call has already returned and been assigned

for a a example on how to use this, see countodwn timer.

avoid nesting Katton.after inside Katton.every

// probably not what you actaully want
Katton.every(20.ticks) {
    Katton.after(1.seconds) {
        doSomething()
    }
}

this schedules a brand new one second delayed task on every single tick of the first repeating timer and since 20.ticks is only 1 second, that means it makes a new nested task every second, stacking up fast and running doSomething() far more often than intended (and burning through your rate limit quickly). if you want something to happen once a second, just use Katton.every(1.seconds) { ... } directly, you don't need to nest

tasks get cleaned up automatically too

you don't strictly need to cancel every task yourself, Katton automatically cancels all of a script's tasks when:

  • running /katton stop,
  • that script is replaced with /katton import (a new version),
  • that script is deleted,
  • you are no longer the admin,
  • the server restarts,
  • a person with op stops it

manual Katton.cancel is for when you want to stop something early based on your own game logic, like a countdown finishing, or an admin running a "stop the game" command

next