Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of DiscordConnector v3.1.2
DiscordConnector.dll
Decompiled 7 months ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Buffers; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Collections.Specialized; using System.ComponentModel; using System.Data; using System.Data.SqlTypes; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Diagnostics.Tracing; using System.Dynamic; using System.Globalization; using System.IO; using System.Linq; using System.Linq.Expressions; using System.Net; using System.Net.Http; using System.Numerics; using System.Reflection; using System.Reflection.Emit; using System.Resources; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.Serialization.Formatters; using System.Runtime.Versioning; using System.Security; using System.Security.AccessControl; using System.Security.Cryptography; using System.Security.Permissions; using System.Security.Principal; using System.Text; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; using System.Timers; using System.Xml; using System.Xml.Linq; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using DiscordConnector.Common; using DiscordConnector.Config; using DiscordConnector.Leaderboards; using DiscordConnector.RPC; using DiscordConnector.Records; using FxResources.System.Buffers; using HarmonyLib; using LiteDB; using LiteDB.Engine; using LiteDB.Utils; using LiteDB.Utils.Extensions; using Microsoft.CodeAnalysis; using Newtonsoft.Json; using Newtonsoft.Json.Bson; using Newtonsoft.Json.Converters; using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq.JsonPath; using Newtonsoft.Json.Schema; using Newtonsoft.Json.Serialization; using Newtonsoft.Json.Utilities; using UnityEngine; using UnityEngine.Device; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("DiscordConnector")] [assembly: AssemblyDescription("Enhances Valheim by sending messages to a Discord Webhook")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("nwesterhausen")] [assembly: AssemblyProduct("DiscordConnector")] [assembly: AssemblyCopyright("© 2025 nwesterhausen")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("4D35EB3F-E4D0-4FD9-9258-9066A85F1BFE")] [assembly: AssemblyFileVersion("3.1.2")] [assembly: TargetFramework(".NETFramework,Version=v4.8.1", FrameworkDisplayName = ".NET Framework 4.8.1")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("3.1.2.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace DiscordConnector { internal class PluginConfig { private const string ConfigJsonFilename = "config-dump.json"; internal static string[] ConfigExtensions = new string[6] { "messages", "variables", "leaderBoard", "toggles", "extraWebhooks", "main" }; public readonly string configPath; private readonly ExtraWebhookConfig extraWebhookConfig; private readonly LeaderBoardConfig leaderBoardConfig; private readonly MainConfig mainConfig; private readonly MessagesConfig messagesConfig; private readonly TogglesConfig togglesConfig; private readonly VariableConfig variableConfig; public bool LaunchMessageEnabled => togglesConfig.LaunchMessageEnabled; public bool LoadedMessageEnabled => togglesConfig.LoadedMessageEnabled; public bool StopMessageEnabled => togglesConfig.StopMessageEnabled; public bool ShutdownMessageEnabled => togglesConfig.ShutdownMessageEnabled; public bool WorldSaveMessageEnabled => togglesConfig.WorldSaveMessageEnabled; public bool ChatShoutEnabled => togglesConfig.ChatShoutEnabled; public bool ChatPingEnabled => togglesConfig.ChatPingEnabled; public bool PlayerJoinMessageEnabled => togglesConfig.PlayerJoinMessageEnabled; public bool PlayerDeathMessageEnabled => togglesConfig.PlayerDeathMessageEnabled; public bool PlayerLeaveMessageEnabled => togglesConfig.PlayerLeaveMessageEnabled; public bool EventStartMessageEnabled => togglesConfig.EventStartMessageEnabled; public bool EventStopMessageEnabled => togglesConfig.EventStopMessageEnabled; public bool EventPausedMessageEnabled => togglesConfig.EventPausedMessageEnabled; public bool EventResumedMessageEnabled => togglesConfig.EventResumedMessageEnabled; public bool ChatShoutAllCaps => togglesConfig.ChatShoutAllCaps; public bool NewDayNumberEnabled => togglesConfig.NewDayNumberEnabled; public bool StatsDeathEnabled { get { if (mainConfig.CollectStatsEnabled) { return togglesConfig.StatsDeathEnabled; } return false; } } public bool StatsJoinEnabled { get { if (mainConfig.CollectStatsEnabled) { return togglesConfig.StatsJoinEnabled; } return false; } } public bool StatsLeaveEnabled { get { if (mainConfig.CollectStatsEnabled) { return togglesConfig.StatsLeaveEnabled; } return false; } } public bool StatsPingEnabled { get { if (mainConfig.CollectStatsEnabled) { return togglesConfig.StatsPingEnabled; } return false; } } public bool StatsShoutEnabled { get { if (mainConfig.CollectStatsEnabled) { return togglesConfig.StatsShoutEnabled; } return false; } } public bool ChatPingPosEnabled { get { if (mainConfig.SendPositionsEnabled) { return togglesConfig.ChatPingPosEnabled; } return false; } } public bool ChatShoutPosEnabled { get { if (mainConfig.SendPositionsEnabled) { return togglesConfig.ChatShoutPosEnabled; } return false; } } public bool PlayerJoinPosEnabled { get { if (mainConfig.SendPositionsEnabled) { return togglesConfig.PlayerJoinPosEnabled; } return false; } } public bool PlayerDeathPosEnabled { get { if (mainConfig.SendPositionsEnabled) { return togglesConfig.PlayerDeathPosEnabled; } return false; } } public bool PlayerLeavePosEnabled { get { if (mainConfig.SendPositionsEnabled) { return togglesConfig.PlayerLeavePosEnabled; } return false; } } public bool EventStartPosEnabled { get { if (mainConfig.SendPositionsEnabled) { return togglesConfig.EventStartPosEnabled; } return false; } } public bool EventStopPosEnabled { get { if (mainConfig.SendPositionsEnabled) { return togglesConfig.EventStopPosEnabled; } return false; } } public bool EventPausedPosEnabled { get { if (mainConfig.SendPositionsEnabled) { return togglesConfig.EventPausedPosEnabled; } return false; } } public bool EventResumedPosEnabled { get { if (mainConfig.SendPositionsEnabled) { return togglesConfig.EventResumedPosEnabled; } return false; } } public string DefaultWebhookUsernameOverride => mainConfig.DefaultWebhookUsernameOverride; public WebhookEntry PrimaryWebhook => mainConfig.PrimaryWebhook; public WebhookEntry SecondaryWebhook => mainConfig.SecondaryWebhook; public bool CollectStatsEnabled => mainConfig.CollectStatsEnabled; public bool DiscordEmbedsEnabled => mainConfig.DiscordEmbedsEnabled; public bool SendPositionsEnabled => mainConfig.SendPositionsEnabled; public bool ShowPlayerIds => mainConfig.ShowPlayerIds; public bool AnnouncePlayerFirsts => mainConfig.AnnouncePlayerFirsts; public bool EmbedTitleEnabled => mainConfig.EmbedTitleEnabled; public bool EmbedDescriptionEnabled => mainConfig.EmbedDescriptionEnabled; public bool EmbedAuthorEnabled => mainConfig.EmbedAuthorEnabled; public bool EmbedThumbnailEnabled => mainConfig.EmbedThumbnailEnabled; public bool EmbedFooterEnabled => mainConfig.EmbedFooterEnabled; public bool EmbedTimestampEnabled => mainConfig.EmbedTimestampEnabled; public string EmbedDefaultColor => mainConfig.EmbedDefaultColor; public string EmbedServerStartColor => mainConfig.EmbedServerStartColor; public string EmbedServerStopColor => mainConfig.EmbedServerStopColor; public string EmbedPlayerJoinColor => mainConfig.EmbedPlayerJoinColor; public string EmbedPlayerLeaveColor => mainConfig.EmbedPlayerLeaveColor; public string EmbedDeathEventColor => mainConfig.EmbedDeathEventColor; public string EmbedShoutMessageColor => mainConfig.EmbedShoutMessageColor; public string EmbedOtherEventColor => mainConfig.EmbedOtherEventColor; public string EmbedWorldEventColor => mainConfig.EmbedWorldEventColor; public string EmbedNewDayColor => mainConfig.EmbedNewDayColor; public string EmbedServerSaveColor => mainConfig.EmbedServerSaveColor; public string EmbedPositionMessageColor => mainConfig.EmbedPositionMessageColor; public string EmbedActivePlayersColor => mainConfig.EmbedActivePlayersColor; public string EmbedLeaderboardEmbedColor => mainConfig.EmbedLeaderboardEmbedColor; public string EmbedFooterText => mainConfig.EmbedFooterText; public List<string> EmbedFieldDisplayOrder => mainConfig.EmbedFieldDisplayOrderList; public string EmbedUrlTemplate => mainConfig.EmbedUrlTemplate; public string EmbedAuthorIconUrl => mainConfig.EmbedAuthorIconUrl; public string EmbedThumbnailUrl => mainConfig.EmbedThumbnailUrl; public string ServerName => "Valheim"; public MainConfig.RetrievalDiscernmentMethods RecordRetrievalDiscernmentMethod => mainConfig.RecordRetrievalDiscernmentMethod; public List<string> MutedPlayers => mainConfig.MutedPlayers; public Regex MutedPlayersRegex => mainConfig.MutedPlayersRegex; public bool AllowNonPlayerShoutLogging => mainConfig.AllowNonPlayerShoutLogging; public bool AllowMentionsHereEveryone => mainConfig.AllowMentionsHereEveryone; public bool AllowMentionsAnyRole => mainConfig.AllowMentionsAnyRole; public bool AllowMentionsAnyUser => mainConfig.AllowMentionsAnyUser; public List<string> AllowedRoleMentions => mainConfig.AllowedRoleMentions; public List<string> AllowedUserMentions => mainConfig.AllowedUserMentions; public string LaunchMessage => messagesConfig.LaunchMessage; public string LoadedMessage => messagesConfig.LoadedMessage; public string StopMessage => messagesConfig.StopMessage; public string ShutdownMessage => messagesConfig.ShutdownMessage; public string SaveMessage => messagesConfig.SaveMessage; public string NewDayMessage => messagesConfig.NewDayMessage; public string JoinMessage => messagesConfig.JoinMessage; public string LeaveMessage => messagesConfig.LeaveMessage; public string DeathMessage => messagesConfig.DeathMessage; public string PingMessage => messagesConfig.PingMessage; public string ShoutMessage => messagesConfig.ShoutMessage; public string PlayerFirstDeathMessage => messagesConfig.PlayerFirstDeathMessage; public string PlayerFirstJoinMessage => messagesConfig.PlayerFirstJoinMessage; public string PlayerFirstLeaveMessage => messagesConfig.PlayerFirstLeaveMessage; public string PlayerFirstPingMessage => messagesConfig.PlayerFirstPingMessage; public string PlayerFirstShoutMessage => messagesConfig.PlayerFirstShoutMessage; public bool AnnouncePlayerFirstDeathEnabled { get { if (mainConfig.AnnouncePlayerFirsts) { return togglesConfig.AnnouncePlayerFirstDeathEnabled; } return false; } } public bool AnnouncePlayerFirstJoinEnabled { get { if (mainConfig.AnnouncePlayerFirsts) { return togglesConfig.AnnouncePlayerFirstJoinEnabled; } return false; } } public bool AnnouncePlayerFirstLeaveEnabled { get { if (mainConfig.AnnouncePlayerFirsts) { return togglesConfig.AnnouncePlayerFirstLeaveEnabled; } return false; } } public bool AnnouncePlayerFirstPingEnabled { get { if (mainConfig.AnnouncePlayerFirsts) { return togglesConfig.AnnouncePlayerFirstPingEnabled; } return false; } } public bool AnnouncePlayerFirstShoutEnabled { get { if (mainConfig.AnnouncePlayerFirsts) { return togglesConfig.AnnouncePlayerFirstShoutEnabled; } return false; } } public string EventStartMessage => messagesConfig.EventStartMessage; public string EventStopMessage => messagesConfig.EventStopMessage; public string EventPausedMessage => messagesConfig.EventPausedMessage; public string EventResumedMessage => messagesConfig.EventResumedMessage; public string UserVariable => variableConfig.UserVariable; public string UserVariable1 => variableConfig.UserVariable1; public string UserVariable2 => variableConfig.UserVariable2; public string UserVariable3 => variableConfig.UserVariable3; public string UserVariable4 => variableConfig.UserVariable4; public string UserVariable5 => variableConfig.UserVariable5; public string UserVariable6 => variableConfig.UserVariable6; public string UserVariable7 => variableConfig.UserVariable7; public string UserVariable8 => variableConfig.UserVariable8; public string UserVariable9 => variableConfig.UserVariable9; public string PosVarFormat => variableConfig.PosVarFormat; public string AppendedPosFormat => variableConfig.AppendedPosFormat; public bool DebugEveryPlayerPosCheck => togglesConfig.DebugEveryPlayerPosCheck; public bool DebugEveryEventCheck => togglesConfig.DebugEveryEventCheck; public bool DebugEveryEventChange => togglesConfig.DebugEveryEventChange; public bool DebugHttpRequestResponse => togglesConfig.DebugHttpRequestResponse; public bool DebugDatabaseMethods => togglesConfig.DebugDatabaseMethods; public bool DebugLeaderboardOperations => togglesConfig.DebugLeaderboardOperations; public string LeaderBoardTopPlayerHeading => messagesConfig.LeaderBoardTopPlayerHeading; public string LeaderBoardBottomPlayersHeading => messagesConfig.LeaderBoardBottomPlayersHeading; public string LeaderBoardHighestHeading => messagesConfig.LeaderBoardHighestHeading; public string LeaderBoardLowestHeading => messagesConfig.LeaderBoardLowestHeading; public LeaderBoardConfigReference[] LeaderBoards => leaderBoardConfig.LeaderBoards; public ActivePlayersAnnouncementConfigValues ActivePlayersAnnouncement => leaderBoardConfig.ActivePlayersAnnouncement; public List<WebhookEntry> ExtraWebhooks => extraWebhookConfig.GetWebhookEntries(); public PluginConfig(ConfigFile config) { //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Expected O, but got Unknown //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Expected O, but got Unknown //IL_015a: Unknown result type (might be due to invalid IL or missing references) //IL_0164: Expected O, but got Unknown //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_0177: Expected O, but got Unknown //IL_0180: Unknown result type (might be due to invalid IL or missing references) //IL_018a: Expected O, but got Unknown //IL_0193: Unknown result type (might be due to invalid IL or missing references) //IL_019d: Expected O, but got Unknown configPath = Path.Combine(Paths.ConfigPath, "games.nwest.valheim.discordconnector"); migrateConfigIfNeeded(); string path = "discordconnector.cfg"; string path2 = "discordconnector-messages.cfg"; string path3 = "discordconnector-toggles.cfg"; string path4 = "discordconnector-variables.cfg"; string path5 = "discordconnector-leaderBoards.cfg"; string path6 = "discordconnector-" + ExtraWebhookConfig.ConfigExtension + ".cfg"; string text = Path.Combine(configPath, path); string text2 = Path.Combine(configPath, path2); string text3 = Path.Combine(configPath, path3); string text4 = Path.Combine(configPath, path4); string text5 = Path.Combine(configPath, path5); string text6 = Path.Combine(configPath, path6); DiscordConnectorPlugin.StaticLogger.LogDebug("Main config: " + text); DiscordConnectorPlugin.StaticLogger.LogDebug("Messages config: " + text2); DiscordConnectorPlugin.StaticLogger.LogDebug("Toggles config: " + text3); DiscordConnectorPlugin.StaticLogger.LogDebug("Variable config: " + text4); DiscordConnectorPlugin.StaticLogger.LogDebug("Leader board config: " + text5); DiscordConnectorPlugin.StaticLogger.LogDebug("Extra Webhook config: " + text6); mainConfig = new MainConfig(new ConfigFile(text, true)); messagesConfig = new MessagesConfig(new ConfigFile(text2, true)); togglesConfig = new TogglesConfig(new ConfigFile(text3, true)); variableConfig = new VariableConfig(new ConfigFile(text4, true)); leaderBoardConfig = new LeaderBoardConfig(new ConfigFile(text5, true)); extraWebhookConfig = new ExtraWebhookConfig(new ConfigFile(text6, true)); DiscordConnectorPlugin.StaticLogger.LogDebug("Configuration Loaded"); DiscordConnectorPlugin.StaticLogger.LogDebug($"Muted Players Regex pattern ('a^' is default for no matches): {mainConfig.MutedPlayersRegex}"); DumpConfigAsJson(); } internal void migrateConfigIfNeeded() { if (!Directory.Exists(configPath)) { Directory.CreateDirectory(configPath); } string[] configExtensions = ConfigExtensions; foreach (string text in configExtensions) { string text2 = Path.Combine(Paths.ConfigPath, "discordconnector-" + text + ".cfg"); string text3 = Path.Combine(configPath, "discordconnector-" + text + ".cfg"); if (text.Equals("main")) { text2 = Path.Combine(Paths.ConfigPath, "discordconnector.cfg"); text3 = Path.Combine(configPath, "discordconnector.cfg"); } if (File.Exists(text2)) { if (File.Exists(text3)) { DiscordConnectorPlugin.StaticLogger.LogWarning("Expected to be moving " + text + " config from pre-2.1.0 location to new config location, but already exists!"); } else { File.Move(text2, text3); } } } } public void DumpConfigAsJson() { string jsonString = "{"; jsonString = jsonString + "\"Config.Main\":" + mainConfig.ConfigAsJson() + ","; jsonString = jsonString + "\"Config.Messages\":" + messagesConfig.ConfigAsJson() + ","; jsonString = jsonString + "\"Config.Toggles\":" + togglesConfig.ConfigAsJson() + ","; jsonString = jsonString + "\"Config.Variables\":" + variableConfig.ConfigAsJson() + ","; jsonString = jsonString + "\"Config.LeaderBoard\":" + leaderBoardConfig.ConfigAsJson() + ","; jsonString = jsonString + "\"Config.ExtraWebhooks\":" + extraWebhookConfig.ConfigAsJson(); jsonString += "}"; Task.Run(delegate { File.WriteAllText(Path.Combine(configPath, "config-dump.json"), jsonString); DiscordConnectorPlugin.StaticLogger.LogDebug("Dumped configuration files to config-dump.json"); }); } } internal class DiscordApi { public static void SendMessage(Webhook.Event ev, string message, Vector3 pos) { //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) try { if (DiscordConnectorPlugin.StaticConfig.DiscordEmbedsEnabled) { try { string serverName = DiscordConnectorPlugin.StaticConfig.ServerName; EmbedBuilder embedBuilder = MessageTransformer.CreatePositionEmbed(message, serverName, pos, ev); SendEmbed(ev, embedBuilder); return; } catch (Exception ex) { DiscordConnectorPlugin.StaticLogger.LogError("Failed to create position embed: " + ex.Message); DiscordConnectorPlugin.StaticLogger.LogDebug(ex.StackTrace); SendMessage(ev, message + " " + MessageTransformer.FormatAppendedPos(pos)); return; } } SendMessage(ev, message + " " + MessageTransformer.FormatAppendedPos(pos)); } catch (Exception ex2) { DiscordConnectorPlugin.StaticLogger.LogError("Error sending message with position: " + ex2.Message); DiscordConnectorPlugin.StaticLogger.LogDebug(ex2.StackTrace); } } public static void SendMessage(Webhook.Event ev, string message) { try { if (string.IsNullOrEmpty(message)) { DiscordConnectorPlugin.StaticLogger.LogWarning("Attempted to send empty message"); message = "[Empty Message]"; } if (DiscordConnectorPlugin.StaticConfig.DiscordEmbedsEnabled) { try { EmbedBuilder embedBuilder = MessageTransformer.CreateServerMessageEmbed(message, ev); SendEmbed(ev, embedBuilder); return; } catch (Exception ex) { DiscordConnectorPlugin.StaticLogger.LogError("Failed to create server message embed: " + ex.Message); DiscordConnectorPlugin.StaticLogger.LogDebug(ex.StackTrace); DiscordExecuteWebhook discordExecuteWebhook = new DiscordExecuteWebhook(); discordExecuteWebhook.content = message; discordExecuteWebhook.SendFor(ev); return; } } DiscordExecuteWebhook discordExecuteWebhook2 = new DiscordExecuteWebhook(); discordExecuteWebhook2.content = message; discordExecuteWebhook2.SendFor(ev); } catch (Exception ex2) { DiscordConnectorPlugin.StaticLogger.LogError("Error sending message: " + ex2.Message); DiscordConnectorPlugin.StaticLogger.LogDebug(ex2.StackTrace); } } public static void SendMessageWithFields(Webhook.Event ev, string? content = null, List<Tuple<string, string>>? fields = null) { try { if (string.IsNullOrEmpty(content) && (fields == null || fields.Count == 0)) { content = "Uh-oh! An unexpectedly empty message was sent!"; DiscordConnectorPlugin.StaticLogger.LogWarning("Attempted to send message with neither content nor fields"); } if (fields != null) { fields = fields.Where((Tuple<string, string> f) => f != null && !string.IsNullOrEmpty(f.Item1) && !string.IsNullOrEmpty(f.Item2)).ToList(); if (fields.Count == 0) { fields = null; } } if (DiscordConnectorPlugin.StaticConfig.DiscordEmbedsEnabled) { try { EmbedBuilder embedBuilder = new EmbedBuilder().SetColorForEvent(ev).SetDescription(content).SetTimestamp(); if (fields != null && fields.Count > 0) { try { if (fields.Count <= 3) { embedBuilder.AddInlineFields(fields); } else { embedBuilder.AddFields(fields); } } catch (Exception ex) { DiscordConnectorPlugin.StaticLogger.LogError("Error processing fields for embed: " + ex.Message); DiscordConnectorPlugin.StaticLogger.LogDebug(ex.StackTrace); } } SendEmbed(ev, embedBuilder); return; } catch (Exception ex2) { DiscordConnectorPlugin.StaticLogger.LogError("Failed to create embed with fields: " + ex2.Message); DiscordConnectorPlugin.StaticLogger.LogDebug(ex2.StackTrace); FallbackToLegacyFormat(ev, content, fields); return; } } FallbackToLegacyFormat(ev, content, fields); } catch (Exception ex3) { DiscordConnectorPlugin.StaticLogger.LogError("Unexpected error in SendMessageWithFields: " + ex3.Message); DiscordConnectorPlugin.StaticLogger.LogDebug(ex3.StackTrace); try { DiscordExecuteWebhook discordExecuteWebhook = new DiscordExecuteWebhook(); discordExecuteWebhook.content = "Error processing message with fields. See logs for details."; discordExecuteWebhook.SendFor(ev); } catch { DiscordConnectorPlugin.StaticLogger.LogError("Failed to send fallback error message"); } } } private static void FallbackToLegacyFormat(Webhook.Event ev, string? content, List<Tuple<string, string>>? fields) { try { DiscordExecuteWebhook discordExecuteWebhook = new DiscordExecuteWebhook { content = content }; if (fields != null && fields.Count > 0) { discordExecuteWebhook.embeds = new List<DiscordEmbed>(); List<DiscordField> list = new List<DiscordField>(); foreach (Tuple<string, string> field in fields) { if (field != null && !string.IsNullOrEmpty(field.Item1) && !string.IsNullOrEmpty(field.Item2)) { list.Add(new DiscordField { name = field.Item1, value = field.Item2 }); } } if (list.Count > 0) { discordExecuteWebhook.embeds.Add(new DiscordEmbed { fields = list }); } } discordExecuteWebhook.SendFor(ev); } catch (Exception ex) { DiscordConnectorPlugin.StaticLogger.LogError("Error in fallback message format: " + ex.Message); DiscordConnectorPlugin.StaticLogger.LogDebug(ex.StackTrace); try { DiscordExecuteWebhook discordExecuteWebhook2 = new DiscordExecuteWebhook(); discordExecuteWebhook2.content = content ?? "Error processing message"; discordExecuteWebhook2.SendFor(ev); } catch { DiscordConnectorPlugin.StaticLogger.LogError("Failed to send simple fallback message"); } } } public static void SendEmbed(Webhook.Event ev, EmbedBuilder embedBuilder) { if (embedBuilder == null) { LogDiscordError("Null EmbedBuilder provided to SendEmbed", null, ev); DiscordExecuteWebhook discordExecuteWebhook = new DiscordExecuteWebhook(); discordExecuteWebhook.content = "Error: Cannot create embed with null builder."; discordExecuteWebhook.SendFor(ev); return; } try { DiscordEmbed discordEmbed; try { discordEmbed = embedBuilder.Build(); if (discordEmbed == null) { throw new InvalidOperationException("Built embed was null"); } } catch (Exception ex) { LogDiscordError("Error building embed", ex, ev); string content = "Error creating embed message. Please check logs."; try { string descriptionForFallback = embedBuilder.GetDescriptionForFallback(); if (!string.IsNullOrEmpty(descriptionForFallback)) { content = descriptionForFallback; } } catch (Exception ex2) { LogDiscordError("Failed to extract fallback description", ex2, ev, logStackTrace: false); } DiscordExecuteWebhook discordExecuteWebhook2 = new DiscordExecuteWebhook(); discordExecuteWebhook2.content = content; discordExecuteWebhook2.SendFor(ev); return; } try { bool flag = true; if (string.IsNullOrEmpty(discordEmbed.title) && string.IsNullOrEmpty(discordEmbed.description) && (discordEmbed.fields == null || discordEmbed.fields.Count <= 0) && (discordEmbed.footer == null || string.IsNullOrEmpty(discordEmbed.footer.text)) && (discordEmbed.author == null || string.IsNullOrEmpty(discordEmbed.author.name)) && (discordEmbed.image == null || string.IsNullOrEmpty(discordEmbed.image.url)) && (discordEmbed.thumbnail == null || string.IsNullOrEmpty(discordEmbed.thumbnail.url))) { DiscordConnectorPlugin.StaticLogger.LogWarning("Embed has no visible content and may not display correctly"); flag = false; } if (!flag) { DiscordConnectorPlugin.StaticLogger.LogWarning("Embed validation failed"); string text = embedBuilder.GetDescriptionForFallback() ?? string.Empty; if (string.IsNullOrEmpty(text)) { text = "Message could not be sent to Discord due to validation issues. Check logs for details."; } DiscordConnectorPlugin.StaticLogger.LogInfo("Sending plain text fallback message instead of invalid embed"); DiscordExecuteWebhook discordExecuteWebhook3 = new DiscordExecuteWebhook(); discordExecuteWebhook3.content = text; discordExecuteWebhook3.SendFor(ev); } else { DiscordExecuteWebhook discordExecuteWebhook4 = new DiscordExecuteWebhook(); discordExecuteWebhook4.embeds = new List<DiscordEmbed>(1) { discordEmbed }; discordExecuteWebhook4.SendFor(ev); } } catch (Exception ex3) { LogDiscordError("Error sending embed payload", ex3, ev); throw new Exception("Error sending embed payload: " + ex3.Message, ex3); } } catch (Exception ex4) { LogDiscordError("Failed to send embed", ex4, ev); try { DiscordExecuteWebhook discordExecuteWebhook5 = new DiscordExecuteWebhook(); discordExecuteWebhook5.content = "Error sending Discord message. Please check logs."; discordExecuteWebhook5.SendFor(ev); } catch (Exception ex5) { LogDiscordError("Complete failure sending Discord message - even fallback failed", ex5, ev, logStackTrace: false); } } } private static void LogDiscordError(string message, Exception? ex = null, Webhook.Event? eventType = null, bool logStackTrace = true) { try { string text = (eventType.HasValue ? $" for event {eventType}" : string.Empty); if (ex != null) { DiscordConnectorPlugin.StaticLogger.LogError(message + text + ": " + ex.Message); if (logStackTrace && ex.StackTrace != null) { DiscordConnectorPlugin.StaticLogger.LogDebug(ex.StackTrace); } if (ex.InnerException != null) { DiscordConnectorPlugin.StaticLogger.LogError("Inner exception: " + ex.InnerException.Message); } } else { DiscordConnectorPlugin.StaticLogger.LogError(message + text); } } catch { try { DiscordConnectorPlugin.StaticLogger.LogError("Failed to log Discord error details due to exception in logging"); } catch { } } } public static void SendSerializedJson(Webhook.Event ev, string serializedJson) { DiscordConnectorPlugin.StaticLogger.LogDebug($"Finding webhooks for event: (event: {ev})"); if (ev == Webhook.Event.Other) { DiscordConnectorPlugin.StaticLogger.LogInfo("Dispatching webhook for 3rd party plugin (configured as 'Other' in WebHook config)"); } if ((string.IsNullOrEmpty(DiscordConnectorPlugin.StaticConfig.PrimaryWebhook.Url) && string.IsNullOrEmpty(DiscordConnectorPlugin.StaticConfig.SecondaryWebhook.Url)) || string.IsNullOrEmpty(serializedJson)) { return; } if (DiscordConnectorPlugin.StaticConfig.PrimaryWebhook.HasEvent(ev)) { DiscordConnectorPlugin.StaticLogger.LogDebug($"Sending {ev} message to Primary Webhook"); DispatchRequest(DiscordConnectorPlugin.StaticConfig.PrimaryWebhook, serializedJson); } if (DiscordConnectorPlugin.StaticConfig.SecondaryWebhook.HasEvent(ev)) { DiscordConnectorPlugin.StaticLogger.LogDebug($"Sending {ev} message to Secondary Webhook"); DispatchRequest(DiscordConnectorPlugin.StaticConfig.SecondaryWebhook, serializedJson); } foreach (WebhookEntry extraWebhook in DiscordConnectorPlugin.StaticConfig.ExtraWebhooks) { if (extraWebhook.HasEvent(ev)) { DiscordConnectorPlugin.StaticLogger.LogDebug($"Sending {ev} message to Extra Webhook: {extraWebhook.Url}"); DispatchRequest(extraWebhook, serializedJson); } } } public static void SendSerializedJson(WebhookEntry webhook, string serializedJson) { DiscordConnectorPlugin.StaticLogger.LogDebug("Trying webhook with payload: " + serializedJson); if (!string.IsNullOrEmpty(webhook.Url) && !string.IsNullOrEmpty(serializedJson)) { Encoding.UTF8.GetBytes(serializedJson); DispatchRequest(webhook, serializedJson); } } private static async void DispatchRequest(WebhookEntry webhook, string serializedJson) { if (string.IsNullOrEmpty(webhook.Url)) { DiscordConnectorPlugin.StaticLogger.LogDebug("Dispatch attempted with empty webhook - ignoring"); return; } string requestId = GuidHelper.GenerateShortHexGuid(); DiscordConnectorPlugin.StaticLogger.LogDebug("DispatchRequest." + requestId + ": sending " + serializedJson + " to Discord"); HttpClient val = new HttpClient(); StringContent val2 = new StringContent(serializedJson, Encoding.UTF8, "application/json"); try { HttpResponseMessage val3 = await val.PostAsync(webhook.Url, (HttpContent)(object)val2); DiscordConnectorPlugin.StaticLogger.LogDebug($"DispatchRequest.{requestId}: Response Code: {val3.StatusCode}"); if (val3.StatusCode != HttpStatusCode.NoContent) { string text = await val3.Content.ReadAsStringAsync(); if (text.Length > 0) { DiscordConnectorPlugin.StaticLogger.LogDebug("DispatchRequest." + requestId + ": Response from server: " + text); } else { DiscordConnectorPlugin.StaticLogger.LogDebug("DispatchRequest." + requestId + ": Empty response from server (normal)"); } } } catch (Exception arg) { DiscordConnectorPlugin.StaticLogger.LogError($"DispatchRequest.{requestId}: Error getting web response: {arg}"); } } public static void SendMessage(string message, Vector3 pos) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) SendMessage(Webhook.Event.Other, message, pos); } public static void SendMessage(string message) { SendMessage(Webhook.Event.Other, message); } public static void SendMessageWithFields(string? content = null, List<Tuple<string, string>>? fields = null) { SendMessageWithFields(Webhook.Event.Other, content, fields); } private static void SendSerializedJson(string serializedJson) { SendSerializedJson(Webhook.Event.Other, serializedJson); } } internal class DiscordExecuteWebhook { public string? content { get; set; } public string? username { get; set; } public string? avatar_url { get; set; } public List<DiscordEmbed>? embeds { get; set; } public AllowedMentions? allowed_mentions { get; set; } public DiscordExecuteWebhook() { allowed_mentions = new AllowedMentions(); ResetOverrides(); } public void SetUsername(string name) { username = name; } public void SetAvatarUrl(string url) { avatar_url = url; } public bool IsValid() { if (string.IsNullOrEmpty(content)) { return embeds != null; } return true; } public void ResetOverrides() { username = null; avatar_url = null; if (!string.IsNullOrEmpty(DiscordConnectorPlugin.StaticConfig.DefaultWebhookUsernameOverride)) { SetUsername(DiscordConnectorPlugin.StaticConfig.DefaultWebhookUsernameOverride); } } public void SendFor(Webhook.Event ev) { if (!IsValid()) { DiscordConnectorPlugin.StaticLogger.LogWarning($"Attempted to send an invalid DiscordExecuteWebhook object:\n{this}"); return; } try { if (DiscordConnectorPlugin.StaticConfig.PrimaryWebhook.HasEvent(ev)) { DiscordConnectorPlugin.StaticLogger.LogDebug($"Sending {ev} message to Primary Webhook"); WebhookEntry primaryWebhook = DiscordConnectorPlugin.StaticConfig.PrimaryWebhook; ResetOverrides(); if (primaryWebhook.HasUsernameOverride()) { SetUsername(primaryWebhook.UsernameOverride); } if (primaryWebhook.HasAvatarOverride()) { SetAvatarUrl(primaryWebhook.AvatarOverride); } DiscordApi.SendSerializedJson(primaryWebhook, JsonConvert.SerializeObject(this)); } if (DiscordConnectorPlugin.StaticConfig.SecondaryWebhook.HasEvent(ev)) { DiscordConnectorPlugin.StaticLogger.LogDebug($"Sending {ev} message to Secondary Webhook"); WebhookEntry secondaryWebhook = DiscordConnectorPlugin.StaticConfig.SecondaryWebhook; ResetOverrides(); if (secondaryWebhook.HasUsernameOverride()) { SetUsername(secondaryWebhook.UsernameOverride); } if (secondaryWebhook.HasAvatarOverride()) { SetAvatarUrl(secondaryWebhook.AvatarOverride); } DiscordApi.SendSerializedJson(secondaryWebhook, JsonConvert.SerializeObject(this)); } foreach (WebhookEntry extraWebhook in DiscordConnectorPlugin.StaticConfig.ExtraWebhooks) { if (extraWebhook.HasEvent(ev)) { DiscordConnectorPlugin.StaticLogger.LogDebug($"Sending {ev} message to an Extra Webhook"); ResetOverrides(); if (extraWebhook.HasUsernameOverride()) { SetUsername(extraWebhook.UsernameOverride); } if (extraWebhook.HasAvatarOverride()) { SetAvatarUrl(extraWebhook.AvatarOverride); } DiscordApi.SendSerializedJson(extraWebhook, JsonConvert.SerializeObject(this)); } } } catch (Exception arg) { DiscordConnectorPlugin.StaticLogger.LogWarning($"Error serializing payload: {arg}"); } } } internal class AllowedMentions { public List<string> parse { get; set; } public List<string> roles { get; set; } public List<string> users { get; set; } public bool replied_user { get; set; } public AllowedMentions() { parse = new List<string>(); roles = new List<string>(); users = new List<string>(); replied_user = false; if (DiscordConnectorPlugin.StaticConfig.AllowMentionsHereEveryone) { AllowEveryone(); } if (DiscordConnectorPlugin.StaticConfig.AllowMentionsAnyRole) { AllowAnyRoles(); } if (DiscordConnectorPlugin.StaticConfig.AllowMentionsAnyUser) { AllowAnyUsers(); } if (DiscordConnectorPlugin.StaticConfig.AllowedRoleMentions.Count > 0) { AllowRoles(DiscordConnectorPlugin.StaticConfig.AllowedRoleMentions); } if (DiscordConnectorPlugin.StaticConfig.AllowedUserMentions.Count > 0) { AllowUsers(DiscordConnectorPlugin.StaticConfig.AllowedUserMentions); } } public void AllowEveryone() { if (!parse.Contains("everyone")) { parse.Add("everyone"); } } public void AllowHere() { if (!parse.Contains("everyone")) { parse.Add("everyone"); } } public void AllowRole(string role_id) { if (!roles.Contains(role_id)) { roles.Add(role_id); } } public void AllowRoles(List<string> role_ids) { foreach (string role_id in role_ids) { AllowRole(role_id); } } public void DisallowRole(string role_id) { if (roles.Contains(role_id)) { roles.Remove(role_id); } } public void AllowUser(string user_id) { if (!users.Contains(user_id)) { users.Add(user_id); } } public void AllowUsers(List<string> user_ids) { foreach (string user_id in user_ids) { AllowUser(user_id); } } public void DisallowUser(string user_id) { if (users.Contains(user_id)) { users.Remove(user_id); } } public void AllowAnyRoles() { if (!parse.Contains("roles")) { parse.Add("roles"); } } public void AllowAnyUsers() { if (!parse.Contains("users")) { parse.Add("users"); } } public void DisallowAnyRoles() { if (parse.Contains("roles")) { parse.Remove("roles"); } } public void DisallowAnyUsers() { if (parse.Contains("users")) { parse.Remove("users"); } } } internal class DiscordEmbed { public string? title { get; set; } public string? description { get; set; } public string? url { get; set; } public string? timestamp { get; set; } public int? color { get; set; } public DiscordEmbedAuthor? author { get; set; } public DiscordEmbedFooter? footer { get; set; } public DiscordEmbedThumbnail? thumbnail { get; set; } public DiscordEmbedImage? image { get; set; } public List<DiscordField>? fields { get; set; } } internal class DiscordField { public string? name { get; set; } public string? value { get; set; } public bool? inline { get; set; } } internal class DiscordEmbedAuthor { public string? name { get; set; } public string? url { get; set; } public string? icon_url { get; set; } } internal class DiscordEmbedFooter { public string? text { get; set; } public string? icon_url { get; set; } } internal class DiscordEmbedThumbnail { public string url { get; set; } = ""; public string? proxy_url { get; set; } public int? height { get; set; } public int? width { get; set; } } internal class DiscordEmbedImage { public string url { get; set; } = ""; public string? proxy_url { get; set; } public int? height { get; set; } public int? width { get; set; } } internal class EmbedBuilder { private const int MAX_FIELDS_PER_ROW = 3; public const int MAX_FIELDS_COUNT = 25; public const string DEFAULT_COLOR = "#7289DA"; public const string DEFAULT_SERVER_START_COLOR = "#43B581"; public const string DEFAULT_SERVER_STOP_COLOR = "#F04747"; public const string DEFAULT_PLAYER_JOIN_COLOR = "#43B581"; public const string DEFAULT_PLAYER_LEAVE_COLOR = "#FAA61A"; public const string DEFAULT_DEATH_EVENT_COLOR = "#F04747"; public const string DEFAULT_SHOUT_MESSAGE_COLOR = "#7289DA"; public const string DEFAULT_POSITION_MESSAGE_COLOR = "#7289DA"; public const string DEFAULT_OTHER_EVENT_COLOR = "#747F8D"; private readonly PluginConfig _config; private readonly DiscordEmbed _embed; private readonly List<DiscordField> _fields; private int _currentRowFieldCount; public EmbedBuilder() { _embed = new DiscordEmbed(); _fields = new List<DiscordField>(); _currentRowFieldCount = 0; _config = DiscordConnectorPlugin.StaticConfig; } public EmbedBuilder SetTitle(string? title) { if (_config.EmbedTitleEnabled) { _embed.title = title; } return this; } public EmbedBuilder SetDescription(string? description) { if (_config.EmbedDescriptionEnabled) { _embed.description = description; } return this; } public EmbedBuilder SetUrl(string? url) { _embed.url = url; return this; } public EmbedBuilder SetUrlFromTemplate(Dictionary<string, string>? variables = null) { if (string.IsNullOrEmpty(_config.EmbedUrlTemplate)) { return this; } string text = _config.EmbedUrlTemplate; if (variables != null) { foreach (KeyValuePair<string, string> variable in variables) { text = text.Replace("{" + variable.Key + "}", variable.Value ?? string.Empty); } } return SetUrl(text); } public EmbedBuilder SetColor(int color) { _embed.color = Math.Max(0, Math.Min(color, 16777215)); return this; } public EmbedBuilder SetColor(string hexColor) { _embed.color = HexColorToDecimal(hexColor); return this; } private int HexColorToDecimal(string hexColor) { if (string.IsNullOrEmpty(hexColor)) { hexColor = "#7289DA"; } if (!hexColor.StartsWith("#")) { hexColor = "#" + hexColor; } try { string text = hexColor.TrimStart(new char[1] { '#' }); if (text.Length != 6) { text = "#7289DA".TrimStart(new char[1] { '#' }); } return Convert.ToInt32(text, 16); } catch { return Convert.ToInt32("#7289DA".TrimStart(new char[1] { '#' }), 16); } } public EmbedBuilder SetColorForEvent(Webhook.Event eventType) { string text = "#7289DA"; text = ((!Webhook.ServerLaunchEvents.Contains(eventType) && !Webhook.ServerStartEvents.Contains(eventType)) ? ((Webhook.ServerStopEvents.Contains(eventType) || Webhook.ServerShutdownEvents.Contains(eventType)) ? _config.EmbedServerStopColor : (Webhook.ServerSaveEvents.Contains(eventType) ? _config.EmbedServerStartColor : (Webhook.PlayerJoinEvents.Contains(eventType) ? _config.EmbedPlayerJoinColor : (Webhook.PlayerLeaveEvents.Contains(eventType) ? _config.EmbedPlayerLeaveColor : (Webhook.PlayerDeathEvents.Contains(eventType) ? _config.EmbedDeathEventColor : (Webhook.PlayerShoutEvents.Contains(eventType) ? _config.EmbedShoutMessageColor : (Webhook.PlayerPingEvents.Contains(eventType) ? _config.EmbedPositionMessageColor : ((!Webhook.WorldEvents.Contains(eventType)) ? _config.EmbedOtherEventColor : _config.EmbedWorldEventColor)))))))) : _config.EmbedServerStartColor); return SetColor(text); } public EmbedBuilder SetAuthor(string? name, string? url = null, string? iconUrl = null) { if (_config.EmbedAuthorEnabled) { _embed.author = new DiscordEmbedAuthor { name = name, url = url, icon_url = iconUrl }; } return this; } public EmbedBuilder SetThumbnail(string? url) { if (_config.EmbedThumbnailEnabled && !string.IsNullOrEmpty(url)) { _embed.thumbnail = new DiscordEmbedThumbnail { url = url }; } return this; } public EmbedBuilder SetImage(string? url) { if (!string.IsNullOrEmpty(url)) { _embed.image = new DiscordEmbedImage { url = url }; } return this; } public EmbedBuilder SetFooter(string? text, string? iconUrl = null) { if (_config.EmbedFooterEnabled) { _embed.footer = new DiscordEmbedFooter { text = text, icon_url = iconUrl }; } return this; } public EmbedBuilder SetFooterFromTemplate(Dictionary<string, string>? variables = null, string? iconUrl = null) { if (!_config.EmbedFooterEnabled || string.IsNullOrEmpty(_config.EmbedFooterText)) { return this; } string text = _config.EmbedFooterText; if (variables != null) { foreach (KeyValuePair<string, string> variable in variables) { text = text.Replace("{" + variable.Key + "}", variable.Value); } } return SetFooter(text, iconUrl); } public EmbedBuilder SetTimestamp(DateTimeOffset? timestamp = null) { if (_config.EmbedTimestampEnabled) { _embed.timestamp = (timestamp ?? DateTimeOffset.UtcNow).ToString("o"); } return this; } public EmbedBuilder AddField(string? name, string? value, bool inline = false) { if (string.IsNullOrEmpty(name) || string.IsNullOrEmpty(value)) { return this; } if (_fields.Count >= 25) { DiscordConnectorPlugin.StaticLogger.LogWarning($"Cannot add more than {25} fields to a Discord embed."); return this; } _fields.Add(new DiscordField { name = name, value = value, inline = inline }); if (inline) { _currentRowFieldCount++; if (_currentRowFieldCount >= 3) { _currentRowFieldCount = 0; } } else { _currentRowFieldCount = 0; } return this; } public EmbedBuilder AddInlineField(string? name, string? value) { return AddField(name, value, inline: true); } public EmbedBuilder AddPositionField(Vector3 position, bool inline = true) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) string value = MessageTransformer.FormatVector3AsPos(position); return AddField("Position", value, inline); } public EmbedBuilder AddRowBreak() { if (_currentRowFieldCount > 0) { _fields.Add(new DiscordField { name = "\u200b", value = "\u200b", inline = false }); _currentRowFieldCount = 0; } return this; } public EmbedBuilder AddFields(List<Tuple<string, string>> fields, bool inline = false) { if (fields == null || fields.Count == 0) { return this; } foreach (Tuple<string, string> field in fields) { AddField(field.Item1, field.Item2, inline); } return this; } public EmbedBuilder AddInlineFields(List<Tuple<string, string>> fields) { return AddFields(fields, inline: true); } public EmbedBuilder AddPositionField(Vector3 position) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) if (_config.SendPositionsEnabled) { string value = MessageTransformer.FormatVector3AsPos(position); AddField("Coordinates", value); } return this; } public EmbedBuilder OrganizeFields() { if (_fields.Count == 0) { return this; } if (_config.EmbedFieldDisplayOrder == null || _config.EmbedFieldDisplayOrder.Count == 0) { return this; } _ = _config.EmbedFieldDisplayOrder.Count; return this; } public DiscordEmbed Build() { if (_fields.Count > 0) { _embed.fields = _fields; } if (!IsWithinCharacterLimit()) { DiscordConnectorPlugin.StaticLogger.LogWarning("Embed exceeds Discord's character limit and will be truncated."); TruncateToFitCharacterLimit(); } return _embed; } private bool IsWithinCharacterLimit() { int num = 0; num += _embed.title?.Length ?? 0; num += _embed.description?.Length ?? 0; num += (_embed.footer?.text?.Length).GetValueOrDefault(); num += (_embed.author?.name?.Length).GetValueOrDefault(); if (_fields != null && _fields.Count > 0) { foreach (DiscordField field in _fields) { num += field.name?.Length ?? 0; num += field.value?.Length ?? 0; } } return num <= 6000; } private void TruncateToFitCharacterLimit() { if (!string.IsNullOrEmpty(_embed.description)) { string? description = _embed.description; if (description != null && description.Length > 1000) { _embed.description = _embed.description.Substring(0, 1000) + "..."; } } if (_fields.Count > 0) { foreach (DiscordField field in _fields) { if (!string.IsNullOrEmpty(field.value)) { string? value = field.value; if (value != null && value.Length > 500) { field.value = field.value.Substring(0, 500) + "..."; } } } } while (_fields.Count > 1 && !IsWithinCharacterLimit()) { _fields.RemoveAt(_fields.Count - 1); } } public string? GetDescriptionForFallback() { try { if (!string.IsNullOrEmpty(_embed.description)) { return _embed.description; } if (!string.IsNullOrEmpty(_embed.title)) { return _embed.title; } if (_embed.author != null && !string.IsNullOrEmpty(_embed.author.name)) { return _embed.author.name; } if (_fields.Count > 0) { List<string> list = new List<string>(); int num = Math.Min(_fields.Count, 3); for (int i = 0; i < num; i++) { if (!string.IsNullOrEmpty(_fields[i].name) && !string.IsNullOrEmpty(_fields[i].value)) { string text = _fields[i].name + ": " + _fields[i].value; if (text != null && text.Length > 100) { text = text.Substring(0, 100) + "..."; } if (text != null) { list.Add(text); } } } if (list.Count > 0) { return string.Join(" | ", list); } } return null; } catch (Exception ex) { DiscordConnectorPlugin.StaticLogger.LogError("Error extracting fallback content: " + ex.Message); return null; } } } internal static class EmbedTemplates { public static EmbedBuilder ServerLifecycle(Webhook.Event eventType, string message, string worldName, string serverName) { Dictionary<string, string> dictionary = new Dictionary<string, string> { { "worldName", worldName }, { "serverName", serverName }, { "timestamp", DateTime.UtcNow.ToString("s") } }; EmbedBuilder embedBuilder = new EmbedBuilder().SetColorForEvent(eventType).SetAuthor(serverName, null, DiscordConnectorPlugin.StaticConfig.EmbedAuthorIconUrl).SetTimestamp(); if (DiscordConnectorPlugin.StaticConfig.EmbedThumbnailEnabled) { embedBuilder.SetThumbnail(DiscordConnectorPlugin.StaticConfig.EmbedThumbnailUrl); } if (Webhook.ServerLaunchEvents.Contains(eventType)) { embedBuilder.SetTitle("\ud83d\ude80 Server Launching"); } else if (Webhook.ServerStartEvents.Contains(eventType)) { embedBuilder.SetTitle("✅ Server Started"); } else if (Webhook.ServerStopEvents.Contains(eventType)) { embedBuilder.SetTitle("\ud83d\uded1 Server Stopping"); } else if (Webhook.ServerShutdownEvents.Contains(eventType)) { embedBuilder.SetTitle("⛔ Server Shutdown"); } else if (Webhook.ServerSaveEvents.Contains(eventType)) { embedBuilder.SetTitle("\ud83d\udcbe World Saved"); } embedBuilder.SetDescription(message); embedBuilder.AddInlineField("World", worldName); embedBuilder.AddInlineField("Status", GetStatusForEvent(eventType)); embedBuilder.SetFooterFromTemplate(dictionary); embedBuilder.SetUrlFromTemplate(dictionary); return embedBuilder; } public static EmbedBuilder PlayerEvent(Webhook.Event eventType, string message, string playerName, Vector3? position = null, string worldName = "", string playerHostName = "") { //IL_019e: Unknown result type (might be due to invalid IL or missing references) Dictionary<string, string> dictionary = new Dictionary<string, string> { { "worldName", worldName }, { "playerName", playerName }, { "timestamp", DateTime.UtcNow.ToString("s") } }; string serverName = DiscordConnectorPlugin.StaticConfig.ServerName; EmbedBuilder embedBuilder = new EmbedBuilder().SetColorForEvent(eventType).SetAuthor(serverName, null, DiscordConnectorPlugin.StaticConfig.EmbedAuthorIconUrl).SetTimestamp(); if (Webhook.PlayerJoinEvents.Contains(eventType)) { embedBuilder.SetTitle("\ud83d\udc4b Player Joined"); if (DiscordConnectorPlugin.StaticConfig.EmbedThumbnailEnabled) { embedBuilder.SetThumbnail(DiscordConnectorPlugin.StaticConfig.EmbedThumbnailUrl); } } else if (Webhook.PlayerLeaveEvents.Contains(eventType)) { embedBuilder.SetTitle("\ud83d\udeb6 Player Left"); if (DiscordConnectorPlugin.StaticConfig.EmbedThumbnailEnabled) { embedBuilder.SetThumbnail(DiscordConnectorPlugin.StaticConfig.EmbedThumbnailUrl); } } else if (Webhook.PlayerDeathEvents.Contains(eventType)) { embedBuilder.SetTitle("\ud83d\udc80 Player Death"); if (DiscordConnectorPlugin.StaticConfig.EmbedThumbnailEnabled) { embedBuilder.SetThumbnail(DiscordConnectorPlugin.StaticConfig.EmbedThumbnailUrl); } } else if (Webhook.PlayerPingEvents.Contains(eventType)) { embedBuilder.SetTitle("\ud83d\udccd Player Pings"); if (DiscordConnectorPlugin.StaticConfig.EmbedThumbnailEnabled) { embedBuilder.SetThumbnail(DiscordConnectorPlugin.StaticConfig.EmbedThumbnailUrl); } } embedBuilder.SetDescription(message); embedBuilder.AddInlineField("Player", playerName); if (DiscordConnectorPlugin.StaticConfig.ShowPlayerIds && !string.IsNullOrEmpty(playerHostName)) { embedBuilder.AddInlineField("Player ID", playerHostName); } if (position.HasValue) { embedBuilder.AddPositionField(position.Value); } embedBuilder.SetFooterFromTemplate(dictionary); embedBuilder.SetUrlFromTemplate(dictionary); return embedBuilder; } public static EmbedBuilder WorldEvent(Webhook.Event eventType, string message, string eventName, string worldName) { Dictionary<string, string> dictionary = new Dictionary<string, string> { { "worldName", worldName }, { "eventName", eventName }, { "timestamp", DateTime.UtcNow.ToString("s") } }; string serverName = DiscordConnectorPlugin.StaticConfig.ServerName; EmbedBuilder embedBuilder = new EmbedBuilder().SetColorForEvent(eventType).SetAuthor(serverName, null, DiscordConnectorPlugin.StaticConfig.EmbedAuthorIconUrl).SetTimestamp(); if (Webhook.Event.EventStart == eventType) { embedBuilder.SetTitle("\ud83c\udf29\ufe0f Event Started: " + eventName); embedBuilder.SetColor(DiscordConnectorPlugin.StaticConfig.EmbedWorldEventColor); if (DiscordConnectorPlugin.StaticConfig.EmbedThumbnailEnabled) { embedBuilder.SetThumbnail(DiscordConnectorPlugin.StaticConfig.EmbedThumbnailUrl); } } else if (Webhook.Event.EventStop == eventType) { embedBuilder.SetTitle("☀\ufe0f Event Ended: " + eventName); embedBuilder.SetColor(DiscordConnectorPlugin.StaticConfig.EmbedWorldEventColor); if (DiscordConnectorPlugin.StaticConfig.EmbedThumbnailEnabled) { embedBuilder.SetThumbnail(DiscordConnectorPlugin.StaticConfig.EmbedThumbnailUrl); } } else if (Webhook.Event.NewDayNumber == eventType) { embedBuilder.SetTitle("\ud83c\udf05 New Day: " + eventName); embedBuilder.SetColor(DiscordConnectorPlugin.StaticConfig.EmbedNewDayColor); if (DiscordConnectorPlugin.StaticConfig.EmbedThumbnailEnabled) { embedBuilder.SetThumbnail(DiscordConnectorPlugin.StaticConfig.EmbedThumbnailUrl); } } else if (Webhook.Event.ServerSave == eventType) { embedBuilder.SetTitle("\ud83d\udcbe World Saved"); embedBuilder.SetColor(DiscordConnectorPlugin.StaticConfig.EmbedServerSaveColor); } embedBuilder.SetDescription(message); embedBuilder.SetFooterFromTemplate(dictionary); embedBuilder.SetUrlFromTemplate(dictionary); return embedBuilder; } public static EmbedBuilder ChatMessage(Webhook.Event eventType, string message, string playerName, Vector3? position = null, string worldName = "") { //IL_00ff: Unknown result type (might be due to invalid IL or missing references) Dictionary<string, string> dictionary = new Dictionary<string, string> { { "worldName", worldName }, { "playerName", playerName }, { "timestamp", DateTime.UtcNow.ToString("s") } }; string serverName = DiscordConnectorPlugin.StaticConfig.ServerName; EmbedBuilder embedBuilder = new EmbedBuilder().SetColorForEvent(eventType).SetAuthor(serverName, null, DiscordConnectorPlugin.StaticConfig.EmbedAuthorIconUrl).SetTimestamp(); embedBuilder.AddInlineField("Player", playerName); if (Webhook.PlayerShoutEvents.Contains(eventType)) { embedBuilder.SetTitle("\ud83d\udce3 Shout Message"); if (DiscordConnectorPlugin.StaticConfig.EmbedThumbnailEnabled) { embedBuilder.SetThumbnail(DiscordConnectorPlugin.StaticConfig.EmbedThumbnailUrl); } } else { embedBuilder.SetTitle("\ud83d\udcac Chat Message"); if (DiscordConnectorPlugin.StaticConfig.EmbedThumbnailEnabled) { embedBuilder.SetThumbnail(DiscordConnectorPlugin.StaticConfig.EmbedThumbnailUrl); } } embedBuilder.SetDescription("> " + message); if (position.HasValue) { embedBuilder.AddPositionField(position.Value); } embedBuilder.SetFooterFromTemplate(dictionary); embedBuilder.SetUrlFromTemplate(dictionary); return embedBuilder; } public static EmbedBuilder PositionMessage(Webhook.Event eventType, string message, string playerName, Vector3 position, string worldName = "") { //IL_0130: Unknown result type (might be due to invalid IL or missing references) Dictionary<string, string> dictionary = new Dictionary<string, string> { { "worldName", worldName }, { "playerName", playerName }, { "timestamp", DateTime.UtcNow.ToString("s") } }; string serverName = DiscordConnectorPlugin.StaticConfig.ServerName; EmbedBuilder embedBuilder = new EmbedBuilder().SetAuthor(serverName, null, DiscordConnectorPlugin.StaticConfig.EmbedAuthorIconUrl).SetTimestamp(); if (DiscordConnectorPlugin.StaticConfig.EmbedThumbnailEnabled) { embedBuilder.SetThumbnail(DiscordConnectorPlugin.StaticConfig.EmbedThumbnailUrl); } if (Webhook.Event.EventStop == eventType) { embedBuilder.SetTitle("☀\ufe0f Event Stopped"); embedBuilder.SetColor(DiscordConnectorPlugin.StaticConfig.EmbedWorldEventColor); } else if (Webhook.Event.EventStart == eventType) { embedBuilder.SetTitle("\ud83c\udf29\ufe0f Event Started"); embedBuilder.SetColor(DiscordConnectorPlugin.StaticConfig.EmbedWorldEventColor); } else if (Webhook.Event.EventPaused == eventType) { embedBuilder.SetTitle("⏸\ufe0f Event Paused"); embedBuilder.SetColor(DiscordConnectorPlugin.StaticConfig.EmbedWorldEventColor); } else if (Webhook.Event.EventResumed == eventType) { embedBuilder.SetTitle("▶\ufe0f Event Resumed"); embedBuilder.SetColor(DiscordConnectorPlugin.StaticConfig.EmbedWorldEventColor); } else { embedBuilder.SetTitle("Event Update"); } embedBuilder.SetDescription(message); embedBuilder.AddField("Coordinates", MessageTransformer.FormatVector3AsPos(position)); embedBuilder.SetFooterFromTemplate(dictionary); embedBuilder.SetUrlFromTemplate(dictionary); return embedBuilder; } public static EmbedBuilder ActivePlayersAnnouncement(string message, string worldName = "") { Dictionary<string, string> dictionary = new Dictionary<string, string> { { "worldName", worldName }, { "timestamp", DateTime.UtcNow.ToString("s") } }; string serverName = DiscordConnectorPlugin.StaticConfig.ServerName; EmbedBuilder embedBuilder = new EmbedBuilder().SetColor(DiscordConnectorPlugin.StaticConfig.EmbedActivePlayersColor).SetAuthor(serverName, null, DiscordConnectorPlugin.StaticConfig.EmbedAuthorIconUrl).SetTitle("\ud83d\udc65 Active Players") .SetDescription(message) .SetTimestamp(); if (DiscordConnectorPlugin.StaticConfig.EmbedThumbnailEnabled) { embedBuilder.SetThumbnail(DiscordConnectorPlugin.StaticConfig.EmbedThumbnailUrl); } embedBuilder.SetFooterFromTemplate(dictionary); embedBuilder.SetUrlFromTemplate(dictionary); return embedBuilder; } public static EmbedBuilder LeaderboardEmbed(string title, List<Tuple<string, string>> fields, string worldName = "") { Dictionary<string, string> dictionary = new Dictionary<string, string> { { "worldName", worldName }, { "timestamp", DateTime.UtcNow.ToString("s") } }; string serverName = DiscordConnectorPlugin.StaticConfig.ServerName; EmbedBuilder embedBuilder = new EmbedBuilder().SetColor(DiscordConnectorPlugin.StaticConfig.EmbedLeaderboardEmbedColor).SetAuthor(serverName, null, DiscordConnectorPlugin.StaticConfig.EmbedAuthorIconUrl).SetTitle("\ud83c\udfc6 " + title) .SetTimestamp(); if (DiscordConnectorPlugin.StaticConfig.EmbedThumbnailEnabled) { embedBuilder.SetThumbnail(DiscordConnectorPlugin.StaticConfig.EmbedThumbnailUrl); } foreach (Tuple<string, string> field in fields) { embedBuilder.AddField(field.Item1, MessageTransformer.FormatFieldContent(field.Item2)); } embedBuilder.SetFooterFromTemplate(dictionary); embedBuilder.SetUrlFromTemplate(dictionary); return embedBuilder; } private static string GetStatusForEvent(Webhook.Event eventType) { if (Webhook.ServerLaunchEvents.Contains(eventType)) { return "Launching"; } if (Webhook.ServerStartEvents.Contains(eventType)) { return "Online"; } if (Webhook.ServerStopEvents.Contains(eventType)) { return "Stopping"; } if (Webhook.ServerShutdownEvents.Contains(eventType)) { return "Offline"; } return eventType switch { Webhook.Event.ServerSave => "Online", Webhook.Event.NewDayNumber => "Online", _ => "Unknown", }; } } internal class EventWatcher { private static class Status { public static bool HaveActiveEvent => RandEventSystem.HaveActiveEvent(); public static RandomEvent? Event { get { if (!HaveActiveEvent) { return null; } return RandEventSystem.instance.GetCurrentRandomEvent(); } } public static string Name { get { if (!HaveActiveEvent || Event == null) { return ""; } return Event.m_name; } } public static float Duration { get { if (!HaveActiveEvent || Event == null) { return 0f; } return Event.m_duration; } } public static float Elapsed { get { if (!HaveActiveEvent || Event == null) { return 0f; } return Event.m_time; } } public static bool IsRunning { get { if (HaveActiveEvent) { return RandEventSystem.instance.IsAnyPlayerInEventArea(Event); } return false; } } public static Vector3 Pos { get { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) if (!HaveActiveEvent || Event == null) { return new Vector3(0f, 0f, 0f); } return Event.m_pos; } } public static string EndMessage { get { if (!HaveActiveEvent || Event == null) { return ""; } return Localization.instance.Localize(Event.m_endMessage); } } public static string StartMessage { get { if (!HaveActiveEvent || Event == null) { return ""; } return Localization.instance.Localize(Event.m_startMessage); } } public static string[] InvolvedPlayersList() { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) List<string> list = new List<string>(); if (!HaveActiveEvent) { return list.ToArray(); } foreach (PlayerInfo player in ZNet.instance.GetPlayerList()) { if (!player.m_publicPosition) { if (DiscordConnectorPlugin.StaticConfig.DebugEveryPlayerPosCheck) { DiscordConnectorPlugin.StaticLogger.LogDebug("Unable to check location for " + player.m_name + " because their location is not public."); } } else if (RandEventSystem.instance.IsInsideRandomEventArea(Event, player.m_position)) { list.Add(player.m_name); if (DiscordConnectorPlugin.StaticConfig.DebugEveryPlayerPosCheck) { DiscordConnectorPlugin.StaticLogger.LogDebug($"{player.m_name} is at {player.m_position}"); } } } return list.ToArray(); } } private readonly System.Timers.Timer randEventTimer; private float PreviousElapsed; private Vector3 PreviousEventPos; private string PreviousEventStartMessage; private string PreviousEventEndMessage; private bool WasRunning; private bool HadActiveEvent; public EventWatcher() { //IL_003b: Unknown result type (might be due to invalid IL or missing references) WasRunning = false; HadActiveEvent = false; PreviousElapsed = 0f; PreviousEventStartMessage = ""; PreviousEventEndMessage = ""; PreviousEventPos = default(Vector3); randEventTimer = new System.Timers.Timer(); randEventTimer.Elapsed += CheckRandomEvent; randEventTimer.Interval = 1000.0; } public void Activate() { randEventTimer.Start(); } public void Dispose() { randEventTimer.Stop(); } public void CheckRandomEvent(object sender, ElapsedEventArgs elapsedEventArgs) { //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_01dd: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_01ae: Unknown result type (might be due to invalid IL or missing references) //IL_01b3: Unknown result type (might be due to invalid IL or missing references) if (Status.HaveActiveEvent) { string message = $"Currently an event: {Status.HaveActiveEvent}. {Status.StartMessage} | {Status.EndMessage}" + Environment.NewLine + $"Event: {Status.Name} at {Status.Pos}. Status.IsRunning: {Status.IsRunning}. {Status.Elapsed} of {Status.Duration} seconds completed." + Environment.NewLine + $"PreviousEventStartMsg: {PreviousEventStartMessage}, PreviousEventEndMsg: {PreviousEventEndMessage}, PreviousEventPos: {PreviousEventPos}" + Environment.NewLine + "Involved Players: " + string.Join(",", Status.InvolvedPlayersList()); if (DiscordConnectorPlugin.StaticConfig.DebugEveryEventCheck) { DiscordConnectorPlugin.StaticLogger.LogDebug(message); } if (Status.IsRunning) { if (!HadActiveEvent) { TriggerEventStart(); if (DiscordConnectorPlugin.StaticConfig.DebugEveryEventChange) { DiscordConnectorPlugin.StaticLogger.LogDebug(message); } } if (HadActiveEvent && !WasRunning) { TriggerEventResumed(); if (DiscordConnectorPlugin.StaticConfig.DebugEveryEventChange) { DiscordConnectorPlugin.StaticLogger.LogDebug(message); } } } else if (!HadActiveEvent || (HadActiveEvent && WasRunning)) { TriggerEventPaused(); if (DiscordConnectorPlugin.StaticConfig.DebugEveryEventChange) { DiscordConnectorPlugin.StaticLogger.LogDebug(message); } } if (Status.Pos != Vector3.zero) { PreviousEventStartMessage = Status.StartMessage; PreviousEventEndMessage = Status.EndMessage; PreviousEventPos = Status.Pos; } } else { if (DiscordConnectorPlugin.StaticConfig.DebugEveryEventCheck) { DiscordConnectorPlugin.StaticLogger.LogDebug($"PreviousEventStartMsg: {PreviousEventStartMessage}, PreviousEventEndMsg: {PreviousEventEndMessage}, PreviousEventPos: {PreviousEventPos}" + Environment.NewLine + "Event check ran, no current events (or world isn't loaded yet)."); } if (HadActiveEvent) { TriggerEventStop(); if (DiscordConnectorPlugin.StaticConfig.DebugEveryEventChange) { DiscordConnectorPlugin.StaticLogger.LogDebug("Event stopped!"); } } } HadActiveEvent = Status.HaveActiveEvent; WasRunning = Status.IsRunning; PreviousElapsed = Status.Elapsed; } internal void TriggerEventStart() { //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) if (DiscordConnectorPlugin.StaticConfig.EventStartMessageEnabled) { string text = MessageTransformer.FormatEventStartMessage(DiscordConnectorPlugin.StaticConfig.EventResumedMessage, Status.StartMessage, Status.EndMessage); if (!DiscordConnectorPlugin.StaticConfig.EventStartPosEnabled) { DiscordApi.SendMessage(Webhook.Event.EventStart, text); return; } if (DiscordConnectorPlugin.StaticConfig.DiscordEmbedsEnabled || !text.Contains("%POS%")) { DiscordApi.SendMessage(Webhook.Event.EventStart, text, Status.Pos); return; } text = MessageTransformer.FormatEventStartMessage(DiscordConnectorPlugin.StaticConfig.EventResumedMessage, Status.EndMessage, Status.StartMessage, Status.Pos); DiscordApi.SendMessage(Webhook.Event.EventStart, text); } } internal void TriggerEventPaused() { //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) if (DiscordConnectorPlugin.StaticConfig.EventPausedMessageEnabled) { string text = MessageTransformer.FormatEventMessage(DiscordConnectorPlugin.StaticConfig.EventPausedMessage, Status.StartMessage, Status.EndMessage); if (!DiscordConnectorPlugin.StaticConfig.EventPausedPosEnabled) { DiscordApi.SendMessage(Webhook.Event.EventPaused, text); return; } if (DiscordConnectorPlugin.StaticConfig.DiscordEmbedsEnabled || !text.Contains("%POS%")) { DiscordApi.SendMessage(Webhook.Event.EventPaused, text, Status.Pos); return; } text = MessageTransformer.FormatEventMessage(DiscordConnectorPlugin.StaticConfig.EventPausedMessage, Status.StartMessage, Status.EndMessage, Status.Pos); DiscordApi.SendMessage(Webhook.Event.EventPaused, text); } } internal void TriggerEventResumed() { //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) if (DiscordConnectorPlugin.StaticConfig.EventResumedMessageEnabled) { string text = MessageTransformer.FormatEventMessage(DiscordConnectorPlugin.StaticConfig.EventResumedMessage, Status.StartMessage, Status.EndMessage); if (!DiscordConnectorPlugin.StaticConfig.EventResumedPosEnabled) { DiscordApi.SendMessage(Webhook.Event.EventResumed, text); return; } if (DiscordConnectorPlugin.StaticConfig.DiscordEmbedsEnabled || !text.Contains("%POS%")) { DiscordApi.SendMessage(Webhook.Event.EventResumed, text, Status.Pos); return; } text = MessageTransformer.FormatEventMessage(DiscordConnectorPlugin.StaticConfig.EventResumedMessage, Status.StartMessage, Status.EndMessage, Status.Pos); DiscordApi.SendMessage(Webhook.Event.EventResumed, text); } } internal void TriggerEventStop() { //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) if (DiscordConnectorPlugin.StaticConfig.EventStopMessageEnabled) { string text = MessageTransformer.FormatEventEndMessage(DiscordConnectorPlugin.StaticConfig.EventStopMessage, PreviousEventStartMessage, PreviousEventEndMessage); if (!DiscordConnectorPlugin.StaticConfig.EventStopPosEnabled) { DiscordApi.SendMessage(Webhook.Event.EventStop, text); return; } if (DiscordConnectorPlugin.StaticConfig.DiscordEmbedsEnabled || !text.Contains("%POS%")) { DiscordApi.SendMessage(Webhook.Event.EventStop, text, PreviousEventPos); return; } text = MessageTransformer.FormatEventEndMessage(DiscordConnectorPlugin.StaticConfig.EventStopMessage, PreviousEventStartMessage, PreviousEventEndMessage, PreviousEventPos); DiscordApi.SendMessage(Webhook.Event.EventStop, text); } } } internal static class Handlers { public static HashSet<string> joinedPlayers = new HashSet<string>(); public static void Join(ZNetPeer peer) { //IL_00f5: Unknown result type (might be due to invalid IL or missing references) if (peer == null) { DiscordConnectorPlugin.StaticLogger.LogDebug("Handler:Join - Guarded against null peer"); return; } Webhook.Event ev = Webhook.Event.PlayerJoin; string text = peer.m_socket.GetHostName() ?? ""; if (!joinedPlayers.Add(text)) { DiscordConnectorPlugin.StaticLogger.LogDebug(text + " already exists in list of joined players."); if (((ZDOID)(ref peer.m_characterID)).ID != 0) { Death(peer); } return; } DiscordConnectorPlugin.StaticLogger.LogDebug($"Added player {text} peer_id:{peer.m_uid} ({peer.m_playerName}) to joined player list."); string text2 = ""; if (DiscordConnectorPlugin.StaticConfig.AnnouncePlayerFirstJoinEnabled && DiscordConnectorPlugin.StaticDatabase.CountOfRecordsByName("join", peer.m_playerName) == 0) { text2 = DiscordConnectorPlugin.StaticConfig.PlayerFirstJoinMessage; ev = Webhook.Event.PlayerFirstJoin; } else if (DiscordConnectorPlugin.StaticConfig.PlayerJoinMessageEnabled) { text2 = DiscordConnectorPlugin.StaticConfig.JoinMessage; } if (DiscordConnectorPlugin.StaticConfig.StatsJoinEnabled) { DiscordConnectorPlugin.StaticDatabase.InsertSimpleStatRecord("join", peer.m_playerName, text, peer.m_refPos); } if (!string.IsNullOrEmpty(text2)) { FinalizeFormattingAndSend(peer, text, text2, DiscordConnectorPlugin.StaticConfig.PlayerJoinPosEnabled, ev); } } public static void Leave(ZNetPeer peer) { //IL_00e2: Unknown result type (might be due to invalid IL or missing references) if (peer == null) { DiscordConnectorPlugin.StaticLogger.LogDebug("Handler:Leave - Guarded against null peer"); return; } Webhook.Event ev = Webhook.Event.PlayerLeave; string text = peer.m_socket.GetHostName() ?? ""; if (!joinedPlayers.Remove(text)) { DiscordConnectorPlugin.StaticLogger.LogDebug(text + " did not exist in the list of joined players!"); return; } DiscordConnectorPlugin.StaticLogger.LogDebug($"Removed player {text} peer_id:{peer.m_uid} ({peer.m_playerName}) from joined player list."); string text2 = ""; if (DiscordConnectorPlugin.StaticConfig.AnnouncePlayerFirstLeaveEnabled && DiscordConnectorPlugin.StaticDatabase.CountOfRecordsByName("leave", peer.m_playerName) == 0) { text2 = DiscordConnectorPlugin.StaticConfig.PlayerFirstLeaveMessage; ev = Webhook.Event.PlayerFirstLeave; } else if (DiscordConnectorPlugin.StaticConfig.PlayerLeaveMessageEnabled) { text2 = DiscordConnectorPlugin.StaticConfig.LeaveMessage; } if (DiscordConnectorPlugin.StaticConfig.StatsLeaveEnabled) { DiscordConnectorPlugin.StaticDatabase.InsertSimpleStatRecord("leave", peer.m_playerName, text, peer.m_refPos); } if (!string.IsNullOrEmpty(text2)) { FinalizeFormattingAndSend(peer, text, text2, DiscordConnectorPlugin.StaticConfig.PlayerLeavePosEnabled, ev); } } public static void Death(ZNetPeer peer) { //IL_0099: Unknown result type (might be due to invalid IL or missing references) if (peer == null) { DiscordConnectorPlugin.StaticLogger.LogDebug("Handler:Death - Guarded against null peer"); return; } Webhook.Event ev = Webhook.Event.PlayerDeath; string playerHostName = peer.m_socket.GetHostName() ?? ""; string text = ""; if (DiscordConnectorPlugin.StaticConfig.AnnouncePlayerFirstDeathEnabled && DiscordConnectorPlugin.StaticDatabase.CountOfRecordsByName("death", peer.m_playerName) == 0) { text = DiscordConnectorPlugin.StaticConfig.PlayerFirstDeathMessage; ev = Webhook.Event.PlayerFirstDeath; } else if (DiscordConnectorPlugin.StaticConfig.PlayerDeathMessageEnabled) { text = DiscordConnectorPlugin.StaticConfig.DeathMessage; } if (DiscordConnectorPlugin.StaticConfig.StatsDeathEnabled) { DiscordConnectorPlugin.StaticDatabase.InsertSimpleStatRecord("death", peer.m_playerName, playerHostName, peer.m_refPos); } if (!string.IsNullOrEmpty(text)) { FinalizeFormattingAndSend(peer, playerHostName, text, DiscordConnectorPlugin.StaticConfig.PlayerDeathPosEnabled, ev); } } public static void Ping(ZNetPeer peer, Vector3 pos) { //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) if (peer == null) { DiscordConnectorPlugin.StaticLogger.LogDebug("Handler:Ping - Guarded against null peer"); return; } Webhook.Event ev = Webhook.Event.PlayerPing; string playerHostName = peer.m_socket.GetHostName() ?? ""; string text = ""; if (DiscordConnectorPlugin.StaticConfig.AnnouncePlayerFirstPingEnabled && DiscordConnectorPlugin.StaticDatabase.CountOfRecordsByName("ping", peer.m_playerName) == 0) { text = DiscordConnectorPlugin.StaticConfig.PlayerFirstPingMessage; ev = Webhook.Event.PlayerFirstPing; } else if (DiscordConnectorPlugin.StaticConfig.ChatPingEnabled) { text = DiscordConnectorPlugin.StaticConfig.PingMessage; } if (DiscordConnectorPlugin.StaticConfig.StatsPingEnabled) { DiscordConnectorPlugin.StaticDatabase.InsertSimpleStatRecord("ping", peer.m_playerName, playerHostName, pos); } if (!string.IsNullOrEmpty(text)) { FinalizeFormattingAndSend(peer, playerHostName, text, DiscordConnectorPlugin.StaticConfig.ChatPingPosEnabled, pos, ev); } } public static void Shout(ZNetPeer peer, Vector3 pos, string text) { //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) if (peer == null) { DiscordConnectorPlugin.StaticLogger.LogDebug("Handler:Shout - Guarded against null peer"); return; } Webhook.Event ev = Webhook.Event.PlayerShout; string playerHostName = peer.m_socket.GetHostName() ?? ""; string text2 = ""; if (DiscordConnectorPlugin.StaticConfig.AnnouncePlayerFirstShoutEnabled && DiscordConnectorPlugin.StaticDatabase.CountOfRecordsByName("shout", peer.m_playerName) == 0) { text2 = DiscordConnectorPlugin.StaticConfig.PlayerFirstShoutMessage; ev = Webhook.Event.PlayerFirstShout; } else if (DiscordConnectorPlugin.StaticConfig.ChatShoutEnabled) { text2 = DiscordConnectorPlugin.StaticConfig.ShoutMessage; } if (DiscordConnectorPlugin.StaticConfig.StatsShoutEnabled) { DiscordConnectorPlugin.StaticDatabase.InsertSimpleStatRecord("shout", peer.m_playerName, playerHostName, pos); } if (!string.IsNullOrEmpty(text2)) { if (DiscordConnectorPlugin.StaticConfig.ChatShoutAllCaps) { text = text.ToUpper(); } FinalizeFormattingAndSend(peer, playerHostName, text2, DiscordConnectorPlugin.StaticConfig.ChatShoutPosEnabled, pos, text, ev); } } private static void FinalizeFormattingAndSend(ZNetPeer peer, string playerHostName, string preFormattedMessage, bool posEnabled, Webhook.Event ev) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) FinalizeFormattingAndSend(peer, playerHostName, preFormattedMessage, posEnabled, peer.m_refPos, ev); } private static void FinalizeFormattingAndSend(ZNetPeer peer, string playerHostName, string preFormattedMessage, bool posEnabled, Vector3 pos, Webhook.Event ev) { //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) bool subtractOne = ev == Webhook.Event.PlayerLeave || ev == Webhook.Event.PlayerFirstLeave; string text; if (preFormattedMessage.Contains("%POS%")) { if (!posEnabled) { preFormattedMessage = preFormattedMessage.Replace("%POS%", ""); } text = MessageTransformer.FormatPlayerMessage(preFormattedMessage, peer.m_playerName, playerHostName, pos, subtractOne); } else { text = MessageTransformer.FormatPlayerMessage(preFormattedMessage, peer.m_playerName, playerHostName, subtractOne); } if (DiscordConnectorPlugin.StaticConfig.DiscordEmbedsEnabled) { EmbedBuilder embedBuilder = (Webhook.PlayerDeathEvents.Contains(ev) ? MessageTransformer.CreateDeathEmbed(peer, text, ev) : ((!posEnabled) ? MessageTransformer.CreatePlayerMessageEmbed(text, ev, peer.m_playerName, playerHostName, subtractOne) : MessageTransformer.CreatePlayerMessageEmbed(text, ev, peer.m_playerName, playerHostName, pos, subtractOne))); DiscordApi.SendEmbed(ev, embedBuilder); } else if (posEnabled) { DiscordApi.SendMessage(ev, text, pos); } else { DiscordApi.SendMessage(ev, text); } } private static void FinalizeFormattingAndSend(ZNetPeer peer, string playerHostName, string preFormattedMessage, bool posEnabled, Vector3 pos, string text, Webhook.Event ev) { //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) if (preFormattedMessage.Contains("%SHOUT%") && string.IsNullOrEmpty(text)) { preFormattedMessage = preFormattedMessage.Replace("%SHOUT%", ""); } string text2; if (preFormattedMessage.Contains("%POS%")) { if (!posEnabled) { preFormattedMessage = preFormattedMessage.Replace("%POS%", ""); } text2 = MessageTransformer.FormatPlayerMessage(preFormattedMessage, peer.m_playerName, playerHostName, text, pos); } else { text2 = MessageTransformer.FormatPlayerMessage(preFormattedMessage, peer.m_playerName, playerHostName, text); } if (DiscordConnectorPlugin.StaticConfig.DiscordEmbedsEnabled) { EmbedBuilder embedBuilder; if (!Webhook.PlayerShoutEvents.Contains(ev)) { embedBuilder = ((!posEnabled) ? MessageTransformer.CreatePlayerMessageEmbed(text2, ev, peer.m_playerName, playerHostName) : MessageTransformer.CreatePlayerMessageEmbed(text2, ev, peer.m_playerName, playerHostName, pos)); } else { embedBuilder = MessageTransformer.CreateShoutMessageEmbed(text2, ev, peer.m_playerName, playerHostName, text); if (posEnabled) { embedBuilder.AddField("Position", MessageTransformer.FormatVector3AsPos(pos), inline: true); } } DiscordApi.SendEmbed(ev, embedBuilder); } else if (posEnabled) { DiscordApi.SendMessage(ev, text2, pos); } else { DiscordApi.SendMessage(ev, text2); } } internal static void NonPlayerChat(Type type, string user, string text) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Invalid comparison between Unknown and I4 if (DiscordConnectorPlugin.StaticConfig.AllowNonPlayerShoutLogging) { if ((int)type != 2) { DiscordConnectorPlugin.StaticLogger.LogDebug("Ignored ping/join/leave from non-player " + user); return; } string playerId = ""; DiscordConnectorPlugin.StaticLogger.LogDebug("Sending shout from '" + user + "' to discord: '" + text + "'"); if (DiscordConnectorPlugin.StaticConfig.ChatShoutEnabled) { string playerName = MessageTransformer.CleanCaretFormatting(user); string text2 = MessageTransformer.FormatPlayerMessage(DiscordConnectorPlugin.StaticConfig.ShoutMessage, playerName, playerId, text); if (text2.Contains("%POS%")) { text2.Replace("%POS%", ""); } DiscordApi.SendMessage(Webhook.Event.PlayerShout, text2); } } else { DiscordConnectorPlugin.StaticLogger.LogInfo("Ignored shout from " + user + " because they aren't a real player"); } } } internal class LeaderbBoard { public static readonly int MAX_LEADER_BOARD_SIZE = 16; public Base LeaderBoard1 { get; } public Base LeaderBoard2 { get; } public Base LeaderBoard3 { get; } public Base LeaderBoard4 { get; } public Base LeaderBoard5 { get; } public LeaderbBoard() { LeaderBoard1 = new Composer(0); LeaderBoard2 = new Composer(1); LeaderBoard3 = new Composer(2); LeaderBoard4 = new Composer(3); LeaderBoard5 = new Composer(4); } public static string RankedCountResultToString(List<CountResult> rankings) { string text = ""; for (int i = 0; i < rankings.Count; i++) { text += $"{i + 1}: {rankings[i].Name}: {rankings[i].Count}{Environment.NewLine}"; } return text; } private static string ToReadableString(TimeSpan span) { string text = string.Format("{0}{1}{2}{3}", (span.Duration().Days > 0) ? string.Format("{0:0} day{1}, ", span.Days, (span.Days == 1) ? string.Empty : "s") : string.Empty, (span.Duration().Hours > 0) ? string.Format("{0:0} hour{1}, ", span.Hours, (span.Hours == 1) ? string.Empty : "s") : string.Empty, (span.Duration().Minutes > 0) ? string.Format("{0:0} minute{1}, ", span.Minutes, (span.Minutes == 1) ? string.Empty : "s") : string.Empty, (span.Duration().Seconds > 0) ? string.Format("{0:0} second{1}", span.Seconds, (span.Seconds == 1) ? string.Empty : "s") : string.Empty); if (text.EndsWith(", ")) { text = text.Substring(0, text.Length - 2); } if (string.IsNullOrEmpty(text)) { text = "0 seconds"; } return text; } public static string RankedSecondsToString(List<CountResult> rankings) { string text = ""; for (int i = 0; i < rankings.Count; i++) { string text2 = ToReadableString(TimeSpan.FromSeconds(rankings[i].Count)); text += $"{i + 1}: {rankings[i].Name}: {text2}{Environment.NewLine}"; } return text; } } internal static class MessageTransformer { private const string PUBLIC_IP = "%PUBLICIP%"; private const string VAR = "%VAR1%"; private const string VAR_1 = "%VAR2%"; private const string VAR_2 = "%VAR3%"; private const string VAR_3 = "%VAR4%"; private const string VAR_4 = "%VAR5%"; private const string VAR_5 = "%VAR6%"; private const string VAR_6 = "%VAR7%"; private const string VAR_7 = "%VAR8%"; private const string VAR_8 = "%VAR9%"; private const string VAR_9 = "%VAR10%"; private const string PLAYER_NAME = "%PLAYER_NAME%"; private const string PLAYER_STEAMID = "%PLAYER_STEAMID%"; private const string PLAYER_ID = "%PLAYER_ID%"; private const string SHOUT = "%SHOUT%"; private const string POS = "%POS%"; private const string EVENT_START_MSG = "%EVENT_START_MSG%"; private const string EVENT_END_MSG = "%EVENT_END_MSG%"; private const string EVENT_MSG = "%EVENT_MSG%"; private const string EVENT_PLAYERS = "%PLAYERS%"; private const string N = "%N%"; private const string WORLD_NAME = "%WORLD_NAME%"; private const string DAY_NUMBER = "%DAY_NUMBER%"; private const string NUM_PLAYERS = "%NUM_PLAYERS%"; private const string JOIN_CODE = "%JOIN_CODE%"; private const string TIMESTAMP = "%TIMESTAMP%"; private const string TIMESINCE = "%TIMESINCE%"; private const string UNIX_TIMESTAMP = "%UNIX_TIMESTAMP%"; private static readonly Regex OpenCaretRegex = new Regex("<[\\w=]+>"); private static readonly Regex CloseCaretRegex = new Regex("</[\\w]+>"); private static string ReplaceVariables(string rawMessage, bool subtractOne = false) { return ReplaceDynamicVariables(rawMessage.Replace("%VAR1%", DiscordConnectorPlugin.StaticConfig.UserVariable).Replace("%VAR2%", DiscordConnectorPlugin.StaticConfig.UserVariable1).Replace("%VAR3%", DiscordConnectorPlugin.StaticConfig.UserVariable2) .Replace("%VAR4%", DiscordConnectorPlugin.StaticConfig.UserVariable3) .Replace("%VAR5%", DiscordConnectorPlugin.StaticConfig.UserVariable4) .Replace("%VAR6%", DiscordConnectorPlugin.StaticConfig.UserVariable5) .Replace("%VAR7%", DiscordConnectorPlugin.StaticConfig.UserVariable6) .Replace("%VAR8%", DiscordConnectorPlugin.StaticConfig.UserVariable7) .Replace("%VAR9%", DiscordConnectorPlugin.StaticConfig.UserVariable8) .Replace("%VAR10%", DiscordConnectorPlugin.StaticConfig.UserVariable9), subtractOne); } private static string ReplaceDynamicVariables(string rawMessage, bool subtractOne = false) { return ReplaceUnixTimestamp(ReplaceTimesince(ReplaceTimestamp(ReplaceJoinCode(ReplaceNumPlayers(ReplaceDayNumber(ReplaceWorldName(ReplacePublicIp(rawMessage))), subtractOne))))); } private static string ReplaceTimestamp(string rawMessage) { return rawMessage.Replace("%TIMESTAMP%", $"<t:{(int)DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1)).TotalSeconds}>"); } private static string ReplaceTimesince(string rawMessage) { return rawMessage.Replace("%TIMESINCE%", $"<t:{(int)DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1)).TotalSeconds}:R>"); } private static string ReplaceUnixTimestamp(string rawMessage) { return rawMessage.Replace("%UNIX_TIMESTAMP%", ((int)DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1)).TotalSeconds).ToString()); } private static string ReplaceJoinCode(string rawMessage) { return rawMessage.Replace("%JOIN_CODE%", ZPlayFabMatchmaking.JoinCode); } private static string ReplaceDayNumber(string rawMessage) { return rawMessage.Replace("%DAY_NUMBER%", ((Object)(object)EnvMan.instance != (Object)null) ? EnvMan.instance.GetCurrentDay().ToString() : "%DAY_NUMBER%"); } private static string ReplaceNumPlayers(string rawMessage, bool subtractOne = false) { if (subtractOne) { return rawMessage.Replace("%NUM_PLAYERS%", ((Object)(object)ZNet.instance != (Object)null) ? (ZNet.instance.GetNrOfPlayers() - 1).ToString() : "%NUM_PLAYERS%"); } return rawMessage.Replace("%NUM_PLAYERS%", ((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetNrOfPlayers().ToString() : "%NUM_PLAYERS%"); } private static string ReplacePublicIp(string rawMessage) { return rawMessage.Replace("%PUBLICIP%", DiscordConnectorPlugin.PublicIpAddress); } private static string ReplaceWorldName(string rawMessage) { return rawMessage.Replace("%WORLD_NAME%", ((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetWorldName() : "%WORLD_NAME%"); } public static string FormatServerMessage(string rawMessage) { return ReplaceVariables(rawMessage); } public static string FormatPlayerMessage(string rawMessage, string playerName, string playerId, bool subtractOne = false) { return ReplaceVariables(rawMessage, subtractOne).Replace("%PLAYER_STEAMID%", playerId).Replace("%PLAYER_ID%", playerId).Replace("%PLAYER_NAME%", playerName); } public static string FormatPlayerMessage(string rawMessage, string playerName, string playerId, Vector3 pos, bool subtractOne = false) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) return FormatPlayerMessage(rawMessage, playerName, playerId, subtractOne).Replace("%POS%", $"{pos}"); } public static string FormatPlayerMessage(string rawMessage, string playerName, string playerId, string shout, bool subtractOne = false) { return FormatPlayerMessage(rawMessage, playerName, playerId, subtractOne).Replace("%SHOUT%", shout); } public static string FormatPlayerMessage(string rawMessage, string playerName, string playerSteamId, string shout, Vector3 pos, bool subtractOne = false) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) return FormatPlayerMessage(rawMessage, playerName, playerSteamId, pos, subtractOne).Replace("%SHOUT%", shout); } public static string FormatEventMessage(string rawMessage, string eventStartMsg, string eventEndMsg) { return ReplaceVariables(rawMessage).Replace("%EVENT_START_MSG%", eventStartMsg).Replace("%EVENT_END_MSG%", eventEndMsg); } public static string FormatEventMessage(string rawMessage, string eventStartMsg, string eventEndMsg, Vector3 pos) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) return FormatEventMessage(rawMessage, eventStartMsg, eventEndMsg).Replace("%POS%", $"{pos}"); } public static string FormatEventStartMessage(string rawMessage, string eventStartMsg, string eventEndMsg) { return FormatEventMessage(rawMessage, eventStartMsg, eventEndMsg).Replace("%EVENT_MSG%", eventStartMsg); } public static string FormatEventEndMessage(string rawMessage, string eventStartMsg, string eventEndMsg) { return FormatEventMessage(rawMessage, eventStartMsg, eventEndMsg).Replace("%EVENT_MSG%", eventEndMsg); } public static string FormatEventStartMessage(string rawMessage, string eventStartMsg, string eventEndMsg, Vector3 pos) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) return FormatEventMessage(rawMessage, eventStartMsg, eventEndMsg, pos).Replace("%EVENT_MSG%", eventStartMsg); } public static string FormatEventEndMessage(string rawMessage, string eventStartMsg, string eventEndMsg, Vector3 pos) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) return FormatEventMessage(rawMessage, eventStartMsg, eventEndMsg, pos).Replace("%EVENT_MSG%", eventEndMsg); } public static string FormatLeaderBoardHeader(string rawMessage) { return ReplaceVariables(rawMessage); } public static string FormatLeaderBoardHeader(string rawMessage, int n) { return ReplaceVariables(rawMessage).Replace("%N%", n.ToString()); } public static string CleanCaretFormatting(string str) { string input = OpenCaretRegex.Replace(str, "", 1); return CloseCaretRegex.Replace(input, "", 1); } public static string FormatVector3AsPos(Vector3 vec3) { return DiscordConnectorPlugin.StaticConfig.PosVarFormat.Replace("%X%", vec3.x.ToString("F1")).Replace("%Y%", vec3.y.ToString("F1")).Replace("%Z%", vec3.z.ToString("F1")); } public static string FormatAppendedPos(Vector3 vec3) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) string newValue = FormatVector3AsPos(vec3); return DiscordConnectorPlugin.StaticConfig.AppendedPosFormat.Replace("%POS%", newValue); } public static EmbedBuilder CreateServerMessageEmbed(string rawMessage, Webhook.Event eventType) { string message = FormatServerMessage(rawMessage); string worldName = (((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetWorldName() : "Unknown World"); string serverName = DiscordConnectorPlugin.StaticConfig.ServerName; return EmbedTemplates.ServerLifecycle(eventType, message, worldName, serverName); } public static EmbedBuilder CreateDeathEmbed(ZNetPeer peer, string message, Webhook.Event eventType) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) string playerName = peer.m_playerName; string hostName = peer.m_socket.GetHostName(); Vector3 refPos = peer.m_refPos; string arg = (((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetWorldName() : "Unknown World"); string serverName = DiscordConnectorPlugin.StaticConfig.ServerName; EmbedBuilder embedBuilder = new EmbedBuilder().SetColorForEvent(eventType).SetDescription(message).SetTimestamp() .SetTitle("\ud83d\udc80 Player Death") .SetAuthor(serverName, null, DiscordConnectorPlugin.StaticConfig.EmbedAuthorIconUrl) .SetFooter($"World: {arg} • Today at {DateTime.Now:HH:mm}"); if (DiscordConnectorPlugin.StaticConfig.EmbedThumbnailEnabled) { embedBuilder.SetThumbnail(DiscordConnectorPlugin.StaticConfig.EmbedThumbnailUrl); } if (DiscordConnectorPlugin.StaticConfig.PlayerDeathPosEnabled) { embedBuilder.AddField("Death Location", FormatVector3AsPos(refPos), inline: true); } if (DiscordConnectorPlugin.StaticConfig.ShowPlayerIds) { embedBuilder.AddField("Player ID", hostName, inline: true); } embedBuilder.AddField("Player", playerName, inline: true); return embedBuilder; } public static EmbedBuilder CreateShoutEmbed(ZNetPeer peer, string text, Webhook.Event eventType) { string playerName = peer.m_playerName; peer.m_socket.GetHostName(); string worldName = (((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetWorldName() : "Unknown World"); string message = (DiscordConnectorPlugin.StaticConfig.ChatShoutAllCaps ? text.ToUpper() : text); return EmbedTemplates.ChatMessage(eventType, message, playerName, null, worldName); } public static EmbedBuilder CreatePlayerMessageEmbed(string rawMessage, Webhook.Event eventType, string playerName, string playerId, bool subtractOne = false) { string message = FormatPlayerMessage(rawMessage, playerName, playerId, subtractOne); string worldName = (((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetWorldName() : "Unknown World"); return EmbedTemplates.PlayerEvent(eventType, message, playerName, null, worldName); } public static EmbedBuilder CreatePlayerMessageEmbed(string rawMessage, Webhook.Event eventType, string playerName, string playerId, Vector3 position, bool subtractOne = false) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) string message = FormatPlayerMessage(rawMessage, playerName, playerId, position, subtractOne); string worldName = (((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetWorldName() : "Unknown World"); return EmbedTemplates.PlayerEvent(eventType, message, playerName, position, worldName); } public static EmbedBuilder CreateShoutMessageEmbed(string rawMessage, Webhook.Event eventType, string playerName, string playerId, string shout, bool subtractOne = false) { FormatPlayerMessage(rawMessage, playerName, playerId, shout, subtractOne); string worldName = (((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetWorldName() : "Unknown World"); return EmbedTemplates.ChatMessage(eventType, shout, playerName, null, worldName); } public static EmbedBuilder C