mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-26 08:32:44 +00:00
fixed
This commit is contained in:
@@ -1,29 +0,0 @@
|
||||
{
|
||||
"id": "test",
|
||||
"name": "Test",
|
||||
"assets": {
|
||||
"structure": {
|
||||
"img": {
|
||||
"port": "structure/test.png",
|
||||
"city": "structure/test.png",
|
||||
"factory": "structure/test.png",
|
||||
"missilesilo": "structure/test.png",
|
||||
"defensepost": "structure/test.png",
|
||||
"samlauncher": "structure/test.png"
|
||||
}
|
||||
},
|
||||
"sprites": {
|
||||
"transportship": "sprites/test.png",
|
||||
"warship": "sprites/test.png",
|
||||
"sammissile": "sprites/test.png",
|
||||
"atombomb": "sprites/test.png",
|
||||
"hydrogenbomb": "sprites/test.png",
|
||||
"tradeship": "sprites/test.png",
|
||||
"mirv": "sprites/test.png",
|
||||
"engine": "sprites/test.png",
|
||||
"carriage": "sprites/test.png",
|
||||
"loadedcarriage": "sprites/test.png"
|
||||
},
|
||||
"audio": {}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
@@ -53,7 +53,25 @@ export interface LobbyConfig {
|
||||
serverConfig: ServerConfig;
|
||||
pattern: PlayerPattern | undefined;
|
||||
flag: string;
|
||||
pack: string | undefined;
|
||||
|
||||
structurePort: string | undefined;
|
||||
structureCity: string | undefined;
|
||||
structureFactory: string | undefined;
|
||||
structureMissilesilo: string | undefined;
|
||||
structureDefensepost: string | undefined;
|
||||
structureSamlauncher: string | undefined;
|
||||
|
||||
spriteTransportship: string | undefined;
|
||||
spriteWarship: string | undefined;
|
||||
spriteSammissile: string | undefined;
|
||||
spriteAtombomb: string | undefined;
|
||||
spriteHydrogenbomb: string | undefined;
|
||||
spriteTradeship: string | undefined;
|
||||
spriteMirv: string | undefined;
|
||||
spriteEngine: string | undefined;
|
||||
spriteCarriage: string | undefined;
|
||||
spriteLoadedcarriage: string | undefined;
|
||||
|
||||
playerName: string;
|
||||
clientID: ClientID;
|
||||
gameID: GameID;
|
||||
|
||||
@@ -1,62 +1,22 @@
|
||||
import test from "../../resources/cosmetics/cosmetic_pack/test/manifest.json";
|
||||
import {
|
||||
CosmeticManifest,
|
||||
CosmeticManifestSchema,
|
||||
} from "../core/CosmeticSchemas";
|
||||
export function fetchUrl(
|
||||
packId: string | undefined,
|
||||
type: string,
|
||||
): string | undefined {
|
||||
// TODO: Fetches the resource URL from the API server.
|
||||
|
||||
function parseCosmeticManifest(json: unknown): CosmeticManifest {
|
||||
const res = CosmeticManifestSchema.safeParse(json);
|
||||
if (!res.success) {
|
||||
throw new Error(`Invalid CosmeticManifest: ${res.error.message}`);
|
||||
}
|
||||
return res.data;
|
||||
}
|
||||
// Request parameters:
|
||||
// - packKey: identifier of the cosmetic pack
|
||||
// - type: asset type (e.g., "structurePort", "structureCity")
|
||||
// Response:
|
||||
// - URL string pointing to the requested asset
|
||||
|
||||
// Even if this approach changes, this function will be responsible for obtaining the URL by some method.
|
||||
|
||||
function fetchManifest(packId: string): CosmeticManifest | undefined {
|
||||
switch (packId) {
|
||||
case "base":
|
||||
return;
|
||||
case "test":
|
||||
return parseCosmeticManifest(test) as CosmeticManifest;
|
||||
return "/images/test/test.png"; // Example URL for testing
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
export async function resolveCosmeticUrl(
|
||||
packId: string | undefined,
|
||||
key: string | undefined,
|
||||
fallback: string,
|
||||
): Promise<string> {
|
||||
if (packId === undefined || key === undefined) {
|
||||
return fallback;
|
||||
}
|
||||
try {
|
||||
const manifest = fetchManifest(packId);
|
||||
if (!manifest) {
|
||||
return fallback;
|
||||
}
|
||||
// Determine category and subKey from the first "/" only.
|
||||
const firstSlash = key.indexOf("/");
|
||||
if (firstSlash === -1) {
|
||||
return fallback;
|
||||
}
|
||||
const category = key.slice(0, firstSlash);
|
||||
const subKey = key.slice(firstSlash + 1);
|
||||
|
||||
const table = (manifest.assets as Record<string, any>)[category];
|
||||
if (table) {
|
||||
const parts = subKey.split("/");
|
||||
let current: any = table;
|
||||
for (const part of parts) {
|
||||
if (current === null) break;
|
||||
current = current[part];
|
||||
}
|
||||
if (typeof current === "string") {
|
||||
return `/cosmetics/cosmetic_pack/${packId}/${current}`;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn("[cosmetics] manifest load failed", e);
|
||||
}
|
||||
return fallback;
|
||||
}
|
||||
|
||||
+31
-1
@@ -516,7 +516,37 @@ class Client {
|
||||
this.flagInput === null || this.flagInput.getCurrentFlag() === "xx"
|
||||
? ""
|
||||
: this.flagInput.getCurrentFlag(),
|
||||
pack: this.userSettings.getSelectedPackId() ?? undefined,
|
||||
structurePort:
|
||||
this.userSettings.getSelectedStructurePort() ?? undefined,
|
||||
structureCity:
|
||||
this.userSettings.getSelectedStructureCity() ?? undefined,
|
||||
structureFactory:
|
||||
this.userSettings.getSelectedStructureFactory() ?? undefined,
|
||||
structureMissilesilo:
|
||||
this.userSettings.getSelectedStructureMissilesilo() ?? undefined,
|
||||
structureDefensepost:
|
||||
this.userSettings.getSelectedStructureDefensepost() ?? undefined,
|
||||
structureSamlauncher:
|
||||
this.userSettings.getSelectedStructureSamlauncher() ?? undefined,
|
||||
|
||||
spriteTransportship:
|
||||
this.userSettings.getSelectedSpriteTransportship() ?? undefined,
|
||||
spriteWarship:
|
||||
this.userSettings.getSelectedSpriteWarship() ?? undefined,
|
||||
spriteSammissile:
|
||||
this.userSettings.getSelectedSpriteSammissile() ?? undefined,
|
||||
spriteAtombomb:
|
||||
this.userSettings.getSelectedSpriteAtombomb() ?? undefined,
|
||||
spriteHydrogenbomb:
|
||||
this.userSettings.getSelectedSpriteHydrogenbomb() ?? undefined,
|
||||
spriteTradeship:
|
||||
this.userSettings.getSelectedSpriteTradeship() ?? undefined,
|
||||
spriteMirv: this.userSettings.getSelectedSpriteMirv() ?? undefined,
|
||||
spriteEngine: this.userSettings.getSelectedSpriteEngine() ?? undefined,
|
||||
spriteCarriage:
|
||||
this.userSettings.getSelectedSpriteCarriage() ?? undefined,
|
||||
spriteLoadedcarriage:
|
||||
this.userSettings.getSelectedSpriteLoadedcarriage() ?? undefined,
|
||||
playerName: this.usernameInput?.getCurrentUsername() ?? "",
|
||||
token: getPlayToken(),
|
||||
clientID: lobby.clientID,
|
||||
|
||||
@@ -21,6 +21,7 @@ import "./components/baseComponents/Button";
|
||||
import "./components/baseComponents/Modal";
|
||||
import "./components/Difficulties";
|
||||
import "./components/Maps";
|
||||
import { fetchUrl } from "./CosmeticPackLoader";
|
||||
import { fetchCosmetics } from "./Cosmetics";
|
||||
import { FlagInput } from "./FlagInput";
|
||||
import { JoinLobbyEvent } from "./Main";
|
||||
@@ -448,7 +449,6 @@ export class SinglePlayerModal extends LitElement {
|
||||
selectedPattern ??= cosmetics
|
||||
? (this.userSettings.getDevOnlyPattern() ?? null)
|
||||
: null;
|
||||
const selectedPackId = this.userSettings.getSelectedPackId();
|
||||
|
||||
this.dispatchEvent(
|
||||
new CustomEvent("join-lobby", {
|
||||
@@ -467,7 +467,84 @@ export class SinglePlayerModal extends LitElement {
|
||||
? ""
|
||||
: flagInput.getCurrentFlag(),
|
||||
pattern: selectedPattern ?? undefined,
|
||||
pack: selectedPackId ?? undefined,
|
||||
pack: {
|
||||
structurePort: fetchUrl(
|
||||
this.userSettings.getSelectedStructurePort() ?? undefined,
|
||||
"structurePort",
|
||||
),
|
||||
structureCity: fetchUrl(
|
||||
this.userSettings.getSelectedStructureCity() ?? undefined,
|
||||
"structureCity",
|
||||
),
|
||||
structureFactory: fetchUrl(
|
||||
this.userSettings.getSelectedStructureFactory() ??
|
||||
undefined,
|
||||
"structureFactory",
|
||||
),
|
||||
structureMissilesilo: fetchUrl(
|
||||
this.userSettings.getSelectedStructureMissilesilo() ??
|
||||
undefined,
|
||||
"structureMissilesilo",
|
||||
),
|
||||
structureDefensepost: fetchUrl(
|
||||
this.userSettings.getSelectedStructureDefensepost() ??
|
||||
undefined,
|
||||
"structureDefensepost",
|
||||
),
|
||||
structureSamlauncher: fetchUrl(
|
||||
this.userSettings.getSelectedStructureSamlauncher() ??
|
||||
undefined,
|
||||
"structureSamlauncher",
|
||||
),
|
||||
|
||||
spriteTransportship: fetchUrl(
|
||||
this.userSettings.getSelectedSpriteTransportship() ??
|
||||
undefined,
|
||||
"spriteTransportship",
|
||||
),
|
||||
spriteWarship: fetchUrl(
|
||||
this.userSettings.getSelectedSpriteWarship() ?? undefined,
|
||||
"spriteWarship",
|
||||
),
|
||||
spriteSammissile: fetchUrl(
|
||||
this.userSettings.getSelectedSpriteSammissile() ??
|
||||
undefined,
|
||||
"spriteSammissile",
|
||||
),
|
||||
spriteAtombomb: fetchUrl(
|
||||
this.userSettings.getSelectedSpriteAtombomb() ??
|
||||
undefined,
|
||||
"spriteAtombomb",
|
||||
),
|
||||
spriteHydrogenbomb: fetchUrl(
|
||||
this.userSettings.getSelectedSpriteHydrogenbomb() ??
|
||||
undefined,
|
||||
"spriteHydrogenbomb",
|
||||
),
|
||||
spriteTradeship: fetchUrl(
|
||||
this.userSettings.getSelectedSpriteTradeship() ??
|
||||
undefined,
|
||||
"spriteTradeship",
|
||||
),
|
||||
spriteMirv: fetchUrl(
|
||||
this.userSettings.getSelectedSpriteMirv() ?? undefined,
|
||||
"spriteMirv",
|
||||
),
|
||||
spriteEngine: fetchUrl(
|
||||
this.userSettings.getSelectedSpriteEngine() ?? undefined,
|
||||
"spriteEngine",
|
||||
),
|
||||
spriteCarriage: fetchUrl(
|
||||
this.userSettings.getSelectedSpriteCarriage() ??
|
||||
undefined,
|
||||
"spriteCarriage",
|
||||
),
|
||||
spriteLoadedcarriage: fetchUrl(
|
||||
this.userSettings.getSelectedSpriteLoadedcarriage() ??
|
||||
undefined,
|
||||
"spriteLoadedcarriage",
|
||||
),
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
+18
-1
@@ -381,7 +381,24 @@ export class Transport {
|
||||
flag: this.lobbyConfig.flag,
|
||||
patternName: this.lobbyConfig.pattern?.name,
|
||||
patternColorPaletteName: this.lobbyConfig.pattern?.colorPalette?.name,
|
||||
pack: this.lobbyConfig.pack,
|
||||
|
||||
structurePort: this.lobbyConfig.structurePort,
|
||||
structureCity: this.lobbyConfig.structureCity,
|
||||
structureFactory: this.lobbyConfig.structureFactory,
|
||||
structureMissilesilo: this.lobbyConfig.structureMissilesilo,
|
||||
structureDefensepost: this.lobbyConfig.structureDefensepost,
|
||||
structureSamlauncher: this.lobbyConfig.structureSamlauncher,
|
||||
|
||||
spriteTransportship: this.lobbyConfig.spriteTransportship,
|
||||
spriteWarship: this.lobbyConfig.spriteWarship,
|
||||
spriteSammissile: this.lobbyConfig.spriteSammissile,
|
||||
spriteAtombomb: this.lobbyConfig.spriteAtombomb,
|
||||
spriteHydrogenbomb: this.lobbyConfig.spriteHydrogenbomb,
|
||||
spriteTradeship: this.lobbyConfig.spriteTradeship,
|
||||
spriteMirv: this.lobbyConfig.spriteMirv,
|
||||
spriteEngine: this.lobbyConfig.spriteEngine,
|
||||
spriteCarriage: this.lobbyConfig.spriteCarriage,
|
||||
spriteLoadedcarriage: this.lobbyConfig.spriteLoadedcarriage,
|
||||
},
|
||||
} satisfies ClientJoinMessage);
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ import warshipSprite from "../../../resources/sprites/warship.png";
|
||||
import { Theme } from "../../core/configuration/Config";
|
||||
import { TrainType, UnitType } from "../../core/game/Game";
|
||||
import { UnitView } from "../../core/game/GameView";
|
||||
import { resolveCosmeticUrl } from "../CosmeticPackLoader";
|
||||
import { PlayerPack } from "../../core/Schemas";
|
||||
|
||||
// Can't reuse TrainType because "loaded" is not a type, just an attribute
|
||||
const TrainTypeSprite = {
|
||||
@@ -27,25 +27,25 @@ const SPRITE_CONFIG: Partial<
|
||||
Record<UnitType | TrainTypeSprite, { key: string; url: string }>
|
||||
> = {
|
||||
[UnitType.TransportShip]: {
|
||||
key: "sprites/transportship",
|
||||
key: "spriteTransportship",
|
||||
url: transportShipSprite,
|
||||
},
|
||||
[UnitType.Warship]: { key: "sprites/warship", url: warshipSprite },
|
||||
[UnitType.SAMMissile]: { key: "sprites/sammissile", url: samMissileSprite },
|
||||
[UnitType.AtomBomb]: { key: "sprites/atombomb", url: atomBombSprite },
|
||||
[UnitType.Warship]: { key: "spriteWarship", url: warshipSprite },
|
||||
[UnitType.SAMMissile]: { key: "spriteSammissile", url: samMissileSprite },
|
||||
[UnitType.AtomBomb]: { key: "spriteAtombomb", url: atomBombSprite },
|
||||
[UnitType.HydrogenBomb]: {
|
||||
key: "sprites/hydrogenbomb",
|
||||
key: "spriteHydrogenbomb",
|
||||
url: hydrogenBombSprite,
|
||||
},
|
||||
[UnitType.TradeShip]: { key: "sprites/tradeship", url: tradeShipSprite },
|
||||
[UnitType.MIRV]: { key: "sprites/mirv", url: mirvSprite },
|
||||
[TrainTypeSprite.Engine]: { key: "sprites/engine", url: trainEngineSprite },
|
||||
[UnitType.TradeShip]: { key: "spriteTradeship", url: tradeShipSprite },
|
||||
[UnitType.MIRV]: { key: "spriteMirv", url: mirvSprite },
|
||||
[TrainTypeSprite.Engine]: { key: "spriteEngine", url: trainEngineSprite },
|
||||
[TrainTypeSprite.Carriage]: {
|
||||
key: "sprites/carriage",
|
||||
key: "spriteCarriage",
|
||||
url: trainCarriageSprite,
|
||||
},
|
||||
[TrainTypeSprite.LoadedCarriage]: {
|
||||
key: "sprites/loadedcarriage",
|
||||
key: "spriteLoadedcarriage",
|
||||
url: trainLoadedCarriageSprite,
|
||||
},
|
||||
};
|
||||
@@ -53,9 +53,7 @@ const SPRITE_CONFIG: Partial<
|
||||
const spriteMap: Map<UnitType | TrainTypeSprite, ImageBitmap> = new Map();
|
||||
|
||||
// preload all images
|
||||
export const loadAllSprites = async (
|
||||
packId: string | undefined,
|
||||
): Promise<void> => {
|
||||
export const loadAllSprites = async (pack: PlayerPack): Promise<void> => {
|
||||
const entries = Object.entries(SPRITE_CONFIG);
|
||||
const totalSprites = entries.length;
|
||||
let loadedCount = 0;
|
||||
@@ -71,7 +69,8 @@ export const loadAllSprites = async (
|
||||
console.warn(`No sprite url for ${typedUnitType}, skipping...`);
|
||||
return;
|
||||
}
|
||||
const url = await resolveCosmeticUrl(packId, key, fallbackUrl);
|
||||
|
||||
const url = pack?.[key] ?? fallbackUrl;
|
||||
|
||||
try {
|
||||
const img = new Image();
|
||||
|
||||
@@ -11,7 +11,7 @@ import { Cell, UnitType } from "../../../core/game/Game";
|
||||
import { euclDistFN, isometricDistFN } from "../../../core/game/GameMap";
|
||||
import { GameUpdateType } from "../../../core/game/GameUpdates";
|
||||
import { GameView, UnitView } from "../../../core/game/GameView";
|
||||
import { resolveCosmeticUrl } from "../../CosmeticPackLoader";
|
||||
import { PlayerPack } from "../../../core/Schemas";
|
||||
import { TransformHandler } from "../TransformHandler";
|
||||
import { Layer } from "./Layer";
|
||||
|
||||
@@ -25,6 +25,7 @@ const ZOOM_THRESHOLD = 4.3; // below this zoom level, structures are not rendere
|
||||
|
||||
interface UnitRenderConfig {
|
||||
icon: string;
|
||||
key: string;
|
||||
borderRadius: number;
|
||||
territoryRadius: number;
|
||||
}
|
||||
@@ -34,7 +35,7 @@ export class StructureLayer implements Layer {
|
||||
private context: CanvasRenderingContext2D;
|
||||
private unitIcons: Map<string, HTMLImageElement> = new Map();
|
||||
private theme: Theme;
|
||||
private packId: string | undefined;
|
||||
private pack: PlayerPack;
|
||||
private structureLoaded = false;
|
||||
private tempCanvas: HTMLCanvasElement;
|
||||
private tempContext: CanvasRenderingContext2D;
|
||||
@@ -43,31 +44,37 @@ export class StructureLayer implements Layer {
|
||||
private unitConfigs: Partial<Record<UnitType, UnitRenderConfig>> = {
|
||||
[UnitType.Port]: {
|
||||
icon: anchorIcon,
|
||||
key: "structurePort",
|
||||
borderRadius: BASE_BORDER_RADIUS * RADIUS_SCALE_FACTOR,
|
||||
territoryRadius: BASE_TERRITORY_RADIUS * RADIUS_SCALE_FACTOR,
|
||||
},
|
||||
[UnitType.City]: {
|
||||
icon: cityIcon,
|
||||
key: "structureCity",
|
||||
borderRadius: BASE_BORDER_RADIUS * RADIUS_SCALE_FACTOR,
|
||||
territoryRadius: BASE_TERRITORY_RADIUS * RADIUS_SCALE_FACTOR,
|
||||
},
|
||||
[UnitType.Factory]: {
|
||||
icon: factoryIcon,
|
||||
key: "structureFactory",
|
||||
borderRadius: BASE_BORDER_RADIUS * RADIUS_SCALE_FACTOR,
|
||||
territoryRadius: BASE_TERRITORY_RADIUS * RADIUS_SCALE_FACTOR,
|
||||
},
|
||||
[UnitType.MissileSilo]: {
|
||||
icon: missileSiloIcon,
|
||||
key: "structureMissilesilo",
|
||||
borderRadius: BASE_BORDER_RADIUS * RADIUS_SCALE_FACTOR,
|
||||
territoryRadius: BASE_TERRITORY_RADIUS * RADIUS_SCALE_FACTOR,
|
||||
},
|
||||
[UnitType.DefensePost]: {
|
||||
icon: shieldIcon,
|
||||
key: "structureDefensepost",
|
||||
borderRadius: BASE_BORDER_RADIUS * RADIUS_SCALE_FACTOR,
|
||||
territoryRadius: BASE_TERRITORY_RADIUS * RADIUS_SCALE_FACTOR,
|
||||
},
|
||||
[UnitType.SAMLauncher]: {
|
||||
icon: SAMMissileIcon,
|
||||
key: "structureSamlauncher",
|
||||
borderRadius: BASE_BORDER_RADIUS * RADIUS_SCALE_FACTOR,
|
||||
territoryRadius: BASE_TERRITORY_RADIUS * RADIUS_SCALE_FACTOR,
|
||||
},
|
||||
@@ -88,6 +95,7 @@ export class StructureLayer implements Layer {
|
||||
|
||||
private loadIcon(unitType: string, config: UnitRenderConfig) {
|
||||
const image = new Image();
|
||||
console.log(`loading icon for ${unitType} from ${config.icon}`);
|
||||
image.src = config.icon;
|
||||
image.onload = () => {
|
||||
this.unitIcons.set(unitType, image);
|
||||
@@ -101,8 +109,8 @@ export class StructureLayer implements Layer {
|
||||
}
|
||||
|
||||
private async loadIconData() {
|
||||
await this.applyCosmeticIcons();
|
||||
Object.entries(this.unitConfigs).forEach(([unitType, config]) => {
|
||||
config.icon = this.pack?.[config.key] ?? config.icon;
|
||||
this.loadIcon(unitType, config);
|
||||
});
|
||||
}
|
||||
@@ -122,7 +130,7 @@ export class StructureLayer implements Layer {
|
||||
if (!this.structureLoaded) {
|
||||
const myPlayer = this.game.myPlayer();
|
||||
if (myPlayer) {
|
||||
this.packId = myPlayer.cosmetics.pack;
|
||||
this.pack = myPlayer.cosmetics.pack ?? {};
|
||||
this.loadIconData();
|
||||
this.structureLoaded = true;
|
||||
}
|
||||
@@ -133,57 +141,6 @@ export class StructureLayer implements Layer {
|
||||
this.redraw();
|
||||
}
|
||||
|
||||
private async applyCosmeticIcons(): Promise<void> {
|
||||
this.unitConfigs[UnitType.Port] = {
|
||||
...this.unitConfigs[UnitType.Port]!,
|
||||
icon: await resolveCosmeticUrl(
|
||||
this.packId,
|
||||
"structure/img/port",
|
||||
anchorIcon,
|
||||
),
|
||||
};
|
||||
this.unitConfigs[UnitType.City] = {
|
||||
...this.unitConfigs[UnitType.City]!,
|
||||
icon: await resolveCosmeticUrl(
|
||||
this.packId,
|
||||
"structure/img/city",
|
||||
cityIcon,
|
||||
),
|
||||
};
|
||||
this.unitConfigs[UnitType.Factory] = {
|
||||
...this.unitConfigs[UnitType.Factory]!,
|
||||
icon: await resolveCosmeticUrl(
|
||||
this.packId,
|
||||
"structure/img/factory",
|
||||
factoryIcon,
|
||||
),
|
||||
};
|
||||
this.unitConfigs[UnitType.MissileSilo] = {
|
||||
...this.unitConfigs[UnitType.MissileSilo]!,
|
||||
icon: await resolveCosmeticUrl(
|
||||
this.packId,
|
||||
"structure/img/missilesilo",
|
||||
missileSiloIcon,
|
||||
),
|
||||
};
|
||||
this.unitConfigs[UnitType.DefensePost] = {
|
||||
...this.unitConfigs[UnitType.DefensePost]!,
|
||||
icon: await resolveCosmeticUrl(
|
||||
this.packId,
|
||||
"structure/img/defensepost",
|
||||
shieldIcon,
|
||||
),
|
||||
};
|
||||
this.unitConfigs[UnitType.SAMLauncher] = {
|
||||
...this.unitConfigs[UnitType.SAMLauncher]!,
|
||||
icon: await resolveCosmeticUrl(
|
||||
this.packId,
|
||||
"structure/img/samlauncher",
|
||||
SAMMissileIcon,
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
redraw() {
|
||||
console.log("structure layer redrawing");
|
||||
this.canvas = document.createElement("canvas");
|
||||
|
||||
@@ -14,6 +14,7 @@ import { MoveWarshipIntentEvent } from "../../Transport";
|
||||
import { TransformHandler } from "../TransformHandler";
|
||||
import { Layer } from "./Layer";
|
||||
|
||||
import { PlayerPack } from "../../../core/Schemas";
|
||||
import { GameUpdateType } from "../../../core/game/GameUpdates";
|
||||
import {
|
||||
getColoredSprite,
|
||||
@@ -36,7 +37,7 @@ export class UnitLayer implements Layer {
|
||||
private unitToTrail = new Map<UnitView, TileRef[]>();
|
||||
|
||||
private theme: Theme;
|
||||
private packId: string | undefined = undefined;
|
||||
private pack: PlayerPack;
|
||||
private spritesLoaded = false;
|
||||
|
||||
private alternateView = false;
|
||||
@@ -74,8 +75,8 @@ export class UnitLayer implements Layer {
|
||||
if (!this.spritesLoaded) {
|
||||
const myPlayer = this.game.myPlayer();
|
||||
if (myPlayer) {
|
||||
this.packId = myPlayer.cosmetics.pack;
|
||||
loadAllSprites(this.packId);
|
||||
this.pack = myPlayer.cosmetics.pack ?? {};
|
||||
loadAllSprites(this.pack);
|
||||
this.spritesLoaded = true;
|
||||
}
|
||||
}
|
||||
@@ -86,7 +87,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(this.packId);
|
||||
loadAllSprites(this.pack);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+41
-2
@@ -390,7 +390,24 @@ export const PlayerCosmeticRefsSchema = z.object({
|
||||
flag: FlagSchema.optional(),
|
||||
patternName: PatternNameSchema.optional(),
|
||||
patternColorPaletteName: z.string().optional(),
|
||||
pack: z.string().optional(),
|
||||
|
||||
structurePort: z.string().optional(),
|
||||
structureCity: z.string().optional(),
|
||||
structureFactory: z.string().optional(),
|
||||
structureMissilesilo: z.string().optional(),
|
||||
structureDefensepost: z.string().optional(),
|
||||
structureSamlauncher: z.string().optional(),
|
||||
|
||||
spriteTransportship: z.string().optional(),
|
||||
spriteWarship: z.string().optional(),
|
||||
spriteSammissile: z.string().optional(),
|
||||
spriteAtombomb: z.string().optional(),
|
||||
spriteHydrogenbomb: z.string().optional(),
|
||||
spriteTradeship: z.string().optional(),
|
||||
spriteMirv: z.string().optional(),
|
||||
spriteEngine: z.string().optional(),
|
||||
spriteCarriage: z.string().optional(),
|
||||
spriteLoadedcarriage: z.string().optional(),
|
||||
});
|
||||
|
||||
export const PlayerPatternSchema = z.object({
|
||||
@@ -398,10 +415,32 @@ export const PlayerPatternSchema = z.object({
|
||||
patternData: PatternDataSchema,
|
||||
colorPalette: ColorPaletteSchema.optional(),
|
||||
});
|
||||
|
||||
export const PlayerPackSchema = z.object({
|
||||
structurePort: z.string().optional(),
|
||||
structureCity: z.string().optional(),
|
||||
structureFactory: z.string().optional(),
|
||||
structureMissilesilo: z.string().optional(),
|
||||
structureDefensepost: z.string().optional(),
|
||||
structureSamlauncher: z.string().optional(),
|
||||
|
||||
spriteTransportship: z.string().optional(),
|
||||
spriteWarship: z.string().optional(),
|
||||
spriteSammissile: z.string().optional(),
|
||||
spriteAtombomb: z.string().optional(),
|
||||
spriteHydrogenbomb: z.string().optional(),
|
||||
spriteTradeship: z.string().optional(),
|
||||
spriteMirv: z.string().optional(),
|
||||
spriteEngine: z.string().optional(),
|
||||
spriteCarriage: z.string().optional(),
|
||||
spriteLoadedcarriage: z.string().optional(),
|
||||
});
|
||||
export type PlayerPack = z.infer<typeof PlayerPackSchema>;
|
||||
|
||||
export const PlayerCosmeticsSchema = z.object({
|
||||
flag: FlagSchema.optional(),
|
||||
pattern: PlayerPatternSchema.optional(),
|
||||
pack: z.string().optional(),
|
||||
pack: PlayerPackSchema.optional(),
|
||||
});
|
||||
export const PlayerSchema = z.object({
|
||||
clientID: ID,
|
||||
|
||||
@@ -169,8 +169,68 @@ export class UserSettings {
|
||||
}
|
||||
}
|
||||
|
||||
getSelectedPackId(): string | undefined {
|
||||
return localStorage.getItem("cosmeticPackId") ?? undefined;
|
||||
getSelectedStructurePort(): string | undefined {
|
||||
return localStorage.getItem("structurePort") ?? undefined;
|
||||
}
|
||||
|
||||
getSelectedStructureCity(): string | undefined {
|
||||
return localStorage.getItem("structureCity") ?? undefined;
|
||||
}
|
||||
|
||||
getSelectedStructureFactory(): string | undefined {
|
||||
return localStorage.getItem("structureFactory") ?? undefined;
|
||||
}
|
||||
|
||||
getSelectedStructureMissilesilo(): string | undefined {
|
||||
return localStorage.getItem("structureMissilesilo") ?? undefined;
|
||||
}
|
||||
|
||||
getSelectedStructureDefensepost(): string | undefined {
|
||||
return localStorage.getItem("structureDefensepost") ?? undefined;
|
||||
}
|
||||
|
||||
getSelectedStructureSamlauncher(): string | undefined {
|
||||
return localStorage.getItem("structureSamlauncher") ?? undefined;
|
||||
}
|
||||
|
||||
getSelectedSpriteTransportship(): string | undefined {
|
||||
return localStorage.getItem("spriteTransportship") ?? undefined;
|
||||
}
|
||||
|
||||
getSelectedSpriteWarship(): string | undefined {
|
||||
return localStorage.getItem("spriteWarship") ?? undefined;
|
||||
}
|
||||
|
||||
getSelectedSpriteSammissile(): string | undefined {
|
||||
return localStorage.getItem("spriteSammissile") ?? undefined;
|
||||
}
|
||||
|
||||
getSelectedSpriteAtombomb(): string | undefined {
|
||||
return localStorage.getItem("spriteAtombomb") ?? undefined;
|
||||
}
|
||||
|
||||
getSelectedSpriteHydrogenbomb(): string | undefined {
|
||||
return localStorage.getItem("spriteHydrogenbomb") ?? undefined;
|
||||
}
|
||||
|
||||
getSelectedSpriteTradeship(): string | undefined {
|
||||
return localStorage.getItem("spriteTradeship") ?? undefined;
|
||||
}
|
||||
|
||||
getSelectedSpriteMirv(): string | undefined {
|
||||
return localStorage.getItem("spriteMirv") ?? undefined;
|
||||
}
|
||||
|
||||
getSelectedSpriteEngine(): string | undefined {
|
||||
return localStorage.getItem("spriteEngine") ?? undefined;
|
||||
}
|
||||
|
||||
getSelectedSpriteCarriage(): string | undefined {
|
||||
return localStorage.getItem("spriteCarriage") ?? undefined;
|
||||
}
|
||||
|
||||
getSelectedSpriteLoadedcarriage(): string | undefined {
|
||||
return localStorage.getItem("spriteLoadedcarriage") ?? undefined;
|
||||
}
|
||||
|
||||
backgroundMusicVolume(): number {
|
||||
|
||||
+46
-1
@@ -7,6 +7,7 @@ import path from "path";
|
||||
import { fileURLToPath } from "url";
|
||||
import { WebSocket, WebSocketServer } from "ws";
|
||||
import { z } from "zod";
|
||||
import { fetchUrl } from "../client/CosmeticPackLoader";
|
||||
import { getServerConfigFromServer } from "../core/configuration/ConfigLoader";
|
||||
import { GameType } from "../core/game/Game";
|
||||
import {
|
||||
@@ -485,12 +486,56 @@ export async function startWorker() {
|
||||
}
|
||||
}
|
||||
|
||||
// Temporary full assignment (unless there’s a better approach).
|
||||
const pack = {
|
||||
structurePort: fetchUrl(cosmetics.structurePort, "structurePort"),
|
||||
structureCity: fetchUrl(cosmetics.structureCity, "structureCity"),
|
||||
structureFactory: fetchUrl(
|
||||
cosmetics.structureFactory,
|
||||
"structureFactory",
|
||||
),
|
||||
structureMissilesilo: fetchUrl(
|
||||
cosmetics.structureMissilesilo,
|
||||
"structureMissilesilo",
|
||||
),
|
||||
structureDefensepost: fetchUrl(
|
||||
cosmetics.structureDefensepost,
|
||||
"structureDefensepost",
|
||||
),
|
||||
structureSamlauncher: fetchUrl(
|
||||
cosmetics.structureSamlauncher,
|
||||
"structureSamlauncher",
|
||||
),
|
||||
spriteTransportship: fetchUrl(
|
||||
cosmetics.spriteTransportship,
|
||||
"spriteTransportship",
|
||||
),
|
||||
spriteWarship: fetchUrl(cosmetics.spriteWarship, "spriteWarship"),
|
||||
spriteSammissile: fetchUrl(
|
||||
cosmetics.spriteSammissile,
|
||||
"spriteSammissile",
|
||||
),
|
||||
spriteAtombomb: fetchUrl(cosmetics.spriteAtombomb, "spriteAtombomb"),
|
||||
spriteHydrogenbomb: fetchUrl(
|
||||
cosmetics.spriteHydrogenbomb,
|
||||
"spriteHydrogenbomb",
|
||||
),
|
||||
spriteTradeship: fetchUrl(cosmetics.spriteTradeship, "spriteTradeship"),
|
||||
spriteMirv: fetchUrl(cosmetics.spriteMirv, "spriteMirv"),
|
||||
spriteEngine: fetchUrl(cosmetics.spriteEngine, "spriteEngine"),
|
||||
spriteCarriage: fetchUrl(cosmetics.spriteCarriage, "spriteCarriage"),
|
||||
spriteLoadedcarriage: fetchUrl(
|
||||
cosmetics.spriteLoadedcarriage,
|
||||
"spriteLoadedcarriage",
|
||||
),
|
||||
};
|
||||
|
||||
return {
|
||||
perm: "allowed",
|
||||
cosmetics: {
|
||||
flag: cosmetics.flag,
|
||||
pattern: pattern,
|
||||
pack: cosmetics.pack,
|
||||
pack: pack,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user