diff --git a/packages/website/src/components/Armor/components/PrimaryArmorScene.tsx b/packages/website/src/components/Armor/components/PrimaryArmorScene.tsx index 09cef062f..bc8dd87df 100644 --- a/packages/website/src/components/Armor/components/PrimaryArmorScene.tsx +++ b/packages/website/src/components/Armor/components/PrimaryArmorScene.tsx @@ -14,7 +14,7 @@ export const PrimaryArmorScene = memo(() => { const wrapper = useRef(null); const turretContainer = useRef(null); const gunContainer = useRef(null); - const protagonist = Duel.use((draft) => draft.protagonist); + // 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); @@ -33,7 +33,7 @@ export const PrimaryArmorScene = memo(() => { state.protagonist.consumables.includes(73), ); - useTankTransform(protagonist, turretContainer, gunContainer); + useTankTransform(track, turret, turretContainer, gunContainer); return ( diff --git a/packages/website/src/components/Armor/components/PrimaryArmorSceneComponent/index.tsx b/packages/website/src/components/Armor/components/PrimaryArmorSceneComponent/index.tsx index b78ecaf0e..c3f1dfbf2 100644 --- a/packages/website/src/components/Armor/components/PrimaryArmorSceneComponent/index.tsx +++ b/packages/website/src/components/Armor/components/PrimaryArmorSceneComponent/index.tsx @@ -78,15 +78,18 @@ export function PrimaryArmorSceneComponent({ await handleProtagonistEquipmentChange(duel.protagonist.equipmentMatrix); await handleAntagonistEquipmentChange(duel.antagonist.equipmentMatrix); + + // console.log('handleShellChange'); + invalidate(); } function handleGreenPenetrationChange(greenPenetration: boolean) { material.uniforms.greenPenetration.value = greenPenetration; - invalidate(); } function handleOpaqueChange(opaque: boolean) { material.uniforms.opaque.value = opaque; - invalidate(); + + // invalidate(); } function handleWireframeChange(wireframe: boolean) { material.wireframe = wireframe; @@ -104,7 +107,7 @@ export function PrimaryArmorSceneComponent({ ? thickness * 1.03 : thickness; - invalidate(); + // invalidate(); } async function handleAntagonistEquipmentChange(equipment: EquipmentMatrix) { const duel = duelStore.getState(); @@ -173,7 +176,7 @@ export function PrimaryArmorSceneComponent({ material.uniforms.inverseProjectionMatrix.value = camera.projectionMatrixInverse; - invalidate(); + // invalidate(); }); return ( diff --git a/packages/website/src/components/Armor/components/ShotDisplay.tsx b/packages/website/src/components/Armor/components/ShotDisplay.tsx index 859b7bc6d..4674f5560 100644 --- a/packages/website/src/components/Armor/components/ShotDisplay.tsx +++ b/packages/website/src/components/Armor/components/ShotDisplay.tsx @@ -1,7 +1,7 @@ import { J_HAT, K_HAT } from '@blitzkit/core'; import { Box, Flex, Text } from '@radix-ui/themes'; import { Html } from '@react-three/drei'; -import { invalidate, useFrame } from '@react-three/fiber'; +import { useFrame } from '@react-three/fiber'; import { clamp } from 'lodash-es'; import { useEffect, useRef, type ComponentProps } from 'react'; import { @@ -105,7 +105,7 @@ export function ShotDisplay() { outTracer.current.position.set(0, tracerT2 * outLength, 0); } - invalidate(); + // invalidate(); } if ( @@ -122,7 +122,7 @@ export function ShotDisplay() { splashRadiusWrapper.current.scale.set(scale, scale, scale); splashRadiusMaterial.current.opacity = opacity; - invalidate(); + // invalidate(); } }); diff --git a/packages/website/src/components/Armor/components/SpacedArmorScene.tsx b/packages/website/src/components/Armor/components/SpacedArmorScene.tsx index a12fa42fa..b3a84d454 100644 --- a/packages/website/src/components/Armor/components/SpacedArmorScene.tsx +++ b/packages/website/src/components/Armor/components/SpacedArmorScene.tsx @@ -25,7 +25,6 @@ export const SpacedArmorScene = memo(({ scene }) => { 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); @@ -50,7 +49,7 @@ export const SpacedArmorScene = memo(({ scene }) => { state.protagonist.consumables.includes(73), ); - useTankTransform(protagonist, turretContainer, gunContainer); + useTankTransform(track, turret, turretContainer, gunContainer); return ( diff --git a/packages/website/src/components/Armor/components/SpacedArmorSceneComponent/components/SpacedArmorSubExternal/index.tsx b/packages/website/src/components/Armor/components/SpacedArmorSceneComponent/components/SpacedArmorSubExternal/index.tsx index 4d4a162eb..34f19bcb4 100644 --- a/packages/website/src/components/Armor/components/SpacedArmorSceneComponent/components/SpacedArmorSubExternal/index.tsx +++ b/packages/website/src/components/Armor/components/SpacedArmorSceneComponent/components/SpacedArmorSubExternal/index.tsx @@ -1,5 +1,4 @@ import { resolvePenetrationCoefficient } from '@blitzkit/core'; -import { invalidate } from '@react-three/fiber'; import { useEffect } from 'react'; import { AdditiveBlending, @@ -54,7 +53,7 @@ export function SpacedArmorSubExternal({ const tankopediaEphemeral = tankopediaEphemeralStore.getState(); const shell = tankopediaEphemeral.customShell ?? duel.antagonist.shell; material.uniforms.penetration.value = shell.penetration.near; - invalidate(); + // invalidate(); } async function handleProtagonistEquipmentChange( equipment: EquipmentMatrix, @@ -69,7 +68,7 @@ export function SpacedArmorSubExternal({ ? thickness * 1.03 : thickness; - invalidate(); + // invalidate(); } async function handleAntagonistEquipmentChange(equipment: EquipmentMatrix) { const duel = duelStore.getState(); @@ -86,7 +85,7 @@ export function SpacedArmorSubExternal({ penetration * resolvePenetrationCoefficient(hasCalibratedShells, shell.type); - invalidate(); + // invalidate(); } handleShellChange(); diff --git a/packages/website/src/components/Armor/components/SpacedArmorSceneComponent/components/SpacedArmorSubSpaced/index.tsx b/packages/website/src/components/Armor/components/SpacedArmorSceneComponent/components/SpacedArmorSubSpaced/index.tsx index 0dbba9c45..7d5561cc1 100644 --- a/packages/website/src/components/Armor/components/SpacedArmorSceneComponent/components/SpacedArmorSubSpaced/index.tsx +++ b/packages/website/src/components/Armor/components/SpacedArmorSceneComponent/components/SpacedArmorSubSpaced/index.tsx @@ -1,5 +1,4 @@ import { isExplosive, resolvePenetrationCoefficient } from '@blitzkit/core'; -import { invalidate } from '@react-three/fiber'; import { useEffect } from 'react'; import { AdditiveBlending, @@ -65,7 +64,7 @@ export function SpacedArmorSubSpaced({ shell.normalization ?? 0, ); - invalidate(); + // invalidate(); } async function handleProtagonistEquipmentChange( equipment: EquipmentMatrix, @@ -80,7 +79,7 @@ export function SpacedArmorSubSpaced({ ? thickness * 1.03 : thickness; - invalidate(); + // invalidate(); } async function handleAntagonistEquipmentChange(equipment: EquipmentMatrix) { const duel = duelStore.getState(); @@ -96,8 +95,6 @@ export function SpacedArmorSubSpaced({ material.uniforms.penetration.value = penetration * resolvePenetrationCoefficient(hasCalibratedShells, shell.type); - - invalidate(); } handleShellChange(); diff --git a/packages/website/src/components/Armor/components/StaticArmor.tsx b/packages/website/src/components/Armor/components/StaticArmor.tsx index ef3711adb..08675a521 100644 --- a/packages/website/src/components/Armor/components/StaticArmor.tsx +++ b/packages/website/src/components/Armor/components/StaticArmor.tsx @@ -69,7 +69,7 @@ export const StaticArmor = memo(({ thicknessRange }) => { state.protagonist.consumables.includes(73), ); - useTankTransform(protagonist, turretContainer, gunContainer); + useTankTransform(track, turret, turretContainer, gunContainer); return ( diff --git a/packages/website/src/components/Tankopedia/HeroSection/components/Options/components/CustomShellButton.tsx b/packages/website/src/components/Tankopedia/HeroSection/components/Options/components/CustomShellButton.tsx index be8c5c946..9721ef0f9 100644 --- a/packages/website/src/components/Tankopedia/HeroSection/components/Options/components/CustomShellButton.tsx +++ b/packages/website/src/components/Tankopedia/HeroSection/components/Options/components/CustomShellButton.tsx @@ -9,6 +9,7 @@ import { Text, TextField, } from '@radix-ui/themes'; +import { throttle } from 'lodash-es'; import { type ChangeEvent } from 'react'; import { Duel } from '../../../../../../stores/duel'; import { TankopediaEphemeral } from '../../../../../../stores/tankopediaEphemeral'; @@ -154,7 +155,13 @@ export function CustomShellButton() { Normalization - + {customShell.normalization ?? 0}° @@ -162,11 +169,13 @@ export function CustomShellButton() { min={0} max={90} value={[customShell.normalization ?? 0]} - onValueChange={([value]) => { + onValueChange={throttle(([value]) => { + console.log('asd'); + mutateTankopediaEphemeral((draft) => { draft.customShell!.normalization = value; }); - }} + }, 1000)} /> @@ -180,11 +189,11 @@ export function CustomShellButton() { min={0} max={90} value={[customShell.ricochet ?? 90]} - onValueChange={([value]) => { + onValueChange={throttle(([value]) => { mutateTankopediaEphemeral((draft) => { draft.customShell!.ricochet = value; }); - }} + }, 1000)} /> diff --git a/packages/website/src/components/Tankopedia/HeroSection/components/Options/components/DynamicArmorSwitcher.tsx b/packages/website/src/components/Tankopedia/HeroSection/components/Options/components/DynamicArmorSwitcher.tsx index 6c571bcc7..b64c216c4 100644 --- a/packages/website/src/components/Tankopedia/HeroSection/components/Options/components/DynamicArmorSwitcher.tsx +++ b/packages/website/src/components/Tankopedia/HeroSection/components/Options/components/DynamicArmorSwitcher.tsx @@ -1,6 +1,5 @@ import { asset } from '@blitzkit/core'; import { IconButton } from '@radix-ui/themes'; -import { invalidate } from '@react-three/fiber'; import { useArmor } from '../../../../../../hooks/useArmor'; import { Duel } from '../../../../../../stores/duel'; import { TankopediaEphemeral } from '../../../../../../stores/tankopediaEphemeral'; @@ -22,7 +21,7 @@ export function DynamicArmorSwitcher() { variant="soft" size={{ initial: '2', sm: '3' }} onClick={() => { - invalidate(); + // invalidate(); mutateDuel((draft) => { if (draft.protagonist.consumables.includes(73)) { draft.protagonist.consumables = 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 1e3b52ad1..f27650112 100644 --- a/packages/website/src/components/Tankopedia/HeroSection/components/Options/index.tsx +++ b/packages/website/src/components/Tankopedia/HeroSection/components/Options/index.tsx @@ -26,7 +26,6 @@ import { Text, Tooltip, } from '@radix-ui/themes'; -import { invalidate } from '@react-three/fiber'; import { useState, type RefObject } from 'react'; import { ENVIRONMENTS } from '../../../../../constants/lightingEnvironments'; import { Pose, poseEvent } from '../../../../../core/blitzkit/pose'; @@ -202,7 +201,7 @@ export function Options({ thicknessRange, canvas }: OptionsProps) { size={{ initial: '2', sm: '3' }} radius="none" onClick={() => { - invalidate(); + // invalidate(); mutateDuel((draft) => { draft.antagonist.shell = thisShell; }); @@ -240,7 +239,7 @@ export function Options({ thicknessRange, canvas }: OptionsProps) { size={{ initial: '2', sm: '3' }} radius="none" onClick={() => { - invalidate(); + // invalidate(); mutateDuel((draft) => { draft.antagonist.equipmentMatrix[0][0] = hasCalibratedShells ? 0 @@ -266,7 +265,7 @@ export function Options({ thicknessRange, canvas }: OptionsProps) { size={{ initial: '2', sm: '3' }} radius="none" onClick={() => { - invalidate(); + // invalidate(); mutateDuel((draft) => { draft.protagonist.equipmentMatrix[1][1] = hasEnhancedArmor ? 0 diff --git a/packages/website/src/components/Tankopedia/HeroSection/components/TankSandbox/components/TankModel.tsx b/packages/website/src/components/Tankopedia/HeroSection/components/TankSandbox/components/TankModel.tsx index dc8f1c64b..b3a9619a5 100644 --- a/packages/website/src/components/Tankopedia/HeroSection/components/TankSandbox/components/TankModel.tsx +++ b/packages/website/src/components/Tankopedia/HeroSection/components/TankSandbox/components/TankModel.tsx @@ -1,5 +1,5 @@ import { normalizeAngleRad } from '@blitzkit/core'; -import { invalidate, useThree, type ThreeEvent } from '@react-three/fiber'; +import { useThree, type ThreeEvent } from '@react-three/fiber'; import { memo, useRef } from 'react'; import { Group, Mesh, MeshStandardMaterial, Vector2 } from 'three'; import { applyPitchYawLimits } from '../../../../../../core/blitz/applyPitchYawLimits'; @@ -20,6 +20,8 @@ export const TankModel = memo(() => { const duelStore = Duel.useStore(); const protagonist = Duel.use((draft) => draft.protagonist); const tankopediaPersistentStore = TankopediaPersistent.useStore(); + const track = Duel.use((state) => state.protagonist.track); + const turret = Duel.use((state) => state.protagonist.turret); const canvas = useThree((state) => state.gl.domElement); const hullContainer = useRef(null); const turretContainer = useRef(null); @@ -33,7 +35,7 @@ export const TankModel = memo(() => { const { gltf } = useModel(protagonist.tank.id); const nodes = Object.values(gltf.nodes); - useTankTransform(protagonist, turretContainer, gunContainer); + useTankTransform(track, turret, turretContainer, gunContainer); return ( @@ -53,7 +55,7 @@ export const TankModel = memo(() => { if (!material) return; - invalidate(); + // invalidate(); if (material.map) material.map.offset.y += offset; if (material.aoMap) material.aoMap.offset.y += offset; diff --git a/packages/website/src/core/blitzkit/modelTransform.ts b/packages/website/src/core/blitzkit/modelTransform.ts index 7966a499a..94fdca87b 100644 --- a/packages/website/src/core/blitzkit/modelTransform.ts +++ b/packages/website/src/core/blitzkit/modelTransform.ts @@ -1,5 +1,4 @@ import { EventManager } from '@blitzkit/core'; -import { invalidate } from '@react-three/fiber'; export interface ModelTransformEventData { yaw?: number; @@ -7,4 +6,6 @@ export interface ModelTransformEventData { } export const modelTransformEvent = new EventManager(); -modelTransformEvent.on(() => invalidate()); +modelTransformEvent.on(() => { + // invalidate(); +}); diff --git a/packages/website/src/hooks/useTankTransform.ts b/packages/website/src/hooks/useTankTransform.ts index 1e40c2f4a..cb296ea6b 100644 --- a/packages/website/src/hooks/useTankTransform.ts +++ b/packages/website/src/hooks/useTankTransform.ts @@ -1,26 +1,30 @@ -import { I_HAT, J_HAT, K_HAT } from '@blitzkit/core'; +import { + I_HAT, + J_HAT, + K_HAT, + TrackDefinition, + TurretDefinition, +} from '@blitzkit/core'; import { type RefObject, useEffect } from 'react'; import { Euler, Group, Vector3 } from 'three'; import { degToRad } from 'three/src/math/MathUtils.js'; import { correctZYTuple } from '../core/blitz/correctZYTuple'; -import { - type ModelTransformEventData, - modelTransformEvent, -} from '../core/blitzkit/modelTransform'; -import type { DuelMember } from '../stores/duel'; +import { modelTransformEvent } from '../core/blitzkit/modelTransform'; +import { Duel } from '../stores/duel'; import { useTankModelDefinition } from './useTankModelDefinition'; export function useTankTransform( - member: DuelMember, + track: TrackDefinition, + turret: TurretDefinition, turretContainer: RefObject, gunContainer: RefObject, ) { const tankModelDefinition = useTankModelDefinition(); + const duelStore = Duel.useStore(); useEffect(() => { - const trackModelDefinition = tankModelDefinition.tracks[member.track.id]; - const turretModelDefinition = tankModelDefinition.turrets[member.turret.id]; - + const trackModelDefinition = tankModelDefinition.tracks[track.id]; + const turretModelDefinition = tankModelDefinition.turrets[turret.id]; const hullOrigin = correctZYTuple(trackModelDefinition.origin); const turretOrigin = correctZYTuple(tankModelDefinition.turret_origin); const gunOrigin = correctZYTuple(turretModelDefinition.gun_origin); @@ -29,7 +33,8 @@ export function useTankTransform( const gunPosition = new Vector3(); const gunRotation = new Euler(); - function handleModelTransform({ yaw, pitch }: ModelTransformEventData) { + function handleModelTransform() { + const { yaw, pitch } = duelStore.getState().protagonist; gunPosition .set(0, 0, 0) .sub(hullOrigin) @@ -77,11 +82,24 @@ export function useTankTransform( turretContainer.current?.rotation.copy(turretRotation); } - handleModelTransform(member); + handleModelTransform(); + modelTransformEvent.on(handleModelTransform); + const unsubscribes = [ + duelStore.subscribe( + (state) => state.protagonist.pitch, + handleModelTransform, + ), + duelStore.subscribe( + (state) => state.protagonist.yaw, + handleModelTransform, + ), + () => modelTransformEvent.off(handleModelTransform), + ]; + return () => { - modelTransformEvent.off(handleModelTransform); + unsubscribes.forEach((unsubscribe) => unsubscribe()); }; - }, [member]); + }, [track, turret]); }