"""D4 Q1d: dump the FutDataManagerImpl primary vtable (PTR_LAB_18021c2a0, assigned last
in ctor FUN_18010cdc0) slots 0x240..0x330 and decompile each, to map vtable slot ->
settings gate byte.

CONTROL: slot +0x2b0 must read byte 0x1fd3a (IS_FRIENDLY_SEASON_ENABLED per
FUN_18006cc60) and slot +0x2c8 must read 0x1fd3d (IS_DRAFT_MODE_ENABLED). If those two
do not come out right, the vtable is wrong and nothing else here counts.

q_pack_reveal_3 failed to auto-detect this vtable because its first entries are
PTR_LAB_ thunks that Ghidra did not turn into functions, so the "first two qwords are
functions" filter rejected it. Addresses are hardcoded here on purpose.
"""
import traceback

OUT = "/tmp/claude-1000/-home-alex-Documents-OpenFUT/8e521ca1-ca3e-4138-bb96-df1744dd1d30/scratchpad/packres/"
BUF = []


def p(*a):
    s = " ".join(str(x) for x in a)
    print(s)
    BUF.append(s)


try:
    for vt in (0x18021C2A0,):
        p("=== vtable %#x ===" % vt)
        for off in range(0x240, 0x340, 8):
            try:
                t = qword(vt + off)
            except Exception:
                p("  +%#05x  <unreadable>" % off)
                continue
            fn = fm.getFunctionAt(addr(t))
            nm = fn.getName() if fn else "?"
            body = ""
            if 0x180001000 <= t < 0x1801E5000:
                body = " ".join(dec(t, 120).split())
            p("  +%#05x  %#x  %-22s :: %s" % (off, t, nm, body[:300]))

    # who calls the accessor at whatever slot reads 0x1fd45?  find it first, then xref.
except Exception:
    traceback.print_exc()
finally:
    with open(OUT + "d4_fdm_vtable.txt", "w") as f:
        f.write("\n".join(BUF))
    print("WROTE d4_fdm_vtable.txt")
