Intersects_protection(): Move from Minetest Game to builtin (#6952)
authorParamat <paramat@users.noreply.github.com>
Tue, 23 Jan 2018 18:04:58 +0000 (18:04 +0000)
committerLoïc Blot <nerzhul@users.noreply.github.com>
Tue, 23 Jan 2018 18:04:58 +0000 (19:04 +0100)
A useful function that applies 'core.is_protected()' to a 3D lattice of
points evenly spaced throughout a defined volume, with a parameter for
the maximum spacing of points.

builtin/game/misc.lua
doc/lua_api.txt

index 39ef9b461ce08b3654d5c4595230e8844a940675..79ca40217754d36555285e36bd416c5f52a923c5 100644 (file)
@@ -40,14 +40,17 @@ function core.check_player_privs(name, ...)
        return true, ""
 end
 
+
 local player_list = {}
 
+
 function core.send_join_message(player_name)
        if not minetest.is_singleplayer() then
                core.chat_send_all("*** " .. player_name .. " joined the game.")
        end
 end
 
+
 function core.send_leave_message(player_name, timed_out)
        local announcement = "*** " ..  player_name .. " left the game."
        if timed_out then
@@ -56,18 +59,21 @@ function core.send_leave_message(player_name, timed_out)
        core.chat_send_all(announcement)
 end
 
+
 core.register_on_joinplayer(function(player)
        local player_name = player:get_player_name()
        player_list[player_name] = player
        core.send_join_message(player_name)
 end)
 
+
 core.register_on_leaveplayer(function(player, timed_out)
        local player_name = player:get_player_name()
        player_list[player_name] = nil
        core.send_leave_message(player_name, timed_out)
 end)
 
+
 function core.get_connected_players()
        local temp_table = {}
        for index, value in pairs(player_list) do
@@ -78,12 +84,15 @@ function core.get_connected_players()
        return temp_table
 end
 
+
 function minetest.player_exists(name)
        return minetest.get_auth_handler().get_auth(name) ~= nil
 end
 
+
 -- Returns two position vectors representing a box of `radius` in each
 -- direction centered around the player corresponding to `player_name`
+
 function core.get_player_radius_area(player_name, radius)
        local player = core.get_player_by_name(player_name)
        if player == nil then
@@ -101,10 +110,12 @@ function core.get_player_radius_area(player_name, radius)
        return p1, p2
 end
 
+
 function core.hash_node_position(pos)
        return (pos.z+32768)*65536*65536 + (pos.y+32768)*65536 + pos.x+32768
 end
 
+
 function core.get_position_from_hash(hash)
        local pos = {}
        pos.x = (hash%65536) - 32768
@@ -115,6 +126,7 @@ function core.get_position_from_hash(hash)
        return pos
 end
 
+
 function core.get_item_group(name, group)
        if not core.registered_items[name] or not
                        core.registered_items[name].groups[group] then
@@ -123,11 +135,13 @@ function core.get_item_group(name, group)
        return core.registered_items[name].groups[group]
 end
 
+
 function core.get_node_group(name, group)
        core.log("deprecated", "Deprecated usage of get_node_group, use get_item_group instead")
        return core.get_item_group(name, group)
 end
 
+
 function core.setting_get_pos(name)
        local value = core.settings:get(name)
        if not value then
@@ -136,17 +150,64 @@ function core.setting_get_pos(name)
        return core.string_to_pos(value)
 end
 
+
 -- To be overriden by protection mods
+
 function core.is_protected(pos, name)
        return false
 end
 
+
 function core.record_protection_violation(pos, name)
        for _, func in pairs(core.registered_on_protection_violation) do
                func(pos, name)
        end
 end
 
+
+-- Checks if specified volume intersects a protected volume
+
+function core.intersects_protection(minp, maxp, player_name, interval)
+       -- 'interval' is the largest allowed interval for the 3D lattice of checks.
+
+       -- Compute the optimal float step 'd' for each axis so that all corners and
+       -- borders are checked. 'd' will be smaller or equal to 'interval'.
+       -- Subtracting 1e-4 ensures that the max co-ordinate will be reached by the
+       -- for loop (which might otherwise not be the case due to rounding errors).
+
+       -- Default to 4
+       interval = interval or 4
+       local d = {}
+
+       for _, c in pairs({"x", "y", "z"}) do
+               if maxp[c] > minp[c] then
+                       d[c] = (maxp[c] - minp[c]) /
+                               math.ceil((maxp[c] - minp[c]) / interval) - 1e-4
+               elseif maxp[c] == minp[c] then
+                       d[c] = 1 -- Any value larger than 0 to avoid division by zero
+               else -- maxp[c] < minp[c], print error and treat as protection intersected
+                       minetest.log("error", "maxp < minp in 'minetest.intersects_protection()'")
+                       return true
+               end
+       end
+
+       for zf = minp.z, maxp.z, d.z do
+               local z = math.floor(zf + 0.5)
+               for yf = minp.y, maxp.y, d.y do
+                       local y = math.floor(yf + 0.5)
+                       for xf = minp.x, maxp.x, d.x do
+                               local x = math.floor(xf + 0.5)
+                               if core.is_protected({x = x, y = y, z = z}, player_name) then
+                                       return true
+                               end
+                       end
+               end
+       end
+
+       return false
+end
+
+
 local raillike_ids = {}
 local raillike_cur_id = 0
 function core.raillike_group(name)
@@ -159,7 +220,9 @@ function core.raillike_group(name)
        return id
 end
 
+
 -- HTTP callback interface
+
 function core.http_add_fetch(httpenv)
        httpenv.fetch = function(req, callback)
                local handle = httpenv.fetch_async(req)
@@ -178,11 +241,12 @@ function core.http_add_fetch(httpenv)
        return httpenv
 end
 
+
 function core.close_formspec(player_name, formname)
        return minetest.show_formspec(player_name, formname, "")
 end
 
+
 function core.cancel_shutdown_requests()
        core.request_shutdown("", false, -1)
 end
-
index d7ea7f79f1fd5c9135a20bc245905910843e8195..27620aa8fe75f96c028ed1b92faf8e09889ad3b7 100644 (file)
@@ -3413,6 +3413,16 @@ These functions return the leftover itemstack.
 * `minetest.record_protection_violation(pos, name)`
     * This function calls functions registered with
       `minetest.register_on_protection_violation`.
+* `minetest.intersects_protection(minp, maxp, player_name, interval)
+    * Returns a boolean, returns true if the volume defined by `minp` and `maxp`
+      intersects a protected area not owned by `player_name`.
+    * Applies `is_protected()` to a 3D lattice of points in the defined volume.
+      The points are spaced evenly throughout the volume and have a spacing
+      similar to, but no larger than, `interval`.
+    * All corners and edges of the defined volume are checked.
+    * `interval` defaults to 4.
+    * `interval` should be carefully chosen and maximised to avoid an excessive
+      number of points being checked.
 * `minetest.rotate_and_place(itemstack, placer, pointed_thing, infinitestacks, orient_flags)`
     * Attempt to predict the desired orientation of the facedir-capable node
       defined by `itemstack`, and place it accordingly (on-wall, on the floor, or