mirror of
https://github.com/minetest-mods/areas.git
synced 2024-12-22 12:52:22 +01:00
Add support for the AreaStore API
This commit is contained in:
parent
177f659f4e
commit
8b0b8c1ad2
101
api.lua
101
api.lua
@ -1,17 +1,54 @@
|
|||||||
|
|
||||||
-- 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 a = {}
|
local res = {}
|
||||||
|
if self.store then
|
||||||
|
local a = self.store:get_areas_for_pos(pos, false, true)
|
||||||
|
for store_id, store_area in pairs(a) do
|
||||||
|
local id = tonumber(store_area.data)
|
||||||
|
res[id] = self.areas[id]
|
||||||
|
end
|
||||||
|
else
|
||||||
local px, py, pz = pos.x, pos.y, pos.z
|
local px, py, pz = pos.x, pos.y, pos.z
|
||||||
for id, area in pairs(self.areas) do
|
for id, area in pairs(self.areas) do
|
||||||
local ap1, ap2 = area.pos1, area.pos2
|
local ap1, ap2 = area.pos1, area.pos2
|
||||||
if px >= ap1.x and px <= ap2.x and
|
if
|
||||||
py >= ap1.y and py <= ap2.y and
|
(px >= ap1.x and px <= ap2.x) and
|
||||||
pz >= ap1.z and pz <= ap2.z then
|
(py >= ap1.y and py <= ap2.y) and
|
||||||
a[id] = area
|
(pz >= ap1.z and pz <= ap2.z) then
|
||||||
|
res[id] = area
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return a
|
end
|
||||||
|
return res
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Returns areas that intersect with the passed area.
|
||||||
|
function areas:getAreasIntersectingArea(pos1, pos2)
|
||||||
|
local res = {}
|
||||||
|
if self.store then
|
||||||
|
local a = self.store:get_areas_in_area(pos1, pos2,
|
||||||
|
true, false, true)
|
||||||
|
for store_id, store_area in pairs(a) do
|
||||||
|
local id = tonumber(store_area.data)
|
||||||
|
res[id] = self.areas[id]
|
||||||
|
end
|
||||||
|
else
|
||||||
|
self:sortPos(pos1, pos2)
|
||||||
|
local p1x, p1y, p1z = pos1.x, pos1.y, pos1.z
|
||||||
|
local p2x, p2y, p2z = pos2.x, pos2.y, pos2.z
|
||||||
|
for id, area in pairs(self.areas) do
|
||||||
|
local ap1, ap2 = area.pos1, area.pos2
|
||||||
|
if
|
||||||
|
(ap1.x <= p2x and ap2.x >= p1x) and
|
||||||
|
(ap1.y <= p2y and ap2.y >= p1y) and
|
||||||
|
(ap1.z <= p2z and ap2.z >= p1z) then
|
||||||
|
-- Found an intersecting area.
|
||||||
|
res[id] = area
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return res
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Checks if the area is unprotected or owned by you
|
-- Checks if the area is unprotected or owned by you
|
||||||
@ -43,41 +80,49 @@ 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 is 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.
|
||||||
function areas:canInteractInArea(pos1, pos2, name, allow_open)
|
function areas:canInteractInArea(pos1, pos2, name, allow_open)
|
||||||
if name and minetest.check_player_privs(name, self.adminPrivs) then
|
if name and minetest.check_player_privs(name, self.adminPrivs) then
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
areas:sortPos(pos1, pos2)
|
self:sortPos(pos1, pos2)
|
||||||
|
|
||||||
|
-- Intersecting non-owned area ID, if found.
|
||||||
|
local blocking_area = nil
|
||||||
|
|
||||||
|
local areas = self:getAreasIntersectingArea(pos1, pos2)
|
||||||
|
for id, area in pairs(areas) do
|
||||||
-- First check for a fully enclosing owned area.
|
-- First check for a fully enclosing owned area.
|
||||||
if name then
|
|
||||||
for id, area in pairs(self.areas) do
|
|
||||||
-- A little optimization: isAreaOwner isn't necessary
|
-- A little optimization: isAreaOwner isn't necessary
|
||||||
-- here since we're iterating through all areas.
|
-- here since we're iterating over all relevant areas.
|
||||||
if area.owner == name and
|
if area.owner == name and
|
||||||
self:isSubarea(pos1, pos2, id) then
|
self:isSubarea(pos1, pos2, id) then
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Then check for intersecting non-owned (blocking) areas.
|
||||||
|
-- We don't bother with this check if we've already found a
|
||||||
|
-- blocking area, as the check is somewhat expensive.
|
||||||
|
-- The area blocks if the area is closed or open areas aren't
|
||||||
|
-- acceptable to the caller, and the area isn't owned.
|
||||||
|
-- Note: We can't return directly here, because there might be
|
||||||
|
-- an exclosing owned area that we haven't gotten to yet.
|
||||||
|
if not blocking_area and
|
||||||
|
(not allow_open or not area.open) and
|
||||||
|
(not name or not self:isAreaOwner(id, name)) then
|
||||||
|
blocking_area = id
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
-- Then check for intersecting (non-owned) areas.
|
|
||||||
for id, area in pairs(self.areas) do
|
if blocking_area then
|
||||||
local p1, p2 = area.pos1, area.pos2
|
return false, blocking_area
|
||||||
if (p1.x <= pos2.x and p2.x >= pos1.x) and
|
|
||||||
(p1.y <= pos2.y and p2.y >= pos1.y) and
|
|
||||||
(p1.z <= pos2.z and p2.z >= pos1.z) then
|
|
||||||
-- Found an intersecting area.
|
|
||||||
-- Return if the area is closed or open areas aren't
|
|
||||||
-- allowed, and the area isn't owned.
|
|
||||||
if (not allow_open or not area.open) and
|
|
||||||
(not name or not areas:isAreaOwner(id, name)) then
|
|
||||||
return false, id
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- There are no intersecting areas or they are only partially
|
||||||
|
-- intersecting areas and they are all owned by the player.
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
61
internal.lua
61
internal.lua
@ -30,6 +30,40 @@ function areas:load()
|
|||||||
self.areas = {}
|
self.areas = {}
|
||||||
end
|
end
|
||||||
file:close()
|
file:close()
|
||||||
|
self:populateStore()
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Checks an AreaStore ID.
|
||||||
|
-- Deletes the AreaStore (falling back to the iterative method)
|
||||||
|
-- and prints an error message if the ID is invalid.
|
||||||
|
-- @return Whether the ID was valid.
|
||||||
|
function areas:checkAreaStoreId(sid)
|
||||||
|
if not sid then
|
||||||
|
minetest.log("error", "AreaStore failed to find an ID for an "
|
||||||
|
.."area! Falling back to iterative area checking.")
|
||||||
|
self.store = nil
|
||||||
|
self.store_ids = nil
|
||||||
|
end
|
||||||
|
return sid and true or false
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Populates the AreaStore after loading, if needed.
|
||||||
|
function areas:populateStore()
|
||||||
|
if not rawget(_G, "AreaStore") then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local store = AreaStore()
|
||||||
|
local store_ids = {}
|
||||||
|
for id, area in pairs(areas.areas) do
|
||||||
|
local sid = store:insert_area(area.pos1,
|
||||||
|
area.pos2, tostring(id))
|
||||||
|
if not self:checkAreaStoreId(sid) then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
store_ids[id] = sid
|
||||||
|
end
|
||||||
|
self.store = store
|
||||||
|
self.store_ids = store_ids
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Finds the first usable index in a table
|
-- Finds the first usable index in a table
|
||||||
@ -41,15 +75,28 @@ local function findFirstUnusedIndex(t)
|
|||||||
return i
|
return i
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Add a area, returning the new area's id.
|
--- Add a area.
|
||||||
|
-- @return The new area's ID.
|
||||||
function areas:add(owner, name, pos1, pos2, parent)
|
function areas:add(owner, name, pos1, pos2, parent)
|
||||||
local id = findFirstUnusedIndex(self.areas)
|
local id = findFirstUnusedIndex(self.areas)
|
||||||
self.areas[id] = {name=name, pos1=pos1, pos2=pos2, owner=owner,
|
self.areas[id] = {
|
||||||
parent=parent}
|
name = name,
|
||||||
|
pos1 = pos1,
|
||||||
|
pos2 = pos2,
|
||||||
|
owner = owner,
|
||||||
|
parent = parent
|
||||||
|
}
|
||||||
|
-- Add to AreaStore
|
||||||
|
if self.store then
|
||||||
|
local sid = self.store:insert_area(pos1, pos2, tostring(id))
|
||||||
|
if self:checkAreaStoreId(sid) then
|
||||||
|
self.store_ids[id] = sid
|
||||||
|
end
|
||||||
|
end
|
||||||
return id
|
return id
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Remove a area, and optionally it's children recursively.
|
--- Remove a area, and optionally it's 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)
|
||||||
@ -73,6 +120,12 @@ function areas:remove(id, recurse)
|
|||||||
|
|
||||||
-- Remove main entry
|
-- Remove main entry
|
||||||
self.areas[id] = nil
|
self.areas[id] = nil
|
||||||
|
|
||||||
|
-- Remove from AreaStore
|
||||||
|
if self.store then
|
||||||
|
self.store:remove_area(self.store_ids[id])
|
||||||
|
self.store_ids[id] = nil
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Checks if a area between two points is entirely contained by another area
|
-- Checks if a area between two points is entirely contained by another area
|
||||||
|
Loading…
Reference in New Issue
Block a user