fix(fifa17): open Seasons/Draft via /settings config gate
RE-confirmed root cause: the FUT client's settings applier FUN_18011dc50 is
the sole writer of the IS_* UI gate bytes (byte = field==1). The Rust host
served GET /ut/game/fifa17/settings as {"configs":[]}, so the applier never
ran and Single-Player Seasons/Draft refused to open while issuing ZERO server
requests (friendlySeasonsEnabled -> settings slot 0x16 -> model byte 0x1fd3a
= IS_FRIENDLY_SEASON_ENABLED).
settings_body() is now env-gated: default (OPENFUT_FUT_SETTINGS unset/off)
keeps the empty baseline; OPENFUT_FUT_SETTINGS=gates returns the enable list.
The applier writes ALL gate bytes, so the working store flags (storeEnabled,
coinEnabled, cardPackStoreEnabled, pointsPackStoreEnabled, tradingEnabled,
+ _JP variants) are re-asserted alongside the Seasons/Draft enables to avoid
clearing the live Store. Instantly revertible by restarting without the env.
This commit is contained in:
@@ -24,9 +24,48 @@ pub fn accountinfo_body() -> Value {
|
||||
json!({})
|
||||
}
|
||||
|
||||
/// `GET …/settings` — production oracle returns an empty config list.
|
||||
/// `GET …/settings` — the FUT client applies this `configs` array via the applier
|
||||
/// `FUN_18011dc50`, the ONLY writer of the `IS_*` UI gate bytes (each
|
||||
/// `byte = (field == 1)`). A flag never sent is a gate never opened — which is why
|
||||
/// Single-Player Seasons/Draft refuse to open while issuing ZERO server requests
|
||||
/// (`friendlySeasonsEnabled` → slot `[0x16]` → model byte `0x1fd3a`
|
||||
/// `IS_FRIENDLY_SEASON_ENABLED`; RE-confirmed via pyghidra on CardsDLL).
|
||||
///
|
||||
/// Default (`OPENFUT_FUT_SETTINGS` unset/`off`) is the historical empty baseline.
|
||||
/// `OPENFUT_FUT_SETTINGS=gates` populates the array. SAFETY: populating it is what
|
||||
/// makes the applier RUN, and it then writes EVERY gate byte, so the already-live
|
||||
/// store flags MUST be re-asserted here or enabling Seasons would clear the working
|
||||
/// Store (those reach the client today via the Blaze FUT_RS4_CONFIG store, not
|
||||
/// here). Mirrors the audited list in `utas_server.py` `_SETTINGS_KEEP`/`_GATES`.
|
||||
pub fn settings_body() -> Value {
|
||||
json!({ "configs": [] })
|
||||
if std::env::var("OPENFUT_FUT_SETTINGS").as_deref() != Ok("gates") {
|
||||
return json!({ "configs": [] });
|
||||
}
|
||||
// Already-live store flags re-asserted (pinned to their working state).
|
||||
const KEEP: &[&str] = &[
|
||||
"storeEnabled",
|
||||
"storeEnabled_JP",
|
||||
"coinEnabled",
|
||||
"coinEnabled_JP",
|
||||
"cardPackStoreEnabled",
|
||||
"cardPackStoreEnabled_JP",
|
||||
"pointsPackStoreEnabled",
|
||||
"tradingEnabled",
|
||||
];
|
||||
// Mode gates that nothing has ever populated (the point of the change).
|
||||
const GATES: &[&str] = &[
|
||||
"friendlySeasonsEnabled",
|
||||
"enableDraftMode",
|
||||
"enableSinglePlayerDraftMode",
|
||||
"enableOfflineDraftMode",
|
||||
"tournamentQuitEnabled",
|
||||
];
|
||||
let configs: Vec<Value> = KEEP
|
||||
.iter()
|
||||
.chain(GATES.iter())
|
||||
.map(|k| json!({ "type": k, "value": 1 }))
|
||||
.collect();
|
||||
json!({ "configs": configs })
|
||||
}
|
||||
|
||||
/// `GET …/leaderboards/options` — production oracle (FUT_MODES off) returns an
|
||||
|
||||
Reference in New Issue
Block a user