Compare commits

..

16 Commits

Author SHA1 Message Date
2184118a4b Fix crash 2024-09-15 23:09:05 +02:00
0c9815460a Merge remote-tracking branch 'upstream/master' 2024-09-15 08:24:21 +02:00
Luke aka SwissalpS
c2e3d073be
Use smallest area at given position (#79)
When checking for permission to interact, currently the smallest id takes precedence in a situation where areas enclose other areas. This makes it complicated to set up private areas within faction areas and vice versa. Same applies for open areas within a bigger private area.

When multiple areas have the same volume, players seem to agree that the most recently protected area should also take precedence.
Since we can't guarantee that the largest id is the most recent, we still use that info as we have no other way to determine age.
2024-09-11 22:00:47 +02:00
1F616EMO~nya
9a5cdb2822
Allow relative coordinates in /area_pos[12] (#77) 2024-08-07 21:33:36 +02:00
1F616EMO~nya
9024be24eb
Fix deprecated hud_elem_type field warning (#78)
Co-authored-by: cx384 <cx384@proton.me>
2024-07-17 18:18:21 +02:00
Alexander Chibrikin
2deb6770f4
Add russian translation (#68)
* Add ru locale.

* Fixed review remarks

---------

Co-authored-by: ssdaniel24 <bo7oaonteg2m@mail.ru>
2024-06-13 17:26:00 +02:00
tour
0bad0ec0ae
Allow custom checks before allowing a player to protect new areas (#74) 2024-03-22 22:26:12 +01:00
SmallJoker
c044d49d21
Short summary print in /list_areas for admins (#72) 2024-02-24 11:46:45 +01:00
1F616EMO~nya
2c900ef2cd
zh_TW and zh_CN translation (#71) 2024-02-15 18:35:43 +01:00
fluxionary
f4bb8eb29b
Include the endpoint position in the area size check (#70) 2024-02-09 21:25:23 +01:00
2fda1adbd7 Merge remote-tracking branch 'upstream/master' 2023-11-22 23:04:43 +01:00
Niklp
cba647225c
Add missing placeholder in French translation (#66) 2023-08-28 12:22:40 +02:00
fluxionary
c8cf4aba92
Fix orthography (it's -> its) (#65) 2023-08-26 11:40:59 +02:00
64b19c2594 Merge remote-tracking branch 'upstream/master' 2023-06-04 23:07:43 +02:00
fluxionary
d464d3484f
Fix chat command typo (#64) 2022-11-07 19:59:25 +01:00
a8cacee8cc Fixed a minor bug introduced when I created openfarming, which skips the faction test if an area is openfarming.
And not return false if not a player(ie:mobs api) or unknown node, continue iterate on others areas(minor bug, generaly if 1 area it's protected).
2022-07-09 02:49:12 +02:00
13 changed files with 663 additions and 92 deletions

View File

@ -87,7 +87,7 @@ Commands
* `/remove_area <ID>` -- Removes an area that you own. Any sub-areas of that * `/remove_area <ID>` -- Removes an area that you own. Any sub-areas of that
area are made sub-areas of the removed area's parent, if it exists. area are made sub-areas of the removed area's parent, if it exists.
If the removed area has no parent it's sub-areas will have no parent. If the removed area has no parent its sub-areas will have no parent.
* `/recursive_remove_areas <ID>` -- Removes an area and all sub-areas of it. * `/recursive_remove_areas <ID>` -- Removes an area and all sub-areas of it.

83
api.lua
View File

@ -19,10 +19,23 @@ local plants = {
["morefarming:seed_carrot"]="air", ["morefarming:seed_corn"]="air", ["morefarming:seed_carrot"]="air", ["morefarming:seed_corn"]="air",
} }
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
@ -101,21 +114,42 @@ function areas:getAreasIntersectingArea(pos1, pos2)
return res return res
end end
-- Checks if the area is unprotected or owned by you -- 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, 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 smallest_volume >= volume then
smallest_area = area
smallest_id = id
smallest_volume = volume
end
end
return smallest_area, smallest_id
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) function areas:canInteract(pos, name)
if minetest.check_player_privs(name, self.adminPrivs) then if minetest.check_player_privs(name, self.adminPrivs) then
return true return true
end end
local owned = false local area = self:getSmallestAreaAtPos(pos)
for _, area in pairs(self:getAreasAtPos(pos)) do -- No area, player owns it or area is open
if area.owner == name or area.open then if not area
return true or area.owner == name
elseif area.openfarming then or area.open
-- if area is openfarming then
local node = minetest.get_node(pos).name return true
if not minetest.registered_nodes[node] then return false end elseif area.openfarming then
local player = minetest.get_player_by_name(name) -- if area is openfarming
if not player then return false end local player = minetest.get_player_by_name(name)
local node = minetest.get_node(pos).name
if player and minetest.registered_nodes[node] then
local wstack = player:get_wielded_item():get_name() local wstack = player:get_wielded_item():get_name()
if wstack == "" then wstack = "hand" end if wstack == "" then wstack = "hand" end
@ -128,27 +162,26 @@ function areas:canInteract(pos, name)
if plants[wstack] ~= nil and plants[wstack] == node then if plants[wstack] ~= nil and plants[wstack] == node then
return true return true
end end
elseif areas.factions_available and area.faction_open then end
if (factions.version or 0) < 2 then elseif areas.factions_available and area.faction_open then
local faction_name = factions.get_player_faction(name) if (factions.version or 0) < 2 then
if faction_name then local faction_name = factions.get_player_faction(name)
for _, fname in ipairs(area.faction_open or {}) do if faction_name then
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 or {}) do
if factions.player_is_in_faction(fname, name) then if faction_name == fname then
return true return true
end end
end 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 end
return not owned return false
end end
-- Returns a table (list) of all players that own an area -- Returns a table (list) of all players that own an area

16
api.md
View File

@ -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
--- ---

View File

@ -71,7 +71,7 @@ minetest.register_chatcommand("set_owner", {
minetest.register_chatcommand("add_owner", { minetest.register_chatcommand("add_owner", {
params = S("<ParentID>").." "..S("<PlayerName>").." "..S("<AreaName>"), params = S("<ParentID>").." "..S("<PlayerName>").." "..S("<AreaName>"),
description = S("Give a player access to a sub-area beetween two" description = S("Give a player access to a sub-area between two"
.." positions that have already been protected," .." positions that have already been protected,"
.." Use set_owner if you don't want the parent to be set."), .." Use set_owner if you don't want the parent to be set."),
func = function(name, param) func = function(name, param)
@ -173,13 +173,46 @@ minetest.register_chatcommand("find_areas", {
minetest.register_chatcommand("list_areas", { minetest.register_chatcommand("list_areas", {
description = S("List your areas, or all areas if you are an admin."), params = S("[<name>]"),
description = S("List your areas. Admins can list all areas or those of a specific player."),
func = function(name, param) func = function(name, param)
local admin = minetest.check_player_privs(name, areas.adminPrivs) local admin = minetest.check_player_privs(name, areas.adminPrivs)
local admin_show_summary = admin
local owner_name = name
if admin and #param > 0 then
owner_name = param
admin_show_summary = false
end
local areaStrings = {} local areaStrings = {}
for id, area in pairs(areas.areas) do if admin_show_summary then
if admin or areas:isAreaOwner(id, name) then -- Summary per-player
table.insert(areaStrings, areas:toString(id)) local indices = {}
local counts = {} -- { [1] = name, [2] = count }, ...
for _, area in pairs(areas.areas) do
local i = indices[area.owner]
if i then
counts[i][2] = counts[i][2] + 1
else
table.insert(counts, { area.owner, 1 })
indices[area.owner] = #counts
end
end
-- Alphabatical name sorting
table.sort(counts, function (kv_a, kv_b)
return kv_a[1] < kv_b[1]
end)
-- Output
for _, kv in ipairs(counts) do
table.insert(areaStrings, S("@1 : @2 area(s)", kv[1], kv[2]))
end
else
-- Detailed list
for id, area in pairs(areas.areas) do
if areas:isAreaOwner(id, owner_name) then
table.insert(areaStrings, areas:toString(id))
end
end end
end end
if #areaStrings == 0 then if #areaStrings == 0 then
@ -207,7 +240,7 @@ minetest.register_chatcommand("recursive_remove_areas", {
areas:remove(id, true) areas:remove(id, true)
areas:save() areas:save()
return true, S("Removed area @1 and it's sub areas.", id) return true, S("Removed area @1 and its sub areas.", id)
end end
}) })

View File

@ -66,7 +66,7 @@ minetest.register_globalstep(function(dtime)
hud = {} hud = {}
areas.hud[name] = hud areas.hud[name] = hud
hud.areasId = player:hud_add({ hud.areasId = player:hud_add({
hud_elem_type = "text", [minetest.features.hud_def_type_field and "type" or "hud_elem_type"] = "text", -- compatible with older versions
name = "Areas", name = "Areas",
number = 0xFFFFFF, number = 0xFFFFFF,
position = {x=0, y=1}, position = {x=0, y=1},

View File

@ -118,7 +118,7 @@ function areas:add(owner, name, pos1, pos2, parent)
return id return id
end end
--- Remove a area, and optionally it's children recursively. --- Remove a area, and optionally its children recursively.
-- If a area is deleted non-recursively the children will -- If a area is deleted non-recursively the children will
-- have the removed area's parent as their new parent. -- have the removed area's parent as their new parent.
function areas:remove(id, recurse) function areas:remove(id, recurse)
@ -195,7 +195,7 @@ function areas:isSubarea(pos1, pos2, id)
end end
end end
-- Returns a table (list) of children of an area given it's identifier -- Returns a table (list) of children of an area given its identifier
function areas:getChildren(id) function areas:getChildren(id)
local children = {} local children = {}
for cid, area in pairs(self.areas) do for cid, area in pairs(self.areas) do
@ -206,62 +206,93 @@ 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)
-- MFF: megabuilders skip checks on size and number of areas -- check if the area is too big
-- NALC: megabuilders skip checks on size and number of areas
areas:registerProtectionCondition(function(pos1, pos2, name)
local privs = minetest.get_player_privs(name)
if not privs.megabuilder then if not privs.megabuilder then
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) > max_size.x or (pos2.x - pos1.x + 1) > max_size.x or
(pos2.y - pos1.y) > max_size.y or (pos2.y - pos1.y + 1) > max_size.y or
(pos2.z - pos1.z) > 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 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
local count = 0 areas:registerProtectionCondition(function(pos1, pos2, name)
for _, area in pairs(self.areas) do local privs = minetest.get_player_privs(name)
if area.owner == name then local count = 0
count = count + 1 for _, area in pairs(areas.areas) do
end if area.owner == name then
count = count + 1
end end
local max_areas = privs.areas_high_limit and end
self.config.self_protection_max_areas_high or local max_areas = privs.areas_high_limit and
self.config.self_protection_max_areas areas.config.self_protection_max_areas_high or
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
return true end)
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"

View File

@ -27,7 +27,7 @@ Faction doesn't exists=La faction n'existe pas
Find areas using a Lua regular expression=Trouve les zones en utilisant une expression régulière Lua. Find areas using a Lua regular expression=Trouve les zones en utilisant une expression régulière Lua.
Get information about area configuration and usage.=Obtient des informations sur la configuration des zones et lutilisation des zones. Get information about area configuration and usage.=Obtient des informations sur la configuration des zones et lutilisation des zones.
Give a player access to a sub-area beetween two positions that have already been protected, Use set_owner if you don't want the parent to be set.=Donne au joueur accès aux sous-zones entre deux positions qui ont déjà été protégées ; utilisez set_owner si vous ne voulez pas que la zone pricipale soit définie. Give a player access to a sub-area between two positions that have already been protected, Use set_owner if you don't want the parent to be set.=Donne au joueur accès aux sous-zones entre deux positions qui ont déjà été protégées ; utilisez set_owner si vous ne voulez pas que la zone pricipale soit définie.
Invalid regular expression.=Expression régulière invalide. Invalid regular expression.=Expression régulière invalide.
Limit: @1 areas=Limite: @1 zones. Limit: @1 areas=Limite: @1 zones.
@ -45,7 +45,7 @@ Protect your own area=Protège votre zone.
Recursively remove areas using an ID=Supprime les zones récursivement en utilisant un ID. Recursively remove areas using an ID=Supprime les zones récursivement en utilisant un ID.
Remove an area using an ID=Supprime une zone en utilisant son ID. Remove an area using an ID=Supprime une zone en utilisant son ID.
Removed area @1=Zone @1 supprimée. Removed area @1=Zone @1 supprimée.
Removed area @1 and it's sub areas.=Zone @1 et ses sous-zones supprimées. Removed area @1 and its sub areas.=Zone @1 et ses sous-zones supprimées.
Removes all ownerless areas=Supprime toutes les zones sans propriétaire Removes all ownerless areas=Supprime toutes les zones sans propriétaire
Rename an area that you own=Renomme une zone qui vous appartient. Rename an area that you own=Renomme une zone qui vous appartient.
Self protection is disabled.=Lautoprotection est désactivée. Self protection is disabled.=Lautoprotection est désactivée.
@ -123,7 +123,7 @@ Area position @1 set to @2=Position @1 de la zone définie à @2.
Position @1 set to @2=Position @1 définie à @2. Position @1 set to @2=Position @1 définie à @2.
Position @1: =Position @1 : Position @1: =Position @1 :
Select an area by ID.=Sélectionnez une zone par son ID. Select an area by ID.=Sélectionnez une zone par son ID.
Select position @1 by punching a node.=Sélectionnez une position en frappant un bloc. Select position @1 by punching a node.=Sélectionnez une position @1 en frappant un bloc.
Select positions by punching two nodes.=Sélectionnez une position en frappant deux blocs. Select positions by punching two nodes.=Sélectionnez une position en frappant deux blocs.
Set area protection region position @1 to your location or the one specified=Définit la position @1 de la région de protection de zone à votre position ou à celle spécifiée. Set area protection region position @1 to your location or the one specified=Définit la position @1 de la région de protection de zone à votre position ou à celle spécifiée.
@ -133,3 +133,5 @@ Set area protection region, position 1, or position 2 by punching nodes, or disp
The area @1 does not exist.=La zone @1 nexiste pas. The area @1 does not exist.=La zone @1 nexiste pas.
Unable to get position.=Impossible dobtenir la position. Unable to get position.=Impossible dobtenir la position.
Unknown subcommand: @1=Sous-commande inconnue : @1 Unknown subcommand: @1=Sous-commande inconnue : @1
Relative coordinates is not supported on this server. Please upgrade Minetest to 5.7.0 or newer versions.=

View File

@ -27,7 +27,7 @@ Faction doesn't exists=La fazione non esiste
Find areas using a Lua regular expression=Trova aree usando una espressione regolare Lua Find areas using a Lua regular expression=Trova aree usando una espressione regolare Lua
Get information about area configuration and usage.=Ottieni informazioni sulla configurazione e l'uso delle aree. Get information about area configuration and usage.=Ottieni informazioni sulla configurazione e l'uso delle aree.
Give a player access to a sub-area beetween two positions that have already been protected, Use set_owner if you don't want the parent to be set.=Dai a un giocatore l'accesso a una sotto-area tra due posizioni che sono già state protette, usa set_owner se non vuoi che sia impostato il parent. Give a player access to a sub-area between two positions that have already been protected, Use set_owner if you don't want the parent to be set.=Dai a un giocatore l'accesso a una sotto-area tra due posizioni che sono già state protette, usa set_owner se non vuoi che sia impostato il parent.
Invalid regular expression.=Espressione regolare non valida. Invalid regular expression.=Espressione regolare non valida.
Limit: @1 areas=Limite: @1 aree Limit: @1 areas=Limite: @1 aree
@ -45,7 +45,7 @@ Protect your own area=Proteggi la tua area
Recursively remove areas using an ID=Elimina ricorsivamente delle aree usando un ID Recursively remove areas using an ID=Elimina ricorsivamente delle aree usando un ID
Remove an area using an ID=Elimina un'area usando un ID Remove an area using an ID=Elimina un'area usando un ID
Removed area @1=Eliminata l'area @1 Removed area @1=Eliminata l'area @1
Removed area @1 and it's sub areas.=Eliminata l'area @1 e le sue sotto-aree. Removed area @1 and its sub areas.=Eliminata l'area @1 e le sue sotto-aree.
Removes all ownerless areas= Removes all ownerless areas=
Rename an area that you own=Rinomina un'area che ti appartiene Rename an area that you own=Rinomina un'area che ti appartiene
Self protection is disabled.=L'auto-protezione è disattivata. Self protection is disabled.=L'auto-protezione è disattivata.
@ -133,3 +133,5 @@ Set area protection region, position 1, or position 2 by punching nodes, or disp
The area @1 does not exist.=L'area @1 non esiste. The area @1 does not exist.=L'area @1 non esiste.
Unable to get position.=Impossibile ottenere la posizione. Unable to get position.=Impossibile ottenere la posizione.
Unknown subcommand: @1=Sotto-comando sconosciuto: @1 Unknown subcommand: @1=Sotto-comando sconosciuto: @1
Relative coordinates is not supported on this server. Please upgrade Minetest to 5.7.0 or newer versions.=

137
locale/areas.ru.tr Normal file
View File

@ -0,0 +1,137 @@
# textdomain: areas
### chatcommands.lua ###
<AreaName>=<имя_территории>
<ID> [faction_name]=<ID> [имя_фракции]
<NewOwner>=<новый_владелец>
<ParentID>=<ID_родительской>
<PlayerName>=<имя_игрока>
<newName>=<новое_имя>
@1 has given you control over the area "@2" (ID @3).=@1 передал вам территорию "@2" (ID @3).
@1 spanning up to @2x@3x@4.=@1 размером до @2x@3x@4.
A regular expression is required.=Не указано регулярное выражение.
Area @1 does not exist or is not owned by you.=Территория @1 не существует или Вы не имеете к ней доступа.
Area closed for faction members.=Территория закрыта для игроков из фракций.
Area closed.=Территория закрыта.
Area does not exist.=Территория не существует.
Area is open for members of: @1=Территория открыта для игроков из фракций: @1
Area opened.=Территория открыта.
Area protected. ID: @1=Территория защищена. ID: @1
Area renamed.=Территория переименована.
Area successfully moved.=Территория успешно перенесена.
Change the owner of an area using its ID=Изменить владельца территории по её ID
Faction doesn't exists=Фракция не существует.
Find areas using a Lua regular expression=Поиск территорий с использованием регулярных выражений Lua
Get information about area configuration and usage.=Получить информацию о конфигурации и использовании защиты территорий.
Give a player access to a sub-area between two positions that have already been protected, Use set_owner if you don't want the parent to be set.=Дать игроку доступ к выделенной территории, создав дополнительный регион. Используйте set_owner, если вы не хотите привязки к родительской территории.
Invalid regular expression.=Неверное регулярное выражение.
Limit: @1 areas=Ограничение: @1 территорий(я)
Limit: no area count limit=Ограничение: нет ограничений на кол-во территорий
List your areas, or all areas if you are an admin.=Вывести список доступных Вам территорий или всех существующих территорий, если вы администратор.
Move (or resize) an area to the current positions.=Переместить (или изменить размер) территории.
No matches found.=Совпадений не найдено.
No visible areas.=Нет доступных территорий.
Owner changed.=Владелец изменён.
Players with the "@1" privilege can protect up to @2 areas=Игроки, имеющие привилегию "@1" могут защищать до @2 территорий
Protect an area between two positions and give a player access to it without setting the parent of the area to any existing area=Защитить территорию между двумя позициями и дать игроку доступ к ней без привязки к родительскому региону.
Protect your own area=Защитить вашу территорию
Recursively remove areas using an ID=Рекурсивное удаление территорий (вместе с дочерними) по его ID
Remove an area using an ID=Удаление территории по его ID
Removed area @1=Удалена территория @1
Removed area @1 and its sub areas.=Удалена территория @1 и её дочерние территории.
Removes all ownerless areas=Удалить все бесхозные территории (без владельца)
Rename an area that you own=Переименовать территорию, которой вы владеете.
Self protection is disabled.=Защита своих территорий отключена.
Self protection is enabled.=Защита своих территорий включена.
That area doesn't exist.=Территория не существует.
The player "@1" does not exist.=Игрок "@1" не существует.
Toggle an area open (anyone can interact) or closed=Открыть/закрыть территорию для других игроков
Toggle an area open/closed for members in your faction.=Открыть/закрыть территорию для игроков вашей фракции.
You are an area administrator ("areas" privilege).=Вы можете управлять всеми территориями (привилегия "areas")
You can protect areas=Вы можете защищать территории
You can't protect that area.=Вы не можете установить защиту на эту территорию.
You can't protect that area: @1=Вы не можете установить защиту на территорию: @1
You don't have the necessary privilege ("@1").=У Вас нет необходимой привилегии ("@1").
You don't own that area.=Вы не являетесь владельцем этой территории.
You have @1 areas.=У вас @1 территорий.
You have been granted control over area #@1. Type /list_areas to show your areas.=Вам выдан доступ к территории #@1.
You have extended area protection limits ("areas_high_limit" privilege).=У вас увеличенный лимит на кол-во создаваемых вами защищённых территорий
You have the necessary privilege ("@1").=У вас есть необходимая привилегия ("@1").
You need to select an area first.=Сначала необходимо выделить территорию.
### chatcommands.lua ###
### pos.lua ###
<ID>=
Invalid usage, see /help @1.=Неверное использование, см. /help @1.
### hud.lua ###
:open=:открытая
Areas:=Территории:
### init.lua ###
Can administer areas.=Может управлять территориями.
Can protect areas.=Может создавать защищённые территории.
Can protect more, bigger areas.=Может создавать защищённые территории больше территорий и с бОльшим размером.
### interact.lua ###
@1 is protected by @2.=@1 - принадлежит @2.
### internal.lua ###
Area is too big.=Территория слишком велика.
Self protection is disabled or you do not have the necessary privilege.=Возможность защиты территорий отключена или же Вы не имеете необходимых привилегий.
The area intersects with @1 [@2] (@3).=Территория пересекается с @1 [@2] (@3).
You have reached the maximum amount of areas that you are allowed to protect.=Вы достигли максимально допустимого количества на создание защищённых территорий.
### legacy.lua ###
<version>=<версия>
Converted areas saved. Done.=Готово. Сконвертированные территории сохранены.
Converting areas…=Конвертирование территорий…
Error loading legacy file: @1=Ошибка загрузки файла с устаревшим форматом: @1
Invalid version number. (0 allowed)=Неверный номер версии. (поддерживается 0)
Legacy file loaded.=Файл с устаревшим форматом загружен.
Loads, converts, and saves the areas from a legacy save file.=Загружает, конвертирует и сохраняет территории из файла с устаревшим форматом.
Table format updated.=Формат обновлён.
unnamed=без_названия
### pos.lua ###
<not set>=<не_установлена>
Area @1 selected.=Территория @1 выбрана.
Area position @1 set to @2=Позиция @1 установлена в @2
Position @1 set to @2=Позиция @1 установлена в @2
Position @1: =Позиция @1:
Select an area by ID.=Выбрать территорию по её ID.
Select position @1 by punching a node.=Установите позицию @1, ударив по блоку.
Select positions by punching two nodes.=Установите позиции, ударив по двум блокам.
Set area protection region position @1 to your location or the one specified=Установить позицию @1 для выбора защищаемой территории
Set area protection region, position 1, or position 2 by punching nodes, or display the region=Установить позиции 1 и/или 2, ударяя по блокам, или вывести ранее установленные позиции
The area @1 does not exist.=Территория @1 не существует.
Unable to get position.=Не удалось получить позицию.
Unknown subcommand: @1=Неизвестная под-команда/аргумент.
Relative coordinates is not supported on this server. Please upgrade Minetest to 5.7.0 or newer versions.=

137
locale/areas.zh_CN.tr Normal file
View File

@ -0,0 +1,137 @@
# textdomain: areas
### chatcommands.lua ###
<AreaName>=<保护区名称>
<ID> [faction_name]=<保护区编号> [派系名称]
<NewOwner>=<新拥有者>
<ParentID>=<上级保护区编号>
<PlayerName>=<玩家名称>
<newName>=<新名称>
@1 has given you control over the area "@2" (ID @3).=@1 已将保护区“@2”编号 @3的控制权交与您。
@1 spanning up to @2x@3x@4.=@1最大为 @2x@3x@4。
A regular expression is required.=需要正则表达式。
Area @1 does not exist or is not owned by you.=保护区 @1 不存在,或并非由您拥有。
Area closed for faction members.=保护区已对派系成员关闭。
Area closed.=保护区已关闭。
Area does not exist.=保护区不存在。
Area is open for members of: @1=保护区已对以下派系的成员开放:@1
Area opened.=保护区已开放。
Area protected. ID: @1=成功进行保护。 保护区编号:@1
Area renamed.=保护区已重新命名。
Area successfully moved.=成功移动保护区。
Change the owner of an area using its ID=通过保护区编号改变其拥有者
Faction doesn't exists=派系不存在
Find areas using a Lua regular expression=使用 Lua 正则表达式寻找保护区
Get information about area configuration and usage.=获得保护区配置与使用的资讯。
Give a player access to a sub-area between two positions that have already been protected, Use set_owner if you don't want the parent to be set.=授予其他玩家已有保护区内一部分地方、两个座标之间区域的的存取权。如果不想上级保护区被设定,请使用 /set_owner。
Invalid regular expression.=正则表达式无效。
Limit: @1 areas=限制:@1个保护区
Limit: no area count limit=限制:无数量限制
List your areas, or all areas if you are an admin.=列出您拥有的保护区,或对于管理员而言,列出所有保护区。
Move (or resize) an area to the current positions.=移动一保护区至目前座标,或改变其大小。
No matches found.=找不到匹配项。
No visible areas.=没有保护区可供查阅。
Owner changed.=拥有者已修改。
Players with the "@1" privilege can protect up to @2 areas=拥有“@1”权限的玩家最多可以保护 @2 个保护区
Protect an area between two positions and give a player access to it without setting the parent of the area to any existing area=授予其他玩家两个座标之间区域的控制权,而不设定上级保护区
Protect your own area=对您自己的地区施加保护
Recursively remove areas using an ID=通过保护区编号移除保护区以及其所有子保护区
Remove an area using an ID=通过保护区编号移除一保护区
Removed area @1=保护区 @1 已移除
Removed area @1 and its sub areas.=保护区 @1 以及其所有子保护区已移除。
Removes all ownerless areas=移除所有无主保护区
Rename an area that you own=重新命名您拥有的保护区
Self protection is disabled.=自我保护被禁用。
Self protection is enabled.=自我保护被启用。
That area doesn't exist.=保护区不存在。
The player "@1" does not exist.=玩家“@1”不存在。
Toggle an area open (anyone can interact) or closed=切换保护区开放状态(如开放,所有玩家均可互动)
Toggle an area open/closed for members in your faction.=切换保护区对派系成员的开放状态
You are an area administrator ("areas" privilege).=您是保护区管理员拥有“area”权限
You can protect areas=您可以建立保护区
You can't protect that area.=您无法保护该区域。
You can't protect that area: @1=您无法保护该区域:@1
You don't have the necessary privilege ("@1").=您没有所需权限(“@1”
You don't own that area.=您并不拥有该保护区。
You have @1 areas.=您有 @1 个保护区。
You have been granted control over area #@1. Type /list_areas to show your areas.=您已被授予保护区 #@1 的控制权。 使用 /list_areas 以查看您的保护区。
You have extended area protection limits ("areas_high_limit" privilege).=您拥有延伸保护权限拥有“areas_high_limit”权限
You have the necessary privilege ("@1").=您拥有所需权限(“@1”
You need to select an area first.=请先选择范围。
### chatcommands.lua ###
### pos.lua ###
<ID>=<保护区编号>
Invalid usage, see /help @1.=无效用法,请参见 /help @1。
### hud.lua ###
:open=:开放
Areas:=保护区:
### init.lua ###
Can administer areas.=可以管理保护区
Can protect areas.=可以进行保护
Can protect more, bigger areas.=进行保护时,数量以及体积上限提高。
### interact.lua ###
@1 is protected by @2.=@1 被 @2 保护。
### internal.lua ###
Area is too big.=区域过大。
Self protection is disabled or you do not have the necessary privilege.=自我保护被禁用,或您没有所需权限。
The area intersects with @1 [@2] (@3).=区域与 @1 [@2] (@3) 重叠。
You have reached the maximum amount of areas that you are allowed to protect.=您的现有保护区数量已达到所允许的上限。
### legacy.lua ###
<version>=<版本>
Converted areas saved. Done.=转换后的保护区已经保存。 完成。
Converting areas…=正在转换保护区……
Error loading legacy file: @1=载入旧档案时发生错误:@1
Invalid version number. (0 allowed)=无效版本号。允许值0
Legacy file loaded.=旧档案已载入。
Loads, converts, and saves the areas from a legacy save file.=载入、转换并储存旧存档中的保护区。
Table format updated.=表格格式已更新。
unnamed=未命名
### pos.lua ###
<not set>=<未设定>
Area @1 selected.=保护区 @1 已选择。
Area position @1 set to @2=保护区座标 @1 已设定为 @2。
Position @1 set to @2=保护区座标 @1 已设定为 @2。
Position @1: =保护区座标 @1
Select an area by ID.=通过保护区编号选择区域
Select position @1 by punching a node.=请击打方块以设定保护区座标 @1 的位置。
Select positions by punching two nodes.=请击打两个方块,以设定保护区座标的位置。
Set area protection region position @1 to your location or the one specified=将保护区座标 @1 的位置设定为您目前的位置或提供的座标
Set area protection region, position 1, or position 2 by punching nodes, or display the region=击打方块设定保护区座标,或获得其座标资讯
The area @1 does not exist.=保护区 @1 不存在。
Unable to get position.=无法获得座标。
Unknown subcommand: @1=子指令不明:@1
Relative coordinates is not supported on this server. Please upgrade Minetest to 5.7.0 or newer versions.=此服务器不支援相对座标。请更新Minetest至5.7.0或之后的版本。

137
locale/areas.zh_TW.tr Normal file
View File

@ -0,0 +1,137 @@
# textdomain: areas
### chatcommands.lua ###
<AreaName>=<保護區名稱>
<ID> [faction_name]=<保護區編號> [派系名稱]
<NewOwner>=<新擁有者>
<ParentID>=<上級保護區編號>
<PlayerName>=<玩家名稱>
<newName>=<新名稱>
@1 has given you control over the area "@2" (ID @3).=@1 已將保護區「@2」編號 @3的控制權交與您。
@1 spanning up to @2x@3x@4.=@1最大爲 @2x@3x@4。
A regular expression is required.=需要正則表達式。
Area @1 does not exist or is not owned by you.=保護區 @1 不存在,或並非由您擁有。
Area closed for faction members.=保護區已對派系成員關閉。
Area closed.=保護區已關閉。
Area does not exist.=保護區不存在。
Area is open for members of: @1=保護區已對以下派系的成員開放:@1
Area opened.=保護區已開放。
Area protected. ID: @1=成功進行保護。保護區編號:@1
Area renamed.=保護區已重新命名。
Area successfully moved.=成功移動保護區。
Change the owner of an area using its ID=通過保護區編號改變其擁有者
Faction doesn't exists=派系不存在
Find areas using a Lua regular expression=使用 Lua 正則表達式尋找保護區
Get information about area configuration and usage.=獲得保護區配置與使用的資訊。
Give a player access to a sub-area between two positions that have already been protected, Use set_owner if you don't want the parent to be set.=授予其他玩家已有保護區內一部分地方、兩個座標之間區域的的存取權。如果不想上級保護區被設定,請使用 /set_owner。
Invalid regular expression.=正則表達式無效。
Limit: @1 areas=限制:@1個保護區
Limit: no area count limit=限制:無數量限制
List your areas, or all areas if you are an admin.=列出您擁有的保護區,或對於管理員而言,列出所有保護區。
Move (or resize) an area to the current positions.=移動一保護區至目前座標,或改變其大小。
No matches found.=找不到匹配項。
No visible areas.=沒有保護區可供查閱。
Owner changed.=擁有者已修改。
Players with the "@1" privilege can protect up to @2 areas=擁有「@1」權限的玩家最多可以保護 @2 個保護區
Protect an area between two positions and give a player access to it without setting the parent of the area to any existing area=授予其他玩家兩個座標之間區域的控制權,而不設定上級保護區
Protect your own area=對您自己的地區施加保護
Recursively remove areas using an ID=通過保護區編號移除保護區以及其所有子保護區
Remove an area using an ID=通過保護區編號移除一保護區
Removed area @1=保護區 @1 已移除
Removed area @1 and its sub areas.=保護區 @1 以及其所有子保護區已移除
Removes all ownerless areas=移除所有無主保護區
Rename an area that you own=重新命名您擁有的保護區
Self protection is disabled.=自我保護被禁用。
Self protection is enabled.=自我保護被啓用。
That area doesn't exist.=保護區不存在。
The player "@1" does not exist.=玩家「@1」不存在。
Toggle an area open (anyone can interact) or closed=切換保護區開放狀態(如開放,所有玩家均可互動)
Toggle an area open/closed for members in your faction.=切換保護區對派系成員的開放狀態
You are an area administrator ("areas" privilege).=您是保護區管理員擁有「area」權限
You can protect areas=您可以建立保護區
You can't protect that area.=您無法保護該區域。
You can't protect that area: @1=您無法保護該區域:@1
You don't have the necessary privilege ("@1").=您沒有所需權限(「@1」
You don't own that area.=您並不擁有改保護區。
You have @1 areas.=您有 @1 個保護區。
You have been granted control over area #@1. Type /list_areas to show your areas.=您已被授予保護區 #@1 的控制權。使用 /list_areas 以查看您的保護區。
You have extended area protection limits ("areas_high_limit" privilege).=您擁有延伸保護權限擁有「areas_high_limit」權限
You have the necessary privilege ("@1").=您擁有所需權限(「@1」
You need to select an area first.=請先選擇範圍。
### chatcommands.lua ###
### pos.lua ###
<ID>=<保護區編號>
Invalid usage, see /help @1.=無效用法,請參見 /help @1。
### hud.lua ###
:open=:開放
Areas:=保護區:
### init.lua ###
Can administer areas.=可以管理保護區
Can protect areas.=可以進行保護
Can protect more, bigger areas.=進行保護時,數量以及體積上限提高。
### interact.lua ###
@1 is protected by @2.=@1 被 @2 保護。
### internal.lua ###
Area is too big.=區域過大。
Self protection is disabled or you do not have the necessary privilege.=自我保護被禁用,或您沒有所需權限。
The area intersects with @1 [@2] (@3).=區域與 @1 [@2] (@3) 重疊。
You have reached the maximum amount of areas that you are allowed to protect.=您的現有保護區數量已達到所允許的上限。
### legacy.lua ###
<version>=<版本>
Converted areas saved. Done.=轉換後的保護區已經保存。完成。
Converting areas…=正在轉換保護區……
Error loading legacy file: @1=載入舊檔案時發生錯誤:@1
Invalid version number. (0 allowed)=無效版本號。允許值0
Legacy file loaded.=舊檔案已載入。
Loads, converts, and saves the areas from a legacy save file.=載入、轉換並儲存舊存檔中的保護區。
Table format updated.=表格格式已更新。
unnamed=未命名
### pos.lua ###
<not set>=<未設定>
Area @1 selected.=保護區 @1 已選擇。
Area position @1 set to @2=保護區座標 @1 已設定爲 @2。
Position @1 set to @2=保護區座標 @1 已設定爲 @2。
Position @1: =保護區座標 @1
Select an area by ID.=通過保護區編號選擇區域
Select position @1 by punching a node.=請擊打方塊,以設定保護區座標 @1 的位置。
Select positions by punching two nodes.=請擊打兩個方塊,以設定保護區座標的位置。
Set area protection region position @1 to your location or the one specified=將保護區座標 @1 的位置設定爲您目前的位置或提供的座標
Set area protection region, position 1, or position 2 by punching nodes, or display the region=擊打方塊設定保護區座標,或獲得其座標資訊
The area @1 does not exist.=保護區 @1 不存在。
Unable to get position.=無法獲得座標。
Unknown subcommand: @1=子指令不明:@1
Relative coordinates is not supported on this server. Please upgrade Minetest to 5.7.0 or newer versions.=此伺服器不支援相對座標。請更新Minetest至5.7.0或之後的版本。

View File

@ -27,7 +27,7 @@ Faction doesn't exists=
Find areas using a Lua regular expression= Find areas using a Lua regular expression=
Get information about area configuration and usage.= Get information about area configuration and usage.=
Give a player access to a sub-area beetween two positions that have already been protected, Use set_owner if you don't want the parent to be set.= Give a player access to a sub-area between two positions that have already been protected, Use set_owner if you don't want the parent to be set.=
Invalid regular expression.= Invalid regular expression.=
Limit: @1 areas= Limit: @1 areas=
@ -45,7 +45,7 @@ Protect your own area=
Recursively remove areas using an ID= Recursively remove areas using an ID=
Remove an area using an ID= Remove an area using an ID=
Removed area @1= Removed area @1=
Removed area @1 and it's sub areas.= Removed area @1 and its sub areas.=
Removes all ownerless areas= Removes all ownerless areas=
Rename an area that you own= Rename an area that you own=
Self protection is disabled.= Self protection is disabled.=
@ -133,3 +133,5 @@ Set area protection region, position 1, or position 2 by punching nodes, or disp
The area @1 does not exist.= The area @1 does not exist.=
Unable to get position.= Unable to get position.=
Unknown subcommand: @1= Unknown subcommand: @1=
Relative coordinates is not supported on this server. Please upgrade Minetest to 5.7.0 or newer versions.=

81
pos.lua
View File

@ -22,6 +22,37 @@ local function posLimit(pos)
} }
end end
local parse_relative_pos
if minetest.parse_relative_number then
parse_relative_pos = function(x_str, y_str, z_str, pos)
local x = pos and minetest.parse_relative_number(x_str, pos.x)
or tonumber(x_str)
local y = pos and minetest.parse_relative_number(y_str, pos.y)
or tonumber(y_str)
local z = pos and minetest.parse_relative_number(z_str, pos.z)
or tonumber(z_str)
if x and y and z then
return vector.new(x, y, z)
end
end
else
parse_relative_pos = function(x_str, y_str, z_str, pos)
local x = tonumber(x_str)
local y = tonumber(y_str)
local z = tonumber(z_str)
if x and y and z then
return vector.new(x, y, z)
elseif string.sub(x_str, 1, 1) == "~"
or string.sub(y_str, 1, 1) == "~"
or string.sub(z_str, 1, 1) == "~" then
return nil, S("Relative coordinates is not supported on this server. " ..
"Please upgrade Minetest to 5.7.0 or newer versions.")
end
end
end
minetest.register_chatcommand("select_area", { minetest.register_chatcommand("select_area", {
params = S("<ID>"), params = S("<ID>"),
description = S("Select an area by ID."), description = S("Select an area by ID."),
@ -47,20 +78,25 @@ minetest.register_chatcommand("area_pos1", {
privs = {}, privs = {},
func = function(name, param) func = function(name, param)
local pos local pos
local found, _, x, y, z = param:find( local player = minetest.get_player_by_name(name)
"^(-?%d+)[, ](-?%d+)[, ](-?%d+)$") if player then
pos = vector.round(player:get_pos())
end
local found, _, x_str, y_str, z_str = param:find(
"^(~?-?%d*)[, ](~?-?%d*)[, ](~?-?%d*)$")
if found then if found then
pos = {x=tonumber(x), y=tonumber(y), z=tonumber(z)} local get_pos, reason = parse_relative_pos(x_str, y_str, z_str, pos)
elseif param == "" then if get_pos then
local player = minetest.get_player_by_name(name) pos = get_pos
if player then elseif not get_pos and reason then
pos = player:get_pos() return false, reason
else
return false, S("Unable to get position.")
end end
else elseif param ~= "" then
return false, S("Invalid usage, see /help @1.", "area_pos1") return false, S("Invalid usage, see /help @1.", "area_pos1")
end end
if not pos then
return false, S("Unable to get position.")
end
pos = posLimit(vector.round(pos)) pos = posLimit(vector.round(pos))
areas:setPos1(name, pos) areas:setPos1(name, pos)
return true, S("Area position @1 set to @2", "1", return true, S("Area position @1 set to @2", "1",
@ -74,20 +110,25 @@ minetest.register_chatcommand("area_pos2", {
.." location or the one specified", "2"), .." location or the one specified", "2"),
func = function(name, param) func = function(name, param)
local pos local pos
local found, _, x, y, z = param:find( local player = minetest.get_player_by_name(name)
"^(-?%d+)[, ](-?%d+)[, ](-?%d+)$") if player then
pos = vector.round(player:get_pos())
end
local found, _, x_str, y_str, z_str = param:find(
"^(~?-?%d*)[, ](~?-?%d*)[, ](~?-?%d*)$")
if found then if found then
pos = {x=tonumber(x), y=tonumber(y), z=tonumber(z)} local get_pos, reason = parse_relative_pos(x_str, y_str, z_str, pos)
elseif param == "" then if get_pos then
local player = minetest.get_player_by_name(name) pos = get_pos
if player then elseif not get_pos and reason then
pos = player:get_pos() return false, reason
else
return false, S("Unable to get position.")
end end
else elseif param ~= "" then
return false, S("Invalid usage, see /help @1.", "area_pos2") return false, S("Invalid usage, see /help @1.", "area_pos2")
end end
if not pos then
return false, S("Unable to get position.")
end
pos = posLimit(vector.round(pos)) pos = posLimit(vector.round(pos))
areas:setPos2(name, pos) areas:setPos2(name, pos)
return true, S("Area position @1 set to @2", "2", return true, S("Area position @1 set to @2", "2",