diff options
Diffstat (limited to 'src/server.cpp')
-rw-r--r-- | src/server.cpp | 270 |
1 files changed, 146 insertions, 124 deletions
diff --git a/src/server.cpp b/src/server.cpp index 13a3b4552..67910e53a 100644 --- a/src/server.cpp +++ b/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"); +} + +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 created for gameid \""<<m_gamespec.id<<"\""; - if(m_simple_singleplayer_mode) - infostream<<" in simple singleplayer mode"<<std::endl; + 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; /* |