@remix-gg/sdk 0.9.0 → 0.10.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/dist/index.d.mts +187 -4
- package/dist/index.d.ts +187 -4
- package/dist/index.js +864 -1
- package/dist/index.min.js +806 -3
- package/dist/index.min.js.map +6 -4
- package/dist/index.mjs +861 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -1,9 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `sdk.realtime` — realtime multiplayer rooms for Remix Desktop games.
|
|
3
|
+
*
|
|
4
|
+
* The game sees rooms, peers, and messages; everything else is deliberately
|
|
5
|
+
* invisible. The platform's room broker (Remix Desktop main) owns identity,
|
|
6
|
+
* room admission, signaling, and ICE minting; this controller rides the
|
|
7
|
+
* `multiplayer_*` game events both ways and drives the data-channel mesh
|
|
8
|
+
* (`./mesh.ts`) under the surface. A game never touches `RTCPeerConnection`,
|
|
9
|
+
* SDP, or ICE — which is what lets the transport change under a published
|
|
10
|
+
* game without the game updating.
|
|
11
|
+
*
|
|
12
|
+
* Membership truth is the SERVER ROSTER the broker relays
|
|
13
|
+
* (`multiplayer_peers`), never the mesh: a rebuilt slot re-fires its
|
|
14
|
+
* transport callbacks and a repeated bye can announce the same departure
|
|
15
|
+
* twice, so peer join/leave here is a roster diff and nothing else. The
|
|
16
|
+
* mesh's own callbacks are diagnostics.
|
|
17
|
+
*/
|
|
18
|
+
type RealtimePeer = {
|
|
19
|
+
userId: string;
|
|
20
|
+
username: string;
|
|
21
|
+
pfp: string | null;
|
|
22
|
+
/** ISO seat stamp; seat order (oldest first) is the deterministic tiebreak. */
|
|
23
|
+
joinedAt: string | null;
|
|
24
|
+
};
|
|
25
|
+
type RealtimeEndReason = 'left' | 'expired' | 'offline' | 'closed';
|
|
26
|
+
type RealtimeErrorCode = 'room_not_found' | 'room_full' | 'game_mismatch' | 'no_game_id' | 'join_failed';
|
|
27
|
+
declare class RealtimeRoomError extends Error {
|
|
28
|
+
readonly code: RealtimeErrorCode;
|
|
29
|
+
constructor(code: RealtimeErrorCode, message: string);
|
|
30
|
+
}
|
|
31
|
+
type RealtimeSendOptions = {
|
|
32
|
+
/**
|
|
33
|
+
* Default true: ordered, retransmitted — lobby, countdowns, results.
|
|
34
|
+
* `reliable: false` is the per-frame state stream (unordered, never
|
|
35
|
+
* retransmitted): a packet that arrives late is worth less than nothing,
|
|
36
|
+
* and one that never arrives is replaced by the next frame anyway.
|
|
37
|
+
*/
|
|
38
|
+
reliable?: boolean;
|
|
39
|
+
};
|
|
40
|
+
interface RealtimeRoom {
|
|
41
|
+
readonly roomId: string;
|
|
42
|
+
/** The join code — what the host shares with friends. */
|
|
43
|
+
readonly code: string;
|
|
44
|
+
readonly selfId: string;
|
|
45
|
+
readonly hostUserId: string;
|
|
46
|
+
/** Whether this player created the room. */
|
|
47
|
+
readonly isHost: boolean;
|
|
48
|
+
/** The live roster, self excluded, in seat order. */
|
|
49
|
+
readonly peers: RealtimePeer[];
|
|
50
|
+
readonly ended: boolean;
|
|
51
|
+
/** Broadcast to every peer. Data must be JSON-serializable. */
|
|
52
|
+
send(data: unknown, options?: RealtimeSendOptions): void;
|
|
53
|
+
sendTo(userId: string, data: unknown, options?: RealtimeSendOptions): void;
|
|
54
|
+
onMessage(callback: (fromUserId: string, data: unknown) => void): () => void;
|
|
55
|
+
onPeerJoin(callback: (peer: RealtimePeer) => void): () => void;
|
|
56
|
+
onPeerLeave(callback: (peer: RealtimePeer) => void): () => void;
|
|
57
|
+
onEnded(callback: (reason: RealtimeEndReason) => void): () => void;
|
|
58
|
+
/** Transport trouble worth telling the player about; the room keeps trying. */
|
|
59
|
+
onError(callback: (message: string) => void): () => void;
|
|
60
|
+
/**
|
|
61
|
+
* Open the platform's invite share flow — the friend picker that sends the
|
|
62
|
+
* room's join code into DMs and groups. The game never sees the friend
|
|
63
|
+
* list; the platform owns the whole exchange. A game may also just show
|
|
64
|
+
* `room.code` for players to share by hand.
|
|
65
|
+
*/
|
|
66
|
+
invite(): void;
|
|
67
|
+
leave(): void;
|
|
68
|
+
}
|
|
69
|
+
interface RealtimeNamespace {
|
|
70
|
+
/** Create a room for this game and take the first seat. One live room at a time. */
|
|
71
|
+
createRoom(): Promise<RealtimeRoom>;
|
|
72
|
+
/** Join a friend's room by its invite code. */
|
|
73
|
+
joinRoom(code: string): Promise<RealtimeRoom>;
|
|
74
|
+
/** The live room, or null. */
|
|
75
|
+
readonly room: RealtimeRoom | null;
|
|
76
|
+
/**
|
|
77
|
+
* Every room that becomes live — including one the PLATFORM joined for the
|
|
78
|
+
* player (accepting an invite boots the game already seated). A lobby
|
|
79
|
+
* screen should mount from here, not only from its own create/join call.
|
|
80
|
+
*/
|
|
81
|
+
onRoom(callback: (room: RealtimeRoom) => void): () => void;
|
|
82
|
+
/**
|
|
83
|
+
* A room the platform tried to join for the player (an accepted invite)
|
|
84
|
+
* that failed — full, expired, or the wrong game. There is no pending
|
|
85
|
+
* `createRoom`/`joinRoom` call to reject, so this is where the failure
|
|
86
|
+
* surfaces; a lobby should tell the player rather than sit solo as if
|
|
87
|
+
* nothing happened. Requested joins keep rejecting their own promise.
|
|
88
|
+
*/
|
|
89
|
+
onRoomError(callback: (error: RealtimeRoomError) => void): () => void;
|
|
90
|
+
}
|
|
91
|
+
|
|
1
92
|
declare global {
|
|
2
93
|
interface Window {
|
|
3
94
|
FarcadeSDK: typeof sdk;
|
|
4
95
|
RemixSDK: typeof sdk;
|
|
5
96
|
}
|
|
6
97
|
}
|
|
98
|
+
|
|
7
99
|
type ViewContext = 'feed' | 'full_screen' | 'challenge' | 'tournament';
|
|
8
100
|
type SafeAreaInset = {
|
|
9
101
|
top: number;
|
|
@@ -175,7 +267,89 @@ type PurchaseCompleteEvent = {
|
|
|
175
267
|
item?: string;
|
|
176
268
|
};
|
|
177
269
|
};
|
|
178
|
-
type
|
|
270
|
+
type RealtimeSignalKind = 'offer' | 'answer' | 'ice' | 'bye';
|
|
271
|
+
type MultiplayerCreateRoomEvent = {
|
|
272
|
+
type: 'multiplayer_create_room';
|
|
273
|
+
data: undefined;
|
|
274
|
+
};
|
|
275
|
+
type MultiplayerJoinRoomEvent = {
|
|
276
|
+
type: 'multiplayer_join_room';
|
|
277
|
+
data: {
|
|
278
|
+
code: string;
|
|
279
|
+
};
|
|
280
|
+
};
|
|
281
|
+
type MultiplayerLeaveRoomEvent = {
|
|
282
|
+
type: 'multiplayer_leave_room';
|
|
283
|
+
data: undefined;
|
|
284
|
+
};
|
|
285
|
+
type MultiplayerSignalEvent = {
|
|
286
|
+
type: 'multiplayer_signal';
|
|
287
|
+
data: {
|
|
288
|
+
toUserId: string;
|
|
289
|
+
kind: RealtimeSignalKind;
|
|
290
|
+
payload: string;
|
|
291
|
+
};
|
|
292
|
+
};
|
|
293
|
+
type MultiplayerRefreshIceEvent = {
|
|
294
|
+
type: 'multiplayer_refresh_ice';
|
|
295
|
+
data: undefined;
|
|
296
|
+
};
|
|
297
|
+
/**
|
|
298
|
+
* Open the platform's invite share flow for the live room. Carries nothing:
|
|
299
|
+
* the platform already knows the room's game and code.
|
|
300
|
+
*/
|
|
301
|
+
type MultiplayerRequestInviteEvent = {
|
|
302
|
+
type: 'multiplayer_request_invite';
|
|
303
|
+
data: undefined;
|
|
304
|
+
};
|
|
305
|
+
type MultiplayerSessionEvent = {
|
|
306
|
+
type: 'multiplayer_session';
|
|
307
|
+
data: {
|
|
308
|
+
roomId: string;
|
|
309
|
+
code: string;
|
|
310
|
+
gameId: string;
|
|
311
|
+
selfId: string;
|
|
312
|
+
hostUserId: string;
|
|
313
|
+
peers: RealtimePeer[];
|
|
314
|
+
iceServers: RTCIceServer[];
|
|
315
|
+
};
|
|
316
|
+
};
|
|
317
|
+
type MultiplayerPeersEvent = {
|
|
318
|
+
type: 'multiplayer_peers';
|
|
319
|
+
data: {
|
|
320
|
+
peers: RealtimePeer[];
|
|
321
|
+
};
|
|
322
|
+
};
|
|
323
|
+
type MultiplayerSignalsEvent = {
|
|
324
|
+
type: 'multiplayer_signals';
|
|
325
|
+
data: {
|
|
326
|
+
signals: Array<{
|
|
327
|
+
fromUserId: string;
|
|
328
|
+
kind: string;
|
|
329
|
+
payload: string;
|
|
330
|
+
}>;
|
|
331
|
+
};
|
|
332
|
+
};
|
|
333
|
+
type MultiplayerIceServersEvent = {
|
|
334
|
+
type: 'multiplayer_ice_servers';
|
|
335
|
+
data: {
|
|
336
|
+
iceServers: RTCIceServer[];
|
|
337
|
+
};
|
|
338
|
+
};
|
|
339
|
+
type MultiplayerSessionEndedEvent = {
|
|
340
|
+
type: 'multiplayer_session_ended';
|
|
341
|
+
data: {
|
|
342
|
+
reason: RealtimeEndReason;
|
|
343
|
+
};
|
|
344
|
+
};
|
|
345
|
+
type MultiplayerErrorEvent = {
|
|
346
|
+
type: 'multiplayer_error';
|
|
347
|
+
data: {
|
|
348
|
+
code: RealtimeErrorCode;
|
|
349
|
+
message: string;
|
|
350
|
+
};
|
|
351
|
+
};
|
|
352
|
+
type GameEvent = PlayAgainEvent | SinglePlayerGameOverEvent | ReadyEvent | HapticFeedbackEvent | ToggleMuteEvent | GameErrorEvent | SaveGameStateEvent | RefuteGameStateEvent | GameInfoEvent | GameStateUpdatedEvent | MultiplayerGameOverEvent | MultiplayerSaveGameStateEvent | PurchaseEvent | PurchaseCompleteEvent | MultiplayerCreateRoomEvent | MultiplayerJoinRoomEvent | MultiplayerLeaveRoomEvent | MultiplayerSignalEvent | MultiplayerRefreshIceEvent | MultiplayerRequestInviteEvent | MultiplayerSessionEvent | MultiplayerPeersEvent | MultiplayerSignalsEvent | MultiplayerIceServersEvent | MultiplayerSessionEndedEvent | MultiplayerErrorEvent;
|
|
179
353
|
type GameEventMessage<T extends GameEvent['type']> = {
|
|
180
354
|
type: 'game_event';
|
|
181
355
|
event: Extract<GameEvent, {
|
|
@@ -185,8 +359,8 @@ type GameEventMessage<T extends GameEvent['type']> = {
|
|
|
185
359
|
/**
|
|
186
360
|
* Messages from the game host to the game client
|
|
187
361
|
*/
|
|
188
|
-
type IncomingGameEvent = GameEventMessage<'play_again' | 'toggle_mute' | 'game_info' | 'game_state_updated' | 'purchase_complete'>;
|
|
189
|
-
type OutgoingGameEvent = GameEventMessage<'game_over' | 'ready' | 'haptic_feedback' | 'error' | 'save_game_state' | 'refute_game_state' | 'multiplayer_game_over' | 'multiplayer_save_game_state' | 'purchase'>;
|
|
362
|
+
type IncomingGameEvent = GameEventMessage<'play_again' | 'toggle_mute' | 'game_info' | 'game_state_updated' | 'purchase_complete' | 'multiplayer_session' | 'multiplayer_peers' | 'multiplayer_signals' | 'multiplayer_ice_servers' | 'multiplayer_session_ended' | 'multiplayer_error'>;
|
|
363
|
+
type OutgoingGameEvent = GameEventMessage<'game_over' | 'ready' | 'haptic_feedback' | 'error' | 'save_game_state' | 'refute_game_state' | 'multiplayer_game_over' | 'multiplayer_save_game_state' | 'purchase' | 'multiplayer_create_room' | 'multiplayer_join_room' | 'multiplayer_leave_room' | 'multiplayer_signal' | 'multiplayer_refresh_ice' | 'multiplayer_request_invite'>;
|
|
190
364
|
type EventCallback = (data: unknown) => void;
|
|
191
365
|
declare class RemixSDK {
|
|
192
366
|
/**
|
|
@@ -266,6 +440,15 @@ declare class RemixSDK {
|
|
|
266
440
|
purchase: (data: PurchaseEvent["data"]) => Promise<PurchaseCompleteEvent["data"]>;
|
|
267
441
|
};
|
|
268
442
|
};
|
|
443
|
+
/**
|
|
444
|
+
* Realtime multiplayer rooms (Remix Desktop): create or join a room, then
|
|
445
|
+
* talk to peers over `room.send` / `room.onMessage`. Distinct from
|
|
446
|
+
* `sdk.multiplayer`, which is the platform-arbitrated turn-based flow.
|
|
447
|
+
* The transport underneath is the platform's business; games see rooms,
|
|
448
|
+
* peers, and messages, and nothing else.
|
|
449
|
+
*/
|
|
450
|
+
private realtimeController;
|
|
451
|
+
realtime: RealtimeNamespace;
|
|
269
452
|
private emit;
|
|
270
453
|
private handleMessage;
|
|
271
454
|
private sendMessage;
|
|
@@ -275,4 +458,4 @@ declare class RemixSDK {
|
|
|
275
458
|
}
|
|
276
459
|
declare const sdk: RemixSDK;
|
|
277
460
|
|
|
278
|
-
export { type GameErrorEvent, type GameEvent, type GameEventMessage, type GameInfo, type GameInfoEvent, type GameState, type GameStateUpdatedEvent, type HapticFeedbackEvent, type HapticFeedbackType, type IncomingGameEvent, type InventoryItem, type LevelAttempt, type LevelAttemptStars, type LevelProgressState, type LevelStars, type MultiplayerGameOverEvent, type MultiplayerSaveGameStateEvent, type OutgoingGameEvent, type PlayAgainEvent, type Player, type PurchaseCompleteEvent, type PurchaseEvent, type ReadyEvent, type RefuteGameStateEvent, RemixSDK, type SafeAreaInset, type SaveGameStateEvent, type ShopItem, type SinglePlayerGameOverEvent, type ToggleMuteEvent, type ViewContext, ZERO_SAFE_AREA_INSET, sdk };
|
|
461
|
+
export { type GameErrorEvent, type GameEvent, type GameEventMessage, type GameInfo, type GameInfoEvent, type GameState, type GameStateUpdatedEvent, type HapticFeedbackEvent, type HapticFeedbackType, type IncomingGameEvent, type InventoryItem, type LevelAttempt, type LevelAttemptStars, type LevelProgressState, type LevelStars, type MultiplayerCreateRoomEvent, type MultiplayerErrorEvent, type MultiplayerGameOverEvent, type MultiplayerIceServersEvent, type MultiplayerJoinRoomEvent, type MultiplayerLeaveRoomEvent, type MultiplayerPeersEvent, type MultiplayerRefreshIceEvent, type MultiplayerRequestInviteEvent, type MultiplayerSaveGameStateEvent, type MultiplayerSessionEndedEvent, type MultiplayerSessionEvent, type MultiplayerSignalEvent, type MultiplayerSignalsEvent, type OutgoingGameEvent, type PlayAgainEvent, type Player, type PurchaseCompleteEvent, type PurchaseEvent, type ReadyEvent, type RealtimeEndReason, type RealtimeErrorCode, type RealtimeNamespace, type RealtimePeer, type RealtimeRoom, RealtimeRoomError, type RealtimeSendOptions, type RealtimeSignalKind, type RefuteGameStateEvent, RemixSDK, type SafeAreaInset, type SaveGameStateEvent, type ShopItem, type SinglePlayerGameOverEvent, type ToggleMuteEvent, type ViewContext, ZERO_SAFE_AREA_INSET, sdk };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `sdk.realtime` — realtime multiplayer rooms for Remix Desktop games.
|
|
3
|
+
*
|
|
4
|
+
* The game sees rooms, peers, and messages; everything else is deliberately
|
|
5
|
+
* invisible. The platform's room broker (Remix Desktop main) owns identity,
|
|
6
|
+
* room admission, signaling, and ICE minting; this controller rides the
|
|
7
|
+
* `multiplayer_*` game events both ways and drives the data-channel mesh
|
|
8
|
+
* (`./mesh.ts`) under the surface. A game never touches `RTCPeerConnection`,
|
|
9
|
+
* SDP, or ICE — which is what lets the transport change under a published
|
|
10
|
+
* game without the game updating.
|
|
11
|
+
*
|
|
12
|
+
* Membership truth is the SERVER ROSTER the broker relays
|
|
13
|
+
* (`multiplayer_peers`), never the mesh: a rebuilt slot re-fires its
|
|
14
|
+
* transport callbacks and a repeated bye can announce the same departure
|
|
15
|
+
* twice, so peer join/leave here is a roster diff and nothing else. The
|
|
16
|
+
* mesh's own callbacks are diagnostics.
|
|
17
|
+
*/
|
|
18
|
+
type RealtimePeer = {
|
|
19
|
+
userId: string;
|
|
20
|
+
username: string;
|
|
21
|
+
pfp: string | null;
|
|
22
|
+
/** ISO seat stamp; seat order (oldest first) is the deterministic tiebreak. */
|
|
23
|
+
joinedAt: string | null;
|
|
24
|
+
};
|
|
25
|
+
type RealtimeEndReason = 'left' | 'expired' | 'offline' | 'closed';
|
|
26
|
+
type RealtimeErrorCode = 'room_not_found' | 'room_full' | 'game_mismatch' | 'no_game_id' | 'join_failed';
|
|
27
|
+
declare class RealtimeRoomError extends Error {
|
|
28
|
+
readonly code: RealtimeErrorCode;
|
|
29
|
+
constructor(code: RealtimeErrorCode, message: string);
|
|
30
|
+
}
|
|
31
|
+
type RealtimeSendOptions = {
|
|
32
|
+
/**
|
|
33
|
+
* Default true: ordered, retransmitted — lobby, countdowns, results.
|
|
34
|
+
* `reliable: false` is the per-frame state stream (unordered, never
|
|
35
|
+
* retransmitted): a packet that arrives late is worth less than nothing,
|
|
36
|
+
* and one that never arrives is replaced by the next frame anyway.
|
|
37
|
+
*/
|
|
38
|
+
reliable?: boolean;
|
|
39
|
+
};
|
|
40
|
+
interface RealtimeRoom {
|
|
41
|
+
readonly roomId: string;
|
|
42
|
+
/** The join code — what the host shares with friends. */
|
|
43
|
+
readonly code: string;
|
|
44
|
+
readonly selfId: string;
|
|
45
|
+
readonly hostUserId: string;
|
|
46
|
+
/** Whether this player created the room. */
|
|
47
|
+
readonly isHost: boolean;
|
|
48
|
+
/** The live roster, self excluded, in seat order. */
|
|
49
|
+
readonly peers: RealtimePeer[];
|
|
50
|
+
readonly ended: boolean;
|
|
51
|
+
/** Broadcast to every peer. Data must be JSON-serializable. */
|
|
52
|
+
send(data: unknown, options?: RealtimeSendOptions): void;
|
|
53
|
+
sendTo(userId: string, data: unknown, options?: RealtimeSendOptions): void;
|
|
54
|
+
onMessage(callback: (fromUserId: string, data: unknown) => void): () => void;
|
|
55
|
+
onPeerJoin(callback: (peer: RealtimePeer) => void): () => void;
|
|
56
|
+
onPeerLeave(callback: (peer: RealtimePeer) => void): () => void;
|
|
57
|
+
onEnded(callback: (reason: RealtimeEndReason) => void): () => void;
|
|
58
|
+
/** Transport trouble worth telling the player about; the room keeps trying. */
|
|
59
|
+
onError(callback: (message: string) => void): () => void;
|
|
60
|
+
/**
|
|
61
|
+
* Open the platform's invite share flow — the friend picker that sends the
|
|
62
|
+
* room's join code into DMs and groups. The game never sees the friend
|
|
63
|
+
* list; the platform owns the whole exchange. A game may also just show
|
|
64
|
+
* `room.code` for players to share by hand.
|
|
65
|
+
*/
|
|
66
|
+
invite(): void;
|
|
67
|
+
leave(): void;
|
|
68
|
+
}
|
|
69
|
+
interface RealtimeNamespace {
|
|
70
|
+
/** Create a room for this game and take the first seat. One live room at a time. */
|
|
71
|
+
createRoom(): Promise<RealtimeRoom>;
|
|
72
|
+
/** Join a friend's room by its invite code. */
|
|
73
|
+
joinRoom(code: string): Promise<RealtimeRoom>;
|
|
74
|
+
/** The live room, or null. */
|
|
75
|
+
readonly room: RealtimeRoom | null;
|
|
76
|
+
/**
|
|
77
|
+
* Every room that becomes live — including one the PLATFORM joined for the
|
|
78
|
+
* player (accepting an invite boots the game already seated). A lobby
|
|
79
|
+
* screen should mount from here, not only from its own create/join call.
|
|
80
|
+
*/
|
|
81
|
+
onRoom(callback: (room: RealtimeRoom) => void): () => void;
|
|
82
|
+
/**
|
|
83
|
+
* A room the platform tried to join for the player (an accepted invite)
|
|
84
|
+
* that failed — full, expired, or the wrong game. There is no pending
|
|
85
|
+
* `createRoom`/`joinRoom` call to reject, so this is where the failure
|
|
86
|
+
* surfaces; a lobby should tell the player rather than sit solo as if
|
|
87
|
+
* nothing happened. Requested joins keep rejecting their own promise.
|
|
88
|
+
*/
|
|
89
|
+
onRoomError(callback: (error: RealtimeRoomError) => void): () => void;
|
|
90
|
+
}
|
|
91
|
+
|
|
1
92
|
declare global {
|
|
2
93
|
interface Window {
|
|
3
94
|
FarcadeSDK: typeof sdk;
|
|
4
95
|
RemixSDK: typeof sdk;
|
|
5
96
|
}
|
|
6
97
|
}
|
|
98
|
+
|
|
7
99
|
type ViewContext = 'feed' | 'full_screen' | 'challenge' | 'tournament';
|
|
8
100
|
type SafeAreaInset = {
|
|
9
101
|
top: number;
|
|
@@ -175,7 +267,89 @@ type PurchaseCompleteEvent = {
|
|
|
175
267
|
item?: string;
|
|
176
268
|
};
|
|
177
269
|
};
|
|
178
|
-
type
|
|
270
|
+
type RealtimeSignalKind = 'offer' | 'answer' | 'ice' | 'bye';
|
|
271
|
+
type MultiplayerCreateRoomEvent = {
|
|
272
|
+
type: 'multiplayer_create_room';
|
|
273
|
+
data: undefined;
|
|
274
|
+
};
|
|
275
|
+
type MultiplayerJoinRoomEvent = {
|
|
276
|
+
type: 'multiplayer_join_room';
|
|
277
|
+
data: {
|
|
278
|
+
code: string;
|
|
279
|
+
};
|
|
280
|
+
};
|
|
281
|
+
type MultiplayerLeaveRoomEvent = {
|
|
282
|
+
type: 'multiplayer_leave_room';
|
|
283
|
+
data: undefined;
|
|
284
|
+
};
|
|
285
|
+
type MultiplayerSignalEvent = {
|
|
286
|
+
type: 'multiplayer_signal';
|
|
287
|
+
data: {
|
|
288
|
+
toUserId: string;
|
|
289
|
+
kind: RealtimeSignalKind;
|
|
290
|
+
payload: string;
|
|
291
|
+
};
|
|
292
|
+
};
|
|
293
|
+
type MultiplayerRefreshIceEvent = {
|
|
294
|
+
type: 'multiplayer_refresh_ice';
|
|
295
|
+
data: undefined;
|
|
296
|
+
};
|
|
297
|
+
/**
|
|
298
|
+
* Open the platform's invite share flow for the live room. Carries nothing:
|
|
299
|
+
* the platform already knows the room's game and code.
|
|
300
|
+
*/
|
|
301
|
+
type MultiplayerRequestInviteEvent = {
|
|
302
|
+
type: 'multiplayer_request_invite';
|
|
303
|
+
data: undefined;
|
|
304
|
+
};
|
|
305
|
+
type MultiplayerSessionEvent = {
|
|
306
|
+
type: 'multiplayer_session';
|
|
307
|
+
data: {
|
|
308
|
+
roomId: string;
|
|
309
|
+
code: string;
|
|
310
|
+
gameId: string;
|
|
311
|
+
selfId: string;
|
|
312
|
+
hostUserId: string;
|
|
313
|
+
peers: RealtimePeer[];
|
|
314
|
+
iceServers: RTCIceServer[];
|
|
315
|
+
};
|
|
316
|
+
};
|
|
317
|
+
type MultiplayerPeersEvent = {
|
|
318
|
+
type: 'multiplayer_peers';
|
|
319
|
+
data: {
|
|
320
|
+
peers: RealtimePeer[];
|
|
321
|
+
};
|
|
322
|
+
};
|
|
323
|
+
type MultiplayerSignalsEvent = {
|
|
324
|
+
type: 'multiplayer_signals';
|
|
325
|
+
data: {
|
|
326
|
+
signals: Array<{
|
|
327
|
+
fromUserId: string;
|
|
328
|
+
kind: string;
|
|
329
|
+
payload: string;
|
|
330
|
+
}>;
|
|
331
|
+
};
|
|
332
|
+
};
|
|
333
|
+
type MultiplayerIceServersEvent = {
|
|
334
|
+
type: 'multiplayer_ice_servers';
|
|
335
|
+
data: {
|
|
336
|
+
iceServers: RTCIceServer[];
|
|
337
|
+
};
|
|
338
|
+
};
|
|
339
|
+
type MultiplayerSessionEndedEvent = {
|
|
340
|
+
type: 'multiplayer_session_ended';
|
|
341
|
+
data: {
|
|
342
|
+
reason: RealtimeEndReason;
|
|
343
|
+
};
|
|
344
|
+
};
|
|
345
|
+
type MultiplayerErrorEvent = {
|
|
346
|
+
type: 'multiplayer_error';
|
|
347
|
+
data: {
|
|
348
|
+
code: RealtimeErrorCode;
|
|
349
|
+
message: string;
|
|
350
|
+
};
|
|
351
|
+
};
|
|
352
|
+
type GameEvent = PlayAgainEvent | SinglePlayerGameOverEvent | ReadyEvent | HapticFeedbackEvent | ToggleMuteEvent | GameErrorEvent | SaveGameStateEvent | RefuteGameStateEvent | GameInfoEvent | GameStateUpdatedEvent | MultiplayerGameOverEvent | MultiplayerSaveGameStateEvent | PurchaseEvent | PurchaseCompleteEvent | MultiplayerCreateRoomEvent | MultiplayerJoinRoomEvent | MultiplayerLeaveRoomEvent | MultiplayerSignalEvent | MultiplayerRefreshIceEvent | MultiplayerRequestInviteEvent | MultiplayerSessionEvent | MultiplayerPeersEvent | MultiplayerSignalsEvent | MultiplayerIceServersEvent | MultiplayerSessionEndedEvent | MultiplayerErrorEvent;
|
|
179
353
|
type GameEventMessage<T extends GameEvent['type']> = {
|
|
180
354
|
type: 'game_event';
|
|
181
355
|
event: Extract<GameEvent, {
|
|
@@ -185,8 +359,8 @@ type GameEventMessage<T extends GameEvent['type']> = {
|
|
|
185
359
|
/**
|
|
186
360
|
* Messages from the game host to the game client
|
|
187
361
|
*/
|
|
188
|
-
type IncomingGameEvent = GameEventMessage<'play_again' | 'toggle_mute' | 'game_info' | 'game_state_updated' | 'purchase_complete'>;
|
|
189
|
-
type OutgoingGameEvent = GameEventMessage<'game_over' | 'ready' | 'haptic_feedback' | 'error' | 'save_game_state' | 'refute_game_state' | 'multiplayer_game_over' | 'multiplayer_save_game_state' | 'purchase'>;
|
|
362
|
+
type IncomingGameEvent = GameEventMessage<'play_again' | 'toggle_mute' | 'game_info' | 'game_state_updated' | 'purchase_complete' | 'multiplayer_session' | 'multiplayer_peers' | 'multiplayer_signals' | 'multiplayer_ice_servers' | 'multiplayer_session_ended' | 'multiplayer_error'>;
|
|
363
|
+
type OutgoingGameEvent = GameEventMessage<'game_over' | 'ready' | 'haptic_feedback' | 'error' | 'save_game_state' | 'refute_game_state' | 'multiplayer_game_over' | 'multiplayer_save_game_state' | 'purchase' | 'multiplayer_create_room' | 'multiplayer_join_room' | 'multiplayer_leave_room' | 'multiplayer_signal' | 'multiplayer_refresh_ice' | 'multiplayer_request_invite'>;
|
|
190
364
|
type EventCallback = (data: unknown) => void;
|
|
191
365
|
declare class RemixSDK {
|
|
192
366
|
/**
|
|
@@ -266,6 +440,15 @@ declare class RemixSDK {
|
|
|
266
440
|
purchase: (data: PurchaseEvent["data"]) => Promise<PurchaseCompleteEvent["data"]>;
|
|
267
441
|
};
|
|
268
442
|
};
|
|
443
|
+
/**
|
|
444
|
+
* Realtime multiplayer rooms (Remix Desktop): create or join a room, then
|
|
445
|
+
* talk to peers over `room.send` / `room.onMessage`. Distinct from
|
|
446
|
+
* `sdk.multiplayer`, which is the platform-arbitrated turn-based flow.
|
|
447
|
+
* The transport underneath is the platform's business; games see rooms,
|
|
448
|
+
* peers, and messages, and nothing else.
|
|
449
|
+
*/
|
|
450
|
+
private realtimeController;
|
|
451
|
+
realtime: RealtimeNamespace;
|
|
269
452
|
private emit;
|
|
270
453
|
private handleMessage;
|
|
271
454
|
private sendMessage;
|
|
@@ -275,4 +458,4 @@ declare class RemixSDK {
|
|
|
275
458
|
}
|
|
276
459
|
declare const sdk: RemixSDK;
|
|
277
460
|
|
|
278
|
-
export { type GameErrorEvent, type GameEvent, type GameEventMessage, type GameInfo, type GameInfoEvent, type GameState, type GameStateUpdatedEvent, type HapticFeedbackEvent, type HapticFeedbackType, type IncomingGameEvent, type InventoryItem, type LevelAttempt, type LevelAttemptStars, type LevelProgressState, type LevelStars, type MultiplayerGameOverEvent, type MultiplayerSaveGameStateEvent, type OutgoingGameEvent, type PlayAgainEvent, type Player, type PurchaseCompleteEvent, type PurchaseEvent, type ReadyEvent, type RefuteGameStateEvent, RemixSDK, type SafeAreaInset, type SaveGameStateEvent, type ShopItem, type SinglePlayerGameOverEvent, type ToggleMuteEvent, type ViewContext, ZERO_SAFE_AREA_INSET, sdk };
|
|
461
|
+
export { type GameErrorEvent, type GameEvent, type GameEventMessage, type GameInfo, type GameInfoEvent, type GameState, type GameStateUpdatedEvent, type HapticFeedbackEvent, type HapticFeedbackType, type IncomingGameEvent, type InventoryItem, type LevelAttempt, type LevelAttemptStars, type LevelProgressState, type LevelStars, type MultiplayerCreateRoomEvent, type MultiplayerErrorEvent, type MultiplayerGameOverEvent, type MultiplayerIceServersEvent, type MultiplayerJoinRoomEvent, type MultiplayerLeaveRoomEvent, type MultiplayerPeersEvent, type MultiplayerRefreshIceEvent, type MultiplayerRequestInviteEvent, type MultiplayerSaveGameStateEvent, type MultiplayerSessionEndedEvent, type MultiplayerSessionEvent, type MultiplayerSignalEvent, type MultiplayerSignalsEvent, type OutgoingGameEvent, type PlayAgainEvent, type Player, type PurchaseCompleteEvent, type PurchaseEvent, type ReadyEvent, type RealtimeEndReason, type RealtimeErrorCode, type RealtimeNamespace, type RealtimePeer, type RealtimeRoom, RealtimeRoomError, type RealtimeSendOptions, type RealtimeSignalKind, type RefuteGameStateEvent, RemixSDK, type SafeAreaInset, type SaveGameStateEvent, type ShopItem, type SinglePlayerGameOverEvent, type ToggleMuteEvent, type ViewContext, ZERO_SAFE_AREA_INSET, sdk };
|