"""D4 Q1c/Q2/Q3: (a) map FutDataManagerImpl vtable slots to the settings gate bytes so
we can tell whether byte 0x1fd45 (packOpeningAnimationEnabled) has an accessor at all,
and (b) open the reveal path via the USE_ANIMATION_STYLE / gmLoadFUTPackOpenSublevel /
CREATE_PACK_STATUS strings.

HYPOTHESIS: FutDataManagerImpl publishes one bool accessor per settings gate byte in a
contiguous vtable band; the publisher FUN_18006cc60 uses slots 0x270..0x2f0. If a slot
returns [this+0x1fd45] then packOpeningAnimationEnabled is readable, and its call sites
tell us what it gates.

CONTROLS: slot +0x2b0 MUST decompile to a read of 0x1fd3a (IS_FRIENDLY_SEASON_ENABLED)
and slot +0x2c8 MUST read 0x1fd3d (IS_DRAFT_MODE_ENABLED). Those two are already proven
by FUN_18006cc60's string arguments. If the vtable I pick does not reproduce them, I
have the wrong vtable and every other slot reading is worthless.
"""
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:
    # ---- ctor, to find the vtable ----
    ct = dec(0x18010CDC0, 300)
    p("=== ctor FUN_18010cdc0 len=%d ; first 1200 chars ===" % len(ct))
    p(ct[:1200])
    with open(OUT + "d4_fdm_ctor.txt", "w") as f:
        f.write(ct)

    # candidate vtables: any .rdata address referenced by the ctor whose first
    # two qwords are functions
    cands = []
    f0 = func(0x18010CDC0)
    for ad in f0.getBody().getAddresses(True):
        ins = listing.getInstructionAt(ad)
        if ins is None:
            continue
        for r in ins.getReferencesFrom():
            t = int(r.getToAddress().getOffset())
            if 0x1801E5000 <= t <= 0x1802891FF:
                try:
                    v0, v1 = qword(t), qword(t + 8)
                except Exception:
                    continue
                if fm.getFunctionAt(addr(v0)) and fm.getFunctionAt(addr(v1)):
                    if t not in cands:
                        cands.append(t)
    p("=== vtable candidates from ctor: %s ===" % [hex(c) for c in cands])

    for vt in cands:
        try:
            s2b0 = qword(vt + 0x2B0)
            s2c8 = qword(vt + 0x2C8)
        except Exception:
            continue
        if not (fm.getFunctionAt(addr(s2b0)) and fm.getFunctionAt(addr(s2c8))):
            continue
        d2b0 = dec(s2b0, 120)
        d2c8 = dec(s2c8, 120)
        ok = ("1fd3a" in d2b0.lower()) and ("1fd3d" in d2c8.lower())
        p("--- vtable %#x : slot2b0=%#x slot2c8=%#x CONTROL_OK=%s ---" % (vt, s2b0, s2c8, ok))
        p("   slot 0x2b0 body: %s" % d2b0.replace("\n", " ")[:300])
        p("   slot 0x2c8 body: %s" % d2c8.replace("\n", " ")[:300])
        if not ok:
            continue
        p("=== CONTROL PASSED for vtable %#x ; dumping slots 0x250..0x320 ===" % vt)
        for off in range(0x250, 0x328, 8):
            try:
                t = qword(vt + off)
            except Exception:
                break
            fn = fm.getFunctionAt(addr(t))
            if fn is None:
                p("  +%#05x  %#x  (not a function)" % (off, t))
                continue
            body = dec(t, 120).replace("\n", " ")
            # squeeze
            body = " ".join(body.split())
            p("  +%#05x  %#x  %s  ::  %s" % (off, t, fn.getName(), body[:260]))

    # ---- reveal-path strings ----
    for sname, sva in (("USE_ANIMATION_STYLE", 0x1801FD580),
                       ("gmLoadFUTPackOpenSublevel", 0x1801EE860),
                       ("gmUnloadFUTPackOpenAnimation", 0x180208828),
                       ("CREATE_PACK_STATUS", 0x180205F28),
                       ("PACK_CREATE_UNOPENED_PACK", 0x1801EC1B8),
                       ("NUM_RARES_IN_PACK", 0x1801EBF90)):
        xs = xrefs_to(sva)
        p("=== xrefs to %s (%#x): %d ===" % (sname, sva, len(xs)))
        for frm, typ, fn, ent in xs:
            p("   from %#x  %s  in %s @ %#x" % (frm, typ, fn, ent))

except Exception:
    traceback.print_exc()
finally:
    try:
        with open(OUT + "d4_vtable_and_xrefs.txt", "w") as f:
            f.write("\n".join(BUF))
        print("WROTE d4_vtable_and_xrefs.txt")
    except Exception:
        traceback.print_exc()
