Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 0 additions & 20 deletions src/client/Auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,12 @@ import { decodeJwt } from "jose";
import { z } from "zod";
import { TokenPayload, TokenPayloadSchema } from "../core/ApiSchemas";
import { base64urlToUuid } from "../core/Base64";
import { ID } from "../core/Schemas";
import { generateID } from "../core/Util";
import { getApiBase, getAudience } from "./Api";
import { generateCryptoRandomUUID } from "./Utils";

export type UserAuth = { jwt: string; claims: TokenPayload } | false;

const PERSISTENT_ID_KEY = "player_persistent_id";
const CLIENT_ID_KEY = "client_join_id";
const CLIENT_GAME_ID_KEY = "client_join_game_id";

let __jwt: string | null = null;

Expand Down Expand Up @@ -213,22 +209,6 @@ export function getPersistentID(): string {
return base64urlToUuid(sub);
}

export function getClientIDForGame(gameID: string): string {
const storedGameID = sessionStorage.getItem(CLIENT_GAME_ID_KEY);
const storedClientID = sessionStorage.getItem(CLIENT_ID_KEY);
if (
storedGameID === gameID &&
storedClientID &&
ID.safeParse(storedClientID).success
) {
return storedClientID;
}
const newID = generateID();
sessionStorage.setItem(CLIENT_GAME_ID_KEY, gameID);
sessionStorage.setItem(CLIENT_ID_KEY, newID);
return newID;
}

// WARNING: DO NOT EXPOSE THIS ID
function getPersistentIDFromLocalStorage(): string {
// Try to get existing localStorage
Expand Down
68 changes: 35 additions & 33 deletions src/client/ClientGameRunner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ export interface LobbyConfig {
serverConfig: ServerConfig;
cosmetics: PlayerCosmeticRefs;
playerName: string;
clientID: ClientID;
gameID: GameID;
turnstileToken: string | null;
// GameStartInfo only exists when playing a singleplayer game.
Expand All @@ -71,9 +70,10 @@ export function joinLobby(
onPrestart: () => void,
onJoin: () => void,
): (force?: boolean) => boolean {
console.log(
`joining lobby: gameID: ${lobbyConfig.gameID}, clientID: ${lobbyConfig.clientID}`,
);
// Mutable clientID state — assigned by server (multiplayer) or derived from gameStartInfo (singleplayer)
let clientID: ClientID | undefined;

console.log(`joining lobby: gameID: ${lobbyConfig.gameID}`);

const userSettings: UserSettings = new UserSettings();
startGame(lobbyConfig.gameID, lobbyConfig.gameStartInfo?.config ?? {});
Expand All @@ -82,23 +82,18 @@ export function joinLobby(

let currentGameRunner: ClientGameRunner | null = null;

let hasJoined = false;

const onconnect = () => {
if (hasJoined) {
console.log("rejoining game");
transport.rejoinGame(0);
} else {
hasJoined = true;
console.log(`Joining game lobby ${lobbyConfig.gameID}`);
transport.joinGame();
}
// Always send join - server will detect reconnection via persistentID
console.log(`Joining game lobby ${lobbyConfig.gameID}`);
transport.joinGame();
};
let terrainLoad: Promise<TerrainMapData> | null = null;

const onmessage = (message: ServerMessage) => {
if (message.type === "lobby_info") {
eventBus.emit(new LobbyInfoEvent(message.lobby));
// Server tells us our assigned clientID
clientID = message.myClientID;
eventBus.emit(new LobbyInfoEvent(message.lobby, message.myClientID));
return;
}
if (message.type === "prestart") {
Expand All @@ -118,11 +113,14 @@ export function joinLobby(
console.log(
`lobby: game started: ${JSON.stringify(message, replacer, 2)}`,
);
// Server tells us our assigned clientID (also sent on start for late joins)
clientID = message.myClientID;
onJoin();
// For multiplayer games, GameStartInfo is not known until game starts.
lobbyConfig.gameStartInfo = message.gameStartInfo;
createClientGame(
lobbyConfig,
clientID,
eventBus,
transport,
userSettings,
Expand All @@ -148,7 +146,7 @@ export function joinLobby(
e.message,
e.stack,
lobbyConfig.gameID,
lobbyConfig.clientID,
clientID,
true,
false,
"error_modal.connection_error",
Expand All @@ -169,7 +167,7 @@ export function joinLobby(
message.error,
message.message,
lobbyConfig.gameID,
lobbyConfig.clientID,
clientID,
true,
false,
"error_modal.connection_error",
Expand All @@ -196,6 +194,7 @@ export function joinLobby(

async function createClientGame(
lobbyConfig: LobbyConfig,
clientID: ClientID | undefined,
eventBus: EventBus,
transport: Transport,
userSettings: UserSettings,
Expand All @@ -205,6 +204,10 @@ async function createClientGame(
if (lobbyConfig.gameStartInfo === undefined) {
throw new Error("missing gameStartInfo");
}
// For local games only, derive clientID from the first player in GameStartInfo
if (!clientID && transport.isLocal) {
clientID = lobbyConfig.gameStartInfo.players[0]?.clientID;
}
const config = await getConfig(
lobbyConfig.gameStartInfo.config,
userSettings,
Expand All @@ -221,16 +224,13 @@ async function createClientGame(
mapLoader,
);
}
const worker = new WorkerClient(
lobbyConfig.gameStartInfo,
lobbyConfig.clientID,
);
const worker = new WorkerClient(lobbyConfig.gameStartInfo, clientID!);
await worker.initialize();
const gameView = new GameView(
worker,
config,
gameMap,
lobbyConfig.clientID,
clientID!,
lobbyConfig.gameStartInfo.gameID,
lobbyConfig.gameStartInfo.players,
);
Expand All @@ -244,6 +244,7 @@ async function createClientGame(

return new ClientGameRunner(
lobbyConfig,
clientID,
eventBus,
gameRenderer,
new InputHandler(gameRenderer.uiState, canvas, eventBus),
Expand All @@ -269,6 +270,7 @@ export class ClientGameRunner {

constructor(
private lobby: LobbyConfig,
private clientID: ClientID | undefined,
private eventBus: EventBus,
private renderer: GameRenderer,
private input: InputHandler,
Expand Down Expand Up @@ -302,8 +304,8 @@ export class ClientGameRunner {
{
persistentID: getPersistentID(),
username: this.lobby.playerName,
clientID: this.lobby.clientID,
stats: update.allPlayersStats[this.lobby.clientID],
clientID: this.clientID!,
stats: update.allPlayersStats[this.clientID!],
},
];

Expand Down Expand Up @@ -360,7 +362,7 @@ export class ClientGameRunner {
gu.errMsg,
gu.stack ?? "missing",
this.lobby.gameStartInfo.gameID,
this.lobby.clientID,
this.clientID,
);
console.error(gu.stack);
this.stop();
Expand Down Expand Up @@ -422,7 +424,7 @@ export class ClientGameRunner {
"spawn_failed",
translateText("error_modal.spawn_failed.description"),
this.lobby.gameID,
this.lobby.clientID,
this.clientID,
true,
false,
translateText("error_modal.spawn_failed.title"),
Expand Down Expand Up @@ -459,7 +461,7 @@ export class ClientGameRunner {
`desync from server: ${JSON.stringify(message)}`,
"",
this.lobby.gameStartInfo.gameID,
this.lobby.clientID,
this.clientID,
true,
false,
"error_modal.desync_notice",
Expand All @@ -470,7 +472,7 @@ export class ClientGameRunner {
message.error,
message.message,
this.lobby.gameID,
this.lobby.clientID,
this.clientID,
true,
false,
"error_modal.connection_error",
Expand Down Expand Up @@ -554,7 +556,7 @@ export class ClientGameRunner {
return;
}
if (this.myPlayer === null) {
const myPlayer = this.gameView.playerByClientID(this.lobby.clientID);
const myPlayer = this.gameView.playerByClientID(this.clientID!);
if (myPlayer === null) return;
this.myPlayer = myPlayer;
}
Expand Down Expand Up @@ -589,7 +591,7 @@ export class ClientGameRunner {
const tile = this.gameView.ref(cell.x, cell.y);

if (this.myPlayer === null) {
const myPlayer = this.gameView.playerByClientID(this.lobby.clientID);
const myPlayer = this.gameView.playerByClientID(this.clientID!);
if (myPlayer === null) return;
this.myPlayer = myPlayer;
}
Expand Down Expand Up @@ -650,7 +652,7 @@ export class ClientGameRunner {
}

if (this.myPlayer === null) {
const myPlayer = this.gameView.playerByClientID(this.lobby.clientID);
const myPlayer = this.gameView.playerByClientID(this.clientID!);
if (myPlayer === null) return;
this.myPlayer = myPlayer;
}
Expand All @@ -669,7 +671,7 @@ export class ClientGameRunner {
}

if (this.myPlayer === null) {
const myPlayer = this.gameView.playerByClientID(this.lobby.clientID);
const myPlayer = this.gameView.playerByClientID(this.clientID!);
if (myPlayer === null) return;
this.myPlayer = myPlayer;
}
Expand Down Expand Up @@ -766,7 +768,7 @@ function showErrorModal(
error: string,
message: string | undefined,
gameID: GameID,
clientID: ClientID,
clientID: ClientID | undefined,
closable = false,
showDiscord = true,
heading = "error_modal.crashed",
Expand Down
Loading
Loading