From 9fa43cb7bfc25ba71d16c8210f0074797a7bca1a Mon Sep 17 00:00:00 2001 From: orwell Date: Sun, 28 Jan 2024 00:42:28 +0100 Subject: Implement routesetting incorporating tscache, other improvements --- advtrains/passive.lua | 2 +- advtrains_interlocking/database.lua | 221 +++++++++++++++++++++----------- advtrains_interlocking/route_prog.lua | 2 + advtrains_interlocking/routesetting.lua | 43 +++++-- advtrains_interlocking/tcb_ts_ui.lua | 5 +- advtrains_interlocking/tool.lua | 6 +- 6 files changed, 185 insertions(+), 94 deletions(-) diff --git a/advtrains/passive.lua b/advtrains/passive.lua index 741d7df..231da82 100644 --- a/advtrains/passive.lua +++ b/advtrains/passive.lua @@ -57,7 +57,7 @@ function advtrains.setstate(parpos, newstate, pnode) return false, "train_here" end - if advtrains.interlocking and advtrains.interlocking.route.has_route_lock(minetest.pos_to_string(pos)) then + if advtrains.interlocking and advtrains.interlocking.route.has_route_lock(minetest.encode_pos(pos)) then return false, "route_lock_here" end diff --git a/advtrains_interlocking/database.lua b/advtrains_interlocking/database.lua index 5d42309..17a4199 100644 --- a/advtrains_interlocking/database.lua +++ b/advtrains_interlocking/database.lua @@ -84,11 +84,34 @@ function ildb.load(data) if pos then -- that was a pos_to_string local epos = advtrains.encode_pos(pos) + atdebug("ILDB converting TCB position format",pts,"->",epos) track_circuit_breaks[epos] = tcb else -- keep entry, it is already new track_circuit_breaks[pts] = tcb end + -- convert the routes.[].locks table keys + for t_side,tcbs in pairs(tcb) do + if tcbs.routes then + for t_rnum,route in pairs(tcbs.routes) do + for t_rsnm,rseg in ipairs(route) do + local locks_n = {} + for lpts,state in pairs(rseg.locks) do + local lpos = minetest.string_to_pos(lpts) + if lpos then + local epos = advtrains.encode_pos(lpos) + atdebug("ILDB converting tcb",pts,"side",t_side,"route",t_route,"lock position format",lpts,"->",epos) + locks_n[epos] = state + else + -- already correct format + locks_n[lpts] = state + end + end + rseg.locks = locks_n + end + end + end + end end end end @@ -99,7 +122,23 @@ function ildb.load(data) signal_assignments = data.signalass end if data.rs_locks then - advtrains.interlocking.route.rte_locks = data.rs_locks + if data.tcbpts_conversion_applied then + advtrains.interlocking.route.rte_locks = data.rs_locks + else + advtrains.interlocking.route.rte_locks = {} + for pts, lta in pairs(data.rs_locks) do + local pos = minetest.string_to_pos(pts) + if pos then + -- that was a pos_to_string + local epos = advtrains.encode_pos(pos) + atdebug("ILDB converting Route Lock position format",pts,"->",epos) + advtrains.interlocking.route.rte_locks[epos] = lta + else + -- keep entry, it is already new + advtrains.interlocking.route.rte_locks[pts] = lta + end + end + end end if data.rs_callbacks then advtrains.interlocking.route.rte_callbacks = data.rs_callbacks @@ -197,8 +236,8 @@ routes = { -- one table for each track section on the route -- Note that the section ID is implicitly inferred from the TCB 1 = { - locks = { -- component locks for this section of the route. Not used when use_rscache is true. - (-16,9,0) = st + locks = { -- component locks for this section of the route. + 800080008000 = st } next = S[(-23,9,0)/2] -- the start TCB of the next route segment (pointing forward) } @@ -208,7 +247,8 @@ routes = { } name = "" ars = { } - use_rscache = false -- if true, instead of "locks", the track section's rs_cache will be used to set locks + use_rscache = false -- if true, the track section's rs_cache will be used to set locks in addition to the locks table + -- this is disabled for legacy routes, but enabled for all new routes by default -- Fields used by the autorouter: ar_end_sigd = -- the sigd describing the end of the route. Used for merging route options on recalculation } @@ -218,10 +258,12 @@ Track section [id] = { name = "Some human-readable name" tc_breaks = { ,... } -- Bounding TC's (signal specifiers) - rs_cache = { [] = { [] = { [] = "state" } } } + rs_cache = { [startTcbPosEnc] = { [endTcbPosEnc] = { [componentPosEnc] = "state" } } } -- Saves the turnout states that need to be locked when a route is set from tcb#x to tcb#y - -- e.g. 1 = { 2 = { "800080008000" = "st" } } + -- e.g. "800080008005" = { "800080007EEA" = { "800080008000" = "st" } } + -- start TCB end TCB switch pos -- Recalculated on every change via update_rs_cache + -- Note that the tcb side number is not saved because it is unnecessary route = { origin = , -- route origin @@ -281,17 +323,24 @@ function ildb.get_all_ts() return track_sections end +function tsrepair_notify(notify_pname, ...) + if notify_pname then + minetest.chat_send_player(notify_pname, advtrains.print_concat_table({"TS Check:",...})) + end +end + -- 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, +-- @param tcb_connid: If provided node is a TCB, the direction in which to search +-- @param notify_pname: the player to notify about reparations -- Returns: -- ts_id - the track section that was found -- nil - No track section exists -function ildb.check_and_repair_ts_at_pos(pos, tcb_connid) - atdebug("check_and_repair_ts_at_pos", pos, tcb_connid) +function ildb.check_and_repair_ts_at_pos(pos, tcb_connid, notify_pname) + --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 @@ -315,15 +364,17 @@ function ildb.check_and_repair_ts_at_pos(pos, tcb_connid) -- these must be the same as the first if ts_id ~= tcbs_ts_id then -- inconsistency is found, repair it - atdebug("check_and_repair_ts_at_pos: Inconsistency is found!") - return ildb.repair_ts_merge_all(all_tcbs) + --atdebug("check_and_repair_ts_at_pos: Inconsistency is found!") + tsrepair_notify(notify_pname, "Track section inconsistent here, repairing...") + return ildb.repair_ts_merge_all(all_tcbs, false, notify_pname) -- Step2 check is no longer necessary since we just created that new section end end end -- only one found (it is either nil or a ts id) - atdebug("check_and_repair_ts_at_pos: TS consistent id=",ts_id,"") + --atdebug("check_and_repair_ts_at_pos: TS consistent id=",ts_id,"") if not ts_id then + tsrepair_notify(notify_pname, "No track section found here.") return -- All TCBs agreed that there is no section here. end @@ -338,9 +389,11 @@ function ildb.check_and_repair_ts_at_pos(pos, tcb_connid) -- ildb.tcbs_ensure_ts_ref_exists(sigd) has already make sure that all tcbs are found in the ts's tc_breaks list -- That means it is sufficient to compare the LENGTHS of both lists, if one is longer then it is inconsistent if #ts.tc_breaks ~= #all_tcbs then - atdebug("check_and_repair_ts_at_pos: Partition is found!") - return ildb.repair_ts_merge_all(all_tcbs) + --atdebug("check_and_repair_ts_at_pos: Partition is found!") + tsrepair_notify(notify_pname, "Track section partition found, repairing...") + return ildb.repair_ts_merge_all(all_tcbs, false, notify_pname) end + tsrepair_notify(notify_pname, "Found section", ts.name or ts_id, "here.") return ts_id end @@ -367,7 +420,7 @@ end -- Returns: a list of sigd's describing the TCBs found (sigd's point inward): -- {p=, s=, tcbs=} function ildb.get_all_tcbs_adjacent(inipos, inidir, per_track_callback) - atdebug("get_all_tcbs_adjacent: inipos",inipos,"inidir",inidir,"") + --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 @@ -377,7 +430,7 @@ function ildb.get_all_tcbs_adjacent(inipos, inidir, per_track_callback) 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) + --atdebug("get_all_tcbs_adjacent: Putting xlink Branch for initial node",initcbs.xlink) ti:add_branch(initcbs.xlink.p, initcbs.xlink.s) end end @@ -400,17 +453,17 @@ function ildb.get_all_tcbs_adjacent(inipos, inidir, per_track_callback) -- 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) + --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) + --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) + --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) @@ -429,8 +482,8 @@ end -- Called by frontend functions when multiple tcbs's that logically belong to one section have been determined to have different sections -- Parameter is the output of ildb.get_all_tcbs_adjacent(pos) -- Returns the ID of the track section that results after the merge -function ildb.repair_ts_merge_all(all_tcbs, force_create) - atdebug("repair_ts_merge_all: Instructed to merge sections of following TCBs:") +function ildb.repair_ts_merge_all(all_tcbs, force_create, notify_pname) + --atdebug("repair_ts_merge_all: Instructed to merge sections of following TCBs:") -- The first loop does the following for each TCBS: -- a) Store the TS ID in the set of TS to update -- b) Set the TS ID to nil, so that the TCBS gets removed from the section @@ -439,7 +492,7 @@ function ildb.repair_ts_merge_all(all_tcbs, force_create) local any_ts = false for _,sigd in ipairs(all_tcbs) do local ts_id = sigd.tcbs.ts_id - atdebug(sigd, "ts=", ts_id) + --atdebug(sigd, "ts=", ts_id) if ts_id then local ts = track_sections[ts_id] if ts then @@ -455,7 +508,7 @@ function ildb.repair_ts_merge_all(all_tcbs, force_create) end if not any_ts and not force_create then -- nothing to do at all, just no interlocking. Why were we even called - atdebug("repair_ts_merge_all: No track section present, will not create a new one") + --atdebug("repair_ts_merge_all: No track section present, will not create a new one") return nil end -- Purge every TS in turn. TS's that are now empty will be deleted. TS's that still have TCBs will be kept @@ -464,6 +517,7 @@ function ildb.repair_ts_merge_all(all_tcbs, force_create) end -- Create a new fresh track section with all the TCBs we have in our collection local new_ts_id, new_ts = ildb.create_ts_from_tcb_list(all_tcbs) + tsrepair_notify(notify_pname, "Created track section",new_ts_id,"from TCBs:", all_tcbs) return new_ts_id end @@ -487,20 +541,20 @@ function ildb.purge_ts_tcb_refs(ts_id) i = i+1 else -- this one is to be purged - atdebug("purge_ts_tcb_refs(",ts_id,"): purging",sigd,"(backreference = ",tcbs.ts_id,")") + --atdebug("purge_ts_tcb_refs(",ts_id,"): purging",sigd,"(backreference = ",tcbs.ts_id,")") table.remove(ts.tc_breaks, i) has_changed = true end else -- if not tcbs: was anyway an orphan, remove it - atdebug("purge_ts_tcb_refs(",ts_id,"): purging",sigd,"(referred nonexisting TCB)") + --atdebug("purge_ts_tcb_refs(",ts_id,"): purging",sigd,"(referred nonexisting TCB)") table.remove(ts.tc_breaks, i) has_changed = true end end if #ts.tc_breaks == 0 then -- remove the section completely - atdebug("purge_ts_tcb_refs(",ts_id,"): after purging, the section is empty, is being deleted") + --atdebug("purge_ts_tcb_refs(",ts_id,"): after purging, the section is empty, is being deleted") track_sections[ts_id] = nil return nil else @@ -520,14 +574,14 @@ function ildb.tcbs_ensure_ts_ref_exists(sigd) if not tcbs or not tcbs.ts_id then return end local ts = ildb.get_ts(tcbs.ts_id) if not ts then - atdebug("tcbs_ensure_ts_ref_exists(",sigd,"): TS does not exist, setting to nil") + --atdebug("tcbs_ensure_ts_ref_exists(",sigd,"): TS does not exist, setting to nil") -- TS is deleted, clear own ts id tcbs.ts_id = nil return end 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) + --atdebug("tcbs_ensure_ts_ref_exists(",sigd,"): TCBS was missing reference in TS",tcbs.ts_id) ildb.update_rs_cache(tcbs.ts_id) end end @@ -538,7 +592,7 @@ function ildb.create_ts_from_tcb_list(sigd_list) while track_sections[id] do id = advtrains.random_id(8) end - atdebug("create_ts_from_tcb_list: sigd_list=",sigd_list, "new ID will be ",id) + --atdebug("create_ts_from_tcb_list: sigd_list=",sigd_list, "new ID will be ",id) local tcbr = {} -- makes a copy of the sigd list, for use in repair mechanisms where sigd may contain a tcbs field which we dont want @@ -585,23 +639,23 @@ function ildb.get_possible_out_connids(node_name, in_connid) local nt = node_from_to_state_cache[node_name] if not nt[in_connid] then local ta = {} - atdebug("Node From/To State Cache: Caching for ",node_name,"connid",in_connid) + --atdebug("Node From/To State Cache: Caching for ",node_name,"connid",in_connid) local ndef = minetest.registered_nodes[node_name] if ndef.advtrains.node_state_map then for state, tnode in pairs(ndef.advtrains.node_state_map) do local tndef = minetest.registered_nodes[tnode] -- verify that the conns table is identical - this is purely to catch setup errors! if not tndef.at_conns or not tndef.at_conn_map then - atdebug("ndef:",ndef,", tndef:",tndef) - error("In AT setup for node "..tnode..": Node set as state "..state.." of "..node_name.." in state_map, but is missing at_conns/at_conn/map!") + --atdebug("ndef:",ndef,", tndef:",tndef) + error("In AT setup for node "..tnode..": Node set as state "..state.." of "..node_name.." in state_map, but is missing at_conns/at_conn_map!") end if #ndef.at_conns ~= #tndef.at_conns then - atdebug("ndef:",ndef,", tndef:",tndef) + --atdebug("ndef:",ndef,", tndef:",tndef) error("In AT setup for node "..tnode..": Conns table does not match that of "..node_name.." (of which this is state "..state..")") end for connid=1,#ndef.at_conns do if ndef.at_conns[connid].c ~= tndef.at_conns[connid].c then - atdebug("ndef:",ndef,", tndef:",tndef) + --atdebug("ndef:",ndef,", tndef:",tndef) error("In AT setup for node "..tnode..": Conns table does not match that of "..node_name.." (of which this is state "..state..")") end end @@ -610,13 +664,13 @@ function ildb.get_possible_out_connids(node_name, in_connid) if ta[target_connid] then -- Select the variant for which the other way would back-connect. This way, turnouts will switch to the appropriate branch if the train joins local have_back_conn = (tndef.at_conn_map[target_connid])==in_connid - atdebug("Found second state mapping",in_connid,"-",target_connid,"have_back_conn=",have_back_conn) + --atdebug("Found second state mapping",in_connid,"-",target_connid,"have_back_conn=",have_back_conn) if have_back_conn then - atdebug("Overwriting",in_connid,"-",target_connid,"=",state) + --atdebug("Overwriting",in_connid,"-",target_connid,"=",state) ta[target_connid] = state end else - atdebug("Setting",in_connid,"-",target_connid,"=",state) + --atdebug("Setting",in_connid,"-",target_connid,"=",state) ta[target_connid] = state end end @@ -629,26 +683,27 @@ function ildb.get_possible_out_connids(node_name, in_connid) end local function recursively_find_routes(s_pos, s_connid, locks_found, result_table, scan_limit) - atdebug("Recursively restarting at ",s_pos, s_connid, "limit left", scan_limit) + --atdebug("Recursively restarting at ",s_pos, s_connid, "limit left", scan_limit) local ti = advtrains.get_track_iterator(s_pos, s_connid, scan_limit, false) local pos, connid, bconnid = ti:next_branch() pos, connid, bconnid = ti:next_track()-- step once to get ahead of previous turnout + local last_pos repeat local node = advtrains.ndb.get_node_or_nil(pos) - atdebug("Walk ",pos, "nodename", node.name, "entering at conn",bconnid) + --atdebug("Walk ",pos, "nodename", node.name, "entering at conn",bconnid) local ndef = minetest.registered_nodes[node.name] if ndef.advtrains and ndef.advtrains.node_state_map then -- Stop, this is a switchable node. Find out which conns we can go at - atdebug("Found turnout ",pos, "nodename", node.name, "entering at conn",bconnid) + --atdebug("Found turnout ",pos, "nodename", node.name, "entering at conn",bconnid) local pts = advtrains.encode_pos(pos) if locks_found[pts] then -- we've been here before. Stop - atdebug("Was already seen! returning") + --atdebug("Was already seen! returning") return end local out_conns = ildb.get_possible_out_connids(node.name, bconnid) for oconnid, state in pairs(out_conns) do - atdebug("Going in direction",oconnid,"state",state) + --atdebug("Going in direction",oconnid,"state",state) locks_found[pts] = state recursively_find_routes(pos, oconnid, locks_found, result_table, ti.limit) locks_found[pts] = nil @@ -656,21 +711,23 @@ local function recursively_find_routes(s_pos, s_connid, locks_found, result_tabl return end --otherwise, this might be a tcb - local tcbs = ildb.get_tcbs({p=pos, s=bconnid}) - if tcbs then + local tcb = ildb.get_tcb(pos) + if tcb then -- we found a tcb, store the current locks in the result_table - local table_key = advtrains.encode_pos(pos).."_"..bconnid - atdebug("Found end TCB", table_key,", returning") - if result_table[table_key] then + local end_pkey = advtrains.encode_pos(pos) + --atdebug("Found end TCB", pos, end_pkey,", returning") + if result_table[end_pkey] then atwarn("While caching track section routing, found multiple route paths within same track section. Only first one found will be used") else - result_table[table_key] = table.copy(locks_found) + result_table[end_pkey] = table.copy(locks_found) end return end -- Go forward + last_pos = pos pos, connid, bconnid = ti:next_track() until not pos -- this stops the loop when either the track end is reached or the limit is hit + --atdebug("recursively_find_routes: Reached track end or limit at", last_pos, ". This path is not saved, returning") end -- Updates the turnout cache of the given track section @@ -680,25 +737,33 @@ function ildb.update_rs_cache(ts_id) error("Update TS Cache called with nonexisting ts_id "..(ts_id or "nil")) end local rscache = {} - atdebug("== Running update_rs_cache for ",ts_id) + --atdebug("== Running update_rs_cache for ",ts_id) -- start on every of the TS's TCBs, walk the track forward and store locks along the way for start_tcbi, start_tcbs in ipairs(ts.tc_breaks) do - rscache[start_tcbi] = {} - atdebug("Starting for ",start_tcbi, start_tcbs) + start_pkey = advtrains.encode_pos(start_tcbs.p) + rscache[start_pkey] = {} + --atdebug("Starting for ",start_tcbi, start_tcbs) local locks_found = {} local result_table = {} recursively_find_routes(start_tcbs.p, start_tcbs.s, locks_found, result_table, TS_MAX_SCAN) -- now result_table contains found route locks. Match them with the other TCBs we have in this section for end_tcbi, end_tcbs in ipairs(ts.tc_breaks) do - local table_key = advtrains.encode_pos(end_tcbs.p).."_"..end_tcbs.s - if result_table[table_key] then - atdebug("Set RSCache entry",start_tcbi.."-"..end_tcbi,"=",result_table[table_key]) - rscache[start_tcbi][end_tcbi] = result_table[table_key] + if end_tcbi ~= start_tcbi then + end_pkey = advtrains.encode_pos(end_tcbs.p) + if result_table[end_pkey] then + --atdebug("Set RSCache entry",end_pkey.."-"..end_pkey,"=",result_table[end_pkey]) + rscache[start_pkey][end_pkey] = result_table[end_pkey] + result_table[end_pkey] = nil + end end end + -- warn about superfluous entry + for sup_end_pkey, sup_entry in pairs(result_table) do + --atwarn("In update_rs_cache for section",ts_id,"found superfluous endpoint",sup_end_pkey,"->",sup_entry) + end end ts.rs_cache = rscache - atdebug("== Done update_rs_cache for ",ts_id, "result:",rscache) + --atdebug("== Done update_rs_cache for ",ts_id, "result:",rscache) end @@ -711,21 +776,21 @@ end -- Create a new TCB at the position and update/repair the adjoining sections function ildb.create_tcb_at(pos) - atdebug("create_tcb_at",pos) + --atdebug("create_tcb_at",pos) local pts = advtrains.encode_pos(pos) track_circuit_breaks[pts] = {[1] = {}, [2] = {}} local all_tcbs_1 = ildb.get_all_tcbs_adjacent(pos, 1) - atdebug("TCBs on A side",all_tcbs_1) + --atdebug("TCBs on A side",all_tcbs_1) local all_tcbs_2 = ildb.get_all_tcbs_adjacent(pos, 2) - atdebug("TCBs on B side",all_tcbs_2) + --atdebug("TCBs on B side",all_tcbs_2) -- perform TS repair - ildb.repair_ts_merge_all(all_tcbs_1) - ildb.repair_ts_merge_all(all_tcbs_2) + ildb.repair_ts_merge_all(all_tcbs_1, false) + ildb.repair_ts_merge_all(all_tcbs_2, false) end --- Create a new TCB at the position and update/repair the now joined section +-- Remove TCB at the position and update/repair the now joined section function ildb.remove_tcb_at(pos) - atdebug("remove_tcb_at",pos) + --atdebug("remove_tcb_at",pos) local pts = advtrains.encode_pos(pos) local old_tcb = track_circuit_breaks[pts] track_circuit_breaks[pts] = nil @@ -745,7 +810,7 @@ function ildb.remove_tcb_at(pos) end advtrains.interlocking.remove_tcb_marker(pos) -- If needed, merge the track sections here - ildb.check_and_repair_ts_at_pos(pos) + ildb.check_and_repair_ts_at_pos(pos, nil) return true end @@ -758,7 +823,7 @@ function ildb.validate_tcb_xlink(sigd, suppress_repairs) 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") + --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) @@ -767,16 +832,16 @@ function ildb.validate_tcb_xlink(sigd, suppress_repairs) 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") + --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") + --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") + --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) @@ -785,19 +850,19 @@ function ildb.validate_tcb_xlink(sigd, suppress_repairs) end function ildb.add_tcb_xlink(sigd1, sigd2) - atdebug("add_tcb_xlink",sigd1, sigd2) + --("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") + --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") + --atdebug("add_tcb_xlink TCBS doesnt exist") return end if tcbs1.xlink or tcbs2.xlink then - atdebug("add_tcb_xlink One already linked") + --atdebug("add_tcb_xlink One already linked") return end -- apply link @@ -808,7 +873,7 @@ function ildb.add_tcb_xlink(sigd1, sigd2) end function ildb.remove_tcb_xlink(sigd) - atdebug("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 @@ -816,7 +881,7 @@ function ildb.remove_tcb_xlink(sigd) local osigd = tcbs.xlink if not osigd then -- validate already cleared us - atdebug("remove_tcb_xlink: Already gone by validate") + --atdebug("remove_tcb_xlink: Already gone by validate") return end local otcbs = ildb.get_tcbs(tcbs.xlink) @@ -829,14 +894,14 @@ function ildb.remove_tcb_xlink(sigd) end function ildb.create_ts_from_tcbs(sigd) - atdebug("create_ts_from_tcbs",sigd) + --atdebug("create_ts_from_tcbs",sigd) local all_tcbs = ildb.get_all_tcbs_adjacent(sigd.p, sigd.s) ildb.repair_ts_merge_all(all_tcbs, true) end -- Remove the given track section, leaving its TCBs with no section assigned function ildb.remove_ts(ts_id) - atdebug("remove_ts",ts_id) + --atdebug("remove_ts",ts_id) local ts = track_sections[ts_id] if not ts then error("remove_ts: "..ts_id.." doesn't exist") @@ -846,10 +911,10 @@ function ildb.remove_ts(ts_id) local sigd = ts.tc_breaks[i] local tcbs = ildb.get_tcbs(sigd) if tcbs then - atdebug("cleared TCB",sigd) + --atdebug("cleared TCB",sigd) tcbs.ts_id = nil else - atdebug("orphan TCB",sigd) + --atdebug("orphan TCB",sigd) end i = i+1 end diff --git a/advtrains_interlocking/route_prog.lua b/advtrains_interlocking/route_prog.lua index 5fd9363..34807cd 100644 --- a/advtrains_interlocking/route_prog.lua +++ b/advtrains_interlocking/route_prog.lua @@ -492,6 +492,8 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) local terminal = get_last_route_item(rp.origin, rp.route) rp.route.terminal = terminal rp.route.name = fields.name + -- new routes now always use the rscache + rp.route.use_rscache = true table.insert(tcbs.routes, rp.route) diff --git a/advtrains_interlocking/routesetting.lua b/advtrains_interlocking/routesetting.lua index ede3d49..64b8c25 100644 --- a/advtrains_interlocking/routesetting.lua +++ b/advtrains_interlocking/routesetting.lua @@ -49,7 +49,7 @@ function ilrs.set_route(signal, route, try) c_tcbs = ildb.get_tcbs(c_sigd) if not c_tcbs then if not try then atwarn("Did not find TCBS",c_sigd,"while setting route",rtename,"of",signal) end - return false, "No TCB found at "..sigd_to_string(c_sigd)..". Please reconfigure route!" + return false, "No TCB found at "..sigd_to_string(c_sigd)..". Please update or reconfigure route!" end c_ts_id = c_tcbs.ts_id if not c_ts_id then @@ -69,28 +69,49 @@ function ilrs.set_route(signal, route, try) return false, "Section '"..c_ts.name.."' is occupied!", c_ts_id, nil end - for pts, state in pairs(c_rseg.locks) do + -- collect locks from rs cache and from route def + local c_locks = {} + if route.use_rscache and c_ts.rs_cache and c_rseg.next then + -- rscache needs to be enabled, present and next must be defined + start_pkey = advtrains.encode_pos(c_sigd.p) + end_pkey = advtrains.encode_pos(c_rseg.next.p) + if c_ts.rs_cache[start_pkey] and c_ts.rs_cache[start_pkey][end_pkey] then + for lp,lst in pairs(c_ts.rs_cache[start_pkey][end_pkey]) do + atdebug("Add lock from RSCache:",lp,"->",lst) + c_locks[lp] = lst + end + elseif not try then + atwarn("While setting route",rtename,"of",signal,"segment "..i..",required path from",c_tcbs,"to",c_rseg.next,"was not found in the track section's RS cache. Please check!") + end + end + -- add all from locks, these override the rscache + for lpts,lst in pairs(c_rseg.locks) do + atdebug("Add lock from Routedef:",lp,"->",lst,"overrides",c_locks[lp] or "none") + c_locks[lp] = lst + end + + for lp, state in pairs(c_locks) do local confl = ilrs.has_route_lock(pts, state) - local pos = minetest.string_to_pos(pts) + local pos = advtrains.decode_pos(lp) if advtrains.is_passive(pos) then local cstate = advtrains.getstate(pos) if cstate ~= state then - local confl = ilrs.has_route_lock(pts) + local confl = ilrs.has_route_lock(lp) if confl then - if not try then atwarn("Encountered route lock while a real run of routesetting routine, at position",pts,"while setting route",rtename,"of",signal) end - return false, "Lock conflict at "..pts..", Held locked by:\n"..confl, nil, pts + if not try then atwarn("Encountered route lock while a real run of routesetting routine, at position",pos,"while setting route",rtename,"of",signal) end + return false, "Lock conflict at "..minetest.pos_to_string(pos)..", Held locked by:\n"..confl, nil, lp elseif not try then advtrains.setstate(pos, state) end end if not try then - ilrs.add_route_lock(pts, c_ts_id, "Route '"..rtename.."' from signal '"..signalname.."'", signal) - c_lckp[#c_lckp+1] = pts + ilrs.add_route_lock(lp, c_ts_id, "Route '"..rtename.."' from signal '"..signalname.."'", signal) + c_lckp[#c_lckp+1] = lp end else if not try then atwarn("Encountered route lock misconfiguration (no passive component) while a real run of routesetting routine, at position",pts,"while setting route",rtename,"of",signal) end - return false, "No passive component at "..pts..". Please reconfigure route!" + return false, "No passive component at "..minetest.pos_to_string(pos)..". Please update track section or reconfigure route!" end end -- reserve ts and write locks @@ -126,6 +147,8 @@ function ilrs.set_route(signal, route, try) return true end +-- Change 2024-01-27: pts is not an encoded pos, not a pos-to-string! + -- Checks whether there is a route lock that prohibits setting the component -- to the wanted state. returns string with reasons on conflict function ilrs.has_route_lock(pts) @@ -191,7 +214,7 @@ function ilrs.free_route_locks_indiv(pts, ts, nocallbacks) -- TODO use luaautomation timers? if not nocallbacks then minetest.after(0, ilrs.update_waiting, "lck", pts) - minetest.after(0.5, advtrains.set_fallback_state, minetest.string_to_pos(pts)) + minetest.after(0.5, advtrains.set_fallback_state, advtrains.decode_pos(pts)) end end -- frees all route locks, even manual ones set with the tool, at a specific position diff --git a/advtrains_interlocking/tcb_ts_ui.lua b/advtrains_interlocking/tcb_ts_ui.lua index e365f4f..9e7fcd4 100755 --- a/advtrains_interlocking/tcb_ts_ui.lua +++ b/advtrains_interlocking/tcb_ts_ui.lua @@ -99,10 +99,11 @@ minetest.register_node("advtrains_interlocking:tcb_node", { end, after_dig_node = function(pos, oldnode, oldmetadata, player) if not oldmetadata or not oldmetadata.fields then return end + local pname = player:get_player_name() local tcbpts = oldmetadata.fields.tcb_pos if tcbpts and tcbpts ~= "" then local tcbpos = minetest.string_to_pos(tcbpts) - ildb.remove_tcb_at(tcbpos) + ildb.remove_tcb_at(tcbpos, pname) end end, }) @@ -160,7 +161,7 @@ minetest.register_on_punchnode(function(pos, node, player, pointed_thing) if ildb.get_tcb(pos) then minetest.chat_send_player(pname, "Configuring TCB: Already existed at this position, it is now linked to this TCB marker") else - ildb.create_tcb_at(pos) + ildb.create_tcb_at(pos, pname) end local meta = minetest.get_meta(tcbnpos) diff --git a/advtrains_interlocking/tool.lua b/advtrains_interlocking/tool.lua index ef0f06e..4ebc56c 100644 --- a/advtrains_interlocking/tool.lua +++ b/advtrains_interlocking/tool.lua @@ -6,7 +6,7 @@ local ilrs = advtrains.interlocking.route local function node_right_click(pos, pname) if advtrains.is_passive(pos) then local form = "size[7,5]label[0.5,0.5;Route lock inspector]" - local pts = minetest.pos_to_string(pos) + local pts = advtrains.encode_pos(pos) local rtl = ilrs.has_route_lock(pts) @@ -53,7 +53,7 @@ local function node_left_click(pos, pname) return end - local ts_id = advtrains.interlocking.db.check_and_repair_ts_at_pos(pos) + local ts_id = advtrains.interlocking.db.check_and_repair_ts_at_pos(pos, nil, pname) if ts_id then advtrains.interlocking.db.update_rs_cache(ts_id) advtrains.interlocking.highlight_track_section(pos) @@ -107,7 +107,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) local pos local pts = string.match(formname, "^at_il_rtool_(.+)$") if pts then - pos = minetest.string_to_pos(pts) + pos = advtrains.decode_pos(pts) end if pos then if advtrains.is_passive(pos) then -- cgit v1.2.3