@gaialabs/core 0.2.12 → 0.2.13

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/dist/index.mjs CHANGED
@@ -935,10 +935,12 @@ var ProcessorStateManager = class {
935
935
  var RomDataReader = class {
936
936
  romData;
937
937
  position;
938
- constructor(romData) {
938
+ offset;
939
+ constructor(romData, offset = 0) {
939
940
  if (!romData) throw new Error("romData cannot be null");
940
941
  this.romData = romData;
941
942
  this.position = 0;
943
+ this.offset = offset;
942
944
  }
943
945
  readByte() {
944
946
  return this.romData[this.position++];
@@ -1670,31 +1672,63 @@ var ChunkFile = class {
1670
1672
  mnemonics;
1671
1673
  group;
1672
1674
  scene;
1673
- constructor(name, size, location, type) {
1675
+ base;
1676
+ referenceManager;
1677
+ constructor(type, name, size = 0, location = 0) {
1678
+ this.type = type;
1674
1679
  this.name = name;
1675
1680
  this.size = size;
1676
1681
  this.location = location;
1677
1682
  this.mnemonics = {};
1678
1683
  this.compressed = type.compressed;
1679
- this.type = type;
1684
+ }
1685
+ enrichWithRawDataFromDbFile(file, rom, compression) {
1686
+ this.upper = file.upper ?? this.upper;
1687
+ this.size = file.end - file.start;
1688
+ this.location = file.start;
1689
+ this.base = file.base ?? this.type.base ?? this.base;
1690
+ this.group = file.group ?? this.group;
1691
+ this.scene = file.scene ?? this.scene;
1692
+ this.compressed = file.compressed;
1693
+ let start = this.location;
1694
+ let header = null;
1695
+ const fileType = this.type;
1696
+ if (fileType.header) {
1697
+ header = new Uint8Array(rom.slice(start, start + fileType.header));
1698
+ start += fileType.header;
1699
+ }
1700
+ let length = this.size;
1701
+ let fileData;
1702
+ if (this.compressed === true && compression) {
1703
+ const expanded = compression.expand(rom, start, length);
1704
+ fileData = combineHeader(expanded, 0, expanded.length, header, fileType.type);
1705
+ } else {
1706
+ if (this.compressed !== void 0) {
1707
+ start += 2;
1708
+ length -= 2;
1709
+ }
1710
+ fileData = combineHeader(rom, start, length, header, fileType.type);
1711
+ }
1712
+ this.rawData = fileData;
1713
+ this.size = fileData.length;
1714
+ }
1715
+ enrichWithAsmBlocksFromDbBlock(block, memoryMode) {
1716
+ this.group = block.group;
1717
+ this.scene = block.scene;
1718
+ this.parts = [];
1719
+ this.size = 0;
1720
+ if (!block.parts?.length) throw new Error(`Block ${block.name} has no parts`);
1721
+ this.location = block.parts[0].start;
1722
+ this.bank = block.movable ? void 0 : memoryMode === MemoryMapMode.Lo ? this.location >> 15 : this.location >> 16;
1723
+ this.transforms = block.transforms;
1724
+ this.postProcess = block.postProcess;
1725
+ for (const part of block.parts) {
1726
+ const asmBlock = new AsmBlock(part.start, part.end - part.start, false, part.name, part.type || void 0, part.bank);
1727
+ this.size += asmBlock.size;
1728
+ this.parts.push(asmBlock);
1729
+ }
1680
1730
  }
1681
1731
  };
1682
- function createChunkFileFromDbFile(rom, compression, dbFile, fileType) {
1683
- const chunkFile = new ChunkFile(dbFile.name, dbFile.end - dbFile.start, dbFile.start, fileType);
1684
- chunkFile.compressed = dbFile.compressed;
1685
- chunkFile.upper = dbFile.upper;
1686
- chunkFile.group = dbFile.group;
1687
- chunkFile.scene = dbFile.scene;
1688
- enrichWithRawDataFromDbFile(rom, chunkFile, compression, dbFile, fileType);
1689
- return chunkFile;
1690
- }
1691
- function createChunkFileFromDbBlock(block, fileType, memoryMode) {
1692
- const chunkFile = new ChunkFile(block.name, 0, 0, fileType);
1693
- chunkFile.group = block.group;
1694
- chunkFile.scene = block.scene;
1695
- enrichWithPartsFromDbBlock(chunkFile, block, memoryMode);
1696
- return chunkFile;
1697
- }
1698
1732
  function combineHeader(data, position, length, header, type) {
1699
1733
  let totalLength = length + (header ? header.length : 0);
1700
1734
  if (type === BinType.Palette && length < 512) totalLength += 512 - length;
@@ -1710,48 +1744,6 @@ function combineHeader(data, position, length, header, type) {
1710
1744
  return result;
1711
1745
  }
1712
1746
  /**
1713
- * Enriches ChunkFile with raw binary data from DbFile
1714
- */
1715
- function enrichWithRawDataFromDbFile(rom, chunkFile, compression, dbFile, fileType) {
1716
- let start = dbFile.start;
1717
- let header = null;
1718
- if (fileType.header) {
1719
- header = new Uint8Array(rom.slice(start, start + fileType.header));
1720
- start += fileType.header;
1721
- }
1722
- let length = dbFile.end - start;
1723
- let fileData;
1724
- if (dbFile.compressed === true && compression) {
1725
- const expanded = compression.expand(rom, start, length);
1726
- fileData = combineHeader(expanded, 0, expanded.length, header, fileType.type);
1727
- } else {
1728
- if (dbFile.compressed !== void 0) {
1729
- start += 2;
1730
- length -= 2;
1731
- }
1732
- fileData = combineHeader(rom, start, length, header, fileType.type);
1733
- }
1734
- chunkFile.rawData = fileData;
1735
- chunkFile.size = fileData.length;
1736
- }
1737
- /**
1738
- * Enriches ChunkFile with AsmBlock parts from DbBlock
1739
- */
1740
- function enrichWithPartsFromDbBlock(chunkFile, block, memoryMode) {
1741
- chunkFile.parts = [];
1742
- chunkFile.size = 0;
1743
- if (!block.parts?.length) throw new Error(`Block ${block.name} has no parts`);
1744
- chunkFile.location = block.parts[0].start;
1745
- chunkFile.bank = block.movable ? void 0 : memoryMode === MemoryMapMode.Lo ? chunkFile.location >> 15 : chunkFile.location >> 16;
1746
- chunkFile.transforms = block.transforms;
1747
- chunkFile.postProcess = block.postProcess;
1748
- for (const part of block.parts) {
1749
- const asmBlock = new AsmBlock(part.start, part.end - part.start, false, part.name, part.type || void 0, part.bank);
1750
- chunkFile.size += asmBlock.size;
1751
- chunkFile.parts.push(asmBlock);
1752
- }
1753
- }
1754
- /**
1755
1747
  * Chunk file utilities
1756
1748
  */
1757
1749
  var ChunkFileUtils = class {
@@ -1773,16 +1765,11 @@ var ChunkFileUtils = class {
1773
1765
  * Calculate the total size of all blocks
1774
1766
  */
1775
1767
  static calculateSize(chunkFile) {
1776
- if (!chunkFile.parts) {
1777
- let size = chunkFile.rawData?.length ?? chunkFile.size;
1778
- if (chunkFile.type.header === -2 || chunkFile.compressed === false) {
1779
- size += 2;
1780
- chunkFile.size = size;
1781
- }
1782
- return size;
1783
- }
1784
1768
  let size = 0;
1785
- for (let x = 0; x < chunkFile.parts.length; x++) {
1769
+ if (chunkFile.rawData) {
1770
+ size = chunkFile.rawData.length;
1771
+ if (chunkFile.type.header === -2 || chunkFile.compressed === false) size += 2;
1772
+ } else if (chunkFile.parts) for (let x = 0; x < chunkFile.parts.length; x++) {
1786
1773
  const block = chunkFile.parts[x];
1787
1774
  if (x > 0 && !block.label) break;
1788
1775
  size += block.size || 0;
@@ -1801,7 +1788,7 @@ var ChunkFileUtils = class {
1801
1788
  block,
1802
1789
  part
1803
1790
  ];
1804
- for (const otherBlock of root) if (otherBlock !== block) {
1791
+ for (const otherBlock of root) if (otherBlock !== block && !otherBlock.type.struct) {
1805
1792
  const [otherIsInside, otherPart] = this.isInsideWithPart(otherBlock, location);
1806
1793
  if (otherIsInside) return [
1807
1794
  true,
@@ -3092,7 +3079,7 @@ var StringReader = class StringReader {
3092
3079
  if (isNaN(sloc)) break;
3093
3080
  if (new Address(sloc >> 16 & 255, sloc & 65535, this._blockReader._root.config.memoryMode).isROM) {
3094
3081
  this._blockReader.resolveInclude(sloc, false);
3095
- const name = this._blockReader.resolveName(sloc, AddressType.Unknown, false);
3082
+ const name = this._blockReader._referenceManager.resolveName(sloc, AddressType.Unknown, false);
3096
3083
  const opix = indexOfAny(name, RomProcessingConstants.OPERATORS);
3097
3084
  if (opix > 0) {
3098
3085
  const offsetStr = name.substring(opix + 1);
@@ -3221,15 +3208,16 @@ var TypeParser = class {
3221
3208
  }
3222
3209
  parseLocation(offset, bank, typeName, addrType) {
3223
3210
  if ((bank === void 0 || bank === null) && offset === 0) return new Word(offset);
3211
+ offset -= this._romDataReader.offset;
3224
3212
  let adrs;
3225
3213
  let loc;
3226
- if (addrType === AddressType.Location) loc = offset | bank << 16;
3214
+ if (addrType === AddressType.Location || this._romDataReader.offset) loc = offset | bank << 16;
3227
3215
  else {
3228
3216
  adrs = new Address(bank ?? Address.resolveBank(this._romDataReader.position, this._blockReader._root.config.memoryMode), offset, this._blockReader._root.config.memoryMode);
3229
3217
  if (!adrs.isROM) return adrs;
3230
3218
  loc = adrs.toLocation();
3231
3219
  }
3232
- if (typeName && !this._blockReader._root.rewrites[loc]) {
3220
+ if (typeName && (this._romDataReader.offset || !this._blockReader._root.rewrites[loc])) {
3233
3221
  const oldStruct = this._referenceManager.structTable.get(loc);
3234
3222
  if (!oldStruct || oldStruct === "Branch") this._referenceManager.structTable.set(loc, typeName);
3235
3223
  const referenceName = `${typeName.toLowerCase()}_${loc.toString(16).toUpperCase().padStart(6, "0")}`;
@@ -3420,8 +3408,6 @@ var BlockReader = class {
3420
3408
  this._stringReader = new StringReader(this);
3421
3409
  this._asmReader = new AsmReader(this);
3422
3410
  this._typeParser = new TypeParser(this);
3423
- this.initializeOverrides();
3424
- this.initializeFileReferences();
3425
3411
  }
3426
3412
  /**
3427
3413
  * Processes predefined overrides for registers and bank notes
@@ -3471,9 +3457,6 @@ var BlockReader = class {
3471
3457
  /**
3472
3458
  * Resolves name for a location (delegated to ReferenceManager)
3473
3459
  */
3474
- resolveName(location, type, isBranch) {
3475
- return this._referenceManager.resolveName(location, type, isBranch);
3476
- }
3477
3460
  /**
3478
3461
  * Resolves include for a location
3479
3462
  */
@@ -3534,6 +3517,8 @@ var BlockReader = class {
3534
3517
  }
3535
3518
  analyzeAndResolve() {
3536
3519
  console.log("analyzeAndResolve started");
3520
+ this.initializeOverrides();
3521
+ this.initializeFileReferences();
3537
3522
  this.createChunkFilesFromDatabase();
3538
3523
  this.initializeBlocksAndParts();
3539
3524
  this.analyzeChunkFiles();
@@ -3648,7 +3633,7 @@ var BlockReader = class {
3648
3633
  const size = getSize();
3649
3634
  const startPos = pos + offset;
3650
3635
  const data = getBytes(size);
3651
- const chunk = new ChunkFile(`sfx${i.toString(16).toUpperCase().padStart(2, "0")}`, size, startPos, fileType);
3636
+ const chunk = new ChunkFile(fileType, `sfx${i.toString(16).toUpperCase().padStart(2, "0")}`, size, startPos);
3652
3637
  chunk.rawData = data;
3653
3638
  chunk.group = "sfx";
3654
3639
  this._enrichedChunks.push(chunk);
@@ -3659,7 +3644,9 @@ var BlockReader = class {
3659
3644
  */
3660
3645
  createChunkFilesFromDbFiles() {
3661
3646
  for (const dbFile of this._root.files) {
3662
- const chunkFile = createChunkFileFromDbFile(this._romDataReader.romData, this._root.compression, dbFile, this._root.fileTypes[dbFile.type]);
3647
+ const fileType = this._root.fileTypes[dbFile.type];
3648
+ const chunkFile = new ChunkFile(fileType, dbFile.name);
3649
+ chunkFile.enrichWithRawDataFromDbFile(dbFile, this._romDataReader.romData, this._root.compression);
3663
3650
  this._enrichedChunks.push(chunkFile);
3664
3651
  }
3665
3652
  }
@@ -3669,7 +3656,8 @@ var BlockReader = class {
3669
3656
  createChunkFilesFromDbBlocks() {
3670
3657
  const fileType = Object.values(this._root.fileTypes).find((x) => x.isBlock);
3671
3658
  for (const block of this._root.blocks) {
3672
- const chunkFile = createChunkFileFromDbBlock(block, fileType, this._root.config.memoryMode);
3659
+ const chunkFile = new ChunkFile(fileType, block.name);
3660
+ chunkFile.enrichWithAsmBlocksFromDbBlock(block, this._root.config.memoryMode);
3673
3661
  this._enrichedChunks.push(chunkFile);
3674
3662
  }
3675
3663
  }
@@ -3678,14 +3666,32 @@ var BlockReader = class {
3678
3666
  */
3679
3667
  analyzeChunkFiles() {
3680
3668
  console.log("analyzeChunkFiles");
3681
- const assemblyChunks = this._enrichedChunks.filter((chunk) => chunk.type.type === "Assembly");
3682
- for (const chunkFile of assemblyChunks) {
3669
+ for (const chunkFile of this._enrichedChunks) {
3670
+ if (!chunkFile.type.isBlock) continue;
3671
+ chunkFile.referenceManager = this._referenceManager;
3683
3672
  this._currentChunk = chunkFile;
3684
3673
  for (const asmBlock of chunkFile.parts || []) {
3685
3674
  this._currentAsmBlock = asmBlock;
3686
3675
  this.processPart(asmBlock);
3687
3676
  }
3688
3677
  }
3678
+ const oldState = this._referenceManager;
3679
+ const oldReader = this._romDataReader;
3680
+ const oldTypeParser = this._typeParser;
3681
+ for (const chunkFile of this._enrichedChunks) {
3682
+ if (!chunkFile.type.struct) continue;
3683
+ this._currentChunk = chunkFile;
3684
+ const asmBlock = new AsmBlock(0, chunkFile.size, false, chunkFile.name, chunkFile.type.struct);
3685
+ chunkFile.parts = [asmBlock];
3686
+ this._currentAsmBlock = asmBlock;
3687
+ this._referenceManager = chunkFile.referenceManager = new ReferenceManager(this._root);
3688
+ this._romDataReader = new RomDataReader(chunkFile.rawData, chunkFile.base ?? 0);
3689
+ this._typeParser = new TypeParser(this);
3690
+ this.processPart(asmBlock);
3691
+ }
3692
+ this._referenceManager = oldState;
3693
+ this._romDataReader = oldReader;
3694
+ this._typeParser = oldTypeParser;
3689
3695
  }
3690
3696
  /**
3691
3697
  * Resolves references in assembly ChunkFiles only
@@ -3693,8 +3699,9 @@ var BlockReader = class {
3693
3699
  resolveReferences() {
3694
3700
  console.log("resolveReferences");
3695
3701
  for (const chunkFile of this._enrichedChunks) {
3702
+ if (!chunkFile.type.isBlock) continue;
3696
3703
  this._currentChunk = chunkFile;
3697
- for (const asmBlock of chunkFile.parts || []) {
3704
+ for (const asmBlock of chunkFile.parts) {
3698
3705
  this._currentAsmBlock = asmBlock;
3699
3706
  this.resolveObject(asmBlock.objList, false);
3700
3707
  }
@@ -3884,6 +3891,7 @@ var BlockWriter = class {
3884
3891
  generateAsm(block) {
3885
3892
  if (!block.parts) throw new Error("Invalid block structure for generateAsm");
3886
3893
  const lines = [];
3894
+ this._referenceManager = block.referenceManager;
3887
3895
  if (block.bank !== void 0) lines.push(`?BANK ${block.bank.toString(16).toUpperCase().padStart(2, "0")}`);
3888
3896
  const includes = ChunkFileUtils.getIncludes(block);
3889
3897
  if (includes && includes.length > 0) {
@@ -3928,11 +3936,11 @@ var BlockWriter = class {
3928
3936
  }
3929
3937
  if (typeof obj === "number") {
3930
3938
  if (op.mode === "Immediate") return obj;
3931
- return this._blockReader.resolveName(obj, AddressType.Address, isBranch);
3939
+ return this._referenceManager.resolveName(obj, AddressType.Address, isBranch);
3932
3940
  }
3933
3941
  if (this.getObjectType(obj) === ObjectType.LocationWrapper) {
3934
3942
  const lw = obj;
3935
- return this._blockReader.resolveName(lw.location, lw.type, isBranch);
3943
+ return this._referenceManager.resolveName(lw.location, lw.type, isBranch);
3936
3944
  }
3937
3945
  if (this.getObjectType(obj) === ObjectType.Address) {
3938
3946
  const addr = obj;
@@ -3984,7 +3992,7 @@ var BlockWriter = class {
3984
3992
  objLines = this.writeOpArray(obj, depth);
3985
3993
  break;
3986
3994
  case ObjectType.LocationWrapper:
3987
- objLines = [this._blockReader.resolveName(obj.location, obj.type, isBranch)];
3995
+ objLines = [this._referenceManager.resolveName(obj.location, obj.type, isBranch)];
3988
3996
  break;
3989
3997
  case ObjectType.Address:
3990
3998
  objLines = isArray ? [`$#${obj.offset.toString(16).toUpperCase().padStart(4, "0")}`] : [`$${obj.toString()}`];
@@ -4102,7 +4110,7 @@ var BlockWriter = class {
4102
4110
  const adrs = new Address(rawAddr >> 16 & 255, rawAddr & 65535, this._blockReader._root.config.memoryMode);
4103
4111
  const addressType = char === "^" ? AddressType.Offset : AddressType.Address;
4104
4112
  let name = "";
4105
- if (adrs.isROM) name = this._blockReader.resolveName(adrs.toLocation(), addressType, false);
4113
+ if (adrs.isROM) name = this._referenceManager.resolveName(adrs.toLocation(), addressType, false);
4106
4114
  else if (addressType === AddressType.Offset) name = adrs.offset.toString(16).toUpperCase().padStart(4, "0");
4107
4115
  else name = adrs.toString();
4108
4116
  str = str.replace(str.substring(ix, ix + 7), name);
@@ -4244,8 +4252,8 @@ var RomLayout = class RomLayout {
4244
4252
  return parseInt(a.name.substring(a.name.length - 2, a.name.length), 16) - parseInt(b.name.substring(b.name.length - 2, b.name.length), 16);
4245
4253
  }) : [];
4246
4254
  this.unmatchedFiles = files.filter((x) => (x.size || 0) > 0).filter((x) => this.sfxPackType === "Individual" || x.type.type !== "Sound").sort((a, b) => {
4247
- const aAsm = a.parts ? 0 : 1;
4248
- const bAsm = b.parts ? 0 : 1;
4255
+ const aAsm = a.rawData ? 1 : 0;
4256
+ const bAsm = b.rawData ? 1 : 0;
4249
4257
  if (aAsm !== bAsm) return aAsm - bAsm;
4250
4258
  if (b.size !== a.size) return b.size - a.size;
4251
4259
  if (a.location !== b.location) return a.location - b.location;
@@ -4295,7 +4303,7 @@ var RomLayout = class RomLayout {
4295
4303
  start += RomProcessingConstants.PAGE_SIZE;
4296
4304
  page++;
4297
4305
  if (offset) {
4298
- const newFile = new ChunkFile(file.name + "_2", file.size, file.location, Object.values(this.root.fileTypes).find((x) => x.type === BinType.Binary));
4306
+ const newFile = new ChunkFile(Object.values(this.root.fileTypes).find((x) => x.type === BinType.Binary), file.name + "_2", file.size, file.location);
4299
4307
  const end = file.rawData.length - offset;
4300
4308
  newFile.rawData = file.rawData.slice(end);
4301
4309
  newFile.size = newFile.rawData.length;
@@ -4385,107 +4393,13 @@ var RomLayout = class RomLayout {
4385
4393
  }
4386
4394
  };
4387
4395
 
4388
- //#endregion
4389
- //#region src/rom/rebuild/processor.ts
4390
- /**
4391
- * ROM rebuild processor
4392
- * Converted from ext/GaiaLib/Rom/Rebuild/RomProcessor.cs
4393
- */
4394
- var RomProcessor = class RomProcessor {
4395
- writer;
4396
- constructor(writer) {
4397
- this.writer = writer;
4398
- }
4399
- async repack(allFiles, modules) {
4400
- const patches = [];
4401
- const asmFiles = [];
4402
- const compression = this.writer.root.compression;
4403
- const canCompress = !!compression;
4404
- const conditionFiles = [];
4405
- if (modules) conditionFiles.push(...modules);
4406
- for (const file of allFiles) {
4407
- if (file.type.type === "Patch") patches.push(file);
4408
- else if (file.type.type !== "Assembly") {
4409
- if (file.compressed === true && canCompress) if (this.writer.root.config.uncompress) file.compressed = false;
4410
- else {
4411
- let newData = compression.compact(file.rawData, file.type.header);
4412
- if (file.type.header) newData = new Uint8Array([...file.rawData.slice(0, file.type.header), ...newData]);
4413
- file.rawData = newData;
4414
- file.size = newData.length;
4415
- }
4416
- continue;
4417
- }
4418
- asmFiles.push(file);
4419
- conditionFiles.push(file.name);
4420
- }
4421
- for (const file of asmFiles) {
4422
- const { blocks, includes, reqBank } = new Assembler(this.writer.root, file.textData, conditionFiles).parseAssembly();
4423
- file.parts = blocks;
4424
- file.includes = includes;
4425
- file.bank = reqBank ?? void 0;
4426
- }
4427
- RomProcessor.applyPatches(asmFiles, patches);
4428
- for (const file of allFiles) ChunkFileUtils.calculateSize(file);
4429
- const pages = new RomLayout(allFiles, this.writer.root).organize();
4430
- for (const file of asmFiles) ChunkFileUtils.rebase(file);
4431
- const masterLookup = /* @__PURE__ */ new Map();
4432
- for (const f of asmFiles) {
4433
- const includeBlocks = asmFiles.filter((x) => f.includes?.has(x.name.toUpperCase())).flatMap((x) => x.parts).filter((b) => !!b.label);
4434
- f.includeLookup = /* @__PURE__ */ new Map();
4435
- for (const b of includeBlocks) if (b.label) f.includeLookup.set(b.label.toUpperCase(), b);
4436
- for (const b of f.parts) if (b.label) {
4437
- const nameUpper = b.label.toUpperCase();
4438
- masterLookup.set(nameUpper, b.location);
4439
- f.includeLookup.set(nameUpper, b);
4440
- }
4441
- }
4442
- const fileLookup = /* @__PURE__ */ new Map();
4443
- for (const f of allFiles) fileLookup.set(f.name.toUpperCase(), f.location);
4444
- this.writer.allocate(pages);
4445
- for (const file of allFiles) await this.writer.writeFile(file, fileLookup);
4446
- return masterLookup;
4447
- }
4448
- static applyPatches(asmFiles, patches) {
4449
- for (const patch of patches.filter((x) => x.includes && x.includes.size > 0)) {
4450
- let file = null;
4451
- let dstIx = -1;
4452
- const inc = asmFiles.filter((x) => patch.includes.has(x.name.toUpperCase()));
4453
- for (let ix = 0; patch.parts && ix < patch.parts.length;) {
4454
- const block = patch.parts[ix];
4455
- let match = null;
4456
- if (block.label) for (const i of inc) {
4457
- if (!i.parts) continue;
4458
- for (let y = 0; y < i.parts.length; y++) {
4459
- const check = i.parts[y];
4460
- if (check.label === block.label) {
4461
- file = i;
4462
- dstIx = y;
4463
- match = check;
4464
- break;
4465
- }
4466
- }
4467
- }
4468
- if (match) file.parts[dstIx++] = block;
4469
- else if (dstIx >= 0) file.parts.splice(dstIx++, 0, block);
4470
- else {
4471
- ix++;
4472
- continue;
4473
- }
4474
- file.includes = file.includes || /* @__PURE__ */ new Set();
4475
- file.includes.add(patch.name.toUpperCase());
4476
- patch.parts.splice(ix, 1);
4477
- }
4478
- }
4479
- }
4480
- };
4481
-
4482
4396
  //#endregion
4483
4397
  //#region src/rom/rebuild/writer.ts
4484
4398
  /**
4485
4399
  * ROM writer (binary)
4486
4400
  * Converted from ext/GaiaLib/Rom/Rebuild/RomWriter.cs (subset: binary write only)
4487
4401
  */
4488
- var RomWriter = class {
4402
+ var RomWriter = class RomWriter {
4489
4403
  bpsPath;
4490
4404
  outBuffer;
4491
4405
  romSize;
@@ -4640,7 +4554,7 @@ var RomWriter = class {
4640
4554
  }
4641
4555
  } else if (file.parts && file.parts.length > 0) {
4642
4556
  if (file.parts[0].location !== file.location && (file.location || 0) !== 0) throw new Error("Assembly was not based properly");
4643
- this.parseAssembly(file.parts, fileLookup, file.includeLookup);
4557
+ RomWriter.parseAssembly(this.root, file.parts, fileLookup, file.includeLookup, this.outBuffer, void 0);
4644
4558
  }
4645
4559
  return pos - start;
4646
4560
  }
@@ -4652,12 +4566,10 @@ var RomWriter = class {
4652
4566
  * Parse assembly blocks and write binary data to output buffer
4653
4567
  * Converted from ext/GaiaLib/Rom/Rebuild/RomWriter.cs ParseAssembly method
4654
4568
  */
4655
- parseAssembly(blocks, fileLookup, includeLookup) {
4569
+ static parseAssembly(root, blocks, fileLookup, includeLookup, outBuffer, addrOffset) {
4656
4570
  if (!blocks) throw new Error("Assembly has not been parsed");
4657
- const buf = this.outBuffer;
4658
4571
  let bix = 0;
4659
4572
  for (const block of blocks) {
4660
- let oldPos = null;
4661
4573
  let position = block.location;
4662
4574
  const objList = block.objList;
4663
4575
  let oix = 0;
@@ -4672,13 +4584,13 @@ var RomWriter = class {
4672
4584
  continue;
4673
4585
  } else if (currentObj instanceof Op) {
4674
4586
  const op = currentObj;
4675
- buf[position++] = op.code & 255;
4587
+ outBuffer[position++] = op.code & 255;
4676
4588
  opos += op.size;
4677
4589
  for (const operand of op.operands) processObject(operand, op);
4678
4590
  break;
4679
4591
  } else if (currentObj instanceof Uint8Array) {
4680
4592
  const arr = currentObj;
4681
- for (let i = 0; i < arr.length; i++) buf[position + i] = arr[i];
4593
+ for (let i = 0; i < arr.length; i++) outBuffer[position + i] = arr[i];
4682
4594
  position += arr.length;
4683
4595
  opos += arr.length;
4684
4596
  break;
@@ -4690,7 +4602,7 @@ var RomWriter = class {
4690
4602
  if (ix > 0) label = label.substring(ix);
4691
4603
  let loc;
4692
4604
  const isRelative = parentOp && (parentOp.mode === "PCRelative" || parentOp.mode === "PCRelativeLong");
4693
- const operatorIdx = this.indexOfAny(label, RomProcessingConstants.OPERATORS);
4605
+ const operatorIdx = RomWriter.indexOfAny(label, RomProcessingConstants.OPERATORS);
4694
4606
  let offset = null;
4695
4607
  let useMarker = false;
4696
4608
  if (operatorIdx > 0) {
@@ -4739,12 +4651,13 @@ var RomWriter = class {
4739
4651
  if (offset !== null) loc += offset;
4740
4652
  else if (useMarker && target instanceof AsmBlock) {
4741
4653
  let markerOffset = 0;
4742
- for (const part of target.objList) if (this.isStringMarker(part)) {
4654
+ for (const part of target.objList) if (RomWriter.isStringMarker(part)) {
4743
4655
  loc += markerOffset;
4744
4656
  break;
4745
4657
  } else markerOffset += RomProcessingConstants.getSize(part);
4746
4658
  }
4747
- if (!isRelative && type !== AddressType.Location) loc = Address.fromLocation(loc, this.root.config.memoryMode, this.root.config.cpuMode).toInt();
4659
+ if (addrOffset !== void 0) loc += addrOffset;
4660
+ else if (!isRelative && type !== AddressType.Location) loc = Address.fromLocation(loc, root.config.memoryMode, root.config.cpuMode).toInt();
4748
4661
  switch (type) {
4749
4662
  case AddressType.Offset:
4750
4663
  case AddressType.WRelative:
@@ -4769,7 +4682,7 @@ var RomWriter = class {
4769
4682
  } else if (currentObj instanceof TypedNumber) {
4770
4683
  let value = currentObj.value;
4771
4684
  for (let i = 0; i < currentObj.size; i++) {
4772
- buf[position++] = value & 255;
4685
+ outBuffer[position++] = value & 255;
4773
4686
  value >>= 8;
4774
4687
  }
4775
4688
  break;
@@ -4777,26 +4690,26 @@ var RomWriter = class {
4777
4690
  const num = currentObj;
4778
4691
  const size = parentOp?.size ?? 0;
4779
4692
  if (num <= 255 && size <= 2) {
4780
- buf[position] = num & 255;
4693
+ outBuffer[position] = num & 255;
4781
4694
  position++;
4782
4695
  } else if (num <= 65535 && size <= 3) {
4783
- buf[position] = num & 255;
4784
- buf[position + 1] = num >> 8 & 255;
4696
+ outBuffer[position] = num & 255;
4697
+ outBuffer[position + 1] = num >> 8 & 255;
4785
4698
  position += 2;
4786
4699
  } else if (num <= 16777215 && size <= 4) {
4787
- buf[position] = num & 255;
4788
- buf[position + 1] = num >> 8 & 255;
4789
- buf[position + 2] = num >> 16 & 255;
4700
+ outBuffer[position] = num & 255;
4701
+ outBuffer[position + 1] = num >> 8 & 255;
4702
+ outBuffer[position + 2] = num >> 16 & 255;
4790
4703
  position += 3;
4791
4704
  } else {
4792
- buf[position] = num & 255;
4793
- buf[position + 1] = num >> 8 & 255;
4794
- buf[position + 2] = num >> 16 & 255;
4795
- buf[position + 3] = num >> 24 & 255;
4705
+ outBuffer[position] = num & 255;
4706
+ outBuffer[position + 1] = num >> 8 & 255;
4707
+ outBuffer[position + 2] = num >> 16 & 255;
4708
+ outBuffer[position + 3] = num >> 24 & 255;
4796
4709
  position += 4;
4797
4710
  }
4798
4711
  break;
4799
- } else if (this.isStringMarker(currentObj)) break;
4712
+ } else if (RomWriter.isStringMarker(currentObj)) break;
4800
4713
  else throw new Error(`Unable to process '${currentObj}'`);
4801
4714
  };
4802
4715
  for (const obj of objList) {
@@ -4809,21 +4722,121 @@ var RomWriter = class {
4809
4722
  /**
4810
4723
  * Helper method to find index of any character from an array in a string
4811
4724
  */
4812
- indexOfAny(str, chars) {
4725
+ static indexOfAny(str, chars) {
4813
4726
  for (let i = 0; i < str.length; i++) if (chars.includes(str[i])) return i;
4814
4727
  return -1;
4815
4728
  }
4816
4729
  /**
4817
4730
  * Helper method to check if an object is a StringMarker
4818
4731
  */
4819
- isStringMarker(obj) {
4732
+ static isStringMarker(obj) {
4820
4733
  return typeof obj === "object" && obj !== null && "offset" in obj;
4821
4734
  }
4822
- isTableEntry(obj) {
4735
+ static isTableEntry(obj) {
4823
4736
  return typeof obj === "object" && obj !== null && "location" in obj && "object" in obj;
4824
4737
  }
4825
4738
  };
4826
4739
 
4740
+ //#endregion
4741
+ //#region src/rom/rebuild/processor.ts
4742
+ /**
4743
+ * ROM rebuild processor
4744
+ * Converted from ext/GaiaLib/Rom/Rebuild/RomProcessor.cs
4745
+ */
4746
+ var RomProcessor = class RomProcessor {
4747
+ writer;
4748
+ constructor(writer) {
4749
+ this.writer = writer;
4750
+ }
4751
+ async repack(allFiles, modules) {
4752
+ const patches = [];
4753
+ const asmFiles = [];
4754
+ const compression = this.writer.root.compression;
4755
+ const canCompress = !!compression;
4756
+ const conditionFiles = [];
4757
+ if (modules) conditionFiles.push(...modules);
4758
+ const dummyMap = /* @__PURE__ */ new Map();
4759
+ for (const file of allFiles) {
4760
+ conditionFiles.push(file.name);
4761
+ if (file.type.isPatch) {
4762
+ patches.push(file);
4763
+ asmFiles.push(file);
4764
+ } else if (file.type.isBlock) asmFiles.push(file);
4765
+ else if (!file.type.struct) continue;
4766
+ const { blocks, includes, reqBank } = new Assembler(this.writer.root, file.textData, conditionFiles).parseAssembly();
4767
+ file.parts = blocks;
4768
+ file.includes = includes;
4769
+ file.bank = reqBank ?? void 0;
4770
+ if (file.type.struct) {
4771
+ file.includeLookup = /* @__PURE__ */ new Map();
4772
+ for (const b of file.parts) if (b.label) file.includeLookup.set(b.label.toUpperCase(), b);
4773
+ file.rawData = void 0;
4774
+ file.rawData = new Uint8Array(ChunkFileUtils.calculateSize(file));
4775
+ RomWriter.parseAssembly(this.writer.root, file.parts, dummyMap, file.includeLookup, file.rawData, file.type.base ?? 0);
4776
+ }
4777
+ }
4778
+ for (const file of allFiles) if (file.compressed === true && canCompress) if (this.writer.root.config.uncompress) file.compressed = false;
4779
+ else {
4780
+ let newData = compression.compact(file.rawData, file.type.header);
4781
+ if (file.type.header) newData = new Uint8Array([...file.rawData.slice(0, file.type.header), ...newData]);
4782
+ file.rawData = newData;
4783
+ file.size = newData.length;
4784
+ }
4785
+ RomProcessor.applyPatches(asmFiles, patches);
4786
+ for (const file of allFiles) ChunkFileUtils.calculateSize(file);
4787
+ const pages = new RomLayout(allFiles, this.writer.root).organize();
4788
+ for (const file of asmFiles) ChunkFileUtils.rebase(file);
4789
+ const masterLookup = /* @__PURE__ */ new Map();
4790
+ for (const f of asmFiles) {
4791
+ const includeBlocks = asmFiles.filter((x) => f.includes?.has(x.name.toUpperCase())).flatMap((x) => x.parts).filter((b) => !!b.label);
4792
+ f.includeLookup = /* @__PURE__ */ new Map();
4793
+ for (const b of includeBlocks) if (b.label) f.includeLookup.set(b.label.toUpperCase(), b);
4794
+ for (const b of f.parts) if (b.label) {
4795
+ const nameUpper = b.label.toUpperCase();
4796
+ masterLookup.set(nameUpper, b.location);
4797
+ f.includeLookup.set(nameUpper, b);
4798
+ }
4799
+ }
4800
+ const fileLookup = /* @__PURE__ */ new Map();
4801
+ for (const f of allFiles) fileLookup.set(f.name.toUpperCase(), f.location);
4802
+ this.writer.allocate(pages);
4803
+ for (const file of allFiles) await this.writer.writeFile(file, fileLookup);
4804
+ return masterLookup;
4805
+ }
4806
+ static applyPatches(asmFiles, patches) {
4807
+ for (const patch of patches.filter((x) => x.includes && x.includes.size > 0)) {
4808
+ let file = null;
4809
+ let dstIx = -1;
4810
+ const inc = asmFiles.filter((x) => patch.includes.has(x.name.toUpperCase()));
4811
+ for (let ix = 0; patch.parts && ix < patch.parts.length;) {
4812
+ const block = patch.parts[ix];
4813
+ let match = null;
4814
+ if (block.label) for (const i of inc) {
4815
+ if (!i.parts) continue;
4816
+ for (let y = 0; y < i.parts.length; y++) {
4817
+ const check = i.parts[y];
4818
+ if (check.label === block.label) {
4819
+ file = i;
4820
+ dstIx = y;
4821
+ match = check;
4822
+ break;
4823
+ }
4824
+ }
4825
+ }
4826
+ if (match) file.parts[dstIx++] = block;
4827
+ else if (dstIx >= 0) file.parts.splice(dstIx++, 0, block);
4828
+ else {
4829
+ ix++;
4830
+ continue;
4831
+ }
4832
+ file.includes = file.includes || /* @__PURE__ */ new Set();
4833
+ file.includes.add(patch.name.toUpperCase());
4834
+ patch.parts.splice(ix, 1);
4835
+ }
4836
+ }
4837
+ }
4838
+ };
4839
+
4827
4840
  //#endregion
4828
4841
  //#region src/rom/rebuild/string-processor.ts
4829
4842
  /**
@@ -5539,6 +5552,7 @@ var DbFile = class {
5539
5552
  upper;
5540
5553
  group;
5541
5554
  scene;
5555
+ base;
5542
5556
  constructor(data) {
5543
5557
  if (!data.name) throw new Error("Name is required");
5544
5558
  if (!data.type) throw new Error("Type is required");
@@ -5552,6 +5566,7 @@ var DbFile = class {
5552
5566
  this.upper = data.upper ?? void 0;
5553
5567
  this.group = data.group || void 0;
5554
5568
  this.scene = data.scene || void 0;
5569
+ this.base = data.base ?? void 0;
5555
5570
  }
5556
5571
  };
5557
5572
  var DbFileType = class {
@@ -5562,17 +5577,21 @@ var DbFileType = class {
5562
5577
  isBlock;
5563
5578
  header;
5564
5579
  compressed;
5580
+ struct;
5581
+ base;
5565
5582
  constructor(data) {
5566
- this.name = data.name ?? "";
5567
- this.extension = data.extension ?? "";
5568
- this.type = data.type ?? "";
5583
+ if (!data.name) throw new Error("Name is required");
5584
+ if (!data.extension) throw new Error("Extension is required");
5585
+ if (!data.type) throw new Error("Type is required");
5586
+ this.name = data.name;
5587
+ this.extension = data.extension;
5588
+ this.type = data.type;
5569
5589
  this.isPatch = data.isPatch ?? false;
5570
5590
  this.isBlock = data.isBlock ?? false;
5571
5591
  this.header = data.header ?? 0;
5572
5592
  this.compressed = data.compressed ?? void 0;
5573
- if (!this.name) throw new Error("Name is required");
5574
- if (!this.extension) throw new Error("Extension is required");
5575
- if (!this.type) throw new Error("Type is required");
5593
+ this.struct = data.struct ?? void 0;
5594
+ this.base = data.base ?? void 0;
5576
5595
  }
5577
5596
  };
5578
5597
 
@@ -6101,7 +6120,7 @@ var DbRootUtils = class {
6101
6120
  const cfg = module.config;
6102
6121
  const compression = cfg.compression ? CompressionAlgorithms[cfg.compression]() : void 0;
6103
6122
  const baseRomChunks = module.baseRomFiles ?? module.supaBaseRomFiles?.map((file) => {
6104
- const chunkFile = new ChunkFile(file.name, 0, 0, fileTypeLookup[file.type]);
6123
+ const chunkFile = new ChunkFile(fileTypeLookup[file.type], file.name);
6105
6124
  if (file.isText) {
6106
6125
  chunkFile.textData = file.text ?? void 0;
6107
6126
  chunkFile.size = file.text?.length ?? 0;
@@ -6112,7 +6131,7 @@ var DbRootUtils = class {
6112
6131
  return chunkFile;
6113
6132
  });
6114
6133
  const projectChunks = module.projectFiles ?? module.supaProjectFiles?.map((file) => {
6115
- const chunkFile = new ChunkFile(file.name, 0, 0, fileTypeLookup[file.type]);
6134
+ const chunkFile = new ChunkFile(fileTypeLookup[file.type], file.name);
6116
6135
  chunkFile.group = file.module ?? void 0;
6117
6136
  if (file.isText) {
6118
6137
  chunkFile.textData = file.text ?? void 0;
@@ -6164,9 +6183,9 @@ var DbRootUtils = class {
6164
6183
  const type = root.fileExtLookup[entry.extension];
6165
6184
  if (!type) continue;
6166
6185
  const existing = chunkFiles.find((x) => x.name === entry.name && x.type.type === type.type);
6167
- const chunkFile = existing ?? new ChunkFile(entry.name, 0, 0, type);
6186
+ const chunkFile = existing ?? new ChunkFile(type, entry.name);
6168
6187
  if (group) chunkFile.group = group;
6169
- if (chunkFile.type.type === "Assembly" || chunkFile.type.type === "Patch") {
6188
+ if (chunkFile.type.isBlock || chunkFile.type.isPatch || chunkFile.type.struct) {
6170
6189
  const chunkData = await readFileAsText(entry.path);
6171
6190
  chunkFile.textData = chunkData;
6172
6191
  chunkFile.size = chunkData.length;
@@ -6195,7 +6214,7 @@ var DbRootUtils = class {
6195
6214
  const ext = block.type.extension;
6196
6215
  const filePath = `${outPath}/${block.group ? block.group + "/" : ""}${block.scene ? block.scene + "/" : ""}${block.name}${ext ? "." + ext : ""}`;
6197
6216
  if (block.parts?.length) {
6198
- if (!block.textData) block.textData = writer.generateAsm(block);
6217
+ block.textData = writer.generateAsm(block);
6199
6218
  await saveFileAsText(filePath, block.textData);
6200
6219
  } else {
6201
6220
  if (!block.rawData) continue;
@@ -7113,6 +7132,7 @@ async function summaryFromSupabaseByProject(projectName) {
7113
7132
  notes,
7114
7133
  gameRomId,
7115
7134
  platformBranchId,
7135
+ fileTypes,
7116
7136
  createdAt,
7117
7137
  updatedAt,
7118
7138
  gameRom:GameRom!inner(
@@ -7223,10 +7243,10 @@ var RomGenerator = class {
7223
7243
  if (!this.sourceData) throw new Error("Source data not initialized");
7224
7244
  const reader = new BlockReader(this.sourceData, this.dbRoot);
7225
7245
  const chunkFiles = reader.analyzeAndResolve();
7226
- const asmFiles = chunkFiles.filter((b) => b.type.type === "Assembly");
7246
+ const asmFiles = chunkFiles.filter((b) => b.type.isBlock);
7227
7247
  const patchFiles = [];
7228
7248
  const writer = new BlockWriter(reader);
7229
- for (const block of asmFiles) block.textData = writer.generateAsm(block);
7249
+ for (const block of chunkFiles) if (block.parts?.length) block.textData = writer.generateAsm(block);
7230
7250
  for (const chunkFile of this.dbRoot.baseRomFiles) this.applyPatchFile(chunkFile, chunkFiles, asmFiles, patchFiles);
7231
7251
  const moduleLookup = this.applyProjectInit(chunkFiles, asmFiles, patchFiles);
7232
7252
  if (unshiftManualFiles) for (const file of manualFiles ?? []) this.applyPatchFile(file, chunkFiles, asmFiles, patchFiles);
@@ -7251,7 +7271,7 @@ var RomGenerator = class {
7251
7271
  const existing = chunkFiles.find((x) => x.name === chunkFile.name);
7252
7272
  if (chunkFile.textData) if (existing) existing.textData = chunkFile.textData;
7253
7273
  else {
7254
- if (chunkFile.type.type === "Patch") patchFiles.push(chunkFile);
7274
+ if (chunkFile.type.isPatch) patchFiles.push(chunkFile);
7255
7275
  asmFiles.push(chunkFile);
7256
7276
  chunkFiles.push(chunkFile);
7257
7277
  }
@@ -7502,5 +7522,5 @@ const snes = {
7502
7522
  const isPlatformNode = typeof process !== "undefined" && process.versions?.node;
7503
7523
 
7504
7524
  //#endregion
7505
- export { Address, AddressSpace, AddressType, AddressingModeHandler, AsmBlock, AsmBlockUtils, AsmReader, Assembler, AssemblerState, BinType, BitStream, BlockReader, BlockReaderConstants, BlockWriter, Byte, ChunkFile, ChunkFileUtils, CompressionAlgorithms, CompressionRegistry, CopCommandProcessor, CopDef, CpuMode, DbAddressingMode, DbBlock, DbFile, DbFileType, DbGroup, DbHeader, DbHeaderPart, DbOverride, DbPart, DbRootUtils, DbScene, DbStringCommand, DbStringDictionary, DbStringType, DbStruct, DbTransform, LocationWrapper, Long, MapExt, MemberType, MemoryMapMode, ObjectType, Op, OpCode, OperationContext, PostProcessor, ProcessorStateManager, QuintetLZ, ReferenceManager, RegisterType, Registers, RomDataReader, RomGenerator, RomLayout, RomProcessingConstants, RomProcessor, RomState, RomStateUtils, RomWriter, SortedMap, SpriteFrame, SpriteGroup, SpriteMap, SpritePart, Stack, StackOperations, StatusFlags, StringProcessor, StringReader, StringSizeComparer, SupabaseErrorCode, SupabaseFromError, TableEntry, TransformProcessor, TypeParser, TypedNumber, Word, XformType, base64ToUint8Array, binaryToUtf8String, bytesToHex, clamp, crc32_buffer, crc32_text_utf16, crc32_text_utf8, createChunkFileFromDbBlock, createChunkFileFromDbFile, createDbPath, createSupabaseClient, createTempDirectory, decodeBase64, decodeBase64String, decodeDataString, encodeBase64, encodeBase64String, fileExists, fromSupabaseByGameRom, fromSupabaseById, fromSupabaseByName, fromSupabaseByProject, getDirectory, getEnvVar, getNestedProperty, getSupabaseClient, hexToBytes, hexToUint8Array, indexOfAny, isPlatformNode, isValidBase64, listDirectory, readFileAsBinary, readFileAsText, readJsonFile, removeDirectory, resetSupabaseClient, saveFileAsBinary, saveFileAsText, snes, summaryFromSupabaseByProject, uint8ArrayToBase64, validateEnvironmentVariables };
7525
+ export { Address, AddressSpace, AddressType, AddressingModeHandler, AsmBlock, AsmBlockUtils, AsmReader, Assembler, AssemblerState, BinType, BitStream, BlockReader, BlockReaderConstants, BlockWriter, Byte, ChunkFile, ChunkFileUtils, CompressionAlgorithms, CompressionRegistry, CopCommandProcessor, CopDef, CpuMode, DbAddressingMode, DbBlock, DbFile, DbFileType, DbGroup, DbHeader, DbHeaderPart, DbOverride, DbPart, DbRootUtils, DbScene, DbStringCommand, DbStringDictionary, DbStringType, DbStruct, DbTransform, LocationWrapper, Long, MapExt, MemberType, MemoryMapMode, ObjectType, Op, OpCode, OperationContext, PostProcessor, ProcessorStateManager, QuintetLZ, ReferenceManager, RegisterType, Registers, RomDataReader, RomGenerator, RomLayout, RomProcessingConstants, RomProcessor, RomState, RomStateUtils, RomWriter, SortedMap, SpriteFrame, SpriteGroup, SpriteMap, SpritePart, Stack, StackOperations, StatusFlags, StringProcessor, StringReader, StringSizeComparer, SupabaseErrorCode, SupabaseFromError, TableEntry, TransformProcessor, TypeParser, TypedNumber, Word, XformType, base64ToUint8Array, binaryToUtf8String, bytesToHex, clamp, combineHeader, crc32_buffer, crc32_text_utf16, crc32_text_utf8, createDbPath, createSupabaseClient, createTempDirectory, decodeBase64, decodeBase64String, decodeDataString, encodeBase64, encodeBase64String, fileExists, fromSupabaseByGameRom, fromSupabaseById, fromSupabaseByName, fromSupabaseByProject, getDirectory, getEnvVar, getNestedProperty, getSupabaseClient, hexToBytes, hexToUint8Array, indexOfAny, isPlatformNode, isValidBase64, listDirectory, readFileAsBinary, readFileAsText, readJsonFile, removeDirectory, resetSupabaseClient, saveFileAsBinary, saveFileAsText, snes, summaryFromSupabaseByProject, uint8ArrayToBase64, validateEnvironmentVariables };
7506
7526
  //# sourceMappingURL=index.mjs.map