@series-inc/rundot-game-sdk 5.23.0-beta.5 → 5.23.0-beta.7
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/dist/SyncplayRoomTransport-D6xsCdn5.d.ts +379 -0
- package/dist/{chunk-T6Q5GL7B.js → chunk-G7TYQYHC.js} +437 -10
- package/dist/chunk-G7TYQYHC.js.map +1 -0
- package/dist/{chunk-WVJVQAW7.js → chunk-RXJPLBXQ.js} +3 -3
- package/dist/{chunk-WVJVQAW7.js.map → chunk-RXJPLBXQ.js.map} +1 -1
- package/dist/chunk-VZLX7S73.js +131 -0
- package/dist/chunk-VZLX7S73.js.map +1 -0
- package/dist/{index-DB99BKTt.d.ts → index-UMslJhz5.d.ts} +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/playground/index.js +26 -1
- package/dist/playground/index.js.map +1 -1
- package/dist/rundot-game-api/index.js +1 -1
- package/dist/session-promotion-DgrVQE2y.d.ts +136 -0
- package/dist/syncplay/browser.d.ts +129 -81
- package/dist/syncplay/browser.js +710 -388
- package/dist/syncplay/browser.js.map +1 -1
- package/dist/syncplay/creator.d.ts +36 -2
- package/dist/syncplay/creator.js +2 -2
- package/dist/syncplay/index.d.ts +2 -2
- package/dist/syncplay/index.js +2 -2
- package/dist/syncplay/node.js +4 -2
- package/dist/syncplay/node.js.map +1 -1
- package/dist/{types-BLIISDww.d.ts → types-DbhOvOdx.d.ts} +1 -1
- package/dist/vite/{dev-server-5OIDIMOM.js → dev-server-V3IZP5XX.js} +144 -28
- package/dist/vite/dev-server-V3IZP5XX.js.map +1 -0
- package/dist/vite/{esbuild-validate-IXG2OBFH.js → esbuild-validate-3ISKFZOW.js} +5 -2
- package/dist/vite/esbuild-validate-3ISKFZOW.js.map +1 -0
- package/dist/vite/index.js +30 -32
- package/dist/vite/index.js.map +1 -1
- package/docs/rundot-developer-platform/api/SYNCPLAY.md +47 -0
- package/package.json +2 -1
- package/dist/SyncplayRoomTransport-DXNJxFKZ.d.ts +0 -196
- package/dist/chunk-QLHQTYP6.js +0 -3
- package/dist/chunk-QLHQTYP6.js.map +0 -1
- package/dist/chunk-T6Q5GL7B.js.map +0 -1
- package/dist/vite/dev-server-5OIDIMOM.js.map +0 -1
- package/dist/vite/esbuild-validate-IXG2OBFH.js.map +0 -1
|
@@ -0,0 +1,379 @@
|
|
|
1
|
+
import { C as CanonicalValue, h as ReplayFile, O as OfflineSession } from './types-DbhOvOdx.js';
|
|
2
|
+
import { M as MultiplayerApi } from './MultiplayerApi-nnrGTTcO.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Game-agnostic input authority (server orders inputs, clients simulate — §2 Option 1).
|
|
6
|
+
*
|
|
7
|
+
* It orders per-slot inputs by tick and confirms each tick exactly once, in order,
|
|
8
|
+
* either when every player slot has reported or when a HardTolerance deadline elapses
|
|
9
|
+
* (substituting the slot's last confirmed input). It never runs the simulation — only
|
|
10
|
+
* inputs cross the wire and clients run the deterministic sim locally.
|
|
11
|
+
*
|
|
12
|
+
* This module is the reusable core: the M0 spike hosts it over sockets, and M2 lifts it
|
|
13
|
+
* into the mp-room-server room type unchanged.
|
|
14
|
+
*/
|
|
15
|
+
/** Opaque, engine-defined input payload. The authority never interprets it. */
|
|
16
|
+
type EncodedInput = CanonicalValue;
|
|
17
|
+
interface ConfirmedInputFrame {
|
|
18
|
+
readonly tick: number;
|
|
19
|
+
/** One entry per player slot, in slot order. */
|
|
20
|
+
readonly inputs: readonly EncodedInput[];
|
|
21
|
+
/** Slots whose input was substituted (repeated) because it never arrived in time. */
|
|
22
|
+
readonly substitutedSlots: readonly number[];
|
|
23
|
+
readonly checksum: string;
|
|
24
|
+
}
|
|
25
|
+
interface InputAuthorityConfig {
|
|
26
|
+
readonly playerCount: number;
|
|
27
|
+
/** Confirm a tick once `now - tick >= hardToleranceTicks`, substituting any missing input. */
|
|
28
|
+
readonly hardToleranceTicks: number;
|
|
29
|
+
/** Substitute this when a slot has no prior confirmed input to repeat. */
|
|
30
|
+
readonly neutralInput: EncodedInput;
|
|
31
|
+
/** Reject inputs whose tick is further ahead than `confirmedThrough + maxFutureTicks`. */
|
|
32
|
+
readonly maxFutureTicks?: number;
|
|
33
|
+
/** Confirmed frames retained for the redundant broadcast window. */
|
|
34
|
+
readonly retainedConfirmedFrames?: number;
|
|
35
|
+
/**
|
|
36
|
+
* Rebuild a previously-persisted authority (M6.5 crash recovery): the
|
|
37
|
+
* retained frames, frontier, and per-slot last-confirmed inputs (derived
|
|
38
|
+
* from the final frame — confirmed inputs equal the post-substitution
|
|
39
|
+
* last-confirmed values by construction). Fail-loud on gaps or a frontier
|
|
40
|
+
* mismatch.
|
|
41
|
+
*/
|
|
42
|
+
readonly restoreFrom?: InputAuthorityRestoreState;
|
|
43
|
+
}
|
|
44
|
+
interface InputAuthorityRestoreState {
|
|
45
|
+
readonly confirmedThrough: number;
|
|
46
|
+
readonly frames: readonly ConfirmedInputFrame[];
|
|
47
|
+
}
|
|
48
|
+
type InputRejectionReason = 'slot-out-of-range' | 'invalid-tick' | 'tick-already-confirmed' | 'tick-too-far-ahead';
|
|
49
|
+
interface InputSubmissionResult {
|
|
50
|
+
readonly accepted: boolean;
|
|
51
|
+
readonly reason?: InputRejectionReason;
|
|
52
|
+
}
|
|
53
|
+
interface InputAuthorityStats {
|
|
54
|
+
readonly confirmedTicks: number;
|
|
55
|
+
readonly substitutedInputs: number;
|
|
56
|
+
readonly droppedLateInputs: number;
|
|
57
|
+
readonly rejectedFutureInputs: number;
|
|
58
|
+
}
|
|
59
|
+
interface InputAuthority {
|
|
60
|
+
readonly playerCount: number;
|
|
61
|
+
/** Highest confirmed tick, or -1 when nothing is confirmed yet. */
|
|
62
|
+
readonly confirmedThrough: number;
|
|
63
|
+
/** Lowest confirmed tick still retained, or -1 when nothing is confirmed yet. */
|
|
64
|
+
readonly earliestRetainedTick: number;
|
|
65
|
+
receiveInput(slot: number, tick: number, input: EncodedInput): InputSubmissionResult;
|
|
66
|
+
/** Confirm every tick that can be confirmed up to and including `now`. Returns the new frames in order. */
|
|
67
|
+
advance(now: number): readonly ConfirmedInputFrame[];
|
|
68
|
+
/** A confirmed frame still inside the retained window, for redundant re-broadcast. */
|
|
69
|
+
confirmedFrame(tick: number): ConfirmedInputFrame | undefined;
|
|
70
|
+
/**
|
|
71
|
+
* The retained frames `from..to` inclusive, for persistence (M6.5). Throws
|
|
72
|
+
* if any tick in the range is no longer retained — a persisted record with
|
|
73
|
+
* a silent gap would strand every restored client.
|
|
74
|
+
*/
|
|
75
|
+
confirmedFrameRange(from: number, to: number): readonly ConfirmedInputFrame[];
|
|
76
|
+
/**
|
|
77
|
+
* Drop retained frames below `tick` (M5.5: history before a validated
|
|
78
|
+
* snapshot is no longer needed for late-join catch-up). Never moves the
|
|
79
|
+
* frontier; a no-op at or below the current earliest retained tick.
|
|
80
|
+
*/
|
|
81
|
+
pruneConfirmedBefore(tick: number): void;
|
|
82
|
+
stats(): InputAuthorityStats;
|
|
83
|
+
}
|
|
84
|
+
declare function createInputAuthority(config: InputAuthorityConfig): InputAuthority;
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Frozen v1 session-control wire protocol for game-agnostic input-authority rooms (§8, M1).
|
|
88
|
+
*
|
|
89
|
+
* Covers the server/client roles for a live match: session-start (slot assignment + the
|
|
90
|
+
* server-owned RNG seed + tick params), clock/time-sync, input, confirmed-input (the verified
|
|
91
|
+
* tick), reconnect, spectator, and close/error. Snapshot request/offer/chunk/complete for
|
|
92
|
+
* late-join reuse the existing envelopes in `local-authority-wire.ts` (wired at M5).
|
|
93
|
+
*
|
|
94
|
+
* Both families share the `rdm-local-authority/v1` version namespace. Decoding is FAIL-CLOSED:
|
|
95
|
+
* unknown protocol, unknown version, unknown kind, malformed payload, or checksum mismatch are
|
|
96
|
+
* rejected with a reason — never silently coerced. This is a public forward-compat boundary; the
|
|
97
|
+
* discriminants below are frozen and must only be extended, never repurposed.
|
|
98
|
+
*/
|
|
99
|
+
declare const deterministicSessionWireVersion = 1;
|
|
100
|
+
type DeterministicSessionRole = 'player' | 'spectator';
|
|
101
|
+
type DeterministicSessionMessage = {
|
|
102
|
+
readonly kind: 'session-start';
|
|
103
|
+
readonly slot: number;
|
|
104
|
+
readonly playerCount: number;
|
|
105
|
+
readonly seed: number;
|
|
106
|
+
readonly tickRateHz: number;
|
|
107
|
+
readonly hardToleranceTicks: number;
|
|
108
|
+
readonly role: DeterministicSessionRole;
|
|
109
|
+
} | {
|
|
110
|
+
readonly kind: 'time-sync-ping';
|
|
111
|
+
readonly clientSendTick: number;
|
|
112
|
+
readonly nonce: number;
|
|
113
|
+
} | {
|
|
114
|
+
readonly kind: 'time-sync-pong';
|
|
115
|
+
readonly clientSendTick: number;
|
|
116
|
+
readonly nonce: number;
|
|
117
|
+
readonly authorityTick: number;
|
|
118
|
+
} | {
|
|
119
|
+
readonly kind: 'input';
|
|
120
|
+
readonly slot: number;
|
|
121
|
+
readonly tick: number;
|
|
122
|
+
readonly input: EncodedInput;
|
|
123
|
+
readonly attempt: number;
|
|
124
|
+
} | {
|
|
125
|
+
readonly kind: 'confirmed-input';
|
|
126
|
+
readonly authorityTick: number;
|
|
127
|
+
readonly frames: readonly ConfirmedInputFrame[];
|
|
128
|
+
} | {
|
|
129
|
+
readonly kind: 'reconnect';
|
|
130
|
+
readonly slot: number;
|
|
131
|
+
readonly resumeFromTick: number;
|
|
132
|
+
} | {
|
|
133
|
+
readonly kind: 'spectator-join';
|
|
134
|
+
} | {
|
|
135
|
+
readonly kind: 'checksum-report';
|
|
136
|
+
readonly slot: number;
|
|
137
|
+
readonly tick: number;
|
|
138
|
+
readonly checksum: string;
|
|
139
|
+
} | {
|
|
140
|
+
/**
|
|
141
|
+
* Client → authority netcode telemetry (G8). Additive v1 extension: unknown
|
|
142
|
+
* kinds are dropped fail-closed by older decoders, so this never breaks an
|
|
143
|
+
* old authority. All fields are integers (rttMs rounded, timescale in
|
|
144
|
+
* permille) so the payload stays canonical-checksum friendly.
|
|
145
|
+
*/
|
|
146
|
+
readonly kind: 'net-stats';
|
|
147
|
+
readonly slot: number;
|
|
148
|
+
readonly tick: number;
|
|
149
|
+
readonly rttMs: number;
|
|
150
|
+
readonly rollbacks: number;
|
|
151
|
+
readonly maxRollbackDepth: number;
|
|
152
|
+
readonly timescalePermille: number;
|
|
153
|
+
readonly inputDelayTicks: number;
|
|
154
|
+
} | {
|
|
155
|
+
readonly kind: 'close';
|
|
156
|
+
readonly code: string;
|
|
157
|
+
readonly reason: string;
|
|
158
|
+
} | {
|
|
159
|
+
readonly kind: 'error';
|
|
160
|
+
readonly code: string;
|
|
161
|
+
readonly message: string;
|
|
162
|
+
};
|
|
163
|
+
type DeterministicSessionMessageKind = DeterministicSessionMessage['kind'];
|
|
164
|
+
type DeterministicSessionDecodeRejection = 'invalid-json' | 'not-an-envelope' | 'unknown-protocol' | 'unknown-version' | 'unknown-kind' | 'checksum-mismatch' | 'malformed-payload';
|
|
165
|
+
type DeterministicSessionDecodeResult = {
|
|
166
|
+
readonly ok: true;
|
|
167
|
+
readonly message: DeterministicSessionMessage;
|
|
168
|
+
} | {
|
|
169
|
+
readonly ok: false;
|
|
170
|
+
readonly reason: DeterministicSessionDecodeRejection;
|
|
171
|
+
};
|
|
172
|
+
declare function encodeDeterministicSessionMessage(message: DeterministicSessionMessage): string;
|
|
173
|
+
declare function decodeDeterministicSessionMessage(text: string): DeterministicSessionDecodeResult;
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Reusable client transport for game-agnostic deterministic multiplayer (§6 M4).
|
|
177
|
+
*
|
|
178
|
+
* A game (or the H5 host bridge) hands this a socket-like transport and a factory for the game's
|
|
179
|
+
* deterministic session. The client speaks the frozen `rdm-local-authority/v1` session protocol:
|
|
180
|
+
* it consumes `session-start` (slot + server-owned seed), predicts locally (repeating opponents'
|
|
181
|
+
* last confirmed input), submits `input`, and reconciles `confirmed-input` via rollback/resim.
|
|
182
|
+
* Only inputs cross the wire; the simulation runs entirely here. This is the same predict/rollback
|
|
183
|
+
* contract the M0 spike proved, packaged for real transports.
|
|
184
|
+
*/
|
|
185
|
+
interface NetworkedClientTransport {
|
|
186
|
+
send(text: string): void;
|
|
187
|
+
onMessage(handler: (text: string) => void): void;
|
|
188
|
+
}
|
|
189
|
+
interface NetworkedSyncplayClientOptions<State, Input> {
|
|
190
|
+
readonly transport: NetworkedClientTransport;
|
|
191
|
+
/** Build the game session once the server issues the seed and player count. */
|
|
192
|
+
readonly createSession: (params: {
|
|
193
|
+
seed: number;
|
|
194
|
+
playerCount: number;
|
|
195
|
+
}) => OfflineSession<State, Input>;
|
|
196
|
+
/** This client's own input for a tick (game-defined). */
|
|
197
|
+
readonly localInputForTick: (slot: number, tick: number) => Input;
|
|
198
|
+
readonly encodeInput: (input: Input) => EncodedInput;
|
|
199
|
+
/** Decode a wire input to a game input; MUST map the neutral substitute (canonical null) to the default. */
|
|
200
|
+
readonly decodeInput: (encoded: EncodedInput) => Input;
|
|
201
|
+
readonly maxPredictionTicks?: number;
|
|
202
|
+
/** Host wire envelope msgType carrying session messages. Default 'rdm'. */
|
|
203
|
+
readonly sessionMsgType?: string;
|
|
204
|
+
/**
|
|
205
|
+
* Auto-send a checksum-report whenever `appliedThrough` crosses a multiple
|
|
206
|
+
* of this cadence (M5.5). Aligned reports across clients are what let the
|
|
207
|
+
* authority quorum-validate donated snapshots; they also feed desync
|
|
208
|
+
* telemetry. Reports are read from the rolling snapshot buffer — never via
|
|
209
|
+
* `restoreToFrame`, which would rewind the live session. Default 120.
|
|
210
|
+
*/
|
|
211
|
+
readonly checksumCadenceTicks?: number;
|
|
212
|
+
/**
|
|
213
|
+
* Wall-clock pacing + clock-drift correction (G1), consumed by
|
|
214
|
+
* {@link NetworkedSyncplayClient.pumpPaced}. The step-counted `pump()` path
|
|
215
|
+
* ignores all of this, so step-driven tests and existing callers are
|
|
216
|
+
* unaffected. Rates are per-tick error corrections in the Quantum
|
|
217
|
+
* TimeCorrectionRate / GGPO frames-behind family: the client measures RTT via
|
|
218
|
+
* `time-sync-ping/pong`, estimates the authority frontier, and nudges its
|
|
219
|
+
* local timescale inside [minTimescale, maxTimescale] so it neither stalls at
|
|
220
|
+
* the prediction cap (fast clock / short path) nor starves into permanent
|
|
221
|
+
* substitution (slow clock / long path).
|
|
222
|
+
*/
|
|
223
|
+
readonly pacing?: NetworkedSyncplayClientPacingOptions;
|
|
224
|
+
/**
|
|
225
|
+
* Own-input scheduling delay in ticks (G2): input sampled while predicting
|
|
226
|
+
* tick T is bound and sent for tick T+delay, trading a fixed sliver of local
|
|
227
|
+
* latency for inputs that arrive before the authority's deadline (fewer
|
|
228
|
+
* substitutions of THIS client's input, shallower rollbacks for peers).
|
|
229
|
+
* With `maxTicks > minTicks` the delay auto-tunes from measured RTT
|
|
230
|
+
* (ping-adaptive, Quantum InputDelayMin/Max analog) — RTT measurement
|
|
231
|
+
* requires driving `pumpPaced`. Defaults to a static 0 (today's behavior).
|
|
232
|
+
*/
|
|
233
|
+
readonly inputDelay?: NetworkedSyncplayClientInputDelayOptions;
|
|
234
|
+
/** Monotonic-enough clock for RTT measurement. Default Date.now. NEVER used by the sim. */
|
|
235
|
+
readonly now?: () => number;
|
|
236
|
+
}
|
|
237
|
+
interface NetworkedSyncplayClientPacingOptions {
|
|
238
|
+
/** Interval between time-sync pings while pumpPaced is driven. Default 1000. */
|
|
239
|
+
readonly pingIntervalMs?: number;
|
|
240
|
+
/** Safety lead (ticks) kept over the input-arrival deadline. Default 2. */
|
|
241
|
+
readonly targetLeadTicks?: number;
|
|
242
|
+
/** Timescale clamp. Defaults 0.9 / 1.1 (±10%, imperceptible per Quantum/GGPO practice). */
|
|
243
|
+
readonly minTimescale?: number;
|
|
244
|
+
readonly maxTimescale?: number;
|
|
245
|
+
/** Timescale correction gain per tick of frame-advantage error. Default 0.02. */
|
|
246
|
+
readonly correctionPerTick?: number;
|
|
247
|
+
/** Catch-up cap: max frames stepped per pumpPaced call. Default 4. */
|
|
248
|
+
readonly maxStepsPerPump?: number;
|
|
249
|
+
}
|
|
250
|
+
interface NetworkedSyncplayClientInputDelayOptions {
|
|
251
|
+
/** Minimum (and initial) own-input delay in ticks. Default 0. */
|
|
252
|
+
readonly minTicks?: number;
|
|
253
|
+
/** Maximum delay for ping-adaptive tuning. Default = minTicks (static). */
|
|
254
|
+
readonly maxTicks?: number;
|
|
255
|
+
}
|
|
256
|
+
/** Live netcode telemetry for the local client (G8). */
|
|
257
|
+
interface NetworkedSyncplayClientNetStats {
|
|
258
|
+
/** Smoothed RTT in ms; -1 until the first time-sync pong arrives. */
|
|
259
|
+
readonly rttMs: number;
|
|
260
|
+
/** Current pacing timescale in permille (1000 = realtime). */
|
|
261
|
+
readonly timescalePermille: number;
|
|
262
|
+
readonly inputDelayTicks: number;
|
|
263
|
+
readonly rollbacks: number;
|
|
264
|
+
readonly maxRollbackDepth: number;
|
|
265
|
+
}
|
|
266
|
+
interface NetworkedSyncplayClient {
|
|
267
|
+
readonly slot: number;
|
|
268
|
+
/** 'player' (holds a slot) or 'spectator' (read-only follower, slot -1). From session-start. */
|
|
269
|
+
readonly role: DeterministicSessionRole;
|
|
270
|
+
readonly ready: boolean;
|
|
271
|
+
readonly predictedThrough: number;
|
|
272
|
+
readonly appliedThrough: number;
|
|
273
|
+
readonly rollbacks: number;
|
|
274
|
+
/** Live local netcode telemetry (RTT, timescale, delay, rollback depth). */
|
|
275
|
+
readonly netStats: NetworkedSyncplayClientNetStats;
|
|
276
|
+
/** Resolves once `session-start` has been received. */
|
|
277
|
+
whenReady(): Promise<void>;
|
|
278
|
+
/** Predict and submit local input up to the prediction budget. */
|
|
279
|
+
pump(): void;
|
|
280
|
+
/**
|
|
281
|
+
* Wall-clock-paced pump (G1): steps as many fixed frames as elapsed time ×
|
|
282
|
+
* the drift-corrected timescale allows (bounded by the prediction budget and
|
|
283
|
+
* the catch-up cap), and drives RTT pings. Call once per host frame (rAF /
|
|
284
|
+
* host tick) with a monotonic-enough `nowMs`. Prefer this over raw `pump()`
|
|
285
|
+
* on real networks — raw pump() slams into the prediction cap and
|
|
286
|
+
* rubber-bands under asymmetric latency.
|
|
287
|
+
*/
|
|
288
|
+
pumpPaced(nowMs: number): void;
|
|
289
|
+
/** Report this client's confirmed-state checksum for desync telemetry. */
|
|
290
|
+
reportChecksum(): void;
|
|
291
|
+
/** Confirmed-state checksum at `frame` (must be <= appliedThrough + 1). */
|
|
292
|
+
confirmedStateChecksum(frame: number): string;
|
|
293
|
+
exportReplay(): ReplayFile;
|
|
294
|
+
}
|
|
295
|
+
declare function createNetworkedSyncplayClient<State, Input>(options: NetworkedSyncplayClientOptions<State, Input>): NetworkedSyncplayClient;
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* Reusable, production-shaped client surface for deterministic multiplayer.
|
|
299
|
+
*
|
|
300
|
+
* A game joins a deterministic room by code (or creates one) and gets back a
|
|
301
|
+
* {@link NetworkedClientTransport} — the exact socket-like surface the
|
|
302
|
+
* deterministic engine's `createNetworkedSyncplayClient` consumes. There is
|
|
303
|
+
* NO per-game server logic: the server-side deterministic room (built-in input
|
|
304
|
+
* authority) is generic, and this transport is a thin, opaque pass-through of the
|
|
305
|
+
* frozen `rdm-local-authority/v1` session envelope over the `rdm` room channel.
|
|
306
|
+
*
|
|
307
|
+
* The room's raw channel ({@link ServerRoom.sendRaw}/{@link ServerRoom.onRaw})
|
|
308
|
+
* carries the session envelope verbatim; the typed-message path would spread a
|
|
309
|
+
* raw string and corrupt it, which is why the raw channel exists.
|
|
310
|
+
*/
|
|
311
|
+
|
|
312
|
+
/** Connection-health signal surfaced by {@link SyncplayRoomTransport.onConnectionEvent}. */
|
|
313
|
+
type SyncplayConnectionEvent = {
|
|
314
|
+
readonly kind: 'error';
|
|
315
|
+
readonly message: string;
|
|
316
|
+
} | {
|
|
317
|
+
readonly kind: 'disconnected';
|
|
318
|
+
} | {
|
|
319
|
+
readonly kind: 'reconnecting';
|
|
320
|
+
};
|
|
321
|
+
interface SyncplayRoomTransport extends NetworkedClientTransport {
|
|
322
|
+
/** The shareable room code (e.g. "HX9KWR"). */
|
|
323
|
+
readonly roomCode: string;
|
|
324
|
+
/** This client's player id, as assigned by the server on join. */
|
|
325
|
+
readonly playerId: string;
|
|
326
|
+
/** Leave the deterministic room and close the underlying connection. */
|
|
327
|
+
close(): void;
|
|
328
|
+
/**
|
|
329
|
+
* Connection-health signal: socket errors, disconnects, and reconnect
|
|
330
|
+
* attempts. Without observing this, a mid-match socket drop is silent — the
|
|
331
|
+
* room layer no-ops sends while dead, so the engine would predict into a
|
|
332
|
+
* dead socket forever. Games should surface these to the player and/or tear
|
|
333
|
+
* the match down.
|
|
334
|
+
*/
|
|
335
|
+
onConnectionEvent(handler: (event: SyncplayConnectionEvent) => void): void;
|
|
336
|
+
}
|
|
337
|
+
/**
|
|
338
|
+
* Join an existing deterministic room by its 6-char code and return a transport
|
|
339
|
+
* ready to hand to `createNetworkedSyncplayClient`.
|
|
340
|
+
*/
|
|
341
|
+
declare function joinSyncplayRoomByCode(api: MultiplayerApi, code: string): Promise<SyncplayRoomTransport>;
|
|
342
|
+
/** Options for {@link quickMatchSyncplayRoom}. */
|
|
343
|
+
interface QuickMatchSyncplayOptions {
|
|
344
|
+
/**
|
|
345
|
+
* Auto-inject a coarse `region` criterion (default true). See
|
|
346
|
+
* {@link quickMatchSyncplayRoom} for the semantics and the tradeoff.
|
|
347
|
+
*/
|
|
348
|
+
readonly autoRegion?: boolean;
|
|
349
|
+
}
|
|
350
|
+
/**
|
|
351
|
+
* Quick-match into a deterministic room (M9): the platform's joinOrCreate
|
|
352
|
+
* matchmaking pools compatible players into an open room or creates a fresh
|
|
353
|
+
* one. Optional `criteria` narrow the pool (matched exactly by the platform).
|
|
354
|
+
* With drop-in defaults the match starts immediately; unfilled slots
|
|
355
|
+
* substitute the canonical null input, which a game can treat as
|
|
356
|
+
* "bot-controlled" deterministically (see SYNCPLAY.md — Bots & quick match).
|
|
357
|
+
*
|
|
358
|
+
* Region-aware by default (G6): a coarse `region` criterion ('na' | 'sa' |
|
|
359
|
+
* 'eu' | 'africa' | 'asia' | 'oceania', derived from the device timezone) is
|
|
360
|
+
* auto-injected so cross-ocean pairings — whose RTT forces constant deep
|
|
361
|
+
* rollback — don't happen by accident. An explicit `criteria.region` wins
|
|
362
|
+
* over the derived value, and an underivable region ('unknown') is never
|
|
363
|
+
* injected: pooling globally beats fragmenting into an 'unknown' bucket.
|
|
364
|
+
*
|
|
365
|
+
* Tradeoff: strict region pools can go thin for low-traffic games. Pass
|
|
366
|
+
* `{ autoRegion: false }` (or your own `region` value) to pool globally;
|
|
367
|
+
* cross-region fallback-after-timeout is future work.
|
|
368
|
+
*/
|
|
369
|
+
declare function quickMatchSyncplayRoom(api: MultiplayerApi, criteria?: Record<string, string | number>, options?: QuickMatchSyncplayOptions): Promise<SyncplayRoomTransport>;
|
|
370
|
+
/**
|
|
371
|
+
* Create a new deterministic room and return a transport ready to hand to
|
|
372
|
+
* `createNetworkedSyncplayClient`. The server mints the room code; read it
|
|
373
|
+
* back from {@link SyncplayRoomTransport.roomCode} to share with peers.
|
|
374
|
+
* (Caller-chosen codes are not supported on create — when the platform grows
|
|
375
|
+
* that path, this signature gains a typed parameter rather than a dead one.)
|
|
376
|
+
*/
|
|
377
|
+
declare function createSyncplayRoom(api: MultiplayerApi): Promise<SyncplayRoomTransport>;
|
|
378
|
+
|
|
379
|
+
export { type ConfirmedInputFrame as C, type DeterministicSessionDecodeRejection as D, type EncodedInput as E, type InputAuthority as I, type NetworkedClientTransport as N, type QuickMatchSyncplayOptions as Q, type SyncplayRoomTransport as S, type DeterministicSessionDecodeResult as a, type DeterministicSessionMessage as b, type DeterministicSessionMessageKind as c, type DeterministicSessionRole as d, type InputAuthorityConfig as e, type InputAuthorityRestoreState as f, type InputAuthorityStats as g, type InputRejectionReason as h, type InputSubmissionResult as i, type NetworkedSyncplayClient as j, type NetworkedSyncplayClientInputDelayOptions as k, type NetworkedSyncplayClientNetStats as l, type NetworkedSyncplayClientOptions as m, type NetworkedSyncplayClientPacingOptions as n, createInputAuthority as o, createNetworkedSyncplayClient as p, createSyncplayRoom as q, decodeDeterministicSessionMessage as r, deterministicSessionWireVersion as s, encodeDeterministicSessionMessage as t, joinSyncplayRoomByCode as u, quickMatchSyncplayRoom as v };
|