From 44a8cef1d5f2433502f5982f1d57410f49bb3afc Mon Sep 17 00:00:00 2001 From: orwell Date: Mon, 3 Jun 2024 23:38:12 +0200 Subject: set_aspect: Flexibility, set aspect either via name or allow to fully specify table (for advanced signals) --- advtrains_interlocking/signal_api.lua | 96 +++++++++++++---------------- advtrains_interlocking/signal_aspect_ui.lua | 16 ++--- advtrains_signals_ks/init.lua | 1 + advtrains_signals_muc_ubahn/init.lua | 2 +- 4 files changed, 53 insertions(+), 62 deletions(-) diff --git a/advtrains_interlocking/signal_api.lua b/advtrains_interlocking/signal_api.lua index 6f52816..a300ab1 100644 --- a/advtrains_interlocking/signal_api.lua +++ b/advtrains_interlocking/signal_api.lua @@ -6,15 +6,12 @@ local signal = {} signal.MASP_HALT = { name = "_halt", - speed = 0, halt = true, - remote = nil, } -signal.MASP_FREE = { +signal.MASP_DEFAULT = { name = "_default", - speed = -1, - remote = nil, + default = true, } signal.ASPI_HALT = { @@ -85,17 +82,15 @@ ndef.advtrains = { } -- This list is mainly for the selection dialog. Order of entries determines list order in the dropdown. -- Some fields have special meaning: - -- name: A unique key to identify the main aspect. Only this key is saved, but APIs always receive the whole table + -- name: A unique key to identify the main aspect. Might be required by some code. -- description: Text shown in UI dropdown - -- speed: a number. When present, a speed field is shown in the UI next to the dropdown (prefilled with the value). - -- When user selects a different speed there, this different speed replaces the value in the table whenever the main_aspect is applied. -- Node can set any other fields at its discretion. They are not touched. - -- Note: On first call advtrains automatically inserts into the ndef.advtrains table a main_aspects_lookup hashtable - -- Note: Pure distant signals (that cannot show halt) should NOT have a main_aspects table + -- Note: Pure distant signals (that cannot show halt) should NOT have a main_aspects table. + -- For these signals no main aspect selection UI is shown and they cannot be startpoint of a route apply_aspect = function(pos, node, main_aspect, rem_aspect, rem_aspinfo) -- set the node to show the desired aspect -- called by advtrains when this signal's aspect group or the remote signal's aspect changes - -- main_aspect is never nil, but can be one of the special aspects { name = "_halt", halt = true } or { name = "_default" } + -- main_aspect is never nil, but can be one of the special aspects { halt = true } or { default = true } -- MAY return the aspect_info. If it returns nil then get_aspect_info will be queried at a later point. get_aspect_info(pos, main_aspect) -- Returns the aspect info table (main, shunt, dst etc.) @@ -133,7 +128,9 @@ Signals that are possible start and end points for a route must satisfy: -- Database -- Signal Aspect store -- Stores for each signal the main aspect and other info, like the assigned remote signal --- [signal encodePos] = { name = "proceed", [speed = 12], [remote = encodedPos] } +-- [signal encodePos] = { main = , [remote = encodedPos] } +-- main is a string: "named aspect" is looked up in the main_aspects table of the ndef +-- main is a table: this table directly is the main aspect (used for advanced signals with additional lights/indicators) signal.aspects = {} -- Distant signal notification. Records for each signal the distant signals that refer to it @@ -167,7 +164,12 @@ end -- - Calling apply_aspect() in the signal's node definition to make the signal show the aspect -- - Calling apply_aspect() again whenever the remote signal changes its aspect -- - Notifying this signal's distant signals about changes to this signal (unless skip_dst_notify is specified) -function signal.set_aspect(pos, main_asp_name, main_asp_speed, rem_pos, skip_dst_notify) +-- main_asp: either a string (==name in ndef.advtrains.main_aspects) or the main aspect table directly (for advanced signals) +function signal.set_aspect(pos, main_asp, rem_pos, skip_dst_notify) + -- safeguard for the two integrated aspects (these two must be passed as string key) + if type(main_asp)=="table" and (main_asp.name=="_default" or main_asp.name=="_halt") then + error("MASP_HALT and MASP_DEFAULT must be passed via string keys _halt or _default, not as tables!") + end local main_pts = advtrains.encode_pos(pos) local old_tbl = signal.aspects[main_pts] local old_remote = old_tbl and old_tbl.remote @@ -179,7 +181,7 @@ function signal.set_aspect(pos, main_asp_name, main_asp_speed, rem_pos, skip_dst signal.distant_refs[old_remote][main_pts] = nil end - signal.aspects[main_pts] = { name = main_asp_name, speed = main_asp_speed, remote = new_remote } + signal.aspects[main_pts] = { main = main_asp, remote = new_remote } -- apply aspect on main signal, this also checks new_remote signal.reapply_aspect(main_pts) @@ -266,49 +268,43 @@ end local function cache_mainaspects(ndefat) ndefat.main_aspects_lookup = {} - for _,ma in ipairs(ndefat.main_aspects) do + for _,ma in ipairs(ndefat.main_aspects) do ndefat.main_aspects_lookup[ma.name] = ma - end + end + ndefat.main_aspects_lookup[signal.MASP_HALT.name] = signal.MASP_HALT.name -- halt is always defined + ndefat.main_aspects_lookup[signal.MASP_DEFAULT.name] = ndefat.main_aspects[1] -- default is the first one end + +-- gets the main aspect. resolves named aspects to aspect table on demand function signal.get_aspect_internal(pos, aspt) - atdebug("get_aspect_internal",pos,aspt) - -- look aspect in nodedef + -- look up node and nodedef local node = advtrains.ndb.get_node_or_nil(pos) local ndef = node and minetest.registered_nodes[node.name] if not aspt then -- oh, no main aspect, nevermind return signal.MASP_HALT, nil, node, ndef end - local ndefat = ndef and ndef.advtrains - if ndefat and ndefat.apply_aspect then - -- only if signal defines main aspect and its set in aspt - if ndefat.main_aspects and aspt.name then + local ndefat = ndef.advtrains or {} + local masp = aspt.main or signal.MASP_HALT + + if type(masp) == "string" then + if masp=="_halt" then + masp = signal.MASP_HALT + elseif masp=="_default" and not ndefat.main_aspects then + -- case is fine, distant only signal + masp = signal.MASP_DEFAULT + else + assert(ndefat.main_aspects, "With named aspects, node needs advtrains.main_aspects table!") + -- resolve the main aspect from the mainaspects table if not ndefat.main_aspects_lookup then cache_mainaspects(ndefat) end - local masp = ndefat.main_aspects_lookup[aspt.name] - -- special handling for the default free aspect ("_default") - if aspt.name == "_default" then - masp = ndefat.main_aspects[1] - end - if not masp then - atwarn(pos,"invalid main aspect",aspt.name,"valid are",ndefat.main_aspects_lookup) - return signal.MASP_HALT, aspt.remote, node, ndef - end - -- if speed, then apply speed - if masp.speed and aspt.speed then - masp = table.copy(masp) - masp.speed = aspt.speed - end - return masp, aspt.remote, node, ndef - elseif aspt.name then - -- Distant-only signal, still supports kind of default aspect - return { name = aspt.name, speed = aspt.speed }, aspt.remote, node, ndef + masp = ndefat.main_aspects_lookup[aspt.main] or signal.MASP_DEFAULT end end - -- invalid node or no main aspect, return default halt aspect for masp - return signal.MASP_HALT, aspt.remote, node, ndef + -- return whatever the main aspect is + return masp, aspt.remote, node, ndef end -- For the signal at pos, get the "aspect info" table. This contains the speed signalling information at this location @@ -336,10 +332,6 @@ function signal.reapply_aspect(pts) local aspt = signal.aspects[pts] atdebug("reapply_aspect",advtrains.decode_pos(pts),"aspt",aspt) local pos = advtrains.decode_pos(pts) - if not aspt then - signal.notify_trains(pos) - return -- oop, nothing to do - end -- resolve mainaspect table by name local masp, remote, node, ndef = signal.get_aspect_internal(pos, aspt) -- if we have remote, resolve remote @@ -352,13 +344,11 @@ function signal.reapply_aspect(pts) signal.distant_refs[remote][pts] = true local rem_aspt = signal.aspects[remote] atdebug("resolving remote",advtrains.decode_pos(remote),"aspt",rem_aspt) - if rem_aspt and rem_aspt.name then - local rem_pos = advtrains.decode_pos(remote) - rem_masp, _, _, rem_ndef = signal.get_aspect_internal(rem_pos, rem_aspt) - if rem_masp then - if rem_ndef.advtrains and rem_ndef.advtrains.get_aspect_info then - rem_aspi = rem_ndef.advtrains.get_aspect_info(rem_pos, rem_masp) - end + local rem_pos = advtrains.decode_pos(remote) + rem_masp, _, _, rem_ndef = signal.get_aspect_internal(rem_pos, rem_aspt) + if rem_masp then + if rem_ndef.advtrains and rem_ndef.advtrains.get_aspect_info then + rem_aspi = rem_ndef.advtrains.get_aspect_info(rem_pos, rem_masp) end end end diff --git a/advtrains_interlocking/signal_aspect_ui.lua b/advtrains_interlocking/signal_aspect_ui.lua index 785e6d4..5ec4c50 100644 --- a/advtrains_interlocking/signal_aspect_ui.lua +++ b/advtrains_interlocking/signal_aspect_ui.lua @@ -121,11 +121,11 @@ function advtrains.interlocking.handle_ip_sa_formspec_fields(pname, pos, fields) new_ma = ndef.advtrains.main_aspects[idx - 1] end end - if new_ma and (new_ma.name ~= ma.name or new_ma.speed ~= ma.speed) then - advtrains.interlocking.signal.set_aspect(pos, new_ma.name, new_ma.speed, rpos) - elseif not new_ma then + if new_ma then + advtrains.interlocking.signal.set_aspect(pos, new_ma.name, rpos) + else -- reset everything - advtrains.interlocking.signal.set_aspect(pos, nil, nil, nil) + advtrains.interlocking.signal.clear_aspect(pos) end end @@ -140,7 +140,7 @@ function advtrains.interlocking.handle_ip_sa_formspec_fields(pname, pos, fields) advtrains.interlocking.init_distant_assign(pos, pname) return elseif fields.sa_undistant then - advtrains.interlocking.signal.set_aspect(pos, ma.name, ma.speed, nil) + advtrains.interlocking.signal.set_aspect(pos, ma.name, nil) return end -- show the form again unless one of the buttons was clicked @@ -226,10 +226,10 @@ minetest.register_on_punchnode(function(pos, node, player, pointed_thing) local nrpos if advtrains.interlocking.signal.get_signal_cap_level(pos) > 1 then nrpos = pos - if not ma then -- make sure that dst is never set without a main aspect (esp. for pure distant signal case) - ma = { name = "_default" } + 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, ma.speed, nrpos) + advtrains.interlocking.signal.set_aspect(signalpos, ma.name, nrpos) end players_assign_distant[pname] = nil end diff --git a/advtrains_signals_ks/init.lua b/advtrains_signals_ks/init.lua index 52f8c58..46b9971 100755 --- a/advtrains_signals_ks/init.lua +++ b/advtrains_signals_ks/init.lua @@ -53,6 +53,7 @@ local applyaspectf_main = function(rot) if main_aspect.halt then -- halt aspect, set red and don't do anything further advtrains.ndb.swap_node(pos, {name="advtrains_signals_ks:hs_danger_"..rot, param2 = node.param2}) + setzs3(pos, "off", rot) setzs3v(pos, nil, rot) return end diff --git a/advtrains_signals_muc_ubahn/init.lua b/advtrains_signals_muc_ubahn/init.lua index baf5d82..4088ba6 100755 --- a/advtrains_signals_muc_ubahn/init.lua +++ b/advtrains_signals_muc_ubahn/init.lua @@ -46,7 +46,7 @@ local function applyaspect_distant(loc) end for r,f in pairs(all_sigs) do - for loc, sbox in pairs({l={-1/2, -1/2, -1/4, 0, 1/2, 1/4}, r={0, -1/2, -1/4, 1/2, 1/2, 1/4}, t={-1/2, 0, -1/4, 1/2, 1/2, 1/4}}) do + for loc, sbox in pairs({l={-1/2, -1/4, -1/8, -1/4, 1/4, 1/8}, r={1/4, -1/4, -1/8, 1/2, 1/4, 1/8}, t={-1/4, 1/4, -1/8, 1/4, 1/2, 1/8}}) do minetest.register_node("advtrains_signals_muc_ubahn:signal_wall_"..loc.."_"..r, { drawtype = "mesh", paramtype="light", -- cgit v1.2.3