feat: add 2023 spec parser fields and constants

This commit is contained in:
Maciej Pędzich 2025-02-20 10:22:06 +01:00
parent ef07718495
commit c4f08877aa
Signed by: maciejpedzich
GPG Key ID: CE4A303D84882F0D
13 changed files with 406 additions and 121 deletions

View File

@ -8,7 +8,8 @@ fn main() -> Result<(), Box<dyn Error>> {
loop { loop {
let (msg_size, _) = socket.recv_from(&mut buf)?; let (msg_size, _) = socket.recv_from(&mut buf)?;
let raw_data = &buf[..msg_size]; let data = &buf[..msg_size];
let _parse_result = parse(raw_data)?;
parse(data)?;
} }
} }

View File

@ -96,7 +96,7 @@ pub const FELIPE_DRUGOVICH: u8 = 98;
pub const ROBERT_SCHWARTZMAN: u8 = 99; pub const ROBERT_SCHWARTZMAN: u8 = 99;
pub const ROY_NISSANY: u8 = 100; pub const ROY_NISSANY: u8 = 100;
pub const MARINO_SATO: u8 = 101; 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 CASPER_AKKERMAN: u8 = 103;
pub const JENSON_BUTTON: u8 = 109; pub const JENSON_BUTTON: u8 = 109;
pub const DAVID_COULTHARD: u8 = 110; pub const DAVID_COULTHARD: u8 = 110;
@ -113,15 +113,33 @@ pub const BENT_VISCAAL: u8 = 122;
pub const ENZO_FITTIPALDI: u8 = 123; pub const ENZO_FITTIPALDI: u8 = 123;
pub const MARK_WEBBER: u8 = 125; pub const MARK_WEBBER: u8 = 125;
pub const JACQUES_VILLENEUVE: u8 = 126; pub const JACQUES_VILLENEUVE: u8 = 126;
pub const JAKE_HUGHES: u8 = 127; pub const JAKE_HUGHES_2022: u8 = 127;
pub const FREDERIK_VESTI: u8 = 128; pub const FREDERIK_VESTI_2022: u8 = 128;
pub const OLLI_CALDWELL: u8 = 129; pub const OLLI_CALDWELL_2022: u8 = 129;
pub const LOGAN_SARGEANT: u8 = 130; pub const LOGAN_SARGEANT_2022: u8 = 130;
pub const CEM_BOLUKBASI: u8 = 131; pub const CEM_BOLUKBASI_2022: u8 = 131;
pub const AYUMU_IWASA: u8 = 132; pub const AYUMU_IWASA_2022: u8 = 132;
pub const CLEMENT_NOVALAK: u8 = 133; pub const CLEMENT_NOVALAK_2022: u8 = 133;
pub const DENNIS_HAUGER: u8 = 134; pub const DENNIS_HAUGER_2022: u8 = 134;
pub const CALAN_WILLIAMS: u8 = 135; 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 JACK_DOOHAN: u8 = 136;
pub const AMAURY_CORDEEL: u8 = 137; 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;

View File

@ -1,4 +1,5 @@
pub mod driver_id; pub mod driver_id;
pub mod team_id;
pub mod wheel_index; pub mod wheel_index;
use binrw::BinRead; use binrw::BinRead;
@ -210,6 +211,8 @@ pub enum Formula {
Supercars = 5, Supercars = 5,
Esports = 6, Esports = 6,
F22021 = 7, F22021 = 7,
F1World = 8,
F1Elimination = 9,
} }
#[non_exhaustive] #[non_exhaustive]
@ -350,6 +353,7 @@ pub enum DynamicRacingLineType {
pub enum GameMode { pub enum GameMode {
EventMode = 0, EventMode = 0,
GrandPrix = 3, GrandPrix = 3,
GrandPrix2023 = 4,
TimeTrial = 5, TimeTrial = 5,
Splitscreen = 6, Splitscreen = 6,
OnlineCustom = 7, OnlineCustom = 7,
@ -359,8 +363,11 @@ pub enum GameMode {
Championship = 13, Championship = 13,
OnlineChampionship = 14, OnlineChampionship = 14,
OnlineWeeklyEvent = 15, OnlineWeeklyEvent = 15,
BrakingPoint2023 = 17,
Career2022 = 19, Career2022 = 19,
Career2022Online = 20, Career2022Online = 20,
Career2023 = 21,
Career2023Online = 22,
Benchmark = 127, Benchmark = 127,
} }
@ -583,6 +590,7 @@ pub enum InfringementType {
RetryPenalty = 49, RetryPenalty = 49,
IllegalTimeGain = 50, IllegalTimeGain = 50,
MandatoryPitStop = 51, MandatoryPitStop = 51,
AttributeAssigned = 54,
} }
#[derive( #[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] #[non_exhaustive]
#[derive( #[derive(
BinRead, BinRead,
@ -1108,6 +1037,7 @@ pub enum ActualTyreCompound {
F1C3 = 18, F1C3 = 18,
F1C2 = 19, F1C2 = 19,
F1C1 = 20, F1C1 = 20,
F1C0 = 21,
F1Inter = 7, F1Inter = 7,
F1Wet = 8, F1Wet = 8,
ClassicDry = 9, ClassicDry = 9,
@ -1185,13 +1115,74 @@ pub struct LapValid(u8);
bitflags! { bitflags! {
impl LapValid: u8 { impl LapValid: u8 {
/// Whether the whole lap is valid. Has a value of `0b0001` /// Whether the whole lap is valid. Has a value of `0x01`.
const Overall = 0b0001; const OVERALL = 0x01;
/// Whether the sector 1 run is valid. Has a value of `0b0010` /// Whether the sector 1 run is valid. Has a value of `0x02`.
const Sector1 = 0b0010; const SECTOR_1 = 0x02;
/// Whether the sector 2 run is valid. Has a value of `0b0100` /// Whether the sector 2 run is valid. Has a value of `0x04`.
const Sector2 = 0b0100; const SECTOR_2 = 0x04;
/// Whether the sector 3 run is valid. Has a value of `0b1000` /// Whether the sector 3 run is valid. Has a value of `0x08`.
const Sector3 = 0b1000; 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,
}

79
src/constants/team_id.rs Normal file
View File

@ -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;

View File

@ -3,10 +3,11 @@ pub mod packets;
use crate::constants::PacketId; use crate::constants::PacketId;
use crate::packets::{ use crate::packets::{
F1PacketCarDamage, F1PacketCarSetups, F1PacketCarStatus, u8_to_usize, F1PacketCarDamage, F1PacketCarSetups, F1PacketCarStatus,
F1PacketCarTelemetry, F1PacketEvent, F1PacketFinalClassification, F1PacketCarTelemetry, F1PacketEvent, F1PacketFinalClassification,
F1PacketLap, F1PacketLobbyInfo, F1PacketMotion, F1PacketParticipants, F1PacketLap, F1PacketLobbyInfo, F1PacketMotion, F1PacketMotionEx,
F1PacketSession, F1PacketSessionHistory, F1PacketParticipants, F1PacketSession, F1PacketSessionHistory,
F1PacketTyreSets,
}; };
use binrw::io::Cursor; use binrw::io::Cursor;
@ -46,6 +47,10 @@ pub struct F1Packet {
pub struct F1PacketHeader { pub struct F1PacketHeader {
/// Value of the "UDP Format" option in the game's telemetry settings. /// Value of the "UDP Format" option in the game's telemetry settings.
pub packet_format: u16, 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". /// Game's major version - "X.00".
pub game_major_version: u8, pub game_major_version: u8,
/// Game's minor version - "1.XX". /// Game's minor version - "1.XX".
@ -60,11 +65,18 @@ pub struct F1PacketHeader {
pub session_time: f32, pub session_time: f32,
/// Identifier for the frame the data was retrieved on. /// Identifier for the frame the data was retrieved on.
pub frame_identifier: u32, 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. /// 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. /// Index of secondary player's car in the array in splitscreen mode.
/// Set to 255 if not 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. /// F1 game packet's body.
@ -110,4 +122,12 @@ pub struct F1PacketBody {
/// Session history data for a specific car. /// Session history data for a specific car.
#[br(if(packet_id == PacketId::SessionHistory), args(packet_format))] #[br(if(packet_id == PacketId::SessionHistory), args(packet_format))]
pub session_history: Option<F1PacketSessionHistory>, pub session_history: Option<F1PacketSessionHistory>,
/// 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<F1PacketTyreSets>,
/// 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<F1PacketMotionEx>,
} }

View File

@ -12,7 +12,7 @@ use serde::{Deserialize, Serialize};
)] )]
#[br( #[br(
little, little,
import(_packet_format: u16), import(packet_format: u16),
assert( assert(
max_gears <= 9, max_gears <= 9,
"Car status entry has an invalid max number of gears: {}", "Car status entry has an invalid max number of gears: {}",
@ -56,6 +56,14 @@ pub struct CarStatusData {
pub tyres_age_laps: u8, pub tyres_age_laps: u8,
/// Flag the driver is currently being shown. /// Flag the driver is currently being shown.
pub vehicle_fia_flag: VehicleFiaFlag, 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. /// ERS energy store in Joules.
pub ers_store_energy: f32, pub ers_store_energy: f32,
/// ERS deployment mode. /// ERS deployment mode.

View File

@ -133,4 +133,15 @@ pub enum EventDataDetails {
#[br(map(ButtonStatus::from_bits_truncate))] #[br(map(ButtonStatus::from_bits_truncate))]
button_status: ButtonStatus, 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,
},
} }

View File

@ -11,7 +11,7 @@ use serde::{Deserialize, Serialize};
)] )]
#[br( #[br(
little, little,
import(_packet_format: u16), import(packet_format: u16),
assert( assert(
sector <= 2, sector <= 2,
"Lap data entry has an invalid sector number: {}", "Lap data entry has an invalid sector number: {}",
@ -25,8 +25,24 @@ pub struct LapData {
pub current_lap_time_ms: u32, pub current_lap_time_ms: u32,
/// Current sector 1 time in milliseconds. /// Current sector 1 time in milliseconds.
pub sector1_time_ms: u16, 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. /// Current sector 2 time in milliseconds.
pub sector2_time_ms: u16, 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. /// The distance the vehicle is around current lap in metres.
/// It may be negative if the start/finish line hasnt been crossed yet. /// It may be negative if the start/finish line hasnt been crossed yet.
pub lap_distance: f32, pub lap_distance: f32,
@ -52,7 +68,17 @@ pub struct LapData {
/// Accumulated time penalties to be added in seconds. /// Accumulated time penalties to be added in seconds.
pub penalties: u8, pub penalties: u8,
/// Accumulated number of warnings issued. /// Accumulated number of warnings issued.
/// Available only in the 2022 format.
#[br(if(packet_format == 2022))]
pub warnings: u8, 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. /// Number of unserved drive through penalties left to serve.
pub num_unserved_drive_through_pens: u8, pub num_unserved_drive_through_pens: u8,
/// Number of unserved stop-go penalties left to serve. /// Number of unserved stop-go penalties left to serve.

View File

@ -1,5 +1,6 @@
use super::{read_name, u8_to_bool}; use super::{read_name, u8_to_bool};
use crate::constants::{Nationality, ReadyStatus, TeamId}; use crate::constants::{Nationality, Platform, ReadyStatus};
use binrw::BinRead; use binrw::BinRead;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -7,19 +8,23 @@ use serde::{Deserialize, Serialize};
#[derive( #[derive(
BinRead, PartialEq, PartialOrd, Clone, Debug, Serialize, Deserialize, BinRead, PartialEq, PartialOrd, Clone, Debug, Serialize, Deserialize,
)] )]
#[br(little, import(_packet_format: u16))] #[br(little, import(packet_format: u16))]
pub struct LobbyInfoData { pub struct LobbyInfoData {
/// Whether the vehicle is controlled by AI. /// Whether the vehicle is controlled by AI.
#[br(map(u8_to_bool))] #[br(map(u8_to_bool))]
pub ai_controlled: bool, pub ai_controlled: bool,
/// Team's ID. /// Team's ID.
pub team_id: TeamId, pub team_id: u8,
/// Driver's nationality. /// Driver's nationality.
pub nationality: Nationality, pub nationality: Nationality,
/// Player's platform.
/// Available from the 2023 format onwards.
#[br(if(packet_format >= 2023))]
pub platform: Option<Platform>,
/// Driver's name. /// Driver's name.
#[br(try_map(read_name))] #[br(try_map(read_name))]
pub name: String, pub name: String,
/// Player's car number /// Player's car number.
pub car_number: u8, pub car_number: u8,
/// Readiness status. /// Readiness status.
pub ready_status: ReadyStatus, pub ready_status: ReadyStatus,

View File

@ -10,11 +10,13 @@ pub mod motion;
pub mod participants; pub mod participants;
pub mod session; pub mod session;
pub mod session_history; pub mod session_history;
pub mod tyre_sets;
use crate::constants::{ use crate::constants::{
BrakingAssist, DynamicRacingLine, DynamicRacingLineType, ForecastAccuracy, BrakingAssist, DynamicRacingLine, DynamicRacingLineType, ForecastAccuracy,
Formula, GameMode, GearboxAssist, MfdPanelIndex, Ruleset, SafetyCarStatus, 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_damage::CarDamageData;
use crate::packets::car_setups::CarSetupData; use crate::packets::car_setups::CarSetupData;
@ -28,6 +30,7 @@ use crate::packets::motion::CarMotionData;
use crate::packets::participants::ParticipantsData; use crate::packets::participants::ParticipantsData;
use crate::packets::session::{MarshalZone, WeatherForecastSample}; use crate::packets::session::{MarshalZone, WeatherForecastSample};
use crate::packets::session_history::{LapHistoryData, TyreStintHistoryData}; use crate::packets::session_history::{LapHistoryData, TyreStintHistoryData};
use crate::packets::tyre_sets::TyreSetData;
use binrw::BinRead; use binrw::BinRead;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -43,7 +46,8 @@ pub struct F1PacketMotion {
/// Motion data for all cars on track. /// Motion data for all cars on track.
#[br(count(MAX_NUM_CARS), args{ inner: (packet_format,) })] #[br(count(MAX_NUM_CARS), args{ inner: (packet_format,) })]
pub car_motion_data: Vec<CarMotionData>, pub car_motion_data: Vec<CarMotionData>,
/// 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))] #[br(if(packet_format == 2022))]
pub motion_ex_data: Option<F1PacketMotionEx>, pub motion_ex_data: Option<F1PacketMotionEx>,
} }
@ -177,6 +181,34 @@ pub struct F1PacketSession {
pub time_of_day: u32, pub time_of_day: u32,
/// Session's length. /// Session's length.
pub session_length: SessionLength, 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<SpeedUnit>,
/// Temperature unit used by player 1.
/// Available from the 2023 format onwards.
#[br(if(packet_format >= 2023))]
pub temperature_unit_lead_player: Option<TemperatureUnit>,
/// Speed unit used by player 2.
/// Available from the 2023 format onwards.
#[br(if(packet_format >= 2023))]
pub speed_unit_secondary_player: Option<SpeedUnit>,
/// Temperature unit used by player 2.
/// Available from the 2023 format onwards.
#[br(if(packet_format >= 2023))]
pub temperature_unit_secondary_player: Option<TemperatureUnit>,
/// 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. /// Data about all the lap times of cars in the session.
@ -409,6 +441,25 @@ pub struct F1PacketSessionHistory {
pub tyre_stint_history_data: Vec<TyreStintHistoryData>, pub tyre_stint_history_data: Vec<TyreStintHistoryData>,
} }
/// 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<TyreSetData>,
/// Index of fitted tyre set.
#[br(map(u8_to_usize))]
pub fitted_index: usize,
}
/// Extended motion data for player's car. Available as a: /// Extended motion data for player's car. Available as a:
/// - part of [`F1PacketMotion`] in the 2022 format /// - part of [`F1PacketMotion`] in the 2022 format
/// - standalone packet from the 2023 format onwards /// - standalone packet from the 2023 format onwards
@ -416,7 +467,7 @@ pub struct F1PacketSessionHistory {
#[derive( #[derive(
BinRead, PartialEq, PartialOrd, Copy, Clone, Debug, Serialize, Deserialize, BinRead, PartialEq, PartialOrd, Copy, Clone, Debug, Serialize, Deserialize,
)] )]
#[br(little, import(_packet_format: u16))] #[br(little, import(packet_format: u16))]
pub struct F1PacketMotionEx { pub struct F1PacketMotionEx {
/// Positions of suspension for each wheel. /// Positions of suspension for each wheel.
/// See [`wheel_index`](mod@crate::constants::wheel_index) /// See [`wheel_index`](mod@crate::constants::wheel_index)
@ -458,6 +509,12 @@ pub struct F1PacketMotionEx {
pub angular_acceleration_z: f32, pub angular_acceleration_z: f32,
/// Current front wheels angle in radians. /// Current front wheels angle in radians.
pub front_wheels_angle: f32, 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 { pub(crate) fn u8_to_bool(value: u8) -> bool {

View File

@ -1,5 +1,5 @@
use super::{read_name, u8_to_bool}; use super::{read_name, u8_to_bool};
use crate::constants::{Nationality, TeamId, YourTelemetry}; use crate::constants::{Nationality, Platform, YourTelemetry};
use binrw::BinRead; use binrw::BinRead;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -8,7 +8,7 @@ use serde::{Deserialize, Serialize};
#[derive( #[derive(
BinRead, PartialEq, PartialOrd, Clone, Debug, Serialize, Deserialize, BinRead, PartialEq, PartialOrd, Clone, Debug, Serialize, Deserialize,
)] )]
#[br(little, import(_packet_format: u16))] #[br(little, import(packet_format: u16))]
pub struct ParticipantsData { pub struct ParticipantsData {
/// Whether the vehicle is controlled by AI /// Whether the vehicle is controlled by AI
#[br(map(u8_to_bool))] #[br(map(u8_to_bool))]
@ -18,7 +18,7 @@ pub struct ParticipantsData {
/// Unique ID for network players /// Unique ID for network players
pub network_id: u8, pub network_id: u8,
/// Team's ID /// Team's ID
pub team_id: TeamId, pub team_id: u8,
/// Whether my team is being used /// Whether my team is being used
#[br(map(u8_to_bool))] #[br(map(u8_to_bool))]
pub my_team: bool, pub my_team: bool,
@ -31,4 +31,12 @@ pub struct ParticipantsData {
pub name: String, pub name: String,
/// Player's UDP visibility setting /// Player's UDP visibility setting
pub your_telemetry: Option<YourTelemetry>, pub your_telemetry: Option<YourTelemetry>,
/// 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<Platform>,
} }

View File

@ -7,16 +7,28 @@ use serde::{Deserialize, Serialize};
#[derive( #[derive(
BinRead, PartialEq, PartialOrd, Clone, Debug, Serialize, Deserialize, BinRead, PartialEq, PartialOrd, Clone, Debug, Serialize, Deserialize,
)] )]
#[br(little, import(_packet_format: u16))] #[br(little, import(packet_format: u16))]
pub struct LapHistoryData { pub struct LapHistoryData {
/// Lap time in milliseconds. /// Lap time in milliseconds.
pub lap_time_ms: u32, pub lap_time_ms: u32,
/// Sector 1 time in milliseconds. /// Sector 1 time in milliseconds.
pub sector1_time_ms: u16, 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. /// Sector 2 time in milliseconds.
pub sector2_time_ms: u16, 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. /// Sector 3 time in milliseconds.
pub sector3_time_ms: u16, 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. /// Bitmap of lap validity across all sectors and overall.
#[br(map(LapValid::from_bits_truncate))] #[br(map(LapValid::from_bits_truncate))]
pub lap_valid_bit_flags: LapValid, pub lap_valid_bit_flags: LapValid,
@ -27,11 +39,11 @@ pub struct LapHistoryData {
)] )]
#[br(little, import(_packet_format: u16))] #[br(little, import(_packet_format: u16))]
pub struct TyreStintHistoryData { 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))] #[br(map(u8_to_usize))]
pub end_lap: usize, pub end_lap: usize,
/// Actual tyre compound used /// Actual tyre compound used.
pub actual_tyre_compound: ActualTyreCompound, pub actual_tyre_compound: ActualTyreCompound,
/// Visual tyre compound used /// Visual tyre compound used.
pub visual_tyre_compound: VisualTyreCompound, pub visual_tyre_compound: VisualTyreCompound,
} }

49
src/packets/tyre_sets.rs Normal file
View File

@ -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,
}