feat: some more stuff

This commit is contained in:
tresabhi committed 2024-12-01 20:23:23 -06:00
1 parent d7e556e136
commit 7a3bdd8f35
7 files changed
+56 -23

No files matched your search

@@ -55,10 +55,7 @@ export function Options({ thicknessRange, canvas }: OptionsProps) {
const hasCustomShell = TankopediaEphemeral.use( const hasCustomShell = TankopediaEphemeral.use(
(state) => state.customShell !== undefined, (state) => state.customShell !== undefined,
); );
const display = TankopediaPersistent.useDeferred( const display = TankopediaEphemeral.use((state) => state.display);
(state) => state.display,
TankopediaDisplay.Model,
);
const isFullScreen = useFullScreen(); const isFullScreen = useFullScreen();
const showGrid = TankopediaPersistent.use((state) => state.showGrid); const showGrid = TankopediaPersistent.use((state) => state.showGrid);
const showEnvironment = TankopediaPersistent.use( const showEnvironment = TankopediaPersistent.use(
@@ -356,7 +353,7 @@ export function Options({ thicknessRange, canvas }: OptionsProps) {
<SegmentedControl.Root <SegmentedControl.Root
value={`${display}`} value={`${display}`}
onValueChange={(value) => { onValueChange={(value) => {
mutateTankopediaPersistent((draft) => { mutateTankopediaEphemeral((draft) => {
draft.display = Number(value); draft.display = Number(value);
}); });
}} }}
@@ -1,7 +1,7 @@
import { OrbitControls } from '@react-three/drei'; import { OrbitControls } from '@react-three/drei';
import { invalidate, useThree } from '@react-three/fiber'; import { invalidate, useThree } from '@react-three/fiber';
import { useEffect, useRef, useState } from 'react'; import { useEffect, useRef, useState } from 'react';
import { Vector3 } from 'three'; import { PerspectiveCamera, Vector3 } from 'three';
import { OrbitControls as OrbitControlsClass } from 'three-stdlib'; import { OrbitControls as OrbitControlsClass } from 'three-stdlib';
import { awaitableModelDefinitions } from '../../../../../../core/awaitables/modelDefinitions'; import { awaitableModelDefinitions } from '../../../../../../core/awaitables/modelDefinitions';
import { applyPitchYawLimits } from '../../../../../../core/blitz/applyPitchYawLimits'; import { applyPitchYawLimits } from '../../../../../../core/blitz/applyPitchYawLimits';
@@ -9,6 +9,7 @@ import { hasEquipment } from '../../../../../../core/blitzkit/hasEquipment';
import { Pose, poseEvent } from '../../../../../../core/blitzkit/pose'; import { Pose, poseEvent } from '../../../../../../core/blitzkit/pose';
import { Duel } from '../../../../../../stores/duel'; import { Duel } from '../../../../../../stores/duel';
import { TankopediaEphemeral } from '../../../../../../stores/tankopediaEphemeral'; import { TankopediaEphemeral } from '../../../../../../stores/tankopediaEphemeral';
import { TankopediaDisplay } from '../../../../../../stores/tankopediaPersistent/constants';
const poseDistances: Record<Pose, number> = { const poseDistances: Record<Pose, number> = {
[Pose.HullDown]: 15, [Pose.HullDown]: 15,
@@ -18,7 +19,14 @@ const poseDistances: Record<Pose, number> = {
const modelDefinitions = await awaitableModelDefinitions; const modelDefinitions = await awaitableModelDefinitions;
const ARCADE_MODE_DISTANCE = 19;
const ARCADE_MODE_ANGLE = Math.PI / 4;
export const ARCADE_MODE_FOV = 54;
export const INSPECT_MODE_FOV = 25;
export function Controls() { export function Controls() {
const display = TankopediaEphemeral.use((state) => state.display);
const duelStore = Duel.useStore(); const duelStore = Duel.useStore();
const tankopediaEphemeralStore = TankopediaEphemeral.useStore(); const tankopediaEphemeralStore = TankopediaEphemeral.useStore();
const camera = useThree((state) => state.camera); const camera = useThree((state) => state.camera);
@@ -62,8 +70,10 @@ export function Controls() {
protagonistTrackModelDefinition.origin.y + protagonistTrackModelDefinition.origin.y +
antagonistModelDefinition.turret_origin.y + antagonistModelDefinition.turret_origin.y +
antagonistTurretModelDefinition.gun_origin.y; antagonistTurretModelDefinition.gun_origin.y;
const [autoRotate, setAutoRotate] = useState(true); const [autoRotate, setAutoRotate] = useState(
const initialPosition = [ display !== TankopediaDisplay.ShootingRange,
);
let initialPosition = [
-8, -8,
protagonistHullOrigin.y + protagonistHullOrigin.y +
protagonistTurretOrigin.y + protagonistTurretOrigin.y +
@@ -72,9 +82,27 @@ export function Controls() {
] as const; ] as const;
useEffect(() => { useEffect(() => {
if (display === TankopediaDisplay.ShootingRange) {
(camera as PerspectiveCamera).fov = ARCADE_MODE_FOV;
camera.position.set(
0,
initialPosition[1] + ARCADE_MODE_DISTANCE * Math.sin(ARCADE_MODE_ANGLE),
ARCADE_MODE_DISTANCE * Math.cos(ARCADE_MODE_ANGLE),
);
orbitControls.current?.target.set(0, initialPosition[1], 0);
} else {
(camera as PerspectiveCamera).fov = INSPECT_MODE_FOV;
camera.position.set(...initialPosition); camera.position.set(...initialPosition);
orbitControls.current?.target.set(0, initialPosition[1] / 2, 0); orbitControls.current?.target.set(0, initialPosition[1] / 2, 0);
}, [camera, protagonistTrack, protagonistTank]); }
camera.updateProjectionMatrix();
}, [
camera,
protagonistTrack,
protagonistTank,
display === TankopediaDisplay.ShootingRange,
]);
useEffect(() => { useEffect(() => {
const unsubscribeTankopediaEphemeral = tankopediaEphemeralStore.subscribe( const unsubscribeTankopediaEphemeral = tankopediaEphemeralStore.subscribe(
@@ -187,13 +215,20 @@ export function Controls() {
poseEvent.on(handleDisturbance); poseEvent.on(handleDisturbance);
canvas.addEventListener('pointerdown', handleDisturbance); canvas.addEventListener('pointerdown', handleDisturbance);
const unsubscribeTankopediaPersistent = tankopediaEphemeralStore.subscribe(
(state) => state.display,
handleDisturbance,
);
return () => { return () => {
canvas.removeEventListener('pointerdown', handleDisturbance); canvas.removeEventListener('pointerdown', handleDisturbance);
poseEvent.off(handleDisturbance); poseEvent.off(handleDisturbance);
unsubscribeTankopediaPersistent();
}; };
}, []); }, []);
useEffect(() => {}, [display]);
return ( return (
<OrbitControls <OrbitControls
maxDistance={20} maxDistance={20}
@@ -1,12 +1,13 @@
import { Environment } from '@react-three/drei'; import { Environment } from '@react-three/drei';
import { useModel } from '../../../../../../hooks/useModel'; import { useModel } from '../../../../../../hooks/useModel';
import { Duel } from '../../../../../../stores/duel'; import { Duel } from '../../../../../../stores/duel';
import { TankopediaEphemeral } from '../../../../../../stores/tankopediaEphemeral';
import { TankopediaPersistent } from '../../../../../../stores/tankopediaPersistent'; import { TankopediaPersistent } from '../../../../../../stores/tankopediaPersistent';
import { TankopediaDisplay } from '../../../../../../stores/tankopediaPersistent/constants'; import { TankopediaDisplay } from '../../../../../../stores/tankopediaPersistent/constants';
export function Lighting() { export function Lighting() {
const protagonist = Duel.use((state) => state.protagonist); const protagonist = Duel.use((state) => state.protagonist);
const display = TankopediaPersistent.use((state) => state.display); const display = TankopediaEphemeral.use((state) => state.display);
const { hasPbr } = useModel(protagonist.tank.id); const { hasPbr } = useModel(protagonist.tank.id);
const isBrighterLighting = const isBrighterLighting =
!hasPbr && display !== TankopediaDisplay.StaticArmor; !hasPbr && display !== TankopediaDisplay.StaticArmor;
@@ -11,7 +11,6 @@ import { useTankModelDefinition } from '../../../../../../hooks/useTankModelDefi
import { useTankTransform } from '../../../../../../hooks/useTankTransform'; import { useTankTransform } from '../../../../../../hooks/useTankTransform';
import { Duel } from '../../../../../../stores/duel'; import { Duel } from '../../../../../../stores/duel';
import { TankopediaEphemeral } from '../../../../../../stores/tankopediaEphemeral'; import { TankopediaEphemeral } from '../../../../../../stores/tankopediaEphemeral';
import { TankopediaPersistent } from '../../../../../../stores/tankopediaPersistent';
import { TankopediaDisplay } from '../../../../../../stores/tankopediaPersistent/constants'; import { TankopediaDisplay } from '../../../../../../stores/tankopediaPersistent/constants';
import { ModelTankWrapper } from '../../../../../Armor/components/ModelTankWrapper'; import { ModelTankWrapper } from '../../../../../Armor/components/ModelTankWrapper';
@@ -19,7 +18,7 @@ export const TankModel = memo(() => {
const mutateDuel = Duel.useMutation(); const mutateDuel = Duel.useMutation();
const duelStore = Duel.useStore(); const duelStore = Duel.useStore();
const protagonist = Duel.use((draft) => draft.protagonist); const protagonist = Duel.use((draft) => draft.protagonist);
const tankopediaPersistentStore = TankopediaPersistent.useStore(); const tankopediaEphemeralStore = TankopediaEphemeral.useStore();
const track = Duel.use((state) => state.protagonist.track); const track = Duel.use((state) => state.protagonist.track);
const turret = Duel.use((state) => state.protagonist.turret); const turret = Duel.use((state) => state.protagonist.turret);
const canvas = useThree((state) => state.gl.domElement); const canvas = useThree((state) => state.gl.domElement);
@@ -67,7 +66,7 @@ export const TankModel = memo(() => {
function onPointerDown(event: ThreeEvent<PointerEvent>) { function onPointerDown(event: ThreeEvent<PointerEvent>) {
if ( if (
isTrack && isTrack &&
tankopediaPersistentStore.getState().display === tankopediaEphemeralStore.getState().display ===
TankopediaDisplay.Model TankopediaDisplay.Model
) { ) {
position.set(event.clientX, event.clientY); position.set(event.clientX, event.clientY);
@@ -24,7 +24,7 @@ import {
type ThicknessRange, type ThicknessRange,
} from '../../../../Armor/components/StaticArmor'; } from '../../../../Armor/components/StaticArmor';
import { AutoClear } from './components/AutoClear'; import { AutoClear } from './components/AutoClear';
import { Controls } from './components/Control'; import { Controls, INSPECT_MODE_FOV } from './components/Control';
import { Lighting } from './components/Lighting'; import { Lighting } from './components/Lighting';
import { ModelLoader } from './components/ModelLoader'; import { ModelLoader } from './components/ModelLoader';
import { SceneProps } from './components/SceneProps'; import { SceneProps } from './components/SceneProps';
@@ -46,10 +46,8 @@ export const TankSandbox = forwardRef<HTMLCanvasElement, TankSandboxProps>(
tankModelDefinition.turrets[protagonist.turret.id]; tankModelDefinition.turrets[protagonist.turret.id];
const gunModelDefinition = const gunModelDefinition =
turretModelDefinition.guns[protagonist.gun.gun_type!.value.base.id]; turretModelDefinition.guns[protagonist.gun.gun_type!.value.base.id];
const display = TankopediaPersistent.useDeferred( const display = TankopediaEphemeral.use((state) => state.display);
(state) => state.display, const tankopediaPersistentStore = TankopediaPersistent.useStore();
TankopediaDisplay.Model,
);
const onScreen = useOnScreen(canvas); const onScreen = useOnScreen(canvas);
useImperativeHandle(ref, () => canvas.current!, []); useImperativeHandle(ref, () => canvas.current!, []);
@@ -177,7 +175,10 @@ export const TankSandbox = forwardRef<HTMLCanvasElement, TankSandboxProps>(
}); });
}} }}
style={{ userSelect: 'none' }} style={{ userSelect: 'none' }}
camera={{ fov: 25, far: 32 }} camera={{
fov: INSPECT_MODE_FOV,
far: 32,
}}
> >
<Controls /> <Controls />
<SceneProps /> <SceneProps />
@@ -11,6 +11,7 @@ import type { ExternalModuleVariant } from '../components/Armor/components/Space
import type { XP_MULTIPLIERS } from '../components/Tankopedia/TechTreeSection'; import type { XP_MULTIPLIERS } from '../components/Tankopedia/TechTreeSection';
import { awaitableSkillDefinitions } from '../core/awaitables/skillDefinitions'; import { awaitableSkillDefinitions } from '../core/awaitables/skillDefinitions';
import { createContextualStore } from '../core/zustand/createContextualStore'; import { createContextualStore } from '../core/zustand/createContextualStore';
import { TankopediaDisplay } from './tankopediaPersistent/constants';
export interface ShotLayerBase { export interface ShotLayerBase {
index: number; index: number;
@@ -100,6 +101,7 @@ interface TankopediaEphemeral {
); );
xpMultiplier: (typeof XP_MULTIPLIERS)[number]; xpMultiplier: (typeof XP_MULTIPLIERS)[number];
customShell?: ShellDefinition; customShell?: ShellDefinition;
display: TankopediaDisplay;
} }
const skillDefinitions = await awaitableSkillDefinitions; const skillDefinitions = await awaitableSkillDefinitions;
@@ -114,6 +116,7 @@ export const TankopediaEphemeral = createContextualStore(
model, model,
controlsEnabled: true, controlsEnabled: true,
xpMultiplier: 1, xpMultiplier: 1,
display: TankopediaDisplay.Model,
})), })),
); );
}, },
@@ -3,7 +3,7 @@ import { create } from 'zustand';
import { persist, subscribeWithSelector } from 'zustand/middleware'; import { persist, subscribeWithSelector } from 'zustand/middleware';
import { ENVIRONMENTS } from '../../constants/lightingEnvironments'; import { ENVIRONMENTS } from '../../constants/lightingEnvironments';
import { createContextualStore } from '../../core/zustand/createContextualStore'; import { createContextualStore } from '../../core/zustand/createContextualStore';
import { SORT_NAMES, TankopediaDisplay } from './constants'; import { SORT_NAMES } from './constants';
export type TankopediaSortBy = keyof typeof SORT_NAMES; export type TankopediaSortBy = keyof typeof SORT_NAMES;
export type TankopediaSortDirection = 'ascending' | 'descending'; export type TankopediaSortDirection = 'ascending' | 'descending';
@@ -25,8 +25,6 @@ export interface TankopediaPersistentStore {
by: TankopediaSortBy; by: TankopediaSortBy;
direction: TankopediaSortDirection; direction: TankopediaSortDirection;
}; };
display: TankopediaDisplay;
} }
export const TankopediaPersistent = createContextualStore(() => export const TankopediaPersistent = createContextualStore(() =>
@@ -47,7 +45,6 @@ export const TankopediaPersistent = createContextualStore(() =>
by: 'meta.none', by: 'meta.none',
direction: 'ascending', direction: 'ascending',
}, },
display: TankopediaDisplay.Model,
})), })),
{ name: 'tankopedia', merge: (a, b) => lodash.merge(b, a) }, { name: 'tankopedia', merge: (a, b) => lodash.merge(b, a) },
), ),