Skip to content
This repository was archived by the owner on Dec 23, 2025. It is now read-only.

Commit afc68db

Browse files
authored
Merge branch 'space-wizards:master' into master
2 parents f7a0624 + 34f8be8 commit afc68db

4 files changed

Lines changed: 129 additions & 11 deletions

File tree

Content.Server/MassMedia/Systems/NewsSystem.cs

Lines changed: 99 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,33 @@
1-
using System.Diagnostics.CodeAnalysis;
21
using Content.Server.Administration.Logs;
3-
using Content.Server.CartridgeLoader;
42
using Content.Server.CartridgeLoader.Cartridges;
3+
using Content.Server.CartridgeLoader;
54
using Content.Server.Chat.Managers;
5+
using Content.Server.Discord;
66
using Content.Server.GameTicking;
77
using Content.Server.MassMedia.Components;
88
using Content.Server.Popups;
99
using Content.Server.Station.Systems;
1010
using Content.Shared.Access.Components;
1111
using Content.Shared.Access.Systems;
12-
using Content.Shared.CartridgeLoader;
12+
using Content.Shared.CCVar;
1313
using Content.Shared.CartridgeLoader.Cartridges;
14+
using Content.Shared.CartridgeLoader;
1415
using Content.Shared.Database;
16+
using Content.Shared.GameTicking;
17+
using Content.Shared.IdentityManagement;
1518
using Content.Shared.MassMedia.Components;
1619
using Content.Shared.MassMedia.Systems;
1720
using Content.Shared.Popups;
1821
using Robust.Server.GameObjects;
22+
using Robust.Server;
1923
using Robust.Shared.Audio.Systems;
20-
using Content.Shared.IdentityManagement;
24+
using Robust.Shared.Configuration;
25+
using Robust.Shared.Maths;
2126
using Robust.Shared.Timing;
27+
using Robust.Shared.Utility;
28+
using System.Diagnostics.CodeAnalysis;
29+
using System.Linq;
30+
using System.Threading.Tasks;
2231

2332
namespace Content.Server.MassMedia.Systems;
2433

@@ -34,11 +43,36 @@ public sealed class NewsSystem : SharedNewsSystem
3443
[Dependency] private readonly StationSystem _station = default!;
3544
[Dependency] private readonly GameTicker _ticker = default!;
3645
[Dependency] private readonly IChatManager _chatManager = default!;
46+
[Dependency] private readonly DiscordWebhook _discord = default!;
47+
[Dependency] private readonly IConfigurationManager _cfg = default!;
48+
[Dependency] private readonly IBaseServer _baseServer = default!;
49+
50+
private WebhookIdentifier? _webhookId = null;
51+
private Color _webhookEmbedColor;
52+
private bool _webhookSendDuringRound;
3753

3854
public override void Initialize()
3955
{
4056
base.Initialize();
4157

58+
// Discord hook
59+
_cfg.OnValueChanged(CCVars.DiscordNewsWebhook,
60+
value =>
61+
{
62+
if (!string.IsNullOrWhiteSpace(value))
63+
_discord.GetWebhook(value, data => _webhookId = data.ToIdentifier());
64+
}, true);
65+
66+
_cfg.OnValueChanged(CCVars.DiscordNewsWebhookEmbedColor, value =>
67+
{
68+
_webhookEmbedColor = Color.LawnGreen;
69+
if (Color.TryParse(value, out var color))
70+
_webhookEmbedColor = color;
71+
}, true);
72+
73+
_cfg.OnValueChanged(CCVars.DiscordNewsWebhookSendDuringRound, value => _webhookSendDuringRound = value, true);
74+
SubscribeLocalEvent<RoundEndMessageEvent>(OnRoundEndMessageEvent);
75+
4276
// News writer
4377
SubscribeLocalEvent<NewsWriterComponent, MapInitEvent>(OnMapInit);
4478

@@ -177,6 +211,9 @@ private void OnWriteUiPublishMessage(Entity<NewsWriterComponent> ent, ref NewsWr
177211
RaiseLocalEvent(readerUid, ref args);
178212
}
179213

214+
if (_webhookSendDuringRound)
215+
Task.Run(async () => await SendArticleToDiscordWebhook(article));
216+
180217
UpdateWriterDevices();
181218
}
182219
#endregion
@@ -324,4 +361,62 @@ private void OnRequestArticleDraftMessage(Entity<NewsWriterComponent> ent, ref N
324361
{
325362
UpdateWriterUi(ent);
326363
}
364+
365+
#region Discord Hook
366+
367+
private void OnRoundEndMessageEvent(RoundEndMessageEvent ev)
368+
{
369+
if (_webhookSendDuringRound)
370+
return;
371+
372+
var query = EntityManager.EntityQueryEnumerator<StationNewsComponent>();
373+
374+
while (query.MoveNext(out _, out var comp))
375+
{
376+
SendArticlesListToDiscordWebhook(comp.Articles.OrderBy(article => article.ShareTime));
377+
}
378+
}
379+
380+
private async void SendArticlesListToDiscordWebhook(IOrderedEnumerable<NewsArticle> articles)
381+
{
382+
foreach (var article in articles)
383+
{
384+
await Task.Delay(TimeSpan.FromSeconds(1)); // TODO: proper discord rate limit handling
385+
await SendArticleToDiscordWebhook(article);
386+
}
387+
}
388+
389+
private async Task SendArticleToDiscordWebhook(NewsArticle article)
390+
{
391+
if (_webhookId is null)
392+
return;
393+
394+
try
395+
{
396+
var embed = new WebhookEmbed
397+
{
398+
Title = article.Title,
399+
// There is no need to cut article content. It's MaxContentLength smaller then discord's limit (4096):
400+
Description = FormattedMessage.RemoveMarkupPermissive(article.Content),
401+
Color = _webhookEmbedColor.ToArgb() & 0xFFFFFF, // HACK: way to get hex without A (transparency)
402+
Footer = new WebhookEmbedFooter
403+
{
404+
Text = Loc.GetString("news-discord-footer",
405+
("server", _baseServer.ServerName),
406+
("round", _ticker.RoundId),
407+
("author", article.Author ?? Loc.GetString("news-discord-unknown-author")),
408+
("time", article.ShareTime.ToString(@"hh\:mm\:ss")))
409+
}
410+
};
411+
var payload = new WebhookPayload { Embeds = [embed] };
412+
await _discord.CreateMessage(_webhookId.Value, payload);
413+
Log.Info("Sent news article to Discord webhook");
414+
}
415+
catch (Exception e)
416+
{
417+
Log.Error($"Error while sending discord news article:\n{e}");
418+
}
419+
}
420+
421+
#endregion
327422
}

Content.Shared/CCVar/CCVars.Discord.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using Robust.Shared.Configuration;
2+
using Robust.Shared.Maths;
23

34
namespace Content.Shared.CCVar;
45

@@ -72,4 +73,24 @@ public sealed partial class CCVars
7273
/// </summary>
7374
public static readonly CVarDef<float> DiscordWatchlistConnectionBufferTime =
7475
CVarDef.Create("discord.watchlist_connection_buffer_time", 5f, CVar.SERVERONLY);
76+
77+
/// <summary>
78+
/// URL of the Discord webhook which will receive station news acticles at the round end.
79+
/// If left empty, disables the webhook.
80+
/// </summary>
81+
public static readonly CVarDef<string> DiscordNewsWebhook =
82+
CVarDef.Create("discord.news_webhook", string.Empty, CVar.SERVERONLY);
83+
84+
/// <summary>
85+
/// HEX color of station news discord webhook's embed.
86+
/// </summary>
87+
public static readonly CVarDef<string> DiscordNewsWebhookEmbedColor =
88+
CVarDef.Create("discord.news_webhook_embed_color", Color.LawnGreen.ToHex(), CVar.SERVERONLY);
89+
90+
/// <summary>
91+
/// Whether or not articles should be sent mid-round instead of all at once at the round's end
92+
/// </summary>
93+
public static readonly CVarDef<bool> DiscordNewsWebhookSendDuringRound =
94+
CVarDef.Create("discord.news_webhook_send_during_round", false, CVar.SERVERONLY);
95+
7596
}

Resources/Changelog/Changelog.yml

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,4 @@
11
Entries:
2-
- author: themias
3-
changes:
4-
- message: Fixed being able to fax multiple times in quick succession
5-
type: Fix
6-
id: 7952
7-
time: '2025-02-13T20:12:57.0000000+00:00'
8-
url: https://github.com/space-wizards/space-station-14/pull/35135
92
- author: Centronias
103
changes:
114
- message: High-heeled Boots now click and clack when walking
@@ -3933,3 +3926,10 @@
39333926
id: 8454
39343927
time: '2025-05-10T15:12:18.0000000+00:00'
39353928
url: https://github.com/space-wizards/space-station-14/pull/37270
3929+
- author: Morb0, ssdaniel24
3930+
changes:
3931+
- message: Added a Discord webhook that will receive station news
3932+
type: Add
3933+
id: 8455
3934+
time: '2025-05-10T18:21:02.0000000+00:00'
3935+
url: https://github.com/space-wizards/space-station-14/pull/36807
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
news-discord-footer = Server: {$server} | Round: #{$round} | Author: {$author} | Time: {$time}
2+
news-discord-unknown-author = Unknown

0 commit comments

Comments
 (0)