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
3 changes: 3 additions & 0 deletions src/client/ClientGameRunner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ export interface LobbyConfig {
serverConfig: ServerConfig;
cosmetics: PlayerCosmeticRefs;
playerName: string;
playerClanTag: string | null;
gameID: GameID;
turnstileToken: string | null;
// GameStartInfo only exists when playing a singleplayer game.
Expand Down Expand Up @@ -228,6 +229,7 @@ async function createClientGame(
gameMap,
clientID,
lobbyConfig.playerName,
lobbyConfig.playerClanTag,
lobbyConfig.gameStartInfo.gameID,
lobbyConfig.gameStartInfo.players,
);
Expand Down Expand Up @@ -301,6 +303,7 @@ export class ClientGameRunner {
{
persistentID: getPersistentID(),
username: this.lobby.playerName,
clanTag: this.lobby.playerClanTag ?? undefined,
clientID: this.clientID,
stats: update.allPlayersStats[this.clientID],
},
Expand Down
19 changes: 4 additions & 15 deletions src/client/GameInfoModal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { GameEndInfo } from "../core/Schemas";
import { GameMapType, hasUnusualThumbnailSize } from "../core/game/Game";
import { fetchGameById } from "./Api";
import { terrainMapFileLoader } from "./TerrainMapFileLoader";
import { UsernameInput } from "./UsernameInput";
import { renderDuration, translateText } from "./Utils";
import {
PlayerInfo,
Expand All @@ -28,7 +27,7 @@ export class GameInfoModal extends LitElement {
@property({ type: String }) gameId: string | null = null;
@property({ type: String }) rankType = RankType.Lifetime;

@state() private username: string | null = null;
@state() private currentClientID: string | null = null;
@state() private isLoadingGame: boolean = true;

private ranking: Ranking | null = null;
Expand Down Expand Up @@ -155,7 +154,7 @@ export class GameInfoModal extends LitElement {
.score=${this.ranking?.score(player, this.rankType) ?? 0}
.rankType=${this.rankType}
.bestScore=${bestScore}
.currentPlayer=${this.username === player.rawUsername}
.currentPlayer=${this.currentClientID === player.id}
></player-row>
`,
)}
Expand Down Expand Up @@ -186,26 +185,16 @@ export class GameInfoModal extends LitElement {
}
}

public loadUserName() {
const usernameInput = document.querySelector(
"username-input",
) as UsernameInput;
if (usernameInput) {
this.username = usernameInput.getCurrentUsername();
}
}

public async loadGame(gameId: string) {
public async loadGame(gameId: string, currentClientID: string | null = null) {
try {
this.isLoadingGame = true;
this.loadUserName();
this.currentClientID = currentClientID;
const session = await fetchGameById(gameId);
if (!session) return;

this.gameInfo = session.info;
this.ranking = new Ranking(session);
this.updateRanking();
this.isLoadingGame = false;
await this.loadMapImage(session.info.config.gameMap);
} catch (err) {
console.error("Failed to load game:", err);
Expand Down
19 changes: 5 additions & 14 deletions src/client/GameModeSelector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { PublicLobbySocket } from "./LobbySocket";
import { JoinLobbyEvent } from "./Main";
import { SinglePlayerModal } from "./SinglePlayerModal";
import { terrainMapFileLoader } from "./TerrainMapFileLoader";
import { UsernameInput } from "./UsernameInput";
import { getMapName, renderDuration, translateText } from "./Utils";

const CARD_BG = "bg-[color-mix(in_oklab,var(--frenchBlue)_70%,black)]";
Expand All @@ -38,20 +39,10 @@ export class GameModeSelector extends LitElement {
* Returns true if valid, false otherwise.
*/
private validateUsername(): boolean {
const usernameInput = document.querySelector("username-input") as any;
if (usernameInput?.isValid?.() === false) {
window.dispatchEvent(
new CustomEvent("show-message", {
detail: {
message: usernameInput.validationError,
color: "red",
duration: 3000,
},
}),
);
return false;
}
return true;
const usernameInput = document.querySelector(
"username-input",
) as UsernameInput | null;
return usernameInput ? usernameInput.validateOrShowError() : true;
}

connectedCallback() {
Expand Down
4 changes: 2 additions & 2 deletions src/client/HostLobbyModal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import {
TeamCountConfig,
isValidGameID,
} from "../core/Schemas";
import { generateID } from "../core/Util";
import { clientInfoListsEqual, generateID } from "../core/Util";
import { getPlayToken } from "./Auth";
import "./components/baseComponents/Modal";
import { BaseModal } from "./components/BaseModal";
Expand Down Expand Up @@ -90,7 +90,7 @@ export class HostLobbyModal extends BaseModal {
return;
}
this.lobbyCreatorClientID = lobby.lobbyCreatorClientID ?? "";
if (lobby.clients) {
if (lobby.clients && !clientInfoListsEqual(this.clients, lobby.clients)) {
this.clients = lobby.clients;
}
};
Expand Down
26 changes: 21 additions & 5 deletions src/client/JoinLobbyModal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
LobbyInfoEvent,
PublicGameInfo,
} from "../core/Schemas";
import { clientInfoListsEqual, gameConfigsEqual } from "../core/Util";
import { getServerConfigFromClient } from "../core/configuration/ConfigLoader";
import {
GameMapSize,
Expand Down Expand Up @@ -61,7 +62,9 @@ export class JoinLobbyModal extends BaseModal {

private readonly handleLobbyInfo = (event: LobbyInfoEvent) => {
const lobby = event.lobby;
this.currentClientID = event.myClientID;
if (this.currentClientID !== event.myClientID) {
this.currentClientID = event.myClientID;
}
// Only stop showing spinner when we have player info
if (this.isConnecting && lobby.clients) {
this.isConnecting = false;
Expand Down Expand Up @@ -514,21 +517,34 @@ export class JoinLobbyModal extends BaseModal {
// --- Lobby event handling ---

private updateFromLobby(lobby: GameInfo | PublicGameInfo) {
this.players = "clients" in lobby ? (lobby.clients ?? []) : [];
this.lobbyStartAt = lobby.startsAt ?? null;
const nextPlayers = "clients" in lobby ? (lobby.clients ?? []) : [];
if (!clientInfoListsEqual(this.players, nextPlayers)) {
this.players = nextPlayers;
}

const nextLobbyStartAt = lobby.startsAt ?? null;
if (this.lobbyStartAt !== nextLobbyStartAt) {
this.lobbyStartAt = nextLobbyStartAt;
}
this.syncCountdownTimer();
if (lobby.gameConfig) {
const mapChanged = this.gameConfig?.gameMap !== lobby.gameConfig.gameMap;
this.gameConfig = lobby.gameConfig;
// Avoid unnecessary rerenders from per-second lobby_info broadcasts.
if (!gameConfigsEqual(this.gameConfig, lobby.gameConfig)) {
this.gameConfig = lobby.gameConfig;
}
if (mapChanged) {
this.loadNationCount();
}
}

this.lobbyCreatorClientID =
const nextLobbyCreatorClientID =
"lobbyCreatorClientID" in lobby
? (lobby.lobbyCreatorClientID ?? null)
: null;
if (this.lobbyCreatorClientID !== nextLobbyCreatorClientID) {
this.lobbyCreatorClientID = nextLobbyCreatorClientID;
}
}

private startLobbyUpdates() {
Expand Down
3 changes: 1 addition & 2 deletions src/client/LocalServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import {
import {
createPartialGameRecord,
decompressGameRecord,
getClanTag,
replacer,
} from "../core/Util";
import { getPersistentID } from "./Auth";
Expand Down Expand Up @@ -240,10 +239,10 @@ export class LocalServer {
{
persistentID: getPersistentID(),
username: this.lobbyConfig.playerName,
clanTag: this.lobbyConfig.playerClanTag ?? undefined,
clientID: this.clientID!,
stats: this.allPlayersStats[this.clientID!],
cosmetics: this.lobbyConfig.gameStartInfo?.players[0].cosmetics,
clanTag: getClanTag(this.lobbyConfig.playerName) ?? undefined,
},
];
if (this.lobbyConfig.gameStartInfo === undefined) {
Expand Down
8 changes: 6 additions & 2 deletions src/client/Main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -737,6 +737,10 @@ class Client {

private async handleJoinLobby(event: CustomEvent<JoinLobbyEvent>) {
const lobby = event.detail;
if (this.usernameInput && !this.usernameInput.validateOrShowError()) {
return;
}

console.log(`joining lobby ${lobby.gameID}`);
if (this.gameStop !== null) {
console.log("joining lobby, stopping existing game");
Expand All @@ -758,8 +762,8 @@ class Client {
serverConfig: config,
cosmetics: await getPlayerCosmeticsRefs(),
turnstileToken: await this.getTurnstileToken(lobby),
playerName:
this.usernameInput?.getCurrentUsername() ?? genAnonUsername(),
playerName: this.usernameInput?.getUsername() ?? genAnonUsername(),
playerClanTag: this.usernameInput?.getClanTag() ?? null,
gameStartInfo: lobby.gameStartInfo ?? lobby.gameRecord?.info,
gameRecord: lobby.gameRecord,
},
Expand Down
3 changes: 2 additions & 1 deletion src/client/SinglePlayerModal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -633,7 +633,8 @@ export class SinglePlayerModal extends BaseModal {
players: [
{
clientID,
username: usernameInput.getCurrentUsername(),
username: usernameInput.getUsername(),
clanTag: usernameInput.getClanTag() ?? undefined,
cosmetics: await getPlayerCosmetics(),
},
],
Expand Down
1 change: 1 addition & 0 deletions src/client/Transport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,7 @@ export class Transport {
gameID: this.lobbyConfig.gameID,
// Note: clientID is not sent - server assigns it based on persistentID
username: this.lobbyConfig.playerName,
clanTag: this.lobbyConfig.playerClanTag ?? undefined,
cosmetics: this.lobbyConfig.cosmetics,
turnstileToken: this.lobbyConfig.turnstileToken,
token: await getPlayToken(),
Expand Down
Loading
Loading