From 6b848c51d26c878a31379ca79dbe92024f82c04a Mon Sep 17 00:00:00 2001 From: kay27 Date: Wed, 2 Feb 2022 05:21:05 +0400 Subject: [PATCH 1/5] Fix villages initialization --- mods/MAPGEN/mcl_villages/buildings.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mods/MAPGEN/mcl_villages/buildings.lua b/mods/MAPGEN/mcl_villages/buildings.lua index 7c70e1d3b..0860ce9a5 100644 --- a/mods/MAPGEN/mcl_villages/buildings.lua +++ b/mods/MAPGEN/mcl_villages/buildings.lua @@ -192,7 +192,8 @@ local function construct_node(p1, p2, name) end minetest.log("warning", "[mcl_villages] Attempt to 'construct' inexistant nodes: " .. name) end -local function init_nodes(p1, p2, size, rotation, pr) +local function init_nodes(p1, rotation, pr, size) + local p2 = vector.subtract(vector.add(p1, size), 1) construct_node(p1, p2, "mcl_itemframes:item_frame") construct_node(p1, p2, "mcl_furnaces:furnace") construct_node(p1, p2, "mcl_anvils:anvil") @@ -272,8 +273,7 @@ function settlements.place_schematics(settlement_info, pr) pos = pos, schematic = schematic, rotation = rotation, - force_placement = true, - on_place = init_nodes, + on_placed = init_nodes, pr = pr, }) end From 7d57bb7d6e5a567713d3852c718040bf6b8c3b63 Mon Sep 17 00:00:00 2001 From: kay27 Date: Fri, 4 Feb 2022 04:44:41 +0400 Subject: [PATCH 2/5] Implement basic part of mapgen API v3 --- mods/CORE/mcl_mapgen/init.lua | 297 +++++++++++++++++----------------- 1 file changed, 152 insertions(+), 145 deletions(-) diff --git a/mods/CORE/mcl_mapgen/init.lua b/mods/CORE/mcl_mapgen/init.lua index 71442dbaf..838f0289b 100644 --- a/mods/CORE/mcl_mapgen/init.lua +++ b/mods/CORE/mcl_mapgen/init.lua @@ -19,13 +19,18 @@ local minetest_log = minetest.log local minetest_pos_to_string = minetest.pos_to_string -- 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) -- might be set to 31000 or removed, see https://github.com/minetest/minetest/issues/10428 -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 +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 = 31000 -- MAX_MAP_GENERATION_LIMIT, https://github.com/minetest/minetest/issues/10428 +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 +mcl_mapgen.LAST_BLOCK = mcl_mapgen.CS - 1 +mcl_mapgen.LAST_NODE_IN_BLOCK = mcl_mapgen.BS - 1 +mcl_mapgen.LAST_NODE_IN_CHUNK = mcl_mapgen.CS_NODES - 1 +mcl_mapgen.HALF_CS_NODES = math_floor(mcl_mapgen.CS_NODES / 2) +mcl_mapgen.CS_3D = mcl_mapgen.CS^3 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 @@ -77,12 +82,14 @@ local nodes_block = 0 local nodes_chunk = 0 local safe_functions = 0 -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 = mcl_mapgen.OFFSET -- Central mapchunk offset (in blocks) -local CS_NODES = mcl_mapgen.CS_NODES -- 80 - -local CS_3D = CS * CS * CS +local BS, CS = mcl_mapgen.BS, mcl_mapgen.CS -- Mapblock size (in nodes), Mapchunk size (in blocks) +local offset = mcl_mapgen.OFFSET -- Central mapchunk offset (in blocks) +local CS_NODES = mcl_mapgen.CS_NODES +local LAST_BLOCK = mcl_mapgen.LAST_BLOCK +local LAST_NODE_IN_BLOCK = mcl_mapgen.LAST_NODE_IN_BLOCK +local LAST_NODE_IN_CHUNK = mcl_mapgen.LAST_NODE_IN_CHUNK +local HALF_CS_NODES = mcl_mapgen.HALF_CS_NODES +local CS_3D = mcl_mapgen.CS_3D local DEFAULT_ORDER = order.DEFAULT @@ -117,20 +124,72 @@ function mcl_mapgen.register_mapgen_block_lvm(callback_function, order) table.sort(queue_blocks_lvm, function(a, b) return (a.order <= b.order) end) end -local storage = minetest.get_mod_storage() -local blocks = minetest.deserialize(storage:get_string("mapgen_blocks") or "return {}") or {} -local chunks = minetest.deserialize(storage:get_string("mapgen_chunks") or "return {}") or {} -minetest.register_on_shutdown(function() - storage:set_string("mapgen_chunks", minetest.serialize(chunks)) - 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, param2_data, light, area -local current_blocks = {} -local current_chunks = {} local lvm_buffer, lvm_param2_buffer, lvm_light_buffer = {}, {}, {} -- Static buffer pointers +local all_blocks_in_chunk = {} +for x = 0, CS-1 do + for y = 0, CS-1 do + for z = 0, CS-1 do + all_blocks_in_chunk[CS * (CS * x + y) + z] = vector.new(x, y, z) + end + end +end + +local chunk_scan_range = { + [-CS_NODES] = {0 , 0 }, + [ 0 ] = {0 , LAST_BLOCK}, + [ CS_NODES] = {LAST_BLOCK, LAST_BLOCK}, +} + +local function is_chunk_finished(minp) + local center = minp + HALF_CS_NODES + for check_x = center.x - CS_NODES, center.x + CS_NODES, CS_NODES do + for check_y = center.y - CS_NODES, center.y + CS_NODES, CS_NODES do + for check_z = center.z - CS_NODES, center.z + CS_NODES, CS_NODES do + local pos = vector.new(check_x, check_y, check_z) + if pos ~= center then + minetest_get_voxel_manip():read_from_map(pos, pos) + local node = minetest_get_node(pos) + if node.name == "ignore" then + return + end + end + end + end + end +end + +local function unsigned(v) + if v < 0 then + v = 0x100000000 - (math.abs(v) % 0x100000000) + end + return v % 0x100000000 +end + +local function bitwise_xor_32(a, b) + local a = unsigned(a) + local b = unsigned(b) + local c = 0 + for n = 31, 0, -1 do + local mask = math.floor(2^n) + if (a >= mask) ~= (b >= mask) then + c = c + mask + end + a = a % mask + b = b % mask + end + return c +end + +local function getBlockSeed2(pos, seed) + local seed = seed or mcl_mapgen.seed + local n = unsigned(unsigned(1619 * pos.x) + unsigned(31337 * pos.y) + unsigned(52591 * pos.z) + unsigned(1013 * seed)) + n = bitwise_xor_32(math.floor(n / 0x2000), n) + return unsigned((n * unsigned(n * n * 60493 + 19990303) + 1376312589)) +end + minetest.register_on_generated(function(minp, maxp, chunkseed) local minp, maxp, chunkseed = minp, maxp, chunkseed local vm, emin, emax = minetest.get_mapgen_object("voxelmanip") @@ -154,117 +213,71 @@ minetest.register_on_generated(function(minp, maxp, chunkseed) chunkseed = chunkseed, } + local current_blocks = {} + local current_chunks = {} if safe_functions > 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 bx1, by1, bz1 = bx0 + LAST_BLOCK, by0 + LAST_BLOCK, bz0 + LAST_BLOCK -- only for entire chunk check - - -- Keep `chunkseed` in `chunks[cx][cy][cz].seed` for further safe usage: - local cx0, cy0, cz0 = math_floor((bx0-offset)/CS), math_floor((by0-offset)/CS), math_floor((bz0-offset)/CS) - if not chunks[cx0] then chunks[cx0] = {} end - if not chunks[cx0][cy0] then chunks[cx0][cy0] = {} end - if not chunks[cx0][cy0][cz0] then - chunks[cx0][cy0][cz0] = {seed = chunkseed, counter = 0} - else - chunks[cx0][cy0][cz0].seed = chunkseed - end - - 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 - local cx = math_floor(block_pos_offset_removed / CS) - box = block_pos_offset_removed % CS - if not blocks[bx] then blocks[bx]={} end - - -- We don't know how many calls, including this one, will overwrite this block content! - -- Start calculating it with `total_mapgen_block_writes_through_x` variable. - -- It can be `8 or less`, if we (speaking of `x` axis) are on chunk edge now, - -- or it can be `4 or less` - if we are in the middle of the chunk by `x` axis: - - 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 - local cy = math_floor(block_pos_offset_removed / CS) - boy = block_pos_offset_removed % CS - if not blocks[bx][by] then blocks[bx][by]={} end - - -- Here we just divide `total_mapgen_block_writes_through_x` by 2, - -- if we are (speaking of `y` axis now) in the middle of the chunk now. - -- Or we don't divide it, if not. - -- So, basing on `total_mapgen_block_writes_through_x`, - --- we calculate `total_mapgen_block_writes_through_y` this way: - - 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 - local cz = math_floor(block_pos_offset_removed / CS) - boz = block_pos_offset_removed % CS - - -- Now we do absolutely the same for `z` axis, basing on our previous result - -- from `total_mapgen_block_writes_through_y` variable. - -- And our final result is in `total_mapgen_block_writes`. - -- It can be still 8, derived from `x` calculation, but it can be less! - -- It can be even 1, if we are in safe 3x3x3 area of mapchunk: - - 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 - - -- Get current number of writes from the table, or just set it to 1, if accessing first time: - - local current_mapgen_block_writes = blocks[bx][by][bz] and (blocks[bx][by][bz] + 1) or 1 - - -- And compare: - - 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 - 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 chunks[cx][cy][cz] = {counter = 1} end + local ready_blocks = table.copy(all_blocks_in_chunk) + local p0 = vector.new(minp) + local center = p0 + HALF_CS_NODES + for x = -CS_NODES, CS_NODES, CS_NODES do + for y = -CS_NODES, CS_NODES, CS_NODES do + for z = -CS_NODES, CS_NODES, CS_NODES do + if x ~= 0 or y ~= 0 or z ~= 0 then + local offset = vector.new(x, y, z) + local pos = center + offset + minetest_get_voxel_manip():read_from_map(pos, pos) + local node = minetest_get_node(pos) + local is_generated = node.name ~= "ignore" + if is_generated then + local adjacent_chunk_pos = p0 + offset + if is_chunk_finished(adjacent_chunk_pos) then + current_chunks[#current_chunks + 1] = adjacent_chunk_pos + end else - chunks[cx][cy][cz].counter = chunks[cx][cy][cz].counter + 1 - 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 - chunks[cx][cy][cz] = nil - if next(chunks[cx][cy]) == nil then chunks[cx][cy] = nil end - if next(chunks[cx]) == nil then chunks[cx] = nil end + local scan_range_x = chunk_scan_range[x] + for cut_x = scan_range_x[1], scan_range_x[2] do + local scan_range_y = chunk_scan_range[y] + for cut_y = scan_range_y[1], scan_range_y[2] do + local scan_range_z = chunk_scan_range[z] + for cut_z = scan_range_z[1], scan_range_z[2] do + ready_blocks[CS * (CS * cut_x + cut_y) + cut_z] = nil + end + end end end - local blockseed = seed + bx * 7 + by * 243 + bz * 11931 - if queue_blocks_lvm_counter > 0 then - vm_context.blockseed = blockseed - vm_context.minp, vm_context.maxp = {x=x, y=y, z=z}, {x=x+LAST_NODE, y=y+LAST_NODE, z=z+LAST_NODE} - for _, v in pairs(queue_blocks_lvm) do - v.callback_function(vm_context) - end - end - if nodes_block > 0 then - current_blocks[#current_blocks+1] = { minp = {x=x, y=y, z=z}, maxp = {x=x+LAST_NODE, y=y+LAST_NODE, z=z+LAST_NODE}, seed = blockseed } - 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 + local number_of_blocks = 0 + for k, offset in pairs(ready_blocks) do + if queue_blocks_lvm_counter > 0 then + local block_minp = p0 + offset * BS + local block_maxp = block_minp + LAST_NODE_IN_BLOCK + local blockseed = getBlockSeed2(block_minp) + vm_context.minp, vm_context.maxp, vm_context.blockseed = block_minp, block_maxp, blockseed + -- -- + -- mcl_mapgen.register_mapgen_block_lvm(function(vm_context), order_number) -- + -- -- + for _, v in pairs(queue_blocks_lvm) do + v.callback_function(vm_context) + end + if nodes_block > 0 then + current_blocks[#current_blocks + 1] = { minp = block_minp, maxp = block_maxp, seed = blockseed } + end + end + number_of_blocks = number_of_blocks + 1 + end + if number_of_blocks == CS_3D then + current_chunks[#current_chunks + 1] = p0 end end if #queue_unsafe_engine > 0 then vm_context.minp, vm_context.maxp = minp, maxp + -- * U N S A F E -- + -- mcl_mapgen.register_on_generated(function(vm_context), order_number) -- + -- * U N S A F E -- for _, v in pairs(queue_unsafe_engine) do v.f(vm_context) end @@ -286,12 +299,9 @@ minetest.register_on_generated(function(minp, maxp, chunkseed) end end - for i, b in pairs(current_chunks) do - 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 i, chunk_minp in pairs(current_chunks) do + local chunk_maxp = chunk_minp + LAST_NODE_IN_CHUNK + local chunkseed = getBlockSeed2(chunk_minp) area = VoxelArea:new({MinEdge=minp, MaxEdge=maxp}) vm_context = { data = data, @@ -301,15 +311,21 @@ minetest.register_on_generated(function(minp, maxp, chunkseed) lvm_buffer = lvm_buffer, lvm_param2_buffer = lvm_param2_buffer, lvm_light_buffer = lvm_light_buffer, - emin = minp, - emax = maxp, - minp = minp, - maxp = maxp, - chunkseed = seed, + emin = chunk_minp, + emax = chunk_maxp, + minp = chunk_minp, + maxp = chunk_maxp, + chunkseed = chunkseedseed, } + -- -- + -- mcl_mapgen.register_mapgen_lvm(function(vm_context), order_number) -- + -- -- for _, v in pairs(queue_chunks_lvm) do vm_context = v.f(vm_context) end + -- -- + -- mcl_mapgen.register_mapgen(function(minp, maxp, chunkseed, vm_context), order_number) -- + -- -- for _, v in pairs(queue_chunks_nodes) do v.f(minp, maxp, seed, vm_context) end @@ -330,14 +346,15 @@ minetest.register_on_generated(function(minp, maxp, chunkseed) elseif vm_context.calc_lighting then vm:calc_lighting(minp, maxp, (vm_context.shadow ~= nil) or true) end - current_chunks[i] = nil end for i, b in pairs(current_blocks) do + -- -- + -- mcl_mapgen.register_mapgen_block(function(minp, maxp, blockseed), order_number) -- + -- -- for _, v in pairs(queue_blocks_nodes) do v.f(b.minp, b.maxp, b.seed) end - current_blocks[i] = nil end end) @@ -391,16 +408,6 @@ mcl_mapgen.minecraft_height_limit = 256 mcl_mapgen.bedrock_is_rough = normal ---[[ 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 overworld.min = -62 if superflat then From 080fe253ade7aa0c6fb78ee7a3c331f551df33d4 Mon Sep 17 00:00:00 2001 From: kay27 Date: Fri, 4 Feb 2022 05:04:31 +0400 Subject: [PATCH 3/5] Remove crashes --- mods/CORE/mcl_mapgen/init.lua | 8 ++++---- mods/MAPGEN/mcl_structures/structures.lua | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/mods/CORE/mcl_mapgen/init.lua b/mods/CORE/mcl_mapgen/init.lua index 838f0289b..7076c5be8 100644 --- a/mods/CORE/mcl_mapgen/init.lua +++ b/mods/CORE/mcl_mapgen/init.lua @@ -144,7 +144,7 @@ local chunk_scan_range = { } local function is_chunk_finished(minp) - local center = minp + HALF_CS_NODES + local center = vector.add(minp, HALF_CS_NODES) for check_x = center.x - CS_NODES, center.x + CS_NODES, CS_NODES do for check_y = center.y - CS_NODES, center.y + CS_NODES, CS_NODES do for check_z = center.z - CS_NODES, center.z + CS_NODES, CS_NODES do @@ -218,7 +218,7 @@ minetest.register_on_generated(function(minp, maxp, chunkseed) if safe_functions > 0 then local ready_blocks = table.copy(all_blocks_in_chunk) local p0 = vector.new(minp) - local center = p0 + HALF_CS_NODES + local center = vector.add(p0, HALF_CS_NODES) for x = -CS_NODES, CS_NODES, CS_NODES do for y = -CS_NODES, CS_NODES, CS_NODES do for z = -CS_NODES, CS_NODES, CS_NODES do @@ -252,8 +252,8 @@ minetest.register_on_generated(function(minp, maxp, chunkseed) local number_of_blocks = 0 for k, offset in pairs(ready_blocks) do if queue_blocks_lvm_counter > 0 then - local block_minp = p0 + offset * BS - local block_maxp = block_minp + LAST_NODE_IN_BLOCK + local block_minp = p0 + vector.multiply(offset, BS) + local block_maxp = vector.add(block_minp, LAST_NODE_IN_BLOCK) local blockseed = getBlockSeed2(block_minp) vm_context.minp, vm_context.maxp, vm_context.blockseed = block_minp, block_maxp, blockseed -- -- diff --git a/mods/MAPGEN/mcl_structures/structures.lua b/mods/MAPGEN/mcl_structures/structures.lua index fd6b21b26..b18904d9a 100644 --- a/mods/MAPGEN/mcl_structures/structures.lua +++ b/mods/MAPGEN/mcl_structures/structures.lua @@ -11,7 +11,7 @@ if not mcl_mapgen.singlenode then dofile(modpath .. "/ice_spike_large.lua") dofile(modpath .. "/jungle_temple.lua") dofile(modpath .. "/nice_jungle_temple.lua") - -- dofile(modpath .. "/noise_indicator.lua") + dofile(modpath .. "/noise_indicator.lua") dofile(modpath .. "/stronghold.lua") dofile(modpath .. "/witch_hut.lua") end From 97896c19e97cd339b4625e603d29d5f09aa17b46 Mon Sep 17 00:00:00 2001 From: kay27 Date: Fri, 4 Feb 2022 06:08:09 +0400 Subject: [PATCH 4/5] Fix last mapgen v3 issues --- mods/CORE/mcl_mapgen/init.lua | 31 +++++++++++++---------- mods/MAPGEN/mcl_structures/structures.lua | 2 +- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/mods/CORE/mcl_mapgen/init.lua b/mods/CORE/mcl_mapgen/init.lua index 7076c5be8..0edaffc38 100644 --- a/mods/CORE/mcl_mapgen/init.lua +++ b/mods/CORE/mcl_mapgen/init.lua @@ -31,6 +31,8 @@ mcl_mapgen.LAST_NODE_IN_BLOCK = mcl_mapgen.BS - 1 mcl_mapgen.LAST_NODE_IN_CHUNK = mcl_mapgen.CS_NODES - 1 mcl_mapgen.HALF_CS_NODES = math_floor(mcl_mapgen.CS_NODES / 2) mcl_mapgen.CS_3D = mcl_mapgen.CS^3 +mcl_mapgen.CHUNK_WITH_SHELL = mcl_mapgen.CS + 2 +mcl_mapgen.CHUNK_WITH_SHELL_3D = mcl_mapgen.CHUNK_WITH_SHELL^3 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 @@ -90,6 +92,8 @@ local LAST_NODE_IN_BLOCK = mcl_mapgen.LAST_NODE_IN_BLOCK local LAST_NODE_IN_CHUNK = mcl_mapgen.LAST_NODE_IN_CHUNK local HALF_CS_NODES = mcl_mapgen.HALF_CS_NODES local CS_3D = mcl_mapgen.CS_3D +local CHUNK_WITH_SHELL = mcl_mapgen.CHUNK_WITH_SHELL +local CHUNK_WITH_SHELL_3D = mcl_mapgen.CHUNK_WITH_SHELL_3D local DEFAULT_ORDER = order.DEFAULT @@ -129,18 +133,18 @@ local data, param2_data, light, area local lvm_buffer, lvm_param2_buffer, lvm_light_buffer = {}, {}, {} -- Static buffer pointers local all_blocks_in_chunk = {} -for x = 0, CS-1 do - for y = 0, CS-1 do - for z = 0, CS-1 do - all_blocks_in_chunk[CS * (CS * x + y) + z] = vector.new(x, y, z) +for x = -1, LAST_BLOCK+1 do + for y = -1, LAST_BLOCK+1 do + for z = -1, LAST_BLOCK+1 do + all_blocks_in_chunk[CHUNK_WITH_SHELL * (CHUNK_WITH_SHELL * y + z) + x] = vector.new(x, y, z) end end end local chunk_scan_range = { - [-CS_NODES] = {0 , 0 }, - [ 0 ] = {0 , LAST_BLOCK}, - [ CS_NODES] = {LAST_BLOCK, LAST_BLOCK}, + [-CS_NODES] = {-1 , -1 }, + [ 0 ] = {-1 , LAST_BLOCK+1}, + [ CS_NODES] = {LAST_BLOCK+1, LAST_BLOCK+1}, } local function is_chunk_finished(minp) @@ -159,6 +163,7 @@ local function is_chunk_finished(minp) end end end + return true end local function unsigned(v) @@ -193,7 +198,7 @@ end minetest.register_on_generated(function(minp, maxp, chunkseed) local minp, maxp, chunkseed = minp, maxp, chunkseed 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) .. ", shell=" .. minetest_pos_to_string(emin) .. "..." .. minetest_pos_to_string(emax) .. ", chunkseed=" .. tostring(chunkseed)) + minetest_log("action", "[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) .. ", chunkseed=" .. tostring(chunkseed)) data = vm:get_data(lvm_buffer) area = VoxelArea:new({MinEdge=emin, MaxEdge=emax}) @@ -240,7 +245,7 @@ minetest.register_on_generated(function(minp, maxp, chunkseed) for cut_y = scan_range_y[1], scan_range_y[2] do local scan_range_z = chunk_scan_range[z] for cut_z = scan_range_z[1], scan_range_z[2] do - ready_blocks[CS * (CS * cut_x + cut_y) + cut_z] = nil + ready_blocks[CHUNK_WITH_SHELL * (CHUNK_WITH_SHELL * cut_y + cut_z) + cut_x] = nil end end end @@ -268,7 +273,7 @@ minetest.register_on_generated(function(minp, maxp, chunkseed) end number_of_blocks = number_of_blocks + 1 end - if number_of_blocks == CS_3D then + if number_of_blocks == CHUNK_WITH_SHELL_3D then current_chunks[#current_chunks + 1] = p0 end end @@ -291,7 +296,7 @@ minetest.register_on_generated(function(minp, maxp, chunkseed) vm:set_light_data(light) end if vm_context.write or vm_context.write_param2 or vm_context.write_light then - vm:calc_lighting(minp, maxp, (vm_context.shadow ~= nil) or true) -- TODO: check boundaries + vm:calc_lighting(minp, maxp, (vm_context.shadow ~= nil) or true) vm:write_to_map() vm:update_liquids() elseif vm_context.calc_lighting then @@ -300,7 +305,7 @@ minetest.register_on_generated(function(minp, maxp, chunkseed) end for i, chunk_minp in pairs(current_chunks) do - local chunk_maxp = chunk_minp + LAST_NODE_IN_CHUNK + local chunk_maxp = vector.add(chunk_minp, LAST_NODE_IN_CHUNK) local chunkseed = getBlockSeed2(chunk_minp) area = VoxelArea:new({MinEdge=minp, MaxEdge=maxp}) vm_context = { @@ -327,7 +332,7 @@ minetest.register_on_generated(function(minp, maxp, chunkseed) -- mcl_mapgen.register_mapgen(function(minp, maxp, chunkseed, vm_context), order_number) -- -- -- for _, v in pairs(queue_chunks_nodes) do - v.f(minp, maxp, seed, vm_context) + v.f(chunk_minp, chunk_maxp, chunkseed, vm_context) end if vm_context.write or vm_context.write_param2 or vm_context.write_light then if vm_context.write then diff --git a/mods/MAPGEN/mcl_structures/structures.lua b/mods/MAPGEN/mcl_structures/structures.lua index b18904d9a..fd6b21b26 100644 --- a/mods/MAPGEN/mcl_structures/structures.lua +++ b/mods/MAPGEN/mcl_structures/structures.lua @@ -11,7 +11,7 @@ if not mcl_mapgen.singlenode then dofile(modpath .. "/ice_spike_large.lua") dofile(modpath .. "/jungle_temple.lua") dofile(modpath .. "/nice_jungle_temple.lua") - dofile(modpath .. "/noise_indicator.lua") + -- dofile(modpath .. "/noise_indicator.lua") dofile(modpath .. "/stronghold.lua") dofile(modpath .. "/witch_hut.lua") end From 24dec437e5868b1e49070661a6cd6fd139de6b9e Mon Sep 17 00:00:00 2001 From: kay27 Date: Fri, 4 Feb 2022 20:28:04 +0400 Subject: [PATCH 5/5] #123 Make latest mapgen changes compatible with 5.4 --- mods/CORE/mcl_compatibility/init.lua | 92 +++++++ mods/CORE/mcl_compatibility/mod.conf | 3 + mods/CORE/mcl_compatibility/vector.lua | 362 +++++++++++++++++++++++++ mods/CORE/mcl_init/compatibility.lua | 76 +----- mods/CORE/mcl_init/init.lua | 6 +- mods/CORE/mcl_init/mod.conf | 1 + 6 files changed, 460 insertions(+), 80 deletions(-) create mode 100644 mods/CORE/mcl_compatibility/init.lua create mode 100644 mods/CORE/mcl_compatibility/mod.conf create mode 100644 mods/CORE/mcl_compatibility/vector.lua diff --git a/mods/CORE/mcl_compatibility/init.lua b/mods/CORE/mcl_compatibility/init.lua new file mode 100644 index 000000000..1ca6fc5ef --- /dev/null +++ b/mods/CORE/mcl_compatibility/init.lua @@ -0,0 +1,92 @@ +mcl_compatibility = mcl_compatibility or {} +mcl_vars = mcl_vars or {} + +local modname = minetest.get_current_modname() +local modpath = minetest.get_modpath(modname) + +function math.round(x) + if x >= 0 then + return math.floor(x + 0.5) + end + return math.ceil(x - 0.5) +end + +dofile(modpath .. "/vector.lua") + +local minetest_get_node = minetest.get_node + +mcl_compatibility.sort_nodes = function(nodes) + if not nodes then return {} end + for _, pos in pairs(nodes) do + if not pos.x or not pos.y or not pos.z then + return nodes + end + end + local new_nodes = {} + for _, pos in pairs(nodes) do + local node = minetest_get_node(pos) + local name = node.name + if not new_nodes[name] then + new_nodes[name] = { pos } + else + table.insert(new_nodes[name], pos) + end + end + return new_nodes +end + +local minetest_find_nodes_in_area = minetest.find_nodes_in_area +minetest.find_nodes_in_area = function(pos1, pos2, nodenames, grouped) + local nodes, num = minetest_find_nodes_in_area(pos1, pos2, nodenames, grouped) + if not grouped or not nodes or next(nodes) == nil then + return nodes, num + end + return mcl_compatibility.sort_nodes(nodes) +end + +function mcl_vars.pos_to_block(pos) + return mcl_mapgen and mcl_mapgen.pos_to_block(pos) +end + +function mcl_vars.pos_to_chunk(pos) + return mcl_mapgen and mcl_mapgen.pos_to_chunk(pos) +end + +function mcl_vars.get_chunk_number(pos) + return mcl_mapgen and get_chunk_number(pos) +end + +function mcl_vars.is_generated(pos) + local node = minetest.get_node(pos) + if not node then return false end + if node.name == "ignore" then return false end + return true +end + +function mcl_vars.get_node(p, force, us_timeout) + if not p or not p.x or not p.y or not p.z then return {name="error"} end + 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(pos) +end + +mcl_vars.mg_overworld_min = -62 +mcl_vars.mg_overworld_max_official = 198 +mcl_vars.mg_bedrock_overworld_min = -62 +mcl_vars.mg_bedrock_overworld_max = -58 +mcl_vars.mg_lava_overworld_max = -52 +mcl_vars.mg_lava = true +mcl_vars.mg_bedrock_is_rough = true +mcl_vars.mg_overworld_max = 30927 +mcl_vars.mg_nether_min = -29067 +mcl_vars.mg_nether_max = -28939 +mcl_vars.mg_bedrock_nether_bottom_min = -29067 +mcl_vars.mg_bedrock_nether_top_max = -29063 +mcl_vars.mg_end_min = -27073 +mcl_vars.mg_end_max_official = -26817 +mcl_vars.mg_end_max = -2062 +mcl_vars.mg_end_platform_pos = { x = 100, y = -26999, z = 0 } +mcl_vars.mg_realm_barrier_overworld_end_max = -2062 +mcl_vars.mg_realm_barrier_overworld_end_min = -2073 +mcl_vars.mg_dungeons = true diff --git a/mods/CORE/mcl_compatibility/mod.conf b/mods/CORE/mcl_compatibility/mod.conf new file mode 100644 index 000000000..b56060ca4 --- /dev/null +++ b/mods/CORE/mcl_compatibility/mod.conf @@ -0,0 +1,3 @@ +name = mcl_compatibility +author = kay27, minetest devs +description = Makes MineClone 5 run in old versions of Minetest and be compatible with mods using old MineClone APIs diff --git a/mods/CORE/mcl_compatibility/vector.lua b/mods/CORE/mcl_compatibility/vector.lua new file mode 100644 index 000000000..581d014e0 --- /dev/null +++ b/mods/CORE/mcl_compatibility/vector.lua @@ -0,0 +1,362 @@ +--[[ +Vector helpers +Note: The vector.*-functions must be able to accept old vectors that had no metatables +]] + +-- localize functions +local setmetatable = setmetatable + +vector = {} + +local metatable = {} +vector.metatable = metatable + +local xyz = {"x", "y", "z"} + +-- only called when rawget(v, key) returns nil +function metatable.__index(v, key) + return rawget(v, xyz[key]) or vector[key] +end + +-- only called when rawget(v, key) returns nil +function metatable.__newindex(v, key, value) + rawset(v, xyz[key] or key, value) +end + +-- constructors + +local function fast_new(x, y, z) + return setmetatable({x = x, y = y, z = z}, metatable) +end + +function vector.new(a, b, c) + if a and b and c then + return fast_new(a, b, c) + end + + -- deprecated, use vector.copy and vector.zero directly + if type(a) == "table" then + return vector.copy(a) + else + assert(not a, "Invalid arguments for vector.new()") + return vector.zero() + end +end + +function vector.zero() + return fast_new(0, 0, 0) +end + +function vector.copy(v) + assert(v.x and v.y and v.z, "Invalid vector passed to vector.copy()") + return fast_new(v.x, v.y, v.z) +end + +function vector.from_string(s, init) + local x, y, z, np = string.match(s, "^%s*%(%s*([^%s,]+)%s*[,%s]%s*([^%s,]+)%s*[,%s]" .. + "%s*([^%s,]+)%s*[,%s]?%s*%)()", init) + x = tonumber(x) + y = tonumber(y) + z = tonumber(z) + if not (x and y and z) then + return nil + end + return fast_new(x, y, z), np +end + +function vector.to_string(v) + return string.format("(%g, %g, %g)", v.x, v.y, v.z) +end +metatable.__tostring = vector.to_string + +function vector.equals(a, b) + return a.x == b.x and + a.y == b.y and + a.z == b.z +end +metatable.__eq = vector.equals + +-- unary operations + +function vector.length(v) + return math.sqrt(v.x * v.x + v.y * v.y + v.z * v.z) +end +-- Note: we can not use __len because it is already used for primitive table length + +function vector.normalize(v) + local len = vector.length(v) + if len == 0 then + return fast_new(0, 0, 0) + else + return vector.divide(v, len) + end +end + +function vector.floor(v) + return vector.apply(v, math.floor) +end + +function vector.round(v) + return fast_new( + math.round(v.x), + math.round(v.y), + math.round(v.z) + ) +end + +function vector.apply(v, func) + return fast_new( + func(v.x), + func(v.y), + func(v.z) + ) +end + +function vector.distance(a, b) + local x = a.x - b.x + local y = a.y - b.y + local z = a.z - b.z + return math.sqrt(x * x + y * y + z * z) +end + +function vector.direction(pos1, pos2) + return vector.subtract(pos2, pos1):normalize() +end + +function vector.angle(a, b) + local dotp = vector.dot(a, b) + local cp = vector.cross(a, b) + local crossplen = vector.length(cp) + return math.atan2(crossplen, dotp) +end + +function vector.dot(a, b) + return a.x * b.x + a.y * b.y + a.z * b.z +end + +function vector.cross(a, b) + return fast_new( + a.y * b.z - a.z * b.y, + a.z * b.x - a.x * b.z, + a.x * b.y - a.y * b.x + ) +end + +function metatable.__unm(v) + return fast_new(-v.x, -v.y, -v.z) +end + +-- add, sub, mul, div operations + +function vector.add(a, b) + if type(b) == "table" then + return fast_new( + a.x + b.x, + a.y + b.y, + a.z + b.z + ) + else + return fast_new( + a.x + b, + a.y + b, + a.z + b + ) + end +end +function metatable.__add(a, b) + return fast_new( + a.x + b.x, + a.y + b.y, + a.z + b.z + ) +end + +function vector.subtract(a, b) + if type(b) == "table" then + return fast_new( + a.x - b.x, + a.y - b.y, + a.z - b.z + ) + else + return fast_new( + a.x - b, + a.y - b, + a.z - b + ) + end +end +function metatable.__sub(a, b) + return fast_new( + a.x - b.x, + a.y - b.y, + a.z - b.z + ) +end + +function vector.multiply(a, b) + if type(b) == "table" then + return fast_new( + a.x * b.x, + a.y * b.y, + a.z * b.z + ) + else + return fast_new( + a.x * b, + a.y * b, + a.z * b + ) + end +end +function metatable.__mul(a, b) + if type(a) == "table" then + return fast_new( + a.x * b, + a.y * b, + a.z * b + ) + else + return fast_new( + a * b.x, + a * b.y, + a * b.z + ) + end +end + +function vector.divide(a, b) + if type(b) == "table" then + return fast_new( + a.x / b.x, + a.y / b.y, + a.z / b.z + ) + else + return fast_new( + a.x / b, + a.y / b, + a.z / b + ) + end +end +function metatable.__div(a, b) + -- scalar/vector makes no sense + return fast_new( + a.x / b, + a.y / b, + a.z / b + ) +end + +-- misc stuff + +function vector.offset(v, x, y, z) + return fast_new( + v.x + x, + v.y + y, + v.z + z + ) +end + +function vector.sort(a, b) + return fast_new(math.min(a.x, b.x), math.min(a.y, b.y), math.min(a.z, b.z)), + fast_new(math.max(a.x, b.x), math.max(a.y, b.y), math.max(a.z, b.z)) +end + +function vector.check(v) + return getmetatable(v) == metatable +end + +local function sin(x) + if x % math.pi == 0 then + return 0 + else + return math.sin(x) + end +end + +local function cos(x) + if x % math.pi == math.pi / 2 then + return 0 + else + return math.cos(x) + end +end + +function vector.rotate_around_axis(v, axis, angle) + local cosangle = cos(angle) + local sinangle = sin(angle) + axis = vector.normalize(axis) + -- https://en.wikipedia.org/wiki/Rodrigues%27_rotation_formula + local dot_axis = vector.multiply(axis, vector.dot(axis, v)) + local cross = vector.cross(v, axis) + return vector.new( + cross.x * sinangle + (v.x - dot_axis.x) * cosangle + dot_axis.x, + cross.y * sinangle + (v.y - dot_axis.y) * cosangle + dot_axis.y, + cross.z * sinangle + (v.z - dot_axis.z) * cosangle + dot_axis.z + ) +end + +function vector.rotate(v, rot) + local sinpitch = sin(-rot.x) + local sinyaw = sin(-rot.y) + local sinroll = sin(-rot.z) + local cospitch = cos(rot.x) + local cosyaw = cos(rot.y) + local cosroll = math.cos(rot.z) + -- Rotation matrix that applies yaw, pitch and roll + local matrix = { + { + sinyaw * sinpitch * sinroll + cosyaw * cosroll, + sinyaw * sinpitch * cosroll - cosyaw * sinroll, + sinyaw * cospitch, + }, + { + cospitch * sinroll, + cospitch * cosroll, + -sinpitch, + }, + { + cosyaw * sinpitch * sinroll - sinyaw * cosroll, + cosyaw * sinpitch * cosroll + sinyaw * sinroll, + cosyaw * cospitch, + }, + } + -- Compute matrix multiplication: `matrix` * `v` + return vector.new( + matrix[1][1] * v.x + matrix[1][2] * v.y + matrix[1][3] * v.z, + matrix[2][1] * v.x + matrix[2][2] * v.y + matrix[2][3] * v.z, + matrix[3][1] * v.x + matrix[3][2] * v.y + matrix[3][3] * v.z + ) +end + +function vector.dir_to_rotation(forward, up) + forward = vector.normalize(forward) + local rot = vector.new(math.asin(forward.y), -math.atan2(forward.x, forward.z), 0) + if not up then + return rot + end + assert(vector.dot(forward, up) < 0.000001, + "Invalid vectors passed to vector.dir_to_rotation().") + up = vector.normalize(up) + -- Calculate vector pointing up with roll = 0, just based on forward vector. + local forwup = vector.rotate(vector.new(0, 1, 0), rot) + -- 'forwup' and 'up' are now in a plane with 'forward' as normal. + -- The angle between them is the absolute of the roll value we're looking for. + rot.z = vector.angle(forwup, up) + + -- Since vector.angle never returns a negative value or a value greater + -- than math.pi, rot.z has to be inverted sometimes. + -- To determine wether this is the case, we rotate the up vector back around + -- the forward vector and check if it worked out. + local back = vector.rotate_around_axis(up, forward, -rot.z) + + -- We don't use vector.equals for this because of floating point imprecision. + if (back.x - forwup.x) * (back.x - forwup.x) + + (back.y - forwup.y) * (back.y - forwup.y) + + (back.z - forwup.z) * (back.z - forwup.z) > 0.0000001 then + rot.z = -rot.z + end + return rot +end diff --git a/mods/CORE/mcl_init/compatibility.lua b/mods/CORE/mcl_init/compatibility.lua index aed291f16..3f1347181 100644 --- a/mods/CORE/mcl_init/compatibility.lua +++ b/mods/CORE/mcl_init/compatibility.lua @@ -1,75 +1 @@ -mcl_compatibility = {} - -function vector.offset(v,x,y,z) - return vector.add(v,{x=x,y=y,z=z}) -end - -local minetest_get_node = minetest.get_node - -mcl_compatibility.sort_nodes = function(nodes) - if not nodes then return {} end - for _, pos in pairs(nodes) do - if not pos.x or not pos.y or not pos.z then - return nodes - end - end - local new_nodes = {} - for _, pos in pairs(nodes) do - local node = minetest_get_node(pos) - local name = node.name - if not new_nodes[name] then - new_nodes[name] = { pos } - else - table.insert(new_nodes[name], pos) - end - end - return new_nodes -end - -function mcl_vars.pos_to_block(pos) - return mcl_mapgen and mcl_mapgen.pos_to_block(pos) -end - -function mcl_vars.pos_to_chunk(pos) - return mcl_mapgen and mcl_mapgen.pos_to_chunk(pos) -end - -function mcl_vars.get_chunk_number(pos) - return mcl_mapgen and get_chunk_number(pos) -end - -function mcl_vars.is_generated(pos) - local node = minetest.get_node(pos) - if not node then return false end - if node.name == "ignore" then return false end - return true -end - -function mcl_vars.get_node(p, force, us_timeout) - if not p or not p.x or not p.y or not p.z then return {name="error"} end - 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(pos) -end - -mcl_vars.mg_overworld_min = -62 -mcl_vars.mg_overworld_max_official = 198 -mcl_vars.mg_bedrock_overworld_min = -62 -mcl_vars.mg_bedrock_overworld_max = -58 -mcl_vars.mg_lava_overworld_max = -52 -mcl_vars.mg_lava = true -mcl_vars.mg_bedrock_is_rough = true -mcl_vars.mg_overworld_max = 30927 -mcl_vars.mg_nether_min = -29067 -mcl_vars.mg_nether_max = -28939 -mcl_vars.mg_bedrock_nether_bottom_min = -29067 -mcl_vars.mg_bedrock_nether_top_max = -29063 -mcl_vars.mg_end_min = -27073 -mcl_vars.mg_end_max_official = -26817 -mcl_vars.mg_end_max = -2062 -mcl_vars.mg_end_platform_pos = { x = 100, y = -26999, z = 0 } -mcl_vars.mg_realm_barrier_overworld_end_max = -2062 -mcl_vars.mg_realm_barrier_overworld_end_min = -2073 -mcl_vars.mg_dungeons = true - +-- moved to mcl_compatibility diff --git a/mods/CORE/mcl_init/init.lua b/mods/CORE/mcl_init/init.lua index 4e5b5b675..17945b472 100644 --- a/mods/CORE/mcl_init/init.lua +++ b/mods/CORE/mcl_init/init.lua @@ -1,5 +1,5 @@ -- Some global variables (don't overwrite them!) -mcl_vars = {} +mcl_vars = mcl_vars or {} mcl_vars.redstone_tick = 0.1 @@ -30,7 +30,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 modname = minetest.get_current_modname() -local modpath = minetest.get_modpath(modname) -dofile(modpath .. "/compatibility.lua") diff --git a/mods/CORE/mcl_init/mod.conf b/mods/CORE/mcl_init/mod.conf index a0e810a2f..5bf2fad76 100644 --- a/mods/CORE/mcl_init/mod.conf +++ b/mods/CORE/mcl_init/mod.conf @@ -1,3 +1,4 @@ name = mcl_init +depends = mcl_compatibility author = Wuzzy description = Initialization mod of MineClone 2. Defines some common shared variables and sets up initial default settings which have to be set at the beginning.