88 lines
3.0 KiB
Rust

pub mod constants;
pub mod packets;
use crate::constants::PacketId;
use crate::packets::{F1PacketEventData, F1PacketLapData, F1PacketMotionData, F1PacketParticipantsData, F1PacketSessionData};
use binrw::io::Cursor;
use binrw::{BinRead, BinReaderExt, BinResult};
use serde::{Deserialize, Serialize};
/// Attempts to extract game packet data from a slice of bytes.
/// See [`binrw::Error`] for possible error variants.
pub fn parse(data: &[u8]) -> BinResult<F1Packet> {
let mut cursor = Cursor::new(data);
let header: F1PacketHeader = cursor.read_le()?;
let body: F1PacketBody =
cursor.read_le_args((header.packet_format, header.packet_id))?;
Ok(F1Packet { header, body })
}
#[derive(PartialEq, PartialOrd, Clone, Debug, Serialize, Deserialize)]
pub struct F1Packet {
pub header: F1PacketHeader,
pub body: F1PacketBody,
}
/// F1 game packet's header.
#[non_exhaustive]
#[derive(
BinRead, PartialEq, PartialOrd, Clone, Debug, Serialize, Deserialize,
)]
#[br(
little,
assert(
(2022..=2024).contains(&packet_format),
"Invalid or unsupported packet format: {}",
packet_format
)
)]
pub struct F1PacketHeader {
/// Value of the "UDP Format" option in the game's telemetry settings.
pub packet_format: u16,
/// Game's major version - "X.00".
pub game_major_version: u8,
/// Game's minor version - "1.XX".
pub game_minor_version: u8,
/// Version of this packet type, all start from 1.
pub packet_version: u8,
/// Identifier for the packet type.
pub packet_id: PacketId,
/// Unique identifier for the session.
pub session_uid: u64,
/// Session timestamp.
pub session_time: f32,
/// Identifier for the frame the data was retrieved on.
pub frame_identifier: u32,
/// Index of player's car in the array.
pub player_car_index: u8,
/// Index of secondary player's car in the array in splitscreen mode.
/// Set to 255 if not in splitscreen mode.
pub secondary_player_car_index: u8,
}
/// F1 game packet's body.
#[non_exhaustive]
#[derive(
BinRead, PartialEq, PartialOrd, Clone, Debug, Serialize, Deserialize,
)]
#[br(little, import(packet_format: u16, packet_id: PacketId))]
pub struct F1PacketBody {
/// Physics data for all the cars being driven.
#[br(if(packet_id == PacketId::Motion), args(packet_format))]
pub motion: Option<F1PacketMotionData>,
/// 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>,
/// List of participants in the race.
#[br(if(packet_id == PacketId::Participants), args(packet_format))]
pub participants: Option<F1PacketParticipantsData>,
}