For many years I have been working on several Swedish routes including Jönköpingsbanan (which despite its name includes Stockholm, including the central station and its surroundings - download link and Swedish forum thread), and refurbishing of the Kiruna-Narvik route by newS (download link and forum thread). Unfortuantely, since around a year, the Jönköpingsbanan route freezes the sim when the route is loading. I found out that disabling certain signal scripts will allow the route to load. Even then, the route frequently crashes when certain signal links are crossed by trains (mostly linked to level crossings). I have all but given up on being able to continue building on and enjoy my routes, as I don't see removing possibly hundreds of signal objects/links as an option. It would be a shame as it essentially throws away 10+ years of work. I would appreciate any help in finding out what the root cause is and if anything can be done. I can think of a few possible ways forward: Finding out what has changed in the handling of signal scripts since the last few sim updates. With this information it might be possible to find the "offending" scripts/signals and adjust them. Reverting to an older version of TS. Is this possible? Doing a complete overhaul of the Swedish signal scripts to ensure that they don't crash the sim. They are LUA scripts that have been around, although modified many times, since the first version or Railsimulator around 2008. I have done several modifications myself, through trial and error, to be able to change signal functionality, add links to support more tracks etc. Below I have included an example of an "offending" script. Ths script is for a stop light used at the end of sidings, but also as a kind of stop repeater signal displaying a stop aspect if the next main signal is at danger; otherwise the stop light is extinguished (pictures). With this script enabled, the route crashes on loading. If I disable this script (by moving or changing the name of the LUA file), the route loads (but crashes when trains cross certain links at level crossings). I'm not sure of course if the problem is with the script itself, or rather how it interacts with other signals. In any case, ideally no script should crash the sim even if signals are placed in a "forbidden" way, so any help as to how these scripts can be improved would be much appreciated. Code: -------------------------------------------------------------------------------------- -- KMW / Anders Eriksson -- 090108 First version -- 201006 Uppdaterad funktion för skyddsstopplykta -------------------------------------------------------------------------------------- --include=SE CommonScript.lua --include=Signal CommonScript.lua -------------------------------------------------------------------------------------- -- INITIALISE -- Signal specific initialise function function Initialise() -- Set our light node names LIGHT_NODE_RED = "R1" BaseInitialise() end -------------------------------------------------------------------------------------- -- ANIMATE -- Any animation that needs doing function Animate() -- use standard Animation DefaultAnimate() end -------------------------------------------------------------------------------------- -- SET LIGHTS -- Set lights according to new signal state function SetLights() -- use standard SetLights DefaultSetLights() end ------------------------------------------------------------------------------------- -- Swedish CommonScript to switch lights on/off -- KMW / Anders Eriksson -- 090108 First version. -------------------------------------------------------------------------------------- --include=Signal CommonScript.lua -------------------------------------------------------------------------------------- -- Animate Swedish distance signals -- switch on/off the appropriate lights function DefaultAnimate() if gHomeSignal and (gSignalState ~= STATE_GO) then return end if (gExpectState == STATE_GO) then SwitchLight( LIGHT_NODE_GREEN2, 0 ) SwitchLight( LIGHT_NODE_WHITE, gLightFlashOn ) SwitchLight( LIGHT_NODE_GREEN3, 0 ) elseif (gExpectState == STATE_SLOW) then SwitchLight( LIGHT_NODE_GREEN2, gLightFlashOn ) SwitchLight( LIGHT_NODE_WHITE, 0 ) SwitchLight( LIGHT_NODE_GREEN3, gLightFlashOn ) else -- stop or blocked SwitchLight( LIGHT_NODE_GREEN2, gLightFlashOn ) SwitchLight( LIGHT_NODE_WHITE, 0 ) SwitchLight( LIGHT_NODE_GREEN3, 0 ) end end -------------------------------------------------------------------------------------- -- Swedish home signals SetLights -- Switch the appropriate lights on and off based on our new state function DefaultSetLights() -- DebugPrint("DefaultSetLights()") if (gSignalState == STATE_GO) then SwitchLight( LIGHT_NODE_RED, 0 ) elseif (gSignalState == STATE_SLOW) then SwitchLight( LIGHT_NODE_RED, 0 ) else -- stop or blocked SwitchLight( LIGHT_NODE_RED, 1 ) end end -------------------------------------------------------------------------------------- -- Required signal functions -------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------- -- ON CONSIST PASS -- Called when a train passes one of the signal's links function OnConsistPass ( prevFrontDist, prevBackDist, frontDist, backDist, linkIndex ) BaseOnConsistPass ( prevFrontDist, prevBackDist, frontDist, backDist, linkIndex ) end -------------------------------------------------------------------------------------- -- ON SIGNAL MESSAGE -- Handles messages from other signals function OnSignalMessage( message, parameter, direction, linkIndex ) BaseOnSignalMessage( message, parameter, direction, linkIndex ) end -------------------------------------------------------------------------------------- -- UPDATE -- Handles moving things and flashing ligths function Update( time ) BaseUpdate( time ) end -------------------------------------------------------------------------------------- -- Signal CommonScript -- KMW / Anders Eriksson -- Based on KUJU / Rail Simulator Signal Scripts -- 090108 First version. -- 091220 Corrected distance signal and handling of crossings. -------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------- -- GLOBALS -- States STATE_GO = 0 STATE_SLOW = 1 STATE_STOP = 2 STATE_BLOCKED = 3 STATE2GO = 4 STATE2STOP = 5 STATE_UNDEFINED = 8 STATE_RESET = 9 -- How long to stay off/on in each flash cycle LIGHT_FLASH_SECS = 0.75 -- 40 flashs/min QUICK_FLASH_SECS = 0.375 -- 80 flashs/min -- Signal Messages (0-9 are reserved by code) RESET_SIGNAL_STATE = 0 INITIALISE_SIGNAL_TO_BLOCKED = 1 JUNCTION_STATE_CHANGE = 2 INITIALISE_TO_PREPARED = 3 -- Locally defined signal mesages SIGNAL_GO = 10 SIGNAL_SLOW = 11 SIGNAL_STOP = 12 SIGNAL_BLOCKED = 13 OCCUPATION_INCREMENT = 14 OCCUPATION_DECREMENT = 15 DISTANCE_INCREMENT = 16 DISTANCE_DECREMENT = 17 LAST_SIGNAL_MESSAGE = 17 -- Crossings CROSSING_GO = 20 CROSSING_INCREMENT = 21 CROSSING_STOP = 22 CROSSING_DECREMENT = 23 CROSSING2GO = 24 CROSSING2STOP = 25 CROSSING_GATE = 26 LAST_CROSSING_MESSAGE = 26 -- What you need to add to a signal message number to turn it into the equivalent PASS message PASS_OFFSET = 50 -- Pass on messages to handle overlapping links (eg for converging junctions / crossovers) -- Populated by BaseInitialise() PASS = { } -- SPAD and warning system messages to pass to consist AWS_MESSAGE = 11 TPWS_MESSAGE = 12 SPAD_MESSAGE = 14 -- Initialise global variables gGoingForward = true gInitialised = false -- has the route finished loading yet? gSignalState = STATE_RESET -- state of this block/signal gExpectState = STATE_RESET -- state of next block/signal gHomeSignal = true gDistanceSignal = false gBlockSignal = false -- is this an intermediate block signal? gConnectedLink = 0 -- which link is connected? -- State of flashing light gLightFlashOn = 0 gTimeSinceLastFlash = 0 -- debugging stuff --math.randomseed(os.time()) gDebugId = math.random(1, 100) function DebugPrint( message ) if gDebugId ~= nil then Print( "[" .. gDebugId .. "] " .. message ) end end -------------------------------------------------------------------------------------- -- BASE INITIALISE -- initialise function used by all signal scripts function BaseInitialise() DebugPrint("BaseInitialise()") gInitialised = false -- Initialise PASS constants for i = 0, PASS_OFFSET do PASS[i] = i + PASS_OFFSET end -- Initialise global variables gLinkCount = Call( "GetLinkCount" ) -- number of links this signal has gLinkState = {} -- state of line beyond this link gYardEntry = {} -- is this link going inside a yard? gDissabled = {} -- is this link dissabled? gOccupationTable = {} -- how many trains are in this part of our block? for link = 0, gLinkCount - 1 do gLinkState[link] = STATE_GO gYardEntry[link] = (link > 6) -- links without numbers (>6) are yard entry gDissabled[link] = false gOccupationTable[link] = 0 end Call("BeginUpdate") end -------------------------------------------------------------------------------------- -- ON CONSIST PASS -- Called when a train passes one of the signal's links function BaseOnConsistPass ( prevFrontDist, prevBackDist, frontDist, backDist, linkIndex ) -- in which direction is the consist going? gGoingForward = (prevFrontDist > frontDist) -- only handle consist pass on active home signal links if linkIndex >= 0 and not gDissabled[linkIndex] then if (frontDist > 0 and backDist < 0) or (frontDist < 0 and backDist > 0) then if (prevFrontDist < 0 and prevBackDist < 0) or (prevFrontDist > 0 and prevBackDist > 0) then DebugPrint("OnConsistPass: Crossing started... linkIndex = " .. linkIndex .. ", gConnectedLink = " .. gConnectedLink) if gGoingForward then if not gYardEntry[linkIndex] then gOccupationTable[linkIndex] = gOccupationTable[linkIndex] + 1 DebugPrint("OnConsistPass: Forward INCREMENT... gOccupationTable[linkIndex]: " .. gOccupationTable[linkIndex]) end elseif linkIndex == 0 then DebugPrint("OnConsistPass: A train starts passing link 0 in the opposite direction. Send OCCUPATION_INCREMENT.") if gHomeSignal then Call( "SendSignalMessage", OCCUPATION_INCREMENT, "", -1, 1, 0 ) end Call( "SendSignalMessage", DISTANCE_INCREMENT, "DoNotForward", -1, 1, 0 ) elseif (gConnectedLink == linkIndex) then gOccupationTable[0] = gOccupationTable[0] + 1 DebugPrint("OnConsistPass: Backward INCREMENT... gOccupationTable[0]: " .. gOccupationTable[0]) end SetSignalState() end else if (prevFrontDist < 0 and prevBackDist > 0) or (prevFrontDist > 0 and prevBackDist < 0) then DebugPrint("OnConsistPass: Crossing cleared... linkIndex = " .. linkIndex .. ", gConnectedLink = " .. gConnectedLink) if not gGoingForward then if not gYardEntry[linkIndex] and gOccupationTable[linkIndex] > 0 then gOccupationTable[linkIndex] = gOccupationTable[linkIndex] - 1 DebugPrint("OnConsistPass: Backward DECREMENT... gOccupationTable[" .. linkIndex .. "]: " .. gOccupationTable[linkIndex]) end elseif linkIndex == 0 then DebugPrint("OnConsistPass: A train finishes passing link 0 in the normal direction, send OCCUPATION_DECREMENT.") if gHomeSignal then Call( "SendSignalMessage", OCCUPATION_DECREMENT, "", -1, 1, 0 ) end Call( "SendSignalMessage", DISTANCE_DECREMENT, "DoNotForward", -1, 1, 0 ) elseif (gConnectedLink == linkIndex) and (gOccupationTable[0] > 0) then gOccupationTable[0] = gOccupationTable[0] - 1 DebugPrint("OnConsistPass: Forward DECREMENT... gOccupationTable[0]: " .. gOccupationTable[0]) end SetSignalState() end end end end -------------------------------------------------------------------------------------- -- ON SIGNAL MESSAGE -- Handles messages from other signals function BaseOnSignalMessage( message, parameter, direction, linkIndex ) DebugPrint("OnSignalMessage(" .. message .. ", " .. parameter .. ", " .. direction .. ", " .. linkIndex .. ")") -- This message is to reset the signals after a scenario / route is reset if (message == RESET_SIGNAL_STATE) then Initialise() return elseif not gInitialised then InitialiseSignal() end -- forward crossing messages if (message >= CROSSING_GO and LAST_CROSSING_MESSAGE >= message) or (message >= CROSSING_GO+PASS_OFFSET and LAST_CROSSING_MESSAGE+PASS_OFFSET >= message) then Call( "SendSignalMessage", message, parameter, -direction, 1, linkIndex ) return end -- Check for signal receiving a message it might need to forward, -- in case there are two overlapping signal blocks (eg for a converging junction or crossover) -- ignore messages that have the "DoNotForward" parameter if (parameter ~= "DoNotForward") then if gDissabled[linkIndex] or not gHomeSignal then -- just forward it on Call( "SendSignalMessage", message, parameter, -direction, 1, linkIndex ) elseif (linkIndex > 0) then -- We've received a PASS message, so forward it on if (message > PASS_OFFSET) then Call( "SendSignalMessage", message, parameter, -direction, 1, linkIndex ) message = message - PASS_OFFSET -- Any message other than JUNCTION_STATE_CHANGE should be forwarded as PASS messages elseif message ~= JUNCTION_STATE_CHANGE then Call( "SendSignalMessage", message + PASS_OFFSET, parameter, -direction, 1, linkIndex ) end end end -- messages arriving on a yard entry or dissabled link should be ignored if (gYardEntry[linkIndex] or gDissabled[linkIndex]) and (message < CROSSING_GO) then return -- Do nothing end -- BLOCK STATES if (message >= SIGNAL_GO) and (message <= SIGNAL_BLOCKED) then DebugPrint("Message: SIGNAL_STATE_CHANGE received ... gLinkState[" .. linkIndex .. "]:" .. message) if gBlockSignal and message == SIGNAL_STOP and parameter == "BLOCKED" then -- train coming our direction in an entry signal, block occupied gLinkState[0] = STATE_BLOCKED else gLinkState[linkIndex] = message - SIGNAL_GO end if (gConnectedLink >= 0) then gExpectState = gLinkState[gConnectedLink] else gExpectState = STATE_UNDEFINED end DebugPrint("Link " .. linkIndex .. " is now " .. gLinkState[linkIndex] .. ", expected state is " .. gExpectState) if gHomeSignal then SetSignalState() end -- INITIALISATION MESSAGES -- There's a train on the line ahead of us when the route first loads elseif (message == INITIALISE_SIGNAL_TO_BLOCKED) then gOccupationTable[linkIndex] = gOccupationTable[linkIndex] + 1 DebugPrint("Message: INITIALISE_SIGNAL_TO_BLOCKED received... gOccupationTable[" .. linkIndex .. "]: " .. gOccupationTable[linkIndex]) -- Only need to do this for block signals - anything spanning a junction will initialise later when junctions are set if (gBlockSignal and gOccupationTable[linkIndex] == 1) then SetSignalState() end elseif message == JUNCTION_STATE_CHANGE and gLinkCount > 1 then -- Only act on message if it arrived at link 0, junction_state parameter is "0", -- and this signal spans a junction (ie, not a block signal) if linkIndex == 0 and parameter == "0" then gConnectedLink = Call( "GetConnectedLink", "10", 1, 0 ) if gConnectedLink >= 0 then gExpectState = gLinkState[gConnectedLink] DebugPrint("Expected state: " .. gExpectState) else gExpectState = STATE_UNDEFINED DebugPrint("Expected state: undefined") end DebugPrint("Message: JUNCTION_STATE_CHANGE received ... activate link: " .. gConnectedLink) SetSignalState() -- Pass on message in case junction is protected by more than one signal -- NB: this message is passed on when received on link 0 instead of link 1+ -- When it reaches a link > 0 or a signal with only one link, it will be consumed Call( "SendSignalMessage", message, parameter, -direction, 1, linkIndex ) end -- OCCUPANCY elseif (message == OCCUPATION_DECREMENT and gHomeSignal or message == DISTANCE_DECREMENT and not gHomeSignal) then -- update the occupation table for this signal given the information that a train has just left this block and entered the next block if gOccupationTable[linkIndex] > 0 then gOccupationTable[linkIndex] = gOccupationTable[linkIndex] - 1 end gGoingForward = true gLinkState[linkIndex] = STATE_STOP -- train going opposite direction, block no longer occupied DebugPrint("Message: OCCUPATION_DECREMENT received... gOccupationTable[" .. linkIndex .. "]: " .. gOccupationTable[linkIndex]) -- If this is the connected link and last train leaving if linkIndex == gConnectedLink and gOccupationTable[linkIndex] == 0 then SetSignalState() end elseif (message == OCCUPATION_INCREMENT and gHomeSignal or message == DISTANCE_INCREMENT and not gHomeSignal) then -- update the occupation table for this signal given the information that a train has just entered this block gOccupationTable[linkIndex] = gOccupationTable[linkIndex] + 1 gGoingForward = false DebugPrint("Message: OCCUPATION_INCREMENT received... gOccupationTable[" .. linkIndex .. "]: " .. gOccupationTable[linkIndex]) -- If this is the connected link and first train entered the block, check the signal state if linkIndex == gConnectedLink and gOccupationTable[linkIndex] == 1 then SetSignalState() end end end -------------------------------------------------------------------------------------- -- UPDATE -- Handles moving things and flashing ligths function BaseUpdate( time ) --DebugPrint("Update(" .. time .. ")") if not gInitialised then InitialiseSignal() else gTimeSinceLastFlash = gTimeSinceLastFlash + time if gTimeSinceLastFlash >= LIGHT_FLASH_SECS then Animate() gLightFlashOn = 1 - gLightFlashOn gTimeSinceLastFlash = 0 end end end -------------------------------------------------------------------------------------- -- INITIALISE SIGNAL -- Called after route is set up and all links and junctions are known function InitialiseSignal() DebugPrint("InitialiseSignal()") -- Remember that we've been initialised gInitialised = true -- check for dissabled links (links placed before link 0) for link = gLinkCount - 1, 1, -1 do local connectedLink = Call( "GetConnectedLink", "10", 1, link ) DebugPrint("Link " .. link .. " connected to " .. connectedLink) if (connectedLink ~= -1) then gDissabled[link] = true gYardEntry[link] = true gLinkCount = gLinkCount - 1 end end if (gLinkCount == 1) then gBlockSignal = gHomeSignal gConnectedLink = 0 else gConnectedLink = Call( "GetConnectedLink", "10", 1, 0 ) end SetSignalState() if gBlockSignal then DebugPrint("BlockSignal[" .. gLinkCount .. "]") elseif gHomeSignal then DebugPrint("HomeSignal[" .. gLinkCount .. "]") end if gDistanceSignal then DebugPrint("DistanceSignal[" .. gLinkCount .. "]") else Call("EndUpdate") end end -------------------------------------------------------------------------------------- -- SET SIGNAL STATE -- Figures out what state to show and messages to send function SetSignalState() local newSignalState = STATE_GO if gBlockSignal then if gOccupationTable[0] > 0 and gGoingForward then newSignalState = STATE_STOP elseif gOccupationTable[0] > 0 or gLinkState[0] == STATE_BLOCKED then newSignalState = STATE_BLOCKED elseif gExpectState == STATE_STOP then newSignalState = STATE_STOP end elseif gOccupationTable[0] > 0 and not gGoingForward then -- might be an entry signal with a consist going backwards into a block newSignalState = STATE_BLOCKED elseif gConnectedLink == -1 or gOccupationTable[0] > 0 or gOccupationTable[gConnectedLink] > 0 then -- no route or occupied newSignalState = STATE_STOP elseif gConnectedLink > 0 and gLinkState[gConnectedLink] == STATE_BLOCKED then -- exit signal facing an occupied block newSignalState = STATE_STOP elseif gExpectState == STATE_STOP then newSignalState = STATE_STOP elseif gConnectedLink > 1 then -- diverging route, signal slow newSignalState = STATE_SLOW end if newSignalState ~= gSignalState then DebugPrint("SetSignalState() - signal state changed from " .. gSignalState .. " to " .. newSignalState .. " - sending message" ) gSignalState = newSignalState SetLights() if gHomeSignal then if gSignalState >= STATE_STOP then Call( "Set2DMapSignalState", STATE_STOP) else Call( "Set2DMapSignalState", gSignalState) end if gSignalState == STATE_BLOCKED and not gBlockSignal then Call( "SendSignalMessage", SIGNAL_STOP, "BLOCKED", -1, 1, 0 ) else Call( "SendSignalMessage", SIGNAL_GO + gSignalState, "", -1, 1, 0 ) end end end end -------------------------------------------------------------------------------------- -- SWITCH LIGHT -- Turns the selected light node on (1) / off (0) -- if the light node exists for this signal function SwitchLight( lightNode, state ) if lightNode ~= nil then Call ( "ActivateNode", lightNode, state ) end end
People are also talking about the Stainforth route that is also causing the sim to crash because of a script problem with the signals Option 2 - Reverting to an older version of TS. Is this possible? Yes. I have a current and an older version (v72.3) https://forums.dovetailgames.com/th...ly-install-old-ts-versions-next-to-tsc.71041/
Thanks! That worked! (In 32 bit. 64 bit still crashes.) This confirms that the core update caused the signal scripts and/or link placement to cause the crashes. I'm wondering if it's possible to narrow down what the issue is with the signals? Any LUA experts out there?
No idea if this has anything whatsoever to do with it, but I did notice a typo here: Should be lights, but I don't know if that would cause a script to fail by itself.
Some of the include statements are now comments, which suggests it was built on top of an existing signal implementation / extension, but now it either uses some basic implementation or none at all. For example it's using constants like LIGHT_NODE_GREEN2 (passed into SwitchNode) but they aren't defined here. (Steve, typos in comments really shouldn't break anything. The only queer system I know processing comments is JavaScript for compatibility with a previous millennium and then habits and conventions.) Some of the methods (starting with Base) are stitched into this script, not ideal, I assume it has something to do with removing the inheritance. So the above constants might be TSC LUA globals as well.
Thanks everyone. My LUA skills are rudimentary at best. The same basic script is used for all Swedish signals, with some modifications depending on the type of signal. I guess that's why there are reference to light nodes that doesn't exist in this particular signal. Could that be a cause for crashes? Am I right in that the script doesn't contain any obvious issues that would let it run before the core update but consistently crashes on route loading post core update? It would be interesting if DTG could provide information on what's actually changed under the hood with the latest updates (maybe this exists?).
The problem is that apparently changes were made "in-place" instead of creating new assets. That means there is different versions of KMW and newS signals with exact same path and filename around, which makes things extremely complicated. It would have been a good thing to clone the assets into your own Provider folder and do changes in there - this way, they would not affect other routes relying on the original signals. (Same happened to signals from Yelland - some freeware developer issued modified versions that broke some routes).
I'm not sure that there are different versions with the exact same name. Sure, the signal scripts have been modified over the years but it hasn't changed the compatibility with signals already placed in routes, as far as I'm aware. The modifications to signal scripts have been mainly adding signal links to be able to use the same signal for more tracks, and we haven't noticed any issues with this over the years. Where there has been a need for a new signal with different behaviour, a new asset (with its own unique name, just referencing the same 3D object blueprints) has been created. I don't think multiple signal versions is the root cause of the crashes, since the routes have been running flawlessly in previous TS versions. There must have been some crucial change in how TS handles errors/exceptions in scripts which is causing the issues with the current TS version. If we could know exactly what has changed then maybe it would be possible to revise the scripts to make them work in the current and future TS version as well?
Thanks for the read, however, this just confirms that since the recent (last year) core updates, some scripts are crashing the sim. Before this, all routes were working (but in some cases crashing in 64 bit). I agree that ideally there should be separate signal versions for each route to avoid overwriting signals in other routes, but it's easier said than done considering that the route authors have had limited knowledge of the inner workings of the sim (speaking for myself, and I believe Totte as well), while there has been a need for improvements to the signals. Adjusting the scripts for existing signals have enhanced their functionality without causing any adverse effects - except suddenly after the recent core update, which would have been impossible to foresee years ago. On my route Jönköpingsbanan and Kiruna-Narvik which I refurbished for newS, I can confirm the following: Pre core update both routes would run in 32 and 64 bit. In 64 bit, the routes would crash in certain scenarios, where I found that the crashes occurred when a train crossed a specific link related to level crossings After the core update, Jönköpingsbanan crashes on route loading (I don't think I've had a chance to check with Kiruna-Narvik and I'm not at my TS computer for a while). I found that disabling the SE End Signal script allows Jönköpingsbanan to load also in the latest TS version (this signal is not used on Kiruna-Narvik as far as I can remember). I have tried with the original version of this signal script as well as the updated one; both crash the route on loading so it's not related to the updated script. Even with the SE End Signal script disabled, post core update, Jönköpingsbanan crashes when crossing certain signal links. Reverting to a pre core update TS version allows me to run routes without signal script related crashes, at least in 32 bit. It would be very interesting to get some insight from the developers as to what exactly has changed in the script handling a) between 32 and 64 bit versions, and b) after the core update.
With some help I finally figured out the main culprit for the crashes: (certain) links turned the "wrong" way. This has been used for the above mentioned "end signal" where it should display a stop aspect continuously, and having a wrong way link ahead of the base link has achieved this previously. Wrong way links have also been used in level crossings. Apparently the newer TS versions will not accept this. By updating the "end signal" script and turning the associated links the "right" way, I was able to keep the function of the signal. I have also replaced level crossings with a modern version (based on the standard TS level crossing scripts). While I'm really happy that the route can now live on (and perhaps I'll even do some work to extend it) but this raises a few new issues: - The level crossing script is not as flexible as the previous setup with links to activate the level crossing at specified points. The new script simply activates the crossing at a set distance. This means that the crossing signals generally activate too early for slow moving trains and too late for fast moving trains. Is it possible to modify the script to be more flexible/realistic? Does anyone know of a good level crossing script to take inspiration from? - The new level crossing sounds only work occasionally. Apparently it's a known issue? Is it possible to do something about that? - I had previously used platform barriers with a bell sound hidden undergound to activate a bell when a train crosses certain points in yards/stations. As this persistently crashed the sim whenever the associated link was activated, I had to remove these and I have yet to find a good replacement. It seems like a simple script to have a sound activate when a train passes a crossing (possibly the "main" LC script can be modified for this?). Perhaps such a script/asset already exists?
Most interesting find. In fact, TSC allowed much "unconventional" trickery which has been restricted to prevent crashes. You could basically feed it with anything previously, even if it not makes any logical sense like wrong direction links. But I can see in my mind what happens in the code and why they removed it. I am in no way an expert in signalling, I know how to place one and the links. But I do know that german Schuster SignalTeam provided a "Hp0" Red Signal Trigger that corrected some Kuju shortcomings.