From a751d1da9c57a40a0df4e8793a1cc46cb7985e12 Mon Sep 17 00:00:00 2001 From: orwell96 Date: Wed, 9 Jan 2019 18:03:40 +0100 Subject: Add Automatic Routesetting UI Settings have no effect so far --- advtrains_interlocking/ars.lua | 22 ++++ advtrains_interlocking/init.lua | 2 + advtrains_interlocking/route_ui.lua | 196 +++++++++++++++++++++++++++++++++++ advtrains_interlocking/tcb_ts_ui.lua | 34 +++--- 4 files changed, 232 insertions(+), 22 deletions(-) create mode 100644 advtrains_interlocking/ars.lua create mode 100644 advtrains_interlocking/route_ui.lua diff --git a/advtrains_interlocking/ars.lua b/advtrains_interlocking/ars.lua new file mode 100644 index 0000000..db67a93 --- /dev/null +++ b/advtrains_interlocking/ars.lua @@ -0,0 +1,22 @@ +-- ars.lua +-- automatic routesetting + +--[[ + The "ARS table" and its effects: + Every route has (or can have) an associated ARS table. This can either be + ars = { [n] = {ln=""}/{rc=""}/{c=""} } + a list of rules involving either line or routingcode matchers (or comments, those are ignored) + The first matching rule determines the route to set. + - or - + ars = {default = true} + this means that all trains that no other rule matches on should use this route + + Compound ("and") conjunctions are not supported (--TODO should they?) + + For editing, those tables are transformed into lines in a text area: + {ln=...} -> LN ... + {rc=...} -> RC ... + {c=...} -> #... + {default=true} -> * + See also route_ui.lua +]] diff --git a/advtrains_interlocking/init.lua b/advtrains_interlocking/init.lua index f46ed65..aa498df 100644 --- a/advtrains_interlocking/init.lua +++ b/advtrains_interlocking/init.lua @@ -19,9 +19,11 @@ dofile(modpath.."train_sections.lua") dofile(modpath.."route_prog.lua") dofile(modpath.."routesetting.lua") dofile(modpath.."tcb_ts_ui.lua") +dofile(modpath.."route_ui.lua") dofile(modpath.."tool.lua") dofile(modpath.."lzb.lua") +dofile(modpath.."ars.lua") minetest.register_privilege("interlocking", {description = "Can set up track sections, routes and signals.", give_to_singleplayer = true}) diff --git a/advtrains_interlocking/route_ui.lua b/advtrains_interlocking/route_ui.lua new file mode 100644 index 0000000..245b082 --- /dev/null +++ b/advtrains_interlocking/route_ui.lua @@ -0,0 +1,196 @@ +-- route_ui.lua +-- User interface for showing and editing routes + +local atil = advtrains.interlocking +local ildb = atil.db + +-- TODO duplicate +local lntrans = { "A", "B" } +local function sigd_to_string(sigd) + return minetest.pos_to_string(sigd.p).." / "..lntrans[sigd.s] +end + +-- The ARS data are saved in a table format, but are entered in text format. Utility functions to transform between both. +local function ars_to_text(arstab) + if not arstab then + return "" + end + + local txt = {} + + for i, arsent in ipairs(arstab) do + if arsent.ln then + txt[#txt+1] = "LN "..arsent.ln + elseif arsent.rc then + txt[#txt+1] = "RC "..arsent.rc + elseif arsent.c then + txt[#txt+1] = "#"..arsent.c + end + end + + if arstab.default then + return "*\n" .. table.concat(txt, "\n") + end + return table.concat(txt, "\n") +end + +local function text_to_ars(t) + if t=="" then + return nil + elseif t=="*" then + return {default=true} + end + local arstab = {} + for line in string.gmatch(t, "[^\r\n]+") do + if line=="*" then + arstab.default = true + else + local c, v = string.match(line, "^(..)%s(.*)$") + if c and v then + local tt=string.upper(c) + if tt=="LN" then + arstab[#arstab+1] = {ln=v} + elseif tt=="RC" then + arstab[#arstab+1] = {rc=v} + end + else + local ct = string.match(line, "^#(.*)$") + if ct then arstab[#arstab+1] = {c = ct} end + end + end + end + return arstab +end + + + +function atil.show_route_edit_form(pname, sigd, routeid) + + if not minetest.check_player_privs(pname, {train_operator=true, interlocking=true}) then + minetest.chat_send_player(pname, "Insufficient privileges to use this!") + return + end + + local tcbs = atil.db.get_tcbs(sigd) + if not tcbs then return end + local route = tcbs.routes[routeid] + if not route then return end + + local form = "size[9,10]label[0.5,0.2;Route overview]" + form = form.."field[0.8,1.2;5.2,1;name;Route name;"..route.name.."]" + form = form.."button[5.5,0.9;1,1;setname;Set]" + + -- construct textlist for route information + local tab = {} + local function itab(t) + tab[#tab+1] = string.gsub(t, ",", " ") + end + itab("TCB "..sigd_to_string(sigd).." ("..tcbs.signal_name..") Route #"..routeid) + + -- 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, 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 + itab("-!- No track section adjacent to "..sigd_to_string(c_sigd)..". Please reconfigure route!") + end + c_ts = ildb.get_ts(c_ts_id) + + c_rseg = route[i] + c_lckp = {} + + itab(""..i.." Entry "..sigd_to_string(c_sigd).." -> Sec. "..c_ts.name.." -> Exit "..(c_rseg.next and sigd_to_string(c_rseg.next) or "END")) + + for pts, state in pairs(c_rseg.locks) do + + local pos = minetest.string_to_pos(pts) + itab(" Lock: "..pts.." -> "..state) + if not advtrains.is_passive(pos) then + itab("-!- No passive component at "..pts..". Please reconfigure route!") + end + end + -- advance + c_sigd = c_rseg.next + i = i + 1 + end + if c_sigd then + local e_tcbs = ildb.get_tcbs(c_sigd) + itab("Route end: "..sigd_to_string(c_sigd).." ("..(e_tcbs.signal_name or "-")..")") + else + itab("Route ends on dead-end") + end + + form = form.."textlist[0.5,2;7,4;rtelog;"..table.concat(tab, ",").."]" + + form = form.."button[0.5,6;2,1;back;<<< Back to signal]" + form = form.."button[3.5,6;2,1;aspect;Signal Aspect]" + form = form.."button[5.5,6;2,1;delete;Delete Route]" + + atdebug(route.ars) + form = form.."textarea[1,7.3;5.2,3;ars;ARS Rule List;"..ars_to_text(route.ars).."]" + form = form.."button[6,7.7;1,1;savears;Save]" + + minetest.show_formspec(pname, "at_il_routeedit_"..minetest.pos_to_string(sigd.p).."_"..sigd.s.."_"..routeid, form) + +end + + +minetest.register_on_player_receive_fields(function(player, formname, fields) + local pname = player:get_player_name() + if not minetest.check_player_privs(pname, {train_operator=true, interlocking=true}) then + return + end + + local pts, connids, routeids = string.match(formname, "^at_il_routeedit_([^_]+)_(%d)_(%d+)$") + local pos, connid, routeid + if pts then + pos = minetest.string_to_pos(pts) + connid = tonumber(connids) + routeid = tonumber(routeids) + if not connid or connid<1 or connid>2 then return end + if not routeid then return end + end + if pos and connid and routeid and not fields.quit then + local sigd = {p=pos, s=connid} + local tcbs = ildb.get_tcbs(sigd) + if not tcbs then return end + local route = tcbs.routes[routeid] + if not route then return end + + if fields.setname and fields.name then + route.name = fields.name + end + + if fields.aspect then + local suppasp = advtrains.interlocking.signal_get_supported_aspects(tcbs.signal) + + local callback = function(pname, asp) + route.aspect = asp + advtrains.interlocking.show_route_edit_form(pname, sigd, routeid) + end + + advtrains.interlocking.show_signal_aspect_selector(pname, suppasp, route.name, callback, rte.aspect) + return + 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) + table.remove(tcbs.routes, routeid) + advtrains.interlocking.show_signalling_form(sigd, pname) + end + + if fields.ars and fields.savears then + route.ars = text_to_ars(fields.ars) + atdebug(route.ars) + end + + if fields.back then + advtrains.interlocking.show_signalling_form(sigd, pname) + end + + end +end) diff --git a/advtrains_interlocking/tcb_ts_ui.lua b/advtrains_interlocking/tcb_ts_ui.lua index c149a44..5ebc0b2 100644 --- a/advtrains_interlocking/tcb_ts_ui.lua +++ b/advtrains_interlocking/tcb_ts_ui.lua @@ -568,7 +568,14 @@ function advtrains.interlocking.show_signalling_form(sigd, pname, sel_rte) if not tcbs.route_origin then local strtab = {} for idx, route in ipairs(tcbs.routes) do - strtab[#strtab+1] = minetest.formspec_escape(route.name) + local clr = "" + if route.ars then + clr = "#FF5555" + if route.ars.default then + clr = "#55FF55" + end + end + strtab[#strtab+1] = clr .. minetest.formspec_escape(route.name) end form = form.."label[0.5,2.5;Routes:]" form = form.."textlist[0.5,3;5,3;rtelist;"..table.concat(strtab, ",").."]" @@ -576,9 +583,7 @@ function advtrains.interlocking.show_signalling_form(sigd, pname, sel_rte) form = form.."button[0.5,6; 5,1;setroute;Set Route]" form = form.."button[0.5,7;2,1;dsproute;Show]" if hasprivs then - form = form.."button[2.5,7;1,1;delroute;Delete]" - form = form.."button[3.5,7;1,1;editroute;Rename]" - form = form.."button[4.5,7;1,1;asproute;Aspect]" + form = form.."button[3.5,7;2,1;editroute;Edit]" end end if hasprivs then @@ -657,26 +662,11 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) minetest.after(10, function() advtrains.interlocking.clear_visu_context("disp_"..t) end) end if fields.editroute and hasprivs then - local rte = tcbs.routes[sel_rte] - minetest.show_formspec(pname, formname.."_renroute_"..sel_rte, "field[name;Enter new route name;"..rte.name.."]") - return - end - if fields.asproute and hasprivs then - local rte = tcbs.routes[sel_rte] - local suppasp = advtrains.interlocking.signal_get_supported_aspects(tcbs.signal) - - local callback = function(pname, asp) - rte.aspect = asp - advtrains.interlocking.show_signalling_form(sigd, pname, sel_rte) - end - - advtrains.interlocking.show_signal_aspect_selector(pname, suppasp, rte.name, callback, rte.aspect) + advtrains.interlocking.show_route_edit_form(pname, sigd, sel_rte) + --local rte = tcbs.routes[sel_rte] + --minetest.show_formspec(pname, formname.."_renroute_"..sel_rte, "field[name;Enter new route name;"..rte.name.."]") return end - if fields.delroute and hasprivs then - table.remove(tcbs.routes, sel_rte) - sel_rte = nil - end end end -- cgit v1.2.3