3 Commits

Author SHA1 Message Date
12c3394114 Express map size in Minetest nodes, not in river grid nodes
This introduces new parameters 'map_x_size' and 'map_z_size' that default to 15K
Deprecates 'grid_x_size' and 'grid_z_size'; if they are present, corresponding
values of 'map_x_size' and 'map_z_size' are automatically written in config files.
Also rework compatibility system to better compare versions,
and bump version to 1.0.2-dev1.
2022-01-18 17:58:51 +01:00
b374e8ee95 Create settings_default.json to store default values for settings
Move noise parameters to settings.lua
2022-01-18 15:21:14 +01:00
1ad8c96b8c Remove 'default' hard dependency 2022-01-17 23:20:34 +01:00
10 changed files with 207 additions and 130 deletions

View File

@ -17,7 +17,7 @@ Code: Gaël de Sailly
Flow routing algorithm concept (in `terrainlib/rivermapper.lua`): Cordonnier, G., Bovy, B., & Braun, J. (2019). A versatile, linear complexity algorithm for flow routing in topographies with depressions. Earth Surface Dynamics, 7(2), 549-562. Flow routing algorithm concept (in `terrainlib/rivermapper.lua`): Cordonnier, G., Bovy, B., & Braun, J. (2019). A versatile, linear complexity algorithm for flow routing in topographies with depressions. Earth Surface Dynamics, 7(2), 549-562.
# Requirements # Requirements
Mod dependencies: `default` required, and [`biomegen`](https://github.com/Gael-de-Sailly/biomegen) optional (provides biome system). No required dependency, but [`biomegen`](https://gitlab.com/gaelysam/biomegen) recommended (provides biome system).
# Installation # Installation
This mod should be placed in the `mods/` directory of Minetest like any other mod. This mod should be placed in the `mods/` directory of Minetest like any other mod.

View File

@ -1,3 +1,21 @@
local function version_is_lower(v1, v2)
local d1, c1, d2, c2
while #v1 > 0 and #v2 > 0 do
d1, c1, v1 = v1:match("^(%d*)(%D*)(.*)$")
d2, c2, v2 = v2:match("^(%d*)(%D*)(.*)$")
d1 = tonumber(d1) or -1
d2 = tonumber(d2) or -1
if d1 ~= d2 then
return d1 < d2
end
if c1 ~= c2 then
return c1 < c2
end
end
return false
end
local function fix_min_catchment(settings, is_global) local function fix_min_catchment(settings, is_global)
local prefix = is_global and "mapgen_rivers_" or "" local prefix = is_global and "mapgen_rivers_" or ""
@ -21,6 +39,18 @@ local function fix_compatibility_minetest(settings)
if previous_version == "0.0" then if previous_version == "0.0" then
fix_min_catchment(settings, true) fix_min_catchment(settings, true)
end end
if version_is_lower(previous_version, "1.0.2-dev1") then
local blocksize = tonumber(settings:get("mapgen_rivers_blocksize") or 15)
local grid_x_size = tonumber(settings:get("mapgen_rivers_grid_x_size"))
if grid_x_size then
settings:set("mapgen_rivers_map_x_size", tostring(grid_x_size * blocksize))
end
local grid_z_size = tonumber(settings:get("mapgen_rivers_grid_z_size"))
if grid_z_size then
settings:set("mapgen_rivers_map_z_size", tostring(grid_z_size * blocksize))
end
end
end end
local function fix_compatibility_mapgen_rivers(settings) local function fix_compatibility_mapgen_rivers(settings)
@ -29,6 +59,18 @@ local function fix_compatibility_mapgen_rivers(settings)
if previous_version == "0.0" then if previous_version == "0.0" then
fix_min_catchment(settings, false) fix_min_catchment(settings, false)
end end
if version_is_lower(previous_version, "1.0.2-dev1") then
local blocksize = tonumber(settings:get("blocksize") or 15)
local grid_x_size = tonumber(settings:get("grid_x_size"))
if grid_x_size then
settings:set("map_x_size", tostring(grid_x_size * blocksize))
end
local grid_z_size = tonumber(settings:get("grid_z_size"))
if grid_z_size then
settings:set("map_z_size", tostring(grid_z_size * blocksize))
end
end
end end
return fix_compatibility_minetest, fix_compatibility_mapgen_rivers return fix_compatibility_minetest, fix_compatibility_mapgen_rivers

View File

@ -16,12 +16,11 @@ local elevation_chill = mapgen_rivers.settings.elevation_chill
local use_distort = mapgen_rivers.settings.distort local use_distort = mapgen_rivers.settings.distort
local use_biomes = mapgen_rivers.settings.biomes local use_biomes = mapgen_rivers.settings.biomes
local use_biomegen_mod = use_biomes and minetest.global_exists('biomegen') local use_biomegen_mod = use_biomes and minetest.global_exists('biomegen')
use_biomes = use_biomes and not use_biomegen_mod use_biomes = use_biomes and minetest.global_exists('default') and not use_biomegen_mod
if use_biomegen_mod then if use_biomegen_mod then
biomegen.set_elevation_chill(elevation_chill) biomegen.set_elevation_chill(elevation_chill)
end end
dofile(modpath .. 'noises.lua')
local heightmaps = dofile(modpath .. 'heightmap.lua') local heightmaps = dofile(modpath .. 'heightmap.lua')
@ -147,15 +146,19 @@ local function generate(minp, maxp, seed)
end end
end end
local c_stone = minetest.get_content_id("default:stone") local c_stone = minetest.get_content_id("mapgen_stone")
local c_dirt = minetest.get_content_id("default:dirt") local c_water = minetest.get_content_id("mapgen_water_source")
local c_lawn = minetest.get_content_id("default:dirt_with_grass") local c_rwater = minetest.get_content_id("mapgen_river_water_source")
local c_dirtsnow = minetest.get_content_id("default:dirt_with_snow")
local c_snow = minetest.get_content_id("default:snowblock") local c_dirt, c_lawn, c_dirtsnow, c_snow, c_sand, c_ice
local c_sand = minetest.get_content_id("default:sand") if use_biomes then
local c_water = minetest.get_content_id("default:water_source") c_dirt = minetest.get_content_id("default:dirt")
local c_rwater = minetest.get_content_id("default:river_water_source") c_lawn = minetest.get_content_id("default:dirt_with_grass")
local c_ice = minetest.get_content_id("default:ice") 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") local vm, emin, emax = minetest.get_mapgen_object("voxelmanip")
vm:get_data(data) vm:get_data(data)

View File

@ -1,4 +1,3 @@
name = mapgen_rivers name = mapgen_rivers
title = Map generator with realistic rivers title = Map generator with realistic rivers
depends = default optional_depends = biomegen, default
optional_depends = biomegen

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

@ -11,8 +11,9 @@ dofile(modpath .. 'load.lua')
mapgen_rivers.grid = {} mapgen_rivers.grid = {}
local X = mapgen_rivers.settings.grid_x_size local blocksize = mapgen_rivers.settings.blocksize
local Z = mapgen_rivers.settings.grid_z_size local X = math.floor(mapgen_rivers.settings.map_x_size / blocksize)
local Z = math.floor(mapgen_rivers.settings.map_z_size / blocksize)
local function offset_converter(o) local function offset_converter(o)
return (o + 0.5) * (1/256) return (o + 0.5) * (1/256)
@ -80,7 +81,6 @@ local function index(x, z)
return z*X+x+1 return z*X+x+1
end end
local blocksize = mapgen_rivers.settings.blocksize
local min_catchment = mapgen_rivers.settings.min_catchment local min_catchment = mapgen_rivers.settings.min_catchment
local max_catchment = mapgen_rivers.settings.max_catchment local max_catchment = mapgen_rivers.settings.max_catchment

View File

@ -5,6 +5,7 @@ local blocksize = mapgen_rivers.settings.blocksize
local tectonic_speed = mapgen_rivers.settings.tectonic_speed local tectonic_speed = mapgen_rivers.settings.tectonic_speed
local np_base = table.copy(mapgen_rivers.noise_params.base) local np_base = table.copy(mapgen_rivers.noise_params.base)
np_base.spread = vector.divide(np_base.spread, blocksize)
local evol_params = mapgen_rivers.settings.evol_params local evol_params = mapgen_rivers.settings.evol_params
@ -17,6 +18,10 @@ local function pregenerate(keep_loaded)
local grid = mapgen_rivers.grid local grid = mapgen_rivers.grid
local size = grid.size local size = grid.size
if size.x * size.y > 4e6 then
minetest.log("warning", "[mapgen_rivers] You are going to generate a very large grid (>4M nodes). If you experience problems, you should increase blocksize or reduce map size.")
end
local seed = tonumber(minetest.get_mapgen_setting("seed")) local seed = tonumber(minetest.get_mapgen_setting("seed"))
np_base.seed = (np_base.seed or 0) + seed np_base.seed = (np_base.seed or 0) + seed

View File

@ -1,7 +1,7 @@
local mtsettings = minetest.settings local mtsettings = minetest.settings
local mgrsettings = Settings(minetest.get_worldpath() .. '/mapgen_rivers.conf') local mgrsettings = Settings(minetest.get_worldpath() .. '/mapgen_rivers.conf')
mapgen_rivers.version = "1.0.2" mapgen_rivers.version = "1.0.2-dev1"
local previous_version_mt = mtsettings:get("mapgen_rivers_version") or "0.0" 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 = mgrsettings:get("version") or "0.0"
@ -19,13 +19,33 @@ end
mtsettings:set("mapgen_rivers_version", mapgen_rivers.version) mtsettings:set("mapgen_rivers_version", mapgen_rivers.version)
mgrsettings:set("version", mapgen_rivers.version) mgrsettings:set("version", mapgen_rivers.version)
local defaults
do
local f = io.open(mapgen_rivers.modpath .. "/settings_default.json")
defaults = minetest.parse_json(f:read("*all"))
f:close()
end
-- Convert strings to numbers in noise params because Minetest API is not able to do it cleanly...
local function clean_np(np)
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
function mapgen_rivers.define_setting(name, dtype, default) function mapgen_rivers.define_setting(name, dtype, default)
if dtype == "number" or dtype == "string" then if dtype == "number" or dtype == "string" then
local v = mgrsettings:get(name) local v = mgrsettings:get(name)
if v == nil then if v == nil then
v = mtsettings:get('mapgen_rivers_' .. name) v = mtsettings:get('mapgen_rivers_' .. name)
if v == nil then if v == nil then
v = default v = defaults[name]
end end
mgrsettings:set(name, v) mgrsettings:set(name, v)
end end
@ -39,7 +59,7 @@ function mapgen_rivers.define_setting(name, dtype, default)
if v == nil then if v == nil then
v = mtsettings:get_bool('mapgen_rivers_' .. name) v = mtsettings:get_bool('mapgen_rivers_' .. name)
if v == nil then if v == nil then
v = default v = defaults[name]
end end
mgrsettings:set_bool(name, v) mgrsettings:set_bool(name, v)
end end
@ -49,10 +69,11 @@ function mapgen_rivers.define_setting(name, dtype, default)
if v == nil then if v == nil then
v = mtsettings:get_np_group('mapgen_rivers_' .. name) v = mtsettings:get_np_group('mapgen_rivers_' .. name)
if v == nil then if v == nil then
v = default v = defaults[name]
end end
mgrsettings:set_np_group(name, v) mgrsettings:set_np_group(name, v)
end end
clean_np(v)
return v return v
end end
end end
@ -60,33 +81,46 @@ end
local def_setting = mapgen_rivers.define_setting local def_setting = mapgen_rivers.define_setting
mapgen_rivers.settings = { mapgen_rivers.settings = {
center = def_setting('center', 'bool', true), center = def_setting('center', 'bool'),
blocksize = def_setting('blocksize', 'number', 15), blocksize = def_setting('blocksize', 'number'),
sea_level = tonumber(minetest.get_mapgen_setting('water_level')), sea_level = tonumber(minetest.get_mapgen_setting('water_level')),
min_catchment = def_setting('min_catchment', 'number', 3600), min_catchment = def_setting('min_catchment', 'number'),
river_widening_power = def_setting('river_widening_power', 'number', 0.5), river_widening_power = def_setting('river_widening_power', 'number'),
riverbed_slope = def_setting('riverbed_slope', 'number', 0.4), riverbed_slope = def_setting('riverbed_slope', 'number'),
distort = def_setting('distort', 'bool', true), distort = def_setting('distort', 'bool'),
biomes = def_setting('biomes', 'bool', true), biomes = def_setting('biomes', 'bool'),
glaciers = def_setting('glaciers', 'bool', false), glaciers = def_setting('glaciers', 'bool'),
glacier_factor = def_setting('glacier_factor', 'number', 8), glacier_factor = def_setting('glacier_factor', 'number'),
elevation_chill = def_setting('elevation_chill', 'number', 0.25), elevation_chill = def_setting('elevation_chill', 'number'),
grid_x_size = def_setting('grid_x_size', 'number', 1000), map_x_size = def_setting('map_x_size', 'number'),
grid_z_size = def_setting('grid_z_size', 'number', 1000), map_z_size = def_setting('map_z_size', 'number'),
evol_params = { evol_params = {
K = def_setting('river_erosion_coef', 'number', 0.5), K = def_setting('river_erosion_coef', 'number'),
m = def_setting('river_erosion_power', 'number', 0.4), m = def_setting('river_erosion_power', 'number'),
d = def_setting('diffusive_erosion', 'number', 0.5), d = def_setting('diffusive_erosion', 'number'),
compensation_radius = def_setting('compensation_radius', 'number', 50), compensation_radius = def_setting('compensation_radius', 'number'),
}, },
tectonic_speed = def_setting('tectonic_speed', 'number', 70), tectonic_speed = def_setting('tectonic_speed', 'number'),
evol_time = def_setting('evol_time', 'number', 10), evol_time = def_setting('evol_time', 'number'),
evol_time_step = def_setting('evol_time_step', 'number', 1), evol_time_step = def_setting('evol_time_step', 'number'),
load_all = mtsettings:get_bool('mapgen_rivers_load_all') load_all = mtsettings:get_bool('mapgen_rivers_load_all')
} }
mapgen_rivers.noise_params = {
base = def_setting("np_base", "noise"),
distort_x = def_setting("np_distort_x", "noise"),
distort_z = def_setting("np_distort_z", "noise"),
distort_amplitude = def_setting("np_distort_amplitude", "noise"),
heat = minetest.get_mapgen_setting_noiseparams('mg_biome_np_heat'),
heat_blend = minetest.get_mapgen_setting_noiseparams('mg_biome_np_heat_blend'),
}
mapgen_rivers.noise_params.heat.offset = mapgen_rivers.noise_params.heat.offset +
mapgen_rivers.settings.sea_level * mapgen_rivers.settings.elevation_chill
local function write_settings() local function write_settings()
mgrsettings:write() mgrsettings:write()
end end

68
settings_default.json Normal file
View File

@ -0,0 +1,68 @@
{
"version": "1.0.2",
"center": true,
"water_level": 1,
"blocksize": 15,
"min_catchment": 3600,
"river_widening_power": 0.5,
"riverbed_slope": 0.4,
"distort": true,
"biomes": true,
"glaciers": false,
"glacier_factor": 8,
"elevation_chill": 0.25,
"map_x_size": 15000,
"map_z_size": 15000,
"river_erosion_coef": 0.5,
"river_erosion_power": 0.4,
"diffusive_erosion": 0.5,
"compensation_radius": 50,
"tectonic_speed": 70,
"evol_time": 10,
"evol_time_step": 1,
"load_all": false,
"np_base": {
"offset": 0,
"scale": 300,
"seed": 2469,
"octaves": 8,
"spread": {"x": 2048, "y": 2048, "z": 2048},
"persist": 0.6,
"lacunarity": 2.0,
"flags": "eased"
},
"np_distort_x": {
"offset": 0,
"scale": 1,
"seed": -4574,
"octaves": 3,
"spread": {"x": 64, "y": 32, "z": 64},
"persist": 0.75,
"lacunarity": 2.0
},
"np_distort_z": {
"offset": 0,
"scale": 1,
"seed": -7940,
"octaves": 3,
"spread": {"x": 64, "y": 32, "z": 64},
"persist": 0.75,
"lacunarity": 2.0
},
"np_distort_amplitude": {
"offset": 0,
"scale": 10,
"seed": 676,
"octaves": 5,
"spread": {"x": 1024, "y": 1024, "z": 1024},
"persist": 0.5,
"lacunarity": 2.0,
"flags": "absvalue"
}
}

View File

@ -3,19 +3,25 @@
# Whether the map should be centered at x=0, z=0. # Whether the map should be centered at x=0, z=0.
mapgen_rivers_center (Center map) bool true mapgen_rivers_center (Center map) bool true
# Represents horizontal map scale. Every cell of the grid will be upscaled to # Every cell of the river grid will represent a square of this size.
# a square of this size. # A lower value will result in more detailed terrain and finer computation
# For example if the grid size is 1000x1000 and block size is 12, # of rivers, but will be slower to generate and use more resources.
# the actual size of the map will be 12000. #
# WARNING: Excessively low values may cause crashes at pre-generation, due to
# memory issues
mapgen_rivers_blocksize (Block size) float 15.0 2.0 100.0 mapgen_rivers_blocksize (Block size) float 15.0 2.0 100.0
# X size of the grid being generated # X size of the map being generated
# Actual size of the map is grid_x_size * blocksize #
mapgen_rivers_grid_x_size (Grid X size) int 1000 50 5000 # X size of the river grid will be this/blocksize
# When increasing, it is recommended to increase blocksize too
mapgen_rivers_map_x_size (Map X size) int 15000 500 66000
# Z size of the grid being generated # Z size of the map being generated
# Actual size of the map is grid_z_size * blocksize #
mapgen_rivers_grid_z_size (Grid Z size) int 1000 50 5000 # Z size of the river grid will be this/blocksize
# When increasing, it is recommended to increase blocksize too
mapgen_rivers_map_z_size (Map Z size) int 15000 500 66000
# Minimal catchment area for a river to be drawn, in square nodes # Minimal catchment area for a river to be drawn, in square nodes
# Lower value means bigger river density # Lower value means bigger river density