2017-02-17 23:06:52 +01:00
-- Some global variables (don't overwrite them!)
mcl_vars = { }
2024-05-22 07:23:43 +02:00
minetest.log ( " action " , " World seed = " .. minetest.get_mapgen_setting ( " seed " ) )
2020-11-13 22:59:03 +01:00
mcl_vars.redstone_tick = 0.1
2022-10-25 00:31:26 +02:00
-- GUI / inventory menu settings
2019-03-07 12:42:08 +01:00
mcl_vars.gui_slots = " listcolors[#9990;#FFF7;#FFF0;#000;#FFF] "
2022-10-25 00:31:26 +02:00
2019-03-07 13:05:26 +01:00
-- nonbg is added as formspec prepend in mcl_formspec_prepend
2022-10-25 00:31:26 +02:00
mcl_vars.gui_nonbg = table.concat ( {
mcl_vars.gui_slots ,
" style_type[image_button;border=false;bgimg=mcl_inventory_button9.png;bgimg_pressed=mcl_inventory_button9_pressed.png;bgimg_middle=2,2] " ,
" style_type[button;border=false;bgimg=mcl_inventory_button9.png;bgimg_pressed=mcl_inventory_button9_pressed.png;bgimg_middle=2,2] " ,
" style_type[field;textcolor=#323232] " ,
" style_type[label;textcolor=#323232] " ,
" style_type[textarea;textcolor=#323232] " ,
" style_type[checkbox;textcolor=#323232] " ,
} )
2019-03-07 13:05:26 +01:00
-- Background stuff must be manually added by mods (no formspec prepend)
2020-03-10 05:01:49 +01:00
mcl_vars.gui_bg_color = " bgcolor[#00000000] "
mcl_vars.gui_bg_img = " background9[1,1;1,1;mcl_base_textures_background9.png;true;7] "
2019-03-07 12:42:08 +01:00
2021-04-05 10:16:56 +02:00
-- Tool wield size
2022-10-25 00:31:26 +02:00
mcl_vars.tool_wield_scale = vector.new ( 1.8 , 1.8 , 1 )
2021-04-05 10:16:56 +02:00
2017-03-04 23:00:23 +01:00
-- Mapgen variables
2017-02-23 00:15:47 +01:00
local mg_name = minetest.get_mapgen_setting ( " mg_name " )
2024-06-14 15:10:03 +02:00
local minecraft_height_limit = 320
2019-02-09 02:42:11 +01:00
local superflat = mg_name == " flat " and minetest.get_mapgen_setting ( " mcl_superflat_classic " ) == " true "
2021-01-26 03:23:38 +01:00
local singlenode = mg_name == " singlenode "
2019-02-09 02:42:11 +01:00
2020-09-26 00:17:49 +02:00
-- Calculate mapgen_edge_min/mapgen_edge_max
mcl_vars.chunksize = math.max ( 1 , tonumber ( minetest.get_mapgen_setting ( " chunksize " ) ) or 5 )
2021-06-12 00:18:52 +02:00
mcl_vars.MAP_BLOCKSIZE = math.max ( 1 , minetest.MAP_BLOCKSIZE or 16 )
2020-09-26 00:17:49 +02:00
mcl_vars.mapgen_limit = math.max ( 1 , tonumber ( minetest.get_mapgen_setting ( " mapgen_limit " ) ) or 31000 )
2021-06-12 00:18:52 +02:00
mcl_vars.MAX_MAP_GENERATION_LIMIT = math.max ( 1 , minetest.MAX_MAP_GENERATION_LIMIT or 31000 )
2022-10-25 00:31:26 +02:00
2024-03-31 04:20:23 +02:00
-- Central chunk is offset from 0,0,0 coordinates by 32 nodes (2 blocks)
2024-05-07 09:11:56 +02:00
-- See more in https://git.minetest.land/VoxeLibre/VoxeLibre/wiki/World-structure%3A-positions%2C-boundaries%2C-blocks%2C-chunks%2C-dimensions%2C-barriers-and-the-void
2020-09-26 00:17:49 +02:00
local central_chunk_offset = - math.floor ( mcl_vars.chunksize / 2 )
2022-10-25 00:31:26 +02:00
2021-03-22 00:14:33 +01:00
mcl_vars.central_chunk_offset_in_nodes = central_chunk_offset * mcl_vars.MAP_BLOCKSIZE
mcl_vars.chunk_size_in_nodes = mcl_vars.chunksize * mcl_vars.MAP_BLOCKSIZE
2022-10-25 00:31:26 +02:00
2020-09-26 00:17:49 +02:00
local central_chunk_min_pos = central_chunk_offset * mcl_vars.MAP_BLOCKSIZE
2021-03-22 00:14:33 +01:00
local central_chunk_max_pos = central_chunk_min_pos + mcl_vars.chunk_size_in_nodes - 1
2020-09-26 00:17:49 +02:00
local ccfmin = central_chunk_min_pos - mcl_vars.MAP_BLOCKSIZE -- Fullminp/fullmaxp of central chunk, in nodes
local ccfmax = central_chunk_max_pos + mcl_vars.MAP_BLOCKSIZE
2022-10-25 00:31:26 +02:00
local mapgen_limit_b = math.floor ( math.min ( mcl_vars.mapgen_limit , mcl_vars.MAX_MAP_GENERATION_LIMIT ) /
mcl_vars.MAP_BLOCKSIZE )
2020-09-26 00:17:49 +02:00
local mapgen_limit_min = - mapgen_limit_b * mcl_vars.MAP_BLOCKSIZE
local mapgen_limit_max = ( mapgen_limit_b + 1 ) * mcl_vars.MAP_BLOCKSIZE - 1
2021-03-22 00:14:33 +01:00
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.
2022-10-25 00:31:26 +02:00
2021-03-22 00:14:33 +01:00
mcl_vars.mapgen_edge_min = central_chunk_min_pos - numcmin * mcl_vars.chunk_size_in_nodes
mcl_vars.mapgen_edge_max = central_chunk_max_pos + numcmax * mcl_vars.chunk_size_in_nodes
2020-09-26 00:17:49 +02:00
2022-10-25 00:31:26 +02:00
---@param x integer
---@return integer
2021-02-22 00:15:32 +01:00
local function coordinate_to_block ( x )
return math.floor ( x / mcl_vars.MAP_BLOCKSIZE )
end
2022-10-25 00:31:26 +02:00
---@param x integer
---@return integer
2021-02-22 00:15:32 +01:00
local function coordinate_to_chunk ( x )
2021-03-22 00:14:33 +01:00
return math.floor ( ( coordinate_to_block ( x ) - central_chunk_offset ) / mcl_vars.chunksize )
2021-02-22 00:15:32 +01:00
end
2022-10-25 00:31:26 +02:00
---@param pos Vector
---@return Vector
2021-02-22 00:15:32 +01:00
function mcl_vars . pos_to_block ( pos )
2022-10-25 00:31:26 +02:00
return vector.new (
coordinate_to_block ( pos.x ) ,
coordinate_to_block ( pos.y ) ,
coordinate_to_block ( pos.z )
)
2021-02-22 00:15:32 +01:00
end
2022-10-25 00:31:26 +02:00
---@param pos Vector
---@return Vector
2021-02-22 00:15:32 +01:00
function mcl_vars . pos_to_chunk ( pos )
2022-10-25 00:31:26 +02:00
return vector.new (
coordinate_to_chunk ( pos.x ) ,
coordinate_to_chunk ( pos.y ) ,
coordinate_to_chunk ( pos.z )
)
2021-02-22 00:15:32 +01:00
end
2021-03-22 00:14:33 +01:00
local k_positive = math.ceil ( mcl_vars.MAX_MAP_GENERATION_LIMIT / mcl_vars.chunk_size_in_nodes )
2021-02-22 00:15:32 +01:00
local k_positive_z = k_positive * 2
local k_positive_y = k_positive_z * k_positive_z
2022-10-25 00:31:26 +02:00
---@param pos Vector
---@return integer
2021-02-22 00:15:32 +01:00
function mcl_vars . get_chunk_number ( pos ) -- unsigned int
local c = mcl_vars.pos_to_chunk ( pos )
2022-10-25 00:31:26 +02:00
return ( c.y + k_positive ) * k_positive_y +
2021-02-22 00:15:32 +01:00
( c.z + k_positive ) * k_positive_z +
2022-10-25 00:31:26 +02:00
c.x + k_positive
2021-02-22 00:15:32 +01:00
end
2021-01-26 03:23:38 +01:00
if not superflat and not singlenode then
2019-02-09 02:42:11 +01:00
-- Normal mode
2017-08-16 15:29:05 +02:00
--[[ 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 )
] ]
2017-03-04 23:00:23 +01:00
2017-08-16 15:29:05 +02:00
-- Overworld
2024-06-14 15:10:03 +02:00
mcl_vars.mg_overworld_min = - 64
2017-08-16 15:29:05 +02:00
mcl_vars.mg_overworld_max_official = mcl_vars.mg_overworld_min + minecraft_height_limit
2017-03-04 23:00:23 +01:00
mcl_vars.mg_bedrock_overworld_min = mcl_vars.mg_overworld_min
mcl_vars.mg_bedrock_overworld_max = mcl_vars.mg_bedrock_overworld_min + 4
2017-05-20 01:27:09 +02:00
mcl_vars.mg_lava_overworld_max = mcl_vars.mg_overworld_min + 10
mcl_vars.mg_lava = true
2017-03-04 23:00:23 +01:00
mcl_vars.mg_bedrock_is_rough = true
2017-08-16 15:29:05 +02:00
2021-01-26 03:23:38 +01:00
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
2017-02-23 00:15:47 +01:00
else
2019-02-09 02:42:11 +01:00
-- Classic superflat
2022-10-25 00:31:26 +02:00
local ground = tonumber ( minetest.get_mapgen_setting ( " mgflat_ground_level " ) ) or 8
2019-02-09 02:42:11 +01:00
mcl_vars.mg_overworld_min = ground - 3
2017-08-16 15:29:05 +02:00
mcl_vars.mg_overworld_max_official = mcl_vars.mg_overworld_min + minecraft_height_limit
2017-05-27 16:10:21 +02:00
mcl_vars.mg_bedrock_overworld_min = mcl_vars.mg_overworld_min
2017-03-04 23:00:23 +01:00
mcl_vars.mg_bedrock_overworld_max = mcl_vars.mg_bedrock_overworld_min
2017-05-20 01:27:09 +02:00
mcl_vars.mg_lava = false
2017-08-21 17:46:12 +02:00
mcl_vars.mg_lava_overworld_max = mcl_vars.mg_overworld_min
2017-03-04 23:00:23 +01:00
mcl_vars.mg_bedrock_is_rough = false
2017-02-23 00:15:47 +01:00
end
2017-02-20 07:10:03 +01:00
2021-02-22 00:15:32 +01:00
mcl_vars.mg_overworld_max = mcl_vars.mapgen_edge_max
2017-08-16 15:29:05 +02:00
2017-08-21 17:35:02 +02:00
-- The Nether (around Y = -29000)
mcl_vars.mg_nether_min = - 29067 -- Carefully chosen to be at a mapchunk border
2017-08-16 15:29:05 +02:00
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
2022-10-27 19:34:58 +02:00
mcl_vars.mg_nether_deco_max = mcl_vars.mg_nether_max - 11 -- this is so ceiling decorations don't spill into other biomes as bedrock generation calls minetest.generate_decorations to put netherrack under the bedrock
2019-02-09 02:42:11 +01:00
if not superflat then
2017-08-30 01:09:49 +02:00
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
2019-02-09 02:42:11 +01:00
mcl_vars.mg_lava_nether_max = mcl_vars.mg_nether_min + 31
2017-08-30 01:09:49 +02:00
else
2019-02-09 02:42:11 +01:00
-- Thin bedrock in classic superflat mapgen
2017-08-30 01:09:49 +02:00
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
2019-02-09 02:42:11 +01:00
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
2017-08-30 01:09:49 +02:00
end
2017-08-16 15:29:05 +02:00
2017-08-21 17:35:02 +02:00
-- The End (surface at ca. Y = -27000)
mcl_vars.mg_end_min = - 27073 -- Carefully chosen to be at a mapchunk border
2017-08-16 15:29:05 +02:00
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
2022-09-13 19:49:08 +02:00
mcl_vars.mg_end_platform_pos = { x = 100 , y = mcl_vars.mg_end_min + 64 , z = 0 }
2022-09-11 02:51:47 +02:00
mcl_vars.mg_end_exit_portal_pos = vector.new ( 0 , mcl_vars.mg_end_min + 71 , 0 )
2017-11-21 05:39:27 +01:00
2017-08-17 19:59:43 +02:00
-- 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
2017-08-16 15:29:05 +02:00
2024-05-02 06:04:41 +02:00
-- Use VoxeLibre-style dungeons
2020-06-16 02:33:51 +02:00
mcl_vars.mg_dungeons = true
2017-02-17 23:06:52 +01:00
-- Set default stack sizes
minetest.nodedef_default . stack_max = 64
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 ( ) )
2021-01-26 03:23:38 +01:00
2021-03-28 20:56:51 +02:00
local chunks = { } -- intervals of chunks generated
2022-10-25 00:31:26 +02:00
---@param pos Vector
2021-03-28 20:56:51 +02:00
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
2022-10-25 00:31:26 +02:00
if n == d [ 1 ] - 1 then -- right before:
if prev and ( prev [ 2 ] == n - 1 ) then
2021-03-28 20:56:51 +02:00
prev [ 2 ] = d [ 2 ]
table.remove ( chunks , i )
return
end
d [ 1 ] = n
return
end
2022-10-25 00:31:26 +02:00
if prev and ( prev [ 2 ] == n - 1 ) then --join to previous
2021-03-28 20:56:51 +02:00
prev [ 2 ] = n
return
end
2022-10-25 00:31:26 +02:00
table.insert ( chunks , i , { n , n } ) -- insert new interval before i
2021-03-28 20:56:51 +02:00
return
end
prev = d
end
2022-10-25 00:31:26 +02:00
chunks [ # chunks + 1 ] = { n , n }
2021-03-28 20:56:51 +02:00
end
2022-10-25 00:31:26 +02:00
---@param pos Vector
---@return boolean
2021-03-28 20:56:51 +02:00
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
2022-10-25 00:31:26 +02:00
---"Trivial" (actually NOT) function to just read the node and some stuff to not just return "ignore", like mt 5.4 does.
---@param pos Vector Position, if it's wrong, `{name="error"}` node will return.
2022-10-25 00:32:35 +02:00
---@param force? boolean Optional (default: `false`), Do the maximum to still read the node within us_timeout.
---@param us_timeout? number Optional (default: `244 = 0.000244 s = 1/80/80/80`), set it at least to `3000000` to let mapgen to finish its job
2022-10-25 00:31:26 +02:00
---@return node # Node definition, eg. `{name="air"}`. Unfortunately still can return `{name="ignore"}`.
2022-10-25 00:32:35 +02:00
---@nodiscard
2022-10-25 00:31:26 +02:00
function mcl_vars . get_node ( pos , force , us_timeout )
2021-03-28 20:56:51 +02:00
-- check initial circumstances
2022-10-25 00:31:26 +02:00
if not pos or not pos.x or not pos.y or not pos.z then return { name = " error " } end
2021-03-28 20:56:51 +02:00
-- try common way
2022-10-25 00:31:26 +02:00
local node = minetest.get_node ( pos )
2021-03-28 20:56:51 +02:00
if node.name ~= " ignore " then
return node
end
2022-10-25 00:31:26 +02:00
-- copy vector to get sure it won't changed by other threads
local pos_copy = vector.copy ( pos )
2021-03-28 20:56:51 +02:00
-- try LVM
2022-10-25 00:31:26 +02:00
minetest.get_voxel_manip ( ) : read_from_map ( pos_copy , pos_copy )
node = minetest.get_node ( pos_copy )
2021-03-28 20:56:51 +02:00
if node.name ~= " ignore " or not force then
return node
end
-- all ways failed - need to emerge (or forceload if generated)
2022-10-25 00:31:26 +02:00
if mcl_vars.is_generated ( pos_copy ) then
2021-03-28 20:56:51 +02:00
minetest.chat_send_all ( " IMPOSSIBLE! Please report this to MCL2 issue tracker! " )
2022-10-25 00:31:26 +02:00
minetest.forceload_block ( pos_copy )
2021-03-28 20:56:51 +02:00
else
2022-10-25 00:31:26 +02:00
minetest.emerge_area ( pos_copy , pos_copy )
2021-03-28 20:56:51 +02:00
end
local t = minetest.get_us_time ( )
2022-10-25 00:31:26 +02:00
node = minetest.get_node ( pos_copy )
2021-03-28 20:56:51 +02:00
2022-10-25 00:31:26 +02:00
while ( not node or node.name == " ignore " ) and ( minetest.get_us_time ( ) - t < ( us_timeout or 244 ) ) do
node = minetest.get_node ( pos_copy )
2021-03-28 20:56:51 +02:00
end
return node
-- it still can return "ignore", LOL, even if force = true, but only after time out
end
2024-05-29 01:29:21 +02:00
-- Workaround because pairs() doesn't always work as expected
do
local old_minetest_register_item = minetest.register_item
local items_registered = { }
mcl_vars.items_registered = items_registered
minetest.register_item = function ( name , itemdef )
if name : sub ( 1 , 1 ) == " : " then
items_registered [ # items_registered + 1 ] = name : sub ( 2 )
else
items_registered [ # items_registered + 1 ] = name
end
return old_minetest_register_item ( name , itemdef )
end
end