Decompiled source of Chat Integration v0.1.0

com.atomic.sbgchatintegration.dll

Decompiled 2 days ago
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Net.Sockets;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Lexone.UnityTwitchChat;
using Microsoft.CodeAnalysis;
using Mirror;
using SBG_Chat_Integration.Actions;
using SBG_Chat_Integration.UI;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("GameAssembly")]
[assembly: IgnoresAccessChecksTo("SharedAssembly")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("com.atomic.sbgchatintegration")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.1.0.0")]
[assembly: AssemblyInformationalVersion("0.1.0")]
[assembly: AssemblyProduct("com.atomic.sbgchatintegration")]
[assembly: AssemblyTitle("SBG_Chat_Integration")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.1.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
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 BepInEx
{
	[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
	[Conditional("CodeGeneration")]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class BepInAutoPluginAttribute : Attribute
	{
		public BepInAutoPluginAttribute(string? id = null, string? name = null, string? version = null)
		{
		}
	}
}
namespace BepInEx.Preloader.Core.Patching
{
	[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
	[Conditional("CodeGeneration")]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class PatcherAutoPluginAttribute : Attribute
	{
		public PatcherAutoPluginAttribute(string? id = null, string? name = null, string? version = null)
		{
		}
	}
}
namespace Microsoft.CodeAnalysis
{
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace Lexone.UnityTwitchChat
{
	[Serializable]
	public class Chatter
	{
		public string login;

		public string channel;

		public string message;

		public IRCTags tags;

		public Chatter(string login, string channel, string message, IRCTags tags)
		{
			this.login = login;
			this.channel = channel;
			this.message = message;
			this.tags = tags;
		}

		public Color GetNameColor(bool normalize = true)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			Color val = default(Color);
			if (ColorUtility.TryParseHtmlString(tags.colorHex, ref val))
			{
				if (normalize)
				{
					return ChatColors.NormalizeColor(val);
				}
				return val;
			}
			return Color.white;
		}

		public bool IsDisplayNameFontSafe()
		{
			return ParseHelper.CheckNameRegex(tags.displayName);
		}

		public bool ContainsEmote(string emoteId)
		{
			return tags.ContainsEmote(emoteId);
		}

		public bool HasBadge(string badgeName)
		{
			return tags.HasBadge(badgeName);
		}
	}
	public static class Extensions
	{
		public static void WriteLine(this NetworkStream stream, string output, bool showDebug = false)
		{
			if (showDebug)
			{
				Debug.Log((object)(Tags.write + " " + output));
			}
			byte[] bytes = Encoding.UTF8.GetBytes(output);
			stream.Write(bytes, 0, bytes.Length);
			stream.WriteByte(13);
			stream.WriteByte(10);
			stream.Flush();
		}

		public static string GetDescription(this IRCReply alert)
		{
			return alert switch
			{
				IRCReply.CONNECTED_TO_SERVER => "Connected to IRC", 
				IRCReply.PONG_RECEIVED => "Pong!", 
				IRCReply.JOINED_CHANNEL => "Joined channel", 
				IRCReply.MISSING_LOGIN_INFO => "Missing login information (OAuth or username)", 
				IRCReply.BAD_LOGIN => "Login failed", 
				IRCReply.CONNECTION_INTERRUPTED => "Connection to IRC interrupted", 
				IRCReply.NO_CONNECTION => "Connection to IRC failed", 
				_ => "Unknown alert", 
			};
		}
	}
	[AddComponentMenu("Unity Twitch Chat/Twitch IRC")]
	public class IRC : MonoBehaviour
	{
		[CompilerGenerated]
		private sealed class <<Connect>g__StartConnection|40_0>d : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public IRC <>4__this;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <<Connect>g__StartConnection|40_0>d(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
				//IL_00d6: Expected O, but got Unknown
				int num = <>1__state;
				IRC iRC = <>4__this;
				switch (num)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					if (iRC.connection != null)
					{
						<>2__current = ((MonoBehaviour)iRC).StartCoroutine(iRC.NonBlockingDisconnect());
						<>1__state = 1;
						return true;
					}
					goto IL_0053;
				case 1:
					<>1__state = -1;
					goto IL_0053;
				case 2:
					{
						<>1__state = -1;
						break;
					}
					IL_0053:
					iRC.connection = new TwitchConnection(iRC);
					if (iRC.connection.tcpClient == null || !iRC.connection.tcpClient.Connected)
					{
						iRC.alertQueue.Enqueue(IRCReply.NO_CONNECTION);
						return false;
					}
					if (iRC.connectionFailCount >= 2)
					{
						int num2 = 1 << iRC.connectionFailCount - 2;
						if (iRC.showIRCDebug)
						{
							Debug.Log((object)$"{Tags.alert} Reconnecting in {num2} seconds");
						}
						<>2__current = (object)new WaitForSecondsRealtime((float)num2);
						<>1__state = 2;
						return true;
					}
					break;
				}
				iRC.connection.Begin();
				return false;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[CompilerGenerated]
		private sealed class <NonBlockingDisconnect>d__42 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public IRC <>4__this;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <NonBlockingDisconnect>d__42(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				int num = <>1__state;
				IRC iRC = <>4__this;
				switch (num)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>2__current = ((MonoBehaviour)iRC).StartCoroutine(iRC.connection.End());
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					iRC.connection = null;
					if (iRC.showIRCDebug)
					{
						Debug.Log((object)(Tags.alert + " Disconnected from Twitch IRC"));
					}
					return false;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[Header("Twitch IRC address and port")]
		[SerializeField]
		public string address = "irc.chat.twitch.tv";

		[SerializeField]
		public int port = 6667;

		[Header("Twitch IRC connection")]
		[Tooltip("If true, the client will connect to Twitch IRC anonymously (OAuth and username will be ignored)\n\nNote that you can't send chat messages when using anonymous login.")]
		[SerializeField]
		private bool useAnonymousLogin;

		[Tooltip("The OAuth token which will be used to authenticate with Twitch.\n\nGenerate one at: https://twitchapps.com/tmi/")]
		[SerializeField]
		public string oauth = "";

		[Tooltip("The Twitch username which will be used to authenticate with Twitch IRC.\n\n(this is the login name, not display name)")]
		[SerializeField]
		public string username = "";

		[Tooltip("The Twitch channel name which the client will join.")]
		[SerializeField]
		public string channel = "";

		[Header("General settings")]
		[Tooltip("If true, the client will connect to Twitch IRC on Start.")]
		[SerializeField]
		private bool connectIRCOnStart = true;

		[Tooltip("If true, the client will automatically join the given channel upon a successful connection.")]
		[SerializeField]
		public bool joinChannelOnStart = true;

		[Tooltip("If true, IRC will be set to DontDestroyOnLoad and any duplicate instances will be removed.")]
		[SerializeField]
		public bool dontDestroyOnLoad = true;

		[Tooltip("If true, every IRC message sent and received will be logged to the console.")]
		[SerializeField]
		public bool showIRCDebug = true;

		[Tooltip("If true, the thread start and stop will be logged to the console.")]
		[SerializeField]
		public bool showThreadDebug = true;

		[Tooltip("If true, chatters who haven't set their name color on Twitch will be assigned a random color, instead of white.")]
		[SerializeField]
		public bool useRandomColorForUndefined;

		[Header("Chat read settings (read thread)")]
		[Tooltip("The number of milliseconds between each time the read thread checks for new messages.")]
		[SerializeField]
		public int readInterval = 50;

		[Tooltip("The capacity of the read buffer. Smaller values consume less memory but require more cycles to retrieve data (CPU usage)")]
		[SerializeField]
		public ReadBufferSize readBufferSize = ReadBufferSize._256;

		[Header("Chat write settings (write thread)")]
		[Tooltip("The number of milliseconds between each time the write thread checks its queues.")]
		public int writeInterval = 50;

		private static readonly int maxDataPerFrame = 100;

		private int connectionFailCount;

		private TwitchConnection connection;

		internal readonly ConcurrentQueue<IRCReply> alertQueue = new ConcurrentQueue<IRCReply>();

		internal readonly ConcurrentQueue<Chatter> chatterQueue = new ConcurrentQueue<Chatter>();

		public static IRC Instance { get; private set; }

		public IRCTags ClientUserTags => connection?.ClientUserTags;

		public event Action<Chatter> OnChatMessage;

		public event Action<IRCReply> OnConnectionAlert;

		[ContextMenu("Ping")]
		public void Ping()
		{
			connection?.Ping();
		}

		private void Awake()
		{
			if (Object.op_Implicit((Object)(object)Instance))
			{
				if (dontDestroyOnLoad)
				{
					((Component)this).gameObject.SetActive(false);
					Object.Destroy((Object)(object)((Component)this).gameObject);
				}
			}
			else
			{
				Instance = this;
				if (dontDestroyOnLoad)
				{
					Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject);
				}
			}
		}

		private void Start()
		{
			if (connectIRCOnStart)
			{
				Connect();
			}
		}

		private void Update()
		{
			HandlePendingInformation();
		}

		private void OnDestroy()
		{
			if (dontDestroyOnLoad && (Object)(object)Instance == (Object)(object)this)
			{
				Instance = null;
			}
			BlockingDisconnect();
		}

		private void OnDisable()
		{
			BlockingDisconnect();
		}

		private void HandlePendingInformation()
		{
			int num = 0;
			while (!alertQueue.IsEmpty && num < maxDataPerFrame)
			{
				if (alertQueue.TryDequeue(out var result))
				{
					HandleConnectionAlert(result);
					num++;
				}
			}
			while (!chatterQueue.IsEmpty && num < maxDataPerFrame)
			{
				if (chatterQueue.TryDequeue(out Chatter result2))
				{
					this.OnChatMessage?.Invoke(result2);
					num++;
				}
			}
		}

		private void HandleConnectionAlert(IRCReply alert)
		{
			if (showIRCDebug)
			{
				Debug.Log((object)(Tags.alert + " " + alert.GetDescription()));
			}
			switch (alert)
			{
			case IRCReply.MISSING_LOGIN_INFO:
			case IRCReply.BAD_LOGIN:
			case IRCReply.NO_CONNECTION:
				connectionFailCount = 0;
				Disconnect();
				break;
			case IRCReply.CONNECTION_INTERRUPTED:
				connectionFailCount++;
				Connect();
				break;
			case IRCReply.JOINED_CHANNEL:
				connectionFailCount = 0;
				break;
			}
			this.OnConnectionAlert?.Invoke(alert);
		}

		[ContextMenu("Connect")]
		public void Connect()
		{
			if (useAnonymousLogin)
			{
				username = "justinfan" + Random.Range(1000, 9999);
				oauth = "";
			}
			else
			{
				if (oauth.Length <= 0 || username.Length <= 0)
				{
					alertQueue.Enqueue(IRCReply.MISSING_LOGIN_INFO);
					return;
				}
				if (oauth.StartsWith("oauth:"))
				{
					oauth = oauth.Substring(6);
				}
			}
			((MonoBehaviour)this).StartCoroutine(StartConnection());
			[IteratorStateMachine(typeof(<<Connect>g__StartConnection|40_0>d))]
			IEnumerator StartConnection()
			{
				//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
				return new <<Connect>g__StartConnection|40_0>d(0)
				{
					<>4__this = this
				};
			}
		}

		[ContextMenu("Disconnect")]
		public void Disconnect()
		{
			if (connection != null && !connection.disconnectCalled)
			{
				((MonoBehaviour)this).StartCoroutine(NonBlockingDisconnect());
			}
		}

		[IteratorStateMachine(typeof(<NonBlockingDisconnect>d__42))]
		private IEnumerator NonBlockingDisconnect()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <NonBlockingDisconnect>d__42(0)
			{
				<>4__this = this
			};
		}

		private void BlockingDisconnect()
		{
			if (connection != null)
			{
				connection.BlockingEnd();
				connection = null;
				if (showIRCDebug)
				{
					Debug.Log((object)(Tags.alert + " Disconnected from Twitch IRC"));
				}
			}
		}

		public void SendChatMessage(string message)
		{
			if (useAnonymousLogin)
			{
				Debug.LogError((object)"Chat messages cannot be sent with anonymous login");
			}
			else
			{
				connection.SendChatMessage(message);
			}
		}

		public void JoinChannel(string channel)
		{
			if (channel == "")
			{
				Debug.LogError((object)"Failed joining channel. Channel name is empty");
			}
			else
			{
				connection.SendCommand("JOIN #" + channel.ToLower(), priority: true);
			}
		}

		public void LeaveChannel(string channel)
		{
			if (channel == "")
			{
				Debug.LogError((object)"Failed leaving channel. Channel name is empty");
			}
			else
			{
				connection.SendCommand("PART #" + channel.ToLower(), priority: true);
			}
		}
	}
	[Serializable]
	public struct ChatterEmote
	{
		[Serializable]
		public struct Index
		{
			public int startIndex;

			public int endIndex;
		}

		public string id;

		public Index[] indexes;
	}
	[Serializable]
	public struct ChatterBadge
	{
		public string id;

		public string version;
	}
	[Serializable]
	public class IRCTags
	{
		public string colorHex = string.Empty;

		public string displayName = string.Empty;

		public string channelId = string.Empty;

		public string userId = string.Empty;

		public ChatterBadge[] badges = new ChatterBadge[0];

		public ChatterEmote[] emotes = new ChatterEmote[0];

		public bool ContainsEmote(string emoteId)
		{
			ChatterEmote[] array = emotes;
			for (int i = 0; i < array.Length; i++)
			{
				ChatterEmote chatterEmote = array[i];
				if (chatterEmote.id == emoteId)
				{
					return true;
				}
			}
			return false;
		}

		public bool HasBadge(string badge)
		{
			ChatterBadge[] array = badges;
			for (int i = 0; i < array.Length; i++)
			{
				ChatterBadge chatterBadge = array[i];
				if (chatterBadge.id == badge)
				{
					return true;
				}
			}
			return false;
		}
	}
	internal static class ParseHelper
	{
		private static Regex symbolRegex = new Regex("^[a-zA-Z0-9_]+$", RegexOptions.Compiled);

		public static int IndexOfNth(this string source, char val, int nth = 0)
		{
			int num = source.IndexOf(val);
			for (int i = 0; i < nth; i++)
			{
				if (num == -1)
				{
					return -1;
				}
				num = source.IndexOf(val, num + 1);
			}
			return num;
		}

		public static bool CheckNameRegex(string displayName)
		{
			return symbolRegex.IsMatch(displayName);
		}

		public static IRCTags ParseTags(string tagString)
		{
			IRCTags iRCTags = new IRCTags();
			string[] array = tagString.Split(';');
			for (int i = 0; i < array.Length; i++)
			{
				string text = array[i].Substring(array[i].IndexOf('=') + 1);
				if (text.Length > 0)
				{
					switch (array[i].Substring(0, array[i].IndexOf('=')))
					{
					case "badges":
						iRCTags.badges = ParseBadges(text.Split(','));
						break;
					case "color":
						iRCTags.colorHex = text;
						break;
					case "display-name":
						iRCTags.displayName = text;
						break;
					case "emotes":
						iRCTags.emotes = ParseTwitchEmotes(text.Split('/'));
						break;
					case "room-id":
						iRCTags.channelId = text;
						break;
					case "user-id":
						iRCTags.userId = text;
						break;
					}
				}
			}
			return iRCTags;
		}

		public static string ParseLoginName(string ircString)
		{
			return ircString.Substring(1, ircString.IndexOf('!') - 1);
		}

		public static string ParseChannel(string ircString)
		{
			string text = ircString.Substring(ircString.IndexOf('#') + 1);
			int num = text.IndexOf(' ');
			if (num == -1)
			{
				return text;
			}
			return text.Substring(0, num);
		}

		public static string ParseMessage(string ircString)
		{
			return ircString.Substring(ircString.IndexOfNth(' ', 2) + 2);
		}

		public static ChatterEmote[] ParseTwitchEmotes(string[] splitEmotes)
		{
			ChatterEmote[] array = new ChatterEmote[splitEmotes.Length];
			for (int i = 0; i < splitEmotes.Length; i++)
			{
				string text = splitEmotes[i];
				string[] array2 = ((text.Substring(text.IndexOf(':') + 1).Length > 0) ? text.Substring(text.IndexOf(':') + 1).Split(',') : new string[0]);
				ChatterEmote.Index[] array3 = new ChatterEmote.Index[array2.Length];
				for (int j = 0; j < array3.Length; j++)
				{
					array3[j].startIndex = int.Parse(array2[j].Substring(0, array2[j].IndexOf('-')));
					array3[j].endIndex = int.Parse(array2[j].Substring(array2[j].IndexOf('-') + 1));
				}
				array[i] = new ChatterEmote
				{
					id = text.Substring(0, text.IndexOf(':')),
					indexes = array3
				};
			}
			return array;
		}

		public static ChatterBadge[] ParseBadges(string[] splitBadges)
		{
			ChatterBadge[] array = new ChatterBadge[splitBadges.Length];
			for (int i = 0; i < splitBadges.Length; i++)
			{
				string text = splitBadges[i];
				array[i].id = text.Substring(0, text.IndexOf('/'));
				array[i].version = text.Substring(text.IndexOf('/') + 1);
			}
			return array;
		}
	}
	public struct RateLimit
	{
		public int count;

		public TimeSpan timeSpan;

		public static readonly RateLimit ChatRegular = new RateLimit(20, new TimeSpan(0, 0, 30));

		public static readonly RateLimit ChatModerator = new RateLimit(100, new TimeSpan(0, 0, 30));

		public static readonly RateLimit SiteLimitVerified = new RateLimit(7500, new TimeSpan(0, 0, 30));

		public static readonly RateLimit AuthAttemptsRegular = new RateLimit(20, new TimeSpan(0, 0, 10));

		public static readonly RateLimit JoinAttemptsRegular = new RateLimit(20, new TimeSpan(0, 0, 10));

		public static readonly RateLimit AuthAttemptsVerified = new RateLimit(200, new TimeSpan(0, 0, 10));

		public static readonly RateLimit JoinAttemptsVerified = new RateLimit(2000, new TimeSpan(0, 0, 10));

		public static readonly RateLimit WhispersA = new RateLimit(3, new TimeSpan(0, 0, 1));

		public static readonly RateLimit WhispersB = new RateLimit(100, new TimeSpan(0, 1, 0));

		public static readonly RateLimit WhisperChannels = new RateLimit(40, new TimeSpan(1, 0, 0, 0));

		public RateLimit(int count, TimeSpan timeSpan)
		{
			this.count = count;
			this.timeSpan = timeSpan;
		}
	}
	internal class TwitchConnection
	{
		[CompilerGenerated]
		private sealed class <End>d__31 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public TwitchConnection <>4__this;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <End>d__31(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				int num = <>1__state;
				TwitchConnection twitchConnection = <>4__this;
				switch (num)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					if (twitchConnection.tcpClient == null || twitchConnection.disconnectCalled)
					{
						return false;
					}
					twitchConnection.disconnectCalled = true;
					twitchConnection.ThreadsRunning = false;
					goto IL_0062;
				case 1:
					<>1__state = -1;
					goto IL_0062;
				case 2:
					{
						<>1__state = -1;
						break;
					}
					IL_0062:
					if (twitchConnection.readThread.IsAlive)
					{
						<>2__current = null;
						<>1__state = 1;
						return true;
					}
					break;
				}
				if (twitchConnection.writeThread.IsAlive)
				{
					<>2__current = null;
					<>1__state = 2;
					return true;
				}
				twitchConnection.tcpClient.Close();
				return false;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		private IRCTags _clientUserTags;

		private int _threadsRunning = 1;

		public bool disconnectCalled;

		private readonly string oauth;

		private readonly string nick;

		private readonly string channel;

		private readonly int readBufferSize;

		private readonly int readInterval;

		private readonly int writeInterval;

		private readonly bool joinChannelOnStart;

		private readonly bool showIRCDebug;

		private readonly bool showThreadDebug;

		private readonly bool useRandomColorForUndefined;

		private readonly ConcurrentQueue<IRCReply> alertQueue;

		private readonly ConcurrentQueue<Chatter> chatterQueue;

		private Thread readThread;

		private Thread writeThread;

		private RateLimit rateLimit = RateLimit.ChatRegular;

		private object rateLimitLock = new object();

		private int sessionRandom = DateTime.Now.Second;

		private ConcurrentQueue<string> priorityWriteQueue = new ConcurrentQueue<string>();

		private ConcurrentQueue<string> writeQueue = new ConcurrentQueue<string>();

		private ConcurrentQueue<DateTime> writeTimestamps = new ConcurrentQueue<DateTime>();

		public TcpClient tcpClient { get; private set; }

		public IRCTags ClientUserTags
		{
			get
			{
				return _clientUserTags;
			}
			set
			{
				Interlocked.Exchange(ref _clientUserTags, value);
			}
		}

		private bool ThreadsRunning
		{
			get
			{
				return _threadsRunning == 1;
			}
			set
			{
				Interlocked.Exchange(ref _threadsRunning, value ? 1 : 0);
			}
		}

		public TwitchConnection(IRC irc)
		{
			try
			{
				tcpClient = new TcpClient(irc.address, irc.port);
			}
			catch
			{
				tcpClient = null;
			}
			oauth = irc.oauth;
			nick = irc.username;
			channel = irc.channel;
			readBufferSize = (int)irc.readBufferSize;
			readInterval = irc.readInterval;
			writeInterval = irc.writeInterval;
			alertQueue = irc.alertQueue;
			chatterQueue = irc.chatterQueue;
			rateLimit = RateLimit.ChatRegular;
			joinChannelOnStart = irc.joinChannelOnStart;
			showIRCDebug = irc.showIRCDebug;
			showThreadDebug = irc.showThreadDebug;
			useRandomColorForUndefined = irc.useRandomColorForUndefined;
		}

		public void Begin()
		{
			readThread = new Thread((ThreadStart)delegate
			{
				ReadThreadLoop();
			});
			writeThread = new Thread((ThreadStart)delegate
			{
				WriteThreadLoop();
			});
			readThread.Start();
			writeThread.Start();
			SendCommand("PASS oauth:" + oauth.ToLower(), priority: true);
			SendCommand("NICK " + nick.ToLower(), priority: true);
			SendCommand("CAP REQ :twitch.tv/tags twitch.tv/commands", priority: true);
		}

		[IteratorStateMachine(typeof(<End>d__31))]
		public IEnumerator End()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <End>d__31(0)
			{
				<>4__this = this
			};
		}

		public void BlockingEnd()
		{
			if (tcpClient != null)
			{
				disconnectCalled = true;
				ThreadsRunning = false;
				readThread?.Join();
				writeThread?.Join();
				tcpClient.Close();
			}
		}

		private void UpdateRateLimits()
		{
			if (ClientUserTags.HasBadge("broadcaster") || ClientUserTags.HasBadge("moderator"))
			{
				lock (rateLimitLock)
				{
					rateLimit = RateLimit.ChatModerator;
					return;
				}
			}
			lock (rateLimitLock)
			{
				rateLimit = RateLimit.ChatRegular;
			}
		}

		private void ReadThreadLoop()
		{
			if (showThreadDebug)
			{
				Debug.Log((object)(Tags.thread + " Read thread started"));
			}
			using (NetworkStream networkStream = tcpClient.GetStream())
			{
				byte[] array = new byte[readBufferSize];
				StringBuilder stringBuilder = new StringBuilder();
				Decoder decoder = Encoding.UTF8.GetDecoder();
				char[] array2 = new char[readBufferSize + Mathf.Clamp(readBufferSize / 4, 1, 32)];
				while (ThreadsRunning)
				{
					if (!CheckConnection(tcpClient.Client))
					{
						alertQueue.Enqueue(IRCReply.CONNECTION_INTERRUPTED);
						return;
					}
					while (networkStream.DataAvailable)
					{
						int byteCount = networkStream.Read(array, 0, readBufferSize);
						int chars = decoder.GetChars(array, 0, byteCount, array2, 0);
						for (int i = 0; i < chars; i++)
						{
							if (array2[i] == '\n' || array2[i] == '\r')
							{
								if (stringBuilder.Length > 0)
								{
									HandleRawLine(stringBuilder.ToString());
									stringBuilder.Clear();
								}
							}
							else
							{
								stringBuilder.Append(array2[i]);
							}
						}
					}
					Thread.Sleep(readInterval);
				}
			}
			if (showThreadDebug)
			{
				Debug.Log((object)(Tags.thread + " Read thread stopped"));
			}
		}

		private bool CheckConnection(Socket socket)
		{
			bool flag = socket.Poll(1000, SelectMode.SelectRead);
			bool flag2 = socket.Available == 0;
			if ((flag && flag2) || !socket.Connected)
			{
				return false;
			}
			return true;
		}

		private void HandleRawLine(string raw)
		{
			if (showIRCDebug)
			{
				Debug.Log((object)(Tags.read + " " + raw));
			}
			string text = raw;
			string tagString = string.Empty;
			if (raw[0] == '@')
			{
				int num = raw.IndexOf(' ');
				tagString = raw.Substring(0, num);
				text = raw.Substring(num).TrimStart();
			}
			if (text[0] == ':')
			{
				string text2 = text.Substring(text.IndexOf(' ')).TrimStart();
				text2 = text2.Substring(0, text2.IndexOf(' '));
				switch (text2)
				{
				case "PRIVMSG":
					HandlePRIVMSG(text, tagString);
					break;
				case "USERSTATE":
					HandleUSERSTATE(text, tagString);
					break;
				case "NOTICE":
					HandleNOTICE(text, tagString);
					break;
				case "353":
				case "001":
					HandleRPL(text2);
					break;
				}
			}
			if (raw.StartsWith("PING"))
			{
				Pong();
			}
			if (raw.StartsWith(":tmi.twitch.tv PONG"))
			{
				alertQueue.Enqueue(IRCReply.PONG_RECEIVED);
			}
		}

		private void HandlePRIVMSG(string ircString, string tagString)
		{
			string login = ParseHelper.ParseLoginName(ircString);
			string text = ParseHelper.ParseChannel(ircString);
			string message = ParseHelper.ParseMessage(ircString);
			IRCTags iRCTags = ParseHelper.ParseTags(tagString);
			if (iRCTags.colorHex.Length <= 0)
			{
				iRCTags.colorHex = (useRandomColorForUndefined ? ChatColors.GetRandomNameColor(sessionRandom, login) : "#FFFFFF");
			}
			if (iRCTags.emotes.Length != 0)
			{
				Array.Sort(iRCTags.emotes, (ChatterEmote a, ChatterEmote b) => a.indexes[0].startIndex.CompareTo(b.indexes[0].startIndex));
			}
			chatterQueue.Enqueue(new Chatter(login, text, message, iRCTags));
		}

		private void HandleUSERSTATE(string ircString, string tagString)
		{
			IRCTags clientUserTags = ParseHelper.ParseTags(tagString);
			ClientUserTags = clientUserTags;
			UpdateRateLimits();
		}

		private void HandleNOTICE(string ircString, string tagString)
		{
			if (ircString.Contains(":Login authentication failed"))
			{
				alertQueue.Enqueue(IRCReply.BAD_LOGIN);
			}
		}

		private void HandleRPL(string type)
		{
			if (!(type == "001"))
			{
				if (type == "353")
				{
					alertQueue.Enqueue(IRCReply.JOINED_CHANNEL);
				}
				return;
			}
			alertQueue.Enqueue(IRCReply.CONNECTED_TO_SERVER);
			if (joinChannelOnStart)
			{
				IRC.Instance.JoinChannel(channel);
			}
		}

		private void WriteThreadLoop()
		{
			if (showThreadDebug)
			{
				Debug.Log((object)(Tags.thread + " Write thread started"));
			}
			NetworkStream stream = tcpClient.GetStream();
			while (ThreadsRunning)
			{
				while (!priorityWriteQueue.IsEmpty)
				{
					if (priorityWriteQueue.TryDequeue(out string result))
					{
						stream.WriteLine(result, showIRCDebug);
					}
				}
				lock (rateLimitLock)
				{
					RateLimit rateLimit = this.rateLimit;
				}
				DateTime dateTime = DateTime.Now - this.rateLimit.timeSpan;
				DateTime result2;
				while (writeTimestamps.TryPeek(out result2) && result2 < dateTime)
				{
					writeTimestamps.TryDequeue(out var _);
				}
				while (!writeQueue.IsEmpty && writeTimestamps.Count < this.rateLimit.count)
				{
					if (writeQueue.TryDequeue(out string result4))
					{
						stream.WriteLine(result4, showIRCDebug);
						writeTimestamps.Enqueue(DateTime.Now);
					}
				}
				Thread.Sleep(writeInterval);
			}
			if (showThreadDebug)
			{
				Debug.Log((object)(Tags.thread + " Write thread stopped"));
			}
		}

		public void Ping()
		{
			SendCommand("PING :tmi.twitch.tv", priority: true);
		}

		public void Pong()
		{
			SendCommand("PONG :tmi.twitch.tv", priority: true);
		}

		public void SendCommand(string command, bool priority = false)
		{
			if (priority)
			{
				priorityWriteQueue.Enqueue(command);
			}
			else
			{
				writeQueue.Enqueue(command);
			}
		}

		public void SendChatMessage(string message)
		{
			if (message.Length <= 0)
			{
				Debug.LogWarning((object)(Tags.write + " Tried sending an empty chat message"));
			}
			else
			{
				SendCommand("PRIVMSG #" + channel + " :" + message);
			}
		}
	}
	public enum IRCReply
	{
		CONNECTED_TO_SERVER = 1,
		PONG_RECEIVED = 7,
		JOINED_CHANNEL = 353,
		MISSING_LOGIN_INFO = 431,
		BAD_LOGIN = 464,
		CONNECTION_INTERRUPTED = 498,
		NO_CONNECTION = 499
	}
	public enum ReadBufferSize
	{
		_32 = 0x20,
		_64 = 0x40,
		_128 = 0x80,
		_256 = 0x100,
		_512 = 0x200,
		_1024 = 0x400,
		_2048 = 0x800,
		_4096 = 0x1000
	}
	public static class Tags
	{
		public static string read = "<color=#00ff00><b>[IRC READ]</b></color>";

		public static string write = "<color=#5274ff><b>[IRC WRITE]</b></color>";

		public static string thread = "<color=#ff5252><b>[THREAD]</b></color>";

		public static string alert = "<color=#ffae00><b>[ALERT]</b></color>";
	}
	public static class ChatColors
	{
		public static string[] defaultNameColors = new string[15]
		{
			"#FF0000", "#00FF00", "#0000FF", "#B22222", "#FF7F50", "#9ACD32", "#FF4500", "#2E8B57", "#DAA520", "#D2691E",
			"#5F9EA0", "#1E90FF", "#FF69B4", "#8A2BE2", "#00FF7F"
		};

		public static float grayscaleLow = 0.3f;

		public static float grayscaleHigh = 1f;

		public static string GetRandomNameColor(int sessionRandom, string login)
		{
			int num = sessionRandom + login[0] + login[login.Length - 1];
			return defaultNameColors[num % defaultNameColors.Length];
		}

		public static Color NormalizeColor(Color color)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: 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)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			if (((Color)(ref color)).grayscale < grayscaleLow)
			{
				float num = grayscaleLow - ((Color)(ref color)).grayscale;
				return new Color(color.r + num, color.g + num, color.b + num);
			}
			if (((Color)(ref color)).grayscale > grayscaleHigh)
			{
				float num2 = grayscaleHigh - ((Color)(ref color)).grayscale;
				return new Color(color.r + num2, color.g + num2, color.b + num2);
			}
			return color;
		}
	}
}
namespace SBG_Chat_Integration
{
	public class ChatAction
	{
		public string name { get; set; }

		public Action onChoose { get; set; }
	}
	public class ChatAPI : MonoBehaviour
	{
		[CompilerGenerated]
		private sealed class <VotingRoutine>d__11 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public ChatAPI <>4__this;

			private float <showTime>5__2;

			private float <timer>5__3;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <VotingRoutine>d__11(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_008b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0095: Expected O, but got Unknown
				int num = <>1__state;
				ChatAPI chatAPI = <>4__this;
				switch (num)
				{
				default:
					return false;
				case 0:
				{
					<>1__state = -1;
					votes.Clear();
					currentOptions.Clear();
					countingVotes = false;
					chatAPI.chattersThatHaveVoted.Clear();
					int num3 = Random.Range(Plugin.minWaitTime.Value, Plugin.maxWaitTime.Value + 1);
					Plugin.Log.LogInfo((object)$"Next vote in {num3} seconds.");
					<>2__current = (object)new WaitForSeconds((float)num3);
					<>1__state = 1;
					return true;
				}
				case 1:
				{
					<>1__state = -1;
					int count = Mathf.Min(Plugin.optionsToShow.Value, allActions.Count);
					List<ChatAction> list = allActions.OrderBy((ChatAction x) => Random.value).Take(count).ToList();
					Plugin.Log.LogInfo((object)"--- UPCOMING OPTIONS (Get Ready!) ---");
					for (int i = 0; i < list.Count; i++)
					{
						int num2 = i + 1;
						currentOptions.Add(num2, list[i]);
						votes.Add(num2, 0);
						Plugin.Log.LogInfo((object)$"[{num2}] {list[i].name}");
					}
					GUIManager.CreateOptionsGUI(list);
					<showTime>5__2 = Plugin.showTimeBeforeVoting.Value;
					Plugin.Log.LogInfo((object)$"Voting starts in {<showTime>5__2} seconds...");
					goto IL_01d8;
				}
				case 2:
					<>1__state = -1;
					goto IL_01d8;
				case 3:
					{
						<>1__state = -1;
						break;
					}
					IL_01d8:
					if (<showTime>5__2 > 0f)
					{
						GUIManager.UpdateTimer(<showTime>5__2);
						<showTime>5__2 -= Time.deltaTime;
						<>2__current = null;
						<>1__state = 2;
						return true;
					}
					GUIManager.StartVotingPhase();
					countingVotes = true;
					<timer>5__3 = Plugin.votingTime.Value;
					Plugin.Log.LogInfo((object)"VOTING OPEN! Type the number in chat!");
					break;
				}
				if (<timer>5__3 > 0f)
				{
					GUIManager.UpdateTimer(<timer>5__3);
					<timer>5__3 -= Time.deltaTime;
					<>2__current = null;
					<>1__state = 3;
					return true;
				}
				countingVotes = false;
				chatAPI.ProcessWinner();
				chatAPI.StartRandomSelection();
				return false;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		public static ChatAPI instance;

		private static List<ChatAction> allActions = new List<ChatAction>();

		public static Dictionary<int, int> votes = new Dictionary<int, int>();

		public static Dictionary<int, ChatAction> currentOptions = new Dictionary<int, ChatAction>();

		public List<string> chattersThatHaveVoted = new List<string>();

		public static bool countingVotes = false;

		private Coroutine currentVoteCoroutine;

		private void Awake()
		{
			instance = this;
		}

		public void RegisterNewAction(ChatAction chatAction)
		{
			if (string.IsNullOrEmpty(chatAction.name))
			{
				Plugin.Log.LogError((object)"The ChatAction must have a name!");
			}
			else if (chatAction.onChoose == null)
			{
				Plugin.Log.LogError((object)("ChatAction: " + chatAction.name + " must have an onChoose event!"));
			}
			else if (!allActions.Contains(chatAction))
			{
				allActions.Add(chatAction);
			}
		}

		public void ForceCancelSelection()
		{
			((MonoBehaviour)this).StopAllCoroutines();
			votes.Clear();
			currentOptions.Clear();
			countingVotes = false;
			chattersThatHaveVoted.Clear();
			GUIManager.CancelGUI();
		}

		public void StartRandomSelection()
		{
			if (allActions.Count == 0)
			{
				Plugin.Log.LogError((object)"Cannot start voting: No actions registered!");
				return;
			}
			if (currentVoteCoroutine != null)
			{
				((MonoBehaviour)this).StopCoroutine(currentVoteCoroutine);
			}
			currentVoteCoroutine = ((MonoBehaviour)this).StartCoroutine(VotingRoutine());
		}

		[IteratorStateMachine(typeof(<VotingRoutine>d__11))]
		private IEnumerator VotingRoutine()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <VotingRoutine>d__11(0)
			{
				<>4__this = this
			};
		}

		private void ProcessWinner()
		{
			if (votes.Count == 0)
			{
				return;
			}
			int key = votes.Aggregate((KeyValuePair<int, int> l, KeyValuePair<int, int> r) => (l.Value <= r.Value) ? r : l).Key;
			int num = votes[key];
			ChatAction chatAction = currentOptions[key];
			Plugin.Log.LogInfo((object)$"--- WINNER: {chatAction.name} with {num} votes! ---");
			GUIManager.ShowWinner(key);
			try
			{
				chatAction.onChoose?.Invoke();
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Error executing ChatAction " + chatAction.name + ": " + ex.Message));
			}
		}

		public void AddVote(int vote)
		{
			if (countingVotes && currentOptions.ContainsKey(vote))
			{
				votes[vote]++;
				GUIManager.UpdateGUI(vote, votes[vote]);
			}
		}
	}
	[BepInPlugin("com.atomic.sbgchatintegration", "SBG_Chat_Integration", "0.1.0")]
	public class Plugin : BaseUnityPlugin
	{
		private TwitchConnection connection;

		public static Harmony harmony;

		public static ConfigEntry<int> showTimeBeforeVoting;

		public static ConfigEntry<int> votingTime;

		public static ConfigEntry<int> optionsToShow;

		public static ConfigEntry<int> minWaitTime;

		public static ConfigEntry<int> maxWaitTime;

		public static ConfigEntry<bool> peopleVoteMultipleTimes;

		public static ConfigEntry<string> guiPosition;

		public static ConfigEntry<string> twitchUsername;

		public static bool gotUIRefs;

		public const string Id = "com.atomic.sbgchatintegration";

		internal static ManualLogSource Log { get; private set; }

		public static string Name => "SBG_Chat_Integration";

		public static string Version => "0.1.0";

		private void Awake()
		{
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Expected O, but got Unknown
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Expected O, but got Unknown
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Expected O, but got Unknown
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Expected O, but got Unknown
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Expected O, but got Unknown
			//IL_01bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c5: Expected O, but got Unknown
			//IL_0208: Unknown result type (might be due to invalid IL or missing references)
			//IL_0212: Expected O, but got Unknown
			//IL_0221: Unknown result type (might be due to invalid IL or missing references)
			//IL_0227: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			twitchUsername = ((BaseUnityPlugin)this).Config.Bind<string>("Setup", "Twitch Username", "your_twitch_handle", "The username that the mod will read chat from.");
			showTimeBeforeVoting = ((BaseUnityPlugin)this).Config.Bind<int>("General", "Show Time Before Voting", 5, new ConfigDescription("(In Seconds): How long the options will wait on screen before stating to vote. Consider stream delay.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(5, 20), Array.Empty<object>()));
			votingTime = ((BaseUnityPlugin)this).Config.Bind<int>("General", "Voting Time", 10, new ConfigDescription("(In Seconds): How long the mod will be tracking votes for.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(5, 30), Array.Empty<object>()));
			optionsToShow = ((BaseUnityPlugin)this).Config.Bind<int>("General", "Options to show", 3, new ConfigDescription("How many options can be picked at once", (AcceptableValueBase)(object)new AcceptableValueRange<int>(2, 5), Array.Empty<object>()));
			minWaitTime = ((BaseUnityPlugin)this).Config.Bind<int>("General", "Minimum Intermission", 30, new ConfigDescription("The minimum time to wait after an event", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 300), Array.Empty<object>()));
			maxWaitTime = ((BaseUnityPlugin)this).Config.Bind<int>("General", "Maximum Intermission", 60, new ConfigDescription("The maximum time to wait after an event", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 300), Array.Empty<object>()));
			peopleVoteMultipleTimes = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Can Vote Multiple Times", false, "If True people can vote for the same poll as many times as they want");
			guiPosition = ((BaseUnityPlugin)this).Config.Bind<string>("General", "GUI Position", "Top-Right", new ConfigDescription("The position the voting UI will be in.", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[8] { "Top-Right", "Top-Middle", "Top-Left", "Middle-Left", "Middle-Right", "Bottom-Left", "Bottom-Middle", "Bottom-Right" }), Array.Empty<object>()));
			if (maxWaitTime.Value < minWaitTime.Value)
			{
				Log.LogWarning((object)"Max Wait Time was lower than Min. Adjusting Max to match Min.");
				maxWaitTime.Value = minWaitTime.Value;
			}
			harmony = new Harmony("com.atomic.sbgchatintegration");
			harmony.PatchAll();
			GameObject val = new GameObject("ChatManager");
			((Object)val).hideFlags = (HideFlags)61;
			ChatAPI chatAPI = val.AddComponent<ChatAPI>();
			GUIManager gUIManager = val.AddComponent<GUIManager>();
			if (twitchUsername.Value != "your_twitch_handle")
			{
				IRC iRC = val.AddComponent<IRC>();
				iRC.showIRCDebug = false;
				iRC.username = "justinfan12345";
				iRC.oauth = "pass";
				iRC.channel = twitchUsername.Value;
				IRC.Instance.OnChatMessage += OnTwitchChatMessage;
				IRC.Instance.Connect();
				Log.LogInfo((object)("Attempting anonymous connect to " + iRC.channel + "..."));
			}
			Object.DontDestroyOnLoad((Object)(object)val);
			DefaultActions.RegisterActions();
		}

		private void OnTwitchChatMessage(Chatter chatter)
		{
			Log.LogInfo((object)(chatter.login + ": " + chatter.message));
			if (ChatAPI.countingVotes && (!ChatAPI.instance.chattersThatHaveVoted.Contains(chatter.login) || peopleVoteMultipleTimes.Value) && int.TryParse(chatter.message, out var result))
			{
				ChatAPI.instance.AddVote(result);
				if (!peopleVoteMultipleTimes.Value)
				{
					ChatAPI.instance.chattersThatHaveVoted.Add(chatter.login);
				}
			}
		}

		private void OnDisable()
		{
			IRC.Instance.Disconnect();
		}
	}
	[HarmonyPatch]
	public static class SBG_ChatIntegration_Patches
	{
		[HarmonyPostfix]
		[HarmonyPatch(typeof(GameManager), "RegisterPlayer")]
		public static void StartVoting(GameManager __instance, PlayerInfo playerInfo)
		{
			if (((NetworkBehaviour)playerInfo).isLocalPlayer)
			{
				Plugin.Log.LogInfo((object)"Passed checks...");
				ChatAPI.instance.StartRandomSelection();
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(MainMenu), "Awake")]
		public static void StopVotes(MainMenu __instance)
		{
			ChatAPI.instance.ForceCancelSelection();
		}
	}
}
namespace SBG_Chat_Integration.UI
{
	public class GUIManager : MonoBehaviour
	{
		[CompilerGenerated]
		private sealed class <FadeOutSequence>d__45 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public float delay;

			public GUIManager <>4__this;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <FadeOutSequence>d__45(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0025: Unknown result type (might be due to invalid IL or missing references)
				//IL_002f: Expected O, but got Unknown
				int num = <>1__state;
				GUIManager gUIManager = <>4__this;
				switch (num)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>2__current = (object)new WaitForSeconds(delay);
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					gUIManager.isFadingOut = true;
					return false;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		private static GUIManager instance;

		private static List<ChatAction> currentActions = new List<ChatAction>();

		private static Dictionary<int, int> currentVotes = new Dictionary<int, int>();

		private static float timerValue;

		private static bool isVotingOpen = false;

		private static bool isPreVoting = false;

		private static bool isShowingWinner = false;

		private static float totalVotes = 0f;

		private static int winningOption = -1;

		private GUIStyle boxStyle;

		private GUIStyle titleStyle;

		private GUIStyle optionStyle;

		private GUIStyle timerStyle;

		private GUIStyle voteBarStyle;

		private GUIStyle percentageStyle;

		private GUIStyle winnerStyle;

		private Dictionary<int, float> targetPercentages = new Dictionary<int, float>();

		private Dictionary<int, float> currentPercentages = new Dictionary<int, float>();

		private Dictionary<int, Color> targetBarColors = new Dictionary<int, Color>();

		private Dictionary<int, Color> currentBarColors = new Dictionary<int, Color>();

		private float animationSpeed = 5f;

		private float fadeAlpha = 1f;

		private float fadeSpeed = 2f;

		private bool isFadingOut;

		private const float windowWidth = 320f;

		private float windowHeight;

		private Rect windowRect;

		private static string currentPosition = "Top-Right";

		private Texture2D backgroundTexture;

		private Texture2D barBackgroundTexture;

		private Dictionary<Color, Texture2D> colorTextures = new Dictionary<Color, Texture2D>();

		private void Awake()
		{
			instance = this;
			Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject);
		}

		private void Start()
		{
			UpdateWindowPosition(Plugin.guiPosition.Value);
			Plugin.guiPosition.SettingChanged += delegate
			{
				UpdateWindowPosition(Plugin.guiPosition.Value);
			};
		}

		private void Update()
		{
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: 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_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			if (isVotingOpen || isShowingWinner)
			{
				for (int i = 1; i <= currentActions.Count; i++)
				{
					if (!currentPercentages.ContainsKey(i))
					{
						currentPercentages[i] = 0f;
					}
					float num = (targetPercentages.ContainsKey(i) ? targetPercentages[i] : 0f);
					currentPercentages[i] = Mathf.Lerp(currentPercentages[i], num, Time.deltaTime * animationSpeed);
					if (!currentBarColors.ContainsKey(i))
					{
						currentBarColors[i] = Color.red;
					}
					Color val = (targetBarColors.ContainsKey(i) ? targetBarColors[i] : Color.red);
					currentBarColors[i] = Color.Lerp(currentBarColors[i], val, Time.deltaTime * animationSpeed);
				}
			}
			if (isFadingOut)
			{
				fadeAlpha = Mathf.MoveTowards(fadeAlpha, 0f, Time.deltaTime * fadeSpeed);
				if (fadeAlpha <= 0.001f)
				{
					fadeAlpha = 0f;
					isFadingOut = false;
					currentActions.Clear();
					currentVotes.Clear();
				}
			}
		}

		private void UpdateWindowPosition(string position)
		{
			//IL_01f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f6: Unknown result type (might be due to invalid IL or missing references)
			currentPosition = position;
			windowHeight = CalculateWindowHeight();
			float num = 20f;
			float num2 = 20f;
			switch (position)
			{
			case "Top-Middle":
				num = ((float)Screen.width - 320f) / 2f;
				break;
			case "Top-Right":
				num = (float)Screen.width - 320f - 20f;
				break;
			case "Middle-Left":
				num2 = ((float)Screen.height - windowHeight) / 2f;
				break;
			case "Middle-Right":
				num = (float)Screen.width - 320f - 20f;
				num2 = ((float)Screen.height - windowHeight) / 2f;
				break;
			case "Bottom-Left":
				num2 = (float)Screen.height - windowHeight - 20f;
				break;
			case "Bottom-Middle":
				num = ((float)Screen.width - 320f) / 2f;
				num2 = (float)Screen.height - windowHeight - 20f;
				break;
			case "Bottom-Right":
				num = (float)Screen.width - 320f - 20f;
				num2 = (float)Screen.height - windowHeight - 20f;
				break;
			}
			windowRect = new Rect(num, num2, 320f, windowHeight);
		}

		private float CalculateWindowHeight()
		{
			if (currentActions.Count == 0)
			{
				return 0f;
			}
			float num = 85f;
			float num2 = (isVotingOpen ? 30f : 0f);
			float num3 = 78f;
			return num + num2 + num3 * (float)currentActions.Count + 20f;
		}

		private Texture2D GetColorTexture(Color color)
		{
			//IL_0002: 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_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Expected O, but got Unknown
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			Color val = default(Color);
			((Color)(ref val))..ctor(Mathf.Round(color.r * 100f) / 100f, Mathf.Round(color.g * 100f) / 100f, Mathf.Round(color.b * 100f) / 100f, color.a);
			if (colorTextures.TryGetValue(val, out Texture2D value))
			{
				return value;
			}
			Texture2D val2 = new Texture2D(1, 1);
			val2.SetPixel(0, 0, val);
			val2.Apply();
			colorTextures[val] = val2;
			return val2;
		}

		private void DrawTextWithOutline(Rect rect, string text, GUIStyle style, Color outColor, Color inColor, float thickness = 1f)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Expected O, but got Unknown
			//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_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: 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)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: 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_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_0145: Unknown result type (might be due to invalid IL or missing references)
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0159: Unknown result type (might be due to invalid IL or missing references)
			//IL_0160: Unknown result type (might be due to invalid IL or missing references)
			GUIStyle val = new GUIStyle(style);
			val.normal.textColor = outColor;
			Color color = GUI.color;
			GUI.color = new Color(outColor.r, outColor.g, outColor.b, outColor.a * color.a);
			Rect val2 = rect;
			((Rect)(ref val2)).x = ((Rect)(ref val2)).x - thickness;
			GUI.Label(val2, text, val);
			((Rect)(ref val2)).x = ((Rect)(ref val2)).x + thickness * 2f;
			GUI.Label(val2, text, val);
			((Rect)(ref val2)).x = ((Rect)(ref val2)).x - thickness;
			((Rect)(ref val2)).y = ((Rect)(ref val2)).y - thickness;
			GUI.Label(val2, text, val);
			((Rect)(ref val2)).y = ((Rect)(ref val2)).y + thickness * 2f;
			GUI.Label(val2, text, val);
			((Rect)(ref val2)).x = ((Rect)(ref val2)).x - thickness;
			((Rect)(ref val2)).y = ((Rect)(ref val2)).y - thickness * 2f;
			GUI.Label(val2, text, val);
			((Rect)(ref val2)).x = ((Rect)(ref val2)).x + thickness * 2f;
			GUI.Label(val2, text, val);
			((Rect)(ref val2)).y = ((Rect)(ref val2)).y + thickness * 2f;
			GUI.Label(val2, text, val);
			((Rect)(ref val2)).x = ((Rect)(ref val2)).x - thickness * 2f;
			GUI.Label(val2, text, val);
			GUI.color = color;
			style.normal.textColor = inColor;
			GUI.Label(rect, text, style);
		}

		private void InitializeStyles()
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: 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)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Expected O, but got Unknown
			//IL_008c: Expected O, but got Unknown
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: 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_00ab: 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_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Expected O, but got Unknown
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: 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_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Expected O, but got Unknown
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Expected O, but got Unknown
			//IL_0136: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0143: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0156: Expected O, but got Unknown
			//IL_0161: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: Unknown result type (might be due to invalid IL or missing references)
			//IL_017c: Expected O, but got Unknown
			//IL_0187: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0194: Unknown result type (might be due to invalid IL or missing references)
			//IL_019b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b7: Expected O, but got Unknown
			if (boxStyle == null)
			{
				backgroundTexture = GetColorTexture(new Color(0.05f, 0.05f, 0.05f, 0.9f));
				barBackgroundTexture = GetColorTexture(new Color(0.2f, 0.2f, 0.2f, 0.5f));
				GUIStyle val = new GUIStyle(GUI.skin.box);
				val.normal.background = backgroundTexture;
				val.padding = new RectOffset(10, 10, 10, 10);
				boxStyle = val;
				GUIStyle val2 = new GUIStyle(GUI.skin.label)
				{
					fontSize = 20,
					fontStyle = (FontStyle)1,
					alignment = (TextAnchor)4
				};
				val2.normal.textColor = new Color(1f, 0.84f, 0f);
				titleStyle = val2;
				GUIStyle val3 = new GUIStyle(GUI.skin.label)
				{
					fontSize = 16
				};
				val3.normal.textColor = Color.white;
				optionStyle = val3;
				GUIStyle val4 = new GUIStyle(optionStyle)
				{
					fontStyle = (FontStyle)1
				};
				val4.normal.textColor = Color.green;
				winnerStyle = val4;
				timerStyle = new GUIStyle(GUI.skin.label)
				{
					fontSize = 18,
					fontStyle = (FontStyle)1,
					alignment = (TextAnchor)4
				};
				GUIStyle val5 = new GUIStyle(GUI.skin.box);
				val5.normal.background = barBackgroundTexture;
				voteBarStyle = val5;
				GUIStyle val6 = new GUIStyle(GUI.skin.label)
				{
					fontSize = 12,
					fontStyle = (FontStyle)1,
					alignment = (TextAnchor)4
				};
				val6.normal.textColor = Color.white;
				percentageStyle = val6;
			}
		}

		private void OnGUI()
		{
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_03dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f7: Expected O, but got Unknown
			//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0205: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_025e: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_02df: Unknown result type (might be due to invalid IL or missing references)
			//IL_0326: Unknown result type (might be due to invalid IL or missing references)
			//IL_032b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0330: Unknown result type (might be due to invalid IL or missing references)
			//IL_0349: Unknown result type (might be due to invalid IL or missing references)
			//IL_034f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0363: Unknown result type (might be due to invalid IL or missing references)
			//IL_037c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0381: Unknown result type (might be due to invalid IL or missing references)
			InitializeStyles();
			if (currentActions.Count == 0 || fadeAlpha <= 0.01f)
			{
				return;
			}
			windowHeight = CalculateWindowHeight();
			UpdateWindowPosition(currentPosition);
			GUI.color = new Color(1f, 1f, 1f, fadeAlpha);
			GUI.Box(windowRect, "", boxStyle);
			GUILayout.BeginArea(new Rect(((Rect)(ref windowRect)).x + 10f, ((Rect)(ref windowRect)).y + 10f, ((Rect)(ref windowRect)).width - 20f, ((Rect)(ref windowRect)).height - 20f));
			GUILayout.BeginVertical(Array.Empty<GUILayoutOption>());
			string text = (isShowingWinner ? "Winner!" : (isPreVoting ? "Upcoming Vote" : "Vote Now!"));
			GUILayout.Label(text, titleStyle, Array.Empty<GUILayoutOption>());
			if (!isShowingWinner)
			{
				timerStyle.normal.textColor = (isPreVoting ? Color.gray : Color.green);
				GUILayout.Label(isPreVoting ? $"Starts in: {Mathf.CeilToInt(timerValue)}s" : $"{Mathf.CeilToInt(timerValue)}s remaining", timerStyle, Array.Empty<GUILayoutOption>());
			}
			else
			{
				GUILayout.Space(10f);
			}
			for (int i = 0; i < currentActions.Count; i++)
			{
				int num = i + 1;
				bool flag = isShowingWinner && num == winningOption;
				int valueOrDefault = currentVotes.GetValueOrDefault(num, 0);
				float num2 = ((totalVotes > 0f) ? ((float)valueOrDefault / totalVotes * 100f) : 0f);
				targetPercentages[num] = num2;
				if (flag)
				{
					targetBarColors[num] = Color.green;
				}
				else
				{
					targetBarColors[num] = Color.Lerp(Color.red, Color.cyan, num2 / 100f);
				}
				GUILayout.BeginVertical(boxStyle, Array.Empty<GUILayoutOption>());
				GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
				GUIStyle val = (flag ? winnerStyle : optionStyle);
				if (isPreVoting)
				{
					val.normal.textColor = new Color(1f, 1f, 1f, 0.5f);
				}
				GUILayout.Label($"[{num}] {currentActions[i].name}", val, Array.Empty<GUILayoutOption>());
				if (!isPreVoting)
				{
					GUILayout.FlexibleSpace();
					GUILayout.Label(valueOrDefault.ToString(), val, Array.Empty<GUILayoutOption>());
				}
				GUILayout.EndHorizontal();
				GUILayout.Space(5f);
				Rect rect = GUILayoutUtility.GetRect(((Rect)(ref windowRect)).width - 40f, 20f);
				GUI.Box(rect, "", voteBarStyle);
				float valueOrDefault2 = currentPercentages.GetValueOrDefault(num, 0f);
				if (valueOrDefault2 > 0f)
				{
					float num3 = valueOrDefault2 / 100f * ((Rect)(ref rect)).width;
					Color valueOrDefault3 = currentBarColors.GetValueOrDefault(num, Color.red);
					GUI.DrawTexture(new Rect(((Rect)(ref rect)).x, ((Rect)(ref rect)).y, num3, ((Rect)(ref rect)).height), (Texture)(object)GetColorTexture(valueOrDefault3));
				}
				if (!isPreVoting)
				{
					DrawTextWithOutline(rect, $"{num2:F0}%", percentageStyle, Color.black, Color.white);
				}
				GUILayout.EndVertical();
			}
			if (isVotingOpen)
			{
				GUILayout.Space(5f);
				GUIStyle val2 = new GUIStyle(GUI.skin.label)
				{
					alignment = (TextAnchor)4,
					fontSize = 12
				};
				val2.normal.textColor = Color.gray;
				GUILayout.Label("Type the number in chat", val2, Array.Empty<GUILayoutOption>());
			}
			GUILayout.EndVertical();
			GUILayout.EndArea();
		}

		public static void CreateOptionsGUI(List<ChatAction> actions)
		{
			//IL_0012: 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_00c7: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)instance == (Object)null)
			{
				instance = new GameObject("VoteGUI").AddComponent<GUIManager>();
			}
			currentActions = actions;
			currentVotes.Clear();
			instance.targetPercentages.Clear();
			instance.currentPercentages.Clear();
			instance.targetBarColors.Clear();
			instance.currentBarColors.Clear();
			for (int i = 1; i <= actions.Count; i++)
			{
				currentVotes[i] = 0;
				instance.currentPercentages[i] = 0f;
				instance.targetPercentages[i] = 0f;
				instance.currentBarColors[i] = Color.red;
				instance.targetBarColors[i] = Color.red;
			}
			isPreVoting = true;
			isVotingOpen = false;
			isShowingWinner = false;
			instance.fadeAlpha = 1f;
			instance.isFadingOut = false;
			timerValue = Plugin.showTimeBeforeVoting.Value;
			totalVotes = 0f;
			winningOption = -1;
		}

		public static void UpdateGUI(int target, int count)
		{
			if (currentVotes.ContainsKey(target))
			{
				currentVotes[target] = count;
				totalVotes = currentVotes.Values.Sum();
			}
		}

		public static void CancelGUI()
		{
			if (!((Object)(object)instance == (Object)null))
			{
				instance.isFadingOut = true;
			}
		}

		public static void StartVotingPhase()
		{
			isPreVoting = false;
			isVotingOpen = true;
			timerValue = Plugin.votingTime.Value;
		}

		public static void ShowWinner(int num)
		{
			winningOption = num;
			isShowingWinner = true;
			isVotingOpen = false;
			((MonoBehaviour)instance).StartCoroutine(instance.FadeOutSequence(3f));
		}

		[IteratorStateMachine(typeof(<FadeOutSequence>d__45))]
		private IEnumerator FadeOutSequence(float delay)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <FadeOutSequence>d__45(0)
			{
				<>4__this = this,
				delay = delay
			};
		}

		public static void UpdateTimer(float time)
		{
			timerValue = time;
		}
	}
}
namespace SBG_Chat_Integration.Actions
{
	[HarmonyPatch]
	public static class ActionPatches
	{
		public static bool canMove = true;

		public static bool invertedControls = false;

		public static bool superSlow = false;

		[HarmonyPrefix]
		[HarmonyPatch(typeof(PlayerGolfer), "CanMove")]
		public static bool OverrideMove(PlayerGolfer __instance, ref bool __result)
		{
			if (((NetworkBehaviour)__instance).isLocalPlayer)
			{
				if (canMove)
				{
					return true;
				}
				__result = false;
				return false;
			}
			return true;
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(PlayerMovement), "ApplyMovement")]
		public static void InvertMovementPrefix(PlayerMovement __instance)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			if (((NetworkBehaviour)__instance).isLocalPlayer && invertedControls)
			{
				__instance.worldMoveVector3d *= -1f;
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(GolfCartInfo), "ServerEnter")]
		public static bool RestrictAccess(GolfCartInfo __instance, PlayerInfo newPassenger)
		{
			if (((NetworkBehaviour)newPassenger).isLocalPlayer)
			{
				return canMove;
			}
			return true;
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(PlayerMovement), "UpdateMovementSpeed")]
		public static void ApplySuperSlow(PlayerMovement __instance)
		{
			if (((NetworkBehaviour)__instance).isLocalPlayer && superSlow)
			{
				__instance.speed *= 0.5f;
			}
		}
	}
	public class DefaultActions
	{
		[CompilerGenerated]
		private sealed class <DanceSequence>d__1 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public float duration;

			private PlayerInfo <player>5__2;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <DanceSequence>d__1(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<player>5__2 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0051: Unknown result type (might be due to invalid IL or missing references)
				//IL_005b: Expected O, but got Unknown
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					ActionPatches.canMove = false;
					<player>5__2 = GameManager.LocalPlayerInfo;
					<player>5__2.ExitGolfCart((GolfCartExitType)0);
					<player>5__2.SetEmoteBeingPlayed((Emote)1);
					GameManager.LocalPlayerInventory.InformIsPlayingEmoteChanged();
					<>2__current = (object)new WaitForSeconds(duration);
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					ActionPatches.canMove = true;
					<player>5__2.SetEmoteBeingPlayed((Emote)0);
					GameManager.LocalPlayerInventory.InformIsPlayingEmoteChanged();
					return false;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[CompilerGenerated]
		private sealed class <InvertedControls>d__2 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public float duration;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <InvertedControls>d__2(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0033: Unknown result type (might be due to invalid IL or missing references)
				//IL_003d: Expected O, but got Unknown
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					ActionPatches.invertedControls = true;
					Plugin.Log.LogInfo((object)"Movement Inverted!");
					<>2__current = (object)new WaitForSeconds(duration);
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					ActionPatches.invertedControls = false;
					Plugin.Log.LogInfo((object)"Movement Restored.");
					return false;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[CompilerGenerated]
		private sealed class <SuperSlow>d__3 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public float duration;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <SuperSlow>d__3(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0024: Unknown result type (might be due to invalid IL or missing references)
				//IL_002e: Expected O, but got Unknown
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					ActionPatches.superSlow = true;
					<>2__current = (object)new WaitForSeconds(duration);
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					ActionPatches.superSlow = false;
					return false;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		public static void RegisterActions()
		{
			ChatAction chatAction = new ChatAction
			{
				name = "Fling ball",
				onChoose = delegate
				{
					//IL_0012: Unknown result type (might be due to invalid IL or missing references)
					//IL_0017: Unknown result type (might be due to invalid IL or missing references)
					//IL_002c: 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_003b: Unknown result type (might be due to invalid IL or missing references)
					//IL_0040: Unknown result type (might be due to invalid IL or missing references)
					//IL_0045: Unknown result type (might be due to invalid IL or missing references)
					//IL_0057: Unknown result type (might be due to invalid IL or missing references)
					float num5 = 100f;
					float num6 = 10f;
					float num7 = 1f;
					Vector3 onUnitSphere = Random.onUnitSphere;
					Vector3 val4 = ((Component)GameManager.LocalPlayerAsGolfer.ownBall.rigidbody).transform.position + Vector3.down * 0.5f;
					GameManager.LocalPlayerAsGolfer.ownBall.rigidbody.AddExplosionForce(num5, val4, num6, num7, (ForceMode)1);
					Plugin.Log.LogInfo((object)"Chat triggered ball fling!");
				}
			};
			ChatAction chatAction2 = new ChatAction
			{
				name = "Do nothing",
				onChoose = delegate
				{
					Plugin.Log.LogInfo((object)"You got lucky...");
				}
			};
			ChatAction chatAction3 = new ChatAction
			{
				name = "Fling Player",
				onChoose = delegate
				{
					//IL_002d: Unknown result type (might be due to invalid IL or missing references)
					//IL_0032: Unknown result type (might be due to invalid IL or missing references)
					//IL_003c: Unknown result type (might be due to invalid IL or missing references)
					//IL_0041: Unknown result type (might be due to invalid IL or missing references)
					//IL_0046: Unknown result type (might be due to invalid IL or missing references)
					//IL_004a: Unknown result type (might be due to invalid IL or missing references)
					Rigidbody rigidbody = GameManager.LocalPlayerMovement.rigidbody;
					if (!((Object)(object)rigidbody == (Object)null))
					{
						float num2 = 9000f;
						float num3 = 100f;
						float num4 = 1f;
						Vector3 val3 = ((Component)rigidbody).transform.position + Vector3.down * 0.5f;
						rigidbody.AddExplosionForce(num2, val3, num3, num4, (ForceMode)1);
						Plugin.Log.LogInfo((object)"BOOM! Player flung by chat.");
					}
				}
			};
			ChatAction chatAction4 = new ChatAction
			{
				name = "Respawn Player",
				onChoose = delegate
				{
					GameManager.LocalPlayerMovement.TryBeginRespawn(false);
				}
			};
			ChatAction chatAction5 = new ChatAction
			{
				name = "Spawn 10 stacked golf carts",
				onChoose = delegate
				{
					//IL_0034: Unknown result type (might be due to invalid IL or missing references)
					//IL_0044: Unknown result type (might be due to invalid IL or missing references)
					//IL_0049: Unknown result type (might be due to invalid IL or missing references)
					//IL_004e: Unknown result type (might be due to invalid IL or missing references)
					//IL_0051: Unknown result type (might be due to invalid IL or missing references)
					//IL_005e: Unknown result type (might be due to invalid IL or missing references)
					//IL_006d: Unknown result type (might be due to invalid IL or missing references)
					//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
					if (NetworkServer.active)
					{
						PlayerInfo playerInfo = GameManager.LocalPlayerAsGolfer.PlayerInfo;
						GolfCartInfo prefab = GameManager.GolfCartSettings.Prefab;
						for (int j = 0; j < 10; j++)
						{
							float num = (float)j * 2.5f;
							Vector3 val = ((Component)playerInfo).transform.position + new Vector3(0f, num, 0f);
							GolfCartInfo val2 = Object.Instantiate<GolfCartInfo>(prefab, val, Quaternion.Euler(0f, ((Component)playerInfo).transform.eulerAngles.y, 0f));
							if (j == 0)
							{
								val2.ServerReserveDriverSeatPreNetworkSpawn(playerInfo);
								NetworkServer.Spawn(((Component)val2).gameObject, (NetworkConnectionToClient)null);
								val2.ServerReserveDriverSeatPostNetworkSpawn();
								val2.ServerEnter(playerInfo);
								Plugin.Log.LogInfo((object)"Spawned base cart and seated player.");
							}
							else
							{
								NetworkServer.Spawn(((Component)val2).gameObject, (NetworkConnectionToClient)null);
								Plugin.Log.LogInfo((object)$"Stacked cart {j + 1}/10 at height {val.y}");
							}
						}
					}
				}
			};
			ChatAction chatAction6 = new ChatAction
			{
				name = "Reset Ball",
				onChoose = delegate
				{
					GameManager.LocalPlayerAsGolfer.CmdRestartBall();
				}
			};
			ChatAction chatAction7 = new ChatAction
			{
				name = "Give 5 Strokes",
				onChoose = delegate
				{
					for (int i = 0; i < 5; i++)
					{
						CourseManager.AddPenaltyStroke(GameManager.LocalPlayerAsGolfer, false);
					}
				}
			};
			ChatAction chatAction8 = new ChatAction
			{
				name = "Dance for 5 seconds",
				onChoose = delegate
				{
					((MonoBehaviour)ChatAPI.instance).StartCoroutine(DanceSequence(5f));
				}
			};
			ChatAction chatAction9 = new ChatAction
			{
				name = "10s of inverted movements",
				onChoose = delegate
				{
					((MonoBehaviour)ChatAPI.instance).StartCoroutine(InvertedControls(10f));
				}
			};
			ChatAction chatAction10 = new ChatAction
			{
				name = "2x Slower for 10 seconds",
				onChoose = delegate
				{
					((MonoBehaviour)ChatAPI.instance).StartCoroutine(SuperSlow(10f));
				}
			};
			ChatAPI.instance.RegisterNewAction(chatAction);
			ChatAPI.instance.RegisterNewAction(chatAction2);
			ChatAPI.instance.RegisterNewAction(chatAction3);
			ChatAPI.instance.RegisterNewAction(chatAction4);
			ChatAPI.instance.RegisterNewAction(chatAction5);
			ChatAPI.instance.RegisterNewAction(chatAction6);
			ChatAPI.instance.RegisterNewAction(chatAction7);
			ChatAPI.instance.RegisterNewAction(chatAction8);
			ChatAPI.instance.RegisterNewAction(chatAction9);
			ChatAPI.instance.RegisterNewAction(chatAction10);
		}

		[IteratorStateMachine(typeof(<DanceSequence>d__1))]
		private static IEnumerator DanceSequence(float duration)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <DanceSequence>d__1(0)
			{
				duration = duration
			};
		}

		[IteratorStateMachine(typeof(<InvertedControls>d__2))]
		private static IEnumerator InvertedControls(float duration)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <InvertedControls>d__2(0)
			{
				duration = duration
			};
		}

		[IteratorStateMachine(typeof(<SuperSlow>d__3))]
		private static IEnumerator SuperSlow(float duration)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <SuperSlow>d__3(0)
			{
				duration = duration
			};
		}
	}
}
namespace System.Diagnostics.CodeAnalysis
{
	[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class ConstantExpectedAttribute : Attribute
	{
		public object? Min { get; set; }

		public object? Max { get; set; }
	}
	[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Interface | AttributeTargets.Delegate, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class ExperimentalAttribute : Attribute
	{
		public string DiagnosticId { get; }

		public string? UrlFormat { get; set; }

		public ExperimentalAttribute(string diagnosticId)
		{
			DiagnosticId = diagnosticId;
		}
	}
	[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)]
	[ExcludeFromCodeCoverage]
	internal sealed class MemberNotNullAttribute : Attribute
	{
		public string[] Members { get; }

		public MemberNotNullAttribute(string member)
		{
			Members = new string[1] { member };
		}

		public MemberNotNullAttribute(params string[] members)
		{
			Members = members;
		}
	}
	[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)]
	[ExcludeFromCodeCoverage]
	internal sealed class MemberNotNullWhenAttribute : Attribute
	{
		public bool ReturnValue { get; }

		public string[] Members { get; }

		public MemberNotNullWhenAttribute(bool returnValue, string member)
		{
			ReturnValue = returnValue;
			Members = new string[1] { member };
		}

		public MemberNotNullWhenAttribute(bool returnValue, params string[] members)
		{
			ReturnValue = returnValue;
			Members = members;
		}
	}
	[AttributeUsage(AttributeTargets.Constructor, AllowMultiple = false, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class SetsRequiredMembersAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class StringSyntaxAttribute : Attribute
	{
		public const string CompositeFormat = "CompositeFormat";

		public const string DateOnlyFormat = "DateOnlyFormat";

		public const string DateTimeFormat = "DateTimeFormat";

		public const string EnumFormat = "EnumFormat";

		public const string GuidFormat = "GuidFormat";

		public const string Json = "Json";

		public const string NumericFormat = "NumericFormat";

		public const string Regex = "Regex";

		public const string TimeOnlyFormat = "TimeOnlyFormat";

		public const string TimeSpanFormat = "TimeSpanFormat";

		public const string Uri = "Uri";

		public const string Xml = "Xml";

		public string Syntax { get; }

		public object?[] Arguments { get; }

		public StringSyntaxAttribute(string syntax)
		{
			Syntax = syntax;
			Arguments = new object[0];
		}

		public StringSyntaxAttribute(string syntax, params object?[] arguments)
		{
			Syntax = syntax;
			Arguments = arguments;
		}
	}
	[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class UnscopedRefAttribute : Attribute
	{
	}
}
namespace System.Runtime.Versioning
{
	[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Interface | AttributeTargets.Delegate, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class RequiresPreviewFeaturesAttribute : Attribute
	{
		public string? Message { get; }

		public string? Url { get; set; }

		public RequiresPreviewFeaturesAttribute()
		{
		}

		public RequiresPreviewFeaturesAttribute(string? message)
		{
			Message = message;
		}
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
	[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class CallerArgumentExpressionAttribute : Attribute
	{
		public string ParameterName { get; }

		public CallerArgumentExpressionAttribute(string parameterName)
		{
			ParameterName = parameterName;
		}
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class CollectionBuilderAttribute : Attribute
	{
		public Type BuilderType { get; }

		public string MethodName { get; }

		public CollectionBuilderAttribute(Type builderType, string methodName)
		{
			BuilderType = builderType;
			MethodName = methodName;
		}
	}
	[AttributeUsage(AttributeTargets.All, AllowMultiple = true, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class CompilerFeatureRequiredAttribute : Attribute
	{
		public const string RefStructs = "RefStructs";

		public const string RequiredMembers = "RequiredMembers";

		public string FeatureName { get; }

		public bool IsOptional { get; set; }

		public CompilerFeatureRequiredAttribute(string featureName)
		{
			FeatureName = featureName;
		}
	}
	[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class InterpolatedStringHandlerArgumentAttribute : Attribute
	{
		public string[] Arguments { get; }

		public InterpolatedStringHandlerArgumentAttribute(string argument)
		{
			Arguments = new string[1] { argument };
		}

		public InterpolatedStringHandlerArgumentAttribute(params string[] arguments)
		{
			Arguments = arguments;
		}
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class InterpolatedStringHandlerAttribute : Attribute
	{
	}
	[EditorBrowsable(EditorBrowsableState.Never)]
	[ExcludeFromCodeCoverage]
	internal static class IsExternalInit
	{
	}
	[AttributeUsage(AttributeTargets.Method, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class ModuleInitializerAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class OverloadResolutionPriorityAttribute : Attribute
	{
		public int Priority { get; }

		public OverloadResolutionPriorityAttribute(int priority)
		{
			Priority = priority;
		}
	}
	[AttributeUsage(AttributeTargets.Parameter, Inherited = true, AllowMultiple = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class ParamCollectionAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class RequiredMemberAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
	[EditorBrowsable(EditorBrowsableState.Never)]
	[ExcludeFromCodeCoverage]
	internal sealed class RequiresLocationAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Event | AttributeTargets.Interface, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class SkipLocalsInitAttribute : Attribute
	{
	}
}