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 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_params = { offset = 0, scale = 1, seed = -4574, spread = {x=64, y=32, z=64}, octaves = 3, persistence = 0.75, lacunarity = 2, } local noise_z_params = { offset = 0, scale = 1, seed = -7940, spread = {x=64, y=32, z=64}, octaves = 3, persistence = 0.75, lacunarity = 2, } local noise_distort_params = { offset = 0, scale = 10, seed = 676, spread = {x=1024, y=1024, z=1024}, octaves = 5, persistence = 0.5, lacunarity = 2, flags = "absvalue", } local noise_x_obj, noise_z_obj, noise_distort_obj local noise_x_map = {} local noise_z_map = {} local noise_distort_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(noise_x_params, mapsize) noise_z_obj = minetest.get_perlin_map(noise_z_params, mapsize) noise_distort_obj = minetest.get_perlin_map(noise_distort_params, chulens) init = true end 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(minp, noise_distort_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_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 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 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 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 then data[ivm] = c_sand else data[ivm] = c_lawn end elseif y <= lake and lake > sea_level then data[ivm] = c_rwater 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 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)