From 2dab59f05572fe6cf73cde353446a5a501550b41 Mon Sep 17 00:00:00 2001 From: orwell Date: Tue, 6 Feb 2024 21:10:40 +0100 Subject: Start changing APIs and applying proof-of-concept to ks signals --- advtrains_interlocking/init.lua | 2 +- advtrains_interlocking/signal_api.lua | 105 +++++++++++++++++--------- advtrains_signals_ks/init.lua | 138 +++++++++++++++++++++------------- 3 files changed, 156 insertions(+), 89 deletions(-) diff --git a/advtrains_interlocking/init.lua b/advtrains_interlocking/init.lua index 4d959cc..9aa0c06 100644 --- a/advtrains_interlocking/init.lua +++ b/advtrains_interlocking/init.lua @@ -12,7 +12,7 @@ end local modpath = minetest.get_modpath(minetest.get_current_modname()) .. DIR_DELIM -advtrains.interlocking.aspect = dofile(modpath.."aspect.lua") +--advtrains.interlocking.aspect = dofile(modpath.."aspect.lua") dofile(modpath.."database.lua") dofile(modpath.."distant.lua") diff --git a/advtrains_interlocking/signal_api.lua b/advtrains_interlocking/signal_api.lua index 743e8e1..c2cc08b 100644 --- a/advtrains_interlocking/signal_api.lua +++ b/advtrains_interlocking/signal_api.lua @@ -2,18 +2,19 @@ local F = advtrains.formspec -local DANGER = { - main = 0, - shunt = false, +local signal = {} + +signal.MASP_HALT = { + name = "halt" + halt = true, } -advtrains.interlocking.DANGER = DANGER -advtrains.interlocking.GENERIC_FREE = { - main = -1, +signal.ASPI_HALT = { + main = 0, shunt = false, - dst = false, } -advtrains.interlocking.FULL_FREE = { + +signal.ASPI_FREE = { main = -1, shunt = false, proceed_as_main = true, @@ -25,14 +26,12 @@ Most parts of ywang's implementation are fine, especially I like the formspecs. - Signal gets distant assigned via field in signal aspect table (instead of explicitly) - Signal speed/shunt are no longer free-text but rather they need to be predefined in the node definition To do this: Differentiation between: -== Aspect Group == +== Main Aspect == This is what a signal is assigned by either the route system or the user. It is a string key which has an appropriate entry in the node definition (where it has a description assigned) The signal mod defines a function to set a signal to the most appropriate aspect. This function gets -a) the aspect group name +a) the main aspect table (straight from node def) b) the distant signal's aspect group name & aspect table -EVERY signal must define the special aspect group "halt". This must always be the most restrictive aspect possible. -The "halt" aspect group should ignore any distant info, in most cases it is called without them anyway. == Aspect == One concrete combination of lights/shapes that a signal signal shows. Handling these is at the discretion of @@ -50,6 +49,11 @@ Note that once apply_aspect returns, there is no need for advtrains anymore to q When the signal, for any reason, wants to change its aspect by itself *without* going through the signal API then it should update the aspect info cache by calling advtrains.interlocking.signal.update_aspect_info(pos) +Note that the apply_aspect function MUST accept the following main aspect, even if it is not defined in the main_aspects table: +{ name = "halt", halt = true } +It should cause the signal to show its most restrictive aspect. Typically it is a halt aspect, but e.g. for distant-only +signals this would be "expect stop". + == Aspect Info == The actual signal aspect in the already-known format. This is what the trains use to determine halt/proceed and speed. In this, the dst field has to be resolved. asp = { @@ -62,7 +66,10 @@ asp = { Node definition of signals: - The signal needs some logic to figure out, for each combination of its own aspect group and the distant signal's aspect, what aspect info it can/will show. ndef.advtrains = { - aspect_groups = { [name] = { description = "Proceed at full speed", } } + main_aspects = { + { name = "proceed" description = "Proceed at full speed", } + { name = "proceed2" description = "Proceed at full speed", } + } -- The numerical order determines the layout of the list in the selection dialog. apply_aspect = function(pos, asp_group, dst_aspgrp, dst_aspinfo) -- set the node to show the desired aspect -- called by advtrains when this signal's aspect group or the distant signal's aspect changes @@ -72,28 +79,61 @@ ndef.advtrains = { } ]] -advtrains.interlocking.signal_convert_aspect_if_necessary = advtrains.interlocking.aspect +-- Set a signal's aspect. +-- Signal aspects should only be set through this function. It takes care of: +-- - Storing the main aspect and dst pos for this signal permanently (until next change) +-- - Assigning the distant signal for this signal +-- - Calling apply_aspect() in the signal's node definition to make the signal show the aspect +-- - Calling apply_aspect() again whenever the distant 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_aspect, dst_pos, skip_dst_notify) + -- TODO +end + +-- Gets the stored main aspect and distant signal position for this signal +-- This information equals the information last passed to set_aspect +-- It does not take into consideration the actual speed signalling, please use +-- get_aspect_info() for this +-- returns: main_aspect, dst_pos +function signal.get_aspect(pos) + --TODO +end + +function signal.get_distant_signals_of(pos) + --TODO +end -function advtrains.interlocking.update_signal_aspect(tcbs, skipdst) +-- Called when either this signal has changed its main aspect +-- or when this distant signal's currently assigned main signal has changed its aspect +-- It retrieves the signal's main aspect and aspect info and calls apply_aspect of the node definition +-- to update the signal's appearance and aspect info +-- pts: The signal position to update as encoded_pos +function signal.reapply_aspect(pts, p_mainaspect) + --TODO +end + +-- Update this signal's aspect based on the set route +-- +function signal.update_route_aspect(tcbs, skip_dst_notify) if tcbs.signal then - local asp = tcbs.aspect or DANGER - advtrains.interlocking.signal_set_aspect(tcbs.signal, asp, skipdst) + local asp = tcbs.aspect or signal.MASP_HALT + signal.set_aspect(tcbs.signal, asp, skip_dst_notify) end end -function advtrains.interlocking.signal_can_dig(pos) +function signal.can_dig(pos) return not advtrains.interlocking.db.get_sigd_for_signal(pos) end function advtrains.interlocking.signal_after_dig(pos) -- clear influence point - advtrains.interlocking.signal_clear_aspect(pos) - advtrains.distant.unassign_all(pos, true) + advtrains.distant.unassign_all(pos, true) -- TODO end --- should be called when aspect has changed on this signal. -function advtrains.interlocking.signal_on_aspect_changed(pos) +-- Update waiting trains and distant signals about a changed signal aspect +function signal.notify_on_aspect_changed(pos, skip_dst_notify) + --TODO update distant? local ipts, iconn = advtrains.interlocking.db.get_ip_by_signalpos(pos) if not ipts then return end local ipos = minetest.string_to_pos(ipts) @@ -103,7 +143,7 @@ function advtrains.interlocking.signal_on_aspect_changed(pos) minetest.after(0, advtrains.invalidate_all_paths, ipos) end -function advtrains.interlocking.signal_rc_handler(pos, node, player, itemstack, pointed_thing) +function signal.on_rightclick(pos, node, player, itemstack, pointed_thing) local pname = player:get_player_name() local control = player:get_player_control() if control.aux1 then @@ -122,7 +162,7 @@ function advtrains.interlocking.show_signal_form(pos, node, pname) if ndef.advtrains and ndef.advtrains.set_aspect then -- permit to set aspect manually local function callback(pname, aspect) - advtrains.interlocking.signal_set_aspect(pos, aspect) + signal.set_aspect(pos, aspect) end local isasp = advtrains.interlocking.signal_get_aspect(pos, node) @@ -138,18 +178,6 @@ function advtrains.interlocking.show_signal_form(pos, node, pname) end end --- Returns the aspect the signal at pos is supposed to show -function advtrains.interlocking.signal_get_supposed_aspect(pos) - local sigd = advtrains.interlocking.db.get_sigd_for_signal(pos) - if sigd then - local tcbs = advtrains.interlocking.db.get_tcbs(sigd) - if tcbs.aspect then - return convert_aspect_if_necessary(tcbs.aspect) - end - end - return DANGER; -end - local players_assign_ip = {} local function ipmarker(ipos, connid) @@ -236,7 +264,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) end) -- inits the signal IP assignment process -function advtrains.interlocking.signal_init_ip_assign(pos, pname) +function signal.init_ip_assign(pos, pname) if not minetest.check_player_privs(pname, "interlocking") then minetest.chat_send_player(pname, "Insufficient privileges to use this!") return @@ -281,3 +309,6 @@ minetest.register_on_punchnode(function(pos, node, player, pointed_thing) players_assign_ip[pname] = nil end end) + + +advtrains.interlocking.signal = signal diff --git a/advtrains_signals_ks/init.lua b/advtrains_signals_ks/init.lua index 7e285ae..c91b4ec 100755 --- a/advtrains_signals_ks/init.lua +++ b/advtrains_signals_ks/init.lua @@ -11,10 +11,9 @@ local function asp_to_zs3type(asp) return math.min(16,4*math.floor(n/4)) end -local function setzs3(msp, lim, rot) +local function setzs3(msp, asp, rot) local pos = {x = msp.x, y = msp.y+1, z = msp.z} local node = advtrains.ndb.get_node(pos) - 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 @@ -50,67 +49,106 @@ local function getzs3v(msp) end local setaspectf = function(rot) - return function(pos, node, asp) - setzs3(pos, asp.main, rot) - if asp.main == 0 then - if asp.shunt then - advtrains.ndb.swap_node(pos, {name="advtrains_signals_ks:hs_shunt_"..rot, param2 = node.param2}) - else - advtrains.ndb.swap_node(pos, {name="advtrains_signals_ks:hs_danger_"..rot, param2 = node.param2}) - end + return function(pos, node, main_aspect, dst_aspect, dst_aspect_info) + -- set zs3 signal to show speed according to main_aspect + setzs3(pos, asp.zs3, rot) + -- select appropriate lamps based on mainaspect and dst + if main_aspect.shunt then + advtrains.ndb.swap_node(pos, {name="advtrains_signals_ks:hs_shunt_"..rot, param2 = node.param2}) + setzs3v(pos, nil, rot) + elseif main_aspect.halt then + advtrains.ndb.swap_node(pos, {name="advtrains_signals_ks:hs_danger_"..rot, param2 = node.param2}) setzs3v(pos, nil, rot) else - if not asp.dst or asp.dst == -1 then + if not dst_aspect_info + or not dst_aspect_info.main + or dst_aspect_info.main == -1 then advtrains.ndb.swap_node(pos, {name="advtrains_signals_ks:hs_free_"..rot, param2 = node.param2}) - elseif asp.dst == 0 then + setzs3v(pos, nil, rot) + elseif dst_aspect_info.main == 0 then advtrains.ndb.swap_node(pos, {name="advtrains_signals_ks:hs_slow_"..rot, param2 = node.param2}) + setzs3v(pos, nil, rot) else advtrains.ndb.swap_node(pos, {name="advtrains_signals_ks:hs_nextslow_"..rot, param2 = node.param2}) + setzs3v(pos, dst_aspect_info.main, rot) end - setzs3v(pos, asp.dst, rot) end end end - -local suppasp = { - main = {0, 4, 6, 8, 12, 16, -1}, - dst = {0, 4, 6, 8, 12, 16, -1, false}, - shunt = nil, - proceed_as_main = true, - info = { - call_on = false, - dead_end = false, - w_speed = nil, - } +-- Main aspects main signal +-- These aspects tell only the speed signalization at this signal. +-- Actual signal aspect is chosen based on this and the Dst signal. +local mainaspects_main = { + { + name = "proceed" + description = "Proceed", + zs3 = "off" + }, + { + name = "shunt" + description = "Shunt", + zs3 = "off", + shunt = true, + }, + { + name = "proceed_16" + description = "Proceed (speed 16)", + zs3 = "16", + }, + { + name = "proceed_12" + description = "Proceed (speed 12)", + zs3 = "12", + }, + { + name = "proceed_8" + description = "Proceed (speed 8)", + zs3 = "8", + }, + { + name = "proceed_6" + description = "Proceed (speed 6)", + zs3 = "6", + }, + { + name = "proceed_4" + description = "Proceed (speed 4)", + zs3 = "4", + }, + { + name = "halt" + description = "Halt", + zs3 = "off", + halt = true, + }, } --Rangiersignal -local setaspectf_ra = function(rot) - return function(pos, node, asp) - if asp.shunt then +local applyaspectf_ra = function(rot) + -- we get here the full main_aspect table + return function(pos, node, main_aspect, dst_aspect, dst_aspect_info) + if main_aspect.shunt then advtrains.ndb.swap_node(pos, {name="advtrains_signals_ks:ra_shuntd_"..rot, param2 = node.param2}) else advtrains.ndb.swap_node(pos, {name="advtrains_signals_ks:ra_danger_"..rot, param2 = node.param2}) end - local meta = minetest.get_meta(pos) - if meta then - meta:set_string("infotext", minetest.serialize(asp)) - end end end -local suppasp_ra = { - main = { false }, - dst = { false }, - shunt = nil, - proceed_as_main = false, - - info = { - call_on = false, - dead_end = false, - w_speed = nil, - } +-- Main aspects shunt signal +-- Shunt signals have only two states, distant doesn't matter +local mainaspects_shunt = { + { + name = "shunt" + description = "Shunt", + shunt = true, + }, + { + name = "halt" + description = "Halt", + halt = true, + }, } advtrains.trackplacer.register_tracktype("advtrains_signals_ks:hs") @@ -192,9 +230,9 @@ for _, rtab in ipairs({ drop = "advtrains_signals_ks:hs_danger_0", inventory_image = "advtrains_signals_ks_hs_inv.png", advtrains = { - set_aspect = setaspectf(rot), - supported_aspects = suppasp, - get_aspect = afunc, + main_aspects = mainaspects_main + apply_aspect = applyaspectf_main(rot), + get_aspect_info = afunc, }, on_rightclick = advtrains.interlocking.signal_rc_handler, can_dig = advtrains.interlocking.signal_can_dig, @@ -235,11 +273,9 @@ for _, rtab in ipairs({ drop = "advtrains_signals_ks:ra_danger_0", inventory_image = "advtrains_signals_ks_ra_inv.png", advtrains = { - set_aspect = setaspectf_ra(rot), - supported_aspects = suppasp_ra, - get_aspect = function(pos, node) - return prts.asp - end, + main_aspects = mainaspects_ra, + apply_aspect = applyaspectf_ra(rot), + get_aspect_info = prts.asp, }, on_rightclick = advtrains.interlocking.signal_rc_handler, can_dig = advtrains.interlocking.signal_can_dig, @@ -276,7 +312,7 @@ for _, rtab in ipairs({ drop = "advtrains_signals_ks:"..prefix.."_"..dtyp.."_0", inventory_image = inv, advtrains = { - get_aspect = function() return asp end + get_aspect_info = asp }, on_rightclick = advtrains.interlocking.signal_rc_handler, can_dig = advtrains.interlocking.signal_can_dig, -- cgit v1.2.3