Allow custom checks before allowing a player to protect new areas (#74)

This commit is contained in:
tour 2024-03-22 22:26:12 +01:00 committed by GitHub
parent c044d49d21
commit 0bad0ec0ae
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 79 additions and 20 deletions

13
api.lua

@ -1,9 +1,22 @@
local hudHandlers = {} local hudHandlers = {}
areas.registered_protection_conditions = {}
areas.registered_on_adds = {} areas.registered_on_adds = {}
areas.registered_on_removes = {} areas.registered_on_removes = {}
areas.registered_on_moves = {} areas.registered_on_moves = {}
areas.callback_origins = {}
function areas:registerProtectionCondition(func)
table.insert(areas.registered_protection_conditions, func)
local debug_info = debug.getinfo(func, "S")
areas.callback_origins[func] = {
mod = core.get_current_modname() or "??",
source = debug_info.short_src or "??",
line = debug_info.linedefined or "??"
}
end
function areas:registerOnAdd(func) function areas:registerOnAdd(func)
table.insert(areas.registered_on_adds, func) table.insert(areas.registered_on_adds, func)
end end

16
api.md

@ -5,11 +5,27 @@ API list
--- ---
* `areas:registerHudHandler(handler)` - Registers a handler to add items to the Areas HUD. See [HUD](#hud). * `areas:registerHudHandler(handler)` - Registers a handler to add items to the Areas HUD. See [HUD](#hud).
* `areas:registerProtectionCondition(func(pos1, pos2, name))` -
See [Protection Conditions](#Protection-Conditions)
* `areas:registerOnAdd(func(id, area))` * `areas:registerOnAdd(func(id, area))`
* `areas:registerOnRemove(func(id))` * `areas:registerOnRemove(func(id))`
* `areas:registerOnMove(func(id, area, pos1, pos2))` * `areas:registerOnMove(func(id, area, pos1, pos2))`
Protection Conditions
---
With `areas:registerProtectionCondition(func(pos1, pos2, name))`
you can register rules to control whether to allow or prohibit the creation of an area.
Return values:
* `true` Forcefully allows the area creation. This overwrites the outcome of any
previously executed conditions, including the default ones registered by this mod.
* `false, errMsg` Disable the creation of the area and return an error message.
* `nil` (or no return value) Enable the creation of the area,
unless specified otherwise by the other registered callbacks.
HUD HUD
--- ---

@ -206,60 +206,90 @@ function areas:getChildren(id)
return children return children
end end
-- Checks if the user has sufficient privileges. -- checks all possible restrictions registered with
-- If the player is not a administrator it also checks -- areas:registerProtectionCondition
-- if the area intersects other areas that they do not own. -- builtin callbacks below
-- Also checks the size of the area and if the user already
-- has more than max_areas.
function areas:canPlayerAddArea(pos1, pos2, name) function areas:canPlayerAddArea(pos1, pos2, name)
local allowed = true
local errMsg
for i=1, #areas.registered_protection_conditions do
local res, msg = areas.registered_protection_conditions[i](pos1, pos2, name)
if res == true then
-- always allow to protect, no matter of other conditions
return true
elseif res == false then
-- there might be another callback that returns true, so we can't break here
allowed = false
-- save the first error that occurred
errMsg = errMsg or msg
elseif res ~= nil then
local origin = areas.callback_origins[areas.registered_protection_conditions[i]]
error("\n[Mod] areas: Invalid api usage from mod '" ..
origin.mod .. "' in callback registerProtectionCondition() at " ..
origin.source .. ":" .. origin.line)
end
end
return allowed, errMsg
end
-- Checks if the user has sufficient privileges.
areas:registerProtectionCondition(function(pos1, pos2, name)
local privs = minetest.get_player_privs(name) local privs = minetest.get_player_privs(name)
if privs.areas then if privs.areas then
-- always allow administrators to create areas
return true return true
end end
-- Check self protection privilege, if it is enabled, -- Check self protection privilege
-- and if the area is too big. if not areas.config.self_protection or
if not self.config.self_protection or
not privs[areas.config.self_protection_privilege] then not privs[areas.config.self_protection_privilege] then
return false, S("Self protection is disabled or you do not have" return false, S("Self protection is disabled or you do not have"
.." the necessary privilege.") .." the necessary privilege.")
end end
end)
-- check if the area is too big
areas:registerProtectionCondition(function(pos1, pos2, name)
local privs = minetest.get_player_privs(name)
local max_size = privs.areas_high_limit and local max_size = privs.areas_high_limit and
self.config.self_protection_max_size_high or areas.config.self_protection_max_size_high or
self.config.self_protection_max_size areas.config.self_protection_max_size
if if
(pos2.x - pos1.x + 1) > max_size.x or (pos2.x - pos1.x + 1) > max_size.x or
(pos2.y - pos1.y + 1) > max_size.y or (pos2.y - pos1.y + 1) > max_size.y or
(pos2.z - pos1.z + 1) > max_size.z then (pos2.z - pos1.z + 1) > max_size.z then
return false, S("Area is too big.") return false, S("Area is too big.")
end end
end)
-- Check number of areas the user has and make sure it not above the max -- Check number of areas the user has and make sure it not above the max
areas:registerProtectionCondition(function(pos1, pos2, name)
local privs = minetest.get_player_privs(name)
local count = 0 local count = 0
for _, area in pairs(self.areas) do for _, area in pairs(areas.areas) do
if area.owner == name then if area.owner == name then
count = count + 1 count = count + 1
end end
end end
local max_areas = privs.areas_high_limit and local max_areas = privs.areas_high_limit and
self.config.self_protection_max_areas_high or areas.config.self_protection_max_areas_high or
self.config.self_protection_max_areas areas.config.self_protection_max_areas
if count >= max_areas then if count >= max_areas then
return false, S("You have reached the maximum amount of" return false, S("You have reached the maximum amount of"
.." areas that you are allowed to protect.") .." areas that you are allowed to protect.")
end end
end)
-- Check intersecting areas -- checks if the area intersects other areas that the player do not own.
local can, id = self:canInteractInArea(pos1, pos2, name) areas:registerProtectionCondition(function(pos1, pos2, name)
local can, id = areas:canInteractInArea(pos1, pos2, name)
if not can then if not can then
local area = self.areas[id] local area = areas.areas[id]
return false, S("The area intersects with @1 [@2] (@3).", return false, S("The area intersects with @1 [@2] (@3).",
area.name, id, area.owner) area.name, id, area.owner)
end end
end)
return true
end
-- Given a id returns a string in the format: -- Given a id returns a string in the format:
-- "name [id]: owner (x1, y1, z1) (x2, y2, z2) -> children" -- "name [id]: owner (x1, y1, z1) (x2, y2, z2) -> children"