Decompiled source of SuperQoLity v0.8.760001

BepInEx/plugins/es.damntry.SuperQoLity/Damntry.Globals.BepInEx.dll

Decompiled a week ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using Damntry.Utils.ExtensionMethods;
using Damntry.Utils.Logging;
using Damntry.Utils.Maths;
using Damntry.Utils.Reflection;
using Damntry.UtilsBepInEx.Configuration.ConfigurationManager;
using Damntry.UtilsBepInEx.Configuration.ConfigurationManager.Patch;
using Damntry.UtilsBepInEx.Configuration.ConfigurationManager.SettingAttributes;
using Damntry.UtilsBepInEx.HarmonyPatching.Attributes;
using Damntry.UtilsBepInEx.HarmonyPatching.AutoPatching.Attributes;
using Damntry.UtilsBepInEx.HarmonyPatching.AutoPatching.BaseClasses;
using Damntry.UtilsBepInEx.HarmonyPatching.AutoPatching.Interfaces;
using Damntry.UtilsBepInEx.HarmonyPatching.Exceptions;
using Damntry.UtilsBepInEx.IL;
using Damntry.UtilsBepInEx.MirrorNetwork.Attributes;
using Damntry.UtilsBepInEx.MirrorNetwork.Components;
using Damntry.UtilsBepInEx.MirrorNetwork.Helpers;
using Damntry.UtilsBepInEx.MirrorNetwork.SyncVar;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Mirror;
using Mono.Cecil;
using Mono.Cecil.Cil;
using Mono.Collections.Generic;
using MonoMod.Utils;
using Newtonsoft.Json;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("Damntry BepInEx Globals")]
[assembly: AssemblyDescription("Utils usable in any type of BepInEx project")]
[assembly: AssemblyCompany("Damntry")]
[assembly: AssemblyProduct("Damntry BepInEx Globals")]
[assembly: AssemblyCopyright("Copyright © Damntry 2025")]
[assembly: AssemblyFileVersion("0.5.9.3")]
[assembly: TargetFramework(".NETFramework,Version=v4.8.1", FrameworkDisplayName = ".NET Framework 4.8.1")]
[assembly: AssemblyVersion("0.5.9.3")]
[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 Damntry.UtilsBepInEx.ModHelpers
{
	public abstract class ExternalModHelper
	{
		protected enum ModLoadStatus
		{
			NotLoaded,
			DifferentVersion,
			LoadedOk
		}

		protected ModLoadStatus ModStatus { get; private set; }

		public bool IsModLoadedAndEnabled => ModStatus != ModLoadStatus.NotLoaded;

		public ModInfoData ModInfo { get; private set; }

		private ExternalModHelper()
		{
		}

		public ExternalModHelper(string GUID, string modName, Version supportedVersion)
		{
			checkArgsForErrors(GUID, modName, supportedVersion);
			Init(GUID, modName, supportedVersion);
		}

		public ExternalModHelper(string GUID, string modName, string supportedVersion)
		{
			checkArgsForErrors(GUID, modName, supportedVersion, out var parsedSupportedVersion);
			Init(GUID, modName, parsedSupportedVersion);
		}

		private void checkArgsForErrors(string GUID, string modName, string supportedVersion, out Version parsedSupportedVersion)
		{
			if (supportedVersion == null)
			{
				throw new ArgumentNullException("supportedVersion");
			}
			if (!Version.TryParse(supportedVersion, out parsedSupportedVersion))
			{
				throw new ArgumentException("The arg supportedVersion doesnt have a valid Version format.");
			}
			checkArgsForErrors(GUID, modName, parsedSupportedVersion);
		}

		private void checkArgsForErrors(string GUID, string modName, Version supportedVersion)
		{
			if (GUID == null)
			{
				throw new ArgumentNullException("GUID");
			}
			if (modName == null)
			{
				throw new ArgumentNullException("modName");
			}
			if (supportedVersion == null)
			{
				throw new ArgumentNullException("supportedVersion");
			}
		}

		private void Init(string GUID, string modName, Version supportedVersion)
		{
			ModInfo = new ModInfoData(GUID, modName, supportedVersion);
			ModStatus = IsModLoaded();
		}

		protected virtual ModLoadStatus IsModLoaded()
		{
			if (Chainloader.PluginInfos.TryGetValue(ModInfo.GUID, out var value))
			{
				ModInfo.LoadedVersion = value.Metadata.Version;
				if (ModInfo.LoadedVersion != ModInfo.SupportedVersion)
				{
					return ModLoadStatus.DifferentVersion;
				}
				return ModLoadStatus.LoadedOk;
			}
			return ModLoadStatus.NotLoaded;
		}
	}
	public class ModInfoData
	{
		public string GUID { get; internal set; }

		public string Name { get; internal set; }

		public Version SupportedVersion { get; internal set; }

		public Version LoadedVersion { get; internal set; }

		internal ModInfoData(string GUID, string modName, Version SupportedVersion)
		{
			this.GUID = GUID;
			Name = modName;
			this.SupportedVersion = SupportedVersion;
		}

		public ModInfoData(ModInfoData modInfo)
		{
			GUID = modInfo.GUID;
			Name = modInfo.Name;
			SupportedVersion = modInfo.SupportedVersion;
			LoadedVersion = modInfo.LoadedVersion;
		}
	}
}
namespace Damntry.UtilsBepInEx.MirrorNetwork.SyncVar
{
	public interface ISyncVar
	{
		void SetToDefaultValue();

		bool Writable();

		void InitializeSyncObject(NetworkBehaviour netBehaviour);
	}
	[Serializable]
	public class SyncVar<T> : SyncObject, ISyncVar, IEquatable<T>
	{
		[SerializeField]
		protected T _Value;

		private NetworkBehaviour networkBehaviourContainer;

		public Action<T, T> OnValueChangedCallback;

		private bool hookGuard;

		public virtual T Value
		{
			[MethodImpl(MethodImplOptions.AggressiveInlining)]
			get
			{
				return _Value;
			}
			set
			{
				SetValue(value, checkWritable: true);
			}
		}

		public T DefaultValue { get; private set; }

		protected void SetValue(T value, bool checkWritable)
		{
			if ((!checkWritable || Writable()) && !Equals(value))
			{
				T value2 = _Value;
				_Value = value;
				if (base.OnDirty != null)
				{
					base.OnDirty();
				}
				if (!hookGuard && (Object)(object)networkBehaviourContainer != (Object)null && !networkBehaviourContainer.authority)
				{
					hookGuard = true;
					InvokeCallback(value2, value);
					hookGuard = false;
				}
			}
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		protected virtual void InvokeCallback(T oldValue, T newValue)
		{
			OnValueChangedCallback?.Invoke(oldValue, newValue);
		}

		public override void ClearChanges()
		{
		}

		public override void Reset()
		{
		}

		public virtual void SetToDefaultValue()
		{
			NetworkSpawnManager.DebugLog(() => $"Setting SyncVar from {_Value} to its DefaultValue {DefaultValue}");
			_Value = DefaultValue;
		}

		public SyncVar(T defaultValue)
		{
			InitValues(defaultValue, defaultValue, null);
		}

		public SyncVar(T value, T defaultValue)
		{
			InitValues(value, defaultValue, null);
		}

		public SyncVar(T value, T defaultValue, Action<T, T> onValueChangedCallback)
		{
			OnValueChangedCallback = (Action<T, T>)Delegate.Combine(OnValueChangedCallback, onValueChangedCallback);
			InitValues(value, defaultValue, null);
		}

		public SyncVar(NetworkBehaviour netBehaviour, T value, T defaultValue)
		{
			if ((Object)(object)netBehaviour == (Object)null)
			{
				throw new ArgumentNullException("netBehaviour");
			}
			InitValues(value, defaultValue, netBehaviour);
		}

		public SyncVar(NetworkBehaviour netBehaviour, T value, T defaultValue, Action<T, T> onValueChangedCallback)
		{
			if ((Object)(object)netBehaviour == (Object)null)
			{
				throw new ArgumentNullException("netBehaviour");
			}
			OnValueChangedCallback = (Action<T, T>)Delegate.Combine(OnValueChangedCallback, onValueChangedCallback);
			InitValues(value, defaultValue, netBehaviour);
		}

		private void InitValues(T value, T defaultValue, NetworkBehaviour netBehaviour)
		{
			_Value = value;
			DefaultValue = defaultValue;
			if (typeof(T).IsEnum)
			{
				RegisterCustomEnum(value);
			}
			if ((Object)(object)netBehaviour != (Object)null)
			{
				InitSyncObjectReflection(netBehaviour);
			}
		}

		private void RegisterCustomEnum<TEnum>(TEnum value)
		{
			if (Writer<TEnum>.write == null)
			{
				Writer<TEnum>.write = delegate(NetworkWriter writer, TEnum value)
				{
					NetworkWriterExtensions.WriteLong(writer, EnumExtension.EnumToLong<TEnum>(value));
				};
			}
			if (Reader<TEnum>.read == null)
			{
				Reader<TEnum>.read = (NetworkReader reader) => EnumExtension.LongToEnumUnconstrained<TEnum>(NetworkReaderExtensions.ReadLong(reader));
			}
		}

		public bool Writable()
		{
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Invalid comparison between Unknown and I4
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Invalid comparison between Unknown and I4
			if ((Object)(object)networkBehaviourContainer == (Object)null)
			{
				bool isNetworkOffline = !NetworkSpawnManager.IsNetworkOnline();
				NetworkSpawnManager.DebugLog(() => $"Writable returned {isNetworkOffline} for a non networked SyncVar!");
				return isNetworkOffline;
			}
			if (NetworkServer.active && NetworkClient.active)
			{
				if ((int)networkBehaviourContainer.syncDirection != 0)
				{
					return networkBehaviourContainer.netIdentity.isOwned;
				}
				return true;
			}
			if (NetworkServer.active)
			{
				return (int)networkBehaviourContainer.syncDirection == 0;
			}
			if (NetworkClient.active)
			{
				if (networkBehaviourContainer.netIdentity.netId != 0)
				{
					if ((int)networkBehaviourContainer.syncDirection == 1)
					{
						return networkBehaviourContainer.netIdentity.isOwned;
					}
					return false;
				}
				return true;
			}
			return true;
		}

		public virtual void InitializeSyncObject(NetworkBehaviour netBehaviour)
		{
			InitSyncObjectReflection(netBehaviour);
		}

		protected void InitSyncObjectReflection(NetworkBehaviour netBehaviour)
		{
			networkBehaviourContainer = netBehaviour;
			NetworkSpawnManager.DebugLog(() => "Initializing SyncVar of Value type " + typeof(T).Name + " in " + ((Object)netBehaviour).name);
			ReflectionHelper.CallMethod((object)netBehaviour, "InitSyncObject", new object[1] { this });
			NetworkSpawnManager.DebugLog(() => "Finished initializing SyncVar of Value type " + typeof(T).Name + " in " + ((Object)netBehaviour).name);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static implicit operator T(SyncVar<T> field)
		{
			return field.Value;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static implicit operator SyncVar<T>(T value)
		{
			return new SyncVar<T>(value);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public override void OnSerializeAll(NetworkWriter writer)
		{
			writer.Write<T>(Value);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public override void OnSerializeDelta(NetworkWriter writer)
		{
			writer.Write<T>(Value);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public override void OnDeserializeAll(NetworkReader reader)
		{
			SetValue(reader.Read<T>(), checkWritable: false);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public override void OnDeserializeDelta(NetworkReader reader)
		{
			SetValue(reader.Read<T>(), checkWritable: false);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public bool Equals(T other)
		{
			return EqualityComparer<T>.Default.Equals(Value, other);
		}

		public override string ToString()
		{
			return Value.ToString();
		}
	}
	public class SyncVarSetting<T> : SyncVar<T>, ISyncVar
	{
		public ConfigEntry<T> ConfigEntry { get; private set; }

		public SyncVarSetting(T defaultValue, ConfigEntry<T> configEntry)
			: base(defaultValue, defaultValue)
		{
			Init(configEntry);
		}

		public SyncVarSetting(T defaultValue, Action<T, T> onValueChangedCallback, ConfigEntry<T> configEntry)
			: base(defaultValue, defaultValue, onValueChangedCallback)
		{
			Init(configEntry);
		}

		private void Init(ConfigEntry<T> configEntry)
		{
			if (configEntry == null)
			{
				throw new ArgumentNullException("configEntry", "SyncVarSetting ConfigEntry cannot be null. Make sure that Bepinex config binding has been completed successfully before this call. If not using a ConfigEntry is intended, use SyncVar instead.");
			}
			NetworkSpawnManager.DebugLog(() => "SyncVarSetting constructor. " + $"Setting SyncVar to its configEntry value ({configEntry.Value}).");
			ConfigEntry = configEntry;
			_Value = configEntry.Value;
			RegisterSyncvarSetting();
		}

		public void RegisterSyncvarSetting()
		{
			UnregisterSyncvarSetting();
			ConfigEntry.SettingChanged += SetValueFromConfig;
		}

		public void UnregisterSyncvarSetting()
		{
			ConfigEntry.SettingChanged -= SetValueFromConfig;
		}

		public override void InitializeSyncObject(NetworkBehaviour netBehaviour)
		{
			InitSyncObjectReflection(netBehaviour);
			NetworkSpawnManager.DebugLog(() => "SyncVarSetting fully initialized. " + $"Setting SyncVar from {_Value} to its configEntry value ({ConfigEntry.Value}).");
			SetValueFromConfig();
		}

		private void SetValueFromConfig(object sender, EventArgs e)
		{
			SetValueFromConfig();
		}

		public void SetValueFromConfig()
		{
			Value = ConfigEntry.Value;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static implicit operator T(SyncVarSetting<T> field)
		{
			return field.Value;
		}
	}
}
namespace Damntry.UtilsBepInEx.MirrorNetwork.Helpers
{
	public static class NetworkPrefabHelper
	{
		private static readonly string NetworkRootObjName = "NetworkedObjects";

		public static GameObject GetNetworkReadyPrefab<T>(string prefabName, out NetworkBehaviour networkBehaviour) where T : NetworkBehaviour
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Expected O, but got Unknown
			GameObject val = new GameObject(prefabName);
			val.SetActive(false);
			val.transform.parent = GetRootNetworkTransform();
			val.AddComponent<NetworkIdentity>();
			networkBehaviour = (NetworkBehaviour)(object)val.AddComponent<T>();
			return val;
		}

		private static Transform GetRootNetworkTransform()
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Expected O, but got Unknown
			GameObject val = GameObject.Find(NetworkRootObjName);
			if (val == null)
			{
				val = new GameObject(NetworkRootObjName);
			}
			return val.transform;
		}

		public static bool AssetIdExists(uint assetId)
		{
			return NetworkClient.prefabs.ContainsKey(assetId);
		}

		public static bool IsPrefabGameObjectRegistered(GameObject prefabObj, uint expectedAssetId)
		{
			if (NetworkClient.prefabs != null && NetworkClient.prefabs.TryGetValue(expectedAssetId, out var value))
			{
				return prefabObj == value;
			}
			return false;
		}

		public static bool IsPrefabHandlerRegistered(SpawnHandlerDelegate spawnHandlerDelegate, uint expectedAssetId)
		{
			if (FindSpawnhandlerByAssetId(expectedAssetId, out var IsFieldNotFound, out var spawnDelegate))
			{
				return spawnHandlerDelegate == spawnDelegate;
			}
			return IsFieldNotFound;
		}

		public static bool FindSpawnhandlerByAssetId(uint assetId, out bool IsFieldNotFound, out SpawnHandlerDelegate spawnDelegate)
		{
			spawnDelegate = null;
			IsFieldNotFound = false;
			try
			{
				string text = "spawnHandlers";
				FieldInfo field = typeof(NetworkClient).GetField("spawnHandlers", AccessTools.all);
				if (field != null)
				{
					return ((Dictionary<uint, SpawnHandlerDelegate>)field.GetValue(null)).TryGetValue(assetId, out spawnDelegate);
				}
				TimeLogger.Logger.LogTimeError("The field " + text + " could not be found in type " + typeof(NetworkClient).Name + ".", (LogCategories)512);
			}
			catch (Exception ex)
			{
				TimeLogger.Logger.LogTimeException(ex, (LogCategories)512);
			}
			IsFieldNotFound = true;
			return false;
		}
	}
	public interface INetworkPrefabSpawner
	{
		Type NetworkBehaviourType { get; }

		uint DefinedAssetId { get; }

		void AddToPrefabs();

		void Spawn();
	}
	public class NetworkPrefabSpawner<T> : INetworkPrefabSpawner where T : NetworkBehaviour
	{
		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static UnSpawnDelegate <>9__15_1;

			internal void <AddToPrefabs>b__15_1(GameObject spawned)
			{
			}
		}

		private GameObject prefabObj;

		private NetworkBehaviour networkBehaviourInstance;

		public uint DefinedAssetId { get; init; }

		public bool PrefabRegisterOk { get; private set; }

		public Type NetworkBehaviourType { get; private set; }

		public NetworkPrefabSpawner(uint assetId)
		{
			NetworkBehaviourType = typeof(T);
			DefinedAssetId = assetId;
		}

		public void AddToPrefabs()
		{
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Expected O, but got Unknown
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Expected O, but got Unknown
			string typeName = NetworkBehaviourType.Name;
			prefabObj = NetworkPrefabHelper.GetNetworkReadyPrefab<T>(typeName, out networkBehaviourInstance);
			if ((Object)(object)prefabObj == (Object)null)
			{
				TimeLogger.Logger.LogTimeError("A prefab object couldnt be created from type " + typeName, (LogCategories)512);
				return;
			}
			uint definedAssetId = DefinedAssetId;
			if (NetworkPrefabHelper.AssetIdExists(definedAssetId))
			{
				TimeLogger.Logger.LogTimeError($"The specified assetId \"{definedAssetId}\" for the NetworkBehaviour " + "class " + typeName + " was already found in the NetworkClient.", (LogCategories)512);
				return;
			}
			SpawnHandlerDelegate val = (SpawnHandlerDelegate)((SpawnMessage msg) => prefabObj);
			object obj = <>c.<>9__15_1;
			if (obj == null)
			{
				UnSpawnDelegate val2 = delegate
				{
				};
				<>c.<>9__15_1 = val2;
				obj = (object)val2;
			}
			UnSpawnDelegate val3 = (UnSpawnDelegate)obj;
			NetworkClient.RegisterPrefab(prefabObj, DefinedAssetId, val, val3);
			PrefabRegisterOk = NetworkPrefabHelper.IsPrefabHandlerRegistered(val, DefinedAssetId);
			if (!PrefabRegisterOk)
			{
				NetworkSpawnManager.DebugLog(() => "Prefab NOT registered for NetworkBehaviour " + typeName + ".");
				return;
			}
			NetworkSpawnManager.DebugLog(() => "Prefab was registered correctly for NetworkBehaviour " + typeName + ".");
			TriggerStartNetworkSession(NetworkSpawnManager.GetCurrentNetworkMode());
		}

		private void TriggerStartNetworkSession(NetworkMode networkMode)
		{
			if (typeof(ISyncVarBehaviour).IsAssignableFrom(typeof(T)))
			{
				((ISyncVarBehaviour)networkBehaviourInstance).StartNetworkSession(networkMode);
			}
		}

		public void Spawn()
		{
			if (PrefabRegisterOk)
			{
				if ((Object)(object)prefabObj == (Object)null)
				{
					TimeLogger.Logger.LogTimeFatal("The prefab object to spawn for type " + NetworkBehaviourType.Name + ". is null. Make sure to call AddToPrefabs() before spawning happens.", (LogCategories)512);
				}
				else
				{
					NetworkServer.Spawn(prefabObj, (NetworkConnection)null);
				}
			}
		}
	}
	public enum NetworkMode
	{
		NotInitialized,
		Offline,
		ServerOnly,
		ClientOnly,
		Host
	}
	[HarmonyPatch]
	public class NetworkSpawnManager
	{
		private static readonly Harmony harmony;

		private static readonly Dictionary<Type, INetworkPrefabSpawner> networkBehaviourRegistry;

		private static uint _assetIdSignature;

		public static bool NetworkDebugLog;

		static NetworkSpawnManager()
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Expected O, but got Unknown
			NetworkDebugLog = true;
			harmony = new Harmony(typeof(NetworkSpawnManager).FullName);
			networkBehaviourRegistry = new Dictionary<Type, INetworkPrefabSpawner>();
		}

		public static bool IsNetworkActive()
		{
			if (!NetworkServer.active)
			{
				return NetworkClient.active;
			}
			return true;
		}

		public static bool IsNetworkOnline()
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Invalid comparison between Unknown and I4
			if ((Object)(object)NetworkManager.singleton != (Object)null)
			{
				return (int)NetworkManager.singleton.mode > 0;
			}
			return false;
		}

		public static bool IsNetworkOnlineHosting()
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Invalid comparison between Unknown and I4
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Invalid comparison between Unknown and I4
			if (!((Object)(object)NetworkManager.singleton != (Object)null) || (int)NetworkManager.singleton.mode != 3)
			{
				return (int)NetworkManager.singleton.mode == 1;
			}
			return true;
		}

		public static bool IsNetworkClientOnly()
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Invalid comparison between Unknown and I4
			if ((Object)(object)NetworkManager.singleton != (Object)null)
			{
				return (int)NetworkManager.singleton.mode == 2;
			}
			return false;
		}

		public static NetworkMode GetCurrentNetworkMode()
		{
			//IL_0016: 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_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Expected I4, but got Unknown
			if ((Object)(object)NetworkManager.singleton == (Object)null)
			{
				return NetworkMode.NotInitialized;
			}
			NetworkManagerMode mode = NetworkManager.singleton.mode;
			return (int)mode switch
			{
				0 => NetworkMode.Offline, 
				1 => NetworkMode.ServerOnly, 
				2 => NetworkMode.ClientOnly, 
				3 => NetworkMode.Host, 
				_ => throw new NotImplementedException(), 
			};
		}

		public static void Initialize(int assetIdSignature)
		{
			if (assetIdSignature < 1 || assetIdSignature > 4293)
			{
				TimeLogger.Logger.LogTimeFatal($"The value of assetIdSignature is {assetIdSignature} " + "but it must be between 1 and 4293, both inclusive. All related network functionality will not work.", (LogCategories)512);
				return;
			}
			_assetIdSignature = (uint)assetIdSignature;
			harmony.PatchAll(typeof(NetworkSpawnManager));
			if (!harmony.GetPatchedMethods().Any())
			{
				TimeLogger.Logger.LogTimeFatal("NetworkSpawnManager patch failed. Modded network features wont work.", (LogCategories)512);
			}
		}

		[HarmonyPatch(typeof(NetworkServer), "SpawnObjects")]
		[HarmonyPatch(typeof(NetworkClient), "PrepareToSpawnSceneObjects")]
		[HarmonyPostfix]
		public static void OnStartNetworkSessionPrefix(MethodBase __originalMethod)
		{
			DebugLog(() => "OnStartNetworkSessionPrefix - Coming from method " + $"{__originalMethod.Name} - Network mode: {NetworkManager.singleton.mode}");
			if (IsNetworkActive())
			{
				DebugLog("Mirror network system is active. Adding network spawns");
				AddNetworkSpawns();
			}
			else
			{
				DebugLog("Mirror network system is NOT active. Skipping this session initialization");
			}
		}

		public static void RegisterNetwork<T>(uint assetId) where T : NetworkBehaviour
		{
			if (assetId == 0)
			{
				throw new ArgumentException("The assetId parameter cant be 0.");
			}
			if (MathMethods.CountDigits(assetId) > 6)
			{
				throw new ArgumentException("The assetId parameter must have less than 7 digits [1 to 999999].");
			}
			Type typeFromHandle = typeof(T);
			if (networkBehaviourRegistry.ContainsKey(typeFromHandle))
			{
				throw new InvalidOperationException("The NetworkBehaviour of type " + typeFromHandle.Name + " was already registered.");
			}
			NetworkPrefabSpawner<T> value = new NetworkPrefabSpawner<T>(GetAssetIdFromSignature(assetId));
			networkBehaviourRegistry.Add(typeFromHandle, value);
		}

		private static void AddNetworkSpawns()
		{
			foreach (KeyValuePair<Type, INetworkPrefabSpawner> item in networkBehaviourRegistry)
			{
				item.Value.AddToPrefabs();
			}
			if (NetworkServer.active)
			{
				SpawnHost();
			}
		}

		private static void SpawnHost()
		{
			DebugLog(() => $"Spawning objects - NetworkServer active? {NetworkServer.active}");
			if (!NetworkServer.active)
			{
				return;
			}
			foreach (KeyValuePair<Type, INetworkPrefabSpawner> item in networkBehaviourRegistry)
			{
				item.Value.Spawn();
			}
		}

		private static uint GetAssetIdFromSignature(uint assetId)
		{
			return _assetIdSignature * 1000000 + assetId;
		}

		public static void DebugLog(Func<string> textLambda)
		{
		}

		public static void DebugLog(string text)
		{
		}
	}
}
namespace Damntry.UtilsBepInEx.MirrorNetwork.Components
{
	internal interface ISyncVarBehaviour
	{
		void StartNetworkSession(NetworkMode networkMode);
	}
	public abstract class SyncVarNetworkBehaviour<T> : NetworkBehaviour, ISyncVarBehaviour where T : SyncVarNetworkBehaviour<T>
	{
		private static readonly BindingFlags SearchFlags = BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;

		private readonly Type derivedType = typeof(T);

		private readonly List<ISyncVar> validSyncVarList = new List<ISyncVar>();

		private static readonly Dictionary<MethodBase, MethodInfo> methodRedirects = new Dictionary<MethodBase, MethodInfo>();

		private readonly Harmony harmony = new Harmony(typeof(SyncVarNetworkBehaviour<T>).FullName);

		private const bool IS_DEBUG_NETWORK_TESTS__ENABLED = false;

		protected virtual void OnStartNetworkSession(NetworkMode networkMode)
		{
		}

		protected virtual void OnSyncVarValuesDefaulted()
		{
		}

		protected virtual void OnSyncVarsNetworkReady()
		{
		}

		void ISyncVarBehaviour.StartNetworkSession(NetworkMode networkMode)
		{
			NetworkSpawnManager.DebugLog(() => "OnStartNetworkSession call begins for type " + derivedType.Name + ".");
			OnStartNetworkSession(networkMode);
			validSyncVarList.Clear();
			foreach (MemberInfoHelper item in GetDerivedSyncVarsOfType(typeof(SyncVar<>)))
			{
				if (CheckSyncVarValidity(item, out var syncVarInstance))
				{
					validSyncVarList.Add(syncVarInstance);
					syncVarInstance.SetToDefaultValue();
				}
			}
			OnSyncVarValuesDefaulted();
		}

		private void Awake()
		{
			foreach (ISyncVar validSyncVar in validSyncVarList)
			{
				InitializeSyncVar(validSyncVar, (T)this);
			}
			validSyncVarList.Clear();
			NetworkSpawnManager.DebugLog(() => "OnSyncVarsNetworkReady call begins for type " + derivedType.Name + ".");
			OnSyncVarsNetworkReady();
		}

		private List<MemberInfoHelper> GetDerivedSyncVarsOfType(Type searchType)
		{
			IEnumerable<MemberInfo> enumerable = derivedType.GetFields(SearchFlags).Cast<MemberInfo>().Concat(derivedType.GetProperties(SearchFlags))
				.Cast<MemberInfo>();
			if (enumerable == null || enumerable.Count() == 0)
			{
				return new List<MemberInfoHelper>();
			}
			return (from mif in enumerable.Where((MemberInfo mi) => ReflectionExtension.HasCustomAttribute<SyncVarNetworkAttribute>(mi)).Select((Func<MemberInfo, MemberInfoHelper>)((MemberInfo mi) => new MemberInfoHelper(mi)))
				where ReflectionExtension.IsSubclassOfRawGeneric(mif.MemberInfoType, searchType)
				select mif).ToList();
		}

		private bool CheckSyncVarValidity(MemberInfoHelper syncVarInfoHelper, out ISyncVar syncVarInstance)
		{
			syncVarInstance = null;
			Type memberInfoType = syncVarInfoHelper.MemberInfoType;
			if (!memberInfoType.IsSubclassOf(typeof(SyncObject)))
			{
				TimeLogger.Logger.LogTimeWarning("The var " + derivedType.Name + "." + ((MemberInfo)(object)syncVarInfoHelper).Name + " does not inherit from SyncObject and will be skipped. Make sure that the SyncVarNetworkAttribute annotation was intended.", (LogCategories)512);
				return false;
			}
			if (!typeof(ISyncVar).IsAssignableFrom(memberInfoType))
			{
				TimeLogger.Logger.LogTimeWarning("The var " + derivedType.Name + "." + ((MemberInfo)(object)syncVarInfoHelper).Name + " does not inherit from ISyncVar and will be skipped. Make sure that the SyncVarNetworkAttribute annotation was intended.", (LogCategories)512);
				return false;
			}
			if (memberInfoType.GetGenericArguments() == null || memberInfoType.GetGenericArguments().Length == 0)
			{
				TimeLogger.Logger.LogTimeWarning("The var " + derivedType.Name + "." + ((MemberInfo)(object)syncVarInfoHelper).Name + " does not declare any generic type parameters and will be skipped. Make sure that the type derives from SyncVar.", (LogCategories)512);
				return false;
			}
			syncVarInstance = (ISyncVar)syncVarInfoHelper.GetValueStaticAgnostic((object)(T)this);
			if (syncVarInstance == null)
			{
				TimeLogger.Logger.LogTimeWarning("The var " + derivedType.Name + "." + ((MemberInfo)(object)syncVarInfoHelper).Name + " has not been instantiated and will be skipped. Make sure to call its constructor.", (LogCategories)512);
				return false;
			}
			return true;
		}

		private void InitializeSyncVar(ISyncVar syncVarInstance, T netBehaviourInstance)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			if (!IsSyncVarNetworkInitialized((SyncObject)syncVarInstance))
			{
				syncVarInstance.InitializeSyncObject((NetworkBehaviour)(object)netBehaviourInstance);
			}
		}

		private bool IsSyncVarNetworkInitialized(SyncObject syncVarInstance)
		{
			return base.syncObjects.Contains(syncVarInstance);
		}

		private Delegate GetOnChangeDelegate(string onChangeMethodName, T netBehaviourInstance, Type syncVarType)
		{
			Type type = syncVarType.GetGenericArguments()[0];
			MethodInfo method = derivedType.GetMethod(onChangeMethodName, SearchFlags, null, new Type[2] { type, type }, null);
			if (method == null)
			{
				TimeLogger.Logger.LogTimeWarning("Method \"" + onChangeMethodName + "\" could not be found in type " + derivedType.Name + ", or does not have the required signature:  " + onChangeMethodName + "(" + syncVarType.Name + " oldValue, " + syncVarType.Name + " newValue).", (LogCategories)512);
				return null;
			}
			Delegate @delegate = Delegate.CreateDelegate(typeof(Action<, >).MakeGenericType(type, type), netBehaviourInstance, method);
			if ((object)@delegate == null)
			{
				TimeLogger.Logger.LogTimeWarning("A delegate for method \"" + derivedType.Name + "." + onChangeMethodName + "\" could not be created.", (LogCategories)512);
				return null;
			}
			return @delegate;
		}

		private void InitializeRedirectsRPC_CMD()
		{
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Expected O, but got Unknown
			List<(MethodInfo, MethodInfo)> rPC_MethodTargets = GetRPC_MethodTargets();
			LOG.TEMPWARNING($"{rPC_MethodTargets.Count} RPC methods", true);
			foreach (var item in rPC_MethodTargets)
			{
				if (!methodRedirects.ContainsKey(item.Item1))
				{
					methodRedirects.Add(item.Item1, item.Item2);
					MethodInfo method = new Func<IEnumerable<CodeInstruction>, ILGenerator, MethodBase, IEnumerable>(TranspileRPC_Call).Method;
					harmony.Patch((MethodBase)item.Item1, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(method), (HarmonyMethod)null, (HarmonyMethod)null);
				}
			}
			LOG.TEMPWARNING("Method patching finished.", true);
		}

		public override void OnStopClient()
		{
			harmony.UnpatchSelf();
			methodRedirects.Clear();
		}

		private List<(MethodInfo origMethod, MethodInfo targetMethod)> GetRPC_MethodTargets()
		{
			return (from mi in derivedType.GetMethods(SearchFlags)
				where ReflectionExtension.HasCustomAttribute<RPC_CallOnClientAttribute>((MemberInfo)mi)
				select (mi, GetMethodInfoFromRPCAttribute(mi)) into tup
				where tup.Item2 != null
				select tup).ToList();
		}

		private MethodInfo GetMethodInfoFromRPCAttribute(MethodInfo methodInfo)
		{
			RPC_CallOnClientAttribute customAttribute = methodInfo.GetCustomAttribute<RPC_CallOnClientAttribute>();
			if (Type.GetType(customAttribute.declaringType.AssemblyQualifiedName) == null)
			{
				TimeLogger.Logger.LogTimeError("The type FullName could not be found.", (LogCategories)512);
			}
			MethodInfo methodInfo2 = AccessTools.Method(customAttribute.declaringType, customAttribute.targetMethodName, customAttribute.parameters, customAttribute.generics);
			if (methodInfo2 != null && !CompareMethodSignatures(methodInfo, methodInfo2))
			{
				methodInfo2 = null;
			}
			return methodInfo2;
		}

		public static bool CompareMethodSignatures(MethodInfo mi1, MethodInfo mi2, bool compareDeclaringType = false)
		{
			List<string> list = new List<string>();
			if (mi1.IsGenericMethod || mi2.IsGenericMethod)
			{
				list.Add("generic methods not supported");
			}
			if (mi1.ReturnType != mi2.ReturnType)
			{
				list.Add("return type");
			}
			if (mi1.GetParameters().Length != mi2.GetParameters().Length)
			{
				list.Add("number of parameters");
			}
			else
			{
				for (int i = 0; i < mi1.GetParameters().Length; i++)
				{
					if (mi1.GetParameters()[i].ParameterType != mi2.GetParameters()[i].ParameterType)
					{
						list.Add($"param {i + 1} type");
					}
				}
			}
			if (mi1.IsStatic != mi2.IsStatic)
			{
				list.Add("static modifier");
			}
			if (list.Count > 0)
			{
				TimeLogger.Logger.LogTimeError("The methods " + mi1.DeclaringType.Name + "." + mi1.Name + " and " + mi2.DeclaringType.Name + "." + mi2.Name + " need to have the same method signature. Fix the following differences: " + string.Join(", ", list), (LogCategories)32);
			}
			return list.Count == 0;
		}

		[HarmonyDebug]
		private static IEnumerable TranspileRPC_Call(IEnumerable<CodeInstruction> instructions, ILGenerator generator, MethodBase originalMethod)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Expected O, but got Unknown
			methodRedirects.TryGetValue(originalMethod, out var value);
			CodeMatcher val = new CodeMatcher(instructions, (ILGenerator)null);
			LOG.TEMPWARNING("Before emitting delegate " + val.InstructionEnumeration().GetFormattedIL(), true);
			if (NetworkServer.active)
			{
				LOG.TEMPWARNING("Host. RPC network send logic.", true);
				val.Advance(1);
				InsertRPC_GenerationCall(val, generator, value.GetParameters(), value.IsStatic);
			}
			else if (NetworkClient.active)
			{
				LOG.TEMPWARNING("Client. Executing next.", true);
				EmitCallTargetMethod(val, value);
			}
			else
			{
				TimeLogger.Logger.LogTimeError("RPC method " + originalMethod.Name + " was called when no Mirror network component was active.", (LogCategories)512);
			}
			LOG.TEMPWARNING("After emitting delegate " + val.InstructionEnumeration().GetFormattedIL(), true);
			return val.InstructionEnumeration();
		}

		private static void InsertRPC_GenerationCall(CodeMatcher codeMatcher, ILGenerator generator, ParameterInfo[] parameters, bool isStatic)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Expected O, but got Unknown
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Expected O, but got Unknown
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Expected O, but got Unknown
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Expected O, but got Unknown
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Expected O, but got Unknown
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Expected O, but got Unknown
			int num = parameters.Length;
			if (num > 0)
			{
				codeMatcher.InsertAndAdvance((CodeInstruction[])(object)new CodeInstruction[1]
				{
					new CodeInstruction(OpCodes.Ldc_I4, (object)num)
				}).InsertAndAdvance((CodeInstruction[])(object)new CodeInstruction[1]
				{
					new CodeInstruction(OpCodes.Newarr, (object)typeof(object))
				});
				int num2 = ((!isStatic) ? 1 : 0);
				for (int i = 0; i < num; i++)
				{
					codeMatcher.InsertAndAdvance((CodeInstruction[])(object)new CodeInstruction[1]
					{
						new CodeInstruction(OpCodes.Dup, (object)null)
					}).InsertAndAdvance((CodeInstruction[])(object)new CodeInstruction[1]
					{
						new CodeInstruction(OpCodes.Ldc_I4, (object)i)
					}).InsertAndAdvance((CodeInstruction[])(object)new CodeInstruction[1] { CodeInstructionNew.LoadArgument(i + num2) });
					Type parameterType = parameters[i].ParameterType;
					if (parameterType.IsValueType)
					{
						codeMatcher.InsertAndAdvance((CodeInstruction[])(object)new CodeInstruction[1]
						{
							new CodeInstruction(OpCodes.Box, (object)parameterType)
						});
					}
					codeMatcher.InsertAndAdvance((CodeInstruction[])(object)new CodeInstruction[1]
					{
						new CodeInstruction(OpCodes.Stelem_Ref, (object)null)
					});
				}
			}
			codeMatcher.Insert((CodeInstruction[])(object)new CodeInstruction[1] { Transpilers.EmitDelegate<Action<object[]>>((Action<object[]>)MakeRPC_Call) });
		}

		private static void MakeRPC_Call(object[] args)
		{
			LOG.TEMPWARNING(string.Format("MakeRPC_Call - {0} ({1}) params: {2}", args.Length, args[0], string.Join(", ", args)), true);
			NetworkWriterPooled val = NetworkWriterPool.Get();
			for (int i = 0; i < args.Length; i++)
			{
				_ = args[i];
			}
			NetworkWriterPool.Return(val);
			LOG.TEMPWARNING("MakeRPC_Call finished", true);
		}

		private static void EmitCallTargetMethod(CodeMatcher codeMatcher, MethodInfo targetMethod)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Expected O, but got Unknown
			codeMatcher.End().Advance(-1);
			LoadMethodArgIntoStack(codeMatcher, targetMethod);
			codeMatcher.Insert((CodeInstruction[])(object)new CodeInstruction[1]
			{
				new CodeInstruction(OpCodes.Call, (object)targetMethod)
			});
		}

		private static void LoadMethodArgIntoStack(CodeMatcher codeMatcher, MethodInfo targetMethod)
		{
			int num = targetMethod.GetParameters().Count() + ((!targetMethod.IsStatic) ? 1 : 0);
			for (int i = 0; i < num; i++)
			{
				codeMatcher.InsertAndAdvance((CodeInstruction[])(object)new CodeInstruction[1] { CodeInstructionNew.LoadArgument(i) });
			}
		}

		[RPC_CallOnClient(typeof(SyncVarNetworkAttribute), "UpdateSupermarketNameOnClient", null)]
		private void UpdateSupermarketName(string marketName)
		{
		}

		private static void UpdateSupermarketNameOnClient()
		{
		}
	}
}
namespace Damntry.UtilsBepInEx.MirrorNetwork.Attributes
{
	[AttributeUsage(AttributeTargets.Method)]
	public class RPC_CallOnClientAttribute : Attribute
	{
		public Type declaringType;

		public string targetMethodName;

		public Type[] parameters;

		public Type[] generics;

		public RPC_CallOnClientAttribute(Type declaringType, string targetMethodName, Type[] parameters = null)
		{
			SetTargetMethod(declaringType, targetMethodName, parameters);
		}

		public RPC_CallOnClientAttribute(Type declaringType, string targetMethodName, Type[] parameters, Type[] generics)
		{
			SetTargetMethod(declaringType, targetMethodName, parameters, generics);
		}

		private void SetTargetMethod(Type declaringType, string targetMethodName, Type[] parameters = null, Type[] generics = null)
		{
			if (declaringType == null)
			{
				TimeLogger.Logger.LogTimeError("Parameter declaringType is null.", (LogCategories)512);
				return;
			}
			if (string.IsNullOrEmpty(targetMethodName))
			{
				TimeLogger.Logger.LogTimeError("Parameter targetMethodName is null or empty.", (LogCategories)512);
				return;
			}
			this.declaringType = declaringType;
			this.targetMethodName = targetMethodName;
			this.parameters = parameters;
			this.generics = generics;
		}
	}
	[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
	public class SyncVarNetworkAttribute : Attribute
	{
	}
}
namespace Damntry.UtilsBepInEx.Logging
{
	public sealed class BepInExTimeLogger : TimeLogger
	{
		private static ManualLogSource bepinexLogger;

		protected override void InitializeLogger(params object[] args)
		{
			if (args == null)
			{
				throw new ArgumentNullException("args");
			}
			if (args.Length == 0 || !(args[0] is string))
			{
				throw new ArgumentException("The argument is empty or its first index is not a string");
			}
			bepinexLogger = Logger.CreateLogSource((string)args[0]);
		}

		protected override void LogMessage(string message, LogTier logLevel)
		{
			//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)
			bepinexLogger.Log(convertLogLevel(logLevel), (object)message);
		}

		private LogLevel convertLogLevel(LogTier logLevel)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Invalid comparison between Unknown and I4
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			if ((int)logLevel == -1)
			{
				return (LogLevel)63;
			}
			return (LogLevel)logLevel;
		}
	}
}
namespace Damntry.UtilsBepInEx.IL
{
	public static class ILExtensionMethods
	{
		public static int LocalIndex(this CodeInstruction code)
		{
			if (code.opcode == OpCodes.Ldloc_0 || code.opcode == OpCodes.Stloc_0)
			{
				return 0;
			}
			if (code.opcode == OpCodes.Ldloc_1 || code.opcode == OpCodes.Stloc_1)
			{
				return 1;
			}
			if (code.opcode == OpCodes.Ldloc_2 || code.opcode == OpCodes.Stloc_2)
			{
				return 2;
			}
			if (code.opcode == OpCodes.Ldloc_3 || code.opcode == OpCodes.Stloc_3)
			{
				return 3;
			}
			if (code.opcode == OpCodes.Ldloc_S || code.opcode == OpCodes.Ldloc)
			{
				return GetLocalOperandIndex(code.operand);
			}
			if (code.opcode == OpCodes.Stloc_S || code.opcode == OpCodes.Stloc)
			{
				return GetLocalOperandIndex(code.operand);
			}
			if (code.opcode == OpCodes.Ldloca_S || code.opcode == OpCodes.Ldloca)
			{
				return GetLocalOperandIndex(code.operand);
			}
			throw new ArgumentException("Instruction is not a load or store", "code");
		}

		private static int GetLocalOperandIndex(object operand)
		{
			if (operand.GetType() == typeof(LocalBuilder))
			{
				return ((LocalBuilder)operand).LocalIndex;
			}
			return Convert.ToInt32(operand);
		}

		public static int ArgumentIndex(this CodeInstruction code)
		{
			if (code.opcode == OpCodes.Ldarg_0)
			{
				return 0;
			}
			if (code.opcode == OpCodes.Ldarg_1)
			{
				return 1;
			}
			if (code.opcode == OpCodes.Ldarg_2)
			{
				return 2;
			}
			if (code.opcode == OpCodes.Ldarg_3)
			{
				return 3;
			}
			if (code.opcode == OpCodes.Ldarg_S || code.opcode == OpCodes.Ldarg)
			{
				return Convert.ToInt32(code.operand);
			}
			if (code.opcode == OpCodes.Starg_S || code.opcode == OpCodes.Starg)
			{
				return Convert.ToInt32(code.operand);
			}
			if (code.opcode == OpCodes.Ldarga_S || code.opcode == OpCodes.Ldarga)
			{
				return Convert.ToInt32(code.operand);
			}
			throw new ArgumentException("Instruction is not a load or store", "code");
		}

		public static string GetFormattedIL(this IEnumerable<CodeInstruction> instrList)
		{
			return instrList.Aggregate("", (string combinedText, CodeInstruction instr) => combinedText + "\n" + GetFormattedILSingleLine(instr));
		}

		private static string GetFormattedILSingleLine(CodeInstruction instruction)
		{
			string text = FormatArgument(instruction.operand);
			string text2 = ((text.Length > 0) ? " " : "");
			string text3 = instruction.opcode.ToString();
			if (instruction.opcode.FlowControl == FlowControl.Branch || instruction.opcode.FlowControl == FlowControl.Cond_Branch)
			{
				text3 += " =>";
			}
			text3 = text3.PadRight(10);
			return $"{CodePos(instruction)}{text3}{text2}{text}";
		}

		private static string CodePos(CodeInstruction instruction)
		{
			return "";
		}

		private static string FormatArgument(object argument, string extra = null)
		{
			if (argument == null)
			{
				return "";
			}
			Type type = argument.GetType();
			if (argument is MethodBase methodBase)
			{
				return GeneralExtensions.FullDescription(methodBase) + ((extra != null) ? (" " + extra) : "");
			}
			if (argument is FieldInfo fieldInfo)
			{
				return GeneralExtensions.FullDescription(fieldInfo.FieldType) + " " + GeneralExtensions.FullDescription(fieldInfo.DeclaringType) + "::" + fieldInfo.Name;
			}
			if (type == typeof(Label))
			{
				return $"Label{((Label)argument).GetHashCode()}";
			}
			if (type == typeof(Label[]))
			{
				return "Labels" + string.Join(",", ((Label[])argument).Select((Label l) => l.GetHashCode().ToString()).ToArray());
			}
			if (type == typeof(LocalBuilder))
			{
				return $"{((LocalBuilder)argument).LocalIndex} ({((LocalBuilder)argument).LocalType})";
			}
			if (type == typeof(string))
			{
				return GeneralExtensions.ToLiteral(argument.ToString(), "\"");
			}
			return argument.ToString().Trim();
		}
	}
	public static class CodeInstructionNew
	{
		public static CodeInstruction LoadLocal(int index, bool useAddress = false)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Expected O, but got Unknown
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Expected O, but got Unknown
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Expected O, but got Unknown
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Expected O, but got Unknown
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Expected O, but got Unknown
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Expected O, but got Unknown
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Expected O, but got Unknown
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Expected O, but got Unknown
			if (useAddress)
			{
				if (index >= 256)
				{
					return new CodeInstruction(OpCodes.Ldloca, (object)index);
				}
				return new CodeInstruction(OpCodes.Ldloca_S, (object)Convert.ToByte(index));
			}
			if (index != 0)
			{
				if (index != 1)
				{
					if (index != 2)
					{
						if (index != 3)
						{
							if (index >= 256)
							{
								return new CodeInstruction(OpCodes.Ldloc, (object)index);
							}
							return new CodeInstruction(OpCodes.Ldloc_S, (object)Convert.ToByte(index));
						}
						return new CodeInstruction(OpCodes.Ldloc_3, (object)null);
					}
					return new CodeInstruction(OpCodes.Ldloc_2, (object)null);
				}
				return new CodeInstruction(OpCodes.Ldloc_1, (object)null);
			}
			return new CodeInstruction(OpCodes.Ldloc_0, (object)null);
		}

		public static CodeInstruction StoreLocal(int index)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Expected O, but got Unknown
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Expected O, but got Unknown
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Expected O, but got Unknown
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Expected O, but got Unknown
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Expected O, but got Unknown
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Expected O, but got Unknown
			if (index != 0)
			{
				if (index != 1)
				{
					if (index != 2)
					{
						if (index != 3)
						{
							if (index >= 256)
							{
								return new CodeInstruction(OpCodes.Stloc, (object)index);
							}
							return new CodeInstruction(OpCodes.Stloc_S, (object)Convert.ToByte(index));
						}
						return new CodeInstruction(OpCodes.Stloc_3, (object)null);
					}
					return new CodeInstruction(OpCodes.Stloc_2, (object)null);
				}
				return new CodeInstruction(OpCodes.Stloc_1, (object)null);
			}
			return new CodeInstruction(OpCodes.Stloc_0, (object)null);
		}

		public static CodeInstruction LoadArgument(int index, bool useAddress = false)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Expected O, but got Unknown
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Expected O, but got Unknown
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Expected O, but got Unknown
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Expected O, but got Unknown
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Expected O, but got Unknown
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Expected O, but got Unknown
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Expected O, but got Unknown
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Expected O, but got Unknown
			if (useAddress)
			{
				if (index >= 256)
				{
					return new CodeInstruction(OpCodes.Ldarga, (object)index);
				}
				return new CodeInstruction(OpCodes.Ldarga_S, (object)Convert.ToByte(index));
			}
			if (index != 0)
			{
				if (index != 1)
				{
					if (index != 2)
					{
						if (index != 3)
						{
							if (index >= 256)
							{
								return new CodeInstruction(OpCodes.Ldarg, (object)index);
							}
							return new CodeInstruction(OpCodes.Ldarg_S, (object)Convert.ToByte(index));
						}
						return new CodeInstruction(OpCodes.Ldarg_3, (object)null);
					}
					return new CodeInstruction(OpCodes.Ldarg_2, (object)null);
				}
				return new CodeInstruction(OpCodes.Ldarg_1, (object)null);
			}
			return new CodeInstruction(OpCodes.Ldarg_0, (object)null);
		}

		public static CodeInstruction StoreArgument(int index)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Expected O, but got Unknown
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Expected O, but got Unknown
			if (index >= 256)
			{
				return new CodeInstruction(OpCodes.Starg, (object)index);
			}
			return new CodeInstruction(OpCodes.Starg_S, (object)Convert.ToByte(index));
		}
	}
}
namespace Damntry.UtilsBepInEx.HarmonyPatching
{
	public class HarmonyInstancePatcher
	{
		private enum PatchRecursiveAction
		{
			StopAll,
			SkipAndContinueNested,
			PatchAndContinueNested
		}

		private readonly Type harmonyInstanceType;

		private readonly Lazy<Harmony> harmonyPatch;

		public HarmonyInstancePatcher(Type harmonyInstanceType)
		{
			this.harmonyInstanceType = harmonyInstanceType;
			harmonyPatch = new Lazy<Harmony>((Func<Harmony>)(() => new Harmony(GetHarmonyInstanceId())));
		}

		internal string GetHarmonyInstanceId()
		{
			return harmonyInstanceType.FullName;
		}

		public List<MethodInfo> PatchInstance()
		{
			return StartRecursivePatching(harmonyPatch.Value);
		}

		public void UnpatchInstance()
		{
			harmonyPatch.Value.UnpatchSelf();
		}

		public int GetPatchedCount()
		{
			return harmonyPatch.Value.GetPatchedMethods().Count();
		}

		private List<MethodInfo> StartRecursivePatching(Harmony harmonyPatch)
		{
			List<MethodInfo> list = new List<MethodInfo>();
			if (PatchClass(harmonyInstanceType, harmonyPatch, list))
			{
				PatchNestedClassesRecursive(new List<Type>(), harmonyInstanceType, harmonyPatch, list);
			}
			return list;
		}

		private void PatchNestedClassesRecursive(List<Type> classList, Type classType, Harmony harmony, List<MethodInfo> listPatchedMethods)
		{
			Type[] nestedTypes = classType.GetNestedTypes(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (Type type in nestedTypes)
			{
				if (type.IsClass && PatchClass(type, harmony, listPatchedMethods))
				{
					PatchNestedClassesRecursive(classList, type, harmony, listPatchedMethods);
				}
			}
		}

		private bool PatchClass(Type classType, Harmony harmonyPatch, List<MethodInfo> listPatchedMethods)
		{
			switch (CheckAttributesForAllowedAction(classType))
			{
			case PatchRecursiveAction.StopAll:
				return false;
			case PatchRecursiveAction.PatchAndContinueNested:
			{
				PatchClassProcessor val = harmonyPatch.CreateClassProcessor(classType, true);
				listPatchedMethods.AddRange(val.Patch());
				break;
			}
			}
			return true;
		}

		private PatchRecursiveAction CheckAttributesForAllowedAction(Type classType)
		{
			if (ReflectionExtension.HasCustomAttribute<AutoPatchIgnoreClassAndNested>((MemberInfo)classType))
			{
				return PatchRecursiveAction.StopAll;
			}
			if (ReflectionExtension.HasCustomAttribute<AutoPatchIgnoreClass>((MemberInfo)classType))
			{
				return PatchRecursiveAction.SkipAndContinueNested;
			}
			return PatchRecursiveAction.PatchAndContinueNested;
		}

		public List<MethodInfo> PatchClassByType(Type classType)
		{
			ThrowIfNotOwnInstanceNestedClass(classType);
			return harmonyPatch.Value.CreateClassProcessor(classType).Patch();
		}

		public void UnpatchMethod(Type originalClassType, string originalMethodName)
		{
			if (originalMethodName == null)
			{
				throw new ArgumentNullException("originalMethodName");
			}
			MethodInfo methodInfo = AccessTools.Method(originalClassType, originalMethodName, (Type[])null, (Type[])null);
			if (methodInfo == null)
			{
				throw new InvalidOperationException("The method \"" + originalMethodName + "\" couldnt be found in the type " + originalClassType.FullName + ".");
			}
			harmonyPatch.Value.Unpatch((MethodBase)methodInfo, (HarmonyPatchType)0, harmonyPatch.Value.Id);
		}

		private void ThrowIfNotOwnInstanceNestedClass(Type classType)
		{
			if (classType == null)
			{
				throw new ArgumentNullException("classType");
			}
			if (classType == harmonyInstanceType)
			{
				throw new InvalidOperationException("Use the method PatchInstance/UnpatchInstance() instead.");
			}
			if (GetTopClassOfNested(classType) != harmonyInstanceType)
			{
				throw new InvalidOperationException("Class must be a nested class of " + harmonyInstanceType.FullName + ". If you want to do this action on another Instance, use that instance methods instead.");
			}
		}

		private Type GetTopClassOfNested(Type classType)
		{
			while (classType.IsNested)
			{
				classType = classType.DeclaringType;
			}
			return classType;
		}
	}
	public class HarmonyMonoMethods
	{
		public static MethodDefinition GetMethodDefinition(MethodInfo methodInfo)
		{
			MethodDefinition val = MethodBaseToMethodDefinition(methodInfo);
			if (val == null)
			{
				AssemblyDefinition val2 = AssemblyDefinition.ReadAssembly(AssemblyUtils.GetAssemblyDllFilePath(methodInfo.DeclaringType));
				try
				{
					val = Extensions.FindMethod(val2.MainModule.GetType(methodInfo.DeclaringType.FullName), Extensions.GetID((MethodBase)methodInfo, (string)null, (string)null, true, false, false), false);
				}
				catch (Exception ex)
				{
					TimeLogger.Logger.LogTimeDebug(TimeLogger.FormatException(ex, "Error while trying to convert MethodInfo to MethodDefinition. You can safely ignore this error if you are not the dev."), (LogCategories)4194304);
				}
			}
			return val;
		}

		public static MethodDefinition MethodBaseToMethodDefinition(MethodBase method)
		{
			//IL_002f: 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_004a: Expected O, but got Unknown
			return (MethodDefinition)((MemberReference)(TypeDefinition)ModuleDefinition.ReadModule((Stream)new MemoryStream(File.ReadAllBytes(method.DeclaringType.Module.FullyQualifiedName))).LookupToken(method.DeclaringType.MetadataToken)).Module.LookupToken(method.MetadataToken);
		}

		public static IEnumerable<(MethodInfo methodInfo, HarmonyMethod harmonyMethod)> GetAllPatchMethodTargets(Type assemblyType, bool skipNonExecutablePatches)
		{
			HarmonyMethod harmonyMethod;
			return (from type in Assembly.GetAssembly(assemblyType).GetTypes()
				where !skipNonExecutablePatches || IsPatchExecutable(type)
				select type).SelectMany((Type type) => from mInfo in type.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)
				where IsHarmonyAttribute(mInfo)
				select (GetTargetMethodFromHarmonyPatchMethod(type, mInfo, out harmonyMethod), harmonyMethod));
		}

		private static bool IsPatchExecutable(Type methodClassType)
		{
			MethodInfo methodInfo = (from m in methodClassType.GetMethods(AccessTools.all)
				where m.ReturnType == typeof(bool)
				select m).FirstOrDefault((MethodInfo m) => m.Name == "Prepare" || m.GetCustomAttributes(inherit: true).Any((object attr) => attr.GetType().FullName == typeof(HarmonyPrepare).FullName));
			if (methodInfo != null)
			{
				object[] array = AccessTools.ActualParameters((MethodBase)methodInfo, Array.Empty<object>());
				return ReflectionHelper.CallMethod<bool>((object)null, methodInfo, array);
			}
			return true;
		}

		public static bool IsHarmonyAttribute(MethodInfo methodInfo)
		{
			IEnumerable<Attribute> enumerable = null;
			try
			{
				enumerable = methodInfo.GetCustomAttributes();
			}
			catch (TypeNotFoundInAssemblyException)
			{
				return false;
			}
			return enumerable.Any((Attribute attr) => attr is HarmonyAttribute);
		}

		public static MethodInfo GetTargetMethodFromHarmonyPatchMethod(Type methodClassType, MethodInfo patchMethodInfo, out HarmonyMethod harmonyMethod)
		{
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			IEnumerable<HarmonyMethod> source = from attr in patchMethodInfo.GetCustomAttributes(inherit: true)
				where attr is HarmonyAttribute
				select ((HarmonyAttribute)attr).info;
			harmonyMethod = HarmonyMethod.Merge(source.ToList());
			if (harmonyMethod.method == null && harmonyMethod.declaringType == null)
			{
				HarmonyMethod val = HarmonyMethod.Merge(HarmonyMethodExtensions.GetFromType(methodClassType));
				harmonyMethod = HarmonyMethodExtensions.Merge(val, harmonyMethod);
			}
			HarmonyMethod val2 = harmonyMethod;
			MethodType valueOrDefault = val2.methodType.GetValueOrDefault();
			if (!val2.methodType.HasValue)
			{
				valueOrDefault = (MethodType)0;
				val2.methodType = valueOrDefault;
			}
			MethodInfo methodInfo = AccessTools.Method("HarmonyLib.PatchTools:GetOriginalMethod", new Type[1] { typeof(HarmonyMethod) }, (Type[])null);
			if (methodInfo != null)
			{
				return (MethodInfo)methodInfo.Invoke(null, new object[1] { harmonyMethod });
			}
			TimeLogger.Logger.LogTimeWarning("Reflection access to \"HarmonyLib.PatchTools:GetOriginalMethod\" returned null. Using backup method.", (LogCategories)4194304);
			return AccessTools.Method(harmonyMethod.declaringType, harmonyMethod.methodName, harmonyMethod.argumentTypes, (Type[])null);
		}
	}
	public class MethodSignatureChecker
	{
		internal class MethodSignature
		{
			public string Arguments { get; set; }

			public string ReturnType { get; set; }

			public int IL_BodyHashcode { get; set; }

			public void Set_IL_BodyHashcode(Collection<Instruction> instructions)
			{
				//IL_0012: Unknown result type (might be due to invalid IL or missing references)
				//IL_0017: Unknown result type (might be due to invalid IL or missing references)
				if (instructions == null)
				{
					throw new ArgumentNullException("instructions");
				}
				int num = 17;
				Enumerator<Instruction> enumerator = instructions.GetEnumerator();
				try
				{
					while (enumerator.MoveNext())
					{
						Instruction current = enumerator.Current;
						num = num * 71 + ((object)current).ToString().GetHashCode();
					}
				}
				finally
				{
					((IDisposable)enumerator).Dispose();
				}
				IL_BodyHashcode = num;
			}

			internal bool Equals(MethodSignature other, out string errorDetail)
			{
				errorDetail = null;
				if (other == null)
				{
					errorDetail = "\tWrong method call or no longer exists.";
				}
				else if (Arguments != other.Arguments)
				{
					errorDetail = "\tArguments are different";
				}
				else if (ReturnType != other.ReturnType)
				{
					errorDetail = "\tReturn types are different";
				}
				else if (IL_BodyHashcode != other.IL_BodyHashcode)
				{
					errorDetail = "\tIL method body hashcode is different";
				}
				if (errorDetail != null)
				{
					errorDetail = errorDetail.PadRight(38);
				}
				return errorDetail == null;
			}
		}

		private readonly struct MethodInfoData
		{
			private readonly struct FullMethodName
			{
				private readonly string method;

				private readonly string declaringType;

				private readonly string[] parameters;

				public FullMethodName(string declaredTypeName, string methodName, string[] typeParameterNames = null)
				{
					method = methodName;
					declaringType = ReflectionHelper.ConvertFullTypeToNormal(declaredTypeName);
					parameters = ReflectionHelper.ConvertFullTypesToNormal(typeParameterNames);
				}

				public FullMethodName(string declaredTypeName, string methodName, Type[] typeParameter = null)
				{
					method = methodName;
					declaringType = ReflectionHelper.ConvertFullTypeToNormal(declaredTypeName);
					string[] array = null;
					if (typeParameter != null && typeParameter.Length != 0)
					{
						array = (from t in typeParameter
							where t != null
							select t.Name).ToArray();
					}
					parameters = array;
				}

				public string GetText()
				{
					string text = "";
					if (parameters != null && parameters.Length != 0)
					{
						text = string.Join(", ", parameters);
					}
					return declaringType + "." + method + "(" + text + ")";
				}
			}

			private readonly bool isMethodInfo;

			private readonly MethodInfo methodInfo;

			private readonly Type declaringType;

			private readonly string methodName;

			private readonly Type[] parameters;

			private readonly Type[] generics;

			private readonly string fullTypeName;

			private readonly string[] fullTypeParameters;

			private readonly FullMethodName fullMethodName;

			public MethodInfoData(MethodInfo methodInfo, string declaredTypeName, string methodName, string[] typeParameterNames = null)
			{
				declaringType = null;
				this.methodName = null;
				parameters = null;
				generics = null;
				fullTypeName = null;
				fullTypeParameters = null;
				if (string.IsNullOrEmpty(declaredTypeName))
				{
					throw new ArgumentNullException("declaredTypeName cannot be empty.");
				}
				if (string.IsNullOrEmpty(methodName))
				{
					throw new ArgumentNullException("methodName cannot be empty.");
				}
				this.methodInfo = methodInfo;
				fullMethodName = new FullMethodName(declaredTypeName, methodName, typeParameterNames);
				isMethodInfo = true;
			}

			public MethodInfoData(MethodInfo methodInfo, Type declaringType, string methodName, Type[] parameters = null, Type[] generics = null)
			{
				this.declaringType = null;
				this.methodName = null;
				this.parameters = null;
				this.generics = null;
				fullTypeName = null;
				fullTypeParameters = null;
				if (declaringType == null)
				{
					throw new ArgumentNullException("declaringType cannot be null.");
				}
				if (string.IsNullOrEmpty(methodName))
				{
					throw new ArgumentException("methodName cannot be null or empty.");
				}
				this.methodInfo = methodInfo;
				fullMethodName = new FullMethodName(declaringType.Name, methodName, parameters);
				isMethodInfo = true;
			}

			public MethodInfoData(Type declaringType, string methodName, Type[] parameters = null, Type[] generics = null)
			{
				isMethodInfo = false;
				methodInfo = null;
				fullTypeName = null;
				fullTypeParameters = null;
				if (declaringType == null)
				{
					throw new ArgumentNullException("declaringType cannot be null.");
				}
				if (string.IsNullOrEmpty(methodName))
				{
					throw new ArgumentException("methodName cannot be null or empty.");
				}
				this.declaringType = declaringType;
				this.methodName = methodName;
				this.parameters = parameters;
				this.generics = generics;
				fullMethodName = new FullMethodName(declaringType.Name, methodName, parameters);
			}

			public MethodInfoData(Type declaringType, string methodName, string[] fullTypeParameters = null, Type[] generics = null)
			{
				isMethodInfo = false;
				methodInfo = null;
				parameters = null;
				fullTypeName = null;
				if (declaringType == null)
				{
					throw new ArgumentNullException("declaringType cannot be null.");
				}
				if (string.IsNullOrEmpty(methodName))
				{
					throw new ArgumentException("methodName cannot be null or empty.");
				}
				this.declaringType = declaringType;
				this.methodName = methodName;
				this.fullTypeParameters = fullTypeParameters;
				this.generics = generics;
				fullMethodName = new FullMethodName(declaringType.Name, methodName, fullTypeParameters);
			}

			public MethodInfoData(string fullTypeName, string methodName, string[] fullTypeParameters = null, Type[] generics = null)
			{
				isMethodInfo = false;
				methodInfo = null;
				declaringType = null;
				parameters = null;
				if (string.IsNullOrEmpty(fullTypeName))
				{
					throw new ArgumentNullException("fullTypeName cannot be null or empty.");
				}
				if (string.IsNullOrEmpty(methodName))
				{
					throw new ArgumentException("methodName cannot be null or empty.");
				}
				this.fullTypeName = fullTypeName;
				this.methodName = methodName;
				this.fullTypeParameters = fullTypeParameters;
				this.generics = generics;
				fullMethodName = new FullMethodName(fullTypeName, methodName, fullTypeParameters);
			}

			public MethodInfo GetMethodInfo()
			{
				if (isMethodInfo)
				{
					return methodInfo;
				}
				Type obj = ((declaringType != null) ? declaringType : AssemblyUtils.GetTypeFromLoadedAssemblies(fullTypeName, true));
				Type[] array = ((parameters != null) ? parameters : AssemblyUtils.GetTypesFromLoadedAssemblies(true, fullTypeParameters));
				return AccessTools.Method(obj, methodName, array, generics);
			}

			public string GetFullMethodName()
			{
				return fullMethodName.GetText();
			}
		}

		private List<MethodInfoData> listMethodInfoData;

		private Dictionary<string, MethodSignature> previousMethodSignatures;

		private readonly string pathFileMethodSignatures;

		private readonly Type pluginType;

		public CheckResult LastCheckResult { get; private set; }

		public MethodSignatureChecker(Type pluginType)
		{
			this.pluginType = pluginType;
			LastCheckResult = new CheckResult();
			string combinedPathFromAssemblyFolder = AssemblyUtils.GetCombinedPathFromAssemblyFolder(pluginType, "MethodSignatureChecker");
			if (!Directory.Exists(combinedPathFromAssemblyFolder))
			{
				Directory.CreateDirectory(combinedPathFromAssemblyFolder);
			}
			char directorySeparatorChar = Path.DirectorySeparatorChar;
			pathFileMethodSignatures = combinedPathFromAssemblyFolder + directorySeparatorChar + "methodsignatures.json";
			listMethodInfoData = new List<MethodInfoData>();
		}

		public static MethodSignatureChecker StartSignatureCheck(Type pluginType)
		{
			MethodSignatureChecker methodSignatureChecker = new MethodSignatureChecker(pluginType);
			methodSignatureChecker.PopulateMethodSignaturesFromHarmonyPatches();
			methodSignatureChecker.StartSignatureCheck();
			return methodSignatureChecker;
		}

		public void PopulateMethodSignaturesFromHarmonyPatches()
		{
			foreach (var (methodInfo, val) in HarmonyMonoMethods.GetAllPatchMethodTargets(pluginType, skipNonExecutablePatches: true))
			{
				AddMethod(methodInfo, val.declaringType, val.methodName, val.argumentTypes);
			}
		}

		public void AddMethod(MethodInfo methodInfo, string declaredTypeName, string methodName, string[] typeParameterNames = null)
		{
			listMethodInfoData.Add(new MethodInfoData(methodInfo, declaredTypeName, methodName, typeParameterNames));
		}

		public void AddMethod(MethodInfo methodInfo, Type declaringType, string methodName, Type[] parameters = null)
		{
			listMethodInfoData.Add(new MethodInfoData(methodInfo, declaringType, methodName, parameters));
		}

		public void AddMethod(string fullTypeName, string methodName, string[] fullTypeParameters = null, Type[] generics = null)
		{
			listMethodInfoData.Add(new MethodInfoData(fullTypeName, methodName, fullTypeParameters, generics));
		}

		public void AddMethod(Type declaringType, string methodName, string[] fullTypeParameters = null, Type[] generics = null)
		{
			listMethodInfoData.Add(new MethodInfoData(declaringType, methodName, fullTypeParameters, generics));
		}

		public void AddMethod(Type declaringType, string methodName)
		{
			listMethodInfoData.Add(new MethodInfoData(declaringType, methodName, (Type[])null, (Type[])null));
		}

		public void AddMethod(Type declaringType, string methodName, Type[] parameters = null, Type[] generics = null)
		{
			listMethodInfoData.Add(new MethodInfoData(declaringType, methodName, parameters, generics));
		}

		private MethodSignature CreateMethodSignature(MethodInfo methodInfo, MethodDefinition methodDef)
		{
			MethodSignature methodSignature = new MethodSignature();
			object[] parameters = methodInfo.GetParameters();
			methodSignature.Arguments = string.Join("", parameters);
			methodSignature.ReturnType = methodInfo.ReturnType.FullName;
			methodSignature.Set_IL_BodyHashcode(methodDef.Body.Instructions);
			return methodSignature;
		}

		public CheckResult StartSignatureCheck()
		{
			CheckResult checkResult = new CheckResult(CheckResult.SignatureCheckResult.Started, "");
			Dictionary<string, MethodSignature> dictionary = new Dictionary<string, MethodSignature>();
			foreach (MethodInfoData listMethodInfoDatum in listMethodInfoData)
			{
				if (GetMethodSignature(listMethodInfoDatum, out var methodSigEntry) && !dictionary.ContainsKey(methodSigEntry.Key))
				{
					dictionary.Add(methodSigEntry.Key, methodSigEntry.Value);
				}
			}
			if (dictionary == null || !dictionary.Any())
			{
				return checkResult.SetValues(CheckResult.SignatureCheckResult.NoSignaturesAdded, "No method signature has been added. Signature comparison will be skipped.");
			}
			if (TryLoadSignaturesFromFile(checkResult))
			{
				CompareOldSignaturesAgainstNew(checkResult, dictionary);
			}
			if (checkResult.Result != CheckResult.SignatureCheckResult.SignaturesDifferent)
			{
				SaveSignaturesToFile(dictionary);
			}
			if (checkResult.Result == CheckResult.SignatureCheckResult.Started)
			{
				throw new InvalidOperationException("Something went wrong. Method check finished with result \"Started\".");
			}
			return LastCheckResult = checkResult;
		}

		private bool GetMethodSignature(MethodInfoData methodInfoData, out KeyValuePair<string, MethodSignature> methodSigEntry)
		{
			string text = "";
			MethodSignature value = null;
			MethodInfo methodInfo = methodInfoData.GetMethodInfo();
			if (methodInfo != null)
			{
				MethodDefinition methodDefinition = HarmonyMonoMethods.GetMethodDefinition(methodInfo);
				if (methodDefinition == null)
				{
					methodSigEntry = default(KeyValuePair<string, MethodSignature>);
					return false;
				}
				value = CreateMethodSignature(methodInfo, methodDefinition);
			}
			text = methodInfoData.GetFullMethodName();
			methodSigEntry = new KeyValuePair<string, MethodSignature>(text, value);
			return true;
		}

		private bool TryLoadSignaturesFromFile(CheckResult checkResult)
		{
			if (!File.Exists(pathFileMethodSignatures))
			{
				checkResult.SetValues(CheckResult.SignatureCheckResult.NoPreviousSignatures, "No method signature file. Skipped check.");
				return false;
			}
			try
			{
				string text = File.ReadAllText(pathFileMethodSignatures, Encoding.Unicode);
				previousMethodSignatures = JsonConvert.DeserializeObject<Dictionary<string, MethodSignature>>(text);
			}
			catch (Exception ex)
			{
				checkResult.SetValues(CheckResult.SignatureCheckResult.FileError, TimeLogger.FormatException(ex, "Error while reading and deserializing from file \"" + pathFileMethodSignatures + "\". It might be corrupted. Trying to delete file and skipping loading signatures."));
				try
				{
					File.Delete(pathFileMethodSignatures);
				}
				catch
				{
				}
				return false;
			}
			return true;
		}

		private void SaveSignaturesToFile(Dictionary<string, MethodSignature> currentMethodSignatures)
		{
			string contents = JsonConvert.SerializeObject((object)currentMethodSignatures, (Formatting)1);
			File.WriteAllText(pathFileMethodSignatures, contents, Encoding.Unicode);
		}

		private void CompareOldSignaturesAgainstNew(CheckResult checkResult, Dictionary<string, MethodSignature> currentMethodSignatures)
		{
			Dictionary<string, MethodSignature> dictionary = previousMethodSignatures;
			if (dictionary == null || !dictionary.Any() || currentMethodSignatures == null || !currentMethodSignatures.Any())
			{
				return;
			}
			foreach (KeyValuePair<string, MethodSignature> currentMethodSignature in currentMethodSignatures)
			{
				if (previousMethodSignatures.TryGetValue(currentMethodSignature.Key, out var value))
				{
					MethodSignature value2 = currentMethodSignature.Value;
					if (value != null && !value.Equals(value2, out var errorDetail))
					{
						checkResult.Result = CheckResult.SignatureCheckResult.SignaturesDifferent;
						checkResult.AddErrorMessage(errorDetail + " | " + currentMethodSignature.Key);
					}
				}
			}
			if (checkResult.Result != CheckResult.SignatureCheckResult.SignaturesDifferent)
			{
				checkResult.SetValues(CheckResult.SignatureCheckResult.SignaturesOk, "Method signature check ok.");
			}
		}
	}
	public class CheckResult
	{
		public enum SignatureCheckResult
		{
			Unchecked,
			Started,
			FileError,
			NoSignaturesAdded,
			NoPreviousSignatures,
			SignaturesDifferent,
			SignaturesOk
		}

		public static CheckResult UnknownError = new CheckResult(SignatureCheckResult.Unchecked, "Unknown Error due to exception");

		private string _result;

		public SignatureCheckResult Result { get; internal set; }

		public string ResultMessage
		{
			get
			{
				return _result;
			}
			private set
			{
				if (value == null)
				{
					_result = "";
				}
				_result = value;
			}
		}

		internal CheckResult()
		{
			ResultMessage = "";
			Result = SignatureCheckResult.Unchecked;
		}

		internal CheckResult(SignatureCheckResult result, string resultMessage)
		{
			ResultMessage = resultMessage;
			Result = result;
		}

		internal CheckResult SetValues(SignatureCheckResult result, string resultMessage)
		{
			ResultMessage = resultMessage;
			Result = result;
			return this;
		}

		internal void AddErrorMessage(string resultMessage)
		{
			if (string.IsNullOrEmpty(ResultMessage))
			{
				ResultMessage = "Method signatures have changed since last successful check:";
			}
			ResultMessage = ResultMessage + "\n" + resultMessage;
		}

		public void LogResultMessage(LogTier logLevel, bool onlyWhenNotOk, bool showInGame)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			if (ShouldLogMessage(onlyWhenNotOk))
			{
				TimeLogger.Logger.LogTime(logLevel, ResultMessage, (LogCategories)4194304, showInGame);
			}
		}

		private bool ShouldLogMessage(bool onlyWhenNotOk)
		{
			if (string.IsNullOrEmpty(ResultMessage))
			{
				if (Result == SignatureCheckResult.Unchecked)
				{
					return false;
				}
				ResultMessage = "Result message was empty for a result in which this is not allowed.";
				return true;
			}
			if (onlyWhenNotOk && (Result == SignatureCheckResult.SignaturesOk || Result == SignatureCheckResult.NoPreviousSignatures))
			{
				return false;
			}
			return true;
		}
	}
}
namespace Damntry.UtilsBepInEx.HarmonyPatching.Helpers
{
	public class ArgumentHelper<T>
	{
		public T Value { get; set; }

		public CodeInstruction LoadFieldArgHelper_IL { get; private set; }

		public CodeInstruction GetterValue_IL { get; private set; }

		public CodeInstruction SetterValue_IL { get; private set; }

		public ArgumentHelper(Type declaringClassType, string instanceName, T argumentValue)
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Expected O, but got Unknown
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Expected O, but got Unknown
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Expected O, but got Unknown
			Value = argumentValue;
			FieldInfo fieldInfo = AccessTools.Field(declaringClassType, instanceName);
			if (fieldInfo == null)
			{
				throw new InvalidOperationException($"No field was found in the type {declaringClassType} with name {instanceName}.");
			}
			LoadFieldArgHelper_IL = new CodeInstruction(OpCodes.Ldsfld, (object)fieldInfo);
			if (!fieldInfo.IsStatic)
			{
				LoadFieldArgHelper_IL.opcode = OpCodes.Ldfld;
			}
			PropertyInfo propertyInfo = AccessTools.Property(typeof(ArgumentHelper<T>), "Value");
			GetterValue_IL = new CodeInstruction(OpCodes.Callvirt, (object)propertyInfo.GetGetMethod());
			SetterValue_IL = new CodeInstruction(OpCodes.Callvirt, (object)propertyInfo.GetSetMethod());
		}
	}
}
namespace Damntry.UtilsBepInEx.HarmonyPatching.Exceptions
{
	public class TranspilerDefaultMsgException : Exception
	{
		private const string defaultErrorText = "Transpiler couldnt perform its changes due to unexpected source code changes.";

		public TranspilerDefaultMsgException()
			: base(composeErrorText())
		{
		}

		public TranspilerDefaultMsgException(string errorDetail)
			: base(composeErrorText(errorDetail))
		{
		}

		public TranspilerDefaultMsgException(string errorDetail, Exception inner)
			: base(composeErrorText(errorDetail), inner)
		{
		}

		private static string composeErrorText(string errorDetail = "")
		{
			return "Transpiler couldnt perform its changes due to unexpected source code changes.\n" + errorDetail;
		}
	}
	public class TypeNotFoundInAssemblyException : Exception
	{
		public TypeNotFoundInAssemblyException()
		{
		}

		public TypeNotFoundInAssemblyException(string errorDetail)
			: base(errorDetail)
		{
		}

		public TypeNotFoundInAssemblyException(string errorDetail, Exception inner)
			: base(errorDetail, inner)
		{
		}
	}
}
namespace Damntry.UtilsBepInEx.HarmonyPatching.AutoPatching
{
	public static class Container<T> where T : AutoPatchedInstanceBase
	{
		public static T Instance => AutoPatchContainer.GetInstance<T>();
	}
	internal static class AutoPatchContainer
	{
		private static Dictionary<Type, AutoPatchedInstanceBase> registeredInstances = new Dictionary<Type, AutoPatchedInstanceBase>();

		internal static T GetInstance<T>() where T : AutoPatchedInstanceBase
		{
			ThrowIfTypeInvalidOrNotRegistered<T>();
			return (T)registeredInstances[typeof(T)];
		}

		internal static AutoPatchedInstanceBase GetAbstractInstance(Type patchType)
		{
			ThrowIfTypeInvalidOrNotRegistered(patchType);
			return registeredInstances[patchType];
		}

		internal static IReadOnlyDictionary<Type, AutoPatchedInstanceBase> GetRegisteredAutoPatches()
		{
			return registeredInstances;
		}

		internal static void RegisterPatchClass(Type autoPatchType)
		{
			ThrowIfTypeInvalidOrAlreadyRegistered(autoPatchType);
			object obj = Activator.CreateInstance(autoPatchType);
			registeredInstances.Add(autoPatchType, (AutoPatchedInstanceBase)obj);
		}

		internal static void UnregisterPatchClass(Type autoPatchClass)
		{
			ThrowIfTypeInvalidOrNotRegistered(autoPatchClass);
			registeredInstances.Remove(autoPatchClass);
		}

		private static void ThrowIfTypeInvalidOrAlreadyRegistered<T>()
		{
			ThrowIfTypeInvalidOrAlreadyRegistered(typeof(T));
		}

		private static void ThrowIfTypeInvalidOrAlreadyRegistered(Type patchClassType)
		{
			if (patchClassType.IsAbstract || !patchClassType.IsSubclassOf(typeof(AutoPatchedInstanceBase)))
			{
				throw new InvalidOperationException("The type " + patchClassType.FullName + " must be a non abstract subclass of AutoPatchedInstanceBase.");
			}
			if (registeredInstances.ContainsKey(patchClassType))
			{
				throw new InvalidOperationException("The type " + patchClassType.FullName + " has already been registered.");
			}
		}

		private static void ThrowIfTypeInvalidOrNotRegistered<T>()
		{
			ThrowIfTypeInvalidOrNotRegistered(typeof(T));
		}

		private static void ThrowIfTypeInvalidOrNotRegistered(Type patchClassType)
		{
			if (patchClassType.IsAbstract || !patchClassType.IsSubclassOf(typeof(AutoPatchedInstanceBase)))
			{
				throw new InvalidOperationException("The type " + patchClassType.FullName + " must be a non abstract subclass of AutoPatchedInstanceBase.");
			}
			if (!registeredInstances.ContainsKey(patchClassType))
			{
				throw new InvalidOperationException("The type " + patchClassType.FullName + " is not registered.");
			}
		}
	}
	public static class AutoPatcher
	{
		public enum AutoPatchResult
		{
			none,
			error,
			disabled,
			success
		}

		public static bool RegisterAllAutoPatchContainers()
		{
			List<Type> list = GetAutoPatchClasses(Assembly.GetCallingAssembly()).ToList();
			if (list.Count == 0)
			{
				return false;
			}
			foreach (Type item in list)
			{
				AutoPatchContainer.RegisterPatchClass(item);
			}
			return true;
		}

		public static bool StartAutoPatcher()
		{
			int num = 0;
			int num2 = 0;
			int num3 = 0;
			foreach (KeyValuePair<Type, AutoPatchedInstanceBase> registeredAutoPatch in AutoPatchContainer.GetRegisteredAutoPatches())
			{
				AutoPatchResult autoPatchResult = Patch(registeredAutoPatch.Key, registeredAutoPatch.Value);
				if (autoPatchResult == AutoPatchResult.disabled)
				{
					num2++;
					continue;
				}
				num3++;
				if (autoPatchResult == AutoPatchResult.error)
				{
					num++;
				}
			}
			if (num == 0)
			{
				TimeLogger.Logger.LogTimeInfo($"All {num3} auto-patches applied successfully.", (LogCategories)8);
				return true;
			}
			TimeLogger.Logger.LogTimeFatal($"Oh oh, {num} out of {num3} auto-patches failed. " + "Check above for errors.", (LogCategories)8);
			return false;
		}

		private static AutoPatchResult Patch(Type autoPatchType, AutoPatchedInstanceBase autoPatchInstance)
		{
			AutoPatchResult autoPatchResult = AutoPatchResult.none;
			try
			{
				if (autoPatchInstance == null)
				{
					throw new InvalidOperationException("Auto patch received a null instance from the registered type " + autoPatchType.FullName + ".");
				}
				if (autoPatchInstance.IsAutoPatchEnabled)
				{
					autoPatchInstance.PatchInstance();
					autoPatchResult = AutoPatchResult.success;
				}
				else
				{
					autoPatchResult = AutoPatchResult.disabled;
				}
			}
			catch (Exception ex)
			{
				autoPatchResult = AutoPatchResult.error;
				TimeLogger.Logger.LogTimeExceptionWithMessage("Error auto patching class " + autoPatchType.FullName + ".", ex, (LogCategories)8);
				if (autoPatchInstance != null)
				{
					TimeLogger.Logger.LogTimeError(autoPatchInstance.ErrorMessageOnAutoPatchFail, (LogCategories)2097152);
					if (autoPatchInstance.IsRollbackOnAutoPatchFail && autoPatchInstance.GetPatchedCount() > 0)
					{
						autoPatchInstance.UnpatchInstance();
					}
				}
			}
			finally
			{
				try
				{
					autoPatchInstance?.RaiseEventOnAutoPatchFinish(autoPatchResult);
				}
				catch (Exception ex2)
				{
					TimeLogger.Logger.LogTimeExceptionWithMessage("Error calling RaiseEventOnAutoPatchFinish:", ex2, (LogCategories)2097152);
				}
			}
			return autoPatchResult;
		}

		public static bool IsPatchActiveFromResult(AutoPatchResult autoPatchResult)
		{
			switch (autoPatchResult)
			{
			case AutoPatchResult.success:
				return true;
			case AutoPatchResult.error:
			case AutoPatchResult.disabled:
				return false;
			default:
				throw new NotImplementedException($"The switch case {autoPatchResult} is not implemented or should not have happened.");
			}
		}

		private static IEnumerable<Type> GetAutoPatchClasses(Assembly assembly)
		{
			return from type in assembly.GetTypes()
				where type.IsClass && !type.IsAbstract && type.IsSubclassOf(typeof(AutoPatchedInstanceBase))
				select type;
		}

		public static string[] GetHarmonyInstanceIdsForAttribute(Type[] autoPatchTypes)
		{
			return autoPatchTypes.Select((Type autoPatchType) => AutoPatchContainer.GetAbstractInstance(autoPatchType).harmonyPatchInstance.Value.GetHarmonyInstanceId()).ToArray();
		}
	}
}
namespace Damntry.UtilsBepInEx.HarmonyPatching.AutoPatching.Interfaces
{
	public interface IAutoPatchSupport : ISelfPatch
	{
		bool IsAutoPatchEnabled { get; }

		bool IsRollbackOnAutoPatchFail { get; }

		string ErrorMessageOnAutoPatchFail { get; }

		void RaiseEventOnAutoPatchFinish(AutoPatcher.AutoPatchResult patchResult);
	}
	public interface IConfigPatchDependence
	{
		void SetSettingPatchDependence<T>(ConfigEntry<T> configEntry);
	}
	public interface ISelfPatch
	{
		bool IsPatchActive { get; }

		event Action<bool> OnPatchFinished;

		List<MethodInfo> PatchInstance();

		void UnpatchInstance();
	}
}
namespace Damntry.UtilsBepInEx.HarmonyPatching.AutoPatching.BaseClasses
{
	public abstract class AutoPatchedInstanceBase : IAutoPatchSupport, ISelfPatch, IConfigPatchDependence
	{
		internal readonly Lazy<HarmonyInstancePatcher> harmonyPatchInstance;

		public abstract bool IsAutoPatchEnabled { get; }

		public abstract bool IsRollbackOnAutoPatchFail { get; }

		public abstract bool IsPatchActive { get; protected set; }

		public abstract string ErrorMessageOnAutoPatchFail { get; protected set; }

		public abstract event Action<bool> OnPatchFinished;

		internal AutoPatchedInstanceBase()
		{
			harmonyPatchInstance = new Lazy<HarmonyInstancePatcher>(() => new HarmonyInstancePatcher(GetType()));
		}

		public List<MethodInfo> PatchInstance()
		{
			return harmonyPatchInstance.Value.PatchInstance();
		}

		public void UnpatchInstance()
		{
			harmonyPatchInstance.Value.UnpatchInstance();
		}

		public int GetPatchedCount()
		{
			return harmonyPatchInstance.Value.GetPatchedCount();
		}

		public abstract void RaiseEventOnAutoPatchFinish(AutoPatcher.AutoPatchResult autoPatchResult);

		public void SetSettingPatchDependence<U>(ConfigEntry<U> configEntry)
		{
			OnPatchFinished += delegate(bool IsPatchActive)
			{
				configEntry.SetConfigAttribute<U, bool>(ConfigurationManagerAttributes.ConfigAttributes.Browsable, IsPatchActive);
			};
		}
	}
}
namespace Damntry.UtilsBepInEx.HarmonyPatching.AutoPatching.BaseClasses.Inheritable
{
	public abstract class FullyAutoPatchedInstance : AutoPatchedInstanceBase
	{
		public override bool IsRollbackOnAutoPatchFail => true;

		public override bool IsPatchActive { get; protected set; }

		public override event Action<bool> OnPatchFinished;

		public void AutoPatchResultEvent(AutoPatcher.AutoPatchResult autoPatchResult)
		{
			IsPatchActive = AutoPatcher.IsPatchActiveFromResult(autoPatchResult);
		}

		public virtual void OnPatchFinishedVirtual(bool IsActive)
		{
		}

		public override void RaiseEventOnAutoPatchFinish(AutoPatcher.AutoPatchResult autoPatchResult)
		{
			AutoPatchResultEvent(autoPatchResult);
			if (OnPatchFinished != null)
			{
				OnPatchFinished(IsPatchActive);
			}
			OnPatchFinishedVirtual(IsPatchActive);
		}
	}
	public abstract class HybridPatchedInstance : AutoPatchedInstanceBase
	{
		public override void RaiseEventOnAutoPatchFinish(AutoPatcher.AutoPatchResult autoPatchResult)
		{
		}

		public List<MethodInfo> PatchClassByType(Type classType)
		{
			return harmonyPatchInstance.Value.PatchClassByType(classType);
		}

		public void UnpatchMethod(Type classType, string methodName)
		{
			harmonyPatchInstance.Value.UnpatchMethod(classType, methodName);
		}
	}
}
namespace Damntry.UtilsBepInEx.HarmonyPatching.AutoPatching.Attributes
{
	[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
	public class AutoPatchIgnoreClass : AutoPatchAttribute
	{
	}
	[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
	public class AutoPatchIgnoreClassAndNested : AutoPatchAttribute
	{
	}
	public abstract class AutoPatchAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
	public class HarmonyBeforeInstance : HarmonyPatch
	{
		private HarmonyBeforeInstance()
		{
		}

		public HarmonyBeforeInstance(params Type[] beforeInstances)
		{
			((HarmonyAttribute)this).info.before = AutoPatcher.GetHarmonyInstanceIdsForAttribute(beforeInstances);
		}
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
	public class HarmonyAfterInstance : HarmonyPatch
	{
		private HarmonyAfterInstance()
		{
		}

		public HarmonyAfterInstance(params Type[] afterInstances)
		{
			((HarmonyAttribute)this).info.after = AutoPatcher.GetHarmonyInstanceIdsForAttribute(afterInstances);
		}
	}
}
namespace Damntry.UtilsBepInEx.HarmonyPatching.Attributes
{
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Delegate, AllowMultiple = true)]
	public class HarmonyPatchStringTypes : HarmonyAttribute
	{
		public HarmonyPatchStringTypes(string fullTypeName, string methodName)
		{
			SetMethodInfo(fullTypeName, methodName, (Type[])null);
		}

		public HarmonyPatchStringTypes(string fullTypeName, string methodName, Type[] argumentTypes)
		{
			SetMethodInfo(fullTypeName, methodName, argumentTypes);
		}

		private void SetMethodInfo(string fullTypeName, string methodName, string[] argumentFullTypeNames)
		{
			Type[] typesFromLoadedAssemblies = AssemblyUtils.GetTypesFromLoadedAssemblies(true, argumentFullTypeNames);
			SetMethodInfo(fullTypeName, methodName, typesFromLoadedAssemblies);
		}

		private void SetMethodInfo(string fullTypeName, string methodName, Type[] argumentTypes)
		{
			Type typeFromLoadedAssemblies = AssemblyUtils.GetTypeFromLoadedAssemblies(fullTypeName, true);
			base.info.declaringType = typeFromLoadedAssemblies;
			base.info.methodName = methodName;
			base.info.argumentTypes = argumentTypes;
		}
	}
}
namespace Damntry.UtilsBepInEx.Configuration
{
	public static class BepinexConfigExtensions
	{
		public static T GetMaxValue<T>(this AcceptableValueBase acceptableVal) where T : IComparable, IEquatable<T>
		{
			if (acceptableVal is AcceptableValueRange<T>)
			{
				return ((AcceptableValueRange<T>)(object)acceptableVal).GetMaxNumericValue<T>();
			}
			if (acceptableVal is AcceptableValueList<T>)
			{
				return ((AcceptableValueList<T>)(object)acceptableVal).GetMaxNumericValue<T>();
			}
			return default(T);
		}

		public static T GetMaxNumericValue<T>(this AcceptableValueRange<T> acceptableVal) where T : IComparable
		{
			return acceptableVal.MaxValue;
		}

		public static T GetMaxNumericValue<T>(this AcceptableValueList<T> acceptableVal) where T : IEquatable<T>, IComparable
		{
			if (!NumberExtensionMethods.IsNumeric(typeof(T)))
			{
				throw new InvalidOperationException("Only numeric types are allowed, but received a " + typeof(T).FullName);
			}
			return acceptableVal.AcceptableValues.OrderBy((T x) => x).Last();
		}
	}
}
namespace Damntry.UtilsBepInEx.Configuration.ConfigurationManager
{
	public enum MultiplayerModInstallSide
	{
		Unspecified,
		Any,
		HostSideOnly,
		HostAndOptionalClient,
		HostAndSoftClient,
		HostAndHardClient
	}
	public class ConfigManagerController
	{
		internal const string ConfigMngFullTypeName = "ConfigurationManager.ConfigurationManager";

		private const string InstallSideInitialDescription = "[Multiplayer requirements] This setting requires that the mod ";

		private ConfigFile configFile;

		private string currentSectionName;

		private int currentSectionOrder;

		private int currentConfigOrder;

		public ConfigManagerController(ConfigFile configFile)
		{
			this.configFile = configFile ?? throw new ArgumentNullException("configFile");
			currentSectionOrder = 0;
			currentConfigOrder = int.MaxValue;
			if (AssemblyUtils.GetTypeFromLoadedAssemblies("ConfigurationManager.ConfigurationManager", true) != null)
			{
				ConfigurationManagerPatch.PatchSelf();
			}
			ConfigEntryBasePatch.PatchSelf();
		}

		private void SetSection(string sectionName, bool skipSectionOrder = false)
		{
			if (!(sectionName == currentSectionName))
			{
				if (!skipSectionOrder)
				{
					currentSectionOrder++;
				}
				currentConfigOrder = int.MaxValue;
				currentSectionName = sectionName;
			}
		}

		public static bool RefreshGUI()
		{
			if (ConfigurationManagerPatch.ConfigMngInstance != null)
			{
				string text = "BuildSettingList";
				try
				{
					ReflectionHelper.CallMethod(ConfigurationManagerPatch.ConfigMngInstance, text, (object[])null);
					return true;
				}
				catch (Exception ex)
				{
					TimeLogger.Logger.LogTimeExceptionWithMessage("Error when trying to call the method to refresh ConfigurationManager GUI.", ex, (LogCategories)64);
				}
			}
			return false;
		}

		public ConfigEntry<bool> AddSectionNote(string sectionText, string description = null, IConfigPatchDependence patchInstanceDependency = null, bool hidden = false, bool isAdvanced = false)
		{
			string text = "\u200b";
			ConfigEntryBasePatch.AddNote(text);
			return AddConfig(sectionText, text, defaultValue: true, description, patchInstanceDependency, MultiplayerModInstallSide.Unspecified, hidden, disabled: true, null, showRangeAsPercent: false, hideDefaultButton: true, isAdvanced, skipSectionIncrease: true);
		}

		public ConfigEntry<string> AddQuasiNote(string sectionName, string key, string textboxMessage, string description = null, IConfigPatchDependence patchInstanceDependency = null, bool hidden = false, bool isAdvanced = false)
		{
			return AddQuasiNote(sectionName, key, textboxMessage, description, patchInstanceDependency, hidden, isAdvanced, skipSectionIncrease: false);
		}

		public ConfigEntry<string> AddGUIHiddenNote(string sectionName, string key, string description = null, IConfigPatchDependence patchInstanceDependency = null, bool isAdvanced = false)
		{
			return AddQuasiNote(sectionName, key, null, description, patchInstanceDependency, hidden: true, isAdvanced, skipSectionIncrease: true);
		}

		private ConfigEntry<string> AddQuasiNote(string sectionName, string key, string textboxMessage, string description = null, IConfigPatchDependence patchInstanceDependency = null, bool hidden = false, bool isAdvanced = false, bool skipSectionIncrease = false)
		{
			if (textboxMessage == null)
			{
				textboxMessage = "";
			}
			ConfigEntryBasePatch.AddNote(key);
			return AddConfig(sectionName, key, textboxMessage, description, patchInstanceDependency, MultiplayerModInstallSide.Unspecified, hidden, disabled: true, null, showRangeAsPercent: false, hideDefaultButton: true, isAdvanced, skipSectionIncrease);
		}

		public ConfigEntry<T> AddConfig<T>(string sectionName, string key, T defaultValue, string description = null, IConfigPatchDependence patchInstanceDependency = null, MultiplayerModInstallSide modInstallSide = MultiplayerModInstallSide.Unspecified, bool hidden = false, bool disabled = false, bool hideDefaultButton = false, bool isAdvanced = false)
		{
			return AddConfig(sectionName, key, defaultValue, description, patchInstanceDependency, modInstallSide, hidden, disabled, null, showRangeAsPercent: false, hideDefaultButton, isAdvanced);
		}

		public ConfigEntry<T> AddConfigWithAcceptableValues<T>(string sectionName, string key, T defaultValue, string description = null, IConfigPatchDependence patchInstanceDependency = null, MultiplayerModInstallSide modInstallSide = MultiplayerModInstallSide.Unspecified, bool hidden = false, bool disabled = false, AcceptableValueList<T> acceptableValueList = null, bool hideDefaultButton = false, bool isAdvanced = false) where T : IEquatable<T>
		{
			return AddConfig(sectionName, key, defaultValue, description, patchInstanceDependency, modInstallSide, hidden, disabled, (AcceptableValueBase)(object)acceptableValueList, showRangeAsPercent: false, hideDefaultButton, isAdvanced);
		}

		public ConfigEntry<T> AddConfigWithAcceptableValues<T>(string sectionName, string key, T defaultValue, string description = null, IConfigPatchDependence patchInstanceDependency = null, MultiplayerModInstallSide modInstallSide = MultiplayerModInstallSide.Unspecified, bool hidden = false, bool disabled = false, AcceptableValueRange<T> acceptableValueRange = null, bool showRangeAsPercent = false, bool hideDefaultButton = false, bool isAdvanced = false) where T : IComparable
		{
			return AddConfig(sectionName, key, defaultValue, description, patchInstanceDependency, modInstallSide, hidden, disabled, (AcceptableValueBase)(object)acceptableValueRange, showRangeAsPercent, hideDefaultButton, isAdvanced);
		}

		private ConfigEntry<T> AddConfig<T>(string sectionName, string key, T defaultValue, string description = null, IConfigPatchDependence patchInstanceDependency = null, MultiplayerModInstallSide modInstallSide = MultiplayerModInstallSide.Unspecified, bool hidden = false, bool disabled = false, AcceptableValueBase acceptableVal = null, bool showRangeAsPercent = false, bool hideDefaultButton = false, bool isAdvanced = false, bool skipSectionIncrease = false)
		{
			SetSection(sectionName, skipSectionIncrease);
			return AddConfig(key, defaultValue, description, patchInstanceDependency, modInstallSide, hidden, disabled, acceptableVal, showRangeAsPercent, hideDefaultButton, isAdvanced);
		}

		private ConfigEntry<T> AddConfig<T>(string key, T defaultValue, string description = null, IConfigPatchDependence patchInstanceDependency = null, MultiplayerModInstallSide modInstallSide = MultiplayerModInstallSide.Unspecified, bool hidden = false, bool disabled = false, AcceptableValueBase acceptableVal = null, bool showRangeAsPercent = false, bool hideDefaultButton = false, bool isAdvanced = false)
		{
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Expected O, but got Unknown
			if (description == null)
			{
				description = "";
			}
			if (patchInstanceDependency != null)
			{
				hidden = true;
			}
			if (modInstallSide != 0)
			{
				string descriptionFromInstallSide = GetDescriptionFromInstallSide(modInstallSide);
				if (!Utility.IsNullOrWhiteSpace(description))
				{
					description += "\n\n";
				}
				description += descriptionFromInstallSide;
			}
			ConfigDescription val = new ConfigDescription(description, acceptableVal, new object[1]
			{
				new ConfigurationManagerAttributes
				{
					IsAdvanced = isAdvanced,
					Order = currentConfigOrder--,
					Browsable = !hidden,
					DefaultValue = defaultValue,
					ShowRangeAsPercent = showRangeAsPercent,
					ReadOnly = disabled,
					HideDefaultButton = hideDefaultButton,
					Category = currentSectionOrder.ToString("D2") + ". " + currentSectionName
				}
			});
			ConfigEntry<T> val2 = configFile.Bind<T>(currentSectionName, key, defaultValue, val);
			patchInstanceDependency?.SetSettingPatchDependence<T>(val2);
			return val2;
		}

		public bool Remove(string section, string key)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Expected O, but got Unknown
			return configFile.Remove(new ConfigDefinition(section, key));
		}

		public bool Remove(ConfigDefinition key)
		{
			return configFile.Remove(key);
		}

		public void ClearAllConfigs()
		{
			configFile.Clear();
		}

		public int Count()
		{
			return configFile.Count;
		}

		private string GetDescriptionFromInstallSide(MultiplayerModInstallSide modInstallSide)
		{
			return "[Multiplayer requirements] This setting requires that the mod " + modInstallSide switch
			{
				MultiplayerModInstallSide.Any => "is installed for the player/s that wants its functionality, hosting or not.", 
				MultiplayerModInstallSide.HostSideOnly => "is installed in the host. It is not needed in the client.", 
				MultiplayerModInstallSide.HostAndOptionalClient => "is installed in the host. Clients can also install it.", 
				MultiplayerModInstallSide.HostAndSoftClient => "is installed in the host, and should be installed in the clients.", 
				MultiplayerModInstallSide.HostAndHardClient => "is installed in both the host and the clients.", 
				_ => "", 
			};
		}

		public bool SetConfigAttribute<T1, T2>(string section, string key, ConfigurationManagerAttributes.ConfigAttributes configAttribute, T2 attrValue)
		{
			return GetConfigEntry<T2>(section, key).SetConfigAttribute<T2, T2>(configAttribute, attrValue);
		}

		public R GetConfigAttribute<T, R>(string section, string key, ConfigurationManagerAttributes.ConfigAttributes configAttribute)
		{
			return GetConfigEntry<T>(section, key).GetConfigAttribute<T, R>(configAttribute);
		}

		private ConfigEntry<T> GetConfigEntry<T>(string section, string key)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Expected O, but got Unknown
			ConfigEntry<T> val = default(ConfigEntry<T>);
			if (!configFile.TryGetEntry<T>(new ConfigDefinition(section, key), ref val) || ((ConfigEntryBase)val).Description == null || ((ConfigEntryBase)val).Description.Tags == null)
			{
				throw new InvalidOperationException("The config entry with section \"" + section + "\" and key \"" + key + "\" could not be found.");
			}
			return val;
		}
	}
	public static class ConfigManagerExtension
	{
		public static bool SetConfigAttribute

BepInEx/plugins/es.damntry.SuperQoLity/Damntry.Globals.dll

Decompiled a week ago
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Serialization;
using System.Runtime.Versioning;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Damntry.Utils.Collections.Queues.Interfaces;
using Damntry.Utils.ExtensionMethods;
using Damntry.Utils.Logging;
using Damntry.Utils.Tasks;
using Damntry.Utils.Tasks.AsyncDelay;
using Damntry.Utils.Tasks.TaskTimeout;
using Damntry.Utils.Timers.StopwatchImpl;
using Microsoft.CodeAnalysis;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("Damntry Globals")]
[assembly: AssemblyDescription("Utils usable in any type of project")]
[assembly: AssemblyCompany("Damntry")]
[assembly: AssemblyProduct("Damntry Globals")]
[assembly: AssemblyCopyright("Copyright © Damntry 2025")]
[assembly: AssemblyFileVersion("0.4.6")]
[assembly: TargetFramework(".NETFramework,Version=v4.8.1", FrameworkDisplayName = ".NET Framework 4.8.1")]
[assembly: AssemblyVersion("0.4.6.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 HighResolutionTimer
{
	public class HighResolutionTimer
	{
		public static readonly double TickLength = 1000f / (float)Stopwatch.Frequency;

		public static readonly double Frequency = Stopwatch.Frequency;

		public static bool IsHighResolution = Stopwatch.IsHighResolution;

		private volatile float _interval;

		private volatile bool _isRunning;

		private Thread _thread;

		public float Interval
		{
			get
			{
				return _interval;
			}
			set
			{
				if (value < 0f || float.IsNaN(value))
				{
					throw new ArgumentOutOfRangeException("value");
				}
				_interval = value;
			}
		}

		public bool IsRunning => _isRunning;

		public bool UseHighPriorityThread { get; set; }

		public event EventHandler<HighResolutionTimerElapsedEventArgs> Elapsed;

		public HighResolutionTimer()
			: this(1f)
		{
		}

		public HighResolutionTimer(float interval)
		{
			Interval = interval;
		}

		public void Start()
		{
			if (!_isRunning)
			{
				_isRunning = true;
				_thread = new Thread(ExecuteTimer)
				{
					IsBackground = true
				};
				if (UseHighPriorityThread)
				{
					_thread.Priority = ThreadPriority.Highest;
				}
				_thread.Start();
			}
		}

		public void Stop(bool joinThread = true)
		{
			_isRunning = false;
			if (joinThread && Thread.CurrentThread != _thread)
			{
				_thread.Join();
			}
		}

		private void ExecuteTimer()
		{
			float num = 0f;
			Stopwatch stopwatch = new Stopwatch();
			stopwatch.Start();
			while (_isRunning)
			{
				num += _interval;
				double num2;
				while (true)
				{
					num2 = ElapsedHiRes(stopwatch);
					double num3 = (double)num - num2;
					if (num3 <= 0.0)
					{
						break;
					}
					if (num3 < 1.0)
					{
						Thread.SpinWait(10);
					}
					else if (num3 < 5.0)
					{
						Thread.SpinWait(100);
					}
					else if (num3 < 15.0)
					{
						Thread.Sleep(1);
					}
					else
					{
						Thread.Sleep(10);
					}
					if (!_isRunning)
					{
						return;
					}
				}
				double delay = num2 - (double)num;
				this.Elapsed?.Invoke(this, new HighResolutionTimerElapsedEventArgs(delay));
				if (!_isRunning)
				{
					return;
				}
				if (stopwatch.Elapsed.TotalHours >= 1.0)
				{
					stopwatch.Restart();
					num = 0f;
				}
			}
			stopwatch.Stop();
		}

		private static double ElapsedHiRes(Stopwatch stopwatch)
		{
			return (double)stopwatch.ElapsedTicks * TickLength;
		}
	}
	public class HighResolutionTimerElapsedEventArgs : EventArgs
	{
		public double Delay { get; }

		internal HighResolutionTimerElapsedEventArgs(double delay)
		{
			Delay = delay;
		}
	}
}
namespace System.Runtime.CompilerServices
{
	public class IsExternalInit
	{
	}
}
namespace Damntry.Utils.Timers
{
	public class PeriodicTimeLimitedCounter<T> where T : IStopwatch, new()
	{
		private IStopwatch swLimitHit;

		private bool constantPeriodTimer;

		private int hitCounter;

		private int hitCounterMax;

		private double maxPeriodTimeMillis;

		private bool triggerOncePerPeriod;

		public PeriodicTimeLimitedCounter(bool constantPeriodTimer, int hitCounterMax, double maxPeriodTimeMillis, bool ignoreFirstHit, bool triggerOncePerPeriod = true)
		{
			this.constantPeriodTimer = constantPeriodTimer;
			this.hitCounterMax = hitCounterMax;
			this.maxPeriodTimeMillis = maxPeriodTimeMillis;
			hitCounter = (ignoreFirstHit ? (-1) : 0);
			this.triggerOncePerPeriod = triggerOncePerPeriod;
			swLimitHit = new T();
		}

		public bool TryIncreaseCounter()
		{
			bool flag = false;
			bool flag2 = false;
			hitCounter++;
			if (swLimitHit.ElapsedMillisecondsPrecise <= maxPeriodTimeMillis)
			{
				if (!constantPeriodTimer)
				{
					flag = true;
				}
				flag2 = (triggerOncePerPeriod ? (hitCounter == hitCounterMax) : (hitCounter >= hitCounterMax));
			}
			else
			{
				flag = true;
			}
			if (flag)
			{
				swLimitHit.Restart();
				hitCounter = 0;
			}
			if (!swLimitHit.IsRunning)
			{
				swLimitHit.Start();
			}
			return !flag2;
		}

		public void StartTime()
		{
			swLimitHit.Restart();
		}

		public void ResetAll()
		{
			hitCounter = 0;
			swLimitHit.Reset();
		}
	}
}
namespace Damntry.Utils.Timers.StopwatchImpl
{
	public interface IStopwatch
	{
		bool IsRunning { get; }

		long ElapsedMilliseconds { get; }

		long ElapsedSeconds { get; }

		double ElapsedMillisecondsPrecise { get; }

		double ElapsedSecondsPrecise { get; }

		void Start();

		void Stop();

		void Reset();

		void Restart();
	}
	public class StopwatchDiag : Stopwatch, IStopwatch
	{
		public long ElapsedSeconds => base.ElapsedMilliseconds * 1000;

		public double ElapsedMillisecondsPrecise => base.Elapsed.TotalMilliseconds;

		public double ElapsedSecondsPrecise => base.Elapsed.TotalSeconds;

		public new static StopwatchDiag StartNew()
		{
			StopwatchDiag stopwatchDiag = new StopwatchDiag();
			stopwatchDiag.Start();
			return stopwatchDiag;
		}

		bool IStopwatch.get_IsRunning()
		{
			return base.IsRunning;
		}

		long IStopwatch.get_ElapsedMilliseconds()
		{
			return base.ElapsedMilliseconds;
		}

		void IStopwatch.Start()
		{
			Start();
		}

		void IStopwatch.Stop()
		{
			Stop();
		}

		void IStopwatch.Reset()
		{
			Reset();
		}

		void IStopwatch.Restart()
		{
			Restart();
		}
	}
}
namespace Damntry.Utils.Tasks
{
	public class CancellableSingleTask<T> where T : AsyncDelayBase<T>
	{
		private SemaphoreSlim semaphoreLock;

		private Task task;

		private string taskLogName;

		private CancellationTokenSource cancelTokenSource;

		private bool isSemaphoreAcquiredManually;

		private bool logEvents;

		private int maxExternalSemaphoreAcquireTimeMillis;

		public bool IsTaskRunning
		{
			get
			{
				if (task != null)
				{
					return task.Status == TaskStatus.Running;
				}
				return false;
			}
		}

		public bool IsCancellationRequested
		{
			get
			{
				if (cancelTokenSource != null)
				{
					return cancelTokenSource.IsCancellationRequested;
				}
				return false;
			}
		}

		public CancellationToken CancellationToken
		{
			get
			{
				if (cancelTokenSource != null)
				{
					return cancelTokenSource.Token;
				}
				throw new InvalidOperationException("There is no cancellation token as no task has been started.");
			}
		}

		public CancellableSingleTask(bool logEvents = true)
		{
			this.logEvents = logEvents;
			semaphoreLock = new SemaphoreSlim(1, 1);
			isSemaphoreAcquiredManually = false;
		}

		public async Task StartTaskAsync(Func<Task> asyncWorkerFunction, string taskLogName, bool throwExceptionIfRunning)
		{
			await StartTaskAsync(asyncWorkerFunction, taskLogName, awaitTask: false, throwExceptionIfRunning, newThread: false);
		}

		public async Task StartThreadedTaskAsync(Func<Task> asyncWorkerFunction, string taskLogName, bool throwExceptionIfRunning)
		{
			await StartTaskAsync(asyncWorkerFunction, taskLogName, awaitTask: false, throwExceptionIfRunning, newThread: true);
		}

		public async Task StartThreadedTaskAsync(Action workerFunction, string taskLogName, bool throwExceptionIfRunning)
		{
			await StartTaskAsync(delegate
			{
				workerFunction();
				return Task.CompletedTask;
			}, taskLogName, awaitTask: false, throwExceptionIfRunning, newThread: true);
		}

		public async Task StartAwaitableTaskAsync(Func<Task> asyncWorkerFunction, string taskLogName, bool throwExceptionIfRunning)
		{
			await StartTaskAsync(asyncWorkerFunction, taskLogName, awaitTask: true, throwExceptionIfRunning, newThread: false);
		}

		public async Task StartAwaitableThreadedTaskAsync(Func<Task> asyncWorkerFunction, string taskLogName, bool throwExceptionIfRunning)
		{
			await StartTaskAsync(asyncWorkerFunction, taskLogName, awaitTask: true, throwExceptionIfRunning, newThread: true);
		}

		private async Task StartTaskAsync(Func<Task> asyncWorkerFunction, string taskLogName, bool awaitTask, bool throwIfAlreadyRunning, bool newThread)
		{
			await GetSemaphoreLock();
			try
			{
				if (task != null && !task.IsCompleted)
				{
					if (throwIfAlreadyRunning)
					{
						throw new InvalidOperationException(GetTextAlreadyRunningTask(taskLogName));
					}
					if (logEvents)
					{
						TimeLogger.Logger.LogTimeDebugFunc(() => GetTextAlreadyRunningTask(taskLogName), LogCategories.Task);
					}
					return;
				}
				this.taskLogName = taskLogName;
				cancelTokenSource = new CancellationTokenSource();
				if (logEvents)
				{
					TimeLogger.Logger.LogTimeDebugFunc(() => "Task \"" + taskLogName + "\" is now going to run " + (newThread ? "in a new thread" : "asynchronously") + ".", LogCategories.Task);
				}
				if (newThread)
				{
					task = Task.Run(() => asyncWorkerFunction());
				}
				else
				{
					task = asyncWorkerFunction();
				}
			}
			finally
			{
				semaphoreLock.Release();
			}
			if (awaitTask)
			{
				await task;
			}
			else
			{
				task.FireAndForgetCancels(LogCategories.Task);
			}
		}

		private string GetTextAlreadyRunningTask(string taskLogName)
		{
			StringBuilder stringBuilder = new StringBuilder(25);
			if (this.taskLogName != taskLogName)
			{
				stringBuilder.Append("Cant start task \"");
				stringBuilder.Append(taskLogName);
				stringBuilder.Append("\": ");
			}
			stringBuilder.Append("Task \"");
			stringBuilder.Append(this.taskLogName);
			stringBuilder.Append("\" is already running.");
			return stringBuilder.ToString();
		}

		public async Task StopTaskAndWaitAsync()
		{
			await StopTaskAndWaitAsync(null, null, -1);
		}

		public async Task StopTaskAndWaitAsync(int maxStopTimeMillis)
		{
			await StopTaskAndWaitAsync(null, null, maxStopTimeMillis);
		}

		public async Task StopTaskAndWaitAsync(Action onTaskStopped, int maxStopTimeMillis)
		{
			await StopTaskAndWaitAsync(onTaskStopped, null, maxStopTimeMillis);
		}

		public async Task StopTaskAndWaitAsync(Func<Task> onTaskStoppedAsync, int maxStopTimeMillis)
		{
			await StopTaskAndWaitAsync(null, onTaskStoppedAsync, maxStopTimeMillis);
		}

		private async Task StopTaskAndWaitAsync(Action onTaskStopped, Func<Task> onTaskStoppedAsync, int maxStopTimeMillis)
		{
			await GetSemaphoreLock();
			try
			{
				Task obj = new Task(async delegate
				{
					if (task == null)
					{
						if (logEvents)
						{
							TimeLogger.Logger.LogTimeDebugFunc(() => "Cant stop task \"" + taskLogName + "\". It was never started, or already stopped.", LogCategories.Task);
						}
					}
					else
					{
						if (cancelTokenSource != null && !task.IsTaskEnded())
						{
							if (logEvents)
							{
								TimeLogger.Logger.LogTimeDebugFunc(() => "Canceling task \"" + taskLogName + "\"", LogCategories.Task);
							}
							cancelTokenSource.Cancel();
						}
						else if (logEvents)
						{
							TimeLogger.Logger.LogTimeDebugFunc(() => "Cant stop task \"" + taskLogName + "\". It is already finished.", LogCategories.Task);
						}
						try
						{
							await task;
						}
						catch (Exception ex)
						{
							if (!(ex is TaskCanceledException) && !(ex is OperationCanceledException))
							{
								throw;
							}
							if (logEvents)
							{
								TimeLogger.Logger.LogTimeDebugFunc(() => "Task \"" + taskLogName + "\" successfully canceled.", LogCategories.Task);
							}
						}
						task.Dispose();
						task = null;
						if (onTaskStopped != null)
						{
							onTaskStopped();
						}
						if (onTaskStoppedAsync != null)
						{
							await onTaskStoppedAsync();
						}
					}
				});
				obj.Start();
				await TaskTimeoutMethods<T>.AwaitTaskWithTimeoutAsync(obj, taskLogName, maxStopTimeMillis, throwTimeoutException: true);
			}
			finally
			{
				semaphoreLock.Release();
			}
		}

		private async Task GetSemaphoreLock()
		{
			int millisecondsTimeout = -1;
			if (isSemaphoreAcquiredManually)
			{
				millisecondsTimeout = maxExternalSemaphoreAcquireTimeMillis;
			}
			if (!(await semaphoreLock.WaitAsync(millisecondsTimeout)))
			{
				throw new ExternalSemaphoreHeldException("The operation could not complete because the semaphore was held externally for too long.");
			}
		}

		public async Task WaitSemaphoreAsync(int maxSemaphoreAcquireTimeMillis)
		{
			await WaitSemaphoreTimeoutAsync(-1, maxSemaphoreAcquireTimeMillis);
		}

		public async Task<bool> WaitSemaphoreTimeoutAsync(int millisecondTimeout, int maxSemaphoreAcquireTimeMillis)
		{
			if (isSemaphoreAcquiredManually)
			{
				throw new InvalidOperationException("Semaphore lock has already been manually acquired. You must release it first by calling ReleaseSemaphore().");
			}
			maxExternalSemaphoreAcquireTimeMillis = maxSemaphoreAcquireTimeMillis;
			isSemaphoreAcquiredManually = await semaphoreLock.WaitAsync(millisecondTimeout);
			return isSemaphoreAcquiredManually;
		}

		public void ReleaseSemaphore()
		{
			if (isSemaphoreAcquiredManually)
			{
				isSemaphoreAcquiredManually = false;
				semaphoreLock.Release();
				return;
			}
			throw new InvalidOperationException("No lock for the semaphore was acquired manually. Call WaitSemaphoreAsync() first.");
		}
	}
	public class ExternalSemaphoreHeldException : Exception
	{
		public ExternalSemaphoreHeldException()
		{
		}

		public ExternalSemaphoreHeldException(string message)
			: base(message)
		{
		}

		public ExternalSemaphoreHeldException(string message, Exception inner)
			: base(message, inner)
		{
		}
	}
	public class DelayedSingleTask<T> where T : AsyncDelayBase<T>
	{
		private Task delayedTask;

		private CancellationTokenSource taskCancel;

		private Action actionTask;

		public DelayedSingleTask(Action actionTask)
		{
			if (actionTask == null)
			{
				throw new ArgumentNullException("actionTask");
			}
			this.actionTask = actionTask;
			taskCancel = new CancellationTokenSource();
		}

		public async void Start(int delayMillis)
		{
			if (delayedTask != null && !delayedTask.IsCompleted && !delayedTask.IsCanceled)
			{
				taskCancel.Cancel();
				try
				{
					await delayedTask;
				}
				catch (Exception ex)
				{
					if (!(ex is TaskCanceledException) && !(ex is OperationCanceledException) && !(ex is ThreadAbortException))
					{
						TimeLogger.Logger.LogTimeExceptionWithMessage("Exception while starting and executing delayed task.", ex, LogCategories.Task);
					}
				}
				taskCancel = new CancellationTokenSource();
			}
			delayedTask = StartDelayedCancellableTask(delayMillis);
			delayedTask.FireAndForgetCancels(LogCategories.Task, dismissCancelLog: true);
		}

		private async Task StartDelayedCancellableTask(int delayMillis)
		{
			await AsyncDelayBase<T>.Instance.Delay(delayMillis, taskCancel.Token);
			if (!taskCancel.IsCancellationRequested)
			{
				actionTask();
			}
		}
	}
}
namespace Damntry.Utils.Tasks.TaskTimeout
{
	public class TaskTimeout<T> where T : AsyncDelayBase<T>
	{
		public static async Task StartAwaitableTaskWithTimeoutAsync(Func<CancellationToken, Task> asyncWorkerFunction, string taskLogName, int maxCompletionTimeMillis)
		{
			await StartTaskStaticAndWaitWithTimeoutAsync(asyncWorkerFunction, taskLogName, newThread: false, maxCompletionTimeMillis);
		}

		public static async Task StartAwaitableThreadedTaskWithTimeoutAsync(Func<CancellationToken, Task> asyncWorkerFunction, string taskLogName, int maxCompletionTimeMillis)
		{
			await StartTaskStaticAndWaitWithTimeoutAsync(asyncWorkerFunction, taskLogName, newThread: true, maxCompletionTimeMillis);
		}

		private static async Task StartTaskStaticAndWaitWithTimeoutAsync(Func<CancellationToken, Task> asyncWorkerFunction, string taskLogName, bool newThread, int maxCompletionTimeMillis)
		{
			TimeLogger.Logger.LogTimeDebugFunc(() => "Task \"" + taskLogName + "\" is now going to run " + (newThread ? "in a new thread" : "asynchronously") + ".", LogCategories.Task);
			CancellationTokenSource cancelWorker = new CancellationTokenSource();
			Task workTask = ((!newThread) ? asyncWorkerFunction(cancelWorker.Token) : Task.Run(() => asyncWorkerFunction(cancelWorker.Token)));
			if (!(await TaskTimeoutMethods<T>.AwaitTaskWithTimeoutAsync(workTask, taskLogName, maxCompletionTimeMillis, throwTimeoutException: false)))
			{
				cancelWorker.Cancel();
				await workTask;
				throw new TimeoutException("Task \"" + taskLogName + "\" is finished but it took longer than " + maxCompletionTimeMillis + "ms.");
			}
		}
	}
	internal class TaskTimeoutMethods<T> where T : AsyncDelayBase<T>
	{
		internal static async Task<bool> AwaitTaskWithTimeoutAsync(Task task, string taskLogName, int maxStopTimeMillis, bool throwTimeoutException)
		{
			CancellationTokenSource cancelDelay = new CancellationTokenSource();
			try
			{
				await AwaitTaskWithTimeoutAsync(task, taskLogName, maxStopTimeMillis, cancelDelay.Token);
				if (!task.IsCompleted)
				{
					if (throwTimeoutException)
					{
						throw new TimeoutException($"Task \"{taskLogName}\" took longer than the specified {maxStopTimeMillis} ms to stop.");
					}
					return false;
				}
				return true;
			}
			finally
			{
				cancelDelay.Cancel();
			}
		}

		private static async Task AwaitTaskWithTimeoutAsync(Task task, string taskLogName, int maxStopTimeMillis, CancellationToken cancelToken)
		{
			try
			{
				await Task.WhenAny(new Task[2]
				{
					task,
					AsyncDelayBase<T>.Instance.Delay(maxStopTimeMillis, cancelToken)
				});
			}
			catch (Exception ex)
			{
				if (ex is TaskCanceledException || ex is OperationCanceledException)
				{
					TimeLogger.Logger.LogTimeDebugFunc(() => "Task \"" + taskLogName + "\" successfully canceled.", LogCategories.Task);
					return;
				}
				throw;
			}
		}
	}
}
namespace Damntry.Utils.Tasks.AsyncDelay
{
	public class AsyncDelay : AsyncDelayBase<AsyncDelay>
	{
		public override Task Delay(int millisecondsDelay)
		{
			return Task.Delay(millisecondsDelay);
		}

		public override Task Delay(int millisecondsDelay, CancellationToken cancellationToken)
		{
			return Task.Delay(millisecondsDelay, cancellationToken);
		}
	}
	public abstract class AsyncDelayBase<T> where T : AsyncDelayBase<T>
	{
		private static AsyncDelayBase<T> instance = Activator.CreateInstance<T>();

		public static AsyncDelayBase<T> Instance => instance;

		public abstract Task Delay(int millisecondsDelay);

		public abstract Task Delay(int millisecondsDelay, CancellationToken cancellationToken);
	}
}
namespace Damntry.Utils.Reflection
{
	public static class AssemblyUtils
	{
		private static Assembly[] assemblyCache;

		public static MethodInfo GetMethodFromLoadedAssembly(string fullTypeName, string methodName, bool refreshCache = true)
		{
			return GetTypeFromLoadedAssemblies(fullTypeName, refreshCache).GetMethod(methodName, ReflectionHelper.AllBindings);
		}

		public static Type GetTypeFromLoadedAssemblies(string fullTypeName, bool refreshCache = true)
		{
			if (refreshCache || assemblyCache == null)
			{
				assemblyCache = AppDomain.CurrentDomain.GetAssemblies();
			}
			return (from a in assemblyCache
				select a.GetType(fullTypeName, throwOnError: false) into t
				where t != null
				select t).FirstOrDefault();
		}

		public static Type[] GetTypesFromLoadedAssemblies(bool refreshCache, params string[] argumentFullTypeNames)
		{
			if (argumentFullTypeNames == null)
			{
				return null;
			}
			bool flag = true;
			List<Type> list = new List<Type>(argumentFullTypeNames.Length);
			foreach (string text in argumentFullTypeNames)
			{
				Type typeFromLoadedAssemblies = GetTypeFromLoadedAssemblies(text, flag && refreshCache);
				if (typeFromLoadedAssemblies == null)
				{
					throw new ArgumentException("The type with value \"" + text + "\" couldnt be found in the assembly.");
				}
				list.Add(typeFromLoadedAssemblies);
				flag = false;
			}
			return list?.ToArray();
		}

		public static string GetAssemblyDllFilePath(Type assemblyType)
		{
			return Assembly.GetAssembly(assemblyType).Location;
		}

		public static string GetAssemblyDllFolderPath(Type assemblyType)
		{
			return Path.GetDirectoryName(GetAssemblyDllFilePath(assemblyType));
		}

		public static string GetCombinedPathFromAssemblyFolder(Type assemblyType, string addedPath)
		{
			string text = GetAssemblyDllFolderPath(assemblyType);
			char directorySeparatorChar = Path.DirectorySeparatorChar;
			if (!addedPath.StartsWith(directorySeparatorChar.ToString()))
			{
				string text2 = text;
				directorySeparatorChar = Path.DirectorySeparatorChar;
				text = text2 + directorySeparatorChar;
			}
			return text + addedPath;
		}
	}
	public class MemberInfoHelper : MemberInfo
	{
		private readonly MemberInfo member;

		private FieldInfo Field => (FieldInfo)member;

		private PropertyInfo Property => (PropertyInfo)member;

		public bool IsStatic => member.MemberType switch
		{
			MemberTypes.Field => Field.IsStatic, 
			MemberTypes.Property => Property.IsStatic(), 
			_ => throw new NotImplementedException(), 
		};

		public Type MemberInfoType => member.MemberType switch
		{
			MemberTypes.Field => Field.FieldType, 
			MemberTypes.Property => Property.PropertyType, 
			_ => throw new NotImplementedException(), 
		};

		public override MemberTypes MemberType => member.MemberType;

		public override string Name => member.Name;

		public override Type DeclaringType => member.DeclaringType;

		public override Type ReflectedType => member.ReflectedType;

		public MemberInfoHelper(MemberInfo memberInfo)
		{
			if (memberInfo == null)
			{
				throw new ArgumentNullException("member");
			}
			if (!(memberInfo is FieldInfo) && !(memberInfo is PropertyInfo))
			{
				throw new NotSupportedException("Only FieldInfo and PropertyInfo members are supported.");
			}
			member = memberInfo;
		}

		public void SetValue(object obj, object value)
		{
			if (member.MemberType == MemberTypes.Field)
			{
				Field.SetValue(obj, value);
			}
			else if (member.MemberType == MemberTypes.Property)
			{
				Property.SetValue(obj, value);
			}
		}

		public object GetValue(object obj)
		{
			if (member.MemberType == MemberTypes.Field)
			{
				return Field.GetValue(obj);
			}
			if (member.MemberType == MemberTypes.Property)
			{
				return Property.GetValue(obj);
			}
			throw new NotImplementedException();
		}

		public object GetValueStaticAgnostic(object obj)
		{
			obj = (IsStatic ? null : obj);
			if (member.MemberType == MemberTypes.Field)
			{
				return Field.GetValue(obj);
			}
			if (member.MemberType == MemberTypes.Property)
			{
				return Property.GetValue(obj);
			}
			throw new NotImplementedException();
		}

		public override object[] GetCustomAttributes(bool inherit)
		{
			return member.GetCustomAttributes(inherit);
		}

		public override object[] GetCustomAttributes(Type attributeType, bool inherit)
		{
			return member.GetCustomAttributes(attributeType, inherit);
		}

		public override bool IsDefined(Type attributeType, bool inherit)
		{
			return member.IsDefined(attributeType, inherit);
		}
	}
	public static class ReflectionHelper
	{
		public enum MemberType
		{
			Property,
			Field,
			Both
		}

		public static BindingFlags AllBindings { get; } = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.SetField | BindingFlags.GetProperty | BindingFlags.SetProperty;


		public static void CallMethod(object classInstance, string methodName, object[] args = null)
		{
			CallMethod<object>(classInstance, methodName, args);
		}

		public static R CallStaticMethod<R>(Type classType, string methodName, object[] args = null)
		{
			return CallMethod<R>(null, classType, methodName, args);
		}

		public static R CallMethod<R>(object classInstance, string methodName, object[] args = null)
		{
			return CallMethod<R>(classInstance, classInstance.GetType(), methodName, args);
		}

		private static R CallMethod<R>(object classInstance, Type classType, string methodName, object[] args = null)
		{
			MethodInfo method = classType.GetMethod(methodName, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
			return CallMethod<R>(classInstance, method, args);
		}

		public static R CallMethod<R>(object classInstance, MethodInfo methodInfo, object[] args = null)
		{
			try
			{
				return (R)methodInfo.Invoke(classInstance, args);
			}
			catch (TargetParameterCountException e)
			{
				TimeLogger.Logger.LogTimeExceptionWithMessage("Parameter count error while calling method " + methodInfo.Name, e, LogCategories.Reflect);
				throw;
			}
		}

		public static string ListMemberValues(object target, MemberType memberType, bool showPrivate = true)
		{
			BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Public;
			if (showPrivate)
			{
				bindingFlags |= BindingFlags.NonPublic;
			}
			StringBuilder sbMembers = new StringBuilder();
			MemberInfo[] array = Array.Empty<MemberInfo>();
			if (memberType == MemberType.Both || memberType == MemberType.Property)
			{
				MemberInfo[] properties = target.GetType().GetProperties(bindingFlags);
				array = properties;
			}
			if (memberType == MemberType.Both || memberType == MemberType.Field)
			{
				if (array.Length != 0)
				{
					array = array.Concat(target.GetType().GetFields(bindingFlags)).ToArray();
				}
				else
				{
					MemberInfo[] properties = target.GetType().GetFields(bindingFlags);
					array = properties;
				}
			}
			Array.ForEach(array, delegate(MemberInfo minfo)
			{
				sbMembers.Append(minfo.Name);
				sbMembers.Append(" = ");
				if (minfo is PropertyInfo)
				{
					sbMembers.Append(((PropertyInfo)minfo).GetValue(target, null));
				}
				else if (minfo is FieldInfo)
				{
					sbMembers.Append(((FieldInfo)minfo).GetValue(target));
				}
				sbMembers.AppendLine();
			});
			return sbMembers.ToString();
		}

		public static string ConvertFullTypeToNormal(string type)
		{
			if (string.IsNullOrEmpty(type) || !type.Contains("."))
			{
				return type;
			}
			return type.Substring(type.LastIndexOf(".") + 1);
		}

		public static string[] ConvertFullTypesToNormal(params string[] types)
		{
			string[] result = null;
			if (types == null || !types.Any())
			{
				result = types.Select((string s) => ConvertFullTypeToNormal(s)).ToArray();
			}
			return result;
		}

		public static object GetDefaultValue(this Type type)
		{
			return FormatterServices.GetUninitializedObject(type);
		}
	}
}
namespace Damntry.Utils.Maths
{
	public static class MathMethods
	{
		public static ulong GreatestCommonDivisor(ulong n1, ulong n2)
		{
			while (n1 != 0L && n2 != 0L)
			{
				if (n1 > n2)
				{
					n1 %= n2;
				}
				else
				{
					n2 %= n1;
				}
			}
			return n1 | n2;
		}

		public static int CountDigits(uint num)
		{
			if ((long)num != 0L)
			{
				return (((long)num > 0L) ? 1 : 2) + (int)Math.Log10(Math.Abs((double)num));
			}
			return 1;
		}

		public static int CountDigits(int num)
		{
			return CountDigits((uint)num);
		}
	}
}
namespace Damntry.Utils.Logging
{
	public class LOG
	{
		public static void TEMPDEBUG(string message, bool onlyIfTrue = true)
		{
		}

		public static void TEMPDEBUG_FUNC(Func<string> textLambda, bool onlyIfTrue = true)
		{
		}

		public static void Debug(string message, LogCategories logCategory, bool onlyIfTrue = true)
		{
		}

		public static void Debug_func(Func<string> textLambda, LogCategories logCategory, bool onlyIfTrue = true)
		{
		}

		public static void TEMPWARNING(string message, bool onlyIfTrue = true)
		{
		}

		public static void TEMPWARNING_FUNC(Func<string> textLambda, bool onlyIfTrue = true)
		{
		}

		public static void TEMPFATAL(string message, bool onlyIfTrue = true)
		{
		}

		public static void TEMP(LogTier logLevel, string message, bool onlyIfTrue = true)
		{
		}

		private static void Log(LogTier logLevel, string message, bool onlyIfTrue = true, LogCategories logCategory = LogCategories.TempTest)
		{
		}

		private static void LogFunc(LogTier logLevel, Func<string> textLambda, bool onlyIfTrue = true, LogCategories logCategory = LogCategories.TempTest)
		{
		}
	}
	public sealed class DefaultTimeLogger : TimeLogger
	{
		protected override void InitializeLogger(params object[] args)
		{
		}

		protected override void LogMessage(string message, LogTier logLevel)
		{
			ConsoleColor consoleColor = ConsoleColor.Gray;
			switch (logLevel)
			{
			case LogTier.All:
				consoleColor = ConsoleColor.White;
				break;
			case LogTier.Debug:
				consoleColor = ConsoleColor.DarkGray;
				break;
			case LogTier.Info:
				consoleColor = ConsoleColor.Gray;
				break;
			case LogTier.Warning:
				consoleColor = ConsoleColor.Yellow;
				break;
			case LogTier.Error:
				consoleColor = ConsoleColor.DarkRed;
				break;
			case LogTier.Fatal:
				consoleColor = ConsoleColor.Red;
				break;
			case LogTier.Message:
				consoleColor = ConsoleColor.Gray;
				break;
			case LogTier.None:
				return;
			default:
				throw new InvalidOperationException("Invalid log level.");
			}
			Console.ForegroundColor = consoleColor;
			Console.WriteLine(message);
			Console.ResetColor();
		}
	}
	public static class Performance
	{
		private enum StopResetAction
		{
			Stop,
			Reset,
			Record,
			Log
		}

		public static class PerformanceFileLoggingMethods
		{
			public static async Task BeginOrResumePerfFileLoggingWithTextFunc(Func<string> getFirstPerfLogLineFunc)
			{
				if (TimeLogger.DebugEnabled)
				{
					string firstPerfLogText = null;
					if (getFirstPerfLogLineFunc != null)
					{
						firstPerfLogText = getFirstPerfLogLineFunc();
					}
					await PerfLogger.DLog.BeginPerfFileLoggingWithText(firstPerfLogText);
				}
			}

			public static async Task BeginOrResumePerfFileLoggingWithText(string firstPerfLogLine)
			{
				if (TimeLogger.DebugEnabled)
				{
					await PerfLogger.DLog.BeginPerfFileLoggingWithText(firstPerfLogLine);
				}
			}

			public static async Task BeginOrResumePerfFileLogging()
			{
				if (TimeLogger.DebugEnabled)
				{
					await PerfLogger.DLog.BeginPerfFileLoggingWithText(null);
				}
			}

			public static async Task StopPerfFileLogging()
			{
				if (PerfLogger.IsInstanced)
				{
					await PerfLogger.DLog.StopPerfFileLogging();
				}
			}
		}

		public static class PerformanceTableLoggingMethods
		{
			public static async Task StartLogPerformanceTableNewThread(int logTableIntervalMillis)
			{
				await logTableTask.StartThreadedTaskAsync(() => LogPerformanceTableInterval(logTableIntervalMillis), "Logger performance table", throwExceptionIfRunning: true);
			}

			public static async Task StopThreadLogPerformanceTable()
			{
				await logTableTask.StopTaskAndWaitAsync(5000);
			}

			public static void LogPerformanceTable()
			{
				Performance.LogPerformanceTable();
			}
		}

		private class StopwatchMeasure : Stopwatch
		{
			private string name;

			private bool showTotals;

			private double lastRunMilli;

			private int runCount;

			private double min;

			private double max;

			private TrimmedMean trimmedMean;

			public double TotalMilli { get; private set; }

			public StopwatchMeasure(string measureName, bool showTotals)
			{
				this.showTotals = showTotals;
				name = measureName;
				trimmedMean = new TrimmedMean();
				initializeMeasure();
			}

			private void initializeMeasure()
			{
				TotalMilli = 0.0;
				runCount = 0;
				min = 2147483647.0;
				max = 0.0;
				trimmedMean.Initialize();
			}

			[Obsolete("Use Start(resetRunValues) instead.", true)]
			public new void Start()
			{
			}

			public void Start(bool resetRunValues)
			{
				if (resetRunValues)
				{
					initializeMeasure();
				}
				base.Start();
			}

			public void RecordRun()
			{
				lastRunMilli = base.Elapsed.TotalMilliseconds;
				if (showTotals)
				{
					TotalMilli += lastRunMilli;
					runCount++;
					if (lastRunMilli < min)
					{
						min = lastRunMilli;
					}
					if (lastRunMilli > max)
					{
						max = lastRunMilli;
					}
					trimmedMean.addNewValue(lastRunMilli);
				}
				Reset();
			}

			public string GetLogString()
			{
				string text = $"{name} has taken {lastRunMilli:F3} ms";
				if (showTotals)
				{
					text += $", with a total of {TotalMilli:F3}ms spent in {runCount} run/s. Avg run: {GetAverageRun(formatTiming: false)}ms, Min: {min:F3}ms, Max: {max:F3}ms";
				}
				return text + ".";
			}

			public (string name, string total, string runs, string avg, string meanTrim, string min, string max) GetFormattedRunValues(int measureNameMaxLength)
			{
				return (name.PadRight(measureNameMaxLength), FormatTiming(TotalMilli), ((base.IsRunning ? "*" : "") + runCount).PadLeft(RunCountPadding), GetAverageRun(formatTiming: true), GetMeanTrimmedRun(), FormatTiming(min), FormatTiming(max));
			}

			private string GetAverageRun(bool formatTiming)
			{
				double number = Math.Round(TotalMilli / (double)runCount, MeasureDecimals);
				if (!formatTiming)
				{
					return number.ToString();
				}
				return FormatTiming(number);
			}

			private string GetMeanTrimmedRun()
			{
				string result = "";
				(double, TrimmedMean.CalculationResult) tuple = trimmedMean.GetTrimmedMean();
				if (tuple.Item2 == TrimmedMean.CalculationResult.NotEnoughData)
				{
					result = "*Collecting*".PadSides(MeasureTimingsPadding);
				}
				else if (tuple.Item2 == TrimmedMean.CalculationResult.Partial)
				{
					result = FormatTiming(tuple.Item1, "~");
				}
				else if (tuple.Item2 == TrimmedMean.CalculationResult.Full)
				{
					result = FormatTiming(tuple.Item1);
				}
				return result;
			}

			private string FormatTiming(double number, string leftSymbol = null)
			{
				string text = string.Format($"{{0:F{MeasureDecimals}}}ms", number);
				return (((leftSymbol != null) ? leftSymbol : "") + text).PadLeft(MeasureTimingsPadding);
			}
		}

		private class TrimmedMean
		{
			public enum CalculationResult
			{
				NotEnoughData,
				Partial,
				Full
			}

			private List<double> historyValues;

			private int rollingIndex;

			private readonly int maxNumValues;

			private readonly int minNumValues;

			private readonly int trimPercentage;

			public TrimmedMean(int minValuesHistoric = 5, int maxValuesHistoric = 30, int trimPercentage = 5)
			{
				if (minValuesHistoric > maxValuesHistoric)
				{
					throw new ArgumentException("minValuesHistoric must be less or equal than maxValuesHistoric.");
				}
				minNumValues = minValuesHistoric.ClampReturn(5, int.MaxValue);
				maxNumValues = maxValuesHistoric.ClampReturn(5, int.MaxValue);
				this.trimPercentage = trimPercentage.ClampReturn(0, 99);
				Initialize();
			}

			public void Initialize()
			{
				if (historyValues == null)
				{
					historyValues = new List<double>(maxNumValues);
				}
				else
				{
					historyValues.Clear();
				}
				rollingIndex = 0;
			}

			public void addNewValue(double value)
			{
				if (historyValues.Count > maxNumValues)
				{
					throw new InvalidOperationException("The trimmed mean cant contain more values that the specified limit.");
				}
				if (historyValues.Count == maxNumValues)
				{
					historyValues[rollingIndex] = value;
				}
				else
				{
					historyValues.Add(value);
				}
				rollingIndex++;
				if (rollingIndex >= maxNumValues)
				{
					rollingIndex = 0;
				}
			}

			public (double trimmedMean, CalculationResult calcResult) GetTrimmedMean()
			{
				CalculationResult item = CalculationResult.NotEnoughData;
				if (historyValues.Count < minNumValues)
				{
					return (0.0, item);
				}
				item = ((historyValues.Count < maxNumValues) ? CalculationResult.Partial : CalculationResult.Full);
				List<double> list = new List<double>(historyValues);
				list.Sort();
				int num = (int)Math.Round((double)maxNumValues * ((double)trimPercentage / 100.0), 0);
				double num2 = 0.0;
				for (int i = num; i < list.Count - num; i++)
				{
					num2 += list[i];
				}
				return (num2 / (double)(list.Count - num * 2), item);
			}
		}

		private class PerfLogger
		{
			private static readonly Lazy<PerfLogger> instance = new Lazy<PerfLogger>(() => new PerfLogger());

			private static readonly Lazy<string> pathLogFile = new Lazy<string>(() => GetLogPathFile());

			private static readonly string folderPerformanceLogs = "PerformanceLogs";

			private static readonly int logIntervalTime = 5000;

			private static Queue<string> logQueue;

			private static object queueLock;

			private static CancellableSingleTask<AsyncDelay> threadedTask;

			private StringBuilder sbLogText;

			public static PerfLogger DLog => instance.Value;

			public static bool IsInstanced => instance != null;

			private PerfLogger()
			{
				logQueue = new Queue<string>();
				queueLock = new object();
				threadedTask = new CancellableSingleTask<AsyncDelay>();
				sbLogText = new StringBuilder();
			}

			public async Task BeginPerfFileLoggingWithText(string firstPerfLogText)
			{
				if (firstPerfLogText != null && firstPerfLogText != "")
				{
					QueueAtFront(firstPerfLogText);
				}
				await threadedTask.StartThreadedTaskAsync((Func<Task>)LogConsumer, "Write performance log", throwExceptionIfRunning: true);
			}

			public async Task StopPerfFileLogging()
			{
				await threadedTask.StopTaskAndWaitAsync(5000);
				WriteBacklogToDisk(checkCancellation: false);
			}

			private void QueueAtFront(string firstPerfLogText)
			{
				lock (queueLock)
				{
					string[] array = logQueue.ToArray();
					logQueue.Clear();
					logQueue.Enqueue(firstPerfLogText);
					string[] array2 = array;
					foreach (string item in array2)
					{
						logQueue.Enqueue(item);
					}
				}
			}

			public void LogPerformance(string message)
			{
				lock (queueLock)
				{
					logQueue.Enqueue(message);
				}
			}

			private async Task LogConsumer()
			{
				if (TimeLogger.DebugEnabled)
				{
					TimeLogger.Logger.LogTimeDebugFunc(() => "Beginning performance logging on file \"" + pathLogFile.Value + "\"", LogCategories.Loading);
					while (!threadedTask.IsCancellationRequested)
					{
						WriteBacklogToDisk(checkCancellation: true);
						await Task.Delay(logIntervalTime, threadedTask.CancellationToken);
					}
					TimeLogger.Logger.LogTimeDebug("Performance logging stopped.", LogCategories.Loading);
				}
			}

			private void WriteBacklogToDisk(bool checkCancellation)
			{
				lock (queueLock)
				{
					if (logQueue.Count > 0)
					{
						do
						{
							sbLogText.AppendLine(logQueue.Dequeue());
						}
						while (logQueue.Count > 0);
					}
				}
				if ((!checkCancellation || !threadedTask.IsCancellationRequested) && sbLogText.Length > 0)
				{
					LogToDisk(sbLogText.ToString());
					sbLogText.Clear();
				}
			}

			private void LogToDisk(string text)
			{
				string directoryName = Path.GetDirectoryName(pathLogFile.Value);
				if (!Directory.Exists(directoryName))
				{
					Directory.CreateDirectory(directoryName);
				}
				using StreamWriter streamWriter = new StreamWriter(pathLogFile.Value, append: true);
				streamWriter.Write(text);
			}

			private static string GetLogPathFile()
			{
				return Path.Combine(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), folderPerformanceLogs), "PerformanceLog_" + DateTime.Now.ToString("yyyy.MM.dd-HH.mm.ss") + ".log");
			}
		}

		private static Dictionary<string, StopwatchMeasure> mapMeasures = new Dictionary<string, StopwatchMeasure>();

		private static int measureNameMaxLength;

		private static readonly int MeasureDecimals = 3;

		private static readonly int MeasureTimingsPadding = MeasureDecimals + 9;

		private static readonly int MeasureTotalTimingPadding = MeasureTimingsPadding + 2;

		private static readonly int RunCountPadding = 8;

		private static Stopwatch swPerfTotalRunTime;

		private static readonly Lazy<string> StaticHeaderText = new Lazy<string>(() => GetStaticHeaderText());

		private static readonly Lazy<string> StaticHorizontalSeparatorText = new Lazy<string>(() => GetStaticHorizontalSeparatorText());

		private static Action<string> logPerfAction = delegate(string text)
		{
			PerfLogger.DLog.LogPerformance(text);
		};

		private static CancellableSingleTask<AsyncDelay> logTableTask = new CancellableSingleTask<AsyncDelay>();

		public static void Start(string measureName, bool logTotals = true)
		{
			GetCreateMeasure(measureName, logTotals).Start(resetRunValues: false);
		}

		public static void StartOver(string measureName, bool logTotals = true)
		{
			GetCreateMeasure(measureName, logTotals).Start(resetRunValues: true);
		}

		public static void Reset(string measureName, bool doNotWarn = false)
		{
			StopOrReset(measureName, StopResetAction.Reset, doNotWarn);
		}

		public static void Stop(string measureName, bool doNotWarn = false)
		{
			StopOrReset(measureName, StopResetAction.Stop, doNotWarn);
		}

		public static void StopAndLog(string measureName, bool doNotWarn = false)
		{
			StopOrReset(measureName, StopResetAction.Log, doNotWarn);
		}

		public static void StopAndRecord(string measureName, bool doNotWarn = false)
		{
			StopOrReset(measureName, StopResetAction.Record, doNotWarn);
		}

		private static void StopOrReset(string measureName, StopResetAction stopResetAction, bool doNotWarn)
		{
			StopwatchMeasure swMeasure = GetMeasure(measureName, doNotWarn);
			if (swMeasure == null)
			{
				return;
			}
			if (stopResetAction == StopResetAction.Reset)
			{
				swMeasure.Reset();
				return;
			}
			if (swMeasure.IsRunning)
			{
				swMeasure.Stop();
			}
			if (stopResetAction != StopResetAction.Record && stopResetAction != StopResetAction.Log)
			{
				return;
			}
			swMeasure.RecordRun();
			if (stopResetAction == StopResetAction.Log)
			{
				LogPerformance(() => swMeasure.GetLogString());
			}
		}

		private static StopwatchMeasure GetCreateMeasure(string measureName, bool logTotals)
		{
			mapMeasures.TryGetValue(measureName, out var value);
			if (value == null)
			{
				value = new StopwatchMeasure(measureName, logTotals);
				mapMeasures.Add(measureName, value);
				measureNameMaxLength = Math.Max(measureNameMaxLength, measureName.Length);
				if (swPerfTotalRunTime == null)
				{
					swPerfTotalRunTime = Stopwatch.StartNew();
				}
			}
			return value;
		}

		private static StopwatchMeasure GetMeasure(string measureName, bool doNotWarn)
		{
			if (!mapMeasures.TryGetValue(measureName, out var value) && !doNotWarn)
			{
				TimeLogger.Logger.LogTimeWarning("The specified stopwatch \"" + measureName + "\" doesnt exist.", LogCategories.PerfTest);
			}
			return value;
		}

		private static async Task LogPerformanceTableInterval(int logTableIntervalMillis)
		{
			while (!logTableTask.IsCancellationRequested)
			{
				await Task.Delay(logTableIntervalMillis, logTableTask.CancellationToken);
				LogPerformanceTable();
			}
		}

		private static void LogPerformanceTable()
		{
			LogPerformance(() => GetAllMeasuresTotalsSorted());
		}

		private static void LogPerformance(Func<string> logTextFunc)
		{
			TimeLogger.Logger.LogTimeDebugFunc(logTextFunc, LogCategories.PerfTest, (logPerfAction, true));
		}

		private static string GetAllMeasuresTotalsSorted()
		{
			List<StopwatchMeasure> list = (from x in mapMeasures.Values.ToList()
				orderby x.TotalMilli descending
				select x).ToList();
			string value = "".PadRight(5, '\t');
			string logStringSummaryHorizontalSeparator = GetLogStringSummaryHorizontalSeparator();
			string logStringSummaryHeader = GetLogStringSummaryHeader();
			StringBuilder stringBuilder = new StringBuilder(100 + 125 * list.Count);
			stringBuilder.Append("Performance table, sorted by total time. ");
			if (swPerfTotalRunTime != null)
			{
				stringBuilder.AppendLine("The total run time since the Start of the first measure is " + swPerfTotalRunTime.Elapsed.ToString("hh':'mm':'ss'.'fff"));
			}
			else
			{
				stringBuilder.AppendLine("No measures have been created yet.");
			}
			stringBuilder.Append(value);
			stringBuilder.AppendLine(logStringSummaryHorizontalSeparator);
			stringBuilder.Append(value);
			stringBuilder.AppendLine(logStringSummaryHeader);
			stringBuilder.Append(value);
			stringBuilder.Append(logStringSummaryHorizontalSeparator);
			foreach (StopwatchMeasure item in list)
			{
				stringBuilder.AppendLine();
				stringBuilder.Append(value);
				stringBuilder.Append(GetLogStringSummaryRunValues(item));
			}
			stringBuilder.AppendLine();
			stringBuilder.Append(value);
			stringBuilder.AppendLine(logStringSummaryHorizontalSeparator);
			return stringBuilder.ToString();
		}

		private static string GetLogStringSummaryHeader()
		{
			return "| " + "Measure name".PadSides(measureNameMaxLength) + " " + StaticHeaderText.Value;
		}

		private static string GetLogStringSummaryHorizontalSeparator()
		{
			return "|-" + "".PadSides(measureNameMaxLength, '-') + "-" + StaticHorizontalSeparatorText.Value;
		}

		private static string GetLogStringSummaryRunValues(StopwatchMeasure measure)
		{
			(string, string, string, string, string, string, string) formattedRunValues = measure.GetFormattedRunValues(measureNameMaxLength);
			return "| " + formattedRunValues.Item1 + " | " + formattedRunValues.Item2 + " | " + formattedRunValues.Item3 + " | " + formattedRunValues.Item4 + " | " + formattedRunValues.Item5 + " | " + formattedRunValues.Item6 + " | " + formattedRunValues.Item7 + " |";
		}

		private static string GetStaticHeaderText()
		{
			return "| " + "Total".PadSides(MeasureTotalTimingPadding) + " | " + "Runs".PadSides(RunCountPadding) + " | " + "Average".PadSides(MeasureTimingsPadding) + " | " + "Mean Trimmed".PadSides(MeasureTimingsPadding) + " | " + "Min".PadSides(MeasureTimingsPadding) + " | " + "Max".PadSides(MeasureTimingsPadding) + " |";
		}

		private static string GetStaticHorizontalSeparatorText()
		{
			return "|-" + "".PadSides(MeasureTotalTimingPadding, '-') + "-|-" + "".PadSides(RunCountPadding, '-') + "-|-" + "".PadSides(MeasureTimingsPadding, '-') + "-|-" + "".PadSides(MeasureTimingsPadding, '-') + "-|-" + "".PadSides(MeasureTimingsPadding, '-') + "-|-" + "".PadSides(MeasureTimingsPadding, '-') + "-|";
		}
	}
	public static class StringExtensions
	{
		public static string PadSides(this string str, int totalWidth, char paddingChar = ' ', bool padLeftOnUneven = true)
		{
			int num = totalWidth - str.Length;
			if (num % 2 == 1)
			{
				str = (padLeftOnUneven ? str.PadLeft(str.Length + 1, paddingChar) : str.PadRight(str.Length + 1, paddingChar));
				num--;
			}
			if (num < 1)
			{
				return str;
			}
			int totalWidth2 = num / 2 + str.Length;
			return str.PadLeft(totalWidth2, paddingChar).PadRight(totalWidth, paddingChar);
		}
	}
	public enum PreprocessType
	{
		FileLogging,
		GameNotification
	}
	[Flags]
	public enum LogTier
	{
		None = 0,
		Fatal = 1,
		Error = 2,
		Warning = 4,
		Message = 8,
		Info = 0x10,
		Debug = 0x20,
		All = -1
	}
	[Flags]
	public enum LogCategories
	{
		Null = 0,
		TempTest = 1,
		Vanilla = 2,
		PerfTest = 4,
		Loading = 8,
		Task = 0x10,
		Reflect = 0x20,
		Config = 0x40,
		PerfCheck = 0x80,
		Events = 0x100,
		Network = 0x200,
		Cache = 0x400,
		UI = 0x800,
		Notifs = 0x100000,
		AutoPatch = 0x200000,
		MethodChk = 0x400000,
		OtherMod = 0x800000,
		JobSched = 0x1000000,
		KeyMouse = 0x2000000,
		Highlight = 0x4000000,
		AI = 0x8000000,
		Visuals = 0x10000000,
		Other = int.MinValue,
		All = -1
	}
	public abstract class TimeLogger
	{
		public delegate string PreprocessMessageFunc(string message, LogTier logLevel, LogCategories category, bool showInGameNotification, PreprocessType preprocType);

		private static TimeLogger instance;

		private Dictionary<LogCategories, string> logCategoryStringCache;

		private static string notificationMsgPrefix;

		private static Action<string, LogTier> notificationAction;

		private static PreprocessMessageFunc globalPreprocessMessageFunc;

		private int maxCategoryLength = Enum.GetNames(typeof(LogCategories)).Aggregate("", (string max, string cur) => (max.Length <= cur.Length) ? cur : max).Length;

		private LogCategories AllowedCategories;

		public static TimeLogger Logger
		{
			get
			{
				if (instance == null)
				{
					InitializeTimeLogger<DefaultTimeLogger>(debugEnabled: false, Array.Empty<object>());
					instance.LogTimeWarning("TimeLogger has been automatically initialized with a DefaultTimeLogger. If you want to use a different custom logger, call a InitializeTimeLogger...() method earlier.", LogCategories.Loading);
				}
				return instance;
			}
		}

		public static bool DebugEnabled { get; set; }

		protected TimeLogger()
		{
			logCategoryStringCache = new Dictionary<LogCategories, string>();
		}

		protected abstract void LogMessage(string logMessage, LogTier logLevel);

		protected abstract void InitializeLogger(params object[] argsT);

		public static void InitializeTimeLogger<T>(bool debugEnabled = false, params object[] argsT) where T : TimeLogger
		{
			InitializeTimeLogger<T>(null, debugEnabled, argsT);
		}

		public static void InitializeTimeLogger<T>(PreprocessMessageFunc preprocessMessageFunc, bool debugEnabled = false, params object[] argsT) where T : TimeLogger
		{
			DebugEnabled = debugEnabled;
			globalPreprocessMessageFunc = preprocessMessageFunc;
			instance = Activator.CreateInstance<T>();
			instance.InitializeLogger(argsT);
		}

		public static void InitializeTimeLoggerWithGameNotifications<T>(Action<string, LogTier> notificationAction, string notificationMsgPrefix, bool debugEnabled = false, params object[] argsT) where T : TimeLogger
		{
			InitializeTimeLoggerWithGameNotifications<T>(null, notificationAction, notificationMsgPrefix, debugEnabled, argsT);
		}

		public static void InitializeTimeLoggerWithGameNotifications<T>(PreprocessMessageFunc preprocessMessageFunc, Action<string, LogTier> notificationAction, string notificationMsgPrefix, bool debugEnabled = false, params object[] argsT) where T : TimeLogger
		{
			if (notificationAction == null)
			{
				throw new ArgumentNullException("notificationAction", "The argument notificationAction cannot be null. Call InitializeTimeLogger(...) instead.");
			}
			InitializeTimeLogger<T>(preprocessMessageFunc, debugEnabled, argsT);
			AddGameNotificationSupport(notificationAction, notificationMsgPrefix);
		}

		public static void AddGameNotificationSupport(Action<string, LogTier> notificationAction, string notificationMsgPrefix)
		{
			if (notificationAction == null)
			{
				throw new ArgumentNullException("notificationAction");
			}
			TimeLogger.notificationAction = notificationAction;
			TimeLogger.notificationMsgPrefix = ((notificationMsgPrefix != null) ? notificationMsgPrefix : "");
		}

		public static void RemoveGameNotificationSupport()
		{
			notificationAction = null;
			notificationMsgPrefix = null;
		}

		public void LogTimeInfo(string text, LogCategories category)
		{
			LogTimeInternal(LogTier.Info, text, category, showInGameNotification: false, null);
		}

		public void LogTimeInfoShowInGame(string text, LogCategories category)
		{
			LogTimeInternal(LogTier.Info, text, category, showInGameNotification: true, null);
		}

		public void LogTimeMessage(string text, LogCategories category)
		{
			LogTimeInternal(LogTier.Message, text, category, showInGameNotification: false, null);
		}

		public void LogTimeMessageShowInGame(string text, LogCategories category)
		{
			LogTimeInternal(LogTier.Message, text, category, showInGameNotification: true, null);
		}

		public void LogTimeDebug(string text, LogCategories category)
		{
			LogTimeInternal(LogTier.Debug, text, category, showInGameNotification: false, null);
		}

		public void LogTimeDebugShowInGame(string text, LogCategories category)
		{
			LogTimeInternal(LogTier.Debug, text, category, showInGameNotification: true, null);
		}

		public void LogTimeDebug(string text, LogCategories category, bool showInGameNotification)
		{
			LogTimeInternal(LogTier.Debug, text, category, showInGameNotification, null);
		}

		public void LogTimeDebugFunc(Func<string> textLambda, LogCategories category)
		{
			LogTimeInternalFunc(LogTier.Debug, textLambda, category, false);
		}

		public void LogTimeDebugFunc(Func<string> textLambda, LogCategories category, params (Action<string> action, bool useFullLog)[] actionsArgs)
		{
			LogTimeInternalFunc(LogTier.Debug, textLambda, category, showInGameNotification: false, actionsArgs);
		}

		public void LogTimeDebugFuncShowInGame(Func<string> textLambda, LogCategories category)
		{
			LogTimeInternalFunc(LogTier.Debug, textLambda, category, true);
		}

		public void LogTimeDebugFunc(Func<string> textLambda, LogCategories category, bool showInGameNotification)
		{
			LogTimeInternalFunc(LogTier.Debug, textLambda, category, showInGameNotification);
		}

		public void LogTimeDebugFunc(Func<string> textLambda, LogCategories category, bool showInGameNotification, params (Action<string> action, bool useFullLog)[] actionsArgs)
		{
			LogTimeInternalFunc(LogTier.Debug, textLambda, category, showInGameNotification, actionsArgs);
		}

		public void LogTimeWarning(string text, LogCategories category)
		{
			LogTimeInternal(LogTier.Warning, text, category, showInGameNotification: false, null);
		}

		public void LogTimeWarningShowInGame(string text, LogCategories category)
		{
			LogTimeInternal(LogTier.Warning, text, category, showInGameNotification: true, null);
		}

		public void LogTimeException(Exception e, LogCategories category)
		{
			LogTimeExceptionInternal(null, e, category, showInGame: false);
		}

		public void LogTimeExceptionWithMessage(string text, Exception e, LogCategories category)
		{
			LogTimeExceptionInternal(text, e, category, showInGame: false);
		}

		public void LogTimeExceptionShowInGame(Exception e, LogCategories category)
		{
			LogTimeExceptionInternal(null, e, category, showInGame: true);
		}

		public void LogTimeExceptionShowInGameWithMessage(string text, Exception e, LogCategories category)
		{
			LogTimeExceptionInternal(text, e, category, showInGame: true);
		}

		private void LogTimeExceptionInternal(string text, Exception e, LogCategories category, bool showInGame)
		{
			PreprocessMessageFunc preprocessMsgFunc = (string msg, LogTier _, LogCategories _, bool _, PreprocessType prepType) => prepType switch
			{
				PreprocessType.FileLogging => FormatException(e, msg), 
				PreprocessType.GameNotification => msg ?? e.Message, 
				_ => null, 
			};
			LogTimeInternal(LogTier.Fatal, text, category, preprocessMsgFunc, showInGame);
		}

		public void LogTimeFatal(string text, LogCategories category)
		{
			LogTimeInternal(LogTier.Fatal, text, category, showInGameNotification: false, null);
		}

		public void LogTimeFatalShowInGame(string text, LogCategories category)
		{
			LogTimeInternal(LogTier.Fatal, text, category, showInGameNotification: true, null);
		}

		public void LogTimeError(string text, LogCategories category)
		{
			LogTimeInternal(LogTier.Error, text, category, showInGameNotification: false, null);
		}

		public void LogTimeErrorShowInGame(string text, LogCategories category)
		{
			LogTimeInternal(LogTier.Error, text, category, showInGameNotification: true, null);
		}

		public void LogTimeFunc(LogTier logLevel, Func<string> textLambda, LogCategories category, bool showInGameNotification, params (Action<string> action, bool useFullLog)[] actionsArgs)
		{
			LogTimeInternalFunc(logLevel, textLambda, category, showInGameNotification, actionsArgs);
		}

		private void LogTimeInternalFunc(LogTier logLevel, Func<string> textLambda, LogCategories category, bool showInGameNotification, params (Action<string> action, bool useFullLog)[] actionsArgs)
		{
			if (logLevel != LogTier.Debug || DebugEnabled)
			{
				LogTimeInternal(logLevel, textLambda(), category, showInGameNotification, actionsArgs);
			}
		}

		public void LogTime(LogTier logLevel, string text, LogCategories category)
		{
			LogTimeInternal(logLevel, text, category, showInGameNotification: false, null);
		}

		public void LogTime(LogTier logLevel, string text, LogCategories category, bool showInGameNotification)
		{
			LogTimeInternal(logLevel, text, category, showInGameNotification, null);
		}

		public void LogTime(LogTier logLevel, string text, LogCategories category, PreprocessMessageFunc preprocessMsgFunc, bool showInGameNotification, params (Action<string> action, bool useFullLog)[] actionsArgs)
		{
			LogTimeInternal(logLevel, text, category, preprocessMsgFunc, showInGameNotification, null);
		}

		private void LogTimeInternal(LogTier logLevel, string originalText, LogCategories category, bool showInGameNotification, params (Action<string> action, bool useFullLog)[] actionsArgs)
		{
			LogTimeInternal(logLevel, originalText, category, globalPreprocessMessageFunc, showInGameNotification, actionsArgs);
		}

		private void LogTimeInternal(LogTier logLevel, string originalText, LogCategories category, PreprocessMessageFunc preprocessMsgFunc, bool showInGameNotification, params (Action<string> action, bool useFullLog)[] actionsArgs)
		{
			if ((logLevel == LogTier.Debug && !DebugEnabled) || (AllowedCategories != 0 && !AllowedCategories.HasFlag(category)))
			{
				return;
			}
			string text = PreprocessMessage(originalText, logLevel, category, showInGameNotification, preprocessMsgFunc, PreprocessType.FileLogging);
			string text2 = FormatLogMessageWithTime(text, category);
			LogMessage(text2, logLevel);
			if (showInGameNotification)
			{
				string message = PreprocessMessage(originalText, logLevel, category, showInGameNotification: true, preprocessMsgFunc, PreprocessType.GameNotification);
				SendMessageNotification(logLevel, message);
			}
			if (actionsArgs != null)
			{
				for (int i = 0; i < actionsArgs.Length; i++)
				{
					(Action<string>, bool) tuple = actionsArgs[i];
					tuple.Item1(tuple.Item2 ? text2 : text);
				}
			}
		}

		private string PreprocessMessage(string text, LogTier logLevel, LogCategories category, bool showInGameNotification, PreprocessMessageFunc preprocessMsgFunc, PreprocessType prepType)
		{
			if (preprocessMsgFunc != null)
			{
				return preprocessMsgFunc(text, logLevel, category, showInGameNotification, prepType) ?? text;
			}
			return text;
		}

		public string GetCategoryStringFromCache(LogCategories category)
		{
			if (!logCategoryStringCache.TryGetValue(category, out var value))
			{
				value = category.ToString();
				logCategoryStringCache.Add(category, value);
			}
			return value;
		}

		private string FormatLogMessageWithTime(string text, LogCategories category)
		{
			StringBuilder stringBuilder = new StringBuilder(100);
			string text2 = ((category == LogCategories.Null) ? "" : GetCategoryStringFromCache(category));
			stringBuilder.Append("[");
			stringBuilder.Append(text2.PadRight(maxCategoryLength, ' '));
			stringBuilder.Append("] ");
			stringBuilder.Append(DateTime.Now.ToString("HH:mm:ss.fff"));
			stringBuilder.Append(" - ");
			stringBuilder.Append(text);
			return stringBuilder.ToString();
		}

		public static string FormatException(Exception e, string text = null)
		{
			string text2 = ((text != null) ? (text + "\n" + e.Message) : e.Message);
			text2 += $"(In {e.TargetSite})\n{e.StackTrace}";
			if (e.InnerException != null)
			{
				text2 = text2 + "\n * InnerException: " + e.InnerException.Message + " " + $"(In {e.InnerException.TargetSite})\n{e.InnerException.StackTrace}";
			}
			return text2;
		}

		public void SendMessageNotificationError(string message)
		{
			SendMessageNotification(LogTier.Error, message);
		}

		public void SendMessageNotification(LogTier logLevel, string message)
		{
			if ((logLevel != LogTier.Debug || DebugEnabled) && notificationAction != null)
			{
				notificationAction(message, logLevel);
			}
		}
	}
}
namespace Damntry.Utils.ExtensionMethods
{
	public static class EnumExtension
	{
		private static class EnumLambdaCompiled<TEnum>
		{
			public static Func<TEnum, long> EnumToLongFunc = GenerateEnumToLongFunc();

			public static Func<long, TEnum> LongToEnumFunc = GenerateLongToEnumFunc();

			private static Func<TEnum, long> GenerateEnumToLongFunc()
			{
				ParameterExpression parameterExpression = Expression.Parameter(typeof(TEnum));
				return Expression.Lambda<Func<TEnum, long>>(Expression.Convert(parameterExpression, typeof(long)), new ParameterExpression[1] { parameterExpression }).Compile();
			}

			private static Func<long, TEnum> GenerateLongToEnumFunc()
			{
				ParameterExpression parameterExpression = Expression.Parameter(typeof(long));
				return Expression.Lambda<Func<long, TEnum>>(Expression.Convert(parameterExpression, typeof(TEnum)), new ParameterExpression[1] { parameterExpression }).Compile();
			}
		}

		public static string GetDescription(this Enum enumValue)
		{
			FieldInfo field = enumValue.GetType().GetField(enumValue.ToString());
			if (field == null)
			{
				return enumValue.ToString();
			}
			field.GetCustomAttributes(typeof(DescriptionAttribute), inherit: false);
			if (Attribute.GetCustomAttribute(field, typeof(DescriptionAttribute)) is DescriptionAttribute descriptionAttribute)
			{
				return descriptionAttribute.Description;
			}
			return enumValue.ToString();
		}

		public static long ToLong<TEnum>(this TEnum enumValue) where TEnum : struct, Enum
		{
			return EnumLambdaCompiled<TEnum>.EnumToLongFunc(enumValue);
		}

		public static long EnumToLong<T>(T enumValue)
		{
			if (typeof(T).IsEnum)
			{
				return EnumLambdaCompiled<T>.EnumToLongFunc(enumValue);
			}
			throw new Exception("The type is not an enum.");
		}

		public static TEnum LongToEnum<TEnum>(long value) where TEnum : Enum
		{
			return EnumLambdaCompiled<TEnum>.LongToEnumFunc(value);
		}

		public static T LongToEnumUnconstrained<T>(long value)
		{
			if (typeof(T).IsEnum)
			{
				return EnumLambdaCompiled<T>.LongToEnumFunc(value);
			}
			throw new Exception("The type is not an enum.");
		}
	}
	public static class NumberExtensionMethods
	{
		public const double EpsilonTolerance = 1E-09;

		private static readonly HashSet<Type> NumericTypes = new HashSet<Type>
		{
			typeof(int),
			typeof(double),
			typeof(decimal),
			typeof(long),
			typeof(short),
			typeof(sbyte),
			typeof(byte),
			typeof(ulong),
			typeof(ushort),
			typeof(uint),
			typeof(float)
		};

		public static bool IsNumeric(this Type myType)
		{
			return NumericTypes.Contains(Nullable.GetUnderlyingType(myType) ?? myType);
		}

		public static bool IsInteger(this float num)
		{
			return (double)Math.Abs(num - (float)(int)num) < 1E-09;
		}

		public static bool IsInteger(this double num)
		{
			return Math.Abs(num - (double)(long)num) < 1E-09;
		}

		public static bool IsInteger(this float num, float epsilonTolerance)
		{
			return Math.Abs(num - (float)(int)num) < epsilonTolerance;
		}

		public static bool IsInteger(this double num, float epsilonTolerance)
		{
			return Math.Abs(num - (double)(long)num) < (double)epsilonTolerance;
		}

		public static bool Clamp(this ref float value, float min, float max)
		{
			return ClampIComparable(ref value, min, max);
		}

		public static bool Clamp(this ref double value, double min, double max)
		{
			return ClampIComparable(ref value, min, max);
		}

		public static bool Clamp(this ref int value, int min, int max)
		{
			return ClampIComparable(ref value, min, max);
		}

		public static bool Clamp(this ref byte value, byte min, byte max)
		{
			return ClampIComparable(ref value, min, max);
		}

		public static float ClampReturn(this float value, float min, float max)
		{
			return ClampIComparable(value, min, max);
		}

		public static double ClampReturn(this double value, double min, double max)
		{
			return ClampIComparable(value, min, max);
		}

		public static int ClampReturn(this int value, int min, int max)
		{
			return ClampIComparable(value, min, max);
		}

		public static byte ClampReturn(this byte value, byte min, byte max)
		{
			return ClampIComparable(value, min, max);
		}

		private static T ClampIComparable<T>(T value, T min, T max) where T : IComparable<T>
		{
			if (min.CompareTo(min) > 0)
			{
				throw new ArgumentException("Clamp: The max value is lower than the min value.");
			}
			if (value.CompareTo(min) < 0)
			{
				return min;
			}
			if (value.CompareTo(max) > 0)
			{
				return max;
			}
			return value;
		}

		private static bool ClampIComparable<T>(ref T value, T min, T max) where T : IComparable<T>
		{
			if (min.CompareTo(min) > 0)
			{
				throw new ArgumentException("Clamp: The max value is lower than the min value.");
			}
			if (value.CompareTo(min) < 0)
			{
				value = min;
				return false;
			}
			if (value.CompareTo(max) > 0)
			{
				value = max;
				return false;
			}
			return true;
		}
	}
	public static class ReflectionExtension
	{
		public static bool IsSubclassOfRawGeneric(this Type toCheck, Type baseType)
		{
			while (toCheck != typeof(object))
			{
				Type type = (toCheck.IsGenericType ? toCheck.GetGenericTypeDefinition() : toCheck);
				if (baseType == type)
				{
					return true;
				}
				toCheck = toCheck.BaseType;
			}
			return false;
		}

		public static bool HasCustomAttribute<T>(this MemberInfo memberInfo) where T : Attribute
		{
			return (T)Attribute.GetCustomAttribute(memberInfo, typeof(T)) != null;
		}

		public static bool IsStatic(this PropertyInfo source, bool nonPublic = true)
		{
			return source.GetAccessors(nonPublic).Any((MethodInfo x) => x.IsStatic);
		}
	}
	public static class TaskExtensionMethods
	{
		public static bool IsTaskEnded(this Task task)
		{
			if (!task.IsCompleted)
			{
				return task.IsFaulted;
			}
			return true;
		}

		public static async void FireAndForgetCancels(this Task task, LogCategories category, bool dismissCancelLog = false)
		{
			try
			{
				if (!task.IsCompleted || task.IsFaulted)
				{
					await task.ConfigureAwait(continueOnCapturedContext: false);
				}
			}
			catch (Exception ex)
			{
				if (ex is TaskCanceledException || ex is OperationCanceledException || ex is ThreadAbortException)
				{
					if (!dismissCancelLog)
					{
						TimeLogger.Logger.LogTimeDebug("\"Fire and Forget\" task successfully canceled.", category);
					}
				}
				else
				{
					TimeLogger.Logger.LogTimeExceptionWithMessage("Error while awaiting \"Fire and Forget\" type of task:", ex, category);
				}
			}
		}

		public static async void FireAndForget(this Task task, LogCategories category)
		{
			try
			{
				if (!task.IsCompleted || task.IsFaulted)
				{
					await task.ConfigureAwait(continueOnCapturedContext: false);
				}
			}
			catch (Exception e)
			{
				TimeLogger.Logger.LogTimeExceptionWithMessage("Error while awaiting \"Fire and Forget\" type of task:", e, category);
			}
		}
	}
}
namespace Damntry.Utils.Events
{
	public static class EventMethods
	{
		public static bool TryTriggerEvents(Action ev)
		{
			bool result = true;
			if (ev != null)
			{
				Delegate[] invocationList = ev.GetInvocationList();
				for (int i = 0; i < invocationList.Length; i++)
				{
					Action action = (Action)invocationList[i];
					try
					{
						action();
					}
					catch (Exception e)
					{
						result = false;
						TimeLogger.Logger.LogTimeExceptionWithMessage("Exception while invoking method \"" + action.Method.Name + "\" " + $"from event {ev.GetType()}", e, LogCategories.Events);
					}
				}
			}
			return result;
		}

		public static bool TryTriggerEvents<T>(Action<T> ev, T arg1)
		{
			bool result = true;
			if (ev != null)
			{
				Delegate[] invocationList = ev.GetInvocationList();
				for (int i = 0; i < invocationList.Length; i++)
				{
					Action<T> action = (Action<T>)invocationList[i];
					try
					{
						action(arg1);
					}
					catch (Exception e)
					{
						result = false;
						TimeLogger.Logger.LogTimeExceptionWithMessage("Exception while invoking method \"" + action.Method.Name + "\" " + $"from event {ev.GetType()}", e, LogCategories.Events);
					}
				}
			}
			return result;
		}

		public static bool TryTriggerEvents<T1, T2>(Action<T1, T2> ev, T1 arg1, T2 arg2)
		{
			bool result = true;
			if (ev != null)
			{
				Delegate[] invocationList = ev.GetInvocationList();
				for (int i = 0; i < invocationList.Length; i++)
				{
					Action<T1, T2> action = (Action<T1, T2>)invocationList[i];
					try
					{
						action(arg1, arg2);
					}
					catch (Exception e)
					{
						result = false;
						TimeLogger.Logger.LogTimeExceptionWithMessage("Exception while invoking method \"" + action.Method.Name + "\" " + $"from event {ev.GetType()}", e, LogCategories.Events);
					}
				}
			}
			return result;
		}

		public static bool TryTriggerEvents<T1, T2, T3>(Action<T1, T2> ev, T1 arg1, T2 arg2, T3 arg3)
		{
			bool result = true;
			if (ev != null)
			{
				Delegate[] invocationList = ev.GetInvocationList();
				for (int i = 0; i < invocationList.Length; i++)
				{
					Action<T1, T2, T3> action = (Action<T1, T2, T3>)invocationList[i];
					try
					{
						action(arg1, arg2, arg3);
					}
					catch (Exception e)
					{
						result = false;
						TimeLogger.Logger.LogTimeExceptionWithMessage("Exception while invoking method \"" + action.Method.Name + "\" " + $"from event {ev.GetType()}", e, LogCategories.Events);
					}
				}
			}
			return result;
		}

		public static bool TryTriggerEvents<T1, T2, T3, T4>(Action<T1, T2> ev, T1 arg1, T2 arg2, T3 arg3, T4 arg4)
		{
			bool result = true;
			if (ev != null)
			{
				Delegate[] invocationList = ev.GetInvocationList();
				for (int i = 0; i < invocationList.Length; i++)
				{
					Action<T1, T2, T3, T4> action = (Action<T1, T2, T3, T4>)invocationList[i];
					try
					{
						action(arg1, arg2, arg3, arg4);
					}
					catch (Exception e)
					{
						result = false;
						TimeLogger.Logger.LogTimeExceptionWithMessage("Exception while invoking method \"" + action.Method.Name + "\" " + $"from event {ev.GetType()}", e, LogCategories.Events);
					}
				}
			}
			return result;
		}

		public static bool TryTriggerEvents<T1, T2, T3, T4, T5>(Action<T1, T2> ev, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5)
		{
			bool result = true;
			if (ev != null)
			{
				Delegate[] invocationList = ev.GetInvocationList();
				for (int i = 0; i < invocationList.Length; i++)
				{
					Action<T1, T2, T3, T4, T5> action = (Action<T1, T2, T3, T4, T5>)invocationList[i];
					try
					{
						action(arg1, arg2, arg3, arg4, arg5);
					}
					catch (Exception e)
					{
						result = false;
						TimeLogger.Logger.LogTimeExceptionWithMessage("Exception while invoking method \"" + action.Method.Name + "\" " + $"from event {ev.GetType()}", e, LogCategories.Events);
					}
				}
			}
			return result;
		}

		public static bool TryTriggerEvents<T1, T2, T3, T4, T5, T6>(Action<T1, T2> ev, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6)
		{
			bool result = true;
			if (ev != null)
			{
				Delegate[] invocationList = ev.GetInvocationList();
				for (int i = 0; i < invocationList.Length; i++)
				{
					Action<T1, T2, T3, T4, T5, T6> action = (Action<T1, T2, T3, T4, T5, T6>)invocationList[i];
					try
					{
						action(arg1, arg2, arg3, arg4, arg5, arg6);
					}
					catch (Exception e)
					{
						result = false;
						TimeLogger.Logger.LogTimeExceptionWithMessage("Exception while invoking method \"" + action.Method.Name + "\" " + $"from event {ev.GetType()}", e, LogCategories.Events);
					}
				}
			}
			return result;
		}

		[Obsolete("Barely faster than TryTriggerEventsDelegate. Use TryTriggerEvents instead.")]
		private static bool TryTriggerEventsLambda<T>(Action<T> ev, T arg1)
		{
			return TryTriggerEventsLambda(ev, delegate(Delegate del)
			{
				((Action<T>)del)(arg1);
			});
		}

		private static bool TryTriggerEventsLambda(Delegate ev, Action<Delegate> action)
		{
			bool result = true;
			if ((object)ev != null)
			{
				Delegate[] invocationList = ev.GetInvocationList();
				foreach (Delegate @delegate in invocationList)
				{
					try
					{
						action(@delegate);
					}
					catch (Exception e)
					{
						result = false;
						TimeLogger.Logger.LogTimeExceptionWithMessage("Exception while invoking method \"" + @delegate.Method.Name + "\" " + $"from event {ev.GetType()}", e, LogCategories.Events);
					}
				}
			}
			return result;
		}

		[Obsolete("Too slow.")]
		private static bool TryTriggerEventsDelegate(Delegate ev, params object[] args)
		{
			bool result = true;
			if ((object)ev != null)
			{
				Delegate[] invocationList = ev.GetInvocationList();
				foreach (Delegate @delegate in invocationList)
				{
					try
					{
						@delegate?.Method.Invoke(@delegate.Target, args);
					}
					catch (Exception e)
					{
						result = false;
						TimeLogger.Logger.LogTimeExceptionWithMessage("Exception while invoking method \"" + @delegate.Method.Name + "\" " + $"from event {ev.GetType()}", e, LogCategories.Events);
					}
				}
			}
			return result;
		}
	}
}
namespace Damntry.Utils.Collections
{
	public class TreeNode<T>
	{
		private readonly T _value;

		private readonly List<TreeNode<T>> _children = new List<TreeNode<T>>();

		public TreeNode<T> this[int i] => _children[i];

		public TreeNode<T> Parent { get; private set; }

		public T Value => _value;

		public ReadOnlyCollection<TreeNode<T>> Children => _children.AsReadOnly();

		public TreeNode(T value)
		{
			_value = value;
		}

		private TreeNode(T value, TreeNode<T> parent)
		{
			_value = value;
			Parent = parent;
		}

		public TreeNode<T> AddChild(T value)
		{
			TreeNode<T> treeNode = new TreeNode<T>(value, this);
			_children.Add(treeNode);
			return treeNode;
		}

		public TreeNode<T>[] AddChildren(params T[] values)
		{
			return values.Select(AddChild).ToArray();
		}

		public bool RemoveChild(TreeNode<T> node)
		{
			return _children.Remove(node);
		}

		public void TransverseAndDo(Action<T> action)
		{
			action(Value);
			foreach (TreeNode<T> child in _children)
			{
				child.TransverseAndDo(action);
			}
		}

		public IEnumerable<T> Flatten()
		{
			return new T[1] { Value }.Concat(_children.SelectMany((TreeNode<T> x) => x.Flatten()));
		}
	}
}
namespace Damntry.Utils.Collections.Queues
{
	public class CommonConcurrentQueue<T> : ConcurrentQueue<T>, ICommonQueue<T>
	{
		public bool TryEnqueue(T item)
		{
			Enqueue(item);
			return true;
		}

		public new bool TryDequeue(out T item)
		{
			return base.TryDequeue(out item);
		}
	}
	public class CommonQueue<T> : Queue<T>, ICommonQueue<T>
	{
		public bool TryEnqueue(T item)
		{
			Enqueue(item);
			return true;
		}

		public new bool TryDequeue(out T item)
		{
			item = Dequeue();
			return true;
		}
	}
	public class ConcurrentFixedCapacityQueue<T> : ConcurrentQueue<T>, ICommonQueue<T>
	{
		private readonly int maxCapacity;

		private readonly bool keepOld;

		private readonly object queueLock;

		public ConcurrentFixedCapacityQueue(int maxCapacity, bool keepOld)
		{
			if (maxCapacity <= 0)
			{
				throw new ArgumentOutOfRangeException("Only values over zero are allowed.");
			}
			this.maxCapacity = maxCapacity;
			this.keepOld = keepOld;
			queueLock = new object();
		}

		[Obsolete("Use \"Enqueue(T item, out T dequeuedItem)\" instead.")]
		public new T Enqueue(T item)
		{
			throw new NotImplementedException("Use \"Enqueue(T item, out T dequeuedItem)\" instead.");
		}

		public bool TryEnqueue(T item)
		{
			T dequeuedItem;
			return TryEnqueue(item, out dequeuedItem);
		}

		public bool TryEnqueue(T item, out T dequeuedItem)
		{
			dequeuedItem = default(T);
			lock (queueLock)
			{
				if (base.Count > maxCapacity)
				{
					throw new InvalidOperationException("This LimitedQueue contains more items than allowed. Avoid casting this FixedCapacityQueue instance into a Queue to call the base Enqueue(T) method.");
				}
				if (!keepOld && base.Count == maxCapacity)
				{
					base.TryDequeue(out dequeuedItem);
				}
				if (base.Count >= maxCapacity)
				{
					return false;
				}
				base.Enqueue(item);
			}
			return true;
		}

		public new bool TryDequeue(out T item)
		{
			lock (queueLock)
			{
				return base.TryDequeue(out item);
			}
		}
	}
	public class FixedCapacityQueue<T> : Queue<T>, ICommonQueue<T>
	{
		private readonly int maxCapacity;

		private readonly bool keepOld;

		public FixedCapacityQueue(int maxCapacity, bool keepOld)
			: base(maxCapacity)
		{
			if (maxCapacity <= 0)
			{
				throw new ArgumentOutOfRangeException("Only values over zero are allowed.");
			}
			this.maxCapacity = maxCapacity;
			this.keepOld = keepOld;
		}

		[Obsolete("Use \"Enqueue(T item, out T dequeuedItem)\" instead.")]
		public new T Enqueue(T item)
		{
			throw new NotImplementedException("Use \"Enqueue(T item, out T dequeuedItem)\" instead.");
		}

		public bool TryEnqueue(T item)
		{
			T dequeuedItem;
			return TryEnqueue(item, out dequeuedItem);
		}

		public bool TryEnqueue(T item, out T dequeuedItem)
		{
			dequeuedItem = default(T);
			if (base.Count > maxCapacity)
			{
				throw new InvalidOperationException("This LimitedQueue contains more items than allowed. Avoid casting this FixedCapacityQueue instance into a Queue to call the base Enqueue(T) method.");
			}
			if (!keepOld && base.Count == maxCapacity)
			{
				dequeuedItem = Dequeue();
			}
			if (base.Count >= maxCapacity)
			{
				return false;
			}
			base.Enqueue(item);
			return true;
		}

		public new bool TryDequeue(out T item)
		{
			item = Dequeue();
			return true;
		}
	}
	public class FixedCapacityUniqueQueue<T> : FixedCapacityQueue<T>
	{
		public FixedCapacityUniqueQueue(int maxCapacity, bool keepOld)
			: base(maxCapacity, keepOld)
		{
		}

		[Obsolete("Use \"Enqueue(T item, out T dequeuedItem)\" instead.")]
		public new T Enqueue(T item)
		{
			throw new NotImplementedException("Use \"Enqueue(T item, out T dequeuedItem)\" instead.");
		}

		public new bool TryEnqueue(T item, out T dequeuedItem)
		{
			dequeuedItem = default(T);
			if (base.Count > 0 && Contains(item))
			{
				return false;
			}
			return base.TryEnqueue(item, out dequeuedItem);
		}
	}
}
namespace Damntry.Utils.Collections.Queues.Interfaces
{
	public interface ICommonQueue<T>
	{
		int Count { get; }

		bool TryEnqueue(T item);

		bool TryDequeue(out T item);
	}
}

BepInEx/plugins/es.damntry.SuperQoLity/Damntry.Globals.Unity.dll

Decompiled a week ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Threading;
using System.Threading.Tasks;
using Cysharp.Threading.Tasks;
using Damntry.Utils.ExtensionMethods;
using Damntry.Utils.Logging;
using Damntry.Utils.Reflection;
using Damntry.Utils.Tasks.AsyncDelay;
using Damntry.Utils.Timers.StopwatchImpl;
using Damntry.UtilsUnity.UI.Extensions;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("Damntry Globals unity")]
[assembly: AssemblyDescription("Utils for projects using Unity")]
[assembly: AssemblyCompany("Damntry")]
[assembly: AssemblyProduct("Damntry Globals unity")]
[assembly: AssemblyCopyright("Copyright © Damntry 2025")]
[assembly: AssemblyFileVersion("0.1.3")]
[assembly: TargetFramework(".NETFramework,Version=v4.8.1", FrameworkDisplayName = ".NET Framework 4.8.1")]
[assembly: AssemblyVersion("0.1.3.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;
		}
	}
}
public class GpuInstancingFrustumCulling : MonoBehaviour
{
	[SerializeField]
	private Camera _camera;

	[SerializeField]
	private MeshRenderer[] _meshRenderers = (MeshRenderer[])(object)new MeshRenderer[0];

	public bool meshesAreStill = true;

	private Dictionary<(Mesh mesh, Material material), (List<Transform> transforms, Bounds aabb)> _sources = new Dictionary<(Mesh, Material), (List<Transform>, Bounds)>();

	private Dictionary<(Mesh mesh, Material material), (Matrix4x4[] matrices, Bounds aabb)> _batches = new Dictionary<(Mesh, Material), (Matrix4x4[], Bounds)>();

	private Dictionary<int, Stack<Matrix4x4[]>> _freeMatrices = new Dictionary<int, Stack<Matrix4x4[]>>();

	private Plane[] _frustum = (Plane[])(object)new Plane[6];

	private void Start()
	{
		Initialize();
		UpdateMatrices();
		if ((Object)(object)_camera == (Object)null)
		{
			_camera = Camera.main;
		}
		if ((Object)(object)_camera == (Object)null)
		{
			Debug.LogError((object)"no camera, can't continue", (Object)(object)this);
			((Behaviour)this).enabled = false;
		}
	}

	private void Update()
	{
		//IL_0046: 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_0053: Unknown result type (might be due to invalid IL or missing references)
		if (!meshesAreStill)
		{
			UpdateMatrices();
		}
		GeometryUtility.CalculateFrustumPlanes(_camera, _frustum);
		foreach (KeyValuePair<(Mesh, Material), (Matrix4x4[], Bounds)> batch in _batches)
		{
			(Mesh, Material) key = batch.Key;
			(Matrix4x4[], Bounds) value = batch.Value;
			Bounds item = value.Item2;
			if (GeometryUtility.TestPlanesAABB(_frustum, item))
			{
				Graphics.DrawMeshInstanced(key.Item1, 0, key.Item2, value.Item1);
			}
		}
	}

	private void Initialize()
	{
		//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_0137: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
		//IL_0110: Unknown result type (might be due to invalid IL or missing references)
		_sources.Clear();
		MeshRenderer[] meshRenderers = _meshRenderers;
		foreach (MeshRenderer val in meshRenderers)
		{
			if ((Object)(object)val == (Object)null)
			{
				continue;
			}
			MeshFilter component = ((Component)val).GetComponent<MeshFilter>();
			if ((Object)(object)component == (Object)null)
			{
				continue;
			}
			Mesh sharedMesh = component.sharedMesh;
			if ((Object)(object)sharedMesh == (Object)null)
			{
				continue;
			}
			Material[] sharedMaterials = ((Renderer)val).sharedMaterials;
			foreach (Material val2 in sharedMaterials)
			{
				if (!val2.enableInstancing && Application.isPlaying)
				{
					Debug.LogWarning((object)("\"" + ((Object)val2).name + "\" material won't be rendered as it's <b>GPU Instancing</b> is not enabled"), (Object)(object)val);
				}
				else if (!((Object)(object)val2 == (Object)null))
				{
					Bounds bounds = ((Renderer)val).bounds;
					(Mesh, Material) key = (sharedMesh, val2);
					if (_sources.ContainsKey(key))
					{
						List<Transform> item = _sources[key].transforms;
						item.Add(((Component)val).transform);
						Bounds item2 = _sources[key].aabb;
						((Bounds)(ref item2)).Encapsulate(bounds);
						_sources[key] = (item, item2);
					}
					else
					{
						_sources.Add(key, (new List<Transform> { ((Component)val).transform }, bounds));
					}
				}
			}
			if (Application.isPlaying)
			{
				((Renderer)val).enabled = false;
			}
		}
	}

	private void UpdateMatrices()
	{
		//IL_011f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0124: Unknown result type (might be due to invalid IL or missing references)
		//IL_0141: Unknown result type (might be due to invalid IL or missing references)
		foreach (KeyValuePair<(Mesh, Material), (Matrix4x4[], Bounds)> batch in _batches)
		{
			Matrix4x4[] item = batch.Value.Item1;
			if (_freeMatrices.ContainsKey(item.Length))
			{
				_freeMatrices[item.Length].Push(item);
				continue;
			}
			Stack<Matrix4x4[]> stack = new Stack<Matrix4x4[]>();
			stack.Push(item);
			_freeMatrices.Add(item.Length, stack);
		}
		_batches.Clear();
		foreach (KeyValuePair<(Mesh, Material), (List<Transform>, Bounds)> source in _sources)
		{
			(Mesh, Material) key = source.Key;
			(List<Transform>, Bounds) value = source.Value;
			List<Transform> item2 = value.Item1;
			int count = item2.Count;
			Matrix4x4[] array = null;
			array = (Matrix4x4[])((!_freeMatrices.ContainsKey(count) || _freeMatrices[count].Count == 0) ? ((Array)new Matrix4x4[count]) : ((Array)_freeMatrices[count].Pop()));
			for (int i = 0; i < count; i++)
			{
				array[i] = item2[i].localToWorldMatrix;
			}
			_batches.Add(key, (array, value.Item2));
		}
	}
}
namespace Damntry.UtilsUnity.UI
{
	public static class CanvasMethods
	{
		public static void AttachPanelToCanvas(GameObject mainPanel, Transform canvasTransformParent)
		{
			CheckAttachArgs(mainPanel, canvasTransformParent);
			mainPanel.transform.SetParent(canvasTransformParent);
		}

		public static void AttachPanelToCanvasWithAnchor(GameObject mainPanel, Transform canvasTransformParent)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			CheckAttachArgs(mainPanel, canvasTransformParent);
			mainPanel.transform.SetParent(canvasTransformParent);
			RectTransform component = mainPanel.GetComponent<RectTransform>();
			component.SetAnchor(AnchorPresets.TopCenter);
			component.sizeDelta = Vector2.zero;
			component.offsetMin = Vector2.zero;
			component.offsetMax = Vector2.zero;
			component.anchoredPosition = Vector2.zero;
		}

		private static void CheckAttachArgs(GameObject mainPanel, Transform canvasTransformParent)
		{
			if ((Object)(object)mainPanel == (Object)null)
			{
				throw new ArgumentNullException("mainPanel");
			}
			if ((Object)(object)canvasTransformParent == (Object)null)
			{
				throw new ArgumentNullException("canvasTransformParent");
			}
		}
	}
}
namespace Damntry.UtilsUnity.UI.Extensions
{
	public enum AnchorPresets
	{
		TopLeft,
		TopCenter,
		TopRight,
		MiddleLeft,
		MiddleCenter,
		MiddleRight,
		BottomLeft,
		BottonCenter,
		BottomRight,
		BottomStretch,
		VertStretchLeft,
		VertStretchRight,
		VertStretchCenter,
		HorStretchTop,
		HorStretchMiddle,
		HorStretchBottom,
		StretchAll
	}
	public enum PivotPresets
	{
		TopLeft,
		TopCenter,
		TopRight,
		MiddleLeft,
		MiddleCenter,
		MiddleRight,
		BottomLeft,
		BottomCenter,
		BottomRight
	}
	public static class RectTransformExtensions
	{
		public static void SetAnchor(this RectTransform source, AnchorPresets alignment, int offsetX = 0, int offsetY = 0)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: 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_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_0146: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			//IL_0186: Unknown result type (might be due to invalid IL or missing references)
			//IL_019c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0273: Unknown result type (might be due to invalid IL or missing references)
			//IL_0288: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02de: Unknown result type (might be due to invalid IL or missing references)
			//IL_029e: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0207: Unknown result type (might be due to invalid IL or missing references)
			//IL_021d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0232: Unknown result type (might be due to invalid IL or missing references)
			//IL_0248: Unknown result type (might be due to invalid IL or missing references)
			//IL_025d: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0309: Unknown result type (might be due to invalid IL or missing references)
			source.anchoredPosition = Vector2.op_Implicit(new Vector3((float)offsetX, (float)offsetY, 0f));
			switch (alignment)
			{
			case AnchorPresets.TopLeft:
				source.anchorMin = new Vector2(0f, 1f);
				source.anchorMax = new Vector2(0f, 1f);
				break;
			case AnchorPresets.TopCenter:
				source.anchorMin = new Vector2(0.5f, 1f);
				source.anchorMax = new Vector2(0.5f, 1f);
				break;
			case AnchorPresets.TopRight:
				source.anchorMin = new Vector2(1f, 1f);
				source.anchorMax = new Vector2(1f, 1f);
				break;
			case AnchorPresets.MiddleLeft:
				source.anchorMin = new Vector2(0f, 0.5f);
				source.anchorMax = new Vector2(0f, 0.5f);
				break;
			case AnchorPresets.MiddleCenter:
				source.anchorMin = new Vector2(0.5f, 0.5f);
				source.anchorMax = new Vector2(0.5f, 0.5f);
				break;
			case AnchorPresets.MiddleRight:
				source.anchorMin = new Vector2(1f, 0.5f);
				source.anchorMax = new Vector2(1f, 0.5f);
				break;
			case AnchorPresets.BottomLeft:
				source.anchorMin = new Vector2(0f, 0f);
				source.anchorMax = new Vector2(0f, 0f);
				break;
			case AnchorPresets.BottonCenter:
				source.anchorMin = new Vector2(0.5f, 0f);
				source.anchorMax = new Vector2(0.5f, 0f);
				break;
			case AnchorPresets.BottomRight:
				source.anchorMin = new Vector2(1f, 0f);
				source.anchorMax = new Vector2(1f, 0f);
				break;
			case AnchorPresets.HorStretchTop:
				source.anchorMin = new Vector2(0f, 1f);
				source.anchorMax = new Vector2(1f, 1f);
				break;
			case AnchorPresets.HorStretchMiddle:
				source.anchorMin = new Vector2(0f, 0.5f);
				source.anchorMax = new Vector2(1f, 0.5f);
				break;
			case AnchorPresets.HorStretchBottom:
				source.anchorMin = new Vector2(0f, 0f);
				source.anchorMax = new Vector2(1f, 0f);
				break;
			case AnchorPresets.VertStretchLeft:
				source.anchorMin = new Vector2(0f, 0f);
				source.anchorMax = new Vector2(0f, 1f);
				break;
			case AnchorPresets.VertStretchCenter:
				source.anchorMin = new Vector2(0.5f, 0f);
				source.anchorMax = new Vector2(0.5f, 1f);
				break;
			case AnchorPresets.VertStretchRight:
				source.anchorMin = new Vector2(1f, 0f);
				source.anchorMax = new Vector2(1f, 1f);
				break;
			case AnchorPresets.StretchAll:
				source.anchorMin = new Vector2(0f, 0f);
				source.anchorMax = new Vector2(1f, 1f);
				break;
			case AnchorPresets.BottomStretch:
				break;
			}
		}

		public static void SetPivot(this RectTransform source, PivotPresets pivotPreset)
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: 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_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			switch (pivotPreset)
			{
			case PivotPresets.TopLeft:
				source.pivot = new Vector2(0f, 1f);
				break;
			case PivotPresets.TopCenter:
				source.pivot = new Vector2(0.5f, 1f);
				break;
			case PivotPresets.TopRight:
				source.pivot = new Vector2(1f, 1f);
				break;
			case PivotPresets.MiddleLeft:
				source.pivot = new Vector2(0f, 0.5f);
				break;
			case PivotPresets.MiddleCenter:
				source.pivot = new Vector2(0.5f, 0.5f);
				break;
			case PivotPresets.MiddleRight:
				source.pivot = new Vector2(1f, 0.5f);
				break;
			case PivotPresets.BottomLeft:
				source.pivot = new Vector2(0f, 0f);
				break;
			case PivotPresets.BottomCenter:
				source.pivot = new Vector2(0.5f, 0f);
				break;
			case PivotPresets.BottomRight:
				source.pivot = new Vector2(1f, 0f);
				break;
			}
		}

		public static void SetAnchorAndPivot(this RectTransform source, AnchorPresets alignment, PivotPresets pivotPreset, int offsetX = 0, int offsetY = 0)
		{
			source.SetAnchor(alignment, offsetX, offsetY);
			source.SetPivot(pivotPreset);
		}
	}
}
namespace Damntry.UtilsUnity.Timers
{
	public class CachedTimeValues
	{
		private static UnityTimeStopwatch unitySW;

		private static float fixedDeltaTime;

		private static int fixedUpdateCycleMax;

		public static (float fixedDeltaTime, int fixedUpdateCycleMax) GetFixedTimeCachedValues()
		{
			if (unitySW == null || unitySW.ElapsedSecondsPrecise > 1.0)
			{
				if (unitySW == null)
				{
					unitySW = UnityTimeStopwatch.StartNew(UnityTimeStopwatch.TimeType.FixedTime);
				}
				fixedDeltaTime = Time.fixedDeltaTime;
				fixedUpdateCycleMax = (int)Math.Round(1f / fixedDeltaTime);
			}
			return (fixedDeltaTime, fixedUpdateCycleMax);
		}
	}
	public class UnityTimeStopwatch : IStopwatch
	{
		public enum TimeType
		{
			Time,
			FixedTime,
			UnscaledTime,
			UnscaledFixedTime
		}

		private double elapsed;

		private double startTimeStamp;

		private bool isRunning;

		private TimeType timeType;

		public bool IsRunning => isRunning;

		public long ElapsedMilliseconds => (long)GetElapsedSeconds(highPrecision: false) * 1000;

		public long ElapsedSeconds => (long)GetElapsedSeconds(highPrecision: false);

		public double ElapsedMillisecondsPrecise => GetElapsedSeconds(highPrecision: true) * 1000.0;

		public double ElapsedSecondsPrecise => GetElapsedSeconds(highPrecision: true);

		static UnityTimeStopwatch()
		{
		}

		public UnityTimeStopwatch()
		{
			timeType = TimeType.Time;
			Reset();
		}

		public UnityTimeStopwatch(TimeType timeType)
		{
			this.timeType = timeType;
			Reset();
		}

		public void Start()
		{
			if (!isRunning)
			{
				startTimeStamp = GetTimestampDouble();
				isRunning = true;
			}
		}

		public static UnityTimeStopwatch StartNew()
		{
			UnityTimeStopwatch unityTimeStopwatch = new UnityTimeStopwatch();
			unityTimeStopwatch.Start();
			return unityTimeStopwatch;
		}

		public static UnityTimeStopwatch StartNew(TimeType timeType)
		{
			UnityTimeStopwatch unityTimeStopwatch = new UnityTimeStopwatch(timeType);
			unityTimeStopwatch.Start();
			return unityTimeStopwatch;
		}

		public void Stop()
		{
			if (isRunning)
			{
				double num = GetTimestampDouble() - startTimeStamp;
				elapsed += num;
				isRunning = false;
				if (elapsed < 0.0)
				{
					elapsed = 0.0;
				}
			}
		}

		public void Reset()
		{
			elapsed = 0.0;
			isRunning = false;
			startTimeStamp = 0.0;
		}

		public void Restart()
		{
			elapsed = 0.0;
			startTimeStamp = GetTimestampDouble();
			isRunning = true;
		}

		private float GetTimestamp()
		{
			return timeType switch
			{
				TimeType.Time => Time.time, 
				TimeType.FixedTime => Time.fixedTime, 
				TimeType.UnscaledTime => Time.unscaledTime, 
				TimeType.UnscaledFixedTime => Time.fixedUnscaledTime, 
				_ => throw new NotImplementedException(), 
			};
		}

		private double GetTimestampDouble()
		{
			return timeType switch
			{
				TimeType.Time => Time.timeAsDouble, 
				TimeType.FixedTime => Time.fixedTimeAsDouble, 
				TimeType.UnscaledTime => Time.unscaledTimeAsDouble, 
				TimeType.UnscaledFixedTime => Time.fixedUnscaledTimeAsDouble, 
				_ => throw new NotImplementedException(), 
			};
		}

		private double GetElapsedSeconds(bool highPrecision)
		{
			double num = elapsed;
			if (isRunning)
			{
				num += (highPrecision ? GetTimestampDouble() : ((double)GetTimestamp())) - startTimeStamp;
			}
			return num;
		}
	}
}
namespace Damntry.UtilsUnity.Tasks.AsyncDelay
{
	public class UniTaskDelay : AsyncDelayBase<UniTaskDelay>
	{
		public override Task Delay(int millisecondsDelay)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			return UniTaskExtensions.AsTask(UniTask.Delay(AdaptToUnitask(millisecondsDelay), false, (PlayerLoopTiming)8, default(CancellationToken), false));
		}

		public override Task Delay(int millisecondsDelay, CancellationToken cancellationToken)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			return UniTaskExtensions.AsTask(UniTask.Delay(AdaptToUnitask(millisecondsDelay), false, (PlayerLoopTiming)8, cancellationToken, false));
		}

		private int AdaptToUnitask(int millisecondsDelay)
		{
			if (millisecondsDelay < 0)
			{
				return int.MaxValue;
			}
			return millisecondsDelay;
		}
	}
}
namespace Damntry.UtilsUnity.Resources
{
	public class AssetBundleElement
	{
		private static Dictionary<string, AssetBundle> bundleCacheStorage = new Dictionary<string, AssetBundle>();

		private readonly string assetBundlePath;

		private AssetBundle loadedBundle;

		public AssetBundleElement(Type assemblyType, string assetName)
		{
			if (assemblyType == null)
			{
				throw new ArgumentNullException("assemblyType");
			}
			if (string.IsNullOrEmpty(assetName))
			{
				throw new ArgumentNullException("The parameter assetName cant be null or empty.");
			}
			assetBundlePath = AssemblyUtils.GetCombinedPathFromAssemblyFolder(assemblyType, assetName);
			if (!File.Exists(assetBundlePath))
			{
				throw new FileNotFoundException(null, assetBundlePath);
			}
		}

		public AssetBundleElement(string assetFullPath)
		{
			if (string.IsNullOrEmpty(assetFullPath))
			{
				throw new ArgumentNullException("The parameter assetFullPath cant be null or empty.");
			}
			if (!File.Exists(assetFullPath))
			{
				throw new FileNotFoundException(null, assetFullPath);
			}
			assetBundlePath = assetFullPath;
		}

		public bool PreloadBundle()
		{
			if ((Object)(object)loadedBundle == (Object)null)
			{
				if (!bundleCacheStorage.TryGetValue(assetBundlePath, out loadedBundle) || (Object)(object)loadedBundle == (Object)null)
				{
					loadedBundle = AssetBundle.LoadFromFile(assetBundlePath);
					if ((Object)(object)loadedBundle == (Object)null)
					{
						throw new LoadBundleFileException(assetBundlePath);
					}
					TimeLogger.Logger.LogTimeDebug("Bundle loaded successfully from " + assetBundlePath, (LogCategories)8);
					bundleCacheStorage.Add(assetBundlePath, loadedBundle);
				}
				else
				{
					TimeLogger.Logger.LogTimeDebug("Bundle loaded successfully from storage cache.", (LogCategories)8);
				}
			}
			return true;
		}

		public string[] GetAllAssetNames()
		{
			if (!PreloadBundle())
			{
				return null;
			}
			return loadedBundle.GetAllAssetNames();
		}

		public string GetAllAssetNamesString(string separator = "\n")
		{
			string[] allAssetNames = GetAllAssetNames();
			if (allAssetNames == null)
			{
				return null;
			}
			return string.Join(separator, allAssetNames);
		}

		public async Task<T[]> LoadAllAssetsAsync<T>() where T : Object
		{
			if (!PreloadBundle())
			{
				return null;
			}
			AssetBundleRequest assetRequest = loadedBundle.LoadAllAssetsAsync(typeof(T));
			ResourceRequestAwaiter val = UnityAsyncExtensions.GetAwaiter((ResourceRequest)(object)assetRequest);
			if (!((ResourceRequestAwaiter)(ref val)).IsCompleted)
			{
				await val;
				ResourceRequestAwaiter val2 = default(ResourceRequestAwaiter);
				val = val2;
			}
			((ResourceRequestAwaiter)(ref val)).GetResult();
			return assetRequest.allAssets.Cast<T>().ToArray();
		}

		public T[] LoadAllAssets<T>() where T : Object
		{
			if (!PreloadBundle())
			{
				return null;
			}
			return loadedBundle.LoadAllAssets<T>().ToArray();
		}

		public bool TryLoadNewPrefabInstance(string prefabName, out GameObject prefabInstance)
		{
			prefabInstance = null;
			string bundleInternalUnityPath = "assets/" + prefabName + ".prefab";
			if (!this.TryLoadObject<GameObject>(bundleInternalUnityPath, out GameObject objectInstance))
			{
				return false;
			}
			prefabInstance = Object.Instantiate<GameObject>(objectInstance);
			return true;
		}

		public bool TryLoadObject<T>(string bundleInternalUnityPath, out T objectInstance) where T : Object
		{
			objectInstance = default(T);
			if (!TryLoadPrefabObject<Object>(bundleInternalUnityPath, out Object loadedObject))
			{
				return false;
			}
			if (!(loadedObject is T))
			{
				TimeLogger.Logger.LogTimeError("The object at " + bundleInternalUnityPath + " is not a " + typeof(T).Name + " type.", (LogCategories)8);
				return false;
			}
			objectInstance = (T)(object)loadedObject;
			return true;
		}

		private bool TryLoadPrefabObject<T>(string bundleInternalUnityPath, out T loadedObject) where T : Object
		{
			loadedObject = default(T);
			if (!PreloadBundle())
			{
				return false;
			}
			loadedObject = loadedBundle.LoadAsset<T>(bundleInternalUnityPath);
			if ((Object)(object)loadedObject == (Object)null)
			{
				TimeLogger.Logger.LogTimeDebug("Asset loaded with path \"" + bundleInternalUnityPath + "\" not found.", (LogCategories)8);
				return false;
			}
			return true;
		}

		public void UnloadBundle()
		{
			if ((Object)(object)loadedBundle == (Object)null)
			{
				TimeLogger.Logger.LogTimeDebug("No loaded bundle was found while trying to unload.", (LogCategories)8);
				return;
			}
			loadedBundle.Unload(true);
			loadedBundle = null;
			bundleCacheStorage.Remove(assetBundlePath);
			TimeLogger.Logger.LogTimeDebug("Asset bundle at " + assetBundlePath + " unloaded successfully.", (LogCategories)8);
		}
	}
	public class LoadBundleFileException : Exception
	{
		public LoadBundleFileException(string assetPath)
			: base("Failed to load asset bundle from path: " + assetPath + ".")
		{
		}
	}
}
namespace Damntry.UtilsUnity.ExtensionMethods
{
	public static class ComponentExtensions
	{
		public static GameObject GameObject(this Component comp)
		{
			if ((Object)(object)comp == (Object)null)
			{
				return null;
			}
			if (!Object.op_Implicit((Object)(object)comp))
			{
				return null;
			}
			return comp.gameObject;
		}
	}
}
namespace Damntry.UtilsUnity.Components
{
	public enum KeyPressAction
	{
		KeyDown,
		KeyUp,
		KeyHeld
	}
	public class KeyPressDetection : MonoBehaviour
	{
		private class KeyPressData
		{
			private readonly double cooldownSeconds;

			private double lastKeyPressTime;

			internal Action Action { get; private set; }

			internal KeyPressAction KeyAction { get; private set; }

			public KeyPressData(Action action, KeyPressAction keyAction, int cooldownMillis)
			{
				Action = action;
				cooldownSeconds = ((cooldownSeconds > 0.0) ? ((double)cooldownMillis / 1000.0) : (-1.0));
				lastKeyPressTime = double.MinValue;
				KeyAction = keyAction;
			}

			internal bool IsNotInCooldown()
			{
				if (!(cooldownSeconds <= 0.0))
				{
					return lastKeyPressTime + cooldownSeconds < Time.timeAsDouble;
				}
				return true;
			}

			internal void UpdateKeyPressTime()
			{
				lastKeyPressTime = Time.timeAsDouble;
			}
		}

		private static KeyPressDetection instance;

		private static Dictionary<KeyCode, KeyPressData> keyPressActions;

		private static Func<bool> preKeyCheckFunc;

		private static Func<MonoBehaviour> getBehaviourAttachFunc;

		private const int DefaultKeyPressCooldown = 65;

		static KeyPressDetection()
		{
			keyPressActions = new Dictionary<KeyCode, KeyPressData>();
		}

		private void Awake()
		{
			instance = this;
		}

		private void Start()
		{
			BehaviourEnabledCheck();
		}

		private void Update()
		{
			//IL_0047: 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_0065: Unknown result type (might be due to invalid IL or missing references)
			if (!Input.anyKey)
			{
				return;
			}
			foreach (KeyValuePair<KeyCode, KeyPressData> keyPressAction in keyPressActions)
			{
				KeyPressData value = keyPressAction.Value;
				if (value.KeyAction switch
				{
					KeyPressAction.KeyDown => Input.GetKeyDown(keyPressAction.Key), 
					KeyPressAction.KeyUp => Input.GetKeyUp(keyPressAction.Key), 
					KeyPressAction.KeyHeld => Input.GetKey(keyPressAction.Key), 
					_ => throw new NotImplementedException(EnumExtension.GetDescription((Enum)value.KeyAction)), 
				} && (preKeyCheckFunc == null || preKeyCheckFunc()) && value.IsNotInCooldown())
				{
					value.UpdateKeyPressTime();
					value.Action();
				}
			}
		}

		private void OnDestroy()
		{
			TaskExtensionMethods.FireAndForget(BeginGetBehaviour(getBehaviourAttachFunc), (LogCategories)33554432);
		}

		public static async Task InitializeAsync(Func<MonoBehaviour> getBehaviourAttachFunc, Func<bool> preKeyCheckFunc = null)
		{
			KeyPressDetection.getBehaviourAttachFunc = getBehaviourAttachFunc;
			await BeginGetBehaviour(getBehaviourAttachFunc);
		}

		private static async Task BeginGetBehaviour(Func<MonoBehaviour> getBehaviourAttachFunc)
		{
			MonoBehaviour val;
			while ((Object)(object)(val = getBehaviourAttachFunc()) == (Object)null || !((Component)val).gameObject.activeInHierarchy)
			{
				await Task.Delay(500);
			}
			Initialize(val, preKeyCheckFunc);
		}

		public static void Initialize(MonoBehaviour unityObject, Func<bool> preKeyCheckFunc = null)
		{
			if ((Object)(object)unityObject == (Object)null)
			{
				throw new ArgumentNullException("unityObject");
			}
			Initialize(((Component)unityObject).gameObject, preKeyCheckFunc);
		}

		public static void Initialize(GameObject unityGameObject, Func<bool> preKeyCheckFunc = null)
		{
			if ((Object)(object)unityGameObject == (Object)null)
			{
				throw new ArgumentNullException("unityGameObject");
			}
			unityGameObject.AddComponent<KeyPressDetection>();
			KeyPressDetection.preKeyCheckFunc = preKeyCheckFunc;
		}

		public static bool TryAddHotkey(KeyCode keyCode, KeyPressAction keyAction, Action action)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			return AddHotkeyInternal(keyCode, 65, keyAction, throwIfExists: false, action);
		}

		public static bool TryAddHotkey(KeyCode keyCode, KeyPressAction keyAction, int cooldownMillis, Action action)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			return AddHotkeyInternal(keyCode, cooldownMillis, keyAction, throwIfExists: false, action);
		}

		public static void AddHotkey(KeyCode keyCode, KeyPressAction keyAction, Action action)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			AddHotkeyInternal(keyCode, 65, keyAction, throwIfExists: true, action);
		}

		public static void AddHotkey(KeyCode keyCode, KeyPressAction keyAction, int cooldownMillis, Action action)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			AddHotkeyInternal(keyCode, cooldownMillis, keyAction, throwIfExists: true, action);
		}

		private static bool AddHotkeyInternal(KeyCode keyCode, int cooldownMillis, KeyPressAction keyAction, bool throwIfExists, Action action)
		{
			//IL_0014: 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_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			if (action == null)
			{
				throw new ArgumentNullException("action");
			}
			if (!keyPressActions.TryGetValue(keyCode, out var value))
			{
				keyPressActions.Add(keyCode, new KeyPressData(action, keyAction, cooldownMillis));
			}
			else
			{
				if (keyAction == value.KeyAction || (keyAction != KeyPressAction.KeyUp && value.KeyAction != KeyPressAction.KeyUp))
				{
					string text = $"Hotkey {keyCode} is already defined.";
					if (throwIfExists)
					{
						throw new InvalidOperationException(text);
					}
					TimeLogger.Logger.LogTimeError(text, (LogCategories)33554432);
					return false;
				}
				keyPressActions.Add(keyCode, new KeyPressData(action, keyAction, cooldownMillis));
			}
			instance?.BehaviourEnabledCheck();
			return true;
		}

		public static void RemoveHotkey(KeyCode keyCode)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			if (keyPressActions.ContainsKey(keyCode))
			{
				keyPressActions.Remove(keyCode);
				instance?.BehaviourEnabledCheck();
			}
		}

		public static string GetRegisteredHotkeys()
		{
			return string.Join(", ", keyPressActions.Keys);
		}

		private void BehaviourEnabledCheck()
		{
			Dictionary<KeyCode, KeyPressData> dictionary = keyPressActions;
			((Behaviour)this).enabled = dictionary != null && dictionary.Count > 0;
		}
	}
}

BepInEx/plugins/es.damntry.SuperQoLity/SuperQoLity-Release.dll

Decompiled a week ago
using System;
using System.CodeDom.Compiler;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Configuration;
using Cysharp.Threading.Tasks;
using Damntry.Utils.Collections.Queues;
using Damntry.Utils.Collections.Queues.Interfaces;
using Damntry.Utils.Events;
using Damntry.Utils.ExtensionMethods;
using Damntry.Utils.Logging;
using Damntry.Utils.Reflection;
using Damntry.Utils.Tasks;
using Damntry.Utils.Tasks.AsyncDelay;
using Damntry.Utils.Timers;
using Damntry.Utils.Timers.StopwatchImpl;
using Damntry.UtilsBepInEx.Configuration;
using Damntry.UtilsBepInEx.Configuration.ConfigurationManager;
using Damntry.UtilsBepInEx.Configuration.ConfigurationManager.SettingAttributes;
using Damntry.UtilsBepInEx.HarmonyPatching;
using Damntry.UtilsBepInEx.HarmonyPatching.Attributes;
using Damntry.UtilsBepInEx.HarmonyPatching.AutoPatching;
using Damntry.UtilsBepInEx.HarmonyPatching.AutoPatching.Attributes;
using Damntry.UtilsBepInEx.HarmonyPatching.AutoPatching.BaseClasses;
using Damntry.UtilsBepInEx.HarmonyPatching.AutoPatching.BaseClasses.Inheritable;
using Damntry.UtilsBepInEx.HarmonyPatching.AutoPatching.Interfaces;
using Damntry.UtilsBepInEx.HarmonyPatching.Exceptions;
using Damntry.UtilsBepInEx.IL;
using Damntry.UtilsBepInEx.Logging;
using Damntry.UtilsBepInEx.MirrorNetwork.Attributes;
using Damntry.UtilsBepInEx.MirrorNetwork.Components;
using Damntry.UtilsBepInEx.MirrorNetwork.Helpers;
using Damntry.UtilsBepInEx.MirrorNetwork.SyncVar;
using Damntry.UtilsBepInEx.ModHelpers;
using Damntry.UtilsUnity.Components;
using Damntry.UtilsUnity.ExtensionMethods;
using Damntry.UtilsUnity.Resources;
using Damntry.UtilsUnity.Tasks.AsyncDelay;
using Damntry.UtilsUnity.Timers;
using Damntry.UtilsUnity.UI;
using Damntry.UtilsUnity.UI.Extensions;
using HarmonyLib;
using HighlightPlus;
using HutongGames.PlayMaker;
using HutongGames.PlayMaker.Actions;
using Microsoft.CodeAnalysis;
using Mirror;
using Rewired;
using StarterAssets;
using SuperQoLity.SuperMarket.ModUtils;
using SuperQoLity.SuperMarket.ModUtils.ExternalMods;
using SuperQoLity.SuperMarket.ModUtils.UI;
using SuperQoLity.SuperMarket.PatchClassHelpers.Components;
using SuperQoLity.SuperMarket.PatchClassHelpers.ContainerEntities;
using SuperQoLity.SuperMarket.PatchClassHelpers.ContainerEntities.Search;
using SuperQoLity.SuperMarket.PatchClassHelpers.ContainerEntities.ShelfSlotInfo;
using SuperQoLity.SuperMarket.PatchClassHelpers.NPCs;
using SuperQoLity.SuperMarket.PatchClassHelpers.NPCs.Employees.JobScheduler;
using SuperQoLity.SuperMarket.PatchClassHelpers.NPCs.Employees.JobScheduler.AutoMode;
using SuperQoLity.SuperMarket.PatchClassHelpers.NPCs.Employees.JobScheduler.AutoMode.DataDefinition;
using SuperQoLity.SuperMarket.PatchClassHelpers.NPCs.Employees.JobScheduler.Helpers;
using SuperQoLity.SuperMarket.PatchClassHelpers.NPCs.Employees.RestockMatch;
using SuperQoLity.SuperMarket.PatchClassHelpers.NPCs.Employees.RestockMatch.Component;
using SuperQoLity.SuperMarket.PatchClassHelpers.NPCs.Employees.RestockMatch.Helpers;
using SuperQoLity.SuperMarket.PatchClassHelpers.NPCs.Employees.RestockMatch.Models;
using SuperQoLity.SuperMarket.PatchClassHelpers.NPCs.Employees.TargetMarking;
using SuperQoLity.SuperMarket.PatchClassHelpers.NPCs.Movement;
using SuperQoLity.SuperMarket.PatchClassHelpers.Networking.SyncVarBehaviours;
using SuperQoLity.SuperMarket.Patches;
using SuperQoLity.SuperMarket.Patches.BetterSMT_Module;
using SuperQoLity.SuperMarket.Patches.EmployeeModule;
using SuperQoLity.SuperMarket.Patches.Misc;
using SuperQoLity.SuperMarket.Patches.TransferItemsModule;
using TMPro;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.Networking;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp-firstpass")]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: TargetFramework(".NETFramework,Version=v4.8.1", FrameworkDisplayName = ".NET Framework 4.8.1")]
[assembly: AssemblyCompany("None")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Bepinex plugin for Supermarket Together adding extra QoL features")]
[assembly: AssemblyFileVersion("0.8.7.60001")]
[assembly: AssemblyInformationalVersion("0.8.7.60001+05cd54f610dbae45caf75a1971c4824e7fbef97f")]
[assembly: AssemblyProduct("es.damntry.SuperQoLity")]
[assembly: AssemblyTitle("SuperQoLity")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.8.7.60001")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace SuperQoLity
{
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInPlugin("es.damntry.SuperQoLity", "SuperQoLity", "0.8.7.60001")]
	public class Plugin : BaseUnityPlugin
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static PreprocessMessageFunc <0>__RemoveSpecialNotifNewLinesForLog;
		}

		public static bool IsSolutionInDebugMode = false;

		private static int AssetIdModSignature { get; } = 3071;


		public void Awake()
		{
			//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>__RemoveSpecialNotifNewLinesForLog;
			if (obj == null)
			{
				PreprocessMessageFunc val = GameNotifications.RemoveSpecialNotifNewLinesForLog;
				<>O.<0>__RemoveSpecialNotifNewLinesForLog = val;
				obj = (object)val;
			}
			TimeLogger.InitializeTimeLogger<BepInExTimeLogger>((PreprocessMessageFunc)obj, false, new object[1] { "SuperQoLity" });
			SolutionDebugModeHandler();
			ModConfig.Instance.InitializeConfig((BaseUnityPlugin)(object)this);
			ConfigDebugModeHandler();
			AutoPatcher.RegisterAllAutoPatchContainers();
			ModConfig.Instance.StartConfigBinding();
			GameNotifications.Instance.InitializeGameNotifications();
			TaskExtensionMethods.FireAndForget(KeyPressDetection.InitializeAsync((Func<MonoBehaviour>)(() => (MonoBehaviour)(object)FirstPersonController.Instance), (Func<bool>)(() => !AuxUtils.IsChatOpen())), (LogCategories)8);
			NetworkSpawnManager.Initialize(AssetIdModSignature);
			TimeLogger.Logger.LogTimeDebug("SuperQoLity (es.damntry.SuperQoLity) initialization finished.", (LogCategories)8);
			bool flag = AutoPatcher.StartAutoPatcher();
			JobSchedulerManager.InitializeJobSchedulerEvents();
			RestockMatcher.Enable();
			StartingMessage.InitStartingMessages(flag);
			TimeLogger.Logger.LogTimeMessage("Mod SuperQoLity (es.damntry.SuperQoLity) loaded " + (flag ? "" : "(not quite) ") + "successfully.", (LogCategories)8);
		}

		private void SolutionDebugModeHandler()
		{
		}

		public static void ConfigDebugModeHandler()
		{
			bool flag = ModConfig.Instance.IsDebugEnabledConfig();
			if (flag != TimeLogger.DebugEnabled)
			{
				TimeLogger.DebugEnabled = flag;
				TimeLogger.Logger.LogTimeWarning("SuperQoLity Debug Dev mode " + (flag ? "enabled" : "disabled") + ".", (LogCategories)8);
			}
		}

		public static void HookChangeDebugSetting()
		{
			ModConfig.Instance.EnabledDevMode.SettingChanged += delegate
			{
				ConfigDebugModeHandler();
			};
		}

		private CheckResult StartMethodSignatureCheck()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			try
			{
				MethodSignatureChecker val = new MethodSignatureChecker(((object)this).GetType());
				val.PopulateMethodSignaturesFromHarmonyPatches();
				val.AddMethod(typeof(NPC_Manager), "EmployeeNPCControl", new Type[1] { typeof(int) }, (Type[])null);
				val.AddMethod(typeof(NPC_Manager), "GetFreeStorageContainer", new Type[1] { typeof(int) }, (Type[])null);
				val.AddMethod(typeof(NPC_Manager), "MainRestockUpdate");
				val.AddMethod(typeof(NPC_Manager), "CheckIfProdShelfWithSameProduct");
				val.AddMethod(typeof(NPC_Manager), "GetRandomGroundBox");
				val.AddMethod(typeof(NPC_Manager), "GetRandomGroundBoxAllowedInStorage");
				val.AddMethod(typeof(NPC_Manager), "DropBoxOnGround");
				val.AddMethod(typeof(NPC_Manager), "UnequipBox");
				val.AddMethod(typeof(NPC_Manager), "AttemptToGetRestPosition");
				val.AddMethod(typeof(NPC_Manager), "CashierGetAvailableCheckout");
				val.AddMethod(typeof(NPC_Manager), "UpdateEmployeeCheckouts");
				val.AddMethod(typeof(NPC_Manager), "CheckIfCustomerInQueue");
				val.AddMethod(typeof(NPC_Manager), "GetThiefTarget");
				val.AddMethod(typeof(NPC_Manager), "IsFirstSecurityEmployee");
				val.AddMethod(typeof(NPC_Manager), "GetClosestDropProduct");
				val.AddMethod(typeof(NPC_Manager), "RetrieveCorrectPatrolPoint");
				val.AddMethod(typeof(NPC_Manager), "UpdateEmployeeStats");
				return val.StartSignatureCheck();
			}
			catch (Exception ex)
			{
				TimeLogger.Logger.LogTimeException(ex, (LogCategories)4194304);
				return CheckResult.UnknownError;
			}
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "es.damntry.SuperQoLity";

		public const string PLUGIN_NAME = "SuperQoLity";

		public const string PLUGIN_VERSION = "0.8.7.60001";

		public const string BETTERSMT_SUPPORTED_VERSION = "2.4.0";
	}
}
namespace SuperQoLity.SuperMarket
{
	public enum GameOnlineMode
	{
		None,
		Host,
		Client
	}
	public enum GameWorldEvent
	{
		QuitOrMenu,
		LoadingWorld,
		CanvasAwake,
		FPControllerStarted,
		WorldStarted
	}
	public static class WorldState
	{
		public static class BuildingsEvents
		{
			public static Action<Data_Container> OnProductShelfLoadedOrUpdated;

			public static Action<Data_Container> OnStorageLoadedOrUpdated;

			public static Action<NetworkSpawner, int> OnShelfBuilt;
		}

		public static GameWorldEvent CurrentGameWorldState { get; private set; }

		public static GameOnlineMode CurrenOnlineMode { get; set; }

		public static bool IsGameWorldStarted => CurrentGameWorldState == GameWorldEvent.WorldStarted;

		public static event Action<GameWorldEvent> OnGameWorldChange;

		public static event Action OnQuitOrMenu;

		public static event Action OnLoadingWorld;

		public static event Action OnCanvasAwake;

		public static event Action OnFPControllerStarted;

		public static event Action OnWorldStarted;

		public static bool IsGameWorldAtOrAfter(GameWorldEvent worldState)
		{
			return CurrentGameWorldState >= worldState;
		}

		public static void SetGameWorldState(GameWorldEvent state)
		{
			TimeLogger.Logger.LogTimeDebugFunc((Func<string>)(() => $"World state change from {CurrentGameWorldState} to {state}"), (LogCategories)8);
			CurrentGameWorldState = state;
			EventMethods.TryTriggerEvents<GameWorldEvent>(WorldState.OnGameWorldChange, state);
			EventMethods.TryTriggerEvents(GetSubscribersForWorldState(state));
		}

		public static void SubscribeToWorldStateEvent(GameWorldEvent state, Action actionOnEvent)
		{
			switch (state)
			{
			case GameWorldEvent.QuitOrMenu:
				OnQuitOrMenu += actionOnEvent;
				break;
			case GameWorldEvent.LoadingWorld:
				OnLoadingWorld += actionOnEvent;
				break;
			case GameWorldEvent.CanvasAwake:
				OnCanvasAwake += actionOnEvent;
				break;
			case GameWorldEvent.FPControllerStarted:
				OnFPControllerStarted += actionOnEvent;
				break;
			case GameWorldEvent.WorldStarted:
				OnWorldStarted += actionOnEvent;
				break;
			}
		}

		public static Action GetSubscribersForWorldState(GameWorldEvent state)
		{
			return state switch
			{
				GameWorldEvent.QuitOrMenu => WorldState.OnQuitOrMenu, 
				GameWorldEvent.LoadingWorld => WorldState.OnLoadingWorld, 
				GameWorldEvent.CanvasAwake => WorldState.OnCanvasAwake, 
				GameWorldEvent.FPControllerStarted => WorldState.OnFPControllerStarted, 
				GameWorldEvent.WorldStarted => WorldState.OnWorldStarted, 
				_ => null, 
			};
		}
	}
}
namespace SuperQoLity.SuperMarket.Patches
{
	public class GameWorldEventsPatch : FullyAutoPatchedInstance
	{
		private class DetectGameLoadFinished
		{
			private enum DetectionState
			{
				Initial,
				Success,
				Failed
			}

			private static readonly Stopwatch sw = Stopwatch.StartNew();

			private static GameObject transitionBCKobj;

			private static DetectionState state = DetectionState.Initial;

			[HarmonyPatch(typeof(NetworkManager), "OnStartServer")]
			[HarmonyPrefix]
			public static void OnStartHostPrefixPatch()
			{
				SetLoadingWorld();
			}

			[HarmonyPatch(typeof(NetworkManager), "OnStartClient")]
			[HarmonyPrefix]
			public static void OnStartClientPrefixPatch()
			{
				if (WorldState.CurrenOnlineMode != GameOnlineMode.Host)
				{
					SetLoadingWorld();
				}
			}

			private static void SetLoadingWorld()
			{
				WorldState.CurrenOnlineMode = (NetworkServer.activeHost ? GameOnlineMode.Host : GameOnlineMode.Client);
				WorldState.SetGameWorldState(GameWorldEvent.LoadingWorld);
			}

			[HarmonyPatch(typeof(GameCanvas), "Awake")]
			[HarmonyPostfix]
			private static void GameCanvasAwake(GameCanvas __instance)
			{
				WorldState.SetGameWorldState(GameWorldEvent.CanvasAwake);
			}

			[HarmonyPatch(typeof(GameCanvas), "Update")]
			[HarmonyPostfix]
			private static void GameCanvasUpdatePostFix(GameCanvas __instance)
			{
				if (sw.ElapsedMilliseconds < 100)
				{
					return;
				}
				try
				{
					if ((Object)(object)transitionBCKobj == (Object)null)
					{
						state = DetectionState.Initial;
						transitionBCKobj = GameObject.Find("MasterOBJ/MasterCanvas/TransitionBCK");
					}
					if ((Object)(object)transitionBCKobj != (Object)null && !transitionBCKobj.activeSelf && state == DetectionState.Initial)
					{
						state = DetectionState.Success;
						WorldState.SetGameWorldState(GameWorldEvent.WorldStarted);
					}
				}
				catch (Exception ex)
				{
					state = DetectionState.Failed;
					TimeLogger.Logger.LogTimeExceptionWithMessage("Error while trying to detect game finished loading.", ex, (LogCategories)8);
				}
				finally
				{
					GameWorldEventsPatch instance = Container<GameWorldEventsPatch>.Instance;
					if (state == DetectionState.Failed)
					{
						TimeLogger.Logger.LogTimeError(((AutoPatchedInstanceBase)instance).ErrorMessageOnAutoPatchFail, (LogCategories)8);
						((AutoPatchedInstanceBase)instance).UnpatchInstance();
						sw.Stop();
					}
					else
					{
						sw.Restart();
					}
				}
			}
		}

		private class FirstPersonControllerStart
		{
			[HarmonyPatch(typeof(FirstPersonController), "Start")]
			[HarmonyPostfix]
			public static void OnClientDisconnectPatch(FirstPersonController __instance)
			{
				WorldState.SetGameWorldState(GameWorldEvent.FPControllerStarted);
			}
		}

		private class DetectQuitToMainMenu
		{
			[HarmonyPatch(typeof(CustomNetworkManager), "OnClientDisconnect")]
			[HarmonyPostfix]
			public static void OnClientDisconnectPatch(CustomNetworkManager __instance)
			{
				WorldState.CurrenOnlineMode = GameOnlineMode.None;
				WorldState.SetGameWorldState(GameWorldEvent.QuitOrMenu);
			}
		}

		private class BuildingEvents
		{
			private class ShelfLoadedOrBuilt
			{
				[HarmonyPatch(typeof(Data_Container), "BoxSpawner")]
				[HarmonyPostfix]
				private static void BoxSpawnerPatch(Data_Container __instance)
				{
					EventMethods.TryTriggerEvents<Data_Container>(WorldState.BuildingsEvents.OnStorageLoadedOrUpdated, __instance);
				}

				[HarmonyPatch(typeof(Data_Container), "ItemSpawner")]
				[HarmonyPostfix]
				private static void ItemSpawnerPatch(Data_Container __instance)
				{
					EventMethods.TryTriggerEvents<Data_Container>(WorldState.BuildingsEvents.OnProductShelfLoadedOrUpdated, __instance);
				}

				[HarmonyPatch(typeof(NetworkSpawner), "UserCode_CmdSpawn__Int32__Vector3__Vector3")]
				[HarmonyPostfix]
				private static void NewBuildableConstructed(NetworkSpawner __instance, int prefabID)
				{
					EventMethods.TryTriggerEvents<NetworkSpawner, int>(WorldState.BuildingsEvents.OnShelfBuilt, __instance, prefabID);
				}
			}
		}

		public override bool IsAutoPatchEnabled => true;

		public override string ErrorMessageOnAutoPatchFail { get; protected set; } = "SuperQoLity - Detection of world events patch failed. Disabled";

	}
	public class PerformanceCachingPatch : FullyAutoPatchedInstance
	{
		public class PopulateCacheOnBuilderInitialization
		{
			[CompilerGenerated]
			private sealed class <WaitEndOfIEnumerable>d__0 : IEnumerator<object>, IDisposable, IEnumerator
			{
				private int <>1__state;

				private object <>2__current;

				public IEnumerator result;

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

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

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

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

				private bool MoveNext()
				{
					switch (<>1__state)
					{
					default:
						return false;
					case 0:
						<>1__state = -1;
						break;
					case 1:
						<>1__state = -1;
						break;
					}
					if (result.MoveNext())
					{
						<>2__current = result.Current;
						<>1__state = 1;
						return true;
					}
					PopulateMaxProductsPerRowCache();
					return false;
				}

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

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

			[IteratorStateMachine(typeof(<WaitEndOfIEnumerable>d__0))]
			[HarmonyPatch(typeof(Builder_Main), "RetrieveInitialBehaviours")]
			[HarmonyPostfix]
			public static IEnumerator WaitEndOfIEnumerable(IEnumerator result)
			{
				//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
				return new <WaitEndOfIEnumerable>d__0(0)
				{
					result = result
				};
			}
		}

		private static readonly Dictionary<(int containerClass, int containerId, int productId), int> maxProductsPerRowCache = new Dictionary<(int, int, int), int>();

		private static bool cachePopulated = false;

		public override bool IsAutoPatchEnabled => ModConfig.Instance.EnableEmployeeChanges.Value;

		public override string ErrorMessageOnAutoPatchFail { get; protected set; } = "SuperQoLity - AI caching patch failed. Disabled";


		private static void PopulateMaxProductsPerRowCache()
		{
			if (cachePopulated)
			{
				return;
			}
			GameObject[] buildables = ((Component)GameData.Instance).GetComponent<NetworkSpawner>().buildables;
			Data_Container val2 = default(Data_Container);
			foreach (GameObject val in buildables)
			{
				if ((Object)(object)val == (Object)null || !val.TryGetComponent<Data_Container>(ref val2) || val2.GetContainerType() != 0)
				{
					continue;
				}
				GameObject[] productPrefabs = ProductListing.Instance.productPrefabs;
				foreach (GameObject val3 in productPrefabs)
				{
					if (!((Object)(object)val3 == (Object)null))
					{
						int productID = val3.GetComponent<Data_Product>().productID;
						int maxProductsPerRow = GetMaxProductsPerRow(val2, productID);
						maxProductsPerRowCache.Add((val2.containerClass, val2.containerID, productID), maxProductsPerRow);
					}
				}
			}
			cachePopulated = true;
		}

		public static int GetMaxProductsPerRowCachedThreaded(Data_Container dataContainer, int shelfProductId, int shelfIndex)
		{
			return GetMaxProductsPerRowCached(null, dataContainer, shelfProductId, shelfIndex, isThreaded: true);
		}

		public static int GetMaxProductsPerRowCached(NPC_Manager __instance, Data_Container dataContainer, int shelfProductId, int shelfIndex)
		{
			return GetMaxProductsPerRowCached(null, dataContainer, shelfProductId, shelfIndex, isThreaded: false);
		}

		public static int GetMaxProductsPerRowCached(NPC_Manager __instance, Data_Container dataContainer, int shelfProductId, int shelfIndex, bool isThreaded)
		{
			bool flag = false;
			int value = 0;
			if (cachePopulated)
			{
				flag = maxProductsPerRowCache.TryGetValue((dataContainer.containerClass, dataContainer.containerID, shelfProductId), out value);
			}
			else
			{
				TimeLogger.Logger.LogTimeWarning("MaxProductsPerRow has been requested from the cache, but it hasnt been populated yet.", (LogCategories)1024);
			}
			if (!flag)
			{
				TimeLogger.Logger.LogTimeWarning($"A maxProductsPerRow cache entry doesnt exist for containerID: {dataContainer.containerID} " + $"and productId: {shelfProductId}. Attempting to obtain it manually.", (LogCategories)8);
				if (((AutoPatchedInstanceBase)Container<PerformanceCachingPatch>.Instance).IsPatchActive)
				{
					value = GetMaxProductsPerRow(dataContainer, shelfProductId);
				}
				else if ((Object)(object)__instance != (Object)null)
				{
					value = __instance.GetMaxProductsPerRow(shelfIndex, shelfProductId);
				}
				else if (isThreaded)
				{
					TimeLogger.Logger.LogTimeWarning("This method is threaded and the amount cannot be calculated from the source Unity objects. Returning 0.", (LogCategories)8);
				}
				else
				{
					TimeLogger.Logger.LogTimeError("The NPC_Manager instance is null and the value could not be obtained manually.", (LogCategories)8);
				}
				maxProductsPerRowCache.Add((dataContainer.containerClass, dataContainer.containerID, shelfProductId), value);
			}
			return value;
		}

		public static int GetMaxProductsPerRow(Data_Container dataContainer, int shelfProductId)
		{
			return GetMaxProductsPerRow(NPC_Manager.Instance, -1, dataContainer, shelfProductId);
		}

		private static int GetMaxProductsPerRow(NPC_Manager __instance, int shelfIndex, Data_Container dataContainer, int ProductID)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			if (ProductID >= ProductListing.Instance.productPrefabs.Length)
			{
				return -1;
			}
			GameObject obj = ProductListing.Instance.productPrefabs[ProductID];
			Vector3 size = obj.GetComponent<BoxCollider>().size;
			bool isStackable = obj.GetComponent<Data_Product>().isStackable;
			int num = Mathf.Clamp(Mathf.FloorToInt(dataContainer.shelfLength / (size.x * 1.1f)), 1, 100);
			int num2 = Mathf.FloorToInt(dataContainer.shelfWidth / (size.z * 1.1f));
			num2 = Mathf.Clamp(num2, 1, 100);
			int num3 = num * num2;
			if (isStackable)
			{
				int num4 = Mathf.FloorToInt(dataContainer.shelfHeight / (size.y * 1.1f));
				num4 = Mathf.Clamp(num4, 1, 100);
				num3 *= num4;
			}
			return num3;
		}
	}
	public class ShelfItemCulling
	{
		public static void Initialize()
		{
		}

		public static void ShelfBuilt(NetworkSpawner instance, int prefabID)
		{
			instance.buildables[prefabID].GetComponent<Data_Container>();
		}

		public static void CreateProductShelfBounds(Data_Container instance)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			foreach (Transform item in ((Component)instance).transform.Find("ProductContainer"))
			{
				_ = item;
			}
		}

		public static void OnStorageLoadedOrUpdated(Data_Container __instance)
		{
		}

		public static void NewBuildableConstructed(NetworkSpawner __instance, int prefabID)
		{
		}
	}
	public class StoreOpenStatusPatch : FullyAutoPatchedInstance
	{
		private static CancellableSingleTask<UniTaskDelay> storeClosedTask = new CancellableSingleTask<UniTaskDelay>(true);

		private static SemaphoreSlim semaphoreLock = new SemaphoreSlim(1, 1);

		public override bool IsAutoPatchEnabled
		{
			get
			{
				if (!ModConfig.Instance.EnableEmployeeChanges.Value)
				{
					return ModConfig.Instance.EnableTransferProducts.Value;
				}
				return true;
			}
		}

		public override string ErrorMessageOnAutoPatchFail { get; protected set; } = "SuperQoLity - Store opening state detection patch failed. Disabled";


		public static event Action<bool> OnSupermarketOpenStateChanged;

		public override void OnPatchFinishedVirtual(bool IsActive)
		{
			if (IsActive)
			{
				NetworkSpawnManager.RegisterNetwork<StoreStatusNetwork>(918219u);
				WorldState.OnQuitOrMenu += async delegate
				{
					await storeClosedTask.StopTaskAndWaitAsync(500);
				};
			}
		}

		[HarmonyPatch(/*Could not decode attribute arguments.*/)]
		[HarmonyPriority(600)]
		[HarmonyPrefix]
		private static bool NetworkisSupermarketOpenPrefixPatch(ref bool __state)
		{
			__state = GameData.Instance.isSupermarketOpen;
			return true;
		}

		[HarmonyPatch(/*Could not decode attribute arguments.*/)]
		[HarmonyPostfix]
		private static async void NetworkisSupermarketOpenPostfixPatch(bool __state)
		{
			if (GameData.Instance.isSupermarketOpen == __state)
			{
				return;
			}
			await storeClosedTask.StopTaskAndWaitAsync();
			await semaphoreLock.WaitAsync();
			try
			{
				bool value = true;
				if (!GameData.Instance.isSupermarketOpen)
				{
					await storeClosedTask.StartAwaitableTaskAsync((Func<Task>)CheckCustomersPendingActions, "Wait for end of customers actions", true);
					if (storeClosedTask.IsCancellationRequested)
					{
						TimeLogger.Logger.LogTimeDebugFunc((Func<string>)(() => "Skipped to next day or quitting to main menu before customers left the store."), (LogCategories)16);
					}
					else
					{
						TimeLogger.Logger.LogTimeDebugFunc((Func<string>)(() => "All customers are leaving or already left the supermarket."), (LogCategories)16);
					}
					value = false;
				}
				StoreStatusNetwork.IsStoreOpenOrCustomersInsideSync.Value = value;
				if (StoreOpenStatusPatch.OnSupermarketOpenStateChanged != null)
				{
					StoreOpenStatusPatch.OnSupermarketOpenStateChanged(SyncVar<bool>.op_Implicit(StoreStatusNetwork.IsStoreOpenOrCustomersInsideSync));
				}
			}
			finally
			{
				semaphoreLock.Release();
			}
		}

		private static async Task CheckCustomersPendingActions()
		{
			UnityTimeStopwatch safetyTimeout = UnityTimeStopwatch.StartNew();
			try
			{
				while (HasCustomersWithPendingActions(storeClosedTask.CancellationToken) && safetyTimeout.ElapsedSeconds < 180)
				{
					await UniTask.Delay(500, false, (PlayerLoopTiming)8, storeClosedTask.CancellationToken, false);
				}
			}
			catch (OperationCanceledException)
			{
			}
		}

		private static bool HasCustomersWithPendingActions(CancellationToken cancelToken = default(CancellationToken))
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			if (cancelToken.IsCancellationRequested)
			{
				return false;
			}
			foreach (Transform item in NPC_Manager.Instance.customersnpcParentOBJ.transform)
			{
				if (((Component)item).gameObject.GetComponent<NPC_Info>().state < 99)
				{
					return true;
				}
			}
			return false;
		}
	}
}
namespace SuperQoLity.SuperMarket.Patches.TransferItemsModule
{
	public enum EnumItemTransferMode
	{
		[Description("Disabled")]
		Disabled,
		[Description("Only while store is closed")]
		OnlyWhileStoreClosed,
		[Description("Always on")]
		AlwaysOn
	}
	[HarmonyPatch(typeof(Data_Container))]
	public class IncreasedItemTransferPatch : FullyAutoPatchedInstance
	{
		private enum RowActionType
		{
			Add,
			Remove
		}

		public enum CharacterType
		{
			Player,
			Employee
		}

		public override bool IsAutoPatchEnabled => ModConfig.Instance.EnableTransferProducts.Value;

		public override string ErrorMessageOnAutoPatchFail { get; protected set; } = "SuperQoLity - Transfer patch failed. Item Transfer Module inactive";


		public override void OnPatchFinishedVirtual(bool IsPatchActive)
		{
			if (IsPatchActive)
			{
				NetworkSpawnManager.RegisterNetwork<ItemTransferNetwork>(871623u);
			}
		}

		public static int GetNumTransferItems(int giverItemCount, int receiverItemCount, int receiverMaxCapacity, CharacterType charType)
		{
			return GetNumTransferItems(giverItemCount, receiverItemCount, receiverMaxCapacity, charType, 1);
		}

		public static int GetNumTransferItems(int giverItemCount, int receiverItemCount, int receiverMaxCapacity, CharacterType charType, int numMovedProducts)
		{
			if (IsItemTransferEnabledFor(charType, numMovedProducts))
			{
				int val = receiverMaxCapacity - receiverItemCount;
				numMovedProducts = Math.Min(Math.Min((charType == CharacterType.Player) ? ((SyncVar<int>)(object)ItemTransferNetwork.ItemTransferQuantitySync).Value : int.MaxValue, giverItemCount), val);
			}
			return numMovedProducts;
		}

		public static bool IsItemTransferEnabledFor(CharacterType charType, int numMovedProducts)
		{
			if ((charType == CharacterType.Player && ((SyncVar<EnumItemTransferMode>)(object)ItemTransferNetwork.ItemTransferModeSync).Value == EnumItemTransferMode.Disabled) || (charType == CharacterType.Employee && !ModConfig.Instance.ClosedStoreEmployeeItemTransferMaxed.Value))
			{
				return false;
			}
			if (!SyncVar<bool>.op_Implicit(StoreStatusNetwork.IsStoreOpenOrCustomersInsideSync))
			{
				return true;
			}
			switch (charType)
			{
			case CharacterType.Player:
				if (ModConfig.Instance.EnableTransferProducts.Value && ((SyncVar<int>)(object)ItemTransferNetwork.ItemTransferQuantitySync).Value != numMovedProducts)
				{
					return ((SyncVar<EnumItemTransferMode>)(object)ItemTransferNetwork.ItemTransferModeSync).Value != EnumItemTransferMode.OnlyWhileStoreClosed;
				}
				return false;
			case CharacterType.Employee:
				return false;
			default:
				throw new InvalidOperationException($"{charType} is not a supported value in this method.");
			}
		}

		[HarmonyPatch("AddItemToRow")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> AddItemToRowTranspiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
		{
			return TranspilerChangeProductTransferCount(instructions, generator, RowActionType.Add);
		}

		[HarmonyPatch("RemoveItemFromRow")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> RemoveItemFromRowTranspiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
		{
			return TranspilerChangeProductTransferCount(instructions, generator, RowActionType.Remove);
		}

		private static IEnumerable<CodeInstruction> TranspilerChangeProductTransferCount(IEnumerable<CodeInstruction> instructions, ILGenerator generator, RowActionType rowActionType)
		{
			//IL_0049: 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_00f1: Unknown result type (might be due to invalid IL or missing references)
			List<CodeInstruction> list = instructions.ToList();
			int num = -1;
			int num2 = -1;
			FieldInfo extraParameter2 = AccessTools.Field(typeof(PlayerNetwork), "extraParameter2");
			int num3 = list.FindLastIndex((CodeInstruction instruction) => CodeInstructionExtensions.LoadsField(instruction, extraParameter2, false));
			if (num3 < 0)
			{
				throw new TranspilerDefaultMsgException("Couldnt find the instruction loading the value of the field extraParameter2");
			}
			int num4 = list.FindLastIndex(num3, num3, (CodeInstruction instruction) => instruction.opcode == OpCodes.Br || instruction.opcode == OpCodes.Br_S);
			if (num4 < 0)
			{
				throw new TranspilerDefaultMsgException($"Couldnt find the Br/Br_S instruction when looking up to IL line {num3}");
			}
			Label endElseLabel = (Label)list[num4].operand;
			int num5 = list.Count - 1;
			int num6 = list.FindLastIndex(num5, num5 - num3, (CodeInstruction instruction) => instruction.labels.FirstOrDefault() == endElseLabel);
			if (num6 < 0)
			{
				throw new TranspilerDefaultMsgException($"Couldnt find IL Label {endElseLabel} when searching from IL line {num3}");
			}
			num = num4 + 1;
			num2 = num6 - 1;
			ReplaceConstantsWithCallResult(list, generator, num, num2, rowActionType);
			return list;
		}

		private static void ReplaceConstantsWithCallResult(List<CodeInstruction> instrList, ILGenerator generator, int indexStart, int indexEnd, RowActionType rowActionType)
		{
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0150: Unknown result type (might be due to invalid IL or missing references)
			List<CodeInstruction> list = CreateILCall_GetNumTransferItems(instrList, indexStart, indexEnd, rowActionType);
			LocalBuilder localBuilder = generator.DeclareLocal(typeof(int));
			CodeInstruction value = CodeInstructionNew.LoadLocal(localBuilder.LocalIndex, false);
			CodeInstructionExtensions.MoveLabelsTo(instrList[indexStart], list[0]);
			if (rowActionType == RowActionType.Add)
			{
				if (instrList[indexStart + 3].operand == null || !instrList[indexStart + 3].operand.ToString().Contains("AchievementPoint"))
				{
					throw new TranspilerDefaultMsgException($"The call to a method containing the text \"AchievementPoint\" wasnt found at the expected line {indexStart + 3}");
				}
				if (instrList[indexStart + 2].opcode != OpCodes.Ldc_I4_1)
				{
					throw new TranspilerDefaultMsgException($"The opcode Ldc_I4_1 for achievements wasnt found at the expected line {indexStart + 2}.");
				}
				instrList[indexStart + 2] = value;
				instrList.InsertRange(indexEnd, instrList.GetRange(indexStart, 4));
				instrList.RemoveRange(indexStart, 4);
			}
			int num = instrList.FindIndex(indexStart, indexEnd - indexStart, (CodeInstruction instruction) => instruction.opcode == OpCodes.Ldc_I4_1);
			if (num == -1)
			{
				throw new TranspilerDefaultMsgException("Couldnt find first line with Ldc_I4_1 to replace with our new local variable numItemsTransfer");
			}
			int num2 = instrList.FindIndex(num + 1, indexEnd - num + 1, (CodeInstruction instruction) => instruction.opcode == OpCodes.Ldc_I4_1);
			if (num2 == -1)
			{
				throw new TranspilerDefaultMsgException("Couldnt find second line with Ldc_I4_1 to replace with our new local variable numItemsTransfer");
			}
			instrList.InsertRange(indexStart, list);
			instrList.Insert(indexStart + list.Count, CodeInstructionNew.StoreLocal(localBuilder.LocalIndex));
			num += list.Count + 1;
			num2 += list.Count + 1;
			instrList[num] = value;
			instrList[num2] = value;
		}

		private static List<CodeInstruction> CreateILCall_GetNumTransferItems(List<CodeInstruction> instrList, int indexStart, int indexEnd, RowActionType rowActionType)
		{
			//IL_0044: 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_0060: Expected O, but got Unknown
			List<CodeInstruction> list = new List<CodeInstruction>();
			List<CodeInstruction> boxCountILInstructions = GetBoxCountILInstructions(instrList, indexStart, indexEnd);
			switch (rowActionType)
			{
			case RowActionType.Add:
				list.AddRange(GetILParametersAddingItems(instrList, boxCountILInstructions));
				break;
			case RowActionType.Remove:
				list.AddRange(GetILParametersRemovingItems(instrList, boxCountILInstructions));
				break;
			default:
				throw new TranspilerDefaultMsgException($"Initial RowActionType: {rowActionType}");
			}
			list.Add(new CodeInstruction(OpCodes.Ldc_I4_S, (object)0));
			list.Add(Transpilers.EmitDelegate<Func<int, int, int, CharacterType, int>>((Func<int, int, int, CharacterType, int>)GetNumTransferItems));
			return list;
		}

		private static List<CodeInstruction> GetILParametersAddingItems(List<CodeInstruction> instrList, List<CodeInstruction> getBoxCountILInstr)
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			List<CodeInstruction> list = new List<CodeInstruction>();
			int num = instrList.FindIndex((CodeInstruction instruction) => instruction.opcode == OpCodes.Ldstr && instruction.operand.ToString() == "message1");
			if (num == -1)
			{
				throw new TranspilerDefaultMsgException("Couldnt find the line loading the string \"message1\".");
			}
			int num2 = instrList.FindLastIndex(num, (CodeInstruction instruction) => CodeInstructionExtensions.IsLdloc(instruction, (LocalBuilder)null));
			if (num2 == -1)
			{
				throw new TranspilerDefaultMsgException("Couldnt find the line loading the local var \"num3\".");
			}
			int index = num2 - 1;
			int num3 = ILExtensionMethods.LocalIndex(instrList[num2]);
			int num4 = ILExtensionMethods.LocalIndex(instrList[index]);
			list.AddRange(getBoxCountILInstr);
			list.Add(CodeInstructionNew.LoadLocal(num4, false));
			list.Add(CodeInstructionNew.LoadLocal(num3, false));
			return list;
		}

		private static List<CodeInstruction> GetILParametersRemovingItems(List<CodeInstruction> instrList, List<CodeInstruction> getBoxCountILInstr)
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_0150: Unknown result type (might be due to invalid IL or missing references)
			List<CodeInstruction> list = new List<CodeInstruction>();
			int num = -1;
			int num2 = 0;
			int num3 = int.MinValue;
			FieldInfo fieldInfo = AccessTools.Field(typeof(Data_Container), "productInfoArray");
			FieldInfo fieldInfo2 = AccessTools.Field(typeof(Data_Product), "maxItemsPerBox");
			if (fieldInfo == null)
			{
				throw new TranspilerDefaultMsgException("The field Data_Container.productInfoArray could not be found.");
			}
			if (fieldInfo2 == null)
			{
				throw new TranspilerDefaultMsgException("The field Data_Product.maxItemsPerBox could not be found.");
			}
			int num4 = -1;
			int num5 = -1;
			for (int i = 0; i < instrList.Count; i++)
			{
				CodeInstruction val = instrList[i];
				if (num2 < 2 && CodeInstructionExtensions.LoadsField(val, fieldInfo, false))
				{
					num2++;
					if (num2 == 2)
					{
						num3 = i + 1;
					}
				}
				else if (num5 == -1 && i >= num3 && i < num3 + 10 && CodeInstructionExtensions.IsStloc(val, (LocalBuilder)null))
				{
					num5 = ILExtensionMethods.LocalIndex(val);
				}
				else if (num < 0 && CodeInstructionExtensions.LoadsField(val, fieldInfo2, false))
				{
					num = i + 1;
				}
				else if (i == num && CodeInstructionExtensions.IsStloc(val, (LocalBuilder)null))
				{
					num4 = ILExtensionMethods.LocalIndex(val);
				}
			}
			if (num2 < 2)
			{
				throw new TranspilerDefaultMsgException($"Couldnt reach the appropiate amount of productInfoArray usages (productInfoArrayInstance = {num2})");
			}
			if (num5 == -1)
			{
				throw new TranspilerDefaultMsgException($"Couldnt find the num3 local var reference (num3IndexBeginSearch = {num3})");
			}
			if (num4 == -1)
			{
				throw new TranspilerDefaultMsgException($"Couldnt find the maxItemsPerBox local var reference (maxItemsPerBoxLocalVarIndex = {num})");
			}
			list.Add(CodeInstructionNew.LoadLocal(num5, false));
			list.AddRange(getBoxCountILInstr);
			list.Add(CodeInstructionNew.LoadLocal(num4, false));
			return list;
		}

		private static List<CodeInstruction> GetBoxCountILInstructions(List<CodeInstruction> instrList, int indexStart, int indexEnd)
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			int num = instrList.FindIndex(indexStart, indexEnd - indexStart, (CodeInstruction instruction) => instruction.opcode == OpCodes.Dup);
			if (num == -1)
			{
				throw new TranspilerDefaultMsgException($"Couldnt find the Dup instruction between: (indexStart = {indexStart}, indexEnd = {indexEnd})");
			}
			return new List<CodeInstruction>((IEnumerable<CodeInstruction>)(object)new CodeInstruction[2]
			{
				instrList[num - 1],
				instrList[num + 1]
			});
		}
	}
}
namespace SuperQoLity.SuperMarket.Patches.Misc
{
	public class CheckoutAutoClickScanner : FullyAutoPatchedInstance
	{
		[CompilerGenerated]
		private sealed class <CreateProductObject>d__19 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public IEnumerator result;

			public ProductCheckoutSpawn __instance;

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

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

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

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

			private bool MoveNext()
			{
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					break;
				case 1:
					<>1__state = -1;
					break;
				}
				if (result.MoveNext())
				{
					<>2__current = result.Current;
					<>1__state = 1;
					return true;
				}
				__instance.isFinished = false;
				return false;
			}

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

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

		private LayerMask interactableMask = LayerMask.op_Implicit(-1);

		private FixedCapacityUniqueQueue<ProductCheckoutSpawn> checkoutItemQueue;

		private static readonly int MaxItemsQueue = 2;

		private float nextCheckoutProductPickTime;

		private float nextCheckoutProductQueueTime;

		private float DequeueTimeLimit;

		private static readonly float CheckoutProductPickInterval = 0.175f;

		private static readonly float CheckoutProductQueueInterval = 0.025f;

		private static readonly float NoCashierPermissionDelay = 0.5f;

		private static readonly float AllowedDequeueTimeSinceLastRaycast = 0.2f;

		private static readonly float NoHitDelay = CheckoutProductQueueInterval;

		private bool wasButtonDown;

		public override bool IsAutoPatchEnabled => ModConfig.Instance.EnableMiscPatches.Value;

		public override string ErrorMessageOnAutoPatchFail { get; protected set; } = "SuperQoLity - Hold click to scan checkout products patch failed. Disabled.";


		public override void OnPatchFinishedVirtual(bool IsPatchActive)
		{
			if (IsPatchActive)
			{
				checkoutItemQueue = new FixedCapacityUniqueQueue<ProductCheckoutSpawn>(MaxItemsQueue, true);
				ModConfig.Instance.EnableCheckoutAutoClicker.SettingChanged += delegate
				{
					ManageState();
				};
				ManageState();
			}
		}

		[IteratorStateMachine(typeof(<CreateProductObject>d__19))]
		[HarmonyPatch(typeof(ProductCheckoutSpawn), "CreateProductObject")]
		[HarmonyPostfix]
		public static IEnumerator CreateProductObject(IEnumerator result, ProductCheckoutSpawn __instance)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <CreateProductObject>d__19(0)
			{
				result = result,
				__instance = __instance
			};
		}

		private void ManageState()
		{
			if (ModConfig.Instance.EnableCheckoutAutoClicker.Value)
			{
				WorldState.OnFPControllerStarted += InitState;
				InputBehaviour.RegisterClickAction<CheckoutAutoClickScanner>(ProcessCheckoutProductPickup, GameWorldEvent.FPControllerStarted);
			}
			else
			{
				WorldState.OnFPControllerStarted -= InitState;
				InputBehaviour.UnregisterClickAction<CheckoutAutoClickScanner>();
			}
			if (WorldState.IsGameWorldAtOrAfter(GameWorldEvent.FPControllerStarted))
			{
				InitState();
			}
		}

		private void InitState()
		{
			//IL_0018: 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_0030: Unknown result type (might be due to invalid IL or missing references)
			SetVanillaCheckoutScanState(!ModConfig.Instance.EnableCheckoutAutoClicker.Value);
			if (LayerMask.op_Implicit(interactableMask) < 0)
			{
				interactableMask = SMTComponentInstances.PlayerNetworkInstance().interactableMask;
			}
		}

		private static void SetVanillaCheckoutScanState(bool enable)
		{
			ChangeVanillaClickEnabled(NPC_Manager.Instance.productCheckoutPrefab, enable);
			ChangeClickAllSpawnProductsInScene(enable);
		}

		private static void ChangeClickAllSpawnProductsInScene(bool enable)
		{
			//IL_0009: 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 (!WorldState.IsGameWorldAtOrAfter(GameWorldEvent.LoadingWorld))
			{
				return;
			}
			Scene activeScene = SceneManager.GetActiveScene();
			ProductCheckoutSpawn val = default(ProductCheckoutSpawn);
			foreach (GameObject item in from g in ((Scene)(ref activeScene)).GetRootGameObjects()
				where g.TryGetComponent<ProductCheckoutSpawn>(ref val)
				select g)
			{
				ChangeVanillaClickEnabled(item, enable);
			}
		}

		private static void ChangeVanillaClickEnabled(GameObject spawnObject, bool enable)
		{
			((Behaviour)((IEnumerable<PlayMakerFSM>)((Component)spawnObject.GetComponent<ProductCheckoutSpawn>()).GetComponents<PlayMakerFSM>()).FirstOrDefault((Func<PlayMakerFSM, bool>)((PlayMakerFSM fsm) => fsm.FsmName == "Behaviour"))).enabled = enable;
		}

		public void ProcessCheckoutProductPickup(float currentTime, Player mainPlayerControl)
		{
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			int mainActionId = KeyActions.MainActionId;
			if (wasButtonDown && mainPlayerControl.GetButtonUp(mainActionId))
			{
				wasButtonDown = false;
				((Queue<ProductCheckoutSpawn>)(object)checkoutItemQueue).Clear();
				nextCheckoutProductQueueTime = 0f;
				nextCheckoutProductPickTime = 0f;
			}
			if (nextCheckoutProductQueueTime > currentTime || !mainPlayerControl.GetButton(mainActionId))
			{
				return;
			}
			wasButtonDown = true;
			nextCheckoutProductQueueTime = currentTime + NoHitDelay;
			RaycastHit val = default(RaycastHit);
			ProductCheckoutSpawn productBelt = default(ProductCheckoutSpawn);
			if (!((Component)FirstPersonController.Instance).GetComponent<PlayerPermissions>().RequestCP())
			{
				nextCheckoutProductQueueTime = currentTime + NoCashierPermissionDelay;
			}
			else if (Physics.Raycast(((Component)Camera.main).transform.position, ((Component)Camera.main).transform.forward, ref val, 4f, LayerMask.op_Implicit(interactableMask)) && ((Component)((RaycastHit)(ref val)).transform).TryGetComponent<ProductCheckoutSpawn>(ref productBelt))
			{
				DequeueTimeLimit = currentTime + AllowedDequeueTimeSinceLastRaycast;
				CheckoutProductAimed(currentTime, productBelt);
			}
			else if (nextCheckoutProductPickTime < currentTime && ((Queue<ProductCheckoutSpawn>)(object)checkoutItemQueue).Count > 0)
			{
				if (DequeueTimeLimit >= currentTime)
				{
					PerformCheckoutProductClick(((Queue<ProductCheckoutSpawn>)(object)checkoutItemQueue).Dequeue(), currentTime);
				}
				else
				{
					((Queue<ProductCheckoutSpawn>)(object)checkoutItemQueue).Clear();
				}
			}
		}

		private void CheckoutProductAimed(float currentTime, ProductCheckoutSpawn productBelt)
		{
			ProductCheckoutSpawn val = default(ProductCheckoutSpawn);
			if (nextCheckoutProductPickTime < currentTime)
			{
				PerformCheckoutProductClick(productBelt, currentTime);
				((Queue<ProductCheckoutSpawn>)(object)checkoutItemQueue).Clear();
			}
			else if (!productBelt.isFinished && checkoutItemQueue.TryEnqueue(productBelt, ref val))
			{
				nextCheckoutProductQueueTime = currentTime + CheckoutProductQueueInterval;
			}
		}

		private void PerformCheckoutProductClick(ProductCheckoutSpawn productBelt, float currentTime)
		{
			productBelt.isFinished = true;
			if (((NetworkBehaviour)productBelt).netId == 0)
			{
				TimeLogger.Logger.LogTimeWarning("Attempted to scan product with netId 0. Skipping.", (LogCategories)int.MinValue);
				return;
			}
			productBelt.CmdAddProductValueToCheckout();
			nextCheckoutProductPickTime = currentTime + CheckoutProductPickInterval;
		}
	}
	public class ExpandProductOrderClickArea : FullyAutoPatchedInstance
	{
		public override bool IsAutoPatchEnabled => ModConfig.Instance.EnableMiscPatches.Value;

		public override string ErrorMessageOnAutoPatchFail { get; protected set; } = "SuperQoLity - Increased clickable area in product order patch failed. Disabled.";


		public override void OnPatchFinishedVirtual(bool IsPatchActive)
		{
			if (IsPatchActive)
			{
				ManageState();
				ModConfig.Instance.EnableExpandedProdOrderClickArea.SettingChanged += delegate
				{
					ManageState();
				};
			}
		}

		private void ManageState()
		{
			if (ModConfig.Instance.EnableExpandedProdOrderClickArea.Value)
			{
				WorldState.OnFPControllerStarted += ExpandOrderClickableArea;
				if (WorldState.IsGameWorldAtOrAfter(GameWorldEvent.FPControllerStarted) && IsOrderUiPrefabLoaded(out var managerBlackboard))
				{
					ExpandOrderClickableArea(managerBlackboard);
				}
			}
			else
			{
				WorldState.OnFPControllerStarted -= ExpandOrderClickableArea;
				if (WorldState.IsGameWorldAtOrAfter(GameWorldEvent.FPControllerStarted) && IsOrderUiPrefabLoaded(out var managerBlackboard2))
				{
					RestoreOrderClickableArea(managerBlackboard2);
				}
			}
		}

		private void ExpandOrderClickableArea()
		{
			if (!IsOrderUiPrefabLoaded(out var managerBlackboard))
			{
				TimeLogger.Logger.LogTimeError("ManagerBlackboard.UIShopItemPrefab should be instanced by now but its not.", (LogCategories)2048);
			}
			else
			{
				ExpandOrderClickableArea(managerBlackboard);
			}
		}

		private void ExpandOrderClickableArea(ManagerBlackboard managerBlackboard)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			SetButtonClickableArea(managerBlackboard, new Vector4(-175f, -5f, -3f, -50f));
			GameObject gameObject = ((Component)managerBlackboard.UIShopItemPrefab.transform.Find("ContainerTypeBCK")).gameObject;
			((Graphic)gameObject.GetComponent<Image>()).raycastTarget = false;
			((Graphic)((Component)gameObject.transform.Find("ContainerImage")).GetComponent<Image>()).raycastTarget = false;
		}

		private void RestoreOrderClickableArea(ManagerBlackboard managerBlackboard)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			SetButtonClickableArea(managerBlackboard, Vector4.zero);
		}

		private void SetButtonClickableArea(ManagerBlackboard managerBlackboard, Vector4 padding)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			((Graphic)((Component)managerBlackboard.UIShopItemPrefab.transform.Find("AddButton")).GetComponent<Image>()).raycastPadding = padding;
		}

		private bool IsOrderUiPrefabLoaded(out ManagerBlackboard managerBlackboard)
		{
			managerBlackboard = null;
			if ((Object)(object)GameData.Instance != (Object)null && ((Component)GameData.Instance).TryGetComponent<ManagerBlackboard>(ref managerBlackboard))
			{
				return (Object)(object)managerBlackboard.UIShopItemPrefab != (Object)null;
			}
			return false;
		}
	}
	public class PricingGunFixPatch : FullyAutoPatchedInstance
	{
		public override bool IsAutoPatchEnabled => ModConfig.Instance.EnableMiscPatches.Value;

		public override string ErrorMessageOnAutoPatchFail { get; protected set; } = "SuperQoLity - Pricing Gun price patch failed. Disabled.";


		[HarmonyPatch(typeof(NPC_Manager), "CustomerNPCControl")]
		[HarmonyTranspiler]
		public static IEnumerable<CodeInstruction> CustomerNPCControlTranspiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Expected O, but got Unknown
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Expected O, but got Unknown
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Expected O, but got Unknown
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Expected O, but got Unknown
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			CodeMatcher codeMatcher = new CodeMatcher(instructions, (ILGenerator)null);
			MethodInfo removeAtMethod = typeof(List<int>).GetMethod("RemoveAt");
			if (MoveToRemoveAt(useEnd: false).IsInvalid)
			{
				throw new TranspilerDefaultMsgException("IL assigning customer max buy price before line \"component.productsIDToBuy.RemoveAt(0);\" could not be found.");
			}
			object num3_Operand = codeMatcher.Instruction.operand;
			codeMatcher.MatchBack(true, (CodeMatch[])(object)new CodeMatch[1]
			{
				new CodeMatch((Func<CodeInstruction, bool>)((CodeInstruction inst) => inst.opcode == OpCodes.Ret), (string)null)
			}).MatchForward(true, (CodeMatch[])(object)new CodeMatch[1]
			{
				new CodeMatch((Func<CodeInstruction, bool>)((CodeInstruction inst) => CodeInstructionExtensions.IsStloc(inst, (LocalBuilder)null)), (string)null)
			});
			if (codeMatcher.IsInvalid)
			{
				throw new TranspilerDefaultMsgException("IL finding \"num\" productId var could not be found.");
			}
			int num = ILExtensionMethods.LocalIndex(codeMatcher.Instruction);
			MoveToRemoveAt(useEnd: true).MatchForward(true, (CodeMatch[])(object)new CodeMatch[1]
			{
				new CodeMatch((Func<CodeInstruction, bool>)((CodeInstruction inst) => CodeInstructionExtensions.IsLdloc(inst, (LocalBuilder)null) && inst.operand == num3_Operand), (string)null)
			});
			if (codeMatcher.IsInvalid)
			{
				throw new TranspilerDefaultMsgException("IL loading num3 value into the stack could not be found.");
			}
			codeMatcher.SetInstructionAndAdvance(CodeInstructionNew.LoadLocal(num, false)).Insert((CodeInstruction[])(object)new CodeInstruction[1] { Transpilers.EmitDelegate<Func<int, float>>((Func<int, float>)GetRandomizedMarketPrice) });
			return codeMatcher.InstructionEnumeration();
			CodeMatcher MoveToRemoveAt(bool useEnd)
			{
				//IL_002f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0035: Expected O, but got Unknown
				//IL_0057: Unknown result type (might be due to invalid IL or missing references)
				//IL_005d: Expected O, but got Unknown
				//IL_007f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0085: Expected O, but got Unknown
				//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ad: Expected O, but got Unknown
				//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
				//IL_00c2: Expected O, but got Unknown
				return codeMatcher.MatchForward(useEnd, (CodeMatch[])(object)new CodeMatch[5]
				{
					new CodeMatch((Func<CodeInstruction, bool>)((CodeInstruction inst) => CodeInstructionExtensions.IsStloc(inst, (LocalBuilder)null)), (string)null),
					new CodeMatch((Func<CodeInstruction, bool>)((CodeInstruction inst) => CodeInstructionExtensions.IsLdloc(inst, (LocalBuilder)null)), (string)null),
					new CodeMatch((Func<CodeInstruction, bool>)((CodeInstruction inst) => inst.opcode == OpCodes.Ldfld), (string)null),
					new CodeMatch((Func<CodeInstruction, bool>)((CodeInstruction inst) => CodeInstructionExtensions.LoadsConstant(inst)), (string)null),
					new CodeMatch((Func<CodeInstruction, bool>)((CodeInstruction inst) => CodeInstructionExtensions.Calls(inst, removeAtMethod)), (string)null)
				});
			}
		}

		private static float GetRandomizedMarketPrice(int productID)
		{
			Data_Product component = ProductListing.Instance.productPrefabs[productID].GetComponent<Data_Product>();
			float num = component.basePricePerUnit * ProductListing.Instance.tierInflation[component.productTier];
			if (ModConfig.Instance.EnablePriceGunFix.Value)
			{
				num = RoundPrice(num);
			}
			return num * Random.Range(2f, 2.5f);
		}

		private static float RoundPrice(float value)
		{
			return Mathf.Round(value * 100f) / 100f;
		}
	}
	public class SharedSavePatch : FullyAutoPatchedInstance
	{
		public override bool IsAutoPatchEnabled => Plugin.IsSolutionInDebugMode;

		public override string ErrorMessageOnAutoPatchFail { get; protected set; } = "SuperQoLity - TestAndDebugPatch FAILED. Disabled";


		public override void OnPatchFinishedVirtual(bool IsPatchActive)
		{
			if (IsPatchActive)
			{
				KeyPressDetection.AddHotkey((KeyCode)267, (KeyPressAction)0, 1000, (Action)delegate
				{
					SaveAsClientX();
				});
			}
		}

		public static async void SaveAsClientX()
		{
			LOG.TEMPWARNING("Save started", true);
			if ((Object)(object)NetworkManager.singleton == (Object)null)
			{
				TimeLogger.Logger.LogTimeWarning("You can only save in a loaded world.", (LogCategories)int.MinValue);
			}
			if (((Component)GameData.Instance).GetComponent<NetworkSpawner>().isSaving)
			{
				TimeLogger.Logger.LogTimeWarning("Saving is already in progress.", (LogCategories)int.MinValue);
				return;
			}
			_ = NetworkManager.singleton.mode;
			_ = 2;
			string loadedSaveFileName = FsmVariables.GlobalVariables.GetFsmString("CurrentFilename").Value;
			string value = "StoreFile12.es3";
			LOG.TEMPWARNING("CurrentFilename: " + loadedSaveFileName + " - City save name (host only) " + GetCityName(loadedSaveFileName), true);
			FsmVariables.GlobalVariables.GetFsmString("CurrentFilename").Value = value;
			await SavePersistentValues();
			await SavePropsCoroutine();
			FsmVariables.GlobalVariables.GetFsmString("CurrentFilename").Value = loadedSaveFileName;
		}

		private static string GetCityName(string loadedSaveFileName)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Expected O, but got Unknown
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			string text = Path.Combine(Application.persistentDataPath, loadedSaveFileName);
			ES3Settings val = new ES3Settings((EncryptionType)1, "g#asojrtg@omos)^yq");
			return new ES3File(text, val, false).Load<string>("StoreName", (string)null);
		}

		private static async Task SavePersistentValues()
		{
			LOG.TEMPDEBUG("1. " + FsmVariables.GlobalVariables.GetFsmString("CurrentFilename").Value, true);
			PlayMakerFSM fsm = GameData.Instance.SaveOBJ.GetComponent<PlayMakerFSM>();
			fsm.FsmVariables.GetFsmBool("IsSaving").Value = true;
			LOG.TEMPDEBUG("2. " + FsmVariables.GlobalVariables.GetFsmString("CurrentFilename").Value, true);
			fsm.SendEvent("Send_Data");
			LOG.TEMPDEBUG("3. " + FsmVariables.GlobalVariables.GetFsmString("CurrentFilename").Value, true);
			while (fsm.FsmVariables.GetFsmBool("IsSaving").Value)
			{
				LOG.TEMPDEBUG("4. " + FsmVariables.GlobalVariables.GetFsmString("CurrentFilename").Value, true);
				await Task.Delay(10);
				LOG.TEMPDEBUG("5. " + FsmVariables.GlobalVariables.GetFsmString("CurrentFilename").Value, true);
			}
		}

		public static async Task SavePropsCoroutine()
		{
			NetworkSpawner instance = GameObject.Find("GameDataManager").GetComponent<NetworkSpawner>();
			instance.isSaving = true;
			((Component)((Component)GameCanvas.Instance).transform.Find("SavingContainer")).gameObject.SetActive(true);
			await Task.Delay(500);
			int num = 0;
			string value = FsmVariables.GlobalVariables.GetFsmString("CurrentFilename").Value;
			string text = Application.persistentDataPath + "/" + value;
			LOG.TEMPWARNING("We will save props in file \"" + value + "\"", true);
			ES3Settings val = new ES3Settings((EncryptionType)1, "g#asojrtg@omos)^yq");
			ES3.CacheFile(text, val);
			ES3Settings val2 = new ES3Settings(text, new Enum[1] { (Enum)(object)(Location)4 });
			CultureInfo cultureInfo = new CultureInfo(Thread.CurrentThread.CurrentCulture.Name);
			if (cultureInfo.NumberFormat.NumberDecimalSeparator != ",")
			{
				cultureInfo.NumberFormat.NumberDecimalSeparator = ",";
				Thread.CurrentThread.CurrentCulture = cultureInfo;
			}
			Quaternion rotation;
			for (int i = 0; i < 4; i++)
			{
				GameObject gameObject = ((Component)instance.levelPropsOBJ.transform.GetChild(i)).gameObject;
				if (gameObject.transform.childCount != 0)
				{
					LOG.TEMPWARNING($"Saving {gameObject.transform.childCount} levelPropsOBJ objects for index {i}.", true);
					for (int j = 0; j < gameObject.transform.childCount; j++)
					{
						GameObject gameObject2 = ((Component)gameObject.transform.GetChild(j)).gameObject;
						string[] obj = new string[11]
						{
							i.ToString(),
							"|",
							gameObject2.GetComponent<Data_Container>().containerID.ToString(),
							"|",
							gameObject2.transform.position.x.ToString(),
							"|",
							gameObject2.transform.position.y.ToString(),
							"|",
							gameObject2.transform.position.z.ToString(),
							"|",
							null
						};
						rotation = gameObject2.transform.rotation;
						obj[10] = ((Quaternion)(ref rotation)).eulerAngles.y.ToString();
						string text2 = string.Concat(obj);
						ES3.Save<string>("propdata" + num, text2, text, val2);
						string text3 = "propinfoproduct" + num;
						int[] productInfoArray = gameObject2.GetComponent<Data_Container>().productInfoArray;
						ES3.Save<int[]>(text3, productInfoArray, text, val2);
						num++;
					}
				}
			}
			for (int k = num; (float)k < float.PositiveInfinity; k++)
			{
				string text4 = "propdata" + num;
				if (!ES3.KeyExists(text4, text, val2))
				{
					break;
				}
				ES3.DeleteKey(text4, text, val2);
			}
			num = 0;
			int num2 = 0;
			GameObject gameObject3 = ((Component)instance.levelPropsOBJ.transform.GetChild(7)).gameObject;
			for (int l = 0; (float)l < float.PositiveInfinity; l++)
			{
				string text5 = "decopropdata" + num2;
				if (!ES3.KeyExists(text5, text, val2))
				{
					break;
				}
				ES3.DeleteKey(text5, text, val2);
				num2++;
			}
			LOG.TEMPWARNING($"Saving {gameObject3.transform.childCount} decorative objects.", true);
			for (int m = 0; m < gameObject3.transform.childCount; m++)
			{
				GameObject gameObject4 = ((Component)gameObject3.transform.GetChild(m)).gameObject;
				string[] obj2 = new string[10]
				{
					"7|",
					gameObject4.GetComponent<BuildableInfo>().decorationID.ToString(),
					"|",
					gameObject4.transform.position.x.ToString(),
					"|",
					gameObject4.transform.position.y.ToString(),
					"|",
					gameObject4.transform.position.z.ToString(),
					"|",
					null
				};
				rotation = gameObject4.transform.rotation;
				obj2[9] = ((Quaternion)(ref rotation)).eulerAngles.y.ToString();
				string text6 = string.Concat(obj2);
				ES3.Save<string>("decopropdata" + num, text6, text, val2);
				if (gameObject4.GetComponent<BuildableInfo>().decorationID == 4)
				{
					string text7 = "decopropdataextra" + num;
					string text8 = gameObject4.GetComponent<DecorationExtraData>().intValue + "|" + gameObject4.GetComponent<DecorationExtraData>().stringValue;
					ES3.Save<string>(text7, text8, text, val2);
				}
				if (Object.op_Implicit((Object)(object)gameObject4.GetComponent<PaintableDecoration>()))
				{
					string text9 = "decopaintabledata" + num;
					string text10 = gameObject4.GetComponent<PaintableDecoration>().mainValue + "|" + gameObject4.GetComponent<PaintableDecoration>().secondaryValue;
					ES3.Save<string>(text9, text10, text, val2);
				}
				num++;
			}
			ES3.StoreCachedFile(text, val);
			await Task.Delay(20);
			((Component)((Component)GameCanvas.Instance).transform.Find("SavingContainer")).gameObject.SetActive(false);
			LOG.TEMPWARNING("Prop saving finished.", true);
			instance.isSaving = false;
		}
	}
}
namespace SuperQoLity.SuperMarket.Patches.EmployeeModule
{
	public enum EmployeeJob
	{
		Unassigned = 0,
		Cashier = 1,
		Restocker = 2,
		Storage = 3,
		Security = 4,
		Technician = 5,
		OnlineOrder = 6,
		Manufacturer = 7,
		Any = 99
	}
	public enum EnumSecurityPickUp
	{
		[Description("Disabled")]
		Disabled,
		[Description("Reduced")]
		Reduced,
		[Description("Normal")]
		Normal,
		[Description("Always Maxed")]
		AlwaysMaxed
	}
	public enum EnumSecurityEmployeeThiefChase
	{
		[Description("Disabled")]
		Disabled,
		[Description("AllChaseButLastOne")]
		AllChaseButLastOne,
		[Description("OnlyOnePerThief")]
		OnlyOnePerThief
	}
	public class EmployeeJobAIPatch : FullyAutoPatchedInstance
	{
		[CompilerGenerated]
		private sealed class <PickupMarkedStolenProductsLoop>d__27 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public EmployeeJobAIPatch <>4__this;

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

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

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

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

			private bool MoveNext()
			{
				int num = <>1__state;
				EmployeeJobAIPatch employeeJobAIPatch = <>4__this;
				if (num != 0)
				{
					if (num != 1)
					{
						return false;
					}
					<>1__state = -1;
					if (WorldState.CurrentGameWorldState == GameWorldEvent.QuitOrMenu)
					{
						stolenProdPickups.Clear();
						return false;
					}
				}
				else
				{
					<>1__state = -1;
				}
				employeeJobAIPatch.destroyCounter += 5f;
				StolenProductSpawn val = default(StolenProductSpawn);
				while (employeeJobAIPatch.destroyCounter >= 1f)
				{
					employeeJobAIPatch.destroyCounter -= 1f;
					if (stolenProdPickups.Count <= 0)
					{
						break;
					}
					if (Extensions.TryDequeue<StolenProductSpawn>(stolenProdPickups, ref val))
					{
						NetworkServer.UnSpawn(((Component)val).gameObject);
					}
				}
				<>2__current = null;
				<>1__state = 1;
				return true;
			}

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

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

		public const bool LogEmployeeActions = false;

		private float destroyCounter;

		private static Queue<StolenProductSpawn> stolenProdPickups;

		public override bool IsAutoPatchEnabled => ModConfig.Instance.EnableEmployeeChanges.Value;

		public override string ErrorMessageOnAutoPatchFail { get; protected set; } = "SuperQoLity - Employee patch failed. Employee Module inactive";


		public static int NumTransferItemsBase { get; } = 1;


		public static int MaxSecurityPickUpLevel { get; } = 200;


		public static float SecurityPickUpRangeLevelMult { get; } = 1.25f;


		public static int SecurityPickUpLayer { get; } = 25;


		public static float LevelsForExtraPickUp { get; } = 10f;


		[HarmonyPatch(typeof(NPC_Manager), "Awake")]
		[HarmonyPostfix]
		public static void AwakePatch(NPC_Manager __instance)
		{
			stolenProdPickups = new Queue<StolenProductSpawn>();
			GenericNPC.AddSuperQolNpcObjects(__instance.npcAgentPrefab, NPCType.Employee);
			GameObject npcAgentPrefab = __instance.npcAgentPrefab;
			GameObject val = ((npcAgentPrefab == null) ? null : npcAgentPrefab.GetComponent<NPC_Info>()?.stolenProductPrefab);
			if (!Object.op_Implicit((Object)(object)val))
			{
				TimeLogger.Logger.LogTimeFatal("An object in the chain \"NPC_Manager.npcAgentPrefab.NPC_Info.stolenProductPrefab\" is null. It was probably renamed of changed places. The employee patches cant be used and will be disabled.", (LogCategories)134217728);
				((AutoPatchedInstanceBase)Container<EmployeeJobAIPatch>.Instance).UnpatchInstance();
				TimeLogger.Logger.SendMessageNotificationError("Something changed due to a game update and the employee module can no longer work. It was disabled so the rest of the mod can still work");
			}
			else
			{
				val.layer = SecurityPickUpLayer;
				((MonoBehaviour)__instance).StartCoroutine(Container<EmployeeJobAIPatch>.Instance.PickupMarkedStolenProductsLoop());
			}
		}

		public static bool EmployeeNPCControl(NPC_Manager __instance, GameObject employeeObj, NPC_Info employee)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_27ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_0672: Unknown result type (might be due to invalid IL or missing references)
			//IL_0682: Unknown result type (might be due to invalid IL or missing references)
			//IL_0ed6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0efe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0f03: Unknown result type (might be due to invalid IL or missing references)
			//IL_0f08: Unknown result type (might be due to invalid IL or missing references)
			//IL_0f14: Unknown result type (might be due to invalid IL or missing references)
			//IL_1339: Unknown result type (might be due to invalid IL or missing references)
			//IL_133e: Unknown result type (might be due to invalid IL or missing references)
			//IL_1585: Unknown result type (might be due to invalid IL or missing references)
			//IL_15ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_15b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_15b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_15c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_167c: Unknown result type (might be due to invalid IL or missing references)
			//IL_168c: Unknown result type (might be due to invalid IL or missing references)
			//IL_2583: Unknown result type (might be due to invalid IL or missing references)
			//IL_258e: Unknown result type (might be due to invalid IL or missing references)
			//IL_1f9b: Unknown result type (might be due to invalid IL or missing references)
			//IL_1fab: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_11e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_1201: Unknown result type (might be due to invalid IL or missing references)
			//IL_120b: Unknown result type (might be due to invalid IL or missing references)
			//IL_121d: Unknown result type (might be due to invalid IL or missing references)
			//IL_1237: Unknown result type (might be due to invalid IL or missing references)
			//IL_1246: Unknown result type (might be due to invalid IL or missing references)
			//IL_2525: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0814: Unknown result type (might be due to invalid IL or missing references)
			//IL_0824: Unknown result type (might be due to invalid IL or missing references)
			//IL_07d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_07dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_07e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_1119: Unknown result type (might be due to invalid IL or missing references)
			//IL_1134: Unknown result type (might be due to invalid IL or missing references)
			//IL_113e: Unknown result type (might be due to invalid IL or missing references)
			//IL_18ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_18f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_1b5a: Unknown result type (might be due to invalid IL or missing references)
			//IL_1b9e: Unknown result type (might be due to invalid IL or missing references)
			//IL_1bae: Unknown result type (might be due to invalid IL or missing references)
			//IL_0149: Unknown result type (might be due to invalid IL or missing references)
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0c89: Unknown result type (might be due to invalid IL or missing references)
			//IL_0d72: Unknown result type (might be due to invalid IL or missing references)
			//IL_0d77: Unknown result type (might be due to invalid IL or missing references)
			//IL_0d7a: Unknown result type (might be due to invalid IL or missing references)
			//IL_1179: Unknown result type (might be due to invalid IL or missing references)
			//IL_1434: Unknown result type (might be due to invalid IL or missing references)
			//IL_1439: Unknown result type (might be due to invalid IL or missing references)
			//IL_143c: Unknown result type (might be due to invalid IL or missing references)
			//IL_1905: Unknown result type (might be due to invalid IL or missing references)
			//IL_1d6f: Unknown result type (might be due to invalid IL or missing references)
			//IL_1d8e: Unknown result type (might be due to invalid IL or missing references)
			//IL_1d98: Unknown result type (might be due to invalid IL or missing references)
			//IL_1daa: Unknown result type (might be due to invalid IL or missing references)
			//IL_1dc4: Unknown result type (might be due to invalid IL or missing references)
			//IL_1dd3: Unknown result type (might be due to invalid IL or missing references)
			//IL_09a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_2279: Unknown result type (might be due to invalid IL or missing references)
			//IL_227e: Unknown result type (might be due to invalid IL or missing references)
			//IL_2281: Unknown result type (might be due to invalid IL or missing references)
			//IL_1f63: Unknown result type (might be due to invalid IL or missing references)
			//IL_2445: Unknown result type (might be due to invalid IL or missing references)
			int state = employee.state;
			if (employee.employeeDismissed)
			{
				if (Vector3.Distance(employeeObj.transform.position, __instance.employeeSpawnpoint.transform.position) < 2f)
				{
					NetworkServer.Destroy(employeeObj);
					return true;
				}
				return false;
			}
			if (__instance.employeesOnRiot)
			{
				if (employee.equippedItem > 0)
				{
					__instance.DropBoxOnGround(employee);
					__instance.UnequipBox(employee);
				}
				if (state != 0)
				{
					employee.state = 0;
				}
				return true;
			}
			if (state == -1)
			{
				return false;
			}
			if (!EmployeeNPC.TryGetEmployeeFrom(employeeObj, out var employeeNPC))
			{
				return true;
			}
			int taskPriority = employee.taskPriority;
			if (taskPriority == 4 && state == 2)
			{
				if (Object.op_Implicit((Object)(object)employee.currentChasedThiefOBJ))
				{
					if (employee.currentChasedThiefOBJ.transform.position.x < -15f || employee.currentChasedThiefOBJ.transform.position.x > 38f || employee.currentChasedThiefOBJ.GetComponent<NPC_Info>().productsIDCarrying.Count == 0)
					{
						employee.state = 0;
						return true;
					}
					if (Vector3.Distance(employeeObj.transform.position, employee.currentChasedThiefOBJ.transform.position) < 2f)
					{
						employeeNPC.MoveEmployeeTo(employeeObj, employee.currentChasedThiefOBJ);
						employee.state = 3;
					}
					else
					{
						employee.CallPathing();
					}
				}
				else
				{
					employee.state = 0;
				}
			}
			NavMeshAgent component = employeeObj.GetComponent<NavMeshAgent>();
			if (IsEmployeeAtDestination(component, out var stoppingDistance))
			{
				employeeNPC.StartLookProcess(RotationSpeedMode.EmployeeTarget);
				switch (taskPriority)
				{
				case 0:
					break;
				case 1:
					switch (state)
					{
					case 0:
					case 1:
					{
						if (employee.equippedItem > 0)
						{
							__instance.DropBoxOnGround(employee);
							UnequipBox(employee);
							return true;
						}
						int num13 = __instance.CashierGetAvailableCheckout();
						if (num13 != -1)
						{
							employee.employeeAssignedCheckoutIndex = num13;
							__instance.UpdateEmployeeCheckouts();
							GameObject gameObject2 = ((Component)__instance.checkoutOBJ.transform.GetChild(num13)).gameObject;
							employeeNPC.MoveEmployeeTo(((Component)gameObject2.transform.Find("EmployeePosition")).transform.position, gameObject2);
							employee.state = 2;
							return true;
						}
						employee.state = 10;
						return true;
					}
					case 2:
						employee.RPCNotificationAboveHead("NPCemployee0", "");
						employee.StartWaitState(ModConfig.Instance.EmployeeNextActionWait.Value, 3);
						employee.state = -1;
						return true;
					case 3:
						if (__instance.CheckIfCustomerInQueue(employee.employeeAssignedCheckoutIndex))
						{
							if (!((Component)__instance.checkoutOBJ.transform.GetChild(employee.employeeAssignedCheckoutIndex)).GetComponent<Data_Container>().checkoutQueue[0])
							{
								employee.state = 4;
								return true;
							}
							if (((Component)__instance.checkoutOBJ.transform.GetChild(employee.employeeAssignedCheckoutIndex)).GetComponent<Data_Container>().productsLeft > 0)
							{
								employee.state = 5;
								return true;
							}
							employee.state = 4;
							return true;
						}
						if (((Component)__instance.checkoutOBJ.transform.GetChild(employee.employeeAssignedCheckoutIndex)).GetComponent<Data_Container>().isCheckoutClosed)
						{
							employee.employeeAssignedCheckoutIndex = -1;
							employee.state = 0;
							return true;
						}
						employee.state = 4;
						return true;
					case 4:
						employee.StartWaitState(ModConfig.Instance.EmployeeNextActionWait.Value, 3);
						employee.state = -1;
						return true;
					case 5:
					{
						if (((Component)__instance.checkoutOBJ.transform.GetChild(employee.employeeAssignedCheckoutIndex)).GetComponent<Data_Container>().productsLeft == 0)
						{
							employee.state = 7;
							return true;
						}
						float num12 = Mathf.Clamp(__instance.productCheckoutWait - (float)employee.cashierLevel * 0.01f, 0.05f, 1f);
						employee.StartWaitState(num12, 6);
						employee.state = -1;
						return true;
					}
					case 6:
					{
						List<GameObject> internalProductListForEmployees = ((Component)__instance.checkoutOBJ.transform.GetChild(employee.employeeAssignedCheckoutIndex)).GetComponent<Data_Container>().internalProductListForEmployees;
						int num8 = employee.cashierLevel / 15;
						num8 = Mathf.Clamp(num8, 1, 10);
						int num9 = Mathf.Clamp(employee.cashierValue - num8 - 1, 2, 10);
						int num10 = 0;
						for (int m = 0; m < internalProductListForEmployees.Count; m++)
						{
							GameObject val10 = internalProductListForEmployees[m];
							if (Object.op_Implicit((Object)(object)val10))
							{
								NPC_Info obj6 = employee;
								obj6.cashierExperience += num9;
								val10.GetComponent<ProductCheckoutSpawn>().AddProductFromNPCEmployee();
								num10++;
								if (num10 >= num8)
								{
									break;
								}
							}
						}
						employee.state = 5;
						return true;
					}
					case 7:
					{
						GameObject currentNPC = ((Component)__instance.checkoutOBJ.transform.GetChild(employee.employeeAssignedCheckoutIndex)).GetComponent<Data_Container>().currentNPC;
						if (!Object.op_Implicit((Object)(object)currentNPC))
						{
							employee.state = 3;
						}
						if (currentNPC.GetComponent<NPC_Info>().alreadyGaveMoney)
						{
							((Component)__instance.checkoutOBJ.transform.GetChild(employee.employeeAssignedCheckoutIndex)).GetComponent<Data_Container>().AuxReceivePayment(0f, true);
							employee.state = 3;
							return true;
						}
						float num11 = Mathf.Clamp(__instance.productCheckoutWait - (float)employee.cashierLevel * 0.01f, 0.05f, 1f);
						employee.StartWaitState(num11, 7);
						employee.state = -1;
						return true;
					}
					case 10:
						if (Vector3.Distance(((Component)employee).transform.position, __instance.restSpotOBJ.transform.position) > 3f)
						{
							employeeNPC.MoveEmployeeToRestPosition();
							return true;
						}
						employee.StartWaitState(ModConfig.Instance.EmployeeIdleWait.Value, 0);
						employee.state = -1;
						return true;
					default:
						employee.state = 0;
						return true;
					}
				case 2:
					switch (state)
					{
					case 0:
					{
						LOG.TEMPDEBUG_FUNC((Func<string>)(() => "Restocker #" + GetUniqueId(employee) + " logic begin."), false);
						if (employee.equippedItem > 0)
						{
							LOG.TEMPDEBUG_FUNC((Func<string>)(() => "Restocker #" + GetUniqueId(employee) + ": Box in hand. Dropping."), false);
							__instance.DropBoxOnGround(employee);
							UnequipBox(employee);
							return true;
						}
						RestockJobInfo restockJob;
						bool availableRestockJob = RestockJobsManager.GetAvailableRestockJob(__instance, out restockJob);
						employee.SetRestockJobInfo(restockJob);
						if (availableRestockJob)
						{
							LOG.TEMPDEBUG_FUNC((Func<string>)(() => "Restocker #" + GetUniqueId(employee) + ": Products available, moving to storage."), false);
							Vector3 position2 = ((Component)__instance.storageOBJ.transform.GetChild(restockJob.Storage.ShelfIndex).Find("Standspot")).transform.position;
							employeeNPC.MoveEmployeeToStorage(position2, restockJob.Storage);
							employeeNPC.AddExtraProductShelfTarget(restockJob.ProdShelf);
							employee.state = 2;
							return true;
						}
						if (Vector3.Distance(((Component)employee).transform.position, __instance.restSpotOBJ.transform.position) > 6.5f)
						{
							LOG.TEMPDEBUG_FUNC((Func<string>)(() => "Restocker #" + GetUniqueId(employee) + ": Moving to rest spot."), false);
							employeeNPC.MoveEmployeeToRestPosition();
							return true;
						}
						employeeNPC.ClearNPCReservations();
						employee.StartWaitState(ModConfig.Instance.EmployeeIdleWait.Value, 0);
						employee.state = -1;
						return true;
					}
					case 1:
						return true;
					case 2:
					{
						LOG.TEMPDEBUG_FUNC((Func<string>)(() => "Restocker #" + GetUniqueId(employee) + ": Storage reached."), false);
						RestockJobInfo restockJobInfo2 = employee.GetRestockJobInfo();
						if (employeeNPC.RefreshAndCheckValidTargetedStorage(__instance, clearReservation: false, out var storageSlotInfo4) && employeeNPC.RefreshAndCheckValidTargetedProductShelf(__instance, restockJobInfo2))
						{
							LOG.TEMPDEBUG_FUNC((Func<string>)(() => "Restocker #" + GetUniqueId(employee) + ": Picking box."), false);
							Transform child = __instance.storageOBJ.transform.GetChild(storageSlotInfo4.ShelfIndex);
							Data_Container component4 = ((Component)child).GetComponent<Data_Container>();
							if (Object.op_Implicit((Object)(object)child.Find("CanvasSigns")))
							{
								component4.EmployeeUpdateArrayValuesStorage(storageSlotInfo4.SlotIndex * 2, storageSlotInfo4.ExtraData.ProductId, -1);
							}
							else
							{
								component4.EmployeeUpdateArrayValuesStorage(storageSlotInfo4.SlotIndex * 2, -1, -1);
							}
							employee.NetworkboxProductID = storageSlotInfo4.ExtraData.ProductId;
							employee.NetworkboxNumberOfProducts = storageSlotInfo4.ExtraData.Quantity;
							employee.EquipNPCItem(1);
							GameObject gameObject = ((Component)__instance.shelvesOBJ.transform.GetChild(restockJobInfo2.ProdShelf.ShelfIndex)).gameObject;
							employeeNPC.MoveEmployeeToShelf(((Component)gameObject.transform.Find("Standspot")).transform.position, restockJobInfo2.ProdShelf);
							employee.state = 3;
							return true;
						}
						LOG.TEMPDEBUG_FUNC((Func<string>)(() => "Restocker #" + GetUniqueId(employee) + ": Either storage or shelf reservations didnt match."), false);
						employee.StartWaitState(ModConfig.Instance.EmployeeNextActionWait.Value, 0);
						employee.state = -1;
						return true;
					}
					case 3:
					{
						LOG.TEMPDEBUG_FUNC((Func<string>)(() => "Restocker #" + GetUniqueId(employee) + ": Product shelf reached."), false);
						RestockJobInfo restockJobInfo3 = employee.GetRestockJobInfo();
						if (((Component)__instance.shelvesOBJ.transform.GetChild(restockJobInfo3.ProdShelf.ShelfIndex)).GetComponent<Data_Container>().productInfoArray[restockJobInfo3.ShelfProdInfoIndex] == restockJobInfo3.ProdShelf.ExtraData.ProductId)
						{
							LOG.TEMPDEBUG_FUNC((Func<string>)(() => "Restocker #" + GetUniqueId(employee) + ": Shelf reached has same product as box. So far so good."), false);
							employee.state = 4;
							return true;
						}
						LOG.TEMPDEBUG_FUNC((Func<string>)(() => "Restocker #" + GetUniqueId(employee) + ": Shelf reached has now different product than box."), false);
						employee.state = 5;
						return true;
					}
					case 4:
					{
						LOG.TEMPDEBUG_FUNC((Func<string>)(() => "Restocker #" + GetUniqueId(employee) + ": Checking if shelf is valid."), false);
						RestockJobInfo restockJobInfo = employee.GetRestockJobInfo();
						if (employeeNPC.RefreshAndCheckValidTargetedProductShelf(__instance, restockJobInfo))
						{
							LOG.TEMPDEBUG_FUNC((Func<string>)(() => "Restocker #" + GetUniqueId(employee) + ": Shelf reached fully valid."), false);
							Data_Container component3 = ((Component)__instance.shelvesOBJ.transform.GetChild(restockJobInfo.ProdShelf.ShelfIndex)).GetComponent<Data_Container>();
							int maxProductsPerRow = restockJobInfo.MaxProductsPerRow;
							int quantity = restockJobInfo.ProdShelf.ExtraData.Quantity;
							if (employee.NetworkboxNumberOfProducts > 0 && quantity < maxProductsPerRow)
							{
								LOG.TEMPDEBUG_FUNC((Func<string>)(() => "Restocker #" + GetUniqueId(employee) + ": Adding products to shelf row."), false);
								int num = Mathf.Clamp(maxProductsPerRow - quantity, NumTransferItemsBase, employee.restockerLevel);
								int num2 = Mathf.Clamp(employee.boxNumberOfProducts, NumTransferItemsBase, employee.restockerLevel);
								int numMovedProducts = Mathf.Min(num, num2);
								numMovedProducts = IncreasedItemTransferPatch.GetNumTransferItems(employee.boxNumberOfProducts, quantity, maxProductsPerRow, IncreasedItemTransferPatch.CharacterType.Employee, numMovedProducts);
								component3.EmployeeAddsItemToRow(restockJobInfo.ShelfProdInfoIndex, numMovedProducts);
								employee.NetworkboxNumberOfProducts = employee.boxNumberOfProducts - numMovedProducts;
								employee.StartWaitState(__instance.employeeItemPlaceWait, 4);
								employee.state = -1;
								NPC_Info obj2 = employee;
								obj2.restockerExperience += employee.restockerValue;
								return true;
							}
						}
						LOG.TEMPDEBUG_FUNC((Func<string>)(() => "Restocker #" + GetUniqueId(employee) + ": Target shelf is already full or not valid. Searching for a different one."), false);
						int productId = restockJobInfo.ProdShelf.ExtraData.ProductId;
						if (employee.NetworkboxNumberOfProducts > 0 && ContainerSearch.CheckIfProdShelfWithSameProduct(__instance, productId, employee, out (ProductShelfSlotInfo, int) result))
						{
							LOG.TEMPDEBUG_FUNC((Func<string>)(() => "Restocker #" + GetUniqueId(employee) + ": Found another different shelf to add products."), false);
							employee.UpdateRestockJobInfo(result.Item1, result.Item2);
							employeeNPC.MoveEmployeeToShelf(result.Item1.ExtraData.Position, result.Item1);
							employee.state = 3;
							return true;
						}
						LOG.TEMPDEBUG_FUNC((Func<string>)(() => "Restocker #" + GetUniqueId(employee) + ": Box is empty or there is no other shelf with the same product."), false);
						employee.state = 5;
						return true;
					}
					case 5:
					{
						LOG.TEMPDEBUG_FUNC((Func<string>)(() => "Restocker #" + GetUniqueId(employee) + ": Box in hand but cant restock anymore. Deciding what to do."), false);
						if (employee.NetworkboxNumberOfProducts <= 0)
						{
							MoveToBalerOrGarbageContainer(__instance, employeeObj, employee, employeeNPC, 30, 6, 9);
							return true;
						}
						if (GetStorageContainerWithBoxToMerge(__instance, employee, employeeNPC))
						{
							return true;
						}
						StorageSlotInfo freeStorageContainer = ContainerSearch.GetFreeStorageContainer(__instance, employeeObj.transform, employee.NetworkboxProductID);
						if (freeStorageContainer.ShelfFound)
						{
							LOG.TEMPDEBUG_FUNC((Func<string>)(() => "Restocker #" + GetUniqueId(employee) + ": Moving to storage to place box."), false);
							Vector3 position = ((Component)((Component)__instance.storageOBJ.transform.GetChild(freeStorageContainer.ShelfIndex)).gameObject.transform.Find("Standspot")).transform.position;
							employeeNPC.MoveEmployeeToStorage(position, freeStorageContainer);
							employee.state = 7;
							return true;
						}
						LOG.TEMPDEBUG_FUNC((Func<string>)(() => "Restocker #" + GetUniqueId(employee) + ": Moving to left over boxes spot."), false);
						employeeNPC.MoveEmployeeTo(__instance.leftoverBoxesSpotOBJ, null);
						employee.state = 8;
						return true;
					}
					case 6:
						LOG.TEMPDEBUG_FUNC((Func<string>)(() => "Restocker #" + GetUniqueId(employee) + ": Removing box in hand"), false);
						UnequipBox(employee);
						return true;
					case 7:
					{
						LOG.TEMPDEBUG_FUNC((Func<string>)(() => "Restocker #" + GetUniqueId(employee) + ": Arrived at storage, but checking again if there is some other slot to merge with."), false);
						if (GetStorageContainerWithBoxToMerge(__instance, employee, employeeNPC))
						{
							return true;
						}
						LOG.TEMPDEBUG_FUNC((Func<string>)(() => "Restocker #" + GetUniqueId(employee) + ": No merge possible."), false);
						if (employeeNPC.RefreshAndCheckValidTargetedStorage(__instance, clearReservation: false, out var storageSlotInfo3))
						{
							LOG.TEMPDEBUG_FUNC((Func<string>)(() => "Restocker #" + GetUniqueId(employee) + ": Placing box in storage."), false);
							((Component)__instance.storageOBJ.transform.GetChild(storageSlotInfo3.ShelfIndex)).GetComponent<Data_Container>().EmployeeUpdateArrayValuesStorage(storageSlotInfo3.SlotIndex * 2, employee.NetworkboxProductID, employee.NetworkboxNumberOfProducts);
							employee.state = 6;
							return true;
						}
						LOG.TEMPDEBUG_FUNC((Func<string>)(() => "Restocker #" + GetUniqueId(employee) + ": Target storage is not valid anymore."), false);
						employee.StartWaitState(ModConfig.Instance.EmployeeNextActionWait.Value, 5);
						employee.state = -1;
						return true;
					}
					case 8:
					{
						LOG.TEMPDEBUG_FUNC((Func<string>)(() => "Restocker #" + GetUniqueId(employee) + ": Dropping box at left over spot."), false);
						Vector3 val5 = __instance.leftoverBoxesSpotOBJ.transform.position + new Vector3(Random.Range(-1f, 1f), 4f, Random.Range(-1f, 1f));
						((Component)GameData.Instance).GetComponent<ManagerBlackboard>().SpawnBoxFromEmployee(val5, employee.NetworkboxProductID, employee.NetworkboxNumberOfProducts);
						employee.state = 6;
						return true;
					}
					case 9:
					{
						LOG.TEMPDEBUG_FUNC((Func<string>)(() => "Restocker #" + GetUniqueId(employee) + ": Recycling box."), false);
						float funds2 = 1.5f * (float)((Component)GameData.Instance).GetComponent<UpgradesManager>().boxRecycleFactor;
						AchievementsManager.Instance.CmdAddAchievementPoint(2, 1);
						SMTAntiCheat_Helper.Instance.CmdAlterFunds(funds2);
						employee.state = 6;
						return true;
					}
					case 20:
						LOG.TEMPDEBUG_FUNC((Func<string>)(() => "Restocker #" + GetUniqueId(employee) + ": Reached storage and merging contents."), false);
						EmployeeTryMergeBoxContents(__instance, employee, employeeNPC, 5);
						return true;
					case 30:
						if (Object.op_Implicit((Object)(object)employee.closestCardboardBaler))
						{
							LOG.TEMPDEBUG_FUNC((Func<string>)(() => "Restocker #" + GetUniqueId(employee) + ": Adding empty box to cardboard baler."), false);
							employee.closestCardboardBaler.GetComponent<CardboardBaler>().AuxiliarAddBoxToBaler(employee.boxProductID);
							UnequipBox(employee);
						}
						else
						{
							LOG.TEMPDEBUG_FUNC((Func<string>)(() => "Restocker #" + GetUniqueId(employee) + ": Cardboard baler not there anymore."), false);
							employee.StartWaitState(1f, 0);
							employee.state = -1;
						}
						return true;
					default:
						employee.state = 0;
						return true;
					}
				case 3:
					switch (state)
					{
					case 0:
					{
						LOG.TEMPDEBUG_FUNC((Func<string>)(() => "Storage #" + GetUniqueId(employee) + " logic begin."), false);
						if (employee.equippedItem > 0)
						{
							LOG.TEMPDEBUG_FUNC((Func<string>)(() => "Storage #" + GetUniqueId(employee) + ": Dropping current box."), false);
							__instance.DropBoxOnGround(employee);
							UnequipBox(employee);
							return true;
						}
						GroundBoxStorageTarget closestGroundBox = GroundBoxSearch.GetClosestGroundBox(__instance, employeeObj.transform);
						NavMeshHit val = default(NavMeshHit);
						if (closestGroundBox.FoundGroundBox && NavMesh.SamplePosition(new Vector3(closestGroundBox.GroundBoxObject.transform.position.x, 0f, closestGroundBox.GroundBoxObject.transform.position.z), ref val, 1f, -1))
						{
							LOG.TEMPDEBUG_FUNC((Func<string>)(() => "Storage #" + GetUniqueId(employee) + ": Going to pick up box."), false);
							employee.randomBox = closestGroundBox.GroundBoxObject;
							employeeNPC.MoveEmployeeToBox(((NavMeshHit)(ref val)).position, closestGroundBox.GroundBoxObject);
							if (closestGroundBox.HasStorageTarget)
							{
								employeeNPC.AddExtraStorageTarget(closestGroundBox.StorageSlot);
							}
							employee.state = 1;
							return true;
						}
						employee.state = 10;
						return true;
					}
					case 1:
						if (Object.op_Implicit((Object)(object)employee.randomBox))
						{
							Vector3 val3 = new Vector3(employee.randomBox.transform.position.x, 0f, employee.randomBox.transform.position.z);
							Vector3 val4 = default(Vector3);
							((Vector3)(ref val4))..ctor(((Component)employee).transform.position.x, 0f, ((Component)employee).transform.position.z);
							if (Vector3.Distance(val3, val4) < 2f)
							{
								LOG.TEMPDEBUG_FUNC((Func<string>)(() => "Storage #" + GetUniqueId(employee) + ": Picking up box."), false);
								BoxData component2 = employee.randomBox.GetComponent<BoxData>();
								employee.NetworkboxProductID = component2.productID;
								employee.NetworkboxNumberOfProducts = component2.numberOfProducts;
								employee.EquipNPCItem(1);
								((Component)GameData.Instance).GetComponent<NetworkSpawner>().EmployeeDestroyBox(employee.randomBox);
								if (component2.numberOfProducts > 0)
								{
									employee.state = 18;
									return true;
								}
								employee.state = 6;
								return true;
							}
						}
						LOG.TEMPDEBUG_FUNC((Func<string>)(() => "Storage #" + GetUniqueId(employee) + ": Box doesnt exist or is not at pick up range anymore."), false);
						employee.StartWaitState(ModConfig.Instance.EmployeeNextActionWait.Value, 0);
						employee.state = -1;
						return true;
					case 2:
					{
						StorageSlotInfo storageSlotInfo = null;
						Vector3 zero = Vector3.zero;
						bool validStorageFound = false;
						if (employeeNPC.HasTargetedStorage())
						{
							LOG.TEMPDEBUG_FUNC((Func<string>)(() => "Storage #" + GetUniqueId(employee) + ": Checking pre-reserved storage."), false);
							validStorageFound = employeeNPC.RefreshAndCheckValidTargetedStorage(__instance, clearReservation: true, out storageSlotInfo);
							LOG.TEMPDEBUG_FUNC((Func<string>)(() => "Storage #" + GetUniqueId(employee) + ": Pre-reserved storage is " + (validStorageFound ? "" : "no longer ") + "valid."), false);
						}
						if (!validStorageFound)
						{
							LOG.TEMPDEBUG_FUNC((Func<string>)(() => "Storage #" + GetUniqueId(employee) + ": Searching for storage to place held box."), false);
							storageSlotInfo = ContainerSearch.GetFreeStorageContainer(__instance, employeeObj.transform, employee.NetworkboxProductID);
							validStorageFound = storageSlotInfo.ShelfFound;
							LOG.TEMPDEBUG_FUNC((Func<string>)(() => "Storage #" + GetUniqueId(employee) + ": Free storage " + (validStorageFound ? "" : "couldnt be ") + "found."), false);
						}
						if (validStorageFound)
						{
							LOG.TEMPDEBUG_FUNC((Func<string>)(() => "Storage #" + GetUniqueId(employee) + ": Moving to storage to place box."), false);
							zero = ((Component)__instance.storageOBJ.transform.GetChild(storageSlotInfo.ShelfIndex).Find("Standspot")).transform.position;
							employeeNPC.MoveEmployeeToStorage(zero, storageSlotInfo);
							employee.state = 3;
							return true;
						}
						LOG.TEMPDEBUG_FUNC((Func<string>)(() => "Storage #" + GetUniqueId(employee) + ": Moving to drop box at left over spot."), false);
						employeeNPC.MoveEmployeeTo(__instance.leftoverBoxesSpotOBJ, null);
						employee.state = 4;
						return true;
					}
					case 3:
					{
						LOG.TEMPDEBUG_FUNC((Func<string>)(() => "Storage #" + GetUniqueId(employee) + ": Arrived at storage."), false);
						if (employeeNPC.RefreshAndCheckValidTargetedStorage(__instance, clearReservation: false, out var storageSlotInfo2))
						{
							LOG.TEMPDEBUG_FUNC((Func<string>)(() => "Storage #" + GetUniqueId(employee) + ": Placing box in storage."), false);
							((Component)__instance.storageOBJ.transform.GetChild(storageSlotInfo2.ShelfIndex)).GetComponent<Data_Container>().EmployeeUpdateArrayValuesStorage(storageSlotInfo2.SlotIndex * 2, employee.NetworkboxProductID, employee.NetworkboxNumberOfProducts);
							employee.state = 5;
							NPC_Info obj = employee;
							obj.storageExperience += employee.storageValue;
							return true;
						}
						LOG.TEMPDEBUG_FUNC((Func<string>)(() => "Storage #" + GetUniqueId(employee) + ": Storage no longer valid."), false);
						employee.StartWaitState(ModConfig.Instance.EmployeeNextActionWait.Value, 2);
						employee.state = -1;
						return true;
					}
					case 4:
					{
						LOG.TEMPDEBUG_FUNC((Func<string>)(() => "Storage #" + GetUniqueId(employee) + ": At left over spot. Spawning box at drop."), false);
						Vector3 val2 = __instance.leftoverBoxesSpotOBJ.transform.position + new Vector3(Random.Range(-1f, 1f), 3f, Random.Range(-1f, 1f));
						((Component)GameData.Instance).GetComponent<ManagerBlackboard>().SpawnBoxFromEmployee(val2, employee.NetworkboxProductID, employee.NetworkboxNumberOfProducts);
						employee.state = 5;
						return true;
					}
					case 5:
						LOG.TEMPDEBUG_FUNC((Func<string>)(() => "Storage #" + GetUniqueId(employee) + ": Removing box in hand."), false);
						UnequipBox(employee);
						return true;
					case 6:
						MoveToBalerOrGarbageContainer(__instance, employeeObj, employee, employeeNPC, 33, 5, 7);
						return true;
					case 7:
					{
						LOG.TEMPDEBUG_FUNC((Func<string>)(() => "Storage #" + GetUniqueId(employee) + ": Recycling."), false);
						float funds = 1.5f * (float)((Component)GameData.Instance).GetComponent<UpgradesManager>().boxRecycleFactor;
						AchievementsManager.Instance.CmdAddAchievementPoint(2, 1);
						SMTAntiCheat_Helper.Instance.CmdAlterFunds(funds);
						employee.state = 5;
						return true;
					}
					case 10:
						if ((double)Vector3.Distance(((Component)employee).transform.position, __instance.restSpotOBJ.transform.position) > 6.5)
						{
							LOG.TEMPDEBUG_FUNC((Func<string>)(() => "Storage #" + GetUniqueId(employee) + ": Moving to rest spot."), false);
							employeeNPC.MoveEmployeeToRestPosition();
							return true;
						}
						employeeNPC.ClearNPCReservations();
						employee.StartWaitState(ModConfig.Instance.EmployeeIdleWait.Value, 0);
						employe

BepInEx/plugins/es.damntry.SuperQoLity/UniTask.dll

Decompiled a week ago
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.ExceptionServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using Cysharp.Threading.Tasks.CompilerServices;
using Cysharp.Threading.Tasks.Internal;
using Cysharp.Threading.Tasks.Triggers;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.LowLevel;
using UnityEngine.PlayerLoop;
using UnityEngine.Rendering;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("UniTask")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("UniTask")]
[assembly: AssemblyCopyright("Copyright ©  2024")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("45d5d502-bd1f-4164-8f95-a940087bd189")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: InternalsVisibleTo("UniTask.Linq")]
[assembly: InternalsVisibleTo("UniTask.Addressables")]
[assembly: InternalsVisibleTo("UniTask.DOTween")]
[assembly: InternalsVisibleTo("UniTask.TextMeshPro")]
[assembly: TargetFramework(".NETFramework,Version=v4.8.1", FrameworkDisplayName = ".NET Framework 4.8.1")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace System.Runtime.CompilerServices
{
	internal sealed class AsyncMethodBuilderAttribute : Attribute
	{
		public Type BuilderType { get; }

		public AsyncMethodBuilderAttribute(Type builderType)
		{
			BuilderType = builderType;
		}
	}
}
namespace Cysharp.Threading.Tasks
{
	public class AsyncLazy
	{
		private static Action<object> continuation = SetCompletionSource;

		private Func<UniTask> taskFactory;

		private UniTaskCompletionSource completionSource;

		private UniTask.Awaiter awaiter;

		private object syncLock;

		private bool initialized;

		public UniTask Task
		{
			get
			{
				EnsureInitialized();
				return completionSource.Task;
			}
		}

		public AsyncLazy(Func<UniTask> taskFactory)
		{
			this.taskFactory = taskFactory;
			completionSource = new UniTaskCompletionSource();
			syncLock = new object();
			initialized = false;
		}

		internal AsyncLazy(UniTask task)
		{
			taskFactory = null;
			completionSource = new UniTaskCompletionSource();
			syncLock = null;
			initialized = true;
			UniTask.Awaiter awaiter = task.GetAwaiter();
			if (awaiter.IsCompleted)
			{
				SetCompletionSource(in awaiter);
				return;
			}
			this.awaiter = awaiter;
			awaiter.SourceOnCompleted(continuation, this);
		}

		public UniTask.Awaiter GetAwaiter()
		{
			return Task.GetAwaiter();
		}

		private void EnsureInitialized()
		{
			if (!Volatile.Read(ref initialized))
			{
				EnsureInitializedCore();
			}
		}

		private void EnsureInitializedCore()
		{
			lock (syncLock)
			{
				if (Volatile.Read(ref initialized))
				{
					return;
				}
				Func<UniTask> func = Interlocked.Exchange(ref taskFactory, null);
				if (func != null)
				{
					UniTask.Awaiter awaiter = func().GetAwaiter();
					if (awaiter.IsCompleted)
					{
						SetCompletionSource(in awaiter);
					}
					else
					{
						this.awaiter = awaiter;
						awaiter.SourceOnCompleted(continuation, this);
					}
					Volatile.Write(ref initialized, value: true);
				}
			}
		}

		private void SetCompletionSource(in UniTask.Awaiter awaiter)
		{
			try
			{
				awaiter.GetResult();
				completionSource.TrySetResult();
			}
			catch (Exception exception)
			{
				completionSource.TrySetException(exception);
			}
		}

		private static void SetCompletionSource(object state)
		{
			AsyncLazy asyncLazy = (AsyncLazy)state;
			try
			{
				asyncLazy.awaiter.GetResult();
				asyncLazy.completionSource.TrySetResult();
			}
			catch (Exception exception)
			{
				asyncLazy.completionSource.TrySetException(exception);
			}
			finally
			{
				asyncLazy.awaiter = default(UniTask.Awaiter);
			}
		}
	}
	public class AsyncLazy<T>
	{
		private static Action<object> continuation = SetCompletionSource;

		private Func<UniTask<T>> taskFactory;

		private UniTaskCompletionSource<T> completionSource;

		private UniTask<T>.Awaiter awaiter;

		private object syncLock;

		private bool initialized;

		public UniTask<T> Task
		{
			get
			{
				EnsureInitialized();
				return completionSource.Task;
			}
		}

		public AsyncLazy(Func<UniTask<T>> taskFactory)
		{
			this.taskFactory = taskFactory;
			completionSource = new UniTaskCompletionSource<T>();
			syncLock = new object();
			initialized = false;
		}

		internal AsyncLazy(UniTask<T> task)
		{
			taskFactory = null;
			completionSource = new UniTaskCompletionSource<T>();
			syncLock = null;
			initialized = true;
			UniTask<T>.Awaiter awaiter = task.GetAwaiter();
			if (awaiter.IsCompleted)
			{
				SetCompletionSource(in awaiter);
				return;
			}
			this.awaiter = awaiter;
			awaiter.SourceOnCompleted(continuation, this);
		}

		public UniTask<T>.Awaiter GetAwaiter()
		{
			return Task.GetAwaiter();
		}

		private void EnsureInitialized()
		{
			if (!Volatile.Read(ref initialized))
			{
				EnsureInitializedCore();
			}
		}

		private void EnsureInitializedCore()
		{
			lock (syncLock)
			{
				if (Volatile.Read(ref initialized))
				{
					return;
				}
				Func<UniTask<T>> func = Interlocked.Exchange(ref taskFactory, null);
				if (func != null)
				{
					UniTask<T>.Awaiter awaiter = func().GetAwaiter();
					if (awaiter.IsCompleted)
					{
						SetCompletionSource(in awaiter);
					}
					else
					{
						this.awaiter = awaiter;
						awaiter.SourceOnCompleted(continuation, this);
					}
					Volatile.Write(ref initialized, value: true);
				}
			}
		}

		private void SetCompletionSource(in UniTask<T>.Awaiter awaiter)
		{
			try
			{
				T result = awaiter.GetResult();
				completionSource.TrySetResult(result);
			}
			catch (Exception exception)
			{
				completionSource.TrySetException(exception);
			}
		}

		private static void SetCompletionSource(object state)
		{
			AsyncLazy<T> asyncLazy = (AsyncLazy<T>)state;
			try
			{
				T result = asyncLazy.awaiter.GetResult();
				asyncLazy.completionSource.TrySetResult(result);
			}
			catch (Exception exception)
			{
				asyncLazy.completionSource.TrySetException(exception);
			}
			finally
			{
				asyncLazy.awaiter = default(UniTask<T>.Awaiter);
			}
		}
	}
	public interface IReadOnlyAsyncReactiveProperty<T> : IUniTaskAsyncEnumerable<T>
	{
		T Value { get; }

		IUniTaskAsyncEnumerable<T> WithoutCurrent();

		UniTask<T> WaitAsync(CancellationToken cancellationToken = default(CancellationToken));
	}
	public interface IAsyncReactiveProperty<T> : IReadOnlyAsyncReactiveProperty<T>, IUniTaskAsyncEnumerable<T>
	{
		new T Value { get; set; }
	}
	[Serializable]
	public class AsyncReactiveProperty<T> : IAsyncReactiveProperty<T>, IReadOnlyAsyncReactiveProperty<T>, IUniTaskAsyncEnumerable<T>, IDisposable
	{
		private sealed class WaitAsyncSource : IUniTaskSource<T>, IUniTaskSource, ITriggerHandler<T>, ITaskPoolNode<WaitAsyncSource>
		{
			private static Action<object> cancellationCallback;

			private static TaskPool<WaitAsyncSource> pool;

			private WaitAsyncSource nextNode;

			private AsyncReactiveProperty<T> parent;

			private CancellationToken cancellationToken;

			private CancellationTokenRegistration cancellationTokenRegistration;

			private UniTaskCompletionSourceCore<T> core;

			ref WaitAsyncSource ITaskPoolNode<WaitAsyncSource>.NextNode => ref nextNode;

			ITriggerHandler<T> ITriggerHandler<T>.Prev { get; set; }

			ITriggerHandler<T> ITriggerHandler<T>.Next { get; set; }

			static WaitAsyncSource()
			{
				cancellationCallback = CancellationCallback;
				TaskPool.RegisterSizeGetter(typeof(WaitAsyncSource), () => pool.Size);
			}

			private WaitAsyncSource()
			{
			}

			public static IUniTaskSource<T> Create(AsyncReactiveProperty<T> parent, CancellationToken cancellationToken, out short token)
			{
				if (cancellationToken.IsCancellationRequested)
				{
					return AutoResetUniTaskCompletionSource<T>.CreateFromCanceled(cancellationToken, out token);
				}
				if (!pool.TryPop(out var result))
				{
					result = new WaitAsyncSource();
				}
				result.parent = parent;
				result.cancellationToken = cancellationToken;
				if (cancellationToken.CanBeCanceled)
				{
					result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(cancellationCallback, result);
				}
				result.parent.triggerEvent.Add(result);
				token = result.core.Version;
				return result;
			}

			private bool TryReturn()
			{
				core.Reset();
				cancellationTokenRegistration.Dispose();
				cancellationTokenRegistration = default(CancellationTokenRegistration);
				parent.triggerEvent.Remove(this);
				parent = null;
				cancellationToken = default(CancellationToken);
				return pool.TryPush(this);
			}

			private static void CancellationCallback(object state)
			{
				WaitAsyncSource obj = (WaitAsyncSource)state;
				obj.OnCanceled(obj.cancellationToken);
			}

			public T GetResult(short token)
			{
				try
				{
					return core.GetResult(token);
				}
				finally
				{
					TryReturn();
				}
			}

			void IUniTaskSource.GetResult(short token)
			{
				GetResult(token);
			}

			public void OnCompleted(Action<object> continuation, object state, short token)
			{
				core.OnCompleted(continuation, state, token);
			}

			public UniTaskStatus GetStatus(short token)
			{
				return core.GetStatus(token);
			}

			public UniTaskStatus UnsafeGetStatus()
			{
				return core.UnsafeGetStatus();
			}

			public void OnCanceled(CancellationToken cancellationToken)
			{
				core.TrySetCanceled(cancellationToken);
			}

			public void OnCompleted()
			{
				core.TrySetCanceled(CancellationToken.None);
			}

			public void OnError(Exception ex)
			{
				core.TrySetException(ex);
			}

			public void OnNext(T value)
			{
				core.TrySetResult(value);
			}
		}

		private sealed class WithoutCurrentEnumerable : IUniTaskAsyncEnumerable<T>
		{
			private readonly AsyncReactiveProperty<T> parent;

			public WithoutCurrentEnumerable(AsyncReactiveProperty<T> parent)
			{
				this.parent = parent;
			}

			public IUniTaskAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = default(CancellationToken))
			{
				return new Enumerator(parent, cancellationToken, publishCurrentValue: false);
			}
		}

		private sealed class Enumerator : MoveNextSource, IUniTaskAsyncEnumerator<T>, IUniTaskAsyncDisposable, ITriggerHandler<T>
		{
			private static Action<object> cancellationCallback = CancellationCallback;

			private readonly AsyncReactiveProperty<T> parent;

			private readonly CancellationToken cancellationToken;

			private readonly CancellationTokenRegistration cancellationTokenRegistration;

			private T value;

			private bool isDisposed;

			private bool firstCall;

			public T Current => value;

			ITriggerHandler<T> ITriggerHandler<T>.Prev { get; set; }

			ITriggerHandler<T> ITriggerHandler<T>.Next { get; set; }

			public Enumerator(AsyncReactiveProperty<T> parent, CancellationToken cancellationToken, bool publishCurrentValue)
			{
				this.parent = parent;
				this.cancellationToken = cancellationToken;
				firstCall = publishCurrentValue;
				parent.triggerEvent.Add(this);
				if (cancellationToken.CanBeCanceled)
				{
					cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(cancellationCallback, this);
				}
			}

			public UniTask<bool> MoveNextAsync()
			{
				if (firstCall)
				{
					firstCall = false;
					value = parent.Value;
					return CompletedTasks.True;
				}
				completionSource.Reset();
				return new UniTask<bool>(this, completionSource.Version);
			}

			public UniTask DisposeAsync()
			{
				if (!isDisposed)
				{
					isDisposed = true;
					completionSource.TrySetCanceled(cancellationToken);
					parent.triggerEvent.Remove(this);
				}
				return default(UniTask);
			}

			public void OnNext(T value)
			{
				this.value = value;
				completionSource.TrySetResult(result: true);
			}

			public void OnCanceled(CancellationToken cancellationToken)
			{
				DisposeAsync().Forget();
			}

			public void OnCompleted()
			{
				completionSource.TrySetResult(result: false);
			}

			public void OnError(Exception ex)
			{
				completionSource.TrySetException(ex);
			}

			private static void CancellationCallback(object state)
			{
				((Enumerator)state).DisposeAsync().Forget();
			}
		}

		private TriggerEvent<T> triggerEvent;

		[SerializeField]
		private T latestValue;

		private static bool isValueType;

		public T Value
		{
			get
			{
				return latestValue;
			}
			set
			{
				latestValue = value;
				triggerEvent.SetResult(value);
			}
		}

		public AsyncReactiveProperty(T value)
		{
			latestValue = value;
			triggerEvent = default(TriggerEvent<T>);
		}

		public IUniTaskAsyncEnumerable<T> WithoutCurrent()
		{
			return new WithoutCurrentEnumerable(this);
		}

		public IUniTaskAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken)
		{
			return new Enumerator(this, cancellationToken, publishCurrentValue: true);
		}

		public void Dispose()
		{
			triggerEvent.SetCompleted();
		}

		public static implicit operator T(AsyncReactiveProperty<T> value)
		{
			return value.Value;
		}

		public override string ToString()
		{
			if (isValueType)
			{
				return latestValue.ToString();
			}
			return latestValue?.ToString();
		}

		public UniTask<T> WaitAsync(CancellationToken cancellationToken = default(CancellationToken))
		{
			short token;
			return new UniTask<T>(WaitAsyncSource.Create(this, cancellationToken, out token), token);
		}

		static AsyncReactiveProperty()
		{
			isValueType = typeof(T).IsValueType;
		}
	}
	public class ReadOnlyAsyncReactiveProperty<T> : IReadOnlyAsyncReactiveProperty<T>, IUniTaskAsyncEnumerable<T>, IDisposable
	{
		private sealed class WaitAsyncSource : IUniTaskSource<T>, IUniTaskSource, ITriggerHandler<T>, ITaskPoolNode<WaitAsyncSource>
		{
			private static Action<object> cancellationCallback;

			private static TaskPool<WaitAsyncSource> pool;

			private WaitAsyncSource nextNode;

			private ReadOnlyAsyncReactiveProperty<T> parent;

			private CancellationToken cancellationToken;

			private CancellationTokenRegistration cancellationTokenRegistration;

			private UniTaskCompletionSourceCore<T> core;

			ref WaitAsyncSource ITaskPoolNode<WaitAsyncSource>.NextNode => ref nextNode;

			ITriggerHandler<T> ITriggerHandler<T>.Prev { get; set; }

			ITriggerHandler<T> ITriggerHandler<T>.Next { get; set; }

			static WaitAsyncSource()
			{
				cancellationCallback = CancellationCallback;
				TaskPool.RegisterSizeGetter(typeof(WaitAsyncSource), () => pool.Size);
			}

			private WaitAsyncSource()
			{
			}

			public static IUniTaskSource<T> Create(ReadOnlyAsyncReactiveProperty<T> parent, CancellationToken cancellationToken, out short token)
			{
				if (cancellationToken.IsCancellationRequested)
				{
					return AutoResetUniTaskCompletionSource<T>.CreateFromCanceled(cancellationToken, out token);
				}
				if (!pool.TryPop(out var result))
				{
					result = new WaitAsyncSource();
				}
				result.parent = parent;
				result.cancellationToken = cancellationToken;
				if (cancellationToken.CanBeCanceled)
				{
					result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(cancellationCallback, result);
				}
				result.parent.triggerEvent.Add(result);
				token = result.core.Version;
				return result;
			}

			private bool TryReturn()
			{
				core.Reset();
				cancellationTokenRegistration.Dispose();
				cancellationTokenRegistration = default(CancellationTokenRegistration);
				parent.triggerEvent.Remove(this);
				parent = null;
				cancellationToken = default(CancellationToken);
				return pool.TryPush(this);
			}

			private static void CancellationCallback(object state)
			{
				WaitAsyncSource obj = (WaitAsyncSource)state;
				obj.OnCanceled(obj.cancellationToken);
			}

			public T GetResult(short token)
			{
				try
				{
					return core.GetResult(token);
				}
				finally
				{
					TryReturn();
				}
			}

			void IUniTaskSource.GetResult(short token)
			{
				GetResult(token);
			}

			public void OnCompleted(Action<object> continuation, object state, short token)
			{
				core.OnCompleted(continuation, state, token);
			}

			public UniTaskStatus GetStatus(short token)
			{
				return core.GetStatus(token);
			}

			public UniTaskStatus UnsafeGetStatus()
			{
				return core.UnsafeGetStatus();
			}

			public void OnCanceled(CancellationToken cancellationToken)
			{
				core.TrySetCanceled(cancellationToken);
			}

			public void OnCompleted()
			{
				core.TrySetCanceled(CancellationToken.None);
			}

			public void OnError(Exception ex)
			{
				core.TrySetException(ex);
			}

			public void OnNext(T value)
			{
				core.TrySetResult(value);
			}
		}

		private sealed class WithoutCurrentEnumerable : IUniTaskAsyncEnumerable<T>
		{
			private readonly ReadOnlyAsyncReactiveProperty<T> parent;

			public WithoutCurrentEnumerable(ReadOnlyAsyncReactiveProperty<T> parent)
			{
				this.parent = parent;
			}

			public IUniTaskAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = default(CancellationToken))
			{
				return new Enumerator(parent, cancellationToken, publishCurrentValue: false);
			}
		}

		private sealed class Enumerator : MoveNextSource, IUniTaskAsyncEnumerator<T>, IUniTaskAsyncDisposable, ITriggerHandler<T>
		{
			private static Action<object> cancellationCallback = CancellationCallback;

			private readonly ReadOnlyAsyncReactiveProperty<T> parent;

			private readonly CancellationToken cancellationToken;

			private readonly CancellationTokenRegistration cancellationTokenRegistration;

			private T value;

			private bool isDisposed;

			private bool firstCall;

			public T Current => value;

			ITriggerHandler<T> ITriggerHandler<T>.Prev { get; set; }

			ITriggerHandler<T> ITriggerHandler<T>.Next { get; set; }

			public Enumerator(ReadOnlyAsyncReactiveProperty<T> parent, CancellationToken cancellationToken, bool publishCurrentValue)
			{
				this.parent = parent;
				this.cancellationToken = cancellationToken;
				firstCall = publishCurrentValue;
				parent.triggerEvent.Add(this);
				if (cancellationToken.CanBeCanceled)
				{
					cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(cancellationCallback, this);
				}
			}

			public UniTask<bool> MoveNextAsync()
			{
				if (firstCall)
				{
					firstCall = false;
					value = parent.Value;
					return CompletedTasks.True;
				}
				completionSource.Reset();
				return new UniTask<bool>(this, completionSource.Version);
			}

			public UniTask DisposeAsync()
			{
				if (!isDisposed)
				{
					isDisposed = true;
					completionSource.TrySetCanceled(cancellationToken);
					parent.triggerEvent.Remove(this);
				}
				return default(UniTask);
			}

			public void OnNext(T value)
			{
				this.value = value;
				completionSource.TrySetResult(result: true);
			}

			public void OnCanceled(CancellationToken cancellationToken)
			{
				DisposeAsync().Forget();
			}

			public void OnCompleted()
			{
				completionSource.TrySetResult(result: false);
			}

			public void OnError(Exception ex)
			{
				completionSource.TrySetException(ex);
			}

			private static void CancellationCallback(object state)
			{
				((Enumerator)state).DisposeAsync().Forget();
			}
		}

		private TriggerEvent<T> triggerEvent;

		private T latestValue;

		private IUniTaskAsyncEnumerator<T> enumerator;

		private static bool isValueType;

		public T Value => latestValue;

		public ReadOnlyAsyncReactiveProperty(T initialValue, IUniTaskAsyncEnumerable<T> source, CancellationToken cancellationToken)
		{
			latestValue = initialValue;
			ConsumeEnumerator(source, cancellationToken).Forget();
		}

		public ReadOnlyAsyncReactiveProperty(IUniTaskAsyncEnumerable<T> source, CancellationToken cancellationToken)
		{
			ConsumeEnumerator(source, cancellationToken).Forget();
		}

		private async UniTaskVoid ConsumeEnumerator(IUniTaskAsyncEnumerable<T> source, CancellationToken cancellationToken)
		{
			enumerator = source.GetAsyncEnumerator(cancellationToken);
			try
			{
				while (await enumerator.MoveNextAsync())
				{
					T result = (latestValue = enumerator.Current);
					triggerEvent.SetResult(result);
				}
			}
			finally
			{
				await enumerator.DisposeAsync();
				enumerator = null;
			}
		}

		public IUniTaskAsyncEnumerable<T> WithoutCurrent()
		{
			return new WithoutCurrentEnumerable(this);
		}

		public IUniTaskAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken)
		{
			return new Enumerator(this, cancellationToken, publishCurrentValue: true);
		}

		public void Dispose()
		{
			if (enumerator != null)
			{
				enumerator.DisposeAsync().Forget();
			}
			triggerEvent.SetCompleted();
		}

		public static implicit operator T(ReadOnlyAsyncReactiveProperty<T> value)
		{
			return value.Value;
		}

		public override string ToString()
		{
			if (isValueType)
			{
				return latestValue.ToString();
			}
			return latestValue?.ToString();
		}

		public UniTask<T> WaitAsync(CancellationToken cancellationToken = default(CancellationToken))
		{
			short token;
			return new UniTask<T>(WaitAsyncSource.Create(this, cancellationToken, out token), token);
		}

		static ReadOnlyAsyncReactiveProperty()
		{
			isValueType = typeof(T).IsValueType;
		}
	}
	public static class StateExtensions
	{
		public static ReadOnlyAsyncReactiveProperty<T> ToReadOnlyAsyncReactiveProperty<T>(this IUniTaskAsyncEnumerable<T> source, CancellationToken cancellationToken)
		{
			return new ReadOnlyAsyncReactiveProperty<T>(source, cancellationToken);
		}

		public static ReadOnlyAsyncReactiveProperty<T> ToReadOnlyAsyncReactiveProperty<T>(this IUniTaskAsyncEnumerable<T> source, T initialValue, CancellationToken cancellationToken)
		{
			return new ReadOnlyAsyncReactiveProperty<T>(initialValue, source, cancellationToken);
		}
	}
	[StructLayout(LayoutKind.Sequential, Size = 1)]
	public readonly struct AsyncUnit : IEquatable<AsyncUnit>
	{
		public static readonly AsyncUnit Default;

		public override int GetHashCode()
		{
			return 0;
		}

		public bool Equals(AsyncUnit other)
		{
			return true;
		}

		public override string ToString()
		{
			return "()";
		}
	}
	public class CancellationTokenEqualityComparer : IEqualityComparer<CancellationToken>
	{
		public static readonly IEqualityComparer<CancellationToken> Default = new CancellationTokenEqualityComparer();

		public bool Equals(CancellationToken x, CancellationToken y)
		{
			return x.Equals(y);
		}

		public int GetHashCode(CancellationToken obj)
		{
			return obj.GetHashCode();
		}
	}
	public static class CancellationTokenExtensions
	{
		private static readonly Action<object> cancellationTokenCallback = Callback;

		private static readonly Action<object> disposeCallback = DisposeCallback;

		public static CancellationToken ToCancellationToken(this UniTask task)
		{
			CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
			ToCancellationTokenCore(task, cancellationTokenSource).Forget();
			return cancellationTokenSource.Token;
		}

		public static CancellationToken ToCancellationToken(this UniTask task, CancellationToken linkToken)
		{
			if (linkToken.IsCancellationRequested)
			{
				return linkToken;
			}
			if (!linkToken.CanBeCanceled)
			{
				return task.ToCancellationToken();
			}
			CancellationTokenSource cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(new CancellationToken[1] { linkToken });
			ToCancellationTokenCore(task, cancellationTokenSource).Forget();
			return cancellationTokenSource.Token;
		}

		public static CancellationToken ToCancellationToken<T>(this UniTask<T> task)
		{
			return task.AsUniTask().ToCancellationToken();
		}

		public static CancellationToken ToCancellationToken<T>(this UniTask<T> task, CancellationToken linkToken)
		{
			return task.AsUniTask().ToCancellationToken(linkToken);
		}

		private static async UniTaskVoid ToCancellationTokenCore(UniTask task, CancellationTokenSource cts)
		{
			try
			{
				await task;
			}
			catch (Exception ex)
			{
				UniTaskScheduler.PublishUnobservedTaskException(ex);
			}
			cts.Cancel();
			cts.Dispose();
		}

		public static (UniTask, CancellationTokenRegistration) ToUniTask(this CancellationToken cancellationToken)
		{
			if (cancellationToken.IsCancellationRequested)
			{
				return (UniTask.FromCanceled(cancellationToken), default(CancellationTokenRegistration));
			}
			UniTaskCompletionSource uniTaskCompletionSource = new UniTaskCompletionSource();
			return (uniTaskCompletionSource.Task, cancellationToken.RegisterWithoutCaptureExecutionContext(cancellationTokenCallback, uniTaskCompletionSource));
		}

		private static void Callback(object state)
		{
			((UniTaskCompletionSource)state).TrySetResult();
		}

		public static CancellationTokenAwaitable WaitUntilCanceled(this CancellationToken cancellationToken)
		{
			return new CancellationTokenAwaitable(cancellationToken);
		}

		public static CancellationTokenRegistration RegisterWithoutCaptureExecutionContext(this CancellationToken cancellationToken, Action callback)
		{
			bool flag = false;
			if (!ExecutionContext.IsFlowSuppressed())
			{
				ExecutionContext.SuppressFlow();
				flag = true;
			}
			try
			{
				return cancellationToken.Register(callback, useSynchronizationContext: false);
			}
			finally
			{
				if (flag)
				{
					ExecutionContext.RestoreFlow();
				}
			}
		}

		public static CancellationTokenRegistration RegisterWithoutCaptureExecutionContext(this CancellationToken cancellationToken, Action<object> callback, object state)
		{
			bool flag = false;
			if (!ExecutionContext.IsFlowSuppressed())
			{
				ExecutionContext.SuppressFlow();
				flag = true;
			}
			try
			{
				return cancellationToken.Register(callback, state, useSynchronizationContext: false);
			}
			finally
			{
				if (flag)
				{
					ExecutionContext.RestoreFlow();
				}
			}
		}

		public static CancellationTokenRegistration AddTo(this IDisposable disposable, CancellationToken cancellationToken)
		{
			return cancellationToken.RegisterWithoutCaptureExecutionContext(disposeCallback, disposable);
		}

		private static void DisposeCallback(object state)
		{
			((IDisposable)state).Dispose();
		}
	}
	public struct CancellationTokenAwaitable
	{
		public struct Awaiter : ICriticalNotifyCompletion, INotifyCompletion
		{
			private CancellationToken cancellationToken;

			public bool IsCompleted
			{
				get
				{
					if (cancellationToken.CanBeCanceled)
					{
						return cancellationToken.IsCancellationRequested;
					}
					return true;
				}
			}

			public Awaiter(CancellationToken cancellationToken)
			{
				this.cancellationToken = cancellationToken;
			}

			public void GetResult()
			{
			}

			public void OnCompleted(Action continuation)
			{
				UnsafeOnCompleted(continuation);
			}

			public void UnsafeOnCompleted(Action continuation)
			{
				cancellationToken.RegisterWithoutCaptureExecutionContext(continuation);
			}
		}

		private CancellationToken cancellationToken;

		public CancellationTokenAwaitable(CancellationToken cancellationToken)
		{
			this.cancellationToken = cancellationToken;
		}

		public Awaiter GetAwaiter()
		{
			return new Awaiter(cancellationToken);
		}
	}
	public static class CancellationTokenSourceExtensions
	{
		private static readonly Action<object> CancelCancellationTokenSourceStateDelegate = CancelCancellationTokenSourceState;

		private static void CancelCancellationTokenSourceState(object state)
		{
			((CancellationTokenSource)state).Cancel();
		}

		public static IDisposable CancelAfterSlim(this CancellationTokenSource cts, int millisecondsDelay, DelayType delayType = DelayType.DeltaTime, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update)
		{
			return cts.CancelAfterSlim(TimeSpan.FromMilliseconds(millisecondsDelay), delayType, delayTiming);
		}

		public static IDisposable CancelAfterSlim(this CancellationTokenSource cts, TimeSpan delayTimeSpan, DelayType delayType = DelayType.DeltaTime, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update)
		{
			return PlayerLoopTimer.StartNew(delayTimeSpan, periodic: false, delayType, delayTiming, cts.Token, CancelCancellationTokenSourceStateDelegate, cts);
		}

		public static void RegisterRaiseCancelOnDestroy(this CancellationTokenSource cts, Component component)
		{
			cts.RegisterRaiseCancelOnDestroy(component.gameObject);
		}

		public static void RegisterRaiseCancelOnDestroy(this CancellationTokenSource cts, GameObject gameObject)
		{
			gameObject.GetAsyncDestroyTrigger().CancellationToken.RegisterWithoutCaptureExecutionContext(CancelCancellationTokenSourceStateDelegate, cts);
		}
	}
	public static class Channel
	{
		public static Channel<T> CreateSingleConsumerUnbounded<T>()
		{
			return new SingleConsumerUnboundedChannel<T>();
		}
	}
	public abstract class Channel<TWrite, TRead>
	{
		public ChannelReader<TRead> Reader { get; protected set; }

		public ChannelWriter<TWrite> Writer { get; protected set; }

		public static implicit operator ChannelReader<TRead>(Channel<TWrite, TRead> channel)
		{
			return channel.Reader;
		}

		public static implicit operator ChannelWriter<TWrite>(Channel<TWrite, TRead> channel)
		{
			return channel.Writer;
		}
	}
	public abstract class Channel<T> : Channel<T, T>
	{
	}
	public abstract class ChannelReader<T>
	{
		public abstract UniTask Completion { get; }

		public abstract bool TryRead(out T item);

		public abstract UniTask<bool> WaitToReadAsync(CancellationToken cancellationToken = default(CancellationToken));

		public virtual UniTask<T> ReadAsync(CancellationToken cancellationToken = default(CancellationToken))
		{
			if (TryRead(out var item))
			{
				return UniTask.FromResult(item);
			}
			return ReadAsyncCore(cancellationToken);
		}

		private async UniTask<T> ReadAsyncCore(CancellationToken cancellationToken = default(CancellationToken))
		{
			if (await WaitToReadAsync(cancellationToken) && TryRead(out var item))
			{
				return item;
			}
			throw new ChannelClosedException();
		}

		public abstract IUniTaskAsyncEnumerable<T> ReadAllAsync(CancellationToken cancellationToken = default(CancellationToken));
	}
	public abstract class ChannelWriter<T>
	{
		public abstract bool TryWrite(T item);

		public abstract bool TryComplete(Exception error = null);

		public void Complete(Exception error = null)
		{
			if (!TryComplete(error))
			{
				throw new ChannelClosedException();
			}
		}
	}
	public class ChannelClosedException : InvalidOperationException
	{
		public ChannelClosedException()
			: base("Channel is already closed.")
		{
		}

		public ChannelClosedException(string message)
			: base(message)
		{
		}

		public ChannelClosedException(Exception innerException)
			: base("Channel is already closed", innerException)
		{
		}

		public ChannelClosedException(string message, Exception innerException)
			: base(message, innerException)
		{
		}
	}
	internal class SingleConsumerUnboundedChannel<T> : Channel<T>
	{
		private sealed class SingleConsumerUnboundedChannelWriter : ChannelWriter<T>
		{
			private readonly SingleConsumerUnboundedChannel<T> parent;

			public SingleConsumerUnboundedChannelWriter(SingleConsumerUnboundedChannel<T> parent)
			{
				this.parent = parent;
			}

			public override bool TryWrite(T item)
			{
				bool isWaiting;
				lock (parent.items)
				{
					if (parent.closed)
					{
						return false;
					}
					parent.items.Enqueue(item);
					isWaiting = parent.readerSource.isWaiting;
				}
				if (isWaiting)
				{
					parent.readerSource.SingalContinuation();
				}
				return true;
			}

			public override bool TryComplete(Exception error = null)
			{
				lock (parent.items)
				{
					if (parent.closed)
					{
						return false;
					}
					parent.closed = true;
					bool isWaiting = parent.readerSource.isWaiting;
					if (parent.items.Count == 0)
					{
						if (error == null)
						{
							if (parent.completedTaskSource != null)
							{
								parent.completedTaskSource.TrySetResult();
							}
							else
							{
								parent.completedTask = UniTask.CompletedTask;
							}
						}
						else if (parent.completedTaskSource != null)
						{
							parent.completedTaskSource.TrySetException(error);
						}
						else
						{
							parent.completedTask = UniTask.FromException(error);
						}
						if (isWaiting)
						{
							parent.readerSource.SingalCompleted(error);
						}
					}
					parent.completionError = error;
				}
				return true;
			}
		}

		private sealed class SingleConsumerUnboundedChannelReader : ChannelReader<T>, IUniTaskSource<bool>, IUniTaskSource
		{
			private sealed class ReadAllAsyncEnumerable : IUniTaskAsyncEnumerable<T>, IUniTaskAsyncEnumerator<T>, IUniTaskAsyncDisposable
			{
				private readonly Action<object> CancellationCallback1Delegate = CancellationCallback1;

				private readonly Action<object> CancellationCallback2Delegate = CancellationCallback2;

				private readonly SingleConsumerUnboundedChannelReader parent;

				private CancellationToken cancellationToken1;

				private CancellationToken cancellationToken2;

				private CancellationTokenRegistration cancellationTokenRegistration1;

				private CancellationTokenRegistration cancellationTokenRegistration2;

				private T current;

				private bool cacheValue;

				private bool running;

				public T Current
				{
					get
					{
						if (cacheValue)
						{
							return current;
						}
						parent.TryRead(out current);
						return current;
					}
				}

				public ReadAllAsyncEnumerable(SingleConsumerUnboundedChannelReader parent, CancellationToken cancellationToken)
				{
					this.parent = parent;
					cancellationToken1 = cancellationToken;
				}

				public IUniTaskAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = default(CancellationToken))
				{
					if (running)
					{
						throw new InvalidOperationException("Enumerator is already running, does not allow call GetAsyncEnumerator twice.");
					}
					if (cancellationToken1 != cancellationToken)
					{
						cancellationToken2 = cancellationToken;
					}
					if (cancellationToken1.CanBeCanceled)
					{
						cancellationTokenRegistration1 = cancellationToken1.RegisterWithoutCaptureExecutionContext(CancellationCallback1Delegate, this);
					}
					if (cancellationToken2.CanBeCanceled)
					{
						cancellationTokenRegistration2 = cancellationToken2.RegisterWithoutCaptureExecutionContext(CancellationCallback2Delegate, this);
					}
					running = true;
					return this;
				}

				public UniTask<bool> MoveNextAsync()
				{
					cacheValue = false;
					return parent.WaitToReadAsync(CancellationToken.None);
				}

				public UniTask DisposeAsync()
				{
					cancellationTokenRegistration1.Dispose();
					cancellationTokenRegistration2.Dispose();
					return default(UniTask);
				}

				private static void CancellationCallback1(object state)
				{
					ReadAllAsyncEnumerable readAllAsyncEnumerable = (ReadAllAsyncEnumerable)state;
					readAllAsyncEnumerable.parent.SingalCancellation(readAllAsyncEnumerable.cancellationToken1);
				}

				private static void CancellationCallback2(object state)
				{
					ReadAllAsyncEnumerable readAllAsyncEnumerable = (ReadAllAsyncEnumerable)state;
					readAllAsyncEnumerable.parent.SingalCancellation(readAllAsyncEnumerable.cancellationToken2);
				}
			}

			private readonly Action<object> CancellationCallbackDelegate = CancellationCallback;

			private readonly SingleConsumerUnboundedChannel<T> parent;

			private CancellationToken cancellationToken;

			private CancellationTokenRegistration cancellationTokenRegistration;

			private UniTaskCompletionSourceCore<bool> core;

			internal bool isWaiting;

			public override UniTask Completion
			{
				get
				{
					if (parent.completedTaskSource != null)
					{
						return parent.completedTaskSource.Task;
					}
					if (parent.closed)
					{
						return parent.completedTask;
					}
					parent.completedTaskSource = new UniTaskCompletionSource();
					return parent.completedTaskSource.Task;
				}
			}

			public SingleConsumerUnboundedChannelReader(SingleConsumerUnboundedChannel<T> parent)
			{
				this.parent = parent;
			}

			public override bool TryRead(out T item)
			{
				lock (parent.items)
				{
					if (parent.items.Count == 0)
					{
						item = default(T);
						return false;
					}
					item = parent.items.Dequeue();
					if (parent.closed && parent.items.Count == 0)
					{
						if (parent.completionError != null)
						{
							if (parent.completedTaskSource != null)
							{
								parent.completedTaskSource.TrySetException(parent.completionError);
							}
							else
							{
								parent.completedTask = UniTask.FromException(parent.completionError);
							}
						}
						else if (parent.completedTaskSource != null)
						{
							parent.completedTaskSource.TrySetResult();
						}
						else
						{
							parent.completedTask = UniTask.CompletedTask;
						}
					}
				}
				return true;
			}

			public override UniTask<bool> WaitToReadAsync(CancellationToken cancellationToken)
			{
				if (cancellationToken.IsCancellationRequested)
				{
					return UniTask.FromCanceled<bool>(cancellationToken);
				}
				lock (parent.items)
				{
					if (parent.items.Count != 0)
					{
						return CompletedTasks.True;
					}
					if (parent.closed)
					{
						if (parent.completionError == null)
						{
							return CompletedTasks.False;
						}
						return UniTask.FromException<bool>(parent.completionError);
					}
					cancellationTokenRegistration.Dispose();
					core.Reset();
					isWaiting = true;
					this.cancellationToken = cancellationToken;
					if (this.cancellationToken.CanBeCanceled)
					{
						cancellationTokenRegistration = this.cancellationToken.RegisterWithoutCaptureExecutionContext(CancellationCallbackDelegate, this);
					}
					return new UniTask<bool>(this, core.Version);
				}
			}

			public void SingalContinuation()
			{
				core.TrySetResult(result: true);
			}

			public void SingalCancellation(CancellationToken cancellationToken)
			{
				core.TrySetCanceled(cancellationToken);
			}

			public void SingalCompleted(Exception error)
			{
				if (error != null)
				{
					core.TrySetException(error);
				}
				else
				{
					core.TrySetResult(result: false);
				}
			}

			public override IUniTaskAsyncEnumerable<T> ReadAllAsync(CancellationToken cancellationToken = default(CancellationToken))
			{
				return new ReadAllAsyncEnumerable(this, cancellationToken);
			}

			bool IUniTaskSource<bool>.GetResult(short token)
			{
				return core.GetResult(token);
			}

			void IUniTaskSource.GetResult(short token)
			{
				core.GetResult(token);
			}

			UniTaskStatus IUniTaskSource.GetStatus(short token)
			{
				return core.GetStatus(token);
			}

			void IUniTaskSource.OnCompleted(Action<object> continuation, object state, short token)
			{
				core.OnCompleted(continuation, state, token);
			}

			UniTaskStatus IUniTaskSource.UnsafeGetStatus()
			{
				return core.UnsafeGetStatus();
			}

			private static void CancellationCallback(object state)
			{
				SingleConsumerUnboundedChannelReader obj = (SingleConsumerUnboundedChannelReader)state;
				obj.SingalCancellation(obj.cancellationToken);
			}
		}

		private readonly Queue<T> items;

		private readonly SingleConsumerUnboundedChannelReader readerSource;

		private UniTaskCompletionSource completedTaskSource;

		private UniTask completedTask;

		private Exception completionError;

		private bool closed;

		public SingleConsumerUnboundedChannel()
		{
			items = new Queue<T>();
			base.Writer = new SingleConsumerUnboundedChannelWriter(this);
			readerSource = new SingleConsumerUnboundedChannelReader(this);
			base.Reader = readerSource;
		}
	}
	public static class EnumerableAsyncExtensions
	{
		public static IEnumerable<UniTask> Select<T>(this IEnumerable<T> source, Func<T, UniTask> selector)
		{
			return Enumerable.Select(source, selector);
		}

		public static IEnumerable<UniTask<TR>> Select<T, TR>(this IEnumerable<T> source, Func<T, UniTask<TR>> selector)
		{
			return Enumerable.Select(source, selector);
		}

		public static IEnumerable<UniTask> Select<T>(this IEnumerable<T> source, Func<T, int, UniTask> selector)
		{
			return Enumerable.Select(source, selector);
		}

		public static IEnumerable<UniTask<TR>> Select<T, TR>(this IEnumerable<T> source, Func<T, int, UniTask<TR>> selector)
		{
			return Enumerable.Select(source, selector);
		}
	}
	public static class EnumeratorAsyncExtensions
	{
		private sealed class EnumeratorPromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<EnumeratorPromise>
		{
			private static TaskPool<EnumeratorPromise> pool;

			private EnumeratorPromise nextNode;

			private IEnumerator innerEnumerator;

			private CancellationToken cancellationToken;

			private int initialFrame;

			private bool loopRunning;

			private bool calledGetResult;

			private UniTaskCompletionSourceCore<object> core;

			private static readonly FieldInfo waitForSeconds_Seconds;

			public ref EnumeratorPromise NextNode => ref nextNode;

			static EnumeratorPromise()
			{
				waitForSeconds_Seconds = typeof(WaitForSeconds).GetField("m_Seconds", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.GetField);
				TaskPool.RegisterSizeGetter(typeof(EnumeratorPromise), () => pool.Size);
			}

			private EnumeratorPromise()
			{
			}

			public static IUniTaskSource Create(IEnumerator innerEnumerator, PlayerLoopTiming timing, CancellationToken cancellationToken, out short token)
			{
				if (cancellationToken.IsCancellationRequested)
				{
					return AutoResetUniTaskCompletionSource.CreateFromCanceled(cancellationToken, out token);
				}
				if (!pool.TryPop(out var result))
				{
					result = new EnumeratorPromise();
				}
				result.innerEnumerator = ConsumeEnumerator(innerEnumerator);
				result.cancellationToken = cancellationToken;
				result.loopRunning = true;
				result.calledGetResult = false;
				result.initialFrame = -1;
				token = result.core.Version;
				if (result.MoveNext())
				{
					PlayerLoopHelper.AddAction(timing, result);
				}
				return result;
			}

			public void GetResult(short token)
			{
				try
				{
					calledGetResult = true;
					core.GetResult(token);
				}
				finally
				{
					if (!loopRunning)
					{
						TryReturn();
					}
				}
			}

			public UniTaskStatus GetStatus(short token)
			{
				return core.GetStatus(token);
			}

			public UniTaskStatus UnsafeGetStatus()
			{
				return core.UnsafeGetStatus();
			}

			public void OnCompleted(Action<object> continuation, object state, short token)
			{
				core.OnCompleted(continuation, state, token);
			}

			public bool MoveNext()
			{
				if (calledGetResult)
				{
					loopRunning = false;
					TryReturn();
					return false;
				}
				if (innerEnumerator == null)
				{
					return false;
				}
				if (cancellationToken.IsCancellationRequested)
				{
					loopRunning = false;
					core.TrySetCanceled(cancellationToken);
					return false;
				}
				if (initialFrame == -1)
				{
					if (PlayerLoopHelper.IsMainThread)
					{
						initialFrame = Time.frameCount;
					}
				}
				else if (initialFrame == Time.frameCount)
				{
					return true;
				}
				try
				{
					if (innerEnumerator.MoveNext())
					{
						return true;
					}
				}
				catch (Exception error)
				{
					loopRunning = false;
					core.TrySetException(error);
					return false;
				}
				loopRunning = false;
				core.TrySetResult(null);
				return false;
			}

			private bool TryReturn()
			{
				core.Reset();
				innerEnumerator = null;
				cancellationToken = default(CancellationToken);
				return pool.TryPush(this);
			}

			private static IEnumerator ConsumeEnumerator(IEnumerator enumerator)
			{
				while (enumerator.MoveNext())
				{
					object current = enumerator.Current;
					if (current == null)
					{
						yield return null;
						continue;
					}
					CustomYieldInstruction cyi = (CustomYieldInstruction)((current is CustomYieldInstruction) ? current : null);
					if (cyi != null)
					{
						while (cyi.keepWaiting)
						{
							yield return null;
						}
						continue;
					}
					if (current is YieldInstruction)
					{
						IEnumerator innerCoroutine2 = null;
						AsyncOperation val = (AsyncOperation)((current is AsyncOperation) ? current : null);
						if (val == null)
						{
							WaitForSeconds val2 = (WaitForSeconds)((current is WaitForSeconds) ? current : null);
							if (val2 != null)
							{
								innerCoroutine2 = UnwrapWaitForSeconds(val2);
							}
						}
						else
						{
							innerCoroutine2 = UnwrapWaitAsyncOperation(val);
						}
						if (innerCoroutine2 != null)
						{
							while (innerCoroutine2.MoveNext())
							{
								yield return null;
							}
							continue;
						}
					}
					else if (current is IEnumerator enumerator2)
					{
						IEnumerator innerCoroutine2 = ConsumeEnumerator(enumerator2);
						while (innerCoroutine2.MoveNext())
						{
							yield return null;
						}
						continue;
					}
					Debug.LogWarning((object)("yield " + current.GetType().Name + " is not supported on await IEnumerator or IEnumerator.ToUniTask(), please use ToUniTask(MonoBehaviour coroutineRunner) instead."));
					yield return null;
				}
			}

			private static IEnumerator UnwrapWaitForSeconds(WaitForSeconds waitForSeconds)
			{
				float second = (float)waitForSeconds_Seconds.GetValue(waitForSeconds);
				float elapsed = 0f;
				do
				{
					yield return null;
					elapsed += Time.deltaTime;
				}
				while (!(elapsed >= second));
			}

			private static IEnumerator UnwrapWaitAsyncOperation(AsyncOperation asyncOperation)
			{
				while (!asyncOperation.isDone)
				{
					yield return null;
				}
			}
		}

		public static UniTask.Awaiter GetAwaiter<T>(this T enumerator) where T : IEnumerator
		{
			object obj = enumerator;
			Error.ThrowArgumentNullException((IEnumerator)obj, "enumerator");
			short token;
			return new UniTask(EnumeratorPromise.Create((IEnumerator)obj, PlayerLoopTiming.Update, CancellationToken.None, out token), token).GetAwaiter();
		}

		public static UniTask WithCancellation(this IEnumerator enumerator, CancellationToken cancellationToken)
		{
			Error.ThrowArgumentNullException(enumerator, "enumerator");
			short token;
			return new UniTask(EnumeratorPromise.Create(enumerator, PlayerLoopTiming.Update, cancellationToken, out token), token);
		}

		public static UniTask ToUniTask(this IEnumerator enumerator, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
		{
			Error.ThrowArgumentNullException(enumerator, "enumerator");
			short token;
			return new UniTask(EnumeratorPromise.Create(enumerator, timing, cancellationToken, out token), token);
		}

		public static UniTask ToUniTask(this IEnumerator enumerator, MonoBehaviour coroutineRunner)
		{
			AutoResetUniTaskCompletionSource autoResetUniTaskCompletionSource = AutoResetUniTaskCompletionSource.Create();
			coroutineRunner.StartCoroutine(Core(enumerator, coroutineRunner, autoResetUniTaskCompletionSource));
			return autoResetUniTaskCompletionSource.Task;
		}

		private static IEnumerator Core(IEnumerator inner, MonoBehaviour coroutineRunner, AutoResetUniTaskCompletionSource source)
		{
			yield return coroutineRunner.StartCoroutine(inner);
			source.TrySetResult();
		}
	}
	public static class ExceptionExtensions
	{
		public static bool IsOperationCanceledException(this Exception exception)
		{
			return exception is OperationCanceledException;
		}
	}
	public static class TaskTracker
	{
		private static List<KeyValuePair<IUniTaskSource, (string formattedType, int trackingId, DateTime addTime, string stackTrace)>> listPool = new List<KeyValuePair<IUniTaskSource, (string, int, DateTime, string)>>();

		private static readonly WeakDictionary<IUniTaskSource, (string formattedType, int trackingId, DateTime addTime, string stackTrace)> tracking = new WeakDictionary<IUniTaskSource, (string, int, DateTime, string)>();

		private static bool dirty;

		[Conditional("UNITY_EDITOR")]
		public static void TrackActiveTask(IUniTaskSource task, int skipFrame)
		{
		}

		[Conditional("UNITY_EDITOR")]
		public static void RemoveTracking(IUniTaskSource task)
		{
		}

		public static bool CheckAndResetDirty()
		{
			bool result = dirty;
			dirty = false;
			return result;
		}

		public static void ForEachActiveTask(Action<int, string, UniTaskStatus, DateTime, string> action)
		{
			lock (listPool)
			{
				int num = tracking.ToList(ref listPool, clear: false);
				try
				{
					for (int i = 0; i < num; i++)
					{
						action(listPool[i].Value.trackingId, listPool[i].Value.formattedType, listPool[i].Key.UnsafeGetStatus(), listPool[i].Value.addTime, listPool[i].Value.stackTrace);
						listPool[i] = default(KeyValuePair<IUniTaskSource, (string, int, DateTime, string)>);
					}
				}
				catch
				{
					listPool.Clear();
					throw;
				}
			}
		}

		private static void TypeBeautify(Type type, StringBuilder sb)
		{
			if (type.IsNested)
			{
				sb.Append(type.DeclaringType.Name.ToString());
				sb.Append(".");
			}
			if (type.IsGenericType)
			{
				int num = type.Name.IndexOf("`");
				if (num != -1)
				{
					sb.Append(type.Name.Substring(0, num));
				}
				else
				{
					sb.Append(type.Name);
				}
				sb.Append("<");
				bool flag = true;
				Type[] genericArguments = type.GetGenericArguments();
				foreach (Type type2 in genericArguments)
				{
					if (!flag)
					{
						sb.Append(", ");
					}
					flag = false;
					TypeBeautify(type2, sb);
				}
				sb.Append(">");
			}
			else
			{
				sb.Append(type.Name);
			}
		}
	}
	public interface IUniTaskAsyncEnumerable<out T>
	{
		IUniTaskAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = default(CancellationToken));
	}
	public interface IUniTaskAsyncEnumerator<out T> : IUniTaskAsyncDisposable
	{
		T Current { get; }

		UniTask<bool> MoveNextAsync();
	}
	public interface IUniTaskAsyncDisposable
	{
		UniTask DisposeAsync();
	}
	public interface IUniTaskOrderedAsyncEnumerable<TElement> : IUniTaskAsyncEnumerable<TElement>
	{
		IUniTaskOrderedAsyncEnumerable<TElement> CreateOrderedEnumerable<TKey>(Func<TElement, TKey> keySelector, IComparer<TKey> comparer, bool descending);

		IUniTaskOrderedAsyncEnumerable<TElement> CreateOrderedEnumerable<TKey>(Func<TElement, UniTask<TKey>> keySelector, IComparer<TKey> comparer, bool descending);

		IUniTaskOrderedAsyncEnumerable<TElement> CreateOrderedEnumerable<TKey>(Func<TElement, CancellationToken, UniTask<TKey>> keySelector, IComparer<TKey> comparer, bool descending);
	}
	public interface IConnectableUniTaskAsyncEnumerable<out T> : IUniTaskAsyncEnumerable<T>
	{
		IDisposable Connect();
	}
	public static class UniTaskAsyncEnumerableExtensions
	{
		public static UniTaskCancelableAsyncEnumerable<T> WithCancellation<T>(this IUniTaskAsyncEnumerable<T> source, CancellationToken cancellationToken)
		{
			return new UniTaskCancelableAsyncEnumerable<T>(source, cancellationToken);
		}
	}
	[StructLayout(LayoutKind.Auto)]
	public readonly struct UniTaskCancelableAsyncEnumerable<T>
	{
		[StructLayout(LayoutKind.Auto)]
		public readonly struct Enumerator
		{
			private readonly IUniTaskAsyncEnumerator<T> enumerator;

			public T Current => enumerator.Current;

			internal Enumerator(IUniTaskAsyncEnumerator<T> enumerator)
			{
				this.enumerator = enumerator;
			}

			public UniTask<bool> MoveNextAsync()
			{
				return enumerator.MoveNextAsync();
			}

			public UniTask DisposeAsync()
			{
				return enumerator.DisposeAsync();
			}
		}

		private readonly IUniTaskAsyncEnumerable<T> enumerable;

		private readonly CancellationToken cancellationToken;

		internal UniTaskCancelableAsyncEnumerable(IUniTaskAsyncEnumerable<T> enumerable, CancellationToken cancellationToken)
		{
			this.enumerable = enumerable;
			this.cancellationToken = cancellationToken;
		}

		public Enumerator GetAsyncEnumerator()
		{
			return new Enumerator(enumerable.GetAsyncEnumerator(cancellationToken));
		}
	}
	public enum UniTaskStatus
	{
		Pending,
		Succeeded,
		Faulted,
		Canceled
	}
	public interface IUniTaskSource
	{
		UniTaskStatus GetStatus(short token);

		void OnCompleted(Action<object> continuation, object state, short token);

		void GetResult(short token);

		UniTaskStatus UnsafeGetStatus();
	}
	public interface IUniTaskSource<out T> : IUniTaskSource
	{
		new T GetResult(short token);
	}
	public static class UniTaskStatusExtensions
	{
		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static bool IsCompleted(this UniTaskStatus status)
		{
			return status != UniTaskStatus.Pending;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static bool IsCompletedSuccessfully(this UniTaskStatus status)
		{
			return status == UniTaskStatus.Succeeded;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static bool IsCanceled(this UniTaskStatus status)
		{
			return status == UniTaskStatus.Canceled;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static bool IsFaulted(this UniTaskStatus status)
		{
			return status == UniTaskStatus.Faulted;
		}
	}
	public abstract class MoveNextSource : IUniTaskSource<bool>, IUniTaskSource
	{
		protected UniTaskCompletionSourceCore<bool> completionSource;

		public bool GetResult(short token)
		{
			return completionSource.GetResult(token);
		}

		public UniTaskStatus GetStatus(short token)
		{
			return completionSource.GetStatus(token);
		}

		public void OnCompleted(Action<object> continuation, object state, short token)
		{
			completionSource.OnCompleted(continuation, state, token);
		}

		public UniTaskStatus UnsafeGetStatus()
		{
			return completionSource.UnsafeGetStatus();
		}

		void IUniTaskSource.GetResult(short token)
		{
			completionSource.GetResult(token);
		}

		protected bool TryGetResult<T>(UniTask<T>.Awaiter awaiter, out T result)
		{
			try
			{
				result = awaiter.GetResult();
				return true;
			}
			catch (Exception error)
			{
				completionSource.TrySetException(error);
				result = default(T);
				return false;
			}
		}

		protected bool TryGetResult(UniTask.Awaiter awaiter)
		{
			try
			{
				awaiter.GetResult();
				return true;
			}
			catch (Exception error)
			{
				completionSource.TrySetException(error);
				return false;
			}
		}
	}
	public static class UniTaskLoopRunners
	{
		[StructLayout(LayoutKind.Sequential, Size = 1)]
		public struct UniTaskLoopRunnerInitialization
		{
		}

		[StructLayout(LayoutKind.Sequential, Size = 1)]
		public struct UniTaskLoopRunnerEarlyUpdate
		{
		}

		[StructLayout(LayoutKind.Sequential, Size = 1)]
		public struct UniTaskLoopRunnerFixedUpdate
		{
		}

		[StructLayout(LayoutKind.Sequential, Size = 1)]
		public struct UniTaskLoopRunnerPreUpdate
		{
		}

		[StructLayout(LayoutKind.Sequential, Size = 1)]
		public struct UniTaskLoopRunnerUpdate
		{
		}

		[StructLayout(LayoutKind.Sequential, Size = 1)]
		public struct UniTaskLoopRunnerPreLateUpdate
		{
		}

		[StructLayout(LayoutKind.Sequential, Size = 1)]
		public struct UniTaskLoopRunnerPostLateUpdate
		{
		}

		[StructLayout(LayoutKind.Sequential, Size = 1)]
		public struct UniTaskLoopRunnerLastInitialization
		{
		}

		[StructLayout(LayoutKind.Sequential, Size = 1)]
		public struct UniTaskLoopRunnerLastEarlyUpdate
		{
		}

		[StructLayout(LayoutKind.Sequential, Size = 1)]
		public struct UniTaskLoopRunnerLastFixedUpdate
		{
		}

		[StructLayout(LayoutKind.Sequential, Size = 1)]
		public struct UniTaskLoopRunnerLastPreUpdate
		{
		}

		[StructLayout(LayoutKind.Sequential, Size = 1)]
		public struct UniTaskLoopRunnerLastUpdate
		{
		}

		[StructLayout(LayoutKind.Sequential, Size = 1)]
		public struct UniTaskLoopRunnerLastPreLateUpdate
		{
		}

		[StructLayout(LayoutKind.Sequential, Size = 1)]
		public struct UniTaskLoopRunnerLastPostLateUpdate
		{
		}

		[StructLayout(LayoutKind.Sequential, Size = 1)]
		public struct UniTaskLoopRunnerYieldInitialization
		{
		}

		[StructLayout(LayoutKind.Sequential, Size = 1)]
		public struct UniTaskLoopRunnerYieldEarlyUpdate
		{
		}

		[StructLayout(LayoutKind.Sequential, Size = 1)]
		public struct UniTaskLoopRunnerYieldFixedUpdate
		{
		}

		[StructLayout(LayoutKind.Sequential, Size = 1)]
		public struct UniTaskLoopRunnerYieldPreUpdate
		{
		}

		[StructLayout(LayoutKind.Sequential, Size = 1)]
		public struct UniTaskLoopRunnerYieldUpdate
		{
		}

		[StructLayout(LayoutKind.Sequential, Size = 1)]
		public struct UniTaskLoopRunnerYieldPreLateUpdate
		{
		}

		[StructLayout(LayoutKind.Sequential, Size = 1)]
		public struct UniTaskLoopRunnerYieldPostLateUpdate
		{
		}

		[StructLayout(LayoutKind.Sequential, Size = 1)]
		public struct UniTaskLoopRunnerLastYieldInitialization
		{
		}

		[StructLayout(LayoutKind.Sequential, Size = 1)]
		public struct UniTaskLoopRunnerLastYieldEarlyUpdate
		{
		}

		[StructLayout(LayoutKind.Sequential, Size = 1)]
		public struct UniTaskLoopRunnerLastYieldFixedUpdate
		{
		}

		[StructLayout(LayoutKind.Sequential, Size = 1)]
		public struct UniTaskLoopRunnerLastYieldPreUpdate
		{
		}

		[StructLayout(LayoutKind.Sequential, Size = 1)]
		public struct UniTaskLoopRunnerLastYieldUpdate
		{
		}

		[StructLayout(LayoutKind.Sequential, Size = 1)]
		public struct UniTaskLoopRunnerLastYieldPreLateUpdate
		{
		}

		[StructLayout(LayoutKind.Sequential, Size = 1)]
		public struct UniTaskLoopRunnerLastYieldPostLateUpdate
		{
		}

		[StructLayout(LayoutKind.Sequential, Size = 1)]
		public struct UniTaskLoopRunnerTimeUpdate
		{
		}

		[StructLayout(LayoutKind.Sequential, Size = 1)]
		public struct UniTaskLoopRunnerLastTimeUpdate
		{
		}

		[StructLayout(LayoutKind.Sequential, Size = 1)]
		public struct UniTaskLoopRunnerYieldTimeUpdate
		{
		}

		[StructLayout(LayoutKind.Sequential, Size = 1)]
		public struct UniTaskLoopRunnerLastYieldTimeUpdate
		{
		}
	}
	public enum PlayerLoopTiming
	{
		Initialization,
		LastInitialization,
		EarlyUpdate,
		LastEarlyUpdate,
		FixedUpdate,
		LastFixedUpdate,
		PreUpdate,
		LastPreUpdate,
		Update,
		LastUpdate,
		PreLateUpdate,
		LastPreLateUpdate,
		PostLateUpdate,
		LastPostLateUpdate,
		TimeUpdate,
		LastTimeUpdate
	}
	[Flags]
	public enum InjectPlayerLoopTimings
	{
		All = 0xFFFF,
		Standard = 0x7555,
		Minimum = 0x2110,
		Initialization = 1,
		LastInitialization = 2,
		EarlyUpdate = 4,
		LastEarlyUpdate = 8,
		FixedUpdate = 0x10,
		LastFixedUpdate = 0x20,
		PreUpdate = 0x40,
		LastPreUpdate = 0x80,
		Update = 0x100,
		LastUpdate = 0x200,
		PreLateUpdate = 0x400,
		LastPreLateUpdate = 0x800,
		PostLateUpdate = 0x1000,
		LastPostLateUpdate = 0x2000,
		TimeUpdate = 0x4000,
		LastTimeUpdate = 0x8000
	}
	public interface IPlayerLoopItem
	{
		bool MoveNext();
	}
	public static class PlayerLoopHelper
	{
		private static readonly ContinuationQueue ThrowMarkerContinuationQueue;

		private static readonly PlayerLoopRunner ThrowMarkerPlayerLoopRunner;

		private static int mainThreadId;

		private static string applicationDataPath;

		private static SynchronizationContext unitySynchronizationContext;

		private static ContinuationQueue[] yielders;

		private static PlayerLoopRunner[] runners;

		public static SynchronizationContext UnitySynchronizationContext => unitySynchronizationContext;

		public static int MainThreadId => mainThreadId;

		internal static string ApplicationDataPath => applicationDataPath;

		public static bool IsMainThread => Thread.CurrentThread.ManagedThreadId == mainThreadId;

		internal static bool IsEditorApplicationQuitting { get; private set; }

		private static PlayerLoopSystem[] InsertRunner(PlayerLoopSystem loopSystem, bool injectOnFirst, Type loopRunnerYieldType, ContinuationQueue cq, Type loopRunnerType, PlayerLoopRunner runner)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Expected O, but got Unknown
			//IL_0023: 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_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Expected O, but got Unknown
			//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_004e: 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_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: 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_007b: 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_0083: Unknown result type (might be due to invalid IL or missing references)
			PlayerLoopSystem val = default(PlayerLoopSystem);
			val.type = loopRunnerYieldType;
			val.updateDelegate = new UpdateFunction(cq.Run);
			PlayerLoopSystem val2 = val;
			val = default(PlayerLoopSystem);
			val.type = loopRunnerType;
			val.updateDelegate = new UpdateFunction(runner.Run);
			PlayerLoopSystem val3 = val;
			PlayerLoopSystem[] array = RemoveRunner(loopSystem, loopRunnerYieldType, loopRunnerType);
			PlayerLoopSystem[] array2 = (PlayerLoopSystem[])(object)new PlayerLoopSystem[array.Length + 2];
			Array.Copy(array, 0, array2, injectOnFirst ? 2 : 0, array.Length);
			if (injectOnFirst)
			{
				array2[0] = val2;
				array2[1] = val3;
			}
			else
			{
				array2[^2] = val2;
				array2[^1] = val3;
			}
			return array2;
		}

		private static PlayerLoopSystem[] RemoveRunner(PlayerLoopSystem loopSystem, Type loopRunnerYieldType, Type loopRunnerType)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			return loopSystem.subSystemList.Where((PlayerLoopSystem ls) => ls.type != loopRunnerYieldType && ls.type != loopRunnerType).ToArray();
		}

		private static PlayerLoopSystem[] InsertUniTaskSynchronizationContext(PlayerLoopSystem loopSystem)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Expected O, but got Unknown
			//IL_002c: 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_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			PlayerLoopSystem val = default(PlayerLoopSystem);
			val.type = typeof(UniTaskSynchronizationContext);
			val.updateDelegate = new UpdateFunction(UniTaskSynchronizationContext.Run);
			PlayerLoopSystem item = val;
			List<PlayerLoopSystem> list = new List<PlayerLoopSystem>(loopSystem.subSystemList.Where((PlayerLoopSystem ls) => ls.type != typeof(UniTaskSynchronizationContext)).ToArray());
			int num = list.FindIndex((PlayerLoopSystem x) => x.type.Name == "ScriptRunDelayedTasks");
			if (num == -1)
			{
				num = list.FindIndex((PlayerLoopSystem x) => x.type.Name == "UniTaskLoopRunnerUpdate");
			}
			list.Insert(num + 1, item);
			return list.ToArray();
		}

		[RuntimeInitializeOnLoadMethod(/*Could not decode attribute arguments.*/)]
		private static void Init()
		{
			//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)
			unitySynchronizationContext = SynchronizationContext.Current;
			mainThreadId = Thread.CurrentThread.ManagedThreadId;
			try
			{
				applicationDataPath = Application.dataPath;
			}
			catch
			{
			}
			if (runners == null)
			{
				PlayerLoopSystem playerLoop = PlayerLoop.GetCurrentPlayerLoop();
				Initialize(ref playerLoop);
			}
		}

		static PlayerLoopHelper()
		{
			ThrowMarkerContinuationQueue = new ContinuationQueue(PlayerLoopTiming.Initialization);
			ThrowMarkerPlayerLoopRunner = new PlayerLoopRunner(PlayerLoopTiming.Initialization);
			Init();
		}

		private static int FindLoopSystemIndex(PlayerLoopSystem[] playerLoopList, Type systemType)
		{
			for (int i = 0; i < playerLoopList.Length; i++)
			{
				if (playerLoopList[i].type == systemType)
				{
					return i;
				}
			}
			throw new Exception("Target PlayerLoopSystem does not found. Type:" + systemType.FullName);
		}

		private static void InsertLoop(PlayerLoopSystem[] copyList, InjectPlayerLoopTimings injectTimings, Type loopType, InjectPlayerLoopTimings targetTimings, int index, bool injectOnFirst, Type loopRunnerYieldType, Type loopRunnerType, PlayerLoopTiming playerLoopTiming)
		{
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			int num = FindLoopSystemIndex(copyList, loopType);
			if ((injectTimings & targetTimings) == targetTimings)
			{
				copyList[num].subSystemList = InsertRunner(copyList[num], injectOnFirst, loopRunnerYieldType, yielders[index] = new ContinuationQueue(playerLoopTiming), loopRunnerType, runners[index] = new PlayerLoopRunner(playerLoopTiming));
			}
			else
			{
				copyList[num].subSystemList = RemoveRunner(copyList[num], loopRunnerYieldType, loopRunnerType);
			}
		}

		public static void Initialize(ref PlayerLoopSystem playerLoop, InjectPlayerLoopTimings injectTimings = InjectPlayerLoopTimings.All)
		{
			//IL_0303: Unknown result type (might be due to invalid IL or missing references)
			//IL_031a: Unknown result type (might be due to invalid IL or missing references)
			yielders = new ContinuationQueue[16];
			runners = new PlayerLoopRunner[16];
			PlayerLoopSystem[] array = playerLoop.subSystemList.ToArray();
			InsertLoop(array, injectTimings, typeof(Initialization), InjectPlayerLoopTimings.Initialization, 0, injectOnFirst: true, typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldInitialization), typeof(UniTaskLoopRunners.UniTaskLoopRunnerInitialization), PlayerLoopTiming.Initialization);
			InsertLoop(array, injectTimings, typeof(Initialization), InjectPlayerLoopTimings.LastInitialization, 1, injectOnFirst: false, typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldInitialization), typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastInitialization), PlayerLoopTiming.LastInitialization);
			InsertLoop(array, injectTimings, typeof(EarlyUpdate), InjectPlayerLoopTimings.EarlyUpdate, 2, injectOnFirst: true, typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldEarlyUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerEarlyUpdate), PlayerLoopTiming.EarlyUpdate);
			InsertLoop(array, injectTimings, typeof(EarlyUpdate), InjectPlayerLoopTimings.LastEarlyUpdate, 3, injectOnFirst: false, typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldEarlyUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastEarlyUpdate), PlayerLoopTiming.LastEarlyUpdate);
			InsertLoop(array, injectTimings, typeof(FixedUpdate), InjectPlayerLoopTimings.FixedUpdate, 4, injectOnFirst: true, typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldFixedUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerFixedUpdate), PlayerLoopTiming.FixedUpdate);
			InsertLoop(array, injectTimings, typeof(FixedUpdate), InjectPlayerLoopTimings.LastFixedUpdate, 5, injectOnFirst: false, typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldFixedUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastFixedUpdate), PlayerLoopTiming.LastFixedUpdate);
			InsertLoop(array, injectTimings, typeof(PreUpdate), InjectPlayerLoopTimings.PreUpdate, 6, injectOnFirst: true, typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldPreUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerPreUpdate), PlayerLoopTiming.PreUpdate);
			InsertLoop(array, injectTimings, typeof(PreUpdate), InjectPlayerLoopTimings.LastPreUpdate, 7, injectOnFirst: false, typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldPreUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastPreUpdate), PlayerLoopTiming.LastPreUpdate);
			InsertLoop(array, injectTimings, typeof(Update), InjectPlayerLoopTimings.Update, 8, injectOnFirst: true, typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerUpdate), PlayerLoopTiming.Update);
			InsertLoop(array, injectTimings, typeof(Update), InjectPlayerLoopTimings.LastUpdate, 9, injectOnFirst: false, typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastUpdate), PlayerLoopTiming.LastUpdate);
			InsertLoop(array, injectTimings, typeof(PreLateUpdate), InjectPlayerLoopTimings.PreLateUpdate, 10, injectOnFirst: true, typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldPreLateUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerPreLateUpdate), PlayerLoopTiming.PreLateUpdate);
			InsertLoop(array, injectTimings, typeof(PreLateUpdate), InjectPlayerLoopTimings.LastPreLateUpdate, 11, injectOnFirst: false, typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldPreLateUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastPreLateUpdate), PlayerLoopTiming.LastPreLateUpdate);
			InsertLoop(array, injectTimings, typeof(PostLateUpdate), InjectPlayerLoopTimings.PostLateUpdate, 12, injectOnFirst: true, typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldPostLateUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerPostLateUpdate), PlayerLoopTiming.PostLateUpdate);
			InsertLoop(array, injectTimings, typeof(PostLateUpdate), InjectPlayerLoopTimings.LastPostLateUpdate, 13, injectOnFirst: false, typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldPostLateUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastPostLateUpdate), PlayerLoopTiming.LastPostLateUpdate);
			InsertLoop(array, injectTimings, typeof(TimeUpdate), InjectPlayerLoopTimings.TimeUpdate, 14, injectOnFirst: true, typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldTimeUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerTimeUpdate), PlayerLoopTiming.TimeUpdate);
			InsertLoop(array, injectTimings, typeof(TimeUpdate), InjectPlayerLoopTimings.LastTimeUpdate, 15, injectOnFirst: false, typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldTimeUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastTimeUpdate), PlayerLoopTiming.LastTimeUpdate);
			int num = FindLoopSystemIndex(array, typeof(Update));
			array[num].subSystemList = InsertUniTaskSynchronizationContext(array[num]);
			playerLoop.subSystemList = array;
			PlayerLoop.SetPlayerLoop(playerLoop);
		}

		public static void AddAction(PlayerLoopTiming timing, IPlayerLoopItem action)
		{
			PlayerLoopRunner obj = runners[(int)timing];
			if (obj == null)
			{
				ThrowInvalidLoopTiming(timing);
			}
			obj.AddAction(action);
		}

		private static void ThrowInvalidLoopTiming(PlayerLoopTiming playerLoopTiming)
		{
			throw new InvalidOperationException("Target playerLoopTiming is not injected. Please check PlayerLoopHelper.Initialize. PlayerLoopTiming:" + playerLoopTiming);
		}

		public static void AddContinuation(PlayerLoopTiming timing, Action continuation)
		{
			ContinuationQueue obj = yielders[(int)timing];
			if (obj == null)
			{
				ThrowInvalidLoopTiming(timing);
			}
			obj.Enqueue(continuation);
		}

		public static void DumpCurrentPlayerLoop()
		{
			//IL_0000: 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_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_004a: 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_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			PlayerLoopSystem currentPlayerLoop = PlayerLoop.GetCurrentPlayerLoop();
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.AppendLine("PlayerLoop List");
			PlayerLoopSystem[] subSystemList = currentPlayerLoop.subSystemList;
			for (int i = 0; i < subSystemList.Length; i++)
			{
				PlayerLoopSystem val = subSystemList[i];
				stringBuilder.AppendFormat("------{0}------", val.type.Name);
				stringBuilder.AppendLine();
				if (val.subSystemList == null)
				{
					stringBuilder.AppendFormat("{0} has no subsystems!", ((object)(PlayerLoopSystem)(ref val)).ToString());
					stringBuilder.AppendLine();
					continue;
				}
				PlayerLoopSystem[] subSystemList2 = val.subSystemList;
				foreach (PlayerLoopSystem val2 in subSystemList2)
				{
					stringBuilder.AppendFormat("{0}", val2.type.Name);
					stringBuilder.AppendLine();
					if (val2.subSystemList != null)
					{
						Debug.LogWarning((object)("More Subsystem:" + val2.subSystemList.Length));
					}
				}
			}
			Debug.Log((object)stringBuilder.ToString());
		}

		public static bool IsInjectedUniTaskPlayerLoop()
		{
			//IL_0000: 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_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			PlayerLoopSystem[] subSystemList = PlayerLoop.GetCurrentPlayerLoop().subSystemList;
			foreach (PlayerLoopSystem val in subSystemList)
			{
				if (val.subSystemList == null)
				{
					continue;
				}
				PlayerLoopSystem[] subSystemList2 = val.subSystemList;
				for (int j = 0; j < subSystemList2.Length; j++)
				{
					if (subSystemList2[j].type == typeof(UniTaskLoopRunners.UniTaskLoopRunnerInitialization))
					{
						return true;
					}
				}
			}
			return false;
		}
	}
	public abstract class PlayerLoopTimer : IDisposable, IPlayerLoopItem
	{
		private readonly CancellationToken cancellationToken;

		private readonly Action<object> timerCallback;

		private readonly object state;

		private readonly PlayerLoopTiming playerLoopTiming;

		private readonly bool periodic;

		private bool isRunning;

		private bool tryStop;

		private bool isDisposed;

		protected PlayerLoopTimer(bool periodic, PlayerLoopTiming playerLoopTiming, CancellationToken cancellationToken, Action<object> timerCallback, object state)
		{
			this.periodic = periodic;
			this.playerLoopTiming = playerLoopTiming;
			this.cancellationToken = cancellationToken;
			this.timerCallback = timerCallback;
			this.state = state;
		}

		public static PlayerLoopTimer Create(TimeSpan interval, bool periodic, DelayType delayType, PlayerLoopTiming playerLoopTiming, CancellationToken cancellationToken, Action<object> timerCallback, object state)
		{
			return delayType switch
			{
				DelayType.UnscaledDeltaTime => new IgnoreTimeScalePlayerLoopTimer(interval, periodic, playerLoopTiming, cancellationToken, timerCallback, state), 
				DelayType.Realtime => new RealtimePlayerLoopTimer(interval, periodic, playerLoopTiming, cancellationToken, timerCallback, state), 
				_ => new DeltaTimePlayerLoopTimer(interval, periodic, playerLoopTiming, cancellationToken, timerCallback, state), 
			};
		}

		public static PlayerLoopTimer StartNew(TimeSpan interval, bool periodic, DelayType delayType, PlayerLoopTiming playerLoopTiming, CancellationToken cancellationToken, Action<object> timerCallback, object state)
		{
			PlayerLoopTimer playerLoopTimer = Create(interval, periodic, delayType, playerLoopTiming, cancellationToken, timerCallback, state);
			playerLoopTimer.Restart();
			return playerLoopTimer;
		}

		public void Restart()
		{
			if (isDisposed)
			{
				throw new ObjectDisposedException(null);
			}
			ResetCore(null);
			if (!isRunning)
			{
				isRunning = true;
				PlayerLoopHelper.AddAction(playerLoopTiming, this);
			}
			tryStop = false;
		}

		public void Restart(TimeSpan interval)
		{
			if (isDisposed)
			{
				throw new ObjectDisposedException(null);
			}
			ResetCore(interval);
			if (!isRunning)
			{
				isRunning = true;
				PlayerLoopHelper.AddAction(playerLoopTiming, this);
			}
			tryStop = false;
		}

		public void Stop()
		{
			tryStop = true;
		}

		protected abstract void ResetCore(TimeSpan? newInterval);

		public void Dispose()
		{
			isDisposed = true;
		}

		bool IPlayerLoopItem.MoveNext()
		{
			if (isDisposed)
			{
				isRunning = false;
				return false;
			}
			if (tryStop)
			{
				isRunning = false;
				return false;
			}
			CancellationToken cancellationToken = this.cancellationToken;
			if (cancellationToken.IsCancellationRequested)
			{
				isRunning = false;
				return false;
			}
			if (!MoveNextCore())
			{
				timerCallback(state);
				if (periodic)
				{
					ResetCore(null);
					return true;
				}
				isRunning = false;
				return false;
			}
			return true;
		}

		protected abstract bool MoveNextCore();
	}
	internal sealed class DeltaTimePlayerLoopTimer : PlayerLoopTimer
	{
		private int initialFrame;

		private float elapsed;

		private float interval;

		public DeltaTimePlayerLoopTimer(TimeSpan interval, bool periodic, PlayerLoopTiming playerLoopTiming, CancellationToken cancellationToken, Action<object> timerCallback, object state)
			: base(periodic, playerLoopTiming, cancellationToken, timerCallback, state)
		{
			ResetCore(interval);
		}

		protected override bool MoveNextCore()
		{
			if (elapsed == 0f && initialFrame == Time.frameCount)
			{
				return true;
			}
			elapsed += Time.deltaTime;
			if (elapsed >= interval)
			{
				return false;
			}
			return true;
		}

		protected override void ResetCore(TimeSpan? interval)
		{
			elapsed = 0f;
			initialFrame = (PlayerLoopHelper.IsMainThread ? Time.frameCount : (-1));
			if (interval.HasValue)
			{
				this.interval = (float)interval.Value.TotalSeconds;
			}
		}
	}
	internal sealed class IgnoreTimeScalePlayerLoopTimer : PlayerLoopTimer
	{
		private int initialFrame;

		private float elapsed;

		private float interval;

		public IgnoreTimeScalePlayerLoopTimer(TimeSpan interval, bool periodic, PlayerLoopTiming playerLoopTiming, CancellationToken cancellationToken, Action<object> timerCallback, object state)
			: base(periodic, playerLoopTiming, cancellationToken, timerCallback, state)
		{
			ResetCore(interval);
		}

		protected override bool MoveNextCore()
		{
			if (elapsed == 0f && initialFrame == Time.frameCount)
			{
				return true;
			}
			elapsed += Time.unscaledDeltaTime;
			if (elapsed >= interval)
			{
				return false;
			}
			return true;
		}

		protected override void ResetCore(TimeSpan? interval)
		{
			elapsed = 0f;
			initialFrame = (PlayerLoopHelper.IsMainThread ? Time.frameCount : (-1));
			if (interval.HasValue)
			{
				this.interval = (float)interval.Value.TotalSeconds;
			}
		}
	}
	internal sealed class RealtimePlayerLoopTimer : PlayerLoopTimer
	{
		private ValueStopwatch stopwatch;

		private long intervalTicks;

		public RealtimePlayerLoopTimer(TimeSpan interval, bool periodic, PlayerLoopTiming playerLoopTiming, CancellationToken cancellationToken, Action<object> timerCallback, object state)
			: base(periodic, playerLoopTiming, cancellationToken, timerCallback, state)
		{
			ResetCore(interval);
		}

		protected override bool MoveNextCore()
		{
			if (stopwatch.ElapsedTicks >= intervalTicks)
			{
				return false;
			}
			return true;
		}

		protected override void ResetCore(TimeSpan? interval)
		{
			stopwatch = ValueStopwatch.StartNew();
			if (interval.HasValue)
			{
				intervalTicks = interval.Value.Ticks;
			}
		}
	}
	public static class Progress
	{
		private sealed class NullProgress<T> : IProgress<T>
		{
			public static readonly IProgress<T> Instance = new NullProgress<T>();

			private NullProgress()
			{
			}

			public void Report(T value)
			{
			}
		}

		private sealed class AnonymousProgress<T> : IProgress<T>
		{
			private readonly Action<T> action;

			public AnonymousProgress(Action<T> action)
			{
				this.action = action;
			}

			public void Report(T value)
			{
				action(value);
			}
		}

		private sealed class OnlyValueChangedProgress<T> : IProgress<T>
		{
			private readonly Action<T> action;

			private readonly IEqualityComparer<T> comparer;

			private bool isFirstCall;

			private T latestValue;

			public OnlyValueChangedProgress(Action<T> action, IEqualityComparer<T> comparer)
			{
				this.action = action;
				this.comparer = comparer;
				isFirstCall = true;
			}

			public void Report(T value)
			{
				if (isFirstCall)
				{
					isFirstCall = false;
				}
				else if (comparer.Equals(value, latestValue))
				{
					return;
				}
				latestValue = value;
				action(value);
			}
		}

		public static IProgress<T> Create<T>(Action<T> handler)
		{
			if (handler == null)
			{
				return NullProgress<T>.Instance;
			}
			return new AnonymousProgress<T>(handler);
		}

		public static IProgress<T> CreateOnlyValueChanged<T>(Action<T> handler, IEqualityComparer<T> comparer = null)
		{
			if (handler == null)
			{
				return NullProgress<T>.Instance;
			}
			return new OnlyValueChangedProgress<T>(handler, comparer ?? UnityEqualityComparer.GetDefault<T>());
		}
	}
	public static class TaskPool
	{
		internal static int MaxPoolSize;

		private static Dictionary<Type, Func<int>> sizes;

		static TaskPool()
		{
			sizes = new Dictionary<Type, Func<int>>();
			try
			{
				string environmentVariable = Environment.GetEnvironmentVariable("UNITASK_MAX_POOLSIZE");
				if (environmentVariable != null && int.TryParse(environmentVariable, out var result))
				{
					MaxPoolSize = result;
					return;
				}
			}
			catch
			{
			}
			MaxPoolSize = int.MaxValue;
		}

		public static void SetMaxPoolSize(int maxPoolSize)
		{
			MaxPoolSize = maxPoolSize;
		}

		public static IEnumerable<(Type, int)> GetCacheSizeInfo()
		{
			lock (sizes)
			{
				foreach (KeyValuePair<Type, Func<int>> size in sizes)
				{
					yield return (size.Key, size.Value());
				}
			}
		}

		public static void RegisterSizeGetter(Type type, Func<int> getSize)
		{
			lock (sizes)
			{
				sizes[type] = getSize;
			}
		}
	}
	public interface ITaskPoolNode<T>
	{
		ref T NextNode { get; }
	}
	[StructLayout(LayoutKind.Auto)]
	public struct TaskPool<T> where T : class, ITaskPoolNode<T>
	{
		private int gate;

		private int size;

		private T root;

		public int Size => size;

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public bool TryPop(out T result)
		{
			if (Interlocked.CompareExchange(ref gate, 1, 0) == 0)
			{
				T val = root;
				if (val != null)
				{
					ref T nextNode = ref val.NextNode;
					root = nextNode;
					nextNode = null;
					size--;
					result = val;
					Volatile.Write(ref gate, 0);
					return true;
				}
				Volatile.Write(ref gate, 0);
			}
			result = null;
			return false;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public bool TryPush(T item)
		{
			if (Interlocked.CompareExchange(ref gate, 1, 0) == 0)
			{
				if (size < TaskPool.MaxPoolSize)
				{
					item.NextNode = root;
					root = item;
					size++;
					Volatile.Write(ref gate, 0);
					return true;
				}
				Volatile.Write(ref gate, 0);
			}
			return false;
		}
	}
	public sealed class TimeoutController : IDisposable
	{
		private static readonly Action<object> CancelCancellationTokenSourceStateDelegate = CancelCancellationTokenSourceState;

		private CancellationTokenSource timeoutSource;

		private CancellationTokenSource linkedSource;

		private PlayerLoopTimer timer;

		private bool isDisposed;

		private readonly DelayType delayType;

		private readonly PlayerLoopTiming delayTiming;

		private readonly CancellationTokenSource originalLinkCancellationTokenSource;

		private static void CancelCancellationTokenSourceState(object state)
		{
			((CancellationTokenSource)state).Cancel();
		}

		public TimeoutController(DelayType delayType = DelayType.DeltaTime, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update)
		{
			timeoutSource = new CancellationTokenSource();
			originalLinkCancellationTokenSource = null;
			linkedSource = null;
			this.delayType = delayType;
			this.delayTiming = delayTiming;
		}

		public TimeoutController(CancellationTokenSource linkCancellationTokenSource, DelayType delayType = DelayType.DeltaTime, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update)
		{
			timeoutSource = new CancellationTokenSource();
			originalLinkCancellationTokenSource = linkCancellationTokenSource;
			linkedSource = CancellationTokenSource.CreateLinkedTokenSource(timeoutSource.Token, linkCancellationTokenSource.Token);
			this.delayType = delayType;
			this.delayTiming = delayTiming;
		}

		public CancellationToken Timeout(int millisecondsTimeout)
		{
			return Timeout(TimeSpan.FromMilliseconds(millisecondsTimeout));
		}

		public CancellationToken Timeout(TimeSpan timeout)
		{
			if (originalLinkCancellationTokenSource != null && originalLinkCancellationTokenSource.IsCancellationRequested)
			{
				return originalLinkCancellationTokenSource.Token;
			}
			if (timeoutSource.IsCancellationRequested)
			{
				timeoutSource.Dispose();
				timeoutSource = new CancellationTokenSource();
				if (linkedSource != null)
				{
					linkedSource.Cancel();
					linkedSource.Dispose();
					linkedSource = CancellationTokenSource.CreateLinkedTokenSource(timeoutSource.Token, originalLinkCancellationTokenSource.Token);
				}
				timer?.Dispose();
				timer = null;
			}
			CancellationToken token = ((linkedSource != null) ? linkedSource : timeoutSource).Token;
			if (timer == null)
			{
				timer = PlayerLoopTimer.StartNew(timeout, periodic: false, delayType, delayTiming, token, CancelCancellationTokenSourceStateDelegate, timeoutSource);
			}
			else
			{
				timer.Restart(timeout);
			}
			return token;
		}

		public bool IsTimeout()
		{
			return timeoutSource.IsCancellationRequested;
		}

		public void Reset()
		{
			timer?.Stop();
		}

		public void Dispose()
		{
			if (isDisposed)
			{
				return;
			}
			try
			{
				timer?.Dispose();
				timeoutSource.Cancel();
				timeoutSource.Dispose();
				if (linkedSource != null)
				{
					linkedSource.Cancel();
					linkedSource.Dispose();
				}
			}
			finally
			{
				isDisposed = true;
			}
		}
	}
	public interface ITriggerHandler<T>
	{
		ITriggerHandler<T> Prev { get; set; }

		ITriggerHandler<T> Next { get; set; }

		void OnNext(T value);

		void OnError(Exception ex);

		void OnCompleted();

		void OnCanceled(CancellationToken cancellationToken);
	}
	public struct TriggerEvent<T>
	{
		private ITriggerHandler<T> head;

		private ITriggerHandler<T> iteratingHead;

		private ITriggerHandler<T> iteratingNode;

		private void LogError(Exception ex)
		{
			Debug.LogException(ex);
		}

		public void SetResult(T value)
		{
			if (iteratingNode != null)
			{
				throw new InvalidOperationException("Can not trigger itself in iterating.");
			}
			for (ITriggerHandler<T> triggerHandler = head; triggerHandler != null; triggerHandler = ((triggerHandler == iteratingNode) ? triggerHandler.Next : iteratingNode))
			{
				iteratingNode = triggerHandler;
				try
				{
					triggerHandler.OnNext(value);
				}
				catch (Exception ex)
				{
					LogError(ex);
					Remove(triggerHandler);
				}
			}
			iteratingNode = null;
			if (iteratingHead != null)
			{
				Add(iteratingHead);
				iteratingHead = null;
			}
		}

		public void SetCanceled(CancellationToken cancellationToken)
		{
			if (iteratingNode != null)
			{
				throw new InvalidOperationException("Can not trigger itself in iterating.");
			}
			ITriggerHandler<T> triggerHandler = head;
			while (triggerHandler != null)
			{
				iteratingNode = triggerHandler;
				try
				{
					triggerHandler.OnCanceled(cancellationToken);
				}
				catch (Exception ex)
				{
					LogError(ex);
				}
				ITriggerHandler<T> obj = ((triggerHandler == iteratingNode) ? triggerHandler.Next : iteratingNode);
				iteratingNode = null;
				Remove(triggerHandler);
				triggerHandler = obj;
			}
			iteratingNode = null;
			if (iteratingHead != null)
			{
				Add(iteratingHead);
				iteratingHead = null;
			}
		}

		public void SetCompleted()
		{
			if (iteratingNode != null)
			{
				throw new InvalidOperationException("Can not trigger itself in iterating.");
			}
			ITriggerHandler<T> triggerHandler = head;
			while (triggerHandler != null)
			{
				iteratingNode = triggerHandler;
				try
				{
					triggerHandler.OnCompleted();
				}
				catch (Exception ex)
				{
					LogError(ex);
				}
				ITriggerHandler<T> obj = ((triggerHandler == iteratingNode) ? triggerHandler.Next : iteratingNode);
				iteratingNode = null;
				Remove(triggerHandler);
				triggerHandler = obj;
			}
			iteratingNode = null;
			if (iteratingHead != null)
			{
				Add(iteratingHead);
				iteratingHead = null;
			}
		}

		public void SetError(Exception exception)
		{
			if (iteratingNode != null)
			{
				throw new InvalidOperationException("Can not trigger itself in iterating.");
			}
			ITriggerHandler<T> triggerHandler = head;
			while (triggerHandler != null)
			{
				iteratingNode = triggerHandler;
				try
				{
					triggerHandler.OnError(exception);
				}
				catch (Exception ex)
				{
					LogError(ex);
				}
				ITriggerHandler<T> obj = ((triggerHandler == iteratingNode) ? triggerHandler.Next : iteratingNode);
				iteratingNode = null;
				Remove(triggerHandler);
				triggerHandler = obj;
			}
			iteratingNode = null;
			if (iteratingHead != null)
			{
				Add(iteratingHead);
				iteratingHead = null;
			}
		}

		public void Add(ITriggerHandler<T> handler)
		{
			if (handler == null)
			{
				throw new ArgumentNullException("handler");
			}
			if (head == null)
			{
				head = handler;
			}
			else if (iteratingNode != null)
			{
				if (iteratingHead == null)
				{
					iteratingHead = handler;
					return;
				}
				ITriggerHandler<T> prev = iteratingHead.Prev;
				if (prev == null)
				{
					iteratingHead.Prev = handler;
					iteratingHead.Next = handler;
					handler.Prev = iteratingHead;
				}
				else
				{
					iteratingHead.Prev = handler;
					prev.Next = handler;
					handler.Prev = prev;
				}
			}
			else
			{
				ITriggerHandler<T> prev2 = head.Prev;
				if (prev2 == null)
				{
					head.Prev = handler;
					head.Next = handler;
					handler.Prev = head;
				}
				else
				{
					head.Prev = handler;
					prev2.Next = handler;
					handler.Prev = prev2;
				}
			}
		}

		public void Remove(ITriggerHandler<T> handler)
		{
			if (handler == null)
			{
				throw new ArgumentNullException("handler");
			}
			ITriggerHandler<T> prev = handler.Prev;
			ITriggerHandler<T> next = handler.Next;
			if (next != null)
			{
				next.Prev = prev;
			}
			if (handler == head)
			{
				head = next;
			}
			else if (prev != null)
			{
				prev.Next = next;
			}
			if (handler == iteratingNode)
			{
				iteratingNode = next;
			}
			if (handler == iteratingHead)
			{
				iteratingHead = next;
			}
			if (head != null && head.Prev == handler)
			{
				if (prev != head)
				{
					head.Prev = prev;
				}
				else
				{
					head.Prev = null;
				}
			}
			if (iteratingHead != null && iteratingHead.Prev == handler)
			{
				if (prev != iteratingHead.Prev)
				{
					iteratingHead.Prev = prev;
				}
				else
				{
					iteratingHead.Prev = null;
				}
			}
			handler.Prev = null;
			handler.Next = null;
		}
	}
	public static class UniTaskCancellationExtensions
	{
		public static CancellationToken GetCancellationTokenOnDestroy(this GameObject gameObject)
		{
			return gameObject.GetAsyncDestroyTrigger().CancellationToken;
		}

		public static CancellationToken GetCancellationTokenOnDestroy(this Component component)
		{
			return component.GetAsyncDestroyTrigger().CancellationToken;
		}
	}
	[StructLayout(LayoutKind.Auto)]
	[AsyncMethodBuilder(typeof(AsyncUniTaskMethodBuilder))]
	public readonly struct UniTask
	{
		private sealed class AsyncUnitSource : IUniTaskSource<AsyncUnit>, IUniTaskSource
		{
			private readonly IUniTaskSource source;

			public AsyncUnitSource(IUniTaskSource source)
			{
				this.source = source;
			}

			public AsyncUnit GetResult(short token)
			{
				source.GetResult(token);
				return AsyncUnit.Default;
			}

			public UniTaskStatus GetStatus(short token)
			{
				return source.GetStatus(token);
			}

			public void OnCompleted(Action<object> continuation, object state, short token)
			{
				source.OnCompleted(continuation, state, token);
			}

			public UniTaskStatus UnsafeGetStatus()
			{
				return source.UnsafeGetStatus();
			}

			void IUniTaskSource.GetResult(short token)
			{
				GetResult(token);
			}
		}

		private sealed class IsCanceledSource : IUniTaskSource<bool>, IUniTaskSource
		{
			private readonly IUniTaskSource source;

			public IsCanceledSource(IUniTaskSource source)
			{
				this.source = source;
			}

			public bool GetResult(short token)
			{
				if (source.GetStatus(token) == UniTaskStatus.Canceled)
				{
					return true;
				}
				source.GetResult(token);
				return false;
			}

			void IUniTaskSource.GetResult(short token)
			{
				GetResult(token);
			}

			public UniTaskStatus GetStatus(short token)
			{
				return source.GetStatus(token);
			}

			public UniTaskStatus UnsafeGetStatus()
			{
				return source.UnsafeGetStatus();
			}

			public void OnCompleted(Action<object> continuation, object state, short token)
			{
				source.OnCompleted(continuation, state, token);
			}
		}

		private sealed class MemoizeSource : IUniTaskSource
		{
			private IUniTaskSource source;

			private ExceptionDispatchInfo exception;

			private UniTaskStatus status;

			public MemoizeSource(IUniTaskSource source)
			{
				this.source = source;
			}

			public void GetResult(short token)
			{
				if (source == null)
				{
					if (exception != null)
					{
						exception.Throw();
					}
					return;
				}
				try
				{
					source.GetResult(token);
					status = UniTaskStatus.Succeeded;
				}
				catch (Exception ex)
				{
					exception = ExceptionDispatchInfo.Capture(ex);
					if (ex is OperationCanceledException)
					{
						status = UniTaskStatus.Canceled;
					}
					else
					{
						status = UniTaskStatus.Faulted;
					}
					throw;
				}
				finally
				{
					source = null;
				}
			}

			public UniTaskStatus GetStatus(short token)
			{
				if (source == null)
				{
					return status;
				}
				return source.GetStatus(token);
			}

			public void OnCompleted(Action<object> continuation, object state, short token)
			{
				if (source == null)
				{
					continuation(state);
				}
				else
				{
					source.OnCompleted(continuation, state, token);
				}
			}

			public UniTaskStatus UnsafeGetStatus()
			{
				if (source == null)
				{
					return status;
				}
				return source.UnsafeGetStatus();
			}
		}

		public readonly struct Awaiter : ICriticalNotifyCompletion, INotifyCompletion
		{
			private readonly UniTask task;

			public bool IsCompleted
			{
				[MethodImpl(MethodImplOptions.AggressiveInlining)]
				[DebuggerHidden]
				get
				{
					return task.Status.IsCompleted();
				}
			}

			[MethodImpl(MethodImplOptions.AggressiveInlining)]
			[DebuggerHidden]
			public Awaiter(in UniTask task)
			{
				this.task = task;
			}

			[MethodImpl(MethodImplOptions.AggressiveInlining)]
			[DebuggerHidden]
			public void GetResult()
			{
				if (task.source != null)
				{
					task.source.GetResult(task.token);
				}
			}

			[MethodImpl(MethodImplOptions.AggressiveInlining)]
			[DebuggerHidden]
			public void OnCompleted(Action continuation)
			{
				if (task.source == null)
				{
					continuation();
				}
				else
				{
					task.source.OnCompleted(AwaiterActions.InvokeContinuationDelegate, continuation, task.token);
				}
			}

			[MethodImpl(MethodImplOptions.AggressiveInlining)]
			[DebuggerHidden]
			public void UnsafeOnCompleted(Action continuation)
			{
				if (task.source == null)
				{
					continuation();
				}
				else
				{
					task.source.OnCompleted(AwaiterActions.InvokeContinuationDelegate, continuation, task.token);
				}
			}

			[MethodImpl(MethodImplOptions.AggressiveInlining)]
			[DebuggerHidden]
			public void SourceOnCompleted(Action<object> continuation, object state)
			{
				if (task.source == null)
				{
					continuation(state);
				}
				else
				{
					task.source.OnCompleted(continuation, state, task.token);
				}
			}
		}

		private sealed class YieldPromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<YieldPromise>
		{
			private static TaskPool<YieldPromise> pool;

			private YieldPromise nextNode;

			private CancellationToken cancellationToken;

			private CancellationTokenRegistration cancellationTokenRegistration;

			private bool cancelImmediately;

			private UniTaskCompletionSourceCore<object> core;

			public ref YieldPromise NextNode => ref nextNode;

			static YieldPromise()
			{
				TaskPool.RegisterSizeGetter(typeof(YieldPromise), () => pool.Size);
			}

			private YieldPromise()
			{
			}

			public static IUniTaskSource Create(PlayerLoopTiming timing, CancellationToken cancellationToken, bool cancelImmediately, out short token)
			{
				if (cancellationToken.IsCancellationRequested)
				{
					return AutoResetUniTaskCompletionSource.CreateFromCanceled(cancellationToken, out token);
				}
				if (!pool.TryPop(out var result))
				{
					result = new YieldPromise();
				}
				result.cancellationToken = cancellationToken;
				result.cancelImmediately = cancelImmediately;
				if (cancelImmediately && cancellationToken.CanBeCanceled)
				{
					result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(delegate(object state)
					{
						YieldPromise yieldPromise = (YieldPromise)state;
						yieldPromise.core.TrySetCanceled(yieldPromise.cancellationToken);
					}, result);
				}
				PlayerLoopHelper.AddAction(timing, result);
				token = result.core.Version;
				return result;
			}

			public void GetResult(short token)
			{
				try
				{
					core.GetResult(token);
				}
				finally
				{
					if (!cancelImmediately || !cancellationToken.IsCancellationRequested)
					{
						TryReturn();
					}
				}
			}

			public UniTaskStatus GetStatus(short token)
			{
				return core.GetStatus(token);
			}

			public UniTaskStatus UnsafeGetStatus()
			{
				return core.UnsafeGetStatus();
			}

			public void OnCompleted(Action<object> continuation, object state, short token)
			{
				core.OnCompleted(continuation, state, token);
			}

			public bool MoveNext()
			{
				if (cancellationToken.IsCancellationRequested)
				{
					core.TrySetCanceled(cancellationToken);
					return false;
				}
				core.TrySetResult(null);
				return false;
			}

			private bool TryReturn()
			{
				core.Reset();
				cancellationToken = default(CancellationToken);
				cancellationTokenRegistration.Dispose();
				cancelImmediately = false;
				return pool.TryPush(this);
			}
		}

		private sealed class NextFramePromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<NextFramePromise>
		{
			private static TaskPool<NextFramePromise> pool;

			private NextFramePromise nextNode;

			private int frameCount;

			private UniTaskCompletionSourceCore<AsyncUnit> core;

			private CancellationToken cancellationToken;

			private CancellationTokenRegistration cancellationTokenRegistration;

			private bool cancelImmediately;

			public ref NextFramePromise NextNode => ref nextNode;

			static NextFramePromise()
			{
				TaskPool.RegisterSizeGetter(typeof(NextFramePromise), () => pool.Size);
			}

			private NextFramePromise()
			{
			}

			public static IUniTaskSource Create(PlayerLoopTiming timing, CancellationToken cancellationToken, bool cancelImmediately, out short token)
			{
				if (cancellationToken.IsCancellationRequested)
				{
					return AutoResetUniTaskCompletionSource.CreateFromCanceled(cancellationToken, out token);
				}
				if (!pool.TryPop(out var result))
				{
					result = new NextFramePromise();
				}
				result.frameCount = (PlayerLoopHelper.IsMainThread ? Time.frameCount : (-1));
				result.cancellationToken = cancellationToken;
				result.cancelImmediately = cancelImmediately;
				if (cancelImmediately && cancellationToken.CanBeCanceled)
				{
					result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(delegate(object state)
					{
						NextFramePromise nextFramePromise = (NextFramePromise)state;
						nextFramePromise.core.TrySetCanceled(nextFramePromise.cancellationToken);
					}, result);
				}
				PlayerLoopHelper.AddAction(timing, result);
				token = result.core.Version;
				return result;
			}

			public void GetResult(short token)
			{
				try
				{
					core.GetResult(token);
				}
				finally
				{
					if (!cancelImmediately || !cancellationToken.IsCancellationRequested)
					{
						TryReturn();
					}
				}
			}

			public UniTaskStatus GetStatus(short token)
			{
				return core.GetStatus(token);
			}

			public UniTa