The block size variable affects how much of the world map will be used, so with the default setting of 12, the world map had abrupt edges at 6000m from origin, meaning the world will generate within (-6000, -6000) to (6000, 6000). Outside of those areas, is nothing but flat ocean, and any terrain get a nicely shaped cliff.
I assumed that I could set the value higher, so tried 60, so that the entire worldmap can emerge. This simply led to out of memory.
Changing the grid size from the default of 1000x1000 to 5000x5000, (multiple of 12 * 5), but again, out of memory.
All this was simply to have the entire worldmap playable. As of now, only the 36sqkm surrounding origin are generated.
Regarding the dem variable, a flat_3d_map, I haven't yet tried to generate one from a 2D noise. The functions I use to generate terrain are not noise based, and so trying to provide a flat map of 1000x1000 also leads to memory issues.
My voronoi mapgen finds the nearest point, and uses the distance from that point to the current position. In the now 2 layer recursive voronoi, I end up with a distance to a cell's defined point, and the distance to the subcell's defined point. The sum of the two distances is subtracted from a maximum terrain height. As each of these calculations occurs during the on_gen call, utilizing the existing z,y,x, for loops, I can only provide the heightmap of the chunk/block that is generated.
As promised, here is my "hacked" init.lua for mapgen_rivers. References to my GAL project are numerous. If you'd like to see any relevant functions, such as my biome selection functions, just ask. Most of my hack is to enable the biomes, but you'll see some experiements with 2D noises, which aren't as successful as I'd like.
Spoiler
if gal.mapgen.name ~= "mg_mapgenrivers" then
return
end
mapgen_rivers = {}
local modpath = minetest.get_modpath(minetest.get_current_modname()) .. '/'
mapgen_rivers.modpath = modpath
mapgen_rivers.world_data_path = minetest.get_worldpath() .. '/river_data/'
dofile(modpath .. 'settings.lua')
-- mapgen_rivers.heightmap = {}
-- mapgen_rivers.biomemap = {}
-- mapgen_rivers.biome_info = {}
local sea_level = mapgen_rivers.settings.sea_level
local elevation_chill = mapgen_rivers.settings.elevation_chill
local use_distort = mapgen_rivers.settings.distort
local use_biomes = mapgen_rivers.settings.biomes
local use_biomegen_mod = use_biomes and minetest.global_exists('biomegen')
use_biomes = use_biomes and not use_biomegen_mod
if use_biomegen_mod then
biomegen.set_elevation_chill(elevation_chill)
end
dofile(modpath .. 'noises.lua')
--
gal.mapgen.biome_vertical_range = 50
--gal.mapgen.biome_vertical_range = mapgen_rivers.noise_params.base.scale / 10
gal.mapgen.biome_vertical_blend = (gal.mapgen.biome_vertical_range / 5) * gal.mapgen.mg_world_scale
gal.mapgen.mg_biome_mode = "full"
gal.mapgen.use_heat_scalar = true
gal.mapgen.use_humid_scalar = true
gal.mapgen.ocean_depth = -2000 * gal.mapgen.mg_world_scale
gal.mapgen.beach_depth = -4 * gal.mapgen.mg_world_scale
gal.mapgen.sea_level = gal.mapgen.water_level
gal.mapgen.maxheight_beach = 4 * gal.mapgen.mg_world_scale
gal.mapgen.maxheight_coastal = gal.mapgen.sea_level + gal.mapgen.biome_vertical_range
gal.mapgen.maxheight_lowland = gal.mapgen.maxheight_coastal + gal.mapgen.biome_vertical_range
gal.mapgen.maxheight_shelf = gal.mapgen.maxheight_lowland + gal.mapgen.biome_vertical_range
gal.mapgen.maxheight_highland = gal.mapgen.maxheight_shelf + gal.mapgen.biome_vertical_range
gal.mapgen.maxheight_mountain = gal.mapgen.maxheight_highland + gal.mapgen.biome_vertical_range
--gal.mapgen.minheight_snow = gal.mapgen.maxheight_mountain + gal.mapgen.biome_vertical_range
gal.mapgen.minheight_snow = gal.mapgen.maxheight_mountain + (gal.mapgen.biome_vertical_range * 2)
gal.mapgen.maxheight_snow = gal.mapgen.minheight_snow + (gal.mapgen.biome_vertical_range * 2)
gal.mapgen.maxheight_strato = gal.mapgen.maxheight_snow + (gal.mapgen.biome_vertical_range * (gal.mapgen.biome_vertical_blend / 2))
local nobj_terrain = nil
local nbuf_terrain = {}
local nobj_cliffs = nil
local nbuf_cliffs = {}
local np_v7_alt = {
offset = -4,
scale = 100,
seed = 5934,
spread = {x = 1200, y = 1200, z = 1200},
octaves = 7,
persist = 0.4,
lacunarity = 2.15,
--flags = "defaults"
--flags = "eased",
}
local np_v7_base = {
offset = -4,
scale = 240,
seed = 5934,
spread = {x = 1200, y = 1200, z = 1200},
octaves = 7,
persist = 0.4,
lacunarity = 2.15,
flags = "defaults"
}
local np_v7_height = {
offset = 0.5,
scale = 1,
spread = {x = 1000, y = 1000, z = 1000},
seed = 4213,
octaves = 7,
persist = 0.4,
lacunarity = 2.15,
flags = "defaults",
}
local np_v7_persist = {
offset = 0.6,
scale = 0.1,
spread = {x = 2000, y = 2000, z = 2000},
seed = 539,
octaves = 3,
persist = 0.6,
lacunarity = 2.15,
flags = "defaults",
}
local np_v7_cliffs = {
offset = 0,
scale = 0.72,
spread = {x = 180, y = 180, z = 180},
seed = 78901,
octaves = 5,
persist = 0.5,
lacunarity = 2.19,
}
local abs = math.abs
local max = math.max
local min = math.min
local floor = math.floor
local cliffs_thresh = floor((np_v7_alt.scale) * 0.5)
mapgen_rivers.rangelim = function(v, min, max)
if v < min then return min end
if v > max then return max end
return v
end
mapgen_rivers.get_terrain_height_cliffs = function(theight,cheight)
-- cliffs
local t_cliff = 0
if theight > 1 and theight < cliffs_thresh then
local clifh = max(min(cheight,1),0)
if clifh > 0 then
clifh = -1 * (clifh - 1) * (clifh - 1) + 1
t_cliff = clifh
theight = theight + (cliffs_thresh - theight) * clifh * ((theight < 2) and theight - 1 or 1)
end
end
return theight, t_cliff
end
mapgen_rivers.get_v7_height = function(z,x)
local aterrain = 0
local hselect = minetest.get_perlin(np_v7_height):get_2d({x=x,y=z})
local hselect = mapgen_rivers.rangelim(hselect, 0, 1)
local persist = minetest.get_perlin(np_v7_persist):get_2d({x=x,y=z})
np_v7_base.persistence = persist;
local height_base = minetest.get_perlin(np_v7_base):get_2d({x=x,y=z})
np_v7_alt.persistence = persist;
local height_alt = minetest.get_perlin(np_v7_alt):get_2d({x=x,y=z})
if (height_alt > height_base) then
aterrain = floor(height_alt)
else
aterrain = floor((height_base * hselect) + (height_alt * (1 - hselect)))
end
return aterrain
end
local heightmaps = dofile(modpath .. 'heightmap.lua')
-- Linear interpolation
local function interp(v00, v01, v11, v10, xf, zf)
local v0 = v01*xf + v00*(1-xf)
local v1 = v11*xf + v10*(1-xf)
return v1*zf + v0*(1-zf)
end
local data = {}
local noise_x_obj, noise_z_obj, noise_distort_obj, noise_heat_obj, noise_heat_blend_obj, noise_humid_obj, noise_humid_blend_obj
local noise_x_map = {}
local noise_z_map = {}
local noise_distort_map = {}
local noise_heat_map = {}
local noise_heat_blend_map = {}
local noise_humid_map = {}
local noise_humid_blend_map = {}
local mapsize
local init = false
local sumtime = 0
local sumtime2 = 0
local ngen = 0
local mapgen_times = {
noisemaps = {},
preparation = {},
loop2d = {},
loop3d = {},
biomes = {},
mainloop = {},
setdata = {},
liquid_lighting = {},
writing = {},
make_chunk = {},
}
local function generate(minp, maxp, seed)
print(("[mapgen_rivers] Generating from %s to %s"):format(minetest.pos_to_string(minp), minetest.pos_to_string(maxp)))
local chulens = {
x = maxp.x-minp.x+1,
y = maxp.y-minp.y+1,
z = maxp.z-minp.z+1,
}
if not init then
mapsize = {
x = chulens.x,
y = chulens.y+1,
z = chulens.z,
}
if use_distort then
noise_x_obj = minetest.get_perlin_map(mapgen_rivers.noise_params.distort_x, mapsize)
noise_z_obj = minetest.get_perlin_map(mapgen_rivers.noise_params.distort_z, mapsize)
noise_distort_obj = minetest.get_perlin_map(mapgen_rivers.noise_params.distort_amplitude, chulens)
end
if use_biomes then
noise_heat_obj = minetest.get_perlin_map(mapgen_rivers.noise_params.heat, chulens)
noise_heat_blend_obj = minetest.get_perlin_map(mapgen_rivers.noise_params.heat_blend, chulens)
noise_humid_obj = minetest.get_perlin_map(mapgen_rivers.noise_params.humid, chulens)
noise_humid_blend_obj = minetest.get_perlin_map(mapgen_rivers.noise_params.humid_blend, chulens)
end
init = true
end
local sidelen = maxp.x - minp.x + 1
local permapdims2d = {x = sidelen, y = sidelen, z = 0}
local minpos2d = {x = minp.x, y = minp.z}
--nobj_terrain = nobj_terrain or minetest.get_perlin_map(np_terrain, permapdims2d)
--nbuf_terrain = nobj_terrain:get_2d_map(minpos2d)
nobj_cliffs = nobj_cliffs or minetest.get_perlin_map(np_v7_cliffs, permapdims2d)
nbuf_cliffs = nobj_cliffs:get_2d_map(minpos2d)
local t0 = os.clock()
local minp2d = {x=minp.x, y=minp.z}
if use_distort then
noise_x_obj:get_3d_map_flat(minp, noise_x_map)
noise_z_obj:get_3d_map_flat(minp, noise_z_map)
noise_distort_obj:get_2d_map_flat(minp2d, noise_distort_map)
end
if use_biomes then
noise_heat_obj:get_2d_map_flat(minp2d, noise_heat_map)
noise_heat_blend_obj:get_2d_map_flat(minp2d, noise_heat_blend_map)
noise_humid_obj:get_2d_map_flat(minp2d, noise_humid_map)
noise_humid_blend_obj:get_2d_map_flat(minp2d, noise_humid_blend_map)
end
local terrain_map, lake_map, incr, i_origin
if use_distort then
local xmin, xmax, zmin, zmax = minp.x, maxp.x, minp.z, maxp.z
local i = 0
local i2d = 0
for z=minp.z, maxp.z do
for y=minp.y, maxp.y+1 do
for x=minp.x, maxp.x do
i = i+1
i2d = i2d+1
local distort = noise_distort_map[i2d]
local xv = noise_x_map*distort + x
if xv < xmin then xmin = xv end
if xv > xmax then xmax = xv end
noise_x_map = xv
local zv = noise_z_map*distort + z
if zv < zmin then zmin = zv end
if zv > zmax then zmax = zv end
noise_z_map = zv
end
i2d = i2d-chulens.x
end
end
local pminp = {x=math.floor(xmin), z=math.floor(zmin)}
local pmaxp = {x=math.floor(xmax)+1, z=math.floor(zmax)+1}
incr = pmaxp.x-pminp.x+1
i_origin = 1 - pminp.z*incr - pminp.x
terrain_map, lake_map = heightmaps(pminp, pmaxp)
else
terrain_map, lake_map = heightmaps(minp, maxp)
end
--local c_stone = minetest.get_content_id("default:stone")
--local c_dirt = minetest.get_content_id("default:dirt")
--local c_lawn = minetest.get_content_id("default:dirt_with_grass")
--local c_dirtsnow = minetest.get_content_id("default:dirt_with_snow")
--local c_snow = minetest.get_content_id("default:snowblock")
--local c_sand = minetest.get_content_id("default:sand")
--local c_water = minetest.get_content_id("default:water_source")
--local c_rwater = minetest.get_content_id("default:river_water_source")
--local c_ice = minetest.get_content_id("default:ice")
local c_stone = minetest.get_content_id("gal:stone")
local c_dirt = minetest.get_content_id("gal:dirt")
local c_lawn = minetest.get_content_id("gal:dirt_with_grass")
local c_dirtsnow = minetest.get_content_id("gal:dirt_with_snow")
local c_snow = minetest.get_content_id("gal:snow_block")
local c_sand = minetest.get_content_id("gal:sand")
local c_water = minetest.get_content_id("gal:liquid_water_source")
local c_rwater = minetest.get_content_id("gal:liquid_water_river_source")
local c_ice = minetest.get_content_id("gal:ice")
local vm, emin, emax = minetest.get_mapgen_object("voxelmanip")
vm:get_data(data)
local a = VoxelArea:new({MinEdge = emin, MaxEdge = emax})
local ystride = a.ystride -- Tip : the ystride of a VoxelArea is the number to add to the array index to get the index of the position above. It's faster because it avoids to completely recalculate the index.
local t1 = os.clock()
local nid = mapsize.x*(mapsize.y-1) + 1
local incrY = -mapsize.x
local incrX = 1 - mapsize.y*incrY
local incrZ = mapsize.x*mapsize.y - mapsize.x*incrX - mapsize.x*mapsize.y*incrY
local i2d = 1
local t2 = os.clock()
local t3 = os.clock()
for z = minp.z, maxp.z do
for x = minp.x, maxp.x do
local ivm = a:index(x, minp.y, z)
local ground_above = false
local temperature
if use_biomes then
--temperature = gal.mapgen.get_heat_scalar(z) + noise_heat_map[i2d]+noise_heat_blend_map[i2d]
temperature = noise_heat_map[i2d]+noise_heat_blend_map[i2d]
--humidity = gal.mapgen.get_humid_scalar(z) + noise_humid_map[i2d]+noise_humid_blend_map[i2d]
humidity = noise_humid_map[i2d]+noise_humid_blend_map[i2d]
end
local terrain, lake
if not use_distort then
terrain = terrain_map[i2d]
lake = lake_map[i2d]
end
--local nterrain = minetest.get_perlin(np_v7_alt):get_2d({x=x,y=z})
--local nterrain = nbuf_terrain[z-minp.z+1][x-minp.x+1]
--local aterrain = minetest.get_perlin(np_v7_alt):get_2d({x=x,y=z})
--local bterrain = minetest.get_perlin(np_v7_base):get_2d({x=x,y=z})
local ncliff = nbuf_cliffs[z-minp.z+1][x-minp.x+1]
local vterrain = mapgen_rivers.get_v7_height(z,x)
local t_y, t_c = mapgen_rivers.get_terrain_height_cliffs(vterrain,ncliff)
local theight = t_y
local t_cliff = t_c or 0
for y = maxp.y+1, minp.y, -1 do
if use_distort then
local xn = noise_x_map[nid]
local zn = noise_z_map[nid]
local x0 = math.floor(xn)
local z0 = math.floor(zn)
local i0 = i_origin + z0*incr + x0
local i1 = i0+1
local i2 = i1+incr
local i3 = i2-1
--terrain = interp(terrain_map[i0], terrain_map[i1], terrain_map[i2], terrain_map[i3], xn-x0, zn-z0)
terrain = interp(terrain_map[i0] + t_y, terrain_map[i1] + t_y, terrain_map[i2] + t_y, terrain_map[i3] + t_y, xn-x0, zn-z0)
--terrain = interp(aterrain, bterrain, vterrain, t_y, xn-x0, zn-z0)
lake = math.min(lake_map[i0] + t_y, lake_map[i1] + t_y, lake_map[i2] + t_y, lake_map[i3] + t_y)
end
theight = terrain
local t_biome_name = gal.mapgen.get_biome_name(temperature,humidity,theight)
gal.mapgen.heightmap[i2d] = theight
--gal.mapgen.heightmap[i2d] = terrain - 1
gal.mapgen.biomemap[i2d] = t_biome_name
local fill_depth = 4
local top_depth = 1
local riverbed_depth = 6
--local river_size_factor = (riverbed_depth - (terrain / 40)) / 100
local river_size_factor = riverbed_depth - (theight / 40)
local t_air = gal.mapgen.c_air
local t_ignore = gal.mapgen.c_ignore
local t_top = gal.mapgen.c_top
local t_top_depth = top_depth
local t_filler = gal.mapgen.c_filler
local t_filldepth = fill_depth
local t_stone = gal.mapgen.c_stone
local t_water = gal.mapgen.c_water
local t_river = gal.mapgen.c_river
local t_riverbed = gal.mapgen.c_gravel
local t_riverbed_depth = riverbed_depth
local t_ice = gal.mapgen.c_ice
local t_mud = gal.mapgen.c_mud
--local t_sand = gal.mapgen.c_sand
t_top = gal.mapgen.biome_info[t_biome_name].b_top
t_top_depth = gal.mapgen.biome_info[t_biome_name].b_top_depth
t_filler = gal.mapgen.biome_info[t_biome_name].b_filler
t_filldepth = gal.mapgen.biome_info[t_biome_name].b_filler_depth
t_stone = gal.mapgen.biome_info[t_biome_name].b_stone
t_water = gal.mapgen.biome_info[t_biome_name].b_water
t_river = gal.mapgen.biome_info[t_biome_name].b_river
t_riverbed = gal.mapgen.biome_info[t_biome_name].b_riverbed
t_riverbed_depth = gal.mapgen.biome_info[t_biome_name].b_riverbed_depth
if y <= maxp.y then
local is_lake = lake > theight
local ivm = a:index(x, y, z)
local t_node = t_ignore
-- if y <= terrain then
-- if not use_biomes or y <= terrain-1 or ground_above then
-- t_node = t_stone
-- elseif is_lake or y < sea_level then
-- t_node = c_sand
-- else
-- local temperature_y = temperature - y*elevation_chill
-- if temperature_y >= 15 then
-- t_node = t_top
-- elseif temperature_y >= 0 then
-- t_node = c_dirtsnow
-- else
-- t_node = c_snow
-- end
-- end
-- elseif y <= lake and lake > sea_level then
-- if not use_biomes or temperature - y*elevation_chill >= 0 then
-- t_node = t_river
-- else
-- t_node = t_ice
-- end
-- elseif y <= sea_level then
-- t_node = t_water
-- end
if t_cliff > 0 then
t_filler = t_stone
end
if is_lake and y <= (lake - 1) and lake > gal.mapgen.water_level then
t_node = t_river
t_filldepth = river_size_factor
end
if y < (theight - (t_filldepth + top_depth)) then
t_node = t_stone
elseif y >= (theight - (t_filldepth + top_depth)) and y < (theight - top_depth) then
if is_lake then
if y <= lake and y > gal.mapgen.water_level then
t_filler = t_river
if y >= (theight - (t_filldepth + top_depth)) and y < (theight - ((t_filldepth * 0.25) + top_depth)) then
t_filler = t_riverbed
end
end
end
t_node = t_filler
elseif y >= (theight - top_depth) and y <= theight then
if is_lake then
if y <= lake and lake > gal.mapgen.water_level then
t_top = t_river
end
end
t_node = t_top
elseif y > theight and y <= gal.mapgen.water_level then
--Water Level (Sea Level)
t_node = t_water
end
data[ivm] = t_node
end
ground_above = y <= theight
ivm = ivm + ystride
if use_distort then
nid = nid + incrY
end
end
if use_distort then
nid = nid + incrX
end
i2d = i2d + 1
end
if use_distort then
nid = nid + incrZ
end
end
local t4 = os.clock()
local t5
if use_biomegen_mod then
biomegen.generate_all(data, a, vm, minp, maxp, seed)
t5 = os.clock()
else
vm:set_data(data)
t5 = os.clock()
minetest.generate_ores(vm, minp, maxp)
minetest.generate_decorations(vm,minp,maxp)
end
vm:set_lighting({day = 0, night = 0})
vm:calc_lighting()
vm:update_liquids()
local t6 = os.clock()
vm:write_to_map()
local t7 = os.clock()
--local t1 = os.clock()
--local t = t1-t0
--ngen = ngen + 1
--sumtime = sumtime + t
--sumtime2 = sumtime2 + t*t
--print(("[mapgen_rivers] Done in %5.3f s"):format(t))
-- Print generation time of this mapchunk.
local chugent = math.ceil((os.clock() - t0) * 1000)
print ("[mg_v7] Mapchunk generation time " .. chugent .. " ms")
table.insert(mapgen_times.noisemaps, 0)
table.insert(mapgen_times.preparation, t1 - t0)
table.insert(mapgen_times.loop2d, t2 - t1)
table.insert(mapgen_times.loop3d, t3 - t2)
table.insert(mapgen_times.mainloop, t4 - t3)
table.insert(mapgen_times.setdata, t5 - t4)
table.insert(mapgen_times.liquid_lighting, t6 - t5)
table.insert(mapgen_times.writing, t7 - t6)
table.insert(mapgen_times.make_chunk, t7 - t0)
-- Deal with memory issues. This, of course, is supposed to be automatic.
local mem = math.floor(collectgarbage("count")/1024)
if mem > 1000 then
print("mg_v7 is manually collecting garbage as memory use has exceeded 500K.")
collectgarbage("collect")
end
end
minetest.register_on_generated(generate)
local function mean( t )
local sum = 0
local count= 0
for k,v in pairs(t) do
if type(v) == 'number' then
sum = sum + v
count = count + 1
end
end
return (sum / count)
end
minetest.register_on_shutdown(function()
local avg = sumtime / ngen
local std = math.sqrt(sumtime2/ngen - avg*avg)
--print(("[mapgen_rivers] Mapgen statistics:\n- Mapgen calls: %4d\n- Mean time: %5.3f s\n- Standard deviation: %5.3f s"):format(avg, std))
if #mapgen_times.make_chunk == 0 then
return
end
local average, standard_dev
minetest.log("mg_v7 lua Mapgen Times:")
average = mean(mapgen_times.noisemaps)
minetest.log(" noisemaps: - - - - - - - - - - - - - - - "..average)
average = mean(mapgen_times.preparation)
minetest.log(" preparation: - - - - - - - - - - - - - - "..average)
average = mean(mapgen_times.loop2d)
minetest.log(" 2D Noise loops: - - - - - - - - - - - - - - - - - "..average)
average = mean(mapgen_times.loop3d)
minetest.log(" 3D Noise loops: - - - - - - - - - - - - - - - - - "..average)
average = mean(mapgen_times.mainloop)
minetest.log(" Main Render loops: - - - - - - - - - - - - - - - - - "..average)
average = mean(mapgen_times.setdata)
minetest.log(" writing: - - - - - - - - - - - - - - - - "..average)
average = mean(mapgen_times.liquid_lighting)
minetest.log(" liquid_lighting: - - - - - - - - - - - - "..average)
average = mean(mapgen_times.writing)
minetest.log(" writing: - - - - - - - - - - - - - - - - "..average)
average = mean(mapgen_times.make_chunk)
minetest.log(" makeChunk: - - - - - - - - - - - - - - - "..average)
end)