Merge pull request 'Reduce tree growth speed, integrate cherry blossom trees better, simpler catch-up LBM' (#4817) from tree-growth-speed into master

Reviewed-on: https://git.minetest.land/VoxeLibre/VoxeLibre/pulls/4817
Reviewed-by: Mikita Wiśniewski <rudzik8@protonmail.com>
This commit is contained in:
the-real-herowl 2025-01-12 17:13:37 +01:00
commit fdc2545511
2 changed files with 154 additions and 187 deletions

View file

@ -1,12 +1,8 @@
-- Tree Growth -- Tree Growth
-- TODO: Use better spawning behavior and wood api when wood api is finished. -- TODO: Use better spawning behavior and wood api when wood api is finished.
function mcl_cherry_blossom.generate_cherry_tree(pos) function mcl_cherry_blossom.generate_cherry_tree(pos)
local pr = PseudoRandom(pos.x+pos.y+pos.z) local r = math.random(1,3)
local r = pr:next(1,3) local path = minetest.get_modpath("mcl_cherry_blossom").."/schematics/mcl_cherry_blossom_tree_"..r..".mts"
local modpath = minetest.get_modpath("mcl_cherry_blossom")
local path = modpath.."/schematics/mcl_cherry_blossom_tree_"..tostring(r)..".mts"
if mcl_core.check_growth_width(pos,7,8) then
minetest.set_node(pos, {name = "air"})
if r == 1 then if r == 1 then
minetest.place_schematic(vector.offset(pos, -2, 0, -2), path, "random", nil, false) minetest.place_schematic(vector.offset(pos, -2, 0, -2), path, "random", nil, false)
elseif r == 2 then elseif r == 2 then
@ -14,17 +10,16 @@ function mcl_cherry_blossom.generate_cherry_tree(pos)
elseif r == 3 then elseif r == 3 then
minetest.place_schematic(vector.offset(pos, -3, 0, -3), path, nil, nil, false) minetest.place_schematic(vector.offset(pos, -3, 0, -3), path, nil, nil, false)
end end
end
end end
minetest.register_abm({ minetest.register_abm({
label = "Cherry Tree Growth", label = "Cherry Tree Growth",
nodenames = "mcl_cherry_blossom:cherrysapling", nodenames = "mcl_cherry_blossom:cherrysapling",
interval = 30, interval = 30,
chance = 5, chance = 3,
action = function(pos,node) action = function(pos, node)
mcl_cherry_blossom.generate_cherry_tree(pos) mcl_core.grow_cherry(pos, node, 1)
end, end
}) })
local cherry_particle = { local cherry_particle = {

View file

@ -22,6 +22,7 @@ local SPRUCE_TREE_ID = 3
local ACACIA_TREE_ID = 4 local ACACIA_TREE_ID = 4
local JUNGLE_TREE_ID = 5 local JUNGLE_TREE_ID = 5
local BIRCH_TREE_ID = 6 local BIRCH_TREE_ID = 6
local CHERRY_TREE_ID = 7
minetest.register_abm({ minetest.register_abm({
label = "Lava cooling", label = "Lava cooling",
@ -305,6 +306,8 @@ local function check_tree_growth(pos, tree_id, options)
return check_growth_width(pos, 7, 8) return check_growth_width(pos, 7, 8)
elseif tree_id == DARK_OAK_TREE_ID and two_by_two then elseif tree_id == DARK_OAK_TREE_ID and two_by_two then
return check_growth_width(pos, 4, 7) return check_growth_width(pos, 4, 7)
elseif tree_id == CHERRY_TREE_ID then
return check_growth_width(pos, 7, 8)
end end
return false return false
@ -356,6 +359,8 @@ function mcl_core.generate_tree(pos, tree_type, options)
end end
elseif tree_type == BIRCH_TREE_ID then elseif tree_type == BIRCH_TREE_ID then
mcl_core.generate_birch_tree(pos) mcl_core.generate_birch_tree(pos)
elseif tree_type == CHERRY_TREE_ID and mcl_cherry_blossom then
mcl_cherry_blossom.generate_cherry_tree(pos)
end end
mcl_core.update_sapling_foliage_colors(pos) mcl_core.update_sapling_foliage_colors(pos)
end end
@ -822,35 +827,14 @@ minetest.register_lbm({
-------------------------- --------------------------
-- Try generate tree --- -- Try generate tree ---
-------------------------- --------------------------
local treelight = 9 local TREE_MINIMUM_LIGHT = 9
local function sapling_grow_action(tree_id, soil_needed, one_by_one, two_by_two, sapling) local function sapling_grow_action(tree_id, soil_needed, one_by_one, two_by_two, sapling)
return function(pos) return function(pos, node, grow_by)
local meta = minetest.get_meta(pos) local meta = minetest.get_meta(pos)
if meta:get("grown") then return end
-- Checks if the sapling at pos has enough light and the correct soil -- Checks if the sapling at pos has enough light and the correct soil
local light = minetest.get_node_light(pos) local light = minetest.get_node_light(pos)
if not light then return end if not light or light < TREE_MINIMUM_LIGHT then return end
local low_light = light < treelight
local delta = 1
local current_game_time = minetest.get_day_count() + minetest.get_timeofday()
local last_game_time = tonumber(meta:get_string("last_gametime"))
meta:set_string("last_gametime", tostring(current_game_time))
if last_game_time then
delta = current_game_time - last_game_time
elseif low_light then
return
end
if low_light then
if delta < 1.2 then return end
if minetest.get_node_light(pos, 0.5) < treelight then return end
end
-- TODO: delta is [days] missed in inactive area. Currently we just add it to stage, which is far from a perfect calculation...
local soilnode = minetest.get_node(vector_offset(pos, 0, -1, 0)) local soilnode = minetest.get_node(vector_offset(pos, 0, -1, 0))
local soiltype = minetest.get_item_group(soilnode.name, "soil_sapling") local soiltype = minetest.get_item_group(soilnode.name, "soil_sapling")
@ -858,17 +842,14 @@ local function sapling_grow_action(tree_id, soil_needed, one_by_one, two_by_two,
-- Increase and check growth stage -- Increase and check growth stage
local meta = minetest.get_meta(pos) local meta = minetest.get_meta(pos)
local stage = meta:get_int("stage") local stage = (meta:get_int("stage") or 0) + (grow_by or 1)
if stage == nil then stage = 0 end if stage < 3 then
stage = stage + max(1, floor(delta)) meta:set_int("stage", stage)
if stage >= 3 then return
meta:set_string("grown", "true") end
-- This sapling grows in a special way when there are 4 saplings in a 2x2 pattern -- This sapling grows in a special way when there are 4 saplings in a 2x2 pattern
if two_by_two then if two_by_two then
-- Check 8 surrounding saplings and try to find a 2x2 pattern -- Check 8 surrounding saplings and try to find a 2x2 pattern
local function is_sapling(pos, sapling)
return minetest.get_node(pos).name == sapling
end
-- clockwise from x+1, coded right/bottom/left/top -- clockwise from x+1, coded right/bottom/left/top
local prr = vector_offset(pos, 1, 0, 0) -- right local prr = vector_offset(pos, 1, 0, 0) -- right
local prb = vector_offset(pos, 1, 0, -1) -- right bottom local prb = vector_offset(pos, 1, 0, -1) -- right bottom
@ -878,14 +859,14 @@ local function sapling_grow_action(tree_id, soil_needed, one_by_one, two_by_two,
local plt = vector_offset(pos, -1, 0, 1) -- left top local plt = vector_offset(pos, -1, 0, 1) -- left top
local ptt = vector_offset(pos, 0, 0, 1) -- top local ptt = vector_offset(pos, 0, 0, 1) -- top
local ptr = vector_offset(pos, 1, 0, 1) -- top right local ptr = vector_offset(pos, 1, 0, 1) -- top right
local srr = is_sapling(prr, sapling) local srr = minetest.get_node(prr).name == sapling
local srb = is_sapling(prb, sapling) local srb = minetest.get_node(prb).name == sapling
local sbb = is_sapling(pbb, sapling) local sbb = minetest.get_node(pbb).name == sapling
local sbl = is_sapling(pbl, sapling) local sbl = minetest.get_node(pbl).name == sapling
local sll = is_sapling(pll, sapling) local sll = minetest.get_node(pll).name == sapling
local slt = is_sapling(plt, sapling) local slt = minetest.get_node(plt).name == sapling
local stt = is_sapling(ptt, sapling) local stt = minetest.get_node(ptt).name == sapling
local str = is_sapling(ptr, sapling) local str = minetest.get_node(ptr).name == sapling
-- In a 3x3 field there are 4 possible 2x2 squares. We check them all. -- In a 3x3 field there are 4 possible 2x2 squares. We check them all.
if srr and srb and sbb and check_tree_growth(pos, tree_id, { two_by_two = true }) then if srr and srb and sbb and check_tree_growth(pos, tree_id, { two_by_two = true }) then
-- Success: Remove saplings and place tree -- Success: Remove saplings and place tree
@ -936,9 +917,6 @@ local function sapling_grow_action(tree_id, soil_needed, one_by_one, two_by_two,
mcl_core.generate_tree(pos, tree_id) mcl_core.generate_tree(pos, tree_id)
return return
end end
else
meta:set_int("stage", stage)
end
end end
end end
@ -948,6 +926,9 @@ local grow_jungle_tree = sapling_grow_action(JUNGLE_TREE_ID, 1, true, true, "mcl
local grow_acacia = sapling_grow_action(ACACIA_TREE_ID, 2, true, false) local grow_acacia = sapling_grow_action(ACACIA_TREE_ID, 2, true, false)
local grow_spruce = sapling_grow_action(SPRUCE_TREE_ID, 1, true, true, "mcl_core:sprucesapling") local grow_spruce = sapling_grow_action(SPRUCE_TREE_ID, 1, true, true, "mcl_core:sprucesapling")
local grow_birch = sapling_grow_action(BIRCH_TREE_ID, 1, true, false) local grow_birch = sapling_grow_action(BIRCH_TREE_ID, 1, true, false)
local grow_cherry = sapling_grow_action(CHERRY_TREE_ID, 1, true, false)
-- export for cherry tree module
mcl_core.grow_cherry = grow_cherry
function mcl_core.update_sapling_foliage_colors(pos) function mcl_core.update_sapling_foliage_colors(pos)
local foliage = minetest.find_nodes_in_area( local foliage = minetest.find_nodes_in_area(
@ -963,45 +944,37 @@ end
-- node: Node table of the node at this position, from minetest.get_node -- node: Node table of the node at this position, from minetest.get_node
-- Returns true on success and false on failure -- Returns true on success and false on failure
-- TODO: replace this with a proper tree API -- TODO: replace this with a proper tree API
function mcl_core.grow_sapling(pos, node) function mcl_core.grow_sapling(pos, node, stages)
if node.name == "mcl_core:sapling" then if node.name == "mcl_core:sapling" then
grow_oak(pos) grow_oak(pos, node, nil, nil, stages)
elseif node.name == "mcl_core:darksapling" then elseif node.name == "mcl_core:darksapling" then
grow_dark_oak(pos) grow_dark_oak(pos, node, nil, nil, stages)
elseif node.name == "mcl_core:junglesapling" then elseif node.name == "mcl_core:junglesapling" then
grow_jungle_tree(pos) grow_jungle_tree(pos, node, nil, nil, stages)
elseif node.name == "mcl_core:acaciasapling" then elseif node.name == "mcl_core:acaciasapling" then
grow_acacia(pos) grow_acacia(pos, node, nil, nil, stages)
elseif node.name == "mcl_core:sprucesapling" then elseif node.name == "mcl_core:sprucesapling" then
grow_spruce(pos) grow_spruce(pos, node, nil, nil, stages)
elseif node.name == "mcl_core:birchsapling" then elseif node.name == "mcl_core:birchsapling" then
grow_birch(pos) grow_birch(pos, node, nil, nil, stages)
elseif node.name == "mcl_cherry_blossom:cherrysapling" then elseif node.name == "mcl_cherry_blossom:cherrysapling" then
return mcl_cherry_blossom.generate_cherry_tree(pos) grow_cherry(pos, node, nil, nil, stages)
else else
return false return false
end end
return true return true
end end
-- TODO: Use better tree models for everything
-- TODO: Support 2x2 saplings
-- Oak tree -- Oak tree
minetest.register_abm({ minetest.register_abm({
label = "Oak tree growth", label = "Oak tree growth",
nodenames = {"mcl_core:sapling"}, nodenames = {"mcl_core:sapling"},
neighbors = {"group:soil_sapling"}, neighbors = {"group:soil_sapling"},
interval = 25, interval = 30,
chance = 2, chance = 3,
action = grow_oak action = function(pos, node)
}) grow_oak(pos, node, 1)
minetest.register_lbm({ end
label = "Add growth for unloaded oak tree",
name = "mcl_core:lbm_oak",
nodenames = {"mcl_core:sapling"},
run_at_every_load = true,
action = grow_oak
}) })
-- Dark oak tree -- Dark oak tree
@ -1009,16 +982,11 @@ minetest.register_abm({
label = "Dark oak tree growth", label = "Dark oak tree growth",
nodenames = {"mcl_core:darksapling"}, nodenames = {"mcl_core:darksapling"},
neighbors = {"group:soil_sapling"}, neighbors = {"group:soil_sapling"},
interval = 25, interval = 30,
chance = 2, chance = 3,
action = grow_dark_oak action = function(pos, node)
}) grow_dark_oak(pos, node, 1)
minetest.register_lbm({ end
label = "Add growth for unloaded dark oak tree",
name = "mcl_core:lbm_dark_oak",
nodenames = {"mcl_core:darksapling"},
run_at_every_load = true,
action = grow_dark_oak
}) })
-- Jungle Tree -- Jungle Tree
@ -1026,16 +994,11 @@ minetest.register_abm({
label = "Jungle tree growth", label = "Jungle tree growth",
nodenames = {"mcl_core:junglesapling"}, nodenames = {"mcl_core:junglesapling"},
neighbors = {"group:soil_sapling"}, neighbors = {"group:soil_sapling"},
interval = 25, interval = 30,
chance = 2, chance = 3,
action = grow_jungle_tree action = function(pos, node)
}) grow_jungle_tree(pos, node, 1)
minetest.register_lbm({ end
label = "Add growth for unloaded jungle tree",
name = "mcl_core:lbm_jungle_tree",
nodenames = {"mcl_core:junglesapling"},
run_at_every_load = true,
action = grow_jungle_tree
}) })
-- Spruce tree -- Spruce tree
@ -1043,16 +1006,11 @@ minetest.register_abm({
label = "Spruce tree growth", label = "Spruce tree growth",
nodenames = {"mcl_core:sprucesapling"}, nodenames = {"mcl_core:sprucesapling"},
neighbors = {"group:soil_sapling"}, neighbors = {"group:soil_sapling"},
interval = 25, interval = 30,
chance = 2, chance = 3,
action = grow_spruce action = function(pos, node)
}) grow_spruce(pos, node, 1)
minetest.register_lbm({ end
label = "Add growth for unloaded spruce tree",
name = "mcl_core:lbm_spruce",
nodenames = {"mcl_core:sprucesapling"},
run_at_every_load = true,
action = grow_spruce
}) })
-- Birch tree -- Birch tree
@ -1060,16 +1018,11 @@ minetest.register_abm({
label = "Birch tree growth", label = "Birch tree growth",
nodenames = {"mcl_core:birchsapling"}, nodenames = {"mcl_core:birchsapling"},
neighbors = {"group:soil_sapling"}, neighbors = {"group:soil_sapling"},
interval = 25, interval = 30,
chance = 2, chance = 3,
action = grow_birch action = function(pos, node)
}) grow_birch(pos, node, 1)
minetest.register_lbm({ end
label = "Add growth for unloaded birch tree",
name = "mcl_core:lbm_birch",
nodenames = {"mcl_core:birchsapling"},
run_at_every_load = true,
action = grow_birch
}) })
-- Acacia tree -- Acacia tree
@ -1077,18 +1030,37 @@ minetest.register_abm({
label = "Acacia tree growth", label = "Acacia tree growth",
nodenames = {"mcl_core:acaciasapling"}, nodenames = {"mcl_core:acaciasapling"},
neighbors = {"group:soil_sapling"}, neighbors = {"group:soil_sapling"},
interval = 20, interval = 30,
chance = 2, chance = 3,
action = grow_acacia action = function(pos, node)
grow_acacia(pos, node, 1)
end
}) })
minetest.register_lbm({ minetest.register_lbm({
label = "Add growth for unloaded acacia tree", label = "Add growth for trees in unloaded blocks",
name = "mcl_core:lbm_acacia", name = "mcl_core:tree_sapling_growth",
nodenames = {"mcl_core:acaciasapling"}, nodenames = { "group:sapling" },
neighbors = {"group:soil_sapling"},
run_at_every_load = true, run_at_every_load = true,
action = grow_acacia action = function(pos, node, dtime_s)
-- right now, all trees have 1/(30*3) chance
-- TODO: make this an API similar to farming
local interval, chance = 30, 3
local rolls = floor(dtime_s / interval)
if rolls <= 0 then return end
-- simulate how often the block will be ticked
local stages = 0
for i = 1,rolls do
if random(1, chance) == 1 then stages = stages + 1 end
end
if stages > 0 then
mcl_core.grow_sapling(pos, node, stages)
end
end,
}) })
local function leafdecay_particles(pos, node) local function leafdecay_particles(pos, node)
minetest.add_particlespawner({ minetest.add_particlespawner({
amount = random(10, 20), amount = random(10, 20),