local CHUNK_SIZE = _cartographer.CHUNK_SIZE; local function register_mapchunk(x, y, biome, height) if not data.generated[x] then data.generated[x] = { [y] = { biome = biome, height = height, } }; elseif not data.generated[x][y] or data.generated[x][y].height < height then data.generated[x][y] = { biome = biome, height = height, }; end end local function get_mapgen_biome(min, max, mmin, mmax) local UNDERGROUND = minetest.get_biome_id("underground"); local DEFAULT = minetest.get_biome_id("default"); local biomes = minetest.get_mapgen_object("biomemap"); local heights = minetest.get_mapgen_object("heightmap"); local xx = max.x - min.x; local yy = max.y - min.y; local zz = max.z - min.z; local xxx = mmax.x - mmin.x; local yyy = mmax.y - mmin.y; local zzz = mmax.z - mmin.z; local startx = min.x - mmin.x; local starty = min.y - mmin.y; local startz = min.z - mmin.z; local scan_biomes = {}; local scan_heights = {}; for i = startx,startx + xx,1 do for k = startz,startz + zz,1 do local b = biomes[i + (k * (xxx + 1))]; if b ~= nil and b ~= UNDERGROUND and b ~= DEFAULT then scan_biomes[b] = (scan_biomes[b] or 0) + 1; scan_heights[b] = (scan_heights[b] or 0) + heights[i + (k * (xxx + 1))]; end end end local biome = nil; local high = 0; for k,v in pairs(scan_biomes) do if v > high then biome = k; high = v; end end local avg_height = 0; if high > 0 then avg_height = scan_heights[biome] / high; end return biome, avg_height; end local function get_biome(min, max) local UNDERGROUND = minetest.get_biome_id("underground"); local DEFAULT = minetest.get_biome_id("default"); local WATER_SOURCE = minetest.registered_aliases["mapgen_water_source"]; local xx = max.x - min.x; local yy = max.y - min.y; local zz = max.z - min.z; local scan_biomes = {}; local scan_heights = {}; for i = min.x,max.x,1 do for j = min.y,max.y,1 do for k = min.z,max.z,1 do local pos = { x=i, y=j, z=k }; local b = minetest.get_biome_data(pos).biome; local node = minetest.get_node(pos).name; if b ~= nil and b ~= UNDERGROUND and b ~= DEFAULT and node ~= "air" and node ~= WATER_SOURCE then pos.y = pos.y + 1; node = minetest.get_node(pos).name; if node == "air" or node == WATER_SOURCE then scan_biomes[b] = (scan_biomes[b] or 0) + 1; scan_heights[b] = (scan_heights[b] or 0) + j; end end end end end local biome = nil; local high = 0; for k,v in pairs(scan_biomes) do if v > high then biome = k; high = v; end end local avg_height = 0; if high > 0 then avg_height = scan_heights[biome] / high; end return biome, avg_height; end local function on_generated(min, max, blockseed) local chunk = { x = tochunk(min.x), y = tochunk(min.z), }; for i = tochunk(min.x),tochunk(max.x),1 do for j = tochunk(min.z),tochunk(max.z),1 do local sub_min = { x = i * CHUNK_SIZE, y = min.y, z = j * CHUNK_SIZE, }; local sub_max = { x = i * CHUNK_SIZE + CHUNK_SIZE, y = max.y, z = j * CHUNK_SIZE + CHUNK_SIZE, }; local biome, height = get_mapgen_biome(sub_min, sub_max, min, max); if biome ~= nil then register_mapchunk(i, j, biome, height) end end end end function cartographer.queue_region(pos) local converted = { x = tochunk(pos.x) * CHUNK_SIZE, y = tochunk(pos.y) * CHUNK_SIZE, z = tochunk(pos.z) * CHUNK_SIZE, }; if data.generated[pos.x] ~= nil and data.generated[pos.x][pos.z] ~= nil then return; end for _,queued_pos in ipairs(cartographer.scan_queue) do if vector.equals(converted, queued_pos) then return; end end cartographer.scan_queue[#cartographer.scan_queue + 1] = converted; end function cartographer.scan_regions() local len = #cartographer.scan_queue; if len == 0 then return; end local startpos = cartographer.scan_queue[len]; local endpos = { x = startpos.x + CHUNK_SIZE, y = startpos.y + CHUNK_SIZE, z = startpos.z + CHUNK_SIZE, }; if data.generated[startpos.x] ~= nil and data.generated[startpos.x][startpos.z] ~= nil then return; end local biome,height = get_biome(startpos, endpos); if biome ~= nil then register_mapchunk(startpos.x / CHUNK_SIZE, startpos.z / CHUNK_SIZE, biome, height) end cartographer.scan_queue[len] = nil; end minetest.register_on_generated(on_generated);