diff --git a/Content.Server/Chat/Managers/ChatManager.cs b/Content.Server/Chat/Managers/ChatManager.cs index 812aed80bd..79683db641 100644 --- a/Content.Server/Chat/Managers/ChatManager.cs +++ b/Content.Server/Chat/Managers/ChatManager.cs @@ -150,6 +150,14 @@ namespace Content.Server.Chat.Managers _adminLogger.Add(LogType.Chat, LogImpact.Low, $"Admin announcement: {message}"); } + public void SendAdminAnnouncementMessage(ICommonSession player, string message, bool suppressLog = true) + { + var wrappedMessage = Loc.GetString("chat-manager-send-admin-announcement-wrap-message", + ("adminChannelName", Loc.GetString("chat-manager-admin-channel-name")), + ("message", FormattedMessage.EscapeText(message))); + ChatMessageToOne(ChatChannel.Admin, message, wrappedMessage, default, false, player.Channel); + } + public void SendAdminAlert(string message) { var clients = _adminManager.ActiveAdmins.Select(p => p.Channel); diff --git a/Content.Server/Chat/Managers/IChatManager.cs b/Content.Server/Chat/Managers/IChatManager.cs index 59945bf5ca..c8c057a1ad 100644 --- a/Content.Server/Chat/Managers/IChatManager.cs +++ b/Content.Server/Chat/Managers/IChatManager.cs @@ -23,6 +23,7 @@ namespace Content.Server.Chat.Managers void SendHookOOC(string sender, string message); void SendAdminAnnouncement(string message, AdminFlags? flagBlacklist = null, AdminFlags? flagWhitelist = null); + void SendAdminAnnouncementMessage(ICommonSession player, string message, bool suppressLog = true); void SendAdminAlert(string message); void SendAdminAlert(EntityUid player, string message); diff --git a/Content.Server/GameTicking/GameTicker.GameRule.cs b/Content.Server/GameTicking/GameTicker.GameRule.cs index f52a3cb296..a6d0a4baf0 100644 --- a/Content.Server/GameTicking/GameTicker.GameRule.cs +++ b/Content.Server/GameTicking/GameTicker.GameRule.cs @@ -1,6 +1,7 @@ using System.Linq; using Content.Server.Administration; using Content.Server.GameTicking.Components; +using Content.Server.GameTicking.Rules.Components; using Content.Shared.Administration; using Content.Shared.Database; using Content.Shared.Prototypes; @@ -42,6 +43,14 @@ public sealed partial class GameTicker string.Empty, "cleargamerules", ClearGameRulesCommand); + + // List game rules command. + var localizedHelp = Loc.GetString("listgamerules-command-help"); + + _consoleHost.RegisterCommand("listgamerules", + string.Empty, + $"listgamerules - {localizedHelp}", + ListGameRuleCommand); } private void ShutdownGameRules() @@ -49,6 +58,7 @@ public sealed partial class GameTicker _consoleHost.UnregisterCommand("addgamerule"); _consoleHost.UnregisterCommand("endgamerule"); _consoleHost.UnregisterCommand("cleargamerules"); + _consoleHost.UnregisterCommand("listgamerules"); } /// @@ -64,6 +74,13 @@ public sealed partial class GameTicker var ev = new GameRuleAddedEvent(ruleEntity, ruleId); RaiseLocalEvent(ruleEntity, ref ev, true); + + var currentTime = RunLevel == GameRunLevel.PreRoundLobby ? TimeSpan.Zero : RoundDuration(); + if (!HasComp(ruleEntity) && !HasComp(ruleEntity)) + { + _allPreviousGameRules.Add((currentTime, ruleId + " (Pending)")); + } + return ruleEntity; } @@ -110,7 +127,8 @@ public sealed partial class GameTicker if (delayTime > TimeSpan.Zero) { _sawmill.Info($"Queued start for game rule {ToPrettyString(ruleEntity)} with delay {delayTime}"); - _adminLogger.Add(LogType.EventStarted, $"Queued start for game rule {ToPrettyString(ruleEntity)} with delay {delayTime}"); + _adminLogger.Add(LogType.EventStarted, + $"Queued start for game rule {ToPrettyString(ruleEntity)} with delay {delayTime}"); var delayed = EnsureComp(ruleEntity); delayed.RuleStartTime = _gameTiming.CurTime + (delayTime); @@ -118,7 +136,20 @@ public sealed partial class GameTicker } } - _allPreviousGameRules.Add((RoundDuration(), id)); + var currentTime = RunLevel == GameRunLevel.PreRoundLobby ? TimeSpan.Zero : RoundDuration(); + + // Remove the first occurrence of the pending entry before adding the started entry + var pendingRuleIndex = _allPreviousGameRules.FindIndex(rule => rule.Item2 == id + " (Pending)"); + if (pendingRuleIndex >= 0) + { + _allPreviousGameRules.RemoveAt(pendingRuleIndex); + } + + if (!HasComp(ruleEntity) && !HasComp(ruleEntity)) + { + _allPreviousGameRules.Add((currentTime, id)); + } + _sawmill.Info($"Started game rule {ToPrettyString(ruleEntity)}"); _adminLogger.Add(LogType.EventStarted, $"Started game rule {ToPrettyString(ruleEntity)}"); @@ -296,6 +327,7 @@ public sealed partial class GameTicker if (shell.Player != null) { _adminLogger.Add(LogType.EventStarted, $"{shell.Player} tried to add game rule [{rule}] via command"); + _chatManager.SendAdminAnnouncement(Loc.GetString("add-gamerule-admin", ("rule", rule), ("admin", shell.Player))); } else { @@ -306,6 +338,7 @@ public sealed partial class GameTicker // Start rule if we're already in the middle of a round if(RunLevel == GameRunLevel.InRound) StartGameRule(ent); + } } @@ -349,5 +382,42 @@ public sealed partial class GameTicker ClearGameRules(); } + [AdminCommand(AdminFlags.Admin)] + private void ListGameRuleCommand(IConsoleShell shell, string argstr, string[] args) + { + _sawmill.Info($"{shell.Player} tried to get list of game rules via command"); + _adminLogger.Add(LogType.Action, $"{shell.Player} tried to get list of game rules via command"); + var message = GetGameRulesListMessage(false); + shell.WriteLine(message); + } + private string GetGameRulesListMessage(bool forChatWindow) + { + if (_allPreviousGameRules.Count > 0) + { + var sortedRules = _allPreviousGameRules.OrderBy(rule => rule.Item1).ToList(); + var message = "\n"; + + if (!forChatWindow) + { + var header = Loc.GetString("list-gamerule-admin-header"); + message += $"\n{header}\n"; + message += "|------------|------------------\n"; + } + + foreach (var (time, rule) in sortedRules) + { + var formattedTime = time.ToString(@"hh\:mm\:ss"); + message += $"| {formattedTime,-10} | {rule,-16} \n"; + } + + return message; + } + else + { + return Loc.GetString("list-gamerule-admin-no-rules"); + + } + } + #endregion } diff --git a/Content.Server/GameTicking/GameTicker.Player.cs b/Content.Server/GameTicking/GameTicker.Player.cs index c1388f6290..61cdf6f855 100644 --- a/Content.Server/GameTicking/GameTicker.Player.cs +++ b/Content.Server/GameTicking/GameTicker.Player.cs @@ -1,4 +1,6 @@ +using System.Linq; using Content.Server.Database; +using Content.Shared.Administration; using Content.Shared.CCVar; using Content.Shared.GameTicking; using Content.Shared.GameWindow; @@ -196,6 +198,15 @@ namespace Content.Server.GameTicking _playerGameStatuses[session.UserId] = PlayerGameStatus.JoinedGame; _db.AddRoundPlayers(RoundId, session.UserId); + if (_adminManager.HasAdminFlag(session, AdminFlags.Admin)) + { + if (_allPreviousGameRules.Count > 0) + { + var rulesMessage = GetGameRulesListMessage(true); + _chatManager.SendAdminAnnouncementMessage(session, Loc.GetString("starting-rule-selected-preset", ("preset", rulesMessage))); + } + } + RaiseNetworkEvent(new TickerJoinGameEvent(), session.Channel); } diff --git a/Content.Server/GameTicking/Rules/SecretRuleSystem.cs b/Content.Server/GameTicking/Rules/SecretRuleSystem.cs index 95bf5986a5..d25262b797 100644 --- a/Content.Server/GameTicking/Rules/SecretRuleSystem.cs +++ b/Content.Server/GameTicking/Rules/SecretRuleSystem.cs @@ -46,7 +46,6 @@ public sealed class SecretRuleSystem : GameRuleSystem Log.Info($"Selected {preset.ID} as the secret preset."); _adminLogger.Add(LogType.EventStarted, $"Selected {preset.ID} as the secret preset."); - _chatManager.SendAdminAnnouncement(Loc.GetString("rule-secret-selected-preset", ("preset", preset.ID))); foreach (var rule in preset.Rules) { diff --git a/Resources/Locale/en-US/game-ticking/game-rules/gamerule-admin.ftl b/Resources/Locale/en-US/game-ticking/game-rules/gamerule-admin.ftl new file mode 100644 index 0000000000..3b31fe4663 --- /dev/null +++ b/Resources/Locale/en-US/game-ticking/game-rules/gamerule-admin.ftl @@ -0,0 +1,6 @@ +#When an admin adds a game rule +add-gamerule-admin = Game rule({$rule}) added - {$admin} +list-gamerule-admin-header = | Time | Rule added +list-gamerule-admin-no-rules = No game rules have been added. +starting-rule-selected-preset = Current gamerules in use: {$preset} +listgamerules-command-help = Lists all rules that have been added for the round so far. diff --git a/Resources/Locale/en-US/game-ticking/game-rules/rule-secret.ftl b/Resources/Locale/en-US/game-ticking/game-rules/rule-secret.ftl deleted file mode 100644 index c38220cca1..0000000000 --- a/Resources/Locale/en-US/game-ticking/game-rules/rule-secret.ftl +++ /dev/null @@ -1,2 +0,0 @@ -# Sent to admin chat -rule-secret-selected-preset = Selected {$preset} for secret.