122 lines
3.6 KiB
JavaScript
122 lines
3.6 KiB
JavaScript
import fs from "node:fs";
|
|
import path from "node:path";
|
|
|
|
const inputDirectory = process.argv[2];
|
|
const outputFile = process.argv[3] ?? path.resolve("schemas", "12340.json");
|
|
const sourceCommit = process.argv[4];
|
|
|
|
if (!inputDirectory) {
|
|
throw new Error(
|
|
"Usage: node scripts/build-schema-bundle.mjs <DBDefsConverter JSON directory> [output file] [source commit]"
|
|
);
|
|
}
|
|
|
|
const target = { expansion: 3, major: 3, minor: 5, build: 12340 };
|
|
const locales = [
|
|
"enUS",
|
|
"enGB",
|
|
"koKR",
|
|
"frFR",
|
|
"deDE",
|
|
"enCN",
|
|
"zhCN",
|
|
"enTW",
|
|
"zhTW",
|
|
"esES",
|
|
"esMX",
|
|
"ruRU",
|
|
"ptPT",
|
|
"ptBR",
|
|
"itIT",
|
|
"Unk"
|
|
];
|
|
|
|
const bundle = {
|
|
build: 12340,
|
|
version: "3.3.5.12340",
|
|
source: {
|
|
project: "WoWDBDefs",
|
|
url: "https://github.com/wowdev/WoWDBDefs",
|
|
license: "CC BY-SA 4.0",
|
|
...(sourceCommit ? { commit: sourceCommit } : {})
|
|
},
|
|
tables: {}
|
|
};
|
|
|
|
for (const fileName of fs.readdirSync(inputDirectory).filter((name) => name.endsWith(".json"))) {
|
|
const definition = JSON.parse(fs.readFileSync(path.join(inputDirectory, fileName), "utf8"));
|
|
const version = definition.versionDefinitions.find((entry) => matches(entry, target));
|
|
if (!version) continue;
|
|
|
|
const tableName = path.basename(fileName, ".json");
|
|
const columns = [];
|
|
let offset = 0;
|
|
|
|
for (const field of version.definitions) {
|
|
if (field.isNonInline) continue;
|
|
const columnDefinition = definition.columnDefinitions[field.name];
|
|
if (!columnDefinition) {
|
|
throw new Error(`${tableName}: missing column definition '${field.name}'.`);
|
|
}
|
|
|
|
const arrayLength = field.arrLength || 1;
|
|
for (let arrayIndex = 0; arrayIndex < arrayLength; arrayIndex += 1) {
|
|
const baseName = arrayLength > 1 ? `${field.name}_${arrayIndex + 1}` : field.name;
|
|
if (columnDefinition.type === "locstring") {
|
|
for (const locale of locales) {
|
|
columns.push({ name: `${baseName}_${locale}`, kind: "string", bits: 32, offset, locale });
|
|
offset += 4;
|
|
}
|
|
columns.push({ name: `${baseName}_Mask`, kind: "uint", bits: 32, offset });
|
|
offset += 4;
|
|
continue;
|
|
}
|
|
|
|
const column = makeColumn(baseName, columnDefinition.type, field, offset);
|
|
if (field.isID) column.isId = true;
|
|
columns.push(column);
|
|
offset += column.bits / 8;
|
|
}
|
|
}
|
|
|
|
bundle.tables[tableName.toLowerCase()] = {
|
|
name: tableName,
|
|
build: 12340,
|
|
recordSize: offset,
|
|
columns,
|
|
source: "WoWDBDefs"
|
|
};
|
|
}
|
|
|
|
fs.mkdirSync(path.dirname(outputFile), { recursive: true });
|
|
fs.writeFileSync(outputFile, `${JSON.stringify(bundle)}\n`);
|
|
process.stdout.write(`Wrote ${Object.keys(bundle.tables).length} schemas to ${outputFile}\n`);
|
|
|
|
function makeColumn(name, type, field, offset) {
|
|
if (type === "string") return { name, kind: "string", bits: 32, offset };
|
|
if (type === "float") return { name, kind: "float", bits: 32, offset };
|
|
if (type !== "int") throw new Error(`Unsupported DBD type '${type}' for '${name}'.`);
|
|
|
|
const bits = field.size || 32;
|
|
if (![8, 16, 32, 64].includes(bits)) {
|
|
throw new Error(`Unsupported integer size ${bits} for '${name}'.`);
|
|
}
|
|
return { name, kind: field.isSigned ? "int" : "uint", bits, offset };
|
|
}
|
|
|
|
function matches(version, build) {
|
|
if (version.builds.some((candidate) => compareBuilds(candidate, build) === 0)) return true;
|
|
return version.buildRanges.some(
|
|
(range) => compareBuilds(range.minBuild, build) <= 0 && compareBuilds(build, range.maxBuild) <= 0
|
|
);
|
|
}
|
|
|
|
function compareBuilds(left, right) {
|
|
for (const key of ["expansion", "major", "minor", "build"]) {
|
|
const difference = left[key] - right[key];
|
|
if (difference !== 0) return difference;
|
|
}
|
|
return 0;
|
|
}
|
|
|