prioritize map decorations to make the generations more deterministic

This commit is contained in:
kno10 2024-08-03 20:28:23 +02:00
parent 9a305b56a8
commit 2a4fe39d5c
5 changed files with 342 additions and 266 deletions

File diff suppressed because it is too large Load Diff

View File

@ -169,3 +169,54 @@ function mcl_mapgen_core.unregister_generator(id)
if rec.needs_param2 then param2 = param2 - 1 end
--if rec.needs_level0 then level0 = level0 - 1 end
end
-- Try to make decorations more deterministic in order, by sorting by priority and name
-- At least for low-priority this should make map seeds more comparable, but
-- adding for example a new structure can still change everything that comes
-- later, because currently decoration blockseeds are incremented sequentially
-- c.f., https://github.com/minetest/minetest/issues/14919
local minetest_register_decoration = minetest.register_decoration
local pending_decorations = {}
function mcl_mapgen_core.register_decoration(def, callback)
if pending_decorations == nil then
minetest.log("warning", "Decoration registered after mapgen: "..tostring(def.name))
minetest_register_decoration(def)
if callback ~= nil then callback() end
return
end
def = table.copy(def) -- defensive deep copy, needed for water lily
def.callback = callback
table.insert(pending_decorations, def)
end
local function sort_decorations()
local keys, map = {}, {}
for i, def in pairs(pending_decorations) do
local name = def.name
-- we try to generate fallback names to make order more deterministic
name = name or (def.decoration and string.format("%s:%04d", def.decoration, i))
if not name and type(def.schematic) == "string" then
local sc = string.split(def.schematic, "/")
name = string.format("%s:%04d", sc[#sc], i)
end
if not name and type(def.schematic) == "table" and def.schematic.data then
name = ""
for _, v in ipairs(def.schematic.data) do
if v.name then name = name .. v.name .. ":" end
end
name = name .. string.format("%04d", i)
end
name = name or string.format("%04d", i)
local prio = (def.priority or 1000) + i/1000
local key = string.format("%08.3f:%s", prio, name)
table.insert(keys, key)
map[key] = def
end
table.sort(keys)
for _, key in ipairs(keys) do
-- minetest.log("action", "Deco: "..key)
minetest_register_decoration(map[key])
if map[key].callback then map[key].callback() end
end
pending_decorations = nil -- as we will not run again
end
minetest.register_on_mods_loaded(sort_decorations)

View File

@ -45,6 +45,7 @@ local function register_mgv6_decorations()
-- Doubletall grass
minetest.register_decoration({
priority = 1500,
deco_type = "schematic",
schematic = {
size = { x=1, y=3, z=1 },
@ -81,6 +82,7 @@ local function register_mgv6_decorations()
},
-- v6 hack: This makes sure large ferns only appear in jungles
spawn_by = { "mcl_core:jungletree", "mcl_flowers:fern" },
priority = 1510, -- larger than fern
num_spawn_by = 1,
place_on = {"group:grass_block_no_snow"},
@ -192,6 +194,7 @@ local function register_mgv6_decorations()
},
-- Small trick to make sure melon spawn in jungles
spawn_by = { "mcl_core:jungletree", "mcl_flowers:fern" },
priority = 1510, -- larger than fern
num_spawn_by = 1,
y_min = 1,
y_max = 40,
@ -214,6 +217,7 @@ local function register_mgv6_decorations()
y_min = 1,
y_max = mcl_vars.overworld_max,
decoration = "mcl_flowers:tallgrass",
priority = 1500,
})
minetest.register_decoration({
deco_type = "simple",
@ -230,6 +234,7 @@ local function register_mgv6_decorations()
y_min = 1,
y_max = mcl_vars.overworld_max,
decoration = "mcl_flowers:tallgrass",
priority = 1500,
})
-- Seagrass and kelp
@ -256,6 +261,7 @@ local function register_mgv6_decorations()
y_min = mcl_vars.overworld_min,
y_max = 0,
decoration = "mcl_ocean:seagrass_"..mat,
priority = 1500,
})
minetest.register_decoration({
deco_type = "simple",
@ -276,6 +282,7 @@ local function register_mgv6_decorations()
y_min = mcl_vars.overworld_min,
y_max = -5,
decoration = "mcl_ocean:seagrass_"..mat,
priority = 1500,
})
minetest.register_decoration({
@ -356,6 +363,7 @@ local function register_mgv6_decorations()
y_min = 1,
y_max = mcl_vars.overworld_max,
decoration = "mcl_flowers:tallgrass",
priority = 1500,
})
local mushrooms = {"mcl_mushrooms:mushroom_red", "mcl_mushrooms:mushroom_brown"}

View File

@ -326,7 +326,6 @@ function mcl_structures.place_structure(pos, def, pr, blockseed, rot)
end
local EMPTY_SCHEMATIC = { size = {x = 0, y = 0, z = 0}, data = { } }
function mcl_structures.register_structure(name,def,nospawn) --nospawn means it will not be placed by mapgen decoration mechanism
if mcl_structures.is_disabled(name) then return end
flags = def.flags or "place_center_x, place_center_z, force_placement"
@ -335,6 +334,7 @@ function mcl_structures.register_structure(name,def,nospawn) --nospawn means it
minetest.register_on_mods_loaded(function() --make sure all previous decorations and biomes have been registered
def.deco = minetest.register_decoration({
name = "mcl_structures:deco_"..name,
priority = def.priority or (def.terrain_feature and 900) or 100, -- run before regular decorations
deco_type = "schematic",
schematic = EMPTY_SCHEMATIC,
place_on = def.place_on,

View File

@ -134,6 +134,7 @@ local function get_fallen_tree_schematic(pos,pr)
end
mcl_structures.register_structure("fallen_tree",{
priority = 1100, -- after regular trees
place_on = {"group:grass_block"},
terrain_feature = true,
noise_params = {
@ -151,12 +152,9 @@ mcl_structures.register_structure("fallen_tree",{
y_min = minetest.get_mapgen_setting("water_level"),
on_place = function(pos,def,pr)
local air_p1 = vector.offset(pos,-def.sidelen/2,1,-def.sidelen/2)
local air_p2 = vector.offset(pos,def.sidelen/2,1,def.sidelen/2)
local air_p2 = vector.offset(air_p1,def.sidelen-1,0,def.sidelen-1)
local air = minetest.find_nodes_in_area(air_p1,air_p2,{"air"})
if #air < ( def.sidelen * def.sidelen ) / 2 then
return false
end
return true
return #air >= (def.sidelen * def.sidelen) / 2
end,
place_func = function(pos,def,pr)
local schem=get_fallen_tree_schematic(pos,pr)