From 7605e1d6f24c483fd85e988e029b766fe0a800ec Mon Sep 17 00:00:00 2001 From: tresabhi <43380238+tresabhi@users.noreply.github.com> Date: Fri, 21 Mar 2025 19:30:37 -0500 Subject: [PATCH] feat: new tab --- packages/i18n/strings/en.json | 4 + .../components/Armor/components/Dissector.tsx | 17 ++++ .../components/DissectorSceneComponent.tsx | 89 +++++++++++++++++++ .../Armor/components/StaticArmor.tsx | 53 ++--------- ...ents.tsx => StaticArmorSceneComponent.tsx} | 8 +- .../HeroSection/components/Options/index.tsx | 9 ++ .../TankSandbox/components/Lighting.tsx | 3 +- .../components/TankSandbox/index.tsx | 5 +- .../website/src/stores/tankopediaEphemeral.ts | 2 +- .../stores/tankopediaPersistent/constants.ts | 1 + 10 files changed, 136 insertions(+), 55 deletions(-) create mode 100644 packages/website/src/components/Armor/components/Dissector.tsx create mode 100644 packages/website/src/components/Armor/components/DissectorSceneComponent.tsx rename packages/website/src/components/Armor/components/{StaticArmorSceneComponents.tsx => StaticArmorSceneComponent.tsx} (94%) diff --git a/packages/i18n/strings/en.json b/packages/i18n/strings/en.json index 6b4d23528..6dfbe5b1c 100644 --- a/packages/i18n/strings/en.json +++ b/packages/i18n/strings/en.json @@ -855,6 +855,10 @@ "tank_seo_description": "%s1 armor, statistics, equipment, provisions, and more. %s2 DPM, %s3hp alpha, %s4mm penetration, %s5kph top speed, %s6hp health.", "sandbox": { + "dissector": { + "name": "Dissector" + }, + "poses": { "hull_down": "Hull down", "face_hug": "Face hug", diff --git a/packages/website/src/components/Armor/components/Dissector.tsx b/packages/website/src/components/Armor/components/Dissector.tsx new file mode 100644 index 000000000..f7a49a326 --- /dev/null +++ b/packages/website/src/components/Armor/components/Dissector.tsx @@ -0,0 +1,17 @@ +import { memo } from 'react'; +import { DissectorSceneComponent } from './DissectorSceneComponent'; + +export const Dissector = memo(() => { + return ( + + + + + + + + + + + ); +}); diff --git a/packages/website/src/components/Armor/components/DissectorSceneComponent.tsx b/packages/website/src/components/Armor/components/DissectorSceneComponent.tsx new file mode 100644 index 000000000..c55386ca2 --- /dev/null +++ b/packages/website/src/components/Armor/components/DissectorSceneComponent.tsx @@ -0,0 +1,89 @@ +import { asset } from '@blitzkit/core'; +import { useGLTF } from '@react-three/drei'; +import { + Color, + DoubleSide, + LineBasicMaterial, + Material, + MeshStandardMaterial, +} from 'three'; +import { jsxTree } from '../../../core/blitzkit/jsxTree'; +import { Duel } from '../../../stores/duel'; +import { TankopediaEphemeral } from '../../../stores/tankopediaEphemeral'; +import { groupNameRegex } from './StaticArmorSceneComponent'; + +interface DissectorSceneComponentProps { + group: string; +} + +const armorColor = new Color().multiplyScalar(1 / 16); + +const moduleColor: Record = { + Armor: armorColor, + ArmorScreen: armorColor, + + Commander: new Color('white'), + Driver: new Color('white'), + Gunner1: new Color('white'), + Loader1: new Color('white'), + + SurveyingDevice: new Color('purple'), + Radio: new Color('indigo'), + Gun: new Color('pink'), + FuelTank: new Color('yellow'), + Engine: new Color('orange'), + AmmoBay: new Color('gold'), + LeftTrack: new Color('green'), + RightTrack: new Color('green'), + TurretRotator: new Color('blue'), + Transmission: new Color('cyan'), +}; +const moduleOutlineColor: Record = {}; + +for (const key in moduleColor) { + moduleOutlineColor[key] = moduleColor[key].clone().multiplyScalar(4); +} + +export function DissectorSceneComponent({ + group, +}: DissectorSceneComponentProps) { + const tank = Duel.use((state) => state.protagonist.tank); + const gltf = useGLTF(asset(`tanks/${tank.id}/collision/${group}.glb`)); + const armor = TankopediaEphemeral.use((state) => state.armor); + const groupName = group.match(groupNameRegex)![1]; + const groupArmor = armor.groups[groupName]; + + return jsxTree(gltf.scene, { + mesh(mesh, props) { + if (!(mesh.material instanceof Material)) { + return null; + } + + const armorName = mesh.material.name; + const armorPlate = groupArmor.armors[armorName]; + + if (!(armorPlate.type in moduleColor)) { + throw new TypeError(`Unhandled armor type: ${armorPlate.type}`); + } + + const material = new MeshStandardMaterial({ + side: DoubleSide, + color: moduleColor[armorPlate.type], + }); + const outlineMaterial = new LineBasicMaterial({ + side: DoubleSide, + color: moduleOutlineColor[armorPlate.type], + }); + + return ( + <> + + + + + + + ); + }, + }); +} diff --git a/packages/website/src/components/Armor/components/StaticArmor.tsx b/packages/website/src/components/Armor/components/StaticArmor.tsx index 3191e7023..a31ba44fd 100644 --- a/packages/website/src/components/Armor/components/StaticArmor.tsx +++ b/packages/website/src/components/Armor/components/StaticArmor.tsx @@ -1,62 +1,19 @@ import { memo } from 'react'; -import { StaticArmorSceneComponents } from './StaticArmorSceneComponents'; +import { StaticArmorSceneComponent } from './StaticArmorSceneComponent'; export interface ThicknessRange { value: number; } export const StaticArmor = memo(() => { - // const wrapper = useRef(null); - // const turretContainer = useRef(null); - // const gunContainer = useRef(null); - // const protagonist = Duel.use((draft) => draft.protagonist); - // const tank = Duel.use((state) => state.protagonist.tank); - // const track = Duel.use((state) => state.protagonist.track); - // const turret = Duel.use((state) => state.protagonist.turret); - // const gun = Duel.use((state) => state.protagonist.gun); - // const { gltf: armorGltf } = useArmor(tank.id); - // const { gltf: modelGltf } = useModel(tank.id); - // const armorNodes = Object.values(armorGltf.nodes); - // const modelNodes = Object.values(modelGltf.nodes); - // const tankModelDefinition = useTankModelDefinition(); - // const trackModelDefinition = tankModelDefinition.tracks[track.id]; - // const turretModelDefinition = tankModelDefinition.turrets[turret.id]; - // const gunModelDefinition = - // turretModelDefinition.guns[gun.gun_type!.value.base.id]; - // const hullOrigin = correctZYTuple(trackModelDefinition.origin); - // const turretOrigin = correctZYTuple(tankModelDefinition.turret_origin); - // const gunOrigin = correctZYTuple(turretModelDefinition.gun_origin); - // const mutateDuel = Duel.useMutation(); - // const canvas = useThree((state) => state.gl.domElement); - // const mutateTankopediaEphemeral = TankopediaEphemeral.useMutation(); - // const duelStore = Duel.useStore(); - // const maskOrigin = - // gunModelDefinition.mask === undefined - // ? undefined - // : gunModelDefinition.mask + hullOrigin.y + turretOrigin.y + gunOrigin.y; - // const showPrimaryArmor = TankopediaPersistent.use( - // (state) => state.showPrimaryArmor, - // ); - // const showSpacedArmor = TankopediaPersistent.use( - // (state) => state.showSpacedArmor, - // ); - // const showExternalModules = TankopediaPersistent.use( - // (state) => state.showExternalModules, - // ); - // const isDynamicArmorActive = Duel.use((state) => - // state.protagonist.consumables.includes(73), - // ); - - // useTankTransform(track, turret, turretContainer, gunContainer); - return ( - - + + - + - + diff --git a/packages/website/src/components/Armor/components/StaticArmorSceneComponents.tsx b/packages/website/src/components/Armor/components/StaticArmorSceneComponent.tsx similarity index 94% rename from packages/website/src/components/Armor/components/StaticArmorSceneComponents.tsx rename to packages/website/src/components/Armor/components/StaticArmorSceneComponent.tsx index 801880fed..69c2857b3 100644 --- a/packages/website/src/components/Armor/components/StaticArmorSceneComponents.tsx +++ b/packages/website/src/components/Armor/components/StaticArmorSceneComponent.tsx @@ -12,16 +12,16 @@ import { Duel } from '../../../stores/duel'; import { TankopediaEphemeral } from '../../../stores/tankopediaEphemeral'; import { TankopediaPersistent } from '../../../stores/tankopediaPersistent'; -interface StaticArmorSceneComponentsProps { +interface StaticArmorSceneComponentsProp { group: string; } const moduleColor = new Color(192 / 255, 192 / 255, 192 / 255); -const groupNameRegex = /([a-z]+)(_\d+)?/; +export const groupNameRegex = /([a-z]+)(_\d+)?/; -export function StaticArmorSceneComponents({ +export function StaticArmorSceneComponent({ group, -}: StaticArmorSceneComponentsProps) { +}: StaticArmorSceneComponentsProp) { const tank = Duel.use((state) => state.protagonist.tank); const showModules = TankopediaPersistent.use((state) => state.showModules); const showArmorScreen = TankopediaPersistent.use( diff --git a/packages/website/src/components/Tankopedia/HeroSection/components/Options/index.tsx b/packages/website/src/components/Tankopedia/HeroSection/components/Options/index.tsx index 191fe44e7..fef2ad1ef 100644 --- a/packages/website/src/components/Tankopedia/HeroSection/components/Options/index.tsx +++ b/packages/website/src/components/Tankopedia/HeroSection/components/Options/index.tsx @@ -395,6 +395,15 @@ export function Options({ canvas }: OptionsProps) { + + + + + + + {/* diff --git a/packages/website/src/components/Tankopedia/HeroSection/components/TankSandbox/components/Lighting.tsx b/packages/website/src/components/Tankopedia/HeroSection/components/TankSandbox/components/Lighting.tsx index a5bf78aa3..3cf039cf8 100644 --- a/packages/website/src/components/Tankopedia/HeroSection/components/TankSandbox/components/Lighting.tsx +++ b/packages/website/src/components/Tankopedia/HeroSection/components/TankSandbox/components/Lighting.tsx @@ -20,7 +20,8 @@ export function Lighting() { environmentRotation={new Euler(0, degToRad(180), 0)} /> )} - {display === TankopediaDisplay.StaticArmor && ( + {(display === TankopediaDisplay.StaticArmor || + display === TankopediaDisplay.Dissector) && ( )} {display === TankopediaDisplay.ShootingRange && ( diff --git a/packages/website/src/components/Tankopedia/HeroSection/components/TankSandbox/index.tsx b/packages/website/src/components/Tankopedia/HeroSection/components/TankSandbox/index.tsx index e411c98a0..ebfc6f23e 100644 --- a/packages/website/src/components/Tankopedia/HeroSection/components/TankSandbox/index.tsx +++ b/packages/website/src/components/Tankopedia/HeroSection/components/TankSandbox/index.tsx @@ -1,12 +1,14 @@ import { BLITZKIT_TANK_ICON_SIZE } from '@blitzkit/core'; import { Canvas } from '@react-three/fiber'; import { forwardRef, Suspense, useImperativeHandle, useRef } from 'react'; +import { Plane, Vector3 } from 'three'; import { useOnScreen } from '../../../../../hooks/useOnScreen'; import { TankopediaEphemeral } from '../../../../../stores/tankopediaEphemeral'; import { TankopediaPersistent } from '../../../../../stores/tankopediaPersistent'; import { TankopediaDisplay } from '../../../../../stores/tankopediaPersistent/constants'; import { Armor } from '../../../../Armor'; import { ArmorPlateDisplay } from '../../../../Armor/components/ArmorPlateDisplay'; +import { Dissector } from '../../../../Armor/components/Dissector'; import { ShotDisplay } from '../../../../Armor/components/ShotDisplay'; import { StaticArmor } from '../../../../Armor/components/StaticArmor'; import { AutoClear } from './components/AutoClear'; @@ -158,7 +160,7 @@ export const TankSandbox = forwardRef( : 'never' } gl={{ - clippingPlanes: [], + clippingPlanes: [new Plane(new Vector3(0, 0, 1))], localClippingEnabled: true, preserveDrawingBuffer: true, }} @@ -190,6 +192,7 @@ export const TankSandbox = forwardRef( }> {display === TankopediaDisplay.DynamicArmor && } {display === TankopediaDisplay.StaticArmor && } + {display === TankopediaDisplay.Dissector && } diff --git a/packages/website/src/stores/tankopediaEphemeral.ts b/packages/website/src/stores/tankopediaEphemeral.ts index 671301f0e..2e9af2b75 100644 --- a/packages/website/src/stores/tankopediaEphemeral.ts +++ b/packages/website/src/stores/tankopediaEphemeral.ts @@ -137,7 +137,7 @@ export const TankopediaEphemeral = createContextualStore( armor, controlsEnabled: true, xpMultiplier: 1, - display: TankopediaDisplay.StaticArmor, + display: TankopediaDisplay.Dissector, })), ); }, diff --git a/packages/website/src/stores/tankopediaPersistent/constants.ts b/packages/website/src/stores/tankopediaPersistent/constants.ts index 49bc4bda1..ba770de86 100644 --- a/packages/website/src/stores/tankopediaPersistent/constants.ts +++ b/packages/website/src/stores/tankopediaPersistent/constants.ts @@ -37,5 +37,6 @@ export enum TankopediaDisplay { Model, DynamicArmor, StaticArmor, + Dissector, ShootingRange, }