Generated from the shipped type definitions.
Game-event subscriptions on this plugin's load-scope (PluginContext.events).
on(name: string, handler: (ev: GameEvent) => void): void
Subscribe to a fired game event (post-phase). The GameEvent is valid only synchronously.
// plugins/disabled/nextmap/src/plugin.ts:133
ctx.events.on("round_end", () => console.log("round ended"));
onPre(name: string, handler: (ev: GameEvent) => HookResultValue | void): void
— Pre-hook a game event: return a HookResultValue (Handled/Stop suppress the client broadcast). Handlers fire for clients that connect AFTER Active. To cover already-connected clients, seed
explicitly in the factory: for (const c of Clients.all()) { … } — there is no framework
replay (replaying onConnect for pre-existing clients would fire auth/ban/reservation logic
out of its real order).
onConnect(handler: (client: Client) => void | Promise<void>): void
— A client began connecting (pre-auth).onPutInServer(handler: (client: Client) => void | Promise<void>): void
— A client's entity was put in the server (ClientPutInServer).onActive(handler: (client: Client) => void | Promise<void>): void
— A client became fully active (in-game, receiving snapshots).onFullyConnect(handler: (client: Client) => void | Promise<void>): void
— A client finished authenticating (Steam ticket validated).onDisconnect(handler: (client: Client) => void): void
— A client disconnected.onSettingsChanged(handler: (client: Client) => void): void
— A client's convars/settings changed (ClientSettingsChanged).onVoice(handler: (client: Client) => void): void
— A client sent a voice packet (per-frame while speaking).onCookiesCached(handler: (client: Client) => void): void
— A client's persisted cookies finished loading and are now readable.onSay(handler: (slot: number, text: string, teamonly: boolean) => HookResultValue | void): void
A client sent chat: return a HookResultValue to suppress it.
- teamonly
- team-channel say.
onRunCmd(handler: (cmd: UserCmdView, info: { slot: number }) => HookResultValue | void): void
— Per-tick usercmd hook (SM OnPlayerRunCmd): read/modify UserCmdView; return Handled to block the tick. Entity lifecycle + damage subscriptions on this plugin's load-scope (PluginContext.entities).
onCreate(className: string, handler: (entity: EntityRef | null, className: string) => void): void
An entity of className was created (not yet spawned).
- className
- match, or
"*" for all.
onSpawn(className: string, handler: (entity: EntityRef | null, className: string) => void): void
— An entity of className spawned (post-DispatchSpawn).onDelete(className: string, handler: (entity: EntityRef | null, className: string) => void): void
— An entity of className is being deleted; the ref goes stale right after.onOutput(classname: string, output: string, handler: (ev: OutputEvent) => HookResultValue | void): void
— Hook a named entity output (FireOutputInternal); return a HookResultValue to suppress it.onDamage(handler: (info: DamageInfo) => HookResultValue | void): void
Damage pre-hook (SDKHooks-equivalent): read/modify DamageInfo; return Handled semantics via info.
// plugins/basecommands/src/plugin.ts:81 — halve incoming damage
ctx.entities.onDamage((info) => { info.damage = info.damage / 2; });
Per-frame + map/precache hooks on this plugin's load-scope (PluginContext.server).
onGameFrame(fn: () => void, opts?: { priority?: "high" | "normal" | "low" | "monitor" }): void
Run fn every game frame.
- opts
priority orders it within the frame (monitor runs last, read-only).
onMapStart(handler: (mapName: string) => void): void
— A new map became live; mapName is the BSP name.onPrecache(handler: (pc: PrecacheContext) => void): void
— Precache window — register models/sounds to precache for the current map. Console/chat command registration on this plugin's load-scope (PluginContext.commands).
register(name: string, handler: (cmd: CommandInvocation) => void): void
— Register a public command (any client may run it).registerServer(name: string, handler: (cmd: CommandInvocation) => void): void
— Register a server-only command (console/rcon, not client-runnable).registerAdmin(name: string, flags: number, handler: (cmd: CommandInvocation) => void): void
— Register an admin command gated by flags (an ADMFLAG bitmask; fail-safe default-deny). Config live-reload subscription on this plugin's load-scope (PluginContext.config).
onChange(handler: (cfg: Config) => void): void
— Fires when the plugin's config file is re-materialized on disk; re-read values inside. TopMenu (adminmenu) contribution on this plugin's load-scope (PluginContext.topmenu).
addCategory(name: string): void
— Add (or reuse) a top-level menu category.addItem(category: string, item: TopMenuItem): void
— Add an item under an existing category. A producer-backed inter-plugin interface: its methods, plus forward subscriptions.
A disposable bundle of subscriptions (PluginContext.createScope). Registering through a scope
lets you drop the whole group at once with Scope.clear without unloading the plugin.
readonly events: CtxEvents
— Game-event subscriptions bound to this scope.readonly clients: CtxClients
— Client-lifecycle subscriptions bound to this scope.readonly entities: CtxEntities
— Entity/damage subscriptions bound to this scope.readonly server: CtxServer
— Per-frame/map subscriptions bound to this scope. — Remove every subscription this scope holds; the scope stays usable (re-register on next open). — clear() + permanently retire the scope. Idempotent. readonly disposed: boolean
— True once Scope.dispose has run. The load-scoped context passed to a plugin's PluginFactory. Its sub-objects register every
subscription; all registration is load-window only (buffered, armed at Active).
— This plugin's id (manifest id). readonly previous: unknown
— The revived hot-reload handoff (the previous instance's state() return), or undefined.readonly events: CtxEvents
— Game-event subscriptions (CtxEvents).readonly clients: CtxClients
— Client-lifecycle subscriptions (CtxClients).readonly entities: CtxEntities
— Entity/damage subscriptions (CtxEntities).readonly server: CtxServer
— Per-frame/map/precache subscriptions (CtxServer).readonly commands: CtxCommands
— Console/chat command registration (CtxCommands).readonly config: CtxConfig
— Config live-reload subscription (CtxConfig).readonly topmenu: CtxTopMenu
— TopMenu (adminmenu) contribution (CtxTopMenu).publish(name: string, impl: T): PublishHandle
— Publish this plugin's manifest-declared interface. Buffered; goes live at Active.use(name: string): InterfaceHandle<T>
— Resolve a HARD dep (must be in pluginDependencies). Immediate — the proxy is callable inside the factory.tryUse(name: string): InterfaceHandle<T> | null
— Resolve an OPTIONAL dep (must be in optionalPluginDependencies); null while unpublished. — Allocate a disposable subscription scope (load-window only — the capability originates at load). Optional lifecycle hooks a PluginFactory may return to participate in unload + hot-reload.
— Best-effort cleanup at unload (the ledger remains the teardown authority). — Hot-reload handoff capture; JSON-serialized (EntityRef-aware) and revived as the next instance's ctx.previous. A plugin's body: called once at load with the PluginContext, optionally returning
PluginHooks. May be async (the load waits for it to settle).
The opaque artifact plugin returns; a module must export default it to be a valid plugin.
— Brand tag proving this object came from plugin (host-checked at load). fn plugin(factory: PluginFactory): PluginDefinition
Define a plugin from its factory. export default the result — the host calls the factory once at load.
import { plugin } from "@s2script/sdk/plugin";
// examples/greeter-plugin/src/plugin.ts:8
export default plugin((ctx) => {
const handle = ctx.publish("@demo/greeter", impl);
ctx.server.onGameFrame(() => handle.emit("greeted", { slot: 0 }));
});