simetry 0.2.3

Interface with telemetry of various racing and driving sims
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
use crate::assetto_corsa_competizione::data::{Aids, CarDamage, GlobalFlags, Vector3, Wheels};
use crate::assetto_corsa_competizione::shared_memory_data::{
    FlagTypeRaw, PageFileGraphics, PageFilePhysics, PageFileStatic, PenaltyRaw, RainIntensityRaw,
    SessionTypeRaw, StatusRaw, TrackGripStatusRaw,
};
use crate::assetto_corsa_competizione::{
    FlagType, Graphics, LapTiming, MfdPitstop, Penalty, Physics, RainIntensity, SessionType,
    StaticData, Status, Time, TrackGripStatus, WheelInfo,
};

pub fn extract_string(data: &[u16]) -> String {
    let length = data.iter().position(|v| *v == 0).unwrap_or(data.len());
    String::from_utf16(&data[0..length]).unwrap_or_default()
}

impl From<PenaltyRaw> for Penalty {
    fn from(v: PenaltyRaw) -> Self {
        match v.data {
            0 => Penalty::None,
            1 => Penalty::DriveThroughCutting,
            2 => Penalty::StopAndGo10Cutting,
            3 => Penalty::StopAndGo20Cutting,
            4 => Penalty::StopAndGo30Cutting,
            5 => Penalty::DisqualifiedCutting,
            6 => Penalty::RemoveBestLaptimeCutting,
            7 => Penalty::DriveThroughPitSpeeding,
            8 => Penalty::StopAndGo10PitSpeeding,
            9 => Penalty::StopAndGo20PitSpeeding,
            10 => Penalty::StopAndGo30PitSpeeding,
            11 => Penalty::DisqualifiedPitSpeeding,
            12 => Penalty::RemoveBestLaptimePitSpeeding,
            13 => Penalty::DisqualifiedIgnoredMandatoryPit,
            14 => Penalty::PostRaceTime,
            15 => Penalty::DisqualifiedTrolling,
            16 => Penalty::DisqualifiedPitEntry,
            17 => Penalty::DisqualifiedPitExit,
            18 => Penalty::DisqualifiedWrongWay,
            19 => Penalty::DriveThroughIgnoredDriverStint,
            20 => Penalty::DisqualifiedIgnoredDriverStint,
            21 => Penalty::DisqualifiedExceededDriverStintLimit,
            _ => Penalty::None,
        }
    }
}

impl From<StatusRaw> for Status {
    fn from(v: StatusRaw) -> Self {
        match v.data {
            0 => Status::Off,
            1 => Status::Replay,
            2 => Status::Live,
            3 => Status::Pause,
            _ => Status::Off,
        }
    }
}

impl From<SessionTypeRaw> for SessionType {
    fn from(v: SessionTypeRaw) -> Self {
        match v.data {
            0 => SessionType::Practice,
            1 => SessionType::Qualify,
            2 => SessionType::Race,
            3 => SessionType::Hotlap,
            4 => SessionType::TimeAttack,
            5 => SessionType::Drift,
            6 => SessionType::Drag,
            7 => SessionType::HotStint,
            8 => SessionType::HotlapSuperPole,
            _ => SessionType::Unknown,
        }
    }
}

impl From<TrackGripStatusRaw> for TrackGripStatus {
    fn from(v: TrackGripStatusRaw) -> Self {
        match v.data {
            0 => TrackGripStatus::Green,
            1 => TrackGripStatus::Fast,
            2 => TrackGripStatus::Optimum,
            3 => TrackGripStatus::Greasy,
            4 => TrackGripStatus::Damp,
            5 => TrackGripStatus::Wet,
            6 => TrackGripStatus::Flooded,
            _ => TrackGripStatus::Green,
        }
    }
}

impl From<RainIntensityRaw> for RainIntensity {
    fn from(v: RainIntensityRaw) -> Self {
        match v.data {
            0 => RainIntensity::NoRain,
            1 => RainIntensity::Drizzle,
            2 => RainIntensity::LightRain,
            3 => RainIntensity::MediumRain,
            4 => RainIntensity::HeavyRain,
            5 => RainIntensity::Thunderstorm,
            _ => RainIntensity::NoRain,
        }
    }
}

impl From<FlagTypeRaw> for FlagType {
    fn from(v: FlagTypeRaw) -> Self {
        match v.data {
            0 => FlagType::None,
            1 => FlagType::Blue,
            2 => FlagType::Yellow,
            3 => FlagType::Black,
            4 => FlagType::White,
            5 => FlagType::Checkered,
            6 => FlagType::Penalty,
            7 => FlagType::Green,
            8 => FlagType::Orange,
            _ => FlagType::None,
        }
    }
}

impl<T> From<[T; 3]> for Vector3<T> {
    fn from([x, y, z]: [T; 3]) -> Self {
        Self { x, y, z }
    }
}

impl<T> From<[T; 4]> for Wheels<T> {
    fn from([front_left, front_right, rear_left, rear_right]: [T; 4]) -> Self {
        Self {
            front_left,
            front_right,
            rear_left,
            rear_right,
        }
    }
}

impl From<[f32; 5]> for CarDamage {
    fn from([front, rear, left, right, center]: [f32; 5]) -> Self {
        Self {
            front,
            rear,
            left,
            right,
            center,
        }
    }
}

fn time(text: [u16; 15], millis: i32) -> Time {
    Time {
        millis,
        text: extract_string(&text),
    }
}

fn combine_car_info<T: Clone + Copy>(cars: [T; 60], max_items: usize) -> Vec<T> {
    cars.iter().take(max_items).copied().collect::<Vec<_>>()
}

impl From<PageFileGraphics> for Graphics {
    fn from(v: PageFileGraphics) -> Self {
        let active_cars = v.active_cars.max(0) as usize;

        let car_coordinates_vec = combine_car_info(v.car_coordinates, active_cars);
        let car_id_vec = combine_car_info(v.car_id, active_cars);
        let car_coordinates = car_id_vec
            .into_iter()
            .zip(car_coordinates_vec)
            .map(|(id, coord)| (id, coord.into()))
            .collect();

        Self {
            packet_id: v.packet_id,
            status: v.status.into(),
            session: v.session.into(),
            lap_timing: LapTiming {
                current: time(v.current_time, v.i_current_time),
                last: time(v.last_time, v.i_last_time),
                best: time(v.best_time, v.i_best_time),
                split: time(v.split, v.i_split),
                delta_lap: time(v.delta_lap_time, v.i_delta_lap_time),
                estimated_lap: time(v.estimated_lap_time, v.i_estimated_lap_time),
                last_sector_ms: v.last_sector_time,
            },
            completed_laps: v.completed_laps,
            position: v.position,
            session_time_left: v.session_time_left,
            distance_traveled: v.distance_traveled,
            is_in_pit: v.is_in_pit != 0,
            current_sector_index: v.current_sector_index,
            tyre_compound: extract_string(&v.tyre_compound),
            normalized_car_position: v.normalized_car_position,
            car_coordinates,
            player_car_id: v.player_car_id,
            penalty_time: v.penalty_time,
            flag: v.flag.into(),
            penalty: v.penalty.into(),
            ideal_line_on: v.ideal_line_on != 0,
            is_in_pit_lane: v.is_in_pit_lane != 0,
            mandatory_pit_done: v.mandatory_pit_done != 0,
            wind_speed: v.wind_speed,
            wind_direction: v.wind_direction,
            is_setup_menu_visible: v.is_setup_menu_visible != 0,
            main_display_index: v.main_display_index,
            secondary_display_index: v.secondary_display_index,
            tc: v.tc,
            tc_cut: v.tc_cut,
            engine_map: v.engine_map,
            abs: v.abs,
            fuel_used_per_lap: v.fuel_used_per_lap,
            rain_lights: v.rain_lights != 0,
            flashing_lights: v.flashing_lights != 0,
            lights_stage: v.lights_stage,
            exhaust_temperature: v.exhaust_temperature,
            wiper_stage: v.wiper_lv,
            driver_stint_total_time_left: v.driver_stint_total_time_left,
            driver_stint_time_left: v.driver_stint_time_left,
            rain_tyres: v.rain_tyres != 0,
            session_index: v.session_index,
            used_fuel: v.used_fuel,
            is_delta_positive: v.is_delta_positive != 0,
            is_valid_lap: v.is_valid_lap != 0,
            fuel_estimated_laps: v.fuel_estimated_laps,
            track_status: extract_string(&v.track_status),
            missing_mandatory_pits: v.missing_mandatory_pits,
            clock: v.clock,
            direction_lights_left: v.direction_lights_left != 0,
            direction_lights_right: v.direction_lights_right != 0,
            global_flags: GlobalFlags {
                yellow: v.global_yellow != 0,
                yellow1: v.global_yellow1 != 0,
                yellow2: v.global_yellow2 != 0,
                yellow3: v.global_yellow3 != 0,
                white: v.global_white != 0,
                green: v.global_green != 0,
                chequered: v.global_chequered != 0,
                red: v.global_red != 0,
            },
            mfd_pitstop: MfdPitstop {
                tyre_set: v.mfd_tyre_set,
                fuel_to_add: v.mfd_fuel_to_add,
                tyre_pressures: Wheels {
                    front_left: v.mfd_tyre_pressure_lf,
                    front_right: v.mfd_tyre_pressure_rf,
                    rear_left: v.mfd_tyre_pressure_lr,
                    rear_right: v.mfd_tyre_pressure_rr,
                },
            },
            track_grip_status: v.track_grip_status.into(),
            rain_intensity: v.rain_intensity.into(),
            rain_intensity_in_30m: v.rain_intensity_in_30m.into(),
            rain_intensity_in_10m: v.rain_intensity_in_10m.into(),
            current_tyre_set: v.current_tyre_set,
            strategy_tyre_set: v.strategy_tyre_set,
        }
    }
}

impl From<PageFilePhysics> for Physics {
    fn from(v: PageFilePhysics) -> Self {
        Self {
            packet_id: v.packet_id,
            gas: v.gas,
            brake: v.brake,
            fuel: v.fuel,
            gear: v.gear,
            rpm: v.rpm,
            steer_angle: v.steer_angle,
            speed_kmh: v.speed_kmh,
            velocity: v.velocity.into(),
            acc_g: v.acc_g.into(),
            wheels: Wheels {
                front_left: WheelInfo {
                    tyre_pressure: v.wheels_pressure[0],
                    angular_speed: v.wheel_angular_speed[0],
                    suspension_travel: v.suspension_travel[0],
                    tyre_core_temperature: v.tyre_core_temperature[0],
                    brake_temperature: v.brake_temp[0],
                    tyre_contact_point: v.tyre_contact_point[0].into(),
                    tyre_contact_normal: v.tyre_contact_normal[0].into(),
                    tyre_contact_heading: v.tyre_contact_heading[0].into(),
                    slip: v.wheel_slip[0],
                    slip_ratio: v.slip_ratio[0],
                    slip_angle: v.slip_angle[0],
                    brake_pressure: v.brake_pressure[0],
                    pad_life: v.pad_life[0],
                    disc_life: v.disc_life[0],
                },
                front_right: WheelInfo {
                    tyre_pressure: v.wheels_pressure[1],
                    angular_speed: v.wheel_angular_speed[1],
                    suspension_travel: v.suspension_travel[1],
                    tyre_core_temperature: v.tyre_core_temperature[1],
                    brake_temperature: v.brake_temp[1],
                    tyre_contact_point: v.tyre_contact_point[1].into(),
                    tyre_contact_normal: v.tyre_contact_normal[1].into(),
                    tyre_contact_heading: v.tyre_contact_heading[1].into(),
                    slip: v.wheel_slip[1],
                    slip_ratio: v.slip_ratio[1],
                    slip_angle: v.slip_angle[1],
                    brake_pressure: v.brake_pressure[1],
                    pad_life: v.pad_life[1],
                    disc_life: v.disc_life[1],
                },
                rear_left: WheelInfo {
                    tyre_pressure: v.wheels_pressure[2],
                    angular_speed: v.wheel_angular_speed[2],
                    suspension_travel: v.suspension_travel[2],
                    tyre_core_temperature: v.tyre_core_temperature[2],
                    brake_temperature: v.brake_temp[2],
                    tyre_contact_point: v.tyre_contact_point[2].into(),
                    tyre_contact_normal: v.tyre_contact_normal[2].into(),
                    tyre_contact_heading: v.tyre_contact_heading[2].into(),
                    slip: v.wheel_slip[2],
                    slip_ratio: v.slip_ratio[2],
                    slip_angle: v.slip_angle[2],
                    brake_pressure: v.brake_pressure[2],
                    pad_life: v.pad_life[2],
                    disc_life: v.disc_life[2],
                },
                rear_right: WheelInfo {
                    tyre_pressure: v.wheels_pressure[3],
                    angular_speed: v.wheel_angular_speed[3],
                    suspension_travel: v.suspension_travel[3],
                    tyre_core_temperature: v.tyre_core_temperature[3],
                    brake_temperature: v.brake_temp[3],
                    tyre_contact_point: v.tyre_contact_point[3].into(),
                    tyre_contact_normal: v.tyre_contact_normal[3].into(),
                    tyre_contact_heading: v.tyre_contact_heading[3].into(),
                    slip: v.wheel_slip[3],
                    slip_ratio: v.slip_ratio[3],
                    slip_angle: v.slip_angle[3],
                    brake_pressure: v.brake_pressure[3],
                    pad_life: v.pad_life[3],
                    disc_life: v.disc_life[3],
                },
            },
            tc: v.tc,
            heading: v.heading,
            pitch: v.pitch,
            roll: v.roll,
            car_damage: v.car_damage.into(),
            pit_limiter_on: v.pit_limiter_on != 0,
            abs: v.abs,
            auto_shifter_on: v.auto_shifter_on != 0,
            turbo_boost: v.turbo_boost,
            air_temperature: v.air_temp,
            road_temperature: v.road_temp,
            local_angular_velocity: v.local_angular_vel.into(),
            final_ff: v.final_ff,
            clutch: v.clutch,
            is_ai_controlled: v.is_ai_controlled != 0,
            brake_bias: v.brake_bias,
            local_velocity: v.local_velocity.into(),
            water_temperature: v.water_temp,
            front_brake_compound: v.front_brake_compound,
            rear_brake_compound: v.rear_brake_compound,
            ignition_on: v.ignition_on != 0,
            starter_engine_on: v.starter_engine_on != 0,
            engine_running: v.is_engine_running != 0,
            kerb_vibration: v.kerb_vibration,
            slip_vibrations: v.slip_vibrations,
            g_vibrations: v.g_vibrations,
            abs_vibrations: v.abs_vibrations,
        }
    }
}

impl From<PageFileStatic> for StaticData {
    fn from(v: PageFileStatic) -> Self {
        Self {
            sm_version: extract_string(&v.sm_version),
            ac_version: extract_string(&v.ac_version),
            number_of_sessions: v.number_of_sessions,
            num_cars: v.num_cars,
            car_model: extract_string(&v.car_model),
            track: extract_string(&v.track),
            track_configuration: extract_string(&v.track_configuration),
            player_name: extract_string(&v.player_name),
            player_surname: extract_string(&v.player_surname),
            player_nick: extract_string(&v.player_nick),
            sector_count: v.sector_count,
            max_rpm: v.max_rpm,
            max_fuel: v.max_fuel,
            penalties_enabled: v.penalties_enabled,
            aids: Aids {
                fuel_rate: v.aid_fuel_rate,
                tyre_rate: v.aid_tyre_rate,
                mechanical_damage: v.aid_mechanical_damage,
                allow_tyre_blankets: v.aid_allow_tyre_blankets,
                stability: v.aid_stability,
                auto_clutch: v.aid_auto_clutch != 0,
                auto_blip: v.aid_auto_blip != 0,
            },
            pit_window_start: v.pit_window_start,
            pit_window_end: v.pit_window_end,
            is_online: v.is_online != 0,
            dry_tyres_name: extract_string(&v.dry_tyres_name),
            wet_tyres_name: extract_string(&v.wet_tyres_name),
        }
    }
}