From e92aed315988916a397809f2a530fa6d893ef3ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20P=C4=99dzich?= Date: Tue, 18 Feb 2025 11:17:11 +0100 Subject: [PATCH] feat: add 2022 spec participants packet parser --- src/constants/mod.rs | 203 ++++++++++++++++++++++++++++++++++++ src/lib.rs | 5 +- src/packets/event.rs | 2 +- src/packets/mod.rs | 41 ++++++-- src/packets/participants.rs | 34 ++++++ 5 files changed, 275 insertions(+), 10 deletions(-) create mode 100644 src/packets/participants.rs diff --git a/src/constants/mod.rs b/src/constants/mod.rs index 708aec0..e8a79dc 100644 --- a/src/constants/mod.rs +++ b/src/constants/mod.rs @@ -678,3 +678,206 @@ bitflags! { const UDP_ACTION_12 = 0x80000000; } } + +#[non_exhaustive] +#[derive( + BinRead, + Eq, + PartialEq, + Ord, + PartialOrd, + Copy, + Clone, + Debug, + Serialize, + Deserialize, +)] +#[br(little, repr(u8))] +pub enum TeamId { + Mercedes = 0, + Ferrari = 1, + RedBull = 2, + Williams = 3, + AstonMartin = 4, + Alpine = 5, + /// Aliases: [`TeamId::AlphaTauri`] + Vcarb = 6, + Haas = 7, + McLaren = 8, + /// Aliases: [`TeamId::AlfaRomeo`] + Sauber = 9, + Mercedes2020 = 85, + Ferrari2020 = 86, + RedBull2020 = 87, + Williams2020 = 88, + RacingPoint2020 = 89, + Renault2020 = 90, + AlphaTauri2020 = 91, + Haas2020 = 92, + McLaren2020 = 93, + AlfaRomeo2020 = 94, + AstonMartinDb11V12 = 95, + AstonMartinVantage = 96, + AstonMartinSafetyCar = 97, + FerrariF8Tributo = 98, + FerrariRoma = 99, + McLaren720S = 100, + McLarenArtura = 101, + MercedesSafetyCar = 102, + MercedesAmgGtrPro = 103, + F1CustomTeam = 104, + Prema2021 = 106, + UniVirtuosi2021 = 107, + Carlin2021 = 108, + Hitech2021 = 109, + ArtGrandPrix2021 = 110, + MpMotorsport2021 = 111, + Charouz2021 = 112, + Dams2021 = 113, + Campos2021 = 114, + Bwt2021 = 115, + Trident2021 = 116, + MercedesAmgGtBlackSeries = 117, + Prema2022 = 118, + UniVirtuosi2022 = 119, + Carlin2022 = 120, + Hitech2022 = 121, + ArtGrandPrix2022 = 122, + MpMotorsport2022 = 123, + Charouz2022 = 124, + Dams2022 = 125, + Campos2022 = 126, + VanAmersfort2022 = 127, + Trident2022 = 128, + MyTeam = 255, +} + +#[allow(non_upper_case_globals)] +impl TeamId { + pub const AlphaTauri: TeamId = TeamId::Vcarb; + pub const AlfaRomeo: TeamId = TeamId::Sauber; +} + +#[non_exhaustive] +#[derive( + BinRead, + Eq, + PartialEq, + Ord, + PartialOrd, + Copy, + Clone, + Debug, + Serialize, + Deserialize, +)] +#[br(little, repr(u8))] +pub enum Nationality { + Unknown = 0, + American = 1, + Argentinian = 2, + Australian = 3, + Austrian = 4, + Azerbaijani = 5, + Bahraini = 6, + Belgian = 7, + Bolivian = 8, + Brazilian = 9, + British = 10, + Bulgarian = 11, + Cameroonian = 12, + Canadian = 13, + Chilean = 14, + Chinese = 15, + Colombian = 16, + CostaRican = 17, + Croatian = 18, + Cypriot = 19, + Czech = 20, + Danish = 21, + Dutch = 22, + Ecuadorian = 23, + English = 24, + Emirian = 25, + Estonian = 26, + Finnish = 27, + French = 28, + German = 29, + Ghanaian = 30, + Greek = 31, + Guatemalan = 32, + Honduran = 33, + HongKonger = 34, + Hungarian = 35, + Icelander = 36, + Indian = 37, + Indonesian = 38, + Irish = 39, + Israeli = 40, + Italian = 41, + Jamaican = 42, + Japanese = 43, + Jordanian = 44, + Kuwaiti = 45, + Latvian = 46, + Lebanese = 47, + Lithuanian = 48, + Luxembourger = 49, + Malaysian = 50, + Maltese = 51, + Mexican = 52, + Monegasque = 53, + NewZealander = 54, + Nicaraguan = 55, + NorthernIrish = 56, + Norwegian = 57, + Omani = 58, + Pakistani = 59, + Panamanian = 60, + Paraguayan = 61, + Peruvian = 62, + Polish = 63, + Portuguese = 64, + Qatari = 65, + Romanian = 66, + Russian = 67, + Salvadoran = 68, + Saudi = 69, + Scottish = 70, + Serbian = 71, + Singaporean = 72, + Slovakian = 73, + Slovenian = 74, + SouthKorean = 75, + SouthAfrican = 76, + Spanish = 77, + Swedish = 78, + Swiss = 79, + Thai = 80, + Turkish = 81, + Uruguayan = 82, + Ukrainian = 83, + Venezuelan = 84, + Welsh = 85, + Barbadian = 86, + Vietnamese = 87, +} + +#[non_exhaustive] +#[derive( + BinRead, + Eq, + PartialEq, + Ord, + PartialOrd, + Copy, + Clone, + Debug, + Serialize, + Deserialize, +)] +#[br(little, repr(u8))] +pub enum YourTelemetry { + Restricted = 0, + Public = 1, +} diff --git a/src/lib.rs b/src/lib.rs index 38a8857..9b07cc0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,7 +2,7 @@ pub mod constants; pub mod packets; use crate::constants::PacketId; -use crate::packets::{F1PacketEventData, F1PacketLapData, F1PacketMotionData, F1PacketSessionData}; +use crate::packets::{F1PacketEventData, F1PacketLapData, F1PacketMotionData, F1PacketParticipantsData, F1PacketSessionData}; use binrw::io::Cursor; use binrw::{BinRead, BinReaderExt, BinResult}; @@ -81,4 +81,7 @@ pub struct F1PacketBody { /// Details of events that happen during the course of a session. #[br(if(packet_id == PacketId::Event), args(packet_format))] pub event: Option, + /// List of participants in the race. + #[br(if(packet_id == PacketId::Participants), args(packet_format))] + pub participants: Option, } diff --git a/src/packets/event.rs b/src/packets/event.rs index c3b7db2..3deef4c 100644 --- a/src/packets/event.rs +++ b/src/packets/event.rs @@ -131,6 +131,6 @@ pub enum EventDataDetails { Buttons { /// Bit flags specifying which buttons are currently pressed. #[br(map(|bits: u32| ButtonStatus::from_bits_truncate(bits)))] - button_status: ButtonStatus + button_status: ButtonStatus, }, } diff --git a/src/packets/mod.rs b/src/packets/mod.rs index 218cebe..ff899c7 100644 --- a/src/packets/mod.rs +++ b/src/packets/mod.rs @@ -1,18 +1,19 @@ -pub mod motion; -pub mod session; -pub mod lap_data; pub mod event; +pub mod lap_data; +pub mod motion; +pub mod participants; +pub mod session; use crate::constants::{ - BrakingAssist, DynamicRacingLine, - DynamicRacingLineType, ForecastAccuracy, Formula, GameMode, - GearboxAssist, Ruleset, SafetyCarStatus, SessionLength, SessionType, - TrackId, Weather, MAX_AI_DIFFICULTY, MAX_NUM_CARS, MAX_NUM_MARSHAL_ZONES, - MAX_NUM_WEATHER_FORECAST_SAMPLES, + BrakingAssist, DynamicRacingLine, DynamicRacingLineType, ForecastAccuracy, + Formula, GameMode, GearboxAssist, Ruleset, SafetyCarStatus, SessionLength, + SessionType, TrackId, Weather, MAX_AI_DIFFICULTY, MAX_NUM_CARS, + MAX_NUM_MARSHAL_ZONES, MAX_NUM_WEATHER_FORECAST_SAMPLES, }; use crate::packets::event::EventDataDetails; use crate::packets::lap_data::LapData; use crate::packets::motion::CarMotionData; +use crate::packets::participants::ParticipantsData; use crate::packets::session::{MarshalZone, WeatherForecastSample}; use binrw::BinRead; @@ -251,6 +252,30 @@ pub struct F1PacketMotionExData { pub front_wheels_angle: f32, } +/// Data of participants in the session, mostly relevant for multiplayer. +#[derive( + BinRead, PartialEq, PartialOrd, Clone, Debug, Serialize, Deserialize, +)] +#[br( + little, + import(packet_format: u16), + assert( + num_active_cars <= MAX_NUM_CARS, + "Participants packet has an invalid number of active cars: {}", + num_active_cars + ) +)] +pub struct F1PacketParticipantsData { + /// Number of active cars in the data (no greater than 22) + #[br(map(u8_to_usize))] + pub num_active_cars: usize, + /// Data for all participants. + /// Should have a size equal to + /// [`num_active_cars`](field@F1PacketParticipantsData::num_active_cars) + #[br(count(num_active_cars), args{ inner: (packet_format,) })] + pub participants: Vec, +} + pub(crate) fn u8_to_bool(value: u8) -> bool { value == 1 } diff --git a/src/packets/participants.rs b/src/packets/participants.rs new file mode 100644 index 0000000..94748fe --- /dev/null +++ b/src/packets/participants.rs @@ -0,0 +1,34 @@ +use super::{read_name, u8_to_bool}; +use crate::constants::{Nationality, TeamId, YourTelemetry}; + +use binrw::BinRead; +use serde::{Deserialize, Serialize}; + +#[non_exhaustive] +#[derive( + BinRead, PartialEq, PartialOrd, Clone, Debug, Serialize, Deserialize, +)] +#[br(little, import(_packet_format: u16))] +pub struct ParticipantsData { + /// Whether the vehicle is controlled by AI + #[br(map(u8_to_bool))] + pub ai_controlled: bool, + /// Driver's ID + pub driver_id: u8, + /// Unique ID for network players + pub network_id: u8, + /// Team's ID + pub team_id: TeamId, + /// Whether my team is being used + #[br(map(u8_to_bool))] + pub my_team: bool, + /// Race number of the car + pub race_number: u8, + /// Driver's nationality + pub nationality: Nationality, + /// Driver's name + #[br(try_map(read_name))] + pub name: String, + /// Player's UDP visibility setting + pub your_telemetry: Option, +}