Skip to content
Snippets Groups Projects
Commit d5ef5993 authored by Chris N's avatar Chris N
Browse files

Switch to subterrain base engine

Huge performance increase and error reduction.  Also fixed stalagmite
and stalactites spawning in midair.   UNLIMITED vertical chunks.
parent 86bbbd66
No related branches found
No related tags found
No related merge requests found
......@@ -23,7 +23,7 @@ end
--generation settings
setting("number", "ymin", -33000) --bottom realm limit
setting("number", "ymax", -700) --top realm limit
setting("number", "chuint", 4) --vertical chunk interval between caves
setting("number", "tcave", 0.5) --cave threshold
--falling icicles
setting("bool", "falling_icicles", true) --enable/disable falling icicles
......@@ -40,6 +40,6 @@ setting("number", "h_clac", 13) --max height of glow crystal stalactites
setting("number", "gemcha", 0.03) --chance of small glow gems
setting("number", "mushcha", 0.04) --chance of mushrooms
setting("number", "myccha", 0.03) --chance of mycena mushrooms
setting("number", "wormcha", 0.03) --chance of glow worms
setting("number", "wormcha", 0.02) --chance of glow worms
setting("number", "giantcha", 0.001) --chance of giant mushrooms
setting("number", "icicha", 0.035) --chance of icicles
......@@ -7,8 +7,32 @@ local H_LAC = caverealms.config.h_lac --20 --...stalactites
local H_CRY = caverealms.config.h_cry --9 --max height of glow crystals
local H_CLAC = caverealms.config.h_clac --13 --max height of glow crystal stalactites
function caverealms:above_solid(x,y,z,area,data)
local c_air = minetest.get_content_id("air")
local ai = area:index(x,y+1,z-3)
if data[ai] == c_air then
return false
else
return true
end
end
function caverealms:below_solid(x,y,z,area,data)
local c_air = minetest.get_content_id("air")
local ai = area:index(x,y-1,z-3)
if data[ai] == c_air then
return false
else
return true
end
end
--stalagmite spawner
function caverealms:stalagmite(x,y,z, area, data)
if not caverealms:below_solid(x,y,z,area,data) then
return
end
--contest ids
local c_stone = minetest.get_content_id("default:stone")
......@@ -42,6 +66,11 @@ end
--stalactite spawner
function caverealms:stalactite(x,y,z, area, data)
if not caverealms:above_solid(x,y,z,area,data) then
return
end
--contest ids
local c_stone = minetest.get_content_id("default:stone")--("caverealms:limestone")
......@@ -75,6 +104,11 @@ end
--glowing crystal stalagmite spawner
function caverealms:crystal_stalagmite(x,y,z, area, data, biome)
if not caverealms:below_solid(x,y,z,area,data) then
return
end
--contest ids
local c_stone = minetest.get_content_id("default:stone")
local c_crystal = minetest.get_content_id("caverealms:glow_crystal")
......@@ -162,6 +196,11 @@ end
--crystal stalactite spawner
function caverealms:crystal_stalactite(x,y,z, area, data, biome)
if not caverealms:above_solid(x,y,z,area,data) then
return
end
--contest ids
local c_stone = minetest.get_content_id("default:stone")
local c_crystore = minetest.get_content_id("caverealms:glow_ore")
......@@ -249,6 +288,11 @@ end
--function to create giant 'shrooms
function caverealms:giant_shroom(x, y, z, area, data)
if not caverealms:below_solid(x,y,z,area,data) then
return
end
--as usual, grab the content ID's
local c_stem = minetest.get_content_id("caverealms:mushroom_stem")
local c_cap = minetest.get_content_id("caverealms:mushroom_cap")
......
-- caverealms 0.2.9 by HeroOfTheWinds
-- For latest stable Minetest and back to 0.4.8
-- caverealms indev by HeroOfTheWinds
-- original cave code modified from paramat's subterrain
-- For Minetest 0.4.8 stable
-- Depends default
-- License: code WTFPL
caverealms = {} --create a container for functions and constants
--grab a shorthand for the filepath of the mod
......@@ -15,26 +17,12 @@ dofile(modpath.."/falling_ice.lua") --complicated function for falling icicles
dofile(modpath.."/nodes.lua") --node definitions
dofile(modpath.."/functions.lua") --function definitions
-- Parameters (see also config.lua)
-- Parameters
local YMIN = caverealms.config.ymin -- Approximate realm limits.
local YMAX = caverealms.config.ymax
local XMIN = -33000
local XMAX = 33000
local ZMIN = -33000
local ZMAX = 33000
local CHUINT = caverealms.config.chuint -- Chunk interval for cave realms
local CLUSAV = -0.5 --cave threshold, determines rarity of caves. -1 = small and rare, 0.5 = default, 0 = nearly half the volume.
local CLUSAM = 0.5 --cave size/density threshold. 0 is off, or little variation, 1 is max.
local WAVAMP = 24 -- Structure wave amplitude
local HISCAL = 32 -- Upper structure vertical scale
local LOSCAL = 32 -- Lower structure vertical scale
local HIEXP = 0.3 -- Upper structure density gradient exponent
local LOEXP = 0.3 -- Lower structure density gradient exponent
local DIRTHR = 0.04 -- Dirt density threshold
local STOTHR = 0.08 -- Stone density threshold
local STABLE = 2 -- Minimum number of stacked stone nodes in column for dirt / sand on top
local TCAVE = caverealms.config.tcave --0.5 -- Cave threshold. 1 = small rare caves, 0.5 = 1/3rd ground volume, 0 = 1/2 ground volume
local BLEND = 128 -- Cave blend distance near YMIN, YMAX
local STAGCHA = caverealms.config.stagcha --0.002 --chance of stalagmites
local STALCHA = caverealms.config.stalcha --0.003 --chance of stalactites
......@@ -46,31 +34,18 @@ local WORMCHA = caverealms.config.wormcha --0.03 --chance of glow worms
local GIANTCHA = caverealms.config.giantcha --0.001 -- chance of giant mushrooms
local ICICHA = caverealms.config.icicha --0.035 -- chance of icicles
-- 3D noise for caverns
-- 3D noise for caves
local np_cave = {
offset = 0,
scale = 1,
spread = {x=512, y=256, z=512},
seed = 277777979,
spread = {x=512, y=256, z=512}, -- squashed 2:1
seed = 59033,
octaves = 6,
persist = 0.6
persist = 0.63
}
-- 3D noise for large scale cavern size/density variation
local np_cluster = {
offset = 0,
scale = 1,
spread = {x=2048, y=2048, z=2048},
seed = 23,
octaves = 1,
persist = 0.5
}
-- 2D noise for wave
-- 3D noise for wave
local np_wave = {
offset = 0,
......@@ -78,7 +53,7 @@ local np_wave = {
spread = {x=256, y=256, z=256},
seed = -400000000089,
octaves = 3,
persist = 0.5
persist = 0.67
}
-- 2D noise for biome
......@@ -92,21 +67,22 @@ local np_biome = {
persist = 0.5
}
-- Stuff
subterrain = {}
local yblmin = YMIN + BLEND * 1.5
local yblmax = YMAX - BLEND * 1.5
-- On generated function
minetest.register_on_generated(function(minp, maxp, seed)
--only continue if within the bounds for creating cave realms
if minp.x < XMIN or maxp.x > XMAX
or minp.y < YMIN or maxp.y > YMAX
or minp.z < ZMIN or maxp.z > ZMAX then
return
--if out of range of caverealms limits
if minp.y > YMAX or maxp.y < YMIN then
return --quit; otherwise, you'd have stalagmites all over the place
end
--determine if there's enough spacing between layers to start a realm
local chulay = math.floor((minp.y + 32) / 80) -- chunk layer number, 0 = surface chunk
local tercen = (math.floor(chulay / CHUINT) * CHUINT + CHUINT / 2) * 80 - 32 -- terrain centre of this layer
--easy to reference variables for limits and time
--easy reference to commonly used values
local t1 = os.clock()
local x1 = maxp.x
local y1 = maxp.y
......@@ -114,15 +90,13 @@ minetest.register_on_generated(function(minp, maxp, seed)
local x0 = minp.x
local y0 = minp.y
local z0 = minp.z
--let people know you're generating a realm
print ("[caverealms] chunk minp ("..x0.." "..y0.." "..z0..")")
--fire up the LVM
print ("[caverealms] chunk minp ("..x0.." "..y0.." "..z0..")") --tell people you are generating a chunk
local vm, emin, emax = minetest.get_mapgen_object("voxelmanip")
local area = VoxelArea:new{MinEdge=emin, MaxEdge=emax}
local data = vm:get_data()
--grab content IDs
local c_air = minetest.get_content_id("air")
local c_stone = minetest.get_content_id("default:stone")
......@@ -144,251 +118,174 @@ minetest.register_on_generated(function(minp, maxp, seed)
local c_worm = minetest.get_content_id("caverealms:glow_worm")
local c_iciu = minetest.get_content_id("caverealms:icicle_up")
local c_icid = minetest.get_content_id("caverealms:icicle_down")
--some mandatory values
local sidelen = x1 - x0 + 1 --usually equals 80 with default mapgen values. Always a multiple of 16.
local chulens = {x=sidelen, y=sidelen, z=sidelen} --position table to pass to get3dMap_flat
local minposxyz = {x=x0, y=y0, z=z0}
local minposxz = {x=x0, y=z0}
--generate the all important perlin that makes nice terrains
local nvals_cave = minetest.get_perlin_map(np_cave, chulens):get3dMap_flat(minposxyz) --obviously for caves
local nvals_cluster = minetest.get_perlin_map(np_cluster, chulens):get3dMap_flat(minposxyz) --how large of clusters of caverns?
local nvals_wave = minetest.get_perlin_map(np_wave, chulens):get2dMap_flat(minposxz) --wavy structure of cavern ceilings and floors
--mandatory values
local sidelen = x1 - x0 + 1 --length of a mapblock
local chulens = {x=sidelen, y=sidelen, z=sidelen} --table of chunk edges
local minposxyz = {x=x0, y=y0, z=z0} --bottom corner
local minposxz = {x=x0, y=z0} --2D bottom corner
local nvals_cave = minetest.get_perlin_map(np_cave, chulens):get3dMap_flat(minposxyz) --cave noise for structure
local nvals_wave = minetest.get_perlin_map(np_wave, chulens):get3dMap_flat(minposxyz) --wavy structure of cavern ceilings and floors
local nvals_biome = minetest.get_perlin_map(np_biome, chulens):get2dMap_flat({x=x0+150, y=z0+50}) --2D noise for biomes (will be 3D humidity/temp later)
--more values
local nixyz = 1 --short for node index xyz
local nixz = 1 --node index xz
local stable = {} --stability for ground
local dirt = {} --table for ground surface
local chumid = y0 + sidelen / 2 --middle of the current chunk
local roof = {}
local nixyz2 = 1 --second 3d index for incrementation
local nixz2 = 1 --second 2d index
local stable2 = {} --second stability table
for z = z0, z1 do --for each xy plane progressing northwards
for x = x0, x1 do
local si = x - x0 + 1 --stability index
dirt[si] = 0 --no dirt here... yet
roof[si] = 0
local nodeid = area:index(x, y0-1, z) --grab the ID of the node just below
if nodeid == c_air
or nodeid == c_water
or nodeid == c_lava then --if a cave or any kind of lake
stable[si] = 0 --this is not stable for plants or falling nodes above
stable2[si] = 0
else -- all else including ignore in ungenerated chunks
stable[si] = STABLE --stuff can safely go above
stable2[si] = STABLE
local nixyz = 1 --3D node index
local nixz = 1 --2D node index
local nixyz2 = 1 --second 3D index for second loop
for z = z0, z1 do -- for each xy plane progressing northwards
--structure loop
for y = y0, y1 do -- for each x row progressing upwards
local tcave --declare variable
--determine the overal cave threshold
if y < yblmin then
tcave = TCAVE + ((yblmin - y) / BLEND) ^ 2
elseif y > yblmax then
tcave = TCAVE + ((y - yblmax) / BLEND) ^ 2
else
tcave = TCAVE
end
end
for y = y1, y0, -1 do -- for each x row progressing downwards
local vi = area:index(x0, y, z) --grab the index of the node to edit
local vi = area:index(x0, y, z) --current node index
for x = x0, x1 do -- for each node do
--here's the good part
local si = x - x0 + 1 --stability index
local cavemid = tercen + nvals_wave[nixz] * WAVAMP --grab the middle of the cave's amplitude
local grad
if y > cavemid then
grad = ((y - cavemid) / HISCAL) ^ HIEXP --for the ceiling
else
grad = ((cavemid - y) / LOSCAL) ^ LOEXP --for the floor
end
--local density = nvals_cave[nixyz] - grad --how dense is the emptiness?
local density = nvals_cave[nixyz] - grad - CLUSAV - nvals_cluster[nixyz] * CLUSAM
if density < 0 and density > -0.7 then -- if cavern "shell"
--local nodename = minetest.get_node({x=x,y=y,z=z}).name --grab the name of the node
data[vi] = c_air --make emptiness
if density < STOTHR and stable[si] <= STABLE then
dirt[si] = dirt[si] + 1
else
stable[si] = stable[si] + 1
end
elseif dirt[si] >= 1 then -- node above surface
--determine biome
local biome = false --preliminary declaration
n_biome = nvals_biome[nixz] --make an easier reference to the noise
--compare noise values to determine a biome
if n_biome >= 0 and n_biome < 0.5 then
biome = 1 --moss
elseif n_biome <= -0.5 then
biome = 2 --fungal
elseif n_biome >= 0.5 then
if n_biome >= 0.7 then
biome = 5 --deep glaciated
else
biome = 4 --glaciated
end
else
biome = 3 --algae
end
--place floor material, add plants/decorations
if biome == 1 then
data[vi] = c_moss
elseif biome == 2 then
data[vi] = c_lichen
elseif biome == 3 then
data[vi] = c_algae
elseif biome == 4 then
data[vi] = c_thinice
local bi = area:index(x,y-1,z)
data[bi] = c_thinice
elseif biome == 5 then
data[vi] = c_ice
local bi = area:index(x,y-1,z)
data[bi] = c_ice
end
--on random chance, place glow crystal formations
if math.random() <= CRYSTAL then
caverealms:crystal_stalagmite(x, y, z, area, data, biome)
end
--randomly place stalagmites
if math.random() <= STAGCHA then
caverealms:stalagmite(x, y, z, area, data, biome)
end
--randomly place glow gems
if math.random() < GEMCHA and biome == 1 then
-- of random size
local gems = { c_gem1, c_gem2, c_gem3, c_gem4, c_gem5 }
local gidx = math.random(1, 12)
if gidx > 5 then
gidx = 1
end
local gi = area:index(x,y+1,z)
data[gi] = gems[gidx]
end
if biome == 2 then --if fungus biome
if math.random() < MUSHCHA then --mushrooms
local gi = area:index(x,y+1,z)
data[gi] = c_fungus
end
if math.random() < MYCCHA then --mycena mushrooms
local gi = area:index(x,y+1,z)
data[gi] = c_mycena
end
if math.random() < GIANTCHA then --giant mushrooms
caverealms:giant_shroom(x, y, z, area, data)
end
end
if math.random() < ICICHA and (biome == 4 or biome == 5) then --if glaciated, place icicles
local gi = area:index(x,y+1,z)
data[gi] = c_iciu
end
dirt[si] = 0
else -- solid rock
stable[si] = 0
if (nvals_cave[nixyz] + nvals_wave[nixyz])/2 > tcave then --if node falls within cave threshold
data[vi] = c_air --hollow it out to make the cave
end
nixyz = nixyz + 1 --increment the 3D index
nixz = nixz + 1 --increment the 2D index
vi = vi + 1 --increment the area index
--increment indices
nixyz = nixyz + 1
vi = vi + 1
end
nixz = nixz - sidelen --shift the 2D index down a layer
end
nixz = nixz + sidelen --shift the 2D index up a layer
--second loop to obtain ceiling
for y = y0, y1 do -- for each x row progressing downwards
local vi = area:index(x0, y, z) --grab the index of the node to edit
--decoration loop
for y = y0, y1 do -- for each x row progressing upwards
local tcave --same as above
if y < yblmin then
tcave = TCAVE + ((yblmin - y) / BLEND) ^ 2
elseif y > yblmax then
tcave = TCAVE + ((y - yblmax) / BLEND) ^ 2
else
tcave = TCAVE
end
local vi = area:index(x0, y, z)
for x = x0, x1 do -- for each node do
--here's the good part
local si = x - x0 + 1 --stability index
local cavemid = tercen + nvals_wave[nixz2] * WAVAMP --grab the middle of the cave's amplitude
local grad
if y > cavemid then
grad = ((y - cavemid) / HISCAL) ^ HIEXP --for the ceiling
else
grad = ((cavemid - y) / LOSCAL) ^ LOEXP --for the floor
end
--local density = nvals_cave[nixyz2] - grad --how dense is the emptiness?
local density = nvals_cave[nixyz2] - grad - CLUSAV - nvals_cluster[nixyz2] * CLUSAM
if density < 0 and density > -0.7 then -- if cavern "shell"
if density < STOTHR and stable2[si] <= STABLE then
roof[si] = roof[si] + 1
--determine biome
local biome = false --preliminary declaration
n_biome = nvals_biome[nixz] --make an easier reference to the noise
--compare noise values to determine a biome
if n_biome >= 0 and n_biome < 0.5 then
biome = 1 --moss
elseif n_biome <= -0.5 then
biome = 2 --fungal
elseif n_biome >= 0.5 then
if n_biome >= 0.7 then
biome = 5 --deep glaciated
else
stable2[si] = stable2[si] + 1
biome = 4 --glaciated
end
elseif roof[si] >= 1 then --and stable2[si] >= 2 then -- node at roof
--determine biome
local biome = false --preliminary declaration
n_biome = nvals_biome[nixz2] --make an easier reference to the noise
if n_biome >= 0 and n_biome < 0.5 then
biome = 1 --moss
elseif n_biome <= -0.5 then
biome = 2 --fungal
elseif n_biome >= 0.5 then
if n_biome >= 0.7 then
biome = 5
else
biome = 4 --glaciated
else
biome = 3 --algae
end
if math.floor(((nvals_cave[nixyz2] + nvals_wave[nixyz2])/2)*100) == math.floor(tcave*100) then
--ceiling
local ai = area:index(x,y+1,z) --above index
if data[ai] == c_stone and data[vi] == c_air then --ceiling
if math.random() < ICICHA and (biome == 4 or biome == 5) then
local bi = area:index(x,y-1,z)
data[bi] = c_icid
end
else
biome = 3 --algae
end
--glow worm
if math.random() <= WORMCHA then
local ai = area:index(x,y+1,z)--index of node above
if data[ai] ~= c_air then
if math.random() < WORMCHA then
data[vi] = c_worm
local bi = area:index(x,y-1,z) --below index 1
local bi = area:index(x,y-1,z)
data[bi] = c_worm
if math.random(2) == 1 then
local ci = area:index(x,y-2,z)
data[ci] = c_worm
if math.random(2) == 1 then
local di = area:index(x,y-3,z)
data[di] = c_worm
if math.random(2) == 1 then
local ei = area:index(x,y-4,z)
data[ei] = c_worm
end
local bbi = area:index(x,y-2,z)
data[bbi] = c_worm
if math.random(2) ==1 then
local bbbi = area:index(x,y-3,z)
data[bbbi] = c_worm
end
end
end
end
--self documenting...
if math.random() < ICICHA and (biome == 4 or biome == 5) then
local ai = area:index(x,y+1,z)--index of node above
if data[ai] ~= c_air then
local gi = area:index(x,y-1,z)
data[gi] = c_icid
if math.random() < STALCHA then
caverealms:stalactite(x,y,z, area, data)
end
end
if math.random() <= STALCHA then
local ai = area:index(x,y+1,z)
if data[ai] ~= c_air then
caverealms:stalactite(x, y, z, area, data, biome)
if math.random() < CRYSTAL then
caverealms:crystal_stalactite(x,y,z, area, data, biome)
end
end
if math.random() <= CRYSTAL then
--ground
local bi = area:index(x,y-1,z) --below index
if data[bi] == c_stone and data[vi] == c_air then --ground
local ai = area:index(x,y+1,z)
if data[ai] ~= c_air then
caverealms:crystal_stalactite(x,y,z, area, data, biome)
--place floor material, add plants/decorations
if biome == 1 then
data[vi] = c_moss
if math.random() < GEMCHA then
-- gems of random size
local gems = { c_gem1, c_gem2, c_gem3, c_gem4, c_gem5 }
local gidx = math.random(1, 12)
if gidx > 5 then
gidx = 1
end
data[ai] = gems[gidx]
end
elseif biome == 2 then
data[vi] = c_lichen
if math.random() < MUSHCHA then --mushrooms
data[ai] = c_fungus
end
if math.random() < MYCCHA then --mycena mushrooms
data[ai] = c_mycena
end
if math.random() < GIANTCHA then --giant mushrooms
caverealms:giant_shroom(x, y, z, area, data)
end
elseif biome == 3 then
data[vi] = c_algae
elseif biome == 4 then
data[vi] = c_thinice
local bi = area:index(x,y-1,z)
data[bi] = c_thinice
if math.random() < ICICHA then --if glaciated, place icicles
data[ai] = c_iciu
end
elseif biome == 5 then
data[vi] = c_ice
local bi = area:index(x,y-1,z)
data[bi] = c_ice
if math.random() < ICICHA then --if glaciated, place icicles
data[ai] = c_iciu
end
end
if math.random() < STAGCHA then
caverealms:stalagmite(x,y,z, area, data)
end
if math.random() < CRYSTAL then
caverealms:crystal_stalagmite(x,y,z, area, data, biome)
end
end
roof[si] = 0
else -- solid rock
stable2[si] = 0
end
nixyz2 = nixyz2 + 1 --increment the 3D index
nixz2 = nixz2 + 1 --increment the 2D index
vi = vi + 1 --increment the area index
nixyz2 = nixyz2 + 1
nixz = nixz + 1
vi = vi + 1
end
nixz2 = nixz2 - sidelen --reverse the index a bit
nixz = nixz - sidelen
end
nixz2 = nixz2 + sidelen --increment the index
end
--write these changes to the world
--send data back to voxelmanip
vm:set_data(data)
--calc lighting
vm:set_lighting({day=0, night=0})
vm:calc_lighting()
--write it to world
vm:write_to_map(data)
local chugent = math.ceil((os.clock() - t1) * 1000) --grab how long this took
print ("[caverealms] "..chugent.." ms") --tell people how long it took
local chugent = math.ceil((os.clock() - t1) * 1000) --grab how long it took
print ("[subterrain] "..chugent.." ms") --tell people how long
end)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment