Trigger plugin code with the /scriptevent command, and send messages between plugins.
A script event is a named message delivered to every plugin. Anyone who can run the /scriptevent command can send one, and so can a plugin. They are the simplest way to:
- give operators a way to trigger plugin code without registering a full command,
- let the terminal poke a plugin, for example from a maintenance script,
- pass messages from one plugin to another.
Receiving
Section titled “Receiving”Subscribe to system.afterEvents.scriptEventReceive:
import { system, world } from "@minecraft/server";
system.afterEvents.scriptEventReceive.subscribe((event) => { if (event.id !== "event:start") return; world.sendMessage(`§6The event is starting! ${event.message}`);});Then, as an operator or from the terminal:
/scriptevent event:start Meet at spawnThe event has four fields:
| Field | Meaning |
|---|---|
id |
The message id: the first word after /scriptevent. |
message |
Everything after the id, as one string. Empty if nothing was given. |
sourceType |
ScriptEventSource.Entity when a player ran the command, ScriptEventSource.Server when the terminal or a plugin sent it. |
sourceEntity |
The player who ran the command. undefined otherwise. |
Every plugin receives every script event, so always check id first and ignore what is not yours. Use a namespace of your own before the colon to avoid clashing with other plugins.
Sending from the command
Section titled “Sending from the command”/scriptevent <messageId> [message]/scriptevent is an operator command and also works in the terminal, without the slash. The message is free text; it is up to the plugin to make sense of it.
Handling several ids
Section titled “Handling several ids”A small dispatcher keeps things tidy when one plugin handles several events:
import { system, world, ScriptEventSource, Player } from "@minecraft/server";
const handlers: Record<string, (message: string, player?: Player) => void> = { "arena:open": () => world.sendMessage("§aThe arena is open."), "arena:close": () => world.sendMessage("§cThe arena is closed."), "arena:say": (message) => world.sendMessage(`§7[Arena] ${message}`), "arena:whoami": (_message, player) => player?.sendMessage(`You are ${player.name}`),};
system.afterEvents.scriptEventReceive.subscribe((event) => { const handler = handlers[event.id]; if (!handler) return;
const player = event.sourceType === ScriptEventSource.Entity && event.sourceEntity instanceof Player ? event.sourceEntity : undefined; handler(event.message, player);});Structured messages
Section titled “Structured messages”The message is a string. To pass more than one value, send JSON and parse it, guarding against input that is not valid:
import { system, world } from "@minecraft/server";
system.afterEvents.scriptEventReceive.subscribe((event) => { if (event.id !== "shop:setprice") return; try { const { item, price } = JSON.parse(event.message); world.setDynamicProperty(`shop:price:${item}`, Number(price)); } catch { console.warn(`shop:setprice needs JSON, got: ${event.message}`); }});/scriptevent shop:setprice {"item":"diamond","price":25}Sending from a plugin
Section titled “Sending from a plugin”system.sendScriptEvent sends a script event from code. Every plugin’s scriptEventReceive handlers hear it, including the sender’s own, with sourceType set to ScriptEventSource.Server.
import { system, world } from "@minecraft/server";
world.afterEvents.playerSpawn.subscribe(({ player, initialSpawn }) => { if (!initialSpawn) return; system.sendScriptEvent("economy:joined", JSON.stringify({ name: player.name }));});Another plugin can then react without either plugin importing the other:
import { system } from "@minecraft/server";
system.afterEvents.scriptEventReceive.subscribe((event) => { if (event.id !== "economy:joined") return; const { name } = JSON.parse(event.message); console.log(`Rewards plugin noticed ${name} joining`);});The id passed to sendScriptEvent must have a namespace (namespace:name); without one the call throws.
This is the recommended way for plugins to talk to each other. Plugins cannot import one another’s files, and dynamic properties are private to each plugin.
Script event or custom command?
Section titled “Script event or custom command?”| Use a script event when | Use a custom command when |
|---|---|
| The trigger is for operators, automation or other plugins | Ordinary players will run it |
| A free-text message is enough | You want typed parameters and auto-complete |
| You want something quick to wire up | You want it listed in /help with a description |
Script events are operator-only when sent by command, so they are not a way to give regular players a command.
After events only
Section titled “After events only”scriptEventReceive is an after event: it is delivered once the command has finished, and there is nothing to cancel. Because of that, handlers can read and change the world freely, with none of the restrictions of before events.