5 Commits

Author SHA1 Message Date
e9fa7f9a5c Adapt to multithreading, now it is working! 2024-01-05 00:02:30 +01:00
f26fd1cccb Fixups 2024-01-04 23:54:59 +01:00
e5b8f2b3b8 Refactor to use only Settings objects for settings.
Also remove globally stored path for modpath and data.
Basically use less global variables for better adaptation to multithreading.
2024-01-04 22:47:50 +01:00
6fa1852277 Replace table settings by the mod's Settings object (to be completed) 2023-12-30 17:38:51 +01:00
11e6e72324 Started refactoring code structure to support a separate mapgen thread
Probably not working for now (untested), still some things to do
Also making the code cleaner
2023-12-28 15:27:36 +01:00
10 changed files with 700 additions and 715 deletions

View File

@ -1,10 +1,10 @@
local modpath = mapgen_rivers.modpath
local modpath = minetest.get_modpath(minetest.get_current_modname())
local make_polygons = dofile(modpath .. 'polygons.lua')
local transform_quadri = dofile(modpath .. 'geometry.lua')
local make_polygons = dofile(modpath .. '/polygons.lua')
local transform_quadri = dofile(modpath .. '/geometry.lua')
local sea_level = mapgen_rivers.settings.sea_level
local riverbed_slope = mapgen_rivers.settings.riverbed_slope * mapgen_rivers.settings.blocksize
local sea_level = tonumber(minetest.get_mapgen_setting("water_level"))
local riverbed_slope = tonumber(mapgen_rivers.settings:get("riverbed_slope")) * tonumber(mapgen_rivers.settings:get("blocksize"))
local MAP_BOTTOM = -31000
@ -46,57 +46,50 @@ local function heightmaps(minp, maxp)
-- = 0: on riverbank
-- > 0: inside river
local depth_factors = {
r_west - xf , -- West edge (1)
r_north - zf , -- North edge (2)
r_east - (1-xf), -- East edge (3)
r_south - (1-zf), -- South edge (4)
c_NW - xf - zf , -- North-West corner (5)
c_NE - (1-xf) - zf , -- North-East corner (6)
c_SE - (1-xf) - (1-zf), -- South-East corner (7)
c_SW - xf - (1-zf), -- South-West corner (8)
r_west - xf,
r_north - zf,
xf - r_east,
zf - r_south,
c_NW-xf-zf,
xf-zf-c_NE,
xf+zf-c_SE,
zf-xf-c_SW,
}
-- Find the maximal depth factor, which determines to which of the 8 river sections (4 edges + 4 corners) the current point belongs.
-- If imax is still at 0, it means that we are not in a river.
local dpmax = 0
-- Find the maximal depth factor and determine to which river it belongs
local depth_factor_max = 0
local imax = 0
for i=1, 8 do
if depth_factors[i] > dpmax then
dpmax = depth_factors[i]
if depth_factors[i] >= depth_factor_max then
depth_factor_max = depth_factors[i]
imax = i
end
end
-- Transform the coordinates to have xfc and zfc = 0 or 1 in rivers (to avoid rivers having lateral slope and to accomodate the riverbanks smoothly)
local xfc, zfc
-- xfc:
if imax == 0 or imax == 2 or imax == 4 then -- river segment does not constrain X coordinate, so accomodate xf in function of other river sections
local x0 = max(r_west-dpmax, c_NW-zf-dpmax, c_SW-(1-zf)-dpmax, 0) -- new xf will be bounded to 0 by western riverbank
local x1 = 1-max(r_east-dpmax, c_NE-zf-dpmax, c_SE-(1-zf)-dpmax, 0) -- and bounded to 1 by eastern riverbank
if x0 >= x1 then
xfc = 0.5
else
xfc = (xf-x0) / (x1-x0)
end
elseif imax == 1 or imax == 5 or imax == 8 then -- river at the western side of the polygon
xfc = 0
else -- 3, 6, 7 : river at the eastern side of the polygon
xfc = 1
end
-- Same for zfc:
if imax == 0 or imax == 1 or imax == 3 then -- river segment does not constrain Z coordinate, so accomodate zf in function of other river sections
local z0 = max(r_north-dpmax, c_NW-xf-dpmax, c_NE-(1-xf)-dpmax, 0) -- new zf will be bounded to 0 by northern riverbank
local z1 = 1-max(r_south-dpmax, c_SW-xf-dpmax, c_SE-(1-xf)-dpmax, 0) -- and bounded to 1 by southern riverbank
if z0 >= z1 then
zfc = 0.5
else
zfc = (zf-z0) / (z1-z0)
end
elseif imax == 2 or imax == 5 or imax == 6 then -- river at the northern side of the polygon
zfc = 0
else -- 4, 7, 8 : river at the southern side of the polygon
zfc = 1
-- Transform the coordinates to have xf and zf = 0 or 1 in rivers (to avoid rivers having lateral slope and to accomodate the surrounding smoothly)
if imax == 0 then
local x0 = max(r_west, c_NW-zf, zf-c_SW)
local x1 = min(r_east, c_NE+zf, c_SE-zf)
local z0 = max(r_north, c_NW-xf, xf-c_NE)
local z1 = min(r_south, c_SW+xf, c_SE-xf)
xf = (xf-x0) / (x1-x0)
zf = (zf-z0) / (z1-z0)
elseif imax == 1 then
xf = 0
elseif imax == 2 then
zf = 0
elseif imax == 3 then
xf = 1
elseif imax == 4 then
zf = 1
elseif imax == 5 then
xf, zf = 0, 0
elseif imax == 6 then
xf, zf = 1, 0
elseif imax == 7 then
xf, zf = 1, 1
elseif imax == 8 then
xf, zf = 0, 1
end
-- Determine elevation by interpolation
@ -106,12 +99,12 @@ local function heightmaps(minp, maxp)
vdem[2],
vdem[3],
vdem[4],
xfc, zfc
xf, zf
))
-- Spatial gradient of the interpolation
local slope_x = zfc*(vdem[3]-vdem[4]) + (1-zfc)*(vdem[2]-vdem[1]) < 0
local slope_z = xfc*(vdem[3]-vdem[2]) + (1-xfc)*(vdem[4]-vdem[1]) < 0
local slope_x = zf*(vdem[3]-vdem[4]) + (1-zf)*(vdem[2]-vdem[1]) < 0
local slope_z = xf*(vdem[3]-vdem[2]) + (1-xf)*(vdem[4]-vdem[1]) < 0
local lake_id = 0
if slope_x then
if slope_z then
@ -128,8 +121,8 @@ local function heightmaps(minp, maxp)
end
local lake_height = max(floor(poly.lake[lake_id]), terrain_height)
if imax > 0 and dpmax > 0 then
terrain_height = min(max(lake_height, sea_level) - floor(1+dpmax*riverbed_slope), terrain_height)
if imax > 0 and depth_factor_max > 0 then
terrain_height = min(max(lake_height, sea_level) - floor(1+depth_factor_max*riverbed_slope), terrain_height)
end
terrain_height_map[i] = terrain_height

294
init.lua
View File

@ -1,279 +1,43 @@
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/'
if minetest.get_mapgen_setting("mg_name") ~= "singlenode" then
minetest.set_mapgen_setting("mg_name", "singlenode", true)
minetest.log("warning", "[mapgen_rivers] Mapgen set to singlenode")
end
dofile(modpath .. 'settings.lua')
local modpath = minetest.get_modpath(minetest.get_current_modname())
dofile(modpath .. '/settings.lua')
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 minetest.global_exists('default') and not use_biomegen_mod
if use_biomegen_mod then
biomegen.set_elevation_chill(elevation_chill)
end
dofile(modpath .. 'noises.lua')
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)
local sfile = io.open(minetest.get_worldpath() .. '/river_data/size')
if sfile then
sfile:close()
else
dofile(modpath .. '/pregenerate.lua')
collectgarbage()
end
-- Localize for performance
local floor, min = math.floor, math.min
local data = {}
local noise_x_obj, noise_z_obj, noise_distort_obj, noise_heat_obj, noise_heat_blend_obj
local noise_x_map = {}
local noise_z_map = {}
local noise_distort_map = {}
local noise_heat_map = {}
local noise_heat_blend_map = {}
local mapsize
local init = false
local sumtime = 0
local sumtime2 = 0
local ngen = 0
local function generate(minp, maxp, seed)
minetest.log("info", ("[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)
end
init = true
end
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)
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[i]*distort + x
if xv < xmin then xmin = xv end
if xv > xmax then xmax = xv end
noise_x_map[i] = xv
local zv = noise_z_map[i]*distort + z
if zv < zmin then zmin = zv end
if zv > zmax then zmax = zv end
noise_z_map[i] = zv
end
i2d = i2d-chulens.x
end
end
local pminp = {x=floor(xmin), z=floor(zmin)}
local pmaxp = {x=floor(xmax)+1, z=floor(zmax)+1}
incr = pmaxp.x-pminp.x+1
i_origin = 1 - pminp.z*incr - pminp.x
terrain_map, lake_map = heightmaps(pminp, pmaxp)
mapgen_rivers.use_mapgen_thread = minetest.settings:get_bool("mapgen_rivers_use_mapgen_thread")
mapgen_rivers.thread = 'main'
if mapgen_rivers.use_mapgen_thread then
if minetest.register_mapgen_dofile then
minetest.register_mapgen_dofile(modpath .. '/mapgen.lua')
else
terrain_map, lake_map = heightmaps(minp, maxp)
minetest.log("warning", "[mapgen_rivers] Mapgen thread not available on this Minetest version.")
mapgen_rivers.use_mapgen_thread = false
end
-- Check that there is at least one position that reaches min y
if minp.y > sea_level then
local y0 = minp.y
local is_empty = true
for i=1, #terrain_map do
if terrain_map[i] >= y0 or lake_map[i] >= y0 then
is_empty = false
break
end
end
-- If not, skip chunk
if is_empty then
local t = os.clock() - t0
ngen = ngen + 1
sumtime = sumtime + t
sumtime2 = sumtime2 + t*t
minetest.log("verbose", "[mapgen_rivers] Skipping empty chunk (fully above ground level)")
minetest.log("verbose", ("[mapgen_rivers] Done in %5.3f s"):format(t))
return
end
end
local c_stone = minetest.get_content_id("mapgen_stone")
local c_water = minetest.get_content_id("mapgen_water_source")
local c_rwater = minetest.get_content_id("mapgen_river_water_source")
local c_dirt, c_lawn, c_dirtsnow, c_snow, c_sand, c_ice
if use_biomes then
c_dirt = minetest.get_content_id("default:dirt")
c_lawn = minetest.get_content_id("default:dirt_with_grass")
c_dirtsnow = minetest.get_content_id("default:dirt_with_snow")
c_snow = minetest.get_content_id("default:snowblock")
c_sand = minetest.get_content_id("default:sand")
c_ice = minetest.get_content_id("default:ice")
end
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 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
for z = minp.z, maxp.z do
for x = minp.x, maxp.x do
local ivm = a:index(x, maxp.y+1, z)
local ground_above = false
local temperature
if use_biomes then
temperature = noise_heat_map[i2d]+noise_heat_blend_map[i2d]
end
local terrain, lake
if not use_distort then
terrain = terrain_map[i2d]
lake = lake_map[i2d]
end
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 = floor(xn)
local z0 = 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)
lake = min(lake_map[i0], lake_map[i1], lake_map[i2], lake_map[i3])
end
if y <= maxp.y then
local is_lake = lake > terrain
if y <= terrain then
if not use_biomes or y <= terrain-1 or ground_above then
data[ivm] = c_stone
elseif is_lake or y < sea_level then
data[ivm] = c_sand
else
local temperature_y = temperature - y*elevation_chill
if temperature_y >= 15 then
data[ivm] = c_lawn
elseif temperature_y >= 0 then
data[ivm] = c_dirtsnow
else
data[ivm] = c_snow
end
end
elseif y <= lake and lake > sea_level then
if not use_biomes or temperature - y*elevation_chill >= 0 then
data[ivm] = c_rwater
else
data[ivm] = c_ice
end
elseif y <= sea_level then
data[ivm] = c_water
end
end
ground_above = y <= terrain
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
if use_biomegen_mod then
biomegen.generate_all(data, a, vm, minp, maxp, seed)
else
vm:set_data(data)
minetest.generate_ores(vm, minp, maxp)
end
vm:set_lighting({day = 0, night = 0})
vm:calc_lighting()
vm:update_liquids()
vm:write_to_map()
local t = os.clock()-t0
ngen = ngen + 1
sumtime = sumtime + t
sumtime2 = sumtime2 + t*t
minetest.log("verbose", ("[mapgen_rivers] Done in %5.3f s"):format(t))
end
minetest.register_on_generated(generate)
minetest.register_on_shutdown(function()
local avg = sumtime / ngen
local std = math.sqrt(sumtime2/ngen - avg*avg)
minetest.log("action", ("[mapgen_rivers] Mapgen statistics:\n- Mapgen calls: %4d\n- Mean time: %5.3f s\n- Standard deviation: %5.3f s"):format(ngen, avg, std))
end)
if not mapgen_rivers.use_mapgen_thread then
dofile(modpath .. '/mapgen.lua')
end
-- Setup a metatable to load grid on request if not present
local mt = {
__index = function(_, field)
if field == 'grid' then
dofile(modpath .. '/load_grid.lua')
return mapgen_rivers.grid
end
end,
}
setmetatable(mapgen_rivers, mt)

View File

@ -1,98 +0,0 @@
local worldpath = mapgen_rivers.world_data_path
local floor = math.floor
local sbyte, schar = string.byte, string.char
local unpk = unpack
function mapgen_rivers.load_map(filename, bytes, signed, size, converter)
local file = io.open(worldpath .. filename, 'rb')
local data = file:read('*all')
if #data < bytes*size then
data = minetest.decompress(data)
end
local map = {}
for i=1, size do
local i0 = (i-1)*bytes+1
local elements = {data:byte(i0, i1)}
local n = sbyte(data, i0)
if signed and n >= 128 then
n = n - 256
end
for j=1, bytes-1 do
n = n*256 + sbyte(data, i0+j)
end
map[i] = n
end
file:close()
if converter then
for i=1, size do
map[i] = converter(map[i])
end
end
return map
end
local loader_mt = {
__index = function(loader, i)
local file = loader.file
local bytes = loader.bytes
file:seek('set', (i-1)*bytes)
local strnum = file:read(bytes)
local n = sbyte(strnum, 1)
if loader.signed and n >= 128 then
n = n - 256
end
for j=2, bytes do
n = n*256 + sbyte(strnum, j)
end
if loader.conv then
n = loader.conv(n)
end
loader[i] = n
return n
end,
}
function mapgen_rivers.interactive_loader(filename, bytes, signed, size, converter)
local file = io.open(worldpath .. filename, 'rb')
if file then
minetest.register_on_shutdown(function()
file:close()
end)
converter = converter or false
return setmetatable({file=file, bytes=bytes, signed=signed, size=size, conv=converter}, loader_mt)
end
end
function mapgen_rivers.write_map(filename, data, bytes)
local size = #data
local file = io.open(worldpath .. filename, 'wb')
local bytelist = {}
for j=1, bytes do
bytelist[j] = 0
end
for i=1, size do
local n = floor(data[i])
data[i] = n
for j=bytes, 2, -1 do
bytelist[j] = n % 256
n = floor(n / 256)
end
bytelist[1] = n % 256
file:write(schar(unpk(bytelist)))
end
file:close()
end

107
load_grid.lua Normal file
View File

@ -0,0 +1,107 @@
local datapath = minetest.get_worldpath() .. "/river_data/"
local floor = math.floor
local sbyte = string.byte
local unpk = unpack
local load_map
local use_interactive_loader
if minetest.settings:has("mapgen_rivers_use_interactive_loader") then
use_interactive_loader = minetest.settings:get_bool("mapgen_rivers_use_interactive_loader")
else
use_interactive_loader = not minetest.settings:get_bool("mapgen_rivers_load_all")
end
if use_interactive_loader then
local loader_mt = {
__index = function(loader, i)
local file = loader.file
local bytes = loader.bytes
file:seek('set', (i-1)*bytes)
local strnum = file:read(bytes)
local n = sbyte(strnum, 1)
if loader.signed and n >= 128 then
n = n - 256
end
for j=2, bytes do
n = n*256 + sbyte(strnum, j)
end
if loader.conv then
n = loader.conv(n)
end
loader[i] = n
return n
end,
}
load_map = function(filename, bytes, signed, size, converter)
local file = io.open(datapath .. filename, 'rb')
if file then
minetest.register_on_shutdown(function()
file:close()
end)
converter = converter or false
return setmetatable({file=file, bytes=bytes, signed=signed, size=size, conv=converter}, loader_mt)
end
end
else
load_map = function(filename, bytes, signed, size, converter)
local file = io.open(datapath .. filename, 'rb')
local data = file:read('*all')
if #data < bytes*size then
data = minetest.decompress(data)
end
local map = {}
for i=1, size do
local i0 = (i-1)*bytes+1
local i1 = i*bytes
local elements = {data:byte(i0, i1)}
local n = sbyte(data, i0)
if signed and n >= 128 then
n = n - 256
end
for j=1, bytes-1 do
n = n*256 + sbyte(data, i0+j)
end
map[i] = n
end
file:close()
if converter then
for i=1, size do
map[i] = converter(map[i])
end
end
return map
end
end
local sfile = io.open(datapath..'size', 'r')
assert(sfile)
local X, Z = tonumber(sfile:read('*l')), tonumber(sfile:read('*l'))
sfile:close()
local function offset_converter(o)
return (o + 0.5) * (1/256)
end
mapgen_rivers.grid = {
size = {x=X, y=Z},
dem = load_map('dem', 2, true, X*Z),
lakes = load_map('lakes', 2, true, X*Z),
dirs = load_map('dirs', 1, false, X*Z),
rivers = load_map('rivers', 4, false, X*Z),
offset_x = load_map('offset_x', 1, true, X*Z, offset_converter),
offset_y = load_map('offset_y', 1, true, X*Z, offset_converter);
}

307
mapgen.lua Normal file
View File

@ -0,0 +1,307 @@
-- Recreate mod table if we are in a separate environment
if not minetest.global_exists("mapgen_rivers") then
mapgen_rivers = {use_mapgen_thread=true, thread='mapgen'}
mapgen_rivers.settings = Settings(minetest.get_worldpath() .. '/mapgen_rivers.conf')
end
if not mapgen_rivers.grid then
dofile(minetest.get_modpath(minetest.get_current_modname()) .. '/load_grid.lua')
end
local settings = mapgen_rivers.settings
local sea_level = tonumber(minetest.get_mapgen_setting("water_level"))
local elevation_chill = tonumber(settings:get('elevation_chill'))
local use_distort = settings:get_bool('distort')
local use_biomes = settings:get_bool('biomes')
local use_biomegen_mod = use_biomes and minetest.global_exists('biomegen')
use_biomes = use_biomes and minetest.get_modpath("default") and not use_biomegen_mod
local noiseparams = {
distort_x = settings:get_np_group('np_distort_x'),
distort_z = settings:get_np_group('np_distort_z'),
distort_amplitude = settings:get_np_group('np_distort_amplitude'),
}
if use_biomes then
noiseparams.heat = minetest.get_mapgen_setting_noiseparams("mg_biome_np_heat")
noiseparams.heat.offset = noiseparams.heat.offset + sea_level / elevation_chill
noiseparams.heat_blend = minetest.get_mapgen_setting_noiseparams("mg_biome_np_heat_blend")
end
if use_biomegen_mod then
biomegen.set_elevation_chill(elevation_chill)
end
local heightmaps = dofile(minetest.get_modpath(minetest.get_current_modname()) .. '/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
-- Localize for performance
local floor, min = math.floor, math.min
local data = {}
local noise_x_obj, noise_z_obj, noise_distort_obj, noise_heat_obj, noise_heat_blend_obj
local noise_x_map = {}
local noise_z_map = {}
local noise_distort_map = {}
local noise_heat_map = {}
local noise_heat_blend_map = {}
local mapsize
local init = false
local sumtime = 0
local sumtime2 = 0
local ngen = 0
local function init_mapgen(chulens)
mapsize = {
x = chulens.x,
y = chulens.y+1,
z = chulens.z,
}
if use_distort then
noise_x_obj = minetest.get_perlin_map(noiseparams.distort_x, mapsize)
noise_z_obj = minetest.get_perlin_map(noiseparams.distort_z, mapsize)
noise_distort_obj = minetest.get_perlin_map(noiseparams.distort_amplitude, chulens)
end
if use_biomes then
noise_heat_obj = minetest.get_perlin_map(noiseparams.heat, chulens)
noise_heat_blend_obj = minetest.get_perlin_map(noiseparams.heat_blend, chulens)
end
end
local function generate(vm, minp, maxp, seed)
minetest.log("info", ("[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
init_mapgen(chulens)
init = true
end
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)
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[i]*distort + x
if xv < xmin then xmin = xv end
if xv > xmax then xmax = xv end
noise_x_map[i] = xv
local zv = noise_z_map[i]*distort + z
if zv < zmin then zmin = zv end
if zv > zmax then zmax = zv end
noise_z_map[i] = zv
end
i2d = i2d-chulens.x
end
end
local pminp = {x=floor(xmin), z=floor(zmin)}
local pmaxp = {x=floor(xmax)+1, z=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
-- Check that there is at least one position that reaches min y
if minp.y > sea_level then
local y0 = minp.y
local is_empty = true
for i=1, #terrain_map do
if terrain_map[i] >= y0 or lake_map[i] >= y0 then
is_empty = false
break
end
end
-- If not, skip chunk
if is_empty then
local t = os.clock() - t0
ngen = ngen + 1
sumtime = sumtime + t
sumtime2 = sumtime2 + t*t
minetest.log("verbose", "[mapgen_rivers] Skipping empty chunk (fully above ground level)")
minetest.log("verbose", ("[mapgen_rivers] Done in %5.3f s"):format(t))
return
end
end
local c_stone = minetest.get_content_id("mapgen_stone")
local c_water = minetest.get_content_id("mapgen_water_source")
local c_rwater = minetest.get_content_id("mapgen_river_water_source")
local c_dirt, c_lawn, c_dirtsnow, c_snow, c_sand, c_ice
if use_biomes then
c_dirt = minetest.get_content_id("default:dirt")
c_lawn = minetest.get_content_id("default:dirt_with_grass")
c_dirtsnow = minetest.get_content_id("default:dirt_with_snow")
c_snow = minetest.get_content_id("default:snowblock")
c_sand = minetest.get_content_id("default:sand")
c_ice = minetest.get_content_id("default:ice")
end
local emin, emax = vm:get_emerged_area()
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 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
for z = minp.z, maxp.z do
for x = minp.x, maxp.x do
local ivm = a:index(x, maxp.y+1, z)
local ground_above = false
local temperature
if use_biomes then
temperature = noise_heat_map[i2d]+noise_heat_blend_map[i2d]
end
local terrain, lake
if not use_distort then
terrain = terrain_map[i2d]
lake = lake_map[i2d]
end
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 = floor(xn)
local z0 = 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)
lake = min(lake_map[i0], lake_map[i1], lake_map[i2], lake_map[i3])
end
if y <= maxp.y then
local is_lake = lake > terrain
if y <= terrain then
if not use_biomes or y <= terrain-1 or ground_above then
data[ivm] = c_stone
elseif is_lake or y < sea_level then
data[ivm] = c_sand
else
local temperature_y = temperature - y*elevation_chill
if temperature_y >= 15 then
data[ivm] = c_lawn
elseif temperature_y >= 0 then
data[ivm] = c_dirtsnow
else
data[ivm] = c_snow
end
end
elseif y <= lake and lake > sea_level then
if not use_biomes or temperature - y*elevation_chill >= 0 then
data[ivm] = c_rwater
else
data[ivm] = c_ice
end
elseif y <= sea_level then
data[ivm] = c_water
end
end
ground_above = y <= terrain
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
if use_biomegen_mod then
biomegen.generate_all(data, a, vm, minp, maxp, seed)
else
vm:set_data(data)
minetest.generate_ores(vm, minp, maxp)
end
vm:set_lighting({day = 0, night = 0})
vm:calc_lighting()
vm:update_liquids()
if mapgen_rivers.thread == "main" then
vm:write_to_map()
end
local t = os.clock()-t0
ngen = ngen + 1
sumtime = sumtime + t
sumtime2 = sumtime2 + t*t
minetest.log("verbose", ("[mapgen_rivers] Done in %5.3f s"):format(t))
end
if mapgen_rivers.thread == "main" then
minetest.register_on_generated(function(minp, maxp, seed)
local vm = minetest.get_mapgen_object("voxelmanip")
generate(vm, minp, maxp, seed)
end)
elseif mapgen_rivers.thread == "mapgen" then
minetest.register_on_generated(generate)
end
minetest.register_on_shutdown(function()
if ngen == 0 then
return
end
local avg = sumtime / ngen
local std = math.sqrt(sumtime2/ngen - avg*avg)
minetest.log("action", ("[mapgen_rivers] Mapgen statistics:\n- Mapgen calls: %4d\n- Mean time: %5.3f s\n- Standard deviation: %5.3f s"):format(ngen, avg, std))
end)

View File

@ -1,80 +0,0 @@
local def_setting = mapgen_rivers.define_setting
mapgen_rivers.noise_params = {
base = def_setting('np_base', 'noise', {
offset = 0,
scale = 300,
seed = 2469,
octaves = 8,
spread = {x=2048, y=2048, z=2048},
persist = 0.6,
lacunarity = 2,
flags = "eased",
}),
distort_x = def_setting('np_distort_x', 'noise', {
offset = 0,
scale = 1,
seed = -4574,
spread = {x=64, y=32, z=64},
octaves = 3,
persistence = 0.75,
lacunarity = 2,
}),
distort_z = def_setting('np_distort_z', 'noise', {
offset = 0,
scale = 1,
seed = -7940,
spread = {x=64, y=32, z=64},
octaves = 3,
persistence = 0.75,
lacunarity = 2,
}),
distort_amplitude = def_setting('np_distort_amplitude', 'noise', {
offset = 0,
scale = 10,
seed = 676,
spread = {x=1024, y=1024, z=1024},
octaves = 5,
persistence = 0.5,
lacunarity = 2,
flags = "absvalue",
}),
heat = minetest.get_mapgen_setting_noiseparams('mg_biome_np_heat'),
heat_blend = minetest.get_mapgen_setting_noiseparams('mg_biome_np_heat_blend'),
}
-- Convert to number because Minetest API is not able to do it cleanly...
for name, np in pairs(mapgen_rivers.noise_params) do
for field, value in pairs(np) do
if field ~= 'flags' and type(value) == 'string' then
np[field] = tonumber(value) or value
elseif field == 'spread' then
for dir, v in pairs(value) do
value[dir] = tonumber(v) or v
end
end
end
end
local heat = mapgen_rivers.noise_params.heat
local base = mapgen_rivers.noise_params.base
local settings = mapgen_rivers.settings
heat.offset = heat.offset + settings.sea_level * settings.elevation_chill
base.spread.x = base.spread.x / settings.blocksize
base.spread.y = base.spread.y / settings.blocksize
base.spread.z = base.spread.z / settings.blocksize
for name, np in pairs(mapgen_rivers.noise_params) do
local lac = np.lacunarity or 2
if lac > 1 then
local omax = math.floor(math.log(math.min(np.spread.x, np.spread.y, np.spread.z)) / math.log(lac))+1
if np.octaves > omax then
minetest.log("warning", "[mapgen_rivers] Noise " .. name .. ": 'octaves' reduced to " .. omax)
np.octaves = omax
end
end
end

View File

@ -1,91 +1,17 @@
local modpath = mapgen_rivers.modpath
local mod_data_path = modpath .. 'river_data/'
if not io.open(mod_data_path .. 'size', 'r') then
mod_data_path = modpath .. 'demo_data/'
end
local world_data_path = mapgen_rivers.world_data_path
minetest.mkdir(world_data_path)
dofile(modpath .. 'load.lua')
mapgen_rivers.grid = {}
local X = mapgen_rivers.settings.grid_x_size
local Z = mapgen_rivers.settings.grid_z_size
local function offset_converter(o)
return (o + 0.5) * (1/256)
end
local load_all = mapgen_rivers.settings.load_all
-- Try to read file 'size'
local sfile = io.open(world_data_path..'size', 'r')
local first_mapgen = true
if sfile then
X, Z = tonumber(sfile:read('*l')), tonumber(sfile:read('*l'))
sfile:close()
first_mapgen = false
end
if first_mapgen then
-- Generate a map!!
local pregenerate = dofile(mapgen_rivers.modpath .. '/pregenerate.lua')
minetest.register_on_mods_loaded(function()
minetest.log("action", '[mapgen_rivers] Generating grid, this may take a while...')
pregenerate(load_all)
if load_all then
local offset_x = mapgen_rivers.grid.offset_x
local offset_y = mapgen_rivers.grid.offset_y
for i=1, X*Z do
offset_x[i] = offset_converter(offset_x[i])
offset_y[i] = offset_converter(offset_y[i])
end
end
end)
end
-- if data not already loaded
if not (first_mapgen and load_all) then
local load_map
if load_all then
load_map = mapgen_rivers.load_map
else
load_map = mapgen_rivers.interactive_loader
end
minetest.register_on_mods_loaded(function()
if load_all then
minetest.log("action", '[mapgen_rivers] Loading full grid')
else
minetest.log("action", '[mapgen_rivers] Loading grid as interactive loaders')
end
local grid = mapgen_rivers.grid
grid.dem = load_map('dem', 2, true, X*Z)
grid.lakes = load_map('lakes', 2, true, X*Z)
grid.dirs = load_map('dirs', 1, false, X*Z)
grid.rivers = load_map('rivers', 4, false, X*Z)
grid.offset_x = load_map('offset_x', 1, true, X*Z, offset_converter)
grid.offset_y = load_map('offset_y', 1, true, X*Z, offset_converter)
end)
end
mapgen_rivers.grid.size = {x=X, y=Z}
local X = mapgen_rivers.grid.size.x
local Z = mapgen_rivers.grid.size.y
local function index(x, z)
return z*X+x+1
end
local blocksize = mapgen_rivers.settings.blocksize
local min_catchment = mapgen_rivers.settings.min_catchment
local max_catchment = mapgen_rivers.settings.max_catchment
local settings = mapgen_rivers.settings
local blocksize = tonumber(settings:get('blocksize'))
local min_catchment = tonumber(settings:get('min_catchment'))
local map_offset = {x=0, z=0}
if mapgen_rivers.settings.center then
if settings:get_bool('center') then
map_offset.x = blocksize*X/2
map_offset.z = blocksize*Z/2
end
@ -93,8 +19,8 @@ end
-- Localize for performance
local floor, ceil, min, max, abs = math.floor, math.ceil, math.min, math.max, math.abs
local min_catchment = mapgen_rivers.settings.min_catchment / (blocksize*blocksize)
local wpower = mapgen_rivers.settings.river_widening_power
min_catchment = min_catchment / (blocksize*blocksize)
local wpower = settings:get('river_widening_power')
local wfactor = 1/(2*blocksize * min_catchment^wpower)
local function river_width(flow)
flow = abs(flow)
@ -106,14 +32,14 @@ local function river_width(flow)
end
local noise_heat -- Need a large-scale noise here so no heat blend
local elevation_chill = mapgen_rivers.settings.elevation_chill
local elevation_chill = settings:get_bool('elevation_chill')
local function get_temperature(x, y, z)
local pos = {x=x, y=z}
return noise_heat:get2d(pos) - y*elevation_chill
end
local glaciers = mapgen_rivers.settings.glaciers
local glacier_factor = mapgen_rivers.settings.glacier_factor
local glaciers = settings:get_bool('glaciers')
local glacier_factor = tonumber(settings:get('glacier_factor'))
local init = false
@ -236,15 +162,15 @@ local function make_polygons(minp, maxp)
end
end
polygon.river_corners = {riverA, riverB, riverC, riverD}
polygon.river_corners = {riverA, 1-riverB, 2-riverC, 1-riverD}
-- Flow directions
local dirA, dirB, dirC, dirD = dirs[iA], dirs[iB], dirs[iC], dirs[iD]
-- Determine the river flux on the edges, by testing dirs values
local river_west = (dirA==1 and riverA or 0) + (dirD==3 and riverD or 0)
local river_north = (dirA==2 and riverA or 0) + (dirB==4 and riverB or 0)
local river_east = (dirB==1 and riverB or 0) + (dirC==3 and riverC or 0)
local river_south = (dirD==2 and riverD or 0) + (dirC==4 and riverC or 0)
local river_east = 1 - (dirB==1 and riverB or 0) - (dirC==3 and riverC or 0)
local river_south = 1 - (dirD==2 and riverD or 0) - (dirC==4 and riverC or 0)
polygon.rivers = {river_west, river_north, river_east, river_south}
end

View File

@ -1,81 +1,131 @@
local EvolutionModel = dofile(mapgen_rivers.modpath .. '/terrainlib_lua/erosion.lua')
local twist = dofile(mapgen_rivers.modpath .. '/terrainlib_lua/twist.lua')
local modpath = minetest.get_modpath(minetest.get_current_modname())
local blocksize = mapgen_rivers.settings.blocksize
local tectonic_speed = mapgen_rivers.settings.tectonic_speed
local EvolutionModel = dofile(modpath .. '/terrainlib_lua/erosion.lua')
local twist = dofile(modpath .. '/terrainlib_lua/twist.lua')
local np_base = table.copy(mapgen_rivers.noise_params.base)
local blocksize = tonumber(mapgen_rivers.settings:get("blocksize"))
local tectonic_speed = tonumber(mapgen_rivers.settings:get("tectonic_speed"))
local evol_params = mapgen_rivers.settings.evol_params
local np_base = mapgen_rivers.settings:get_np_group("np_base")
np_base.spread.x = np_base.spread.x / blocksize
np_base.spread.y = np_base.spread.y / blocksize
np_base.spread.z = np_base.spread.z / blocksize
local time = mapgen_rivers.settings.evol_time
local time_step = mapgen_rivers.settings.evol_time_step
local evol_params = {
K = tonumber(mapgen_rivers.settings:get("river_erosion_coef")),
m = tonumber(mapgen_rivers.settings:get("river_erosion_power")),
d = tonumber(mapgen_rivers.settings:get("difusive_erosion")),
}
local time = tonumber(mapgen_rivers.settings:get("evol_time"))
local time_step = tonumber(mapgen_rivers.settings:get("evol_time_step"))
local niter = math.ceil(time/time_step)
time_step = time / niter
local function pregenerate(keep_loaded)
local grid = mapgen_rivers.grid
local size = grid.size
-- Setup the model
local size = {
x = tonumber(mapgen_rivers.settings:get("grid_x_size")),
y = tonumber(mapgen_rivers.settings:get("grid_z_size")),
}
local seed = tonumber(minetest.get_mapgen_setting("seed"))
np_base.seed = (np_base.seed or 0) + seed
local seed = tonumber(minetest.get_mapgen_setting("seed"))
np_base.seed = (np_base.seed or 0) + seed
local nobj_base = PerlinNoiseMap(np_base, {x=size.x, y=1, z=size.y})
local nobj_base = PerlinNoiseMap(np_base, {x=size.x, y=1, z=size.y})
local dem = nobj_base:get_3d_map_flat({x=0, y=0, z=0})
dem.X = size.x
dem.Y = size.y
local dem = nobj_base:get_3d_map_flat({x=0, y=0, z=0})
dem.X = size.x
dem.Y = size.y
local model = EvolutionModel(evol_params)
model.dem = dem
local ref_dem = model:define_isostasy(dem)
local model = EvolutionModel(evol_params)
model.dem = dem
local ref_dem = model:define_isostasy(dem)
local tectonic_step = tectonic_speed * time_step
collectgarbage()
for i=1, niter do
minetest.log("info", "[mapgen_rivers] Iteration " .. i .. " of " .. niter)
local tectonic_step = tectonic_speed * time_step
collectgarbage()
model:diffuse(time_step)
model:flow()
model:erode(time_step)
if i < niter then
if tectonic_step ~= 0 then
nobj_base:get_3d_map_flat({x=0, y=tectonic_step*i, z=0}, ref_dem)
end
model:isostasy()
end
-- Run the model
for i=1, niter do
minetest.log("info", "[mapgen_rivers] Iteration " .. i .. " of " .. niter)
collectgarbage()
end
model:diffuse(time_step)
model:flow()
local mfloor = math.floor
local mmin, mmax = math.min, math.max
local offset_x, offset_y = twist(model.dirs, model.rivers, 5)
for i=1, size.x*size.y do
offset_x[i] = mmin(mmax(offset_x[i]*256, -128), 127)
offset_y[i] = mmin(mmax(offset_y[i]*256, -128), 127)
model:erode(time_step)
if i < niter then
if tectonic_step ~= 0 then
nobj_base:get_3d_map_flat({x=0, y=tectonic_step*i, z=0}, ref_dem)
end
model:isostasy()
end
mapgen_rivers.write_map('dem', model.dem, 2)
mapgen_rivers.write_map('lakes', model.lakes, 2)
mapgen_rivers.write_map('dirs', model.dirs, 1)
mapgen_rivers.write_map('rivers', model.rivers, 4)
mapgen_rivers.write_map('offset_x', offset_x, 1)
mapgen_rivers.write_map('offset_y', offset_y, 1)
local sfile = io.open(mapgen_rivers.world_data_path .. 'size', "w")
sfile:write(size.x..'\n'..size.y)
sfile:close()
if keep_loaded then
grid.dem = model.dem
grid.lakes = model.lakes
grid.dirs = model.dirs
grid.rivers = model.rivers
grid.offset_x = offset_x
grid.offset_y = offset_y
end
collectgarbage()
end
model:flow()
return pregenerate
local mfloor = math.floor
local mmin, mmax = math.min, math.max
local offset_x, offset_y = twist(model.dirs, model.rivers, 5)
for i=1, size.x*size.y do
offset_x[i] = mmin(mmax(offset_x[i]*256, -128), 127)
offset_y[i] = mmin(mmax(offset_y[i]*256, -128), 127)
end
-- Write the results in the world directory
local datapath = minetest.get_worldpath() .. "/river_data/"
minetest.mkdir(datapath)
local function write_map(filename, data, bytes)
local size = #data
local file = io.open(datapath .. filename, 'wb')
local bytelist = {}
for j=1, bytes do
bytelist[j] = 0
end
local unpk = unpack
local schar = string.char
local floor = math.floor
for i=1, size do
local n = floor(data[i])
data[i] = n
for j=bytes, 2, -1 do
bytelist[j] = n % 256
n = floor(n / 256)
end
bytelist[1] = n % 256
file:write(schar(unpk(bytelist)))
end
file:close()
end
write_map('dem', model.dem, 2)
write_map('lakes', model.lakes, 2)
write_map('dirs', model.dirs, 1)
write_map('rivers', model.rivers, 4)
write_map('offset_x', offset_x, 1)
write_map('offset_y', offset_y, 1)
local sfile = io.open(datapath .. 'size', "w")
sfile:write(size.x..'\n'..size.y)
sfile:close()
local use_interactive_loader
if minetest.settings:has("mapgen_rivers_use_interactive_loader") then
use_interactive_loader = minetest.settings:get_bool("mapgen_rivers_use_interactive_loader")
else
use_interactive_loader = not minetest.settings:get_bool("mapgen_rivers_load_all")
end
if not use_interactive_loader then
mapgen_rivers.grid = {
size = size,
dem = model.dem,
lakes = model.lakes,
dirs = model.dirs,
rivers = model.rivers,
offset_x = offset_x,
offset_y = offset_y,
}
end

View File

@ -1,10 +1,11 @@
local mtsettings = minetest.settings
local mgrsettings = Settings(minetest.get_worldpath() .. '/mapgen_rivers.conf')
local settings = Settings(minetest.get_worldpath() .. '/mapgen_rivers.conf')
mapgen_rivers.version = "1.0.2"
mapgen_rivers.settings = settings
local previous_version_mt = mtsettings:get("mapgen_rivers_version") or "0.0"
local previous_version_mgr = mgrsettings:get("version") or "0.0"
local previous_version_mgr = settings:get("version") or "0.0"
if mapgen_rivers.version ~= previous_version_mt or mapgen_rivers.version ~= previous_version_mgr then
local compat_mt, compat_mgr = dofile(minetest.get_modpath(minetest.get_current_modname()) .. "/compatibility.lua")
@ -12,84 +13,103 @@ if mapgen_rivers.version ~= previous_version_mt or mapgen_rivers.version ~= prev
compat_mt(mtsettings)
end
if mapgen_rivers.version ~= previous_version_mgr then
compat_mgr(mgrsettings)
compat_mgr(settings)
end
end
mtsettings:set("mapgen_rivers_version", mapgen_rivers.version)
mgrsettings:set("version", mapgen_rivers.version)
settings:set("version", mapgen_rivers.version)
function mapgen_rivers.define_setting(name, dtype, default)
local modified = false
local function verify_setting(name, dtype, default)
if settings:has(name) then
return
end
modified = true
local v = default
local mtname = 'mapgen_rivers_' .. name
local mthas = mtsettings:has(mtname)
if dtype == "number" or dtype == "string" then
local v = mgrsettings:get(name)
if v == nil then
v = mtsettings:get('mapgen_rivers_' .. name)
if v == nil then
if mthas then
v = mtsettings:get(mtname)
if dtype == "number" and tonumber(v) == nil then
v = default
end
mgrsettings:set(name, v)
end
if dtype == "number" then
return tonumber(v)
else
return v
end
settings:set(name, v)
elseif dtype == "bool" then
local v = mgrsettings:get_bool(name)
if v == nil then
v = mtsettings:get_bool('mapgen_rivers_' .. name)
if v == nil then
v = default
end
mgrsettings:set_bool(name, v)
if mthas then
v = mtsettings:get(mtname)
end
return v
settings:set_bool(name, v)
elseif dtype == "noise" then
local v = mgrsettings:get_np_group(name)
if v == nil then
v = mtsettings:get_np_group('mapgen_rivers_' .. name)
if v == nil then
v = default
end
mgrsettings:set_np_group(name, v)
if mthas then
v = mtsettings:get_np_group(mtname)
end
return v
settings:set_np_group(name, v)
end
end
local def_setting = mapgen_rivers.define_setting
verify_setting('center', 'bool', true)
verify_setting('blocksize', 'number', 15)
verify_setting('min_catchment', 'number', 3600)
verify_setting('river_widening_power', 'number', 0.5)
verify_setting('riverbed_slope', 'number', 0.4)
verify_setting('distort', 'bool', true)
verify_setting('biomes', 'bool', true)
verify_setting('glaciers', 'bool', false)
verify_setting('glacier_factor', 'number', 8)
verify_setting('elevation_chill', 'number', 0.25)
verify_setting('grid_x_size', 'number', 1000)
verify_setting('grid_z_size', 'number', 1000)
verify_setting('river_erosion_coef', 'number', 0.5)
verify_setting('river_erosion_power', 'number', 0.4)
verify_setting('diffusive_erosion', 'number', 0.5)
verify_setting('compensation_radius', 'number', 50)
verify_setting('tectonic_speed', 'number', 70)
verify_setting('evol_time', 'number', 10)
verify_setting('evol_time_step', 'number', 1)
mapgen_rivers.settings = {
center = def_setting('center', 'bool', true),
blocksize = def_setting('blocksize', 'number', 15),
sea_level = tonumber(minetest.get_mapgen_setting('water_level')),
min_catchment = def_setting('min_catchment', 'number', 3600),
river_widening_power = def_setting('river_widening_power', 'number', 0.5),
riverbed_slope = def_setting('riverbed_slope', 'number', 0.4),
distort = def_setting('distort', 'bool', true),
biomes = def_setting('biomes', 'bool', true),
glaciers = def_setting('glaciers', 'bool', false),
glacier_factor = def_setting('glacier_factor', 'number', 8),
elevation_chill = def_setting('elevation_chill', 'number', 0.25),
verify_setting('np_base', 'noise', {
offset = 0,
scale = 300,
seed = 2469,
octaves = 8,
spread = {x=2048, y=2048, z=2048},
persist = 0.6,
lacunarity = 2,
flags = "eased",
})
verify_setting('np_distort_x', 'noise', {
offset = 0,
scale = 1,
seed = -4574,
spread = {x=64, y=32, z=64},
octaves = 3,
persistence = 0.75,
lacunarity = 2,
})
verify_setting('np_distort_z', 'noise', {
offset = 0,
scale = 1,
seed = -7940,
spread = {x=64, y=32, z=64},
octaves = 3,
persistence = 0.75,
lacunarity = 2,
})
verify_setting('np_distort_amplitude', 'noise', {
offset = 0,
scale = 10,
seed = 676,
spread = {x=1024, y=1024, z=1024},
octaves = 5,
persistence = 0.5,
lacunarity = 2,
flags = "absvalue",
})
grid_x_size = def_setting('grid_x_size', 'number', 1000),
grid_z_size = def_setting('grid_z_size', 'number', 1000),
evol_params = {
K = def_setting('river_erosion_coef', 'number', 0.5),
m = def_setting('river_erosion_power', 'number', 0.4),
d = def_setting('diffusive_erosion', 'number', 0.5),
compensation_radius = def_setting('compensation_radius', 'number', 50),
},
tectonic_speed = def_setting('tectonic_speed', 'number', 70),
evol_time = def_setting('evol_time', 'number', 10),
evol_time_step = def_setting('evol_time_step', 'number', 1),
load_all = mtsettings:get_bool('mapgen_rivers_load_all')
}
local function write_settings()
mgrsettings:write()
if modified then
settings:write()
end
minetest.register_on_mods_loaded(write_settings)
minetest.register_on_shutdown(write_settings)

View File

@ -123,11 +123,7 @@ end
local modpath = ""
if minetest then
if minetest.global_exists('mapgen_rivers') then
modpath = mapgen_rivers.modpath .. "terrainlib_lua/"
else
modpath = minetest.get_modpath(minetest.get_current_modname()) .. "terrainlib_lua/"
end
modpath = minetest.get_modpath(minetest.get_current_modname()) .. "/terrainlib_lua/"
end
local rivermapper = dofile(modpath .. "rivermapper.lua")