From 332c1787f4bf017eeb5152eef2c258f59609ce82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Tue, 9 Jul 2024 20:35:36 -0500 Subject: [PATCH] feat: migrated duel store --- .../components/Consumables.tsx | 9 ++--- .../Characteristics/components/Equipment.tsx | 7 ++-- .../components/Miscellaneous.tsx | 11 +++--- .../Characteristics/components/Modules.tsx | 13 +++---- .../Characteristics/components/Provisions.tsx | 7 ++-- .../[id]/components/Characteristics/index.tsx | 15 ++++---- .../tankopedia/[id]/components/Control.tsx | 9 ++--- .../[id]/components/HistorySection.tsx | 4 +-- .../tankopedia/[id]/components/Lighting.tsx | 4 +-- .../[id]/components/Model/HeroSection.tsx | 6 ++-- .../[id]/components/Model/TankSandbox.tsx | 5 +-- .../[id]/components/Model/TechTreeSection.tsx | 4 +-- .../components/Model/components/Options.tsx | 11 +++--- .../components/Model/components/TankModel.tsx | 10 +++--- .../[id]/components/QuickInputs/index.tsx | 5 +-- .../tankopedia/[id]/components/Title.tsx | 21 +++++++---- .../[id]/components/VideoSection.tsx | 4 +-- src/app/tools/tankopedia/[id]/page.tsx | 36 ++++++++----------- src/app/tools/tankopedia/layout.tsx | 13 ++++--- .../Armor/components/CoreArmorScene.tsx | 12 +++---- .../CoreArmorSceneComponent/index.tsx | 30 +++++++++------- .../Armor/components/SpacedArmorScene.tsx | 12 +++---- .../SpacedArmorSubExternal/index.tsx | 28 +++++++++------ .../components/SpacedArmorSubSpaced/index.tsx | 30 +++++++++------- .../SpacedArmorSceneComponent/index.tsx | 5 +-- src/core/blitzkit/assignDuelMember.ts | 26 -------------- src/core/zustand/createNextSafeStore.tsx | 22 ++++++++++-- src/hooks/useEccentricity.ts | 4 +-- src/hooks/useEquipment.ts | 6 ++-- src/hooks/useProvision.ts | 4 +-- src/stores/duel/index.ts | 35 +++++++++++------- src/themes/mint.ts | 6 ---- 32 files changed, 223 insertions(+), 191 deletions(-) delete mode 100644 src/core/blitzkit/assignDuelMember.ts delete mode 100644 src/themes/mint.ts diff --git a/src/app/tools/tankopedia/[id]/components/Characteristics/components/Consumables.tsx b/src/app/tools/tankopedia/[id]/components/Characteristics/components/Consumables.tsx index 1f323b28c..4a79a3b06 100644 --- a/src/app/tools/tankopedia/[id]/components/Characteristics/components/Consumables.tsx +++ b/src/app/tools/tankopedia/[id]/components/Characteristics/components/Consumables.tsx @@ -12,13 +12,14 @@ import { ConsumablesManager } from '../../../../../../../components/ConsumablesM import { checkConsumableProvisionInclusivity } from '../../../../../../../core/blitzkit/checkConsumableProvisionInclusivity'; import { consumableDefinitions } from '../../../../../../../core/blitzkit/consumableDefinitions'; import { useEquipment } from '../../../../../../../hooks/useEquipment'; -import { mutateDuel, useDuel } from '../../../../../../../stores/duel'; +import * as Duel from '../../../../../../../stores/duel'; import { ConfigurationChildWrapper } from './ConfigurationChildWrapper'; export function Consumables() { - const protagonist = useDuel((state) => state.protagonist!); + const mutateDuel = Duel.useMutation(); + const protagonist = Duel.use((state) => state.protagonist!); const awaitedConsumableDefinitions = use(consumableDefinitions); - const consumables = useDuel((state) => state.protagonist!.consumables); + const consumables = Duel.use((state) => state.protagonist!.consumables); const consumablesList = Object.values(awaitedConsumableDefinitions).filter( (consumable) => checkConsumableProvisionInclusivity( @@ -27,7 +28,7 @@ export function Consumables() { protagonist.gun, ), ); - const cooldownBooster = useDuel( + const cooldownBooster = Duel.use( (state) => state.protagonist!.cooldownBooster, ); const hasConsumableDeliverySystem = useEquipment(118); diff --git a/src/app/tools/tankopedia/[id]/components/Characteristics/components/Equipment.tsx b/src/app/tools/tankopedia/[id]/components/Characteristics/components/Equipment.tsx index 21e619843..2ecc5e30d 100644 --- a/src/app/tools/tankopedia/[id]/components/Characteristics/components/Equipment.tsx +++ b/src/app/tools/tankopedia/[id]/components/Characteristics/components/Equipment.tsx @@ -2,15 +2,16 @@ import { Button, Flex, Heading } from '@radix-ui/themes'; import { use } from 'react'; import { EquipmentManager } from '../../../../../../../components/EquipmentManager'; import { equipmentDefinitions } from '../../../../../../../core/blitzkit/equipmentDefinitions'; -import { mutateDuel, useDuel } from '../../../../../../../stores/duel'; +import * as Duel from '../../../../../../../stores/duel'; import { ConfigurationChildWrapper } from './ConfigurationChildWrapper'; export function Equipment() { - const protagonist = useDuel((state) => state.protagonist!); + const mutateDuel = Duel.useMutation(); + const protagonist = Duel.use((state) => state.protagonist!); const awaitedEquipmentDefinitions = use(equipmentDefinitions); const equipmentPreset = awaitedEquipmentDefinitions.presets[protagonist.tank.equipment]; - const equipmentMatrix = useDuel( + const equipmentMatrix = Duel.use( (state) => state.protagonist!.equipmentMatrix, ); diff --git a/src/app/tools/tankopedia/[id]/components/Characteristics/components/Miscellaneous.tsx b/src/app/tools/tankopedia/[id]/components/Characteristics/components/Miscellaneous.tsx index b285f34e1..102b14a09 100644 --- a/src/app/tools/tankopedia/[id]/components/Characteristics/components/Miscellaneous.tsx +++ b/src/app/tools/tankopedia/[id]/components/Characteristics/components/Miscellaneous.tsx @@ -3,18 +3,19 @@ import { clamp, debounce } from 'lodash'; import { useEffect, useMemo, useRef, useState } from 'react'; import { GenericTankComponentButton } from '../../../../../../../components/ModuleButtons/GenericTankComponentButton'; import { asset } from '../../../../../../../core/blitzkit/asset'; -import { mutateDuel, useDuel } from '../../../../../../../stores/duel'; +import * as Duel from '../../../../../../../stores/duel'; import { ConfigurationChildWrapper } from './ConfigurationChildWrapper'; export function Miscellaneous() { - const camouflage = useDuel((state) => state.protagonist!.camouflage); - const cooldownBooster = useDuel( + const mutateDuel = Duel.useMutation(); + const camouflage = Duel.use((state) => state.protagonist!.camouflage); + const cooldownBooster = Duel.use( (state) => state.protagonist!.cooldownBooster, ); - const crewMastery = useDuel((state) => state.protagonist!.crewMastery); + const crewMastery = Duel.use((state) => state.protagonist!.crewMastery); const crewInput = useRef(null); const [crewMasteryDraft, setCrewMasteryDraft] = useState(crewMastery); - const { tank } = useDuel((state) => state.protagonist!); + const { tank } = Duel.use((state) => state.protagonist!); const debouncedApplyDraft = useMemo( () => diff --git a/src/app/tools/tankopedia/[id]/components/Characteristics/components/Modules.tsx b/src/app/tools/tankopedia/[id]/components/Characteristics/components/Modules.tsx index 13aadb5d3..ef5fa7848 100644 --- a/src/app/tools/tankopedia/[id]/components/Characteristics/components/Modules.tsx +++ b/src/app/tools/tankopedia/[id]/components/Characteristics/components/Modules.tsx @@ -19,7 +19,7 @@ import { } from '../../../../../../../core/blitzkit/tankDefinitions'; import { TIER_ROMAN_NUMERALS } from '../../../../../../../core/blitzkit/tankDefinitions/constants'; import { tankIcon } from '../../../../../../../core/blitzkit/tankIcon'; -import { mutateDuel, useDuel } from '../../../../../../../stores/duel'; +import * as Duel from '../../../../../../../stores/duel'; import { ConfigurationChildWrapper } from './ConfigurationChildWrapper'; function ModuleButton({ @@ -116,17 +116,18 @@ function ModuleButton({ } export function Modules() { + const mutateDuel = Duel.useMutation(); const awaitedTankDefinitions = use(tankDefinitions); - const tank = useDuel((state) => state.protagonist!.tank); + const tank = Duel.use((state) => state.protagonist!.tank); const hasUpgrades = tank.turrets.length > 1 || tank.turrets[0].guns.length > 1 || tank.engines.length > 1 || tank.tracks.length > 1; - const turret = useDuel((state) => state.protagonist!.turret); - const gun = useDuel((state) => state.protagonist!.gun); - const engine = useDuel((state) => state.protagonist!.engine); - const track = useDuel((state) => state.protagonist!.track); + const turret = Duel.use((state) => state.protagonist!.turret); + const gun = Duel.use((state) => state.protagonist!.gun); + const engine = Duel.use((state) => state.protagonist!.engine); + const track = Duel.use((state) => state.protagonist!.track); const turret0 = tank.turrets[0]; const gun0 = turret0.guns[0]; const engine0 = tank.engines[0]; diff --git a/src/app/tools/tankopedia/[id]/components/Characteristics/components/Provisions.tsx b/src/app/tools/tankopedia/[id]/components/Characteristics/components/Provisions.tsx index e62670515..206b69269 100644 --- a/src/app/tools/tankopedia/[id]/components/Characteristics/components/Provisions.tsx +++ b/src/app/tools/tankopedia/[id]/components/Characteristics/components/Provisions.tsx @@ -3,12 +3,13 @@ import { use } from 'react'; import { ProvisionsManager } from '../../../../../../../components/ProvisionsManager'; import { availableProvisions } from '../../../../../../../core/blitzkit/availableProvisions'; import { provisionDefinitions } from '../../../../../../../core/blitzkit/provisionDefinitions'; -import { mutateDuel, useDuel } from '../../../../../../../stores/duel'; +import * as Duel from '../../../../../../../stores/duel'; import { ConfigurationChildWrapper } from './ConfigurationChildWrapper'; export function Provisions() { - const { tank, gun } = useDuel((state) => state.protagonist!); - const provisions = useDuel((state) => state.protagonist!.provisions); + const mutateDuel = Duel.useMutation(); + const { tank, gun } = Duel.use((state) => state.protagonist!); + const provisions = Duel.use((state) => state.protagonist!.provisions); const awaitedProvisionDefinitions = use(provisionDefinitions); const provisionsList = availableProvisions( tank, diff --git a/src/app/tools/tankopedia/[id]/components/Characteristics/index.tsx b/src/app/tools/tankopedia/[id]/components/Characteristics/index.tsx index 3dee62a96..7c99160d5 100644 --- a/src/app/tools/tankopedia/[id]/components/Characteristics/index.tsx +++ b/src/app/tools/tankopedia/[id]/components/Characteristics/index.tsx @@ -28,12 +28,13 @@ import { } from '../../../../../../core/blitzkit/tankDefinitions/constants'; import { useAdExempt } from '../../../../../../hooks/useAdExempt'; import { useEquipment } from '../../../../../../hooks/useEquipment'; -import { mutateDuel, useDuel } from '../../../../../../stores/duel'; +import * as Duel from '../../../../../../stores/duel'; import * as TankopediaEphemeral from '../../../../../../stores/tankopediaEphemeral'; import { Info } from './components/Info'; import { InfoWithDelta } from './components/InfoWithDelta'; export function Characteristics() { + const mutateDuel = Duel.useMutation(); const exempt = useAdExempt(); const awaitedEquipmentDefinitions = use(equipmentDefinitions); const awaitedModelDefinitions = use(modelDefinitions); @@ -41,10 +42,10 @@ export function Characteristics() { const crewSkills = TankopediaEphemeral.use((state) => state.skills); const penetrationDistanceInput = useRef(null); const hasImprovedVentilation = useEquipment(102); - const crewMastery = useDuel((state) => state.protagonist!.crewMastery); + const crewMastery = Duel.use((state) => state.protagonist!.crewMastery); const [penetrationDistance, setPenetrationDistance] = useState(250); - const provisions = useDuel((state) => state.protagonist!.provisions); + const provisions = Duel.use((state) => state.protagonist!.provisions); const provisionCrewBonus = provisions.reduce( (total, provision) => @@ -55,12 +56,12 @@ export function Characteristics() { ) + (hasImprovedVentilation ? 0.08 : 0); const commanderMastery = crewMastery + provisionCrewBonus; const crewMemberMastery = commanderMastery * 1.1; - const consumables = useDuel((state) => state.protagonist!.consumables); - const camouflage = useDuel((state) => state.protagonist!.camouflage); - const equipmentMatrix = useDuel( + const consumables = Duel.use((state) => state.protagonist!.consumables); + const camouflage = Duel.use((state) => state.protagonist!.camouflage); + const equipmentMatrix = Duel.use( (state) => state.protagonist!.equipmentMatrix, ); - const { tank, turret, gun, engine, track, shell } = useDuel( + const { tank, turret, gun, engine, track, shell } = Duel.use( (state) => state.protagonist!, ); const stockEngine = tank.engines[0]; diff --git a/src/app/tools/tankopedia/[id]/components/Control.tsx b/src/app/tools/tankopedia/[id]/components/Control.tsx index 5a74ffcd6..44d43fe87 100644 --- a/src/app/tools/tankopedia/[id]/components/Control.tsx +++ b/src/app/tools/tankopedia/[id]/components/Control.tsx @@ -8,7 +8,7 @@ import { hasEquipment } from '../../../../../core/blitzkit/hasEquipment'; import { modelDefinitions } from '../../../../../core/blitzkit/modelDefinitions'; import { Pose, poseEvent } from '../../../../../core/blitzkit/pose'; import { useAwait } from '../../../../../hooks/useAwait'; -import { useDuel } from '../../../../../stores/duel'; +import * as Duel from '../../../../../stores/duel'; import * as TankopediaEphemeral from '../../../../../stores/tankopediaEphemeral'; const poseDistances: Record = { @@ -18,13 +18,14 @@ const poseDistances: Record = { }; export function Controls() { + const duelStore = Duel.useStore(); const tankopediaEphemeralStore = TankopediaEphemeral.useStore(); const camera = useThree((state) => state.camera); const canvas = useThree((state) => state.gl.domElement); const orbitControls = useRef(null); const awaitedModelDefinitions = useAwait(modelDefinitions); - const protagonist = useDuel((state) => state.protagonist!); - const antagonist = useDuel((state) => state.antagonist!); + const protagonist = Duel.use((state) => state.protagonist!); + const antagonist = Duel.use((state) => state.antagonist!); const protagonistModelDefinition = awaitedModelDefinitions[protagonist.tank.id]; const protagonistTrackModelDefinition = @@ -71,7 +72,7 @@ export function Controls() { ); async function handlePoseEvent(event: Pose) { - const duel = useDuel.getState(); + const duel = duelStore.getState(); const hasImprovedVerticalStabilizer = await hasEquipment( 122, duel.protagonist!.tank.equipment, diff --git a/src/app/tools/tankopedia/[id]/components/HistorySection.tsx b/src/app/tools/tankopedia/[id]/components/HistorySection.tsx index 73d7fa835..a6931cdc9 100644 --- a/src/app/tools/tankopedia/[id]/components/HistorySection.tsx +++ b/src/app/tools/tankopedia/[id]/components/HistorySection.tsx @@ -1,9 +1,9 @@ import { Heading, Text } from '@radix-ui/themes'; import PageWrapper from '../../../../../components/PageWrapper'; -import { useDuel } from '../../../../../stores/duel'; +import * as Duel from '../../../../../stores/duel'; export function HistorySection() { - const tank = useDuel((state) => state.protagonist!.tank); + const tank = Duel.use((state) => state.protagonist!.tank); if (!tank.description) return null; diff --git a/src/app/tools/tankopedia/[id]/components/Lighting.tsx b/src/app/tools/tankopedia/[id]/components/Lighting.tsx index 7814f7a8d..64dadbf06 100644 --- a/src/app/tools/tankopedia/[id]/components/Lighting.tsx +++ b/src/app/tools/tankopedia/[id]/components/Lighting.tsx @@ -1,6 +1,6 @@ import { Environment } from '@react-three/drei'; import { useModel } from '../../../../../hooks/useModel'; -import { useDuel } from '../../../../../stores/duel'; +import * as Duel from '../../../../../stores/duel'; import * as TankopediaPersistent from '../../../../../stores/tankopediaPersistent'; export const ENVIRONMENTS = [ @@ -12,7 +12,7 @@ export const ENVIRONMENTS = [ ] as const; export function Lighting() { - const protagonist = useDuel((state) => state.protagonist!); + const protagonist = Duel.use((state) => state.protagonist!); const { hasPbr } = useModel(protagonist.tank.id); const showEnvironment = TankopediaPersistent.use( (state) => state.model.visual.showEnvironment, diff --git a/src/app/tools/tankopedia/[id]/components/Model/HeroSection.tsx b/src/app/tools/tankopedia/[id]/components/Model/HeroSection.tsx index f2a1482d6..b64ab956b 100644 --- a/src/app/tools/tankopedia/[id]/components/Model/HeroSection.tsx +++ b/src/app/tools/tankopedia/[id]/components/Model/HeroSection.tsx @@ -7,13 +7,13 @@ import { useFullScreen } from '../../../../../../hooks/useFullScreen'; import { useWideFormat } from '../../../../../../hooks/useWideFormat'; import strings from '../../../../../../lang/en-US.json'; import { theme } from '../../../../../../stitches.config'; -import { useDuel } from '../../../../../../stores/duel'; +import * as Duel from '../../../../../../stores/duel'; import { TankSandbox } from './TankSandbox'; import { Options } from './components/Options'; export function HeroSection() { - const protagonist = useDuel((state) => state.protagonist!.tank); - const antagonist = useDuel((state) => state.antagonist!.tank); + const protagonist = Duel.use((state) => state.protagonist!.tank); + const antagonist = Duel.use((state) => state.antagonist!.tank); const wideFormat = useWideFormat(880); const compareTanks = protagonist.id === antagonist.id diff --git a/src/app/tools/tankopedia/[id]/components/Model/TankSandbox.tsx b/src/app/tools/tankopedia/[id]/components/Model/TankSandbox.tsx index 19b608297..046a75baa 100644 --- a/src/app/tools/tankopedia/[id]/components/Model/TankSandbox.tsx +++ b/src/app/tools/tankopedia/[id]/components/Model/TankSandbox.tsx @@ -7,7 +7,7 @@ import { modelDefinitions } from '../../../../../../core/blitzkit/modelDefinitio import { modelTransformEvent } from '../../../../../../core/blitzkit/modelTransform'; import { Pose, poseEvent } from '../../../../../../core/blitzkit/pose'; import { useEquipment } from '../../../../../../hooks/useEquipment'; -import { mutateDuel, useDuel } from '../../../../../../stores/duel'; +import * as Duel from '../../../../../../stores/duel'; import * as TankopediaEphemeral from '../../../../../../stores/tankopediaEphemeral'; import { Controls } from '../Control'; import { Lighting } from '../Lighting'; @@ -20,7 +20,8 @@ export function TankSandbox() { const canvas = useRef(null); const hasImprovedVerticalStabilizer = useEquipment(122); const awaitedModelDefinitions = use(modelDefinitions); - const protagonist = useDuel((state) => state.protagonist!); + const protagonist = Duel.use((state) => state.protagonist!); + const mutateDuel = Duel.useMutation(); const tankModelDefinition = awaitedModelDefinitions[protagonist.tank.id]; const turretModelDefinition = tankModelDefinition.turrets[protagonist.turret.id]; diff --git a/src/app/tools/tankopedia/[id]/components/Model/TechTreeSection.tsx b/src/app/tools/tankopedia/[id]/components/Model/TechTreeSection.tsx index 48349c6a4..f89bd8f9d 100644 --- a/src/app/tools/tankopedia/[id]/components/Model/TechTreeSection.tsx +++ b/src/app/tools/tankopedia/[id]/components/Model/TechTreeSection.tsx @@ -7,7 +7,7 @@ import { asset } from '../../../../../../core/blitzkit/asset'; import { tankDefinitions } from '../../../../../../core/blitzkit/tankDefinitions'; import { TIER_ROMAN_NUMERALS } from '../../../../../../core/blitzkit/tankDefinitions/constants'; import { useWideFormat } from '../../../../../../hooks/useWideFormat'; -import { useDuel } from '../../../../../../stores/duel'; +import * as Duel from '../../../../../../stores/duel'; export function TreeArrow({ style, @@ -53,7 +53,7 @@ export function TreeArrow({ export function TechTreeSection() { const wideFormat = useWideFormat(720); const awaitedTankDefinitions = use(tankDefinitions); - const tank = useDuel((state) => state.protagonist!.tank); + const tank = Duel.use((state) => state.protagonist!.tank); if (tank.treeType !== 'researchable') return null; diff --git a/src/app/tools/tankopedia/[id]/components/Model/components/Options.tsx b/src/app/tools/tankopedia/[id]/components/Model/components/Options.tsx index 7559723aa..af03c6fe9 100644 --- a/src/app/tools/tankopedia/[id]/components/Model/components/Options.tsx +++ b/src/app/tools/tankopedia/[id]/components/Model/components/Options.tsx @@ -32,7 +32,7 @@ import { import { useEquipment } from '../../../../../../../hooks/useEquipment'; import { useFullScreen } from '../../../../../../../hooks/useFullScreen'; import * as App from '../../../../../../../stores/app'; -import { mutateDuel, useDuel } from '../../../../../../../stores/duel'; +import * as Duel from '../../../../../../../stores/duel'; import * as TankopediaEphemeral from '../../../../../../../stores/tankopediaEphemeral'; import * as TankopediaPersistent from '../../../../../../../stores/tankopediaPersistent'; import { TankSearch } from '../../../../components/TankSearch'; @@ -66,13 +66,14 @@ export function Options() { (state) => state.model.visual.environment, ); const developerMode = App.use((state) => state.developerMode); - const antagonistGun = useDuel((state) => state.antagonist!.gun); - const antagonistShell = useDuel((state) => state.antagonist!.shell); + const antagonistGun = Duel.use((state) => state.antagonist!.gun); + const antagonistShell = Duel.use((state) => state.antagonist!.shell); const [antagonistSelectorOpen, setAntagonistSelectorOpen] = useState(false); - const antagonistTank = useDuel((state) => state.antagonist!.tank); - const antagonistTurret = useDuel((state) => state.antagonist!.turret); + const antagonistTank = Duel.use((state) => state.antagonist!.tank); + const antagonistTurret = Duel.use((state) => state.antagonist!.turret); const hasCalibratedShells = useEquipment(103, true); const [tab, setTab] = useState('search'); + const mutateDuel = Duel.useMutation(); const hasEnhancedArmor = useEquipment(110); return ( diff --git a/src/app/tools/tankopedia/[id]/components/Model/components/TankModel.tsx b/src/app/tools/tankopedia/[id]/components/Model/components/TankModel.tsx index 71f335a56..1c019ffa1 100644 --- a/src/app/tools/tankopedia/[id]/components/Model/components/TankModel.tsx +++ b/src/app/tools/tankopedia/[id]/components/Model/components/TankModel.tsx @@ -21,12 +21,14 @@ import { import { normalizeAngleRad } from '../../../../../../../core/math/normalizeAngleRad'; import { useAwait } from '../../../../../../../hooks/useAwait'; import { useModel } from '../../../../../../../hooks/useModel'; -import { mutateDuel, useDuel } from '../../../../../../../stores/duel'; +import * as Duel from '../../../../../../../stores/duel'; import * as TankopediaEphemeral from '../../../../../../../stores/tankopediaEphemeral'; export const TankModel = memo(() => { + const mutateDuel = Duel.useMutation(); + const duelStore = Duel.useStore(); const awaitedModelDefinitions = useAwait(modelDefinitions); - const protagonist = useDuel((draft) => draft.protagonist!); + const protagonist = Duel.use((draft) => draft.protagonist!); const canvas = useThree((state) => state.gl.domElement); const hullContainer = useRef(null); const turretContainer = useRef(null); @@ -216,7 +218,7 @@ export const TankModel = memo(() => { } } async function handlePointerMove(event: PointerEvent) { - const duel = useDuel.getState(); + const duel = duelStore.getState(); const hasImprovedVerticalStabilizer = await hasEquipment( 122, duel.protagonist!.tank.equipment, @@ -296,7 +298,7 @@ export const TankModel = memo(() => { window.addEventListener('pointerup', handlePointerUp); } async function handlePointerMove(event: PointerEvent) { - const duel = useDuel.getState(); + const duel = duelStore.getState(); const hasImprovedVerticalStabilizer = await hasEquipment( 122, duel.protagonist!.tank.equipment, diff --git a/src/app/tools/tankopedia/[id]/components/QuickInputs/index.tsx b/src/app/tools/tankopedia/[id]/components/QuickInputs/index.tsx index 6983b22e1..69b37397f 100644 --- a/src/app/tools/tankopedia/[id]/components/QuickInputs/index.tsx +++ b/src/app/tools/tankopedia/[id]/components/QuickInputs/index.tsx @@ -10,11 +10,12 @@ import { } from '../../../../../../core/blitzkit/modelTransform'; import { useEquipment } from '../../../../../../hooks/useEquipment'; import { useFullScreen } from '../../../../../../hooks/useFullScreen'; -import { mutateDuel, useDuel } from '../../../../../../stores/duel'; +import * as Duel from '../../../../../../stores/duel'; import * as styles from './index.css'; export function RotationInputs() { - const protagonist = useDuel((state) => state.protagonist!); + const mutateDuel = Duel.useMutation(); + const protagonist = Duel.use((state) => state.protagonist!); const awaitedModelDefinitions = use(modelDefinitions); const yawInput = useRef(null); const pitchInput = useRef(null); diff --git a/src/app/tools/tankopedia/[id]/components/Title.tsx b/src/app/tools/tankopedia/[id]/components/Title.tsx index 25e39d1d6..28f8f3539 100644 --- a/src/app/tools/tankopedia/[id]/components/Title.tsx +++ b/src/app/tools/tankopedia/[id]/components/Title.tsx @@ -1,21 +1,24 @@ import { CaretRightIcon, UpdateIcon } from '@radix-ui/react-icons'; import { Button, Dialog, Flex, Heading } from '@radix-ui/themes'; import Link from 'next/link'; -import { useState } from 'react'; +import { use, useState } from 'react'; import { TREE_TYPE_ICONS } from '../../../../../components/Tanks/components/Item/constants'; -import { assignDuelMember } from '../../../../../core/blitzkit/assignDuelMember'; +import { provisionDefinitions } from '../../../../../core/blitzkit/provisionDefinitions'; import { pushTankopediaPath } from '../../../../../core/blitzkit/pushTankopediaPath'; -import { useDuel } from '../../../../../stores/duel'; +import { tankToDuelMember } from '../../../../../core/blitzkit/tankToDuelMember'; +import * as Duel from '../../../../../stores/duel'; import { TankSearch } from '../../components/TankSearch'; export function Title() { - const protagonist = useDuel((state) => state.protagonist!); - const antagonist = useDuel((state) => state.antagonist!); + const awaitedProvisionDefinitions = use(provisionDefinitions); + const protagonist = Duel.use((state) => state.protagonist!); + const antagonist = Duel.use((state) => state.antagonist!); const compareTanks = protagonist.tank.id === antagonist.tank.id ? [protagonist.tank.id] : [protagonist.tank.id, antagonist.tank.id]; const [changeTankDialogOpen, setChangeTankDialogOpen] = useState(false); + const mutateDuel = Duel.useMutation(); return ( <> @@ -76,9 +79,15 @@ export function Title() { { - assignDuelMember('protagonist', tank.id); setChangeTankDialogOpen(false); pushTankopediaPath(tank.id); + + mutateDuel((draft) => { + draft.protagonist = tankToDuelMember( + tank, + awaitedProvisionDefinitions, + ); + }); }} /> diff --git a/src/app/tools/tankopedia/[id]/components/VideoSection.tsx b/src/app/tools/tankopedia/[id]/components/VideoSection.tsx index d85dc3b20..e031dc46b 100644 --- a/src/app/tools/tankopedia/[id]/components/VideoSection.tsx +++ b/src/app/tools/tankopedia/[id]/components/VideoSection.tsx @@ -2,10 +2,10 @@ import { Flex, Heading, Link, Text } from '@radix-ui/themes'; import { use } from 'react'; import PageWrapper from '../../../../../components/PageWrapper'; import { videoDefinitions } from '../../../../../core/blitzkit/videos'; -import { useDuel } from '../../../../../stores/duel'; +import * as Duel from '../../../../../stores/duel'; export function VideoSection() { - const tank = useDuel((state) => state.protagonist!.tank); + const tank = Duel.use((state) => state.protagonist!.tank); const awaitedVideoDefinitions = use(videoDefinitions); const videos = awaitedVideoDefinitions[tank.id]?.videos ?? []; diff --git a/src/app/tools/tankopedia/[id]/page.tsx b/src/app/tools/tankopedia/[id]/page.tsx index c02a3f6ce..09eb0f310 100644 --- a/src/app/tools/tankopedia/[id]/page.tsx +++ b/src/app/tools/tankopedia/[id]/page.tsx @@ -3,9 +3,8 @@ import { useEffect } from 'react'; import { AdMidSectionResponsive } from '../../../../components/AdMidSectionResponsive'; import PageWrapper from '../../../../components/PageWrapper'; -import { assignDuelMember } from '../../../../core/blitzkit/assignDuelMember'; import { useAdExempt } from '../../../../hooks/useAdExempt'; -import { mutateDuel, useDuel } from '../../../../stores/duel'; +import * as Duel from '../../../../stores/duel'; import * as TankopediaEphemeral from '../../../../stores/tankopediaEphemeral'; import { HistorySection } from './components/HistorySection'; import { CharacteristicsSection } from './components/Model/CharacteristicsSection'; @@ -14,15 +13,14 @@ import { TechTreeSection } from './components/Model/TechTreeSection'; import { ShotDisplaySection } from './components/ShotDisplaySection'; import { VideoSection } from './components/VideoSection'; +// TODO: remove this param if not needed for duel assignment export default function Page({ params }: { params: { id: string } }) { - const initialId = parseInt(params.id); - const assigned = useDuel((state) => state.assigned); const exempt = useAdExempt(); const mutateTankopediaEphemeral = TankopediaEphemeral.useMutation(); + const mutateDuel = Duel.useMutation(); + const duelStore = Duel.useStore(); useEffect(() => { - assignDuelMember('both', initialId); - function handleKeyDown(event: KeyboardEvent) { if (document.activeElement instanceof HTMLInputElement) return; @@ -59,10 +57,10 @@ export default function Page({ params }: { params: { id: string } }) { return () => { window.removeEventListener('keydown', handleKeyDown); }; - }, [initialId, assigned]); + }, []); useEffect(() => { - const unsubscribe = useDuel.subscribe( + const unsubscribe = duelStore.subscribe( (state) => state.protagonist?.tank.id, () => { mutateTankopediaEphemeral((draft) => { @@ -76,19 +74,15 @@ export default function Page({ params }: { params: { id: string } }) { return ( - {assigned && ( - <> - - - {!exempt && } - - {!exempt && } - - - {!exempt && } - - - )} + + + {!exempt && } + + {!exempt && } + + + {!exempt && } + ); } diff --git a/src/app/tools/tankopedia/layout.tsx b/src/app/tools/tankopedia/layout.tsx index 1d3b927f1..ac81d2445 100644 --- a/src/app/tools/tankopedia/layout.tsx +++ b/src/app/tools/tankopedia/layout.tsx @@ -1,13 +1,16 @@ +import * as Duel from '../../../stores/duel'; import * as TankopediaEphemeral from '../../../stores/tankopediaEphemeral'; import * as TankopediaPersistent from '../../../stores/tankopediaPersistent'; import * as TankopediaSort from '../../../stores/tankopediaSort'; export default function Layout({ children }: { children: React.ReactNode }) { return ( - - - {children} - - + + + + {children} + + + ); } diff --git a/src/components/Armor/components/CoreArmorScene.tsx b/src/components/Armor/components/CoreArmorScene.tsx index 75a408994..7e89b8e1a 100644 --- a/src/components/Armor/components/CoreArmorScene.tsx +++ b/src/components/Armor/components/CoreArmorScene.tsx @@ -10,7 +10,7 @@ import { nameToArmorId } from '../../../core/blitzkit/nameToArmorId'; import { resolveArmor } from '../../../core/blitzkit/resolveThickness'; import { useArmor } from '../../../hooks/useArmor'; import { useModelDefinitions } from '../../../hooks/useModelDefinitions'; -import { useDuel } from '../../../stores/duel'; +import * as Duel from '../../../stores/duel'; import * as TankopediaPersistent from '../../../stores/tankopediaPersistent'; import { CoreArmorSceneComponent } from './CoreArmorSceneComponent'; import { ShotDisplay } from './ShotDisplay'; @@ -22,7 +22,7 @@ export const CoreArmorScene = memo(() => { const gunContainer = useRef(null); const tankopediaPersistentStore = TankopediaPersistent.useStore(); const initialTankopediaState = tankopediaPersistentStore.getState(); - const protagonist = useDuel((draft) => draft.protagonist!); + const protagonist = Duel.use((draft) => draft.protagonist); useEffect(() => { if (!modelDefinitions) return; @@ -110,10 +110,10 @@ export const CoreArmorScene = memo(() => { return unsubscribe; }); - const tank = useDuel((state) => state.protagonist!.tank); - const track = useDuel((state) => state.protagonist!.track); - const turret = useDuel((state) => state.protagonist!.turret); - const gun = useDuel((state) => state.protagonist!.gun); + 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 armorGltf = useArmor(tank.id); const armorNodes = Object.values(armorGltf.nodes); const tankModelDefinition = modelDefinitions[tank.id]; diff --git a/src/components/Armor/components/CoreArmorSceneComponent/index.tsx b/src/components/Armor/components/CoreArmorSceneComponent/index.tsx index bab6af1d1..d6b853da6 100644 --- a/src/components/Armor/components/CoreArmorSceneComponent/index.tsx +++ b/src/components/Armor/components/CoreArmorSceneComponent/index.tsx @@ -9,7 +9,7 @@ import { resolvePenetrationCoefficient } from '../../../../core/blitz/resolvePen import { hasEquipment } from '../../../../core/blitzkit/hasEquipment'; import { jsxTree } from '../../../../core/blitzkit/jsxTree'; import { ShellDefinition } from '../../../../core/blitzkit/tankDefinitions'; -import { EquipmentMatrix, useDuel } from '../../../../stores/duel'; +import * as Duel from '../../../../stores/duel'; import * as TankopediaPersistent from '../../../../stores/tankopediaPersistent'; import fragmentShader from './shaders/fragment.glsl'; import vertexShader from './shaders/vertex.glsl'; @@ -29,6 +29,7 @@ export function CoreArmorSceneComponent({ thickness, }: CoreArmorSceneComponentProps) { const tankopediaPersistentStore = TankopediaPersistent.useStore(); + const duelStore = Duel.useStore(); const material = new ShaderMaterial({ fragmentShader, vertexShader, @@ -70,7 +71,7 @@ export function CoreArmorSceneComponent({ material.uniforms.damage.value = shell.damage.armor; material.uniforms.explosionRadius.value = shell.explosionRadius; - const duel = useDuel.getState(); + const duel = duelStore.getState(); await handleProtagonistEquipmentChange(duel.protagonist!.equipmentMatrix); await handleAntagonistEquipmentChange(duel.antagonist!.equipmentMatrix); } @@ -83,9 +84,9 @@ export function CoreArmorSceneComponent({ material.wireframe = visual.wireframe; } async function handleProtagonistEquipmentChange( - equipment: EquipmentMatrix, + equipment: Duel.EquipmentMatrix, ) { - const duel = useDuel.getState(); + const duel = duelStore.getState(); const hasEnhancedArmor = await hasEquipment( 110, duel.protagonist!.tank.equipment, @@ -95,8 +96,10 @@ export function CoreArmorSceneComponent({ ? thickness * 1.03 : thickness; } - async function handleAntagonistEquipmentChange(equipment: EquipmentMatrix) { - const duel = useDuel.getState(); + async function handleAntagonistEquipmentChange( + equipment: Duel.EquipmentMatrix, + ) { + const duel = duelStore.getState(); const shell = duel.antagonist!.shell; const penetration = resolveNearPenetration(shell.penetration); const hasCalibratedShells = await hasEquipment( @@ -110,26 +113,29 @@ export function CoreArmorSceneComponent({ resolvePenetrationCoefficient(hasCalibratedShells, shell.type); } - handleShellChange(useDuel.getState().antagonist!.shell); + handleShellChange(duelStore.getState().antagonist!.shell); handleVisualChange(tankopediaPersistentStore.getState().model.visual); handleProtagonistEquipmentChange( - useDuel.getState().protagonist!.equipmentMatrix, + duelStore.getState().protagonist!.equipmentMatrix, ); handleAntagonistEquipmentChange( - useDuel.getState().antagonist!.equipmentMatrix, + duelStore.getState().antagonist!.equipmentMatrix, ); const unsubscribes = [ - useDuel.subscribe((state) => state.antagonist!.shell, handleShellChange), + duelStore.subscribe( + (state) => state.antagonist!.shell, + handleShellChange, + ), tankopediaPersistentStore.subscribe( (state) => state.model.visual, handleVisualChange, ), - useDuel.subscribe( + duelStore.subscribe( (state) => state.protagonist!.equipmentMatrix, handleProtagonistEquipmentChange, ), - useDuel.subscribe( + duelStore.subscribe( (state) => state.antagonist!.equipmentMatrix, handleAntagonistEquipmentChange, ), diff --git a/src/components/Armor/components/SpacedArmorScene.tsx b/src/components/Armor/components/SpacedArmorScene.tsx index 7663f8484..b95303668 100644 --- a/src/components/Armor/components/SpacedArmorScene.tsx +++ b/src/components/Armor/components/SpacedArmorScene.tsx @@ -11,7 +11,7 @@ import { resolveArmor } from '../../../core/blitzkit/resolveThickness'; import { useArmor } from '../../../hooks/useArmor'; import { useModel } from '../../../hooks/useModel'; import { useModelDefinitions } from '../../../hooks/useModelDefinitions'; -import { useDuel } from '../../../stores/duel'; +import * as Duel from '../../../stores/duel'; import * as TankopediaPersistent from '../../../stores/tankopediaPersistent'; import { SpacedArmorSceneComponent } from './SpacedArmorSceneComponent'; @@ -32,7 +32,7 @@ export const SpacedArmorScene = memo(({ scene }) => { const gunContainer = useRef(null); const tankopediaPersistentStore = TankopediaPersistent.useStore(); const initialTankopediaState = tankopediaPersistentStore.getState(); - const protagonist = useDuel((draft) => draft.protagonist!); + const protagonist = Duel.use((draft) => draft.protagonist); useEffect(() => { if (!modelDefinitions) return; @@ -120,10 +120,10 @@ export const SpacedArmorScene = memo(({ scene }) => { return unsubscribe; }); - const tank = useDuel((state) => state.protagonist!.tank); - const track = useDuel((state) => state.protagonist!.track); - const turret = useDuel((state) => state.protagonist!.turret); - const gun = useDuel((state) => state.protagonist!.gun); + 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 armorGltf = useArmor(tank.id); const { gltf: modelGltf } = useModel(tank.id); const armorNodes = Object.values(armorGltf.nodes); diff --git a/src/components/Armor/components/SpacedArmorSceneComponent/components/SpacedArmorSubExternal/index.tsx b/src/components/Armor/components/SpacedArmorSceneComponent/components/SpacedArmorSubExternal/index.tsx index 676865f40..cbba4fc77 100644 --- a/src/components/Armor/components/SpacedArmorSceneComponent/components/SpacedArmorSubExternal/index.tsx +++ b/src/components/Armor/components/SpacedArmorSceneComponent/components/SpacedArmorSubExternal/index.tsx @@ -12,7 +12,7 @@ import { resolvePenetrationCoefficient } from '../../../../../../core/blitz/reso import { hasEquipment } from '../../../../../../core/blitzkit/hasEquipment'; import { jsxTree } from '../../../../../../core/blitzkit/jsxTree'; import { ShellDefinition } from '../../../../../../core/blitzkit/tankDefinitions'; -import { EquipmentMatrix, useDuel } from '../../../../../../stores/duel'; +import * as Duel from '../../../../../../stores/duel'; import { ArmorType } from '../../../SpacedArmorScene'; import fragmentShader from './shaders/fragment.glsl'; import vertexShader from './shaders/vertex.glsl'; @@ -30,6 +30,7 @@ export function SpacedArmorSubExternal({ variant, clip, }: SpacedArmorSubExternalProps) { + const duelStore = Duel.useStore(); const material = new ShaderMaterial({ fragmentShader, vertexShader, @@ -53,9 +54,9 @@ export function SpacedArmorSubExternal({ ); } async function handleProtagonistEquipmentChange( - equipment: EquipmentMatrix, + equipment: Duel.EquipmentMatrix, ) { - const duel = useDuel.getState(); + const duel = duelStore.getState(); const hasEnhancedArmor = await hasEquipment( 110, duel.protagonist!.tank.equipment, @@ -65,8 +66,10 @@ export function SpacedArmorSubExternal({ ? thickness * 1.03 : thickness; } - async function handleAntagonistEquipmentChange(equipment: EquipmentMatrix) { - const duel = useDuel.getState(); + async function handleAntagonistEquipmentChange( + equipment: Duel.EquipmentMatrix, + ) { + const duel = duelStore.getState(); const shell = duel.antagonist!.shell; const penetration = resolveNearPenetration(shell.penetration); const hasCalibratedShells = await hasEquipment( @@ -80,21 +83,24 @@ export function SpacedArmorSubExternal({ resolvePenetrationCoefficient(hasCalibratedShells, shell.type); } - handleShellChange(useDuel.getState().antagonist!.shell); + handleShellChange(duelStore.getState().antagonist!.shell); handleProtagonistEquipmentChange( - useDuel.getState().protagonist!.equipmentMatrix, + duelStore.getState().protagonist!.equipmentMatrix, ); handleAntagonistEquipmentChange( - useDuel.getState().antagonist!.equipmentMatrix, + duelStore.getState().antagonist!.equipmentMatrix, ); const unsubscribes = [ - useDuel.subscribe((state) => state.antagonist!.shell, handleShellChange), - useDuel.subscribe( + duelStore.subscribe( + (state) => state.antagonist!.shell, + handleShellChange, + ), + duelStore.subscribe( (state) => state.protagonist!.equipmentMatrix, handleProtagonistEquipmentChange, ), - useDuel.subscribe( + duelStore.subscribe( (state) => state.antagonist!.equipmentMatrix, handleAntagonistEquipmentChange, ), diff --git a/src/components/Armor/components/SpacedArmorSceneComponent/components/SpacedArmorSubSpaced/index.tsx b/src/components/Armor/components/SpacedArmorSceneComponent/components/SpacedArmorSubSpaced/index.tsx index 1dc904787..e6283da3c 100644 --- a/src/components/Armor/components/SpacedArmorSceneComponent/components/SpacedArmorSubSpaced/index.tsx +++ b/src/components/Armor/components/SpacedArmorSceneComponent/components/SpacedArmorSubSpaced/index.tsx @@ -13,7 +13,7 @@ import { resolvePenetrationCoefficient } from '../../../../../../core/blitz/reso import { hasEquipment } from '../../../../../../core/blitzkit/hasEquipment'; import { jsxTree } from '../../../../../../core/blitzkit/jsxTree'; import { ShellDefinition } from '../../../../../../core/blitzkit/tankDefinitions'; -import { EquipmentMatrix, useDuel } from '../../../../../../stores/duel'; +import * as Duel from '../../../../../../stores/duel'; import { ArmorType } from '../../../SpacedArmorScene'; import fragmentShader from './shaders/fragment.glsl'; import vertexShader from './shaders/vertex.glsl'; @@ -32,6 +32,7 @@ export function SpacedArmorSubSpaced({ node, thickness, }: SpacedArmorSubSpacedProps) { + const duelStore = Duel.useStore(); const material = new ShaderMaterial({ fragmentShader, vertexShader, @@ -63,9 +64,9 @@ export function SpacedArmorSubSpaced({ ); } async function handleProtagonistEquipmentChange( - equipment: EquipmentMatrix, + equipment: Duel.EquipmentMatrix, ) { - const duel = useDuel.getState(); + const duel = duelStore.getState(); const hasEnhancedArmor = await hasEquipment( 110, duel.protagonist!.tank.equipment, @@ -75,9 +76,11 @@ export function SpacedArmorSubSpaced({ ? thickness * 1.03 : thickness; } - async function handleAntagonistEquipmentChange(equipment: EquipmentMatrix) { - const duel = useDuel.getState(); - const shell = useDuel.getState().antagonist!.shell; + async function handleAntagonistEquipmentChange( + equipment: Duel.EquipmentMatrix, + ) { + const duel = duelStore.getState(); + const shell = duelStore.getState().antagonist!.shell; const penetration = resolveNearPenetration(shell.penetration); const hasCalibratedShells = await hasEquipment( 103, @@ -90,21 +93,24 @@ export function SpacedArmorSubSpaced({ resolvePenetrationCoefficient(hasCalibratedShells, shell.type); } - handleShellChange(useDuel.getState().antagonist!.shell); + handleShellChange(duelStore.getState().antagonist!.shell); handleProtagonistEquipmentChange( - useDuel.getState().protagonist!.equipmentMatrix, + duelStore.getState().protagonist!.equipmentMatrix, ); handleAntagonistEquipmentChange( - useDuel.getState().antagonist!.equipmentMatrix, + duelStore.getState().antagonist!.equipmentMatrix, ); const unsubscribes = [ - useDuel.subscribe((state) => state.antagonist!.shell, handleShellChange), - useDuel.subscribe( + duelStore.subscribe( + (state) => state.antagonist!.shell, + handleShellChange, + ), + duelStore.subscribe( (state) => state.protagonist!.equipmentMatrix, handleProtagonistEquipmentChange, ), - useDuel.subscribe( + duelStore.subscribe( (state) => state.antagonist!.equipmentMatrix, handleAntagonistEquipmentChange, ), diff --git a/src/components/Armor/components/SpacedArmorSceneComponent/index.tsx b/src/components/Armor/components/SpacedArmorSceneComponent/index.tsx index b40f4384e..e57e7f4ab 100644 --- a/src/components/Armor/components/SpacedArmorSceneComponent/index.tsx +++ b/src/components/Armor/components/SpacedArmorSceneComponent/index.tsx @@ -16,7 +16,7 @@ import { resolvePenetrationCoefficient } from '../../../../core/blitz/resolvePen import { hasEquipment } from '../../../../core/blitzkit/hasEquipment'; import { jsxTree } from '../../../../core/blitzkit/jsxTree'; import { ShellType } from '../../../../core/blitzkit/tankDefinitions'; -import { useDuel } from '../../../../stores/duel'; +import * as Duel from '../../../../stores/duel'; import * as TankopediaEphemeral from '../../../../stores/tankopediaEphemeral'; import { ArmorType } from '../SpacedArmorScene'; import { SpacedArmorSubExternal } from './components/SpacedArmorSubExternal'; @@ -74,6 +74,7 @@ export function SpacedArmorSceneComponent({ }: SpacedArmorSceneComponentProps) { const tankopediaEphemeralStore = TankopediaEphemeral.useStore(); const camera = useThree((state) => state.camera); + const duelStore = Duel.useStore(); async function shoot( point: Vector3, @@ -81,7 +82,7 @@ export function SpacedArmorSceneComponent({ allowRicochet: boolean, remainingPenetrationInput?: number, ) { - const { antagonist, protagonist } = useDuel.getState(); + const { antagonist, protagonist } = duelStore.getState(); const shell = antagonist!.shell; const cameraNormal = camera.position.clone().sub(point).normalize(); const shot: TankopediaEphemeral.Shot = { diff --git a/src/core/blitzkit/assignDuelMember.ts b/src/core/blitzkit/assignDuelMember.ts deleted file mode 100644 index 377dd0da9..000000000 --- a/src/core/blitzkit/assignDuelMember.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { mutateDuel } from '../../stores/duel'; -import { provisionDefinitions } from './provisionDefinitions'; -import { tankDefinitions } from './tankDefinitions'; -import { tankToDuelMember } from './tankToDuelMember'; - -export async function assignDuelMember( - type: 'antagonist' | 'protagonist' | 'both', - id: number, -) { - const awaitedTankDefinitions = await tankDefinitions; - const awaitedProvisionDefinitions = await provisionDefinitions; - const tank = awaitedTankDefinitions[id]; - const member = tankToDuelMember(tank, awaitedProvisionDefinitions); - - mutateDuel((draft) => { - draft.assigned = true; - if (type === 'antagonist') { - draft.antagonist = member; - } else if (type === 'protagonist') { - draft.protagonist = member; - } else { - draft.protagonist = member; - draft.antagonist = { ...member }; - } - }); -} diff --git a/src/core/zustand/createNextSafeStore.tsx b/src/core/zustand/createNextSafeStore.tsx index d9afcbb5d..04e521fa3 100644 --- a/src/core/zustand/createNextSafeStore.tsx +++ b/src/core/zustand/createNextSafeStore.tsx @@ -1,5 +1,13 @@ import { Draft, produce } from 'immer'; -import { createContext, ReactNode, useContext, useRef } from 'react'; +import { usePathname } from 'next/navigation'; +import { + createContext, + ReactNode, + useContext, + useMemo, + use as useReact, + useRef, +} from 'react'; import { StoreApi, useStore as useStoreZustand } from 'zustand'; interface StoreProviderProps { @@ -13,16 +21,24 @@ type ExtractState = S extends { ? T : never; +interface InitialContext { + pathName: string; +} + export function createNextSafeStore>( - initial: () => Store, + initial: (context: InitialContext) => Store | Promise, ) { type Type = Store extends StoreApi ? T : never; const Context = createContext(undefined); function Provider({ children }: StoreProviderProps) { + const pathName = usePathname(); const storeRef = useRef(); - if (!storeRef.current) storeRef.current = initial() as Store; + const context = { pathName }; + const storePromise = useMemo(async () => await initial(context), []); + const awaitedStore = useReact(storePromise); + if (!storeRef.current) storeRef.current = awaitedStore; return ( {children} diff --git a/src/hooks/useEccentricity.ts b/src/hooks/useEccentricity.ts index df0d27b86..67c8d1580 100644 --- a/src/hooks/useEccentricity.ts +++ b/src/hooks/useEccentricity.ts @@ -4,7 +4,7 @@ import { TankDefinition, tankDefinitions, } from '../core/blitzkit/tankDefinitions'; -import { useDuel } from '../stores/duel'; +import * as Duel from '../stores/duel'; export enum UseEccentricityMode { Tier, @@ -13,7 +13,7 @@ export enum UseEccentricityMode { export function useEccentricity(mode: UseEccentricityMode) { const awaitedTankDefinitions = use(tankDefinitions); - const tank = useDuel((state) => state.protagonist!.tank); + const tank = Duel.use((state) => state.protagonist!.tank); const similarTanks = useMemo( () => Object.values(awaitedTankDefinitions).filter( diff --git a/src/hooks/useEquipment.ts b/src/hooks/useEquipment.ts index dddd430aa..c184ab275 100644 --- a/src/hooks/useEquipment.ts +++ b/src/hooks/useEquipment.ts @@ -1,15 +1,15 @@ import { use, useMemo } from 'react'; import { equipmentDefinitions } from '../core/blitzkit/equipmentDefinitions'; -import { useDuel } from '../stores/duel'; +import * as Duel from '../stores/duel'; export function useEquipment(id: number, antagonist = false) { const awaitedEquipmentDefinitions = use(equipmentDefinitions); - const member = useDuel( + const member = Duel.use( (state) => state[antagonist ? 'antagonist' : 'protagonist']!, ); const equipmentRows = awaitedEquipmentDefinitions.presets[member.tank.equipment]; - const equipmentMatrix = useDuel( + const equipmentMatrix = Duel.use( (state) => state[antagonist ? 'antagonist' : 'protagonist']!.equipmentMatrix, ); diff --git a/src/hooks/useProvision.ts b/src/hooks/useProvision.ts index 217af4cf4..a7f3ff7b0 100644 --- a/src/hooks/useProvision.ts +++ b/src/hooks/useProvision.ts @@ -1,6 +1,6 @@ -import { useDuel } from '../stores/duel'; +import * as Duel from '../stores/duel'; export function useProvision(id: number) { - const provisions = useDuel((state) => state.protagonist!.provisions); + const provisions = Duel.use((state) => state.protagonist!.provisions); return provisions.includes(id); } diff --git a/src/stores/duel/index.ts b/src/stores/duel/index.ts index 14dd60d67..278a4cc3c 100644 --- a/src/stores/duel/index.ts +++ b/src/stores/duel/index.ts @@ -1,14 +1,19 @@ -import { produce } from 'immer'; +'use client'; + import { create } from 'zustand'; import { subscribeWithSelector } from 'zustand/middleware'; +import { provisionDefinitions } from '../../core/blitzkit/provisionDefinitions'; import { EngineDefinition, GunDefinition, ShellDefinition, TankDefinition, + tankDefinitions, TrackDefinition, TurretDefinition, } from '../../core/blitzkit/tankDefinitions'; +import { tankToDuelMember } from '../../core/blitzkit/tankToDuelMember'; +import { createNextSafeStore } from '../../core/zustand/createNextSafeStore'; type EquipmentMatrixItem = -1 | 0 | 1; type EquipmentMatrixRow = [ @@ -40,17 +45,23 @@ export interface DuelMember { } export interface Duel { - assigned: boolean; - protagonist?: DuelMember; - antagonist?: DuelMember; + protagonist: DuelMember; + antagonist: DuelMember; } -export const useDuel = create()( - subscribeWithSelector(() => ({ - assigned: false, - })), +export const { Provider, use, useMutation, useStore } = createNextSafeStore( + async ({ pathName }) => { + const id = Number(pathName.split('/')[3]); + const awaitedTankDefinitions = await tankDefinitions; + const awaitedProvisionDefinitions = await provisionDefinitions; + const tank = awaitedTankDefinitions[id]; + const protagonist = tankToDuelMember(tank, awaitedProvisionDefinitions); + + return create()( + subscribeWithSelector(() => ({ + protagonist, + antagonist: protagonist, + })), + ); + }, ); - -export function mutateDuel(recipe: (draft: Duel) => void) { - useDuel.setState(produce(recipe)); -} diff --git a/src/themes/mint.ts b/src/themes/mint.ts deleted file mode 100644 index 9c63ae9be..000000000 --- a/src/themes/mint.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { mintDark } from '@radix-ui/colors'; -import { createColors } from 'bepaint'; - -export const mintTheme = { - colors: createColors(mintDark), -};