"""DIMENSION 4 (duplicates), pass 8: name the request emitted on the
NOT-duplicate branch.

The FUT item-manager singleton's vtable was resolved from the LIVE process
(read-only): DAT_1802e6398 -> object 0xb81b0940 -> vtable live 0x6ffffc35c2a0 =
static 0x18021c2a0, control-checked against the RS4:FutSquadSaveServerResponse
literal. Slots:
    +0x0c0 -> 0x1801180a0   <- called on the NOT-duplicate branch of FUN_18009bc40
    +0x160 -> 0x18011b780   <- container the CreatePack fixup writes into
    +0x7d8 -> 0x18011b500   <- container the HAS_DUPLICATE providers read
    +0xa08 -> 0x18011cca0   <- item registration (called by the item deser)
    +0xa40 -> 0x18011bf40

HYPOTHESIS: 0x1801180a0 issues a server call, and the 0x20-byte record
{itemId:int64, 7:int32, 0, 0} it is handed is an item-action list entry (7 being
an action/pile enum). If so the duplicate flag GATES an existing endpoint rather
than unlocking a new one.

CONTROL: 0x18011b780 must be a small getter returning an object whose +0x30 is a
vector (that is how FUN_180162880 uses it), and 0x18011b500 likewise; if those
two do not look like getters, the live vtable read is wrong and nothing here
stands.
"""
import traceback

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

def w(fh, s=""):
    fh.write(str(s) + "\n")

def dump(fh, a, label, depth=0):
    s = dec(a)
    w(fh, "")
    w(fh, "#" * 70)
    w(fh, "# %s  %#x  len(src)=%d  FULL" % (label, a, len(s)))
    w(fh, "#" * 70)
    w(fh, s)

try:
    fh = open(OUT, "w")
    dump(fh, 0x18011B780, "CONTROL vt+0x160 container getter")
    dump(fh, 0x18011B500, "CONTROL vt+0x7d8 container getter")
    dump(fh, 0x1801180A0, "vt+0x0c0  the call made when NOT a duplicate")
    dump(fh, 0x18011CCA0, "vt+0xa08 item registration")

    w(fh, "")
    w(fh, "=== callees of 0x1801180a0 ===")
    f = func(0x1801180A0)
    if f is not None:
        seen = set()
        it = listing.getInstructions(f.getBody(), True)
        while it.hasNext():
            ins = it.next()
            for r in ins.getReferencesFrom():
                t = int(r.getToAddress().getOffset())
                g = fm.getFunctionAt(addr(t))
                if g is not None and t not in seen:
                    seen.add(t)
                    w(fh, "   %#x %s" % (t, g.getName()))
        for t in sorted(seen):
            dump(fh, t, "callee of vt+0xc0")

    fh.close()
    print("WROTE", OUT)
except Exception:
    traceback.print_exc()
