mirror of
https://github.com/sys4-fr/server-nalc.git
synced 2024-11-18 08:10:38 +01:00
65e736b5b1
- Solves #241
166 lines
4.4 KiB
Lua
Executable File
166 lines
4.4 KiB
Lua
Executable File
--------------
|
|
-- 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())
|
|
|
|
-- 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
|
|
|
|
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}
|
|
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)
|
|
elseif pos.z <= -edge then
|
|
newpos = {x = pos.x, y = 10, z = newedge}
|
|
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)
|
|
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
|
|
end
|
|
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
|
|
})
|