The online racing simulator
Quote from amp88 :That's why I'm not at the point of releasing the app because I'm trying to improve the accuracy further.

Are using it on the smallest MCI update setting, 50 ms? I noticed your still using the 2 second delay between each update, I say don't bother, update on each new MCI packet you get. Yes there are a lot of calculations, but a 400 Mhz computer should be able to handle it.

Proposed Change to IS_ISI packet, regarding MCI/NPL updates.
It would be nice to have the option in the IS_ISI packet to have the an MCI/NPL packet sent when the car enters a new node. That way it would make this extremely accurate (within 1ms).
Quote from Dygear :Are using it on the smallest MCI update setting, 50 ms? I noticed your still using the 2 second delay between each update, I say don't bother, update on each new MCI packet you get. Yes there are a lot of calculations, but a 400 Mhz computer should be able to handle it.

Yeah, behind the scenes I'm using the smallest update time for best possible accuracy but I'm only displaying the gap (i.e. updating the LFS button) roughly every half second. CPU/memory usage at the moment is pretty minimal. With the control GUI used it's taking roughly 10 seconds CPU time (on a Q9450 @ 30.5GHz) and 60MB RAM for 25 cars in a 30 minute qualifying session and the average time to process a response from InSim is less than 0.2 milliseconds. Without the GUI it's taking just 1 or 2 seconds of CPU time and about 30MB of RAM in the same session and the average time to process a response from InSim is 0.01-0.02 milliseconds. Obviously as I add complexity into the system to try and improve the accuracy (which is going to include more floating point calculations and manipulation of more data) the requirements will increase, but I don't see it becoming an issue even worth thinking about. I've tried to design it from the ground up with performance in mind (i.e. when choosing ADTs and designing algorithms).

Quote from Dygear :Proposed Change to IS_ISI packet, regarding MCI/NPL updates.
It would be nice to have the option in the IS_ISI packet to have the an MCI/NPL packet sent when the car enters a new node. That way it would make this extremely accurate (within 1ms).

Yeah, this would certainly ease the situation.
Quote from amp88 :
Quote from Dygear :Proposed Change to IS_ISI packet, regarding MCI/NPL updates.
It would be nice to have the option in the IS_ISI packet to have the an MCI/NPL packet sent when the car enters a new node. That way it would make this extremely accurate (within 1ms).

Yeah, this would certainly ease the situation.

I wonder if the Devs would be willing to comment on this? If it is feseable within the current InSim system and the game engine. (Then game engine updates 100 times a second. 1 Second / 100 Frames = .01 Second Per Frame or 10ms per frame. From what I understand that's also why the games timing only goes down to .01 of a second and not F1 style .001 intervals. I wonder what effect this would have on the MCI/NPL updates by putting this into the main game loop and the performance of the game engine as a whole.) I am pretty sure this information was sourced from a TAA post (TAA if you could comment that would be awesome too.) but I believe he was quoting the devs at the time of writing.

Source: Collision Detection

Quote from Bob Smith :Also, the car moves every 1/2000th of a second, but collision checking only happens every 1/100th (because it's CPU intensive). So the collision code should really allow for this somehow.

Quote from the_angry_angel :I believe Bob isnt 100% correct in his explanation (Scawen, or anyone who knows better feel free to correct me); The main game loop runs at 100Hz (100 times per second). In this loop boundary box sanity checking occurs. However, there is a internal loop, which runs at approximately 2MHz (if I remember correctly). This inner loop moves the car and samples things like tyres, etc.

I'll consider this information authoritative, until proven otherwise.
Yeah, I've read before that some of the physics are done at a much higher rate than the car position updates. Obviously without Scawen's input we can't say for certain how much effort would be needed to send a packet when a player moves from node to node but I don't think it would be that difficult.

Anyway, progress update. I've been trying to improve the accuracy and do a little bit more tinkering over the last few days. I'm still not happy yet so it's going to take a bit more time before I release a test version.

For anyone who's interested here's some detail of the method for calculating the gaps I'm using at the moment:

Every time a driver enters a new node (node is determined using the MCI packet) store the CompCar object from the MCI packet for that lap.
When the player is viewing a driver who is on a hotlap and there is a lap to compare their current lap with (i.e. someone has completed a hotlap in the session already) the comparison begins.
  • Get the last CompCar packet for the viewed player's current lap.
  • Get the CompCar packet from the current fastest lap in the session at the same node.
  • Calculate the length of the lap completed at the position contained in the CompCar packet.
  • If one player has completed less of the lap compared to the other, calculate how long it would take to equalise the lengths completed using the difference in distance and the speed of the player who completed the shorter distance at the point they entered the node (from the CompCar packet).
  • Add the time calculated above to the time at which the player entered the node.
  • Calculate the elapsed laptime of each driver up to this point from the first node on this lap (which is standardised using the same method as above with the difference in length)
  • Return the difference in elapsed times calculated above.
The difference can be averaged over a number of nodes (e.g. return the average difference over the last 3 nodes) and more than one CompCar packet per node can also be handled. I'm still experimenting with getting the best accuracy for the lowest performance cost.

Something else I'm trying to add is a clickable track map that I've wanted to have a go at developing for a while but never had the data required to do it. I've attached a preview of the map in its current state (very simple (e.g. doesn't show direction of travel)).
Attached images
qualitickertrackmap.png
[ot]Where did you get the data from to make the track diagram?[/ot]
Quote from Dygear :[ot]Where did you get the data from to make the track diagram?[/ot]

By reading the details of the .pth files in the LFS/data/smx folder. The algorithm I'm using to read the details was originally posted here by Greenseed, but I've modified it slightly for Java. I've attached the 3 classes I'm using in the process of reading and storing track information. The TrackModel.java class contains the logic for reading in the PTH files and creating the classes that store the information, the TrackData.java holds data for each track in LFS (i.e. there's a TrackData object created for AS1, one for AS1R etc) and each TrackData object contains a number (usually 200-500) of OneNode.java objects. I don't know if you read Java, so if you have any questions about the code I'd be happy to try and answer them.

Other informational posts I used when looking for information on PTH files: 1, 2 and 3
Attached files
PTHTrackDataReading.zip - 6.1 KB - 239 views
#32 - mobu
amp88: Nice and easy to read code. Thanks for sharing.

/Morten
That's fantastic mate! I'll endeavor to make a PHP class to read PTH files .
I have some Python code that reads pth files, nothing fancy.

#!/usr/bin/env python
import struct

_HEADER = 'LFSPTH'
_VERSION = 0
_REVISION = 0
_HEADER_STRUCT = struct.Struct('6s2B2i')
_NODE_STRUCT = struct.Struct('3i7f')

class PthException(Exception):
pass

class _Node:
def __init__(self, file):
data = _NODE_STRUCT.unpack(file.read(_NODE_STRUCT.size))
self.X = data[0]
self.Y = data[1]
self.Z = data[2]
self.DirX = data[3]
self.DirY = data[4]
self.DirZ = data[5]
self.LimitLeft = data[6]
self.LimitRight = data[7]
self.DriveLeft = data[8]
self.DriveRight = data[9]

class Pth:
def __init__(self, path):
with open(path, 'rb') as file:
data = _HEADER_STRUCT.unpack(file.read(_HEADER_STRUCT.size))

# Read header.
if data[0] != _HEADER:
raise PthException('Invalid header')
if data[1] != _VERSION:
raise PthException('Invalid version')
if data[2] != _REVISION:
raise PthException('Invalid revision')
self.path = path
self.numNodes = data[3]
self.finishLine = data[4]

# Read nodes.
self.nodes = []
for i in range(self.numNodes):
self.nodes.append(_Node(file))

if __name__ == '__main__':
pass

Anymore progress?
No, I've been busy with other things lately.
2

FGED GREDG RDFGDR GSFDG