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
|
if var.switchalt and var.switchst then
|
||||||
local switchfunc=function(pos, node, newstate)
|
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.ndb.swap_node(pos, {name=def.nodename_prefix.."_"..var.switchalt..rotation, param2=node.param2})
|
||||||
advtrains.invalidate_all_paths(pos)
|
advtrains.invalidate_all_paths(pos)
|
||||||
end
|
end
|
||||||
|
|
|
@ -64,6 +64,7 @@ Whenever train leaves a TC
|
||||||
-> Clearing any routes set from this TC outward recursively - see "Reversing problem"
|
-> Clearing any routes set from this TC outward recursively - see "Reversing problem"
|
||||||
Whenever train enters a TC
|
Whenever train enters a TC
|
||||||
-> Clear route status from the just entered 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 ==
|
== 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.
|
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)
|
Imagine this setup: (T=Train, R=Route, >=in_dir TCB)
|
||||||
|
@ -108,10 +109,18 @@ function ildb.load(data)
|
||||||
if data.signalass then
|
if data.signalass then
|
||||||
signal_assignments = data.signalass
|
signal_assignments = data.signalass
|
||||||
end
|
end
|
||||||
|
if data.rs_locks then
|
||||||
|
advtrains.interlocking.route.rte_locks = data.rs_locks
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function ildb.save()
|
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
|
end
|
||||||
|
|
||||||
--
|
--
|
||||||
|
@ -144,9 +153,21 @@ Track section
|
||||||
name = "Some human-readable name"
|
name = "Some human-readable name"
|
||||||
tc_breaks = { <signal specifier>,... } -- Bounding TC's (signal specifiers)
|
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
|
-- 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
|
-- 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
|
trains = {<id>, ...} -- Set whenever a train (or more) reside in this TC
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -379,10 +400,11 @@ function ildb.remove_from_interlocking(sigd)
|
||||||
end
|
end
|
||||||
|
|
||||||
function ildb.remove_tcb(pos)
|
function ildb.remove_tcb(pos)
|
||||||
|
local pts = advtrains.roundfloorpts(pos)
|
||||||
|
if not track_circuit_breaks[pts] then return end
|
||||||
for connid=1,2 do
|
for connid=1,2 do
|
||||||
ildb.remove_from_interlocking({p=pos, s=connid})
|
ildb.remove_from_interlocking({p=pos, s=connid})
|
||||||
end
|
end
|
||||||
local pts = advtrains.roundfloorpts(pos)
|
|
||||||
track_circuit_breaks[pts] = nil
|
track_circuit_breaks[pts] = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -11,3 +11,4 @@ dofile(modpath.."signal_api.lua")
|
||||||
dofile(modpath.."demosignals.lua")
|
dofile(modpath.."demosignals.lua")
|
||||||
dofile(modpath.."train_related.lua")
|
dofile(modpath.."train_related.lua")
|
||||||
dofile(modpath.."route_prog.lua")
|
dofile(modpath.."route_prog.lua")
|
||||||
|
dofile(modpath.."routesetting.lua")
|
||||||
|
|
|
@ -356,6 +356,6 @@ minetest.register_chatcommand("at_rp_discard",
|
||||||
|
|
||||||
|
|
||||||
--TODO on route setting
|
--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
|
-- unify luaautomation get/setstate interface to the core
|
||||||
-- privileges for route programming
|
-- 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
|
-- 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 = {}
|
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
|
-- Requests the given route
|
||||||
-- This function will try to set the designated route.
|
-- This function will try to set the designated route.
|
||||||
|
@ -10,3 +23,204 @@ local ilrs = {}
|
||||||
function ilrs.request_route(signal, tcbs, routeid)
|
function ilrs.request_route(signal, tcbs, routeid)
|
||||||
|
|
||||||
end
|
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,2.5;A route is requested from this signal:]"
|
||||||
form = form.."label[0.5,3.0;"..rte.name.."]"
|
form = form.."label[0.5,3.0;"..rte.name.."]"
|
||||||
if tcbs.route_committed then
|
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
|
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
|
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
|
else
|
||||||
local strtab = {}
|
local strtab = {}
|
||||||
for idx, route in ipairs(tcbs.routes) do
|
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
|
tcbs.signal_name = fields.name
|
||||||
end
|
end
|
||||||
if tcbs.routeset and fields.cancelroute then
|
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
|
end
|
||||||
if not tcbs.routeset then
|
if not tcbs.routeset then
|
||||||
if fields.newroute then
|
if fields.newroute then
|
||||||
|
@ -525,7 +532,15 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
|
||||||
end
|
end
|
||||||
if sel_rte and tcbs.routes[sel_rte] then
|
if sel_rte and tcbs.routes[sel_rte] then
|
||||||
if fields.setroute 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
|
end
|
||||||
if fields.dsproute then
|
if fields.dsproute then
|
||||||
local t = os.clock()
|
local t = os.clock()
|
||||||
|
|
|
@ -73,6 +73,19 @@ local function setsection(tid, train, ts_id, ts, origin)
|
||||||
table.insert(ts.trains, tid)
|
table.insert(ts.trains, tid)
|
||||||
end
|
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
|
end
|
||||||
|
|
||||||
local function freesection(tid, train, ts_id, ts)
|
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
|
if not ts.trains then ts.trains = {} end
|
||||||
itremove(ts.trains, tid)
|
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
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue