aboutsummaryrefslogtreecommitdiff
path: root/advtrains_interlocking/routesetting.lua
Commit message (Expand)AuthorAge
* Tag strings for Interlockingorwell2025-06-11
* Multi-ARS (waiting for multiple routes simultaneously, load-balancing)release-2.6.0orwell2025-05-06
* fix undeclared global accessesorwell2025-03-25
* Convert old PTS format on freeing route locks (route_post is not migrated)orwell2025-01-09
* Various bugfixes found in lunixforks debugorwell2025-01-09
* Fix crash with missing section in routesetting, correctly clear ARS table whe...orwell2025-01-07
* Repair sections on smartroute, detect start!=end TS in routesetting, create s...orwell2024-12-13
* Route Edit: Support aspect selection per signal, support call-on routesorwell2024-12-05
* Clear route_rsn when route commit succeeds and on section enteringorwell2024-11-25
* Remove debug prints of distant signalling systemorwell2024-11-25
* Add Blocksignal mode for signals to autocreate simple block routeorwell2024-11-14
* Merge branch 'master' into route_prog_reworkorwell2024-11-11
|\
| * Fix update_route receiving invalid route ID in after()1F616EMO2024-11-09
| * Clear tcbs.route_rsn when a route is setY. Wang2024-09-02
* | Support signal aspect selection for routes againorwell2024-07-20
* | ARS supports triggering distant signal, other bugfixesorwell2024-07-20
* | Respect route_role of signals during routesetting, assign distant signals in ...orwell2024-06-12
* | Add proper UI aspect selection for static dialogorwell2024-05-23
* | Connect the ropes, start on making the UI workorwell2024-05-23
* | Merge branch 'new-ks-orwell' into route_prog_reworkorwell2024-04-08
|\ \
| * | Add hotfix for path invalidationY. Wang2023-03-23
| * | Automatic dst unassignment; respect tcbs.nodstY. Wang2023-03-23
| * | Reduce number of set_aspect callsY. Wang2023-03-23
| * | Unassign distant signals when canceling routeY. Wang2023-03-23
| * | Implement primitive distant signalingY. Wang2023-03-23
| |/
* | Implement routesetting incorporating tscache, other improvementsorwell2024-01-28
* | Signals can have nil name, documentation on route deforwell2023-12-17
|/
* Fix things, rework signal aspect select dialog, transform old aspects on-the-flyorwell962021-02-10
* Simplify Signal Aspect Table (H#132) [breaks compatibility with signal API]orwell962021-02-10
* Add "Fallback state" for freed routes, move p_mesecon_iface.lua to coreorwell962020-07-07
* Fix minetest.after() loop between ARS->update_route->update_signal_aspect->in...orwell962020-06-05
* Fix the "red signals" bug that appeared when clicking a green signalorwell962019-11-21
* Fix cancelling "Unknown Route" when section is deleted.orwell962019-03-15
* Fix routesetting when TCBS is missing (H#109)orwell962019-02-12
* Signalling form auto-updateorwell962019-02-05
* Prohibit removing/changing of TCBs and sections while routes or signals are setorwell962019-01-22
* Actual working ARSorwell962019-01-15
* Permit basic signal aspect settingorwell962018-11-19
* Replace "Allow accelereting train towards signal"orwell962018-10-30
* Miscellaneous routesetting fixesorwell962018-10-29
* Display route_rsn when denying routesetting by subroute locked.orwell962018-10-25
* Improve route programming:orwell962018-10-07
* Add LuaAutomation interface functions for interlocking routesetting and aspec...orwell962018-08-24
* Move passive API to the advtrains coreorwell962018-08-16
* Fix various bugs found while testingorwell962018-08-13
* Automatic working (re-set certain route on train pass)orwell962018-08-12
* Signal aspect handling, make default signals compatible, fix signal diggingorwell962018-08-12
* Add routesetting callbacks.orwell962018-08-12
* Uncommitted route handling (update_route function)orwell962018-08-03
* Implement routesettingorwell962018-07-21
nd c_ts = ildb.get_ts(c_ts_id) c_rseg = route[i] c_lckp = {} if c_ts.route then if not try then atwarn("Encountered ts lock during a real run of routesetting routine, at ts=",c_ts_id,"while setting route",rtename,"of",signal) end return false, "Section '"..c_ts.name.."' already has route set from "..sigd_to_string(c_ts.route.origin)..":\n"..c_ts.route.rsn, c_ts_id, nil end if c_ts.trains and #c_ts.trains>0 then if not try then atwarn("Encountered ts occupied during a real run of routesetting routine, at ts=",c_ts_id,"while setting route",rtename,"of",signal) end return false, "Section '"..c_ts.name.."' is occupied!", c_ts_id, nil end for pts, state in pairs(c_rseg.locks) do local confl = ilrs.has_route_lock(pts, state) local pos = minetest.string_to_pos(pts) if advtrains.is_passive(pos) then local cstate = advtrains.getstate(pos) if cstate ~= state then local confl = ilrs.has_route_lock(pts) if confl then if not try then atwarn("Encountered route lock while a real run of routesetting routine, at position",pts,"while setting route",rtename,"of",signal) end return false, "Lock conflict at "..pts..", Held locked by:\n"..confl, nil, pts elseif not try then advtrains.setstate(pos, state) end end if not try then ilrs.add_route_lock(pts, c_ts_id, "Route '"..rtename.."' from signal '"..signalname.."'", signal) c_lckp[#c_lckp+1] = pts end else if not try then atwarn("Encountered route lock misconfiguration (no passive component) while a real run of routesetting routine, at position",pts,"while setting route",rtename,"of",signal) end return false, "No passive component at "..pts..". Please reconfigure route!" end end -- reserve ts and write locks if not try then local nvar = c_rseg.next if not route[i+1] then -- We shouldn't use the "next" value of the final route segment, because this can lead to accidental route-cancelling of already set routes from another signal. nvar = nil end c_ts.route = { origin = signal, entry = c_sigd, rsn = "Route '"..rtename.."' from signal '"..signalname.."', segment #"..i, first = first, } c_ts.route_post = { locks = c_lckp, next = nvar, } if c_tcbs.signal then c_tcbs.route_committed = true c_tcbs.aspect = route.aspect or asp_generic_free c_tcbs.route_origin = signal advtrains.interlocking.update_signal_aspect(c_tcbs) end end -- advance first = nil c_sigd = c_rseg.next i = i + 1 end return true end -- Checks whether there is a route lock that prohibits setting the component -- to the wanted state. returns string with reasons on conflict function ilrs.has_route_lock(pts) -- look this up local e = ilrs.rte_locks[pts] if not e then return nil elseif #e==0 then ilrs.rte_locks[pts] = nil return nil end local txts = {} for _, ent in ipairs(e) do txts[#txts+1] = ent.rsn end return table.concat(txts, "\n") end -- adds route lock for position function ilrs.add_route_lock(pts, ts, rsn, origin) ilrs.free_route_locks_indiv(pts, ts, true) local elm = {by=ts, rsn=rsn, origin=origin} if not ilrs.rte_locks[pts] then ilrs.rte_locks[pts] = { elm } else table.insert(ilrs.rte_locks[pts], elm) end end -- adds route lock for position function ilrs.add_manual_route_lock(pts, rsn) local elm = {rsn=rsn} if not ilrs.rte_locks[pts] then ilrs.rte_locks[pts] = { elm } else table.insert(ilrs.rte_locks[pts], elm) end end -- frees route locking for all points (components) that were set by this ts function ilrs.free_route_locks(ts, lcks, nocallbacks) for _,pts in pairs(lcks) do ilrs.free_route_locks_indiv(pts, ts, nocallbacks) end end function ilrs.free_route_locks_indiv(pts, ts, nocallbacks) local e = ilrs.rte_locks[pts] if not e then return nil elseif #e==0 then ilrs.rte_locks[pts] = nil return nil end local i = 1 while i <= #e do if e[i].by == ts then --atdebug("free_route_locks_indiv",pts,"clearing entry",e[i].by,e[i].rsn) table.remove(e,i) else i = i + 1 end end -- This must be delayed, because this code is executed in-between a train step -- TODO use luaautomation timers? if not nocallbacks then minetest.after(0, ilrs.update_waiting, "lck", pts) end end -- frees all route locks, even manual ones set with the tool, at a specific position function ilrs.remove_route_locks(pts, nocallbacks) ilrs.rte_locks[pts] = nil -- This must be delayed, because this code is executed in-between a train step -- TODO use luaautomation timers? if not nocallbacks then minetest.after(0, ilrs.update_waiting, "lck", pts) end end -- starting from the designated sigd, clears all subsequent route and route_post -- information from the track sections. -- note that this does not clear the routesetting status from the entry signal, -- only from the ts's function ilrs.cancel_route_from(sigd) -- we start at the tc designated by signal local c_sigd = sigd local c_tcbs, c_ts_id, c_ts, c_rseg, c_lckp while c_sigd do --atdebug("cancel_route_from: at sigd",c_sigd) c_tcbs = ildb.get_tcbs(c_sigd) c_ts_id = c_tcbs.ts_id c_ts = ildb.get_ts(c_ts_id) if not c_ts or not c_ts.route or not sigd_equal(c_ts.route.entry, c_sigd) then --atdebug("cancel_route_from: abort (eoi/no route):") return end --atdebug("cancelling",c_ts.route.rsn) -- clear signal aspect and routesetting state c_tcbs.route_committed = nil c_tcbs.aspect = nil c_tcbs.routeset = nil c_tcbs.route_auto = nil c_tcbs.route_origin = nil advtrains.interlocking.update_signal_aspect(c_tcbs) c_ts.route = nil if c_ts.route_post then advtrains.interlocking.route.free_route_locks(c_ts_id, c_ts.route_post.locks) c_sigd = c_ts.route_post.next else c_sigd = nil end c_ts.route_post = nil minetest.after(0, advtrains.interlocking.route.update_waiting, "ts", c_ts_id) end --atdebug("cancel_route_from: done (no final sigd)") end -- TCBS Routesetting helper: generic update function for -- route setting function ilrs.update_route(sigd, tcbs, newrte, cancel) -- in general, always show danger signal tcbs.aspect = nil --atdebug("Update_Route for",sigd,tcbs.signal_name) if tcbs.route_origin and not sigd_equal(tcbs.route_origin, sigd) then --atdebug("Signal not in control, held by",tcbs.signal_name) return end if (newrte and tcbs.routeset and tcbs.routeset ~= newrte) or cancel then if tcbs.route_committed then --atdebug("Cancelling:",tcbs.routeset) advtrains.interlocking.route.cancel_route_from(sigd) end tcbs.route_committed = nil tcbs.aspect = nil tcbs.routeset = nil tcbs.route_auto = nil tcbs.route_rsn = nil end if newrte or tcbs.routeset then if tcbs.route_committed then return end if newrte then tcbs.routeset = newrte end --atdebug("Setting:",tcbs.routeset) local succ, rsn, cbts, cblk = ilrs.set_route(sigd, tcbs.routes[tcbs.routeset]) if not succ then tcbs.route_rsn = rsn --atdebug("Routesetting failed:",rsn) -- add cbts or cblk to callback table if cbts then --atdebug("cbts =",cbts) if not ilrs.rte_callbacks.ts[cbts] then ilrs.rte_callbacks.ts[cbts]={} end advtrains.insert_once(ilrs.rte_callbacks.ts[cbts], sigd, sigd_equal) end if cblk then --atdebug("cblk =",cblk) if not ilrs.rte_callbacks.lck[cblk] then ilrs.rte_callbacks.lck[cblk]={} end advtrains.insert_once(ilrs.rte_callbacks.lck[cblk], sigd, sigd_equal) end else --atdebug("Committed Route:",tcbs.routeset) end end advtrains.interlocking.update_signal_aspect(tcbs) end -- Try to re-set routes that conflicted with this point -- sys can be one of "ts" and "lck" -- key is then ts_id or pts respectively function ilrs.update_waiting(sys, key) --atdebug("update_waiting:",sys,".",key) local t = ilrs.rte_callbacks[sys][key] ilrs.rte_callbacks[sys][key] = nil if t then for _,sigd in ipairs(t) do --atdebug("Updating", sigd) -- While these are run, the table we cleared before may be populated again, which is in our interest. -- (that's the reason we needed to copy it) local tcbs = ildb.get_tcbs(sigd) if tcbs then ilrs.update_route(sigd, tcbs) end end end end advtrains.interlocking.route = ilrs