From 336c0849aaa266cd8dd98b879ca0749955abc46e Mon Sep 17 00:00:00 2001 From: FaceDeer Date: Mon, 10 Feb 2020 13:38:27 -0700 Subject: [PATCH] improve the efficiency of giant mycelium growth using flat node array, fewer dereferences --- df_caverns/primordial.lua | 4 +- df_primordial_items/giant_mycelium.lua | 219 ++++++++++++++----------- 2 files changed, 123 insertions(+), 100 deletions(-) diff --git a/df_caverns/primordial.lua b/df_caverns/primordial.lua index 4514c4b..c2b46db 100644 --- a/df_caverns/primordial.lua +++ b/df_caverns/primordial.lua @@ -104,7 +104,7 @@ local mushroom_warren_ceiling = function(abs_cracks, vi, area, data, data_param2 data[vi] = c_mycelial_dirt if abs_cracks < 0.2 then local rand = math.random() - if rand < 0.002 then + if rand < 0.001 then local mycelium_index = vi-ystride data[mycelium_index] = c_giant_mycelium minetest.get_node_timer(area:position(mycelium_index)):start(math.random(1,giant_mycelium_timer_spread)) @@ -354,7 +354,7 @@ local decorate_primordial = function(minp, maxp, seed, vm, node_arrays, area, da minetest.get_node_timer(area:position(vi)):start(math.random(30, 120)) else data[vi] = c_mycelial_dirt - if math.random() < 0.025 then + if math.random() < 0.05 then local rand_vi = vi + random_dir[math.random(1,4)] if data[rand_vi] == c_air then data[rand_vi] = c_giant_mycelium diff --git a/df_primordial_items/giant_mycelium.lua b/df_primordial_items/giant_mycelium.lua index 840ca3d..9f8a8d9 100644 --- a/df_primordial_items/giant_mycelium.lua +++ b/df_primordial_items/giant_mycelium.lua @@ -111,29 +111,37 @@ minetest.register_craft({ -- By growing with these conditions hyphae will hug the ground and will not immediately loop back on themselves -- (though they can run into other pre-existing growths, forming larger loops - which is fine, large loops are nice) +local ystride = 3 +local zstride = 9 +local get_item_group = minetest.get_item_group +local get_node = minetest.get_node +local registered_nodes = minetest.registered_nodes +local math_random = math.random + local find_mycelium_growth_targets = function(pos) local nodes = {} + local pos_x = pos.x + local pos_y = pos.y + local pos_z = pos.z + for x = -1, 1 do - nodes[x] = {} for y = -1, 1 do - nodes[x][y] = {} for z = -1, 1 do if not (x == y and y == z) then -- we don't care about the diagonals or the center node - local node = minetest.get_node({x=pos.x+x, y=pos.y+y, z=pos.z+z}) - if node.name == "ignore" then + local node = get_node({x=pos_x+x, y=pos_y+y, z=pos_z+z}) + local node_name = node.name + if node_name == "ignore" then -- Pause growth! We're at the edge of the known world. return nil end - local state = {} - if minetest.get_item_group(node.name, "soil") > 0 or - minetest.get_item_group(node.name, "stone") > 0 and math.random() < 0.5 then -- let hyphae explore out over stone - state.soil = true - elseif minetest.get_item_group(node.name, "hypha") > 0 then - state.hypha = true - elseif minetest.registered_nodes[node.name] and minetest.registered_nodes[node.name].buildable_to then - state.buildable = true + if get_item_group(node_name, "soil") > 0 or + get_item_group(node_name, "stone") > 0 and math_random() < 0.5 then -- let hyphae explore out over stone + nodes[x + y*ystride + z*zstride] = "soil" + elseif get_item_group(node_name, "hypha") > 0 then + nodes[x + y*ystride + z*zstride] = "hypha" + elseif registered_nodes[node_name] and registered_nodes[node_name].buildable_to then + nodes[x + y*ystride + z*zstride] = "buildable" end - nodes[x][y][z] = state end end end @@ -143,119 +151,119 @@ local find_mycelium_growth_targets = function(pos) --copy and pasting is easy and nobody's going to decide whether to hire or fire me based on this --particular snippet of code so what the hell. I'll fix it later when that clever way comes to me. local valid_targets = {} - if nodes[-1][0][0].buildable and + if nodes[-1] == "buildable" and -- test for soil to directly support new growth - (nodes[-1][-1][0].soil or - nodes[-1][1][0].soil or - nodes[-1][0][-1].soil or - nodes[-1][0][1].soil or + (nodes[-1 -ystride] == "soil" or + nodes[-1 +ystride] == "soil" or + nodes[-1 -zstride] == "soil" or + nodes[-1 +zstride] == "soil" or -- test for soil "around the corner" to allow for growth over an edge - nodes[0][-1][0].soil or - nodes[0][1][0].soil or - nodes[0][0][-1].soil or - nodes[0][0][1].soil) + nodes[-ystride] == "soil" or + nodes[ystride] == "soil" or + nodes[-zstride] == "soil" or + nodes[zstride] == "soil") and not -- no adjacent hypha - (nodes[-1][-1][0].hypha or - nodes[-1][1][0].hypha or - nodes[-1][0][-1].hypha or - nodes[-1][0][1].hypha) + (nodes[-1 -ystride] == "hypha" or + nodes[-1 +ystride] == "hypha" or + nodes[-1 -zstride] == "hypha" or + nodes[-1 +zstride] == "hypha") then - table.insert(valid_targets, {x=pos.x-1, y=pos.y, z=pos.z}) + table.insert(valid_targets, {x=pos_x-1, y=pos_y, z=pos_z}) end - if nodes[1][0][0].buildable and + if nodes[1] == "buildable" and -- test for soil to directly support new growth - (nodes[1][-1][0].soil or - nodes[1][1][0].soil or - nodes[1][0][-1].soil or - nodes[1][0][1].soil or + (nodes[1 -ystride] == "soil" or + nodes[1 +ystride] == "soil" or + nodes[1 -zstride] == "soil" or + nodes[1 +zstride] == "soil" or -- test for soil "around the corner" to allow for growth over an edge - nodes[0][-1][0].soil or - nodes[0][1][0].soil or - nodes[0][0][-1].soil or - nodes[0][0][1].soil) + nodes[-ystride] == "soil" or + nodes[ystride] == "soil" or + nodes[-zstride] == "soil" or + nodes[zstride] == "soil") and not -- no adjacent hypha - (nodes[1][-1][0].hypha or - nodes[1][1][0].hypha or - nodes[1][0][-1].hypha or - nodes[1][0][1].hypha) + (nodes[1 -ystride] == "hypha" or + nodes[1 +ystride] == "hypha" or + nodes[1 -zstride] == "hypha" or + nodes[1 +zstride] == "hypha") then - table.insert(valid_targets, {x=pos.x+1, y=pos.y, z=pos.z}) + table.insert(valid_targets, {x=pos_x+1, y=pos_y, z=pos_z}) end - if nodes[0][-1][0].buildable and + if nodes[-ystride] == "buildable" and -- test for soil to directly support new growth - (nodes[-1][-1][0].soil or - nodes[1][-1][0].soil or - nodes[0][-1][-1].soil or - nodes[0][-1][1].soil or + (nodes[-1 -ystride] == "soil" or + nodes[1 -ystride] == "soil" or + nodes[-ystride -zstride] == "soil" or + nodes[-ystride +zstride] == "soil" or -- test for soil "around the corner" to allow for growth over an edge - nodes[-1][0][0].soil or - nodes[1][0][0].soil or - nodes[0][0][-1].soil or - nodes[0][0][1].soil) + nodes[-1] == "soil" or + nodes[1] == "soil" or + nodes[-zstride] == "soil" or + nodes[zstride] == "soil") and not -- no adjacent hypha - (nodes[-1][-1][0].hypha or - nodes[1][-1][0].hypha or - nodes[0][-1][-1].hypha or - nodes[0][-1][1].hypha) + (nodes[-1 -ystride] == "hypha" or + nodes[1 -ystride] == "hypha" or + nodes[-ystride -zstride] == "hypha" or + nodes[-ystride +zstride] == "hypha") then - table.insert(valid_targets, {x=pos.x, y=pos.y-1, z=pos.z}) + table.insert(valid_targets, {x=pos_x, y=pos_y-1, z=pos_z}) end - if nodes[0][1][0].buildable and + if nodes[ystride] == "buildable" and -- test for soil to directly support new growth - (nodes[-1][1][0].soil or - nodes[1][1][0].soil or - nodes[0][1][-1].soil or - nodes[0][1][1].soil or + (nodes[-1 +ystride] == "soil" or + nodes[1 +ystride] == "soil" or + nodes[ystride -zstride] == "soil" or + nodes[ystride +zstride] == "soil" or -- test for soil "around the corner" to allow for growth over an edge - nodes[-1][0][0].soil or - nodes[1][0][0].soil or - nodes[0][0][-1].soil or - nodes[0][0][1].soil) + nodes[-1] == "soil" or + nodes[1] == "soil" or + nodes[-zstride] == "soil" or + nodes[zstride] == "soil") and not -- no adjacent hypha - (nodes[-1][1][0].hypha or - nodes[1][1][0].hypha or - nodes[0][1][-1].hypha or - nodes[0][1][1].hypha) + (nodes[-1] == "hypha" or + nodes[1 + ystride] == "hypha" or + nodes[ystride -zstride] == "hypha" or + nodes[ystride +zstride] == "hypha") then - table.insert(valid_targets, {x=pos.x, y=pos.y+1, z=pos.z}) + table.insert(valid_targets, {x=pos_x, y=pos_y+1, z=pos_z}) end - if nodes[0][0][-1].buildable and + if nodes[-zstride] == "buildable" and -- test for soil to directly support new growth - (nodes[-1][0][-1].soil or - nodes[1][0][-1].soil or - nodes[0][-1][-1].soil or - nodes[0][1][-1].soil or + (nodes[-1 -zstride] == "soil" or + nodes[1 -zstride] == "soil" or + nodes[-ystride -zstride] == "soil" or + nodes[ystride -zstride] == "soil" or -- test for soil "around the corner" to allow for growth over an edge - nodes[-1][0][0].soil or - nodes[1][0][0].soil or - nodes[0][-1][0].soil or - nodes[0][1][0].soil) + nodes[-1] == "soil" or + nodes[1] == "soil" or + nodes[-ystride] == "soil" or + nodes[ystride] == "soil") and not -- no adjacent hypha - (nodes[-1][0][-1].hypha or - nodes[1][0][-1].hypha or - nodes[0][-1][-1].hypha or - nodes[0][1][-1].hypha) + (nodes[-1 -zstride] == "hypha" or + nodes[1 -zstride] == "hypha" or + nodes[-ystride -zstride] == "hypha" or + nodes[ystride -zstride] == "hypha") then - table.insert(valid_targets, {x=pos.x, y=pos.y, z=pos.z-1}) + table.insert(valid_targets, {x=pos_x, y=pos_y, z=pos_z-1}) end - if nodes[0][0][1].buildable and + if nodes[zstride] == "buildable" and -- test for soil to directly support new growth - (nodes[-1][0][1].soil or - nodes[1][0][1].soil or - nodes[0][-1][1].soil or - nodes[0][1][1].soil or + (nodes[-1 +zstride] == "soil" or + nodes[1 +zstride] == "soil" or + nodes[-ystride +zstride] == "soil" or + nodes[ystride +zstride] == "soil" or -- test for soil "around the corner" to allow for growth over an edge - nodes[-1][0][0].soil or - nodes[1][0][0].soil or - nodes[0][-1][0].soil or - nodes[0][1][0].soil) + nodes[-1] == "soil" or + nodes[1] == "soil" or + nodes[-ystride] == "soil" or + nodes[ystride] == "soil") and not -- no adjacent hypha - (nodes[-1][0][1].hypha or - nodes[1][0][1].hypha or - nodes[0][-1][1].hypha or - nodes[0][1][1].hypha) + (nodes[-1 +zstride] == "hypha" or + nodes[1 +zstride] == "hypha" or + nodes[-ystride + zstride] == "hypha" or + nodes[ystride +zstride] == "hypha") then - table.insert(valid_targets, {x=pos.x, y=pos.y, z=pos.z+1}) + table.insert(valid_targets, {x=pos_x, y=pos_y, z=pos_z+1}) end return valid_targets @@ -371,11 +379,12 @@ local grow_mycelium_immediately = function(pos) local pos = table.remove(stack) if not (df_farming and df_farming.kill_if_sunlit(pos)) then local new_poses = grow_mycelium(pos, "df_primordial_items:giant_hypha_apical_mapgen") - if new_poses then -- if we hit the end of the world, just stop. There'll be a mapgen meristem left here, re-trigger it. + if new_poses then for _, new_pos in ipairs(new_poses) do table.insert(stack, new_pos) end else + -- if we hit the end of the world, just stop. There'll be a mapgen meristem left here, re-trigger it. minetest.get_node_timer(pos):start(math.random(10,60)) end end @@ -407,4 +416,18 @@ minetest.register_node("df_primordial_items:giant_hypha_apical_mapgen", { on_destruct = function(pos) minetest.get_node_timer(pos):stop() end, +}) + +-- Just in case mapgen fails to trigger the timer on a mapgen mycelium this ABM will clean up. +minetest.register_abm({ + label = "df_primordial_items ensure giant mycelium growth", + nodenames = {"df_primordial_items:giant_hypha_apical_mapgen"}, + interval = 10.0, + chance = 1, + action = function(pos, node, active_object_count, active_object_count_wider) + local timer = minetest.get_node_timer(pos) + if not timer:is_started() then + timer:start(math.random(1,10)) + end + end, }) \ No newline at end of file