Compare commits

...

58 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
76f8ccf8ab Add morefarming and improve farming support on openfarming areas 2020-10-14 22:33:09 +02:00
02b23b0371 Merge remote-tracking branch 'upstream/master' 2020-09-08 18:45:48 +02:00
Louis Royer
4018c0d204
Add privilege translations and update translations (#49)
+ Add new french translation strings
2020-09-07 17:47:18 +02:00
Kalio_42
c167b30ebf
Adapt to the new version of playerfactions (#48)
Enable to open an area to many factions
    Update to adapt to the new version of playerfactions mod, with its new multi-faction mode
2020-09-05 18:49:17 +02:00
4eeb2a9d11 Merge remote-tracking branch 'upstream/master' 2020-08-29 20:29:29 +02:00
luk3yx
a9c05f0e38
Use JSON to store areas (#47)
This works around a limit of ~21000 areas because of limits in 'minetest.deserialize()'. Files will be migrated to the new format on first change.
2020-08-28 12:54:48 +02:00
99408df96a Delete unused textures 2020-07-05 17:10:03 +02:00
42cde6a494 Merge branch 'nalc-1.2-dev' 2020-07-05 17:02:34 +02:00
e0783cf8bf Corrige crash au démarrage 2020-06-15 01:10:47 +02:00
0b2baacb92 Merge remote-tracking branch 'upstream/master' into nalc-1.2-dev 2020-06-14 23:38:20 +02:00
Hamlet
142a723eb2
Add Italian translation (#45) 2020-06-14 18:59:48 +02:00
Buckaroo Banzai
66bd6a9b1d
Add luacheck CI and drop node_ownership remnants (#44)
`node_ownership` is long dead, and pollutes the global namespace. Support dropped after ~7 years.

Co-authored-by: BuckarooBanzay <BuckarooBanzay@users.noreply.github.com>
2020-06-08 21:52:11 +02:00
MoNTE48
aa3e35acbe /areas_cleanup for removing ownerless areas 2020-06-04 20:36:12 +02:00
MoNTE48
800a93f5ee Minor cleanup 2020-06-04 20:36:12 +02:00
Louis Royer
448fe3ebf1 Rework on messages displayed
Co-authored-by: SmallJoker <SmallJoker@users.noreply.github.com>
2020-03-19 22:46:22 +01:00
Louis Royer
2f4eddd324 Add french translation 2020-03-19 22:46:22 +01:00
Louis Royer
4179917eb4 Add translation support 2020-03-19 22:46:22 +01:00
54c504fa0d [areas] Remet le HUD comme avant la modif du feae996 2019-12-30 01:02:36 +01:00
26d6f56485 Ajoute description privilège \"megabuilder\" pour admins d'areas 2019-12-28 15:26:21 +01:00
57f20bb25f Ajoute infos privilège "megabuilder" dans la commande /area_info 2019-12-28 15:07:13 +01:00
feae9967dc Ajoute certaines modifications venant de MFF + ajustement HUD
* Aires openfarming
* Privilège megabuilder
* HUD légèrement modifié pour laisser de la place à celui de factions
2019-12-28 02:43:12 +01:00
Alden Peeters
aca830fd22 Add support for playerfactions mod (#37)
Add faction indicator to HUD
2019-09-21 15:33:42 +02:00
SmallJoker
95c1165e28 Add and parse from settingtypes.txt. Update readme 2019-07-11 20:02:32 +02:00
Panquesito7
5527dc8945 Replace deprecated functions with newer ones (#36)
This commit replaces a few deprecated calls to getpos with get_pos
2019-07-10 20:26:42 +02:00
Auke Kok
6218e5884d Limit areas to -30992,30992 due to MABLOCK_SIZE=16
Internally, when allocating an AreaStore, the limits are required
to be within the last full block, and so, you cannot create one "on"
the edge, as it will trigger an exception. When limited to the last
full mapblock, it all works fine.
2019-04-03 11:10:59 -07:00
Auke Kok
cfd4bb2423 Last of the luacheck cleanups. 2019-04-03 10:26:20 -07:00
Auke Kok
6e2b9a0a51 Needs to be defined earlier. 2019-04-03 10:24:02 -07:00
Auke Kok
024424ee8b Also limit chatcommand area_pos[12] positions. 2019-04-03 10:17:47 -07:00
Vanessa Dannenberg
f70600db30 oops, commas would be nice. 2019-04-02 16:06:19 -07:00
Vanessa Dannenberg
9508a004d0 fix posLimit(pos) to process and return a position table 2019-04-02 14:53:54 -07:00
Auke Kok
630bdefd98 Don't allow areas to cross outside mapgen world limits.
Limit any area to within [-31000,31000].
2019-04-01 21:28:03 -07:00
Auke Kok
a303abe51b Add template .luacheckrc 2019-04-01 21:22:31 -07:00
Tai Kedzierski
7b51f84404 Limit recalculations.
Setting based - limit area recalculation and allow tuning of the
interval.
2019-04-01 21:21:31 -07:00
sofar
1bbb997c7a
Add callbacks for area operations 2019-04-01 20:28:50 -07:00
red-001
09c030352f Use the new minetest.safe_file_write API if possible when saving database. 2019-04-01 20:27:17 -07:00
sofar
2637876555
Fix pos big (#1)
* fix pos being to big

* improve

* make the change instead in hud.lua
2019-04-01 20:24:59 -07:00
sys4-fr
c4d0fe020f Corrige lecture de paramètre de configuration 2018-12-24 02:22:29 +01:00
AntumDeluge
289d0e623c Update usage of settings API 2017-06-09 13:00:12 -04:00
Jordan Irwin
d3d43d9511 Reference 'settings.lua' instead of 'config.lua' (#21) 2017-05-06 13:41:45 -04:00
Tai @ Flex
6080ff065e Add API for adding areas to HUD 2016-12-19 16:36:37 +00:00
ShadowNinja
23f81f6278 Add mod.conf 2016-12-04 04:12:27 +00:00
Dorian Wouters
7cb8787beb Use get_auth_handler().get_auth() instead of auth_table
minetest.auth_table is an implementation detail of the default auth handler.
No guarantee is made that it even exists and using this table directly is incompatible
with custom auth handlers.  Instead, use the proper auth handler API.
2016-09-03 21:05:52 -04:00
30 changed files with 1687 additions and 553 deletions

17
.github/workflows/luacheck.yml vendored Normal file
View File

@ -0,0 +1,17 @@
name: luacheck
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: apt
run: sudo apt-get install -y luarocks
- name: luacheck install
run: luarocks install --local luacheck
- name: luacheck run
run: $HOME/.luarocks/bin/luacheck ./

24
.luacheckrc Normal file
View File

@ -0,0 +1,24 @@
unused_args = false
read_globals = {
"DIR_DELIM",
"core",
"dump",
"vector", "nodeupdate",
"VoxelManip", "VoxelArea",
"PseudoRandom", "ItemStack",
"AreaStore",
"default",
"factions",
table = { fields = { "copy", "getn", "indexof" } }
}
globals = {
"minetest",
-- mod namespace
"areas"
}
files["legacy.lua"] = {
ignore = {"512"}
}

View File

@ -1,21 +1,34 @@
Areas mod for Minetest 0.4.8+
=============================
Areas mod for Minetest
======================
Dependencies
------------
Minetest 5.0.0+ is recommended, but 0.4.16+ should work as well.
Minetest 5.0.0+
Optional support for following mods:
* [playerfactions](https://git.leagueh.xyz/katp32/playerfactions/) by [katp32](https://git.leagueh.xyz/katp32) & [Kalio_42](https://git.leagueh.xyz/Kalio_42)
Configuration
-------------
If you wish to specify configuration options, such as whether players are
allowed to protect their own areas with the `protect` command (disabled by
default), you should check config.lua and set the appropriate settings in your
server's configuration file (probably `minetest.conf`).
Open the tab `Settings -> All Settings -> Mods -> areas` to get a list of all
possible settings.
For server owners: Check `settingtypes.txt` and modify your `minetest.conf`
according to the wanted setting changes.
Tutorial
--------
To protect an area you must first set the corner positions of the area.
In order to set the corner positions you can run:
1) Specify the corner positions of the area you would like to protect.
Use one of the following commands:
* `/area_pos set` and punch the two corner nodes to set them.
* `/area_pos set1/set2` and punch only the first or second corner node to
set them one at a time.
@ -23,25 +36,25 @@ In order to set the corner positions you can run:
* `/area_pos1/2 X Y Z` to set one of the positions to the specified
coordinates.
Once you have set the border positions you can protect the area by running one
of the following commands:
2) Protect the selected area by running one of the following commands:
* `/set_owner <OwnerName> <AreaName>` -- If you have the `areas` privilege.
* `/protect <AreaName>` -- If you have the `areas` privilege or the server
administrator has enabled area self-protection.
The area name is used only for informational purposes (so that you know what
an area is for). It is not used for any other purpose.
The area name is used only for informational purposes and has no functional
importance.
For example: `/set_owner SomePlayer Mese city`
Now that you own an area you may want to add sub-owners to it. You can do this
with the `add_owner` command. Anyone with an area can use the `add_owner`
command on their areas. Before using the `add_owner` command you have to
select the corners of the sub-area as you did for `set_owner`. If your markers
are still around your original area and you want to grant access to your
entire area you will not have to re-set them. You can also use `select_area` to
place the markers at the corners of an existing area if you've reset your
3) You now own an area. You may now add sub-owners to it if you want to (see command `/add_owner`). Before using the `/add_owner` command you have to
select the corners of the sub-area as you did in step 1.
If your markers are still around your original area and you want to grant
access to your entire area you will not have to re-set them. Use `/select_area` to place the markers at the corners of an existing area if you've reset your
markers and want to grant access to a full area.
The `add_owner` command expects three arguments:
The `/add_owner` command expects three arguments:
1. The ID number of the parent area (the area that you want to add a
sub-area to).
2. The name of the player that will own the sub-area.
@ -74,7 +87,7 @@ Commands
* `/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.
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.
@ -94,11 +107,21 @@ Commands
* `/area_pos2 [X,Y,Z|X Y Z]` -- Sets area position two to your position or
the one supplied.
* `/areas_cleanup` -- Removes all ownerless areas.
Useful for cleaning after user deletion, for example using /remove_player.
* `/area_open <ID>` -- Toggle open/closed the specified area for everyone.
* `/area_faction_open <ID> <faction>` -- Toggle open/closed the specified
area for members of the faction. Factions are created and managed by
playerfactions mod.
License
-------
Copyright (C) 2013 ShadowNinja
Copyright (C) 2013-2017 ShadowNinja
Copyright (C) 2015-2020 various contributors
Licensed under the GNU LGPL version 2.1 or later.
See LICENSE.txt and http://www.gnu.org/licenses/lgpl-2.1.txt

206
api.lua
View File

@ -1,14 +1,70 @@
local hudHandlers = {}
--plants to place in openfarming
local plants = { ["farming:blueberries"]="air", ["farming:carrot"]="air", ["farming:coffee_beans"]="air", ["farming:corn"]="air", ["farming:cucumber"]="air",
["farming:melon_slice"]="air", ["farming:potato"]="air", ["farming:pumpkin_slice"]="air", ["farming:raspberries"]="air", ["farming:rhubarb"]="air",
["farming:tomato"]="air", ["farming:seed_cotton"]="air", ["farming:seed_wheat"]="air",["default:papyrus"]="air", ["farming:trellis"]="air",
["farming:grapes"]="farming:trellis", ["farming:beanpole"]="air", ["farming:beans"]="farming:beanpole",
}
---plants to place in openfarming
local plants = {
["farming:beetroot"]="air", ["farming:blueberries"]="air", ["farming:cabbage"]="air",
["farming:carrot"]="air", ["farming:chili_pepper"]="air", ["farming:coffee_beans"]="air",
["farming:corn"]="air", ["farming:cucumber"]="air", ["farming:garlic_clove"]="air",
["farming:melon_slice"]="air", ["farming:onion"]="air", ["default:papyrus"]="air",
["farming:pea_pod"]="air", ["farming:peppercorn"]="air", ["farming:pineapple_top"]="air",
["farming:potato"]="air", ["farming:pumpkin_slice"]="air", ["farming:raspberries"]="air",
["farming:rhubarb"]="air",
["farming:seed_barley"]="air", ["farming:seed_cotton"]="air", ["farming:seed_hemp"]="air",
["farming:seed_mint"]="air", ["farming:seed_oat"]="air", ["farming:seed_rice"]="air",
["farming:seed_rye"]="air", ["farming:seed_wheat"]="air",
["farming:tomato"]="air",
["farming:trellis"]="air", ["farming:grapes"]="farming:trellis",
["farming:beanpole"]="air", ["farming:beans"]="farming:beanpole",
["morefarming:seed_wildcarrot"]="air", ["morefarming:seed_teosinte"]="air",
["morefarming:seed_carrot"]="air", ["morefarming:seed_corn"]="air",
}
areas.registered_protection_conditions = {}
areas.registered_on_adds = {}
areas.registered_on_removes = {}
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)
table.insert(areas.registered_on_adds, func)
end
function areas:registerOnRemove(func)
table.insert(areas.registered_on_removes, func)
end
function areas:registerOnMove(func)
table.insert(areas.registered_on_moves, func)
end
--- Adds a function as a HUD handler, it will be able to add items to the Areas HUD element.
function areas:registerHudHandler(handler)
table.insert(hudHandlers, handler)
end
function areas:getExternalHudEntries(pos)
local areas = {}
for _, func in pairs(hudHandlers) do
func(pos, areas)
end
return areas
end
--- Returns a list of areas that include the provided position.
function areas:getAreasAtPos(pos)
local res = {}
if self.store then
local a = self.store:get_areas_for_pos(pos, false, true)
for store_id, store_area in pairs(a) do
@ -58,22 +114,42 @@ function areas:getAreasIntersectingArea(pos1, pos2)
return res
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)
if minetest.check_player_privs(name, self.adminPrivs) then
return true
end
local owned = false
if pos == nil then return not owned end -- pour éviter crash avec nénuphar
for _, area in pairs(self:getAreasAtPos(pos)) do
if area.owner == name or area.open then
return true
elseif area.openfarming then
-- if area is openfarming
local node = minetest.get_node(pos).name
if not minetest.registered_nodes[node] then return false end
local player = minetest.get_player_by_name(name)
if not player then return false 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 area.openfarming then
-- if area is openfarming
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()
if wstack == "" then wstack = "hand" end
@ -86,13 +162,26 @@ function areas:canInteract(pos, name)
if plants[wstack] ~= nil and plants[wstack] == node then
return true
end
owned = true
end
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
owned = true
for _, fname in ipairs(area.faction_open or {}) do
if factions.player_is_in_faction(fname, name) then
return true
end
end
end
end
return not owned
return false
end
-- Returns a table (list) of all players that own an area
@ -108,7 +197,7 @@ end
-- Note that this fails and returns false when the specified area is fully
-- owned by the player, but with multiple protection zones, none of which
-- cover the entire checked area.
-- @param name (optional) Player name. If not specified checks for any intersecting areas.
-- @param name (optional) Player name. If not specified checks for any intersecting areas.
-- @param allow_open Whether open areas should be counted as if they didn't exist.
-- @return Boolean indicating whether the player can interact in that area.
-- @return Un-owned intersecting area ID, if found.
@ -153,74 +242,3 @@ function areas:canInteractInArea(pos1, pos2, name, allow_open)
-- intersecting areas and they are all owned by the player.
return true
end
function areas:canMakeArea(pos1, pos2, name) --MFF crabman(25/02/2016) fix areas in areas
if name and minetest.check_player_privs(name, self.adminPrivs) then
return true
end
areas:sortPos(pos1, pos2)
local id_areas_intersect = {}
local areas = self:getAreasIntersectingArea(pos1, pos2)
if not areas then return true end
for id, area in pairs(areas) do
if area.owner == name and self:isSubarea(pos1, pos2, id) then
return true
end
if not area.open and not self:isAreaOwner(id, name) then
table.insert(id_areas_intersect, id)
end
end
if #id_areas_intersect > 0 then
return false, id_areas_intersect[1]
end
return true
end
--MFF crabman(5/03/2016 ) return special area pos if a spawn is set.
--1 party (2 party in beds mod)
function areas:getSpawn(pos)
for _, area in pairs(areas:getAreasAtPos(pos)) do
if area.spawn and area.spawn.x then
return area.spawn
end
end
return nil
end
--MFF DEBUT crabman(17/09/2015 ) respawn player in special area(event) if a spawn is set.
--1 party (2 party in beds mod)
local dead_players = {}
minetest.register_on_dieplayer(function(player)
local player_name = player:get_player_name()
if not player_name then return end
local pos = player:getpos()
if pos then
dead_players[player_name] = pos
end
end)
function areas:onRespawn(player)
local player_name = player:get_player_name()
if not player_name or not dead_players[player_name] then return false end
local pos = dead_players[player_name]
dead_players[player_name] = nil
if pos then
for _, area in pairs(areas:getAreasAtPos(pos)) do
if area.spawn then
player:setpos(area.spawn)
return true
end
end
end
return false
end
--FIN

64
api.md Normal file
View File

@ -0,0 +1,64 @@
Areas mod API
===
API list
---
* `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:registerOnRemove(func(id))`
* `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
---
If you are making a protection mod or a similar mod that adds invisible regions
to the world, and you would like then to show up in the areas HUD element, you
can register a callback to show your areas.
HUD handler specification:
* `handler(pos, list)`
* `pos` - The position to check.
* `list` - The list of area HUD elements, this should be modified in-place.
The area list item is a table containing a list of tables with the following fields:
* `id` - An identifier for the area. This should be a unique string in the format `mod:id`.
* `name` - The name of the area.
* `owner` - The player name of the region owner, if any.
All of the fields are optional but at least one of them must be set.
### Example
local function areas_hud_handler(pos, areas)
local val = find_my_protection(pos)
if val then
table.insert(areas, {
id = "mod:"..val.id,
name = val.name,
owner = val.owner,
})
end
end
areas:registerHudHandler(areas_hud_handler)

View File

@ -1,15 +1,16 @@
local S = minetest.get_translator("areas")
minetest.register_chatcommand("protect", {
params = "<AreaName>",
description = "Protect your own area",
params = S("<AreaName>"),
description = S("Protect your own area"),
privs = {[areas.config.self_protection_privilege]=true},
func = function(name, param)
if param == "" then
return false, "Invalid usage, see /help protect."
return false, S("Invalid usage, see /help @1.", "protect")
end
local pos1, pos2 = areas:getPos(name)
if not (pos1 and pos2) then
return false, "You need to select an area first."
return false, S("You need to select an area first.")
end
minetest.log("action", "/protect invoked, owner="..name..
@ -19,38 +20,37 @@ minetest.register_chatcommand("protect", {
local canAdd, errMsg = areas:canPlayerAddArea(pos1, pos2, name)
if not canAdd then
return false, "You can't protect that area: "..errMsg
return false, S("You can't protect that area: @1", errMsg)
end
local id = areas:add(name, param, pos1, pos2, nil)
areas:save()
return true, "Area protected. ID: "..id
return true, S("Area protected. ID: @1", id)
end
})
minetest.register_chatcommand("set_owner", {
params = "<PlayerName> <AreaName>",
description = "Protect an area beetween two positions and give"
params = S("<PlayerName>").." "..S("<AreaName>"),
description = S("Protect an area between two positions and give"
.." a player access to it without setting the parent of the"
.." area to any existing area",
.." area to any existing area"),
privs = areas.adminPrivs,
func = function(name, param)
local ownerName, areaName = param:match('^(%S+)%s(.+)$')
if not ownerName then
return false, "Incorrect usage, see /help set_owner."
return false, S("Invalid usage, see /help @1.", "set_owner")
end
local pos1, pos2 = areas:getPos(name)
if not (pos1 and pos2) then
return false, "You need to select an area first."
return false, S("You need to select an area first.")
end
if not areas:player_exists(ownerName) then
return false, "The player \""
..ownerName.."\" does not exist."
return false, S("The player \"@1\" does not exist.", ownerName)
end
minetest.log("action", name.." runs /set_owner. Owner = "..ownerName..
@ -62,34 +62,33 @@ minetest.register_chatcommand("set_owner", {
areas:save()
minetest.chat_send_player(ownerName,
"You have been granted control over area #"..
id..". Type /list_areas to show your areas.")
return true, "Area protected. ID: "..id
S("You have been granted control over area #@1. "..
"Type /list_areas to show your areas.", id))
return true, S("Area protected. ID: @1", id)
end
})
minetest.register_chatcommand("add_owner", {
params = "<ParentID> <Player> <AreaName>",
description = "Give a player access to a sub-area beetween two"
params = S("<ParentID>").." "..S("<PlayerName>").." "..S("<AreaName>"),
description = S("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.",
.." Use set_owner if you don't want the parent to be set."),
func = function(name, param)
local pid, ownerName, areaName
= param:match('^(%d+) ([^ ]+) (.+)$')
local pid, ownerName, areaName = param:match('^(%d+) ([^ ]+) (.+)$')
if not pid then
minetest.chat_send_player(name, "Incorrect usage, see /help add_owner")
minetest.chat_send_player(name, S("Invalid usage, see /help @1.", "add_owner"))
return
end
local pos1, pos2 = areas:getPos(name)
if not (pos1 and pos2) then
return false, "You need to select an area first."
return false, S("You need to select an area first.")
end
if not areas:player_exists(ownerName) then
return false, "The player \""..ownerName.."\" does not exist."
return false, S("The player \"@1\" does not exist.", ownerName)
end
minetest.log("action", name.." runs /add_owner. Owner = "..ownerName..
@ -101,52 +100,52 @@ minetest.register_chatcommand("add_owner", {
pid = tonumber(pid)
if (not areas:isAreaOwner(pid, name)) or
(not areas:isSubarea(pos1, pos2, pid)) then
return false, "You can't protect that area."
return false, S("You can't protect that area.")
end
local id = areas:add(ownerName, areaName, pos1, pos2, pid)
areas:save()
minetest.chat_send_player(ownerName,
"You have been granted control over area #"..
id..". Type /list_areas to show your areas.")
return true, "Area protected. ID: "..id
S("You have been granted control over area #@1. "..
"Type /list_areas to show your areas.", id))
return true, S("Area protected. ID: @1", id)
end
})
minetest.register_chatcommand("rename_area", {
params = "<ID> <newName>",
description = "Rename a area that you own",
params = S("<ID>").." "..S("<newName>"),
description = S("Rename an area that you own"),
func = function(name, param)
local id, newName = param:match("^(%d+)%s(.+)$")
if not id then
return false, "Invalid usage, see /help rename_area."
return false, S("Invalid usage, see /help @1.", "rename_area")
end
id = tonumber(id)
if not id then
return false, "That area doesn't exist."
return false, S("That area doesn't exist.")
end
if not areas:isAreaOwner(id, name) then
return true, "You don't own that area."
return true, S("You don't own that area.")
end
areas.areas[id].name = newName
areas:save()
return true, "Area renamed."
return true, S("Area renamed.")
end
})
minetest.register_chatcommand("find_areas", {
params = "<regexp>",
description = "Find areas using a Lua regular expression",
description = S("Find areas using a Lua regular expression"),
privs = areas.adminPrivs,
func = function(name, param)
if param == "" then
return false, "A regular expression is required."
return false, S("A regular expression is required.")
end
-- Check expression for validity
@ -154,7 +153,7 @@ minetest.register_chatcommand("find_areas", {
("Test [1]: Player (0,0,0) (0,0,0)"):find(param)
end
if not pcall(testRegExp) then
return false, "Invalid regular expression."
return false, S("Invalid regular expression.")
end
local matches = {}
@ -167,24 +166,57 @@ minetest.register_chatcommand("find_areas", {
if #matches > 0 then
return true, table.concat(matches, "\n")
else
return true, "No matches found."
return true, S("No matches found.")
end
end
})
minetest.register_chatcommand("list_areas", {
description = "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)
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 = {}
for id, area in pairs(areas.areas) do
if admin or areas:isAreaOwner(id, name) then
table.insert(areaStrings, areas:toString(id))
if admin_show_summary then
-- Summary per-player
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
if #areaStrings == 0 then
return true, "No visible areas."
return true, S("No visible areas.")
end
return true, table.concat(areaStrings, "\n")
end
@ -192,152 +224,194 @@ minetest.register_chatcommand("list_areas", {
minetest.register_chatcommand("recursive_remove_areas", {
params = "<id>",
description = "Recursively remove areas using an id",
params = S("<ID>"),
description = S("Recursively remove areas using an ID"),
func = function(name, param)
local id = tonumber(param)
if not id then
return false, "Invalid usage, see"
.." /help recursive_remove_areas"
return false, S("Invalid usage, see"
.." /help @1.", "recursive_remove_areas")
end
if not areas:isAreaOwner(id, name) then
return false, "Area "..id.." does not exist or is"
.." not owned by you."
return false, S("Area @1 does not exist or is"
.." not owned by you.", id)
end
areas:remove(id, true)
areas:save()
return true, "Removed area "..id.." and it's sub areas."
return true, S("Removed area @1 and its sub areas.", id)
end
})
minetest.register_chatcommand("remove_area", {
params = "<id>",
description = "Remove an area using an id",
params = S("<ID>"),
description = S("Remove an area using an ID"),
func = function(name, param)
local id = tonumber(param)
if not id then
return false, "Invalid usage, see /help remove_area"
return false, S("Invalid usage, see /help @1.", "remove_area")
end
if not areas:isAreaOwner(id, name) then
return false, "Area "..id.." does not exist or"
.." is not owned by you."
return false, S("Area @1 does not exist or"
.." is not owned by you.", id)
end
areas:remove(id)
areas:save()
return true, "Removed area "..id
return true, S("Removed area @1", id)
end
})
minetest.register_chatcommand("change_owner", {
params = "<ID> <NewOwner>",
description = "Change the owner of an area using it's ID",
params = S("<ID>").." "..S("<NewOwner>"),
description = S("Change the owner of an area using its ID"),
func = function(name, param)
local id, newOwner = param:match("^(%d+)%s(%S+)$")
if not id then
return false, "Invalid usage, see"
.." /help change_owner."
return false, S("Invalid usage, see"
.." /help @1.", "change_owner")
end
if not areas:player_exists(newOwner) then
return false, "The player \""..newOwner
.."\" does not exist."
return false, S("The player \"@1\" does not exist.", newOwner)
end
id = tonumber(id)
if not areas:isAreaOwner(id, name) then
return false, "Area "..id.." does not exist"
.." or is not owned by you."
return false, S("Area @1 does not exist"
.." or is not owned by you.", id)
end
areas.areas[id].owner = newOwner
areas:save()
minetest.chat_send_player(newOwner,
("%s has given you control over the area %q (ID %d).")
:format(name, areas.areas[id].name, id))
return true, "Owner changed."
S("@1 has given you control over the area \"@2\" (ID @3).",
name, areas.areas[id].name, id))
return true, S("Owner changed.")
end
})
minetest.register_chatcommand("area_open", {
params = "<ID>",
description = "Toggle an area open (anyone can interact) or closed",
params = S("<ID>"),
description = S("Toggle an area open (anyone can interact) or closed"),
func = function(name, param)
local id = tonumber(param)
if not id then
return false, "Invalid usage, see /help area_open."
return false, S("Invalid usage, see /help @1.", "area_open")
end
if not areas:isAreaOwner(id, name) then
return false, "Area "..id.." does not exist"
.." or is not owned by you."
return false, S("Area @1 does not exist"
.." or is not owned by you.", id)
end
local open = not areas.areas[id].open
-- Save false as nil to avoid inflating the DB.
areas.areas[id].open = open or nil
areas:save()
return true, ("Area %s."):format(open and "opened" or "closed")
return true, open and S("Area opened.") or S("Area closed.")
end
})
minetest.register_chatcommand("area_openfarming", {
params = "<ID>",
description = "Toggle an area open (anyone can interact farming) or closed",
func = function(name, param)
local id = tonumber(param)
if not id then
return false, "Invalid usage, see /help area_openfarming."
end
if not areas:isAreaOwner(id, name) then
return false, "Area "..id.." does not exist"
minetest.register_chatcommand(
"area_openfarming", {
params = "<ID>",
description = "Toggle an area as open farming (anyone can harvest and plant) or closed",
func = function(name, param)
local id = tonumber(param)
if not id then
return false, "Invalid usage, see /help area_openfarming."
end
if not areas:isAreaOwner(id, name) then
return false, "Area "..id.." does not exist"
.." or is not owned by you."
end
local open = not areas.areas[id].openfarming
-- Save false as nil to avoid inflating the DB.
areas.areas[id].openfarming = open or nil
areas:save()
return true, ("Area %s to farming."):format(open and "opened" or "closed")
end
local openfarming = not areas.areas[id].openfarming
-- Save false as nil to avoid inflating the DB.
areas.areas[id].openfarming = openfarming or nil
areas:save()
return true, ("Area %s to farming."):format(openfarming and "opened" or "closed")
end
})
if areas.factions_available then
minetest.register_chatcommand("area_faction_open", {
params = S("<ID> [faction_name]"),
description = S("Toggle an area open/closed for members in your faction."),
func = function(name, param)
local params = param:split(" ")
local id = tonumber(params[1])
local faction_name = params[2]
if not id or not faction_name then
return false, S("Invalid usage, see /help @1.", "area_faction_open")
end
if not areas:isAreaOwner(id, name) then
return false, S("Area @1 does not exist"
.." or is not owned by you.", id)
end
if not factions.get_owner(faction_name) then
return false, S("Faction doesn't exists")
end
local fnames = areas.areas[id].faction_open or {}
local pos = table.indexof(fnames, faction_name)
if pos < 0 then
-- Add new faction to the list
table.insert(fnames, faction_name)
else
table.remove(fnames, pos)
end
if #fnames == 0 then
-- Save {} as nil to avoid inflating the DB.
fnames = nil
end
areas.areas[id].faction_open = fnames
areas:save()
return true, fnames and S("Area is open for members of: @1", table.concat(fnames, ", "))
or S("Area closed for faction members.")
end
})
end
minetest.register_chatcommand("move_area", {
params = "<ID>",
description = "Move (or resize) an area to the current positions.",
params = S("<ID>"),
description = S("Move (or resize) an area to the current positions."),
privs = areas.adminPrivs,
func = function(name, param)
local id = tonumber(param)
if not id then
return false, "Invalid usage, see /help move_area."
return false, S("Invalid usage, see /help @1.", "move_area")
end
local area = areas.areas[id]
if not area then
return false, "Area does not exist."
return false, S("Area does not exist.")
end
local pos1, pos2 = areas:getPos(name)
if not pos1 then
return false, "You need to select an area first."
return false, S("You need to select an area first.")
end
areas:move(id, area, pos1, pos2)
areas:save()
return true, "Area successfully moved."
return true, S("Area successfully moved.")
end,
})
minetest.register_chatcommand("area_info", {
description = "Get information about area configuration and usage.",
description = S("Get information about area configuration and usage."),
func = function(name, param)
local lines = {}
local privs = minetest.get_player_privs(name)
@ -359,27 +433,24 @@ minetest.register_chatcommand("area_info", {
local max_size = has_high_limit and
size_limit_high or size_limit
-- Privilege information
local self_prot_line = ("Self protection is %sabled"):format(
self_prot and "en" or "dis")
if self_prot and prot_priv then
self_prot_line = self_prot_line..
(" %s have the neccessary privilege (%q).")
:format(
has_prot_priv and "and you" or
"but you don't",
prot_priv)
else
self_prot_line = self_prot_line.."."
end
-- Self protection information
local self_prot_line = self_prot and S("Self protection is enabled.") or
S("Self protection is disabled.")
table.insert(lines, self_prot_line)
-- Privilege information
local priv_line = has_prot_priv and
S("You have the necessary privilege (\"@1\").", prot_priv) or
S("You don't have the necessary privilege (\"@1\").", prot_priv)
table.insert(lines, priv_line)
if privs.areas then
table.insert(lines, "You are an area"..
" administrator (\"areas\" privilege).")
table.insert(lines, S("You are an area"..
" administrator (\"areas\" privilege)."))
elseif has_high_limit then
table.insert(lines,
"You have extended area protection"..
" limits (\"areas_high_limit\" privilege).")
S("You have extended area protection"..
" limits (\"areas_high_limit\" privilege)."))
elseif privs.megabuilder then
table.insert(lines, "You are a megabuilder (\"megabuilder\" privilege).")
end
-- Area count
@ -389,26 +460,23 @@ minetest.register_chatcommand("area_info", {
area_num = area_num + 1
end
end
local count_line = ("You have %d area%s"):format(
area_num, area_num == 1 and "" or "s")
if privs.areas then
count_line = count_line..
" and have no area protection limits."
elseif can_prot then
count_line = count_line..(", out of a maximum of %d.")
:format(max_count)
end
table.insert(lines, count_line)
table.insert(lines, S("You have @1 areas.", area_num))
-- Area limit
local area_limit_line = (privs.areas or privs.megabuilder) and
S("Limit: no area count limit") or
S("Limit: @1 areas", max_count)
table.insert(lines, area_limit_line)
-- Area size limits
local function size_info(str, size)
table.insert(lines, ("%s spanning up to %dx%dx%d.")
:format(str, size.x, size.y, size.z))
table.insert(lines, S("@1 spanning up to @2x@3x@4.",
str, size.x, size.y, size.z))
end
local function priv_limit_info(priv, max_count, max_size)
size_info(("Players with the %q privilege"..
" can protect up to %d areas"):format(
priv, max_count), max_size)
local function priv_limit_info(lpriv, lmax_count, lmax_size)
size_info(S("Players with the \"@1\" privilege"..
" can protect up to @2 areas", lpriv, lmax_count),
lmax_size)
end
if self_prot then
if privs.areas then
@ -416,8 +484,11 @@ minetest.register_chatcommand("area_info", {
limit, size_limit)
priv_limit_info("areas_high_limit",
limit_high, size_limit_high)
table.insert(lines, "Players with the \"megabuilder\" privilege can protect unlimited areas in size and number.")
elseif privs.megabuilder then
table.insert(lines, "You can protect areas unlimited in size and number.")
elseif has_prot_priv then
size_info("You can protect areas", max_size)
size_info(S("You can protect areas"), max_size)
end
end
@ -426,62 +497,26 @@ minetest.register_chatcommand("area_info", {
})
--MFF DEBUT crabman(17/09/2015 ) respawn player at in special area(event) if a spawn is set.
minetest.register_chatcommand("area_addspawn", {
params = "<ID>",
privs = areas.adminPrivs,
description = "Define special spawn for area",
func = function(name, param)
local id = param:match("^(%d+)")
if not id then
return false, "Invalid usage, see /help area_addspawn."
end
minetest.register_chatcommand("areas_cleanup", {
description = S("Removes all ownerless areas"),
privs = areas.adminPrivs,
func = function()
local total, count = 0, 0
id = tonumber(id)
if not id then
return false, "Error, Param id must be int."
end
local aareas = areas.areas
for id, _ in pairs(aareas) do
local owner = aareas[id].owner
local player = minetest.get_player_by_name(name)
if not player then
return false, "Error, there is not player"
end
local pos = player:getpos()
if not pos then
return false, "Error, there is not pos."
end
if not areas:player_exists(owner) then
areas:remove(id)
count = count + 1
end
if not areas.areas[id] then
return false, "Area ".. id .." does not exist."
total = total + 1
end
areas.areas[id].spawn = pos
areas:save()
return true, "spawn of area ".. id .." defined."
return true, "Total areas: " .. total .. ", Removed " ..
count .. " areas. New count: " .. (total - count)
end
})
minetest.register_chatcommand("area_delspawn", {
params = "<ID>",
privs = areas.adminPrivs,
description = "Delete special spawn of area",
func = function(name, param)
local id = param:match("^(%d+)")
if not id then
return false, "Invalid usage, see /help area_delspawn."
end
id = tonumber(id)
if not id then
return false, "Error, Param id must be int."
end
if not areas.areas[id] then
return false, "Area ".. id .." does not exist."
end
areas.areas[id].spawn = nil
areas:save()
return true, "spawn of area ".. id .." deleted."
end
})
-- FIN

128
hud.lua
View File

@ -1,85 +1,89 @@
-- This is inspired by the landrush mod by Bremaweb
local S = minetest.get_translator("areas")
areas.hud = {}
areas.hud.refresh = 0
minetest.register_globalstep(function(dtime)
areas.hud.refresh = areas.hud.refresh + dtime
if areas.hud.refresh > areas.config["tick"] then
areas.hud.refresh = 0
else
return
end
local function tick()
for _, player in pairs(minetest.get_connected_players()) do
local name = player:get_player_name()
local pos = vector.round(player:getpos())
local area_text = "No area(s)\n\n"
local area_owner_name = ""
local mod_owner = 0
local mod_open = 0
local mod_farming = 0
local area_name = ""
local nb_areas = 0
local pos = vector.round(player:get_pos())
pos = vector.apply(pos, function(p)
return math.max(math.min(p, 2147483), -2147483)
end)
local areaStrings = {}
for id, area in pairs(areas:getAreasAtPos(pos)) do
nb_areas = nb_areas+1
if areas:isAreaOwner(id, name) then
mod_owner = 1
local faction_info
if area.faction_open and areas.factions_available then
-- Gather and clean up disbanded factions
local changed = false
for i, fac_name in ipairs(area.faction_open) do
if not factions.get_owner(fac_name) then
table.remove(area.faction_open, i)
changed = true
end
end
if #area.faction_open == 0 then
-- Prevent DB clutter, remove value
area.faction_open = nil
else
faction_info = table.concat(area.faction_open, ", ")
end
if changed then
areas:save()
end
end
if area.open then
mod_open = 1
end
if area.openfarming then
mod_farming = 1
end
if not area.parent then
area_owner_name = area.owner
area_name = area.name
end
table.insert(areaStrings, ("%s [%u] (%s%s%s)")
:format(area.name, id, area.owner,
area.open and S(":open") or area.openfarming and ":openfarming" or "",
faction_info and ":"..faction_info or ""))
end
local icon = "areas_not_area.png"
if nb_areas > 0 then
local plural = ""
if nb_areas > 1 then
plural = "s"
end
area_text = ("%s\nOwner: %s\n%u area" .. plural):format(area_name, area_owner_name, nb_areas)
icon = ("areas_%u_%u_%u.png"):format(mod_owner, mod_open, mod_farming)
for i, area in pairs(areas:getExternalHudEntries(pos)) do
local str = ""
if area.name then str = area.name .. " " end
if area.id then str = str.."["..area.id.."] " end
if area.owner then str = str.."("..area.owner..")" end
table.insert(areaStrings, str)
end
if not areas.hud[name] then
areas.hud[name] = {}
areas.hud[name].icon = player:hud_add({
hud_elem_type = "image",
position = {x=0,y=1},
scale = {x=1,y=1},
offset = {x=26,y=-60},
text = icon,
})
areas.hud[name].areas_id = player:hud_add({
hud_elem_type = "text",
local areaString = S("Areas:")
if #areaStrings > 0 then
areaString = areaString.."\n"..
table.concat(areaStrings, "\n")
end
local hud = areas.hud[name]
if not hud then
hud = {}
areas.hud[name] = hud
hud.areasId = player:hud_add({
[minetest.features.hud_def_type_field and "type" or "hud_elem_type"] = "text", -- compatible with older versions
name = "Areas",
number = 0xFFFFFF,
position = {x=0, y=1},
offset = {x=48, y=-40},
text = area_text,
scale = {x=1, y=1},
offset = {x=8, y=-8},
text = areaString,
scale = {x=200, y=60},
alignment = {x=1, y=-1},
})
areas.hud[name].old_area_text = area_text
areas.hud[name].old_icon = icon
else
if areas.hud[name].old_area_text ~= area_text then
player:hud_change(areas.hud[name].areas_id, "text", area_text)
areas.hud[name].old_area_text = area_text
end
if areas.hud[name].old_icon ~= icon then
player:hud_change(areas.hud[name].icon, "text", icon)
areas.hud[name].old_icon = icon
end
hud.oldAreas = areaString
return
elseif hud.oldAreas ~= areaString then
player:hud_change(hud.areasId, "text", areaString)
hud.oldAreas = areaString
end
end
minetest.after(1.5, tick)
end
tick()
end)
minetest.register_on_leaveplayer(function(player)
areas.hud[player:get_player_name()] = nil
end)

View File

@ -4,6 +4,8 @@
areas = {}
areas.factions_available = minetest.get_modpath("playerfactions") and true
areas.adminPrivs = {areas=true}
areas.startTime = os.clock()
@ -19,21 +21,28 @@ dofile(areas.modpath.."/hud.lua")
areas:load()
local S = minetest.get_translator("areas")
minetest.register_privilege("areas", {
description = "Can administer areas."
description = S("Can administer areas."),
give_to_singleplayer = false
})
minetest.register_privilege("areas_high_limit", {
description = "Can can more, bigger areas."
description = S("Can protect more, bigger areas."),
give_to_singleplayer = false
})
-- Mega_builder privilege -- MFF
minetest.register_privilege("megabuilder", {
description = "Can protect an infinite amount of areas."
})
if not minetest.registered_privileges[areas.config.self_protection_privilege] then
minetest.register_privilege(areas.config.self_protection_privilege, {
description = "Can protect areas.",
description = S("Can protect areas."),
})
end
if minetest.setting_getbool("log_mod") then
if minetest.settings:get_bool("log_mods") then
local diffTime = os.clock() - areas.startTime
minetest.log("action", "areas loaded in "..diffTime.."s.")
end

View File

@ -1,3 +1,4 @@
local S = minetest.get_translator("areas")
local old_is_protected = minetest.is_protected
function minetest.is_protected(pos, name)
@ -11,9 +12,8 @@ minetest.register_on_protection_violation(function(pos, name)
if not areas:canInteract(pos, name) then
local owners = areas:getNodeOwners(pos)
minetest.chat_send_player(name,
("%s is protected by %s."):format(
S("@1 is protected by @2.",
minetest.pos_to_string(pos),
table.concat(owners, ", ")))
end
end)

View File

@ -1,23 +1,29 @@
-- Mega_builder privilege
minetest.register_privilege("megabuilder","Can protect an infinite amount of areas.")
local S = minetest.get_translator("areas")
function areas:player_exists(name)
return minetest.get_auth_handler().get_auth(name) ~= nil
end
local safe_file_write = minetest.safe_file_write
if safe_file_write == nil then
function safe_file_write(path, content)
local file, err = io.open(path, "w")
if err then
return err
end
file:write(content)
file:close()
end
end
-- Save the areas table to a file
function areas:save()
local datastr = minetest.serialize(self.areas)
local datastr = minetest.write_json(self.areas)
if not datastr then
minetest.log("error", "[areas] Failed to serialize area data!")
return
end
local file, err = io.open(self.config.filename, "w")
if err then
return err
end
file:write(datastr)
file:close()
return safe_file_write(self.config.filename, datastr)
end
-- Load the areas table from the save file
@ -27,10 +33,19 @@ function areas:load()
self.areas = self.areas or {}
return err
end
self.areas = minetest.deserialize(file:read("*a"))
local data = file:read("*a")
if data:sub(1, 1) == "[" then
self.areas, err = minetest.parse_json(data)
else
self.areas, err = minetest.deserialize(data)
end
if type(self.areas) ~= "table" then
self.areas = {}
end
if err and #data > 10 then
minetest.log("error", "[areas] Failed to load area data: " ..
tostring(err))
end
file:close()
self:populateStore()
end
@ -42,7 +57,7 @@ end
function areas:checkAreaStoreId(sid)
if not sid then
minetest.log("error", "AreaStore failed to find an ID for an "
.."area! Falling back to iterative area checking.")
.."area! Falling back to iterative area checking.")
self.store = nil
self.store_ids = nil
end
@ -88,6 +103,11 @@ function areas:add(owner, name, pos1, pos2, parent)
owner = owner,
parent = parent
}
for i=1, #areas.registered_on_adds do
areas.registered_on_adds[i](id, self.areas[id])
end
-- Add to AreaStore
if self.store then
local sid = self.store:insert_area(pos1, pos2, tostring(id))
@ -98,7 +118,7 @@ function areas:add(owner, name, pos1, pos2, parent)
return id
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
-- have the removed area's parent as their new parent.
function areas:remove(id, recurse)
@ -120,6 +140,10 @@ function areas:remove(id, recurse)
end
end
for i=1, #areas.registered_on_removes do
areas.registered_on_removes[i](id)
end
-- Remove main entry
self.areas[id] = nil
@ -135,6 +159,10 @@ function areas:move(id, area, pos1, pos2)
area.pos1 = pos1
area.pos2 = pos2
for i=1, #areas.registered_on_moves do
areas.registered_on_moves[i](id, area, pos1, pos2)
end
if self.store then
self.store:remove_area(areas.store_ids[id])
local sid = self.store:insert_area(pos1, pos2, tostring(id))
@ -167,7 +195,7 @@ function areas:isSubarea(pos1, pos2, id)
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)
local children = {}
for cid, area in pairs(self.areas) do
@ -178,64 +206,93 @@ function areas:getChildren(id)
return children
end
-- Checks if the user has sufficient privileges.
-- If the player is not a administrator it also checks
-- if the area intersects other areas that they do not own.
-- Also checks the size of the area and if the user already
-- has more than max_areas.
-- checks all possible restrictions registered with
-- areas:registerProtectionCondition
-- builtin callbacks below
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)
if privs.areas then
-- always allow administrators to create areas
return true
end
-- Check self protection privilege, if it is enabled,
-- and if the area is too big.
if not self.config.self_protection or
-- Check self protection privilege
if not areas.config.self_protection or
not privs[areas.config.self_protection_privilege] then
return false, "Self protection is disabled or you do not have"
.." the necessary privilege."
return false, S("Self protection is disabled or you do not have"
.." the necessary privilege.")
end
end)
-- MFF: megabuilders skip checks on size and number of areas.
if not privs["megabuilder"] then
-- Check size
-- 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
local max_size = privs.areas_high_limit and
self.config.self_protection_max_size_high or
self.config.self_protection_max_size
areas.config.self_protection_max_size_high or
areas.config.self_protection_max_size
if
(pos2.x - pos1.x) > max_size.x or
(pos2.y - pos1.y) > max_size.y or
(pos2.z - pos1.z) > max_size.z then
return false, "Area is too big."
end
-- Check number of areas the user has and make sure it not above the max
local count = 0
for _, area in pairs(self.areas) do
if area.owner == name then
count = count + 1
end
end
local max_areas = privs.areas_high_limit and
self.config.self_protection_max_areas_high or
self.config.self_protection_max_areas
if count >= max_areas then
return false, "You have reached the maximum amount of"
.." areas that you are allowed to protect."
(pos2.x - pos1.x + 1) > max_size.x or
(pos2.y - pos1.y + 1) > max_size.y or
(pos2.z - pos1.z + 1) > max_size.z then
return false, S("Area is too big.")
end
end
end)
-- Check intersecting areas
local can, id = self:canMakeArea(pos1, pos2, name) --MFF crabman(25/02/2016) fix areas in areas
-- 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
for _, area in pairs(areas.areas) do
if area.owner == name then
count = count + 1
end
end
local max_areas = privs.areas_high_limit and
areas.config.self_protection_max_areas_high or
areas.config.self_protection_max_areas
if count >= max_areas then
return false, S("You have reached the maximum amount of"
.." areas that you are allowed to protect.")
end
end)
-- checks if the area intersects other areas that the player do not own.
areas:registerProtectionCondition(function(pos1, pos2, name)
local can, id = areas:canInteractInArea(pos1, pos2, name)
if not can then
local area = self.areas[id]
return false, ("The area intersects with %s [%u] (%s).")
:format(area.name, id, area.owner)
local area = areas.areas[id]
return false, S("The area intersects with @1 [@2] (@3).",
area.name, id, area.owner)
end
return true
end
end)
-- Given a id returns a string in the format:
-- "name [id]: owner (x1, y1, z1) (x2, y2, z2) -> children"
@ -288,4 +345,3 @@ function areas:isAreaOwner(id, name)
end
return false
end

View File

@ -1,25 +1,26 @@
-- This file contains functions to convert from
-- the old areas format and other compatability code.
local S = minetest.get_translator("areas")
minetest.register_chatcommand("legacy_load_areas", {
params = "<version>",
description = "Loads, converts, and saves the areas from"
.." a legacy save file.",
params = S("<version>"),
description = S("Loads, converts, and saves the areas from"
.." a legacy save file."),
privs = {areas=true, server=true},
func = function(name, param)
minetest.chat_send_player(name, "Converting areas...")
minetest.chat_send_player(name, S("Converting areas…"))
local version = tonumber(param)
if version == 0 then
err = areas:node_ownership_load()
local err = areas:node_ownership_load()
if err then
minetest.chat_send_player(name, "Error loading legacy file: "..err)
minetest.chat_send_player(name, S("Error loading legacy file: @1", err))
return
end
else
minetest.chat_send_player(name, "Invalid version number. (0 allowed)")
minetest.chat_send_player(name, S("Invalid version number. (0 allowed)"))
return
end
minetest.chat_send_player(name, "Legacy file loaded.")
minetest.chat_send_player(name, S("Legacy file loaded."))
for k, area in pairs(areas.areas) do
-- New position format
@ -34,20 +35,21 @@ minetest.register_chatcommand("legacy_load_areas", {
areas:sortPos(area.pos1, area.pos2)
-- Add name
area.name = "unnamed"
area.name = S("unnamed")
-- Remove ID
area.id = nil
end
minetest.chat_send_player(name, "Table format updated.")
minetest.chat_send_player(name, S("Table format updated."))
areas:save()
minetest.chat_send_player(name, "Converted areas saved. Done.")
minetest.chat_send_player(name, S("Converted areas saved. Done."))
end
})
function areas:node_ownership_load()
local filename = minetest.get_worldpath().."/owners.tbl"
local tables, err
tables, err = loadfile(filename)
if err then
return err
@ -104,35 +106,3 @@ function areas.hasOwner(pos)
end
return false
end
IsPlayerNodeOwner = areas.isNodeOwner
GetNodeOwnerName = areas.getNodeOwnerName
HasOwner = areas.hasOwner
-- This is entirely untested and may break in strange and new ways.
if areas.config.legacy_table then
owner_defs = setmetatable({}, {
__index = function(table, key)
local a = rawget(areas.areas, key)
if not a then return a end
local b = {}
for k, v in pairs(a) do b[k] = v end
b.x1, b.y1, b.z1 = b.pos1.x, b.pos1.y, b.pos1.z
b.x2, b.y1, b.z2 = b.pos2.x, b.pos2.y, b.pos2.z
b.pos1, b.pos2 = nil, nil
b.id = key
return b
end,
__newindex = function(table, key, value)
local a = value
a.pos1, a.pos2 = {x=a.x1, y=a.y1, z=a.z1},
{x=a.x2, y=a.y2, z=a.z2}
a.x1, a.y1, a.z1, a.x2, a.y2, a.z2 =
nil, nil, nil, nil, nil, nil
a.name = a.name or "unnamed"
a.id = nil
return rawset(areas.areas, key, a)
end
})
end

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

@ -0,0 +1,137 @@
# textdomain: areas
### chatcommands.lua ###
<AreaName>=<NomZone>
<ID> [faction_name]=<ID> [nom_de_faction]
<NewOwner>=<NouveauPropriétaire>
<ParentID>=<IDZonePrincipale>
<PlayerName>=<NomJoueur>
<newName>=<NouveauNom>
@1 has given you control over the area "@2" (ID @3).=@1 vous a donné le contrôle de la zone "@2" (ID @3).
@1 spanning up to @2x@3x@4.=@1 sétendant jusquà @2x@3x@4.
A regular expression is required.=Une expression régulière est requise.
Area @1 does not exist or is not owned by you.=La zone @1 nexiste pas ou ne vous appartient pas.
Area closed for faction members.=Zone fermée aux membres de la faction.
Area closed.=Zone fermée.
Area does not exist.=La zone nexiste pas.
Area is open for members of: @1=Zone ouverte aux membres de ces factions : @1
Area opened.=Zone ouverte.
Area protected. ID: @1=Zone protégée. ID : @1
Area renamed.=Zone renommée.
Area successfully moved.=Zone déplacée avec succès.
Change the owner of an area using its ID=Change le propriétaire dune zone en utilisant son ID.
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.
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 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.
Limit: @1 areas=Limite: @1 zones.
Limit: no area count limit=Limite: pas de limite de nombre de zones.
List your areas, or all areas if you are an admin.=Liste vos zones, ou toutes les zones si vous êtes administrateur.
Move (or resize) an area to the current positions.=Déplace (ou redimensionne) une zone aux positions actuelles.
No matches found.=Aucun résultat.
No visible areas.=Pas de zone visible.
Owner changed.=Propriétaire changé.
Players with the "@1" privilege can protect up to @2 areas=Les joueurs avec le privilège "@1" peuvent protéger jusquà @2 zones
Protect an area between two positions and give a player access to it without setting the parent of the area to any existing area=Protège une zone entre deux positions et donne à un joueur accès à cette zone sans définir la zone principale de cette zone ni aucune zone existante.
Protect your own area=Protège votre zone.
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.
Removed area @1=Zone @1 supprimée.
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
Rename an area that you own=Renomme une zone qui vous appartient.
Self protection is disabled.=Lautoprotection est désactivée.
Self protection is enabled.=Lautoprotection est activée.
That area doesn't exist.=La zone nexiste pas.
The player "@1" does not exist.=Le joueur "@1" nexiste pas.
Toggle an area open (anyone can interact) or closed=Bascule entre zone ouverte (tout le monde peut intéragir) ou fermée.
Toggle an area open/closed for members in your faction.=Bascule entre zone ouverte/fermée pour les membres de votre faction.
You are an area administrator ("areas" privilege).=Vous êtes un administrateur de zone (privilège "areas").
You can protect areas=Vous pouvez protéger des zones.
You can't protect that area.=Vous ne pouvez pas protéger cette zone.
You can't protect that area: @1=Vous ne pouvez pas protéger cette zone : @1.
You don't have the necessary privilege ("@1").=Vous navez pas le privilège nécessaire ("@1").
You don't own that area.=Vous ne possédez pas cette zone.
You have @1 areas.=Vous avez @1 zones.
You have been granted control over area #@1. Type /list_areas to show your areas.=Vous avez reçu lautorisation de contrôler la zone #@1.
You have extended area protection limits ("areas_high_limit" privilege).=Votre limite de protection de zones est étendue (privilège "areas_high_limit").
You have the necessary privilege ("@1").=Vous avez le privilège nécessaire ("@1").
You need to select an area first.=Vous devez sélectionner une zone dabord.
### chatcommands.lua ###
### pos.lua ###
<ID>=<ID>
Invalid usage, see /help @1.=Utilisation incorrecte, voir /help @1.
### hud.lua ###
:open= : ouverte
Areas:=Zones :
### init.lua ###
Can administer areas.=Permet dadministrer des zones.
Can protect areas.=Permet de protéger des zones.
Can protect more, bigger areas.=Permet de protéger plus, et de plus grandes zones.
### interact.lua ###
@1 is protected by @2.=@1 est protégée par @2.
### internal.lua ###
Area is too big.=La zone est trop grande.
Self protection is disabled or you do not have the necessary privilege.=Lautoprotection est désactivée ou vous navez pas le privilège nécessaire.
The area intersects with @1 [@2] (@3).=La zone a une intersection avec @1 [@2] (@3).
You have reached the maximum amount of areas that you are allowed to protect.=Vous avez atteint le nombre maximum de zones que vous êtes autorisé à protéger.
### legacy.lua ###
<version>=<version>
Converted areas saved. Done.=Zones converties sauvegardées. Fait.
Converting areas…=Conversion des zones…
Error loading legacy file: @1=Erreur lors du chargement du fichier : @1
Invalid version number. (0 allowed)=Numéro de version invalide. (0 autorisé)
Legacy file loaded.=Fichier obsolète chargé.
Loads, converts, and saves the areas from a legacy save file.=Charge, fait la conversion et sauvegarde les zones depuis un fichier de sauvegarde obsolète.
Table format updated.=Format de tableau mis à jour.
unnamed=Non nommé
### pos.lua ###
<not set>=<no définie>
Area @1 selected.=Zone @1 sélectionnée.
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: =Position @1 :
Select an area by ID.=Sélectionnez une zone par son ID.
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.
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, or position 2 by punching nodes, or display the region=Définit la région de protection de zone, la position 1, ou la position 2 en frappant des blocs, ou en affichant la région.
The area @1 does not exist.=La zone @1 nexiste pas.
Unable to get position.=Impossible dobtenir la position.
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.=

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

@ -0,0 +1,137 @@
# textdomain: areas
### chatcommands.lua ###
<AreaName>=<NomeArea>
<ID> [faction_name]= <ID> [nome_fazione]
<NewOwner>=<NuovoProprietario>
<ParentID>=<IDparent>
<PlayerName>=<NomeGiocatore>
<newName>=<nuovoNome>
@1 has given you control over the area "@2" (ID @3).=@1 ti ha dato il controllo sull'area "@2" (ID @3).
@1 spanning up to @2x@3x@4.=@1 si estende fino a @2x@3@4.
A regular expression is required.=È necessaria una espressione regolare.
Area @1 does not exist or is not owned by you.=L'area @1 non esiste o non è di tua proprietà.
Area closed for faction members.=Area chiusa per i membri della fazione.
Area closed.=Area chiusa.
Area does not exist.=L'area non esiste.
Area is open for members of: @1=L'area è aperta ai membri di: @1
Area opened.=Area aperta.
Area protected. ID: @1=Area protetta. ID: @1
Area renamed.=Area rinominata.
Area successfully moved.=Area spostata con successo.
Change the owner of an area using its ID=Cambia il proprietario di un'area usando il suo ID
Faction doesn't exists=La fazione non esiste
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.
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.
Limit: @1 areas=Limite: @1 aree
Limit: no area count limit=Limite: nessun limite al numero delle aree
List your areas, or all areas if you are an admin.=Elenca le tue aree, o tutte le aree se sei un amministratore.
Move (or resize) an area to the current positions.=Sposta (o ridimensiona) un'area alle posizioni attuali.
No matches found.=Nessuna corrispondenza trovata.
No visible areas.=Nessuna area visibile.
Owner changed.=Proprietario cambiato.
Players with the "@1" privilege can protect up to @2 areas=I giocatori col privilegio "@1" possono proteggere fino a @2 aree
Protect an area between two positions and give a player access to it without setting the parent of the area to any existing area=Proteggi un'area tra due posizioni e danne l'accesso a un giocatore senza impostare il parent dell'area a qualsiasi area esistente
Protect your own area=Proteggi la tua area
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
Removed area @1=Eliminata l'area @1
Removed area @1 and its sub areas.=Eliminata l'area @1 e le sue sotto-aree.
Removes all ownerless areas=
Rename an area that you own=Rinomina un'area che ti appartiene
Self protection is disabled.=L'auto-protezione è disattivata.
Self protection is enabled.=L'auto-protezione è attivata.
That area doesn't exist.=Quell'area non esiste.
The player "@1" does not exist.=Il giocatore "@1" non esiste.
Toggle an area open (anyone can interact) or closed=Apri o chiudi un'area (chiunque può interagirvi)
Toggle an area open/closed for members in your faction.=Apri o chiudi un'area per i membri della tua fazione.
You are an area administrator ("areas" privilege).=Sei un amministratore di aree (privilegio "areas")
You can protect areas=Puoi proteggere aree
You can't protect that area.=Non puoi proteggere quell'area.
You can't protect that area: @1=Non puoi proteggere quell'area: @1
You don't have the necessary privilege ("@1").=Non hai il privilegio necessario ("@1")
You don't own that area.=Non possiedi quell'area.
You have @1 areas.=Hai @1 aree.
You have been granted control over area #@1. Type /list_areas to show your areas.=Ti è stato concesso il controllo sull'area #@1. Digita /list_areas per mostrare le tue aree.
You have extended area protection limits ("areas_high_limit" privilege).=Hai limiti di protezione aree estesi (privilegio "areas_high_limit")
You have the necessary privilege ("@1").=Hai il privilegio necessario ("@1")
You need to select an area first.=Prima devi selezionare un'area.
### chatcommands.lua ###
### pos.lua ###
<ID>=<ID>
Invalid usage, see /help @1.=Utilizzo non valido, si veda /help @1.
### hud.lua ###
:open=:aperta
Areas:=Aree:
### init.lua ###
Can administer areas.=
Can protect areas.=
Can protect more, bigger areas.=
### interact.lua ###
@1 is protected by @2.=@1 è protetta da @2.
### internal.lua ###
Area is too big.=L'area è troppo grande.
Self protection is disabled or you do not have the necessary privilege.=L'auto-protezione è disattivata o non possiedi il privilegio necessario.
The area intersects with @1 [@2] (@3).=L'area interseca con @1 [@2] (@3).
You have reached the maximum amount of areas that you are allowed to protect.=Hai raggiunto il numero massimo di aree che ti è consentito proteggere.
### legacy.lua ###
<version>=<versione>
Converted areas saved. Done.=Aree convertite salvate. Fatto.
Converting areas…=Conversione delle aree...
Error loading legacy file: @1=Errore nel caricamento del file precedente: @1
Invalid version number. (0 allowed)=Numero di versione non valido. (0 permesso)
Legacy file loaded.=File precedente caricato.
Loads, converts, and saves the areas from a legacy save file.=Carica, converte e salva le aree da un file di salvataggio precedente.
Table format updated.=Aggiornato il formato della tabella.
unnamed=innominato
### pos.lua ###
<not set>=<non impostato>
Area @1 selected.=Area @1 selezionata.
Area position @1 set to @2=Posizione @1 dell'area impostata a @2
Position @1 set to @2=Posizione @1 impostata a @2
Position @1: =Posizione @1:
Select an area by ID.=Scegli un'area tramite l'ID.
Select position @1 by punching a node.=Seleziona la posizione @1 colpendo un nodo.
Select positions by punching two nodes.=Seleziona le posizioni colpendo due nodi.
Set area protection region position @1 to your location or the one specified=Imposta la protezione area della posizione @1 della regione alla tua posizione o quella specificata
Set area protection region, position 1, or position 2 by punching nodes, or display the region=Imposta la protezione area della regione, posizione 1, o posizione 2, colpendo due nodi, o mostra la regione
The area @1 does not exist.=L'area @1 non esiste.
Unable to get position.=Impossibile ottenere la posizione.
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或之後的版本。

137
locale/template.txt 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 spanning up to @2x@3x@4.=
A regular expression is required.=
Area @1 does not exist or is not owned by you.=
Area closed for faction members.=
Area closed.=
Area does not exist.=
Area is open for members of: @1=
Area opened.=
Area protected. ID: @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=
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.=
Invalid regular expression.=
Limit: @1 areas=
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=
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=
Removed area @1 and its sub areas.=
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.=
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).=
You can protect areas=
You can't protect that area.=
You can't protect that area: @1=
You don't have the necessary privilege ("@1").=
You don't own that area.=
You have @1 areas.=
You have been granted control over area #@1. Type /list_areas to show your areas.=
You have extended area protection limits ("areas_high_limit" privilege).=
You have the necessary privilege ("@1").=
You need to select an area first.=
### chatcommands.lua ###
### pos.lua ###
<ID>=
Invalid usage, see /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.=
### 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).=
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=
Invalid version number. (0 allowed)=
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.=
Area position @1 set to @2=
Position @1 set to @2=
Position @1: =
Select an area by ID.=
Select position @1 by punching a node.=
Select positions by punching two nodes.=
Set area protection region position @1 to your location or the one specified=
Set area protection region, position 1, or position 2 by punching nodes, or display the region=
The area @1 does not exist.=
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.=

2
mod.conf Normal file
View File

@ -0,0 +1,2 @@
name = areas
optional_depends = playerfactions

173
pos.lua
View File

@ -1,3 +1,4 @@
local S = minetest.get_translator("areas")
-- I could depend on WorldEdit for this, but you need to have the 'worldedit'
-- permission to use those commands and you don't have
@ -11,109 +12,160 @@ areas.set_pos = {}
areas.pos1 = {}
areas.pos2 = {}
local LIMIT = 30992 -- this is due to MAPBLOCK_SIZE=16!
local function posLimit(pos)
return {
x = math.max(math.min(pos.x, LIMIT), -LIMIT),
y = math.max(math.min(pos.y, LIMIT), -LIMIT),
z = math.max(math.min(pos.z, LIMIT), -LIMIT)
}
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", {
params = "<ID>",
description = "Select a area by id.",
params = S("<ID>"),
description = S("Select an area by ID."),
func = function(name, param)
local id = tonumber(param)
if not id then
return false, "Invalid usage, see /help select_area."
return false, S("Invalid usage, see /help @1.", "select_area")
end
if not areas.areas[id] then
return false, "The area "..id.." does not exist."
return false, S("The area @1 does not exist.", id)
end
areas:setPos1(name, areas.areas[id].pos1)
areas:setPos2(name, areas.areas[id].pos2)
return true, "Area "..id.." selected."
return true, S("Area @1 selected.", id)
end,
})
minetest.register_chatcommand("area_pos1", {
params = "[X Y Z|X,Y,Z]",
description = "Set area protection region position 1 to your"
.." location or the one specified",
description = S("Set area protection region position @1 to your"
.." location or the one specified", "1"),
privs = {},
func = function(name, param)
local pos = nil
local found, _, x, y, z = param:find(
"^(-?%d+)[, ](-?%d+)[, ](-?%d+)$")
if found then
pos = {x=tonumber(x), y=tonumber(y), z=tonumber(z)}
elseif param == "" then
local player = minetest.get_player_by_name(name)
if player then
pos = player:getpos()
else
return false, "Unable to get position."
end
else
return false, "Invalid usage, see /help area_pos1."
local pos
local player = minetest.get_player_by_name(name)
if player then
pos = vector.round(player:get_pos())
end
pos = vector.round(pos)
local found, _, x_str, y_str, z_str = param:find(
"^(~?-?%d*)[, ](~?-?%d*)[, ](~?-?%d*)$")
if found then
local get_pos, reason = parse_relative_pos(x_str, y_str, z_str, pos)
if get_pos then
pos = get_pos
elseif not get_pos and reason then
return false, reason
end
elseif param ~= "" then
return false, S("Invalid usage, see /help @1.", "area_pos1")
end
if not pos then
return false, S("Unable to get position.")
end
pos = posLimit(vector.round(pos))
areas:setPos1(name, pos)
return true, "Area position 1 set to "
..minetest.pos_to_string(pos)
return true, S("Area position @1 set to @2", "1",
minetest.pos_to_string(pos))
end,
})
minetest.register_chatcommand("area_pos2", {
params = "[X Y Z|X,Y,Z]",
description = "Set area protection region position 2 to your"
.." location or the one specified",
description = S("Set area protection region position @1 to your"
.." location or the one specified", "2"),
func = function(name, param)
local pos = nil
local found, _, x, y, z = param:find(
"^(-?%d+)[, ](-?%d+)[, ](-?%d+)$")
if found then
pos = {x=tonumber(x), y=tonumber(y), z=tonumber(z)}
elseif param == "" then
local player = minetest.get_player_by_name(name)
if player then
pos = player:getpos()
else
return false, "Unable to get position."
end
else
return false, "Invalid usage, see /help area_pos2."
local pos
local player = minetest.get_player_by_name(name)
if player then
pos = vector.round(player:get_pos())
end
pos = vector.round(pos)
local found, _, x_str, y_str, z_str = param:find(
"^(~?-?%d*)[, ](~?-?%d*)[, ](~?-?%d*)$")
if found then
local get_pos, reason = parse_relative_pos(x_str, y_str, z_str, pos)
if get_pos then
pos = get_pos
elseif not get_pos and reason then
return false, reason
end
elseif param ~= "" then
return false, S("Invalid usage, see /help @1.", "area_pos2")
end
if not pos then
return false, S("Unable to get position.")
end
pos = posLimit(vector.round(pos))
areas:setPos2(name, pos)
return true, "Area position 2 set to "
..minetest.pos_to_string(pos)
return true, S("Area position @1 set to @2", "2",
minetest.pos_to_string(pos))
end,
})
minetest.register_chatcommand("area_pos", {
params = "set/set1/set2/get",
description = "Set area protection region, position 1, or position 2"
.." by punching nodes, or display the region",
description = S("Set area protection region, position 1, or position 2"
.." by punching nodes, or display the region"),
func = function(name, param)
if param == "set" then -- Set both area positions
areas.set_pos[name] = "pos1"
return true, "Select positions by punching two nodes."
return true, S("Select positions by punching two nodes.")
elseif param == "set1" then -- Set area position 1
areas.set_pos[name] = "pos1only"
return true, "Select position 1 by punching a node."
return true, S("Select position @1 by punching a node.", "1")
elseif param == "set2" then -- Set area position 2
areas.set_pos[name] = "pos2"
return true, "Select position 2 by punching a node."
return true, S("Select position @1 by punching a node.", "2")
elseif param == "get" then -- Display current area positions
local pos1str, pos2str = "Position 1: ", "Position 2: "
local pos1str, pos2str = S("Position @1: ", "1"), S("Position @1: ", "2")
if areas.pos1[name] then
pos1str = pos1str..minetest.pos_to_string(areas.pos1[name])
else
pos1str = pos1str.."<not set>"
pos1str = pos1str..S("<not set>")
end
if areas.pos2[name] then
pos2str = pos2str..minetest.pos_to_string(areas.pos2[name])
else
pos2str = pos2str.."<not set>"
pos2str = pos2str..S("<not set>")
end
return true, pos1str.."\n"..pos2str
else
return false, "Unknown subcommand: "..param
return false, S("Unknown subcommand: @1", param)
end
end,
})
@ -130,12 +182,12 @@ function areas:getPos(playerName)
end
function areas:setPos1(playerName, pos)
areas.pos1[playerName] = pos
areas.pos1[playerName] = posLimit(pos)
areas.markPos1(playerName)
end
function areas:setPos2(playerName, pos)
areas.pos2[playerName] = pos
areas.pos2[playerName] = posLimit(pos)
areas.markPos2(playerName)
end
@ -149,22 +201,22 @@ minetest.register_on_punchnode(function(pos, node, puncher)
areas.markPos1(name)
areas.set_pos[name] = "pos2"
minetest.chat_send_player(name,
"Position 1 set to "
..minetest.pos_to_string(pos))
S("Position @1 set to @2", "1",
minetest.pos_to_string(pos)))
elseif areas.set_pos[name] == "pos1only" then
areas.pos1[name] = pos
areas.markPos1(name)
areas.set_pos[name] = nil
minetest.chat_send_player(name,
"Position 1 set to "
..minetest.pos_to_string(pos))
S("Position @1 set to @2", "1",
minetest.pos_to_string(pos)))
elseif areas.set_pos[name] == "pos2" then
areas.pos2[name] = pos
areas.markPos2(name)
areas.set_pos[name] = nil
minetest.chat_send_player(name,
"Position 2 set to "
..minetest.pos_to_string(pos))
S("Position @1 set to @2", "2",
minetest.pos_to_string(pos)))
end
end
end)
@ -252,4 +304,3 @@ minetest.register_entity("areas:pos2", {
areas.marker2[name] = nil
end,
})

View File

@ -2,42 +2,44 @@ local world_path = minetest.get_worldpath()
areas.config = {}
local function setting(tp, name, default)
local full_name = "areas."..name
local function setting(name, tp, default)
local full_name = "areas." .. name
local value
if tp == "boolean" then
value = minetest.setting_getbool(full_name)
if tp == "bool" then
value = minetest.settings:get_bool(full_name)
default = value == nil and minetest.is_yes(default)
elseif tp == "string" then
value = minetest.setting_get(full_name)
elseif tp == "position" then
value = minetest.settings:get(full_name)
elseif tp == "v3f" then
value = minetest.setting_get_pos(full_name)
elseif tp == "number" then
value = tonumber(minetest.setting_get(full_name))
default = value == nil and minetest.string_to_pos(default)
elseif tp == "float" or tp == "int" then
value = tonumber(minetest.settings:get(full_name))
local v, other = default:match("^(%S+) (.+)")
default = value == nil and tonumber(other and v or default)
else
error("Invalid setting type!")
error("Cannot parse setting type " .. tp)
end
if value == nil then
value = default
assert(default ~= nil, "Cannot parse default for " .. full_name)
end
--print("add", name, default, value)
areas.config[name] = value
end
local file = io.open(areas.modpath .. "/settingtypes.txt", "r")
for line in file:lines() do
local name, tp, value = line:match("^areas%.(%S+) %(.*%) (%S+) (.*)")
if value then
setting(name, tp, value)
end
end
file:close()
--------------
-- Settings --
--------------
setting("string", "filename", world_path.."/areas.dat")
-- Allow players with a privilege create their own areas
-- within the maximum size and number.
setting("boolean", "self_protection", false)
setting("string", "self_protection_privilege", "interact")
setting("position", "self_protection_max_size", {x=64, y=128, z=64})
setting("number", "self_protection_max_areas", 4)
-- For players with the areas_high_limit privilege.
setting("position", "self_protection_max_size_high", {x=512, y=512, z=512})
setting("number", "self_protection_max_areas_high", 32)
-- legacy_table (owner_defs) compatibility. Untested and has known issues.
setting("boolean", "legacy_table", false)
setting("filename", "string", world_path.."/areas.dat")

37
settingtypes.txt Normal file
View File

@ -0,0 +1,37 @@
# This file is parsed in "settings.lua". Check regex first.
# Static paths do not work well with settings
#areas.filename (Configuration file path) string (world_path)/areas.dat
# 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
# Self protection: Privilege required to protect an area
areas.self_protection_privilege (Self protection: Required privs) string interact
# Refresh delay for the name displays in the HUD in seconds
areas.tick (HUD update delay) float 0.5 0 100
# Enable the legacy owner_defs metatable mode. Untested and possibly unstable
areas.legacy_table (Legacy owner_defs metatable) bool false
[Self protection (normal)]
# Self protection (normal): Maximal size of the protectable area
# Only enter positive whole numbers for the coordinate values or you'll mess up stuff.
areas.self_protection_max_size (Maximal area size) v3f (64, 128, 64)
# Self protection (normal): Maximal amount of protected areas per player
areas.self_protection_max_areas (Maximal area count) int 4
[Self protection (high)]
# Self protection (normal): Maximal size of the protectable area
# This setting applies for plyaers with the privilege 'areas_high_limit'
areas.self_protection_max_size_high (Maximal area size) v3f (512, 512, 512)
# Self protection (normal): Maximal amount of protected areas per player
# Only enter positive whole numbers for the coordinate values or you'll mess up stuff.
# This setting applies for plyaers with the privilege 'areas_high_limit'
areas.self_protection_max_areas_high (Maximal area count) float 32

Binary file not shown.

Before

Width:  |  Height:  |  Size: 275 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 440 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 437 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 437 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 341 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 491 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 278 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 495 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 288 B