From c4f08877aa6d40951c338476b1672fcc3a93b0ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20P=C4=99dzich?= Date: Thu, 20 Feb 2025 10:22:06 +0100 Subject: [PATCH] feat: add 2023 spec parser fields and constants --- src/bin/udpclient.rs | 5 +- src/constants/driver_id.rs | 40 +++++--- src/constants/mod.rs | 165 ++++++++++++++++----------------- src/constants/team_id.rs | 79 ++++++++++++++++ src/lib.rs | 30 +++++- src/packets/car_status.rs | 10 +- src/packets/event.rs | 11 +++ src/packets/lap.rs | 28 +++++- src/packets/lobby.rs | 13 ++- src/packets/mod.rs | 63 ++++++++++++- src/packets/participants.rs | 14 ++- src/packets/session_history.rs | 20 +++- src/packets/tyre_sets.rs | 49 ++++++++++ 13 files changed, 406 insertions(+), 121 deletions(-) create mode 100644 src/constants/team_id.rs create mode 100644 src/packets/tyre_sets.rs diff --git a/src/bin/udpclient.rs b/src/bin/udpclient.rs index e28ec5a..2d8efff 100644 --- a/src/bin/udpclient.rs +++ b/src/bin/udpclient.rs @@ -8,7 +8,8 @@ fn main() -> Result<(), Box> { loop { let (msg_size, _) = socket.recv_from(&mut buf)?; - let raw_data = &buf[..msg_size]; - let _parse_result = parse(raw_data)?; + let data = &buf[..msg_size]; + + parse(data)?; } } diff --git a/src/constants/driver_id.rs b/src/constants/driver_id.rs index 045d4e1..adec755 100644 --- a/src/constants/driver_id.rs +++ b/src/constants/driver_id.rs @@ -96,7 +96,7 @@ pub const FELIPE_DRUGOVICH: u8 = 98; pub const ROBERT_SCHWARTZMAN: u8 = 99; pub const ROY_NISSANY: u8 = 100; pub const MARINO_SATO: u8 = 101; -pub const AIDEN_JACKSON: u8 = 102; +pub const AIDAN_JACKSON: u8 = 102; pub const CASPER_AKKERMAN: u8 = 103; pub const JENSON_BUTTON: u8 = 109; pub const DAVID_COULTHARD: u8 = 110; @@ -113,15 +113,33 @@ pub const BENT_VISCAAL: u8 = 122; pub const ENZO_FITTIPALDI: u8 = 123; pub const MARK_WEBBER: u8 = 125; pub const JACQUES_VILLENEUVE: u8 = 126; -pub const JAKE_HUGHES: u8 = 127; -pub const FREDERIK_VESTI: u8 = 128; -pub const OLLI_CALDWELL: u8 = 129; -pub const LOGAN_SARGEANT: u8 = 130; -pub const CEM_BOLUKBASI: u8 = 131; -pub const AYUMU_IWASA: u8 = 132; -pub const CLEMENT_NOVALAK: u8 = 133; -pub const DENNIS_HAUGER: u8 = 134; -pub const CALAN_WILLIAMS: u8 = 135; +pub const JAKE_HUGHES_2022: u8 = 127; +pub const FREDERIK_VESTI_2022: u8 = 128; +pub const OLLI_CALDWELL_2022: u8 = 129; +pub const LOGAN_SARGEANT_2022: u8 = 130; +pub const CEM_BOLUKBASI_2022: u8 = 131; +pub const AYUMU_IWASA_2022: u8 = 132; +pub const CLEMENT_NOVALAK_2022: u8 = 133; +pub const DENNIS_HAUGER_2022: u8 = 134; +pub const CALAN_WILLIAMS_2022: u8 = 135; +pub const JACK_DOOHAN_2022: u8 = 136; +pub const AMAURY_CORDEEL_2022: u8 = 137; +pub const MIKA_HAKKINEN_2022: u8 = 138; +pub const CALLIE_MAYER: u8 = 127; +pub const NOAH_BELL: u8 = 128; +pub const JAKE_HUGHES: u8 = 129; +pub const FREDERIK_VESTI: u8 = 130; +pub const OLLI_CALDWELL: u8 = 131; +pub const LOGAN_SARGEANT: u8 = 132; +pub const CEM_BOLUKBASI: u8 = 133; +pub const AYUMU_IWASA: u8 = 134; +pub const CLEMENT_NOVALAK: u8 = 135; pub const JACK_DOOHAN: u8 = 136; pub const AMAURY_CORDEEL: u8 = 137; -pub const MIKA_HAKKINEN: u8 = 138; +pub const DENNIS_HAUGER: u8 = 138; +pub const CALAN_WILLIAMS: u8 = 139; +pub const JAMIE_CHADWICK: u8 = 140; +pub const KAMUI_KOBAYASHI: u8 = 141; +pub const PASTOR_MALDONADO: u8 = 142; +pub const MIKA_HAKKINEN: u8 = 143; +pub const NIGEL_MANSELL: u8 = 144; diff --git a/src/constants/mod.rs b/src/constants/mod.rs index 9ae7054..9538cc0 100644 --- a/src/constants/mod.rs +++ b/src/constants/mod.rs @@ -1,4 +1,5 @@ pub mod driver_id; +pub mod team_id; pub mod wheel_index; use binrw::BinRead; @@ -210,6 +211,8 @@ pub enum Formula { Supercars = 5, Esports = 6, F22021 = 7, + F1World = 8, + F1Elimination = 9, } #[non_exhaustive] @@ -350,6 +353,7 @@ pub enum DynamicRacingLineType { pub enum GameMode { EventMode = 0, GrandPrix = 3, + GrandPrix2023 = 4, TimeTrial = 5, Splitscreen = 6, OnlineCustom = 7, @@ -359,8 +363,11 @@ pub enum GameMode { Championship = 13, OnlineChampionship = 14, OnlineWeeklyEvent = 15, + BrakingPoint2023 = 17, Career2022 = 19, Career2022Online = 20, + Career2023 = 21, + Career2023Online = 22, Benchmark = 127, } @@ -583,6 +590,7 @@ pub enum InfringementType { RetryPenalty = 49, IllegalTimeGain = 50, MandatoryPitStop = 51, + AttributeAssigned = 54, } #[derive( @@ -678,85 +686,6 @@ bitflags! { } } -#[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, @@ -1108,6 +1037,7 @@ pub enum ActualTyreCompound { F1C3 = 18, F1C2 = 19, F1C1 = 20, + F1C0 = 21, F1Inter = 7, F1Wet = 8, ClassicDry = 9, @@ -1185,13 +1115,74 @@ pub struct LapValid(u8); bitflags! { impl LapValid: u8 { - /// Whether the whole lap is valid. Has a value of `0b0001` - const Overall = 0b0001; - /// Whether the sector 1 run is valid. Has a value of `0b0010` - const Sector1 = 0b0010; - /// Whether the sector 2 run is valid. Has a value of `0b0100` - const Sector2 = 0b0100; - /// Whether the sector 3 run is valid. Has a value of `0b1000` - const Sector3 = 0b1000; + /// Whether the whole lap is valid. Has a value of `0x01`. + const OVERALL = 0x01; + /// Whether the sector 1 run is valid. Has a value of `0x02`. + const SECTOR_1 = 0x02; + /// Whether the sector 2 run is valid. Has a value of `0x04`. + const SECTOR_2 = 0x04; + /// Whether the sector 3 run is valid. Has a value of `0x08`. + const SECTOR_3 = 0x08; } } + +#[non_exhaustive] +#[derive( + BinRead, + Eq, + PartialEq, + Ord, + PartialOrd, + Copy, + Clone, + Debug, + Serialize, + Deserialize, +)] +#[br(little, repr(u8))] +pub enum SpeedUnit { + MilesPerHour = 0, + KilometresPerHour = 1, +} + +#[non_exhaustive] +#[derive( + BinRead, + Eq, + PartialEq, + Ord, + PartialOrd, + Copy, + Clone, + Debug, + Serialize, + Deserialize, +)] +#[br(little, repr(u8))] +pub enum TemperatureUnit { + Celsius = 0, + Fahrenheit = 1, +} + +#[non_exhaustive] +#[derive( + BinRead, + Eq, + PartialEq, + Ord, + PartialOrd, + Copy, + Clone, + Debug, + Serialize, + Deserialize, +)] +#[br(little, repr(u8))] +pub enum Platform { + Invalid = 0, + Steam = 1, + PlayStation = 3, + Xbox = 4, + Origin = 6, + Unknown = 255, +} diff --git a/src/constants/team_id.rs b/src/constants/team_id.rs new file mode 100644 index 0000000..121406b --- /dev/null +++ b/src/constants/team_id.rs @@ -0,0 +1,79 @@ +pub const MERCEDES: u8 = 0; +pub const FERRARI: u8 = 1; +pub const RED_BULL: u8 = 2; +pub const WILLIAMS: u8 = 3; +pub const ASTON_MARTIN: u8 = 4; +pub const ALPINE: u8 = 5; +pub const ALPHA_TAURI: u8 = 6; +pub const VCARB: u8 = 6; +pub const HAAS: u8 = 7; +pub const MCLAREN: u8 = 8; +pub const ALFA_ROMEO: u8 = 9; +pub const SAUBER: u8 = 9; +pub const MERCEDES_2020: u8 = 85; +pub const FERRARI_2020: u8 = 86; +pub const RED_BULL_2020: u8 = 87; +pub const WILLIAMS_2020: u8 = 88; +pub const RACING_POINT_2020: u8 = 89; +pub const RENAULT_2020: u8 = 90; +pub const ALPHA_TAURI_2020: u8 = 91; +pub const HAAS_2020: u8 = 92; +pub const MCLAREN_2020: u8 = 93; +pub const ALFA_ROMEO_2020: u8 = 94; +pub const ASTON_MARTIN_DB11_V12: u8 = 95; +pub const ASTON_MARTIN_VANTAGE: u8 = 96; +pub const ASTON_MARTIN_SAFETY_CAR: u8 = 97; +pub const FERRARI_F8_TRIBUTO: u8 = 98; +pub const FERRARI_ROMA: u8 = 99; +pub const MCLAREN_720S: u8 = 100; +pub const MCLAREN_ARTURA: u8 = 101; +pub const MERCEDES_SAFETY_CAR: u8 = 102; +pub const MERCEDES_AMG_GTR_PRO: u8 = 103; +pub const F1_CUSTOM_TEAM: u8 = 104; +pub const PREMA_2021: u8 = 106; +pub const UNI_VIRTUOSI_2021: u8 = 107; +pub const CARLIN_2021: u8 = 108; +pub const HITECH_2021: u8 = 109; +pub const ART_GP_2021: u8 = 110; +pub const MP_MOTORSPORT_2021: u8 = 111; +pub const CHAROUZ_2021: u8 = 112; +pub const DAMS_2021: u8 = 113; +pub const CAMPOS_2021: u8 = 114; +pub const BWT_2021: u8 = 115; +pub const TRIDENT_2021: u8 = 116; +pub const MERCEDES_AMG_GT_BLACK_SERIES: u8 = 117; +pub const F1_22_PREMA_2022: u8 = 118; +pub const F1_22_VIRTUOSI_2022: u8 = 119; +pub const F1_22_CARLIN_2022: u8 = 120; +pub const F1_22_HITECH_2022: u8 = 121; +pub const F1_22_ART_GP_2022: u8 = 122; +pub const F1_22_MP_MOTORSPORT_2022: u8 = 123; +pub const F1_22_CHAROUZ_2022: u8 = 124; +pub const F1_22_DAMS_2022: u8 = 125; +pub const F1_22_CAMPOS_2022: u8 = 126; +pub const F1_22_VAN_AMERSFORT_2022: u8 = 127; +pub const F1_22_TRIDENT_2022: u8 = 128; +pub const MERCEDES_2022: u8 = 118; +pub const FERRARI_2022: u8 = 119; +pub const RED_BULL_2022: u8 = 120; +pub const WILLIAMS_2022: u8 = 121; +pub const ASTON_MARTIN_2022: u8 = 122; +pub const ALPINE_2022: u8 = 123; +pub const ALPHA_TAURI_2022: u8 = 124; +pub const HAAS_2022: u8 = 125; +pub const MCLAREN_2022: u8 = 126; +pub const ALFA_ROMEO_2022: u8 = 127; +pub const KONNERSPORT_2022: u8 = 128; +pub const KONNERSPORT: u8 = 129; +pub const F1_23_PREMA_2022: u8 = 130; +pub const F1_23_VIRTUOSI_2022: u8 = 131; +pub const F1_23_CARLIN_2022: u8 = 132; +pub const F1_23_MP_MOTORSPORT_2022: u8 = 133; +pub const F1_23_CHAROUZ_2022: u8 = 134; +pub const F1_23_DAMS_2022: u8 = 135; +pub const F1_23_CAMPOS_2022: u8 = 136; +pub const F1_23_VAN_AMERSFORT_2022: u8 = 137; +pub const F1_23_TRIDENT_2022: u8 = 138; +pub const F1_23_HITECH_2022: u8 = 139; +pub const F1_23_ART_GP_2022: u8 = 140; +pub const MY_TEAM: u8 = 255; diff --git a/src/lib.rs b/src/lib.rs index a0dd8bf..503a366 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,10 +3,11 @@ pub mod packets; use crate::constants::PacketId; use crate::packets::{ - F1PacketCarDamage, F1PacketCarSetups, F1PacketCarStatus, + u8_to_usize, F1PacketCarDamage, F1PacketCarSetups, F1PacketCarStatus, F1PacketCarTelemetry, F1PacketEvent, F1PacketFinalClassification, - F1PacketLap, F1PacketLobbyInfo, F1PacketMotion, F1PacketParticipants, - F1PacketSession, F1PacketSessionHistory, + F1PacketLap, F1PacketLobbyInfo, F1PacketMotion, F1PacketMotionEx, + F1PacketParticipants, F1PacketSession, F1PacketSessionHistory, + F1PacketTyreSets, }; use binrw::io::Cursor; @@ -46,6 +47,10 @@ pub struct F1Packet { pub struct F1PacketHeader { /// Value of the "UDP Format" option in the game's telemetry settings. pub packet_format: u16, + /// Game year (last two digits) + /// Available from the 2023 format onwards. + #[br(if(packet_format >= 2023))] + pub game_year: u8, /// Game's major version - "X.00". pub game_major_version: u8, /// Game's minor version - "1.XX". @@ -60,11 +65,18 @@ pub struct F1PacketHeader { pub session_time: f32, /// Identifier for the frame the data was retrieved on. pub frame_identifier: u32, + /// Overall identifier for the frame the data was retrieved on + /// (doesn't go back after flashbacks). + /// Available from the 2023 format onwards. + #[br(if(packet_format >= 2023))] + pub overall_frame_identifier: u32, /// Index of player's car in the array. - pub player_car_index: u8, + #[br(map(u8_to_usize))] + pub player_car_index: usize, /// Index of secondary player's car in the array in splitscreen mode. /// Set to 255 if not in splitscreen mode. - pub secondary_player_car_index: u8, + #[br(map(u8_to_usize))] + pub secondary_player_car_index: usize, } /// F1 game packet's body. @@ -110,4 +122,12 @@ pub struct F1PacketBody { /// Session history data for a specific car. #[br(if(packet_id == PacketId::SessionHistory), args(packet_format))] pub session_history: Option, + /// In-depth details about tyre sets assigned to a vehicle during the session. + /// Available from the 2023 format onwards. + #[br(if(packet_id == PacketId::TyreSets), args(packet_format))] + pub tyre_sets: Option, + /// Extended player car only motion data. + /// Available from the 2023 format onwards. + #[br(if(packet_id == PacketId::MotionEx), args(packet_format))] + pub motion_ex: Option, } diff --git a/src/packets/car_status.rs b/src/packets/car_status.rs index f195a12..61aa41c 100644 --- a/src/packets/car_status.rs +++ b/src/packets/car_status.rs @@ -12,7 +12,7 @@ use serde::{Deserialize, Serialize}; )] #[br( little, - import(_packet_format: u16), + import(packet_format: u16), assert( max_gears <= 9, "Car status entry has an invalid max number of gears: {}", @@ -56,6 +56,14 @@ pub struct CarStatusData { pub tyres_age_laps: u8, /// Flag the driver is currently being shown. pub vehicle_fia_flag: VehicleFiaFlag, + /// Engine power output of ICE in watts. + /// Available from the 2023 format onwards. + #[br(if(packet_format >= 2023))] + pub engine_power_ice: f32, + /// Engine power output of MGU-K in watts. + /// Available from the 2023 format onwards. + #[br(if(packet_format >= 2023))] + pub engine_power_mguk: f32, /// ERS energy store in Joules. pub ers_store_energy: f32, /// ERS deployment mode. diff --git a/src/packets/event.rs b/src/packets/event.rs index 8bb7c9f..4fdb7c2 100644 --- a/src/packets/event.rs +++ b/src/packets/event.rs @@ -133,4 +133,15 @@ pub enum EventDataDetails { #[br(map(ButtonStatus::from_bits_truncate))] button_status: ButtonStatus, }, + /// Sent when a car has overtaken another. + /// Available from the 2023 format onwards. + #[br(magic = b"OVTK")] + Overtake { + /// Index of the overtaking vehicle. + #[br(map(u8_to_usize))] + overtaking_vehicle_index: usize, + /// Index of the overtaken vehicle. + #[br(map(u8_to_usize))] + overtaken_vehicle_index: usize, + }, } diff --git a/src/packets/lap.rs b/src/packets/lap.rs index 64dece1..5da26fe 100644 --- a/src/packets/lap.rs +++ b/src/packets/lap.rs @@ -11,7 +11,7 @@ use serde::{Deserialize, Serialize}; )] #[br( little, - import(_packet_format: u16), + import(packet_format: u16), assert( sector <= 2, "Lap data entry has an invalid sector number: {}", @@ -25,8 +25,24 @@ pub struct LapData { pub current_lap_time_ms: u32, /// Current sector 1 time in milliseconds. pub sector1_time_ms: u16, + /// Sector 1 whole minute part. + /// Available from the 2023 format onwards. + #[br(if(packet_format >= 2023))] + pub sector1_time_minutes: u8, /// Current sector 2 time in milliseconds. pub sector2_time_ms: u16, + /// Sector 2 whole minute part. + /// Available from the 2023 format onwards. + #[br(if(packet_format >= 2023))] + pub sector2_time_minutes: u8, + /// Time delta to car in front in milliseconds. + /// Available from the 2023 format onwards. + #[br(if(packet_format >= 2023))] + pub delta_to_car_in_front_ms: u16, + /// Time delta to race leader in milliseconds. + /// Available from the 2023 format onwards. + #[br(if(packet_format >= 2023))] + pub delta_to_race_leader_ms: u16, /// The distance the vehicle is around current lap in metres. /// It may be negative if the start/finish line hasn’t been crossed yet. pub lap_distance: f32, @@ -52,7 +68,17 @@ pub struct LapData { /// Accumulated time penalties to be added in seconds. pub penalties: u8, /// Accumulated number of warnings issued. + /// Available only in the 2022 format. + #[br(if(packet_format == 2022))] pub warnings: u8, + /// Accumulated number of warnings issued. + /// Available from the 2023 format onwards. + #[br(if(packet_format >= 2023))] + pub total_warnings: u8, + /// Accumulated number of corner cutting warnings issued. + /// Available from the 2023 format onwards. + #[br(if(packet_format >= 2023))] + pub corner_cutting_warnings: u8, /// Number of unserved drive through penalties left to serve. pub num_unserved_drive_through_pens: u8, /// Number of unserved stop-go penalties left to serve. diff --git a/src/packets/lobby.rs b/src/packets/lobby.rs index 2d384f0..b9d9ac1 100644 --- a/src/packets/lobby.rs +++ b/src/packets/lobby.rs @@ -1,5 +1,6 @@ use super::{read_name, u8_to_bool}; -use crate::constants::{Nationality, ReadyStatus, TeamId}; +use crate::constants::{Nationality, Platform, ReadyStatus}; + use binrw::BinRead; use serde::{Deserialize, Serialize}; @@ -7,19 +8,23 @@ use serde::{Deserialize, Serialize}; #[derive( BinRead, PartialEq, PartialOrd, Clone, Debug, Serialize, Deserialize, )] -#[br(little, import(_packet_format: u16))] +#[br(little, import(packet_format: u16))] pub struct LobbyInfoData { /// Whether the vehicle is controlled by AI. #[br(map(u8_to_bool))] pub ai_controlled: bool, /// Team's ID. - pub team_id: TeamId, + pub team_id: u8, /// Driver's nationality. pub nationality: Nationality, + /// Player's platform. + /// Available from the 2023 format onwards. + #[br(if(packet_format >= 2023))] + pub platform: Option, /// Driver's name. #[br(try_map(read_name))] pub name: String, - /// Player's car number + /// Player's car number. pub car_number: u8, /// Readiness status. pub ready_status: ReadyStatus, diff --git a/src/packets/mod.rs b/src/packets/mod.rs index bdcbd7e..ab121b6 100644 --- a/src/packets/mod.rs +++ b/src/packets/mod.rs @@ -10,11 +10,13 @@ pub mod motion; pub mod participants; pub mod session; pub mod session_history; +pub mod tyre_sets; use crate::constants::{ BrakingAssist, DynamicRacingLine, DynamicRacingLineType, ForecastAccuracy, Formula, GameMode, GearboxAssist, MfdPanelIndex, Ruleset, SafetyCarStatus, - SessionLength, SessionType, TrackId, Weather, MAX_NUM_CARS, + SessionLength, SessionType, SpeedUnit, TemperatureUnit, TrackId, Weather, + MAX_NUM_CARS, }; use crate::packets::car_damage::CarDamageData; use crate::packets::car_setups::CarSetupData; @@ -28,6 +30,7 @@ use crate::packets::motion::CarMotionData; use crate::packets::participants::ParticipantsData; use crate::packets::session::{MarshalZone, WeatherForecastSample}; use crate::packets::session_history::{LapHistoryData, TyreStintHistoryData}; +use crate::packets::tyre_sets::TyreSetData; use binrw::BinRead; use serde::{Deserialize, Serialize}; @@ -43,7 +46,8 @@ pub struct F1PacketMotion { /// Motion data for all cars on track. #[br(count(MAX_NUM_CARS), args{ inner: (packet_format,) })] pub car_motion_data: Vec, - /// Extra player car only motion data (2022 format only). + /// Extra player car only motion data. + /// Only in the 2022 format. #[br(if(packet_format == 2022))] pub motion_ex_data: Option, } @@ -177,6 +181,34 @@ pub struct F1PacketSession { pub time_of_day: u32, /// Session's length. pub session_length: SessionLength, + /// Speed unit used by player 1. + /// Available from the 2023 format onwards. + #[br(if(packet_format >= 2023))] + pub speed_unit_lead_player: Option, + /// Temperature unit used by player 1. + /// Available from the 2023 format onwards. + #[br(if(packet_format >= 2023))] + pub temperature_unit_lead_player: Option, + /// Speed unit used by player 2. + /// Available from the 2023 format onwards. + #[br(if(packet_format >= 2023))] + pub speed_unit_secondary_player: Option, + /// Temperature unit used by player 2. + /// Available from the 2023 format onwards. + #[br(if(packet_format >= 2023))] + pub temperature_unit_secondary_player: Option, + /// Number of full safety cars called during the session. + /// Available from the 2023 format onwards. + #[br(if(packet_format >= 2023))] + pub num_safety_car_periods: u8, + /// Number of virtual safety cars called during the session. + /// Available from the 2023 format onwards. + #[br(if(packet_format >= 2023))] + pub num_virtual_safety_car_periods: u8, + /// Number of red flags called during the session. + /// Available from the 2023 format onwards. + #[br(if(packet_format >= 2023))] + pub num_red_flag_periods: u8, } /// Data about all the lap times of cars in the session. @@ -409,6 +441,25 @@ pub struct F1PacketSessionHistory { pub tyre_stint_history_data: Vec, } +/// In-depth details about tyre sets assigned to a vehicle during the session. +/// Available from the 2023 format onwards. +#[non_exhaustive] +#[derive( + BinRead, PartialEq, PartialOrd, Clone, Debug, Serialize, Deserialize, +)] +#[br(little, import(packet_format: u16))] +pub struct F1PacketTyreSets { + /// Index of the car this packet relates to. + #[br(map(u8_to_usize))] + pub vehicle_index: usize, + /// 13 dry + 7 wet tyre sets. + #[br(count(20), args{ inner: (packet_format,) })] + pub tyre_set_data: Vec, + /// Index of fitted tyre set. + #[br(map(u8_to_usize))] + pub fitted_index: usize, +} + /// Extended motion data for player's car. Available as a: /// - part of [`F1PacketMotion`] in the 2022 format /// - standalone packet from the 2023 format onwards @@ -416,7 +467,7 @@ pub struct F1PacketSessionHistory { #[derive( BinRead, PartialEq, PartialOrd, Copy, Clone, Debug, Serialize, Deserialize, )] -#[br(little, import(_packet_format: u16))] +#[br(little, import(packet_format: u16))] pub struct F1PacketMotionEx { /// Positions of suspension for each wheel. /// See [`wheel_index`](mod@crate::constants::wheel_index) @@ -458,6 +509,12 @@ pub struct F1PacketMotionEx { pub angular_acceleration_z: f32, /// Current front wheels angle in radians. pub front_wheels_angle: f32, + /// Vertical forces for each wheel. + /// See [`wheel_index`](mod@crate::constants::wheel_index) + /// for wheel order. + /// Available from the 2023 format onwards. + #[br(if(packet_format >= 2023))] + pub wheel_vert_force: [f32; 4], } pub(crate) fn u8_to_bool(value: u8) -> bool { diff --git a/src/packets/participants.rs b/src/packets/participants.rs index 94748fe..89f8b08 100644 --- a/src/packets/participants.rs +++ b/src/packets/participants.rs @@ -1,5 +1,5 @@ use super::{read_name, u8_to_bool}; -use crate::constants::{Nationality, TeamId, YourTelemetry}; +use crate::constants::{Nationality, Platform, YourTelemetry}; use binrw::BinRead; use serde::{Deserialize, Serialize}; @@ -8,7 +8,7 @@ use serde::{Deserialize, Serialize}; #[derive( BinRead, PartialEq, PartialOrd, Clone, Debug, Serialize, Deserialize, )] -#[br(little, import(_packet_format: u16))] +#[br(little, import(packet_format: u16))] pub struct ParticipantsData { /// Whether the vehicle is controlled by AI #[br(map(u8_to_bool))] @@ -18,7 +18,7 @@ pub struct ParticipantsData { /// Unique ID for network players pub network_id: u8, /// Team's ID - pub team_id: TeamId, + pub team_id: u8, /// Whether my team is being used #[br(map(u8_to_bool))] pub my_team: bool, @@ -31,4 +31,12 @@ pub struct ParticipantsData { pub name: String, /// Player's UDP visibility setting pub your_telemetry: Option, + /// Whether this player's "show online names" setting is on. + /// Available from the 2023 format onwards. + #[br(if(packet_format >= 2023), map(u8_to_bool))] + pub show_online_names: bool, + /// Player's platform. + /// Available from the 2023 format onwards. + #[br(if(packet_format >= 2023))] + pub platform: Option, } diff --git a/src/packets/session_history.rs b/src/packets/session_history.rs index b61fcbd..049372a 100644 --- a/src/packets/session_history.rs +++ b/src/packets/session_history.rs @@ -7,16 +7,28 @@ use serde::{Deserialize, Serialize}; #[derive( BinRead, PartialEq, PartialOrd, Clone, Debug, Serialize, Deserialize, )] -#[br(little, import(_packet_format: u16))] +#[br(little, import(packet_format: u16))] pub struct LapHistoryData { /// Lap time in milliseconds. pub lap_time_ms: u32, /// Sector 1 time in milliseconds. pub sector1_time_ms: u16, + /// Sector 1 whole minute part + /// Available from the 2023 format onwards. + #[br(if(packet_format >= 2023))] + pub sector1_time_minutes: u8, /// Sector 2 time in milliseconds. pub sector2_time_ms: u16, + /// Sector 2 whole minute part + /// Available from the 2023 format onwards. + #[br(if(packet_format >= 2023))] + pub sector2_time_minutes: u8, /// Sector 3 time in milliseconds. pub sector3_time_ms: u16, + /// Sector 3 whole minute part + /// Available from the 2023 format onwards. + #[br(if(packet_format >= 2023))] + pub sector3_time_minutes: u8, /// Bitmap of lap validity across all sectors and overall. #[br(map(LapValid::from_bits_truncate))] pub lap_valid_bit_flags: LapValid, @@ -27,11 +39,11 @@ pub struct LapHistoryData { )] #[br(little, import(_packet_format: u16))] pub struct TyreStintHistoryData { - /// Lap the tyre usage ends on (255 if current tyre) + /// Lap the tyre usage ends on (255 if current tyre). #[br(map(u8_to_usize))] pub end_lap: usize, - /// Actual tyre compound used + /// Actual tyre compound used. pub actual_tyre_compound: ActualTyreCompound, - /// Visual tyre compound used + /// Visual tyre compound used. pub visual_tyre_compound: VisualTyreCompound, } diff --git a/src/packets/tyre_sets.rs b/src/packets/tyre_sets.rs new file mode 100644 index 0000000..3b78a0f --- /dev/null +++ b/src/packets/tyre_sets.rs @@ -0,0 +1,49 @@ +use super::u8_to_bool; +use crate::constants::{ActualTyreCompound, SessionType, VisualTyreCompound}; + +use binrw::BinRead; +use serde::{Deserialize, Serialize}; + +#[derive( + BinRead, + Eq, + PartialEq, + Ord, + PartialOrd, + Copy, + Clone, + Debug, + Serialize, + Deserialize, +)] +#[br( + little, + import(_packet_format: u16), + assert( + wear <= 100, + "Tyre set entry has an invalid wear percentage: {}", + wear + ) +)] +pub struct TyreSetData { + /// Actual tyre compound. + pub actual_tyre_compound: ActualTyreCompound, + /// Visual tyre compound. + pub visual_tyre_compound: VisualTyreCompound, + /// Tyre wear (percentage). + pub wear: u8, + /// Whether this set is currently available. + #[br(map(u8_to_bool))] + pub available: bool, + /// Recommended session for this tyre set. + pub recommended_session: SessionType, + /// Laps left in this set. + pub life_span: u8, + /// Max number of laps recommended for this compound. + pub usable_life: u8, + /// Lap time delta in milliseconds compared to fitted set. + pub lap_delta_time: i16, + /// Whether this set is fitted or not. + #[br(map(u8_to_bool))] + pub fitted: bool, +}