Compare commits

...
3 Commits
Author SHA1 Message Date
tresabhi 746c7963de add website build 2026-05-24 12:59:42 -05:00
tresabhi ae96ae34c0 move media to /media 2026-05-24 12:55:30 -05:00
tresabhi 1f690d11c7 equipment icons 2026-05-24 12:42:08 -05:00
46 changed files with 115 additions and 43 deletions

No files matched your search

+1 -1
View File
@@ -31,7 +31,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
chunk: [pages, api]
chunk: [pages, api, media]
steps:
- name: Checkout
+2 -1
View File
@@ -6,7 +6,8 @@
"scripts": {
"setup": "chmod a+x scripts/*.sh && ./scripts/setup.sh",
"dev": "./scripts/dev.sh",
"build-game": "./scripts/build_game.sh"
"build-game": "./scripts/build_game.sh",
"build-website": "./scripts/build_website.sh"
},
"type": "module",
"workspaces": [
+6 -24
View File
@@ -22,7 +22,7 @@ public partial class GameInterface
public HashSet<string> files;
public string[] tanksDirectoryNations;
public GameInterface(string directory, string map)
public GameInterface(string directory, string map, string temp)
{
provider = new(directory, map);
@@ -39,8 +39,8 @@ public partial class GameInterface
.Distinct(),
];
string oodlePath = "temp/oodle.so";
OodleHelper.DownloadOodleDll(ref oodlePath);
string oodlePath = $"{temp}/oodle.so";
OodleHelper.DownloadOodleDll(ref oodlePath!);
OodleHelper.Initialize(oodlePath);
}
@@ -157,27 +157,9 @@ public partial class GameInterface
return [];
}
var path = $"{candidate}.{Path.GetFileNameWithoutExtension(candidate)}";
var pda = provider.PDA(candidate);
var icon = pda.Get<FSoftObjectPath>("Icon");
if (provider.TryLoadPackageObject<UPrimaryDataAsset>(path, out var pda))
{
var icon = pda.Get<FSoftObjectPath>("Icon");
var uTexture = icon.Load<UTexture2D>();
var cTexture = uTexture.Decode(ETexturePlatform.DesktopMobile);
if (cTexture is null)
{
Console.WriteLine($"Could not extract icon for {path}");
return [];
}
var bitmap = cTexture.ToSkBitmap();
var data = bitmap.Encode(SKEncodedImageFormat.Webp, 80);
return data.ToArray();
}
Console.WriteLine($"Could not load {path} as pda");
return [];
return provider.Image(icon);
}
}
+33
View File
@@ -1,10 +1,15 @@
using System.Runtime.InteropServices;
using CUE4Parse_Conversion.Textures;
using CUE4Parse.Compression;
using CUE4Parse.FileProvider;
using CUE4Parse.MappingsProvider;
using CUE4Parse.UE4.Assets.Exports.Texture;
using CUE4Parse.UE4.Exceptions;
using CUE4Parse.UE4.Objects.Engine;
using CUE4Parse.UE4.Objects.UObject;
using CUE4Parse.UE4.Versions;
using CUE4Parse.Utils;
using SkiaSharp;
namespace BlitzKit.Game.Models;
@@ -23,4 +28,32 @@ public class BlitzFileProvider : DefaultFileProvider
Initialize();
Mount();
}
public UPrimaryDataAsset PDA(string path)
{
var name = Path.GetFileNameWithoutExtension(path);
var combined = $"{path}.{name}";
return LoadPackageObject<UPrimaryDataAsset>(combined);
}
public byte[] Image(FSoftObjectPath path)
{
var uTexture = path.Load<UTexture2D>();
return Image(uTexture);
}
private readonly SKEncodedImageFormat imageFormat = SKEncodedImageFormat.Webp;
private readonly int imageQuality = 80;
public byte[] Image(UTexture2D uTexture)
{
var cTexture = uTexture.Decode(ETexturePlatform.DesktopMobile);
ArgumentNullException.ThrowIfNull(cTexture);
var bitmap = cTexture.ToSkBitmap();
var data = bitmap.Encode(imageFormat, imageQuality);
return data.ToArray();
}
}
+4 -4
View File
@@ -2,10 +2,10 @@
"name": "@blitzkit/website-ue",
"type": "module",
"scripts": {
"dev": "PUBLIC_TARGET=web astro dev",
"build": "PUBLIC_TARGET=web astro build",
"preview": "PUBLIC_TARGET=web astro preview",
"lint": "PUBLIC_TARGET=web astro check",
"dev": "astro dev",
"build": "astro build",
"preview": "astro preview",
"lint": "astro check",
"astro": "astro"
},
"dependencies": {
@@ -40,14 +40,14 @@ function PriceEntry({ entry }: PriceEntryProps) {
<>
{entry.currency_price && (
<PriceInternal
icon={`/api/currencies/${entry.currency_price.currency_catalog_id}.webp`}
icon={`/media/currencies/${entry.currency_price.currency_catalog_id}.webp`}
value={entry.currency_price.amount}
/>
)}
{entry.stuff_price && (
<PriceInternal
icon={`/api/stuff/${entry.stuff_price.stuff_catalog_id}.webp`}
icon={`/media/stuff/${entry.stuff_price.stuff_catalog_id}.webp`}
value={entry.stuff_price.amount}
/>
)}
@@ -12,7 +12,6 @@ import {
import { chunk } from "lodash-es";
import { useMemo } from "react";
import { equipmentColumns } from "../../config/equipment";
import { catImages } from "../../config/images";
import {
alternativeLines,
isAlternativeLine,
@@ -148,6 +147,10 @@ function EquipmentOption({
columnIndex,
}: EquipmentOptionProps) {
const equipmentIndex = rowIndex * equipmentColumns + columnIndex;
const tank = useProtagonist();
const equipment = useEquipment(tank.tank!);
const slot = equipment.preset.slots[equipmentIndex];
const id = slot.options_catalog_i_ds[optionIndex];
const isSelected = Tankopedia.use(
(state) =>
@@ -172,7 +175,7 @@ function EquipmentOption({
});
}}
>
<img src={catImages.squareTransparent} />
<img src={`/media/equipment/${id}.webp`} />
</Button>
);
}
@@ -422,7 +425,7 @@ function LineElement({ index, lineName, stage }: LineElementProps) {
>
<img
className={styles.icon}
src={`/api/tanks/modules/${stage.stage_type}.webp`}
src={`/media/modules/${stage.stage_type}.webp`}
/>
{/* {stage.display_name} */}
+5 -1
View File
@@ -6,7 +6,11 @@ let _game: GameInterface | null = null;
if (!clientUnmounted) {
const { GameInterface } = await import("@blitzkit/game");
_game = new GameInterface(assertSecret(import.meta.env.PUBLIC_WOTB_CLIENT));
_game = new GameInterface(
assertSecret(import.meta.env.PUBLIC_WOTB_CLIENT),
assertSecret(import.meta.env.WOTB_USMAP),
"../../temp",
);
}
export const game = _game;
@@ -0,0 +1,7 @@
import type { GetStaticPaths } from "astro";
import { isChunkEnabled } from "../../astro/isChunkEnabled";
export const getStaticPaths = (() => {
if (!isChunkEnabled("media")) return [];
return [{ params: { media: "media" } }];
}) satisfies GetStaticPaths;
@@ -2,7 +2,7 @@ import type { APIContext } from "astro";
import { api } from "../../../api/dynamic";
import { imageProxy } from "../../../api/imageProxy";
export { getStaticPaths } from "./[id].json";
export { getStaticPaths } from "../../[api]/avatars/[id].json";
/**
* Returns an avatar image based on its `id` in the `webp` format.
@@ -2,7 +2,7 @@ import type { APIContext } from "astro";
import { api } from "../../../api/dynamic";
import { imageProxy } from "../../../api/imageProxy";
export { getStaticPaths } from "./[id].json";
export { getStaticPaths } from "../../[api]/backgrounds/[id].json";
export async function GET({ params }: APIContext<never, { id: string }>) {
const background = await api.background(params.id);
@@ -0,0 +1,40 @@
import type { APIContext } from "astro";
import { api } from "../../../api/dynamic";
import { notFoundResponse } from "../../../api/responses";
import { mixStaticPaths } from "../../../astro/mixStaticPaths";
import { game } from "../../../game/game";
import { getStaticPaths as _getStaticPaths } from "../_index";
export const getStaticPaths = mixStaticPaths(_getStaticPaths, () => {
return api.metadata
.group("EquipmentEntity")
.map(({ id }) => ({ params: { id } }));
});
const HACK_nameMap: Record<string, string> = {
SystemsFineTuning: "SystemFineTuning",
};
export function GET({ params }: APIContext<never, { id: string }>) {
const item = api.metadata.item(params.id);
const assetDiscovery = item.BlitzStaticAssetsDiscovery();
const names = assetDiscovery.required_tags!.tags.map(
(tag) => tag.value.split(".").at(-1)!,
);
for (const name of names) {
if (name in HACK_nameMap) {
names.push(HACK_nameMap[name]);
}
}
const icon = game!.equipmentIcon(names);
if (icon.length === 0) {
return notFoundResponse;
}
const array = new Uint8Array(icon);
return new Response(array);
}
@@ -1,13 +1,13 @@
import type { APIContext } from "astro";
import { api } from "../../../api/dynamic";
import { api } from "../../../../api/dynamic";
import {
clientUnmountedResponse,
notFoundResponse,
} from "../../../api/responses";
import { game } from "../../../game/game";
import { clientUnmounted } from "../../../game/unmounted";
} from "../../../../api/responses";
import { game } from "../../../../game/game";
import { clientUnmounted } from "../../../../game/unmounted";
export { getStaticPaths } from "./[id].json";
export { getStaticPaths } from "../../../[api]/tanks/[id].json";
export async function GET({ params }: APIContext<never, { id: string }>) {
if (clientUnmounted) return clientUnmountedResponse;
+2
View File
@@ -0,0 +1,2 @@
cd packages/website-ue
bun run build