From a51cbc51def64082f91423dd5689de7229cdb3d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Tue, 20 Feb 2024 11:21:01 -0600 Subject: [PATCH] feat: proper lod0 handling --- scripts/buildAssets/boosterIcons.ts | 3 +- scripts/buildAssets/camouflageIcons.ts | 3 +- scripts/buildAssets/circleFlags.ts | 3 +- scripts/buildAssets/constants.ts | 11 + .../buildAssets/consumableProvisionIcons.ts | 3 +- scripts/buildAssets/definitions.ts | 3 +- scripts/buildAssets/equipmentIcons.ts | 3 +- scripts/buildAssets/index.ts | 28 +-- scripts/buildAssets/moduleIcons.ts | 3 +- scripts/buildAssets/scratchedFlags.ts | 3 +- scripts/buildAssets/shellIcons.ts | 3 +- scripts/buildAssets/tankArmors.ts | 3 +- scripts/buildAssets/tankIcons.ts | 3 +- scripts/buildAssets/tankModels.ts | 7 +- src/core/blitz/extractModel.ts | 207 ++++++------------ 15 files changed, 108 insertions(+), 178 deletions(-) diff --git a/scripts/buildAssets/boosterIcons.ts b/scripts/buildAssets/boosterIcons.ts index 3c4196687..2b1069ba8 100644 --- a/scripts/buildAssets/boosterIcons.ts +++ b/scripts/buildAssets/boosterIcons.ts @@ -1,11 +1,10 @@ import { readdir } from 'fs/promises'; import sharp from 'sharp'; -import { DATA } from '.'; import { readDVPLFile } from '../../src/core/blitz/readDVPLFile'; import { readStringDVPL } from '../../src/core/blitz/readStringDVPL'; import { commitAssets } from '../../src/core/blitzkrieg/commitAssets'; import { FileChange } from '../../src/core/blitzkrieg/commitMultipleFiles'; -import { POI } from './constants'; +import { DATA, POI } from './constants'; export async function boosterIcons(production: boolean) { const boosterFiles = (await readdir(`${DATA}/${POI.boosterIcons}`)).filter( diff --git a/scripts/buildAssets/camouflageIcons.ts b/scripts/buildAssets/camouflageIcons.ts index cde6c6b0c..c9543456c 100644 --- a/scripts/buildAssets/camouflageIcons.ts +++ b/scripts/buildAssets/camouflageIcons.ts @@ -1,8 +1,7 @@ -import { DATA } from '.'; import { readDVPLFile } from '../../src/core/blitz/readDVPLFile'; import { commitAssets } from '../../src/core/blitzkrieg/commitAssets'; import { FileChange } from '../../src/core/blitzkrieg/commitMultipleFiles'; -import { POI } from './constants'; +import { DATA, POI } from './constants'; export async function camouflageIcons(production: boolean) { console.log('Building camouflage icons...'); diff --git a/scripts/buildAssets/circleFlags.ts b/scripts/buildAssets/circleFlags.ts index 720da1b02..d293f2bb7 100644 --- a/scripts/buildAssets/circleFlags.ts +++ b/scripts/buildAssets/circleFlags.ts @@ -1,9 +1,8 @@ import { readdir } from 'fs/promises'; -import { DATA } from '.'; import { readBase64DVPL } from '../../src/core/blitz/readBase64DVPL'; import { commitAssets } from '../../src/core/blitzkrieg/commitAssets'; import { FileChange } from '../../src/core/blitzkrieg/commitMultipleFiles'; -import { POI } from './constants'; +import { DATA, POI } from './constants'; export async function circleFlags(production: boolean) { const flags = await readdir(`${DATA}/${POI.flags}`); diff --git a/scripts/buildAssets/constants.ts b/scripts/buildAssets/constants.ts index 9ddff759e..741fa1fb0 100644 --- a/scripts/buildAssets/constants.ts +++ b/scripts/buildAssets/constants.ts @@ -1,3 +1,14 @@ +import { readdir } from 'fs/promises'; +import { argv } from 'process'; + +const isDepot = argv.includes('--depot'); +export const DATA = isDepot + ? await (async () => { + const [installationVersion] = await readdir('depots/444202'); + return `depots/444202/${installationVersion}/Data`; + })() + : 'C:/Program Files (x86)/Steam/steamapps/common/World of Tanks Blitz/Data'; + export const POI = { vehicleDefinitions: 'XML/item_defs/vehicles', strings: 'Strings', diff --git a/scripts/buildAssets/consumableProvisionIcons.ts b/scripts/buildAssets/consumableProvisionIcons.ts index ce78c5dc8..9f1f2ca0a 100644 --- a/scripts/buildAssets/consumableProvisionIcons.ts +++ b/scripts/buildAssets/consumableProvisionIcons.ts @@ -1,12 +1,11 @@ import sharp from 'sharp'; -import { DATA } from '.'; import { readDVPLFile } from '../../src/core/blitz/readDVPLFile'; import { readStringDVPL } from '../../src/core/blitz/readStringDVPL'; import { readXMLDVPL } from '../../src/core/blitz/readXMLDVPL'; import { readYAMLDVPL } from '../../src/core/blitz/readYAMLDVPL'; import { commitAssets } from '../../src/core/blitzkrieg/commitAssets'; import { FileChange } from '../../src/core/blitzkrieg/commitMultipleFiles'; -import { POI } from './constants'; +import { DATA, POI } from './constants'; import { ConsumablesCommon, ProvisionsCommon } from './definitions'; interface Mappings { diff --git a/scripts/buildAssets/definitions.ts b/scripts/buildAssets/definitions.ts index 7c9e247c5..0b87de030 100644 --- a/scripts/buildAssets/definitions.ts +++ b/scripts/buildAssets/definitions.ts @@ -2,7 +2,6 @@ import { readdir } from 'fs/promises'; import { parse as parsePath } from 'path'; import { Vector3Tuple } from 'three'; import { parse as parseYaml } from 'yaml'; -import { DATA } from '.'; import { TankType } from '../../src/components/Tanks'; import { readXMLDVPL } from '../../src/core/blitz/readXMLDVPL'; import { readYAMLDVPL } from '../../src/core/blitz/readYAMLDVPL'; @@ -32,7 +31,7 @@ import { TankDefinitions, Tier, } from '../../src/core/blitzkrieg/tankDefinitions'; -import { POI } from './constants'; +import { DATA, POI } from './constants'; import { TankParameters } from './tankIcons'; type BlitzTankType = 'AT-SPG' | 'lightTank' | 'mediumTank' | 'heavyTank'; diff --git a/scripts/buildAssets/equipmentIcons.ts b/scripts/buildAssets/equipmentIcons.ts index 7334c2612..31e178b8c 100644 --- a/scripts/buildAssets/equipmentIcons.ts +++ b/scripts/buildAssets/equipmentIcons.ts @@ -1,12 +1,11 @@ import sharp from 'sharp'; -import { DATA } from '.'; import { readDVPLFile } from '../../src/core/blitz/readDVPLFile'; import { readStringDVPL } from '../../src/core/blitz/readStringDVPL'; import { readXMLDVPL } from '../../src/core/blitz/readXMLDVPL'; import { readYAMLDVPL } from '../../src/core/blitz/readYAMLDVPL'; import { commitAssets } from '../../src/core/blitzkrieg/commitAssets'; import { FileChange } from '../../src/core/blitzkrieg/commitMultipleFiles'; -import { POI } from './constants'; +import { DATA, POI } from './constants'; import { OptionalDevices } from './definitions'; interface Mappings { diff --git a/scripts/buildAssets/index.ts b/scripts/buildAssets/index.ts index 69cd9d84b..b68263abf 100644 --- a/scripts/buildAssets/index.ts +++ b/scripts/buildAssets/index.ts @@ -1,6 +1,15 @@ import { config } from 'dotenv'; -import { readdir } from 'fs/promises'; import { argv } from 'process'; + +config(); + +const allTargets = argv.includes('--all-targets'); +const targets = argv + .find((argument) => argument.startsWith('--target')) + ?.split('=')[1] + .split(','); +const production = argv.includes('--production'); + import { boosterIcons } from './boosterIcons'; import { camouflageIcons } from './camouflageIcons'; import { circleFlags } from './circleFlags'; @@ -14,23 +23,6 @@ import { tankArmors } from './tankArmors'; import { tankIcons } from './tankIcons'; import { tankModels } from './tankModels'; -config(); - -const allTargets = argv.includes('--all-targets'); -const targets = argv - .find((argument) => argument.startsWith('--target')) - ?.split('=')[1] - .split(','); -const production = argv.includes('--production'); -const isDepot = argv.includes('--depot'); - -export const DATA = isDepot - ? await (async () => { - const [installationVersion] = await readdir('depots/444202'); - return `depots/444202/${installationVersion}/Data`; - })() - : 'C:/Program Files (x86)/Steam/steamapps/common/World of Tanks Blitz/Data'; - if (!targets && !allTargets) throw new Error('No target(s) specified'); const methods = [ diff --git a/scripts/buildAssets/moduleIcons.ts b/scripts/buildAssets/moduleIcons.ts index 3f2e32606..1866e9aa4 100644 --- a/scripts/buildAssets/moduleIcons.ts +++ b/scripts/buildAssets/moduleIcons.ts @@ -1,9 +1,8 @@ import { readdir } from 'fs/promises'; -import { DATA } from '.'; import { readBase64DVPL } from '../../src/core/blitz/readBase64DVPL'; import { commitAssets } from '../../src/core/blitzkrieg/commitAssets'; import { FileChange } from '../../src/core/blitzkrieg/commitMultipleFiles'; -import { POI } from './constants'; +import { DATA, POI } from './constants'; export async function moduleIcons(production: boolean) { console.log('Building module icons...'); diff --git a/scripts/buildAssets/scratchedFlags.ts b/scripts/buildAssets/scratchedFlags.ts index 95b02c981..8bde6509b 100644 --- a/scripts/buildAssets/scratchedFlags.ts +++ b/scripts/buildAssets/scratchedFlags.ts @@ -1,9 +1,8 @@ import { readdir } from 'fs/promises'; -import { DATA } from '.'; import { readBase64DVPL } from '../../src/core/blitz/readBase64DVPL'; import { commitAssets } from '../../src/core/blitzkrieg/commitAssets'; import { FileChange } from '../../src/core/blitzkrieg/commitMultipleFiles'; -import { POI } from './constants'; +import { DATA, POI } from './constants'; export async function scratchedFlags(production: boolean) { console.log('Building scratched flags...'); diff --git a/scripts/buildAssets/shellIcons.ts b/scripts/buildAssets/shellIcons.ts index 3d7c4ddb2..350bfd72e 100644 --- a/scripts/buildAssets/shellIcons.ts +++ b/scripts/buildAssets/shellIcons.ts @@ -1,11 +1,10 @@ import { readdir } from 'fs/promises'; import sharp from 'sharp'; -import { DATA } from '.'; import { readDVPLFile } from '../../src/core/blitz/readDVPLFile'; import { readStringDVPL } from '../../src/core/blitz/readStringDVPL'; import { commitAssets } from '../../src/core/blitzkrieg/commitAssets'; import { FileChange } from '../../src/core/blitzkrieg/commitMultipleFiles'; -import { POI } from './constants'; +import { DATA, POI } from './constants'; export async function shellIcons(production: boolean) { console.log('Building shell icons...'); diff --git a/scripts/buildAssets/tankArmors.ts b/scripts/buildAssets/tankArmors.ts index 53ea6d770..b23bbf1ae 100644 --- a/scripts/buildAssets/tankArmors.ts +++ b/scripts/buildAssets/tankArmors.ts @@ -1,12 +1,11 @@ import { NodeIO } from '@gltf-transform/core'; import { readdir } from 'fs/promises'; -import { DATA } from '.'; import { extractArmor } from '../../src/core/blitz/extractArmor'; import { readXMLDVPL } from '../../src/core/blitz/readXMLDVPL'; import { toUniqueId } from '../../src/core/blitz/toUniqueId'; import { commitAssets } from '../../src/core/blitzkrieg/commitAssets'; import { FileChange } from '../../src/core/blitzkrieg/commitMultipleFiles'; -import { POI } from './constants'; +import { DATA, POI } from './constants'; import { VehicleDefinitionList } from './definitions'; export async function tankArmors(production: boolean) { diff --git a/scripts/buildAssets/tankIcons.ts b/scripts/buildAssets/tankIcons.ts index ccfa00fa2..2bef7b303 100644 --- a/scripts/buildAssets/tankIcons.ts +++ b/scripts/buildAssets/tankIcons.ts @@ -1,13 +1,12 @@ import { readdir } from 'fs/promises'; import { Vector3Tuple } from 'three'; -import { DATA } from '.'; import { NATION_IDS } from '../../src/constants/nations'; import { readBase64DVPL } from '../../src/core/blitz/readBase64DVPL'; import { readXMLDVPL } from '../../src/core/blitz/readXMLDVPL'; import { readYAMLDVPL } from '../../src/core/blitz/readYAMLDVPL'; import { commitAssets } from '../../src/core/blitzkrieg/commitAssets'; import { FileChange } from '../../src/core/blitzkrieg/commitMultipleFiles'; -import { POI } from './constants'; +import { DATA, POI } from './constants'; import { VehicleDefinitionList } from './definitions'; export interface TankParameters { diff --git a/scripts/buildAssets/tankModels.ts b/scripts/buildAssets/tankModels.ts index e03e0cd05..6c5627af4 100644 --- a/scripts/buildAssets/tankModels.ts +++ b/scripts/buildAssets/tankModels.ts @@ -1,14 +1,13 @@ import { NodeIO } from '@gltf-transform/core'; import { readdir } from 'fs/promises'; import { Vector3Tuple } from 'three'; -import { DATA } from '.'; import { extractModel } from '../../src/core/blitz/extractModel'; import { readXMLDVPL } from '../../src/core/blitz/readXMLDVPL'; import { readYAMLDVPL } from '../../src/core/blitz/readYAMLDVPL'; import { toUniqueId } from '../../src/core/blitz/toUniqueId'; import { commitAssets } from '../../src/core/blitzkrieg/commitAssets'; import { FileChange } from '../../src/core/blitzkrieg/commitMultipleFiles'; -import { POI } from './constants'; +import { DATA, POI } from './constants'; import { VehicleDefinitionList } from './definitions'; import { TankParameters } from './tankIcons'; @@ -40,7 +39,7 @@ export async function tankModels(production: boolean) { .map(Number) .map((channel) => channel / 255) as Vector3Tuple; - if (nation !== 'other') continue; + console.log(`Building models for ${nation}`); await Promise.all( Object.entries(tanks.root).map(async ([tankKey, tank]) => { @@ -59,6 +58,8 @@ export async function tankModels(production: boolean) { baseColor, ); + // writeFile(`test.${tankKey}.glb`, await nodeIO.writeBinary(model)); + changes.push({ path: `3d/tanks/models/${id}.glb`, content: Buffer.from(await nodeIO.writeBinary(model)).toString( diff --git a/src/core/blitz/extractModel.ts b/src/core/blitz/extractModel.ts index 454d8aeda..427672617 100644 --- a/src/core/blitz/extractModel.ts +++ b/src/core/blitz/extractModel.ts @@ -53,7 +53,7 @@ export async function extractModel( const document = new Document(); const scene = document.createScene(); const buffer = document.createBuffer(); - const materials = new Map(); + const materials = new Map(); // create materials await Promise.all( @@ -138,9 +138,12 @@ export async function extractModel( ), ); } - } - materials.set(new DataView(node['#id']).getBigUint64(0, true), material); + materials.set( + new DataView(node['#id']).getBigUint64(0, true), + material, + ); + } }), ); @@ -148,15 +151,11 @@ export async function extractModel( materials.forEach((material, id) => { if (typeof material !== 'bigint') return; - let resolvedMaterial: Material | bigint = material; + let resolvedMaterial: Material | bigint | undefined = material; while (typeof resolvedMaterial === 'bigint') { const linkedParentMaterial = materials.get(resolvedMaterial); - if (linkedParentMaterial === undefined) { - throw new Error('Could not resolve material'); - } - resolvedMaterial = linkedParentMaterial; } @@ -221,141 +220,79 @@ export async function extractModel( } case 'RenderComponent': { - // let minLODDistanceBatchId: undefined | number; + const renderObject = component['rc.renderObj']; - // if (component['rc.renderObj']['rb0.lodIndex'] === -1) { - // minLODDistanceBatchId = 0; - // } else { - // const lodList = components.find( - // (component) => component['comp.typename'] === 'LodComponent', - // ); + times(renderObject['ro.batchCount'], (batchIndex): void => { + const lodIndex = renderObject[`rb${batchIndex}.lodIndex`]; - // if ( - // lodList === undefined || - // lodList['comp.typename'] !== 'LodComponent' // type annotation hack - // ) { - // throw new SyntaxError('Missing LodComponent'); - // } + if (lodIndex !== 0) return; - // let minLODDistance = Infinity; - // let isFirstMaxFloat = true; - // let lodIndexStreak = 0; - // let lodIndexStreakIndex: undefined | number = undefined; + const batchKey = batchIndex.toString().padStart(4, '0'); + const batch = renderObject['ro.batches'][batchKey]; + const material = materials.get(batch['rb.nmatname']); + const polygonGroup = scg.get(batch['rb.datasource']); - // range(component['rc.renderObj']['ro.batchCount']).forEach( - // (id) => { - // const lodIndex = - // component['rc.renderObj'][`rb${id}.lodIndex`]; - // const lodDistance = - // lodList['lc.loddist'][`distance${lodIndex}`]; + if (!(material instanceof Material)) { + // probably shadow material + return; + } + if (polygonGroup === undefined) { + throw new Error( + `Missing polygon group ${batch['rb.datasource']}`, + ); + } - // if (lodIndexStreakIndex === lodIndex) { - // lodIndexStreak++; - // } else { - // lodIndexStreak = 0; - // lodIndexStreakIndex = lodIndex; - // } - - // if ( - // lodDistance < minLODDistance || - // (lodDistance === minLODDistance && lodIndexStreak > 0) || - // (lodDistance === MAX_FLOAT32 && isFirstMaxFloat) - // ) { - // if (lodDistance === MAX_FLOAT32) isFirstMaxFloat = false; - // minLODDistance = lodDistance; - // minLODDistanceBatchId = id; - // } - // }, - // ); - // } - - let batch = component['rc.renderObj']['ro.batches']['0000']; - let polygonGroup = scg.get(batch['rb.datasource'])!; - - Object.values(component['rc.renderObj']['ro.batches']).forEach( - (thisBatch) => { - const thisPolygonGroup = scg.get(thisBatch['rb.datasource']); - - if ( - thisPolygonGroup && - thisPolygonGroup.vertices.length > - polygonGroup.vertices.length - ) { - batch = thisBatch; - polygonGroup = thisPolygonGroup; - } - }, - ); - - // const batch = - // component['rc.renderObj']['ro.batches'][ - // minLODDistanceBatchId!.toString().padStart(4, '0') - // ]; - // const polygonGroup = scg.get(batch['rb.datasource']); - - if (!polygonGroup) { - console.warn( - `Missing polygon group ${batch['rb.datasource']} (${hierarchy.name}); skipping...`, - ); - - break; - } - - const material = materials.get(batch['rb.nmatname']); - - if (!(material instanceof Material)) { - throw new Error(`Material ${batch['rb.nmatname']} is unresolved`); - } - - const indicesAccessor = document - .createAccessor() - .setType('SCALAR') - .setArray(new Uint16Array(polygonGroup.indices)) - .setBuffer(buffer); - const primitive = document - .createPrimitive() - .setIndices(indicesAccessor) - .setMaterial(material); - const attributes = new Map(); - - polygonGroup.vertices.forEach((vertex) => { - vertex.forEach(({ attribute, value }) => { - if (!attributes.has(attribute)) { - attributes.set(attribute, []); - } - - attributes.get(attribute)!.push(value); - }); - }); - - if (attributes.has(VertexAttribute.TANGENT)) { - attributes.set( - VertexAttribute.TANGENT, - attributes - .get(VertexAttribute.TANGENT)! - .map((tangent) => [...tangent, 1]), - ); - } - - attributes.forEach((value, attribute) => { - const name = vertexAttributeGLTFName[attribute]; - if (!name || primitive.getAttribute(name)) return; - const vertexSize = vertexAttributeGltfVectorSizes[attribute]; - - const attributeAccessor = document - .createAccessor(name) - .setType(vertexSize === 1 ? 'SCALAR' : `VEC${vertexSize}`) - .setArray(new Float32Array(value.flat())) + const lodNode = document.createNode(batchKey); + const indicesAccessor = document + .createAccessor() + .setType('SCALAR') + .setArray(new Uint16Array(polygonGroup.indices)) .setBuffer(buffer); - primitive.setAttribute(name, attributeAccessor); + const primitive = document + .createPrimitive() + .setIndices(indicesAccessor) + .setMaterial(material); + const attributes = new Map(); + + polygonGroup.vertices.forEach((vertex) => { + vertex.forEach(({ attribute, value }) => { + if (!attributes.has(attribute)) { + attributes.set(attribute, []); + } + + attributes.get(attribute)!.push(value); + }); + }); + + if (attributes.has(VertexAttribute.TANGENT)) { + attributes.set( + VertexAttribute.TANGENT, + attributes + .get(VertexAttribute.TANGENT)! + .map((tangent) => [...tangent, 1]), + ); + } + + attributes.forEach((value, attribute) => { + const name = vertexAttributeGLTFName[attribute]; + if (!name || primitive.getAttribute(name)) return; + const vertexSize = vertexAttributeGltfVectorSizes[attribute]; + + const attributeAccessor = document + .createAccessor(name) + .setType(vertexSize === 1 ? 'SCALAR' : `VEC${vertexSize}`) + .setArray(new Float32Array(value.flat())) + .setBuffer(buffer); + primitive.setAttribute(name, attributeAccessor); + }); + + const mesh = document + .createMesh(batch['##name']) + .addPrimitive(primitive); + lodNode.setMesh(mesh); + node.addChild(lodNode); }); - const mesh = document - .createMesh(batch['##name']) - .addPrimitive(primitive); - - node.setMesh(mesh); - break; }