mirror of
https://github.com/luanti-org/luanti.git
synced 2025-08-11 17:51:04 +00:00
Server: move shutdown parts to a specific shutdown state object (#7437)
* Server: move shutdown parts to a specific shutdown state object
This commit is contained in:
parent
10634f0443
commit
9a1d3584c2
7 changed files with 296 additions and 137 deletions
270
src/server.cpp
270
src/server.cpp
|
@ -139,7 +139,60 @@ v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
|
|||
return v3f(0,0,0);
|
||||
}
|
||||
|
||||
void Server::ShutdownState::reset()
|
||||
{
|
||||
m_timer = 0.0f;
|
||||
message.clear();
|
||||
should_reconnect = false;
|
||||
is_requested = false;
|
||||
}
|
||||
|
||||
void Server::ShutdownState::trigger(float delay, const std::string &msg, bool reconnect)
|
||||
{
|
||||
m_timer = delay;
|
||||
message = msg;
|
||||
should_reconnect = reconnect;
|
||||
}
|
||||
|
||||
void Server::ShutdownState::tick(float dtime, Server *server)
|
||||
{
|
||||
if (m_timer <= 0.0f)
|
||||
return;
|
||||
|
||||
// Timed shutdown
|
||||
static const float shutdown_msg_times[] =
|
||||
{
|
||||
1, 2, 3, 4, 5, 10, 20, 40, 60, 120, 180, 300, 600, 1200, 1800, 3600
|
||||
};
|
||||
|
||||
// Automated messages
|
||||
if (m_timer < shutdown_msg_times[ARRLEN(shutdown_msg_times) - 1]) {
|
||||
for (float t : shutdown_msg_times) {
|
||||
// If shutdown timer matches an automessage, shot it
|
||||
if (m_timer > t && m_timer - dtime < t) {
|
||||
std::wstring periodicMsg = getShutdownTimerMessage();
|
||||
|
||||
infostream << wide_to_utf8(periodicMsg).c_str() << std::endl;
|
||||
server->SendChatMessage(PEER_ID_INEXISTENT, periodicMsg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_timer -= dtime;
|
||||
if (m_timer < 0.0f) {
|
||||
m_timer = 0.0f;
|
||||
is_requested = true;
|
||||
}
|
||||
}
|
||||
|
||||
std::wstring Server::ShutdownState::getShutdownTimerMessage() const
|
||||
{
|
||||
std::wstringstream ws;
|
||||
ws << L"*** Server shutting down in "
|
||||
<< duration_to_string(myround(m_timer)).c_str() << ".";
|
||||
return ws.str();
|
||||
}
|
||||
|
||||
/*
|
||||
Server
|
||||
|
@ -174,22 +227,96 @@ Server::Server(
|
|||
{
|
||||
m_lag = g_settings->getFloat("dedicated_server_step");
|
||||
|
||||
if (path_world.empty())
|
||||
if (m_path_world.empty())
|
||||
throw ServerError("Supplied empty world path");
|
||||
|
||||
if(!gamespec.isValid())
|
||||
if (!gamespec.isValid())
|
||||
throw ServerError("Supplied invalid gamespec");
|
||||
}
|
||||
|
||||
infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
|
||||
if(m_simple_singleplayer_mode)
|
||||
infostream<<" in simple singleplayer mode"<<std::endl;
|
||||
Server::~Server()
|
||||
{
|
||||
infostream << "Server destructing" << std::endl;
|
||||
|
||||
// Send shutdown message
|
||||
SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(CHATMESSAGE_TYPE_ANNOUNCE,
|
||||
L"*** Server shutting down"));
|
||||
|
||||
if (m_env) {
|
||||
MutexAutoLock envlock(m_env_mutex);
|
||||
|
||||
infostream << "Server: Saving players" << std::endl;
|
||||
m_env->saveLoadedPlayers();
|
||||
|
||||
infostream << "Server: Kicking players" << std::endl;
|
||||
std::string kick_msg;
|
||||
bool reconnect = false;
|
||||
if (isShutdownRequested()) {
|
||||
reconnect = m_shutdown_state.should_reconnect;
|
||||
kick_msg = m_shutdown_state.message;
|
||||
}
|
||||
if (kick_msg.empty()) {
|
||||
kick_msg = g_settings->get("kick_msg_shutdown");
|
||||
}
|
||||
m_env->kickAllPlayers(SERVER_ACCESSDENIED_SHUTDOWN,
|
||||
kick_msg, reconnect);
|
||||
}
|
||||
|
||||
// Do this before stopping the server in case mapgen callbacks need to access
|
||||
// server-controlled resources (like ModStorages). Also do them before
|
||||
// shutdown callbacks since they may modify state that is finalized in a
|
||||
// callback.
|
||||
if (m_emerge)
|
||||
m_emerge->stopThreads();
|
||||
|
||||
if (m_env) {
|
||||
MutexAutoLock envlock(m_env_mutex);
|
||||
|
||||
// Execute script shutdown hooks
|
||||
infostream << "Executing shutdown hooks" << std::endl;
|
||||
m_script->on_shutdown();
|
||||
|
||||
infostream << "Server: Saving environment metadata" << std::endl;
|
||||
m_env->saveMeta();
|
||||
}
|
||||
|
||||
// Stop threads
|
||||
if (m_thread) {
|
||||
stop();
|
||||
delete m_thread;
|
||||
}
|
||||
|
||||
// Delete things in the reverse order of creation
|
||||
delete m_emerge;
|
||||
delete m_env;
|
||||
delete m_rollback;
|
||||
delete m_banmanager;
|
||||
delete m_itemdef;
|
||||
delete m_nodedef;
|
||||
delete m_craftdef;
|
||||
|
||||
// Deinitialize scripting
|
||||
infostream << "Server: Deinitializing scripting" << std::endl;
|
||||
delete m_script;
|
||||
|
||||
// Delete detached inventories
|
||||
for (auto &detached_inventory : m_detached_inventories) {
|
||||
delete detached_inventory.second;
|
||||
}
|
||||
}
|
||||
|
||||
void Server::init()
|
||||
{
|
||||
infostream << "Server created for gameid \"" << m_gamespec.id << "\"";
|
||||
if (m_simple_singleplayer_mode)
|
||||
infostream << " in simple singleplayer mode" << std::endl;
|
||||
else
|
||||
infostream<<std::endl;
|
||||
infostream<<"- world: "<<m_path_world<<std::endl;
|
||||
infostream<<"- game: "<<m_gamespec.path<<std::endl;
|
||||
infostream << std::endl;
|
||||
infostream << "- world: " << m_path_world << std::endl;
|
||||
infostream << "- game: " << m_gamespec.path << std::endl;
|
||||
|
||||
// Create world if it doesn't exist
|
||||
if(!loadGameConfAndInitWorld(m_path_world, m_gamespec))
|
||||
if (!loadGameConfAndInitWorld(m_path_world, m_gamespec))
|
||||
throw ServerError("Failed to initialize world");
|
||||
|
||||
// Create server thread
|
||||
|
@ -202,8 +329,7 @@ Server::Server(
|
|||
std::string ban_path = m_path_world + DIR_DELIM "ipban.txt";
|
||||
m_banmanager = new BanManager(ban_path);
|
||||
|
||||
m_modmgr = std::unique_ptr<ServerModManager>(new ServerModManager(
|
||||
m_path_world));
|
||||
m_modmgr = std::unique_ptr<ServerModManager>(new ServerModManager(m_path_world));
|
||||
std::vector<ModSpec> unsatisfied_mods = m_modmgr->getUnsatisfiedMods();
|
||||
// complain about mods with unsatisfied dependencies
|
||||
if (!m_modmgr->isConsistent()) {
|
||||
|
@ -214,10 +340,10 @@ Server::Server(
|
|||
MutexAutoLock envlock(m_env_mutex);
|
||||
|
||||
// Create the Map (loads map_meta.txt, overriding configured mapgen params)
|
||||
ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
|
||||
ServerMap *servermap = new ServerMap(m_path_world, this, m_emerge);
|
||||
|
||||
// Initialize scripting
|
||||
infostream<<"Server: Initializing Lua"<<std::endl;
|
||||
infostream << "Server: Initializing Lua" << std::endl;
|
||||
|
||||
m_script = new ServerScripting(this);
|
||||
|
||||
|
@ -279,74 +405,6 @@ Server::Server(
|
|||
m_csm_noderange_limit = g_settings->getU32("csm_flavour_noderange_limit");
|
||||
}
|
||||
|
||||
Server::~Server()
|
||||
{
|
||||
infostream << "Server destructing" << std::endl;
|
||||
|
||||
// Send shutdown message
|
||||
SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(CHATMESSAGE_TYPE_ANNOUNCE,
|
||||
L"*** Server shutting down"));
|
||||
|
||||
{
|
||||
MutexAutoLock envlock(m_env_mutex);
|
||||
|
||||
infostream << "Server: Saving players" << std::endl;
|
||||
m_env->saveLoadedPlayers();
|
||||
|
||||
infostream << "Server: Kicking players" << std::endl;
|
||||
std::string kick_msg;
|
||||
bool reconnect = false;
|
||||
if (getShutdownRequested()) {
|
||||
reconnect = m_shutdown_ask_reconnect;
|
||||
kick_msg = m_shutdown_msg;
|
||||
}
|
||||
if (kick_msg.empty()) {
|
||||
kick_msg = g_settings->get("kick_msg_shutdown");
|
||||
}
|
||||
m_env->kickAllPlayers(SERVER_ACCESSDENIED_SHUTDOWN,
|
||||
kick_msg, reconnect);
|
||||
}
|
||||
|
||||
// Do this before stopping the server in case mapgen callbacks need to access
|
||||
// server-controlled resources (like ModStorages). Also do them before
|
||||
// shutdown callbacks since they may modify state that is finalized in a
|
||||
// callback.
|
||||
m_emerge->stopThreads();
|
||||
|
||||
{
|
||||
MutexAutoLock envlock(m_env_mutex);
|
||||
|
||||
// Execute script shutdown hooks
|
||||
infostream << "Executing shutdown hooks" << std::endl;
|
||||
m_script->on_shutdown();
|
||||
|
||||
infostream << "Server: Saving environment metadata" << std::endl;
|
||||
m_env->saveMeta();
|
||||
}
|
||||
|
||||
// Stop threads
|
||||
stop();
|
||||
delete m_thread;
|
||||
|
||||
// Delete things in the reverse order of creation
|
||||
delete m_emerge;
|
||||
delete m_env;
|
||||
delete m_rollback;
|
||||
delete m_banmanager;
|
||||
delete m_itemdef;
|
||||
delete m_nodedef;
|
||||
delete m_craftdef;
|
||||
|
||||
// Deinitialize scripting
|
||||
infostream << "Server: Deinitializing scripting" << std::endl;
|
||||
delete m_script;
|
||||
|
||||
// Delete detached inventories
|
||||
for (auto &detached_inventory : m_detached_inventories) {
|
||||
delete detached_inventory.second;
|
||||
}
|
||||
}
|
||||
|
||||
void Server::start()
|
||||
{
|
||||
infostream << "Starting server on " << m_bind_addr.serializeString()
|
||||
|
@ -916,38 +974,7 @@ void Server::AsyncRunStep(bool initial_step)
|
|||
}
|
||||
}
|
||||
|
||||
// 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(myround(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;
|
||||
}
|
||||
}
|
||||
m_shutdown_state.tick(dtime, this);
|
||||
}
|
||||
|
||||
void Server::Receive()
|
||||
|
@ -3398,16 +3425,13 @@ void Server::requestShutdown(const std::string &msg, bool reconnect, float delay
|
|||
{
|
||||
if (delay == 0.0f) {
|
||||
// No delay, shutdown immediately
|
||||
m_shutdown_requested = true;
|
||||
m_shutdown_state.is_requested = true;
|
||||
// only print to the infostream, a chat message saying
|
||||
// "Server Shutting Down" is sent when the server destructs.
|
||||
infostream << "*** Immediate Server shutdown requested." << std::endl;
|
||||
} 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;
|
||||
} else if (delay < 0.0f && m_shutdown_state.isTimerRunning()) {
|
||||
// Negative delay, cancel shutdown if requested
|
||||
m_shutdown_state.reset();
|
||||
std::wstringstream ws;
|
||||
|
||||
ws << L"*** Server shutdown canceled.";
|
||||
|
@ -3428,9 +3452,7 @@ void Server::requestShutdown(const std::string &msg, bool reconnect, float delay
|
|||
SendChatMessage(PEER_ID_INEXISTENT, ws.str());
|
||||
}
|
||||
|
||||
m_shutdown_timer = delay;
|
||||
m_shutdown_msg = msg;
|
||||
m_shutdown_ask_reconnect = reconnect;
|
||||
m_shutdown_state.trigger(delay, msg, reconnect);
|
||||
}
|
||||
|
||||
PlayerSAO* Server::emergePlayer(const char *name, session_t peer_id, u16 proto_version)
|
||||
|
@ -3518,7 +3540,7 @@ void dedicated_server_loop(Server &server, bool &kill)
|
|||
}
|
||||
server.step(steplen);
|
||||
|
||||
if (server.getShutdownRequested() || kill)
|
||||
if (server.isShutdownRequested() || kill)
|
||||
break;
|
||||
|
||||
/*
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue