Compare commits

...
3 Commits
Author SHA1 Message Date
TrèsAbhi fd6b69edc1 fix: missing tank icon handling 2026-04-18 00:30:21 -05:00
TrèsAbhi 2504833a29 fix: optimize async cache 2026-04-17 23:52:33 -05:00
TrèsAbhi 6d31dcb74b fix: styles of home page 2026-04-17 23:35:56 -05:00
10 changed files with 54 additions and 38 deletions

No files matched your search

-10
View File
@@ -1,10 +0,0 @@
{
"folders": [
{
"path": ".",
},
{
"path": "C:/Program Files/WindowsApps/7458BE2C.WorldofTanksBlitz_11.1.256.0_x64__x4tje2y229k00/Data",
},
],
}
+14 -13
View File
@@ -4,6 +4,7 @@ using CUE4Parse.UE4.Assets.Exports.Texture;
using CUE4Parse.UE4.Objects.Engine;
using CUE4Parse.UE4.Objects.UObject;
using Microsoft.JavaScript.NodeApi;
using SkiaSharp;
namespace BlitzKit.Game.JSExport;
@@ -44,20 +45,20 @@ public class GameInterface
if (provider.TryLoadPackageObject<UPrimaryDataAsset>(path, out var pda))
{
try
FSoftObjectPath objectPath = pda.Get<FSoftObjectPath>("BigIcon");
UTexture2D uTexture = objectPath.Load<UTexture2D>();
CTexture? cTexture = uTexture.Decode(ETexturePlatform.DesktopMobile);
if (cTexture is null)
{
return pda.Get<FSoftObjectPath>("BigIcon")
.Load<UTexture2D>()
.Decode(ETexturePlatform.DesktopMobile)!
.ToSkBitmap()
.Encode(SkiaSharp.SKEncodedImageFormat.Webp, 80)
.ToArray();
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
continue;
}
SKBitmap bitmap = cTexture.ToSkBitmap();
SKData data = bitmap.Encode(SKEncodedImageFormat.Webp, 80);
byte[] bytes = data.ToArray();
return bytes;
}
else
{
@@ -65,6 +66,6 @@ public class GameInterface
}
}
throw new FileNotFoundException($"Tank {tankId}/{pdaName} not found in any nation");
return [];
}
}
+3
View File
@@ -0,0 +1,3 @@
<Solution>
<Project Path="game.csproj" />
</Solution>
@@ -1,8 +1,8 @@
import type { PopularTank } from "@protos/blitzkit/popular_tanks";
import { api } from "../../core/api/dynamic";
import { useAwait } from "../../hooks/useAwait";
import { useGameStrings } from "../../hooks/useGameStrings";
import { useLocale } from "../../hooks/useLocale";
import type { PopularTank } from "../../protos/popular_tanks";
import { LinkI18n } from "../LinkI18n";
import { Text } from "../Text";
import styles from "./index.module.css";
@@ -1,6 +1,5 @@
.text {
font-size: var(--font-size-regular);
color: var(--gray-12);
&[data-size="minor"] {
font-size: var(--font-size-minor);
@@ -21,6 +21,13 @@ export function Text({
color = "gray",
...props
}: TextProps) {
const scale = color === "gray" && lowContrast ? "white" : color;
let power: string | number = 12;
if (lowContrast) {
power = color === "gray" ? "a9" : 11;
}
return (
<span
className={classNames(styles.text, className)}
@@ -28,7 +35,9 @@ export function Text({
data-size={size}
data-weight={weight}
data-align={align === "left" ? undefined : align}
style={{ color: `var(--${color}-${lowContrast ? 10 : 12})` }}
style={{
color: `var(--${scale}-${power})`,
}}
{...props}
/>
);
@@ -20,6 +20,7 @@ const toolStrings = strings.tools[tool.id as keyof typeof strings.tools];
<style>
.tool-card {
display: flex;
flex-direction: column;
height: 10rem;
position: relative;
+22 -8
View File
@@ -64,7 +64,7 @@ export abstract class AbstractAPI {
export function Cache<Arguments extends unknown[]>(
discriminator: (...args: Arguments) => string = (...args) => args.join("-"),
) {
const cache = new WeakMap<object, Map<string, unknown>>();
const cache = new WeakMap<object, Map<string, Promise<unknown>>>();
return function (
_target: unknown,
@@ -73,18 +73,32 @@ export function Cache<Arguments extends unknown[]>(
) {
const original = descriptor.value;
descriptor.value = async function (...args: Arguments) {
descriptor.value = function (...args: Arguments) {
const key = discriminator(...args);
const thisCache = cache.get(this) ?? new Map<string, unknown>();
if (!cache.has(this)) cache.set(this, thisCache);
if (thisCache.has(key)) return thisCache.get(key);
let thisCache = cache.get(this);
const result = await original.apply(this, args);
if (!thisCache) {
thisCache = new Map();
cache.set(this, thisCache);
}
thisCache.set(key, result);
if (thisCache.has(key)) {
return thisCache.get(key);
}
return result;
const promise = (async () => {
try {
return await original.apply(this, args);
} catch (error) {
thisCache!.delete(key);
throw error;
}
})();
thisCache.set(key, promise);
return promise;
};
};
}
@@ -243,10 +243,6 @@ export class ServerAPI extends AbstractAPI {
strings[key] = parsed[key].replaceAll('\\"', '"');
}
console.log(
namespaceStrings["ProfileAvatarEntity__1_ct_legendary__DisplayName"],
);
Object.assign(strings, namespaceStrings);
}
} catch (error) {
@@ -7,5 +7,8 @@ export { getStaticPaths } from "./[id].pb";
export async function GET({ params }: APIContext<never, { id: string }>) {
const tank = await api.tank(params.id);
const image = game.tankBigIcon(params.id, tank.tank!.visual_data);
if (image.length === 0) return new Response(null, { status: 404 });
return new Response(new Uint8Array(image));
}