From dcdd3ea702494e9e5bfeba96a72999f35aa2c91a Mon Sep 17 00:00:00 2001 From: ywang Date: Sun, 30 May 2021 12:16:09 +0200 Subject: round speed limit downward if needed; add basic distant signal implementation --- advtrains_interlocking/database.lua | 2 + advtrains_interlocking/distant_signals.lua | 83 ++++++++++++++++++++++++++++++ advtrains_interlocking/init.lua | 1 + advtrains_interlocking/routesetting.lua | 24 +++++++-- advtrains_interlocking/tcb_ts_ui.lua | 1 + advtrains_signals_ks/init.lua | 15 +++--- 6 files changed, 116 insertions(+), 10 deletions(-) create mode 100644 advtrains_interlocking/distant_signals.lua diff --git a/advtrains_interlocking/database.lua b/advtrains_interlocking/database.lua index a35d446..ee21db9 100644 --- a/advtrains_interlocking/database.lua +++ b/advtrains_interlocking/database.lua @@ -195,6 +195,8 @@ TCB data structure signal_name = -- The human-readable name of the signal, only for documenting purposes routes = { } -- a collection of routes from this signal route_auto = -- When set, we will automatically re-set the route (designated by routeset) + distant = { ... } -- a collection of sigd that points to a side of a TCB with a distant signal for this current signal. + distant_of = { , } -- the reverse of the above field, along with the index of the entry in the list (for easier lookup) }, -- This is the "B" side of the TCB [2] = { -- Variant: end of track-circuited area (initial state of TC) diff --git a/advtrains_interlocking/distant_signals.lua b/advtrains_interlocking/distant_signals.lua new file mode 100644 index 0000000..0da1c10 --- /dev/null +++ b/advtrains_interlocking/distant_signals.lua @@ -0,0 +1,83 @@ +local interlocking = advtrains.interlocking +local ildb = advtrains.interlocking.db + +local function update_distant(tcbs) + if not (tcbs and tcbs.signal) then return end + if not tcbs.aspect then tcbs.aspect = table.copy(interlocking.DANGER) end + local asp = tcbs.aspect + if tcbs.distant_of then + asp.dst = (ildb.get_tcbs(tcbs.distant_of[1]).aspect or interlocking.DANGER).main + end + interlocking.update_signal_aspect(tcbs) + if tcbs.distant then + local dst = tcbs.distant + for i = 1, #dst do + local s = ildb.get_tcbs(dst[i]) + if not s.aspect then s.aspect = table.copy(interlocking.DANGER) end + s.aspect.dst = asp.main + interlocking.update_signal_aspect(s) + end + end +end + +local function unassign_distant(dsts) + if not dsts then return end + local dof = dsts.distant_of + if not dof then return end + if dsts.signal and dsts.aspect then + dsts.aspect.dst = nil + interlocking.update_signal_aspect(dsts) + end + local sigd, idx = dof[1], dof[2] + local tcbs = ildb.get_tcbs(sigd) + local dst = tcbs.distant + dsts.distant_of = nil + if idx == #dst then + dst[#dst] = nil + else + local ent = dst[#dst] + dst[idx] = ent + dst[#dst] = nil + local repl = ildb.get_tcbs(ent) + repl.distant_of[2] = idx + end +end + +local function assign_distant(sigd, dstd) + if not sigd then return end + if not dstd then return end + local tcbs = ildb.get_tcbs(sigd) + local dsts = ildb.get_tcbs(dstd) + unassign_distant(dsts) + if not (tcbs.signal and dsts.signal) then return end + local dst = tcbs.distant + if not dst then + dst = {} + tcbs.distant = dst + end + local newidx = #dst+1 + dsts.distant_of = {sigd, newidx} + dst[newidx] = dstd + update_distant(dsts) +end + +local function remove_distant(tcbs) + if not tcbs then return end + if tcbs.distant_of then + unassign_distant(tcbs) + end + if tcbs.distant then + local dst = tcbs.distant + for i = #dst, 1, -1 do + local s = ildb.get_tcbs(dst[i]) + unassign_distant(s) + end + end +end + +interlocking.distant = { + assign = assign_distant, + unassign = unassign_distant, + remove = remove_distant, + update = update_distant, +} diff --git a/advtrains_interlocking/init.lua b/advtrains_interlocking/init.lua index a2f5882..cfbb8e5 100644 --- a/advtrains_interlocking/init.lua +++ b/advtrains_interlocking/init.lua @@ -16,6 +16,7 @@ dofile(modpath.."database.lua") dofile(modpath.."signal_api.lua") dofile(modpath.."demosignals.lua") dofile(modpath.."train_sections.lua") +dofile(modpath.."distant_signals.lua") dofile(modpath.."route_prog.lua") dofile(modpath.."routesetting.lua") dofile(modpath.."tcb_ts_ui.lua") diff --git a/advtrains_interlocking/routesetting.lua b/advtrains_interlocking/routesetting.lua index 67efaea..d801608 100644 --- a/advtrains_interlocking/routesetting.lua +++ b/advtrains_interlocking/routesetting.lua @@ -44,7 +44,7 @@ function ilrs.set_route(signal, route, try) 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 + local c_tcbs, c_ts_id, c_ts, c_rseg, c_lckp, p_ssigd while c_sigd and i<=#route do c_tcbs = ildb.get_tcbs(c_sigd) if not c_tcbs then @@ -112,9 +112,16 @@ function ilrs.set_route(signal, route, try) } if c_tcbs.signal then c_tcbs.route_committed = true - c_tcbs.aspect = route.aspect or advtrains.interlocking.GENERIC_FREE + local asp = route.aspect or advtrains.interlocking.GENERIC_FREE + asp.dst = nil + c_tcbs.aspect = asp c_tcbs.route_origin = signal - advtrains.interlocking.update_signal_aspect(c_tcbs) + advtrains.interlocking.distant.update(c_tcbs) + -- Update the previous distant signal + if p_ssigd then + advtrains.interlocking.distant.assign(c_sigd, p_ssigd) + end + p_ssigd = c_sigd end end -- advance @@ -122,6 +129,17 @@ function ilrs.set_route(signal, route, try) c_sigd = c_rseg.next i = i + 1 end + + if c_sigd and p_ssigd then + local e_tcbs = ildb.get_tcbs(c_sigd) + if e_tcbs.signal then + if p_stcb then + p_stcb.aspect.dst = (e_tcbs.aspect or advtrains.interlocking.DANGER).main + advtrains.interlocking.update_signal_aspect(p_stcb) + end + end + advtrains.interlocking.distant.assign(c_sigd, p_ssigd) + end return true end diff --git a/advtrains_interlocking/tcb_ts_ui.lua b/advtrains_interlocking/tcb_ts_ui.lua index 34fbf7f..2425bf2 100755 --- a/advtrains_interlocking/tcb_ts_ui.lua +++ b/advtrains_interlocking/tcb_ts_ui.lua @@ -778,6 +778,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) ildb.set_sigd_for_signal(signal_pos, nil) tcbs.signal = nil tcbs.aspect = nil + advtrains.interlocking.distant.remove(tcbs) minetest.close_formspec(pname, formname) minetest.chat_send_player(pname, "Signal has been unassigned. Name and routes are kept for reuse.") return diff --git a/advtrains_signals_ks/init.lua b/advtrains_signals_ks/init.lua index a1f056c..3a2f4d0 100755 --- a/advtrains_signals_ks/init.lua +++ b/advtrains_signals_ks/init.lua @@ -4,15 +4,17 @@ -- Note that the group value of advtrains_signal is 2, which means "step 2 of signal capabilities" -- advtrains_signal=1 is meant for signals that do not implement set_aspect. -local supported_speed_limits = { - [4] = true, [6] = true, [8] = true, [12] = true, [16] = true -} +local function asp_to_zs3type(asp) + local n = tonumber(asp) + if not n or n < 4 then return "off" end + if n < 8 then return 2*math.floor(n/2) end + return math.min(16,4*math.floor(n/4)) +end local function setzs3(msp, lim, rot) local pos = {x = msp.x, y = msp.y+1, z = msp.z} local node = advtrains.ndb.get_node(pos) - local asp = lim - if not asp or not supported_speed_limits[lim] then asp = "off" end + local asp = asp_to_zs3type(lim) if node.name:find("^advtrains_signals_ks:zs3_") then advtrains.ndb.swap_node(pos, {name="advtrains_signals_ks:zs3_"..asp.."_"..rot, param2 = node.param2}) end @@ -31,8 +33,7 @@ end local function setzs3v(msp, lim, rot) local pos = {x = msp.x, y = msp.y-1, z = msp.z} local node = advtrains.ndb.get_node(pos) - local asp = lim - if not asp or not supported_speed_limits[lim] then asp = "off" end + local asp = asp_to_zs3type(lim) if node.name:find("^advtrains_signals_ks:zs3v_") then advtrains.ndb.swap_node(pos, {name="advtrains_signals_ks:zs3v_"..asp.."_"..rot, param2 = node.param2}) end -- cgit v1.2.3