Compare commits

...

48 Commits

Author SHA1 Message Date
bri cassa 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
bri cassa 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
Crabman77 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
Sys Quatre 76f8ccf8ab Add morefarming and improve farming support on openfarming areas 2020-10-14 22:33:09 +02:00
Sys Quatre 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
Sys Quatre 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
Sys Quatre 99408df96a Delete unused textures 2020-07-05 17:10:03 +02:00
Sys Quatre 42cde6a494 Merge branch 'nalc-1.2-dev' 2020-07-05 17:02:34 +02:00
Sys Quatre e0783cf8bf Corrige crash au démarrage 2020-06-15 01:10:47 +02:00
Sys Quatre 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
Sys Quatre 54c504fa0d [areas] Remet le HUD comme avant la modif du feae996 2019-12-30 01:02:36 +01:00
Sys Quatre 26d6f56485 Ajoute description privilège \"megabuilder\" pour admins d'areas 2019-12-28 15:26:21 +01:00
Sys Quatre 57f20bb25f Ajoute infos privilège "megabuilder" dans la commande /area_info 2019-12-28 15:07:13 +01:00
Sys Quatre 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
27 changed files with 1080 additions and 515 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 Configuration
------------- -------------
If you wish to specify configuration options, such as whether players are Open the tab `Settings -> All Settings -> Mods -> areas` to get a list of all
allowed to protect their own areas with the `protect` command (disabled by possible settings.
default), you should check config.lua and set the appropriate settings in your
server's configuration file (probably `minetest.conf`). For server owners: Check `settingtypes.txt` and modify your `minetest.conf`
according to the wanted setting changes.
Tutorial Tutorial
-------- --------
To protect an area you must first set the corner positions of the area. 1) Specify the corner positions of the area you would like to protect.
In order to set the corner positions you can run: Use one of the following commands:
* `/area_pos set` and punch the two corner nodes to set them. * `/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 * `/area_pos set1/set2` and punch only the first or second corner node to
set them one at a time. 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 * `/area_pos1/2 X Y Z` to set one of the positions to the specified
coordinates. coordinates.
Once you have set the border positions you can protect the area by running one 2) Protect the selected area by running one of the following commands:
of the following commands:
* `/set_owner <OwnerName> <AreaName>` -- If you have the `areas` privilege. * `/set_owner <OwnerName> <AreaName>` -- If you have the `areas` privilege.
* `/protect <AreaName>` -- If you have the `areas` privilege or the server * `/protect <AreaName>` -- If you have the `areas` privilege or the server
administrator has enabled area self-protection. administrator has enabled area self-protection.
The area name is used only for informational purposes (so that you know what The area name is used only for informational purposes and has no functional
an area is for). It is not used for any other purpose. importance.
For example: `/set_owner SomePlayer Mese city` 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 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
with the `add_owner` command. Anyone with an area can use the `add_owner` select the corners of the sub-area as you did in step 1.
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 If your markers are still around your original area and you want to grant
are still around your original area and you want to grant access to your 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
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
markers and want to grant access to a full area. 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 1. The ID number of the parent area (the area that you want to add a
sub-area to). sub-area to).
2. The name of the player that will own the sub-area. 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 * `/remove_area <ID>` -- Removes an area that you own. Any sub-areas of that
area are made sub-areas of the removed area's parent, if it exists. area are made sub-areas of the removed area's parent, if it exists.
If the removed area has no parent it's sub-areas will have no parent. If the removed area has no parent its sub-areas will have no parent.
* `/recursive_remove_areas <ID>` -- Removes an area and all sub-areas of it. * `/recursive_remove_areas <ID>` -- Removes an area and all sub-areas of it.
@ -94,11 +107,21 @@ Commands
* `/area_pos2 [X,Y,Z|X Y Z]` -- Sets area position two to your position or * `/area_pos2 [X,Y,Z|X Y Z]` -- Sets area position two to your position or
the one supplied. 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 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. Licensed under the GNU LGPL version 2.1 or later.
See LICENSE.txt and http://www.gnu.org/licenses/lgpl-2.1.txt See LICENSE.txt and http://www.gnu.org/licenses/lgpl-2.1.txt

189
api.lua
View File

@ -1,14 +1,57 @@
local hudHandlers = {}
--plants to place in openfarming ---plants to place in openfarming
local plants = { ["farming:blueberries"]="air", ["farming:carrot"]="air", ["farming:coffee_beans"]="air", ["farming:corn"]="air", ["farming:cucumber"]="air", local plants = {
["farming:melon_slice"]="air", ["farming:potato"]="air", ["farming:pumpkin_slice"]="air", ["farming:raspberries"]="air", ["farming:rhubarb"]="air", ["farming:beetroot"]="air", ["farming:blueberries"]="air", ["farming:cabbage"]="air",
["farming:tomato"]="air", ["farming:seed_cotton"]="air", ["farming:seed_wheat"]="air",["default:papyrus"]="air", ["farming:trellis"]="air", ["farming:carrot"]="air", ["farming:chili_pepper"]="air", ["farming:coffee_beans"]="air",
["farming:grapes"]="farming:trellis", ["farming:beanpole"]="air", ["farming:beans"]="farming:beanpole", ["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_on_adds = {}
areas.registered_on_removes = {}
areas.registered_on_moves = {}
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. --- Returns a list of areas that include the provided position.
function areas:getAreasAtPos(pos) function areas:getAreasAtPos(pos)
local res = {} local res = {}
if self.store then if self.store then
local a = self.store:get_areas_for_pos(pos, false, true) local a = self.store:get_areas_for_pos(pos, false, true)
for store_id, store_area in pairs(a) do for store_id, store_area in pairs(a) do
@ -64,33 +107,48 @@ function areas:canInteract(pos, name)
return true return true
end end
local owned = false 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 for _, area in pairs(self:getAreasAtPos(pos)) do
if area.owner == name or area.open then if area.owner == name or area.open then
return true 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 wstack = player:get_wielded_item():get_name()
if wstack == "" then wstack = "hand" end
--on_dig
if minetest.get_item_group(node, "plant") == 1 and (wstack == "hand" or minetest.registered_tools[wstack]) then
return true
end
--on_place
if plants[wstack] ~= nil and plants[wstack] == node then
return true
end
owned = true
else
owned = true
end end
if 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
--on_dig
if minetest.get_item_group(node, "plant") == 1 and (wstack == "hand" or minetest.registered_tools[wstack]) then
return true
end
--on_place
if plants[wstack] ~= nil and plants[wstack] == node then
return true
end
end
end
if areas.factions_available and area.faction_open then
if (factions.version or 0) < 2 then
local faction_name = factions.get_player_faction(name)
if faction_name then
for _, fname in ipairs(area.faction_open or {}) do
if faction_name == fname then
return true
end
end
end
else
for _, fname in ipairs(area.faction_open or {}) do
if factions.player_is_in_faction(fname, name) then
return true
end
end
end
end
owned = true
end end
return not owned return not owned
end end
@ -108,7 +166,7 @@ end
-- Note that this fails and returns false when the specified area is fully -- 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 -- owned by the player, but with multiple protection zones, none of which
-- cover the entire checked area. -- 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. -- @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 Boolean indicating whether the player can interact in that area.
-- @return Un-owned intersecting area ID, if found. -- @return Un-owned intersecting area ID, if found.
@ -153,74 +211,3 @@ function areas:canInteractInArea(pos1, pos2, name, allow_open)
-- intersecting areas and they are all owned by the player. -- intersecting areas and they are all owned by the player.
return true return true
end 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

48
api.md Normal file
View File

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

126
hud.lua
View File

@ -1,85 +1,89 @@
-- This is inspired by the landrush mod by Bremaweb -- This is inspired by the landrush mod by Bremaweb
local S = minetest.get_translator("areas")
areas.hud = {} 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 for _, player in pairs(minetest.get_connected_players()) do
local name = player:get_player_name() local name = player:get_player_name()
local pos = vector.round(player:getpos()) local pos = vector.round(player:get_pos())
local area_text = "No area(s)\n\n" pos = vector.apply(pos, function(p)
local area_owner_name = "" return math.max(math.min(p, 2147483), -2147483)
local mod_owner = 0 end)
local mod_open = 0 local areaStrings = {}
local mod_farming = 0
local area_name = ""
local nb_areas = 0
for id, area in pairs(areas:getAreasAtPos(pos)) do for id, area in pairs(areas:getAreasAtPos(pos)) do
nb_areas = nb_areas+1 local faction_info
if areas:isAreaOwner(id, name) then if area.faction_open and areas.factions_available then
mod_owner = 1 -- 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 end
if area.open then table.insert(areaStrings, ("%s [%u] (%s%s%s)")
mod_open = 1 :format(area.name, id, area.owner,
end area.open and S(":open") or area.openfarming and ":openfarming" or "",
if area.openfarming then faction_info and ":"..faction_info or ""))
mod_farming = 1
end
if not area.parent then
area_owner_name = area.owner
area_name = area.name
end
end end
local icon = "areas_not_area.png" for i, area in pairs(areas:getExternalHudEntries(pos)) do
if nb_areas > 0 then local str = ""
local plural = "" if area.name then str = area.name .. " " end
if nb_areas > 1 then if area.id then str = str.."["..area.id.."] " end
plural = "s" if area.owner then str = str.."("..area.owner..")" end
end table.insert(areaStrings, str)
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)
end 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({ 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({
hud_elem_type = "text", hud_elem_type = "text",
name = "Areas", name = "Areas",
number = 0xFFFFFF, number = 0xFFFFFF,
position = {x=0, y=1}, position = {x=0, y=1},
offset = {x=48, y=-40}, offset = {x=8, y=-8},
text = area_text, text = areaString,
scale = {x=1, y=1}, scale = {x=200, y=60},
alignment = {x=1, y=-1}, alignment = {x=1, y=-1},
}) })
areas.hud[name].old_area_text = area_text hud.oldAreas = areaString
areas.hud[name].old_icon = icon return
else elseif hud.oldAreas ~= areaString then
if areas.hud[name].old_area_text ~= area_text then player:hud_change(hud.areasId, "text", areaString)
player:hud_change(areas.hud[name].areas_id, "text", area_text) hud.oldAreas = areaString
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
end end
end end
minetest.after(1.5, tick) end)
end
tick()
minetest.register_on_leaveplayer(function(player) minetest.register_on_leaveplayer(function(player)
areas.hud[player:get_player_name()] = nil areas.hud[player:get_player_name()] = nil
end) end)

View File

@ -4,6 +4,8 @@
areas = {} areas = {}
areas.factions_available = minetest.get_modpath("playerfactions") and true
areas.adminPrivs = {areas=true} areas.adminPrivs = {areas=true}
areas.startTime = os.clock() areas.startTime = os.clock()
@ -19,21 +21,28 @@ dofile(areas.modpath.."/hud.lua")
areas:load() areas:load()
local S = minetest.get_translator("areas")
minetest.register_privilege("areas", { minetest.register_privilege("areas", {
description = "Can administer areas." description = S("Can administer areas."),
give_to_singleplayer = false
}) })
minetest.register_privilege("areas_high_limit", { 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 if not minetest.registered_privileges[areas.config.self_protection_privilege] then
minetest.register_privilege(areas.config.self_protection_privilege, { minetest.register_privilege(areas.config.self_protection_privilege, {
description = "Can protect areas.", description = S("Can protect areas."),
}) })
end end
if minetest.setting_getbool("log_mod") then if minetest.settings:get_bool("log_mods") then
local diffTime = os.clock() - areas.startTime local diffTime = os.clock() - areas.startTime
minetest.log("action", "areas loaded in "..diffTime.."s.") minetest.log("action", "areas loaded in "..diffTime.."s.")
end end

View File

@ -1,3 +1,4 @@
local S = minetest.get_translator("areas")
local old_is_protected = minetest.is_protected local old_is_protected = minetest.is_protected
function minetest.is_protected(pos, name) 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 if not areas:canInteract(pos, name) then
local owners = areas:getNodeOwners(pos) local owners = areas:getNodeOwners(pos)
minetest.chat_send_player(name, minetest.chat_send_player(name,
("%s is protected by %s."):format( S("@1 is protected by @2.",
minetest.pos_to_string(pos), minetest.pos_to_string(pos),
table.concat(owners, ", "))) table.concat(owners, ", ")))
end end
end) end)

View File

@ -1,23 +1,29 @@
-- Mega_builder privilege local S = minetest.get_translator("areas")
minetest.register_privilege("megabuilder","Can protect an infinite amount of areas.")
function areas:player_exists(name) function areas:player_exists(name)
return minetest.get_auth_handler().get_auth(name) ~= nil return minetest.get_auth_handler().get_auth(name) ~= nil
end 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 -- Save the areas table to a file
function areas:save() function areas:save()
local datastr = minetest.serialize(self.areas) local datastr = minetest.write_json(self.areas)
if not datastr then if not datastr then
minetest.log("error", "[areas] Failed to serialize area data!") minetest.log("error", "[areas] Failed to serialize area data!")
return return
end end
local file, err = io.open(self.config.filename, "w") return safe_file_write(self.config.filename, datastr)
if err then
return err
end
file:write(datastr)
file:close()
end end
-- Load the areas table from the save file -- Load the areas table from the save file
@ -27,10 +33,19 @@ function areas:load()
self.areas = self.areas or {} self.areas = self.areas or {}
return err return err
end 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 if type(self.areas) ~= "table" then
self.areas = {} self.areas = {}
end end
if err and #data > 10 then
minetest.log("error", "[areas] Failed to load area data: " ..
tostring(err))
end
file:close() file:close()
self:populateStore() self:populateStore()
end end
@ -42,7 +57,7 @@ end
function areas:checkAreaStoreId(sid) function areas:checkAreaStoreId(sid)
if not sid then if not sid then
minetest.log("error", "AreaStore failed to find an ID for an " 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 = nil
self.store_ids = nil self.store_ids = nil
end end
@ -88,6 +103,11 @@ function areas:add(owner, name, pos1, pos2, parent)
owner = owner, owner = owner,
parent = parent parent = parent
} }
for i=1, #areas.registered_on_adds do
areas.registered_on_adds[i](id, self.areas[id])
end
-- Add to AreaStore -- Add to AreaStore
if self.store then if self.store then
local sid = self.store:insert_area(pos1, pos2, tostring(id)) local sid = self.store:insert_area(pos1, pos2, tostring(id))
@ -98,7 +118,7 @@ function areas:add(owner, name, pos1, pos2, parent)
return id return id
end end
--- Remove a area, and optionally it's children recursively. --- Remove a area, and optionally its children recursively.
-- If a area is deleted non-recursively the children will -- If a area is deleted non-recursively the children will
-- have the removed area's parent as their new parent. -- have the removed area's parent as their new parent.
function areas:remove(id, recurse) function areas:remove(id, recurse)
@ -120,6 +140,10 @@ function areas:remove(id, recurse)
end end
end end
for i=1, #areas.registered_on_removes do
areas.registered_on_removes[i](id)
end
-- Remove main entry -- Remove main entry
self.areas[id] = nil self.areas[id] = nil
@ -135,6 +159,10 @@ function areas:move(id, area, pos1, pos2)
area.pos1 = pos1 area.pos1 = pos1
area.pos2 = pos2 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 if self.store then
self.store:remove_area(areas.store_ids[id]) self.store:remove_area(areas.store_ids[id])
local sid = self.store:insert_area(pos1, pos2, tostring(id)) local sid = self.store:insert_area(pos1, pos2, tostring(id))
@ -167,7 +195,7 @@ function areas:isSubarea(pos1, pos2, id)
end end
end end
-- Returns a table (list) of children of an area given it's identifier -- Returns a table (list) of children of an area given its identifier
function areas:getChildren(id) function areas:getChildren(id)
local children = {} local children = {}
for cid, area in pairs(self.areas) do for cid, area in pairs(self.areas) do
@ -193,22 +221,22 @@ function areas:canPlayerAddArea(pos1, pos2, name)
-- and if the area is too big. -- and if the area is too big.
if not self.config.self_protection or if not self.config.self_protection or
not privs[areas.config.self_protection_privilege] then not privs[areas.config.self_protection_privilege] then
return false, "Self protection is disabled or you do not have" return false, S("Self protection is disabled or you do not have"
.." the necessary privilege." .." the necessary privilege.")
end end
-- MFF: megabuilders skip checks on size and number of areas. -- MFF: megabuilders skip checks on size and number of areas
if not privs["megabuilder"] then if not privs.megabuilder then
-- Check size
local max_size = privs.areas_high_limit and local max_size = privs.areas_high_limit and
self.config.self_protection_max_size_high or self.config.self_protection_max_size_high or
self.config.self_protection_max_size self.config.self_protection_max_size
if if
(pos2.x - pos1.x) > max_size.x or (pos2.x - pos1.x) > max_size.x or
(pos2.y - pos1.y) > max_size.y or (pos2.y - pos1.y) > max_size.y or
(pos2.z - pos1.z) > max_size.z then (pos2.z - pos1.z) > max_size.z then
return false, "Area is too big." return false, S("Area is too big.")
end end
end
-- Check number of areas the user has and make sure it not above the max -- Check number of areas the user has and make sure it not above the max
local count = 0 local count = 0
@ -218,22 +246,20 @@ function areas:canPlayerAddArea(pos1, pos2, name)
end end
end end
local max_areas = privs.areas_high_limit and local max_areas = privs.areas_high_limit and
self.config.self_protection_max_areas_high or self.config.self_protection_max_areas_high or
self.config.self_protection_max_areas self.config.self_protection_max_areas
if count >= max_areas then if count >= max_areas then
return false, "You have reached the maximum amount of" return false, S("You have reached the maximum amount of"
.." areas that you are allowed to protect." .." areas that you are allowed to protect.")
end
end end
-- Check intersecting areas -- Check intersecting areas
local can, id = self:canMakeArea(pos1, pos2, name) --MFF crabman(25/02/2016) fix areas in areas local can, id = self:canInteractInArea(pos1, pos2, name)
if not can then if not can then
local area = self.areas[id] local area = self.areas[id]
return false, ("The area intersects with %s [%u] (%s).") return false, S("The area intersects with @1 [@2] (@3).",
:format(area.name, id, area.owner) area.name, id, area.owner)
end end
return true return true
end end
@ -288,4 +314,3 @@ function areas:isAreaOwner(id, name)
end end
return false return false
end end

View File

@ -1,25 +1,26 @@
-- This file contains functions to convert from -- This file contains functions to convert from
-- the old areas format and other compatability code. -- the old areas format and other compatability code.
local S = minetest.get_translator("areas")
minetest.register_chatcommand("legacy_load_areas", { minetest.register_chatcommand("legacy_load_areas", {
params = "<version>", params = S("<version>"),
description = "Loads, converts, and saves the areas from" description = S("Loads, converts, and saves the areas from"
.." a legacy save file.", .." a legacy save file."),
privs = {areas=true, server=true}, privs = {areas=true, server=true},
func = function(name, param) func = function(name, param)
minetest.chat_send_player(name, "Converting areas...") minetest.chat_send_player(name, S("Converting areas…"))
local version = tonumber(param) local version = tonumber(param)
if version == 0 then if version == 0 then
err = areas:node_ownership_load() local err = areas:node_ownership_load()
if err then 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 return
end end
else else
minetest.chat_send_player(name, "Invalid version number. (0 allowed)") minetest.chat_send_player(name, S("Invalid version number. (0 allowed)"))
return return
end 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 for k, area in pairs(areas.areas) do
-- New position format -- New position format
@ -34,20 +35,21 @@ minetest.register_chatcommand("legacy_load_areas", {
areas:sortPos(area.pos1, area.pos2) areas:sortPos(area.pos1, area.pos2)
-- Add name -- Add name
area.name = "unnamed" area.name = S("unnamed")
-- Remove ID -- Remove ID
area.id = nil area.id = nil
end end
minetest.chat_send_player(name, "Table format updated.") minetest.chat_send_player(name, S("Table format updated."))
areas:save() areas:save()
minetest.chat_send_player(name, "Converted areas saved. Done.") minetest.chat_send_player(name, S("Converted areas saved. Done."))
end end
}) })
function areas:node_ownership_load() function areas:node_ownership_load()
local filename = minetest.get_worldpath().."/owners.tbl" local filename = minetest.get_worldpath().."/owners.tbl"
local tables, err
tables, err = loadfile(filename) tables, err = loadfile(filename)
if err then if err then
return err return err
@ -104,35 +106,3 @@ function areas.hasOwner(pos)
end end
return false return false
end 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

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

@ -0,0 +1,135 @@
# 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

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

@ -0,0 +1,135 @@
# 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

135
locale/template.txt Normal file
View File

@ -0,0 +1,135 @@
# 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=

2
mod.conf Normal file
View File

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

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

View File

@ -2,42 +2,44 @@ local world_path = minetest.get_worldpath()
areas.config = {} areas.config = {}
local function setting(tp, name, default) local function setting(name, tp, default)
local full_name = "areas."..name local full_name = "areas." .. name
local value local value
if tp == "boolean" then if tp == "bool" then
value = minetest.setting_getbool(full_name) value = minetest.settings:get_bool(full_name)
default = value == nil and minetest.is_yes(default)
elseif tp == "string" then elseif tp == "string" then
value = minetest.setting_get(full_name) value = minetest.settings:get(full_name)
elseif tp == "position" then elseif tp == "v3f" then
value = minetest.setting_get_pos(full_name) value = minetest.setting_get_pos(full_name)
elseif tp == "number" then default = value == nil and minetest.string_to_pos(default)
value = tonumber(minetest.setting_get(full_name)) 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 else
error("Invalid setting type!") error("Cannot parse setting type " .. tp)
end end
if value == nil then if value == nil then
value = default value = default
assert(default ~= nil, "Cannot parse default for " .. full_name)
end end
--print("add", name, default, value)
areas.config[name] = value areas.config[name] = value
end 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 -- -- Settings --
-------------- --------------
setting("string", "filename", world_path.."/areas.dat") setting("filename", "string", 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)

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