Skip to content

Commit 0ac0969

Browse files
committedJul 27, 2016
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.
1 parent 2df7ce2 commit 0ac0969

File tree

3 files changed

+172
-15
lines changed

3 files changed

+172
-15
lines changed
 

Diff for: ‎mods/default/functions.lua

+40
Original file line numberDiff line numberDiff line change
@@ -481,3 +481,43 @@ minetest.register_abm({
481481
end
482482
end
483483
})
484+
485+
486+
--
487+
-- Checks if specified volume intersects a protected volume
488+
--
489+
490+
function default.intersects_protection(minp, maxp, player_name, interval)
491+
-- 'interval' is the largest allowed interval for the 3D lattice of checks
492+
493+
-- Compute the optimal float step 'd' for each axis so that all corners and
494+
-- borders are checked. 'd' will be smaller or equal to 'interval'.
495+
-- Subtracting 1e-4 ensures that the max co-ordinate will be reached by the
496+
-- for loop (which might otherwise not be the case due to rounding errors).
497+
local d = {}
498+
for _, c in pairs({"x", "y", "z"}) do
499+
if maxp[c] > minp[c] then
500+
d[c] = (maxp[c] - minp[c]) / math.ceil((maxp[c] - minp[c]) / interval) - 1e-4
501+
elseif maxp[c] == minp[c] then
502+
d[c] = 1 -- Any value larger than 0 to avoid division by zero
503+
else -- maxp[c] < minp[c], print error and treat as protection intersected
504+
minetest.log("error", "maxp < minp in 'default.intersects_protection()'")
505+
return true
506+
end
507+
end
508+
509+
for zf = minp.z, maxp.z, d.z do
510+
local z = math.floor(zf + 0.5)
511+
for yf = minp.y, maxp.y, d.y do
512+
local y = math.floor(yf + 0.5)
513+
for xf = minp.x, maxp.x, d.x do
514+
local x = math.floor(xf + 0.5)
515+
if minetest.is_protected({x = x, y = y, z = z}, player_name) then
516+
return true
517+
end
518+
end
519+
end
520+
end
521+
522+
return false
523+
end

Diff for: ‎mods/default/nodes.lua

+86-15
Original file line numberDiff line numberDiff line change
@@ -500,16 +500,30 @@ minetest.register_node("default:sapling", {
500500
sunlight_propagates = true,
501501
walkable = false,
502502
on_timer = default.grow_sapling,
503-
on_construct = function(pos)
504-
minetest.get_node_timer(pos):start(math.random(2400,4800))
505-
end,
506503
selection_box = {
507504
type = "fixed",
508505
fixed = {-0.3, -0.5, -0.3, 0.3, 0.35, 0.3}
509506
},
510507
groups = {snappy = 2, dig_immediate = 3, flammable = 2,
511508
attached_node = 1, sapling = 1},
512509
sounds = default.node_sound_leaves_defaults(),
510+
511+
on_construct = function(pos)
512+
minetest.get_node_timer(pos):start(math.random(2400,4800))
513+
end,
514+
515+
on_place = function(itemstack, placer, pointed_thing)
516+
itemstack = default.sapling_on_place(itemstack, placer, pointed_thing,
517+
"default:sapling",
518+
-- minp, maxp to be checked, relative to sapling pos
519+
-- minp_relative.y = 1 because sapling pos has been checked
520+
{x = -2, y = 1, z = -2},
521+
{x = 2, y = 6, z = 2},
522+
-- maximum interval of interior volume check
523+
4)
524+
525+
return itemstack
526+
end,
513527
})
514528

515529
minetest.register_node("default:leaves", {
@@ -624,16 +638,30 @@ minetest.register_node("default:junglesapling", {
624638
sunlight_propagates = true,
625639
walkable = false,
626640
on_timer = default.grow_sapling,
627-
on_construct = function(pos)
628-
minetest.get_node_timer(pos):start(math.random(2400,4800))
629-
end,
630641
selection_box = {
631642
type = "fixed",
632643
fixed = {-0.3, -0.5, -0.3, 0.3, 0.35, 0.3}
633644
},
634645
groups = {snappy = 2, dig_immediate = 3, flammable = 2,
635646
attached_node = 1, sapling = 1},
636647
sounds = default.node_sound_leaves_defaults(),
648+
649+
on_construct = function(pos)
650+
minetest.get_node_timer(pos):start(math.random(2400,4800))
651+
end,
652+
653+
on_place = function(itemstack, placer, pointed_thing)
654+
itemstack = default.sapling_on_place(itemstack, placer, pointed_thing,
655+
"default:junglesapling",
656+
-- minp, maxp to be checked, relative to sapling pos
657+
-- minp_relative.y = 1 because sapling pos has been checked
658+
{x = -2, y = 1, z = -2},
659+
{x = 2, y = 15, z = 2},
660+
-- maximum interval of interior volume check
661+
4)
662+
663+
return itemstack
664+
end,
637665
})
638666

639667

@@ -691,16 +719,30 @@ minetest.register_node("default:pine_sapling", {
691719
sunlight_propagates = true,
692720
walkable = false,
693721
on_timer = default.grow_sapling,
694-
on_construct = function(pos)
695-
minetest.get_node_timer(pos):start(math.random(2400,4800))
696-
end,
697722
selection_box = {
698723
type = "fixed",
699724
fixed = {-0.3, -0.5, -0.3, 0.3, 0.35, 0.3}
700725
},
701726
groups = {snappy = 2, dig_immediate = 3, flammable = 2,
702727
attached_node = 1, sapling = 1},
703728
sounds = default.node_sound_leaves_defaults(),
729+
730+
on_construct = function(pos)
731+
minetest.get_node_timer(pos):start(math.random(2400,4800))
732+
end,
733+
734+
on_place = function(itemstack, placer, pointed_thing)
735+
itemstack = default.sapling_on_place(itemstack, placer, pointed_thing,
736+
"default:pine_sapling",
737+
-- minp, maxp to be checked, relative to sapling pos
738+
-- minp_relative.y = 1 because sapling pos has been checked
739+
{x = -2, y = 1, z = -2},
740+
{x = 2, y = 12, z = 2},
741+
-- maximum interval of interior volume check
742+
4)
743+
744+
return itemstack
745+
end,
704746
})
705747

706748

@@ -758,16 +800,30 @@ minetest.register_node("default:acacia_sapling", {
758800
sunlight_propagates = true,
759801
walkable = false,
760802
on_timer = default.grow_sapling,
761-
on_construct = function(pos)
762-
minetest.get_node_timer(pos):start(math.random(2400,4800))
763-
end,
764803
selection_box = {
765804
type = "fixed",
766805
fixed = {-0.3, -0.5, -0.3, 0.3, 0.35, 0.3}
767806
},
768807
groups = {snappy = 2, dig_immediate = 3, flammable = 2,
769808
attached_node = 1, sapling = 1},
770809
sounds = default.node_sound_leaves_defaults(),
810+
811+
on_construct = function(pos)
812+
minetest.get_node_timer(pos):start(math.random(2400,4800))
813+
end,
814+
815+
on_place = function(itemstack, placer, pointed_thing)
816+
itemstack = default.sapling_on_place(itemstack, placer, pointed_thing,
817+
"default:acacia_sapling",
818+
-- minp, maxp to be checked, relative to sapling pos
819+
-- minp_relative.y = 1 because sapling pos has been checked
820+
{x = -4, y = 1, z = -4},
821+
{x = 4, y = 6, z = 4},
822+
-- maximum interval of interior volume check
823+
4)
824+
825+
return itemstack
826+
end,
771827
})
772828

773829
minetest.register_node("default:aspen_tree", {
@@ -824,17 +880,32 @@ minetest.register_node("default:aspen_sapling", {
824880
sunlight_propagates = true,
825881
walkable = false,
826882
on_timer = default.grow_sapling,
827-
on_construct = function(pos)
828-
minetest.get_node_timer(pos):start(math.random(2400,4800))
829-
end,
830883
selection_box = {
831884
type = "fixed",
832885
fixed = {-0.3, -0.5, -0.3, 0.3, 0.35, 0.3}
833886
},
834887
groups = {snappy = 2, dig_immediate = 3, flammable = 2,
835888
attached_node = 1, sapling = 1},
836889
sounds = default.node_sound_leaves_defaults(),
890+
891+
on_construct = function(pos)
892+
minetest.get_node_timer(pos):start(math.random(2400,4800))
893+
end,
894+
895+
on_place = function(itemstack, placer, pointed_thing)
896+
itemstack = default.sapling_on_place(itemstack, placer, pointed_thing,
897+
"default:aspen_sapling",
898+
-- minp, maxp to be checked, relative to sapling pos
899+
-- minp_relative.y = 1 because sapling pos has been checked
900+
{x = -2, y = 1, z = -2},
901+
{x = 2, y = 12, z = 2},
902+
-- maximum interval of interior volume check
903+
4)
904+
905+
return itemstack
906+
end,
837907
})
908+
838909
--
839910
-- Ores
840911
--

Diff for: ‎mods/default/trees.lua

+46
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,7 @@ function default.grow_new_acacia_tree(pos)
418418
path, "random", nil, false)
419419
end
420420

421+
421422
-- New aspen tree
422423

423424
function default.grow_new_aspen_tree(pos)
@@ -426,3 +427,48 @@ function default.grow_new_aspen_tree(pos)
426427
minetest.place_schematic({x = pos.x - 2, y = pos.y - 1, z = pos.z - 2},
427428
path, "0", nil, false)
428429
end
430+
431+
432+
--
433+
-- Sapling 'on place' function to check protection of node and resulting tree volume
434+
--
435+
436+
function default.sapling_on_place(itemstack, placer, pointed_thing,
437+
sapling_name, minp_relative, maxp_relative, interval)
438+
-- Position of sapling
439+
local pos = pointed_thing.under
440+
local node = minetest.get_node(pos)
441+
local pdef = minetest.registered_nodes[node.name]
442+
if not pdef or not pdef.buildable_to then
443+
pos = pointed_thing.above
444+
node = minetest.get_node(pos)
445+
pdef = minetest.registered_nodes[node.name]
446+
if not pdef or not pdef.buildable_to then
447+
return itemstack
448+
end
449+
end
450+
451+
local player_name = placer:get_player_name()
452+
-- Check sapling position for protection
453+
if minetest.is_protected(pos, player_name) then
454+
minetest.record_protection_violation(pos, player_name)
455+
return itemstack
456+
end
457+
-- Check tree volume for protection
458+
if not default.intersects_protection(
459+
vector.add(pos, minp_relative),
460+
vector.add(pos, maxp_relative),
461+
player_name,
462+
interval) then
463+
minetest.set_node(pos, {name = sapling_name})
464+
if not minetest.setting_getbool("creative_mode") then
465+
itemstack:take_item()
466+
end
467+
else
468+
minetest.record_protection_violation(pos, player_name)
469+
-- Print extra information to explain
470+
minetest.chat_send_player(player_name, "Tree will intersect protection")
471+
end
472+
473+
return itemstack
474+
end

0 commit comments

Comments
 (0)
Please sign in to comment.