Add lua locals into mcl_dungeons for performance

This commit is contained in:
jordan4ibanez 2021-04-09 01:38:34 -04:00
parent bc16c33dde
commit e15fd2f4b6
1 changed files with 60 additions and 37 deletions

View File

@ -9,15 +9,38 @@ if mcl_vars.mg_dungeons == false or mg_name == "singlenode" then
return return
end end
local min_y = math.max(mcl_vars.mg_overworld_min, mcl_vars.mg_bedrock_overworld_max) + 1 --lua locals
local max_y = mcl_vars.mg_overworld_max - 1 --minetest
local registered_nodes = minetest.registered_nodes
local swap_node = minetest.swap_node
local set_node = minetest.set_node
local dir_to_facedir = minetest.dir_to_facedir
local get_meta = minetest.get_meta
local emerge_area = minetest.emerge_area
--vector
local vector_add = vector.add
local vector_subtract = vector.subtract
--table
local table_insert = table.insert
local table_sort = table.sort
--math
local math_min = math.min
local math_max = math.max
local math_ceil = math.ceil
--custom mcl_vars
local get_node = mcl_vars.get_node local get_node = mcl_vars.get_node
local min_y = math_max(mcl_vars.mg_overworld_min, mcl_vars.mg_bedrock_overworld_max) + 1
local max_y = mcl_vars.mg_overworld_max - 1
-- Calculate the number of dungeon spawn attempts -- Calculate the number of dungeon spawn attempts
-- In Minecraft, there 8 dungeon spawn attempts Minecraft chunk (16*256*16 = 65536 blocks). -- In Minecraft, there 8 dungeon spawn attempts Minecraft chunk (16*256*16 = 65536 blocks).
-- Minetest chunks don't have this size, so scale the number accordingly. -- Minetest chunks don't have this size, so scale the number accordingly.
local attempts = math.ceil(((mcl_vars.chunksize * mcl_vars.MAP_BLOCKSIZE) ^ 3) / 8192) -- 63 = 80*80*80/8192 local attempts = math_ceil(((mcl_vars.chunksize * mcl_vars.MAP_BLOCKSIZE) ^ 3) / 8192) -- 63 = 80*80*80/8192
local dungeonsizes = { local dungeonsizes = {
{ x=5, y=4, z=5}, { x=5, y=4, z=5},
@ -51,8 +74,8 @@ local function ecb_spawn_dungeon(blockpos, action, calls_remaining, param)
local y_floor = y local y_floor = y
local y_ceiling = y + dim.y + 1 local y_ceiling = y + dim.y + 1
if check then for tx = x+1, x+dim.x do for tz = z+1, z+dim.z do if check then for tx = x+1, x+dim.x do for tz = z+1, z+dim.z do
if not minetest.registered_nodes[get_node({x = tx, y = y_floor , z = tz}).name].walkable if not registered_nodes[get_node({x = tx, y = y_floor , z = tz}).name].walkable
or not minetest.registered_nodes[get_node({x = tx, y = y_ceiling, z = tz}).name].walkable then return false end or not registered_nodes[get_node({x = tx, y = y_ceiling, z = tz}).name].walkable then return false end
end end end end end end
-- Check for air openings (2 stacked air at ground level) in wall positions -- Check for air openings (2 stacked air at ground level) in wall positions
@ -69,25 +92,25 @@ local function ecb_spawn_dungeon(blockpos, action, calls_remaining, param)
openings_counter = openings_counter + 1 openings_counter = openings_counter + 1
if not openings[x] then openings[x]={} end if not openings[x] then openings[x]={} end
openings[x][z] = true openings[x][z] = true
table.insert(corners, {x=x, z=z}) table_insert(corners, {x=x, z=z})
end end
if get_node({x=x2, y=y+1, z=z}).name == "air" and get_node({x=x2, y=y+2, z=z}).name == "air" then if get_node({x=x2, y=y+1, z=z}).name == "air" and get_node({x=x2, y=y+2, z=z}).name == "air" then
openings_counter = openings_counter + 1 openings_counter = openings_counter + 1
if not openings[x2] then openings[x2]={} end if not openings[x2] then openings[x2]={} end
openings[x2][z] = true openings[x2][z] = true
table.insert(corners, {x=x2, z=z}) table_insert(corners, {x=x2, z=z})
end end
if get_node({x=x, y=y+1, z=z2}).name == "air" and get_node({x=x, y=y+2, z=z2}).name == "air" then if get_node({x=x, y=y+1, z=z2}).name == "air" and get_node({x=x, y=y+2, z=z2}).name == "air" then
openings_counter = openings_counter + 1 openings_counter = openings_counter + 1
if not openings[x] then openings[x]={} end if not openings[x] then openings[x]={} end
openings[x][z2] = true openings[x][z2] = true
table.insert(corners, {x=x, z=z2}) table_insert(corners, {x=x, z=z2})
end end
if get_node({x=x2, y=y+1, z=z2}).name == "air" and get_node({x=x2, y=y+2, z=z2}).name == "air" then if get_node({x=x2, y=y+1, z=z2}).name == "air" and get_node({x=x2, y=y+2, z=z2}).name == "air" then
openings_counter = openings_counter + 1 openings_counter = openings_counter + 1
if not openings[x2] then openings[x2]={} end if not openings[x2] then openings[x2]={} end
openings[x2][z2] = true openings[x2][z2] = true
table.insert(corners, {x=x2, z=z2}) table_insert(corners, {x=x2, z=z2})
end end
for wx = x+1, x+dim.x do for wx = x+1, x+dim.x do
@ -180,16 +203,16 @@ local function ecb_spawn_dungeon(blockpos, action, calls_remaining, param)
secondChance = false secondChance = false
end end
lastRandom = r lastRandom = r
table.insert(chestSlots, r) table_insert(chestSlots, r)
end end
table.sort(chestSlots) table_sort(chestSlots)
local currentChest = 1 local currentChest = 1
-- Calculate the mob spawner position, to be re-used for later -- Calculate the mob spawner position, to be re-used for later
local sp = {x = x + math.ceil(dim.x/2), y = y+1, z = z + math.ceil(dim.z/2)} local sp = {x = x + math_ceil(dim.x/2), y = y+1, z = z + math_ceil(dim.z/2)}
local rn = minetest.registered_nodes[get_node(sp).name] local rn = registered_nodes[get_node(sp).name]
if rn and rn.is_ground_content then if rn and rn.is_ground_content then
table.insert(spawner_posses, sp) table_insert(spawner_posses, sp)
end end
-- Generate walls and floor -- Generate walls and floor
@ -203,13 +226,13 @@ local function ecb_spawn_dungeon(blockpos, action, calls_remaining, param)
-- Do not overwrite nodes with is_ground_content == false (e.g. bedrock) -- Do not overwrite nodes with is_ground_content == false (e.g. bedrock)
-- Exceptions: cobblestone and mossy cobblestone so neighborings dungeons nicely connect to each other -- Exceptions: cobblestone and mossy cobblestone so neighborings dungeons nicely connect to each other
local name = get_node(p).name local name = get_node(p).name
if minetest.registered_nodes[name].is_ground_content or name == "mcl_core:cobble" or name == "mcl_core:mossycobble" then if registered_nodes[name].is_ground_content or name == "mcl_core:cobble" or name == "mcl_core:mossycobble" then
-- Floor -- Floor
if ty == y then if ty == y then
if pr:next(1,4) == 1 then if pr:next(1,4) == 1 then
minetest.swap_node(p, {name = "mcl_core:cobble"}) swap_node(p, {name = "mcl_core:cobble"})
else else
minetest.swap_node(p, {name = "mcl_core:mossycobble"}) swap_node(p, {name = "mcl_core:mossycobble"})
end end
-- Generate walls -- Generate walls
@ -221,14 +244,14 @@ local function ecb_spawn_dungeon(blockpos, action, calls_remaining, param)
-- Check if it's an opening first -- Check if it's an opening first
if (ty == maxy) or (not (openings[tx] and openings[tx][tz])) then if (ty == maxy) or (not (openings[tx] and openings[tx][tz])) then
-- Place wall or ceiling -- Place wall or ceiling
minetest.swap_node(p, {name = "mcl_core:cobble"}) swap_node(p, {name = "mcl_core:cobble"})
elseif ty < maxy - 1 then elseif ty < maxy - 1 then
-- Normally the openings are already clear, but not if it is a corner -- Normally the openings are already clear, but not if it is a corner
-- widening. Make sure to clear at least the bottom 2 nodes of an opening. -- widening. Make sure to clear at least the bottom 2 nodes of an opening.
if name ~= "air" then minetest.swap_node(p, {name = "air"}) end if name ~= "air" then swap_node(p, {name = "air"}) end
elseif name ~= "air" then elseif name ~= "air" then
-- This allows for variation between 2-node and 3-node high openings. -- This allows for variation between 2-node and 3-node high openings.
minetest.swap_node(p, {name = "mcl_core:cobble"}) swap_node(p, {name = "mcl_core:cobble"})
end end
-- If it was an opening, the lower 3 blocks are not touched at all -- If it was an opening, the lower 3 blocks are not touched at all
@ -236,9 +259,9 @@ local function ecb_spawn_dungeon(blockpos, action, calls_remaining, param)
else else
if (ty==y+1) and (tx==x+1 or tx==maxx-1 or tz==z+1 or tz==maxz-1) and (currentChest < totalChests + 1) and (chestSlots[currentChest] == chestSlotCounter) then if (ty==y+1) and (tx==x+1 or tx==maxx-1 or tz==z+1 or tz==maxz-1) and (currentChest < totalChests + 1) and (chestSlots[currentChest] == chestSlotCounter) then
currentChest = currentChest + 1 currentChest = currentChest + 1
table.insert(chests, {x=tx, y=ty, z=tz}) table_insert(chests, {x=tx, y=ty, z=tz})
else else
minetest.swap_node(p, {name = "air"}) swap_node(p, {name = "air"})
end end
local forChest = ty==y+1 and (tx==x+1 or tx==maxx-1 or tz==z+1 or tz==maxz-1) local forChest = ty==y+1 and (tx==x+1 or tx==maxx-1 or tz==z+1 or tz==maxz-1)
@ -246,9 +269,9 @@ local function ecb_spawn_dungeon(blockpos, action, calls_remaining, param)
-- Place next chest at the wall (if it was its chosen wall slot) -- Place next chest at the wall (if it was its chosen wall slot)
if forChest and (currentChest < totalChests + 1) and (chestSlots[currentChest] == chestSlotCounter) then if forChest and (currentChest < totalChests + 1) and (chestSlots[currentChest] == chestSlotCounter) then
currentChest = currentChest + 1 currentChest = currentChest + 1
table.insert(chests, {x=tx, y=ty, z=tz}) table_insert(chests, {x=tx, y=ty, z=tz})
-- else -- else
--minetest.swap_node(p, {name = "air"}) --swap_node(p, {name = "air"})
end end
if forChest then if forChest then
chestSlotCounter = chestSlotCounter + 1 chestSlotCounter = chestSlotCounter + 1
@ -263,15 +286,15 @@ local function ecb_spawn_dungeon(blockpos, action, calls_remaining, param)
local surroundings = {} local surroundings = {}
for s=1, #surround_vectors do for s=1, #surround_vectors do
-- Detect the 4 horizontal neighbors -- Detect the 4 horizontal neighbors
local spos = vector.add(pos, surround_vectors[s]) local spos = vector_add(pos, surround_vectors[s])
local wpos = vector.subtract(pos, surround_vectors[s]) local wpos = vector_subtract(pos, surround_vectors[s])
local nodename = get_node(spos).name local nodename = get_node(spos).name
local nodename2 = get_node(wpos).name local nodename2 = get_node(wpos).name
local nodedef = minetest.registered_nodes[nodename] local nodedef = registered_nodes[nodename]
local nodedef2 = minetest.registered_nodes[nodename2] local nodedef2 = registered_nodes[nodename2]
-- The chest needs an open space in front of it and a walkable node (except chest) behind it -- The chest needs an open space in front of it and a walkable node (except chest) behind it
if nodedef and nodedef.walkable == false and nodedef2 and nodedef2.walkable == true and nodename2 ~= "mcl_chests:chest" then if nodedef and nodedef.walkable == false and nodedef2 and nodedef2.walkable == true and nodename2 ~= "mcl_chests:chest" then
table.insert(surroundings, spos) table_insert(surroundings, spos)
end end
end end
-- Set param2 (=facedir) of this chest -- Set param2 (=facedir) of this chest
@ -282,11 +305,11 @@ local function ecb_spawn_dungeon(blockpos, action, calls_remaining, param)
else else
-- 1 or multiple possible open directions: Choose random facedir -- 1 or multiple possible open directions: Choose random facedir
local face_to = surroundings[pr:next(1, #surroundings)] local face_to = surroundings[pr:next(1, #surroundings)]
facedir = minetest.dir_to_facedir(vector.subtract(pos, face_to)) facedir = dir_to_facedir(vector_subtract(pos, face_to))
end end
minetest.set_node(pos, {name="mcl_chests:chest", param2=facedir}) set_node(pos, {name="mcl_chests:chest", param2=facedir})
local meta = minetest.get_meta(pos) local meta = get_meta(pos)
local loottable = local loottable =
{ {
@ -336,7 +359,7 @@ local function ecb_spawn_dungeon(blockpos, action, calls_remaining, param)
-- Bonus loot for v6 mapgen: Otherwise unobtainable saplings. -- Bonus loot for v6 mapgen: Otherwise unobtainable saplings.
if mg_name == "v6" then if mg_name == "v6" then
table.insert(loottable, { table_insert(loottable, {
stacks_min = 1, stacks_min = 1,
stacks_max = 3, stacks_max = 3,
items = { items = {
@ -356,7 +379,7 @@ local function ecb_spawn_dungeon(blockpos, action, calls_remaining, param)
for s=#spawner_posses, 1, -1 do for s=#spawner_posses, 1, -1 do
local sp = spawner_posses[s] local sp = spawner_posses[s]
-- ... and place it and select a random mob -- ... and place it and select a random mob
minetest.set_node(sp, {name = "mcl_mobspawners:spawner"}) set_node(sp, {name = "mcl_mobspawners:spawner"})
local mobs = { local mobs = {
"mobs_mc:zombie", "mobs_mc:zombie",
"mobs_mc:zombie", "mobs_mc:zombie",
@ -370,7 +393,7 @@ local function ecb_spawn_dungeon(blockpos, action, calls_remaining, param)
end end
local function dungeons_nodes(minp, maxp, blockseed) local function dungeons_nodes(minp, maxp, blockseed)
local ymin, ymax = math.max(min_y, minp.y), math.min(max_y, maxp.y) local ymin, ymax = math_max(min_y, minp.y), math_min(max_y, maxp.y)
if ymax < ymin then return false end if ymax < ymin then return false end
local pr = PseudoRandom(blockseed) local pr = PseudoRandom(blockseed)
for a=1, attempts do for a=1, attempts do
@ -382,7 +405,7 @@ local function dungeons_nodes(minp, maxp, blockseed)
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))
local param = {p1=p1, p2=p2, dim=dim, pr=pr} local param = {p1=p1, p2=p2, dim=dim, pr=pr}
minetest.emerge_area(p1, p2, ecb_spawn_dungeon, param) emerge_area(p1, p2, ecb_spawn_dungeon, param)
end end
end end
@ -392,7 +415,7 @@ function mcl_dungeons.spawn_dungeon(p1, _, pr)
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))
local param = {p1=p1, p2=p2, dim=dim, pr=pr, dontcheck=true} local param = {p1=p1, p2=p2, dim=dim, pr=pr, dontcheck=true}
minetest.emerge_area(p1, p2, ecb_spawn_dungeon, param) emerge_area(p1, p2, ecb_spawn_dungeon, param)
end end
mcl_mapgen_core.register_generator("dungeons", nil, dungeons_nodes, 999999) mcl_mapgen_core.register_generator("dungeons", nil, dungeons_nodes, 999999)