spawnarea/init.lua

95 lines
2.4 KiB
Lua

local radius = 128
local spawn = {x=0, y=0, z=0}
local center = {x=0, y=0, z=0}
local timer = 295 -- first run shortly after start
--
-- Determine center of spawnpoint as mean of player positions
--
minetest.register_globalstep(function(dtime)
timer = timer + dtime
if timer < 300 then return end -- 300 = 5 minutes
timer = 0
local cx = 0
local cy = 0
local cz = 0
local n = 0 -- number of players counted
local players = minetest.get_connected_players()
if #players < 1 then return end
for _,player in ipairs(players) do
local pos = player:get_pos()
-- only count players close to the surface
if pos.y >= 0 and pos.y < 256 then
cx = cx+pos.x
cy = cy+pos.y
cz = cz+pos.z
n = n + 1
end
end
if n < 1 then return end
center = {x=cx/n, y=cy/n, z=cz/n}
-- slowly approximate spawnpoint to new center
-- changes faster with more players
local sx = math.floor((spawn.x * 10 + center.x * n) / (10+n))
local sy = math.floor((spawn.y * 10 + center.y * n) / (10+n))
local sz = math.floor((spawn.z * 10 + center.z * n) / (10+n))
spawn = {x = sx, y = sy, z = sz}
print("spawnarea: new spawn at = "..spawn.x..", "..spawn.y..", "..spawn.z)
end)
--
-- Spawn players randomly within the defined area
--
local function findspawn(player)
for try=100, 0, -1 do
local pos = {x = spawn.x, y = spawn.y, z = spawn.z}
pos.x = spawn.x + math.random(-radius, radius)
pos.y = spawn.y
pos.z = spawn.z + math.random(-radius, radius)
local free = pos
minetest.forceload_block(free, true)
-- Find ground level
local ground_y = nil
for y=128, -128, -1 do
local nn = minetest.get_node({x=pos.x, y=pos.y+y, z=pos.z}).name
if nn ~= "air" and nn ~= "ignore" then
ground_y = pos.y+y
break
end
end
if ground_y then
pos.y = ground_y
if minetest.registered_nodes[minetest.get_node(pos).name].walkable == true and
minetest.get_node({x=pos.x, y=pos.y+1, z=pos.z}).name == "air" and
minetest.get_node({x=pos.x, y=pos.y+2, z=pos.z}).name == "air" then
local pos_spawn = {x=pos.x, y=pos.y+1, z=pos.z}
return pos_spawn
end
end
minetest.forceload_free_block(free, true)
end
end
local function spawnarea(player)
local pos = findspawn(player)
if pos then
player:set_pos(pos)
else
player:set_pos(spawn)
end
end
if not minetest.is_singleplayer() then
minetest.register_on_newplayer(function(player)
spawnarea(player)
end)
end
minetest.register_on_respawnplayer(function(player)
spawnarea(player)
return true
end)