Bits and pieces about signals and AI

A collection of tutorials, guides and FAQ's.
Forum rules
Please only create new topics if you are posting a new guide, tutorial or FAQ.

Feel free to post in any existing topic asking questions, seeking clarification etc.

Bits and pieces about signals and AI

Postby AndiS » Fri Apr 11, 2014 3:21 pm

The following is a collection of links to stuff I posted over time, with some stealing from others. I put the more systematic stuff on top, and the bits and pieces below.

Messages sent by the system.
Influence factors on AI speed.
Two systematic write-up based on my experiments.

Nice scripting resource set up by Tankski

Mark's guide to the default signal, Part 1 - Semaphores and Part 2 - Light Signals. Both are indispensable to get started as they contain a complete reference of all the signals with their sometimes confusing names.

John's guide to British Signalling Practice to give you a first idea of the prototype. But don't ask too much about implementation of that using RW default signals, please.

If you want better UK semaphores here and now, get Mark's packs.
There are other signal sets using his scripts on UKTS:
China Clay for Export Route by Creative [post stating this]
IOW Network (contains items not in the signalling packs)
LNWR signals by Anthony Brailsford

Less widely known system calls (discovered by various people)

Searching for their names on UKTS gives you an overview of the current state of discovery in the not-so-clear cases.

General
secondsSinceMidnight = SysCall ("ScenarioManager:GetTimeOfDay")
Season = SysCall ("ScenarioManager:GetSeason") -- Spring = 0, summer = 1, autumn/fall = 2, winter = 3

Cab signalling
metresPerSecond = Call("GetCurrentSpeedLimit")
type, speed, distance = Call("GetNextSpeedLimit", direction, distance)
type, state, distance, aspect = Call("GetNextRestrictiveSignal", direction, distance)

I don't fully understand the distance parameter, most likely the upper limit for the distance returned.
See original post and erratum for full details.

For in-cab signalling to show nice results, route building must be flawless, too, and scripts must ensure that signals clear as far ahead as the cab displays them.

AI passes signals at red

  1. Be sure that the signal .bin has this line:
    Code: Select all
    <Stopping d:type="cDeltaString">eTrue</Stopping>
    If you find eFalse instead of eTrue, the AI just ignores it, like distants, stand-alone route indicators and shunting signals.
  2. Be sure that no numbered link is too far from the farthest switch, so a train may stop there. Some people love to push the numbered links of signals protecting a platform track beyond the platform. On motivation is that the speed limit in HUD matches German rules then. There might be other reasons, like covering a crossover at the far platform end.
    What happens in my opinion is this: The dispatcher monitors trains like the script, i.e., all the area between link 0 and the numbered links is lumped together in one "inner block". Now if switches change while there is "something" inside, the dispatcher can either block this junction forever or forget about whatever was inside. I guess he opts for the second choice to keep the game going, relying on other parts (like the scenario editor) to rule out conflicts. Now, your train stopping at the platform becomes invisible if it is still "inside the junction", and the next AI train will crash into it.
    This has also been observed for movements in opposite direction where the paths cross after stopping at the platform (inside the links of the signal for the opposite direction, which is cleared for AI during the stop).
  3. If you modified the route (or signals) or otherwise have the slightest motivation to do so, load the scenario in scenario editor and move the trains concerned by a metre or so. That will make the dispatcher reconsider everything, possible introducing more red Xs, instead of staging the crash.
  4. You have 100% of all switches passed by AI wrapped in signal links, in all directions used, don't you?
Optional further reading

AI stops at clear signals

  1. AI performs rule 39 everywhere which means that if the block beyond the next block is occupied and the next block is clear, it comes to a near halt and the resumes travel speed. Of course, this is only correct for UK semaphore home signals without a distant arm (slightly simplified). All you can do about it is setting the path for the tarrying AI train as far as possible. If two blocks are cleared, the AI train will still perform "half a rule 39 application", same for three, so the more blocks you can clear, the less time is lost. Of course it is hard to give a general advice how to set a clear route, you depend on the dispatcher setting the path well in advance, which he does most of the time.
  2. In very rare cases, someone put
    Code: Select all
    <Stopping d:type="cDeltaString">eFalse</Stopping>
    in the .bin file of a main signal. In that case, the block in rear does not appear to be cleared to AI as a train passes such faulty signal. The signal in rear of the faulty signal will still switch to clear, based on the script logic.

AI refuses to take a certain path (not related to signal)

Consider the track type (passenger only/freight only) and direction. Also electrification type. Remember that visuals are nothing. What counts is the service type set in scenario editor, the colourful bands shown in route editor when you press space repeatedly, and the electrification type specified in the engine's .bin file.
Optional further reading

Bits and pieces

What is the difference between the various UK disk shunting signals?

Signal properties

How to place signals correctly

When to start the signal placement

Using German Zs2 as a theatre box for UK signals

Information on German signalling in the prototype

Scripting a scenery item to show animated advertisement

Modifying signal plates

Vague stuff about signal arm animation

Edits:
April 13: Added references to Mark and John, and fixed some typos and tweaked the formatting.
April 15: Added reference to signals using Mark's scripts.
Last edited by AndiS on Tue Apr 15, 2014 7:21 pm, edited 4 times in total.
AndiS
Top Link Driver!
 
Posts: 736
Joined: Wed Apr 09, 2014 5:48 pm
Has thanked: 268 times
Been thanked: 308 times

Re: Bits and pieces about signals and AI

Postby Nobkins » Fri Apr 11, 2014 3:23 pm

Superb stuff thanks Andi.

Jim
TrainSimDev.com YouTube Channel
Video tutorials and other resources
User avatar
Nobkins
Site Admin
 
Posts: 547
Images: 3164
Joined: Wed Feb 05, 2014 12:24 am
Has thanked: 325 times
Been thanked: 185 times

Re: Bits and pieces about signals and AI

Postby AndiS » Sun Apr 13, 2014 12:32 am

I put the sequel here to help those who already digested the above. Later, I may merge it, if I find even more to say.

AI collisions
  • Most AI collisions are not real collisions but AI consists not coupled up properly. Two couplers overlap somewhere in the train just a bit and at departure time, the game physics kick in and immediately find that something has collided with this train - which is the other half of that train.
    To check against that, select the whole train (selecting the single bullet bottom-left in the editor), if all of it turns red as you click on one vehicle, you are fine. If half the train turns red, you found a culprit.
  • AI only sees consist that have a driver icon on one of the vehicles. This means that it happily ploughs through loose wagons. Just be sure to get them out of the way. Note: This might have been rectified with the introduction of AI coupling to vehicles in their initially position, but I would not rely on it. Just plan the path carefully.
  • If the path of an AI train contains switches or crossings which are not properly signalled (as in having link 0 in front of any switch group and a numbered link beyond it), there may be chance to lure another AT train into a colliding path, in particular if the paths don't converge but cross. If you want to route two AI trains into the same block, the dispatcher will complain. If you route them to a double slip at the same time, each going to a different branch, the dispatcher will not notice the problem if the signalling is not correct, e.g., if there is no signal at all. The trains will duly crash, but this is simply due to the lack of signalling.
  • Switches and crossings not showing guide rails are not properly formed and not seen as such by the dispatcher. They are another recipe for disaster.
  • I never observed an AI train run into a crawling AI train in front of it, but I did not spend too much time with them.
  • I did observe a crawling AI train hammer against buffer stops, but I cannot remember whether there was an error message.
  • While having a portal in the middle of a route as opposed to just the ends of branches seems to be safe for getting rid of trains, it obviously is a dubious idea to spawn trains from them. You may well do it, but be sure that no train in the whole scenario passes by that portal, or it will get some train spawned right into its neck if the timing is right - and Murphy says it will be right one day.

Signal will not clear - initially
  • Be sure that your train is not already on link 0.
  • If there are switches not wrapped in signal links between the initial position of the train and link 0 of the signal, the signal may not learn of the existence of the train. Ensure that the path is set for your train initially - it may or may not help. Better: get those switches signalled properly (you may sink the signal underground, any signal will do in your case). Or start the train nearer to the signal.
  • Some third party signals require you to draw up against the signal for them to clear. Check the documentation or try it out.

Signal will not clear - en route
  • If there is a switch not wrapped in signal links for your direction, the message of the signal at the end of the block telling the signal protecting the block that the block was cleared gets lost. At the missing signal in that case.

Signal will not clear - either situation
  • The route builder may not have planned the path chosen by the scenario author to be taken. To find out about it, note the path (blue line) in scenario editor and check - in route editor - whether the blocking signal has a numbered link in the track you are going to.
  • If you find that link, make sure it is beyond the convergence of the last switch, which is the meeting point of the curved track ribbon (yellow or red outline around the ballast texture) with the straight. What matters is the centre of the cube from which the arrow extends, but in practice, you want to see the whole cube beyond the track joint just to be sure.
  • Is there an AI train crossing the path of your train later? The dispatcher may hog the crossing long in advance. If there are switches involved, you may fly there and look at the blades. For diamonds, you can only take the AI train out of the schedule for testing. Diamonds are handled like slips or turntables - if the path is set for one train, the other signal for the other train will "see a trailing switch set against it" Thus it will not clear.
  • Don't expect signals you place in route editor to work before you safe and reload the route. They do lots of stuff on route loading and while they may look fair enough after placement, they just don't operate normally.
  • Almost no signal will clear unless a train (that is a consist with driver icon) is near them. Near means that nothing but plain track lies between them. Distance does not matter.

The case of the default CLS
I single that out as it is convoluted enough on its own. Default signal scripts seem to work like this:

  • Colour light signals send SIGNAL_PREPARED_VISIBLE to the signal in advance as the train head reaches link 0 if they have only one link. If they have more, they send SIGNAL_PREPARED instead.
  • On receipt of SIGNAL_PREPARED, the 3 aspect signal in advance does nothing if the path is set for links greater 1. 4-aspect signals ought to change to yellow in this situation(*). 2-aspect signals clear.
  • On receipt of SIGNAL_PREPARED_VISIBLE, signals clear without further ado (if the block ahead is clear and the route is set).
  • AWS ramps convert SIGNAL_PREPARED_VISIBLE messages to SIGNAL_PREPARED.
  • Only after the train end clears the AWS ramp the latter sends SIGNAL_PREPARED_VISIBLE to the signal in advance. Depending on train length and braking distance, this may appear late or too late.

(*) In a practical test, the 4 aspect signal stayed at red for link 1 and switched to green for link 2 when the train passed the signal in approach to it. I cannot explain that.

Interestingly enough, there is more than one bug. I placed an engine in advance to a 1T signal followed by a 2T signal protecting a facing switch. The first cleared, the second not, which was the subject of examination. However, when I changed the switch from straight to diverting, the first signal, next to the engine, changed to red. Very interesting. It has to do with SIGNAL_QUERY_PREPAREDNESS messages I never cared to understand.

The conclusion seems to be that you need AWS ramps beyond CLS with more than one link and you need to ensure that their track link is quite near the signal in approach, which is necessary for the timing of the AWS indicator in the cab anyway. And you just need a decent distance between those signals relative to train length and travel speed. However, I would not claim to fully understand the code. I just explored it because there are numerous complaints about signals clearing late if ever and AWS are considered suspicious. But I don't feel like I got to the bottom of this, and I'd rather return to my own projects.
AndiS
Top Link Driver!
 
Posts: 736
Joined: Wed Apr 09, 2014 5:48 pm
Has thanked: 268 times
Been thanked: 308 times

Re: Bits and pieces about signals and AI

Postby Nobkins » Sun Apr 13, 2014 9:15 am

A real gold mine of info in their. Thanks Andi.
TrainSimDev.com YouTube Channel
Video tutorials and other resources
User avatar
Nobkins
Site Admin
 
Posts: 547
Images: 3164
Joined: Wed Feb 05, 2014 12:24 am
Has thanked: 325 times
Been thanked: 185 times

Ideas for scenario-specific signal objects

Postby AndiS » Tue Apr 15, 2014 11:58 am

Now that Pete showed me the light called scenario-specific signal objects, I cannot hold back the top half of the ideas floating around in me for years.

The basic idea is this: The scenario author places bespoke objects next the track, and the track link(s) on the track, just like signals. These objects talk to signals and modify their behaviour. Or they do other nice things. Since these objects are specific to a certain scenario, they can give signals information about what is going on that they dearly miss otherwise.

Unless otherwise noted, the blueprint setup is as follows.
  1. In some 3D editor, create a small quad that is a metre underground. I.e., the quad is 1 metre below the object of the origin. Export to IGS.
  2. Create a simple object that somehow represents the functionality. E.g., a double-sided quad with something written on. E.g., on a return point marker, you could put "return" or put some U-shaped arrow. But the quad on a post if you like. I make these things 1 m wide so they look ok in the six-foot. They will only be seen in the editor, so visuals are not critical, but they should help the authors remember what they did there. Export to IGS.
  3. In Blueprint Editor, create an Editor shape blueprint. That is scenery only seen in the world editor, like scenario markers, but without a built-in function, of course. The IGS is the second of the both above. Keep Category at Uncategorised. Export and save.
  4. Then create a Signal blueprint with the first IGS above. Set Category to Track Infrastructure. Set Valid in scenarios (just below) to True.
    Unless specified otherwise below, the number of track links is one and Stopping is false. Script is one of those given below.
    Make the blueprint created above a child of this blueprint. This results in a quad 1 m below ground shown all the time and the descriptive object shown in world and scenario editors only. Export and save.

Things you can use right now

Please consider the code below beta. I can't test it now in the version presented here, but it is all proven stuff from various unfinished works of mine.

Suppress initial clearing of signal

You start a train at a platform that has a starter at both ends and you hate to see them both clear.
Place this object between the train and the starter that should stay at red, track link pointing to signal.

1 track link, Stopping=false. Script:
Code: Select all
--------------------------------------------------------------------------------------
-- Do nothing but suppress INITIALISE_TO_PREPARED
--------------------------------------------------------------------------------------

function Initialise ()
end

function OnConsistPass ( prevFrontDist, prevBackDist, frontDist, backDist, linkIndex )
end

function OnSignalMessage( message, parameter, direction, linkIndex )

   -- Forward each message, except INITIALISE_TO_PREPARED
   if ( parameter ~= "DoNotForward" and message == INITIALISE_TO_PREPARED ) then
      
      Call( "SendSignalMessage", message, parameter, -direction, 1, linkIndex )
      
   end
end

INITIALISE_TO_PREPARED   = 3

function GetSignalState( )
   return Call( "GetNextSignalState", "", 1, 1, 0 )
end


Returning point

Your train is returning from an intermediate stations and you hate to the starter clear for travelling further on.
Place this object where the train comes to a halt, track link pointing into original direction of travel before returning.

1 track link, Stopping=false. Script:
Code: Select all
--------------------------------------------------------------------------------------
-- Suppress preparation messages. When train stops, send SIGNAL_PREPARED_VISIBLE backwards.
-- Does nothing for trains starting on it and for trains in the opposite direction.
--------------------------------------------------------------------------------------

function Initialise ()
end

function OnConsistPass ( prevFrontDist, prevBackDist, frontDist, backDist, linkIndex )
   -- Train is on link
   if frontDist < 0 and backDist > 0 then
      -- We haven't done anything yet for this train and it is approaching from the right side
      if interestingTrain then
         local speed = Call("GetConsistSpeed")
         -- Define standing as 0 m/s plus a bit of random quivering seen in standing consists
         if speed < 0.05 then
            -- we are done with that one
            interestingTrain = false
            -- send preparation message back to signal for other direction, parameter 1 could be tuned to receiving signal
            Call( "SendSignalMessage", SIGNAL_PREPARED_VISIBLE, "1", -1, -1, linkIndex )
         end
      end
   -- Train is not on link, but is approaching from the "normal" side
   elseif frontDist > 0 and backDist > frontDist then
      interestingTrain = false
   end
end

function OnSignalMessage( message, parameter, direction, linkIndex )

   -- Forward each message, except all the preparation messages
   if ( parameter ~= "DoNotForward"
         and message ~= SIGNAL_UNPREPARED
         and message ~= SIGNAL_PREPARED
         and message ~= SIGNAL_PREPARED_VISIBLE
         and message ~= SIGNAL_TYPE_CONTROL_APPROACH_RED
         and message ~= SIGNAL_TYPE_CONTROL_APPROACH_FLASHING_YELLOW
         and message ~= PASS_OFFSET + SIGNAL_UNPREPARED
         and message ~= PASS_OFFSET + SIGNAL_PREPARED
         and message ~= PASS_OFFSET + SIGNAL_PREPARED_VISIBLE
         and message ~= PASS_OFFSET + SIGNAL_TYPE_CONTROL_APPROACH_RED
         and message ~= PASS_OFFSET + SIGNAL_TYPE_CONTROL_APPROACH_FLASHING_YELLOW ) then
      
      Call( "SendSignalMessage", message, parameter, -direction, 1, linkIndex )
      
   end
end

function GetSignalState( )
   return Call( "GetNextSignalState", "", 1, 1, 0 )
end


AI-only signal

You got an unsignalled yard and you want more than one AI move about it it, or you want to stop the dispatcher from changing switches under the train.
Signal it using these signals - as far as required in your scenario.

Stopping = true! Track links to taste (3 track links for a diversion into two branches).
The following script does absolutely nothing. But the dispatcher will see signals and benefit from your link placement.
Code: Select all
--------------------------------------------------------------------------------------
-- Do nothing, but don't block the message passing.
--------------------------------------------------------------------------------------

function Initialise ()
end

function OnConsistPass ( prevFrontDist, prevBackDist, frontDist, backDist, linkIndex )
end

function OnSignalMessage( message, parameter, direction, linkIndex )

   -- Forward each message
   if ( parameter ~= "DoNotForward" ) then
      
      Call( "SendSignalMessage", message, parameter, -direction, 1, linkIndex )
      
   end
end

function GetSignalState( )
   return Call( "GetNextSignalState", "", 1, 1, 0 )
end


Further uses of the single link version of this signal:
  • Defy undue rule 39 applications. AI loves to loose time at signals when the second or third block ahead is occupied. But 1 to 3 of these dummy signals at each signal where this disturbs your plans and the dispatcher will see the same number of additional clear blocks.
    Put these signals on the approach side of link 0(i.e., "before" the signal). Put them close to each other - when the real signal shows red, the AI will stop at each of these dummy signals, inching along mysteriously. You only notice this if there is enough distance between these stops.
  • Get two trains into the same block. You can add block separations using this signal. This can lead to permissive block working with AI, but beware that AI may stop in the middle of the block at the invisible signal if the second half is occupied. Slowing down at each invisible signal should not be as much of a problem since you run slow anyway. Just the opposite - better distribute invisible signals evenly as AI will speed between them as if under normal block working.
    Don't say I lured you into coupling to an AI train or stuff like that. Last time I tried, I got very exciting visuals, but nothing satisfying.
  • Depending on how you set things up, you may use one such signal in approach to a "broken down consist" which you are going to rescue.

Random delays in signal clearing

For the player train, where you don't see the AI ahead anyway, it can increase the continued value of a scenario to clear some signals at different delays. Of course, you would no do it for all signals and you would devise maximum delays. But getting a yellow here and there that they did not get last time they ran the scenario is something many people dream of.

Implementing that with the default signal is a bit tricky because of the design of their scripts. You must remember the issue with AWS and late clearing anyway. So I would not be too bold in proposing much, but basically, you would start a timer for a random duration when you receive a preparation message and forward it only after the timer completed. Timers are simply implemented by adding up parameter time in function Update.

You could also delay OCCUPATION_DECREMENT from the signal in advance. This has the advantage that you can place the delaying signal objects beyond the signal that is delayed, which is on the open route for starter signal. It is much more realistic for those to be delayed, but a late arrival of the preceding train in the distant station ahead. On game start-up, this object would send OCCUPATION_INCREMENT back, simulating block occupation without the need of a preceding train.

The important bit for me is to keep these objects out of the loop of AWS and the like so my invention does not get associated with the working or not-working of these things. So a stretch of plain track is the best place for them.


Helpers for improved signals

The following objects only make sense together with signals that make use of their assistence. While you will say that many of these objects should be placed permanently as needed - and this is true - permanent signals have a fixed value in the Identity field and you need to put scenario-specific content there. So you will find yourself placing some of these objects at the same place in several scenarios, but with a different ID causing different signalling sequences.

Switching between shunting and running movements

For starters with subsidiary signals, it is impossible to decide what to show because the path ahead is used for both departing and running around the train or doing some other shunting move. This is more common on the continent, but still an issue in UK.

You could place an object next the starter that tells it what to show when. Specific parameters could be written into the Identity field in the signal properties - invisible signals don't need a signal plate anyway. E.g., 201 would mean that the first train does two forward shunting movements before departing, the second none, the third one.

A more advanced version of this object would not only tell the signal ahead, but also the signal for the opposite direction ahead what will happen. This would reduce the number of helper objects a scenario author needs to place. In the ID, you would (instead of the digits in the previous paragraph), specify for each time a preparation message occurs, where this will be a) a running movement, b) a shunting movement not returning, c) a reversing shunting movement over the switches ahead, d) a reversing movement over the switches in rear, not bothering the signals in advance at all.

Foretelling AI movements

AI trains waiting at junctions start moving when the switches start to change over. This is 2 seconds before the signal has a chance to know the new path. Placing a prompting object next to them can tell the signal which path the AI will take in this single case, so the signal can display the aspect for the path that will be set in a few seconds, just in time before AI starts to move.

Wrong line working

To implement the UK style of setting the semaphore at the right track for a train on the wrong track, you need a two-link object. Link 0 in the wrong track, link 1 in the right track, in approach to each signal. When link 0 receives train preparation messages, they are forwarded at link 1, causing the main signal to clear. As the train passes, a preparation message is sent from link 0 and SIGNAL_UNPREPARED is sent from link 1 causing the main signal to reset.

However, this does not work for junction signals. Those will refuse to clear while the path is not set for them (and it will not be set, certainly not where the train changes back from the wrong to the right track). So you need a new message "force clear" which is sent from link 1 of this signal object and modified main signals obeying to this message, even if the path is not set for them.

Influencing signal reset timing

Sometimes you want a certain semaphore to reset later. Place a "reset here" object somewhere. It will tell the real signal to wait with reset and later send a message "reset now", when the train reaches it. (You are right in saying that this would not be placed scenario-specific.)

Foretelling train type

In many signalling schemes, CLS show a specific aspect when a train with cab signalling should ignore them. The signal must know this, of course, and there is no way to send a message from the train to the signal ahead.
A signal object doing nothing but reading this information from its Identity field and forwarding it to the next signal could help here. E.g., an ID of 0110 would mean that the first train does not have cab signalling, the next two does, the fourth does not.

Failed signals

Put a signal object in front of the signal telling it that it failed. As above, you could switch this behaviour for a series of trains based on 0 and 1 in the ID field.

Selecting the starter

In modern installations e.g. in Germany, there are two starters at the platform. The first is spaced from the fouling point by the complete overlap (100 to 250 m), so a train can reach it without blocking the station exit. The second is at the far end of the platform track, utilising the full length of that track but its overlap blocks neighbouring exit paths while a train arrives there. Again, a simple object can foretell the situation.


Other fun

Shunting guard

Ok, Pete tells me that animating custom figures is not possible currently (at least not with Blender), so think of an animated 2D puppet for the following.

You place a guard besides the rake of wagons you are going to couple to. This guard has a track link pointing towards the wagons, placed precisely at the coupling. It monitors the speed of the consists around him. OnConsistPass gets called for anything that moves. He discards what moves away or not at all. So he will pick out your consist as you propel it into that track, having no clue when to stop, as is prototypical. He computes the deceleration you need to stop there:

deceleration = square(speed) / 2 / distance

distance is parameter frontDist, speed is result of GetConsistSpeed, deceleration is in m/s2.

In a simple implementation, the guard shows "stop" (doing some waving animation) when the require deceleration exceeds some threshold like 0.5. Otherwise he shows "approach slowly". If the required deceleration is below some other threshold, or if your consist is too far away, he does nothing, meaning that you should maintain your speed (or even accelerate if you braked to hard or too early).

In a more sophisticated implementation, he can force you into a two-step approach where you take the last metres at 1 m/s (the speed of walking) depending on what the regulations prescribe.

You can make the guard a child object of the signal blueprint (called Guard). Then you can do the following using
Code: Select all
Call("Guard:setNearPosition", x, y, z)

  • Make the guard slide along the track to align with the place of uncoupling. I don't think he can sense the standing wagons but he can sense the leaving consist and he gets characterist sequence of OCCUPATION_DECREMENT followed by one or two OCCUPATION_INCREMENT, depending on where the track link is. So he can get there to direct you when you return to recouple, after setting off some wagons somewhere.
  • Make the guard jump between parallel sidings depending on which you approach. He needs a track link in each to get the preparation message when you set the path to a new track. However, he does not sense the initially placed wagons there and the links must be aligned precisely since he is positioned relativ to the original location near link 0, so this will not get too far.
  • Make him disappear by moving him underground, and make his twin appear in the neighbouring track as you get there. Disappearing when the shunting consist is 500 m away or SIGNAL_UNPREPARED is received (because switches are set for another track) should be a safe strategy. For small yards, you might change him to a hanging-around pose though.

Of course, it would be even more fun to have a shunter ride on the front wagon of the propelled consist directing you depending on the messages he receives from the first guard. That waggon would need to be a driving trailer (i.e. unpowered but with engine blueprint). However, I don't think those receive messages if they are not the active cab. But it's not my domain of expertise.

Custom loading/unloading animations

You could have a mobile crane approach your wagon precisely as it stops near the track link of the crane. Of course, much of that can be done by loading points, assuming you can place them in scenario editor (after modifying ValidInScenarios). I am not sure about the sophistication of the animations possible there. In signals, you have complete control to do the following.

  • Load or unload a single block of stone, or a box, using a crane that first lifts it, then rotates around its centre, then lowers it. Ok, to make the block disappear from the wagon, it must be an unloading point. And you need matching blocks on wagons, thus not so easy.
  • Have cattle march into the van. Ok, the problem of not having bone-based animation strikes again.
  • Wheel stuff in and out a van. Ok, same animation problem.
At least on the continent, the vans of passenger trains carried mail and smaller parcels, at least until the 80ies or whenever they started rationalising=closing everything. So it was a normal sight that as the train stops at the station, someone waiting there with a cart, maybe in the middle of the platform, would scurry to the van's door to hand over something and get some other things handed down. Of course, seeing the current state of passengers, this sounds a bit over-ambitious, but it is pretty scenic nonetheless.

Edits:
1) Added a paragraph in the shunting helper object.
2) Added section Random delays in signal clearing
Last edited by AndiS on Tue Apr 15, 2014 6:11 pm, edited 2 times in total.
AndiS
Top Link Driver!
 
Posts: 736
Joined: Wed Apr 09, 2014 5:48 pm
Has thanked: 268 times
Been thanked: 308 times

Re: Bits and pieces about signals and AI

Postby JamesLit » Tue Apr 15, 2014 12:39 pm

I'm thinking of delving into making my own signals or modifying some existing ones for personal use on my favourite route, for which this info will be absolutely invaluable, Andi, so thank you very much.

I'm wondering: let's say a run-round is taking place in a station. For the locomotive to get onto the back (now front) of the train, it needs to leave the station and stop on the inbound side of a signal gantry which protects access to that station. Because the loco gets there from the side it protects and then stops, rather than approaching it from the inbound side, the signal will not update and show clear when the loco stops and the points are changed, because it can't see the engine is there as it's stopped and hasn't moved towards the signal because it's not come from the inbound direction. Is there a way to make signals see stopped trains in front of them and update to show clear if possible?
The Forge Simulation | Like us on Facebook!
Owner & Director | Content built with care, not compromises.
User avatar
JamesLit
Driver
 
Posts: 370
Images: 26
Joined: Mon Apr 07, 2014 3:26 pm
Location: Kent
Has thanked: 433 times
Been thanked: 141 times

Re: Bits and pieces about signals and AI

Postby malkymackay » Tue Apr 15, 2014 4:32 pm

I like the sound of being able to have permissive working for AI. Could be useful for several scenarios I have in mind. :)
User avatar
malkymackay
Full Time Fireman
 
Posts: 87
Images: 58
Joined: Thu Apr 10, 2014 9:19 am
Location: Kilsyth, Scotland
Has thanked: 36 times
Been thanked: 127 times

Re: Bits and pieces about signals and AI

Postby AndiS » Tue Apr 15, 2014 5:23 pm

Signals do see the traffic in the opposite direction. And ironically, the default signals all clear as a train passes them in the opposite (i.e., "wrong") direction, just in case it might return, and this looks pretty stupid 99% of the time. I forgot to mention that having the returning point object I described above allows you to do away with this behaviour.

What happens when you run around your train?

I first present how the signals work in principle and then describe what they look like in the UK. So don't be put off if you think your loop will not be signalled that way.

Building up a sketch of the track layout and all the signal links as you read along is a good repetition of the signalling guides that float around.

Suppose you run your train from A to B which is just a loop on a single line (for our purpose). Instead of proceeding to C, your engine runs around and the train goes back to A.

  • As you enter the station, you pass 'home from A' before you pass the diverging switch of the loop. This signal has link 1 (say) in the platform track where you stop. As your train clears it (it is well before the platform), this signal 'home from A' sends a message (called OCCUPATION_DECREMENT, in case you care) back to A to tell that the block is clear and they could send another train from there. Of course, we hope that none is scheduled right now.
    Signal 'home from A' also sends a message forward to tell the next signal, which is 'starter 1 to C' to clear. Not knowing what goes on, it will show the standard green aspect.
  • You also pass 'starter 1 to A' protecting the switch against movements towards A.
    As you pass link 1 of that signal, which is near the post of 'home from A', it sends message OCCUPATION_INCREMENT to 'home from C' to prevent that one from clearing while you enter this track.
    As you pass link 0 (at the signal post) of 'starter 1 to A', as a default signal, it clears for you just in case you want to return right now, e.g., if your train had a driving trailer. You don't want this in general.
  • Now, you uncouple.
  • You pass 'starter 1 to C' showing proceed. You would have preferred to see aspect "shunt-on" there (details on that below). The default signal will announce your engine to C now, causing the home there to clear for you.
  • Near the post of this signal, you pass link 1 of 'home from C'. As you do so, this signal discounts the number of consists in the platform track by one. However, when you uncoupled, it got messages telling it that there are two consists in that track after the uncoupling: the engine and the rake of coaches.
  • Beyond the converging switch, you pass link 0 of 'home from C', located near the signal post. As it senses you pass, it wants to clear from you right away, like all default signals. But the track ahead is occupied - the coaches are still there.
  • After the switch runs around to route you to the loop track besides the platform track, the path is clear from 'home from C'. You would like to see a shunting aspect there, too, because your light engine is not going to A alone.
  • As you pass 'home from C', it announces you to 'starter 2 to A' at the far end of the loop track, which again currently just shows green.
  • As you pass link 1 of 'starter 1 to C' (placed next 'home from C'), the default signal will cancel your arrival at C (just in case you worried about that).
  • At the C end of the loop track, you pass 'starter 2 to C' in the opposite direction, which does not matter here.
  • After you passed the converging switch on the A end of the loop, the switch runs around.
  • Now, you need to pass 'home from A' but it knows that the track is occupied by the coaches. Without a shunting aspect at this signal, you are truly shot.
  • When you couple up, the game sends more messages to the home signals telling them that the two consists at the platform track became one.
  • Now, all you need is a clear signal - this time for a running movement to A - from 'starter 1 to A'. The default signal will do that automatically. A better implementation would do that on receipt of a command from the invisible signal object placed in the platform track.

Signalling schemes for this:
  • The wasteful maximum installation for this layout would be 3-aspect CLS with subsidiary aspect (colour position light head attached to the post or placed at its foot). You will not find that in many places.
  • In semaphore times, both parallel tracks (called platform and loop here) would only see unidirectional traffic, having a ground signal (disc) as a starter for the wrong direction movements. There would be platforms on either side, of course.
  • With only one platform, the loop track could have ground signals as starters on both ends. That way, trains run over the straight branch of switches all the time except for the engine running around. But trains cannot meet at B then, the loop track not being used for running movements, i.e., block protected train movements.
  • Semaphores had a small arm below the normal one to show the "shunt on" aspect. They had been modelled in the past but were difficult to bring to life without scenario-specific hints.
  • In the days of old, there would be no shunting signals and subsidiary aspects. The signaller would just direct the whole operation by verbal instruction and a bit of waiving.

The important bit regarding RW is this: No matter what the signal shapes look like, you need to cover all your trackwork with two networks of signal links, one for each direction. These networks consist of nodes containing switches, where the train first passes link 0, then switches and then a numbered link. Between such nodes, only plain track is allowed, no switches.

Track that is always used in one direction still ought to be covered for both directions, at least near any place where bi-directional movements occur. Since every station qualifies as that, you arive at "cover everything" immediately.

Remember that both directions are independent (except for some of my tricky schemes). Thus no one suggests mirroring block signals by invisible counterparts. But you need to put some sort of signal at junctions to cover wrong direction movements should they ever occur. At least myself, I maintain this view. At the same time, I acknowledge that signal placement is a chore for a large route and it can be tiring to place all the links right in big junctions as it involves a lot of flying around.
AndiS
Top Link Driver!
 
Posts: 736
Joined: Wed Apr 09, 2014 5:48 pm
Has thanked: 268 times
Been thanked: 308 times

AI-only block signal revisited

Postby AndiS » Wed Apr 16, 2014 12:54 pm

Since this seems to be the most attractive bit of the above collection, let me revisit it. This is still nothing I upload anywhere, since I don't have the time to create the model right now. Just read through the warnings, you will find that you can handle them well for your own purposes.

I call this thing "SHO AI-only signal" where SHO stands for Signal Helper Object or Scenario Helper Object. You need some sort of prefix in the object list, and I hope no one else uses SHO.

The script

If you want zero fuss, save it as Assets\Kuju\RailSimulator\RailNetwork\Signals\UK Colour Light\_dummy.lua.
If you are a bit more responsible, save it somewhere else.
Code: Select all
--------------------------------------------------------------------------------------
-- Do nothing, but don't block the message passing.
-- AndiS, 16 April 2014
-- Place this in approach to a signal not double up the blocks as perceived by the AI
-- Space a few of these evenly on track under permissive block working
-- Place this anywhere you like to show a block separation to the dispatcher
-- Warning: shows up in the HUD, so it may confuse users
--------------------------------------------------------------------------------------

function Initialise ()
end

function OnConsistPass ( prevFrontDist, prevBackDist, frontDist, backDist, linkIndex )
end

function OnSignalMessage( message, parameter, direction, linkIndex )

   -- Forward each message
   if ( parameter ~= "DoNotForward" ) then
      
      Call( "SendSignalMessage", message, parameter, -direction, 1, linkIndex )
      
   end
end

function GetSignalState( )
   return Call( "GetNextSignalState", "", 1, 1, 0 )
end


The object's XML file

Store the following as "SHO AI only signal.xml" - or any name you like better.
Code: Select all
<?xml version="1.0" encoding="utf-8"?>
<cBlueprintLoader xmlns:d="http://www.kuju.com/TnT/2003/Delta" d:version="1.0">
   <Blueprint>
      <cSignalBlueprint>
         <Name d:type="cDeltaString">SHO AI only signal</Name>
         <BrowseInformation>
            <iBrowseableBlueprint-cBrowseInformation>
               <DisplayName>
                  <Localisation-cUserLocalisedString>
                     <English d:type="cDeltaString">SHO AI only signal</English>
                     <French d:type="cDeltaString">SHO AI only signal</French>
                     <Italian d:type="cDeltaString">SHO AI only signal</Italian>
                     <German d:type="cDeltaString">SHO AI only signal</German>
                     <Spanish d:type="cDeltaString">SHO AI only signal</Spanish>
                     <Dutch d:type="cDeltaString">SHO AI only signal</Dutch>
                     <Polish d:type="cDeltaString">SHO AI only signal</Polish>
                     <Russian d:type="cDeltaString">SHO AI only signal</Russian>
                     <Other/>
                     <Key d:type="cDeltaString"></Key>
                  </Localisation-cUserLocalisedString>
               </DisplayName>
               <Description>
                  <Localisation-cUserLocalisedString>
                     <English d:type="cDeltaString">Place this do create a block boundary for the AI.</English>
                     <French d:type="cDeltaString">Place this do create a block boundary for the AI.</French>
                     <Italian d:type="cDeltaString">Place this do create a block boundary for the AI.</Italian>
                     <German d:type="cDeltaString">Place this do create a block boundary for the AI.</German>
                     <Spanish d:type="cDeltaString">Place this do create a block boundary for the AI.</Spanish>
                     <Dutch d:type="cDeltaString">Place this do create a block boundary for the AI.</Dutch>
                     <Polish d:type="cDeltaString">Place this do create a block boundary for the AI.</Polish>
                     <Russian d:type="cDeltaString">Place this do create a block boundary for the AI.</Russian>
                     <Other/>
                     <Key d:type="cDeltaString"></Key>
                  </Localisation-cUserLocalisedString>
               </Description>
               <Category d:type="cDeltaString">eTrackInfrastructure</Category>
               <ValidInScenarios d:type="cDeltaString">eTrue</ValidInScenarios>
            </iBrowseableBlueprint-cBrowseInformation>
         </BrowseInformation>
         <_posori>
            <cPosOriBlueprint/>
         </_posori>
         <_object>
            <cSceneryRenderBlueprint>
               <PrimaryNamedTextureSet>
                  <iBlueprintLibrary-cAbsoluteBlueprintID>
                     <BlueprintSetID>
                        <iBlueprintLibrary-cBlueprintSetID>
                           <Provider d:type="cDeltaString"></Provider>
                           <Product d:type="cDeltaString"></Product>
                        </iBlueprintLibrary-cBlueprintSetID>
                     </BlueprintSetID>
                     <BlueprintID d:type="cDeltaString"></BlueprintID>
                  </iBlueprintLibrary-cAbsoluteBlueprintID>
               </PrimaryNamedTextureSet>
               <SecondaryNamedTextureSet>
                  <iBlueprintLibrary-cAbsoluteBlueprintID>
                     <BlueprintSetID>
                        <iBlueprintLibrary-cBlueprintSetID>
                           <Provider d:type="cDeltaString"></Provider>
                           <Product d:type="cDeltaString"></Product>
                        </iBlueprintLibrary-cBlueprintSetID>
                     </BlueprintSetID>
                     <BlueprintID d:type="cDeltaString"></BlueprintID>
                  </iBlueprintLibrary-cAbsoluteBlueprintID>
               </SecondaryNamedTextureSet>
               <GeometryID d:type="cDeltaString">Kuju\RailSimulator\Scenery\Clutter\[00]rusty_rails</GeometryID>
               <CollisionGeometryID d:type="cDeltaString"></CollisionGeometryID>
               <Pickable d:type="cDeltaString">eTrue</Pickable>
               <ShadowType d:type="cDeltaString">eShadowType_None</ShadowType>
               <ViewType d:type="cDeltaString">ExternalView</ViewType>
               <HeatHaze/>
               <TexText/>
               <ProjectedLightElement/>
               <Instancable d:type="bool">0</Instancable>
               <DetailLevelGenerationRange>
                  <cSceneryRenderBlueprint-sDetailLevelGenerationRange>
                     <HighestLevel_1isHighest d:type="sInt32">10</HighestLevel_1isHighest>
                     <LowestLevel_10isLowest d:type="sInt32">10</LowestLevel_10isLowest>
                  </cSceneryRenderBlueprint-sDetailLevelGenerationRange>
               </DetailLevelGenerationRange>
            </cSceneryRenderBlueprint>
         </_object>
         <_signal>
            <cSignalComponentBlueprint>
               <NumberOfTrackLinks d:type="sUInt32">1</NumberOfTrackLinks>
               <Stopping d:type="cDeltaString">eTrue</Stopping>
               <JunctionSignalType d:type="cDeltaString">eJunctionTypeNone</JunctionSignalType>
               <ControlMode d:type="cDeltaString">eControlModeAutomatic</ControlMode>
            </cSignalComponentBlueprint>
         </_signal>
         <_script>
            <cScriptComponentBlueprint>
               <Name d:type="cDeltaString">Kuju\RailSimulator\RailNetwork\Signals\UK Colour Light\_dummy</Name>
            </cScriptComponentBlueprint>
         </_script>
         <_container>
            <cEntityContainerBlueprint>
               <Children/>
            </cEntityContainerBlueprint>
         </_container>
      </cSignalBlueprint>
   </Blueprint>
</cBlueprintLoader>

Edit the script name and path, if you found a better place than Kuju\RailSimulator\RailNetwork\Signals\UK Colour Light\_dummy. Note that the .lua extension is omitted normally.
I linked the object to the rusty rails, hoping they are default content still for all and that they don't disturb much in practice. Change GeometryID as you see fit.
Save and serz it.

The usage

Warning 1: this shows up in the HUD as normal signal. I guess people will not be too much disturbed as long as it lies next link 0 of a real signal, the symbols in the HUD will just be superimposed.

Warning 2: Never place this directly after a normal signal. It will make the AI stop there instead at the signal which makes the signal look even more stupid. Place it in advance of the signal and you will be fine.

In scenario editor, select the signal icon. You will see few items in the list. SHO AI only signal is what we are talking about.

Use case 1: Permissive block working
Space instances of this every few hundred yards along the track. Players running there will be disturbed by the extra signals in the HUD, but AI will treat there. AI will come to a near halt at each of them as it approaches the train ahead, and stop at the last one behind the other train. Setting the line speed to a realistic value will keep AI from speeding between the stops.

Use case 2: Make AI see more blocks than the user sees
Place this object such that the track link points in the same direction as link 0 of a normal signal and make their cubes just touch. The idea is that you should be close, but you must be sure that the train passes the invisible helper object first and link 0 of the real signal afterwards.

If you place this a few metres from link 0 of the real signal, AI will first stop at the helper object, then move on to link 0 of the signal. It does so anyway, but if there is but a metre between them you don't notice it as much. The cube of the track link arcs is 1 m wide, so if the cubes touch, the AI will still inch forward 1 m.

You may use more than one of these objects, if you see the need. It depends on how allergic against useless slowdown of the AI you are.

If you want AI to really move up to this signal while something scaring it happens beyond the signal, you might need a dose of 4 helper objects. I never tried it and I would not be surprised if the required dose changes between annual software revisions. Certainly you must consider both directions. I.e., you need to double up the signal stopping the player from hitting the AI just as much as you double up the signal stopping the AI from hitting the player. However, much of this will be trial and error.

Use case 3: Make AI share unsignalled track
If you have a yard where you want two AI engines shunt about, things are much more deterministic. Any single signal suffices to separate two AI trains.

Duplicate SHO AI only signal.xml naming the copy SHO AI only signal 1T.xml. Change the names in the file accordingly. Increase the NumberOfTrackLinks to 2 for tha 1T variant. Repeat for as many links as you need.

Signal the relevant part of the yard according to the known rules. In theory, you could be sloppy because you don't care if messages between signals get lost. You don't need their aspects anyway. But in practice, little is known about AI behaviour on unsignalled parts of the route. It is known that the switches are not changed until 5 seconds after the numbered link is cleared. It is very likely that the dispatcher forgets trains inside the links (between link 0 and the numbered links) when he changes the switches, which should only occur for movements in the opposite direction, if it happens for AI at all.

There will be cases where you get away with a pair of single-link signal objects facing each other, splitting the track concerned in two. Then AI can do their stuff on either side of this barrier without endangering each other. It all depends on your scenario and the track layout.
AndiS
Top Link Driver!
 
Posts: 736
Joined: Wed Apr 09, 2014 5:48 pm
Has thanked: 268 times
Been thanked: 308 times

Re: Bits and pieces about signals and AI

Postby JamesLit » Wed Apr 16, 2014 1:35 pm

Thanks for all this Andi, your head is a factual goldmine! :D :P I shall have to dedicate a few evenings to having a play with some of this. I may well make my own signals for the fun of it. The modelling side of things is the easy bit (for once!) for me here, so... :)
The Forge Simulation | Like us on Facebook!
Owner & Director | Content built with care, not compromises.
User avatar
JamesLit
Driver
 
Posts: 370
Images: 26
Joined: Mon Apr 07, 2014 3:26 pm
Location: Kent
Has thanked: 433 times
Been thanked: 141 times

Next

Return to Tutorials, Guides, FAQ

Who is online

Users browsing this forum: No registered users and 4 guests