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

42 lines
2.3 KiB
JavaScript

// Current .54 SHA 4aa08a0706f27d2cf9951b61920c179140ece9ea94f7e34422c18e46922939b6.
// Exact Row.FromBinary -> Add -> lazy GetAll chain in comic-*-current.asm.
// Only two flat config getters; no repository/scene/gameplay constructors.
const module = Process.getModuleByName('GameAssembly.dll');
const tables = [['cycle', 0x1eafb230], ['level', 0x1e2556c0]];
for (const [name,rva] of tables) {
if (module.base.add(rva).readU32()!==0x28ec8348) throw Error('Getter differs: '+name);
}
const serializer=module.base.add(0x1d46c040);
const serialize=new NativeFunction(serializer,'pointer',['pointer','pointer']);
const marker='GAC_COMIC_FLAT_TICK';
let table=0,index=0,count=0,entries=null,done=false,busy=false;
Interceptor.attach(serializer,{
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||done||busy)return;busy=true;
try{
if(entries===null){
const get=new NativeFunction(module.base.add(tables[table][1]),'pointer',['pointer']);
const dict=get(ptr(0));if(dict.isNull())throw Error('Missing dictionary');
count=dict.add(0x20).readU32();entries=dict.add(0x18).readPointer();index=0;
if(count>256||count>0&&(entries.isNull()||entries.add(0x18).readU32()<count))throw Error('Dictionary bound');
send({kind:'BEGIN',table:tables[table][0],count});
}
const rows=[];
for(let n=0;n<4&&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 size bound');
rows.push(value.add(0x14).readUtf16String(length));
}
send({kind:'ROWS',table:tables[table][0],rows});
if(index>=count){send({kind:'TABLE_END',table:tables[table][0],count});table++;entries=null;if(table===tables.length){done=true;send({kind:'END'});}}
}catch(e){done=true;send({kind:'ERROR',error:String(e)});}finally{busy=false;}
}
});
send({kind:'ATTACHED',scope:'two exact lazy flat getters, four rows per marker heartbeat',module:module.path});