@series-inc/rundot-game-sdk 5.7.0-beta.8 → 5.7.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.
@@ -946,9 +946,11 @@ declare class RundotGameTransport implements RpcTransport {
946
946
  }
947
947
 
948
948
  /** Constraint for user-defined message unions shared between client and server. */
949
- type Protocol = {
949
+ type BaseMessage = {
950
950
  type: string;
951
951
  };
952
+ /** Constraint for user-defined state objects shared between client and server. */
953
+ type BaseState = Record<string, unknown>;
952
954
 
953
955
  /**
954
956
  * Server-authoritative room types used by the client multiplayer layer.
@@ -961,11 +963,13 @@ interface ServerPlayer {
961
963
  avatarUrl?: string | null;
962
964
  }
963
965
  /** Public interface for a server-authoritative room. */
964
- interface ServerRoom<P extends Protocol> {
966
+ interface ServerRoom<M extends BaseMessage, S extends BaseState> {
965
967
  /** The shareable room code (e.g. "HX9KWR") */
966
968
  readonly roomCode: string;
967
969
  /** The current player's ID */
968
970
  readonly playerId: string;
971
+ /** Current room state (synced from the server) */
972
+ readonly state: S;
969
973
  /** Whether the room is locked */
970
974
  readonly locked: boolean;
971
975
  /** Current latency in ms (round-trip / 2) */
@@ -973,19 +977,21 @@ interface ServerRoom<P extends Protocol> {
973
977
  /** Connection state */
974
978
  readonly connectionState: ConnectionState;
975
979
  /** Register event handlers. */
976
- on(events: RoomEvents<P>): void;
980
+ on(events: RoomEvents<M, S>): void;
977
981
  /** Send a typed message to the server room. */
978
- send(message: P): void;
982
+ send(message: M): void;
979
983
  /** Leave the room and close the connection. */
980
984
  leave(): void;
981
985
  /** Get estimated server time (local time + offset). */
982
986
  getServerTime(): number;
983
987
  }
984
- interface RoomEvents<P extends Protocol> {
988
+ interface RoomEvents<M extends BaseMessage, S extends BaseState> {
989
+ /** Called when the synced state changes */
990
+ onStateChange?: (state: S) => void;
985
991
  /** Called when a broadcast message is received from the server */
986
- onMessage?: (message: P) => void;
992
+ onMessage?: (message: M) => void;
987
993
  /** Called when a targeted message is received */
988
- onPrivateMessage?: (message: P) => void;
994
+ onPrivateMessage?: (message: M) => void;
989
995
  /** Called when a player joins the room */
990
996
  onPlayerJoined?: (player: ServerPlayer) => void;
991
997
  /** Called when a player leaves the room */
@@ -1013,15 +1019,15 @@ interface MultiplayerApi {
1013
1019
  /**
1014
1020
  * Create a new room of the given type.
1015
1021
  */
1016
- createRoom<P extends Protocol>(roomType: string): Promise<ServerRoom<P>>;
1022
+ createRoom<M extends BaseMessage, S extends BaseState>(roomType: string): Promise<ServerRoom<M, S>>;
1017
1023
  /**
1018
1024
  * Join a room by its 6-char code.
1019
1025
  */
1020
- joinRoomByCode<P extends Protocol>(code: string): Promise<ServerRoom<P>>;
1026
+ joinRoomByCode<M extends BaseMessage, S extends BaseState>(code: string): Promise<ServerRoom<M, S>>;
1021
1027
  /**
1022
1028
  * Join an existing room or create a new one (matchmaking by room type).
1023
1029
  */
1024
- joinOrCreateRoom<P extends Protocol>(roomType: string): Promise<ServerRoom<P>>;
1030
+ joinOrCreateRoom<M extends BaseMessage, S extends BaseState>(roomType: string): Promise<ServerRoom<M, S>>;
1025
1031
  }
1026
1032
 
1027
1033
  interface LoggingApi {
@@ -2269,4 +2275,4 @@ interface AdsApi {
2269
2275
  showInterstitialAd(options?: ShowInterstitialAdOptions): Promise<boolean>;
2270
2276
  }
2271
2277
 
2272
- export { type AiChatCompletionRequest as $, type AnalyticsApi as A, type BatchRecipeRequirementsResult as B, type ScheduleLocalNotification as C, type ScheduleNotificationOptions as D, type PopupsApi as E, type ShowToastOptions as F, type ShowInterstitialAdOptions as G, type Host as H, type ShowRewardedAdOptions as I, type ProfileApi as J, type DeviceApi as K, type DeviceInfo as L, type EnvironmentApi as M, type NavigationApi as N, type EnvironmentInfo as O, type Profile as P, type QuitOptions as Q, type RundotGameAPI as R, type SimulationRunSummary as S, type SystemApi as T, type SafeArea as U, type CdnApi as V, type FetchFromCdnOptions as W, type TimeApi as X, type ServerTimeData as Y, type GetFutureTimeOptions as Z, type AiApi as _, type RecipeRequirementResult as a, type LeaderboardApi as a$, type AiChatCompletionData as a0, type HapticsApi as a1, HapticFeedbackStyle as a2, type FeaturesApi as a3, type Experiment as a4, type LifecycleApi as a5, type SleepCallback as a6, type Subscription as a7, type AwakeCallback as a8, type PauseCallback as a9, type RoomMessageEvent as aA, type ProposedMoveEvent as aB, RundotGameTransport as aC, type RoomsApi as aD, type CreateRoomOptions as aE, type JoinOrCreateRoomOptions as aF, type JoinOrCreateResult as aG, type ListRoomsOptions as aH, type UpdateRoomDataOptions as aI, type RoomMessageRequest as aJ, type StartRoomGameOptions as aK, type ProposeMoveRequest as aL, type ProposeMoveResult as aM, type ValidateMoveVerdict as aN, type ValidateMoveResult as aO, type RoomSubscriptionOptions as aP, type LoggingApi as aQ, type IapApi as aR, type SpendCurrencyOptions as aS, type SpendCurrencyResult as aT, type SubscriptionTier as aU, type RunSubscriptionsResponse as aV, type SubscriptionInterval as aW, type PurchaseSubscriptionResponse as aX, type OpenStoreResult as aY, type LoadEmbeddedAssetsResponse as aZ, type SharedAssetsApi as a_, type ResumeCallback as aa, type QuitCallback as ab, type SimulationApi as ac, type SimulationSlotValidationResult as ad, type SimulationBatchOperation as ae, type SimulationBatchOperationsResult as af, type SimulationAvailableItem as ag, type SimulationPowerPreview as ah, type SimulationSlotMutationResult as ai, type SimulationSlotContainer as aj, type SimulationAssignment as ak, type SimulationState as al, type ExecuteRecipeOptions as am, type ExecuteRecipeResponse as an, type CollectRecipeResult as ao, type ResetStateOptions as ap, type ResetStateResult as aq, type GetActiveRunsOptions as ar, type ExecuteScopedRecipeOptions as as, type ExecuteScopedRecipeResult as at, type GetAvailableRecipesOptions as au, type GetAvailableRecipesResult as av, type Recipe as aw, type GetBatchRecipeRequirements as ax, type TriggerRecipeChainOptions as ay, type RoomDataUpdate as az, type RundotGameSimulationStateResponse as b, type RoomMessagePayload as b$, type ScoreToken as b0, type SubmitScoreParams as b1, type SubmitScoreResult as b2, type GetPagedScoresOptions as b3, type PagedScoresResponse as b4, type PlayerRankOptions as b5, type PlayerRankResult as b6, type GetPodiumScoresOptions as b7, type PodiumScoresResponse as b8, type PreloaderApi as b9, type ImageGenResult as bA, type MultiplayerApi as bB, type InitializationContext as bC, type InitializationOptions as bD, type ServerRoom as bE, type ServerPlayer as bF, type RoomEvents as bG, type ConnectionState as bH, type Protocol as bI, type AiMessage as bJ, type Asset as bK, type Category as bL, MockAvatarApi as bM, type SubPath as bN, type IsPlayerSubscribedRequest as bO, type RunSubscription as bP, type PurchaseSubscriptionRequest as bQ, type GetSubscriptionsForTierRequest as bR, type TimeIntervalTriggerInput as bS, type NotificationTriggerInput as bT, type OnRequestCallback as bU, type OnResponseCallback as bV, type OnNotificationCallback as bW, type RpcTransport as bX, type ImageGenModel as bY, type JoinRoomMatchCriteria as bZ, type RoomMessageEventType as b_, type SocialApi as ba, type ShareMetadata as bb, type ShareLinkResult as bc, type SocialQRCodeOptions as bd, type QRCodeResult as be, type ShareClickData as bf, type EntitlementApi as bg, type Entitlement as bh, type LedgerEntry as bi, type ShopApi as bj, type StorefrontResponse as bk, type StorefrontItem as bl, type ShopPurchaseResponse as bm, type ShopOrderHistoryResponse as bn, type PromptLoginResult as bo, type AccessTier as bp, type AccessGateApi as bq, type ImageGenApi as br, type UgcApi as bs, type Avatar3dApi as bt, type AssetManifest as bu, type Avatar3dConfig as bv, type ShowEditorOptions as bw, type Avatar3dEdits as bx, type AdsApi as by, type ImageGenParams as bz, type SimulationUpdateType as c, type ProposedMovePayload as c0, ROOM_GAME_PHASES as c1, type RoomGamePhase as c2, type RundotGameRoomRulesGameState as c3, type RundotGameRoomRules as c4, type RundotGameRoomCustomMetadata as c5, type RundotGameRoomPayload as c6, type RoomEnvelopeResponse as c7, type RoomsEnvelopeResponse as c8, type JoinOrCreateRoomEnvelopeResponse as c9, type RecipeInfo as ca, type SimulationPersonalState as cb, type SimulationRoomActiveRecipe as cc, type SimulationRoomState as cd, type SimulationBatchOperationAssign as ce, type SimulationBatchOperationRemove as cf, type SimulationBatchOperationResult as cg, RpcSharedAssetsApi as ch, type LoadEmbeddedAssetsRequest as ci, type LeaderboardModeConfig as cj, type LeaderboardPeriodType as ck, type LeaderboardPeriodConfig as cl, type LeaderboardAntiCheatConfig as cm, type LeaderboardDisplaySettings as cn, type LeaderboardConfig as co, type LeaderboardEntry as cp, type PodiumScoresContext as cq, type ShopOrder as cr, type HudInsets as cs, createHost as ct, AccessDeniedError as cu, type SimulationEntityUpdate as d, type SimulationActiveRunsUpdate as e, type SimulationSnapshotUpdate as f, type SimulationUpdateData as g, type SimulationSubscribeOptions as h, type RundotGameSimulationEffect as i, type RundotGameSimulationRecipe as j, type RundotGameSimulationConfig as k, type RecipeRequirementQuery as l, type RundotGameExecuteRecipeOptions as m, type RundotGameExecuteScopedRecipeOptions as n, type RundotGameAvailableRecipe as o, type RundotGameCollectRecipeResult as p, type RundotGameExecuteRecipeResult as q, RundotGameRoom as r, type RpcRequest as s, type RpcResponse as t, type RpcNotification as u, RpcClient as v, type StorageApi as w, type NavigationStackInfo as x, type PushAppOptions as y, type NotificationsApi as z };
2278
+ export { type AiChatCompletionRequest as $, type AnalyticsApi as A, type BatchRecipeRequirementsResult as B, type ScheduleLocalNotification as C, type ScheduleNotificationOptions as D, type PopupsApi as E, type ShowToastOptions as F, type ShowInterstitialAdOptions as G, type Host as H, type ShowRewardedAdOptions as I, type ProfileApi as J, type DeviceApi as K, type DeviceInfo as L, type EnvironmentApi as M, type NavigationApi as N, type EnvironmentInfo as O, type Profile as P, type QuitOptions as Q, type RundotGameAPI as R, type SimulationRunSummary as S, type SystemApi as T, type SafeArea as U, type CdnApi as V, type FetchFromCdnOptions as W, type TimeApi as X, type ServerTimeData as Y, type GetFutureTimeOptions as Z, type AiApi as _, type RecipeRequirementResult as a, type LeaderboardApi as a$, type AiChatCompletionData as a0, type HapticsApi as a1, HapticFeedbackStyle as a2, type FeaturesApi as a3, type Experiment as a4, type LifecycleApi as a5, type SleepCallback as a6, type Subscription as a7, type AwakeCallback as a8, type PauseCallback as a9, type RoomMessageEvent as aA, type ProposedMoveEvent as aB, RundotGameTransport as aC, type RoomsApi as aD, type CreateRoomOptions as aE, type JoinOrCreateRoomOptions as aF, type JoinOrCreateResult as aG, type ListRoomsOptions as aH, type UpdateRoomDataOptions as aI, type RoomMessageRequest as aJ, type StartRoomGameOptions as aK, type ProposeMoveRequest as aL, type ProposeMoveResult as aM, type ValidateMoveVerdict as aN, type ValidateMoveResult as aO, type RoomSubscriptionOptions as aP, type LoggingApi as aQ, type IapApi as aR, type SpendCurrencyOptions as aS, type SpendCurrencyResult as aT, type SubscriptionTier as aU, type RunSubscriptionsResponse as aV, type SubscriptionInterval as aW, type PurchaseSubscriptionResponse as aX, type OpenStoreResult as aY, type LoadEmbeddedAssetsResponse as aZ, type SharedAssetsApi as a_, type ResumeCallback as aa, type QuitCallback as ab, type SimulationApi as ac, type SimulationSlotValidationResult as ad, type SimulationBatchOperation as ae, type SimulationBatchOperationsResult as af, type SimulationAvailableItem as ag, type SimulationPowerPreview as ah, type SimulationSlotMutationResult as ai, type SimulationSlotContainer as aj, type SimulationAssignment as ak, type SimulationState as al, type ExecuteRecipeOptions as am, type ExecuteRecipeResponse as an, type CollectRecipeResult as ao, type ResetStateOptions as ap, type ResetStateResult as aq, type GetActiveRunsOptions as ar, type ExecuteScopedRecipeOptions as as, type ExecuteScopedRecipeResult as at, type GetAvailableRecipesOptions as au, type GetAvailableRecipesResult as av, type Recipe as aw, type GetBatchRecipeRequirements as ax, type TriggerRecipeChainOptions as ay, type RoomDataUpdate as az, type RundotGameSimulationStateResponse as b, type RoomMessageEventType as b$, type ScoreToken as b0, type SubmitScoreParams as b1, type SubmitScoreResult as b2, type GetPagedScoresOptions as b3, type PagedScoresResponse as b4, type PlayerRankOptions as b5, type PlayerRankResult as b6, type GetPodiumScoresOptions as b7, type PodiumScoresResponse as b8, type PreloaderApi as b9, type ImageGenResult as bA, type MultiplayerApi as bB, type InitializationContext as bC, type InitializationOptions as bD, type ServerRoom as bE, type ServerPlayer as bF, type RoomEvents as bG, type ConnectionState as bH, type BaseMessage as bI, type BaseState as bJ, type AiMessage as bK, type Asset as bL, type Category as bM, MockAvatarApi as bN, type SubPath as bO, type IsPlayerSubscribedRequest as bP, type RunSubscription as bQ, type PurchaseSubscriptionRequest as bR, type GetSubscriptionsForTierRequest as bS, type TimeIntervalTriggerInput as bT, type NotificationTriggerInput as bU, type OnRequestCallback as bV, type OnResponseCallback as bW, type OnNotificationCallback as bX, type RpcTransport as bY, type ImageGenModel as bZ, type JoinRoomMatchCriteria as b_, type SocialApi as ba, type ShareMetadata as bb, type ShareLinkResult as bc, type SocialQRCodeOptions as bd, type QRCodeResult as be, type ShareClickData as bf, type EntitlementApi as bg, type Entitlement as bh, type LedgerEntry as bi, type ShopApi as bj, type StorefrontResponse as bk, type StorefrontItem as bl, type ShopPurchaseResponse as bm, type ShopOrderHistoryResponse as bn, type PromptLoginResult as bo, type AccessTier as bp, type AccessGateApi as bq, type ImageGenApi as br, type UgcApi as bs, type Avatar3dApi as bt, type AssetManifest as bu, type Avatar3dConfig as bv, type ShowEditorOptions as bw, type Avatar3dEdits as bx, type AdsApi as by, type ImageGenParams as bz, type SimulationUpdateType as c, type RoomMessagePayload as c0, type ProposedMovePayload as c1, ROOM_GAME_PHASES as c2, type RoomGamePhase as c3, type RundotGameRoomRulesGameState as c4, type RundotGameRoomRules as c5, type RundotGameRoomCustomMetadata as c6, type RundotGameRoomPayload as c7, type RoomEnvelopeResponse as c8, type RoomsEnvelopeResponse as c9, type JoinOrCreateRoomEnvelopeResponse as ca, type RecipeInfo as cb, type SimulationPersonalState as cc, type SimulationRoomActiveRecipe as cd, type SimulationRoomState as ce, type SimulationBatchOperationAssign as cf, type SimulationBatchOperationRemove as cg, type SimulationBatchOperationResult as ch, RpcSharedAssetsApi as ci, type LoadEmbeddedAssetsRequest as cj, type LeaderboardModeConfig as ck, type LeaderboardPeriodType as cl, type LeaderboardPeriodConfig as cm, type LeaderboardAntiCheatConfig as cn, type LeaderboardDisplaySettings as co, type LeaderboardConfig as cp, type LeaderboardEntry as cq, type PodiumScoresContext as cr, type ShopOrder as cs, type HudInsets as ct, createHost as cu, AccessDeniedError as cv, type SimulationEntityUpdate as d, type SimulationActiveRunsUpdate as e, type SimulationSnapshotUpdate as f, type SimulationUpdateData as g, type SimulationSubscribeOptions as h, type RundotGameSimulationEffect as i, type RundotGameSimulationRecipe as j, type RundotGameSimulationConfig as k, type RecipeRequirementQuery as l, type RundotGameExecuteRecipeOptions as m, type RundotGameExecuteScopedRecipeOptions as n, type RundotGameAvailableRecipe as o, type RundotGameCollectRecipeResult as p, type RundotGameExecuteRecipeResult as q, RundotGameRoom as r, type RpcRequest as s, type RpcResponse as t, type RpcNotification as u, RpcClient as v, type StorageApi as w, type NavigationStackInfo as x, type PushAppOptions as y, type NotificationsApi as z };
@@ -4180,6 +4180,7 @@ var RundotServerRoom = class _RundotServerRoom {
4180
4180
  roomCode;
4181
4181
  playerId;
4182
4182
  ws;
4183
+ _state;
4183
4184
  _locked = false;
4184
4185
  _phase = "active";
4185
4186
  events = {};
@@ -4193,32 +4194,40 @@ var RundotServerRoom = class _RundotServerRoom {
4193
4194
  }
4194
4195
  warn(msg) {
4195
4196
  }
4196
- toMessage(msgType, data) {
4197
- return { ...data, type: msgType };
4198
- }
4199
4197
  /**
4200
4198
  * Attempt a phase transition. Returns true if the transition occurred.
4201
4199
  * Once `dead`, no further transitions are allowed.
4202
4200
  */
4201
+ toMessage(msgType, data) {
4202
+ return { ...data, type: msgType };
4203
+ }
4203
4204
  transitionTo(newPhase) {
4204
4205
  if (this._phase === "dead" || this._phase === newPhase) return false;
4205
4206
  this.log(`phase ${this._phase} \u2192 ${newPhase}`);
4206
4207
  this._phase = newPhase;
4207
4208
  return true;
4208
4209
  }
4209
- constructor(roomCode, playerId, ws) {
4210
+ constructor(roomCode, playerId, ws, initialState) {
4210
4211
  this.roomCode = roomCode;
4211
4212
  this.playerId = playerId;
4212
4213
  this.ws = ws;
4213
- this.log(`created roomCode=${roomCode} playerId=${playerId}`);
4214
+ this._state = initialState;
4215
+ this.log(`created roomCode=${roomCode} playerId=${playerId} stateKeys=${Object.keys(initialState)}`);
4214
4216
  ws.on({
4215
- onMessage: (msg) => this.onMessageReceived(msg),
4216
- onStateChange: (state) => this.onConnectionStateChanged(state),
4217
- onError: (err) => this.onError(err)
4217
+ onMessage: (msg) => this.handleMessage(msg),
4218
+ onStateChange: (state) => this.handleConnectionState(state),
4219
+ onError: (err) => {
4220
+ this.warn(`ws error: ${err.message}`);
4221
+ this.events.onError?.(err.message);
4222
+ }
4218
4223
  });
4219
4224
  this.startPing();
4220
4225
  }
4221
4226
  // ── Accessors ──
4227
+ /** Current room state (synced from the server) */
4228
+ get state() {
4229
+ return this._state;
4230
+ }
4222
4231
  /** Whether the room is locked */
4223
4232
  get locked() {
4224
4233
  return this._locked;
@@ -4243,7 +4252,7 @@ var RundotServerRoom = class _RundotServerRoom {
4243
4252
  * Send a typed message to the server room.
4244
4253
  */
4245
4254
  send(message) {
4246
- if (this._phase === "dead" || this._phase === "reconnecting") return;
4255
+ if (this._phase === "dead") return;
4247
4256
  const { type, ...data } = message;
4248
4257
  this.ws.send({ type: "message", msgType: type, data });
4249
4258
  }
@@ -4263,127 +4272,90 @@ var RundotServerRoom = class _RundotServerRoom {
4263
4272
  return Date.now() + this._serverTimeOffset;
4264
4273
  }
4265
4274
  // ── Message Handling ──
4266
- onMessageReceived(msg) {
4275
+ handleMessage(msg) {
4267
4276
  if (msg.type !== "pong") {
4268
4277
  this.log(`handleMessage type=${msg.type}`);
4269
4278
  }
4270
4279
  switch (msg.type) {
4280
+ case "room:sync":
4281
+ this._state = msg.state;
4282
+ this.log(`state synced, keys=${Object.keys(msg.state)}`);
4283
+ this.events.onStateChange?.(msg.state);
4284
+ break;
4271
4285
  case "room:broadcast":
4272
- this.onBroadcastMessageReceived(msg);
4286
+ this.log(`broadcast msgType=${msg.msgType}`);
4287
+ this.events.onMessage?.(this.toMessage(msg.msgType, msg.data));
4273
4288
  break;
4274
4289
  case "room:sendTo":
4275
- this.onSendToMessageReceived(msg);
4290
+ this.log(`sendTo msgType=${msg.msgType}`);
4291
+ this.events.onPrivateMessage?.(this.toMessage(msg.msgType, msg.data));
4276
4292
  break;
4277
4293
  case "room:lock":
4278
- this.onLockMessageReceived();
4294
+ this._locked = true;
4295
+ this.log(`room locked`);
4296
+ this.events.onLock?.();
4279
4297
  break;
4280
4298
  case "room:unlock":
4281
- this.onUnlockMessageReceived();
4299
+ this._locked = false;
4300
+ this.log(`room unlocked`);
4301
+ this.events.onUnlock?.();
4282
4302
  break;
4283
4303
  case "room:playerJoined":
4284
- this.onPlayerJoinedMessageReceived(msg);
4304
+ this.log(`playerJoined id=${msg.playerId}`);
4305
+ this.events.onPlayerJoined?.({
4306
+ id: msg.playerId,
4307
+ username: msg.username,
4308
+ avatarUrl: msg.avatarUrl
4309
+ });
4285
4310
  break;
4286
4311
  case "room:playerLeft":
4287
- this.onPlayerLeftMessageReceived(msg);
4312
+ this.log(`playerLeft id=${msg.playerId}`);
4313
+ this.events.onPlayerLeft?.(msg.playerId);
4288
4314
  break;
4289
4315
  case "room:error":
4290
- this.onErrorMessageReceived(msg);
4316
+ this.warn(`error: ${msg.message}`);
4317
+ this.events.onError?.(msg.message);
4291
4318
  break;
4292
4319
  case "room:reconnecting":
4293
- this.onReconnectingMessageReceived();
4320
+ if (this.transitionTo("reconnecting")) {
4321
+ this.events.onReconnecting?.();
4322
+ }
4294
4323
  break;
4295
4324
  case "room:reconnected":
4296
- this.onReconnectedMessageReceived(msg);
4325
+ this.ws.confirmConnection();
4326
+ if (this.transitionTo("active")) {
4327
+ this.events.onReconnected?.();
4328
+ }
4297
4329
  break;
4298
- case "pong":
4299
- this.onPongMessageReceived(msg);
4330
+ case "pong": {
4331
+ const now = Date.now();
4332
+ const rtt = now - msg.ts;
4333
+ this._latency = Math.round(rtt / 2);
4334
+ this._serverTimeOffset = msg.serverTs - now + this._latency;
4300
4335
  break;
4336
+ }
4301
4337
  }
4302
4338
  }
4303
- onBroadcastMessageReceived(msg) {
4304
- this.log(`broadcast msgType=${msg.msgType}`);
4305
- this.events.onMessage?.(this.toMessage(msg.msgType, msg.data));
4306
- }
4307
- onSendToMessageReceived(msg) {
4308
- this.log(`sendTo msgType=${msg.msgType}`);
4309
- this.events.onPrivateMessage?.(this.toMessage(msg.msgType, msg.data));
4310
- }
4311
- onLockMessageReceived() {
4312
- this._locked = true;
4313
- this.log(`room locked`);
4314
- this.events.onLock?.();
4315
- }
4316
- onUnlockMessageReceived() {
4317
- this._locked = false;
4318
- this.log(`room unlocked`);
4319
- this.events.onUnlock?.();
4320
- }
4321
- onPlayerJoinedMessageReceived(msg) {
4322
- this.log(`playerJoined id=${msg.playerId}`);
4323
- this.events.onPlayerJoined?.({
4324
- id: msg.playerId,
4325
- username: msg.username,
4326
- avatarUrl: msg.avatarUrl
4327
- });
4328
- }
4329
- onPlayerLeftMessageReceived(msg) {
4330
- this.log(`playerLeft id=${msg.playerId}`);
4331
- this.events.onPlayerLeft?.(msg.playerId);
4332
- }
4333
- onErrorMessageReceived(msg) {
4334
- this.warn(`error: ${msg.message}`);
4335
- this.events.onError?.(msg.message);
4336
- }
4337
- onReconnectingMessageReceived() {
4338
- if (this.transitionTo("reconnecting")) {
4339
- this.events.onReconnecting?.();
4340
- }
4341
- }
4342
- onReconnectedMessageReceived(_msg) {
4343
- this.ws.confirmConnection();
4344
- if (this.transitionTo("active")) {
4345
- this.events.onReconnected?.();
4346
- }
4347
- }
4348
- onPongMessageReceived(msg) {
4349
- const now = Date.now();
4350
- const rtt = now - msg.ts;
4351
- this._latency = Math.round(rtt / 2);
4352
- this._serverTimeOffset = msg.serverTs - now + this._latency;
4353
- }
4354
- onError(err) {
4355
- this.warn(`ws error: ${err.message}`);
4356
- this.events.onError?.(err.message);
4357
- }
4358
- onConnectionStateChanged(state) {
4339
+ handleConnectionState(state) {
4359
4340
  this.log(`connectionState=${state}`);
4360
4341
  switch (state) {
4361
4342
  case "connected":
4362
- this.onConnectedStateEntered();
4343
+ this.startPing();
4363
4344
  break;
4364
4345
  case "disconnected":
4365
- this.onDisconnectedStateEntered();
4346
+ this.stopPing();
4347
+ if (this.transitionTo("dead")) {
4348
+ this.events.onDisconnect?.();
4349
+ }
4366
4350
  break;
4367
4351
  case "reconnecting":
4368
- this.onReconnectingStateEntered();
4352
+ this.stopPing();
4353
+ if (this.transitionTo("reconnecting")) {
4354
+ this.events.onReconnecting?.();
4355
+ }
4369
4356
  break;
4370
4357
  }
4371
4358
  }
4372
- onConnectedStateEntered() {
4373
- this.startPing();
4374
- }
4375
- onDisconnectedStateEntered() {
4376
- this.stopPing();
4377
- if (this.transitionTo("dead")) {
4378
- this.events.onDisconnect?.();
4379
- }
4380
- }
4381
- onReconnectingStateEntered() {
4382
- this.stopPing();
4383
- if (this.transitionTo("reconnecting")) {
4384
- this.events.onReconnecting?.();
4385
- }
4386
- }
4387
4359
  startPing() {
4388
4360
  if (this.pingInterval) return;
4389
4361
  this.pingInterval = setInterval(() => {
@@ -4414,7 +4386,6 @@ var ServerWebSocket = class {
4414
4386
  _getJoinTicket;
4415
4387
  _authMessage;
4416
4388
  _isReconnect = false;
4417
- _authenticated = false;
4418
4389
  constructor(options) {
4419
4390
  this.url = options.url;
4420
4391
  this.maxReconnectAttempts = options.maxReconnectAttempts ?? 10;
@@ -4450,7 +4421,6 @@ var ServerWebSocket = class {
4450
4421
  connect() {
4451
4422
  if (this.disposed) return;
4452
4423
  console.log(`[ServerWebSocket] connect() isReconnect=${this._isReconnect} url=${this.url}`);
4453
- this._authenticated = false;
4454
4424
  this.setState(this._isReconnect ? "reconnecting" : "connecting");
4455
4425
  try {
4456
4426
  if (this.ws) {
@@ -4476,7 +4446,7 @@ var ServerWebSocket = class {
4476
4446
  * Send a message to the server.
4477
4447
  */
4478
4448
  send(msg) {
4479
- if (this.ws && this.ws.readyState === WebSocket.OPEN && this._authenticated) {
4449
+ if (this.ws && this.ws.readyState === WebSocket.OPEN) {
4480
4450
  this.ws.send(JSON.stringify(msg));
4481
4451
  }
4482
4452
  }
@@ -4515,7 +4485,6 @@ var ServerWebSocket = class {
4515
4485
  const authMsg = { ...this._authMessage, ticket: freshTicket, reconnect: true };
4516
4486
  console.log(`[ServerWebSocket] sending reconnect auth roomId=${this._authMessage._roomId}`);
4517
4487
  socket.send(JSON.stringify(authMsg));
4518
- this._authenticated = true;
4519
4488
  } catch {
4520
4489
  console.error(`[ServerWebSocket] failed to get join ticket for reconnection`);
4521
4490
  this.events.onError?.(new Error("Failed to get join ticket for reconnection"));
@@ -4525,7 +4494,6 @@ var ServerWebSocket = class {
4525
4494
  } else if (this._authMessage) {
4526
4495
  if (socket.readyState === WebSocket.OPEN) {
4527
4496
  socket.send(JSON.stringify(this._authMessage));
4528
- this._authenticated = true;
4529
4497
  }
4530
4498
  }
4531
4499
  if (this.ws !== socket) return;
@@ -4541,7 +4509,6 @@ var ServerWebSocket = class {
4541
4509
  }
4542
4510
  onClose(event) {
4543
4511
  console.log(`[ServerWebSocket] onclose code=${event.code} reason=${event.reason} disposed=${this.disposed}`);
4544
- this._authenticated = false;
4545
4512
  if (this.disposed) {
4546
4513
  this.setState("disconnected");
4547
4514
  return;
@@ -4581,9 +4548,6 @@ var ServerWebSocket = class {
4581
4548
  }
4582
4549
  };
4583
4550
 
4584
- // src/mp/client/ServerProtocol.ts
4585
- var PROTOCOL_VERSION = 1;
4586
-
4587
4551
  // src/mp/client/WsMultiplayerApi.ts
4588
4552
  var WsMultiplayerApi = class {
4589
4553
  serverUrl;
@@ -4607,7 +4571,7 @@ var WsMultiplayerApi = class {
4607
4571
  async _joinWithAction(action, roomType, roomCode) {
4608
4572
  const req = { roomType, action, roomCode };
4609
4573
  const ticket = await this.getJoinTicket(req);
4610
- return this._connect({ type: "auth", protocolVersion: PROTOCOL_VERSION, ticket, roomType, action, roomCode });
4574
+ return this._connect({ type: "auth", ticket, roomType, action, roomCode });
4611
4575
  }
4612
4576
  _connect(authMsg) {
4613
4577
  const wsUrl = this.resolveServerUrl().replace(/^http/, "ws") + "/ws";
@@ -4634,9 +4598,9 @@ var WsMultiplayerApi = class {
4634
4598
  if (resolved) return;
4635
4599
  console.log(`[WsMultiplayerApi] pre-join msg: ${msg.type}`, msg);
4636
4600
  if (msg.type === "room:joined") {
4637
- console.log(`[WsMultiplayerApi] room:joined roomCode=${msg.roomCode} playerId=${msg.playerId}`);
4601
+ console.log(`[WsMultiplayerApi] room:joined roomCode=${msg.roomCode} playerId=${msg.playerId} stateKeys=${Object.keys(msg.state ?? {})}`);
4638
4602
  ws.setAuthMessage({ ...authMsg, _roomId: msg._roomId });
4639
- const room = new RundotServerRoom(msg.roomCode, msg.playerId, ws);
4603
+ const room = new RundotServerRoom(msg.roomCode, msg.playerId, ws, msg.state);
4640
4604
  settle(() => resolve(room));
4641
4605
  } else if (msg.type === "room:error") {
4642
4606
  console.error(`[WsMultiplayerApi] room:error code=${msg.code} message=${msg.message}`);
@@ -4707,7 +4671,7 @@ var MockMultiplayerApi = class {
4707
4671
  });
4708
4672
  const roomCode = Math.random().toString(36).slice(2, 8).toUpperCase();
4709
4673
  const playerId = `mock-player-${Math.random().toString(36).slice(2, 8)}`;
4710
- const room = new RundotServerRoom(roomCode, playerId, ws);
4674
+ const room = new RundotServerRoom(roomCode, playerId, ws, {});
4711
4675
  console.log(`[MockMultiplayerApi] Created mock room ${roomCode} (${roomType})`);
4712
4676
  return room;
4713
4677
  }
@@ -4722,5 +4686,5 @@ var MockMultiplayerApi = class {
4722
4686
  };
4723
4687
 
4724
4688
  export { AccessDeniedError, BaseCdnApi, DEFAULT_SHARED_LIB_CDN_BASE, EMBEDDED_LIBRARIES, EMBEDDED_LIBRARY_BY_KEY, FILE_EXTENSION_PATTERN, HapticFeedbackStyle, HostCdnApi, HostDeviceApi, HostEnvironmentApi, HostProfileApi, HostSystemApi, HostTimeApi, MIN_CDN_PATH_SEGMENTS, MODULE_TO_LIBRARY_SPECIFIERS, MockAccessGateApi, MockAdsApi, MockAiApi, MockAnalyticsApi, MockAvatarApi, MockCdnApi, MockDeviceApi, MockEntitlementApi, MockEnvironmentApi, MockFeaturesApi, MockHapticsApi, MockIapApi, MockLifecycleApi, MockLoggingApi, MockMultiplayerApi, MockNavigationApi, MockNotificationsApi, MockPopupsApi, MockPreloaderApi, MockProfileApi, MockSharedAssetsApi, MockShopApi, MockSocialApi, MockStorageApi, MockSystemApi, MockTimeApi, ROOM_GAME_PHASES, RpcAccessGateApi, RpcAdsApi, RpcAiApi, RpcAnalyticsApi, RpcAvatarApi, RpcEntitlementApi, RpcFeaturesApi, RpcHapticsApi, RpcIapApi, RpcLifecycleApi, RpcLoggingApi, RpcNavigationApi, RpcNotificationsApi, RpcPopupsApi, RpcPreloaderApi, RpcRoomsApi, RpcSharedAssetsApi, RpcShopApi, RpcStorageApi, RundotGameMessageId, RundotGameRoom, SandboxProfileApi, WsMultiplayerApi, applyAccessGates, base64ToArrayBuffer, base64ToUtf8, createAccessGatedApi, createMockStorageApi, generateId, getLibraryDefinition, hasHostedUrlStructure, initializeAccessGate, initializeAds, initializeAi, initializeAnalytics, initializeAvatar3d, initializeCdn, initializeEntitlements, initializeFeaturesApi, initializeHaptics, initializeIap, initializeLifecycleApi, initializeLocalNotifications, initializeLoggingApi, initializePopups, initializePreloader, initializeProfile, initializeRoomsApi, initializeShop, initializeStackNavigation, initializeStorage, initializeSystem, initializeTime, isPacificDaylightTime, parseCdnPathSegments, setupRoomNotifications };
4725
- //# sourceMappingURL=chunk-YCM54J5I.js.map
4726
- //# sourceMappingURL=chunk-YCM54J5I.js.map
4689
+ //# sourceMappingURL=chunk-BYPG3HXZ.js.map
4690
+ //# sourceMappingURL=chunk-BYPG3HXZ.js.map