Hook points

Game events as hook points

Each event is also a hook point with the same name. You can still veto the step it reports, as before, but you can now also run before it, run instead of it, or change what came of it.

For each point the input is a record. Positions are [x, y, z]. A prepend's replacement is the same record with changed fields.

PointInputOutputprependoverrideappend
block_break{player, at, block} (block is what the edit writes: air)bool: the break may go aheadmove the break, or write something other than airrefuse (false) or allow it past the eventrefuse
block_place{player, at, block}boolmove it, or change the block (by name; default state)refuse or allowrefuse
player_interact{player, at} (the block clicked)boolmove the click (any placement beside it moves too)refuse or allowrefuse
damage{victim, attacker?, cause, amount}{damage, raw, resisted, absorbed, health, died}change the blowanswer what it did; nothing is taken offchange what the caller (knockback, thorns, statistics) sees
death{victim, killer?, message}{keep_inventory, keep_experience} (both the keep_inventory rule's answer), or nullreport a different deathreport it yourself; no death screen or message, and null means no drops either, while {keep_inventory, keep_experience} has the game drop what it does not keepruns after the death screen and message, before the drops: say what this one death keeps (null drops and does nothing more)
game_mode_changed{player, mode} (0 survival, 1 creative, 2 adventure, 3 spectator)bool changedchange the modeanswer; nothing changeschange the answer /gamemode reports
player_chat{player, message}{relay, message}change the words (they go out unsigned, "Not Secure", as the game sends any unsigned line)decide whether and what to relaychange that decision
command_run{player?, command, rest}bool runschange the command (a new name is checked for permission again)decide whether it runschange that
player_joined{player, name}string?: the line everybody is toldchange the nameanswer the line (null: none); the event is not firedchange the line
player_left{player, name}string?change the nameanswer the line; the event is not fired; the player is removed regardlesschange the line
player_payload{player, channel, data} (data as hex)nullchange the channel or the byteshandle it yourself (the brand is not recorded, the event not fired)runs after
player_move_block{player, from, to}nullchange what listeners are toldtell nobody, or tell them yourselfruns after
tick{tick}nullchange the countskip the tick for every listening plugin, the game's own rules includedruns after
server_startednullnullruns before any plugin's startstart nothing, tell nobodyruns after
server_stoppingnullnullruns while everything is loaded and unsavedreplace the telling, stopping and saveruns after the save
inventory_click{player, window, slot, button, mode} (the wire's)bool goes aheadchange the clickanswer whether it goes aheadchange that
player_edit{player, world, at, action}bool goes aheadchange what is toldanswer whether it goes aheadchange that
entity_harm{player, target, kind, world, at, cause}bool goes aheadchange what is toldanswer whether it goes aheadchange that
player_swing{player, hand}bool goes aheadswing the other handanswer whether it goes aheadchange that
player_use_item{player, hand}boolanswer the use from the other handanswer whether it goes aheadchange that
player_swap_hands{player, slot} (the hotbar slot, 0-8, that changes places with the off hand: the selected one)boolswap another hotbar slotanswer whether it goes aheadchange that
player_drop_item{player, whole_stack}boolthrow the whole stack, or oneanswer whether it goes aheadchange that
player_hotbar_change{player, from, to} (hotbar slots, 0-8)boolselect another slotanswer whether it goes aheadchange that
item_crafted{player, item, count, recipe}nullchange what is toldtell nobodyrun after it is told
fish_caught{player, item, table}string: the item that comes up, empty for nonechange the catchanswer the catch ("" for nothing)change the answered catch
loot_generated{source, table, player?, entity?, items} (items is [[item, count], ...])[[item, count], ...]: the stacks placedadd or remove stacksanswer the stackschange the answered stacks
advancement_done{player, advancement}nullchange what is toldtell nobodyrun after it is told
statistic_changed{player, stat, key, value, amount}nullchange what is toldtell nobodyrun after it is told
player_resource_pack{player, pack, status}nullchange what is toldtell nobody (the game still acts on the answer)run after it is told
player_respawn{player, world, at}nullchange what is toldtell nobodyrun after it is told
player_pickup_item{player, entity} (the item entity)bool: it is picked upchange what is told (the pickup is the one the game found)answer whether it goes aheadchange that
block_hit{player, world, at, face} (face the wire's number, 0 down to 5 east)bool: the dig goes aheadchange what is told (the dig is the packet's)answer whether it goes aheadchange that
entity_attack{player, target}bool: the blow goes aheadstrike another entityanswer whether it goes aheadchange that
reserved_exploded{world, at, blocks} (blocks is [[x, y, z], ...])nullchange what is toldtell nobodyrun after it is told
ores_exploded{world, at, player, nearby, blocks} (nearby is [[player, distance], ...], blocks is [[at, block], ...])nullchange what is toldtell nobodyrun after it is told
entity_mounted{rider, vehicle}bool: it goes aheadchange what is toldanswer whether it goes aheadchange that
entity_dismounted{rider, vehicle}bool: it goes ahead, where it can be refusedchange what is toldanswer whether it goes aheadchange that
inspect_change{player, name, view, changes} (changes is [[item, count], ...]; the account is not offered)nullchange what is toldtell nobodyrun after it is told
blocks_pushed{world, moved} (moved is [[from, to, block], ...])nullchange what is toldtell nobodyrun after it is told
entity_interact{player, target, hand} (hand is the wire's: 0 main, 1 off)bool: the click goes aheadpoint the click at another entity; the game then acts on that oneanswer whether it goes ahead; the event is not firedchange that
container_change{player, world, at, block, changes} (changes is [[item, count], ...])nullchange what is toldtell nobodyrun after it is told
mob_death{victim, kind, killer?}nullchange what is told (the event's world, at and cause are the creature's own, not the input's)tell nobody; the creature dies either wayrun after it is told
world_changed{player, from, to}nullchange what is toldtell nobody; the player has moved either wayrun after it is told
settings_changed{plugin, key, value} (value is the new value as JSON text)string: why the change was refused; empty when it was keptchange whose setting, which key, or the valueanswer the refusal; nothing is keptchange the answer
network_message{from, channel, payload} (payload as hex)nullchange where it is from, its channel (and so who hears it) or its byteshandle it yourself; no subscriber is toldruns after they are told

settings_changed runs once for each key set, through the portal or setting_set; the event that follows names every key that changed.

Six events have no hook point: player_look, player_input, creature_order_done, creature_sees, creature_damaged and creature_gone. They are told only to the plugin that asked for them (watch_look, watch_input) or that owns the creature, not through the bus.

  • move.player: every position a client reports, before the server judges it. See subsystems.
  • Fall damage goes through damage too, with cause: "minecraft:fall".
  • entity.damage: any living thing's blow, a creature's as well as a player's, asked before damage. See subsystems.
  • death's keep_inventory keeps every item where it is and drops none; keep_experience drops no orbs and carries the bar through the respawn. Each is for that one death, as the rule would.

From docs/api/reference/hooks/game-events.md in the RustMC repository at bbd81209ad.