Decompiled source of RiskOfChaos v2.3.1

patchers/RiskOfChaos/RiskOfChaosPatcher.dll

Decompiled 3 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx.Logging;
using Microsoft.CodeAnalysis;
using Mono.Cecil;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("RiskOfChaosPatcher")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+c158cf629270665c915140fc70b979c1b9cb1479")]
[assembly: AssemblyProduct("RiskOfChaosPatcher")]
[assembly: AssemblyTitle("RiskOfChaosPatcher")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace RiskOfChaosPatcher
{
	internal static class AssemblyNames
	{
		public const string RoR2 = "RoR2.dll";
	}
	internal class LogWriter
	{
		private ManualLogSource _logSource;

		public LogWriter(ManualLogSource logSource)
		{
			_logSource = logSource;
		}

		public LogWriter()
			: this(null)
		{
		}

		public void SetLogSource(ManualLogSource logSource)
		{
			_logSource = logSource;
		}

		public void Fatal(object message)
		{
			ManualLogSource logSource = _logSource;
			if (logSource != null)
			{
				logSource.LogFatal(message);
			}
		}

		public void Error(object message)
		{
			ManualLogSource logSource = _logSource;
			if (logSource != null)
			{
				logSource.LogError(message);
			}
		}

		public void Warning(object message)
		{
			ManualLogSource logSource = _logSource;
			if (logSource != null)
			{
				logSource.LogWarning(message);
			}
		}

		public void Message(object message)
		{
			ManualLogSource logSource = _logSource;
			if (logSource != null)
			{
				logSource.LogMessage(message);
			}
		}

		public void Info(object message)
		{
			ManualLogSource logSource = _logSource;
			if (logSource != null)
			{
				logSource.LogInfo(message);
			}
		}

		[Conditional("DEBUG")]
		public void Debug(object message)
		{
			ManualLogSource logSource = _logSource;
			if (logSource != null)
			{
				logSource.LogDebug(message);
			}
		}
	}
	public class ProjectilePatcher
	{
		private static readonly LogWriter _log = new LogWriter();

		public static IEnumerable<string> TargetDLLs { get; } = new <>z__ReadOnlySingleElementList<string>("RoR2.dll");


		public static void Initialize()
		{
			_log.SetLogSource(Logger.CreateLogSource("ProjectilePatcher"));
		}

		public static void Patch(AssemblyDefinition assembly)
		{
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Expected O, but got Unknown
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Expected O, but got Unknown
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Expected O, but got Unknown
			TypeDefinition type = assembly.MainModule.GetType("RoR2.Projectile.FireProjectileInfo");
			if (type == null)
			{
				_log.Error("Failed to find type: FireProjectileInfo");
				return;
			}
			TypeDefinition type2 = assembly.MainModule.GetType("RoR2.Projectile.ProjectileManager/PlayerFireProjectileMessage");
			if (type2 == null)
			{
				_log.Error("Failed to find type: PlayerFireProjectileMessage");
				return;
			}
			TypeDefinition type3 = assembly.MainModule.GetType("RoR2.ProcChainMask");
			if (type3 == null)
			{
				_log.Error("Failed to find type: ProcChainMask");
				return;
			}
			TypeReference val = assembly.MainModule.ImportReference(typeof(float));
			addField(type, new FieldDefinition("roc_procCoefficientOverridePlusOne", (FieldAttributes)6, val));
			addField(type2, new FieldDefinition("roc_procCoefficientOverridePlusOne", (FieldAttributes)6, val));
			addField(type2, new FieldDefinition("roc_procChainMask", (FieldAttributes)6, (TypeReference)(object)type3));
		}

		private static void addField(TypeDefinition declaringType, FieldDefinition field)
		{
			declaringType.Fields.Add(field);
		}
	}
}
internal sealed class <>z__ReadOnlySingleElementList<T> : IEnumerable, ICollection, IList, IEnumerable<T>, IReadOnlyCollection<T>, IReadOnlyList<T>, ICollection<T>, IList<T>
{
	private sealed class Enumerator : IDisposable, IEnumerator, IEnumerator<T>
	{
		object IEnumerator.Current => _item;

		T IEnumerator<T>.Current => _item;

		public Enumerator(T item)
		{
			_item = item;
		}

		bool IEnumerator.MoveNext()
		{
			if (!_moveNextCalled)
			{
				return _moveNextCalled = true;
			}
			return false;
		}

		void IEnumerator.Reset()
		{
			_moveNextCalled = false;
		}

		void IDisposable.Dispose()
		{
		}
	}

	int ICollection.Count => 1;

	bool ICollection.IsSynchronized => false;

	object ICollection.SyncRoot => this;

	object IList.this[int index]
	{
		get
		{
			if (index != 0)
			{
				throw new IndexOutOfRangeException();
			}
			return _item;
		}
		set
		{
			throw new NotSupportedException();
		}
	}

	bool IList.IsFixedSize => true;

	bool IList.IsReadOnly => true;

	int IReadOnlyCollection<T>.Count => 1;

	T IReadOnlyList<T>.this[int index]
	{
		get
		{
			if (index != 0)
			{
				throw new IndexOutOfRangeException();
			}
			return _item;
		}
	}

	int ICollection<T>.Count => 1;

	bool ICollection<T>.IsReadOnly => true;

	T IList<T>.this[int index]
	{
		get
		{
			if (index != 0)
			{
				throw new IndexOutOfRangeException();
			}
			return _item;
		}
		set
		{
			throw new NotSupportedException();
		}
	}

	public <>z__ReadOnlySingleElementList(T item)
	{
		_item = item;
	}

	IEnumerator IEnumerable.GetEnumerator()
	{
		return new Enumerator(_item);
	}

	void ICollection.CopyTo(Array array, int index)
	{
		array.SetValue(_item, index);
	}

	int IList.Add(object value)
	{
		throw new NotSupportedException();
	}

	void IList.Clear()
	{
		throw new NotSupportedException();
	}

	bool IList.Contains(object value)
	{
		return EqualityComparer<T>.Default.Equals(_item, (T)value);
	}

	int IList.IndexOf(object value)
	{
		if (!EqualityComparer<T>.Default.Equals(_item, (T)value))
		{
			return -1;
		}
		return 0;
	}

	void IList.Insert(int index, object value)
	{
		throw new NotSupportedException();
	}

	void IList.Remove(object value)
	{
		throw new NotSupportedException();
	}

	void IList.RemoveAt(int index)
	{
		throw new NotSupportedException();
	}

	IEnumerator<T> IEnumerable<T>.GetEnumerator()
	{
		return new Enumerator(_item);
	}

	void ICollection<T>.Add(T item)
	{
		throw new NotSupportedException();
	}

	void ICollection<T>.Clear()
	{
		throw new NotSupportedException();
	}

	bool ICollection<T>.Contains(T item)
	{
		return EqualityComparer<T>.Default.Equals(_item, item);
	}

	void ICollection<T>.CopyTo(T[] array, int arrayIndex)
	{
		array[arrayIndex] = _item;
	}

	bool ICollection<T>.Remove(T item)
	{
		throw new NotSupportedException();
	}

	int IList<T>.IndexOf(T item)
	{
		if (!EqualityComparer<T>.Default.Equals(_item, item))
		{
			return -1;
		}
		return 0;
	}

	void IList<T>.Insert(int index, T item)
	{
		throw new NotSupportedException();
	}

	void IList<T>.RemoveAt(int index)
	{
		throw new NotSupportedException();
	}
}

plugins/RiskOfChaos/RiskOfChaos.dll

Decompiled 3 days ago
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using EntityStates;
using EntityStates.Barrel;
using EntityStates.Captain.Weapon;
using EntityStates.Croco;
using EntityStates.GoldGat;
using EntityStates.GolemMonster;
using EntityStates.Interactables.GoldBeacon;
using EntityStates.Merc;
using EntityStates.VoidInfestor;
using HG;
using HG.Reflection;
using HarmonyLib;
using IL.EntityStates;
using IL.EntityStates.Bandit2.Weapon;
using IL.EntityStates.Geode;
using IL.EntityStates.GoldGat;
using IL.EntityStates.GolemMonster;
using IL.EntityStates.Merc;
using IL.EntityStates.Railgunner.Scope;
using IL.EntityStates.ShrineHalcyonite;
using IL.EntityStates.Toolbot;
using IL.EntityStates.VoidSurvivor.Weapon;
using IL.RoR2;
using IL.RoR2.CharacterAI;
using IL.RoR2.Items;
using IL.RoR2.Orbs;
using IL.RoR2.Projectile;
using IL.RoR2.Skills;
using IL.RoR2.UI;
using KinematicCharacterController;
using Microsoft.CodeAnalysis;
using Mono.Cecil;
using Mono.Cecil.Cil;
using Mono.Collections.Generic;
using MonoMod.Cil;
using MonoMod.RuntimeDetour;
using MonoMod.Utils;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
using On.RoR2;
using On.RoR2.CameraModes;
using On.RoR2.CharacterAI;
using On.RoR2.Orbs;
using On.RoR2.Projectile;
using On.RoR2.UI;
using On.RoR2.UI.LogBook;
using On.RoR2.UI.MainMenu;
using ProperSave;
using R2API;
using R2API.Networking;
using R2API.Networking.Interfaces;
using R2API.Utils;
using Rewired;
using Rewired.ComponentControls.Effects;
using RiskOfChaos.ChatMessages;
using RiskOfChaos.Collections;
using RiskOfChaos.Collections.CatalogIndex;
using RiskOfChaos.Collections.ParsedValue;
using RiskOfChaos.Components;
using RiskOfChaos.Components.CostProviders;
using RiskOfChaos.Components.MaterialInterpolation;
using RiskOfChaos.ConfigHandling;
using RiskOfChaos.ConfigHandling.AcceptableValues;
using RiskOfChaos.Content;
using RiskOfChaos.Content.AssetCollections;
using RiskOfChaos.Content.Logbook;
using RiskOfChaos.Content.Orbs;
using RiskOfChaos.EffectDefinitions;
using RiskOfChaos.EffectDefinitions.Character;
using RiskOfChaos.EffectDefinitions.Character.Equipment;
using RiskOfChaos.EffectDefinitions.UI;
using RiskOfChaos.EffectDefinitions.World;
using RiskOfChaos.EffectDefinitions.World.Items;
using RiskOfChaos.EffectDefinitions.World.Knockback;
using RiskOfChaos.EffectDefinitions.World.RunTimer;
using RiskOfChaos.EffectHandling;
using RiskOfChaos.EffectHandling.Controllers;
using RiskOfChaos.EffectHandling.Controllers.ChatVoting;
using RiskOfChaos.EffectHandling.Controllers.ChatVoting.Twitch;
using RiskOfChaos.EffectHandling.EffectClassAttributes;
using RiskOfChaos.EffectHandling.EffectClassAttributes.Data;
using RiskOfChaos.EffectHandling.EffectClassAttributes.Methods;
using RiskOfChaos.EffectHandling.EffectComponents;
using RiskOfChaos.EffectHandling.EffectComponents.SubtitleProviders;
using RiskOfChaos.EffectHandling.Formatting;
using RiskOfChaos.EffectUtils.Character.AllSkillsAgile;
using RiskOfChaos.EffectUtils.Character.Player.Items;
using RiskOfChaos.EffectUtils.World;
using RiskOfChaos.EffectUtils.World.AllChanceShrines;
using RiskOfChaos.EffectUtils.World.Items;
using RiskOfChaos.EffectUtils.World.Spawn;
using RiskOfChaos.ModCompatibility;
using RiskOfChaos.ModificationController;
using RiskOfChaos.ModificationController.AttackDelay;
using RiskOfChaos.ModificationController.Camera;
using RiskOfChaos.ModificationController.Cost;
using RiskOfChaos.ModificationController.Director;
using RiskOfChaos.ModificationController.Effect;
using RiskOfChaos.ModificationController.Gravity;
using RiskOfChaos.ModificationController.HoldoutZone;
using RiskOfChaos.ModificationController.Knockback;
using RiskOfChaos.ModificationController.Pickups;
using RiskOfChaos.ModificationController.Projectile;
using RiskOfChaos.ModificationController.SkillSlots;
using RiskOfChaos.ModificationController.TimeScale;
using RiskOfChaos.ModificationController.UI;
using RiskOfChaos.Networking;
using RiskOfChaos.Networking.Components;
using RiskOfChaos.Networking.SyncList;
using RiskOfChaos.Patches;
using RiskOfChaos.Patches.AttackHooks;
using RiskOfChaos.SaveHandling;
using RiskOfChaos.SaveHandling.DataContainers;
using RiskOfChaos.SaveHandling.DataContainers.EffectHandlerControllers;
using RiskOfChaos.ScreenEffect;
using RiskOfChaos.Serialization.Converters;
using RiskOfChaos.Trackers;
using RiskOfChaos.Twitch;
using RiskOfChaos.UI.ActiveEffectsPanel;
using RiskOfChaos.UI.ChatVoting;
using RiskOfChaos.UI.NextEffectDisplay;
using RiskOfChaos.Utilities;
using RiskOfChaos.Utilities.Assets;
using RiskOfChaos.Utilities.BodySnapshots;
using RiskOfChaos.Utilities.Comparers;
using RiskOfChaos.Utilities.DropTables;
using RiskOfChaos.Utilities.Extensions;
using RiskOfChaos.Utilities.Interpolation;
using RiskOfChaos.Utilities.ParsedValueHolders;
using RiskOfChaos.Utilities.PersistentSaveData;
using RiskOfChaos.Utilities.Pickup;
using RiskOfChaos.Utilities.Pool;
using RiskOfChaos.Utilities.Reflection;
using RiskOfChaos_PatcherInterop;
using RiskOfOptions;
using RiskOfOptions.OptionConfigs;
using RiskOfOptions.Options;
using RiskOfTwitch;
using RiskOfTwitch.Chat.Message;
using RiskOfTwitch.Chat.Notification;
using RiskOfTwitch.EventSub;
using RiskOfTwitch.Logging;
using RiskOfTwitch.User;
using RoR2;
using RoR2.Artifacts;
using RoR2.CameraModes;
using RoR2.CharacterAI;
using RoR2.ConVar;
using RoR2.ContentManagement;
using RoR2.ExpansionManagement;
using RoR2.Hologram;
using RoR2.Items;
using RoR2.Navigation;
using RoR2.Networking;
using RoR2.Orbs;
using RoR2.Projectile;
using RoR2.Skills;
using RoR2.Stats;
using RoR2.UI;
using RoR2.UI.LogBook;
using RoR2.UI.MainMenu;
using RoR2.UI.SkinControllers;
using RoR2BepInExPack.Utilities;
using TMPro;
using Unity;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.Networking;
using UnityEngine.ResourceManagement.AsyncOperations;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: NetworkCompatibility(/*Could not decode attribute arguments.*/)]
[assembly: OptIn]
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyInformationalVersion("1.0.0+0bc92c17cfeb39ad8e315081998979773a7d698c")]
[assembly: AssemblyProduct("RiskOfChaos")]
[assembly: AssemblyTitle("RiskOfChaos")]
[assembly: AssemblyCompany("RiskOfChaos")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("2.0.0")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("2.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	[Microsoft.CodeAnalysis.Embedded]
	[CompilerGenerated]
	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;
		}
	}
	[Microsoft.CodeAnalysis.Embedded]
	[CompilerGenerated]
	[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;
		}
	}
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
	internal sealed class IsExternalInit
	{
	}
}
namespace RiskOfChaos
{
	public static class Configs
	{
		public static class ChatVoting
		{
			public enum ChatVotingMode
			{
				Disabled,
				Twitch
			}

			[CompilerGenerated]
			private static class <>O
			{
				public static UnityAction <0>__AuthenticateNewToken;
			}

			[Serializable]
			[CompilerGenerated]
			private sealed class <>c
			{
				public static readonly <>c <>9 = new <>c();

				public static UnityAction <>9__12_1;

				internal void <Bind>b__12_1()
				{
					ChatVoting.OnReconnectButtonPressed?.Invoke();
				}
			}

			public const string SECTION_NAME = "Streamer Integration";

			public static readonly ConfigHolder<ChatVotingMode> VotingMode = ConfigFactory<ChatVotingMode>.CreateConfig("Voting Mode", ChatVotingMode.Disabled).OptionConfig((BaseOptionConfig)new ChoiceConfig()).Build();

			public static readonly ConfigHolder<string> OverrideChannelName = ConfigFactory<string>.CreateConfig("Override Channel Name", string.Empty).Description("Used to specify a different channel the mod will connect to, leave empty to use the channel of the account that you authenticated with").OptionConfig((BaseOptionConfig)new InputFieldConfig
			{
				lineType = (LineType)0,
				richText = false,
				submitOn = (SubmitEnum)6,
				checkIfDisabled = new IsDisabledDelegate(isVotingDisabled)
			})
				.Build();

			private const int NUM_EFFECT_OPTIONS_MIN_VALUE = 2;

			public static readonly ConfigHolder<int> NumEffectOptions;

			public static readonly ConfigHolder<bool> IncludeRandomEffectInVote;

			public static readonly ConfigHolder<VoteWinnerSelectionMode> WinnerSelectionMode;

			public static event Action OnReconnectButtonPressed;

			[MethodImpl(MethodImplOptions.AggressiveInlining)]
			private static bool isVotingDisabled()
			{
				return VotingMode.Value == ChatVotingMode.Disabled;
			}

			internal static void Bind(ConfigFile file)
			{
				//IL_0043: Unknown result type (might be due to invalid IL or missing references)
				//IL_0057: Expected O, but got Unknown
				//IL_0038: 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_0043: Expected O, but got Unknown
				//IL_0096: Unknown result type (might be due to invalid IL or missing references)
				//IL_00aa: Expected O, but got Unknown
				//IL_008b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0090: Unknown result type (might be due to invalid IL or missing references)
				//IL_0096: Expected O, but got Unknown
				bindConfig(VotingMode);
				object obj = <>O.<0>__AuthenticateNewToken;
				if (obj == null)
				{
					UnityAction val = TwitchAuthenticationManager.AuthenticateNewToken;
					<>O.<0>__AuthenticateNewToken = val;
					obj = (object)val;
				}
				ModSettingsManager.AddOption((BaseOption)new GenericButtonOption("Authenticate (Twitch)", "Streamer Integration", "Authenticate your account with Risk of Chaos (Opens browser tab)", "Open", (UnityAction)obj), "RoC_Config_General", "Risk of Chaos: General");
				bindConfig(OverrideChannelName);
				object obj2 = <>c.<>9__12_1;
				if (obj2 == null)
				{
					UnityAction val2 = delegate
					{
						ChatVoting.OnReconnectButtonPressed?.Invoke();
					};
					<>c.<>9__12_1 = val2;
					obj2 = (object)val2;
				}
				ModSettingsManager.AddOption((BaseOption)new GenericButtonOption("Manual reconnect", "Streamer Integration", "Use this to manually reconnect the mod to your channel if connection is lost", "Reconnect", (UnityAction)obj2), "RoC_Config_General", "Risk of Chaos: General");
				bindConfig(NumEffectOptions);
				bindConfig(IncludeRandomEffectInVote);
				bindConfig(WinnerSelectionMode);
				void bindConfig(ConfigHolderBase configHolder)
				{
					configHolder.Bind(file, "Streamer Integration", "RoC_Config_General", "Risk of Chaos: General");
				}
			}

			static ChatVoting()
			{
				//IL_000b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0015: Expected O, but got Unknown
				//IL_0038: 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_003f: 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_004b: Unknown result type (might be due to invalid IL or missing references)
				//IL_004d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0052: Unknown result type (might be due to invalid IL or missing references)
				//IL_005a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0064: Expected O, but got Unknown
				//IL_0069: Expected O, but got Unknown
				//IL_0093: Unknown result type (might be due to invalid IL or missing references)
				//IL_0098: Unknown result type (might be due to invalid IL or missing references)
				//IL_009f: Expected O, but got Unknown
				//IL_009f: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
				//IL_00b1: Expected O, but got Unknown
				//IL_00b6: Expected O, but got Unknown
				//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
				//IL_00da: Unknown result type (might be due to invalid IL or missing references)
				//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ec: Expected O, but got Unknown
				//IL_00f1: Expected O, but got Unknown
				//IL_0110: Unknown result type (might be due to invalid IL or missing references)
				//IL_0115: Unknown result type (might be due to invalid IL or missing references)
				//IL_011d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0127: Expected O, but got Unknown
				//IL_012c: Expected O, but got Unknown
				ConfigFactory<int> configFactory = ConfigFactory<int>.CreateConfig("Num Effect Options", 3).Description("The number of effects viewers can pick from during voting").AcceptableValues((AcceptableValueBase)(object)new AcceptableValueMin<int>(2));
				IntFieldConfig val = new IntFieldConfig();
				((NumericFieldConfig<int>)val).Min = 2;
				((BaseOptionConfig)val).checkIfDisabled = new IsDisabledDelegate(isVotingDisabled);
				NumEffectOptions = configFactory.OptionConfig((BaseOptionConfig)val).Build();
				IncludeRandomEffectInVote = ConfigFactory<bool>.CreateConfig("Include Random Effect In Vote", defaultValue: true).Description("If this is enabled, an additional option will be added to the effect vote list, which will activate a random effect instead of a specific one").OptionConfig((BaseOptionConfig)new CheckBoxConfig
				{
					checkIfDisabled = new IsDisabledDelegate(isVotingDisabled)
				})
					.Build();
				WinnerSelectionMode = ConfigFactory<VoteWinnerSelectionMode>.CreateConfig("Vote Winner Selection Mode", VoteWinnerSelectionMode.MostVotes).Description("How the winner of any vote should be selected.\r\n\r\nMostVotes (Default): The vote with the most votes will be selected, if there is a tie, a random tied option is selected\r\nRandomProportional: Every option has a chance to be selected, weighted by the number of votes. Ex. an option with 70% of the votes will have a 70% chance to be selected.").OptionConfig((BaseOptionConfig)new ChoiceConfig
				{
					checkIfDisabled = new IsDisabledDelegate(isVotingDisabled)
				})
					.Build();
			}
		}

		public static class ChatVotingUI
		{
			public enum VoteDisplayScalingMode
			{
				Disabled,
				Smooth,
				Immediate
			}

			public const string SECTION_NAME = "Streamer Integration: UI";

			public static readonly ConfigHolder<float> VoteDisplayScaleMultiplier;

			public static readonly ConfigHolder<Color> VoteDisplayTextColor;

			public static readonly ConfigHolder<Color> VoteDisplayBackgroundColor;

			public static readonly ConfigHolder<VoteDisplayScalingMode> VoteDisplayScalingModeConfig;

			internal static void Bind(ConfigFile file)
			{
				bindConfig(VoteDisplayScaleMultiplier);
				bindConfig(VoteDisplayTextColor);
				bindConfig(VoteDisplayBackgroundColor);
				bindConfig(VoteDisplayScalingModeConfig);
				void bindConfig(ConfigHolderBase configHolder)
				{
					configHolder.Bind(file, "Streamer Integration: UI", "RoC_Config_General", "Risk of Chaos: General");
				}
			}

			static ChatVotingUI()
			{
				//IL_0028: Unknown result type (might be due to invalid IL or missing references)
				//IL_002d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0038: Expected O, but got Unknown
				//IL_0038: Unknown result type (might be due to invalid IL or missing references)
				//IL_0043: Expected O, but got Unknown
				//IL_0048: Expected O, but got Unknown
				//IL_0075: Unknown result type (might be due to invalid IL or missing references)
				//IL_0089: Unknown result type (might be due to invalid IL or missing references)
				//IL_0093: Expected O, but got Unknown
				//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
				//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
				//IL_00de: Expected O, but got Unknown
				//IL_0107: Unknown result type (might be due to invalid IL or missing references)
				//IL_0111: Expected O, but got Unknown
				ConfigFactory<float> configFactory = ConfigFactory<float>.CreateConfig("Vote Display UI Scale", 1f).Description("The scale multiplier of the effect vote options display").AcceptableValues((AcceptableValueBase)(object)new AcceptableValueMin<float>(0f));
				FloatFieldConfig val = new FloatFieldConfig();
				((NumericFieldConfig<float>)val).FormatString = "{0}X";
				((NumericFieldConfig<float>)val).Min = 0f;
				VoteDisplayScaleMultiplier = configFactory.OptionConfig((BaseOptionConfig)val).MovedFrom("Streamer Integration").Build();
				VoteDisplayTextColor = ConfigFactory<Color>.CreateConfig("Vote Display Text Color", new Color(1f, 1f, 1f, 1f)).Description("The color of the effect voting options text").OptionConfig((BaseOptionConfig)new ColorOptionConfig())
					.MovedFrom("Streamer Integration")
					.Build();
				VoteDisplayBackgroundColor = ConfigFactory<Color>.CreateConfig("Vote Display Background Color", new Color(0.0943f, 0.0943f, 0.0943f, 0.3373f)).Description("The color of the effect voting options backdrop").OptionConfig((BaseOptionConfig)new ColorOptionConfig())
					.MovedFrom("Streamer Integration")
					.Build();
				VoteDisplayScalingModeConfig = ConfigFactory<VoteDisplayScalingMode>.CreateConfig("Vote Display Text Scaling Mode", VoteDisplayScalingMode.Smooth).Description("Controls how the vote options text will be scaled depending on how many votes that option has\r\n\r\nDisabled: No scaling is done, all options are always displayed exactly the same\r\n\r\nSmooth: Scaling is done, and interpolated to smoothly approach the target scale\r\n\r\nImmediate: Scaling is done, and applied immediately instead of smoothly interpolating").OptionConfig((BaseOptionConfig)new ChoiceConfig())
					.Build();
			}
		}

		public static class EffectSelection
		{
			[CompilerGenerated]
			private static class <>O
			{
				public static IsDisabledDelegate <0>__perStageEffectListDisabled;
			}

			public const string SECTION_NAME = "Effect Selection";

			public static readonly ConfigHolder<bool> SeededEffectSelection = ConfigFactory<bool>.CreateConfig("Seeded Effect Selection", defaultValue: false).Description("If the effects should be consistent with the run seed, only really changes anything if you're setting run seeds manually").OptionConfig((BaseOptionConfig)new CheckBoxConfig())
				.MovedFrom("General")
				.Build();

			public static readonly ConfigHolder<bool> PerStageEffectListEnabled = ConfigFactory<bool>.CreateConfig("Per-Stage Effect List", defaultValue: false).Description("If enabled, a subsection of all effects is generated each stage and only effects from this list are activated.\r\nNot supported in any chat voting mode").OptionConfig((BaseOptionConfig)new CheckBoxConfig())
				.Build();

			public static ConfigHolder<int> PerStageEffectListSize { get; private set; }

			private static bool perStageEffectListDisabled()
			{
				return !PerStageEffectListEnabled.Value;
			}

			internal static void Bind(ConfigFile file)
			{
				bindConfig(SeededEffectSelection);
				bindConfig(PerStageEffectListEnabled);
				((ResourceAvailability)(ref ChaosEffectCatalog.Availability)).CallWhenAvailable((Action)delegate
				{
					//IL_0026: Unknown result type (might be due to invalid IL or missing references)
					//IL_002b: 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_003d: Unknown result type (might be due to invalid IL or missing references)
					//IL_0063: Expected O, but got Unknown
					//IL_004e: Unknown result type (might be due to invalid IL or missing references)
					//IL_0053: Unknown result type (might be due to invalid IL or missing references)
					//IL_0059: Expected O, but got Unknown
					ConfigFactory<int> configFactory = ConfigFactory<int>.CreateConfig("Effect List Size", 50).Description("The size of the per-stage effect list\r\nNot supported in any chat voting mode").AcceptableValues((AcceptableValueBase)(object)new AcceptableValueRange<int>(1, ChaosEffectCatalog.EffectCount));
					IntSliderConfig val = new IntSliderConfig
					{
						min = 1,
						max = ChaosEffectCatalog.EffectCount
					};
					object obj = <>O.<0>__perStageEffectListDisabled;
					if (obj == null)
					{
						IsDisabledDelegate val2 = perStageEffectListDisabled;
						<>O.<0>__perStageEffectListDisabled = val2;
						obj = (object)val2;
					}
					((BaseOptionConfig)val).checkIfDisabled = (IsDisabledDelegate)obj;
					PerStageEffectListSize = configFactory.OptionConfig((BaseOptionConfig)val).Build();
					bindConfig(PerStageEffectListSize);
				});
				void bindConfig(ConfigHolderBase config)
				{
					config.Bind(file, "Effect Selection", "RoC_Config_General", "Risk of Chaos: General");
				}
			}
		}

		public static class General
		{
			public const string SECTION_NAME = "General";

			public static readonly ConfigHolder<bool> DisableEffectDispatching = ConfigFactory<bool>.CreateConfig("Disable Effect Activation", defaultValue: false).Description("If effect activation should be disabled completely").OptionConfig((BaseOptionConfig)new CheckBoxConfig())
				.Networked()
				.Build();

			private const float TIME_BETWEEN_EFFECTS_MIN_VALUE = 5f;

			public static readonly ConfigHolder<float> TimeBetweenEffects;

			public static readonly ConfigHolder<bool> RunEffectsTimerWhileRunTimerPaused;

			private static bool effectDispatchingDisabled()
			{
				return DisableEffectDispatching.LocalValue;
			}

			internal static void Bind(ConfigFile file)
			{
				bindConfig(DisableEffectDispatching);
				bindConfig(TimeBetweenEffects);
				bindConfig(RunEffectsTimerWhileRunTimerPaused);
				void bindConfig(ConfigHolderBase config)
				{
					config.Bind(file, "General", "RoC_Config_General", "Risk of Chaos: General");
				}
			}

			static General()
			{
				//IL_0015: Unknown result type (might be due to invalid IL or missing references)
				//IL_001f: Expected O, but got Unknown
				//IL_0056: Unknown result type (might be due to invalid IL or missing references)
				//IL_005b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0066: Expected O, but got Unknown
				//IL_0066: Unknown result type (might be due to invalid IL or missing references)
				//IL_0071: Expected O, but got Unknown
				//IL_0071: Unknown result type (might be due to invalid IL or missing references)
				//IL_0079: Unknown result type (might be due to invalid IL or missing references)
				//IL_0083: Expected O, but got Unknown
				//IL_0088: Expected O, but got Unknown
				//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ac: 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_00be: Expected O, but got Unknown
				//IL_00c3: Expected O, but got Unknown
				ConfigFactory<float> configFactory = ConfigFactory<float>.CreateConfig("Effect Timer", 60f).Description("How often new effects should happen").AcceptableValues((AcceptableValueBase)(object)new AcceptableValueMin<float>(5f));
				FloatFieldConfig val = new FloatFieldConfig();
				((NumericFieldConfig<float>)val).FormatString = "{0}s";
				((NumericFieldConfig<float>)val).Min = 5f;
				((BaseOptionConfig)val).checkIfDisabled = new IsDisabledDelegate(effectDispatchingDisabled);
				TimeBetweenEffects = configFactory.OptionConfig((BaseOptionConfig)val).Build();
				RunEffectsTimerWhileRunTimerPaused = ConfigFactory<bool>.CreateConfig("Dispatch Effects While Timer Paused", defaultValue: true).Description("If the mod should activate effects while the run timer is paused (in Bazaar, Gilded Coast, etc.)").OptionConfig((BaseOptionConfig)new CheckBoxConfig
				{
					checkIfDisabled = new IsDisabledDelegate(effectDispatchingDisabled)
				})
					.Networked()
					.Build();
			}
		}

		internal static class Metadata
		{
			public const string SECTION_NAME = "META";

			public const uint CONFIG_FILE_VERSION_LEGACY = 0u;

			public const uint CURRENT_CONFIG_FILE_VERSION = 10u;

			public static ConfigHolder<uint> ConfigFileVersion = ConfigFactory<uint>.CreateConfig("VERSION", 0u).Description("Used internally by the mod\r\nDO NOT MODIFY MANUALLY").Build();

			internal static void Bind(ConfigFile file)
			{
				bindConfig(ConfigFileVersion);
				void bindConfig(ConfigHolderBase config)
				{
					config.Bind(file, "META", "RoC_Config_General", "Risk of Chaos: General");
				}
			}

			private static bool isOutdatedVersion()
			{
				if (ConfigFileVersion.Value < 10)
				{
					return ConfigManager.AllConfigs.Any((ConfigHolderBase c) => !c.IsDefaultValue);
				}
				return false;
			}

			internal static void CheckVersion()
			{
				if (isOutdatedVersion())
				{
					PopupAlertQueue.EnqueueAlert(delegate(SimpleDialogBox dialogBox)
					{
						//IL_000b: 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)
						dialogBox.headerToken = new TokenParamsPair("POPUP_CONFIG_UPDATE_HEADER", Array.Empty<object>());
						dialogBox.descriptionToken = new TokenParamsPair("POPUP_CONFIG_UPDATE_DESCRIPTION", Array.Empty<object>());
						dialogBox.AddCommandButton("roc_delete_config", "POPUP_CONFIG_UPDATE_RESET", Array.Empty<object>());
						dialogBox.AddCancelButton("POPUP_CONFIG_UPDATE_IGNORE", Array.Empty<object>());
					});
				}
				ConfigFileVersion.LocalValue = 10u;
			}
		}

		public static class UI
		{
			public enum NextEffectTimerDisplayType : byte
			{
				Never,
				WhenRunTimerUnavailable,
				Always
			}

			public const string SECTION_NAME = "UI";

			public static readonly ConfigHolder<bool> HideActiveEffectsPanel = ConfigFactory<bool>.CreateConfig("Hide Active Effects Panel", defaultValue: false).Description("Hides the active effects list under the Objectives display").OptionConfig((BaseOptionConfig)new CheckBoxConfig())
				.Build();

			public static readonly ConfigHolder<bool> DisplayAlwaysActiveEffects = ConfigFactory<bool>.CreateConfig("Display Permanently Active Effects", defaultValue: false).Description("If effects configured to always be active should be displayed in the active effects panel").OptionConfig((BaseOptionConfig)new CheckBoxConfig
			{
				checkIfDisabled = new IsDisabledDelegate(activeEffectsPanelHidden)
			})
				.Build();

			public static readonly ConfigHolder<Color> ActiveEffectsTextColor = ConfigFactory<Color>.CreateConfig("Active Effect Text Color", Color.white).Description("The color of the effect names in the \"Active Effects\" list").OptionConfig((BaseOptionConfig)new ColorOptionConfig
			{
				checkIfDisabled = new IsDisabledDelegate(activeEffectsPanelHidden)
			})
				.MovedFrom("General")
				.Build();

			public static readonly ConfigHolder<bool> DisplayNextEffect = ConfigFactory<bool>.CreateConfig("Display Next Effect", defaultValue: true).Description("Displays the next effect that will happen.\r\nOnly works if chat voting is disabled and seeded mode is enabled").OptionConfig((BaseOptionConfig)new CheckBoxConfig())
				.Build();

			public static readonly ConfigHolder<NextEffectTimerDisplayType> NextEffectTimerDisplayMode = ConfigFactory<NextEffectTimerDisplayType>.CreateConfig("Next Effect Timer Display Mode", NextEffectTimerDisplayType.WhenRunTimerUnavailable).Description("Displays how much time is left until the next effect.\r\n\r\nNever: The time remaining is never displayed.\r\nWhenRunTimerUnavailable: Displays time remaining only when the regular run timer is paused or otherwise not visible.\r\nAlways: Time remaining is always displayed").OptionConfig((BaseOptionConfig)new ChoiceConfig())
				.Build();

			private static bool activeEffectsPanelHidden()
			{
				return HideActiveEffectsPanel.Value;
			}

			public static bool ShouldShowNextEffectTimer(HUD hud)
			{
				switch (NextEffectTimerDisplayMode.Value)
				{
				case NextEffectTimerDisplayType.Never:
					return false;
				case NextEffectTimerDisplayType.WhenRunTimerUnavailable:
				{
					Run instance = Run.instance;
					if (Object.op_Implicit((Object)(object)instance))
					{
						if (!instance.isRunStopwatchPaused || !General.RunEffectsTimerWhileRunTimerPaused.Value)
						{
							return !RunTimerUITracker.IsAnyTimerVisibleForHUD(hud);
						}
						return true;
					}
					return false;
				}
				case NextEffectTimerDisplayType.Always:
					return true;
				default:
					throw new NotImplementedException();
				}
			}

			internal static void Bind(ConfigFile file)
			{
				bindConfig(HideActiveEffectsPanel);
				bindConfig(DisplayAlwaysActiveEffects);
				bindConfig(ActiveEffectsTextColor);
				bindConfig(DisplayNextEffect);
				bindConfig(NextEffectTimerDisplayMode);
				void bindConfig(ConfigHolderBase config)
				{
					config.Bind(file, "UI", "RoC_Config_General", "Risk of Chaos: General");
				}
			}
		}

		private const string CONFIG_GUID = "RoC_Config_General";

		private const string CONFIG_NAME = "Risk of Chaos: General";

		public static Sprite GenericIcon { get; private set; }

		private static void findIcon()
		{
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Expected O, but got Unknown
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			FileInfo fileInfo = null;
			DirectoryInfo directoryInfo = new DirectoryInfo(Main.ModDirectory);
			do
			{
				FileInfo[] files = directoryInfo.GetFiles("icon.png", SearchOption.TopDirectoryOnly);
				if (files != null && files.Length != 0)
				{
					fileInfo = files[0];
					break;
				}
				directoryInfo = directoryInfo.Parent;
			}
			while (directoryInfo != null && !string.Equals(directoryInfo.Name, "plugins", StringComparison.OrdinalIgnoreCase));
			if (fileInfo != null)
			{
				Texture2D val = new Texture2D(256, 256);
				((Object)val).name = "texRiskOfChaosIcon";
				if (ImageConversion.LoadImage(val, File.ReadAllBytes(fileInfo.FullName)))
				{
					GenericIcon = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f));
					((Object)GenericIcon).name = "RiskOfChaosIcon";
				}
			}
			if (!Object.op_Implicit((Object)(object)GenericIcon))
			{
				Log.Error("Failed to load config icon", "D:\\Git\\RiskOfChaos\\Solution\\RiskOfChaos\\Config\\Configs.cs", "findIcon", 47);
			}
		}

		internal static void Init(ConfigFile file)
		{
			General.Bind(file);
			EffectSelection.Bind(file);
			UI.Bind(file);
			ChatVoting.Bind(file);
			ChatVotingUI.Bind(file);
			Metadata.Bind(file);
			findIcon();
			if (Object.op_Implicit((Object)(object)GenericIcon))
			{
				ModSettingsManager.SetModIcon(GenericIcon, "RoC_Config_General", "Risk of Chaos: General");
			}
			ModSettingsManager.SetModDescription("General config options for Risk of Chaos", "RoC_Config_General", "Risk of Chaos: General");
		}
	}
	internal static class LanguageFileHandler
	{
		internal static void Init()
		{
			Language.collectLanguageRootFolders += delegate(List<string> folders)
			{
				string text = Path.Combine(Main.ModDirectory, "lang");
				if (Directory.Exists(text))
				{
					folders.Add(text);
				}
				else
				{
					Log.Warning("Unable to find lang folder at " + text, "D:\\Git\\RiskOfChaos\\Solution\\RiskOfChaos\\LanguageFileHandler.cs", "Init", 20);
				}
			};
		}
	}
	internal static class Log
	{
		private static readonly object _stringBuilderLock;

		private static readonly StringBuilder _sharedStringBuilder;

		private static readonly int _cachedCallerPathPrefixLength;

		private static ManualLogSource _logSource;

		static Log()
		{
			_stringBuilderLock = new object();
			_sharedStringBuilder = new StringBuilder(256);
			_cachedCallerPathPrefixLength = getCallerPathPrefixLength("D:\\Git\\RiskOfChaos\\Solution\\RiskOfChaos\\Log.cs");
			static int getCallerPathPrefixLength([CallerFilePath] string callerPath = null)
			{
				int num = callerPath.LastIndexOf("RiskOfChaos\\");
				if (num >= 0)
				{
					return num + "RiskOfChaos\\".Length;
				}
				Debug.LogError((object)"[RiskOfChaos] Logger failed to determine caller path prefix length");
				return 0;
			}
		}

		internal static void Init(ManualLogSource logSource)
		{
			_logSource = logSource;
		}

		private static StringBuilder AppendCallerPrefix(this StringBuilder stringBuilder, string callerPath, string callerMemberName, int callerLineNumber)
		{
			return stringBuilder.Append(callerPath, _cachedCallerPathPrefixLength, callerPath.Length - _cachedCallerPathPrefixLength).Append(':').Append(callerLineNumber)
				.Append(" (")
				.Append(callerMemberName)
				.Append("):");
		}

		private static StringBuilder buildCallerLogString(string callerPath, string callerMemberName, int callerLineNumber, object data)
		{
			lock (_stringBuilderLock)
			{
				return _sharedStringBuilder.Clear().AppendCallerPrefix(callerPath, callerMemberName, callerLineNumber).Append(' ')
					.Append(data);
			}
		}

		[Conditional("DEBUG")]
		internal static void Debug(object data, [CallerFilePath] string callerPath = "", [CallerMemberName] string callerMemberName = "", [CallerLineNumber] int callerLineNumber = -1)
		{
			_logSource.LogDebug((object)buildCallerLogString(callerPath, callerMemberName, callerLineNumber, data));
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		[Conditional("DEBUG")]
		internal static void Debug_NoCallerPrefix(object data)
		{
			_logSource.LogDebug(data);
		}

		internal static void Error(object data, [CallerFilePath] string callerPath = "", [CallerMemberName] string callerMemberName = "", [CallerLineNumber] int callerLineNumber = -1)
		{
			_logSource.LogError((object)buildCallerLogString(callerPath, callerMemberName, callerLineNumber, data));
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		internal static void Error_NoCallerPrefix(object data)
		{
			_logSource.LogError(data);
		}

		internal static void Fatal(object data, [CallerFilePath] string callerPath = "", [CallerMemberName] string callerMemberName = "", [CallerLineNumber] int callerLineNumber = -1)
		{
			_logSource.LogFatal((object)buildCallerLogString(callerPath, callerMemberName, callerLineNumber, data));
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		internal static void Fatal_NoCallerPrefix(object data)
		{
			_logSource.LogFatal(data);
		}

		internal static void Info(object data, [CallerFilePath] string callerPath = "", [CallerMemberName] string callerMemberName = "", [CallerLineNumber] int callerLineNumber = -1)
		{
			_logSource.LogInfo((object)buildCallerLogString(callerPath, callerMemberName, callerLineNumber, data));
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		internal static void Info_NoCallerPrefix(object data)
		{
			_logSource.LogInfo(data);
		}

		internal static void Message(object data, [CallerFilePath] string callerPath = "", [CallerMemberName] string callerMemberName = "", [CallerLineNumber] int callerLineNumber = -1)
		{
			_logSource.LogMessage((object)buildCallerLogString(callerPath, callerMemberName, callerLineNumber, data));
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		internal static void Message_NoCallerPrefix(object data)
		{
			_logSource.LogMessage(data);
		}

		internal static void Warning(object data, [CallerFilePath] string callerPath = "", [CallerMemberName] string callerMemberName = "", [CallerLineNumber] int callerLineNumber = -1)
		{
			_logSource.LogWarning((object)buildCallerLogString(callerPath, callerMemberName, callerLineNumber, data));
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		internal static void Warning_NoCallerPrefix(object data)
		{
			_logSource.LogWarning(data);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		internal static bool ShouldLog(LogLevel logLevel)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Invalid comparison between Unknown and I4
			if ((logLevel & 0x20) != 0)
			{
				return false;
			}
			return (int)logLevel > 0;
		}

		internal static void LogType(LogLevel logLevel, object data)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			if (ShouldLog(logLevel))
			{
				_logSource.Log(logLevel, data);
			}
		}
	}
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInPlugin("Gorakh.RiskOfChaos", "RiskOfChaos", "2.3.1")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Main : BaseUnityPlugin
	{
		public const string PluginGUID = "Gorakh.RiskOfChaos";

		public const string PluginAuthor = "Gorakh";

		public const string PluginName = "RiskOfChaos";

		public const string PluginVersion = "2.3.1";

		private Harmony _harmonyInstance;

		private static Main _instance;

		public static Main Instance => _instance;

		public static string ModDirectory { get; private set; }

		public RoCContent ContentPackProvider { get; private set; }

		private void Awake()
		{
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Expected O, but got Unknown
			SingletonHelper.Assign<Main>(ref _instance, this);
			Stopwatch stopwatch = Stopwatch.StartNew();
			Log.Init(((BaseUnityPlugin)this).Logger);
			TaskExceptionHandler.Initialize();
			Log.LogSource = (ILogSource)(object)new TwitchLibLogSource();
			ModDirectory = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location);
			ContentPackProvider = new RoCContent();
			ContentPackProvider.Register();
			LanguageFileHandler.Init();
			NetworkMessageManager.RegisterMessages();
			AdditionalResourceAvailability.InitHooks();
			if (ProperSaveCompat.Active)
			{
				ProperSaveCompat.Init();
			}
			_harmonyInstance = new Harmony("com.Gorakh.RiskOfChaos");
			_harmonyInstance.PatchAll(Assembly.GetExecutingAssembly());
			initConfigs();
			Log.Message_NoCallerPrefix($"Initialized in {stopwatch.Elapsed.TotalSeconds:F2} seconds");
			stopwatch.Stop();
		}

		private void initConfigs()
		{
			((BaseUnityPlugin)this).Config.SaveOnConfigSet = false;
			Configs.Init(((BaseUnityPlugin)this).Config);
			ChaosEffectCatalog.InitConfig(((BaseUnityPlugin)this).Config);
			RoR2Application.onLoad = (Action)Delegate.Combine(RoR2Application.onLoad, (Action)delegate
			{
				((BaseUnityPlugin)this).Config.SaveOnConfigSet = true;
				((BaseUnityPlugin)this).Config.Save();
				Configs.Metadata.CheckVersion();
			});
		}

		private void OnDestroy()
		{
			SingletonHelper.Unassign<Main>(ref _instance, this);
			TaskExceptionHandler.Cleanup();
			if (ProperSaveCompat.Active)
			{
				ProperSaveCompat.Cleanup();
			}
			Harmony harmonyInstance = _harmonyInstance;
			if (harmonyInstance != null)
			{
				harmonyInstance.UnpatchSelf();
			}
		}
	}
	internal static class MidRunArtifactsHandler
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static ArtifactStateChangeDelegate <0>__RunArtifactManager_onArtifactEnabledGlobal;

			public static ArtifactStateChangeDelegate <1>__RunArtifactManager_onArtifactDisabledGlobal;

			public static Action <2>__MarkDirty;
		}

		[SystemInitializer(new Type[] { })]
		private static void InitListeners()
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Expected O, but got Unknown
			object obj = <>O.<0>__RunArtifactManager_onArtifactEnabledGlobal;
			if (obj == null)
			{
				ArtifactStateChangeDelegate val = RunArtifactManager_onArtifactEnabledGlobal;
				<>O.<0>__RunArtifactManager_onArtifactEnabledGlobal = val;
				obj = (object)val;
			}
			RunArtifactManager.onArtifactEnabledGlobal += (ArtifactStateChangeDelegate)obj;
			object obj2 = <>O.<1>__RunArtifactManager_onArtifactDisabledGlobal;
			if (obj2 == null)
			{
				ArtifactStateChangeDelegate val2 = RunArtifactManager_onArtifactDisabledGlobal;
				<>O.<1>__RunArtifactManager_onArtifactDisabledGlobal = val2;
				obj2 = (object)val2;
			}
			RunArtifactManager.onArtifactDisabledGlobal += (ArtifactStateChangeDelegate)obj2;
			SingleMonsterTypeChangedHook.OnSingleMonsterTypeChanged += EnemyInfoPanel.MarkDirty;
		}

		private static void RunArtifactManager_onArtifactEnabledGlobal(RunArtifactManager runArtifactManager, ArtifactDef artifactDef)
		{
			onArtifactStateChanged(artifactDef, enabled: true);
		}

		private static void RunArtifactManager_onArtifactDisabledGlobal(RunArtifactManager runArtifactManager, ArtifactDef artifactDef)
		{
			onArtifactStateChanged(artifactDef, enabled: false);
		}

		private static void onArtifactStateChanged(ArtifactDef artifactDef, bool enabled)
		{
			if (!Object.op_Implicit((Object)(object)Stage.instance))
			{
				return;
			}
			if ((Object)(object)artifactDef == (Object)(object)Artifacts.Sacrifice)
			{
				if (enabled)
				{
					onSacrificeEnabled();
				}
			}
			else if ((Object)(object)artifactDef == (Object)(object)Artifacts.RandomSurvivorOnRespawn)
			{
				if (enabled)
				{
					onMetamorphosisEnabled();
				}
			}
			else if ((Object)(object)artifactDef == (Object)(object)Artifacts.SingleMonsterType)
			{
				if (!enabled)
				{
					onKinDisabled();
				}
			}
			else if ((Object)(object)artifactDef == (Object)(object)Artifacts.Enigma)
			{
				if (enabled)
				{
					onEnigmaEnabled();
				}
			}
			else if ((Object)(object)artifactDef == (Object)(object)Artifacts.Devotion)
			{
				if (enabled)
				{
					onDevotionEnabled();
				}
			}
			else if ((Object)(object)artifactDef == (Object)(object)Artifacts.Delusion)
			{
				onDelusionEnabledOrDisabled(enabled);
			}
			else if ((Object)(object)artifactDef == (Object)(object)Artifacts.Rebirth && enabled)
			{
				onRebirthEnabled();
			}
			CharacterBodyUtils.MarkAllBodyStatsDirty();
			if (!enabled)
			{
				return;
			}
			foreach (LocalUser readOnlyLocalUsers in LocalUserManager.readOnlyLocalUsersList)
			{
				if (readOnlyLocalUsers != null)
				{
					CharacterMaster cachedMaster = readOnlyLocalUsers.cachedMaster;
					if (Object.op_Implicit((Object)(object)cachedMaster))
					{
						CharacterMasterNotificationQueue.PushArtifactNotification(cachedMaster, artifactDef);
					}
				}
			}
		}

		private static void onKinDisabled()
		{
			if (NetworkServer.active && Object.op_Implicit((Object)(object)Stage.instance))
			{
				Stage.instance.singleMonsterTypeBodyIndex = (BodyIndex)(-1);
			}
		}

		private static void onSacrificeEnabled()
		{
			if (!NetworkServer.active)
			{
				return;
			}
			List<ObjectSpawnCardTracker> instancesList = InstanceTracker.GetInstancesList<ObjectSpawnCardTracker>();
			for (int num = instancesList.Count - 1; num >= 0; num--)
			{
				ObjectSpawnCardTracker objectSpawnCardTracker = instancesList[num];
				if (Object.op_Implicit((Object)(object)objectSpawnCardTracker))
				{
					SpawnCard spawnCard = objectSpawnCardTracker.SpawnCard;
					InteractableSpawnCard val = (InteractableSpawnCard)(object)((spawnCard is InteractableSpawnCard) ? spawnCard : null);
					if (val != null && val.skipSpawnWhenSacrificeArtifactEnabled)
					{
						NetworkServer.Destroy(((Component)objectSpawnCardTracker).gameObject);
					}
				}
			}
		}

		private static void onMetamorphosisEnabled()
		{
			if (!NetworkServer.active)
			{
				return;
			}
			foreach (CharacterBody allPlayerBody in PlayerUtils.GetAllPlayerBodies(requireAlive: true))
			{
				allPlayerBody.master.Respawn(CharacterRespawnFlags.KeepState);
			}
		}

		private static void onEnigmaEnabled()
		{
			if (!NetworkServer.active)
			{
				return;
			}
			foreach (CharacterBody allPlayerBody in PlayerUtils.GetAllPlayerBodies(requireAlive: true))
			{
				EnigmaArtifactManager.OnPlayerCharacterBodyStartServer(allPlayerBody);
			}
		}

		private static void onDevotionEnabled()
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: 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_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Expected O, but got Unknown
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Expected O, but got Unknown
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: 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_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Expected O, but got Unknown
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Expected O, but got Unknown
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Unknown result type (might be due to invalid IL or missing references)
			if (!NetworkServer.active)
			{
				return;
			}
			SceneDirector val = null;
			if (Object.op_Implicit((Object)(object)DirectorCore.instance))
			{
				val = ((Component)DirectorCore.instance).GetComponent<SceneDirector>();
			}
			DirectorCard val2;
			if (Object.op_Implicit((Object)(object)val))
			{
				val2 = val.lumerianEgg;
			}
			else
			{
				Log.Warning("Failed to find SceneDirector", "D:\\Git\\RiskOfChaos\\Solution\\RiskOfChaos\\MidRunArtifactsHandler.cs", "onDevotionEnabled", 181);
				val2 = new DirectorCard
				{
					spawnCard = (SpawnCard)(object)Addressables.LoadAssetAsync<InteractableSpawnCard>((object)"RoR2/CU8/LemurianEgg/iscLemurianEgg.asset").WaitForCompletion()
				};
			}
			if (val2 == null || !Object.op_Implicit((Object)(object)val2.spawnCard))
			{
				Log.Error("Failed to find valid egg spawn card", "D:\\Git\\RiskOfChaos\\Solution\\RiskOfChaos\\MidRunArtifactsHandler.cs", "onDevotionEnabled", 191);
				return;
			}
			Xoroshiro128Plus val3 = new Xoroshiro128Plus(RoR2Application.rng.nextUlong);
			List<ObjectSpawnCardTracker> instancesList = InstanceTracker.GetInstancesList<ObjectSpawnCardTracker>();
			for (int num = instancesList.Count - 1; num >= 0; num--)
			{
				ObjectSpawnCardTracker objectSpawnCardTracker = instancesList[num];
				if (Object.op_Implicit((Object)(object)objectSpawnCardTracker))
				{
					SpawnCard spawnCard = objectSpawnCardTracker.SpawnCard;
					InteractableSpawnCard val4 = (InteractableSpawnCard)(object)((spawnCard is InteractableSpawnCard) ? spawnCard : null);
					if (val4 != null && val4.skipSpawnWhenDevotionArtifactEnabled)
					{
						DirectorPlacementRule val5 = new DirectorPlacementRule
						{
							placementMode = (PlacementMode)0,
							spawnOnTarget = ((Component)objectSpawnCardTracker).transform
						};
						DirectorSpawnRequest val6 = new DirectorSpawnRequest(val2.spawnCard, val5, val3);
						val6.spawnCard.DoSpawn(((Component)objectSpawnCardTracker).transform.position, ((Component)objectSpawnCardTracker).transform.rotation, val6);
						NetworkServer.Destroy(((Component)objectSpawnCardTracker).gameObject);
					}
				}
			}
		}

		private static void onDelusionEnabledOrDisabled(bool enabled)
		{
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: 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_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Expected O, but got Unknown
			TeleporterInteraction instance = TeleporterInteraction.instance;
			bool flag = Object.op_Implicit((Object)(object)instance) && instance.isCharged;
			EntityStateMachine val2 = default(EntityStateMachine);
			foreach (DelusionChestControllerTracker instances in InstanceTracker.GetInstancesList<DelusionChestControllerTracker>())
			{
				DelusionChestController delusionChestController = instances.DelusionChestController;
				if (!Object.op_Implicit((Object)(object)delusionChestController))
				{
					continue;
				}
				if (enabled)
				{
					if (!delusionChestController.hasBeenReset)
					{
						((Behaviour)delusionChestController).enabled = true;
						PickupIndex val = instances.TakePendingDelusionPickupIndex();
						if (((PickupIndex)(ref val)).isValid)
						{
							delusionChestController.delusionChest.CallRpcSetDelusionPickupIndex(val);
						}
						if (flag)
						{
							delusionChestController.delusionChest.CallRpcResetChests();
						}
					}
				}
				else if (delusionChestController.hasBeenReset)
				{
					((Behaviour)delusionChestController).enabled = false;
					NetworkUIPromptController netUIPromptController = delusionChestController._netUIPromptController;
					if (Object.op_Implicit((Object)(object)netUIPromptController))
					{
						((Behaviour)netUIPromptController).enabled = false;
					}
					PickupPickerController pickupPickerController = delusionChestController._pickupPickerController;
					if (Object.op_Implicit((Object)(object)pickupPickerController))
					{
						((Behaviour)pickupPickerController).enabled = false;
						pickupPickerController.SetAvailable(false);
					}
					if (((Component)delusionChestController).TryGetComponent<EntityStateMachine>(ref val2))
					{
						val2.SetNextState((EntityState)new Opening());
					}
				}
			}
		}

		private static void onRebirthEnabled()
		{
			if (NetworkServer.active && Object.op_Implicit((Object)(object)Run.instance))
			{
				Run.instance.ServerGiveRebirthItems();
			}
			if (!NetworkClient.active)
			{
				return;
			}
			foreach (NetworkUser readOnlyInstances in NetworkUser.readOnlyInstancesList)
			{
				LocalUser localUser = readOnlyInstances.localUser;
				UserProfile val = ((localUser != null) ? localUser.userProfile : null);
				if (val != null && !string.IsNullOrEmpty(val.RebirthItem))
				{
					val.RebirthItem = null;
					val.RequestEventualSave();
				}
			}
		}
	}
	internal sealed class TwitchLibLogSource : ILogSource
	{
		public void Log(object message, LogType type)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Expected I4, but got Unknown
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: 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_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			RiskOfChaos.Log.LogType((LogLevel)((int)type switch
			{
				0 => 32, 
				1 => 16, 
				2 => 8, 
				3 => 4, 
				4 => 2, 
				5 => 1, 
				_ => throw new NotImplementedException($"Log type {type} is not implemented"), 
			}), message);
		}
	}
}
namespace RiskOfChaos.Utilities
{
	public static class AdditionalResourceAvailability
	{
		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static hook_Init <>9__3_0;

			public static hook_Init <>9__3_1;

			public static hook_SetEntries <>9__3_2;

			internal void <InitHooks>b__3_0(orig_Init orig)
			{
				orig.Invoke();
				((ResourceAvailability)(ref BuffCatalog)).MakeAvailable();
			}

			internal void <InitHooks>b__3_1(orig_Init orig)
			{
				orig.Invoke();
				((ResourceAvailability)(ref MasterCatalog)).MakeAvailable();
			}

			internal void <InitHooks>b__3_2(orig_SetEntries orig, PickupDef[] entries)
			{
				orig.Invoke(entries);
				((ResourceAvailability)(ref PickupCatalog)).MakeAvailable();
			}
		}

		public static ResourceAvailability BuffCatalog;

		public static ResourceAvailability MasterCatalog;

		public static ResourceAvailability PickupCatalog;

		internal static void InitHooks()
		{
			//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_001f: Expected O, but got Unknown
			//IL_0038: 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_0043: Expected O, but got Unknown
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Expected O, but got Unknown
			object obj = <>c.<>9__3_0;
			if (obj == null)
			{
				hook_Init val = delegate(orig_Init orig)
				{
					orig.Invoke();
					((ResourceAvailability)(ref BuffCatalog)).MakeAvailable();
				};
				<>c.<>9__3_0 = val;
				obj = (object)val;
			}
			BuffCatalog.Init += (hook_Init)obj;
			object obj2 = <>c.<>9__3_1;
			if (obj2 == null)
			{
				hook_Init val2 = delegate(orig_Init orig)
				{
					orig.Invoke();
					((ResourceAvailability)(ref MasterCatalog)).MakeAvailable();
				};
				<>c.<>9__3_1 = val2;
				obj2 = (object)val2;
			}
			MasterCatalog.Init += (hook_Init)obj2;
			object obj3 = <>c.<>9__3_2;
			if (obj3 == null)
			{
				hook_SetEntries val3 = delegate(orig_SetEntries orig, PickupDef[] entries)
				{
					orig.Invoke(entries);
					((ResourceAvailability)(ref PickupCatalog)).MakeAvailable();
				};
				<>c.<>9__3_2 = val3;
				obj3 = (object)val3;
			}
			PickupCatalog.SetEntries += (hook_SetEntries)obj3;
		}
	}
	public static class AttackUtils
	{
		public static BulletAttack Clone(BulletAttack src)
		{
			return src.ShallowCopy<BulletAttack>(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		}

		public static BlastAttack Clone(BlastAttack src)
		{
			return src.ShallowCopy<BlastAttack>();
		}

		public static OverlapAttack Clone(OverlapAttack src)
		{
			return src.ShallowCopy<OverlapAttack>(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		}
	}
	public readonly record struct BodySkillPair(BodyIndex BodyIndex, SkillSlot SkillSlot)
	{
		public BodySkillPair(BodyIndex BodyIndex, SkillSlot SkillSlot)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			this.BodyIndex = BodyIndex;
			this.SkillSlot = SkillSlot;
		}

		public BodySkillPair(string bodyName, SkillSlot slot)
			: this(BodyCatalog.FindBodyIndex(bodyName), slot)
		{
		}//IL_0002: Unknown result type (might be due to invalid IL or missing references)
		//IL_0007: Unknown result type (might be due to invalid IL or missing references)


		[CompilerGenerated]
		private bool PrintMembers(StringBuilder builder)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			builder.Append("BodyIndex = ");
			BodyIndex bodyIndex = BodyIndex;
			builder.Append(((object)(BodyIndex)(ref bodyIndex)).ToString());
			builder.Append(", SkillSlot = ");
			SkillSlot skillSlot = SkillSlot;
			builder.Append(((object)(SkillSlot)(ref skillSlot)).ToString());
			return true;
		}

		[CompilerGenerated]
		public void Deconstruct(out BodyIndex BodyIndex, out SkillSlot SkillSlot)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Expected I4, but got Unknown
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected I4, but got Unknown
			BodyIndex = (BodyIndex)(int)this.BodyIndex;
			SkillSlot = (SkillSlot)(int)this.SkillSlot;
		}
	}
	public static class BossUtils
	{
		public static void TryRefreshBossTitleFor(CharacterMaster master)
		{
			if (Object.op_Implicit((Object)(object)master))
			{
				CharacterBody body = master.GetBody();
				if (Object.op_Implicit((Object)(object)body))
				{
					TryRefreshBossTitleFor(body);
				}
			}
		}

		public static void TryRefreshBossTitleFor(CharacterBody characterBody)
		{
			BossGroup val = BossGroup.FindBossGroup(characterBody);
			if (Object.op_Implicit((Object)(object)val))
			{
				RefreshBossTitle(val);
			}
		}

		public static void RefreshBossTitle(BossGroup bossGroup)
		{
			bossGroup.bestObservedName = string.Empty;
			bossGroup.bestObservedSubtitle = string.Empty;
		}
	}
	public static class CharacterBodyUtils
	{
		public static void MarkAllBodyStatsDirty()
		{
			foreach (CharacterBody readOnlyInstances in CharacterBody.readOnlyInstancesList)
			{
				readOnlyInstances.MarkAllStatsDirty();
			}
		}
	}
	public static class CharacterMasterNotificationQueueUtils
	{
		public static void SendPickupTransformNotification(CharacterMaster characterMaster, PickupIndex fromPickupIndex, PickupIndex toPickupIndex, TransformationType transformationType)
		{
			//IL_001f: 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)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			if (!NetworkServer.active)
			{
				Log.Error("Called on client", "D:\\Git\\RiskOfChaos\\Solution\\RiskOfChaos\\Utilities\\CharacterMasterNotificationQueueUtils.cs", "SendPickupTransformNotification", 15);
			}
			else
			{
				NetMessageExtensions.Send((INetMessage)(object)new PickupTransformationNotificationMessage(characterMaster, fromPickupIndex, toPickupIndex, transformationType), (NetworkDestination)3);
			}
		}

		public static bool IsAnyNotificationQueued(CharacterMaster viewerMaster)
		{
			if (!Object.op_Implicit((Object)(object)viewerMaster) || !((NetworkBehaviour)viewerMaster).hasAuthority)
			{
				return false;
			}
			CharacterMasterNotificationQueue val = (Object.op_Implicit((Object)(object)viewerMaster) ? ((Component)viewerMaster).GetComponent<CharacterMasterNotificationQueue>() : null);
			if (Object.op_Implicit((Object)(object)val))
			{
				return val.GetCurrentNotification() != (NotificationInfo)null;
			}
			return false;
		}
	}
	public static class ClampedConversion
	{
		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static int Int32(uint value)
		{
			if (value > int.MaxValue)
			{
				return int.MaxValue;
			}
			return (int)value;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static int Int32(long value)
		{
			if (value > int.MaxValue)
			{
				return int.MaxValue;
			}
			if (value < int.MinValue)
			{
				return int.MinValue;
			}
			return (int)value;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static uint UInt32(int value)
		{
			if ((long)value < 0L)
			{
				return 0u;
			}
			return (uint)value;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static uint UInt32(long value)
		{
			if (value > uint.MaxValue)
			{
				return uint.MaxValue;
			}
			if (value < 0)
			{
				return 0u;
			}
			return (uint)value;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static uint UInt32(ulong value)
		{
			if (value > uint.MaxValue)
			{
				return uint.MaxValue;
			}
			return (uint)value;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static sbyte Int8(int value)
		{
			if (value > 127)
			{
				return sbyte.MaxValue;
			}
			if (value < -128)
			{
				return sbyte.MinValue;
			}
			return (sbyte)value;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static byte UInt8(int value)
		{
			if (value > 255)
			{
				return byte.MaxValue;
			}
			if (value < 0)
			{
				return 0;
			}
			return (byte)value;
		}
	}
	public static class ConVarFlagUtil
	{
		public const ConVarFlags SERVER = 2;
	}
	public static class CostUtils
	{
		public static bool AllowsZeroCost(CostTypeIndex costType)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Invalid comparison between Unknown and I4
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Invalid comparison between Unknown and I4
			if ((int)costType <= 3 || costType - 14 <= 1)
			{
				return true;
			}
			return false;
		}

		public static int GetMaxCost(CostTypeIndex costType)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Invalid comparison between Unknown and I4
			//IL_0004: 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_0008: Invalid comparison between Unknown and I4
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Invalid comparison between Unknown and I4
			if ((int)costType != 2)
			{
				if (costType - 7 <= 1)
				{
					return 1;
				}
				if ((int)costType != 15)
				{
					return int.MaxValue;
				}
			}
			return 99;
		}

		public static int GetMinCost(CostTypeIndex costType)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Invalid comparison between Unknown and I4
			if ((int)costType != 0)
			{
				if ((int)costType == 15)
				{
					return 10;
				}
				return 1;
			}
			return 0;
		}

		public static float ConvertCost(float cost, CostTypeIndex from, CostTypeIndex to)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//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_0008: Invalid comparison between Unknown and I4
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Invalid comparison between Unknown and I4
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Invalid comparison between Unknown and I4
			//IL_001e: 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_001c: Invalid comparison between Unknown and I4
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: 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_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			if (from == to)
			{
				return cost;
			}
			if ((int)to <= 0 || (int)to >= 16)
			{
				return 0f;
			}
			if ((int)from <= 0 || (int)from >= 16)
			{
				return GetMinCost(to);
			}
			int minCost = GetMinCost(from);
			int maxCost = GetMaxCost(from);
			int maxCost2 = GetMaxCost(to);
			int minCost2 = GetMinCost(to);
			if (maxCost < int.MaxValue && minCost != maxCost)
			{
				float num = Mathf.Clamp01(Mathf.InverseLerp((float)minCost, (float)maxCost, cost));
				cost = (float)minCost - (50f - (float)minCost) * (1f + 1f / (num - 1f));
			}
			cost *= getConversionRate(from) / getConversionRate(to);
			if (maxCost2 < int.MaxValue && minCost2 != maxCost2)
			{
				float num2 = 1f + 1f / (((float)minCost2 - cost) / (50f - (float)minCost2) - 1f);
				cost = Mathf.Lerp((float)minCost2, (float)maxCost2, num2);
			}
			cost = Mathf.Clamp(cost, (float)minCost2, (float)maxCost2);
			return cost;
			static float getConversionRate(CostTypeIndex costType)
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				//IL_0002: Unknown result type (might be due to invalid IL or missing references)
				//IL_0038: Expected I4, but got Unknown
				switch (costType - 3)
				{
				case 1:
					return 25f;
				case 0:
				case 2:
				case 4:
				case 5:
				case 11:
					return 50f;
				case 9:
					return 75f;
				case 6:
					return 100f;
				case 3:
				case 7:
				case 8:
				case 10:
					return 150f;
				default:
					return 1f;
				}
			}
		}
	}
	public static class Ease
	{
		public static float InQuad(float t)
		{
			return t * t;
		}

		public static float OutQuad(float t)
		{
			return 1f - (1f - t) * (1f - t);
		}

		public static float InOutQuad(float t)
		{
			if (t < 0.5f)
			{
				return 2f * t * t;
			}
			float num = -2f * t + 2f;
			return 1f - num * num / 2f;
		}

		public static float InCubic(float t)
		{
			return t * t * t;
		}

		public static float OutCubic(float t)
		{
			float num = 1f - t;
			return 1f - num * num * num;
		}

		public static float InOutCubic(float t)
		{
			if (t < 0.5f)
			{
				return 4f * t * t * t;
			}
			float num = -2f * t + 2f;
			return 1f - num * num * num / 2f;
		}
	}
	public static class EliteUtils
	{
		private static EliteIndex[] _baseEliteIndices = Array.Empty<EliteIndex>();

		private static EquipmentIndex[] _baseEliteEquipmentIndices = Array.Empty<EquipmentIndex>();

		private static EliteIndex[] _runAvailableEliteIndices = Array.Empty<EliteIndex>();

		public static bool HasAnyRunAvailableElites => _runAvailableEliteIndices.Length != 0;

		[SystemInitializer(new Type[]
		{
			typeof(EquipmentCatalog),
			typeof(EliteCatalog)
		})]
		private static void Init()
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			List<EliteIndex> list = new List<EliteIndex>(EliteCatalog.eliteList.Count);
			List<EquipmentIndex> list2 = new List<EquipmentIndex>(EliteCatalog.eliteList.Count);
			foreach (EliteIndex elite in EliteCatalog.eliteList)
			{
				EliteDef eliteDef = EliteCatalog.GetEliteDef(elite);
				if (!Object.op_Implicit((Object)(object)eliteDef) || ((Object)eliteDef).name.EndsWith("Honor", StringComparison.OrdinalIgnoreCase))
				{
					continue;
				}
				EquipmentDef eliteEquipmentDef = eliteDef.eliteEquipmentDef;
				if (Object.op_Implicit((Object)(object)eliteEquipmentDef) && Object.op_Implicit((Object)(object)eliteEquipmentDef.pickupModelPrefab) && !string.Equals(((Object)eliteEquipmentDef.pickupModelPrefab).name, "NullModel", StringComparison.OrdinalIgnoreCase) && !(eliteEquipmentDef.dropOnDeathChance <= 0f))
				{
					if (!list.Contains(elite))
					{
						list.Add(elite);
					}
					if (!list2.Contains(eliteEquipmentDef.equipmentIndex))
					{
						list2.Add(eliteEquipmentDef.equipmentIndex);
					}
				}
			}
			list.Sort();
			_baseEliteIndices = list.ToArray();
			list2.Sort();
			_baseEliteEquipmentIndices = list2.ToArray();
			Run.onRunStartGlobal += delegate
			{
				//IL_001a: 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_0036: Unknown result type (might be due to invalid IL or missing references)
				List<EliteIndex> list3 = new List<EliteIndex>(_baseEliteIndices.Length);
				EliteIndex[] baseEliteIndices = _baseEliteIndices;
				foreach (EliteIndex val in baseEliteIndices)
				{
					EliteDef eliteDef2 = EliteCatalog.GetEliteDef(val);
					if (Object.op_Implicit((Object)(object)eliteDef2) && eliteDef2.IsAvailable())
					{
						list3.Add(val);
					}
				}
				_runAvailableEliteIndices = list3.ToArray();
			};
			Run.onRunDestroyGlobal += delegate
			{
				_runAvailableEliteIndices = Array.Empty<EliteIndex>();
			};
		}

		public static bool IsAvailable(EliteIndex eliteIndex)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			return Array.BinarySearch(_baseEliteIndices, eliteIndex) >= 0;
		}

		public static bool IsRunAvailable(EliteIndex eliteIndex)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			return Array.BinarySearch(_runAvailableEliteIndices, eliteIndex) >= 0;
		}

		public static EliteIndex[] GetRunAvailableElites(bool ignoreEliteTierAvailability)
		{
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			List<EliteIndex> list = new List<EliteIndex>(_runAvailableEliteIndices.Length);
			EliteTierDef[] eliteTiers = CombatDirector.eliteTiers;
			foreach (EliteTierDef val in eliteTiers)
			{
				if (!ignoreEliteTierAvailability && !val.CanSelect((EliteRules)0))
				{
					continue;
				}
				EliteDef[] eliteTypes = val.eliteTypes;
				foreach (EliteDef val2 in eliteTypes)
				{
					if (Object.op_Implicit((Object)(object)val2) && IsRunAvailable(val2.eliteIndex) && !list.Contains(val2.eliteIndex))
					{
						list.Add(val2.eliteIndex);
					}
				}
			}
			return list.ToArray();
		}

		public static bool IsEliteEquipment(EquipmentIndex equipmentIndex)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			return Array.BinarySearch(_baseEliteEquipmentIndices, equipmentIndex) >= 0;
		}
	}
	public class EventWaiter
	{
		private record struct EventInfo(bool HasInvoked);

		private bool _allEventsInvoked;

		public bool ResetAfterAllEventsInvoked;

		private readonly List<EventInfo> _events = new List<EventInfo>();

		public event Action OnAnyEventInvoked;

		public event Action OnAllEventsInvoked;

		public Action GetListener()
		{
			_events.Add(new EventInfo(HasInvoked: false));
			int eventIndex = _events.Count - 1;
			return delegate
			{
				if (eventIndex >= 0 && eventIndex < _events.Count && !_events[eventIndex].HasInvoked)
				{
					setHasEventInvoked(eventIndex, isInvoked: true);
					onEventInvoked();
				}
			};
		}

		private void setHasEventInvoked(int index, bool isInvoked)
		{
			if (index >= 0 && index < _events.Count)
			{
				EventInfo value = _events[index]with
				{
					HasInvoked = isInvoked
				};
				_events[index] = value;
			}
		}

		private void onEventInvoked()
		{
			this.OnAnyEventInvoked?.Invoke();
			if (_allEventsInvoked || !_events.All((EventInfo e) => e.HasInvoked))
			{
				return;
			}
			this.OnAllEventsInvoked?.Invoke();
			if (ResetAfterAllEventsInvoked)
			{
				for (int i = 0; i < _events.Count; i++)
				{
					setHasEventInvoked(i, isInvoked: false);
				}
			}
			else
			{
				_allEventsInvoked = true;
			}
		}
	}
	public static class ExpansionUtils
	{
		public static ExpansionDef DLC1 { get; private set; }

		public static ExpansionDef DLC2 { get; private set; }

		public static bool DLC1Enabled
		{
			[MethodImpl(MethodImplOptions.AggressiveInlining)]
			get
			{
				if (Object.op_Implicit((Object)(object)DLC1))
				{
					return IsExpansionEnabled(DLC1);
				}
				return false;
			}
		}

		public static bool DLC2Enabled
		{
			[MethodImpl(MethodImplOptions.AggressiveInlining)]
			get
			{
				if (Object.op_Implicit((Object)(object)DLC2))
				{
					return IsExpansionEnabled(DLC2);
				}
				return false;
			}
		}

		[SystemInitializer(new Type[] { })]
		private static IEnumerator Init()
		{
			List<AsyncOperationHandle> list = new List<AsyncOperationHandle>(2);
			AsyncOperationHandle<ExpansionDef> handle = Addressables.LoadAssetAsync<ExpansionDef>((object)"RoR2/DLC1/Common/DLC1.asset");
			handle.OnSuccess(delegate(ExpansionDef dlc1)
			{
				DLC1 = dlc1;
			});
			list.Add(AsyncOperationHandle<ExpansionDef>.op_Implicit(handle));
			AsyncOperationHandle<ExpansionDef> handle2 = Addressables.LoadAssetAsync<ExpansionDef>((object)"RoR2/DLC2/Common/DLC2.asset");
			handle2.OnSuccess(delegate(ExpansionDef dlc2)
			{
				DLC2 = dlc2;
			});
			list.Add(AsyncOperationHandle<ExpansionDef>.op_Implicit(handle2));
			yield return list.WaitForAllLoaded();
		}

		public static bool IsExpansionEnabled(ExpansionDef expansionDef)
		{
			if (Object.op_Implicit((Object)(object)expansionDef))
			{
				if (Object.op_Implicit((Object)(object)Run.instance))
				{
					return Run.instance.IsExpansionEnabled(expansionDef);
				}
				return false;
			}
			return true;
		}

		public static bool AllExpansionsEnabled(IEnumerable<ExpansionDef> expansions)
		{
			foreach (ExpansionDef expansion in expansions)
			{
				if (!IsExpansionEnabled(expansion))
				{
					return false;
				}
			}
			return true;
		}

		private static void addAllRequiredExpansions(GameObject obj, List<ExpansionDef> dest)
		{
			if (!Object.op_Implicit((Object)(object)obj))
			{
				return;
			}
			ExpansionRequirementComponent[] components = obj.GetComponents<ExpansionRequirementComponent>();
			ListExtensions.EnsureCapacity(dest, dest.Count + components.Length);
			ExpansionRequirementComponent[] array = components;
			foreach (ExpansionRequirementComponent val in array)
			{
				if (Object.op_Implicit((Object)(object)val.requiredExpansion))
				{
					dest.Add(val.requiredExpansion);
				}
			}
			CharacterMaster val2 = default(CharacterMaster);
			if (obj.TryGetComponent<CharacterMaster>(ref val2) && Object.op_Implicit((Object)(object)val2.bodyPrefab))
			{
				addAllRequiredExpansions(val2.bodyPrefab, dest);
			}
		}

		public static IReadOnlyList<ExpansionDef> GetObjectRequiredExpansions(GameObject obj)
		{
			if (!Object.op_Implicit((Object)(object)obj))
			{
				return Array.Empty<ExpansionDef>();
			}
			List<ExpansionDef> list = new List<ExpansionDef>();
			addAllRequiredExpansions(obj, list);
			list.TrimExcess();
			return list.AsReadOnly();
		}

		public static bool IsObjectExpansionAvailable(GameObject obj)
		{
			return AllExpansionsEnabled(GetObjectRequiredExpansions(obj));
		}
	}
	public static class FormatUtils
	{
		public static string GetBestBodyName(CharacterBody body)
		{
			if (!Object.op_Implicit((Object)(object)body))
			{
				return "null";
			}
			string bestBodyName = Util.GetBestBodyName(((Component)body).gameObject);
			if (!string.IsNullOrWhiteSpace(bestBodyName))
			{
				return bestBodyName;
			}
			return ((object)body).ToString();
		}

		public static string GetBestItemDisplayName(ItemIndex item)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Invalid comparison between Unknown and I4
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			if ((int)item == -1)
			{
				return "None";
			}
			return GetBestItemDisplayName(ItemCatalog.GetItemDef(item));
		}

		public static string GetBestItemDisplayName(ItemDef item)
		{
			if (!Object.op_Implicit((Object)(object)item))
			{
				return "null";
			}
			if (!string.IsNullOrWhiteSpace(item.nameToken) && !Language.IsTokenInvalid(item.nameToken))
			{
				string @string = Language.GetString(item.nameToken);
				if (!string.IsNullOrWhiteSpace(@string))
				{
					return @string;
				}
			}
			return ((Object)item).name;
		}

		public static string GetBestEquipmentDisplayName(EquipmentIndex equipmentIndex)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Invalid comparison between Unknown and I4
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			if ((int)equipmentIndex == -1)
			{
				return "None";
			}
			return GetBestEquipmentDisplayName(EquipmentCatalog.GetEquipmentDef(equipmentIndex));
		}

		public static string GetBestEquipmentDisplayName(EquipmentDef equipmentDef)
		{
			if (!Object.op_Implicit((Object)(object)equipmentDef))
			{
				return "null";
			}
			if (!string.IsNullOrEmpty(equipmentDef.nameToken) && !Language.IsTokenInvalid(equipmentDef.nameToken))
			{
				string @string = Language.GetString(equipmentDef.nameToken);
				if (!string.IsNullOrWhiteSpace(@string))
				{
					return @string;
				}
			}
			return ((Object)equipmentDef).name;
		}

		public static string GetBestDifficultyDisplayName(DifficultyIndex difficultyIndex)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			return GetBestDifficultyDisplayName(DifficultyCatalog.GetDifficultyDef(difficultyIndex));
		}

		public static string GetBestDifficultyDisplayName(DifficultyDef difficultyDef)
		{
			if (difficultyDef == null)
			{
				return "null";
			}
			return Language.GetString(difficultyDef.nameToken);
		}

		public static string FormatTimeSeconds(float seconds)
		{
			if (seconds < 120.5f)
			{
				return seconds.ToString((seconds >= 9.95f) ? "F0" : "F1") + "s";
			}
			int num = Mathf.FloorToInt(seconds / 60f);
			int num2 = Mathf.RoundToInt(seconds % 60f);
			return $"{num}:{num2:D2}";
		}
	}
	public static class InputUtils
	{
		private static MemoizedGetComponent<TMP_InputField> _currentSelectedObjectTMPInputField;

		private static MemoizedGetComponent<InputField> _currentSelectedObjectInputField;

		public static bool IsUsingInputField()
		{
			EventSystem val = (EventSystem)(object)MPEventSystemManager.FindEventSystem(ReInput.players.GetPlayer(0));
			if (Object.op_Implicit((Object)(object)val))
			{
				GameObject currentSelectedGameObject = val.currentSelectedGameObject;
				if (Object.op_Implicit((Object)(object)_currentSelectedObjectTMPInputField.Get(currentSelectedGameObject)) || Object.op_Implicit((Object)(object)_currentSelectedObjectInputField.Get(currentSelectedGameObject)))
				{
					return true;
				}
			}
			return false;
		}
	}
	public static class InstanceUtils
	{
		public static void DestroyAllTrackedInstances<T>(bool destroyGameObject = false) where T : MonoBehaviour
		{
			List<T> instancesList = InstanceTracker.GetInstancesList<T>();
			for (int num = instancesList.Count - 1; num >= 0; num--)
			{
				T val = instancesList[num];
				if (Object.op_Implicit((Object)(object)val))
				{
					Object.Destroy((Object)(destroyGameObject ? ((Component)(object)val).gameObject : ((object)val)));
				}
			}
		}
	}
	public readonly record struct ItemStack(ItemIndex ItemIndex, int ItemCount)
	{
		[CompilerGenerated]
		private bool PrintMembers(StringBuilder builder)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			builder.Append("ItemIndex = ");
			ItemIndex itemIndex = ItemIndex;
			builder.Append(((object)(ItemIndex)(ref itemIndex)).ToString());
			builder.Append(", ItemCount = ");
			builder.Append(ItemCount.ToString());
			return true;
		}

		[CompilerGenerated]
		public void Deconstruct(out ItemIndex ItemIndex, out int ItemCount)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Expected I4, but got Unknown
			ItemIndex = (ItemIndex)(int)this.ItemIndex;
			ItemCount = this.ItemCount;
		}
	}
	public class ItemTierPickupRulesOverride : IDisposable
	{
		private static PickupRules[] _originalPickupRules = Array.Empty<PickupRules>();

		private static readonly List<ItemTierPickupRulesOverride> _activeRuleOverrides = new List<ItemTierPickupRulesOverride>();

		private PickupRules _overrideRules;

		public PickupRules OverrideRules
		{
			get
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				return _overrideRules;
			}
			set
			{
				//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_000b: Unknown result type (might be due to invalid IL or missing references)
				//IL_000c: Unknown result type (might be due to invalid IL or missing references)
				if (_overrideRules != value)
				{
					_overrideRules = value;
					refreshPickupRules();
				}
			}
		}

		[SystemInitializer(new Type[] { typeof(ItemTierCatalog) })]
		private unsafe static void Init()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Expected I4, but got Unknown
			ReadOnlyArray<ItemTierDef> allItemTierDefs = ItemTierCatalog.allItemTierDefs;
			_originalPickupRules = (PickupRules[])(object)new PickupRules[allItemTierDefs.Length];
			for (int i = 0; i < allItemTierDefs.Length; i++)
			{
				_originalPickupRules[i] = (PickupRules)(int)((ItemTierDef)Unsafe.Read<object>((void*)allItemTierDefs[i])).pickupRules;
			}
		}

		private static void refreshPickupRules()
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			if (_activeRuleOverrides.Count > 0)
			{
				List<ItemTierPickupRulesOverride> activeRuleOverrides = _activeRuleOverrides;
				setOverridePickupRules(activeRuleOverrides[activeRuleOverrides.Count - 1].OverrideRules);
			}
			else
			{
				restorePickupRules();
			}
		}

		private unsafe static void setOverridePickupRules(PickupRules overridePickupRules)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: 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)
			for (int i = 0; i < ItemTierCatalog.allItemTierDefs.Length; i++)
			{
				((ItemTierDef)Unsafe.Read<object>((void*)ItemTierCatalog.allItemTierDefs[i])).pickupRules = overridePickupRules;
			}
		}

		private unsafe static void restorePickupRules()
		{
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			if (_originalPickupRules.Length == 0)
			{
				Log.Error("Original rules not initialized, cannot restore pickup rules", "D:\\Git\\RiskOfChaos\\Solution\\RiskOfChaos\\Utilities\\ItemTierPickupRulesOverride.cs", "restorePickupRules", 52);
				return;
			}
			for (int i = 0; i < ItemTierCatalog.allItemTierDefs.Length; i++)
			{
				if (i >= _originalPickupRules.Length)
				{
					Log.Error("Missing original pickup rules for " + ((Object)ItemTierCatalog.GetItemTierDef((ItemTier)i)).name, "D:\\Git\\RiskOfChaos\\Solution\\RiskOfChaos\\Utilities\\ItemTierPickupRulesOverride.cs", "restorePickupRules", 60);
				}
				else
				{
					((ItemTierDef)Unsafe.Read<object>((void*)ItemTierCatalog.allItemTierDefs[i])).pickupRules = _originalPickupRules[i];
				}
			}
		}

		public ItemTierPickupRulesOverride(PickupRules pickupRulesOverride)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			_overrideRules = pickupRulesOverride;
			_activeRuleOverrides.Add(this);
			refreshPickupRules();
		}

		public void Dispose()
		{
			if (_activeRuleOverrides.Remove(this))
			{
				refreshPickupRules();
			}
		}
	}
	public static class LoadoutUtils
	{
		[Flags]
		public enum GeneratorFlags : byte
		{
			None = 0,
			Skills = 1,
			Skin = 2,
			All = byte.MaxValue
		}

		public static Loadout GetRandomLoadoutFor(BodyIndex bodyIndex, Xoroshiro128Plus rng, GeneratorFlags flags = GeneratorFlags.All)
		{
			//IL_0005: 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_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Expected O, but got Unknown
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: 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_0038: Unknown result type (might be due to invalid IL or missing references)
			BodyInfo val = BodyLoadoutManager.allBodyInfos[bodyIndex];
			Loadout val2 = new Loadout();
			if ((flags & GeneratorFlags.Skills) != 0)
			{
				for (int i = 0; i < ((BodyInfo)(ref val)).skillSlotCount; i++)
				{
					Variant[] variants = val.prefabSkillSlots[i].skillFamily.variants;
					if (variants.Length != 0)
					{
						try
						{
							val2.bodyLoadoutManager.SetSkillVariant(bodyIndex, i, (uint)rng.RangeInt(0, variants.Length));
						}
						catch (Exception arg)
						{
							Log.Error_NoCallerPrefix($"Failed to set {BodyCatalog.GetBodyName(bodyIndex)} {(object)(SkillSlot)(sbyte)i} skill: {arg}");
						}
					}
				}
			}
			if ((flags & GeneratorFlags.Skin) != 0)
			{
				int num = BodyCatalog.GetBodySkins(bodyIndex).Length;
				if (num > 0)
				{
					try
					{
						val2.bodyLoadoutManager.SetSkinIndex(bodyIndex, (uint)rng.RangeInt(0, num));
					}
					catch (Exception arg2)
					{
						Log.Error_NoCallerPrefix($"Failed to set {BodyCatalog.GetBodyName(bodyIndex)} skin: {arg2}");
					}
				}
			}
			return val2;
		}

		public static Loadout GetRandomLoadoutFor(CharacterMaster master, Xoroshiro128Plus rng, GeneratorFlags flags = GeneratorFlags.All)
		{
			//IL_001f: 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_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Invalid comparison between Unknown and I4
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			if (Object.op_Implicit((Object)(object)master))
			{
				GameObject val = master.GetBodyObject();
				if (!Object.op_Implicit((Object)(object)val))
				{
					val = master.bodyPrefab;
				}
				BodyIndex val2 = BodyCatalog.FindBodyIndex(val);
				if ((int)val2 != -1)
				{
					return GetRandomLoadoutFor(val2, rng, flags);
				}
			}
			return null;
		}

		public static Loadout GetRandomLoadoutFor(GameObject characterPrefab, Xoroshiro128Plus rng, GeneratorFlags flags = GeneratorFlags.All)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)characterPrefab))
			{
				return null;
			}
			CharacterBody val = default(CharacterBody);
			if (characterPrefab.TryGetComponent<CharacterBody>(ref val))
			{
				return GetRandomLoadoutFor(val.bodyIndex, rng, flags);
			}
			CharacterMaster master = default(CharacterMaster);
			if (characterPrefab.TryGetComponent<CharacterMaster>(ref master))
			{
				return GetRandomLoadoutFor(master, rng, flags);
			}
			Log.Warning($"{characterPrefab} has no character related components", "D:\\Git\\RiskOfChaos\\Solution\\RiskOfChaos\\Utilities\\LoadoutUtils.cs", "GetRandomLoadoutFor", 99);
			return null;
		}

		public static Loadout GetRandomLoadoutFor(CharacterSpawnCard spawnCard, Xoroshiro128Plus rng, GeneratorFlags flags = GeneratorFlags.All)
		{
			if (!Object.op_Implicit((Object)(object)spawnCard))
			{
				return null;
			}
			return GetRandomLoadoutFor(((SpawnCard)spawnCard).prefab, rng, flags);
		}
	}
	public static class OrbUtils
	{
		public static bool IsTransferOrb(Orb orb)
		{
			if (orb is ItemTransferOrb || orb is EquipmentTransferOrb)
			{
				return true;
			}
			return false;
		}

		public static Orb Clone(Orb src)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Expected O, but got Unknown
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Expected O, but got Unknown
			Orb dest;
			try
			{
				ChainGunOrb val = (ChainGunOrb)(object)((src is ChainGunOrb) ? src : null);
				Orb val2 = (Orb)((val == null) ? ((object)(Orb)Activator.CreateInstance(((object)src).GetType())) : ((object)new ChainGunOrb(val.orbEffectPrefab)));
				dest = val2;
			}
			catch (Exception arg)
			{
				Log.Error_NoCallerPrefix($"Failed to create new orb from {src}: {arg}");
				return null;
			}
			src.ShallowCopy(ref dest);
			return dest;
		}
	}
	public struct PickupPair : IEquatable<PickupPair>
	{
		public PickupIndex PickupA;

		public PickupIndex PickupB;

		public PickupPair(PickupIndex pickupA, PickupIndex pickupB)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			PickupA = pickupA;
			PickupB = pickupB;
		}

		public override readonly bool Equals(object obj)
		{
			if (obj is PickupPair other)
			{
				return Equals(other);
			}
			return false;
		}

		public readonly bool Equals(PickupPair other)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: 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_001a: Unknown result type (might be due to invalid IL or missing references)
			if (PickupA == other.PickupA)
			{
				return PickupB == other.PickupB;
			}
			return false;
		}

		public override readonly int GetHashCode()
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			return HashCode.Combine<PickupIndex, PickupIndex>(PickupA, PickupB);
		}

		public static bool operator ==(PickupPair left, PickupPair right)
		{
			return left.Equals(right);
		}

		public static bool operator !=(PickupPair left, PickupPair right)
		{
			return !(left == right);
		}
	}
	public static class PlayerUtils
	{
		public static IEnumerable<CharacterMaster> GetAllPlayerMasters(bool requireAlive)
		{
			return from p in PlayerCharacterMasterController.instances
				where Object.op_Implicit((Object)(object)p)
				select p.master into m
				where Object.op_Implicit((Object)(object)m) && (!requireAlive || m.IsAlive())
				select m;
		}

		public static IEnumerable<CharacterBody> GetAllPlayerBodies(bool requireAlive)
		{
			return from m in GetAllPlayerMasters(requireAlive)
				select m.GetBody() into b
				where Object.op_Implicit((Object)(object)b)
				select b;
		}
	}
	public static class PopupAlertQueue
	{
		public delegate void SetupDialogDelegate(SimpleDialogBox dialogBox);

		private readonly record struct Alert(SetupDialogDelegate SetupDialog);

		[CompilerGenerated]
		private static class <>O
		{
			public static hook_OnEnter <0>__BaseMainMenuScreen_OnEnter;

			public static Action <1>__fixedUpdate;
		}

		private static readonly Queue<Alert> _alertQueue = new Queue<Alert>();

		private static SimpleDialogBox _currentDialogBox;

		[SystemInitializer(new Type[] { })]
		private static void Init()
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			object obj = <>O.<0>__BaseMainMenuScreen_OnEnter;
			if (obj == null)
			{
				hook_OnEnter val = BaseMainMenuScreen_OnEnter;
				<>O.<0>__BaseMainMenuScreen_OnEnter = val;
				obj = (object)val;
			}
			BaseMainMenuScreen.OnEnter += (hook_OnEnter)obj;
			static void BaseMainMenuScreen_OnEnter(orig_OnEnter orig, BaseMainMenuScreen self, MainMenuController mainMenuController)
			{
				//IL_0026: Unknown result type (might be due to invalid IL or missing references)
				//IL_002b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0031: Expected O, but got Unknown
				orig.Invoke(self, mainMenuController);
				if ((Object)(object)self == (Object)(object)mainMenuController.titleMenuScreen)
				{
					object obj2 = <>O.<0>__BaseMainMenuScreen_OnEnter;
					if (obj2 == null)
					{
						hook_OnEnter val2 = BaseMainMenuScreen_OnEnter;
						<>O.<0>__BaseMainMenuScreen_OnEnter = val2;
						obj2 = (object)val2;
					}
					BaseMainMenuScreen.OnEnter -= (hook_OnEnter)obj2;
					startAlertQueue();
				}
			}
		}

		public static void EnqueueAlert(SetupDialogDelegate setupDialog)
		{
			if (setupDialog == null)
			{
				throw new ArgumentNullException("setupDialog");
			}
			_alertQueue.Enqueue(new Alert(setupDialog));
		}

		private static void startAlertQueue()
		{
			RoR2Application.onFixedUpdate += fixedUpdate;
		}

		private static void fixedUpdate()
		{
			if (!Object.op_Implicit((Object)(object)_currentDialogBox) && _alertQueue.Count != 0)
			{
				Alert alert = _alertQueue.Dequeue();
				SimpleDialogBox val = SimpleDialogBox.Create((MPEventSystem)null);
				alert.SetupDialog(val);
				_currentDialogBox = val;
			}
		}
	}
	public static class QuaternionUtils
	{
		public static Quaternion PointLocalDirectionAt(Vector3 localDirection, Vector3 targetDirection)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//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_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			return Util.QuaternionSafeLookRotation(targetDirection) * Quaternion.FromToRotation(localDirection, Vector3.forward);
		}

		public static Quaternion Spread(Vector3 direction, float minAngle, float maxAngle, Xoroshiro128Plus rng)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: 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)
			//IL_001d: 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)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			direction = ((Vector3)(ref direction)).normalized;
			float num = rng.RangeFloat(minAngle, maxAngle);
			Vector3 val = Vector3.Cross(direction, RngExtensions.PointOnUnitSphere(rng));
			Vector3 normalized = ((Vector3)(ref val)).normalized;
			return Quaternion.AngleAxis(num, normalized);
		}

		public static Quaternion Spread(Vector3 baseDirection, float maxAngle, Xoroshiro128Plus rng)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			return Spread(baseDirection, 0f, maxAngle, rng);
		}
	}
	[Serializable]
	[JsonObject(/*Could not decode attribute arguments.*/)]
	public struct RunTimeStamp : IEquatable<RunTimeStamp>, IComparable<RunTimeStamp>
	{
		[JsonProperty("t")]
		public RunTimerType TimeType;

		[JsonProperty("v")]
		public float Time;

		private readonly float currentTime
		{
			get
			{
				Run instance = Run.instance;
				if (!Object.op_Implicit((Object)(object)instance))
				{
					Log.Warning("no run instance", "D:\\Git\\RiskOfChaos\\Solution\\RiskOfChaos\\Utilities\\RunTimeStamp.cs", "currentTime", 27);
					return 0f;
				}
				return instance.GetRunTime(TimeType);
			}
		}

		public readonly float TimeUntil => Time - currentTime;

		public readonly float TimeSince => currentTime - Time;

		public readonly float TimeUntilClamped => Mathf.Max(0f, TimeUntil);

		public readonly float TimeSinceClamped => Mathf.Max(0f, TimeSince);

		public readonly bool HasPassed => currentTime >= Time;

		public readonly bool IsInfinity => float.IsInfinity(Time);

		public readonly bool IsPositiveInfinity => float.IsPositiveInfinity(Time);

		public readonly bool IsNegativeInfinity => float.IsNegativeInfinity(Time);

		public RunTimeStamp(RunTimerType timeType, float time)
		{
			TimeType = timeType;
			Time = time;
		}

		public static RunTimeStamp Now(RunTimerType timeType)
		{
			Run instance = Run.instance;
			float time;
			if (Object.op_Implicit((Object)(object)instance))
			{
				time = instance.GetRunTime(timeType);
			}
			else
			{
				Log.Warning("no run instance", "D:\\Git\\RiskOfChaos\\Solution\\RiskOfChaos\\Utilities\\RunTimeStamp.cs", "Now", 68);
				time = 0f;
			}
			return new RunTimeStamp(timeType, time);
		}

		public readonly RunTimeStamp ConvertTo(RunTimerType timeType)
		{
			//IL_0042: 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_006f: Unknown result type (might be due to inva

plugins/RiskOfChaos/RiskOfChaos_PatcherInterop.dll

Decompiled 3 days ago
using System;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using Microsoft.CodeAnalysis;
using RoR2;
using RoR2.Projectile;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: InternalsVisibleTo("RiskOfChaos")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("RiskOfChaos_PatcherInterop")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+c158cf629270665c915140fc70b979c1b9cb1479")]
[assembly: AssemblyProduct("RiskOfChaos_PatcherInterop")]
[assembly: AssemblyTitle("RiskOfChaos_PatcherInterop")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace RiskOfChaos_PatcherInterop
{
	internal static class ProjectileInteropExtensions
	{
		private static float? decodeProcCoefficientOverride(float overridePlusOne)
		{
			float num = overridePlusOne - 1f;
			if (num < 0f)
			{
				return null;
			}
			return num;
		}

		private static float encodeProcCoefficientOverride(float? overrideProcCoefficient)
		{
			if (!overrideProcCoefficient.HasValue)
			{
				return 0f;
			}
			return overrideProcCoefficient.Value + 1f;
		}

		public static float GetProcCoefficientOverridePlusOne(this in FireProjectileInfo fireProjectileInfo)
		{
			return fireProjectileInfo.roc_procCoefficientOverridePlusOne;
		}

		public static float? GetProcCoefficientOverride(this in FireProjectileInfo fireProjectileInfo)
		{
			return decodeProcCoefficientOverride(fireProjectileInfo.roc_procCoefficientOverridePlusOne);
		}

		public static void SetProcCoefficientOverridePlusOne(this ref FireProjectileInfo fireProjectileInfo, float value)
		{
			fireProjectileInfo.roc_procCoefficientOverridePlusOne = value;
		}

		public static void SetProcCoefficientOverride(this ref FireProjectileInfo fireProjectileInfo, float? value)
		{
			fireProjectileInfo.roc_procCoefficientOverridePlusOne = encodeProcCoefficientOverride(value);
		}

		public static float GetProcCoefficientOverridePlusOne(this PlayerFireProjectileMessage playerFireProjectileMessage)
		{
			return playerFireProjectileMessage.roc_procCoefficientOverridePlusOne;
		}

		public static float? GetProcCoefficientOverride(this PlayerFireProjectileMessage playerFireProjectileMessage)
		{
			return decodeProcCoefficientOverride(playerFireProjectileMessage.roc_procCoefficientOverridePlusOne);
		}

		public static void SetProcCoefficientOverridePlusOne(this PlayerFireProjectileMessage playerFireProjectileMessage, float value)
		{
			playerFireProjectileMessage.roc_procCoefficientOverridePlusOne = value;
		}

		public static void SetProcCoefficientOverride(this PlayerFireProjectileMessage playerFireProjectileMessage, float? value)
		{
			playerFireProjectileMessage.roc_procCoefficientOverridePlusOne = encodeProcCoefficientOverride(value);
		}

		public static ProcChainMask GetProcChainMask(this PlayerFireProjectileMessage playerFireProjectileMessage)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			return playerFireProjectileMessage.roc_procChainMask;
		}

		public static void SetProcChainMask(this PlayerFireProjectileMessage playerFireProjectileMessage, ProcChainMask procChainMask)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			playerFireProjectileMessage.roc_procChainMask = procChainMask;
		}
	}
}

plugins/RiskOfChaos/RiskOfTwitch.dll

Decompiled 3 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Net.WebSockets;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security.Authentication;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Web;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using RiskOfTwitch.Chat.Message;
using RiskOfTwitch.Chat.Notification;
using RiskOfTwitch.Logging;
using RiskOfTwitch.User;
using RiskOfTwitch.WebSockets;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("RiskOfTwitch")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+c158cf629270665c915140fc70b979c1b9cb1479")]
[assembly: AssemblyProduct("RiskOfTwitch")]
[assembly: AssemblyTitle("RiskOfTwitch")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace RiskOfTwitch
{
	public class Authentication
	{
		public const string CLIENT_ID = "2h96zmad9nhz11unv407c9ou6i6ofj";

		public const string AUTH_REDIRECT_URL = "http://localhost:4000/roc/oauth/redirect";

		private static readonly byte[] _authRedirectResponseBytes = Encoding.ASCII.GetBytes("<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\r\n</head>\r\n<body>\r\nAuthentication complete. You may close this window.\r\n   <script>\r\n       var url = window.location;\r\n       url.replace(window.location.hash, \"\");\r\n       fetch(url, {\r\n          method: 'GET',\r\n          headers: {\r\n             'fragment': window.location.hash\r\n          }\r\n       });\r\n   </script>\r\n</body>");

		public static string CreateAuthorizeUrl(string scopes, out string authState)
		{
			using (RandomNumberGenerator randomNumberGenerator = RandomNumberGenerator.Create())
			{
				byte[] array = new byte[16];
				randomNumberGenerator.GetBytes(array);
				StringBuilder stringBuilder = new StringBuilder(32);
				for (int i = 0; i < 16; i++)
				{
					stringBuilder.Append(array[i].ToString("x2"));
				}
				authState = stringBuilder.ToString();
			}
			return "https://id.twitch.tv/oauth2/authorize?response_type=token&client_id=2h96zmad9nhz11unv407c9ou6i6ofj&redirect_uri=http://localhost:4000/roc/oauth/redirect&scope=" + HttpUtility.UrlEncode(scopes) + "&state=" + authState;
		}

		public static async Task<Result<string>> AuthenticateUserAccessToken(string scopes, CancellationToken cancellationToken = default(CancellationToken))
		{
			Application.OpenURL(CreateAuthorizeUrl(scopes, out var authState));
			using HttpListener httpListener = new HttpListener();
			httpListener.Prefixes.Add("http://localhost:4000/roc/oauth/redirect/");
			httpListener.Start();
			HttpListenerContext context2 = await httpListener.GetContextAsync().ConfigureAwait(continueOnCapturedContext: false);
			context2.Response.ContentType = "text/html";
			context2.Response.ContentEncoding = Encoding.ASCII;
			context2.Response.ContentLength64 = _authRedirectResponseBytes.LongLength;
			await context2.Response.OutputStream.WriteAsync(_authRedirectResponseBytes, 0, _authRedirectResponseBytes.Length, cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
			context2.Response.Close();
			context2 = await httpListener.GetContextAsync().ConfigureAwait(continueOnCapturedContext: false);
			string text = context2.Request.Headers["fragment"];
			Uri url = context2.Request.Url;
			Dictionary<string, string> destination = new Dictionary<string, string>();
			if (url != null)
			{
				string text2 = url.Query;
				if (!string.IsNullOrEmpty(text2))
				{
					if (text2[0] == '?')
					{
						text2 = text2.Substring(1);
					}
					UrlUtils.SplitUrlQueries(text2, destination);
				}
			}
			Dictionary<string, string> dictionary = new Dictionary<string, string>();
			if (!string.IsNullOrEmpty(text))
			{
				if (text[0] == '#')
				{
					text = text.Substring(1);
				}
				UrlUtils.SplitUrlQueries(text, dictionary);
			}
			context2.Response.StatusCode = 200;
			context2.Response.KeepAlive = false;
			context2.Response.Close();
			if (!dictionary.TryGetValue("state", out var value) || !string.Equals(authState, value))
			{
				return new Result<string>(new AuthenticationException("Invalid authentication state"));
			}
			if (!dictionary.TryGetValue("access_token", out var value2))
			{
				return new Result<string>(new AuthenticationException("No token received"));
			}
			return value2;
		}

		public static async Task<Result<AuthenticationTokenValidationResponse>> GetAccessTokenValidationAsync(string accessToken, CancellationToken cancellationToken = default(CancellationToken))
		{
			using HttpClient client = new HttpClient();
			client.DefaultRequestHeaders.Add("Authorization", "Bearer " + accessToken);
			using HttpResponseMessage validationResponse = await client.GetAsync("https://id.twitch.tv/oauth2/validate", cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
			string text = await validationResponse.Content.ReadAsStringAsync().ConfigureAwait(continueOnCapturedContext: false);
			if (!validationResponse.IsSuccessStatusCode)
			{
				if (validationResponse.StatusCode == HttpStatusCode.Unauthorized && !string.IsNullOrEmpty(text) && text.Contains("invalid access token", StringComparison.OrdinalIgnoreCase))
				{
					return new Result<AuthenticationTokenValidationResponse>(new InvalidAccessTokenException());
				}
				return new Result<AuthenticationTokenValidationResponse>(new HttpResponseException(validationResponse));
			}
			try
			{
				return JsonConvert.DeserializeObject<AuthenticationTokenValidationResponse>(text);
			}
			catch (Exception exception)
			{
				return new Result<AuthenticationTokenValidationResponse>(exception);
			}
		}
	}
	[Serializable]
	public class AuthenticationTokenValidationResponse
	{
		[JsonProperty("client_id")]
		public string ClientId { get; set; } = string.Empty;


		[JsonProperty("login")]
		public string Username { get; set; } = string.Empty;


		[JsonProperty("scopes")]
		public string[] Scopes { get; set; } = Array.Empty<string>();


		[JsonProperty("user_id")]
		public string UserID { get; set; } = string.Empty;


		[JsonProperty("expires_in")]
		private int expiresInSeconds
		{
			get
			{
				return (int)Math.Round(ExpiryDate.TimeUntil.TotalSeconds);
			}
			set
			{
				ExpiryDate = DateTime.Now.AddSeconds(value);
			}
		}

		[JsonIgnore]
		public DateTimeStamp ExpiryDate { get; set; }
	}
	public readonly struct DateTimeStamp : IEquatable<DateTimeStamp>
	{
		public readonly DateTime Time;

		public static DateTimeStamp Now => new DateTimeStamp(DateTime.Now);

		public TimeSpan TimeSince => DateTime.Now - Time;

		public TimeSpan TimeUntil => Time - DateTime.Now;

		public bool IsFuture => TimeUntil.Ticks > 0;

		public bool HasPassed => TimeSince.Ticks > 0;

		public DateTimeStamp(DateTime time)
		{
			Time = time;
		}

		public override string ToString()
		{
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.Append(Time.ToString());
			if (IsFuture)
			{
				stringBuilder.Append($" (in {TimeUntil})");
			}
			else
			{
				stringBuilder.Append($" ({TimeSince} ago)");
			}
			return stringBuilder.ToString();
		}

		public override bool Equals(object obj)
		{
			if (obj is DateTimeStamp other)
			{
				return Equals(other);
			}
			return false;
		}

		public bool Equals(DateTimeStamp other)
		{
			return Time == other.Time;
		}

		public override int GetHashCode()
		{
			return 615635108 + Time.GetHashCode();
		}

		public static implicit operator DateTimeStamp(DateTime time)
		{
			return new DateTimeStamp(time);
		}

		public static bool operator ==(DateTimeStamp left, DateTimeStamp right)
		{
			return left.Equals(right);
		}

		public static bool operator !=(DateTimeStamp left, DateTimeStamp right)
		{
			return !(left == right);
		}

		public static bool operator <(DateTimeStamp left, DateTimeStamp right)
		{
			return left.Time < right.Time;
		}

		public static bool operator <(DateTimeStamp left, DateTime right)
		{
			return left.Time < right;
		}

		public static bool operator <(DateTime left, DateTimeStamp right)
		{
			return left < right.Time;
		}

		public static bool operator >(DateTimeStamp left, DateTimeStamp right)
		{
			return left.Time > right.Time;
		}

		public static bool operator >(DateTimeStamp left, DateTime right)
		{
			return left.Time > right;
		}

		public static bool operator >(DateTime left, DateTimeStamp right)
		{
			return left > right.Time;
		}

		public static bool operator <=(DateTimeStamp left, DateTimeStamp right)
		{
			return left.Time <= right.Time;
		}

		public static bool operator <=(DateTimeStamp left, DateTime right)
		{
			return left.Time <= right;
		}

		public static bool operator <=(DateTime left, DateTimeStamp right)
		{
			return left <= right.Time;
		}

		public static bool operator >=(DateTimeStamp left, DateTimeStamp right)
		{
			return left.Time >= right.Time;
		}

		public static bool operator >=(DateTimeStamp left, DateTime right)
		{
			return left.Time >= right;
		}

		public static bool operator >=(DateTime left, DateTimeStamp right)
		{
			return left >= right.Time;
		}
	}
	public sealed class HttpResponseException : Exception
	{
		public HttpStatusCode StatusCode { get; }

		public string ReasonPhrase { get; }

		public HttpResponseException(HttpStatusCode statusCode, string reasonPhrase)
			: base($"{statusCode} ({reasonPhrase})")
		{
			StatusCode = statusCode;
			ReasonPhrase = reasonPhrase;
		}

		public HttpResponseException(HttpResponseMessage responseMessage)
			: this(responseMessage.StatusCode, responseMessage.ReasonPhrase)
		{
		}
	}
	public sealed class InvalidAccessTokenException : Exception
	{
		public InvalidAccessTokenException()
			: base("The provided access token is not valid or has expired")
		{
		}
	}
	public static class Log
	{
		private static readonly object _stringBuilderLock;

		private static readonly StringBuilder _sharedStringBuilder;

		private static readonly int _cachedCallerPathPrefixLength;

		public static ILogSource LogSource { get; set; }

		static Log()
		{
			LogSource = new ConsoleLogSource();
			_stringBuilderLock = new object();
			_sharedStringBuilder = new StringBuilder(256);
			_cachedCallerPathPrefixLength = getCallerPathPrefixLength("D:\\Git\\RiskOfChaos\\Solution\\RiskOfTwitch\\Log.cs");
			static int getCallerPathPrefixLength([CallerFilePath] string callerPath = null)
			{
				int num = callerPath.LastIndexOf("RiskOfTwitch");
				if (num >= 0)
				{
					return num;
				}
				Error_NoCallerPrefix("[RiskOfTwitch] Logger failed to determine caller path prefix length");
				return 0;
			}
		}

		private static StringBuilder AppendCallerPrefix(this StringBuilder stringBuilder, string callerPath, string callerMemberName, int callerLineNumber)
		{
			return stringBuilder.Append(callerPath, _cachedCallerPathPrefixLength, callerPath.Length - _cachedCallerPathPrefixLength).Append(':').Append(callerLineNumber)
				.Append(" (")
				.Append(callerMemberName)
				.Append("):");
		}

		private static StringBuilder buildCallerLogString(string callerPath, string callerMemberName, int callerLineNumber, object data)
		{
			lock (_stringBuilderLock)
			{
				return _sharedStringBuilder.Clear().AppendCallerPrefix(callerPath, callerMemberName, callerLineNumber).Append(' ')
					.Append(data);
			}
		}

		[Conditional("DEBUG")]
		internal static void Debug(object data, [CallerFilePath] string callerPath = "", [CallerMemberName] string callerMemberName = "", [CallerLineNumber] int callerLineNumber = -1)
		{
			LogSource.Log(buildCallerLogString(callerPath, callerMemberName, callerLineNumber, data), LogType.Debug);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		[Conditional("DEBUG")]
		internal static void Debug_NoCallerPrefix(object data)
		{
			LogSource.Log(data, LogType.Debug);
		}

		internal static void Error(object data, [CallerFilePath] string callerPath = "", [CallerMemberName] string callerMemberName = "", [CallerLineNumber] int callerLineNumber = -1)
		{
			LogSource.Log(buildCallerLogString(callerPath, callerMemberName, callerLineNumber, data), LogType.Error);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		internal static void Error_NoCallerPrefix(object data)
		{
			LogSource.Log(data, LogType.Error);
		}

		internal static void Fatal(object data, [CallerFilePath] string callerPath = "", [CallerMemberName] string callerMemberName = "", [CallerLineNumber] int callerLineNumber = -1)
		{
			LogSource.Log(buildCallerLogString(callerPath, callerMemberName, callerLineNumber, data), LogType.Fatal);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		internal static void Fatal_NoCallerPrefix(object data)
		{
			LogSource.Log(data, LogType.Fatal);
		}

		internal static void Info(object data, [CallerFilePath] string callerPath = "", [CallerMemberName] string callerMemberName = "", [CallerLineNumber] int callerLineNumber = -1)
		{
			LogSource.Log(buildCallerLogString(callerPath, callerMemberName, callerLineNumber, data), LogType.Info);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		internal static void Info_NoCallerPrefix(object data)
		{
			LogSource.Log(data, LogType.Info);
		}

		internal static void Message(object data, [CallerFilePath] string callerPath = "", [CallerMemberName] string callerMemberName = "", [CallerLineNumber] int callerLineNumber = -1)
		{
			LogSource.Log(buildCallerLogString(callerPath, callerMemberName, callerLineNumber, data), LogType.Message);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		internal static void Message_NoCallerPrefix(object data)
		{
			LogSource.Log(data, LogType.Message);
		}

		internal static void Warning(object data, [CallerFilePath] string callerPath = "", [CallerMemberName] string callerMemberName = "", [CallerLineNumber] int callerLineNumber = -1)
		{
			LogSource.Log(buildCallerLogString(callerPath, callerMemberName, callerLineNumber, data), LogType.Warning);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		internal static void Warning_NoCallerPrefix(object data)
		{
			LogSource.Log(data, LogType.Warning);
		}
	}
	public sealed class Result<T>
	{
		private readonly T _value;

		public bool IsSuccess { get; }

		public Exception Exception { get; }

		public T Value
		{
			get
			{
				if (!IsSuccess)
				{
					throw new ArgumentException("Result is not success, cannot get value");
				}
				return _value;
			}
		}

		private Result(T value, Exception exception, bool isSuccess)
		{
			_value = value;
			Exception = exception;
			IsSuccess = isSuccess;
		}

		public Result(T value)
			: this(value, (Exception)null, isSuccess: true)
		{
		}

		public Result(Exception exception)
			: this(default(T), exception, isSuccess: false)
		{
		}

		public static implicit operator Result<T>(T value)
		{
			return new Result<T>(value);
		}
	}
	public static class StaticTwitchAPI
	{
		public static async Task<Result<GetUsersResponse>> GetUsers(string accessToken, string[] userIds, string[] usernames, CancellationToken cancellationToken = default(CancellationToken))
		{
			if (userIds == null)
			{
				userIds = Array.Empty<string>();
			}
			if (usernames == null)
			{
				usernames = Array.Empty<string>();
			}
			int num = userIds.Length + usernames.Length;
			if (num == 0)
			{
				return GetUsersResponse.Empty;
			}
			if (num > 100)
			{
				return new Result<GetUsersResponse>(new ArgumentOutOfRangeException("userIds, usernames", "Combined size of user ids and usernames cannot exceed 100"));
			}
			using HttpClient client = new HttpClient();
			client.DefaultRequestHeaders.Add("Authorization", "Bearer " + accessToken);
			client.DefaultRequestHeaders.Add("Client-Id", "2h96zmad9nhz11unv407c9ou6i6ofj");
			StringBuilder stringBuilder = new StringBuilder(num * 25);
			string[] array = userIds;
			foreach (string arg in array)
			{
				if (stringBuilder.Length > 0)
				{
					stringBuilder.Append('&');
				}
				stringBuilder.AppendFormat("id={0}", arg);
			}
			array = usernames;
			foreach (string arg2 in array)
			{
				if (stringBuilder.Length > 0)
				{
					stringBuilder.Append('&');
				}
				stringBuilder.AppendFormat("login={0}", arg2);
			}
			using HttpResponseMessage getUsersResponseMessage = await client.GetAsync($"https://api.twitch.tv/helix/users?{stringBuilder}", cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
			if (!getUsersResponseMessage.IsSuccessStatusCode)
			{
				return new Result<GetUsersResponse>(new HttpResponseException(getUsersResponseMessage));
			}
			GetUsersResponse getUsersResponse;
			try
			{
				getUsersResponse = JsonConvert.DeserializeObject<GetUsersResponse>(await getUsersResponseMessage.Content.ReadAsStringAsync().ConfigureAwait(continueOnCapturedContext: false));
			}
			catch (JsonException val)
			{
				return new Result<GetUsersResponse>((Exception)val);
			}
			return getUsersResponse;
		}
	}
	public static class UrlUtils
	{
		public static void SplitUrlQueries(string queries, IDictionary<string, string> destination)
		{
			if (destination == null)
			{
				throw new ArgumentNullException("destination");
			}
			if (string.IsNullOrWhiteSpace(queries))
			{
				return;
			}
			string[] array = queries.Split(new char[1] { '&' }, StringSplitOptions.RemoveEmptyEntries);
			for (int i = 0; i < array.Length; i++)
			{
				string[] array2 = array[i].Split('=');
				if (array2.Length == 2)
				{
					string text = HttpUtility.UrlDecode(array2[0]).Trim();
					string value = HttpUtility.UrlDecode(array2[1]).Trim();
					if (!string.IsNullOrEmpty(text) && !string.IsNullOrEmpty(value) && !destination.ContainsKey(text))
					{
						destination.Add(text, value);
					}
				}
			}
		}
	}
}
namespace RiskOfTwitch.WebSockets
{
	internal abstract class ClientWebSocketConnection : IDisposable
	{
		private ClientWebSocket _client;

		private readonly CancellationTokenSource _objectDisposedTokenSource = new CancellationTokenSource();

		private bool _isReconnecting;

		private bool _hasEverConnected;

		private bool _isDisposed;

		public Uri ConnectionUrl { get; set; }

		public bool AutoReconnect { get; set; } = true;


		public TimeSpan ConnectionTimeout { get; set; } = TimeSpan.FromSeconds(30.0);


		public WebSocketState? State => _client?.State;

		public ClientWebSocketConnection(Uri url)
		{
			ConnectionUrl = url;
		}

		public void Dispose()
		{
			if (_isDisposed)
			{
				return;
			}
			_isDisposed = true;
			_objectDisposedTokenSource.Cancel();
			_objectDisposedTokenSource.Dispose();
			if (_client != null)
			{
				try
				{
					Disconnect().Wait(TimeSpan.FromSeconds(2.0));
				}
				catch (Exception data)
				{
					Log.Error(data, "D:\\Git\\RiskOfChaos\\Solution\\RiskOfTwitch\\WebSockets\\ClientWebSocketConnection.cs", "Dispose", 51);
				}
				_client?.Dispose();
				_client = null;
			}
		}

		private void throwIfDisposed()
		{
			lock (this)
			{
				if (_isDisposed)
				{
					throw new ObjectDisposedException(string.Format("{0} ({1})", "ClientWebSocketConnection", ConnectionUrl));
				}
			}
		}

		protected virtual ClientWebSocket createClient()
		{
			ClientWebSocket clientWebSocket = new ClientWebSocket();
			clientWebSocket.Options.KeepAliveInterval = ConnectionTimeout;
			return clientWebSocket;
		}

		public async Task Connect(CancellationToken cancellationToken = default(CancellationToken))
		{
			throwIfDisposed();
			if (_client != null)
			{
				if (State.GetValueOrDefault() == WebSocketState.Connecting || State.GetValueOrDefault() == WebSocketState.Open)
				{
					Log.Error("Already connected", "D:\\Git\\RiskOfChaos\\Solution\\RiskOfTwitch\\WebSockets\\ClientWebSocketConnection.cs", "Connect", 87);
					return;
				}
				Log.Warning("Connecting while there is still an existing client instance, disposing old instance", "D:\\Git\\RiskOfChaos\\Solution\\RiskOfTwitch\\WebSockets\\ClientWebSocketConnection.cs", "Connect", 91);
				_client.Dispose();
			}
			CancellationTokenSource cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(_objectDisposedTokenSource.Token, cancellationToken);
			_client = createClient();
			await _client.ConnectAsync(ConnectionUrl, cancellationTokenSource.Token).ConfigureAwait(continueOnCapturedContext: false);
			if (!_hasEverConnected)
			{
				Task.Run(() => updateLoop(_objectDisposedTokenSource.Token));
				_hasEverConnected = true;
			}
		}

		public virtual async Task Disconnect(CancellationToken cancellationToken = default(CancellationToken))
		{
			if (_client != null)
			{
				if (State >= WebSocketState.CloseSent)
				{
					_client.Dispose();
					_client = null;
					return;
				}
				CancellationTokenSource cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(_objectDisposedTokenSource.Token, cancellationToken);
				await _client.CloseOutputAsync(WebSocketCloseStatus.NormalClosure, "", cancellationTokenSource.Token).ConfigureAwait(continueOnCapturedContext: false);
				_client?.Dispose();
				_client = null;
			}
		}

		public async Task Reconnect(TimeSpan delay = default(TimeSpan), CancellationToken cancellationToken = default(CancellationToken))
		{
			_isReconnecting = true;
			try
			{
				await Disconnect(cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
				await Task.Delay(delay).ConfigureAwait(continueOnCapturedContext: false);
				await Connect(cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
			}
			finally
			{
				_isReconnecting = false;
			}
		}

		private async Task updateLoop(CancellationToken cancellationToken)
		{
			while (!cancellationToken.IsCancellationRequested)
			{
				if (_client == null)
				{
					if (AutoReconnect && !_isReconnecting)
					{
						await Connect(cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
					}
				}
				else if (State.GetValueOrDefault() == WebSocketState.Open || State.GetValueOrDefault() == WebSocketState.CloseSent)
				{
					try
					{
						await handleNextMessageAsync(cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
					}
					catch (Exception ex) when (!(ex is OperationCanceledException))
					{
						Log.Error_NoCallerPrefix($"Unhandled exception handling web socket message: {ex}");
						await Reconnect(TimeSpan.FromSeconds(1.0), cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
					}
				}
			}
		}

		private async Task<WebSocketMessage> receiveMessageAsync(CancellationToken cancellationToken)
		{
			byte[] receivedData = new byte[1024];
			int totalReceivedDataLength = 0;
			WebSocketReceiveResult webSocketReceiveResult;
			while (true)
			{
				if (totalReceivedDataLength >= receivedData.Length)
				{
					Array.Resize(ref receivedData, receivedData.Length + 1024);
					continue;
				}
				ArraySegment<byte> buffer = new ArraySegment<byte>(receivedData, totalReceivedDataLength, receivedData.Length - totalReceivedDataLength);
				webSocketReceiveResult = await _client.ReceiveAsync(buffer, cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
				totalReceivedDataLength += webSocketReceiveResult.Count;
				if (webSocketReceiveResult.EndOfMessage)
				{
					break;
				}
			}
			return new WebSocketMessage(new ArraySegment<byte>(receivedData, 0, totalReceivedDataLength), webSocketReceiveResult);
		}

		private async Task handleNextMessageAsync(CancellationToken cancellationToken)
		{
			using CancellationTokenSource timeoutTokenSource = new CancellationTokenSource(ConnectionTimeout);
			using CancellationTokenSource cancelledOrTimedOutTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, timeoutTokenSource.Token);
			WebSocketMessage message;
			try
			{
				message = await receiveMessageAsync(cancelledOrTimedOutTokenSource.Token).ConfigureAwait(continueOnCapturedContext: false);
			}
			catch (OperationCanceledException)
			{
				if (timeoutTokenSource.Token.IsCancellationRequested)
				{
					Log.Info("WebSocket connection timed out, attempting reconnect...", "D:\\Git\\RiskOfChaos\\Solution\\RiskOfTwitch\\WebSockets\\ClientWebSocketConnection.cs", "handleNextMessageAsync", 212);
					await Reconnect(TimeSpan.FromSeconds(1.0), cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
					return;
				}
				throw;
			}
			if (message.MessageType == WebSocketMessageType.Close)
			{
				if (message.CloseStatus.GetValueOrDefault() != WebSocketCloseStatus.NormalClosure)
				{
					if (shouldReconnect(message))
					{
						Log.Info($"WebSocket connection closed (status={message.CloseStatus}, description='{message.CloseStatusDescription}'), attempting reconnect...", "D:\\Git\\RiskOfChaos\\Solution\\RiskOfTwitch\\WebSockets\\ClientWebSocketConnection.cs", "handleNextMessageAsync", 227);
						await Reconnect(TimeSpan.FromSeconds(1.0), cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
					}
					else
					{
						Log.Info($"WebSocket connection closed (status={message.CloseStatus}, description='{message.CloseStatusDescription}'), not attempting reconnect", "D:\\Git\\RiskOfChaos\\Solution\\RiskOfTwitch\\WebSockets\\ClientWebSocketConnection.cs", "handleNextMessageAsync", 233);
						AutoReconnect = false;
						await Disconnect(cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
					}
				}
				else
				{
					Log.Info("WebSocket connection closed", "D:\\Git\\RiskOfChaos\\Solution\\RiskOfTwitch\\WebSockets\\ClientWebSocketConnection.cs", "handleNextMessageAsync", 241);
				}
			}
			else
			{
				await handleSocketMessageAsync(message, cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
			}
		}

		protected abstract Task handleSocketMessageAsync(WebSocketMessage message, CancellationToken cancellationToken);

		protected virtual bool shouldReconnect(WebSocketMessage closingMessage)
		{
			return true;
		}
	}
	internal readonly struct WebSocketMessage
	{
		public readonly ArraySegment<byte> MessageData;

		public readonly WebSocketCloseStatus? CloseStatus;

		public readonly string CloseStatusDescription;

		public readonly WebSocketMessageType MessageType;

		public WebSocketMessage(ArraySegment<byte> messageData, WebSocketReceiveResult result)
		{
			MessageData = messageData;
			CloseStatus = result.CloseStatus;
			CloseStatusDescription = result.CloseStatusDescription;
			MessageType = result.MessageType;
		}
	}
}
namespace RiskOfTwitch.User
{
	public class GetUsersResponse
	{
		public static GetUsersResponse Empty { get; } = new GetUsersResponse
		{
			Users = Array.Empty<TwitchUserData>()
		};


		[JsonProperty("data")]
		public TwitchUserData[] Users { get; set; } = Array.Empty<TwitchUserData>();

	}
	public class TwitchUserData
	{
		[JsonProperty("id")]
		public string UserId { get; set; }

		[JsonProperty("login")]
		public string UserLoginName { get; set; }

		[JsonProperty("display_name")]
		public string UserDisplayName { get; set; }

		[JsonProperty("type")]
		public string UserType { get; set; }

		[JsonProperty("broadcaster_type")]
		public string BroadcasterType { get; set; }

		[JsonProperty("description")]
		public string UserDescription { get; set; }

		[JsonProperty("profile_image_url")]
		public string ProfileImageURL { get; set; }

		[JsonProperty("offline_image_url")]
		public string OfflineImageURL { get; set; }

		[JsonProperty("email")]
		public string UserEmail { get; set; }

		[JsonProperty("created_at")]
		public string UserCreatedAt { get; set; }
	}
}
namespace RiskOfTwitch.Logging
{
	internal class ConsoleLogSource : ILogSource
	{
		public void Log(object message, LogType type)
		{
			if (type != 0)
			{
				Console.WriteLine(message);
			}
		}
	}
	public interface ILogSource
	{
		void Log(object message, LogType type);
	}
	public enum LogType
	{
		Debug,
		Info,
		Message,
		Warning,
		Error,
		Fatal
	}
}
namespace RiskOfTwitch.EventSub
{
	public enum ConnectionErrorType
	{
		FailedRetrieveUser,
		FailedEventSubscribe,
		TokenAuthenticationFailed,
		TokenInvalid,
		Generic
	}
	public class ConnectionErrorEventArgs : EventArgs
	{
		public ConnectionErrorType Type { get; }

		public ConnectionErrorEventArgs(ConnectionErrorType type)
		{
			Type = type;
		}
	}
	internal interface ITwitchEventSubMessageHandler
	{
		Task HandleEventAsync(JToken deserializedEvent, CancellationToken cancellationToken);
	}
	public class TokenAccessRevokedEventData
	{
		public readonly string SubscriptionType;

		public readonly string Status;

		public TokenAccessRevokedEventData(string subscriptionType, string status)
		{
			SubscriptionType = subscriptionType;
			Status = status;
		}
	}
	public class TwitchEventSubClient : ITwitchEventSubMessageHandler
	{
		private readonly string _accessToken;

		private readonly string _overrideBroadcasterName;

		private readonly HashSet<string> _handledMessageIDs = new HashSet<string>();

		private readonly HashSet<string> _activeSubscriptions = new HashSet<string>();

		private CancellationTokenSource _disconnectedTokenSource = new CancellationTokenSource();

		private TwitchEventSubConnection _mainConnection;

		private TwitchEventSubConnection _migratingConnection;

		private string _sessionID;

		public string ConnectedToChannel { get; private set; }

		public bool IsConnecting
		{
			get
			{
				if (_mainConnection != null)
				{
					return _mainConnection.State.GetValueOrDefault() == WebSocketState.Connecting;
				}
				return false;
			}
		}

		public bool HasConnection
		{
			get
			{
				if (_mainConnection != null)
				{
					return _mainConnection.State.GetValueOrDefault() == WebSocketState.Open;
				}
				return false;
			}
		}

		public bool IsFullyConnected
		{
			get
			{
				if (!string.IsNullOrEmpty(_sessionID))
				{
					return _activeSubscriptions.Count > 0;
				}
				return false;
			}
		}

		public bool IsMigrating => _migratingConnection != null;

		public event EventHandler<ChannelChatMessageEvent> OnChannelChatMessage;

		public event EventHandler<ChannelChatNotificationEvent> OnChannelChatNotification;

		public event EventHandler<TokenAccessRevokedEventData> OnTokenAccessRevoked;

		public event EventHandler OnFullyConnected;

		public event EventHandler<ConnectionErrorEventArgs> OnConnectionError;

		public TwitchEventSubClient(string accessToken, string overrideBroadcasterName)
		{
			_accessToken = accessToken;
			_overrideBroadcasterName = overrideBroadcasterName;
		}

		public Task Connect(CancellationToken cancellationToken = default(CancellationToken))
		{
			return Connect(new Uri("wss://eventsub.wss.twitch.tv/ws"), cancellationToken);
		}

		public async Task Connect(Uri uri, CancellationToken cancellationToken = default(CancellationToken))
		{
			_disconnectedTokenSource?.Dispose();
			_disconnectedTokenSource = new CancellationTokenSource();
			using CancellationTokenSource cancelledOrDisconnectedSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, _disconnectedTokenSource.Token);
			if (_mainConnection == null)
			{
				_mainConnection = new TwitchEventSubConnection(uri, this);
				await _mainConnection.Connect(cancelledOrDisconnectedSource.Token).ConfigureAwait(continueOnCapturedContext: false);
			}
			else
			{
				_mainConnection.ConnectionUrl = uri;
				await _mainConnection.Reconnect(TimeSpan.FromSeconds(0.5), cancelledOrDisconnectedSource.Token).ConfigureAwait(continueOnCapturedContext: false);
			}
		}

		public async Task Disconnect(CancellationToken cancellationToken = default(CancellationToken))
		{
			_disconnectedTokenSource.Cancel();
			if (_mainConnection != null)
			{
				await _mainConnection.Disconnect(cancellationToken);
				_mainConnection?.Dispose();
				_mainConnection = null;
			}
			if (_migratingConnection != null)
			{
				await _migratingConnection.Disconnect(cancellationToken);
				_migratingConnection?.Dispose();
				_migratingConnection = null;
			}
			if (_activeSubscriptions.Count <= 0)
			{
				return;
			}
			foreach (string subscriptionId in _activeSubscriptions)
			{
				using HttpClient httpClient = new HttpClient();
				httpClient.DefaultRequestHeaders.Add("Authorization", "Bearer " + _accessToken);
				httpClient.DefaultRequestHeaders.Add("Client-Id", "2h96zmad9nhz11unv407c9ou6i6ofj");
				httpClient.DeleteAsync("https://api.twitch.tv/helix/eventsub/subscriptions?id=" + subscriptionId, cancellationToken).ContinueWith(delegate(Task<HttpResponseMessage> task)
				{
					if (!task.IsCanceled)
					{
						if (!task.IsFaulted)
						{
							using (HttpResponseMessage httpResponseMessage = task.Result)
							{
								if (!httpResponseMessage.IsSuccessStatusCode)
								{
									Log.Error($"Unable to delete subscription {subscriptionId}: {httpResponseMessage.StatusCode:D} {httpResponseMessage.ReasonPhrase}", "D:\\Git\\RiskOfChaos\\Solution\\RiskOfTwitch\\EventSub\\TwitchEventSubClient.cs", "Disconnect", 126);
								}
								return;
							}
						}
						Log.Error(task.Exception, "D:\\Git\\RiskOfChaos\\Solution\\RiskOfTwitch\\EventSub\\TwitchEventSubClient.cs", "Disconnect", 118);
					}
				});
			}
			_activeSubscriptions.Clear();
		}

		private void beginMigration(string reconnectUrl)
		{
			_migratingConnection = new TwitchEventSubConnection(new Uri(reconnectUrl), this);
			_migratingConnection.Connect();
		}

		public async Task HandleEventAsync(JToken jsonObject, CancellationToken cancellationToken)
		{
			JToken val = jsonObject.SelectToken("metadata.message_id", false);
			if (val == null)
			{
				Log.Error("Could not deserialize message_id property", "D:\\Git\\RiskOfChaos\\Solution\\RiskOfTwitch\\EventSub\\TwitchEventSubClient.cs", "HandleEventAsync", 153);
			}
			else
			{
				if (!_handledMessageIDs.Add(val.ToObject<string>()))
				{
					return;
				}
				JToken val2 = jsonObject.SelectToken("metadata.message_type", false);
				if (val2 != null)
				{
					using (CancellationTokenSource cancelledOrDisconnectedSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, _disconnectedTokenSource.Token))
					{
						string text = val2.ToObject<string>();
						switch (text)
						{
						case "session_welcome":
							await handleSessionWelcomeMessage(jsonObject, cancelledOrDisconnectedSource.Token);
							break;
						case "notification":
							handleNotificationMessage(jsonObject);
							break;
						case "session_reconnect":
							handleSessionReconnectMessage(jsonObject);
							break;
						case "revocation":
							handleRevokeMessageAsync(jsonObject);
							break;
						default:
							Log.Warning("Unhandled message type: " + text, "D:\\Git\\RiskOfChaos\\Solution\\RiskOfTwitch\\EventSub\\TwitchEventSubClient.cs", "HandleEventAsync", 188);
							break;
						case "session_keepalive":
							break;
						}
						return;
					}
				}
				Log.Error("Could not deserialize message_type property", "D:\\Git\\RiskOfChaos\\Solution\\RiskOfTwitch\\EventSub\\TwitchEventSubClient.cs", "HandleEventAsync", 163);
			}
		}

		private void handleSessionReconnectMessage(JToken jsonObject)
		{
			//IL_0035: Expected O, but got Unknown
			JToken val = jsonObject.SelectToken("payload.session", false);
			if (val == null)
			{
				Log.Error("Could not deserialize session data", "D:\\Git\\RiskOfChaos\\Solution\\RiskOfTwitch\\EventSub\\TwitchEventSubClient.cs", "handleSessionReconnectMessage", 198);
				return;
			}
			WebSocketSessionData webSocketSessionData;
			try
			{
				webSocketSessionData = val.ToObject<WebSocketSessionData>();
			}
			catch (JsonException val2)
			{
				JsonException arg = val2;
				Log.Error_NoCallerPrefix($"Failed to deserialize session object: {arg}");
				return;
			}
			beginMigration(webSocketSessionData.ReconnectUrl);
		}

		private void handleRevokeMessageAsync(JToken jsonObject)
		{
			string text = null;
			string text2 = null;
			JToken val = jsonObject.SelectToken("payload.subscription", false);
			if (val != null)
			{
				JToken val2 = val.SelectToken("type", false);
				if (val2 != null)
				{
					text = val2.ToObject<string>();
				}
				JToken val3 = val.SelectToken("status", false);
				if (val3 != null)
				{
					text2 = val3.ToObject<string>();
				}
			}
			this.OnTokenAccessRevoked?.Invoke(this, new TokenAccessRevokedEventData(text ?? string.Empty, text2 ?? string.Empty));
		}

		private async Task handleSessionWelcomeMessage(JToken jsonObject, CancellationToken cancellationToken)
		{
			JToken val = jsonObject.SelectToken("payload.session", false);
			if (val == null)
			{
				Log.Error("Could not deserialize session data", "D:\\Git\\RiskOfChaos\\Solution\\RiskOfTwitch\\EventSub\\TwitchEventSubClient.cs", "handleSessionWelcomeMessage", 247);
				this.OnConnectionError?.Invoke(this, new ConnectionErrorEventArgs(ConnectionErrorType.Generic));
				return;
			}
			WebSocketSessionData webSocketSessionData;
			try
			{
				webSocketSessionData = val.ToObject<WebSocketSessionData>();
			}
			catch (JsonException val2)
			{
				JsonException arg = val2;
				Log.Error_NoCallerPrefix($"Failed to deserialize session object: {arg}");
				this.OnConnectionError?.Invoke(this, new ConnectionErrorEventArgs(ConnectionErrorType.Generic));
				return;
			}
			if (IsMigrating)
			{
				if (_mainConnection != null)
				{
					_mainConnection.Dispose();
					_mainConnection = null;
				}
				_mainConnection = _migratingConnection;
				return;
			}
			_sessionID = webSocketSessionData.SessionID;
			Result<AuthenticationTokenValidationResponse> result = await Authentication.GetAccessTokenValidationAsync(_accessToken, cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
			if (!result.IsSuccess)
			{
				ConnectionErrorType type = ConnectionErrorType.TokenAuthenticationFailed;
				if (result.Exception is InvalidAccessTokenException)
				{
					type = ConnectionErrorType.TokenInvalid;
				}
				this.OnConnectionError?.Invoke(this, new ConnectionErrorEventArgs(type));
				return;
			}
			AuthenticationTokenValidationResponse value = result.Value;
			string userId = value.UserID;
			string broadcasterId = userId;
			string broadcasterName = value.Username;
			if (!string.IsNullOrEmpty(_overrideBroadcasterName))
			{
				Result<GetUsersResponse> result2 = await StaticTwitchAPI.GetUsers(_accessToken, Array.Empty<string>(), new string[1] { _overrideBroadcasterName }, cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
				if (result2.IsSuccess)
				{
					broadcasterName = _overrideBroadcasterName;
					broadcasterId = result2.Value.Users[0].UserId;
				}
				else
				{
					Log.Error($"Failed to retrieve override broadcaster data {result2.Exception}", "D:\\Git\\RiskOfChaos\\Solution\\RiskOfTwitch\\EventSub\\TwitchEventSubClient.cs", "handleSessionWelcomeMessage", 366);
				}
			}
			ConnectedToChannel = broadcasterName;
			bool flag = true;
			bool flag2 = flag;
			flag = flag2 & await sendSubscription<<>f__AnonymousType0<string, string, <>f__AnonymousType1<string, string>, <>f__AnonymousType2<string, string>>>(new
			{
				type = "channel.chat.message",
				version = "1",
				condition = new
				{
					broadcaster_user_id = broadcasterId,
					user_id = userId
				},
				transport = new
				{
					method = "websocket",
					session_id = _sessionID
				}
			}, cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
			flag2 = flag;
			if (flag2 & await sendSubscription<<>f__AnonymousType0<string, string, <>f__AnonymousType1<string, string>, <>f__AnonymousType2<string, string>>>(new
			{
				type = "channel.chat.notification",
				version = "1",
				condition = new
				{
					broadcaster_user_id = broadcasterId,
					user_id = userId
				},
				transport = new
				{
					method = "websocket",
					session_id = _sessionID
				}
			}, cancellationToken).ConfigureAwait(continueOnCapturedContext: false))
			{
				this.OnFullyConnected?.Invoke(this, EventArgs.Empty);
			}
			else
			{
				this.OnConnectionError?.Invoke(this, new ConnectionErrorEventArgs(ConnectionErrorType.FailedEventSubscribe));
			}
			async Task<bool> sendSubscription<T>(T message, CancellationToken cancellationToken)
			{
				using HttpClient client = new HttpClient();
				client.DefaultRequestHeaders.Add("Authorization", "Bearer " + _accessToken);
				client.DefaultRequestHeaders.Add("Client-Id", "2h96zmad9nhz11unv407c9ou6i6ofj");
				StringContent stringContent = new StringContent(JsonConvert.SerializeObject((object)message));
				stringContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
				using HttpResponseMessage subscribeResponseMessage = await client.PostAsync("https://api.twitch.tv/helix/eventsub/subscriptions", stringContent, cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
				if (!subscribeResponseMessage.IsSuccessStatusCode)
				{
					Log.Error($"Subscribe failed: {subscribeResponseMessage.StatusCode:D} ({subscribeResponseMessage.StatusCode:G}) {subscribeResponseMessage.ReasonPhrase}", "D:\\Git\\RiskOfChaos\\Solution\\RiskOfTwitch\\EventSub\\TwitchEventSubClient.cs", "handleSessionWelcomeMessage", 309);
					return false;
				}
				using StreamReader responseReader = new StreamReader(await subscribeResponseMessage.Content.ReadAsStreamAsync().ConfigureAwait(continueOnCapturedContext: false), Encoding.UTF8);
				JsonReader responseJsonReader = (JsonReader)new JsonTextReader((TextReader)responseReader);
				try
				{
					_ = 2;
					JToken val3;
					try
					{
						val3 = await JToken.ReadFromAsync(responseJsonReader, cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
					}
					catch (JsonException val4)
					{
						JsonException arg2 = val4;
						Log.Error($"Failed to deserialize subscribe response: {arg2}", "D:\\Git\\RiskOfChaos\\Solution\\RiskOfTwitch\\EventSub\\TwitchEventSubClient.cs", "handleSessionWelcomeMessage", 329);
						return false;
					}
					JToken obj = val3.SelectToken("data", false);
					JArray val5 = (JArray)(object)((obj is JArray) ? obj : null);
					if (val5 == null || ((JContainer)val5).Count <= 0)
					{
						Log.Error("Subscribe response contained invalid data", "D:\\Git\\RiskOfChaos\\Solution\\RiskOfTwitch\\EventSub\\TwitchEventSubClient.cs", "handleSessionWelcomeMessage", 336);
						return false;
					}
					JToken val6 = val5[0].SelectToken("id");
					if (val6 == null)
					{
						Log.Error("Could not find subscription id", "D:\\Git\\RiskOfChaos\\Solution\\RiskOfTwitch\\EventSub\\TwitchEventSubClient.cs", "handleSessionWelcomeMessage", 343);
						return false;
					}
					_activeSubscriptions.Add(val6.ToObject<string>());
					return true;
				}
				finally
				{
					((IDisposable)responseJsonReader)?.Dispose();
				}
			}
		}

		private void handleNotificationMessage(JToken jsonObject)
		{
			JToken val = jsonObject.SelectToken("payload.subscription.type", false);
			if (val == null)
			{
				Log.Error("Failed to find subscription type", "D:\\Git\\RiskOfChaos\\Solution\\RiskOfTwitch\\EventSub\\TwitchEventSubClient.cs", "handleNotificationMessage", 421);
				return;
			}
			string text = val.ToObject<string>();
			if (!(text == "channel.chat.message"))
			{
				if (text == "channel.chat.notification")
				{
					handleChannelChatNotificationNotification(jsonObject);
				}
				else
				{
					Log.Warning("Unhandled notification message: " + text, "D:\\Git\\RiskOfChaos\\Solution\\RiskOfTwitch\\EventSub\\TwitchEventSubClient.cs", "handleNotificationMessage", 435);
				}
			}
			else
			{
				handleChannelChatMessageNotification(jsonObject);
			}
		}

		private void handleChannelChatMessageNotification(JToken jsonObject)
		{
			//IL_003d: Expected O, but got Unknown
			if (this.OnChannelChatMessage == null)
			{
				return;
			}
			JToken val = jsonObject.SelectToken("payload.event");
			if (val == null)
			{
				Log.Error("Failed to find event object", "D:\\Git\\RiskOfChaos\\Solution\\RiskOfTwitch\\EventSub\\TwitchEventSubClient.cs", "handleChannelChatMessageNotification", 448);
				return;
			}
			ChannelChatMessageEvent e;
			try
			{
				e = val.ToObject<ChannelChatMessageEvent>();
			}
			catch (JsonException val2)
			{
				JsonException arg = val2;
				Log.Error_NoCallerPrefix($"Failed to deserialize chat message: {arg}");
				return;
			}
			this.OnChannelChatMessage?.Invoke(this, e);
		}

		private void handleChannelChatNotificationNotification(JToken jsonObject)
		{
			//IL_003d: Expected O, but got Unknown
			if (this.OnChannelChatNotification == null)
			{
				return;
			}
			JToken val = jsonObject.SelectToken("payload.event");
			if (val == null)
			{
				Log.Error("Failed to find event object", "D:\\Git\\RiskOfChaos\\Solution\\RiskOfTwitch\\EventSub\\TwitchEventSubClient.cs", "handleChannelChatNotificationNotification", 474);
				return;
			}
			ChannelChatNotificationEvent e;
			try
			{
				e = val.ToObject<ChannelChatNotificationEvent>();
			}
			catch (JsonException val2)
			{
				JsonException arg = val2;
				Log.Error_NoCallerPrefix($"Failed to deserialize chat notification: {arg}");
				return;
			}
			this.OnChannelChatNotification?.Invoke(this, e);
		}
	}
	internal class TwitchEventSubConnection : ClientWebSocketConnection
	{
		private readonly ITwitchEventSubMessageHandler _eventHandler;

		public TwitchEventSubConnection(Uri url, ITwitchEventSubMessageHandler eventHandler)
			: base(url)
		{
			_eventHandler = eventHandler;
		}

		protected override async Task handleSocketMessageAsync(WebSocketMessage message, CancellationToken cancellationToken)
		{
			if (message.MessageType != 0)
			{
				Log.Warning($"Unhandled socket message type: {message.MessageType}", "D:\\Git\\RiskOfChaos\\Solution\\RiskOfTwitch\\EventSub\\TwitchEventSubConnection.cs", "handleSocketMessageAsync", 32);
				return;
			}
			using MemoryStream memoryStream = new MemoryStream(message.MessageData.Array, message.MessageData.Offset, message.MessageData.Count);
			using StreamReader streamReader = new StreamReader(memoryStream, Encoding.UTF8);
			JsonTextReader jsonReader = new JsonTextReader((TextReader)streamReader);
			try
			{
				JToken deserializedMessage;
				try
				{
					deserializedMessage = await JToken.ReadFromAsync((JsonReader)(object)jsonReader, cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
				}
				catch (JsonException val)
				{
					JsonException arg = val;
					Log.Error_NoCallerPrefix($"Failed to deserialize web socket message: {arg}");
					return;
				}
				Task.Run(async delegate
				{
					await _eventHandler.HandleEventAsync(deserializedMessage, cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
				});
			}
			finally
			{
				((IDisposable)jsonReader)?.Dispose();
			}
		}

		protected override bool shouldReconnect(WebSocketMessage closingMessage)
		{
			if (closingMessage.CloseStatus.HasValue)
			{
				switch (closingMessage.CloseStatus.Value)
				{
				case (WebSocketCloseStatus)4003:
				case (WebSocketCloseStatus)4004:
					return false;
				}
			}
			return base.shouldReconnect(closingMessage);
		}
	}
	[Serializable]
	public class WebSocketSessionData
	{
		[JsonProperty("id")]
		public string SessionID { get; set; }

		[JsonProperty("status")]
		public string Status { get; set; }

		[JsonProperty("connected_at")]
		public string ConnectedAt { get; set; }

		[JsonProperty("keepalive_timeout_seconds")]
		public int? KeepaliveTimeoutSeconds { get; set; }

		[JsonProperty("reconnect_url")]
		public string ReconnectUrl { get; set; }
	}
}
namespace RiskOfTwitch.Emotes
{
	public class EmoteSetEmoteData
	{
		[JsonProperty("id")]
		public string EmoteId { get; set; }

		[JsonProperty("name")]
		public string EmoteName { get; set; }

		[JsonProperty("images")]
		public EmoteSetEmoteImageData ImageData { get; set; }

		[JsonProperty("emote_type")]
		public string EmoteType { get; set; }

		[JsonProperty("emote_set_id")]
		public string EmoteSetId { get; set; }

		[JsonProperty("owner_id")]
		public string EmoteOwnerId { get; set; }

		[JsonProperty("format")]
		public string[] EmoteFormats { get; set; }

		[JsonProperty("scale")]
		public string[] Scales { get; set; }

		[JsonProperty("theme_mode")]
		public string[] ThemeModes { get; set; }
	}
	public class EmoteSetEmoteImageData
	{
		[JsonProperty("url_1x")]
		public string SmallUrl { get; set; }

		[JsonProperty("url_2x")]
		public string MediumUrl { get; set; }

		[JsonProperty("url_4x")]
		public string LargeUrl { get; set; }
	}
	public class GetEmoteSetResponse
	{
		public static GetEmoteSetResponse Empty { get; } = new GetEmoteSetResponse
		{
			Emotes = Array.Empty<EmoteSetEmoteData>(),
			UrlTemplate = string.Empty
		};


		[JsonProperty("data")]
		public EmoteSetEmoteData[] Emotes { get; set; }

		[JsonProperty("template")]
		public string UrlTemplate { get; set; }

		public bool TryFindEmote(string emoteId, out EmoteSetEmoteData emote)
		{
			EmoteSetEmoteData[] emotes = Emotes;
			foreach (EmoteSetEmoteData emoteSetEmoteData in emotes)
			{
				if (string.Equals(emoteSetEmoteData.EmoteId, emoteId, StringComparison.Ordinal))
				{
					emote = emoteSetEmoteData;
					return true;
				}
			}
			emote = null;
			return false;
		}

		public string GetEmoteFetchUrl(EmoteSetEmoteData emote, string format, string theme, string scale)
		{
			return UrlTemplate.Replace("{{id}}", emote.EmoteId).Replace("{{format}}", format).Replace("{{theme_mode}}", theme)
				.Replace("{{scale}}", scale);
		}
	}
}
namespace RiskOfTwitch.Chat
{
	public class ChannelChatClearUserMessagesEvent
	{
		[JsonProperty("broadcaster_user_id")]
		public string BroadcasterUserId { get; set; }

		[JsonProperty("broadcaster_user_name")]
		public string BroadcasterDisplayName { get; set; }

		[JsonProperty("broadcaster_user_login")]
		public string BroadcasterLoginName { get; set; }

		[JsonProperty("target_user_id")]
		public string TargetUserId { get; set; }

		[JsonProperty("target_user_name")]
		public string TargetUserDisplayName { get; set; }

		[JsonProperty("target_user_login")]
		public string TargetUserLoginName { get; set; }
	}
	public class ChatterBadgeData
	{
		[JsonProperty("set_id")]
		public string BadgeSetID { get; set; }

		[JsonProperty("id")]
		public string BadgeID { get; set; }

		[JsonProperty("info")]
		public string BadgeMetadata { get; set; }
	}
}
namespace RiskOfTwitch.Chat.Notification
{
	public class ChannelChatAnnouncementNotificationData
	{
		[JsonProperty("color")]
		public string Color { get; set; }
	}
	public class ChannelChatBitsBadgeTierNotificationData
	{
		[JsonProperty("tier")]
		public int Tier { get; set; }
	}
	public class ChannelChatCharityDonationAmountData
	{
		[JsonProperty("value")]
		public int Value { get; set; }

		[JsonProperty("decimal_place")]
		public int DecimalPlace { get; set; }

		[JsonProperty("currency")]
		public string CurrencyCode { get; set; }
	}
	public class ChannelChatCharityDonationNotificationData
	{
		[JsonProperty("charity_name")]
		public string CharityName { get; set; }

		[JsonProperty("amount")]
		public ChannelChatCharityDonationAmountData Amount { get; set; }
	}
	public class ChannelChatCommunitySubGiftNotificationData
	{
		[JsonProperty("id")]
		public string Id { get; set; }

		[JsonProperty("total")]
		public int Amount { get; set; }

		[JsonProperty("sub_tier")]
		public string SubTier { get; set; }

		[JsonProperty("cumulative_total")]
		public int? TotalGiftedByUser { get; set; }
	}
	public class ChannelChatGiftPaidUpgradeNotificationData
	{
		[JsonProperty("gifter_is_anonymous")]
		public bool GifterIsAnonymous { get; set; }

		[JsonProperty("gifter_user_id")]
		public string GifterUserId { get; set; }

		[JsonProperty("gifter_user_name")]
		public string GifterDisplayName { get; set; }

		[JsonProperty("gifter_user_login")]
		public string GifterLoginName { get; set; }
	}
	public class ChannelChatNotificationEvent
	{
		[JsonProperty("broadcaster_user_id")]
		public string BroadcasterUserId { get; set; }

		[JsonProperty("broadcaster_user_name")]
		public string BroadcasterDisplayName { get; set; }

		[JsonProperty("broadcaster_user_login")]
		public string BroadcasterLoginName { get; set; }

		[JsonProperty("chatter_user_id")]
		public string ChatterUserId { get; set; }

		[JsonProperty("chatter_user_name")]
		public string ChatterDisplayName { get; set; }

		[JsonProperty("chatter_user_login")]
		public string ChatterLoginName { get; set; }

		[JsonProperty("chatter_is_anonymous")]
		public bool AnonymousChatter { get; set; }

		[JsonProperty("color")]
		public string ChatterNameColor { get; set; }

		[JsonProperty("badges")]
		public ChatterBadgeData[] Badges { get; set; }

		[JsonProperty("system_message")]
		public string SystemMessage { get; set; }

		[JsonProperty("message_id")]
		public string MessageId { get; set; }

		[JsonProperty("message")]
		public ChannelChatMessageData MessageData { get; set; }

		[JsonProperty("notice_type")]
		public string NoticeType { get; set; }

		[JsonProperty("sub")]
		public ChannelChatSubNotificationData SubData { get; set; }

		[JsonProperty("resub")]
		public ChannelChatResubNotificationData ResubData { get; set; }

		[JsonProperty("sub_gift")]
		public ChannelChatSubGiftNotificationData SubGiftData { get; set; }

		[JsonProperty("community_sub_gift")]
		public ChannelChatCommunitySubGiftNotificationData CommunitySubGiftData { get; set; }

		[JsonProperty("gift_paid_upgrade")]
		public ChannelChatGiftPaidUpgradeNotificationData GiftPaidUpgradeData { get; set; }

		[JsonProperty("prime_paid_upgrade")]
		public ChannelChatPrimePaidUpgradeNotificationData PrimePaidUpgradeData { get; set; }

		[JsonProperty("raid")]
		public ChannelChatRaidNotificationData RaidData { get; set; }

		[JsonProperty("unraid")]
		public ChannelChatUnraidNotificationData UnraidData { get; set; }

		[JsonProperty("pay_it_forward")]
		public ChannelChatPayItForwardNotificationData PayItForwardData { get; set; }

		[JsonProperty("announcement")]
		public ChannelChatAnnouncementNotificationData AnnouncementData { get; set; }

		[JsonProperty("charity_donation")]
		public ChannelChatCharityDonationNotificationData CharityDonationData { get; set; }

		[JsonProperty("bits_badge_tier")]
		public ChannelChatBitsBadgeTierNotificationData ChatBitsBadgeTierData { get; set; }
	}
	public class ChannelChatPayItForwardNotificationData
	{
		[JsonProperty("gifter_is_anonymous")]
		public bool GifterIsAnonymous { get; set; }

		[JsonProperty("gifter_user_id")]
		public string GifterUserId { get; set; }

		[JsonProperty("gifter_user_name")]
		public string GifterDisplayName { get; set; }

		[JsonProperty("gifter_user_login")]
		public string GifterLoginName { get; set; }
	}
	public class ChannelChatPrimePaidUpgradeNotificationData
	{
		[JsonProperty("sub_tier")]
		public string Tier { get; set; }
	}
	public class ChannelChatRaidNotificationData
	{
		[JsonProperty("user_id")]
		public string RaiderUserId { get; set; }

		[JsonProperty("user_name")]
		public string RaiderDisplayName { get; set; }

		[JsonProperty("user_login")]
		public string RaiderLoginName { get; set; }

		[JsonProperty("viewer_count")]
		public int NumViewers { get; set; }

		[JsonProperty("profile_image_url")]
		public string RaiderProfileImageUrl { get; set; }
	}
	public class ChannelChatResubNotificationData
	{
		[JsonProperty("cumulative_months")]
		public int CumulativeMonths { get; set; }

		[JsonProperty("duration_months")]
		public int DurationMonths { get; set; }

		[JsonProperty("streak_months")]
		public int? StreakMonths { get; set; }

		[JsonProperty("sub_tier")]
		public string Tier { get; set; }

		[JsonProperty("is_prime")]
		public bool? IsPrime { get; set; }

		[JsonProperty("is_gift")]
		public bool IsGifted { get; set; }

		[JsonProperty("gifter_is_anonymous")]
		public bool? GifterIsAnonymous { get; set; }

		[JsonProperty("gifter_user_id")]
		public string GifterUserId { get; set; }

		[JsonProperty("gifter_user_name")]
		public string GifterDisplayName { get; set; }

		[JsonProperty("gifter_user_login")]
		public string GifterLoginName { get; set; }
	}
	public class ChannelChatSubGiftNotificationData
	{
		[JsonProperty("duration_months")]
		public int DurationMonths { get; set; }

		[JsonProperty("cumulative_total")]
		public int? TotalSubsGivenByUser { get; set; }

		[JsonProperty("recipient_user_id")]
		public string RecipientUserId { get; set; }

		[JsonProperty("recipient_user_name")]
		public string RecipientDisplayName { get; set; }

		[JsonProperty("recipient_user_login")]
		public string RecipientLoginName { get; set; }

		[JsonProperty("sub_tier")]
		public string SubTier { get; set; }

		[JsonProperty("community_gift_id")]
		public string CommunityGiftId { get; set; }
	}
	public class ChannelChatSubNotificationData
	{
		[JsonProperty("sub_tier")]
		public string Tier { get; set; }

		[JsonProperty("is_prime")]
		public bool IsPrime { get; set; }

		[JsonProperty("duration_months")]
		public int DurationMonths { get; set; }
	}
	public class ChannelChatUnraidNotificationData
	{
	}
}
namespace RiskOfTwitch.Chat.Message
{
	public class ChannelChatMessageData
	{
		[JsonProperty("text")]
		public string FullText { get; set; }

		[JsonProperty("fragments")]
		public ChatMessageFragment[] Fragments { get; set; }
	}
	public class ChannelChatMessageEvent
	{
		[JsonProperty("broadcaster_user_id")]
		public string BroadcasterUserId { get; set; }

		[JsonProperty("broadcaster_user_name")]
		public string BroadcasterDisplayName { get; set; }

		[JsonProperty("broadcaster_user_login")]
		public string BroadcasterLoginName { get; set; }

		[JsonProperty("chatter_user_id")]
		public string ChatterUserId { get; set; }

		[JsonProperty("chatter_user_name")]
		public string ChatterDisplayName { get; set; }

		[JsonProperty("chatter_user_login")]
		public string ChatterLoginName { get; set; }

		[JsonProperty("message")]
		public ChannelChatMessageData MessageData { get; set; }

		[JsonProperty("message_type")]
		public string MessageType { get; set; }

		[JsonProperty("badges")]
		public ChatterBadgeData[] UserBadges { get; set; }

		[JsonProperty("cheer")]
		public ChatMessageCheerData CheerData { get; set; }

		[JsonProperty("color")]
		public string UserColor { get; set; }

		[JsonProperty("reply")]
		public ChatMessageReplyData ReplyData { get; set; }

		[JsonProperty("channel_points_custom_reward_id")]
		public string ChannelPointRedeemID { get; set; }
	}
	public class ChatMessageCheerData
	{
		[JsonProperty("bits")]
		public int TotalBits { get; set; }
	}
	public class ChatMessageCheermoteData
	{
		[JsonProperty("prefix")]
		public string Prefix { get; set; }

		[JsonProperty("bits")]
		public int BitAmount { get; set; }

		[JsonProperty("tier")]
		public int Tier { get; set; }
	}
	public class ChatMessageEmoteData
	{
		private static readonly string[] _emoteModificationSuffixes = new string[5] { "_BW", "_HF", "_SG", "_SQ", "_TK" };

		private string _emoteID;

		[JsonProperty("id")]
		public string EmoteID
		{
			get
			{
				return _emoteID;
			}
			set
			{
				_emoteID = value;
				string text = _emoteID;
				string[] emoteModificationSuffixes = _emoteModificationSuffixes;
				foreach (string text2 in emoteModificationSuffixes)
				{
					if (text.EndsWith(text2))
					{
						text = text.Remove(text.Length - text2.Length);
						break;
					}
				}
				BaseEmoteID = text;
			}
		}

		[JsonIgnore]
		public string BaseEmoteID { get; private set; }

		[JsonProperty("emote_set_id")]
		public string EmoteSetID { get; set; }

		[JsonProperty("owner_id")]
		public string EmoteOwnerUserID { get; set; }

		[JsonProperty("format")]
		public string[] EmoteTypes { get; set; }
	}
	public class ChatMessageFragment
	{
		[JsonProperty("type")]
		public string FragmentType { get; set; }

		[JsonProperty("text")]
		public string FragmentText { get; set; }

		[JsonProperty("cheermote")]
		public ChatMessageCheermoteData CheermoteData { get; set; }

		[JsonProperty("emote")]
		public ChatMessageEmoteData EmoteData { get; set; }

		[JsonProperty("mention")]
		public ChatMessageMentionData MentionData { get; set; }
	}
	public class ChatMessageMentionData
	{
		[JsonProperty("user_id")]
		public string MentionedUserID { get; set; }

		[JsonProperty("user_name")]
		public string MentionedUserDisplayName { get; set; }

		[JsonProperty("user_login")]
		public string MentionedUserLoginName { get; set; }
	}
	public class ChatMessageReplyData
	{
		[JsonProperty("parent_message_id")]
		public string ReplyingToMessageID { get; set; }

		[JsonProperty("parent_message_body")]
		public string ReplyingToMessageBody { get; set; }

		[JsonProperty("parent_user_id")]
		public string ReplyingToUserID { get; set; }

		[JsonProperty("parent_user_name")]
		public string ReplyingToUserDisplayName { get; set; }

		[JsonProperty("parent_user_login")]
		public string ReplyingToUserLoginName { get; set; }

		[JsonProperty("thread_message_id")]
		public string ThreadRootMessageID { get; set; }

		[JsonProperty("thread_user_id")]
		public string ThreadRootUserID { get; set; }

		[JsonProperty("thread_user_name")]
		public string ThreadRootUserDisplayName { get; set; }

		[JsonProperty("thread_user_login")]
		public string ThreadRootUserLoginName { get; set; }
	}
}