"Overgenerate" caverns to open up border regions (#11)
Previously, only nodes strictly within the map block were being carved out as open space. This meant that multi-node decorations (such as giant mushrooms) would collide with walls and ceilings that would be carved out by adjacent block generation later, leaving them sliced off. Now Subterrane carves out border regions too. Make note of the is_ground_content function, put all your decoration nodes into this to prevent them from being removed. Can't rely on just is_ground_function node properties for most situations, it's too simplistic.
This commit is contained in:
parent
28d1aa3634
commit
bd5b1d22c8
@ -30,6 +30,7 @@ cave_layer_def is a table of the form:
|
||||
columns = -- optional, a column_def table for producing truly enormous dripstone formations. See below for definition. Set to nil to disable columns.
|
||||
double_frequency = -- when set to true, uses the absolute value of the cavern field to determine where to place caverns instead. This effectively doubles the number of large non-connected caverns.
|
||||
on_decorate = -- optional, a function that is given a table of indices and a variety of other mapgen information so that it can place custom decorations on floors and ceilings. It is given the parameters (minp, maxp, seed, vm, cavern_data, area, data). See below for the cavern_data table's member definitions.
|
||||
is_ground_content = -- optional, a function that takes a content_id and returns true if caverns should be carved through that node type. If not provided it defaults to a "is_ground_content" test.
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -75,7 +75,6 @@ subterrane.register_stalagmite_nodes = function(base_name, base_node_def, drop_b
|
||||
base_node_def.drawtype = "nodebox"
|
||||
base_node_def.paramtype = "light"
|
||||
base_node_def.paramtype2 = "facedir"
|
||||
base_node_def.is_ground_content = true
|
||||
base_node_def.node_box = {type = "fixed"}
|
||||
|
||||
local def1 = deep_copy(base_node_def)
|
||||
|
140
init.lua
140
init.lua
@ -181,6 +181,15 @@ local clear_node_arrays = function()
|
||||
cavern_data.tunnel_ceiling_count = 0
|
||||
cavern_data.tunnel_floor_count = 0
|
||||
cavern_data.column_count = 0
|
||||
|
||||
-- for k,v in pairs(cavern_ceiling_nodes) do cavern_ceiling_nodes[k] = nil end
|
||||
-- for k,v in pairs(cavern_floor_nodes) do cavern_floor_nodes[k] = nil end
|
||||
-- for k,v in pairs(warren_ceiling_nodes) do warren_ceiling_nodes[k] = nil end
|
||||
-- for k,v in pairs(warren_floor_nodes) do warren_floor_nodes[k] = nil end
|
||||
-- for k,v in pairs(tunnel_ceiling_nodes) do tunnel_ceiling_nodes[k] = nil end
|
||||
-- for k,v in pairs(tunnel_floor_nodes) do tunnel_floor_nodes[k] = nil end
|
||||
-- for k,v in pairs(column_nodes) do column_nodes[k] = nil end
|
||||
|
||||
close_node_arrays()
|
||||
end
|
||||
|
||||
@ -202,6 +211,7 @@ end
|
||||
-- columns = -- optional, a column_def table for producing truly enormous dripstone formations. See below for definition. Set to nil to disable columns.
|
||||
-- double_frequency = -- when set to true, uses the absolute value of the cavern field to determine where to place caverns instead. This effectively doubles the number of large non-connected caverns.
|
||||
-- decorate = -- optional, a function that is given a table of indices and a variety of other mapgen information so that it can place custom decorations on floors and ceilings. It is given the parameters (minp, maxp, seed, vm, cavern_data, area, data). See below for the cavern_data table's member definitions.
|
||||
-- is_ground_content = -- optional, a function that takes a content_id and returns true if caverns should be carved through that node type. If not provided it defaults to a "is_ground_content" test.
|
||||
--}
|
||||
|
||||
-- column_def
|
||||
@ -315,11 +325,15 @@ subterrane.register_layer = function(cave_layer_def)
|
||||
c_warren_column = nil
|
||||
end
|
||||
|
||||
local is_ground_content = cave_layer_def.is_ground_content
|
||||
if is_ground_content == nil then
|
||||
is_ground_content = mapgen_helper.is_ground_content
|
||||
end
|
||||
|
||||
-- On generated
|
||||
----------------------------------------------------------------------------------
|
||||
|
||||
minetest.register_on_generated(function(minp, maxp, seed)
|
||||
|
||||
--if out of range of cave definition limits, abort
|
||||
if minp.y > YMAX or maxp.y < YMIN then
|
||||
return
|
||||
@ -336,8 +350,10 @@ minetest.register_on_generated(function(minp, maxp, seed)
|
||||
end
|
||||
|
||||
local vm, data, data_param2, area = mapgen_helper.mapgen_vm_data_param2()
|
||||
local nvals_cave, cave_area = mapgen_helper.perlin3d("subterrane:cave", minp, maxp, np_cave) --cave noise for structure
|
||||
local nvals_wave = mapgen_helper.perlin3d("subterrane:wave", minp, maxp, np_wave) --wavy structure of cavern ceilings and floors
|
||||
local emin = area.MinEdge
|
||||
local emax = area.MaxEdge
|
||||
local nvals_cave, cave_area = mapgen_helper.perlin3d("subterrane:cave", emin, emax, np_cave) --cave noise for structure
|
||||
local nvals_wave = mapgen_helper.perlin3d("subterrane:wave", emin, emax, np_wave) --wavy structure of cavern ceilings and floors
|
||||
|
||||
-- pre-average everything so that the final values can be passed
|
||||
-- along to the decorate function if it wants them
|
||||
@ -350,12 +366,9 @@ minetest.register_on_generated(function(minp, maxp, seed)
|
||||
local warrens_uninitialized = true
|
||||
local nvals_warrens
|
||||
|
||||
-- The interp_yxz iterator iterates upwards in columns along the y axis.
|
||||
-- starts at miny, goes to maxy, then switches to a new x,z and repeats.
|
||||
local cave_iterator = cave_area:iterp_yxz(minp, maxp)
|
||||
|
||||
local previous_y = minp.y
|
||||
local previous_y = emin.y
|
||||
local previous_node_state = outside_region
|
||||
local this_node_state = outside_region
|
||||
|
||||
local column_points = nil
|
||||
local column_weight = nil
|
||||
@ -367,14 +380,22 @@ minetest.register_on_generated(function(minp, maxp, seed)
|
||||
cavern_data.cave_area = cave_area
|
||||
cavern_data.cavern_def = cave_layer_def
|
||||
|
||||
for vi, x, y, z in area:iterp_yxz(minp, maxp) do
|
||||
local vi3d = cave_iterator() -- for use with noise data
|
||||
-- The interp_yxz iterator iterates upwards in columns along the y axis.
|
||||
-- starts at miny, goes to maxy, then switches to a new x,z and repeats.
|
||||
for vi, x, y, z in area:iterp_yxz(emin, emax) do
|
||||
-- We're "over-generating" when carving out the empty space of the cave volume so that decorations
|
||||
-- can slop over the boundaries of the mapblock without being cut off.
|
||||
-- We only want to add vi to the various decoration node lists if we're actually whithin the mapblock.
|
||||
local is_within_current_mapblock = mapgen_helper.is_pos_within_box({x=x, y=y, z=z}, minp, maxp)
|
||||
|
||||
if y < previous_y then
|
||||
-- we've switched to a new column
|
||||
previous_node_state = outside_region
|
||||
else
|
||||
previous_node_state = this_node_state
|
||||
end
|
||||
previous_y = y
|
||||
this_node_state = inside_ground
|
||||
|
||||
local cave_local_threshold
|
||||
if y < y_blend_min then
|
||||
@ -385,7 +406,7 @@ minetest.register_on_generated(function(minp, maxp, seed)
|
||||
cave_local_threshold = TCAVE
|
||||
end
|
||||
|
||||
local cave_value = nvals_cave[vi3d]
|
||||
local cave_value = nvals_cave[vi]
|
||||
if double_frequency then
|
||||
if cave_value < 0 then
|
||||
cave_value = -cave_value
|
||||
@ -407,24 +428,25 @@ minetest.register_on_generated(function(minp, maxp, seed)
|
||||
local column_value = 0
|
||||
if column_def then
|
||||
if column_points == nil then
|
||||
column_points = subterrane.get_column_points(minp, maxp, column_def)
|
||||
column_points = subterrane.get_column_points(emin, maxp, column_def)
|
||||
column_weight = column_def.weight
|
||||
end
|
||||
column_value = subterrane.get_column_value({x=x, y=y, z=z}, column_points)
|
||||
end
|
||||
|
||||
if column_value > 0 and cave_value - column_value * column_weight < cave_local_threshold then
|
||||
if is_ground_content(data[vi]) then
|
||||
data[vi] = c_column -- add a column node
|
||||
previous_node_state = inside_column
|
||||
else
|
||||
data[vi] = c_cavern_air --hollow it out to make the cave
|
||||
cavern_data.contains_cavern = true
|
||||
if previous_node_state == inside_ground then
|
||||
-- we just entered the cavern from below
|
||||
cavern_data.cavern_floor_count = cavern_data.cavern_floor_count + 1
|
||||
cavern_floor_nodes[cavern_data.cavern_floor_count] = vi - area.ystride
|
||||
end
|
||||
previous_node_state = inside_cavern
|
||||
this_node_state = inside_column
|
||||
else
|
||||
if is_ground_content(data[vi]) then
|
||||
data[vi] = c_cavern_air --hollow it out to make the cave
|
||||
end
|
||||
this_node_state = inside_cavern
|
||||
if is_within_current_mapblock then
|
||||
cavern_data.contains_cavern = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -437,11 +459,11 @@ minetest.register_on_generated(function(minp, maxp, seed)
|
||||
if cave_value <= cave_local_threshold and cave_value > warren_area_threshold then
|
||||
|
||||
if warren_area_uninitialized then
|
||||
nvals_warren_area = mapgen_helper.perlin3d("subterrane:warren_area", minp, maxp, np_warren_area) -- determine which areas are spongey with warrens
|
||||
nvals_warren_area = mapgen_helper.perlin3d("subterrane:warren_area", emin, emax, np_warren_area) -- determine which areas are spongey with warrens
|
||||
warren_area_uninitialized = false
|
||||
end
|
||||
|
||||
local warren_area_value = nvals_warren_area[vi3d]
|
||||
local warren_area_value = nvals_warren_area[vi]
|
||||
if warren_area_value > warren_area_variability_threshold then
|
||||
-- we're in a warren-containing area
|
||||
if solidify_lava and c_lava_set[data[vi]] then
|
||||
@ -449,7 +471,7 @@ minetest.register_on_generated(function(minp, maxp, seed)
|
||||
end
|
||||
|
||||
if warrens_uninitialized then
|
||||
nvals_warrens = mapgen_helper.perlin3d("subterrane:warrens", minp, maxp, np_warrens) --spongey warrens
|
||||
nvals_warrens = mapgen_helper.perlin3d("subterrane:warrens", emin, emax, np_warrens) --spongey warrens
|
||||
warrens_uninitialized = false
|
||||
end
|
||||
|
||||
@ -458,14 +480,14 @@ minetest.register_on_generated(function(minp, maxp, seed)
|
||||
local cave_value_edge = math.min(1, (cave_value - warren_area_threshold) * 20) -- make 0.3 = 0 and 0.25 = 1 to produce a border gradient
|
||||
local warren_area_value_edge = math.min(1, warren_area_value * 50) -- make 0 = 0 and 0.02 = 1 to produce a border gradient
|
||||
|
||||
local warren_value = nvals_warrens[vi3d]
|
||||
local warren_value = nvals_warrens[vi]
|
||||
local warren_local_threshold = warren_threshold + (2 - warren_area_value_edge - cave_value_edge)
|
||||
if warren_value > warren_local_threshold then
|
||||
|
||||
local column_value = 0
|
||||
if column_def then
|
||||
if column_points == nil then
|
||||
column_points = subterrane.get_column_points(minp, maxp, column_def)
|
||||
column_points = subterrane.get_column_points(emin, emax, column_def)
|
||||
column_weight = column_def.weight
|
||||
end
|
||||
column_value = subterrane.get_column_value({x=x, y=y, z=z}, column_points)
|
||||
@ -473,18 +495,19 @@ minetest.register_on_generated(function(minp, maxp, seed)
|
||||
|
||||
if column_value > 0 and column_value + (warren_local_threshold - warren_value) * column_weight > 0 then
|
||||
if c_warren_column then
|
||||
if is_ground_content(data[vi]) then
|
||||
data[vi] = c_warren_column -- add a column node
|
||||
previous_node_state = inside_column
|
||||
end
|
||||
this_node_state = inside_column
|
||||
end
|
||||
else
|
||||
if is_ground_content(data[vi]) then
|
||||
data[vi] = c_warren_air --hollow it out to make the cave
|
||||
cavern_data.contains_warren = true
|
||||
if previous_node_state == inside_ground then
|
||||
-- we just entered the warren from below
|
||||
cavern_data.warren_floor_count = cavern_data.warren_floor_count + 1
|
||||
warren_floor_nodes[cavern_data.warren_floor_count] = vi - area.ystride
|
||||
end
|
||||
previous_node_state = inside_warren
|
||||
if is_within_current_mapblock then
|
||||
cavern_data.contains_warren = true
|
||||
end
|
||||
this_node_state = inside_warren
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -493,20 +516,37 @@ minetest.register_on_generated(function(minp, maxp, seed)
|
||||
-- If decorate is defined, we want to track all this stuff
|
||||
if decorate ~= nil then
|
||||
local c_current_node = data[vi]
|
||||
local current_node_is_open = mapgen_helper.buildable_to(c_current_node)
|
||||
local current_node_is_open = c_current_node == c_air -- mapgen_helper.buildable_to(c_current_node)
|
||||
if current_node_is_open and this_node_state == inside_ground then
|
||||
-- we're in a preexisting open space (tunnel).
|
||||
this_node_state = inside_tunnel
|
||||
end
|
||||
|
||||
if previous_node_state == inside_column then
|
||||
-- in this case previous node state is actually current node state,
|
||||
-- we placed a column node during this loop
|
||||
if is_within_current_mapblock then
|
||||
if this_node_state == inside_column then
|
||||
cavern_data.column_count = cavern_data.column_count + 1
|
||||
column_nodes[cavern_data.column_count] = vi
|
||||
elseif previous_node_state == inside_ground and current_node_is_open then
|
||||
-- we just entered a tunnel from below
|
||||
elseif previous_node_state ~= this_node_state and previous_node_state ~= inside_column then
|
||||
if previous_node_state == inside_ground then
|
||||
if this_node_state == inside_tunnel then
|
||||
-- we just entered a tunnel from below.
|
||||
cavern_data.tunnel_floor_count = cavern_data.tunnel_floor_count + 1
|
||||
tunnel_floor_nodes[cavern_data.tunnel_floor_count] = vi-area.ystride
|
||||
previous_node_state = inside_tunnel
|
||||
elseif previous_node_state ~= inside_ground and not current_node_is_open then
|
||||
if previous_node_state == inside_cavern then
|
||||
elseif this_node_state == inside_cavern then
|
||||
-- we just entered the cavern from below
|
||||
cavern_data.cavern_floor_count = cavern_data.cavern_floor_count + 1
|
||||
cavern_floor_nodes[cavern_data.cavern_floor_count] = vi - area.ystride
|
||||
elseif this_node_state == inside_warren then
|
||||
-- we just entered the warren from below
|
||||
cavern_data.warren_floor_count = cavern_data.warren_floor_count + 1
|
||||
warren_floor_nodes[cavern_data.warren_floor_count] = vi - area.ystride
|
||||
end
|
||||
elseif this_node_state == inside_ground then
|
||||
if previous_node_state == inside_tunnel then
|
||||
-- we just left a tunnel from below
|
||||
cavern_data.tunnel_ceiling_count = cavern_data.tunnel_ceiling_count + 1
|
||||
tunnel_ceiling_nodes[cavern_data.tunnel_ceiling_count] = vi
|
||||
elseif previous_node_state == inside_cavern then
|
||||
--we just left the cavern from below
|
||||
cavern_data.cavern_ceiling_count = cavern_data.cavern_ceiling_count + 1
|
||||
cavern_ceiling_nodes[cavern_data.cavern_ceiling_count] = vi
|
||||
@ -514,22 +554,10 @@ minetest.register_on_generated(function(minp, maxp, seed)
|
||||
--we just left the cavern from below
|
||||
cavern_data.warren_ceiling_count = cavern_data.warren_ceiling_count + 1
|
||||
warren_ceiling_nodes[cavern_data.warren_ceiling_count] = vi
|
||||
elseif previous_node_state == inside_tunnel then
|
||||
-- we just left a tunnel from below
|
||||
cavern_data.tunnel_ceiling_count = cavern_data.tunnel_ceiling_count + 1
|
||||
tunnel_ceiling_nodes[cavern_data.tunnel_ceiling_count] = vi
|
||||
end
|
||||
|
||||
-- if we laid down a column node we don't want to switch to "inside ground",
|
||||
-- if we hit air next node then it'll get flagged as a floor node and we don't want that for columns
|
||||
if previous_node_state ~= inside_column then
|
||||
previous_node_state = inside_ground
|
||||
end
|
||||
end
|
||||
else
|
||||
-- This will prevent any values from being inserted into the node lists, saving
|
||||
-- a bunch of memory and processor time
|
||||
previous_node_state = outside_region
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
local enable_legacy = minetest.setting_getbool("subterrane_enable_legacy_dripstone")
|
||||
|
||||
if enable_legacy == nil or enable_legacy == true then
|
||||
if enable_legacy then
|
||||
|
||||
subterrane.register_stalagmite_nodes("subterrane:dry_stal", {
|
||||
description = "Dry Dripstone",
|
||||
@ -18,7 +18,6 @@ minetest.register_node("subterrane:dry_flowstone", {
|
||||
description = "Dry Flowstone",
|
||||
tiles = {"default_stone.png^[brighten"},
|
||||
groups = {cracky = 3, stone = 1},
|
||||
is_ground_content = true,
|
||||
drop = 'default:cobble',
|
||||
sounds = default.node_sound_stone_defaults(),
|
||||
})
|
||||
@ -38,7 +37,6 @@ minetest.register_node("subterrane:wet_flowstone", {
|
||||
description = "Wet Flowstone",
|
||||
tiles = {"default_stone.png^[brighten^subterrane_dripstone_streaks.png"},
|
||||
groups = {cracky = 3, stone = 1, subterrane_wet_dripstone = 1},
|
||||
is_ground_content = true,
|
||||
drop = 'default:cobble',
|
||||
sounds = default.node_sound_stone_defaults(),
|
||||
})
|
||||
@ -435,7 +433,7 @@ end
|
||||
local grid_size = mapgen_helper.block_size * 4
|
||||
|
||||
function subterrane:vertically_consistent_randomp(pos)
|
||||
local next_seed = math.random(1, 2^31)
|
||||
local next_seed = math.floor(math.random() * 2^31)
|
||||
math.randomseed(minetest.hash_node_position({x=pos.x, y=0, z=pos.z}))
|
||||
local output = math.random()
|
||||
math.randomseed(next_seed)
|
||||
|
3
mod.conf
3
mod.conf
@ -1 +1,4 @@
|
||||
name = subterrane
|
||||
description = A mapgen helper mod that facilitates the creation of vast underground caverns
|
||||
depends = default, mapgen_helper
|
||||
optional_depends = intllib
|
BIN
screenshot.png
BIN
screenshot.png
Binary file not shown.
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 10 KiB |
@ -1,3 +1,3 @@
|
||||
subterrane_enable_legacy_dripstone (Adds old dripstone node definitions) bool true
|
||||
subterrane_enable_legacy_dripstone (Adds old dripstone node definitions) bool false
|
||||
#Use this mode with singlenode mapgen to produce a large-scale map of a particular world's caverns
|
||||
subterrane_enable_singlenode_mapping_mode (Fills cavern volume with stone and warrens with desertstone) bool false
|
Binary file not shown.
Before Width: | Height: | Size: 465 B After Width: | Height: | Size: 381 B |
Loading…
x
Reference in New Issue
Block a user