diff --git a/builtin/game/chat.lua b/builtin/game/chat.lua index fc0b861ff..befdd47f9 100644 --- a/builtin/game/chat.lua +++ b/builtin/game/chat.lua @@ -1172,7 +1172,8 @@ core.register_chatcommand("spawn", { if not player then return false end - local spawnpoint = core.setting_get_pos("static_spawnpoint") + local spawnpoint = core.setting_get_pos("static_spawnpoint") or + core.get_world_spawnpoint() if spawnpoint then player:set_pos(spawnpoint) return true, "Teleporting to spawn..." @@ -1190,9 +1191,20 @@ core.register_chatcommand("setspawn", { if not player then return false end - local pos = core.pos_to_string(player:get_pos(), 1) - core.settings:set("static_spawnpoint", pos) - core.settings:write() - return true, "The spawn point are set to " .. pos + + -- Round the player's position to one decimal place + local pos = vector.apply(player:get_pos(), function(dir) + return math.floor(dir * 10 + 0.5) / 10 + end) + + -- Remove the static_spawnpoint setting if it exists + if core.settings:get("static_spawnpoint") then + core.settings:remove("static_spawnpoint") + core.settings:write() + end + + core.set_world_spawnpoint(pos) + + return true, "The spawn point has been set to " .. core.pos_to_string(pos) end }) diff --git a/builtin/game/init.lua b/builtin/game/init.lua index 500e2aa90..e71a8eeb9 100644 --- a/builtin/game/init.lua +++ b/builtin/game/init.lua @@ -25,7 +25,6 @@ dofile(gamepath .. "auth.lua") dofile(commonpath .. "chatcommands.lua") dofile(gamepath .. "chat.lua") dofile(commonpath .. "information_formspecs.lua") -dofile(gamepath .. "static_spawn.lua") dofile(gamepath .. "detached_inventory.lua") assert(loadfile(gamepath .. "falling.lua"))(builtin_shared) dofile(gamepath .. "features.lua") diff --git a/builtin/game/static_spawn.lua b/builtin/game/static_spawn.lua deleted file mode 100644 index fae23eab0..000000000 --- a/builtin/game/static_spawn.lua +++ /dev/null @@ -1,23 +0,0 @@ --- Minetest: builtin/static_spawn.lua - -local static_spawnpoint_string = core.settings:get("static_spawnpoint") -if static_spawnpoint_string and - static_spawnpoint_string ~= "" and - not core.setting_get_pos("static_spawnpoint") then - error('The static_spawnpoint setting is invalid: "' .. - static_spawnpoint_string .. '"') -end - -local function put_player_in_spawn(player_obj) - local static_spawnpoint = core.setting_get_pos("static_spawnpoint") - if not static_spawnpoint then - return false - end - core.log("action", "Moving " .. player_obj:get_player_name() .. - " to static spawnpoint at " .. core.pos_to_string(static_spawnpoint)) - player_obj:set_pos(static_spawnpoint) - return true -end - -core.register_on_newplayer(put_player_in_spawn) -core.register_on_respawnplayer(put_player_in_spawn) diff --git a/doc/lua_api.txt b/doc/lua_api.txt index d7208e950..148891a5f 100644 --- a/doc/lua_api.txt +++ b/doc/lua_api.txt @@ -5283,6 +5283,12 @@ Environment access * The spawn level returned is for a player spawn in unmodified terrain. * The spawn level is intentionally above terrain level to cope with full-node biome 'dust' nodes. + * `minetest.set_world_spawnpoint([pos])` + * Sets the world-specific spawnpoint to pos (or `nil` to reset). + * If `static_spawnpoint` is specified in multicraft.conf, the + world-specific spawnpoint will be ignored. + * `minetest.get_world_spawnpoint()` + * Returns the world-specific spawnpoint. Mod channels ------------ diff --git a/src/script/lua_api/l_env.cpp b/src/script/lua_api/l_env.cpp index 831b93b73..8c3a1985c 100644 --- a/src/script/lua_api/l_env.cpp +++ b/src/script/lua_api/l_env.cpp @@ -748,7 +748,7 @@ int ModApiEnvMod::l_get_objects_in_area(lua_State *L) { GET_ENV_PTR; ScriptApiBase *script = getScriptApiBase(L); - + v3f minp = read_v3f(L, 1) * BS; v3f maxp = read_v3f(L, 2) * BS; aabb3f box(minp, maxp); @@ -1416,6 +1416,34 @@ int ModApiEnvMod::l_get_translated_string(lua_State * L) return 1; } +// get_world_spawnpoint() +int ModApiEnvMod::l_get_world_spawnpoint(lua_State * L) +{ + GET_ENV_PTR; + + v3f spawnpoint; + if (!env->getWorldSpawnpoint(spawnpoint)) + return 0; + + push_v3f(L, spawnpoint); + return 1; +} + +// set_world_spawnpoint(spawnpoint) +int ModApiEnvMod::l_set_world_spawnpoint(lua_State * L) +{ + GET_ENV_PTR; + + if (lua_isnil(L, 1)) { + env->resetWorldSpawnpoint(); + } else { + const v3f spawnpoint = read_v3f(L, 1); + env->setWorldSpawnpoint(spawnpoint); + } + + return 0; +} + void ModApiEnvMod::Initialize(lua_State *L, int top) { API_FCT(set_node); @@ -1466,6 +1494,8 @@ void ModApiEnvMod::Initialize(lua_State *L, int top) API_FCT(forceload_block); API_FCT(forceload_free_block); API_FCT(get_translated_string); + API_FCT(get_world_spawnpoint); + API_FCT(set_world_spawnpoint); } void ModApiEnvMod::InitializeClient(lua_State *L, int top) diff --git a/src/script/lua_api/l_env.h b/src/script/lua_api/l_env.h index a1dea6ef7..81d5eb126 100644 --- a/src/script/lua_api/l_env.h +++ b/src/script/lua_api/l_env.h @@ -114,7 +114,7 @@ private: // get_objects_inside_radius(pos, radius) static int l_get_objects_inside_radius(lua_State *L); - + // get_objects_in_area(pos, minp, maxp) static int l_get_objects_in_area(lua_State *L); @@ -198,6 +198,12 @@ private: // Get a string translated server side static int l_get_translated_string(lua_State * L); + // Get the world-specific spawnpoint + static int l_get_world_spawnpoint(lua_State *L); + + // Set the world-specific spawnpoint + static int l_set_world_spawnpoint(lua_State *L); + /* Helpers */ static void collectNodeIds(lua_State *L, int idx, diff --git a/src/server.cpp b/src/server.cpp index d3fbb693c..8977861b5 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -2970,7 +2970,11 @@ void Server::RespawnPlayer(session_t peer_id) bool repositioned = m_script->on_respawnplayer(playersao); if (!repositioned) { // setPos will send the new position to client - playersao->setPos(findSpawnPos()); + const v3f pos = findSpawnPos(); + actionstream << "Moving " << playersao->getPlayer()->getName() << + " to spawnpoint at (" << pos.X << ", " << pos.Y << ", " << + pos.Z << ")" << std::endl; + playersao->setPos(pos); } SendPlayerHP(peer_id); @@ -3816,7 +3820,8 @@ v3f Server::findSpawnPos() { ServerMap &map = m_env->getServerMap(); v3f nodeposf; - if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf)) + if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf) || + m_env->getWorldSpawnpoint(nodeposf)) return nodeposf * BS; bool is_good = false; diff --git a/src/serverenvironment.cpp b/src/serverenvironment.cpp index dd8743340..383dd2ef4 100644 --- a/src/serverenvironment.cpp +++ b/src/serverenvironment.cpp @@ -648,6 +648,10 @@ void ServerEnvironment::saveMeta() args.set("lbm_introduction_times", m_lbm_mgr.createIntroductionTimesString()); args.setU64("day_count", m_day_count); + + if (m_has_world_spawnpoint) + args.setV3F("static_spawnpoint", m_world_spawnpoint); + args.writeLines(ss); if(!fs::safeWriteToFile(path, ss.str())) @@ -721,6 +725,8 @@ void ServerEnvironment::loadMeta() m_day_count = args.exists("day_count") ? args.getU64("day_count") : 0; + + m_has_world_spawnpoint = args.getV3FNoEx("static_spawnpoint", m_world_spawnpoint); } /** diff --git a/src/serverenvironment.h b/src/serverenvironment.h index 146572a0f..ab2c594e5 100644 --- a/src/serverenvironment.h +++ b/src/serverenvironment.h @@ -374,6 +374,21 @@ public: */ void loadDefaultMeta(); + bool getWorldSpawnpoint(v3f &spawnpoint) { + if (m_has_world_spawnpoint) + spawnpoint = m_world_spawnpoint; + return m_has_world_spawnpoint; + } + + void setWorldSpawnpoint(const v3f &spawnpoint) { + m_world_spawnpoint = spawnpoint; + m_has_world_spawnpoint = true; + } + + void resetWorldSpawnpoint() { + m_has_world_spawnpoint = false; + } + private: static PlayerDatabase *openPlayerDatabase(const std::string &name, const std::string &savedir, const Settings &conf); @@ -485,5 +500,8 @@ private: std::vector m_compat_player_models; bool m_compat_send_original_model; + v3f m_world_spawnpoint = v3f(0.f, 0.f, 0.f); + bool m_has_world_spawnpoint = false; + ServerActiveObject* createSAO(ActiveObjectType type, v3f pos, const std::string &data); };