diff options
Diffstat (limited to 'advtrains_interlocking/routesetting.lua')
-rw-r--r-- | advtrains_interlocking/routesetting.lua | 357 |
1 files changed, 0 insertions, 357 deletions
diff --git a/advtrains_interlocking/routesetting.lua b/advtrains_interlocking/routesetting.lua deleted file mode 100644 index 575b053..0000000 --- a/advtrains_interlocking/routesetting.lua +++ /dev/null @@ -1,357 +0,0 @@ --- Setting and clearing routes - --- TODO duplicate -local lntrans = { "A", "B" } -local function sigd_to_string(sigd) - return minetest.pos_to_string(sigd.p).." / "..lntrans[sigd.s] -end - -local asp_generic_free = { - main = { - free = true, - speed = -1, - }, - shunt = { - free = false, - }, - dst = { - free = true, - speed = -1, - }, - info = {} -} - -local ildb = advtrains.interlocking.db -local ilrs = {} - -local sigd_equal = advtrains.interlocking.sigd_equal - --- table containing locked points --- also manual locks (maintenance a.s.o.) are recorded here --- [pts] = { --- [n] = { [by = <ts_id>], rsn = <human-readable text>, [origin = <sigd>] } --- } -ilrs.rte_locks = {} -ilrs.rte_callbacks = { - ts = {}, - lck = {} -} - - --- main route setting. First checks if everything can be set as designated, --- then (if "try" is not set) actually sets it --- returns: --- true - route can be/was successfully set --- false, message, cbts, cblk - something went wrong, what is contained in the message. --- cbts: the ts id of the conflicting ts, cblk: the pts of the conflicting component -function ilrs.set_route(signal, route, try) - if not try then - local tsuc, trsn, cbts, cblk = ilrs.set_route(signal, route, true) - if not tsuc then - return false, trsn, cbts, cblk - end - end - - - -- we start at the tc designated by signal - local c_sigd = signal - local first = true - local i = 1 - local rtename = route.name - local signalname = ildb.get_tcbs(signal).signal_name - local c_tcbs, c_ts_id, c_ts, c_rseg, c_lckp - while c_sigd and i<=#route do - c_tcbs = ildb.get_tcbs(c_sigd) - if not c_tcbs then - if not try then atwarn("Did not find TCBS",c_sigd,"while setting route",rtename,"of",signal) end - return false, "No TCB found at "..sigd_to_string(c_sigd)..". Please reconfigure route!" - end - c_ts_id = c_tcbs.ts_id - if not c_ts_id then - if not try then atwarn("Encountered End-Of-Interlocking while setting route",rtename,"of",signal) end - return false, "No track section adjacent to "..sigd_to_string(c_sigd)..". Please reconfigure route!" - end - 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) - minetest.after(0.5, advtrains.set_fallback_state, minetest.string_to_pos(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) - if not c_tcbs then - atwarn("Failed to cancel route, no TCBS at",c_sigd) - return false - 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_id = c_tcbs.ts_id - if not c_tcbs then - atwarn("Failed to cancel route, end of interlocking at",c_sigd) - return false - end - 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 false - end - - 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)") - return true -end - --- TCBS Routesetting helper: generic update function for --- route setting --- Call this function to set and cancel routes! --- sigd, tcbs: self-explanatory --- newrte: If a new route should be set, the route index of it (in tcbs.routes). nil otherwise --- cancel: true in combination with newrte=nil causes cancellation of the current route. -function ilrs.update_route(sigd, tcbs, newrte, cancel) - --atdebug("Update_Route for",sigd,tcbs.signal_name) - local has_changed_aspect = false - 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 - has_changed_aspect = true - 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) - has_changed_aspect = true - end - end - if has_changed_aspect then - -- FIX: prevent an minetest.after() loop caused by update_signal_aspect dispatching path invalidation, which in turn calls ARS again - advtrains.interlocking.update_signal_aspect(tcbs) - end - advtrains.interlocking.update_player_forms(sigd) -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 - |