47 lines
2.5 KiB
JavaScript
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});
|