How server and client plugins talk to each other.
Server ↔ Client Communication
Server and client plugins communicate through named channels — a simple message-passing system.
Server → Client
Send to one player
// In a server plugin:
ctx.sendToClient(entityId, "quest-tracker", {
questId: "clear_mine",
progress: 7,
target: 10,
});Broadcast to all players
ctx.broadcastToClients("world-event", {
type: "boss-spawn",
bossName: "Dragon King",
startsIn: 60,
});Receive on client
// In a client plugin:
ctx.on("quest-tracker", function(data) {
ctx.updateWidget(questWidgetId, {
html: "Quest: " + data.questId +
" — " + data.progress + "/" + data.target,
});
});
ctx.on("world-event", function(data) {
if (data.type === "boss-spawn") {
ctx.addLocalChatMessage(
"[EVENT] " + data.bossName + " spawns in " + data.startsIn + "s!"
);
}
});
Client → Server
Send from client
ctx.send("auction-bid", {
itemId: "rare-sword-001",
amount: 500,
});Receive on server
ctx.onClientMessage("auction-bid", (entityId, data) => {
ctx.log.info(Player ${entityId} bid ${data.amount} on ${data.itemId});
ctx.sendToClient(entityId, "auction-result", {
success: true,
message: "Bid placed!",
});
});Best Practices
- Use descriptive channel names —
"auction:bid"not"data" - Always validate on the server — never trust client data
- Keep payloads small — only send what's needed
- Handle missing data — check for undefined/null in handlers