//! # openfut-protocol-blaze //! //! Game-independent EA Blaze wire protocol: Fire2 framing and the Heat2/TDF //! codec. //! //! ## What belongs here //! //! Only things that are true of Blaze itself: //! //! * [`fire2`] — the 16-byte frame header and frame/stream splitting //! * [`heat2`] — tag packing, varints, and the eleven TDF value types //! * [`message`] — a frame plus its decoded body, routed by numeric //! component/command //! * [`diagnostics`] — dumps for capture review //! //! ## What does not belong here //! //! Anything that would have to change for a different title: command and //! component name tables, notification IDs, response schemas, login sequencing, //! session identity. FIFA 17 says `0x0009/0x0007` is `Util::preAuth`; this //! crate only knows it is component 9, command 7. A game adapter owns the rest. //! //! The test for a change landing in the right place: *could FIFA 18 or FIFA 23 //! use this without importing FIFA 17's command tables?* If not, it belongs in //! an adapter. //! //! ## Provenance and confidence //! //! Ported from the Python implementation in `fifa17-recon/tools/` that drove a //! retail FIFA 17 client from Origin login to an opened FUT pack — the //! project's behavioural oracle. Parity is not asserted, it is tested: the //! vectors in `fixtures/` are generated from that Python code and replayed //! byte-for-byte by `tests/oracle_parity.rs`. //! //! Confidence is not uniform, and the code says so rather than leaving it in a //! comment. Int, string, blob and struct layouts are proven against captured //! traffic; list, map, union, varlist, objtype, objid and float are not, and //! [`heat2::TypeId::is_verified`] reports which is which. //! //! ``` //! use openfut_protocol_blaze::fire2::{Frame, MsgType}; //! use openfut_protocol_blaze::heat2::{self, Struct, Value}; //! //! let body = Struct::new() //! .with("PID", Value::Int(33068179)) //! .with("NAME", Value::String("CAGE".into())); //! //! let frame = Frame::new(0x0001, 0x000A, 7, MsgType::Reply, heat2::encode(&body)); //! let wire = frame.encode(); //! //! let (parsed, used) = Frame::parse(&wire).unwrap(); //! assert_eq!(used, wire.len()); //! assert_eq!(parsed.header.component, 0x0001); //! assert_eq!(wire[13], 0x20); // msgType REPLY in the top 3 bits, userIndex 0 //! ``` #![forbid(unsafe_code)] pub mod diagnostics; pub mod error; pub mod fire2; pub mod heat2; pub mod message; pub use error::{Error, Result}; pub use fire2::{Frame, Header, MsgType}; pub use heat2::{Struct, Tag, TypeId, Value}; pub use message::Message;