From 15e743629e60fd7b588383c4fd855d51d1859693 Mon Sep 17 00:00:00 2001 From: Vitaliy Date: Fri, 20 Sep 2019 23:04:52 +0000 Subject: [PATCH] Respect protection in MVPS (#466) --- mesecons_movestones/init.lua | 22 +++++++++- mesecons_mvps/init.lua | 85 ++++++++++++++++++++++++++++++++---- mesecons_pistons/init.lua | 25 ++++++++--- settingtypes.txt | 11 +++++ 4 files changed, 128 insertions(+), 15 deletions(-) diff --git a/mesecons_movestones/init.lua b/mesecons_movestones/init.lua index cd82294..49ac2b5 100644 --- a/mesecons_movestones/init.lua +++ b/mesecons_movestones/init.lua @@ -43,10 +43,16 @@ function mesecon.register_movestone(name, def, is_sticky, is_vertical) local function movestone_move(pos, node, rulename) local direction = get_movestone_direction(rulename, is_vertical) local frontpos = vector.add(pos, direction) + local meta = minetest.get_meta(pos) + local owner = meta:get_string("owner") -- ### Step 1: Push nodes in front ### - local success, stack, oldstack = mesecon.mvps_push(frontpos, direction, max_push) + local success, stack, oldstack = mesecon.mvps_push(frontpos, direction, max_push, owner) if not success then + if stack == "protected" then + meta:set_string("infotext", "Can't move: protected area on the way") + return + end minetest.get_node_timer(pos):start(timer_interval) return end @@ -54,6 +60,8 @@ function mesecon.register_movestone(name, def, is_sticky, is_vertical) -- ### Step 2: Move the movestone ### minetest.set_node(frontpos, node) + local meta2 = minetest.get_meta(frontpos) + meta2:set_string("owner", owner) minetest.remove_node(pos) mesecon.on_dignode(pos, node) mesecon.on_placenode(frontpos, node) @@ -62,7 +70,7 @@ function mesecon.register_movestone(name, def, is_sticky, is_vertical) -- ### Step 3: If sticky, pull stack behind ### if is_sticky then local backpos = vector.subtract(pos, direction) - success, stack, oldstack = mesecon.mvps_pull_all(backpos, direction, max_pull) + success, stack, oldstack = mesecon.mvps_pull_all(backpos, direction, max_pull, owner) if success then mesecon.mvps_move_objects(backpos, vector.multiply(direction, -1), oldstack, -1) end @@ -83,6 +91,16 @@ function mesecon.register_movestone(name, def, is_sticky, is_vertical) rules = mesecon.rules.default, }} + def.after_place_node = mesecon.mvps_set_owner + + def.on_punch = function(pos, node, player) + local player_name = player and player.get_player_name and player:get_player_name() + if mesecon.mvps_claim(pos, player_name) then + minetest.get_node_timer(pos):start(timer_interval) + minetest.chat_send_player(player_name, "Reclaimed movestone") + end + end + def.on_timer = function(pos, elapsed) local sourcepos = mesecon.is_powered(pos) if not sourcepos then diff --git a/mesecons_mvps/init.lua b/mesecons_mvps/init.lua index 7b90c9f..1b300aa 100644 --- a/mesecons_mvps/init.lua +++ b/mesecons_mvps/init.lua @@ -133,31 +133,100 @@ function mesecon.mvps_get_stack(pos, dir, maximum, all_pull_sticky) return nodes end -function mesecon.mvps_push(pos, dir, maximum) - return mesecon.mvps_push_or_pull(pos, dir, dir, maximum) +function mesecon.mvps_set_owner(pos, placer) + local meta = minetest.get_meta(pos) + local owner = placer and placer.get_player_name and placer:get_player_name() + if owner and owner ~= "" then + meta:set_string("owner", owner) + else + meta:set_string("owner", "$unknown") -- to distinguish from older pistons + end end -function mesecon.mvps_pull_all(pos, dir, maximum) - return mesecon.mvps_push_or_pull(pos, vector.multiply(dir, -1), dir, maximum, true) +function mesecon.mvps_claim(pos, player_name) + if not player_name or player_name == "" then return end + local meta = minetest.get_meta(pos) + if meta:get_string("infotext") == "" then return end + if meta:get_string("owner") == player_name then return end -- already owned + if minetest.is_protected(pos, player_name) then + minetest.chat_send_player(player_name, "Can't reclaim: protected") + return + end + meta:set_string("owner", player_name) + meta:set_string("infotext", "") + return true end -function mesecon.mvps_pull_single(pos, dir, maximum) - return mesecon.mvps_push_or_pull(pos, vector.multiply(dir, -1), dir, maximum) +local function add_pos(positions, pos) + local hash = minetest.hash_node_position(pos) + positions[hash] = pos end --- pos: pos of mvps; stackdir: direction of building the stack +local function are_protected(positions, player_name) + local mode = mesecon.setting("mvps_protection_mode", "normal") + if mode == "ignore" then + return false + end + local name = player_name + if player_name == "" or not player_name then -- legacy MVPS + if mode == "normal" then + name = "$unknown" -- sentinel, for checking for *any* protection + elseif mode == "compat" then + return false + elseif mode == "restrict" then + return true + else + error("Invalid protection mode") + end + end + local is_protected = minetest.is_protected + for _, pos in pairs(positions) do + if is_protected(pos, name) then + return true + end + end + return false +end + +function mesecon.mvps_push(pos, dir, maximum, player_name) + return mesecon.mvps_push_or_pull(pos, dir, dir, maximum, false, player_name) +end + +function mesecon.mvps_pull_all(pos, dir, maximum, player_name) + return mesecon.mvps_push_or_pull(pos, vector.multiply(dir, -1), dir, maximum, true, player_name) +end + +function mesecon.mvps_pull_single(pos, dir, maximum, player_name) + return mesecon.mvps_push_or_pull(pos, vector.multiply(dir, -1), dir, maximum, false, player_name) +end + +-- pos: pos of mvps +-- stackdir: direction of building the stack -- movedir: direction of actual movement -- maximum: maximum nodes to be pushed -- all_pull_sticky: All nodes are sticky in the direction that they are pulled from -function mesecon.mvps_push_or_pull(pos, stackdir, movedir, maximum, all_pull_sticky) +-- player_name: Player responsible for the action. +-- - empty string means legacy MVPS, actual check depends on configuration +-- - "$unknown" is a sentinel for forcing the check +function mesecon.mvps_push_or_pull(pos, stackdir, movedir, maximum, all_pull_sticky, player_name) local nodes = mesecon.mvps_get_stack(pos, movedir, maximum, all_pull_sticky) if not nodes then return end + + local protection_check_set = {} + if vector.equals(stackdir, movedir) then -- pushing + add_pos(protection_check_set, pos) + end -- determine if one of the nodes blocks the push / pull for id, n in ipairs(nodes) do if mesecon.is_mvps_stopper(n.node, movedir, nodes, id) then return end + add_pos(protection_check_set, n.pos) + add_pos(protection_check_set, vector.add(n.pos, movedir)) + end + if are_protected(protection_check_set, player_name) then + return false, "protected" end -- remove all nodes diff --git a/mesecons_pistons/init.lua b/mesecons_pistons/init.lua index 56a3f73..1af80c5 100644 --- a/mesecons_pistons/init.lua +++ b/mesecons_pistons/init.lua @@ -86,11 +86,15 @@ local piston_on = function(pos, node) local pistonspec = get_pistonspec(node.name, "offname") local dir = vector.multiply(minetest.facedir_to_dir(node.param2), -1) local pusher_pos = vector.add(pos, dir) - local success, stack, oldstack = mesecon.mvps_push(pusher_pos, dir, max_push) + local meta = minetest.get_meta(pos) + local success, stack, oldstack = mesecon.mvps_push(pusher_pos, dir, max_push, meta:get_string("owner")) if not success then + if stack == "protected" then + meta:set_string("infotext", "Can't extend: protected area on the way") + end return end - minetest.set_node(pos, {param2 = node.param2, name = pistonspec.onname}) + minetest.swap_node(pos, {param2 = node.param2, name = pistonspec.onname}) minetest.set_node(pusher_pos, {param2 = node.param2, name = pistonspec.pusher}) minetest.sound_play("piston_extend", { pos = pos, @@ -103,15 +107,16 @@ end local function piston_off(pos, node) local pistonspec = get_pistonspec(node.name, "onname") - minetest.set_node(pos, {param2 = node.param2, name = pistonspec.offname}) - piston_remove_pusher(pos, node, not pistonspec.sticky) + minetest.swap_node(pos, {param2 = node.param2, name = pistonspec.offname}) + piston_remove_pusher(pos, node, not pistonspec.sticky) -- allow that even in protected area if not pistonspec.sticky then return end local dir = minetest.facedir_to_dir(node.param2) local pullpos = vector.add(pos, vector.multiply(dir, -2)) - local success, stack, oldstack = mesecon.mvps_pull_single(pullpos, dir, max_pull) + local meta = minetest.get_meta(pos) + local success, stack, oldstack = mesecon.mvps_pull_single(pullpos, dir, max_pull, meta:get_string("owner")) if success then mesecon.mvps_move_objects(pullpos, vector.multiply(dir, -1), oldstack, -1) end @@ -125,6 +130,7 @@ local orientations = { } local function piston_orientate(pos, placer) + mesecon.mvps_set_owner(pos, placer) if not placer then return end @@ -237,6 +243,13 @@ local function piston_rotate_pusher(pos, node, player, mode) return piston_rotate_on(piston_pos, piston_node, player, mode) end +local function piston_punch(pos, node, player) + local player_name = player and player.get_player_name and player:get_player_name() + if mesecon.mvps_claim(pos, player_name) then + minetest.chat_send_player(player_name, "Reclaimed piston") + end +end + -- Boxes: @@ -279,6 +292,7 @@ minetest.register_node("mesecons_pistons:piston_normal_off", { action_on = piston_on, rules = piston_get_rules, }}, + on_punch = piston_punch, on_rotate = piston_rotate, on_blast = mesecon.on_blastnode, }) @@ -357,6 +371,7 @@ minetest.register_node("mesecons_pistons:piston_sticky_off", { action_on = piston_on, rules = piston_get_rules, }}, + on_punch = piston_punch, on_rotate = piston_rotate, on_blast = mesecon.on_blastnode, }) diff --git a/settingtypes.txt b/settingtypes.txt index 9259a83..5627440 100644 --- a/settingtypes.txt +++ b/settingtypes.txt @@ -28,6 +28,17 @@ mesecon.luacontroller_memsize (Controller memory limit) int 100000 10000 1000000 # IID is ignored and at most one interrupt may be queued if this setting is enabled. mesecon.luacontroller_lightweight_interrupts (Lightweight interrupts) bool false +[mesecons_mvps] + +# In pre-existing world, MVPS may not be labelled with the owner. +# Protection handling for them is configurable. +# - normal: allow legacy MVPS to work in unprotected areas only +# - compat: allow legacy MVPS to work everywhere +# - ignore: allow all MVPS to work everywhere +# - restrict: disallow legacy MVPS +# Note that new unowned (e.g. machine-placed) MVPS are always +# handled as in `normal` mode. +mesecon.mvps_protection_mode (MVPS [movestones, pistons] protection handling) enum compat normal,compat,ignore,restrict [mesecons_movestones]