forked from minetest/minetest_game
Add API to control respawn logic and behavior
This commit is contained in:
parent
d1ba7c3db3
commit
c60d8e4da0
28
game_api.txt
28
game_api.txt
|
@ -632,6 +632,34 @@ set a players home position and teleport a player to home position.
|
||||||
* `name` Player you wish to teleport to their home position
|
* `name` Player you wish to teleport to their home position
|
||||||
* return value: false if player cannot be sent home, otherwise true
|
* return value: false if player cannot be sent home, otherwise true
|
||||||
|
|
||||||
|
Spawn API
|
||||||
|
---------
|
||||||
|
|
||||||
|
The spawn mod takes care of deciding the position of new and respawning players
|
||||||
|
in the world and has an API to modify its behavior.
|
||||||
|
|
||||||
|
`spawn.get_default_pos()`
|
||||||
|
* Gets the default spawn position as decided by a biome-dependent algorithm.
|
||||||
|
* This is not influenced by settings like "static_spawnpoint" or "engine_spawn".
|
||||||
|
* return value: a vector or `nil` on failure
|
||||||
|
|
||||||
|
`spawn.add_suitable_biome(biome)`:
|
||||||
|
* Adds a biome to the list of allowed biomes for the above algorithm.
|
||||||
|
* `biome`: Name of a registered biome
|
||||||
|
|
||||||
|
`spawn.register_on_spawn(func)`:
|
||||||
|
* Registers a callback to be called when a player (re-)spawns. This can be used
|
||||||
|
to intercept the normal logic to e.g. respawn a player at his bed.
|
||||||
|
* `func`: `function(player, is_new)` with arguments
|
||||||
|
- `player`: ObjectRef
|
||||||
|
- `is_new`: true if the player is joining the server for the first time
|
||||||
|
- return value: true to skip all other spawn logic, false or nil otherwise
|
||||||
|
|
||||||
|
When a player (re-)spawns the following order is executed:
|
||||||
|
1. All spawn callbacks in order of registration.
|
||||||
|
2. If no result, teleport player to `spawn.get_default_pos()`.
|
||||||
|
3. If that fails, spawning is left up to engine.
|
||||||
|
|
||||||
|
|
||||||
Sfinv API
|
Sfinv API
|
||||||
---------
|
---------
|
||||||
|
|
|
@ -244,10 +244,9 @@ end
|
||||||
-- Callbacks
|
-- Callbacks
|
||||||
-- Only register respawn callback if respawn enabled
|
-- Only register respawn callback if respawn enabled
|
||||||
if enable_respawn then
|
if enable_respawn then
|
||||||
-- respawn player at bed if enabled and valid position is found
|
-- Respawn player at bed if valid position is found
|
||||||
minetest.register_on_respawnplayer(function(player)
|
spawn.register_on_spawn(function(player, is_new)
|
||||||
local name = player:get_player_name()
|
local pos = beds.spawn[player:get_player_name()]
|
||||||
local pos = beds.spawn[name]
|
|
||||||
if pos then
|
if pos then
|
||||||
player:set_pos(pos)
|
player:set_pos(pos)
|
||||||
return true
|
return true
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
name = beds
|
name = beds
|
||||||
description = Minetest Game mod: beds
|
description = Minetest Game mod: beds
|
||||||
depends = default, wool
|
depends = default, wool, spawn
|
||||||
|
|
49
mods/spawn/api.lua
Normal file
49
mods/spawn/api.lua
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
spawn = {}
|
||||||
|
|
||||||
|
-- provide empty default implementations
|
||||||
|
|
||||||
|
function spawn.get_default_pos()
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
function spawn.add_suitable_biome(biome)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Callback registration
|
||||||
|
|
||||||
|
spawn.registered_on_spawn = {}
|
||||||
|
|
||||||
|
function spawn.register_on_spawn(func)
|
||||||
|
table.insert(spawn.registered_on_spawn, func)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Logic run on spawn
|
||||||
|
|
||||||
|
local use_engine_spawn = minetest.settings:get("static_spawnpoint") or
|
||||||
|
minetest.settings:get_bool("engine_spawn")
|
||||||
|
|
||||||
|
local function on_spawn(player, is_new)
|
||||||
|
-- Ask all callbacks first
|
||||||
|
for _, cb in ipairs(spawn.registered_on_spawn) do
|
||||||
|
if cb(player, is_new) then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- Fall back to default spawn
|
||||||
|
if not use_engine_spawn then
|
||||||
|
local pos = spawn.get_default_pos()
|
||||||
|
if pos then
|
||||||
|
player:set_pos(pos)
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
minetest.register_on_newplayer(function(player)
|
||||||
|
on_spawn(player, true)
|
||||||
|
end)
|
||||||
|
|
||||||
|
minetest.register_on_respawnplayer(function(player)
|
||||||
|
return on_spawn(player, false)
|
||||||
|
end)
|
|
@ -1,12 +1,12 @@
|
||||||
-- spawn/init.lua
|
-- Always load the API
|
||||||
|
----------------------
|
||||||
|
dofile(minetest.get_modpath(minetest.get_current_modname()) .. "/api.lua")
|
||||||
|
|
||||||
-- Disable by mapgen, setting or if 'static_spawnpoint' is set
|
-- Disable biome-search implementation on unsuitable mapgens
|
||||||
--------------------------------------------------------------
|
------------------------------------------------------------
|
||||||
|
|
||||||
local mg_name = minetest.get_mapgen_setting("mg_name")
|
local mg_name = minetest.get_mapgen_setting("mg_name")
|
||||||
if mg_name == "v6" or mg_name == "singlenode" or
|
if mg_name == "v6" or mg_name == "singlenode" then
|
||||||
minetest.settings:get("static_spawnpoint") or
|
|
||||||
minetest.settings:get_bool("engine_spawn") then
|
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -23,27 +23,32 @@ local checks = 128 * 128
|
||||||
local pos = {x = 0, y = 8, z = 0}
|
local pos = {x = 0, y = 8, z = 0}
|
||||||
|
|
||||||
|
|
||||||
-- Table of suitable biomes
|
-- Table of suitable biomes and matching API function
|
||||||
|
|
||||||
local biome_ids = {
|
local biome_ids = {}
|
||||||
minetest.get_biome_id("taiga"),
|
|
||||||
minetest.get_biome_id("coniferous_forest"),
|
function spawn.add_suitable_biome(biome)
|
||||||
minetest.get_biome_id("deciduous_forest"),
|
local id = minetest.get_biome_id(biome)
|
||||||
minetest.get_biome_id("grassland"),
|
assert(id ~= nil)
|
||||||
minetest.get_biome_id("savanna"),
|
biome_ids[id] = true
|
||||||
}
|
end
|
||||||
|
|
||||||
|
for _, name in ipairs({
|
||||||
|
"taiga", "coniferous_forest", "deciduous_forest", "grassland", "savanna"
|
||||||
|
}) do
|
||||||
|
spawn.add_suitable_biome(name)
|
||||||
|
end
|
||||||
|
|
||||||
-- End of parameters
|
-- End of parameters
|
||||||
--------------------
|
--------------------
|
||||||
|
|
||||||
|
|
||||||
-- Direction table
|
-- Direction table
|
||||||
|
|
||||||
local dirs = {
|
local dirs = {
|
||||||
{x = 0, y = 0, z = 1},
|
vector.new(0, 0, 1),
|
||||||
{x = -1, y = 0, z = 0},
|
vector.new(-1, 0, 0),
|
||||||
{x = 0, y = 0, z = -1},
|
vector.new(0, 0, -1),
|
||||||
{x = 1, y = 0, z = 0},
|
vector.new(1, 0, 0),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -67,8 +72,8 @@ local chunksize = tonumber(minetest.get_mapgen_setting("chunksize"))
|
||||||
local spawn_limit = math.max(mapgen_limit - (chunksize + 1) * 16, 0)
|
local spawn_limit = math.max(mapgen_limit - (chunksize + 1) * 16, 0)
|
||||||
|
|
||||||
|
|
||||||
--Functions
|
-- Functions
|
||||||
-----------
|
------------
|
||||||
|
|
||||||
-- Get next position on square search spiral
|
-- Get next position on square search spiral
|
||||||
|
|
||||||
|
@ -98,17 +103,13 @@ local function search()
|
||||||
for iter = 1, checks do
|
for iter = 1, checks do
|
||||||
local biome_data = minetest.get_biome_data(pos)
|
local biome_data = minetest.get_biome_data(pos)
|
||||||
-- Sometimes biome_data is nil
|
-- Sometimes biome_data is nil
|
||||||
local biome = biome_data and biome_data.biome
|
if biome_data and biome_ids[biome_data.biome] then
|
||||||
for id_ind = 1, #biome_ids do
|
|
||||||
local biome_id = biome_ids[id_ind]
|
|
||||||
if biome == biome_id then
|
|
||||||
local spawn_y = minetest.get_spawn_level(pos.x, pos.z)
|
local spawn_y = minetest.get_spawn_level(pos.x, pos.z)
|
||||||
if spawn_y then
|
if spawn_y then
|
||||||
spawn_pos = {x = pos.x, y = spawn_y, z = pos.z}
|
spawn_pos = vector.new(pos.x, spawn_y, pos.z)
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
pos = next_pos()
|
pos = next_pos()
|
||||||
-- Check for position being outside world edge
|
-- Check for position being outside world edge
|
||||||
|
@ -121,38 +122,11 @@ local function search()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
-- On new player spawn and player respawn
|
function spawn.get_default_pos()
|
||||||
|
-- Search for spawn position once per server session
|
||||||
-- Search for spawn position once per server session. If successful, store
|
|
||||||
-- position and reposition players, otherwise leave them at engine spawn
|
|
||||||
-- position.
|
|
||||||
|
|
||||||
local function on_spawn(player)
|
|
||||||
if not searched then
|
if not searched then
|
||||||
success = search()
|
success = search()
|
||||||
searched = true
|
searched = true
|
||||||
end
|
end
|
||||||
if success then
|
return success and spawn_pos
|
||||||
player:set_pos(spawn_pos)
|
|
||||||
end
|
|
||||||
return success
|
|
||||||
end
|
end
|
||||||
|
|
||||||
minetest.register_on_newplayer(function(player)
|
|
||||||
on_spawn(player)
|
|
||||||
end)
|
|
||||||
|
|
||||||
local enable_bed_respawn = minetest.settings:get_bool("enable_bed_respawn")
|
|
||||||
if enable_bed_respawn == nil then
|
|
||||||
enable_bed_respawn = true
|
|
||||||
end
|
|
||||||
|
|
||||||
minetest.register_on_respawnplayer(function(player)
|
|
||||||
-- Avoid respawn conflict with beds mod
|
|
||||||
if beds and enable_bed_respawn and
|
|
||||||
beds.spawn[player:get_player_name()] then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
return on_spawn(player)
|
|
||||||
end)
|
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
name = spawn
|
name = spawn
|
||||||
description = Minetest Game mod: spawn
|
description = Minetest Game mod: spawn
|
||||||
depends = default
|
depends = default
|
||||||
optional_depends = beds
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user