TCB Xlinking added, to make nonconnected crossings possible
This commit is contained in:
parent
6a5540878f
commit
a14eb7fe73
|
@ -297,6 +297,7 @@ end
|
|||
function advtrains.get_adjacent_rail(this_posnr, this_conns_p, conn_idx, drives_on)
|
||||
local this_pos = advtrains.round_vector_floor_y(this_posnr)
|
||||
local this_conns = this_conns_p
|
||||
local _
|
||||
if not this_conns then
|
||||
_, this_conns = advtrains.get_rail_info_at(this_pos)
|
||||
end
|
||||
|
@ -583,6 +584,7 @@ function advtrains.get_track_iterator(initial_pos, initial_connid, limit, follow
|
|||
table.insert(ti.branches, {pos = initial_pos, connid = coni, limit=limit})
|
||||
end
|
||||
end
|
||||
ti.limit = limit -- safeguard if someone adds a branch before calling anything
|
||||
setmetatable(ti, {__index=trackiter_mt})
|
||||
return ti
|
||||
end
|
||||
|
|
|
@ -163,6 +163,9 @@ TCB data structure
|
|||
-- This is the "A" side of the TCB
|
||||
[1] = { -- Variant: with adjacent TCs.
|
||||
ts_id = <id> -- ID of the assigned track section
|
||||
xlink = <other sigd> -- If two sections of track are not physically joined but must function as one TS (e.g. knights move crossing), a bidirectional link can be added with exactly one other TCB.
|
||||
-- TS search will behave as if these two TCBs were physically connected.
|
||||
|
||||
signal = <pos> -- optional: when set, routes can be set from this tcb/direction and signal
|
||||
-- aspect will be set accordingly.
|
||||
routeset = <index in routes> -- Route set from this signal. This is the entry that is cleared once
|
||||
|
@ -249,17 +252,26 @@ function ildb.get_all_ts()
|
|||
return track_sections
|
||||
end
|
||||
|
||||
-- Checks the consistency of the track section at the given position
|
||||
-- This method attempts to autorepair track sections if they are inconsistent
|
||||
-- Checks the consistency of the track section at the given position, attempts to autorepair track sections if they are inconsistent
|
||||
-- There are 2 operation modes:
|
||||
-- 1: pos is NOT a TCB, tcb_connid MUST be nil
|
||||
-- 2: pos is a TCB, tcb_connid MUST be given
|
||||
-- @param pos: the position to start from
|
||||
-- @param tcb_connid: If provided node is a TCB,
|
||||
-- Returns:
|
||||
-- ts_id - the track section that was found
|
||||
-- nil - No track section exists
|
||||
function ildb.check_and_repair_ts_at_pos(pos)
|
||||
atdebug("check_and_repair_ts_at_pos", pos)
|
||||
function ildb.check_and_repair_ts_at_pos(pos, tcb_connid)
|
||||
atdebug("check_and_repair_ts_at_pos", pos, tcb_connid)
|
||||
-- check prereqs
|
||||
if ildb.get_tcb(pos) then
|
||||
if not tcb_connid then error("check_and_repair_ts_at_pos: Startpoint is TCB, must provide tcb_connid!") end
|
||||
else
|
||||
if tcb_connid then error("check_and_repair_ts_at_pos: Startpoint is not TCB, must not provide tcb_connid!") end
|
||||
end
|
||||
-- STEP 1: Ensure that only one section is at this place
|
||||
-- get all TCBs adjacent to this
|
||||
local all_tcbs = ildb.get_all_tcbs_adjacent(pos, nil)
|
||||
local all_tcbs = ildb.get_all_tcbs_adjacent(pos, tcb_connid)
|
||||
local first_ts = true
|
||||
local ts_id
|
||||
for _,sigd in ipairs(all_tcbs) do
|
||||
|
@ -321,41 +333,63 @@ end
|
|||
-- This function does not trigger a repair.
|
||||
-- @param inipos: the initial position
|
||||
-- @param inidir: the initial direction, or nil to search in all directions
|
||||
-- @param per_track_callback: A callback function called with signature (pos, connid, bconnid) for every track encountered
|
||||
-- Returns: a list of sigd's describing the TCBs found (sigd's point inward):
|
||||
-- {p=<pos>, s=<side>, tcbs=<ref to tcbs table>}
|
||||
function ildb.get_all_tcbs_adjacent(inipos, inidir)
|
||||
function ildb.get_all_tcbs_adjacent(inipos, inidir, per_track_callback)
|
||||
atdebug("get_all_tcbs_adjacent: inipos",inipos,"inidir",inidir,"")
|
||||
local found_sigd = {}
|
||||
local ti = advtrains.get_track_iterator(inipos, inidir, TS_MAX_SCAN, true)
|
||||
-- if initial start is TCBS and has xlink, need to add that to the TI
|
||||
local inisi = {p=inipos, s=inidir};
|
||||
local initcbs = ildb.get_tcbs(inisi)
|
||||
if initcbs then
|
||||
ildb.validate_tcb_xlink(inisi, true)
|
||||
if initcbs.xlink then
|
||||
-- adding the tcb will happen when this branch is retrieved again using ti:next_branch()
|
||||
atdebug("get_all_tcbs_adjacent: Putting xlink Branch for initial node",initcbs.xlink)
|
||||
ti:add_branch(initcbs.xlink.p, initcbs.xlink.s)
|
||||
end
|
||||
end
|
||||
local pos, connid, bconnid, tcb
|
||||
while ti:has_next_branch() do
|
||||
pos, connid = ti:next_branch()
|
||||
--atdebug("get_all_tcbs_adjacent: BRANCH: ",pos, connid)
|
||||
bconnid = nil
|
||||
is_branch_start = true
|
||||
repeat
|
||||
-- callback
|
||||
if per_track_callback then
|
||||
per_track_callback(pos, connid, bconnid)
|
||||
end
|
||||
tcb = ildb.get_tcb(pos)
|
||||
if tcb then
|
||||
local using_connid = bconnid
|
||||
-- found a tcb
|
||||
if not bconnid then
|
||||
-- A branch start point cannot be a TCB, as that would imply that it was a turnout/crossing (illegal)
|
||||
-- Only exception where this can happen is if the start point is a TCB, then we'd need to add the forward side of it to our list
|
||||
if pos.x==inipos.x and pos.y==inipos.y and pos.z==inipos.z then
|
||||
-- Note "connid" instead of "bconnid"
|
||||
atdebug("get_all_tcbs_adjacent: Found Startpoint TCB: ",pos, connid, "ts=", tcb[connid].ts_id)
|
||||
insert_sigd_if_not_present(found_sigd, {p=pos, s=connid, tcbs=tcb[connid]})
|
||||
else
|
||||
-- this may not happend
|
||||
error("Found TCB at TrackIterator new branch which is not the start point, this is illegal! pos="..minetest.pos_to_string(pos))
|
||||
end
|
||||
|
||||
else
|
||||
-- add the sigd of this tcb and a reference to the tcb table in it
|
||||
atdebug("get_all_tcbs_adjacent: Found TCB: ",pos, bconnid, "ts=", tcb[bconnid].ts_id)
|
||||
insert_sigd_if_not_present(found_sigd, {p=pos, s=bconnid, tcbs=tcb[bconnid]})
|
||||
if is_branch_start then
|
||||
-- A branch cannot be a TCB, as that would imply that it was a turnout/crossing (illegal)
|
||||
-- UNLESS: (a) it is the start point or (b) it was added via xlink
|
||||
-- Then the correct conn to use is connid (pointing forward)
|
||||
atdebug("get_all_tcbs_adjacent: Inserting TCB at branch start",pos, connid)
|
||||
using_connid = connid
|
||||
end
|
||||
-- add the sigd of this tcb and a reference to the tcb table in it
|
||||
atdebug("get_all_tcbs_adjacent: Found TCB: ",pos, using_connid, "ts=", tcb[using_connid].ts_id)
|
||||
local si = {p=pos, s=using_connid, tcbs=tcb[using_connid]}
|
||||
-- if xlink exists, add it now (only if we are not in branch start)
|
||||
ildb.validate_tcb_xlink(si, true)
|
||||
if not is_branch_start and si.tcbs.xlink then
|
||||
-- adding the tcb will happen when this branch is retrieved again using ti:next_branch()
|
||||
atdebug("get_all_tcbs_adjacent: Putting xlink Branch",si.tcbs.xlink)
|
||||
ti:add_branch(si.tcbs.xlink.p, si.tcbs.xlink.s)
|
||||
end
|
||||
insert_sigd_if_not_present(found_sigd, si)
|
||||
if not is_branch_start then
|
||||
break
|
||||
end
|
||||
end
|
||||
pos, connid, bconnid = ti:next_track()
|
||||
is_branch_start = false
|
||||
--atdebug("get_all_tcbs_adjacent: TRACK: ",pos, connid, bconnid)
|
||||
until not pos
|
||||
end
|
||||
|
@ -464,7 +498,7 @@ function ildb.tcbs_ensure_ts_ref_exists(sigd)
|
|||
local did_insert = insert_sigd_if_not_present(ts.tc_breaks, {p=sigd.p, s=sigd.s})
|
||||
if did_insert then
|
||||
atdebug("tcbs_ensure_ts_ref_exists(",sigd,"): TCBS was missing reference in TS",tcbs.ts_id)
|
||||
ildb.update_ts_cache(ts_id)
|
||||
ildb.update_ts_cache(tcbs.ts_id)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -515,7 +549,7 @@ function ildb.update_ts_cache(ts_id)
|
|||
end
|
||||
|
||||
local lntrans = { "A", "B" }
|
||||
local function sigd_to_string(sigd)
|
||||
function ildb.sigd_to_string(sigd)
|
||||
return minetest.pos_to_string(sigd.p).." / "..lntrans[sigd.s]
|
||||
end
|
||||
|
||||
|
@ -546,12 +580,98 @@ function ildb.remove_tcb_at(pos)
|
|||
if old_tcb[2].ts_id then
|
||||
ildb.purge_ts_tcb_refs(old_tcb[2].ts_id)
|
||||
end
|
||||
-- update xlink partners
|
||||
if old_tcb[1].xlink then
|
||||
ildb.validate_tcb_xlink(old_tcb[1].xlink)
|
||||
end
|
||||
if old_tcb[2].xlink then
|
||||
ildb.validate_tcb_xlink(old_tcb[2].xlink)
|
||||
end
|
||||
advtrains.interlocking.remove_tcb_marker(pos)
|
||||
-- If needed, merge the track sections here
|
||||
ildb.check_and_repair_ts_at_pos(pos)
|
||||
return true
|
||||
end
|
||||
|
||||
-- Xlink: Connecting not-physically-connected sections handling
|
||||
|
||||
-- Ensures that the xlink of this tcbs is bidirectional
|
||||
function ildb.validate_tcb_xlink(sigd, suppress_repairs)
|
||||
local tcbs = sigd.tcbs or ildb.get_tcbs(sigd)
|
||||
local osigd = tcbs.xlink
|
||||
if not osigd then return end
|
||||
local otcbs = ildb.get_tcbs(tcbs.xlink)
|
||||
if not otcbs then
|
||||
atdebug("validate_tcb_xlink",sigd,": Link partner ",osigd,"orphaned")
|
||||
tcbs.xlink = nil
|
||||
if not suppress_repairs then
|
||||
ildb.check_and_repair_ts_at_pos(sigd.p, sigd.s)
|
||||
end
|
||||
return
|
||||
end
|
||||
if otcbs.xlink then
|
||||
if not vector.equals(otcbs.xlink.p, sigd.p) or otcbs.xlink.s~=sigd.s then
|
||||
atdebug("validate_tcb_xlink",sigd,": Link partner ",osigd,"backreferencing to someone else (namely",otcbs.xlink,") clearing it")
|
||||
tcbs.xlink = nil
|
||||
if not suppress_repairs then
|
||||
ildb.check_and_repair_ts_at_pos(sigd.p, sigd.s)
|
||||
atdebug("validate_tcb_xlink",sigd,": Link partner ",osigd," was backreferencing to someone else, now updating that")
|
||||
ildb.validate_tcb_xlink(osigd)
|
||||
end
|
||||
end
|
||||
else
|
||||
atdebug("validate_tcb_xlink",sigd,": Link partner ",osigd,"wasn't backreferencing, clearing it")
|
||||
tcbs.xlink = nil
|
||||
if not suppress_repairs then
|
||||
ildb.check_and_repair_ts_at_pos(sigd.p, sigd.s)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function ildb.add_tcb_xlink(sigd1, sigd2)
|
||||
atdebug("add_tcb_xlink",sigd1, sigd2)
|
||||
local tcbs1 = sigd1.tcbs or ildb.get_tcbs(sigd1)
|
||||
local tcbs2 = sigd2.tcbs or ildb.get_tcbs(sigd2)
|
||||
if vector.equals(sigd1.p, sigd2.p) then
|
||||
atdebug("add_tcb_xlink Cannot xlink with same TCB")
|
||||
return
|
||||
end
|
||||
if not tcbs1 or not tcbs2 then
|
||||
atdebug("add_tcb_xlink TCBS doesnt exist")
|
||||
return
|
||||
end
|
||||
if tcbs1.xlink or tcbs2.xlink then
|
||||
atdebug("add_tcb_xlink One already linked")
|
||||
return
|
||||
end
|
||||
-- apply link
|
||||
tcbs1.xlink = {p=sigd2.p, s=sigd2.s}
|
||||
tcbs2.xlink = {p=sigd1.p, s=sigd1.s}
|
||||
-- update section. It should be sufficient to call update only once because the TCBs are linked anyway now
|
||||
ildb.check_and_repair_ts_at_pos(sigd1.p, sigd1.s)
|
||||
end
|
||||
|
||||
function ildb.remove_tcb_xlink(sigd)
|
||||
atdebug("remove_tcb_xlink",sigd)
|
||||
-- Validate first. If Xlink is gone already then, nothing to do
|
||||
ildb.validate_tcb_xlink(sigd)
|
||||
-- Checking all of these already done by validate
|
||||
local tcbs = sigd.tcbs or ildb.get_tcbs(sigd)
|
||||
local osigd = tcbs.xlink
|
||||
if not osigd then
|
||||
-- validate already cleared us
|
||||
atdebug("remove_tcb_xlink: Already gone by validate")
|
||||
return
|
||||
end
|
||||
local otcbs = ildb.get_tcbs(tcbs.xlink)
|
||||
-- clear it
|
||||
otcbs.xlink = nil
|
||||
tcbs.xlink = nil
|
||||
-- Update section for ourself and the other one
|
||||
ildb.check_and_repair_ts_at_pos(sigd.p, sigd.s)
|
||||
ildb.check_and_repair_ts_at_pos(osigd.p, osigd.s)
|
||||
end
|
||||
|
||||
function ildb.create_ts_from_tcbs(sigd)
|
||||
atdebug("create_ts_from_tcbs",sigd)
|
||||
local all_tcbs = ildb.get_all_tcbs_adjacent(sigd.p, sigd.s)
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
local players_assign_tcb = {}
|
||||
local players_assign_signal = {}
|
||||
local players_assign_xlink = {}
|
||||
local players_link_ts = {}
|
||||
|
||||
local ildb = advtrains.interlocking.db
|
||||
|
@ -166,6 +167,7 @@ minetest.register_on_punchnode(function(pos, node, player, pointed_thing)
|
|||
meta:set_string("tcb_pos", minetest.pos_to_string(pos))
|
||||
meta:set_string("infotext", "TCB assigned to "..minetest.pos_to_string(pos))
|
||||
minetest.chat_send_player(pname, "Configuring TCB: Successfully configured TCB")
|
||||
advtrains.interlocking.show_tcb_marker(pos)
|
||||
else
|
||||
minetest.chat_send_player(pname, "Configuring TCB: This is not a normal two-connection rail! Aborted.")
|
||||
end
|
||||
|
@ -213,9 +215,14 @@ end)
|
|||
|
||||
-- TCB Form
|
||||
|
||||
local function mktcbformspec(tcbs, btnpref, offset, pname)
|
||||
local function mktcbformspec(pos, side, tcbs, offset, pname)
|
||||
local form = ""
|
||||
local btnpref = side==1 and "A" or "B"
|
||||
local ts
|
||||
-- ensure that mapping and xlink are up to date
|
||||
ildb.tcbs_ensure_ts_ref_exists({p=pos, s=side, tcbs=tcbs})
|
||||
ildb.validate_tcb_xlink({p=pos, s=side, tcbs=tcbs})
|
||||
-- Note: repair operations may have been triggered by this
|
||||
if tcbs.ts_id then
|
||||
ts = ildb.get_ts(tcbs.ts_id)
|
||||
end
|
||||
|
@ -227,6 +234,19 @@ local function mktcbformspec(tcbs, btnpref, offset, pname)
|
|||
form = form.."label[0.5,"..offset..";Side "..btnpref..": ".."End of interlocking]"
|
||||
form = form.."button[0.5,"..(offset+0.5)..";5,1;"..btnpref.."_makeil;Create Interlocked Track Section]"
|
||||
end
|
||||
-- xlink
|
||||
if tcbs.xlink then
|
||||
form = form.."label[0.5,"..(offset+1.5)..";Link:"..ildb.sigd_to_string(tcbs.xlink).."]"
|
||||
form = form.."button[4.5,"..(offset+1.5)..";1,1;"..btnpref.."_xlinkdel;X]"
|
||||
else
|
||||
if players_assign_xlink[pname] then
|
||||
form = form.."button[0.5,"..(offset+1.5)..";4,1;"..btnpref.."_xlinklink;Link "..ildb.sigd_to_string(players_assign_xlink[pname]).."]"
|
||||
form = form.."button[4.5,"..(offset+1.5)..";1,1;"..btnpref.."_xlinkabrt;X]"
|
||||
else
|
||||
form = form.."label[0.5,"..(offset+1.5)..";No Link]"
|
||||
form = form.."button[4.5,"..(offset+1.5)..";1,1;"..btnpref.."_xlinkadd;+]"
|
||||
end
|
||||
end
|
||||
if tcbs.signal then
|
||||
form = form.."button[0.5,"..(offset+2.5)..";5,1;"..btnpref.."_sigdia;Signalling]"
|
||||
else
|
||||
|
@ -245,8 +265,8 @@ function advtrains.interlocking.show_tcb_form(pos, pname)
|
|||
if not tcb then return end
|
||||
|
||||
local form = "size[6,9] label[0.5,0.5;Track Circuit Break Configuration]"
|
||||
form = form .. mktcbformspec(tcb[1], "A", 1, pname)
|
||||
form = form .. mktcbformspec(tcb[2], "B", 5, pname)
|
||||
form = form .. mktcbformspec(pos, 1, tcb[1], 1, pname)
|
||||
form = form .. mktcbformspec(pos, 2, tcb[2], 5, pname)
|
||||
|
||||
minetest.show_formspec(pname, "at_il_tcbconfig_"..minetest.pos_to_string(pos), form)
|
||||
advtrains.interlocking.show_tcb_marker(pos)
|
||||
|
@ -276,6 +296,10 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
|
|||
local f_makeil = {fields.A_makeil, fields.B_makeil}
|
||||
local f_asnsig = {fields.A_asnsig, fields.B_asnsig}
|
||||
local f_sigdia = {fields.A_sigdia, fields.B_sigdia}
|
||||
local f_xlinkadd = {fields.A_xlinkadd, fields.B_xlinkadd}
|
||||
local f_xlinkdel = {fields.A_xlinkdel, fields.B_xlinkdel}
|
||||
local f_xlinklink = {fields.A_xlinklink, fields.B_xlinklink}
|
||||
local f_xlinkabrt = {fields.A_xlinkabrt, fields.B_xlinkabrt}
|
||||
|
||||
for connid=1,2 do
|
||||
local tcbs = tcb[connid]
|
||||
|
@ -291,6 +315,28 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
|
|||
end
|
||||
end
|
||||
end
|
||||
if tcbs.xlink then
|
||||
if f_xlinkdel[connid] then
|
||||
ildb.remove_tcb_xlink({p=pos, s=connid})
|
||||
end
|
||||
else
|
||||
local osigd = players_assign_xlink[pname]
|
||||
if osigd then
|
||||
if f_xlinklink[connid] then
|
||||
ildb.add_tcb_xlink({p=pos, s=connid}, osigd)
|
||||
players_assign_xlink[pname] = nil
|
||||
elseif f_xlinkabrt[connid] then
|
||||
players_assign_xlink[pname] = nil
|
||||
end
|
||||
else
|
||||
if f_xlinkadd[connid] then
|
||||
players_assign_xlink[pname] = {p=pos, s=connid}
|
||||
minetest.chat_send_player(pname, "TCB Link: Select linked TCB now!")
|
||||
minetest.close_formspec(pname, formname)
|
||||
return -- to not reopen form
|
||||
end
|
||||
end
|
||||
end
|
||||
if f_asnsig[connid] and not tcbs.signal then
|
||||
minetest.chat_send_player(pname, "Configuring TCB: Please punch the signal to assign.")
|
||||
players_assign_signal[pname] = {p=pos, s=connid}
|
||||
|
@ -496,36 +542,25 @@ function advtrains.interlocking.remove_tcb_marker(pos)
|
|||
markerent[pts] = nil
|
||||
end
|
||||
|
||||
local ts_showparticles_callback = function(pos, connid, bconnid)
|
||||
minetest.add_particle({
|
||||
pos = pos,
|
||||
velocity = {x=0, y=0, z=0},
|
||||
acceleration = {x=0, y=0, z=0},
|
||||
expirationtime = 10,
|
||||
size = 7,
|
||||
vertical = true,
|
||||
texture = "at_il_ts_highlight_particle.png",
|
||||
glow = 6,
|
||||
})
|
||||
end
|
||||
|
||||
-- Spawns particles to highlight the clicked track section
|
||||
-- TODO: Adapt behavior to not dumb-walk anymore
|
||||
function advtrains.interlocking.highlight_track_section(pos)
|
||||
local ti = advtrains.get_track_iterator(pos, nil, 100, true)
|
||||
local pos, connid, bconnid, tcb
|
||||
while ti:has_next_branch() do
|
||||
pos, connid = ti:next_branch()
|
||||
--atdebug("highlight_track_section: BRANCH: ",pos, connid)
|
||||
bconnid = nil
|
||||
repeat
|
||||
-- spawn particles
|
||||
minetest.add_particle({
|
||||
pos = pos,
|
||||
velocity = {x=0, y=0, z=0},
|
||||
acceleration = {x=0, y=0, z=0},
|
||||
expirationtime = 10,
|
||||
size = 7,
|
||||
vertical = true,
|
||||
texture = "at_il_ts_highlight_particle.png",
|
||||
glow = 6,
|
||||
})
|
||||
-- abort if TCB is found
|
||||
tcb = ildb.get_tcb(pos)
|
||||
if tcb then
|
||||
advtrains.interlocking.show_tcb_marker(pos)
|
||||
break
|
||||
end
|
||||
pos, connid, bconnid = ti:next_track()
|
||||
--atdebug("highlight_track_section: TRACK: ",pos, connid, bconnid)
|
||||
until not pos
|
||||
local all_tcbs = ildb.get_all_tcbs_adjacent(pos, nil, ts_showparticles_callback)
|
||||
for _,sigd in ipairs(all_tcbs) do
|
||||
advtrains.interlocking.show_tcb_marker(sigd.p)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -26,7 +26,11 @@ local function node_right_click(pos, pname)
|
|||
local node_ok, conns, rail_y=advtrains.get_rail_info_at(pos)
|
||||
if not node_ok then
|
||||
minetest.chat_send_player(pname, "Node is not a track!")
|
||||
return
|
||||
return
|
||||
end
|
||||
if advtrains.interlocking.db.get_tcb(pos) then
|
||||
advtrains.interlocking.show_tcb_form(pos, pname)
|
||||
return
|
||||
end
|
||||
|
||||
local ts_id = advtrains.interlocking.db.check_and_repair_ts_at_pos(pos)
|
||||
|
@ -41,7 +45,12 @@ local function node_left_click(pos, pname)
|
|||
local node_ok, conns, rail_y=advtrains.get_rail_info_at(pos)
|
||||
if not node_ok then
|
||||
minetest.chat_send_player(pname, "Node is not a track!")
|
||||
return
|
||||
return
|
||||
end
|
||||
|
||||
if advtrains.interlocking.db.get_tcb(pos) then
|
||||
advtrains.interlocking.show_tcb_marker(pos)
|
||||
return
|
||||
end
|
||||
|
||||
local ts_id = advtrains.interlocking.db.check_and_repair_ts_at_pos(pos)
|
||||
|
|
Loading…
Reference in New Issue