Add biome optimizations + decorations
parent
6b38a7d7b2
commit
99e9753772
413
init.lua
413
init.lua
|
@ -63,63 +63,57 @@ function internal.cave_vastness(pos)
|
|||
end
|
||||
|
||||
-- Classify all nodes in the chunk into what they are
|
||||
-- TODO: Perhaps instead of iterating over ALL nodes, we can sort all node types
|
||||
-- TODO: into separate tables, effectively allowing us to process the nodes
|
||||
-- TODO: independently, saving computation time.
|
||||
function internal.classify_nodes(used_shapes, minp, maxp)
|
||||
local sminp = vector.offset(minp, 1, 1, 1)
|
||||
local smaxp = vector.offset(maxp, -1, -1, -1)
|
||||
local sva = VoxelArea(sminp, smaxp)
|
||||
local va = VoxelArea(minp, maxp)
|
||||
|
||||
local items = {}
|
||||
local ceiling_decos = {}
|
||||
local ceilings = {}
|
||||
local contents = {}
|
||||
local floor_decos = {}
|
||||
local floors = {}
|
||||
local walls = {}
|
||||
|
||||
for i in sva:iterp(sminp, smaxp) do
|
||||
|
||||
local pos = sva:position(i)
|
||||
local bi = va:index(pos.x, pos.y, pos.z)
|
||||
|
||||
local function is_part_of_cave(v)
|
||||
return used_shapes[va:index(v.x, v.y, v.z)]
|
||||
end
|
||||
|
||||
if used_shapes[bi] == true then
|
||||
if used_shapes[va:index(pos.x, pos.y, pos.z)] == true then
|
||||
-- Part of cave
|
||||
if not used_shapes[va:index(pos.x, pos.y + 1, pos.z)] then
|
||||
items[i] = ENUM_CEILING_DECORATION
|
||||
table.insert(ceiling_decos, i)
|
||||
elseif not used_shapes[va:index(pos.x, pos.y - 1, pos.z)] then
|
||||
items[i] = ENUM_FLOOR_DECORATION
|
||||
table.insert(floor_decos, i)
|
||||
else
|
||||
items[i] = ENUM_AIR
|
||||
table.insert(contents, i)
|
||||
end
|
||||
else
|
||||
-- Not part of cave
|
||||
if used_shapes[va:index(pos.x, pos.y + 1, pos.z)] then
|
||||
items[i] = ENUM_FLOOR
|
||||
table.insert(floors, i)
|
||||
elseif used_shapes[va:index(pos.x, pos.y - 1, pos.z)] then
|
||||
items[i] = ENUM_CEILING
|
||||
table.insert(ceilings, i)
|
||||
elseif used_shapes[va:index(pos.x - 1, pos.y, pos.z)] then
|
||||
items[i] = ENUM_WALL
|
||||
table.insert(walls, i)
|
||||
elseif used_shapes[va:index(pos.x + 1, pos.y, pos.z)] then
|
||||
items[i] = ENUM_WALL
|
||||
table.insert(walls, i)
|
||||
elseif used_shapes[va:index(pos.x, pos.y, pos.z - 1)] then
|
||||
items[i] = ENUM_WALL
|
||||
table.insert(walls, i)
|
||||
elseif used_shapes[va:index(pos.x, pos.y, pos.z + 1)] then
|
||||
items[i] = ENUM_WALL
|
||||
else
|
||||
items[i] = ENUM_STONE
|
||||
table.insert(walls, i)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local custom_y = -13
|
||||
if sminp.y < custom_y and custom_y < smaxp.y then
|
||||
for i in sva:iterp({ x = sminp.x, y = custom_y, z = sminp.z }, { x = smaxp.x, y = custom_y, z = smaxp.z }) do
|
||||
items[i] = ENUM_CEILING
|
||||
end
|
||||
end
|
||||
|
||||
return items
|
||||
return {
|
||||
ceiling_decos = ceiling_decos,
|
||||
ceilings = ceilings,
|
||||
contents = contents,
|
||||
floor_decos = floor_decos,
|
||||
floors = floors,
|
||||
walls = walls,
|
||||
}
|
||||
end
|
||||
|
||||
function internal.clean_biome_def(def)
|
||||
|
@ -156,6 +150,41 @@ function internal.clean_biome_def(def)
|
|||
return def
|
||||
end
|
||||
|
||||
function internal.clean_deco_def(def)
|
||||
def.deco_type = def.deco_type or "simple"
|
||||
def.place_on = def.place_on or "floor"
|
||||
def.y_min = def.y_min or WORLD_MINP.y
|
||||
def.y_max = def.y_max or WORLD_MAXP.y
|
||||
|
||||
assert(def.deco_type == "simple" or def.deco_type == "schematic")
|
||||
assert(def.place_on == "floor" or def.place_on == "ceiling")
|
||||
assert(type(def.fill_ratio) == "number")
|
||||
assert(def.biomes == nil or type(def.biomes) == "table")
|
||||
|
||||
if def.deco_type == "simple" then
|
||||
def.height = def.height or 1
|
||||
def.height_max = def.height_max or def.height
|
||||
def.place_offset_y = def.place_offset_y or 0
|
||||
|
||||
assert(type(def.deco_type) == "string")
|
||||
assert(type(def.height) == "number")
|
||||
assert(type(def.height_max) == "number")
|
||||
assert(type(def.place_offset_y) == "number")
|
||||
|
||||
elseif def.deco_type == "schematic" then
|
||||
def.replacements = def.replacements or {}
|
||||
def.place_offset_y = def.place_offset_y or 0
|
||||
|
||||
assert(type(def.schematic) == "string" or type(def.schematic) == "table")
|
||||
assert(type(def.replacements) == "table")
|
||||
|
||||
assert(def.rotation == "0" or def.rotation == "90" or def.rotation == "180" or def.rotation == "270" or def.rotation == "random")
|
||||
assert(type(def.place_offset_y) == "number")
|
||||
end
|
||||
|
||||
return def
|
||||
end
|
||||
|
||||
function internal.clean_shape_def(def)
|
||||
assert(
|
||||
type(def) == "table",
|
||||
|
@ -455,13 +484,52 @@ function internal.mapgen(minp, maxp, blockseed, vm, va)
|
|||
|
||||
-- Manipulate `data` table by adding classified nodes based on which biome
|
||||
-- they're in.
|
||||
local sva = VoxelArea(minp, maxp)
|
||||
local data = vm:get_data()
|
||||
|
||||
internal.write_classified_biome_nodes(
|
||||
data, va, classified_nodes, used_biomes, minp, maxp
|
||||
internal.write_classified_node(
|
||||
data, va, used_biomes, classified_nodes.ceilings, sva, "node_roof"
|
||||
)
|
||||
internal.write_classified_node(
|
||||
data, va, used_biomes, classified_nodes.contents, sva, "node_air"
|
||||
)
|
||||
internal.write_classified_node(
|
||||
data, va, used_biomes, classified_nodes.floors, sva, "node_floor"
|
||||
)
|
||||
internal.write_classified_node(
|
||||
data, va, used_biomes, classified_nodes.walls, sva, "node_wall"
|
||||
)
|
||||
|
||||
-- Place floor decorations
|
||||
-- In case the dust has not been defined, place air nodes first
|
||||
internal.write_classified_node(
|
||||
data, va, used_biomes, classified_nodes.floor_decos, sva, "node_air"
|
||||
)
|
||||
internal.write_classified_node(
|
||||
data, va, used_biomes, classified_nodes.floor_decos, sva, "node_dust"
|
||||
)
|
||||
local claimed_floor = internal.write_simple_floor_decorations(
|
||||
data, va, used_biomes, classified_nodes.floor_decos, sva
|
||||
)
|
||||
|
||||
-- Place ceiling decorations
|
||||
internal.write_classified_node(
|
||||
data, va, used_biomes, classified_nodes.ceiling_decos, sva, "node_air"
|
||||
)
|
||||
local claimed_ceiling = internal.write_simple_ceiling_decorations(
|
||||
data, va, used_biomes, classified_nodes.ceiling_decos, sva
|
||||
)
|
||||
|
||||
vm:set_data(data)
|
||||
|
||||
-- Set schematic decorations
|
||||
internal.write_schematic_floor_decoration(
|
||||
vm, used_biomes, classified_nodes.floor_decos, sva, claimed_floor
|
||||
)
|
||||
internal.write_schematic_ceiling_decoration(
|
||||
vm, used_biomes, classified_nodes.ceiling_decos, sva, claimed_ceiling
|
||||
)
|
||||
|
||||
vm:write_to_map()
|
||||
end
|
||||
|
||||
|
@ -486,6 +554,14 @@ function internal.register_biome(biome)
|
|||
ns_caves.registered_biomes[biome.name] = biome
|
||||
end
|
||||
|
||||
-- Register a new decoration
|
||||
function internal.register_decoration(deco)
|
||||
table.insert(
|
||||
ns_caves.registered_decorations,
|
||||
internal.clean_deco_def(deco)
|
||||
)
|
||||
end
|
||||
|
||||
-- Register a new shape
|
||||
function internal.register_shape(shape)
|
||||
shape = internal.clean_shape_def(shape)
|
||||
|
@ -530,57 +606,242 @@ function internal.verticality_noise_params()
|
|||
}
|
||||
end
|
||||
|
||||
function internal.write_classified_biome_nodes(vm_data, va, classified_nodes, used_biomes, minp, maxp)
|
||||
local small_va = VoxelArea(minp, maxp)
|
||||
|
||||
-- assert(#classified_nodes == #used_biomes)
|
||||
-- assert(#classified_nodes == small_va:getVolume())
|
||||
|
||||
function internal.write_classified_node(vm_data, va, used_biomes, classified_nodes, small_va, biome_key)
|
||||
local default_biome = internal.default_biome()
|
||||
local schems = {}
|
||||
|
||||
for i in va:iterp(minp, maxp) do
|
||||
local pos = va:position(i)
|
||||
local si = small_va:index(pos.x, pos.y, pos.z)
|
||||
local biome_to_id = {}
|
||||
biome_to_id[default_biome.name] = default_biome[biome_key] or ""
|
||||
|
||||
local node_type = classified_nodes[si]
|
||||
local biome = used_biomes[si]
|
||||
for _, i in ipairs(classified_nodes) do
|
||||
local pos = small_va:position(i)
|
||||
local biome = used_biomes[i] or default_biome.name
|
||||
|
||||
if biome == nil then
|
||||
biome = default_biome
|
||||
else
|
||||
biome = ns_caves.registered_biomes[biome] or default_biome
|
||||
if biome_to_id[biome] == nil then
|
||||
local biome_def
|
||||
|
||||
if biome == default_biome.name then
|
||||
biome_def = default_biome
|
||||
else
|
||||
biome_def = ns_caves.registered_biomes[biome] or default_biome
|
||||
end
|
||||
|
||||
if biome_def[biome_key] == nil then
|
||||
biome_to_id[biome] = ""
|
||||
else
|
||||
biome_to_id[biome] = minetest.get_content_id(biome_def[biome_key]) or ""
|
||||
end
|
||||
end
|
||||
|
||||
if node_type == ENUM_AIR then
|
||||
internal.place_node_on_data(vm_data, i, biome.node_air)
|
||||
elseif node_type == ENUM_CEILING then
|
||||
internal.place_node_on_data(vm_data, i, biome.node_roof)
|
||||
elseif node_type == ENUM_CEILING_DECORATION then
|
||||
-- TODO: Return schematics to be placed
|
||||
internal.place_node_on_data(vm_data, i, biome.node_air)
|
||||
elseif node_type == ENUM_FLOOR then
|
||||
internal.place_node_on_data(vm_data, i, biome.node_floor)
|
||||
elseif node_type == ENUM_FLOOR_DECORATION then
|
||||
-- TODO: Return schematics to be placed
|
||||
internal.place_node_on_data(vm_data, i, biome.node_air)
|
||||
elseif node_type == ENUM_STONE then
|
||||
-- Nothing needs to be placed
|
||||
elseif node_type == ENUM_WALL then
|
||||
internal.place_node_on_data(vm_data, i, biome.node_wall)
|
||||
else
|
||||
if node_type == nil then
|
||||
error(
|
||||
"Expected enum value, encountered nil at index " .. si .. " (originally " .. i .. ")"
|
||||
)
|
||||
local content_id = biome_to_id[biome]
|
||||
|
||||
if content_id ~= "" then
|
||||
vm_data[va:index(pos.x, pos.y, pos.z)] = content_id
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function internal.write_schematic_ceiling_decoration(vmanip, used_biomes, classified_nodes, sva, claimed_spots)
|
||||
for _, def in pairs(ns_caves.registered_decorations) do
|
||||
if def.deco_type == "schematic" and def.place_on == "ceiling" then
|
||||
-- Place the decoration, if they're in the appropriate biome
|
||||
for _, i in ipairs(classified_nodes) do
|
||||
local good_biome = def.biomes == nil
|
||||
local unclaimed_spot = true
|
||||
|
||||
for _, ci in ipairs(claimed_spots) do
|
||||
if ci == i then
|
||||
unclaimed_spot = false
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if unclaimed_spot and not good_biome then
|
||||
local current_biome = used_biomes[i]
|
||||
for _, name in ipairs(def.biomes) do
|
||||
if name == current_biome then
|
||||
good_biome = true
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if unclaimed_spot and good_biome and math.random() < def.fill_ratio then
|
||||
-- Automatically place the top at the top of the cave
|
||||
local pos = sva:position(i)
|
||||
local h = def.schematic
|
||||
|
||||
if type(def.schematic) == "string" then
|
||||
h = minetest.read_schematic(h, {})
|
||||
|
||||
if type(h) == "nil" then
|
||||
error("Could not find schematic! Perhaps it the filename is incorrect?")
|
||||
end
|
||||
end
|
||||
|
||||
h = h.size.y
|
||||
|
||||
minetest.place_schematic_on_vmanip(vmanip,
|
||||
{ x = pos.x, y = pos.y - h + 1 + def.place_offset_y, z = pos.z },
|
||||
def.schematic, def.rotation, def.replacement, true,
|
||||
def.flags
|
||||
)
|
||||
|
||||
table.insert(claimed_spots, i)
|
||||
end
|
||||
end
|
||||
error(
|
||||
"Encountered unknown node type enum value " .. node_type
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
return schems
|
||||
return claimed_spots
|
||||
end
|
||||
|
||||
function internal.write_schematic_floor_decoration(vmanip, used_biomes, classified_nodes, sva, claimed_spots)
|
||||
for _, def in pairs(ns_caves.registered_decorations) do
|
||||
if def.deco_type == "schematic" and def.place_on == "floor" then
|
||||
-- Place the decoration, if they're in the appropriate biome
|
||||
for _, i in ipairs(classified_nodes) do
|
||||
local good_biome = def.biomes == nil
|
||||
local unclaimed_spot = true
|
||||
|
||||
for _, ci in ipairs(claimed_spots) do
|
||||
if ci == i then
|
||||
unclaimed_spot = false
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if unclaimed_spot and not good_biome then
|
||||
local current_biome = used_biomes[i]
|
||||
for _, name in ipairs(def.biomes) do
|
||||
if name == current_biome then
|
||||
good_biome = true
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if unclaimed_spot and good_biome and math.random() < def.fill_ratio then
|
||||
minetest.place_schematic_on_vmanip(
|
||||
vmanip, sva:position(i), def.schematic, def.rotation,
|
||||
def.replacement, true, def.flags
|
||||
)
|
||||
|
||||
table.insert(claimed_spots, i)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return claimed_spots
|
||||
end
|
||||
|
||||
function internal.write_simple_ceiling_decorations(vm_data, va, used_biomes, classified_nodes, sva)
|
||||
local claimed_spots = {}
|
||||
|
||||
for _, def in pairs(ns_caves.registered_decorations) do
|
||||
if def.deco_type == "simple" and def.place_on == "ceiling" then
|
||||
-- Place the decoration, if they're in the appropriate biome.
|
||||
for _, i in ipairs(classified_nodes) do
|
||||
local pos = sva:position(i)
|
||||
local good_biome = def.biomes == nil
|
||||
local unclaimed_spot = true
|
||||
|
||||
for _, ci in ipairs(claimed_spots) do
|
||||
if ci == i then
|
||||
unclaimed_spot = false
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if not good_biome and unclaimed_spot then
|
||||
local current_biome = used_biomes[i]
|
||||
for _, name in ipairs(def.biomes) do
|
||||
if name == current_biome then
|
||||
good_biome = true
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if unclaimed_spot and good_biome and math.random() < def.fill_ratio then
|
||||
-- Determine the height
|
||||
local height = def.height
|
||||
if def.height_max > height then
|
||||
height = math.min(
|
||||
16, math.random(def.height, def.height_max)
|
||||
)
|
||||
end
|
||||
|
||||
-- Place the structure!
|
||||
for h = 1, height, 1 do
|
||||
local y = pos.y - h + def.place_offset_y + 1
|
||||
|
||||
if sva:contains(pos.x, y, pos.z) then
|
||||
vm_data[va:index(pos.x, y, pos.z)] = minetest.get_content_id(def.decoration)
|
||||
end
|
||||
end
|
||||
|
||||
table.insert(claimed_spots, i)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return claimed_spots
|
||||
end
|
||||
function internal.write_simple_floor_decorations(vm_data, va, used_biomes, classified_nodes, sva)
|
||||
local claimed_spots = {}
|
||||
|
||||
for _, def in pairs(ns_caves.registered_decorations) do
|
||||
if def.deco_type == "simple" and def.place_on == "floor" then
|
||||
-- Place the decoration, if they're in the appropriate biome.
|
||||
for _, i in ipairs(classified_nodes) do
|
||||
local pos = sva:position(i)
|
||||
local good_biome = def.biomes == nil
|
||||
local unclaimed_spot = true
|
||||
|
||||
for _, ci in ipairs(claimed_spots) do
|
||||
if ci == i then
|
||||
unclaimed_spot = false
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if unclaimed_spot and not good_biome then
|
||||
local current_biome = used_biomes[i]
|
||||
for _, name in ipairs(def.biomes) do
|
||||
if name == current_biome then
|
||||
good_biome = true
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if unclaimed_spot and good_biome and math.random() < def.fill_ratio then
|
||||
-- Determine the height
|
||||
local height = def.height
|
||||
if def.height_max > height then
|
||||
height = math.min(
|
||||
16, math.random(def.height, def.height_max)
|
||||
)
|
||||
end
|
||||
|
||||
-- Place the structure!
|
||||
for h = 1, height, 1 do
|
||||
local y = pos.y + h + def.place_offset_y - 1
|
||||
|
||||
if sva:contains(pos.x, y, pos.z) then
|
||||
vm_data[va:index(pos.x, y, pos.z)] = minetest.get_content_id(def.decoration)
|
||||
end
|
||||
end
|
||||
|
||||
table.insert(claimed_spots, i)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return claimed_spots
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
@ -597,6 +858,8 @@ minetest.register_on_generated(function(minp, maxp, blockseed)
|
|||
local vm = minetest.get_mapgen_object("voxelmanip")
|
||||
local va = VoxelArea(vm:get_emerged_area())
|
||||
|
||||
math.randomseed(blockseed)
|
||||
|
||||
internal.mapgen(minp, maxp, blockseed, vm, va)
|
||||
end)
|
||||
|
||||
|
@ -613,10 +876,14 @@ ns_caves = {
|
|||
|
||||
register_biome = internal.register_biome,
|
||||
|
||||
register_decoration = internal.register_decoration,
|
||||
|
||||
register_shape = internal.register_shape,
|
||||
|
||||
registered_biomes = {},
|
||||
|
||||
registered_decorations = {},
|
||||
|
||||
registered_shapes = {},
|
||||
}
|
||||
|
||||
|
|
|
@ -44,3 +44,41 @@ ns_caves.register_biome({
|
|||
heat_point = 0,
|
||||
humidity_point = 50,
|
||||
})
|
||||
|
||||
ns_caves.register_biome({
|
||||
name = "ns_caves:drip",
|
||||
node_floor = "dripstone:dry_dripstone_block",
|
||||
node_wall = "dripstone:dry_dripstone_block",
|
||||
node_roof = "dripstone:dry_dripstone_block",
|
||||
heat_point = 50,
|
||||
humidity_point = 0,
|
||||
})
|
||||
|
||||
ns_caves.register_decoration({
|
||||
deco_type = "simple",
|
||||
place_on = "ceiling",
|
||||
fill_ratio = 0.25,
|
||||
biomes = { "ns_caves:snow" },
|
||||
decoration = "mcl_core:water_source",
|
||||
height = 1,
|
||||
place_offset_y = 2,
|
||||
})
|
||||
|
||||
ns_caves.register_decoration({
|
||||
deco_type = "simple",
|
||||
place_on = "ceiling",
|
||||
fill_ratio = 0.025,
|
||||
decoration = "mcl_bamboo:bamboo_block",
|
||||
height = 3,
|
||||
height_max = 16,
|
||||
})
|
||||
|
||||
ns_caves.register_decoration({
|
||||
deco_type = "simple",
|
||||
place_on = "floor",
|
||||
fill_ratio = 0.025,
|
||||
decoration = "mcl_bamboo:bamboo_block",
|
||||
height = 3,
|
||||
height_max = 16,
|
||||
})
|
||||
|
||||
|
|
Loading…
Reference in New Issue