|
|
|
@ -0,0 +1,196 @@
|
|
|
|
|
local S = minetest.get_translator("mcl_anti_dimension_hopping")
|
|
|
|
|
|
|
|
|
|
local storage = minetest.get_mod_storage()
|
|
|
|
|
|
|
|
|
|
local MAX_DISTANCE = 40
|
|
|
|
|
|
|
|
|
|
local dimension_change_is_legal = function(
|
|
|
|
|
player_name, -- string
|
|
|
|
|
dimension, -- "end"|"nether"|"overworld"|"void"
|
|
|
|
|
last_dimension, -- "end"|"nether"|"overworld"|"void"
|
|
|
|
|
last_last_dimension -- "end"|"nether"|"overworld"|"void"|nil
|
|
|
|
|
)
|
|
|
|
|
local player = minetest.get_player_by_name(player_name)
|
|
|
|
|
if nil == player then
|
|
|
|
|
return false
|
|
|
|
|
end
|
|
|
|
|
local player_position = player:get_pos()
|
|
|
|
|
if "end" == dimension then
|
|
|
|
|
assert( player_position.y > mcl_vars.mg_end_min )
|
|
|
|
|
assert( player_position.y < mcl_vars.mg_end_max )
|
|
|
|
|
-- Going to the End through a portal is allowed, but a
|
|
|
|
|
-- player must appear at End spawn for it to be legal.
|
|
|
|
|
-- The Nether as the last dimension is included here
|
|
|
|
|
-- because an End portal in the nether sends players
|
|
|
|
|
-- to End spawn, but cheaters can not teleport down
|
|
|
|
|
-- from the Nether, as the Nether is below the End.
|
|
|
|
|
if (
|
|
|
|
|
"overworld" == last_dimension or
|
|
|
|
|
"nether" == last_dimension
|
|
|
|
|
) then
|
|
|
|
|
if vector.distance(
|
|
|
|
|
player_position,
|
|
|
|
|
mcl_vars.mg_end_platform_pos
|
|
|
|
|
) < MAX_DISTANCE then
|
|
|
|
|
return true
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
-- Going to the End via the Void is allowed only if
|
|
|
|
|
-- the player entered the Void from the End … nil has
|
|
|
|
|
-- to be handled here for players who were in the Void
|
|
|
|
|
-- when this mod was activated.
|
|
|
|
|
if "void" == last_dimension then
|
|
|
|
|
if (
|
|
|
|
|
"end" == last_last_dimension or
|
|
|
|
|
nil == last_last_dimension
|
|
|
|
|
) then
|
|
|
|
|
return true
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
if "nether" == dimension then
|
|
|
|
|
assert( player_position.y > mcl_vars.mg_nether_min )
|
|
|
|
|
assert( player_position.y < mcl_vars.mg_nether_max )
|
|
|
|
|
-- Going to the Nether through a portal is allowed.
|
|
|
|
|
if "overworld" == last_dimension then
|
|
|
|
|
if nil ~= minetest.find_node_near(
|
|
|
|
|
player_position,
|
|
|
|
|
MAX_DISTANCE,
|
|
|
|
|
"mcl_portals:portal"
|
|
|
|
|
) then
|
|
|
|
|
-- TODO: check for portal in Overworld
|
|
|
|
|
return true
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
-- Going to the Nether via the Void is allowed only if
|
|
|
|
|
-- the player entered the Void from the Nether … nil
|
|
|
|
|
-- has to be handled here for players who were in the
|
|
|
|
|
-- Void when this mod was activated.
|
|
|
|
|
if "void" == last_dimension then
|
|
|
|
|
if (
|
|
|
|
|
"nether" == last_last_dimension or
|
|
|
|
|
nil == last_last_dimension
|
|
|
|
|
) then
|
|
|
|
|
return true
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
if "overworld" == dimension then
|
|
|
|
|
assert( player_position.y > mcl_vars.mg_overworld_min )
|
|
|
|
|
assert( player_position.y < mcl_vars.mg_overworld_max )
|
|
|
|
|
-- Going to the Overworld from the Nether through a
|
|
|
|
|
-- portal is allowed.
|
|
|
|
|
if "nether" == last_dimension then
|
|
|
|
|
if nil ~= minetest.find_node_near(
|
|
|
|
|
player_position,
|
|
|
|
|
MAX_DISTANCE,
|
|
|
|
|
"mcl_portals:portal"
|
|
|
|
|
) then
|
|
|
|
|
-- TODO: check for portal in Nether
|
|
|
|
|
return true
|
|
|
|
|
end
|
|
|
|
|
return true
|
|
|
|
|
end
|
|
|
|
|
-- Going to the Overworld via the Void is allowed only
|
|
|
|
|
-- if the player entered the Void from the Overworld …
|
|
|
|
|
-- nil has to be handled here for players who were in
|
|
|
|
|
-- the Void when this mod was activated.
|
|
|
|
|
if "void" == last_dimension then
|
|
|
|
|
if (
|
|
|
|
|
"overworld" == last_last_dimension or
|
|
|
|
|
nil == last_last_dimension
|
|
|
|
|
) then
|
|
|
|
|
return true
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
-- Going to the Overworld via the End (or any other
|
|
|
|
|
-- way) is allowed only if the player appears at their
|
|
|
|
|
-- respawn location, either because they used a portal
|
|
|
|
|
-- in the End or because they died.
|
|
|
|
|
local player_spawn_position = (
|
|
|
|
|
mcl_spawn.get_player_spawn_pos(player) or
|
|
|
|
|
mcl_spawn.get_world_spawn_pos(player)
|
|
|
|
|
)
|
|
|
|
|
if vector.distance(
|
|
|
|
|
player_position,
|
|
|
|
|
player_spawn_position
|
|
|
|
|
) < MAX_DISTANCE then
|
|
|
|
|
return true
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
if "void" == dimension then
|
|
|
|
|
-- Going to the Void is always legal – a player who
|
|
|
|
|
-- enters the Void and then goes anywhere else than
|
|
|
|
|
-- where they came from is already handled above.
|
|
|
|
|
return true
|
|
|
|
|
end
|
|
|
|
|
return false
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local kill_player_for_dimensional_trespassing = function(
|
|
|
|
|
player_name,
|
|
|
|
|
dimension,
|
|
|
|
|
last_dimension,
|
|
|
|
|
last_last_dimension
|
|
|
|
|
)
|
|
|
|
|
local player = minetest.get_player_by_name(player_name)
|
|
|
|
|
if nil == player then
|
|
|
|
|
return
|
|
|
|
|
end
|
|
|
|
|
-- If the player holds a totem of undying, destroy it before
|
|
|
|
|
-- killing, so it doesn't rescue the player.
|
|
|
|
|
local wield = player:get_wielded_item()
|
|
|
|
|
if wield:get_name() == "mobs_mc:totem" then
|
|
|
|
|
player:set_wielded_item("")
|
|
|
|
|
end
|
|
|
|
|
local death_message = S(
|
|
|
|
|
"@1 was executed for dimensional trespassing.",
|
|
|
|
|
player_name
|
|
|
|
|
)
|
|
|
|
|
mcl_death_messages.player_damage(
|
|
|
|
|
player,
|
|
|
|
|
death_message
|
|
|
|
|
)
|
|
|
|
|
player:set_hp(0)
|
|
|
|
|
local log_message = string.format(
|
|
|
|
|
"%s was executed for dimensional trespassing: %s → %s → %s",
|
|
|
|
|
tostring(player_name),
|
|
|
|
|
tostring(last_last_dimension),
|
|
|
|
|
tostring(last_dimension),
|
|
|
|
|
tostring(dimension)
|
|
|
|
|
)
|
|
|
|
|
minetest.log(
|
|
|
|
|
"action",
|
|
|
|
|
log_message
|
|
|
|
|
)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
mcl_worlds.register_on_dimension_change(
|
|
|
|
|
function(player, dimension, last_dimension)
|
|
|
|
|
local player_name = player:get_player_name()
|
|
|
|
|
local last_last_dimension = storage:get_string(
|
|
|
|
|
player_name .. ":dimension_previous_previous"
|
|
|
|
|
)
|
|
|
|
|
if not dimension_change_is_legal(
|
|
|
|
|
player_name,
|
|
|
|
|
dimension,
|
|
|
|
|
last_dimension,
|
|
|
|
|
last_last_dimension
|
|
|
|
|
) then
|
|
|
|
|
kill_player_for_dimensional_trespassing(
|
|
|
|
|
player_name,
|
|
|
|
|
dimension,
|
|
|
|
|
last_dimension,
|
|
|
|
|
last_last_dimension
|
|
|
|
|
)
|
|
|
|
|
end
|
|
|
|
|
storage:set_string(
|
|
|
|
|
player_name .. ":dimension_previous_previous",
|
|
|
|
|
last_dimension
|
|
|
|
|
)
|
|
|
|
|
storage:set_string(
|
|
|
|
|
player_name .. ":dimension_previous",
|
|
|
|
|
dimension
|
|
|
|
|
)
|
|
|
|
|
end
|
|
|
|
|
)
|