Concepts
Hooks
On this page
A hook point is a place where the server takes one of the game's own steps, such as running a command, sending a packet or breaking a block. Each step is written as a function from an input to an output:
input ──prepend*──▶ input′ ──override? or the game's own step──▶ output ──append*──▶ output′
A plugin subscribes to a hook point in one or more modes:
| Mode | Runs | Is shown | May answer Reply::Replace(..) with | Then |
|---|---|---|---|---|
prepend | before the step | the input | a new input | the step runs on the new input |
override | instead of the step | the input | the output | the game's own step does not run |
append | after the step | the input and the output | a new output | the caller gets the new output |
Answering Reply::Pass changes nothing. A plugin that does nothing at a hook point must
answer Pass, which is the trait's default.
Several plugins at one point
Plugins run in priority order (First, Early, Normal, Late, Observer). Within a
priority, they run in load order.
- Prepends chain. Each prepend sees the input the previous one left.
- The first override wins. Overrides are asked in order. The first one to answer
Replacesupplies the output, and the rest are not asked. If none answers, the game's own step runs. - Appends chain. Each append sees the output the previous one left.
A plugin subscribed in several modes at one point is called once per mode, in the order prepend, override, append.
Subscribing
Manifest::new("x", "1")
.hooking("command.time", Mode::Override) // one point
.hooking("packet.play.*", Mode::Append) // a family: a prefix ending in ".*"
.hooking("*", Mode::Prepend) // every point
A prefix pattern must end at a dot. packet.pl* matches nothing.
The call
pub struct HookCall<'a> {
pub point: &'a str, // e.g. "command.time"
pub mode: Mode,
pub input: &'a Data, // what the step runs (or would run) on
pub output: Option<&'a Data>, // Some only for an append
}
The input and output are Data. Each point's shape is listed in the
hook point reference.
Cancelling
There is no separate "cancel". To cancel a step, override it with an output that means "did
not happen". For a command that is false; for a clientbound packet it is [] (nothing
written); for a serverbound packet it is {"handled": false, "reply": []}.
A wrong answer is refused, not obeyed
If a reply does not fit the point's type (a missing field, a string where a number belongs, a negative count where only positive ones exist), the server logs it once and keeps the value it would have replaced. See Guarantees.
From docs/api/concepts/hooks.md in the RustMC repository at bbd81209ad.