From 29727136ac1975751c8a395e51d0653589de3f1b Mon Sep 17 00:00:00 2001 From: kay27 Date: Tue, 27 Apr 2021 01:30:07 +0400 Subject: [PATCH] [mapgen] redesign the code --- mods/CORE/mcl_init/init.lua | 174 -------- mods/CORE/mcl_mapgen/init.lua | 517 +++++++++++++---------- mods/ENTITIES/mcl_mobs/api.lua | 15 +- mods/ENTITIES/mcl_mobs/mod.conf | 2 +- mods/ITEMS/mcl_portals/mod.conf | 2 +- mods/ITEMS/mcl_portals/portal_nether.lua | 6 +- mods/MAPGEN/mcl_dungeons/init.lua | 2 +- mods/MAPGEN/mcl_dungeons/mod.conf | 2 +- mods/MAPGEN/mcl_mapgen_core/init.lua | 2 +- mods/PLAYER/mcl_spawn/init.lua | 2 +- mods/PLAYER/mcl_spawn/mod.conf | 2 +- 11 files changed, 317 insertions(+), 409 deletions(-) diff --git a/mods/CORE/mcl_init/init.lua b/mods/CORE/mcl_init/init.lua index 7441267d9..cd88b8dfc 100644 --- a/mods/CORE/mcl_init/init.lua +++ b/mods/CORE/mcl_init/init.lua @@ -24,97 +24,6 @@ mcl_vars.inventory_header = "" -- Tool wield size mcl_vars.tool_wield_scale = { x = 1.8, y = 1.8, z = 1 } --- Mapgen variables -local mg_name = minetest.get_mapgen_setting("mg_name") -local minecraft_height_limit = 256 -local superflat = mg_name == "flat" and minetest.get_mapgen_setting("mcl_superflat_classic") == "true" -local singlenode = mg_name == "singlenode" - -if not superflat and not singlenode then - -- Normal mode - --[[ Realm stacking (h is for height) - - Overworld (h>=256) - - Void (h>=1000) - - Realm Barrier (h=11), to allow escaping the End - - End (h>=256) - - Void (h>=1000) - - Nether (h=128) - - Void (h>=1000) - ]] - - -- Overworld - mcl_vars.mg_overworld_min = -62 - mcl_vars.mg_overworld_max_official = mcl_vars.mg_overworld_min + minecraft_height_limit - mcl_vars.mg_bedrock_overworld_min = mcl_vars.mg_overworld_min - mcl_vars.mg_bedrock_overworld_max = mcl_vars.mg_bedrock_overworld_min + 4 - mcl_vars.mg_lava_overworld_max = mcl_vars.mg_overworld_min + 10 - mcl_vars.mg_lava = true - mcl_vars.mg_bedrock_is_rough = true - -elseif singlenode then - mcl_vars.mg_overworld_min = -66 - mcl_vars.mg_overworld_max_official = mcl_vars.mg_overworld_min + minecraft_height_limit - mcl_vars.mg_bedrock_overworld_min = mcl_vars.mg_overworld_min - mcl_vars.mg_bedrock_overworld_max = mcl_vars.mg_bedrock_overworld_min - mcl_vars.mg_lava = false - mcl_vars.mg_lava_overworld_max = mcl_vars.mg_overworld_min - mcl_vars.mg_bedrock_is_rough = false -else - -- Classic superflat - local ground = minetest.get_mapgen_setting("mgflat_ground_level") - ground = tonumber(ground) - if not ground then - ground = 8 - end - mcl_vars.mg_overworld_min = ground - 3 - mcl_vars.mg_overworld_max_official = mcl_vars.mg_overworld_min + minecraft_height_limit - mcl_vars.mg_bedrock_overworld_min = mcl_vars.mg_overworld_min - mcl_vars.mg_bedrock_overworld_max = mcl_vars.mg_bedrock_overworld_min - mcl_vars.mg_lava = false - mcl_vars.mg_lava_overworld_max = mcl_vars.mg_overworld_min - mcl_vars.mg_bedrock_is_rough = false -end - -mcl_vars.mg_overworld_max = mcl_vars.mapgen_edge_max - --- The Nether (around Y = -29000) -mcl_vars.mg_nether_min = -29067 -- Carefully chosen to be at a mapchunk border -mcl_vars.mg_nether_max = mcl_vars.mg_nether_min + 128 -mcl_vars.mg_bedrock_nether_bottom_min = mcl_vars.mg_nether_min -mcl_vars.mg_bedrock_nether_top_max = mcl_vars.mg_nether_max -if not superflat then - mcl_vars.mg_bedrock_nether_bottom_max = mcl_vars.mg_bedrock_nether_bottom_min + 4 - mcl_vars.mg_bedrock_nether_top_min = mcl_vars.mg_bedrock_nether_top_max - 4 - mcl_vars.mg_lava_nether_max = mcl_vars.mg_nether_min + 31 -else - -- Thin bedrock in classic superflat mapgen - mcl_vars.mg_bedrock_nether_bottom_max = mcl_vars.mg_bedrock_nether_bottom_min - mcl_vars.mg_bedrock_nether_top_min = mcl_vars.mg_bedrock_nether_top_max - mcl_vars.mg_lava_nether_max = mcl_vars.mg_nether_min + 2 -end -if mg_name == "flat" then - if superflat then - mcl_vars.mg_flat_nether_floor = mcl_vars.mg_bedrock_nether_bottom_max + 4 - mcl_vars.mg_flat_nether_ceiling = mcl_vars.mg_bedrock_nether_bottom_max + 52 - else - mcl_vars.mg_flat_nether_floor = mcl_vars.mg_lava_nether_max + 4 - mcl_vars.mg_flat_nether_ceiling = mcl_vars.mg_lava_nether_max + 52 - end -end - --- The End (surface at ca. Y = -27000) -mcl_vars.mg_end_min = -27073 -- Carefully chosen to be at a mapchunk border -mcl_vars.mg_end_max_official = mcl_vars.mg_end_min + minecraft_height_limit -mcl_vars.mg_end_max = mcl_vars.mg_overworld_min - 2000 -mcl_vars.mg_end_platform_pos = { x = 100, y = mcl_vars.mg_end_min + 74, z = 0 } - --- Realm barrier used to safely separate the End from the void below the Overworld -mcl_vars.mg_realm_barrier_overworld_end_max = mcl_vars.mg_end_max -mcl_vars.mg_realm_barrier_overworld_end_min = mcl_vars.mg_end_max - 11 - --- Use MineClone 2-style dungeons -mcl_vars.mg_dungeons = true - -- Set default stack sizes minetest.nodedef_default.stack_max = 64 minetest.craftitemdef_default.stack_max = 64 @@ -122,86 +31,3 @@ minetest.craftitemdef_default.stack_max = 64 -- Set random seed for all other mods (Remember to make sure no other mod calls this function) math.randomseed(os.time()) -local chunks = {} -- intervals of chunks generated -function mcl_vars.add_chunk(pos) - local n = mcl_vars.get_chunk_number(pos) -- unsigned int - local prev - for i, d in pairs(chunks) do - if n <= d[2] then -- we've found it - if (n == d[2]) or (n >= d[1]) then return end -- already here - if n == d[1]-1 then -- right before: - if prev and (prev[2] == n-1) then - prev[2] = d[2] - table.remove(chunks, i) - return - end - d[1] = n - return - end - if prev and (prev[2] == n-1) then --join to previous - prev[2] = n - return - end - table.insert(chunks, i, {n, n}) -- insert new interval before i - return - end - prev = d - end - chunks[#chunks+1] = {n, n} -end -function mcl_vars.is_generated(pos) - local n = mcl_vars.get_chunk_number(pos) -- unsigned int - for i, d in pairs(chunks) do - if n <= d[2] then - return (n >= d[1]) - end - end - return false -end - --- "Trivial" (actually NOT) function to just read the node and some stuff to not just return "ignore", like mt 5.4 does. --- p: Position, if it's wrong, {name="error"} node will return. --- force: optional (default: false) - Do the maximum to still read the node within us_timeout. --- us_timeout: optional (default: 244 = 0.000244 s = 1/80/80/80), set it at least to 3000000 to let mapgen to finish its job. --- --- returns node definition, eg. {name="air"}. Unfortunately still can return {name="ignore"}. -function mcl_vars.get_node(p, force, us_timeout) - -- check initial circumstances - if not p or not p.x or not p.y or not p.z then return {name="error"} end - - -- try common way - local node = minetest.get_node(p) - if node.name ~= "ignore" then - return node - end - - -- copy table to get sure it won't changed by other threads - local pos = {x=p.x,y=p.y,z=p.z} - - -- try LVM - minetest.get_voxel_manip():read_from_map(pos, pos) - node = minetest.get_node(pos) - if node.name ~= "ignore" or not force then - return node - end - - -- all ways failed - need to emerge (or forceload if generated) - local us_timeout = us_timeout or 244 - if mcl_vars.is_generated(pos) then - minetest.chat_send_all("IMPOSSIBLE! Please report this to MCL2 issue tracker!") - minetest.forceload_block(pos) - else - minetest.emerge_area(pos, pos) - end - - local t = minetest.get_us_time() - - node = minetest.get_node(pos) - - while (not node or node.name == "ignore") and (minetest.get_us_time() - t < us_timeout) do - node = minetest.get_node(pos) - end - - return node - -- it still can return "ignore", LOL, even if force = true, but only after time out -end diff --git a/mods/CORE/mcl_mapgen/init.lua b/mods/CORE/mcl_mapgen/init.lua index 056da9146..f5c6a16f9 100644 --- a/mods/CORE/mcl_mapgen/init.lua +++ b/mods/CORE/mcl_mapgen/init.lua @@ -1,212 +1,305 @@ -mcl_mapgen = {} - -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_buffer, lvm_param2_buffer = {}, {} -- Static buffer pointers -local BS, CS = mcl_vars.MAP_BLOCKSIZE, mcl_vars.chunksize -- 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 offset = math.floor(mcl_vars.central_chunk_offset_in_nodes / BS) -- Central mapchunk offset (in blocks) - -local DEFAULT_PRIORITY = 5000 - -local minetest_log, math_floor = minetest.log, math.floor - -function mcl_mapgen.register_chunk_generator(callback_function, priority) - nodes_chunk = nodes_chunk + 1 - 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) -end -function mcl_mapgen.register_chunk_generator_lvm(callback_function, priority) - lvm = lvm + 1 - lvm_chunk_queue[lvm_chunk] = {i = priority or DEFAULT_PRIORITY, f = callback_function} - table.sort(lvm_chunk_queue, function(a, b) return (a.i <= b.i) end) -end -function mcl_mapgen.register_block_generator(callback_function, priority) - block = block + 1 - nodes_block = nodes_block + 1 - 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) -end -function mcl_mapgen.register_block_generator_lvm(callback_function, priority) - block = block + 1 - lvm = lvm + 1 - lvm_block = lvm_block + 1 - lvm_block_queue[lvm_block] = {i = priority or DEFAULT_PRIORITY, f = callback_function} - table.sort(lvm_block_queue, function(a, b) return (a.i <= b.i) end) -end - -local storage = minetest.get_mod_storage() -local blocks = minetest.deserialize( storage:get_string("mapgen_blocks") or "return {}") or {} -minetest.register_on_shutdown(function() storage:set_string("mapgen_blocks", minetest.serialize(blocks)) end) - -local vm_context-- here will be many references and flags, like: param2, light_data, heightmap, biomemap, heatmap, humiditymap, gennotify, write_lvm, write_param2, shadow -local data, data2, area -local current_blocks = {} - -minetest.register_on_generated(function(minp, maxp, blockseed) - local minp, maxp, blockseed = minp, maxp, blockseed - minetest_log("verbose", "[mcl_mapgen] New chunk: minp=" .. minetest.pos_to_string(minp) .. ", maxp=" .. minetest.pos_to_string(maxp) .. ", blockseed=" .. blockseed) - - local vm, emin, emax = minetest.get_mapgen_object("voxelmanip") - - if lvm > 0 then - vm_context = {lvm_param2_buffer = lvm_param2_buffer, vm = vm, emin = emin, emax = emax, minp = minp, maxp = maxp, blockseed = blockseed} - data = vm:get_data(lvm_buffer) - vm_context.data = data - area = VoxelArea:new({MinEdge=emin, MaxEdge=emax}) - vm_context.area = area - for _, v in pairs(lvm_chunk_queue) do - vm_context = v.f(vm_context) - end - end - - if block > 0 then - local x0, y0, z0 = minp.x, minp.y, minp.z - local bx0, by0, bz0 = math_floor(x0/BS), math_floor(y0/BS), math_floor(z0/BS) - local x1, y1, z1, x2, y2, z2 = emin.x, emin.y, emin.z, emax.x, emax.y, emax.z - local x, y, z = x1, y1, z1 -- iterate 7x7x7 mapchunk, {x,y,z} - first node pos. of mapblock - local bx, by, bz -- block coords (in blocs) - local box, boy, boz -- block offsets in chunks (in blocks) - while x < x2 do - bx = math_floor(x/BS) - local block_pos_offset_removed = bx - offset - box = block_pos_offset_removed % CS - if not blocks[bx] then blocks[bx]={} end - local total_mapgen_block_writes_through_x = (box > 0 and box < LAST_BLOCK) and 4 or 8 - while y < y2 do - by = math_floor(y/BS) - block_pos_offset_removed = by - offset - boy = block_pos_offset_removed % CS - if not blocks[bx][by] then blocks[bx][by]={} end - local total_mapgen_block_writes_through_y = (boy > 0 and boy < LAST_BLOCK) and math_floor(total_mapgen_block_writes_through_x / 2) or total_mapgen_block_writes_through_x - while z < z2 do - bz = math_floor(z/BS) - block_pos_offset_removed = bz - offset - boz = block_pos_offset_removed % CS - local total_mapgen_block_writes = (boz > 0 and boz < LAST_BLOCK) and math_floor(total_mapgen_block_writes_through_y / 2) or total_mapgen_block_writes_through_y - local current_mapgen_block_writes = blocks[bx][by][bz] and (blocks[bx][by][bz] + 1) or 1 - if current_mapgen_block_writes == total_mapgen_block_writes then - -- this block shouldn't be overwritten anymore, no need to keep it in memory - blocks[bx][by][bz] = nil - vm_context.seed = blockseed + box * 7 + boy * 243 + boz * 11931 - if lvm_block > 0 then - vm_context.minp, vm_content.maxp = {x=x, y=y, z=z}, {x=x+LAST_NODE, y=y+LAST_NODE, z=z+LAST_NODE} - for _, v in pairs(lvm_block_queue) do - vm_context = v.f(vm_context) - end - end - if nodes_block > 0 then - current_blocks[#current_blocks+1] = { minp = {x=x, y=y, z=z}, maxp = {x=pos.x+LAST_NODE, y=pos.y+LAST_NODE, z=pos.z+LAST_NODE}, seed = seed } - end - else - blocks[bx][by][bz] = current_mapgen_block_writes - end - z = z + BS - end - if next(blocks[bx][by]) == nil then blocks[bx][by] = nil end - z = z1 - y = y + BS - end - if next(blocks[bx]) == nil then blocks[bx] = nil end - y = y1 - x = x + BS - end - end - - if vm_context.write then - vm:set_data(data) - end - if vm_context.write_param2 then - vm:set_param2_data(data2) - end - vm:calc_lighting(p1, p2, shadow) - vm:write_to_map() - vm:update_liquids() - - for _, v in pairs(node_chunk_queue) do - v.f(minp, maxp, blockseed) - end - - for i, b in pairs(current_blocks) do - for _, v in pairs(node_block_queue) do - v.f(b.minp, b.maxp, b.seed) - end - current_blocks[id] = nil - end -end) - -minetest.register_on_generated = mcl_mapgen.register_chunk_generator - -function mcl_mapgen.get_far_node(p) - local p = p - local node = minetest_get_node(p) - if node.name ~= "ignore" then return node end - minetest_get_voxel_manip():read_from_map(p, p) - return minetest_get_node(p) -end - --- Calculate mapgen_edge_min/mapgen_edge_max -local function calculate_mapgen_basics() - mcl_mapgen.CS = math.max(1, tonumber(minetest.get_mapgen_setting("chunksize")) or 5) - mcl_mapgen.BS = math.max(1, core.MAP_BLOCKSIZE or 16) - mcl_mapgen.LIMIT = math.max(1, tonumber(minetest.get_mapgen_setting("mapgen_limit")) or 31000) - mcl_mapgen.MAX_LIMIT = math.max(1, core.MAX_MAP_GENERATION_LIMIT or 31000) - mcl_mapgen.OFFSET = - math.floor(mcl_mapgen.CS / 2) - mcl_mapgen.OFFSET_NODES = mcl_mapgen.OFFSET * mcl_mapgen.BS - mcl_mapgen.CS_NODES = mcl_mapgen.CS * mcl_mapgen.BS - - local central_chunk_min_pos = mcl_mapgen.OFFSET * mcl_mapgen.BS - local central_chunk_max_pos = central_chunk_min_pos + mcl_mapgen.CS_NODES - 1 - - local ccfmin = central_chunk_min_pos - mcl_mapgen.BS -- Fullminp/fullmaxp of central chunk, in nodes - local ccfmax = central_chunk_max_pos + mcl_mapgen.BS - - local mapgen_limit_b = math.floor(math.min(mcl_mapgen.LIMIT, mcl_mapgen.MAX_LIMIT) / mcl_mapgen.BS) - local mapgen_limit_min = - mapgen_limit_b * mcl_mapgen.BS - local mapgen_limit_max = (mapgen_limit_b + 1) * mcl_mapgen.BS - 1 - - local numcmin = math.max(math.floor((ccfmin - mapgen_limit_min) / mcl_vars.chunk_size_in_nodes), 0) -- Number of complete chunks from central chunk - local numcmax = math.max(math.floor((mapgen_limit_max - ccfmax) / mcl_vars.chunk_size_in_nodes), 0) -- fullminp/fullmaxp to effective mapgen limits. - - mcl_mapgen.EDGE_MIN = central_chunk_min_pos - numcmin * mcl_mapgen.CS_NODES - mcl_mapgen.EDGE_MAX = central_chunk_max_pos + numcmax * mcl_mapgen.CS_NODES -end - -local function coordinate_to_block(x) - return math_floor(x / mcl_mapgen.BS) -end - -local function coordinate_to_chunk(x) - return math_floor((coordinate_to_block(x) - central_chunk_offset) / mcl_vars.chunksize) -end - -function mcl_mapgen.pos_to_block(pos) - return { - x = coordinate_to_block(pos.x), - y = coordinate_to_block(pos.y), - z = coordinate_to_block(pos.z) - } -end - -function mcl_mapgen.pos_to_chunk(pos) - return { - x = coordinate_to_chunk(pos.x), - y = coordinate_to_chunk(pos.y), - z = coordinate_to_chunk(pos.z) - } -end - -calculate_mapgen_basics() - -local k_positive = math.ceil(mcl_mapgen.MAX_LIMIT / mcl_vars.chunk_size_in_nodes) -local k_positive_z = k_positive * 2 -local k_positive_y = k_positive_z * k_positive_z - -function mcl_mapgen.get_chunk_number(pos) -- unsigned int - local c = mcl_mapgen.pos_to_chunk(pos) - return - (c.y + k_positive) * k_positive_y + - (c.z + k_positive) * k_positive_z + - c.x + k_positive -end - +mcl_mapgen = {} + + +-- Calculate mapgen_edge_min/mapgen_edge_max +mcl_mapgen.CS = math.max(1, tonumber(minetest.get_mapgen_setting("chunksize")) or 5) +mcl_mapgen.BS = math.max(1, core.MAP_BLOCKSIZE or 16) +mcl_mapgen.LIMIT = math.max(1, tonumber(minetest.get_mapgen_setting("mapgen_limit")) or 31000) +mcl_mapgen.MAX_LIMIT = math.max(1, core.MAX_MAP_GENERATION_LIMIT or 31000) +mcl_mapgen.OFFSET = - math.floor(mcl_mapgen.CS / 2) +mcl_mapgen.OFFSET_NODES = mcl_mapgen.OFFSET * mcl_mapgen.BS +mcl_mapgen.CS_NODES = mcl_mapgen.CS * mcl_mapgen.BS + +local central_chunk_min_pos = mcl_mapgen.OFFSET * mcl_mapgen.BS +local central_chunk_max_pos = central_chunk_min_pos + mcl_mapgen.CS_NODES - 1 + +local ccfmin = central_chunk_min_pos - mcl_mapgen.BS -- Fullminp/fullmaxp of central chunk, in nodes +local ccfmax = central_chunk_max_pos + mcl_mapgen.BS + +local mapgen_limit_b = math.floor(math.min(mcl_mapgen.LIMIT, mcl_mapgen.MAX_LIMIT) / mcl_mapgen.BS) +local mapgen_limit_min = - mapgen_limit_b * mcl_mapgen.BS +local mapgen_limit_max = (mapgen_limit_b + 1) * mcl_mapgen.BS - 1 + +local numcmin = math.max(math.floor((ccfmin - mapgen_limit_min) / mcl_vars.chunk_size_in_nodes), 0) -- Number of complete chunks from central chunk +local numcmax = math.max(math.floor((mapgen_limit_max - ccfmax) / mcl_vars.chunk_size_in_nodes), 0) -- fullminp/fullmaxp to effective mapgen limits. + +mcl_mapgen.EDGE_MIN = central_chunk_min_pos - numcmin * mcl_mapgen.CS_NODES +mcl_mapgen.EDGE_MAX = central_chunk_max_pos + numcmax * mcl_mapgen.CS_NODES +------------------------------------------ + + +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_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 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 = math.floor(mcl_vars.central_chunk_offset_in_nodes / BS) -- Central mapchunk offset (in blocks) + +local DEFAULT_PRIORITY = 5000 + +local minetest_log, math_floor = minetest.log, math.floor + +function mcl_mapgen.register_chunk_generator(callback_function, priority) + nodes_chunk = nodes_chunk + 1 + 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) +end +function mcl_mapgen.register_chunk_generator_lvm(callback_function, priority) + lvm = lvm + 1 + lvm_chunk_queue[lvm_chunk] = {i = priority or DEFAULT_PRIORITY, f = callback_function} + table.sort(lvm_chunk_queue, function(a, b) return (a.i <= b.i) end) +end +function mcl_mapgen.register_block_generator(callback_function, priority) + block = block + 1 + nodes_block = nodes_block + 1 + 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) +end +function mcl_mapgen.register_block_generator_lvm(callback_function, priority) + block = block + 1 + lvm = lvm + 1 + lvm_block = lvm_block + 1 + lvm_block_queue[lvm_block] = {i = priority or DEFAULT_PRIORITY, f = callback_function} + table.sort(lvm_block_queue, function(a, b) return (a.i <= b.i) end) +end + +local storage = minetest.get_mod_storage() +local blocks = minetest.deserialize( storage:get_string("mapgen_blocks") or "return {}") or {} +minetest.register_on_shutdown(function() storage:set_string("mapgen_blocks", minetest.serialize(blocks)) end) + +local vm_context-- here will be many references and flags, like: param2, light_data, heightmap, biomemap, heatmap, humiditymap, gennotify, write_lvm, write_param2, shadow +local data, data2, area +local current_blocks = {} + +minetest.register_on_generated(function(minp, maxp, blockseed) + local minp, maxp, blockseed = minp, maxp, blockseed + minetest_log("verbose", "[mcl_mapgen] New chunk: minp=" .. minetest.pos_to_string(minp) .. ", maxp=" .. minetest.pos_to_string(maxp) .. ", blockseed=" .. blockseed) + + local vm, emin, emax = minetest.get_mapgen_object("voxelmanip") + + if lvm > 0 then + vm_context = {lvm_param2_buffer = lvm_param2_buffer, vm = vm, emin = emin, emax = emax, minp = minp, maxp = maxp, blockseed = blockseed} + data = vm:get_data(lvm_buffer) + vm_context.data = data + area = VoxelArea:new({MinEdge=emin, MaxEdge=emax}) + vm_context.area = area + for _, v in pairs(lvm_chunk_queue) do + vm_context = v.f(vm_context) + end + end + + if block > 0 then + local x0, y0, z0 = minp.x, minp.y, minp.z + local bx0, by0, bz0 = math_floor(x0/BS), math_floor(y0/BS), math_floor(z0/BS) + local x1, y1, z1, x2, y2, z2 = emin.x, emin.y, emin.z, emax.x, emax.y, emax.z + local x, y, z = x1, y1, z1 -- iterate 7x7x7 mapchunk, {x,y,z} - first node pos. of mapblock + local bx, by, bz -- block coords (in blocs) + local box, boy, boz -- block offsets in chunks (in blocks) + while x < x2 do + bx = math_floor(x/BS) + local block_pos_offset_removed = bx - offset + box = block_pos_offset_removed % CS + if not blocks[bx] then blocks[bx]={} end + local total_mapgen_block_writes_through_x = (box > 0 and box < LAST_BLOCK) and 4 or 8 + while y < y2 do + by = math_floor(y/BS) + block_pos_offset_removed = by - offset + boy = block_pos_offset_removed % CS + if not blocks[bx][by] then blocks[bx][by]={} end + local total_mapgen_block_writes_through_y = (boy > 0 and boy < LAST_BLOCK) and math_floor(total_mapgen_block_writes_through_x / 2) or total_mapgen_block_writes_through_x + while z < z2 do + bz = math_floor(z/BS) + block_pos_offset_removed = bz - offset + boz = block_pos_offset_removed % CS + local total_mapgen_block_writes = (boz > 0 and boz < LAST_BLOCK) and math_floor(total_mapgen_block_writes_through_y / 2) or total_mapgen_block_writes_through_y + local current_mapgen_block_writes = blocks[bx][by][bz] and (blocks[bx][by][bz] + 1) or 1 + if current_mapgen_block_writes == total_mapgen_block_writes then + -- this block shouldn't be overwritten anymore, no need to keep it in memory + blocks[bx][by][bz] = nil + vm_context.seed = blockseed + box * 7 + boy * 243 + boz * 11931 + if lvm_block > 0 then + vm_context.minp, vm_content.maxp = {x=x, y=y, z=z}, {x=x+LAST_NODE, y=y+LAST_NODE, z=z+LAST_NODE} + for _, v in pairs(lvm_block_queue) do + vm_context = v.f(vm_context) + end + end + if nodes_block > 0 then + current_blocks[#current_blocks+1] = { minp = {x=x, y=y, z=z}, maxp = {x=pos.x+LAST_NODE, y=pos.y+LAST_NODE, z=pos.z+LAST_NODE}, seed = seed } + end + else + blocks[bx][by][bz] = current_mapgen_block_writes + end + z = z + BS + end + if next(blocks[bx][by]) == nil then blocks[bx][by] = nil end + z = z1 + y = y + BS + end + if next(blocks[bx]) == nil then blocks[bx] = nil end + y = y1 + x = x + BS + end + end + + if vm_context.write then + vm:set_data(data) + end + if vm_context.write_param2 then + vm:set_param2_data(data2) + end + vm:calc_lighting(p1, p2, shadow) + vm:write_to_map() + vm:update_liquids() + + for _, v in pairs(node_chunk_queue) do + v.f(minp, maxp, blockseed) + end + + for i, b in pairs(current_blocks) do + for _, v in pairs(node_block_queue) do + v.f(b.minp, b.maxp, b.seed) + end + current_blocks[id] = nil + end +end) + +minetest.register_on_generated = mcl_mapgen.register_chunk_generator + +function mcl_mapgen.get_far_node(p) + local p = p + local node = minetest_get_node(p) + if node.name ~= "ignore" then return node end + minetest_get_voxel_manip():read_from_map(p, p) + return minetest_get_node(p) +end + +local function coordinate_to_block(x) + return math_floor(x / mcl_mapgen.BS) +end + +local function coordinate_to_chunk(x) + return math_floor((coordinate_to_block(x) - central_chunk_offset) / mcl_mapgen.CS) +end + +function mcl_mapgen.pos_to_block(pos) + return { + x = coordinate_to_block(pos.x), + y = coordinate_to_block(pos.y), + z = coordinate_to_block(pos.z) + } +end + +function mcl_mapgen.pos_to_chunk(pos) + return { + x = coordinate_to_chunk(pos.x), + y = coordinate_to_chunk(pos.y), + z = coordinate_to_chunk(pos.z) + } +end + +local k_positive = math.ceil(mcl_mapgen.MAX_LIMIT / mcl_vars.chunk_size_in_nodes) +local k_positive_z = k_positive * 2 +local k_positive_y = k_positive_z * k_positive_z + +function mcl_mapgen.get_chunk_number(pos) -- unsigned int + local c = mcl_mapgen.pos_to_chunk(pos) + return + (c.y + k_positive) * k_positive_y + + (c.z + k_positive) * k_positive_z + + c.x + k_positive +end + + + + + +-- Mapgen variables +local mg_name = minetest.get_mapgen_setting("mg_name") +local minecraft_height_limit = 256 +local superflat = mg_name == "flat" and minetest.get_mapgen_setting("mcl_superflat_classic") == "true" +local singlenode = mg_name == "singlenode" + +if not superflat and not singlenode then + -- Normal mode + --[[ Realm stacking (h is for height) + - Overworld (h>=256) + - Void (h>=1000) + - Realm Barrier (h=11), to allow escaping the End + - End (h>=256) + - Void (h>=1000) + - Nether (h=128) + - Void (h>=1000) + ]] + + -- Overworld + mcl_vars.mg_overworld_min = -62 + mcl_vars.mg_overworld_max_official = mcl_vars.mg_overworld_min + minecraft_height_limit + mcl_vars.mg_bedrock_overworld_min = mcl_vars.mg_overworld_min + mcl_vars.mg_bedrock_overworld_max = mcl_vars.mg_bedrock_overworld_min + 4 + mcl_vars.mg_lava_overworld_max = mcl_vars.mg_overworld_min + 10 + mcl_vars.mg_lava = true + mcl_vars.mg_bedrock_is_rough = true + +elseif singlenode then + mcl_vars.mg_overworld_min = -66 + mcl_vars.mg_overworld_max_official = mcl_vars.mg_overworld_min + minecraft_height_limit + mcl_vars.mg_bedrock_overworld_min = mcl_vars.mg_overworld_min + mcl_vars.mg_bedrock_overworld_max = mcl_vars.mg_bedrock_overworld_min + mcl_vars.mg_lava = false + mcl_vars.mg_lava_overworld_max = mcl_vars.mg_overworld_min + mcl_vars.mg_bedrock_is_rough = false +else + -- Classic superflat + local ground = minetest.get_mapgen_setting("mgflat_ground_level") + ground = tonumber(ground) + if not ground then + ground = 8 + end + mcl_vars.mg_overworld_min = ground - 3 + mcl_vars.mg_overworld_max_official = mcl_vars.mg_overworld_min + minecraft_height_limit + mcl_vars.mg_bedrock_overworld_min = mcl_vars.mg_overworld_min + mcl_vars.mg_bedrock_overworld_max = mcl_vars.mg_bedrock_overworld_min + mcl_vars.mg_lava = false + mcl_vars.mg_lava_overworld_max = mcl_vars.mg_overworld_min + mcl_vars.mg_bedrock_is_rough = false +end + +mcl_vars.mg_overworld_max = mcl_mapgen.EDGE_MAX + +-- The Nether (around Y = -29000) +mcl_vars.mg_nether_min = -29067 -- Carefully chosen to be at a mapchunk border +mcl_vars.mg_nether_max = mcl_vars.mg_nether_min + 128 +mcl_vars.mg_bedrock_nether_bottom_min = mcl_vars.mg_nether_min +mcl_vars.mg_bedrock_nether_top_max = mcl_vars.mg_nether_max +if not superflat then + mcl_vars.mg_bedrock_nether_bottom_max = mcl_vars.mg_bedrock_nether_bottom_min + 4 + mcl_vars.mg_bedrock_nether_top_min = mcl_vars.mg_bedrock_nether_top_max - 4 + mcl_vars.mg_lava_nether_max = mcl_vars.mg_nether_min + 31 +else + -- Thin bedrock in classic superflat mapgen + mcl_vars.mg_bedrock_nether_bottom_max = mcl_vars.mg_bedrock_nether_bottom_min + mcl_vars.mg_bedrock_nether_top_min = mcl_vars.mg_bedrock_nether_top_max + mcl_vars.mg_lava_nether_max = mcl_vars.mg_nether_min + 2 +end +if mg_name == "flat" then + if superflat then + mcl_vars.mg_flat_nether_floor = mcl_vars.mg_bedrock_nether_bottom_max + 4 + mcl_vars.mg_flat_nether_ceiling = mcl_vars.mg_bedrock_nether_bottom_max + 52 + else + mcl_vars.mg_flat_nether_floor = mcl_vars.mg_lava_nether_max + 4 + mcl_vars.mg_flat_nether_ceiling = mcl_vars.mg_lava_nether_max + 52 + end +end + +-- The End (surface at ca. Y = -27000) +mcl_vars.mg_end_min = -27073 -- Carefully chosen to be at a mapchunk border +mcl_vars.mg_end_max_official = mcl_vars.mg_end_min + minecraft_height_limit +mcl_vars.mg_end_max = mcl_vars.mg_overworld_min - 2000 +mcl_vars.mg_end_platform_pos = { x = 100, y = mcl_vars.mg_end_min + 74, z = 0 } + +-- Realm barrier used to safely separate the End from the void below the Overworld +mcl_vars.mg_realm_barrier_overworld_end_max = mcl_vars.mg_end_max +mcl_vars.mg_realm_barrier_overworld_end_min = mcl_vars.mg_end_max - 11 + +-- Use MineClone 2-style dungeons +mcl_vars.mg_dungeons = true diff --git a/mods/ENTITIES/mcl_mobs/api.lua b/mods/ENTITIES/mcl_mobs/api.lua index 3f635ece0..16ab55a28 100644 --- a/mods/ENTITIES/mcl_mobs/api.lua +++ b/mods/ENTITIES/mcl_mobs/api.lua @@ -919,19 +919,8 @@ end -- check if within physical map limits (-30911 to 30927) -local within_limits, wmin, wmax = nil, -30913, 30928 -within_limits = function(pos, radius) - if mcl_vars then - if mcl_vars.mapgen_edge_min and mcl_vars.mapgen_edge_max then - wmin, wmax = mcl_vars.mapgen_edge_min, mcl_vars.mapgen_edge_max - within_limits = function(pos, radius) - return pos - and (pos.x - radius) > wmin and (pos.x + radius) < wmax - and (pos.y - radius) > wmin and (pos.y + radius) < wmax - and (pos.z - radius) > wmin and (pos.z + radius) < wmax - end - end - end +local wmin, wmax = mcl_mapgen.EDGE_MIN, mcl_mapgen.EDGE_MAX +local function within_limits(pos, radius) return pos and (pos.x - radius) > wmin and (pos.x + radius) < wmax and (pos.y - radius) > wmin and (pos.y + radius) < wmax diff --git a/mods/ENTITIES/mcl_mobs/mod.conf b/mods/ENTITIES/mcl_mobs/mod.conf index 0d622f6a9..d6089dac6 100644 --- a/mods/ENTITIES/mcl_mobs/mod.conf +++ b/mods/ENTITIES/mcl_mobs/mod.conf @@ -1,5 +1,5 @@ name = mcl_mobs author = PilzAdam description = Adds a mob API for mods to add animals or monsters, etc. -depends = mcl_particles +depends = mcl_mapgen, mcl_particles optional_depends = mcl_weather, mcl_explosions, mcl_hunger, mcl_worlds, invisibility, lucky_block, cmi, doc_identifier, mcl_armor, mcl_portals, mcl_experience diff --git a/mods/ITEMS/mcl_portals/mod.conf b/mods/ITEMS/mcl_portals/mod.conf index d99344a76..e2ebc0385 100644 --- a/mods/ITEMS/mcl_portals/mod.conf +++ b/mods/ITEMS/mcl_portals/mod.conf @@ -1,4 +1,4 @@ name = mcl_portals description = Adds buildable portals to the Nether and End dimensions. -depends = mcl_nether, mcl_end, mcl_particles, mcl_spawn +depends = mcl_mapgen, mcl_nether, mcl_end, mcl_particles, mcl_spawn optional_depends = awards, doc diff --git a/mods/ITEMS/mcl_portals/portal_nether.lua b/mods/ITEMS/mcl_portals/portal_nether.lua index a121f719c..7fd0191fa 100644 --- a/mods/ITEMS/mcl_portals/portal_nether.lua +++ b/mods/ITEMS/mcl_portals/portal_nether.lua @@ -19,7 +19,7 @@ local W_MIN, W_MAX = 4, 23 local H_MIN, H_MAX = 5, 23 local N_MIN, N_MAX = 6, (W_MAX-2) * (H_MAX-2) local TRAVEL_X, TRAVEL_Y, TRAVEL_Z = 8, 1, 8 -local LIM_MIN, LIM_MAX = mcl_vars.mapgen_edge_min, mcl_vars.mapgen_edge_max +local LIM_MIN, LIM_MAX = mcl_mapgen.EDGE_MIN, mcl_mapgen.EDGE_MAX local PLAYER_COOLOFF, MOB_COOLOFF = 3, 14 -- for this many seconds they won't teleported again local TOUCH_CHATTER_TIME = 1 -- prevent multiple teleportation attempts caused by multiple portal touches, for this number of seconds local CHATTER_US = TOUCH_CHATTER_TIME * 1000000 @@ -522,8 +522,8 @@ local function create_portal(pos, limit1, limit2, name, obj) -- so we'll emerge single chunk only: 5x5x5 blocks, 80x80x80 nodes maximum -- and maybe one more chunk from below if (SCAN_2_MAP_CHUNKS = true) - local pos1 = add(mul(mcl_vars.pos_to_chunk(pos), mcl_vars.chunk_size_in_nodes), mcl_vars.central_chunk_offset_in_nodes) - local pos2 = add(pos1, mcl_vars.chunk_size_in_nodes - 1) + local pos1 = add(mul(mcl_mapgen.pos_to_chunk(pos), mcl_mapgen.CS_NODES), mcl_mapgen.OFFSET_NODES) + local pos2 = add(pos1, mcl_mapgen.CS_NODES - 1) if not SCAN_2_MAP_CHUNKS then if limit1 and limit1.x and limit1.y and limit1.z then diff --git a/mods/MAPGEN/mcl_dungeons/init.lua b/mods/MAPGEN/mcl_dungeons/init.lua index 63433d08d..40af11d37 100644 --- a/mods/MAPGEN/mcl_dungeons/init.lua +++ b/mods/MAPGEN/mcl_dungeons/init.lua @@ -40,7 +40,7 @@ local max_y = mcl_vars.mg_overworld_max - 1 -- Calculate the number of dungeon spawn attempts -- 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. -local attempts = math_ceil(((mcl_vars.chunksize * mcl_vars.MAP_BLOCKSIZE) ^ 3) / 8192) -- 63 = 80*80*80/8192 +local attempts = math_ceil((mcl_mapgen.CS_NODES ^ 3) / 8192) -- 63 = 80*80*80/8192 local dungeonsizes = { { x=5, y=4, z=5}, diff --git a/mods/MAPGEN/mcl_dungeons/mod.conf b/mods/MAPGEN/mcl_dungeons/mod.conf index fe02286fa..e7a7d921c 100644 --- a/mods/MAPGEN/mcl_dungeons/mod.conf +++ b/mods/MAPGEN/mcl_dungeons/mod.conf @@ -1,4 +1,4 @@ name = mcl_dungeons author = Wuzzy description = Generates random dungeons in the world -depends = mcl_init, mcl_core, mcl_chests, mcl_mobs, mcl_mobspawners, mcl_mapgen_core, mobs_mc +depends = mcl_mapgen, mcl_core, mcl_chests, mcl_mobs, mcl_mobspawners, mcl_mapgen_core, mobs_mc diff --git a/mods/MAPGEN/mcl_mapgen_core/init.lua b/mods/MAPGEN/mcl_mapgen_core/init.lua index 031a568f7..b14e1c2c7 100644 --- a/mods/MAPGEN/mcl_mapgen_core/init.lua +++ b/mods/MAPGEN/mcl_mapgen_core/init.lua @@ -1899,7 +1899,7 @@ local function basic(c) local pr = PseudoRandom(blockseed) -- The Void below the Nether: - lvm_used = set_layers(data, area, c_void , nil, mcl_vars.mapgen_edge_min , mcl_vars.mg_nether_min -1, minp, maxp, lvm_used, pr) + lvm_used = set_layers(data, area, c_void , nil, mcl_mapgen.EDGE_MIN , mcl_vars.mg_nether_min -1, minp, maxp, lvm_used, pr) -- [[ THE NETHER: mcl_vars.mg_nether_min mcl_vars.mg_nether_max ]] diff --git a/mods/PLAYER/mcl_spawn/init.lua b/mods/PLAYER/mcl_spawn/init.lua index b8c746d1f..34105c094 100644 --- a/mods/PLAYER/mcl_spawn/init.lua +++ b/mods/PLAYER/mcl_spawn/init.lua @@ -81,7 +81,7 @@ local dir_step = storage:get_int("mcl_spawn_dir_step") or 0 local dir_ind = storage:get_int("mcl_spawn_dir_ind") or 1 local emerge_pos1, emerge_pos2 -local spawn_limit = mcl_vars.mapgen_edge_max +local spawn_limit = mcl_mapgen.EDGE_MAX --Functions diff --git a/mods/PLAYER/mcl_spawn/mod.conf b/mods/PLAYER/mcl_spawn/mod.conf index 954f831db..2c7953fe7 100644 --- a/mods/PLAYER/mcl_spawn/mod.conf +++ b/mods/PLAYER/mcl_spawn/mod.conf @@ -1,4 +1,4 @@ name = mcl_spawn author = Wuzzy description = Set and get the player's respawn position -depends = mcl_init +depends = mcl_mapgen