95 lines
2.4 KiB
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)
|