Decompiled source of H3MP v1.10.5

H3MP.dll

Decompiled 2 months ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Cryptography;
using System.Security.Permissions;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Timers;
using Anvil;
using BepInEx;
using BepInEx.Bootstrap;
using FistVR;
using H3MP.Networking;
using H3MP.Patches;
using H3MP.Scripts;
using H3MP.Tracking;
using HarmonyLib;
using HarmonyLib.Public.Patching;
using Mono.Cecil.Cil;
using Open.Nat;
using UnityEngine;
using UnityEngine.Audio;
using UnityEngine.Events;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using Valve.Newtonsoft.Json.Linq;
using Valve.VR;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("H3MP")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("H3MP")]
[assembly: AssemblyCopyright("Copyright ©  2022")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("4e60aee7-baed-4e40-8c9c-2edc0a12f580")]
[assembly: AssemblyFileVersion("1.10.5.0")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.10.5.0")]
[module: UnverifiableCode]
namespace H3MP
{
	public class GameManager : MonoBehaviour
	{
		public delegate void OnUpdatePlayerHiddenDelegate(PlayerManager player, ref bool visible);

		public delegate void OnPlayerDamageDelegate(float damageMultiplier, Damage damage, ref bool processDamage);

		public delegate void OnSpectatorHostsChangedDelegate();

		public delegate void OnSpectatorHostToggledDelegate(bool spectatorHost);

		public delegate void OnInstanceLeftDelegate(int instance, int destination);

		public delegate void OnInstanceJoinedDelegate(int instance, int source);

		public delegate void OnPlayerInstanceChangedDelegate(int ID, int instance, int destination);

		public delegate void OnSceneLeftDelegate(string scene, string destination);

		public delegate void OnSceneJoinedDelegate(string scene, string source);

		public delegate void OnPlayerBodyInitDelegate(FVRPlayerBody playerBody);

		public delegate void OnPlayerAddedDelegate(PlayerManager player);

		private static GameManager _singleton;

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

		public static List<TrackedObjectData> objects = new List<TrackedObjectData>();

		public static Dictionary<MonoBehaviour, TrackedObject> trackedObjectByObject = new Dictionary<MonoBehaviour, TrackedObject>();

		public static Dictionary<FVRInteractiveObject, TrackedObject> trackedObjectByInteractive = new Dictionary<FVRInteractiveObject, TrackedObject>();

		public static Dictionary<IFVRDamageable, TrackedObject> trackedObjectByDamageable = new Dictionary<IFVRDamageable, TrackedObject>();

		public static Dictionary<UberShatterable, TrackedObject> trackedObjectByShatterable = new Dictionary<UberShatterable, TrackedObject>();

		public static Dictionary<FVRPhysicalObject, TrackedItem> trackedItemByItem = new Dictionary<FVRPhysicalObject, TrackedItem>();

		public static Dictionary<SosigWeapon, TrackedItem> trackedItemBySosigWeapon = new Dictionary<SosigWeapon, TrackedItem>();

		public static Dictionary<Sosig, TrackedSosig> trackedSosigBySosig = new Dictionary<Sosig, TrackedSosig>();

		public static Dictionary<AutoMeater, TrackedAutoMeater> trackedAutoMeaterByAutoMeater = new Dictionary<AutoMeater, TrackedAutoMeater>();

		public static Dictionary<TNH_EncryptionTarget, TrackedEncryption> trackedEncryptionByEncryption = new Dictionary<TNH_EncryptionTarget, TrackedEncryption>();

		public static Dictionary<BreakableGlass, TrackedBreakableGlass> trackedBreakableGlassByBreakableGlass = new Dictionary<BreakableGlass, TrackedBreakableGlass>();

		public static Dictionary<BreakableGlassDamager, TrackedBreakableGlass> trackedBreakableGlassByBreakableGlassDamager = new Dictionary<BreakableGlassDamager, TrackedBreakableGlass>();

		public static Dictionary<wwGatlingGun, TrackedGatlingGun> trackedGatlingGunByGatlingGun = new Dictionary<wwGatlingGun, TrackedGatlingGun>();

		public static Dictionary<BrutBlockSystem, TrackedBrutBlockSystem> trackedBrutBlockSystemByBrutBlockSystem = new Dictionary<BrutBlockSystem, TrackedBrutBlockSystem>();

		public static Dictionary<Construct_Blister, TrackedBlister> trackedBlisterByBlister = new Dictionary<Construct_Blister, TrackedBlister>();

		public static Dictionary<Construct_Floater, TrackedFloater> trackedFloaterByFloater = new Dictionary<Construct_Floater, TrackedFloater>();

		public static Dictionary<Construct_Iris, TrackedIris> trackedIrisByIris = new Dictionary<Construct_Iris, TrackedIris>();

		public static Dictionary<Construct_Sentinel, TrackedSentinel> trackedSentinelBySentinel = new Dictionary<Construct_Sentinel, TrackedSentinel>();

		public static Dictionary<Construct_Node, TrackedNode> trackedNodeByNode = new Dictionary<Construct_Node, TrackedNode>();

		public static Dictionary<Construct_Haze, TrackedHaze> trackedHazeByHaze = new Dictionary<Construct_Haze, TrackedHaze>();

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

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

		public static List<int> playersAtLoadStart;

		public static Dictionary<string, Dictionary<int, List<int>>> playersByInstanceByScene = new Dictionary<string, Dictionary<int, List<int>>>();

		public static Dictionary<string, Dictionary<int, List<int>>> objectsByInstanceByScene = new Dictionary<string, Dictionary<int, List<int>>>();

		public static List<GameObject> retrack = new List<GameObject>();

		public static bool spectatorHost;

		public static List<int> spectatorHosts = new List<int>();

		public static int controlledSpectatorHost = -1;

		public static int spectatorHostControlledBy = -1;

		public static bool resetSpectatorHost;

		public static bool instanceBringItems;

		public static long ping = -1L;

		public static int reconnectionInstance = -1;

		public static Dictionary<string, byte> nonSynchronizedScenes = new Dictionary<string, byte>();

		public static int giveControlOfDestroyed;

		public static bool controlOverride;

		public static bool firstPlayerInSceneInstance;

		public static bool dontAddToInstance;

		public static bool inPostSceneLoadTrack;

		public static int ID = 0;

		public static Vector3 torsoOffset = new Vector3(0f, -0.4f, 0f);

		public static Vector3 overheadDisplayOffset = new Vector3(0f, 0.25f, 0f);

		public static List<int> playersPresent = new List<int>();

		public static int playerStateAddtionalDataSize = -1;

		public static int instance = 0;

		public static string scene = "MainMenu3";

		public static bool sceneLoading;

		public static int instanceAtSceneLoadStart;

		public static string sceneAtSceneLoadStart;

		public static bool connectedAtLoadStart;

		public static int colorIndex = 0;

		public static readonly string[] colorNames = new string[7] { "White", "Red", "Green", "Blue", "Black", "Desert", "Forest" };

		public static readonly Color[] colors = (Color[])(object)new Color[7]
		{
			Color.white,
			Color.red,
			Color.green,
			Color.blue,
			Color.black,
			new Color(0.98431f, 0.86275f, 0.71373f),
			new Color(0.31373f, 0.31373f, 0.15294f)
		};

		public static bool colorByIFF = false;

		public static int nameplateMode = 1;

		public static int radarMode = 0;

		public static bool radarColor = true;

		public static bool overrideMaxHealthSetting = false;

		public static float[] maxHealths = new float[9] { 1f, 500f, 1000f, 2000f, 3000f, 4000f, 5000f, 7500f, 10000f };

		public static int maxHealthIndex = -1;

		public static Dictionary<string, Dictionary<int, KeyValuePair<float, int>>> maxHealthByInstanceByScene = new Dictionary<string, Dictionary<int, KeyValuePair<float, int>>>();

		public static string playerPrefabID = "None";

		public static int playerPrefabIndex = -1;

		public static TrackedPlayerBody currentTrackedPlayerBody;

		public static bool playerModelAwaitingInstantiation = false;

		public static PlayerBody currentPlayerBody = null;

		public static bool bodyVisible = true;

		public static bool handsVisible = true;

		public static Dictionary<string, Object> playerPrefabs = new Dictionary<string, Object>();

		public static List<string> playerPrefabIDs = new List<string>();

		public static GameManager singleton
		{
			get
			{
				return _singleton;
			}
			private set
			{
				if ((Object)(object)_singleton == (Object)null)
				{
					_singleton = value;
				}
				else if ((Object)(object)_singleton != (Object)(object)value)
				{
					Mod.LogInfo("GameManager instance already exists, destroying duplicate!", debug: false);
					Object.Destroy((Object)(object)value);
				}
			}
		}

		public static event OnUpdatePlayerHiddenDelegate OnUpdatePlayerHidden;

		public static event OnPlayerDamageDelegate OnPlayerDamage;

		public static event OnSpectatorHostsChangedDelegate OnSpectatorHostsChanged;

		public static event OnSpectatorHostToggledDelegate OnSpectatorHostToggled;

		public static event OnInstanceLeftDelegate OnInstanceLeft;

		public static event OnInstanceJoinedDelegate OnInstanceJoined;

		public static event OnPlayerInstanceChangedDelegate OnPlayerInstanceChanged;

		public static event OnSceneLeftDelegate OnSceneLeft;

		public static event OnSceneJoinedDelegate OnSceneJoined;

		public static event OnPlayerBodyInitDelegate OnPlayerBodyInit;

		public static event OnPlayerAddedDelegate OnPlayerAdded;

		private void Awake()
		{
			singleton = this;
			activeInstances.Add(instance, 1);
		}

		private void Update()
		{
			if (!Input.GetKeyDown((KeyCode)287) || sceneLoading)
			{
				return;
			}
			spectatorHost = !spectatorHost;
			if ((Object)(object)GM.CurrentPlayerBody != (Object)null)
			{
				((Behaviour)GM.CurrentPlayerBody.EyeCam).enabled = !spectatorHost;
			}
			if (ThreadManager.host)
			{
				if (spectatorHost)
				{
					spectatorHosts.Add(0);
					Server.availableSpectatorHosts.Add(0);
				}
				else
				{
					spectatorHosts.Remove(0);
					Server.availableSpectatorHosts.Remove(0);
				}
				ServerSend.SpectatorHost(0, spectatorHost);
			}
			else
			{
				spectatorHosts.Add(ID);
				ClientSend.SpectatorHost(spectatorHost);
			}
			if (spectatorHost)
			{
				Mod.LogWarning("Player is now a spectator host!");
				if (!scene.Equals("MainMenu3"))
				{
					SteamVR_LoadLevel.Begin("MainMenu3", false, 0.5f, 0f, 0f, 0f, 1f);
				}
			}
			else
			{
				Mod.LogWarning("Player is no longer a spectator host!");
				spectatorHostControlledBy = -1;
				Mod.spectatorHostWaitingForTNHSetup = false;
			}
			if (GameManager.OnSpectatorHostToggled != null)
			{
				GameManager.OnSpectatorHostToggled(spectatorHost);
			}
		}

		public static void OnSpectatorHostsChangedInvoke()
		{
			if (GameManager.OnSpectatorHostsChanged != null)
			{
				GameManager.OnSpectatorHostsChanged();
			}
		}

		public void SpawnPlayer(int ID, string username, string scene, int instance, int IFF, int colorIndex, bool join = false)
		{
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Expected O, but got Unknown
			if ((Object)(object)Client.singleton != (Object)null && ID == Client.singleton.ID)
			{
				return;
			}
			Mod.LogInfo($"Spawn player called with ID: {ID}", debug: false);
			GameObject val = new GameObject("PlayerRoot" + ID);
			Object.DontDestroyOnLoad((Object)(object)val);
			PlayerManager playerManager = val.AddComponent<PlayerManager>();
			playerManager.Init(ID, username, scene, instance, IFF, colorIndex);
			players.Add(ID, playerManager);
			bool flag = false;
			if (playersByInstanceByScene.TryGetValue(scene, out var value))
			{
				if (value.TryGetValue(instance, out var value2))
				{
					value2.Add(ID);
					flag = value2.Count == 1;
				}
				else
				{
					value.Add(instance, new List<int> { ID });
					flag = true;
				}
			}
			else
			{
				Dictionary<int, List<int>> dictionary = new Dictionary<int, List<int>>();
				dictionary.Add(instance, new List<int> { ID });
				playersByInstanceByScene.Add(scene, dictionary);
				flag = true;
			}
			flag = (playerManager.firstInSceneInstance = flag & (sceneLoading || !scene.Equals(GameManager.scene) || instance != GameManager.instance));
			if (ThreadManager.host)
			{
				Server.clients[ID].player.firstInSceneInstance = flag;
			}
			if (activeInstances.ContainsKey(instance))
			{
				Dictionary<int, int> dictionary2 = activeInstances;
				int value3 = dictionary2[instance] + 1;
				dictionary2[instance] = value3;
			}
			else
			{
				activeInstances.Add(instance, 1);
			}
			UpdatePlayerHidden(playerManager);
			if (!nonSynchronizedScenes.ContainsKey(scene) && scene.Equals(GameManager.scene) && instance == GameManager.instance)
			{
				playersPresent.Add(ID);
				if (join)
				{
					firstPlayerInSceneInstance = false;
				}
			}
			if (GameManager.OnPlayerAdded != null)
			{
				GameManager.OnPlayerAdded(playerManager);
			}
		}

		public static IEnumerator InstantiatePlayerBody(FVRObject playerModelFVRObject, string playerPrefabID)
		{
			yield return ((AnvilAsset)playerModelFVRObject).GetGameObjectAsync();
			GameObject prefab = ((AnvilAsset)playerModelFVRObject).GetGameObject();
			if ((Object)(object)prefab == (Object)null)
			{
				Mod.LogWarning("Attempted to instantiate player model \"" + playerPrefabID + "\" but failed to get prefab. Using Default instead.");
				GameManager.playerPrefabID = "Default";
			}
			currentPlayerBody = Object.Instantiate<GameObject>(prefab).GetComponent<PlayerBody>();
			playerModelAwaitingInstantiation = false;
		}

		public static void Reset()
		{
			foreach (KeyValuePair<int, PlayerManager> player in players)
			{
				Object.Destroy((Object)(object)((Component)player.Value).gameObject);
			}
			players.Clear();
			objects.Clear();
			spectatorHosts.Clear();
			trackedObjectByObject.Clear();
			trackedObjectByInteractive.Clear();
			trackedObjectByDamageable.Clear();
			trackedItemByItem.Clear();
			trackedSosigBySosig.Clear();
			trackedItemBySosigWeapon.Clear();
			trackedAutoMeaterByAutoMeater.Clear();
			trackedEncryptionByEncryption.Clear();
			trackedBreakableGlassByBreakableGlass.Clear();
			trackedBreakableGlassByBreakableGlassDamager.Clear();
			trackedBlisterByBlister.Clear();
			trackedFloaterByFloater.Clear();
			trackedGatlingGunByGatlingGun.Clear();
			trackedBrutBlockSystemByBrutBlockSystem.Clear();
			trackedIrisByIris.Clear();
			trackedSentinelBySentinel.Clear();
			trackedNodeByNode.Clear();
			trackedObjectByShatterable.Clear();
			if (playersAtLoadStart != null)
			{
				playersAtLoadStart.Clear();
			}
			activeInstances.Clear();
			TNHInstances.Clear();
			playersByInstanceByScene.Clear();
			objectsByInstanceByScene.Clear();
			ID = 0;
			instance = 0;
			giveControlOfDestroyed = 0;
			controlOverride = false;
			firstPlayerInSceneInstance = false;
			dontAddToInstance = false;
			playersPresent.Clear();
			playerStateAddtionalDataSize = -1;
			sceneLoading = false;
			instanceAtSceneLoadStart = 0;
			ping = -1L;
			colorByIFF = false;
			nameplateMode = 1;
			radarMode = 0;
			radarColor = true;
			maxHealthIndex = -1;
			maxHealthByInstanceByScene.Clear();
			spectatorHost = false;
			((Behaviour)GM.CurrentPlayerBody.EyeCam).enabled = true;
			spectatorHostControlledBy = -1;
			controlledSpectatorHost = -1;
			for (int i = 0; i < TrackedObject.trackedReferenceObjects.Length; i++)
			{
				if ((Object)(object)TrackedObject.trackedReferenceObjects[i] != (Object)null)
				{
					Object.Destroy((Object)(object)TrackedObject.trackedReferenceObjects[i]);
				}
			}
			TrackedObject.trackedReferenceObjects = (GameObject[])(object)new GameObject[100];
			TrackedObject.trackedReferences = new TrackedObject[100];
			TrackedObject.availableTrackedRefIndices = new List<int>
			{
				1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
				11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
				21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
				31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
				41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
				51, 52, 53, 54, 55, 56, 57, 58, 59, 60,
				61, 62, 63, 64, 65, 66, 67, 68, 69, 70,
				71, 72, 73, 74, 75, 76, 77, 78, 79, 80,
				81, 82, 83, 84, 85, 86, 87, 88, 89, 90,
				91, 92, 93, 94, 95, 96, 97, 98, 99
			};
			TrackedObject.unknownTrackedIDs.Clear();
			TrackedObject.unknownParentWaitList.Clear();
			TrackedObject.unknownControlTrackedIDs.Clear();
			TrackedObject.unknownDestroyTrackedIDs.Clear();
			TrackedObject.unknownParentTrackedIDs.Clear();
			TrackedItem.unknownCrateHolding.Clear();
			TrackedItem.unknownSosigInventoryItems.Clear();
			TrackedItem.unknownSosigInventoryObjects.Clear();
			TrackedItem.unknownGasCuboidGout.Clear();
			TrackedItem.unknownGasCuboidDamageHandle.Clear();
			TrackedSosig.unknownBodyStates.Clear();
			TrackedSosig.unknownIFFChart.Clear();
			TrackedSosig.unknownItemInteract.Clear();
			TrackedSosig.unknownSetIFFs.Clear();
			TrackedSosig.unknownSetOriginalIFFs.Clear();
			TrackedSosig.unknownTNHKills.Clear();
			TrackedSosig.unknownCurrentOrder.Clear();
			TrackedSosig.unknownConfiguration.Clear();
			TrackedSosig.unknownWearable.Clear();
			TrackedEncryption.unknownDisableSubTarg.Clear();
			TrackedEncryption.unknownInit.Clear();
			TrackedEncryption.unknownResetGrowth.Clear();
			TrackedEncryption.unknownSpawnGrowth.Clear();
			TrackedEncryption.unknownSpawnSubTarg.Clear();
			TrackedEncryption.unknownSpawnSubTargGeo.Clear();
			TrackedEncryption.unknownUpdateDisplay.Clear();
			TrackedEncryption.unknownPreviewPos.Clear();
			TrackedEncryption.unknownShieldRot.Clear();
			TrackedFloater.unknownFloaterBeginExploding.Clear();
			TrackedFloater.unknownFloaterBeginDefusing.Clear();
			TrackedFloater.unknownFloaterExplode.Clear();
			TrackedIris.unknownIrisShatter.Clear();
			TrackedIris.unknownIrisSetState.Clear();
			TrackedNode.unknownInit.Clear();
			TrackedSentinel.unknownInit.Clear();
		}

		public static void UpdatePlayerState(int ID, Vector3 position, Quaternion rotation, Vector3 headPos, Quaternion headRot, Vector3 torsoPos, Quaternion torsoRot, Vector3 leftHandPos, Quaternion leftHandRot, Vector3 rightHandPos, Quaternion rightHandRot, float health, int maxHealth, byte[] additionalData)
		{
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: 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)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: 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)
			if (!players.ContainsKey(ID))
			{
				Mod.LogWarning($"Received UDP order to update player {ID} state but player of this ID hasnt been spawned yet");
				return;
			}
			PlayerManager playerManager = players[ID];
			playerManager.EnqueuePositionData(position, rotation, headPos, headRot, torsoPos, torsoRot, leftHandPos, leftHandRot, rightHandPos, rightHandRot);
			float health2 = playerManager.health;
			playerManager.health = health;
			int maxHealth2 = playerManager.maxHealth;
			playerManager.maxHealth = maxHealth;
			if ((Object)(object)playerManager.playerBody != (Object)null && (health != health2 || maxHealth != maxHealth2))
			{
				playerManager.playerBody.UpdateHealthLabel();
			}
			if ((health <= 0f && playerManager.visible) || (health > 0f && !playerManager.visible))
			{
				UpdatePlayerHidden(playerManager);
			}
		}

		public static void UpdatePlayerScene(int playerID, string sceneName)
		{
			Mod.LogInfo("Player " + playerID + " joining scene " + sceneName, debug: false);
			PlayerManager value = null;
			if (!players.TryGetValue(playerID, out value))
			{
				return;
			}
			playersByInstanceByScene[value.scene][value.instance].Remove(value.ID);
			if (playersByInstanceByScene[value.scene][value.instance].Count == 0)
			{
				playersByInstanceByScene[value.scene].Remove(value.instance);
			}
			if (playersByInstanceByScene[value.scene].Count == 0)
			{
				playersByInstanceByScene.Remove(value.scene);
			}
			if (value.scene.Equals(scene) && !nonSynchronizedScenes.ContainsKey(value.scene) && instance == value.instance)
			{
				playersPresent.Remove(playerID);
			}
			value.scene = sceneName;
			bool flag = false;
			if (playersByInstanceByScene.TryGetValue(value.scene, out var value2))
			{
				if (value2.TryGetValue(value.instance, out var value3))
				{
					value3.Add(value.ID);
					flag = value3.Count == 1;
				}
				else
				{
					value2.Add(value.instance, new List<int> { value.ID });
					flag = true;
				}
			}
			else
			{
				Dictionary<int, List<int>> dictionary = new Dictionary<int, List<int>>();
				dictionary.Add(value.instance, new List<int> { value.ID });
				playersByInstanceByScene.Add(value.scene, dictionary);
				flag = true;
			}
			flag = (value.firstInSceneInstance = flag & (sceneLoading || !value.scene.Equals(scene) || value.instance != instance));
			if (ThreadManager.host)
			{
				Server.clients[playerID].player.scene = sceneName;
				Server.clients[playerID].player.firstInSceneInstance = flag;
			}
			UpdatePlayerHidden(value);
			if (sceneName.Equals(scene) && !nonSynchronizedScenes.ContainsKey(sceneName) && instance == value.instance)
			{
				playersPresent.Add(playerID);
			}
		}

		public static bool UpdatePlayerHidden(PlayerManager player)
		{
			bool flag = true;
			flag &= !nonSynchronizedScenes.ContainsKey(player.scene) && player.scene.Equals(scene) && player.instance == instance && !spectatorHosts.Contains(player.ID) && player.health > 0f;
			if (flag && Mod.currentTNHInstance != null)
			{
				flag &= !Mod.currentTNHInstance.dead.Contains(player.ID);
				if (!flag && (Object)(object)player.reticleContact != (Object)null)
				{
					if ((Object)(object)Mod.currentTNHInstance.manager != (Object)null && (Object)(object)Mod.currentTNHInstance.manager.TAHReticle != (Object)null)
					{
						for (int i = 0; i < Mod.currentTNHInstance.manager.TAHReticle.Contacts.Count; i++)
						{
							if ((Object)(object)Mod.currentTNHInstance.manager.TAHReticle.Contacts[i] == (Object)(object)player.reticleContact)
							{
								GM.TNH_Manager.TAHReticle.m_trackedTransforms.Remove(GM.TNH_Manager.TAHReticle.Contacts[i].TrackedTransform);
								Object.Destroy((Object)(object)((Component)Mod.currentTNHInstance.manager.TAHReticle.Contacts[i]).gameObject);
								Mod.currentTNHInstance.manager.TAHReticle.Contacts.RemoveAt(i);
								player.reticleContact = null;
								break;
							}
						}
					}
				}
				else if (flag && (Object)(object)player.reticleContact == (Object)null && (Object)(object)Mod.currentTNHInstance.manager != (Object)null && Mod.currentTNHInstance.currentlyPlaying.Contains(player.ID))
				{
					switch (radarMode)
					{
					case 0:
						player.reticleContact = GM.TNH_Manager.TAHReticle.RegisterTrackedObject(player.head, (ContactType)((!radarColor) ? (player.colorIndex - 4) : ((player.IFF == GM.CurrentPlayerBody.GetPlayerIFF()) ? (-2) : (-3))));
						break;
					case 1:
						if (player.IFF == GM.CurrentPlayerBody.GetPlayerIFF())
						{
							player.reticleContact = GM.TNH_Manager.TAHReticle.RegisterTrackedObject(player.head, (ContactType)((!radarColor) ? (player.colorIndex - 4) : ((player.IFF == GM.CurrentPlayerBody.GetPlayerIFF()) ? (-2) : (-3))));
						}
						break;
					}
				}
			}
			if (GameManager.OnUpdatePlayerHidden != null)
			{
				GameManager.OnUpdatePlayerHidden(player, ref flag);
			}
			player.SetVisible(flag);
			return flag;
		}

		public static void UpdatePlayerInstance(int playerID, int instance)
		{
			//IL_01ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e3: Unknown result type (might be due to invalid IL or missing references)
			Mod.LogInfo("Player " + playerID + " joining instance " + instance, debug: false);
			PlayerManager playerManager = players[playerID];
			if (activeInstances.ContainsKey(playerManager.instance))
			{
				Dictionary<int, int> dictionary = activeInstances;
				int key = playerManager.instance;
				int value = dictionary[key] - 1;
				dictionary[key] = value;
				if (activeInstances[playerManager.instance] == 0)
				{
					activeInstances.Remove(playerManager.instance);
				}
			}
			if (TNHInstances.TryGetValue(playerManager.instance, out var value2))
			{
				int num = value2.playerIDs[0];
				value2.playerIDs.Remove(playerID);
				if (value2.playerIDs.Count == 0)
				{
					TNHInstances.Remove(playerManager.instance);
					if ((Object)(object)Mod.TNHInstanceList != (Object)null && Mod.joinTNHInstances != null && Mod.joinTNHInstances.ContainsKey(instance))
					{
						Object.Destroy((Object)(object)Mod.joinTNHInstances[instance]);
						Mod.joinTNHInstances.Remove(instance);
					}
					if (Mod.currentTNHInstance != null && Mod.currentTNHInstance.instance == playerManager.instance)
					{
						Mod.TNHSpectating = false;
						if ((Object)(object)GM.CurrentPlayerBody != (Object)null)
						{
							GM.CurrentPlayerBody.SetPlayerIFF(GM.CurrentSceneSettings.DefaultPlayerIFF);
							if ((Object)(object)GM.CurrentPlayerBody.RightHand != (Object)null && (Object)(object)GM.CurrentPlayerBody.LeftHand != (Object)null)
							{
								((Component)GM.CurrentPlayerBody.RightHand).GetComponent<FVRViveHand>().Mode = (HandMode)0;
								((Component)GM.CurrentPlayerBody.LeftHand).GetComponent<FVRViveHand>().Mode = (HandMode)0;
							}
						}
					}
				}
				else
				{
					if ((Object)(object)Mod.TNHMenu != (Object)null && (Object)(object)Mod.TNHPlayerList != (Object)null && (Object)(object)Mod.TNHPlayerPrefab != (Object)null && Mod.currentTNHInstancePlayers != null && Mod.currentTNHInstancePlayers.ContainsKey(playerID))
					{
						Object.Destroy((Object)(object)Mod.currentTNHInstancePlayers[playerID]);
						Mod.currentTNHInstancePlayers.Remove(playerID);
						if (num != value2.playerIDs[0])
						{
							Text component = ((Component)Mod.currentTNHInstancePlayers[value2.playerIDs[0]].transform.GetChild(0)).GetComponent<Text>();
							component.text += " (Host)";
						}
					}
					value2.currentlyPlaying.Remove(playerID);
					value2.played.Remove(playerID);
					value2.dead.Remove(playerID);
				}
			}
			if (GameManager.OnPlayerInstanceChanged != null)
			{
				GameManager.OnPlayerInstanceChanged(playerManager.ID, playerManager.instance, instance);
			}
			playersByInstanceByScene[playerManager.scene][playerManager.instance].Remove(playerManager.ID);
			if (playersByInstanceByScene[playerManager.scene][playerManager.instance].Count == 0)
			{
				playersByInstanceByScene[playerManager.scene].Remove(playerManager.instance);
			}
			if (playerManager.scene.Equals(scene) && !nonSynchronizedScenes.ContainsKey(playerManager.scene) && GameManager.instance == playerManager.instance)
			{
				playersPresent.Remove(playerID);
			}
			playerManager.instance = instance;
			bool flag = false;
			if (playersByInstanceByScene[playerManager.scene].TryGetValue(instance, out var value3))
			{
				value3.Add(playerManager.ID);
				flag = value3.Count == 1;
			}
			else
			{
				playersByInstanceByScene[playerManager.scene].Add(instance, new List<int> { playerManager.ID });
				flag = true;
			}
			flag = (playerManager.firstInSceneInstance = flag & (sceneLoading || !playerManager.scene.Equals(scene) || playerManager.instance != GameManager.instance));
			if (ThreadManager.host)
			{
				Server.clients[playerID].player.instance = instance;
				Server.clients[playerID].player.firstInSceneInstance = flag;
			}
			UpdatePlayerHidden(playerManager);
			if (playerManager.scene.Equals(scene) && !nonSynchronizedScenes.ContainsKey(playerManager.scene) && GameManager.instance == playerManager.instance)
			{
				playersPresent.Add(playerID);
			}
			if (activeInstances.ContainsKey(instance))
			{
				Dictionary<int, int> dictionary2 = activeInstances;
				int value = instance;
				int key = dictionary2[value] + 1;
				dictionary2[value] = key;
			}
			else
			{
				activeInstances.Add(instance, 1);
			}
			if (TNHInstances.ContainsKey(instance) && !TNHInstances[instance].playerIDs.Contains(playerID))
			{
				TNHInstances[instance].playerIDs.Add(playerID);
				if ((Object)(object)Mod.TNHMenu != (Object)null && (Object)(object)Mod.TNHPlayerList != (Object)null && (Object)(object)Mod.TNHPlayerPrefab != (Object)null && Mod.currentTNHInstancePlayers != null && !Mod.currentTNHInstancePlayers.ContainsKey(playerID))
				{
					GameObject val = Object.Instantiate<GameObject>(Mod.TNHPlayerPrefab, Mod.TNHPlayerList.transform);
					((Component)val.transform.GetChild(0)).GetComponent<Text>().text = playerManager.username;
					val.SetActive(true);
					Mod.currentTNHInstancePlayers.Add(playerID, val);
				}
			}
		}

		public static void SetPlayerColor(int ID, int index, bool received = false, int clientID = 0, bool send = true)
		{
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)Mod.managerObject == (Object)null)
			{
				colorIndex = index;
				if ((Object)(object)BodyWristMenuSection.colorText != (Object)null)
				{
					BodyWristMenuSection.colorText.text = "Current color: " + colorNames[colorIndex];
				}
				return;
			}
			if (GameManager.ID == ID)
			{
				colorIndex = index;
				if ((Object)(object)currentPlayerBody != (Object)null)
				{
					currentPlayerBody.SetColor(colors[colorIndex]);
				}
				if ((Object)(object)BodyWristMenuSection.colorText != (Object)null)
				{
					BodyWristMenuSection.colorText.text = "Current color: " + colorNames[colorIndex];
				}
			}
			else
			{
				players[ID].SetColor(index);
				if (ThreadManager.host)
				{
					Server.clients[ID].player.colorIndex = index;
				}
			}
			if (send)
			{
				if (ThreadManager.host)
				{
					ServerSend.PlayerColor(ID, index, clientID);
				}
				else if (!received)
				{
					ClientSend.PlayerColor(ID, index);
				}
			}
		}

		public static void SetPlayerPrefab(string prefabID)
		{
			string text = playerPrefabID;
			if (playerPrefabs.ContainsKey(prefabID))
			{
				playerPrefabID = prefabID;
			}
			else if ((Object)(object)Mod.managerObject == (Object)null)
			{
				playerPrefabID = "None";
			}
			else
			{
				playerPrefabID = "Default";
			}
			if (text.Equals(playerPrefabID) && (Object)(object)currentPlayerBody != (Object)null)
			{
				return;
			}
			if ((Object)(object)currentPlayerBody != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)currentPlayerBody).gameObject);
			}
			if (playerPrefabID.Equals("None"))
			{
				return;
			}
			if (playerPrefabID.Equals("Default"))
			{
				Object obj = playerPrefabs["Default"];
				currentPlayerBody = Object.Instantiate<GameObject>((GameObject)(object)((obj is GameObject) ? obj : null)).GetComponent<PlayerBody>();
			}
			else
			{
				bool flag = false;
				if (playerPrefabs.TryGetValue(playerPrefabID, out var value))
				{
					if (value == (Object)null)
					{
						if (IM.OD.TryGetValue(playerPrefabID, out var value2) && (Object)(object)value2 != (Object)null)
						{
							flag = true;
							playerModelAwaitingInstantiation = true;
							AnvilManager.Run(InstantiatePlayerBody(value2, playerPrefabID));
						}
					}
					else if (value is FVRObject)
					{
						flag = true;
						playerModelAwaitingInstantiation = true;
						AnvilManager.Run(InstantiatePlayerBody((FVRObject)(object)((value is FVRObject) ? value : null), playerPrefabID));
					}
				}
				if (!flag)
				{
					Mod.LogWarning("Attempt to set player prefab to \"" + playerPrefabID + "\" failed, could not obtain prefab, using default");
					playerPrefabID = "Default";
					Object obj2 = playerPrefabs[playerPrefabID];
					currentPlayerBody = Object.Instantiate<GameObject>((GameObject)(object)((obj2 is GameObject) ? obj2 : null)).GetComponent<PlayerBody>();
				}
			}
			if ((Object)(object)BodyWristMenuSection.playerBodyText != (Object)null)
			{
				BodyWristMenuSection.playerBodyText.text = "Body: " + playerPrefabID;
			}
		}

		public static void AddPlayerPrefabID(string newPlayerPrefabID)
		{
			if (newPlayerPrefabID.Equals("Default"))
			{
				Mod.LogError("A mod attempted to register \"Default\" player prefab ID:\n" + Environment.StackTrace);
				return;
			}
			playerPrefabs.Add(newPlayerPrefabID, null);
			playerPrefabIDs.Add(newPlayerPrefabID);
		}

		public static void SyncTrackedObjects(bool init = false, bool inControl = false)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			if (!ThreadManager.host && !Client.singleton.gotConnectSync)
			{
				return;
			}
			Scene activeScene = SceneManager.GetActiveScene();
			GameObject[] rootGameObjects = ((Scene)(ref activeScene)).GetRootGameObjects();
			GameObject[] array = rootGameObjects;
			foreach (GameObject val in array)
			{
				SyncTrackedObjects(val.transform, init ? inControl : controlOverride, null);
			}
			_ = Mod.DDOLScene;
			if (true)
			{
				rootGameObjects = ((Scene)(ref Mod.DDOLScene)).GetRootGameObjects();
				GameObject[] array2 = rootGameObjects;
				foreach (GameObject val2 in array2)
				{
					SyncTrackedObjects(val2.transform, init ? inControl : controlOverride, null);
				}
			}
		}

		public static void SyncTrackedObjects(Transform root, bool controlEverything, TrackedObjectData parent)
		{
			//IL_01fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0204: Expected O, but got Unknown
			//IL_016d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0174: Expected O, but got Unknown
			if (!ThreadManager.host && !Client.singleton.gotConnectSync)
			{
				return;
			}
			if (GetTrackedObjectType(root, out var trackedObjectType))
			{
				TrackedObject component = ((Component)root).GetComponent<TrackedObject>();
				if ((Object)(object)component == (Object)null)
				{
					if (controlEverything || IsControlled(root, trackedObjectType))
					{
						TrackedObject trackedObject = MakeObjectTracked(root, parent, trackedObjectType);
						if (!((Object)(object)trackedObject != (Object)null))
						{
							return;
						}
						if (trackedObject.awoken)
						{
							if (ThreadManager.host)
							{
								Mod.LogInfo("Server made new object tracked with type ID: " + trackedObject.data.typeIdentifier, debug: false);
								Server.AddTrackedObject(trackedObject.data, 0);
							}
							else
							{
								trackedObject.data.localWaitingIndex = Client.localObjectCounter++;
								Mod.LogInfo("Client made new object tracked with local waiting index: " + trackedObject.data.localWaitingIndex + " and type ID: " + trackedObject.data.typeIdentifier, debug: false);
								Client.waitingLocalObjects.Add(trackedObject.data.localWaitingIndex, trackedObject.data);
								ClientSend.TrackedObject(trackedObject.data);
							}
							trackedObject.data.OnTracked();
						}
						else
						{
							trackedObject.sendOnAwake = true;
						}
						{
							foreach (Transform item in root)
							{
								Transform root2 = item;
								SyncTrackedObjects(root2, controlEverything, trackedObject.data);
							}
							return;
						}
					}
					if (TrackSkipped(root, trackedObjectType))
					{
						Object.Destroy((Object)(object)((Component)root).gameObject);
					}
				}
				else
				{
					parent?.children.Add(component.data);
				}
				return;
			}
			foreach (Transform item2 in root)
			{
				Transform root3 = item2;
				SyncTrackedObjects(root3, controlEverything, parent);
			}
		}

		private static TrackedObject MakeObjectTracked(Transform root, TrackedObjectData parent, Type trackedObjectType)
		{
			Mod.LogInfo("Making tracked object from " + ((Object)root).name, debug: false);
			return (TrackedObject)trackedObjectType.GetMethod("MakeTracked", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).Invoke(null, new object[2] { root, parent });
		}

		public static TNHInstance AddNewTNHInstance(int hostID, bool letPeopleJoin, int progressionTypeSetting, int healthModeSetting, int equipmentModeSetting, int targetModeSetting, int AIDifficultyModifier, int radarModeModifier, int itemSpawnerMode, int backpackMode, int healthMult, int sosiggunShakeReloading, int TNHSeed, string levelID)
		{
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Expected O, but got Unknown
			if (ThreadManager.host)
			{
				int freeInstance = 1;
				while (activeInstances.ContainsKey(freeInstance))
				{
					int num = freeInstance + 1;
					freeInstance = num;
				}
				TNHInstance tNHInstance = new TNHInstance(freeInstance, hostID, letPeopleJoin, progressionTypeSetting, healthModeSetting, equipmentModeSetting, targetModeSetting, AIDifficultyModifier, radarModeModifier, itemSpawnerMode, backpackMode, healthMult, sosiggunShakeReloading, TNHSeed, levelID);
				TNHInstances.Add(freeInstance, tNHInstance);
				if ((tNHInstance.letPeopleJoin || tNHInstance.currentlyPlaying.Count == 0) && (Object)(object)Mod.TNHInstanceList != (Object)null && Mod.joinTNHInstances != null && !Mod.joinTNHInstances.ContainsKey(freeInstance))
				{
					GameObject val = Object.Instantiate<GameObject>(Mod.TNHInstancePrefab, Mod.TNHInstanceList.transform);
					((Component)val.transform.GetChild(0)).GetComponent<Text>().text = "Instance " + freeInstance;
					val.SetActive(true);
					FVRPointableButton val2 = val.AddComponent<FVRPointableButton>();
					val2.SetButton();
					((FVRPointable)val2).MaxPointingRange = 5f;
					((UnityEvent)val2.Button.onClick).AddListener((UnityAction)delegate
					{
						Mod.OnTNHInstanceClicked(freeInstance);
					});
					Mod.joinTNHInstances.Add(freeInstance, val);
				}
				activeInstances.Add(freeInstance, 0);
				Mod.modInstance.OnTNHInstanceReceived(tNHInstance);
				return tNHInstance;
			}
			ClientSend.AddTNHInstance(hostID, letPeopleJoin, progressionTypeSetting, healthModeSetting, equipmentModeSetting, targetModeSetting, AIDifficultyModifier, radarModeModifier, itemSpawnerMode, backpackMode, healthMult, sosiggunShakeReloading, TNHSeed, levelID);
			return null;
		}

		public static int AddNewInstance()
		{
			if (ThreadManager.host)
			{
				int i;
				for (i = 1; activeInstances.ContainsKey(i); i++)
				{
				}
				activeInstances.Add(i, 0);
				Mod.modInstance.OnInstanceReceived(i);
				ServerSend.AddInstance(i);
				return i;
			}
			ClientSend.AddInstance();
			return -1;
		}

		public static void AddTNHInstance(TNHInstance instance)
		{
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			//IL_014b: Expected O, but got Unknown
			if (!activeInstances.ContainsKey(instance.instance))
			{
				activeInstances.Add(instance.instance, instance.playerIDs.Count);
			}
			TNHInstances.Add(instance.instance, instance);
			if ((instance.letPeopleJoin || instance.currentlyPlaying.Count == 0) && (Object)(object)Mod.TNHInstanceList != (Object)null && Mod.joinTNHInstances != null && !Mod.joinTNHInstances.ContainsKey(instance.instance))
			{
				GameObject val = Object.Instantiate<GameObject>(Mod.TNHInstancePrefab, Mod.TNHInstanceList.transform);
				((Component)val.transform.GetChild(0)).GetComponent<Text>().text = "Instance " + instance.instance;
				val.SetActive(true);
				FVRPointableButton val2 = val.AddComponent<FVRPointableButton>();
				val2.SetButton();
				((FVRPointable)val2).MaxPointingRange = 5f;
				((UnityEvent)val2.Button.onClick).AddListener((UnityAction)delegate
				{
					Mod.OnTNHInstanceClicked(instance.instance);
				});
				Mod.joinTNHInstances.Add(instance.instance, val);
			}
			dontAddToInstance = Mod.setLatestInstance;
			Mod.modInstance.OnTNHInstanceReceived(instance);
		}

		public static void AddInstance(int instance)
		{
			if (!activeInstances.ContainsKey(instance))
			{
				activeInstances.Add(instance, 0);
			}
			Mod.modInstance.OnInstanceReceived(instance);
		}

		public static void SetInstance(int instance)
		{
			//IL_01da: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ef: Unknown result type (might be due to invalid IL or missing references)
			Mod.LogInfo("Changing instance from " + GameManager.instance + " to " + instance + ":\n" + Environment.StackTrace, debug: false);
			if (activeInstances.ContainsKey(GameManager.instance))
			{
				Dictionary<int, int> dictionary = activeInstances;
				int key = GameManager.instance;
				int value = dictionary[key] - 1;
				dictionary[key] = value;
				if (activeInstances[GameManager.instance] == 0)
				{
					activeInstances.Remove(GameManager.instance);
				}
			}
			else
			{
				Mod.LogError("Instance we are leaving is missing from active instances!");
			}
			if (GameManager.OnInstanceLeft != null)
			{
				GameManager.OnInstanceLeft(GameManager.instance, instance);
			}
			if (TNHInstances.TryGetValue(GameManager.instance, out var value2))
			{
				value2.playerIDs.Remove(ID);
				if (value2.playerIDs.Count == 0)
				{
					TNHInstances.Remove(GameManager.instance);
					if ((Object)(object)Mod.TNHInstanceList != (Object)null && Mod.joinTNHInstances.ContainsKey(instance))
					{
						Object.Destroy((Object)(object)Mod.joinTNHInstances[instance]);
						Mod.joinTNHInstances.Remove(instance);
					}
					Mod.TNHSpectating = false;
					if ((Object)(object)GM.CurrentPlayerBody != (Object)null)
					{
						GM.CurrentPlayerBody.SetPlayerIFF(GM.CurrentSceneSettings.DefaultPlayerIFF);
						if ((Object)(object)GM.CurrentPlayerBody.RightHand != (Object)null && (Object)(object)GM.CurrentPlayerBody.LeftHand != (Object)null)
						{
							((Component)GM.CurrentPlayerBody.RightHand).GetComponent<FVRViveHand>().Mode = (HandMode)0;
							((Component)GM.CurrentPlayerBody.LeftHand).GetComponent<FVRViveHand>().Mode = (HandMode)0;
						}
					}
				}
				value2.currentlyPlaying.Remove(ID);
				value2.dead.Remove(ID);
				if (controlledSpectatorHost != -1 && value2.currentlyPlaying.Count > 1 && value2.currentlyPlaying.Contains(controlledSpectatorHost))
				{
					if (ThreadManager.host)
					{
						ReassignSpectatorHost(0, new List<int> { 0 });
					}
					else
					{
						ClientSend.ReassignSpectatorHost(new List<int> { ID });
					}
					Mod.OnSpectatorHostGiveUpInvoke();
				}
			}
			if (!sceneLoading)
			{
				if (playersByInstanceByScene.TryGetValue(scene, out var value3))
				{
					if (value3.TryGetValue(GameManager.instance, out var value4))
					{
						playersAtLoadStart = value4;
					}
					else
					{
						playersAtLoadStart = null;
					}
				}
				else
				{
					playersAtLoadStart = null;
				}
			}
			int source = GameManager.instance;
			GameManager.instance = instance;
			if (!activeInstances.ContainsKey(instance))
			{
				activeInstances.Add(instance, 0);
			}
			if (dontAddToInstance)
			{
				dontAddToInstance = false;
			}
			else
			{
				Dictionary<int, int> dictionary2 = activeInstances;
				int value = instance;
				int key = dictionary2[value] + 1;
				dictionary2[value] = key;
			}
			instanceBringItems = !playersByInstanceByScene.TryGetValue(sceneLoading ? LoadLevelBeginPatch.loadingLevel : scene, out var value5) || !value5.TryGetValue(instance, out var value6) || value6.Count == 0;
			if (GameManager.OnInstanceJoined != null)
			{
				GameManager.OnInstanceJoined(instance, source);
			}
			if (TNHInstances.ContainsKey(instance))
			{
				if (!TNHInstances[instance].playerIDs.Contains(ID))
				{
					TNHInstances[instance].playerIDs.Add(ID);
				}
				if ((Object)(object)Mod.currentTNHUIManager != (Object)null)
				{
					Mod.InitTNHUIManager(TNHInstances[instance]);
				}
				else
				{
					Mod.currentTNHUIManager = Object.FindObjectOfType<TNH_UIManager>();
					Mod.currentTNHSceneLoader = Object.FindObjectOfType<SceneLoader>();
					if ((Object)(object)Mod.currentTNHUIManager != (Object)null)
					{
						Mod.InitTNHUIManager(TNHInstances[instance]);
					}
				}
			}
			if (sceneLoading)
			{
				controlOverride = instanceBringItems;
				firstPlayerInSceneInstance = instanceBringItems;
			}
			if (ThreadManager.host)
			{
				ServerSend.PlayerInstance(0, instance);
			}
			else
			{
				ClientSend.PlayerInstance(instance, sceneLoading);
			}
			playersPresent.Clear();
			if (!nonSynchronizedScenes.ContainsKey(scene))
			{
				foreach (KeyValuePair<int, PlayerManager> player in players)
				{
					if (player.Value.scene.Equals(scene) && player.Value.instance == instance)
					{
						playersPresent.Add(player.Key);
						if (ThreadManager.host && !sceneLoading)
						{
							if (Server.clientsWaitingUpDate.TryGetValue(player.Key, out var value7))
							{
								value7.Add(0);
							}
							else
							{
								Server.clientsWaitingUpDate.Add(player.Key, new List<int> { 0 });
							}
							if (Server.loadingClientsWaitingFrom.TryGetValue(0, out var value8))
							{
								value8.Add(player.Key);
							}
							else
							{
								Server.loadingClientsWaitingFrom.Add(0, new List<int> { player.Key });
							}
							ServerSend.RequestUpToDateObjects(player.Key, instantiateOnReceive: true, 0);
						}
					}
					UpdatePlayerHidden(player.Value);
				}
			}
			else
			{
				foreach (KeyValuePair<int, PlayerManager> player2 in players)
				{
					UpdatePlayerHidden(player2.Value);
				}
			}
			H3MPWristMenuSection.UpdateMaxHealth(scene, instance, -2, -1f);
		}

		public static void DestroyTrackedScripts(TrackedObjectData trackedObjectData)
		{
			if (trackedObjectData.children != null)
			{
				for (int i = 0; i < trackedObjectData.children.Count; i++)
				{
					DestroyTrackedScripts(trackedObjectData.children[i]);
				}
			}
			if ((Object)(object)trackedObjectData.physical != (Object)null)
			{
				Object.DestroyImmediate((Object)(object)trackedObjectData.physical);
			}
		}

		public static void ReassignSpectatorHost(int clientID, List<int> debounce)
		{
			if (!Server.spectatorHostByController.TryGetValue(clientID, out var value))
			{
				return;
			}
			List<int> list = new List<int>();
			if (scene.Equals(Server.clients[clientID].player.scene) && instance == Server.clients[clientID].player.instance)
			{
				list.Add(0);
			}
			if (playersByInstanceByScene.TryGetValue(Server.clients[clientID].player.scene, out var value2) && value2.TryGetValue(Server.clients[clientID].player.instance, out var value3))
			{
				list.AddRange(value3);
			}
			list.RemoveRange(0, debounce.Count);
			int num = -1;
			if (list.Count > 0)
			{
				num = Mod.GetBestPotentialObjectHost(clientID, forUs: false);
			}
			if (num == -1)
			{
				Server.spectatorHostByController.Remove(clientID);
				Server.spectatorHostControllers.Remove(value);
				if (spectatorHosts.Contains(value))
				{
					Server.availableSpectatorHosts.Add(value);
				}
				if (value == ID)
				{
					spectatorHostControlledBy = -1;
					if (!sceneLoading)
					{
						if (!scene.Equals("MainMenu3"))
						{
							SteamVR_LoadLevel.Begin("MainMenu3", false, 0.5f, 0f, 0f, 0f, 1f);
						}
					}
					else
					{
						resetSpectatorHost = true;
					}
				}
				else
				{
					ServerSend.UnassignSpectatorHost(value);
				}
			}
			else
			{
				Server.spectatorHostByController.Remove(clientID);
				Server.spectatorHostControllers.Remove(value);
				Server.spectatorHostByController.Add(num, value);
				Server.spectatorHostControllers.Add(value, num);
				if (value == 0)
				{
					spectatorHostControlledBy = num;
				}
				else if (num == 0)
				{
					Mod.OnSpectatorHostReceivedInvoke(value, reassignment: true);
				}
				ServerSend.SpectatorHostAssignment(value, num, reassignment: true);
			}
		}

		public static bool GetTrackedObjectType(Transform t, out Type trackedObjectType)
		{
			List<Type> list = new List<Type>();
			foreach (KeyValuePair<Type, List<Type>> trackedObjectType2 in Mod.trackedObjectTypes)
			{
				for (int num = trackedObjectType2.Value.Count - 1; num >= 0; num--)
				{
					MethodInfo method = trackedObjectType2.Value[num].GetMethod("IsOfType", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
					if ((bool)method.Invoke(null, new object[1] { t }))
					{
						list.Add(trackedObjectType2.Value[num]);
						break;
					}
				}
			}
			if (list.Count == 0)
			{
				trackedObjectType = null;
				return false;
			}
			if (list.Count == 1)
			{
				trackedObjectType = list[0];
				return true;
			}
			Type type = list[0];
			for (int i = 0; i < list.Count; i++)
			{
				MethodInfo method2 = list[i].GetMethod("GetTypeOverrides", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				if ((object)method2 != null && method2.Invoke(null, null) is Type[] array)
				{
					int num2 = 0;
					while (num2 < array.Length)
					{
						list.Remove(array[i]);
						i++;
					}
				}
			}
			if (list.Count == 0)
			{
				Mod.LogWarning(((Object)t).name + " had conflicting possible tracked types overriding each other. Tracked as: " + type.Name);
				trackedObjectType = type;
			}
			else if (list.Count == 1)
			{
				trackedObjectType = list[0];
			}
			else
			{
				Mod.LogWarning(((Object)t).name + " had conflicting possible tracked types missing override. Tracked as: " + list[0].Name);
				trackedObjectType = list[0];
			}
			return true;
		}

		public static bool IsControlled(Transform root, Type trackedObjectType)
		{
			MethodInfo method = trackedObjectType.GetMethod("IsControlled", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
			if ((object)method != null && (object)method.ReturnType == typeof(bool) && (object)method.GetParameters()[0].ParameterType == typeof(Transform))
			{
				return (bool)method.Invoke(null, new object[1] { root });
			}
			return false;
		}

		public static bool TrackSkipped(Transform root, Type trackedObjectType)
		{
			MethodInfo method = trackedObjectType.GetMethod("TrackSkipped", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
			if ((object)method != null && (object)method.ReturnType == typeof(bool) && (object)method.GetParameters()[0].ParameterType == typeof(Transform))
			{
				return (bool)method.Invoke(null, new object[1] { root });
			}
			return true;
		}

		public static void OnSceneLoadedVR(bool loading)
		{
			//IL_018d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_023f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0254: Unknown result type (might be due to invalid IL or missing references)
			if (loading)
			{
				Mod.LogInfo("Switching scene, from " + scene + " to " + LoadLevelBeginPatch.loadingLevel, debug: false);
				sceneLoading = true;
				instanceAtSceneLoadStart = instance;
				sceneAtSceneLoadStart = scene;
				if ((Object)(object)Mod.managerObject == (Object)null)
				{
					connectedAtLoadStart = false;
					return;
				}
				connectedAtLoadStart = true;
				giveControlOfDestroyed++;
				Mod.skipAllInstantiates++;
				if (playersByInstanceByScene.TryGetValue(scene, out var value))
				{
					if (value.TryGetValue(instance, out var value2))
					{
						playersAtLoadStart = value2;
					}
					else
					{
						playersAtLoadStart = null;
					}
				}
				else
				{
					playersAtLoadStart = null;
				}
				if (LoadLevelBeginPatch.loadingLevel.Equals("MainMenu3") && Mod.currentTNHInstance != null)
				{
					SetInstance(0);
					if (Mod.currentlyPlayingTNH)
					{
						Mod.currentTNHInstance.RemoveCurrentlyPlaying(send: true, ID, ThreadManager.host);
						Mod.currentlyPlayingTNH = false;
					}
					Mod.currentTNHInstance = null;
					Mod.TNHSpectating = false;
					if ((Object)(object)GM.CurrentPlayerBody != (Object)null)
					{
						GM.CurrentPlayerBody.SetPlayerIFF(GM.CurrentSceneSettings.DefaultPlayerIFF);
						if ((Object)(object)GM.CurrentPlayerBody.RightHand != (Object)null && (Object)(object)GM.CurrentPlayerBody.LeftHand != (Object)null)
						{
							((Component)GM.CurrentPlayerBody.RightHand).GetComponent<FVRViveHand>().Mode = (HandMode)0;
							((Component)GM.CurrentPlayerBody.LeftHand).GetComponent<FVRViveHand>().Mode = (HandMode)0;
						}
					}
					Mod.currentlyPlayingTNH = false;
				}
				if (LoadLevelBeginPatch.loadingLevel.Equals("TakeAndHold_Lobby_2") && Mod.currentTNHInstance != null)
				{
					Mod.TNHSpectating = false;
					if ((Object)(object)GM.CurrentPlayerBody != (Object)null)
					{
						GM.CurrentPlayerBody.SetPlayerIFF(GM.CurrentSceneSettings.DefaultPlayerIFF);
						if ((Object)(object)GM.CurrentPlayerBody.RightHand != (Object)null && (Object)(object)GM.CurrentPlayerBody.LeftHand != (Object)null)
						{
							((Component)GM.CurrentPlayerBody.RightHand).GetComponent<FVRViveHand>().Mode = (HandMode)0;
							((Component)GM.CurrentPlayerBody.LeftHand).GetComponent<FVRViveHand>().Mode = (HandMode)0;
						}
					}
				}
				if (playersByInstanceByScene.TryGetValue(LoadLevelBeginPatch.loadingLevel, out var value3))
				{
					if (value3.TryGetValue(instance, out var value4))
					{
						controlOverride = value4.Count == 0;
						firstPlayerInSceneInstance = controlOverride;
					}
					else
					{
						controlOverride = true;
						firstPlayerInSceneInstance = true;
					}
				}
				else
				{
					controlOverride = true;
					firstPlayerInSceneInstance = true;
				}
				ClearUnawoken();
				if (GameManager.OnSceneLeft != null)
				{
					GameManager.OnSceneLeft(sceneAtSceneLoadStart, LoadLevelBeginPatch.loadingLevel);
				}
				return;
			}
			scene = LoadLevelBeginPatch.loadingLevel;
			sceneLoading = false;
			Mod.LogInfo("Arrived in scene: " + scene, debug: false);
			if ((Object)(object)Mod.managerObject != (Object)null)
			{
				if (ThreadManager.host)
				{
					ServerSend.PlayerScene(0, LoadLevelBeginPatch.loadingLevel);
				}
				else
				{
					ClientSend.PlayerScene(LoadLevelBeginPatch.loadingLevel);
				}
				if (connectedAtLoadStart)
				{
					Mod.skipAllInstantiates--;
					giveControlOfDestroyed--;
				}
				playersPresent.Clear();
				if (!nonSynchronizedScenes.ContainsKey(scene))
				{
					controlOverride = true;
					firstPlayerInSceneInstance = true;
					foreach (KeyValuePair<int, PlayerManager> player in players)
					{
						if (player.Value.scene.Equals(scene) && player.Value.instance == instance)
						{
							playersPresent.Add(player.Key);
							controlOverride = false;
							firstPlayerInSceneInstance = false;
							if (ThreadManager.host)
							{
								if (Server.clientsWaitingUpDate.TryGetValue(player.Key, out var value5))
								{
									value5.Add(0);
								}
								else
								{
									Server.clientsWaitingUpDate.Add(player.Key, new List<int> { 0 });
								}
								if (Server.loadingClientsWaitingFrom.TryGetValue(0, out var value6))
								{
									value6.Add(player.Key);
								}
								else
								{
									Server.loadingClientsWaitingFrom.Add(0, new List<int> { player.Key });
								}
								ServerSend.RequestUpToDateObjects(player.Key, instantiateOnReceive: true, 0);
							}
						}
						UpdatePlayerHidden(player.Value);
					}
					controlOverride &= connectedAtLoadStart;
					firstPlayerInSceneInstance &= connectedAtLoadStart;
					inPostSceneLoadTrack = true;
					SyncTrackedObjects();
					inPostSceneLoadTrack = false;
					controlOverride = false;
					for (int i = 0; i < objects.Count; i++)
					{
						if ((Object)(object)objects[i].physical == (Object)null && !objects[i].awaitingInstantiation)
						{
							objects[i].awaitingInstantiation = true;
							AnvilManager.Run(objects[i].Instantiate());
						}
					}
					if (Mod.spectatorHostWaitingForTNHSetup)
					{
						if (scene.Equals("TakeAndHold_Lobby_2"))
						{
							if (spectatorHostControlledBy != -1)
							{
								Mod.OnTNHHostClicked();
								Mod.TNHOnDeathSpectate = Mod.TNHRequestHostOnDeathSpectate;
								Mod.OnTNHHostConfirmClicked();
								if (ThreadManager.host)
								{
									ServerSend.TNHSpectatorHostReady(spectatorHostControlledBy, instance);
								}
								else
								{
									Mod.spectatorHostWaitingForTNHInstance = true;
								}
							}
							Mod.spectatorHostWaitingForTNHSetup = false;
						}
						else if (scene.Equals("MainMenu3"))
						{
							SteamVR_LoadLevel.Begin("TakeAndHold_Lobby_2", false, 0.5f, 0f, 0f, 0f, 1f);
							Mod.spectatorHostWaitingForTNHSetup = true;
						}
						else
						{
							SteamVR_LoadLevel.Begin("MainMenu3", false, 0.5f, 0f, 0f, 0f, 1f);
							Mod.spectatorHostWaitingForTNHSetup = true;
						}
					}
				}
				else
				{
					foreach (KeyValuePair<int, PlayerManager> player2 in players)
					{
						UpdatePlayerHidden(player2.Value);
					}
				}
				H3MPWristMenuSection.UpdateMaxHealth(scene, instance, -2, -1f);
				if (resetSpectatorHost)
				{
					if (!scene.Equals("MainMenu3"))
					{
						SteamVR_LoadLevel.Begin("MainMenu3", false, 0.5f, 0f, 0f, 0f, 1f);
					}
					resetSpectatorHost = false;
				}
				if (GameManager.OnSceneJoined != null)
				{
					GameManager.OnSceneJoined(scene, sceneAtSceneLoadStart);
				}
				TrackedGatlingGunData.firstInScene = true;
				for (int j = 0; j < retrack.Count; j++)
				{
					if ((Object)(object)retrack[j] != (Object)null)
					{
						SyncTrackedObjects(retrack[j].transform, controlEverything: true, null);
					}
				}
				retrack.Clear();
			}
			Mod.LogInfo("Setting player prefab to " + playerPrefabID);
			SetPlayerPrefab(playerPrefabID);
		}

		public static void ClearUnawoken()
		{
			for (int num = objects.Count - 1; num >= 0; num--)
			{
				if (((Object)(object)objects[num].physical != (Object)null && !objects[num].physical.awoken) || ((Object)(object)objects[num].physical == (Object)null && !objects[num].awaitingInstantiation))
				{
					objects[num].RemoveFromLocal();
				}
			}
		}

		public static void ProcessPlayerDamage(float damageMult, bool head, Damage damage)
		{
			bool processDamage = true;
			if (GameManager.OnPlayerDamage != null)
			{
				GameManager.OnPlayerDamage(damageMult, damage, ref processDamage);
			}
			if (processDamage)
			{
				damage.Dam_TotalEnergetic *= damageMult;
				damage.Dam_TotalKinetic *= damageMult;
				if (head)
				{
					GM.CurrentPlayerBody.Hitboxes[0].Damage(damage);
				}
				else
				{
					GM.CurrentPlayerBody.Hitboxes[2].Damage(damage);
				}
			}
		}

		public static void DistributeAllControl(int clientID, int overrideController = -1, List<Type> types = null)
		{
			int num = ((overrideController == -1) ? Mod.GetBestPotentialObjectHost(clientID, forUs: false) : overrideController);
			for (int i = 0; i < Server.objects.Length; i++)
			{
				if (Server.objects[i] == null || (types != null && !types.Contains(Server.objects[i].GetType())) || Server.objects[i].controller != clientID)
				{
					continue;
				}
				TrackedObjectData trackedObjectData = Server.objects[i];
				bool flag = num == -1;
				if (flag)
				{
					if ((Object)(object)trackedObjectData.physical == (Object)null)
					{
						ServerSend.DestroyObject(trackedObjectData.trackedID);
						Server.objects[trackedObjectData.trackedID] = null;
						if (Server.connectedClients.Count > 0)
						{
							if (Server.availableIndexBufferWaitingFor.TryGetValue(trackedObjectData.trackedID, out var value))
							{
								for (int j = 0; j < Server.connectedClients.Count; j++)
								{
									if (!value.Contains(Server.connectedClients[j]))
									{
										value.Add(Server.connectedClients[j]);
									}
								}
							}
							else
							{
								Server.availableIndexBufferWaitingFor.Add(trackedObjectData.trackedID, new List<int>(Server.connectedClients));
							}
							for (int k = 0; k < Server.connectedClients.Count; k++)
							{
								if (Server.availableIndexBufferClients.TryGetValue(Server.connectedClients[k], out var value2))
								{
									value2.Add(trackedObjectData.trackedID);
									continue;
								}
								Server.availableIndexBufferClients.Add(Server.connectedClients[k], new List<int> { trackedObjectData.trackedID });
							}
							if (Server.IDsToConfirm.TryGetValue(trackedObjectData.trackedID, out var value3))
							{
								for (int l = 0; l < Server.connectedClients.Count; l++)
								{
									if (!value3.Contains(Server.connectedClients[l]))
									{
										value3.Add(Server.connectedClients[l]);
									}
								}
							}
							else
							{
								Server.IDsToConfirm.Add(trackedObjectData.trackedID, new List<int>(Server.connectedClients));
							}
							Mod.LogInfo("Added " + trackedObjectData.trackedID + " to ID buffer");
						}
						else
						{
							Server.availableObjectIndices.Add(trackedObjectData.trackedID);
						}
						if (objectsByInstanceByScene.TryGetValue(trackedObjectData.scene, out var value4) && value4.TryGetValue(trackedObjectData.instance, out var value5))
						{
							value5.Remove(trackedObjectData.trackedID);
						}
						trackedObjectData.awaitingInstantiation = false;
						if (clientID == ID)
						{
							trackedObjectData.RemoveFromLocal();
						}
					}
					else
					{
						Object.Destroy((Object)(object)((Component)trackedObjectData.physical).gameObject);
					}
				}
				else if (clientID != 0 && num == 0)
				{
					trackedObjectData.localTrackedID = objects.Count;
					objects.Add(trackedObjectData);
					if ((Object)(object)trackedObjectData.physical == (Object)null && !sceneLoading)
					{
						if (trackedObjectData.scene.Equals(scene) && trackedObjectData.instance == instance)
						{
							if (!trackedObjectData.awaitingInstantiation)
							{
								trackedObjectData.awaitingInstantiation = true;
								AnvilManager.Run(trackedObjectData.Instantiate());
							}
						}
						else
						{
							if ((Object)(object)trackedObjectData.physical != (Object)null)
							{
								Object.Destroy((Object)(object)((Component)trackedObjectData.physical).gameObject);
							}
							else
							{
								ServerSend.DestroyObject(trackedObjectData.trackedID);
								trackedObjectData.RemoveFromLocal();
								Server.objects[trackedObjectData.trackedID] = null;
								if (Server.connectedClients.Count > 0)
								{
									if (Server.availableIndexBufferWaitingFor.TryGetValue(trackedObjectData.trackedID, out var value6))
									{
										for (int m = 0; m < Server.connectedClients.Count; m++)
										{
											if (!value6.Contains(Server.connectedClients[m]))
											{
												value6.Add(Server.connectedClients[m]);
											}
										}
									}
									else
									{
										Server.availableIndexBufferWaitingFor.Add(trackedObjectData.trackedID, new List<int>(Server.connectedClients));
									}
									for (int n = 0; n < Server.connectedClients.Count; n++)
									{
										if (Server.availableIndexBufferClients.TryGetValue(Server.connectedClients[n], out var value7))
										{
											value7.Add(trackedObjectData.trackedID);
											continue;
										}
										Server.availableIndexBufferClients.Add(Server.connectedClients[n], new List<int> { trackedObjectData.trackedID });
									}
									if (Server.IDsToConfirm.TryGetValue(trackedObjectData.trackedID, out var value8))
									{
										for (int num2 = 0; num2 < Server.connectedClients.Count; num2++)
										{
											if (!value8.Contains(Server.connectedClients[num2]))
											{
												value8.Add(Server.connectedClients[num2]);
											}
										}
									}
									else
									{
										Server.IDsToConfirm.Add(trackedObjectData.trackedID, new List<int>(Server.connectedClients));
									}
									Mod.LogInfo("Added " + trackedObjectData.trackedID + " to ID buffer");
								}
								else
								{
									Server.availableObjectIndices.Add(trackedObjectData.trackedID);
								}
								if (objectsByInstanceByScene.TryGetValue(trackedObjectData.scene, out var value9) && value9.TryGetValue(trackedObjectData.instance, out var value10))
								{
									value10.Remove(trackedObjectData.trackedID);
								}
								trackedObjectData.awaitingInstantiation = false;
							}
							flag = true;
						}
					}
				}
				if (!flag)
				{
					trackedObjectData.SetController(num);
					ServerSend.GiveObjectControl(trackedObjectData.trackedID, num, null);
				}
			}
		}

		public static void TakeAllPhysicalControl(bool destroyTrackedScript)
		{
			TrackedObjectData[] array = null;
			array = ((!ThreadManager.host) ? Client.objects : Server.objects);
			TrackedObjectData[] array2 = array;
			foreach (TrackedObjectData trackedObjectData in array2)
			{
				if (trackedObjectData != null && (Object)(object)trackedObjectData.physical != (Object)null)
				{
					trackedObjectData.controller = ID;
					if (destroyTrackedScript)
					{
						trackedObjectData.physical.skipFullDestroy = true;
						Object.Destroy((Object)(object)trackedObjectData.physical);
					}
				}
			}
		}

		public static void RaisePlayerBodyInit(FVRPlayerBody playerBody)
		{
			if (GameManager.OnPlayerBodyInit != null)
			{
				GameManager.OnPlayerBodyInit(playerBody);
			}
		}

		public static bool InSceneInit()
		{
			return SpawnVaultFileRoutinePatch.inInitSpawnVaultFileRoutine || AnvilPrefabSpawnPatch.inInitPrefabSpawn || inPostSceneLoadTrack || BrutPlacerPatch.inInitBrutPlacer;
		}
	}
	[BepInPlugin("VIP.TommySoucy.H3MP", "H3MP", "1.10.5")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Mod : BaseUnityPlugin
	{
		public delegate void CustomPacketHandler(int clientID, Packet packet);

		public delegate void CustomPacketHandlerReceivedDelegate(string ID, int index);

		public delegate void GenericCustomPacketReceivedDelegate(int clientID, string ID, Packet packet);

		public delegate void OnGetBestPotentialObjectHostDelegate(int currentController, bool forUs, bool hasWhiteList, List<int> whiteList, string sceneOverride, int instanceOverride, ref int bestPotentialObjectHost);

		public delegate void OnRemovePlayerFromSpecificListsDelegate(PlayerManager player);

		public delegate void OnSpectatorHostReceivedDelegate(int host, ref bool confirmed);

		public delegate void OnSpectatorHostGiveUpDelegate();

		public delegate void OnInstantiationTrackDelegate(GameObject gameObject);

		public delegate void OnConnectionDelegate();

		public delegate void OnPlayerRemovedDelegate(PlayerManager player);

		public const string pluginGuid = "VIP.TommySoucy.H3MP";

		public const string pluginName = "H3MP";

		public const string pluginVersion = "1.10.5";

		public static JObject config;

		public static GameObject TNHMenuPrefab;

		public static GameObject TNHStartEquipButtonPrefab;

		public static GameObject playerPrefab;

		public static GameObject keyboardPrefab;

		public static GameObject serverListPrefab;

		public static Material reticleFriendlyContactArrowMat;

		public static Material reticleFriendlyContactIconMat;

		public static Dictionary<string, string> sosigWearableMap;

		public static string H3MPPath;

		public static GameObject glassPrefab;

		public static GameObject glassPFXPrefab;

		public static MatDef glassMatDef;

		public static AudioEvent glassShotEvent;

		public static AudioEvent glassThudHeadEvent;

		public static AudioEvent glassThudTailEvent;

		public static AudioEvent glassTotalMediumEvent;

		public static AudioEvent glassGroundShatterEvent;

		public static Dictionary<FVRSoundEnvironment, AudioEvent> distantShotSets;

		public static SosigSpeechSet defaultSosigSpeechSet;

		public static AudioEvent sosigAlertAlarm;

		public static Text mainStatusText;

		public static Text statusLocationText;

		public static Text statusPlayerCountText;

		public GameObject hostButton;

		public GameObject connectButton;

		public GameObject joinButton;

		public static GameObject TNHMenu;

		public static GameObject[] TNHMenuPages;

		public static Text TNHStatusText;

		public static GameObject TNHInstanceList;

		public static GameObject TNHInstancePrefab;

		public static GameObject TNHInstanceListScrollUpArrow;

		public static GameObject TNHInstanceListScrollDownArrow;

		public static Scrollbar TNHInstanceListScrollBar;

		public static GameObject TNHHostButton;

		public static GameObject TNHJoinButton;

		public static GameObject TNHLPJCheck;

		public static GameObject TNHHostOnDeathSpectateRadio;

		public static GameObject TNHHostOnDeathLeaveRadio;

		public static GameObject TNHHostConfirmButton;

		public static GameObject TNHHostCancelButton;

		public static GameObject TNHJoinCancelButton;

		public static GameObject TNHJoinInstanceCancelButton;

		public static GameObject TNHJoinOptionsCancelButton;

		public static GameObject TNHJoinOnDeathSpectateRadio;

		public static GameObject TNHJoinOnDeathLeaveRadio;

		public static GameObject TNHJoinConfirmButton;

		public static GameObject TNHPlayerList;

		public static GameObject TNHPlayerPrefab;

		public static GameObject TNHPlayerListScrollUpArrow;

		public static GameObject TNHPlayerListScrollDownArrow;

		public static Scrollbar TNHPlayerListScrollBar;

		public static GameObject TNHLPJCheckMark;

		public static GameObject TNHHostOnDeathSpectateCheckMark;

		public static GameObject TNHHostOnDeathLeaveCheckMark;

		public static GameObject TNHJoinOnDeathSpectateCheckMark;

		public static GameObject TNHJoinOnDeathLeaveCheckMark;

		public static GameObject TNHRequestHostButton;

		public static GameObject TNHRequestHostConfirmButton;

		public static GameObject TNHRequestHostCancelButton;

		public static GameObject TNHRequestHostWaitingCancelButton;

		public static GameObject TNHRequestHostOnDeathSpectateRadio;

		public static GameObject TNHRequestHostOnDeathLeaveRadio;

		public static GameObject TNHRequestHostOnDeathSpectateCheckMark;

		public static GameObject TNHRequestHostOnDeathLeaveCheckMark;

		public static Text TNHInstanceTitle;

		public static Mod modInstance;

		public static GameObject managerObject;

		public static int skipNextFires = 0;

		public static int skipAllInstantiates = 0;

		public static AudioEvent sosigFootstepAudioEvent;

		public static bool TNHMenuLPJ;

		public static bool TNHOnDeathSpectate;

		public static bool TNHRequestHostOnDeathSpectate;

		public static bool TNHSpectating;

		public static bool setLatestInstance;

		public static TNHInstance currentTNHInstance;

		public static bool currentlyPlayingTNH;

		public static Dictionary<int, GameObject> joinTNHInstances;

		public static Dictionary<int, GameObject> currentTNHInstancePlayers;

		public static TNH_UIManager currentTNHUIManager;

		public static SceneLoader currentTNHSceneLoader;

		public static bool waitingForTNHHost;

		public static int TNHHostedInstance;

		public static GameObject TNHStartEquipButton;

		public static Dictionary<Type, List<Type>> trackedObjectTypes;

		public static Dictionary<string, Type> trackedObjectTypesByName;

		public static CustomPacketHandler[] customPacketHandlers = new CustomPacketHandler[10];

		public static List<int> availableCustomPacketIndices = new List<int> { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

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

		public static bool spectatorHostWaitingForTNHInstance;

		public static bool spectatorHostWaitingForTNHSetup;

		public static bool waitingForTNHGameStart;

		public static Scene DDOLScene;

		public static bool waitingForDebugCode;

		public static string debugCode;

		public static Vector3 TNHSpawnPoint;

		public static bool nullDriverControls;

		public static Vector3 nullDriverMovement = Vector3.zero;

		public static float defaultNullDriverMovementMultiplier = 0.2f;

		public static float defaultNullDriverRotationMultiplier = 0.4f;

		public static float nullDriverVerticalRot = 0f;

		public static float nullDriverHorzontalRot = 0f;

		public static int testCustomPacketID;

		public static event CustomPacketHandlerReceivedDelegate CustomPacketHandlerReceived;

		public static event GenericCustomPacketReceivedDelegate GenericCustomPacketReceived;

		public static event OnGetBestPotentialObjectHostDelegate OnGetBestPotentialObjectHost;

		public static event OnRemovePlayerFromSpecificListsDelegate OnRemovePlayerFromSpecificLists;

		public static event OnSpectatorHostReceivedDelegate OnSpectatorHostReceived;

		public static event OnSpectatorHostGiveUpDelegate OnSpectatorHostGiveUp;

		public static event OnInstantiationTrackDelegate OnInstantiationTrack;

		public static event OnConnectionDelegate OnConnection;

		public static event OnPlayerRemovedDelegate OnPlayerRemoved;

		private void Start()
		{
			((BaseUnityPlugin)this).Logger.LogInfo((object)"H3MP Started");
			modInstance = this;
			Init();
		}

		public static void Reset()
		{
			//IL_00a5: 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)
			LogInfo("Mod reset called", debug: false);
			skipNextFires = 0;
			skipAllInstantiates = 0;
			TNHMenuLPJ = true;
			TNHOnDeathSpectate = true;
			TNHSpectating = false;
			if ((Object)(object)GM.CurrentPlayerBody != (Object)null)
			{
				SetPlayerIFFPatch.skip++;
				GM.CurrentPlayerBody.SetPlayerIFF(GM.CurrentSceneSettings.DefaultPlayerIFF);
				SetPlayerIFFPatch.skip--;
				if ((Object)(object)GM.CurrentPlayerBody.RightHand != (Object)null && (Object)(object)GM.CurrentPlayerBody.LeftHand != (Object)null)
				{
					((Component)GM.CurrentPlayerBody.RightHand).GetComponent<FVRViveHand>().Mode = (HandMode)0;
					((Component)GM.CurrentPlayerBody.LeftHand).GetComponent<FVRViveHand>().Mode = (HandMode)0;
				}
			}
			setLatestInstance = false;
			currentTNHInstance = null;
			currentlyPlayingTNH = false;
			customPacketHandlers = new CustomPacketHandler[10];
			registeredCustomPacketIDs.Clear();
			availableCustomPacketIndices = new List<int> { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
			spectatorHostWaitingForTNHSetup = false;
			Object.DestroyImmediate((Object)(object)managerObject);
			managerObject = null;
		}

		private void Update()
		{
			//IL_115b: Unknown result type (might be due to invalid IL or missing references)
			//IL_1160: Unknown result type (might be due to invalid IL or missing references)
			//IL_1173: Unknown result type (might be due to invalid IL or missing references)
			//IL_1182: Unknown result type (might be due to invalid IL or missing references)
			//IL_118c: Unknown result type (might be due to invalid IL or missing references)
			//IL_1191: Unknown result type (might be due to invalid IL or missing references)
			//IL_1196: Unknown result type (might be due to invalid IL or missing references)
			//IL_11aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_11b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_11c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_11c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_11cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_11e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_11f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_11fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_11ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_1204: Unknown result type (might be due to invalid IL or missing references)
			//IL_1218: Unknown result type (might be due to invalid IL or missing references)
			//IL_1227: Unknown result type (might be due to invalid IL or missing references)
			//IL_1231: Unknown result type (might be due to invalid IL or missing references)
			//IL_1236: Unknown result type (might be due to invalid IL or missing references)
			//IL_123b: Unknown result type (might be due to invalid IL or missing references)
			//IL_08f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0902: Unknown result type (might be due to invalid IL or missing references)
			//IL_090c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0911: Unknown result type (might be due to invalid IL or missing references)
			//IL_0916: Unknown result type (might be due to invalid IL or missing references)
			//IL_0943: Unknown result type (might be due to invalid IL or missing references)
			//IL_0952: Unknown result type (might be due to invalid IL or missing references)
			//IL_0957: Unknown result type (might be due to invalid IL or missing references)
			//IL_095c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0e8d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0e94: Expected O, but got Unknown
			//IL_0eca: Unknown result type (might be due to invalid IL or missing references)
			//IL_0ed8: Expected O, but got Unknown
			//IL_0ef1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0f53: Unknown result type (might be due to invalid IL or missing references)
			//IL_0f5e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0f65: Expected O, but got Unknown
			//IL_0f65: Unknown result type (might be due to invalid IL or missing references)
			//IL_0f6c: Expected O, but got Unknown
			//IL_103c: Unknown result type (might be due to invalid IL or missing references)
			//IL_1043: Expected O, but got Unknown
			//IL_1043: Unknown result type (might be due to invalid IL or missing references)
			//IL_104a: Expected O, but got Unknown
			//IL_124f: Unknown result type (might be due to invalid IL or missing references)
			//IL_125e: Unknown result type (might be due to invalid IL or missing references)
			//IL_1268: Unknown result type (might be due to invalid IL or missing references)
			//IL_126d: Unknown result type (might be due to invalid IL or missing references)
			//IL_1272: Unknown result type (might be due to invalid IL or missing references)
			//IL_0cd1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0cd6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0cdb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0ce0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0cf6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0d00: Unknown result type (might be due to invalid IL or missing references)
			//IL_0d02: Unknown result type (might be due to invalid IL or missing references)
			//IL_0d07: Unknown result type (might be due to invalid IL or missing references)
			//IL_0d1c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0d1e: Unknown result type (might be due to invalid IL or missing references)
			//IL_12bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_12c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_12cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_1289: Unknown result type (might be due to invalid IL or missing references)
			//IL_1298: Unknown result type (might be due to invalid IL or missing references)
			//IL_12a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_12a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_12ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_12e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_12f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_12f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_1408: Unknown result type (might be due to invalid IL or missing references)
			//IL_141e: Unknown result type (might be due to invalid IL or missing references)
			//IL_1423: Unknown result type (might be due to invalid IL or missing references)
			//IL_1428: Unknown result type (might be due to invalid IL or missing references)
			//IL_158d: Unknown result type (might be due to invalid IL or missing references)
			//IL_1592: Unknown result type (might be due to invalid IL or missing references)
			if (waitingForDebugCode)
			{
				if (Input.GetKeyDown((KeyCode)256))
				{
					debugCode += "0";
					LogInfo("DebugCode: " + debugCode);
				}
				else if (Input.GetKeyDown((KeyCode)257))
				{
					debugCode += "1";
					LogInfo("DebugCode: " + debugCode);
				}
				else if (Input.GetKeyDown((KeyCode)258))
				{
					debugCode += "2";
					LogInfo("DebugCode: " + debugCode);
				}
				else if (Input.GetKeyDown((KeyCode)259))
				{
					debugCode += "3";
					LogInfo("DebugCode: " + debugCode);
				}
				else if (Input.GetKeyDown((KeyCode)260))
				{
					debugCode += "4";
					LogInfo("DebugCode: " + debugCode);
				}
				else if (Input.GetKeyDown((KeyCode)261))
				{
					debugCode += "5";
					LogInfo("DebugCode: " + debugCode);
				}
				else if (Input.GetKeyDown((KeyCode)262))
				{
					debugCode += "6";
					LogInfo("DebugCode: " + debugCode);
				}
				else if (Input.GetKeyDown((KeyCode)263))
				{
					debugCode += "7";
					LogInfo("DebugCode: " + debugCode);
				}
				else if (Input.GetKeyDown((KeyCode)264))
				{
					debugCode += "8";
					LogInfo("DebugCode: " + debugCode);
				}
				else if (Input.GetKeyDown((KeyCode)265))
				{
					debugCode += "9";
					LogInfo("DebugCode: " + debugCode);
				}
			}
			if (Input.GetKeyDown((KeyCode)292))
			{
				waitingForDebugCode = !waitingForDebugCode;
				if (waitingForDebugCode)
				{
					debugCode = string.Empty;
				}
				else
				{
					LogInfo("Activating DebugCode: " + debugCode);
					if (debugCode != string.Empty && int.TryParse(debugCode, out var result))
					{
						switch (result)
						{
						case 0:
							LogInfo("\tDebug: Start hosting");
							OnHostClicked();
							break;
						case 1:
							LogInfo("\tDebug: Connect");
							OnConnectClicked(null);
							break;
						case 2:
							LogInfo("\tDebug: Load config");
							LoadConfig();
							break;
						case 3:
							LogInfo("\tDebug: Disconnect/Close server");
							if ((Object)(object)managerObject != (Object)null)
							{
								if (ThreadManager.host)
								{
									Server.Close();
								}
								else
								{
									Client.singleton.Disconnect(sendToServer: true, 0);
								}
							}
							break;
						case 4:
							LogInfo("\tDebug: Load to main menu");
							SteamVR_LoadLevel.Begin("MainMenu3", false, 0.5f, 0f, 0f, 0f, 1f);
							break;
						case 5:
							LogInfo("\tDebug: Load to proving grounds");
							SteamVR_LoadLevel.Begin("ProvingGround", false, 0.5f, 0f, 0f, 0f, 1f);
							break;
						case 6:
						{
							LogInfo("\tDebug: Build sosig wearable map");
							Dictionary<string, string> dictionary = new Dictionary<string, string>();
							foreach (KeyValuePair<string, FVRObject> item in IM.OD)
							{
								LogInfo("Checking " + item.Key);
								GameObject val9 = null;
								try
								{
									val9 = ((AnvilAsset)item.Value).GetGameObject();
								}
								catch (Exception)
								{
									LogError("There was an error trying to retrieve prefab with ID: " + item.Key);
									continue;
								}
								try
								{
									SosigWearable component = val9.GetComponent<SosigWearable>();
									if ((Object)(object)component != (Object)null)
									{
										if (dictionary.ContainsKey(((Object)val9).name))
										{
											LogWarning("Sosig wearable with name: " + ((Object)val9).name + " is already in the map with value: " + dictionary[((Object)val9).name] + " and wewanted to add value: " + item.Key);
										}
										else
										{
											dictionary.Add(((Object)val9).name, item.Key);
											LogWarning("\tAdded");
										}
									}
								}
								catch (Exception ex2)
								{
									LogError("There was an error trying to check if prefab with ID: " + item.Key + " is wearable or adding it to the list: " + ex2.Message + "\n" + ex2.StackTrace);
								}
							}
							LogInfo("\tGot wearables, writing...");
							JObject val10 = JObject.FromObject((object)dictionary);
							File.WriteAllText(H3MPPath + "/SosigWearableMap.json", ((object)val10).ToString());
							LogInfo("\tNew wearables map written");
							break;
						}
						case 7:
							LogInfo("\tDebug: Load to TNH lobby");
							SteamVR_LoadLevel.Begin("TakeAndHold_Lobby_2", false, 0.5f, 0f, 0f, 0f, 1f);
							break;
						case 8:
							LogInfo("\tDebug: Join first TNH instance");
							if (currentTNHInstance == null)
							{
								OnTNHJoinClicked();
								OnTNHJoinConfirmClicked();
								OnTNHInstanceClicked(1);
							}
							break;
						case 9:
							LogInfo("\tDebug: Create new TNH instance");
							if (currentTNHInstance == null)
							{
								OnTNHHostClicked();
								OnTNHHostConfirmClicked();
							}
							break;
						case 10:
							LogInfo("\tDebug: Begin TNH hold");
							GM.TNH_Manager.m_curHoldPoint.m_systemNode.m_hasActivated = true;
							GM.TNH_Manager.m_curHoldPoint.m_systemNode.m_hasInitiatedHold = true;
							GM.TNH_Manager.m_curHoldPoint.BeginHoldChallenge();
							break;
						case 11:
							LogInfo("\tDebug: Trigger first scene loader we can find in the scene");
							Object.FindObjectOfType<SceneLoader>().LoadMG();
							break;
						case 12:
						{
							LogInfo("\tDebug: Write PatchHashes");
							string destFileName = H3MPPath + "/PatchHashes" + DateTimeOffset.Now.ToString().Replace("/", ".").Replace(":", ".") + ".json";
							File.Copy(H3MPPath + "/PatchHashes.json", destFileName);
							LogWarning("Writing new hashes to file!");
							File.WriteAllText(H3MPPath + "/PatchHashes.json", ((object)JObject.FromObject((object)PatchController.hashes)).ToString());
							break;
						}
						case 13:
							LogInfo("\tDebug: Load to friendly 45");
							SteamVR_LoadLevel.Begin("Friendly45_New", false, 0.5f, 0f, 0f, 0f, 1f);
							break;
						case 14:
						{
							LogInfo("\tDebug: Send packet with size > MTU");
							using (Packet packet = new Packet(ThreadManager.host ? 170 : 164))
							{
								byte[] value = new byte[2048];
								packet.Write(value);
								if (ThreadManager.host)
								{
									ServerSend.SendTCPDataToAll(packet);
								}
								else
								{
									ClientSend.SendTCPData(packet);
								}
							}
							break;
						}
						case 15:
						{
							LogInfo("\tDebug: Spawning items");
							GameObject gameObject = ((AnvilAsset)IM.OD["ModulAR300LowerFDEdupe"]).GetGameObject();
							Object.Instantiate<GameObject>(gameObject, GM.CurrentPlayerBody.Head.position + GM.CurrentPlayerBody.Head.forward * 0.5f, Quaternion.identity);
							GameObject gameObject2 = ((AnvilAsset)IM.OD["AR15UpperM4FDE"]).GetGameObject();
							Object.Instantiate<GameObject>(gameObject2, GM.CurrentPlayerBody.Head.position + GM.CurrentPlayerBody.Head.forward, Quaternion.identity);
							break;
						}
						case 16:
							LogInfo("\tDebug: Dumping item IDs");
							foreach (KeyValuePair<string, FVRObject> item2 in IM.OD)
							{
								LogInfo(item2.Key);
							}
							break;
						case 17:
							nullDriverControls = !nullDriverControls;
							LogInfo("\tDebug: Null driver controls: " + nullDriverControls);
							if (nullDriverControls)
							{
								nullDriverVerticalRot = 0f;
								nullDriverHorzontalRot = 0f;
							}
							break;
						case 18:
							LogInfo("\tDebug: Sub domain h3mp.tommysoucy.vip resolved to: " + Dns.GetHostAddresses("h3mp.tommysoucy.vip")[0].ToString());
							break;
						case 19:
							LogInfo("\tDebug: Load to grillhouse");
							SteamVR_LoadLevel.Begin("Grillhouse_2Story", false, 0.5f, 0f, 0f, 0f, 1f);
							break;
						case 20:
							LogInfo("\tDebug: Spawn SMG AutoMeater");
							SpawnItem("Turburgert_SMG");
							break;
						case 21:
							LogInfo("\tDebug: Spawn Flak AutoMeater");
							SpawnItem("Turburgert_Flak");
							break;
						case 22:
							LogInfo("\tDebug: Spawn Flamethrower AutoMeater");
							SpawnItem("Turburgert_Flamethrower");
							break;
						case 23:
							LogInfo("\tDebug: Spawn MachineGun AutoMeater");
							SpawnItem("Turburgert_MachineGun");
							break;
						case 24:
							LogInfo("\tDebug: Spawn Suppression AutoMeater");
							SpawnItem("Turburgert_Suppression");
							break;
						case 25:
							LogInfo("\tDebug: Spawn blue MF AutoMeater");
							SpawnItem("TurburgertMFBlue");
							break;
						case 26:
							LogInfo("\tDebug: Spawn red MF AutoMeater");
							SpawnItem("TurburgertMFRed");
							break;
						case 27:
							LogInfo("\tDebug: Load to SamplerPlatter");
							SteamVR_LoadLevel.Begin("SamplerPlatter", false, 0.5f, 0f, 0f, 0f, 1f);
							break;
						case 28:
						{
							LogInfo("\tDebug: Register test custom packet");
							int value3;
							if (ThreadManager.host)
							{
								if (registeredCustomPacketIDs.TryGetValue("TestCustomPacketID", out var value2))
								{
									testCustomPacketID = value2;
								}
								else
								{
									testCustomPacketID = Server.RegisterCustomPacketType("TestCustomPacketID");
								}
								customPacketHandlers[testCustomPacketID] = TestCustomPacketIDServerHandler;
							}
							else if (registeredCustomPacketIDs.TryGetValue("TestCustomPacketID", out value3))
							{
								testCustomPacketID = value3;
								customPacketHandlers[testCustomPacketID] = TestCustomPacketIDClientHandler;
							}
							else
							{
								ClientSend.RegisterCustomPacketType("TestCustomPacketID");
								CustomPacketHandlerReceived += TestCustomPacketIDReceived;
							}
							break;
						}
						case 29:
							LogInfo("\tDebug: Send test custom packet");
							if (ThreadManager.host)
							{
								using Packet packet2 = new Packet(testCustomPacketID);
								ServerSend.SendTCPDataToAll(packet2, custom: true);
							}
							else
							{
								using Packet packet3 = new Packet(testCustomPacketID);
								ClientSend.SendTCPData(packet3, custom: true);
							}
							break;
						case 30:
							LogInfo("\tDebug: Toggle server list");
							if ((Object)(object)ServerListController.instance == (Object)null)
							{
								Object.Instantiate<GameObject>(serverListPrefab);
								Vector3 val8 = Vector3.ProjectOnPlane(GM.CurrentPlayerBody.Head.forward, Vector3.up);
								((Component)ServerListController.instance).transform.position = GM.CurrentPlayerBody.Head.position + 2f * val8;
								((Component)ServerListController.instance).transform.rotation = Quaternion.LookRotation(val8);
							}
							else
							{
								Object.Destroy((Object)(object)((Component)ServerListController.instance).gameObject);
							}
							break;
						case 31:
							LogInfo("\tDebug: Server list, host");
							if ((Object)(object)ServerListController.instance != (Object)null)
							{
								ServerListController.instance.OnHostClicked();
								ServerListController.instance.hostServerName.text = "Debug server";
								ServerListController.instance.hostLimit.text = "5";
								ServerListController.instance.hostUsername.text = "Debug host";
								ServerListController.instance.hostPort.text = "7863";
								ServerListController.instance.OnHostConfirmClicked();
							}
							break;
						case 32:
							LogInfo("\tDebug: Server list, join first host");
							if ((Object)(object)ServerListController.instance != (Object)null)
							{
								((UnityEvent)((Component)ServerListController.instance.main.transform.GetChild(2).GetChild(1).GetChild(1)).GetComponent<Button>().onClick).Invoke();
								ServerListController.instance.joinUsername.text = "Debug client";
								ServerListController.instance.OnJoinConfirmClicked();
							}
							break;
						case 33:
							LogInfo("\tDebug: Load to Institution Preview");
							SteamVR_LoadLevel.Begin("Institution_Preview", false, 0.5f, 0f, 0f, 0f, 1f);
							break;
						case 34:
						{
							LogInfo("\tDebug: Patch ViveHand.PollInput");
							Harmony val7 = new Harmony("VIP.TommySoucy.H3MPDebug");
							MethodInfo method = typeof(FVRViveHand).GetMethod("PollInput", BindingFlags.Instance | BindingFlags.Public);
							MethodInfo method2 = typeof(Mod).GetMethod("PollInputPrefix", BindingFlags.Static | BindingFlags.Public);
							val7.Patch((MethodBase)method, new HarmonyMethod(method2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
							break;
						}
						case 35:
							LogInfo("\tDebug: Toggle vulnerability");
							SM.PlayGlobalUISound((GlobalUISound)0, ((Component)this).transform.position);
							H3MPWristMenuSection.invulnerable = !H3MPWristMenuSection.invulnerable;
							if ((Object)(object)H3MPWristMenuSection.invulnerableText != (Object)null)
							{
								H3MPWristMenuSection.invulnerableText.text = "Debug: Invulnerable: " + H3MPWristMenuSection.invulnerable;
							}
							break;
						case 36:
						{
							LogInfo("\tDebug: Discover NAT devices");
							SM.PlayGlobalUISound((GlobalUISound)0, ((Component)this).transform.position);
							NatDiscoverer val4 = new NatDiscoverer();
							CancellationTokenSource val5 = new CancellationTokenSource();
							CancellationTokenSourceExtension.CancelAfter(val5, 10000);
							Task<IEnumerable<NatDevice>> val6 = val4.DiscoverDevicesAsync((PortMapper)2, val5);
							((Task)val6).Wait();
							List<NatDevice> list2 = new List<NatDevice>(val6.Result);
							LogInfo("Got " + list2.Count + " devices:");
							for (int j = 0; j < list2.Count; j++)
							{
								Task<IPAddress> externalIPAsync = list2[j].GetExternalIPAsync();
								((Task)externalIPAsync).Wait();
								IPAddress result3 = externalIPAsync.Result;
								LogInfo("NAT Device " + j + ": " + result3);
							}
							break;
						}
						case 37:
						{
							LogInfo("\tDebug: Clear UPnP mappings");
							NatDiscoverer val = new NatDiscoverer();
							CancellationTokenSource val2 = new CancellationTokenSource();
							CancellationTokenSourceExtension.CancelAfter(val2, 10000);
							Task<NatDevice> val3 = val.DiscoverDeviceAsync((PortMapper)2, val2);
							((Task)val3).Wait();
							NatDevice result2 = val3.Result;
							Task<IEnumerable<Mapping>> allMappingsAsync = result2.GetAllMappingsAsync();
							((Task)allMappingsAsync).Wait();
							List<Mapping> list = new List<Mapping>(allMappingsAsync.Result);
							LogInfo("Got " + list.Count + " mappings:");
							for (int i = 0; i < list.Count; i++)
							{
								LogInfo("\tMapping " + i + ": " + list[i].Description);
								if (list[i].Description.Contains("H3MP"))
								{
									LogInfo("\t\tH3MP Mapping, removing...");
									result2.DeletePortMapAsync(list[i]).Wait();
								}
							}
							break;
						}
						}
					}
				}
			}
			if (!nullDriverControls)
			{
				return;
			}
			nullDriverMovement = Vector3.zero;
			if (Input.GetKey((KeyCode)119))
			{
				nullDriverMovement += GM.CurrentPlayerBody.Head.forward * Time.deltaTime;
			}
			if (Input.GetKey((KeyCode)115))
			{
				nullDriverMovement -= GM.CurrentPlayerBody.Head.forward * Time.deltaTime;
			}
			if (Input.GetKey((KeyCode)100))
			{
				nullDriverMovement += GM.CurrentPlayerBody.Head.right * Time.deltaTime;
			}
			if (Input.GetKey((KeyCode)97))
			{
				nullDriverMovement -= GM.CurrentPlayerBody.Head.right * Time.deltaTime;
			}
			if (Input.GetKey((KeyCode)32))
			{
				nullDriverMovement += GM.CurrentPlayerBody.Head.up * Time.deltaTime;
			}
			if (Input.GetKey((KeyCode)306))
			{
				nullDriverMovement -= GM.CurrentPlayerBody.Head.up * Time.deltaTime;
			}
			((Vector3)(ref nullDriverMovement)).Normalize();
			nullDriverMovement *= defaultNullDriverMovementMultiplier;
			float num = defaultNullDriverRotationMultiplier;
			if (Input.GetKey((KeyCode)304))
			{
				nullDriverMovement *= 5f;
				num = 2f;
			}
			if (Input.GetKey((KeyCode)273))
			{
				nullDriverVerticalRot -= 90f * Time.deltaTime * num;
				if (nullDriverVerticalRot < -90f)
				{
					nullDriverVerticalRot = -90f;
				}
			}
			else if (Input.GetKey((KeyCode)274))
			{
				nullDriverVerticalRot += 90f * Time.deltaTime * num;
				if (nullDriverVerticalRot > 90f)
				{
					nullDriverVerticalRot = 90f;
				}
			}
			if (Input.GetKey((KeyCode)275))
			{
				nullDriverHorzontalRot += 90f * Time.deltaTime * num;
			}
			if (Input.GetKey((KeyCode)276))
			{
				nullDriverHorzontalRot -= 90f * Time.deltaTime * num;
			}
			((Component)GM.CurrentPlayerBody).transform.rotation = Quaternion.Euler(nullDriverVerticalRot, nullDriverHorzontalRot, 0f);
			Transform transform = ((Component)GM.CurrentPlayerBody).transform;
			transform.position += nullDriverMovement;
			bool mouseButtonDown = Input.GetMouseButtonDown(0);
			bool mouseButtonDown2 = Input.GetMouseButtonDown(1);
			bool flag = false;
			if (mouseButtonDown)
			{
				FVRViveHand component2 = ((Component)GM.CurrentPlayerBody.LeftHand).GetComponent<FVRViveHand>();
				if ((Object)(object)component2.CurrentInteractable != (Object)null)
				{
					TrackedItem component3 = ((Component)component2.CurrentInteractable).GetComponent<TrackedItem>();
					if ((Object)(object)component3 == (Object)null)
					{
						component2.CurrentInteractable.ForceBreakInteraction();
					}
					else if (component3.fireFunc != null)
					{
						component3.fireFunc(0);
					}
					else
					{
						component2.CurrentInteractable.ForceBreakInteraction();
					}
				}
				flag = true;
			}
			if (mouseButtonDown2)
			{
				FVRViveHand component4 = ((Component)GM.CurrentPlayerBody.RightHand).GetComponent<FVRViveHand>();
				if ((Object)(object)component4.CurrentInteractable != (Object)null)
				{
					TrackedItem component5 = ((Component)component4.CurrentInteractable).GetComponent<TrackedItem>();
					if ((Object)(object)component5 == (Object)null)
					{
						component4.CurrentInteractable.ForceBreakInteraction();
					}
					else if (component5.fireFunc != null)
					{
						component5.fireFunc(0);
					}
					else
					{
						component4.CurrentInteractable.ForceBreakInteraction();
					}
				}
				flag = true;
			}
			if (flag || !(mouseButtonDown || mouseButtonDown2))
			{
				return;
			}
			RaycastHit[] array = Physics.RaycastAll(Camera.main.ScreenPointToRay(Input.mousePosition), 10f);
			if (array == null || array.Length == 0)
			{
				return;
			}
			for (int k = 0; k < array.Length; k++)
			{
				FVRInteractiveObject component6 = ((Component)((RaycastHit)(ref array[k])).collider).GetComponent<FVRInteractiveObject>();
				if ((Object)(object)component6 != (Object)null)
				{
					if (mouseButtonDown)
					{
						FVRViveHand component7 = ((Component)GM.CurrentPlayerBody.LeftHand).GetComponent<FVRViveHand>();
						component6.BeginInteraction(component7);
						component7.ForceSetInteractable(component6);
					}
					else if (mouseButtonDown2)
					{
						FVRViveHand component8 = ((Component)GM.CurrentPlayerBody.RightHand).GetComponent<FVRViveHand>();
						component6.BeginInteraction(component8);
						component8.ForceSetInteractable(component6);
					}
				}
			}
		}

		public static void TestCustomPacketIDServerHandler(int clientID, Packet packet)
		{
			LogInfo("Custom packet received from client " + clientID);
		}

		public static void TestCustomPacketIDClientHandler(int clientID, Packet packet)
		{
			LogInfo("Custom packet received from server");
		}

		public static void TestCustomPacketIDReceived(string identifier, int ID)
		{
			LogInfo("Client received ID " + ID + " for custom packet ID " + identifier);
			if (identifier.Equals("TestCustomPacketID"))
			{
				testCustomPacketID = ID;
				customPacketHandlers[testCustomPacketID] = TestCustomPacketIDClientHandler;
				CustomPacketHandlerReceived -= TestCustomPacketIDReceived;
			}
		}

		public GameObject SpawnItem(string itemID)
		{
			//IL_0023: 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_0037: 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)
			if (IM.OD.TryGetValue(itemID, out var 

Open.Nat.dll

Decompiled 2 months ago
#define TRACE
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Security.Permissions;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Xml;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("Open.Nat")]
[assembly: AssemblyDescription(".NET Library for automatic network address translation")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Open.Nat")]
[assembly: AssemblyCopyright("Copyright Alan McGovern, Ben Motmans, Lucas Ontivero ©  2006-2014")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("c8e81e95-9f15-4eb8-8982-3d2c9cd95dee")]
[assembly: AssemblyFileVersion("1.1.0.0")]
[assembly: CLSCompliant(false)]
[assembly: AssemblyVersion("1.0.0.0")]
namespace Open.Nat;

internal sealed class Finalizer
{
	~Finalizer()
	{
		NatDiscoverer.TraceSource.LogInfo("Closing ports opened in this session");
		NatDiscoverer.RenewTimer.Dispose();
		NatDiscoverer.ReleaseSessionMappings();
	}
}
internal class Guard
{
	private Guard()
	{
	}

	internal static void IsInRange(int paramValue, int lowerBound, int upperBound, string paramName)
	{
		if (paramValue < lowerBound || paramValue > upperBound)
		{
			throw new ArgumentOutOfRangeException(paramName);
		}
	}

	internal static void IsTrue(bool exp, string paramName)
	{
		if (!exp)
		{
			throw new ArgumentOutOfRangeException(paramName);
		}
	}

	internal static void IsNotNull(object obj, string paramName)
	{
		if (obj == null)
		{
			throw new ArgumentNullException(paramName);
		}
	}
}
public abstract class NatDevice
{
	private readonly HashSet<Mapping> _openedMapping = new HashSet<Mapping>();

	protected DateTime LastSeen { get; private set; }

	internal void Touch()
	{
		LastSeen = DateTime.Now;
	}

	public abstract Task CreatePortMapAsync(Mapping mapping);

	public abstract Task DeletePortMapAsync(Mapping mapping);

	public abstract Task<IEnumerable<Mapping>> GetAllMappingsAsync();

	public abstract Task<IPAddress> GetExternalIPAsync();

	public abstract Task<Mapping> GetSpecificMappingAsync(Protocol protocol, int port);

	protected void RegisterMapping(Mapping mapping)
	{
		_openedMapping.Remove(mapping);
		_openedMapping.Add(mapping);
	}

	protected void UnregisterMapping(Mapping mapping)
	{
		_openedMapping.RemoveWhere((Mapping x) => x.Equals(mapping));
	}

	internal void ReleaseMapping(IEnumerable<Mapping> mappings)
	{
		int num = mappings.ToArray().Length;
		NatDiscoverer.TraceSource.LogInfo("{0} ports to close", num);
		for (int i = 0; i < num; i = checked(i + 1))
		{
			Mapping mapping = _openedMapping.ElementAt(i);
			try
			{
				DeletePortMapAsync(mapping);
				NatDiscoverer.TraceSource.LogInfo(string.Concat(mapping, " port successfully closed"));
			}
			catch (Exception)
			{
				NatDiscoverer.TraceSource.LogError(string.Concat(mapping, " port couldn't be close"));
			}
		}
	}

	internal void ReleaseAll()
	{
		ReleaseMapping(_openedMapping);
	}

	internal void ReleaseSessionMappings()
	{
		IEnumerable<Mapping> mappings = _openedMapping.Where((Mapping m) => m.LifetimeType == MappingLifetime.Session);
		ReleaseMapping(mappings);
	}

	internal Task RenewMappings()
	{
		Task val = null;
		Mapping[] array = _openedMapping.Where((Mapping x) => x.ShoundRenew()).ToArray();
		foreach (Mapping mapping in array)
		{
			Mapping i = mapping;
			val = ((val == null) ? RenewMapping(i) : TaskExtensions.Unwrap(val.ContinueWith<Task>((Func<Task, Task>)((Task t) => RenewMapping(i)))));
		}
		return val;
	}

	private Task RenewMapping(Mapping mapping)
	{
		Mapping renewMapping = new Mapping(mapping);
		renewMapping.Expiration = DateTime.UtcNow.AddSeconds(mapping.Lifetime);
		NatDiscoverer.TraceSource.LogInfo("Renewing mapping {0}", renewMapping);
		return CreatePortMapAsync(renewMapping).ContinueWith((Action<Task>)delegate(Task task)
		{
			if (task.IsFaulted)
			{
				NatDiscoverer.TraceSource.LogWarn("Renew {0} failed", mapping);
			}
			else
			{
				NatDiscoverer.TraceSource.LogInfo("Next renew scheduled at: {0}", renewMapping.Expiration.ToLocalTime().TimeOfDay);
			}
		});
	}
}
public enum Protocol
{
	Tcp,
	Udp
}
internal class DeviceEventArgs : EventArgs
{
	public NatDevice Device { get; private set; }

	public DeviceEventArgs(NatDevice device)
	{
		Device = device;
	}
}
[Serializable]
public class MappingException : Exception
{
	public int ErrorCode { get; private set; }

	public string ErrorText { get; private set; }

	internal MappingException()
	{
	}

	internal MappingException(string message)
		: base(message)
	{
	}

	internal MappingException(int errorCode, string errorText)
		: base($"Error {errorCode}: {errorText}")
	{
		ErrorCode = errorCode;
		ErrorText = errorText;
	}

	internal MappingException(string message, Exception innerException)
		: base(message, innerException)
	{
	}

	protected MappingException(SerializationInfo info, StreamingContext context)
		: base(info, context)
	{
	}

	[SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)]
	public override void GetObjectData(SerializationInfo info, StreamingContext context)
	{
		if (info == null)
		{
			throw new ArgumentNullException("info");
		}
		ErrorCode = info.GetInt32("errorCode");
		ErrorText = info.GetString("errorText");
		base.GetObjectData(info, context);
	}
}
internal interface ISearcher
{
	void Search(CancellationToken cancellationToken);

	IEnumerable<NatDevice> Receive();

	NatDevice AnalyseReceivedResponse(IPAddress localAddress, byte[] response, IPEndPoint endpoint);
}
internal enum MappingLifetime
{
	Permanent,
	Session,
	Manual,
	ForcedSession
}
public class Mapping
{
	private DateTime _expiration;

	private int _lifetime;

	internal MappingLifetime LifetimeType { get; set; }

	public string Description { get; internal set; }

	public IPAddress PrivateIP { get; internal set; }

	public Protocol Protocol { get; internal set; }

	public int PrivatePort { get; internal set; }

	public IPAddress PublicIP { get; internal set; }

	public int PublicPort { get; internal set; }

	public int Lifetime
	{
		get
		{
			return _lifetime;
		}
		internal set
		{
			switch (value)
			{
			case int.MaxValue:
				LifetimeType = MappingLifetime.Session;
				_lifetime = 600;
				_expiration = DateTime.UtcNow.AddSeconds(_lifetime);
				break;
			case 0:
				LifetimeType = MappingLifetime.Permanent;
				_lifetime = 0;
				_expiration = DateTime.UtcNow;
				break;
			default:
				LifetimeType = MappingLifetime.Manual;
				_lifetime = value;
				_expiration = DateTime.UtcNow.AddSeconds(_lifetime);
				break;
			}
		}
	}

	public DateTime Expiration
	{
		get
		{
			return _expiration;
		}
		internal set
		{
			_expiration = value;
			_lifetime = checked((int)(_expiration - DateTime.UtcNow).TotalSeconds);
		}
	}

	internal Mapping(Protocol protocol, IPAddress privateIP, int privatePort, int publicPort)
		: this(protocol, privateIP, privatePort, publicPort, 0, "Open.Nat")
	{
	}

	public Mapping(Protocol protocol, IPAddress privateIP, int privatePort, int publicPort, int lifetime, string description)
	{
		Guard.IsInRange(privatePort, 0, 65535, "privatePort");
		Guard.IsInRange(publicPort, 0, 65535, "publicPort");
		Guard.IsInRange(lifetime, 0, int.MaxValue, "lifetime");
		Guard.IsTrue(protocol == Protocol.Tcp || protocol == Protocol.Udp, "protocol");
		Guard.IsNotNull(privateIP, "privateIP");
		Protocol = protocol;
		PrivateIP = privateIP;
		PrivatePort = privatePort;
		PublicIP = IPAddress.None;
		PublicPort = publicPort;
		Lifetime = lifetime;
		Description = description;
	}

	public Mapping(Protocol protocol, int privatePort, int publicPort)
		: this(protocol, IPAddress.None, privatePort, publicPort, 0, "Open.NAT")
	{
	}

	public Mapping(Protocol protocol, int privatePort, int publicPort, string description)
		: this(protocol, IPAddress.None, privatePort, publicPort, int.MaxValue, description)
	{
	}

	public Mapping(Protocol protocol, int privatePort, int publicPort, int lifetime, string description)
		: this(protocol, IPAddress.None, privatePort, publicPort, lifetime, description)
	{
	}

	internal Mapping(Mapping mapping)
	{
		PrivateIP = mapping.PrivateIP;
		PrivatePort = mapping.PrivatePort;
		Protocol = mapping.Protocol;
		PublicIP = mapping.PublicIP;
		PublicPort = mapping.PublicPort;
		LifetimeType = mapping.LifetimeType;
		Description = mapping.Description;
		_lifetime = mapping._lifetime;
		_expiration = mapping._expiration;
	}

	public bool IsExpired()
	{
		if (LifetimeType != 0 && LifetimeType != MappingLifetime.ForcedSession)
		{
			return Expiration < DateTime.UtcNow;
		}
		return false;
	}

	internal bool ShoundRenew()
	{
		if (LifetimeType == MappingLifetime.Session)
		{
			return IsExpired();
		}
		return false;
	}

	public override bool Equals(object obj)
	{
		if (obj == null)
		{
			return false;
		}
		if (this == obj)
		{
			return true;
		}
		if (!(obj is Mapping mapping))
		{
			return false;
		}
		if (PublicPort == mapping.PublicPort)
		{
			return PrivatePort == mapping.PrivatePort;
		}
		return false;
	}

	public override int GetHashCode()
	{
		return (((PublicPort * 397) ^ ((PrivateIP != null) ? PrivateIP.GetHashCode() : 0)) * 397) ^ PrivatePort;
	}

	public override string ToString()
	{
		return string.Format("{0} {1} --> {2}:{3} ({4})", (Protocol == Protocol.Tcp) ? "Tcp" : "Udp", PublicPort, PrivateIP, PrivatePort, Description);
	}
}
[Serializable]
public class NatDeviceNotFoundException : Exception
{
	public NatDeviceNotFoundException()
	{
	}

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

	public NatDeviceNotFoundException(string message, Exception innerException)
		: base(message, innerException)
	{
	}

	protected NatDeviceNotFoundException(SerializationInfo info, StreamingContext context)
		: base(info, context)
	{
	}
}
public class NatDiscoverer
{
	public static readonly TraceSource TraceSource = new TraceSource("Open.NAT");

	private static readonly Dictionary<string, NatDevice> Devices = new Dictionary<string, NatDevice>();

	private static readonly Finalizer Finalizer = new Finalizer();

	internal static readonly Timer RenewTimer = new Timer(RenewMappings, null, 5000, 2000);

	public Task<NatDevice> DiscoverDeviceAsync()
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: Expected O, but got Unknown
		CancellationTokenSource val = new CancellationTokenSource();
		val.CancelAfter(3000);
		return DiscoverDeviceAsync(PortMapper.Pmp | PortMapper.Upnp, val);
	}

	public Task<NatDevice> DiscoverDeviceAsync(PortMapper portMapper, CancellationTokenSource cancellationTokenSource)
	{
		Guard.IsTrue(EnumExtension.HasFlag(portMapper, PortMapper.Upnp) || EnumExtension.HasFlag(portMapper, PortMapper.Pmp), "portMapper");
		Guard.IsNotNull(cancellationTokenSource, "cancellationTokenSource");
		return DiscoverAsync(portMapper, onlyOne: true, cancellationTokenSource).ContinueWith<NatDevice>((Func<Task<IEnumerable<NatDevice>>, NatDevice>)delegate(Task<IEnumerable<NatDevice>> task)
		{
			NatDevice natDevice = task.Result.FirstOrDefault();
			if (natDevice == null)
			{
				TraceSource.LogInfo("Device not found. Common reasons:");
				TraceSource.LogInfo("\t* No device is present or,");
				TraceSource.LogInfo("\t* Upnp is disabled in the router or");
				TraceSource.LogInfo("\t* Antivirus software is filtering SSDP (discovery protocol).");
				throw new NatDeviceNotFoundException();
			}
			return natDevice;
		});
	}

	public Task<IEnumerable<NatDevice>> DiscoverDevicesAsync(PortMapper portMapper, CancellationTokenSource cancellationTokenSource)
	{
		Guard.IsTrue(EnumExtension.HasFlag(portMapper, PortMapper.Upnp) || EnumExtension.HasFlag(portMapper, PortMapper.Pmp), "portMapper");
		Guard.IsNotNull(cancellationTokenSource, "cancellationTokenSource");
		return DiscoverAsync(portMapper, onlyOne: false, cancellationTokenSource).ContinueWith<IEnumerable<NatDevice>>((Func<Task<IEnumerable<NatDevice>>, IEnumerable<NatDevice>>)((Task<IEnumerable<NatDevice>> t) => t.Result.ToArray()));
	}

	private Task<IEnumerable<NatDevice>> DiscoverAsync(PortMapper portMapper, bool onlyOne, CancellationTokenSource cts)
	{
		//IL_0081: Unknown result type (might be due to invalid IL or missing references)
		//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
		TraceSource.LogInfo("Start Discovery");
		List<Task<IEnumerable<NatDevice>>> searcherTasks = new List<Task<IEnumerable<NatDevice>>>();
		if (EnumExtension.HasFlag(portMapper, PortMapper.Upnp))
		{
			UpnpSearcher upnpSearcher = new UpnpSearcher(new IPAddressesProvider());
			upnpSearcher.DeviceFound = (EventHandler<DeviceEventArgs>)Delegate.Combine(upnpSearcher.DeviceFound, (EventHandler<DeviceEventArgs>)delegate
			{
				if (onlyOne)
				{
					cts.Cancel();
				}
			});
			searcherTasks.Add(upnpSearcher.Search(cts.Token));
		}
		if (EnumExtension.HasFlag(portMapper, PortMapper.Pmp))
		{
			PmpSearcher pmpSearcher = new PmpSearcher(new IPAddressesProvider());
			pmpSearcher.DeviceFound = (EventHandler<DeviceEventArgs>)Delegate.Combine(pmpSearcher.DeviceFound, (EventHandler<DeviceEventArgs>)delegate
			{
				if (onlyOne)
				{
					cts.Cancel();
				}
			});
			searcherTasks.Add(pmpSearcher.Search(cts.Token));
		}
		return TaskExtension.WhenAll((Task[])(object)searcherTasks.ToArray()).ContinueWith<IEnumerable<NatDevice>>((Func<Task, IEnumerable<NatDevice>>)delegate
		{
			TraceSource.LogInfo("Stop Discovery");
			IEnumerable<NatDevice> enumerable = searcherTasks.SelectMany((Task<IEnumerable<NatDevice>> x) => x.Result);
			foreach (NatDevice item in enumerable)
			{
				string key = item.ToString();
				if (Devices.TryGetValue(key, out var value))
				{
					value.Touch();
				}
				else
				{
					Devices.Add(key, item);
				}
			}
			return enumerable;
		});
	}

	public static void ReleaseAll()
	{
		foreach (NatDevice value in Devices.Values)
		{
			value.ReleaseAll();
		}
	}

	internal static void ReleaseSessionMappings()
	{
		foreach (NatDevice value in Devices.Values)
		{
			value.ReleaseSessionMappings();
		}
	}

	private static void RenewMappings(object state)
	{
		Task.Factory.StartNew((Action)delegate
		{
			Task val = null;
			foreach (NatDevice value in Devices.Values)
			{
				NatDevice d = value;
				val = (Task)((val == null) ? ((object)value.RenewMappings()) : ((object)val.ContinueWith<Task>((Func<Task, Task>)((Task t) => d.RenewMappings()))));
			}
		});
	}
}
internal class PmpSearcher : Searcher
{
	private readonly IIPAddressesProvider _ipprovider;

	private Dictionary<UdpClient, IEnumerable<IPEndPoint>> _gatewayLists;

	private int _timeout;

	internal PmpSearcher(IIPAddressesProvider ipprovider)
	{
		_ipprovider = ipprovider;
		_timeout = 250;
		CreateSocketsAndAddGateways();
	}

	private void CreateSocketsAndAddGateways()
	{
		Sockets = new List<UdpClient>();
		_gatewayLists = new Dictionary<UdpClient, IEnumerable<IPEndPoint>>();
		try
		{
			List<IPEndPoint> list = (from ip in _ipprovider.GatewayAddresses()
				select new IPEndPoint(ip, 5351)).ToList();
			if (!list.Any())
			{
				list.AddRange(from ip in _ipprovider.DnsAddresses()
					select new IPEndPoint(ip, 5351));
			}
			if (!list.Any())
			{
				return;
			}
			foreach (IPAddress item in _ipprovider.UnicastAddresses())
			{
				UdpClient udpClient;
				try
				{
					udpClient = new UdpClient(new IPEndPoint(item, 0));
				}
				catch (SocketException)
				{
					continue;
				}
				_gatewayLists.Add(udpClient, list);
				Sockets.Add(udpClient);
			}
		}
		catch (Exception ex2)
		{
			NatDiscoverer.TraceSource.LogError("There was a problem finding gateways: " + ex2);
		}
	}

	protected override void Discover(UdpClient client, CancellationToken cancelationToken)
	{
		NextSearch = DateTime.UtcNow.AddMilliseconds(_timeout);
		checked
		{
			_timeout *= 2;
			if (_timeout >= 3000)
			{
				_timeout = 250;
				NextSearch = DateTime.UtcNow.AddSeconds(10.0);
				return;
			}
			byte[] array = new byte[2];
			foreach (IPEndPoint item in _gatewayLists[client])
			{
				if (((CancellationToken)(ref cancelationToken)).IsCancellationRequested)
				{
					break;
				}
				client.Send(array, array.Length, item);
			}
		}
	}

	private bool IsSearchAddress(IPAddress address)
	{
		return _gatewayLists.Values.SelectMany((IEnumerable<IPEndPoint> x) => x).Any((IPEndPoint x) => x.Address.Equals(address));
	}

	public override NatDevice AnalyseReceivedResponse(IPAddress localAddress, byte[] response, IPEndPoint endpoint)
	{
		if (!IsSearchAddress(endpoint.Address) || response.Length != 12 || response[0] != 0 || response[1] != 128)
		{
			return null;
		}
		int num = IPAddress.NetworkToHostOrder(BitConverter.ToInt16(response, 2));
		if (num != 0)
		{
			NatDiscoverer.TraceSource.LogError("Non zero error: {0}", num);
		}
		IPAddress publicAddress = new IPAddress(new byte[4]
		{
			response[8],
			response[9],
			response[10],
			response[11]
		});
		_timeout = 250;
		return new PmpNatDevice(endpoint.Address, publicAddress);
	}
}
internal static class PmpConstants
{
	public const byte Version = 0;

	public const byte OperationExternalAddressRequest = 0;

	public const byte OperationCodeUdp = 1;

	public const byte OperationCodeTcp = 2;

	public const byte ServerNoop = 128;

	public const int ClientPort = 5350;

	public const int ServerPort = 5351;

	public const int RetryDelay = 250;

	public const int RetryAttempts = 9;

	public const int RecommendedLeaseTime = 3600;

	public const int DefaultLeaseTime = 3600;

	public const short ResultCodeSuccess = 0;

	public const short ResultCodeUnsupportedVersion = 1;

	public const short ResultCodeNotAuthorized = 2;

	public const short ResultCodeNetworkFailure = 3;

	public const short ResultCodeOutOfResources = 4;

	public const short ResultCodeUnsupportedOperationCode = 5;
}
internal sealed class PmpNatDevice : NatDevice
{
	private readonly IPAddress _publicAddress;

	internal IPAddress LocalAddress { get; private set; }

	internal PmpNatDevice(IPAddress localAddress, IPAddress publicAddress)
	{
		LocalAddress = localAddress;
		_publicAddress = publicAddress;
	}

	public override Task CreatePortMapAsync(Mapping mapping)
	{
		return InternalCreatePortMapAsync(mapping, create: true).TimeoutAfter<Mapping>(TimeSpan.FromSeconds(4.0)).ContinueWith((Action<Task<Mapping>>)delegate
		{
			RegisterMapping(mapping);
		});
	}

	public override Task DeletePortMapAsync(Mapping mapping)
	{
		return InternalCreatePortMapAsync(mapping, create: false).TimeoutAfter<Mapping>(TimeSpan.FromSeconds(4.0)).ContinueWith((Action<Task<Mapping>>)delegate
		{
			UnregisterMapping(mapping);
		});
	}

	public override Task<IEnumerable<Mapping>> GetAllMappingsAsync()
	{
		throw new NotSupportedException();
	}

	public override Task<IPAddress> GetExternalIPAsync()
	{
		return Task.Factory.StartNew<IPAddress>((Func<IPAddress>)(() => _publicAddress)).TimeoutAfter<IPAddress>(TimeSpan.FromSeconds(4.0));
	}

	public override Task<Mapping> GetSpecificMappingAsync(Protocol protocol, int port)
	{
		throw new NotSupportedException("NAT-PMP does not specify a way to get a specific port map");
	}

	private Task<Mapping> InternalCreatePortMapAsync(Mapping mapping, bool create)
	{
		List<byte> list = new List<byte>();
		list.Add(0);
		list.Add((byte)((mapping.Protocol != 0) ? 1 : 2));
		list.Add(0);
		list.Add(0);
		list.AddRange(BitConverter.GetBytes(IPAddress.HostToNetworkOrder(checked((short)mapping.PrivatePort))));
		list.AddRange(BitConverter.GetBytes((short)(create ? IPAddress.HostToNetworkOrder(checked((short)mapping.PublicPort)) : 0)));
		list.AddRange(BitConverter.GetBytes(IPAddress.HostToNetworkOrder(mapping.Lifetime)));
		byte[] buffer = list.ToArray();
		int num = 0;
		int num2 = 250;
		UdpClient udpClient = new UdpClient();
		CreatePortMapListen(udpClient, mapping);
		Task val = (Task)(object)Task.Factory.FromAsync<byte[], int, IPEndPoint, int>((Func_<byte[], int, IPEndPoint, AsyncCallback, object, IAsyncResult>)udpClient.BeginSend, (Func<IAsyncResult, int>)udpClient.EndSend, buffer, buffer.Length, new IPEndPoint(LocalAddress, 5351), (object)null);
		checked
		{
			while (num < 8)
			{
				val = (Task)(object)TaskExtensions.Unwrap<int>(val.ContinueWith<Task<int>>((Func<Task, Task<int>>)delegate(Task t)
				{
					if (t.IsFaulted)
					{
						string arg = (create ? "create" : "delete");
						string text = $"Failed to {arg} portmap (protocol={mapping.Protocol}, private port={mapping.PrivatePort})";
						NatDiscoverer.TraceSource.LogError(text);
						throw new MappingException(text, (Exception)(object)t.Exception);
					}
					return Task.Factory.FromAsync<byte[], int, IPEndPoint, int>((Func_<byte[], int, IPEndPoint, AsyncCallback, object, IAsyncResult>)udpClient.BeginSend, (Func<IAsyncResult, int>)udpClient.EndSend, buffer, buffer.Length, new IPEndPoint(LocalAddress, 5351), (object)null);
				}));
				num++;
				num2 *= 2;
				Thread.Sleep(num2);
			}
			return val.ContinueWith<Mapping>((Func<Task, Mapping>)delegate
			{
				udpClient.Close();
				return mapping;
			});
		}
	}

	private void CreatePortMapListen(UdpClient udpClient, Mapping mapping)
	{
		IPEndPoint remoteEP = new IPEndPoint(LocalAddress, 5351);
		byte[] array;
		do
		{
			array = udpClient.Receive(ref remoteEP);
		}
		while (array.Length < 16 || array[0] != 0);
		checked
		{
			byte num = (byte)(array[1] & 0x7F);
			Protocol protocol = Protocol.Tcp;
			if (num == 1)
			{
				protocol = Protocol.Udp;
			}
			short num2 = IPAddress.NetworkToHostOrder(BitConverter.ToInt16(array, 2));
			IPAddress.NetworkToHostOrder(BitConverter.ToInt32(array, 4));
			short num3 = IPAddress.NetworkToHostOrder(BitConverter.ToInt16(array, 8));
			short num4 = IPAddress.NetworkToHostOrder(BitConverter.ToInt16(array, 10));
			uint num5 = (uint)IPAddress.NetworkToHostOrder(BitConverter.ToInt32(array, 12));
			if (num3 < 0 || num4 < 0 || num2 != 0)
			{
				string[] array2 = new string[6] { "Success", "Unsupported Version", "Not Authorized/Refused (e.g. box supports mapping, but user has turned feature off)", "Network Failure (e.g. NAT box itself has not obtained a DHCP lease)", "Out of resources (NAT box cannot create any more mappings at this time)", "Unsupported opcode" };
				throw new MappingException(num2, array2[num2]);
			}
			if (num5 != 0)
			{
				mapping.PublicPort = num4;
				mapping.Protocol = protocol;
				mapping.Expiration = DateTime.Now.AddSeconds(num5);
			}
		}
	}

	public override string ToString()
	{
		return $"Local Address: {LocalAddress}\nPublic IP: {_publicAddress}\nLast Seen: {base.LastSeen}";
	}
}
[Flags]
public enum PortMapper
{
	Pmp = 1,
	Upnp = 2
}
internal abstract class Searcher
{
	private readonly List<NatDevice> _devices = new List<NatDevice>();

	protected List<UdpClient> Sockets;

	public EventHandler<DeviceEventArgs> DeviceFound;

	internal DateTime NextSearch = DateTime.UtcNow;

	public Task<IEnumerable<NatDevice>> Search(CancellationToken cancelationToken)
	{
		//IL_000e: 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_0026: Unknown result type (might be due to invalid IL or missing references)
		return Task.Factory.StartNew((Action<object>)delegate
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			NatDiscoverer.TraceSource.LogInfo("Searching for: {0}", GetType().Name);
			while (!((CancellationToken)(ref cancelationToken)).IsCancellationRequested)
			{
				Discover(cancelationToken);
				Receive(cancelationToken);
			}
			CloseSockets();
		}, (object)cancelationToken).ContinueWith<IEnumerable<NatDevice>>((Func<Task, IEnumerable<NatDevice>>)((Task task) => _devices));
	}

	private void Discover(CancellationToken cancelationToken)
	{
		//IL_002b: Unknown result type (might be due to invalid IL or missing references)
		if (DateTime.UtcNow < NextSearch)
		{
			return;
		}
		foreach (UdpClient socket in Sockets)
		{
			try
			{
				Discover(socket, cancelationToken);
			}
			catch (Exception ex)
			{
				NatDiscoverer.TraceSource.LogError("Error searching {0} - Details:", GetType().Name);
				NatDiscoverer.TraceSource.LogError(ex.ToString());
			}
		}
	}

	private void Receive(CancellationToken cancelationToken)
	{
		foreach (UdpClient item in Sockets.Where((UdpClient x) => x.Available > 0))
		{
			if (((CancellationToken)(ref cancelationToken)).IsCancellationRequested)
			{
				break;
			}
			IPAddress address = ((IPEndPoint)item.Client.LocalEndPoint).Address;
			IPEndPoint remoteEP = new IPEndPoint(IPAddress.None, 0);
			byte[] response = item.Receive(ref remoteEP);
			NatDevice natDevice = AnalyseReceivedResponse(address, response, remoteEP);
			if (natDevice != null)
			{
				RaiseDeviceFound(natDevice);
			}
		}
	}

	protected abstract void Discover(UdpClient client, CancellationToken cancelationToken);

	public abstract NatDevice AnalyseReceivedResponse(IPAddress localAddress, byte[] response, IPEndPoint endpoint);

	public void CloseSockets()
	{
		foreach (UdpClient socket in Sockets)
		{
			socket.Close();
		}
	}

	private void RaiseDeviceFound(NatDevice device)
	{
		_devices.Add(device);
		DeviceFound?.Invoke(this, new DeviceEventArgs(device));
	}
}
internal class UpnpSearcher : Searcher
{
	private readonly IIPAddressesProvider _ipprovider;

	private readonly IDictionary<Uri, NatDevice> _devices;

	private readonly Dictionary<IPAddress, DateTime> _lastFetched;

	private static readonly string[] ServiceTypes = new string[4] { "WANIPConnection:2", "WANPPPConnection:2", "WANIPConnection:1", "WANPPPConnection:1" };

	internal UpnpSearcher(IIPAddressesProvider ipprovider)
	{
		_ipprovider = ipprovider;
		Sockets = CreateSockets();
		_devices = new Dictionary<Uri, NatDevice>();
		_lastFetched = new Dictionary<IPAddress, DateTime>();
	}

	private List<UdpClient> CreateSockets()
	{
		List<UdpClient> list = new List<UdpClient>();
		try
		{
			foreach (IPAddress item in _ipprovider.UnicastAddresses())
			{
				try
				{
					list.Add(new UdpClient(new IPEndPoint(item, 0)));
				}
				catch (Exception)
				{
				}
			}
		}
		catch (Exception)
		{
			list.Add(new UdpClient(0));
		}
		return list;
	}

	protected override void Discover(UdpClient client, CancellationToken cancelationToken)
	{
		NextSearch = DateTime.UtcNow.AddSeconds(1.0);
		IPEndPoint endPoint = new IPEndPoint(WellKnownConstants.IPv4MulticastAddress, 1900);
		string[] serviceTypes = ServiceTypes;
		for (int i = 0; i < serviceTypes.Length; i++)
		{
			string s = DiscoverDeviceMessage.Encode(serviceTypes[i]);
			byte[] bytes = Encoding.ASCII.GetBytes(s);
			for (int j = 0; j < 2; j = checked(j + 1))
			{
				if (((CancellationToken)(ref cancelationToken)).IsCancellationRequested)
				{
					return;
				}
				client.Send(bytes, bytes.Length, endPoint);
			}
		}
	}

	public override NatDevice AnalyseReceivedResponse(IPAddress localAddress, byte[] response, IPEndPoint endpoint)
	{
		string text = null;
		try
		{
			text = Encoding.UTF8.GetString(response);
			DiscoveryResponseMessage discoveryResponseMessage = new DiscoveryResponseMessage(text);
			string text2 = discoveryResponseMessage["ST"];
			if (!IsValidControllerService(text2))
			{
				NatDiscoverer.TraceSource.LogWarn("Invalid controller service. Ignoring.");
				return null;
			}
			NatDiscoverer.TraceSource.LogInfo("UPnP Response: Router advertised a '{0}' service!!!", text2);
			Uri uri = new Uri(discoveryResponseMessage["Location"] ?? discoveryResponseMessage["AL"]);
			NatDiscoverer.TraceSource.LogInfo("Found device at: {0}", uri.ToString());
			if (_devices.ContainsKey(uri))
			{
				NatDiscoverer.TraceSource.LogInfo("Already found - Ignored");
				_devices[uri].Touch();
				return null;
			}
			if (_lastFetched.ContainsKey(endpoint.Address))
			{
				DateTime dateTime = _lastFetched[endpoint.Address];
				if (DateTime.Now - dateTime < TimeSpan.FromSeconds(20.0))
				{
					return null;
				}
			}
			_lastFetched[endpoint.Address] = DateTime.Now;
			NatDiscoverer.TraceSource.LogInfo("{0}:{1}: Fetching service list", uri.Host, uri.Port);
			UpnpNatDeviceInfo deviceInfo = BuildUpnpNatDeviceInfo(localAddress, uri);
			UpnpNatDevice upnpNatDevice;
			lock (_devices)
			{
				upnpNatDevice = new UpnpNatDevice(deviceInfo);
				if (!_devices.ContainsKey(uri))
				{
					_devices.Add(uri, upnpNatDevice);
				}
			}
			return upnpNatDevice;
		}
		catch (Exception ex)
		{
			NatDiscoverer.TraceSource.LogError("Unhandled exception when trying to decode a device's response. ");
			NatDiscoverer.TraceSource.LogError("Report the issue in https://github.com/lontivero/Open.Nat/issues");
			NatDiscoverer.TraceSource.LogError("Also copy and paste the following info:");
			NatDiscoverer.TraceSource.LogError("-- beging ---------------------------------");
			NatDiscoverer.TraceSource.LogError(ex.Message);
			NatDiscoverer.TraceSource.LogError("Data string:");
			NatDiscoverer.TraceSource.LogError(text ?? "No data available");
			NatDiscoverer.TraceSource.LogError("-- end ------------------------------------");
		}
		return null;
	}

	private static bool IsValidControllerService(string serviceType)
	{
		return (from serviceName in ServiceTypes
			let serviceUrn = $"urn:schemas-upnp-org:service:{serviceName}"
			where serviceType.ContainsIgnoreCase(serviceUrn)
			select new
			{
				ServiceName = serviceName,
				ServiceUrn = serviceUrn
			}).Any();
	}

	private UpnpNatDeviceInfo BuildUpnpNatDeviceInfo(IPAddress localAddress, Uri location)
	{
		NatDiscoverer.TraceSource.LogInfo("Found device at: {0}", location.ToString());
		IPEndPoint iPEndPoint = new IPEndPoint(IPAddress.Parse(location.Host), location.Port);
		WebResponse webResponse = null;
		try
		{
			WebRequest webRequest = WebRequest.Create(location);
			webRequest.Headers.Add("ACCEPT-LANGUAGE", "en");
			webRequest.Method = "GET";
			webResponse = webRequest.GetResponse();
			if (webResponse is HttpWebResponse httpWebResponse && httpWebResponse.StatusCode != HttpStatusCode.OK)
			{
				throw new Exception($"Couldn't get services list: {httpWebResponse.StatusCode} {httpWebResponse.StatusDescription}");
			}
			XmlDocument xmlDocument = ReadXmlResponse(webResponse);
			NatDiscoverer.TraceSource.LogInfo("{0}: Parsed services list", iPEndPoint);
			XmlNamespaceManager xmlNamespaceManager = new XmlNamespaceManager(xmlDocument.NameTable);
			xmlNamespaceManager.AddNamespace("ns", "urn:schemas-upnp-org:device-1-0");
			foreach (XmlNode item in xmlDocument.SelectNodes("//ns:service", xmlNamespaceManager))
			{
				string xmlElementText = item.GetXmlElementText("serviceType");
				if (IsValidControllerService(xmlElementText))
				{
					NatDiscoverer.TraceSource.LogInfo("{0}: Found service: {1}", iPEndPoint, xmlElementText);
					string xmlElementText2 = item.GetXmlElementText("controlURL");
					NatDiscoverer.TraceSource.LogInfo("{0}: Found upnp service at: {1}", iPEndPoint, xmlElementText2);
					NatDiscoverer.TraceSource.LogInfo("{0}: Handshake Complete", iPEndPoint);
					return new UpnpNatDeviceInfo(localAddress, location, xmlElementText2, xmlElementText);
				}
			}
			throw new Exception("No valid control service was found in the service descriptor document");
		}
		catch (WebException ex)
		{
			NatDiscoverer.TraceSource.LogError("{0}: Device denied the connection attempt: {1}", iPEndPoint, ex);
			if (ex.InnerException is SocketException ex2)
			{
				NatDiscoverer.TraceSource.LogError("{0}: ErrorCode:{1}", iPEndPoint, ex2.ErrorCode);
				NatDiscoverer.TraceSource.LogError("Go to http://msdn.microsoft.com/en-us/library/system.net.sockets.socketerror.aspx");
				NatDiscoverer.TraceSource.LogError("Usually this happens. Try resetting the device and try again. If you are in a VPN, disconnect and try again.");
			}
			throw;
		}
		finally
		{
			webResponse?.Close();
		}
	}

	private static XmlDocument ReadXmlResponse(WebResponse response)
	{
		using StreamReader streamReader = new StreamReader(response.GetResponseStream(), Encoding.UTF8);
		string xml = streamReader.ReadToEnd();
		XmlDocument xmlDocument = new XmlDocument();
		xmlDocument.LoadXml(xml);
		return xmlDocument;
	}
}
internal class DiscoveryResponseMessage
{
	private readonly IDictionary<string, string> _headers;

	public string this[string key] => _headers[key.ToUpperInvariant()];

	public DiscoveryResponseMessage(string message)
	{
		var source = from h in message.Split(new string[1] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries).Skip(1)
			let c = h.Split(new char[1] { ':' })
			let key = c[0]
			let value = (c.Length > 1) ? string.Join(":", c.Skip(1).ToArray()) : string.Empty
			select new
			{
				Key = key,
				Value = value.Trim()
			};
		_headers = source.ToDictionary(x => x.Key.ToUpperInvariant(), x => x.Value);
	}
}
internal static class DiscoverDeviceMessage
{
	public static string Encode(string serviceType)
	{
		return string.Format(CultureInfo.InvariantCulture, "M-SEARCH * HTTP/1.1\r\nHOST: 239.255.255.250:1900\r\nMAN: \"ssdp:discover\"\r\nMX: 3\r\nST: urn:schemas-upnp-org:service:{0}\r\n\r\n", new object[1] { serviceType });
	}
}
internal class CreatePortMappingRequestMessage : RequestMessageBase
{
	private readonly Mapping _mapping;

	public CreatePortMappingRequestMessage(Mapping mapping)
	{
		_mapping = mapping;
	}

	public override IDictionary<string, object> ToXml()
	{
		string value = (_mapping.PublicIP.Equals(IPAddress.None) ? string.Empty : _mapping.PublicIP.ToString());
		return new Dictionary<string, object>
		{
			{ "NewRemoteHost", value },
			{ "NewExternalPort", _mapping.PublicPort },
			{
				"NewProtocol",
				(_mapping.Protocol == Protocol.Tcp) ? "TCP" : "UDP"
			},
			{ "NewInternalPort", _mapping.PrivatePort },
			{ "NewInternalClient", _mapping.PrivateIP },
			{ "NewEnabled", 1 },
			{ "NewPortMappingDescription", _mapping.Description },
			{ "NewLeaseDuration", _mapping.Lifetime }
		};
	}
}
internal class DeletePortMappingRequestMessage : RequestMessageBase
{
	private readonly Mapping _mapping;

	public DeletePortMappingRequestMessage(Mapping mapping)
	{
		_mapping = mapping;
	}

	public override IDictionary<string, object> ToXml()
	{
		return new Dictionary<string, object>
		{
			{
				"NewRemoteHost",
				string.Empty
			},
			{ "NewExternalPort", _mapping.PublicPort },
			{
				"NewProtocol",
				(_mapping.Protocol == Protocol.Tcp) ? "TCP" : "UDP"
			}
		};
	}
}
internal class GetExternalIPAddressRequestMessage : RequestMessageBase
{
	public override IDictionary<string, object> ToXml()
	{
		return new Dictionary<string, object>();
	}
}
internal class GetGenericPortMappingEntry : RequestMessageBase
{
	private readonly int _index;

	public GetGenericPortMappingEntry(int index)
	{
		_index = index;
	}

	public override IDictionary<string, object> ToXml()
	{
		return new Dictionary<string, object> { { "NewPortMappingIndex", _index } };
	}
}
internal class GetSpecificPortMappingEntryRequestMessage : RequestMessageBase
{
	private readonly int _externalPort;

	private readonly Protocol _protocol;

	public GetSpecificPortMappingEntryRequestMessage(Protocol protocol, int externalPort)
	{
		_protocol = protocol;
		_externalPort = externalPort;
	}

	public override IDictionary<string, object> ToXml()
	{
		return new Dictionary<string, object>
		{
			{
				"NewRemoteHost",
				string.Empty
			},
			{ "NewExternalPort", _externalPort },
			{
				"NewProtocol",
				(_protocol == Protocol.Tcp) ? "TCP" : "UDP"
			}
		};
	}
}
internal abstract class ResponseMessageBase
{
	private readonly XmlDocument _document;

	protected string ServiceType;

	private readonly string _typeName;

	protected ResponseMessageBase(XmlDocument response, string serviceType, string typeName)
	{
		_document = response;
		ServiceType = serviceType;
		_typeName = typeName;
	}

	protected XmlNode GetNode()
	{
		XmlNamespaceManager xmlNamespaceManager = new XmlNamespaceManager(_document.NameTable);
		xmlNamespaceManager.AddNamespace("responseNs", ServiceType);
		string typeName = _typeName;
		string text = typeName.Substring(0, checked(typeName.Length - "Message".Length));
		return _document.SelectSingleNode("//responseNs:" + text, xmlNamespaceManager) ?? throw new InvalidOperationException("The response is invalid: " + text);
	}
}
internal class GetExternalIPAddressResponseMessage : ResponseMessageBase
{
	public IPAddress ExternalIPAddress { get; private set; }

	public GetExternalIPAddressResponseMessage(XmlDocument response, string serviceType)
		: base(response, serviceType, "GetExternalIPAddressResponseMessage")
	{
		string xmlElementText = GetNode().GetXmlElementText("NewExternalIPAddress");
		ExternalIPAddress = IPAddress.Parse(xmlElementText);
	}
}
internal class GetPortMappingEntryResponseMessage : ResponseMessageBase
{
	public string RemoteHost { get; private set; }

	public int ExternalPort { get; private set; }

	public Protocol Protocol { get; private set; }

	public int InternalPort { get; private set; }

	public string InternalClient { get; private set; }

	public bool Enabled { get; private set; }

	public string PortMappingDescription { get; private set; }

	public int LeaseDuration { get; private set; }

	internal GetPortMappingEntryResponseMessage(XmlDocument response, string serviceType, bool genericMapping)
		: base(response, serviceType, genericMapping ? "GetGenericPortMappingEntryResponseMessage" : "GetSpecificPortMappingEntryResponseMessage")
	{
		XmlNode node = GetNode();
		RemoteHost = (genericMapping ? node.GetXmlElementText("NewRemoteHost") : string.Empty);
		ExternalPort = (genericMapping ? Convert.ToInt32(node.GetXmlElementText("NewExternalPort")) : 65535);
		if (genericMapping)
		{
			Protocol = ((!node.GetXmlElementText("NewProtocol").Equals("TCP", StringComparison.InvariantCultureIgnoreCase)) ? Protocol.Udp : Protocol.Tcp);
		}
		else
		{
			Protocol = Protocol.Udp;
		}
		InternalPort = Convert.ToInt32(node.GetXmlElementText("NewInternalPort"));
		InternalClient = node.GetXmlElementText("NewInternalClient");
		Enabled = node.GetXmlElementText("NewEnabled") == "1";
		PortMappingDescription = node.GetXmlElementText("NewPortMappingDescription");
		LeaseDuration = Convert.ToInt32(node.GetXmlElementText("NewLeaseDuration"));
	}
}
internal abstract class RequestMessageBase
{
	public abstract IDictionary<string, object> ToXml();
}
internal class SoapClient
{
	private readonly string _serviceType;

	private readonly Uri _url;

	public SoapClient(Uri url, string serviceType)
	{
		_url = url;
		_serviceType = serviceType;
	}

	public Task<XmlDocument> InvokeAsync(string operationName, IDictionary<string, object> args)
	{
		NatDiscoverer.TraceSource.TraceEvent(TraceEventType.Verbose, 0, "SOAPACTION: **{0}** url:{1}", operationName, _url);
		byte[] messageBody = BuildMessageBody(operationName, args);
		HttpWebRequest request = BuildHttpWebRequest(operationName, messageBody);
		Task<WebResponse> val;
		if (messageBody.Length != 0)
		{
			Stream requestStream = null;
			val = TaskExtensions.Unwrap<WebResponse>(TaskExtensions.Unwrap(Task.Factory.FromAsync<Stream>((Func<AsyncCallback, object, IAsyncResult>)request.BeginGetRequestStream, (Func<IAsyncResult, Stream>)request.EndGetRequestStream, (object)null).ContinueWith<Task>((Func<Task<Stream>, Task>)delegate(Task<Stream> requestSteamTask)
			{
				requestStream = requestSteamTask.Result;
				TaskFactory factory = Task.Factory;
				Stream stream = requestStream;
				return factory.FromAsync<byte[], int, int>((Func_<byte[], int, int, AsyncCallback, object, IAsyncResult>)stream.BeginWrite, (Action<IAsyncResult>)requestStream.EndWrite, messageBody, 0, messageBody.Length, (object)null);
			})).ContinueWith<Task<WebResponse>>((Func<Task, Task<WebResponse>>)delegate
			{
				requestStream.Close();
				return GetWebResponse(request);
			}));
		}
		else
		{
			val = GetWebResponse(request);
		}
		return val.ContinueWith<XmlDocument>((Func<Task<WebResponse>, XmlDocument>)delegate(Task<WebResponse> task)
		{
			using WebResponse webResponse = task.Result;
			Stream responseStream = webResponse.GetResponseStream();
			long contentLength = webResponse.ContentLength;
			StreamReader streamReader = new StreamReader(responseStream, Encoding.UTF8);
			string response = ((contentLength != -1) ? streamReader.ReadAsMany(checked((int)contentLength)) : streamReader.ReadToEnd());
			XmlDocument xmlDocument = GetXmlDocument(response);
			webResponse.Close();
			return xmlDocument;
		});
	}

	private static Task<WebResponse> GetWebResponse(WebRequest request)
	{
		return Task.Factory.FromAsync<WebResponse>((Func<AsyncCallback, object, IAsyncResult>)request.BeginGetResponse, (Func<IAsyncResult, WebResponse>)request.EndGetResponse, (object)null).ContinueWith<WebResponse>((Func<Task<WebResponse>, WebResponse>)delegate(Task<WebResponse> task)
		{
			WebResponse webResponse;
			if (!((Task)task).IsFaulted)
			{
				webResponse = task.Result;
			}
			else
			{
				if (!(((Exception)(object)((Task)task).Exception).InnerException is WebException ex))
				{
					throw ((Task)task).Exception;
				}
				NatDiscoverer.TraceSource.TraceEvent(TraceEventType.Verbose, 0, "WebException status: {0}", ex.Status);
				webResponse = ex.Response as HttpWebResponse;
				if (webResponse == null)
				{
					throw ((Task)task).Exception;
				}
			}
			return webResponse;
		});
	}

	private HttpWebRequest BuildHttpWebRequest(string operationName, byte[] messageBody)
	{
		HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create(_url);
		httpWebRequest.KeepAlive = false;
		httpWebRequest.Method = "POST";
		httpWebRequest.ContentType = "text/xml; charset=\"utf-8\"";
		httpWebRequest.Headers.Add("SOAPACTION", "\"" + _serviceType + "#" + operationName + "\"");
		httpWebRequest.ContentLength = messageBody.Length;
		return httpWebRequest;
	}

	private byte[] BuildMessageBody(string operationName, IEnumerable<KeyValuePair<string, object>> args)
	{
		StringBuilder stringBuilder = new StringBuilder();
		stringBuilder.AppendLine("<s:Envelope ");
		stringBuilder.AppendLine("   xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" ");
		stringBuilder.AppendLine("   s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">");
		stringBuilder.AppendLine("   <s:Body>");
		stringBuilder.AppendLine("\t  <u:" + operationName + " xmlns:u=\"" + _serviceType + "\">");
		foreach (KeyValuePair<string, object> arg in args)
		{
			stringBuilder.AppendLine("\t\t <" + arg.Key + ">" + Convert.ToString(arg.Value, CultureInfo.InvariantCulture) + "</" + arg.Key + ">");
		}
		stringBuilder.AppendLine("\t  </u:" + operationName + ">");
		stringBuilder.AppendLine("   </s:Body>");
		stringBuilder.Append("</s:Envelope>\r\n\r\n");
		string s = stringBuilder.ToString();
		return Encoding.UTF8.GetBytes(s);
	}

	private XmlDocument GetXmlDocument(string response)
	{
		XmlDocument xmlDocument = new XmlDocument();
		xmlDocument.LoadXml(response);
		XmlNamespaceManager xmlNamespaceManager = new XmlNamespaceManager(xmlDocument.NameTable);
		xmlNamespaceManager.AddNamespace("errorNs", "urn:schemas-upnp-org:control-1-0");
		XmlNode node;
		if ((node = xmlDocument.SelectSingleNode("//errorNs:UPnPError", xmlNamespaceManager)) != null)
		{
			int num = Convert.ToInt32(node.GetXmlElementText("errorCode"), CultureInfo.InvariantCulture);
			string xmlElementText = node.GetXmlElementText("errorDescription");
			NatDiscoverer.TraceSource.LogWarn("Server failed with error: {0} - {1}", num, xmlElementText);
			throw new MappingException(num, xmlElementText);
		}
		return xmlDocument;
	}
}
internal static class UpnpConstants
{
	public const int InvalidArguments = 402;

	public const int ActionFailed = 501;

	public const int Unathorized = 606;

	public const int SpecifiedArrayIndexInvalid = 713;

	public const int NoSuchEntryInArray = 714;

	public const int WildCardNotPermittedInSourceIp = 715;

	public const int WildCardNotPermittedInExternalPort = 716;

	public const int ConflictInMappingEntry = 718;

	public const int SamePortValuesRequired = 724;

	public const int OnlyPermanentLeasesSupported = 725;

	public const int RemoteHostOnlySupportsWildcard = 726;

	public const int ExternalPortOnlySupportsWildcard = 727;

	public const int NoPortMapsAvailable = 728;

	public const int ConflictWithOtherMechanisms = 729;

	public const int WildCardNotPermittedInIntPort = 732;
}
internal class UpnpNatDeviceInfo
{
	public IPEndPoint HostEndPoint { get; private set; }

	public IPAddress LocalAddress { get; private set; }

	public string ServiceType { get; private set; }

	public Uri ServiceControlUri { get; private set; }

	public UpnpNatDeviceInfo(IPAddress localAddress, Uri locationUri, string serviceControlUrl, string serviceType)
	{
		LocalAddress = localAddress;
		ServiceType = serviceType;
		HostEndPoint = new IPEndPoint(IPAddress.Parse(locationUri.Host), locationUri.Port);
		if (Uri.IsWellFormedUriString(serviceControlUrl, UriKind.Absolute))
		{
			Uri uri = new Uri(serviceControlUrl);
			IPEndPoint hostEndPoint = HostEndPoint;
			serviceControlUrl = uri.PathAndQuery;
			NatDiscoverer.TraceSource.LogInfo("{0}: Absolute URI detected. Host address is now: {1}", hostEndPoint, HostEndPoint);
			NatDiscoverer.TraceSource.LogInfo("{0}: New control url: {1}", HostEndPoint, serviceControlUrl);
		}
		UriBuilder uriBuilder = new UriBuilder("http", locationUri.Host, locationUri.Port);
		ServiceControlUri = new Uri(uriBuilder.Uri, serviceControlUrl);
	}
}
internal sealed class UpnpNatDevice : NatDevice
{
	internal readonly UpnpNatDeviceInfo DeviceInfo;

	private readonly SoapClient _soapClient;

	internal UpnpNatDevice(UpnpNatDeviceInfo deviceInfo)
	{
		Touch();
		DeviceInfo = deviceInfo;
		_soapClient = new SoapClient(DeviceInfo.ServiceControlUri, DeviceInfo.ServiceType);
	}

	public override Task<IPAddress> GetExternalIPAsync()
	{
		NatDiscoverer.TraceSource.LogInfo("GetExternalIPAsync - Getting external IP address");
		GetExternalIPAddressRequestMessage getExternalIPAddressRequestMessage = new GetExternalIPAddressRequestMessage();
		return _soapClient.InvokeAsync("GetExternalIPAddress", getExternalIPAddressRequestMessage.ToXml()).TimeoutAfter<XmlDocument>(TimeSpan.FromSeconds(4.0)).ContinueWith<IPAddress>((Func<Task<XmlDocument>, IPAddress>)((Task<XmlDocument> task) => new GetExternalIPAddressResponseMessage(task.Result, DeviceInfo.ServiceType).ExternalIPAddress));
	}

	public override Task CreatePortMapAsync(Mapping mapping)
	{
		Guard.IsNotNull(mapping, "mapping");
		if (mapping.PrivateIP.Equals(IPAddress.None))
		{
			mapping.PrivateIP = DeviceInfo.LocalAddress;
		}
		NatDiscoverer.TraceSource.LogInfo("CreatePortMapAsync - Creating port mapping {0}", mapping);
		CreatePortMappingRequestMessage createPortMappingRequestMessage = new CreatePortMappingRequestMessage(mapping);
		return _soapClient.InvokeAsync("AddPortMapping", createPortMappingRequestMessage.ToXml()).TimeoutAfter<XmlDocument>(TimeSpan.FromSeconds(4.0)).ContinueWith((Action<Task<XmlDocument>>)delegate(Task<XmlDocument> task)
		{
			if (!((Task)task).IsFaulted)
			{
				RegisterMapping(mapping);
			}
			else
			{
				if (!(((Exception)(object)((Task)task).Exception).InnerException is MappingException ex))
				{
					throw ((Exception)(object)((Task)task).Exception).InnerException;
				}
				switch (ex.ErrorCode)
				{
				case 725:
					NatDiscoverer.TraceSource.LogWarn("Only Permanent Leases Supported - There is no warranty it will be closed");
					mapping.Lifetime = 0;
					mapping.LifetimeType = MappingLifetime.ForcedSession;
					CreatePortMapAsync(mapping);
					break;
				case 724:
					NatDiscoverer.TraceSource.LogWarn("Same Port Values Required - Using internal port {0}", mapping.PrivatePort);
					mapping.PublicPort = mapping.PrivatePort;
					CreatePortMapAsync(mapping);
					break;
				case 726:
					NatDiscoverer.TraceSource.LogWarn("Remote Host Only Supports Wildcard");
					mapping.PublicIP = IPAddress.None;
					CreatePortMapAsync(mapping);
					break;
				case 727:
					NatDiscoverer.TraceSource.LogWarn("External Port Only Supports Wildcard");
					throw ex;
				case 718:
					NatDiscoverer.TraceSource.LogWarn("Conflict with an already existing mapping");
					throw ex;
				default:
					throw ex;
				}
			}
		});
	}

	public override Task DeletePortMapAsync(Mapping mapping)
	{
		Guard.IsNotNull(mapping, "mapping");
		if (mapping.PrivateIP.Equals(IPAddress.None))
		{
			mapping.PrivateIP = DeviceInfo.LocalAddress;
		}
		NatDiscoverer.TraceSource.LogInfo("DeletePortMapAsync - Deleteing port mapping {0}", mapping);
		DeletePortMappingRequestMessage deletePortMappingRequestMessage = new DeletePortMappingRequestMessage(mapping);
		return _soapClient.InvokeAsync("DeletePortMapping", deletePortMappingRequestMessage.ToXml()).TimeoutAfter<XmlDocument>(TimeSpan.FromSeconds(4.0)).ContinueWith((Action<Task<XmlDocument>>)delegate(Task<XmlDocument> task)
		{
			if (!((Task)task).IsFaulted)
			{
				UnregisterMapping(mapping);
			}
			else if (((Exception)(object)((Task)task).Exception).InnerException is MappingException ex && ex.ErrorCode != 714)
			{
				throw ex;
			}
		});
	}

	public void GetGenericMappingAsync(int index, List<Mapping> mappings, TaskCompletionSource<IEnumerable<Mapping>> taskCompletionSource)
	{
		GetGenericPortMappingEntry getGenericPortMappingEntry = new GetGenericPortMappingEntry(index);
		_soapClient.InvokeAsync("GetGenericPortMappingEntry", getGenericPortMappingEntry.ToXml()).TimeoutAfter<XmlDocument>(TimeSpan.FromSeconds(4.0)).ContinueWith((Action<Task<XmlDocument>>)delegate(Task<XmlDocument> task)
		{
			if (!((Task)task).IsFaulted)
			{
				GetPortMappingEntryResponseMessage getPortMappingEntryResponseMessage = new GetPortMappingEntryResponseMessage(task.Result, DeviceInfo.ServiceType, genericMapping: true);
				if (!IPAddress.TryParse(getPortMappingEntryResponseMessage.InternalClient, out IPAddress address))
				{
					NatDiscoverer.TraceSource.LogWarn("InternalClient is not an IP address. Mapping ignored!");
				}
				else
				{
					Mapping item = new Mapping(getPortMappingEntryResponseMessage.Protocol, address, getPortMappingEntryResponseMessage.InternalPort, getPortMappingEntryResponseMessage.ExternalPort, getPortMappingEntryResponseMessage.LeaseDuration, getPortMappingEntryResponseMessage.PortMappingDescription);
					mappings.Add(item);
				}
				GetGenericMappingAsync(checked(index + 1), mappings, taskCompletionSource);
			}
			else
			{
				if (!(((Exception)(object)((Task)task).Exception).InnerException is MappingException ex))
				{
					throw ((Exception)(object)((Task)task).Exception).InnerException;
				}
				if (ex.ErrorCode == 713 || ex.ErrorCode == 714)
				{
					taskCompletionSource.SetResult((IEnumerable<Mapping>)mappings);
				}
				else
				{
					if (ex.ErrorCode != 402)
					{
						throw ((Exception)(object)((Task)task).Exception).InnerException;
					}
					NatDiscoverer.TraceSource.LogWarn("Router failed with 402-InvalidArgument. No more mappings is assumed.");
					taskCompletionSource.SetResult((IEnumerable<Mapping>)mappings);
				}
			}
		});
	}

	public override Task<IEnumerable<Mapping>> GetAllMappingsAsync()
	{
		TaskCompletionSource<IEnumerable<Mapping>> val = new TaskCompletionSource<IEnumerable<Mapping>>();
		NatDiscoverer.TraceSource.LogInfo("GetAllMappingsAsync - Getting all mappings");
		GetGenericMappingAsync(0, new List<Mapping>(), val);
		return val.Task;
	}

	public override Task<Mapping> GetSpecificMappingAsync(Protocol protocol, int publicPort)
	{
		Guard.IsTrue(protocol == Protocol.Tcp || protocol == Protocol.Udp, "protocol");
		Guard.IsInRange(publicPort, 0, 65535, "port");
		NatDiscoverer.TraceSource.LogInfo("GetSpecificMappingAsync - Getting mapping for protocol: {0} port: {1}", Enum.GetName(typeof(Protocol), protocol), publicPort);
		GetSpecificPortMappingEntryRequestMessage getSpecificPortMappingEntryRequestMessage = new GetSpecificPortMappingEntryRequestMessage(protocol, publicPort);
		return _soapClient.InvokeAsync("GetSpecificPortMappingEntry", getSpecificPortMappingEntryRequestMessage.ToXml()).TimeoutAfter<XmlDocument>(TimeSpan.FromSeconds(4.0)).ContinueWith<Mapping>((Func<Task<XmlDocument>, Mapping>)delegate(Task<XmlDocument> task)
		{
			if (!((Task)task).IsFaulted)
			{
				GetPortMappingEntryResponseMessage getPortMappingEntryResponseMessage = new GetPortMappingEntryResponseMessage(task.Result, DeviceInfo.ServiceType, genericMapping: false);
				return new Mapping(getPortMappingEntryResponseMessage.Protocol, IPAddress.Parse(getPortMappingEntryResponseMessage.InternalClient), getPortMappingEntryResponseMessage.InternalPort, publicPort, getPortMappingEntryResponseMessage.LeaseDuration, getPortMappingEntryResponseMessage.PortMappingDescription);
			}
			MappingException ex = ((Exception)(object)((Task)task).Exception).InnerException as MappingException;
			if (ex != null && ex.ErrorCode == 714)
			{
				return null;
			}
			if (ex != null && ex.ErrorCode == 402)
			{
				NatDiscoverer.TraceSource.LogWarn("Router failed with 402-InvalidArgument. Mapping not found is assumed.");
				return null;
			}
			throw ((Exception)(object)((Task)task).Exception).InnerException;
		});
	}

	public override string ToString()
	{
		return $"EndPoint: {DeviceInfo.HostEndPoint}\nControl Url: {DeviceInfo.ServiceControlUri}\nService Type: {DeviceInfo.ServiceType}\nLast Seen: {base.LastSeen}";
	}
}
internal static class StreamExtensions
{
	internal static string ReadAsMany(this StreamReader stream, int bytesToRead)
	{
		char[] array = new char[bytesToRead];
		stream.ReadBlock(array, 0, bytesToRead);
		return new string(array);
	}

	internal static string GetXmlElementText(this XmlNode node, string elementName)
	{
		XmlElement xmlElement = node[elementName];
		if (xmlElement == null)
		{
			return string.Empty;
		}
		return xmlElement.InnerText;
	}

	internal static bool ContainsIgnoreCase(this string s, string pattern)
	{
		return s.IndexOf(pattern, StringComparison.OrdinalIgnoreCase) >= 0;
	}

	internal static void LogInfo(this TraceSource source, string format, params object[] args)
	{
		source.TraceEvent(TraceEventType.Information, 0, format, args);
	}

	internal static void LogWarn(this TraceSource source, string format, params object[] args)
	{
		source.TraceEvent(TraceEventType.Warning, 0, format, args);
	}

	internal static void LogError(this TraceSource source, string format, params object[] args)
	{
		source.TraceEvent(TraceEventType.Error, 0, format, args);
	}

	internal static string ToPrintableXml(this XmlDocument document)
	{
		using MemoryStream memoryStream = new MemoryStream();
		using XmlTextWriter xmlTextWriter = new XmlTextWriter(memoryStream, Encoding.Unicode);
		try
		{
			xmlTextWriter.Formatting = Formatting.Indented;
			document.WriteContentTo(xmlTextWriter);
			xmlTextWriter.Flush();
			memoryStream.Flush();
			memoryStream.Position = 0L;
			return new StreamReader(memoryStream).ReadToEnd();
		}
		catch (Exception)
		{
			return document.ToString();
		}
	}

	public static Task<TResult> TimeoutAfter<TResult>(this Task<TResult> task, TimeSpan timeout)
	{
		//IL_000e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0018: Expected O, but got Unknown
		//IL_0030: Unknown result type (might be due to invalid IL or missing references)
		CancellationTokenSource timeoutCancellationTokenSource = new CancellationTokenSource();
		return TaskExtensions.Unwrap<TResult>(TaskExtension.WhenAny((Task)task, TaskExtension.Delay(timeout, timeoutCancellationTokenSource.Token)).ContinueWith<Task<TResult>>((Func<Task<Task>, Task<TResult>>)delegate(Task<Task> t)
		{
			if (t.Result == task)
			{
				timeoutCancellationTokenSource.Cancel();
				return task;
			}
			throw new TimeoutException("The operation has timed out. The network is broken, router has gone or is too busy.");
		}));
	}
}
internal static class EnumExtension
{
	public static bool HasFlag(this Enum value, Enum flag)
	{
		int num = (int)(object)value;
		int num2 = (int)(object)flag;
		return (num & num2) == num2;
	}
}
public static class CancellationTokenSourceExtension
{
	public static void CancelAfter(this CancellationTokenSource source, int millisecondsDelay)
	{
		if (millisecondsDelay < -1)
		{
			throw new ArgumentOutOfRangeException("millisecondsDelay");
		}
		new Timer(delegate(object self)
		{
			((Timer)self).Dispose();
			try
			{
				source.Cancel();
			}
			catch (ObjectDisposedException)
			{
			}
		}).Change(millisecondsDelay, -1);
	}
}
public static class TaskExtension
{
	public static Task Delay(TimeSpan delay, CancellationToken token)
	{
		//IL_005c: Unknown result type (might be due to invalid IL or missing references)
		long num = checked((long)delay.TotalMilliseconds);
		if (num < -1 || num > int.MaxValue)
		{
			throw new ArgumentOutOfRangeException("delay");
		}
		TaskCompletionSource<object> tcs = new TaskCompletionSource<object>();
		Timer timer = new Timer(delegate
		{
			tcs.TrySetResult((object)null);
		}, null, num, -1L);
		((CancellationToken)(ref token)).Register((Action)delegate
		{
			timer.Dispose();
			tcs.TrySetCanceled();
		});
		return (Task)(object)tcs.Task;
	}

	public static Task<Task> WhenAny(params Task[] tasks)
	{
		return Task.Factory.ContinueWhenAny<Task>(tasks, (Func<Task, Task>)((Task t) => t));
	}

	public static Task WhenAll(params Task[] tasks)
	{
		return (Task)(object)Task.Factory.ContinueWhenAll<Task[]>(tasks, (Func<Task[], Task[]>)((Task[] t) => t));
	}
}
internal interface IIPAddressesProvider
{
	IEnumerable<IPAddress> DnsAddresses();

	IEnumerable<IPAddress> GatewayAddresses();

	IEnumerable<IPAddress> UnicastAddresses();
}
internal class IPAddressesProvider : IIPAddressesProvider
{
	public IEnumerable<IPAddress> UnicastAddresses()
	{
		return IPAddresses((IPInterfaceProperties p) => p.UnicastAddresses.Select((UnicastIPAddressInformation x) => x.Address));
	}

	public IEnumerable<IPAddress> DnsAddresses()
	{
		return IPAddresses((IPInterfaceProperties p) => p.DnsAddresses);
	}

	public IEnumerable<IPAddress> GatewayAddresses()
	{
		return IPAddresses((IPInterfaceProperties p) => p.GatewayAddresses.Select((GatewayIPAddressInformation x) => x.Address));
	}

	private static IEnumerable<IPAddress> IPAddresses(Func<IPInterfaceProperties, IEnumerable<IPAddress>> ipExtractor)
	{
		return from networkInterface in NetworkInterface.GetAllNetworkInterfaces()
			where networkInterface.OperationalStatus == OperationalStatus.Up || networkInterface.OperationalStatus == OperationalStatus.Unknown
			let properties = networkInterface.GetIPProperties()
			from address in ipExtractor(properties)
			where address.AddressFamily == AddressFamily.InterNetwork
			select address;
	}
}
internal static class WellKnownConstants
{
	public static IPAddress IPv4MulticastAddress = IPAddress.Parse("239.255.255.250");

	public static IPEndPoint NatPmpEndPoint = new IPEndPoint(IPAddress.Parse("192.168.0.1"), 5351);
}

System.Threading.dll

Decompiled 2 months ago
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Globalization;
using System.Linq.Parallel;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Security;
using System.Security.Permissions;
using System.Threading;
using System.Threading.Tasks;

[assembly: InternalsVisibleTo("PlinqTest, PublicKey=0024000004800000940000000602000000240000525341310004000001000100CB7351F3887F5CB603C8CFBCA50868570B5BBECB60106DCBBDC4E18A20D5F84A64294699284628A768130175AF63C391C5E0D7FF19F05AF5FD4BC9641391293E094F92CCFF19234F3284DB149AFAE9F604A9A34FA7203549D2D4AD5CD80088682E0C137BCE1C38400955CB7CEDF5E9F532852F9C06AB50FCAA036216A95DE0CE")]
[assembly: CompilationRelaxations(8)]
[assembly: AssemblyFileVersion("1.0.2856.0")]
[assembly: CLSCompliant(true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: InternalsVisibleTo("plinq_devtests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100CB7351F3887F5CB603C8CFBCA50868570B5BBECB60106DCBBDC4E18A20D5F84A64294699284628A768130175AF63C391C5E0D7FF19F05AF5FD4BC9641391293E094F92CCFF19234F3284DB149AFAE9F604A9A34FA7203549D2D4AD5CD80088682E0C137BCE1C38400955CB7CEDF5E9F532852F9C06AB50FCAA036216A95DE0CE")]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: AssemblyCompany("Microsoft Corporation")]
[assembly: AssemblyCopyright("Copyright © Microsoft Corporation 2011")]
[assembly: AssemblyTitle("System.Threading")]
[assembly: AssemblyProduct("Reactive Extensions Core Library")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.2856.102")]
[module: UnverifiableCode]
namespace System.Diagnostics.Contracts
{
	internal static class Contract
	{
		[Conditional("DEBUG")]
		internal static void Assert(bool condition)
		{
		}

		[Conditional("DEBUG")]
		internal static void Assert(bool condition, string message)
		{
		}

		[Conditional("DEBUG")]
		internal static void Ensures(bool condition)
		{
		}

		[Conditional("DEBUG")]
		internal static void EndContractBlock()
		{
		}
	}
}
namespace System
{
	internal static class Environment2
	{
		internal static string GetResourceString(string key)
		{
			if (key == "AggregateException_ToString")
			{
				return "{0}{1}---> (Inner Exception #{2}) {3}{4}{5}";
			}
			return key;
		}
	}
}
namespace System.Threading.Tasks
{
	internal interface IThreadPoolWorkItem
	{
		void ExecuteWorkItem();

		void MarkAborted(ThreadAbortException tae);
	}
}
namespace System.Threading
{
	internal class Monitor2
	{
		internal static void Enter(object obj, ref bool taken)
		{
			Monitor.Enter(obj);
			taken = true;
		}

		internal static bool TryEnter(object obj)
		{
			return Monitor.TryEnter(obj);
		}

		internal static void TryEnter(object obj, ref bool taken)
		{
			taken = Monitor.TryEnter(obj);
		}

		internal static bool TryEnter(object obj, int millisecondsTimeout)
		{
			return Monitor.TryEnter(obj, millisecondsTimeout);
		}

		internal static bool TryEnter(object obj, TimeSpan timeout)
		{
			return Monitor.TryEnter(obj, timeout);
		}

		internal static void TryEnter(object obj, int millisecondsTimeout, ref bool taken)
		{
			taken = Monitor.TryEnter(obj, millisecondsTimeout);
		}
	}
}
namespace System.Collections.Generic
{
	internal sealed class Mscorlib_DictionaryDebugView<K, V>
	{
		private IDictionary<K, V> dict;

		[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
		internal KeyValuePair<K, V>[] Items
		{
			get
			{
				KeyValuePair<K, V>[] array = new KeyValuePair<K, V>[dict.Count];
				dict.CopyTo(array, 0);
				return array;
			}
		}

		internal Mscorlib_DictionaryDebugView(IDictionary<K, V> dictionary)
		{
			if (dictionary == null)
			{
				throw new ArgumentNullException("dictionary");
			}
			dict = dictionary;
		}
	}
}
namespace System
{
	[Serializable]
	[ComVisible(true)]
	internal class OperationCanceledException2 : OperationCanceledException
	{
		[NonSerialized]
		private CancellationToken _cancellationToken;

		public new CancellationToken CancellationToken
		{
			get
			{
				return _cancellationToken;
			}
			private set
			{
				_cancellationToken = value;
			}
		}

		public OperationCanceledException2()
			: base(Environment2.GetResourceString("OperationCanceled"))
		{
		}

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

		public OperationCanceledException2(string message, Exception innerException)
			: base(message, innerException)
		{
		}

		public OperationCanceledException2(CancellationToken token)
			: this()
		{
			CancellationToken = token;
		}

		public OperationCanceledException2(string message, CancellationToken token)
			: this(message)
		{
			CancellationToken = token;
		}

		public OperationCanceledException2(string message, Exception innerException, CancellationToken token)
			: this(message, innerException)
		{
			CancellationToken = token;
		}

		protected OperationCanceledException2(SerializationInfo info, StreamingContext context)
			: base(info, context)
		{
		}
	}
}
namespace System.Threading
{
	internal static class Platform
	{
		internal static int ProcessorCount => Environment.ProcessorCount;

		internal static bool IsSingleProcessor => ProcessorCount == 1;

		[DllImport("kernel32.dll")]
		private static extern int SwitchToThread();

		internal static void Yield()
		{
			SwitchToThread();
		}
	}
}
namespace System
{
	internal class SecuritySafeCriticalAttribute : Attribute
	{
	}
}
namespace System.Threading
{
	[StructLayout(LayoutKind.Sequential, Size = 1)]
	internal struct StackCrawlMark2
	{
		internal static StackCrawlMark2 LookForMyCaller => default(StackCrawlMark2);
	}
}
namespace System.Collections.Concurrent
{
	[Serializable]
	[DebuggerTypeProxy(typeof(Mscorlib_DictionaryDebugView<, >))]
	[DebuggerDisplay("Count = {Count}")]
	[ComVisible(false)]
	[HostProtection(SecurityAction.LinkDemand, Synchronization = true, ExternalThreading = true)]
	public class ConcurrentDictionary<TKey, TValue> : IDictionary<TKey, TValue>, ICollection<KeyValuePair<TKey, TValue>>, IEnumerable<KeyValuePair<TKey, TValue>>, IDictionary, ICollection, IEnumerable
	{
		private class Node
		{
			internal TKey m_key;

			internal TValue m_value;

			internal volatile Node m_next;

			internal int m_hashcode;

			internal Node(TKey key, TValue value, int hashcode)
				: this(key, value, hashcode, (Node)null)
			{
			}

			internal Node(TKey key, TValue value, int hashcode, Node next)
			{
				m_key = key;
				m_value = value;
				m_next = next;
				m_hashcode = hashcode;
			}
		}

		private class DictionaryEnumerator : IDictionaryEnumerator, IEnumerator
		{
			private IEnumerator<KeyValuePair<TKey, TValue>> m_enumerator;

			public DictionaryEntry Entry => new DictionaryEntry(m_enumerator.Current.Key, m_enumerator.Current.Value);

			public object Key => m_enumerator.Current.Key;

			public object Value => m_enumerator.Current.Value;

			public object Current => Entry;

			internal DictionaryEnumerator(ConcurrentDictionary<TKey, TValue> dictionary)
			{
				m_enumerator = dictionary.GetEnumerator();
			}

			public bool MoveNext()
			{
				return m_enumerator.MoveNext();
			}

			public void Reset()
			{
				m_enumerator.Reset();
			}
		}

		private const int DEFAULT_CONCURRENCY_MULTIPLIER = 4;

		private const int DEFAULT_CAPACITY = 31;

		[NonSerialized]
		private volatile Node[] m_buckets;

		[NonSerialized]
		private object[] m_locks;

		[NonSerialized]
		private volatile int[] m_countPerLock;

		private IEqualityComparer<TKey> m_comparer;

		private KeyValuePair<TKey, TValue>[] m_serializationArray;

		private int m_serializationConcurrencyLevel;

		private int m_serializationCapacity;

		public TValue this[TKey key]
		{
			get
			{
				if (!TryGetValue(key, out var value))
				{
					throw new KeyNotFoundException();
				}
				return value;
			}
			set
			{
				if (key == null)
				{
					throw new ArgumentNullException("key");
				}
				TryAddInternal(key, value, updateIfExists: true, acquireLock: true, out var _);
			}
		}

		public int Count
		{
			get
			{
				int num = 0;
				int locksAcquired = 0;
				try
				{
					AcquireAllLocks(ref locksAcquired);
					for (int i = 0; i < m_countPerLock.Length; i++)
					{
						num += m_countPerLock[i];
					}
					return num;
				}
				finally
				{
					ReleaseLocks(0, locksAcquired);
				}
			}
		}

		public bool IsEmpty
		{
			get
			{
				int locksAcquired = 0;
				try
				{
					AcquireAllLocks(ref locksAcquired);
					for (int i = 0; i < m_countPerLock.Length; i++)
					{
						if (m_countPerLock[i] != 0)
						{
							return false;
						}
					}
				}
				finally
				{
					ReleaseLocks(0, locksAcquired);
				}
				return true;
			}
		}

		public ICollection<TKey> Keys => GetKeys();

		public ICollection<TValue> Values => GetValues();

		bool ICollection<KeyValuePair<TKey, TValue>>.IsReadOnly => false;

		bool IDictionary.IsFixedSize => false;

		bool IDictionary.IsReadOnly => false;

		ICollection IDictionary.Keys => GetKeys();

		ICollection IDictionary.Values => GetValues();

		object IDictionary.this[object key]
		{
			get
			{
				if (key == null)
				{
					throw new ArgumentNullException("key");
				}
				if (key is TKey && TryGetValue((TKey)key, out var value))
				{
					return value;
				}
				return null;
			}
			set
			{
				if (key == null)
				{
					throw new ArgumentNullException("key");
				}
				if (!(key is TKey))
				{
					throw new ArgumentException(GetResource("ConcurrentDictionary_TypeOfKeyIncorrect"));
				}
				if (!(value is TValue))
				{
					throw new ArgumentException(GetResource("ConcurrentDictionary_TypeOfValueIncorrect"));
				}
				this[(TKey)key] = (TValue)value;
			}
		}

		bool ICollection.IsSynchronized => false;

		object ICollection.SyncRoot
		{
			get
			{
				throw new NotSupportedException(Environment2.GetResourceString("ConcurrentCollection_SyncRoot_NotSupported"));
			}
		}

		private static int DefaultConcurrencyLevel => 4 * Environment.ProcessorCount;

		public ConcurrentDictionary()
			: this(DefaultConcurrencyLevel, 31)
		{
		}

		public ConcurrentDictionary(int concurrencyLevel, int capacity)
			: this(concurrencyLevel, capacity, (IEqualityComparer<TKey>)EqualityComparer<TKey>.Default)
		{
		}

		public ConcurrentDictionary(IEnumerable<KeyValuePair<TKey, TValue>> collection)
			: this(collection, (IEqualityComparer<TKey>)EqualityComparer<TKey>.Default)
		{
		}

		public ConcurrentDictionary(IEqualityComparer<TKey> comparer)
			: this(DefaultConcurrencyLevel, 31, comparer)
		{
		}

		public ConcurrentDictionary(IEnumerable<KeyValuePair<TKey, TValue>> collection, IEqualityComparer<TKey> comparer)
			: this(DefaultConcurrencyLevel, collection, comparer)
		{
		}

		public ConcurrentDictionary(int concurrencyLevel, IEnumerable<KeyValuePair<TKey, TValue>> collection, IEqualityComparer<TKey> comparer)
			: this(concurrencyLevel, 31, comparer)
		{
			if (collection == null)
			{
				throw new ArgumentNullException("collection");
			}
			if (comparer == null)
			{
				throw new ArgumentNullException("comparer");
			}
			InitializeFromCollection(collection);
		}

		private void InitializeFromCollection(IEnumerable<KeyValuePair<TKey, TValue>> collection)
		{
			foreach (KeyValuePair<TKey, TValue> item in collection)
			{
				if (item.Key == null)
				{
					throw new ArgumentNullException("key");
				}
				if (!TryAddInternal(item.Key, item.Value, updateIfExists: false, acquireLock: false, out var _))
				{
					throw new ArgumentException(GetResource("ConcurrentDictionary_SourceContainsDuplicateKeys"));
				}
			}
		}

		public ConcurrentDictionary(int concurrencyLevel, int capacity, IEqualityComparer<TKey> comparer)
		{
			if (concurrencyLevel < 1)
			{
				throw new ArgumentOutOfRangeException("concurrencyLevel", GetResource("ConcurrentDictionary_ConcurrencyLevelMustBePositive"));
			}
			if (capacity < 0)
			{
				throw new ArgumentOutOfRangeException("capacity", GetResource("ConcurrentDictionary_CapacityMustNotBeNegative"));
			}
			if (comparer == null)
			{
				throw new ArgumentNullException("comparer");
			}
			if (capacity < concurrencyLevel)
			{
				capacity = concurrencyLevel;
			}
			m_locks = new object[concurrencyLevel];
			for (int i = 0; i < m_locks.Length; i++)
			{
				m_locks[i] = new object();
			}
			m_countPerLock = new int[m_locks.Length];
			m_buckets = new Node[capacity];
			m_comparer = comparer;
		}

		public bool TryAdd(TKey key, TValue value)
		{
			if (key == null)
			{
				throw new ArgumentNullException("key");
			}
			TValue resultingValue;
			return TryAddInternal(key, value, updateIfExists: false, acquireLock: true, out resultingValue);
		}

		public bool ContainsKey(TKey key)
		{
			if (key == null)
			{
				throw new ArgumentNullException("key");
			}
			TValue value;
			return TryGetValue(key, out value);
		}

		public bool TryRemove(TKey key, out TValue value)
		{
			if (key == null)
			{
				throw new ArgumentNullException("key");
			}
			return TryRemoveInternal(key, out value, matchValue: false, default(TValue));
		}

		private bool TryRemoveInternal(TKey key, out TValue value, bool matchValue, TValue oldValue)
		{
			while (true)
			{
				Node[] buckets = m_buckets;
				GetBucketAndLockNo(m_comparer.GetHashCode(key), out var bucketNo, out var lockNo, buckets.Length);
				lock (m_locks[lockNo])
				{
					if (buckets != m_buckets)
					{
						continue;
					}
					Node node = null;
					for (Node node2 = m_buckets[bucketNo]; node2 != null; node2 = node2.m_next)
					{
						if (m_comparer.Equals(node2.m_key, key))
						{
							if (matchValue && !EqualityComparer<TValue>.Default.Equals(oldValue, node2.m_value))
							{
								value = default(TValue);
								return false;
							}
							if (node == null)
							{
								m_buckets[bucketNo] = node2.m_next;
							}
							else
							{
								node.m_next = node2.m_next;
							}
							value = node2.m_value;
							m_countPerLock[lockNo]--;
							return true;
						}
						node = node2;
					}
					break;
				}
			}
			value = default(TValue);
			return false;
		}

		public bool TryGetValue(TKey key, out TValue value)
		{
			if (key == null)
			{
				throw new ArgumentNullException("key");
			}
			Node[] buckets = m_buckets;
			GetBucketAndLockNo(m_comparer.GetHashCode(key), out var bucketNo, out var _, buckets.Length);
			Node node = buckets[bucketNo];
			Thread.MemoryBarrier();
			while (node != null)
			{
				if (m_comparer.Equals(node.m_key, key))
				{
					value = node.m_value;
					return true;
				}
				node = node.m_next;
			}
			value = default(TValue);
			return false;
		}

		public bool TryUpdate(TKey key, TValue newValue, TValue comparisonValue)
		{
			if (key == null)
			{
				throw new ArgumentNullException("key");
			}
			int hashCode = m_comparer.GetHashCode(key);
			IEqualityComparer<TValue> @default = EqualityComparer<TValue>.Default;
			while (true)
			{
				Node[] buckets = m_buckets;
				GetBucketAndLockNo(hashCode, out var bucketNo, out var lockNo, buckets.Length);
				lock (m_locks[lockNo])
				{
					if (buckets != m_buckets)
					{
						continue;
					}
					Node node = null;
					for (Node node2 = buckets[bucketNo]; node2 != null; node2 = node2.m_next)
					{
						if (m_comparer.Equals(node2.m_key, key))
						{
							if (@default.Equals(node2.m_value, comparisonValue))
							{
								Node node3 = new Node(node2.m_key, newValue, hashCode, node2.m_next);
								if (node == null)
								{
									buckets[bucketNo] = node3;
								}
								else
								{
									node.m_next = node3;
								}
								return true;
							}
							return false;
						}
						node = node2;
					}
					return false;
				}
			}
		}

		public void Clear()
		{
			int locksAcquired = 0;
			try
			{
				AcquireAllLocks(ref locksAcquired);
				m_buckets = new Node[31];
				Array.Clear(m_countPerLock, 0, m_countPerLock.Length);
			}
			finally
			{
				ReleaseLocks(0, locksAcquired);
			}
		}

		void ICollection<KeyValuePair<TKey, TValue>>.CopyTo(KeyValuePair<TKey, TValue>[] array, int index)
		{
			if (array == null)
			{
				throw new ArgumentNullException("array");
			}
			if (index < 0)
			{
				throw new ArgumentOutOfRangeException("index", GetResource("ConcurrentDictionary_IndexIsNegative"));
			}
			int locksAcquired = 0;
			try
			{
				AcquireAllLocks(ref locksAcquired);
				int num = 0;
				for (int i = 0; i < m_locks.Length; i++)
				{
					num += m_countPerLock[i];
				}
				if (array.Length - num < index || num < 0)
				{
					throw new ArgumentException(GetResource("ConcurrentDictionary_ArrayNotLargeEnough"));
				}
				CopyToPairs(array, index);
			}
			finally
			{
				ReleaseLocks(0, locksAcquired);
			}
		}

		public KeyValuePair<TKey, TValue>[] ToArray()
		{
			int locksAcquired = 0;
			checked
			{
				try
				{
					AcquireAllLocks(ref locksAcquired);
					int num = 0;
					for (int i = 0; i < m_locks.Length; i++)
					{
						num += m_countPerLock[i];
					}
					KeyValuePair<TKey, TValue>[] array = new KeyValuePair<TKey, TValue>[num];
					CopyToPairs(array, 0);
					return array;
				}
				finally
				{
					ReleaseLocks(0, locksAcquired);
				}
			}
		}

		private void CopyToPairs(KeyValuePair<TKey, TValue>[] array, int index)
		{
			Node[] buckets = m_buckets;
			for (int i = 0; i < buckets.Length; i++)
			{
				for (Node node = buckets[i]; node != null; node = node.m_next)
				{
					ref KeyValuePair<TKey, TValue> reference = ref array[index];
					reference = new KeyValuePair<TKey, TValue>(node.m_key, node.m_value);
					index++;
				}
			}
		}

		private void CopyToEntries(DictionaryEntry[] array, int index)
		{
			Node[] buckets = m_buckets;
			for (int i = 0; i < buckets.Length; i++)
			{
				for (Node node = buckets[i]; node != null; node = node.m_next)
				{
					ref DictionaryEntry reference = ref array[index];
					reference = new DictionaryEntry(node.m_key, node.m_value);
					index++;
				}
			}
		}

		private void CopyToObjects(object[] array, int index)
		{
			Node[] buckets = m_buckets;
			for (int i = 0; i < buckets.Length; i++)
			{
				for (Node node = buckets[i]; node != null; node = node.m_next)
				{
					array[index] = new KeyValuePair<TKey, TValue>(node.m_key, node.m_value);
					index++;
				}
			}
		}

		public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
		{
			Node[] buckets = m_buckets;
			for (int i = 0; i < buckets.Length; i++)
			{
				Node current = buckets[i];
				Thread.MemoryBarrier();
				while (current != null)
				{
					yield return new KeyValuePair<TKey, TValue>(current.m_key, current.m_value);
					current = current.m_next;
				}
			}
		}

		private bool TryAddInternal(TKey key, TValue value, bool updateIfExists, bool acquireLock, out TValue resultingValue)
		{
			int hashCode = m_comparer.GetHashCode(key);
			Node[] buckets;
			bool flag;
			while (true)
			{
				buckets = m_buckets;
				GetBucketAndLockNo(hashCode, out var bucketNo, out var lockNo, buckets.Length);
				flag = false;
				bool taken = false;
				try
				{
					if (acquireLock)
					{
						Monitor2.Enter(m_locks[lockNo], ref taken);
					}
					if (buckets != m_buckets)
					{
						continue;
					}
					Node node = null;
					for (Node node2 = buckets[bucketNo]; node2 != null; node2 = node2.m_next)
					{
						if (m_comparer.Equals(node2.m_key, key))
						{
							if (updateIfExists)
							{
								Node node3 = new Node(node2.m_key, value, hashCode, node2.m_next);
								if (node == null)
								{
									buckets[bucketNo] = node3;
								}
								else
								{
									node.m_next = node3;
								}
								resultingValue = value;
							}
							else
							{
								resultingValue = node2.m_value;
							}
							return false;
						}
						node = node2;
					}
					buckets[bucketNo] = new Node(key, value, hashCode, buckets[bucketNo]);
					checked
					{
						m_countPerLock[lockNo]++;
					}
					if (m_countPerLock[lockNo] > buckets.Length / m_locks.Length)
					{
						flag = true;
					}
					break;
				}
				finally
				{
					if (taken)
					{
						Monitor.Exit(m_locks[lockNo]);
					}
				}
			}
			if (flag)
			{
				GrowTable(buckets);
			}
			resultingValue = value;
			return true;
		}

		public TValue GetOrAdd(TKey key, Func<TKey, TValue> valueFactory)
		{
			if (key == null)
			{
				throw new ArgumentNullException("key");
			}
			if (valueFactory == null)
			{
				throw new ArgumentNullException("valueFactory");
			}
			if (TryGetValue(key, out var value))
			{
				return value;
			}
			TryAddInternal(key, valueFactory(key), updateIfExists: false, acquireLock: true, out value);
			return value;
		}

		public TValue GetOrAdd(TKey key, TValue value)
		{
			if (key == null)
			{
				throw new ArgumentNullException("key");
			}
			TryAddInternal(key, value, updateIfExists: false, acquireLock: true, out var resultingValue);
			return resultingValue;
		}

		public TValue AddOrUpdate(TKey key, Func<TKey, TValue> addValueFactory, Func<TKey, TValue, TValue> updateValueFactory)
		{
			if (key == null)
			{
				throw new ArgumentNullException("key");
			}
			if (addValueFactory == null)
			{
				throw new ArgumentNullException("addValueFactory");
			}
			if (updateValueFactory == null)
			{
				throw new ArgumentNullException("updateValueFactory");
			}
			TValue resultingValue;
			while (true)
			{
				if (TryGetValue(key, out var value))
				{
					TValue val = updateValueFactory(key, value);
					if (TryUpdate(key, val, value))
					{
						return val;
					}
				}
				else
				{
					TValue val = addValueFactory(key);
					if (TryAddInternal(key, val, updateIfExists: false, acquireLock: true, out resultingValue))
					{
						break;
					}
				}
			}
			return resultingValue;
		}

		public TValue AddOrUpdate(TKey key, TValue addValue, Func<TKey, TValue, TValue> updateValueFactory)
		{
			if (key == null)
			{
				throw new ArgumentNullException("key");
			}
			if (updateValueFactory == null)
			{
				throw new ArgumentNullException("updateValueFactory");
			}
			TValue resultingValue;
			while (true)
			{
				if (TryGetValue(key, out var value))
				{
					TValue val = updateValueFactory(key, value);
					if (TryUpdate(key, val, value))
					{
						return val;
					}
				}
				else if (TryAddInternal(key, addValue, updateIfExists: false, acquireLock: true, out resultingValue))
				{
					break;
				}
			}
			return resultingValue;
		}

		void IDictionary<TKey, TValue>.Add(TKey key, TValue value)
		{
			if (!TryAdd(key, value))
			{
				throw new ArgumentException(GetResource("ConcurrentDictionary_KeyAlreadyExisted"));
			}
		}

		bool IDictionary<TKey, TValue>.Remove(TKey key)
		{
			TValue value;
			return TryRemove(key, out value);
		}

		void ICollection<KeyValuePair<TKey, TValue>>.Add(KeyValuePair<TKey, TValue> keyValuePair)
		{
			((IDictionary<TKey, TValue>)this).Add(keyValuePair.Key, keyValuePair.Value);
		}

		bool ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue> keyValuePair)
		{
			if (!TryGetValue(keyValuePair.Key, out var value))
			{
				return false;
			}
			return EqualityComparer<TValue>.Default.Equals(value, keyValuePair.Value);
		}

		bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> keyValuePair)
		{
			if (keyValuePair.Key == null)
			{
				throw new ArgumentNullException(GetResource("ConcurrentDictionary_ItemKeyIsNull"));
			}
			TValue value;
			return TryRemoveInternal(keyValuePair.Key, out value, matchValue: true, keyValuePair.Value);
		}

		IEnumerator IEnumerable.GetEnumerator()
		{
			return GetEnumerator();
		}

		void IDictionary.Add(object key, object value)
		{
			if (key == null)
			{
				throw new ArgumentNullException("key");
			}
			if (!(key is TKey))
			{
				throw new ArgumentException(GetResource("ConcurrentDictionary_TypeOfKeyIncorrect"));
			}
			TValue value2;
			try
			{
				value2 = (TValue)value;
			}
			catch (InvalidCastException)
			{
				throw new ArgumentException(GetResource("ConcurrentDictionary_TypeOfValueIncorrect"));
			}
			((IDictionary<TKey, TValue>)this).Add((TKey)key, value2);
		}

		bool IDictionary.Contains(object key)
		{
			if (key == null)
			{
				throw new ArgumentNullException("key");
			}
			if (key is TKey)
			{
				return ContainsKey((TKey)key);
			}
			return false;
		}

		IDictionaryEnumerator IDictionary.GetEnumerator()
		{
			return new DictionaryEnumerator(this);
		}

		void IDictionary.Remove(object key)
		{
			if (key == null)
			{
				throw new ArgumentNullException("key");
			}
			if (key is TKey)
			{
				TryRemove((TKey)key, out var _);
			}
		}

		void ICollection.CopyTo(Array array, int index)
		{
			if (array == null)
			{
				throw new ArgumentNullException("array");
			}
			if (index < 0)
			{
				throw new ArgumentOutOfRangeException("index", GetResource("ConcurrentDictionary_IndexIsNegative"));
			}
			int locksAcquired = 0;
			try
			{
				AcquireAllLocks(ref locksAcquired);
				int num = 0;
				for (int i = 0; i < m_locks.Length; i++)
				{
					num += m_countPerLock[i];
				}
				if (array.Length - num < index || num < 0)
				{
					throw new ArgumentException(GetResource("ConcurrentDictionary_ArrayNotLargeEnough"));
				}
				if (array is KeyValuePair<TKey, TValue>[] array2)
				{
					CopyToPairs(array2, index);
					return;
				}
				if (array is DictionaryEntry[] array3)
				{
					CopyToEntries(array3, index);
					return;
				}
				if (array is object[] array4)
				{
					CopyToObjects(array4, index);
					return;
				}
				throw new ArgumentException(GetResource("ConcurrentDictionary_ArrayIncorrectType"), "array");
			}
			finally
			{
				ReleaseLocks(0, locksAcquired);
			}
		}

		private void GrowTable(Node[] buckets)
		{
			int locksAcquired = 0;
			checked
			{
				try
				{
					AcquireLocks(0, 1, ref locksAcquired);
					if (buckets != m_buckets)
					{
						return;
					}
					int i;
					try
					{
						for (i = buckets.Length * 2 + 1; unchecked(i % 3 == 0 || i % 5 == 0 || i % 7 == 0); i += 2)
						{
						}
					}
					catch (OverflowException)
					{
						return;
					}
					Node[] array = new Node[i];
					int[] array2 = new int[m_locks.Length];
					AcquireLocks(1, m_locks.Length, ref locksAcquired);
					for (int j = 0; j < buckets.Length; j = unchecked(j + 1))
					{
						Node node = buckets[j];
						while (node != null)
						{
							Node next = node.m_next;
							GetBucketAndLockNo(node.m_hashcode, out var bucketNo, out var lockNo, array.Length);
							array[bucketNo] = new Node(node.m_key, node.m_value, node.m_hashcode, array[bucketNo]);
							array2[lockNo]++;
							node = next;
						}
					}
					m_buckets = array;
					m_countPerLock = array2;
				}
				finally
				{
					ReleaseLocks(0, locksAcquired);
				}
			}
		}

		private void GetBucketAndLockNo(int hashcode, out int bucketNo, out int lockNo, int bucketCount)
		{
			bucketNo = (hashcode & 0x7FFFFFFF) % bucketCount;
			lockNo = bucketNo % m_locks.Length;
		}

		private void AcquireAllLocks(ref int locksAcquired)
		{
			AcquireLocks(0, m_locks.Length, ref locksAcquired);
		}

		private void AcquireLocks(int fromInclusive, int toExclusive, ref int locksAcquired)
		{
			for (int i = fromInclusive; i < toExclusive; i++)
			{
				bool taken = false;
				try
				{
					Monitor2.Enter(m_locks[i], ref taken);
				}
				finally
				{
					if (taken)
					{
						locksAcquired++;
					}
				}
			}
		}

		private void ReleaseLocks(int fromInclusive, int toExclusive)
		{
			for (int i = fromInclusive; i < toExclusive; i++)
			{
				Monitor.Exit(m_locks[i]);
			}
		}

		private ReadOnlyCollection<TKey> GetKeys()
		{
			int locksAcquired = 0;
			try
			{
				AcquireAllLocks(ref locksAcquired);
				List<TKey> list = new List<TKey>();
				for (int i = 0; i < m_buckets.Length; i++)
				{
					for (Node node = m_buckets[i]; node != null; node = node.m_next)
					{
						list.Add(node.m_key);
					}
				}
				return new ReadOnlyCollection<TKey>(list);
			}
			finally
			{
				ReleaseLocks(0, locksAcquired);
			}
		}

		private ReadOnlyCollection<TValue> GetValues()
		{
			int locksAcquired = 0;
			try
			{
				AcquireAllLocks(ref locksAcquired);
				List<TValue> list = new List<TValue>();
				for (int i = 0; i < m_buckets.Length; i++)
				{
					for (Node node = m_buckets[i]; node != null; node = node.m_next)
					{
						list.Add(node.m_value);
					}
				}
				return new ReadOnlyCollection<TValue>(list);
			}
			finally
			{
				ReleaseLocks(0, locksAcquired);
			}
		}

		[Conditional("DEBUG")]
		private void Assert(bool condition)
		{
		}

		private string GetResource(string key)
		{
			return Environment2.GetResourceString(key);
		}

		[OnSerializing]
		private void OnSerializing(StreamingContext context)
		{
			m_serializationArray = ToArray();
			m_serializationConcurrencyLevel = m_locks.Length;
			m_serializationCapacity = m_buckets.Length;
		}

		[OnDeserialized]
		private void OnDeserialized(StreamingContext context)
		{
			KeyValuePair<TKey, TValue>[] serializationArray = m_serializationArray;
			m_buckets = new Node[m_serializationCapacity];
			m_countPerLock = new int[m_serializationConcurrencyLevel];
			m_locks = new object[m_serializationConcurrencyLevel];
			for (int i = 0; i < m_locks.Length; i++)
			{
				m_locks[i] = new object();
			}
			InitializeFromCollection(serializationArray);
			m_serializationArray = null;
		}
	}
	public interface IProducerConsumerCollection<T> : IEnumerable<T>, ICollection, IEnumerable
	{
		void CopyTo(T[] array, int index);

		bool TryAdd(T item);

		bool TryTake(out T item);

		T[] ToArray();
	}
	[Serializable]
	[DebuggerDisplay("Count = {Count}")]
	[ComVisible(false)]
	[DebuggerTypeProxy(typeof(SystemCollectionsConcurrent_ProducerConsumerCollectionDebugView<>))]
	[HostProtection(SecurityAction.LinkDemand, Synchronization = true, ExternalThreading = true)]
	public class ConcurrentQueue<T> : IProducerConsumerCollection<T>, IEnumerable<T>, ICollection, IEnumerable
	{
		private class Segment
		{
			internal volatile T[] m_array;

			private volatile int[] m_state;

			private volatile Segment m_next;

			internal readonly long m_index;

			private volatile int m_low;

			private volatile int m_high;

			internal Segment Next => m_next;

			internal bool IsEmpty => Low > High;

			internal int Low => Math.Min(m_low, 32);

			internal int High => Math.Min(m_high, 31);

			internal Segment(long index)
			{
				m_array = new T[32];
				m_state = new int[32];
				m_high = -1;
				m_index = index;
			}

			internal void UnsafeAdd(T value)
			{
				m_high++;
				m_array[m_high] = value;
				m_state[m_high] = 1;
			}

			internal Segment UnsafeGrow()
			{
				return m_next = new Segment(m_index + 1);
			}

			internal void Grow(ref Segment tail)
			{
				Segment next = new Segment(m_index + 1);
				m_next = next;
				tail = m_next;
			}

			internal bool TryAppend(T value, ref Segment tail)
			{
				if (m_high >= 31)
				{
					return false;
				}
				int num = 32;
				try
				{
				}
				finally
				{
					num = Interlocked.Increment(ref m_high);
					if (num <= 31)
					{
						m_array[num] = value;
						m_state[num] = 1;
					}
					if (num == 31)
					{
						Grow(ref tail);
					}
				}
				return num <= 31;
			}

			internal bool TryRemove(out T result, ref Segment head)
			{
				SpinWait spinWait = default(SpinWait);
				int low = Low;
				int high = High;
				while (low <= high)
				{
					if (Interlocked.CompareExchange(ref m_low, low + 1, low) == low)
					{
						SpinWait spinWait2 = default(SpinWait);
						while (m_state[low] == 0)
						{
							spinWait2.SpinOnce();
						}
						result = m_array[low];
						if (low + 1 >= 32)
						{
							spinWait2 = default(SpinWait);
							while (m_next == null)
							{
								spinWait2.SpinOnce();
							}
							head = m_next;
						}
						return true;
					}
					spinWait.SpinOnce();
					low = Low;
					high = High;
				}
				result = default(T);
				return false;
			}

			internal bool TryPeek(out T result)
			{
				result = default(T);
				int low = Low;
				if (low > High)
				{
					return false;
				}
				SpinWait spinWait = default(SpinWait);
				while (m_state[low] == 0)
				{
					spinWait.SpinOnce();
				}
				result = m_array[low];
				return true;
			}

			internal List<T> ToList(int start, int end)
			{
				List<T> list = new List<T>();
				for (int i = start; i <= end; i++)
				{
					SpinWait spinWait = default(SpinWait);
					while (m_state[i] == 0)
					{
						spinWait.SpinOnce();
					}
					list.Add(m_array[i]);
				}
				return list;
			}
		}

		private const int SEGMENT_SIZE = 32;

		[NonSerialized]
		private volatile Segment m_head;

		[NonSerialized]
		private volatile Segment m_tail;

		private T[] m_serializationArray;

		bool ICollection.IsSynchronized => false;

		object ICollection.SyncRoot
		{
			get
			{
				throw new NotSupportedException(Environment2.GetResourceString("ConcurrentCollection_SyncRoot_NotSupported"));
			}
		}

		public bool IsEmpty
		{
			get
			{
				Segment head = m_head;
				if (!head.IsEmpty)
				{
					return false;
				}
				if (head.Next == null)
				{
					return true;
				}
				SpinWait spinWait = default(SpinWait);
				while (head.IsEmpty)
				{
					if (head.Next == null)
					{
						return true;
					}
					spinWait.SpinOnce();
					head = m_head;
				}
				return false;
			}
		}

		public int Count
		{
			get
			{
				GetHeadTailPositions(out var head, out var tail, out var headLow, out var tailHigh);
				if (head == tail)
				{
					return tailHigh - headLow + 1;
				}
				int num = 32 - headLow;
				num += 32 * (int)(tail.m_index - head.m_index - 1);
				return num + (tailHigh + 1);
			}
		}

		public ConcurrentQueue()
		{
			m_head = (m_tail = new Segment(0L));
		}

		private void InitializeFromCollection(IEnumerable<T> collection)
		{
			m_head = (m_tail = new Segment(0L));
			int num = 0;
			foreach (T item in collection)
			{
				m_tail.UnsafeAdd(item);
				num++;
				if (num >= 32)
				{
					m_tail = m_tail.UnsafeGrow();
					num = 0;
				}
			}
		}

		public ConcurrentQueue(IEnumerable<T> collection)
		{
			if (collection == null)
			{
				throw new ArgumentNullException("collection");
			}
			InitializeFromCollection(collection);
		}

		[OnSerializing]
		private void OnSerializing(StreamingContext context)
		{
			m_serializationArray = ToArray();
		}

		[OnDeserialized]
		private void OnDeserialized(StreamingContext context)
		{
			InitializeFromCollection(m_serializationArray);
			m_serializationArray = null;
		}

		void ICollection.CopyTo(Array array, int index)
		{
			if (array == null)
			{
				throw new ArgumentNullException("array");
			}
			((ICollection)ToList()).CopyTo(array, index);
		}

		IEnumerator IEnumerable.GetEnumerator()
		{
			return ((IEnumerable<T>)this).GetEnumerator();
		}

		bool IProducerConsumerCollection<T>.TryAdd(T item)
		{
			Enqueue(item);
			return true;
		}

		bool IProducerConsumerCollection<T>.TryTake(out T item)
		{
			return TryDequeue(out item);
		}

		public T[] ToArray()
		{
			return ToList().ToArray();
		}

		private List<T> ToList()
		{
			GetHeadTailPositions(out var head, out var tail, out var headLow, out var tailHigh);
			if (head == tail)
			{
				return head.ToList(headLow, tailHigh);
			}
			List<T> list = new List<T>(head.ToList(headLow, 31));
			for (Segment next = head.Next; next != tail; next = next.Next)
			{
				list.AddRange(next.ToList(0, 31));
			}
			list.AddRange(tail.ToList(0, tailHigh));
			return list;
		}

		private void GetHeadTailPositions(out Segment head, out Segment tail, out int headLow, out int tailHigh)
		{
			head = m_head;
			tail = m_tail;
			headLow = head.Low;
			tailHigh = tail.High;
			SpinWait spinWait = default(SpinWait);
			while (head != m_head || tail != m_tail || headLow != head.Low || tailHigh != tail.High || head.m_index > tail.m_index)
			{
				spinWait.SpinOnce();
				head = m_head;
				tail = m_tail;
				headLow = head.Low;
				tailHigh = tail.High;
			}
		}

		public void CopyTo(T[] array, int index)
		{
			if (array == null)
			{
				throw new ArgumentNullException("array");
			}
			ToList().CopyTo(array, index);
		}

		public IEnumerator<T> GetEnumerator()
		{
			return ToList().GetEnumerator();
		}

		public void Enqueue(T item)
		{
			SpinWait spinWait = default(SpinWait);
			while (true)
			{
				Segment tail = m_tail;
				if (tail.TryAppend(item, ref m_tail))
				{
					break;
				}
				spinWait.SpinOnce();
			}
		}

		public bool TryDequeue(out T result)
		{
			while (!IsEmpty)
			{
				Segment head = m_head;
				if (head.TryRemove(out result, ref m_head))
				{
					return true;
				}
			}
			result = default(T);
			return false;
		}

		public bool TryPeek(out T result)
		{
			while (!IsEmpty)
			{
				Segment head = m_head;
				if (head.TryPeek(out result))
				{
					return true;
				}
			}
			result = default(T);
			return false;
		}
	}
	[Serializable]
	[DebuggerDisplay("Count = {Count}")]
	[DebuggerTypeProxy(typeof(SystemCollectionsConcurrent_ProducerConsumerCollectionDebugView<>))]
	[HostProtection(SecurityAction.LinkDemand, Synchronization = true, ExternalThreading = true)]
	public class ConcurrentStack<T> : IProducerConsumerCollection<T>, IEnumerable<T>, ICollection, IEnumerable
	{
		private class Node
		{
			internal T m_value;

			internal Node m_next;

			internal Node(T value)
			{
				m_value = value;
				m_next = null;
			}
		}

		private const int BACKOFF_MAX_YIELDS = 8;

		[NonSerialized]
		private volatile Node m_head;

		private T[] m_serializationArray;

		public bool IsEmpty => m_head == null;

		public int Count
		{
			get
			{
				int num = 0;
				for (Node node = m_head; node != null; node = node.m_next)
				{
					num++;
				}
				return num;
			}
		}

		bool ICollection.IsSynchronized => false;

		object ICollection.SyncRoot
		{
			get
			{
				throw new NotSupportedException(Environment2.GetResourceString("ConcurrentCollection_SyncRoot_NotSupported"));
			}
		}

		public ConcurrentStack()
		{
		}

		public ConcurrentStack(IEnumerable<T> collection)
		{
			if (collection == null)
			{
				throw new ArgumentNullException("collection");
			}
			InitializeFromCollection(collection);
		}

		private void InitializeFromCollection(IEnumerable<T> collection)
		{
			Node node = null;
			foreach (T item in collection)
			{
				Node node2 = new Node(item);
				node2.m_next = node;
				node = node2;
			}
			m_head = node;
		}

		[OnSerializing]
		private void OnSerializing(StreamingContext context)
		{
			m_serializationArray = ToArray();
		}

		[OnDeserialized]
		private void OnDeserialized(StreamingContext context)
		{
			Node node = null;
			Node head = null;
			for (int i = 0; i < m_serializationArray.Length; i++)
			{
				Node node2 = new Node(m_serializationArray[i]);
				if (node == null)
				{
					head = node2;
				}
				else
				{
					node.m_next = node2;
				}
				node = node2;
			}
			m_head = head;
			m_serializationArray = null;
		}

		public void Clear()
		{
			m_head = null;
		}

		void ICollection.CopyTo(Array array, int index)
		{
			if (array == null)
			{
				throw new ArgumentNullException("array");
			}
			((ICollection)ToList()).CopyTo(array, index);
		}

		public void CopyTo(T[] array, int index)
		{
			if (array == null)
			{
				throw new ArgumentNullException("array");
			}
			ToList().CopyTo(array, index);
		}

		public void Push(T item)
		{
			Node node = new Node(item);
			node.m_next = m_head;
			if (Interlocked.CompareExchange(ref m_head, node, node.m_next) != node.m_next)
			{
				PushCore(node, node);
			}
		}

		public void PushRange(T[] items)
		{
			if (items == null)
			{
				throw new ArgumentNullException("items");
			}
			PushRange(items, 0, items.Length);
		}

		public void PushRange(T[] items, int startIndex, int count)
		{
			ValidatePushPopRangeInput(items, startIndex, count);
			if (count != 0)
			{
				Node node;
				Node node2 = (node = new Node(items[startIndex]));
				for (int i = startIndex + 1; i < startIndex + count; i++)
				{
					Node node3 = new Node(items[i]);
					node3.m_next = node2;
					node2 = node3;
				}
				node.m_next = m_head;
				if (Interlocked.CompareExchange(ref m_head, node2, node.m_next) != node.m_next)
				{
					PushCore(node2, node);
				}
			}
		}

		private void PushCore(Node head, Node tail)
		{
			SpinWait spinWait = default(SpinWait);
			do
			{
				spinWait.SpinOnce();
				tail.m_next = m_head;
			}
			while (Interlocked.CompareExchange(ref m_head, head, tail.m_next) != tail.m_next);
		}

		private void ValidatePushPopRangeInput(T[] items, int startIndex, int count)
		{
			if (items == null)
			{
				throw new ArgumentNullException("items");
			}
			if (count < 0)
			{
				throw new ArgumentOutOfRangeException("count", Environment2.GetResourceString("ConcurrentStack_PushPopRange_CountOutOfRange"));
			}
			int num = items.Length;
			if (startIndex >= num || startIndex < 0)
			{
				throw new ArgumentOutOfRangeException("startIndex", Environment2.GetResourceString("ConcurrentStack_PushPopRange_StartOutOfRange"));
			}
			if (num - count < startIndex)
			{
				throw new ArgumentException(Environment2.GetResourceString("ConcurrentStack_PushPopRange_InvalidCount"));
			}
		}

		bool IProducerConsumerCollection<T>.TryAdd(T item)
		{
			Push(item);
			return true;
		}

		public bool TryPeek(out T result)
		{
			Node head = m_head;
			if (head == null)
			{
				result = default(T);
				return false;
			}
			result = head.m_value;
			return true;
		}

		public bool TryPop(out T result)
		{
			Node head = m_head;
			if (head == null)
			{
				result = default(T);
				return false;
			}
			if (Interlocked.CompareExchange(ref m_head, head.m_next, head) == head)
			{
				result = head.m_value;
				return true;
			}
			return TryPopCore(out result);
		}

		public int TryPopRange(T[] items)
		{
			if (items == null)
			{
				throw new ArgumentNullException("items");
			}
			return TryPopRange(items, 0, items.Length);
		}

		public int TryPopRange(T[] items, int startIndex, int count)
		{
			ValidatePushPopRangeInput(items, startIndex, count);
			if (count == 0)
			{
				return 0;
			}
			Node poppedHead;
			int num = TryPopCore(count, out poppedHead);
			if (num > 0)
			{
				CopyRemovedItems(poppedHead, items, startIndex, num);
			}
			return num;
		}

		private bool TryPopCore(out T result)
		{
			if (TryPopCore(1, out var poppedHead) == 1)
			{
				result = poppedHead.m_value;
				return true;
			}
			result = default(T);
			return false;
		}

		private int TryPopCore(int count, out Node poppedHead)
		{
			SpinWait spinWait = default(SpinWait);
			int num = 1;
			Random random = new Random(Environment.TickCount & 0x7FFFFFFF);
			Node head;
			int i;
			while (true)
			{
				head = m_head;
				if (head == null)
				{
					poppedHead = null;
					return 0;
				}
				Node node = head;
				for (i = 1; i < count; i++)
				{
					if (node.m_next == null)
					{
						break;
					}
					node = node.m_next;
				}
				if (Interlocked.CompareExchange(ref m_head, node.m_next, head) == head)
				{
					break;
				}
				for (int j = 0; j < num; j++)
				{
					spinWait.SpinOnce();
				}
				num = (spinWait.NextSpinWillYield ? random.Next(1, 8) : (num * 2));
			}
			poppedHead = head;
			return i;
		}

		private void CopyRemovedItems(Node head, T[] collection, int startIndex, int nodesCount)
		{
			Node node = head;
			for (int i = startIndex; i < startIndex + nodesCount; i++)
			{
				collection[i] = node.m_value;
				node = node.m_next;
			}
		}

		bool IProducerConsumerCollection<T>.TryTake(out T item)
		{
			return TryPop(out item);
		}

		public T[] ToArray()
		{
			return ToList().ToArray();
		}

		private List<T> ToList()
		{
			List<T> list = new List<T>();
			for (Node node = m_head; node != null; node = node.m_next)
			{
				list.Add(node.m_value);
			}
			return list;
		}

		public IEnumerator<T> GetEnumerator()
		{
			return GetEnumerator(m_head);
		}

		private IEnumerator<T> GetEnumerator(Node head)
		{
			for (Node current = head; current != null; current = current.m_next)
			{
				yield return current.m_value;
			}
		}

		IEnumerator IEnumerable.GetEnumerator()
		{
			return ((IEnumerable<T>)this).GetEnumerator();
		}
	}
	internal sealed class SystemCollectionsConcurrent_ProducerConsumerCollectionDebugView<T>
	{
		private IProducerConsumerCollection<T> m_collection;

		[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
		public T[] Items => m_collection.ToArray();

		public SystemCollectionsConcurrent_ProducerConsumerCollectionDebugView(IProducerConsumerCollection<T> collection)
		{
			if (collection == null)
			{
				throw new ArgumentNullException("collection");
			}
			m_collection = collection;
		}
	}
	[HostProtection(SecurityAction.LinkDemand, Synchronization = true, ExternalThreading = true)]
	public abstract class Partitioner<TSource>
	{
		public virtual bool SupportsDynamicPartitions => false;

		public abstract IList<IEnumerator<TSource>> GetPartitions(int partitionCount);

		public virtual IEnumerable<TSource> GetDynamicPartitions()
		{
			throw new NotSupportedException(Environment2.GetResourceString("Partitioner_DynamicPartitionsNotSupported"));
		}
	}
	[HostProtection(SecurityAction.LinkDemand, Synchronization = true, ExternalThreading = true)]
	public abstract class OrderablePartitioner<TSource> : Partitioner<TSource>
	{
		private class EnumerableDropIndices : IEnumerable<TSource>, IEnumerable, IDisposable
		{
			private readonly IEnumerable<KeyValuePair<long, TSource>> m_source;

			public EnumerableDropIndices(IEnumerable<KeyValuePair<long, TSource>> source)
			{
				m_source = source;
			}

			public IEnumerator<TSource> GetEnumerator()
			{
				return new EnumeratorDropIndices(m_source.GetEnumerator());
			}

			IEnumerator IEnumerable.GetEnumerator()
			{
				return GetEnumerator();
			}

			public void Dispose()
			{
				if (m_source is IDisposable disposable)
				{
					disposable.Dispose();
				}
			}
		}

		private class EnumeratorDropIndices : IEnumerator<TSource>, IDisposable, IEnumerator
		{
			private readonly IEnumerator<KeyValuePair<long, TSource>> m_source;

			public TSource Current => m_source.Current.Value;

			object IEnumerator.Current => Current;

			public EnumeratorDropIndices(IEnumerator<KeyValuePair<long, TSource>> source)
			{
				m_source = source;
			}

			public bool MoveNext()
			{
				return m_source.MoveNext();
			}

			public void Dispose()
			{
				m_source.Dispose();
			}

			public void Reset()
			{
				m_source.Reset();
			}
		}

		public bool KeysOrderedInEachPartition { get; private set; }

		public bool KeysOrderedAcrossPartitions { get; private set; }

		public bool KeysNormalized { get; private set; }

		protected OrderablePartitioner(bool keysOrderedInEachPartition, bool keysOrderedAcrossPartitions, bool keysNormalized)
		{
			KeysOrderedInEachPartition = keysOrderedInEachPartition;
			KeysOrderedAcrossPartitions = keysOrderedAcrossPartitions;
			KeysNormalized = keysNormalized;
		}

		public abstract IList<IEnumerator<KeyValuePair<long, TSource>>> GetOrderablePartitions(int partitionCount);

		public virtual IEnumerable<KeyValuePair<long, TSource>> GetOrderableDynamicPartitions()
		{
			throw new NotSupportedException(Environment2.GetResourceString("Partitioner_DynamicPartitionsNotSupported"));
		}

		public override IList<IEnumerator<TSource>> GetPartitions(int partitionCount)
		{
			IList<IEnumerator<KeyValuePair<long, TSource>>> orderablePartitions = GetOrderablePartitions(partitionCount);
			if (orderablePartitions.Count != partitionCount)
			{
				throw new InvalidOperationException("OrderablePartitioner_GetPartitions_WrongNumberOfPartitions");
			}
			IEnumerator<TSource>[] array = new IEnumerator<TSource>[partitionCount];
			for (int i = 0; i < partitionCount; i++)
			{
				array[i] = new EnumeratorDropIndices(orderablePartitions[i]);
			}
			return array;
		}

		public override IEnumerable<TSource> GetDynamicPartitions()
		{
			IEnumerable<KeyValuePair<long, TSource>> orderableDynamicPartitions = GetOrderableDynamicPartitions();
			return new EnumerableDropIndices(orderableDynamicPartitions);
		}
	}
	[HostProtection(SecurityAction.LinkDemand, Synchronization = true, ExternalThreading = true)]
	public static class Partitioner
	{
		private abstract class DynamicPartitionEnumerator_Abstract<TSource, TSourceReader> : IEnumerator<KeyValuePair<long, TSource>>, IDisposable, IEnumerator
		{
			private const int CHUNK_DOUBLING_RATE = 3;

			protected readonly TSourceReader m_sharedReader;

			protected static int s_defaultMaxChunkSize = GetDefaultChunkSize<TSource>();

			protected Shared<int> m_currentChunkSize;

			protected Shared<int> m_localOffset;

			private int m_doublingCountdown;

			protected readonly int m_maxChunkSize;

			protected readonly Shared<long> m_sharedIndex;

			protected abstract bool HasNoElementsLeft { get; set; }

			public abstract KeyValuePair<long, TSource> Current { get; }

			object IEnumerator.Current => Current;

			protected DynamicPartitionEnumerator_Abstract(TSourceReader sharedReader, Shared<long> sharedIndex)
				: this(sharedReader, sharedIndex, -1)
			{
			}

			protected DynamicPartitionEnumerator_Abstract(TSourceReader sharedReader, Shared<long> sharedIndex, int maxChunkSize)
			{
				m_sharedReader = sharedReader;
				m_sharedIndex = sharedIndex;
				if (maxChunkSize == -1)
				{
					m_maxChunkSize = s_defaultMaxChunkSize;
				}
				else
				{
					m_maxChunkSize = maxChunkSize;
				}
			}

			protected abstract bool GrabNextChunk(int requestedChunkSize);

			public abstract void Dispose();

			public void Reset()
			{
				throw new NotSupportedException();
			}

			public bool MoveNext()
			{
				if (m_localOffset == null)
				{
					m_localOffset = new Shared<int>(-1);
					m_currentChunkSize = new Shared<int>(0);
					m_doublingCountdown = 3;
				}
				if (m_localOffset.Value < m_currentChunkSize.Value - 1)
				{
					m_localOffset.Value++;
					return true;
				}
				int requestedChunkSize;
				if (m_currentChunkSize.Value == 0)
				{
					requestedChunkSize = 1;
				}
				else if (m_doublingCountdown > 0)
				{
					requestedChunkSize = m_currentChunkSize.Value;
				}
				else
				{
					requestedChunkSize = Math.Min(m_currentChunkSize.Value * 2, m_maxChunkSize);
					m_doublingCountdown = 3;
				}
				m_doublingCountdown--;
				if (GrabNextChunk(requestedChunkSize))
				{
					m_localOffset.Value = 0;
					return true;
				}
				return false;
			}
		}

		private class DynamicPartitionerForIEnumerable<TSource> : OrderablePartitioner<TSource>
		{
			private class InternalPartitionEnumerable : IEnumerable<KeyValuePair<long, TSource>>, IEnumerable, IDisposable
			{
				private readonly IEnumerator<TSource> m_sharedReader;

				private Shared<long> m_sharedIndex;

				private Shared<bool> m_hasNoElementsLeft;

				private object m_sharedLock;

				private bool m_disposed;

				private Shared<int> m_activePartitionCount;

				private readonly int m_maxChunkSize;

				internal InternalPartitionEnumerable(IEnumerator<TSource> sharedReader, int maxChunkSize)
				{
					m_sharedReader = sharedReader;
					m_sharedIndex = new Shared<long>(-1L);
					m_hasNoElementsLeft = new Shared<bool>(value: false);
					m_sharedLock = new object();
					m_activePartitionCount = new Shared<int>(0);
					m_maxChunkSize = maxChunkSize;
				}

				public IEnumerator<KeyValuePair<long, TSource>> GetEnumerator()
				{
					if (m_disposed)
					{
						throw new ObjectDisposedException(Environment2.GetResourceString("PartitionerStatic_CanNotCallGetEnumeratorAfterSourceHasBeenDisposed"));
					}
					return new InternalPartitionEnumerator(m_sharedReader, m_sharedIndex, m_hasNoElementsLeft, m_sharedLock, m_activePartitionCount, this, m_maxChunkSize);
				}

				IEnumerator IEnumerable.GetEnumerator()
				{
					return GetEnumerator();
				}

				public void Dispose()
				{
					if (!m_disposed)
					{
						m_disposed = true;
						m_sharedReader.Dispose();
					}
				}
			}

			private class InternalPartitionEnumerator : DynamicPartitionEnumerator_Abstract<TSource, IEnumerator<TSource>>
			{
				private KeyValuePair<long, TSource>[] m_localList;

				private readonly Shared<bool> m_hasNoElementsLeft;

				private readonly object m_sharedLock;

				private readonly Shared<int> m_activePartitionCount;

				private InternalPartitionEnumerable m_enumerable;

				protected override bool HasNoElementsLeft
				{
					get
					{
						return m_hasNoElementsLeft.Value;
					}
					set
					{
						m_hasNoElementsLeft.Value = true;
					}
				}

				public override KeyValuePair<long, TSource> Current
				{
					get
					{
						if (m_currentChunkSize == null)
						{
							throw new InvalidOperationException(Environment2.GetResourceString("PartitionerStatic_CurrentCalledBeforeMoveNext"));
						}
						return m_localList[m_localOffset.Value];
					}
				}

				internal InternalPartitionEnumerator(IEnumerator<TSource> sharedReader, Shared<long> sharedIndex, Shared<bool> hasNoElementsLeft, object sharedLock, Shared<int> activePartitionCount, InternalPartitionEnumerable enumerable, int maxChunkSize)
					: base(sharedReader, sharedIndex, maxChunkSize)
				{
					m_hasNoElementsLeft = hasNoElementsLeft;
					m_sharedLock = sharedLock;
					m_enumerable = enumerable;
					m_activePartitionCount = activePartitionCount;
					Interlocked.Increment(ref m_activePartitionCount.Value);
				}

				protected override bool GrabNextChunk(int requestedChunkSize)
				{
					if (HasNoElementsLeft)
					{
						return false;
					}
					lock (m_sharedLock)
					{
						if (HasNoElementsLeft)
						{
							return false;
						}
						try
						{
							int i;
							for (i = 0; i < requestedChunkSize; i++)
							{
								if (m_sharedReader.MoveNext())
								{
									if (m_localList == null)
									{
										m_localList = new KeyValuePair<long, TSource>[m_maxChunkSize];
									}
									m_sharedIndex.Value = checked(m_sharedIndex.Value + 1);
									ref KeyValuePair<long, TSource> reference = ref m_localList[i];
									reference = new KeyValuePair<long, TSource>(m_sharedIndex.Value, m_sharedReader.Current);
									continue;
								}
								HasNoElementsLeft = true;
								break;
							}
							if (i > 0)
							{
								m_currentChunkSize.Value = i;
								return true;
							}
							return false;
						}
						catch
						{
							HasNoElementsLeft = true;
							throw;
						}
					}
				}

				public override void Dispose()
				{
					if (Interlocked.Decrement(ref m_activePartitionCount.Value) == 0)
					{
						m_enumerable.Dispose();
					}
				}
			}

			private IEnumerable<TSource> m_source;

			private int m_maxChunkSize;

			public override bool SupportsDynamicPartitions => true;

			internal DynamicPartitionerForIEnumerable(IEnumerable<TSource> source, int maxChunkSize)
				: base(keysOrderedInEachPartition: true, keysOrderedAcrossPartitions: false, keysNormalized: true)
			{
				m_source = source;
				m_maxChunkSize = maxChunkSize;
			}

			public override IList<IEnumerator<KeyValuePair<long, TSource>>> GetOrderablePartitions(int partitionCount)
			{
				if (partitionCount <= 0)
				{
					throw new ArgumentOutOfRangeException("partitionCount");
				}
				IEnumerator<KeyValuePair<long, TSource>>[] array = new IEnumerator<KeyValuePair<long, TSource>>[partitionCount];
				IEnumerable<KeyValuePair<long, TSource>> enumerable = new InternalPartitionEnumerable(m_source.GetEnumerator(), m_maxChunkSize);
				for (int i = 0; i < partitionCount; i++)
				{
					array[i] = enumerable.GetEnumerator();
				}
				return array;
			}

			public override IEnumerable<KeyValuePair<long, TSource>> GetOrderableDynamicPartitions()
			{
				return new InternalPartitionEnumerable(m_source.GetEnumerator(), m_maxChunkSize);
			}
		}

		private abstract class DynamicPartitionerForIndexRange_Abstract<TSource, TCollection> : OrderablePartitioner<TSource>
		{
			private TCollection m_data;

			public override bool SupportsDynamicPartitions => true;

			protected DynamicPartitionerForIndexRange_Abstract(TCollection data)
				: base(keysOrderedInEachPartition: true, keysOrderedAcrossPartitions: false, keysNormalized: true)
			{
				m_data = data;
			}

			protected abstract IEnumerable<KeyValuePair<long, TSource>> GetOrderableDynamicPartitions_Factory(TCollection data);

			public override IList<IEnumerator<KeyValuePair<long, TSource>>> GetOrderablePartitions(int partitionCount)
			{
				if (partitionCount <= 0)
				{
					throw new ArgumentOutOfRangeException("partitionCount");
				}
				IEnumerator<KeyValuePair<long, TSource>>[] array = new IEnumerator<KeyValuePair<long, TSource>>[partitionCount];
				IEnumerable<KeyValuePair<long, TSource>> orderableDynamicPartitions_Factory = GetOrderableDynamicPartitions_Factory(m_data);
				for (int i = 0; i < partitionCount; i++)
				{
					array[i] = orderableDynamicPartitions_Factory.GetEnumerator();
				}
				return array;
			}

			public override IEnumerable<KeyValuePair<long, TSource>> GetOrderableDynamicPartitions()
			{
				return GetOrderableDynamicPartitions_Factory(m_data);
			}
		}

		private abstract class DynamicPartitionEnumeratorForIndexRange_Abstract<TSource, TSourceReader> : DynamicPartitionEnumerator_Abstract<TSource, TSourceReader>
		{
			protected int m_startIndex;

			protected abstract int SourceCount { get; }

			protected override bool HasNoElementsLeft
			{
				get
				{
					return m_sharedIndex.Value >= SourceCount - 1;
				}
				set
				{
				}
			}

			protected DynamicPartitionEnumeratorForIndexRange_Abstract(TSourceReader sharedReader, Shared<long> sharedIndex)
				: base(sharedReader, sharedIndex)
			{
			}

			protected override bool GrabNextChunk(int requestedChunkSize)
			{
				while (!HasNoElementsLeft)
				{
					long value = m_sharedIndex.Value;
					if (HasNoElementsLeft)
					{
						return false;
					}
					long num = Math.Min(SourceCount - 1, value + requestedChunkSize);
					if (Interlocked.CompareExchange(ref m_sharedIndex.Value, num, value) == value)
					{
						m_currentChunkSize.Value = (int)(num - value);
						m_localOffset.Value = -1;
						m_startIndex = (int)(value + 1);
						return true;
					}
				}
				return false;
			}

			public override void Dispose()
			{
			}
		}

		private class DynamicPartitionerForIList<TSource> : DynamicPartitionerForIndexRange_Abstract<TSource, IList<TSource>>
		{
			private class InternalPartitionEnumerable : IEnumerable<KeyValuePair<long, TSource>>, IEnumerable
			{
				private readonly IList<TSource> m_sharedReader;

				private Shared<long> m_sharedIndex;

				internal InternalPartitionEnumerable(IList<TSource> sharedReader)
				{
					m_sharedReader = sharedReader;
					m_sharedIndex = new Shared<long>(-1L);
				}

				public IEnumerator<KeyValuePair<long, TSource>> GetEnumerator()
				{
					return new InternalPartitionEnumerator(m_sharedReader, m_sharedIndex);
				}

				IEnumerator IEnumerable.GetEnumerator()
				{
					return GetEnumerator();
				}
			}

			private class InternalPartitionEnumerator : DynamicPartitionEnumeratorForIndexRange_Abstract<TSource, IList<TSource>>
			{
				protected override int SourceCount => m_sharedReader.Count;

				public override KeyValuePair<long, TSource> Current
				{
					get
					{
						if (m_currentChunkSize == null)
						{
							throw new InvalidOperationException(Environment2.GetResourceString("PartitionerStatic_CurrentCalledBeforeMoveNext"));
						}
						return new KeyValuePair<long, TSource>(m_startIndex + m_localOffset.Value, m_sharedReader[m_startIndex + m_localOffset.Value]);
					}
				}

				internal InternalPartitionEnumerator(IList<TSource> sharedReader, Shared<long> sharedIndex)
					: base(sharedReader, sharedIndex)
				{
				}
			}

			internal DynamicPartitionerForIList(IList<TSource> source)
				: base(source)
			{
			}

			protected override IEnumerable<KeyValuePair<long, TSource>> GetOrderableDynamicPartitions_Factory(IList<TSource> m_data)
			{
				return new InternalPartitionEnumerable(m_data);
			}
		}

		private class DynamicPartitionerForArray<TSource> : DynamicPartitionerForIndexRange_Abstract<TSource, TSource[]>
		{
			private class InternalPartitionEnumerable : IEnumerable<KeyValuePair<long, TSource>>, IEnumerable
			{
				private readonly TSource[] m_sharedReader;

				private Shared<long> m_sharedIndex;

				internal InternalPartitionEnumerable(TSource[] sharedReader)
				{
					m_sharedReader = sharedReader;
					m_sharedIndex = new Shared<long>(-1L);
				}

				IEnumerator IEnumerable.GetEnumerator()
				{
					return GetEnumerator();
				}

				public IEnumerator<KeyValuePair<long, TSource>> GetEnumerator()
				{
					return new InternalPartitionEnumerator(m_sharedReader, m_sharedIndex);
				}
			}

			private class InternalPartitionEnumerator : DynamicPartitionEnumeratorForIndexRange_Abstract<TSource, TSource[]>
			{
				protected override int SourceCount => m_sharedReader.Length;

				public override KeyValuePair<long, TSource> Current
				{
					get
					{
						if (m_currentChunkSize == null)
						{
							throw new InvalidOperationException(Environment2.GetResourceString("PartitionerStatic_CurrentCalledBeforeMoveNext"));
						}
						return new KeyValuePair<long, TSource>(m_startIndex + m_localOffset.Value, m_sharedReader[m_startIndex + m_localOffset.Value]);
					}
				}

				internal InternalPartitionEnumerator(TSource[] sharedReader, Shared<long> sharedIndex)
					: base(sharedReader, sharedIndex)
				{
				}
			}

			internal DynamicPartitionerForArray(TSource[] source)
				: base(source)
			{
			}

			protected override IEnumerable<KeyValuePair<long, TSource>> GetOrderableDynamicPartitions_Factory(TSource[] m_data)
			{
				return new InternalPartitionEnumerable(m_data);
			}
		}

		private abstract class StaticIndexRangePartitioner<TSource, TCollection> : OrderablePartitioner<TSource>
		{
			protected abstract int SourceCount { get; }

			protected StaticIndexRangePartitioner()
				: base(keysOrderedInEachPartition: true, keysOrderedAcrossPartitions: true, keysNormalized: true)
			{
			}

			protected abstract IEnumerator<KeyValuePair<long, TSource>> CreatePartition(int startIndex, int endIndex);

			public override IList<IEnumerator<KeyValuePair<long, TSource>>> GetOrderablePartitions(int partitionCount)
			{
				if (partitionCount <= 0)
				{
					throw new ArgumentOutOfRangeException("partitionCount");
				}
				int result;
				int num = Math.DivRem(SourceCount, partitionCount, out result);
				IEnumerator<KeyValuePair<long, TSource>>[] array = new IEnumerator<KeyValuePair<long, TSource>>[partitionCount];
				int num2 = -1;
				for (int i = 0; i < partitionCount; i++)
				{
					int num3 = num2 + 1;
					num2 = ((i >= result) ? (num3 + num - 1) : (num3 + num));
					array[i] = CreatePartition(num3, num2);
				}
				return array;
			}
		}

		private abstract class StaticIndexRangePartition<TSource> : IEnumerator<KeyValuePair<long, TSource>>, IDisposable, IEnumerator
		{
			protected readonly int m_startIndex;

			protected readonly int m_endIndex;

			protected volatile int m_offset;

			public abstract KeyValuePair<long, TSource> Current { get; }

			object IEnumerator.Current => Current;

			protected StaticIndexRangePartition(int startIndex, int endIndex)
			{
				m_startIndex = startIndex;
				m_endIndex = endIndex;
				m_offset = startIndex - 1;
			}

			public void Dispose()
			{
			}

			public void Reset()
			{
				throw new NotSupportedException();
			}

			public bool MoveNext()
			{
				if (m_offset < m_endIndex)
				{
					m_offset++;
					return true;
				}
				m_offset = m_endIndex + 1;
				return false;
			}
		}

		private class StaticIndexRangePartitionerForIList<TSource> : StaticIndexRangePartitioner<TSource, IList<TSource>>
		{
			private IList<TSource> m_list;

			protected override int SourceCount => m_list.Count;

			internal StaticIndexRangePartitionerForIList(IList<TSource> list)
			{
				m_list = list;
			}

			protected override IEnumerator<KeyValuePair<long, TSource>> CreatePartition(int startIndex, int endIndex)
			{
				return new StaticIndexRangePartitionForIList<TSource>(m_list, startIndex, endIndex);
			}
		}

		private class StaticIndexRangePartitionForIList<TSource> : StaticIndexRangePartition<TSource>
		{
			private volatile IList<TSource> m_list;

			public override KeyValuePair<long, TSource> Current
			{
				get
				{
					if (m_offset < m_startIndex)
					{
						throw new InvalidOperationException(Environment2.GetResourceString("PartitionerStatic_CurrentCalledBeforeMoveNext"));
					}
					return new KeyValuePair<long, TSource>(m_offset, m_list[m_offset]);
				}
			}

			internal StaticIndexRangePartitionForIList(IList<TSource> list, int startIndex, int endIndex)
				: base(startIndex, endIndex)
			{
				m_list = list;
			}
		}

		private class StaticIndexRangePartitionerForArray<TSource> : StaticIndexRangePartitioner<TSource, TSource[]>
		{
			private TSource[] m_array;

			protected override int SourceCount => m_array.Length;

			internal StaticIndexRangePartitionerForArray(TSource[] array)
			{
				m_array = array;
			}

			protected override IEnumerator<KeyValuePair<long, TSource>> CreatePartition(int startIndex, int endIndex)
			{
				return new StaticIndexRangePartitionForArray<TSource>(m_array, startIndex, endIndex);
			}
		}

		private class StaticIndexRangePartitionForArray<TSource> : StaticIndexRangePartition<TSource>
		{
			private volatile TSource[] m_array;

			public override KeyValuePair<long, TSource> Current
			{
				get
				{
					if (m_offset < m_startIndex)
					{
						throw new InvalidOperationException(Environment2.GetResourceString("PartitionerStatic_CurrentCalledBeforeMoveNext"));
					}
					return new KeyValuePair<long, TSource>(m_offset, m_array[m_offset]);
				}
			}

			internal StaticIndexRangePartitionForArray(TSource[] array, int startIndex, int endIndex)
				: base(startIndex, endIndex)
			{
				m_array = array;
			}
		}

		private class Shared<TSource>
		{
			internal TSource Value;

			internal Shared(TSource value)
			{
				Value = value;
			}
		}

		private const int DEFAULT_BYTES_PER_CHUNK = 512;

		public static OrderablePartitioner<TSource> Create<TSource>(IList<TSource> list, bool loadBalance)
		{
			if (list == null)
			{
				throw new ArgumentNullException("list");
			}
			if (loadBalance)
			{
				return new DynamicPartitionerForIList<TSource>(list);
			}
			return new StaticIndexRangePartitionerForIList<TSource>(list);
		}

		public static OrderablePartitioner<TSource> Create<TSource>(TSource[] array, bool loadBalance)
		{
			if (array == null)
			{
				throw new ArgumentNullException("array");
			}
			if (loadBalance)
			{
				return new DynamicPartitionerForArray<TSource>(array);
			}
			return new StaticIndexRangePartitionerForArray<TSource>(array);
		}

		public static OrderablePartitioner<TSource> Create<TSource>(IEnumerable<TSource> source)
		{
			return Create(source, -1);
		}

		internal static OrderablePartitioner<TSource> Create<TSource>(IEnumerable<TSource> source, int maxChunkSize)
		{
			if (source == null)
			{
				throw new ArgumentNullException("source");
			}
			return new DynamicPartitionerForIEnumerable<TSource>(source, maxChunkSize);
		}

		private static int GetDefaultChunkSize<TSource>()
		{
			if (typeof(TSource).IsValueType)
			{
				if (typeof(TSource).StructLayoutAttribute.Value == LayoutKind.Explicit)
				{
					return Math.Max(1, 512 / Marshal.SizeOf(typeof(TSource)));
				}
				return 128;
			}
			return 512 / IntPtr.Size;
		}
	}
}
namespace System
{
	[Serializable]
	[DebuggerDisplay("Count = {InnerExceptions.Count}")]
	public class AggregateException : Exception
	{
		private ReadOnlyCollection<Exception> m_innerExceptions;

		public ReadOnlyCollection<Exception> InnerExceptions => m_innerExceptions;

		public AggregateException()
			: base(Environment2.GetResourceString("AggregateException_ctor_DefaultMessage"))
		{
			m_innerExceptions = new ReadOnlyCollection<Exception>(new Exception[0]);
		}

		public AggregateException(string message)
			: base(message)
		{
			m_innerExceptions = new ReadOnlyCollection<Exception>(new Exception[0]);
		}

		public AggregateException(string message, Exception innerException)
			: base(message, innerException)
		{
			if (innerException == null)
			{
				throw new ArgumentNullException("innerException");
			}
			m_innerExceptions = new ReadOnlyCollection<Exception>(new Exception[1] { innerException });
		}

		public AggregateException(IEnumerable<Exception> innerExceptions)
			: this(Environment2.GetResourceString("AggregateException_ctor_DefaultMessage"), innerExceptions)
		{
		}

		public AggregateException(params Exception[] innerExceptions)
			: this(Environment2.GetResourceString("AggregateException_ctor_DefaultMessage"), innerExceptions)
		{
		}

		public AggregateException(string message, IEnumerable<Exception> innerExceptions)
			: this(message, (innerExceptions == null) ? null : new List<Exception>(innerExceptions))
		{
		}

		public AggregateException(string message, params Exception[] innerExceptions)
			: this(message, (IList<Exception>)innerExceptions)
		{
		}

		private AggregateException(string message, IList<Exception> innerExceptions)
			: base(message, (innerExceptions != null && innerExceptions.Count > 0) ? innerExceptions[0] : null)
		{
			if (innerExceptions == null)
			{
				throw new ArgumentNullException("innerExceptions");
			}
			Exception[] array = new Exception[innerExceptions.Count];
			for (int i = 0; i < array.Length; i++)
			{
				array[i] = innerExceptions[i];
				if (array[i] == null)
				{
					throw new ArgumentException(Environment2.GetResourceString("AggregateException_ctor_InnerExceptionNull"));
				}
			}
			m_innerExceptions = new ReadOnlyCollection<Exception>(array);
		}

		[SecurityCritical]
		protected AggregateException(SerializationInfo info, StreamingContext context)
			: base(info, context)
		{
			if (info == null)
			{
				throw new ArgumentNullException("info");
			}
			if (!(info.GetValue("InnerExceptions", typeof(Exception[])) is Exception[] list))
			{
				throw new SerializationException(Environment2.GetResourceString("AggregateException_DeserializationFailure"));
			}
			m_innerExceptions = new ReadOnlyCollection<Exception>(list);
		}

		[SecurityCritical]
		public override void GetObjectData(SerializationInfo info, StreamingContext context)
		{
			if (info == null)
			{
				throw new ArgumentNullException("info");
			}
			base.GetObjectData(info, context);
			Exception[] array = new Exception[m_innerExceptions.Count];
			m_innerExceptions.CopyTo(array, 0);
			info.AddValue("InnerExceptions", array, typeof(Exception[]));
		}

		public override Exception GetBaseException()
		{
			Exception ex = this;
			AggregateException ex2 = this;
			while (ex2 != null && ex2.InnerExceptions.Count == 1)
			{
				ex = ex.InnerException;
				ex2 = ex as AggregateException;
			}
			return ex;
		}

		public void Handle(Func<Exception, bool> predicate)
		{
			if (predicate == null)
			{
				throw new ArgumentNullException("predicate");
			}
			List<Exception> list = null;
			for (int i = 0; i < m_innerExceptions.Count; i++)
			{
				if (!predicate(m_innerExceptions[i]))
				{
					if (list == null)
					{
						list = new List<Exception>();
					}
					list.Add(m_innerExceptions[i]);
				}
			}
			if (list != null)
			{
				throw new AggregateException(Message, list);
			}
		}

		public AggregateException Flatten()
		{
			List<Exception> list = new List<Exception>();
			List<AggregateException> list2 = new List<AggregateException>();
			list2.Add(this);
			int num = 0;
			while (list2.Count > num)
			{
				IList<Exception> innerExceptions = list2[num++].InnerExceptions;
				for (int i = 0; i < innerExceptions.Count; i++)
				{
					Exception ex = innerExceptions[i];
					if (ex != null)
					{
						if (ex is AggregateException item)
						{
							list2.Add(item);
						}
						else
						{
							list.Add(ex);
						}
					}
				}
			}
			return new AggregateException(Message, list);
		}

		public override string ToString()
		{
			string text = base.ToString();
			for (int i = 0; i < m_innerExceptions.Count; i++)
			{
				text = string.Format(CultureInfo.InvariantCulture, Environment2.GetResourceString("AggregateException_ToString"), text, Environment.NewLine, i, m_innerExceptions[i].ToString(), "<---", Environment.NewLine);
			}
			return text;
		}
	}
	public delegate TResult Func_<T1, T2, T3, T4, T5, TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5);
}
namespace System.Threading
{
	[ComVisible(false)]
	[DebuggerDisplay("IsCancellationRequested = {IsCancellationRequested}")]
	[HostProtection(SecurityAction.LinkDemand, Synchronization = true, ExternalThreading = true)]
	public struct CancellationToken
	{
		private CancellationTokenSource m_source;

		private static Action<object> s_ActionToActionObjShunt = ActionToActionObjShunt;

		public static CancellationToken None => default(CancellationToken);

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

		public bool CanBeCanceled
		{
			get
			{
				if (m_source != null)
				{
					return m_source.CanBeCanceled;
				}
				return false;
			}
		}

		public WaitHandle WaitHandle
		{
			get
			{
				if (m_source == null)
				{
					InitializeDefaultSource();
				}
				return m_source.WaitHandle;
			}
		}

		internal CancellationToken(CancellationTokenSource source)
		{
			m_source = source;
		}

		public CancellationToken(bool canceled)
		{
			this = default(CancellationToken);
			if (canceled)
			{
				m_source = CancellationTokenSource.InternalGetStaticSource(canceled);
			}
		}

		private static void ActionToActionObjShunt(object obj)
		{
			Action action = obj as Action;
			action();
		}

		public CancellationTokenRegistration Register(Action callback)
		{
			if (callback == null)
			{
				throw new ArgumentNullException("callback");
			}
			return Register(s_ActionToActionObjShunt, callback, useSynchronizationContext: false, useExecutionContext: true);
		}

		public CancellationTokenRegistration Register(Action callback, bool useSynchronizationContext)
		{
			if (callback == null)
			{
				throw new ArgumentNullException("callback");
			}
			return Register(s_ActionToActionObjShunt, callback, useSynchronizationContext, useExecutionContext: true);
		}

		public CancellationTokenRegistration Register(Action<object> callback, object state)
		{
			if (callback == null)
			{
				throw new ArgumentNullException("callback");
			}
			return Register(callback, state, useSynchronizationContext: false, useExecutionContext: true);
		}

		public CancellationTokenRegistration Register(Action<object> callback, object state, bool useSynchronizationContext)
		{
			return Register(callback, state, useSynchronizationContext, useExecutionContext: true);
		}

		internal CancellationTokenRegistration InternalRegisterWithoutEC(Action<object> callback, object state)
		{
			return Register(callback, state, useSynchronizationContext: false, useExecutionContext: false);
		}

		private CancellationTokenRegistration Register(Action<object> callback, object state, bool useSynchronizationContext, bool useExecutionContext)
		{
			if (callback == null)
			{
				throw new ArgumentNullException("callback");
			}
			if (!CanBeCanceled)
			{
				return default(CancellationTokenRegistration);
			}
			SynchronizationContext targetSyncContext = null;
			if (!IsCancellationRequested && useSynchronizationContext)
			{
				targetSyncContext = SynchronizationContext.Current;
			}
			ExecutionContext executionContext = null;
			if (!IsCancellationRequested && useExecutionContext)
			{
				executionContext = ExecutionContext.Capture();
			}
			return m_source.InternalRegister(callback, state, targetSyncContext, executionContext);
		}

		public bool Equals(CancellationToken other)
		{
			if (m_source == null && other.m_source == null)
			{
				return true;
			}
			if (m_source == null)
			{
				return other.m_source == CancellationTokenSource.InternalGetStaticSource(set: false);
			}
			if (other.m_source == null)
			{
				return m_source == CancellationTokenSource.InternalGetStaticSource(set: false);
			}
			return m_source == other.m_source;
		}

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

		public override int GetHashCode()
		{
			if (m_source == null)
			{
				return CancellationTokenSource.InternalGetStaticSource(set: false).GetHashCode();
			}
			return m_source.GetHashCode();
		}

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

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

		public void ThrowIfCancellationRequested()
		{
			if (IsCancellationRequested)
			{
				throw new OperationCanceledException2(Environment2.GetResourceString("OperationCanceled"), this);
			}
		}

		internal void ThrowIfSourceDisposed()
		{
			if (m_source != null && m_source.IsDisposed)
			{
				throw new ObjectDisposedException(null, Environment2.GetResourceString("CancellationToken_SourceDisposed"));
			}
		}

		private void InitializeDefaultSource()
		{
			m_source = CancellationTokenSource.InternalGetStaticSource(set: false);
		}
	}
	[HostProtection(SecurityAction.LinkDemand, Synchronization = true, ExternalThreading = true)]
	public struct CancellationTokenRegistration : IEquatable<CancellationTokenRegistration>, IDisposable
	{
		private readonly CancellationTokenSource m_tokenSource;

		private readonly CancellationCallbackInfo m_callbackInfo;

		private readonly SparselyPopulatedArrayAddInfo<CancellationCallbackInfo> m_registrationInfo;

		internal CancellationTokenRegistration(CancellationTokenSource tokenSource, CancellationCallbackInfo callbackInfo, SparselyPopulatedArrayAddInfo<CancellationCallbackInfo> registrationInfo)
		{
			m_tokenSource = tokenSource;
			m_callbackInfo = callbackInfo;
			m_registrationInfo = registrationInfo;
		}

		internal bool TryDeregister()
		{
			if (m_registrationInfo.Source == null)
			{
				return false;
			}
			CancellationCallbackInfo cancellationCallbackInfo = m_registrationInfo.Source.SafeAtomicRemove(m_registrationInfo.Index, m_callbackInfo);
			if (cancellationCallbackInfo != m_callbackInfo)
			{
				return false;
			}
			return true;
		}

		public void Dispose()
		{
			if (m_tokenSource != null)
			{
				m_tokenSource.ThrowIfDisposed();
			}
			bool flag = TryDeregister();
			if (m_tokenSource != null && m_tokenSource.IsCancellationRequested && !m_tokenSource.IsCancellationCompleted && !flag && m_tokenSource.ThreadIDExecutingCallbacks != Thread.CurrentThread.ManagedThreadId)
			{
				m_tokenSource.WaitForCallbackToComplete(m_callbackInfo);
			}
		}

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

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

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

		public bool Equals(CancellationTokenRegistration other)
		{
			if (m_tokenSource == other.m_tokenSource && m_callbackInfo == other.m_callbackInfo && m_registrationInfo.Source == other.m_registrationInfo.Source)
			{
				return m_registrationInfo.Index == other.m_registrationInfo.Index;
			}
			return false;
		}

		public override int GetHashCode()
		{
			if (m_registrationInfo.Source != null)
			{
				return m_registrationInfo.Source.GetHashCode() ^ m_registrationInfo.Index.GetHashCode();
			}
			return m_registrationInfo.Index.GetHashCode();
		}
	}
	[ComVisible(false)]
	[HostProtection(SecurityAction.LinkDemand, Synchronization = true, ExternalThreading = true)]
	public sealed class CancellationTokenSource : IDisposable
	{
		private const int CANNOT_BE_CANCELED = 0;

		private const int NOT_CANCELED = 1;

		private const int NOTIFYING = 2;

		private const int NOTIFYINGCOMPLETE = 3;

		private static readonly CancellationTokenSource _staticSource_Set = new CancellationTokenSource(set: true);

		private static readonly CancellationTokenSource _staticSource_NotCancelable = new CancellationTokenSource(set: false);

		private static readonly int s_nLists = ((PlatformHelper.ProcessorCount > 24) ? 24 : PlatformHelper.ProcessorCount);

		private volatile ManualResetEvent m_kernelEvent;

		private volatile SparselyPopulatedArray<CancellationCallbackInfo>[] m_registeredCallbacksLists;

		private volatile int m_state;

		private volatile int m_threadIDExecutingCallbacks = -1;

		private bool m_disposed;

		private List<CancellationTokenRegistration> m_linkingRegistrations;

		private static readonly Action<object> s_LinkedTokenCancelDelegate = LinkedTokenCancelDelegate;

		private volatile CancellationCallbackInfo m_executingCallback;

		public bool IsCancellationRequested => m_state >= 2;

		internal bool IsCancellationCompleted => m_state == 3;

		internal bool IsDisposed => m_disposed;

		internal int ThreadIDExecutingCallbacks
		{
			get
			{
				return m_threadIDExecutingCallbacks;
			}
			set
			{
				m_threadIDExecutingCallbacks = value;
			}
		}

		public CancellationToken Token
		{
			get
			{
				ThrowIfDisposed();
				return new CancellationToken(this);
			}
		}

		internal bool CanBeCanceled => m_state != 0;

		internal WaitHandle WaitHandle
		{
			get
			{
				ThrowIfDisposed();
				if (m_kernelEvent != null)
				{
					return m_kernelEvent;
				}
				ManualResetEvent manualResetEvent = new ManualResetEvent(initialState: false);
				if (Interlocked.CompareExchange(ref m_kernelEvent, manualResetEvent, null) != null)
				{
					((IDisposable)manualResetEvent).Dispose();
				}
				if (IsCancellationRequested)
				{
					m_kernelEvent.Set();
				}
				return m_kernelEvent;
			}
		}

		internal CancellationCallbackInfo ExecutingCallback => m_executingCallback;

		private static void LinkedTokenCancelDelegate(object source)
		{
			CancellationTokenSource cancellationTokenSource = source as CancellationTokenSource;
			cancellationTokenSource.Cancel();
		}

		public CancellationTokenSource()
		{
			m_state = 1;
		}

		private CancellationTokenSource(bool set)
		{
			m_state = (set ? 3 : 0);
		}

		public void Cancel()
		{
			Cancel(throwOnFirstException: false);
		}

		public void Cancel(bool throwOnFirstException)
		{
			ThrowIfDisposed();
			NotifyCancellation(throwOnFirstException);
		}

		public void Dispose()
		{
			if (m_disposed)
			{
				return;
			}
			if (m_linkingRegistrations != null)
			{
				foreach (CancellationTokenRegistration linkingRegistration in m_linkingRegistrations)
				{
					linkingRegistration.Dispose();
				}
				m_linkingRegistrations = null;
			}
			m_registeredCallbacksLists = null;
			if (m_kernelEvent != null)
			{
				m_kernelEvent.Close();
				m_kernelEvent = null;
			}
			m_disposed = true;
		}

		internal void ThrowIfDisposed()
		{
			if (m_disposed)
			{
				throw new ObjectDisposedException(null, Environment2.GetResourceString("CancellationTokenSource_Disposed"));
			}
		}

		internal static CancellationTokenSource InternalGetStaticSource(bool set)
		{
			if (!set)
			{
				return _staticSource_NotCancelable;
			}
			return _staticSource_Set;
		}

		internal CancellationTokenRegistration InternalRegister(Action<object> callback, object stateForCallback, SynchronizationContext targetSyncContext, ExecutionContext executionContext)
		{
			ThrowIfDisposed();
			if (!IsCancellationRequested)
			{
				int num = Thread.CurrentThread.ManagedThreadId % s_nLists;
				CancellationCallbackInfo cancellationCallbackInfo = new CancellationCallbackInfo(callback, stateForCallback, targetSyncContext, executionContext, this);
				if (m_registeredCallbacksLists == null)
				{
					SparselyPopulatedArray<CancellationCallbackInfo>[] value = new SparselyPopulatedArray<CancellationCallbackInfo>[s_nLists];
					Interlocked.CompareExchange(ref m_registeredCallbacksLists, value, null);
				}
				if (m_registeredCallbacksLists[num] == null)
				{
					SparselyPopulatedArray<CancellationCallbackInfo> value2 = new SparselyPopulatedArray<CancellationCallbackInfo>(4);
					Interlocked.CompareExchange(ref m_registeredCallbacksLists[num], value2, null);
				}
				SparselyPopulatedArray<CancellationCallbackInfo> sparselyPopulatedArray = m_registeredCallbacksLists[num];
				SparselyPopulatedArrayAddInfo<CancellationCallbackInfo> registrationInfo = sparselyPopulatedArray.Add(cancellationCallbackInfo);
				CancellationTokenRegistration result = new CancellationTokenRegistration(this, cancellationCallbackInfo, registrationInfo);
				if (!IsCancellationRequested)
				{
					return result;
				}
				if (!result.TryDeregister())
				{
					WaitForCallbackToComplete(cancellationCallbackInfo);
					return default(CancellationTokenRegistration);
				}
			}
			callback(stateForCallback);
			return default(CancellationTokenRegistration);
		}

		private void NotifyCancellation(bool throwOnFirstException)
		{
			if (!IsCancellationRequested && Interlocked.CompareExchange(ref m_state, 2, 1) == 1)
			{
				ThreadIDExecutingCallbacks = Thread.CurrentThread.ManagedThreadId;
				if (m_kernelEvent != null)
				{
					m_kernelEvent.Set();
				}
				ExecuteCallbackHandlers(throwOnFirstException);
			}
		}

		private void ExecuteCallbackHandlers(bool throwOnFirstException)
		{
			List<Exception> list = null;
			SparselyPopulatedArray<CancellationCallbackInfo>[] registeredCallbacksLists = m_registeredCallbacksLists;
			if (registeredCallbacksLists == null)
			{
				Interlocked.Exchange(ref m_state, 3);
				return;
			}
			try
			{
				foreach (SparselyPopulatedArray<CancellationCallbackInfo> sparselyPopulatedArray in registeredCallbacksLists)
				{
					if (sparselyPopulatedArray == null)
					{
						continue;
					}
					for (SparselyPopulatedArrayFragment<CancellationCallbackInfo> sparselyPopulatedArrayFragment = sparselyPopulatedArray.Tail; sparselyPopulatedArrayFragment != null; sparselyPopulatedArrayFragment = sparselyPopulatedArrayFragment.Prev)
					{
						for (int num = sparselyPopulatedArrayFragment.Length - 1; num >= 0; num--)
						{
							m_executingCallback = sparselyPopulatedArrayFragment[num];
							if (m_executingCallback != null)
							{
								CancellationCallbackCoreWorkArguments cancellationCallbackCoreWorkArguments = new CancellationCallbackCoreWorkArguments(sparselyPopulatedArrayFragment, num);
								try
								{
									if (m_executingCallback.TargetSyncContext != null)
									{
										m_executingCallback.TargetSyncContext.Send(CancellationCallbackCoreWork_OnSyncContext, cancellationCallbackCoreWorkArguments);
										ThreadIDExecutingCallbacks = Thread.CurrentThread.ManagedThreadId;
									}
									else
									{
										CancellationCallbackCoreWork_OnSyncContext(cancellationCallbackCoreWorkArguments);
									}
								}
								catch (Exception item)
								{
									if (throwOnFirstException)
									{
										throw;
									}
									if (list == null)
									{
										list = new List<Exception>();
									}
									list.Add(item);
								}
							}
						}
					}
				}
			}
			finally
			{
				m_state = 3;
				m_executingCallback = null;
				Thread.MemoryBarrier();
			}
			if (list == null)
			{
				return;
			}
			throw new AggregateException(list);
		}

		private void CancellationCallbackCoreWork_OnSyncContext(object obj)
		{
			CancellationCallbackCoreWorkArguments cancellationCallbackCoreWorkArguments = (CancellationCallbackCoreWorkArguments)obj;
			CancellationCallbackInfo cancellationCallbackInfo = cancellationCallbackCoreWorkArguments.m_currArrayFragment.SafeAtomicRemove(cancellationCallbackCoreWorkArguments.m_currArrayIndex, m_executingCallback);
			if (cancellationCallbackInfo == m_executingCallback)
			{
				if (cancellationCallbackInfo.TargetExecutionContext != null)
				{
					cancellationCallbackInfo.CancellationTokenSource.ThreadIDExecutingCallbacks = Thread.CurrentThread.ManagedThreadId;
				}
				cancellationCallbackInfo.ExecuteCallback();
			}
		}

		public static CancellationTokenSource CreateLinkedTokenSource(CancellationToken token1, CancellationToken token2)
		{
			CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
			if (token1.CanBeCanceled)
			{
				cancellationTokenSource.m_linkingRegistrations = new List<CancellationTokenRegistration>();
				cancellationTokenSource.m_linkingRegistrations.Add(token1.InternalRegisterWithoutEC(s_LinkedTokenCancelDelegate, cancellationTokenSource));
			}
			if (token2.CanBeCanceled)
			{
				if (cancellationTokenSource.m_linkingRegistrations == null)
				{
					cancellationTokenSource.m_linkingRegistrations = new List<CancellationTokenRegistration>();
				}
				cancellationTokenSource.m_linkingRegistrations.Add(token2.InternalRegisterWithoutEC(s_LinkedTokenCancelDelegate, cancellationTokenSource));
			}
			return cancellationTokenSource;
		}

		public static CancellationTokenSource CreateLinkedTokenSource(params CancellationToken[] tokens)
		{
			if (tokens == null)
			{
				throw new ArgumentNullException("tokens");
			}
			if (tokens.Length == 0)
			{
				throw new ArgumentException(Environment2.GetResourceString("CancellationToken_CreateLinkedToken_TokensIsEmpty"));
			}
			CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
			cancellationTokenSource.m_linkingRegistrations = new List<CancellationTokenRegistration>();
			for (int i = 0; i < tokens.Length; i++)
			{
				if (tokens[i].CanBeCanceled)
				{
					cancellationTokenSource.m_linkingRegistrations.Add(tokens[i].InternalRegisterWithoutEC(s_LinkedTokenCancelDelegate, cancellationTokenSource));
				}
			}
			return cancellationTokenSource;
		}

		internal void WaitForCallbackToComplete(CancellationCallbackInfo callbackInfo)
		{
			SpinWait spinWait = default(SpinWait);
			while (ExecutingCallback == callbackInfo)
			{
				spinWait.SpinOnce();
			}
		}
	}
	internal struct CancellationCallbackCoreWorkArguments
	{
		internal SparselyPopulatedArrayFragment<CancellationCallbackInfo> m_currArrayFragment;

		internal int m_currArrayIndex;

		public CancellationCallbackCoreWorkArguments(SparselyPopulatedArrayFragment<CancellationCallbackInfo> currArrayFragment, int currArrayIndex)
		{
			m_currArrayFragment = currArrayFragment;
			m_currArrayIndex = currArrayIndex;
		}
	}
	internal class CancellationCallbackInfo
	{
		internal readonly Action<object> Callback;

		internal readonly object StateForCallback;

		internal readonly SynchronizationContext TargetSyncContext;

		internal readonly ExecutionContext TargetExecutionContext;

		internal readonly CancellationTokenSource CancellationTokenSource;

		internal CancellationCallbackInfo(Action<object> callback, object stateForCallback, SynchronizationContext targetSyncContext, ExecutionContext targetExecutionContext, CancellationTokenSource cancellationTokenSource)
		{
			Callback = callback;
			StateForCallback = stateForCallback;
			TargetSyncContext = targetSyncContext;
			TargetExecutionContext = targetExecutionContext;
			CancellationTokenSource = cancellationTokenSource;
		}

		[SecuritySafeCritical]
		internal void ExecuteCallback()
		{
			if (TargetExecutionContext != null)
			{
				ExecutionContext.Run(TargetExecutionContext, ExecutionContextCallback, this);
			}
			else
			{
				ExecutionContextCallback(this);
			}
		}

		private static void ExecutionContextCallback(object obj)
		{
			CancellationCallbackInfo cancellationCallbackInfo = obj as CancellationCallbackInfo;
			cancellationCallbackInfo.Callback(cancellationCallbackInfo.StateForCallback);
		}
	}
	internal class SparselyPopulatedArray<T> where T : class
	{
		private readonly SparselyPopulatedArrayFragment<T> m_head;

		private volatile SparselyPopulatedArrayFragment<T> m_tail;

		internal SparselyPopulatedArrayFragment<T> Head => m_head;

		internal SparselyPopulatedArrayFragment<T> Tail => m_tail;

		internal SparselyPopulatedArray(int initialSize)
		{
			m_head = (m_tail = new SparselyPopulatedArrayFragment<T>(initialSize));
		}

		internal SparselyPopulatedArrayAddInfo<T> Add(T element)
		{
			while (true)
			{
				SparselyPopulatedArrayFragment<T> sparselyPopulatedArrayFragment = m_tail;
				while (sparselyPopulatedArrayFragment.m_next != null)
				{
					sparselyPopulatedArrayFragment = (m_tail = sparselyPopulatedArrayFragment.m_next);
				}
				for (SparselyPopulatedArrayFragment<T> sparselyPopulatedArrayFragment2 = sparselyPopulatedArrayFragment; sparselyPopulatedArrayFragment2 != null; sparselyPopulatedArrayFragment2 = sparselyPopulatedArrayFragment2.m_prev)
				{
					if (sparselyPopulatedArrayFragment2.m_freeCount < 1)
					{
						sparselyPopulatedArrayFragment2.m_freeCount--;
					}
					if (sparselyPopulatedArrayFragment2.m_freeCount > 0 || sparselyPopulatedArrayFragment2.m_freeCount < -10)
					{
						int length = sparselyPopulatedArrayFragment2.Length;
						int num = (length - sparselyPopulatedArrayFragment2.m_freeCount) % length;
						if (num < 0)
						{
							num = 0;
							sparselyPopulatedArrayFragment2.m_freeCount--;
						}
						for (int i = 0; i < length; i++)
						{
							int num2 = (num + i) % length;
							if (sparselyPopulatedArrayFragment2.m_elements[num2] == null && Interlocked.CompareExchange(ref sparselyPopulatedArrayFragment2.m_elements[num2], element, null) == null)
							{
								int num3 = sparselyPopulatedArrayFragment2.m_freeCount - 1;
								sparselyPopulatedArrayFragment2.m_freeCount = ((num3 > 0) ? num3 : 0);
								return new SparselyPopulatedArrayAddInfo<T>(sparselyPopulatedArrayFragment2, num2);
							}
						}
					}
				}
				SparselyPopulatedArrayFragment<T> sparselyPopulatedArrayFragment3 = new SparselyPopulatedArrayFragment<T>((sparselyPopulatedArrayFragment.m_elements.Length == 4096) ? 4096 : (sparselyPopulatedArrayFragment.m_elements.Length * 2), sparselyPopulatedArrayFragment);
				if (Interlocked.CompareExchange(ref sparselyPopulatedArrayFragment.m_next, sparselyPopulatedArrayFragment3, null) == null)
				{
					m_tail = sparselyPopulatedArrayFragment3;
				}
			}
		}
	}
	internal struct SparselyPopulatedArrayAddInfo<T> where T : class
	{
		private SparselyPopulatedArrayFragment<T> m_source;

		private int m_index;

		internal SparselyPopulatedArrayFragment<T> Source => m_source;

		internal int Index => m_index;

		internal SparselyPopulatedArrayAddInfo(SparselyPopulatedArrayFragment<T> source, int index)
		{
			m_source = source;
			m_index = index;
		}
	}
	internal class SparselyPopulatedArrayFragment<T> where T : class
	{
		internal readonly T[] m_elements;

		internal volatile int m_freeCount;

		internal volatile SparselyPopulatedArrayFragment<T> m_next;

		internal volatile SparselyPopulatedArrayFragment<T> m_prev;

		internal T this[int index] => m_elements[index];

		internal int Length => m_elements.Length;

		internal SparselyPopulatedArrayFragment<T> Next => m_next;

		internal SparselyPopulatedArrayFragment<T> Prev => m_prev;

		internal SparselyPopulatedArrayFragment(int size)
			: this(size, (SparselyPopulatedArrayFragment<T>)null)
		{
		}

		internal SparselyPopulatedArrayFragment(int size, SparselyPopulatedArrayFragment<T> prev)
		{
			m_elements = new T[size];
			m_freeCount = size;
			m_prev = prev;
		}

		internal T SafeAtomicRemove(int index, T expectedElement)
		{
			T val = Interlocked.CompareExchange(ref m_elements[index], null, expectedElement);
			if (val != null)
			{
				m_freeCount++;
			}
			return val;
		}
	}
	[DebuggerDisplay("Initial Count={InitialCount}, Current Count={CurrentCount}")]
	[ComVisible(false)]
	[HostProtection(SecurityAction.LinkDemand, Synchronization = true, ExternalThreading = true)]
	public class CountdownEvent : IDisposable
	{
		private int m_initialCount;

		private volatile int m_currentCount;

		private ManualResetEventSlim m_event;

		private volatile bool m_disposed;

		public int CurrentCount => m_currentCount;

		public int InitialCount => m_initialCount;

		public bool IsSet => m_currentCount == 0;

		public WaitHandle WaitHandle
		{
			get
			{
				ThrowIfDisposed();
				return m_event.WaitHandle;
			}
		}

		public CountdownEvent(int initialCount)
		{
			if (initialCount < 0)
			{
				throw new ArgumentOutOfRangeException("initialCount");
			}
			m_initialCount = initialCount;
			m_currentCount = initialCount;
			m_event = new ManualResetEventSlim();
			if (initialCount == 0)
			{
				m_event.Set();
			}
		}

		public void Dispose()
		{
			Dispose(disposing: true);
			GC.SuppressFinalize(this);
		}

		protected virtual void Dispose(bool disposing)
		{
			if (disposing)
			{
				m_event.Dispose();
				m_disposed = true;
			}
		}

		public bool Signal()
		{
			return Signal(1);
		}

		public bool Signal(int signalCount)
		{
			if (signalCount <= 0)
			{
				throw new ArgumentOutOfRangeException("signalCount");
			}
			ThrowIfDisposed();
			SpinWait spinWait = default(SpinWait);
			int currentCount;
			while (true)
			{
				currentCount = m_currentCount;
				if (currentCount < signalCount)
				{
					throw new InvalidOperationException(Environment2.GetResourceString("CountdownEvent_Decrement_BelowZero"));
				}
				if (Interlocked.CompareExchange(ref m_currentCount, currentCount - signalCount, currentCount) == currentCount)
				{
					break;
				}
				spinWait.SpinOnce();
			}
			if (currentCount == signalCount)
			{
				m_event.Set();
				return true;
			}
			return false;
		}

		public void AddCount()
		{
			AddCount(1);
		}

		public bool TryAddCount()
		{
			return TryAddCount(1);
		}

		public void AddCount(int signalCount)
		{
			if (!TryAddCount(signalCount))
			{
				throw new InvalidOperationException(Environment2.GetResourceString("CountdownEvent_Increment_AlreadyZero"));
			}
		}

		public bool TryAddCount(int signalCount)
		{
			if (signalCount <= 0)
			{
				throw new ArgumentOutOfRangeException("signalCount");
			}
			ThrowIfDisposed();
			SpinWait spinWait = default(SpinWait);
			while (true)
			{
				int currentCount = m_currentCount;
				if (currentCount == 0)
				{
					return false;
				}
				if (currentCount > int.MaxValue - signalCount)
				{
					throw new InvalidOperationException(Environment2.GetResourceString("CountdownEvent_Increment_AlreadyMax"));
				}
				if (Interlocked.CompareExchange(ref m_currentCount, currentCount + signalCount, currentCount) == currentCount)
				{
					break;
				}
				spinWait.SpinOnce();
			}
			return true;
		}

		public void Reset()
		{
			Reset(m_initialCount);
		}

		public void Reset(int count)
		{
			ThrowIfDisposed();
			if (count < 0)
			{
				throw new ArgumentOutOfRangeException("count");
			}
			m_currentCount = count;
			m_initialCount = count;
			if (count == 0)
			{
				m_event.Set();
			}
			else
			{
				m_event.Reset();
			}
		}

		public void Wait()
		{
			Wait(-1, default(CancellationToken));
		}

		public void Wait(CancellationToken cancellationToken)
		{
			Wait(-1, cancellationToken);
		}

		public bool Wait(TimeSpan timeout)
		{
			long num = (long)timeout.TotalMilliseconds;
			if (num < -1 || num > int.MaxValue)
			{
				throw new ArgumentOutOfRangeException("timeout");
			}
			return Wait((int)num, default(CancellationToken));
		}

		public bool Wait(TimeSpan timeout, CancellationToken cancellationToken)
		{
			long num = (long)timeout.TotalMilliseconds;
			if (num < -1 || num > int.MaxValue)
			{
				throw new ArgumentOutOfRangeException("timeout");
			}
			return Wait((int)num, cancellationToken);
		}

		public bool Wait(int millisecondsTimeout)
		{
			return Wait(millisecondsTimeout, default(CancellationToken));
		}

		public bool Wait(int millisecondsTimeout, CancellationToken cancellationToken)
		{
			if (millisecondsTimeout < -1)
			{
				throw new ArgumentOutOfRangeException("millisecondsTimeout");
			}
			ThrowIfDisposed();
			cancellationToken.ThrowIfCancellationRequested();
			bool flag = IsSet;
			if (!flag)
			{
				flag = m_event.Wait(millisecondsTimeout, cancellationToken);
			}
			return flag;
		}

		private void ThrowIfDisposed()
		{
			if (m_disposed)
			{
				throw new ObjectDisposedException("CountdownEvent");
			}
		}
	}
	[ComVisible(false)]
	[DebuggerDisplay("Set = {IsSet}")]
	[HostProtection(SecurityAction.LinkDemand, Synchronization = true, ExternalThreading = true)]
	public class ManualResetEventSlim : IDisposable
	{
		private const int DEFAULT_SPIN_SP = 1;

		private const int DEFAULT_SPIN_MP = 10;

		private const int SignalledState_BitMask = int.MinValue;

		private const int SignalledState_ShiftCount = 31;

		private const int Dispose_BitMask = 1073741824;

		private const int SpinCountState_BitMask = 1073217536;

		private const int SpinCountState_ShiftCount = 19;

		private const int SpinCountState_MaxValue = 2047;

		private const int NumWaitersState_BitMask = 524287;

		private const int NumWaitersState_ShiftCount = 0;

		private const int NumWaitersState_MaxValue = 524287;

		private object m_lock;

		private ManualResetEvent m_eventObj;

		private volatile int m_combinedState;

		private static Action<object> s_cancellationTokenCallback = CancellationTokenCallback;

		public WaitHandle WaitHandle
		{
			get
			{
				ThrowIfDisposed();
				if (m_eventObj == null)
				{
					LazyInitializeEvent();
				}
				return m_eventObj;
			}
		}

		public bool IsSet
		{
			get
			{
				return 0 != ExtractStatePortion(m_combinedState, int.MinValue);
			}
			private set
			{
				UpdateStateAtomically((value ? 1 : 0) << 31, int.MinValue);
			}
		}

		public int SpinCount
		{
			get
			{
				return ExtractStatePortionAndShiftRight(m_combinedState, 1073217536, 19);
			}
			private set
			{
				m_combinedState = (m_combinedState & -1073217537) | (value << 19);
			}
		}

		private int Waiter