local modpath = minetest.get_modpath(minetest.get_current_modname()) local EvolutionModel = dofile(modpath .. '/terrainlib_lua/erosion.lua') local twist = dofile(modpath .. '/terrainlib_lua/twist.lua') local blocksize = tonumber(mapgen_rivers.settings:get("blocksize")) local tectonic_speed = tonumber(mapgen_rivers.settings:get("tectonic_speed")) 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 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 -- 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 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 model = EvolutionModel(evol_params) model.dem = dem local ref_dem = model:define_isostasy(dem) local tectonic_step = tectonic_speed * time_step collectgarbage() -- Run the model for i=1, niter do minetest.log("info", "[mapgen_rivers] Iteration " .. i .. " of " .. niter) 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 collectgarbage() end 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) 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