Files
GaCy-GO/tools/glm_beta_gacha_groups.js
2026-10-28 18:54:43 +07:00

47 lines
2.5 KiB
JavaScript

// Research capture for assembly SHA256
// 4aa08a0706f27d2cf9951b61920c179140ece9ea94f7e34422c18e46922939b6.
// GachaGroupDataRow.FromBinary -> wrapper -> dictionary Add disassembly:
// battle_diagnostics/glm-gacha-group-{add,dictionary}.asm.
// Use the proven flat GetAll accessor (lazy initialization only). No level graph,
// UI or gameplay loader; no dictionary writes by this capture.
const mod = Process.getModuleByName('GameAssembly.dll');
const serialize = new NativeFunction(mod.base.add(0x1d46c040), 'pointer', ['pointer', 'pointer']);
const marker = 'GAC_GLM_GROUP_TICK';
let done = false, busy = false, index = 0, count = 0, entries = null;
Interceptor.attach(mod.base.add(0x1d46c040), {
onEnter(args) {
this.trigger = false;
if (done || busy) return;
try { this.trigger = args[0].add(0x10).readS32() === marker.length && args[0].add(0x14).readUtf16String(marker.length) === marker; } catch (_) {}
},
onLeave() {
if (!this.trigger || busy || done) return;
busy = true;
try {
if (entries === null) {
if(mod.base.add(0x1e852f20).readU32()!==0x28ec8348)throw Error('Flat getter prologue differs');
const get = new NativeFunction(mod.base.add(0x1e852f20), 'pointer', ['pointer']);
const dict = get(ptr(0));
if (dict.isNull()) throw Error('Missing gacha group dictionary');
count = dict.add(0x20).readU32(); entries = dict.add(0x18).readPointer();
if(count===0){done=true;send({kind:'BEGIN',table:'gacha_groups',count});send({kind:'END',table:'gacha_groups',count});return;}
if (count > 256 || entries.isNull() || entries.add(0x18).readU32() < count) throw Error('Dictionary bound');
send({kind:'BEGIN', table:'gacha_groups', count});
}
const rows = [];
for (let n=0; n<8 && index<count; n++) {
const entry = entries.add(0x20 + 24 * index++);
if (entry.readS32()<0) continue;
const row = entry.add(16).readPointer(); if (row.isNull()) continue;
const value = serialize(row, ptr(0)); if (value.isNull()) throw Error('Missing serialization');
const length = value.add(0x10).readS32(); if (length<2 || length>32768) throw Error('Row bound');
rows.push(value.add(0x14).readUtf16String(length));
}
send({kind:'ROWS', table:'gacha_groups', rows});
if (index>=count) {done=true;send({kind:'END',table:'gacha_groups',count});}
} catch (e) {done=true;send({kind:'ERROR',error:String(e)});}
finally {busy=false;}
}
});
send({kind:'ATTACHED',scope:'one named flat gacha group table; eight rows per managed marker',module:mod.path});