From b996c0673d0d9ca14bf8671c4c7e27128964c3d8 Mon Sep 17 00:00:00 2001 From: funman300 Date: Tue, 4 Aug 2026 21:25:43 -0700 Subject: [PATCH] fifa17-recon: sweep every staff table at once (t*@) The manager sweep (subtype 4, ids 1-5000) came back with 5000 records at cardtype 2 -- confirming FUN_1800d8330(4)=2 live -- and NOTHING written: no name, no nation, no teamid, and no miss-fill either. Our sentinel rating 7, position 25 and attributes all survived. So either manager ids are not in 1-5000 or that branch keys off something the player branch does not. Guessing the id space costs a club visit per guess, so 't*@lo-hi' now fans all five non-player tables across one range in a single response: 4 managercards, 5 headcoachcards, 6 gkcoachcards, 7 physiocards, 8 fitnesscoachcards. One staff tab load tests 1000 ids against all five. The full table set, from the DLL's own strings: players, managercards, headcoachcards, fitnesscoachcards, gkcoachcards, physiocards, fancards, newcards -- plus a consumables family (contract, fitness, healing, position, training and playstyle modifiers, formation and league mods) and club items (badges, balls, kits) which are almost certainly NOT DB-resolved the way cards are. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01VUT92pz6RWKih9dSr8ZpxW --- fifa17-recon/tools/utas_server.py | 44 ++++++++++++++++++++----------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/fifa17-recon/tools/utas_server.py b/fifa17-recon/tools/utas_server.py index ce400d5..2890139 100755 --- a/fifa17-recon/tools/utas_server.py +++ b/fifa17-recon/tools/utas_server.py @@ -1306,6 +1306,10 @@ def sweep_window(): _SWEEP_SPEC = None _SWEEP_POS = 0 _SWEEP_SUBTYPE = 0 # 0..3 = player; see _parse_window for the other tables +# The five non-player card tables, as dispatched by FUN_1800d8330: +# 4 -> managercards 5 -> headcoachcards 6 -> gkcoachcards +# 7 -> physiocards 8 -> fitnesscoachcards +_STAFF_SUBTYPES = [4, 5, 6, 7, 8] def _parse_window(win): @@ -1329,10 +1333,13 @@ def _parse_window(win): _SWEEP_SUBTYPE = 0 if win.startswith("t") and "@" in win: head, win = win.split("@", 1) - try: - _SWEEP_SUBTYPE = int(head[1:], 0) - except ValueError: - return None + if head == "t*": + _SWEEP_SUBTYPE = -1 # fan every staff table across the range + else: + try: + _SWEEP_SUBTYPE = int(head[1:], 0) + except ValueError: + return None auto = win.startswith("auto:") step = None if auto: @@ -1382,21 +1389,28 @@ def sweep_items(): else: start, end = lo, hi + # 't*@' fans EVERY staff subtype across the range at once, so one staff-tab + # load tests managercards / headcoachcards / fitnesscoachcards / physiocards / + # gkcoachcards together instead of costing five separate visits. + subs = _STAFF_SUBTYPES if _SWEEP_SUBTYPE == -1 else [_SWEEP_SUBTYPE] + + # Only cardsubtypeid ever changes. itemType stays "player" because the merge + # dispatches on the subtype alone and the wire shape of a real staff item has + # never been observed -- inventing one is the change class that freezes this + # client. out = [] for pid in range(start, end + 1): - it = _item(SWEEP_ID_BASE + (pid - lo), pid, SWEEP_SENTINEL_RATING, - "ST", 0, 0, 0, [1, 1, 1, 1, 1, 1]) - if _SWEEP_SUBTYPE: - # Only the subtype is changed. itemType stays "player" because the - # merge dispatches on cardsubtypeid alone and the wire shape for a - # staff item has never been observed -- inventing one is the change - # class that freezes the client. - it["cardsubtypeid"] = _SWEEP_SUBTYPE - out.append(it) - log(" SWEEP: serving %d candidate id(s) %d..%d%s subtype=%d " + for si, sub in enumerate(subs): + it = _item(SWEEP_ID_BASE + (pid - lo) * len(subs) + si, pid, + SWEEP_SENTINEL_RATING, "ST", 0, 0, 0, [1, 1, 1, 1, 1, 1]) + if sub: + it["cardsubtypeid"] = sub + out.append(it) + log(" SWEEP: serving %d item(s) for id(s) %d..%d%s subtype(s)=%s " "[synthetic, nothing saved]" % (len(out), start, end, - (" (auto, %d..%d done)" % (lo, end)) if step else "", _SWEEP_SUBTYPE)) + (" (auto, %d..%d done)" % (lo, end)) if step else "", + ",".join(str(s) for s in subs))) return out