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

View file

@ -22,6 +22,7 @@ local SPRUCE_TREE_ID = 3
local ACACIA_TREE_ID = 4
local JUNGLE_TREE_ID = 5
local BIRCH_TREE_ID = 6
local CHERRY_TREE_ID = 7
minetest.register_abm({
label = "Lava cooling",
@ -305,6 +306,8 @@ local function check_tree_growth(pos, tree_id, options)
return check_growth_width(pos, 7, 8)
elseif tree_id == DARK_OAK_TREE_ID and two_by_two then
return check_growth_width(pos, 4, 7)
elseif tree_id == CHERRY_TREE_ID then
return check_growth_width(pos, 7, 8)
end
return false
@ -356,6 +359,8 @@ function mcl_core.generate_tree(pos, tree_type, options)
end
elseif tree_type == BIRCH_TREE_ID then
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
mcl_core.update_sapling_foliage_colors(pos)
end
@ -822,35 +827,14 @@ minetest.register_lbm({
--------------------------
-- 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)
return function(pos)
return function(pos, node, grow_by)
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
local light = minetest.get_node_light(pos)
if not 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...
if not light or light < TREE_MINIMUM_LIGHT then return end
local soilnode = minetest.get_node(vector_offset(pos, 0, -1, 0))
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
local meta = minetest.get_meta(pos)
local stage = meta:get_int("stage")
if stage == nil then stage = 0 end
stage = stage + max(1, floor(delta))
if stage >= 3 then
meta:set_string("grown", "true")
local stage = (meta:get_int("stage") or 0) + (grow_by or 1)
if stage < 3 then
meta:set_int("stage", stage)
return
end
-- This sapling grows in a special way when there are 4 saplings in a 2x2 pattern
if two_by_two then
-- 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
local prr = vector_offset(pos, 1, 0, 0) -- right
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 ptt = vector_offset(pos, 0, 0, 1) -- top
local ptr = vector_offset(pos, 1, 0, 1) -- top right
local srr = is_sapling(prr, sapling)
local srb = is_sapling(prb, sapling)
local sbb = is_sapling(pbb, sapling)
local sbl = is_sapling(pbl, sapling)
local sll = is_sapling(pll, sapling)
local slt = is_sapling(plt, sapling)
local stt = is_sapling(ptt, sapling)
local str = is_sapling(ptr, sapling)
local srr = minetest.get_node(prr).name == sapling
local srb = minetest.get_node(prb).name == sapling
local sbb = minetest.get_node(pbb).name == sapling
local sbl = minetest.get_node(pbl).name == sapling
local sll = minetest.get_node(pll).name == sapling
local slt = minetest.get_node(plt).name == sapling
local stt = minetest.get_node(ptt).name == sapling
local str = minetest.get_node(ptr).name == sapling
-- 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
-- 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)
return
end
else
meta:set_int("stage", stage)
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_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_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)
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
-- Returns true on success and false on failure
-- 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
grow_oak(pos)
grow_oak(pos, node, nil, nil, stages)
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
grow_jungle_tree(pos)
grow_jungle_tree(pos, node, nil, nil, stages)
elseif node.name == "mcl_core:acaciasapling" then
grow_acacia(pos)
grow_acacia(pos, node, nil, nil, stages)
elseif node.name == "mcl_core:sprucesapling" then
grow_spruce(pos)
grow_spruce(pos, node, nil, nil, stages)
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
return mcl_cherry_blossom.generate_cherry_tree(pos)
grow_cherry(pos, node, nil, nil, stages)
else
return false
end
return true
end
-- TODO: Use better tree models for everything
-- TODO: Support 2x2 saplings
-- Oak tree
minetest.register_abm({
label = "Oak tree growth",
nodenames = {"mcl_core:sapling"},
neighbors = {"group:soil_sapling"},
interval = 25,
chance = 2,
action = grow_oak
})
minetest.register_lbm({
label = "Add growth for unloaded oak tree",
name = "mcl_core:lbm_oak",
nodenames = {"mcl_core:sapling"},
run_at_every_load = true,
action = grow_oak
interval = 30,
chance = 3,
action = function(pos, node)
grow_oak(pos, node, 1)
end
})
-- Dark oak tree
@ -1009,16 +982,11 @@ minetest.register_abm({
label = "Dark oak tree growth",
nodenames = {"mcl_core:darksapling"},
neighbors = {"group:soil_sapling"},
interval = 25,
chance = 2,
action = grow_dark_oak
})
minetest.register_lbm({
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
interval = 30,
chance = 3,
action = function(pos, node)
grow_dark_oak(pos, node, 1)
end
})
-- Jungle Tree
@ -1026,16 +994,11 @@ minetest.register_abm({
label = "Jungle tree growth",
nodenames = {"mcl_core:junglesapling"},
neighbors = {"group:soil_sapling"},
interval = 25,
chance = 2,
action = grow_jungle_tree
})
minetest.register_lbm({
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
interval = 30,
chance = 3,
action = function(pos, node)
grow_jungle_tree(pos, node, 1)
end
})
-- Spruce tree
@ -1043,16 +1006,11 @@ minetest.register_abm({
label = "Spruce tree growth",
nodenames = {"mcl_core:sprucesapling"},
neighbors = {"group:soil_sapling"},
interval = 25,
chance = 2,
action = grow_spruce
})
minetest.register_lbm({
label = "Add growth for unloaded spruce tree",
name = "mcl_core:lbm_spruce",
nodenames = {"mcl_core:sprucesapling"},
run_at_every_load = true,
action = grow_spruce
interval = 30,
chance = 3,
action = function(pos, node)
grow_spruce(pos, node, 1)
end
})
-- Birch tree
@ -1060,16 +1018,11 @@ minetest.register_abm({
label = "Birch tree growth",
nodenames = {"mcl_core:birchsapling"},
neighbors = {"group:soil_sapling"},
interval = 25,
chance = 2,
action = grow_birch
})
minetest.register_lbm({
label = "Add growth for unloaded birch tree",
name = "mcl_core:lbm_birch",
nodenames = {"mcl_core:birchsapling"},
run_at_every_load = true,
action = grow_birch
interval = 30,
chance = 3,
action = function(pos, node)
grow_birch(pos, node, 1)
end
})
-- Acacia tree
@ -1077,18 +1030,37 @@ minetest.register_abm({
label = "Acacia tree growth",
nodenames = {"mcl_core:acaciasapling"},
neighbors = {"group:soil_sapling"},
interval = 20,
chance = 2,
action = grow_acacia
interval = 30,
chance = 3,
action = function(pos, node)
grow_acacia(pos, node, 1)
end
})
minetest.register_lbm({
label = "Add growth for unloaded acacia tree",
name = "mcl_core:lbm_acacia",
nodenames = {"mcl_core:acaciasapling"},
label = "Add growth for trees in unloaded blocks",
name = "mcl_core:tree_sapling_growth",
nodenames = { "group:sapling" },
neighbors = {"group:soil_sapling"},
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)
minetest.add_particlespawner({
amount = random(10, 20),