mirror of
https://github.com/maciejpedzich/f1-game-packet-parser.git
synced 2025-06-27 09:46:17 +02:00
feat: add 2022 spec session packet parser
This commit is contained in:
parent
4b304fbd4e
commit
dee766fb12
@ -34,3 +34,377 @@ pub enum PacketId {
|
||||
MotionEx = 13,
|
||||
TimeTrial = 14,
|
||||
}
|
||||
|
||||
#[non_exhaustive]
|
||||
#[derive(
|
||||
BinRead,
|
||||
Eq,
|
||||
PartialEq,
|
||||
Ord,
|
||||
PartialOrd,
|
||||
Copy,
|
||||
Clone,
|
||||
Debug,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
)]
|
||||
#[br(little, repr(i8))]
|
||||
pub enum MarshalZoneFlag {
|
||||
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(u8))]
|
||||
pub enum Weather {
|
||||
Clear = 0,
|
||||
LightCloud = 1,
|
||||
Overcast = 2,
|
||||
LightRain = 3,
|
||||
HeavyRain = 4,
|
||||
Storm = 5,
|
||||
}
|
||||
|
||||
#[non_exhaustive]
|
||||
#[derive(
|
||||
BinRead,
|
||||
Eq,
|
||||
PartialEq,
|
||||
Ord,
|
||||
PartialOrd,
|
||||
Copy,
|
||||
Clone,
|
||||
Debug,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
)]
|
||||
#[br(little, repr(u8))]
|
||||
pub enum SessionType {
|
||||
Unknown = 0,
|
||||
Practice1 = 1,
|
||||
Practice2 = 2,
|
||||
Practice3 = 3,
|
||||
ShortPractice = 4,
|
||||
Qualifying1 = 5,
|
||||
Qualifying2 = 6,
|
||||
Qualifying3 = 7,
|
||||
ShortQualifying = 8,
|
||||
OneShotQualifying = 9,
|
||||
Race = 10,
|
||||
Race2 = 11,
|
||||
TimeTrial = 12,
|
||||
}
|
||||
|
||||
#[non_exhaustive]
|
||||
#[derive(
|
||||
BinRead,
|
||||
Eq,
|
||||
PartialEq,
|
||||
Ord,
|
||||
PartialOrd,
|
||||
Copy,
|
||||
Clone,
|
||||
Debug,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
)]
|
||||
#[br(little, repr(i8))]
|
||||
pub enum TemperatureChange {
|
||||
Up = 0,
|
||||
Down = 1,
|
||||
NoChange = 2,
|
||||
}
|
||||
|
||||
#[non_exhaustive]
|
||||
#[derive(
|
||||
BinRead,
|
||||
Eq,
|
||||
PartialEq,
|
||||
Ord,
|
||||
PartialOrd,
|
||||
Copy,
|
||||
Clone,
|
||||
Debug,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
)]
|
||||
#[br(little, repr(i8))]
|
||||
pub enum TrackId {
|
||||
Unknown = -1,
|
||||
Melbourne = 0,
|
||||
PaulRicard = 1,
|
||||
Shanghai = 2,
|
||||
Sakhir = 3,
|
||||
Catalunya = 4,
|
||||
Monaco = 5,
|
||||
Montreal = 6,
|
||||
Silverstone = 7,
|
||||
Hockenheim = 8,
|
||||
Hungaroring = 9,
|
||||
Spa = 10,
|
||||
Monza = 11,
|
||||
Singapore = 12,
|
||||
Suzuka = 13,
|
||||
AbuDhabi = 14,
|
||||
Texas = 15,
|
||||
Brazil = 16,
|
||||
Austria = 17,
|
||||
Sochi = 18,
|
||||
Mexico = 19,
|
||||
Baku = 20,
|
||||
SakhirShort = 21,
|
||||
SilverstoneShort = 22,
|
||||
TexasShort = 23,
|
||||
SuzukaShort = 24,
|
||||
Hanoi = 25,
|
||||
Zandvoort = 26,
|
||||
Imola = 27,
|
||||
Portimao = 28,
|
||||
Jeddah = 29,
|
||||
Miami = 30,
|
||||
LasVegas = 31,
|
||||
Losail = 32,
|
||||
}
|
||||
|
||||
#[non_exhaustive]
|
||||
#[derive(
|
||||
BinRead,
|
||||
Eq,
|
||||
PartialEq,
|
||||
Ord,
|
||||
PartialOrd,
|
||||
Copy,
|
||||
Clone,
|
||||
Debug,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
)]
|
||||
#[br(little, repr(u8))]
|
||||
pub enum Formula {
|
||||
F1Modern = 0,
|
||||
F1Classic = 1,
|
||||
F2 = 2,
|
||||
F1Generic = 3,
|
||||
Beta = 4,
|
||||
Supercars = 5,
|
||||
Esports = 6,
|
||||
F22021 = 7,
|
||||
}
|
||||
|
||||
#[non_exhaustive]
|
||||
#[derive(
|
||||
BinRead,
|
||||
Eq,
|
||||
PartialEq,
|
||||
Ord,
|
||||
PartialOrd,
|
||||
Copy,
|
||||
Clone,
|
||||
Debug,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
)]
|
||||
#[br(little, repr(u8))]
|
||||
pub enum SafetyCarStatus {
|
||||
None = 0,
|
||||
Virtual = 1,
|
||||
Full = 2,
|
||||
FormationLap = 3,
|
||||
}
|
||||
|
||||
#[non_exhaustive]
|
||||
#[derive(
|
||||
BinRead,
|
||||
Eq,
|
||||
PartialEq,
|
||||
Ord,
|
||||
PartialOrd,
|
||||
Copy,
|
||||
Clone,
|
||||
Debug,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
)]
|
||||
#[br(little, repr(u8))]
|
||||
pub enum ForecastAccuracy {
|
||||
Perfect = 0,
|
||||
Approximate = 1,
|
||||
}
|
||||
|
||||
#[non_exhaustive]
|
||||
#[derive(
|
||||
BinRead,
|
||||
Eq,
|
||||
PartialEq,
|
||||
Ord,
|
||||
PartialOrd,
|
||||
Copy,
|
||||
Clone,
|
||||
Debug,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
)]
|
||||
#[br(little, repr(u8))]
|
||||
pub enum BrakingAssist {
|
||||
Off = 0,
|
||||
Low = 1,
|
||||
Medium = 2,
|
||||
High = 3,
|
||||
}
|
||||
|
||||
#[non_exhaustive]
|
||||
#[derive(
|
||||
BinRead,
|
||||
Eq,
|
||||
PartialEq,
|
||||
Ord,
|
||||
PartialOrd,
|
||||
Copy,
|
||||
Clone,
|
||||
Debug,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
)]
|
||||
#[br(little, repr(u8))]
|
||||
pub enum GearboxAssist {
|
||||
Unknown = 0,
|
||||
Manual = 1,
|
||||
ManualWithSuggestedGear = 2,
|
||||
Automatic = 3,
|
||||
}
|
||||
|
||||
#[non_exhaustive]
|
||||
#[derive(
|
||||
BinRead,
|
||||
Eq,
|
||||
PartialEq,
|
||||
Ord,
|
||||
PartialOrd,
|
||||
Copy,
|
||||
Clone,
|
||||
Debug,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
)]
|
||||
#[br(little, repr(u8))]
|
||||
pub enum DynamicRacingLine {
|
||||
Off = 0,
|
||||
CornersOnly = 1,
|
||||
Full = 2,
|
||||
}
|
||||
|
||||
#[non_exhaustive]
|
||||
#[derive(
|
||||
BinRead,
|
||||
Eq,
|
||||
PartialEq,
|
||||
Ord,
|
||||
PartialOrd,
|
||||
Copy,
|
||||
Clone,
|
||||
Debug,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
)]
|
||||
#[br(little, repr(u8))]
|
||||
pub enum DynamicRacingLineType {
|
||||
TwoDimensional = 0,
|
||||
ThreeDimensional = 1,
|
||||
}
|
||||
|
||||
#[non_exhaustive]
|
||||
#[derive(
|
||||
BinRead,
|
||||
Eq,
|
||||
PartialEq,
|
||||
Ord,
|
||||
PartialOrd,
|
||||
Copy,
|
||||
Clone,
|
||||
Debug,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
)]
|
||||
#[br(little, repr(u8))]
|
||||
pub enum GameMode {
|
||||
EventMode = 0,
|
||||
GrandPrix = 3,
|
||||
TimeTrial = 5,
|
||||
Splitscreen = 6,
|
||||
OnlineCustom = 7,
|
||||
OnlineLeague = 8,
|
||||
CareerInvitational = 11,
|
||||
ChampionshipInvitational = 12,
|
||||
Championship = 13,
|
||||
OnlineChampionship = 14,
|
||||
OnlineWeeklyEvent = 15,
|
||||
Career2022 = 19,
|
||||
Career2022Online = 20,
|
||||
Benchmark = 127,
|
||||
}
|
||||
|
||||
#[non_exhaustive]
|
||||
#[derive(
|
||||
BinRead,
|
||||
Eq,
|
||||
PartialEq,
|
||||
Ord,
|
||||
PartialOrd,
|
||||
Copy,
|
||||
Clone,
|
||||
Debug,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
)]
|
||||
#[br(little, repr(u8))]
|
||||
pub enum Ruleset {
|
||||
PracticeAndQualifying = 0,
|
||||
Race = 1,
|
||||
TimeTrial = 2,
|
||||
TimeAttack = 4,
|
||||
CheckpointChallenge = 6,
|
||||
Autocross = 8,
|
||||
Drift = 9,
|
||||
AverageSpeedZone = 10,
|
||||
RivalDuel = 11,
|
||||
}
|
||||
|
||||
#[non_exhaustive]
|
||||
#[derive(
|
||||
BinRead,
|
||||
Eq,
|
||||
PartialEq,
|
||||
Ord,
|
||||
PartialOrd,
|
||||
Copy,
|
||||
Clone,
|
||||
Debug,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
)]
|
||||
#[br(little, repr(u8))]
|
||||
pub enum SessionLength {
|
||||
None = 0,
|
||||
VeryShort = 2,
|
||||
Short = 3,
|
||||
Medium = 4,
|
||||
MediumLong = 5,
|
||||
Long = 6,
|
||||
Full = 7,
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ pub mod constants;
|
||||
pub mod packets;
|
||||
|
||||
use crate::constants::PacketId;
|
||||
use crate::packets::F1PacketMotionData;
|
||||
use crate::packets::{F1PacketMotionData, F1PacketSessionData};
|
||||
|
||||
use binrw::io::Cursor;
|
||||
use binrw::{BinRead, BinReaderExt, BinResult};
|
||||
@ -69,4 +69,6 @@ pub struct F1PacketHeader {
|
||||
pub struct F1PacketBody {
|
||||
#[br(if(packet_id == PacketId::Motion), args(packet_format))]
|
||||
pub motion: Option<F1PacketMotionData>,
|
||||
#[br(if(packet_id == PacketId::Session), args(packet_format))]
|
||||
pub session: Option<F1PacketSessionData>,
|
||||
}
|
||||
|
@ -1,7 +1,15 @@
|
||||
pub mod motion;
|
||||
pub mod session;
|
||||
|
||||
use crate::packets::motion::CarMotionData;
|
||||
|
||||
use crate::constants::{
|
||||
BrakingAssist, DynamicRacingLine, DynamicRacingLineType, ForecastAccuracy,
|
||||
Formula, GameMode, GearboxAssist, Ruleset, SafetyCarStatus, SessionLength,
|
||||
SessionType, TrackId, Weather,
|
||||
};
|
||||
use crate::packets::session::{MarshalZone, WeatherForecastSample};
|
||||
|
||||
use binrw::BinRead;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::string::FromUtf8Error;
|
||||
@ -16,11 +24,119 @@ pub struct F1PacketMotionData {
|
||||
/// Motion data for all cars on track.
|
||||
#[br(count(22))]
|
||||
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))]
|
||||
pub motion_ex_data: Option<F1PacketMotionExData>,
|
||||
}
|
||||
|
||||
#[allow(clippy::struct_excessive_bools)]
|
||||
#[non_exhaustive]
|
||||
#[derive(
|
||||
BinRead, PartialEq, PartialOrd, Clone, Debug, Serialize, Deserialize,
|
||||
)]
|
||||
#[br(
|
||||
little,
|
||||
import(packet_format: u16),
|
||||
)]
|
||||
pub struct F1PacketSessionData {
|
||||
/// Current weather.
|
||||
pub weather: Weather,
|
||||
/// Track temperature in degrees Celsius.
|
||||
pub track_temperature: i8,
|
||||
/// Air temperature in degrees Celsius.
|
||||
pub air_temperature: i8,
|
||||
/// Total number of laps in this session.
|
||||
pub total_laps: u8,
|
||||
/// Track's length in metres.
|
||||
pub track_length: u16,
|
||||
/// Session's type.
|
||||
pub session_type: SessionType,
|
||||
/// Unique identifier of the track.
|
||||
pub track_id: TrackId,
|
||||
/// Formula of cars being raced.
|
||||
pub formula: Formula,
|
||||
/// Time left in the session in seconds.
|
||||
pub session_time_left: u16,
|
||||
/// Session's duration in seconds.
|
||||
pub session_duration: u16,
|
||||
/// Pit lane's speed limit in kilometres per hour.
|
||||
pub pit_speed_limit: u8,
|
||||
/// Whether the game is paused.
|
||||
#[br(map(u8_to_bool))]
|
||||
pub game_paused: bool,
|
||||
/// Whether the player is spectating.
|
||||
#[br(map(u8_to_bool))]
|
||||
pub is_spectating: bool,
|
||||
/// Index of the car being spectated.
|
||||
#[br(map(u8_to_usize))]
|
||||
pub spectator_car_index: usize,
|
||||
/// Whether SLI Pro support is active.
|
||||
#[br(map(u8_to_bool))]
|
||||
pub sli_pro_native_support: bool,
|
||||
/// Number of marshal zones to follow.
|
||||
#[br(map(u8_to_usize))]
|
||||
pub num_marshal_zones: usize,
|
||||
/// List of up to 21 marshal zones.
|
||||
#[br(count(21), args{ inner: (packet_format,) })]
|
||||
pub marshal_zones: Vec<MarshalZone>,
|
||||
/// Safety car deployment status.
|
||||
pub safety_car_status: SafetyCarStatus,
|
||||
/// Whether this game is online.
|
||||
#[br(map(u8_to_bool))]
|
||||
pub network_game: bool,
|
||||
/// Number of weather samples to follow.
|
||||
#[br(map(u8_to_usize))]
|
||||
pub num_weather_forecast_samples: usize,
|
||||
/// List of up to 56 weather forecast samples.
|
||||
#[br(count(56), args{ inner: (packet_format,) })]
|
||||
pub weather_forecast_samples: Vec<WeatherForecastSample>,
|
||||
/// Weather forecast accuracy.
|
||||
pub forecast_accuracy: ForecastAccuracy,
|
||||
/// AI difficulty rating (0-110).
|
||||
pub ai_difficulty: u8,
|
||||
/// Identifier for season - persists across saves.
|
||||
pub season_link_identifier: u32,
|
||||
/// Identifier for weekend - persists across saves.
|
||||
pub weekend_link_identifier: u32,
|
||||
/// Identifier for session - persists across saves.
|
||||
pub session_link_identifier: u32,
|
||||
/// Ideal lap for the player to pit on for current strategy.
|
||||
pub pit_stop_window_ideal_lap: u8,
|
||||
/// The latest lap for the player to pit on for current strategy.
|
||||
pub pit_stop_window_latest_lap: u8,
|
||||
/// Predicted position for the player to rejoin at.
|
||||
pub pit_stop_rejoin_position: u8,
|
||||
/// Whether the steering assist is enabled.
|
||||
#[br(map(u8_to_bool))]
|
||||
pub steering_assist: bool,
|
||||
/// Type of braking assist enabled.
|
||||
pub braking_assist: BrakingAssist,
|
||||
/// Type of gearbox assist enabled.
|
||||
pub gearbox_assist: GearboxAssist,
|
||||
/// Whether the pit assist is enabled.
|
||||
#[br(map(u8_to_bool))]
|
||||
pub pit_assist: bool,
|
||||
/// Whether the pit release assist is enabled.
|
||||
#[br(map(u8_to_bool))]
|
||||
pub pit_release_assist: bool,
|
||||
/// Whether the ERS assist is enabled.
|
||||
#[br(map(u8_to_bool))]
|
||||
pub ers_assist: bool,
|
||||
/// Whether the DRS assist is enabled.
|
||||
#[br(map(u8_to_bool))]
|
||||
pub drs_assist: bool,
|
||||
/// Type of the dynamic racing line assist.
|
||||
pub dynamic_racing_line: DynamicRacingLine,
|
||||
/// Type of the dynamic racing line (2D/3D).
|
||||
pub dynamic_racing_line_type: DynamicRacingLineType,
|
||||
/// Game mode's identifier.
|
||||
pub game_mode: GameMode,
|
||||
/// Ruleset's identifier.
|
||||
pub ruleset: Ruleset,
|
||||
/// Session's length.
|
||||
pub session_length: SessionLength,
|
||||
}
|
||||
|
||||
/// Extended motion data for player's car. Available as a:
|
||||
/// - part of [`F1PacketMotionData`] in the 2022 format
|
||||
/// - standalone packet from the 2023 format onwards
|
||||
|
41
src/packets/session.rs
Normal file
41
src/packets/session.rs
Normal file
@ -0,0 +1,41 @@
|
||||
use crate::constants::{
|
||||
MarshalZoneFlag, SessionType, TemperatureChange, Weather,
|
||||
};
|
||||
use binrw::BinRead;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// Section of the track supervised by marshals.
|
||||
#[derive(
|
||||
BinRead, PartialEq, PartialOrd, Copy, Clone, Debug, Serialize, Deserialize,
|
||||
)]
|
||||
#[br(little, import(_packet_format: u16))]
|
||||
pub struct MarshalZone {
|
||||
/// Fraction (0..1) of way through the lap the marshal zone starts.
|
||||
pub zone_start: f32,
|
||||
/// Flag that's currently being waved in the marshal zone.
|
||||
pub zone_flag: MarshalZoneFlag,
|
||||
}
|
||||
|
||||
/// Weather forecast sample for a given session.
|
||||
#[derive(
|
||||
BinRead, PartialEq, PartialOrd, Copy, Clone, Debug, Serialize, Deserialize,
|
||||
)]
|
||||
#[br(little, import(_packet_format: u16))]
|
||||
pub struct WeatherForecastSample {
|
||||
/// Session's type.
|
||||
pub session_type: SessionType,
|
||||
/// Time in minutes the forecast is for.
|
||||
pub time_offset: u8,
|
||||
/// Forecasted weather.
|
||||
pub weather: Weather,
|
||||
/// Track temperature in degrees Celsius.
|
||||
pub track_temperature: i8,
|
||||
/// Track temperature change.
|
||||
pub track_temperature_change: TemperatureChange,
|
||||
/// Air temperature in degrees Celsius.
|
||||
pub air_temperature: i8,
|
||||
/// Air temperature change.
|
||||
pub air_temperature_change: TemperatureChange,
|
||||
/// Chance of rain.
|
||||
pub rain_percentage: u8,
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user