# openfut-protocol-blaze Game-independent EA Blaze wire protocol: **Fire2** framing and the **Heat2/TDF** codec. This is the first Rust component of the Python → Rust migration. It was chosen first because it is the lowest layer that is genuinely game-independent, it has an executable oracle, and both existing Rust implementations of it are wrong. ## Scope | In | Out | |---|---| | Fire2 16-byte frame header, frame/stream splitting | Component and command *name* tables | | Heat2 tag packing, varints, the 11 value types | Notification IDs, response schemas | | A message = frame + decoded body, routed by number | Login sequencing, session identity | | Diagnostics dumps | Anything FIFA-17-specific | The boundary test: *could FIFA 18 or FIFA 23 use this without importing FIFA 17's command tables?* This crate knows `0x0009/0x0007` is component 9, command 7. That it means `Util::preAuth` is a FIFA 17 fact, and belongs in a FIFA 17 adapter. ## Provenance Ported from `fifa17-recon/tools/heat2.py` (TDF codec) and `fifa17-recon/tools/blaze_responder_v3b.py` (Fire2 framing) — the Python implementation that drove a retail FIFA 17 client from Origin login to an opened FUT pack. That implementation is the project's behavioural oracle, and this crate does not claim parity with it, it *tests* parity against it. ### Two superseded framing implementations Both other Fire2 implementations in this repository are wrong for FIFA 17, and this crate exists partly to replace them: * **`fifa-blaze/crates/blaze-proto/src/frame.rs`** — a **12-byte** header with a `u16` length, nibble-packed type/options, an `error` field, and a JUMBO-frame escape flag. Its own doc comment says FIFA 23's variant "is UNKNOWN" and that Fire2 was picked because it "is the most likely candidate". It predates the FIFA 17 recon and nothing has since validated it. * **`fifa17-recon/tools/heat2.py::build_fire2_frame`** — packs `>IHHHHB3s`, putting a `u16 msgId` at `[10:12]` and `msgType` at `[12]`. Dead code: the responder carries a comment telling callers not to use it, and it is not on any live path. Its module docstring still describes the old layout. The proven layout is 16 bytes, with a `u24 msgNum` at `[10:13]` and `(msgType << 5) | userIndex` in byte 13. There is **no error field** (that is Fire v1) and **no jumbo flag** (the length is already a `u32`). The `payload_over_64kib_needs_no_jumbo_flag` test is the direct refutation. ## Confidence is not uniform `int`, `string`, `blob` and `struct` are validated byte-exact against captured FIFA 17 traffic. `list`, `map`, `union`, `varlist`, `objtype`, `objid` and `float` are marked UNVERIFIED in the oracle — they are absent from every capture we hold. `TypeId::is_verified()` reports which is which, and a test asserts the unverified ones stay flagged, so "Rust and Python agree" can never be quietly read as "this is how EA does it". ## Testing ```bash cargo test -p openfut-protocol-blaze # 43 unit + 10 differential + 1 doc ./check-parity.sh # regenerate fixtures, then re-verify ``` Differential vectors live in `fixtures/`, generated by `fixtures/generate.py` from the Python oracle. 25 of the TDF vectors and 6 of the Fire2 vectors are `origin: "live"` — real payloads from the responder's own builders, including the preAuth reply (~11.8 KB) that is the first RPC FIFA 17 sends. Comparison is **byte-for-byte**. FIFA 17's deserialisers hard-freeze on an unexpected shape, so "semantically equivalent" is not a useful category at this layer. (It *is* the right call one layer up at UTAS/JSON — see `fifa17-recon/tools/test_fut_contract.py`.) Regenerate fixtures after any change to the Python oracle: ```bash python3 fixtures/generate.py # rewrite python3 fixtures/generate.py --check # assert committed files are current ``` ## No runtime dependencies Deliberate. This is a byte-level codec whose oracle is stdlib-only Python; there is nothing here a third-party crate can do that `std` cannot. In particular the crates.io `tdf` crate (already a `fifa-blaze` dependency) is **not** used: it targets a generic BlazeSDK 15.x dialect, and adopting it would substitute someone else's reading of the format for our own captured evidence. It remains useful as an independent cross-check, not as the implementation. `serde_json` is a dev-dependency only, for reading fixture files. ## Not yet done * No TLS, no sockets, no async. Framing and codec only; transport belongs to whatever hosts this. * The Blaze **redirector** (HTTPS + XML `getServerInstance`) is a different protocol and is not here. * Nothing consumes this crate yet. The Python backend remains the live runtime, untouched.