The online racing simulator
GIS Hub
The GIS Hub (or Godot InSim Hub) is, as its name implies, a hub application for Godot InSim. Its main goal is to provide a common interface for multiple Godot InSim apps to interface with LFS via a single InSim connection - which means you can have as many "apps" running as you want, sharing the same InSim connection, instead of being limited to the 8 connections LFS supports.

This allows the hub app to be the only "heavy" part, as a single Godot executable (and its ~80MB) is necessary here; all Godot InSim apps can instead be distributed as "modules", as small .pck files, and run directly in GIS Hub.




GIS Hub provides the following features:
  • Manage a single InSim connection to use with any number of modules (practical limit is 50)
  • Manage modules (discover on startup, hot enable/disable), with active modules arranged as tabs in the GUI
  • Save and load module configuration, including InSim settings and enabled modules, and give access to a per-module data folder
  • Route packets from LFS to all modules and the other way around
  • Mirror Godot InSim functions for sending packets, managing InSim buttons, etc. at the module level (wrapper functions)
  • Callback functions for all InSim packets, ISP_TINY/ISP_SMALL packet subtypes, and Relay packets
  • Inter-module communication with the ability for a module to send arbitrary data, and subscribe to other modules to handle data they send
  • Graphical interface for included modules (InSim settings and module manager, log module, etc.), and all modules can provide their own GUI
For instance, the GIS Hub tab is itself a module, although it doesn't do much on the InSim side. The Log module, however, provides a visual display of all packet traffic, and includes the name of the module when a packet is sent (or defaults to "InSim" if Godot InSim sent the packet automatically).
These 2 modules are considered "core": they are included in the GIS Hub app, and cannot be disabled. You can however disable logging through the Log module's options.

All other modules, including those distributed with GIS Hub, can be enabled or disabled at any time. Adding a module is as simple as dropping a .pck file in the "modules" folder next to the GIS Hub executable.
Modules can write config and data in their dedicated folder, located in the "user://modules" directory, which corresponds to:
  • Windows: "%APPDATA%\Godot\app_userdata\GIS Hub\modules\<module name>"
  • Linux: "~/.local/share/godot/app_userdata/GIS Hub/modules/<module name>"
As an example, the Teleporter module allows configuring the position of its InSim button interface, and saves it to its data folder (and will read it when enabled, of course). It also reads saved teleport destinations in txt files in the "spawn" subfolder, which means you can easily modify destinations without exiting the app, and even update the destinations for the current track by simply disabling and re-enabling the module (as destinations are updated when the track changes or the module is enabled).


Downloads and documentation:
GIS Hub is not released yet, but will likely be soon after Godot InSim 3.0, which I plan to release shortly after Godot 4.5 is available. You can still download it from the GitLab repository and use it or create modules. Do keep in mind that it may still be unstable at this time, and requires a beta version of Godot 4.5 to work with the latest version of Godot InSim.

A documentation website for module developers is in the works; the public API is also documented inside the Godot editor, and you can read the source code of both core and other modules for reference.


Provided modules:
GIS Hub: [Core] This module provides the main interface for InSim settings and module management.

Log: [Core] This module displays all InSim packet traffic, including timestamps, packet direction (and the sender module if relevant), and a human-readable version of the packet contents (which may omit some data, depending on the packet type). It also creates a log file with the full data for all packets, and allows loading such files back into its GUI for easier reading.
Log options include color management for log files (none, ANSI, BBCode), whether to log files to screen and/or file, and whether to include NLP/MCI packets.

Teleporter: This module provides the "teleport" command to display a simple InSim button GUI allowing to choose a teleport destination. Such destinations can be included in a "track.txt" file according to the format in the provided examples, and files should be named according to the track they are intended for (e.g. "BL1.txt", "SO4R.txt"), or only the first 2 letters for open configs (e.g. "WE.txt" instead of "WE1X.txt").
The "teleport" command can be typed either as "/i teleport" or using the InSim connection's prefix ("!teleport", "@teleport", or any other prefix character).

Messager: This module provides a simple text entry GUI allowing you to type messages directly in UTF8, without having to go through the multiple LFS character pages. You can also easily change text color on the fly without having to retype text, and you can also mention someone using the list of connected players, just like you would in the game.
Do note that LFS has poor support for UTF8, despite the addition of code pages for multiple languages, so many characters are not supported and will produce garbage.
Additional planned features include saving shortcuts to custom messages and message history. Providing a virtual keyboard to show characters from some code pages, as you can see in LFS, is very unlikely to happen.
Attached images
gishub_1.jpg
gishub_2.jpg
As a quick module development introduction, here are some guidelines, virtual methods for module management, InSim callbacks, and what I consider to be best practices.

Modules are Godot scenes based on a MarginContainer, with a script inheriting GISModule. The only thing a module is required to do is provide a name for itself, in the _initialize_module() virtual method, which must return a String. After that, modules are free to do whatever they want within the possibilities offered by Godot: logic only, 2D graphics, or even 3D graphics.

While Godot InSim provides signals to connect to, GIS Hub connects itself to those signals, and provides callback functions instead, that you need to implement. For instance, you don't manually connect to the isp_mso_received signal, but directly implement the _on_isp_mso_received() callback.

GIS Hub provides wrapper functions for all Godot InSim helper methods that send packets (send_message(), add_button(), etc.); helper methods that are only used to get data or otherwise don't result in sending packets have no wrapper, and should instead be accessed via the hub_insim variable available to all modules.

Virtual methods for modules include the following:
  • _initialize_config(): Assign a custom module config class to your module.
  • _initialize_module(): Assign a name to your module, and optionally perform initialization before adding the module to the scene.
  • _ready_module(): Perform scene initialization, called when the module is first enabled.
  • _load_config(): Define steps for loading module configuration (such as updating the module's GUI).
  • _save_config(): Define steps for saving module configuration (such as updating values from the GUI). Call save_config() (no underscore) when you want to update the saved configuration.
  • _on_insim_connected(): Called when InSim connects to LFS.
  • _on_insim_disconnected(): Called when InSim disconnects from LFS.
  • _on_module_enabled(): Called when the module is enabled. If InSim is connected, _on_insim_connected() will also be called.
  • _on_module_disabled(): Called when the module is disabled. If InSim is connected, _on_insim_disconnected() will also be called.
  • _on_module_sent_custom_data(): Called when a subscribed module sends custom data, that you can then handle here.
The following is a very basic module example, which sends a message upon InSim connecting (or enabling the module if InSim is already connected), and logs incoming messages to the screen, using a RichTextLabel:

class_name MyFirstModule
extends GISModule

@onready var rich_text_label: RichTextLabel = %RichTextLabel

func _initialize_module() -> String:
return "My First Module"

func _on_insim_connected() -> void:
send_message("Hello GIS Hub!")

func _on_isp_mso_received(packet: InSimMSOPacket) -> void:
rich_text_label.append_text(
LFSText.convert_colors(packet.msg, LFSText.ColorType.BBCODE) + "\n"
)

Now for some "best practices", I would recommend the following:
  • Naming: Name your module class "ModuleMyCustomModule", and your module config "ModuleMyCustomModuleConfig", to avoid naming conflicts. You can return whatever you want in _initialize_module(), but should likely stick to "My Custom Module".
  • Typing: I strongly recommend that you use typed GDScript as much as possible, as this helps both with code autocompletion and catching errors. The GIS Hub project considers untyped variables as errors, and also errors on most "unsafe" GDScript warnings.
  • Code order: You should ideally follow the official GDScript style guide as a general rule. For GISModule virtual methods, I suggest the following order: _initialize_config(), _initialize_module(), _ready_module(), remaining virtual methods (grouped by theme, such as _load_config() and _save_config(), or ordered alphabetically). After that, GISModule callbacks (so all _on_isp_xxx_received() methods) and remaining overridden methods, then public methods, then private methods.
  • GIS Hub vs Godot InSim: Modules can access the hub_insim variable, which is the InSim instance handled by GIS Hub. You should only use it when you actually have to, and use methods provided by GIS Hub when possible. Feel free to report missing wrapper methods in GIS Hub if you find yourself using hub_insim too much or when you don't expect it. However, you can and should use other features provided by Godot InSim, such as LFSText for text handling, GISTime and GISUnit for converting data, etc.
  • Module integration in the hub: Handle all InSim packets you need to provide a smooth integration in the hub; if your module displays an InSim button GUI to currently driving players, you want to make sure those buttons are removed when the player spectates or pits, or when the module is disabled, for instance. Keep your module's internal state as clean as possible, and provide options for InSim button placement. You should also make sure your code is not likely to crash the entire app, so you need to handle situations where you may try to access data from null objects, etc.
And finally, on the distribution and security side, I would recommend providing the source code on a public repository (GitHub, GitLab, etc.), and if possible distribute PCK files generated via CI, to ensure they are consistent with the source code. I will strive to do the same for GIS Hub itself and all modules I create.

FGED GREDG RDFGDR GSFDG