229 lines
6.5 KiB
Lua
229 lines
6.5 KiB
Lua
-- Arguments
|
|
-- map_data: The cartographer map data table
|
|
local map_data = ...;
|
|
|
|
-- Constants
|
|
local CHUNK_SIZE = _cartographer.CHUNK_SIZE;
|
|
|
|
-- Register a new tile in map data
|
|
-- x: The x position in map coordinates
|
|
-- y: The y position in map coordinates
|
|
-- biome: The tile's biome id
|
|
-- height: The tile's height
|
|
-- (Optional): manual_scan: Indicates if this was a 'manual' (non-generated)
|
|
-- scan. Manual scans are overridden by generated
|
|
-- scans under normal circumstances.
|
|
local function register_tile(x, y, biome, height, manual_scan)
|
|
if not map_data.generated[x] then
|
|
map_data.generated[x] = {
|
|
[y] = {
|
|
biome = biome,
|
|
height = height,
|
|
}
|
|
};
|
|
if manual_scan ~= nil then
|
|
map_data.generated[x][y].manual_scan = manual_scan;
|
|
end
|
|
elseif not map_data.generated[x][y] or map_data.generated[x][y].height < height then
|
|
map_data.generated[x][y] = {
|
|
biome = biome,
|
|
height = height,
|
|
};
|
|
if manual_scan ~= nil or map_data.generated[x][y].manual_scan then
|
|
map_data.generated[x][y].manual_scan = manual_scan;
|
|
end
|
|
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_tile(i, j, biome, height)
|
|
end
|
|
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Is the scan of this position already handled?
|
|
-- x: The x position, in map coordinates
|
|
-- y: The y position, in world coordinates
|
|
-- x: The z position, in map coordinates
|
|
--
|
|
-- Returns true if the position is handled by the current map data
|
|
local function is_scan_handled(x, y, z)
|
|
if not map_data.generated[x] then
|
|
return false;
|
|
end
|
|
|
|
local tile = map_data.generated[x][z];
|
|
|
|
return tile and ((not tile.manual_scan and tile.height > 0) or tile.height >= y);
|
|
end
|
|
|
|
-- Queue a tile for manual scanning
|
|
-- pos: The position as a table, in world coordinates
|
|
function cartographer.queue_region(pos)
|
|
local converted = {
|
|
x = fromchunk(tochunk(pos.x)),
|
|
y = fromchunk(tochunk(pos.y)),
|
|
z = fromchunk(tochunk(pos.z)),
|
|
};
|
|
|
|
if is_scan_handled(tochunk(pos.x), pos.y, tochunk(pos.z)) 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
|
|
|
|
-- Scan the next tile on the queue, and remove it
|
|
function cartographer.scan_regions()
|
|
local len = #cartographer.scan_queue;
|
|
|
|
if len == 0 then
|
|
return;
|
|
end
|
|
|
|
local startpos = cartographer.scan_queue[1];
|
|
local endpos = {
|
|
x = startpos.x + CHUNK_SIZE,
|
|
y = startpos.y + CHUNK_SIZE,
|
|
z = startpos.z + CHUNK_SIZE,
|
|
};
|
|
|
|
if is_scan_handled(tochunk(startpos.x), startpos.y, tochunk(startpos.z)) then
|
|
table.remove(cartographer.scan_queue, 1);
|
|
return;
|
|
end
|
|
|
|
local biome,height = get_biome(startpos, endpos);
|
|
if biome ~= nil then
|
|
register_tile(tochunk(startpos.x), tochunk(startpos.z), biome, height, true)
|
|
end
|
|
|
|
table.remove(cartographer.scan_queue, 1);
|
|
end
|
|
|
|
minetest.register_on_generated(on_generated);
|