ACC — UDP Telemetry Protocol Specification

# ACC — UDP Telemetry Protocol Specification

> **Game**: Assetto Corsa Competizione (2019) by Kunos Simulazioni
> **Engine**: Unreal Engine 4
> **Parser status**: ❌ Not implemented in rusty-telemetry
> **Platform note**: Runs on Windows; Linux via Proton works but shared memory is unavailable

---

## Key Finding: ACC Protocol Is Completely Different from AC

ACC uses **Unreal Engine 4**, not AC's in-house engine. The telemetry protocol is entirely separate:
- **Does NOT use** AC's KSUDP (port 9996)
- **Does NOT use** AC's Telemetry Tool plugin (port 10101)
- **Does NOT use** AC's Lua plugin (port 5005)
- **Requires its own parser** written from scratch

ACC provides telemetry through two channels:
1. **UDP broadcast** (cross-platform, works on Linux/Proton) — moderate data depth
2. **Shared memory** (Windows only) — richer data but inaccessible on Linux

---

## Cross-References

- **AC original protocol**: [Assetto Corsa — UDP Telemetry Protocol Specification](joplin://aed9f3be040943048273a16e05a8100f)
- **AC EVO status**: [AC EVO — Telemetry Status & Research](joplin://2171d34ab9c1431ea3a979d30d206e23)
- **AC Rally status**: [AC Rally — Telemetry Status & Research](joplin://b7b331aa87544b6ebe5db5b8d7bcd2a0)
- **PCARS protocol**: [Project CARS 1 & 2 — UDP Telemetry Protocol Specification](joplin://c6bd2c45938246fa9d61776deae9874b)
- **DiRT Rally protocol**: [DiRT Rally 1 & 2.0 — UDP Telemetry Protocol Specification](joplin://877a753ad06a40e08059834d8c8fb438)

---

## Connection Protocol (Registration Handshake)

ACC uses a **connection-oriented registration model** similar in concept to AC's KSUDP but with a completely different binary protocol:

### Registration Flow

1. ACC listens on a configurable UDP port (set in-game)
2. Client sends a **registration request** to ACC's port
3. ACC starts broadcasting telemetry packets to the client's return address
4. Client must send **keep-alive** registration packets periodically (~every 10 seconds)
5. If keep-alive stops, ACC stops broadcasting after a timeout (~30 seconds)

### Registration Packet (Client → ACC)

| Offset | Size | Type | Field | Value |
|---|---|---|---|---|
| 0 | 1 | uint8 | packet_type | 1 = registration request |
| 1 | 4 | char[4] | display_name | Client name (e.g. "rusty-telemetry") |

### In-Game Configuration

- **Location**: Options → System → UDP Configuration
- **Settings**:
  - Enable UDP: On
  - Target IP: `127.0.0.1` (for local analysis)
  - Target Port: configurable (commonly `9000`)
  - Send Rate: configurable (e.g. "Second" = ~1 Hz, "Heavy" = ~10 Hz)

---

## Packet Types

ACC uses a **multi-packet broadcast model** with distinct packet IDs:

| Type ID | Name | Description | Rate |
|---|---|---|---|
| 0 | Entry Request | Registration/keep-alive (client → ACC) | Every ~10s |
| 1 | Car Info | Driver name, car name, track name | On registration |
| 2 | Car Damage | Tyre/suspension/aero damage | ~2 Hz |
| 3 | Car Setup | Tyre compound, pressures, brake bias | On change |
| 4 | Lap Data | Lap times, splits, positions, session state | On lap events |
| 5 | Realtime Update | Speed, RPM, gear, inputs, fuel, position | ~10 Hz |
| 6 | Track Map | Sector boundaries, track data | On registration |

---

## Broadcast 5: Realtime Car Update (Primary Physics Packet)

**This is the main telemetry packet for live analysis.**

### Header

| Offset | Size | Type | Field |
|---|---|---|---|
| 0 | 1 | uint8 | packet_type = 5 |
| 1 | 4 | float32_le | car_position | Race position (1-indexed) |

### Per-Car Data (repeated for each car in session)

| Offset | Size | Type | Field | Notes |
|---|---|---|---|---|
| 0 | 1 | uint8 | car_index | Unique car identifier |
| 1 | 1 | uint8 | driver_index | |
| 2 | 1 | uint8 | gear | Current gear (+ reverse = -1, neutral = 0) |
| 3 | 2 | uint16_le | rpm | Current engine RPM × 4 (divide by 4) |
| 5 | 2 | uint16_le | speed_ms | Speed in m/s × 1000 (divide by 1000) |
| 7 | 2 | uint16_le | best_lap_ms | Best lap time in ms |
| 9 | 2 | uint16_le | last_lap_ms | Last lap time in ms |
| 11 | 2 | uint16_le | current_lap_ms | Current lap time in ms |
| 13 | 2 | int16_le | world_position_x | World X (cm) |
| 15 | 2 | int16_le | world_position_y | World Y (cm) |
| 17 | 2 | int16_le | world_position_z | World Z (cm) |
| 19 | 1 | uint8 | throttle | 0–255 |
| 20 | 1 | uint8 | steer | 0–255 (128 = center) |
| 21 | 1 | uint8 | brake | 0–255 |
| 22 | 1 | uint8 | drs | DRS state |
| 23 | 1 | uint8 | pits | Pit status |
| 24 | 2 | uint16_le | fuel | Fuel remaining (liters × 10) |
| 26 | 2 | uint16_le | position | Track position (0 = start/finish) |
| 28 | 2 | uint16_le | laps | Completed laps |

> **Note**: Exact byte offsets may vary between ACC versions. The above is based on community documentation and may need verification against live data. ACC's protocol has evolved across patches (1.0 → 1.9+).

---

## Broadcast 2: Car Damage

| Field | Type | Notes |
|---|---|---|
| car_index | uint8 | |
| tyre_damage | float32_le × 4 | Per-wheel (0.0 = perfect, 1.0 = destroyed) |
| suspension_damage | float32_le × 4 | Per-wheel |
| aero_damage | float32_le | Overall aero (0.0–1.0) |
| engine_damage | float32_le | Engine wear (0.0–1.0) |

---

## Broadcast 3: Car Setup

| Field | Type | Notes |
|---|---|---|
| car_index | uint8 | |
| tyre_compound | uint8 | 0=Dry, 1=Wet |
| tyre_pressure | float32_le × 4 | Per-wheel PSI |
| brake_bias | float8 | 0.0–1.0 |

---

## Broadcast 4: Lap Data

| Field | Type | Notes |
|---|---|---|
| car_index | uint8 | |
| lap_time_ms | uint32_le | |
| splits | float32_le × 3 | Sector times |
| is_valid | bool | Lap validity |
| session_type | uint8 | Practice/Qualifying/Race |

---

## Data Depth vs AC Telemetry Tool

| Capability | AC Telemetry Tool (10101) | ACC UDP |
|---|---|---|
| **Update rate** | 60 Hz | ~10 Hz |
| **Speed/RPM/Gear** | ✅ | ✅ |
| **Driver inputs** | ✅ (float 0–1) | ✅ (uint8 0–255) |
| **World position** | ✅ (float32 × 3) | ✅ (int16 × 3, cm) |
| **Spline position** | ✅ (float64) | ❌ |
| **G-forces** | ✅ 3-axis | ❌ (not in UDP) |
| **Tyre slip ratio** | ✅ Per-wheel | ❌ |
| **Tyre slip angle** | ✅ Per-wheel | ❌ |
| **Tyre core temps** | ✅ Per-wheel | ❌ (only in shared memory) |
| **nd_slip** | ✅ Per-wheel | ❌ |
| **Multi-car** | ✅ All drivers | ✅ All drivers |
| **Damage model** | ❌ | ✅ Per-wheel + aero + engine |
| **Tyre pressures** | ❌ | ✅ In setup packet |
| **Fuel** | ❌ | ✅ In realtime packet |
| **Lap validity** | ✅ | ✅ |
| **Weather** | ❌ | ✅ |
| **Tyre compound** | ✅ (string) | ✅ (enum) |

### Key ACC Limitations (vs AC Telemetry Tool)

1. **No G-force data in UDP** — only available via Windows shared memory
2. **No tyre physics detail** — no slip ratios, slip angles, tyre temps in UDP
3. **No spline position** — track progress must be calculated from world coordinates
4. **Lower update rate** — 10 Hz vs 60 Hz
5. **Quantized values** — uint8/uint16 instead of float32, reduced precision
6. **No velocity vectors** — no world/local velocity in UDP

### ACC Advantages (vs AC Telemetry Tool)

1. **Damage model** — per-wheel + aero + engine damage tracking
2. **Fuel management** — fuel remaining in liters
3. **Tyre pressures** — actual PSI values per wheel
4. **Official protocol** — documented by Kunos, not dependent on third-party plugin
5. **Tyre compound** — wet/dry selection
6. **Weather data** — track/ambient conditions

---

## Shared Memory (Windows Only — NOT Available on Linux)

ACC exposes more detailed data via Windows shared memory:
- Physical memory mapped file: `Local\ACCUdpSharedMemory`
- Contains: full physics state, tyre temps, G-forces, suspension details
- **Not accessible on Linux/Proton** — the Wine/Proton shared memory translation layer does not support this

This is why ACC UDP telemetry analysis on Linux is more limited than on Windows.

---

## Rust Implementation Plan

### Recommended Port

| Port | Use |
|---|---|
| Configurable (default: 9000) | ACC UDP telemetry |

### Parser Architecture

```
src/
  parser_acc.rs          — Main ACC UDP parser
  acc_registration.rs    — Registration/keep-alive handler
```

### Implementation Steps

1. **Registration handler**: Send periodic keep-alive packets to ACC's port
2. **Packet dispatcher**: Read byte 0 for packet type, dispatch to type-specific parser
3. **Realtime update parser** (type 5): Speed, RPM, gear, inputs, fuel, position
4. **Damage parser** (type 2): Per-wheel + aero + engine damage
5. **Setup parser** (type 3): Tyre pressures, brake bias
6. **Lap data parser** (type 4): Lap times, sectors, validity
7. **Track map parser** (type 6): Sector boundaries

### Estimated Effort

~5–7 days for a complete ACC parser with all packet types, assuming live data available for verification.

---

## Live Verification Needed

**No ACC data has been captured yet.** The protocol structure above is based on community documentation. Verification requires:
1. ACC installed and configured for UDP output
2. rusty-telemetry listening on the configured port
3. Registration packet sent and ACC responding
4. Packet captures to verify byte offsets against documentation

---

*Created: 2026-06-06*
*Status: Research phase — no live verification yet*
*Next step: Install ACC, configure UDP, capture and verify packets*

id: 6ae7005d9810437093d63470cff98b59
parent_id: 94aa3283ead4477d8449e324a27eb3d0
created_time: 2026-06-06T07:54:52.419Z
updated_time: 2026-06-06T08:27:31.459Z
is_conflict: 0
latitude: 0.00000000
longitude: 0.00000000
altitude: 0.0000
author: 
source_url: 
is_todo: 0
todo_due: 0
todo_completed: 0
source: joplin-desktop
source_application: net.cozic.joplin-desktop
application_data: 
order: 1780732492419
user_created_time: 2026-06-06T07:54:52.419Z
user_updated_time: 2026-06-06T08:27:31.459Z
encryption_cipher_text: 
encryption_applied: 0
markup_language: 1
is_shared: 0
share_id: 
conflict_original_id: 
master_key_id: 
user_data: 
deleted_time: 0
type_: 1