fifa17-recon: correct tradePile/counts shape, and narrow the marketdata array fix

Two follow-ups on the working transfer market.

1. GET /tradePile/counts now returns the FutGetAuctionCount shape
   ({count, maxAuctionsAllowed, offered, selling, sold}, all scalar ints, atoms
   0xbc/0x1bf/0x1e5/0x2b8/0x2c9) via a dedicated route ordered before /tradePile.
   Previously it fell through to tradepile_route and got the auction-LIST body, which
   the counts deser skips, leaving every tally at its constructor default. Survivable
   but wrong; the doc flags the loaded byte at +0x28 as gating a completion-handler
   branch. selling reflects real STORE.listings().

2. Narrowed the marketdata bare-array fix to /pricelimits only. The client sends TWO
   marketdata requests: /marketdata/pricelimits (GetSuggestedPricing, a bare array,
   the thing that froze) and plain /marketdata?defId=N (price comparison, an OBJECT).
   The prior commit returned the array for both, which the contract suite caught
   (test_market_bodies: 'list' has no attribute get) -- plain /marketdata wants
   {minPrice,maxPrice} and was never the freeze. Returning the array for it would be
   the same desync in reverse. Now: pricelimits -> array, plain marketdata -> object.

The contract suite catching my over-broadened fix before it reached the game is the
suite doing its job. 439 contract checks pass, market unit suite passes.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
funman300
2026-08-06 14:39:38 -07:00
parent 43557989f5
commit 245c22161b
+28 -1
View File
@@ -673,7 +673,15 @@ def marketdata_route(h):
pricing is a later refinement, not a freeze concern.
"""
from urllib.parse import urlparse, parse_qs
q = parse_qs(urlparse(h.path).query)
parsed = urlparse(h.path)
# ONLY /marketdata/pricelimits is the bare-array GetSuggestedPricing. Plain
# /marketdata?defId=N is a DIFFERENT endpoint (price comparison) that takes an
# OBJECT: it was served {minPrice,maxPrice} in the frozen session and did NOT
# freeze, so it wants an object, not the array. Returning the array for it would
# be the same object-vs-array desync in reverse. Keep them distinct.
if not parsed.path.endswith("/pricelimits"):
return 200, {"minPrice": 150, "maxPrice": 15000}
q = parse_qs(parsed.query)
raw = q.get("defId", [""])[0]
ids = [int(x) for x in raw.split(",") if x.strip().isdigit()]
return 200, [{"defId": d, "minPrice": 150, "maxPrice": 15000} for d in ids]
@@ -1147,6 +1155,9 @@ ROUTES = [
(re.compile(G + r"/activeMessage"), lambda m, h: (200, {})),
# ---- transfer market / auction house (empty-but-valid; ENDPOINT_MAP market §)
# tradePile MUST precede /trade ("/tradePile" contains the "/trade" prefix).
# /tradePile/counts (GetAuctionCount) MUST precede /tradePile: the latter's regex
# also matches the /counts path, and the two responses are different shapes.
(re.compile(G + r"/tradePile/counts"), lambda m, h: auction_counts_route(h)),
(re.compile(G + r"/tradePile"), lambda m, h: tradepile_route(h)),
(re.compile(G + r"/trade"), lambda m, h: trade_route(h)),
(re.compile(G + r"/watchList"), lambda m, h: watchlist_route(h)),
@@ -2959,6 +2970,22 @@ def watchlist_route(h):
return 200, {"auctionInfo": [], "credits": STORE.coins(), "total": 0}
def auction_counts_route(h):
"""GET tradePile/counts -- FutGetAuctionCount (deser 0x180163770). Distinct from
/tradePile: this is the auction TALLY, not the listing list. Until now it fell
through to tradepile_route and got {auctionInfo,...}, which the counts deser skips,
leaving every count at its constructor default. Survivable but wrong.
All five fields are scalar ints (count 0xbc, maxAuctionsAllowed 0x1bf, offered
0x1e5, selling 0x2b8, sold 0x2c9), so there is no container-type freeze risk.
They are the only inputs to IS_MAX_AUCTIONS (FUN_1800377c0 = !(max<0 || cur<max));
maxAuctionsAllowed 100 with selling < 100 keeps the cap open.
"""
n = len(STORE.listings())
return 200, {"count": n, "maxAuctionsAllowed": 100,
"offered": 0, "selling": n, "sold": 0}
class H(http.server.BaseHTTPRequestHandler):
protocol_version = "HTTP/1.1"