Files
mtgodot-poc/script/audit_native_trees.mjs

44 lines
2.5 KiB
JavaScript

import fs from 'node:fs';
import path from 'node:path';
import crypto from 'node:crypto';
import {execFileSync} from 'node:child_process';
const assets = process.argv[2] ?? 'assets';
const output = process.argv[3];
const manifest = JSON.parse(fs.readFileSync(path.join(assets, 'TreeGeometry/manifest.json')));
const normalize = s => s.replaceAll('\\', '/').toLowerCase().replace(/^.*?ymir work\//, 'ymir work/');
const converted = new Set(Object.values(manifest.trees).map(r => normalize(r.source)));
const list = pattern => execFileSync('rg', ['--files', assets, '-g', pattern], {encoding: 'utf8', maxBuffer: 8 * 1024 * 1024}).trim().split('\n').filter(Boolean);
const references = new Set();
const propertyReferences = new Map();
for (const file of list('*.prt')) {
const source = fs.readFileSync(file, 'utf8');
for (const match of source.matchAll(/^\s*treefile\s+"([^"]+)"/gmi)) {
const reference = normalize(match[1]);
references.add(reference);
propertyReferences.set(source.split(/\r?\n/)[1].trim(), reference);
}
}
const placedReferences = new Set();
for (const file of list('areadata.txt')) {
const source = fs.readFileSync(file, 'utf8');
for (const match of source.matchAll(/^Start Object\d+\r?\n[^\n]*\n\s*(\d+)/gm)) {
const reference = propertyReferences.get(match[1]);
if (reference) placedReferences.add(reference);
}
}
const unmatched = [];
let matched = 0;
for (const file of list('*.spt')) {
const hash = crypto.createHash('sha256').update(fs.readFileSync(file)).digest('hex');
if (manifest.trees[hash]) matched++;
else unmatched.push({file, source_sha256: hash, referenced_by_property: references.has(normalize(file))});
}
const missing_referenced = [...references].filter(r => !converted.has(r)).sort();
const missing_placed = [...placedReferences].filter(r => !converted.has(r)).sort();
const report = {matched_spt_files: matched, converted_species: converted.size, referenced_species: references.size,
placed_species: placedReferences.size, missing_placed,
missing_referenced, unconverted_spt: unmatched, scope: 'SPT inventory and text PRT/AreaData references; six-map runtime validation is separate'};
if (output) fs.writeFileSync(output, JSON.stringify(report, null, 2) + '\n');
console.log(JSON.stringify({matched, converted: converted.size, referenced: references.size, placed: placedReferences.size, missing_placed, missing_referenced, unconverted: unmatched.length}));
if (!placedReferences.size || missing_placed.length) process.exitCode = 1;