aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--builtin/game/chatcommands.lua16
-rw-r--r--builtin/game/misc.lua5
-rw-r--r--doc/lua_api.txt8
-rw-r--r--src/network/serverpackethandler.cpp7
-rw-r--r--src/script/lua_api/l_server.cpp3
-rw-r--r--src/server.cpp67
-rw-r--r--src/server.h8
-rw-r--r--src/util/string.h24
8 files changed, 124 insertions, 14 deletions
diff --git a/builtin/game/chatcommands.lua b/builtin/game/chatcommands.lua
index 8df3903d2..25cc06178 100644
--- a/builtin/game/chatcommands.lua
+++ b/builtin/game/chatcommands.lua
@@ -763,14 +763,20 @@ core.register_chatcommand("days", {
core.register_chatcommand("shutdown", {
description = "Shutdown server",
- params = "[reconnect] [message]",
+ params = "[delay_in_seconds(0..inf) or -1 for cancel] [reconnect] [message]",
privs = {server=true},
func = function(name, param)
- core.log("action", name .. " shuts down server")
- core.chat_send_all("*** Server shutting down (operator request).")
- local reconnect, message = param:match("([^ ]+)(.*)")
+ local delay, reconnect, message = param:match("([^ ][-]?[0-9]+)([^ ]+)(.*)")
message = message or ""
- core.request_shutdown(message:trim(), core.is_yes(reconnect))
+
+ if delay ~= "" then
+ delay = tonumber(param) or 0
+ else
+ delay = 0
+ core.log("action", name .. " shuts down server")
+ core.chat_send_all("*** Server shutting down (operator request).")
+ end
+ core.request_shutdown(message:trim(), core.is_yes(reconnect), delay)
end,
})
diff --git a/builtin/game/misc.lua b/builtin/game/misc.lua
index 618d4d97f..a3eb26ac2 100644
--- a/builtin/game/misc.lua
+++ b/builtin/game/misc.lua
@@ -173,3 +173,8 @@ end
function core.close_formspec(player_name, formname)
return minetest.show_formspec(player_name, formname, "")
end
+
+function core.cancel_shutdown_requests()
+ core.request_shutdown("", false, -1)
+end
+
diff --git a/doc/lua_api.txt b/doc/lua_api.txt
index 721f5448a..7b967726d 100644
--- a/doc/lua_api.txt
+++ b/doc/lua_api.txt
@@ -2576,8 +2576,12 @@ These functions return the leftover itemstack.
* Optional: Variable number of arguments that are passed to `func`
### Server
-* `minetest.request_shutdown([message],[reconnect])`: request for server shutdown. Will display `message` to clients,
- and `reconnect` == true displays a reconnect button.
+* `minetest.request_shutdown([message],[reconnect],[delay])`: request for server shutdown. Will display `message` to clients,
+ `reconnect` == true displays a reconnect button,
+ `delay` adds an optional delay (in seconds) before shutdown
+ negative delay cancels the current active shutdown
+ zero delay triggers an immediate shutdown.
+* `minetest.cancel_shutdown_requests()`: cancel current delayed shutdown
* `minetest.get_server_status()`: returns server status string
* `minetest.get_server_uptime()`: returns the server uptime in seconds
diff --git a/src/network/serverpackethandler.cpp b/src/network/serverpackethandler.cpp
index 27c33a4f6..2e4c5b6be 100644
--- a/src/network/serverpackethandler.cpp
+++ b/src/network/serverpackethandler.cpp
@@ -722,6 +722,13 @@ void Server::handleCommand_ClientReady(NetworkPacket* pkt)
m_clients.event(peer_id, CSE_SetClientReady);
m_script->on_joinplayer(playersao);
+ // Send shutdown timer if shutdown has been scheduled
+ if (m_shutdown_timer > 0.0f) {
+ std::wstringstream ws;
+ ws << L"*** Server shutting down in "
+ << duration_to_string(round(m_shutdown_timer)).c_str() << ".";
+ SendChatMessage(pkt->getPeerId(), ws.str());
+ }
}
void Server::handleCommand_GotBlocks(NetworkPacket* pkt)
diff --git a/src/script/lua_api/l_server.cpp b/src/script/lua_api/l_server.cpp
index b6d44e0ff..343d11b7e 100644
--- a/src/script/lua_api/l_server.cpp
+++ b/src/script/lua_api/l_server.cpp
@@ -33,7 +33,8 @@ int ModApiServer::l_request_shutdown(lua_State *L)
NO_MAP_LOCK_REQUIRED;
const char *msg = lua_tolstring(L, 1, NULL);
bool reconnect = lua_toboolean(L, 2);
- getServer(L)->requestShutdown(msg ? msg : "", reconnect);
+ float seconds_before_shutdown = lua_tonumber(L, 3);
+ getServer(L)->requestShutdown(msg ? msg : "", reconnect, seconds_before_shutdown);
return 0;
}
diff --git a/src/server.cpp b/src/server.cpp
index 7ed8a8bf4..5328b6897 100644
--- a/src/server.cpp
+++ b/src/server.cpp
@@ -177,6 +177,7 @@ Server::Server(
m_clients(&m_con),
m_shutdown_requested(false),
m_shutdown_ask_reconnect(false),
+ m_shutdown_timer(0.0f),
m_admin_chat(iface),
m_ignore_map_edit_events(false),
m_ignore_map_edit_events_peer_id(0),
@@ -1029,6 +1030,39 @@ void Server::AsyncRunStep(bool initial_step)
m_env->saveMeta();
}
}
+
+ // Timed shutdown
+ static const float shutdown_msg_times[] =
+ {
+ 1, 2, 3, 4, 5, 10, 15, 20, 25, 30, 45, 60, 120, 180, 300, 600, 1200, 1800, 3600
+ };
+
+ if (m_shutdown_timer > 0.0f) {
+ // Automated messages
+ if (m_shutdown_timer < shutdown_msg_times[ARRLEN(shutdown_msg_times) - 1]) {
+ for (u16 i = 0; i < ARRLEN(shutdown_msg_times) - 1; i++) {
+ // If shutdown timer matches an automessage, shot it
+ if (m_shutdown_timer > shutdown_msg_times[i] &&
+ m_shutdown_timer - dtime < shutdown_msg_times[i]) {
+ std::wstringstream ws;
+
+ ws << L"*** Server shutting down in "
+ << duration_to_string(round(m_shutdown_timer - dtime)).c_str()
+ << ".";
+
+ infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
+ SendChatMessage(PEER_ID_INEXISTENT, ws.str());
+ break;
+ }
+ }
+ }
+
+ m_shutdown_timer -= dtime;
+ if (m_shutdown_timer < 0.0f) {
+ m_shutdown_timer = 0.0f;
+ m_shutdown_requested = true;
+ }
+ }
}
void Server::Receive()
@@ -3443,6 +3477,39 @@ v3f Server::findSpawnPos()
return nodeposf;
}
+void Server::requestShutdown(const std::string &msg, bool reconnect, float delay)
+{
+ if (delay == 0.0f) {
+ // No delay, shutdown immediately
+ m_shutdown_requested = true;
+ } else if (delay < 0.0f && m_shutdown_timer > 0.0f) {
+ // Negative delay, cancel shutdown if requested
+ m_shutdown_timer = 0.0f;
+ m_shutdown_msg = "";
+ m_shutdown_ask_reconnect = false;
+ m_shutdown_requested = false;
+ std::wstringstream ws;
+
+ ws << L"*** Server shutdown canceled.";
+
+ infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
+ SendChatMessage(PEER_ID_INEXISTENT, ws.str());
+ } else if (delay > 0.0f) {
+ // Positive delay, delay the shutdown
+ m_shutdown_timer = delay;
+ m_shutdown_msg = msg;
+ m_shutdown_ask_reconnect = reconnect;
+ std::wstringstream ws;
+
+ ws << L"*** Server shutting down in "
+ << duration_to_string(round(m_shutdown_timer)).c_str()
+ << ".";
+
+ infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
+ SendChatMessage(PEER_ID_INEXISTENT, ws.str());
+ }
+}
+
PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id, u16 proto_version)
{
bool newplayer = false;
diff --git a/src/server.h b/src/server.h
index 1df9d0a93..e2445f833 100644
--- a/src/server.h
+++ b/src/server.h
@@ -226,12 +226,7 @@ public:
inline bool getShutdownRequested() const { return m_shutdown_requested; }
// request server to shutdown
- void requestShutdown(const std::string &msg, bool reconnect)
- {
- m_shutdown_requested = true;
- m_shutdown_msg = msg;
- m_shutdown_ask_reconnect = reconnect;
- }
+ void requestShutdown(const std::string &msg, bool reconnect, float delay = 0.0f);
// Returns -1 if failed, sound handle on success
// Envlock
@@ -602,6 +597,7 @@ private:
bool m_shutdown_requested;
std::string m_shutdown_msg;
bool m_shutdown_ask_reconnect;
+ float m_shutdown_timer;
ChatInterface *m_admin_chat;
std::string m_admin_nick;
diff --git a/src/util/string.h b/src/util/string.h
index 572c37150..c155d2f4a 100644
--- a/src/util/string.h
+++ b/src/util/string.h
@@ -614,4 +614,28 @@ inline const char *bool_to_cstr(bool val)
return val ? "true" : "false";
}
+inline const std::string duration_to_string(int sec)
+{
+ int min = floor(sec / 60);
+ sec %= 60;
+ int hour = floor(min / 60);
+ min %= 60;
+
+ std::stringstream ss;
+ if (hour > 0) {
+ ss << hour << "h ";
+ }
+
+ if (min > 0) {
+ ss << min << "m ";
+ }
+
+ if (sec > 0) {
+ ss << sec << "s ";
+ }
+
+ return ss.str();
+}
+
+
#endif