Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Content.Server/IoC/ServerContentIoC.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using Content.Server._Monkestation;
using Content.Server._Monkestation.Administration.Managers;
using Content.Server._Monkestation.Announcements;
using Content.Server._Monkestation.Discord.Commands;
using Content.Server.Administration;
using Content.Server.Administration.Logs;
using Content.Server.Administration.Managers;
Expand Down Expand Up @@ -89,6 +90,7 @@ public static void Register(IDependencyCollection deps)
// Monkestation start
deps.Register<RoleTimeExemptionManager>();
deps.Register<AnnouncerManager>();
deps.Register<StatusDiscordCommand>();
// Monkestation end
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
using System.Linq;
using System.Threading.Tasks;
using Content.Server.Administration.Managers;
using Content.Server.Discord.DiscordLink;
using Content.Server.GameTicking;
using Content.Server.Maps;
using Content.Shared.CCVar;
using NetCord;
using NetCord.Rest;
using Robust.Server;
using Robust.Server.Player;
using Robust.Shared.Asynchronous;
using Robust.Shared.Configuration;

namespace Content.Server._Monkestation.Discord.Commands;

public sealed partial class StatusDiscordCommand : IPostInjectInit
{
[Dependency] private DiscordLink _discordLink = default!;
[Dependency] private IConfigurationManager _cfg = default!;
[Dependency] private IPlayerManager _playerManager = default!;
[Dependency] private IAdminManager _adminManager = default!;
[Dependency] private IBaseServer _baseServer = default!;
[Dependency] private IGameMapManager _gameMapManager = default!;
[Dependency] private IEntityManager _entityManager = default!;
[Dependency] private ITaskManager _taskManager = default!;

public void PostInject()
{
_discordLink.RegisterCommandCallback(OnStatusCommand, "status");
}

private async void OnStatusCommand(CommandReceivedEventArgs args)
{
var channelId = args.Message.Channel?.Id;
if (channelId == null)
return;
var embed = await RunOnMainThread(() =>
{
var gameTicker = _entityManager.System<GameTicker>();

List<string> rows = [];

var playerCount = _cfg.GetCVar(CCVars.AdminsCountInReportedPlayerCount)
? _playerManager.PlayerCount
: _playerManager.PlayerCount - _adminManager.ActiveAdmins.Count();
var playerCap = _cfg.GetCVar(CCVars.SoftMaxPlayers);
rows.Add(Loc.GetString("ms-discord-cmd-status-playercount", ("players", playerCount), ("maxPlayers", playerCap)));

var mapName = _gameMapManager.GetSelectedMap()?.MapName;
if (mapName != null)
rows.Add(Loc.GetString("ms-discord-cmd-status-mapname", ("map", mapName)));

var roundId = gameTicker.RoundId;
rows.Add(Loc.GetString("ms-discord-cmd-status-roundid", ("round", roundId)));

switch (gameTicker.RunLevel)
{
case GameRunLevel.PreRoundLobby:
rows.Add(Loc.GetString("ms-discord-cmd-status-runlevel-preround"));
break;
case GameRunLevel.InRound:
rows.Add(Loc.GetString("ms-discord-cmd-status-runlevel-inround", ("time", TimeSpan.FromSeconds(Math.Round(gameTicker.RoundDuration().TotalSeconds)))));
break;
case GameRunLevel.PostRound:
rows.Add(Loc.GetString("ms-discord-cmd-status-runlevel-postround"));
break;
}

return new EmbedProperties()
.WithTitle(_baseServer.ServerName)
.WithDescription(string.Join("\n", rows))
.WithColor(new NetCord.Color(0, 255, 0));

});

await _discordLink.SendEmbedAsync(channelId.Value, embed);
}

private async Task<T> RunOnMainThread<T>(Func<T> func)
{
var taskCompletionSource = new TaskCompletionSource<T>();
_taskManager.RunOnMainThread(() =>
{
try
{
taskCompletionSource.TrySetResult(func());
}
catch (Exception e)
{
taskCompletionSource.TrySetException(e);
}
});

var result = await taskCompletionSource.Task;
return result;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using NetCord;
using NetCord.Rest;
using System.Threading.Tasks;

// ReSharper disable once CheckNamespace
namespace Content.Server.Discord.DiscordLink;

public sealed partial class DiscordLink
{
/// <summary>
/// Sends an embed to a Discord channel with the specified ID. Without any mentions.
/// </summary>
public async Task SendEmbedAsync(ulong channelId, EmbedProperties embed)
{
if (_client == null)
{
return;
}

var channel = await _client.Rest.GetChannelAsync(channelId) as TextChannel;
if (channel == null)
{
_sawmill.Error("Tried to send a message to Discord but the channel {Channel} was not found.", channel);
return;
}

await channel.SendMessageAsync(new MessageProperties()
{
AllowedMentions = AllowedMentionsProperties.None,
Embeds = [embed],
});
}
}
6 changes: 6 additions & 0 deletions Resources/Locale/en-US/_Monkestation/Discord/commands.ftl
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
ms-discord-cmd-status-playercount = **Players**: {$players}/{$maxPlayers}
ms-discord-cmd-status-mapname = **Map**: {$map}
ms-discord-cmd-status-roundid = **Round#** {$round}
ms-discord-cmd-status-runlevel-preround = **Status**: Lobby
ms-discord-cmd-status-runlevel-inround = **Round Time**: {$time}
ms-discord-cmd-status-runlevel-postround = **Status**: Round End
Loading