@lagless/relay-server 0.0.33

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.
@@ -0,0 +1,9 @@
1
+ export * from './lib/types.js';
2
+ export { ServerClock } from './lib/server-clock.js';
3
+ export { PlayerConnection } from './lib/player-connection.js';
4
+ export { InputHandler, type ValidatedInput, type ValidationResult } from './lib/input-handler.js';
5
+ export { StateTransfer, type StateResponse, type StateTransferResult } from './lib/state-transfer.js';
6
+ export { RelayRoom } from './lib/relay-room.js';
7
+ export { RoomRegistry } from './lib/room-registry.js';
8
+ export { LatencySimulator, type LatencySimulatorConfig } from './lib/latency-simulator.js';
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,KAAK,cAAc,EAAE,KAAK,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAClG,OAAO,EAAE,aAAa,EAAE,KAAK,aAAa,EAAE,KAAK,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AACtG,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,KAAK,sBAAsB,EAAE,MAAM,4BAA4B,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,8 @@
1
+ export * from './lib/types.js';
2
+ export { ServerClock } from './lib/server-clock.js';
3
+ export { PlayerConnection } from './lib/player-connection.js';
4
+ export { InputHandler } from './lib/input-handler.js';
5
+ export { StateTransfer } from './lib/state-transfer.js';
6
+ export { RelayRoom } from './lib/relay-room.js';
7
+ export { RoomRegistry } from './lib/room-registry.js';
8
+ export { LatencySimulator } from './lib/latency-simulator.js';
@@ -0,0 +1,48 @@
1
+ import { TickInputKind, CancelReason } from '@lagless/net-wire';
2
+ import type { ServerClock } from './server-clock.js';
3
+ import type { PlayerConnection } from './player-connection.js';
4
+ import type { RoomTypeConfig, PlayerSlot } from './types.js';
5
+ export interface ValidatedInput {
6
+ readonly tick: number;
7
+ readonly playerSlot: PlayerSlot;
8
+ readonly seq: number;
9
+ readonly kind: TickInputKind;
10
+ readonly payload: Uint8Array;
11
+ }
12
+ export type ValidationResult = {
13
+ readonly accepted: true;
14
+ readonly input: ValidatedInput;
15
+ } | {
16
+ readonly accepted: false;
17
+ readonly reason: CancelReason;
18
+ readonly tick: number;
19
+ readonly seq: number;
20
+ };
21
+ export declare class InputHandler {
22
+ private readonly _clock;
23
+ private readonly _config;
24
+ constructor(_clock: ServerClock, _config: RoomTypeConfig);
25
+ /**
26
+ * Parse and validate a TickInputBatch message from a client.
27
+ * Returns one ValidationResult per input in the batch.
28
+ */
29
+ validateClientInputBatch(senderSlot: PlayerSlot, raw: ArrayBuffer): ValidationResult[];
30
+ /**
31
+ * Broadcast a validated input to all connected players as TickInputFanout.
32
+ */
33
+ broadcastInput(input: ValidatedInput, connections: ReadonlyMap<PlayerSlot, PlayerConnection>): void;
34
+ /**
35
+ * Broadcast multiple inputs in a single fanout message.
36
+ */
37
+ broadcastInputBatch(inputs: ValidatedInput[], connections: ReadonlyMap<PlayerSlot, PlayerConnection>): void;
38
+ /**
39
+ * Send a batch of inputs to a single player as TickInputFanout.
40
+ * Used for replaying server event journal on connect.
41
+ */
42
+ sendInputBatchToPlayer(inputs: ValidatedInput[], connection: PlayerConnection): void;
43
+ /**
44
+ * Send CancelInput to a specific player.
45
+ */
46
+ sendCancel(connection: PlayerConnection, tick: number, seq: number, reason: CancelReason): void;
47
+ }
48
+ //# sourceMappingURL=input-handler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"input-handler.d.ts","sourceRoot":"","sources":["../../src/lib/input-handler.ts"],"names":[],"mappings":"AACA,OAAO,EACL,aAAa,EAAE,YAAY,EAG5B,MAAM,mBAAmB,CAAC;AAE3B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAQ7D,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;IAChC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;IAC7B,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAC;CAC9B;AAED,MAAM,MAAM,gBAAgB,GACxB;IAAE,QAAQ,CAAC,QAAQ,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAA;CAAE,GAC3D;IAAE,QAAQ,CAAC,QAAQ,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC;AAI7G,qBAAa,YAAY;IAErB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,OAAO;gBADP,MAAM,EAAE,WAAW,EACnB,OAAO,EAAE,cAAc;IAG1C;;;OAGG;IACI,wBAAwB,CAC7B,UAAU,EAAE,UAAU,EACtB,GAAG,EAAE,WAAW,GACf,gBAAgB,EAAE;IA+ErB;;OAEG;IACI,cAAc,CACnB,KAAK,EAAE,cAAc,EACrB,WAAW,EAAE,WAAW,CAAC,UAAU,EAAE,gBAAgB,CAAC,GACrD,IAAI;IAcP;;OAEG;IACI,mBAAmB,CACxB,MAAM,EAAE,cAAc,EAAE,EACxB,WAAW,EAAE,WAAW,CAAC,UAAU,EAAE,gBAAgB,CAAC,GACrD,IAAI;IAaP;;;OAGG;IACI,sBAAsB,CAC3B,MAAM,EAAE,cAAc,EAAE,EACxB,UAAU,EAAE,gBAAgB,GAC3B,IAAI;IAWP;;OAEG;IACI,UAAU,CACf,UAAU,EAAE,gBAAgB,EAC5B,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,YAAY,GACnB,IAAI;CASR"}
@@ -0,0 +1,143 @@
1
+ import { createLogger } from '@lagless/misc';
2
+ import { TickInputKind, CancelReason, HeaderSchema, packTickInputFanout, packCancelInput, } from '@lagless/net-wire';
3
+ import { LE } from '@lagless/binary';
4
+ const log = createLogger('InputHandler');
5
+ const TICK_INPUT_HEADER_SIZE = 12; // tick(4) + slot(1) + seq(4) + kind(1) + payloadLength(2)
6
+ // ─── InputHandler ───────────────────────────────────────────
7
+ export class InputHandler {
8
+ _clock;
9
+ _config;
10
+ constructor(_clock, _config) {
11
+ this._clock = _clock;
12
+ this._config = _config;
13
+ }
14
+ /**
15
+ * Parse and validate a TickInputBatch message from a client.
16
+ * Returns one ValidationResult per input in the batch.
17
+ */
18
+ validateClientInputBatch(senderSlot, raw) {
19
+ const view = new DataView(raw);
20
+ let offset = HeaderSchema.byteLength; // skip header
21
+ if (offset + 1 > raw.byteLength) {
22
+ log.warn(`validateClientInputBatch: message too short for batch header (${raw.byteLength} bytes)`);
23
+ return [];
24
+ }
25
+ const inputCount = view.getUint8(offset);
26
+ offset += 1;
27
+ const results = [];
28
+ for (let i = 0; i < inputCount; i++) {
29
+ if (offset + TICK_INPUT_HEADER_SIZE > raw.byteLength) {
30
+ log.warn(`validateClientInputBatch: truncated at input ${i}/${inputCount} (offset=${offset}, byteLength=${raw.byteLength})`);
31
+ break;
32
+ }
33
+ const tick = view.getUint32(offset, LE);
34
+ offset += 4;
35
+ const claimedSlot = view.getUint8(offset);
36
+ offset += 1;
37
+ const seq = view.getUint32(offset, LE);
38
+ offset += 4;
39
+ const kind = view.getUint8(offset);
40
+ offset += 1;
41
+ const payloadLength = view.getUint16(offset, LE);
42
+ offset += 2;
43
+ if (offset + payloadLength > raw.byteLength) {
44
+ log.warn(`validateClientInputBatch: truncated payload at input ${i}/${inputCount} (need=${payloadLength}, remaining=${raw.byteLength - offset})`);
45
+ break;
46
+ }
47
+ if (claimedSlot !== senderSlot) {
48
+ log.warn(`Batch slot mismatch: sender=${senderSlot}, claimed=${claimedSlot}`);
49
+ results.push({ accepted: false, reason: CancelReason.InvalidSlot, tick, seq });
50
+ offset += payloadLength;
51
+ continue;
52
+ }
53
+ if (kind === TickInputKind.Server) {
54
+ log.warn(`Client sent Server-kind input in batch, slot=${senderSlot}`);
55
+ results.push({ accepted: false, reason: CancelReason.InvalidSlot, tick, seq });
56
+ offset += payloadLength;
57
+ continue;
58
+ }
59
+ const serverTick = this._clock.tick;
60
+ if (tick < serverTick) {
61
+ log.warn(`REJECT TooOld: slot=${senderSlot} inputTick=${tick} serverTick=${serverTick} delta=${tick - serverTick} seq=${seq}`);
62
+ results.push({ accepted: false, reason: CancelReason.TooOld, tick, seq });
63
+ offset += payloadLength;
64
+ continue;
65
+ }
66
+ if (tick > serverTick + this._config.maxFutureTicks) {
67
+ log.warn(`REJECT TooFarFuture: slot=${senderSlot} inputTick=${tick} serverTick=${serverTick} delta=${tick - serverTick} maxFuture=${this._config.maxFutureTicks} seq=${seq}`);
68
+ results.push({ accepted: false, reason: CancelReason.TooFarFuture, tick, seq });
69
+ offset += payloadLength;
70
+ continue;
71
+ }
72
+ const payload = new Uint8Array(raw.slice(offset, offset + payloadLength));
73
+ offset += payloadLength;
74
+ log.debug(`ACCEPT: slot=${senderSlot} inputTick=${tick} serverTick=${serverTick} delta=${tick - serverTick} seq=${seq} payloadLen=${payloadLength}`);
75
+ results.push({
76
+ accepted: true,
77
+ input: {
78
+ tick,
79
+ playerSlot: senderSlot,
80
+ seq,
81
+ kind: TickInputKind.Client,
82
+ payload,
83
+ },
84
+ });
85
+ }
86
+ return results;
87
+ }
88
+ /**
89
+ * Broadcast a validated input to all connected players as TickInputFanout.
90
+ */
91
+ broadcastInput(input, connections) {
92
+ const fanout = packTickInputFanout({
93
+ serverTick: this._clock.tick,
94
+ inputs: [input],
95
+ });
96
+ let sentCount = 0;
97
+ for (const conn of connections.values()) {
98
+ if (conn.isConnected)
99
+ sentCount++;
100
+ conn.send(fanout);
101
+ }
102
+ log.debug(`BROADCAST: tick=${input.tick} slot=${input.playerSlot} kind=${input.kind} → ${sentCount} connected clients`);
103
+ }
104
+ /**
105
+ * Broadcast multiple inputs in a single fanout message.
106
+ */
107
+ broadcastInputBatch(inputs, connections) {
108
+ if (inputs.length === 0)
109
+ return;
110
+ const fanout = packTickInputFanout({
111
+ serverTick: this._clock.tick,
112
+ inputs,
113
+ });
114
+ for (const conn of connections.values()) {
115
+ conn.send(fanout);
116
+ }
117
+ }
118
+ /**
119
+ * Send a batch of inputs to a single player as TickInputFanout.
120
+ * Used for replaying server event journal on connect.
121
+ */
122
+ sendInputBatchToPlayer(inputs, connection) {
123
+ if (inputs.length === 0)
124
+ return;
125
+ const fanout = packTickInputFanout({
126
+ serverTick: this._clock.tick,
127
+ inputs,
128
+ });
129
+ connection.send(fanout);
130
+ }
131
+ /**
132
+ * Send CancelInput to a specific player.
133
+ */
134
+ sendCancel(connection, tick, seq, reason) {
135
+ const msg = packCancelInput({
136
+ tick,
137
+ playerSlot: connection.slot,
138
+ seq,
139
+ reason,
140
+ });
141
+ connection.send(msg);
142
+ }
143
+ }
@@ -0,0 +1,22 @@
1
+ export interface LatencySimulatorConfig {
2
+ delayMs: number;
3
+ jitterMs: number;
4
+ packetLossPercent: number;
5
+ }
6
+ /**
7
+ * Wraps callbacks with artificial delay, jitter, and packet loss.
8
+ * Used for testing network adaptation under poor conditions.
9
+ */
10
+ export declare class LatencySimulator {
11
+ private _delayMs;
12
+ private _jitterMs;
13
+ private _packetLossPercent;
14
+ constructor(config: LatencySimulatorConfig);
15
+ /** Wraps a callback with artificial delay; drops it on simulated packet loss. */
16
+ apply(fn: () => void): void;
17
+ setDelay(ms: number): void;
18
+ setJitter(ms: number): void;
19
+ setPacketLoss(percent: number): void;
20
+ get config(): LatencySimulatorConfig;
21
+ }
22
+ //# sourceMappingURL=latency-simulator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"latency-simulator.d.ts","sourceRoot":"","sources":["../../src/lib/latency-simulator.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED;;;GAGG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,kBAAkB,CAAS;gBAEvB,MAAM,EAAE,sBAAsB;IAM1C,iFAAiF;IACjF,KAAK,CAAC,EAAE,EAAE,MAAM,IAAI,GAAG,IAAI;IAkB3B,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAI1B,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAI3B,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAIpC,IAAI,MAAM,IAAI,sBAAsB,CAMnC;CACF"}
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Wraps callbacks with artificial delay, jitter, and packet loss.
3
+ * Used for testing network adaptation under poor conditions.
4
+ */
5
+ export class LatencySimulator {
6
+ _delayMs;
7
+ _jitterMs;
8
+ _packetLossPercent;
9
+ constructor(config) {
10
+ this._delayMs = config.delayMs;
11
+ this._jitterMs = config.jitterMs;
12
+ this._packetLossPercent = config.packetLossPercent;
13
+ }
14
+ /** Wraps a callback with artificial delay; drops it on simulated packet loss. */
15
+ apply(fn) {
16
+ // Simulate packet loss
17
+ if (this._packetLossPercent > 0 && Math.random() * 100 < this._packetLossPercent) {
18
+ return;
19
+ }
20
+ const jitter = this._jitterMs > 0
21
+ ? (Math.random() * 2 - 1) * this._jitterMs
22
+ : 0;
23
+ const delay = Math.max(0, this._delayMs + jitter);
24
+ if (delay === 0) {
25
+ fn();
26
+ }
27
+ else {
28
+ setTimeout(fn, delay);
29
+ }
30
+ }
31
+ setDelay(ms) {
32
+ this._delayMs = Math.max(0, ms);
33
+ }
34
+ setJitter(ms) {
35
+ this._jitterMs = Math.max(0, ms);
36
+ }
37
+ setPacketLoss(percent) {
38
+ this._packetLossPercent = Math.max(0, Math.min(100, percent));
39
+ }
40
+ get config() {
41
+ return {
42
+ delayMs: this._delayMs,
43
+ jitterMs: this._jitterMs,
44
+ packetLossPercent: this._packetLossPercent,
45
+ };
46
+ }
47
+ }
@@ -0,0 +1,29 @@
1
+ import type { PlayerId, PlayerSlot, PlayerInfo, IWebSocket } from './types.js';
2
+ import { ConnectionState } from './types.js';
3
+ /**
4
+ * Represents a player's connection to a relay room.
5
+ * Manages connection state, WebSocket reference, and reconnect timing.
6
+ */
7
+ export declare class PlayerConnection {
8
+ private readonly _info;
9
+ private _state;
10
+ private _disconnectedAt;
11
+ private _ws;
12
+ private _hasConnectedBefore;
13
+ constructor(_info: PlayerInfo, ws: IWebSocket | null);
14
+ get info(): PlayerInfo;
15
+ get playerId(): PlayerId;
16
+ get slot(): PlayerSlot;
17
+ get isBot(): boolean;
18
+ get state(): ConnectionState;
19
+ get isConnected(): boolean;
20
+ get isDisconnected(): boolean;
21
+ get isGone(): boolean;
22
+ send(data: Uint8Array): void;
23
+ get hasConnectedBefore(): boolean;
24
+ connect(ws: IWebSocket): void;
25
+ markDisconnected(): void;
26
+ markGone(): void;
27
+ isReconnectExpired(timeoutMs: number): boolean;
28
+ }
29
+ //# sourceMappingURL=player-connection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"player-connection.d.ts","sourceRoot":"","sources":["../../src/lib/player-connection.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC/E,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAE7C;;;GAGG;AACH,qBAAa,gBAAgB;IAOzB,OAAO,CAAC,QAAQ,CAAC,KAAK;IANxB,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,eAAe,CAAuB;IAC9C,OAAO,CAAC,GAAG,CAAoB;IAC/B,OAAO,CAAC,mBAAmB,CAAS;gBAGjB,KAAK,EAAE,UAAU,EAClC,EAAE,EAAE,UAAU,GAAG,IAAI;IAMvB,IAAW,IAAI,IAAI,UAAU,CAAuB;IACpD,IAAW,QAAQ,IAAI,QAAQ,CAAgC;IAC/D,IAAW,IAAI,IAAI,UAAU,CAA4B;IACzD,IAAW,KAAK,IAAI,OAAO,CAA6B;IACxD,IAAW,KAAK,IAAI,eAAe,CAAwB;IAE3D,IAAW,WAAW,IAAI,OAAO,CAEhC;IAED,IAAW,cAAc,IAAI,OAAO,CAEnC;IAED,IAAW,MAAM,IAAI,OAAO,CAE3B;IAEM,IAAI,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI;IAKnC,IAAW,kBAAkB,IAAI,OAAO,CAEvC;IAEM,OAAO,CAAC,EAAE,EAAE,UAAU,GAAG,IAAI;IAO7B,gBAAgB,IAAI,IAAI;IAMxB,QAAQ,IAAI,IAAI;IAMhB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO;CAKtD"}
@@ -0,0 +1,62 @@
1
+ import { ConnectionState } from './types.js';
2
+ /**
3
+ * Represents a player's connection to a relay room.
4
+ * Manages connection state, WebSocket reference, and reconnect timing.
5
+ */
6
+ export class PlayerConnection {
7
+ _info;
8
+ _state;
9
+ _disconnectedAt = null;
10
+ _ws;
11
+ _hasConnectedBefore = false;
12
+ constructor(_info, ws) {
13
+ this._info = _info;
14
+ this._ws = ws;
15
+ this._state = _info.isBot ? ConnectionState.Gone : ConnectionState.Disconnected;
16
+ }
17
+ get info() { return this._info; }
18
+ get playerId() { return this._info.playerId; }
19
+ get slot() { return this._info.slot; }
20
+ get isBot() { return this._info.isBot; }
21
+ get state() { return this._state; }
22
+ get isConnected() {
23
+ return this._state === ConnectionState.Connected;
24
+ }
25
+ get isDisconnected() {
26
+ return this._state === ConnectionState.Disconnected;
27
+ }
28
+ get isGone() {
29
+ return this._state === ConnectionState.Gone;
30
+ }
31
+ send(data) {
32
+ if (this._state !== ConnectionState.Connected || !this._ws)
33
+ return;
34
+ this._ws.sendBinary(data);
35
+ }
36
+ get hasConnectedBefore() {
37
+ return this._hasConnectedBefore;
38
+ }
39
+ connect(ws) {
40
+ this._state = ConnectionState.Connected;
41
+ this._disconnectedAt = null;
42
+ this._ws = ws;
43
+ this._hasConnectedBefore = true;
44
+ }
45
+ markDisconnected() {
46
+ this._state = ConnectionState.Disconnected;
47
+ this._disconnectedAt = performance.now();
48
+ this._ws = null;
49
+ }
50
+ markGone() {
51
+ this._state = ConnectionState.Gone;
52
+ this._disconnectedAt = null;
53
+ this._ws = null;
54
+ }
55
+ isReconnectExpired(timeoutMs) {
56
+ if (this._state !== ConnectionState.Disconnected)
57
+ return false;
58
+ if (this._disconnectedAt === null)
59
+ return false;
60
+ return performance.now() - this._disconnectedAt > timeoutMs;
61
+ }
62
+ }
@@ -0,0 +1,71 @@
1
+ import { LatencySimulator } from './latency-simulator.js';
2
+ import { type MatchId, type PlayerId, type PlayerSlot, type PlayerInfo, type RoomTypeConfig, type RoomHooks, type RoomContext, type IWebSocket, type InputRegistry } from './types.js';
3
+ /**
4
+ * Manages one match room. Sealed by design — use RoomHooks for game-specific behavior.
5
+ */
6
+ export declare class RelayRoom {
7
+ readonly matchId: MatchId;
8
+ readonly roomType: string;
9
+ private readonly _config;
10
+ private readonly _hooks;
11
+ private readonly _clock;
12
+ private readonly _inputHandler;
13
+ private readonly _stateTransfer;
14
+ private readonly _connections;
15
+ private readonly _playersByPlayerId;
16
+ private readonly _results;
17
+ private readonly _serverEventJournal;
18
+ private readonly _context;
19
+ private readonly _createdAt;
20
+ private readonly _seed;
21
+ private readonly _scopeJson;
22
+ private readonly _inputRegistry;
23
+ private _disposed;
24
+ private _reconnectTimer;
25
+ private _serverSeq;
26
+ private _latencySimulator;
27
+ private _nextSlot;
28
+ constructor(matchId: MatchId, roomType: string, _config: RoomTypeConfig, _hooks: RoomHooks<unknown>, inputRegistry: InputRegistry, players: ReadonlyArray<{
29
+ playerId: PlayerId;
30
+ isBot: boolean;
31
+ metadata: Record<string, unknown>;
32
+ }>, seed: Uint8Array, scopeJson?: string);
33
+ init(): Promise<void>;
34
+ get isDisposed(): boolean;
35
+ get tick(): number;
36
+ get config(): Readonly<RoomTypeConfig>;
37
+ get context(): RoomContext;
38
+ get createdAt(): number;
39
+ get hasOpenSlots(): boolean;
40
+ get latencySimulator(): LatencySimulator | null;
41
+ set latencySimulator(sim: LatencySimulator | null);
42
+ getConnectedHumanCount(): number;
43
+ getTotalHumanCount(): number;
44
+ addPlayer(playerId: PlayerId, isBot: boolean, metadata: Readonly<Record<string, unknown>>): PlayerInfo | null;
45
+ /** @internal */
46
+ getPlayerInfos(): ReadonlyArray<PlayerInfo>;
47
+ /** @internal */
48
+ isSlotConnected(slot: PlayerSlot): boolean;
49
+ /** @internal */
50
+ sendToSlot(slot: PlayerSlot, message: Uint8Array): void;
51
+ /** @internal */
52
+ broadcastToAll(message: Uint8Array): void;
53
+ /** @internal */
54
+ requestEndMatch(): void;
55
+ handlePlayerConnect(playerId: PlayerId, ws: IWebSocket): Promise<boolean>;
56
+ handlePlayerDisconnect(playerId: PlayerId): Promise<void>;
57
+ handleMessage(playerId: PlayerId, data: ArrayBuffer): void;
58
+ dispose(): Promise<void>;
59
+ /** @internal - called by RoomContextImpl */
60
+ _emitServerEvent(inputId: number, data: Record<string, number | ArrayLike<number>>, tick: number): void;
61
+ private handleTickInputBatch;
62
+ private handlePing;
63
+ private handlePlayerFinished;
64
+ private handleStateResponse;
65
+ private checkMatchEnd;
66
+ private endMatch;
67
+ private checkReconnectTimeouts;
68
+ private buildServerHello;
69
+ private sendStateToPlayer;
70
+ }
71
+ //# sourceMappingURL=relay-room.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"relay-room.d.ts","sourceRoot":"","sources":["../../src/lib/relay-room.ts"],"names":[],"mappings":"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"}