use crate::core::SharedMemoryReader;
use crate::datatypes::{Vector3f, Wheels};
use crate::enums::{
AccFlagType, AccPenaltyType, AccRainIntensity, AccSessionType, AccStatus, AccTrackGripStatus,
};
use crate::maps::GraphicsMap;
use crate::{ACCError, Result};
pub fn parse_graphics_map(reader: &SharedMemoryReader) -> Result<GraphicsMap> {
let mut _offset = 0;
macro_rules! read_value {
($type:ty) => {{
let value = reader.read_at::<$type>(_offset)?;
_offset += std::mem::size_of::<$type>();
value
}};
}
macro_rules! read_array {
($type:ty, $count:expr) => {{
let values = reader.read_array_at::<$type>(_offset, $count)?;
_offset += std::mem::size_of::<$type>() * $count;
values
}};
}
let read_string = |offset: &mut usize, char_count: usize, padding: usize| -> Result<String> {
let s = reader.read_utf16_string_at(*offset, char_count)?;
*offset += (char_count * 2) + padding;
Ok(s)
};
let try_enum_or_default = |value: i32| -> AccPenaltyType {
AccPenaltyType::try_from(value).unwrap_or(AccPenaltyType::Unknown)
};
let packet_id = read_value!(i32);
let status = AccStatus::try_from(read_value!(i32))
.map_err(|_| ACCError::InvalidData("Invalid ACC status".to_string()))?;
let session_type = AccSessionType::try_from(read_value!(i32))
.map_err(|_| ACCError::InvalidData("Invalid session type".to_string()))?;
let current_time_str = read_string(&mut _offset, 15, 0)?;
let last_time_str = read_string(&mut _offset, 15, 0)?;
let best_time_str = read_string(&mut _offset, 15, 0)?;
let last_sector_time_str = read_string(&mut _offset, 15, 0)?;
let completed_lap = read_value!(i32);
let position = read_value!(i32);
let current_time = read_value!(i32);
let last_time = read_value!(i32);
let best_time = read_value!(i32);
let session_time_left = read_value!(f32);
let distance_traveled = read_value!(f32);
let is_in_pit = read_value!(i32) != 0;
let current_sector_index = read_value!(i32);
let last_sector_time = read_value!(i32);
let number_of_laps = read_value!(i32);
let tyre_compound = read_string(&mut _offset, 33, 2)?;
let _replay_time_multiplier = read_value!(f32); let normalized_car_position = read_value!(f32);
let active_cars = read_value!(i32);
let mut car_coordinates = Vec::with_capacity(60);
for _ in 0..60 {
let coords = read_array!(f32, 3);
car_coordinates.push(Vector3f::new(coords[0], coords[1], coords[2]));
}
let car_id = read_array!(i32, 60);
let player_car_id = read_value!(i32);
let penalty_time = read_value!(f32);
let flag = AccFlagType::try_from(read_value!(i32))
.map_err(|_| ACCError::InvalidData("Invalid flag type".to_string()))?;
let penalty = try_enum_or_default(read_value!(i32));
let ideal_line_on = read_value!(i32) != 0;
let is_in_pit_lane = read_value!(i32) != 0;
let _surface_grip = read_value!(f32); let mandatory_pit_done = read_value!(i32) != 0;
let wind_speed = read_value!(f32);
let wind_direction = read_value!(f32);
let is_setup_menu_visible = read_value!(i32) != 0;
let main_display_index = read_value!(i32);
let secondary_display_index = read_value!(i32);
let tc_level = read_value!(i32);
let tc_cut_level = read_value!(i32);
let engine_map = read_value!(i32);
let abs_level = read_value!(i32);
let fuel_per_lap = read_value!(f32);
let rain_light = read_value!(i32) != 0;
let flashing_light = read_value!(i32) != 0;
let light_stage = read_value!(i32);
let exhaust_temp = read_value!(f32);
let wiper_stage = read_value!(i32);
let driver_stint_total_time_left = read_value!(i32);
let driver_stint_time_left = read_value!(i32);
let rain_tyres = read_value!(i32) != 0;
let session_index = read_value!(i32);
let used_fuel = read_value!(f32);
let delta_lap_time_str = read_string(&mut _offset, 15, 2)?;
let delta_lap_time = read_value!(i32);
let estimated_lap_time_str = read_string(&mut _offset, 15, 2)?;
let estimated_lap_time = read_value!(i32);
let is_delta_positive = read_value!(i32) != 0;
let _i_split = read_value!(i32); let is_valid_lap = read_value!(i32) != 0;
let fuel_estimated_laps = read_value!(f32);
let track_status = read_string(&mut _offset, 33, 2)?;
let missing_mandatory_pits = read_value!(i32);
let clock = read_value!(f32);
let direction_light_left = read_value!(i32) != 0;
let direction_light_right = read_value!(i32) != 0;
let global_yellow = read_value!(i32) != 0;
let global_yellow_s1 = read_value!(i32) != 0;
let global_yellow_s2 = read_value!(i32) != 0;
let global_yellow_s3 = read_value!(i32) != 0;
let global_white = read_value!(i32) != 0;
let global_green = read_value!(i32) != 0;
let global_chequered = read_value!(i32) != 0;
let global_red = read_value!(i32) != 0;
let mfd_tyre_set = read_value!(i32);
let mfd_fuel_to_add = read_value!(f32);
let mfd_tyre_pressure_fl = read_value!(f32);
let mfd_tyre_pressure_fr = read_value!(f32);
let mfd_tyre_pressure_rl = read_value!(f32);
let mfd_tyre_pressure_rr = read_value!(f32);
let mfd_tyre_pressure = Wheels::new(
mfd_tyre_pressure_fl,
mfd_tyre_pressure_fr,
mfd_tyre_pressure_rl,
mfd_tyre_pressure_rr,
);
let track_grip_status = AccTrackGripStatus::try_from(read_value!(i32))
.map_err(|_| ACCError::InvalidData("Invalid track grip status".to_string()))?;
let rain_intensity = AccRainIntensity::try_from(read_value!(i32))
.map_err(|_| ACCError::InvalidData("Invalid rain intensity".to_string()))?;
let rain_intensity_in_10min = AccRainIntensity::try_from(read_value!(i32))
.map_err(|_| ACCError::InvalidData("Invalid rain intensity (10min)".to_string()))?;
let rain_intensity_in_30min = AccRainIntensity::try_from(read_value!(i32))
.map_err(|_| ACCError::InvalidData("Invalid rain intensity (30min)".to_string()))?;
let current_tyre_set = read_value!(i32);
let strategy_tyre_set = read_value!(i32);
let gap_ahead = read_value!(i32);
let gap_behind = read_value!(i32);
Ok(GraphicsMap {
packet_id,
status,
session_type,
session_index,
current_time_str,
last_time_str,
best_time_str,
last_sector_time_str,
completed_lap,
position,
current_time,
last_time,
best_time,
last_sector_time,
number_of_laps,
delta_lap_time_str,
estimated_lap_time_str,
delta_lap_time,
estimated_lap_time,
is_delta_positive,
is_valid_lap,
fuel_estimated_laps,
distance_traveled,
normalized_car_position,
session_time_left,
current_sector_index,
is_in_pit,
is_in_pit_lane,
ideal_line_on,
mandatory_pit_done,
missing_mandatory_pits,
penalty_time,
penalty,
flag,
car_coordinates,
car_id,
player_car_id,
active_cars,
wind_speed,
wind_direction,
rain_intensity,
rain_intensity_in_10min,
rain_intensity_in_30min,
track_grip_status,
track_status,
clock,
tc_level,
tc_cut_level,
engine_map,
abs_level,
wiper_stage,
driver_stint_total_time_left,
driver_stint_time_left,
rain_tyres,
rain_light,
flashing_light,
light_stage,
direction_light_left,
direction_light_right,
tyre_compound,
is_setup_menu_visible,
main_display_index,
secondary_display_index,
fuel_per_lap,
used_fuel,
exhaust_temp,
gap_ahead,
gap_behind,
global_yellow,
global_yellow_s1,
global_yellow_s2,
global_yellow_s3,
global_white,
global_green,
global_chequered,
global_red,
mfd_tyre_set,
mfd_fuel_to_add,
mfd_tyre_pressure,
current_tyre_set,
strategy_tyre_set,
})
}