aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorY. Wang <yw05@forksworld.de>2022-06-11 18:07:00 +0200
committerY. Wang <yw05@forksworld.de>2023-03-23 20:06:02 +0100
commit98c37108762c6d7c9f1d691b84f49bfa65b81b28 (patch)
tree32402fd5365d14470016562f16a5bc5f560eec87
parentd1a0d8f2654d6ee64c1a43de7958b1eadfaff6b0 (diff)
downloadadvtrains-98c37108762c6d7c9f1d691b84f49bfa65b81b28.tar.gz
advtrains-98c37108762c6d7c9f1d691b84f49bfa65b81b28.tar.bz2
advtrains-98c37108762c6d7c9f1d691b84f49bfa65b81b28.zip
Implement primitive distant signaling
-rw-r--r--advtrains/formspec.lua10
-rw-r--r--advtrains_interlocking/database.lua4
-rw-r--r--advtrains_interlocking/demosignals.lua6
-rw-r--r--advtrains_interlocking/distant.lua137
-rw-r--r--advtrains_interlocking/distant_ui.lua76
-rw-r--r--advtrains_interlocking/init.lua3
-rw-r--r--advtrains_interlocking/routesetting.lua21
-rw-r--r--advtrains_interlocking/signal_api.lua85
-rw-r--r--advtrains_interlocking/signal_aspect_accessors.lua127
-rw-r--r--advtrains_interlocking/signal_aspect_ui.lua6
-rw-r--r--advtrains_interlocking/signal_aspects.lua26
-rw-r--r--advtrains_interlocking/signal_main_ui.lua0
-rw-r--r--advtrains_interlocking/spec/basic_signalling_spec.lua87
-rw-r--r--advtrains_interlocking/spec/signal_api_spec.lua49
-rwxr-xr-xadvtrains_interlocking/tcb_ts_ui.lua8
15 files changed, 507 insertions, 138 deletions
diff --git a/advtrains/formspec.lua b/advtrains/formspec.lua
index aa5aa69..20dab59 100644
--- a/advtrains/formspec.lua
+++ b/advtrains/formspec.lua
@@ -9,6 +9,14 @@ local function make_list(entries)
return table.concat(t, ",")
end
+local function f_button(x, y, w, h, id, text)
+ return sformat("button[%f,%f;%f,%f;%s;%s]", x, y, w, h, id, text)
+end
+
+local function S_button(x, y, w, h, id, ...)
+ return f_button(x, y, w, h, id, attrans(...))
+end
+
local function f_button_exit(x, y, w, h, id, text)
return sformat("button_exit[%f,%f;%f,%f;%s;%s]", x, y, w, h, id, text)
end
@@ -54,6 +62,8 @@ local function f_tabheader(x, y, w, h, id, entries, sel, transparent, border)
end
return {
+ button = f_button,
+ S_button = S_button,
button_exit = f_button_exit,
S_button_exit = S_button_exit,
dropdown = f_dropdown,
diff --git a/advtrains_interlocking/database.lua b/advtrains_interlocking/database.lua
index efa5eb8..c5ae906 100644
--- a/advtrains_interlocking/database.lua
+++ b/advtrains_interlocking/database.lua
@@ -134,6 +134,9 @@ function ildb.load(data)
if data.supposed_aspects then
advtrains.interlocking.load_supposed_aspects(data.supposed_aspects)
end
+ if data.distant then
+ advtrains.distant.load(data.distant)
+ end
--COMPATIBILITY to Signal aspect format
-- TODO remove in time...
@@ -177,6 +180,7 @@ function ildb.save()
influence_points = influence_points,
npr_rails = advtrains.interlocking.npr_rails,
supposed_aspects = advtrains.interlocking.save_supposed_aspects(),
+ distant = advtrains.distant.save(),
}
end
diff --git a/advtrains_interlocking/demosignals.lua b/advtrains_interlocking/demosignals.lua
index 1c1b8b2..de6926a 100644
--- a/advtrains_interlocking/demosignals.lua
+++ b/advtrains_interlocking/demosignals.lua
@@ -50,7 +50,7 @@ minetest.register_node("advtrains_interlocking:ds_danger", {
},
on_rightclick = advtrains.interlocking.signal_rc_handler,
can_dig = advtrains.interlocking.signal_can_dig,
- after_dig_node = advtrains.interlocking.signal_after_dig,
+ after_destruct = advtrains.interlocking.signal_after_dig,
})
minetest.register_node("advtrains_interlocking:ds_free", {
description = "Demo signal at Free",
@@ -71,7 +71,7 @@ minetest.register_node("advtrains_interlocking:ds_free", {
},
on_rightclick = advtrains.interlocking.signal_rc_handler,
can_dig = advtrains.interlocking.signal_can_dig,
- after_dig_node = advtrains.interlocking.signal_after_dig,
+ after_destruct = advtrains.interlocking.signal_after_dig,
})
minetest.register_node("advtrains_interlocking:ds_slow", {
description = "Demo signal at Slow",
@@ -92,6 +92,6 @@ minetest.register_node("advtrains_interlocking:ds_slow", {
},
on_rightclick = advtrains.interlocking.signal_rc_handler,
can_dig = advtrains.interlocking.signal_can_dig,
- after_dig_node = advtrains.interlocking.signal_after_dig,
+ after_destruct = advtrains.interlocking.signal_after_dig,
})
diff --git a/advtrains_interlocking/distant.lua b/advtrains_interlocking/distant.lua
new file mode 100644
index 0000000..ffa9e08
--- /dev/null
+++ b/advtrains_interlocking/distant.lua
@@ -0,0 +1,137 @@
+local db_distant = {}
+local db_distant_of = {}
+
+local A = advtrains.interlocking.aspects
+local pts = advtrains.encode_pos
+local stp = advtrains.decode_pos
+
+local function db_load(x)
+ if type(x) ~= "table" then
+ return
+ end
+ db_distant = x.distant
+ db_distant_of = x.distant_of
+end
+
+local function db_save()
+ return {
+ distant = db_distant,
+ distant_of = db_distant_of,
+ }
+end
+
+local update_signal, update_main, update_dst
+
+local function unassign_dst(dst, force)
+ local pts_dst = pts(dst)
+ local main = db_distant_of[pts_dst]
+ db_distant_of[pts_dst] = nil
+ if main then
+ local pts_main = main[1]
+ local t = db_distant[pts_main]
+ if t then
+ t[pts_dst] = nil
+ end
+ end
+ if not force then
+ update_dst(dst)
+ end
+end
+
+local function unassign_main(main, force)
+ local pts_main = pts(main)
+ local t = db_distant[pts_main]
+ if not t then
+ return
+ end
+ for pts_dst in pairs(t) do
+ local realmain = db_distant_of[pts_dst]
+ if realmain and realmain[1] == pts_main then
+ db_distant_of[pts_dst] = nil
+ if not force then
+ local dst = stp(pts_dst)
+ update_dst(dst)
+ end
+ end
+ end
+ db_distant[pts_main] = nil
+end
+
+local function unassign_all(pos, force)
+ unassign_main(pos)
+ unassign_dst(pos, force)
+end
+
+local function assign(main, dst, by)
+ local pts_main = pts(main)
+ local pts_dst = pts(dst)
+ local t = db_distant[pts_main]
+ if not t then
+ t = {}
+ db_distant[pts_main] = t
+ end
+ if not by then
+ by = "manual"
+ end
+ unassign_dst(dst, true)
+ t[pts_dst] = by
+ db_distant_of[pts_dst] = {pts_main, by}
+ update_dst(dst)
+end
+
+local function pre_occupy(dst, by)
+ local pts_dst = pts(dst)
+ unassign_dst(dst)
+ db_distant_of[pts_dst] = {nil, by}
+end
+
+local function get_distant(main)
+ local pts_main = pts(main)
+ return db_distant[pts_main] or {}
+end
+
+local function get_main(dst)
+ local pts_dst = pts(dst)
+ local main = db_distant_of[pts_dst]
+ if not main then
+ return
+ end
+ if main[1] then
+ return stp(main[1]), unpack(main, 2)
+ else
+ return unpack(main)
+ end
+end
+
+update_main = function(main)
+ local pts_main = pts(main)
+ local t = get_distant(main)
+ for pts_dst in pairs(t) do
+ local dst = stp(pts_dst)
+ advtrains.interlocking.signal_readjust_aspect(dst)
+ end
+end
+
+update_dst = function(dst)
+ advtrains.interlocking.signal_readjust_aspect(dst)
+end
+
+update_signal = function(pos)
+ update_main(pos)
+ update_dst(pos)
+end
+
+advtrains.distant = {
+ load = db_load,
+ save = db_save,
+ assign = assign,
+ unassign_dst = unassign_dst,
+ unassign_main = unassign_main,
+ unassign_all = unassign_all,
+ get_distant = get_distant,
+ get_dst = get_distant,
+ get_main = get_main,
+ update_main = update_main,
+ update_dst = update_dst,
+ update_signal = update_signal,
+}
diff --git a/advtrains_interlocking/distant_ui.lua b/advtrains_interlocking/distant_ui.lua
new file mode 100644
index 0000000..4ec2255
--- /dev/null
+++ b/advtrains_interlocking/distant_ui.lua
@@ -0,0 +1,76 @@
+local F = advtrains.formspec
+local D = advtrains.distant
+local I = advtrains.interlocking
+
+function advtrains.interlocking.show_distant_signal_form(pos, pname)
+ local form = {"size[7,7]"}
+ form[#form+1] = advtrains.interlocking.make_signal_formspec_tabheader(pname, pos, 7, 3)
+ local main, set_by = D.get_main(pos)
+ if main then
+ local pts_main = minetest.pos_to_string(main)
+ form[#form+1] = F.S_label(0.5, 0.5, "This signal is a distant signal of @1.", pts_main)
+ if set_by == "manual" then
+ form[#form+1] = F.S_label(0.5, 1, "The assignment is made manually.")
+ elseif set_by == "routesetting" then
+ form[#form+1] = F.S_label(0.5, 1, "The assignment is made by the routesetting system.")
+ end
+ else
+ form[#form+1] = F.S_label(0.5, 0.5, "This signal is not assigned to a main signal.")
+ form[#form+1] = F.S_label(0.5, 1, "The distant aspect of the signal is not used.")
+ end
+ if set_by ~= nil then
+ form[#form+1] = F.S_button_exit(0.5, 1.5, 3, 1, "unassign_dst", "Unassign")
+ form[#form+1] = F.S_button_exit(3.5, 1.5, 3, 1, "assign_dst", "Reassign")
+ else
+ form[#form+1] = F.S_button_exit(0.5, 1.5, 6, 1, "assign_dst", "Assign")
+ end
+ minetest.show_formspec(pname, "advtrains:distant_" .. minetest.pos_to_string(pos), table.concat(form))
+end
+
+local signal_pos = {}
+local function init_signal_assignment(pname, pos)
+ if not minetest.check_player_privs(pname, "interlocking") then
+ minetest.chat_send_player(pname, attrans("This operation is not allowed without the @1 privilege.", "interlocking"))
+ return
+ end
+ signal_pos[pname] = pos
+ minetest.chat_send_player(pname, attrans("Please punch the signal to use as the main signal."))
+end
+
+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
+ local spos = signal_pos[pname]
+ if not spos then
+ return
+ end
+ signal_pos[pname] = nil
+ local is_signal = minetest.get_item_group(node.name, "advtrains_signal") >= 2
+ if not is_signal then
+ minetest.chat_send_player(pname, attrans("Incompatible signal."))
+ return
+ end
+ minetest.chat_send_player(pname, attrans("Successfully assigned signal."))
+ D.assign(pos, spos, "manual")
+end)
+
+minetest.register_on_player_receive_fields(function(player, formname, fields)
+ local pname = player:get_player_name()
+ local pos = minetest.string_to_pos(string.match(formname, "^advtrains:distant_(.+)$") or "")
+ if not pos then
+ return
+ end
+ if not minetest.check_player_privs(pname, "interlocking") then
+ return
+ end
+ if advtrains.interlocking.handle_signal_formspec_tabheader_fields(pname, fields) then
+ return true
+ end
+ if fields.unassign_dst then
+ D.unassign_dst(pos)
+ elseif fields.assign_dst then
+ init_signal_assignment(pname, pos)
+ end
+end)
diff --git a/advtrains_interlocking/init.lua b/advtrains_interlocking/init.lua
index d0b75a8..908d998 100644
--- a/advtrains_interlocking/init.lua
+++ b/advtrains_interlocking/init.lua
@@ -15,6 +15,9 @@ local modpath = minetest.get_modpath(minetest.get_current_modname()) .. DIR_DELI
advtrains.interlocking.aspects = dofile(modpath.."signal_aspects.lua")
dofile(modpath.."database.lua")
+dofile(modpath.."distant.lua")
+dofile(modpath.."distant_ui.lua")
+dofile(modpath.."signal_aspect_accessors.lua")
dofile(modpath.."signal_api.lua")
dofile(modpath.."signal_aspect_ui.lua")
dofile(modpath.."demosignals.lua")
diff --git a/advtrains_interlocking/routesetting.lua b/advtrains_interlocking/routesetting.lua
index 67efaea..f1b4455 100644
--- a/advtrains_interlocking/routesetting.lua
+++ b/advtrains_interlocking/routesetting.lua
@@ -45,6 +45,7 @@ function ilrs.set_route(signal, route, try)
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 signals = {}
while c_sigd and i<=#route do
c_tcbs = ildb.get_tcbs(c_sigd)
if not c_tcbs then
@@ -115,6 +116,7 @@ function ilrs.set_route(signal, route, try)
c_tcbs.aspect = route.aspect or advtrains.interlocking.GENERIC_FREE
c_tcbs.route_origin = signal
advtrains.interlocking.update_signal_aspect(c_tcbs)
+ signals[#signals+1] = c_tcbs.signal
end
end
-- advance
@@ -122,6 +124,25 @@ function ilrs.set_route(signal, route, try)
c_sigd = c_rseg.next
i = i + 1
end
+
+ -- Distant signaling
+ local lastsig = nil
+ if c_sigd then
+ local e_tcbs = ildb.get_tcbs(c_sigd)
+ local pos = e_tcbs and e_tcbs.signal
+ if pos then
+ lastsig = pos
+ end
+ end
+ for i = #signals, 1, -1 do
+ if lastsig then
+ local pos = signals[i]
+ local _, assigned_by = advtrains.distant.get_main(pos)
+ if assigned_by ~= "manual" then
+ advtrains.distant.assign(lastsig, signals[i], "routesetting")
+ end
+ end
+ end
return true
end
diff --git a/advtrains_interlocking/signal_api.lua b/advtrains_interlocking/signal_api.lua
index 5b3baf8..1fd4e34 100644
--- a/advtrains_interlocking/signal_api.lua
+++ b/advtrains_interlocking/signal_api.lua
@@ -167,7 +167,6 @@ This function will query get_aspect to retrieve the new aspect.
local DANGER = {
main = 0,
- dst = false,
shunt = false,
}
advtrains.interlocking.DANGER = DANGER
@@ -178,8 +177,6 @@ advtrains.interlocking.GENERIC_FREE = {
dst = false,
}
-local supposed_aspects = {}
-
local function convert_aspect_if_necessary(asp)
if type(asp.main) == "table" then
local newasp = {}
@@ -200,24 +197,7 @@ local function convert_aspect_if_necessary(asp)
end
return asp
end
-
-function advtrains.interlocking.load_supposed_aspects(tbl)
- if tbl then
- supposed_aspects = tbl
- end
-end
-
-function advtrains.interlocking.save_supposed_aspects()
- return supposed_aspects
-end
-
-local function set_supposed_aspect(pos, asp)
- supposed_aspects[advtrains.roundfloorpts(pos)] = asp
-end
-
-local function get_supposed_aspect(pos)
- return supposed_aspects[advtrains.roundfloorpts(pos)]
-end
+advtrains.interlocking.signal_convert_aspect_if_necessary = convert_aspect_if_necessary
function advtrains.interlocking.update_signal_aspect(tcbs)
if tcbs.signal then
@@ -233,27 +213,8 @@ end
function advtrains.interlocking.signal_after_dig(pos)
-- clear influence point
advtrains.interlocking.db.clear_ip_by_signalpos(pos)
- set_supposed_aspect(pos, nil)
-end
-
-function advtrains.interlocking.signal_set_aspect(pos, asp)
- asp = convert_aspect_if_necessary(asp)
- local node=advtrains.ndb.get_node(pos)
- local ndef=minetest.registered_nodes[node.name]
- if ndef and ndef.advtrains and ndef.advtrains.set_aspect then
- local oldasp = advtrains.interlocking.signal_get_aspect(pos) or DANGER
- local suppasp = advtrains.interlocking.signal_get_supported_aspects(pos) or {}
- local newasp = asp
- if suppasp.type == 2 then
- asp = advtrains.interlocking.aspects.type1_to_type2main(asp, suppasp.group)
- end
- set_supposed_aspect(pos, newasp)
- ndef.advtrains.set_aspect(pos, node, asp)
- local aspect_changed = advtrains.interlocking.aspects.not_equalp(oldasp, newasp)
- if aspect_changed then
- advtrains.interlocking.signal_on_aspect_changed(pos)
- end
- end
+ advtrains.interlocking.signal_clear_aspect(pos)
+ advtrains.distant.unassign_all(pos, true)
end
-- should be called when aspect has changed on this signal.
@@ -312,46 +273,6 @@ function advtrains.interlocking.signal_get_supposed_aspect(pos)
return DANGER;
end
--- Returns the actual aspect of the signal at position, as returned by the nodedef.
--- returns nil when there's no signal at the position
-function advtrains.interlocking.signal_get_real_aspect(pos)
- local node=advtrains.ndb.get_node(pos)
- local ndef=minetest.registered_nodes[node.name]
- if ndef and ndef.advtrains and ndef.advtrains.get_aspect then
- local asp = ndef.advtrains.get_aspect(pos, node)
- local suppasp = advtrains.interlocking.signal_get_supported_aspects(pos) or {}
- if suppasp.type == 2 then
- asp = advtrains.interlocking.aspects.type2main_to_type1(suppasp.group, asp)
- end
- if not asp then asp = DANGER end
- asp = convert_aspect_if_necessary(asp)
- return asp
- end
- return nil
-end
-
--- Returns the signal aspect as reported in the suppasp table.
-function advtrains.interlocking.signal_get_aspect(pos)
- local asp = get_supposed_aspect(pos)
- if not asp then
- asp = advtrains.interlocking.signal_get_real_aspect(pos)
- set_supposed_aspect(pos, asp)
- end
- return asp
-end
-
--- Returns the "supported_aspects" of the signal at position, as returned by the nodedef.
--- returns nil when there's no signal at the position
-function advtrains.interlocking.signal_get_supported_aspects(pos)
- local node=advtrains.ndb.get_node(pos)
- local ndef=minetest.registered_nodes[node.name]
- if ndef and ndef.advtrains and ndef.advtrains.supported_aspects then
- local asp = ndef.advtrains.supported_aspects
- return asp
- end
- return nil
-end
-
local players_assign_ip = {}
local function ipmarker(ipos, connid)
diff --git a/advtrains_interlocking/signal_aspect_accessors.lua b/advtrains_interlocking/signal_aspect_accessors.lua
new file mode 100644
index 0000000..02a03ea
--- /dev/null
+++ b/advtrains_interlocking/signal_aspect_accessors.lua
@@ -0,0 +1,127 @@
+local A = advtrains.interlocking.aspects
+local D = advtrains.distant
+local I = advtrains.interlocking
+local N = advtrains.ndb
+local pts = advtrains.roundfloorpts
+
+local get_aspect
+
+local supposed_aspects = {}
+
+function I.load_supposed_aspects(tbl)
+ if tbl then
+ supposed_aspects = tbl
+ end
+end
+
+function I.save_supposed_aspects()
+ return supposed_aspects
+end
+
+local function get_supposed_aspect(pos)
+ return supposed_aspects[pts(pos)]
+end
+
+local function set_supposed_aspect(pos, asp)
+ supposed_aspects[pts(pos)] = asp
+end
+
+local function get_ndef(pos)
+ local node = N.get_node(pos)
+ return minetest.registered_nodes[node.name] or {}
+end
+
+local function get_supported_aspects(pos)
+ local ndef = get_ndef(pos)
+ if ndef.advtrains and ndef.advtrains.supported_aspects then
+ return ndef.advtrains.supported_aspects
+ end
+ return nil
+end
+
+local function adjust_aspect(pos, asp)
+ asp = table.copy(I.signal_convert_aspect_if_necessary(asp))
+
+ local mainpos = D.get_main(pos)
+ local nxtasp
+ if asp.main ~= 0 and mainpos then
+ nxtasp = get_aspect(mainpos)
+ asp.dst = nxtasp.main
+ else
+ asp.dst = nil
+ end
+
+ local suppasp = get_supported_aspects(pos)
+ if not suppasp then
+ return asp, asp
+ end
+ local stype = suppasp.type
+ if stype == 2 then
+ local group = suppasp.group
+ local name
+ if asp.main ~= 0 and nxtasp and nxtasp.type2group == group and nxtasp.type2name then
+ name = A.get_type2_dst(group, nxtasp.type2name)
+ else
+ name = A.type1_to_type2main(asp, group)
+ end
+ asp.type2group = group
+ asp.type2name = name
+ return asp, name
+ end
+ asp.type2name = nil
+ asp.type2group = nil
+ return asp, asp
+end
+
+local function get_real_aspect(pos)
+ local ndef = get_ndef(pos)
+ if ndef.advtrains and ndef.advtrains.get_aspect then
+ local asp = ndef.advtrains.get_aspect(pos, node) or I.DANGER
+ local suppasp = get_supported_aspects(pos)
+ if suppasp.type == 2 then
+ asp = A.type2main_to_type1(suppasp.group, asp)
+ end
+ return adjust_aspect(pos, asp)
+ end
+ return nil
+end
+
+get_aspect = function(pos)
+ local asp = get_supposed_aspect(pos)
+ if not asp then
+ asp = get_real_aspect(pos)
+ set_supposed_aspect(pos, asp)
+ end
+ return asp
+end
+
+local function set_aspect(pos, asp)
+ local node = N.get_node(pos)
+ local ndef = minetest.registered_nodes[node.name]
+ if ndef and ndef.advtrains and ndef.advtrains.set_aspect then
+ local oldasp = I.signal_get_aspect(pos) or DANGER
+ local newasp, aspval = adjust_aspect(pos, asp)
+ set_supposed_aspect(pos, newasp)
+ ndef.advtrains.set_aspect(pos, node, aspval)
+ local aspect_changed = A.not_equalp(oldasp, newasp)
+ if aspect_changed then
+ I.signal_on_aspect_changed(pos)
+ D.update_main(pos)
+ end
+ end
+end
+
+local function clear_aspect(pos)
+ set_supposed_aspect(pos, nil)
+end
+
+local function readjust_aspect(pos)
+ set_aspect(pos, get_aspect(pos))
+end
+
+I.signal_get_supported_aspects = get_supported_aspects
+I.signal_get_real_aspect = get_real_aspect
+I.signal_get_aspect = get_aspect
+I.signal_set_aspect = set_aspect
+I.signal_clear_aspect = clear_aspect
+I.signal_readjust_aspect = readjust_aspect
diff --git a/advtrains_interlocking/signal_aspect_ui.lua b/advtrains_interlocking/signal_aspect_ui.lua
index 4b41187..30b5165 100644
--- a/advtrains_interlocking/signal_aspect_ui.lua
+++ b/advtrains_interlocking/signal_aspect_ui.lua
@@ -43,7 +43,7 @@ local function describe_supported_aspects_t1(suppasp, isasp)
local entries = {}
local selid = 1
for idx, spv in ipairs(suppasp.main) do
- if isasp and spv == isasp.main then
+ if isasp and spv == (isasp.main or false) then
selid = idx
end
entries[idx] = describe_t1_main_aspect(spv)
@@ -67,7 +67,7 @@ local function describe_supported_aspects_t1(suppasp, isasp)
entries = {}
selid = 1
for idx, spv in ipairs(suppasp.dst) do
- if isasp and spv == isasp.dst then
+ if isasp and spv == (isasp.dst or false) then
selid = idx
end
entries[idx] = describe_t1_distant_aspect(spv)
@@ -102,6 +102,8 @@ local function handle_signal_formspec_tabheader_fields(pname, fields)
advtrains.interlocking.show_signal_form(pos, node, pname)
elseif n == 2 then
advtrains.interlocking.show_ip_form(pos, pname)
+ elseif n == 3 then
+ advtrains.interlocking.show_distant_signal_form(pos, pname)
end
return true
end
diff --git a/advtrains_interlocking/signal_aspects.lua b/advtrains_interlocking/signal_aspects.lua
index eebb4ba..2866ae1 100644
--- a/advtrains_interlocking/signal_aspects.lua
+++ b/advtrains_interlocking/signal_aspects.lua
@@ -44,6 +44,27 @@ local function get_type2_definition(name)
return type2defs[name]
end
+local function get_type2_danger(group)
+ local def = type2defs[group]
+ if not def then
+ return nil
+ end
+ local main = def.main
+ return main[#main]
+end
+
+local function get_type2_dst(group, name)
+ local def = type2defs[group]
+ if not def then
+ return nil
+ end
+ local aspidx = name
+ if type(name) ~= "number" then
+ aspidx = def.main[name] or 1
+ end
+ return def.main[math.max(1, aspidx-1)].name
+end
+
local function type2main_to_type1(name, asp)
local def = type2defs[name]
if not def then
@@ -53,7 +74,7 @@ local function type2main_to_type1(name, asp)
if type(asp) == "number" then
aspidx = asp
else
- aspidx = def.main[asp]
+ aspidx = def.main[asp] or 2
end
local asptbl = def.main[aspidx]
if not asptbl then
@@ -62,11 +83,13 @@ local function type2main_to_type1(name, asp)
if type(asp) == "number" then
asp = asptbl.name
end
+ local dst = def.main[math.min(#def.main, aspidx+1)].main
local t = {
main = asptbl.main,
type2name = asp,
type2group = name,
+ dst = dst,
}
if aspidx > 1 and aspidx < #asptbl then
t.dst = asptbl[aspidx+1].main
@@ -116,6 +139,7 @@ end
return {
register_type2 = register_type2,
get_type2_definition = get_type2_definition,
+ get_type2_dst = get_type2_dst,
type2main_to_type1 = type2main_to_type1,
type1_to_type2main = type1_to_type2main,
equalp = equalp,
diff --git a/advtrains_interlocking/signal_main_ui.lua b/advtrains_interlocking/signal_main_ui.lua
deleted file mode 100644
index e69de29..0000000
--- a/advtrains_interlocking/signal_main_ui.lua
+++ /dev/null
diff --git a/advtrains_interlocking/spec/basic_signalling_spec.lua b/advtrains_interlocking/spec/basic_signalling_spec.lua
new file mode 100644
index 0000000..0b79972
--- /dev/null
+++ b/advtrains_interlocking/spec/basic_signalling_spec.lua
@@ -0,0 +1,87 @@
+--[[
+This file tests a large part of the signaling system, as a lot of tests for the
+signaling system tend to overlap for various parts of the system.
+]]
+
+require("mineunit")
+mineunit("core")
+
+_G.advtrains = {
+ interlocking = {
+ aspects = fixture("../../signal_aspects"),
+ },
+ ndb = {
+ get_node = minetest.get_node,
+ swap_node = minetest.swap_node,
+ }
+}
+
+fixture("advtrains_helpers")
+fixture("../../database")
+sourcefile("distant")
+sourcefile("signal_api")
+sourcefile("signal_aspect_accessors")
+fixture("../../demosignals")
+
+local D = advtrains.distant
+local I = advtrains.interlocking
+
+local stub_aspect_t1 = {
+ free = {main = -1},
+ slow = {main = 6},
+ danger = {main = 0, shunt = false},
+}
+local stub_pos_t1 = {}
+for i = 1, 3 do
+ stub_pos_t1[i] = {x = 1, y = 0, z = i}
+end
+
+world.layout {
+ {stub_pos_t1[1], "advtrains_interlocking:ds_danger"},
+ {stub_pos_t1[2], "advtrains_interlocking:ds_slow"},
+ {stub_pos_t1[3], "advtrains_interlocking:ds_free"},
+}
+
+describe("API for supposed signal aspects", function()
+ it("should load and save data properly", function()
+ local tbl = {_foo = true}
+ I.load_supposed_aspects(tbl)
+ assert.same(tbl, I.save_supposed_aspects())
+ end)
+ it("should set and get type 1 signals properly", function ()
+ local pos = stub_pos_t1[2]
+ local asp = stub_aspect_t1.slow
+ local newasp = { main = math.random(1,5) }
+ assert.same(asp, I.signal_get_aspect(pos))
+ I.signal_set_aspect(pos, newasp)
+ assert.same(newasp, I.signal_get_aspect(pos))
+ assert.same(asp, I.signal_get_real_aspect(pos))
+ I.signal_set_aspect(pos, asp)
+ end)
+end)
+
+describe("Distant signaling", function()
+ it("should assign distant signals and set the distant aspect correspondingly", function()
+ for i = 1, 2 do
+ D.assign(stub_pos_t1[i], stub_pos_t1[i+1])
+ end
+ assert.same(stub_aspect_t1.danger, I.signal_get_aspect(stub_pos_t1[1]))
+ assert.same({main = 6, dst = 0}, I.signal_get_aspect(stub_pos_t1[2]))
+ assert.same({main = -1, dst = 6}, I.signal_get_aspect(stub_pos_t1[3]))
+ end)
+ it("should report assignments properly", function()
+ assert.same({stub_pos_t1[1], "manual"}, {D.get_main(stub_pos_t1[2])})
+ assert.same({[advtrains.encode_pos(stub_pos_t1[3])] = "manual"}, D.get_dst(stub_pos_t1[2]))
+ end)
+ it("should update distant aspects automatically", function()
+ I.signal_set_aspect(stub_pos_t1[2], {main = 2, dst = -1})
+ assert.same({main = 2, dst = 0}, I.signal_get_aspect(stub_pos_t1[2]))
+ assert.same({main = -1, dst = 2}, I.signal_get_aspect(stub_pos_t1[3]))
+ end)
+ it("should unassign signals when one is removed", function()
+ world.set_node(stub_pos_t1[2], "air")
+ assert.same({}, D.get_dst(stub_pos_t1[1]))
+ assert.same({}, {D.get_main(stub_pos_t1[3])})
+ assert.same(stub_aspect_t1.free, I.signal_get_aspect(stub_pos_t1[3]))
+ end)
+end)
diff --git a/advtrains_interlocking/spec/signal_api_spec.lua b/advtrains_interlocking/spec/signal_api_spec.lua
deleted file mode 100644
index cd7a1d1..0000000
--- a/advtrains_interlocking/spec/signal_api_spec.lua
+++ /dev/null
@@ -1,49 +0,0 @@
-require("mineunit")
-
-mineunit("core")
-
-_G.advtrains = {
- interlocking = {
- aspects = fixture("../../signal_aspects"),
- },
- ndb = {
- get_node = minetest.get_node,
- }
-}
-
-fixture("advtrains_helpers")
-fixture("../../database")
-sourcefile("signal_api")
-
-local stub_aspect_t1 = { main = math.random() }
-local stub_pos_t1 = {x = 1, y = 0, z = 1}
-
-minetest.register_node(":stubsignal_t1", {
- advtrains = {
- supported_aspects = {},
- get_aspect = function () return stub_aspect_t1 end,
- set_aspect = function () end,
- },
- groups = { advtrains_signal = 2 },
-})
-
-world.layout {
- {stub_pos_t1, "stubsignal_t1"},
-}
-
-describe("API for supposed signal aspects", function()
- it("should load and save data properly", function()
- local tbl = {_foo = true}
- advtrains.interlocking.load_supposed_aspects(tbl)
- assert.same(tbl, advtrains.interlocking.save_supposed_aspects())
- end)
- it("should set and get type 1 signals properly", function ()
- local pos = stub_pos_t1
- local asp = stub_aspect_t1
- local newasp = { dst = math.random() }
- assert.same(asp, advtrains.interlocking.signal_get_aspect(pos))
- advtrains.interlocking.signal_set_aspect(pos, newasp)
- assert.same(newasp, advtrains.interlocking.signal_get_aspect(pos))
- assert.same(asp, advtrains.interlocking.signal_get_real_aspect(pos))
- end)
-end)
diff --git a/advtrains_interlocking/tcb_ts_ui.lua b/advtrains_interlocking/tcb_ts_ui.lua
index b3b8221..9f88296 100755
--- a/advtrains_interlocking/tcb_ts_ui.lua
+++ b/advtrains_interlocking/tcb_ts_ui.lua
@@ -14,6 +14,7 @@ local lntrans = { "A", "B" }
local function sigd_to_string(sigd)
return minetest.pos_to_string(sigd.p).." / "..lntrans[sigd.s]
end
+advtrains.interlocking.sigd_to_string = sigd_to_string
minetest.register_node("advtrains_interlocking:tcb_node", {
drawtype = "mesh",
@@ -608,7 +609,7 @@ function advtrains.interlocking.show_signalling_form(sigd, pname, sel_rte, calle
if not tcbs.signal_name then tcbs.signal_name = "Signal at "..minetest.pos_to_string(sigd.p) end
if not tcbs.routes then tcbs.routes = {} end
- local form = "size[7,9.75]label[0.5,0.5;Signal at "..minetest.pos_to_string(sigd.p).."]"
+ local form = "size[7,10.25]label[0.5,0.5;Signal at "..minetest.pos_to_string(sigd.p).."]"
form = form .. advtrains.interlocking.make_signal_formspec_tabheader(pname, tcbs.signal, 7, 1)
form = form.."field[0.8,1.5;5.2,1;name;Signal name;"..minetest.formspec_escape(tcbs.signal_name).."]"
form = form.."button[5.5,1.2;1,1;setname;Set]"
@@ -670,6 +671,7 @@ function advtrains.interlocking.show_signalling_form(sigd, pname, sel_rte, calle
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..string.format("checkbox[0.5,8.75;ars;Automatic routesetting;%s]", not tcbs.ars_disabled)
+ form = form..string.format("checkbox[0.5,9.25;dst;Distant signalling;%s]", not tcbs.nodst)
end
elseif sigd_equal(tcbs.route_origin, sigd) then
-- something has gone wrong: tcbs.routeset should have been set...
@@ -796,6 +798,10 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
if fields.ars then
tcbs.ars_disabled = not minetest.is_yes(fields.ars)
end
+
+ if fields.dst then
+ tcbs.nodst = not minetest.is_yes(fields.dst)
+ end
if fields.auto then
tcbs.route_auto = true