--------------------------------------------------------------------------- -- Voxelis - Voxel survival sandbox for Luanti -- Copyright (C) 2024 Mad Star Studio LLC -- -- This program is free software; you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation; either version 3 of the License, or -- (at your option) any later version. -- -- You should have received a copy of the GNU General Public License along -- with this program; if not, see . --------------------------------------------------------------------------- vox_mapgen_core = {} -- -------------------------------------------------------------- -- -- Configuration: Noise Parameters -- -------------------------------------------------------------- -- local noise_heat = { offset = 50, scale = 50, spread = {x = 1000, y = 1000, z = 1000}, seed = 1234, octaves = 3, persistence = 0.5, lacunarity = 2.0, } local noise_humidity = { offset = 50, scale = 50, spread = {x = 1000, y = 1000, z = 1000}, seed = 5678, octaves = 3, persistence = 0.5, lacunarity = 2.0, } local noise_altitude = { offset = 50, scale = 50, spread = {x = 1000, y = 1000, z = 1000}, seed = 91011, octaves = 3, persistence = 0.5, lacunarity = 2.0, } local biome_size_noise = { offset = 0, scale = 10, spread = {x = 2000, y = 2000, z = 2000}, seed = 78910, octaves = 2, persistence = 0.4, lacunarity = 2.0, } -- Apply noise parameters to the map generator minetest.register_on_mapgen_init(function(mapgen_params) minetest.set_mapgen_setting_noiseparams("heat", noise_heat, true) minetest.set_mapgen_setting_noiseparams("humidity", noise_humidity, true) minetest.set_mapgen_setting_noiseparams("altitude", noise_altitude, true) end) -- -------------------------------------------------------------- -- -- Biome Assignment Logic -- -------------------------------------------------------------- -- local function get_biome(heat, humidity, altitude) if heat > 70 and humidity < 30 then return "desert" elseif heat > 70 and humidity > 50 then if altitude > 100 then return "volcanic_fields" end return "savannah" elseif heat > 50 and humidity > 70 then return "tropical_rainforest" elseif heat < 30 and humidity > 60 then return "boreal_forest" elseif heat < 10 and humidity > 40 then return "frozen_tundra" elseif altitude > 256 then return "jade_cliffs" else return "grassland" -- Default biome end end local function blend_biomes(current_biome, neighbor_biome, distance) if distance < 10 and math.random() < 0.5 then return neighbor_biome end return current_biome end -- -------------------------------------------------------------- -- -- Map Generation Logic -- -------------------------------------------------------------- -- minetest.register_on_generated(function(minp, maxp, seed) local vm, emin, emax = minetest.get_mapgen_object("voxelmanip") local area = VoxelArea:new{MinEdge = emin, MaxEdge = emax} local data = vm:get_data() -- Generate noise maps local heat_map = minetest.get_perlin_map(noise_heat, {x = maxp.x - minp.x + 1, y = maxp.z - minp.z + 1}) local humidity_map = minetest.get_perlin_map(noise_humidity, {x = maxp.x - minp.x + 1, y = maxp.z - minp.z + 1}) local altitude_map = minetest.get_perlin_map(noise_altitude, {x = maxp.x - minp.x + 1, y = maxp.z - minp.z + 1}) local biome_size_map = minetest.get_perlin_map(biome_size_noise, {x = maxp.x - minp.x + 1, y = maxp.z - minp.z + 1}) local heat = heat_map:get_2d_map_flat({x = minp.x, y = minp.z}) local humidity = humidity_map:get_2d_map_flat({x = minp.x, y = minp.z}) local altitude = altitude_map:get_2d_map_flat({x = minp.x, y = minp.z}) local biome_sizes = biome_size_map:get_2d_map_flat({x = minp.x, y = minp.z}) for z = minp.z, maxp.z do for x = minp.x, maxp.x do local index2d = (z - minp.z) * (maxp.x - minp.x + 1) + (x - minp.x + 1) local h = heat[index2d] local hum = humidity[index2d] local alt = altitude[index2d] local biome_size = biome_sizes[index2d] local current_biome = get_biome(h, hum, alt) local neighbor_biome = get_biome(h + 5, hum + 5, alt) current_biome = blend_biomes(current_biome, neighbor_biome, biome_size) -- Fetch biome properties local node_top = core.get_biome_top_node(current_biome) or "vox_worldblocks:grass" local node_filler = core.get_biome_filler_node(current_biome) or "vox_worldblocks:dirt" local depth_top = core.get_biome_depth_top(current_biome) or 1 local depth_filler = core.get_biome_depth_filler(current_biome) or 3 for y = minp.y, maxp.y do local vi = area:index(x, y, z) if y == minp.y then data[vi] = minetest.get_content_id("vox_worldblocks:bedrock") elseif y < -10001 then data[vi] = minetest.get_content_id("air") elseif y <= minp.y + depth_top then data[vi] = minetest.get_content_id(node_top) elseif y <= minp.y + depth_top + depth_filler then data[vi] = minetest.get_content_id(node_filler) else data[vi] = minetest.get_content_id("air") end end end end vm:set_data(data) vm:write_to_map() end)