~lucidiot's wiki

Microsoft Train Simulator Packaged Activity

The 2001 video game Microsoft Train Simulator (MSTS) allows players to install new routes to play in, new trains, and new activities. Activities are scenarios that apply on a specific route. They specify what AI traffic should be where and when, where the player starts and in which trains, which assignments they have (stopping at a station, coupling or uncoupling cars at specified locations, etc.), which messages should appear and when, and more.

Some tools are included to create routes, trains, train cabs and activities. MSTS was for a while the most popular train simulator, so it has a pretty large community that has developed even more tools and shared many additions. There even were paid additions to the game being sold on CDs or DVDs.

Routes and trains usually come in the shape of an archive with a README file that explains how to install it into your game. But activities have their own format, called a Packaged Activity, with the .apk extension. This has nothing to do with Android packages, which came in many years later.

The game provides ways to both pack and unpack activities into those Packaged Activity files, but the unpacking utility, TSUnpack.exe, found in the UTILS folder of the game, has proven to be quite unreliable or difficult to use. There are many unofficial extractor tools out there, or converters that can turn activities into ZIP files that are compatible with OpenRails, the open source successor to MSTS.

When I looked for an extractor that could run on Windows XP in late 2021, my options were quite limited. There was very little documentation or open source software available, so I decided to write my own software and document it.

File format

I wrote a Kaitai Struct schema for this format.

String

The file format uses UCS-2 little-endian as its text encoding. Strings are both fixed and null-terminated, with two null bytes since this is UCS-2.

Length Text
Length
32-bit unsigned integer. Size of the string, in characters, including the final null character.
Text
Text, encoded using UCS-2 little-endian, with a final null character (two null bytes).

File

Size Path Contents
Size
32-bit unsigned integer. Size of the file in bytes.
Path
String. Path and name of the file, relative to the root of the game’s installation directory.
Contents
Uncompressed contents of the file, of the size determined by the Size field. Extracting only involves copying those bytes without any additional work.

Packaged Activity

Route display name Route ID Route ID 4 bytes File count File 1 File 2 ...
Route display name
String. Display name of the route that this activity applies to. This value is not necessary to perform any extraction.
Route ID
String, repeated twice. Should match the name of the folder that contains the route that this activity applies to, under the ROUTES folder in the game’s installation directory. For example, USA1 for the Northeast Corridor. This value must not be concatenated to the file paths and is not necessary to perform any extraction.
4 bytes
Four unknown bytes. They are not necessary to perform any extraction.
File count
32-bit unsigned integer. Number of files stored in this archive.

Implementation

I wrote a C# library based on Kaitai Struct and a command-line tool to replace the official TSUnpack tool and allow extracting packaged activities more reliably. It is available on Tildegit.

By default, the tool will extract activities to the game’s installation folder, using the Path value of the HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft Games\Train Simulator\1.0 registry key, just like how the original TSUnpack.exe does. If a file already exists, the extraction stops. Some options are available:

-d, --destination
Destination folder to extract to, instead of the game’s installation folder.
-f, --force
If a file already exists, overwrite it.