2015-05-19 11:36:42 +02:00
--------------
-- TODO: Check for terrain height
-- Defines the edge of a world
local edge = 30000
-- Radius which should be checked for a good teleportation place
local radius = 2
--------------
local count = 0
local waiting_list = { }
--[[ Explanation of waiting_list table
Index = Player name
Value = {
player = Player to teleport
pos = Destination
obj = Attacked entity
notified = When the player must wait longer ...
}
] ]
minetest.register_globalstep ( function ( dtime )
count = count + dtime
if count < 3 then
return
end
count = 0
for k , v in pairs ( waiting_list ) do
if v.player and v.player : is_player ( ) then
local pos = get_surface_pos ( v.pos )
if pos then
v.obj : setpos ( pos )
minetest.after ( 0.2 , function ( p , o )
p : set_detach ( )
o : remove ( )
end , v.player , v.obj )
waiting_list [ k ] = nil
elseif not v.notified then
v.notified = true
minetest.chat_send_player ( k , " Sorry, we have not found a free place yet. Please be patient. " )
end
else
v.obj : remove ( )
waiting_list [ k ] = nil
end
end
local newedge = edge - 5
-- Check if the players are near the edge and teleport them
local players = minetest.get_connected_players ( )
for i , player in ipairs ( players ) do
local name = player : get_player_name ( )
if not waiting_list [ name ] then
local pos = vector.round ( player : getpos ( ) )
2015-08-29 11:54:25 +02:00
-- Sanity check for insane coordinates
if pos.x > 31000 or pos.y > 31000 or pos.z > 31000
or pos.x < - 31000 or pos.y < - 31000 or pos.z < - 31000 then
-- Move to spawn asap
-- The server probably set invalid/insane coordinates. We have not saved the previous ones,
-- So we need to teleport the player to the spawn to save them from an endless loop of
-- Teleportation.
local spawn = minetest.string_to_pos ( minetest.setting_get ( " static_spawnpoint " ) or " 0,0,0 " )
minetest.chat_send_player ( player : get_player_name ( ) , " An internal error has occured. Your coordinates were corrupted. You are now teleported to the spawn. " ..
" Please report it to any staff member. " )
minetest.log ( " error " , " [WorldEdge] Corrupted position detected for player " .. player : get_player_name ( ) )
player : setpos ( spawn )
else -- Indent skipped, too many lines to change... We'll wait for "continue" to be introduced in Lua5.2
2015-05-19 11:36:42 +02:00
local newpos = nil
if pos.x >= edge then
newpos = { x = - newedge , y = 10 , z = pos.z }
elseif pos.x <= - edge then
newpos = { x = newedge , y = 10 , z = pos.z }
end
if pos.z >= edge then
newpos = { x = pos.x , y = 10 , z = - newedge }
2015-07-14 14:52:39 +02:00
if get_surface_pos ( newpos ) then
newpos.y = get_surface_pos ( newpos ) . y + 1 -- /MFF (Mg|19/05//15)
end -- /MFF (Mg|14/07/15)
2015-05-19 11:36:42 +02:00
elseif pos.z <= - edge then
newpos = { x = pos.x , y = 10 , z = newedge }
2015-07-14 14:52:39 +02:00
if get_surface_pos ( newpos ) then
newpos.y = get_surface_pos ( newpos ) . y + 1 -- /MFF (Mg|19/05/15)
end -- /MFF (Mg|14/07/15)
2015-05-19 11:36:42 +02:00
end
-- Teleport the player
if newpos then
minetest.chat_send_player ( name , " Please wait a few seconds. We will teleport you soon. " )
local obj = minetest.add_entity ( newpos , " worldedge:lock " )
player : set_attach ( obj , " " , { x = 0 , y = 0 , z = 0 } , { x = 0 , y = 0 , z = 0 } )
waiting_list [ name ] = {
player = player ,
pos = newpos ,
obj = obj
}
obj : setpos ( newpos )
end
2015-08-29 11:54:25 +02:00
end
2015-05-19 11:36:42 +02:00
end
end
end )
function get_surface_pos ( pos )
local minp = {
x = pos.x - radius - 1 ,
y = - 10 ,
z = pos.z - radius - 1
}
local maxp = {
x = pos.x + radius - 1 ,
y = 50 ,
z = pos.z + radius - 1
}
local c_air = minetest.get_content_id ( " air " )
local c_ignore = minetest.get_content_id ( " ignore " )
local vm = minetest.get_voxel_manip ( )
local emin , emax = vm : read_from_map ( minp , maxp )
local area = VoxelArea : new { MinEdge = emin , MaxEdge = emax }
local data = vm : get_data ( )
local seen_air = false
local deepest_place = vector.new ( pos )
deepest_place.y = 50
for x = minp.x , maxp.x do
for z = minp.z , maxp.z do
local solid = 0
for y = deepest_place.y , - 10 , - 1 do
local node = data [ area : index ( x , y , z ) ]
if y < deepest_place.y and node == c_air then
deepest_place = vector.new ( x , y , z )
seen_air = true
end
if solid > 5 then
-- Do not find caves!
break
end
if node ~= c_air and node ~= c_ignore then
solid = solid + 1
end
end
end
end
if seen_air then
return deepest_place
else
return false
end
end
minetest.register_entity ( " worldedge:lock " , {
initial_properties = {
is_visible = false
} ,
on_activate = function ( staticdata , dtime_s )
--self.object:set_armor_groups({immortal = 1})
end
} )