using System; using log4net; using ACE.Common.Extensions; using ACE.Entity.Enum; using ACE.Server.Managers; using ACE.Server.Network; using ACE.Server.Network.GameMessages.Messages; namespace ACE.Server.Command.Handlers { public static class AdminShardCommands { private static readonly ILog log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); // // commandname parameters // [CommandHandler("commandname", AccessLevel.Admin, CommandHandlerFlag.RequiresWorld, 0)] // public static void HandleHelp(Session session, params string[] parameters) // { // //TODO: output // } /// /// Cancels an in-progress shutdown event. /// [CommandHandler("cancel-shutdown", AccessLevel.Admin, CommandHandlerFlag.None, 0, "Stops an active server shutdown.", "")] public static void HandleCancelShutdown(Session session, params string[] parameters) { var adminName = (session == null) ? "CONSOLE" : session.Player.Name; var msg = $"{adminName} has requested the pending shut down @ {ServerManager.ShutdownTime.ToLocalTime().ToCommonString()} ({ServerManager.ShutdownTime.ToCommonString()} UTC) be cancelled."; log.Info(msg); PlayerManager.BroadcastToAuditChannel(session?.Player, msg); ServerManager.CancelShutdown(); } /// /// Increase or decrease the server shutdown interval in seconds /// [CommandHandler("set-shutdown-interval", AccessLevel.Admin, CommandHandlerFlag.None, 1, "Changes the delay, in seconds, before the server will shutdown.", "< 0-99999 > in seconds")] public static void HandleSetShutdownInterval(Session session, params string[] parameters) { if (parameters?.Length > 0) { // delay server shutdown for up to x minutes // limit to uint length 65535 string parseInt = parameters[0].Length > 5 ? parameters[0].Substring(0, 5) : parameters[0]; if (uint.TryParse(parseInt, out var newShutdownInterval)) { // newShutdownInterval is represented as a time element if (newShutdownInterval > uint.MaxValue) newShutdownInterval = uint.MaxValue; var adminName = (session == null) ? "CONSOLE" : session.Player.Name; var msg = $"{adminName} has requested the shut down interval be changed from {ServerManager.ShutdownInterval} seconds to {newShutdownInterval} seconds."; //log.Info(msg); PlayerManager.BroadcastToAuditChannel(session?.Player, msg); // set the interval ServerManager.SetShutdownInterval(Convert.ToUInt32(newShutdownInterval)); // message the admin CommandHandlerHelper.WriteOutputInfo(session, $"Shutdown Interval (seconds to shutdown server) has been set to {ServerManager.ShutdownInterval}.", ChatMessageType.Broadcast); return; } } CommandHandlerHelper.WriteOutputInfo(session, "Usage: /set-shutdown-interval <00000>", ChatMessageType.Broadcast); } /// /// Immediately begins the shutdown process by setting the shutdown interval to 0 before executing the shutdown method /// [CommandHandler("stop-now", AccessLevel.Admin, CommandHandlerFlag.None, -1, "Shuts the server down, immediately!", "\nThis command will attempt to safely logoff all players, before shutting down the server.")] public static void ShutdownServerNow(Session session, params string[] parameters) { var adminName = (session == null) ? "CONSOLE" : session.Player.Name; var msg = $"{adminName} has initiated an immediate server shut down."; //log.Info(msg); PlayerManager.BroadcastToAuditChannel(session?.Player, msg); ServerManager.SetShutdownInterval(0); ShutdownServer(session, parameters); } /// /// Function to shutdown the server from console or in-game. /// [CommandHandler("shutdown", AccessLevel.Admin, CommandHandlerFlag.None, 0, "Begins the server shutdown process. Optionally displays a shutdown message, if a string is passed.", "< Optional Shutdown Message >\n" + "\tUse @cancel-shutdown to abort an active shutdown!\n" + "\tSet the shutdown delay in seconds with @set-shutdown-interval < 0-99999 >")] public static void ShutdownServer(Session session, params string[] parameters) { if (ServerManager.ShutdownInitiated) { CommandHandlerHelper.WriteOutputInfo(session, "Shutdown is already in progress.", ChatMessageType.Broadcast); return; } var adminText = ""; if (parameters.Length > 0) adminText = string.Join(" ", parameters); var adminName = (session == null) ? "CONSOLE" : session.Player.Name; var hideName = string.IsNullOrEmpty(adminText); var timeTillShutdown = TimeSpan.FromSeconds(ServerManager.ShutdownInterval); var timeRemaining = "The server will shut down in " + (timeTillShutdown.TotalSeconds > 120 ? $"{(int)timeTillShutdown.TotalMinutes} minutes." : $"{timeTillShutdown.TotalSeconds} seconds."); log.Info($"{adminName} initiated a complete server shutdown @ {DateTime.Now.ToCommonString()} ({DateTime.UtcNow.ToCommonString()} UTC)"); log.Info(timeRemaining); PlayerManager.BroadcastToAuditChannel(session?.Player, $"{adminName} initiated a complete server shutdown @ {DateTime.Now.ToCommonString()} ({DateTime.UtcNow.ToCommonString()} UTC)"); if (adminText.Length > 0) { log.Info("Admin message: " + adminText); PlayerManager.BroadcastToAuditChannel(session?.Player, $"{adminName} sent the following message for the shutdown: {adminText}"); } var sdt = timeTillShutdown; var timeHrs = $"{(sdt.Hours >= 1 ? $"{sdt.ToString("%h")}" : "")}{(sdt.Hours >= 2 ? $" hours" : sdt.Hours == 1 ? " hour" : "")}"; var timeMins = $"{(sdt.Minutes != 0 ? $"{sdt.ToString("%m")}" : "")}{(sdt.Minutes >= 2 ? $" minutes" : sdt.Minutes == 1 ? " minute" : "")}"; var timeSecs = $"{(sdt.Seconds != 0 ? $"{sdt.ToString("%s")}" : "")}{(sdt.Seconds >= 2 ? $" seconds" : sdt.Seconds == 1 ? " second" : "")}"; var time = $"{(timeHrs != "" ? timeHrs : "")}{(timeMins != "" ? $"{((timeHrs != "") ? ", " : "")}" + timeMins : "")}{(timeSecs != "" ? $"{((timeHrs != "" || timeMins != "") ? " and " : "")}" + timeSecs : "")}"; if (adminName.Equals("CONSOLE")) adminName = "System"; var genericMsgToPlayers = $"Broadcast from {(hideName ? "System": $"{adminName}")}> {(timeTillShutdown.TotalMinutes > 1.5 ? "ATTENTION" : "WARNING")} - This Asheron's Call Server will be shutting down in {time}{(sdt.TotalMinutes <= 1 ? "!" : ".")}{(timeTillShutdown.TotalMinutes <= 3 ? $" Please log out{(sdt.TotalMinutes <= 1 ? "!" : ".")}" : "")}"; if (sdt.TotalMilliseconds == 0) genericMsgToPlayers = $"Broadcast from {(hideName ? "System" : $"{adminName}")}> ATTENTION - This Asheron's Call Server is shutting down NOW!!!!"; if (!hideName) PlayerManager.BroadcastToAll(new GameMessageSystemChat($"Broadcast from {adminName}> {adminText}\n" + genericMsgToPlayers, ChatMessageType.WorldBroadcast)); else PlayerManager.BroadcastToAll(new GameMessageSystemChat(genericMsgToPlayers, ChatMessageType.WorldBroadcast)); ServerManager.BeginShutdown(); } [CommandHandler("world", AccessLevel.Admin, CommandHandlerFlag.None, 0, "Open or Close world to player access.", "[open | close] \nIf closing world, using @world close boot will force players to logoff immediately")] public static void HandleHelp(Session session, params string[] parameters) { var open = false; var close = false; var bootPlayers = false; var message = $"World is currently {WorldManager.WorldStatus.ToString()}\nPlease specify state to change\n@world [open | close] \nIf closing world, using @world close boot will force players to logoff immediately"; if (parameters.Length >= 1) { switch (parameters[0].ToLower()) { case "open": if (WorldManager.WorldStatus != WorldManager.WorldStatusState.Open) { message = "Opening world to players..."; open = true; } else { message = "World is already open."; } break; case "close": if (WorldManager.WorldStatus != WorldManager.WorldStatusState.Closed) { if (parameters.Length > 1) { if (parameters[1].ToLower() == "boot") bootPlayers = true; } message = "Closing world"; if (bootPlayers) message += ", and booting all online players."; else message += "..."; close = true; } else { message = "World is already closed."; } break; } } CommandHandlerHelper.WriteOutputInfo(session, message, ChatMessageType.WorldBroadcast); if (open) WorldManager.Open(session == null ? null : session.Player); else if (close) WorldManager.Close(session == null ? null : session.Player, bootPlayers); } } }