diff --git a/.vscode/settings.json b/.vscode/settings.json index d39e73aa8..0ca7d3e4e 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -26,6 +26,7 @@ "deburr", "decalmask", "diacriticless", + "donotremove", "drei", "dvpl", "DVPLCRC", diff --git a/public/test/11633.glb b/public/test/11633.glb new file mode 100644 index 000000000..379cca1ba Binary files /dev/null and b/public/test/11633.glb differ diff --git a/scripts/buildAssets.ts b/scripts/buildAssets.ts index 3db91b009..5f918f1a1 100644 --- a/scripts/buildAssets.ts +++ b/scripts/buildAssets.ts @@ -532,7 +532,8 @@ if (allTargets || targets?.includes('tankModels')) { // if (id !== 7297) continue; // 60tp // if (id !== 1) continue; // t-34 // if (id !== 6753) continue; // type 71 - if (id !== 5137) continue; // tiger ii + // if (id !== 5137) continue; // tiger ii + if (id !== 11633) continue; // tiger ii // if (id !== 6225) continue; // fv215b console.log(`Building model ${id} @ ${nation}/${tankIndex}`); diff --git a/src/app/tools/tankopedia/[id]/page.tsx b/src/app/tools/tankopedia/[id]/page.tsx index cf9f35a94..6b58da012 100644 --- a/src/app/tools/tankopedia/[id]/page.tsx +++ b/src/app/tools/tankopedia/[id]/page.tsx @@ -20,16 +20,16 @@ import { Theme, Tooltip, } from '@radix-ui/themes'; -import { Environment, OrbitControls } from '@react-three/drei'; +import { OrbitControls } from '@react-three/drei'; import { Canvas, ThreeEvent, useLoader } from '@react-three/fiber'; -import { EffectComposer, SSAO } from '@react-three/postprocessing'; import { go } from 'fuzzysort'; import { debounce } from 'lodash'; import Link from 'next/link'; import { use, useEffect, useRef, useState } from 'react'; -import { Group, Mesh, Vector3 } from 'three'; +import { Color, Group, Mesh, Vector3 } from 'three'; import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'; import { Flag } from '../../../../components/Flag'; +import InfiniteGridHelper from '../../../../components/InfiniteGridHelper'; import { ModuleButtons } from '../../../../components/ModuleButton'; import PageWrapper from '../../../../components/PageWrapper'; import { asset } from '../../../../core/blitzkrieg/asset'; @@ -63,7 +63,7 @@ export default function Page({ params }: { params: { id: string } }) { const [versusGun, setVersusGun] = useState(versusTurret.guns.at(-1)!); const [versusTankTab, setVersusTankTab] = useState('search'); const canvas = useRef(null); - const gltf = useLoader(GLTFLoader, '/test/5137.glb'); + const gltf = useLoader(GLTFLoader, `/test/${id}.glb`); const turretOrigin = new Vector3( tank.turretOrigin[0], tank.turretOrigin[1], @@ -135,32 +135,46 @@ export default function Page({ params }: { params: { id: string } }) {
event.preventDefault()} - camera={{ fov: 20, position: [4, 0, -16] }} + camera={{ fov: 20 }} > - + + {/* I really like apartment, dawn, and sunset */} - - - - - + + + {gltf.scene.children[0].children.map((child) => { const isHull = child.name === 'hull'; diff --git a/src/components/InfiniteGridHelper.tsx b/src/components/InfiniteGridHelper.tsx new file mode 100644 index 000000000..21d0c5664 --- /dev/null +++ b/src/components/InfiniteGridHelper.tsx @@ -0,0 +1,79 @@ +import { MeshProps } from '@react-three/fiber'; +import { forwardRef } from 'react'; +import { DoubleSide, Mesh } from 'three'; + +interface InfiniteGridHelperProps extends MeshProps { + size1?: number; + size2?: number; + color?: THREE.Color; + distance?: number; + axes?: string; +} +/** + * Thanks, Fyrestar, for [THREE.InfiniteGridHelper](https://github.com/Fyrestar/THREE.InfiniteGridHelper/)! + */ +const InfiniteGridHelper = forwardRef( + ({ size1, size2, color, axes = 'xzy', distance, ...props }, ref) => { + const planeAxes = axes.slice(0, 2); + + return ( + + + + + ); + }, +); +export default InfiniteGridHelper; diff --git a/src/core/blitz/extractModel.ts b/src/core/blitz/extractModel.ts index ec70b4174..6931e4521 100644 --- a/src/core/blitz/extractModel.ts +++ b/src/core/blitz/extractModel.ts @@ -14,6 +14,10 @@ import { ScgStream, vertexAttributeVectorSizes } from '../streams/scg'; import { VertexAttribute } from '../streams/scpg'; import { readDVPLFile } from './readDVPLFile'; +BigInt.prototype.toJSON = function () { + return this.toString(); +}; + const MAX_FLOAT32 = 2 ** 127 * (2 - 2 ** -23); const vertexAttributeGLTFName: Partial> = { @@ -168,9 +172,14 @@ export async function extractModel( case 'NewSlotComponent': case 'StateSwitcherComponent': case 'CustomPropertiesComponent': + case 'ActionComponent': + case 'ParticleEffectComponent': case 'SlotComponent': + case 'TankElementComponent': break; + // console.log(JSON.stringify(component, null, 2)); + case 'TransformComponent': { const translation = new Vector3(); const rotation = new Quaternion(); diff --git a/src/core/streams/sc2.ts b/src/core/streams/sc2.ts index c5f2990c5..64b69d783 100644 --- a/src/core/streams/sc2.ts +++ b/src/core/streams/sc2.ts @@ -183,6 +183,55 @@ export type Component = 'cpc.properties.archive': { 'editor.donotremove': number; }; + } + | ({ + 'comp.typename': 'ActionComponent'; + 'ac.actionCount': number; + } & Record< + string, // 0000, 0001, ... + { + 'act.delay': number; + 'act.delayVariation': number; + 'act.entityName': string; + 'act.event': number; + 'act.eventToTrigger': string; + 'act.motionFrameTime': number; + 'act.motionSpeed': number; + 'act.stateActivated': number; + 'act.stopAfterNRepeats': number; + 'act.stopWhenEmpty': boolean; + 'act.switchIndex': number; + 'act.type': number; + 'act.userEventId': string; + } + >) + | { + 'comp.typename': 'ParticleEffectComponent'; + 'pe.clearOnRestart': boolean; + 'pe.effectDuration': number; + 'pe.emitters': { + '##name': string; + 'emitter.data': { + 'emitter.id': `${number}`; + 'emitter.quality': string; + }[]; + 'emitter.position': Vector3Tuple; + 'emitter.rotation': Vector4Tuple; + 'emitter.scale': Vector3Tuple; + }[]; + 'pe.inheritScale': boolean; + 'pe.nestedEmitters': boolean; + 'pe.repeatsCount': number; + 'pe.startFromTime': number; + 'pe.stopWhenEmpty': boolean; + 'pe.version': number; + 'ro.flags': number; + } + | { + 'comp.typename': 'TankElementComponent'; + isDestructible: boolean; + shouldCastShadow: boolean; + shouldGenerateSilhouette: boolean; }; interface SceneComponents {