diff options
Diffstat (limited to 'advtrains_interlocking')
-rw-r--r-- | advtrains_interlocking/init.lua | 1 | ||||
-rw-r--r-- | advtrains_interlocking/route_ui.lua | 8 | ||||
-rw-r--r-- | advtrains_interlocking/signal_api.lua | 23 | ||||
-rw-r--r-- | advtrains_interlocking/signal_aspect_ui.lua | 3 | ||||
-rw-r--r-- | advtrains_interlocking/smartroute.lua | 149 | ||||
-rwxr-xr-x | advtrains_interlocking/tcb_ts_ui.lua | 31 |
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 |