@s2script/sdk 0.0.1 → 0.3.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/topmenu.d.ts ADDED
@@ -0,0 +1,25 @@
1
+ /** @s2script/topmenu — the extensible admin/top menu registry. NO runtime code (injected at load). */
2
+ export interface TopMenuItem {
3
+ /** Plugin-namespaced unique id, e.g. "playercommands:slap". A duplicate id replaces. */
4
+ id: string;
5
+ /** Shown label. */
6
+ name: string;
7
+ /** Required ADMFLAG bit mask (adminmenu hides items the caller lacks flags for). */
8
+ flags: number;
9
+ /** Runs in THIS plugin's context when an admin selects the item; receives the admin's 0-based slot. */
10
+ onSelect: (adminSlot: number) => void;
11
+ }
12
+ export interface TopMenuSnapshot {
13
+ categories: string[];
14
+ items: { id: string; category: string; name: string; flags: number }[];
15
+ }
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
+ /** All categories + item metadata (no handlers) — the adminmenu renderer reads this. */
22
+ snapshot(): TopMenuSnapshot;
23
+ /** Fire an item's onSelect (dispatched post-frame to the owner's context). */
24
+ select(id: string, slot: number): void;
25
+ };
package/trace.d.ts ADDED
@@ -0,0 +1,67 @@
1
+ /**
2
+ * @s2script/trace — author-time type stubs for the injected ray-tracing API.
3
+ * NO runtime code: the engine injects the implementation (core prelude) at load time.
4
+ *
5
+ * ENGINE-GENERIC (Source-2 physics) — over `CNavPhysicsInterface::TraceShape`, RTTI-resolved
6
+ * shim-side. Degrades to a MISS `TraceHit` (`didHit:false, fraction:1, entity:null`) when the
7
+ * underlying vtable can't be resolved (a different Source 2 game build, or in-isolate tests) —
8
+ * never a crash.
9
+ */
10
+ import type { Vector, QAngle } from "./math";
11
+ import type { EntityRef } from "./entity";
12
+
13
+ /** Named `InteractionLayers` bitmasks for `TraceOptions.mask`/`exclude` (bitwise-OR combinable). */
14
+ export declare const TraceMask: {
15
+ /** World + player-clip + windows + players/NPCs/physics-props — a bullet trace (the default). */
16
+ readonly ShotPhysics: number;
17
+ /** Hitboxes only (headshot-style detection). */
18
+ readonly ShotHitbox: number;
19
+ /** Physics + hitboxes (a full bullet trace: world geometry AND hitbox precision). */
20
+ readonly ShotFull: number;
21
+ /** World geometry only, no entities at all. */
22
+ readonly WorldOnly: number;
23
+ /** Grenade trajectory trace (world + physics props, no players). */
24
+ readonly Grenade: number;
25
+ /** Brushes only (no clip volumes, no entities). */
26
+ readonly BrushOnly: number;
27
+ /** Player movement collision (world + player-clip). */
28
+ readonly PlayerMove: number;
29
+ /** NPC movement collision (world + npc-clip). */
30
+ readonly NPCMove: number;
31
+ };
32
+
33
+ /** The result of a `Trace.line`/`ray`/`hull` call. */
34
+ export interface TraceHit {
35
+ /** True iff the trace hit something before reaching `endPos`. */
36
+ didHit: boolean;
37
+ /** 0..1 — the fraction of the start->end segment traveled before the hit (1 = no hit). */
38
+ fraction: number;
39
+ /** The trace's final position (the hit point, or the requested end on a miss). */
40
+ endPos: Vector;
41
+ /** The surface normal at the hit point ((0,0,0) on a miss). */
42
+ normal: Vector;
43
+ /** The hit entity, or null if none was hit (or it went stale in the same frame). */
44
+ entity: EntityRef | null;
45
+ /** True iff the trace STARTED embedded in solid geometry (Source `startsolid`; CS2's CGameTrace
46
+ * exposes only `m_bStartInSolid`, not a whole-segment `allsolid` flag — don't confuse with SM's TR_AllSolid). */
47
+ startSolid: boolean;
48
+ }
49
+
50
+ /** Options shared by `Trace.line`/`ray`/`hull`. */
51
+ export interface TraceOptions {
52
+ /** `InteractionLayers` bits the trace should interact with. Default `TraceMask.ShotPhysics`. */
53
+ mask?: number;
54
+ /** `InteractionLayers` bits to explicitly exclude. Default 0 (none). */
55
+ exclude?: number;
56
+ /** An entity to ignore (e.g. the tracing pawn itself, for `pawn.aimTrace`'s self-ignore). */
57
+ ignoreEntity?: EntityRef;
58
+ }
59
+
60
+ export declare const Trace: {
61
+ /** A line trace from `start` to `end`. */
62
+ line(start: Vector, end: Vector, opts?: TraceOptions): TraceHit;
63
+ /** A line trace from `start` along `angles`' forward direction, `distance` units long. */
64
+ ray(start: Vector, angles: QAngle, distance: number, opts?: TraceOptions): TraceHit;
65
+ /** A swept-box (hull) trace from `start` to `end` with the given `mins`/`maxs` extents. */
66
+ hull(start: Vector, end: Vector, mins: Vector, maxs: Vector, opts?: TraceOptions): TraceHit;
67
+ };
@@ -0,0 +1,10 @@
1
+ /** @s2script/translations — SourceMod-style i18n (per-client language, phrase files, {1} formatting). */
2
+ export type Phrases = Record<string, string>;
3
+ export declare const Translations: {
4
+ /** Register a phrase set: `seed` is the built-in English default; translations/<code>/<name>.phrases.json overrides per language. */
5
+ load(name: string, seed: Phrases): void;
6
+ /** Translate `key` for `slot`'s language (slot < 0 = the server default), substituting positional {1}/{2} args. */
7
+ translate(slot: number, key: string, ...args: (string | number)[]): string;
8
+ /** Set the server/console default language code (default "" = root/English). */
9
+ setDefaultLanguage(code: string): void;
10
+ };
package/transmit.d.ts ADDED
@@ -0,0 +1,32 @@
1
+ /** @s2script/transmit — per-client entity visibility filtering (Source2 CheckTransmit).
2
+ * Declarative rules: a plugin says "this entity is visible only to these viewer slots" and the
3
+ * engine-side hook enforces it every snapshot — zero JS runs in the per-client hot path. */
4
+ import type { EntityRef } from "./entity";
5
+
6
+ export interface TransmitStats {
7
+ /** CheckTransmit invocations observed since load/reset. */
8
+ snapshots: number;
9
+ /** Live rule entries in the native table. */
10
+ entries: number;
11
+ /** Total transmit bits cleared since load/reset. */
12
+ bitsCleared: number;
13
+ /** Nanoseconds spent in the post-hook, last invocation. */
14
+ nsLast: number;
15
+ /** Worst single invocation (ns) since load/reset. */
16
+ nsMax: number;
17
+ }
18
+
19
+ export declare const Transmit: {
20
+ /** Replace this plugin's visibility rule for `entity`: it is transmitted ONLY to the given viewer
21
+ * slots (an empty array = hidden from everyone). Multiple plugins AND-merge — an entity reaches a
22
+ * viewer only if every plugin holding a rule on it allows that viewer. Returns false if the ref is
23
+ * stale or the capability is unavailable/disabled. Throws RangeError on a slot outside [0, 64). */
24
+ setVisibleTo(entity: EntityRef, viewers: readonly number[]): boolean;
25
+ /** Remove this plugin's rule for `entity` (visible to all again, as far as this plugin is
26
+ * concerned). Returns false if the ref is stale or the capability is unavailable. */
27
+ reset(entity: EntityRef): boolean;
28
+ /** Remove all of this plugin's rules. */
29
+ resetAll(): void;
30
+ /** Hot-path counters for measurement/debugging. */
31
+ stats(): TransmitStats;
32
+ };
package/usercmd.d.ts ADDED
@@ -0,0 +1,51 @@
1
+ /**
2
+ * @s2script/usercmd — a SourceMod `OnPlayerRunCmd`-equivalent: intercept, read, modify, and block a
3
+ * player's per-tick input (buttons, view angles, movement, impulse) before the game processes it.
4
+ * NO runtime code (injected at load) — `CBaseUserCmdPB`/`CMsgQAngle`/`CInButtonStatePB` are a
5
+ * Source2-shared concept (`usercmd.proto`), so this module is engine-generic.
6
+ */
7
+ import type { QAngle } from "./math";
8
+ import type { HookResultValue } from "./events";
9
+
10
+ /**
11
+ * A block-scoped view of the CURRENT tick's usercmd (valid only during a `UserCmd.onRun` handler —
12
+ * a stashed `Cmd` used after the handler returns, or across an `await`, reads/writes nothing).
13
+ * There is exactly ONE `Cmd` instance for the whole process; every handler call operates on it.
14
+ */
15
+ export interface Cmd {
16
+ /** +forward / -back. Normalized to roughly [-1, 1] (not the legacy ±450 units). */
17
+ forwardMove: number;
18
+ /**
19
+ * +right / -left (SourceMod convention). Assigning MODIFIES the live input.
20
+ * Note: internally negated from the raw protobuf `leftmove` (which is +LEFT) — this field is
21
+ * already sign-corrected, so `sideMove > 0` always means "moving right".
22
+ */
23
+ sideMove: number;
24
+ /** +up / -down (e.g. crouch-jump analog). */
25
+ upMove: number;
26
+ /** The pressed impulse (e.g. 100 = +usering). */
27
+ impulse: number;
28
+ /** The pressed-button mask (`IN_*` bit values, mirrors `pawn.buttons`). 64-bit — always a real `bigint`. */
29
+ buttons: bigint;
30
+ /** View angles for this tick ({x: pitch, y: yaw, z: roll}). Assigning writes all three fields. */
31
+ viewAngles: QAngle;
32
+ /**
33
+ * Drop this tick's subtick analog-move deltas (optional helper). A coarse `forwardMove`/`sideMove`/
34
+ * `upMove` write already takes effect without this (live-verified) — call it only if you need to
35
+ * make sure no residual subtick analog data survives your modify. No-op if there are none.
36
+ */
37
+ clearSubtickMoves(): void;
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
+ };
@@ -0,0 +1,49 @@
1
+ import type { HookResultValue } from "./events";
2
+
3
+ /** A general protobuf user-message builder. Build then send in one synchronous burst. */
4
+ export class UserMessage {
5
+ constructor(name: string);
6
+ setInt(field: string, value: number): this;
7
+ setFloat(field: string, value: number): this;
8
+ setString(field: string, value: string): this;
9
+ setBool(field: string, value: boolean): this;
10
+ /** Infer the setter from the JS value type. */
11
+ set(field: string, value: number | string | boolean): this;
12
+ /** Send to one slot or a list of slots. Returns true if delivered to >=1 real client. */
13
+ send(slots: number | number[]): boolean;
14
+ /** Broadcast to all connected non-bot clients. */
15
+ sendAll(): boolean;
16
+ }
17
+
18
+ // --- UserMessage interception (usermsg-hook slice) ---
19
+
20
+ /** A BLOCK-SCOPED view of an intercepted outbound user message — valid only during a
21
+ * UserMessages.onPre handler; across an await (or stashed) all reads return null/[]/"". */
22
+ export interface UserMessageView {
23
+ /** Canonical unscoped message name (e.g. "CMsgTEFireBullets"). */
24
+ readonly name: string;
25
+ /** Numeric network-message id (e.g. 452). */
26
+ readonly id: number;
27
+ /** Recipient slots (0-based) this post targets; a broadcast decodes to all live slots. Read-only in v1. */
28
+ readonly recipients: number[];
29
+ /** protobuf TextFormat dump — the documented FALLBACK for unmapped messages only; prefer typed reads. */
30
+ readonly debugString: string;
31
+ hasField(path: string): boolean;
32
+ /** Scalar int read (int32/uint32/fixed32/enum; bool as 0/1). Dotted nested paths supported
33
+ * ("origin.x" walks sub-messages). null = no such field / repeated / no current message. */
34
+ readInt(path: string): number | null;
35
+ readFloat(path: string): number | null;
36
+ readBool(path: string): boolean | null;
37
+ readString(path: string): string | null;
38
+ }
39
+
40
+ export declare const UserMessages: {
41
+ /** Pre-hook an outbound user message by unscoped name (partial match, SayText2-style; the view
42
+ * carries the canonical name). Runs SYNCHRONOUSLY before delivery. Return >= HookResult.Handled
43
+ * to SUPPRESS the send for every recipient; Continue/undefined passes it through. THROWS at
44
+ * subscribe time on an unresolvable name or a degraded intercept descriptor. */
45
+ onPre(name: string, handler: (msg: UserMessageView) => HookResultValue | void): void;
46
+ /** Removes ALL of the calling plugin's handlers for this name (mux off semantics — handler
47
+ * identity not compared, matching Events.off). */
48
+ off(name: string, handler?: (msg: UserMessageView) => HookResultValue | void): void;
49
+ };
package/votes.d.ts ADDED
@@ -0,0 +1,23 @@
1
+ /** @s2script/votes — chat-ballot voting with revote + an optional live center tally. NO runtime code (injected at load). */
2
+ export interface VoteResult { readonly winner: number | null; readonly counts: number[]; readonly total: number; }
3
+ export interface VoteConfig {
4
+ question: string;
5
+ /** 2..9 options (chat votes are single-digit). */
6
+ options: string[];
7
+ /** seconds. */
8
+ duration: number;
9
+ /** show a live center tally (default false — the SM chat-only way). */
10
+ showLiveTally?: boolean;
11
+ onEnd: (result: VoteResult) => void;
12
+ }
13
+ export interface VoteTally { question: string; options: { label: string; count: number }[]; total: number; secondsLeft: number; }
14
+ export interface VoteTallyRenderer { show(slot: number, tally: VoteTally): void; clear(slot: number): void; }
15
+ export declare const Vote: {
16
+ /** Start a vote (chat ballot to all connected players). Returns false if one is already active. */
17
+ start(config: VoteConfig): boolean;
18
+ isActive(): boolean;
19
+ /** Abort the active vote (no onEnd). */
20
+ cancel(): void;
21
+ /** Register the live-tally renderer (the CS2 center-HTML renderer). */
22
+ registerTallyRenderer(renderer: VoteTallyRenderer): void;
23
+ };
package/ws.d.ts ADDED
@@ -0,0 +1,12 @@
1
+ /** @s2script/ws — client WebSocket. NO runtime code (injected as __s2pkg_ws). */
2
+ export interface WebSocket {
3
+ onMessage(handler: (data: string) => void): void;
4
+ onClose(handler: (code: number, reason: string) => void): void;
5
+ onError(handler: (err: string) => void): void;
6
+ send(data: string): void;
7
+ close(): void;
8
+ }
9
+ export declare const WebSocket: {
10
+ /** Connect to a WebSocket server (wss:// for TLS). Resolves on the open handshake; rejects on connect failure. */
11
+ connect(url: string): Promise<WebSocket>;
12
+ };