91 lines
2.5 KiB
JavaScript
91 lines
2.5 KiB
JavaScript
import fs from 'node:fs';
|
|
import path from 'node:path';
|
|
import { parseLsetWdl } from './src/wdl.js';
|
|
|
|
const wdlPath = path.resolve('..', '..', 'Crusader-Map-Viewer', 'map_renderer', 'STATIC_PSX', 'LSET1', 'L0.WDL');
|
|
const buffer = fs.readFileSync(wdlPath);
|
|
const wdl = parseLsetWdl(buffer, wdlPath);
|
|
const section = wdl.sections.find((entry) => entry.name === 'post_audio_section_00');
|
|
const region = wdl.regions.find((entry) => entry.name === 'post_audio_region_00');
|
|
|
|
function readWords(sourceBuffer, offset, wordCount = 6) {
|
|
return Array.from({ length: wordCount }, (_, index) => sourceBuffer.readUInt16LE(offset + index * 2));
|
|
}
|
|
|
|
function isStructuredCandidate(words) {
|
|
const [typeWord, xWord, yWord, zWord, selectorWord, laneWord] = words;
|
|
if (typeWord >= 0x200) {
|
|
return false;
|
|
}
|
|
if (xWord === 0 && yWord === 0) {
|
|
return false;
|
|
}
|
|
if (xWord >= 0x4000 || yWord >= 0x4000) {
|
|
return false;
|
|
}
|
|
if (zWord > 0x20 || selectorWord > 0x04) {
|
|
return false;
|
|
}
|
|
return laneWord === 0x20 || laneWord === 0x22 || laneWord === 0x30;
|
|
}
|
|
|
|
function inspectCountPrefixed12ByteStreams(source) {
|
|
const hits = [];
|
|
|
|
for (let offset = 0; offset + 4 + 12 <= source.buffer.length; offset += 4) {
|
|
const count = source.buffer.readUInt32LE(offset);
|
|
if (count === 0 || count > 0x2000) {
|
|
continue;
|
|
}
|
|
|
|
let good = 0;
|
|
const preview = [];
|
|
for (let index = 0; index < count && offset + 4 + (index + 1) * 12 <= source.buffer.length; index += 1) {
|
|
const recordOffset = offset + 4 + index * 12;
|
|
const words = readWords(source.buffer, recordOffset);
|
|
const structured = isStructuredCandidate(words);
|
|
if (index < 6) {
|
|
preview.push({ index, recordOffset, words, structured });
|
|
}
|
|
if (!structured) {
|
|
break;
|
|
}
|
|
good += 1;
|
|
}
|
|
|
|
if (good >= 16) {
|
|
hits.push({
|
|
offset,
|
|
absoluteOffset: source.offset + offset,
|
|
count,
|
|
good,
|
|
preview,
|
|
});
|
|
}
|
|
}
|
|
|
|
return hits;
|
|
}
|
|
|
|
const sectionHits = inspectCountPrefixed12ByteStreams(section);
|
|
const regionHits = inspectCountPrefixed12ByteStreams(region);
|
|
const preview = [];
|
|
for (let offset = 0; offset < 0x90; offset += 12) {
|
|
const words = readWords(section.buffer, offset);
|
|
preview.push({
|
|
offset,
|
|
absoluteOffset: section.offset + offset,
|
|
words,
|
|
structured: isStructuredCandidate(words),
|
|
});
|
|
}
|
|
|
|
console.log(JSON.stringify({
|
|
sectionOffset: section.offset,
|
|
sectionSize: section.size,
|
|
regionOffset: region.offset,
|
|
regionSize: region.size,
|
|
sectionHits,
|
|
regionHits,
|
|
preview,
|
|
}, null, 2));
|