mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-21 10:47:04 +02:00
small tank icons
This commit is contained in:
1 parent
be0804ae59
commit
9968b2c83d
4 files changed
+58
-26
No files matched your search
@@ -1,6 +1,5 @@
|
|||||||
import { asset } from '@blitzkit/core';
|
import { GenericTankComponentButton } from "./GenericTankComponentButton";
|
||||||
import { GenericTankComponentButton } from './GenericTankComponentButton';
|
import type { TankComponentButtonProps } from "./TankComponentButton";
|
||||||
import type { TankComponentButtonProps } from './TankComponentButton';
|
|
||||||
|
|
||||||
interface ModuleProps extends TankComponentButtonProps {
|
interface ModuleProps extends TankComponentButtonProps {
|
||||||
module: string;
|
module: string;
|
||||||
@@ -9,11 +8,11 @@ interface ModuleProps extends TankComponentButtonProps {
|
|||||||
export function ModuleButton({ module, ...props }: ModuleProps) {
|
export function ModuleButton({ module, ...props }: ModuleProps) {
|
||||||
return (
|
return (
|
||||||
<GenericTankComponentButton
|
<GenericTankComponentButton
|
||||||
icon={asset(`icons/modules/${module}.webp`)}
|
icon={`/api/icons/modules/${module}.webp`}
|
||||||
iconStyles={{
|
iconStyles={{
|
||||||
top: '50%',
|
top: "50%",
|
||||||
left: '50%',
|
left: "50%",
|
||||||
transform: 'translate(calc(-50% + 2px), calc(-50% + 2px))',
|
transform: "translate(calc(-50% + 2px), calc(-50% + 2px))",
|
||||||
}}
|
}}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
import { asset } from '@blitzkit/core';
|
|
||||||
|
|
||||||
interface SmallTankIconProps {
|
interface SmallTankIconProps {
|
||||||
id: number;
|
id: number;
|
||||||
size?: number;
|
size?: number;
|
||||||
@@ -13,16 +11,16 @@ export function SmallTankIcon({ id, size = HEIGHT }: SmallTankIconProps) {
|
|||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
height: size,
|
height: size,
|
||||||
overflow: 'hidden',
|
overflow: "hidden",
|
||||||
width: WIDTH * (size / HEIGHT),
|
width: WIDTH * (size / HEIGHT),
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
alt={`Tank ${id}`}
|
alt={`Tank ${id}`}
|
||||||
src={asset(`icons/tanks/small/${id}.webp`)}
|
src={`/tanks/${id}/icons/small.webp`}
|
||||||
style={{
|
style={{
|
||||||
transform: `scale(${(size / HEIGHT) * 100}%)`,
|
transform: `scale(${(size / HEIGHT) * 100}%)`,
|
||||||
transformOrigin: 'top left',
|
transformOrigin: "top left",
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -36,40 +36,32 @@ export async function GET({ props }: APIContext<{ id: number }>) {
|
|||||||
const bigPath = `Data/${parameters.resourcesPath.bigIconPath
|
const bigPath = `Data/${parameters.resourcesPath.bigIconPath
|
||||||
.replace(/~res:\//, "")
|
.replace(/~res:\//, "")
|
||||||
.replace(/\..+/, "")}.packed.webp`;
|
.replace(/\..+/, "")}.packed.webp`;
|
||||||
const big = await extractPackedTankIcon(
|
const big = await extractPackedTankIcon(await vfs.file(bigPath));
|
||||||
await vfs.file(bigPath),
|
|
||||||
`tank ${tankKey} big`,
|
|
||||||
);
|
|
||||||
|
|
||||||
return new Response(big);
|
return new Response(big);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function extractPackedTankIcon(
|
export async function extractPackedTankIcon(bytes: Uint8Array) {
|
||||||
bytes: Uint8Array,
|
|
||||||
context: string,
|
|
||||||
) {
|
|
||||||
const texture = sharp(bytes);
|
const texture = sharp(bytes);
|
||||||
const spriteRect = parsePackedSpriteRect(bytes);
|
const spriteRect = parsePackedSpriteRect(bytes);
|
||||||
|
|
||||||
if (!spriteRect) {
|
if (!spriteRect) {
|
||||||
throw new Error(`Missing RIFF sprite bounds for ${context}`);
|
throw new Error(`Missing RIFF sprite bounds`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const [left, top, width, height] = spriteRect;
|
const [left, top, width, height] = spriteRect;
|
||||||
const bounds = [left, top, width, height];
|
const bounds = [left, top, width, height];
|
||||||
|
|
||||||
if (!bounds.every(Number.isInteger)) {
|
if (!bounds.every(Number.isInteger)) {
|
||||||
throw new Error(
|
throw new Error(`Invalid RIFF sprite bounds: ${bounds.join(" ")}`);
|
||||||
`Invalid RIFF sprite bounds for ${context}: ${bounds.join(" ")}`,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const metadata = await texture.metadata();
|
const metadata = await texture.metadata();
|
||||||
|
|
||||||
if (metadata.width === undefined || metadata.height === undefined) {
|
if (metadata.width === undefined || metadata.height === undefined) {
|
||||||
throw new Error(`Failed to read image dimensions for ${context}`);
|
throw new Error(`Failed to read image dimensions`);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
@@ -81,7 +73,7 @@ export async function extractPackedTankIcon(
|
|||||||
top + height > metadata.height
|
top + height > metadata.height
|
||||||
) {
|
) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Out-of-bounds RIFF sprite for ${context}: ${bounds.join(" ")} in ${metadata.width}x${metadata.height}`,
|
`Out-of-bounds RIFF sprite: ${bounds.join(" ")} in ${metadata.width}x${metadata.height}`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
import {
|
||||||
|
NATION_IDS,
|
||||||
|
type TankParameters,
|
||||||
|
type VehicleDefinitionList,
|
||||||
|
} from "@blitzkit/core";
|
||||||
|
import type { APIContext } from "astro";
|
||||||
|
import { vfs } from "../../../../../core/blitzkit/vfs";
|
||||||
|
import { extractPackedTankIcon } from "./big.webp";
|
||||||
|
|
||||||
|
export { getStaticPaths } from "../_index";
|
||||||
|
|
||||||
|
export async function GET({ props }: APIContext<{ id: number }>) {
|
||||||
|
const nations = await vfs
|
||||||
|
.dir(`Data/XML/item_defs/vehicles`)
|
||||||
|
.then((files) => files.filter((nation) => nation !== "common"));
|
||||||
|
|
||||||
|
for (const nation of nations) {
|
||||||
|
const tanks = await vfs.xml<{ root: VehicleDefinitionList }>(
|
||||||
|
`Data/XML/item_defs/vehicles/${nation}/list.xml`,
|
||||||
|
);
|
||||||
|
|
||||||
|
for (const tankKey in tanks.root) {
|
||||||
|
const tank = tanks.root[tankKey];
|
||||||
|
|
||||||
|
if (tankKey.includes("tutorial_bot")) continue;
|
||||||
|
|
||||||
|
const nationVehicleId = tank.id;
|
||||||
|
const id = (nationVehicleId << 8) + (NATION_IDS[nation] << 4) + 1;
|
||||||
|
|
||||||
|
if (id !== props.id) continue;
|
||||||
|
|
||||||
|
const parameters = await vfs.yaml<TankParameters>(
|
||||||
|
`Data/3d/Tanks/Parameters/${nation}/${tankKey}.yaml`,
|
||||||
|
);
|
||||||
|
const bigPath = `Data/${parameters.resourcesPath.smallIconPath
|
||||||
|
.replace(/~res:\//, "")
|
||||||
|
.replace(/\..+/, "")}.packed.webp`;
|
||||||
|
const big = await extractPackedTankIcon(await vfs.file(bigPath));
|
||||||
|
|
||||||
|
return new Response(big);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in new issue
Block a user