/// <summary> /// Called when the who admin command is executed. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">An <see cref="AdminCommandEventArgs"/> object containing the event data.</param> private void OnWhoCommandExecuted(object sender, AdminCommandEventArgs e) { if (this.ShouldReplyToChat(e.Client)) { this.ReplyToCommand(e.Client, "See console for output"); } SdtdConsole.Instance.Output(this.GetString("Who Columns", e.Client)); foreach (var client in GameManager.Instance.World.Players.dict.Values) { var player = ConnectionManager.Instance.Clients.ForEntityId(client.entityId); var admin = AdminManager.GetAdmin(player.playerId); var flags = string.Empty; if (admin.Flags == 0) { flags = this.GetString("none", e.Client); } else if ((admin.Flags & AdminFlags.Root) == AdminFlags.Root) { flags = this.GetString("root", e.Client); } else { foreach (var keyValue in AdminManager.AdminFlagKeys) { if ((admin.Flags & keyValue.Value) == keyValue.Value) { flags += keyValue.Key; } } } SdtdConsole.Instance.Output($" {player.playerName, -24} {player.playerId, -18} {flags}"); } }
/// <summary> /// Called when the addban admin command is executed. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">An <see cref="AdminCommandEventArgs"/> object containing the event data.</param> private void OnAddbanCommandExecuted(object sender, AdminCommandEventArgs e) { if (e.Arguments.Count < 1) { e.Command.PrintUsage(e.Client, "<playerId> <{0:t}|0> [{1:t}]", "minutes", "reason"); return; } if (!ConsoleHelper.ParseParamSteamIdValid(e.Arguments[0])) { this.ReplyToCommand(e.Client, "Invalid player ID"); return; } if (!uint.TryParse(e.Arguments[1], out var duration)) { this.ReplyToCommand(e.Client, "Invalid ban duration"); return; } var reason = e.Arguments.Count > 2 ? string.Join(" ", e.Arguments.GetRange(2, e.Arguments.Count - 2).ToArray()) : string.Empty; this.LogAction(e.Client, null, "\"{0:L}\" added ban (minutes \"{1:d}\") (id \"{2:s}\") (reason \"{3:s}\")", e.Client, duration, e.Arguments[0], reason); var unit = "minutes"; if (duration == 0) { unit = "years"; duration = 1000; } SdtdConsole.Instance.ExecuteSync($"ban add {e.Arguments[0]} {duration} {unit} \"{reason}\"", null); }
/// <summary> /// Called when the kick admin command is executed. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">An <see cref="AdminCommandEventArgs"/> object containing the event data.</param> private void OnCvarCommandExecuted(object sender, AdminCommandEventArgs e) { if (e.Arguments.Count < 1) { e.Command.PrintUsage(e.Client, "<cvar> [{0:t}]", "value"); return; } var cvar = this.FindConVar(e.Arguments[0]); if (cvar == null) { this.ReplyToCommand(e.Client, "Unable to find ConVar", e.Arguments[0]); return; } if (e.Arguments.Count == 1) { this.ReplyToCommand(e.Client, "Value of ConVar", cvar.Name, cvar.Value.AsString); } else { cvar.Value.Value = string.Join(" ", e.Arguments.GetRange(1, e.Arguments.Count - 1).ToArray()); this.LogAction(e.Client, null, "\"{0:L}\" changed cvar (cvar \"{1:s}\") (value \"{2:s}\")", e.Client, cvar.Name, cvar.Value.AsString); this.ReplyToCommand(e.Client, "Changed ConVar", cvar.Name, cvar.Value.AsString); } }
/// <summary> /// Called when the unban admin command is executed. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">An <see cref="AdminCommandEventArgs"/> object containing the event data.</param> private void OnUnbanCommandExecuted(object sender, AdminCommandEventArgs e) { if (!this.unban.AsBool) { this.ReplyToCommand(e.Client, "Unban Disabled", this.website.AsString); return; } if (e.Arguments.Count < 1) { e.Command.PrintUsage(e.Client, "<playerId|ip> [{0:t}]", "reason"); return; } var prefix = this.databasePrefix.AsString; if (SteamUtils.NormalizeSteamId(e.Arguments[0], out var playerId)) { var auth = GetAuth(playerId); this.database.TQuery($"SELECT bid FROM {prefix}_bans WHERE (type = 0 AND authid = '{auth}') AND (length = '0' OR ends > UNIX_TIMESTAMP()) AND RemoveType IS NULL", e).QueryCompleted += this.OnUnbanQueryCompleted; } else { var ip = this.database.Escape(e.Arguments[0]); this.database.TQuery($"SELECT bid FROM {prefix}_bans WHERE (type = 1 AND ip = '{ip}') AND (length = '0' OR ends > UNIX_TIMESTAMP()) AND RemoveType IS NULL", e).QueryCompleted += this.OnUnbanQueryCompleted; } }
/// <summary> /// Called when the ban admin command is executed. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">An <see cref="AdminCommandEventArgs"/> object containing the event data.</param> private void OnBanCommandExecuted(object sender, AdminCommandEventArgs e) { if (e.Arguments.Count < 2) { e.Command.PrintUsage(e.Client, "<{0:t}> <{1:t}|0> [{2:t}]", "target", "minutes", "reason"); return; } if (!uint.TryParse(e.Arguments[1], out var duration)) { this.ReplyToCommand(e.Client, "Invalid ban duration"); return; } if (this.ParseSingleTargetString(e.Client, e.Arguments[0], out var target)) { var reason = e.Arguments.Count > 2 ? string.Join(" ", e.Arguments.GetRange(2, e.Arguments.Count - 2).ToArray()) : string.Empty; this.LogAction(e.Client, target, "\"{0:L}\" banned \"{1:L}\" (minutes \"{2:d}\") (reason \"{3:s}\")", e.Client, target, duration, reason); var unit = "minutes"; if (duration == 0) { unit = "years"; duration = 1000; this.ShowActivity(e.Client, "Permabanned player", target.PlayerName); } else { this.ShowActivity(e.Client, "Banned player", target.PlayerName, duration); } SdtdConsole.Instance.ExecuteSync($"ban add {target.PlayerId} {duration} {unit} \"{reason}\"", null); } }
/// <summary> /// Called when the ban admin command is executed. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">An <see cref="AdminCommandEventArgs"/> object containing the event data.</param> private void OnBanCommandExecuted(object sender, AdminCommandEventArgs e) { if (e.Arguments.Count < 2) { e.Command.PrintUsage(e.Client, "<{0:t}> <{1:t}|0> [{2:t}]", "target", "minutes", "reason"); return; } if (!uint.TryParse(e.Arguments[1], out var duration)) { this.ReplyToCommand(e.Client, "Invaid ban duration"); return; } if (duration == 0 && !AdminManager.CheckAccess(e.Client, AdminFlags.Unban)) { this.ReplyToCommand(e.Client, "No Perm Ban"); return; } if (this.ParseSingleTargetString(e.Client, e.Arguments[0], out var target)) { var reason = (e.Arguments.Count > 2) ? string.Join(" ", e.Arguments.GetRange(2, e.Arguments.Count - 2).ToArray()) : string.Empty; this.LogAction(e.Client, target, "\"{0:L}\" banned \"{1:L}\" (minutes \"{2:d}\") (reason \"{3:s}\")", e.Client, target, duration, reason); if (string.IsNullOrEmpty(reason)) { if (duration == 0) { this.ShowActivity(e.Client, "Permabanned player", target.PlayerName); } else { this.ShowActivity(e.Client, "Banned player", target.PlayerName, duration); } } else { if (duration == 0) { this.ShowActivity(e.Client, "Permabanned player reason", target.PlayerName, reason); } else { this.ShowActivity(e.Client, "Banned player reason", target.PlayerName, duration, reason); } } var auth = GetAuth(target.PlayerId); var name = this.database.Escape(target.PlayerName); duration *= 60; reason = this.database.Escape(reason); var adminAuth = (e.Client != null) ? GetAuth(e.Client.PlayerId) : "STEAM_ID_SERVER"; var adminIp = (e.Client != null) ? e.Client.Ip : string.Empty; this.InsertBan(auth, target.Ip, name, GetTime(), duration, reason, adminAuth, adminIp); this.ServerCommand(this.GetString("Kick Command", target, target.PlayerId, this.website.AsString)); this.ReplyToCommand(e.Client, "Player Banned", name); } }
/// <summary> /// Called when the slay admin command is executed. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">An <see cref="AdminCommandEventArgs"/> object containing the event data.</param> private void OnSlayCommandExecuted(object sender, AdminCommandEventArgs e) { if (e.Arguments.Count < 1) { e.Command.PrintUsage(e.Client, "<{0:t}>", "target"); return; } if (this.ParseTargetString(e.Client, e.Arguments[0], out var targets, out var targetName, out var nameIsPhrase) > 0) { if (nameIsPhrase) { this.ShowActivity(e.Client, "Slayed target", targetName); } else if (targetName != null) { this.ShowActivity(e.Client, "Slayed player", targetName); } foreach (var target in targets) { this.LogAction(e.Client, target, "\"{0:L}\" slayed \"{1:L}\"", e.Client, target); if (targetName == null) { this.ShowActivity(e.Client, "Slayed player", target.PlayerName); } SdtdConsole.Instance.ExecuteSync($"kill {target.PlayerId}", null); } } }
/// <summary> /// Called when the rehash admin command is executed. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">An <see cref="AdminCommandEventArgs"/> object containing the event data.</param> private void OnRehashCommandExecuted(object sender, AdminCommandEventArgs e) { if (this.enableAdmins.AsBool) { this.LogAction(e.Client, null, "\"{0:L}\" refreshed the admin cache.", e.Client); AdminManager.ReloadAdmins(); } }
/// <summary> /// Called when the bloodmoon admin command is executed. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">An <see cref="AdminCommandEventArgs"/> object containing the event data.</param> private void OnBloodmoonCommandExecuted(object sender, AdminCommandEventArgs e) { var days = this.GetDays(); var message = this.GetMessage(days); if (!this.ShouldReplyToChat(e.Client)) { this.ReplyToCommand(e.Client, message, days); } this.PrintToChatAll(message, days); }
/// <summary> /// Called when the chat admin command is executed. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">An <see cref="AdminCommandEventArgs"/> object containing the event data.</param> private void OnChatCommandExecuted(object sender, AdminCommandEventArgs e) { if (e.Arguments.Count < 1) { e.Command.PrintUsage(e.Client, "<{0:t}>", "message"); return; } var message = string.Join(" ", e.Arguments.ToArray()); this.SendChatToAdmins(e.Client, message); }
/// <summary> /// Called when the rcon admin command is executed. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">An <see cref="AdminCommandEventArgs"/> object containing the event data.</param> private void OnRconCommandExecuted(object sender, AdminCommandEventArgs e) { if (e.Arguments.Count < 1) { e.Command.PrintUsage(e.Client, "<{0:t}>", "command"); return; } var command = string.Join(" ", e.Arguments.ToArray()); this.LogAction(e.Client, null, "\"{0:L}\" console command (cmdline \"{1:s}\")", e.Client, command); this.ServerCommand(command); }
/// <summary> /// Called when the addban admin command is executed. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">An <see cref="AdminCommandEventArgs"/> object containing the event data.</param> private void OnAddbanCommandExecuted(object sender, AdminCommandEventArgs e) { if (!this.addban.AsBool) { this.ReplyToCommand(e.Client, "Addban Disabled"); return; } if (e.Arguments.Count < 2) { e.Command.PrintUsage(e.Client, "<{0:t}|0> <playerId> [{1:t}]", "minutes", "reason"); return; } if (!uint.TryParse(e.Arguments[0], out var duration)) { this.ReplyToCommand(e.Client, "Invaid ban duration"); return; } if (duration == 0 && !AdminManager.CheckAccess(e.Client, AdminFlags.Unban)) { return; } if (SteamUtils.NormalizeSteamId(e.Arguments[1], out var playerId)) { var auth = GetAuth(playerId); var reason = (e.Arguments.Count > 2) ? string.Join(" ", e.Arguments.GetRange(2, e.Arguments.Count - 2).ToArray()) : string.Empty; this.LogAction(e.Client, null, "\"{0:L}\" added ban (minutes \"{1:d}\") (id \"{2:s}\") (reason \"{3:s})", e.Client, 0, auth, reason); duration *= 60; reason = this.database.Escape(reason); var adminAuth = (e.Client != null) ? GetAuth(e.Client.PlayerId) : "STEAM_ID_SERVER"; var adminIp = (e.Client != null) ? e.Client.Ip : string.Empty; this.InsertBan(auth, string.Empty, string.Empty, GetTime(), duration, reason, adminAuth, adminIp); var target = ClientHelper.ForPlayerId(playerId); if (target != null) { this.ServerCommand(this.GetString("Kick Command", target, target.PlayerId, this.website.AsString)); } this.ReplyToCommand(e.Client, "Player Banned", playerId); } else { this.ReplyToCommand(e.Client, "Invalid player ID", e.Arguments[1]); } }
/// <summary> /// Called when the kick admin command is executed. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">An <see cref="AdminCommandEventArgs"/> object containing the event data.</param> private void OnKickCommandExecuted(object sender, AdminCommandEventArgs e) { if (e.Arguments.Count < 1) { e.Command.PrintUsage(e.Client, "<{0:t}> [{1:t}]", "target", "reason"); return; } if (this.ParseTargetString(e.Client, e.Arguments[0], out var targets, out var targetName, out var nameIsPhrase) > 0) { var reason = e.Arguments.Count > 1 ? string.Join(" ", e.Arguments.GetRange(1, e.Arguments.Count - 1).ToArray()) : string.Empty; if (nameIsPhrase) { this.ShowActivity(e.Client, "Kicked target", targetName); } else if (targetName != null) { this.ShowActivity(e.Client, "Kicked player", targetName); } SMClient self = null; foreach (var target in targets) { this.LogAction(e.Client, target, "\"{0:L}\" kicked \"{1:L}\" (reason \"{2:s}\")", e.Client, target, reason); if (target == e.Client) { self = target; } else { if (targetName == null) { this.ShowActivity(e.Client, "Kicked player", target.PlayerName); } SdtdConsole.Instance.ExecuteSync($"kick {target.PlayerId} \"{reason}\"", null); } } if (self != null) { if (targetName == null) { this.ShowActivity(e.Client, "Kicked player", self.PlayerName); } SdtdConsole.Instance.ExecuteSync($"kick {self.PlayerId} \"{reason}\"", null); } } }
/// <summary> /// Called when the cancelvote admin command is executed. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">An <see cref="AdminCommandEventArgs"/> object containing the event data.</param> private void OnCancelvoteCommandExecuted(object sender, AdminCommandEventArgs e) { if (!VoteManager.VoteInProgress) { this.ReplyToCommand(e.Client, "Vote not in progress"); return; } VoteManager.CurrentVote.Cancel(); this.ShowActivity(e.Client, "Cancelled vote"); if (!this.ShouldReplyToChat(e.Client)) { this.ReplyToCommand(e.Client, "Cancelled vote"); } }
/// <summary> /// Called when the unban admin command is executed. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">An <see cref="AdminCommandEventArgs"/> object containing the event data.</param> private void OnUnbanCommandExecuted(object sender, AdminCommandEventArgs e) { if (e.Arguments.Count < 1) { e.Command.PrintUsage(e.Client, "<playerId>"); return; } if (!ConsoleHelper.ParseParamSteamIdValid(e.Arguments[0])) { this.ReplyToCommand(e.Client, "Invalid player ID"); return; } this.LogAction(e.Client, null, "\"{0:L}\" removed ban (filter \"{1:s}\")", e.Client, e.Arguments[0]); SdtdConsole.Instance.ExecuteSync($"ban remove {e.Arguments[0]}", null); }
/// <summary> /// Called when the psay admin command is executed. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">An <see cref="AdminCommandEventArgs"/> object containing the event data.</param> private void OnPsayCommandExecuted(object sender, AdminCommandEventArgs e) { if (e.Arguments.Count < 2) { e.Command.PrintUsage(e.Client, "<{0:t}> <{1:t}>", "target", "message"); return; } if (!this.ParseSingleTargetString(e.Client, e.Arguments[0], out var target)) { this.ReplyToCommand(e.Client, "Player not found"); return; } var message = string.Join(" ", e.Arguments.GetRange(1, e.Arguments.Count - 1).ToArray()); this.SendPrivateChat(e.Client, target, message); }
/// <summary> /// Called when the voteban admin command is executed. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">An <see cref="AdminCommandEventArgs"/> object containing the event data.</param> private void OnVotebanCommandExecuted(object sender, AdminCommandEventArgs e) { if (e.Arguments.Count < 1) { e.Command.PrintUsage(e.Client, "<{0:t}>", "target"); return; } if (this.ParseSingleTargetString(e.Client, e.Arguments[0], out var target)) { if (VoteManager.CreateVote("Voteban Started", target.PlayerName).SetData(target).Start()) { this.LogAction(e.Client, target, "\"{0:L}\" initiated a ban vote against \"{1:L}\"", e.Client, target); this.ShowActivity(e.Client, "Initiated Vote Ban", target.PlayerName); VoteManager.CurrentVote.Ended += this.OnBanVoteEnded; } } }
/// <summary> /// Called when the cancelshutdown admin command is executed. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">An <see cref="AdminCommandEventArgs"/> object containing the event data.</param> private void OnCancelshutdownCommandExecuted(object sender, AdminCommandEventArgs e) { if (this.shutdownInProgress) { this.ScheduleNext(); this.ShowActivity(e.Client, $"Cancelled {(this.autoRestart.AsBool ? "Restart" : "Shutdown")}"); if (!this.ShouldReplyToChat(e.Client)) { this.ReplyToCommand(e.Client, $"Cancelled {(this.autoRestart.AsBool ? "Restart" : "Shutdown")}"); } this.LogAction(e.Client, null, "\"{0:L}\" cancelled the server shutdown", e.Client); } else { this.ReplyToCommand(e.Client, $"No {(this.autoRestart.AsBool ? "restart" : "shutdown")} in progress"); } }
/// <summary> /// Called when the voteshutdown admin command is executed. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">An <see cref="AdminCommandEventArgs"/> object containing the event data.</param> private void OnVoteshutdownCommandExecuted(object sender, AdminCommandEventArgs e) { if (!this.enableVote.AsBool) { return; } if (this.shutdownInProgress) { this.ReplyToCommand(e.Client, $"{(this.autoRestart.AsBool ? "Restart" : "Shutdown")} In Progress"); return; } if (VoteManager.CreateVote($"{(this.autoRestart.AsBool ? "Restart" : "Shutdown")} Vote").Start()) { this.ShowActivity(e.Client, $"Initiated Vote {(this.autoRestart.AsBool ? "Restart" : "Shutdown")}"); this.LogAction(e.Client, null, "\"{0:L}\" initiated a server shutdown vote", e.Client); VoteManager.CurrentVote.Ended += this.OnShutdownVoteEnded; } }
/// <summary> /// Called when the vote admin command is executed. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">An <see cref="AdminCommandEventArgs"/> object containing the event data.</param> private void OnVoteCommandExecuted(object sender, AdminCommandEventArgs e) { if (e.Arguments.Count < 1) { e.Command.PrintUsage(e.Client, "<{0:t}> [{1:t}] ...", "question", "option"); return; } if (e.Arguments.Count > 5) { this.ReplyToCommand(e.Client, "Too many options"); return; } if (VoteManager.CreateVote(e.Arguments[0]).SetOptions(e.Arguments.GetRange(1, e.Arguments.Count - 1)).Start()) { this.LogAction(e.Client, null, "\"{0:L}\" initiated a generic vote.", e.Client); this.ShowActivity(e.Client, "Initiated Vote", e.Arguments[0]); VoteManager.CurrentVote.Ended += this.OnVoteEnded; } }
/// <summary> /// Called when the kick admin command is executed. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">An <see cref="AdminCommandEventArgs"/> object containing the event data.</param> private void OnResetcvarCommandExecuted(object sender, AdminCommandEventArgs e) { if (e.Arguments.Count < 1) { e.Command.PrintUsage(e.Client, "<cvar>"); return; } var name = string.Join(" ", e.Arguments.ToArray()); var cvar = this.FindConVar(name); if (cvar == null) { this.ReplyToCommand(e.Client, "Unable to find ConVar", name); return; } cvar.Reset(); this.LogAction(e.Client, null, "\"{0:L}\" reset cvar (cvar \"{1:s}\") (value \"{2:s}\")", e.Client, cvar.Name, cvar.Value.AsString); this.ReplyToCommand(e.Client, "Changed ConVar", cvar.Name, cvar.Value.AsString); }
/// <summary> /// Called when the help admin command is executed. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">An <see cref="AdminCommandEventArgs"/> object containing the event data.</param> private void OnHelpCommandExecuted(object sender, AdminCommandEventArgs e) { if (this.ShouldReplyToChat(e.Client)) { this.ReplyToCommand(e.Client, "See console for output"); } var page = 1; if (e.Arguments.Count > 0) { int.TryParse(e.Arguments[0], out page); } SdtdConsole.Instance.Output(this.GetString("Command Information", e.Client)); var start = Math.Max(0, page - 1) * CommandsPerPage; var list = AdminCommandManager.Commands.Where((AdminCommand c) => c.HasAccess(e.Client)).OrderBy((AdminCommand c) => c.Command).ToArray(); if (start >= list.Length) { SdtdConsole.Instance.Output(this.GetString("No commands available", e.Client)); return; } var noDescription = this.GetString("No description available", e.Client); var end = Math.Min(start + CommandsPerPage - 1, list.Length - 1); for (var i = start; i <= end; i++) { var desc = string.IsNullOrEmpty(list[i].Description) ? noDescription : this.GetString(list[i].Description, e.Client); SdtdConsole.Instance.Output($"[{i + 1:D3}] sm {list[i].Command} - {desc}"); } SdtdConsole.Instance.Output(this.GetString("Entries", e.Client, start + 1, end + 1, page)); if (end < list.Length - 2) { SdtdConsole.Instance.Output(this.GetString("See More Commands", e.Client, page + 1)); } }
/// <summary> /// Called when the searchcmd admin command is executed. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">An <see cref="AdminCommandEventArgs"/> object containing the event data.</param> private void OnSearchcmdCommandExecuted(object sender, AdminCommandEventArgs e) { if (this.ShouldReplyToChat(e.Client)) { this.ReplyToCommand(e.Client, "See console for output"); } var search = e.Arguments.Count > 0 ? e.Arguments[0] : string.Empty; var list = AdminCommandManager.Commands.Where((AdminCommand c) => c.HasAccess(e.Client) && c.Command.Contains(search)).OrderBy((AdminCommand c) => c.Command).ToArray(); if (list.Length < 1) { SdtdConsole.Instance.Output(this.GetString("No matching results found", e.Client)); return; } var noDescription = this.GetString("No description available", e.Client); for (var i = 0; i < list.Length; i++) { var desc = string.IsNullOrEmpty(list[i].Description) ? noDescription : this.GetString(list[i].Description, e.Client); SdtdConsole.Instance.Output($"[{i + 1:D3}] sm {list[i].Command} - {desc}"); } }
/// <summary> /// Called when the restart admin command is executed. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">An <see cref="AdminCommandEventArgs"/> object containing the event data.</param> private void OnRestartCommandExecuted(object sender, AdminCommandEventArgs e) { if (!this.enableRestartCommand.AsBool) { return; } if (this.shutdownInProgress) { this.ReplyToCommand(e.Client, "Restart In Progress"); return; } this.countdown = this.countdownTime.AsInt; if (e.Arguments.Count > 0 && int.TryParse(e.Arguments[0], out var countdown)) { this.countdown = Math.Max(1, Math.Min(20, countdown)); } this.ReplyToCommand(e.Client, "Restart Countdown Started"); this.ShowActivity(e.Client, "Initiated Restart"); this.LogAction(e.Client, null, "\"{0:L}\" initiated a server shutdown (countdown \"{1:d}\")", e.Client, this.countdown); this.CountDown(); }