aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--advtrains_interlocking/database.lua17
-rw-r--r--advtrains_interlocking/route_ui.lua25
-rw-r--r--advtrains_interlocking/smartroute.lua118
-rwxr-xr-xadvtrains_interlocking/tcb_ts_ui.lua52
4 files changed, 134 insertions, 78 deletions
diff --git a/advtrains_interlocking/database.lua b/advtrains_interlocking/database.lua
index 09b1c72..3104a20 100644
--- a/advtrains_interlocking/database.lua
+++ b/advtrains_interlocking/database.lua
@@ -245,6 +245,14 @@ routes = {
800080008000 = st
}
next = S[(-23,9,0)/2] -- the start TCB of the next route segment (pointing forward)
+ -- Signal info: relates to the signal at the start of this section:
+ main_aspect = "_free" -- The main aspect that the route start signal is to show
+ assign_dst = false -- Whether to assign distant signal (affects only the signal at the start of the route)
+ -- false: start signal does not set distant signal (the default), for long blocks
+ -- it is assumed that the next main signal will have its own distant sig
+ -- true: start signal sets distant signal to the next signal on the route with route_role "main" (typically the end signal)
+ -- for short blocks where end signal doesn't have its own distant sig
+ call_on = false -- if true, when this route is set, section is allowed to be occupied by a train (but it must not have a route set in)
}
2 = {
locks = {}
@@ -254,15 +262,6 @@ routes = {
ars = { <ARS rule definition table> }
use_rscache = false -- if true, the track section's rs_cache will be used to set locks in addition to the locks table
-- this is disabled for legacy routes, but enabled for all new routes by default
- -- Fields to specify the signal aspect of the signal
- main_aspect = "_free" -- The main aspect that the route start signal is to show
- assign_dst = false -- Whether to assign distant signal (affects only the signal at the start of the route)
- -- false: start signal does not set distant signal (the default), for long blocks
- -- it is assumed that the next main signal will have its own distant sig
- -- true: start signal sets distant signal to the next signal on the route with route_role "main" (typically the end signal)
- -- for short blocks where end signal doesn't have its own distant sig
- terminal = <sigd> -- the sigd describing the end of the route (e.g. the "next" entry in the final route segment).
- -- Might be missing or wrong. Routesetting currently does not care about this value being present.
default_autoworking = false -- if true, when route is set autoworking will be by default on. Used for Blocksignal mode
}
}
diff --git a/advtrains_interlocking/route_ui.lua b/advtrains_interlocking/route_ui.lua
index fa707d9..b75f9d7 100644
--- a/advtrains_interlocking/route_ui.lua
+++ b/advtrains_interlocking/route_ui.lua
@@ -43,7 +43,7 @@ function atil.show_route_edit_form(pname, sigd, routeid, sel_rpartidx)
-- we start at the tc designated by signal
local c_sigd = sigd
local i = 1
- local c_tcbs, c_ts_id, c_ts, c_rseg, c_lckp
+ local c_tcbs, c_ts_id, c_ts, c_rseg
while c_sigd and i<=#route do
c_tcbs = ildb.get_tcbs(c_sigd)
if not c_tcbs then
@@ -58,7 +58,6 @@ function atil.show_route_edit_form(pname, sigd, routeid, sel_rpartidx)
c_ts = ildb.get_ts(c_ts_id)
c_rseg = route[i]
- c_lckp = {}
local signame = "-"
if c_tcbs and c_tcbs.signal then signame = c_tcbs.signal_name or "o" end
@@ -145,9 +144,9 @@ function atil.show_route_edit_form(pname, sigd, routeid, sel_rpartidx)
form = form.."button[2.5,6;1,1;next;>>>]"
- if route.smartroute_generated or route.default_autoworking then
- form = form.."button[3.5,6;2,1;noautogen;Clr Autogen]"
- end
+ --if route.smartroute_generated or route.default_autoworking then
+ -- form = form.."button[3.5,6;2,1;noautogen;Clr Autogen]"
+ --end
form = form.."button[5.5,6;3,1;delete;Delete Route]"
form = form.."button[0.5,7;3,1;back;Back to signal]"
form = form.."button[3.5,7;2,1;clone;Clone Route]"
@@ -235,13 +234,13 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
end
end
- if fields.noautogen then
- route.smartroute_generated = nil
- route.default_autoworking = nil
- -- reshow form for the button to disappear
- atil.show_route_edit_form(pname, sigd, routeid, sel_rpart and sel_rpart.idx)
- return
- end
+ --if fields.noautogen then
+ -- route.smartroute_generated = nil
+ -- route.default_autoworking = nil
+ -- -- reshow form for the button to disappear
+ -- atil.show_route_edit_form(pname, sigd, routeid, sel_rpart and sel_rpart.idx)
+ -- return
+ --end
if fields.delete then
-- if something set the route in the meantime, make sure this doesn't break.
@@ -298,7 +297,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
end
end
- if field.quit then
+ if fields.quit then
-- cleanup
sel_rpartcache[pname] = nil
end
diff --git a/advtrains_interlocking/smartroute.lua b/advtrains_interlocking/smartroute.lua
index 770c379..07cdf46 100644
--- a/advtrains_interlocking/smartroute.lua
+++ b/advtrains_interlocking/smartroute.lua
@@ -6,6 +6,23 @@ local ildb = atil.db
local sr = {}
+-- Start the SmartRoute process. This searches for routes and tries to match them with existing routes, showing them in a form
+function sr.start(pname, sigd)
+ -- is start signal a shunt signal? This becomes default setting for searching_shunt
+ local is_startsignal_shunt = false
+ local tcbs = ildb.get_tcbs(sigd)
+ if tcbs.signal then
+ local ndef = advtrains.ndb.get_ndef(tcbs.signal)
+ if ndef and ndef.advtrains then
+ if ndef.advtrains.route_role == "shunt" then
+ is_startsignal_shunt = true
+ end
+ end
+ end
+ sr.propose_next(pname, sigd, 10, is_startsignal_shunt) -- TODO set tscnt_limit to 2 initially and then increase it. Do this when form is implemented
+end
+
+
local function otherside(s)
if s==1 then return 2 else return 1 end
end
@@ -13,8 +30,8 @@ end
--route search implementation
-- Note this is similar to recursively_find_routes in database.lua, there used for the rscache
-local function recursively_find_routes(s_pos, s_connid, searching_shunt, tcbseq, mark_pos, result_table, scan_limit)
- --atdebug("Recursively restarting at ",s_pos, s_connid, "limit left", scan_limit)
+local function recursively_find_routes(s_pos, s_connid, searching_shunt, tcbseq, mark_pos, result_table, scan_limit, tscnt_limit)
+ atdebug("(SmartRoute) Recursively restarting at ",s_pos, s_connid, "limit left", scan_limit,"tscnt",tscnt_limit)
local ti = advtrains.get_track_iterator(s_pos, s_connid, scan_limit, false)
local pos, connid, bconnid = ti:next_branch()
pos, connid, bconnid = ti:next_track()-- step once to get ahead of previous turnout
@@ -25,7 +42,7 @@ local function recursively_find_routes(s_pos, s_connid, searching_shunt, tcbseq,
mark_pos[pts] = true
local node = advtrains.ndb.get_node_or_nil(pos)
- atdebug("(SmartRoute) Walk ",pos, "nodename", node.name, "entering at conn",bconnid)
+ --atdebug("(SmartRoute) Walk ",pos, "nodename", node.name, "entering at conn",bconnid)
local ndef = minetest.registered_nodes[node.name]
if ndef.advtrains and ndef.advtrains.node_state_map then
-- Stop, this is a switchable node. Find out which conns we can go at
@@ -33,7 +50,9 @@ local function recursively_find_routes(s_pos, s_connid, searching_shunt, tcbseq,
local out_conns = ildb.get_possible_out_connids(node.name, bconnid)
for oconnid, state in pairs(out_conns) do
--atdebug("Going in direction",oconnid,"state",state)
- recursively_find_routes(pos, oconnid, searching_shunt, table.copy(tcbseq), table.copy(mark_pos), result_table, ti.limit)
+ recursively_find_routes(pos, oconnid, searching_shunt,
+ table.copy(tcbseq), table.copy(mark_pos),
+ result_table, ti.limit, tscnt_limit)
end
return
end
@@ -68,12 +87,18 @@ local function recursively_find_routes(s_pos, s_connid, searching_shunt, tcbseq,
end
end
end
+ -- decrease tscnt
+ tscnt_limit = tscnt_limit - 1
+ atdebug("(SmartRoute) Remaining TS Count:",tscnt_limit)
+ if tscnt_limit <= 0 then
+ break
+ end
end
-- Go forward
last_pos = pos
pos, connid, bconnid = ti:next_track()
until not pos -- this stops the loop when either the track end is reached or the limit is hit
- --atdebug("recursively_find_routes: Reached track end or limit at", last_pos, ". This path is not saved, returning")
+ atdebug("(SmartRoute) Reached track end or limit at", last_pos, ". This path is not saved, returning")
end
local function build_route_from_foundroute(froute, name)
@@ -91,59 +116,54 @@ end
-- Maximum scan length for track iterator
local TS_MAX_SCAN = 1000
-function sr.init(pname, sigd)
- -- is start signal a shunt signal?
- local is_startsignal_shunt = false
+function sr.rescan(pname, sigd, tscnt_limit, searching_shunt)
+ local result_table = {}
+ recursively_find_routes(sigd.p, sigd.s, is_startsignal_shunt, {}, {}, result_table, TS_MAX_SCAN, tscnt_limit)
+ return result_table
+end
+
+-- Propose to pname the smartroute actions in a form, with the current settings as passed to this function
+function sr.propose_next(pname, sigd, tscnt_limit, searching_shunt)
local tcbs = ildb.get_tcbs(sigd)
- if tcbs.signal then
- local ndef = advtrains.ndb.get_ndef(tcbs.signal)
- if ndef and ndef.advtrains then
- if ndef.advtrains.route_role == "shunt" then
- is_startsignal_shunt = true
- end
+ if not tcbs or not tcbs.routes then
+ minetest.chat_send_player(pname, "Smartroute: TCBS or routes don't exist here!")
+ return
+ end
+ -- Step 1: search for routes using the current settings
+ local found_routes = sr.rescan(pname, sigd, tscnt_limit, searching_shunt)
+ -- Step 2: remove routes for endpoints for which routes already exist
+ local ex_endpts = {} -- key = sigd_to_string
+ for rtid, route in ipairs(tcbs.routes) do
+ local valid = advtrains.interlocking.check_route_valid(route, sigd)
+ local endpoint = route[#route].next -- 'next' field of the last route segment (the segment with index==len)
+ if valid and endpoint then
+ local endstr = advtrains.interlocking.sigd_to_string(endpoint)
+ atdebug("(Smartroute) Find existing endpoint:",route.name,"ends at",endstr)
+ ex_endpts[endstr] = route.name
+ else
+ atdebug("(Smartroute) Find existing endpoint:",route.name," not considered, endpoint",endpoint,"valid",valid)
end
end
- local result_table = {}
- recursively_find_routes(sigd.p, sigd.s, is_startsignal_shunt, {}, {}, result_table, TS_MAX_SCAN)
-
- atdebug("Smartroute search finished:",result_table)
-
- -- Short-circuit logic right now for testing
- -- go through and delete all routes that are autogenerated
- local i = 1
- while i<=#tcbs.routes do
- if tcbs.routes[i].smartroute_generated then
- table.remove(tcbs.routes, i)
+ local new_frte = {}
+ for _,froute in ipairs(found_routes) do
+ local endpoint = froute.tcbseq[#froute.tcbseq]
+ local endstr = advtrains.interlocking.sigd_to_string(endpoint)
+ if not ex_endpts[endstr] then
+ new_frte[#new_frte+1] = froute
else
- i=i+1
+ atdebug("(Smartroute) Throwing away",froute.name,"because endpoint",endstr,"already reached by route",ex_endpts[endstr])
end
end
- -- just plainly create routes!
- for idx, froute in ipairs(result_table) do
+
+ -- All remaining routes will be shown to user now.
+ -- TODO: show a form. Right now still shortcircuit
+ local sel_rte = #tcbs.routes+1
+ for idx, froute in ipairs(new_frte) do
tcbs.routes[#tcbs.routes+1] = build_route_from_foundroute(froute)
end
- atwarn("Smartroute done!")
+ atdebug("Smartroute done!")
+ advtrains.interlocking.show_signalling_form(sigd, pname, sel_rte)
end
-
---[[
- player1 = {
- origin = <sigd>
- found_routes = {
- { tcbseq = {<sigd1>, <sigd2>, <end_sigd>}, mark_pos = { table with keys being encoded_pos of rails constituting route }, to_end_of_track = false, shunt_route = false }
- }
- }
-]]--
-local player_smartroute = {}
-
-minetest.register_on_punchnode(function(pos, node, player, pointed_thing)
- local pname = player:get_player_name()
- if not minetest.check_player_privs(pname, "interlocking") then
- return
- end
- -- TODO
-end)
-
-
advtrains.interlocking.smartroute = sr
diff --git a/advtrains_interlocking/tcb_ts_ui.lua b/advtrains_interlocking/tcb_ts_ui.lua
index dfb2714..5bd6c08 100755
--- a/advtrains_interlocking/tcb_ts_ui.lua
+++ b/advtrains_interlocking/tcb_ts_ui.lua
@@ -6,6 +6,7 @@ local players_assign_xlink = {}
local players_link_ts = {}
local players_assign_fixedlocks = {}
+local atil = advtrains.interlocking
local ildb = advtrains.interlocking.db
local ilrs = advtrains.interlocking.route
@@ -746,6 +747,42 @@ function advtrains.interlocking.highlight_track_section(pos)
end
end
+-- checks that the given route is still valid (i.e. all its TCBs, sections and locks exist)
+-- returns true (ok) or false, reason (on issue)
+function advtrains.interlocking.check_route_valid(route, sigd)
+ -- this code is partially copy-pasted from routesetting.lua
+ -- we start at the tc designated by signal
+ local c_sigd = sigd
+ local i = 1
+ local c_tcbs, c_ts_id, c_ts, c_rseg
+ while c_sigd and i<=#route do
+ c_tcbs = ildb.get_tcbs(c_sigd)
+ if not c_tcbs then
+ return false, "No TCBS at "..sigd_to_string(c_sigd)
+ end
+ c_ts_id = c_tcbs.ts_id
+ if not c_ts_id then
+ 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]
+
+ if c_rseg.locks then
+ for pts, state in pairs(c_rseg.locks) do
+ local pos = minetest.string_to_pos(pts)
+ if not advtrains.is_passive(pos) then
+ return false, "No passive component for lock at "..pts
+ end
+ end
+ end
+ -- advance
+ c_sigd = c_rseg.next
+ i = i + 1
+ end
+ return true, nil, c_sigd
+end
+
-- Signalling formspec - set routes a.s.o
-- textlist selection temporary storage
@@ -800,17 +837,19 @@ function advtrains.interlocking.show_signalling_form(sigd, pname, sel_rte, calle
-- at least one route is defined, show normal dialog
local strtab = {}
for idx, route in ipairs(tcbs.routes) do
+ local rname = route.name
+ local valid = atil.check_route_valid(route, sigd)
local clr = ""
- if route.smartroute_generated then
- clr = "#FFFF55"
- end
- if route.ars then
+ if not valid then
clr = "#FF5555"
+ rname = rname.." (invalid)"
+ elseif route.ars then
+ clr = "#FFFF55"
if route.ars.default then
clr = "#55FF55"
end
end
- strtab[#strtab+1] = clr .. minetest.formspec_escape(route.name)
+ strtab[#strtab+1] = clr .. minetest.formspec_escape(rname)
end
form = form.."label[0.5,2.5;Routes:]"
form = form.."textlist[0.5,3;5,3;rtelist;"..table.concat(strtab, ",")
@@ -961,8 +1000,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
return
end
if fields.smartroute and hasprivs then
- advtrains.interlocking.smartroute.init(pname, sigd)
- minetest.close_formspec(pname, formname)
+ advtrains.interlocking.smartroute.start(pname, sigd)
tcbs.ars_ignore_next = nil
return
end