worldedge/init.lua

150 lines
3.5 KiB
Lua

--------------
-- TODO: Check for terrain height
-- Defines the edge of a world
local edge = tonumber(minetest.settings:get("world_edge")) or 30000
-- Radius which should be checked for a good teleportation place
local radius = 2
--------------
if minetest.settings:get_bool("log_mods") then
minetest.log("action", "World edge: " .. edge)
end
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())
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}
elseif pos.z <= -edge then
newpos = {x = pos.x, y = 10, z = newedge}
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)
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
})
minetest.log("action", "[worldedge] loaded.")