@loova/game-sdk 0.1.0-alpha.1 → 0.1.0-alpha.3

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/README.md CHANGED
@@ -17,12 +17,16 @@ The protocol source of truth is
17
17
  Protobuf-ES bindings are committed under `src/gen`; published packages do not
18
18
  need `buf` or `protoc` at runtime.
19
19
 
20
- ## Runtime client
20
+ ## Stable realtime core
21
21
 
22
22
  ```ts
23
- import { InputAction, createLoovaGameSDK } from "@loova/game-sdk";
23
+ import {
24
+ TypedProfileClient,
25
+ createJsonCodec,
26
+ createLoovaRealtimeClient,
27
+ } from "@loova/game-sdk";
24
28
 
25
- const sdk = createLoovaGameSDK({
29
+ const sdk = createLoovaRealtimeClient({
26
30
  apiUrl: "https://api.loova.example",
27
31
  });
28
32
 
@@ -37,12 +41,19 @@ await sdk.connect({
37
41
  roomId: session.roomId,
38
42
  });
39
43
 
40
- sdk.sendInput({
44
+ const shooter = new TypedProfileClient(sdk, {
45
+ schemaId: "loova/shooter/v1",
46
+ commands: createJsonCodec<ShooterCommand>(),
47
+ states: createJsonCodec<ShooterState>(),
48
+ events: createJsonCodec<ShooterEvent>(),
49
+ });
50
+
51
+ shooter.send("input", {
41
52
  moveX: 1,
42
53
  moveY: 0,
43
54
  aimX: 1,
44
55
  aimY: 0,
45
- actions: InputAction.Fire,
56
+ actions: 1,
46
57
  });
47
58
  ```
48
59
 
@@ -52,28 +63,22 @@ never be created inside an untrusted browser game.
52
63
  ## Events
53
64
 
54
65
  ```ts
55
- sdk.onPlayerJoin(({ player }) => console.log("join", player.playerId));
56
- sdk.onSnapshot(({ serverTick, players }) => render(players, serverTick));
66
+ sdk.onPlayerJoin(({ playerId }) => console.log("join", playerId));
57
67
  sdk.onPlayerLeave(({ playerId }) => console.log("left", playerId));
58
- sdk.onDamage(({ playerId, damage }) => showDamage(playerId, damage));
59
- sdk.onDeath(({ playerId, killerPlayerId }) => showDeath(playerId, killerPlayerId));
60
68
  sdk.onMatchEnd(({ winnerPlayerId }) => showWinner(winnerPlayerId));
69
+
70
+ shooter.onState(({ state, revision }) => render(state, revision));
71
+ shooter.onEvent(({ eventType, event }) => showEffect(eventType, event));
61
72
  ```
62
73
 
63
74
  Every subscription returns an unsubscribe function.
64
75
 
65
- ## Prediction and interpolation
66
-
67
- - Sent inputs are retained in a bounded input buffer.
68
- - `FullSnapshot` acknowledges processed input sequences.
69
- - `ServerCorrection` resets the local player to authoritative state and replays
70
- unacknowledged inputs.
71
- - `getPredictedLocalPlayer()` returns the predicted local state.
72
- - `getInterpolatedPlayers()` returns remote state sampled behind realtime by the
73
- configured interpolation delay.
76
+ ## Profile boundary
74
77
 
75
- Prediction is visual only. The SDK never sends predicted positions, health,
76
- hits, deaths, or match outcomes back to the server.
78
+ SDK Core transports opaque `Command`, `GameState`, and `ProfileEvent` payloads.
79
+ It does not know about movement, health, weapons, cards, or physics. A typed
80
+ profile client supplies codecs for one schema ID. Prediction and interpolation
81
+ belong in optional profile adapters and remain presentation-only.
77
82
 
78
83
  ## Heartbeat and reconnect
79
84
 
@@ -83,16 +88,9 @@ The first frame on the replacement socket is `Reconnect` with the last received
83
88
  server sequence. Without a reconnect token, the SDK closes instead of replaying
84
89
  the one-time Auth ticket.
85
90
 
86
- ## Two-player demo
87
-
88
- ```bash
89
- npm run build
90
- npm run demo:build
91
- python3 -m http.server 4173
92
- ```
93
-
94
- Open `http://localhost:4173/demo/`, enter two one-time tickets for the same
95
- room, and connect. Space fires for player A; Enter fires for player B.
91
+ `LoovaGameClient` remains exported temporarily for source migration but targets
92
+ the retired shooter-specific wire messages. New games must use
93
+ `LoovaRealtimeClient`.
96
94
 
97
95
  ## Protocol stability
98
96
 
@@ -102,3 +100,17 @@ room, and connect. Space fires for player A; Enter fires for player B.
102
100
  reused.
103
101
  - Breaking protocol changes require a new protobuf package and protocol major
104
102
  version.
103
+
104
+
105
+ ## publish
106
+ npm run check
107
+ npm test
108
+ npm run build
109
+ npm pack --dry-run
110
+
111
+ npm pkg get name version
112
+
113
+ npm publish \
114
+ --tag alpha \
115
+ --access public \
116
+ --registry=https://registry.npmjs.org/
@@ -0,0 +1,69 @@
1
+ import { type Unsubscribe } from "./events.js";
2
+ import type { ProfileCommand, ProfileEventMessage, ProfileStateUpdate, ProfileTransport } from "./profile-client.js";
3
+ import { type CreateRoomOptions, type CreateRoomResult, type JoinRoomOptions, type JoinRoomResult } from "./room-api.js";
4
+ import { type WebSocketFactory } from "./websocket.js";
5
+ export declare const PROTOCOL_VERSION = 1;
6
+ export interface RealtimeConnectOptions {
7
+ websocketUrl: string;
8
+ ticket: string;
9
+ playerId: string;
10
+ roomId: string;
11
+ reconnectToken?: string;
12
+ }
13
+ export interface RealtimeReconnectOptions {
14
+ enabled?: boolean;
15
+ initialDelayMs?: number;
16
+ maximumDelayMs?: number;
17
+ maximumAttempts?: number;
18
+ }
19
+ export interface LoovaRealtimeClientOptions {
20
+ apiUrl: string;
21
+ protocolVersion?: number;
22
+ heartbeatIntervalMs?: number;
23
+ reconnect?: RealtimeReconnectOptions;
24
+ websocketFactory?: WebSocketFactory;
25
+ fetcher?: typeof fetch;
26
+ now?: () => number;
27
+ }
28
+ export interface WelcomeEvent {
29
+ roomId: string;
30
+ playerId: string;
31
+ tickRate: number;
32
+ snapshotRate: number;
33
+ simulationProfile: string;
34
+ }
35
+ export interface PresenceJoinEvent {
36
+ playerId: string;
37
+ }
38
+ export interface PresenceLeaveEvent {
39
+ playerId: string;
40
+ reason: number;
41
+ }
42
+ export interface RealtimeMatchEndEvent {
43
+ winnerPlayerId: string;
44
+ reason: number;
45
+ players: ReadonlyArray<{
46
+ playerId: string;
47
+ score: number;
48
+ winner: boolean;
49
+ }>;
50
+ }
51
+ type ConnectionState = "idle" | "connecting" | "connected" | "reconnecting" | "closed";
52
+ export declare class LoovaRealtimeClient implements ProfileTransport {
53
+ #private;
54
+ constructor(options: LoovaRealtimeClientOptions);
55
+ get state(): ConnectionState;
56
+ createRoom(options: CreateRoomOptions): Promise<CreateRoomResult>;
57
+ joinRoom(roomId: string, options: JoinRoomOptions): Promise<JoinRoomResult>;
58
+ connect(options: RealtimeConnectOptions): Promise<void>;
59
+ disconnect(code?: number, reason?: string): void;
60
+ sendCommand(command: ProfileCommand): bigint;
61
+ onWelcome(listener: (event: WelcomeEvent) => void): Unsubscribe;
62
+ onState(listener: (state: ProfileStateUpdate) => void): Unsubscribe;
63
+ onProfileEvent(listener: (event: ProfileEventMessage) => void): Unsubscribe;
64
+ onPlayerJoin(listener: (event: PresenceJoinEvent) => void): Unsubscribe;
65
+ onPlayerLeave(listener: (event: PresenceLeaveEvent) => void): Unsubscribe;
66
+ onMatchEnd(listener: (event: RealtimeMatchEndEvent) => void): Unsubscribe;
67
+ }
68
+ export {};
69
+ //# sourceMappingURL=core-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"core-client.d.ts","sourceRoot":"","sources":["../src/core-client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,365 @@
1
+ import { create, fromBinary, toBinary } from "@bufbuild/protobuf";
2
+ import { EventChannel } from "./events.js";
3
+ import { AuthSchema, ClientMessageSchema, CommandSchema, MessageType, PingSchema, ReconnectSchema, ServerMessageSchema, } from "./gen/realtime/v1/realtime_pb.js";
4
+ import { RoomApi, } from "./room-api.js";
5
+ import { browserWebSocketFactory, } from "./websocket.js";
6
+ export const PROTOCOL_VERSION = 1;
7
+ const MAX_PROFILE_PAYLOAD_BYTES = 64 * 1024;
8
+ const DEFAULT_RECONNECT = {
9
+ enabled: true,
10
+ initialDelayMs: 250,
11
+ maximumDelayMs: 5_000,
12
+ maximumAttempts: 8,
13
+ };
14
+ // LoovaRealtimeClient is the stable SDK core. It owns transport and lifecycle;
15
+ // profile codecs own every game-specific command, state, and event.
16
+ export class LoovaRealtimeClient {
17
+ #protocolVersion;
18
+ #heartbeatIntervalMs;
19
+ #reconnect;
20
+ #websocketFactory;
21
+ #now;
22
+ #rooms;
23
+ #welcome = new EventChannel();
24
+ #stateUpdate = new EventChannel();
25
+ #profileEvent = new EventChannel();
26
+ #playerJoin = new EventChannel();
27
+ #playerLeave = new EventChannel();
28
+ #matchEnd = new EventChannel();
29
+ #socket;
30
+ #connection;
31
+ #state = "idle";
32
+ #sequence = 0n;
33
+ #lastServerSequence = 0n;
34
+ #serverTick = 0n;
35
+ #heartbeatTimer;
36
+ #reconnectTimer;
37
+ #reconnectAttempts = 0;
38
+ #manualClose = false;
39
+ constructor(options) {
40
+ this.#protocolVersion = options.protocolVersion ?? PROTOCOL_VERSION;
41
+ this.#heartbeatIntervalMs = options.heartbeatIntervalMs ?? 10_000;
42
+ this.#reconnect = { ...DEFAULT_RECONNECT, ...options.reconnect };
43
+ this.#websocketFactory = options.websocketFactory ?? browserWebSocketFactory;
44
+ this.#now = options.now ?? Date.now;
45
+ this.#rooms = new RoomApi(options.apiUrl, options.fetcher);
46
+ }
47
+ get state() {
48
+ return this.#state;
49
+ }
50
+ async createRoom(options) {
51
+ return await this.#rooms.createRoom(options);
52
+ }
53
+ async joinRoom(roomId, options) {
54
+ return await this.#rooms.joinRoom(roomId, options);
55
+ }
56
+ connect(options) {
57
+ if (this.#state === "connecting" || this.#state === "connected") {
58
+ return Promise.reject(new Error("SDK is already connected"));
59
+ }
60
+ this.#connection = { ...options };
61
+ this.#manualClose = false;
62
+ this.#sequence = 0n;
63
+ this.#lastServerSequence = 0n;
64
+ return this.#open(false);
65
+ }
66
+ disconnect(code = 1000, reason = "client disconnect") {
67
+ this.#manualClose = true;
68
+ this.#state = "closed";
69
+ this.#clearTimers();
70
+ this.#socket?.close(code, reason);
71
+ this.#socket = undefined;
72
+ }
73
+ sendCommand(command) {
74
+ validateProfileCommand(command);
75
+ const sequence = this.#nextSequence();
76
+ this.#send(MessageType.COMMAND, sequence, {
77
+ case: "command",
78
+ value: create(CommandSchema, {
79
+ schemaId: command.schemaId,
80
+ commandType: command.commandType,
81
+ payload: command.payload,
82
+ clientTick: this.#serverTick,
83
+ }),
84
+ });
85
+ return sequence;
86
+ }
87
+ onWelcome(listener) {
88
+ return this.#welcome.subscribe(listener);
89
+ }
90
+ onState(listener) {
91
+ return this.#stateUpdate.subscribe(listener);
92
+ }
93
+ onProfileEvent(listener) {
94
+ return this.#profileEvent.subscribe(listener);
95
+ }
96
+ onPlayerJoin(listener) {
97
+ return this.#playerJoin.subscribe(listener);
98
+ }
99
+ onPlayerLeave(listener) {
100
+ return this.#playerLeave.subscribe(listener);
101
+ }
102
+ onMatchEnd(listener) {
103
+ return this.#matchEnd.subscribe(listener);
104
+ }
105
+ #open(isReconnect) {
106
+ const connection = this.#connection;
107
+ if (!connection) {
108
+ return Promise.reject(new Error("connection options are missing"));
109
+ }
110
+ this.#state = isReconnect ? "reconnecting" : "connecting";
111
+ const socket = this.#websocketFactory(websocketURL(connection.websocketUrl, connection.roomId));
112
+ socket.binaryType = "arraybuffer";
113
+ this.#socket = socket;
114
+ return new Promise((resolve, reject) => {
115
+ let settled = false;
116
+ socket.onopen = () => {
117
+ if (isReconnect && connection.reconnectToken) {
118
+ this.#sendReconnect(connection);
119
+ }
120
+ else {
121
+ this.#sendAuth(connection);
122
+ }
123
+ };
124
+ socket.onmessage = (event) => {
125
+ try {
126
+ if (typeof event.data === "string") {
127
+ throw new Error("unexpected text server message");
128
+ }
129
+ const message = fromBinary(ServerMessageSchema, new Uint8Array(event.data));
130
+ this.#handleServerMessage(message);
131
+ if (!settled && message.payload.case === "welcome") {
132
+ settled = true;
133
+ this.#state = "connected";
134
+ this.#reconnectAttempts = 0;
135
+ this.#startHeartbeat();
136
+ resolve();
137
+ }
138
+ }
139
+ catch (error) {
140
+ if (!settled) {
141
+ settled = true;
142
+ reject(error);
143
+ }
144
+ socket.close(1002, "invalid server message");
145
+ }
146
+ };
147
+ socket.onerror = () => {
148
+ if (!settled) {
149
+ settled = true;
150
+ reject(new Error("WebSocket connection failed"));
151
+ }
152
+ };
153
+ socket.onclose = () => {
154
+ this.#stopHeartbeat();
155
+ if (!settled) {
156
+ settled = true;
157
+ reject(new Error("WebSocket closed before Welcome"));
158
+ }
159
+ if (!this.#manualClose) {
160
+ this.#scheduleReconnect();
161
+ }
162
+ };
163
+ });
164
+ }
165
+ #sendAuth(connection) {
166
+ const sequence = this.#nextSequence();
167
+ this.#send(MessageType.AUTH, sequence, {
168
+ case: "auth",
169
+ value: create(AuthSchema, {
170
+ ticket: connection.ticket,
171
+ playerId: connection.playerId,
172
+ roomId: connection.roomId,
173
+ protocolVersion: this.#protocolVersion,
174
+ }),
175
+ });
176
+ }
177
+ #sendReconnect(connection) {
178
+ const sequence = this.#nextSequence();
179
+ this.#send(MessageType.RECONNECT, sequence, {
180
+ case: "reconnect",
181
+ value: create(ReconnectSchema, {
182
+ reconnectToken: connection.reconnectToken ?? "",
183
+ playerId: connection.playerId,
184
+ roomId: connection.roomId,
185
+ lastReceivedSequence: this.#lastServerSequence,
186
+ }),
187
+ });
188
+ }
189
+ #send(messageType, sequence, payload) {
190
+ const socket = this.#socket;
191
+ if (!socket || socket.readyState !== socket.OPEN) {
192
+ throw new Error("WebSocket is not open");
193
+ }
194
+ socket.send(toBinary(ClientMessageSchema, create(ClientMessageSchema, {
195
+ protocolVersion: this.#protocolVersion,
196
+ messageType,
197
+ sequence,
198
+ serverTick: this.#serverTick,
199
+ payload,
200
+ })));
201
+ }
202
+ #handleServerMessage(message) {
203
+ if (message.protocolVersion !== this.#protocolVersion) {
204
+ throw new Error(`unsupported protocol version ${message.protocolVersion}`);
205
+ }
206
+ if (message.messageType !== expectedMessageType(message.payload.case)) {
207
+ throw new Error("server message type does not match payload");
208
+ }
209
+ if (message.sequence === 0n || message.sequence <= this.#lastServerSequence) {
210
+ throw new Error("server sequence is missing or out of order");
211
+ }
212
+ this.#lastServerSequence = message.sequence;
213
+ this.#serverTick = message.serverTick;
214
+ switch (message.payload.case) {
215
+ case "welcome":
216
+ this.#welcome.emit({
217
+ roomId: message.payload.value.roomId,
218
+ playerId: message.payload.value.playerId,
219
+ tickRate: message.payload.value.tickRate,
220
+ snapshotRate: message.payload.value.snapshotRate,
221
+ simulationProfile: message.payload.value.simulationProfile,
222
+ });
223
+ break;
224
+ case "gameState":
225
+ this.#stateUpdate.emit({
226
+ schemaId: message.payload.value.schemaId,
227
+ revision: message.payload.value.revision,
228
+ baseRevision: message.payload.value.baseRevision,
229
+ full: message.payload.value.full,
230
+ payload: message.payload.value.payload.slice(),
231
+ });
232
+ break;
233
+ case "profileEvent":
234
+ this.#profileEvent.emit({
235
+ schemaId: message.payload.value.schemaId,
236
+ eventType: message.payload.value.eventType,
237
+ eventId: message.payload.value.eventId,
238
+ payload: message.payload.value.payload.slice(),
239
+ });
240
+ break;
241
+ case "playerJoined":
242
+ this.#playerJoin.emit({ playerId: message.payload.value.playerId });
243
+ break;
244
+ case "playerLeft":
245
+ this.#playerLeave.emit({
246
+ playerId: message.payload.value.playerId,
247
+ reason: message.payload.value.reason,
248
+ });
249
+ break;
250
+ case "serverCorrection":
251
+ if (message.payload.value.authoritativeState) {
252
+ const state = message.payload.value.authoritativeState;
253
+ this.#stateUpdate.emit({
254
+ schemaId: state.schemaId,
255
+ revision: state.revision,
256
+ baseRevision: state.baseRevision,
257
+ full: state.full,
258
+ payload: state.payload.slice(),
259
+ });
260
+ }
261
+ break;
262
+ case "matchEnded":
263
+ this.#emitMatchEnd(message.payload.value);
264
+ break;
265
+ case "pong":
266
+ break;
267
+ default:
268
+ throw new Error(`unsupported server payload ${String(message.payload.case)}`);
269
+ }
270
+ }
271
+ #emitMatchEnd(match) {
272
+ this.#matchEnd.emit({
273
+ winnerPlayerId: match.winnerPlayerId,
274
+ reason: match.reason,
275
+ players: match.players.map((player) => ({
276
+ playerId: player.playerId,
277
+ score: player.score,
278
+ winner: player.winner,
279
+ })),
280
+ });
281
+ }
282
+ #startHeartbeat() {
283
+ this.#stopHeartbeat();
284
+ this.#heartbeatTimer = setInterval(() => {
285
+ if (this.#state !== "connected")
286
+ return;
287
+ const sequence = this.#nextSequence();
288
+ try {
289
+ this.#send(MessageType.PING, sequence, {
290
+ case: "ping",
291
+ value: create(PingSchema, {
292
+ nonce: sequence,
293
+ clientTimeMs: BigInt(Math.trunc(this.#now())),
294
+ }),
295
+ });
296
+ }
297
+ catch {
298
+ this.#socket?.close(1011, "heartbeat failed");
299
+ }
300
+ }, this.#heartbeatIntervalMs);
301
+ }
302
+ #scheduleReconnect() {
303
+ const connection = this.#connection;
304
+ if (!connection?.reconnectToken || !this.#reconnect.enabled ||
305
+ this.#reconnectAttempts >= this.#reconnect.maximumAttempts) {
306
+ this.#state = "closed";
307
+ return;
308
+ }
309
+ const delay = Math.min(this.#reconnect.initialDelayMs * 2 ** this.#reconnectAttempts, this.#reconnect.maximumDelayMs);
310
+ this.#reconnectAttempts += 1;
311
+ this.#state = "reconnecting";
312
+ this.#reconnectTimer = setTimeout(() => void this.#open(true).catch(() => { }), delay);
313
+ }
314
+ #nextSequence() {
315
+ this.#sequence += 1n;
316
+ return this.#sequence;
317
+ }
318
+ #stopHeartbeat() {
319
+ if (this.#heartbeatTimer !== undefined)
320
+ clearInterval(this.#heartbeatTimer);
321
+ this.#heartbeatTimer = undefined;
322
+ }
323
+ #clearTimers() {
324
+ this.#stopHeartbeat();
325
+ if (this.#reconnectTimer !== undefined)
326
+ clearTimeout(this.#reconnectTimer);
327
+ this.#reconnectTimer = undefined;
328
+ }
329
+ }
330
+ function validateProfileCommand(command) {
331
+ if (!command.schemaId || !command.commandType) {
332
+ throw new TypeError("profile command schemaId and commandType are required");
333
+ }
334
+ if (!(command.payload instanceof Uint8Array) || command.payload.byteLength > MAX_PROFILE_PAYLOAD_BYTES) {
335
+ throw new RangeError(`profile command payload must be at most ${MAX_PROFILE_PAYLOAD_BYTES} bytes`);
336
+ }
337
+ }
338
+ function websocketURL(baseURL, roomId) {
339
+ const url = new URL(baseURL);
340
+ url.searchParams.set("roomId", roomId);
341
+ return url.toString();
342
+ }
343
+ function expectedMessageType(payloadCase) {
344
+ switch (payloadCase) {
345
+ case "welcome":
346
+ return MessageType.WELCOME;
347
+ case "gameState":
348
+ return MessageType.GAME_STATE;
349
+ case "profileEvent":
350
+ return MessageType.PROFILE_EVENT;
351
+ case "playerJoined":
352
+ return MessageType.PLAYER_JOINED;
353
+ case "playerLeft":
354
+ return MessageType.PLAYER_LEFT;
355
+ case "serverCorrection":
356
+ return MessageType.SERVER_CORRECTION;
357
+ case "matchEnded":
358
+ return MessageType.MATCH_ENDED;
359
+ case "pong":
360
+ return MessageType.PONG;
361
+ default:
362
+ return MessageType.UNSPECIFIED;
363
+ }
364
+ }
365
+ //# sourceMappingURL=core-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"core-client.js","sourceRoot":"","sources":["../src/core-client.ts"],"names":[],"mappings":"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"}