/// <summary> /// Threaded task created when performing a server shutdown /// </summary> private static void ShutdownServer() { DateTime shutdownTime = DateTime.UtcNow.AddSeconds(ShutdownInterval); // wait for shutdown interval to expire while (shutdownTime != DateTime.MinValue && shutdownTime >= DateTime.UtcNow) { // this allows the server shutdown to be canceled if (!ShutdownInitiated) { // reset shutdown details string shutdownText = $"The server has canceled the shutdown procedure @ {DateTime.UtcNow} UTC"; log.Info(shutdownText); // special text foreach (var player in WorldManager.GetAll()) { player.WorldBroadcast(shutdownText); } // break function return; } Thread.Sleep(1); } // logout each player foreach (var player in WorldManager.GetAll()) { player.LogOffPlayer(); } // wait 6 seconds for log-off Thread.Sleep(6000); // TODO: Make sure that the landblocks unloads properly. // TODO: Make sure that the databasemanager unloads properly. // disabled thread update loop and halt application WorldManager.StopWorld(); // wait for world to end while (WorldManager.WorldActive) { ; // do nothing } // write exit to console/log log.Info($"Exiting at {DateTime.UtcNow}"); // system exit Environment.Exit(Environment.ExitCode); }
/// <summary> /// Threaded task created when performing a server shutdown /// </summary> private static void ShutdownServer() { var shutdownTime = DateTime.UtcNow.AddSeconds(ShutdownInterval); ShutdownTime = shutdownTime; var lastNoticeTime = DateTime.UtcNow; // wait for shutdown interval to expire while (shutdownTime != DateTime.MinValue && shutdownTime >= DateTime.UtcNow) { // this allows the server shutdown to be canceled if (!ShutdownInitiated) { // reset shutdown details string shutdownText = $"The server has canceled the shutdown procedure @ {DateTime.UtcNow} UTC"; log.Info(shutdownText); // special text foreach (var player in PlayerManager.GetAllOnline()) { player.Session.WorldBroadcast(shutdownText); } // break function return; } lastNoticeTime = NotifyPlayersOfPendingShutdown(lastNoticeTime, shutdownTime.AddSeconds(1)); Thread.Sleep(10); } PropertyManager.ResyncVariables(); PropertyManager.StopUpdating(); log.Debug("Logging off all players..."); // logout each player foreach (var player in PlayerManager.GetAllOnline()) { player.Session.LogOffPlayer(); } log.Info("Waiting for all players to log off..."); // wait 10 seconds for log-off while (PlayerManager.GetAllOnline().Count > 0) { Thread.Sleep(10); } log.Debug("Adding all landblocks to destruction queue..."); // Queue unloading of all the landblocks // The actual unloading will happen in WorldManager.UpdateGameWorld LandblockManager.AddAllActiveLandblocksToDestructionQueue(); log.Info("Waiting for all active landblocks to unload..."); while (LandblockManager.GetLoadedLandblocks().Count > 0) { Thread.Sleep(10); } log.Debug("Stopping world..."); // Disabled thread update loop WorldManager.StopWorld(); log.Info("Waiting for world to stop..."); // Wait for world to end while (WorldManager.WorldActive) { Thread.Sleep(10); } //log.Info("Saving OfflinePlayers that have unsaved changes..."); //PlayerManager.SaveOfflinePlayersWithChanges(); log.Info("Waiting for database queue to empty..."); // Wait for the database queue to empty while (DatabaseManager.Shard.QueueCount > 0) { Thread.Sleep(10); } // Write exit to console/log log.Info($"Exiting at {DateTime.UtcNow}"); // System exit Environment.Exit(Environment.ExitCode); }
/// <summary> /// Threaded task created when performing a server shutdown /// </summary> private static void ShutdownServer() { var shutdownTime = DateTime.UtcNow.AddSeconds(ShutdownInterval); ShutdownTime = shutdownTime; var lastNoticeTime = DateTime.UtcNow; // wait for shutdown interval to expire while (shutdownTime != DateTime.MinValue && shutdownTime >= DateTime.UtcNow) { // this allows the server shutdown to be canceled if (!ShutdownInitiated) { // reset shutdown details string shutdownText = $"The server has canceled the shutdown procedure @ {DateTime.UtcNow} UTC"; log.Info(shutdownText); // special text foreach (var player in PlayerManager.GetAllOnline()) { player.Session.WorldBroadcast(shutdownText); } // break function return; } lastNoticeTime = NotifyPlayersOfPendingShutdown(lastNoticeTime, shutdownTime.AddSeconds(1)); Thread.Sleep(10); } ShutdownInProgress = true; PropertyManager.ResyncVariables(); PropertyManager.StopUpdating(); log.Debug("Logging off all players..."); // logout each player foreach (var player in PlayerManager.GetAllOnline()) { player.Session.LogOffPlayer(true); } // Wait for all players to log out var logUpdateTS = DateTime.MinValue; int playerCount; while ((playerCount = PlayerManager.GetOnlineCount()) > 0) { logUpdateTS = LogStatusUpdate(logUpdateTS, $"Waiting for {playerCount} player{(playerCount > 1 ? "s" : "")} to log off..."); Thread.Sleep(10); } log.Debug("Disconnecting all sessions..."); // disconnect each session NetworkManager.DisconnectAllSessionsForShutdown(); // Wait for all sessions to drop out logUpdateTS = DateTime.MinValue; int sessionCount; while ((sessionCount = NetworkManager.GetSessionCount()) > 0) { logUpdateTS = LogStatusUpdate(logUpdateTS, $"Waiting for {sessionCount} session{(sessionCount > 1 ? "s" : "")} to disconnect..."); Thread.Sleep(10); } log.Debug("Adding all landblocks to destruction queue..."); // Queue unloading of all the landblocks // The actual unloading will happen in WorldManager.UpdateGameWorld LandblockManager.AddAllActiveLandblocksToDestructionQueue(); // Wait for all landblocks to unload logUpdateTS = DateTime.MinValue; int landblockCount; while ((landblockCount = LandblockManager.GetLoadedLandblocks().Count) > 0) { logUpdateTS = LogStatusUpdate(logUpdateTS, $"Waiting for {landblockCount} loaded landblock{(landblockCount > 1 ? "s" : "")} to unload..."); Thread.Sleep(10); } log.Debug("Stopping world..."); // Disabled thread update loop WorldManager.StopWorld(); // Wait for world to end logUpdateTS = DateTime.MinValue; while (WorldManager.WorldActive) { logUpdateTS = LogStatusUpdate(logUpdateTS, "Waiting for world to stop..."); Thread.Sleep(10); } log.Info("Saving OfflinePlayers that have unsaved changes..."); PlayerManager.SaveOfflinePlayersWithChanges(); // Wait for the database queue to empty logUpdateTS = DateTime.MinValue; int shardQueueCount; while ((shardQueueCount = DatabaseManager.Shard.QueueCount) > 0) { logUpdateTS = LogStatusUpdate(logUpdateTS, $"Waiting for database queue ({shardQueueCount}) to empty..."); Thread.Sleep(10); } // Write exit to console/log log.Info($"Exiting at {DateTime.UtcNow}"); // System exit Environment.Exit(Environment.ExitCode); }
/// <summary> /// Threaded task created when performing a server shutdown /// </summary> private static void ShutdownServer() { var shutdownTime = DateTime.UtcNow.AddSeconds(ShutdownInterval); ShutdownTime = shutdownTime; var lastNoticeTime = DateTime.UtcNow; // wait for shutdown interval to expire while (shutdownTime != DateTime.MinValue && shutdownTime >= DateTime.UtcNow) { // this allows the server shutdown to be canceled if (!ShutdownInitiated) { // reset shutdown details string shutdownText = $"The server shut down has been cancelled @ {DateTime.Now} ({DateTime.UtcNow} UTC)"; log.Info(shutdownText); // special text foreach (var player in PlayerManager.GetAllOnline()) { player.Session.WorldBroadcast($"Broadcast from System> ATTENTION - This Asheron's Call Server shut down has been cancelled."); } // break function return; } lastNoticeTime = NotifyPlayersOfPendingShutdown(lastNoticeTime, shutdownTime.AddSeconds(1)); Thread.Sleep(10); } ShutdownInProgress = true; PropertyManager.ResyncVariables(); PropertyManager.StopUpdating(); WorldManager.EnqueueAction(new ActionEventDelegate(() => { log.Debug("Logging off all players..."); // logout each player foreach (var player in PlayerManager.GetAllOnline()) { player.Session.LogOffPlayer(true); } })); // Wait for all players to log out var logUpdateTS = DateTime.MinValue; int playerCount; var playerLogoffStart = DateTime.UtcNow; while ((playerCount = PlayerManager.GetOnlineCount()) > 0) { logUpdateTS = LogStatusUpdate(logUpdateTS, $"Waiting for {playerCount} player{(playerCount > 1 ? "s" : "")} to log off..."); Thread.Sleep(10); if (playerCount > 0 && DateTime.UtcNow - playerLogoffStart > TimeSpan.FromMinutes(5)) { playerLogoffStart = DateTime.UtcNow; log.Warn($"5 minute log off failsafe reached and there are {playerCount} player{(playerCount > 1 ? "s" : "")} still online."); foreach (var player in PlayerManager.GetAllOnline()) { log.Warn($"Player {player.Name} (0x{player.Guid}) appears to be stuck in world and unable to log off normally. Requesting Forced Logoff..."); player.ForcedLogOffRequested = true; player.ForceLogoff(); } } } WorldManager.EnqueueAction(new ActionEventDelegate(() => { log.Debug("Disconnecting all sessions..."); // disconnect each session NetworkManager.DisconnectAllSessionsForShutdown(); })); // Wait for all sessions to drop out logUpdateTS = DateTime.MinValue; int sessionCount; while ((sessionCount = NetworkManager.GetAuthenticatedSessionCount()) > 0) { logUpdateTS = LogStatusUpdate(logUpdateTS, $"Waiting for {sessionCount} authenticated session{(sessionCount > 1 ? "s" : "")} to disconnect..."); Thread.Sleep(10); } log.Debug("Adding all landblocks to destruction queue..."); // Queue unloading of all the landblocks // The actual unloading will happen in WorldManager.UpdateGameWorld LandblockManager.AddAllActiveLandblocksToDestructionQueue(); // Wait for all landblocks to unload logUpdateTS = DateTime.MinValue; int landblockCount; while ((landblockCount = LandblockManager.GetLoadedLandblocks().Count) > 0) { logUpdateTS = LogStatusUpdate(logUpdateTS, $"Waiting for {landblockCount} loaded landblock{(landblockCount > 1 ? "s" : "")} to unload..."); Thread.Sleep(10); } log.Debug("Stopping world..."); // Disabled thread update loop WorldManager.StopWorld(); // Wait for world to end logUpdateTS = DateTime.MinValue; while (WorldManager.WorldActive) { logUpdateTS = LogStatusUpdate(logUpdateTS, "Waiting for world to stop..."); Thread.Sleep(10); } log.Info("Saving OfflinePlayers that have unsaved changes..."); PlayerManager.SaveOfflinePlayersWithChanges(); // Wait for the database queue to empty logUpdateTS = DateTime.MinValue; int shardQueueCount; while ((shardQueueCount = DatabaseManager.Shard.QueueCount) > 0) { logUpdateTS = LogStatusUpdate(logUpdateTS, $"Waiting for database queue ({shardQueueCount}) to empty..."); Thread.Sleep(10); } // Write exit to console/log log.Info($"Exiting at {DateTime.UtcNow}"); // System exit Environment.Exit(Environment.ExitCode); }