This commit is contained in:
Lars Müller 2025-06-29 21:04:49 +02:00 committed by GitHub
commit c9d755b405
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 157 additions and 198 deletions

View file

@ -835,3 +835,17 @@ function default.can_interact_with_node(player, pos)
return false return false
end end
function default.do_with_area(p1, p2, func)
local vm = VoxelManip()
local minp, maxp = vm:read_from_map(p1, p2)
local va = VoxelArea:new({MinEdge = minp, MaxEdge = maxp})
local data = vm:get_data()
func(va, data)
vm:set_data(data)
vm:write_to_map()
vm:update_liquids()
if vm.close ~= nil then
vm:close()
end
end

View file

@ -115,26 +115,13 @@ function default.grow_tree(pos, is_apple_tree, bad)
error("Deprecated use of default.grow_tree") error("Deprecated use of default.grow_tree")
end end
local x, y, z = pos.x, pos.y, pos.z
local height = random(4, 5) local height = random(4, 5)
local c_tree = minetest.get_content_id("default:tree") local c_tree = minetest.get_content_id("default:tree")
local c_leaves = minetest.get_content_id("default:leaves") local c_leaves = minetest.get_content_id("default:leaves")
local vm = minetest.get_voxel_manip() default.do_with_area(pos:offset(-2, 0, -2), pos:offset(2, height + 1, 2), function(a, data)
local minp, maxp = vm:read_from_map( add_trunk_and_leaves(data, a, pos, c_tree, c_leaves, height, 2, 8, is_apple_tree)
{x = x - 2, y = y, z = z - 2}, end)
{x = x + 2, y = y + height + 1, z = z + 2}
)
local a = VoxelArea:new({MinEdge = minp, MaxEdge = maxp})
local data = vm:get_data()
add_trunk_and_leaves(data, a, pos, c_tree, c_leaves, height, 2, 8, is_apple_tree)
vm:set_data(data)
vm:write_to_map()
if vm.close ~= nil then
vm:close()
end
end end
-- Jungle tree -- Jungle tree
@ -156,39 +143,27 @@ function default.grow_jungle_tree(pos, bad)
local c_jungletree = minetest.get_content_id("default:jungletree") local c_jungletree = minetest.get_content_id("default:jungletree")
local c_jungleleaves = minetest.get_content_id("default:jungleleaves") local c_jungleleaves = minetest.get_content_id("default:jungleleaves")
local vm = minetest.get_voxel_manip() default.do_with_area(pos:offset(-3, -1, -3), pos:offset(3, height + 1, 3), function(a, data)
local minp, maxp = vm:read_from_map( add_trunk_and_leaves(data, a, pos, c_jungletree, c_jungleleaves,
{x = x - 3, y = y - 1, z = z - 3}, height, 3, 30, false)
{x = x + 3, y = y + height + 1, z = z + 3}
)
local a = VoxelArea:new({MinEdge = minp, MaxEdge = maxp})
local data = vm:get_data()
add_trunk_and_leaves(data, a, pos, c_jungletree, c_jungleleaves, -- Roots
height, 3, 30, false) for z_dist = -1, 1 do
local vi_1 = a:index(x - 1, y - 1, z + z_dist)
-- Roots local vi_2 = a:index(x - 1, y, z + z_dist)
for z_dist = -1, 1 do for x_dist = -1, 1 do
local vi_1 = a:index(x - 1, y - 1, z + z_dist) if random(1, 3) >= 2 then
local vi_2 = a:index(x - 1, y, z + z_dist) if data[vi_1] == c_air or data[vi_1] == c_ignore then
for x_dist = -1, 1 do data[vi_1] = c_jungletree
if random(1, 3) >= 2 then elseif data[vi_2] == c_air or data[vi_2] == c_ignore then
if data[vi_1] == c_air or data[vi_1] == c_ignore then data[vi_2] = c_jungletree
data[vi_1] = c_jungletree end
elseif data[vi_2] == c_air or data[vi_2] == c_ignore then
data[vi_2] = c_jungletree
end end
vi_1 = vi_1 + 1
vi_2 = vi_2 + 1
end end
vi_1 = vi_1 + 1
vi_2 = vi_2 + 1
end end
end end)
vm:set_data(data)
vm:write_to_map()
if vm.close ~= nil then
vm:close()
end
end end
@ -218,105 +193,93 @@ function default.grow_pine_tree(pos, snow)
local c_pine_needles = minetest.get_content_id("default:pine_needles") local c_pine_needles = minetest.get_content_id("default:pine_needles")
local c_snow = minetest.get_content_id("default:snow") local c_snow = minetest.get_content_id("default:snow")
local vm = minetest.get_voxel_manip() default.do_with_area(pos:offset(-3, 0, -3), vector.new(x + 3, maxy + 3, z + 3), function(a, data)
local minp, maxp = vm:read_from_map( -- Upper branches layer
{x = x - 3, y = y, z = z - 3}, local dev = 3
{x = x + 3, y = maxy + 3, z = z + 3} for yy = maxy - 1, maxy + 1 do
) for zz = z - dev, z + dev do
local a = VoxelArea:new({MinEdge = minp, MaxEdge = maxp}) local vi = a:index(x - dev, yy, zz)
local data = vm:get_data() local via = a:index(x - dev, yy + 1, zz)
for xx = x - dev, x + dev do
if random() < 0.95 - dev * 0.05 then
add_pine_needles(data, vi, c_air, c_ignore, c_snow,
c_pine_needles)
if snow then
add_snow(data, via, c_air, c_ignore, c_snow)
end
end
vi = vi + 1
via = via + 1
end
end
dev = dev - 1
end
-- Upper branches layer -- Centre top nodes
local dev = 3 add_pine_needles(data, a:index(x, maxy + 1, z), c_air, c_ignore, c_snow,
for yy = maxy - 1, maxy + 1 do c_pine_needles)
for zz = z - dev, z + dev do add_pine_needles(data, a:index(x, maxy + 2, z), c_air, c_ignore, c_snow,
local vi = a:index(x - dev, yy, zz) c_pine_needles) -- Paramat added a pointy top node
local via = a:index(x - dev, yy + 1, zz) if snow then
for xx = x - dev, x + dev do add_snow(data, a:index(x, maxy + 3, z), c_air, c_ignore, c_snow)
if random() < 0.95 - dev * 0.05 then end
-- Lower branches layer
local my = 0
for i = 1, 20 do -- Random 2x2 squares of needles
local xi = x + random(-3, 2)
local yy = maxy + random(-6, -5)
local zi = z + random(-3, 2)
if yy > my then
my = yy
end
for zz = zi, zi+1 do
local vi = a:index(xi, yy, zz)
local via = a:index(xi, yy + 1, zz)
for xx = xi, xi + 1 do
add_pine_needles(data, vi, c_air, c_ignore, c_snow, add_pine_needles(data, vi, c_air, c_ignore, c_snow,
c_pine_needles) c_pine_needles)
if snow then if snow then
add_snow(data, via, c_air, c_ignore, c_snow) add_snow(data, via, c_air, c_ignore, c_snow)
end end
vi = vi + 1
via = via + 1
end end
vi = vi + 1
via = via + 1
end end
end end
dev = dev - 1
end
-- Centre top nodes dev = 2
add_pine_needles(data, a:index(x, maxy + 1, z), c_air, c_ignore, c_snow, for yy = my + 1, my + 2 do
c_pine_needles) for zz = z - dev, z + dev do
add_pine_needles(data, a:index(x, maxy + 2, z), c_air, c_ignore, c_snow, local vi = a:index(x - dev, yy, zz)
c_pine_needles) -- Paramat added a pointy top node local via = a:index(x - dev, yy + 1, zz)
if snow then for xx = x - dev, x + dev do
add_snow(data, a:index(x, maxy + 3, z), c_air, c_ignore, c_snow) if random() < 0.95 - dev * 0.05 then
end add_pine_needles(data, vi, c_air, c_ignore, c_snow,
c_pine_needles)
-- Lower branches layer if snow then
local my = 0 add_snow(data, via, c_air, c_ignore, c_snow)
for i = 1, 20 do -- Random 2x2 squares of needles end
local xi = x + random(-3, 2)
local yy = maxy + random(-6, -5)
local zi = z + random(-3, 2)
if yy > my then
my = yy
end
for zz = zi, zi+1 do
local vi = a:index(xi, yy, zz)
local via = a:index(xi, yy + 1, zz)
for xx = xi, xi + 1 do
add_pine_needles(data, vi, c_air, c_ignore, c_snow,
c_pine_needles)
if snow then
add_snow(data, via, c_air, c_ignore, c_snow)
end
vi = vi + 1
via = via + 1
end
end
end
dev = 2
for yy = my + 1, my + 2 do
for zz = z - dev, z + dev do
local vi = a:index(x - dev, yy, zz)
local via = a:index(x - dev, yy + 1, zz)
for xx = x - dev, x + dev do
if random() < 0.95 - dev * 0.05 then
add_pine_needles(data, vi, c_air, c_ignore, c_snow,
c_pine_needles)
if snow then
add_snow(data, via, c_air, c_ignore, c_snow)
end end
vi = vi + 1
via = via + 1
end end
vi = vi + 1 end
via = via + 1 dev = dev - 1
end
-- Trunk
-- Force-place lowest trunk node to replace sapling
data[a:index(x, y, z)] = c_pine_tree
for yy = y + 1, maxy do
local vi = a:index(x, yy, z)
local node_id = data[vi]
if node_id == c_air or node_id == c_ignore or
node_id == c_pine_needles or node_id == c_snow then
data[vi] = c_pine_tree
end end
end end
dev = dev - 1 end)
end
-- Trunk
-- Force-place lowest trunk node to replace sapling
data[a:index(x, y, z)] = c_pine_tree
for yy = y + 1, maxy do
local vi = a:index(x, yy, z)
local node_id = data[vi]
if node_id == c_air or node_id == c_ignore or
node_id == c_pine_needles or node_id == c_snow then
data[vi] = c_pine_tree
end
end
vm:set_data(data)
vm:write_to_map()
if vm.close ~= nil then
vm:close()
end
end end

View file

@ -294,12 +294,8 @@ end
local function tnt_explode(pos, radius, ignore_protection, ignore_on_blast, owner, explode_center) local function tnt_explode(pos, radius, ignore_protection, ignore_on_blast, owner, explode_center)
pos = vector.round(pos) pos = vector.round(pos)
-- scan for adjacent TNT nodes first, and enlarge the explosion -- scan for adjacent TNT nodes first, and enlarge the explosion
local vm1 = VoxelManip() -- TODO given that we're looking at a fraction of a mapblock here,
local p1 = vector.subtract(pos, 2) -- there is probably little reason to use VoxelManip.
local p2 = vector.add(pos, 2)
local minp, maxp = vm1:read_from_map(p1, p2)
local a = VoxelArea:new({MinEdge = minp, MaxEdge = maxp})
local data = vm1:get_data()
local count = 0 local count = 0
local c_tnt local c_tnt
local c_tnt_burning = minetest.get_content_id("tnt:tnt_burning") local c_tnt_burning = minetest.get_content_id("tnt:tnt_burning")
@ -311,88 +307,74 @@ local function tnt_explode(pos, radius, ignore_protection, ignore_on_blast, owne
else else
c_tnt = c_tnt_burning -- tnt is not registered if disabled c_tnt = c_tnt_burning -- tnt is not registered if disabled
end end
-- make sure we still have explosion even when centre node isnt tnt related
if explode_center then
count = 1
end
for z = pos.z - 2, pos.z + 2 do default.do_with_area(pos:subtract(2), pos:add(2), function(a, data)
for y = pos.y - 2, pos.y + 2 do -- make sure we still have explosion even when centre node isnt tnt related
local vi = a:index(pos.x - 2, y, z) if explode_center then
for x = pos.x - 2, pos.x + 2 do count = 1
local cid = data[vi]
if cid == c_tnt or cid == c_tnt_boom or cid == c_tnt_burning then
count = count + 1
data[vi] = c_air
end
vi = vi + 1
end end
end
end
vm1:set_data(data) for z = pos.z - 2, pos.z + 2 do
vm1:write_to_map() for y = pos.y - 2, pos.y + 2 do
if vm1.close ~= nil then local vi = a:index(pos.x - 2, y, z)
vm1:close() for x = pos.x - 2, pos.x + 2 do
end local cid = data[vi]
if cid == c_tnt or cid == c_tnt_boom or cid == c_tnt_burning then
count = count + 1
data[vi] = c_air
end
vi = vi + 1
end
end
end
end)
-- recalculate new radius -- recalculate new radius
radius = math.floor(radius * math.pow(count, 1/3)) radius = math.floor(radius * math.pow(count, 1/3))
-- perform the explosion -- perform the explosion
local vm = VoxelManip()
local pr = PseudoRandom(os.time()) local pr = PseudoRandom(os.time())
p1 = vector.subtract(pos, radius)
p2 = vector.add(pos, radius)
minp, maxp = vm:read_from_map(p1, p2)
a = VoxelArea:new({MinEdge = minp, MaxEdge = maxp})
data = vm:get_data()
local drops = {} local drops = {}
local on_blast_queue = {} local on_blast_queue = {}
local on_construct_queue = {} local on_construct_queue = {}
basic_flame_on_construct = minetest.registered_nodes["fire:basic_flame"].on_construct basic_flame_on_construct = minetest.registered_nodes["fire:basic_flame"].on_construct
-- Used to efficiently remove metadata of nodes that were destroyed. local p1, p2 = pos:subtract(radius), pos:add(radius)
-- Metadata is probably sparse, so this may save us some work. default.do_with_area(p1, p2, function(a, data) -- luacheck: ignore
local has_meta = {} -- Used to efficiently remove metadata of nodes that were destroyed.
for _, p in ipairs(minetest.find_nodes_with_meta(p1, p2)) do -- Metadata is probably sparse, so this may save us some work.
has_meta[a:indexp(p)] = true local has_meta = {}
end for _, p in ipairs(minetest.find_nodes_with_meta(p1, p2)) do
has_meta[a:indexp(p)] = true
end
local c_fire = minetest.get_content_id("fire:basic_flame") local c_fire = minetest.get_content_id("fire:basic_flame")
for z = -radius, radius do for z = -radius, radius do
for y = -radius, radius do for y = -radius, radius do
local vi = a:index(pos.x + (-radius), pos.y + y, pos.z + z) local vi = a:index(pos.x + (-radius), pos.y + y, pos.z + z)
for x = -radius, radius do for x = -radius, radius do
local r = vector.length(vector.new(x, y, z)) local r = vector.length(vector.new(x, y, z))
if (radius * radius) / (r * r) >= (pr:next(80, 125) / 100) then if (radius * radius) / (r * r) >= (pr:next(80, 125) / 100) then
local cid = data[vi] local cid = data[vi]
local p = {x = pos.x + x, y = pos.y + y, z = pos.z + z} local p = {x = pos.x + x, y = pos.y + y, z = pos.z + z}
if cid ~= c_air and cid ~= c_ignore then if cid ~= c_air and cid ~= c_ignore then
local new_cid = destroy(drops, p, cid, c_air, c_fire, local new_cid = destroy(drops, p, cid, c_air, c_fire,
on_blast_queue, on_construct_queue, on_blast_queue, on_construct_queue,
ignore_protection, ignore_on_blast, owner) ignore_protection, ignore_on_blast, owner)
if new_cid ~= data[vi] then if new_cid ~= data[vi] then
data[vi] = new_cid data[vi] = new_cid
if has_meta[vi] then if has_meta[vi] then
minetest.get_meta(p):from_table(nil) minetest.get_meta(p):from_table(nil)
end
end end
end end
end end
vi = vi + 1
end end
vi = vi + 1 end
end end
end end)
end
vm:set_data(data)
vm:write_to_map()
vm:update_liquids()
if vm.close ~= nil then
vm:close()
end
-- call check_single_for_falling for everything within 1.5x blast radius -- call check_single_for_falling for everything within 1.5x blast radius
for y = -radius * 1.5, radius * 1.5 do for y = -radius * 1.5, radius * 1.5 do