[mapgen] GETTING RID OF EMERGE AREAS! Currently for dungeons and villages, and it works

This commit is contained in:
kay27 2021-05-02 03:56:55 +04:00
parent f38c8daab7
commit f4a28cfab0
4 changed files with 54 additions and 68 deletions

View File

@ -37,11 +37,12 @@ minetest_log("action", "[mcl_mapgen] World edges are: mcl_mapgen.EDGE_MIN = " ..
local lvm_block_queue, lvm_chunk_queue, node_block_queue, node_chunk_queue = {}, {}, {}, {} -- Generators' queues local lvm_block_queue, lvm_chunk_queue, node_block_queue, node_chunk_queue = {}, {}, {}, {} -- Generators' queues
local lvm, block, lvm_block, lvm_chunk, param2, nodes_block, nodes_chunk = 0, 0, 0, 0, 0, 0, 0 -- Requirements: 0 means none; greater than 0 means 'required' local lvm, block, lvm_block, lvm_chunk, param2, nodes_block, nodes_chunk, safe_functions = 0, 0, 0, 0, 0, 0, 0, 0 -- Requirements: 0 means none; greater than 0 means 'required'
local lvm_buffer, lvm_param2_buffer = {}, {} -- Static buffer pointers local lvm_buffer, lvm_param2_buffer = {}, {} -- Static buffer pointers
local BS, CS = mcl_mapgen.BS, mcl_mapgen.CS -- Mapblock size (in nodes), Mapchunk size (in blocks) local BS, CS = mcl_mapgen.BS, mcl_mapgen.CS -- Mapblock size (in nodes), Mapchunk size (in blocks)
local LAST_BLOCK, LAST_NODE = CS - 1, BS - 1 -- First mapblock in chunk (node in mapblock) has number 0, last has THIS number. It's for runtime optimization local LAST_BLOCK, LAST_NODE = CS - 1, BS - 1 -- First mapblock in chunk (node in mapblock) has number 0, last has THIS number. It's for runtime optimization
local offset = mcl_mapgen.OFFSET -- Central mapchunk offset (in blocks) local offset = mcl_mapgen.OFFSET -- Central mapchunk offset (in blocks)
local CS_NODES = mcl_mapgen.CS_NODES -- 80
local CS_3D = CS * CS * CS local CS_3D = CS * CS * CS
@ -49,6 +50,7 @@ local DEFAULT_PRIORITY = 5000
function mcl_mapgen.register_chunk_generator(callback_function, priority) function mcl_mapgen.register_chunk_generator(callback_function, priority)
nodes_chunk = nodes_chunk + 1 nodes_chunk = nodes_chunk + 1
safe_functions = safe_functions + 1
node_chunk_queue[nodes_chunk] = {i = priority or DEFAULT_PRIORITY, f = callback_function} node_chunk_queue[nodes_chunk] = {i = priority or DEFAULT_PRIORITY, f = callback_function}
table.sort(node_chunk_queue, function(a, b) return (a.i <= b.i) end) table.sort(node_chunk_queue, function(a, b) return (a.i <= b.i) end)
end end
@ -60,6 +62,7 @@ end
function mcl_mapgen.register_block_generator(callback_function, priority) function mcl_mapgen.register_block_generator(callback_function, priority)
block = block + 1 block = block + 1
nodes_block = nodes_block + 1 nodes_block = nodes_block + 1
safe_functions = safe_functions + 1
node_block_queue[nodes_block] = {i = priority or DEFAULT_PRIORITY, f = callback_function} node_block_queue[nodes_block] = {i = priority or DEFAULT_PRIORITY, f = callback_function}
table.sort(node_block_queue, function(a, b) return (a.i <= b.i) end) table.sort(node_block_queue, function(a, b) return (a.i <= b.i) end)
end end
@ -87,7 +90,7 @@ local current_chunks = {}
minetest.register_on_generated(function(minp, maxp, blockseed) minetest.register_on_generated(function(minp, maxp, blockseed)
local minp, maxp, blockseed = minp, maxp, blockseed local minp, maxp, blockseed = minp, maxp, blockseed
local vm, emin, emax = minetest.get_mapgen_object("voxelmanip") local vm, emin, emax = minetest.get_mapgen_object("voxelmanip")
minetest_log("warning", "[mcl_mapgen] New_chunk=" .. minetest_pos_to_string(minp) .. "..." .. minetest_pos_to_string(maxp) .. ", shall=" .. minetest_pos_to_string(emin) .. "..." .. minetest_pos_to_string(emax) .. ", blockseed=" .. tostring(blockseed)) minetest_log("warning", "[mcl_mapgen] New_chunk=" .. minetest_pos_to_string(minp) .. "..." .. minetest_pos_to_string(maxp) .. ", shell=" .. minetest_pos_to_string(emin) .. "..." .. minetest_pos_to_string(emax) .. ", blockseed=" .. tostring(blockseed))
if lvm > 0 then if lvm > 0 then
vm_context = {lvm_param2_buffer = lvm_param2_buffer, vm = vm, emin = emin, emax = emax, minp = minp, maxp = maxp, blockseed = blockseed} vm_context = {lvm_param2_buffer = lvm_param2_buffer, vm = vm, emin = emin, emax = emax, minp = minp, maxp = maxp, blockseed = blockseed}
@ -140,17 +143,15 @@ minetest.register_on_generated(function(minp, maxp, blockseed)
if current_mapgen_block_writes == total_mapgen_block_writes then if current_mapgen_block_writes == total_mapgen_block_writes then
-- this block shouldn't be overwritten anymore, no need to keep it in memory -- this block shouldn't be overwritten anymore, no need to keep it in memory
blocks[bx][by][bz] = nil blocks[bx][by][bz] = nil
if not chunks[cx] then chunks[cx] = {} end
if not chunks[cx][cy] then chunks[cx][cy] = {} end
if not chunks[cx][cy][cz] then if not chunks[cx][cy][cz] then
if not chunks[cx] then chunks[cx] = {} end
if not chunks[cx][cy] then chunks[cx][cy] = {} end
if not chunks[cx][cy][cz] then chunks[cx][cy][cz] = {counter = 1} end if not chunks[cx][cy][cz] then chunks[cx][cy][cz] = {counter = 1} end
else else
chunks[cx][cy][cz].counter = chunks[cx][cy][cz].counter + 1 chunks[cx][cy][cz].counter = chunks[cx][cy][cz].counter + 1
if chunks[cx][cy][cz].counter >= CS_3D then if chunks[cx][cy][cz].counter >= CS_3D then
current_chunks[#current_chunks+1] = { x = cx, y = cy, z = cz, s = chunks[cx][cy][cz].seed }
-- this chunk shouldn't be overwritten anymore, no need to keep it in memory -- this chunk shouldn't be overwritten anymore, no need to keep it in memory
local chunkseed = chunks[cx][cy][cz].seed
process_generated_chunk(cx, cy, cz, chunkseed)
chunks[cx][cy][cz] = nil chunks[cx][cy][cz] = nil
if next(chunks[cx][cy]) == nil then chunks[cx][cy] = nil end if next(chunks[cx][cy]) == nil then chunks[cx][cy] = nil end
if next(chunks[cx]) == nil then chunks[cx] = nil end if next(chunks[cx]) == nil then chunks[cx] = nil end
@ -196,15 +197,23 @@ minetest.register_on_generated(function(minp, maxp, blockseed)
vm:update_liquids() vm:update_liquids()
end end
for _, v in pairs(node_chunk_queue) do for i, b in pairs(current_chunks) do
v.f(minp, maxp, blockseed) local cx, cy, cz, seed = b.x, b.y, b.z, b.s
local bx, by, bz = cx * CS + offset, cy * CS + offset, cz * CS + offset
local x, y, z = bx * BS, by * BS, bz * BS
local minp = {x = x, y = y, z = z}
local maxp = {x = x + CS_NODES - 1, y = y + CS_NODES - 1, z = z + CS_NODES - 1}
for _, v in pairs(node_chunk_queue) do
v.f(minp, maxp, seed)
end
current_chunks[i] = nil
end end
for i, b in pairs(current_blocks) do for i, b in pairs(current_blocks) do
for _, v in pairs(node_block_queue) do for _, v in pairs(node_block_queue) do
v.f(b.minp, b.maxp, b.seed) v.f(b.minp, b.maxp, b.seed)
end end
current_blocks[id] = nil current_blocks[i] = nil
end end
end) end)

View File

@ -14,7 +14,7 @@ local swap_node = minetest.swap_node
local set_node = minetest.set_node local set_node = minetest.set_node
local dir_to_facedir = minetest.dir_to_facedir local dir_to_facedir = minetest.dir_to_facedir
local get_meta = minetest.get_meta local get_meta = minetest.get_meta
local emerge_area = minetest.emerge_area -- local emerge_area = minetest.emerge_area
--vector --vector
local vector_add = vector.add local vector_add = vector.add
@ -61,12 +61,14 @@ local surround_vectors = {
{ x=0, y=0, z=1 }, { x=0, y=0, z=1 },
} }
local function ecb_spawn_dungeon(blockpos, action, calls_remaining, param) --local function ecb_spawn_dungeon(blockpos, action, calls_remaining, param)
if calls_remaining >= 1 then return end -- if calls_remaining >= 1 then return end
-- local p1, _, dim, pr = param.p1, param.p2, param.dim, param.pr
-- local check = not (param.dontcheck or false)
local function spawn_dungeon(p1, p2, dim, pr, dontcheck)
local p1, _, dim, pr = param.p1, param.p2, param.dim, param.pr
local x, y, z = p1.x, p1.y, p1.z local x, y, z = p1.x, p1.y, p1.z
local check = not (param.dontcheck or false) local check = not (dontcheck or false)
-- Check floor and ceiling: Must be *completely* solid -- Check floor and ceiling: Must be *completely* solid
local y_floor = y local y_floor = y
@ -401,8 +403,9 @@ local function dungeons_nodes(minp, maxp, blockseed)
local z = pr:next(minp.z, maxp.z-dim.z-1) local z = pr:next(minp.z, maxp.z-dim.z-1)
local p1 = {x=x,y=y,z=z} local p1 = {x=x,y=y,z=z}
local p2 = {x = x+dim.x+1, y = y+dim.y+1, z = z+dim.z+1} local p2 = {x = x+dim.x+1, y = y+dim.y+1, z = z+dim.z+1}
minetest.log("verbose","[mcl_dungeons] size=" ..minetest.pos_to_string(dim) .. ", emerge from "..minetest.pos_to_string(p1) .. " to " .. minetest.pos_to_string(p2)) -- minetest.log("verbose","[mcl_dungeons] size=" ..minetest.pos_to_string(dim) .. ", emerge from "..minetest.pos_to_string(p1) .. " to " .. minetest.pos_to_string(p2))
emerge_area(p1, p2, ecb_spawn_dungeon, {p1=p1, p2=p2, dim=dim, pr=pr}) -- emerge_area(p1, p2, ecb_spawn_dungeon, {p1=p1, p2=p2, dim=dim, pr=pr})
spawn_dungeon(p1, p2, dim, pr)
end end
end end
@ -410,8 +413,9 @@ function mcl_dungeons.spawn_dungeon(p1, _, pr)
if not p1 or not pr or not p1.x or not p1.y or not p1.z then return end if not p1 or not pr or not p1.x or not p1.y or not p1.z then return end
local dim = dungeonsizes[pr:next(1, #dungeonsizes)] local dim = dungeonsizes[pr:next(1, #dungeonsizes)]
local p2 = {x = p1.x+dim.x+1, y = p1.y+dim.y+1, z = p1.z+dim.z+1} local p2 = {x = p1.x+dim.x+1, y = p1.y+dim.y+1, z = p1.z+dim.z+1}
minetest.log("verbose","[mcl_dungeons] size=" ..minetest.pos_to_string(dim) .. ", emerge from "..minetest.pos_to_string(p1) .. " to " .. minetest.pos_to_string(p2)) -- minetest.log("verbose","[mcl_dungeons] size=" ..minetest.pos_to_string(dim) .. ", emerge from "..minetest.pos_to_string(p1) .. " to " .. minetest.pos_to_string(p2))
emerge_area(p1, p2, ecb_spawn_dungeon, {p1=p1, p2=p2, dim=dim, pr=pr, dontcheck=true}) -- emerge_area(p1, p2, ecb_spawn_dungeon, {p1=p1, p2=p2, dim=dim, pr=pr, dontcheck=true})
spawn_dungeon(p1, p2, dim, pr, true)
end end
mcl_mapgen.register_chunk_generator(dungeons_nodes, 999999) mcl_mapgen.register_chunk_generator(dungeons_nodes, 999999)

View File

@ -1,6 +1,8 @@
settlements = {} settlements = {}
settlements.modpath = minetest.get_modpath("mcl_villages") settlements.modpath = minetest.get_modpath("mcl_villages")
local minetest_get_spawn_level = minetest.get_spawn_level
dofile(settlements.modpath.."/const.lua") dofile(settlements.modpath.."/const.lua")
dofile(settlements.modpath.."/utils.lua") dofile(settlements.modpath.."/utils.lua")
dofile(settlements.modpath.."/foundation.lua") dofile(settlements.modpath.."/foundation.lua")
@ -53,6 +55,7 @@ end
-- on map generation, try to build a settlement -- on map generation, try to build a settlement
-- --
local function build_a_settlement(minp, maxp, blockseed) local function build_a_settlement(minp, maxp, blockseed)
minetest.log("action","[mcl_villages] Building village at mapchunk " .. minetest.pos_to_string(minp) .. "..." .. minetest.pos_to_string(maxp) .. ", blockseed = " .. tostring(blockseed))
local pr = PseudoRandom(blockseed) local pr = PseudoRandom(blockseed)
-- fill settlement_info with buildings and their data -- fill settlement_info with buildings and their data
@ -69,28 +72,36 @@ local function build_a_settlement(minp, maxp, blockseed)
settlements.place_schematics(settlement_info, pr) settlements.place_schematics(settlement_info, pr)
end end
local function ecb_village(blockpos, action, calls_remaining, param)
if calls_remaining >= 1 then return end
local minp, maxp, blockseed = param.minp, param.maxp, param.blockseed
build_a_settlement(minp, maxp, blockseed)
end
-- Disable natural generation in singlenode. -- Disable natural generation in singlenode.
local mg_name = minetest.get_mapgen_setting("mg_name") local mg_name = minetest.get_mapgen_setting("mg_name")
if mg_name ~= "singlenode" then if mg_name ~= "singlenode" then
mcl_mapgen.register_chunk_generator(function(minp, maxp, blockseed) mcl_mapgen.register_chunk_generator(function(minp, maxp, blockseed)
-- local str1 = (maxp.y >= 0 and blockseed % 77 == 17) and "YES" or "no"
-- minetest.log("action","[mcl_villages] " .. str1 .. ": minp=" .. minetest.pos_to_string(minp) .. ", maxp=" .. minetest.pos_to_string(maxp) .. ", blockseed=" .. tostring(blockseed))
-- don't build settlement underground -- don't build settlement underground
if maxp.y < 0 then return end if maxp.y < 0 then return end
-- randomly try to build settlements -- randomly try to build settlements
if blockseed % 77 ~= 17 then return end if blockseed % 77 ~= 17 then return end
-- needed for manual and automated settlement building
-- don't build settlements on (too) uneven terrain -- don't build settlements on (too) uneven terrain
--local heightmap = minetest.get_mapgen_object("heightmap")
local height_difference = settlements.evaluate_heightmap() -- lame and quick replacement of `heightmap` by kay27 - we maybe need to restore `heightmap` analysis if there will be a way for the engine to avoid cavegen conflicts:
--------------------------------------------------------------------------
local height_difference, min, max
local pr1=PseudoRandom(blockseed)
for i=1,pr1:next(5,10) do
local x = pr1:next(0, 40) + minp.x + 19
local z = pr1:next(0, 40) + minp.z + 19
local y = minetest_get_spawn_level(x, z)
if y < (min or y+1) then min = y end
if y > (max or y-1) then max = y end
end
height_difference = max - min + 1
--------------------------------------------------------------------------
if height_difference > max_height_difference then return end if height_difference > max_height_difference then return end
local param={minp=vector.new(minp), maxp=vector.new(maxp), blockseed=blockseed} build_a_settlement(minp, maxp, blockseed)
minetest.emerge_area(minp, maxp, ecb_village, param)
end) end)
end end
-- manually place villages -- manually place villages

View File

@ -207,44 +207,6 @@ function shuffle(tbl, pr)
return table return table
end end
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
-- evaluate heightmap
-------------------------------------------------------------------------------
function settlements.evaluate_heightmap()
local heightmap = minetest.get_mapgen_object("heightmap")
-- max height and min height, initialize with impossible values for easier first time setting
local max_y = -50000
local min_y = 50000
-- only evaluate the center square of heightmap 40 x 40
local square_start = 1621
local square_end = 1661
for j = 1 , 40, 1 do
for i = square_start, square_end, 1 do
-- skip buggy heightmaps, return high value
if heightmap[i] == -31000 or heightmap[i] == 31000 then
return max_height_difference + 1
end
if heightmap[i] < min_y then
min_y = heightmap[i]
end
if heightmap[i] > max_y then
max_y = heightmap[i]
end
end
-- set next line
square_start = square_start + 80
square_end = square_end + 80
end
-- return the difference between highest and lowest pos in chunk
local height_diff = max_y - min_y
-- filter buggy heightmaps
if height_diff <= 1 then
return max_height_difference + 1
end
-- debug info
settlements.debug("heightdiff ".. height_diff)
return height_diff
end
-------------------------------------------------------------------------------
-- Set array to list -- Set array to list
-- https://stackoverflow.com/questions/656199/search-for-an-item-in-a-lua-list -- https://stackoverflow.com/questions/656199/search-for-an-item-in-a-lua-list
------------------------------------------------------------------------------- -------------------------------------------------------------------------------