fifa17-recon: populate transfer market with real listings (freeze-safe)

Serve 18 real-player auctions on GET auctionhouse (search) built to the reversed
auction record schema (deser 0x18013e410) field-for-field: itemData reuses
fut_store._item (the proven club/squad card parser 0x18013fe00), scalar fields
all HIGH-confidence reversed. Rating-based buy-now pricing; tradeId space
900000000+. tradePile/watchList stay empty (no live sell/watch flow yet). Toggle
off with FUT_MARKET=empty.

Extend test_fut_contract.py to validate EVERY populated record field type
(numbers/strings/bool/object) so the listings are proven freeze-safe OFFLINE
before the game parses them. 311 checks, all passing.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PN5bmpDVQR1aXgefyWAt7o
This commit is contained in:
funman300
2026-08-02 19:59:41 -07:00
parent 7a243aa795
commit f7f19aeed3
2 changed files with 86 additions and 15 deletions
+24 -1
View File
@@ -86,6 +86,29 @@ def test_market_bodies():
check("marketdata maxPrice is number", is_num(md.get("maxPrice")))
def test_auction_record_shape():
# Every populated auction record MUST match the reversed schema (deser
# 0x18013e410) field-for-field, or the market screen freezes. This proves the
# sample listings are freeze-safe OFFLINE, before the game ever parses them.
d = _get(G + "/auctionhouse?type=player&start=0&num=21")
recs = d.get("auctionInfo", [])
check("auctionhouse returns >=1 listing (or FUT_MARKET=empty)", is_arr(recs))
numeric = ["tradeId", "buyNowPrice", "startingBid", "currentBid", "expires",
"sellerEstablished", "coinsProcessed"]
strings = ["tradeState", "bidState", "sellerName"]
for r in recs:
check("record.itemData is object", is_obj(r.get("itemData")), repr(type(r.get("itemData"))))
check("record.watched is bool", isinstance(r.get("watched"), bool), repr(r.get("watched")))
for k in numeric:
check(f"record.{k} is number", is_num(r.get(k)), repr(r.get(k)))
for k in strings:
check(f"record.{k} is string", is_str(r.get(k)), repr(r.get(k)))
# itemData must itself be a valid card object (reuses club/squad parser)
it = r.get("itemData", {})
check("record.itemData.attributeList is array", is_arr(it.get("attributeList")))
check("record.itemData.resourceId is number", is_num(it.get("resourceId")))
def test_squad_boot():
# LoadActiveSquad (deser 0x18013d1f0): players MUST be array; empty body would reset
# the 23 slots. formation is a string. This is the boot-critical path.
@@ -115,7 +138,7 @@ def test_club_items():
def main():
tests = [test_credits, test_v2_store_gate, test_store_catalog, test_market_bodies,
test_squad_boot, test_massinfo_empty, test_club_items]
test_auction_record_shape, test_squad_boot, test_massinfo_empty, test_club_items]
try:
_get(G + "/user/credits")
except Exception as e: