feat: add 2022 spec motion packet parser

This commit is contained in:
Maciej Pędzich 2025-02-17 13:21:30 +01:00
parent cdcf1c4961
commit 4b304fbd4e
Signed by: maciejpedzich
GPG Key ID: CE4A303D84882F0D
6 changed files with 219 additions and 0 deletions

8
.idea/.gitignore generated vendored Normal file
View File

@ -0,0 +1,8 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

6
rustfmt.toml Normal file
View File

@ -0,0 +1,6 @@
max_width = 80
format_code_in_doc_comments = true
imports_granularity = "Crate"
imports_layout = "Vertical"
use_small_heuristics = "Max"
wrap_comments = true

36
src/constants/mod.rs Normal file
View File

@ -0,0 +1,36 @@
pub mod wheel_index;
use binrw::BinRead;
use serde::{Deserialize, Serialize};
#[non_exhaustive]
#[derive(
BinRead,
Eq,
PartialEq,
Ord,
PartialOrd,
Copy,
Clone,
Debug,
Serialize,
Deserialize,
)]
#[br(little, repr(u8))]
pub enum PacketId {
Motion = 0,
Session = 1,
LapData = 2,
Event = 3,
Participants = 4,
CarSetups = 5,
CarTelemetry = 6,
CarStatus = 7,
FinalClassification = 8,
LobbyInfo = 9,
CarDamage = 10,
SessionHistory = 11,
TyreSets = 12,
MotionEx = 13,
TimeTrial = 14,
}

View File

@ -0,0 +1,4 @@
pub const REAR_LEFT: usize = 0;
pub const REAR_RIGHT: usize = 1;
pub const FRONT_LEFT: usize = 2;
pub const FRONT_RIGHT: usize = 3;

88
src/packets/mod.rs Normal file
View File

@ -0,0 +1,88 @@
pub mod motion;
use crate::packets::motion::CarMotionData;
use binrw::BinRead;
use serde::{Deserialize, Serialize};
use std::string::FromUtf8Error;
/// Physics data for all the cars being driven.
#[non_exhaustive]
#[derive(
BinRead, PartialEq, PartialOrd, Clone, Debug, Serialize, Deserialize,
)]
#[br(little, import(packet_format: u16))]
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).
#[br(if(packet_format == 2022))]
pub motion_ex_data: Option<F1PacketMotionExData>,
}
/// Extended motion data for player's car. Available as a:
/// - part of [`F1PacketMotionData`] in the 2022 format
/// - standalone packet from the 2023 format onwards
#[non_exhaustive]
#[derive(
BinRead, PartialEq, PartialOrd, Copy, Clone, Debug, Serialize, Deserialize,
)]
#[br(little, import(_packet_format: u16))]
pub struct F1PacketMotionExData {
/// Positions of suspension for each wheel.
/// See [`wheel_index`](mod@crate::constants::wheel_index)
/// for wheel order.
pub suspension_position: [f32; 4],
/// Velocities of suspension.
/// See [`wheel_index`](mod@crate::constants::wheel_index)
/// for wheel order.
pub suspension_velocity: [f32; 4],
/// Accelerations of suspension in the following order:
/// See [`wheel_index`](mod@crate::constants::wheel_index)
/// for wheel order.
pub suspension_acceleration: [f32; 4],
/// Speed of each wheel in the following order:
/// See [`wheel_index`](mod@crate::constants::wheel_index)
/// for wheel order.
pub wheel_speed: [f32; 4],
/// Slip ratio of each wheel in the following order:
/// See [`wheel_index`](mod@crate::constants::wheel_index)
/// for wheel order.
pub wheel_slip: [f32; 4],
/// X velocity in local space.
pub local_velocity_x: f32,
/// Y velocity in local space.
pub local_velocity_y: f32,
/// Z velocity in local space.
pub local_velocity_z: f32,
/// Angular velocity X component.
pub angular_velocity_x: f32,
/// Angular velocity Y component.
pub angular_velocity_y: f32,
/// Angular velocity Z component.
pub angular_velocity_z: f32,
/// Angular acceleration X component.
pub angular_acceleration_x: f32,
/// Angular acceleration Y component.
pub angular_acceleration_y: f32,
/// Angular acceleration Z component.
pub angular_acceleration_z: f32,
/// Current front wheels angle in radians.
pub front_wheels_angle: f32,
}
pub(crate) fn u8_to_bool(value: u8) -> bool {
value == 1
}
pub(crate) fn u8_to_usize(value: u8) -> usize {
value as usize
}
pub(crate) fn read_name(bytes: [u8; 48]) -> Result<String, FromUtf8Error> {
let first_nul_index =
bytes.iter().position(|&byte| byte == b'\0').unwrap_or(bytes.len());
String::from_utf8(bytes[..first_nul_index].to_vec())
}

77
src/packets/motion.rs Normal file
View File

@ -0,0 +1,77 @@
use binrw::BinRead;
use serde::{Deserialize, Serialize};
#[derive(
BinRead, PartialEq, PartialOrd, Copy, Clone, Debug, Serialize, Deserialize,
)]
#[br(little)]
pub struct CarMotionData {
/// World space X position in metres
pub world_position_x: f32,
/// World space Y position in metres
pub world_position_y: f32,
/// World space Z position in metres
pub world_position_z: f32,
/// Velocity in world space X position
pub world_velocity_x: f32,
/// Velocity in world space Y position
pub world_velocity_y: f32,
/// Velocity in world space Z position
pub world_velocity_z: f32,
/// World space forward X direction (normalised)
pub world_forward_dir_x: i16,
/// World space forward Y direction (normalised)
pub world_forward_dir_y: i16,
/// World space forward Z direction (normalised)
pub world_forward_dir_z: i16,
/// World space right X direction (normalised)
pub world_right_dir_x: i16,
/// World space right Y direction (normalised)
pub world_right_dir_y: i16,
/// World space right Z direction (normalised)
pub world_right_dir_z: i16,
/// Lateral G-Force component
pub g_force_lateral: f32,
/// Longitudinal G-Force component
pub g_force_longitudinal: f32,
/// Vertical G-Force component
pub g_force_vertical: f32,
/// Yaw angle in radians
pub yaw: f32,
/// Pitch angle in radians
pub pitch: f32,
/// Roll angle in radians
pub roll: f32,
}
impl CarMotionData {
/// Returns [`self.world_forward_dir_x`] divided by `32767.0f32`
pub fn world_forward_dir_x_as_f32(&self) -> f32 {
self.world_forward_dir_x as f32 / 32767.0
}
/// Returns [`self.world_forward_dir_y`] divided by `32767.0f32`
pub fn world_forward_dir_y_as_f32(&self) -> f32 {
self.world_forward_dir_y as f32 / 32767.0
}
/// Returns [`self.world_forward_dir_z`] divided by `32767.0f32`
pub fn world_forward_dir_z_as_f32(&self) -> f32 {
self.world_forward_dir_z as f32 / 32767.0
}
/// Returns [`self.world_right_dir_x`] divided by `32767.0f32`
pub fn world_right_dir_x_as_f32(&self) -> f32 {
self.world_right_dir_x as f32 / 32767.0
}
/// Returns [`self.world_right_dir_y`] divided by `32767.0f32`
pub fn world_right_dir_y_as_f32(&self) -> f32 {
self.world_right_dir_y as f32 / 32767.0
}
/// Returns [`self.world_right_dir_z`] divided by `32767.0f32`
pub fn world_right_dir_z_as_f32(&self) -> f32 {
self.world_right_dir_z as f32 / 32767.0
}
}