Developing for the project
Please use the project's homepage on GitHub to file issues and submit pull requests.
All code for the Open NEC project is currently written in Lua, plus some Python to automate the building process.
Train Simulator uses Lua 5.0. It will compile .lua files, but if an .out file is present with the same filename, the bytecode will be prioritized over the source file. Therefore, unless we want to require our users to unpack their .ap files, we must replace the target .out file with our own compiled bytecode.
Repository structure
Src\Mod\
maps to Train Simulator's Assets\ folder on a 1:1 basis. Replacement Lua code goes here.Src\Lib\
contains any common Lua code. The build system automatically includes these files when linting or compiling files in Src\Mod\.Docs
contains the Markdown text of this manual.wscript
contains build instructions, which are written for WAF.
Building the project
To compile the mod, you will need the following tools in your %PATH%
:
python.exe
: a recent copy of Python 3 is required. Our build system uses WAF, which runs on Python.luacheck.exe
: the Luacheck linter. Its static analysis capabilities are much appreciated for an untyped language like Lua. Although it was designed for Lua 5.1+, it works well enough on 5.0—with the exception of variable length arguments, which it misinterprets as "unused variables." The static Windows executable will work just fine.lua-format.exe
: the LuaFormatter code formatter. You can obtain a Windows executable from the repository for the official Visual Studio Code extension.compressonatorcli.exe
: The CLI version of AMD's Compressonator, a tool we use to generate DDS textures.
In the root directory of the project, run python waf configure
to confirm that your system has met all of these requirements.
The build process also needs to be informed of the location of Train Simulator—the game comes with several essential command-line utilities. The WAF script attempts to infer its location using the Steam uninstallation path in the Registry. If this autodetection fails, you should set the %RAILWORKS%
environment variable to the path to your copy of Train Simulator.
If all looks good after the configure step, run python waf build
to compile the project. The compiled files will output to the Mod\ folder, from which they can be copied into Train Simulator's Assets\ folder. (You can copy all artifacts into the Assets folder by running python waf build install
.) The build process will also run LuaFormatter on the code to enforce a consistent style.
Other useful WAF commands include:
python waf clean
: delete compiled files in the Mod\ folder.python waf distclean
: delete the Mod\ folder entirely.python waf release
: build a redistributable Zip archive for a release.
Programming resources
- Lua 5.0 Reference Manual
- Programming in Lua, First Edition
- Train Simulator Developer Documentation (sadly, incomplete)
- David Richardson's TS scripting reference
- AndiS's guide to signal messages
- AndiS's guide to AI train behavior
The following tools are not needed to compile project, but they may assist you in development work:
- unluac can be used to decompile and study (to varying degrees of success) Dovetail's Lua bytecode.
- My Rail Sim Remote program exposes Train Simulator's RailDriver interface via a REST API. You can use this in conjunction with cURL or a browser developer console to experiment with a locomotive's controls.
- Build the website with MkDocs using the included Visual Studio Code development container. Or, install MkDocs directly.
- If you have Discord, join the Train Sim Community server for modding tips, street cred, and comradery.
Reference material
- NORAC signal rules
- cActUsjUiCe's guide to the Northeast Corridor
- cActUsjUiCe's critique of Train Sim World's Northeast Corridor New York DLC
Coding style
- Please follow the standard Lua style. That means 2-space indents.
- Dovetail's programmers don't take full advantage of the language's features, so don't use their source files as a reference.
- Write packages using PiL's suggested "privacy" style, and classes using PiL's suggested "basic" style.
- Lua places heavy emphasis on tables and their
pairs()
andipairs()
iterators. I've created theIterator
package to introduce useful transformations and compositions for such key-value iterators.