@gaialabs/core 0.2.11 → 0.2.12

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
@@ -1246,6 +1246,7 @@ let MemberType = /* @__PURE__ */ function(MemberType) {
1246
1246
  MemberType["Address"] = "Address";
1247
1247
  MemberType["Binary"] = "Binary";
1248
1248
  MemberType["Code"] = "Code";
1249
+ MemberType["Branch"] = "Branch";
1249
1250
  MemberType["Location"] = "Location";
1250
1251
  return MemberType;
1251
1252
  }({});
@@ -1986,6 +1987,7 @@ var ReferenceManager = class {
1986
1987
  }
1987
1988
  createTypeName(type, location) {
1988
1989
  let name = type.toLowerCase();
1990
+ if (name === "branch") name = "loc";
1989
1991
  while (name.length > 0 && BlockReaderConstants.POINTER_CHARACTERS.includes(name[0])) name = name.substring(1) + "_list";
1990
1992
  return `${name}_${location.toString(16).toUpperCase().padStart(6, "0")}`;
1991
1993
  }
@@ -2363,6 +2365,7 @@ var AddressingModeHandler = class {
2363
2365
  }
2364
2366
  handlePCRelativeMode(operands, nextAddress, reg, isLong) {
2365
2367
  const relative = isLong ? nextAddress + this._dataReader.readShort() : nextAddress + this._dataReader.readSByte();
2368
+ this._blockReader._referenceManager.tryAddStruct(relative, "Branch");
2366
2369
  this._blockReader.updateRegisterState(relative, reg);
2367
2370
  operands.push(new LocationWrapper(relative, isLong ? AddressType.WRelative : AddressType.Relative));
2368
2371
  }
@@ -2986,7 +2989,7 @@ var StringReader = class StringReader {
2986
2989
  this._romDataReader = blockReader._romDataReader;
2987
2990
  }
2988
2991
  resolveCommand(cmd, builder) {
2989
- if (cmd.dictionary) builder.push(cmd.dictionary.entries[this._romDataReader.readByte() - (cmd.dictionary.base ?? 0)]);
2992
+ if (cmd.dictionary) builder.push(`[${cmd.dictionary.commandName ?? cmd.dictionary.command?.toString(16).padEnd(2, "0").toUpperCase()}:${this._romDataReader.readByte().toString(16).padEnd(2, "0").toUpperCase()}]`);
2990
2993
  else if (cmd.types && cmd.types.length > 0) {
2991
2994
  builder.push(`[${cmd.name}`);
2992
2995
  let first = true;
@@ -3027,7 +3030,7 @@ var StringReader = class StringReader {
3027
3030
  }
3028
3031
  parseString(stringType, fixedSize) {
3029
3032
  const commands = stringType.commandLookup;
3030
- const dictionaries = stringType.dictionaries;
3033
+ stringType.dictionaries;
3031
3034
  const builder = [];
3032
3035
  const strLoc = this._romDataReader.position;
3033
3036
  const terminator = stringType.terminator;
@@ -3044,23 +3047,17 @@ var StringReader = class StringReader {
3044
3047
  if (cmd.halt) break;
3045
3048
  } else {
3046
3049
  let found = false;
3047
- for (const dictionary of Object.values(dictionaries)) if (dictionary.base !== void 0 && c >= dictionary.base && c <= dictionary.range) {
3048
- builder.push(dictionary.entries[c - dictionary.base]);
3049
- found = true;
3050
- break;
3051
- }
3052
- if (!found) {
3053
- for (const layer of stringType.layers) if (layer.on !== void 0) {
3054
- if (c === layer.on) {
3055
- currentLayer = layer;
3056
- found = true;
3057
- break;
3058
- }
3059
- } else if (layer.base && c >= layer.base && c < layer.base + layer.map.length) {
3060
- builder.push(layer.map[c - layer.base]);
3050
+ for (const layer of stringType.layers) if (layer.on !== void 0) {
3051
+ if (c === layer.on) {
3052
+ currentLayer = layer;
3053
+ builder.push("[--]");
3061
3054
  found = true;
3062
3055
  break;
3063
3056
  }
3057
+ } else if (layer.base && c >= layer.base && c < layer.base + layer.map.length) {
3058
+ builder.push(layer.map[c - layer.base]);
3059
+ found = true;
3060
+ break;
3064
3061
  }
3065
3062
  if (!found) {
3066
3063
  let index = c - (currentLayer.base ?? 0);
@@ -3089,28 +3086,26 @@ var StringReader = class StringReader {
3089
3086
  let str = sw.string;
3090
3087
  let ix = indexOfAny(str, StringReader.STRING_REFERENCE_CHARACTERS);
3091
3088
  while (ix >= 0) {
3092
- if (ix + 6 < str.length) {
3093
- const hexStr = str.substring(ix + 1, ix + 7);
3094
- const sloc = parseInt(hexStr, 16);
3095
- if (!isNaN(sloc)) {
3096
- if (new Address(sloc >> 16 & 255, sloc & 65535, this._blockReader._root.config.memoryMode).isROM) {
3097
- this._blockReader.resolveInclude(sloc, false);
3098
- const name = this._blockReader.resolveName(sloc, AddressType.Unknown, false);
3099
- const opix = indexOfAny(name, RomProcessingConstants.OPERATORS);
3100
- if (opix > 0) {
3101
- const offsetStr = name.substring(opix + 1);
3102
- let offset;
3103
- if (offsetStr === "M") offset = this._blockReader._referenceManager.markerTable.get(sloc) || 0;
3104
- else offset = parseInt(offsetStr, 16) || 0;
3105
- if (name[opix] === "-") offset = -offset;
3106
- name.substring(0, opix);
3107
- const target = sloc - offset;
3108
- const [isOutside, block, part] = ChunkFileUtils.isOutsideWithPart(this._blockReader._enrichedChunks, this._blockReader._currentChunk, sloc);
3109
- if (part != null) {
3110
- const entry = part.objList?.find((x) => typeof x === "object" && x !== null && "location" in x && "object" in x && x.location === target);
3111
- if (entry && entry.object) entry.object.marker = offset;
3112
- }
3113
- }
3089
+ if (ix + 6 >= str.length) break;
3090
+ const hexStr = str.substring(ix + 1, ix + 7);
3091
+ const sloc = parseInt(hexStr, 16);
3092
+ if (isNaN(sloc)) break;
3093
+ if (new Address(sloc >> 16 & 255, sloc & 65535, this._blockReader._root.config.memoryMode).isROM) {
3094
+ this._blockReader.resolveInclude(sloc, false);
3095
+ const name = this._blockReader.resolveName(sloc, AddressType.Unknown, false);
3096
+ const opix = indexOfAny(name, RomProcessingConstants.OPERATORS);
3097
+ if (opix > 0) {
3098
+ const offsetStr = name.substring(opix + 1);
3099
+ let offset;
3100
+ if (offsetStr === "M") offset = this._blockReader._referenceManager.markerTable.get(sloc) || 0;
3101
+ else offset = parseInt(offsetStr, 16) || 0;
3102
+ if (name[opix] === "-") offset = -offset;
3103
+ name.substring(0, opix);
3104
+ const target = sloc - offset;
3105
+ const [isOutside, block, part] = ChunkFileUtils.isOutsideWithPart(this._blockReader._enrichedChunks, this._blockReader._currentChunk, sloc);
3106
+ if (part != null) {
3107
+ const entry = part.objList?.find((x) => typeof x === "object" && x !== null && "location" in x && "object" in x && x.location === target);
3108
+ if (entry && entry.object) entry.object.marker = offset;
3114
3109
  }
3115
3110
  }
3116
3111
  }
@@ -3160,7 +3155,8 @@ var TypeParser = class {
3160
3155
  case MemberType.Address: return this.parseLocation(this._romDataReader.readUShort(), this._romDataReader.readByte(), null, AddressType.Address);
3161
3156
  case MemberType.Location: return this.parseLocation(this._romDataReader.readUShort(), this._romDataReader.readByte(), null, AddressType.Location);
3162
3157
  case MemberType.Binary: return this.parseBinary(fixedSize);
3163
- case MemberType.Code: return this.parseCode(reg);
3158
+ case MemberType.Code:
3159
+ case MemberType.Branch: return this.parseCode(reg);
3164
3160
  default: throw new Error("Invalid member type");
3165
3161
  }
3166
3162
  const parentType = this._blockReader._root.structs[fixedTypeName];
@@ -3194,7 +3190,7 @@ var TypeParser = class {
3194
3190
  let checkPosition = startPosition;
3195
3191
  while (++checkPosition < this._romDataReader.position) {
3196
3192
  const struct = this._referenceManager.tryGetStruct(checkPosition);
3197
- if (struct.found && struct.chunkType !== "Code") {
3193
+ if (struct.found && struct.chunkType !== "Code" && struct.chunkType !== "Branch") {
3198
3194
  this._romDataReader.position = checkPosition;
3199
3195
  break;
3200
3196
  }
@@ -3234,7 +3230,8 @@ var TypeParser = class {
3234
3230
  loc = adrs.toLocation();
3235
3231
  }
3236
3232
  if (typeName && !this._blockReader._root.rewrites[loc]) {
3237
- this._referenceManager.tryAddStruct(loc, typeName);
3233
+ const oldStruct = this._referenceManager.structTable.get(loc);
3234
+ if (!oldStruct || oldStruct === "Branch") this._referenceManager.structTable.set(loc, typeName);
3238
3235
  const referenceName = `${typeName.toLowerCase()}_${loc.toString(16).toUpperCase().padStart(6, "0")}`;
3239
3236
  this._referenceManager.tryAddName(loc, referenceName);
3240
3237
  }
@@ -3245,7 +3242,10 @@ var TypeParser = class {
3245
3242
  let first = true;
3246
3243
  while (this._romDataReader.position < this._blockReader._partEnd) {
3247
3244
  if (first) first = false;
3248
- else if (this._referenceManager.containsStruct(this._romDataReader.position)) break;
3245
+ else {
3246
+ const struct = this._referenceManager.structTable.get(this._romDataReader.position);
3247
+ if (struct && struct !== "Branch") break;
3248
+ }
3249
3249
  if (reg) this._blockReader.hydrateRegisters(reg);
3250
3250
  const op = this._blockReader._asmReader.parseAsm(reg);
3251
3251
  opList.push(op);
@@ -3492,7 +3492,8 @@ var BlockReader = class {
3492
3492
  * Notes a type at a location and manages chunk references
3493
3493
  */
3494
3494
  noteType(loc, type, silent = false, reg) {
3495
- this._referenceManager.tryAddStruct(loc, type);
3495
+ const oldStruct = this._referenceManager.structTable.get(loc);
3496
+ if (!oldStruct || oldStruct === "Branch") this._referenceManager.structTable.set(loc, type);
3496
3497
  const nameResult = this._referenceManager.tryGetName(loc);
3497
3498
  let name;
3498
3499
  if (!nameResult.found) {
@@ -3532,10 +3533,12 @@ var BlockReader = class {
3532
3533
  return this._romDataReader.position < this._partEnd && !this._referenceManager.containsStruct(this._romDataReader.position);
3533
3534
  }
3534
3535
  analyzeAndResolve() {
3536
+ console.log("analyzeAndResolve started");
3535
3537
  this.createChunkFilesFromDatabase();
3536
3538
  this.initializeBlocksAndParts();
3537
3539
  this.analyzeChunkFiles();
3538
3540
  this.resolveReferences();
3541
+ console.log("analyzeAndResolve complete");
3539
3542
  return this._enrichedChunks;
3540
3543
  }
3541
3544
  /**
@@ -3545,6 +3548,7 @@ var BlockReader = class {
3545
3548
  * Initializes blocks and parts with base references
3546
3549
  */
3547
3550
  initializeBlocksAndParts() {
3551
+ console.log("initializeBlocksAndParts");
3548
3552
  for (const block of this._enrichedChunks) for (const part of block.parts || []) {
3549
3553
  if (part.structName) this._referenceManager.tryAddStruct(part.location, part.structName);
3550
3554
  if (part.label) this._referenceManager.tryAddName(part.location, part.label);
@@ -3599,6 +3603,7 @@ var BlockReader = class {
3599
3603
  * Creates ChunkFile objects from database structure
3600
3604
  */
3601
3605
  createChunkFilesFromDatabase() {
3606
+ console.log("createChunkFilesFromDatabase");
3602
3607
  this._enrichedChunks = [];
3603
3608
  this.createChunkFilesFromSfx();
3604
3609
  this.createChunkFilesFromDbFiles();
@@ -3672,6 +3677,7 @@ var BlockReader = class {
3672
3677
  * Analyzes only assembly ChunkFiles (those with parts from DbBlocks)
3673
3678
  */
3674
3679
  analyzeChunkFiles() {
3680
+ console.log("analyzeChunkFiles");
3675
3681
  const assemblyChunks = this._enrichedChunks.filter((chunk) => chunk.type.type === "Assembly");
3676
3682
  for (const chunkFile of assemblyChunks) {
3677
3683
  this._currentChunk = chunkFile;
@@ -3685,6 +3691,7 @@ var BlockReader = class {
3685
3691
  * Resolves references in assembly ChunkFiles only
3686
3692
  */
3687
3693
  resolveReferences() {
3694
+ console.log("resolveReferences");
3688
3695
  for (const chunkFile of this._enrichedChunks) {
3689
3696
  this._currentChunk = chunkFile;
3690
3697
  for (const asmBlock of chunkFile.parts || []) {
@@ -4112,10 +4119,10 @@ var BlockWriter = class {
4112
4119
  let six = 0;
4113
4120
  let mix = 0;
4114
4121
  while (mix < marker) if (str[six] === "[") {
4115
- const eix = str.indexOf("]", ++six);
4116
- const parts = str.substring(six, eix).split(/[,: ]/);
4122
+ const eix = str.indexOf("]", six);
4123
+ const parts = str.substring(six + 1, eix).split(/[,: ]/);
4117
4124
  const cmd = stringObj.type.commands[parts[0]];
4118
- if (cmd && cmd.types) for (const t of cmd.types) switch (t) {
4125
+ if (cmd) for (const t of cmd.types) switch (t) {
4119
4126
  case MemberType.Byte:
4120
4127
  mix += 1;
4121
4128
  break;
@@ -4132,6 +4139,7 @@ var BlockWriter = class {
4132
4139
  break;
4133
4140
  default: throw new Error("Unsupported member type");
4134
4141
  }
4142
+ else mix += parts.length - 1;
4135
4143
  six = eix + 1;
4136
4144
  mix++;
4137
4145
  } else {
@@ -4140,6 +4148,18 @@ var BlockWriter = class {
4140
4148
  }
4141
4149
  str = str.substring(0, six) + "[::]" + str.substring(six);
4142
4150
  }
4151
+ const dictionaries = stringObj.type.dictionaries;
4152
+ for (const dictionary of Object.values(dictionaries)) {
4153
+ const commandName = `[${dictionary.commandName ?? dictionary.command?.toString(16).padEnd(2, "0").toUpperCase()}:`;
4154
+ let cmdIx;
4155
+ while ((cmdIx = str.indexOf(commandName)) >= 0) {
4156
+ const endIx = str.indexOf("]", cmdIx);
4157
+ const strIx = parseInt(str.substring(cmdIx + commandName.length, endIx), 16);
4158
+ const newText = dictionary.entries[strIx];
4159
+ str = str.substring(0, cmdIx) + newText + str.substring(endIx + 1);
4160
+ }
4161
+ }
4162
+ str = str.replace(/\[--\]/g, "");
4143
4163
  const sizeParam = stringObj.fixedSize ? `(${stringObj.fixedSize})` : "";
4144
4164
  return [`${refChar}${str}${refChar}${sizeParam}`];
4145
4165
  }
@@ -4376,12 +4396,13 @@ var RomProcessor = class RomProcessor {
4376
4396
  constructor(writer) {
4377
4397
  this.writer = writer;
4378
4398
  }
4379
- async repack(allFiles) {
4399
+ async repack(allFiles, modules) {
4380
4400
  const patches = [];
4381
4401
  const asmFiles = [];
4382
4402
  const compression = this.writer.root.compression;
4383
4403
  const canCompress = !!compression;
4384
4404
  const conditionFiles = [];
4405
+ if (modules) conditionFiles.push(...modules);
4385
4406
  for (const file of allFiles) {
4386
4407
  if (file.type.type === "Patch") patches.push(file);
4387
4408
  else if (file.type.type !== "Assembly") {
@@ -4472,8 +4493,8 @@ var RomWriter = class {
4472
4493
  constructor(root) {
4473
4494
  this.root = root;
4474
4495
  }
4475
- async repack(files) {
4476
- const masterLookup = await new RomProcessor(this).repack(files);
4496
+ async repack(files, modules) {
4497
+ const masterLookup = await new RomProcessor(this).repack(files, modules);
4477
4498
  this.writeHeaders(masterLookup);
4478
4499
  return this.outBuffer;
4479
4500
  }
@@ -4961,7 +4982,6 @@ var StringProcessor = class {
4961
4982
  break;
4962
4983
  case MemberType.Offset:
4963
4984
  case MemberType.Address:
4964
- this.flushBuffer(stringType, false);
4965
4985
  this.context.currentBlock.objList.push(parts[pix]);
4966
4986
  this.context.currentBlock.size += cmd.types[y] === MemberType.Offset ? 2 : 3;
4967
4987
  break;
@@ -5628,21 +5648,18 @@ var DbStringCommand = class {
5628
5648
  }
5629
5649
  };
5630
5650
  var DbStringDictionary = class {
5631
- base;
5632
- range;
5633
5651
  command;
5652
+ commandName;
5634
5653
  name;
5635
5654
  entries;
5636
5655
  constructor(data) {
5637
- if (typeof data.base !== "number" && typeof data.command !== "number") throw new Error("Base or command is required");
5656
+ if (typeof data.command !== "number") throw new Error("Command is required");
5638
5657
  if (!data.name) throw new Error("Name is required");
5639
5658
  if (!data.entries || data.entries.length === 0) throw new Error("Entries is required");
5640
- this.base = data.base ?? void 0;
5641
- this.range = data.range ?? 0;
5642
5659
  this.command = data.command ?? void 0;
5660
+ this.commandName = data.commandName ?? void 0;
5643
5661
  this.name = data.name;
5644
5662
  this.entries = data.entries;
5645
- if (this.base !== void 0) this.range = this.base + this.entries.length;
5646
5663
  }
5647
5664
  };
5648
5665
  /**
@@ -5677,7 +5694,7 @@ var DbStringType = class {
5677
5694
  }, {});
5678
5695
  this.dictionaryLookup = Object.values(this.dictionaries).flatMap((y) => y.entries.map((z, ix) => ({
5679
5696
  text: z,
5680
- id: (y.command ?? 0) << 8 | (y.base ?? 0 + ix)
5697
+ id: (y.command ?? 0) << 8 | ix
5681
5698
  }))).sort((a, b) => b.text.length - a.text.length);
5682
5699
  }
5683
5700
  };
@@ -6139,7 +6156,7 @@ var DbRootUtils = class {
6139
6156
  projectFiles: projectChunks
6140
6157
  };
6141
6158
  }
6142
- static async applyFolder(root, folderPath, sourceFiles = []) {
6159
+ static async applyFolder(root, folderPath, sourceFiles = [], group) {
6143
6160
  const chunkFiles = sourceFiles;
6144
6161
  const folderEntries = await listDirectory(folderPath, { recursive: true });
6145
6162
  for (const entry of folderEntries) {
@@ -6148,6 +6165,7 @@ var DbRootUtils = class {
6148
6165
  if (!type) continue;
6149
6166
  const existing = chunkFiles.find((x) => x.name === entry.name && x.type.type === type.type);
6150
6167
  const chunkFile = existing ?? new ChunkFile(entry.name, 0, 0, type);
6168
+ if (group) chunkFile.group = group;
6151
6169
  if (chunkFile.type.type === "Assembly" || chunkFile.type.type === "Patch") {
6152
6170
  const chunkData = await readFileAsText(entry.path);
6153
6171
  chunkFile.textData = chunkData;
@@ -7178,6 +7196,20 @@ var RomGenerator = class {
7178
7196
  this.projectName = projectName;
7179
7197
  this.crc = crc;
7180
7198
  }
7199
+ async validateAndLoad(sourceData, gameModule, baseRomPath, modulePath) {
7200
+ const calc = crc32_buffer(sourceData);
7201
+ if (this.crc !== calc) return false;
7202
+ this.dbRoot = DbRootUtils.fromGameModule(gameModule);
7203
+ let moduleFiles = [];
7204
+ for (const entry of await listDirectory(modulePath)) {
7205
+ if (!entry.isDirectory) continue;
7206
+ moduleFiles.push(...await DbRootUtils.applyFolder(this.dbRoot, entry.path, [], entry.name));
7207
+ }
7208
+ this.dbRoot.baseRomFiles = await DbRootUtils.applyFolder(this.dbRoot, baseRomPath);
7209
+ this.dbRoot.projectFiles = moduleFiles;
7210
+ this.sourceData = sourceData;
7211
+ return true;
7212
+ }
7181
7213
  async validateAndDownload(sourceData) {
7182
7214
  const calc = crc32_buffer(sourceData);
7183
7215
  if (this.crc !== calc) return false;
@@ -7200,7 +7232,7 @@ var RomGenerator = class {
7200
7232
  if (unshiftManualFiles) for (const file of manualFiles ?? []) this.applyPatchFile(file, chunkFiles, asmFiles, patchFiles);
7201
7233
  for (const module of modules) for (const file of moduleLookup.get(module)) this.applyPatchFile(file, chunkFiles, asmFiles, patchFiles);
7202
7234
  if (!unshiftManualFiles) for (const file of manualFiles ?? []) this.applyPatchFile(file, chunkFiles, asmFiles, patchFiles);
7203
- return await new RomWriter(this.dbRoot).repack(chunkFiles);
7235
+ return await new RomWriter(this.dbRoot).repack(chunkFiles, modules);
7204
7236
  }
7205
7237
  applyProjectInit(chunkFiles, asmFiles, patchFiles) {
7206
7238
  const moduleLookup = /* @__PURE__ */ new Map();