So, I implemented something like this for SimFIA around 15 years ago now. It only used the Split packets because it was the only thing that was reliable. We would have the Timing and Scoring interface that would show deltas to car in front, car behind for our league races, but it would only show for 5 seconds when the player passed a sector. The FiA and FOM get their timing information on the F1 cars from the timing lines as well, but not just each sector time, but also the mini-sectors between the marshal posts (around 200 meters apart on average) each have a timing loop on them. The FOM TV feed actually updates the deltas between the cars on each timing loop by calculating the delta between Car 1 and Car 2's time between the same timing loop. That effectively works out to an array of timestamps. It's also why you don't see a sector time display, until all cars have passed the first sector timing line.
The array would be something like ...
struct Cars {
UCID u8;
PLID u8;
Info u8; // Is Player; Is IA;
Sp0 u8; // Padding. Always 0;
Lap u16; // Current Lap; Used to index into Laps array.
Node u16; // Current Node; Used to index into Best and Laps array.
Last u32; // Current Timestamp; Used to show last update from car.
// Array of Nodes
Best[Node] = CarInfo;
Laps[Lap][Node] = CarInfo;
}
struct CarInfo {
Lap = u16; // 24 Hour Races could have more than 255 laps.
Node = u16; // Node ID
Time = u32; // Timestamp (Milliseconds, So / 1000 for seconds.)
// Location in map in LFS Meter Units.
LocX = u32;
LocY = u32;
LocZ = u32;
// Vector of their velocity in LFS Meters Units.
// 9.80665 m/s² = 952_863 = 1G; Z should equal this when sitting still on level ground.
// -49.03325 m/s² = -4_764_315 = -5G; X Formula Car Hard Breaking.
VelX = i32;
VelY = i32;
VelZ = i32;
// Heading Degrees from Center +90.00 = 9000; -180.00 = -18000
HeadX = i16; // -Left / +Right
HeadY = i16; // +Up / -Down
// Rotating Degrees from Center +90.00 = 9000; -180.00 = -18000
RotX = i16; // Roll: between -180 and 180 deg;
RotY = i16; // Pitch: between -90 and 90 deg;
RotZ = i16; // Yaw: between -180 and 180 deg;
}
If you are going for iRacing type delta for players to compare against themselves, a much higher resolution timing loop is required. I'd want a timestamp for every time they enter each track node. Yeah, that's going to be like 350+ data points for each lap, and sometimes much more. I'd additionally, want their X, Y, Z world cords, as well as their heading vector, and speed (in the LFS meters per second, so the u32 where the upper u16 is the actual meters, and the lower u16 is the 65536th of a meter.)
IS_GPS {
Size = 12; // Bytes * 4;
Type = ISP_GPS;
SubT = u8;
ReqI = u8;
UCID = u8;
PLID = u8;
Info = u8; // Is AI, is Player;
Sp0 = u8; // Padding
Lap = u16; // 24 Hour Races could have more than 255 laps.
Node = u16; // Node ID
Time = u32; // Timestamp (Milliseconds, So / 1000 for seconds.)
Speed = u32; // Speed in m/s using LFS Meter Units.
// Location in map in LFS Meter Units.
LocX = u32;
LocY = u32;
LocZ = u32;
// Vector of their velocity in LFS Meters Units.
// 9.80665 m/s² = 952_863 = 1G; Z should equal this when sitting still on level ground.
// -49.03325 m/s² = -4_764_315 = -5G; X Formula Car Hard Breaking.
VelX = i32;
VelY = i32;
VelZ = i32;
// Heading Degrees from Center +90.00 = 9000; -180.00 = -18000
HeadX = i16; // -Left / +Right
HeadY = i16; // +Up / -Down
// Rotating Degrees from Center +90.00 = 9000; -180.00 = -18000
RotX = i16; // Roll: between -180 and 180 deg;
RotY = i16; // Pitch: between -90 and 90 deg;
RotZ = i16; // Yaw: between -180 and 180 deg;
}
That should get us pretty close. The
CarInfo->Best[CarInfo->Node]->Time - CarInfo->Best[0]->Time
gives you the delta of time into the lap. If you're faster into that node the time delta will be negative.
CarInfo->Best[CarInfo->Node]->Speed - CarInfo->Speed
if positive, you are faster than into that node speed wise than before, negative you are slower speed wise into that node.