mirror of
https://github.com/minetest/minetest_game.git
synced 2024-12-23 14:42:27 +01:00
Default: Prevent placing sapling if grown tree intersects protection
Add a global 'intersects protection' function to functions.lua for checking if a specified volume intersects with a protected volume. A 3D lattice of points are checked with an adjustable interval. Add a global 'sapling on place' function to avoid duplicated code in nodes.lua.
This commit is contained in:
parent
2df7ce20dd
commit
0ac096991c
@ -481,3 +481,43 @@ minetest.register_abm({
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Checks if specified volume intersects a protected volume
|
||||||
|
--
|
||||||
|
|
||||||
|
function default.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).
|
||||||
|
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 'default.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 minetest.is_protected({x = x, y = y, z = z}, player_name) then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
@ -500,9 +500,6 @@ minetest.register_node("default:sapling", {
|
|||||||
sunlight_propagates = true,
|
sunlight_propagates = true,
|
||||||
walkable = false,
|
walkable = false,
|
||||||
on_timer = default.grow_sapling,
|
on_timer = default.grow_sapling,
|
||||||
on_construct = function(pos)
|
|
||||||
minetest.get_node_timer(pos):start(math.random(2400,4800))
|
|
||||||
end,
|
|
||||||
selection_box = {
|
selection_box = {
|
||||||
type = "fixed",
|
type = "fixed",
|
||||||
fixed = {-0.3, -0.5, -0.3, 0.3, 0.35, 0.3}
|
fixed = {-0.3, -0.5, -0.3, 0.3, 0.35, 0.3}
|
||||||
@ -510,6 +507,23 @@ minetest.register_node("default:sapling", {
|
|||||||
groups = {snappy = 2, dig_immediate = 3, flammable = 2,
|
groups = {snappy = 2, dig_immediate = 3, flammable = 2,
|
||||||
attached_node = 1, sapling = 1},
|
attached_node = 1, sapling = 1},
|
||||||
sounds = default.node_sound_leaves_defaults(),
|
sounds = default.node_sound_leaves_defaults(),
|
||||||
|
|
||||||
|
on_construct = function(pos)
|
||||||
|
minetest.get_node_timer(pos):start(math.random(2400,4800))
|
||||||
|
end,
|
||||||
|
|
||||||
|
on_place = function(itemstack, placer, pointed_thing)
|
||||||
|
itemstack = default.sapling_on_place(itemstack, placer, pointed_thing,
|
||||||
|
"default:sapling",
|
||||||
|
-- minp, maxp to be checked, relative to sapling pos
|
||||||
|
-- minp_relative.y = 1 because sapling pos has been checked
|
||||||
|
{x = -2, y = 1, z = -2},
|
||||||
|
{x = 2, y = 6, z = 2},
|
||||||
|
-- maximum interval of interior volume check
|
||||||
|
4)
|
||||||
|
|
||||||
|
return itemstack
|
||||||
|
end,
|
||||||
})
|
})
|
||||||
|
|
||||||
minetest.register_node("default:leaves", {
|
minetest.register_node("default:leaves", {
|
||||||
@ -624,9 +638,6 @@ minetest.register_node("default:junglesapling", {
|
|||||||
sunlight_propagates = true,
|
sunlight_propagates = true,
|
||||||
walkable = false,
|
walkable = false,
|
||||||
on_timer = default.grow_sapling,
|
on_timer = default.grow_sapling,
|
||||||
on_construct = function(pos)
|
|
||||||
minetest.get_node_timer(pos):start(math.random(2400,4800))
|
|
||||||
end,
|
|
||||||
selection_box = {
|
selection_box = {
|
||||||
type = "fixed",
|
type = "fixed",
|
||||||
fixed = {-0.3, -0.5, -0.3, 0.3, 0.35, 0.3}
|
fixed = {-0.3, -0.5, -0.3, 0.3, 0.35, 0.3}
|
||||||
@ -634,6 +645,23 @@ minetest.register_node("default:junglesapling", {
|
|||||||
groups = {snappy = 2, dig_immediate = 3, flammable = 2,
|
groups = {snappy = 2, dig_immediate = 3, flammable = 2,
|
||||||
attached_node = 1, sapling = 1},
|
attached_node = 1, sapling = 1},
|
||||||
sounds = default.node_sound_leaves_defaults(),
|
sounds = default.node_sound_leaves_defaults(),
|
||||||
|
|
||||||
|
on_construct = function(pos)
|
||||||
|
minetest.get_node_timer(pos):start(math.random(2400,4800))
|
||||||
|
end,
|
||||||
|
|
||||||
|
on_place = function(itemstack, placer, pointed_thing)
|
||||||
|
itemstack = default.sapling_on_place(itemstack, placer, pointed_thing,
|
||||||
|
"default:junglesapling",
|
||||||
|
-- minp, maxp to be checked, relative to sapling pos
|
||||||
|
-- minp_relative.y = 1 because sapling pos has been checked
|
||||||
|
{x = -2, y = 1, z = -2},
|
||||||
|
{x = 2, y = 15, z = 2},
|
||||||
|
-- maximum interval of interior volume check
|
||||||
|
4)
|
||||||
|
|
||||||
|
return itemstack
|
||||||
|
end,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
@ -691,9 +719,6 @@ minetest.register_node("default:pine_sapling", {
|
|||||||
sunlight_propagates = true,
|
sunlight_propagates = true,
|
||||||
walkable = false,
|
walkable = false,
|
||||||
on_timer = default.grow_sapling,
|
on_timer = default.grow_sapling,
|
||||||
on_construct = function(pos)
|
|
||||||
minetest.get_node_timer(pos):start(math.random(2400,4800))
|
|
||||||
end,
|
|
||||||
selection_box = {
|
selection_box = {
|
||||||
type = "fixed",
|
type = "fixed",
|
||||||
fixed = {-0.3, -0.5, -0.3, 0.3, 0.35, 0.3}
|
fixed = {-0.3, -0.5, -0.3, 0.3, 0.35, 0.3}
|
||||||
@ -701,6 +726,23 @@ minetest.register_node("default:pine_sapling", {
|
|||||||
groups = {snappy = 2, dig_immediate = 3, flammable = 2,
|
groups = {snappy = 2, dig_immediate = 3, flammable = 2,
|
||||||
attached_node = 1, sapling = 1},
|
attached_node = 1, sapling = 1},
|
||||||
sounds = default.node_sound_leaves_defaults(),
|
sounds = default.node_sound_leaves_defaults(),
|
||||||
|
|
||||||
|
on_construct = function(pos)
|
||||||
|
minetest.get_node_timer(pos):start(math.random(2400,4800))
|
||||||
|
end,
|
||||||
|
|
||||||
|
on_place = function(itemstack, placer, pointed_thing)
|
||||||
|
itemstack = default.sapling_on_place(itemstack, placer, pointed_thing,
|
||||||
|
"default:pine_sapling",
|
||||||
|
-- minp, maxp to be checked, relative to sapling pos
|
||||||
|
-- minp_relative.y = 1 because sapling pos has been checked
|
||||||
|
{x = -2, y = 1, z = -2},
|
||||||
|
{x = 2, y = 12, z = 2},
|
||||||
|
-- maximum interval of interior volume check
|
||||||
|
4)
|
||||||
|
|
||||||
|
return itemstack
|
||||||
|
end,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
@ -758,9 +800,6 @@ minetest.register_node("default:acacia_sapling", {
|
|||||||
sunlight_propagates = true,
|
sunlight_propagates = true,
|
||||||
walkable = false,
|
walkable = false,
|
||||||
on_timer = default.grow_sapling,
|
on_timer = default.grow_sapling,
|
||||||
on_construct = function(pos)
|
|
||||||
minetest.get_node_timer(pos):start(math.random(2400,4800))
|
|
||||||
end,
|
|
||||||
selection_box = {
|
selection_box = {
|
||||||
type = "fixed",
|
type = "fixed",
|
||||||
fixed = {-0.3, -0.5, -0.3, 0.3, 0.35, 0.3}
|
fixed = {-0.3, -0.5, -0.3, 0.3, 0.35, 0.3}
|
||||||
@ -768,6 +807,23 @@ minetest.register_node("default:acacia_sapling", {
|
|||||||
groups = {snappy = 2, dig_immediate = 3, flammable = 2,
|
groups = {snappy = 2, dig_immediate = 3, flammable = 2,
|
||||||
attached_node = 1, sapling = 1},
|
attached_node = 1, sapling = 1},
|
||||||
sounds = default.node_sound_leaves_defaults(),
|
sounds = default.node_sound_leaves_defaults(),
|
||||||
|
|
||||||
|
on_construct = function(pos)
|
||||||
|
minetest.get_node_timer(pos):start(math.random(2400,4800))
|
||||||
|
end,
|
||||||
|
|
||||||
|
on_place = function(itemstack, placer, pointed_thing)
|
||||||
|
itemstack = default.sapling_on_place(itemstack, placer, pointed_thing,
|
||||||
|
"default:acacia_sapling",
|
||||||
|
-- minp, maxp to be checked, relative to sapling pos
|
||||||
|
-- minp_relative.y = 1 because sapling pos has been checked
|
||||||
|
{x = -4, y = 1, z = -4},
|
||||||
|
{x = 4, y = 6, z = 4},
|
||||||
|
-- maximum interval of interior volume check
|
||||||
|
4)
|
||||||
|
|
||||||
|
return itemstack
|
||||||
|
end,
|
||||||
})
|
})
|
||||||
|
|
||||||
minetest.register_node("default:aspen_tree", {
|
minetest.register_node("default:aspen_tree", {
|
||||||
@ -824,9 +880,6 @@ minetest.register_node("default:aspen_sapling", {
|
|||||||
sunlight_propagates = true,
|
sunlight_propagates = true,
|
||||||
walkable = false,
|
walkable = false,
|
||||||
on_timer = default.grow_sapling,
|
on_timer = default.grow_sapling,
|
||||||
on_construct = function(pos)
|
|
||||||
minetest.get_node_timer(pos):start(math.random(2400,4800))
|
|
||||||
end,
|
|
||||||
selection_box = {
|
selection_box = {
|
||||||
type = "fixed",
|
type = "fixed",
|
||||||
fixed = {-0.3, -0.5, -0.3, 0.3, 0.35, 0.3}
|
fixed = {-0.3, -0.5, -0.3, 0.3, 0.35, 0.3}
|
||||||
@ -834,7 +887,25 @@ minetest.register_node("default:aspen_sapling", {
|
|||||||
groups = {snappy = 2, dig_immediate = 3, flammable = 2,
|
groups = {snappy = 2, dig_immediate = 3, flammable = 2,
|
||||||
attached_node = 1, sapling = 1},
|
attached_node = 1, sapling = 1},
|
||||||
sounds = default.node_sound_leaves_defaults(),
|
sounds = default.node_sound_leaves_defaults(),
|
||||||
|
|
||||||
|
on_construct = function(pos)
|
||||||
|
minetest.get_node_timer(pos):start(math.random(2400,4800))
|
||||||
|
end,
|
||||||
|
|
||||||
|
on_place = function(itemstack, placer, pointed_thing)
|
||||||
|
itemstack = default.sapling_on_place(itemstack, placer, pointed_thing,
|
||||||
|
"default:aspen_sapling",
|
||||||
|
-- minp, maxp to be checked, relative to sapling pos
|
||||||
|
-- minp_relative.y = 1 because sapling pos has been checked
|
||||||
|
{x = -2, y = 1, z = -2},
|
||||||
|
{x = 2, y = 12, z = 2},
|
||||||
|
-- maximum interval of interior volume check
|
||||||
|
4)
|
||||||
|
|
||||||
|
return itemstack
|
||||||
|
end,
|
||||||
})
|
})
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Ores
|
-- Ores
|
||||||
--
|
--
|
||||||
|
@ -418,6 +418,7 @@ function default.grow_new_acacia_tree(pos)
|
|||||||
path, "random", nil, false)
|
path, "random", nil, false)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
-- New aspen tree
|
-- New aspen tree
|
||||||
|
|
||||||
function default.grow_new_aspen_tree(pos)
|
function default.grow_new_aspen_tree(pos)
|
||||||
@ -426,3 +427,48 @@ function default.grow_new_aspen_tree(pos)
|
|||||||
minetest.place_schematic({x = pos.x - 2, y = pos.y - 1, z = pos.z - 2},
|
minetest.place_schematic({x = pos.x - 2, y = pos.y - 1, z = pos.z - 2},
|
||||||
path, "0", nil, false)
|
path, "0", nil, false)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Sapling 'on place' function to check protection of node and resulting tree volume
|
||||||
|
--
|
||||||
|
|
||||||
|
function default.sapling_on_place(itemstack, placer, pointed_thing,
|
||||||
|
sapling_name, minp_relative, maxp_relative, interval)
|
||||||
|
-- Position of sapling
|
||||||
|
local pos = pointed_thing.under
|
||||||
|
local node = minetest.get_node(pos)
|
||||||
|
local pdef = minetest.registered_nodes[node.name]
|
||||||
|
if not pdef or not pdef.buildable_to then
|
||||||
|
pos = pointed_thing.above
|
||||||
|
node = minetest.get_node(pos)
|
||||||
|
pdef = minetest.registered_nodes[node.name]
|
||||||
|
if not pdef or not pdef.buildable_to then
|
||||||
|
return itemstack
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local player_name = placer:get_player_name()
|
||||||
|
-- Check sapling position for protection
|
||||||
|
if minetest.is_protected(pos, player_name) then
|
||||||
|
minetest.record_protection_violation(pos, player_name)
|
||||||
|
return itemstack
|
||||||
|
end
|
||||||
|
-- Check tree volume for protection
|
||||||
|
if not default.intersects_protection(
|
||||||
|
vector.add(pos, minp_relative),
|
||||||
|
vector.add(pos, maxp_relative),
|
||||||
|
player_name,
|
||||||
|
interval) then
|
||||||
|
minetest.set_node(pos, {name = sapling_name})
|
||||||
|
if not minetest.setting_getbool("creative_mode") then
|
||||||
|
itemstack:take_item()
|
||||||
|
end
|
||||||
|
else
|
||||||
|
minetest.record_protection_violation(pos, player_name)
|
||||||
|
-- Print extra information to explain
|
||||||
|
minetest.chat_send_player(player_name, "Tree will intersect protection")
|
||||||
|
end
|
||||||
|
|
||||||
|
return itemstack
|
||||||
|
end
|
||||||
|
Loading…
Reference in New Issue
Block a user