Add round end Discord pings, discord webhook API (#19468)
This commit is contained in:
@@ -3,10 +3,10 @@ using System.Net.Http;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Text.Json.Nodes;
|
using System.Text.Json.Nodes;
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Content.Server.Administration.Managers;
|
using Content.Server.Administration.Managers;
|
||||||
|
using Content.Server.Discord;
|
||||||
using Content.Server.GameTicking;
|
using Content.Server.GameTicking;
|
||||||
using Content.Server.Players;
|
using Content.Server.Players;
|
||||||
using Content.Shared.Administration;
|
using Content.Shared.Administration;
|
||||||
@@ -337,13 +337,13 @@ namespace Content.Server.Administration.Systems
|
|||||||
{
|
{
|
||||||
Username = username,
|
Username = username,
|
||||||
AvatarUrl = string.IsNullOrWhiteSpace(_avatarUrl) ? null : _avatarUrl,
|
AvatarUrl = string.IsNullOrWhiteSpace(_avatarUrl) ? null : _avatarUrl,
|
||||||
Embeds = new List<Embed>
|
Embeds = new List<WebhookEmbed>
|
||||||
{
|
{
|
||||||
new()
|
new()
|
||||||
{
|
{
|
||||||
Description = messages,
|
Description = messages,
|
||||||
Color = color,
|
Color = color,
|
||||||
Footer = new EmbedFooter
|
Footer = new WebhookEmbedFooter
|
||||||
{
|
{
|
||||||
Text = $"{serverName} ({round})",
|
Text = $"{serverName} ({round})",
|
||||||
IconUrl = string.IsNullOrWhiteSpace(_footerIconUrl) ? null : _footerIconUrl
|
IconUrl = string.IsNullOrWhiteSpace(_footerIconUrl) ? null : _footerIconUrl
|
||||||
@@ -469,75 +469,6 @@ namespace Content.Server.Administration.Systems
|
|||||||
stringbuilder.Append(message);
|
stringbuilder.Append(message);
|
||||||
return stringbuilder.ToString();
|
return stringbuilder.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://discord.com/developers/docs/resources/channel#message-object-message-structure
|
|
||||||
private struct WebhookPayload
|
|
||||||
{
|
|
||||||
[JsonPropertyName("username")]
|
|
||||||
public string Username { get; set; } = "";
|
|
||||||
|
|
||||||
[JsonPropertyName("avatar_url")]
|
|
||||||
public string? AvatarUrl { get; set; } = "";
|
|
||||||
|
|
||||||
[JsonPropertyName("embeds")]
|
|
||||||
public List<Embed>? Embeds { get; set; } = null;
|
|
||||||
|
|
||||||
[JsonPropertyName("allowed_mentions")]
|
|
||||||
public Dictionary<string, string[]> AllowedMentions { get; set; } =
|
|
||||||
new()
|
|
||||||
{
|
|
||||||
{ "parse", Array.Empty<string>() },
|
|
||||||
};
|
|
||||||
|
|
||||||
public WebhookPayload()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://discord.com/developers/docs/resources/channel#embed-object-embed-structure
|
|
||||||
private struct Embed
|
|
||||||
{
|
|
||||||
[JsonPropertyName("description")]
|
|
||||||
public string Description { get; set; } = "";
|
|
||||||
|
|
||||||
[JsonPropertyName("color")]
|
|
||||||
public int Color { get; set; } = 0;
|
|
||||||
|
|
||||||
[JsonPropertyName("footer")]
|
|
||||||
public EmbedFooter? Footer { get; set; } = null;
|
|
||||||
|
|
||||||
public Embed()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://discord.com/developers/docs/resources/channel#embed-object-embed-footer-structure
|
|
||||||
private struct EmbedFooter
|
|
||||||
{
|
|
||||||
[JsonPropertyName("text")]
|
|
||||||
public string Text { get; set; } = "";
|
|
||||||
|
|
||||||
[JsonPropertyName("icon_url")]
|
|
||||||
public string? IconUrl { get; set; }
|
|
||||||
|
|
||||||
public EmbedFooter()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://discord.com/developers/docs/resources/webhook#webhook-object-webhook-structure
|
|
||||||
private struct WebhookData
|
|
||||||
{
|
|
||||||
[JsonPropertyName("guild_id")]
|
|
||||||
public string? GuildId { get; set; } = null;
|
|
||||||
|
|
||||||
[JsonPropertyName("channel_id")]
|
|
||||||
public string? ChannelId { get; set; } = null;
|
|
||||||
|
|
||||||
public WebhookData()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
101
Content.Server/Discord/DiscordWebhook.cs
Normal file
101
Content.Server/Discord/DiscordWebhook.cs
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
using System.Net.Http;
|
||||||
|
using System.Net.Http.Json;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Content.Server.Discord;
|
||||||
|
|
||||||
|
public sealed class DiscordWebhook : IPostInjectInit
|
||||||
|
{
|
||||||
|
[Dependency] private readonly ILogManager _log = default!;
|
||||||
|
|
||||||
|
private const string BaseUrl = "https://discord.com/api/v10/webhooks";
|
||||||
|
private readonly HttpClient _http = new();
|
||||||
|
private ISawmill _sawmill = default!;
|
||||||
|
|
||||||
|
private string GetUrl(WebhookIdentifier identifier)
|
||||||
|
{
|
||||||
|
return $"{BaseUrl}/{identifier.Id}/{identifier.Token}";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the webhook data from the given webhook url.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="url">The url to get the data from.</param>
|
||||||
|
/// <returns>The webhook data returned from the url.</returns>
|
||||||
|
public async Task<WebhookData?> GetWebhook(string url)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return await _http.GetFromJsonAsync<WebhookData>(url);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
_sawmill.Error($"Error getting discord webhook data. Stack trace:\n{Environment.StackTrace}");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the webhook data from the given webhook url.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="url">The url to get the data from.</param>
|
||||||
|
/// <param name="onComplete">The delegate to invoke with the obtained data, if any.</param>
|
||||||
|
public async void GetWebhook(string url, Action<WebhookData> onComplete)
|
||||||
|
{
|
||||||
|
if (await GetWebhook(url) is { } data)
|
||||||
|
onComplete(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tries to get the webhook data from the given webhook url if it is not null or whitespace.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="url">The url to get the data from.</param>
|
||||||
|
/// <param name="onComplete">The delegate to invoke with the obtained data, if any.</param>
|
||||||
|
public async void TryGetWebhook(string url, Action<WebhookData> onComplete)
|
||||||
|
{
|
||||||
|
if (await GetWebhook(url) is { } data)
|
||||||
|
onComplete(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new webhook message with the given identifier and payload.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="identifier">The identifier for the webhook url.</param>
|
||||||
|
/// <param name="payload">The payload to create the message from.</param>
|
||||||
|
/// <returns>The response from Discord's API.</returns>
|
||||||
|
public async Task<HttpResponseMessage> CreateMessage(WebhookIdentifier identifier, WebhookPayload payload)
|
||||||
|
{
|
||||||
|
var url = $"{GetUrl(identifier)}?wait=true";
|
||||||
|
return await _http.PostAsJsonAsync(url, payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Deletes a webhook message with the given identifier and message id.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="identifier">The identifier for the webhook url.</param>
|
||||||
|
/// <param name="messageId">The message id to delete.</param>
|
||||||
|
/// <returns>The response from Discord's API.</returns>
|
||||||
|
public async Task<HttpResponseMessage> DeleteMessage(WebhookIdentifier identifier, ulong messageId)
|
||||||
|
{
|
||||||
|
var url = $"{GetUrl(identifier)}/messages/{messageId}";
|
||||||
|
return await _http.DeleteAsync(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new webhook message with the given identifier, message id and payload.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="identifier">The identifier for the webhook url.</param>
|
||||||
|
/// <param name="messageId">The message id to edit.</param>
|
||||||
|
/// <param name="payload">The payload used to edit the message.</param>
|
||||||
|
/// <returns>The response from Discord's API.</returns>
|
||||||
|
public async Task<HttpResponseMessage> EditMessage(WebhookIdentifier identifier, ulong messageId, WebhookPayload payload)
|
||||||
|
{
|
||||||
|
var url = $"{GetUrl(identifier)}/messages/{messageId}";
|
||||||
|
return await _http.PatchAsJsonAsync(url, payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IPostInjectInit.PostInject()
|
||||||
|
{
|
||||||
|
_sawmill = _log.GetSawmill("DISCORD");
|
||||||
|
}
|
||||||
|
}
|
||||||
42
Content.Server/Discord/WebhookData.cs
Normal file
42
Content.Server/Discord/WebhookData.cs
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace Content.Server.Discord;
|
||||||
|
|
||||||
|
// https://discord.com/developers/docs/resources/webhook#webhook-object-webhook-structure
|
||||||
|
public struct WebhookData
|
||||||
|
{
|
||||||
|
[JsonPropertyName("id")]
|
||||||
|
public ulong Id { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("type")]
|
||||||
|
public int Type { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("guild_id")]
|
||||||
|
public ulong? GuildId { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("channel_id")]
|
||||||
|
public ulong? ChannelId { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("user")]
|
||||||
|
public WebhookUser? User { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("name")]
|
||||||
|
public string? Name { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("avatar")]
|
||||||
|
public string? Avatar { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("token")]
|
||||||
|
public string Token { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("application_id")]
|
||||||
|
public ulong? ApplicationId { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("url")]
|
||||||
|
public string? Url { get; set; }
|
||||||
|
|
||||||
|
public WebhookIdentifier ToIdentifier()
|
||||||
|
{
|
||||||
|
return new WebhookIdentifier(Id, Token);
|
||||||
|
}
|
||||||
|
}
|
||||||
20
Content.Server/Discord/WebhookEmbed.cs
Normal file
20
Content.Server/Discord/WebhookEmbed.cs
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace Content.Server.Discord;
|
||||||
|
|
||||||
|
// https://discord.com/developers/docs/resources/channel#embed-object-embed-structure
|
||||||
|
public struct WebhookEmbed
|
||||||
|
{
|
||||||
|
[JsonPropertyName("description")]
|
||||||
|
public string Description { get; set; } = "";
|
||||||
|
|
||||||
|
[JsonPropertyName("color")]
|
||||||
|
public int Color { get; set; } = 0;
|
||||||
|
|
||||||
|
[JsonPropertyName("footer")]
|
||||||
|
public WebhookEmbedFooter? Footer { get; set; } = null;
|
||||||
|
|
||||||
|
public WebhookEmbed()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
17
Content.Server/Discord/WebhookEmbedFooter.cs
Normal file
17
Content.Server/Discord/WebhookEmbedFooter.cs
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace Content.Server.Discord;
|
||||||
|
|
||||||
|
// https://discord.com/developers/docs/resources/channel#embed-object-embed-footer-structure
|
||||||
|
public struct WebhookEmbedFooter
|
||||||
|
{
|
||||||
|
[JsonPropertyName("text")]
|
||||||
|
public string Text { get; set; } = "";
|
||||||
|
|
||||||
|
[JsonPropertyName("icon_url")]
|
||||||
|
public string? IconUrl { get; set; }
|
||||||
|
|
||||||
|
public WebhookEmbedFooter()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
3
Content.Server/Discord/WebhookIdentifier.cs
Normal file
3
Content.Server/Discord/WebhookIdentifier.cs
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
namespace Content.Server.Discord;
|
||||||
|
|
||||||
|
public record struct WebhookIdentifier(ulong Id, string Token);
|
||||||
18
Content.Server/Discord/WebhookMentions.cs
Normal file
18
Content.Server/Discord/WebhookMentions.cs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace Content.Server.Discord;
|
||||||
|
|
||||||
|
public struct WebhookMentions
|
||||||
|
{
|
||||||
|
[JsonPropertyName("parse")]
|
||||||
|
public HashSet<string> Parse { get; set; } = new();
|
||||||
|
|
||||||
|
public WebhookMentions()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AllowRoleMentions()
|
||||||
|
{
|
||||||
|
Parse.Add("roles");
|
||||||
|
}
|
||||||
|
}
|
||||||
29
Content.Server/Discord/WebhookPayload.cs
Normal file
29
Content.Server/Discord/WebhookPayload.cs
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace Content.Server.Discord;
|
||||||
|
|
||||||
|
// https://discord.com/developers/docs/resources/channel#message-object-message-structure
|
||||||
|
public struct WebhookPayload
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The message to send in the webhook. Maximum of 2000 characters.
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("content")]
|
||||||
|
public string Content { get; set; } = "";
|
||||||
|
|
||||||
|
[JsonPropertyName("username")]
|
||||||
|
public string? Username { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("avatar_url")]
|
||||||
|
public string? AvatarUrl { get; set; } = "";
|
||||||
|
|
||||||
|
[JsonPropertyName("embeds")]
|
||||||
|
public List<WebhookEmbed>? Embeds { get; set; } = null;
|
||||||
|
|
||||||
|
[JsonPropertyName("allowed_mentions")]
|
||||||
|
public WebhookMentions AllowedMentions { get; set; } = new();
|
||||||
|
|
||||||
|
public WebhookPayload()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
58
Content.Server/Discord/WebhookUser.cs
Normal file
58
Content.Server/Discord/WebhookUser.cs
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace Content.Server.Discord;
|
||||||
|
|
||||||
|
// https://discord.com/developers/docs/resources/user#user-object
|
||||||
|
public struct WebhookUser
|
||||||
|
{
|
||||||
|
[JsonPropertyName("id")]
|
||||||
|
public ulong Id { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("username")]
|
||||||
|
public string Username { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("discriminator")]
|
||||||
|
public string Discriminator { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("global_name")]
|
||||||
|
public string? GlobalName { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("avatar")]
|
||||||
|
public string? Avatar { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("bot")]
|
||||||
|
public bool? Bot { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("system")]
|
||||||
|
public bool? System { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("mfa_enabled")]
|
||||||
|
public bool? MfaEnabled { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("banner")]
|
||||||
|
public string? Banner { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("accent_color")]
|
||||||
|
public int? AccentColor { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("locale")]
|
||||||
|
public string? Locale { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("verified")]
|
||||||
|
public bool? Verified { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("email")]
|
||||||
|
public string? Email { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("flags")]
|
||||||
|
public int? Flags { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("premium_type")]
|
||||||
|
public int? PremiumType { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("public_flags")]
|
||||||
|
public int? PublicFlags { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("avatar_decoration")]
|
||||||
|
public string? AvatarDecoration { get; set; }
|
||||||
|
}
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using Content.Server.Discord;
|
||||||
using Content.Shared.CCVar;
|
using Content.Shared.CCVar;
|
||||||
using Content.Shared.GameTicking;
|
using Content.Shared.GameTicking;
|
||||||
|
|
||||||
@@ -26,6 +27,14 @@ namespace Content.Server.GameTicking
|
|||||||
[ViewVariables]
|
[ViewVariables]
|
||||||
public float MaxStationOffset { get; private set; } = 0f;
|
public float MaxStationOffset { get; private set; } = 0f;
|
||||||
|
|
||||||
|
[ViewVariables]
|
||||||
|
public string? ServerName { get; private set; }
|
||||||
|
|
||||||
|
[ViewVariables]
|
||||||
|
private long? DiscordRoundEndRole { get; set; }
|
||||||
|
|
||||||
|
private WebhookIdentifier? _webhookIdentifier;
|
||||||
|
|
||||||
#if EXCEPTION_TOLERANCE
|
#if EXCEPTION_TOLERANCE
|
||||||
[ViewVariables]
|
[ViewVariables]
|
||||||
public int RoundStartFailShutdownCount { get; private set; } = 0;
|
public int RoundStartFailShutdownCount { get; private set; } = 0;
|
||||||
@@ -51,6 +60,27 @@ namespace Content.Server.GameTicking
|
|||||||
_configurationManager.OnValueChanged(CCVars.StationOffset, value => StationOffset = value, true);
|
_configurationManager.OnValueChanged(CCVars.StationOffset, value => StationOffset = value, true);
|
||||||
_configurationManager.OnValueChanged(CCVars.StationRotation, value => StationRotation = value, true);
|
_configurationManager.OnValueChanged(CCVars.StationRotation, value => StationRotation = value, true);
|
||||||
_configurationManager.OnValueChanged(CCVars.MaxStationOffset, value => MaxStationOffset = value, true);
|
_configurationManager.OnValueChanged(CCVars.MaxStationOffset, value => MaxStationOffset = value, true);
|
||||||
|
_configurationManager.OnValueChanged(CCVars.AdminLogsServerName, value =>
|
||||||
|
{
|
||||||
|
// TODO why tf is the server name on admin logs
|
||||||
|
ServerName = value;
|
||||||
|
}, true);
|
||||||
|
_configurationManager.OnValueChanged(CCVars.DiscordRoundRestartWebhook, value =>
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrWhiteSpace(value))
|
||||||
|
{
|
||||||
|
_discord.GetWebhook(value, data => _webhookIdentifier = data.ToIdentifier());
|
||||||
|
}
|
||||||
|
}, true);
|
||||||
|
_configurationManager.OnValueChanged(CCVars.DiscordRoundEndRoleWebhook, value =>
|
||||||
|
{
|
||||||
|
DiscordRoundEndRole = value;
|
||||||
|
|
||||||
|
if (value == 0)
|
||||||
|
{
|
||||||
|
DiscordRoundEndRole = null;
|
||||||
|
}
|
||||||
|
}, true);
|
||||||
#if EXCEPTION_TOLERANCE
|
#if EXCEPTION_TOLERANCE
|
||||||
_configurationManager.OnValueChanged(CCVars.RoundStartFailShutdownCount, value => RoundStartFailShutdownCount = value, true);
|
_configurationManager.OnValueChanged(CCVars.RoundStartFailShutdownCount, value => RoundStartFailShutdownCount = value, true);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ using Robust.Shared.Player;
|
|||||||
using Robust.Shared.Random;
|
using Robust.Shared.Random;
|
||||||
using Robust.Shared.Utility;
|
using Robust.Shared.Utility;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using Content.Server.Discord;
|
||||||
using Content.Shared.Database;
|
using Content.Shared.Database;
|
||||||
using Robust.Shared.Asynchronous;
|
using Robust.Shared.Asynchronous;
|
||||||
using PlayerData = Content.Server.Players.PlayerData;
|
using PlayerData = Content.Server.Players.PlayerData;
|
||||||
@@ -24,6 +25,7 @@ namespace Content.Server.GameTicking
|
|||||||
{
|
{
|
||||||
public sealed partial class GameTicker
|
public sealed partial class GameTicker
|
||||||
{
|
{
|
||||||
|
[Dependency] private readonly DiscordWebhook _discord = default!;
|
||||||
[Dependency] private readonly ITaskManager _taskManager = default!;
|
[Dependency] private readonly ITaskManager _taskManager = default!;
|
||||||
|
|
||||||
private static readonly Counter RoundNumberMetric = Metrics.CreateCounter(
|
private static readonly Counter RoundNumberMetric = Metrics.CreateCounter(
|
||||||
@@ -303,6 +305,7 @@ namespace Content.Server.GameTicking
|
|||||||
LobbySong = _robustRandom.Pick(_lobbyMusicCollection.PickFiles).ToString();
|
LobbySong = _robustRandom.Pick(_lobbyMusicCollection.PickFiles).ToString();
|
||||||
|
|
||||||
ShowRoundEndScoreboard(text);
|
ShowRoundEndScoreboard(text);
|
||||||
|
SendRoundEndDiscordMessage();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ShowRoundEndScoreboard(string text = "")
|
public void ShowRoundEndScoreboard(string text = "")
|
||||||
@@ -385,6 +388,33 @@ namespace Content.Server.GameTicking
|
|||||||
new SoundCollectionSpecifier("RoundEnd").GetSound()));
|
new SoundCollectionSpecifier("RoundEnd").GetSound()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async void SendRoundEndDiscordMessage()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (_webhookIdentifier == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var content = "The round has ended.";
|
||||||
|
if (DiscordRoundEndRole != null)
|
||||||
|
content += $"\n\n<@&{DiscordRoundEndRole}>, the server will reboot shortly!";
|
||||||
|
|
||||||
|
var payload = new WebhookPayload
|
||||||
|
{
|
||||||
|
Content = content,
|
||||||
|
Username = ServerName,
|
||||||
|
};
|
||||||
|
|
||||||
|
payload.AllowedMentions.AllowRoleMentions();
|
||||||
|
|
||||||
|
await _discord.CreateMessage(_webhookIdentifier.Value, payload);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Log.Error($"Error while sending discord round end message:\n{e}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void RestartRound()
|
public void RestartRound()
|
||||||
{
|
{
|
||||||
// If this game ticker is a dummy, do nothing!
|
// If this game ticker is a dummy, do nothing!
|
||||||
@@ -426,6 +456,31 @@ namespace Content.Server.GameTicking
|
|||||||
|
|
||||||
ReqWindowAttentionAll();
|
ReqWindowAttentionAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SendRoundStartingDiscordMessage();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void SendRoundStartingDiscordMessage()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (_webhookIdentifier == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var content = "New round starting!";
|
||||||
|
|
||||||
|
var payload = new WebhookPayload
|
||||||
|
{
|
||||||
|
Content = content,
|
||||||
|
Username = ServerName,
|
||||||
|
};
|
||||||
|
|
||||||
|
await _discord.CreateMessage(_webhookIdentifier.Value, payload);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Log.Error($"Error while sending discord round starting message:\n{e}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ using Content.Server.Afk;
|
|||||||
using Content.Server.Chat.Managers;
|
using Content.Server.Chat.Managers;
|
||||||
using Content.Server.Connection;
|
using Content.Server.Connection;
|
||||||
using Content.Server.Database;
|
using Content.Server.Database;
|
||||||
|
using Content.Server.Discord;
|
||||||
using Content.Server.EUI;
|
using Content.Server.EUI;
|
||||||
using Content.Server.GhostKick;
|
using Content.Server.GhostKick;
|
||||||
using Content.Server.Info;
|
using Content.Server.Info;
|
||||||
@@ -58,6 +59,7 @@ namespace Content.Server.IoC
|
|||||||
IoCManager.Register<UserDbDataManager>();
|
IoCManager.Register<UserDbDataManager>();
|
||||||
IoCManager.Register<ServerInfoManager>();
|
IoCManager.Register<ServerInfoManager>();
|
||||||
IoCManager.Register<PoissonDiskSampler>();
|
IoCManager.Register<PoissonDiskSampler>();
|
||||||
|
IoCManager.Register<DiscordWebhook>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -341,6 +341,18 @@ namespace Content.Shared.CCVar
|
|||||||
public static readonly CVarDef<string> DiscordAHelpAvatar =
|
public static readonly CVarDef<string> DiscordAHelpAvatar =
|
||||||
CVarDef.Create("discord.ahelp_avatar", string.Empty, CVar.SERVERONLY);
|
CVarDef.Create("discord.ahelp_avatar", string.Empty, CVar.SERVERONLY);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// URL of the Discord webhook which will relay round restart messages.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly CVarDef<string> DiscordRoundRestartWebhook =
|
||||||
|
CVarDef.Create("discord.round_restart_webhook", string.Empty, CVar.SERVERONLY);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Role id for the Discord webhook to ping when the round ends.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly CVarDef<long> DiscordRoundEndRoleWebhook =
|
||||||
|
CVarDef.Create("discord.round_end_role", 0L, CVar.SERVERONLY);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Suspicion
|
* Suspicion
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user