"""DIMENSION 5 pass 5: (a) the CreateUser response object's own handler, which is what
consumes starterPack/bonusPacks; (b) the other writer of model+0x20950; (c) the two
0x273d event handlers; (d) callers of FUN_180017390 (the second caller of the count
setter).

Correction carried into this pass: pass 4's "model=False" filter was TOO NARROW. The
userInfo deser reaches the model through the raw singleton FUN_18011a830, but UI code
reaches the SAME object through the ref-counted service locator
FUN_180009c80(&out, FUN_1800d7170()). Both then call slots 0x160 / 0x4d8 / 0x4e0 /
0x530 on it, so the locator form is the same class. Do not read pass 4's False column
as "not the model".

CONTROL for the response-vtable walk: slot +0x08 of the resolved vtable must be the
known deserializer 0x18014cc60. If it is not, the vtable is the wrong one and every
other slot read from it is meaningless.
"""
import traceback, os

OUT = "/tmp/claude-1000/-home-alex-Documents-OpenFUT/8e521ca1-ca3e-4138-bb96-df1744dd1d30/scratchpad/store"

try:
    print("### FUN_18014c810 (CreateUser response ctor)")
    src = dec(0x18014c810, 300)
    print(src)
    open(os.path.join(OUT, "dec_ctor_18014c810.c"), "w").write(src)

    # find the vtable it installs: any .rdata address referenced whose +8 is 0x18014cc60
    print("\n### hunting the response vtable (control: slot +0x08 == 0x18014cc60)")
    hits = find_all((0x18014cc60).to_bytes(8, "little"), blocks=(".rdata", ".data"))
    for h in hits:
        vt = h - 8
        print("  candidate vtable %#x  (slot+8 = deser)" % vt)
        for i in range(0, 0x60, 8):
            t = qword(vt + i)
            fn = fm.getFunctionAt(addr(t)) if 0x180000000 <= t < 0x181000000 else None
            print("     +%#04x -> %#x %s" % (i, t, fn.getName() if fn else ""))
        for frm, typ, fn, ent in xrefs_to(vt):
            print("     vtable xref from %#x in %s @ %#x" % (frm, fn, ent))

    print("\n### callers of FUN_180017390 (second caller of the 0x4e0 count setter)")
    for frm, typ, fn, ent in xrefs_to(0x180017390):
        print("  from %#x (%s) in %s @ %#x" % (frm, typ, fn, ent))

    print("\n### FUN_180199cc0 (raises 0x273d)")
    s = dec(0x180199cc0, 300)
    print(s)
    open(os.path.join(OUT, "dec_fn_180199cc0.c"), "w").write(s)

    for a, nm in ((0x18010cdc0, "writer2_18010cdc0"), (0x18007e7f0, "evt_18007e7f0"),
                  (0x1800b3900, "evt_1800b3900")):
        s = dec(a, 300)
        open(os.path.join(OUT, "dec_%s.c" % nm), "w").write(s)
        print("\n### %s len=%d -> file" % (nm, len(s)))
except Exception:
    traceback.print_exc()
