2017-11-24 02:10:02 +00:00
|
|
|
mcl_worlds = {}
|
|
|
|
|
2021-05-29 14:12:33 +00:00
|
|
|
local get_connected_players = minetest.get_connected_players
|
|
|
|
|
2017-11-24 02:10:02 +00:00
|
|
|
-- For a given position, returns a 2-tuple:
|
|
|
|
-- 1st return value: true if pos is in void
|
|
|
|
-- 2nd return value: true if it is in the deadly part of the void
|
2022-01-20 01:11:21 +00:00
|
|
|
local min1, min2, min3 = mcl_mapgen.overworld.min, mcl_mapgen.end_.min, mcl_mapgen.nether.min
|
|
|
|
local max1, max2, max3 = mcl_mapgen.overworld.max, mcl_mapgen.end_.max, mcl_mapgen.nether.max+128
|
2017-11-24 02:10:02 +00:00
|
|
|
function mcl_worlds.is_in_void(pos)
|
2022-01-20 01:11:21 +00:00
|
|
|
local y = pos.y
|
|
|
|
local void = not ((y < max1 and y > min1) or (y < max2 and y > min2) or (y < max3 and y > min3))
|
2017-11-24 02:10:02 +00:00
|
|
|
|
|
|
|
local void_deadly = false
|
|
|
|
local deadly_tolerance = 64 -- the player must be this many nodes “deep” into the void to be damaged
|
|
|
|
if void then
|
|
|
|
-- Overworld → Void → End → Void → Nether → Void
|
2022-01-20 01:11:21 +00:00
|
|
|
if y < min1 and y > max2 then
|
|
|
|
void_deadly = y < min1 - deadly_tolerance
|
|
|
|
elseif y < min2 and y > max3 then
|
2017-12-09 14:39:27 +00:00
|
|
|
-- The void between End and Nether. Like usual, but here, the void
|
|
|
|
-- *above* the Nether also has a small tolerance area, so player
|
|
|
|
-- can fly above the Nether without getting hurt instantly.
|
2022-01-20 01:11:21 +00:00
|
|
|
void_deadly = (y < min2 - deadly_tolerance) and (y > max3 + deadly_tolerance)
|
|
|
|
elseif y < min3 then
|
|
|
|
void_deadly = y < min3 - deadly_tolerance
|
2017-11-24 02:10:02 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
return void, void_deadly
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Takes an Y coordinate as input and returns:
|
|
|
|
-- 1) The corresponding Minecraft layer (can be nil if void)
|
|
|
|
-- 2) The corresponding Minecraft dimension ("overworld", "nether" or "end") or "void" if it is in the void
|
|
|
|
-- If the Y coordinate is not located in any dimension, it will return:
|
|
|
|
-- nil, "void"
|
|
|
|
function mcl_worlds.y_to_layer(y)
|
2022-01-20 01:11:21 +00:00
|
|
|
if y >= min1 then
|
|
|
|
return y - min1, "overworld"
|
|
|
|
elseif y >= min3 and y <= max3 then
|
|
|
|
return y - min3, "nether"
|
|
|
|
elseif y >= min2 and y <= max2 then
|
|
|
|
return y - min2, "end"
|
|
|
|
else
|
|
|
|
return nil, "void"
|
|
|
|
end
|
2017-11-24 02:10:02 +00:00
|
|
|
end
|
|
|
|
|
2021-05-29 14:12:33 +00:00
|
|
|
local y_to_layer = mcl_worlds.y_to_layer
|
|
|
|
|
2017-11-24 02:10:02 +00:00
|
|
|
-- Takes a pos and returns the dimension it belongs to (same as above)
|
|
|
|
function mcl_worlds.pos_to_dimension(pos)
|
2021-05-29 14:12:33 +00:00
|
|
|
local _, dim = y_to_layer(pos.y)
|
2017-11-24 02:10:02 +00:00
|
|
|
return dim
|
|
|
|
end
|
|
|
|
|
2021-05-29 14:12:33 +00:00
|
|
|
local pos_to_dimension = mcl_worlds.pos_to_dimension
|
|
|
|
|
2017-11-24 02:10:02 +00:00
|
|
|
-- Takes a Minecraft layer and a “dimension” name
|
|
|
|
-- and returns the corresponding Y coordinate for
|
|
|
|
-- MineClone 2.
|
|
|
|
-- mc_dimension is one of "overworld", "nether", "end" (default: "overworld").
|
|
|
|
function mcl_worlds.layer_to_y(layer, mc_dimension)
|
2022-01-20 01:11:21 +00:00
|
|
|
if not mc_dimension or mc_dimension == "overworld" then
|
|
|
|
return layer + min1
|
|
|
|
elseif mc_dimension == "nether" then
|
|
|
|
return layer + min3
|
|
|
|
elseif mc_dimension == "end" then
|
|
|
|
return layer + min2
|
|
|
|
end
|
2017-11-24 02:10:02 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
-- Takes a position and returns true if this position can have weather
|
|
|
|
function mcl_worlds.has_weather(pos)
|
2022-01-20 01:11:21 +00:00
|
|
|
-- Weather in the Overworld and the high part of the void below
|
|
|
|
return pos.y <= max1 and pos.y >= min1 - 64
|
2017-11-24 02:10:02 +00:00
|
|
|
end
|
|
|
|
|
2020-10-24 17:49:11 +00:00
|
|
|
-- Takes a position and returns true if this position can have Nether dust
|
|
|
|
function mcl_worlds.has_dust(pos)
|
2022-01-20 01:11:21 +00:00
|
|
|
-- Weather in the Overworld and the high part of the void below
|
|
|
|
return pos.y <= max3 + 138 and pos.y >= min3 - 10
|
2020-10-24 17:49:11 +00:00
|
|
|
end
|
|
|
|
|
2017-11-24 02:10:02 +00:00
|
|
|
-- Takes a position (pos) and returns true if compasses are working here
|
|
|
|
function mcl_worlds.compass_works(pos)
|
2022-01-20 01:11:21 +00:00
|
|
|
-- It doesn't work in Nether and the End, but it works in the Overworld and in the high part of the void below
|
|
|
|
local _, dim = mcl_worlds.y_to_layer(pos.y)
|
|
|
|
if dim == "nether" or dim == "end" then
|
|
|
|
return false
|
|
|
|
elseif dim == "void" then
|
|
|
|
return pos.y <= max1 and pos.y >= min1 - 64
|
|
|
|
else
|
|
|
|
return true
|
|
|
|
end
|
2017-11-24 02:10:02 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
-- Takes a position (pos) and returns true if clocks are working here
|
|
|
|
mcl_worlds.clock_works = mcl_worlds.compass_works
|
|
|
|
|
2017-11-24 02:48:32 +00:00
|
|
|
--------------- CALLBACKS ------------------
|
|
|
|
mcl_worlds.registered_on_dimension_change = {}
|
|
|
|
|
|
|
|
-- Register a callback function func(player, dimension).
|
|
|
|
-- It will be called whenever a player changes between dimensions.
|
|
|
|
-- The void counts as dimension.
|
|
|
|
-- * player: The player who changed the dimension
|
|
|
|
-- * dimension: The new dimension of the player ("overworld", "nether", "end", "void").
|
|
|
|
function mcl_worlds.register_on_dimension_change(func)
|
|
|
|
table.insert(mcl_worlds.registered_on_dimension_change, func)
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Playername-indexed table containig the name of the last known dimension the
|
|
|
|
-- player was in.
|
|
|
|
local last_dimension = {}
|
|
|
|
|
|
|
|
-- Notifies this mod about a dimension change of a player.
|
|
|
|
-- * player: Player who changed the dimension
|
2018-01-26 18:37:00 +00:00
|
|
|
-- * dimension: New dimension ("overworld", "nether", "end", "void")
|
2017-11-24 02:48:32 +00:00
|
|
|
function mcl_worlds.dimension_change(player, dimension)
|
2021-05-25 08:51:46 +00:00
|
|
|
local playername = player:get_player_name()
|
2017-11-24 02:48:32 +00:00
|
|
|
for i=1, #mcl_worlds.registered_on_dimension_change do
|
2021-05-13 20:55:17 +00:00
|
|
|
mcl_worlds.registered_on_dimension_change[i](player, dimension, last_dimension[playername])
|
2017-11-24 02:48:32 +00:00
|
|
|
end
|
2021-05-25 08:51:46 +00:00
|
|
|
last_dimension[playername] = dimension
|
2017-11-24 02:48:32 +00:00
|
|
|
end
|
|
|
|
|
2021-05-29 14:12:33 +00:00
|
|
|
local dimension_change = mcl_worlds.dimension_change
|
|
|
|
|
2017-11-24 02:48:32 +00:00
|
|
|
----------------------- INTERNAL STUFF ----------------------
|
|
|
|
|
|
|
|
-- Update the dimension callbacks every DIM_UPDATE seconds
|
|
|
|
local DIM_UPDATE = 1
|
|
|
|
local dimtimer = 0
|
|
|
|
|
|
|
|
minetest.register_on_joinplayer(function(player)
|
2021-05-29 14:12:33 +00:00
|
|
|
last_dimension[player:get_player_name()] = pos_to_dimension(player:get_pos())
|
2017-11-24 02:48:32 +00:00
|
|
|
end)
|
|
|
|
|
|
|
|
minetest.register_globalstep(function(dtime)
|
|
|
|
-- regular updates based on iterval
|
|
|
|
dimtimer = dimtimer + dtime;
|
|
|
|
if dimtimer >= DIM_UPDATE then
|
2021-05-29 14:12:33 +00:00
|
|
|
local players = get_connected_players()
|
|
|
|
for p = 1, #players do
|
|
|
|
local dim = pos_to_dimension(players[p]:get_pos())
|
2017-11-24 02:48:32 +00:00
|
|
|
local name = players[p]:get_player_name()
|
|
|
|
if dim ~= last_dimension[name] then
|
2021-05-29 14:12:33 +00:00
|
|
|
dimension_change(players[p], dim)
|
2017-11-24 02:48:32 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
dimtimer = 0
|
|
|
|
end
|
|
|
|
end)
|