From aa14c9d7b66fa0621997de13ea2a9376ffe5ed29 Mon Sep 17 00:00:00 2001 From: Luke aka SwissalpS Date: Tue, 3 Sep 2024 00:06:00 +0200 Subject: [PATCH 01/10] check interact permission on smallest area at position --- api.lua | 51 ++++++++++++++++++++++++++++++++------------------- 1 file changed, 32 insertions(+), 19 deletions(-) diff --git a/api.lua b/api.lua index 8d6313f..2b4de2f 100644 --- a/api.lua +++ b/api.lua @@ -95,36 +95,49 @@ function areas:getAreasIntersectingArea(pos1, pos2) return res end --- Checks if the area is unprotected or owned by you +-- Checks if the area is unprotected, open, owned by player +-- or player is part of faction of smallest area at position. function areas:canInteract(pos, name) if minetest.check_player_privs(name, self.adminPrivs) then return true end - local owned = false + -- Determine smallest area at position + -- If multiple areas have the same volume, larger id takes precedence. + local smallest_area, smallest_volume, volume for _, area in pairs(self:getAreasAtPos(pos)) do - if area.owner == name or area.open then - return true - elseif areas.factions_available and area.faction_open then - if (factions.version or 0) < 2 then - local faction_name = factions.get_player_faction(name) - if faction_name then - for _, fname in ipairs(area.faction_open or {}) do - if faction_name == fname then - return true - end - end - end - else - for _, fname in ipairs(area.faction_open or {}) do - if factions.player_is_in_faction(fname, name) then + volume = (area.pos2.x - area.pos1.x + 1) + * (area.pos2.y - area.pos1.y + 1) + * (area.pos2.z - area.pos1.z + 1) + if not smallest_volume or smallest_volume >= volume then + smallest_area = area + smallest_volume = volume + end + end + -- No area, player owns it or area is open + if not smallest_area + or smallest_area.owner == name + or smallest_area.open + then + return true + elseif areas.factions_available and smallest_area.faction_open then + if (factions.version or 0) < 2 then + local faction_name = factions.get_player_faction(name) + if faction_name then + for _, fname in ipairs(smallest_area.faction_open or {}) do + if faction_name == fname then return true end end end + else + for _, fname in ipairs(smallest_area.faction_open or {}) do + if factions.player_is_in_faction(fname, name) then + return true + end + end end - owned = true end - return not owned + return false end -- Returns a table (list) of all players that own an area From 1b86480f3d6dbe04432c6faa9a18488651389438 Mon Sep 17 00:00:00 2001 From: Luke aka SwissalpS Date: Tue, 3 Sep 2024 09:53:40 +0200 Subject: [PATCH 02/10] expose getSmallestAreaAtPos() --- api.lua | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/api.lua b/api.lua index 2b4de2f..51cc943 100644 --- a/api.lua +++ b/api.lua @@ -95,15 +95,10 @@ function areas:getAreasIntersectingArea(pos1, pos2) return res end --- Checks if the area is unprotected, open, owned by player --- or player is part of faction of smallest area at position. -function areas:canInteract(pos, name) - if minetest.check_player_privs(name, self.adminPrivs) then - return true - end - -- Determine smallest area at position - -- If multiple areas have the same volume, larger id takes precedence. - local smallest_area, smallest_volume, volume +-- Returns smallest area at position or nil. +-- If multiple areas have the same volume, larger id takes precedence. +function areas:getSmallestAreaAtPos(pos) + local smallest_area, smallest_volume, volume = nil for _, area in pairs(self:getAreasAtPos(pos)) do volume = (area.pos2.x - area.pos1.x + 1) * (area.pos2.y - area.pos1.y + 1) @@ -113,24 +108,34 @@ function areas:canInteract(pos, name) smallest_volume = volume end end + return smallest_area +end + +-- Checks if the area is unprotected, open, owned by player +-- or player is part of faction of smallest area at position. +function areas:canInteract(pos, name) + if minetest.check_player_privs(name, self.adminPrivs) then + return true + end + local area = self:getSmallestAreaAtPos(pos) -- No area, player owns it or area is open - if not smallest_area - or smallest_area.owner == name - or smallest_area.open + if not area + or area.owner == name + or area.open then return true - elseif areas.factions_available and smallest_area.faction_open then + elseif areas.factions_available and area.faction_open then if (factions.version or 0) < 2 then local faction_name = factions.get_player_faction(name) if faction_name then - for _, fname in ipairs(smallest_area.faction_open or {}) do + for _, fname in ipairs(area.faction_open or {}) do if faction_name == fname then return true end end end else - for _, fname in ipairs(smallest_area.faction_open or {}) do + for _, fname in ipairs(area.faction_open or {}) do if factions.player_is_in_faction(fname, name) then return true end From fd6d7e4056ff7ca638cb45eada1ee3466a63b3f2 Mon Sep 17 00:00:00 2001 From: Luke aka SwissalpS Date: Tue, 3 Sep 2024 10:20:14 +0200 Subject: [PATCH 03/10] also return area id --- api.lua | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/api.lua b/api.lua index 51cc943..e96d6f5 100644 --- a/api.lua +++ b/api.lua @@ -95,20 +95,21 @@ function areas:getAreasIntersectingArea(pos1, pos2) return res end --- Returns smallest area at position or nil. +-- Returns smallest area at position and its id or nil. -- If multiple areas have the same volume, larger id takes precedence. function areas:getSmallestAreaAtPos(pos) - local smallest_area, smallest_volume, volume = nil - for _, area in pairs(self:getAreasAtPos(pos)) do + local smallest_area, smallest_id, smallest_volume, volume = nil + for id, area in pairs(self:getAreasAtPos(pos)) do volume = (area.pos2.x - area.pos1.x + 1) * (area.pos2.y - area.pos1.y + 1) * (area.pos2.z - area.pos1.z + 1) if not smallest_volume or smallest_volume >= volume then smallest_area = area + smallest_id = id smallest_volume = volume end end - return smallest_area + return smallest_area, smallest_id end -- Checks if the area is unprotected, open, owned by player From 56763e16f9b262059782935c27adb91bd84a3c99 Mon Sep 17 00:00:00 2001 From: Luke aka SwissalpS Date: Sun, 8 Sep 2024 09:47:40 +0200 Subject: [PATCH 04/10] cleanup as suggested by SmallJoker --- api.lua | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/api.lua b/api.lua index e96d6f5..d872577 100644 --- a/api.lua +++ b/api.lua @@ -98,12 +98,13 @@ end -- Returns smallest area at position and its id or nil. -- If multiple areas have the same volume, larger id takes precedence. function areas:getSmallestAreaAtPos(pos) - local smallest_area, smallest_id, smallest_volume, volume = nil + local smallest_area, smallest_id, volume + local smallest_volume = math.huge for id, area in pairs(self:getAreasAtPos(pos)) do volume = (area.pos2.x - area.pos1.x + 1) * (area.pos2.y - area.pos1.y + 1) * (area.pos2.z - area.pos1.z + 1) - if not smallest_volume or smallest_volume >= volume then + if smallest_volume >= volume then smallest_area = area smallest_id = id smallest_volume = volume From 68e8237fce39a6f5a3f96128dcdd49bfb420e84c Mon Sep 17 00:00:00 2001 From: Luke aka SwissalpS Date: Tue, 17 Sep 2024 14:20:16 +0200 Subject: [PATCH 05/10] make smallest area concept optional --- api.lua | 64 ++++++++++++++++++++++++++++++++++-------------- settingtypes.txt | 3 +++ 2 files changed, 49 insertions(+), 18 deletions(-) diff --git a/api.lua b/api.lua index d872577..e698fea 100644 --- a/api.lua +++ b/api.lua @@ -114,37 +114,65 @@ function areas:getSmallestAreaAtPos(pos) end -- Checks if the area is unprotected, open, owned by player --- or player is part of faction of smallest area at position. +-- or player is part of faction of [smallest] area at position. function areas:canInteract(pos, name) if minetest.check_player_privs(name, self.adminPrivs) then return true end - local area = self:getSmallestAreaAtPos(pos) - -- No area, player owns it or area is open - if not area - or area.owner == name - or area.open - then - return true - elseif areas.factions_available and area.faction_open then - if (factions.version or 0) < 2 then - local faction_name = factions.get_player_faction(name) - if faction_name then + if areas.config.use_smallest_area_precedence then + local area = self:getSmallestAreaAtPos(pos) + -- No area, player owns it or area is open + if not area + or area.owner == name + or area.open + then + return true + elseif areas.factions_available and area.faction_open then + if (factions.version or 0) < 2 then + local faction_name = factions.get_player_faction(name) + if faction_name then + for _, fname in ipairs(area.faction_open or {}) do + if faction_name == fname then + return true + end + end + end + else for _, fname in ipairs(area.faction_open or {}) do - if faction_name == fname then + if factions.player_is_in_faction(fname, name) then return true end end end - else - for _, fname in ipairs(area.faction_open or {}) do - if factions.player_is_in_faction(fname, name) then - return true + end + return false + else + local owned = false + for _, area in pairs(self:getAreasAtPos(pos)) do + if area.owner == name or area.open then + return true + elseif areas.factions_available and area.faction_open then + if (factions.version or 0) < 2 then + local faction_name = factions.get_player_faction(name) + if faction_name then + for _, fname in ipairs(area.faction_open or {}) do + if faction_name == fname then + return true + end + end + end + else + for _, fname in ipairs(area.faction_open or {}) do + if factions.player_is_in_faction(fname, name) then + return true + end + end end end + owned = true end + return not owned end - return false end -- Returns a table (list) of all players that own an area diff --git a/settingtypes.txt b/settingtypes.txt index 9abffa4..09d7036 100644 --- a/settingtypes.txt +++ b/settingtypes.txt @@ -3,6 +3,9 @@ # Static paths do not work well with settings #areas.filename (Configuration file path) string (world_path)/areas.dat +# Use smallest area volume precedence concept. (experimental may change) +areas.use_smallest_area_precedence (Smallest area rules) bool false + # Allow players with a privilege create their own areas using /protect # within the specified size and amount limits. areas.self_protection (Self protection) bool false From e50cc25349c028505d2f347a65cdd694eea041a6 Mon Sep 17 00:00:00 2001 From: Luke aka SwissalpS Date: Sun, 22 Sep 2024 11:10:20 +0200 Subject: [PATCH 06/10] revised description of setting --- settingtypes.txt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/settingtypes.txt b/settingtypes.txt index 09d7036..059bc35 100644 --- a/settingtypes.txt +++ b/settingtypes.txt @@ -4,6 +4,14 @@ #areas.filename (Configuration file path) string (world_path)/areas.dat # Use smallest area volume precedence concept. (experimental may change) +# Determine area access based on the smallest area volume that contains +# the interaction position. Sharing areas is achieved with factions instead +# of using /add_owner. +# This allows players to have private areas within a greater open/shared area +# and also define open/shared areas within those private areas. +# If set to `false`: interacting is allowed if the interaction position +# resides in the players own area, area is open or shared with factions. +# Even if other more restrictive areas enclose the interaction position. areas.use_smallest_area_precedence (Smallest area rules) bool false # Allow players with a privilege create their own areas using /protect From 71ae3c0a6ca80698f364142d80342bceb7a48214 Mon Sep 17 00:00:00 2001 From: Luke aka SwissalpS Date: Sun, 22 Sep 2024 11:29:51 +0200 Subject: [PATCH 07/10] de-duplicate code using table --- api.lua | 53 ++++++++++++++++++----------------------------------- 1 file changed, 18 insertions(+), 35 deletions(-) diff --git a/api.lua b/api.lua index e698fea..17c9bcb 100644 --- a/api.lua +++ b/api.lua @@ -119,60 +119,43 @@ function areas:canInteract(pos, name) if minetest.check_player_privs(name, self.adminPrivs) then return true end + local areas_list if areas.config.use_smallest_area_precedence then - local area = self:getSmallestAreaAtPos(pos) - -- No area, player owns it or area is open - if not area - or area.owner == name - or area.open - then + local smallest_area = self:getSmallestAreaAtPos(pos) + -- No area + if not smallest_area then + return true + end + areas_list = { smallest_area } + else + areas_list = self:getAreasAtPos(pos) + end + local owned = false + for _, area in pairs(areas_list) do + -- Player owns the area or area is open + if area.owner == name or area.open then return true elseif areas.factions_available and area.faction_open then if (factions.version or 0) < 2 then local faction_name = factions.get_player_faction(name) if faction_name then - for _, fname in ipairs(area.faction_open or {}) do + for _, fname in ipairs(area.faction_open) do if faction_name == fname then return true end end end else - for _, fname in ipairs(area.faction_open or {}) do + for _, fname in ipairs(area.faction_open) do if factions.player_is_in_faction(fname, name) then return true end end end end - return false - else - local owned = false - for _, area in pairs(self:getAreasAtPos(pos)) do - if area.owner == name or area.open then - return true - elseif areas.factions_available and area.faction_open then - if (factions.version or 0) < 2 then - local faction_name = factions.get_player_faction(name) - if faction_name then - for _, fname in ipairs(area.faction_open or {}) do - if faction_name == fname then - return true - end - end - end - else - for _, fname in ipairs(area.faction_open or {}) do - if factions.player_is_in_faction(fname, name) then - return true - end - end - end - end - owned = true - end - return not owned + owned = true end + return not owned end -- Returns a table (list) of all players that own an area From 1f770bcbdead83de3c0ff506c91151e87042e380 Mon Sep 17 00:00:00 2001 From: Luke aka SwissalpS Date: Mon, 23 Sep 2024 07:55:37 +0200 Subject: [PATCH 08/10] revised settingtypes.txt thanks SmallJoker --- settingtypes.txt | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/settingtypes.txt b/settingtypes.txt index 059bc35..1ca0d3f 100644 --- a/settingtypes.txt +++ b/settingtypes.txt @@ -3,15 +3,18 @@ # Static paths do not work well with settings #areas.filename (Configuration file path) string (world_path)/areas.dat -# Use smallest area volume precedence concept. (experimental may change) -# Determine area access based on the smallest area volume that contains -# the interaction position. Sharing areas is achieved with factions instead -# of using /add_owner. -# This allows players to have private areas within a greater open/shared area -# and also define open/shared areas within those private areas. -# If set to `false`: interacting is allowed if the interaction position -# resides in the players own area, area is open or shared with factions. -# Even if other more restrictive areas enclose the interaction position. +# Use smallest area volume precedence concept. (experimental; may change) +# +# If set to `true`: +# The interaction permission is defined by the smallest area volume that +# contains the interaction position. Granting access to areas is achieved +# by factions instead of using `/add_owner`. +# This allows players to have private areas within a greater open/shared +# area and also define open/shared areas within those private areas. +# If set to `false`: (default) +# Interacting is permitted if the interaction position resides in any of the +# player's own areas, shared or open areas. +# This permission is not impacted by more restrictive, intersecting areas. areas.use_smallest_area_precedence (Smallest area rules) bool false # Allow players with a privilege create their own areas using /protect From a4a4ff34cc91e7727b1c967cab2de72346013608 Mon Sep 17 00:00:00 2001 From: Luke aka SwissalpS Date: Tue, 24 Sep 2024 09:51:38 +0200 Subject: [PATCH 09/10] whitespace tweak --- api.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/api.lua b/api.lua index 17c9bcb..3c34eaa 100644 --- a/api.lua +++ b/api.lua @@ -101,9 +101,9 @@ function areas:getSmallestAreaAtPos(pos) local smallest_area, smallest_id, volume local smallest_volume = math.huge for id, area in pairs(self:getAreasAtPos(pos)) do - volume = (area.pos2.x - area.pos1.x + 1) - * (area.pos2.y - area.pos1.y + 1) - * (area.pos2.z - area.pos1.z + 1) + volume = (area.pos2.x - area.pos1.x + 1) + * (area.pos2.y - area.pos1.y + 1) + * (area.pos2.z - area.pos1.z + 1) if smallest_volume >= volume then smallest_area = area smallest_id = id From 2b43015b330298599b0f871d57f8ae5018bbb592 Mon Sep 17 00:00:00 2001 From: Luke aka SwissalpS Date: Tue, 24 Sep 2024 10:33:45 +0200 Subject: [PATCH 10/10] shorten code and indicate why var is needed can't do: areas_list = { self:getSmallestAreaAtPos(pos) } because that method returns two values. --- api.lua | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/api.lua b/api.lua index 3c34eaa..8042785 100644 --- a/api.lua +++ b/api.lua @@ -121,11 +121,7 @@ function areas:canInteract(pos, name) end local areas_list if areas.config.use_smallest_area_precedence then - local smallest_area = self:getSmallestAreaAtPos(pos) - -- No area - if not smallest_area then - return true - end + local smallest_area, _ = self:getSmallestAreaAtPos(pos) areas_list = { smallest_area } else areas_list = self:getAreasAtPos(pos)