Implement routesetting
Missing things: signal aspect updating, waiting routes handling, management /info toolmaster
parent
5fc5eb9c2a
commit
c34794e8a1
|
@ -304,7 +304,8 @@ function advtrains.register_tracks(tracktype, def, preset)
|
|||
|
||||
if var.switchalt and var.switchst then
|
||||
local switchfunc=function(pos, node, newstate)
|
||||
if newstate~=var.switchst and not advtrains.get_train_at_pos(pos) then
|
||||
if newstate~=var.switchst and not advtrains.get_train_at_pos(pos)
|
||||
and not (advtrains.interlocking and advtrains.interlocking.route.has_route_lock(advtrains.roundfloorpts(pos)) ) then --TODO schöner machen
|
||||
advtrains.ndb.swap_node(pos, {name=def.nodename_prefix.."_"..var.switchalt..rotation, param2=node.param2})
|
||||
advtrains.invalidate_all_paths(pos)
|
||||
end
|
||||
|
|
|
@ -64,6 +64,7 @@ Whenever train leaves a TC
|
|||
-> Clearing any routes set from this TC outward recursively - see "Reversing problem"
|
||||
Whenever train enters a TC
|
||||
-> Clear route status from the just entered TC
|
||||
Note that this prohibits by design that the train clears the route ahead of it.
|
||||
== Reversing Problem ==
|
||||
Encountered at the Royston simulation in SimSig. It is solved there by imposing a time limit on the set route. Call-on routes can somehow be set anyway.
|
||||
Imagine this setup: (T=Train, R=Route, >=in_dir TCB)
|
||||
|
@ -108,10 +109,18 @@ function ildb.load(data)
|
|||
if data.signalass then
|
||||
signal_assignments = data.signalass
|
||||
end
|
||||
if data.rs_locks then
|
||||
advtrains.interlocking.route.rte_locks = data.rs_locks
|
||||
end
|
||||
end
|
||||
|
||||
function ildb.save()
|
||||
return {tcbs = track_circuit_breaks, ts=track_sections, signalass = signal_assignments}
|
||||
return {
|
||||
tcbs = track_circuit_breaks,
|
||||
ts=track_sections,
|
||||
signalass = signal_assignments,
|
||||
rs_locks = advtrains.interlocking.route.rte_locks,
|
||||
}
|
||||
end
|
||||
|
||||
--
|
||||
|
@ -144,9 +153,21 @@ Track section
|
|||
name = "Some human-readable name"
|
||||
tc_breaks = { <signal specifier>,... } -- Bounding TC's (signal specifiers)
|
||||
-- Can be direct ends (auto-detected), conflicting routes or TCBs that are too far away from each other
|
||||
route = {origin = <signal>, from_tcb = <index>}
|
||||
route = {
|
||||
origin = <signal>, -- route origin
|
||||
entry = <sigd>, -- supposed train entry point
|
||||
rsn = <string>,
|
||||
first = <bool>
|
||||
}
|
||||
route_post = {
|
||||
locks = {[n] = <pts>}
|
||||
next = <sigd>
|
||||
}
|
||||
-- Set whenever a route has been set through this TC. It saves the origin tcb id and side
|
||||
-- (=the origin signal). index is the TCB of the route origin
|
||||
-- (=the origin signal). rsn is some description to be shown to the user
|
||||
-- first says whether to clear the routesetting status from the origin signal.
|
||||
-- locks contains the positions where locks are held by this ts.
|
||||
-- 'route' is cleared when train enters the section, while 'route_post' cleared when train leaves section.
|
||||
trains = {<id>, ...} -- Set whenever a train (or more) reside in this TC
|
||||
}
|
||||
|
||||
|
@ -379,10 +400,11 @@ function ildb.remove_from_interlocking(sigd)
|
|||
end
|
||||
|
||||
function ildb.remove_tcb(pos)
|
||||
local pts = advtrains.roundfloorpts(pos)
|
||||
if not track_circuit_breaks[pts] then return end
|
||||
for connid=1,2 do
|
||||
ildb.remove_from_interlocking({p=pos, s=connid})
|
||||
end
|
||||
local pts = advtrains.roundfloorpts(pos)
|
||||
track_circuit_breaks[pts] = nil
|
||||
end
|
||||
|
||||
|
|
|
@ -11,3 +11,4 @@ dofile(modpath.."signal_api.lua")
|
|||
dofile(modpath.."demosignals.lua")
|
||||
dofile(modpath.."train_related.lua")
|
||||
dofile(modpath.."route_prog.lua")
|
||||
dofile(modpath.."routesetting.lua")
|
||||
|
|
|
@ -356,6 +356,6 @@ minetest.register_chatcommand("at_rp_discard",
|
|||
|
||||
|
||||
--TODO on route setting
|
||||
-- locked turnouts need to somehow know the TS they're associated to, which isn't possible with the current route programming and saving method
|
||||
-- unify luaautomation get/setstate interface to the core
|
||||
-- privileges for route programming
|
||||
-- routes should end at signals. complete route setting by punching a signal, and command as exceptional route completion
|
||||
|
|
|
@ -1,7 +1,20 @@
|
|||
-- 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 ildb = advtrains.interlocking.db
|
||||
local ilrs = {}
|
||||
|
||||
-- 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 = {}
|
||||
|
||||
-- Requests the given route
|
||||
-- This function will try to set the designated route.
|
||||
|
@ -10,3 +23,204 @@ local ilrs = {}
|
|||
function ilrs.request_route(signal, tcbs, routeid)
|
||||
|
||||
end
|
||||
|
||||
-- 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 - something went wrong, what is contained in the message.
|
||||
function ilrs.set_route(signal, route, try)
|
||||
if not try then
|
||||
atdebug("rteset real-run")
|
||||
local tsuc, trsn = ilrs.set_route(signal, route, true)
|
||||
if not tsuc then
|
||||
return false, trsn
|
||||
end
|
||||
atdebug("doing stuff")
|
||||
else
|
||||
atdebug("rteset try-run")
|
||||
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)
|
||||
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).."!"
|
||||
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 while 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).."!"
|
||||
end
|
||||
if c_ts.trains and #c_ts.trains>0 then
|
||||
if not try then atwarn("Encountered ts occupied while 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!"
|
||||
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)
|
||||
local node = advtrains.ndb.get_node(pos)
|
||||
local ndef = minetest.registered_nodes[node.name]
|
||||
if ndef and ndef.luaautomation and ndef.luaautomation.setstate and ndef.luaautomation.getstate then
|
||||
local cstate = ndef.luaautomation.getstate
|
||||
if type(cstate)=="function" then cstate = cstate(pos) end
|
||||
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
|
||||
elseif not try then
|
||||
ndef.luaautomation.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, "Route misconfiguration: No passive component at "..pts..". Please reconfigure route!"
|
||||
end
|
||||
end
|
||||
-- reserve ts and write locks
|
||||
if not try then
|
||||
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 = c_rseg.next,
|
||||
}
|
||||
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
|
||||
|
||||
--TODO callbacks
|
||||
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
|
||||
--TODO callbacks
|
||||
end
|
||||
|
||||
local function sigd_equal(sigd, cmp)
|
||||
return vector.equals(sigd.p, cmp.p) and sigd.s==cmp.s
|
||||
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
|
||||
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
|
||||
return
|
||||
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
|
||||
end
|
||||
end
|
||||
|
||||
advtrains.interlocking.route = ilrs
|
||||
|
||||
|
|
|
@ -457,12 +457,12 @@ function advtrains.interlocking.show_signalling_form(sigd, pname, sel_rte)
|
|||
form = form.."label[0.5,2.5;A route is requested from this signal:]"
|
||||
form = form.."label[0.5,3.0;"..rte.name.."]"
|
||||
if tcbs.route_committed then
|
||||
form = form.."label[0.5,2.5;Route has been set.]"
|
||||
form = form.."label[0.5,3.5;Route has been set.]"
|
||||
else
|
||||
form = form.."label[0.5,2.5;Waiting for route to be set...]"
|
||||
form = form.."label[0.5,3.5;Waiting for route to be set...]"
|
||||
end
|
||||
|
||||
form = form.."button[0.5,6.5;1,6;cancelroute;Cancel Route]"
|
||||
form = form.."button[0.5,6; 5,1;cancelroute;Cancel Route]"
|
||||
else
|
||||
local strtab = {}
|
||||
for idx, route in ipairs(tcbs.routes) do
|
||||
|
@ -515,7 +515,14 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
|
|||
tcbs.signal_name = fields.name
|
||||
end
|
||||
if tcbs.routeset and fields.cancelroute then
|
||||
--TODO
|
||||
-- if route committed, cancel route ts info
|
||||
if tcbs.route_committed then
|
||||
advtrains.interlocking.route.cancel_route_from(sigd)
|
||||
end
|
||||
-- then clear own routeset state
|
||||
--TODO callbacks
|
||||
tcbs.routeset = nil
|
||||
tcbs.route_committed = nil
|
||||
end
|
||||
if not tcbs.routeset then
|
||||
if fields.newroute then
|
||||
|
@ -525,7 +532,15 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
|
|||
end
|
||||
if sel_rte and tcbs.routes[sel_rte] then
|
||||
if fields.setroute then
|
||||
--TODO
|
||||
tcbs.routeset = sel_rte
|
||||
local succ, rsn = advtrains.interlocking.route.set_route(sigd, tcbs.routes[sel_rte])
|
||||
if not succ then
|
||||
atwarn("Setting route failed:")
|
||||
atwarn(rsn)
|
||||
tcbs.routeset = nil
|
||||
else
|
||||
tcbs.route_committed = true
|
||||
end
|
||||
end
|
||||
if fields.dsproute then
|
||||
local t = os.clock()
|
||||
|
|
|
@ -73,6 +73,19 @@ local function setsection(tid, train, ts_id, ts, origin)
|
|||
table.insert(ts.trains, tid)
|
||||
end
|
||||
|
||||
-- route setting - clear route state
|
||||
if ts.route then
|
||||
if ts.route.first then
|
||||
local tcbs = advtrains.interlocking.db.get_tcbs(ts.route.origin)
|
||||
if tcbs then
|
||||
--TODO callbacks
|
||||
tcbs.routeset = nil
|
||||
tcbs.route_committed = nil
|
||||
end
|
||||
end
|
||||
ts.route = nil
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
local function freesection(tid, train, ts_id, ts)
|
||||
|
@ -84,6 +97,15 @@ local function freesection(tid, train, ts_id, ts)
|
|||
if not ts.trains then ts.trains = {} end
|
||||
itremove(ts.trains, tid)
|
||||
|
||||
if ts.route_post then
|
||||
advtrains.interlocking.route.free_route_locks(ts_id, ts.route_post.locks)
|
||||
if ts.route_post.next then
|
||||
--this does nothing when the train went the right way, because
|
||||
-- "route" info is already cleared.
|
||||
advtrains.interlocking.route.cancel_route_from(ts.route_post.next)
|
||||
end
|
||||
ts.route_post = nil
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue