Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of SimpleTwitchChat v0.0.1
SimpleTwitchChat.dll
Decompiled 5 hours agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using TwitchChatAPI; using TwitchChatAPI.Objects; using Unity.Netcode; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("SimpleTwitchChat")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("SimpleTwitchChat")] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("40bf9cbf-1c57-4f43-92af-6600335dd3ae")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyVersion("1.0.0.0")] namespace SimpleTwitchChat; internal class ConfigHandler : MonoBehaviour { public enum PrefixColorModes { BothTwitchPurple, BothTwitchUsernameColor, Hybrid, CustomColor } public enum ChatColorModes { TwitchPurple, TwitchUsernameColor, CustomColor } public static ConfigEntry<string> ChatPrefix; public static ConfigEntry<PrefixColorModes> PrefixColorMode; public static ConfigEntry<string> CustomPrefixColor; public static ConfigEntry<ChatColorModes> ChatColorMode; public static ConfigEntry<string> CustomChatColor; public static ConfigEntry<bool> shouldHighlightsAlert; public static ConfigEntry<bool> shouldAlertsSkipChat; public static ConfigEntry<float> alertWaitTime; public static ConfigEntry<bool> hideClankers; public static ConfigEntry<bool> hideBroadcaster; public static ConfigEntry<bool> hideMods; public static ConfigEntry<string> blacklistedUsers; public static ConfigEntry<bool> blacklistIsWhitelist; public static ConfigEntry<bool> subOnly; public static ConfigEntry<bool> networkHostsEntireChat; public static ConfigEntry<bool> printDebugInfo; public static ConfigEntry<bool> printRedeemInfo; public static ConfigEntry<bool> forceGiftRedeem; public static ConfigEntry<string> forceGiftRedeemID; public static ConfigEntry<bool> forceDiceRedeem; public static ConfigEntry<string> forceDiceRedeemID; public static ConfigEntry<bool> forceSuitChangeRedeem; public static ConfigEntry<string> forceSuitChangeRedeemID; public static ConfigEntry<bool> forceWeatherChangeRedeem; public static ConfigEntry<string> forceWeatherChangeRedeemID; public static ConfigEntry<bool> weatherChangeHard; public static ConfigEntry<bool> whiteboardReplaceRedeem; public static ConfigEntry<string> whiteboardReplaceRedeemID; public static ConfigEntry<bool> TTSRedeem; public static ConfigEntry<string> TTSRedeemID; public static ConfigEntry<float> chatDelay; public static void Init(ConfigFile config) { printDebugInfo = config.Bind<bool>("Debugging", "Print Debug Info", false, "If true, any chat messages that come into the connected chat will have all their metadata printed into the log."); printRedeemInfo = config.Bind<bool>("Debugging", "Print Redeem Info", false, "If true, any redeems used will print their IDs into the log, useful for setting up the Redeem part of this config."); ChatPrefix = config.Bind<string>("Chat Formatting", "Chat Prefix", "[TTV]", "What to prefix any chat messages coming from Twitch with. Leave blank for nothing."); PrefixColorMode = config.Bind<PrefixColorModes>("Chat Formatting", "Prefix Color Mode", PrefixColorModes.Hybrid, "What mode to color the Prefix + Username of Twitch chat messages. BothTwitchPurple = Both will be Purple. BothUsernameColor = Both will match their Twitch Username color. Hybrid = The Prefix will Twitch Purple, whilst the Username will be their Twitch Username color. CustomColor = Both will be a custom color you set below."); CustomPrefixColor = config.Bind<string>("Chat Formatting", "Custom Prefix Color", "#FFFFFF", "If 'Prefix Color Mode' is set to 'AllCustomColor', this color will be used instead for the Prefix. Needs to be the Hex color code."); ChatColorMode = config.Bind<ChatColorModes>("Chat Formatting", "Chat Color Mode", ChatColorModes.CustomColor, "Mode to choose the color for the actual message from the Twitch User. Default is Custom Color which is set to white."); CustomChatColor = config.Bind<string>("Chat Formatting", "Custom Chat Color", "#FFFFFF", "If 'Chat Color Mode' is set to 'CustomColor', this will be used for the message's color. Default is white."); shouldHighlightsAlert = config.Bind<bool>("Highlights", "Should Highlights Alert", true, "If true, when a redeem is used to highlight a Twitch message, it will popup as a yellow 'Alert' like message at the bottom of the screen."); shouldAlertsSkipChat = config.Bind<bool>("Highlights", "Should Alerts Skip Chat", false, "If 'Should Highlights Alert' is true, and an Alert comes through, this being enabled prevents the message appearing in the normal chat as well. Disable if you want highlighted messages to appear both as an Alert AND in the text chat."); alertWaitTime = config.Bind<float>("Highlights", "Alert Wait Time", 9f, "How long the Alert message will stay on screen for before disappearing."); hideClankers = config.Bind<bool>("Filtering", "Hide Clankers", true, "If true, any messages from users with a Bot Badge will not be passed in game. Isn't smart enough to catch user-bots though."); hideBroadcaster = config.Bind<bool>("Filtering", "Hide Broadcaster", false, "If true, any messages from the Broadcaster themself will not be passed in game."); hideMods = config.Bind<bool>("Filtering", "Hide Mods", false, "If true, any messages from moderators will not be passed in game."); subOnly = config.Bind<bool>("Filtering", "Sub Only", false, "If true, any messages from users who are not subscribed to the channel will not be passed in game."); blacklistedUsers = config.Bind<string>("Filtering", "Blacklisted User IDs", "", "A comma separated list of Twitch IDs that you want to block messages from coming through from. Example: '469784489,469334489,555584489'. This config takes priority over all other filters. You can use 'StreamWeasels' web tool to get User IDs from Usernames."); blacklistIsWhitelist = config.Bind<bool>("Filtering", "Blacklist is Whitelist", false, "If true, the above list of Blacklisted User IDs will be treated as a Whitelist instead, meaning only users in that list will be allowed to have their messages come through. This config still takes priority over all other filters, meaning if you Whitelist a non-sub in sub-only mode, their message will still come through."); networkHostsEntireChat = config.Bind<bool>("Networking", "(Unused) Network Chat to Whole Lobby", false, "If true, all Twitch chat messages from the Host's Twitch will be sent to all players in the game (This also means ONLY the host's Twitch stream will work. Any clients playing who are also streaming will not be able to see their chat in game as it is overwritten). If false, only the host will see their own Twitch chat messages, and clients will be able to see their own seperate Twitch chat messages. "); chatDelay = config.Bind<float>("Networking", "(Unused) Message Cooldown", 0f, "How much of a cooldown to put between chat messages, useful for very busy Twitch channels were lots of messages can come through at once, to queue them up."); } } internal class RedeemHandler : MonoBehaviour { } [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInPlugin("ZetaArcade.SimpleTwitchChat", "SimpleTwitchChat", "0.0.1")] public class SimpleTwitchChatBase : BaseUnityPlugin { private const string modGUID = "ZetaArcade.SimpleTwitchChat"; private const string modName = "SimpleTwitchChat"; private const string modVersion = "0.0.1"; private Harmony harmony = new Harmony("ZetaArcade.SimpleTwitchChat"); public static ManualLogSource Logger; public static SimpleTwitchChatBase Instance; private void Awake() { if ((Object)(object)Instance == (Object)null) { Instance = this; } Logger = ((BaseUnityPlugin)this).Logger; Logger.LogDebug((object)"Config begin initialize..."); ConfigHandler.Init(((BaseUnityPlugin)this).Config); Logger.LogDebug((object)"Config Initialised!"); Logger.LogDebug((object)"Twitch Handler begin initialize..."); TwitchHandler.Initialize(); Logger.LogDebug((object)"Twitch Handler Initialised!"); Logger.LogInfo((object)"Plugin is loaded!"); harmony.PatchAll(typeof(SimpleTwitchChatBase)); } } internal class TwitchHandler : MonoBehaviour { public static List<string> userBlacklist; private static readonly WaitUntil WaitForAnimation = new WaitUntil((Func<bool>)delegate { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) AnimatorStateInfo currentAnimatorStateInfo = HUDManager.Instance.tipsPanelAnimator.GetCurrentAnimatorStateInfo(0); return ((AnimatorStateInfo)(ref currentAnimatorStateInfo)).normalizedTime >= 1f; }); public static void Initialize() { API.OnMessage += HandleMessage; SimpleTwitchChatBase.Logger.LogDebug((object)"TwitchHandler initializing..."); string[] source = ConfigHandler.blacklistedUsers.Value.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries); userBlacklist = source.ToList(); Application.quitting += delegate { API.OnMessage -= HandleMessage; }; } public static void Send(HUDManager hud, string msg, string sender) { MethodInfo method = typeof(HUDManager).GetMethod("AddChatMessage", BindingFlags.Instance | BindingFlags.NonPublic); method.Invoke(hud, new object[4] { msg, sender, -1, false }); } internal static IEnumerator ShowMessageAfterDelay(string title, string text, float delay = 0f, bool isWarning = false) { if (delay > 0f) { yield return (object)new WaitForSeconds(delay); } yield return WaitForAnimation; HUDManager.Instance.DisplayTip(title, text, isWarning, false, "LC_Tip1"); } private void OnEnable() { API.OnMessage += HandleMessage; } private void OnDisable() { API.OnMessage -= HandleMessage; } public static List<DialogueSegment> GetDialogueSegment(string newSpeakerText, string newBodyText, float newWaitTime) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown DialogueSegment item = new DialogueSegment { speakerText = newSpeakerText, bodyText = newBodyText, waitTime = newWaitTime }; List<DialogueSegment> list = new List<DialogueSegment>(); list.Add(item); return list; } private static void HandleMessage(TwitchMessage message) { //IL_00af: 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) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Unknown result type (might be due to invalid IL or missing references) //IL_0210: Unknown result type (might be due to invalid IL or missing references) //IL_0215: Unknown result type (might be due to invalid IL or missing references) //IL_022b: Unknown result type (might be due to invalid IL or missing references) //IL_0230: Unknown result type (might be due to invalid IL or missing references) //IL_037d: Unknown result type (might be due to invalid IL or missing references) //IL_0382: Unknown result type (might be due to invalid IL or missing references) //IL_03c3: Unknown result type (might be due to invalid IL or missing references) //IL_03c8: Unknown result type (might be due to invalid IL or missing references) //IL_0407: Unknown result type (might be due to invalid IL or missing references) //IL_040c: Unknown result type (might be due to invalid IL or missing references) //IL_0446: Unknown result type (might be due to invalid IL or missing references) //IL_044b: Unknown result type (might be due to invalid IL or missing references) //IL_04ac: Unknown result type (might be due to invalid IL or missing references) //IL_04b1: Unknown result type (might be due to invalid IL or missing references) //IL_04fb: Unknown result type (might be due to invalid IL or missing references) //IL_0500: Unknown result type (might be due to invalid IL or missing references) //IL_05dc: Unknown result type (might be due to invalid IL or missing references) //IL_05e1: Unknown result type (might be due to invalid IL or missing references) //IL_0637: Unknown result type (might be due to invalid IL or missing references) //IL_063c: Unknown result type (might be due to invalid IL or missing references) //IL_0649: Unknown result type (might be due to invalid IL or missing references) //IL_064e: Unknown result type (might be due to invalid IL or missing references) //IL_0664: Unknown result type (might be due to invalid IL or missing references) //IL_0669: Unknown result type (might be due to invalid IL or missing references) //IL_06d7: Unknown result type (might be due to invalid IL or missing references) //IL_06dc: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)HUDManager.Instance != (Object)null)) { return; } bool flag = false; string value = ""; if (ConfigHandler.printRedeemInfo.Value && ((TwitchMessage)(ref message)).Tags.ContainsKey("custom-reward-id") && ((TwitchMessage)(ref message)).Tags.TryGetValue("custom-reward-id", out value)) { SimpleTwitchChatBase.Logger.LogInfo((object)("Redeem ID for: '" + ((TwitchMessage)(ref message)).Message + "' is: " + value)); } TwitchUser user; if (ConfigHandler.printDebugInfo.Value) { SimpleTwitchChatBase.Logger.LogInfo((object)"------Printing Full Message Debug Info Below-------"); ManualLogSource logger = SimpleTwitchChatBase.Logger; user = ((TwitchMessage)(ref message)).User; logger.LogInfo((object)("[" + ((TwitchUser)(ref user)).DisplayName + "]: " + ((TwitchMessage)(ref message)).Message)); SimpleTwitchChatBase.Logger.LogInfo((object)("Channel: " + ((TwitchMessage)(ref message)).Channel)); ManualLogSource logger2 = SimpleTwitchChatBase.Logger; user = ((TwitchMessage)(ref message)).User; logger2.LogInfo((object)("Display Name: " + ((TwitchUser)(ref user)).DisplayName)); ManualLogSource logger3 = SimpleTwitchChatBase.Logger; user = ((TwitchMessage)(ref message)).User; logger3.LogInfo((object)("Username: " + ((TwitchUser)(ref user)).Username)); ManualLogSource logger4 = SimpleTwitchChatBase.Logger; user = ((TwitchMessage)(ref message)).User; logger4.LogInfo((object)("User Color: " + ((TwitchUser)(ref user)).Color)); ManualLogSource logger5 = SimpleTwitchChatBase.Logger; user = ((TwitchMessage)(ref message)).User; logger5.LogInfo((object)("User ID: " + ((TwitchUser)(ref user)).UserId)); SimpleTwitchChatBase.Logger.LogInfo((object)"Tags below: "); foreach (KeyValuePair<string, string> tag in ((TwitchMessage)(ref message)).Tags) { SimpleTwitchChatBase.Logger.LogInfo((object)(tag.Key + " = " + tag.Value)); } } if (flag) { HUDManager instance = HUDManager.Instance; string[] obj = new string[7] { "<color=#A970FF>[TTV]</color> <color=", null, null, null, null, null, null }; user = ((TwitchMessage)(ref message)).User; obj[1] = ((TwitchUser)(ref user)).Color; obj[2] = ">["; user = ((TwitchMessage)(ref message)).User; obj[3] = ((TwitchUser)(ref user)).DisplayName; obj[4] = "]</color>: <color=#FFFFFF>"; obj[5] = ((TwitchMessage)(ref message)).Message; obj[6] = "</color>"; Send(instance, string.Concat(obj), ""); HUDManager.Instance.PingHUDElement(HUDManager.Instance.Chat, 4f, 1f, 0.2f); return; } NetworkManager networkManager = ((NetworkBehaviour)StartOfRound.Instance.localPlayerController).NetworkManager; bool flag2 = false; bool flag3 = false; bool flag4 = false; if (((TwitchMessage)(ref message)).Tags.ContainsKey("badges") && ((TwitchMessage)(ref message)).Tags["badges"].Contains("bot-badge")) { flag2 = true; } if (((TwitchMessage)(ref message)).Tags.ContainsKey("msg-id") && ((TwitchMessage)(ref message)).Tags["msg-id"] == "highlighted-message") { flag3 = true; } if (((TwitchMessage)(ref message)).Tags.ContainsKey("custom-reward-id")) { flag4 = true; } if (!networkManager.IsServer) { SimpleTwitchChatBase.Logger.LogDebug((object)"Skipping message because this player is not the Host"); return; } if (!ConfigHandler.blacklistIsWhitelist.Value) { List<string> source = userBlacklist; user = ((TwitchMessage)(ref message)).User; if (Enumerable.Contains(source, ((TwitchUser)(ref user)).UserId)) { SimpleTwitchChatBase.Logger.LogDebug((object)"Skipping message because this sender is Blacklisted"); return; } } if (ConfigHandler.blacklistIsWhitelist.Value) { List<string> source2 = userBlacklist; user = ((TwitchMessage)(ref message)).User; if (!Enumerable.Contains(source2, ((TwitchUser)(ref user)).UserId)) { SimpleTwitchChatBase.Logger.LogDebug((object)"Skipping message because this sender is not in the Whitelist"); return; } } if (ConfigHandler.subOnly.Value) { user = ((TwitchMessage)(ref message)).User; if (!((TwitchUser)(ref user)).IsSubscriber) { SimpleTwitchChatBase.Logger.LogDebug((object)"Skipping message because this sender is not a subscriber"); return; } } if (ConfigHandler.hideBroadcaster.Value) { user = ((TwitchMessage)(ref message)).User; if (((TwitchUser)(ref user)).IsBroadcaster) { SimpleTwitchChatBase.Logger.LogDebug((object)"Skipping message because this sender is the Broadcaster"); return; } } if (ConfigHandler.hideClankers.Value && flag2) { SimpleTwitchChatBase.Logger.LogDebug((object)"Skipping message because this sender is a CLANKER"); return; } if (ConfigHandler.hideMods.Value) { user = ((TwitchMessage)(ref message)).User; if (((TwitchUser)(ref user)).IsModerator) { SimpleTwitchChatBase.Logger.LogDebug((object)"Skipping message because this sender is a moderator"); return; } } if (ConfigHandler.shouldHighlightsAlert.Value && flag3) { HUDManager instance2 = HUDManager.Instance; user = ((TwitchMessage)(ref message)).User; instance2.ReadDialogue(GetDialogueSegment("Message from: " + ((TwitchUser)(ref user)).DisplayName, ((TwitchMessage)(ref message)).Message ?? "", ConfigHandler.alertWaitTime.Value).ToArray()); } if (ConfigHandler.shouldHighlightsAlert.Value && ConfigHandler.shouldAlertsSkipChat.Value && flag3) { SimpleTwitchChatBase.Logger.LogDebug((object)"Skipping message because this message is a highlight"); HUDManager.Instance.PingHUDElement(HUDManager.Instance.Chat, 4f, 1f, 0.2f); return; } string text = "#FFFFFF"; string text2 = "#FFFFFF"; string text3 = "#FFFFFF"; switch (ConfigHandler.ChatColorMode.Value) { case ConfigHandler.ChatColorModes.TwitchPurple: text2 = "#A970FF"; break; case ConfigHandler.ChatColorModes.TwitchUsernameColor: user = ((TwitchMessage)(ref message)).User; text2 = ((TwitchUser)(ref user)).Color; break; case ConfigHandler.ChatColorModes.CustomColor: text2 = ConfigHandler.CustomChatColor.Value; break; } switch (ConfigHandler.PrefixColorMode.Value) { case ConfigHandler.PrefixColorModes.BothTwitchPurple: text = "#A970FF"; text3 = "#A970FF"; break; case ConfigHandler.PrefixColorModes.BothTwitchUsernameColor: user = ((TwitchMessage)(ref message)).User; text = ((TwitchUser)(ref user)).Color; user = ((TwitchMessage)(ref message)).User; text3 = ((TwitchUser)(ref user)).Color; break; case ConfigHandler.PrefixColorModes.Hybrid: text = "#A970FF"; user = ((TwitchMessage)(ref message)).User; text3 = ((TwitchUser)(ref user)).Color; break; case ConfigHandler.PrefixColorModes.CustomColor: text = ConfigHandler.CustomPrefixColor.Value; text3 = ConfigHandler.CustomPrefixColor.Value; break; } HUDManager instance3 = HUDManager.Instance; string[] obj2 = new string[13] { "<color=", text, ">", ConfigHandler.ChatPrefix.Value, "</color> <color=", text3, ">[", null, null, null, null, null, null }; user = ((TwitchMessage)(ref message)).User; obj2[7] = ((TwitchUser)(ref user)).DisplayName; obj2[8] = "]</color>: <color="; obj2[9] = text2; obj2[10] = ">"; obj2[11] = ((TwitchMessage)(ref message)).Message; obj2[12] = "</color>"; Send(instance3, string.Concat(obj2), ""); HUDManager.Instance.PingHUDElement(HUDManager.Instance.Chat, 4f, 1f, 0.2f); bool flag5 = false; if (flag4 && flag5) { bool flag6 = false; string text4 = ""; if (value != "" && value == ConfigHandler.whiteboardReplaceRedeemID.Value && ConfigHandler.whiteboardReplaceRedeem.Value) { text4 += "Change Whiteboard..."; } if (value != "" && value == ConfigHandler.forceDiceRedeemID.Value && ConfigHandler.forceDiceRedeem.Value) { flag6 = true; text4 += "Roll Dice..."; } if (value != "" && value == ConfigHandler.forceGiftRedeemID.Value && ConfigHandler.forceGiftRedeem.Value) { flag6 = true; text4 += "Open Gift..."; } if (value != "" && value == ConfigHandler.forceSuitChangeRedeemID.Value && ConfigHandler.forceSuitChangeRedeem.Value) { text4 += "Suit Change..."; } if (value != "" && value == ConfigHandler.TTSRedeemID.Value && ConfigHandler.TTSRedeem.Value) { flag6 = true; text4 += "TTS..."; } if (value != "" && value == ConfigHandler.forceWeatherChangeRedeemID.Value && ConfigHandler.forceWeatherChangeRedeem.Value) { flag6 = true; text4 += "Weather Change..."; } if (!flag6 && !(text4 != "")) { } } } }