// 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()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});