Skip to content

Instantly share code, notes, and snippets.

@nicosingh
Created May 3, 2025 19:59
Show Gist options
  • Save nicosingh/a8d7214392db03cea6f5ac296d8bcf1a to your computer and use it in GitHub Desktop.
Save nicosingh/a8d7214392db03cea6f5ac296d8bcf1a to your computer and use it in GitHub Desktop.
F1 24 UDP Client in Python
import socket
import ctypes
from enum import IntEnum, Enum
import time
class PacketID(IntEnum):
MOTION = 0
SESSION = 1
LAP_DATA = 2
EVENT = 3
PARTICIPANTS = 4
CAR_SETUPS = 5
CAR_TELEMETRY = 6
CAR_STATUS = 7
FINAL_CLASSIFICATION = 8
LOBBY_INFO = 9
CAR_DAMAGE = 10
SESSION_HISTORY = 11
TYRE_SETS = 12
MOTION_EX = 13
TIME_TRIAL = 14
class Packet(ctypes.Structure):
"""Base class for all F1 packet types"""
_pack_ = 1
@classmethod
def from_buffer(cls, data, offset=0):
return cls.from_buffer_copy(data, offset)
def to_dict(self):
"""Convert the structure to a nested dictionary"""
result = {}
for field_name, _ in self._fields_:
value = getattr(self, field_name)
# Handle arrays
if hasattr(value, '_length_'):
result[field_name] = [item.to_dict() if hasattr(item, 'to_dict') else item for item in value]
# Handle nested structures
elif hasattr(value, '_fields_'):
result[field_name] = value.to_dict() if hasattr(value, 'to_dict') else value
# Handle normal fields
else:
result[field_name] = value
return result
class PacketHeader(Packet):
_fields_ = [
("m_packet_format", ctypes.c_uint16),
("m_game_year", ctypes.c_uint8),
("m_game_major_version", ctypes.c_uint8),
("m_game_minor_version", ctypes.c_uint8),
("m_packet_version", ctypes.c_uint8),
("m_packet_id", ctypes.c_uint8),
("m_session_uid", ctypes.c_uint64),
("m_session_time", ctypes.c_float),
("m_frame_identifier", ctypes.c_uint32),
("m_overall_frame_identifier", ctypes.c_uint32),
("m_player_car_index", ctypes.c_uint8),
("m_secondary_player_car_index", ctypes.c_uint8)
]
class CarMotionData(Packet):
_fields_ = [
("m_world_position_x", ctypes.c_float), # World space X position
("m_world_position_y", ctypes.c_float), # World space Y position
("m_world_position_z", ctypes.c_float), # World space Z position
("m_world_velocity_x", ctypes.c_float), # Velocity in world space X
("m_world_velocity_y", ctypes.c_float), # Velocity in world space Y
("m_world_velocity_z", ctypes.c_float), # Velocity in world space Z
("m_world_forward_dir_x", ctypes.c_int16), # World space forward X direction (normalised)
("m_world_forward_dir_y", ctypes.c_int16), # World space forward Y direction (normalised)
("m_world_forward_dir_z", ctypes.c_int16), # World space forward Z direction (normalised)
("m_world_right_dir_x", ctypes.c_int16), # World space right X direction (normalised)
("m_world_right_dir_y", ctypes.c_int16), # World space right Y direction (normalised)
("m_world_right_dir_z", ctypes.c_int16), # World space right Z direction (normalised)
("m_g_force_lateral", ctypes.c_float), # Lateral G-Force component
("m_g_force_longitudinal", ctypes.c_float), # Longitudinal G-Force component
("m_g_force_vertical", ctypes.c_float), # Vertical G-Force component
("m_yaw", ctypes.c_float), # Yaw angle in radians
("m_pitch", ctypes.c_float), # Pitch angle in radians
("m_roll", ctypes.c_float), # Roll angle in radians
]
class PacketMotionData(Packet):
_fields_ = [
("m_header", PacketHeader), # Header
("m_car_motion_data", CarMotionData * 22), # Data for all cars on track
]
class MarshalZone(Packet):
_fields_ = [
("m_zone_start", ctypes.c_float), # Fraction (0..1) of way through the lap the marshal zone starts
("m_zone_flag", ctypes.c_int8), # -1 = invalid/unknown, 0 = none, 1 = green, 2 = blue, 3 = yellow
]
class WeatherForecastSample(Packet):
_fields_ = [
("m_session_type", ctypes.c_uint8), # 0 = unknown, see appendix
("m_time_offset", ctypes.c_uint8), # Time in minutes the forecast is for
("m_weather", ctypes.c_uint8), # Weather - 0 = clear, 1 = light cloud, 2 = overcast, 3 = light rain, 4 = heavy rain, 5 = storm
("m_track_temperature", ctypes.c_int8), # Track temp. in degrees Celsius
("m_track_temperature_change", ctypes.c_int8), # Track temp. change – 0 = up, 1 = down, 2 = no change
("m_air_temperature", ctypes.c_int8), # Air temp. in degrees celsius
("m_air_temperature_change", ctypes.c_int8), # Air temp. change – 0 = up, 1 = down, 2 = no change
("m_rain_percentage", ctypes.c_uint8), # Rain percentage (0-100)
]
class PacketSessionData(Packet):
_fields_ = [
("m_header", PacketHeader), # Header
("m_weather", ctypes.c_uint8), # Weather - 0 = clear, 1 = light cloud, 2 = overcast, 3 = light rain, 4 = heavy rain, 5 = storm
("m_track_temperature", ctypes.c_int8), # Track temp. in degrees celsius
("m_air_temperature", ctypes.c_int8), # Air temp. in degrees celsius
("m_total_laps", ctypes.c_uint8), # Total number of laps in this race
("m_track_length", ctypes.c_uint16), # Track length in metres
("m_session_type", ctypes.c_uint8), # 0 = unknown, see appendix
("m_track_id", ctypes.c_int8), # -1 for unknown, see appendix
("m_formula", ctypes.c_uint8), # Formula, 0 = F1 Modern, 1 = F1 Classic, 2 = F2, 3 = F1 Generic, 4 = Beta, 6 = Esports, 8 = F1 World, 9 = F1 Elimination
("m_session_time_left", ctypes.c_uint16), # Time left in session in seconds
("m_session_duration", ctypes.c_uint16), # Session duration in seconds
("m_pit_speed_limit", ctypes.c_uint8), # Pit speed limit in kilometres per hour
("m_game_paused", ctypes.c_uint8), # Whether the game is paused – network game only
("m_is_spectating", ctypes.c_uint8), # Whether the player is spectating
("m_spectator_car_index", ctypes.c_uint8), # Index of the car being spectated
("m_sli_pro_native_support", ctypes.c_uint8), # SLI Pro support, 0 = inactive, 1 = active
("m_num_marshal_zones", ctypes.c_uint8), # Number of marshal zones to follow
("m_marshal_zones", MarshalZone * 21), # List of marshal zones – max 21
("m_safety_car_status", ctypes.c_uint8), # 0 = no safety car, 1 = full, 2 = virtual, 3 = formation lap
("m_network_game", ctypes.c_uint8), # 0 = offline, 1 = online
("m_num_weather_forecast_samples", ctypes.c_uint8), # Number of weather samples to follow
("m_weather_forecast_samples", WeatherForecastSample * 64), # Array of weather forecast samples
("m_forecast_accuracy", ctypes.c_uint8), # 0 = Perfect, 1 = Approximate
("m_ai_difficulty", ctypes.c_uint8), # AI Difficulty rating – 0-110
("m_season_link_identifier", ctypes.c_uint32), # Identifier for season - persists across saves
("m_weekend_link_identifier", ctypes.c_uint32), # Identifier for weekend - persists across saves
("m_session_link_identifier", ctypes.c_uint32), # Identifier for session - persists across saves
("m_pit_stop_window_ideal_lap", ctypes.c_uint8), # Ideal lap to pit on for current strategy (player)
("m_pit_stop_window_latest_lap", ctypes.c_uint8), # Latest lap to pit on for current strategy (player)
("m_pit_stop_rejoin_position", ctypes.c_uint8), # Predicted position to rejoin at (player)
("m_steering_assist", ctypes.c_uint8), # 0 = off, 1 = on
("m_braking_assist", ctypes.c_uint8), # 0 = off, 1 = low, 2 = medium, 3 = high
("m_gearbox_assist", ctypes.c_uint8), # 1 = manual, 2 = manual & suggested gear, 3 = auto
("m_pit_assist", ctypes.c_uint8), # 0 = off, 1 = on
("m_pit_release_assist", ctypes.c_uint8), # 0 = off, 1 = on
("m_ers_assist", ctypes.c_uint8), # 0 = off, 1 = on
("m_drs_assist", ctypes.c_uint8), # 0 = off, 1 = on
("m_dynamic_racing_line", ctypes.c_uint8), # 0 = off, 1 = corners only, 2 = full
("m_dynamic_racing_line_type", ctypes.c_uint8), # 0 = 2D, 1 = 3D
("m_game_mode", ctypes.c_uint8), # Game mode id - see appendix
("m_rule_set", ctypes.c_uint8), # Ruleset - see appendix
("m_time_of_day", ctypes.c_uint32), # Local time of day - minutes since midnight
("m_session_length", ctypes.c_uint8), # 0 = None, 2 = Very Short, 3 = Short, 4 = Medium, 5 = Medium Long, 6 = Long, 7 = Full
("m_speed_units_lead_player", ctypes.c_uint8), # 0 = MPH, 1 = KPH
("m_temperature_units_lead_player", ctypes.c_uint8), # 0 = Celsius, 1 = Fahrenheit
("m_speed_units_secondary_player", ctypes.c_uint8), # 0 = MPH, 1 = KPH
("m_temperature_units_secondary_player", ctypes.c_uint8), # 0 = Celsius, 1 = Fahrenheit
("m_num_safety_car_periods", ctypes.c_uint8), # Number of safety cars called during session
("m_num_virtual_safety_car_periods", ctypes.c_uint8), # Number of virtual safety cars called
("m_num_red_flag_periods", ctypes.c_uint8), # Number of red flags called during session
("m_equal_car_performance", ctypes.c_uint8), # 0 = Off, 1 = On
("m_recovery_mode", ctypes.c_uint8), # 0 = None, 1 = Flashbacks, 2 = Auto-recovery
("m_flashback_limit", ctypes.c_uint8), # 0 = Low, 1 = Medium, 2 = High, 3 = Unlimited
("m_surface_type", ctypes.c_uint8), # 0 = Simplified, 1 = Realistic
("m_low_fuel_mode", ctypes.c_uint8), # 0 = Easy, 1 = Hard
("m_race_starts", ctypes.c_uint8), # 0 = Manual, 1 = Assisted
("m_tyre_temperature", ctypes.c_uint8), # 0 = Surface only, 1 = Surface & Carcass
("m_pit_lane_tyre_sim", ctypes.c_uint8), # 0 = On, 1 = Off
("m_car_damage", ctypes.c_uint8), # 0 = Off, 1 = Reduced, 2 = Standard, 3 = Simulation
("m_car_damage_rate", ctypes.c_uint8), # 0 = Reduced, 1 = Standard, 2 = Simulation
("m_collisions", ctypes.c_uint8), # 0 = Off, 1 = Player-to-Player Off, 2 = On
("m_collisions_off_for_first_lap_only", ctypes.c_uint8), # 0 = Disabled, 1 = Enabled
("m_mp_unsafe_pit_release", ctypes.c_uint8), # 0 = On, 1 = Off (Multiplayer)
("m_mp_off_for_griefing", ctypes.c_uint8), # 0 = Disabled, 1 = Enabled (Multiplayer)
("m_corner_cutting_stringency", ctypes.c_uint8), # 0 = Regular, 1 = Strict
("m_parc_ferme_rules", ctypes.c_uint8), # 0 = Off, 1 = On
("m_pit_stop_experience", ctypes.c_uint8), # 0 = Automatic, 1 = Broadcast, 2 = Immersive
("m_safety_car", ctypes.c_uint8), # 0 = Off, 1 = Reduced, 2 = Standard, 3 = Increased
("m_safety_car_experience", ctypes.c_uint8), # 0 = Broadcast, 1 = Immersive
("m_formation_lap", ctypes.c_uint8), # 0 = Off, 1 = On
("m_formation_lap_experience", ctypes.c_uint8), # 0 = Broadcast, 1 = Immersive
("m_red_flags", ctypes.c_uint8), # 0 = Off, 1 = Reduced, 2 = Standard, 3 = Increased
("m_affects_licence_level_solo", ctypes.c_uint8), # 0 = Off, 1 = On
("m_affects_licence_level_mp", ctypes.c_uint8), # 0 = Off, 1 = On
("m_num_sessions_in_weekend", ctypes.c_uint8), # Number of session in following array
("m_weekend_structure", ctypes.c_uint8 * 12), # List of session types to show weekend structure - see appendix for types
("m_sector2_lap_distance_start", ctypes.c_float), # Distance in m around track where sector 2 starts
("m_sector3_lap_distance_start", ctypes.c_float), # Distance in m around track where sector 3 starts
]
class LapData(Packet):
_fields_ = [
("m_last_lap_time_in_ms", ctypes.c_uint32), # Last lap time in milliseconds
("m_current_lap_time_in_ms", ctypes.c_uint32), # Current time around the lap in milliseconds
("m_sector1_time_ms_part", ctypes.c_uint16), # Sector 1 time milliseconds part
("m_sector1_time_minutes_part", ctypes.c_uint8), # Sector 1 whole minute part
("m_sector2_time_ms_part", ctypes.c_uint16), # Sector 2 time milliseconds part
("m_sector2_time_minutes_part", ctypes.c_uint8), # Sector 2 whole minute part
("m_delta_to_car_in_front_ms_part", ctypes.c_uint16), # Time delta to car in front milliseconds part
("m_delta_to_car_in_front_minutes_part", ctypes.c_uint8), # Time delta to car in front whole minute part
("m_delta_to_race_leader_ms_part", ctypes.c_uint16), # Time delta to race leader milliseconds part
("m_delta_to_race_leader_minutes_part", ctypes.c_uint8), # Time delta to race leader whole minute part
("m_lap_distance", ctypes.c_float), # Distance vehicle is around current lap in metres
("m_total_distance", ctypes.c_float), # Total distance travelled in session in metres
("m_safety_car_delta", ctypes.c_float), # Delta in seconds for safety car
("m_car_position", ctypes.c_uint8), # Car race position
("m_current_lap_num", ctypes.c_uint8), # Current lap number
("m_pit_status", ctypes.c_uint8), # 0 = none, 1 = pitting, 2 = in pit area
("m_num_pit_stops", ctypes.c_uint8), # Number of pit stops taken in this race
("m_sector", ctypes.c_uint8), # 0 = sector1, 1 = sector2, 2 = sector3
("m_current_lap_invalid", ctypes.c_uint8), # Current lap invalid - 0 = valid, 1 = invalid
("m_penalties", ctypes.c_uint8), # Accumulated time penalties in seconds to be added
("m_total_warnings", ctypes.c_uint8), # Accumulated number of warnings issued
("m_corner_cutting_warnings", ctypes.c_uint8), # Accumulated number of corner cutting warnings issued
("m_num_unserved_drive_through_pens", ctypes.c_uint8), # Num drive through pens left to serve
("m_num_unserved_stop_go_pens", ctypes.c_uint8), # Num stop go pens left to serve
("m_grid_position", ctypes.c_uint8), # Grid position the vehicle started the race in
("m_driver_status", ctypes.c_uint8), # Status of driver - 0 = in garage, 1 = flying lap, etc
("m_result_status", ctypes.c_uint8), # Result status - 0 = invalid, 1 = inactive, etc
("m_pit_lane_timer_active", ctypes.c_uint8), # Pit lane timing, 0 = inactive, 1 = active
("m_pit_lane_time_in_lane_in_ms", ctypes.c_uint16), # If active, the current time spent in the pit lane in ms
("m_pit_stop_timer_in_ms", ctypes.c_uint16), # Time of the actual pit stop in ms
("m_pit_stop_should_serve_pen", ctypes.c_uint8), # Whether the car should serve a penalty at this stop
("m_speed_trap_fastest_speed", ctypes.c_float), # Fastest speed through speed trap for this car in kmph
("m_speed_trap_fastest_lap", ctypes.c_uint8), # Lap no the fastest speed was achieved, 255 = not set
]
class PacketLapData(Packet):
_fields_ = [
("m_header", PacketHeader), # Header
("m_lap_data", LapData * 22), # Lap data for all cars on track
("m_time_trial_pb_car_idx", ctypes.c_uint8), # Index of Personal Best car in time trial (255 if invalid)
("m_time_trial_rival_car_idx", ctypes.c_uint8), # Index of Rival car in time trial (255 if invalid)
]
class FastestLapData(Packet):
_fields_ = [
("vehicle_idx", ctypes.c_uint8), # Vehicle index of car achieving fastest lap
("lap_time", ctypes.c_float) # Lap time in seconds
]
class RetirementData(Packet):
_fields_ = [
("vehicle_idx", ctypes.c_uint8) # Vehicle index of car retiring
]
class TeamMateInPitsData(Packet):
_fields_ = [
("vehicle_idx", ctypes.c_uint8) # Vehicle index of team mate
]
class RaceWinnerData(Packet):
_fields_ = [
("vehicle_idx", ctypes.c_uint8) # Vehicle index of the race winner
]
class PenaltyData(Packet):
_fields_ = [
("penalty_type", ctypes.c_uint8), # Penalty type – see Appendices
("infringement_type", ctypes.c_uint8), # Infringement type – see Appendices
("vehicle_idx", ctypes.c_uint8), # Vehicle index of the car the penalty is applied to
("other_vehicle_idx", ctypes.c_uint8), # Vehicle index of the other car involved
("time", ctypes.c_uint8), # Time gained, or time spent doing action in seconds
("lap_num", ctypes.c_uint8), # Lap the penalty occurred on
("places_gained", ctypes.c_uint8) # Number of places gained by this
]
class SpeedTrapData(Packet):
_fields_ = [
("vehicle_idx", ctypes.c_uint8), # Vehicle index triggering speed trap
("speed", ctypes.c_float), # Top speed achieved in kph
("is_overall_fastest_in_session", ctypes.c_uint8), # Overall fastest in session (1) or not (0)
("is_driver_fastest_in_session", ctypes.c_uint8), # Fastest for driver in session (1) or not (0)
("fastest_vehicle_idx_in_session", ctypes.c_uint8), # Vehicle index of fastest in session
("fastest_speed_in_session", ctypes.c_float) # Speed of the fastest vehicle in session
]
class StartLightsData(Packet):
_fields_ = [
("num_lights", ctypes.c_uint8) # Number of lights showing
]
class DriveThroughPenaltyServedData(Packet):
_fields_ = [
("vehicle_idx", ctypes.c_uint8) # Vehicle index serving drive through
]
class StopGoPenaltyServedData(Packet):
_fields_ = [
("vehicle_idx", ctypes.c_uint8) # Vehicle index serving stop go
]
class FlashbackData(Packet):
_fields_ = [
("flashback_frame_identifier", ctypes.c_uint32), # Frame identifier flashed back to
("flashback_session_time", ctypes.c_float) # Session time flashed back to
]
class ButtonsData(Packet):
_fields_ = [
("button_status", ctypes.c_uint32) # Bit flags for button presses - see appendices
]
class OvertakeData(Packet):
_fields_ = [
("overtaking_vehicle_idx", ctypes.c_uint8), # Vehicle index overtaking
("being_overtaken_vehicle_idx", ctypes.c_uint8) # Vehicle index being overtaken
]
class SafetyCarData(Packet):
_fields_ = [
("safety_car_type", ctypes.c_uint8), # 0=None, 1=Full, 2=Virtual, 3=Formation Lap
("event_type", ctypes.c_uint8) # 0=Deployed, 1=Returning, 2=Returned, 3=Resume Race
]
class CollisionData(Packet):
_fields_ = [
("vehicle1_idx", ctypes.c_uint8), # First vehicle in collision
("vehicle2_idx", ctypes.c_uint8) # Second vehicle in collision
]
class EventDataDetails(ctypes.Union):
_fields_ = [
("fastest_lap", FastestLapData),
("retirement", RetirementData),
("team_mate_in_pits", TeamMateInPitsData),
("race_winner", RaceWinnerData),
("penalty", PenaltyData),
("speed_trap", SpeedTrapData),
("start_lights", StartLightsData),
("drive_through_penalty_served", DriveThroughPenaltyServedData),
("stop_go_penalty_served", StopGoPenaltyServedData),
("flashback", FlashbackData),
("buttons", ButtonsData),
("overtake", OvertakeData),
("safety_car", SafetyCarData),
("collision", CollisionData)
]
class PacketEventData(Packet):
_fields_ = [
("m_header", PacketHeader), # Header
("m_event_string_code", ctypes.c_char * 4), # Event string code, see below
("m_event_details", EventDataDetails) # Event details - interpret based on event code
]
class ParticipantData(Packet):
_fields_ = [
("m_ai_controlled", ctypes.c_uint8), # Whether the vehicle is AI (1) or Human (0) controlled
("m_driver_id", ctypes.c_uint8), # Driver id - see appendix, 255 if network human
("m_network_id", ctypes.c_uint8), # Network id – unique identifier for network players
("m_team_id", ctypes.c_uint8), # Team id - see appendix
("m_my_team", ctypes.c_uint8), # My team flag – 1 = My Team, 0 = otherwise
("m_race_number", ctypes.c_uint8), # Race number of the car
("m_nationality", ctypes.c_uint8), # Nationality of the driver
("m_name", ctypes.c_char * 48), # Name of participant in UTF-8 format – null terminated
("m_your_telemetry", ctypes.c_uint8), # The player's UDP setting, 0 = restricted, 1 = public
("m_show_online_names", ctypes.c_uint8), # The player's show online names setting, 0 = off, 1 = on
("m_tech_level", ctypes.c_uint16), # F1 World tech level
("m_platform", ctypes.c_uint8), # 1 = Steam, 3 = PlayStation, 4 = Xbox, 6 = Origin, 255 = unknown
]
class PacketParticipantsData(Packet):
_fields_ = [
("m_header", PacketHeader), # Header
("m_num_active_cars", ctypes.c_uint8), # Number of active cars in the data – should match number of cars on HUD
("m_participants", ParticipantData * 22),
]
class CarSetupData(Packet):
_fields_ = [
("m_front_wing", ctypes.c_uint8), # Front wing aero
("m_rear_wing", ctypes.c_uint8), # Rear wing aero
("m_on_throttle", ctypes.c_uint8), # Differential adjustment on throttle (percentage)
("m_off_throttle", ctypes.c_uint8), # Differential adjustment off throttle (percentage)
("m_front_camber", ctypes.c_float), # Front camber angle (suspension geometry)
("m_rear_camber", ctypes.c_float), # Rear camber angle (suspension geometry)
("m_front_toe", ctypes.c_float), # Front toe angle (suspension geometry)
("m_rear_toe", ctypes.c_float), # Rear toe angle (suspension geometry)
("m_front_suspension", ctypes.c_uint8), # Front suspension
("m_rear_suspension", ctypes.c_uint8), # Rear suspension
("m_front_anti_roll_bar", ctypes.c_uint8), # Front anti-roll bar
("m_rear_anti_roll_bar", ctypes.c_uint8), # Front anti-roll bar
("m_front_suspension_height", ctypes.c_uint8), # Front ride height
("m_rear_suspension_height", ctypes.c_uint8), # Rear ride height
("m_brake_pressure", ctypes.c_uint8), # Brake pressure (percentage)
("m_brake_bias", ctypes.c_uint8), # Brake bias (percentage)
("m_engine_braking", ctypes.c_uint8), # Engine braking (percentage)
("m_rear_left_tyre_pressure", ctypes.c_float), # Rear left tyre pressure (PSI)
("m_rear_right_tyre_pressure", ctypes.c_float), # Rear right tyre pressure (PSI)
("m_front_left_tyre_pressure", ctypes.c_float), # Front left tyre pressure (PSI)
("m_front_right_tyre_pressure", ctypes.c_float),# Front right tyre pressure (PSI)
("m_ballast", ctypes.c_uint8), # Ballast
("m_fuel_load", ctypes.c_float), # Fuel load
]
class PacketCarSetupData(Packet):
_fields_ = [
("m_header", PacketHeader), # Header
("m_car_setups", CarSetupData * 22), # Data for all cars on track
("m_next_front_wing_value", ctypes.c_float) # Value of front wing after next pit stop - player only
]
class CarTelemetryData(Packet):
_fields_ = [
("m_speed", ctypes.c_uint16), # Speed of car in kilometres per hour
("m_throttle", ctypes.c_float), # Amount of throttle applied (0.0 to 1.0)
("m_steer", ctypes.c_float), # Steering (-1.0 (full lock left) to 1.0 (full lock right))
("m_brake", ctypes.c_float), # Amount of brake applied (0.0 to 1.0)
("m_clutch", ctypes.c_uint8), # Amount of clutch applied (0 to 100)
("m_gear", ctypes.c_int8), # Gear selected (1-8, N=0, R=-1)
("m_engine_rpm", ctypes.c_uint16), # Engine RPM
("m_drs", ctypes.c_uint8), # 0 = off, 1 = on
("m_rev_lights_percent", ctypes.c_uint8), # Rev lights indicator (percentage)
("m_rev_lights_bit_value", ctypes.c_uint16), # Rev lights (bit 0 = leftmost LED, bit 14 = rightmost LED)
("m_brakes_temperature", ctypes.c_uint16 * 4), # Brakes temperature (celsius)
("m_tyres_surface_temperature", ctypes.c_uint8 * 4), # Tyres surface temperature (celsius)
("m_tyres_inner_temperature", ctypes.c_uint8 * 4), # Tyres inner temperature (celsius)
("m_engine_temperature", ctypes.c_uint16), # Engine temperature (celsius)
("m_tyres_pressure", ctypes.c_float * 4), # Tyres pressure (PSI)
("m_surface_type", ctypes.c_uint8 * 4), # Driving surface, see appendices
]
class PacketCarTelemetryData(Packet):
_fields_ = [
("m_header", PacketHeader), # Header
("m_car_telemetry_data", CarTelemetryData * 22), # Data for all cars on track
("m_mfd_panel_index", ctypes.c_uint8), # Index of MFD panel open - 255 = MFD closed
("m_mfd_panel_index_secondary_player", ctypes.c_uint8), # See above for secondary player
("m_suggested_gear", ctypes.c_int8), # Suggested gear for the player (1-8), 0 if no gear suggested
]
class CarStatusData(Packet):
_fields_ = [
("m_traction_control", ctypes.c_uint8), # Traction control - 0 = off, 1 = medium, 2 = full
("m_anti_lock_brakes", ctypes.c_uint8), # 0 (off) - 1 (on)
("m_fuel_mix", ctypes.c_uint8), # Fuel mix - 0 = lean, 1 = standard, 2 = rich, 3 = max
("m_front_brake_bias", ctypes.c_uint8), # Front brake bias (percentage)
("m_pit_limiter_status", ctypes.c_uint8), # Pit limiter status - 0 = off, 1 = on
("m_fuel_in_tank", ctypes.c_float), # Current fuel mass
("m_fuel_capacity", ctypes.c_float), # Fuel capacity
("m_fuel_remaining_laps", ctypes.c_float), # Fuel remaining in terms of laps (value on MFD)
("m_max_rpm", ctypes.c_uint16), # Cars max RPM, point of rev limiter
("m_idle_rpm", ctypes.c_uint16), # Cars idle RPM
("m_max_gears", ctypes.c_uint8), # Maximum number of gears
("m_drs_allowed", ctypes.c_uint8), # 0 = not allowed, 1 = allowed
("m_drs_activation_distance", ctypes.c_uint16), # 0 = DRS not available, non-zero - DRS will be available in [X] metres
("m_actual_tyre_compound", ctypes.c_uint8), # F1 Modern - 16 = C5, 17 = C4, 18 = C3, 19 = C2, 20 = C1, 21 = C0, 7 = inter, 8 = wet. F1 Classic - 9 = dry, 10 = wet. F2 – 11 = super soft, 12 = soft, 13 = medium, 14 = hard, 15 = wet
("m_visual_tyre_compound", ctypes.c_uint8), # F1 visual (can be different from actual compound), 16 = soft, 17 = medium, 18 = hard, 7 = inter, 8 = wet. F1 Classic – same as above. F2 '19, 15 = wet, 19 – super soft, 20 = soft, 21 = medium , 22 = hard
("m_tyres_age_laps", ctypes.c_uint8), # Age in laps of the current set of tyres
("m_vehicle_fia_flags", ctypes.c_int8), # -1 = invalid/unknown, 0 = none, 1 = green, 2 = blue, 3 = yellow
("m_engine_power_ice", ctypes.c_float), # Engine power output of ICE (W)
("m_engine_power_mguk", ctypes.c_float), # Engine power output of MGU-K (W)
("m_ers_store_energy", ctypes.c_float), # ERS energy store in Joules
("m_ers_deploy_mode", ctypes.c_uint8), # ERS deployment mode, 0 = none, 1 = medium, 2 = hotlap, 3 = overtake
("m_ers_harvested_this_lap_mguk", ctypes.c_float), # ERS energy harvested this lap by MGU-K
("m_ers_harvested_this_lap_mguh", ctypes.c_float), # ERS energy harvested this lap by MGU-H
("m_ers_deployed_this_lap", ctypes.c_float), # ERS energy deployed this lap
("m_network_paused", ctypes.c_uint8), # Whether the car is paused in a network game
]
class PacketCarStatusData(Packet):
_fields_ = [
("m_header", PacketHeader), # Header
("m_car_status_data", CarStatusData * 22), # Data for all cars on track
]
class FinalClassificationData(Packet):
_fields_ = [
("m_position", ctypes.c_uint8), # Finishing position
("m_num_laps", ctypes.c_uint8), # Number of laps completed
("m_grid_position", ctypes.c_uint8), # Grid position of the car
("m_points", ctypes.c_uint8), # Number of points scored
("m_num_pit_stops", ctypes.c_uint8), # Number of pit stops made
("m_result_status", ctypes.c_uint8), # Result status - 0 = invalid, 1 = inactive, 2 = active,
# 3 = finished, 4 = didnotfinish, 5 = disqualified,
# 6 = not classified, 7 = retired
("m_best_lap_time_in_ms", ctypes.c_uint32), # Best lap time of the session in milliseconds
("m_total_race_time", ctypes.c_double), # Total race time in seconds without penalties
("m_penalties_time", ctypes.c_uint8), # Total penalties accumulated in seconds
("m_num_penalties", ctypes.c_uint8), # Number of penalties applied to this driver
("m_num_tyre_stints", ctypes.c_uint8), # Number of tyres stints up to maximum
("m_tyre_stints_actual", ctypes.c_uint8 * 8), # Actual tyres used by this driver
("m_tyre_stints_visual", ctypes.c_uint8 * 8), # Visual tyres used by this driver
("m_tyre_stints_end_laps", ctypes.c_uint8 * 8), # The lap number stints end on
]
class PacketFinalClassificationData(Packet):
_fields_ = [
("m_header", PacketHeader), # Header
("m_num_cars", ctypes.c_uint8), # Number of cars in the final classification
("m_classification_data", FinalClassificationData * 22), # Data for all cars
]
class LobbyInfoData(Packet):
_fields_ = [
("m_ai_controlled", ctypes.c_uint8), # Whether the vehicle is AI (1) or Human (0) controlled
("m_team_id", ctypes.c_uint8), # Team id - see appendix (255 if no team currently selected)
("m_nationality", ctypes.c_uint8), # Nationality of the driver
("m_platform", ctypes.c_uint8), # 1 = Steam, 3 = PlayStation, 4 = Xbox, 6 = Origin, 255 = unknown
("m_name", ctypes.c_char * 48), # Name of participant in UTF-8 format – null terminated
("m_car_number", ctypes.c_uint8), # Car number of the player
("m_your_telemetry", ctypes.c_uint8), # The player's UDP setting, 0 = restricted, 1 = public
("m_show_online_names", ctypes.c_uint8), # The player's show online names setting, 0 = off, 1 = on
("m_tech_level", ctypes.c_uint16), # F1 World tech level
("m_ready_status", ctypes.c_uint8), # 0 = not ready, 1 = ready, 2 = spectating
]
class PacketLobbyInfoData(Packet):
_fields_ = [
("m_header", PacketHeader), # Header
("m_num_players", ctypes.c_uint8), # Number of players in the lobby data
("m_lobby_players", LobbyInfoData * 22), # Array of lobby players data
]
class CarDamageData(Packet):
_fields_ = [
("m_tyres_wear", ctypes.c_float * 4), # Tyre wear (percentage)
("m_tyres_damage", ctypes.c_uint8 * 4), # Tyre damage (percentage)
("m_brakes_damage", ctypes.c_uint8 * 4), # Brakes damage (percentage)
("m_front_left_wing_damage", ctypes.c_uint8), # Front left wing damage (percentage)
("m_front_right_wing_damage", ctypes.c_uint8), # Front right wing damage (percentage)
("m_rear_wing_damage", ctypes.c_uint8), # Rear wing damage (percentage)
("m_floor_damage", ctypes.c_uint8), # Floor damage (percentage)
("m_diffuser_damage", ctypes.c_uint8), # Diffuser damage (percentage)
("m_sidepod_damage", ctypes.c_uint8), # Sidepod damage (percentage)
("m_drs_fault", ctypes.c_uint8), # Indicator for DRS fault, 0 = OK, 1 = fault
("m_ers_fault", ctypes.c_uint8), # Indicator for ERS fault, 0 = OK, 1 = fault
("m_gear_box_damage", ctypes.c_uint8), # Gear box damage (percentage)
("m_engine_damage", ctypes.c_uint8), # Engine damage (percentage)
("m_engine_mguh_wear", ctypes.c_uint8), # Engine wear MGU-H (percentage)
("m_engine_es_wear", ctypes.c_uint8), # Engine wear ES (percentage)
("m_engine_ce_wear", ctypes.c_uint8), # Engine wear CE (percentage)
("m_engine_ice_wear", ctypes.c_uint8), # Engine wear ICE (percentage)
("m_engine_mguk_wear", ctypes.c_uint8), # Engine wear MGU-K (percentage)
("m_engine_tc_wear", ctypes.c_uint8), # Engine wear TC (percentage)
("m_engine_blown", ctypes.c_uint8), # Engine blown, 0 = OK, 1 = fault
("m_engine_seized", ctypes.c_uint8), # Engine seized, 0 = OK, 1 = fault
]
class PacketCarDamageData(Packet):
_fields_ = [
("m_header", PacketHeader), # Header
("m_car_damage_data", CarDamageData * 22), # Data for all cars on track
]
class LapHistoryData(Packet):
_fields_ = [
("m_lap_time_in_ms", ctypes.c_uint32), # Lap time in milliseconds
("m_sector1_time_ms_part", ctypes.c_uint16), # Sector 1 milliseconds part
("m_sector1_time_minutes_part", ctypes.c_uint8), # Sector 1 whole minute part
("m_sector2_time_ms_part", ctypes.c_uint16), # Sector 2 time milliseconds part
("m_sector2_time_minutes_part", ctypes.c_uint8), # Sector 2 whole minute part
("m_sector3_time_ms_part", ctypes.c_uint16), # Sector 3 time milliseconds part
("m_sector3_time_minutes_part", ctypes.c_uint8), # Sector 3 whole minute part
("m_lap_valid_bit_flags", ctypes.c_uint8) # 0x01 bit set-lap valid, 0x02 bit set-sector 1 valid,
# 0x04 bit set-sector 2 valid, 0x08 bit set-sector 3 valid
]
class TyreStintHistoryData(Packet):
_fields_ = [
("m_end_lap", ctypes.c_uint8), # Lap the tyre usage ends on (255 of current tyre)
("m_tyre_actual_compound", ctypes.c_uint8), # Actual tyres used by this driver
("m_tyre_visual_compound", ctypes.c_uint8) # Visual tyres used by this driver
]
class PacketSessionHistoryData(Packet):
_fields_ = [
("m_header", PacketHeader), # Header
("m_car_idx", ctypes.c_uint8), # Index of the car this lap data relates to
("m_num_laps", ctypes.c_uint8), # Num laps in the data (including current partial lap)
("m_num_tyre_stints", ctypes.c_uint8), # Number of tyre stints in the data
("m_best_lap_time_lap_num", ctypes.c_uint8), # Lap the best lap time was achieved on
("m_best_sector1_lap_num", ctypes.c_uint8), # Lap the best Sector 1 time was achieved on
("m_best_sector2_lap_num", ctypes.c_uint8), # Lap the best Sector 2 time was achieved on
("m_best_sector3_lap_num", ctypes.c_uint8), # Lap the best Sector 3 time was achieved on
("m_lap_history_data", LapHistoryData * 100), # 100 laps of data max (0 = first lap, 1 = second lap, ...)
("m_tyre_stints_history_data", TyreStintHistoryData * 8) # 8 tyre stints max
]
class TyreSetData(Packet):
_fields_ = [
("m_actual_tyre_compound", ctypes.c_uint8), # Actual tyre compound used
("m_visual_tyre_compound", ctypes.c_uint8), # Visual tyre compound used
("m_wear", ctypes.c_uint8), # Tyre wear (percentage)
("m_available", ctypes.c_uint8), # Whether this set is currently available
("m_recommended_session", ctypes.c_uint8), # Recommended session for tyre set, see appendix
("m_life_span", ctypes.c_uint8), # Laps left in this tyre set
("m_usable_life", ctypes.c_uint8), # Max number of laps recommended for this compound
("m_lap_delta_time", ctypes.c_int16), # Lap delta time in milliseconds compared to fitted set
("m_fitted", ctypes.c_uint8), # Whether the set is fitted or not
]
class PacketTyreSetsData(Packet):
_fields_ = [
("m_header", PacketHeader), # Header
("m_car_idx", ctypes.c_uint8), # Index of the car this data relates to
("m_tyre_set_data", TyreSetData * 20), # 13 (dry) + 7 (wet)
("m_fitted_idx", ctypes.c_uint8), # Index into array of fitted tyre
]
class PacketMotionExData(Packet):
_fields_ = [
("m_header", PacketHeader), # Header
("m_suspension_position", ctypes.c_float * 4), # Note: All wheel arrays have the following order:
("m_suspension_velocity", ctypes.c_float * 4), # RL, RR, FL, FR
("m_suspension_acceleration", ctypes.c_float * 4), # RL, RR, FL, FR
("m_wheel_speed", ctypes.c_float * 4), # Speed of each wheel
("m_wheel_slip_ratio", ctypes.c_float * 4), # Slip ratio for each wheel
("m_wheel_slip_angle", ctypes.c_float * 4), # Slip angles for each wheel
("m_wheel_lat_force", ctypes.c_float * 4), # Lateral forces for each wheel
("m_wheel_long_force", ctypes.c_float * 4), # Longitudinal forces for each wheel
("m_height_of_cog_above_ground", ctypes.c_float), # Height of centre of gravity above ground
("m_local_velocity_x", ctypes.c_float), # Velocity in local space – metres/s
("m_local_velocity_y", ctypes.c_float), # Velocity in local space
("m_local_velocity_z", ctypes.c_float), # Velocity in local space
("m_angular_velocity_x", ctypes.c_float), # Angular velocity x-component – radians/s
("m_angular_velocity_y", ctypes.c_float), # Angular velocity y-component
("m_angular_velocity_z", ctypes.c_float), # Angular velocity z-component
("m_angular_acceleration_x", ctypes.c_float), # Angular acceleration x-component – radians/s/s
("m_angular_acceleration_y", ctypes.c_float), # Angular acceleration y-component
("m_angular_acceleration_z", ctypes.c_float), # Angular acceleration z-component
("m_front_wheels_angle", ctypes.c_float), # Current front wheels angle in radians
("m_wheel_vert_force", ctypes.c_float * 4), # Vertical forces for each wheel
("m_front_aero_height", ctypes.c_float), # Front plank edge height above road surface
("m_rear_aero_height", ctypes.c_float), # Rear plank edge height above road surface
("m_front_roll_angle", ctypes.c_float), # Roll angle of the front suspension
("m_rear_roll_angle", ctypes.c_float), # Roll angle of the rear suspension
("m_chassis_yaw", ctypes.c_float) # Yaw angle of the chassis relative to the direction of motion - radians
]
class TimeTrialDataSet(Packet):
_fields_ = [
("m_car_idx", ctypes.c_uint8), # Index of the car this data relates to
("m_team_id", ctypes.c_uint8), # Team id - see appendix
("m_lap_time_in_ms", ctypes.c_uint32), # Lap time in milliseconds
("m_sector1_time_in_ms", ctypes.c_uint32), # Sector 1 time in milliseconds
("m_sector2_time_in_ms", ctypes.c_uint32), # Sector 2 time in milliseconds
("m_sector3_time_in_ms", ctypes.c_uint32), # Sector 3 time in milliseconds
("m_traction_control", ctypes.c_uint8), # 0 = off, 1 = medium, 2 = full
("m_gearbox_assist", ctypes.c_uint8), # 1 = manual, 2 = manual & suggested gear, 3 = auto
("m_anti_lock_brakes", ctypes.c_uint8), # 0 (off) - 1 (on)
("m_equal_car_performance", ctypes.c_uint8), # 0 = Realistic, 1 = Equal
("m_custom_setup", ctypes.c_uint8), # 0 = No, 1 = Yes
("m_valid", ctypes.c_uint8), # 0 = invalid, 1 = valid
]
class PacketTimeTrialData(Packet):
_fields_ = [
("m_header", PacketHeader), # Header
("m_player_session_best_data_set", TimeTrialDataSet), # Player session best data set
("m_personal_best_data_set", TimeTrialDataSet), # Personal best data set
("m_rival_data_set", TimeTrialDataSet), # Rival data set
]
class EventStringCode(Enum):
SSTA = b'SSTA' # Session Started
SEND = b'SEND' # Session Ended
FTLP = b'FTLP' # Fastest Lap
RTMT = b'RTMT' # Retirement
DRSE = b'DRSE' # DRS enabled
DRSD = b'DRSD' # DRS disabled
TMPT = b'TMPT' # Team mate in pits
CHQF = b'CHQF' # Chequered flag
RCWN = b'RCWN' # Race Winner
PENA = b'PENA' # Penalty Issued
SPTP = b'SPTP' # Speed Trap Triggered
STLG = b'STLG' # Start lights
DTSV = b'DTSV' # Drive through served
SGSV = b'SGSV' # Stop go served
FLBK = b'FLBK' # Flashback
BUTN = b'BUTN' # Button status
OVTK = b'OVTK' # Overtake
SCDB = b'SCDB' # Safety Car
COLS = b'COLS' # Collision
class F1TelemetryClient:
# Map packet IDs to their corresponding packet classes
PACKET_TYPES = {
PacketID.MOTION: PacketMotionData,
PacketID.SESSION: PacketSessionData,
PacketID.LAP_DATA: PacketLapData,
PacketID.EVENT: PacketEventData,
PacketID.PARTICIPANTS: PacketParticipantsData,
PacketID.CAR_SETUPS: PacketCarSetupData,
PacketID.CAR_TELEMETRY: PacketCarTelemetryData,
PacketID.CAR_STATUS: PacketCarStatusData,
PacketID.FINAL_CLASSIFICATION: PacketFinalClassificationData,
PacketID.LOBBY_INFO: PacketLobbyInfoData,
PacketID.CAR_DAMAGE: PacketCarDamageData,
PacketID.SESSION_HISTORY: PacketSessionHistoryData,
PacketID.TYRE_SETS: PacketTyreSetsData,
PacketID.MOTION_EX: PacketMotionExData,
PacketID.TIME_TRIAL: PacketTimeTrialData
}
def __init__(self, ip="0.0.0.0", port=20777):
self.ip = ip
self.port = port
self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self.socket.bind((self.ip, self.port))
self.socket.setblocking(False)
self.player_car_index = None
def receive_packet(self):
"""
Try to receive a UDP packet and parse it into the appropriate packet structure.
Returns the parsed packet object or None if no data is available.
"""
try:
data, addr = self.socket.recvfrom(2048)
# First, parse just the header to identify the packet type
header = PacketHeader.from_buffer_copy(data)
# Track player car index
if self.player_car_index is None:
self.player_car_index = header.m_player_car_index
# If we have a packet class for this packet type, parse and return it
packet_id = header.m_packet_id
if packet_id in self.PACKET_TYPES:
# Use the appropriate packet class to parse the data
packet_class = self.PACKET_TYPES[packet_id]
return packet_class.from_buffer_copy(data)
return None
except BlockingIOError:
# No data available, return None
return None
except Exception as e:
print(f"Error receiving packet: {e}")
return None
def run(self, callback=None):
"""Main loop to continually receive packets"""
print(f"Listening for F1 24 telemetry on {self.ip}:{self.port}")
try:
while True:
packet = self.receive_packet()
if packet and callback:
callback(packet)
# Small sleep to prevent maxing out CPU
time.sleep(0.001)
except KeyboardInterrupt:
print("Shutting down telemetry client...")
finally:
self.socket.close()
if __name__ == "__main__":
# Example usage - just print data from every packet type
def raw_packet_handler(packet):
if isinstance(packet, PacketMotionData):
# print(f"Received MOTION packet, frame: {packet.m_header.m_frame_identifier}, packet: {packet.to_dict()}")
# Access to raw packet data without transformation
player_index = packet.m_header.m_player_car_index
player_car = packet.m_car_motion_data[player_index]
# print(f"player_car: {player_car.m_g_force_lateral}")
elif isinstance(packet, PacketSessionData):
# print(f"Received SESSION packet, frame: {packet.m_header.m_frame_identifier}, packet: {packet.to_dict()}")
m_speed_units_lead_player = packet.m_speed_units_lead_player
# print(f"m_speed_units_lead_player: {m_speed_units_lead_player}")
elif isinstance(packet, PacketLapData):
# print(f"Received LAP_DATA packet, frame: {packet.m_header.m_frame_identifier}, packet: {packet.to_dict()}")
player_index = packet.m_header.m_player_car_index
m_lap_data = packet.m_lap_data[player_index]
# print(f"m_current_lap_time_in_ms: {m_lap_data.m_current_lap_time_in_ms}")
elif isinstance(packet, PacketEventData):
# print(f"Received EVENT packet, frame: {packet.m_header.m_frame_identifier}, packet: {packet.to_dict()}")
event_code = bytes(packet.m_event_string_code)
if event_code == EventStringCode.PENA.value:
penalty = packet.m_event_details.penalty # see EventDataDetails class to check variable depending on event_code
# print(f"Penalty for vehicle {penalty.vehicle_idx}, type: {penalty.penalty_type}")
elif isinstance(packet, PacketParticipantsData):
# print(f"Received PARTICIPANTS packet, frame: {packet.m_header.m_frame_identifier}, packet: {packet.to_dict()}")
player_index = packet.m_header.m_player_car_index
m_name = packet.m_participants[player_index].m_name
# print(f"m_name: {m_name}")
elif isinstance(packet, PacketCarSetupData):
# print(f"Received CAR_SETUPS packet, frame: {packet.m_header.m_frame_identifier}, packet: {packet.to_dict()}")
player_index = packet.m_header.m_player_car_index
m_brake_bias = packet.m_car_setups[player_index].m_brake_bias
# print(f"m_brake_bias: {m_brake_bias}")
elif isinstance(packet, PacketCarTelemetryData):
# print(f"Received CAR_TELEMETRY packet, frame: {packet.m_header.m_frame_identifier}, packet: {packet.to_dict()}")
player_index = packet.m_header.m_player_car_index
m_gear = packet.m_car_telemetry_data[player_index].m_gear
# print(f"m_gear: {m_gear}")
elif isinstance(packet, PacketCarStatusData):
# print(f"Received CAR_STATUS packet, frame: {packet.m_header.m_frame_identifier}, packet: {packet.to_dict()}")
player_index = packet.m_header.m_player_car_index
m_fuel_remaining_laps = packet.m_car_status_data[player_index].m_fuel_remaining_laps
# print(f"m_fuel_remaining_laps: {m_fuel_remaining_laps}")
elif isinstance(packet, PacketFinalClassificationData):
# print(f"Received FINAL_CLASSIFICATION packet, frame: {packet.m_header.m_frame_identifier}, packet: {packet.to_dict()}")
player_index = packet.m_header.m_player_car_index
m_result_status = packet.m_classification_data[player_index].m_result_status
# print(f"m_result_status: {m_result_status}")
elif isinstance(packet, PacketLobbyInfoData):
# print(f"Received LOBBY_INFO packet, frame: {packet.m_header.m_frame_identifier}, packet: {packet.to_dict()}")
player_index = packet.m_header.m_player_car_index
m_name = packet.m_lobby_players[player_index].m_name
# print(f"m_name: {m_name}")
elif isinstance(packet, PacketCarDamageData):
# print(f"Received CAR_DAMAGE packet, frame: {packet.m_header.m_frame_identifier}, packet: {packet.to_dict()}")
player_index = packet.m_header.m_player_car_index
m_tyres_wear = packet.m_car_damage_data[player_index].m_tyres_wear[0]
# print(f"m_tyres_wear: {m_tyres_wear}")
elif isinstance(packet, PacketSessionHistoryData):
# print(f"Received SESSION_HISTORY packet, frame: {packet.m_header.m_frame_identifier}, packet: {packet.to_dict()}")
player_index = packet.m_header.m_player_car_index
if packet.m_car_idx == player_index:
m_sector1_time_ms_part = packet.m_lap_history_data[0].m_sector1_time_ms_part
# print(f"m_sector1_time_ms_part: {m_sector1_time_ms_part}")
elif isinstance(packet, PacketTyreSetsData):
# print(f"Received TYRE_SETS packet, frame: {packet.m_header.m_frame_identifier}, packet: {packet.to_dict()}")
player_index = packet.m_header.m_player_car_index
if packet.m_car_idx == player_index:
m_wear = packet.m_tyre_set_data[0].m_wear
# print(f"m_wear: {m_wear}")
elif isinstance(packet, PacketMotionExData):
# print(f"Received MOTION_EX packet, frame: {packet.m_header.m_frame_identifier}, packet: {packet.to_dict()}")
m_wheel_speed = packet.m_wheel_speed[0]
# print(f"m_wheel_speed: {m_wheel_speed}")
elif isinstance(packet, PacketTimeTrialData):
# print(f"Received TIME_TRIAL packet, frame: {packet.m_header.m_frame_identifier}, packet: {packet.to_dict()}")
m_lap_time_in_ms = packet.m_personal_best_data_set.m_lap_time_in_ms
# print(f"m_lap_time_in_ms: {m_lap_time_in_ms}")
else:
print(f"Received packet type: {packet.m_header.m_packet_id}")
# Create a client and register packet types
client = F1TelemetryClient()
# Run client with raw packet handler
client.run(callback=raw_packet_handler)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment