summaryrefslogtreecommitdiff
path: root/biome_lib
diff options
context:
space:
mode:
authorVanessa Dannenberg <vanessa.e.dannenberg@gmail.com>2019-03-06 17:01:02 -0500
committerVanessa Dannenberg <vanessa.e.dannenberg@gmail.com>2019-03-06 17:01:02 -0500
commitb21c3d368077aa3a1c42ff1582cda6263c018585 (patch)
tree4053ef589ef5c5b99f0a87b567207e8c52cf4c76 /biome_lib
parentec25fd83415d0ecb49f41295af3dc30f14850b2f (diff)
downloaddreambuilder_modpack-b21c3d368077aa3a1c42ff1582cda6263c018585.tar
dreambuilder_modpack-b21c3d368077aa3a1c42ff1582cda6263c018585.tar.gz
dreambuilder_modpack-b21c3d368077aa3a1c42ff1582cda6263c018585.tar.bz2
dreambuilder_modpack-b21c3d368077aa3a1c42ff1582cda6263c018585.tar.xz
dreambuilder_modpack-b21c3d368077aa3a1c42ff1582cda6263c018585.zip
updated cottages, areasprotector, bees, biome_lib, technic, facade,
farming redo, homedecor, maptools, mesecons, moreblocks, moreores, pipeworks, quartz, travelnet, unified_inventory, unifieddyes, xban2 delete the playeranim mod, not 5.0.0 compatible.
Diffstat (limited to 'biome_lib')
-rw-r--r--biome_lib/growth.lua80
-rw-r--r--biome_lib/init.lua693
-rw-r--r--biome_lib/search_functions.lua60
3 files changed, 471 insertions, 362 deletions
diff --git a/biome_lib/growth.lua b/biome_lib/growth.lua
new file mode 100644
index 0000000..56ba4ef
--- /dev/null
+++ b/biome_lib/growth.lua
@@ -0,0 +1,80 @@
+local time_scale = ...
+
+-- The growing ABM
+
+function biome_lib:grow_plants(opts)
+
+ local options = opts
+
+ options.height_limit = options.height_limit or 5
+ options.ground_nodes = options.ground_nodes or { "default:dirt_with_grass" }
+ options.grow_nodes = options.grow_nodes or { "default:dirt_with_grass" }
+ options.seed_diff = options.seed_diff or 0
+
+ local n
+
+ if type(options.grow_plant) == "table" then
+ n = "multi: "..options.grow_plant[1]..", ..."
+ else
+ n = options.grow_plant
+ end
+
+ options.label = options.label or "biome_lib grow_plants(): "..n
+
+ if options.grow_delay*time_scale >= 1 then
+ options.interval = options.grow_delay*time_scale
+ else
+ options.interval = 1
+ end
+
+ minetest.register_abm({
+ nodenames = { options.grow_plant },
+ interval = options.interval,
+ chance = options.grow_chance,
+ label = options.label,
+ action = function(pos, node, active_object_count, active_object_count_wider)
+ local p_top = {x=pos.x, y=pos.y+1, z=pos.z}
+ local p_bot = {x=pos.x, y=pos.y-1, z=pos.z}
+ local n_top = minetest.get_node(p_top)
+ local n_bot = minetest.get_node(p_bot)
+ local root_node = minetest.get_node({x=pos.x, y=pos.y-options.height_limit, z=pos.z})
+ local walldir = nil
+ if options.need_wall and options.verticals_list then
+ walldir = biome_lib:find_adjacent_wall(p_top, options.verticals_list, options.choose_random_wall)
+ end
+ if (n_top.name == "air" or n_top.name == "default:snow")
+ and (not options.need_wall or (options.need_wall and walldir)) then
+ -- corner case for changing short junglegrass
+ -- to dry shrub in desert
+ if n_bot.name == options.dry_early_node and options.grow_plant == "junglegrass:short" then
+ minetest.swap_node(pos, { name = "default:dry_shrub" })
+
+ elseif options.grow_vertically and walldir then
+ if biome_lib:search_downward(pos, options.height_limit, options.ground_nodes) then
+ minetest.swap_node(p_top, { name = options.grow_plant, param2 = walldir})
+ end
+
+ elseif not options.grow_result and not options.grow_function then
+ minetest.swap_node(pos, biome_lib.air)
+
+ else
+ biome_lib:replace_object(pos, options.grow_result, options.grow_function, options.facedir, options.seed_diff)
+ end
+ end
+ end
+ })
+end
+
+
+-- spawn_tree() on generate is routed through here so that other mods can hook
+-- into it.
+
+function biome_lib:generate_tree(pos, nodes_or_function_or_model)
+ minetest.spawn_tree(pos, nodes_or_function_or_model)
+end
+
+-- and this one's for the call used in the growing code
+
+function biome_lib:grow_tree(pos, nodes_or_function_or_model)
+ minetest.spawn_tree(pos, nodes_or_function_or_model)
+end
diff --git a/biome_lib/init.lua b/biome_lib/init.lua
index f79c1d7..e54f9a4 100644
--- a/biome_lib/init.lua
+++ b/biome_lib/init.lua
@@ -84,6 +84,22 @@ biome_lib.perlin_humidity = PerlinNoise(humidity_seeddiff, humidity_octaves, hum
-- Local functions
+local function get_biome_data(pos, perlin_fertile)
+ local fertility = perlin_fertile:get2d({x=pos.x, y=pos.z})
+
+ if type(minetest.get_biome_data) == "function" then
+ local data = minetest.get_biome_data(pos)
+ if data then
+ return fertility, data.heat / 100, data.humidity / 100
+ end
+ end
+
+ local temperature = biome_lib.perlin_temperature:get2d({x=pos.x, y=pos.z})
+ local humidity = biome_lib.perlin_humidity:get2d({x=pos.x+150, y=pos.z+50})
+
+ return fertility, temperature, humidity
+end
+
function biome_lib:is_node_loaded(node_pos)
local n = minetest.get_node_or_nil(node_pos)
if (not n) or (n.name == "ignore") then
@@ -198,6 +214,87 @@ function biome_lib:register_generate_plant(biomedef, nodes_or_function_or_model)
end
end
+-- Function to check whether a position matches the given biome definition
+-- Returns true when the surface can be populated
+
+local function populate_single_surface(biome, pos, perlin_fertile_area, checkair)
+ local p_top = { x = pos.x, y = pos.y + 1, z = pos.z }
+
+ if math.random(1, 100) <= biome.rarity then
+ return
+ end
+
+ local fertility, temperature, humidity = get_biome_data(pos, perlin_fertile_area)
+
+ local pos_biome_ok = pos.y >= biome.min_elevation and pos.y <= biome.max_elevation
+ and fertility > biome.plantlife_limit
+ and temperature <= biome.temp_min and temperature >= biome.temp_max
+ and humidity <= biome.humidity_min and humidity >= biome.humidity_max
+
+ if not pos_biome_ok then
+ return -- Y position mismatch, outside of biome
+ end
+
+ local biome_surfaces_string = dump(biome.surface)
+ local surface_ok = false
+
+ if not biome.depth then
+ local dest_node = minetest.get_node(pos)
+ if string.find(biome_surfaces_string, dest_node.name) then
+ surface_ok = true
+ else
+ if string.find(biome_surfaces_string, "group:") then
+ for j = 1, #biome.surface do
+ if string.find(biome.surface[j], "^group:")
+ and minetest.get_item_group(dest_node.name, biome.surface[j]) then
+ surface_ok = true
+ break
+ end
+ end
+ end
+ end
+ elseif not string.find(biome_surfaces_string,
+ minetest.get_node({ x = pos.x, y = pos.y-biome.depth-1, z = pos.z }).name) then
+ surface_ok = true
+ end
+
+ if not surface_ok then
+ return -- Surface does not match the given node group/name
+ end
+
+ if checkair and minetest.get_node(p_top).name ~= "air" then
+ return
+ end
+
+ if biome.below_nodes and
+ not string.find(dump(biome.below_nodes),
+ minetest.get_node({x=pos.x, y=pos.y-1, z=pos.z}).name
+ ) then
+ return -- Node below does not match
+ end
+
+ if biome.ncount and
+ #minetest.find_nodes_in_area(
+ {x=pos.x-1, y=pos.y, z=pos.z-1},
+ {x=pos.x+1, y=pos.y, z=pos.z+1},
+ biome.neighbors
+ ) <= biome.ncount then
+ return -- Not enough similar biome nodes around
+ end
+
+ if biome.near_nodes and
+ #minetest.find_nodes_in_area(
+ {x=pos.x-biome.near_nodes_size, y=pos.y-biome.near_nodes_vertical, z=pos.z-biome.near_nodes_size},
+ {x=pos.x+biome.near_nodes_size, y=pos.y+biome.near_nodes_vertical, z=pos.z+biome.near_nodes_size},
+ biome.near_nodes
+ ) < biome.near_nodes_count then
+ return -- Long distance neighbours do not match
+ end
+
+ -- Position fits into given biome
+ return true
+end
+
function biome_lib:populate_surfaces(biome, nodes_or_function_or_model, snodes, checkair)
biome_lib:set_defaults(biome)
@@ -208,47 +305,8 @@ function biome_lib:populate_surfaces(biome, nodes_or_function_or_model, snodes,
local perlin_fertile_area = minetest.get_perlin(biome.seed_diff, perlin_octaves, perlin_persistence, perlin_scale)
for i = 1, #snodes do
- local pos = snodes[i]
- local p_top = { x = pos.x, y = pos.y + 1, z = pos.z }
- local noise1 = perlin_fertile_area:get2d({x=pos.x, y=pos.z})
- local noise2 = biome_lib.perlin_temperature:get2d({x=pos.x, y=pos.z})
- local noise3 = biome_lib.perlin_humidity:get2d({x=pos.x+150, y=pos.z+50})
- local biome_surfaces_string = dump(biome.surface)
- local surface_ok = false
-
- if not biome.depth then
- local dest_node = minetest.get_node(pos)
- if string.find(biome_surfaces_string, dest_node.name) then
- surface_ok = true
- else
- if string.find(biome_surfaces_string, "group:") then
- for j = 1, #biome.surface do
- if string.find(biome.surface[j], "^group:")
- and minetest.get_item_group(dest_node.name, biome.surface[j]) then
- surface_ok = true
- break
- end
- end
- end
- end
- elseif not string.find(biome_surfaces_string, minetest.get_node({ x = pos.x, y = pos.y-biome.depth-1, z = pos.z }).name) then
- surface_ok = true
- end
-
- if surface_ok
- and pos.y >= biome.min_elevation
- and pos.y <= biome.max_elevation
- and noise1 > biome.plantlife_limit
- and noise2 <= biome.temp_min
- and noise2 >= biome.temp_max
- and noise3 <= biome.humidity_min
- and noise3 >= biome.humidity_max
- and (not checkair or minetest.get_node(p_top).name == "air")
- and (not biome.ncount or #(minetest.find_nodes_in_area({x=pos.x-1, y=pos.y, z=pos.z-1}, {x=pos.x+1, y=pos.y, z=pos.z+1}, biome.neighbors)) > biome.ncount)
- and (not biome.near_nodes or #(minetest.find_nodes_in_area({x=pos.x-biome.near_nodes_size, y=pos.y-biome.near_nodes_vertical, z=pos.z-biome.near_nodes_size}, {x=pos.x+biome.near_nodes_size, y=pos.y+biome.near_nodes_vertical, z=pos.z+biome.near_nodes_size}, biome.near_nodes)) >= biome.near_nodes_count)
- and math.random(1,100) > biome.rarity
- and (not biome.below_nodes or string.find(dump(biome.below_nodes), minetest.get_node({x=pos.x, y=pos.y-1, z=pos.z}).name) )
- then
+ local pos = vector.new(snodes[i])
+ if populate_single_surface(biome, pos, perlin_fertile_area, checkair) then
in_biome_nodes[#in_biome_nodes + 1] = pos
end
end
@@ -257,73 +315,77 @@ function biome_lib:populate_surfaces(biome, nodes_or_function_or_model, snodes,
local num_in_biome_nodes = #in_biome_nodes
- if num_in_biome_nodes > 0 then
- for i = 1, math.min(biome.max_count, num_in_biome_nodes) do
- local tries = 0
- local spawned = false
- while tries < 2 and not spawned do
- local pos = in_biome_nodes[math.random(1, num_in_biome_nodes)]
- if biome.spawn_replace_node then
- pos.y = pos.y-1
+ if num_in_biome_nodes == 0 then
+ return
+ end
+
+ for i = 1, math.min(biome.max_count, num_in_biome_nodes) do
+ local tries = 0
+ local spawned = false
+ while tries < 2 and not spawned do
+ local pos = in_biome_nodes[math.random(1, num_in_biome_nodes)]
+ if biome.spawn_replace_node then
+ pos.y = pos.y-1
+ end
+ local p_top = { x = pos.x, y = pos.y + 1, z = pos.z }
+
+ if not (biome.avoid_nodes and biome.avoid_radius
+ and minetest.find_node_near(p_top, biome.avoid_radius
+ + math.random(-1.5,2), biome.avoid_nodes)) then
+ if biome.delete_above then
+ minetest.swap_node(p_top, biome_lib.air)
+ minetest.swap_node({x=p_top.x, y=p_top.y+1, z=p_top.z}, biome_lib.air)
end
- local p_top = { x = pos.x, y = pos.y + 1, z = pos.z }
- if not (biome.avoid_nodes and biome.avoid_radius and minetest.find_node_near(p_top, biome.avoid_radius + math.random(-1.5,2), biome.avoid_nodes)) then
- if biome.delete_above then
- minetest.swap_node(p_top, biome_lib.air)
- minetest.swap_node({x=p_top.x, y=p_top.y+1, z=p_top.z}, biome_lib.air)
- end
+ if biome.delete_above_surround then
+ minetest.swap_node({x=p_top.x-1, y=p_top.y, z=p_top.z}, biome_lib.air)
+ minetest.swap_node({x=p_top.x+1, y=p_top.y, z=p_top.z}, biome_lib.air)
+ minetest.swap_node({x=p_top.x, y=p_top.y, z=p_top.z-1}, biome_lib.air)
+ minetest.swap_node({x=p_top.x, y=p_top.y, z=p_top.z+1}, biome_lib.air)
- if biome.delete_above_surround then
- minetest.swap_node({x=p_top.x-1, y=p_top.y, z=p_top.z}, biome_lib.air)
- minetest.swap_node({x=p_top.x+1, y=p_top.y, z=p_top.z}, biome_lib.air)
- minetest.swap_node({x=p_top.x, y=p_top.y, z=p_top.z-1}, biome_lib.air)
- minetest.swap_node({x=p_top.x, y=p_top.y, z=p_top.z+1}, biome_lib.air)
+ minetest.swap_node({x=p_top.x-1, y=p_top.y+1, z=p_top.z}, biome_lib.air)
+ minetest.swap_node({x=p_top.x+1, y=p_top.y+1, z=p_top.z}, biome_lib.air)
+ minetest.swap_node({x=p_top.x, y=p_top.y+1, z=p_top.z-1}, biome_lib.air)
+ minetest.swap_node({x=p_top.x, y=p_top.y+1, z=p_top.z+1}, biome_lib.air)
+ end
- minetest.swap_node({x=p_top.x-1, y=p_top.y+1, z=p_top.z}, biome_lib.air)
- minetest.swap_node({x=p_top.x+1, y=p_top.y+1, z=p_top.z}, biome_lib.air)
- minetest.swap_node({x=p_top.x, y=p_top.y+1, z=p_top.z-1}, biome_lib.air)
- minetest.swap_node({x=p_top.x, y=p_top.y+1, z=p_top.z+1}, biome_lib.air)
- end
+ if biome.spawn_replace_node then
+ minetest.swap_node(pos, biome_lib.air)
+ end
- if biome.spawn_replace_node then
- minetest.swap_node(pos, biome_lib.air)
- end
+ local objtype = type(nodes_or_function_or_model)
- local objtype = type(nodes_or_function_or_model)
-
- if objtype == "table" then
- if nodes_or_function_or_model.axiom then
- biome_lib:generate_tree(p_top, nodes_or_function_or_model)
- spawned = true
- else
- local fdir = nil
- if biome.random_facedir then
- fdir = math.random(biome.random_facedir[1], biome.random_facedir[2])
- end
- minetest.swap_node(p_top, { name = nodes_or_function_or_model[math.random(#nodes_or_function_or_model)], param2 = fdir })
- spawned = true
- end
- elseif objtype == "string" and
- minetest.registered_nodes[nodes_or_function_or_model] then
+ if objtype == "table" then
+ if nodes_or_function_or_model.axiom then
+ biome_lib:generate_tree(p_top, nodes_or_function_or_model)
+ spawned = true
+ else
local fdir = nil
if biome.random_facedir then
fdir = math.random(biome.random_facedir[1], biome.random_facedir[2])
end
- minetest.swap_node(p_top, { name = nodes_or_function_or_model, param2 = fdir })
- spawned = true
- elseif objtype == "function" then
- nodes_or_function_or_model(pos)
- spawned = true
- elseif objtype == "string" and pcall(loadstring(("return %s(...)"):
- format(nodes_or_function_or_model)),pos) then
+ minetest.swap_node(p_top, { name = nodes_or_function_or_model[math.random(#nodes_or_function_or_model)], param2 = fdir })
spawned = true
- else
- biome_lib:dbg("Warning: Ignored invalid definition for object "..dump(nodes_or_function_or_model).." that was pointed at {"..dump(pos).."}")
end
+ elseif objtype == "string" and
+ minetest.registered_nodes[nodes_or_function_or_model] then
+ local fdir = nil
+ if biome.random_facedir then
+ fdir = math.random(biome.random_facedir[1], biome.random_facedir[2])
+ end
+ minetest.swap_node(p_top, { name = nodes_or_function_or_model, param2 = fdir })
+ spawned = true
+ elseif objtype == "function" then
+ nodes_or_function_or_model(pos)
+ spawned = true
+ elseif objtype == "string" and pcall(loadstring(("return %s(...)"):
+ format(nodes_or_function_or_model)),pos) then
+ spawned = true
else
- tries = tries + 1
+ biome_lib:dbg("Warning: Ignored invalid definition for object "..dump(nodes_or_function_or_model).." that was pointed at {"..dump(pos).."}")
end
+ else
+ tries = tries + 1
end
end
end
@@ -333,51 +395,52 @@ end
-- a surface during the initial map read stage.
function biome_lib:generate_block_with_air_checking()
- if #biome_lib.blocklist_aircheck > 0 then
+ if #biome_lib.blocklist_aircheck == 0 then
+ return
+ end
- local minp = biome_lib.blocklist_aircheck[1][1]
- local maxp = biome_lib.blocklist_aircheck[1][2]
+ local minp = biome_lib.blocklist_aircheck[1][1]
+ local maxp = biome_lib.blocklist_aircheck[1][2]
- -- use the block hash as a unique key into the surface nodes
- -- tables, so that we can write the tables thread-safely.
+ -- use the block hash as a unique key into the surface nodes
+ -- tables, so that we can write the tables thread-safely.
- local blockhash = minetest.hash_node_position(minp)
+ local blockhash = minetest.hash_node_position(minp)
- if not biome_lib.surface_nodes_aircheck.blockhash then
+ if not biome_lib.surface_nodes_aircheck.blockhash then
- if type(minetest.find_nodes_in_area_under_air) == "function" then -- use newer API call
- biome_lib.surface_nodes_aircheck.blockhash =
- minetest.find_nodes_in_area_under_air(minp, maxp, biome_lib.surfaceslist_aircheck)
- else
- local search_area = minetest.find_nodes_in_area(minp, maxp, biome_lib.surfaceslist_aircheck)
+ if type(minetest.find_nodes_in_area_under_air) == "function" then -- use newer API call
+ biome_lib.surface_nodes_aircheck.blockhash =
+ minetest.find_nodes_in_area_under_air(minp, maxp, biome_lib.surfaceslist_aircheck)
+ else
+ local search_area = minetest.find_nodes_in_area(minp, maxp, biome_lib.surfaceslist_aircheck)
- -- search the generated block for air-bounded surfaces the slow way.
+ -- search the generated block for air-bounded surfaces the slow way.
- biome_lib.surface_nodes_aircheck.blockhash = {}
+ biome_lib.surface_nodes_aircheck.blockhash = {}
- for i = 1, #search_area do
- local pos = search_area[i]
- local p_top = { x=pos.x, y=pos.y+1, z=pos.z }
- if minetest.get_node(p_top).name == "air" then
- biome_lib.surface_nodes_aircheck.blockhash[#biome_lib.surface_nodes_aircheck.blockhash + 1] = pos
- end
+ for i = 1, #search_area do
+ local pos = search_area[i]
+ local p_top = { x=pos.x, y=pos.y+1, z=pos.z }
+ if minetest.get_node(p_top).name == "air" then
+ biome_lib.surface_nodes_aircheck.blockhash[#biome_lib.surface_nodes_aircheck.blockhash + 1] = pos
end
end
- biome_lib.actioncount_aircheck.blockhash = 1
+ end
+ biome_lib.actioncount_aircheck.blockhash = 1
+ else
+ if biome_lib.actioncount_aircheck.blockhash <= #biome_lib.actionslist_aircheck then
+ -- [1] is biome, [2] is node/function/model
+ biome_lib:populate_surfaces(
+ biome_lib.actionslist_aircheck[biome_lib.actioncount_aircheck.blockhash][1],
+ biome_lib.actionslist_aircheck[biome_lib.actioncount_aircheck.blockhash][2],
+ biome_lib.surface_nodes_aircheck.blockhash, true)
+ biome_lib.actioncount_aircheck.blockhash = biome_lib.actioncount_aircheck.blockhash + 1
else
- if biome_lib.actioncount_aircheck.blockhash <= #biome_lib.actionslist_aircheck then
- -- [1] is biome, [2] is node/function/model
- biome_lib:populate_surfaces(
- biome_lib.actionslist_aircheck[biome_lib.actioncount_aircheck.blockhash][1],
- biome_lib.actionslist_aircheck[biome_lib.actioncount_aircheck.blockhash][2],
- biome_lib.surface_nodes_aircheck.blockhash, true)
- biome_lib.actioncount_aircheck.blockhash = biome_lib.actioncount_aircheck.blockhash + 1
- else
- if biome_lib.surface_nodes_aircheck.blockhash then
- table.remove(biome_lib.blocklist_aircheck, 1)
- biome_lib.surface_nodes_aircheck.blockhash = nil
- end
+ if biome_lib.surface_nodes_aircheck.blockhash then
+ table.remove(biome_lib.blocklist_aircheck, 1)
+ biome_lib.surface_nodes_aircheck.blockhash = nil
end
end
end
@@ -387,66 +450,60 @@ end
-- checking for air during the initial map read stage.
function biome_lib:generate_block_no_aircheck()
- if #biome_lib.blocklist_no_aircheck > 0 then
+ if #biome_lib.blocklist_no_aircheck == 0 then
+ return
+ end
- local minp = biome_lib.blocklist_no_aircheck[1][1]
- local maxp = biome_lib.blocklist_no_aircheck[1][2]
+ local minp = biome_lib.blocklist_no_aircheck[1][1]
+ local maxp = biome_lib.blocklist_no_aircheck[1][2]
- local blockhash = minetest.hash_node_position(minp)
+ local blockhash = minetest.hash_node_position(minp)
- if not biome_lib.surface_nodes_no_aircheck.blockhash then
+ if not biome_lib.surface_nodes_no_aircheck.blockhash then
- -- directly read the block to be searched into the chunk cache
+ -- directly read the block to be searched into the chunk cache
- biome_lib.surface_nodes_no_aircheck.blockhash =
- minetest.find_nodes_in_area(minp, maxp, biome_lib.surfaceslist_no_aircheck)
- biome_lib.actioncount_no_aircheck.blockhash = 1
+ biome_lib.surface_nodes_no_aircheck.blockhash =
+ minetest.find_nodes_in_area(minp, maxp, biome_lib.surfaceslist_no_aircheck)
+ biome_lib.actioncount_no_aircheck.blockhash = 1
+ else
+ if biome_lib.actioncount_no_aircheck.blockhash <= #biome_lib.actionslist_no_aircheck then
+ biome_lib:populate_surfaces(
+ biome_lib.actionslist_no_aircheck[biome_lib.actioncount_no_aircheck.blockhash][1],
+ biome_lib.actionslist_no_aircheck[biome_lib.actioncount_no_aircheck.blockhash][2],
+ biome_lib.surface_nodes_no_aircheck.blockhash, false)
+ biome_lib.actioncount_no_aircheck.blockhash = biome_lib.actioncount_no_aircheck.blockhash + 1
else
- if biome_lib.actioncount_no_aircheck.blockhash <= #biome_lib.actionslist_no_aircheck then
- biome_lib:populate_surfaces(
- biome_lib.actionslist_no_aircheck[biome_lib.actioncount_no_aircheck.blockhash][1],
- biome_lib.actionslist_no_aircheck[biome_lib.actioncount_no_aircheck.blockhash][2],
- biome_lib.surface_nodes_no_aircheck.blockhash, false)
- biome_lib.actioncount_no_aircheck.blockhash = biome_lib.actioncount_no_aircheck.blockhash + 1
- else
- if biome_lib.surface_nodes_no_aircheck.blockhash then
- table.remove(biome_lib.blocklist_no_aircheck, 1)
- biome_lib.surface_nodes_no_aircheck.blockhash = nil
- end
+ if biome_lib.surface_nodes_no_aircheck.blockhash then
+ table.remove(biome_lib.blocklist_no_aircheck, 1)
+ biome_lib.surface_nodes_no_aircheck.blockhash = nil
end
end
end
end
--- "Record" the chunks being generated by the core mapgen
-
-minetest.register_on_generated(function(minp, maxp, blockseed)
- biome_lib.blocklist_aircheck[#biome_lib.blocklist_aircheck + 1] = { minp, maxp }
-end)
-
-minetest.register_on_generated(function(minp, maxp, blockseed)
- biome_lib.blocklist_no_aircheck[#biome_lib.blocklist_no_aircheck + 1] = { minp, maxp }
-end)
-
-- "Play" them back, populating them with new stuff in the process
+local step_duration = tonumber(minetest.settings:get("dedicated_server_step"))
minetest.register_globalstep(function(dtime)
- if dtime < 0.2 -- don't attempt to populate if lag is already too high
- and math.random(100) <= biome_lib.queue_run_ratio
- and (#biome_lib.blocklist_aircheck > 0 or #biome_lib.blocklist_no_aircheck > 0) then
- biome_lib.globalstep_start_time = minetest.get_us_time()
- biome_lib.globalstep_runtime = 0
- while (#biome_lib.blocklist_aircheck > 0 or #biome_lib.blocklist_no_aircheck > 0)
- and biome_lib.globalstep_runtime < 200000 do -- 0.2 seconds, in uS.
- if #biome_lib.blocklist_aircheck > 0 then
- biome_lib:generate_block_with_air_checking()
- end
- if #biome_lib.blocklist_no_aircheck > 0 then
- biome_lib:generate_block_no_aircheck()
- end
- biome_lib.globalstep_runtime = minetest.get_us_time() - biome_lib.globalstep_start_time
+ if dtime >= step_duration + 0.1 -- don't attempt to populate if lag is already too high
+ or math.random(100) > biome_lib.queue_run_ratio
+ or (#biome_lib.blocklist_aircheck == 0 and #biome_lib.blocklist_no_aircheck == 0) then
+ return
+ end
+
+ biome_lib.globalstep_start_time = minetest.get_us_time()
+ biome_lib.globalstep_runtime = 0
+ while (#biome_lib.blocklist_aircheck > 0 or #biome_lib.blocklist_no_aircheck > 0)
+ and biome_lib.globalstep_runtime < 200000 do -- 0.2 seconds, in uS.
+ if #biome_lib.blocklist_aircheck > 0 then
+ biome_lib:generate_block_with_air_checking()
end
+ if #biome_lib.blocklist_no_aircheck > 0 then
+ biome_lib:generate_block_no_aircheck()
+ end
+ biome_lib.globalstep_runtime = minetest.get_us_time() - biome_lib.globalstep_start_time
end
end)
@@ -454,24 +511,26 @@ end)
-- to prevent unpopulated map areas
minetest.register_on_shutdown(function()
- if #biome_lib.blocklist_aircheck > 0 then
- print("[biome_lib] Stand by, playing out the rest of the aircheck mapblock log")
- print("(there are "..#biome_lib.blocklist_aircheck.." entries)...")
- while true do
- biome_lib:generate_block_with_air_checking(0.1)
- if #biome_lib.blocklist_aircheck == 0 then return end
- end
+ if #biome_lib.blocklist_aircheck == 0 then
+ return
+ end
+
+ print("[biome_lib] Stand by, playing out the rest of the aircheck mapblock log")
+ print("(there are "..#biome_lib.blocklist_aircheck.." entries)...")
+ while #biome_lib.blocklist_aircheck > 0 do
+ biome_lib:generate_block_with_air_checking(0.1)
end
end)
minetest.register_on_shutdown(function()
- if #biome_lib.blocklist_no_aircheck > 0 then
- print("[biome_lib] Stand by, playing out the rest of the no-aircheck mapblock log")
- print("(there are "..#biome_lib.blocklist_no_aircheck.." entries)...")
- while true do
- biome_lib:generate_block_no_aircheck(0.1)
- if #biome_lib.blocklist_no_aircheck == 0 then return end
- end
+ if #biome_lib.blocklist_aircheck == 0 then
+ return
+ end
+
+ print("[biome_lib] Stand by, playing out the rest of the no-aircheck mapblock log")
+ print("(there are "..#biome_lib.blocklist_no_aircheck.." entries)...")
+ while #biome_lib.blocklist_no_aircheck > 0 do
+ biome_lib:generate_block_no_aircheck(0.1)
end
end)
@@ -519,127 +578,99 @@ function biome_lib:spawn_on_surfaces(sd,sp,sr,sc,ss,sa)
local p_top = { x = pos.x, y = pos.y + 1, z = pos.z }
local n_top = minetest.get_node(p_top)
local perlin_fertile_area = minetest.get_perlin(biome.seed_diff, perlin_octaves, perlin_persistence, perlin_scale)
- local noise1 = perlin_fertile_area:get2d({x=p_top.x, y=p_top.z})
- local noise2 = biome_lib.perlin_temperature:get2d({x=p_top.x, y=p_top.z})
- local noise3 = biome_lib.perlin_humidity:get2d({x=p_top.x+150, y=p_top.z+50})
- if noise1 > biome.plantlife_limit
- and noise2 <= biome.temp_min
- and noise2 >= biome.temp_max
- and noise3 <= biome.humidity_min
- and noise3 >= biome.humidity_max
- and biome_lib:is_node_loaded(p_top) then
- local n_light = minetest.get_node_light(p_top, nil)
- if not (biome.avoid_nodes and biome.avoid_radius and minetest.find_node_near(p_top, biome.avoid_radius + math.random(-1.5,2), biome.avoid_nodes))
- and n_light >= biome.light_min
- and n_light <= biome.light_max
- and (not(biome.neighbors and biome.ncount) or #(minetest.find_nodes_in_area({x=pos.x-1, y=pos.y, z=pos.z-1}, {x=pos.x+1, y=pos.y, z=pos.z+1}, biome.neighbors)) > biome.ncount )
- and (not(biome.near_nodes and biome.near_nodes_count and biome.near_nodes_size) or #(minetest.find_nodes_in_area({x=pos.x-biome.near_nodes_size, y=pos.y-biome.near_nodes_vertical, z=pos.z-biome.near_nodes_size}, {x=pos.x+biome.near_nodes_size, y=pos.y+biome.near_nodes_vertical, z=pos.z+biome.near_nodes_size}, biome.near_nodes)) >= biome.near_nodes_count)
- and (not(biome.air_count and biome.air_size) or #(minetest.find_nodes_in_area({x=p_top.x-biome.air_size, y=p_top.y, z=p_top.z-biome.air_size}, {x=p_top.x+biome.air_size, y=p_top.y, z=p_top.z+biome.air_size}, "air")) >= biome.air_count)
- and pos.y >= biome.min_elevation
- and pos.y <= biome.max_elevation
- then
- local walldir = biome_lib:find_adjacent_wall(p_top, biome.verticals_list, biome.choose_random_wall)
- if biome.alt_wallnode and walldir then
- if n_top.name == "air" then
- minetest.swap_node(p_top, { name = biome.alt_wallnode, param2 = walldir })
- end
- else
- local currentsurface = minetest.get_node(pos).name
- if currentsurface ~= "default:water_source"
- or (currentsurface == "default:water_source" and #(minetest.find_nodes_in_area({x=pos.x, y=pos.y-biome.depth_max-1, z=pos.z}, {x=pos.x, y=pos.y, z=pos.z}, {"default:dirt", "default:dirt_with_grass", "default:sand"})) > 0 )
- then
- local rnd = math.random(1, biome.spawn_plants_count)
- local plant_to_spawn = biome.spawn_plants[rnd]
- local fdir = biome.facedir
- if biome.random_facedir then
- fdir = math.random(biome.random_facedir[1],biome.random_facedir[2])
- end
- if type(biome.spawn_plants) == "string" then
- assert(loadstring(biome.spawn_plants.."(...)"))(pos)
- elseif not biome.spawn_on_side and not biome.spawn_on_bottom and not biome.spawn_replace_node then
- if n_top.name == "air" then
- minetest.swap_node(p_top, { name = plant_to_spawn, param2 = fdir })
- end
- elseif biome.spawn_replace_node then
- minetest.swap_node(pos, { name = plant_to_spawn, param2 = fdir })
-
- elseif biome.spawn_on_side then
- local onside = biome_lib:find_open_side(pos)
- if onside then
- minetest.swap_node(onside.newpos, { name = plant_to_spawn, param2 = onside.facedir })
- end
- elseif biome.spawn_on_bottom then
- if minetest.get_node({x=pos.x, y=pos.y-1, z=pos.z}).name == "air" then
- minetest.swap_node({x=pos.x, y=pos.y-1, z=pos.z}, { name = plant_to_spawn, param2 = fdir} )
- end
- end
- end
- end
- end
- end
- end
- })
-end
--- The growing ABM
+ local fertility, temperature, humidity = get_biome_data(pos, perlin_fertile_area)
-function biome_lib:grow_plants(opts)
+ local pos_biome_ok = pos.y >= biome.min_elevation and pos.y <= biome.max_elevation
+ and fertility > biome.plantlife_limit
+ and temperature <= biome.temp_min and temperature >= biome.temp_max
+ and humidity <= biome.humidity_min and humidity >= biome.humidity_max
+ and biome_lib:is_node_loaded(p_top)
- local options = opts
+ if not pos_biome_ok then
+ return -- Outside of biome
+ end
- options.height_limit = options.height_limit or 5
- options.ground_nodes = options.ground_nodes or { "default:dirt_with_grass" }
- options.grow_nodes = options.grow_nodes or { "default:dirt_with_grass" }
- options.seed_diff = options.seed_diff or 0
+ local n_light = minetest.get_node_light(p_top, nil)
+ if n_light < biome.light_min or n_light > biome.light_max then
+ return -- Too dark or too bright
+ end
- local n
+ if biome.avoid_nodes and biome.avoid_radius and minetest.find_node_near(
+ p_top, biome.avoid_radius + math.random(-1.5,2), biome.avoid_nodes) then
+ return -- Nodes to avoid are nearby
+ end
- if type(options.grow_plant) == "table" then
- n = "multi: "..options.grow_plant[1]..", ..."
- else
- n = options.grow_plant
- end
+ if biome.neighbors and biome.ncount and
+ #minetest.find_nodes_in_area(
+ {x=pos.x-1, y=pos.y, z=pos.z-1},
+ {x=pos.x+1, y=pos.y, z=pos.z+1},
+ biome.neighbors
+ ) <= biome.ncount then
+ return -- Near neighbour nodes are not present
+ end
- options.label = options.label or "biome_lib grow_plants(): "..n
+ local NEAR_DST = biome.near_nodes_size
+ if biome.near_nodes and biome.near_nodes_count and biome.near_nodes_size and
+ #minetest.find_nodes_in_area(
+ {x=pos.x-NEAR_DST, y=pos.y-biome.near_nodes_vertical, z=pos.z-NEAR_DST},
+ {x=pos.x+NEAR_DST, y=pos.y+biome.near_nodes_vertical, z=pos.z+NEAR_DST},
+ biome.near_nodes
+ ) < biome.near_nodes_count then
+ return -- Far neighbour nodes are not present
+ end
- if options.grow_delay*time_scale >= 1 then
- options.interval = options.grow_delay*time_scale
- else
- options.interval = 1
- end
+ if (biome.air_count and biome.air_size) and
+ #minetest.find_nodes_in_area(
+ {x=p_top.x-biome.air_size, y=p_top.y, z=p_top.z-biome.air_size},
+ {x=p_top.x+biome.air_size, y=p_top.y, z=p_top.z+biome.air_size},
+ "air"
+ ) < biome.air_count then
+ return -- Not enough air
+ end
- minetest.register_abm({
- nodenames = { options.grow_plant },
- interval = options.interval,
- chance = options.grow_chance,
- label = options.label,
- action = function(pos, node, active_object_count, active_object_count_wider)
- local p_top = {x=pos.x, y=pos.y+1, z=pos.z}
- local p_bot = {x=pos.x, y=pos.y-1, z=pos.z}
- local n_top = minetest.get_node(p_top)
- local n_bot = minetest.get_node(p_bot)
- local root_node = minetest.get_node({x=pos.x, y=pos.y-options.height_limit, z=pos.z})
- local walldir = nil
- if options.need_wall and options.verticals_list then
- walldir = biome_lib:find_adjacent_wall(p_top, options.verticals_list, options.choose_random_wall)
+ local walldir = biome_lib:find_adjacent_wall(p_top, biome.verticals_list, biome.choose_random_wall)
+ if biome.alt_wallnode and walldir then
+ if n_top.name == "air" then
+ minetest.swap_node(p_top, { name = biome.alt_wallnode, param2 = walldir })
+ end
+ return
end
- if (n_top.name == "air" or n_top.name == "default:snow")
- and (not options.need_wall or (options.need_wall and walldir)) then
- -- corner case for changing short junglegrass
- -- to dry shrub in desert
- if n_bot.name == options.dry_early_node and options.grow_plant == "junglegrass:short" then
- minetest.swap_node(pos, { name = "default:dry_shrub" })
-
- elseif options.grow_vertically and walldir then
- if biome_lib:search_downward(pos, options.height_limit, options.ground_nodes) then
- minetest.swap_node(p_top, { name = options.grow_plant, param2 = walldir})
- end
- elseif not options.grow_result and not options.grow_function then
- minetest.swap_node(pos, biome_lib.air)
+ local currentsurface = minetest.get_node(pos).name
- else
- biome_lib:replace_object(pos, options.grow_result, options.grow_function, options.facedir, options.seed_diff)
+ if currentsurface == "default:water_source" and
+ #minetest.find_nodes_in_area(
+ {x=pos.x, y=pos.y-biome.depth_max-1, z=pos.z},
+ vector.new(pos),
+ {"default:dirt", "default:dirt_with_grass", "default:sand"}
+ ) == 0 then
+ return -- On water but no ground nearby
+ end
+
+ local rnd = math.random(1, biome.spawn_plants_count)
+ local plant_to_spawn = biome.spawn_plants[rnd]
+ local fdir = biome.facedir
+ if biome.random_facedir then
+ fdir = math.random(biome.random_facedir[1],biome.random_facedir[2])
+ end
+ if type(biome.spawn_plants) == "string" then
+ assert(loadstring(biome.spawn_plants.."(...)"))(pos)
+ elseif not biome.spawn_on_side and not biome.spawn_on_bottom and not biome.spawn_replace_node then
+ if n_top.name == "air" then
+ minetest.swap_node(p_top, { name = plant_to_spawn, param2 = fdir })
+ end
+ elseif biome.spawn_replace_node then
+ minetest.swap_node(pos, { name = plant_to_spawn, param2 = fdir })
+
+ elseif biome.spawn_on_side then
+ local onside = biome_lib:find_open_side(pos)
+ if onside then
+ minetest.swap_node(onside.newpos, { name = plant_to_spawn, param2 = onside.facedir })
+ end
+ elseif biome.spawn_on_bottom then
+ if minetest.get_node({x=pos.x, y=pos.y-1, z=pos.z}).name == "air" then
+ minetest.swap_node({x=pos.x, y=pos.y-1, z=pos.z}, { name = plant_to_spawn, param2 = fdir} )
end
end
end
@@ -657,15 +688,13 @@ function biome_lib:replace_object(pos, replacement, grow_function, walldir, seed
return
elseif growtype == "function" then
local perlin_fertile_area = minetest.get_perlin(seeddiff, perlin_octaves, perlin_persistence, perlin_scale)
- local noise1 = perlin_fertile_area:get2d({x=pos.x, y=pos.z})
- local noise2 = biome_lib.perlin_temperature:get2d({x=pos.x, y=pos.z})
- grow_function(pos,noise1,noise2,walldir)
+ local fertility, temperature, _ = get_biome_data(pos, perlin_fertile_area)
+ grow_function(pos, fertility, temperature, walldir)
return
elseif growtype == "string" then
local perlin_fertile_area = minetest.get_perlin(seeddiff, perlin_octaves, perlin_persistence, perlin_scale)
- local noise1 = perlin_fertile_area:get2d({x=pos.x, y=pos.z})
- local noise2 = biome_lib.perlin_temperature:get2d({x=pos.x, y=pos.z})
- assert(loadstring(grow_function.."(...)"))(pos,noise1,noise2,walldir)
+ local fertility, temperature, _ = get_biome_data(pos, perlin_fertile_area)
+ assert(loadstring(grow_function.."(...)"))(pos, fertility, temperature, walldir)
return
elseif growtype == "nil" then
minetest.swap_node(pos, { name = replacement, param2 = walldir})
@@ -675,71 +704,11 @@ function biome_lib:replace_object(pos, replacement, grow_function, walldir, seed
end
end
--- function to decide if a node has a wall that's in verticals_list{}
--- returns wall direction of valid node, or nil if invalid.
-
-function biome_lib:find_adjacent_wall(pos, verticals, randomflag)
- local verts = dump(verticals)
- if randomflag then
- local walltab = {}
-
- if string.find(verts, minetest.get_node({ x=pos.x-1, y=pos.y, z=pos.z }).name) then walltab[#walltab + 1] = 3 end
- if string.find(verts, minetest.get_node({ x=pos.x+1, y=pos.y, z=pos.z }).name) then walltab[#walltab + 1] = 2 end
- if string.find(verts, minetest.get_node({ x=pos.x , y=pos.y, z=pos.z-1 }).name) then walltab[#walltab + 1] = 5 end
- if string.find(verts, minetest.get_node({ x=pos.x , y=pos.y, z=pos.z+1 }).name) then walltab[#walltab + 1] = 4 end
-
- if #walltab > 0 then return walltab[math.random(1, #walltab)] end
-
- else
- if string.find(verts, minetest.get_node({ x=pos.x-1, y=pos.y, z=pos.z }).name) then return 3 end
- if string.find(verts, minetest.get_node({ x=pos.x+1, y=pos.y, z=pos.z }).name) then return 2 end
- if string.find(verts, minetest.get_node({ x=pos.x , y=pos.y, z=pos.z-1 }).name) then return 5 end
- if string.find(verts, minetest.get_node({ x=pos.x , y=pos.y, z=pos.z+1 }).name) then return 4 end
- end
- return nil
-end
-
--- Function to search downward from the given position, looking for the first
--- node that matches the ground table. Returns the new position, or nil if
--- height limit is exceeded before finding it.
-function biome_lib:search_downward(pos, heightlimit, ground)
- for i = 0, heightlimit do
- if string.find(dump(ground), minetest.get_node({x=pos.x, y=pos.y-i, z = pos.z}).name) then
- return {x=pos.x, y=pos.y-i, z = pos.z}
- end
- end
- return false
-end
+dofile(biome_lib.modpath .. "/search_functions.lua")
+assert(loadfile(biome_lib.modpath .. "/growth.lua"))(time_scale)
-function biome_lib:find_open_side(pos)
- if minetest.get_node({ x=pos.x-1, y=pos.y, z=pos.z }).name == "air" then
- return {newpos = { x=pos.x-1, y=pos.y, z=pos.z }, facedir = 2}
- end
- if minetest.get_node({ x=pos.x+1, y=pos.y, z=pos.z }).name == "air" then
- return {newpos = { x=pos.x+1, y=pos.y, z=pos.z }, facedir = 3}
- end
- if minetest.get_node({ x=pos.x, y=pos.y, z=pos.z-1 }).name == "air" then
- return {newpos = { x=pos.x, y=pos.y, z=pos.z-1 }, facedir = 4}
- end
- if minetest.get_node({ x=pos.x, y=pos.y, z=pos.z+1 }).name == "air" then
- return {newpos = { x=pos.x, y=pos.y, z=pos.z+1 }, facedir = 5}
- end
- return nil
-end
-
--- spawn_tree() on generate is routed through here so that other mods can hook
--- into it.
-function biome_lib:generate_tree(pos, nodes_or_function_or_model)
- minetest.spawn_tree(pos, nodes_or_function_or_model)
-end
-
--- and this one's for the call used in the growing code
-
-function biome_lib:grow_tree(pos, nodes_or_function_or_model)
- minetest.spawn_tree(pos, nodes_or_function_or_model)
-end
-- Check for infinite stacks
diff --git a/biome_lib/search_functions.lua b/biome_lib/search_functions.lua
new file mode 100644
index 0000000..d665b5f
--- /dev/null
+++ b/biome_lib/search_functions.lua
@@ -0,0 +1,60 @@
+
+-- function to decide if a node has a wall that's in verticals_list{}
+-- returns wall direction of valid node, or nil if invalid.
+
+function biome_lib:find_adjacent_wall(pos, verticals, randomflag)
+ local verts = dump(verticals)
+ if randomflag then
+ local walltab = {}
+
+ if string.find(verts, minetest.get_node({ x=pos.x-1, y=pos.y, z=pos.z }).name) then walltab[#walltab + 1] = 3 end
+ if string.find(verts, minetest.get_node({ x=pos.x+1, y=pos.y, z=pos.z }).name) then walltab[#walltab + 1] = 2 end
+ if string.find(verts, minetest.get_node({ x=pos.x , y=pos.y, z=pos.z-1 }).name) then walltab[#walltab + 1] = 5 end
+ if string.find(verts, minetest.get_node({ x=pos.x , y=pos.y, z=pos.z+1 }).name) then walltab[#walltab + 1] = 4 end
+
+ if #walltab > 0 then return walltab[math.random(1, #walltab)] end
+
+ else
+ if string.find(verts, minetest.get_node({ x=pos.x-1, y=pos.y, z=pos.z }).name) then return 3 end
+ if string.find(verts, minetest.get_node({ x=pos.x+1, y=pos.y, z=pos.z }).name) then return 2 end
+ if string.find(verts, minetest.get_node({ x=pos.x , y=pos.y, z=pos.z-1 }).name) then return 5 end
+ if string.find(verts, minetest.get_node({ x=pos.x , y=pos.y, z=pos.z+1 }).name) then return 4 end
+ end
+ return nil
+end
+
+-- Function to search downward from the given position, looking for the first
+-- node that matches the ground table. Returns the new position, or nil if
+-- height limit is exceeded before finding it.
+
+function biome_lib:search_downward(pos, heightlimit, ground)
+ for i = 0, heightlimit do
+ if string.find(dump(ground), minetest.get_node({x=pos.x, y=pos.y-i, z = pos.z}).name) then
+ return {x=pos.x, y=pos.y-i, z = pos.z}
+ end
+ end
+ return false
+end
+
+function biome_lib:find_open_side(pos)
+ if minetest.get_node({ x=pos.x-1, y=pos.y, z=pos.z }).name == "air" then
+ return {newpos = { x=pos.x-1, y=pos.y, z=pos.z }, facedir = 2}
+ end
+ if minetest.get_node({ x=pos.x+1, y=pos.y, z=pos.z }).name == "air" then
+ return {newpos = { x=pos.x+1, y=pos.y, z=pos.z }, facedir = 3}
+ end
+ if minetest.get_node({ x=pos.x, y=pos.y, z=pos.z-1 }).name == "air" then
+ return {newpos = { x=pos.x, y=pos.y, z=pos.z-1 }, facedir = 4}
+ end
+ if minetest.get_node({ x=pos.x, y=pos.y, z=pos.z+1 }).name == "air" then
+ return {newpos = { x=pos.x, y=pos.y, z=pos.z+1 }, facedir = 5}
+ end
+ return nil
+end
+
+-- "Record" the chunks being generated by the core mapgen
+
+minetest.register_on_generated(function(minp, maxp, blockseed)
+ biome_lib.blocklist_aircheck[#biome_lib.blocklist_aircheck + 1] = { minp, maxp }
+ biome_lib.blocklist_no_aircheck[#biome_lib.blocklist_no_aircheck + 1] = { minp, maxp }
+end)