dbc editor vscode extentsion
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
import assert from "node:assert/strict";
|
||||
import test from "node:test";
|
||||
import { DbcTable } from "../src/dbc/table";
|
||||
import { DbcSchema } from "../src/dbc/types";
|
||||
|
||||
const schema: DbcSchema = {
|
||||
name: "Synthetic",
|
||||
build: 12340,
|
||||
recordSize: 12,
|
||||
columns: [
|
||||
{ name: "ID", kind: "int", bits: 32, offset: 0, isId: true },
|
||||
{ name: "Scale", kind: "float", bits: 32, offset: 4 },
|
||||
{ name: "Name", kind: "string", bits: 32, offset: 8 }
|
||||
]
|
||||
};
|
||||
|
||||
test("reads, edits and writes WDBC records and strings", () => {
|
||||
const table = new DbcTable(makeFixture(), schema);
|
||||
assert.equal(table.header.recordCount, 2);
|
||||
assert.equal(table.getCell(0, 0), "1");
|
||||
assert.equal(table.getCell(0, 1), "1.5");
|
||||
assert.equal(table.getCell(0, 2), "hello");
|
||||
assert.equal(table.getCell(1, 2), "world");
|
||||
|
||||
table.setCell(0, 1, "2.25");
|
||||
table.setCell(0, 2, "Привет");
|
||||
table.setCell(1, 0, "42");
|
||||
|
||||
const reparsed = new DbcTable(table.serialize(), schema);
|
||||
assert.equal(reparsed.getCell(0, 1), "2.25");
|
||||
assert.equal(reparsed.getCell(0, 2), "Привет");
|
||||
assert.equal(reparsed.getCell(1, 0), "42");
|
||||
assert.equal(reparsed.getCell(1, 2), "world");
|
||||
});
|
||||
|
||||
test("adds, duplicates and deletes rows with unique generated IDs", () => {
|
||||
const table = new DbcTable(makeFixture(), schema);
|
||||
const added = table.appendRow();
|
||||
assert.equal(added, 2);
|
||||
assert.equal(table.getCell(added, 0), "3");
|
||||
assert.equal(table.getCell(added, 2), "");
|
||||
|
||||
const duplicate = table.duplicateRow(0);
|
||||
assert.equal(duplicate, 1);
|
||||
assert.equal(table.getCell(duplicate, 0), "4");
|
||||
assert.equal(table.getCell(duplicate, 2), "hello");
|
||||
|
||||
const removed = table.deleteRow(duplicate);
|
||||
assert.equal(table.rows.length, 3);
|
||||
table.insertRow(duplicate, removed);
|
||||
assert.equal(table.getCell(duplicate, 0), "4");
|
||||
|
||||
const reparsed = new DbcTable(table.serialize(), schema);
|
||||
assert.equal(reparsed.header.recordCount, 4);
|
||||
});
|
||||
|
||||
test("validates integer ranges and duplicate IDs", () => {
|
||||
const table = new DbcTable(makeFixture(), schema);
|
||||
assert.throws(() => table.setCell(0, 0, "2"), /already used/);
|
||||
assert.throws(() => table.setCell(0, 0, "2147483648"), /between/);
|
||||
assert.throws(() => table.setCell(0, 1, "not-a-float"), /floating-point/);
|
||||
});
|
||||
|
||||
function makeFixture(): Uint8Array {
|
||||
const strings = Buffer.from("\0hello\0world\0", "utf8");
|
||||
const bytes = Buffer.alloc(20 + 24 + strings.length);
|
||||
bytes.write("WDBC", 0, "ascii");
|
||||
bytes.writeUInt32LE(2, 4);
|
||||
bytes.writeUInt32LE(3, 8);
|
||||
bytes.writeUInt32LE(12, 12);
|
||||
bytes.writeUInt32LE(strings.length, 16);
|
||||
bytes.writeInt32LE(1, 20);
|
||||
bytes.writeFloatLE(1.5, 24);
|
||||
bytes.writeUInt32LE(1, 28);
|
||||
bytes.writeInt32LE(2, 32);
|
||||
bytes.writeFloatLE(-3.25, 36);
|
||||
bytes.writeUInt32LE(7, 40);
|
||||
strings.copy(bytes, 44);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
import assert from "node:assert/strict";
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import test from "node:test";
|
||||
import { parseHeader } from "../src/dbc/codec";
|
||||
import { DbcTable } from "../src/dbc/table";
|
||||
import { DbcSchemaBundle } from "../src/dbc/types";
|
||||
|
||||
const extensionRoot = path.resolve(__dirname, "..");
|
||||
const projectRoot = path.resolve(extensionRoot, "..");
|
||||
const bundle = JSON.parse(
|
||||
fs.readFileSync(path.join(extensionRoot, "schemas", "12340.json"), "utf8")
|
||||
) as DbcSchemaBundle;
|
||||
|
||||
const projectDbcs = [
|
||||
"assets/dbc/3.3.5a/CreatureModelData.dbc",
|
||||
"assets/dbc/3.3.5a/CreatureDisplayInfo.dbc",
|
||||
"src/Data/ruRU/patch-ruRU-Z/DBFilesClient/SpellVisualKitModelAttach.dbc",
|
||||
"src/Data/ruRU/patch-ruRU-Z/DBFilesClient/Spell.dbc",
|
||||
"src/Data/ruRU/patch-ruRU-Z/DBFilesClient/CreatureDisplayInfoExtra.dbc",
|
||||
"src/Data/ruRU/patch-ruRU-Z/DBFilesClient/BarberShopStyle.dbc",
|
||||
"src/Data/ruRU/patch-ruRU-5/DBFilesClient/Achievement.dbc",
|
||||
"src/Data/patch-Z/DBFilesClient/LFGDungeons.dbc",
|
||||
"src/Data/patch-Z/DBFilesClient/ItemDisplayInfo.dbc",
|
||||
"src/Data/patch-Z/DBFilesClient/Item.dbc"
|
||||
];
|
||||
|
||||
test("bundled build 12340 schemas match every project DBC record size", () => {
|
||||
for (const relativePath of projectDbcs) {
|
||||
const fullPath = path.join(projectRoot, ...relativePath.split("/"));
|
||||
const bytes = fs.readFileSync(fullPath);
|
||||
const header = parseHeader(bytes);
|
||||
const tableName = path.basename(relativePath, ".dbc").toLowerCase();
|
||||
const schema = bundle.tables[tableName];
|
||||
assert.ok(schema, `Missing schema for ${relativePath}`);
|
||||
assert.equal(schema.recordSize, header.recordSize, `Record size mismatch for ${relativePath}`);
|
||||
}
|
||||
});
|
||||
|
||||
test("opens every project DBC with named columns", () => {
|
||||
for (const relativePath of projectDbcs) {
|
||||
const fullPath = path.join(projectRoot, ...relativePath.split("/"));
|
||||
const bytes = fs.readFileSync(fullPath);
|
||||
const tableName = path.basename(relativePath, ".dbc").toLowerCase();
|
||||
const schema = bundle.tables[tableName]!;
|
||||
const table = new DbcTable(bytes, schema);
|
||||
const page = table.getPage(0, 1);
|
||||
assert.equal(page.rows.length, table.header.recordCount > 0 ? 1 : 0);
|
||||
assert.equal(page.rows[0]?.length ?? schema.columns.length, schema.columns.length);
|
||||
}
|
||||
});
|
||||
|
||||
test("round-trips project numeric and localized-string tables", () => {
|
||||
for (const relativePath of [projectDbcs[2]!, projectDbcs[5]!]) {
|
||||
const fullPath = path.join(projectRoot, ...relativePath.split("/"));
|
||||
const bytes = fs.readFileSync(fullPath);
|
||||
const tableName = path.basename(relativePath, ".dbc").toLowerCase();
|
||||
const schema = bundle.tables[tableName]!;
|
||||
const source = new DbcTable(bytes, schema);
|
||||
const reparsed = new DbcTable(source.serialize(), schema);
|
||||
assert.equal(reparsed.header.recordCount, source.header.recordCount);
|
||||
|
||||
for (const rowIndex of [0, Math.floor(source.rows.length / 2), source.rows.length - 1]) {
|
||||
for (let columnIndex = 0; columnIndex < schema.columns.length; columnIndex += 1) {
|
||||
assert.equal(
|
||||
reparsed.getCell(rowIndex, columnIndex),
|
||||
source.getCell(rowIndex, columnIndex),
|
||||
`${relativePath}, row ${rowIndex + 1}, ${schema.columns[columnIndex]!.name}`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user