Skip to content

Run Timing

Quick Start: Spice it up with twists.

Triggers plus the options that shape them: start timing, chance, execution, intervals, and delays.

The commands run on these triggers:

Value Trigger
ON_START Once when the match starts (runs for all participants)
INTERVAL On a fixed interval that starts counting when the game begins
ON_MOB_KILLED When a participating player kills a mob or other non-player entity (never players)
ON_PLAYER_KILLS, ON_HUNTER_KILLS, ON_SPEEDRUNNER_KILLS When a participating player kills another player (variants fire for hunter/speedrunner killers only)
ON_BLOCK_BROKEN, ON_BLOCK_PLACED When a participating player breaks or places a block (runs for the acting player only)
ON_RIGHT_CLICK, ON_LEFT_CLICK When a participating player presses right or left click, main hand only (runs for the clicker only)
ON_CRAFT_PREPARE, ON_CRAFT When a participating player previews a recipe result or lands a craft (runs for the crafter only)
ON_NETHER_ENTER When a participating player enters the Nether (once per player per match)
ON_END_ENTER When a participating player enters the End (once per player per match)
ON_FIRST_NETHER_ENTER When the first participating player enters the Nether (once per match)
ON_FIRST_END_ENTER When the first participating player enters the End (once per match)
ON_EVERY_ADVANCEMENT When a participating player earns an advancement the engine announces (recipe book unlocks and hidden advancements excluded)
ON_RESPAWN, ON_SPEEDRUNNER_RESPAWN, ON_HUNTER_RESPAWN When a player is back in play after respawning (only the executing player; fires once per life, after headstart and respawn holds release; variants fire for their role only)
ON_DAMAGE_TAKEN When a player takes damage from any source (runs for the damaged player only)
ON_DEATH When a participant dies (runs for the dead player only; <args:0> is the exact dead-player name, <args:1> is the exact killer name or null; elimination kills from <loseplayer> and lethal max health skip it, observe those with ON_ELIM)
ON_DISCONNECT When a match member disconnects, eliminated by it or not (runs for the quitter only; <args:0> is the exact quitter name, <args:1> is the quitter role; there are no hunter/speedrunner variants)
ON_ELIM, ON_SPEEDRUNNER_ELIM, ON_HUNTER_ELIM When a participant is eliminated, by death, removal, or disconnect (runs for the eliminated player only; <args:0> is the exact eliminated-player name, <args:1> is the former role; variants fire for their side only)
ON_CLEANUP When modifier state must be undone: at match end (console lists once, then every participant), on mid-match toggle-off (same shape), and for one player mid-match on elimination, role switch, or leave (player and role lists only, console skipped)
ON_PLAYER_INPUT paid Every tick the movement vector is nonzero, plus one zero-vector release when it settles (runs for the acting player only; skipped on free)
ON_MOVE Every tick the player's x/y/z spot changed since last tick (runs for the moving player only; rotation never fires)
ON_CROUCH Every tick the player is crouching (runs for the crouching player only)
ON_JUMP Every tick the player holds the jump key (runs for the acting player only)
ON_PGHOST_EXIT When a ghost session ends for any reason except match end (runs for the ghosted player only; quits pass no player, so per-player lists skip)
ON_SHAPESHIFT_EXIT When a shapeshift session ends for any reason except match end (runs for the shifted player only; quits pass no player, so per-player lists skip)

Who runs

  • Nothing runs automatically: if runs-on is omitted or empty, the behavior stays silent. Blocks that only <runblock> calls omit it on purpose.
  • ON_START and INTERVAL run for all participants. Every other event trigger runs the player, hunter, and speedrunner lists only for the player involved.
  • ON_CLEANUP at match end runs console once, then every participant; mid-match it runs the one involved player with console skipped.
  • Eliminations that land while the player is offline run console only: there is no <p> executor, so read the name from <args:0>.
  • Kill triggers see the attributed killer: the vanilla killer when clear, else the last player the victim fought within 8 seconds (lava and fire deaths after combat count). Natural deaths fire no kill trigger and report null as the ON_DEATH killer. To count every kill, enable both ON_MOB_KILLED and ON_PLAYER_KILLS.
  • ON_BLOCK_BROKEN listens at HIGH priority so it observes protection cancels from lower priorities; a cancel from a later priority is a documented residual risk.
  • ON_CRAFT_PREPARE fires on every recipe preview update while the crafter arranges the grid; ON_CRAFT fires once per landed craft, with shift-clicks reporting the per-unit result.

Intercepting Drops

<intercept:item> replaces event drops on the events that allow it: ON_MOB_KILLED, ON_BLOCK_BROKEN, and ON_CRAFT_PREPARE (where it replaces the prepared result slot instead). On ON_BLOCK_PLACED the same payload swaps the placed block instead.

  • The payload is one item or a nested list of [material, qty] items. On ON_CRAFT_PREPARE and ON_BLOCK_PLACED it must be exactly one item: a nested payload warns and keeps the original.
  • On ON_BLOCK_PLACED, air cancels the placement without consuming anything, while qty and item data stay ignored.
  • Replacements keep nothing of the originals, except on ON_BLOCK_BROKEN, where only the primary drop is replaced and every other drop (including container contents) still drops. XP still drops as vanilla computed it everywhere.
  • Using <intercept> in any other block is a blocking validator error; at runtime the tag warns and yields empty outside an interceptable dispatch.
  • Intercepting behaviors run synchronously during the event (their options.delay is ignored with a once-per-match warning), the last evaluated intercept wins across every behavior, and a payload that builds zero valid stacks keeps the original drops.

Lucky blocks, for example:

behavior:
  lucky:
    runs-on:
      - ON_BLOCK_BROKEN
    commands:
      player:
        - <intercept:[[diamond, 3], [tnt, 1]]>

Lucky crafting, for example (prepare takes exactly one item):

behavior:
  lucky_craft:
    runs-on:
      - ON_CRAFT_PREPARE
    commands:
      player:
        - <intercept:[diamond_sword, 1]>

Start Timing

An ON_START modifier can wait out the pre-start window before running:

mods/modifiers/hunter-post-start-speed.yml:

behavior:
  0:
    on-start:
      # BEFORE runs at /manhunt start; AFTER waits until the speedrunner
      # first hits a hunter (or the match force-starts), plus each
      # side's own headstart after that. Defaults to BEFORE.
      pre-start-order: AFTER
  • Only applies when runs-on contains ON_START.
  • When start-on-speedrunner-damage is disabled there is no pre-start window, so both settings run at match start.
  • With headstarts configured, AFTER runs per player: console lists fire once at begin, each side's player lists fire once its own hold lifts (sides with no headstart get theirs at begin, held sides at release). PER_INVOKE chance and picks roll once per side delivery instead of once per match when headstarts split the run.
  • INTERVAL behaviors can fire while an ON_START behavior with AFTER is still waiting. Guard intervals that depend on deferred initialization with a match flag, set after initialization finishes:
behavior:
  init:
    runs-on: [ON_START]
    on-start:
      pre-start-order: AFTER
    commands:
      console:
        - '<runblock:generate-card>'
        - '<gflag:card-ready,true>'
  poll:
    runs-on: [INTERVAL]
    commands:
      console:
        - '<if:"<gflag:card-ready> != true","exit">'
        - '<runblock:check-card>'

Success Chance

Make the modifier run only sometimes:

mods/modifiers/gear-dice.yml:

behavior:
  0:
    options:
      success-chance:
        # Chance to run, from 0.0 (never) to 1.0 (always). This is a fraction,
        # not a percent: use 0.5 for 50%. Defaults to 1.0.
        chance: 0.5
        # PER_INVOKE rolls once for everyone; PER_EXECUTOR rolls the console
        # and each player separately. Defaults to PER_INVOKE.
        behavior: PER_EXECUTOR

Without this section the modifier always runs. The roll happens on every trigger, including each interval firing and ON_CLEANUP.

Command Execution

Run a random line from a command list instead of every line:

mods/modifiers/gear-dice.yml:

behavior:
  0:
    options:
      execution:
        # IN_ORDER runs every line. PICK_RANDOM runs a random few instead.
        # Defaults to IN_ORDER.
        selection: PICK_RANDOM
        pick-random:
          # How many lines to pick. Minimum 1. Defaults to 1.
          count: 1
          # PER_INVOKE picks once for everyone; PER_EXECUTOR picks separately
          # for the console and each player. Defaults to PER_INVOKE.
          behavior: PER_EXECUTOR
  • Applies to each command list on its own. Asking for more lines than the list has runs the whole list.
  • ON_CLEANUP behaviors honor the selection like any trigger, so keep cleanup selection at IN_ORDER unless a random undo is really what you want.

Interval Settings

How often an INTERVAL modifier repeats (only applies with INTERVAL in runs-on):

mods/modifiers/random-mob-spawner.yml:

enabled: false
behavior:
  0:
    runs-on:
      - INTERVAL
    options:
      interval-settings:
        # Interval duration in seconds.
        interval: 60
        # Random spread in seconds. 60 and 15 means every 45 to 75 seconds.
        # Cannot go above interval. Defaults to 0.
        deviation: 15
        # PER_INVOKE shares one timer; PER_EXECUTOR gives every player and the
        # console their own timer. Defaults to PER_INVOKE.
        behavior: PER_INVOKE
  • Counting starts when the game actually begins (first damage or force start), not at /manhunt start.
  • With PER_EXECUTOR deviation, each player has their own timer, so players who join mid-match get timed in as well.
  • interval supports decimals, rounded to the nearest tick (1 tick is 0.05 seconds). Values between 0 and 0.05 execute every tick; set 0 or 0.05 for every-tick execution. Negative values disable the modifier.
  • Each firing skips players who cannot play right now: match watchers, dead players waiting on a respawn, and players held in spectator mode. The console list still fires.

Command Delay

Delay the modifier's commands by a number of ticks after they trigger:

mods/modifiers/everyone-gets-beef.yml:

behavior:
  0:
    options:
      delay: 5
  • Applies to start, interval, and event triggers, but never to ON_CLEANUP: cleanup always runs inline, so teardown observes settled state.
  • Positions and roles resolve when the delayed commands fire, not when they trigger. If the match ends before the delay elapses, the commands are dropped.

Line Delays

<delay:seconds,id?> pauses the command list mid-run: the lines after it fire after the pause (seconds as a decimal, at most 600, converted to ticks), while the lines before it run inline:

behavior:
  storm:
    runs-on:
      - ON_START
    commands:
      console:
        - 'say The storm gathers.'
        - '<delay:1.5,storm>'
        - 'summon lightning_bolt 0 64 0'
        - 'say The storm breaks.'
  • The id is optional and names the pending delay: <delaycancel:storm> cancels it instantly, and the lines after it never run.
  • A delay evaluated during any line splits the list after that line (inside <if> branches too); the first delay per line wins.
  • Like behavior delays, positions and roles resolve when the rest fires, and match end drops everything pending. A continuation whose executor left skips silently, while console continuations always fire.
  • Delays and intercepts do not mix: <intercept> lines after a delay never apply, so keep replacements before the pause.

Next Steps