Merge pull request 'Release 1.4' (#164) from compatibility into production-compatible

Reviewed-on: MineClone5/MineClone5#164
This commit is contained in:
kay27 2022-02-04 19:50:01 +00:00
commit 697d8396dd
8 changed files with 623 additions and 231 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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")

View File

@ -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.

View File

@ -22,10 +22,17 @@ local minetest_pos_to_string = minetest.pos_to_string
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.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
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
@ -78,11 +85,15 @@ 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 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 CHUNK_WITH_SHELL = mcl_mapgen.CHUNK_WITH_SHELL
local CHUNK_WITH_SHELL_3D = mcl_mapgen.CHUNK_WITH_SHELL_3D
local DEFAULT_ORDER = order.DEFAULT
@ -117,24 +128,77 @@ 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 = -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] = {-1 , -1 },
[ 0 ] = {-1 , LAST_BLOCK+1},
[ CS_NODES] = {LAST_BLOCK+1, LAST_BLOCK+1},
}
local function is_chunk_finished(minp)
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
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
return true
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")
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})
@ -154,117 +218,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}
local ready_blocks = table.copy(all_blocks_in_chunk)
local p0 = vector.new(minp)
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
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[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
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[CHUNK_WITH_SHELL * (CHUNK_WITH_SHELL * cut_y + cut_z) + cut_x] = nil
end
end
local blockseed = seed + bx * 7 + by * 243 + bz * 11931
end
end
end
end
end
end
local number_of_blocks = 0
for k, offset in pairs(ready_blocks) do
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}
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
-- --
-- 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
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 }
current_blocks[#current_blocks + 1] = { minp = block_minp, maxp = block_maxp, seed = blockseed }
end
else
blocks[bx][by][bz] = current_mapgen_block_writes
end
z = z + BS
number_of_blocks = number_of_blocks + 1
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
if number_of_blocks == CHUNK_WITH_SHELL_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
@ -278,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
@ -286,12 +304,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 = vector.add(chunk_minp, LAST_NODE_IN_CHUNK)
local chunkseed = getBlockSeed2(chunk_minp)
area = VoxelArea:new({MinEdge=minp, MaxEdge=maxp})
vm_context = {
data = data,
@ -301,17 +316,23 @@ 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)
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
@ -330,14 +351,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 +413,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

View File

@ -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