Add pack handling to lobby configuration and cosmetic loading

This commit is contained in:
Aotumuri
2025-10-01 21:11:53 +09:00
parent 3122052f60
commit 7d624f508b
11 changed files with 49 additions and 14 deletions
+1
View File
@@ -52,6 +52,7 @@ export interface LobbyConfig {
serverConfig: ServerConfig;
pattern: PlayerPattern | undefined;
flag: string;
pack: string | undefined;
playerName: string;
clientID: ClientID;
gameID: GameID;
+2 -2
View File
@@ -23,11 +23,11 @@ function fetchManifest(packId: string): CosmeticManifest | undefined {
}
export async function resolveCosmeticUrl(
packId: string | null,
packId: string | undefined,
key: string | undefined,
fallback: string,
): Promise<string> {
if (!packId || key === undefined) {
if (packId === undefined || key === undefined) {
return fallback;
}
try {
+1
View File
@@ -516,6 +516,7 @@ class Client {
this.flagInput === null || this.flagInput.getCurrentFlag() === "xx"
? ""
: this.flagInput.getCurrentFlag(),
pack: this.userSettings.getSelectedPackId() ?? undefined,
playerName: this.usernameInput?.getCurrentUsername() ?? "",
token: getPlayToken(),
clientID: lobby.clientID,
+2
View File
@@ -448,6 +448,7 @@ export class SinglePlayerModal extends LitElement {
selectedPattern ??= cosmetics
? (this.userSettings.getDevOnlyPattern() ?? null)
: null;
const selectedPackId = this.userSettings.getSelectedPackId();
this.dispatchEvent(
new CustomEvent("join-lobby", {
@@ -466,6 +467,7 @@ export class SinglePlayerModal extends LitElement {
? ""
: flagInput.getCurrentFlag(),
pattern: selectedPattern ?? undefined,
pack: selectedPackId ?? undefined,
},
},
],
+1
View File
@@ -381,6 +381,7 @@ export class Transport {
flag: this.lobbyConfig.flag,
patternName: this.lobbyConfig.pattern?.name,
patternColorPaletteName: this.lobbyConfig.pattern?.colorPalette?.name,
pack: this.lobbyConfig.pack,
},
} satisfies ClientJoinMessage);
}
+3 -3
View File
@@ -53,13 +53,13 @@ const SPRITE_CONFIG: Partial<
const spriteMap: Map<UnitType | TrainTypeSprite, ImageBitmap> = new Map();
// preload all images
export const loadAllSprites = async (): Promise<void> => {
export const loadAllSprites = async (
packId: string | undefined,
): Promise<void> => {
const entries = Object.entries(SPRITE_CONFIG);
const totalSprites = entries.length;
let loadedCount = 0;
const packId: string | null = "test"; // TODO: wire from server/client selection
await Promise.all(
entries.map(async ([unitType, value]) => {
const typedUnitType = unitType as UnitType | TrainTypeSprite;
+20 -7
View File
@@ -34,6 +34,8 @@ export class StructureLayer implements Layer {
private context: CanvasRenderingContext2D;
private unitIcons: Map<string, HTMLImageElement> = new Map();
private theme: Theme;
private packId: string | undefined;
private structureLoaded = false;
private tempCanvas: HTMLCanvasElement;
private tempContext: CanvasRenderingContext2D;
@@ -117,6 +119,14 @@ export class StructureLayer implements Layer {
if (unit === undefined) continue;
this.handleUnitRendering(unit);
}
if (!this.structureLoaded) {
const myPlayer = this.game.myPlayer();
if (myPlayer) {
this.packId = myPlayer.cosmetics.pack;
this.loadIconData();
this.structureLoaded = true;
}
}
}
init() {
@@ -124,23 +134,26 @@ export class StructureLayer implements Layer {
}
private async applyCosmeticIcons(): Promise<void> {
const packSpec = "test";
this.unitConfigs[UnitType.Port] = {
...this.unitConfigs[UnitType.Port]!,
icon: await resolveCosmeticUrl(
packSpec,
this.packId,
"structure/img/port",
anchorIcon,
),
};
this.unitConfigs[UnitType.City] = {
...this.unitConfigs[UnitType.City]!,
icon: await resolveCosmeticUrl(packSpec, "structure/img/city", cityIcon),
icon: await resolveCosmeticUrl(
this.packId,
"structure/img/city",
cityIcon,
),
};
this.unitConfigs[UnitType.Factory] = {
...this.unitConfigs[UnitType.Factory]!,
icon: await resolveCosmeticUrl(
packSpec,
this.packId,
"structure/img/factory",
factoryIcon,
),
@@ -148,7 +161,7 @@ export class StructureLayer implements Layer {
this.unitConfigs[UnitType.MissileSilo] = {
...this.unitConfigs[UnitType.MissileSilo]!,
icon: await resolveCosmeticUrl(
packSpec,
this.packId,
"structure/img/missilesilo",
missileSiloIcon,
),
@@ -156,7 +169,7 @@ export class StructureLayer implements Layer {
this.unitConfigs[UnitType.DefensePost] = {
...this.unitConfigs[UnitType.DefensePost]!,
icon: await resolveCosmeticUrl(
packSpec,
this.packId,
"structure/img/defensepost",
shieldIcon,
),
@@ -164,7 +177,7 @@ export class StructureLayer implements Layer {
this.unitConfigs[UnitType.SAMLauncher] = {
...this.unitConfigs[UnitType.SAMLauncher]!,
icon: await resolveCosmeticUrl(
packSpec,
this.packId,
"structure/img/samlauncher",
SAMMissileIcon,
),
+12 -2
View File
@@ -36,6 +36,8 @@ export class UnitLayer implements Layer {
private unitToTrail = new Map<UnitView, TileRef[]>();
private theme: Theme;
private packId: string | undefined = undefined;
private spritesLoaded = false;
private alternateView = false;
@@ -68,6 +70,15 @@ export class UnitLayer implements Layer {
?.[GameUpdateType.Unit]?.map((unit) => unit.id);
this.updateUnitsSprites(unitIds ?? []);
if (!this.spritesLoaded) {
const myPlayer = this.game.myPlayer();
if (myPlayer) {
this.packId = myPlayer.cosmetics.pack;
loadAllSprites(this.packId);
this.spritesLoaded = true;
}
}
}
init() {
@@ -75,8 +86,7 @@ export class UnitLayer implements Layer {
this.eventBus.on(MouseUpEvent, (e) => this.onMouseUp(e));
this.eventBus.on(UnitSelectionEvent, (e) => this.onUnitSelectionChange(e));
this.redraw();
loadAllSprites();
loadAllSprites(this.packId);
}
/**
+2
View File
@@ -390,6 +390,7 @@ export const PlayerCosmeticRefsSchema = z.object({
flag: FlagSchema.optional(),
patternName: PatternNameSchema.optional(),
patternColorPaletteName: z.string().optional(),
pack: z.string().optional(),
});
export const PlayerPatternSchema = z.object({
@@ -400,6 +401,7 @@ export const PlayerPatternSchema = z.object({
export const PlayerCosmeticsSchema = z.object({
flag: FlagSchema.optional(),
pattern: PlayerPatternSchema.optional(),
pack: z.string().optional(),
});
export const PlayerSchema = z.object({
clientID: ID,
+4
View File
@@ -154,4 +154,8 @@ export class UserSettings {
localStorage.setItem(PATTERN_KEY, patternName);
}
}
getSelectedPackId(): string | undefined {
return localStorage.getItem("cosmeticPackId") ?? undefined;
}
}
+1
View File
@@ -490,6 +490,7 @@ export async function startWorker() {
cosmetics: {
flag: cosmetics.flag,
pattern: pattern,
pack: cosmetics.pack,
},
};
}