Search docs
Search modules and symbols
Authoring plugins

Authoring plugins

A plugin is an ordinary npm package that export defaults a plugin(…) definition and builds to a .s2sp archive. Author-time types come from @s2script/sdk (engine-generic capabilities) and @s2script/cs2 (CS2 game types); the engine injects the runtime at load.

Scaffold

npx @s2script/sdk create my-plugin --game cs2
cd my-plugin
npm install
npm run build          # runs `s2s build .`

s2s is the CLI shipped in @s2script/sdk. create writes a package.json, a strict tsconfig.json, an ESLint config (the same pinned rules s2s build enforces, so violations are red squiggles in your editor), and a starter src/plugin.ts.

Drop the resulting .s2sp into addons/s2script/plugins/. The runtime watches that directory: drop → load, replace → hot-reload, delete → unload.

The plugin shape

A plugin’s body runs once at load with a PluginContext. Register everything through ctx — subscriptions are ledgered and torn down for you on unload.

import { plugin } from '@s2script/sdk/plugin';
import { Chat } from '@s2script/sdk/chat';
import { Player } from '@s2script/cs2';

export default plugin((ctx) => {
	ctx.commands.register('hello', (cmd) => {
		cmd.reply(`hi from slot ${cmd.callerSlot}`);
	});

	ctx.clients.onActive((client) => {
		Chat.toSlot(client.slot, 'Welcome!');
	});
});

ctx groups the load-scoped capabilities: ctx.commands, ctx.events, ctx.clients, ctx.entities, ctx.server, ctx.config, ctx.topmenu, plus ctx.use / ctx.publish for inter-plugin interfaces. Stateless helpers — Chat, Player, Admin, config — are plain named imports.

Imports

Every built-in capability is a subpath of the one @s2script/sdk package; CS2 APIs live in @s2script/cs2:

import { plugin } from '@s2script/sdk/plugin';
import { Events, HookResult } from '@s2script/sdk/events';
import { config } from '@s2script/sdk/config';
import { Player, ChatColors } from '@s2script/cs2';

Add @s2script/sdk (and @s2script/cs2 for CS2 plugins) to your package’s dependencies. Browse every subpath in the package reference.

package.json

Standard npm fields, plus an optional s2script block for engine facts:

{
	"name": "@demo/hello",
	"version": "0.1.0",
	"main": "src/plugin.ts",
	"dependencies": {
		"@s2script/sdk": "^0.5.0",
		"@s2script/cs2": "^0.7.0"
	},
	"s2script": {
		"config": {
			"greeting": { "type": "string", "default": "hello", "description": "Chat greeting" }
		},
		"pluginDependencies": { "@demo/greeter": "^1.0.0" },
		"publishes": { "@demo/hello": "1.0.0" }
	}
}
  • dependencies — npm build deps (@s2script/sdk, @s2script/cs2, your own libs)
  • s2script.configtyped config materialized at load
  • s2script.pluginDependencies — hard inter-plugin deps you ctx.use
  • s2script.publishes — interfaces you ctx.publish for other plugins

Typecheck gate

s2s build typechecks strictly against the shipped @s2script/sdk / @s2script/cs2 .d.ts files and refuses to emit a .s2sp on any error. A failing file-watch reload leaves the running plugin untouched.

Next

s2script — Source 2 plugin framework

GitHub