Thursday 2nd April, 2015
The hitch-hiker's guide to raildriver.dll, part 2: more functions for your plugins. There are three other functions that you as the plugin can call to extract information from the simulator. I'm not going to give full examples for these because they're fairly straightforward. I've updated RailDriver.cs in the previous post to include these functions.

GetRailSimConnected does exactly what it says on the tin. Note, however, that this relies on a flag that is stored in the DLL. It is quite possible for a railway simulator to go away and not unset this flag. Thus, don't use this as a way of predicting whether GetRailSimValue will block, or whether the rail simulator is actually there.

Here might be a good place to talk about something mildly contentious that I did in the demos in the previous posts. Note that they call SetRailDriverConnected(true) but they never clear that when they leave: they never call SetRailDriverConnected(false). The reason for this is that this, too, is implemented as a flag inside the DLL. If you have multiple programs talking to the DLL, and one of them calls SetRailDriverConnected(false), then the rail simulator is quite within its rights to stop talking to all of those programs.

In the general case, in fact, the DLL may not behave at all well if more than one plugin uses it at once. If you are just sending control traffic in using SetRailSimValue, then this is likely not to be a problem: later changes to any given control will override earlier ones, and the rail simulator will just pick up the latest. However, if you are calling GetRailSimValue, be careful! If two plugins call GetRailSimValue at the same time, and the rail simulator is being slow, then one of the requests will get lost. Caveat haxor.

Returning to the point:

GetRailSimLocoChanged returns true if the simulator has changed locomotive since the last time GetRailSimLocoChanged was called.

GetRailSimCombinedThrottleBrake returns true if the throttle and brake are combined in one lever on the locomotive currently being simulated, or false if they're not.

posted by Rob Mitchelmore, 18:54 (anchor)
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)
June 2015May 2015April 2015June 2014
January 2014November 2013October 2013July 2013
April 2013March 2013January 2013November 2012
older posts