MotD (#13655)
* MOTD * Message of the Day * Pretty sure the tests aren't me. Let's check. * Update Content.Shared/CCVar/CCVars.cs Co-authored-by: AJCM-git <60196617+AJCM-git@users.noreply.github.com> * command dependencies and moving MOTD to its own system * Some doc comments * Let's try those tests again * More doc comments, most of the github reviews, and aliases for get-motd and set-motd * Clear test MOTD * Localized motd commands and completion hints * Makes set-motd only show up in the alias command if the player has access to it. --------- Co-authored-by: AJCM-git <60196617+AJCM-git@users.noreply.github.com>
This commit is contained in:
@@ -77,6 +77,7 @@ public sealed partial class ChatSystem : SharedChatSystem
|
|||||||
base.Shutdown();
|
base.Shutdown();
|
||||||
ShutdownEmotes();
|
ShutdownEmotes();
|
||||||
_configurationManager.UnsubValueChanged(CCVars.LoocEnabled, OnLoocEnabledChanged);
|
_configurationManager.UnsubValueChanged(CCVars.LoocEnabled, OnLoocEnabledChanged);
|
||||||
|
_configurationManager.UnsubValueChanged(CCVars.DeadLoocEnabled, OnDeadLoocEnabledChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnLoocEnabledChanged(bool val)
|
private void OnLoocEnabledChanged(bool val)
|
||||||
@@ -99,13 +100,17 @@ public sealed partial class ChatSystem : SharedChatSystem
|
|||||||
|
|
||||||
private void OnGameChange(GameRunLevelChangedEvent ev)
|
private void OnGameChange(GameRunLevelChangedEvent ev)
|
||||||
{
|
{
|
||||||
if (_configurationManager.GetCVar(CCVars.OocEnableDuringRound))
|
switch(ev.New)
|
||||||
return;
|
{
|
||||||
|
case GameRunLevel.InRound:
|
||||||
if (ev.New == GameRunLevel.InRound)
|
if(!_configurationManager.GetCVar(CCVars.OocEnableDuringRound))
|
||||||
_configurationManager.SetCVar(CCVars.OocEnabled, false);
|
_configurationManager.SetCVar(CCVars.OocEnabled, false);
|
||||||
else if (ev.New == GameRunLevel.PostRound)
|
break;
|
||||||
_configurationManager.SetCVar(CCVars.OocEnabled, true);
|
case GameRunLevel.PostRound:
|
||||||
|
if(!_configurationManager.GetCVar(CCVars.OocEnableDuringRound))
|
||||||
|
_configurationManager.SetCVar(CCVars.OocEnabled, true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
20
Content.Server/Motd/GetMOTDCommand.cs
Normal file
20
Content.Server/Motd/GetMOTDCommand.cs
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
using Content.Shared.Administration;
|
||||||
|
using Robust.Shared.Console;
|
||||||
|
|
||||||
|
namespace Content.Server.Motd;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A command that can be used by any player to print the Message of the Day.
|
||||||
|
/// </summary>
|
||||||
|
[AnyCommand]
|
||||||
|
public sealed class GetMotdCommand : LocalizedCommands
|
||||||
|
{
|
||||||
|
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||||
|
|
||||||
|
public override string Command => "get-motd";
|
||||||
|
|
||||||
|
public override void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||||
|
{
|
||||||
|
_entityManager.EntitySysManager.GetEntitySystem<MOTDSystem>().TrySendMOTD(shell);
|
||||||
|
}
|
||||||
|
}
|
||||||
36
Content.Server/Motd/MOTDCommand.cs
Normal file
36
Content.Server/Motd/MOTDCommand.cs
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
using Content.Server.Administration.Managers;
|
||||||
|
using Content.Shared.Administration;
|
||||||
|
using Robust.Server.Player;
|
||||||
|
using Robust.Shared.Console;
|
||||||
|
|
||||||
|
namespace Content.Server.Motd;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A console command which acts as an alias for <see cref="GetMotdCommand"/> or <see cref="SetMotdCommand"/> depending on the number of arguments given.
|
||||||
|
/// </summary>
|
||||||
|
[AnyCommand]
|
||||||
|
internal sealed class MOTDCommand : LocalizedCommands
|
||||||
|
{
|
||||||
|
[Dependency] private readonly IAdminManager _adminManager = default!;
|
||||||
|
|
||||||
|
public override string Command => "motd";
|
||||||
|
|
||||||
|
public override void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||||
|
{
|
||||||
|
var player = (IPlayerSession?)shell.Player;
|
||||||
|
if (args.Length < 1 || (player != null && _adminManager is AdminManager aMan && !aMan.CanCommand(player, "set-motd")))
|
||||||
|
shell.ConsoleHost.ExecuteCommand(shell.Player, "get-motd");
|
||||||
|
else
|
||||||
|
shell.ConsoleHost.ExecuteCommand(shell.Player, $"set-motd {string.Join(" ", args)}");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override CompletionResult GetCompletion(IConsoleShell shell, string[] args)
|
||||||
|
{
|
||||||
|
var player = (IPlayerSession?)shell.Player;
|
||||||
|
if (player != null && _adminManager is AdminManager aMan && !aMan.CanCommand(player, "set-motd"))
|
||||||
|
return CompletionResult.Empty;
|
||||||
|
if (args.Length == 1)
|
||||||
|
return CompletionResult.FromHint(Loc.GetString("cmd-set-motd-hint-head"));
|
||||||
|
return CompletionResult.FromHint(Loc.GetString("cmd-set-motd-hint-cont"));
|
||||||
|
}
|
||||||
|
}
|
||||||
101
Content.Server/Motd/MOTDSystem.cs
Normal file
101
Content.Server/Motd/MOTDSystem.cs
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
using Content.Server.Chat.Managers;
|
||||||
|
using Content.Server.GameTicking;
|
||||||
|
using Content.Shared.CCVar;
|
||||||
|
using Content.Shared.Chat;
|
||||||
|
using Robust.Server.Player;
|
||||||
|
using Robust.Shared.Console;
|
||||||
|
using Robust.Shared.Configuration;
|
||||||
|
|
||||||
|
namespace Content.Server.Motd;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The system that handles broadcasting the Message Of The Day to players when they join the lobby/the MOTD changes/they ask for it to be printed.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class MOTDSystem : EntitySystem
|
||||||
|
{
|
||||||
|
[Dependency] private readonly IChatManager _chatManager = default!;
|
||||||
|
[Dependency] private readonly IConfigurationManager _configurationManager = default!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The cached value of the Message of the Day. Used for fast access.
|
||||||
|
/// </summary>
|
||||||
|
private string _messageOfTheDay = "";
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
_configurationManager.OnValueChanged(CCVars.MOTD, OnMOTDChanged, invokeImmediately: true);
|
||||||
|
SubscribeLocalEvent<PlayerJoinedLobbyEvent>(OnPlayerJoinedLobby);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Shutdown()
|
||||||
|
{
|
||||||
|
_configurationManager.UnsubValueChanged(CCVars.MOTD, OnMOTDChanged);
|
||||||
|
base.Shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sends the Message Of The Day, if any, to all connected players.
|
||||||
|
/// </summary>
|
||||||
|
public void TrySendMOTD()
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(_messageOfTheDay))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var wrappedMessage = Loc.GetString("motd-wrap-message", ("motd", _messageOfTheDay));
|
||||||
|
_chatManager.ChatMessageToAll(ChatChannel.Server, _messageOfTheDay, wrappedMessage, source: EntityUid.Invalid, hideChat: false, recordReplay: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sends the Message Of The Day, if any, to a specific player.
|
||||||
|
/// </summary>
|
||||||
|
public void TrySendMOTD(IPlayerSession player)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(_messageOfTheDay))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var wrappedMessage = Loc.GetString("motd-wrap-message", ("motd", _messageOfTheDay));
|
||||||
|
_chatManager.ChatMessageToOne(ChatChannel.Server, _messageOfTheDay, wrappedMessage, source: EntityUid.Invalid, hideChat: false, client: player.ConnectedClient);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sends the Message Of The Day, if any, to a specific player's console and chat.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// This is used by the MOTD console command because we can't tell whether the player is using `console or /console so we send the message to both.
|
||||||
|
/// </remarks>
|
||||||
|
public void TrySendMOTD(IConsoleShell shell)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(_messageOfTheDay))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var wrappedMessage = Loc.GetString("motd-wrap-message", ("motd", _messageOfTheDay));
|
||||||
|
shell.WriteLine(wrappedMessage);
|
||||||
|
if (shell.Player is IPlayerSession player)
|
||||||
|
_chatManager.ChatMessageToOne(ChatChannel.Server, _messageOfTheDay, wrappedMessage, source: EntityUid.Invalid, hideChat: false, client: player.ConnectedClient);
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Event Handlers
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Posts the Message Of The Day to any players who join the lobby.
|
||||||
|
/// </summary>
|
||||||
|
private void OnPlayerJoinedLobby(PlayerJoinedLobbyEvent ev)
|
||||||
|
{
|
||||||
|
TrySendMOTD(ev.PlayerSession);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Broadcasts changes to the Message Of The Day to all players.
|
||||||
|
/// </summary>
|
||||||
|
private void OnMOTDChanged(string val)
|
||||||
|
{
|
||||||
|
if (val == _messageOfTheDay)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_messageOfTheDay = val;
|
||||||
|
TrySendMOTD();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Event Handlers
|
||||||
|
}
|
||||||
55
Content.Server/Motd/SetMOTDCommand.cs
Normal file
55
Content.Server/Motd/SetMOTDCommand.cs
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
using Content.Server.Administration;
|
||||||
|
using Content.Server.Administration.Logs;
|
||||||
|
using Content.Shared.Administration;
|
||||||
|
using Content.Shared.Database;
|
||||||
|
using Content.Shared.CCVar;
|
||||||
|
using Content.Server.Chat.Managers;
|
||||||
|
using Robust.Server.Player;
|
||||||
|
using Robust.Shared.Configuration;
|
||||||
|
using Robust.Shared.Console;
|
||||||
|
|
||||||
|
namespace Content.Server.Motd;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A console command usable by any user which prints or sets the Message of the Day.
|
||||||
|
/// </summary>
|
||||||
|
[AdminCommand(AdminFlags.Admin)]
|
||||||
|
public sealed class SetMotdCommand : LocalizedCommands
|
||||||
|
{
|
||||||
|
[Dependency] private readonly IAdminLogManager _adminLogManager = default!;
|
||||||
|
[Dependency] private readonly IChatManager _chatManager = default!;
|
||||||
|
[Dependency] private readonly IConfigurationManager _configurationManager = default!;
|
||||||
|
|
||||||
|
public override string Command => "set-motd";
|
||||||
|
|
||||||
|
public override void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||||
|
{
|
||||||
|
string motd = "";
|
||||||
|
var player = (IPlayerSession?)shell.Player;
|
||||||
|
if (args.Length > 0)
|
||||||
|
{
|
||||||
|
motd = string.Join(" ", args).Trim();
|
||||||
|
if (player != null && _chatManager.MessageCharacterLimit(player, motd))
|
||||||
|
return; // check function prints its own error response
|
||||||
|
}
|
||||||
|
|
||||||
|
_configurationManager.SetCVar(CCVars.MOTD, motd); // A hook in MOTDSystem broadcasts changes to the MOTD to everyone so we don't need to do it here.
|
||||||
|
if (string.IsNullOrEmpty(motd))
|
||||||
|
{
|
||||||
|
shell.WriteLine(Loc.GetString("cmd-set-motd-cleared-motd-message"));
|
||||||
|
_adminLogManager.Add(LogType.Chat, LogImpact.Low, $"{(player == null ? "LOCALHOST" : player.ConnectedClient.UserName):Player} cleared the MOTD for the server.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
shell.WriteLine(Loc.GetString("cmd-set-motd-set-motd-message", ("motd", motd)));
|
||||||
|
_adminLogManager.Add(LogType.Chat, LogImpact.Low, $"{(player == null ? "LOCALHOST" : player.ConnectedClient.UserName):Player} set the MOTD for the server to \"{motd:motd}\"");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override CompletionResult GetCompletion(IConsoleShell shell, string[] args)
|
||||||
|
{
|
||||||
|
if (args.Length == 1)
|
||||||
|
return CompletionResult.FromHint(Loc.GetString("cmd-set-motd-hint-head"));
|
||||||
|
return CompletionResult.FromHint(Loc.GetString("cmd-set-motd-hint-cont"));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1214,6 +1214,15 @@ namespace Content.Shared.CCVar
|
|||||||
public static readonly CVarDef<bool> ChatShowTypingIndicator =
|
public static readonly CVarDef<bool> ChatShowTypingIndicator =
|
||||||
CVarDef.Create("chat.show_typing_indicator", true, CVar.CLIENTONLY);
|
CVarDef.Create("chat.show_typing_indicator", true, CVar.CLIENTONLY);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A message broadcast to each player that joins the lobby.
|
||||||
|
/// May be changed by admins ingame through use of the "set-motd" command.
|
||||||
|
/// In this case the new value, if not empty, is broadcast to all connected players and saved between rounds.
|
||||||
|
/// May be requested by any player through use of the "get-motd" command.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly CVarDef<string> MOTD =
|
||||||
|
CVarDef.Create("chat.motd", "", CVar.SERVER | CVar.SERVERONLY | CVar.ARCHIVE, "A message broadcast to each player that joins the lobby.");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* AFK
|
* AFK
|
||||||
*/
|
*/
|
||||||
|
|||||||
11
Resources/Locale/en-US/motd/motd.ftl
Normal file
11
Resources/Locale/en-US/motd/motd.ftl
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
cmd-motd-desc = Prints or sets the Message Of The Day.
|
||||||
|
cmd-motd-help = motd [ message... ]
|
||||||
|
cmd-get-motd-desc = Prints the Message Of The Day.
|
||||||
|
cmd-get-motd-help = get-motd
|
||||||
|
cmd-set-motd-desc = Sets or clears the Message Of The Day.
|
||||||
|
cmd-set-motd-help = set-motd [ message... ]
|
||||||
|
cmd-set-motd-hint-head = [ message... ]
|
||||||
|
cmd-set-motd-hint-cont = [ ...message... ]
|
||||||
|
cmd-set-motd-cleared-motd-message = Cleared the Message of the Day.
|
||||||
|
cmd-set-motd-set-motd-message = Set the Message Of The Day to "{$motd}".
|
||||||
|
motd-wrap-message = Message of the Day: {$motd}
|
||||||
Reference in New Issue
Block a user