mapgen_rivers = {} local modpath = minetest.get_modpath(minetest.get_current_modname()) .. '/' dofile(modpath .. 'settings.lua') local blocksize = mapgen_rivers.blocksize local sea_level = mapgen_rivers.sea_level local riverbed_slope = mapgen_rivers.riverbed_slope local elevation_chill = mapgen_rivers.elevation_chill dofile(modpath .. 'noises.lua') local make_polygons = dofile(modpath .. 'polygons.lua') local transform_quadri = dofile(modpath .. 'geometry.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) end 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 function generate(minp, maxp, seed) 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, } 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_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_distort_obj = minetest.get_perlin_map(mapgen_rivers.noise_params.distort_amplitude, chulens) init = true end local minp2d = {x=minp.x, y=minp.z} 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) noise_heat_obj:get_2d_map_flat(minp2d, noise_heat_map) noise_heat_blend_obj:get_2d_map_flat(minp2d, noise_heat_blend_map) 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=math.floor(xmin), z=math.floor(zmin)} local pmaxp = {x=math.floor(xmax)+1, z=math.floor(zmax)+1} local incr = pmaxp.z-pminp.z+1 local i_origin = 1 - pminp.x*incr - pminp.z local terrain_map, lake_map = heightmaps(pminp, pmaxp) 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 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, minp.y, z) local ground_above = false local temperature = noise_heat_map[i2d]+noise_heat_blend_map[i2d] for y = maxp.y+1, minp.y, -1 do 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 + x0*incr + z0 local i1 = i0+incr local i2 = i1+1 local i3 = i0+1 local terrain = interp(terrain_map[i0], terrain_map[i1], terrain_map[i2], terrain_map[i3], xn-x0, zn-z0) if y <= maxp.y then local lake = math.min(lake_map[i0], lake_map[i1], lake_map[i2], lake_map[i3]) local is_lake = lake > terrain local ivm = a:index(x, y, z) if y <= terrain then if 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 local temperature_y = temperature - y*elevation_chill if temperature_y >= 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 nid = nid + incrY end nid = nid + incrX i2d = i2d + 1 end nid = nid + incrZ end vm:set_data(data) minetest.generate_ores(vm, minp, maxp) vm:set_lighting({day = 0, night = 0}) vm:calc_lighting() vm:update_liquids() vm:write_to_map() end minetest.register_on_generated(generate)