Decompiled source of DiscordConnector v3.1.0
DiscordConnector.dll
Decompiled 3 weeks 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.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.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8.1", FrameworkDisplayName = ".NET Framework 4.8.1")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("3.1.0.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; } byte[] bytes = Encoding.UTF8.GetBytes(serializedJson); if (DiscordConnectorPlugin.StaticConfig.PrimaryWebhook.HasEvent(ev)) { DiscordConnectorPlugin.StaticLogger.LogDebug($"Sending {ev} message to Primary Webhook"); DispatchRequest(DiscordConnectorPlugin.StaticConfig.PrimaryWebhook, bytes); } if (DiscordConnectorPlugin.StaticConfig.SecondaryWebhook.HasEvent(ev)) { DiscordConnectorPlugin.StaticLogger.LogDebug($"Sending {ev} message to Secondary Webhook"); DispatchRequest(DiscordConnectorPlugin.StaticConfig.SecondaryWebhook, bytes); } foreach (WebhookEntry extraWebhook in DiscordConnectorPlugin.StaticConfig.ExtraWebhooks) { if (extraWebhook.HasEvent(ev)) { DiscordConnectorPlugin.StaticLogger.LogDebug($"Sending {ev} message to Extra Webhook: {extraWebhook.Url}"); DispatchRequest(extraWebhook, bytes); } } } public static void SendSerializedJson(WebhookEntry webhook, string serializedJson) { DiscordConnectorPlugin.StaticLogger.LogDebug("Trying webhook with payload: " + serializedJson); if (!string.IsNullOrEmpty(webhook.Url) && !string.IsNullOrEmpty(serializedJson)) { byte[] bytes = Encoding.UTF8.GetBytes(serializedJson); DispatchRequest(webhook, bytes); } } private static void DispatchRequest(WebhookEntry webhook, byte[] byteArray) { byte[] byteArray2 = byteArray; 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 {byteArray2.Length} bytes to Discord"); WebRequest request = WebRequest.Create(webhook.Url); request.Method = "POST"; request.ContentType = "application/json"; request.ContentLength = byteArray2.Length; Task.Run(delegate { try { using (Stream stream = request.GetRequestStream()) { stream.Write(byteArray2, 0, byteArray2.Length); } bool flag = true; WebResponse response; try { response = request.GetResponse(); if (DiscordConnectorPlugin.StaticConfig.DebugHttpRequestResponse) { if (response is HttpWebResponse httpWebResponse) { if (httpWebResponse.StatusCode == HttpStatusCode.NoContent) { flag = false; } DiscordConnectorPlugin.StaticLogger.LogDebug($"DispatchRequest.{requestId}: Response Code: {httpWebResponse.StatusCode}"); } else { DiscordConnectorPlugin.StaticLogger.LogDebug("DispatchRequest." + requestId + ": Response was not an HttpWebResponse"); } } } catch (WebException arg) { DiscordConnectorPlugin.StaticLogger.LogError($"DispatchRequest.{requestId}: Error getting web response: {arg}"); return; } if (flag) { using Stream stream2 = response.GetResponseStream(); if (stream2 == null) { DiscordConnectorPlugin.StaticLogger.LogError("DispatchRequest." + requestId + ": Response stream is null"); return; } using StreamReader streamReader = new StreamReader(stream2); string text = streamReader.ReadToEnd(); if (DiscordConnectorPlugin.StaticConfig.DebugHttpRequestResponse) { if (text.Length > 0) { DiscordConnectorPlugin.StaticLogger.LogDebug("DispatchRequest." + requestId + ": Response from server: " + text); } else { DiscordConnectorPlugin.StaticLogger.LogDebug("DispatchRequest." + requestId + ": Empty response from server (normal)"); } } } response.Close(); } catch (Exception arg2) { DiscordConnectorPlugin.StaticLogger.LogWarning($"Error dispatching webhook: {arg2}"); } }).ConfigureAwait(continueOnCapturedContext: false); } 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.GetWor