@helix3/helix-sdk 0.1.1-helix3.20
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/LICENSE +21 -0
- package/README.md +128 -0
- package/dist/camera.d.ts +14 -0
- package/dist/camera.js +72 -0
- package/dist/camera.js.map +1 -0
- package/dist/index.d.ts +131 -0
- package/dist/index.js +704 -0
- package/dist/index.js.map +1 -0
- package/dist/multiplayer-contract/credential.d.ts +42 -0
- package/dist/multiplayer-contract/credential.js +5 -0
- package/dist/multiplayer-contract/credential.js.map +1 -0
- package/dist/multiplayer-contract/index.d.ts +14 -0
- package/dist/multiplayer-contract/index.js +30 -0
- package/dist/multiplayer-contract/index.js.map +1 -0
- package/dist/multiplayer-contract/messages.d.ts +284 -0
- package/dist/multiplayer-contract/messages.js +111 -0
- package/dist/multiplayer-contract/messages.js.map +1 -0
- package/dist/multiplayer-contract/room.d.ts +126 -0
- package/dist/multiplayer-contract/room.js +17 -0
- package/dist/multiplayer-contract/room.js.map +1 -0
- package/dist/multiplayer-contract/state.d.ts +61 -0
- package/dist/multiplayer-contract/state.js +15 -0
- package/dist/multiplayer-contract/state.js.map +1 -0
- package/dist/multiplayer.d.ts +133 -0
- package/dist/multiplayer.js +334 -0
- package/dist/multiplayer.js.map +1 -0
- package/dist/protocol.d.ts +219 -0
- package/dist/protocol.js +25 -0
- package/dist/protocol.js.map +1 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -0
- package/package.json +53 -0
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import type { Vec3, Quat } from './state';
|
|
2
|
+
import type { PlayerIdentity, PlayerReplicaState } from './state';
|
|
3
|
+
/**
|
|
4
|
+
* The runtime value vocabulary for declared custom state. A `ref`-typed var's value is the **id** of a live
|
|
5
|
+
* member (a player's `playerKey` or an entity id) as a string, or `null` when unset/dangling — hence `null`
|
|
6
|
+
* is included. The DECLARATION vocabulary (`VarType`: number/string/boolean/vec3/ref + bounds) lives in
|
|
7
|
+
* `@hypersoniclabs/helix-manifest` (authored config, validated at publish); this is the wire value side.
|
|
8
|
+
*/
|
|
9
|
+
export type RoomVarValue = number | string | boolean | Vec3 | null | RoomVarCollection;
|
|
10
|
+
/**
|
|
11
|
+
* Per-player/room/entity COLLECTION values (Tier 2 Phase 4.5.13 + P3 collections, spec §5). A `list` var reads as
|
|
12
|
+
* an ordered array — of a scalar element (`number`/`string`/`boolean`), a **ref** element (an id `string`), or a
|
|
13
|
+
* flat **record** (`{field: scalar}`, P3) — realized server-side as a colyseus ArraySchema; a `counterMap` var
|
|
14
|
+
* reads as a string→number record over its declared keys (a MapSchema<number>). P3 also lets entities hold
|
|
15
|
+
* collections and broadcast payloads carry a collection snapshot. Mutated only via the dedicated effects
|
|
16
|
+
* (append/clear/addCount/removeAt/setField) + read via listLength/listAt/count — never a normal scalar expr/arg.
|
|
17
|
+
*/
|
|
18
|
+
export type RoomVarRecord = Record<string, number | string | boolean | Vec3>;
|
|
19
|
+
export type RoomVarCollection = number[] | string[] | boolean[] | RoomVarRecord[] | Record<string, number>;
|
|
20
|
+
/** A declared bag of custom state — names + types are declared per-world; used for both room-level and per-player vars. */
|
|
21
|
+
export type RoomVars = Record<string, RoomVarValue>;
|
|
22
|
+
/** Full authoritative per-player state: the FIXED character contract + identity + DECLARED game vars. */
|
|
23
|
+
export interface PlayerState extends PlayerIdentity, PlayerReplicaState {
|
|
24
|
+
/** Declared per-player game state (e.g. team, health, score). Same vocabulary as roomVars; declared per-world. */
|
|
25
|
+
vars: RoomVars;
|
|
26
|
+
/**
|
|
27
|
+
* Presence (Tier 2 Phase 3, spec §8): `false` while this seat sits in the reconnection grace window after an
|
|
28
|
+
* unexpected drop — the seat (and its refs) persists, but the server excludes it from reductions. The seat is
|
|
29
|
+
* removed (an `onRemove('players')`) only at grace expiry; until then the engine should render the replica idle.
|
|
30
|
+
* This layers on Colyseus's own reconnection — it annotates the seat, it does not drive the reconnect handshake.
|
|
31
|
+
*/
|
|
32
|
+
connected: boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Participation (Tier 2 P3-B2 elimination): `false` when this still-connected player has been removed from the
|
|
35
|
+
* ACTIVE set mid-match (eliminated / benched / a spectator). An inactive seat is excluded from the same gameplay
|
|
36
|
+
* reductions + spatial detection a disconnected seat is (forEachPlayer / playerCount / aggregate players /
|
|
37
|
+
* nearestPlayer / zone + contact), but it stays `connected` and keeps rendering, and `broadcast` still reaches it
|
|
38
|
+
* (so it can spectate). The room sets it via the `eliminate`/`revive` effects; defaults `true`. Clients may read it
|
|
39
|
+
* to render spectators (e.g. greyed out). (Distinct from `connected`, which is presence/reconnection-grace.)
|
|
40
|
+
*/
|
|
41
|
+
active: boolean;
|
|
42
|
+
/**
|
|
43
|
+
* Source-time stamp (ms) of this seat's current `position` — the SANITIZED sender send-time (`StateMessage.tMs`), or
|
|
44
|
+
* the server's apply-clock when the upload carried none. Clients SPACE interpolation keyframes by `posT` deltas
|
|
45
|
+
* instead of local arrival time, so jitter in DELIVERY (network + 20 Hz-tick aliasing) stops becoming jitter in
|
|
46
|
+
* rendered MOTION. Monotonic per seat; only deltas are meaningful (origin = the sender's arbitrary clock base).
|
|
47
|
+
*/
|
|
48
|
+
posT: number;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* RESERVED (Tier 2): a server-spawned object (pickup, projectile, NPC). Empty in v1 — the shape is
|
|
52
|
+
* reserved so adding server-spawned entities later is additive. Tier 2 gives these author-defined
|
|
53
|
+
* behavior; v1 only freezes the slot in RoomState.
|
|
54
|
+
*/
|
|
55
|
+
export interface EntityState {
|
|
56
|
+
id: string;
|
|
57
|
+
/** Author-defined kind (e.g. 'flag', 'pickup'). */
|
|
58
|
+
kind: string;
|
|
59
|
+
position?: Vec3;
|
|
60
|
+
/**
|
|
61
|
+
* Physics state — present ONLY for a `physics` (dynamic-body) kind (networked-physics, plan Phase 0). A kinematic
|
|
62
|
+
* entity carries position only (these stay undefined; @colyseus/schema delta-encodes an unwritten field to ~0 bytes).
|
|
63
|
+
* Synced so a remote client extrapolates with the RIGHT velocities (research §2: without synced velocity, remote
|
|
64
|
+
* extrapolation pops) and reproduces orientation. Units: m/s (linear), rad/s (angular), unit quaternion.
|
|
65
|
+
*/
|
|
66
|
+
velocity?: Vec3;
|
|
67
|
+
angularVelocity?: Vec3;
|
|
68
|
+
orientation?: Quat;
|
|
69
|
+
/**
|
|
70
|
+
* Who simulates this entity (Tier 2 Phase 4.6c, spec §9). '' = server-authoritative (deterministic kinematics).
|
|
71
|
+
* A player id (a state.players key) = an owner-authoritative entity that client simulates + uploads (the others
|
|
72
|
+
* render it); a client reads this to know which entities it should be uploading via uploadEntity.
|
|
73
|
+
*/
|
|
74
|
+
controller: string;
|
|
75
|
+
/**
|
|
76
|
+
* Monotonic authority epoch (Tier 2 Phase 4.5.12, spec §9), bumped on every controller handoff — host
|
|
77
|
+
* migration AND voluntary ownership transfer. A controller client mirrors this into each EntityStateMessage;
|
|
78
|
+
* the room rejects an upload whose epoch ≠ the current one, fencing a stale authority era (a still-connected
|
|
79
|
+
* prior owner's in-flight frames after ownership moved). 0 at spawn; clients only read it.
|
|
80
|
+
*/
|
|
81
|
+
authorityEpoch: number;
|
|
82
|
+
/** Declared custom vars (same vocabulary as roomVars). */
|
|
83
|
+
vars: RoomVars;
|
|
84
|
+
/**
|
|
85
|
+
* Source-time stamp (ms) of this entity's current `position` — the server's apply-clock (owner-entity sender-time is
|
|
86
|
+
* a follow-up; server-authoritative entities self-stamp each tick). Consumers space interpolation by `posT` deltas,
|
|
87
|
+
* not arrival time. Monotonic; deltas only. 0 before first move.
|
|
88
|
+
*/
|
|
89
|
+
posT: number;
|
|
90
|
+
}
|
|
91
|
+
/** The authoritative shared state. Always carries all three collections (entities empty until Tier 2). */
|
|
92
|
+
export interface RoomState {
|
|
93
|
+
/** Per-player authoritative state, keyed by player id. Realized as a colyseus MapSchema. */
|
|
94
|
+
players: Record<string, PlayerState>;
|
|
95
|
+
/** Room-level declared game state (scores, timers, objectives). Names/types declared per-world. */
|
|
96
|
+
roomVars: RoomVars;
|
|
97
|
+
/** RESERVED (Tier 2): server-spawned entities. Empty in v1. */
|
|
98
|
+
entities: Record<string, EntityState>;
|
|
99
|
+
/** Authoritative server clock: a monotonic counter advanced once per fixed-rate sim tick. */
|
|
100
|
+
serverTick: number;
|
|
101
|
+
/**
|
|
102
|
+
* Authoritative server wall-clock (epoch ms) sampled at the last tick. Clients align to it (offset via the
|
|
103
|
+
* ping/pong echo, see messages.ts) and interpolate between patches, so timer/phase deadlines expressed
|
|
104
|
+
* against server time agree across clients without a per-tick countdown var.
|
|
105
|
+
*/
|
|
106
|
+
serverTimeMs: number;
|
|
107
|
+
/**
|
|
108
|
+
* The current phase of the world's room-scoped state machine (Tier 2 Phase 3, spec §8), or `''` when the
|
|
109
|
+
* world declares no `states`. Authored phase names; changed only by the server's `transitionTo`. A
|
|
110
|
+
* late-joiner reads it off synced state to know whether to spawn in or spectate (the join policy).
|
|
111
|
+
*/
|
|
112
|
+
phase: string;
|
|
113
|
+
/**
|
|
114
|
+
* The `serverTick` at which the room entered its current `phase`. With `serverTick`/`serverTimeMs` a client
|
|
115
|
+
* computes time-in-phase locally (e.g. a round countdown) without a per-tick countdown var.
|
|
116
|
+
*/
|
|
117
|
+
phaseStartTick: number;
|
|
118
|
+
/**
|
|
119
|
+
* Active timers (Tier 2 Phase 3, spec §8) → absolute deadline as `serverTimeMs` (epoch ms). The map key is
|
|
120
|
+
* the timer name for a room-scoped timer, or `"<timer>|<playerKey>"` for a per-player **keyed** timer (e.g.
|
|
121
|
+
* read your own cooldown at `"cooldown|" + room.sessionId`). A client computes the seconds remaining as
|
|
122
|
+
* `(deadline − estimatedServerTimeMs) / 1000` using its ping/pong offset, so a countdown interpolates locally
|
|
123
|
+
* without a per-tick countdown var. An entry is removed when the timer fires or is cancelled.
|
|
124
|
+
*/
|
|
125
|
+
timerDeadlines: Record<string, number>;
|
|
126
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// The authoritative room state shape — the FRAMEWORK for what a world syncs. The room holds this as
|
|
2
|
+
// @colyseus/schema (the Record<string, T> maps below are realized as MapSchema); the SDK exposes it as
|
|
3
|
+
// room.state. Two layers, and the distinction is the whole answer to "how does an agent sync more?":
|
|
4
|
+
//
|
|
5
|
+
// • players — FIXED. Each player is the engine's character contract (PlayerReplicaState) + identity.
|
|
6
|
+
// Universal across every world; an agent never changes its fields.
|
|
7
|
+
// • roomVars / per-player vars / entities — DECLARED PER-WORLD. This is where an agent's game state
|
|
8
|
+
// lives (scores, timers, teams, objectives). The agent DECLARES names + types in the
|
|
9
|
+
// world's multiplayer config (loaded by buildId at onCreate); the one generic HelixRoom
|
|
10
|
+
// interprets the declaration — no agent-authored server code (Tier 1).
|
|
11
|
+
//
|
|
12
|
+
// Tier-1 vocabulary is intentionally bounded (primitives + Vec3). Rich/nested custom state and
|
|
13
|
+
// author-defined entity behavior are Tier 2 (a reflection-based dynamic schema + behavior DSL),
|
|
14
|
+
// deferred — the `entities` collection and this declared-bag shape are the reserved seams that keep
|
|
15
|
+
// Tier 2 additive rather than a rewrite.
|
|
16
|
+
export {};
|
|
17
|
+
//# sourceMappingURL=room.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"room.js","sourceRoot":"","sources":["../../src/multiplayer-contract/room.ts"],"names":[],"mappings":"AAAA,oGAAoG;AACpG,uGAAuG;AACvG,qGAAqG;AACrG,EAAE;AACF,wGAAwG;AACxG,kFAAkF;AAClF,sGAAsG;AACtG,oGAAoG;AACpG,uGAAuG;AACvG,sFAAsF;AACtF,EAAE;AACF,+FAA+F;AAC/F,gGAAgG;AAChG,oGAAoG;AACpG,yCAAyC"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
export type Vec3 = {
|
|
2
|
+
x: number;
|
|
3
|
+
y: number;
|
|
4
|
+
z: number;
|
|
5
|
+
};
|
|
6
|
+
/** A rotation quaternion. Physics (dynamic-body) kinds only — kinematic kinds carry no orientation on the wire. */
|
|
7
|
+
export type Quat = {
|
|
8
|
+
x: number;
|
|
9
|
+
y: number;
|
|
10
|
+
z: number;
|
|
11
|
+
w: number;
|
|
12
|
+
};
|
|
13
|
+
/** Pinned units. Linear in meters / meters-per-second; every angle is degrees (see the *Deg suffixes). */
|
|
14
|
+
export declare const UNITS: {
|
|
15
|
+
readonly position: "meters";
|
|
16
|
+
readonly velocity: "meters/second";
|
|
17
|
+
readonly angles: "degrees";
|
|
18
|
+
};
|
|
19
|
+
/** Stable per-player identity (set at join from the room credential; not part of the per-tick churn). */
|
|
20
|
+
export interface PlayerIdentity {
|
|
21
|
+
/** Opaque per-connection room playerKey (= the state.players map key). NOT the credential `sub` — that stays server-side (§4). */
|
|
22
|
+
id: string;
|
|
23
|
+
/** Sanitized display name for nameplates (sanitized before it enters room state — see plan H4). */
|
|
24
|
+
displayName: string;
|
|
25
|
+
/**
|
|
26
|
+
* CDN URL of this player's equipped universal avatar (a converted single-file GLB on the
|
|
27
|
+
* helix-humanoid rig), or '' when they have none — clients render the default body on ''.
|
|
28
|
+
* Resolved and skeleton-gated SERVER-SIDE at join (backend → signed credential → room), never
|
|
29
|
+
* client-supplied — and it is item-keyed public catalog data, NOT the userId (which stays
|
|
30
|
+
* server-side, §4). Fixed for the seat's lifetime: equip changes apply on the next join. (v17)
|
|
31
|
+
*/
|
|
32
|
+
avatarUrl: string;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* The per-tick replicated kinematic + animation parameters for one player. The room holds the
|
|
36
|
+
* authoritative copy (a @colyseus/schema mirror of these fields); the NetworkDriver maps each field
|
|
37
|
+
* onto the named character blackboard param. FIRST DRAFT — the exact injected set is confirmed by
|
|
38
|
+
* spike S2 (engine headless-replica write-path); changing the field set bumps CONTRACT_VERSION.
|
|
39
|
+
*/
|
|
40
|
+
export interface PlayerReplicaState {
|
|
41
|
+
/** World feet position, METERS. Interpolated by the remote replica. */
|
|
42
|
+
position: Vec3;
|
|
43
|
+
/** Body facing, DEGREES. The adapter converts to radians for body.setFacingYaw. */
|
|
44
|
+
facingYawDeg: number;
|
|
45
|
+
/** Horizontal planar speed, M/S. → blackboard 'speed' (blend-space input). */
|
|
46
|
+
speed: number;
|
|
47
|
+
/** Signed movement direction relative to facing, DEGREES (−180..180). → blackboard 'direction'. */
|
|
48
|
+
moveDirectionDeg: number;
|
|
49
|
+
/** Vertical velocity, M/S (+up). → blackboard 'verticalVelocity' (jump/fall states). */
|
|
50
|
+
verticalVelocity: number;
|
|
51
|
+
/** Ground contact. → blackboard 'isGrounded' (grounded/air transitions). */
|
|
52
|
+
grounded: boolean;
|
|
53
|
+
/** Crouch stance. → routes the locomotion anim graph to its crouched states. */
|
|
54
|
+
crouched: boolean;
|
|
55
|
+
/** Aim yaw, DEGREES (world). → blackboard 'cameraYaw' (aim-additive source). */
|
|
56
|
+
aimYawDeg: number;
|
|
57
|
+
/** Aim pitch, DEGREES. → blackboard 'cameraPitch' (aim-additive source). */
|
|
58
|
+
aimPitchDeg: number;
|
|
59
|
+
/** Ability ids currently active (e.g. ['locomotion','fly']). Drives remote ability activation. */
|
|
60
|
+
activeAbilities: string[];
|
|
61
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// Replicated player state — the parameters the room broadcasts and the engine's NetworkDriver feeds
|
|
2
|
+
// into the character blackboard. We replicate PARAMETERS, never bone transforms: animation runs fully
|
|
3
|
+
// client-side off these values (see character-architecture §3).
|
|
4
|
+
//
|
|
5
|
+
// ALL ANGLES ARE DEGREES — every angular field is suffixed *Deg. One unit on the wire, so there is no
|
|
6
|
+
// radians/degrees ambiguity to forget. The engine mixes units internally (the body is radians, the
|
|
7
|
+
// animation params are degrees); the engine adapter owns the single deg↔rad conversion at the body
|
|
8
|
+
// boundary (body.setFacingYaw) — the contract itself stays all-degrees.
|
|
9
|
+
/** Pinned units. Linear in meters / meters-per-second; every angle is degrees (see the *Deg suffixes). */
|
|
10
|
+
export const UNITS = {
|
|
11
|
+
position: 'meters',
|
|
12
|
+
velocity: 'meters/second',
|
|
13
|
+
angles: 'degrees',
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state.js","sourceRoot":"","sources":["../../src/multiplayer-contract/state.ts"],"names":[],"mappings":"AAAA,oGAAoG;AACpG,sGAAsG;AACtG,gEAAgE;AAChE,EAAE;AACF,sGAAsG;AACtG,mGAAmG;AACnG,mGAAmG;AACnG,wEAAwE;AAOxE,0GAA0G;AAC1G,MAAM,CAAC,MAAM,KAAK,GAAG;IACnB,QAAQ,EAAE,QAAQ;IAClB,QAAQ,EAAE,eAAe;IACzB,MAAM,EAAE,SAAS;CACT,CAAC"}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { type StateMessage, type StateAckMessage, type EntityStateAckMessage, type RoomState, type PlayerState, type EntityState, type RoomVarValue, type Vec3, type Quat } from './multiplayer-contract';
|
|
2
|
+
export type ReplicaInput = Omit<StateMessage, 'seq' | 'tMs'>;
|
|
3
|
+
/** Options for joinRoom — only needed where the API base can't be derived from the token (local dev/tests). */
|
|
4
|
+
export interface JoinRoomOptions {
|
|
5
|
+
/** Override the platform API base URL. Default: the world_session token's `iss`, else configure({ apiBaseUrl }). */
|
|
6
|
+
apiBaseUrl?: string;
|
|
7
|
+
/**
|
|
8
|
+
* State upload cadence (Hz) for the player-seat flush — from the world's `multiplayer.uploadHz`. Clamped to
|
|
9
|
+
* [MESSAGE_RATE.stateHz, MESSAGE_RATE.maxUploadHz] (10..20); absent ⇒ the 10 Hz default. The room derives its
|
|
10
|
+
* own ceiling from the trusted configUrl, so a lying client only throttles itself.
|
|
11
|
+
*/
|
|
12
|
+
uploadHz?: number;
|
|
13
|
+
}
|
|
14
|
+
/** The curated live-room surface handed to world authors. Colyseus's API, re-exposed under Helix.*. */
|
|
15
|
+
export interface HelixRoom {
|
|
16
|
+
readonly roomId: string;
|
|
17
|
+
readonly sessionId: string;
|
|
18
|
+
/**
|
|
19
|
+
* The clamped player-seat upload cadence (Hz) this connection flushes at — `multiplayer.uploadHz` resolved to
|
|
20
|
+
* [10,20]. The engine paces its hosted-entity (EntityScene) uploads to the SAME value so both channels match.
|
|
21
|
+
*/
|
|
22
|
+
readonly effectiveUploadHz: number;
|
|
23
|
+
/** Authoritative shared state (a @colyseus/schema instance shaped like the contract RoomState). */
|
|
24
|
+
readonly state: RoomState;
|
|
25
|
+
/** Fires after every applied patch from the server. */
|
|
26
|
+
onStateChange(cb: (state: RoomState) => void): void;
|
|
27
|
+
/** Subscribe to a collection's adds (Tier-2 seam: players today, entities reserved). Fires for existing entries too. */
|
|
28
|
+
onAdd(collection: 'players', cb: (player: PlayerState, id: string) => void): void;
|
|
29
|
+
onAdd(collection: 'entities', cb: (entity: EntityState, id: string) => void): void;
|
|
30
|
+
onRemove(collection: 'players', cb: (player: PlayerState, id: string) => void): void;
|
|
31
|
+
onRemove(collection: 'entities', cb: (entity: EntityState, id: string) => void): void;
|
|
32
|
+
/** A world-authored server→client message (the room broadcasts these for declared events). */
|
|
33
|
+
onMessage<Payload = unknown>(type: string, cb: (payload: Payload) => void): void;
|
|
34
|
+
/**
|
|
35
|
+
* A2 (spec §9) the room's player-seat divergence correction — fires ONLY when the movement gate REJECTED an
|
|
36
|
+
* upload (the accepted case is silent). The engine snaps the local body to `position`; the SDK has already
|
|
37
|
+
* pruned its reconciliation buffer through `seq` before this fires.
|
|
38
|
+
*/
|
|
39
|
+
onStateAck(cb: (ack: StateAckMessage) => void): void;
|
|
40
|
+
/**
|
|
41
|
+
* A2 (spec §9) the room's owner-hosted-entity divergence correction, BATCHED — the engine re-anchors each
|
|
42
|
+
* hosted entity's local sim to its anchor so a sparse/throttled host stops being fenced by the gate.
|
|
43
|
+
*/
|
|
44
|
+
onEntityStateAck(cb: (ack: EntityStateAckMessage) => void): void;
|
|
45
|
+
/** Per-tick predicted state. Coalesced + flushed at MESSAGE_RATE.stateHz, seq-tagged (D3/D4). */
|
|
46
|
+
sendState(input: ReplicaInput): void;
|
|
47
|
+
/** Activate/deactivate a built-in ability (sent immediately; server enforces the rate ceiling). */
|
|
48
|
+
sendAbility(ability: string, active: boolean): void;
|
|
49
|
+
/** A world-authored declared action (the generic extensibility channel). */
|
|
50
|
+
sendAction(name: string, args?: Record<string, RoomVarValue>): void;
|
|
51
|
+
/**
|
|
52
|
+
* Upload an owner-authoritative entity's client-simulated state (Tier 2 Phase 4.6c). Call only for an entity
|
|
53
|
+
* whose `controller` is this client (state.entities[id].controller === sessionId); the room rejects others.
|
|
54
|
+
* Sent immediately, per-entity seq-tagged; the room gates the position against the kind's maxSpeed + clamps vars.
|
|
55
|
+
*/
|
|
56
|
+
uploadEntity(entityId: string, input: {
|
|
57
|
+
position: Vec3;
|
|
58
|
+
velocity?: Vec3;
|
|
59
|
+
angularVelocity?: Vec3;
|
|
60
|
+
orientation?: Quat;
|
|
61
|
+
vars?: Record<string, RoomVarValue>;
|
|
62
|
+
epoch?: number;
|
|
63
|
+
}): void;
|
|
64
|
+
/**
|
|
65
|
+
* Upload MANY owner-authoritative entities in ONE message (Tier 2 Phase 4.10). Prefer this over per-entity
|
|
66
|
+
* uploadEntity when hosting multiple entities: the per-connection rate cap counts messages, so N single uploads
|
|
67
|
+
* spend N tokens/tick and starve, while one batch spends one. Position is sent as a compact [x,y,z] tuple; each
|
|
68
|
+
* entry is gated/clamped server-side exactly like uploadEntity. Pass only entities this client controls.
|
|
69
|
+
*/
|
|
70
|
+
uploadEntities(entities: ReadonlyArray<{
|
|
71
|
+
id: string;
|
|
72
|
+
position: Vec3;
|
|
73
|
+
velocity?: Vec3;
|
|
74
|
+
angularVelocity?: Vec3;
|
|
75
|
+
orientation?: Quat;
|
|
76
|
+
vars?: Record<string, RoomVarValue>;
|
|
77
|
+
epoch?: number;
|
|
78
|
+
}>): void;
|
|
79
|
+
/** Sent-but-unacknowledged states — the reconciliation tail the engine NetworkDriver replays (D4). */
|
|
80
|
+
pendingInputs(): readonly StateMessage[];
|
|
81
|
+
/** Prune the reconciliation buffer once the server confirms it processed up to `seq` (D4). */
|
|
82
|
+
acknowledge(seq: number): void;
|
|
83
|
+
/** Connection dropped; the client is auto-reconnecting (built into @colyseus/sdk). */
|
|
84
|
+
onDrop(cb: () => void): void;
|
|
85
|
+
/** Auto-reconnection succeeded. */
|
|
86
|
+
onReconnect(cb: () => void): void;
|
|
87
|
+
/** Left for good (kicked, room disposed, or after we leave) — `code` is the close code. */
|
|
88
|
+
onLeave(cb: (code: number) => void): void;
|
|
89
|
+
/** Leave intentionally (no reconnection grace held server-side). */
|
|
90
|
+
leave(): Promise<void>;
|
|
91
|
+
}
|
|
92
|
+
export interface MultiplayerHost {
|
|
93
|
+
isInitialized(): boolean;
|
|
94
|
+
getToken(): string | null;
|
|
95
|
+
getWorldId(): string | null;
|
|
96
|
+
}
|
|
97
|
+
export declare class HelixMultiplayer {
|
|
98
|
+
private readonly host;
|
|
99
|
+
private apiBaseUrl;
|
|
100
|
+
private room;
|
|
101
|
+
private callbacks;
|
|
102
|
+
private seq;
|
|
103
|
+
private entitySeq;
|
|
104
|
+
private entityBatchSeq;
|
|
105
|
+
private pendingInput;
|
|
106
|
+
private flushTimer;
|
|
107
|
+
private effectiveUploadHz;
|
|
108
|
+
private inputBuffer;
|
|
109
|
+
private worldId;
|
|
110
|
+
private onStateAckCb;
|
|
111
|
+
private onEntityStateAckCb;
|
|
112
|
+
private nlSend;
|
|
113
|
+
private nlPatch;
|
|
114
|
+
constructor(host: MultiplayerHost);
|
|
115
|
+
configure(options: {
|
|
116
|
+
apiBaseUrl: string;
|
|
117
|
+
}): void;
|
|
118
|
+
resolveApiBase(token: string | null): string | null;
|
|
119
|
+
joinRoom(worldId?: string, options?: JoinRoomOptions): Promise<HelixRoom>;
|
|
120
|
+
private requestJoin;
|
|
121
|
+
private makeHandle;
|
|
122
|
+
private startFlush;
|
|
123
|
+
private flush;
|
|
124
|
+
private nlOnPatch;
|
|
125
|
+
private nlTick;
|
|
126
|
+
private persistReconnect;
|
|
127
|
+
private readReconnect;
|
|
128
|
+
private reconnectWsUrl;
|
|
129
|
+
private clearReconnect;
|
|
130
|
+
private tryReconnect;
|
|
131
|
+
private leave;
|
|
132
|
+
private teardown;
|
|
133
|
+
}
|