Record heightmap when scanning

- Use heightmap value for more granular biome texture selection
This commit is contained in:
Hugues Ross 2020-02-16 20:18:47 -05:00
parent d0f7c58c47
commit e5371e19ed
5 changed files with 80 additions and 25 deletions

View File

@ -2,13 +2,12 @@ local mod_storage = minetest.get_mod_storage();
-- The API object -- The API object
cartographer = { cartographer = {
biome_lookup = {},
biome_heights = {},
scan_queue = {}, scan_queue = {},
}; };
_cartographer = { _cartographer = {
CHUNK_SIZE = 16, CHUNK_SIZE = 16,
biome_lookup = {},
maps = minetest.deserialize(mod_storage:get_string("maps")) or {}, maps = minetest.deserialize(mod_storage:get_string("maps")) or {},
next_map_id = mod_storage:get_int("next_map_id"), next_map_id = mod_storage:get_int("next_map_id"),
last_deaths = minetest.deserialize(mod_storage:get_string("deaths")) or {}, last_deaths = minetest.deserialize(mod_storage:get_string("deaths")) or {},

View File

@ -92,12 +92,20 @@ minetest.register_globalstep(function(dt)
end end
end) end)
function cartographer.register_biome(name, texture, height) -- Register a biome with textures to display
cartographer.biome_lookup[name] = texture; -- name: A string containing the biome name
-- textures: A table of texture names.
if height ~= nil and height ~= 0 then -- These should correspond with detail levels,
cartographer.biome_heights[name] = height; -- any detail level past the length of the table will return the last texture
end -- (Optional) min_height: The minimum Y position where this biome data should be used
-- (Optional) max_height: The maximum Y position where this biome data should be used
function cartographer.register_biome(name, textures, min_height, max_height)
_cartographer.biome_lookup[#_cartographer.biome_lookup + 1] = {
name = name,
textures = textures,
min_height = min_height,
max_height = max_height,
};
end end
function cartographer.is_filled(map, x, z) function cartographer.is_filled(map, x, z)
@ -108,3 +116,18 @@ function cartographer.is_filled(map, x, z)
minetest.chat_send_all(tostring(x).. ", " .. tostring(z) .. "(" .. tostring(x + (z * map.w)) .."): " .. tostring(map.fill[x + (z * map.w)])); minetest.chat_send_all(tostring(x).. ", " .. tostring(z) .. "(" .. tostring(x + (z * map.w)) .."): " .. tostring(map.fill[x + (z * map.w)]));
return map.fill[(x - map.x) + ((z - map.z) * map.w)] ~= nil; return map.fill[(x - map.x) + ((z - map.z) * map.w)] ~= nil;
end end
-- Get the texture name (minus index/extension) for the given biome, height, and detail level.
-- name: A string containing the biome name
-- height: A number representing the Y position of the biome
-- detail: The detail level
-- Returns a string with a texture name, or nil if no matching biome entry was found.
function cartographer.get_biome_texture(name, height, detail)
for _,biome in ipairs(_cartographer.biome_lookup) do
if biome.name == name and (biome.min_height == nil or height >= biome.min_height) and (biome.max_height == nil or height <= biome.max_height) then
return biome.textures[math.min(detail, #biome.textures)];
end
end
return nil;
end

View File

@ -26,23 +26,23 @@ local function generate_map(data, x, y, w, h, player_x, player_y, spawn_x, spawn
if column == nil or column[j] == nil or (is_visible and not is_visible(user, i, j)) then if column == nil or column[j] == nil or (is_visible and not is_visible(user, i, j)) then
str = str..tile:format(fx, fy, scale, scale, "cartographer_unknown_biome." .. tostring(get_variant(random)) .. ".png") str = str..tile:format(fx, fy, scale, scale, "cartographer_unknown_biome." .. tostring(get_variant(random)) .. ".png")
else else
local name = minetest.get_biome_name(column[j]); local name = minetest.get_biome_name(column[j].biome);
local biome = cartographer.biome_lookup[name]; local height = column[j].height;
local height = cartographer.biome_heights[name] or 0; local biome = cartographer.get_biome_texture(name, math.floor(height + 0.5), detail);
if biome == nil then if biome == nil then
minetest.chat_send_all(name); -- minetest.chat_send_all(name);
str = str..tile:format(fx, fy, scale, scale, "cartographer_unknown_biome." .. tostring(get_variant(random)) .. ".png") str = str..tile:format(fx, fy, scale, scale, "cartographer_unknown_biome." .. tostring(get_variant(random)) .. ".png")
else else
if height > 0 then if height > 0 then
str = str..tile:format(fx, fy, scale, scale, "cartographer_cliff.png") str = str..tile:format(fx, fy, scale, scale, "cartographer_cliff.png")
end end
str = str..tile:format(fx, fy - (height * 0.025), scale, scale, biome[math.min(detail, #biome)] .. "." .. tostring(get_variant(random)) .. ".png") str = str..tile:format(fx, fy, scale, scale, biome .. "." .. tostring(get_variant(random)) .. ".png")
end end
if i == player_x and j == player_y then if i == player_x and j == player_y then
str = str..marker:format(fx, fy - (height * 0.025), scale, scale, "cartographer_player_icon.png", 2, 500) str = str..marker:format(fx, fy, scale, scale, "cartographer_player_icon.png", 2, 500)
-- elseif i == death_x and j == death_y then -- elseif i == death_x and j == death_y then
-- str = str..marker:format(fx, fy - (height * 0.025), scale, scale, "dicon.png") -- str = str..marker:format(fx, fy - (height * 0.025), scale, scale, "dicon.png")
-- elseif i == spawn_x and j == spawn_y then -- elseif i == spawn_x and j == spawn_y then

View File

@ -62,16 +62,28 @@ cartographer.register_biome("Wasteland", {
cartographer.register_biome("Grassland Ocean", { cartographer.register_biome("Grassland Ocean", {
"cartographer_simple_water", "cartographer_simple_water",
"cartographer_colored_water", "cartographer_colored_water",
}); }, nil, 0);
cartographer.register_biome("Grassland Ocean", {
"cartographer_simple_land",
"cartographer_colored_sand",
}, 0);
cartographer.register_biome("Gravel Beach", { cartographer.register_biome("Gravel Beach", {
"cartographer_simple_land", "cartographer_simple_land",
"cartographer_colored_sand", "cartographer_colored_sand",
"cartographer_gravel", "cartographer_gravel",
}); }, 0);
cartographer.register_biome("Gravel Beach", {
"cartographer_simple_water",
"cartographer_colored_water",
}, nil, 0);
cartographer.register_biome("Savanna Ocean", { cartographer.register_biome("Savanna Ocean", {
"cartographer_simple_water", "cartographer_simple_water",
"cartographer_colored_water", "cartographer_colored_water",
}); }, nil, 0);
cartographer.register_biome("Savanna Ocean", {
"cartographer_simple_land",
"cartographer_colored_sand",
}, 0);
-- Materials -- Materials
cartographer.register_map_material_name("default:paper", "fiber", 5); cartographer.register_map_material_name("default:paper", "fiber", 5);

View File

@ -1,12 +1,18 @@
local CHUNK_SIZE = _cartographer.CHUNK_SIZE; local CHUNK_SIZE = _cartographer.CHUNK_SIZE;
local function register_mapchunk(x, y, biome) local function register_mapchunk(x, y, biome, height)
if not data.generated[x] then if not data.generated[x] then
data.generated[x] = { data.generated[x] = {
[y] = biome, [y] = {
biome = biome,
height = height,
}
}; };
elseif not data.generated[x][y] then elseif not data.generated[x][y] then
data.generated[x][y] = biome; data.generated[x][y] = {
biome = biome,
height = height,
};
end end
end end
@ -15,6 +21,7 @@ local function get_mapgen_biome(min, max, mmin, mmax)
local DEFAULT = minetest.get_biome_id("default"); local DEFAULT = minetest.get_biome_id("default");
local biomes = minetest.get_mapgen_object("biomemap"); local biomes = minetest.get_mapgen_object("biomemap");
local heights = minetest.get_mapgen_object("heightmap");
local xx = max.x - min.x; local xx = max.x - min.x;
local yy = max.y - min.y; local yy = max.y - min.y;
@ -29,12 +36,14 @@ local function get_mapgen_biome(min, max, mmin, mmax)
local startz = min.z - mmin.z; local startz = min.z - mmin.z;
local scan_biomes = {}; local scan_biomes = {};
local scan_heights = {};
for i = startx,startx + xx,1 do for i = startx,startx + xx,1 do
for k = startz,startz + zz,1 do for k = startz,startz + zz,1 do
local b = biomes[i + (k * (xxx + 1))] local b = biomes[i + (k * (xxx + 1))];
if b ~= nil and b ~= UNDERGROUND and b ~= DEFAULT then if b ~= nil and b ~= UNDERGROUND and b ~= DEFAULT then
scan_biomes[b] = (scan_biomes[b] or 0) + 1; 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 end
end end
@ -48,7 +57,12 @@ local function get_mapgen_biome(min, max, mmin, mmax)
end end
end end
return biome; local avg_height = 0;
if high > 0 then
avg_height = scan_heights[biome] / high;
end
return biome, avg_height;
end end
local function get_biome(min, max) local function get_biome(min, max)
@ -61,6 +75,7 @@ local function get_biome(min, max)
local zz = max.z - min.z; local zz = max.z - min.z;
local scan_biomes = {}; local scan_biomes = {};
local scan_heights = {};
for i = min.x,max.x,1 do for i = min.x,max.x,1 do
for j = min.y,max.y,1 do for j = min.y,max.y,1 do
@ -73,6 +88,7 @@ local function get_biome(min, max)
node = minetest.get_node(pos).name; node = minetest.get_node(pos).name;
if node == "air" or node == WATER_SOURCE then if node == "air" or node == WATER_SOURCE then
scan_biomes[b] = (scan_biomes[b] or 0) + 1; scan_biomes[b] = (scan_biomes[b] or 0) + 1;
scan_heights[b] = (scan_heights[b] or 0) + j;
end end
end end
end end
@ -88,7 +104,12 @@ local function get_biome(min, max)
end end
end end
return biome; local avg_height = 0;
if high > 0 then
avg_height = scan_heights[biome] / high;
end
return biome, avg_height;
end end
local function on_generated(min, max, blockseed) local function on_generated(min, max, blockseed)
@ -110,9 +131,9 @@ local function on_generated(min, max, blockseed)
y = max.y, y = max.y,
z = j * CHUNK_SIZE + CHUNK_SIZE, z = j * CHUNK_SIZE + CHUNK_SIZE,
}; };
local biome = get_mapgen_biome(sub_min, sub_max, min, max); local biome, height = get_mapgen_biome(sub_min, sub_max, min, max);
if biome ~= nil then if biome ~= nil then
register_mapchunk(i, j, biome) register_mapchunk(i, j, biome, height)
end end
end end