From 64e59b54f880fde044332e23b80aff3e8ce14b15 Mon Sep 17 00:00:00 2001 From: orwell96 Date: Tue, 22 Jan 2019 12:07:53 +0100 Subject: Prohibit removing/changing of TCBs and sections while routes or signals are set --- advtrains_interlocking/database.lua | 39 ++++++++++++++- advtrains_interlocking/route_ui.lua | 2 +- advtrains_interlocking/routesetting.lua | 11 +++- advtrains_interlocking/tcb_ts_ui.lua | 89 ++++++++++++++++++++------------- 4 files changed, 101 insertions(+), 40 deletions(-) diff --git a/advtrains_interlocking/database.lua b/advtrains_interlocking/database.lua index 12853c0..af20bea 100644 --- a/advtrains_interlocking/database.lua +++ b/advtrains_interlocking/database.lua @@ -304,6 +304,9 @@ local function merge_ts(root_id, merge_id) if not mts then return end -- This may be the case when sync_tcb_neighbors -- inserts the same id twice. do nothing. + if not ildb.may_modify_ts(rts) then return false end + if not ildb.may_modify_ts(mts) then return false end + -- cobble together the list of TCBs for _, msigd in ipairs(mts.tc_breaks) do local tcbs = ildb.get_tcbs(msigd) @@ -384,12 +387,14 @@ end function ildb.remove_from_interlocking(sigd) local tcbs = ildb.get_tcbs(sigd) + if not ildb.may_modify_tcbs(tcbs) then return false end + if tcbs.ts_id then local tsid = tcbs.ts_id local ts = ildb.get_ts(tsid) if not ts then tcbs.ts_id = nil - return + return true end -- remove entry from the list @@ -411,24 +416,54 @@ function ildb.remove_from_interlocking(sigd) end end advtrains.interlocking.show_tcb_marker(sigd.p) + return true end function ildb.remove_tcb(pos) local pts = advtrains.roundfloorpts(pos) if not track_circuit_breaks[pts] then return end for connid=1,2 do - ildb.remove_from_interlocking({p=pos, s=connid}) + if not ildb.remove_from_interlocking({p=pos, s=connid}) then + return false + end end track_circuit_breaks[pts] = nil + return true end function ildb.dissolve_ts(ts_id) local ts = ildb.get_ts(ts_id) + if not ildb.may_modify_ts(ts) then return false end local tcbr = advtrains.merge_tables(ts.tc_breaks) for _,sigd in ipairs(tcbr) do ildb.remove_from_interlocking(sigd) end -- Note: ts gets removed in the moment of the removal of the last TCB. + return true +end + +-- Returns true if it is allowed to modify any property of a track section, such as +-- - removing TCBs +-- - merging and dissolving sections +-- As of now the action will be denied if a route is set or if a train is in the section. +function ildb.may_modify_ts(ts) + if ts.route or ts.route_post or #ts.trains>0 then + return false + end + return true +end + + +function ildb.may_modify_tcbs(tcbs) + if tcbs.signal then + return false + elseif tcbs.ts_id then + local ts = ildb.get_ts(tcbs.ts_id) + if ts and not ildb.may_modify_ts(ts) then + return false + end + end + return true end -- Utilize the traverser to find the track section at the specified position diff --git a/advtrains_interlocking/route_ui.lua b/advtrains_interlocking/route_ui.lua index 9c1f794..d615841 100644 --- a/advtrains_interlocking/route_ui.lua +++ b/advtrains_interlocking/route_ui.lua @@ -130,7 +130,7 @@ function atil.show_route_edit_form(pname, sigd, routeid) form = form.."button[3.5,6;2,1;aspect;Signal Aspect]" form = form.."button[5.5,6;2,1;delete;Delete Route]" - atdebug(route.ars) + --atdebug(route.ars) form = form.."textarea[1,7.3;5.2,3;ars;ARS Rule List;"..ars_to_text(route.ars).."]" form = form.."button[6,7.7;1,1;savears;Save]" diff --git a/advtrains_interlocking/routesetting.lua b/advtrains_interlocking/routesetting.lua index 7b08c4e..44f4592 100644 --- a/advtrains_interlocking/routesetting.lua +++ b/advtrains_interlocking/routesetting.lua @@ -226,14 +226,22 @@ function ilrs.cancel_route_from(sigd) while c_sigd do --atdebug("cancel_route_from: at sigd",c_sigd) c_tcbs = ildb.get_tcbs(c_sigd) + if not c_tcbs then + atwarn("Failed to cancel route, no TCBS at",c_sigd) + return false + end c_ts_id = c_tcbs.ts_id + if not c_tcbs then + atwarn("Failed to cancel route, end of interlocking at",c_sigd) + return false + end c_ts = ildb.get_ts(c_ts_id) if not c_ts or not c_ts.route or not sigd_equal(c_ts.route.entry, c_sigd) then --atdebug("cancel_route_from: abort (eoi/no route):") - return + return false end --atdebug("cancelling",c_ts.route.rsn) @@ -258,6 +266,7 @@ function ilrs.cancel_route_from(sigd) minetest.after(0, advtrains.interlocking.route.update_waiting, "ts", c_ts_id) end --atdebug("cancel_route_from: done (no final sigd)") + return true end -- TCBS Routesetting helper: generic update function for diff --git a/advtrains_interlocking/tcb_ts_ui.lua b/advtrains_interlocking/tcb_ts_ui.lua index 91c2697..a81b12a 100644 --- a/advtrains_interlocking/tcb_ts_ui.lua +++ b/advtrains_interlocking/tcb_ts_ui.lua @@ -182,8 +182,11 @@ local function mktcbformspec(tcbs, btnpref, offset, pname) if ts then form = form.."label[0.5,"..offset..";Side "..btnpref..": "..ts.name.."]" form = form.."button[0.5,"..(offset+0.5)..";5,1;"..btnpref.."_gotots;Show track section]" - form = form.."button[0.5,"..(offset+1.5)..";2.5,1;"..btnpref.."_update;Update near TCBs]" - form = form.."button[3 ,"..(offset+1.5)..";2.5,1;"..btnpref.."_remove;Remove from section]" + if ildb.may_modify_tcbs(tcbs) then + -- Note: the security check to prohibit those actions is located in database.lua in the corresponding functions. + form = form.."button[0.5,"..(offset+1.5)..";2.5,1;"..btnpref.."_update;Update near TCBs]" + form = form.."button[3 ,"..(offset+1.5)..";2.5,1;"..btnpref.."_remove;Remove from section]" + end else tcbs.ts_id = nil form = form.."label[0.5,"..offset..";Side "..btnpref..": ".."End of interlocking]" @@ -323,22 +326,30 @@ function advtrains.interlocking.show_ts_form(ts_id, pname, sel_tcb) end form = form.."textlist[0.5,3;5,3;tcblist;"..table.concat(strtab, ",").."]" - if players_link_ts[pname] then - local other_id = players_link_ts[pname] - local other_ts = ildb.get_ts(other_id) - if other_ts then - form = form.."button[5.5,3;3.5,1;mklink;Join with "..other_ts.name.."]" - form = form.."button[9 ,3;0.5,1;cancellink;X]" + + if ildb.may_modify_ts(ts) then + + if players_link_ts[pname] then + local other_id = players_link_ts[pname] + local other_ts = ildb.get_ts(other_id) + if other_ts then + if ildb.may_modify_ts(other_ts) then + form = form.."button[5.5,3;3.5,1;mklink;Join with "..other_ts.name.."]" + form = form.."button[9 ,3;0.5,1;cancellink;X]" + end + end + else + form = form.."button[5.5,3;4,1;link;Join into other section]" + hint = 1 + end + form = form.."button[5.5,4;4,1;dissolve;Dissolve Section]" + form = form.."tooltip[dissolve;This will remove the track section and set all its end points to End Of Interlocking]" + if sel_tcb then + form = form.."button[5.5,5;4,1;del_tcb;Unlink selected TCB]" + hint = 2 end else - form = form.."button[5.5,3;4,1;link;Join into other section]" - hint = 1 - end - form = form.."button[5.5,4;4,1;dissolve;Dissolve Section]" - form = form.."tooltip[dissolve;This will remove the track section and set all its end points to End Of Interlocking]" - if sel_tcb then - form = form.."button[5.5,5;4,1;del_tcb;Unlink selected TCB]" - hint = 2 + hint=3 end if ts.route then @@ -360,6 +371,8 @@ function advtrains.interlocking.show_ts_form(ts_id, pname, sel_tcb) form = form.."label[0.5,0.75;Use the 'Join' button to designate rail crosses and link not listed far-away TCBs]" elseif hint == 2 then form = form.."label[0.5,0.75;Unlinking a TCB will set it to non-interlocked mode.]" + elseif hint == 3 then + form = form.."label[0.5,0.75;You cannot modify track sections when a route is set or a train is on the section.]" --form = form.."label[0.5,1;Trying to unlink a TCB directly connected to this track will not work.]" end @@ -392,27 +405,31 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) sel_tcb = tpsi end - if players_link_ts[pname] then - if fields.cancellink then - players_link_ts[pname] = nil - elseif fields.mklink then - ildb.link_track_sections(players_link_ts[pname], ts_id) - players_link_ts[pname] = nil + if ildb.may_modify_ts(ts) then + if players_link_ts[pname] then + if fields.cancellink then + players_link_ts[pname] = nil + elseif fields.mklink then + ildb.link_track_sections(players_link_ts[pname], ts_id) + players_link_ts[pname] = nil + end + end + + if fields.del_tcb and sel_tcb and sel_tcb > 0 and sel_tcb <= #ts.tc_breaks then + if not ildb.remove_from_interlocking(ts.tc_breaks[sel_tcb]) then + minetest.chat_send_player(pname, "Please unassign signal first!") + end + sel_tcb = nil + end + + if fields.link then + players_link_ts[pname] = ts_id + end + if fields.dissolve then + ildb.dissolve_ts(ts_id) + minetest.close_formspec(pname, formname) + return end - end - - if fields.del_tcb and sel_tcb and sel_tcb > 0 and sel_tcb <= #ts.tc_breaks then - ildb.remove_from_interlocking(ts.tc_breaks[sel_tcb]) - sel_tcb = nil - end - - if fields.link then - players_link_ts[pname] = ts_id - end - if fields.dissolve then - ildb.dissolve_ts(ts_id) - minetest.close_formspec(pname, formname) - return end if fields.setname then -- cgit v1.2.3