c0a3f68ded
openfut-utas-host: the first live UTAS host. Serves GET /ut/game/<title>/club from OpenFUT Core via the FIFA17 adapter and reverse-proxies every other UTAS route verbatim to the Python oracle. Plaintext HTTP/1.1 keep-alive (no TLS); route classification before execution; a Core error on /club degrades to an empty page and never falls back to Python. CoreAccess is a host-owned boundary (the adapter stays transport-agnostic). openfut-adapter-fifa17::fut: owned_query (wire parse + FIFA id->name mapping, unknown id = hard error), entities (id<->name from committed tables), and club_response (FIFA _item shaping; drops items lacking a real FIFA asset id, never fabricates one). openfut-core submodule advanced to the reconciled trunk (6acae54 = 8c8a4116 multi-game + eab522a replace_squad/SquadRules + the /club semantic query). 11 host tests + adapter fut tests; 10/10 host mutations killed. rare=SP UNKNOWN. Retail rendering of Core inventory still blocked on the Core-card->asset-id identity decision (next phase).
80 lines
3.3 KiB
Rust
80 lines
3.3 KiB
Rust
//! # openfut-adapter-fifa17
|
|
//!
|
|
//! The FIFA 17 game adapter: everything that is true of *FIFA 17 specifically*
|
|
//! and must therefore stay out of OpenFUT Core and out of the generic protocol
|
|
//! crates.
|
|
//!
|
|
//! ## Layering
|
|
//!
|
|
//! ```text
|
|
//! openfut-protocol-blaze generic Blaze: Fire2 framing, Heat2/TDF codec
|
|
//! ▲
|
|
//! openfut-adapter-fifa17 THIS: FIFA 17 command tables, response bodies,
|
|
//! ▲ dispatch ordering, session identity
|
|
//! OpenFUT Core game-independent FUT domain (not yet wired)
|
|
//! ```
|
|
//!
|
|
//! A second title gets its own adapter crate and reuses the protocol layer
|
|
//! underneath. Nothing here is written to be shared with one; if something in
|
|
//! this crate turns out to be title-independent, it belongs one layer down.
|
|
//!
|
|
//! ## Modules
|
|
//!
|
|
//! * [`blaze`] — the Blaze/Fire2 RPC surface. Implemented, runtime validated.
|
|
//! * [`redirector`] — the first hop's `<serverinstanceinfo>` response.
|
|
//! Implemented; runtime validated against the retail client.
|
|
//! * [`roster`] — the FUT roster-update response, the last gate before the hub.
|
|
//! Implemented; not yet runtime validated.
|
|
//! * [`fut`] — FUT/RS4 (UTAS) wire → Core semantic mappings; currently the
|
|
//! owned-player ("My Squad") search: query parse + FIFA-id→name resolution +
|
|
//! semantic filter/pagination. Pure mapping; no Rust UTAS host yet.
|
|
//!
|
|
//! Still served only by the Python backend: LSX/Origin (`:4216`), UTAS/RS4
|
|
//! (`:8099`) and POW/EASFC (`:8094`). Roster XML (`:8081`) has an adapter here
|
|
//! but no Rust host yet.
|
|
//!
|
|
//! **Nucleus (`:42131`) is deliberately not ported.** Instrumentation across
|
|
//! every live session showed the client never dials it: the listener is bound,
|
|
//! the handler logs unconditionally on connect, the client fetches the
|
|
//! `OSDK_NUCLEUS` config that carries the URL — and makes zero requests. It is
|
|
//! dead code on the observed path, so porting it would add an untested
|
|
//! component for no parity gain. See the vault's Protocol Findings.
|
|
//!
|
|
//! ## Provenance
|
|
//!
|
|
//! Ported from `fifa17-recon/tools/blaze_responder_v3b.py`, the implementation
|
|
//! that drove a retail FIFA 17 client from Origin login to an opened FUT pack.
|
|
//! Parity is tested, not asserted: `fixtures/blaze_transactions.jsonl` records
|
|
//! real request→response(s) transactions produced by the Python dispatcher, and
|
|
//! `tests/oracle_parity.rs` replays them byte-for-byte.
|
|
//!
|
|
//! ## Not a server
|
|
//!
|
|
//! This crate answers frames. It opens no socket, terminates no TLS and owns no
|
|
//! runtime. Hosting it is a separate, later decision — the Python backend
|
|
//! remains the live runtime and nothing here is wired into it.
|
|
//!
|
|
//! ```
|
|
//! use openfut_adapter_fifa17::blaze::{Adapter, AdapterConfig, Session};
|
|
//! use openfut_protocol_blaze::fire2::{Header, MsgType};
|
|
//! use openfut_protocol_blaze::heat2::Struct;
|
|
//!
|
|
//! let adapter = Adapter::new(AdapterConfig::loopback());
|
|
//! let mut session = Session::new("session-key", 0x656E5553);
|
|
//!
|
|
//! // Util::ping
|
|
//! let request = Header::new(0x0009, 0x0002, 1, MsgType::Message);
|
|
//! let out = adapter.dispatch(&request, &Struct::new(), &mut session, 1_754_870_400);
|
|
//!
|
|
//! assert_eq!(out.len(), 1);
|
|
//! assert_eq!(out[0].header.msg_type, MsgType::Reply);
|
|
//! ```
|
|
|
|
pub mod blaze;
|
|
pub mod fut;
|
|
pub mod redirector;
|
|
pub mod roster;
|
|
pub mod tls;
|
|
|
|
pub use blaze::{Adapter, AdapterConfig, Session};
|