@s2script/sdk 0.8.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/clients.d.ts +36 -0
- package/contracts/README.md +37 -0
- package/contracts/workshop.d.ts +82 -0
- package/dist/cli.js +629 -91
- package/package.json +13 -3
- package/server.d.ts +22 -0
- package/timers.d.ts +39 -0
- package/unsafe.d.ts +35 -0
- package/voice.d.ts +59 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@s2script/sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"license": "MIT OR Apache-2.0",
|
|
5
5
|
"description": "s2script SDK — the builtin capability types (imported as @s2script/sdk/entity, …) plus the `s2s` CLI for building Source 2 / CS2 plugins.",
|
|
6
6
|
"type": "module",
|
|
@@ -30,7 +30,8 @@
|
|
|
30
30
|
"*.d.ts",
|
|
31
31
|
"README.md",
|
|
32
32
|
"LICENSE-MIT",
|
|
33
|
-
"LICENSE-APACHE"
|
|
33
|
+
"LICENSE-APACHE",
|
|
34
|
+
"contracts"
|
|
34
35
|
],
|
|
35
36
|
"exports": {
|
|
36
37
|
"./admin": {
|
|
@@ -111,19 +112,28 @@
|
|
|
111
112
|
"./transmit": {
|
|
112
113
|
"types": "./transmit.d.ts"
|
|
113
114
|
},
|
|
115
|
+
"./unsafe": {
|
|
116
|
+
"types": "./unsafe.d.ts"
|
|
117
|
+
},
|
|
114
118
|
"./usercmd": {
|
|
115
119
|
"types": "./usercmd.d.ts"
|
|
116
120
|
},
|
|
117
121
|
"./usermessages": {
|
|
118
122
|
"types": "./usermessages.d.ts"
|
|
119
123
|
},
|
|
124
|
+
"./voice": {
|
|
125
|
+
"types": "./voice.d.ts"
|
|
126
|
+
},
|
|
120
127
|
"./votes": {
|
|
121
128
|
"types": "./votes.d.ts"
|
|
122
129
|
},
|
|
123
130
|
"./ws": {
|
|
124
131
|
"types": "./ws.d.ts"
|
|
125
132
|
},
|
|
126
|
-
"./package.json": "./package.json"
|
|
133
|
+
"./package.json": "./package.json",
|
|
134
|
+
"./contracts/workshop": {
|
|
135
|
+
"types": "./contracts/workshop.d.ts"
|
|
136
|
+
}
|
|
127
137
|
},
|
|
128
138
|
"repository": {
|
|
129
139
|
"type": "git",
|
package/server.d.ts
CHANGED
|
@@ -35,6 +35,28 @@ export declare const Server: {
|
|
|
35
35
|
min?: number;
|
|
36
36
|
max?: number;
|
|
37
37
|
}): boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Watch a cvar for changes (SourceMod `HookConVarChange`, ModSharp's cvar change hook).
|
|
40
|
+
*
|
|
41
|
+
* `name` is a cvar name, or `"*"` for every cvar. The handler receives the cvar's name and its
|
|
42
|
+
* new and old values as strings — for `"*"` the name tells you which one moved.
|
|
43
|
+
*
|
|
44
|
+
* NOTIFY-only: the engine's global change callback runs **after** the value has been applied, so
|
|
45
|
+
* a handler cannot veto a change; returning anything is ignored. A handler that throws is logged
|
|
46
|
+
* and contained, and the remaining handlers still run.
|
|
47
|
+
*
|
|
48
|
+
* Subscriptions are ledgered — unload removes them whether or not `dispose()` is called.
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* import { Server } from "@s2script/sdk/server";
|
|
52
|
+
* Server.onCvarChange("mp_friendlyfire", (name, next, prev) => {
|
|
53
|
+
* console.log(`${name}: ${prev} -> ${next}`);
|
|
54
|
+
* });
|
|
55
|
+
*/
|
|
56
|
+
onCvarChange(
|
|
57
|
+
name: string,
|
|
58
|
+
handler: (name: string, newValue: string, oldValue: string) => void,
|
|
59
|
+
): { dispose(): void };
|
|
38
60
|
/** The server's configured max client count (`GetMaxClients()`). `0` if unavailable. */
|
|
39
61
|
readonly maxPlayers: number;
|
|
40
62
|
/** The current map name (`GetMapName()`, the BSP). `""` if unavailable. */
|
package/timers.d.ts
CHANGED
|
@@ -20,3 +20,42 @@ export declare function nextFrame(): Promise<void>;
|
|
|
20
20
|
* Only valid inside a threadSleep-capable fiber context.
|
|
21
21
|
*/
|
|
22
22
|
export declare function threadSleep(ms: number): void;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* A live callback timer, returned by {@link after} and {@link every}. Ledgered against the creating
|
|
26
|
+
* plugin: unload kills it whether or not `kill()` was called, so a repeating timer can never outlive
|
|
27
|
+
* its plugin and fire into a dead context.
|
|
28
|
+
*/
|
|
29
|
+
export interface Timer {
|
|
30
|
+
/** False once the timer has fired (one-shot), been killed, or had its plugin unloaded. */
|
|
31
|
+
readonly alive: boolean;
|
|
32
|
+
/** Cancel it. Idempotent — returns false if it was already dead. Safe to call from inside the callback. */
|
|
33
|
+
kill(): boolean;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Run `fn` once after `ms` milliseconds (SourceMod `CreateTimer` without `TIMER_REPEAT`).
|
|
38
|
+
*
|
|
39
|
+
* Prefer {@link delay} when you can `await`; use this when you need something cancellable.
|
|
40
|
+
* A throwing callback is reported and contained — it never kills the frame or the timer system.
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* import { after } from "@s2script/sdk/timers";
|
|
44
|
+
* const t = after(5000, () => console.log("5s later"));
|
|
45
|
+
* t.kill(); // ...unless cancelled first
|
|
46
|
+
*/
|
|
47
|
+
export declare function after(ms: number, fn: () => void): Timer;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Run `fn` every `ms` milliseconds until killed (SourceMod `CreateTimer` with `TIMER_REPEAT`).
|
|
51
|
+
*
|
|
52
|
+
* The next firing is scheduled *after* the callback returns, so a slow callback cannot pile up.
|
|
53
|
+
* `ms` must be greater than 0 — a zero-interval repeat would re-arm every drain and starve the
|
|
54
|
+
* frame, so it throws rather than degrading.
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* import { every } from "@s2script/sdk/timers";
|
|
58
|
+
* const tick = every(1000, () => console.log("tick"));
|
|
59
|
+
* // later: tick.kill();
|
|
60
|
+
*/
|
|
61
|
+
export declare function every(ms: number, fn: () => void): Timer;
|
package/unsafe.d.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @s2script/sdk/unsafe — plugin-declared engine calls. NO runtime code: the engine injects the
|
|
3
|
+
* implementation at load (`__s2pkg_unsafe`).
|
|
4
|
+
*
|
|
5
|
+
* UNSAFE by design. A declared call reaches a real engine function. The framework validates every
|
|
6
|
+
* descriptor at load and degrades a failure to `null`, but it cannot prove your signature or vtable
|
|
7
|
+
* index names the function you meant. Requires manifest `permissions: ["engine:calls"]` AND an
|
|
8
|
+
* operator allow-list entry (see docs/superpowers/specs/2026-07-24-plugin-gamedata-design.md §6).
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* The calls this plugin declares. The base interface is EMPTY — `s2s build` generates
|
|
13
|
+
* `.s2script/gamedata.d.ts`, which augments this from your gamedata's `calls` section.
|
|
14
|
+
*/
|
|
15
|
+
export interface EngineCalls {}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Plugin-declared engine calls, resolved from this plugin's own gamedata.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* import { Engine } from "@s2script/sdk/unsafe";
|
|
22
|
+
* // Resolve ONCE at load — null means the descriptor failed a load-time gate.
|
|
23
|
+
* const ignite = Engine.call("ignite");
|
|
24
|
+
* if (!ignite) console.log(`unavailable: ${Engine.status("ignite")}`);
|
|
25
|
+
*/
|
|
26
|
+
export declare const Engine: {
|
|
27
|
+
/**
|
|
28
|
+
* The declared call, or `null` when its descriptor failed a load-time gate (signature miss,
|
|
29
|
+
* validator rejection, slot outside `.text`, missing platform entry, or the plugin is not
|
|
30
|
+
* operator-allow-listed). Guard once at load; the returned function is a plain callable.
|
|
31
|
+
*/
|
|
32
|
+
call<K extends keyof EngineCalls>(name: K): EngineCalls[K] | null;
|
|
33
|
+
/** Why a descriptor is unavailable; `"available"` when it resolved. For diagnostics/operator reports. */
|
|
34
|
+
status(name: string): string;
|
|
35
|
+
};
|
package/voice.d.ts
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @s2script/sdk/voice — who can hear whom. NO runtime code: the engine injects the implementation
|
|
3
|
+
* at load (`__s2pkg_voice`).
|
|
4
|
+
*
|
|
5
|
+
* Layered UNDER `Client.voiceMuted`: a muted sender is inaudible to everyone regardless of any rule
|
|
6
|
+
* here, so admin moderation always beats a gameplay rule.
|
|
7
|
+
*
|
|
8
|
+
* Rules are declarative state, not a callback. The engine's listen matrix is re-asserted
|
|
9
|
+
* continuously and the underlying hook fires per (receiver, sender) pair, so a per-pair JS callback
|
|
10
|
+
* would run up to 64x64 times per refresh. Set a rule; the shim enforces it.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/** Hot-path measurement counters returned by {@link Voice.stats}. */
|
|
14
|
+
export interface VoiceStats {
|
|
15
|
+
/** Listen-matrix decisions the engine has asked about. */
|
|
16
|
+
calls: number;
|
|
17
|
+
/** Senders currently carrying a merged rule. */
|
|
18
|
+
entries: number;
|
|
19
|
+
/** Times a rule actually silenced a pair. THE effect counter — a rule that never rewrites is not working. */
|
|
20
|
+
rewrites: number;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Per-(receiver, sender) voice hearability.
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* import { Voice } from "@s2script/sdk/voice";
|
|
28
|
+
* // A dead player is heard only by other dead players.
|
|
29
|
+
* Voice.setAudibleTo(deadSlot, otherDeadSlots);
|
|
30
|
+
* // ...and on respawn, hand the slot back to the engine.
|
|
31
|
+
* Voice.reset(deadSlot);
|
|
32
|
+
*/
|
|
33
|
+
export declare const Voice: {
|
|
34
|
+
/**
|
|
35
|
+
* This sender is audible ONLY to `receivers` (0-based slots). An empty array means audible to
|
|
36
|
+
* nobody — distinct from {@link Voice.reset}, which removes the rule and lets the engine decide.
|
|
37
|
+
* Rules from multiple plugins AND-merge, so another plugin can only ever narrow yours, never widen it.
|
|
38
|
+
*
|
|
39
|
+
* A rule is dropped automatically when the sender disconnects: slots are recycled, and a rule is
|
|
40
|
+
* about the player who occupied one, not the seat.
|
|
41
|
+
*
|
|
42
|
+
* Returns `false` — never throws — when the rule was NOT applied: voice control is degraded or its
|
|
43
|
+
* engine hook never installed on this build, `sender` is outside `[0, 64)`, or any element of
|
|
44
|
+
* `receivers` is. Note this differs from {@link import("./transmit").Transmit.setVisibleTo}, which
|
|
45
|
+
* throws `RangeError` on a bad slot; check the return value here rather than relying on a throw.
|
|
46
|
+
*
|
|
47
|
+
* @throws `TypeError` if `receivers` is not an array.
|
|
48
|
+
*/
|
|
49
|
+
setAudibleTo(sender: number, receivers: readonly number[]): boolean;
|
|
50
|
+
/**
|
|
51
|
+
* Drop THIS plugin's rule for `sender`; other plugins' rules survive and are re-merged.
|
|
52
|
+
* `false` when you had no rule for that sender.
|
|
53
|
+
*/
|
|
54
|
+
reset(sender: number): boolean;
|
|
55
|
+
/** Drop every rule this plugin owns. Unload does this automatically. */
|
|
56
|
+
resetAll(): void;
|
|
57
|
+
/** Hot-path counters, or null when the running shim predates this capability. */
|
|
58
|
+
stats(): VoiceStats | null;
|
|
59
|
+
};
|