@s2script/sdk 0.3.0 → 0.5.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/chat.d.ts +0 -7
- package/clients.d.ts +0 -18
- package/commands.d.ts +1 -4
- package/config.d.ts +3 -3
- package/cookies.d.ts +0 -3
- package/damage.d.ts +0 -5
- package/dist/cli.js +494 -135
- package/entity.d.ts +21 -36
- package/events.d.ts +0 -13
- package/interfaces.d.ts +1 -24
- package/package.json +7 -5
- package/plugin.d.ts +112 -0
- package/plugins.d.ts +11 -1
- package/server.d.ts +0 -7
- package/sound.d.ts +0 -4
- package/topmenu.d.ts +0 -4
- package/usercmd.d.ts +5 -18
- package/frame.d.ts +0 -13
package/entity.d.ts
CHANGED
|
@@ -2,21 +2,28 @@
|
|
|
2
2
|
* @s2script/entity — author-time type stubs for the injected entity API.
|
|
3
3
|
* NO runtime code: the engine injects the implementation at load time.
|
|
4
4
|
*/
|
|
5
|
-
import type { HookResultValue } from "./events";
|
|
6
5
|
|
|
7
6
|
/**
|
|
8
|
-
* A
|
|
9
|
-
*
|
|
10
|
-
*
|
|
7
|
+
* A host-liveness-gated handle to a live entity. `id` is a HOST-MINTED monotonic liveness
|
|
8
|
+
* id — liveness is decided by the host's books (fed by engine create/delete notifications,
|
|
9
|
+
* cleared at map transition), NEVER by reading the entity's own memory. Every access
|
|
10
|
+
* re-resolves: books first, then identity-slot validation, instance last. A stale ref
|
|
11
|
+
* degrades to null/false — including across a changelevel.
|
|
12
|
+
*
|
|
13
|
+
* The framework mints every `EntityRef`; plugin code never constructs one (the constructor
|
|
14
|
+
* is intentionally not part of the public surface — a hand-built ref is the "raw ref across
|
|
15
|
+
* time" footgun). Obtain refs from the engine (events, `findByClass`, `readHandle`, …).
|
|
11
16
|
*/
|
|
12
17
|
export declare class EntityRef {
|
|
13
18
|
readonly index: number;
|
|
14
|
-
|
|
19
|
+
/** The host-minted liveness id for this ref (books key). Not the raw engine serial. */
|
|
20
|
+
readonly id: number;
|
|
15
21
|
/** This entity's targetname (`CEntityIdentity::m_name`) — e.g. a map trigger's `"map_start"`. `""` if
|
|
16
22
|
* the entity has no targetname; `null` if the ref is stale/invalid. */
|
|
17
23
|
readonly name: string | null;
|
|
18
|
-
|
|
19
|
-
|
|
24
|
+
/** @internal The host mints refs; this is not part of the public API surface. */
|
|
25
|
+
private constructor();
|
|
26
|
+
/** True iff the host's books say live AND the identity slot still matches. */
|
|
20
27
|
isValid(): boolean;
|
|
21
28
|
/** Read an i32 at `offset` bytes into the entity, or null if the ref is stale. */
|
|
22
29
|
readInt32(offset: number): number | null;
|
|
@@ -68,9 +75,9 @@ export declare class EntityRef {
|
|
|
68
75
|
* is null. */
|
|
69
76
|
readFloatsChain(ptrOffs: number[], finalOff: number, count: number): number[] | null;
|
|
70
77
|
/** Follow a pointer chain (each an offset), then read a scalar at `finalOff`. null if the root is stale or any
|
|
71
|
-
* hop is null. `readHandleVia` decodes a handle field → a
|
|
78
|
+
* hop is null. `readHandleVia` decodes a handle field → a liveness-gated EntityRef; vectors use readFloatsChain. */
|
|
72
79
|
readInt32Via(pathOffs: number[], finalOff: number): number | null;
|
|
73
|
-
/** Write an int32 at the end of a pointer chain (each hop deref'd,
|
|
80
|
+
/** Write an int32 at the end of a pointer chain (each hop deref'd, liveness-gated at the root). Returns
|
|
74
81
|
* false on a stale ref or a null hop. Used to clear a flag on a pointer-referenced sub-object. */
|
|
75
82
|
writeInt32Via(pathOffs: number[], finalOff: number, value: number): boolean;
|
|
76
83
|
readInt8Via(pathOffs: number[], finalOff: number): number | null;
|
|
@@ -83,7 +90,7 @@ export declare class EntityRef {
|
|
|
83
90
|
readUInt64Via(pathOffs: number[], finalOff: number): bigint | null;
|
|
84
91
|
readInt64Via(pathOffs: number[], finalOff: number): bigint | null;
|
|
85
92
|
readHandleVia(pathOffs: number[], finalOff: number): EntityRef | null;
|
|
86
|
-
/** Write a scalar through a pointer chain (write mirror of `read*Via`).
|
|
93
|
+
/** Write a scalar through a pointer chain (write mirror of `read*Via`). Liveness-gated at the root;
|
|
87
94
|
* returns false on a stale ref, an unresolved hop, or a bad offset/kind. Does NOT notifyStateChanged —
|
|
88
95
|
* the caller decides (many sub-object fields, e.g. the fire gate, are server-authoritative).
|
|
89
96
|
* (`writeInt32Via` is declared above alongside `readInt32Via`.) */
|
|
@@ -93,6 +100,8 @@ export declare class EntityRef {
|
|
|
93
100
|
readHandle(offset: number): EntityRef | null;
|
|
94
101
|
/** Notify the engine that the field at `offset` changed (triggers network replication). No-op if stale. */
|
|
95
102
|
notifyStateChanged(offset: number): void;
|
|
103
|
+
/** Raw identity-slot flags (engine m_flags), or null when stale/unavailable. Bit meanings are game-specific. */
|
|
104
|
+
identityFlags(): number | null;
|
|
96
105
|
/** DispatchSpawn this created entity. With keyvalues, the entity's own Spawn() parses them (the
|
|
97
106
|
* SourceMod DispatchKeyValue / CSSharp DispatchSpawn(kv) mechanism). Returns false if stale,
|
|
98
107
|
* unresolved, or the keyvalue map is rejected (non-finite number, unsupported value type, empty
|
|
@@ -109,7 +118,7 @@ export declare class EntityRef {
|
|
|
109
118
|
* `trigger_multiple` needs a model to build the physics volume that fires touch. Returns false
|
|
110
119
|
* if the op is unavailable or the ref is stale. */
|
|
111
120
|
setModel(name: string): boolean;
|
|
112
|
-
/** Read a CUtlVector<CHandle> at (ptrOffs chain -> vectorOff) as live
|
|
121
|
+
/** Read a CUtlVector<CHandle> at (ptrOffs chain -> vectorOff) as live liveness-gated EntityRefs.
|
|
113
122
|
* Follows the pointer chain, reads count@+0 / elements@+8, caps at maxCount. [] if stale/unresolved. */
|
|
114
123
|
readHandleVector(ptrOffs: number[], vectorOff: number, maxCount?: number): EntityRef[];
|
|
115
124
|
/** Fire an entity input (e.g. "Kill"/"Ignite"/"SetHealth"/"Enable"/"Open"/"FireUser1"/"AddOutput")
|
|
@@ -146,31 +155,7 @@ export interface OutputEvent {
|
|
|
146
155
|
delay: number;
|
|
147
156
|
}
|
|
148
157
|
|
|
149
|
-
/**
|
|
150
|
-
* Hook Source 2 entity outputs (`func_button`→`OnPressed`, `trigger_multiple`→`OnStartTouch`,
|
|
151
|
-
* `logic_relay`→`OnTrigger`, …) via a `FireOutputInternal` detour. `classname`/`output` accept `"*"`
|
|
152
|
-
* wildcards. The handler runs SYNCHRONOUSLY (may block): returning a `HookResultValue >= Handled`
|
|
153
|
-
* (2/3) SUPPRESSES the output — the original `FireOutputInternal` call is skipped.
|
|
154
|
-
*/
|
|
155
158
|
export declare const Entity: {
|
|
156
|
-
|
|
157
|
-
/**
|
|
158
|
-
* Fire when the engine CREATES an entity of `className` (`"*"` = all) — earliest hook; the entity is
|
|
159
|
-
* barely constructed, schema fields may be zero/default. The handler receives the serial-gated
|
|
160
|
-
* `entity` (may be `null`) plus its `className`. Prefer `onSpawn` to read fields.
|
|
161
|
-
*/
|
|
162
|
-
onCreate(className: string, handler: (entity: EntityRef | null, className: string) => void): void;
|
|
163
|
-
/**
|
|
164
|
-
* Fire after the engine SPAWNS an entity of `className` (`"*"` = all) — `Spawn()` has run, so schema
|
|
165
|
-
* fields/keyvalues are populated. The useful hook for reading state.
|
|
166
|
-
*/
|
|
167
|
-
onSpawn(className: string, handler: (entity: EntityRef | null, className: string) => void): void;
|
|
168
|
-
/**
|
|
169
|
-
* Fire as the engine DELETES an entity of `className` (`"*"` = all). The entity is still readable
|
|
170
|
-
* during the synchronous handler; a stashed ref reads `null` once the slot is freed (serial gate),
|
|
171
|
-
* never garbage.
|
|
172
|
-
*/
|
|
173
|
-
onDelete(className: string, handler: (entity: EntityRef | null, className: string) => void): void;
|
|
174
|
-
/** Find every entity whose designer-name (class) exactly matches `className`. Returns serial-gated refs. */
|
|
159
|
+
/** Find every entity whose designer-name (class) exactly matches `className`. Returns liveness-gated refs. */
|
|
175
160
|
findByClass(className: string): EntityRef[];
|
|
176
161
|
};
|
package/events.d.ts
CHANGED
|
@@ -26,19 +26,6 @@ export declare const HookResult: { readonly Continue: 0; readonly Changed: 1; re
|
|
|
26
26
|
export type HookResultValue = 0 | 1 | 2 | 3;
|
|
27
27
|
|
|
28
28
|
export declare const Events: {
|
|
29
|
-
/** Subscribe to a game event by name. The handler runs synchronously when the event fires. */
|
|
30
|
-
on(name: string, handler: (ev: GameEvent) => void): void;
|
|
31
|
-
/**
|
|
32
|
-
* Unsubscribe from a game event by name.
|
|
33
|
-
*
|
|
34
|
-
* **Note:** `off` removes ALL of the calling plugin's handlers for the given event name —
|
|
35
|
-
* handler identity is NOT compared. This matches the engine-op semantics: the mux removes
|
|
36
|
-
* every subscription the current plugin holds for `name` in one call. Avoid double-subscribing
|
|
37
|
-
* the same name with different handlers if you need selective removal.
|
|
38
|
-
*/
|
|
39
|
-
off(name: string, handler: (ev: GameEvent) => void): void;
|
|
40
|
-
/** Pre-hook: runs before the event broadcasts; may read+modify `ev` and return a HookResult to block. */
|
|
41
|
-
onPre(name: string, handler: (ev: GameEvent) => HookResultValue | void): void;
|
|
42
29
|
/** Fire a game event. Returns the engine FireEvent result. */
|
|
43
30
|
fire(name: string, fields?: Record<string, number | string | boolean | bigint>, dontBroadcast?: boolean): boolean;
|
|
44
31
|
/** Fire a game event to ONE client (SourceMod FireToClient). Same field type-inference as `fire`. Returns false on miss. */
|
package/interfaces.d.ts
CHANGED
|
@@ -4,33 +4,10 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
* Handle returned by
|
|
7
|
+
* Handle returned by `ctx.publish(name, impl)`: lets the producer emit forwarded
|
|
8
8
|
* events to every plugin subscribed to this interface via its `on(event, …)`.
|
|
9
9
|
*/
|
|
10
10
|
export interface PublishHandle {
|
|
11
11
|
/** Emit a forwarded event to all consumers subscribed via `interface.on(event, …)`. */
|
|
12
12
|
emit(event: string, payload: unknown): void;
|
|
13
13
|
}
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Publish a typed inter-plugin interface under `name`. `impl`'s methods become the
|
|
17
|
-
* natives consumers call (`interface.method(...)`); the returned handle's `emit` fans
|
|
18
|
-
* forwarded events out to consumers' `on(event, …)` subscriptions.
|
|
19
|
-
*
|
|
20
|
-
* The interface's VERSION is injected by the host from this plugin's manifest
|
|
21
|
-
* `publishes` map — never passed here, and never written in TypeScript source.
|
|
22
|
-
* Publishing a name the manifest does not declare is refused at load.
|
|
23
|
-
*
|
|
24
|
-
* `impl` is generic over `object` rather than `Record<string, Function>` so that a
|
|
25
|
-
* producer can bind it to its contract — `const impl: Zones = {…}` — which is what
|
|
26
|
-
* actually proves the implementation matches the published `.d.ts`. A TypeScript
|
|
27
|
-
* `interface` has no implicit index signature (only a `type` alias does), so a
|
|
28
|
-
* `Record<…>` parameter would reject every interface-typed contract. The host
|
|
29
|
-
* enumerates `impl`'s own function properties; non-function properties are ignored.
|
|
30
|
-
*
|
|
31
|
-
* Auto-ledgered: the interface is withdrawn (and hard-dep consumers degraded) on unload.
|
|
32
|
-
*/
|
|
33
|
-
export declare function publishInterface<T extends object>(
|
|
34
|
-
name: string,
|
|
35
|
-
impl: T,
|
|
36
|
-
): PublishHandle;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@s2script/sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "s2script SDK — the builtin capability types (imported as @s2script/sdk/entity, …) plus the `s2s` CLI for building Source 2 / CS2 plugins.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -14,7 +14,9 @@
|
|
|
14
14
|
"dependencies": {
|
|
15
15
|
"esbuild": "^0.25.0",
|
|
16
16
|
"adm-zip": "^0.5.16",
|
|
17
|
-
"typescript": "^5.6.0"
|
|
17
|
+
"typescript": "^5.6.0",
|
|
18
|
+
"eslint": "^10.7.0",
|
|
19
|
+
"@s2script/eslint-plugin": "0.2.0"
|
|
18
20
|
},
|
|
19
21
|
"devDependencies": {
|
|
20
22
|
"@types/adm-zip": "^0.5.7"
|
|
@@ -64,9 +66,6 @@
|
|
|
64
66
|
"./events": {
|
|
65
67
|
"types": "./events.d.ts"
|
|
66
68
|
},
|
|
67
|
-
"./frame": {
|
|
68
|
-
"types": "./frame.d.ts"
|
|
69
|
-
},
|
|
70
69
|
"./http": {
|
|
71
70
|
"types": "./http.d.ts"
|
|
72
71
|
},
|
|
@@ -82,6 +81,9 @@
|
|
|
82
81
|
"./net": {
|
|
83
82
|
"types": "./net.d.ts"
|
|
84
83
|
},
|
|
84
|
+
"./plugin": {
|
|
85
|
+
"types": "./plugin.d.ts"
|
|
86
|
+
},
|
|
85
87
|
"./plugins": {
|
|
86
88
|
"types": "./plugins.d.ts"
|
|
87
89
|
},
|
package/plugin.d.ts
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @s2script/sdk/plugin — the typed plugin artifact: `plugin(factory)`, the load-scoped `PluginContext`,
|
|
3
|
+
* and `Scope`. NO runtime code: the engine injects the implementation at load time
|
|
4
|
+
* (`__s2pkg_plugin`, resolved via the existing `@s2script/sdk/*` prefix strip).
|
|
5
|
+
*
|
|
6
|
+
* See docs/superpowers/specs/2026-07-20-L1-lifecycle-v2-design.md §1-§3 for the full contract.
|
|
7
|
+
*/
|
|
8
|
+
import type { GameEvent, HookResultValue } from "./events";
|
|
9
|
+
import type { Client } from "./clients";
|
|
10
|
+
import type { EntityRef, OutputEvent } from "./entity";
|
|
11
|
+
import type { DamageInfo } from "./damage";
|
|
12
|
+
import type { CommandInvocation } from "./commands";
|
|
13
|
+
import type { Config } from "./config";
|
|
14
|
+
import type { PublishHandle } from "./interfaces";
|
|
15
|
+
import type { TopMenuItem } from "./topmenu";
|
|
16
|
+
import type { PrecacheContext } from "./sound";
|
|
17
|
+
import type { UserCmdView } from "./usercmd";
|
|
18
|
+
|
|
19
|
+
export interface CtxEvents {
|
|
20
|
+
on(name: string, handler: (ev: GameEvent) => void): void;
|
|
21
|
+
onPre(name: string, handler: (ev: GameEvent) => HookResultValue | void): void;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Handlers fire for clients that connect AFTER Active. To cover already-connected clients, seed
|
|
25
|
+
* explicitly in the factory: `for (const c of Clients.all()) { … }` — there is no framework
|
|
26
|
+
* replay (replaying `onConnect` for pre-existing clients would fire auth/ban/reservation logic
|
|
27
|
+
* out of its real order).
|
|
28
|
+
*/
|
|
29
|
+
export interface CtxClients {
|
|
30
|
+
onConnect(handler: (client: Client) => void | Promise<void>): void;
|
|
31
|
+
onPutInServer(handler: (client: Client) => void | Promise<void>): void;
|
|
32
|
+
onActive(handler: (client: Client) => void | Promise<void>): void;
|
|
33
|
+
onFullyConnect(handler: (client: Client) => void | Promise<void>): void;
|
|
34
|
+
onDisconnect(handler: (client: Client) => void): void;
|
|
35
|
+
onSettingsChanged(handler: (client: Client) => void): void;
|
|
36
|
+
onVoice(handler: (client: Client) => void): void;
|
|
37
|
+
onCookiesCached(handler: (client: Client) => void): void;
|
|
38
|
+
onSay(handler: (slot: number, text: string, teamonly: boolean) => HookResultValue | void): void;
|
|
39
|
+
onRunCmd(handler: (cmd: UserCmdView, info: { slot: number }) => HookResultValue | void): void;
|
|
40
|
+
}
|
|
41
|
+
export interface CtxEntities {
|
|
42
|
+
onCreate(className: string, handler: (entity: EntityRef | null, className: string) => void): void;
|
|
43
|
+
onSpawn(className: string, handler: (entity: EntityRef | null, className: string) => void): void;
|
|
44
|
+
onDelete(className: string, handler: (entity: EntityRef | null, className: string) => void): void;
|
|
45
|
+
onOutput(classname: string, output: string, handler: (ev: OutputEvent) => HookResultValue | void): void;
|
|
46
|
+
onDamage(handler: (info: DamageInfo) => HookResultValue | void): void;
|
|
47
|
+
}
|
|
48
|
+
export interface CtxServer {
|
|
49
|
+
onGameFrame(fn: () => void, opts?: { priority?: "high" | "normal" | "low" | "monitor" }): void;
|
|
50
|
+
onMapStart(handler: (mapName: string) => void): void;
|
|
51
|
+
onPrecache(handler: (pc: PrecacheContext) => void): void;
|
|
52
|
+
}
|
|
53
|
+
export interface CtxCommands {
|
|
54
|
+
register(name: string, handler: (cmd: CommandInvocation) => void): void;
|
|
55
|
+
registerServer(name: string, handler: (cmd: CommandInvocation) => void): void;
|
|
56
|
+
registerAdmin(name: string, flags: number, handler: (cmd: CommandInvocation) => void): void;
|
|
57
|
+
}
|
|
58
|
+
export interface CtxConfig { onChange(handler: (cfg: Config) => void): void; }
|
|
59
|
+
export interface CtxTopMenu {
|
|
60
|
+
addCategory(name: string): void;
|
|
61
|
+
addItem(category: string, item: TopMenuItem): void;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** A producer-backed inter-plugin interface: its methods, plus forward subscriptions. */
|
|
65
|
+
export type InterfaceHandle<T extends object> = T & {
|
|
66
|
+
/** Subscribe to a producer forward. Load-window only (buffered, armed at Active) — like every registration. */
|
|
67
|
+
on(event: string, handler: (payload: any) => void): void;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
export interface Scope {
|
|
71
|
+
readonly events: CtxEvents;
|
|
72
|
+
readonly clients: CtxClients;
|
|
73
|
+
readonly entities: CtxEntities;
|
|
74
|
+
readonly server: CtxServer;
|
|
75
|
+
/** Remove every subscription this scope holds; the scope stays usable (re-register on next open). */
|
|
76
|
+
clear(): void;
|
|
77
|
+
/** clear() + permanently retire the scope. Idempotent. */
|
|
78
|
+
dispose(): void;
|
|
79
|
+
readonly disposed: boolean;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export interface PluginContext {
|
|
83
|
+
/** This plugin's id (manifest `id`). */
|
|
84
|
+
readonly id: string;
|
|
85
|
+
/** The revived hot-reload handoff (the previous instance's `state()` return), or undefined. */
|
|
86
|
+
readonly previous: unknown;
|
|
87
|
+
readonly events: CtxEvents;
|
|
88
|
+
readonly clients: CtxClients;
|
|
89
|
+
readonly entities: CtxEntities;
|
|
90
|
+
readonly server: CtxServer;
|
|
91
|
+
readonly commands: CtxCommands;
|
|
92
|
+
readonly config: CtxConfig;
|
|
93
|
+
readonly topmenu: CtxTopMenu;
|
|
94
|
+
/** Publish this plugin's manifest-declared interface. Buffered; goes live at Active. */
|
|
95
|
+
publish<T extends object>(name: string, impl: T): PublishHandle;
|
|
96
|
+
/** Resolve a HARD dep (must be in `pluginDependencies`). Immediate — the proxy is callable inside the factory. */
|
|
97
|
+
use<T extends object>(name: string): InterfaceHandle<T>;
|
|
98
|
+
/** Resolve an OPTIONAL dep (must be in `optionalPluginDependencies`); null while unpublished. */
|
|
99
|
+
tryUse<T extends object>(name: string): InterfaceHandle<T> | null;
|
|
100
|
+
/** Allocate a disposable subscription scope (load-window only — the capability originates at load). */
|
|
101
|
+
createScope(): Scope;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export interface PluginHooks {
|
|
105
|
+
/** Best-effort cleanup at unload (the ledger remains the teardown authority). */
|
|
106
|
+
onUnload?(): void;
|
|
107
|
+
/** Hot-reload handoff capture; JSON-serialized (EntityRef-aware) and revived as the next instance's ctx.previous. */
|
|
108
|
+
state?(): unknown;
|
|
109
|
+
}
|
|
110
|
+
export type PluginFactory = (ctx: PluginContext) => void | PluginHooks | Promise<void | PluginHooks>;
|
|
111
|
+
export interface PluginDefinition { readonly __s2plugin: 1; }
|
|
112
|
+
export declare function plugin(factory: PluginFactory): PluginDefinition;
|
package/plugins.d.ts
CHANGED
|
@@ -2,8 +2,18 @@
|
|
|
2
2
|
export interface PluginInfo {
|
|
3
3
|
/** the plugin id (from its manifest). */
|
|
4
4
|
readonly id: string;
|
|
5
|
-
/** true = running; false =
|
|
5
|
+
/** true = running; false = not running (loading, waiting, failed, or manually unloaded). Exactly
|
|
6
|
+
* `state === "running"`. */
|
|
6
7
|
readonly loaded: boolean;
|
|
8
|
+
/** the plugin's lifecycle state (L1 lifecycle v2):
|
|
9
|
+
* - `"running"` — Active (factory settled, armed).
|
|
10
|
+
* - `"loading"` — an in-flight factory load (async factory not yet settled).
|
|
11
|
+
* - `"waiting"` — parked until a hard-dependency producer is published (or a ~30s timeout).
|
|
12
|
+
* - `"failed"` — the load failed (bad artifact, throwing/rejecting factory, publishes mismatch,
|
|
13
|
+
* or a load timeout); the plugin is NOT running.
|
|
14
|
+
* - `"unloaded"` — on disk but manually unloaded via `unload` (not auto-reloaded until `load`/`reload`).
|
|
15
|
+
*/
|
|
16
|
+
readonly state: "running" | "loading" | "waiting" | "failed" | "unloaded";
|
|
7
17
|
}
|
|
8
18
|
export declare const Plugins: {
|
|
9
19
|
/** Every loaded/unloaded plugin. */
|
package/server.d.ts
CHANGED
|
@@ -27,13 +27,6 @@ export declare const Server: {
|
|
|
27
27
|
min?: number;
|
|
28
28
|
max?: number;
|
|
29
29
|
}): boolean;
|
|
30
|
-
/**
|
|
31
|
-
* Subscribe to map start (fires on every server map startup — the framework event that replaces
|
|
32
|
-
* polling `Server.mapName` on OnGameFrame). Boot-loaded plugins receive the first map's fire;
|
|
33
|
-
* a plugin hot-loaded mid-map does NOT get a synthetic fire for the current map — read
|
|
34
|
-
* `Server.mapName` at load. Torn down automatically on plugin unload.
|
|
35
|
-
*/
|
|
36
|
-
onMapStart(handler: (mapName: string) => void): void;
|
|
37
30
|
/** The server's configured max client count (`GetMaxClients()`). `0` if unavailable. */
|
|
38
31
|
readonly maxPlayers: number;
|
|
39
32
|
/** The current map name (`GetMapName()`, the BSP). `""` if unavailable. */
|
package/sound.d.ts
CHANGED
|
@@ -28,8 +28,4 @@ export declare const Sound: {
|
|
|
28
28
|
* function / stale source entity / an empty `recipients` array). An all-bot-skipped recipient
|
|
29
29
|
* set still emits to nobody (a real engine call, may return a nonzero GUID). */
|
|
30
30
|
emit(name: string, opts?: SoundEmitOptions): number;
|
|
31
|
-
/** Subscribe to the session resource-manifest build (fires at map load / mapchange). Register
|
|
32
|
-
* custom .vsndevts/.vsnd content here so a later emit can play it. A plugin hot-loaded mid-map
|
|
33
|
-
* gets its first fire at the NEXT map change. */
|
|
34
|
-
onPrecache(handler: (ctx: PrecacheContext) => void): void;
|
|
35
31
|
};
|
package/topmenu.d.ts
CHANGED
|
@@ -14,10 +14,6 @@ export interface TopMenuSnapshot {
|
|
|
14
14
|
items: { id: string; category: string; name: string; flags: number }[];
|
|
15
15
|
}
|
|
16
16
|
export declare const TopMenu: {
|
|
17
|
-
/** Register a category (idempotent; order = first-registration order). */
|
|
18
|
-
addCategory(name: string): void;
|
|
19
|
-
/** Register/replace an item under a category (auto-creates the category). */
|
|
20
|
-
addItem(category: string, item: TopMenuItem): void;
|
|
21
17
|
/** All categories + item metadata (no handlers) — the adminmenu renderer reads this. */
|
|
22
18
|
snapshot(): TopMenuSnapshot;
|
|
23
19
|
/** Fire an item's onSelect (dispatched post-frame to the owner's context). */
|
package/usercmd.d.ts
CHANGED
|
@@ -5,14 +5,14 @@
|
|
|
5
5
|
* Source2-shared concept (`usercmd.proto`), so this module is engine-generic.
|
|
6
6
|
*/
|
|
7
7
|
import type { QAngle } from "./math";
|
|
8
|
-
import type { HookResultValue } from "./events";
|
|
9
8
|
|
|
10
9
|
/**
|
|
11
|
-
* A block-scoped view of the CURRENT tick's usercmd (valid only during a `
|
|
12
|
-
* a stashed `
|
|
13
|
-
* There is exactly ONE `
|
|
10
|
+
* A block-scoped view of the CURRENT tick's usercmd (valid only during a `ctx.clients.onRunCmd`
|
|
11
|
+
* handler — a stashed `UserCmdView` used after the handler returns, or across an `await`,
|
|
12
|
+
* reads/writes nothing). There is exactly ONE `UserCmdView` instance for the whole process; every
|
|
13
|
+
* handler call operates on it.
|
|
14
14
|
*/
|
|
15
|
-
export interface
|
|
15
|
+
export interface UserCmdView {
|
|
16
16
|
/** +forward / -back. Normalized to roughly [-1, 1] (not the legacy ±450 units). */
|
|
17
17
|
forwardMove: number;
|
|
18
18
|
/**
|
|
@@ -36,16 +36,3 @@ export interface Cmd {
|
|
|
36
36
|
*/
|
|
37
37
|
clearSubtickMoves(): void;
|
|
38
38
|
}
|
|
39
|
-
|
|
40
|
-
export declare const UserCmd: {
|
|
41
|
-
/**
|
|
42
|
-
* Subscribe to the per-tick input hook. The handler runs SYNCHRONOUSLY during the engine's
|
|
43
|
-
* usercmd processing, once per player per batched tick; `cmd` is the singleton, block-scoped
|
|
44
|
-
* current usercmd and `ctx.slot` is the firing player's 0-based slot.
|
|
45
|
-
*
|
|
46
|
-
* Return a `HookResultValue >= Handled` to SUPPRESS this tick's input (the game processes a
|
|
47
|
-
* zeroed/idle command instead); return `Continue`/`undefined` to let the (possibly modified)
|
|
48
|
-
* command through unblocked.
|
|
49
|
-
*/
|
|
50
|
-
onRun(handler: (cmd: Cmd, ctx: { slot: number }) => HookResultValue | void): void;
|
|
51
|
-
};
|
package/frame.d.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @s2script/frame — author-time type stubs for the per-frame subscription API.
|
|
3
|
-
* NO runtime code: the engine injects the implementation at load time.
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
export interface SubscribeOptions {
|
|
7
|
-
priority?: number;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export declare const OnGameFrame: {
|
|
11
|
-
/** Register a callback that fires every game frame. */
|
|
12
|
-
subscribe(fn: () => void, opts?: SubscribeOptions): void;
|
|
13
|
-
};
|