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