Wednesday 1st April, 2015
The hitch-hiker's guide to raildriver.dll, part 1: the plugin side. This blog post is the second of a small series of posts about train simulation. These posts are side-effects of some work I'm doing for Human Factors' Transport Simulation Laboratory at the University of Nottingham. Needless to say, all opinions and words in this series are my own: if you take issue with them, they're my fault entirely, not theirs. Contact me and don't bother them!

The RailDriver controller, which I talked about last time, uses a DLL to talk to the railway simulator game on the PC. This blog post will tell you how to call that DLL from your own software in order to control the train simulator game and to get information out of it. This will let you write simple plugins for games that support raildriver.dll. I'm using Train Simulator 2015.

If you're going to follow along at home, I've generated a C# file that contains bindings for the functions you need and the relevant contants, here.

raildriver.dll provides two communications channels, one from the plugin software to the simulator, and one from the simulator to the plugin software. These are accessed with the GetRailSimValue function, to get data from the simulator to the plugin, and SetRailSimValue, to send controls to the simulator. Do not be confused by the names of these functions! They do not access a single data structure: if you push something to the emulator using SetRailSimValue you will not be able to get it back using GetRailSimValue. Think of SetRailSimValue as "send information to simulator" and GetRailSimValue as "request information from simulator".

A plugin is just a standard executable that uses raildriver.dll. There's nothing magical about it at all. When your program loads, it should call SetRailDriverConnected(true). It can then use SetRailSimValue(id, value) to send a control to the simulator, and GetRailSimValue(id) to request information from the simulator.

This is best, perhaps, shown by examples. Let's start with getting information out of the simulator. This (binary) is a small speed recorder. Drop the executable into your RailWorks\plugins directory and run it, then drive a train around a bit. Every second, the current speed should be logged to the list box (most recent speed first). The speedometer is the only thing that I've reliably managed to get out of Train Simulator 2015.

Note that it calls SetRailDriverConnected(true) when the form is loaded. It then, in the timer, calls GetRailSimValue to get the current value of the speedometer.

Note that GetRailSimValue is a blocking call. It requests the value from the simulator and then waits. If it reaches the end of its wait period, then it bails out and returns 0. The timeout period is a little unpredictable, but is usually about a second.

(Gory details: GetRailSimValue calls Sleep(1) 100 times while waiting. How long this actually corresponds to may vary.)

Here's another example: this one (binary) controls the throttle. Every second, it increments the throttle by 10%. When it hits the top, it changes its mind and decreases the throttle by 10% until it hits the bottom. And so on. This is obviously a slightly contrived example. Again, put the executable in your plugins directory, run it, then start driving your train around.

Here, the timer is calling SetRailSimValue to change the throttle, with 1.0 being full scale and 0.0 being... zero. SetRailSimValue will not block no matter what you do to it, and you receive no notification whether or not the rail simulator has acted upon your information or not.

For writing a simple plugin there's not really a great deal more to it than that! The list of knobs you can fiddle with is in the RailDriver.RDId enum in RailDriver.cs.

posted by Rob Mitchelmore, 21:16 (anchor)