diff --git a/advtrains/init.lua b/advtrains/init.lua index c7cbf9d..9d20722 100644 --- a/advtrains/init.lua +++ b/advtrains/init.lua @@ -11,7 +11,7 @@ end --advtrains -DUMP_DEBUG_SAVE = true +DUMP_DEBUG_SAVE = false --Constant for maximum connection value/division of the circle AT_CMAX = 16 diff --git a/advtrains/protection.lua b/advtrains/protection.lua index 73b725f..1ea4957 100644 --- a/advtrains/protection.lua +++ b/advtrains/protection.lua @@ -61,50 +61,96 @@ Wagon coupling: local boo = minetest.settings:get_bool("advtrains_allow_build_to_owner") - +-- temporarily prevent scanning for neighboring rail nodes recursively local nocheck + +local old_is_protected = minetest.is_protected + -- Check if the node we are about to check is in the range of a track that is protected from a player ---WARN: true means here that the action is forbidden! -function advtrains.check_track_protection(pos, pname) +minetest.is_protected = function(pos, pname) + + -- old_is_protected: + -- If an earlier callback decided that pos is protected, we wouldn't have been called + -- if a later callback decides it, get that here. + -- this effectively puts this function into a final-choice position + local oprot = old_is_protected(pos, pname) + if oprot then + return true + end + if nocheck or pname=="" then return false end - nocheck=true --prevent recursive calls, never check this again if we're already in + + -- Special exception: to allow seamless rail connections between 2 separately protected + -- networks, rails itself are not affected by the radius setting. So, if the node here is + -- a rail, we skip the check and just use check_track_protection on same pos. + local node = minetest.get_node(pos) + if minetest.get_item_group(node.name, "advtrains_track") > 0 then + -- by here, we know that no other protection callback has this protected, we can safely pass "false". + -- hope this doesn't lead to bugs! + return not advtrains.check_track_protection(pos, pname, nil, false) + end + local r, vr = 1, 3 local nodes = minetest.find_nodes_in_area( {x = pos.x - r, y = pos.y - vr, z = pos.z - r}, - {x = pos.x + r, y = pos.y, z = pos.z + r}, + {x = pos.x + r, y = pos.y + 1, z = pos.z + r}, {"group:advtrains_track"}) for _,npos in ipairs(nodes) do - if not minetest.check_player_privs(pname, {track_builder = true}) then - if boo and not minetest.is_protected(npos, pname) and minetest.is_protected(npos, "*dummy*") then - nocheck = false - return false - else - minetest.chat_send_player(pname, "You are not allowed to dig or place nodes near tracks (missing track_builder privilege)") - minetest.log("action", pname.." tried to dig/place nodes near the track at "..minetest.pos_to_string(npos).." but does not have track_builder") - nocheck = false - return true - end - end - if not minetest.check_player_privs(pname, {protection_bypass = true}) then - if minetest.is_protected(npos, pname) then - nocheck = false - minetest.record_protection_violation(pos, pname) - return true - end + if not advtrains.check_track_protection(npos, pname, pos) then + return true end end nocheck=false return false end -local old_is_protected = minetest.is_protected -minetest.is_protected = function(pos, pname) - if advtrains.check_track_protection(pos, pname) then +-- Check whether the player is permitted to modify this track +-- Shall be called only for nodes that are or are about to become tracks. +-- The range check from is_track_near_protected is disabled here. +-- this splits in 1. track_builder privilege and 2. is_protected +-- also respects the allow_build_to_owner property. +--WARN: true means here that the action is allowed! +function advtrains.check_track_protection(pos, pname, near, prot_p) + -- Parameter "near" is an optional position, the original node that the player + -- was about to affect, while "pos" represents the checked rail node + -- if "near" is not set, pos is the same node. + local nears = near and "near " or "" + local apos = near or pos + + -- note that having protection_bypass implicitly implies having track_builder, because else it would be possible to dig rails + -- (only checked by is_protected, which is not respected) but not place them. + -- We won't impose restrictions on protection_bypass owners. + if minetest.check_player_privs(pname, {protection_bypass = true}) then return true end - return old_is_protected(pos, pname) + + nocheck = true + local priv = minetest.check_player_privs(pname, {track_builder = true}) + + -- note: is_protected above already checks the is_protected value against the current player, so checking it again is useless. + local prot = prot_p + if prot==nil then + prot = advtrains.is_protected(pos, pname) + end + local dprot = minetest.is_protected(pos, "*dummy*") + nocheck = false + + --atdebug("CTP: ",pos,pname,near,prot_p,"priv=",priv,"prot=",prot,"dprot=",dprot) + + if not priv and (not boo or prot or not dprot) then + minetest.chat_send_player(pname, "You are not allowed to build "..nears.."tracks without track_builder privilege") + minetest.log("action", pname.." tried to modify terrain "..nears.."track at "..minetest.pos_to_string(apos).." but is not permitted to (no privilege)") + return false + end + if prot then + minetest.chat_send_player(pname, "You are not allowed to build "..nears.."tracks at protected position!") + minetest.record_protection_violation(pos, pname) + minetest.log("action", pname.." tried to modify "..nears.."track at "..minetest.pos_to_string(apos).." but position is protected!") + return false + end + return true end --WARN: true means here that the action is allowed! @@ -126,7 +172,7 @@ end function advtrains.check_turnout_signal_protection(pos, pname) nocheck=true if not minetest.check_player_privs(pname, {railway_operator = true}) then - if boo and not minetest.is_protected(pos, pname) and minetest.is_protected(pos, "*dummy*") then + if boo and not advtrains.is_protected(pos, pname) and minetest.is_protected(pos, "*dummy*") then nocheck=false return true else @@ -136,12 +182,10 @@ function advtrains.check_turnout_signal_protection(pos, pname) return false end end - if not minetest.check_player_privs(pname, {protection_bypass = true}) then - if minetest.is_protected(pos, pname) then - minetest.record_protection_violation(pos, pname) - nocheck=false - return false - end + if advtrains.is_protected(pos, pname) then + minetest.record_protection_violation(pos, pname) + nocheck=false + return false end nocheck=false return true diff --git a/advtrains/trackplacer.lua b/advtrains/trackplacer.lua index 427a20e..9f5fadd 100644 --- a/advtrains/trackplacer.lua +++ b/advtrains/trackplacer.lua @@ -277,8 +277,7 @@ function tp.register_track_placer(nnprefix, imgprefix, dispname) if pointed_thing.type=="node" then local pos=pointed_thing.above local upos=vector.subtract(pointed_thing.above, {x=0, y=1, z=0}) - if advtrains.is_protected(pos,name) then - minetest.record_protection_violation(pos, name) + if not advtrains.check_track_protection(pos, name) then return itemstack, false end if minetest.registered_nodes[minetest.get_node(pos).name] and minetest.registered_nodes[minetest.get_node(pos).name].buildable_to @@ -286,7 +285,7 @@ function tp.register_track_placer(nnprefix, imgprefix, dispname) -- minetest.chat_send_all(nnprefix) local yaw = placer:get_look_horizontal() tp.placetrack(pos, nnprefix, placer, itemstack, pointed_thing, yaw) - if not minetest.settings:get_bool("creative_mode") then + if not advtrains.is_creative(name) then itemstack:take_item() end end @@ -314,8 +313,7 @@ minetest.register_craftitem("advtrains:trackworker",{ local has_aux1_down = placer:get_player_control().aux1 if pointed_thing.type=="node" then local pos=pointed_thing.under - if advtrains.is_protected(pos, name) then - minetest.record_protection_violation(pos, name) + if not advtrains.check_track_protection(pos, name) then return end local node=minetest.get_node(pos) @@ -369,8 +367,7 @@ minetest.register_craftitem("advtrains:trackworker",{ if pointed_thing.type=="node" then local pos=pointed_thing.under local node=minetest.get_node(pos) - if advtrains.is_protected(pos, name) then - minetest.record_protection_violation(pos, name) + if not advtrains.check_track_protection(pos, name) then return end diff --git a/privilege_guide.txt b/privilege_guide.txt index 7c4952f..cb282d0 100644 --- a/privilege_guide.txt +++ b/privilege_guide.txt @@ -2,6 +2,7 @@ ### Advtrains Privilege Guide All privileges are automatically granted to singleplayer, but for multiplayer servers this might be interesting. +In this document, "protected from" means the player does NOT have access to the area, while "protected by" means the player has (semi-)exclusive access to the area. There are 3 groups of privileges introduced by advtrains: ## Trains @@ -17,10 +18,10 @@ destroy any train. The area 1 node around and 4 nodes up from each track node is protected. Players that don't have the 'track_builder' privilege can not build or dig (or modify) anything inside this area. -If any player tries to modify anything that is in the area of a track -node and this track node is protected from him, he also can not do this. +If a player has this privilege and tries to modify anything that is in the area of a track node which is protected from him, he also can not do this. (that said, while checking protection, the area around a track is treated as the track node itself) +Note that having 'protection_bypass' automatically implies 'track_builder' due to internal engine mechanics. (see comments in source code) ## Turnouts and Signals* Players without the 'railway_operator' privilege can not operate signals @@ -31,3 +32,12 @@ an exception applies to players missing the required privileges when they are in a protected area that they have access to. Whether the area is protected from others is checked by checking for protection against a dummy player called '*dummy*' + +## Privileges of extensions: + +* atlatc: +This privilege allows to create and modify LUA code in LuaATC rails added by the advtrains_luaautomation mod, as well as to create and manage code environments. + +* interlocking: +This privilege allows to build, set up, configure and control all sorts of interlocking equipment. +Players without this privilege are still allowed to set and cancel routes (under the condition that they have train_operator). \ No newline at end of file