1
0
mirror of https://github.com/mt-mods/biome_lib.git synced 2025-06-29 14:50:49 +02:00

18 Commits

Author SHA1 Message Date
bf2ac2ea57 don't nil-out the recheck list, just empty it. 2021-04-16 13:06:24 -04:00
6342a16b0a Reign-in the default on-generated limit from +/- 31k to -16/+48m
since nothing much is normally found outside that range anyway

only enqueue blocks that are within that range, or within
the range specfied by all of the mods that make generate_plant() calls,
whichever covers more volume.
2021-04-16 13:02:54 -04:00
c6cd524f62 fix reporting of log sizes during shutdown 2021-04-16 12:06:52 -04:00
2dbacae561 remove mapblocks from the queue early if they have no surfaces to work on
(sadly can't be done for blocks in the deferred queue until
they come out of "idle")
2021-04-16 12:02:13 -04:00
f165434a84 change the queue ratio config setting
to avoid breaking old configs
also increase the default amount of work done per tick.
2021-04-16 10:41:38 -04:00
d6cba18844 add a mention in the readme about the mod's config settings 2021-04-16 10:39:17 -04:00
f003f19998 add a proper settingtypes.txt 2021-04-10 06:01:01 -04:00
d06ab90e01 allow re-check-log entries to time out gradually rather than
having to go all at once.  This purges the log sooner than before,
but without damaging the mapgen results.
2021-04-09 13:26:42 -04:00
ba46e6c05e Report the mod's progress and ETA
while purging the mapblock log at shutdown
2021-04-09 12:38:09 -04:00
ed0b23677d fix typo 2021-04-08 08:09:59 -04:00
3b35fc67c6 Periodically re-trigger the mapblock queue code if it's idle,
to give old, deferrred blocks a chance to time-out.  Needed
because if players aren't currently creating new terrain,
old blocks would never get processed, causing the block log
to only grow rather than eventually run dry (which could result
in very long shutdown times).
2021-04-08 06:33:43 -04:00
eabc053c05 If a block has to be re-checked, renew its timestamp 2021-04-07 09:12:57 -04:00
dd650da443 Allow old blocks to time-out after a while
(default 5 minutes).

Rationale: if a block is old enough, there's a very high probability
that the engine's done screwing around with its neighbors, so it's safe
to process.
2021-04-07 07:41:48 -04:00
0a34e3c7af rename debug variable and option for consistency
make global so it can be changed while running
2021-04-07 07:41:32 -04:00
07c2b1d9d4 move all settings at the top of the code
(some were scattered here and there)
2021-04-07 07:13:53 -04:00
1dc0febd8c print a message when the queue goes idle. 2021-04-07 05:26:31 -04:00
50f921a85a implement variable log levels
so that one need not see all the spammy stuff
if the only things of interest are e.g. warnings
2021-04-07 05:16:11 -04:00
6009f261c2 make sure that any block about to be scanned is definitely loaded (in
case the engine has unloaded the block because the player wandered off
for too long)
2021-04-07 04:55:57 -04:00
5 changed files with 247 additions and 116 deletions

55
API.txt
View File

@ -112,9 +112,9 @@ biome = {
depth_max = num, -- If the object spawns on top of a water source, the depth_max = num, -- If the object spawns on top of a water source, the
-- water must be at most this deep. Defaults to 1. -- water must be at most this deep. Defaults to 1.
min_elevation = num, -- Surface must be at this altitude or higher to min_elevation = num, -- Surface must be at this altitude or higher to
-- spawn at all. Defaults to -31000... -- spawn at all. Defaults to -16 meters.
max_elevation = num, -- ...but must be no higher than this altitude. max_elevation = num, -- Surface must be no higher than this altitude.
-- Defaults to +31000. -- Defaults to +48.
near_nodes = {table}, -- List of nodes that must be somewhere in the near_nodes = {table}, -- List of nodes that must be somewhere in the
-- vicinity in order for the plant to spawn. Can also -- vicinity in order for the plant to spawn. Can also
-- be a string with a single node name. If not -- be a string with a single node name. If not
@ -270,8 +270,8 @@ biome = {
depth = num, -- How deep/thick of a layer the spawned-on node must depth = num, -- How deep/thick of a layer the spawned-on node must
-- be. Typically used for water. -- be. Typically used for water.
min_elevation = num, -- Minimum elevation in meters/nodes. Defaults to min_elevation = num, -- Minimum elevation in meters/nodes. Defaults to
-- -31000 (unlimited). -- -16 meters.
max_elevation = num, -- Max elevation. Defaults to +31000 (unlimited). max_elevation = num, -- Max elevation. Defaults to +48m.
near_nodes = {table}, -- what nodes must be in the general vicinity of the near_nodes = {table}, -- what nodes must be in the general vicinity of the
-- object being spawned. -- object being spawned.
near_nodes_size = num, -- how wide of a search area to look for the nodes near_nodes_size = num, -- how wide of a search area to look for the nodes
@ -446,12 +446,22 @@ question is already loaded, or false if not.
===== =====
dbg(string) dbg(string, level)
This is a simple debug output function which takes one string parameter. It This is a simple debug output function which takes one string parameter. It
just checks if DEBUG is true and outputs the phrase "[Plantlife] " followed by just checks if DEBUG is true and outputs the phrase "[Plantlife] " followed by
the supplied string, via the print() function, if so. the supplied string, via the print() function, if so.
'level' is a number that, if supplied, dictates the lowest 'biome_lib_debug'
can be set to in minetest.conf for this message to be displayed. Both the
default log level and the default message level are 0, thus always showing the
supplied message.
Although it's not set in stone, a good practice is to use a level of 0 (or
just omit the value) for anything that generally important enough that it
ought always be shown, 1 for errors, 2 for warnings, 3 for info, 4 for verbose
spammy stuff.
===== =====
biome_lib:generate_tree(pos, treemodel) biome_lib:generate_tree(pos, treemodel)
biome_lib:grow_tree(pos, treemodel) biome_lib:grow_tree(pos, treemodel)
@ -597,34 +607,7 @@ Although this project was intended to be used with minetest_game, it can be
configured to work with something else instead. All you need to do is provide configured to work with something else instead. All you need to do is provide
the names of the nodes in your game you want biome_lib's internals to use. the names of the nodes in your game you want biome_lib's internals to use.
Put these settings in your game's minetest.conf (or your client's own config, See settingtypes.txt for a list. Any item listed there can be changed either
if desired). You'll need to set all of them. by adding it to your minetest.conf, or by using the "all settings" menu in
Minetest, whatever's appropriate for your particular setup.
biome_lib_default_grow_through_nodes
Comma-separated list of things that a spawned node is allowed to grow
through. Air is always added to whatever you specify.
Default: air, default:snow
biome_lib_default_water_nodes
Comma-separated list of nodes that should be treated as water for the sake
of looking for neighboring "wet" ground.
Default: default:water_source, default:water_flowing,
default:river_water_source, default:river_water_flowing
biome_lib_default_wet_surfaces
Comma-separated list of nodes that should be considered "wet" if one of
the aforementioned water nodes is nearby.
Default: default:dirt, default:dirt_with_grass, default:sand
biome_lib_default_grow_nodes
Comma-separated list of nodes that something must be sitting on to be
able to actively change from one thing to another (such as a sapling
growing into a tree), to be used for ALL growable nodes, if the calling
mod doesn't provide its own lists.
Default: "default:dirt_with_grass"
biome_lib_default_ground_nodes
Comma-separated list of nodes to use as the "root" of something that can
gradually climb up a wall, to be used for ALL such nodes, if the calling
mod doesn't provide its own lists.
Default: "default:dirt_with_grass"

View File

@ -25,4 +25,6 @@ It is primarily intended for mapgen v6, but it should work fine when used with m
* biome_lib:find_valid_wall() * biome_lib:find_valid_wall()
* biome_lib:is_node_loaded() * biome_lib:is_node_loaded()
For a complete description of these functions as well as several of the internal variables within the mod, [read the API.txt document](https://raw.githubusercontent.com/minetest-mods/biome_lib/master/API.txt) included in this package. For a complete description of these functions as well as several of the internal variables within the mod, see `API.txt`.
**Configuration:** This mod has several variables you can set in your `minetest.conf` to change things a bit, from the default nodes it uses, to the debug log level and the block queue behavior. For a list with complete descriptions, see `settingtypes.txt`.

223
init.lua
View File

@ -4,12 +4,28 @@
-- Splizard's snow mod. -- Splizard's snow mod.
-- --
biome_lib = {}
-- Boilerplate to support localized strings if intllib mod is installed.
local S
if minetest.global_exists("intllib") then
if intllib.make_gettext_pair then
S = intllib.make_gettext_pair()
else
S = intllib.Getter()
end
else
S = function(s) return s end
end
biome_lib.intllib = S
-- Various settings - most of these probably won't need to be changed -- Various settings - most of these probably won't need to be changed
biome_lib = {}
biome_lib.air = {name = "air"} biome_lib.air = {name = "air"}
biome_lib.block_log = {} biome_lib.block_log = {}
biome_lib.block_recheck_list = {}
biome_lib.run_block_recheck_list = false
biome_lib.actionslist_aircheck = {} biome_lib.actionslist_aircheck = {}
biome_lib.actionslist_no_aircheck = {} biome_lib.actionslist_no_aircheck = {}
@ -17,6 +33,10 @@ biome_lib.actionslist_no_aircheck = {}
biome_lib.surfaceslist_aircheck = {} biome_lib.surfaceslist_aircheck = {}
biome_lib.surfaceslist_no_aircheck = {} biome_lib.surfaceslist_no_aircheck = {}
-- the mapgen rarely creates useful surfaces outside this range, but mods can
-- still specify a wider range if needed.
biome_lib.mapgen_elevation_limit = { ["min"] = -16, ["max"] = 48 }
biome_lib.modpath = minetest.get_modpath("biome_lib") biome_lib.modpath = minetest.get_modpath("biome_lib")
local function tableize(s) local function tableize(s)
@ -54,27 +74,25 @@ biome_lib.default_wet_surfaces = c3 and tableize(c3) or {"default:dirt", "defaul
biome_lib.default_ground_nodes = c4 and tableize(c4) or {"default:dirt_with_grass"} biome_lib.default_ground_nodes = c4 and tableize(c4) or {"default:dirt_with_grass"}
biome_lib.default_grow_nodes = c5 and tableize(c5) or {"default:dirt_with_grass"} biome_lib.default_grow_nodes = c5 and tableize(c5) or {"default:dirt_with_grass"}
-- Boilerplate to support localized strings if intllib mod is installed. biome_lib.debug_log_level = tonumber(minetest.settings:get("biome_lib_debug_log_level")) or 0
local S
if minetest.global_exists("intllib") then
if intllib.make_gettext_pair then
S = intllib.make_gettext_pair()
else
S = intllib.Getter()
end
else
S = function(s) return s end
end
biome_lib.intllib = S
local DEBUG = minetest.settings:get_bool("biome_lib_debug", false) local rr = tonumber(minetest.settings:get("biome_lib_queue_ratio")) or -200
biome_lib.queue_ratio = 100 - rr
biome_lib.entries_per_step = math.max(-rr, 1)
function biome_lib:dbg(msg) -- the timer that manages the block timeout is in microseconds, but the timer
if DEBUG then -- that manages the queue wakeup call has to be in seconds, and works best if
print("[Biome Lib] "..msg) -- it takes a fraction of the block timeout interval.
minetest.log("verbose", "[Biome Lib] "..msg)
end local t = tonumber(minetest.settings:get("biome_lib_block_timeout")) or 300
end
biome_lib.block_timeout = t * 1000000
-- we don't want the wakeup function to trigger TOO often,
-- in case the user's block timeout setting is really low
biome_lib.block_queue_wakeup_time = math.min(t/2, math.max(20, t/10))
local time_speed = tonumber(minetest.settings:get("time_speed"))
biome_lib.plantlife_seed_diff = 329 -- needs to be global so other mods can see it biome_lib.plantlife_seed_diff = 329 -- needs to be global so other mods can see it
@ -93,7 +111,6 @@ local humidity_persistence = 0.5
local humidity_scale = 250 local humidity_scale = 250
local time_scale = 1 local time_scale = 1
local time_speed = tonumber(minetest.settings:get("time_speed"))
if time_speed and time_speed > 0 then if time_speed and time_speed > 0 then
time_scale = 72 / time_speed time_scale = 72 / time_speed
@ -106,6 +123,14 @@ biome_lib.perlin_humidity = PerlinNoise(humidity_seeddiff, humidity_octaves, hum
-- Local functions -- Local functions
function biome_lib.dbg(msg, level)
local l = tonumber(level) or 0
if biome_lib.debug_log_level >= l then
print("[Biome Lib] "..msg)
minetest.log("verbose", "[Biome Lib] "..msg)
end
end
local function get_biome_data(pos, perlin_fertile) local function get_biome_data(pos, perlin_fertile)
local fertility = perlin_fertile:get_2d({x=pos.x, y=pos.z}) local fertility = perlin_fertile:get_2d({x=pos.x, y=pos.z})
@ -132,8 +157,8 @@ end
function biome_lib:set_defaults(biome) function biome_lib:set_defaults(biome)
biome.seed_diff = biome.seed_diff or 0 biome.seed_diff = biome.seed_diff or 0
biome.min_elevation = biome.min_elevation or -31000 biome.min_elevation = biome.min_elevation or biome_lib.mapgen_elevation_limit.min
biome.max_elevation = biome.max_elevation or 31000 biome.max_elevation = biome.max_elevation or biome_lib.mapgen_elevation_limit.max
biome.temp_min = biome.temp_min or 1 biome.temp_min = biome.temp_min or 1
biome.temp_max = biome.temp_max or -1 biome.temp_max = biome.temp_max or -1
biome.humidity_min = biome.humidity_min or 1 biome.humidity_min = biome.humidity_min or 1
@ -176,17 +201,20 @@ function biome_lib:register_generate_plant(biomedef, nodes_or_function_or_model)
if type(nodes_or_function_or_model) == "string" if type(nodes_or_function_or_model) == "string"
and string.find(nodes_or_function_or_model, ":") and string.find(nodes_or_function_or_model, ":")
and not minetest.registered_nodes[nodes_or_function_or_model] then and not minetest.registered_nodes[nodes_or_function_or_model] then
biome_lib:dbg("Warning: Ignored registration for undefined spawn node: "..dump(nodes_or_function_or_model)) biome_lib.dbg("Warning: Ignored registration for undefined spawn node: "..dump(nodes_or_function_or_model), 2)
return return
end end
if type(nodes_or_function_or_model) == "string" if type(nodes_or_function_or_model) == "string"
and not string.find(nodes_or_function_or_model, ":") then and not string.find(nodes_or_function_or_model, ":") then
biome_lib:dbg("Warning: Registered function call using deprecated string method: "..dump(nodes_or_function_or_model)) biome_lib.dbg("Warning: Registered function call using deprecated string method: "..dump(nodes_or_function_or_model), 2)
end end
biome_lib.mapgen_elevation_limit.min = math.min(biomedef.min_elevation or 0, biome_lib.mapgen_elevation_limit.min)
biome_lib.mapgen_elevation_limit.max = math.max(biomedef.max_elevation or 0, biome_lib.mapgen_elevation_limit.max)
if biomedef.check_air == false then if biomedef.check_air == false then
biome_lib:dbg("Register no-air-check mapgen hook: "..dump(nodes_or_function_or_model)) biome_lib.dbg("Register no-air-check mapgen hook: "..dump(nodes_or_function_or_model), 3)
biome_lib.actionslist_no_aircheck[#biome_lib.actionslist_no_aircheck + 1] = { biomedef, nodes_or_function_or_model } biome_lib.actionslist_no_aircheck[#biome_lib.actionslist_no_aircheck + 1] = { biomedef, nodes_or_function_or_model }
local s = biomedef.surface local s = biomedef.surface
if type(s) == "string" then if type(s) == "string" then
@ -195,7 +223,7 @@ function biome_lib:register_generate_plant(biomedef, nodes_or_function_or_model)
biome_lib.surfaceslist_no_aircheck[#biome_lib.surfaceslist_no_aircheck + 1] = s biome_lib.surfaceslist_no_aircheck[#biome_lib.surfaceslist_no_aircheck + 1] = s
end end
else else
biome_lib:dbg("Warning: Ignored no-air-check registration for undefined surface node: "..dump(s)) biome_lib.dbg("Warning: Ignored no-air-check registration for undefined surface node: "..dump(s), 2)
end end
else else
for i = 1, #biomedef.surface do for i = 1, #biomedef.surface do
@ -205,12 +233,12 @@ function biome_lib:register_generate_plant(biomedef, nodes_or_function_or_model)
biome_lib.surfaceslist_no_aircheck[#biome_lib.surfaceslist_no_aircheck + 1] = s biome_lib.surfaceslist_no_aircheck[#biome_lib.surfaceslist_no_aircheck + 1] = s
end end
else else
biome_lib:dbg("Warning: Ignored no-air-check registration for undefined surface node: "..dump(s)) biome_lib.dbg("Warning: Ignored no-air-check registration for undefined surface node: "..dump(s), 2)
end end
end end
end end
else else
biome_lib:dbg("Register with-air-checking mapgen hook: "..dump(nodes_or_function_or_model)) biome_lib.dbg("Register with-air-checking mapgen hook: "..dump(nodes_or_function_or_model), 3)
biome_lib.actionslist_aircheck[#biome_lib.actionslist_aircheck + 1] = { biomedef, nodes_or_function_or_model } biome_lib.actionslist_aircheck[#biome_lib.actionslist_aircheck + 1] = { biomedef, nodes_or_function_or_model }
local s = biomedef.surface local s = biomedef.surface
if type(s) == "string" then if type(s) == "string" then
@ -219,7 +247,7 @@ function biome_lib:register_generate_plant(biomedef, nodes_or_function_or_model)
biome_lib.surfaceslist_aircheck[#biome_lib.surfaceslist_aircheck + 1] = s biome_lib.surfaceslist_aircheck[#biome_lib.surfaceslist_aircheck + 1] = s
end end
else else
biome_lib:dbg("Warning: Ignored with-air-checking registration for undefined surface node: "..dump(s)) biome_lib.dbg("Warning: Ignored with-air-checking registration for undefined surface node: "..dump(s), 2)
end end
else else
for i = 1, #biomedef.surface do for i = 1, #biomedef.surface do
@ -229,7 +257,7 @@ function biome_lib:register_generate_plant(biomedef, nodes_or_function_or_model)
biome_lib.surfaceslist_aircheck[#biome_lib.surfaceslist_aircheck + 1] = s biome_lib.surfaceslist_aircheck[#biome_lib.surfaceslist_aircheck + 1] = s
end end
else else
biome_lib:dbg("Warning: Ignored with-air-checking registration for undefined surface node: "..dump(s)) biome_lib.dbg("Warning: Ignored with-air-checking registration for undefined surface node: "..dump(s), 2)
end end
end end
end end
@ -381,7 +409,7 @@ function biome_lib.populate_surfaces(biome, nodes_or_function_or_model, snodes,
if objtype == "table" then if objtype == "table" then
if nodes_or_function_or_model.axiom then if nodes_or_function_or_model.axiom then
biome_lib:generate_tree(p_top, nodes_or_function_or_model) biome_lib:generate_tree(p_top, nodes_or_function_or_model)
biome_lib:dbg("An L-tree was spawned at "..minetest.pos_to_string(p_top)) biome_lib.dbg("An L-tree was spawned at "..minetest.pos_to_string(p_top), 4)
spawned = true spawned = true
else else
local fdir = nil local fdir = nil
@ -390,7 +418,7 @@ function biome_lib.populate_surfaces(biome, nodes_or_function_or_model, snodes,
end end
local n=nodes_or_function_or_model[math.random(#nodes_or_function_or_model)] local n=nodes_or_function_or_model[math.random(#nodes_or_function_or_model)]
minetest.swap_node(p_top, { name = n, param2 = fdir }) minetest.swap_node(p_top, { name = n, param2 = fdir })
biome_lib:dbg("Node \""..n.."\" was randomly picked from a list and placed at "..minetest.pos_to_string(p_top)) biome_lib.dbg("Node \""..n.."\" was randomly picked from a list and placed at "..minetest.pos_to_string(p_top), 4)
spawned = true spawned = true
end end
elseif objtype == "string" and elseif objtype == "string" and
@ -400,18 +428,18 @@ function biome_lib.populate_surfaces(biome, nodes_or_function_or_model, snodes,
fdir = math.random(biome.random_facedir[1], biome.random_facedir[2]) fdir = math.random(biome.random_facedir[1], biome.random_facedir[2])
end end
minetest.swap_node(p_top, { name = nodes_or_function_or_model, param2 = fdir }) minetest.swap_node(p_top, { name = nodes_or_function_or_model, param2 = fdir })
biome_lib:dbg("Node \""..nodes_or_function_or_model.."\" was placed at "..minetest.pos_to_string(p_top)) biome_lib.dbg("Node \""..nodes_or_function_or_model.."\" was placed at "..minetest.pos_to_string(p_top), 4)
spawned = true spawned = true
elseif objtype == "function" then elseif objtype == "function" then
nodes_or_function_or_model(pos) nodes_or_function_or_model(pos)
biome_lib:dbg("A function was run on surface node at "..minetest.pos_to_string(pos)) biome_lib.dbg("A function was run on surface node at "..minetest.pos_to_string(pos), 4)
spawned = true spawned = true
elseif objtype == "string" and pcall(loadstring(("return %s(...)"): elseif objtype == "string" and pcall(loadstring(("return %s(...)"):
format(nodes_or_function_or_model)),pos) then format(nodes_or_function_or_model)),pos) then
spawned = true spawned = true
biome_lib:dbg("An obsolete string-specified function was run on surface node at "..minetest.pos_to_string(p_top)) biome_lib.dbg("An obsolete string-specified function was run on surface node at "..minetest.pos_to_string(p_top), 4)
else else
biome_lib:dbg("Warning: Ignored invalid definition for object "..dump(nodes_or_function_or_model).." that was pointed at {"..dump(pos).."}") biome_lib.dbg("Warning: Ignored invalid definition for object "..dump(nodes_or_function_or_model).." that was pointed at {"..dump(pos).."}", 2)
end end
else else
tries = tries + 1 tries = tries + 1
@ -439,9 +467,6 @@ local function confirm_block_surroundings(p)
return true return true
end end
biome_lib.block_recheck_list = {}
biome_lib.run_block_recheck_list = false
function biome_lib.generate_block(shutting_down) function biome_lib.generate_block(shutting_down)
if shutting_down then if shutting_down then
@ -471,9 +496,12 @@ function biome_lib.generate_block(shutting_down)
local pos_hash = minetest.hash_node_position(minp) local pos_hash = minetest.hash_node_position(minp)
if not biome_lib.pos_hash then -- we need to read the maplock and get the surfaces list if not biome_lib.pos_hash then -- we need to read the maplock and get the surfaces list
local now = minetest.get_us_time()
biome_lib.pos_hash = {} biome_lib.pos_hash = {}
minetest.load_area(minp)
if not confirm_block_surroundings(minp) if not confirm_block_surroundings(minp)
and not shutting_down then -- if any neighbors appear not to be loaded, skip this block for now and not shutting_down
and (blocklog[1][4] + biome_lib.block_timeout) > now then -- if any neighbors appear not to be loaded and the block hasn't expired yet, defer it
if biome_lib.run_block_recheck_list then if biome_lib.run_block_recheck_list then
biome_lib.block_log[#biome_lib.block_log + 1] = table.copy(biome_lib.block_recheck_list[1]) biome_lib.block_log[#biome_lib.block_log + 1] = table.copy(biome_lib.block_recheck_list[1])
@ -483,25 +511,30 @@ function biome_lib.generate_block(shutting_down)
table.remove(biome_lib.block_log, 1) table.remove(biome_lib.block_log, 1)
end end
biome_lib.pos_hash = nil biome_lib.pos_hash = nil
biome_lib:dbg("Mapblock at "..minetest.pos_to_string(minp).. biome_lib.dbg("Mapblock at "..minetest.pos_to_string(minp)..
" had a neighbor not fully emerged, skipped it for now.") " had a neighbor not fully emerged, skipped it for now.", 4)
return return
else else
biome_lib.pos_hash.surface_node_list = airflag biome_lib.pos_hash.surface_node_list = airflag
and minetest.find_nodes_in_area_under_air(minp, maxp, biome_lib.surfaceslist_aircheck) and minetest.find_nodes_in_area_under_air(minp, maxp, biome_lib.surfaceslist_aircheck)
or minetest.find_nodes_in_area(minp, maxp, biome_lib.surfaceslist_no_aircheck) or minetest.find_nodes_in_area(minp, maxp, biome_lib.surfaceslist_no_aircheck)
if #biome_lib.pos_hash.surface_node_list == 0 then
biome_lib.dbg("Mapblock at "..minetest.pos_to_string(minp).." dequeued: no detected surfaces.", 4)
table.remove(blocklog, 1)
biome_lib.pos_hash = nil
return
else
biome_lib.pos_hash.action_index = 1 biome_lib.pos_hash.action_index = 1
if #biome_lib.pos_hash.surface_node_list > 0 then biome_lib.dbg("Mapblock at "..minetest.pos_to_string(minp)..
biome_lib:dbg("Mapblock at "..minetest.pos_to_string(minp)..
" has "..#biome_lib.pos_hash.surface_node_list.. " has "..#biome_lib.pos_hash.surface_node_list..
" surface nodes to work on (airflag="..dump(airflag)..")") " surface nodes to work on (airflag="..dump(airflag)..")", 4)
end end
end end
elseif not (airflag and biome_lib.actionslist_aircheck[biome_lib.pos_hash.action_index]) elseif not (airflag and biome_lib.actionslist_aircheck[biome_lib.pos_hash.action_index])
and not (not airflag and biome_lib.actionslist_no_aircheck[biome_lib.pos_hash.action_index]) then and not (not airflag and biome_lib.actionslist_no_aircheck[biome_lib.pos_hash.action_index]) then
-- the block is finished, remove it -- the block is finished, remove it
if #biome_lib.pos_hash.surface_node_list > 0 then if #biome_lib.pos_hash.surface_node_list > 0 then
biome_lib:dbg("Deleted mapblock "..minetest.pos_to_string(minp).." from the block log") biome_lib.dbg("Deleted mapblock "..minetest.pos_to_string(minp).." from the block log", 4)
end end
table.remove(blocklog, 1) table.remove(blocklog, 1)
biome_lib.pos_hash = nil biome_lib.pos_hash = nil
@ -526,49 +559,93 @@ function biome_lib.generate_block(shutting_down)
end end
end end
if added > 0 then if added > 0 then
biome_lib:dbg("biome_lib.populate_surfaces ran on mapblock at ".. biome_lib.dbg("biome_lib.populate_surfaces ran on mapblock at "..
minetest.pos_to_string(minp)..". Entry #".. minetest.pos_to_string(minp)..". Entry #"..
(biome_lib.pos_hash.action_index-1).." added "..added.." items.") (biome_lib.pos_hash.action_index-1).." added "..added.." items.", 4)
end end
end end
end end
-- "Play" them back, populating them with new stuff in the process -- "Play" them back, populating them with new stuff in the process
local rr = tonumber(minetest.settings:get("biome_lib_queue_run_ratio")) or -100
biome_lib.queue_run_ratio = 100 - rr
biome_lib.entries_per_step = math.max(-rr, 1)
minetest.register_globalstep(function(dtime) minetest.register_globalstep(function(dtime)
if not biome_lib.block_log[1] then return end -- the block log is empty if not biome_lib.block_log[1] then return end -- the block log is empty
if math.random(100) > biome_lib.queue_run_ratio then return end if math.random(100) > biome_lib.queue_ratio then return end
for s = 1, biome_lib.entries_per_step do for s = 1, biome_lib.entries_per_step do
biome_lib.generate_block() biome_lib.generate_block()
end end
end) end)
-- Periodically wake-up the queue to give old blocks a chance to time-out
-- if the player isn't currently exploring (i.e. they're just playing in one area)
function biome_lib.wake_up_queue()
if #biome_lib.block_recheck_list > 1
and #biome_lib.block_log == 0 then
biome_lib.block_log[#biome_lib.block_log + 1] =
table.copy(biome_lib.block_recheck_list[#biome_lib.block_recheck_list])
biome_lib.block_recheck_list[#biome_lib.block_recheck_list] = nil
biome_lib.run_block_recheck_list = true
biome_lib.dbg("Woke-up the map queue to give old blocks a chance to time-out.", 3)
end
minetest.after(biome_lib.block_queue_wakeup_time, biome_lib.wake_up_queue)
end
biome_lib.wake_up_queue()
-- Play out the entire log all at once on shutdown -- Play out the entire log all at once on shutdown
-- to prevent unpopulated map areas -- to prevent unpopulated map areas
local function format_time(t)
if t > 59999999 then
return os.date("!%M minutes and %S seconds", math.ceil(t/1000000))
else
return os.date("!%S seconds", math.ceil(t/1000000))
end
end
function biome_lib.check_remaining_time()
if minetest.get_us_time() > (biome_lib.shutdown_last_timestamp + 10000000) then -- report progress every 10s
biome_lib.shutdown_last_timestamp = minetest.get_us_time()
local entries_remaining = #biome_lib.block_log + #biome_lib.block_recheck_list
local total_purged = biome_lib.starting_count - entries_remaining
local elapsed_time = biome_lib.shutdown_last_timestamp - biome_lib.shutdown_start_time
biome_lib.dbg(string.format("%i entries, approximately %s remaining.",
entries_remaining, format_time(elapsed_time/total_purged * entries_remaining)))
end
end
minetest.register_on_shutdown(function() minetest.register_on_shutdown(function()
if #biome_lib.block_log + #biome_lib.block_recheck_list == 0 then biome_lib.shutdown_start_time = minetest.get_us_time()
biome_lib.shutdown_last_timestamp = minetest.get_us_time()+1
biome_lib.starting_count = #biome_lib.block_log + #biome_lib.block_recheck_list
if biome_lib.starting_count == 0 then
return return
end end
print("[biome_lib] Stand by, playing out the rest of the mapblock log") biome_lib.dbg("Stand by, purging the mapblock log "..
print("(there are "..(#biome_lib.block_log + #biome_lib.block_recheck_list).." entries)...") "(there are "..biome_lib.starting_count.." entries) ...", 0)
while #biome_lib.block_log > 0 do while #biome_lib.block_log > 0 do
biome_lib.generate_block(true) biome_lib.generate_block(true)
biome_lib.check_remaining_time()
end end
if #biome_lib.block_recheck_list > 0 then if #biome_lib.block_recheck_list > 0 then
biome_lib.block_log = table.copy(biome_lib.block_recheck_list) biome_lib.block_log = table.copy(biome_lib.block_recheck_list)
biome_lib.block_recheck_list = {}
while #biome_lib.block_log > 0 do while #biome_lib.block_log > 0 do
biome_lib.generate_block(true) biome_lib.generate_block(true)
biome_lib.check_remaining_time()
end end
end end
biome_lib.dbg("Log purge completed after "..
format_time(minetest.get_us_time() - biome_lib.shutdown_start_time)..".", 0)
end) end)
-- The spawning ABM -- The spawning ABM
@ -761,24 +838,36 @@ function biome_lib:get_nodedef_field(nodename, fieldname)
return minetest.registered_nodes[nodename][fieldname] return minetest.registered_nodes[nodename][fieldname]
end end
if DEBUG then if biome_lib.debug_log_level >= 3 then
biome_lib.last_count = 0 biome_lib.last_count = 0
function biome_lib.show_pending_block_count() function biome_lib.show_pending_block_count()
if biome_lib.last_count ~= #biome_lib.block_log then if biome_lib.last_count ~= #biome_lib.block_log then
biome_lib:dbg("Pending block count: "..(#biome_lib.block_log + #biome_lib.block_recheck_list)) biome_lib.dbg(string.format("Pending block counts - ready to process: %-8icurrently deferred: %i",
#biome_lib.block_log, #biome_lib.block_recheck_list), 3)
biome_lib.last_count = #biome_lib.block_log biome_lib.last_count = #biome_lib.block_log
biome_lib.queue_idle_flag = false
elseif not biome_lib.queue_idle_flag then
if #biome_lib.block_recheck_list > 0 then
biome_lib.dbg("Mapblock queue only contains blocks that can't yet be processed.", 3)
biome_lib.dbg("Idling the queue until new blocks arrive or the next wake-up call occurs.", 3)
else
biome_lib.dbg("Mapblock queue has run dry.", 3)
biome_lib.dbg("Idling the queue until new blocks arrive.", 3)
end
biome_lib.queue_idle_flag = true
end end
minetest.after(1, biome_lib.show_pending_block_count) minetest.after(1, biome_lib.show_pending_block_count)
end end
biome_lib.show_pending_block_count() biome_lib.show_pending_block_count()
minetest.after(0, function()
print("Registered a total of "..(#biome_lib.surfaceslist_aircheck)+(#biome_lib.surfaceslist_no_aircheck).." surface types to be evaluated, spread")
print("across "..#biome_lib.actionslist_aircheck.." actions with air-checking and "..#biome_lib.actionslist_no_aircheck.." actions without.")
end)
end end
print("[Biome Lib] Loaded") minetest.after(0, function()
biome_lib.dbg("Registered a total of "..(#biome_lib.surfaceslist_aircheck)+(#biome_lib.surfaceslist_no_aircheck).." surface types to be evaluated, spread", 0)
biome_lib.dbg("across "..#biome_lib.actionslist_aircheck.." actions with air-checking and "..#biome_lib.actionslist_no_aircheck.." actions without.", 0)
biome_lib.dbg("within an elevation range of "..biome_lib.mapgen_elevation_limit.min.." and "..biome_lib.mapgen_elevation_limit.max.." meters.", 0)
end)
biome_lib.dbg("[Biome Lib] Loaded", 0)

View File

@ -56,19 +56,28 @@ end
-- split into individual mapblocks to reduce lag -- split into individual mapblocks to reduce lag
minetest.register_on_generated(function(minp, maxp, blockseed) minetest.register_on_generated(function(minp, maxp, blockseed)
for x = 0, 4 do local timestamp = minetest.get_us_time()
local minx = minp.x + x*16
for y = 0, 4 do for y = 0, 4 do
local miny = minp.y + y*16 local miny = minp.y + y*16
if miny >= biome_lib.mapgen_elevation_limit.min
and (miny + 15) <= biome_lib.mapgen_elevation_limit.max then
for x = 0, 4 do
local minx = minp.x + x*16
for z = 0, 4 do for z = 0, 4 do
local minz = minp.z + z*16 local minz = minp.z + z*16
local bmin = {x=minx, y=miny, z=minz} local bmin = {x=minx, y=miny, z=minz}
local bmax = {x=minx + 15, y=miny + 15, z=minz + 15} local bmax = {x=minx + 15, y=miny + 15, z=minz + 15}
biome_lib.block_log[#biome_lib.block_log + 1] = { bmin, bmax, true } biome_lib.block_log[#biome_lib.block_log + 1] = { bmin, bmax, true, timestamp }
biome_lib.block_log[#biome_lib.block_log + 1] = { bmin, bmax, false } biome_lib.block_log[#biome_lib.block_log + 1] = { bmin, bmax, false, timestamp }
end end
end end
else
biome_lib.dbg("Did not enqueue mapblocks at elevation "..miny.."m, they're out of range of any generate_plant() calls.", 4)
end
end end
biome_lib.run_block_recheck_list = true biome_lib.run_block_recheck_list = true
end) end)

48
settingtypes.txt Normal file
View File

@ -0,0 +1,48 @@
# Comma-separated list of things that a spawned node is allowed to grow
# through. Air is always added to whatever else you specify here.
biome_lib_default_grow_through_nodes (List of things a plant can grow through) string default:snow
# Comma-separated list of nodes that should be treated as water or water-like
# for the sake of looking for neighboring wet ground.
biome_lib_default_water_nodes (List of "water-like" sources) string default:water_source,default:water_flowing,default:river_water_source,default:river_water_flowing
# Comma-separated list of nodes that should be considered "wet" if one of
# the configured "water-like" sources is nearby.
biome_lib_default_wet_surfaces (List of "wet" nodes) string default:dirt,default:dirt_with_grass,default:sand
# Comma-separated list of nodes that something must be sitting on to be
# able to actively change from one thing to another (such as a sapling
# growing into a tree), to be used if the mod that added that growable
# thing didn't provide its own list of suitable surfaces.
biome_lib_default_grow_nodes (List of default surfaces a plant can thrive on) string default:dirt_with_grass
# Comma-separated list of nodes to use as the "root" of something that can
# gradually climb up a wall (such as ivy), to be used if the mod that added
# the climing thing didn't provide its own list.
biome_lib_default_ground_nodes (List of default root nodes) string default:dirt_with_grass
# biome_lib divides its workload into "actions", as dictated by the sum
# total of all mods that use it, and this sets how much of that work is done
# per globalstep tick. If positive, a single action is executed on that
# percentage of ticks, on average. If negative, it becomes positive, and
# that many actions are executed on every single tick, skipping none.
# More negative means more throughput, at the expense of lag. On fast PC's,
# a setting of between -500 and -2000 might be good.
biome_lib_queue_ratio (Queue run ratio) int -200
# Minetest's map generator allows neighboring areas to overflow into one
# another, to create smooth terrain, but it often hands the map blocks that
# comprise those areas to Lua (and hence, to biome_lib) before that overflow
# function happens, which causes the mapgen to overwrite whatever Lua does
# to them. This setting (in seconds) makes biome_lib wait before adding its
# normal output to those map blocks, to give the engine plenty of time to
# run that overflow feature first.
biome_lib_block_timeout (Deferred block timeout) int 300
# This does just what it sounds like - it shows all debug output that's sent
# with a level equal to or greater than this value. A setting of 0 shows only
# the bare necessities, such as the startup and shutdown messages, 1 adds
# internal non-fatal errors to what's shown, 2 adds warnings, 3 adds other
# basic info, 4 adds all the verbose debugging spew. 3 is perhaps the most
# useful setting.
biome_lib_debug_log_level (Debug log level) int 0