2013-09-03 01:16:14 +02:00
|
|
|
function areas:player_exists(name)
|
|
|
|
return minetest.auth_table[name] ~= nil
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Save the areas table to a file
|
|
|
|
function areas:save()
|
|
|
|
file, err = io.open(self.filename, "w")
|
|
|
|
if err then
|
|
|
|
return err
|
|
|
|
end
|
|
|
|
file:write(minetest.serialize(self.areas))
|
|
|
|
file:close()
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Load the areas table from the save file
|
|
|
|
function areas:load()
|
|
|
|
file, err = io.open(self.filename, "r")
|
|
|
|
if err then
|
|
|
|
self.areas = self.areas or {}
|
|
|
|
return err
|
|
|
|
end
|
|
|
|
self.areas = minetest.deserialize(file:read("*a"))
|
|
|
|
if type(self.areas) ~= "table" then self.areas = {} end
|
|
|
|
file:close()
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Shorter than the table function
|
|
|
|
function areas:add(owner, name, pos1, pos2, parent)
|
|
|
|
table.insert(areas.areas, {id=table.maxn(self.areas)+1, name=name,
|
|
|
|
pos1=pos1, pos2=pos2, owner=owner, parent=parent})
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Remove a area, and optionally it's 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)
|
|
|
|
if recurse then
|
|
|
|
-- Recursively find child entries and remove them
|
|
|
|
local cids = self:getChildren(id)
|
|
|
|
for _, cid in pairs(cids) do
|
|
|
|
self:removeArea(cid, true)
|
|
|
|
end
|
|
|
|
else
|
|
|
|
-- Update parents
|
|
|
|
local parent = self:getAreaById(id).parent
|
|
|
|
local children = self:getChildren(id)
|
|
|
|
for _, child in pairs(children) do
|
2013-09-03 07:33:08 +02:00
|
|
|
-- The subarea parent will be niled out if the
|
|
|
|
-- removed area does not have a parent
|
2013-09-03 01:16:14 +02:00
|
|
|
areas.areas[self:getIndexById(child)].parent = parent
|
|
|
|
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Remove main entry
|
|
|
|
table.remove(self.areas, self:getIndexById(id))
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Checks if a area between two points is entirely contained by another area
|
|
|
|
function areas:isSubarea(pos1, pos2, id)
|
|
|
|
local area = areas:getAreaById(id)
|
2013-09-03 07:33:08 +02:00
|
|
|
if not area then
|
|
|
|
return false
|
|
|
|
end
|
|
|
|
p1, p2 = area.pos1, area.pos2
|
|
|
|
if (pos1.x >= p1.x and pos1.x <= p2.x) and
|
|
|
|
(pos2.x >= p1.x and pos2.x <= p2.x) and
|
|
|
|
(pos1.y >= p1.y and pos1.y <= p2.y) and
|
|
|
|
(pos2.y >= p1.y and pos2.y <= p2.y) and
|
|
|
|
(pos1.z >= p1.z and pos1.z <= p2.z) and
|
|
|
|
(pos2.z >= p1.z and pos2.z <= p2.z) then
|
|
|
|
return true
|
2013-09-03 01:16:14 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Returns a table (list) of children of an area given it's identifier
|
|
|
|
function areas:getChildren(id)
|
|
|
|
local children = {}
|
|
|
|
for _, area in pairs(self.areas) do
|
|
|
|
if area.parent and area.parent == id then
|
|
|
|
table.insert(children, area.id)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
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.
|
2013-09-03 07:33:08 +02:00
|
|
|
-- Also checks the size of the area and if the user already
|
|
|
|
-- has more than max_areas.
|
2013-09-03 01:16:14 +02:00
|
|
|
function areas:canPlayerAddArea(pos1, pos2, name)
|
|
|
|
if minetest.check_player_privs(name, {areas=true}) then
|
|
|
|
return true
|
2013-09-03 07:33:08 +02:00
|
|
|
end
|
2013-09-03 01:16:14 +02:00
|
|
|
|
2013-09-03 07:33:08 +02:00
|
|
|
-- Check self protection privilege, if it is enabled,
|
|
|
|
-- and if the area is too big.
|
2013-09-03 01:16:14 +02:00
|
|
|
if (not self.self_protection) or
|
2013-09-03 07:33:08 +02:00
|
|
|
(not minetest.check_player_privs(name,
|
|
|
|
{[areas.self_protection_privilege]=true})) then
|
|
|
|
return false, "Self protection is disabled or you do not have"
|
|
|
|
.." the necessary privilege."
|
2013-09-03 01:16:14 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
if (pos2.x - pos1.x) > self.self_protection_max_size.x or
|
|
|
|
(pos2.y - pos1.y) > self.self_protection_max_size.y or
|
|
|
|
(pos2.z - pos1.z) > self.self_protection_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
|
|
|
|
if self.self_protection then
|
|
|
|
local count = 0
|
|
|
|
for _, area in pairs(self.areas) do
|
|
|
|
if area.owner == name then
|
|
|
|
count = count + 1
|
|
|
|
end
|
|
|
|
end
|
|
|
|
if count > self.self_protection_max_areas then
|
2013-09-03 07:33:08 +02:00
|
|
|
return false, "You have reached the maximum amount"
|
|
|
|
.." of areas that you are allowed to"
|
|
|
|
.." protect."
|
2013-09-03 01:16:14 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Check intersecting areas
|
|
|
|
for _, area in pairs(self.areas) do
|
|
|
|
if (area.pos1.x <= pos2.x and area.pos2.x >= pos1.x) and
|
|
|
|
(area.pos1.y <= pos2.y and area.pos2.y >= pos1.y) and
|
|
|
|
(area.pos1.z <= pos2.z and area.pos2.z >= pos1.z) then
|
|
|
|
--Found an area intersecting with the suplied area
|
|
|
|
if area.owner ~= name then
|
2013-09-03 07:33:08 +02:00
|
|
|
return false, "The area intersects with an"
|
|
|
|
.." area that you do not own."
|
2013-09-03 01:16:14 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
return true, ""
|
|
|
|
end
|
|
|
|
|
2013-09-03 07:33:08 +02:00
|
|
|
-- Given a area returns a string in the format:
|
|
|
|
-- "name [id]: owner (x1, y1, z1) (x2, y2, z2) -> children"
|
2013-09-03 01:16:14 +02:00
|
|
|
function areas:toString(area)
|
|
|
|
local message = area.name..
|
2013-09-03 01:44:18 +02:00
|
|
|
" ["..area.id.."]: "..area.owner.." "..
|
|
|
|
minetest.pos_to_string(area.pos1).." "..
|
2013-09-03 01:16:14 +02:00
|
|
|
minetest.pos_to_string(area.pos2)
|
|
|
|
|
|
|
|
local children = areas:getChildren(id)
|
|
|
|
if #children > 0 then
|
|
|
|
message = message..
|
|
|
|
" -> "..table.concat(children, ", ")
|
|
|
|
end
|
|
|
|
return message
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Returns a area given it's identifier
|
|
|
|
function areas:getAreaById(id)
|
|
|
|
for _, area in pairs(self.areas) do
|
|
|
|
if area.id == id then return area end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Returns a table index for an area given it's identifier
|
|
|
|
function areas:getIndexById(id)
|
|
|
|
for i, area in pairs(self.areas) do
|
|
|
|
if area.id == id then return i end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Re-order areas in table by their identifiers
|
|
|
|
function areas:sort()
|
|
|
|
for k, area in pairs(self.areas) do
|
|
|
|
if area.id ~= k then
|
|
|
|
for _, subarea in pairs(self.areas) do
|
|
|
|
if subarea.parent == area.id then
|
|
|
|
subarea.parent = k
|
|
|
|
end
|
|
|
|
end
|
|
|
|
area.id = k
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Checks if a player owns an area or a parent of it
|
|
|
|
function areas:isAreaOwner(id, name)
|
|
|
|
cur = self:getAreaById(id)
|
|
|
|
if cur and minetest.check_player_privs(name, {areas=true}) then
|
|
|
|
return true
|
|
|
|
end
|
|
|
|
while cur do
|
|
|
|
if cur.owner == name then
|
|
|
|
return true
|
|
|
|
elseif cur.parent then
|
|
|
|
cur = self:getAreaById(cur.parent)
|
|
|
|
else
|
|
|
|
return false
|
|
|
|
end
|
|
|
|
end
|
|
|
|
return false
|
|
|
|
end
|
|
|
|
|