From 01bc817fe0a59e2e2b20c26d395c5b989c5156c9 Mon Sep 17 00:00:00 2001 From: Paramat Date: Tue, 23 Jan 2018 18:04:58 +0000 Subject: [PATCH] Intersects_protection(): Move from Minetest Game to builtin (#6952) 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 | 66 ++++++++++++++++++++++++++++++++++++++++++- doc/lua_api.txt | 10 +++++++ 2 files changed, 75 insertions(+), 1 deletion(-) diff --git a/builtin/game/misc.lua b/builtin/game/misc.lua index 39ef9b461..79ca40217 100644 --- a/builtin/game/misc.lua +++ b/builtin/game/misc.lua @@ -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 - diff --git a/doc/lua_api.txt b/doc/lua_api.txt index d7ea7f79f..27620aa8f 100644 --- a/doc/lua_api.txt +++ b/doc/lua_api.txt @@ -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