Guides

Your first Rust plugin

On this page

A Rust plugin is a type that implements rustmc_plugin::Plugin. It is compiled into the server and loaded at start-up. The examples in crates/rustmc-plugins (greeter, protect) are complete plugins you can copy.

1. Depend on the API crate

[dependencies]
rustmc-plugin = { path = "../rustmc-plugin" }

The crate has no dependencies of its own.

2. Say who you are, and what you want

use rustmc_plugin::{Event, Host, Manifest, Outcome, Plugin};
use rustmc_plugin::hook::{HookCall, Mode, Reply};

pub struct Shout;

impl Plugin for Shout {
    fn manifest(&self) -> Manifest {
        Manifest::new("shout", "1.0")
            // Events: an empty list means *all* of them, so name the ones you want.
            .hearing(&["player_joined"])
            // Hooks: none unless named.
            .hooking("command.say", Mode::Prepend)
    }

    fn on(&self, host: &dyn Host, event: &Event) -> Outcome {
        if let Event::PlayerJoined { name, .. } = event {
            host.broadcast(&format!("{name} is here!"));
        }
        Outcome::Continue
    }

    fn hook(&self, _host: &dyn Host, call: HookCall<'_>) -> Reply {
        // `/say hello` becomes `/say HELLO`.
        let mut input = call.input.clone();
        let loud = input.get("rest").and_then(|rest| rest.as_str()).map(str::to_uppercase);
        match loud {
            Some(loud) => {
                input.set("rest", loud);
                Reply::Replace(input)
            }
            None => Reply::Pass,
        }
    }
}

3. Load it

The server loads built-in plugins in crates/rustmc-server/src/plugins.rs, next to greeter and protect:

bus.load(Box::new(Shout))?;
  • Hooks: what Replace means in each mode.
  • Data: use record! to read inputs as typed structs instead of picking fields by hand.
  • Host calls: everything host can do.

From docs/api/guide/rust-plugin.md in the RustMC repository at bbd81209ad.