id: 9a5607b540c842bab336a8b16639d6c1
parent_id: 483eaebb6f7745e997075b942363c050
item_type: 1
item_id: 6c0dcb2a567348fd9796f50c790082e4
item_updated_time: 1780473448206
title_diff: "[]"
body_diff: "[{\"diffs\":[[0,\"th\\\n\\\n\"],[-1,\"### Starting Point: `ac-tracer` by Tobi\\\n- CSP Lua-based application for driver input telemetry\\\n- Can be forked and adapted — proven data reading and processing pipeline\\\n- High-frequency data capture suitable for coaching\\\n- Provides patterns for: data reading, signal processing, real-time analysis, in-game UI\\\n- **Main modification needed**: Add UDP output module (serialize data + send via socket)\\\n\\\n\"],[0,\"---\\\n\"]],\"start1\":3177,\"start2\":3177,\"length1\":408,\"length2\":8},{\"diffs\":[[0,\"cture — \"],[-1,\"Dual\"],[1,\"Triple\"],[0,\"-Source \"]],\"start1\":3199,\"start2\":3199,\"length1\":20,\"length2\":22},{\"diffs\":[[0,\"etry\"],[1,\" for AC\"],[0,\"\\\n\\\n### T\"],[-1,\"wo\"],[1,\"hree\"],[0,\" Ind\"]],\"start1\":3226,\"start2\":3226,\"length1\":17,\"length2\":26},{\"diffs\":[[0,\" Sources\"],[-1,\" for AC\"],[0,\"\\\n\\\nAC pro\"]],\"start1\":3265,\"start2\":3265,\"length1\":23,\"length2\":16},{\"diffs\":[[0,\"hrough t\"],[-1,\"wo\"],[1,\"hree\"],[0,\" indepen\"]],\"start1\":3298,\"start2\":3298,\"length1\":18,\"length2\":20},{\"diffs\":[[0,\"nels\"],[-1,\" that complement each other\"],[0,\":\\\n\\\n```\\\n┌\"],[1,\"────────\"],[0,\"────\"]],\"start1\":3327,\"start2\":3327,\"length1\":43,\"length2\":24},{\"diffs\":[[0,\"────────────────\"],[1,\"─────\"],[0,\"┐\\\n│\"],[1,\"  \"],[0,\"                \"]],\"start1\":3392,\"start2\":3392,\"length1\":35,\"length2\":42},{\"diffs\":[[0,\" Proton)\"],[1,\"          \"],[0,\"        \"]],\"start1\":3456,\"start2\":3456,\"length1\":16,\"length2\":26},{\"diffs\":[[0,\"                \"],[1,\"             \"],[0,\"│\\\n│  ┌──────────\"]],\"start1\":3538,\"start2\":3538,\"length1\":32,\"length2\":45},{\"diffs\":[[0,\"────────\"],[1,\"┐ ┌\"],[0,\"──────\"],[-1,\"┐  ┌\"],[1,\"──────────\"],[0,\"───────\"],[1,\"┐ ┌\"],[0,\"────────\"]],\"start1\":3585,\"start2\":3585,\"length1\":33,\"length2\":45},{\"diffs\":[[0,\"│  │ AC \"],[-1,\"Built-in \"],[0,\"Engine  \"]],\"start1\":3644,\"start2\":3644,\"length1\":25,\"length2\":16},{\"diffs\":[[0,\"    \"],[-1,\"│\"],[1,\" \"],[0,\"  │ \"],[-1,\"ac-t\"],[1,\"│ T\"],[0,\"elemetry\"],[-1,\"-plugin      │ │\\\n│  │ (always runs, no plug\"],[1,\" Tool Plugin  │ │ ac-telemetry-    │ │\\\n│  │ (built-\"],[0,\"in)  \"],[-1,\"│  │ (CSP Lua app)           \"],[1,\"        │ │ (Python, 3rd party)    │ │ plugin (CSP Lua)\"],[0,\" │ │\"]],\"start1\":3662,\"start2\":3662,\"length1\":102,\"length2\":135},{\"diffs\":[[0,\"            \"],[-1,\"      \"],[0,\"│\"],[-1,\" \"],[0,\" │ \"],[1,\"IkoRein v1.3\"],[0,\"            \"]],\"start1\":3811,\"start2\":3811,\"length1\":35,\"length2\":40},{\"diffs\":[[0,\"v1.3            \"],[-1,\"   \"],[1,\"│ │ (ours)\"],[0,\"           │ │\\\n│\"]],\"start1\":3835,\"start2\":3835,\"length1\":35,\"length2\":42},{\"diffs\":[[0,\"  │ \"],[-1,\"Reads: shared memory\"],[1,\"Binary, ~20Hz \"],[0,\"      │\"],[-1,\" \"],[0,\" │ \"],[-1,\"Reads: CSP Lua API        │ │\\\n│  │ Format: binary (undoc.)   │  │ Format: JSON (defined)    │ │\\\n│  │ Rate: ~20Hz fixed   \"],[1,\"Binary, all cars       │ │ JSON, 60Hz       │ │\\\n│  │ Basic fields        │ │ Full fields incl.\"],[0,\"      │\"],[-1,\" \"],[0,\" │ \"],[-1,\"Rate: c\"],[1,\"C\"],[0,\"onfi\"]],\"start1\":3877,\"start2\":3877,\"length1\":178,\"length2\":137},{\"diffs\":[[0,\"gurable \"],[-1,\"60Hz\"],[1,\" \"],[0,\"   │ │\\\n│\"]],\"start1\":4014,\"start2\":4014,\"length1\":20,\"length2\":17},{\"diffs\":[[0,\"  │ \"],[-1,\"Target: 127.0.0.1:9996\"],[1,\"Always runs     \"],[0,\"    │\"],[-1,\" \"],[0,\" │ \"],[-1,\"Target: configurable IP\"],[1,\"wheel slip, tyre temps │ │ CSP extensions\"],[0,\"   │\"],[1,\" │\"],[0,\"\\\n│  \"]],\"start1\":4031,\"start2\":4031,\"length1\":66,\"length2\":79},{\"diffs\":[[0,\"│ │\\\n│  └────────\"],[1,\"┬───────\"],[0,\"──\"],[-1,\"┬\"],[0,\"──\"],[1,\"┘ └\"],[0,\"─────────────┘  \"]],\"start1\":4103,\"start2\":4103,\"length1\":37,\"length2\":47},{\"diffs\":[[0,\"┘ └─────────\"],[1,\"┬─\"],[0,\"────\"],[-1,\"┘  └──\"],[1,\"─────────┘ └\"],[0,\"────────┬───\"]],\"start1\":4131,\"start2\":4131,\"length1\":34,\"length2\":42},{\"diffs\":[[0,\"──┬─────────\"],[-1,\"───────\"],[0,\"┘ │\\\n│       \"]],\"start1\":4167,\"start2\":4167,\"length1\":31,\"length2\":24},{\"diffs\":[[0,\"        \"],[-1,\"  │ UDP\"],[1,\"│\"],[0,\" :9996  \"]],\"start1\":4187,\"start2\":4187,\"length1\":23,\"length2\":17},{\"diffs\":[[0,\"    \"],[1,\"│ :10101                \"],[0,\"   │\"],[-1,\" UDP\"],[0,\" :50\"]],\"start1\":4215,\"start2\":4215,\"length1\":16,\"length2\":36},{\"diffs\":[[0,\"005     \"],[-1,\"   \"],[0,\"│\\\n└─────\"]],\"start1\":4250,\"start2\":4250,\"length1\":19,\"length2\":16},{\"diffs\":[[0,\"  │\\\n└───────────\"],[1,\"┼─────\"],[0,\"──\"],[-1,\"┼\"],[0,\"────\"],[1,\"────────────┼\"],[0,\"────────────────\"]],\"start1\":4256,\"start2\":4256,\"length1\":39,\"length2\":57},{\"diffs\":[[0,\"────\"],[-1,\"───────\"],[0,\"┘\\\n     \"],[1,\"       │\"],[0,\"    \"]],\"start1\":4330,\"start2\":4330,\"length1\":22,\"length2\":23},{\"diffs\":[[0,\"  │         \"],[-1,\"│\"],[0,\"    \"],[1,\"          │\"],[0,\"            \"]],\"start1\":4346,\"start2\":4346,\"length1\":29,\"length2\":39},{\"diffs\":[[0,\"    \"],[1,\"   ▼\"],[0,\"     \"],[-1,\"▼\"],[0,\"    \"],[1,\"              ▼\"],[0,\"    \"]],\"start1\":4406,\"start2\":4406,\"length1\":18,\"length2\":36},{\"diffs\":[[0,\"────────────────\"],[1,\"─────────────\"],[0,\"┐\\\n│\"],[1,\"  \"],[0,\"                \"]],\"start1\":4512,\"start2\":4512,\"length1\":35,\"length2\":50},{\"diffs\":[[0,\"INE \"],[-1,\"                         │\\\n│                   \"],[1,\"—\"],[0,\" rus\"]],\"start1\":4579,\"start2\":4579,\"length1\":55,\"length2\":9},{\"diffs\":[[0,\"ry              \"],[1,\"     │\\\n│\"],[0,\"             │\\\n│\"]],\"start1\":4598,\"start2\":4598,\"length1\":32,\"length2\":40},{\"diffs\":[[0,\"│\\\n│             \"],[-1,\"│\\\n│\"],[0,\"                \"]],\"start1\":4619,\"start2\":4619,\"length1\":35,\"length2\":32},{\"diffs\":[[0,\"────\"],[-1,\"─────────────────────────────┐   │\\\n│  │     \"],[1,\" Multi-Port UDP Receiver ────────────────────┐ │\\\n│  │  :9996  ──→ parser-ksudp\"],[0,\"     \"],[1,\"──┐\"],[0,\"    \"],[-1,\"Multi-Port UDP Receiver\"],[1,\"                \"],[0,\"    \"]],\"start1\":4722,\"start2\":4722,\"length1\":84,\"length2\":114},{\"diffs\":[[0,\"               │\"],[-1,\"  \"],[0,\" │\\\n│  │  :9996 ─\"]],\"start1\":4834,\"start2\":4834,\"length1\":34,\"length2\":32},{\"diffs\":[[0,\"\\\n│  │  :\"],[-1,\"9996\"],[1,\"10101\"],[0,\" ──→ par\"]],\"start1\":4852,\"start2\":4852,\"length1\":20,\"length2\":21},{\"diffs\":[[0,\"ser-\"],[-1,\"ksudp ──┐                         │  \"],[1,\"telemetry   ──┼──→ Core Telemetry Model           │\"],[0,\" │\\\n│\"]],\"start1\":4873,\"start2\":4873,\"length1\":45,\"length2\":59},{\"diffs\":[[0,\"  :5005 \"],[1,\" \"],[0,\"──→ pars\"]],\"start1\":4935,\"start2\":4935,\"length1\":16,\"length2\":17},{\"diffs\":[[0,\"    \"],[1,\"     \"],[0,\"──\"],[-1,\"┼──→ Core Telemetry Model │  \"],[1,\"┤   + Per-Feed Status                │\"],[0,\" │\\\n│\"]],\"start1\":4957,\"start2\":4957,\"length1\":39,\"length2\":53},{\"diffs\":[[0,\"  :5015 \"],[1,\" \"],[0,\"──→ pars\"]],\"start1\":5013,\"start2\":5013,\"length1\":16,\"length2\":17},{\"diffs\":[[0,\"2   \"],[-1,\"──┤\"],[0,\"     \"],[-1,\"       \"],[1,\"──┤   + Data Dump per Feed\"],[0,\"    \"]],\"start1\":5035,\"start2\":5035,\"length1\":23,\"length2\":39},{\"diffs\":[[0,\"           │\"],[-1,\"  \"],[0,\" │\\\n│  │  :50\"]],\"start1\":5072,\"start2\":5072,\"length1\":26,\"length2\":24},{\"diffs\":[[0,\"  :5006 \"],[1,\" \"],[0,\"──→ pars\"]],\"start1\":5091,\"start2\":5091,\"length1\":16,\"length2\":17},{\"diffs\":[[0,\"r-pcars \"],[1,\"     \"],[0,\"──┘     \"]],\"start1\":5109,\"start2\":5109,\"length1\":16,\"length2\":21},{\"diffs\":[[0,\"        \"],[-1,\"│\"],[0,\"  \"],[1,\"          │\"],[0,\" │\\\n│  └─\"]],\"start1\":5142,\"start2\":5142,\"length1\":19,\"length2\":29},{\"diffs\":[[0,\"────\"],[-1,\"┘   │\\\n│\"],[1,\"────────────────┘ │\\\n│        \"],[0,\"    \"]],\"start1\":5219,\"start2\":5219,\"length1\":15,\"length2\":37},{\"diffs\":[[0,\"                \"],[1,\"     \"],[0,\"│\\\n│  ┌──────────\"]],\"start1\":5297,\"start2\":5297,\"length1\":32,\"length2\":37},{\"diffs\":[[0,\"────────────────\"],[-1,\"────┐\"],[1,\"┐                 \"],[0,\" │\\\n│  │ Plausibi\"]],\"start1\":5359,\"start2\":5359,\"length1\":37,\"length2\":50},{\"diffs\":[[0,\"I Coach         \"],[1,\"│             \"],[0,\"    \"],[-1,\"│\"],[0,\" │\\\n│  │ Checker \"]],\"start1\":5435,\"start2\":5435,\"length1\":37,\"length2\":50},{\"diffs\":[[0,\"    \"],[-1,\"    │ │\\\n│  │ (cross-ref)  │  │\"],[1,\"│                  │\\\n│  └──────────────┘  └───────────┘  └──────────────────┘                  │\\\n│                                  \"],[0,\"    \"]],\"start1\":5523,\"start2\":5523,\"length1\":38,\"length2\":140},{\"diffs\":[[0,\"        \"],[-1,\"│  │\"],[1,\"       \"],[0,\"        \"]],\"start1\":5662,\"start2\":5662,\"length1\":20,\"length2\":23},{\"diffs\":[[0,\"               │\"],[-1,\" │\"],[0,\"\\\n│  \"],[-1,\"└\"],[1,\"┌─────\"],[0,\"──────────────┘ \"]],\"start1\":5684,\"start2\":5684,\"length1\":39,\"length2\":42},{\"diffs\":[[0,\"────────────────\"],[-1,\"┘  └\"],[1,\"──\"],[0,\"───────────┘  └─\"]],\"start1\":5708,\"start2\":5708,\"length1\":36,\"length2\":34},{\"diffs\":[[0,\"────\"],[-1,\"┘  └──────────────────────┘ │\\\n└\"],[1,\"──────────────────────────────────────┐│\\\n│  │ Data Dump: ./data/<session>/<feed>_<timestamp>.{json,bin,csv}       ││\\\n│  └──────────────────────────────────────────────────────────────────────┘│\\\n└────────\"],[0,\"────\"]],\"start1\":5733,\"start2\":5733,\"length1\":39,\"length2\":211},{\"diffs\":[[0,\"────────\"],[1,\"─────\"],[0,\"┘\\\n```\\\n\\\n#\"]],\"start1\":5993,\"start2\":5993,\"length1\":16,\"length2\":21},{\"diffs\":[[0,\"### \"],[-1,\"Why Dual-Source?\"],[1,\"Source Comparison\"],[0,\"\\\n\\\n| \"]],\"start1\":6013,\"start2\":6013,\"length1\":24,\"length2\":25},{\"diffs\":[[0,\"lt-in) |\"],[1,\" Port 10101 (Telemetry Tool) |\"],[0,\" Port 50\"]],\"start1\":6061,\"start2\":6061,\"length1\":16,\"length2\":46},{\"diffs\":[[0,\"05 (our \"],[1,\"Lua \"],[0,\"plugin) \"]],\"start1\":6107,\"start2\":6107,\"length1\":16,\"length2\":20},{\"diffs\":[[0,\"---|\"],[1,\"---|\"],[0,\"\\\n| **\"],[-1,\"Availability** | Always runs, no install needed | Requires\"],[1,\"Origin** | AC engine | Python plugin (IkoRein) |\"],[0,\" CSP\"],[-1,\" +\"],[0,\" Lua\"]],\"start1\":6138,\"start2\":6138,\"length1\":77,\"length2\":69},{\"diffs\":[[0,\"app \"],[-1,\"enabled |\\\n| **Reliability** | Hardcoded in AC binary, never crashes | Lua script can crash (like current bug)\"],[1,\"(ours) |\\\n| **Status** | ✅ Always runs | ✅ **ENABLED** in python.ini | 🔧 Fixed, needs AC restart\"],[0,\" |\\\n|\"]],\"start1\":6208,\"start2\":6208,\"length1\":117,\"length2\":104},{\"diffs\":[[0,\"| Binary\"],[-1,\",\"],[0,\" \"],[1,\"(\"],[0,\"communit\"]],\"start1\":6324,\"start2\":6324,\"length1\":18,\"length2\":18},{\"diffs\":[[0,\"nity\"],[-1,\"-reverse-engineered | JSON, we define the\"],[1,\" RE) | Binary (struct in source) | JSON (our\"],[0,\" schema\"],[1,\")\"],[0,\" |\\\n| **\"],[-1,\"Config** | Hardcoded `127.0.0.1:9996` | C\"],[1,\"Rate** | ~20 Hz fixed | Per-frame | 60 Hz c\"],[0,\"onfi\"]],\"start1\":6339,\"start2\":6339,\"length1\":104,\"length2\":110},{\"diffs\":[[0,\"ble \"],[-1,\"host/port \"],[0,\"|\\\n| **\"],[-1,\"Rate** | ~20 Hz fixed | Configurable (60 Hz default) |\\\n| **Data depth** | Basic telemetry (speed, inputs, G, position) | Extended (tyre slip, temps, pressures, damage) |\\\n| **Cross-machine** | ❌ Localhost only | ✅ Any LAN IP |\\\n| **Coaching tier** | Basic + intermediate | Advanced (tyre management, traction analysis) |\\\n\\\n### Coaching Capability by Data Source\\\n\\\n| Coaching Use Case | Built-in (9996) | Plugin (5005) | Combined |\\\n|---|---|---|---|\\\n| **Lap time analysis** | ✅ Sufficient | ✅ Sufficient | ✅ Cross-validate lap times |\\\n| **Braking point coaching** | ✅ Sufficient | ✅ Sufficient | ✅ Brake onset plausibility |\\\n| **Racing line analysis** | ⚠️ Adequate (has world pos + G) | ⚠️ Adequate (has G, no world pos yet) | ✅ World pos from 9996 + tyre slip from 5005 |\\\n| **Throttle application** | ⚠️ Adequate (wheel speed proxy) | ✅ Sufficient (wheel_slip) | ✅ Wheel speed vs wheel slip cross-check |\\\n| **Corner entry/exit** | ⚠️ Adequate (steering vs G, ~70% confidence) | ✅ Sufficient (wheel_slip, ~95% confidence) | ✅ G-force method validated by slip data |\\\n| **Tyre management** | ❌ No tyre data | ✅ Full tyre temps/pressures | ✅ Only from plugin |\\\n| **Damage monitoring** | ❌ No damage data | ✅ 5-zone damage | ✅ Only from plugin |\\\n\\\n### Data Plausibility Checking\\\n\\\nCross-referencing the two sources enables automatic data quality validation:\\\n\\\n| Check | Method | Detects |\\\n|---|---|---|\\\n| **Speed comparison** | `abs(speed_9996 - speed_5005) < threshold` | Plugin reading error, stale data |\\\n| **Input correlation** | `throttle_9996 ≈ throttle_5005` | Plugin desync |\\\n| **Lap time match** | `lap_time_9996 == lap_time_5005` | Timing drift between sources |\\\n| **G-force consistency** | `G_LAT_9996 ≈ g_forces.y_5005` | Coordinate system mismatch |\\\n| **Suspension correlation** | `susp_9996[i] ≈ suspension_travel_5005[i]` | Wheel index mapping error |\\\n| **Packet rate monitoring** | Track pkts/sec on each port | Plugin crash detection (9996 keeps flowing) |\\\n\\\nIf the plugin crashes (like the current LuaSocket bug), the system automatically falls back to port 9996 data and flags the plugin as offline — basic coaching continues uninterrupted.\\\n\\\n### AC Built-in UDP Protocol (Port 9996) — Reference\\\n\\\n**Status**: Binary protocol reverse-engineered by community. Not documented in the AC installation. The packet structure mirrors AC's shared memory layout (used by CrewChief, SIM Dashboard, SIM Hub).\\\n\\\n**Confirmed fields** (from AC log telemetry channels + community documentation):\\\n\\\n| Field | Type | Rate | Notes |\\\n|---|---|---|---|\\\n| packetId | int32 | — | Sequential packet counter |\\\n| speedKmh | float | ~20 Hz | Vehicle speed |\\\n| rpm | int32 | ~20 Hz | Engine RPM |\\\n| gear | int32 | ~20 Hz | Current gear (-1=N, 0=R, 1-6=forward) |\\\n| gas | float | ~20 Hz | Throttle 0–1 |\\\n| brake | float | ~20 Hz | Brake 0–1 |\\\n| clutch | float | ~20 Hz | Clutch 0–1 |\\\n| steerAngle | float | ~20 Hz | Steering angle (radians) |\\\n| G_LAT | float | ~20 Hz | Lateral G-force |\\\n| G_LON | float | ~20 Hz | Longitudinal G-force |\\\n| splinePosition | float | ~20 Hz | Normalized track position 0–1 |\\\n| worldPosition | vec3 | ~20 Hz | World coordinates (x, y, z) |\\\n| suspensionTravel[4] | float×4 | **200 Hz** | Per-wheel suspension travel |\\\n| wheelSpeed[4] | float×4 | ~20 Hz | Per-wheel speed |\\\n| lapTime | float | ~20 Hz | Current lap time (ms) |\\\n| lapCount | int | ~20 Hz | Current lap number |\\\n| fuel | float | ~20 Hz | Fuel level 0–1 |\\\n| bestLap | float | — | Best lap time (ms) |\\\n| lastLap | float | — | Last completed lap time (ms) |\\\n\\\n**Limitations for coaching:**\\\n- No wheel slip / tyre slip data → understeer/oversteer detection is inferential only (~70% confidence)\\\n- No vertical G-force → bump/aero analysis not possible\\\n- No tyre temperatures → tyre management coaching impossible\\\n- No tyre pressures → tyre strategy coaching impossible\\\n- No damage data → damage-aware strategy not possible\\\n- Hardcoded to localhost:9996 → requires game machine to relay for cross-machine use\\\n\\\n### Server Plugin Protocol (Port 11000) — Reference\\\n\\\n**Fully documented** in `sdk/dev/acRemoteServerUDP_Example/`. This is a different protocol for server-side plugins (multiplayer monitoring, race control). Provides:\\\n- `ACSP_CAR_UPDATE` — position, velocity, gear, RPM, spline for ALL cars\\\n- `ACSP_LAP_COMPLETED` — lap times with cuts, grip level\\\n- `ACSP_CLIENT_EVENT` — collisions (car-car, car-environment) with impact speed\\\n- `ACSP_SESSION_INFO` — session type, track, weather\\\n\\\nOnly available when running an AC server instance.\"],[1,\"Data depth** | Basic | **Full** (wheel slip, tyres, ERS) | Configurable, CSP extensions |\\\n| **All cars** | No (focused car) | **Yes** (multi-driver packets) | No (focused car, can extend) |\\\n| **Config** | Hardcoded localhost | config.ini (IP/port) | config.lua (IP/port) |\\\n| **World position** | ✅ Yes | ✅ Yes | ❌ Not yet (trivial to add) |\\\n| **Wheel slip** | ❌ No | ✅ Yes | ✅ Yes |\\\n| **Tyre temps** | ❌ No | ✅ Core temps | Available via CSP API |\\\n| **Suspension** | ✅ 200 Hz | ✅ Per-frame | ✅ 60 Hz |\\\n| **Crash resilience** | Never crashes | Python process | Lua script can crash |\\\n\\\n### Coaching Capability by Source\\\n\\\n| Use Case | 9996 (built-in) | 10101 (Telemetry Tool) | 5005 (our plugin) |\\\n|---|---|---|---|\\\n| Lap time analysis | ✅ | ✅ | ✅ |\\\n| Braking point coaching | ✅ | ✅ | ✅ |\\\n| Racing line analysis | ⚠️ (has world pos) | ✅ (has world pos) | ⚠️ (needs world pos) |\\\n| Throttle/traction coaching | ⚠️ (infer from wheel speed) | ✅ (has wheel slip) | ✅ (has wheel slip) |\\\n| Understeer/oversteer | ⚠️ (~70% confidence) | ✅ (~95% with slip data) | ✅ (~95% with slip data) |\\\n| Tyre management | ❌ | ✅ (core temps) | ✅ (full CSP tyre API) |\\\n| Damage monitoring | ❌ | ❌ | ✅ (5-zone damage) |\\\n| Multi-car tracking | ❌ | ✅ (all cars) | ❌ (can extend) |\\\n\\\n### Rust Listener Requirements (Next Steps)\\\n\\\nThe `rusty-telemetry` listener needs these changes:\\\n\\\n1. **Multi-port binding**: Listen on ports 9996, 10101, and 5005 simultaneously\\\n2. **Per-feed status reporting**: For each port/feed, log:\\\n   - Feed name (ksudp / telemetry_tool / ac_plugin)\\\n   - Bind status (listening / error)\\\n   - Packet count, packets/sec\\\n   - Data rate (KB/s)\\\n   - Last packet timestamp\\\n   - Feed health (alive / stale / dead)\\\n3. **Data dump to files**: Write raw received data to per-feed files:\\\n   - `./data/<session_id>/feed_9996_ksudp_<timestamp>.bin` (raw binary)\\\n   - `./data/<session_id>/feed_10101_telemetrytool_<timestamp>.bin` (raw binary)\\\n   - `./data/<session_id>/feed_5005_acplugin_<timestamp>.json` (parsed JSON)\\\n   - `./data/<session_id>/feed_5005_acplugin_<timestamp>.csv` (human-readable)\\\n   - Session ID = `YYYYMMDD_HHMMSS` at startup\\\n   - File rotation every N minutes or N MB\\\n4. **Startup banner**: Show all configured ports and their bind status:\\\n   ```\\\n   rusty-telemetry v0.2.0 — Multi-feed telemetry listener\\\n   ─────────────────────────────────────────────────────\\\n   Feed :9996  [KSUDP]            ✅ Listening (20.1 pkt/s)\\\n   Feed :10101 [Telemetry Tool]   ✅ Listening (60.3 pkt/s)\\\n   Feed :5005  [AC Lua Plugin]    ⏳ Waiting for data...\\\n   ─────────────────────────────────────────────────────\\\n   Data dir: ./data/20260603_094500/\\\n   ```\\\n\\\n### Telemetry Tool Plugin (Port 10101) — Packet Structure\\\n\\\n**Source**: `/home/jan/.steam/.../apps/python/Telemetry_Tool_plugin/Telemetry_Tool_plugin.py`\\\n**Config**: `config.ini` — `to_ip=127.0.0.1`, `to_port=10101`\\\n\\\n**Packet structure per driver** (binary, little-endian, packed):\\\n\\\n| Offset | Type | Field | Notes |\\\n|--------|------|-------|-------|\\\n| 0 | uint32 | driver_id | Car index |\\\n| 4 | uint32 | lap_time | Current lap time (ms) |\\\n| 8 | uint32 | last_lap | Last completed lap (ms) |\\\n| 12 | uint32 | best_lap | Best lap (ms) |\\\n| 16 | byte | current_splits_num | Number of splits |\\\n| 17 | uint32×3 | cur_split[1-3] | Current sector times (ms) |\\\n| 29 | uint32×3 | last_split[1-3] | Last lap sector times (ms) |\\\n| 41 | float | steer | Steering input |\\\n| 45 | float | throttle | Throttle 0–1 |\\\n| 49 | float | brake | Brake 0–1 |\\\n| 53 | float | clutch | Clutch 0–1 |\\\n| 57 | int16 | gear | Current gear |\\\n| 59 | float | engineRPM | Engine RPM |\\\n| 63 | float | speed | Speed km/h |\\\n| 67 | int16 | track_position | Track position |\\\n| 69 | int16 | leaderboard_position | Leaderboard pos |\\\n| 71 | int16 | lap_count | Lap number |\\\n| 73 | float×3 | x, y, z | World position |\\\n| 85 | double | spline_position | Normalized 0–1 |\\\n| 93 | float | test_float | Validation (666.666) |\\\n| 97 | char[33] | driver_name | Null-padded |\\\n| 130 | char[4] | nationality | Null-padded |\\\n| 134 | char[33] | car_name | Null-padded |\\\n| 167 | char[10] | tyre_name | Tyre compound |\\\n| 177 | uint32 | test_int | Validation (666) |\\\n| 181 | byte | is_connected | Connection status |\\\n| 182 | byte | is_in_pit | Pit stop active |\\\n| 183 | byte | is_car_in_pitlane | In pit lane |\\\n| 184 | byte | valid | Lap validity flag |\\\n| 185 | float | acc_vertical | Vertical G |\\\n| 189 | float | acc_horizontal | Horizontal G |\\\n| 193 | float | acc_frontal | Longitudinal G |\\\n| 196 | byte | is_engine_limiter_on | Rev limiter |\\\n| 197 | byte | is_drs_available | DRS available |\\\n| 198 | byte | is_drs_enabled | DRS active |\\\n| 199 | byte | is_race_finished | Race complete |\\\n| 200 | byte | ptp_status | Push-to-pass status |\\\n| 201 | uint32 | ptp_activations | P2P uses remaining |\\\n| 205 | float | ers_max_j | ERS capacity |\\\n| 209 | float | ers_current_kj | ERS current charge |\\\n| 213 | float×4 | tyre_dirty_level | Tyre marbles (4 wheels) |\\\n| 229 | float | turbo_boost | Turbo boost |\\\n| 233 | float×2 | ride_height | Front/rear ride height |\\\n| 241 | float×4 | current_tyres_core_temp | Core temps (4 wheels) |\\\n| 257 | float×4 | tyres_slip_ratio | Slip ratios (4 wheels) |\\\n| 273 | float×4 | tyres_slip_angle | Slip angles (4 wheels) |\\\n| 289 | float×4 | nd_slip | Normalized slip (4 wheels) |\\\n| 305 | float×4 | wheel_slip | Wheel slip (4 wheels) |\\\n| 321 | float×3 | world_speed | World velocity vector |\\\n| 333 | float×3 | local_speed | Local velocity vector |\\\n| 345 | int32 | valid (trailer) | Validation check |\\\n| 349 | double | test_float (trailer) | Validation (666.666) |\\\n\\\n**Outer wrapper**: `byte(1) packet_type=22` + `[driver_data × cars_count]`\\\n\\\n### AC Built-in UDP (Port 9996) — Reference\\\n\\\n**Status**: Binary, community-reverse-engineered. Mirrors AC shared memory layout.\\\n\\\n| Field | Type | Rate |\\\n|---|---|---|\\\n| packetId, speedKmh, rpm, gear | int/float | ~20 Hz |\\\n| gas, brake, clutch, steerAngle | float | ~20 Hz |\\\n| G_LAT, G_LON | float | ~20 Hz |\\\n| splinePosition, worldPosition | float/vec3 | ~20 Hz |\\\n| suspensionTravel[4] | float×4 | **200 Hz** |\\\n| wheelSpeed[4] | float×4 | ~20 Hz |\\\n| lapTime, lapCount, fuel | float/int | ~20 Hz |\\\n| bestLap, lastLap | float | — |\"],[0,\"\\\n\\\n--\"]],\"start1\":6453,\"start2\":6453,\"length1\":4526,\"length2\":6183},{\"diffs\":[[0,\"myLua |\\\n\"],[1,\"| **Project path** | `~/IdeaProjects/ac-telemetry-plugin` |\\\n\"],[0,\"| **Remo\"]],\"start1\":12813,\"start2\":12813,\"length1\":16,\"length2\":76},{\"diffs\":[[0,\"| **\"],[-1,\"Runs on** | Game machine (inside AC / Proton) |\\\n| **Dependencies** | LuaSocket (bundled with CSP) |\\\n| **Git commit** | `3900d2a` (`feat: initial AC telemetry Lua plugin`) |\\\n| **Status** | **Phase 1.1 — bug found, needs fix** |\\\n\\\n**🐛 CONFIRMED BUG: `require(\\\"socket.udp\\\")` is incorrect** — see Section 13.2 for details\\\n\\\n#### Folder Paths (Three Copies Currently Exist)\\\n\\\n| Role | Path | Git Status | manifest.ini | main.lua |\\\n|---|---|---|---|---|\\\n| **Project source** | `~/IdeaProjects/ac-telemetry-plugin` | `3900d2a` clean | `[SCRIPT]` (headless) | No `script.windowMain` |\\\n| **App deployment** | `<AC>/apps/lua/ac-telemetry-plugin/` | `3900d2a` **dirty** (modified manifest.ini, main.lua; untracked icon.png) | `[WINDOW_...]` (app window) | Has `script.windowMain` + `ui.text()` |\\\n| **Extension deployment** | `<AC>/extension/lua/ac-telemetry-plugin/` | `3900d2a` clean | `[SCRIPT]` (headless) | No `script.windowMain` |\\\n\\\n`<AC>` = `/home/jan/.steam/debian-installation/steamapps/common/assettocorsa`\\\n\\\n**Core files are identical across all three**: `config.lua`, `src/telemetry.lua`, `src/json.lua`\\\n\\\n#### Deployment Workflow\\\n\\\n```\\\n~/IdeaProjects/ac-telemetry-plugin/          ← Edit here (git repo, IntelliJ project)\\\n    ↓ copy/symlink\\\n<AC>/apps/lua/ac-telemetry-plugin/           ← Deploy here (CSP loads as in-game app)\\\n```\\\n\\\n**Action items:**\\\n1. **Merge the app modifications back into the project source** — commit the `[WINDOW_...]` manifest, `script.windowMain`, and `icon.png` into the git repo\\\n2. **Delete `<AC>/extension/lua/ac-telemetry-plugin/`** — prevents double loading\\\n3. **Use the project source as the single source of truth**, deploy only to `apps/lua/\"],[1,\"Codeberg** | `ssh://git@codeberg.org/jhunnius/ac-telemetry-plugin` |\\\n| **Runs on** | Game machine (inside AC / Proton) |\\\n| **Status** | **Phase 1.1 — LuaSocket bug FIXED, uncommitted** |\\\n\\\n#### Current Folder State\\\n\\\n| Role | Path | Status |\\\n|---|---|---|\\\n| **Project source** | `~/IdeaProjects/ac-telemetry-plugin` | ✅ App variant + LuaSocket fix + icon.png — **needs commit** |\\\n| **App deployment** | `<AC>/apps/lua/ac-telemetry-plugin/` | ✅ Synced with project source |\\\n| **Extension deployment** | `<AC>/extension/lua/ac-telemetry-plugin/` | ❌ **DELETED** |\\\n\\\n#### Changes Made (Uncommitted)\\\n\\\n1. **manifest.ini**: `[SCRIPT]` → `[WINDOW_...]` with `[CORE] LAZY=FULL`, `REQUIRED_VERSION=0`\\\n2. **main.lua**: Added `script.windowMain(dt)` with `ui.text(\\\"AC Telemetry ●\\\")`\\\n3. **src/telemetry.lua**: Fixed `require(\\\"socket.udp\\\")` → `require(\\\"socket\\\")` + `socket.udp()`\\\n4. **icon.png**: Copied from apps/lua deployment (209 bytes)\\\n\\\n#### Next Commit Should Include\\\n\\\n```\\\nfix: correct LuaSocket require pattern, switch to app window variant\\\n\\\n- Fix: require(\\\"socket.udp\\\") → require(\\\"socket\\\") + socket.udp()\\\n  socket.udp is a function, not a module. The old pattern crashed the\\\n  entire script at load time, causing blank windows and no UDP output.\\\n- Change manifest.ini from [SCRIPT] to [WINDOW_...] with CORE LAZY=FULL\\\n- Add script.windowMain() with app title display\\\n- Add icon.png for app bar\\\n``\"],[0,\"`\\\n\\\n#\"]],\"start1\":12980,\"start2\":12980,\"length1\":1677,\"length2\":1396},{\"diffs\":[[0,\"| **\"],[-1,\"Runs on** | Analysis machine (independent from game machines) |\\\n| **Stack** | Tokio (async), Serde (JSON), Chrono |\\\n| **Status** | **Phase 1.1 complete** (simple listener) — commit `30543fd`\"],[1,\"Status** | **Phase 1.1 — needs multi-port + data dump upgrade**\"],[0,\" |\\\n\\\n\"]],\"start1\":14656,\"start2\":14656,\"length1\":198,\"length2\":71},{\"diffs\":[[0,\"SON \"],[-1,\"→ generic telemetry model)\\\n│   ├── parser-ksudp/             (AC binary KSUDP → generic telemetry model)  ← NEW\\\n│   ├── parser-dr2/               (DR2 binary → generic telemetry model)\\\n│   ├── parser-pcars/             (Project CARS 1 & 2 binary → generic telemetry model)\\\n│   ├── plausibility/             (cross-source data validation)                ← NEW\\\n│   ├── storage/                  (SQLite persistence, migrations)\\\n│   ├── analyzer/                 (derived metrics, lap comparison, track mapping)\\\n│   ├── api/                      (REST + WebSocket server, Axum)\\\n│   └── web/                      (frontend — Yew/Leptos or static SPA)\\\n├── bin/\\\n│   └── rusty-telemetry.rs        (main binary, wires crates together)\\\n├── migrations/                   (SQLx migrations)\\\n└── config/                       (default config files)\\\n```\\\n\\\nEach parser implements a common `TelemetryParser` trait from `core`. Adding a new game is `cargo new crates/parser-evo` + implement the trait.\\\n\\\n### Why 2 Repos (Not 3)\\\n\\\nThe original plan had a third repo for the DR2 listener. That was folded into `rusty-telemetry` because:\\\n- DR2 has **native UDP output** — no code runs on the DR2 machine\\\n- Project CARS 1 & 2 likewise use **native UDP** — folded into the same receiver\\\n- Each game's parser is a module (~200–400 lines), not an independent service\\\n- All parsers share the same UDP listener infrastructure and data model\\\n- One `cargo test` / `cargo build` covers everything\\\n\\\n---\\\n\\\n## 6. Data Format — JSON Schema (Phase 1)\\\n\\\nFrom Lua plugin → Rust listener on port 5005:\\\n\\\n```json\\\n{\\\n  \\\"timestamp\\\": 1716123456,\\\n  \\\"speed_kmh\\\": 245.3,\\\n  \\\"rpm\\\": 8750,\\\n  \\\"gear\\\": 6,\\\n  \\\"throttle\\\": 0.850,\\\n  \\\"brake\\\": 0.000,\\\n  \\\"steering\\\": 0.120,\\\n  \\\"g_forces\\\": { \\\"x\\\": 0.500, \\\"y\\\": -0.200, \\\"z\\\": 1.000 },\\\n  \\\"wheel_slip\\\": [0.100, 0.100, 0.000, 0.000],\\\n  \\\"suspension_travel\\\": [0.150, 0.140, 0.160, 0.150],\\\n  \\\"lap_time\\\": 85.234,\\\n  \\\"lap_count\\\": 5\\\n}\\\n```\\\n\\\n**Notes:**\\\n- `timestamp` is a Unix epoch in integer seconds (`os.time()` in Lua, deserialized as `f64` in Rust)\\\n- All floating-point values use 3 decimal places via `string.format`\\\n- `lap_count` is the current lap number (1-indexed), not the total session laps\\\n- The Rust structs use `#[serde(deny_unknown_fields)]` so any field name mismatch causes an immediate parse error\\\n\\\nFuture: Migrate to **Protocol Buffers** for efficiency. Define a generic `.proto` schema with common fields + `oneof` for game-specific extensions.\\\n\\\n---\\\n\\\n## 7. Implementation Phases\\\n\\\n### Phase 1: Core Infrastructure (Weeks 1–6)\\\n\\\n- **1.0 KSUDP Parser (port 9996)** — **NEW** — Can start immediately, no plugin dependency\\\n  - [ ] Implement `parser-ksudp` crate with binary parser for AC's built-in UDP\\\n  - [ ] Map to generic telemetry model (speed, inputs, G-forces, position, lap data)\\\n  - [ ] Listen on port 9996 alongside port 5005\\\n  - [ ] Enables basic coaching (lap times, braking points, racing line) from day one\\\n  - [ ] Works even if Lua plugin is broken — always-available fallback\\\n\\\n- **1.1 AC Lua Plugin prototype** — **BUG FOUND, NEEDS FIX** (commit `3900d2a`)\\\n  - [x] Set up project at `~/IdeaProjects/ac-telemetry-plugin`\\\n  - [x] Implement telemetry reader via `ac.getCarState(0)` with field fallbacks\\\n  - [x] Create purpose-built JSON serializer (zero-allocation `string.format`)\\\n  - [x] Create UDP sender module with configurable target\\\n  - [x] Pre-allocated buffer tables for zero GC pressure at 60Hz\\\n  - [x] Test with simple Rust listener\\\n  - [x] Code review: fixed timestamp (`os.time()`), lap count source, suspension fallbacks\\\n  - [ ] **FIX: Correct LuaSocket require pattern** — `require(\\\"socket.udp\\\")` → `require(\\\"socket\\\")` + `socket.udp()`\\\n  - [ ] **MERGE: Commit app variant into git** — manifest.ini with `[WINDOW_...]`, `script.windowMain`, `icon.png`\\\n  - [ ] **CLEANUP: Delete `extension/lua/ac-telemetry-plugin/`** to prevent double UDP transmission\\\n  - [ ] **ADD: Debug logging** — `ac.log()` and `ac.debug()` calls for troubleshooting\\\n  - [ ] **ADD: world position + spline position + fuel** to telemetry output (available from CSP API)\\\n\\\n- **1.2 `rusty-telemetry` workspace skeleton** — **PARTIAL** (commit `30543fd`)\\\n  - [x] Simple single-crate UDP listener on `127.0.0.1:5005` (configurable via env)\\\n  - [x] JSON deserialization with `deny_unknown_fields` for schema contract\\\n  - [x] ReceiveStats tracker (packet count, rates)\\\n  - [x] Code review: bind address security, stdout lock consolidation\\\n  - [ ] Refactor to Cargo workspace with `core`, `receiver`, `parser-ac`, `parser-ksudp` crates\\\n  - [ ] Multi-port UDP listener (ports 9996, 5005, 5015, 5006)\\\n  - [ ] `plausibility` crate for cross-source data validation\\\n  - [ ] SQLite database with migrations\\\n  - [ ] Basic REST API endpoints\\\n\\\n- **1.3 DR2.0 parser crate**\\\n  - [ ] Add `parser-dr2` crate to workspace\\\n  - [ ] Analyze DR2.0 UDP packet structure, implement binary parser\\\n  - [ ] Map to generic telemetry model\\\n\\\n- **1.4 Project CARS 1 & 2 parser crate**\\\n  - [ ] Add `parser-pcars` crate to workspace\\\n  - [ ] Implement binary parser for PCARS UDP packet structure\\\n  - [ ] Map to generic telemetry model\\\n\\\n### Phase 2: Data Analysis & Storage (Weeks 7–12)\\\n- Derived metrics: G-forces, slip ratios, curvature (G_LAT / v²), derivatives\\\n- **Plausibility engine**: cross-reference port 9996 vs port 5005 data\\\n- Data decimation strategy (full data for 5 min, then 1-second averages)\\\n- Session/lap management and comparison\\\n- Track mapping from world position data\\\n- Reference lap system using spline position\\\n\\\n### Phase 3: Web Visualization (Weeks 13–18)\\\n- Real-time telemetry dashboard\\\n- Lap comparison overlays (trace overlay — reference lap vs user)\\\n- **Track map with racing line** (world position from port 9996)\\\n- Time-distance plots, histograms\\\n- Driver input dashboard: steering vs G-force, throttle/brake trace\\\n\\\n### Phase 4: AI Coaching with GLM-5.1 (Weeks 19–24)\\\n- **Basic coaching** (from port 9996 data): braking points, lap consistency, racing line\\\n- **Advanced coaching** (from port 5005 data): traction management, tyre strategy\\\n- Feature extraction from telemetry patterns\\\n- Structured prompts with relevant data excerpts\\\n- GLM-5.1 API integration with function calling for structured coaching\\\n\\\n---\\\n\\\n## 8. Development Tools\\\n\\\n| Component | IDE | Project Path | AI Assistant |\\\n|---|---|---|---|\\\n| `ac-telemetry-plugin` | IntelliJ IDEA + EmmyLua | `~/IdeaProjects/ac-telemetry-plugin` | Kilo Code + GLM 5.1 |\\\n| `rusty-telemetry` | RustRover | `~/RustroverProjects/rusty-telemetry` | Kilo Code + GLM 5.1 |\\\n| Web UI (within `rusty-telemetry`) | RustRover | `~/RustroverProjects/rusty-telemetry/crates/web` | Kilo Code + GLM 5.1 |\\\n\\\n---\\\n\\\n## 9. Rally Game Telemetry — Why It Matters\\\n\\\nRally telemetry is arguably **more valuable** than circuit racing because:\\\n- **Surface adaptation**: Analyze input changes between tarmac, gravel, snow\\\n- **Pace note correlation**: Overlay braking points with pace notes — are you braking too early/late?\\\n- **Technique breakdown**: Scandinavian flick — precise sequence of steering, braking, throttle\\\n- **Consistency under pressure**: Compare multiple runs on same stage\\\n- **Car setup validation**: Differential, suspension, gear settings vs grip/stability\\\n\\\n---\\\n\\\n## 10. Key References\\\n\\\n- AC Shared Memory API Documentation\\\n- **AC Server Plugin Protocol** — fully documented in `sdk/dev/acRemoteServerUDP_Example/`\\\n- **AC Shared Memory reverse-engineering** — `raphael-rial/ACSharedMemory` and `compujuckel/AssettoCorsaSharedMemory` on GitHub (port 9996 binary structure)\\\n- `acevo-shared-memory` Rust crate (struct definitions for EVO shared memory layout)\\\n- `ac-tracer` by Tobi on GitHub (CSP Lua telemetry app)\\\n- `acc-lua-sdk` on GitHub (Lua API reference)\\\n- DR2.0 UDP packet structure (official sharedmemory.h definition)\\\n- Project CARS UDP packet structure (official documentation)\\\n- GLM-5.1 API for AI coaching\\\n\\\n---\\\n\\\n## 11. Success Metrics\\\n\\\n| Metric | Target |\\\n|---|---|\\\n| Data capture rate | 95%+ frames at 60Hz |\\\n| Storage efficiency | <1MB/min after decimation |\\\n| API response time | <200ms for historical queries |\\\n| AI coaching relevance | 70%+ useful suggestions |\\\n| Cross-game compatibility | 3+ games supported |\\\n| Plausibility check coverage | All shared fields validated |\\\n\\\n---\\\n\\\n## 12. Game Support Priority\\\n\\\n| Priority | Game | Method | Status |\\\n|---|---|---|---|\\\n| 1 | Assetto Corsa (classic) | KSUDP :9996 + Lua Plugin :5005 | **KSUDP can start now, plugin needs bug fix** |\\\n| 2 | Dirt Rally 2.0 | Native UDP :5015 | Phase 1 |\\\n| 3 | Project CARS 1 & 2 | Native UDP :5006 | Phase 1 |\\\n| 4 | Assetto Corsa Evo | Lua Plugin (when SDK ready) | Future |\\\n| 5 | Assetto Corsa Rally | Shared memory / SimHub ref | Future |\\\n| 6 | Dirt Rally 1.0 | UDP (same as DR2) | Future |\\\n| 7 | ACC | Relay tool (if needed) | Low priority |\\\n\\\n---\\\n\\\n## 13. CSP Lua App Architecture & Debugging\\\n\\\n*Added 2026-06-03*\\\n\\\n### 13.1 How CSP Lua App Windows Work\\\n\\\nCSP (Custom Shaders Patch) loads Lua apps from two locations:\\\n- **`apps/lua/<appname>/`** — user-facing apps that appear in the in-game app bar (use `[WINDOW_...]` manifest sections)\\\n- **`extension/lua/<category>/`** — system scripts (tools, game modes, cameras, FFB, PP filters) loaded by category\\\n\\\n### 13.2 CONFIRMED BUG: `require(\\\"socket.udp\\\")` — Wrong Module Path\\\n\\\n**Root cause of the blank window AND no UDP packets.**\\\n\\\n```lua\\\n-- ❌ CURRENT (broken):\\\nlocal socket = require(\\\"socket.udp\\\")   -- module doesn't exist\\\nlocal udp = socket()\\\n\\\n-- ✅ CORRECT:\\\nlocal socket = require(\\\"socket\\\")       -- loads socket.lua → socket.core (native C)\\\nlocal udp = socket.udp()               -- creates UDP socket from the table\\\n```\\\n\\\n**Required fix** in `src/telemetry.lua`.\\\n\\\n### 13.3 How to Check if a CSP Lua App is Running\\\n\\\n**CSP log location (Linux/Proton):**\\\n```\\\n~/.steam/debian-installation/steamapps/compatdata/244210/pfx/drive_c/users/steamuser/Documents/Assetto Corsa/logs/\\\n├── log.txt                        ← Main AC + CSP log\\\n├── custom_shaders_patch.log       ← Detailed CSP log (binary/UTF-16)\\\n├── errors.txt                     ← INI reader errors\\\n└── py_log.txt                     ← Python plugin log\\\n```\\\n\\\n**In-game debugging:**\\\n- **Lua Debug App** — open from app launcher (developer section). Shows `ac.debug()` values and `ac.log()` output live.\\\n- **`ac.log(message)`** — writes to CSP log + Lua Debug App\\\n- **`ac.debug(key, value)`** — live values with optional graphs in Lua Debug App\\\n- **`ac.console(message)`** — prints to AC in-game console (backtick/tilde key)\\\n\\\n### 13.4 One Variant: App Deployment Only\\\n\\\n**Maintain only the `apps/lua/` app variant.** Delete the `extension/lua/` copy. Reasons:\\\n1. Double-loading risk (120 pkt/s instead of 60)\\\n2. App variant supports settings UI (`FUNCTION_SETTINGS`)\\\n3. `LAZY = FULL` gives on-demand loading\\\n4. Extension copy is at wrong path (not under a subsystem directory)\\\n\\\n### 13.5 Proton Rendering\\\n\\\n- **All app icons fail to load** under Proton — confirmed from log. Apps still work, only sidebar icons missing.\\\n- ImGui rendering itself works (built-in apps function correctly).\\\n- If window is still blank after LuaSocket fix, remove `NO_BACKGROUND,NO_TITLE_BAR,FADING` flags temporarily.\\\n\\\n### 13.6 UDP Configuration\\\n\\\nCurrent: `config.lua` with hardcoded `127.0.0.1:5005`. For cross-machine, change `target_host` to LAN IP. Future: settings panel via `FUNCTION_SETTINGS`.\\\n\\\n---\\\n\\\n## 14. CSP Lua App Window Patterns (Reference)\\\n\\\n| Pattern | How it works | Example |\\\n|---------|-------------|---------|\\\n| `[WINDOW_...]` manifest + `script.windowXxx(dt)` | CSP creates window frame, calls your function each frame | `ac-tracer`, `ac-telemetry-plugin` |\\\n| `ui.onExclusiveHUD(callback)` | Draw during specific modes (pause, etc.) | `ac-tracer` pause overlay |\\\n| `ui.toolWindow(id, pos, size, scrollbar, movable, callback)` | Custom positioned/movable window | `ac-tracer` pause windows |\\\n| Direct `ui.drawRectFilled()`, `ui.dwriteDrawText()` | Draw directly on screen, no window | `drift-challenge/drift_hud.lua` |\\\n\\\n---\\\n\\\n*Last updated: 2026-06-03*\\\n*Source: Research conversation on sim racing telemetry APIs and system design*\\\n*Phase 1.1 completed: 2026-06-01 — ac-telemetry-plugin (3900d2a), rusty-telemetry (30543fd)*\\\n*Architecture update: 2026-06-03 — dual-source telemetry (port 9996 + 5005), KSUDP parser added to plan\"],[1,\":5005 → generic model)\\\n│   ├── parser-ksudp/             (AC binary :9996 → generic model)\\\n│   ├── parser-telemetry-tool/    (AC binary :10101 → generic model)\\\n│   ├── parser-dr2/               (DR2 binary :5015 → generic model)\\\n│   ├── parser-pcars/             (PCARS binary :5006 → generic model)\\\n│   ├── plausibility/             (cross-source data validation)\\\n│   ├── storage/                  (SQLite persistence, migrations)\\\n│   ├── analyzer/                 (derived metrics, lap comparison)\\\n│   ├── api/                      (REST + WebSocket server, Axum)\\\n│   └── web/                      (frontend)\\\n├── bin/\\\n│   └── rusty-telemetry.rs\\\n└── data/                         (runtime data dumps)\\\n    └── <session>/\\\n        ├── feed_9996_*.bin\\\n        ├── feed_10101_*.bin\\\n        └── feed_5005_*.{json,csv}\\\n```\\\n\\\n---\\\n\\\n## 6. Data Format — JSON Schema (Lua Plugin, Port 5005)\\\n\\\n```json\\\n{\\\n  \\\"timestamp\\\": 1716123456,\\\n  \\\"speed_kmh\\\": 245.3,\\\n  \\\"rpm\\\": 8750,\\\n  \\\"gear\\\": 6,\\\n  \\\"throttle\\\": 0.850,\\\n  \\\"brake\\\": 0.000,\\\n  \\\"steering\\\": 0.120,\\\n  \\\"g_forces\\\": { \\\"x\\\": 0.500, \\\"y\\\": -0.200, \\\"z\\\": 1.000 },\\\n  \\\"wheel_slip\\\": [0.100, 0.100, 0.000, 0.000],\\\n  \\\"suspension_travel\\\": [0.150, 0.140, 0.160, 0.150],\\\n  \\\"lap_time\\\": 85.234,\\\n  \\\"lap_count\\\": 5\\\n}\\\n```\\\n\\\n---\\\n\\\n## 7. Implementation Phases\\\n\\\n### Phase 1: Core Infrastructure\\\n\\\n- **1.0 Rust listener upgrade — IMMEDIATE**\\\n  - [ ] Multi-port UDP binding (9996, 10101, 5005)\\\n  - [ ] Per-feed status reporting with health indicators\\\n  - [ ] Data dump to per-feed files (`./data/<session>/feed_<port>_*.{bin,json,csv}`)\\\n  - [ ] Startup banner showing all feed ports and bind status\\\n  - [ ] Configurable via env vars or config file\\\n\\\n- **1.1 Binary parsers — START NOW**\\\n  - [ ] `parser-ksudp` for port 9996 (AC built-in, community-reverse-engineered structure)\\\n  - [ ] `parser-telemetry-tool` for port 10101 (struct layout documented in Python source)\\\n  - [ ] Map both to generic `TelemetryFrame` model\\\n\\\n- **1.2 AC Lua Plugin — FIXED, needs testing**\\\n  - [x] Fix LuaSocket require pattern\\\n  - [x] Switch to app window variant\\\n  - [x] Add icon.png\\\n  - [x] Delete extension/lua duplicate\\\n  - [ ] **Commit changes to git**\\\n  - [ ] **Test in AC** — restart AC, open app, verify UDP packets arrive on port 5005\\\n  - [ ] **Add fields**: world position, spline position, fuel (trivial, available from CSP API)\\\n  - [ ] **Add debug logging**: `ac.log()` and `ac.debug()` calls\\\n\\\n- **1.3 Python Telemetry Tool — ENABLED**\\\n  - [x] Added `[TELEMETRY_TOOL_PLUGIN] ACTIVE=1` to `python.ini`\\\n  - [ ] **Test in AC** — restart AC, verify packets arrive on port 10101\\\n  - [ ] Confirm data includes wheel slip, tyre temps, all cars\\\n\\\n- **1.4 Workspace refactor**\\\n  - [ ] Split into Cargo workspace with `core`, `receiver`, parsers\\\n  - [ ] SQLite database with migrations\\\n  - [ ] Basic REST API endpoints\\\n\\\n- **1.5 DR2.0 + PCARS parsers** (deferred until AC feeds work)\\\n\\\n### Phase 2: Data Analysis & Storage\\\n- Plausibility engine: cross-reference feeds\\\n- Derived metrics: curvature (G_LAT / v²), slip ratios, derivatives\\\n- Track mapping from world position data\\\n- Reference lap system\\\n\\\n### Phase 3: Web Visualization\\\n- Real-time telemetry dashboard\\\n- Track map with racing line (world position)\\\n- Lap comparison overlays\\\n\\\n### Phase 4: AI Coaching with GLM-5.1\\\n- Basic coaching from built-in feeds (braking, lap consistency, racing line)\\\n- Advanced coaching from Lua plugin (traction, tyre strategy, damage)\\\n\\\n---\\\n\\\n## 8. Development Tools\\\n\\\n| Component | IDE | Project Path |\\\n|---|---|---|\\\n| `ac-telemetry-plugin` | IntelliJ IDEA + EmmyLua | `~/IdeaProjects/ac-telemetry-plugin` |\\\n| `rusty-telemetry` | RustRover | `~/RustroverProjects/rusty-telemetry` |\\\n\\\n---\\\n\\\n## 9–12. [Unchanged — Rally, References, Metrics, Game Priority]\\\n\\\n*(See previous versions of this note for unchanged sections 9–12)*\\\n\\\n---\\\n\\\n## 13. Operations & Debugging Reference\\\n\\\n### How to Check if Feeds Are Running\\\n\\\n**CSP log location (Linux/Proton):**\\\n```\\\n~/.steam/.../compatdata/244210/.../Documents/Assetto Corsa/logs/\\\n├── log.txt                  ← Main AC log (check for \\\"RemoteTelemetryUDP\\\", \\\"IMGUI_LUA_ac-telemetry\\\", Python errors)\\\n├── custom_shaders_patch.log ← Detailed CSP log (binary/UTF-16)\\\n└── py_log.txt               ← Python plugin log\\\n```\\\n\\\n**In-game debugging:**\\\n- **Lua Debug App** — app launcher → developer section → shows `ac.debug()` and `ac.log()` live\\\n- **AC console** — backtick/tilde key → shows `ac.console()` output\\\n\\\n### Port 9996 (AC Built-in) — Always Running\\\n- Created by AC engine at startup: `RemoteTelemetryUDP :: creating socket on port 9996`\\\n- No configuration needed, no plugin required\\\n- Sends to 127.0.0.1:9996 only\\\n\\\n### Port 10101 (Telemetry Tool Plugin) — Just Enabled\\\n- Config: `<AC>/apps/python/Telemetry_Tool_plugin/config.ini`\\\n- Enabled: `python.ini` → `[TELEMETRY_TOOL_PLUGIN] ACTIVE=1`\\\n- Sends to 127.0.0.1:10101 (configurable in config.ini)\\\n- Requires AC restart to activate\\\n\\\n### Port 5005 (Our Lua Plugin) — Bug Fixed, Needs AC Restart\\\n- Config: `<AC>/apps/lua/ac-telemetry-plugin/config.lua`\\\n- Bug fix: `require(\\\"socket.udp\\\")` → `require(\\\"socket\\\")` + `socket.udp()`\\\n- Deployed to `apps/lua/` only (extension copy deleted)\\\n- Requires AC restart + enabling the app in the in-game app launcher\\\n\\\n### Deployment Paths\\\n\\\n| Path | Purpose |\\\n|---|---|\\\n| `~/IdeaProjects/ac-telemetry-plugin/` | **Source of truth** — git repo, edit here |\\\n| `<AC>/apps/lua/ac-telemetry-plugin/` | **Deployed app** — CSP loads from here |\\\n| `<AC>/apps/python/Telemetry_Tool_plugin/` | **Third-party plugin** — config.ini for IP/port |\\\n| `~/RustroverProjects/rusty-telemetry/` | **Rust listener** — multi-port receiver |\\\n\\\n`<AC>` = `/home/jan/.steam/debian-installation/steamapps/common/assettocorsa`\\\n`<Proton Docs>` = `~/.steam/.../compatdata/244210/pfx/drive_c/users/steamuser/Documents/Assetto Corsa`\\\n\\\n---\\\n\\\n*Last updated: 2026-06-03 — Phase 1 restructured for triple-feed approach*\\\n*LuaSocket bug fixed, Python Telemetry Tool enabled, extension copy deleted*\\\n*Next: restart AC → verify all three feeds → upgrade Rust listener\"],[0,\"*\"]],\"start1\":15025,\"start2\":15025,\"length1\":12227,\"length2\":6002}]"
metadata_diff: {"new":{},"deleted":[]}
encryption_cipher_text: 
encryption_applied: 0
updated_time: 2026-06-03T07:57:52.998Z
created_time: 2026-06-03T07:57:52.998Z
type_: 13