Compare commits

...

2 Commits

Author SHA1 Message Date
Nils Dagsson Moskopp a3fd07a167
Execute players for illegal dimension hopping 2021-12-05 08:25:12 +01:00
Nils Dagsson Moskopp 28e4622712
Add origin dimension to dimension change hook 2021-12-05 00:46:40 +01:00
3 changed files with 199 additions and 1 deletions

View File

@ -113,7 +113,7 @@ local last_dimension = {}
-- * dimension: New dimension ("overworld", "nether", "end", "void")
function mcl_worlds.dimension_change(player, dimension)
for i=1, #mcl_worlds.registered_on_dimension_change do
mcl_worlds.registered_on_dimension_change[i](player, dimension)
mcl_worlds.registered_on_dimension_change[i](player, dimension, last_dimension[player:get_player_name()])
last_dimension[player:get_player_name()] = dimension
end
end

View File

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

View File

@ -0,0 +1,2 @@
name = mcl_anti_dimension_hopping
depends = mcl_init, mcl_death_messages, mcl_portals, mcl_spawn, mcl_worlds