cartographer/scanner.lua

190 lines
5.1 KiB
Lua

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);