@rhyster/wow-casc-dbc 2.3.0 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -4,7 +4,11 @@ Node.js tool to fetch World of Warcraft data files from CASC and parse DBC/DB2 f
4
4
 
5
5
  ## Snippet
6
6
 
7
+ ### Basic Usage
8
+
7
9
  ```javascript
10
+ import { CASCClient, WDCReader, DBDParser } from '@rhyster/wow-casc-dbc';
11
+
8
12
  // Get version
9
13
  const region = 'us';
10
14
  const product = 'wow';
@@ -14,10 +18,10 @@ const version = await CASCClient.getProductVersion(region, product);
14
18
  const client = new CASCClient(region, product, version);
15
19
  await client.init();
16
20
  await client.loadRemoteTACTKeys();
17
- await client.loadRemoteListFile();
21
+ await client.loadRemoteListFile(); // pretty slow, recommend to provide fileDataID directly
18
22
 
19
23
  // Fetch file
20
- const fileDataID = client.getFileDataIDByName('dbfilesclient/questxp.db2');
24
+ const fileDataID = client.getFileDataIDByName('dbfilesclient/questxp.db2'); // see previous line
21
25
  const cKeys = client.getContentKeysByFileDataID(fileDataID);
22
26
  const cKey = cKeys.find((data) => !!(data.localeFlags & CASCClient.LocaleFlags.enUS));
23
27
  const { buffer } = await client.getFileByContentKey(cKey.cKey);
@@ -27,8 +31,47 @@ const reader = new WDCReader(buffer);
27
31
  const parser = await DBDParser.parse(reader);
28
32
 
29
33
  // Access DB2 file
30
- // reader.getRowData
31
- // parser.getRowData
34
+ reader.getAllIDs().forEach((id) => {
35
+ const rowFields = reader.getRowData(id);
36
+ });
37
+ parser.getAllIDs().forEach((id) => {
38
+ const rowObject = parser.getRowData(id);
39
+ });
40
+ ```
41
+
42
+ ### Partial Decrypt
43
+
44
+ Some file is encrypted and no key released yet. For DB2 files, you can ignore the encrypted part and parse the others.
45
+
46
+ ```javascript
47
+ // ...
48
+
49
+ const result = await client.getFileByContentKey(cKey.cKey, true);
50
+ const reader = new WDCReader(result.buffer, result.type === 'partial' ? result.blocks : []);
51
+ const parser = await DBDParser.parse(reader);
52
+
53
+ // ...
54
+ ```
55
+
56
+ ### Hotfix
57
+
58
+ Applying hotfix requires `DBCache.bin` file from the client, and it seems the only way to get this is from the client. So, you need to search for `DBCache.bin` yourself, like `<WoWPath>/_retail_/Cache/ADB/enUS/DBCache.bin` or download it somewhere.
59
+
60
+ It's also important to compare build, region and locale with the db2 file that to be patched to avoid broken data.
61
+
62
+ ```javascript
63
+ // ...
64
+
65
+ const dbcache = await fs.readFile('path/to/DBCache.bin');
66
+ const buffer = await fs.readFile('path/to/name.db2');
67
+
68
+ const adb = new ADBReader(dbcache);
69
+ assert(adb.build === parseInt(version.BuildId, 10));
70
+
71
+ const reader = new WDCReader(buffer, [], adb);
72
+ const parser = await DBDParser.parse(reader);
73
+
74
+ // ...
32
75
  ```
33
76
 
34
77
  ## License
package/dist/index.cjs CHANGED
@@ -19,17 +19,17 @@ const path__default = /*#__PURE__*/_interopDefaultCompat(path);
19
19
  const http__default = /*#__PURE__*/_interopDefaultCompat(http);
20
20
  const zlib__default = /*#__PURE__*/_interopDefaultCompat(zlib);
21
21
 
22
- var __defProp$5 = Object.defineProperty;
23
- var __defNormalProp$5 = (obj, key, value) => key in obj ? __defProp$5(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
24
- var __publicField$5 = (obj, key, value) => {
25
- __defNormalProp$5(obj, typeof key !== "symbol" ? key + "" : key, value);
22
+ var __defProp$6 = Object.defineProperty;
23
+ var __defNormalProp$6 = (obj, key, value) => key in obj ? __defProp$6(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
24
+ var __publicField$6 = (obj, key, value) => {
25
+ __defNormalProp$6(obj, typeof key !== "symbol" ? key + "" : key, value);
26
26
  return value;
27
27
  };
28
28
  class Store {
29
29
  constructor(dataFile) {
30
- __publicField$5(this, "data");
31
- __publicField$5(this, "dataFile");
32
- __publicField$5(this, "promise");
30
+ __publicField$6(this, "data");
31
+ __publicField$6(this, "dataFile");
32
+ __publicField$6(this, "promise");
33
33
  this.dataFile = dataFile;
34
34
  this.data = {};
35
35
  this.promise = new Promise((resolve) => {
@@ -294,21 +294,21 @@ const parseArchiveIndex = (buffer, cKey) => {
294
294
  return result;
295
295
  };
296
296
 
297
- var __defProp$4 = Object.defineProperty;
298
- var __defNormalProp$4 = (obj, key, value) => key in obj ? __defProp$4(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
299
- var __publicField$4 = (obj, key, value) => {
300
- __defNormalProp$4(obj, typeof key !== "symbol" ? key + "" : key, value);
297
+ var __defProp$5 = Object.defineProperty;
298
+ var __defNormalProp$5 = (obj, key, value) => key in obj ? __defProp$5(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
299
+ var __publicField$5 = (obj, key, value) => {
300
+ __defNormalProp$5(obj, typeof key !== "symbol" ? key + "" : key, value);
301
301
  return value;
302
302
  };
303
303
  class Salsa20 {
304
304
  constructor(key, nonce) {
305
- __publicField$4(this, "fixed");
306
- __publicField$4(this, "key");
307
- __publicField$4(this, "nonce");
308
- __publicField$4(this, "counter", new Uint32Array([0, 0]));
309
- __publicField$4(this, "state", new Uint32Array(16));
310
- __publicField$4(this, "block", new Uint8Array(64));
311
- __publicField$4(this, "position", 0);
305
+ __publicField$5(this, "fixed");
306
+ __publicField$5(this, "key");
307
+ __publicField$5(this, "nonce");
308
+ __publicField$5(this, "counter", new Uint32Array([0, 0]));
309
+ __publicField$5(this, "state", new Uint32Array(16));
310
+ __publicField$5(this, "block", new Uint8Array(64));
311
+ __publicField$5(this, "position", 0);
312
312
  assert__default(key.length === 32 || key.length === 16, "Salsa20 requires 128-bit or 256-bit key");
313
313
  assert__default(nonce.length === 8, "Salsa20 requires 64-bit nonce");
314
314
  this.key = new Uint32Array(8);
@@ -411,10 +411,10 @@ class Salsa20 {
411
411
  }
412
412
  }
413
413
 
414
- var __defProp$3 = Object.defineProperty;
415
- var __defNormalProp$3 = (obj, key, value) => key in obj ? __defProp$3(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
416
- var __publicField$3 = (obj, key, value) => {
417
- __defNormalProp$3(obj, typeof key !== "symbol" ? key + "" : key, value);
414
+ var __defProp$4 = Object.defineProperty;
415
+ var __defNormalProp$4 = (obj, key, value) => key in obj ? __defProp$4(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
416
+ var __publicField$4 = (obj, key, value) => {
417
+ __defNormalProp$4(obj, typeof key !== "symbol" ? key + "" : key, value);
418
418
  return value;
419
419
  };
420
420
  const BLTE_MAGIC = 1112298565;
@@ -422,12 +422,12 @@ const ENC_TYPE_SALSA20 = 83;
422
422
  const EMPTY_HASH = "00000000000000000000000000000000";
423
423
  class BLTEReader {
424
424
  constructor(buffer, eKey, keys = /* @__PURE__ */ new Map()) {
425
- __publicField$3(this, "buffer");
426
- __publicField$3(this, "blte");
427
- __publicField$3(this, "blocks", []);
428
- __publicField$3(this, "keys");
429
- __publicField$3(this, "processedBlock", 0);
430
- __publicField$3(this, "processedOffset", 0);
425
+ __publicField$4(this, "buffer");
426
+ __publicField$4(this, "blte");
427
+ __publicField$4(this, "blocks", []);
428
+ __publicField$4(this, "keys");
429
+ __publicField$4(this, "processedBlock", 0);
430
+ __publicField$4(this, "processedOffset", 0);
431
431
  this.blte = buffer;
432
432
  this.buffer = Buffer.alloc(0);
433
433
  this.keys = keys;
@@ -895,10 +895,10 @@ const getNameHash = (name) => {
895
895
  return `${pc.toString(16).padStart(8, "0")}${pb.toString(16).padStart(8, "0")}`;
896
896
  };
897
897
 
898
- var __defProp$2 = Object.defineProperty;
899
- var __defNormalProp$2 = (obj, key, value) => key in obj ? __defProp$2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
900
- var __publicField$2 = (obj, key, value) => {
901
- __defNormalProp$2(obj, typeof key !== "symbol" ? key + "" : key, value);
898
+ var __defProp$3 = Object.defineProperty;
899
+ var __defNormalProp$3 = (obj, key, value) => key in obj ? __defProp$3(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
900
+ var __publicField$3 = (obj, key, value) => {
901
+ __defNormalProp$3(obj, typeof key !== "symbol" ? key + "" : key, value);
902
902
  return value;
903
903
  };
904
904
  const WDC5_MAGIC = 1464091445;
@@ -924,17 +924,18 @@ const readBitpackedValue = (buffer, fieldOffsetBits, fieldSizeBits, signed = fal
924
924
  return signed ? BigInt.asIntN(fieldSizeBits, value >> BigInt(bitOffset)) : BigInt.asUintN(fieldSizeBits, value >> BigInt(bitOffset));
925
925
  };
926
926
  class WDCReader {
927
- constructor(buffer, blocks = []) {
928
- __publicField$2(this, "tableHash");
929
- __publicField$2(this, "layoutHash");
930
- __publicField$2(this, "locale");
931
- __publicField$2(this, "isNormal");
932
- __publicField$2(this, "hasRelationshipData");
933
- __publicField$2(this, "fields");
934
- __publicField$2(this, "fieldsInfo");
935
- __publicField$2(this, "rows", /* @__PURE__ */ new Map());
936
- __publicField$2(this, "relationships", /* @__PURE__ */ new Map());
937
- __publicField$2(this, "copyTable", /* @__PURE__ */ new Map());
927
+ constructor(buffer, blocks = [], adb) {
928
+ __publicField$3(this, "tableHash");
929
+ __publicField$3(this, "layoutHash");
930
+ __publicField$3(this, "locale");
931
+ __publicField$3(this, "isNormal");
932
+ __publicField$3(this, "hasRelationshipData");
933
+ __publicField$3(this, "fields");
934
+ __publicField$3(this, "fieldsInfo");
935
+ __publicField$3(this, "rows", /* @__PURE__ */ new Map());
936
+ __publicField$3(this, "relationships", /* @__PURE__ */ new Map());
937
+ __publicField$3(this, "copyTable", /* @__PURE__ */ new Map());
938
+ __publicField$3(this, "hotfixes", /* @__PURE__ */ new Map());
938
939
  const magic = buffer.readUInt32BE(0);
939
940
  const fieldCount = buffer.readUInt32LE(140);
940
941
  const recordSize = buffer.readUInt32LE(144);
@@ -1339,11 +1340,43 @@ class WDCReader {
1339
1340
  }
1340
1341
  }
1341
1342
  });
1343
+ const entries = adb?.tableEntries.get(tableHash);
1344
+ entries?.filter((entry) => entry.pushID !== -1).sort((a, b) => a.pushID - b.pushID).forEach((entry) => {
1345
+ switch (entry.recordState) {
1346
+ case 1:
1347
+ this.hotfixes.set(entry.recordID, { type: "modify", data: entry.data });
1348
+ break;
1349
+ case 2:
1350
+ this.hotfixes.set(entry.recordID, { type: "delete" });
1351
+ break;
1352
+ case 3:
1353
+ this.hotfixes.delete(entry.recordID);
1354
+ break;
1355
+ case 4:
1356
+ break;
1357
+ default:
1358
+ throw new Error(`Unknown record state: ${entry.recordState.toString()}`);
1359
+ }
1360
+ });
1342
1361
  }
1343
1362
  getAllIDs() {
1344
1363
  return [...this.rows.keys(), ...this.copyTable.keys()];
1345
1364
  }
1346
1365
  getRowData(id) {
1366
+ const hotfix = this.hotfixes.get(id);
1367
+ if (hotfix) {
1368
+ switch (hotfix.type) {
1369
+ case "modify":
1370
+ return {
1371
+ type: "sparse",
1372
+ data: hotfix.data
1373
+ };
1374
+ case "delete":
1375
+ return void 0;
1376
+ default:
1377
+ throw new Error("Unreachable");
1378
+ }
1379
+ }
1347
1380
  const dst = this.copyTable.get(id);
1348
1381
  if (dst) {
1349
1382
  return this.rows.get(dst);
@@ -1405,10 +1438,10 @@ const formatFileSize = (input) => {
1405
1438
  return result.join(" ");
1406
1439
  };
1407
1440
 
1408
- var __defProp$1 = Object.defineProperty;
1409
- var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
1410
- var __publicField$1 = (obj, key, value) => {
1411
- __defNormalProp$1(obj, typeof key !== "symbol" ? key + "" : key, value);
1441
+ var __defProp$2 = Object.defineProperty;
1442
+ var __defNormalProp$2 = (obj, key, value) => key in obj ? __defProp$2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
1443
+ var __publicField$2 = (obj, key, value) => {
1444
+ __defNormalProp$2(obj, typeof key !== "symbol" ? key + "" : key, value);
1412
1445
  return value;
1413
1446
  };
1414
1447
  var LogLevel = /* @__PURE__ */ ((LogLevel2) => {
@@ -1421,13 +1454,13 @@ var LogLevel = /* @__PURE__ */ ((LogLevel2) => {
1421
1454
  const textLogLevel = ["ERROR", "WARN", "INFO", "DEBUG"];
1422
1455
  class CASCClient {
1423
1456
  constructor(region, product, version, logLevel = 2 /* info */) {
1424
- __publicField$1(this, "region");
1425
- __publicField$1(this, "product");
1426
- __publicField$1(this, "version");
1427
- __publicField$1(this, "name2FileDataID", /* @__PURE__ */ new Map());
1428
- __publicField$1(this, "keys", /* @__PURE__ */ new Map());
1429
- __publicField$1(this, "preload");
1430
- __publicField$1(this, "logLevel");
1457
+ __publicField$2(this, "region");
1458
+ __publicField$2(this, "product");
1459
+ __publicField$2(this, "version");
1460
+ __publicField$2(this, "name2FileDataID", /* @__PURE__ */ new Map());
1461
+ __publicField$2(this, "keys", /* @__PURE__ */ new Map());
1462
+ __publicField$2(this, "preload");
1463
+ __publicField$2(this, "logLevel");
1431
1464
  this.region = region;
1432
1465
  this.product = product;
1433
1466
  this.version = version;
@@ -1572,7 +1605,7 @@ class CASCClient {
1572
1605
  ]);
1573
1606
  const keysReader = new WDCReader(keysResult.buffer);
1574
1607
  const lookupReader = new WDCReader(lookupResult.buffer);
1575
- [...lookupReader.rows.keys()].forEach((keyID) => {
1608
+ lookupReader.getAllIDs().forEach((keyID) => {
1576
1609
  const lookupRow = lookupReader.rows.get(keyID);
1577
1610
  const keyRow = keysReader.rows.get(keyID);
1578
1611
  if (keyRow) {
@@ -1588,6 +1621,31 @@ class CASCClient {
1588
1621
  }
1589
1622
  });
1590
1623
  }
1624
+ loadBroadcastTACTKeys(adb) {
1625
+ adb.tableEntries.get(35137211)?.forEach(({ data }) => {
1626
+ if (data.byteLength > 0) {
1627
+ let pointer = 0;
1628
+ while (data[pointer] !== 0) {
1629
+ pointer += 1;
1630
+ }
1631
+ pointer += 1;
1632
+ while (data[pointer] !== 0) {
1633
+ pointer += 1;
1634
+ }
1635
+ pointer += 1 + 43;
1636
+ if (pointer < data.byteLength) {
1637
+ const extraTableHash = data.readUInt32LE(pointer);
1638
+ if (extraTableHash === 3744420815) {
1639
+ const keyName = data.readBigUInt64LE(pointer + 4).toString(16).padStart(16, "0");
1640
+ const key = Uint8Array.from(data.subarray(pointer + 12));
1641
+ if (!this.keys.has(keyName)) {
1642
+ this.keys.set(keyName, key);
1643
+ }
1644
+ }
1645
+ }
1646
+ }
1647
+ });
1648
+ }
1591
1649
  getFileDataIDByName(name) {
1592
1650
  assert__default(this.preload, "Client not initialized");
1593
1651
  const { rootFile } = this.preload;
@@ -1641,14 +1699,14 @@ class CASCClient {
1641
1699
  };
1642
1700
  }
1643
1701
  }
1644
- __publicField$1(CASCClient, "LocaleFlags", LocaleFlags);
1645
- __publicField$1(CASCClient, "ContentFlags", ContentFlags);
1646
- __publicField$1(CASCClient, "LogLevel", LogLevel);
1702
+ __publicField$2(CASCClient, "LocaleFlags", LocaleFlags);
1703
+ __publicField$2(CASCClient, "ContentFlags", ContentFlags);
1704
+ __publicField$2(CASCClient, "LogLevel", LogLevel);
1647
1705
 
1648
- var __defProp = Object.defineProperty;
1649
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
1650
- var __publicField = (obj, key, value) => {
1651
- __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
1706
+ var __defProp$1 = Object.defineProperty;
1707
+ var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
1708
+ var __publicField$1 = (obj, key, value) => {
1709
+ __defNormalProp$1(obj, typeof key !== "symbol" ? key + "" : key, value);
1652
1710
  return value;
1653
1711
  };
1654
1712
  const PATTERN_COLUMN = /^(int|float|locstring|string)(<[^:]+::[^>]+>)?\s([^\s]+)/;
@@ -1684,10 +1742,10 @@ const castBigInt64 = (value, srcSigned, dstSigned) => {
1684
1742
  };
1685
1743
  class DBDParser {
1686
1744
  constructor(wdc) {
1687
- __publicField(this, "wdc");
1688
- __publicField(this, "definitions", /* @__PURE__ */ new Map());
1689
- __publicField(this, "columns", []);
1690
- __publicField(this, "cache", /* @__PURE__ */ new Map());
1745
+ __publicField$1(this, "wdc");
1746
+ __publicField$1(this, "definitions", /* @__PURE__ */ new Map());
1747
+ __publicField$1(this, "columns", []);
1748
+ __publicField$1(this, "cache", /* @__PURE__ */ new Map());
1691
1749
  this.wdc = wdc;
1692
1750
  }
1693
1751
  async init() {
@@ -1855,6 +1913,9 @@ class DBDParser {
1855
1913
  if (column.isID) {
1856
1914
  data[column.name] = id;
1857
1915
  if (column.isInline) {
1916
+ const currField = this.wdc.fields[fieldIndex];
1917
+ const size = Math.ceil((column.size ?? 32 - currField.size) / 8);
1918
+ offset += size;
1858
1919
  fieldIndex += 1;
1859
1920
  }
1860
1921
  } else if (column.isInline) {
@@ -1876,7 +1937,7 @@ class DBDParser {
1876
1937
  const size = Math.ceil((column.size ?? 32 - currField.size) / 8);
1877
1938
  let count;
1878
1939
  if (fieldIndex + 1 < this.wdc.fields.length) {
1879
- count = (nextField.position - currField.position) / size;
1940
+ count = Math.max((nextField.position - currField.position) / size, 1);
1880
1941
  } else {
1881
1942
  count = column.arraySize ? (buffer.byteLength - offset) / size : 1;
1882
1943
  }
@@ -1910,6 +1971,58 @@ class DBDParser {
1910
1971
  }
1911
1972
  }
1912
1973
 
1974
+ var __defProp = Object.defineProperty;
1975
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
1976
+ var __publicField = (obj, key, value) => {
1977
+ __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
1978
+ return value;
1979
+ };
1980
+ const ADB_MAGIC = 1481004104;
1981
+ class ADBReader {
1982
+ constructor(buffer) {
1983
+ __publicField(this, "build");
1984
+ __publicField(this, "entries", []);
1985
+ __publicField(this, "tableEntries", /* @__PURE__ */ new Map());
1986
+ const magic = buffer.readUInt32BE(0);
1987
+ assert__default(magic === ADB_MAGIC, `[ADB]: Invalid magic: ${magic.toString(16).padStart(8, "0")}`);
1988
+ const version = buffer.readUInt32LE(4);
1989
+ assert__default(version === 9, `[ADB]: Invalid version: ${version.toString()}`);
1990
+ const build = buffer.readUInt32LE(8);
1991
+ this.build = build;
1992
+ let pointer = 44;
1993
+ while (pointer < buffer.byteLength) {
1994
+ const offset = pointer;
1995
+ const entryMagic = buffer.readUInt32BE(offset);
1996
+ assert__default(entryMagic === ADB_MAGIC, `[ADB]: Invalid entry magic: ${magic.toString(16).padStart(8, "0")}`);
1997
+ const regionID = buffer.readInt32LE(offset + 4);
1998
+ const pushID = buffer.readInt32LE(offset + 8);
1999
+ const uniqueID = buffer.readUInt32LE(offset + 12);
2000
+ const tableHash = buffer.readUInt32LE(offset + 16);
2001
+ const recordID = buffer.readUInt32LE(offset + 20);
2002
+ const dataSize = buffer.readUInt32LE(offset + 24);
2003
+ const recordState = buffer.readUInt32LE(offset + 28);
2004
+ const data = buffer.subarray(offset + 32, offset + 32 + dataSize);
2005
+ const entry = {
2006
+ regionID,
2007
+ pushID,
2008
+ uniqueID,
2009
+ tableHash,
2010
+ recordID,
2011
+ dataSize,
2012
+ recordState,
2013
+ data
2014
+ };
2015
+ this.entries.push(entry);
2016
+ if (!this.tableEntries.has(tableHash)) {
2017
+ this.tableEntries.set(tableHash, []);
2018
+ }
2019
+ this.tableEntries.get(tableHash)?.push(entry);
2020
+ pointer += 32 + dataSize;
2021
+ }
2022
+ }
2023
+ }
2024
+
2025
+ exports.ADBReader = ADBReader;
1913
2026
  exports.CASCClient = CASCClient;
1914
2027
  exports.DBDParser = DBDParser;
1915
2028
  exports.WDCReader = WDCReader;
package/dist/index.d.cts CHANGED
@@ -42,6 +42,23 @@ interface MissingKeyBlock {
42
42
  keyName: string;
43
43
  }
44
44
 
45
+ interface HotfixEntry {
46
+ regionID: number;
47
+ pushID: number;
48
+ uniqueID: number;
49
+ tableHash: number;
50
+ recordID: number;
51
+ dataSize: number;
52
+ recordState: number;
53
+ data: Buffer;
54
+ }
55
+ declare class ADBReader {
56
+ build: number;
57
+ entries: HotfixEntry[];
58
+ tableEntries: Map<number, HotfixEntry[]>;
59
+ constructor(buffer: Buffer);
60
+ }
61
+
45
62
  interface ClientPreloadData {
46
63
  prefixes: string[];
47
64
  archives: ReturnType<typeof parseArchiveIndex>;
@@ -111,6 +128,7 @@ declare class CASCClient {
111
128
  loadRemoteListFile(): Promise<void>;
112
129
  loadRemoteTACTKeys(): Promise<void>;
113
130
  loadTACTKeys(): Promise<void>;
131
+ loadBroadcastTACTKeys(adb: ADBReader): void;
114
132
  getFileDataIDByName(name: string): number | undefined;
115
133
  getContentKeysByFileDataID(fileDataID: number): FileInfo[] | undefined;
116
134
  getFileByContentKey(cKey: string, allowMissingKey?: false): Promise<FileFetchResultFull>;
@@ -192,6 +210,14 @@ interface SparseRow {
192
210
  type: 'sparse';
193
211
  data: Buffer;
194
212
  }
213
+ interface HotfixModify {
214
+ type: 'modify';
215
+ data: Buffer;
216
+ }
217
+ interface HotfixDelete {
218
+ type: 'delete';
219
+ }
220
+ type Hotfix = HotfixModify | HotfixDelete;
195
221
  declare class WDCReader {
196
222
  readonly tableHash: number;
197
223
  readonly layoutHash: number;
@@ -203,7 +229,8 @@ declare class WDCReader {
203
229
  readonly rows: Map<number, SparseRow | ParsedField[]>;
204
230
  readonly relationships: Map<number, number>;
205
231
  readonly copyTable: Map<number, number>;
206
- constructor(buffer: Buffer, blocks?: MissingKeyBlock[]);
232
+ readonly hotfixes: Map<number, Hotfix>;
233
+ constructor(buffer: Buffer, blocks?: MissingKeyBlock[], adb?: ADBReader);
207
234
  getAllIDs(): number[];
208
235
  getRowData(id: number): ParsedField[] | SparseRow | undefined;
209
236
  getRowRelationship(id: number): number | undefined;
@@ -232,4 +259,4 @@ declare class DBDParser {
232
259
  getRowData(id: number): Record<string, ColumnData | ColumnData[]> | undefined;
233
260
  }
234
261
 
235
- export { CASCClient, DBDParser, WDCReader };
262
+ export { ADBReader, CASCClient, DBDParser, WDCReader };
package/dist/index.d.mts CHANGED
@@ -42,6 +42,23 @@ interface MissingKeyBlock {
42
42
  keyName: string;
43
43
  }
44
44
 
45
+ interface HotfixEntry {
46
+ regionID: number;
47
+ pushID: number;
48
+ uniqueID: number;
49
+ tableHash: number;
50
+ recordID: number;
51
+ dataSize: number;
52
+ recordState: number;
53
+ data: Buffer;
54
+ }
55
+ declare class ADBReader {
56
+ build: number;
57
+ entries: HotfixEntry[];
58
+ tableEntries: Map<number, HotfixEntry[]>;
59
+ constructor(buffer: Buffer);
60
+ }
61
+
45
62
  interface ClientPreloadData {
46
63
  prefixes: string[];
47
64
  archives: ReturnType<typeof parseArchiveIndex>;
@@ -111,6 +128,7 @@ declare class CASCClient {
111
128
  loadRemoteListFile(): Promise<void>;
112
129
  loadRemoteTACTKeys(): Promise<void>;
113
130
  loadTACTKeys(): Promise<void>;
131
+ loadBroadcastTACTKeys(adb: ADBReader): void;
114
132
  getFileDataIDByName(name: string): number | undefined;
115
133
  getContentKeysByFileDataID(fileDataID: number): FileInfo[] | undefined;
116
134
  getFileByContentKey(cKey: string, allowMissingKey?: false): Promise<FileFetchResultFull>;
@@ -192,6 +210,14 @@ interface SparseRow {
192
210
  type: 'sparse';
193
211
  data: Buffer;
194
212
  }
213
+ interface HotfixModify {
214
+ type: 'modify';
215
+ data: Buffer;
216
+ }
217
+ interface HotfixDelete {
218
+ type: 'delete';
219
+ }
220
+ type Hotfix = HotfixModify | HotfixDelete;
195
221
  declare class WDCReader {
196
222
  readonly tableHash: number;
197
223
  readonly layoutHash: number;
@@ -203,7 +229,8 @@ declare class WDCReader {
203
229
  readonly rows: Map<number, SparseRow | ParsedField[]>;
204
230
  readonly relationships: Map<number, number>;
205
231
  readonly copyTable: Map<number, number>;
206
- constructor(buffer: Buffer, blocks?: MissingKeyBlock[]);
232
+ readonly hotfixes: Map<number, Hotfix>;
233
+ constructor(buffer: Buffer, blocks?: MissingKeyBlock[], adb?: ADBReader);
207
234
  getAllIDs(): number[];
208
235
  getRowData(id: number): ParsedField[] | SparseRow | undefined;
209
236
  getRowRelationship(id: number): number | undefined;
@@ -232,4 +259,4 @@ declare class DBDParser {
232
259
  getRowData(id: number): Record<string, ColumnData | ColumnData[]> | undefined;
233
260
  }
234
261
 
235
- export { CASCClient, DBDParser, WDCReader };
262
+ export { ADBReader, CASCClient, DBDParser, WDCReader };
package/dist/index.d.ts CHANGED
@@ -42,6 +42,23 @@ interface MissingKeyBlock {
42
42
  keyName: string;
43
43
  }
44
44
 
45
+ interface HotfixEntry {
46
+ regionID: number;
47
+ pushID: number;
48
+ uniqueID: number;
49
+ tableHash: number;
50
+ recordID: number;
51
+ dataSize: number;
52
+ recordState: number;
53
+ data: Buffer;
54
+ }
55
+ declare class ADBReader {
56
+ build: number;
57
+ entries: HotfixEntry[];
58
+ tableEntries: Map<number, HotfixEntry[]>;
59
+ constructor(buffer: Buffer);
60
+ }
61
+
45
62
  interface ClientPreloadData {
46
63
  prefixes: string[];
47
64
  archives: ReturnType<typeof parseArchiveIndex>;
@@ -111,6 +128,7 @@ declare class CASCClient {
111
128
  loadRemoteListFile(): Promise<void>;
112
129
  loadRemoteTACTKeys(): Promise<void>;
113
130
  loadTACTKeys(): Promise<void>;
131
+ loadBroadcastTACTKeys(adb: ADBReader): void;
114
132
  getFileDataIDByName(name: string): number | undefined;
115
133
  getContentKeysByFileDataID(fileDataID: number): FileInfo[] | undefined;
116
134
  getFileByContentKey(cKey: string, allowMissingKey?: false): Promise<FileFetchResultFull>;
@@ -192,6 +210,14 @@ interface SparseRow {
192
210
  type: 'sparse';
193
211
  data: Buffer;
194
212
  }
213
+ interface HotfixModify {
214
+ type: 'modify';
215
+ data: Buffer;
216
+ }
217
+ interface HotfixDelete {
218
+ type: 'delete';
219
+ }
220
+ type Hotfix = HotfixModify | HotfixDelete;
195
221
  declare class WDCReader {
196
222
  readonly tableHash: number;
197
223
  readonly layoutHash: number;
@@ -203,7 +229,8 @@ declare class WDCReader {
203
229
  readonly rows: Map<number, SparseRow | ParsedField[]>;
204
230
  readonly relationships: Map<number, number>;
205
231
  readonly copyTable: Map<number, number>;
206
- constructor(buffer: Buffer, blocks?: MissingKeyBlock[]);
232
+ readonly hotfixes: Map<number, Hotfix>;
233
+ constructor(buffer: Buffer, blocks?: MissingKeyBlock[], adb?: ADBReader);
207
234
  getAllIDs(): number[];
208
235
  getRowData(id: number): ParsedField[] | SparseRow | undefined;
209
236
  getRowRelationship(id: number): number | undefined;
@@ -232,4 +259,4 @@ declare class DBDParser {
232
259
  getRowData(id: number): Record<string, ColumnData | ColumnData[]> | undefined;
233
260
  }
234
261
 
235
- export { CASCClient, DBDParser, WDCReader };
262
+ export { ADBReader, CASCClient, DBDParser, WDCReader };
package/dist/index.mjs CHANGED
@@ -7,17 +7,17 @@ import path from 'node:path';
7
7
  import http from 'node:http';
8
8
  import zlib from 'node:zlib';
9
9
 
10
- var __defProp$5 = Object.defineProperty;
11
- var __defNormalProp$5 = (obj, key, value) => key in obj ? __defProp$5(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
12
- var __publicField$5 = (obj, key, value) => {
13
- __defNormalProp$5(obj, typeof key !== "symbol" ? key + "" : key, value);
10
+ var __defProp$6 = Object.defineProperty;
11
+ var __defNormalProp$6 = (obj, key, value) => key in obj ? __defProp$6(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
12
+ var __publicField$6 = (obj, key, value) => {
13
+ __defNormalProp$6(obj, typeof key !== "symbol" ? key + "" : key, value);
14
14
  return value;
15
15
  };
16
16
  class Store {
17
17
  constructor(dataFile) {
18
- __publicField$5(this, "data");
19
- __publicField$5(this, "dataFile");
20
- __publicField$5(this, "promise");
18
+ __publicField$6(this, "data");
19
+ __publicField$6(this, "dataFile");
20
+ __publicField$6(this, "promise");
21
21
  this.dataFile = dataFile;
22
22
  this.data = {};
23
23
  this.promise = new Promise((resolve) => {
@@ -282,21 +282,21 @@ const parseArchiveIndex = (buffer, cKey) => {
282
282
  return result;
283
283
  };
284
284
 
285
- var __defProp$4 = Object.defineProperty;
286
- var __defNormalProp$4 = (obj, key, value) => key in obj ? __defProp$4(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
287
- var __publicField$4 = (obj, key, value) => {
288
- __defNormalProp$4(obj, typeof key !== "symbol" ? key + "" : key, value);
285
+ var __defProp$5 = Object.defineProperty;
286
+ var __defNormalProp$5 = (obj, key, value) => key in obj ? __defProp$5(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
287
+ var __publicField$5 = (obj, key, value) => {
288
+ __defNormalProp$5(obj, typeof key !== "symbol" ? key + "" : key, value);
289
289
  return value;
290
290
  };
291
291
  class Salsa20 {
292
292
  constructor(key, nonce) {
293
- __publicField$4(this, "fixed");
294
- __publicField$4(this, "key");
295
- __publicField$4(this, "nonce");
296
- __publicField$4(this, "counter", new Uint32Array([0, 0]));
297
- __publicField$4(this, "state", new Uint32Array(16));
298
- __publicField$4(this, "block", new Uint8Array(64));
299
- __publicField$4(this, "position", 0);
293
+ __publicField$5(this, "fixed");
294
+ __publicField$5(this, "key");
295
+ __publicField$5(this, "nonce");
296
+ __publicField$5(this, "counter", new Uint32Array([0, 0]));
297
+ __publicField$5(this, "state", new Uint32Array(16));
298
+ __publicField$5(this, "block", new Uint8Array(64));
299
+ __publicField$5(this, "position", 0);
300
300
  assert(key.length === 32 || key.length === 16, "Salsa20 requires 128-bit or 256-bit key");
301
301
  assert(nonce.length === 8, "Salsa20 requires 64-bit nonce");
302
302
  this.key = new Uint32Array(8);
@@ -399,10 +399,10 @@ class Salsa20 {
399
399
  }
400
400
  }
401
401
 
402
- var __defProp$3 = Object.defineProperty;
403
- var __defNormalProp$3 = (obj, key, value) => key in obj ? __defProp$3(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
404
- var __publicField$3 = (obj, key, value) => {
405
- __defNormalProp$3(obj, typeof key !== "symbol" ? key + "" : key, value);
402
+ var __defProp$4 = Object.defineProperty;
403
+ var __defNormalProp$4 = (obj, key, value) => key in obj ? __defProp$4(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
404
+ var __publicField$4 = (obj, key, value) => {
405
+ __defNormalProp$4(obj, typeof key !== "symbol" ? key + "" : key, value);
406
406
  return value;
407
407
  };
408
408
  const BLTE_MAGIC = 1112298565;
@@ -410,12 +410,12 @@ const ENC_TYPE_SALSA20 = 83;
410
410
  const EMPTY_HASH = "00000000000000000000000000000000";
411
411
  class BLTEReader {
412
412
  constructor(buffer, eKey, keys = /* @__PURE__ */ new Map()) {
413
- __publicField$3(this, "buffer");
414
- __publicField$3(this, "blte");
415
- __publicField$3(this, "blocks", []);
416
- __publicField$3(this, "keys");
417
- __publicField$3(this, "processedBlock", 0);
418
- __publicField$3(this, "processedOffset", 0);
413
+ __publicField$4(this, "buffer");
414
+ __publicField$4(this, "blte");
415
+ __publicField$4(this, "blocks", []);
416
+ __publicField$4(this, "keys");
417
+ __publicField$4(this, "processedBlock", 0);
418
+ __publicField$4(this, "processedOffset", 0);
419
419
  this.blte = buffer;
420
420
  this.buffer = Buffer.alloc(0);
421
421
  this.keys = keys;
@@ -883,10 +883,10 @@ const getNameHash = (name) => {
883
883
  return `${pc.toString(16).padStart(8, "0")}${pb.toString(16).padStart(8, "0")}`;
884
884
  };
885
885
 
886
- var __defProp$2 = Object.defineProperty;
887
- var __defNormalProp$2 = (obj, key, value) => key in obj ? __defProp$2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
888
- var __publicField$2 = (obj, key, value) => {
889
- __defNormalProp$2(obj, typeof key !== "symbol" ? key + "" : key, value);
886
+ var __defProp$3 = Object.defineProperty;
887
+ var __defNormalProp$3 = (obj, key, value) => key in obj ? __defProp$3(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
888
+ var __publicField$3 = (obj, key, value) => {
889
+ __defNormalProp$3(obj, typeof key !== "symbol" ? key + "" : key, value);
890
890
  return value;
891
891
  };
892
892
  const WDC5_MAGIC = 1464091445;
@@ -912,17 +912,18 @@ const readBitpackedValue = (buffer, fieldOffsetBits, fieldSizeBits, signed = fal
912
912
  return signed ? BigInt.asIntN(fieldSizeBits, value >> BigInt(bitOffset)) : BigInt.asUintN(fieldSizeBits, value >> BigInt(bitOffset));
913
913
  };
914
914
  class WDCReader {
915
- constructor(buffer, blocks = []) {
916
- __publicField$2(this, "tableHash");
917
- __publicField$2(this, "layoutHash");
918
- __publicField$2(this, "locale");
919
- __publicField$2(this, "isNormal");
920
- __publicField$2(this, "hasRelationshipData");
921
- __publicField$2(this, "fields");
922
- __publicField$2(this, "fieldsInfo");
923
- __publicField$2(this, "rows", /* @__PURE__ */ new Map());
924
- __publicField$2(this, "relationships", /* @__PURE__ */ new Map());
925
- __publicField$2(this, "copyTable", /* @__PURE__ */ new Map());
915
+ constructor(buffer, blocks = [], adb) {
916
+ __publicField$3(this, "tableHash");
917
+ __publicField$3(this, "layoutHash");
918
+ __publicField$3(this, "locale");
919
+ __publicField$3(this, "isNormal");
920
+ __publicField$3(this, "hasRelationshipData");
921
+ __publicField$3(this, "fields");
922
+ __publicField$3(this, "fieldsInfo");
923
+ __publicField$3(this, "rows", /* @__PURE__ */ new Map());
924
+ __publicField$3(this, "relationships", /* @__PURE__ */ new Map());
925
+ __publicField$3(this, "copyTable", /* @__PURE__ */ new Map());
926
+ __publicField$3(this, "hotfixes", /* @__PURE__ */ new Map());
926
927
  const magic = buffer.readUInt32BE(0);
927
928
  const fieldCount = buffer.readUInt32LE(140);
928
929
  const recordSize = buffer.readUInt32LE(144);
@@ -1327,11 +1328,43 @@ class WDCReader {
1327
1328
  }
1328
1329
  }
1329
1330
  });
1331
+ const entries = adb?.tableEntries.get(tableHash);
1332
+ entries?.filter((entry) => entry.pushID !== -1).sort((a, b) => a.pushID - b.pushID).forEach((entry) => {
1333
+ switch (entry.recordState) {
1334
+ case 1:
1335
+ this.hotfixes.set(entry.recordID, { type: "modify", data: entry.data });
1336
+ break;
1337
+ case 2:
1338
+ this.hotfixes.set(entry.recordID, { type: "delete" });
1339
+ break;
1340
+ case 3:
1341
+ this.hotfixes.delete(entry.recordID);
1342
+ break;
1343
+ case 4:
1344
+ break;
1345
+ default:
1346
+ throw new Error(`Unknown record state: ${entry.recordState.toString()}`);
1347
+ }
1348
+ });
1330
1349
  }
1331
1350
  getAllIDs() {
1332
1351
  return [...this.rows.keys(), ...this.copyTable.keys()];
1333
1352
  }
1334
1353
  getRowData(id) {
1354
+ const hotfix = this.hotfixes.get(id);
1355
+ if (hotfix) {
1356
+ switch (hotfix.type) {
1357
+ case "modify":
1358
+ return {
1359
+ type: "sparse",
1360
+ data: hotfix.data
1361
+ };
1362
+ case "delete":
1363
+ return void 0;
1364
+ default:
1365
+ throw new Error("Unreachable");
1366
+ }
1367
+ }
1335
1368
  const dst = this.copyTable.get(id);
1336
1369
  if (dst) {
1337
1370
  return this.rows.get(dst);
@@ -1393,10 +1426,10 @@ const formatFileSize = (input) => {
1393
1426
  return result.join(" ");
1394
1427
  };
1395
1428
 
1396
- var __defProp$1 = Object.defineProperty;
1397
- var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
1398
- var __publicField$1 = (obj, key, value) => {
1399
- __defNormalProp$1(obj, typeof key !== "symbol" ? key + "" : key, value);
1429
+ var __defProp$2 = Object.defineProperty;
1430
+ var __defNormalProp$2 = (obj, key, value) => key in obj ? __defProp$2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
1431
+ var __publicField$2 = (obj, key, value) => {
1432
+ __defNormalProp$2(obj, typeof key !== "symbol" ? key + "" : key, value);
1400
1433
  return value;
1401
1434
  };
1402
1435
  var LogLevel = /* @__PURE__ */ ((LogLevel2) => {
@@ -1409,13 +1442,13 @@ var LogLevel = /* @__PURE__ */ ((LogLevel2) => {
1409
1442
  const textLogLevel = ["ERROR", "WARN", "INFO", "DEBUG"];
1410
1443
  class CASCClient {
1411
1444
  constructor(region, product, version, logLevel = 2 /* info */) {
1412
- __publicField$1(this, "region");
1413
- __publicField$1(this, "product");
1414
- __publicField$1(this, "version");
1415
- __publicField$1(this, "name2FileDataID", /* @__PURE__ */ new Map());
1416
- __publicField$1(this, "keys", /* @__PURE__ */ new Map());
1417
- __publicField$1(this, "preload");
1418
- __publicField$1(this, "logLevel");
1445
+ __publicField$2(this, "region");
1446
+ __publicField$2(this, "product");
1447
+ __publicField$2(this, "version");
1448
+ __publicField$2(this, "name2FileDataID", /* @__PURE__ */ new Map());
1449
+ __publicField$2(this, "keys", /* @__PURE__ */ new Map());
1450
+ __publicField$2(this, "preload");
1451
+ __publicField$2(this, "logLevel");
1419
1452
  this.region = region;
1420
1453
  this.product = product;
1421
1454
  this.version = version;
@@ -1560,7 +1593,7 @@ class CASCClient {
1560
1593
  ]);
1561
1594
  const keysReader = new WDCReader(keysResult.buffer);
1562
1595
  const lookupReader = new WDCReader(lookupResult.buffer);
1563
- [...lookupReader.rows.keys()].forEach((keyID) => {
1596
+ lookupReader.getAllIDs().forEach((keyID) => {
1564
1597
  const lookupRow = lookupReader.rows.get(keyID);
1565
1598
  const keyRow = keysReader.rows.get(keyID);
1566
1599
  if (keyRow) {
@@ -1576,6 +1609,31 @@ class CASCClient {
1576
1609
  }
1577
1610
  });
1578
1611
  }
1612
+ loadBroadcastTACTKeys(adb) {
1613
+ adb.tableEntries.get(35137211)?.forEach(({ data }) => {
1614
+ if (data.byteLength > 0) {
1615
+ let pointer = 0;
1616
+ while (data[pointer] !== 0) {
1617
+ pointer += 1;
1618
+ }
1619
+ pointer += 1;
1620
+ while (data[pointer] !== 0) {
1621
+ pointer += 1;
1622
+ }
1623
+ pointer += 1 + 43;
1624
+ if (pointer < data.byteLength) {
1625
+ const extraTableHash = data.readUInt32LE(pointer);
1626
+ if (extraTableHash === 3744420815) {
1627
+ const keyName = data.readBigUInt64LE(pointer + 4).toString(16).padStart(16, "0");
1628
+ const key = Uint8Array.from(data.subarray(pointer + 12));
1629
+ if (!this.keys.has(keyName)) {
1630
+ this.keys.set(keyName, key);
1631
+ }
1632
+ }
1633
+ }
1634
+ }
1635
+ });
1636
+ }
1579
1637
  getFileDataIDByName(name) {
1580
1638
  assert(this.preload, "Client not initialized");
1581
1639
  const { rootFile } = this.preload;
@@ -1629,14 +1687,14 @@ class CASCClient {
1629
1687
  };
1630
1688
  }
1631
1689
  }
1632
- __publicField$1(CASCClient, "LocaleFlags", LocaleFlags);
1633
- __publicField$1(CASCClient, "ContentFlags", ContentFlags);
1634
- __publicField$1(CASCClient, "LogLevel", LogLevel);
1690
+ __publicField$2(CASCClient, "LocaleFlags", LocaleFlags);
1691
+ __publicField$2(CASCClient, "ContentFlags", ContentFlags);
1692
+ __publicField$2(CASCClient, "LogLevel", LogLevel);
1635
1693
 
1636
- var __defProp = Object.defineProperty;
1637
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
1638
- var __publicField = (obj, key, value) => {
1639
- __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
1694
+ var __defProp$1 = Object.defineProperty;
1695
+ var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
1696
+ var __publicField$1 = (obj, key, value) => {
1697
+ __defNormalProp$1(obj, typeof key !== "symbol" ? key + "" : key, value);
1640
1698
  return value;
1641
1699
  };
1642
1700
  const PATTERN_COLUMN = /^(int|float|locstring|string)(<[^:]+::[^>]+>)?\s([^\s]+)/;
@@ -1672,10 +1730,10 @@ const castBigInt64 = (value, srcSigned, dstSigned) => {
1672
1730
  };
1673
1731
  class DBDParser {
1674
1732
  constructor(wdc) {
1675
- __publicField(this, "wdc");
1676
- __publicField(this, "definitions", /* @__PURE__ */ new Map());
1677
- __publicField(this, "columns", []);
1678
- __publicField(this, "cache", /* @__PURE__ */ new Map());
1733
+ __publicField$1(this, "wdc");
1734
+ __publicField$1(this, "definitions", /* @__PURE__ */ new Map());
1735
+ __publicField$1(this, "columns", []);
1736
+ __publicField$1(this, "cache", /* @__PURE__ */ new Map());
1679
1737
  this.wdc = wdc;
1680
1738
  }
1681
1739
  async init() {
@@ -1843,6 +1901,9 @@ class DBDParser {
1843
1901
  if (column.isID) {
1844
1902
  data[column.name] = id;
1845
1903
  if (column.isInline) {
1904
+ const currField = this.wdc.fields[fieldIndex];
1905
+ const size = Math.ceil((column.size ?? 32 - currField.size) / 8);
1906
+ offset += size;
1846
1907
  fieldIndex += 1;
1847
1908
  }
1848
1909
  } else if (column.isInline) {
@@ -1864,7 +1925,7 @@ class DBDParser {
1864
1925
  const size = Math.ceil((column.size ?? 32 - currField.size) / 8);
1865
1926
  let count;
1866
1927
  if (fieldIndex + 1 < this.wdc.fields.length) {
1867
- count = (nextField.position - currField.position) / size;
1928
+ count = Math.max((nextField.position - currField.position) / size, 1);
1868
1929
  } else {
1869
1930
  count = column.arraySize ? (buffer.byteLength - offset) / size : 1;
1870
1931
  }
@@ -1898,4 +1959,55 @@ class DBDParser {
1898
1959
  }
1899
1960
  }
1900
1961
 
1901
- export { CASCClient, DBDParser, WDCReader };
1962
+ var __defProp = Object.defineProperty;
1963
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
1964
+ var __publicField = (obj, key, value) => {
1965
+ __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
1966
+ return value;
1967
+ };
1968
+ const ADB_MAGIC = 1481004104;
1969
+ class ADBReader {
1970
+ constructor(buffer) {
1971
+ __publicField(this, "build");
1972
+ __publicField(this, "entries", []);
1973
+ __publicField(this, "tableEntries", /* @__PURE__ */ new Map());
1974
+ const magic = buffer.readUInt32BE(0);
1975
+ assert(magic === ADB_MAGIC, `[ADB]: Invalid magic: ${magic.toString(16).padStart(8, "0")}`);
1976
+ const version = buffer.readUInt32LE(4);
1977
+ assert(version === 9, `[ADB]: Invalid version: ${version.toString()}`);
1978
+ const build = buffer.readUInt32LE(8);
1979
+ this.build = build;
1980
+ let pointer = 44;
1981
+ while (pointer < buffer.byteLength) {
1982
+ const offset = pointer;
1983
+ const entryMagic = buffer.readUInt32BE(offset);
1984
+ assert(entryMagic === ADB_MAGIC, `[ADB]: Invalid entry magic: ${magic.toString(16).padStart(8, "0")}`);
1985
+ const regionID = buffer.readInt32LE(offset + 4);
1986
+ const pushID = buffer.readInt32LE(offset + 8);
1987
+ const uniqueID = buffer.readUInt32LE(offset + 12);
1988
+ const tableHash = buffer.readUInt32LE(offset + 16);
1989
+ const recordID = buffer.readUInt32LE(offset + 20);
1990
+ const dataSize = buffer.readUInt32LE(offset + 24);
1991
+ const recordState = buffer.readUInt32LE(offset + 28);
1992
+ const data = buffer.subarray(offset + 32, offset + 32 + dataSize);
1993
+ const entry = {
1994
+ regionID,
1995
+ pushID,
1996
+ uniqueID,
1997
+ tableHash,
1998
+ recordID,
1999
+ dataSize,
2000
+ recordState,
2001
+ data
2002
+ };
2003
+ this.entries.push(entry);
2004
+ if (!this.tableEntries.has(tableHash)) {
2005
+ this.tableEntries.set(tableHash, []);
2006
+ }
2007
+ this.tableEntries.get(tableHash)?.push(entry);
2008
+ pointer += 32 + dataSize;
2009
+ }
2010
+ }
2011
+ }
2012
+
2013
+ export { ADBReader, CASCClient, DBDParser, WDCReader };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rhyster/wow-casc-dbc",
3
- "version": "2.3.0",
3
+ "version": "2.4.0",
4
4
  "description": "Fetch World of Warcraft data files from CASC and parse DBC/DB2 files.",
5
5
  "type": "module",
6
6
  "exports": {
@@ -41,14 +41,14 @@
41
41
  "@types/cli-progress": "^3.11.5",
42
42
  "@types/jest": "^29.5.12",
43
43
  "@types/node": "^20.12.7",
44
- "@typescript-eslint/eslint-plugin": "^7.7.1",
45
- "@typescript-eslint/parser": "^7.7.1",
44
+ "@typescript-eslint/eslint-plugin": "^7.8.0",
45
+ "@typescript-eslint/parser": "^7.8.0",
46
46
  "eslint": "^8.57.0",
47
47
  "eslint-config-airbnb-base": "^15.0.0",
48
48
  "eslint-config-airbnb-typescript": "^18.0.0",
49
49
  "jest": "^29.7.0",
50
50
  "ts-jest": "^29.1.2",
51
- "ts-node": "^10.9.2",
51
+ "tsx": "^4.7.3",
52
52
  "typescript": "^5.4.5",
53
53
  "unbuild": "^2.0.0"
54
54
  },