mirror of
https://github.com/maciejpedzich/f1-game-packet-parser.git
synced 2025-04-16 01:51:12 +02:00
feat: add 2022 spec car status packet parser
This commit is contained in:
parent
8ea06e5a53
commit
839e1ab30b
@ -1,14 +1,11 @@
|
||||
pub mod wheel_index;
|
||||
pub mod driver_id;
|
||||
pub mod wheel_index;
|
||||
|
||||
use binrw::BinRead;
|
||||
use bitflags::bitflags;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
pub(crate) const MAX_NUM_CARS: usize = 22;
|
||||
pub(crate) const MAX_NUM_MARSHAL_ZONES: usize = 21;
|
||||
pub(crate) const MAX_NUM_WEATHER_FORECAST_SAMPLES: usize = 56;
|
||||
pub(crate) const MAX_AI_DIFFICULTY: u8 = 110;
|
||||
|
||||
#[non_exhaustive]
|
||||
#[derive(
|
||||
@ -983,3 +980,170 @@ pub enum MfdPanelIndex {
|
||||
Temperatures = 4,
|
||||
Closed = 255,
|
||||
}
|
||||
|
||||
#[non_exhaustive]
|
||||
#[derive(
|
||||
BinRead,
|
||||
Eq,
|
||||
PartialEq,
|
||||
Ord,
|
||||
PartialOrd,
|
||||
Copy,
|
||||
Clone,
|
||||
Debug,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
)]
|
||||
#[br(little, repr(u8))]
|
||||
pub enum TractionControl {
|
||||
Off = 0,
|
||||
Medium = 1,
|
||||
Full = 2,
|
||||
}
|
||||
|
||||
#[non_exhaustive]
|
||||
#[derive(
|
||||
BinRead,
|
||||
Eq,
|
||||
PartialEq,
|
||||
Ord,
|
||||
PartialOrd,
|
||||
Copy,
|
||||
Clone,
|
||||
Debug,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
)]
|
||||
#[br(little, repr(u8))]
|
||||
pub enum FuelMix {
|
||||
Lean = 0,
|
||||
Standard = 1,
|
||||
Rich = 2,
|
||||
Max = 3,
|
||||
}
|
||||
|
||||
#[non_exhaustive]
|
||||
#[derive(
|
||||
BinRead,
|
||||
Eq,
|
||||
PartialEq,
|
||||
Ord,
|
||||
PartialOrd,
|
||||
Copy,
|
||||
Clone,
|
||||
Debug,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
)]
|
||||
#[br(little, repr(u8))]
|
||||
pub enum ErsDeployMode {
|
||||
None = 0,
|
||||
Medium = 1,
|
||||
Overtake = 2,
|
||||
Hotlap = 3,
|
||||
}
|
||||
|
||||
#[non_exhaustive]
|
||||
#[derive(
|
||||
BinRead,
|
||||
Eq,
|
||||
PartialEq,
|
||||
Ord,
|
||||
PartialOrd,
|
||||
Copy,
|
||||
Clone,
|
||||
Debug,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
)]
|
||||
#[br(little, repr(i8))]
|
||||
pub enum VehicleFiaFlag {
|
||||
Unknown = -1,
|
||||
None = 0,
|
||||
Green = 1,
|
||||
Blue = 2,
|
||||
Yellow = 3,
|
||||
Red = 4,
|
||||
}
|
||||
|
||||
#[non_exhaustive]
|
||||
#[derive(
|
||||
BinRead,
|
||||
Eq,
|
||||
PartialEq,
|
||||
Ord,
|
||||
PartialOrd,
|
||||
Copy,
|
||||
Clone,
|
||||
Debug,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
)]
|
||||
#[br(little, repr(i8))]
|
||||
pub enum DrsAllowed {
|
||||
Unknown = -1,
|
||||
NotAllowed = 0,
|
||||
Allowed = 1,
|
||||
}
|
||||
|
||||
#[non_exhaustive]
|
||||
#[derive(
|
||||
BinRead,
|
||||
Eq,
|
||||
PartialEq,
|
||||
Ord,
|
||||
PartialOrd,
|
||||
Copy,
|
||||
Clone,
|
||||
Debug,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
)]
|
||||
#[br(little, repr(u8))]
|
||||
pub enum ActualTyreCompound {
|
||||
Unknown = 0,
|
||||
F1C5 = 16,
|
||||
F1C4 = 17,
|
||||
F1C3 = 18,
|
||||
F1C2 = 19,
|
||||
F1C1 = 20,
|
||||
F1Inter = 7,
|
||||
F1Wet = 8,
|
||||
ClassicDry = 9,
|
||||
ClassicWet = 10,
|
||||
F2SuperSoft = 11,
|
||||
F2Soft = 12,
|
||||
F2Medium = 13,
|
||||
F2Hard = 14,
|
||||
F2Wet = 15,
|
||||
}
|
||||
|
||||
#[non_exhaustive]
|
||||
#[derive(
|
||||
BinRead,
|
||||
Eq,
|
||||
PartialEq,
|
||||
Ord,
|
||||
PartialOrd,
|
||||
Copy,
|
||||
Clone,
|
||||
Debug,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
)]
|
||||
#[br(little, repr(u8))]
|
||||
pub enum VisualTyreCompound {
|
||||
Unknown = 0,
|
||||
F1Soft = 16,
|
||||
F1Medium = 17,
|
||||
F1Hard = 18,
|
||||
F1Inter = 7,
|
||||
F1Wet = 8,
|
||||
ClassicDry = 9,
|
||||
ClassicWet = 10,
|
||||
F2SuperSoft = 19,
|
||||
F2Soft = 20,
|
||||
F2Medium = 21,
|
||||
F2Hard = 22,
|
||||
F2Wet = 15,
|
||||
}
|
||||
|
@ -3,9 +3,9 @@ pub mod packets;
|
||||
|
||||
use crate::constants::PacketId;
|
||||
use crate::packets::{
|
||||
F1PacketCarSetupsData, F1PacketCarTelemetryData, F1PacketEventData,
|
||||
F1PacketLapData, F1PacketMotionData, F1PacketParticipantsData,
|
||||
F1PacketSessionData,
|
||||
F1PacketCarSetupsData, F1PacketCarStatusData, F1PacketCarTelemetryData,
|
||||
F1PacketEventData, F1PacketLapData, F1PacketMotionData,
|
||||
F1PacketParticipantsData, F1PacketSessionData,
|
||||
};
|
||||
|
||||
use binrw::io::Cursor;
|
||||
@ -93,4 +93,6 @@ pub struct F1PacketBody {
|
||||
pub car_setups: Option<F1PacketCarSetupsData>,
|
||||
#[br(if(packet_id == PacketId::CarTelemetry), args(packet_format))]
|
||||
pub car_telemetry: Option<F1PacketCarTelemetryData>,
|
||||
#[br(if(packet_id == PacketId::CarStatus), args(packet_format))]
|
||||
pub car_status: Option<F1PacketCarStatusData>,
|
||||
}
|
||||
|
72
src/packets/car_status.rs
Normal file
72
src/packets/car_status.rs
Normal file
@ -0,0 +1,72 @@
|
||||
use super::u8_to_bool;
|
||||
use crate::constants::{
|
||||
ActualTyreCompound, DrsAllowed, ErsDeployMode, FuelMix, TractionControl,
|
||||
VehicleFiaFlag, VisualTyreCompound,
|
||||
};
|
||||
|
||||
use binrw::BinRead;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(
|
||||
BinRead, PartialEq, PartialOrd, Copy, Clone, Debug, Serialize, Deserialize,
|
||||
)]
|
||||
#[br(
|
||||
little,
|
||||
import(_packet_format: u16),
|
||||
assert(
|
||||
max_gears <= 8,
|
||||
"Car status entry has an invalid max number of gears: {}",
|
||||
max_gears
|
||||
)
|
||||
)]
|
||||
pub struct CarStatusData {
|
||||
/// How much traction control is enabled.
|
||||
pub traction_control: TractionControl,
|
||||
/// Whether ABS is enabled.
|
||||
#[br(map(u8_to_bool))]
|
||||
pub anti_lock_brakes: bool,
|
||||
/// Fuel mix currently in use.
|
||||
pub fuel_mix: FuelMix,
|
||||
/// Front brake bias (percentage).
|
||||
pub front_brake_bias: u8,
|
||||
/// Whether the pit limiter is enabled.
|
||||
#[br(map(u8_to_bool))]
|
||||
pub pit_limiter_enabled: bool,
|
||||
/// Current fuel mass.
|
||||
pub fuel_in_tank: f32,
|
||||
/// Fuel capacity.
|
||||
pub fuel_capacity: f32,
|
||||
/// Fuel remaining in terms of laps.
|
||||
pub fuel_remaining_laps: f32,
|
||||
/// Car's max RPM, point of rev limiter.
|
||||
pub max_rpm: u16,
|
||||
/// Car's idle RPM.
|
||||
pub idle_rpm: u16,
|
||||
/// Maximum number of gears.
|
||||
pub max_gears: u8,
|
||||
/// Whether DRS can be used (might be unknown).
|
||||
pub drs_allowed: DrsAllowed,
|
||||
/// 0 = DRS is unavailable, Non-zero = DRS will be available in X metres.
|
||||
pub drs_activation_distance: u16,
|
||||
/// Actual tyre compound currently in use.
|
||||
pub actual_tyre_compound: ActualTyreCompound,
|
||||
/// Visible tyre compound currently in use.
|
||||
pub visual_tyre_compound: VisualTyreCompound,
|
||||
/// Age of the current set of tyres in laps.
|
||||
pub tyres_age_laps: u8,
|
||||
/// Flag the driver is currently being shown.
|
||||
pub vehicle_fia_flag: VehicleFiaFlag,
|
||||
/// ERS energy store in Joules.
|
||||
pub ers_store_energy: f32,
|
||||
/// ERS deployment mode.
|
||||
pub ers_deploy_mode: ErsDeployMode,
|
||||
/// ERS energy harvested this lap by the MGU-K.
|
||||
pub ers_harvested_this_lap_mguk: f32,
|
||||
/// ERS energy harvested this lap by the MGU-H.
|
||||
pub ers_harvested_this_lap_mguh: f32,
|
||||
/// ERS energy deployed this lap.
|
||||
pub ers_deployed_this_lap: f32,
|
||||
/// Whether the car has paused in a network game.
|
||||
#[br(map(u8_to_bool))]
|
||||
pub network_paused: bool,
|
||||
}
|
@ -27,7 +27,7 @@ use serde::{Deserialize, Serialize};
|
||||
brake
|
||||
),
|
||||
assert(
|
||||
(0..=100).contains(&clutch),
|
||||
clutch <= 100,
|
||||
"Car telemetry entry has an invalid clutch value: {}",
|
||||
clutch
|
||||
),
|
||||
@ -37,7 +37,7 @@ use serde::{Deserialize, Serialize};
|
||||
gear
|
||||
),
|
||||
assert(
|
||||
(0..=100).contains(&rev_lights_percent),
|
||||
rev_lights_percent <= 100,
|
||||
"Car telemetry entry has an invalid rev lights percentage: {}",
|
||||
rev_lights_percent
|
||||
),
|
||||
@ -51,7 +51,7 @@ pub struct CarTelemetryData {
|
||||
pub steer: f32,
|
||||
/// Amount of brake applied. Value in range `(0.0..=1.0)`.
|
||||
pub brake: f32,
|
||||
/// Amount of clutch applied. Value in range `(0..=100)`.
|
||||
/// Amount of clutch applied (percentage).
|
||||
pub clutch: u8,
|
||||
/// Selected gear. Neutral = 0, reverse = -1.
|
||||
pub gear: i8,
|
||||
|
@ -1,4 +1,5 @@
|
||||
pub mod car_setups;
|
||||
pub mod car_status;
|
||||
pub mod car_telemetry;
|
||||
pub mod event;
|
||||
pub mod lap_data;
|
||||
@ -9,8 +10,7 @@ pub mod session;
|
||||
use crate::constants::{
|
||||
BrakingAssist, DynamicRacingLine, DynamicRacingLineType, ForecastAccuracy,
|
||||
Formula, GameMode, GearboxAssist, MfdPanelIndex, Ruleset, SafetyCarStatus,
|
||||
SessionLength, SessionType, TrackId, Weather, MAX_AI_DIFFICULTY,
|
||||
MAX_NUM_CARS, MAX_NUM_MARSHAL_ZONES, MAX_NUM_WEATHER_FORECAST_SAMPLES,
|
||||
SessionLength, SessionType, TrackId, Weather, MAX_NUM_CARS,
|
||||
};
|
||||
use crate::packets::event::EventDataDetails;
|
||||
use crate::packets::lap_data::LapData;
|
||||
@ -19,6 +19,7 @@ use crate::packets::participants::ParticipantsData;
|
||||
use crate::packets::session::{MarshalZone, WeatherForecastSample};
|
||||
|
||||
use crate::packets::car_setups::CarSetupData;
|
||||
use crate::packets::car_status::CarStatusData;
|
||||
use crate::packets::car_telemetry::CarTelemetryData;
|
||||
use binrw::BinRead;
|
||||
use serde::{Deserialize, Serialize};
|
||||
@ -49,17 +50,17 @@ pub struct F1PacketMotionData {
|
||||
little,
|
||||
import(packet_format: u16),
|
||||
assert(
|
||||
num_marshal_zones <= MAX_NUM_MARSHAL_ZONES,
|
||||
num_marshal_zones <= 21,
|
||||
"Session packet has an invalid number of marshal zones: {}",
|
||||
num_marshal_zones
|
||||
),
|
||||
assert(
|
||||
num_weather_forecast_samples <= MAX_NUM_WEATHER_FORECAST_SAMPLES,
|
||||
num_weather_forecast_samples <= 56,
|
||||
"Session packet has an invalid number of weather forecast samples: {}",
|
||||
num_weather_forecast_samples
|
||||
),
|
||||
assert(
|
||||
ai_difficulty <= MAX_AI_DIFFICULTY,
|
||||
ai_difficulty <= 110,
|
||||
"Session packet has an invalid AI difficulty value: {}",
|
||||
ai_difficulty
|
||||
),
|
||||
@ -104,7 +105,7 @@ pub struct F1PacketSessionData {
|
||||
pub num_marshal_zones: usize,
|
||||
/// List of marshal zones.
|
||||
/// Has a size of 21 regardless of the `num_marshal_zones` value.
|
||||
#[br(count(MAX_NUM_MARSHAL_ZONES), args{ inner: (packet_format,) })]
|
||||
#[br(count(21), args{ inner: (packet_format,) })]
|
||||
pub marshal_zones: Vec<MarshalZone>,
|
||||
/// Safety car deployment status.
|
||||
pub safety_car_status: SafetyCarStatus,
|
||||
@ -116,10 +117,7 @@ pub struct F1PacketSessionData {
|
||||
pub num_weather_forecast_samples: usize,
|
||||
/// List of up to weather forecast samples.
|
||||
/// Has a size of 56 regardless of the `num_weather_forecast_samples` value.
|
||||
#[br(
|
||||
count(MAX_NUM_WEATHER_FORECAST_SAMPLES),
|
||||
args{ inner: (packet_format,) }
|
||||
)]
|
||||
#[br(count(56), args{ inner: (packet_format,) })]
|
||||
pub weather_forecast_samples: Vec<WeatherForecastSample>,
|
||||
/// Weather forecast accuracy.
|
||||
pub forecast_accuracy: ForecastAccuracy,
|
||||
@ -224,8 +222,7 @@ pub struct F1PacketParticipantsData {
|
||||
#[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)
|
||||
/// Should have a size equal to `num_active_cars`.
|
||||
#[br(count(num_active_cars), args{ inner: (packet_format,) })]
|
||||
pub participants: Vec<ParticipantsData>,
|
||||
}
|
||||
@ -261,20 +258,29 @@ pub struct F1PacketCarSetupsData {
|
||||
)]
|
||||
pub struct F1PacketCarTelemetryData {
|
||||
/// Telemetry data for all cars on track.
|
||||
/// Should have a size of 22
|
||||
#[br(
|
||||
count(MAX_NUM_CARS),
|
||||
args{ inner: (packet_format,) }
|
||||
)]
|
||||
/// Should have a size of 22.
|
||||
#[br(count(MAX_NUM_CARS), args{ inner: (packet_format,) })]
|
||||
pub car_telemetry_data: Vec<CarTelemetryData>,
|
||||
/// Index of currently open MFD panel.
|
||||
pub mfd_panel_index: MfdPanelIndex,
|
||||
/// See [`mfd_panel_index`](field@F1PacketCarTelemetryData::mfd_panel_index)
|
||||
/// See [`mfd_panel_index`](field@F1PacketCarTelemetryData::mfd_panel_index).
|
||||
pub mfd_panel_index_secondary_player: MfdPanelIndex,
|
||||
/// Suggested gear (0 if no gear suggested).
|
||||
pub suggested_gear: i8,
|
||||
}
|
||||
|
||||
/// Car status data for each car in the race.
|
||||
#[non_exhaustive]
|
||||
#[derive(
|
||||
BinRead, PartialEq, PartialOrd, Clone, Debug, Serialize, Deserialize,
|
||||
)]
|
||||
#[br(little, import(packet_format: u16))]
|
||||
pub struct F1PacketCarStatusData {
|
||||
/// Status data for all cars. Should have a size of 22.
|
||||
#[br(count(MAX_NUM_CARS), args{ inner: (packet_format,) })]
|
||||
pub car_status_data: Vec<CarStatusData>,
|
||||
}
|
||||
|
||||
/// Extended motion data for player's car. Available as a:
|
||||
/// - part of [`F1PacketMotionData`] in the 2022 format
|
||||
/// - standalone packet from the 2023 format onwards
|
||||
|
Loading…
x
Reference in New Issue
Block a user