Merge branch 'main' into ue

This commit is contained in:
tresabhi committed 2026-06-10 13:11:59 -05:00
commit 173c476fb4
12 files changed
+240 -110

No files matched your search

+18 -8
View File
@@ -58,12 +58,14 @@ export function Guesser() {
const [results, setResults] = useState<TankDefinition[] | null>(null);
const [selected, setSelected] = useState<TankDefinition | null>(null);
const tiers = Guess.use((state) => state.tiers);
const status = useRef<HTMLSpanElement>(null);
const requestSearch = useCallback(() => {
setSelected(null);
setSearching(true);
search();
}, []);
const search = useCallback(
debounce(() => {
if (!input.current) return;
@@ -92,6 +94,20 @@ export function Guesser() {
if (guessState !== GuessState.NotGuessed) setSelected(null);
}, [guessState]);
useEffect(() => {
const interval = setInterval(() => {
if (!status.current) return;
status.current.innerText = literals(strings.website.tools.guess.stats, {
correct: correctGuesses,
total: totalGuesses,
streak: streak,
});
}, 1000 / 200);
return () => clearInterval(interval);
}, [correctGuesses, totalGuesses, streak]);
return (
<Flex
direction="column"
@@ -158,13 +174,7 @@ export function Guesser() {
</Box>
<Flex justify="center" style={{ userSelect: "none" }}>
<Text>
{literals(strings.website.tools.guess.stats, {
correct: correctGuesses,
total: totalGuesses,
streak: streak,
})}
</Text>
<Text ref={status} />
</Flex>
<Flex gap={{ initial: "2", sm: "3" }}>
@@ -312,7 +322,7 @@ export function Guesser() {
? GuessState.Correct
: GuessState.Incorrect;
draft.totalGuesses++;
draft.correctGuesses += correct ? 1 : 0;
draft.correctGuesses += correct && draft.tiers.length === 10 ? 1 : 0;
draft.streak = correct ? draft.streak + 1 : 0;
});
} else {
@@ -70,37 +70,6 @@ export function Equalizer() {
<Switch checked={equalize} />
</Flex>
</Box>
<Popover.Root>
<Popover.Trigger>
<Text style={{ cursor: "pointer" }} size="2" color="gray">
<Flex align="center" gap="2">
Brought to you by{" "}
<img
src="/assets/images/third-party/wotb-news.png"
style={{
width: "1rem",
height: "1rem",
objectFit: "cover",
borderRadius: "50%",
}}
/>{" "}
WoTB News <InfoCircledIcon />
</Flex>
</Text>
</Popover.Trigger>
<Popover.Content>
<Text>
This feature was brought to you early, ahead of the release of the
game mode, thanks to{" "}
<Link href="https://discord.gg/WHdER7ZPAD" target="_blank">
WoTB News
</Link>
.
</Text>
</Popover.Content>
</Popover.Root>
</ConfigurationChildWrapper>
);
}
@@ -18,6 +18,7 @@ import {
Heading,
IconButton,
Text,
Tooltip,
} from "@radix-ui/themes";
import { awaitableTankDefinitions } from "../../../../core/awaitables/tankDefinitions";
import { useLocale } from "../../../../hooks/useLocale";
@@ -55,12 +56,14 @@ function ModuleButton({
selected,
unlock,
top,
tooltip,
onClick,
}: {
unlock: Unlock;
tier: number;
selected: boolean;
top: boolean;
tooltip?: string;
onClick: () => void;
}) {
const isTank = unlock.type === ModuleType.MODULE_TYPE_VEHICLE;
@@ -134,7 +137,7 @@ function ModuleButton({
</IconButton>
);
return isTank ? (
const node = isTank ? (
<LinkI18n
locale={locale}
href={`/tanks/${tankDefinitions.tanks[unlock.id].slug}`}
@@ -144,6 +147,10 @@ function ModuleButton({
) : (
button
);
if (!tooltip) return node;
return <Tooltip content={tooltip}>{node}</Tooltip>;
}
const tankDefinitions = await awaitableTankDefinitions;
@@ -167,7 +174,7 @@ export function Modules() {
const topGun = topTurret.guns.at(-1)!;
const topEngine = tank.engines.at(-1)!;
const topTrack = tank.tracks.at(-1)!;
const { strings } = useLocale();
const { strings, unwrap } = useLocale();
function setByUnlock(unlock: Unlock) {
Duel.mutate((draft) => {
@@ -249,6 +256,8 @@ export function Modules() {
if (module === undefined) return null;
const tooltip = unwrap(module.name!);
return (
<Flex
key={unlock.id}
@@ -301,6 +310,7 @@ export function Modules() {
<ModuleButton
unlock={unlock}
tier={extractModule(module).tier}
tooltip={tooltip}
selected={
(unlock.type === ModuleType.MODULE_TYPE_TURRET
? turret.id
+15 -19
View File
@@ -1,23 +1,19 @@
import { asset } from '@blitzkit/core';
import { type ObjectMap, useLoader } from '@react-three/fiber';
import { type GLTF, GLTFLoader } from 'three-stdlib';
const cache: Record<
number,
{ gltf: GLTF & ObjectMap; hasDynamicArmor: boolean }
> = {};
import { asset } from "@blitzkit/core";
import { useLoader } from "@react-three/fiber";
import { GLTFLoader } from "three-stdlib";
import { useDispose } from "./useDispose";
export function useArmor(id: number) {
const gltf = useLoader(GLTFLoader, asset(`3d/tanks/armor/${id}.glb`));
const path = asset(`3d/tanks/armor/${id}.glb`);
const gltf = useLoader(GLTFLoader, path);
if (!cache[id]) {
cache[id] = {
gltf,
hasDynamicArmor: Object.values(gltf.nodes).some(
(node) =>
node.name.includes('state_00') || node.name.includes('state_01'),
),
};
}
return cache[id];
useDispose(gltf, path);
return {
gltf,
hasDynamicArmor: Object.values(gltf.nodes).some(
(node) =>
node.name.includes("state_00") || node.name.includes("state_01"),
),
};
}
+50
View File
@@ -0,0 +1,50 @@
import { useLoader, type ObjectMap } from "@react-three/fiber";
import { useEffect } from "react";
import { Cache, Group, Mesh, MeshStandardMaterial, Object3D } from "three";
import { GLTFLoader, type GLTF } from "three-stdlib";
export function useDispose(gltf: GLTF & ObjectMap, path: string) {
useEffect(() => {
return () => {
gltf.scene.traverse((object) => {
if (object instanceof Mesh) {
if (object.material instanceof MeshStandardMaterial) {
const maps = [
object.material.map,
object.material.aoMap,
object.material.envMap,
object.material.bumpMap,
object.material.alphaMap,
object.material.lightMap,
object.material.normalMap,
object.material.emissiveMap,
object.material.roughnessMap,
object.material.metalnessMap,
object.material.displacementMap,
];
for (const map of maps) {
if (!map) continue;
map.source.data.close();
map.dispose();
}
object.material.dispose();
} else {
throw new TypeError(
`Unexpected material type: ${object.material.type}`,
);
}
} else if (object instanceof Group || object instanceof Object3D) {
// traverse will get children
} else {
throw new TypeError(`Unexpected object type: ${object}`);
}
});
useLoader.clear(GLTFLoader, path);
Cache.remove(path);
};
}, [gltf, path]);
}
+15 -23
View File
@@ -1,30 +1,22 @@
import { asset } from "@blitzkit/core";
import { type ObjectMap, useLoader } from "@react-three/fiber";
import { useLoader } from "@react-three/fiber";
import { Mesh, MeshStandardMaterial } from "three";
import { type GLTF, GLTFLoader } from "three-stdlib";
const cache: Record<
number,
{
gltf: GLTF & ObjectMap;
hasPbr: boolean;
}
> = {};
import { GLTFLoader } from "three-stdlib";
import { useDispose } from "./useDispose";
export function useModel(id: number) {
const gltf = useLoader(GLTFLoader, asset(`3d/tanks/models/${id}.glb`));
const path = asset(`3d/tanks/models/${id}.glb`);
const gltf = useLoader(GLTFLoader, path);
if (!cache[id]) {
cache[id] = {
gltf,
hasPbr: Object.values(gltf.nodes).some(
(node) =>
node instanceof Mesh &&
node.material instanceof MeshStandardMaterial &&
node.material.roughnessMap !== null
),
};
}
useDispose(gltf, path);
return cache[id];
return {
gltf,
hasPbr: Object.values(gltf.nodes).some(
(node) =>
node instanceof Mesh &&
node.material instanceof MeshStandardMaterial &&
node.material.roughnessMap !== null,
),
};
}