I decided to remove the WIP status with the latest update to the mod \o/ While there's still room for improvement (such as stuchlo's suggestions), I'm pretty happy with what I've got so far, and I'll try to get the other versions published (and work on the road version's interior).
I just updated the mod and removed the WIP status \o/ There's still room for improvement, but I'm pretty happy with what I've managed to do so far.
For hybrid tyres, as Kova said, there are other versions in the works, such as the Laurent Coil RX, which is already available, but also coming are the rally5 and rally3 versions, as soon as the RX gets published and I can submit them.
Scawen mentioned that the layout object format could be updated to double capacity at some point, and my suggestion for the possible new format, along with doubled object count, would still result in pretty small layout files, so this could be a big win for usability and layout possibilities.
Thanks a lot! I completely agree that the interior can become extremely bright, because of how LFS does lighting currently (and rough metallic "overlay" materials that get completely black right now, but render properly in the editor). I do hope that the graphics update will alleviate this with shadows, but I do indeed need to try applying some textures there. Do you create UV maps in Blender using a selection and projecting from the camera? As I guess this is the closest to how LFS does mappings. I haven't been using alpha textures more than for on/off transparency so far, so I need to see how partial transparency turns out for variable shine.
Also, on another note, I noticed that creating a mapping with a color, say 50,50,50 in the editor, and another mapping with a texture that has that same 50,50,50 color as a background, the result is slightly different (I saw this happen with both GIMP and Krita). Do you have any idea why this happens? I was wondering whether color profiles could have something to do with this.
In the example below, the slightly brighter triangle is the one that has a texture applied, while the rest is an untextured mapping. Both cutouts have the same settings (except the texture of course).
I spent some time optimizing the geometry where I could, because I'm really reaching into the 65k triangle limit. The nice thing is, without destroying the shapes (too much), I am actually managing to add more things while saving triangles... to an extent.
The interior's raw frame was updated to be less blocky, door panels were added (with door handles to be added, but those are costly triangle-wise without making them extra blocky), and I added more "accessories" (fire extinguisher nozzle and control box).
I also added textures to new and existing parts, and I'm now this close to calling the mod "done" (or at least not WIP anymore).
And finally, I'm making some progress on the other variants too, as I recently submitted the RX version, and will soon also submit the rally3 version. I'm not really planning to go into as much details for the rally3 version, in part because I have less reference materials, and in part because I don't really have the triangle budget anyway (at this point, I have ~61.1k triangles for the Cup version, and ~64.2k for the rally3 version).
Once the Cup, RX and rally versions are out of the way, I will switch focus to the road version; for the exterior, I need to model the front grille, and for the interior... almost everything needs to be done.
I haven't tested it, but this may be achievable in a similar way to what I did in the video I posted about improved pit limiter behavior. Basically forcing throttle to zero for a short while when reaching the rev limiter to simulate ignition cut; this won't make any loud popping noise, but should act as a rev bouncer if done properly. But of course, "properly" may also vary from car to car, so maybe that's something that could be set on the mod side.
Looking back, I think the issue stems from how Godot InSim handles text in the various InSim packets (and, I believe, many other InSim libraries): basically, codepages are a pain to deal with, so we store everything as UTF8, and only present UTF8 to the user, for both input and output; because of this, Godot InSim gives access to the InSimMSOPacket.msg property as a UTF8-encoded string only, and using TextStart to offset this string (or the "UTF16" intermediate string) doesn't work in the scenarios I presented.
I believe you are most likely right that there is in fact no issue here, and I was just not using TextStart as intended. I will, however, keep calling this property "unreliable" in Godot InSim, because it actually is, as a result of the text handling. I ended up adding utility functions to retrieve a message's author, and the message's contents, based on the regex shown above, which is a workaround I'm okay with.
I have a semi-automatic (quarter-automatic?) solution to this, which I could improve a bit with InSim (for taking screenshots automatically).
The idea is as follows:
Create all "colors" (skins + car colors) you want to generate
Place the camera as needed (R or L in the garage, then V to get into the viewer, or change the camera directly in the viewer)
Take a first screenshot with a black background
Set the background to the lightest gray you can
Take a screenshot for every skin/color you want
Use imagemagick to create a mask and automatically remove the background for every car
I have a small Godot program that automates the imagemagick part, and adds some GUI elements to set car name and number, drivers, team, etc.
It uses a JSON file to set the data for each car, which could also be used by InSim to automate the taking of screenshots after the first one.
This can result in things like this:
But of course, since the background is removed by imagemagick, you can also just drop this into a stream overlay.
It would certainly help if we could get a player's colors via some InSim packet, so we don't have to ask them to send their colors or manually recreate them.
Also, one small caveat: the /colour command does not allow us to select one of the default colors (or at least, I don't know what parameter to pass for default colors), so we have to duplicate those first.
LFS being the single fastest racing sim to boot up (we're talking 5 seconds tops, it's barely over a second on my PC to get to the menu), I'm not sure this is really a problem (at least we don't have to sit through a dozen splash screens or various logos, then wait half a minute to get into the menu, and another minute or 2 to go through the menus and load the track + cars).
Now, it's true that credits could be made available from the main menu, but you can just launch LFS again. Also, the credits are not very long and are looping. And finally, it may not be a bug at all that /entry doesn't work there, as it's likely just an exit path in the code: disable all command processing, show credits, exit on input.
The current behavior of the pit speed limiter is a bit weird and unrealistic, as well as flawed in its speed tracking. I will list the issues I have noticed, what can be improved (some suggestions have already been made in the past), and also show a custom pit limiter I implemented with a PID controller and IS_AIC packets.
The general idea of the limiter is, of course, to avoid exceeding the speed limit. LFS quite clearly uses a PID controller for this, and a heavily damped one, probably to avoid the slight overshoot that a more reactive controller can exhibit. While I believe some real-life limiters do override the throttle application to track the speed limit, it's quite common to see ignition cut as the way to limit the speed. In LFS, this could easily be done by setting throttle to zero when reaching the limit.
Now, on to the list:
The limiter is overdamped, causing it to take some time to reach the actual speed limit.
It is too conservative, and often tracks at 78-79 km/h on flat surfaces.
It doesn't handle uphill properly, speed can drop to 76-77 km/h.
The way I see it, the PID controller uses a lot of Kd to avoid overshoot, and little to no Ki, causing the speed drop when going uphill. Either that or the actual target is wrong when going uphill, e.g. 80 km/h in 3D space which gets projected to the horizontal plane.
I played around with the AI control packets to make a custom pit speed limiter, here's a comparison video:
Key takeaways from this:
Using only a PID controller, we can definitely improve speed tracking without overshoot, with less damping, less conservative tracking, and better uphill handling.
The PID controller tracks the speed limit (with a 0.5 km/h margin in my implementation), and cuts to zero throttle if the target value is exceeded.
My implementation uses a high Ki value for better uphill management, and uses Kd to control the smoothness of the tracking, which can lead to pseudo-simulating ignition cut limiters when Kd is too high.
The main issue I have with my current implementation is that I have to rely on the velocity vector included in the IS_AII packet, while pit limiters would normally measure speed at the wheels (driven or not, depending on the system). I believe LFS already does that, since spinning the wheels with the limiter enabled does decrease throttle.
And of course, as has already been suggested (again recently), and is shown in the video, it would be really nice to be able to set a custom speed limit (since currently, only Rockingham has a different limit).
As a final disclaimer, I have not tried any car other than the Coil Cup, so results may vary. However, cutting throttle to zero when exceeding the speed limit should work for all vehicles, and could even help avoid the current behavior where shifting up can cause a car to exceed the limit temporarily.
EDIT: A few additional notes:
Performance is further improved by clamping the derivative term to be negative only, so we don't add excessive throttle when resuming from an "ignition cut". I also tried my implementation with a different car, the McLata GT3 (303CB1), as I know it tends to overspeed when shifting to 2nd gear - no change here, the car jumps from 79.5 to ~81.5 from shifting up due to engine inertia alone, so it would be up to the driver not to overspeed. It did however improve the behavior as the speed reaches the limit (less risk of overspeed, contained within the 0.5 km/h margin).
Yes, I know that the PID I show here is technically very poorly tuned, as it is very twitchy; that is however exactly what I'm going for. "Proper" tuning is in the order of 10x lower values, much less Ki, and Kd used for "better" damping, but then I get results closer to what LFS currently does.
I'm finally ready to release the first public version of GIS Hub! It obviously has a lot of room to grow and improve, but this should be quite usable already (it has already seen some real use over the summer for a couple races, and that was still much earlier in the development).
If you're interested, you can head over to GitLab to get the binaries and a few example modules. As a reminder, if you want to develop modules for GIS Hub, you will need the Godot editor and a version of Godot InSim that is compatible with your version of GIS Hub (3.0.1 at the time of this writing).
Here's a selection of additional skins, as color variations of the default ones. Some of them are based on actual color variations, others are made up.
I just released v3.0, based on Godot 4.5 (I believe it should mostly still work with Godot 4.4, but LYTObject now uses a class exposed in Godot 4.5 for proper raycasting to the ground).
I've been optimizing the geometry a bit (managed to save about 3k triangles with mostly minimal visual changes), which will help when I find the time to finish the interior, so I can finally remove the WIP status. The skin template was modified slightly to accommodate the changes, of note being a better layout for the rear wing, which now avoids overlaps and allows painting its front and back edges more easily; the plastic triangles between the front bumper blade and DRL covers can also be painted now, the lifting blocks can be painted separately, and the rest is just a few changes from the geometry optimization, which should not require changes unless you were closely following the geometry (if you made skins that only fill the alpha mask, make sure to check the rear corners, where the transition between rear view and side views has changed).
In the meantime though, I started working on default skins that are more interesting than plain colors with the same stickers every time. I have 7 of them, inspired by real Clio Cup liveries, mostly done (paint jobs and some of the common overlays are done, but most of them still need to get a proper logos and brands rework). I am planning to use all of the 9 default skins we can have for a mod, so I need one more (I'll keep the plain white one as well), and will most likely provide 2048x2048 skins in this thread or the mod page itself with color variations.
I will also officially introduce a "Cup" configuration, which will let you write a number on all 4 windows, using your license plate. In this configuration, the actual plate at the rear will read "Coil Cup Series" instead, and the numbers on the windows are made to fit 2 digits and nothing else.
I must say I didn't think of the possibility to just forward the data to a web client, and I guess you may want to avoid too much data processing there. In my live gaps implementation (not delta), I keep track of the last updated node for each car, and only update a node's timestamp when the node from the IS_MCI packet is different from the last updated one. For gaps between cars, and a decently smooth map animation, 250ms between packets is a decent interval, you can interpolate map positions from there using heading and speed (which is effectively a 2D version of the velocity vector you proposed), and I don't think there's much point in updating gaps in the standings more often than once or twice per second anyway.
If you want some telemetry data for all cars, running IS_MCI at 100Hz (with timestamps and pitch and roll included, instead of just heading) should be good enough (the additional angles would help showing cars rolling over too, if that's needed). You can also prune data from the stream of IS_MCI packets to only keep new nodes (as explained above).
For delta itself, my implementation uses OutSim (because it relies on the indexed distance, which I can recreate approximately from the PTH file (this requires creating an accurate PTH file for custom layouts), and delta only applies to the local car anyway, unless you want to display the delta for every car e.g. during qualifying), and I just compare the reference lap and current lap distances at the current timestamp offset by lap start timestamp, so we don't need nodes here. This assumes that you're driving close to your best time, though, since it can get pretty inaccurate otherwise, being distance-based.
I like the general idea of what you're proposing here, but I think there are some bits that can be removed for optimization:
The Cars struct doesn't really need UCID or Info (as long as that Info byte only contains the AI flag, at least), since those can easily be retrieved from the PLID.
Similarly in IS_GPS, Info, PLID, and SubT (what is it supposed to represent?) can be removed, which saves us 4 bytes with the spare Sp0. Although to be honest, I think this could also be achieved with an upgrade IS_MCI (or rather CompCar, which should include pitch and yaw in addition to heading).
Overall, I think your proposed IS_GPS, CarInfo, and Cars structs overlap a bit too much, and similar info could be retrieved by adding pitch and yaw to CompCar, as well as timestamps to IS_MCI. The tracking of timestamps at each node could probably be left to InSim developers (I did that myself, I know KingOfIce did too - not sure how exactly, but likely the same principle), but we would really need to be able to load custom PTH files via InSim for this to work in custom layouts.
And another hurdle is the lack of a signal for race start, which, while it helps prevent perfect starts via InSim, also prevents proper time tracking (even in hotlap mode, where we don't know when the finish line is crossed for the first time). Having a packet sent a few seconds after race start, and including the timestamp of the start, could be pretty nice for this.
I certainly hope that turning the headlights off during the night will disable the "physical" lights, not just the textures, otherwise things will look very weird. Your first question is interesting though, as it wouldn't be so surprising that lights are "optimized out" during day time; however, I think that would be a mistake in some situations, e.g. going through a tunnel/underpass (KY3, South City) or just into the shadows of buildings in South City in some lighting conditions. There are also more tunnel-like driveable areas in the updated Kyoto and South City.
Another concern I have regarding headlights is how far they can illuminate: I believe AI turns on the high/full beam at night, and well, that doesn't really look like high beam lights to me, but rather low beam. Regulations may vary for each country, but high beams should typically illuminate at least around 100m, while low beams are around 30m (at least that's what regulations say in France). In the videos, it looks like the lights barely reach 30m, let alone 100, which might make racing even more difficult than it should already be at night.
And on a related note: mods - I assume all vehicles will have either one or two "physical" lights, but will we be able to set their position (and orientation) manually? I imagine beam asymmetry is not too much of a concern and doesn't really need to be accounted for.
EDIT: To be fair, even from real life aerial views at the likes of Spa 24h or Nurburgring 24h, the visible illuminated spot on the road in front of the car doesn't reach that far either, but still a bit more than what we can see here. However, in the attached screenshot, the yellow car at the front doesn't appear to be illuminated by the white car's lights at all, when they look like they should be around 25m apart.
Also good to see (at least from what I can see in the 2 videos) that AI seem to have a smoother transition into the pitlane. In the current public version, in some configurations, AI can swerve pretty heavily to get into the pitlane, or when exiting, they will brake and turn (e.g. BL1 into chicane). Or maybe it's just the updated tracks that have their blend lines reworked?
On the multithreading front, I was wondering: you say graphics and physics are split over 2 cores, but aren't you using more threads now for various things? Is the out-of-pit stutter mitigation only about spreading the loading over several frames, but not several threads? I was also wondering about splitting car physics over a few (physical) cores, say 16 cars per core or something.
But in any case, I just hope you (and Eric) are now closing in on the finishing touches leading to the test patch, so we can both enjoy it and hopefully have some useful feedback for you.
Hi there, here are a few punctuation issues (missing spaces) I found using regexes:
Question marks:
French.txt:3a_exitprog Quitter LFS?
French.txt:3a_endonlin Finir le jeu en ligne?
French.txt:3a_levonlin Quitter le jeu en ligne?
French.txt:3h_kickplyr Expulser le joueur %s^8? (%s^8)
French.txt:3a_deletset Supprimer le setup?
French.txt:3a_deletcol Supprimer les couleurs?
French.txt:3g_deletrep Supprimer le replay?
French.txt:3a_exitnosv Quitter sans sauvegarder?
French.txt:3a_delchnlq Supprimer le canal?
French.txt:3a_clrall_q Effacer tous les objets de la configuration?
French.txt:3g_delete_l Supprimer la disposition?
French.txt:3g_lockques Verrouiller Live for Speed?
French.txt:3a_overwrex Remplacer le fichier existant?
French.txt:3g_deleteex Supprimer le fichier existant?
Exclamation marks:
French.txt:3g_not_time Vous n'avez pas fini dans les temps!
French.txt:3b_wlcmxinr Bienvenue! Il y a %d pilotes dans le salon
help_French.txt:^3Bienvenue sur Live for Speed!^8
I looked for "?", "!", ":", and ";", so those should be all occurrences (there are some for ":", but they're not used as punctuation, so those are fine as is).
Anyone who has read through the InSim.txt doc, either to make an InSim library or create an InSim app from scratch, knows that parts of the documentation are a bit difficult to parse, because there are many mentions of "see below", but how far below we need to look is not always obvious.
Using a regex search, I found 50 occurrences of "see below", and I believe 14 of them could use some rewording, or directly reference the corresponding enums. The rest are ok as the corresponding info is almost always directly following the "see below" mention.
struct IS_SFP: "Other states must be set by using keypresses or messages (see below) → this one should reference TEXT MESSAGES AND KEY PRESSES
struct IS_RST: "race flags (must pit, can reset, etc - see below) → biggest offender, you have to scroll 700 lines to find the corresponding info; this should reference the HOSTF_ enum
struct IS_CNL: leave reason → should mention LEAVR_ enum
struct IS_LAP, IS_SPX, and IS_PIT: penalty → should mention PENALTY_ enum
struct IS_PLA: Fact → should mention PITLANE_ enum
struct IS_CCH: Camera → should mention VIEW_ enum
struct IS_PEN: OldPen, NewPen, and Reason → should mention PENALTY_ and PENR_ enums
struct IS_PFL: Flags → should mention PIF_ enum
struct IS_FIN and IS_RES: Confirm, Flags → should mention CONF_ and PIF_ enums
struct IS_UCO: UCOAction → no description, should add "see below" and/or mention UCO_ enum
BUTTONS: "You can also make buttons visible in all screens - see below" → this should probably mention the Inst byte or reference INST_ALWAYS_ON, as the relevant info is buried in the middle of everything else (buttons are a complex subject with dense documentation).
More of a nitpick, but ALLOWED CARS also has 2 occurrences with SMALL_ALC reading "cars (see below)", with the IS_PLC struct in-between; the car list itself could use a "// Cars" title or something.
And a bonus one, may be intended: CAR LIGHTS uses the Switches word everywhere, like CAR SWITCHES - I was just wondering if it should be Lights instead, or if Switches was intended?
The additional data space could then be used for added precision for pitch for some concrete objects, maybe allow more colors for some objects, could also help store more variants of the letter signs (maybe even some symbols?), etc.
How open would you be to opening the development/maintenance of those "auxiliary" tools to the community? I'm not volunteering, but I'm sure some people would be interested. This would probably be best handled by giving access to a select few trusted people, and only disclosing relevant parts of the codebase.
While I'm honestly not certain about the Relay (but I do know it has a different handling of packet size ), the REST API seems to be quite popular: I was told that's what is used to authenticate people on the LFS Discord server, and it's also very handy for fetching data about existing mods.
On the mods side, there are even a few things that I, and most likely the rest of the community (cruise server InSim devs in particular), would like to see:
the ability to fetch multiple mods per request: currently, we can get the mod list in a single request, but only a single mod with full details, which means we have to perform thousands of requests to update data for all mods; including the full details in the whole list, or fetching multiple skinIDs would help both ends.
there seem to be missing fields: for instance, we cannot get the Approved status of a mod from the API.
If Victor is not interested in maintaining those anymore, and to avoid distracting you even more from your own tasks, maybe it would be a good option to let some of us help in those areas?
Just for reference, I made a REST API demo for Godot InSim, fetching the mod list and then details about a select few mods - cruise server InSim devs are actually feeding entire vehicle databases from those requests.
Getting people to read is probably the biggest challenge in dev, or any business, really. Or not even in business: take any live stream of a race; even if the laps are displayed on the screen, you can be sure someone in the chat will ask how long the race is.
The main thing you can be sure people will read is API documentation, when they need to implement the API and even then, some parts may be skipped over, willingly or not...
But surely, if the test patch/next update has a flashing button for the unlock code, I expect people will notice it more easily.
I don't know why you felt the need to mention my answer as "focusing on the things which do not matter": you provided a number of combinations (generated by AI, but that doesn't matter in the end), which was wrong, I just pointed that out...
Your follow-up with the updated version does give the right answer, okay (but we didn't really need the whole reasoning, 58^20 was ok from the beginning, the "result" the AI gave was just wrong), now back to the "things that matter": 20 characters is way too long, I guess? This is a code you're supposed to copy-paste anyway, how can it be a problem? Should Scawen make a system that generates 10 characters or less, so people who copy the code by hand have an easier time? Is it a sensible thing to do when inputting the unlock code is something you're supposed to do once and forget about it? People who need to regularly get a new code probably should either get the email on their PC to copy-paste, or share their phone's clipboard via wifi or any other means.