Handy Key Presses for Track Laying

By chance, I discovered two handy and undocumented functions of the World Editor for laying track:

In both cases, you start track laying as usual, expanding the track ribbon. Before you click the left mouse button to really place the ribbon, you press either Shift or Ctrl and release them after you clicked.

Shift switches "camera follows track" on even if you have not select this option in the bottom left flyout. But if this function is selected in the flyout, Shift does nothing, i.e., it does not temporarily turn it off.

Ctrl toggles the "snap to track" function. I.e., if you press Ctrl and this function is not selected, then for this one track placement, the curve will snap to straights (which will turn pink in the process) to form a converging junction. If the function is selected and you hold shift, you will be able to draw a straight (showing yellow), deactivating the "snap to track" for this one section of ribbon.

Messages sent to signals on coupling

I just found out that the track occupation management of the game must have improved at some point in the past, without leaving any trace in any documentation.

On game start-up, “initialise to blocked” is sent once per consist, which means that a signal protecting 3 groups of wagons gets 3 messages.

When you couple up wagons, all the signals which protected that group and the train coupling to it first get an "occupation decrement" message from the system, faking their exit from the block. Then, all the signals protecting the joint train get an "occupation increment" message, faking their entry into the block from the far side.

Track links currently under one of the involved vehicles get the message with parameter "DoNotForward", which means that this message is just for that link, in contrast to the normal messages which need to be forwarded on remote links (numbered 1 and bigger).

These things put together mean that occupation management by the default scripts is far better than it seems by looking at scripts and documentation. Not only is the system aware of multiple groups of wagons on the same track initially, it also does the right thing in the advent of coupling and uncoupling by magically increasing and decreasing the consist count correctly.

The fact that also driverless consists send the "prepare for train" message is a little let-down as I see it currently, because it results in even more unnecessarily cleared signals.

Track Properties and AI

Part of the problems with the AI are related to track properties. The following is a collection of the hard and soft facts I collected over time.

Theory
The dispatcher has to find one solution of a complex search problem. The search space is constrained by the track properties set by the route author, the instructions of the scenario author, and the trains already placed. There are different possible cases.

On the one hand, a problem can be over-constraint. This means that there is no solution to it which fulfils all constraints. E.g., all routes are blocked. This is more likely to happen the more constraints you set forth, as a route builder or as a scenario author.

On the other hand, a problem can also be under-constraint. This means that there are so many possibilities that the memory or processing time is not sufficient to explore them all. AI typically uses rules of thumb, called heuristics, to cut a heap of those considerations. This generally leads to solutions which are less then perfect, but they are generated in short time while the perfect solution would take very long to find.

Nothing is known about the heuristics of the RW dispatcher. But it has been observed that he does not work too hard to find out when a blocking train will move on. Instead, he simplifies the situation for himself by assuming that the train will stay there and finds complex ways to shunt around it. While this could be a good cop out in hard cases, it is not desired in many cases where the heuristics claiming that the block will stay simply fails.

An important questions in evaluating heuristics are metrics for solution quality. Nothing has been revealed and nothing can be set by the user, and few people are aware of the issue at all. What makes a solution good, or unacceptable? This requires complex knowledge certainly not able to model in RW currently. E.g., a passenger train will not reverse into a parallel track even if it wins him 5 minute, because shunting trains with passengers in them may be prohibited, or because waiting for the station staff to perform the manoeuvre causes of loss of 5 minutes.

This means that even though everyone would wish for a clever automatic genius, arriving there is a tough challenge.

An important factor RW AI is the train density. For moderate density, i.e., about 2 clear blocks between succeeding trains, many weird solutions do not get on the table at all. But people want to see dense operation, with waiting for opposite movements and then, finding a solution gets hard and harder.

Of course, there should be an ideal golden path in the middle between over and under-constraining. There are two things to consider in this quest.
  • Optimising the trade-off between desired guidance and undesired limitation cause by each information bit attached to any piece of track.
  • Perfect communication between those who make the rules of usage and those who need to follow them.

Practice
  • Marking a track as passenger locks out freight trains.
  • Likewise, marking track as freight locks out passenger trains.
  • Of course, uni-directional track locks out traffic for the other direction.

Note that freight and passenger exclusively refers to the train type selected for the driver icon in scenario editor, and nothing else.

Unfortunately, these are all the hard facts that I really can establish.

Track type yard remains a miracle. While I had the impression that it is avoided, it is clearly not a stop block for any train type. In one case, a freight train preferred 15 mph yard track over 50 mph mainline, while the same train from the same location took the mainline to reach the same destination when classified as passenger train.

Also line speed versus route length is a soft factor. I saw AI crawl along a speed restriction zone when the mainline just beside was clear and unrestricted. But I also saw AI prefer the faster track. I guess that the AI does not consider acceleration and deceleration losses. A short limit of 10 mph does not impress it, but a long one by just a few mph less makes it reconsider the route.

Sometimes I feel the the number of switches to pass is a factor. I saw AI take the loop when the clear mainline had a few more switches to other sidings in it.

A note on the hard blocks mentioned above: A a short piece of such track is sufficient for the result. This means that there is no need for miles of it. Therefore, keep direction restrictions out of places where someone might want to shunt, which is easy for route track. At the same time, make the marks long enough to be clearly seen when flying along the route. And do document them.

AI speed
This is calculated by the following interesting formula:

Line speed * (100 + tolerance) / 100 * performance

Line speed is the speed set in the track rules or by marking the track and setting the speed for this stretch. The choice of primary or secondary speed limit is decided by the train type defined in the scenario editor.

Tolerance is pegged to 60%. It is not the MaxSpeedTolerance defined in the XML of the track rule, as I believed earlier. That figure only influences the sharpness of easements, but not the speed of I, as later tests showed.

Performance is the % figure defaulting to 75% which you set for each intermediate destination.

If you want to experiment, start a scenario without being bound to a train, press F3 and then click on an AI train at an interesting place. It will shut off the power, so you need to take a quick look at the F3 display to see the value from the speed will steadily decrease. You also see the current speed limit, which can be well below the actual speed.

Given the uncertainty described above, using exactly one track class everywhere sounds most advisable, if only to rule out another factor of uncertainty with regards to AI behaviour.

Signals and their interaction with the game

I has been said before that signals are route decorations. In the following, I wrap up their relation to trains, F3 display and map, based on recent tests confirming old knowledge.

Signals' awareness of trains
On game start-up, a message is sent to the next signal ahead of consist, to tell it “prepare for coming train”. Also, for each consist, a message is sent to the next signal on either end saying “initialise to blocked”, meaning “protect this train”.

Note that both messages may end up at signals which are not stopping signals. It is the responsibility of the scripter to pass them on to where they can be acted upon. (For example, distants and AWS ramps cannot protect anything on their own.)

Signals' awareness of editing
When you enter scenario editor (not just world editor), all signals receive message 0 - RESET_SIGNAL_STATE. After that, they receive the same messages as after game start-up. On exiting the scenario editor, the same thing happens again.

In contrast, on game start-up, function Initialise is called very early and the above messages are then received.

This means, that signal scripts should call Initialise when they receive the RESET_SIGNAL_STATE message. This was the case for KRS, but for RW, the call was commented out and I have not got around why. Maybe because it only cures half of the problem as explained in the next paragraph.

The bad new is that in route editing mode in world editor, you can move around signals and their links (and also add and remove some) and in this case, the signals are not reset. Therefore, even with careful programming, the signals cannot adapt to the new situation after this type of modification.

F3 and map
Signals explicitly set the colour to show in the map, choosing from red, yellow, green and invisible without any requirement to correlate this with the aspect shown by the 3D shape.

The F3 display shows the same colour. For invisible signals, it shows the colour of the next signal and on also the distance to that one. Only signals classified as stop signals in the blueprint are considered here.

The distance shown in F3 refers to link 0 while the position shown in the map is that of the signal shape.

Player trains and signals
Signals may send messages to trains within 100m of their links. Note that there is no need to synchronise them with an aspect shown. For example, the TPWS ramp does not show any aspect but sends nasty messages.

I am pretty certain that when the player hits TAB, the request goes to the dispatcher who decides whether he would run an AI train into the next block, and this determines acception or denial of passing the signal at red. For sure, the signals (currently) are not even informed about the whole action, let alone asked.

AIs awareness of signals and trains
AI organises the route in blocks delimited by the link 0s or the stop signals. It only sees engines with driver icons. If one of them is inside a block, no AI train will go there, even if that engine would be located well behind the final target of the AI train.

AI trains do not receive messages sent by signals. They are not bothered by anything else the signals do, either.

As a consequence, on a correctly signalled route, signals will protect wagons and unmanned engines against player trains, but AI will plough through.

On a balance, you will not be able to lure AI into an occupied track by call-on signals and the like. You need to insert an invisible block signal beyond the marker where you want the AI to go.

Interestingly enough, this is only for the direction of the AI train. If you put a train just behind the signal for the AI, up to which it goes, this other train could proceed to the destination place of the AI train without violating any signal. But AI does not care about such issues.

One thing it worries about is when another train is straddling a link of a junction signal which the AI has to pass. Then, the AI train slows down and as soon as it passed link 0 of that junction, it speeds up again. Move the other train off the link, but still not separated by any signal from where it could collide with the AI train, and the AI does not hesitate anymore.

The AI ignores the signals, what should I do?
Despite all the frustrating signals I made above, I must say that a big number of signals would actually work in practice, if they were the right versions in the right place, had their links set up correctly and if the game was reloaded after modifications of route or scenario.

So, if you find a signal still shows a stop aspect while the AI train passes it, and if this signal is meant to be a bog standard signal, no permissive stop or call-on or approach from red, check the following.

From link 0, follow the route of the train to the next stop signal.
  • If the signal has several links, then are all the switches between link 0 and the far link through which the train passed set? (*)
  • So you find switches or crossings, those should have been protected.
  • So you find a consist without a driver, add one or remove the consist. AI limitation, not signal issue.
  • So you find a stop signal for the same direction before any of the above, check the XML file of the “bad“ signal to see whether this is classified as stopping signal.
  • Did you see the signal work on other occasions (i.e., did you witness all aspects being displayed under plausible circumstances, in another location). If yes, I forgot something on this list. If not, it is time to look into the script. If you are lucky, the name of some light is wrong and the signal died while trying to switch it on or off. Otherwise, err, you are not so lucky.

(*) It is pretty like that the route is set for AI trains, but at least for player trains, automatic trailing switches set against them do not end the game, but certainly they do cause the signal protecting them to show stop. So maybe there are situations in which you can change some switch before an AI train without the dispatcher setting it back immediately (or locking it in the first place). I only did one experiments and there, the dispatcher always set it back whenever I set it for my train.

Note: Modified sentence on Prepare For Train (message is also sent for driverless consists).

See also this follow up.

Sending several values in one message

Until recently, I maintained that modulo nor string functions would work, although Dave told me otherwise. I just did not get around testing it. Now I did and I found that both the string and the integer method work. These are the details:

The string method
You fix the number of digits (or otherwise characters) that every part will occupy. To piece the parameter together, you use the string concatenation operator “..” (two dots). To decompose the parameter by the receiver, you use the substring method.

string.sub(text, first character, last character)

Characters are counted from one. Note that the last argument is the index of the last character to include, not the first one not included nor the length of the substring.

I always add 0 to such terms to make sure that Lua stores them as numbers, not strings. I believe that I had bad results one time from comparing strings containing digits with numbers.

The integer method
After determining the maximum value of each component, you multiply the parts. For simplicity, lets use 99 as a maximum value for A, B, and C. So the parameter is

A * 10000 + B * 100 + C

On the receiving side, you use the modulo operation together with integer division to separate the parts. The way I found to be working in this Lua implementation is this.

A = math.floor( parameter / 10000)
B = math.mod(math.floor( parameter / 100), 100)
C = math.mod(parameter, 100)

In plain text, B is gained by first stripping off the two digits on the right using math.floor and division (because the division alone yields a real number) and then stripping off the two digits on the left by using math.mod.

Comparison
The main limitation of the numeric method is that numbers are represented as 31-bit bases which means that the maximum number you can represent without getting rounding phenomena is 2,000,000,000. If you need more digits, you are better off with the string method.

I believe that the numeric calculations are faster than string operations, but this is just a believe.

I did not test the string formatting function. Instead, I add a number to the result from the numeric method which is just a bit bigger. That way, I can be sure about the string format, with very simple calculation steps. In the above example, I would add 1,000,000, giving 1AABBCC where AA etc are the digits for A etc, so you can always get them by doing

A = string.sub(parameter, 2, 3) + 0

Impact
For the communication from the signals to the engine, this is good news, of course. Now, we need a standardisation body to keep the formats of different contributions compatible.

For the inter-signal communication, I am not so sure of the gain of composite messages over a series of simple messages (with ready-to-use parameters). All I observe regarding timing and delays is that either you run LogMate and accept the occasional hanging, or you don't run it and there is no hanging or jerking.

In Search of a Straight Frog

In a switch, the curve can end before or after the frog (or V formed by the inner rails). If it ends before, the rails from which the frog is formed are both straight, which reduces manufacture effort, eases track maintenance, and increases the durability. But dragging out the curved part through the frog and beyond allows for smoother curves. Consequently, straight frogs are a popular choice for yards and inexpensive trackwork while curved frogs are preferred for loops regularly passed by trains.

Until today, I believed that RW simply does not render frogs in straight switches. Either the curved ribbon extends past the frog or you don't get one (and no guiderails either). Then, I saw it render straight frogs in crossovers.

After getting rid of the blocks in flangeways, I had some crossover renaissance. But creating regularly shaped trackwork using them proved very tiring.

Then, I dug into the track XML data to see what was so special with these crossovers.

Now, I know two options, both of which are not exactly attractive, but much more than I had this morning.

The task at hand is the construction of a rake of loops, 4.5 apart, connected to the mainline via 1:9 switches with a radius of 190 m. The curve of this switch is 21.0 m long (rounded to 0.1 m). The length of a 1:9 diagonal from one track centre to the next is 40.8 m for 4.5 m track distance.

Innovative usage of the crossover tool
  • Lay some 500 m of straight track for the mainline.
  • Create a crossover to the right (since the loops will be at the right). Radius 190, length of curve 21.0. To make sure this radius is used, you need a track rule specifying it.
  • Unfortunately, the crossover tool only works on parallel (or very near parallel) track. Therefore, we only get one loop of it. The technique to produce it does not scale to a higher number of tracks.
  • Therefore, delete the curve at the far end of the crossover. Extend the straight track by some long straight, for working purposes only.
  • Move this new straight to the left, by some 20 m, without rotating it. It will help to inspire the crossover tool end then be deleted.
  • Now, add 40.8 m straights to the diverging straight (in place of that straight that we just moved to the side). Their number is equal to the number of loop tracks.
  • Now, select the crossover tool, place the gizmo exactly at the small red triangle separating two of these 40.8 m sections and create a crossover to the temporary track on the left. Curve radius is 190 again, and length 21.0.
  • After you did this for all the tracks, you delete the temporary track (which now is fragmented into 40.8 m pieces, and the curves connecting to them, leaving nothing but a range of nice switches with parallel tracks of equal length.

Fine, now we only need the opposite and then connect the two. Then, you find out that this simply does not work. The parallel tracks we created are never as exact enough. The will be off by a small number of centimetres, but this is enough to keep RW from joining the track. What is worse is that RW refuses to make such minimal S curves to compensate the small deviations.

You may be able to drag up a 1:100 curve (I hardly managed to created "flatter" ones), but the curve with "snap to track" (where the found target turns pink) does not work at this angle. RW always creates straights, which then do not join, exactly because the are a little apart. I also tried splitting and welding the straights of such an extra-sharp X. Sometimes it works, sometimes not.

Of course, there is not problem with using the join tool to simply make the straights ahead jump that centimetre or three, no one will notice. But what about the other end?

For converging switches, the recommendation I follow is to have a diagonal track across the whole rake and insert curves using "snap to track". If you pick a trackrule that has a somewhat smaller minimum radius, with some practice and patience, you will end up with a row of converging switches in the range of 185 to 195 radius, to approximate 190. However, these switches are of the "usual" type, not rendered as such and marked by a big red rectangle.

So you revert to the crossover method for both ends.

A clever variant is to make sure the parallel lines from the second end cross those from the first one, then you only need to find the place where they perfectly overlap and insert a piece of straight track there, after you cut them back. Less nasty than parallel track, 3 cm apart.

Still, all this is just too much pain in my view.

Poking into the XML
The track layout consists of ribbons which again consist of segments. The difference between a correctly rendered switch with straight frog and on that is not is this: The diverging branch of the switch is formed by a single ribbon, having two segments, first an arc (curved part), and then a straight. The crossover tools creates them that way. In contrast, when you create a curve, followed by a straight, the editor creates two separate ribbons with one segment each (at least when you are near other track or a switch).

Apart from fixing the core game, the solution is this:
  • You locate the two ribbons in Tracks.xml (easier in RW thanks to showing part of the ribbon ID in the editor), and in the corresponding file in Track Tiles.
  • You cut the cCurveStraight bit from the straight ribbon in the Track Tiles file, delete the now empty hull, and insert the cut out bit after the end of the cCurveArc segment in the curved ribbon.
  • In Tracks.xml, you remove the definition of the straight ribbon, noting its length before; then the node which connects the straight ribbon with the curved one.
  • Then, you look for the remaining mention of the straight ribbon and replace it by the key of the curved ribbon.
  • Then, you add the length of the straight to that of the curve (still in Tracks.xml). Also replace the old length by the new one in the rest of the record, namely for the height and track properties (track rule) information.

Sounds like work, because it is. But at least it has some potential for automatising, which gluing nearly joint track together has not.

Clearing Blocked Flangeways

We all love the crossover tool for creating those lovely frogs where the diverging track is continued through the flangeway of the straight track, looking truly stupid. By chance, I found out that this has to do with the opposing switch. Therefore, decoupling the two switches of the crossover solves the problem.

This is how I do it:

Case 1 - with intermediate straight. In this case there is a single straight between the two curved ribbons of the switches. Select the split tool and click somewhere in the middle of this straight. If only one of the two buffer stops appears, don't panic. Select the weld tool and click on the grey cube that will appear where you split the track. Reload the route to see the result, overcoming the usual track rendering issue. You should see two perfect switches and no buffer stops or track gaps at all.

Case 2 - without intermediate straight. In this case the two curved ribbons directly connect. Using the split tool again, cut off a bit from one of the two ribbons. Be careful not to cut into the guiderails and don't make the bit ridiculously short. 1m is fine. Like above, the result will look like a mess. Just pick the weld tool, click on the one cube showing where you cut, once. Then reload the route and enjoy.

Even tough I applied this method often with success, I urge everyone to keep backups of the Networks folder outside the Steam folders. Keep a series of version, so when you find a problem, you have several steps to go back and retrieve a version where the problem has not yet appeared.

Route Building Do-s and Don't-s

My personal selection of Do-s and Don't-s in route building, all documented elsewhere, just to pass on recent experiences.

Do not create scenarios before track-laying is closed.
Who can resist to run a train on his nearly finished route? And who can resist some fine tuning later, tearing out something here and adding something there? Only problem: If you used something in a scenario, you should not tear it out or RW will issue the maximum penalty, "something bad happened, you will so see your route again".

If this happens -- or better, before -- move all scenarios to a safe place or better don't create them.

Clearly, there are compromises, just create free-roam ones with a starting place that will not change in the life of the route.

Do not believe what you see after deleting track
In particular when you delete pieces of track that formed or might form a junction, RW sometimes, but not all times deletes one more than you selected. Do not place a new piece to close the gap. Exit and reload the route and the missing piece will be back.

Do not expect signals or AI to work after you modified either anything scenario-related, or any signal. Just reload, it is the lesser of two wastes of time.

Do not remove parts of double or single slips.
I remembered that as a valid technology, to create a slip and then remove the crossing pieces, to obtain a regularly shaped curve. Don't do it. RW gets angry about the missing pieces of the slip and you sit debugging Tracks.xml.

Do make backups.
The most critical file in my view is Tracks.bin. Since the above mentioned crisis, I do a simple Ctrl-C, Ctrl-V in the Networks folder of the route I edit, whenever I cycle to "play again" and back, which is what you need to do if you want to know if your route still loads.

Pressing the play button in the world editor does not to the checks that are done on loading. I.e., you can "test" your route, then edit some more, etc., and the next day you find out that a lot of work is lost.

If you click "play again" on the main menu, everything is initialised as if you would have started the game, if you can load your route now, you will be able to do so tomorrow.

Praise of the Scenery Viewer

Normally, when I call RW a scenery viewer, I am a naughty anorak lamenting about some feature missing or the prototype being poorly represented.

Today, I must say that this is the best living 3D postcard I ever saw. It should see a bright future in the treatment of aggressive or hyperactive persons.

Sorry if you hate these people who just upload lots of screenshots and then not even their own work, but today I am one of those. I will make up with a very technical article soon, but first you must see my postcard collection.












Who needs a cinema when mother nature plays a movie for him, in what they sell as a rail works? No noise, no dirt, just peace and fresh air.



No Sir, I did not smoke anything, I just inh...





Somehow, this farmer got stuck long ago. Or he got suddenly depressed from going up and down the fields all day. The tiller looks already rusty, but the point on the tractor is still good. Now he must wait for the spring to release his machinery from the ice.
Genetically modified sheep, certainly in danger of pig flu now.
Shut up and look at the winter woods.

The dark side of the --include statement, continued

Another nice feature of --include is that the blueprint editor is too stupid to understand dependencies. Normally, if A contains the line

--include=B

and you change B, then A is updated by any decent compiler. However, the blueprint editor only copies over B from the Source folder to the Asset folder and does not compile the file A again, although that contains a now outdated copy of B.

The only workaround is to save A anew even if you did not change it, every time you save B. Pretty boring if you have lots of 'A's, which is the normal situation.

In practice, I debug the file in the Asset folder until I am satisfied (or tired), and then copy it back to the source folder. However, this is risky (click the Export button in the blueprint editor once an your debugging work is lost). And if your project is made up of a set of files, splitting the merged file after debugging is another tedious working step.

The other disadvantage of editing the copy in the Asset folder is that syntax errors lead to program crashes (of KRS or RW). In contrast, if you make an error in the Source folder, the blueprint editor may tell you about it on exporting, if you are lucky.