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