local origin = minetest.setting_get_pos("static_spawnpoint") or {x=0, y=0, z=0} local adminname = minetest.setting_get("name") or "singleplayer" local playerspawns = {} local spawnsfile = minetest.get_worldpath().."/dynamicspawns.lua.ser" local bedspawn = minetest.setting_getbool("enable_bed_respawn") minetest.register_privilege("spawn", "Can teleport to spawn position.") minetest.register_chatcommand("spawn", { description = "Teleport to spawn position.", params = "", privs = "spawn", func = function(name) local target = playerspawns[name] if not target then playerspawns[name] = newspawn() target = playerspawns[name] spawnsave() end minetest.get_player_by_name(name):setpos(target) end }) local function newspawn(radius) if not radius then radius = 32 end if radius > 256 then minetest.log("error", "No valid spawnable location") return origin -- always return a position of sorts end local pos1 = {x=origin.x-radius, y=origin.y, z=origin.z-radius} local pos2 = {x=origin.x+radius, y=origin.y+(radius/2), z=origin.z+radius} local airnodes = minetest.find_nodes_in_area(pos1, pos2, {"air"}) local validnodes = {} for _,anode in pairs(airnodes) do local under = minetest.get_node( {x=anode.x, y=anode.y-1, z=anode.z} ).name local over = minetest.get_node( {x=anode.x, y=anode.y+1, z=anode.z} ).name under = minetest.registered_nodes[under] over = minetest.registered_nodes[over] if under.walkable and not over.walkable and not minetest.is_protected(anode, adminname) then validnodes[#validnodes+1] = anode end end if #validnodes > 0 then minetest.log("info", "New spawn point found with radius "..tostring(radius)) return validnodes[math.random(1,#validnodes)] end return newspawn(radius+32) end minetest.register_privilege("newspawn", "Can get a new randomized spawn position.") minetest.register_chatcommand("newspawn", { description = "Randomly select a new spawn position.", params = "", privs = "newspawn", func = function(name) playerspawns[name] = newspawn() minetest.get_player_by_name(name):setpos(playerspawns[name]) spawnsave() minetest.chat_send_player(name, "New spawn set !") end }) minetest.register_privilege("setspawn", "Can manually set a spawn point") minetest.register_chatcommand("setspawn", { description = "Assign current position as spawn position.", params = "", privs = "setspawn", func = function(name) playerspawns[name] = minetest.get_player_by_name(name):getpos() spawnsave() minetest.chat_send_player(name, "New spawn set !") end }) function spawnsave() local serdata = minetest.serialize(playerspawns) if not serdata then minetest.log("error", "[spawn] Data serialization failed") return end local file, err = io.open(spawnsfile, "w") if err then return err end file:write(serdata) file:close() end function spawnload() local file, err = io.open(spawnsfile, "r") if err then minetest.log("error", "[spawn] Data read failed") return end playerspawns = minetest.deserialize(file:read("*a")) file:close() end spawnload() minetest.register_on_newplayer(function(player) local name = player:get_player_name() playerspawns[name] = player:getpos() spawnsave() return end) minetest.register_on_joinplayer(function(player) minetest.after(1.1, function() local name = player:get_player_name() if not playerspawns[name] then playerspawns[name] = newspawn() player:setpos(playerspawns[name]) spawnsave() end end) end) minetest.register_on_respawnplayer(function(player) local name = player:get_player_name() if bedspawn == true then local pos = beds.spawn[name] if pos then player:setpos(pos) return true end end -- And if no bed, nor bed spwawning not active: player:setpos(playerspawns[name]) return true end)