improved gennotify callback mechanism

This commit is contained in:
kno10 2025-01-11 23:26:28 +01:00 committed by the-real-herowl
parent 73b675448e
commit 088095adf3
3 changed files with 131 additions and 169 deletions
mods/MAPGEN
mcl_biomes
mcl_mapgen_core
mcl_structures

View file

@ -26,11 +26,6 @@ local mod_mcl_crimson = minetest.get_modpath("mcl_crimson")
local mod_mcl_blackstone = minetest.get_modpath("mcl_blackstone")
local mod_mcl_mangrove = minetest.get_modpath("mcl_mangrove")
-- these are registered asynchronously
local deco_ids_fungus = {}
local deco_ids_trees = {}
local deco_id_chorus_plant
--
-- Register biomes
--
@ -3528,6 +3523,37 @@ local function register_coral_decos(ck)
})
end
--- Fix light for mushroom lights after generation
local function fix_light_17x17_gennotify(t, minp, maxp, blockseed)
for _, pos in ipairs(t) do
minetest.fix_light(vector.offset(pos, -8, -8, -8), vector.offset(pos, 8, 8, 8))
end
end
--- Grow mangrove roots after generation
local swamp_biome_id, swamp_shore_id
local function mangrove_root_gennotify(t, minp, maxp, blockseed)
for _, pos in ipairs(t) do
local nn = minetest.find_nodes_in_area(vector.offset(pos, -8, -1, -8), vector.offset(pos, 8, 0, 8), {"mcl_mangrove:mangrove_roots"})
if nn and #nn > 0 then
local pr = PcgRandom(blockseed + mg_seed + 38327)
for _, v in pairs(nn) do
local l = pr:next(2, 16)
local n = minetest.get_node(vector.offset(v, 0, -1, 0)).name
if minetest.get_item_group(n, "water") > 0 then
local wl = "mcl_mangrove:water_logged_roots"
if n:find("river") then wl = "mcl_mangrove:river_water_logged_roots" end
minetest.bulk_set_node(minetest.find_nodes_in_area(v, vector.offset(v, 0, -l, 0), {"group:water"}), {name = wl})
elseif n == "mcl_mud:mud" then
minetest.bulk_set_node(minetest.find_nodes_in_area(v, vector.offset(v, 0, -l, 0), {"mcl_mud:mud"}), {name = "mcl_mangrove:mangrove_mud_roots"})
elseif n == "air" then
minetest.bulk_set_node(minetest.find_nodes_in_area(v, vector.offset(v, 0, -l, 0), {"air"}), {name = "mcl_mangrove:mangrove_roots"})
end
end
end
end
end
local function register_decorations()
-- Coral Reefs
for k, _ in pairs(corals) do
@ -3991,11 +4017,8 @@ local function register_decorations()
schematic = mod_mcl_mangrove .. "/schematics/mcl_mangrove_tree_1.mts",
flags = "place_center_x, place_center_z, force_placement",
rotation = "random",
}, function()
local f = minetest.get_decoration_id("mcl_biomes:mangrove_tree_1")
table.insert(deco_ids_trees, f)
minetest.set_gen_notify({decoration = true}, {f})
end)
gen_callback = mangrove_root_gennotify,
})
mcl_mapgen_core.register_decoration({
name = "mcl_biomes:mangrove_tree_2",
deco_type = "schematic",
@ -4008,11 +4031,8 @@ local function register_decorations()
schematic = mod_mcl_mangrove .. "/schematics/mcl_mangrove_tree_2.mts",
flags = "place_center_x, place_center_z, force_placement",
rotation = "random",
}, function()
local f = minetest.get_decoration_id("mcl_biomes:mangrove_tree_2")
table.insert(deco_ids_trees, f)
minetest.set_gen_notify({decoration = true}, {f})
end)
gen_callback = mangrove_root_gennotify,
})
mcl_mapgen_core.register_decoration({
name = "mcl_biomes:mangrove_tree_3",
deco_type = "schematic",
@ -4025,11 +4045,8 @@ local function register_decorations()
schematic = mod_mcl_mangrove .. "/schematics/mcl_mangrove_tree_3.mts",
flags = "place_center_x, place_center_z, force_placement",
rotation = "random",
}, function()
local f = minetest.get_decoration_id("mcl_biomes:mangrove_tree_3")
table.insert(deco_ids_trees, f)
minetest.set_gen_notify({decoration = true}, {f})
end)
gen_callback = mangrove_root_gennotify,
})
mcl_mapgen_core.register_decoration({
name = "mcl_biomes:mangrove_tree_4",
deco_type = "schematic",
@ -4042,11 +4059,8 @@ local function register_decorations()
schematic = mod_mcl_mangrove .. "/schematics/mcl_mangrove_tree_4.mts",
flags = "place_center_x, place_center_z, force_placement",
rotation = "random",
}, function()
local f = minetest.get_decoration_id("mcl_biomes:mangrove_tree_4")
table.insert(deco_ids_trees, f)
minetest.set_gen_notify({decoration = true}, {f})
end)
gen_callback = mangrove_root_gennotify,
})
mcl_mapgen_core.register_decoration({
name = "mcl_biomes:mangrove_tree_5",
deco_type = "schematic",
@ -4059,11 +4073,8 @@ local function register_decorations()
schematic = mod_mcl_mangrove .. "/schematics/mcl_mangrove_tree_5.mts",
flags = "place_center_x, place_center_z, force_placement",
rotation = "random",
}, function()
local f = minetest.get_decoration_id("mcl_biomes:mangrove_tree_5")
table.insert(deco_ids_trees, f)
minetest.set_gen_notify({decoration = true}, {f})
end)
gen_callback = mangrove_root_gennotify,
})
mcl_mapgen_core.register_decoration({
name = "mcl_biomes:mangrove_bee_nest",
deco_type = "schematic",
@ -4086,11 +4097,8 @@ local function register_decorations()
rotation = "random",
spawn_by = "group:flower",
rank = 1550,
}, function()
local f = minetest.get_decoration_id("mcl_biomes:mangrove_bee_nest")
table.insert(deco_ids_trees, f)
minetest.set_gen_notify({decoration = true}, {f})
end)
gen_callback = mangrove_root_gennotify,
})
mcl_mapgen_core.register_decoration({
deco_type = "simple",
place_on = {"mcl_mud:mud"},
@ -4698,9 +4706,9 @@ local function register_decorations()
y_max = mcl_vars.mg_overworld_max,
decoration = "mcl_core:cactus",
biomes = {"Desert",
"Mesa", "Mesa_sandlevel",
"MesaPlateauF", "MesaPlateauF_sandlevel",
"MesaPlateauFM", "MesaPlateauFM_sandlevel"},
"Mesa", "Mesa_sandlevel",
"MesaPlateauF", "MesaPlateauF_sandlevel",
"MesaPlateauFM", "MesaPlateauFM_sandlevel"},
height = 1,
height_max = 3,
spawn_by = "air",
@ -4907,7 +4915,7 @@ local function register_decorations()
octaves = 4,
persist = 0.6,
},
biomes = {"Jungle", },
biomes = {"Jungle"},
y_min = 3,
y_max = mcl_vars.mg_overworld_max,
schematic = mod_mcl_core .. "/schematics/mcl_core_jungle_bush_oak_leaves_2.mts",
@ -5604,11 +5612,8 @@ local function register_dimension_decorations()
schematic = mod_mcl_crimson .. "/schematics/warped_fungus_1.mts",
size = vector.new(5, 11, 5),
rotation = "random",
}, function()
local f = minetest.get_decoration_id("mcl_biomes:warped_tree1")
table.insert(deco_ids_fungus, f)
minetest.set_gen_notify({decoration = true}, {f})
end)
gen_callback = fix_light_17x17_gennotify,
})
mcl_mapgen_core.register_decoration({
deco_type = "schematic",
name = "mcl_biomes:warped_tree2",
@ -5622,11 +5627,8 @@ local function register_dimension_decorations()
schematic = mod_mcl_crimson .. "/schematics/warped_fungus_2.mts",
size = vector.new(5, 6, 5),
rotation = "random",
}, function()
local f = minetest.get_decoration_id("mcl_biomes:warped_tree2")
table.insert(deco_ids_fungus, f)
minetest.set_gen_notify({decoration = true}, {f})
end)
gen_callback = fix_light_17x17_gennotify,
})
mcl_mapgen_core.register_decoration({
deco_type = "schematic",
name = "mcl_biomes:warped_tree3",
@ -5640,11 +5642,8 @@ local function register_dimension_decorations()
schematic = mod_mcl_crimson .. "/schematics/warped_fungus_3.mts",
size = vector.new(5, 12, 5),
rotation = "random",
}, function()
local f = minetest.get_decoration_id("mcl_biomes:warped_tree3")
table.insert(deco_ids_fungus, f)
minetest.set_gen_notify({decoration = true}, {f})
end)
gen_callback = fix_light_17x17_gennotify,
})
mcl_mapgen_core.register_decoration({
deco_type = "simple",
place_on = {"mcl_crimson:warped_nylium", "mcl_crimson:twisting_vines"},
@ -5703,11 +5702,8 @@ local function register_dimension_decorations()
schematic = mod_mcl_crimson .. "/schematics/crimson_fungus_1.mts",
size = vector.new(5, 8, 5),
rotation = "random",
}, function()
local f = minetest.get_decoration_id("mcl_biomes:crimson_tree1")
table.insert(deco_ids_fungus, f)
minetest.set_gen_notify({decoration = true}, {f})
end)
gen_callback = fix_light_17x17_gennotify,
})
minetest.register_alias("mcl_biomes:crimson_tree", "mcl_biomes:crimson_tree1") -- legacy inconsistency, fixed 08/2024
mcl_mapgen_core.register_decoration({
deco_type = "schematic",
@ -5722,11 +5718,8 @@ local function register_dimension_decorations()
schematic = mod_mcl_crimson .. "/schematics/crimson_fungus_2.mts",
size = vector.new(5, 12, 5),
rotation = "random",
}, function()
local f = minetest.get_decoration_id("mcl_biomes:crimson_tree2")
table.insert(deco_ids_fungus, f)
minetest.set_gen_notify({decoration = true}, {f})
end)
gen_callback = fix_light_17x17_gennotify,
})
mcl_mapgen_core.register_decoration({
deco_type = "schematic",
name = "mcl_biomes:crimson_tree3",
@ -5740,11 +5733,8 @@ local function register_dimension_decorations()
schematic = mod_mcl_crimson .. "/schematics/crimson_fungus_3.mts",
size = vector.new(7, 13, 7),
rotation = "random",
}, function()
local f = minetest.get_decoration_id("mcl_biomes:crimson_tree3")
table.insert(deco_ids_fungus, f)
minetest.set_gen_notify({decoration = true}, {f})
end)
gen_callback = fix_light_17x17_gennotify,
})
mcl_mapgen_core.register_decoration({
deco_type = "simple",
place_on = {"mcl_crimson:warped_nylium", "mcl_crimson:weeping_vines", "mcl_nether:netherrack"},
@ -5955,15 +5945,24 @@ local function register_dimension_decorations()
decoration = "mcl_end:chorus_flower",
height = 1,
biomes = {"End", "EndMidlands", "EndHighlands", "EndBarrens", "EndSmallIslands"},
},function()
deco_id_chorus_plant = minetest.get_decoration_id("mcl_biomes:chorus_plant")
minetest.set_gen_notify({decoration = true}, {deco_id_chorus_plant})
end)
gen_callback = function(t, minp, maxp, blockseed)
local pr = PcgRandom(blockseed + mg_seed + 99682)
for _, pos in ipairs(t) do
local x, y, z = pos.x, pos.y, pos.z
if x < -10 or x > 10 or z < -10 or z > 10 then
local realpos = vector.new(x, y + 1, z)
local node = minetest.get_node(realpos)
if node and node.name == "mcl_end:chorus_flower" then
mcl_end.grow_chorus_plant(realpos, node, pr)
end
end
end
end,
})
-- TODO: End cities
end
--
-- Detect mapgen to select functions
--
@ -5991,74 +5990,4 @@ if mg_name ~= "singlenode" then
register_dimension_biomes()
register_dimension_ores()
register_dimension_decorations()
-- Overworld decorations for v6 are handled in mcl_mapgen_core
local function mangrove_roots_gen(gennotify, pr)
for _, f in pairs(deco_ids_trees) do
for _, pos in ipairs(gennotify["decoration#" .. f] or {}) do
local nn = minetest.find_nodes_in_area(vector.offset(pos, -8, -1, -8), vector.offset(pos, 8, 0, 8), {"mcl_mangrove:mangrove_roots"})
for _, v in pairs(nn) do
local l = pr:next(2, 16)
local n = minetest.get_node(vector.offset(v, 0, -1, 0)).name
if minetest.get_item_group(n, "water") > 0 then
local wl = "mcl_mangrove:water_logged_roots"
if n:find("river") then
wl = "mcl_mangrove:river_water_logged_roots"
end
minetest.bulk_set_node(minetest.find_nodes_in_area(vector.offset(v, 0, 0, 0), vector.offset(v, 0, -l, 0), {"group:water"}), {name = wl})
elseif n == "mcl_mud:mud" then
minetest.bulk_set_node(minetest.find_nodes_in_area(vector.offset(v, 0, 0, 0), vector.offset(v, 0, -l, 0), {"mcl_mud:mud"}), {name = "mcl_mangrove:mangrove_mud_roots"})
elseif n == "air" then
minetest.bulk_set_node(minetest.find_nodes_in_area(vector.offset(v, 0, 0, 0), vector.offset(v, 0, -l, 0), {"air"}), {name = "mcl_mangrove:mangrove_roots"})
end
end
end
end
end
local function chorus_gen (gennotify, pr)
for _, pos in ipairs(gennotify["decoration#" .. deco_id_chorus_plant] or {}) do
local x, y, z = pos.x, pos.y, pos.z
if x < -10 or x > 10 or z < -10 or z > 10 then
local realpos = vector.new(x, y + 1, z)
local node = minetest.get_node(realpos)
if node and node.name == "mcl_end:chorus_flower" then
mcl_end.grow_chorus_plant(realpos, node, pr)
end
end
end
end
local function crimson_warped_gen(gennotify)
for _, f in pairs(deco_ids_fungus) do
for _, pos in ipairs(gennotify["decoration#" .. f] or {}) do
minetest.fix_light(vector.offset(pos, -8, -8, -8), vector.offset(pos, 8, 8, 8))
end
end
end
if deco_id_chorus_plant or deco_ids_fungus or deco_ids_trees then
mcl_mapgen_core.register_generator("chorus_grow", nil, function(minp, maxp, blockseed)
local gennotify = minetest.get_mapgen_object("gennotify")
local pr = PseudoRandom(blockseed + 14)
if not (maxp.y < mcl_vars.mg_overworld_min or minp.y > mcl_vars.mg_overworld_max) then
local biomemap = minetest.get_mapgen_object("biomemap")
local swamp_biome_id = minetest.get_biome_id("MangroveSwamp")
local swamp_shore_id = minetest.get_biome_id("MangroveSwamp_shore")
if biomemap and (table.indexof(biomemap, swamp_biome_id) ~= -1 or table.indexof(biomemap, swamp_shore_id) ~= -1) then
mangrove_roots_gen(gennotify, pr)
end
end
if not (maxp.y < mcl_vars.mg_end_min or minp.y > mcl_vars.mg_end_max) then
chorus_gen(gennotify, pr)
end
if not (maxp.y < mcl_vars.mg_nether_min or minp.y > mcl_vars.mg_nether_max) then
crimson_warped_gen(gennotify)
end
end)
end
end

View file

@ -5,6 +5,7 @@ local lvm_buffer, lvm_buffer2 = {}, {}
local logging = minetest.settings:get_bool("mcl_logging_mapgen", false)
local log_timing = minetest.settings:get_bool("mcl_logging_mapgen_timing", false) -- detailed, for performance debugging
local seed = minetest.get_mapgen_setting("seed")
local function run_generators(minp, maxp, blockseed)
if nodes == 0 then return end
@ -147,20 +148,30 @@ end
-- later, because currently decoration blockseeds are incremented sequentially
-- c.f., https://github.com/minetest/minetest/issues/14919
local pending_decorations = {}
local gennotify_map = {}
function mcl_mapgen_core.register_decoration(def, callback)
def = table.copy(def) -- defensive deep copy, needed for water lily
if def.gen_callback and not def.name then error("gen_callback requires a named decoration.") end
if callback then error("Callbacks have been redesigned.") end
if pending_decorations == nil then
-- Please do not register decorations in minetest.register_on_mods_loaded.
-- This should usually not happen, but modders may misuse this.
-- Nothing really bad should happen though, but the rank is ignored.
minetest.log("warning", "Decoration registered after mapgen: "..tostring(def.name))
minetest.log("warning", "Decoration registered after mapgen core initialization: "..tostring(def.name))
minetest.register_decoration(def)
if callback then callback() end
if def.gen_callback then
def.deco_id = minetest.get_decoration_id(def.name)
if not def.deco_id then
error("Failed to get the decoration id for "..tostring(key))
else
minetest.set_gen_notify({decoration = true}, {def.deco_id})
gennotify_map["decoration#" .. def.deco_id] = def
end
end
return
end
def = table.copy(def) -- defensive deep copy, needed for water lily
def.callback = callback
pending_decorations[#pending_decorations+1] = def
end
@ -187,11 +198,38 @@ local function sort_decorations()
end
table.sort(keys)
for _, key in ipairs(keys) do
-- minetest.log("action", "Deco: "..key) -- dump the resulting order
minetest.register_decoration(map[key])
if map[key].callback then map[key].callback() end
local def = map[key]
local deco_id = minetest.register_decoration(def)
if not deco_id then
error("Failed to register decoration"..tostring(key))
end
if def.name and def.gen_callback then
deco_id = minetest.get_decoration_id(def.name)
if not deco_id then
error("Failed to get the decoration id for "..tostring(key))
else
minetest.set_gen_notify({decoration = true}, {deco_id})
gennotify_map["decoration#" .. deco_id] = def
end
end
end
pending_decorations = nil -- as we will not run again
end
mcl_mapgen_core.register_generator("Gennotify callbacks", nil, function(minp, maxp, blockseed)
local pr = PcgRandom(blockseed + seed + 48214) -- constant seed offset
local gennotify = minetest.get_mapgen_object("gennotify")
for key, def in pairs(gennotify_map) do
local t = gennotify[key]
if t and #t > 0 then
-- Fisher-Yates shuffle, using pr
for i = 1, #t-1 do
local r = pr:next(i,#t)
t[i], t[r] = t[r], t[i]
end
def.gen_callback(t, minp, maxp, blockseed)
end
end
end)
minetest.register_on_mods_loaded(sort_decorations)

View file

@ -11,6 +11,7 @@ local mob_cap_player = tonumber(minetest.settings:get("mcl_mob_cap_player")) or
local mob_cap_animal = tonumber(minetest.settings:get("mcl_mob_cap_animal")) or 10
local logging = minetest.settings:get_bool("mcl_logging_structures",true)
local worldseed = minetest.get_mapgen_setting("seed")
local mg_name = minetest.get_mapgen_setting("mg_name")
@ -348,14 +349,17 @@ function mcl_structures.register_structure(name,def,nospawn) --nospawn means it
flags = flags,
biomes = def.biomes,
y_max = def.y_max,
y_min = def.y_min
},
function()
def.deco_id = minetest.get_decoration_id("mcl_structures:"..name)
minetest.set_gen_notify({decoration=true}, { def.deco_id })
--catching of gennotify happens in mcl_mapgen_core
y_min = def.y_min,
gen_callback = function(t,minp,maxp,blockseed)
for _, pos in ipairs(t) do
local pr = PcgRandom(minetest.hash_node_position(pos) + worldseed + RANDOM_SEED_OFFSET)
if def.chunk_probability == nil or pr:next(0, 1e9) * 1e-9 * def.chunk_probability <= 1 then
mcl_structures.place_structure(pos, def, pr, blockseed)
if def.chunk_probability ~= nil then break end -- allow only one per gennotify, e.g., on multiple surfaces
end
end
end
)
})
end)
end
mcl_structures.registered_structures[name] = def
@ -397,18 +401,9 @@ end
-- To avoid a cyclic dependency, run this when modules have finished loading
minetest.register_on_mods_loaded(function()
mcl_mapgen_core.register_generator("structures", nil, function(minp, maxp, blockseed)
local gennotify = minetest.get_mapgen_object("gennotify")
mcl_mapgen_core.register_generator("static structures", nil, function(minp, maxp, blockseed)
for _,struct in pairs(mcl_structures.registered_structures) do
if struct.deco_id then
for _, pos in pairs(gennotify["decoration#"..struct.deco_id] or {}) do
local pr = PcgRandom(minetest.hash_node_position(pos) + blockseed + RANDOM_SEED_OFFSET)
if struct.chunk_probability == nil or pr:next(1, struct.chunk_probability) == 1 then
mcl_structures.place_structure(vector.offset(pos,0,1,0),struct,pr,blockseed)
if struct.chunk_probability then break end -- one (attempt) per chunk only
end
end
elseif struct.static_pos then
if struct.static_pos then
local pr = PcgRandom(blockseed + RANDOM_SEED_OFFSET)
for _, pos in pairs(struct.static_pos) do
if vector.in_area(pos, minp, maxp) then