Files
racing-data/docs/udp-packets.schema.json
2026-05-19 15:38:16 +10:00

747 lines
25 KiB
JSON

{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://local.projectcars-data/schemas/udp-packets.schema.json",
"title": "Project CARS UDP Parsed Packet State",
"description": "Readable JSON Schema for the parsed JSON emitted by this app from Project CARS UDP packets. The game sends binary UDP packets; this schema describes the decoded JSON shape exposed by /api/state and SSE events.",
"type": "object",
"additionalProperties": false,
"properties": {
"latest": {
"type": "object",
"description": "Latest parsed packet by packet type number.",
"additionalProperties": {
"$ref": "#/$defs/parsedPacket"
},
"properties": {
"0": { "$ref": "#/$defs/carPhysicsPacket" },
"1": { "$ref": "#/$defs/raceDefinitionPacket" },
"2": { "$ref": "#/$defs/participantsPacket" },
"3": { "$ref": "#/$defs/timingsPacket" },
"4": { "$ref": "#/$defs/gameStatePacket" },
"5": { "$ref": "#/$defs/weatherStatePacket" },
"6": { "$ref": "#/$defs/vehicleNamesPacket" },
"7": { "$ref": "#/$defs/timeStatsPacket" },
"8": { "$ref": "#/$defs/participantVehicleNamesPacket" }
}
},
"recent": {
"type": "array",
"description": "Most recent raw parsed packets, newest first.",
"items": { "$ref": "#/$defs/parsedPacket" }
},
"leaderboard": {
"$ref": "#/$defs/leaderboard"
}
},
"$defs": {
"parsedPacket": {
"type": "object",
"additionalProperties": false,
"required": ["receivedAt", "source", "base", "name", "size", "data"],
"properties": {
"receivedAt": { "type": "string", "format": "date-time" },
"source": { "type": "string", "examples": ["127.0.0.1:5606"] },
"base": { "$ref": "#/$defs/packetBase" },
"name": { "type": "string" },
"size": { "type": "integer", "minimum": 0 },
"data": { "type": "object" }
}
},
"packetBase": {
"type": "object",
"additionalProperties": false,
"required": [
"packetNumber",
"categoryPacketNumber",
"partialPacketIndex",
"partialPacketNumber",
"packetType",
"packetVersion"
],
"properties": {
"packetNumber": { "type": "integer", "minimum": 0 },
"categoryPacketNumber": { "type": "integer", "minimum": 0 },
"partialPacketIndex": { "type": "integer", "minimum": 0, "maximum": 255 },
"partialPacketNumber": { "type": "integer", "minimum": 0, "maximum": 255 },
"packetType": {
"type": "integer",
"enum": [0, 1, 2, 3, 4, 5, 6, 7, 8],
"description": "0 CarPhysics, 1 RaceDefinition, 2 Participants, 3 Timings, 4 GameState, 5 WeatherState, 6 VehicleNames, 7 TimeStats, 8 ParticipantVehicleNames"
},
"packetVersion": { "type": "integer", "minimum": 0, "maximum": 255 }
}
},
"number3": {
"type": "array",
"prefixItems": [{ "type": "number" }, { "type": "number" }, { "type": "number" }],
"minItems": 3,
"maxItems": 3
},
"number4": {
"type": "array",
"prefixItems": [{ "type": "number" }, { "type": "number" }, { "type": "number" }, { "type": "number" }],
"minItems": 4,
"maxItems": 4
},
"integer3": {
"type": "array",
"prefixItems": [{ "type": "integer" }, { "type": "integer" }, { "type": "integer" }],
"minItems": 3,
"maxItems": 3
},
"integer4": {
"type": "array",
"prefixItems": [{ "type": "integer" }, { "type": "integer" }, { "type": "integer" }, { "type": "integer" }],
"minItems": 4,
"maxItems": 4
},
"carPhysicsPacket": {
"allOf": [
{ "$ref": "#/$defs/parsedPacket" },
{
"properties": {
"base": {
"allOf": [
{ "$ref": "#/$defs/packetBase" },
{ "properties": { "packetType": { "const": 0 } } }
]
},
"data": { "$ref": "#/$defs/carPhysicsData" }
}
}
]
},
"carPhysicsData": {
"type": "object",
"additionalProperties": false,
"properties": {
"viewedParticipantIndex": { "type": "integer" },
"input": {
"type": "object",
"additionalProperties": false,
"properties": {
"throttle": { "type": "integer" },
"brake": { "type": "integer" },
"steering": { "type": "integer" },
"clutch": { "type": "integer" }
}
},
"car": {
"type": "object",
"additionalProperties": false,
"properties": {
"flags": { "type": "integer" },
"oilTempCelsius": { "type": "integer" },
"oilPressureKPa": { "type": "integer" },
"waterTempCelsius": { "type": "integer" },
"waterPressureKpa": { "type": "integer" },
"fuelPressureKpa": { "type": "integer" },
"fuelCapacity": { "type": "integer" },
"brake": { "type": "integer" },
"throttle": { "type": "integer" },
"clutch": { "type": "integer" },
"fuelLevel": { "type": "number" },
"speedMps": { "type": "number" },
"speedKph": { "type": "number" },
"rpm": { "type": "integer" },
"maxRpm": { "type": "integer" },
"steering": { "type": "integer" },
"gear": { "type": "string" },
"numGears": { "type": "integer" },
"boostAmount": { "type": "integer" },
"crashState": { "type": "integer" },
"odometerKM": { "type": "number" },
"brakeBias": { "type": "integer" }
}
},
"vectors": {
"type": "object",
"additionalProperties": false,
"properties": {
"orientation": { "$ref": "#/$defs/number3" },
"localVelocity": { "$ref": "#/$defs/number3" },
"worldVelocity": { "$ref": "#/$defs/number3" },
"angularVelocity": { "$ref": "#/$defs/number3" },
"localAcceleration": { "$ref": "#/$defs/number3" },
"worldAcceleration": { "$ref": "#/$defs/number3" },
"extentsCentre": { "$ref": "#/$defs/number3" },
"fullPosition": { "$ref": "#/$defs/number3" }
}
},
"tyres": {
"type": "object",
"additionalProperties": false,
"properties": {
"flags": { "$ref": "#/$defs/integer4" },
"terrain": { "$ref": "#/$defs/integer4" },
"y": { "$ref": "#/$defs/number4" },
"rps": { "$ref": "#/$defs/number4" },
"temp": { "$ref": "#/$defs/integer4" },
"heightAboveGround": { "$ref": "#/$defs/number4" },
"wear": { "$ref": "#/$defs/integer4" },
"brakeTempCelsius": { "$ref": "#/$defs/integer4" },
"treadTemp": { "$ref": "#/$defs/integer4" },
"layerTemp": { "$ref": "#/$defs/integer4" },
"carcassTemp": { "$ref": "#/$defs/integer4" },
"rimTemp": { "$ref": "#/$defs/integer4" },
"internalAirTemp": { "$ref": "#/$defs/integer4" },
"tempLeft": { "$ref": "#/$defs/integer4" },
"tempCenter": { "$ref": "#/$defs/integer4" },
"tempRight": { "$ref": "#/$defs/integer4" },
"wheelLocalPositionY": { "$ref": "#/$defs/number4" },
"rideHeight": { "$ref": "#/$defs/number4" },
"suspensionTravel": { "$ref": "#/$defs/number4" },
"suspensionVelocity": { "$ref": "#/$defs/number4" },
"suspensionRideHeight": { "$ref": "#/$defs/integer4" },
"airPressure": { "$ref": "#/$defs/integer4" },
"compound": {
"type": "array",
"items": { "type": "string" },
"minItems": 4,
"maxItems": 4
}
}
},
"engine": {
"type": "object",
"additionalProperties": false,
"properties": {
"speed": { "type": "number" },
"torque": { "type": "number" },
"turboBoostPressure": { "type": "number" },
"wings": {
"type": "array",
"items": { "type": "integer" },
"minItems": 2,
"maxItems": 2
},
"handBrake": { "type": "integer" }
}
},
"damage": {
"type": "object",
"additionalProperties": false,
"properties": {
"aero": { "type": "integer" },
"engine": { "type": "integer" },
"brake": { "$ref": "#/$defs/integer4" },
"suspension": { "$ref": "#/$defs/integer4" }
}
},
"hardware": {
"type": "object",
"additionalProperties": false,
"properties": {
"joyPad0": { "type": "integer" },
"dPad": { "type": "integer" }
}
}
}
},
"raceDefinitionPacket": {
"allOf": [
{ "$ref": "#/$defs/parsedPacket" },
{
"properties": {
"base": {
"allOf": [
{ "$ref": "#/$defs/packetBase" },
{ "properties": { "packetType": { "const": 1 } } }
]
},
"data": { "$ref": "#/$defs/raceDefinitionData" }
}
}
]
},
"raceDefinitionData": {
"type": "object",
"additionalProperties": false,
"properties": {
"worldFastestLapTime": { "type": "number" },
"personalFastestLapTime": { "type": "number" },
"personalFastestSectors": { "$ref": "#/$defs/number3" },
"worldFastestSectors": { "$ref": "#/$defs/number3" },
"trackLength": { "type": "number" },
"trackLocation": { "type": "string" },
"trackVariation": { "type": "string" },
"translatedTrackLocation": { "type": "string" },
"translatedTrackVariation": { "type": "string" },
"lapsTimeInEvent": { "type": "integer" },
"enforcedPitStopLap": { "type": "integer" }
}
},
"participantsPacket": {
"allOf": [
{ "$ref": "#/$defs/parsedPacket" },
{
"properties": {
"base": {
"allOf": [
{ "$ref": "#/$defs/packetBase" },
{ "properties": { "packetType": { "const": 2 } } }
]
},
"data": { "$ref": "#/$defs/participantsData" }
}
}
]
},
"participantsData": {
"type": "object",
"additionalProperties": false,
"properties": {
"participantsChangedTimestamp": { "type": "integer" },
"participants": {
"type": "array",
"items": { "$ref": "#/$defs/participantName" }
}
}
},
"participantName": {
"type": "object",
"additionalProperties": false,
"properties": {
"slot": { "type": "integer" },
"localSlot": { "type": "integer" },
"partialPacketIndex": { "type": "integer" },
"name": { "type": "string" },
"nationality": { "type": "integer" },
"index": { "type": "integer" }
}
},
"timingsPacket": {
"allOf": [
{ "$ref": "#/$defs/parsedPacket" },
{
"properties": {
"base": {
"allOf": [
{ "$ref": "#/$defs/packetBase" },
{ "properties": { "packetType": { "const": 3 } } }
]
},
"data": { "$ref": "#/$defs/timingsData" }
}
}
]
},
"timingsData": {
"type": "object",
"additionalProperties": false,
"properties": {
"numParticipants": { "type": "integer" },
"participantsChangedTimestamp": { "type": "integer" },
"eventTimeRemaining": { "type": "number" },
"splitTimeAhead": { "type": "number" },
"splitTimeBehind": { "type": "number" },
"splitTime": { "type": "number" },
"localParticipantIndex": { "type": "integer" },
"participants": {
"type": "array",
"items": { "$ref": "#/$defs/timingParticipant" }
}
}
},
"timingParticipant": {
"type": "object",
"additionalProperties": false,
"properties": {
"slot": { "type": "integer" },
"worldPosition": { "$ref": "#/$defs/integer3" },
"orientation": { "$ref": "#/$defs/integer3" },
"currentLapDistance": { "type": "integer" },
"racePosition": { "type": "integer" },
"active": { "type": "boolean" },
"sector": { "type": "integer" },
"sectorRaw": { "type": "integer" },
"sectorExtraPrecision": { "type": "integer" },
"highestFlag": { "type": "integer" },
"pitModeSchedule": { "type": "integer" },
"carIndex": { "type": "integer" },
"raceState": { "type": "integer" },
"currentLap": { "type": "integer" },
"currentTime": { "type": "number" },
"currentSectorTime": { "type": "number" },
"mpParticipantIndex": { "type": "integer" }
}
},
"gameStatePacket": {
"allOf": [
{ "$ref": "#/$defs/parsedPacket" },
{
"properties": {
"base": {
"allOf": [
{ "$ref": "#/$defs/packetBase" },
{ "properties": { "packetType": { "const": 4 } } }
]
},
"data": { "$ref": "#/$defs/gameStateData" }
}
}
]
},
"gameStateData": {
"type": "object",
"additionalProperties": false,
"properties": {
"buildVersionNumber": { "type": "integer" },
"gameStateRaw": { "type": "integer" },
"gameState": { "type": "integer" },
"gameStateName": { "type": ["string", "null"] },
"sessionState": { "type": "integer" },
"sessionStateName": { "type": ["string", "null"] },
"ambientTemperature": { "type": "integer" },
"trackTemperature": { "type": "integer" },
"rainDensity": { "type": "integer" },
"snowDensity": { "type": "integer" },
"windSpeed": { "type": "integer" },
"windDirectionX": { "type": "integer" },
"windDirectionY": { "type": "integer" }
}
},
"weatherStatePacket": {
"description": "Packet type 5 is recognized by the app but currently emitted with the generic unimplemented parser payload.",
"allOf": [
{ "$ref": "#/$defs/parsedPacket" },
{
"properties": {
"base": {
"allOf": [
{ "$ref": "#/$defs/packetBase" },
{ "properties": { "packetType": { "const": 5 } } }
]
},
"data": { "$ref": "#/$defs/unimplementedPacketData" }
}
}
]
},
"vehicleNamesPacket": {
"description": "Packet type 6 is recognized by the app but currently emitted with the generic unimplemented parser payload. Participant vehicle/class names are decoded from packet type 8.",
"allOf": [
{ "$ref": "#/$defs/parsedPacket" },
{
"properties": {
"base": {
"allOf": [
{ "$ref": "#/$defs/packetBase" },
{ "properties": { "packetType": { "const": 6 } } }
]
},
"data": { "$ref": "#/$defs/unimplementedPacketData" }
}
}
]
},
"unimplementedPacketData": {
"type": "object",
"additionalProperties": false,
"required": ["rawPacketType", "message"],
"properties": {
"rawPacketType": { "type": "integer", "enum": [5, 6] },
"message": { "type": "string" }
}
},
"timeStatsPacket": {
"allOf": [
{ "$ref": "#/$defs/parsedPacket" },
{
"properties": {
"base": {
"allOf": [
{ "$ref": "#/$defs/packetBase" },
{ "properties": { "packetType": { "const": 7 } } }
]
},
"data": { "$ref": "#/$defs/timeStatsData" }
}
}
]
},
"timeStatsData": {
"type": "object",
"additionalProperties": false,
"properties": {
"participantsChangedTimestamp": { "type": "integer" },
"participants": {
"type": "array",
"items": { "$ref": "#/$defs/timeStatsParticipant" }
}
}
},
"timeStatsParticipant": {
"type": "object",
"additionalProperties": false,
"properties": {
"slot": { "type": "integer" },
"fastestLapTime": { "type": "number" },
"lastLapTime": { "type": "number" },
"lastSectorTime": { "type": "number" },
"fastestSectors": { "$ref": "#/$defs/number3" },
"participantOnlineRep": { "type": "integer" },
"mpParticipantIndex": { "type": "integer" }
}
},
"participantVehicleNamesPacket": {
"allOf": [
{ "$ref": "#/$defs/parsedPacket" },
{
"properties": {
"base": {
"allOf": [
{ "$ref": "#/$defs/packetBase" },
{ "properties": { "packetType": { "const": 8 } } }
]
},
"data": { "$ref": "#/$defs/participantVehicleNamesData" }
}
}
]
},
"participantVehicleNamesData": {
"type": "object",
"additionalProperties": false,
"properties": {
"vehicles": {
"type": "array",
"items": { "$ref": "#/$defs/vehicleInfo" }
},
"classes": {
"type": "array",
"items": { "$ref": "#/$defs/classInfo" }
}
}
},
"vehicleInfo": {
"type": "object",
"additionalProperties": false,
"properties": {
"index": { "type": "integer" },
"class": { "type": "integer" },
"name": { "type": "string" }
}
},
"classInfo": {
"type": "object",
"additionalProperties": false,
"properties": {
"classIndex": { "type": "integer" },
"name": { "type": "string" }
}
},
"leaderboard": {
"type": "object",
"additionalProperties": false,
"properties": {
"rows": {
"type": "array",
"items": { "$ref": "#/$defs/leaderboardRow" }
},
"note": { "type": "string" },
"session": {
"type": "object",
"additionalProperties": false,
"properties": {
"trackName": { "type": "string" },
"sessionType": { "type": "string" },
"timeLeft": { "type": ["number", "null"] },
"weather": { "type": "string" },
"lastUpdate": { "type": ["string", "null"], "format": "date-time" }
}
}
}
},
"stateEvent": {
"type": "object",
"additionalProperties": false,
"required": ["latest", "recent", "leaderboard"],
"properties": {
"latest": {
"type": "object",
"description": "Latest parsed packet by packet type number.",
"additionalProperties": {
"$ref": "#/$defs/parsedPacket"
}
},
"recent": {
"type": "array",
"items": { "$ref": "#/$defs/parsedPacket" }
},
"leaderboard": { "$ref": "#/$defs/leaderboard" }
}
},
"packetEvent": {
"type": "object",
"additionalProperties": false,
"required": ["packet", "state", "leaderboard"],
"properties": {
"packet": { "$ref": "#/$defs/parsedPacket" },
"state": {
"type": "object",
"additionalProperties": false,
"required": ["latest", "recent"],
"properties": {
"latest": {
"type": "object",
"additionalProperties": {
"$ref": "#/$defs/parsedPacket"
}
},
"recent": {
"type": "array",
"items": { "$ref": "#/$defs/parsedPacket" }
}
}
},
"leaderboard": { "$ref": "#/$defs/leaderboard" }
}
},
"sharedMemoryIngestRequest": {
"type": "object",
"additionalProperties": true,
"required": ["packets"],
"properties": {
"source": { "type": "string", "examples": ["shared-memory"] },
"sequence": { "type": "integer", "minimum": 0 },
"capturedAt": { "type": "string", "format": "date-time" },
"packets": {
"type": "array",
"items": { "$ref": "#/$defs/parsedPacket" }
}
}
},
"ingestAccepted": {
"type": "object",
"additionalProperties": false,
"required": ["ok", "packets"],
"properties": {
"ok": { "type": "boolean", "const": true },
"packets": { "type": "integer", "minimum": 0 }
}
},
"errorResponse": {
"type": "object",
"additionalProperties": false,
"required": ["ok", "error"],
"properties": {
"ok": { "type": "boolean", "const": false },
"error": { "type": "string" }
}
},
"leaderboardRow": {
"type": "object",
"additionalProperties": true,
"properties": {
"id": { "type": ["integer", "string"] },
"slot": { "type": ["integer", "string"] },
"sortPosition": { "type": "number" },
"position": { "type": ["integer", "null"] },
"positionChange": {
"type": ["object", "null"],
"additionalProperties": false,
"properties": {
"direction": { "type": "string", "enum": ["up", "down"] },
"places": { "type": "integer", "minimum": 1 },
"previousPosition": { "type": "integer" },
"currentPosition": { "type": "integer" },
"changedAt": { "type": "string", "format": "date-time" }
}
},
"active": { "type": ["boolean", "null"] },
"status": {
"type": ["object", "null"],
"additionalProperties": false,
"properties": {
"code": {
"type": "string",
"enum": ["unknown", "dnf", "dsq", "finished", "waiting", "drive_through", "pit_entry", "pit_stop", "pit_exit", "garage", "garage_exit", "invalidated", "blue_flag", "inactive", "racing"]
},
"label": { "type": "string" },
"tone": { "type": "string", "enum": ["good", "warn"] }
}
},
"driver": { "type": "string" },
"nationality": {
"type": ["object", "null"],
"additionalProperties": false,
"properties": {
"code": { "type": "string" },
"country": { "type": "string" },
"source": { "type": "string", "enum": ["udp", "override"] }
}
},
"vehicle": { "type": ["string", "null"] },
"vehicleShortName": { "type": ["string", "null"] },
"lap": { "type": ["integer", "null"] },
"sector": { "type": ["integer", "null"] },
"sectorRaw": { "type": ["integer", "null"] },
"sectorExtraPrecision": { "type": ["integer", "null"] },
"currentTime": { "type": ["number", "null"] },
"currentSectorTime": { "type": ["number", "null"] },
"checkpointSplit": {
"$ref": "#/$defs/sectorSplit"
},
"sectorTimeSplit": { "$ref": "#/$defs/sectorSplit" },
"lastLapTime": { "type": ["number", "null"] },
"latestLapSplit": { "$ref": "#/$defs/lapSplit" },
"fastestLapTime": { "type": ["number", "null"] },
"bestLapSplit": { "$ref": "#/$defs/lapSplit" },
"fastestSectors": { "$ref": "#/$defs/number3" },
"pitModeSchedule": { "type": ["integer", "null"] },
"pit": {
"type": ["object", "null"],
"additionalProperties": false,
"properties": {
"raw": { "type": "integer" },
"pitMode": { "type": "integer" },
"pitSchedule": { "type": "integer" },
"phase": { "type": ["string", "null"], "enum": ["Pit entry", "Pit stop", "Pit exit", "Serving drive-through", "Garage", "Garage exit", null] },
"penalty": { "type": ["string", "null"], "enum": ["drive-through", null] }
}
},
"highestFlag": { "type": ["integer", "null"] },
"flag": {
"type": ["object", "null"],
"additionalProperties": false,
"properties": {
"raw": { "type": "integer" },
"colour": { "type": "integer" },
"reason": { "type": "integer" },
"observed": { "type": ["string", "null"], "enum": ["blue", "black", "checkered", null] }
}
},
"raceState": { "type": ["integer", "null"] },
"raceStateCode": { "type": ["integer", "null"] },
"invalidatedLap": { "type": ["boolean", "null"] },
"carIndex": { "type": ["integer", "null"] },
"nationalityRaw": { "type": ["integer", "null"] }
}
},
"lapSplit": {
"type": ["object", "null"],
"additionalProperties": false,
"properties": {
"comparedTo": { "type": "string" },
"time": { "type": "number" },
"referenceTime": { "type": "number" },
"delta": { "type": "number" }
}
},
"sectorSplit": {
"type": ["object", "null"],
"additionalProperties": false,
"properties": {
"source": { "type": ["string", "null"], "enum": ["checkpoint", "timeStats", null] },
"basis": { "type": ["string", "null"], "enum": ["raceOrder", "personalBestSector", null] },
"checkpoint": { "type": "string" },
"comparedTo": { "type": ["string", "null"] },
"time": { "type": "number" },
"referenceTime": { "type": ["number", "null"] },
"delta": { "type": ["number", "null"] }
}
}
}
}