From dba04027df723880c096f0d3b975e831425f63fd Mon Sep 17 00:00:00 2001
From: FloPinguin <25036848+FloPinguin@users.noreply.github.com>
Date: Sat, 17 Jan 2026 15:35:26 +0100
Subject: [PATCH] Merge pull request #2933 from FloPinguin/fix-nation-loading
Fix for v29: Add nation count loading for JoinPrivateLobbyModal; change HvN difficulty
---
src/client/HostLobbyModal.ts | 69 ++++++-------------
src/client/JoinPrivateLobbyModal.ts | 66 ++++++++++++------
.../{LobbyTeamView.ts => LobbyPlayerView.ts} | 57 ++++++++++++---
src/client/styles.css | 1 -
src/server/MapPlaylist.ts | 4 +-
5 files changed, 115 insertions(+), 82 deletions(-)
rename src/client/components/{LobbyTeamView.ts => LobbyPlayerView.ts} (83%)
diff --git a/src/client/HostLobbyModal.ts b/src/client/HostLobbyModal.ts
index e7d709c12..2401c6d3a 100644
--- a/src/client/HostLobbyModal.ts
+++ b/src/client/HostLobbyModal.ts
@@ -14,7 +14,6 @@ import {
UnitType,
mapCategories,
} from "../core/game/Game";
-import { getCompactMapNationCount } from "../core/game/NationCreation";
import { UserSettings } from "../core/game/UserSettings";
import {
ClientInfo,
@@ -28,7 +27,7 @@ import "./components/baseComponents/Modal";
import { BaseModal } from "./components/BaseModal";
import "./components/Difficulties";
import "./components/FluentSlider";
-import "./components/LobbyTeamView";
+import "./components/LobbyPlayerView";
import "./components/Maps";
import { modalHeader } from "./components/ui/ModalHeader";
import { crazyGamesSDK } from "./CrazyGamesSDK";
@@ -934,33 +933,16 @@ export class HostLobbyModal extends BaseModal {
-
-
-
- ${this.clients.length}
- ${this.clients.length === 1
- ? translateText("host_modal.player")
- : translateText("host_modal.players")}
- •
- ${this.getEffectiveNationCount()}
- ${this.getEffectiveNationCount() === 1
- ? translateText("host_modal.nation_player")
- : translateText("host_modal.nation_players")}
-
-
-
-
this.kickPlayer(clientID)}
- >
-
+ this.kickPlayer(clientID)}
+ >
@@ -1438,31 +1420,22 @@ export class HostLobbyModal extends BaseModal {
}
private async loadNationCount() {
+ const currentMap = this.selectedMap;
try {
- const mapData = this.mapLoader.getMapData(this.selectedMap);
+ const mapData = this.mapLoader.getMapData(currentMap);
const manifest = await mapData.manifest();
- this.nationCount = manifest.nations.length;
+ // Only update if the map hasn't changed
+ if (this.selectedMap === currentMap) {
+ this.nationCount = manifest.nations.length;
+ }
} catch (error) {
console.warn("Failed to load nation count", error);
- this.nationCount = 0;
+ // Only update if the map hasn't changed
+ if (this.selectedMap === currentMap) {
+ this.nationCount = 0;
+ }
}
}
-
- /**
- * Returns the effective nation count for display purposes.
- * In HumansVsNations mode, this equals the number of human players.
- * For compact maps, only 25% of nations are used.
- * Otherwise, it uses the manifest nation count (or 0 if nations are disabled).
- */
- private getEffectiveNationCount(): number {
- if (this.disableNations) {
- return 0;
- }
- if (this.gameMode === GameMode.Team && this.teamCount === HumansVsNations) {
- return this.clients.length;
- }
- return getCompactMapNationCount(this.nationCount, this.compactMap);
- }
}
async function createLobby(creatorClientID: string): Promise {
diff --git a/src/client/JoinPrivateLobbyModal.ts b/src/client/JoinPrivateLobbyModal.ts
index cb65b428f..a618a9ccc 100644
--- a/src/client/JoinPrivateLobbyModal.ts
+++ b/src/client/JoinPrivateLobbyModal.ts
@@ -10,13 +10,14 @@ import {
} from "../core/Schemas";
import { generateID } from "../core/Util";
import { getServerConfigFromClient } from "../core/configuration/ConfigLoader";
-import { GameMode } from "../core/game/Game";
+import { GameMapSize, GameMode } from "../core/game/Game";
import { UserSettings } from "../core/game/UserSettings";
import { getApiBase } from "./Api";
import { JoinLobbyEvent } from "./Main";
+import { terrainMapFileLoader } from "./TerrainMapFileLoader";
import { BaseModal } from "./components/BaseModal";
import "./components/Difficulties";
-import "./components/LobbyTeamView";
+import "./components/LobbyPlayerView";
import { modalHeader } from "./components/ui/ModalHeader";
@customElement("join-private-lobby-modal")
export class JoinPrivateLobbyModal extends BaseModal {
@@ -29,9 +30,11 @@ export class JoinPrivateLobbyModal extends BaseModal {
@state() private lobbyIdVisible: boolean = true;
@state() private copySuccess: boolean = false;
@state() private currentLobbyId: string = "";
+ @state() private nationCount: number = 0;
private playersInterval: NodeJS.Timeout | null = null;
private userSettings: UserSettings = new UserSettings();
+ private mapLoader = terrainMapFileLoader;
private leaveLobbyOnClose = true;
@@ -180,26 +183,17 @@ export class JoinPrivateLobbyModal extends BaseModal {
${this.renderGameConfig()}
${this.hasJoined && this.players.length > 0
? html`
-
-
-
- ${this.players.length}
- ${this.players.length === 1
- ? translateText("private_lobby.player")
- : translateText("private_lobby.players")}
-
-
-
-
-
+
`
: ""}
@@ -387,6 +381,7 @@ export class JoinPrivateLobbyModal extends BaseModal {
this.hasJoined = false;
this.message = "";
this.currentLobbyId = "";
+ this.nationCount = 0;
this.leaveLobbyOnClose = true;
}
@@ -612,11 +607,38 @@ export class JoinPrivateLobbyModal extends BaseModal {
this.lobbyCreatorClientID = data.clients?.[0]?.clientID ?? null;
this.players = data.clients ?? [];
if (data.gameConfig) {
+ const mapChanged =
+ this.gameConfig?.gameMap !== data.gameConfig.gameMap;
this.gameConfig = data.gameConfig;
+ if (mapChanged) {
+ this.loadNationCount();
+ }
}
})
.catch((error) => {
console.error("Error polling players:", error);
});
}
+
+ private async loadNationCount() {
+ if (!this.gameConfig) {
+ this.nationCount = 0;
+ return;
+ }
+ const currentMap = this.gameConfig.gameMap;
+ try {
+ const mapData = this.mapLoader.getMapData(currentMap);
+ const manifest = await mapData.manifest();
+ // Only update if the map hasn't changed
+ if (this.gameConfig?.gameMap === currentMap) {
+ this.nationCount = manifest.nations.length;
+ }
+ } catch (error) {
+ console.warn("Failed to load nation count", error);
+ // Only update if the map hasn't changed
+ if (this.gameConfig?.gameMap === currentMap) {
+ this.nationCount = 0;
+ }
+ }
+ }
}
diff --git a/src/client/components/LobbyTeamView.ts b/src/client/components/LobbyPlayerView.ts
similarity index 83%
rename from src/client/components/LobbyTeamView.ts
rename to src/client/components/LobbyPlayerView.ts
index d85105c4b..2bcac3108 100644
--- a/src/client/components/LobbyTeamView.ts
+++ b/src/client/components/LobbyPlayerView.ts
@@ -13,6 +13,7 @@ import {
Team,
Trios,
} from "../../core/game/Game";
+import { getCompactMapNationCount } from "../../core/game/NationCreation";
import { assignTeamsLobbyPreview } from "../../core/game/TeamAssignment";
import { ClientInfo, TeamCountConfig } from "../../core/Schemas";
import { translateText } from "../Utils";
@@ -22,7 +23,7 @@ export interface TeamPreviewData {
players: ClientInfo[];
}
-@customElement("lobby-team-view")
+@customElement("lobby-player-view")
export class LobbyTeamView extends LitElement {
@property({ type: String }) gameMode: GameMode = GameMode.FFA;
@property({ type: Array }) clients: ClientInfo[] = [];
@@ -32,6 +33,8 @@ export class LobbyTeamView extends LitElement {
@property({ attribute: "team-count" }) teamCount: TeamCountConfig = 2;
@property({ type: Function }) onKickPlayer?: (clientID: string) => void;
@property({ type: Number }) nationCount: number = 0;
+ @property({ type: Boolean }) disableNations: boolean = false;
+ @property({ type: Boolean }) isCompactMap: boolean = false;
private theme: PastelTheme = new PastelTheme();
@state() private showTeamColors: boolean = false;
@@ -52,11 +55,32 @@ export class LobbyTeamView extends LitElement {
}
render() {
- return html`
- ${this.gameMode === GameMode.Team
- ? this.renderTeamMode()
- : this.renderFreeForAll()}
-
`;
+ return html`
+
+
+
+ ${this.clients.length}
+ ${this.clients.length === 1
+ ? translateText("host_modal.player")
+ : translateText("host_modal.players")}
+ •
+ ${this.getEffectiveNationCount()}
+ ${this.getEffectiveNationCount() === 1
+ ? translateText("host_modal.nation_player")
+ : translateText("host_modal.nation_players")}
+
+
+
+ ${this.gameMode === GameMode.Team
+ ? this.renderTeamMode()
+ : this.renderFreeForAll()}
+
+
+ `;
}
createRenderRoot() {
@@ -148,14 +172,15 @@ export class LobbyTeamView extends LitElement {
}
private renderTeamCard(preview: TeamPreviewData, isEmpty: boolean = false) {
+ const effectiveNationCount = this.getEffectiveNationCount();
const displayCount =
preview.team === ColoredTeams.Nations
- ? this.nationCount
+ ? effectiveNationCount
: preview.players.length;
const maxTeamSize =
preview.team === ColoredTeams.Nations
- ? this.nationCount
+ ? effectiveNationCount
: this.teamMaxSize;
return html`
@@ -308,4 +333,20 @@ export class LobbyTeamView extends LitElement {
players: buckets.get(t) ?? [],
}));
}
+
+ /**
+ * Returns the effective nation count for display purposes.
+ * In HumansVsNations mode, this equals the number of human players.
+ * For compact maps, only 25% of nations are used.
+ * Otherwise, it uses the manifest nation count (or 0 if nations are disabled).
+ */
+ private getEffectiveNationCount(): number {
+ if (this.disableNations) {
+ return 0;
+ }
+ if (this.gameMode === GameMode.Team && this.teamCount === HumansVsNations) {
+ return this.clients.length;
+ }
+ return getCompactMapNationCount(this.nationCount, this.isCompactMap);
+ }
}
diff --git a/src/client/styles.css b/src/client/styles.css
index 9873cd4f0..7023676e8 100644
--- a/src/client/styles.css
+++ b/src/client/styles.css
@@ -546,7 +546,6 @@ label.option-card:hover {
flex-wrap: wrap;
gap: 8px;
justify-content: center;
- padding: 0 16px;
}
/* News Button Notification */
diff --git a/src/server/MapPlaylist.ts b/src/server/MapPlaylist.ts
index c4430e332..97b23f0e4 100644
--- a/src/server/MapPlaylist.ts
+++ b/src/server/MapPlaylist.ts
@@ -127,9 +127,7 @@ export class MapPlaylist {
publicGameModifiers: { isCompact, isRandomSpawn, startingGold },
startingGold,
difficulty:
- playerTeams === HumansVsNations
- ? Difficulty.Impossible
- : Difficulty.Easy,
+ playerTeams === HumansVsNations ? Difficulty.Hard : Difficulty.Easy,
infiniteGold: false,
infiniteTroops: false,
maxTimerValue: undefined,