Skip to main content

Events

Plugins subscribe to proxy and game events via ctx.events. Handlers receive a typed payload depending on the event name.

Subscribing

ctx.events.on('game:start', (payload) => {
  // payload is GameStartPayload: { timestamp, mode, map?, gametype, server }
  ctx.client.sendChat(`§a${payload.mode} on ${payload.map ?? '?'}`);
});

// Fire once, then auto-unsubscribe
ctx.events.once('opponent:detected', (payload) => {
  ctx.client.sendChat(`§eOpponent: ${payload.username}`);
});

// Unsubscribe (same function reference as on())
const handler = (p: GameEndPayload) => { /* ... */ };
ctx.events.on('game:end', handler);
ctx.events.off('game:end', handler);

Event list

EventWhen it firesPayload
proxy:readyProxy has startedBaseEventPayload (timestamp)
client:connectedPlayer connected to proxyClientConnectedPayload (username, uuid)
client:disconnectedPlayer disconnectedClientDisconnectedPayload (username, reason?)
game:startGame has started (mode/map known)GameStartPayload (mode, map?, gametype, server)
game:endGame ended (any result)GameEndPayload (mode, map, result, duration, opponents?)
game:victoryPlayer wonGameEndPayload
game:defeatPlayer lostGameEndPayload
game:joinPlayer joined a gameGameJoinPayload (mode, map?, gametype, server)
game:leavePlayer left a gameGameLeavePayload (mode, result?, duration?)
lobby:joinPlayer joined a lobbyLobbyJoinPayload (gametype, lobbyname, server)
lobby:leavePlayer left a lobbyBaseEventPayload
locraw:update/locraw data updatedLocrawUpdatePayload (data, previous?)
server:changeServer changedLocrawUpdatePayload
mode:changeGame mode changedModeChangePayload (newMode, previousMode)
opponent:detectedOpponent detected in gameOpponentDetectedPayload (username, uuid?, mode)
opponent:statsOpponent stats fetchedOpponentStatsPayload (username, uuid, mode, stats)
All payloads extend BaseEventPayload and include timestamp: number.

TypeScript types

Import payload types from @duelsplus/plugin-api for type-safe handlers:
import type { GameStartPayload, OpponentDetectedPayload } from '@duelsplus/plugin-api';

ctx.events.on('game:start', (payload: GameStartPayload) => {
  // payload.mode, payload.map, payload.gametype, payload.server
});
The package uses PluginEventName and PluginEventPayloadMap so on() and once() infer the payload type from the event name.