aboutsummaryrefslogtreecommitdiff
path: root/advtrains_interlocking
diff options
context:
space:
mode:
Diffstat (limited to 'advtrains_interlocking')
-rw-r--r--advtrains_interlocking/init.lua1
-rw-r--r--advtrains_interlocking/route_ui.lua8
-rw-r--r--advtrains_interlocking/signal_api.lua23
-rw-r--r--advtrains_interlocking/signal_aspect_ui.lua3
-rw-r--r--advtrains_interlocking/smartroute.lua149
-rwxr-xr-xadvtrains_interlocking/tcb_ts_ui.lua31
6 files changed, 191 insertions, 24 deletions
diff --git a/advtrains_interlocking/init.lua b/advtrains_interlocking/init.lua
index a4ddbad..5883ab3 100644
--- a/advtrains_interlocking/init.lua
+++ b/advtrains_interlocking/init.lua
@@ -22,6 +22,7 @@ dofile(modpath.."route_prog.lua")
dofile(modpath.."routesetting.lua")
dofile(modpath.."tcb_ts_ui.lua")
dofile(modpath.."route_ui.lua")
+dofile(modpath.."smartroute.lua")
dofile(modpath.."tool.lua")
dofile(modpath.."approach.lua")
diff --git a/advtrains_interlocking/route_ui.lua b/advtrains_interlocking/route_ui.lua
index 982c579..863fe11 100644
--- a/advtrains_interlocking/route_ui.lua
+++ b/advtrains_interlocking/route_ui.lua
@@ -86,6 +86,9 @@ function atil.show_route_edit_form(pname, sigd, routeid)
form = form.."textlist[0.5,2;3,3.9;rtelog;"..table.concat(tab, ",").."]"
form = form.."button[0.5,6;3,1;back;<<< Back to signal]"
+ if route.smartroute_generated then
+ form = form.."button[3.5,6;2,1;noautogen;Clr Autogen]"
+ end
form = form.."button[5.5,6;3,1;delete;Delete Route]"
--atdebug(route.ars)
@@ -135,6 +138,11 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
advtrains.interlocking.show_signal_aspect_selector(pname, suppasp, route.name, callback, route.aspect or advtrains.interlocking.GENERIC_FREE)
return
end
+
+ if fields.noautogen then
+ route.smartroute_generated = nil
+ end
+
if fields.delete then
-- if something set the route in the meantime, make sure this doesn't break.
atil.route.update_route(sigd, tcbs, nil, true)
diff --git a/advtrains_interlocking/signal_api.lua b/advtrains_interlocking/signal_api.lua
index 65fc787..eddf9da 100644
--- a/advtrains_interlocking/signal_api.lua
+++ b/advtrains_interlocking/signal_api.lua
@@ -419,12 +419,29 @@ end
----------------
function signal.can_dig(pos)
- return not advtrains.interlocking.db.get_sigd_for_signal(pos)
+ local sigd = advtrains.interlocking.db.get_sigd_for_signal(pos)
+ if sigd then
+ local tcbs = advtrains.interlocking.db.get_tcbs(sigd)
+ if tcbs.routeset then
+ return false
+ end
+ end
+ return true
end
-function signal.after_dig(pos)
+function signal.after_dig(pos, oldnode, oldmetadata, player)
+ -- unassign signal if necessary
+ local sigd = advtrains.interlocking.db.get_sigd_for_signal(pos)
+ if sigd then
+ local tcbs = advtrains.interlocking.db.get_tcbs(sigd)
+ advtrains.interlocking.db.set_sigd_for_signal(pos, nil)
+ tcbs.signal = nil
+ tcbs.route_aspect = nil
+ tcbs.route_remote = nil
+ minetest.chat_send_player(player:get_player_name(), "Signal has been unassigned. Name and routes are kept for reuse.")
+ end
-- TODO clear influence point
- advtrains.interlocking.signal.clear_aspect(pos)
+ advtrains.interlocking.signal.unregister_aspect(pos)
end
function signal.on_rightclick(pos, node, player, itemstack, pointed_thing)
diff --git a/advtrains_interlocking/signal_aspect_ui.lua b/advtrains_interlocking/signal_aspect_ui.lua
index 5ec4c50..39aab17 100644
--- a/advtrains_interlocking/signal_aspect_ui.lua
+++ b/advtrains_interlocking/signal_aspect_ui.lua
@@ -83,6 +83,7 @@ function advtrains.interlocking.show_ip_sa_form(pos, pname)
-- Create Signal aspect formspec elements
local ndef = advtrains.ndb.get_ndef(pos)
if ndef and ndef.advtrains then
+ form[#form+1] = F.label(0.5, 2, "Signal Aspect:")
-- main aspect list
if ndef.advtrains.main_aspects then
local entries = { "<none>" }
@@ -229,7 +230,7 @@ minetest.register_on_punchnode(function(pos, node, player, pointed_thing)
if not ma or ma.halt then -- make sure that dst is never set without a main aspect (esp. for pure distant signal case)
ma = "_default"
end
- advtrains.interlocking.signal.set_aspect(signalpos, ma.name, nrpos)
+ advtrains.interlocking.signal.set_aspect(signalpos, ma, nrpos)
end
players_assign_distant[pname] = nil
end
diff --git a/advtrains_interlocking/smartroute.lua b/advtrains_interlocking/smartroute.lua
new file mode 100644
index 0000000..770c379
--- /dev/null
+++ b/advtrains_interlocking/smartroute.lua
@@ -0,0 +1,149 @@
+-- smartroute.lua
+-- Implementation of the advtrains auto-route search
+
+local atil = advtrains.interlocking
+local ildb = atil.db
+local sr = {}
+
+
+local function otherside(s)
+ if s==1 then return 2 else return 1 end
+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 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
+ local last_pos
+ repeat
+ -- record position in mark_pos
+ local pts = advtrains.encode_pos(pos)
+ mark_pos[pts] = true
+
+ local node = advtrains.ndb.get_node_or_nil(pos)
+ 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
+ atdebug("(SmartRoute) Found turnout ",pos, "nodename", node.name, "entering at conn",bconnid)
+ 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)
+ end
+ return
+ end
+ --otherwise, this might be a tcb
+ local tcb = ildb.get_tcb(pos)
+ if tcb then
+ local fsigd = { p = pos, s = connid }
+ atdebug("(SmartRoute) Encounter TCB ",fsigd)
+ tcbseq[#tcbseq+1] = fsigd
+ -- check if this is a possible route endpoint
+ local tcbs = tcb[connid]
+ if tcbs.signal then
+ local ndef = advtrains.ndb.get_ndef(tcbs.signal)
+ if ndef and ndef.advtrains then
+ if ndef.advtrains.route_role == "main" or ndef.advtrains.route_role == "main_distant"
+ or ndef.advtrains.route_role == "end" or ndef.advtrains.route_role == "shunt" then
+ -- signal is suitable target
+ local is_mainsignal = ndef.advtrains.route_role ~= "shunt"
+ -- record the found route in the results
+ result_table[#result_table+1] = {
+ tcbseq = table.copy(tcbseq),
+ mark_pos = table.copy(mark_pos),
+ shunt_route = not is_mainsignal,
+ to_end_of_track = false,
+ name = tcbs.signal_name or atil.sigd_to_string(fsigd)
+ }
+ -- if this is a main signal and/or we are only searching shunt routes, stop the search here
+ if is_mainsignal or searching_shunt then
+ atdebug("(SmartRoute) Terminating here because it is main or only shunt routes searched")
+ return
+ end
+ end
+ end
+ 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")
+end
+
+local function build_route_from_foundroute(froute, name)
+ local route = {
+ name = froute.name,
+ use_rscache = true,
+ smartroute_generated = true,
+ }
+ for _, sigd in ipairs(froute.tcbseq) do
+ route[#route+1] = { next = sigd, locks = {} }
+ end
+ return route
+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
+ 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
+ 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)
+ else
+ i=i+1
+ end
+ end
+ -- just plainly create routes!
+ for idx, froute in ipairs(result_table) do
+ tcbs.routes[#tcbs.routes+1] = build_route_from_foundroute(froute)
+ end
+ atwarn("Smartroute done!")
+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 60be5f3..7f75bb9 100755
--- a/advtrains_interlocking/tcb_ts_ui.lua
+++ b/advtrains_interlocking/tcb_ts_ui.lua
@@ -616,6 +616,9 @@ function advtrains.interlocking.show_signalling_form(sigd, pname, sel_rte, calle
local strtab = {}
for idx, route in ipairs(tcbs.routes) do
local clr = ""
+ if route.smartroute_generated then
+ clr = "#FFFF55"
+ end
if route.ars then
clr = "#FF5555"
if route.ars.default then
@@ -639,8 +642,8 @@ function advtrains.interlocking.show_signalling_form(sigd, pname, sel_rte, calle
end
end
if hasprivs then
- form = form.."button[0.5,8;2.5,1;newroute;New Route]"
- form = form.."button[ 3,8;2.5,1;unassign;Unassign Signal]"
+ form = form.."button[0.5,8;2.5,1;smartroute;Smart Route]"
+ form = form.."button[ 3,8;2.5,1;newroute;New (Manual)]"
form = form..string.format("checkbox[0.5,8.75;ars;Automatic routesetting;%s]", not tcbs.ars_disabled)
end
elseif sigd_equal(tcbs.route_origin, sigd) then
@@ -730,6 +733,12 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
tcbs.ars_ignore_next = nil
return
end
+ if fields.smartroute and hasprivs then
+ advtrains.interlocking.smartroute.init(pname, sigd)
+ minetest.close_formspec(pname, formname)
+ tcbs.ars_ignore_next = nil
+ return
+ end
if sel_rte and tcbs.routes[sel_rte] then
if fields.setroute then
ilrs.update_route(sigd, tcbs, sel_rte)
@@ -748,24 +757,6 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
end
end
- if fields.unassign and hasprivs then
- -- unassigning the signal from the tcbs
- -- only when no route is set.
- -- Routes and name remain saved, in case the player wants to reassign a new signal
- if not tcbs.routeset then
- local signal_pos = tcbs.signal
- ildb.set_sigd_for_signal(signal_pos, nil)
- tcbs.signal = nil
- tcbs.route_aspect = nil
- tcbs.route_remote = nil
- minetest.close_formspec(pname, formname)
- minetest.chat_send_player(pname, "Signal has been unassigned. Name and routes are kept for reuse.")
- return
- else
- minetest.chat_send_player(pname, "Please cancel route first!")
- end
- end
-
if fields.ars then
tcbs.ars_disabled = not minetest.is_yes(fields.ars)
end