mirror of
https://github.com/maciejpedzich/f1-game-packet-parser.git
synced 2025-04-19 03:01:10 +02:00
feat: add 2022 spec final classification packet parser
This commit is contained in:
parent
2ccfdae321
commit
32471a952d
31
src/lib.rs
31
src/lib.rs
@ -3,9 +3,9 @@ pub mod packets;
|
|||||||
|
|
||||||
use crate::constants::PacketId;
|
use crate::constants::PacketId;
|
||||||
use crate::packets::{
|
use crate::packets::{
|
||||||
F1PacketCarSetupsData, F1PacketCarStatusData, F1PacketCarTelemetryData,
|
F1PacketCarSetups, F1PacketCarStatus, F1PacketCarTelemetry, F1PacketEvent,
|
||||||
F1PacketEventData, F1PacketLapData, F1PacketMotionData,
|
F1PacketFinalClassification, F1PacketLap, F1PacketMotion,
|
||||||
F1PacketParticipantsData, F1PacketSessionData,
|
F1PacketParticipants, F1PacketSession,
|
||||||
};
|
};
|
||||||
|
|
||||||
use binrw::io::Cursor;
|
use binrw::io::Cursor;
|
||||||
@ -73,26 +73,31 @@ pub struct F1PacketHeader {
|
|||||||
)]
|
)]
|
||||||
#[br(little, import(packet_format: u16, packet_id: PacketId))]
|
#[br(little, import(packet_format: u16, packet_id: PacketId))]
|
||||||
pub struct F1PacketBody {
|
pub struct F1PacketBody {
|
||||||
/// Physics data for all the cars being driven.
|
/// Physics data for all cars in the session.
|
||||||
#[br(if(packet_id == PacketId::Motion), args(packet_format))]
|
#[br(if(packet_id == PacketId::Motion), args(packet_format))]
|
||||||
pub motion: Option<F1PacketMotionData>,
|
pub motion: Option<F1PacketMotion>,
|
||||||
/// Data about the ongoing session.
|
/// Data about the ongoing session.
|
||||||
#[br(if(packet_id == PacketId::Session), args(packet_format))]
|
#[br(if(packet_id == PacketId::Session), args(packet_format))]
|
||||||
pub session: Option<F1PacketSessionData>,
|
pub session: Option<F1PacketSession>,
|
||||||
/// Lap data for all cars on track.
|
/// Lap data for all cars on track.
|
||||||
#[br(if(packet_id == PacketId::LapData), args(packet_format))]
|
#[br(if(packet_id == PacketId::LapData), args(packet_format))]
|
||||||
pub lap: Option<F1PacketLapData>,
|
pub lap: Option<F1PacketLap>,
|
||||||
/// Details of events that happen during the course of a session.
|
/// Details of events that happen during the course of a session.
|
||||||
#[br(if(packet_id == PacketId::Event), args(packet_format))]
|
#[br(if(packet_id == PacketId::Event), args(packet_format))]
|
||||||
pub event: Option<F1PacketEventData>,
|
pub event: Option<F1PacketEvent>,
|
||||||
/// List of participants in the race.
|
/// List of participants in the race.
|
||||||
#[br(if(packet_id == PacketId::Participants), args(packet_format))]
|
#[br(if(packet_id == PacketId::Participants), args(packet_format))]
|
||||||
pub participants: Option<F1PacketParticipantsData>,
|
pub participants: Option<F1PacketParticipants>,
|
||||||
/// Car setups for each vehicle in the session.
|
/// Car setups for all cars in the session.
|
||||||
#[br(if(packet_id == PacketId::CarSetups), args(packet_format))]
|
#[br(if(packet_id == PacketId::CarSetups), args(packet_format))]
|
||||||
pub car_setups: Option<F1PacketCarSetupsData>,
|
pub car_setups: Option<F1PacketCarSetups>,
|
||||||
|
/// Telemetry data for all cars in the session.
|
||||||
#[br(if(packet_id == PacketId::CarTelemetry), args(packet_format))]
|
#[br(if(packet_id == PacketId::CarTelemetry), args(packet_format))]
|
||||||
pub car_telemetry: Option<F1PacketCarTelemetryData>,
|
pub car_telemetry: Option<F1PacketCarTelemetry>,
|
||||||
|
/// Status data for all cars in the session.
|
||||||
#[br(if(packet_id == PacketId::CarStatus), args(packet_format))]
|
#[br(if(packet_id == PacketId::CarStatus), args(packet_format))]
|
||||||
pub car_status: Option<F1PacketCarStatusData>,
|
pub car_status: Option<F1PacketCarStatus>,
|
||||||
|
/// Final classification confirmation at the end of a race.
|
||||||
|
#[br(if(packet_id == PacketId::FinalClassification), args(packet_format))]
|
||||||
|
pub final_classification: Option<F1PacketFinalClassification>,
|
||||||
}
|
}
|
||||||
|
50
src/packets/final_classification.rs
Normal file
50
src/packets/final_classification.rs
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
use super::u8_to_usize;
|
||||||
|
use crate::constants::{ActualTyreCompound, ResultStatus, VisualTyreCompound};
|
||||||
|
|
||||||
|
use binrw::BinRead;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[non_exhaustive]
|
||||||
|
#[derive(
|
||||||
|
BinRead, PartialEq, PartialOrd, Copy, Clone, Debug, Serialize, Deserialize,
|
||||||
|
)]
|
||||||
|
#[br(
|
||||||
|
little,
|
||||||
|
import(_packet_format: u16),
|
||||||
|
assert(
|
||||||
|
num_tyre_stints <= 8,
|
||||||
|
"Final classification entry has an invalid number of tyre stints: {}",
|
||||||
|
num_tyre_stints
|
||||||
|
)
|
||||||
|
)]
|
||||||
|
pub struct FinalClassificationData {
|
||||||
|
/// Finishing position.
|
||||||
|
pub position: u8,
|
||||||
|
/// Number of laps completed.
|
||||||
|
pub num_laps: u8,
|
||||||
|
/// Grid position of the car.
|
||||||
|
pub grid_position: u8,
|
||||||
|
/// Number of points scored.
|
||||||
|
pub points: u8,
|
||||||
|
/// Number of pit stops made.
|
||||||
|
pub num_pit_stops: u8,
|
||||||
|
/// Result status.
|
||||||
|
pub result_status: ResultStatus,
|
||||||
|
/// Best lap time of the session in milliseconds.
|
||||||
|
pub best_lap_time_ms: u32,
|
||||||
|
/// Total race time in seconds (without penalties).
|
||||||
|
pub total_race_time: f64,
|
||||||
|
/// Total penalties accumulated in seconds.
|
||||||
|
pub penalties_time: u8,
|
||||||
|
/// Number of penalties applied to this driver.
|
||||||
|
pub num_penalties: u8,
|
||||||
|
/// Number of tyre stints (no greater than 8).
|
||||||
|
#[br(map(u8_to_usize))]
|
||||||
|
pub num_tyre_stints: usize,
|
||||||
|
/// Actual tyres used by the driver.
|
||||||
|
pub tyre_stints_actual: [ActualTyreCompound; 8],
|
||||||
|
/// Visual tyres used by the driver.
|
||||||
|
pub tyre_stints_visual: [VisualTyreCompound; 8],
|
||||||
|
/// The lap numbers the stints end on.
|
||||||
|
pub tyre_stints_end_laps: [u8; 8],
|
||||||
|
}
|
@ -2,7 +2,8 @@ pub mod car_setups;
|
|||||||
pub mod car_status;
|
pub mod car_status;
|
||||||
pub mod car_telemetry;
|
pub mod car_telemetry;
|
||||||
pub mod event;
|
pub mod event;
|
||||||
pub mod lap_data;
|
pub mod final_classification;
|
||||||
|
pub mod lap;
|
||||||
pub mod motion;
|
pub mod motion;
|
||||||
pub mod participants;
|
pub mod participants;
|
||||||
pub mod session;
|
pub mod session;
|
||||||
@ -12,15 +13,16 @@ use crate::constants::{
|
|||||||
Formula, GameMode, GearboxAssist, MfdPanelIndex, Ruleset, SafetyCarStatus,
|
Formula, GameMode, GearboxAssist, MfdPanelIndex, Ruleset, SafetyCarStatus,
|
||||||
SessionLength, SessionType, TrackId, Weather, MAX_NUM_CARS,
|
SessionLength, SessionType, TrackId, Weather, MAX_NUM_CARS,
|
||||||
};
|
};
|
||||||
|
use crate::packets::car_setups::CarSetupData;
|
||||||
|
use crate::packets::car_status::CarStatusData;
|
||||||
|
use crate::packets::car_telemetry::CarTelemetryData;
|
||||||
use crate::packets::event::EventDataDetails;
|
use crate::packets::event::EventDataDetails;
|
||||||
use crate::packets::lap_data::LapData;
|
use crate::packets::lap::LapData;
|
||||||
use crate::packets::motion::CarMotionData;
|
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::car_setups::CarSetupData;
|
use crate::packets::final_classification::FinalClassificationData;
|
||||||
use crate::packets::car_status::CarStatusData;
|
|
||||||
use crate::packets::car_telemetry::CarTelemetryData;
|
|
||||||
use binrw::BinRead;
|
use binrw::BinRead;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::string::FromUtf8Error;
|
use std::string::FromUtf8Error;
|
||||||
@ -31,13 +33,13 @@ use std::string::FromUtf8Error;
|
|||||||
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 F1PacketMotionData {
|
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 (2022 format only).
|
||||||
#[br(if(packet_format == 2022))]
|
#[br(if(packet_format == 2022))]
|
||||||
pub motion_ex_data: Option<F1PacketMotionExData>,
|
pub motion_ex_data: Option<F1PacketMotionEx>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Data about the ongoing session.
|
/// Data about the ongoing session.
|
||||||
@ -65,7 +67,7 @@ pub struct F1PacketMotionData {
|
|||||||
ai_difficulty
|
ai_difficulty
|
||||||
),
|
),
|
||||||
)]
|
)]
|
||||||
pub struct F1PacketSessionData {
|
pub struct F1PacketSession {
|
||||||
/// Current weather.
|
/// Current weather.
|
||||||
pub weather: Weather,
|
pub weather: Weather,
|
||||||
/// Track temperature in degrees Celsius.
|
/// Track temperature in degrees Celsius.
|
||||||
@ -104,7 +106,8 @@ pub struct F1PacketSessionData {
|
|||||||
#[br(map(u8_to_usize))]
|
#[br(map(u8_to_usize))]
|
||||||
pub num_marshal_zones: usize,
|
pub num_marshal_zones: usize,
|
||||||
/// List of marshal zones.
|
/// List of marshal zones.
|
||||||
/// Has a size of 21 regardless of the `num_marshal_zones` value.
|
/// Has a size of 21 regardless of the
|
||||||
|
/// [`num_marshal_zones`](field@F1PacketSession::num_marshal_zones) value.
|
||||||
#[br(count(21), args{ inner: (packet_format,) })]
|
#[br(count(21), args{ inner: (packet_format,) })]
|
||||||
pub marshal_zones: Vec<MarshalZone>,
|
pub marshal_zones: Vec<MarshalZone>,
|
||||||
/// Safety car deployment status.
|
/// Safety car deployment status.
|
||||||
@ -116,7 +119,9 @@ pub struct F1PacketSessionData {
|
|||||||
#[br(map(u8_to_usize))]
|
#[br(map(u8_to_usize))]
|
||||||
pub num_weather_forecast_samples: usize,
|
pub num_weather_forecast_samples: usize,
|
||||||
/// List of up to weather forecast samples.
|
/// List of up to weather forecast samples.
|
||||||
/// Has a size of 56 regardless of the `num_weather_forecast_samples` value.
|
/// Has a size of 56 regardless of the
|
||||||
|
/// [`num_weather_forecast_samples`](field@F1PacketSession::num_weather_forecast_samples)
|
||||||
|
/// value.
|
||||||
#[br(count(56), args{ inner: (packet_format,) })]
|
#[br(count(56), args{ inner: (packet_format,) })]
|
||||||
pub weather_forecast_samples: Vec<WeatherForecastSample>,
|
pub weather_forecast_samples: Vec<WeatherForecastSample>,
|
||||||
/// Weather forecast accuracy.
|
/// Weather forecast accuracy.
|
||||||
@ -174,7 +179,7 @@ pub struct F1PacketSessionData {
|
|||||||
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 F1PacketLapData {
|
pub struct F1PacketLap {
|
||||||
/// Lap data for all cars on track.
|
/// Lap 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 lap_data: Vec<LapData>,
|
pub lap_data: Vec<LapData>,
|
||||||
@ -192,7 +197,7 @@ pub struct F1PacketLapData {
|
|||||||
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 F1PacketEventData {
|
pub struct F1PacketEvent {
|
||||||
/// 4-letter event code.
|
/// 4-letter event code.
|
||||||
#[br(
|
#[br(
|
||||||
try_map(|bytes: [u8; 4]| String::from_utf8(bytes.to_vec())),
|
try_map(|bytes: [u8; 4]| String::from_utf8(bytes.to_vec())),
|
||||||
@ -212,18 +217,19 @@ pub struct F1PacketEventData {
|
|||||||
little,
|
little,
|
||||||
import(packet_format: u16),
|
import(packet_format: u16),
|
||||||
assert(
|
assert(
|
||||||
num_active_cars <= MAX_NUM_CARS,
|
num_cars <= MAX_NUM_CARS,
|
||||||
"Participants packet has an invalid number of active cars: {}",
|
"Participants packet has an invalid number of cars: {}",
|
||||||
num_active_cars
|
num_cars
|
||||||
)
|
)
|
||||||
)]
|
)]
|
||||||
pub struct F1PacketParticipantsData {
|
pub struct F1PacketParticipants {
|
||||||
/// Number of active cars in the data (no greater than 22)
|
/// Number of active cars in the data (no greater than 22)
|
||||||
#[br(map(u8_to_usize))]
|
#[br(map(u8_to_usize))]
|
||||||
pub num_active_cars: usize,
|
pub num_cars: usize,
|
||||||
/// Data for all participants.
|
/// Data for all participants.
|
||||||
/// Should have a size equal to `num_active_cars`.
|
/// Should have a size equal to
|
||||||
#[br(count(num_active_cars), args{ inner: (packet_format,) })]
|
/// [`num_cars`](field@F1PacketParticipants::num_cars).
|
||||||
|
#[br(count(num_cars), args{ inner: (packet_format,) })]
|
||||||
pub participants: Vec<ParticipantsData>,
|
pub participants: Vec<ParticipantsData>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -235,7 +241,7 @@ pub struct F1PacketParticipantsData {
|
|||||||
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 F1PacketCarSetupsData {
|
pub struct F1PacketCarSetups {
|
||||||
/// Setup data for all cars on track.
|
/// Setup data for all cars on track.
|
||||||
/// Should have a size of 22.
|
/// Should have a size of 22.
|
||||||
#[br(count(MAX_NUM_CARS), args{ inner: (packet_format,) })]
|
#[br(count(MAX_NUM_CARS), args{ inner: (packet_format,) })]
|
||||||
@ -256,14 +262,14 @@ pub struct F1PacketCarSetupsData {
|
|||||||
suggested_gear
|
suggested_gear
|
||||||
),
|
),
|
||||||
)]
|
)]
|
||||||
pub struct F1PacketCarTelemetryData {
|
pub struct F1PacketCarTelemetry {
|
||||||
/// Telemetry data for all cars on track.
|
/// Telemetry data for all cars on track.
|
||||||
/// Should have a size of 22.
|
/// Should have a size of 22.
|
||||||
#[br(count(MAX_NUM_CARS), args{ inner: (packet_format,) })]
|
#[br(count(MAX_NUM_CARS), args{ inner: (packet_format,) })]
|
||||||
pub car_telemetry_data: Vec<CarTelemetryData>,
|
pub car_telemetry_data: Vec<CarTelemetryData>,
|
||||||
/// Index of currently open MFD panel.
|
/// Index of currently open MFD panel.
|
||||||
pub mfd_panel_index: MfdPanelIndex,
|
pub mfd_panel_index: MfdPanelIndex,
|
||||||
/// See [`mfd_panel_index`](field@F1PacketCarTelemetryData::mfd_panel_index).
|
/// See [`mfd_panel_index`](field@F1PacketCarTelemetry::mfd_panel_index).
|
||||||
pub mfd_panel_index_secondary_player: MfdPanelIndex,
|
pub mfd_panel_index_secondary_player: MfdPanelIndex,
|
||||||
/// Suggested gear (0 if no gear suggested).
|
/// Suggested gear (0 if no gear suggested).
|
||||||
pub suggested_gear: i8,
|
pub suggested_gear: i8,
|
||||||
@ -275,21 +281,46 @@ pub struct F1PacketCarTelemetryData {
|
|||||||
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 F1PacketCarStatusData {
|
pub struct F1PacketCarStatus {
|
||||||
/// Status data for all cars. Should have a size of 22.
|
/// Status data for all cars. Should have a size of 22.
|
||||||
#[br(count(MAX_NUM_CARS), args{ inner: (packet_format,) })]
|
#[br(count(MAX_NUM_CARS), args{ inner: (packet_format,) })]
|
||||||
pub car_status_data: Vec<CarStatusData>,
|
pub car_status_data: Vec<CarStatusData>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Final classification confirmation at the end of a race.
|
||||||
|
#[non_exhaustive]
|
||||||
|
#[derive(
|
||||||
|
BinRead, PartialEq, PartialOrd, Clone, Debug, Serialize, Deserialize,
|
||||||
|
)]
|
||||||
|
#[br(
|
||||||
|
little,
|
||||||
|
import(packet_format: u16),
|
||||||
|
assert(
|
||||||
|
num_cars <= MAX_NUM_CARS,
|
||||||
|
"Final classification packet has an invalid number of cars: {}",
|
||||||
|
num_cars
|
||||||
|
)
|
||||||
|
)]
|
||||||
|
pub struct F1PacketFinalClassification {
|
||||||
|
/// Number of cars in the final classification (no greater than 22).
|
||||||
|
#[br(map(u8_to_usize))]
|
||||||
|
pub num_cars: usize,
|
||||||
|
/// Final classification data for all cars.
|
||||||
|
/// Should have a size equal to
|
||||||
|
/// [`num_cars`](field@F1PacketFinalClassificationData::num_cars).
|
||||||
|
#[br(count(num_cars), args{ inner: (packet_format,) })]
|
||||||
|
pub final_classification_data: Vec<FinalClassificationData>,
|
||||||
|
}
|
||||||
|
|
||||||
/// Extended motion data for player's car. Available as a:
|
/// Extended motion data for player's car. Available as a:
|
||||||
/// - part of [`F1PacketMotionData`] 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
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
#[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 F1PacketMotionExData {
|
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)
|
||||||
/// for wheel order.
|
/// for wheel order.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user