mirror of
https://github.com/maciejpedzich/f1-game-packet-parser.git
synced 2025-04-16 18:11:11 +02:00
feat: add 2022 spec event event packet parser
This commit is contained in:
parent
fb83776da5
commit
e4728bcf45
7
Cargo.lock
generated
7
Cargo.lock
generated
@ -32,6 +32,12 @@ dependencies = [
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36"
|
||||
|
||||
[[package]]
|
||||
name = "bytemuck"
|
||||
version = "1.21.0"
|
||||
@ -49,6 +55,7 @@ name = "f1-game-packet-parser"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"binrw",
|
||||
"bitflags",
|
||||
"serde",
|
||||
]
|
||||
|
||||
|
@ -5,4 +5,5 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
binrw = "0.14"
|
||||
bitflags = "2.8"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
|
@ -1,6 +1,7 @@
|
||||
pub mod wheel_index;
|
||||
|
||||
use binrw::BinRead;
|
||||
use bitflags::bitflags;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
pub(crate) const MAX_NUM_CARS: usize = 22;
|
||||
@ -414,6 +415,7 @@ pub enum SessionLength {
|
||||
Full = 7,
|
||||
}
|
||||
|
||||
#[non_exhaustive]
|
||||
#[derive(
|
||||
BinRead,
|
||||
Eq,
|
||||
@ -433,6 +435,7 @@ pub enum PitStatus {
|
||||
InPitArea = 2,
|
||||
}
|
||||
|
||||
#[non_exhaustive]
|
||||
#[derive(
|
||||
BinRead,
|
||||
Eq,
|
||||
@ -454,6 +457,7 @@ pub enum DriverStatus {
|
||||
OnTrack = 4,
|
||||
}
|
||||
|
||||
#[non_exhaustive]
|
||||
#[derive(
|
||||
BinRead,
|
||||
Eq,
|
||||
@ -477,3 +481,200 @@ pub enum ResultStatus {
|
||||
NotClassified = 6,
|
||||
Retired = 7,
|
||||
}
|
||||
|
||||
#[non_exhaustive]
|
||||
#[derive(
|
||||
BinRead,
|
||||
Eq,
|
||||
PartialEq,
|
||||
Ord,
|
||||
PartialOrd,
|
||||
Copy,
|
||||
Clone,
|
||||
Debug,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
)]
|
||||
#[br(little, repr(u8))]
|
||||
pub enum PenaltyType {
|
||||
DriveThrough = 0,
|
||||
StopGo = 1,
|
||||
GridPenalty = 2,
|
||||
PenaltyReminder = 3,
|
||||
TimePenalty = 4,
|
||||
Warning = 5,
|
||||
Disqualified = 6,
|
||||
RemovedFromFormationLap = 7,
|
||||
ParkedTooLongTimer = 8,
|
||||
TyreRegulations = 9,
|
||||
ThisLapInvalidated = 10,
|
||||
ThisAndNextLapInvalidated = 11,
|
||||
ThisLapInvalidatedWithoutReason = 12,
|
||||
ThisAndNextLapInvalidatedWithoutReason = 13,
|
||||
ThisAndPreviousLapInvalidated = 14,
|
||||
ThisAndPreviousLapInvalidatedWithoutReason = 15,
|
||||
Retired = 16,
|
||||
BlackFlagTimer = 17,
|
||||
}
|
||||
|
||||
#[non_exhaustive]
|
||||
#[derive(
|
||||
BinRead,
|
||||
Eq,
|
||||
PartialEq,
|
||||
Ord,
|
||||
PartialOrd,
|
||||
Copy,
|
||||
Clone,
|
||||
Debug,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
)]
|
||||
#[br(little, repr(u8))]
|
||||
pub enum InfringementType {
|
||||
BlockingBySlowDriving = 0,
|
||||
BlockingByWrongWayDriving = 1,
|
||||
ReversingOffTheStartLine = 2,
|
||||
BigCollision = 3,
|
||||
SmallCollision = 4,
|
||||
CollisionFailedToHandBackPositionSingle = 5,
|
||||
CollisionFailedToHandBackPositionMultiple = 6,
|
||||
CornerCuttingGainedTime = 7,
|
||||
CornerCuttingOvertakeSingle = 8,
|
||||
CornerCuttingOvertakeMultiple = 9,
|
||||
CrossedPitExitLane = 10,
|
||||
IgnoringBlueFlags = 11,
|
||||
IgnoringYellowFlags = 12,
|
||||
IgnoringDriveThrough = 13,
|
||||
TooManyDriveThroughs = 14,
|
||||
DriveThroughReminderServeWithinNLaps = 15,
|
||||
DriveThroughReminderServeThisLap = 16,
|
||||
PitLaneSpeeding = 17,
|
||||
ParkedForTooLong = 18,
|
||||
IgnoringTyreRegulations = 19,
|
||||
TooManyPenalties = 20,
|
||||
MultipleWarnings = 21,
|
||||
ApproachingDisqualification = 22,
|
||||
TyreRegulationsSelectSingle = 23,
|
||||
TyreRegulationsSelectMultiple = 24,
|
||||
LapInvalidatedCornerCutting = 25,
|
||||
LapInvalidatedRunningWide = 26,
|
||||
CornerCuttingRanWideMinorTimeGain = 27,
|
||||
CornerCuttingRanWideSignificantTimeGain = 28,
|
||||
CornerCuttingRanWideExtremeTimeGain = 29,
|
||||
LapInvalidatedWallRiding = 30,
|
||||
LapInvalidatedFlashbackUsed = 31,
|
||||
LapInvalidatedResetToTrack = 32,
|
||||
BlockingThePitLane = 33,
|
||||
JumpStart = 34,
|
||||
SafetyCarCollision = 35,
|
||||
SafetyCarIllegalOvertake = 36,
|
||||
SafetyCarExceedingAllowedPace = 37,
|
||||
VirtualSafetyCarExceedingAllowedPace = 38,
|
||||
FormationLapBelowAllowedSpeed = 39,
|
||||
RetiredMechanicalFailure = 40,
|
||||
RetiredTerminallyDamaged = 41,
|
||||
SafetyCarFallingTooFarBack = 42,
|
||||
BlackFlagTimer = 43,
|
||||
UnservedStopGoPenalty = 44,
|
||||
UnservedDriveThroughPenalty = 45,
|
||||
EngineComponentChange = 46,
|
||||
GearboxChange = 47,
|
||||
LeagueGridPenalty = 48,
|
||||
RetryPenalty = 49,
|
||||
IllegalTimeGain = 50,
|
||||
MandatoryPitStop = 51,
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
Clone,
|
||||
Copy,
|
||||
PartialEq,
|
||||
Eq,
|
||||
Ord,
|
||||
PartialOrd,
|
||||
Hash,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
)]
|
||||
pub struct ButtonStatus(u32);
|
||||
|
||||
bitflags! {
|
||||
impl ButtonStatus: u32 {
|
||||
/// The "A" button on an Xbox controller
|
||||
/// or the cross button on a PlayStation controller.
|
||||
/// Has a value of `0x00000001`.
|
||||
const A_OR_CROSS = 0x00000001;
|
||||
/// The "Y" button on an Xbox controller
|
||||
/// or the triangle button on a PlayStation controller.
|
||||
/// Has a value of `0x00000002`.
|
||||
const Y_OR_TRIANGLE = 0x00000002;
|
||||
/// The "B" button on an Xbox controller
|
||||
/// or the circle button on a PlayStation controller.
|
||||
/// Has a value of `0x00000004`.
|
||||
const B_OR_CIRCLE = 0x00000004;
|
||||
/// The "X" button on an Xbox controller
|
||||
/// or the square button on a PlayStation controller.
|
||||
/// Has a value of `0x00000008`.
|
||||
const X_OR_SQUARE = 0x00000008;
|
||||
/// Left directional pad button. Has a value of `0x00000010`.
|
||||
const DPAD_LEFT = 0x00000010;
|
||||
/// Right directional pad button. Has a value of `0x00000020`.
|
||||
const DPAD_RIGHT = 0x00000020;
|
||||
/// Up directional pad button. Has a value of `0x00000040`.
|
||||
const DPAD_UP = 0x00000040;
|
||||
/// Down directional pad button. Has a value of `0x00000080`.
|
||||
const DPAD_DOWN = 0x00000080;
|
||||
/// The "Menu" button on an Xbox controller
|
||||
/// or the "Options" button on a PlayStation controller.
|
||||
/// Has a value of `0x00000100`.
|
||||
const MENU_OR_OPTIONS = 0x00000100;
|
||||
/// Left bumper. Has a value of `0x00000200`.
|
||||
const LEFT_BUMPER = 0x00000200;
|
||||
/// Right bumper. Has a value of `0x00000400`.
|
||||
const RIGHT_BUMPER = 0x00000400;
|
||||
/// Left trigger. Has a value of `0x00000800`.
|
||||
const LEFT_TRIGGER = 0x00000800;
|
||||
/// Right trigger. Has a value of `0x00001000`.
|
||||
const RIGHT_TRIGGER = 0x00001000;
|
||||
/// Left analog stick click. Has a value of `0x00002000`.
|
||||
const LEFT_STICK_CLICK = 0x00002000;
|
||||
/// Right analog stick click. Has a value of `0x00004000`.
|
||||
const RIGHT_STICK_CLICK = 0x00004000;
|
||||
/// Right analog stick left. Has a value of `0x00008000`.
|
||||
const RIGHT_STICK_LEFT = 0x00008000;
|
||||
/// Right analog stick right. Has a value of `0x00010000`
|
||||
const RIGHT_STICK_RIGHT = 0x00010000;
|
||||
/// Right analog stick up. Has a value of `0x00020000`
|
||||
const RIGHT_STICK_UP = 0x00020000;
|
||||
/// Right analog stick down. Has a value of `0x00040000`
|
||||
const RIGHT_STICK_DOWN = 0x00040000;
|
||||
/// Special button. Has a value of `0x00080000`.
|
||||
const SPECIAL = 0x00080000;
|
||||
/// UDP Action 1. Has a value of `0x00100000`.
|
||||
const UDP_ACTION_1 = 0x00100000;
|
||||
/// UDP Action 2. Has a value of `0x00200000`.
|
||||
const UDP_ACTION_2 = 0x00200000;
|
||||
/// UDP Action 3. Has a value of `0x00400000`.
|
||||
const UDP_ACTION_3 = 0x00400000;
|
||||
/// UDP Action 4. Has a value of `0x00800000`.
|
||||
const UDP_ACTION_4 = 0x00800000;
|
||||
/// UDP Action 5. Has a value of `0x01000000`.
|
||||
const UDP_ACTION_5 = 0x01000000;
|
||||
/// UDP Action 6. Has a value of `0x02000000`.
|
||||
const UDP_ACTION_6 = 0x02000000;
|
||||
/// UDP Action 7. Has a value of `0x04000000`.
|
||||
const UDP_ACTION_7 = 0x04000000;
|
||||
/// UDP Action 8. Has a value of `0x08000000`.
|
||||
const UDP_ACTION_8 = 0x08000000;
|
||||
/// UDP Action 9. Has a value of `0x10000000`.
|
||||
const UDP_ACTION_9 = 0x10000000;
|
||||
/// UDP Action 10. Has a value of `0x20000000`.
|
||||
const UDP_ACTION_10 = 0x20000000;
|
||||
/// UDP Action 11. Has a value of `0x40000000`.
|
||||
const UDP_ACTION_11 = 0x40000000;
|
||||
/// UDP Action 12. Has a value of `0x80000000`.
|
||||
const UDP_ACTION_12 = 0x80000000;
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ pub mod constants;
|
||||
pub mod packets;
|
||||
|
||||
use crate::constants::PacketId;
|
||||
use crate::packets::{F1PacketMotionData, F1PacketSessionData};
|
||||
use crate::packets::{F1PacketEventData, F1PacketLapData, F1PacketMotionData, F1PacketSessionData};
|
||||
|
||||
use binrw::io::Cursor;
|
||||
use binrw::{BinRead, BinReaderExt, BinResult};
|
||||
@ -75,4 +75,10 @@ pub struct F1PacketBody {
|
||||
/// Data about the ongoing session.
|
||||
#[br(if(packet_id == PacketId::Session), args(packet_format))]
|
||||
pub session: Option<F1PacketSessionData>,
|
||||
/// Lap data for all cars on track.
|
||||
#[br(if(packet_id == PacketId::LapData), args(packet_format))]
|
||||
pub lap: Option<F1PacketLapData>,
|
||||
/// Details of events that happen during the course of a session.
|
||||
#[br(if(packet_id == PacketId::Event), args(packet_format))]
|
||||
pub event: Option<F1PacketEventData>,
|
||||
}
|
||||
|
125
src/packets/event.rs
Normal file
125
src/packets/event.rs
Normal file
@ -0,0 +1,125 @@
|
||||
use super::u8_to_usize;
|
||||
use crate::constants::{ButtonStatus, InfringementType, PenaltyType};
|
||||
|
||||
use binrw::BinRead;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[non_exhaustive]
|
||||
#[derive(
|
||||
BinRead, PartialEq, PartialOrd, Clone, Debug, Serialize, Deserialize,
|
||||
)]
|
||||
#[br(little)]
|
||||
pub enum EventDataDetails {
|
||||
/// Sent when the session starts.
|
||||
#[br(magic = b"SSTA")]
|
||||
SessionStarted,
|
||||
/// Sent when the session ends.
|
||||
#[br(magic = b"SEND")]
|
||||
SessionEnded,
|
||||
/// Sent when a driver achieves the fastest lap.
|
||||
#[br(magic = b"FTLP")]
|
||||
FastestLap {
|
||||
/// Index of the car that's achieved the fastest lap.
|
||||
#[br(map(u8_to_usize))]
|
||||
vehicle_index: usize,
|
||||
/// Lap time in seconds.
|
||||
lap_time: f32,
|
||||
},
|
||||
/// Sent when a driver retires.
|
||||
#[br(magic = b"RTMT")]
|
||||
Retirement {
|
||||
/// Index of the retiring car.
|
||||
#[br(map(u8_to_usize))]
|
||||
vehicle_index: usize,
|
||||
},
|
||||
/// Sent when race control enable DRS.
|
||||
#[br(magic = b"DRSE")]
|
||||
DrsEnabled,
|
||||
/// Sent when race control disable DRS.
|
||||
#[br(magic = b"DRSD")]
|
||||
DrsDisabled,
|
||||
/// Sent when your teammate enters the pit lane.
|
||||
#[br(magic = b"TMPT")]
|
||||
TeamMateInPits {
|
||||
/// Index of teammate's car.
|
||||
#[br(map(u8_to_usize))]
|
||||
vehicle_index: usize,
|
||||
},
|
||||
/// Sent when the chequered flag has been waved.
|
||||
#[br(magic = b"CHQF")]
|
||||
ChequeredFlag,
|
||||
/// Sent when the race winner is announced.
|
||||
#[br(magic = b"RCWN")]
|
||||
RaceWinner {
|
||||
/// Index of race winner's car.
|
||||
#[br(map(u8_to_usize))]
|
||||
vehicle_index: usize,
|
||||
},
|
||||
/// Sent when a penalty has been issued.
|
||||
#[br(magic = b"PENA")]
|
||||
Penalty {
|
||||
/// Penalty type.
|
||||
penalty_type: PenaltyType,
|
||||
/// Infringement type.
|
||||
infringement_type: InfringementType,
|
||||
/// Index of the car the penalty is applied to.
|
||||
#[br(map(u8_to_usize))]
|
||||
vehicle_index: usize,
|
||||
/// Index of the other car involved.
|
||||
#[br(map(u8_to_usize))]
|
||||
other_vehicle_index: usize,
|
||||
/// Time gained/spent doing the action in seconds.
|
||||
time: u8,
|
||||
/// Number of the lap the infringement occurred on.
|
||||
lap_num: u8,
|
||||
/// Number of places gained by this infringement.
|
||||
places_gained: u8,
|
||||
},
|
||||
/// Sent when a speed trap is triggered.
|
||||
#[br(magic = b"SPTP")]
|
||||
SpeedTrap {
|
||||
/// Index of the car that's triggered the speed trap.
|
||||
#[br(map(u8_to_usize))]
|
||||
vehicle_index: usize,
|
||||
/// Top speed achieved in kilometres per hour.
|
||||
speed: f32,
|
||||
},
|
||||
/// Sent when a start light is lit.
|
||||
#[br(magic = b"STLG")]
|
||||
StartLights {
|
||||
/// Number of lights showing.
|
||||
num_lights: u8,
|
||||
},
|
||||
/// "It's lights out, and away we go!"
|
||||
#[br(magic = b"LGOT")]
|
||||
LightsOut,
|
||||
/// Sent when a driver has served a drive-through penalty.
|
||||
#[br(magic = b"DTSV")]
|
||||
DriveThroughServed {
|
||||
/// Index of the vehicle serving the penalty.
|
||||
#[br(map(u8_to_usize))]
|
||||
vehicle_index: usize,
|
||||
},
|
||||
/// Sent when a driver has served a stop-go penalty.
|
||||
#[br(magic = b"SGSV")]
|
||||
StopGoServed {
|
||||
/// Index of the vehicle serving the penalty.
|
||||
#[br(map(u8_to_usize))]
|
||||
vehicle_index: usize,
|
||||
},
|
||||
/// Sent when a flashback is activated.
|
||||
#[br(magic = b"FLBK")]
|
||||
Flashback {
|
||||
/// Frame identifier that's been flashed back to.
|
||||
frame_identifier: u32,
|
||||
/// Session time that's been flashed back to.
|
||||
flashback_session_time: f32,
|
||||
},
|
||||
/// Sent when the button status has changed.
|
||||
#[br(magic = b"BUTN")]
|
||||
Buttons {
|
||||
/// Bit flags specifying which buttons are currently pressed.
|
||||
#[br(map(|bits: u32| ButtonStatus::from_bits_truncate(bits)))]
|
||||
button_status: ButtonStatus
|
||||
},
|
||||
}
|
@ -1,8 +1,7 @@
|
||||
pub mod motion;
|
||||
pub mod session;
|
||||
pub mod lap_data;
|
||||
|
||||
use crate::packets::motion::CarMotionData;
|
||||
pub mod event;
|
||||
|
||||
use crate::constants::{
|
||||
BrakingAssist, DynamicRacingLine,
|
||||
@ -11,9 +10,11 @@ use crate::constants::{
|
||||
TrackId, Weather, MAX_AI_DIFFICULTY, MAX_NUM_CARS, MAX_NUM_MARSHAL_ZONES,
|
||||
MAX_NUM_WEATHER_FORECAST_SAMPLES,
|
||||
};
|
||||
use crate::packets::event::EventDataDetails;
|
||||
use crate::packets::lap_data::LapData;
|
||||
use crate::packets::motion::CarMotionData;
|
||||
use crate::packets::session::{MarshalZone, WeatherForecastSample};
|
||||
|
||||
use crate::packets::lap_data::LapData;
|
||||
use binrw::BinRead;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::string::FromUtf8Error;
|
||||
@ -180,6 +181,23 @@ pub struct F1PacketLapData {
|
||||
pub time_trial_rival_car_index: usize,
|
||||
}
|
||||
|
||||
/// Various notable events that happen during a session.
|
||||
#[non_exhaustive]
|
||||
#[derive(
|
||||
BinRead, PartialEq, PartialOrd, Clone, Debug, Serialize, Deserialize,
|
||||
)]
|
||||
#[br(little, import(_packet_format: u16))]
|
||||
pub struct F1PacketEventData {
|
||||
/// 4-letter event code.
|
||||
#[br(
|
||||
try_map(|bytes: [u8; 4]| String::from_utf8(bytes.to_vec())),
|
||||
restore_position
|
||||
)]
|
||||
pub event_string_code: String,
|
||||
/// Extra data for this event.
|
||||
pub event_details: EventDataDetails,
|
||||
}
|
||||
|
||||
/// 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