Add decoration engine

This commit still has an unexplained bug where it fails to place schematics underground, and this is to be investigated.
Bram van den Heuvel 2024-04-30 14:44:54 +02:00
parent 5005ae7d32
commit 39406abfaf
1 changed files with 144 additions and 11 deletions

155
init.lua
View File

@ -704,12 +704,13 @@ function internal.generate_caves(data, minp, maxp)
) )
local air = minetest.get_content_id("air") local air = minetest.get_content_id("air")
local schems = {}
-- Place blocks where necessary -- Place blocks where necessary
internal.iter_3d_area(bminp, bmaxp, function (i, pos) internal.iter_3d_area(bminp, bmaxp, function (i, pos)
local function place(name)
local vi = vmanip:pos_to_index(pos) local vi = vmanip:pos_to_index(pos)
local function place(name)
if vmanip:get_index(vi) == air then if vmanip:get_index(vi) == air then
elseif type(name) == "string" then elseif type(name) == "string" then
@ -726,14 +727,6 @@ function internal.generate_caves(data, minp, maxp)
elseif nt == internal.node_types.stick_edge then elseif nt == internal.node_types.stick_edge then
elseif nt == internal.node_types.air then elseif nt == internal.node_types.air then
place("air") place("air")
elseif nt == internal.node_types.floor_deco then
for _, deco in ipairs(noordstar_caves.registered_decorations) do
if deco.place_on ~= "floor" then
elseif math.random() > deco.fill_ratio then
else
-- TODO: Check for biome
end
end
else else
-- Find appropriate biome -- Find appropriate biome
local heat = heat_points:get_index(i) local heat = heat_points:get_index(i)
@ -747,6 +740,32 @@ function internal.generate_caves(data, minp, maxp)
place(def.node_wall) place(def.node_wall)
elseif nt == internal.node_types.ceiling then elseif nt == internal.node_types.ceiling then
place(def.node_roof) place(def.node_roof)
elseif nt == internal.node_types.floor_deco then
local schem_placed = false
if not schem_placed then
-- Prevent decorations from spawning in the air
if vmanip:get_index(vi) == air then
schem_placed = true
end
end
if not schem_placed then
for _, deco in ipairs(noordstar_caves.registered_decorations) do
if deco.place_on ~= "floor" then
elseif math.random() > deco.fill_ratio then
elseif not internal.is_deco_biome(deco, def.name) then
else
table.insert(schems, { pos = pos, deco = deco })
schem_placed = true
break
end
end
end
if not schem_placed then
place(def.node_dust or "air")
end
else else
error( error(
table.concat( table.concat(
@ -763,7 +782,7 @@ function internal.generate_caves(data, minp, maxp)
end end
end) end)
return vmanip.arr return vmanip.arr, schems
end end
-- Get the noise params for the cave biome temperature. -- Get the noise params for the cave biome temperature.
@ -799,6 +818,23 @@ function internal.is_cave_node(noise, vastness)
return noise > 1 - vastness return noise > 1 - vastness
end end
-- Return whether a given decoration definition can spawn in a given biome name
function internal.is_deco_biome(def, biome_name)
if type(def.biomes) == "nil" then
return true
elseif type(def.biomes) == "string" then
return def.biomes == biome_name
elseif type(def.biomes) == "table" then
for _, name in pairs(def.biomes) do
if name == biome_name then
return true
end
end
end
return false
end
-- Return a bool whether a position is within a given volume -- Return a bool whether a position is within a given volume
function internal.is_valid_pos(pos, minp, maxp) function internal.is_valid_pos(pos, minp, maxp)
if minp.x <= pos.x and pos.x <= maxp.x then if minp.x <= pos.x and pos.x <= maxp.x then
@ -869,6 +905,80 @@ end
-- minetest.chat_send_all(os.time() .. " - " .. text) -- minetest.chat_send_all(os.time() .. " - " .. text)
-- end -- end
-- Place a table full of schematics into the world
function internal.place_schematics(schems)
for _, schem in ipairs(schems) do
local pos = schem.pos
local deco = schem.deco
if deco.deco_type == "simple" then
local h_min = deco.height
local h_max = math.max(deco.height_max, deco.height)
local dy = deco.place_offset_y - 1
if deco.place_on == "floor" then
for y = 1, math.random(h_min, h_max), 1 do
minetest.set_node(
{ x = pos.x, y = pos.y + y + dy, z = pos.z },
{ name = deco.decoration }
)
end
elseif deco.place_on == "ceiling" then
for y = 1, math.random(h_min, h_max), 1 do
minetest.set_node(
{ x = pos.x, y = pos.y - y - dy, z = pos.z },
{ name = deco.decoration }
)
end
else
error("Unknown place_on parameter `" .. deco.place_on .. "` for simple decoration!")
end
elseif deco.deco_type == "schematic" then
local name = deco.schematic
local force_placement = true
if string.find("force_placement", deco.flags) then
force_placement = true
end
if deco.place_on == "floor" then
local n = minetest.place_schematic(
pos, name, deco.rotation, deco.replacements,
force_placement, deco.flags
)
if type(n) == "nil" then
minetest.chat_send_all("Squeak could not load!")
else
minetest.chat_send_all("Placed a Squeak!")
if not tpd_yet then
minetest.get_player_by_name("singleplayer"):move_to(pos)
tpd_yet = true
minetest.chat_send_all(internal.pos_to_str(pos))
end
end
elseif deco.place_on == "ceiling" then
-- Aim to place schematic against the ceiling, not through it
local h = minetest.read_schematic(name).size.y
local c_pos = { x = pos.x, y = pos.y - h, z = pos.z }
if string.find("place_center_y", deco.flags) then
c_pos = pos
end
minetest.place_schematic(
pos, name, deco.rotation, deco.replacements,
force_placement, deco.flags
)
else
error("Unknown place_on parameter `" .. deco.place_on .. "` for simple decoration!")
end
else
error("Unknown decoration type `" .. deco.deco_type .. "`")
end
end
end
-- Helper function to convert a set of coordinates to a readable string -- Helper function to convert a set of coordinates to a readable string
function internal.pos_to_str(pos) function internal.pos_to_str(pos)
return "(" .. pos.x .. ", " .. pos.y .. ", " .. pos.z .. " )" return "(" .. pos.x .. ", " .. pos.y .. ", " .. pos.z .. " )"
@ -1090,13 +1200,17 @@ end
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
minetest.register_on_generated(function(minp, maxp, blockseed) minetest.register_on_generated(function(minp, maxp, blockseed)
math.randomseed(blockseed)
local vm = minetest.get_mapgen_object("voxelmanip") local vm = minetest.get_mapgen_object("voxelmanip")
local data = vm:get_data() local data = vm:get_data()
data = internal.generate_caves(data, minp, maxp) data, schems = internal.generate_caves(data, minp, maxp)
vm:set_data(data) vm:set_data(data)
vm:write_to_map() vm:write_to_map()
internal.place_schematics(schems)
end) end)
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
@ -1202,6 +1316,7 @@ noordstar_caves.register_biome({
node_floor = "mcl_core:crying_obsidian", node_floor = "mcl_core:crying_obsidian",
node_wall = "mcl_core:sand", node_wall = "mcl_core:sand",
node_roof = "mcl_ocean:sea_lantern", node_roof = "mcl_ocean:sea_lantern",
node_dust = "mcl_core:snow",
heat_point = 0, heat_point = 0,
humidity_point = 0, humidity_point = 0,
}) })
@ -1213,3 +1328,21 @@ noordstar_caves.register_biome({
heat_point = 100, heat_point = 100,
humidity_point = 100, humidity_point = 100,
}) })
noordstar_caves.register_decoration({
deco_type = "simple",
place_on = "floor",
fill_ratio = 0.01,
decoration = "mcl_core:cactus",
height = 3,
height_max = 8,
biomes = { "test" },
})
noordstar_caves.register_decoration({
deco_type = "schematic",
place_on = "floor",
fill_ratio = 0.005,
schematic = "test.mts",
rotation = "random",
place_offset_y = 5,
})