Files
OpenFUT/fifa17-recon/tools
funman300 4c5cc3ab4b fifa17-recon: THE MY CLUB COUNTER -- it was clubPlayers in GET /hub all along
The tile's big number is `clubPlayers` (atom 0x90) in the body of GET ut/%s/hub, a
route we have answered with {} for the life of the project.

The chain, re-derived independently by two agents (one via Ghidra, one via raw PE plus
capstone with no decompiler) and checked by two reviewers:

  clubPlayers(0x90) --INT getter 0x1801c79d0--> clamp FUN_1800d7b30 (<=0 becomes 0)
    -> R+0x3c, where R = FUT data-manager slot +0x1f8 (FUN_18011a810 is literally
       `lea rax,[rcx+0x1fd70]; ret`)
    -> read by FUN_1800b0250, published as TEXT0 of TILE_ID 0x210
    -> captions FUT_GH_TOTAL_PLAYERS_0/_1 at 0x18020a0f8 / 0x18020a110
  auctionCount(0x33) -> R+0x38 -> TEXT0 of TILE_ID 0x1b0, the TRANSFERS tile

FUN_180139610 (the hub body parser, 14855 chars, censused in full: 18 atoms, none
missed) is the ONLY writer of +0x3c anywhere in the image, one write, guarded by
`if (iVar6 != 0x90)`. This is not a candidate, it is the field.

I SPENT A DAY ON THE WRONG SURFACE AND WROTE THE WRONG CONCLUSION. REBUILD_RESEARCH
S19 declared the counter "not server-fixable" with a mechanism that was internally
correct and completely beside the point: the tile never read the club-stat store.
Two things reinforced the error and both are now fixed in the docs:

  * ENDPOINT_MAP said this response "uses C++ reflection / vtable dispatch, NOT an
    inline atom ladder -- no static field ladder to read" and marked it a GAP. False.
    There is an inline ladder, one indirection away.
  * The eight-row MY CLUB panel was assumed to be FUN_180043b90 case 1, which
    publishes six keys, and I treated the six-versus-eight mismatch as a puzzle rather
    than as evidence. It is a DIFFERENT provider, FUN_180094ce0, using a different
    string family (FUT_MYCLUB_*), reading neither the mode tag nor any type id we were
    sending. Two providers; we were reading the wrong one.

That is the third negative claim of this shape to fail today, after "this deserializer
has no skip handler" and "the factory does not wipe the stat map".

auctionCount is included as a FREE CONTROL: different field, different tile, so if MY
CLUB moves and TRANSFERS does not, delivery is fine and something is specific to +0x3c.

Default ON. Freeze risk is low by construction rather than by belief: a flat object of
two integers, both read with the INT getter, so there is no array, no nested object and
no type-desync surface. FUT_HUBDATA=0 restores {}.

Contract guard added, and verified to bite rather than merely pass:
  default        439 checks, 0 failed
  FUT_HUBDATA=0  435 checks, 3 FAILED  (clubPlayers missing / not a number)
A regression here would otherwise be silent: still 200, still valid JSON, tile quietly
back to 0.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VUT92pz6RWKih9dSr8ZpxW
2026-08-04 15:29:59 -07:00
..