Decompiled source of REPO Active v5.1.0

BepInEx\plugins\REPO_Active\REPO_Active.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using REPO_Active.Reflection;
using REPO_Active.Runtime;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("REPO_Active")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("5.1.0.0")]
[assembly: AssemblyInformationalVersion("5.1.0+fd2a9afffcbc228da2de632ea7f5cf7cb58a1c3c")]
[assembly: AssemblyProduct("REPO_Active")]
[assembly: AssemblyTitle("REPO_Active")]
[assembly: AssemblyVersion("5.1.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

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

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace REPO_Active
{
	[BepInPlugin("angelcomilk.repo_active", "REPO_Active", "5.1.0")]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "angelcomilk.repo_active";

		public const string PluginName = "REPO_Active";

		public const string PluginVersion = "5.1.0";

		private ConfigEntry<bool> _autoActivate;

		private ConfigEntry<KeyCode> _keyActivateNearest;

		private ConfigEntry<bool> _discoverAllPoints;

		private ExtractionPointScanner _scanner;

		private ExtractionPointInvoker _invoker;

		private Harmony? _harmony;

		private static Plugin? _instance;

		private float _autoTimer;

		private float _discoverTimer;

		private float _autoReadyTime = -1f;

		private float _discoverReadyTime = -1f;

		private bool _autoPrimed;

		private readonly HashSet<int> _deferredMarking = new HashSet<int>();

		private readonly List<Component> _playerCache = new List<Component>();

		private readonly List<Vector3> _playerLastPos = new List<Vector3>();

		private int _playerCacheHash;

		private int _playerListEmptyStreak;

		private int _lastPlayerCount = -1;

		private float _lastBaseInterval = 0.5f;

		private int _lastHostPosCount = -1;

		private int _lastAutoBufferBucket = int.MinValue;

		private int _lastDiscoverBufferBucket = int.MinValue;

		private string _lastBusyInfo = "";

		private int _lastBusyCount = -1;

		private float _lastBusyLogTime = -1f;

		private bool? _lastTailHoldState;

		private const float RESCAN_COOLDOWN = 0.6f;

		private const bool SKIP_ACTIVATED = true;

		private const float AUTO_INTERVAL = 5f;

		private const float DISCOVER_INTERVAL_BASE = 0.5f;

		private const float DISCOVER_INTERVAL_4_6 = 1f;

		private const float DISCOVER_INTERVAL_7_9 = 1.5f;

		private const float DISCOVER_INTERVAL_10_12 = 2f;

		private const float DISCOVER_INTERVAL_MAX = 3f;

		private const float DISCOVER_RADIUS = 20f;

		private const float AUTO_READY_BUFFER = 30f;

		private void Awake()
		{
			_autoActivate = ((BaseUnityPlugin)this).Config.Bind<bool>("Auto", "AutoActivate", false, "Auto activate when idle.");
			_keyActivateNearest = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Keybinds", "ActivateNearest", (KeyCode)284, "Press to activate next extraction point (uses OnClick via reflection).");
			_discoverAllPoints = ((BaseUnityPlugin)this).Config.Bind<bool>("Discovery", "DiscoverAllPoints", false, "If true, treat all extraction points as discovered.");
			_invoker = new ExtractionPointInvoker();
			_scanner = new ExtractionPointScanner(0.6f);
			_instance = this;
			InstallEventPatches();
			SceneManager.sceneLoaded += OnSceneLoaded;
		}

		private void OnDestroy()
		{
			try
			{
				SceneManager.sceneLoaded -= OnSceneLoaded;
			}
			catch
			{
			}
			try
			{
				UninstallEventPatches();
			}
			catch
			{
			}
			if (_instance == this)
			{
				_instance = null;
			}
		}

		private void Update()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			if (Input.GetKeyDown(_keyActivateNearest.Value) && !_autoActivate.Value)
			{
				ActivateNearest();
			}
			_discoverTimer += Time.deltaTime;
			float discoveryInterval = GetDiscoveryInterval();
			if (_discoverTimer >= discoveryInterval)
			{
				_discoverTimer = 0f;
				DiscoveryTick();
			}
			if (!_autoActivate.Value)
			{
				return;
			}
			if (_autoReadyTime < 0f)
			{
				if (_scanner.EnsureReady())
				{
					List<Component> list = _scanner.ScanAndGetAllPoints();
					Vector3 referencePos = _scanner.GetReferencePos();
					if (list.Count > 0 && referencePos != Vector3.zero)
					{
						_scanner.CaptureSpawnPosIfNeeded(referencePos);
						_autoReadyTime = Time.realtimeSinceStartup;
						_autoTimer = 0f;
					}
				}
				return;
			}
			if (Time.realtimeSinceStartup - _autoReadyTime >= 30f)
			{
				_lastAutoBufferBucket = int.MinValue;
				if (!_autoPrimed)
				{
					PrimeFirstPointIfAlreadyActivated();
					_autoPrimed = true;
				}
				_autoTimer += Time.deltaTime;
				if (_autoTimer >= 5f)
				{
					_autoTimer = 0f;
					AutoActivateIfIdle();
				}
				return;
			}
			float num = 30f - (Time.realtimeSinceStartup - _autoReadyTime);
			if (num > 0f)
			{
				int num2 = (int)(num / 5f);
				if (num2 != _lastAutoBufferBucket)
				{
					_lastAutoBufferBucket = num2;
				}
			}
		}

		private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
		{
			_autoReadyTime = -1f;
			_discoverReadyTime = Time.realtimeSinceStartup;
			_autoPrimed = false;
			_autoTimer = 0f;
			_discoverTimer = 0f;
			_lastTailHoldState = null;
			_scanner.ResetForNewRound();
			_lastPlayerCount = -1;
			_lastBaseInterval = 0.5f;
			RefreshDiscoveryIntervalFromCurrentPlayerCount("scene init", invalidateCache: true);
		}

		private void DiscoveryTick()
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			if (!_scanner.EnsureReady())
			{
				return;
			}
			List<Component> list = _scanner.ScanAndGetAllPoints();
			Vector3 referencePos = _scanner.GetReferencePos();
			_scanner.CaptureSpawnPosIfNeeded(referencePos);
			if (list.Count == 0)
			{
				return;
			}
			if (_discoverAllPoints.Value)
			{
				_scanner.MarkAllDiscovered(list);
				return;
			}
			if (_discoverReadyTime < 0f)
			{
				_discoverReadyTime = Time.realtimeSinceStartup;
			}
			if (Time.realtimeSinceStartup - _discoverReadyTime < 30f)
			{
				int num = (int)((30f - (Time.realtimeSinceStartup - _discoverReadyTime)) / 5f);
				if (num != _lastDiscoverBufferBucket)
				{
					_lastDiscoverBufferBucket = num;
				}
				return;
			}
			_lastDiscoverBufferBucket = int.MinValue;
			if (_scanner.DiscoveredCount >= list.Count)
			{
				return;
			}
			List<Vector3> list2 = TryGetAllPlayerPositionsHost();
			if (list2.Count == 0)
			{
				_playerListEmptyStreak++;
				_scanner.UpdateDiscovered(referencePos, 20f);
				return;
			}
			_playerListEmptyStreak = 0;
			for (int i = 0; i < list2.Count; i++)
			{
				_scanner.UpdateDiscovered(list2[i], 20f);
			}
			if (list2.Count != _lastHostPosCount)
			{
				_lastHostPosCount = list2.Count;
			}
		}

		private void AutoActivateIfIdle()
		{
			if (_scanner.EnsureReady())
			{
				ActivateNearest();
			}
		}

		private void ActivateNearest()
		{
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0203: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0230: Unknown result type (might be due to invalid IL or missing references)
			if (!_scanner.EnsureReady())
			{
				return;
			}
			List<Component> list = _scanner.ScanAndGetAllPoints();
			if (_scanner.TryGetActivatingInfo(list, out string info, out int busyCount))
			{
				float realtimeSinceStartup = Time.realtimeSinceStartup;
				if (info != _lastBusyInfo || busyCount != _lastBusyCount || realtimeSinceStartup - _lastBusyLogTime > 2f)
				{
					_lastBusyInfo = info;
					_lastBusyCount = busyCount;
					_lastBusyLogTime = realtimeSinceStartup;
				}
				return;
			}
			Vector3 referencePos = _scanner.GetReferencePos();
			_scanner.CaptureSpawnPosIfNeeded(referencePos);
			Vector3 spawnPos = _scanner.GetSpawnPos();
			if (_discoverAllPoints.Value)
			{
				_scanner.MarkAllDiscovered(list);
			}
			else
			{
				UpdateDiscoveredFromCachedPlayers(referencePos);
			}
			List<Component> list2 = (List<Component>)(_discoverAllPoints.Value ? ((IList)list) : ((IList)_scanner.FilterDiscovered(list)));
			List<Component> allPoints = list2;
			if (!_discoverAllPoints.Value && list2.Count > 1 && _scanner.TryGetGlobalAnchorsNoCache(list, spawnPos, out Component _, out Component tailAnchor) && (Object)(object)tailAnchor != (Object)null)
			{
				int instanceID = ((Object)tailAnchor).GetInstanceID();
				bool flag = false;
				for (int i = 0; i < list2.Count; i++)
				{
					if (Object.op_Implicit((Object)(object)list2[i]) && ((Object)list2[i]).GetInstanceID() == instanceID)
					{
						flag = true;
						break;
					}
				}
				if (flag)
				{
					List<Component> list3 = new List<Component>();
					int num = 0;
					for (int j = 0; j < list2.Count; j++)
					{
						Component val = list2[j];
						if (Object.op_Implicit((Object)(object)val) && ((Object)val).GetInstanceID() != instanceID)
						{
							list3.Add(val);
							if (!ExtractionPointScanner.IsCompletedLikeState(_scanner.ReadStateName(val)))
							{
								num++;
							}
						}
					}
					if (list3.Count > 0 && num > 0)
					{
						allPoints = list3;
					}
				}
			}
			List<Component> list4 = (_discoverAllPoints.Value ? _scanner.BuildPlanDiscoverAllFixedAnchors(list, spawnPos, skipActivated: true) : _scanner.BuildStage1PlannedList(allPoints, spawnPos, skipActivated: true));
			if (list4.Count == 0)
			{
				return;
			}
			Component val2 = list4[0];
			if ((_discoverAllPoints.Value || !ShouldHoldTailPointActivation(list, spawnPos, list4, val2, out string _)) && _invoker.InvokeOnClick(val2))
			{
				string text = _scanner.ReadStateName(val2);
				if (!string.IsNullOrEmpty(text) && !ExtractionPointScanner.IsIdleLikeState(text) && !ExtractionPointScanner.IsCompletedLikeState(text))
				{
					_scanner.MarkActivated(val2);
				}
				else
				{
					TryDeferredMarkActivated(val2);
				}
			}
		}

		private void TryDeferredMarkActivated(Component ep)
		{
			if (!((Object)(object)ep == (Object)null))
			{
				int instanceID = ((Object)ep).GetInstanceID();
				if (_deferredMarking.Add(instanceID))
				{
					((MonoBehaviour)this).StartCoroutine(DeferredMarkActivated(ep, instanceID));
				}
			}
		}

		private IEnumerator DeferredMarkActivated(Component ep, int id)
		{
			try
			{
				if ((Object)(object)ep == (Object)null)
				{
					yield break;
				}
				float[] waits = new float[5] { 0.15f, 0.25f, 0.35f, 0.35f, 0.4f };
				for (int i = 0; i < waits.Length; i++)
				{
					if (waits[i] > 0f)
					{
						yield return (object)new WaitForSeconds(waits[i]);
					}
					if ((Object)(object)ep == (Object)null)
					{
						break;
					}
					string text = _scanner.ReadStateName(ep);
					if (!string.IsNullOrEmpty(text) && !ExtractionPointScanner.IsIdleLikeState(text) && !ExtractionPointScanner.IsCompletedLikeState(text))
					{
						_scanner.MarkActivated(ep);
						break;
					}
					if (i == 0)
					{
						yield return null;
						if ((Object)(object)ep == (Object)null)
						{
							break;
						}
						string text2 = _scanner.ReadStateName(ep);
						if (!string.IsNullOrEmpty(text2))
						{
						}
						if (!string.IsNullOrEmpty(text2) && !ExtractionPointScanner.IsIdleLikeState(text2) && !ExtractionPointScanner.IsCompletedLikeState(text2))
						{
							_scanner.MarkActivated(ep);
							break;
						}
					}
				}
			}
			finally
			{
				_deferredMarking.Remove(id);
			}
		}

		private void PrimeFirstPointIfAlreadyActivated()
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			List<Component> list = _scanner.ScanAndGetAllPoints();
			if (list.Count == 0)
			{
				return;
			}
			Vector3 referencePos = _scanner.GetReferencePos();
			_scanner.CaptureSpawnPosIfNeeded(referencePos);
			if (_discoverAllPoints.Value)
			{
				_scanner.MarkAllDiscovered(list);
			}
			else
			{
				_scanner.UpdateDiscovered(referencePos, 20f);
			}
			List<Component> allPoints = (List<Component>)(_discoverAllPoints.Value ? ((IList)list) : ((IList)_scanner.FilterDiscovered(list)));
			Vector3 spawnPos = _scanner.GetSpawnPos();
			List<Component> list2 = (_discoverAllPoints.Value ? _scanner.BuildPlanDiscoverAllFixedAnchors(list, spawnPos, skipActivated: true) : _scanner.BuildStage1PlannedList(allPoints, spawnPos, skipActivated: true));
			if (list2.Count != 0)
			{
				Component ep = list2[0];
				string text = _scanner.ReadStateName(ep);
				if (!string.IsNullOrEmpty(text) && !ExtractionPointScanner.IsIdleLikeState(text))
				{
					_scanner.MarkActivated(ep);
				}
			}
		}

		private List<Vector3> TryGetAllPlayerPositionsHost()
		{
			//IL_0290: Unknown result type (might be due to invalid IL or missing references)
			//IL_0305: Unknown result type (might be due to invalid IL or missing references)
			//IL_030a: Unknown result type (might be due to invalid IL or missing references)
			//IL_030d: Unknown result type (might be due to invalid IL or missing references)
			//IL_031c: Unknown result type (might be due to invalid IL or missing references)
			List<Vector3> list = new List<Vector3>();
			try
			{
				Type type = Type.GetType("Photon.Pun.PhotonNetwork, PhotonUnityNetworking");
				if (type == null)
				{
					return list;
				}
				PropertyInfo property = type.GetProperty("InRoom");
				PropertyInfo property2 = type.GetProperty("IsMasterClient");
				bool flag = default(bool);
				int num;
				if (property != null)
				{
					object value = property.GetValue(null);
					if (value is bool)
					{
						flag = (bool)value;
						num = 1;
					}
					else
					{
						num = 0;
					}
				}
				else
				{
					num = 0;
				}
				int num2 = num & (flag ? 1 : 0);
				bool flag2 = default(bool);
				int num3;
				if (property2 != null)
				{
					object value = property2.GetValue(null);
					if (value is bool)
					{
						flag2 = (bool)value;
						num3 = 1;
					}
					else
					{
						num3 = 0;
					}
				}
				else
				{
					num3 = 0;
				}
				bool flag3 = (byte)((uint)num3 & (flag2 ? 1u : 0u)) != 0;
				if (num2 == 0 || !flag3)
				{
					return list;
				}
				Type type2 = Type.GetType("GameDirector, Assembly-CSharp");
				if (type2 == null)
				{
					return list;
				}
				object obj = null;
				PropertyInfo property3 = type2.GetProperty("instance", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				if (property3 != null)
				{
					obj = property3.GetValue(null, null);
				}
				if (obj == null)
				{
					FieldInfo field = type2.GetField("instance", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
					if (field != null)
					{
						obj = field.GetValue(null);
					}
				}
				if (obj == null)
				{
					return list;
				}
				object obj2 = null;
				PropertyInfo property4 = type2.GetProperty("PlayerList", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (property4 != null)
				{
					obj2 = property4.GetValue(obj, null);
				}
				if (obj2 == null)
				{
					FieldInfo field2 = type2.GetField("PlayerList", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					if (field2 != null)
					{
						obj2 = field2.GetValue(obj);
					}
				}
				if (obj2 == null)
				{
					return list;
				}
				if (!(obj2 is IEnumerable enumerable))
				{
					return list;
				}
				List<Component> list2 = new List<Component>();
				int num4 = 17;
				foreach (object item in enumerable)
				{
					if (item != null)
					{
						Component val = ExtractPlayerComponent(item);
						if (!((Object)(object)val == (Object)null) && !((Object)(object)val.transform == (Object)null))
						{
							list2.Add(val);
							num4 = num4 * 31 + ((Object)val).GetInstanceID();
						}
					}
				}
				if (list2.Count == 0)
				{
					return list;
				}
				if (num4 != _playerCacheHash || _playerCache.Count != list2.Count)
				{
					_playerCacheHash = num4;
					_playerCache.Clear();
					_playerCache.AddRange(list2);
					_playerLastPos.Clear();
					for (int i = 0; i < _playerCache.Count; i++)
					{
						_playerLastPos.Add(_playerCache[i].transform.position);
					}
				}
				for (int j = 0; j < _playerCache.Count; j++)
				{
					Component val2 = _playerCache[j];
					if ((Object)(object)val2 == (Object)null || (Object)(object)val2.transform == (Object)null)
					{
						_playerCache.Clear();
						_playerLastPos.Clear();
						_playerCacheHash = 0;
						return list;
					}
					Vector3 position = val2.transform.position;
					list.Add(position);
					_playerLastPos[j] = position;
				}
				return list;
			}
			catch
			{
				return list;
			}
		}

		private Component? ExtractPlayerComponent(object p)
		{
			Component val = (Component)((p is Component) ? p : null);
			if (val != null && (Object)(object)val.transform != (Object)null)
			{
				return val;
			}
			Type type = p.GetType();
			object obj = null;
			PropertyInfo property = type.GetProperty("PlayerAvatar", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (property != null)
			{
				obj = property.GetValue(p, null);
			}
			if (obj == null)
			{
				FieldInfo field = type.GetField("PlayerAvatar", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (field != null)
				{
					obj = field.GetValue(p);
				}
			}
			if (obj == null)
			{
				return null;
			}
			Component val2 = (Component)((obj is Component) ? obj : null);
			if (val2 != null && (Object)(object)val2.transform != (Object)null)
			{
				return val2;
			}
			PropertyInfo property2 = obj.GetType().GetProperty("transform", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (!(property2 != null))
			{
				return null;
			}
			object? value = property2.GetValue(obj, null);
			return (Component?)((value is Transform) ? value : null);
		}

		private void UpdateDiscoveredFromCachedPlayers(Vector3 fallbackPos)
		{
			//IL_005f: 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)
			if (_playerCache.Count > 0 && _playerLastPos.Count == _playerCache.Count)
			{
				for (int i = 0; i < _playerLastPos.Count; i++)
				{
					_scanner.UpdateDiscovered(_playerLastPos[i], 20f);
				}
			}
			else
			{
				_scanner.UpdateDiscovered(fallbackPos, 20f);
			}
		}

		private bool ShouldHoldTailPointActivation(List<Component> allPoints, Vector3 spawnPos, List<Component> plan, Component next, out string reason)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			reason = "";
			if (_discoverAllPoints.Value)
			{
				return false;
			}
			if ((Object)(object)next == (Object)null)
			{
				return false;
			}
			if (!_scanner.TryGetGlobalAnchorsNoCache(allPoints, spawnPos, out Component firstAnchor, out Component tailAnchor))
			{
				return false;
			}
			if ((Object)(object)tailAnchor == (Object)null)
			{
				return false;
			}
			int num = (((Object)(object)firstAnchor != (Object)null) ? ((Object)firstAnchor).GetInstanceID() : int.MinValue);
			int instanceID = ((Object)tailAnchor).GetInstanceID();
			bool flag = ((Object)next).GetInstanceID() == instanceID;
			List<string> list = new List<string>();
			for (int i = 0; i < allPoints.Count; i++)
			{
				Component val = allPoints[i];
				if (!Object.op_Implicit((Object)(object)val))
				{
					continue;
				}
				int instanceID2 = ((Object)val).GetInstanceID();
				if (instanceID2 != num && instanceID2 != instanceID)
				{
					string text = _scanner.ReadStateName(val);
					if (!ExtractionPointScanner.IsCompletedLikeState(text))
					{
						list.Add($"{((Object)val.gameObject).name}#{((Object)val).GetInstanceID()}({text})");
					}
				}
			}
			bool flag2 = flag && list.Count > 0;
			string arg = ((plan == null || plan.Count == 0) ? "-" : string.Join(" -> ", from x in plan
				where (Object)(object)x != (Object)null
				select $"{((Object)x.gameObject).name}#{((Object)x).GetInstanceID()}"));
			_lastTailHoldState = flag2;
			if (!flag2)
			{
				return false;
			}
			reason = string.Format("tail point locked, pendingOthers={0}, pending=[{1}], queue={2}", list.Count, string.Join(", ", list), arg);
			return true;
		}

		private void HandleRoomPopulationChangedEvent(string reason)
		{
			RefreshDiscoveryIntervalFromCurrentPlayerCount(reason, invalidateCache: true);
		}

		private void RefreshDiscoveryIntervalFromCurrentPlayerCount(string reason, bool invalidateCache)
		{
			int num = GetPlayerCountHost();
			if (num < 1)
			{
				num = 1;
			}
			if (num != _lastPlayerCount)
			{
				_lastPlayerCount = num;
				_lastBaseInterval = ComputeDiscoveryInterval(num);
			}
			if (invalidateCache)
			{
				_playerCache.Clear();
				_playerLastPos.Clear();
				_playerCacheHash = 0;
			}
		}

		private float GetDiscoveryInterval()
		{
			if (_discoverAllPoints.Value)
			{
				return 0.5f;
			}
			if (_lastPlayerCount < 1)
			{
				RefreshDiscoveryIntervalFromCurrentPlayerCount("lazy init", invalidateCache: false);
			}
			float lastBaseInterval = _lastBaseInterval;
			if (_playerListEmptyStreak <= 0)
			{
				return lastBaseInterval;
			}
			float num = 1f + (float)Math.Min(_playerListEmptyStreak, 10) * 0.2f;
			float num2 = lastBaseInterval * num;
			if (!(num2 > 3f))
			{
				return num2;
			}
			return 3f;
		}

		private float ComputeDiscoveryInterval(int players)
		{
			if (players <= 3)
			{
				return 0.5f;
			}
			if (players <= 6)
			{
				return 1f;
			}
			if (players <= 9)
			{
				return 1.5f;
			}
			return 2f;
		}

		private static void OnPlayerEnteredRoomPostfix()
		{
			_instance?.HandleRoomPopulationChangedEvent("player entered");
		}

		private static void OnPlayerLeftRoomPostfix()
		{
			_instance?.HandleRoomPopulationChangedEvent("player left");
		}

		private void InstallEventPatches()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected O, but got Unknown
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Expected O, but got Unknown
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Expected O, but got Unknown
			try
			{
				_harmony = new Harmony("angelcomilk.repo_active.population");
				Type type = AccessTools.TypeByName("NetworkManager");
				MethodInfo methodInfo = ((type != null) ? AccessTools.DeclaredMethod(type, "OnPlayerEnteredRoom", (Type[])null, (Type[])null) : null);
				if (methodInfo != null)
				{
					_harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(Plugin), "OnPlayerEnteredRoomPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
				MethodInfo methodInfo2 = ((type != null) ? AccessTools.DeclaredMethod(type, "OnPlayerLeftRoom", (Type[])null, (Type[])null) : null);
				if (methodInfo2 != null)
				{
					_harmony.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, new HarmonyMethod(typeof(Plugin), "OnPlayerLeftRoomPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
			}
			catch (Exception)
			{
			}
		}

		private void UninstallEventPatches()
		{
			try
			{
				Harmony? harmony = _harmony;
				if (harmony != null)
				{
					harmony.UnpatchSelf();
				}
				_harmony = null;
			}
			catch
			{
			}
		}

		private int GetPlayerCountHost()
		{
			try
			{
				Type type = Type.GetType("Photon.Pun.PhotonNetwork, PhotonUnityNetworking");
				if (type == null)
				{
					return 1;
				}
				PropertyInfo property = type.GetProperty("InRoom");
				PropertyInfo property2 = type.GetProperty("IsMasterClient");
				PropertyInfo property3 = type.GetProperty("PlayerList");
				bool flag = default(bool);
				int num;
				if (property != null)
				{
					object value = property.GetValue(null);
					if (value is bool)
					{
						flag = (bool)value;
						num = 1;
					}
					else
					{
						num = 0;
					}
				}
				else
				{
					num = 0;
				}
				int num2 = num & (flag ? 1 : 0);
				bool flag2 = default(bool);
				int num3;
				if (property2 != null)
				{
					object value = property2.GetValue(null);
					if (value is bool)
					{
						flag2 = (bool)value;
						num3 = 1;
					}
					else
					{
						num3 = 0;
					}
				}
				else
				{
					num3 = 0;
				}
				bool flag3 = (byte)((uint)num3 & (flag2 ? 1u : 0u)) != 0;
				if (num2 == 0 || !flag3)
				{
					return 1;
				}
				if (property3 != null && property3.GetValue(null) is Array array && array.Length > 0)
				{
					return array.Length;
				}
			}
			catch
			{
			}
			return 1;
		}
	}
}
namespace REPO_Active.Runtime
{
	public sealed class ExtractionPointScanner
	{
		private Type? _epType;

		private readonly List<Component> _cached = new List<Component>();

		private float _lastScanRealtime;

		private int _lastScanCount = -1;

		private Vector3? _spawnPos;

		private readonly HashSet<int> _activatedIds = new HashSet<int>();

		private readonly HashSet<int> _discovered = new HashSet<int>();

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

		private readonly HashSet<int> _spawnPathInvalid = new HashSet<int>();

		private readonly Dictionary<long, float> _edgePathCache = new Dictionary<long, float>();

		private readonly HashSet<long> _edgePathInvalid = new HashSet<long>();

		private int? _firstAnchorId;

		private int? _lastAnchorId;

		private static readonly Dictionary<string, bool> _idleCache = new Dictionary<string, bool>(StringComparer.OrdinalIgnoreCase);

		private static readonly Dictionary<string, bool> _completeCache = new Dictionary<string, bool>(StringComparer.OrdinalIgnoreCase);

		public float RescanCooldown { get; set; }

		public int CachedCount => _cached.Count;

		public int DiscoveredCount => _discovered.Count;

		public ExtractionPointScanner(float rescanCooldown)
		{
			RescanCooldown = rescanCooldown;
		}

		public bool EnsureReady()
		{
			if (_epType != null)
			{
				return true;
			}
			_epType = AppDomain.CurrentDomain.GetAssemblies().SelectMany(delegate(Assembly a)
			{
				try
				{
					return a.GetTypes();
				}
				catch
				{
					return Array.Empty<Type>();
				}
			}).FirstOrDefault((Type t) => t != null && t.Name == "ExtractionPoint");
			return _epType != null;
		}

		public void ScanIfNeeded(bool force)
		{
			try
			{
				float realtimeSinceStartup = Time.realtimeSinceStartup;
				float num = realtimeSinceStartup;
				if (!force && num - _lastScanRealtime < RescanCooldown)
				{
					return;
				}
				_lastScanRealtime = num;
				if (EnsureReady())
				{
					Object[] source = Object.FindObjectsOfType(_epType);
					_cached.Clear();
					_cached.AddRange(from c in source.OfType<Component>()
						where (Object)(object)c != (Object)null
						select c);
					_ = Time.realtimeSinceStartup;
					if (_lastScanCount != _cached.Count)
					{
						_lastScanCount = _cached.Count;
					}
				}
			}
			catch (Exception)
			{
			}
		}

		public Vector3 GetReferencePos()
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if ((Object)(object)Camera.main != (Object)null)
				{
					return ((Component)Camera.main).transform.position;
				}
			}
			catch
			{
			}
			try
			{
				GameObject val = GameObject.FindWithTag("Player");
				if ((Object)(object)val != (Object)null)
				{
					return val.transform.position;
				}
			}
			catch
			{
			}
			return Vector3.zero;
		}

		public void MarkAllDiscovered(List<Component> allPoints)
		{
			int count = _discovered.Count;
			for (int i = 0; i < allPoints.Count; i++)
			{
				Component val = allPoints[i];
				if (Object.op_Implicit((Object)(object)val))
				{
					_discovered.Add(((Object)val).GetInstanceID());
				}
			}
			_ = _discovered.Count - count;
			_ = 0;
		}

		public void UpdateDiscovered(Vector3 refPos, float radius)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			UpdateDiscoveredDetailed(refPos, radius, null);
		}

		public int UpdateDiscoveredDetailed(Vector3 refPos, float radius, List<Component>? newly)
		{
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			if (_cached.Count == 0)
			{
				return 0;
			}
			int count = _discovered.Count;
			for (int i = 0; i < _cached.Count; i++)
			{
				Component val = _cached[i];
				if (!Object.op_Implicit((Object)(object)val))
				{
					continue;
				}
				int instanceID = ((Object)val).GetInstanceID();
				if (!_discovered.Contains(instanceID))
				{
					Vector3 val2 = refPos - val.transform.position;
					if (((Vector3)(ref val2)).sqrMagnitude <= radius * radius)
					{
						_discovered.Add(instanceID);
						newly?.Add(val);
					}
				}
			}
			int num = _discovered.Count - count;
			if (num > 0)
			{
			}
			return num;
		}

		public List<Component> FilterDiscovered(List<Component> allPoints)
		{
			List<Component> list = new List<Component>();
			for (int i = 0; i < allPoints.Count; i++)
			{
				Component val = allPoints[i];
				if (Object.op_Implicit((Object)(object)val) && _discovered.Contains(((Object)val).GetInstanceID()))
				{
					list.Add(val);
				}
			}
			return list;
		}

		public Vector3 GetSpawnPos()
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			return (Vector3)(((??)_spawnPos) ?? Vector3.zero);
		}

		public void CaptureSpawnPosIfNeeded(Vector3 refPos)
		{
			//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_001d: Unknown result type (might be due to invalid IL or missing references)
			if (!_spawnPos.HasValue && !(refPos == Vector3.zero))
			{
				_spawnPos = refPos;
			}
		}

		public List<Component> ScanAndGetAllPoints()
		{
			ScanIfNeeded(force: true);
			return _cached.Where((Component c) => (Object)(object)c != (Object)null).ToList();
		}

		public bool TryGetRoundAnchors(List<Component> allPoints, Vector3 spawnPos, out Component? firstAnchor, out Component? tailAnchor)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			return TryGetGlobalAnchorsNoCache(allPoints, spawnPos, out firstAnchor, out tailAnchor);
		}

		public bool TryGetGlobalAnchorsNoCache(List<Component> allPoints, Vector3 spawnPos, out Component? firstAnchor, out Component? tailAnchor)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			firstAnchor = null;
			tailAnchor = null;
			if (allPoints == null || allPoints.Count == 0)
			{
				return false;
			}
			if (spawnPos == Vector3.zero)
			{
				return false;
			}
			List<(Component, int, float)> list2 = new List<(Component, int, float)>();
			for (int i = 0; i < allPoints.Count; i++)
			{
				Component val = allPoints[i];
				if (Object.op_Implicit((Object)(object)val) && TryGetSpawnPathLength(val, spawnPos, _spawnPathCache, _spawnPathInvalid, out var length))
				{
					list2.Add((val, ((Object)val).GetInstanceID(), length));
				}
			}
			if (list2.Count == 0)
			{
				return false;
			}
			(Component, int, float) tuple = PickByMinSpawn(list2);
			firstAnchor = tuple.Item1;
			List<(Component, int, float)> list3 = new List<(Component, int, float)>();
			for (int j = 0; j < list2.Count; j++)
			{
				if (list2[j].Item2 != tuple.Item2)
				{
					list3.Add(list2[j]);
				}
			}
			if (list3.Count == 0)
			{
				return true;
			}
			(tailAnchor, _, _) = PickByMinSpawn(list3);
			return true;
			static (Component ep, int id, float spawnPath) PickByMinSpawn(List<(Component ep, int id, float spawnPath)> list)
			{
				(Component, int, float) result = list[0];
				for (int k = 1; k < list.Count; k++)
				{
					(Component, int, float) tuple3 = list[k];
					if (tuple3.Item3 + 0.0001f < result.Item3 || (Mathf.Abs(tuple3.Item3 - result.Item3) <= 0.0001f && tuple3.Item2 < result.Item2))
					{
						result = tuple3;
					}
				}
				return result;
			}
		}

		public void ResetForNewRound()
		{
			_cached.Clear();
			_activatedIds.Clear();
			_discovered.Clear();
			_spawnPos = null;
			_spawnPathCache.Clear();
			_spawnPathInvalid.Clear();
			_edgePathCache.Clear();
			_edgePathInvalid.Clear();
			_firstAnchorId = null;
			_lastAnchorId = null;
			_lastScanRealtime = 0f;
			_lastScanCount = -1;
		}

		public void MarkActivated(Component ep)
		{
			if (!((Object)(object)ep == (Object)null))
			{
				_activatedIds.Add(((Object)ep).GetInstanceID());
			}
		}

		private bool IsMarkedActivated(Component ep)
		{
			if ((Object)(object)ep == (Object)null)
			{
				return false;
			}
			return _activatedIds.Contains(((Object)ep).GetInstanceID());
		}

		public bool ReconcileActivatedMarks(List<Component> allPoints)
		{
			if (allPoints == null || allPoints.Count == 0)
			{
				if (_activatedIds.Count == 0)
				{
					return false;
				}
				_activatedIds.Clear();
				return true;
			}
			HashSet<int> liveActive = new HashSet<int>();
			for (int i = 0; i < allPoints.Count; i++)
			{
				Component val = allPoints[i];
				if (Object.op_Implicit((Object)(object)val))
				{
					string text = ReadStateName(val);
					if (!string.IsNullOrEmpty(text) && !IsIdleLikeState(text) && !IsCompletedLikeState(text))
					{
						liveActive.Add(((Object)val).GetInstanceID());
					}
				}
			}
			bool result = false;
			if (_activatedIds.Count > 0)
			{
				List<int> list = _activatedIds.Where((int id) => !liveActive.Contains(id)).ToList();
				if (list.Count > 0)
				{
					for (int j = 0; j < list.Count; j++)
					{
						_activatedIds.Remove(list[j]);
					}
					result = true;
				}
			}
			foreach (int item in liveActive)
			{
				if (_activatedIds.Add(item))
				{
					result = true;
				}
			}
			return result;
		}

		public bool IsAnyExtractionPointActivating(List<Component> allPoints)
		{
			string info;
			int busyCount;
			return TryGetActivatingInfo(allPoints, out info, out busyCount);
		}

		public bool TryGetActivatingInfo(List<Component> allPoints, out string info, out int busyCount)
		{
			info = "";
			busyCount = 0;
			if (allPoints == null || allPoints.Count == 0)
			{
				return false;
			}
			for (int i = 0; i < allPoints.Count; i++)
			{
				Component val = allPoints[i];
				if (!Object.op_Implicit((Object)(object)val))
				{
					continue;
				}
				try
				{
					Type type = ((object)val).GetType();
					FieldInfo field = type.GetField("currentState", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					PropertyInfo property = type.GetProperty("currentState", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					object obj = null;
					if (property != null)
					{
						obj = property.GetValue(val, null);
					}
					if (obj == null && field != null)
					{
						obj = field.GetValue(val);
					}
					if (obj == null)
					{
						continue;
					}
					string text = obj.ToString() ?? "";
					if (text.Length != 0 && !IsIdleLikeState(text) && !IsCompletedLikeState(text))
					{
						busyCount++;
						if (string.IsNullOrEmpty(info))
						{
							info = ((Object)val.gameObject).name + " state=" + text;
						}
					}
				}
				catch
				{
					if (busyCount == 0)
					{
						busyCount = 1;
					}
					if (string.IsNullOrEmpty(info))
					{
						info = "state read failed";
					}
					return true;
				}
			}
			return busyCount > 0;
		}

		internal static bool IsIdleLikeState(string stateName)
		{
			if (string.IsNullOrEmpty(stateName))
			{
				return false;
			}
			if (_idleCache.TryGetValue(stateName, out var value))
			{
				return value;
			}
			bool flag = stateName.IndexOf("Idle", StringComparison.OrdinalIgnoreCase) >= 0;
			_idleCache[stateName] = flag;
			return flag;
		}

		internal static bool IsCompletedLikeState(string stateName)
		{
			if (string.IsNullOrEmpty(stateName))
			{
				return false;
			}
			if (_completeCache.TryGetValue(stateName, out var value))
			{
				return value;
			}
			string text = stateName.ToLowerInvariant();
			bool flag = text.Contains("success") || text.Contains("complete") || text.Contains("submitted") || text.Contains("finish") || text.Contains("done");
			_completeCache[stateName] = flag;
			return flag;
		}

		public string ReadStateName(Component ep)
		{
			if (!Object.op_Implicit((Object)(object)ep))
			{
				return "";
			}
			try
			{
				Type type = ((object)ep).GetType();
				FieldInfo field = type.GetField("currentState", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				PropertyInfo property = type.GetProperty("currentState", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				object obj = null;
				if (property != null)
				{
					obj = property.GetValue(ep, null);
				}
				if (obj == null && field != null)
				{
					obj = field.GetValue(ep);
				}
				if (obj == null)
				{
					return "";
				}
				return obj.ToString() ?? "";
			}
			catch
			{
				return "";
			}
		}

		public List<Component> BuildStage1PlannedList(List<Component> allPoints, Vector3 spawnPos, bool skipActivated)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			float realtimeSinceStartup = Time.realtimeSinceStartup;
			List<Component> list2 = new List<Component>();
			if (allPoints == null || allPoints.Count == 0)
			{
				return list2;
			}
			if (spawnPos == Vector3.zero)
			{
				return list2;
			}
			List<Component> list3 = new List<Component>(allPoints.Count);
			for (int i = 0; i < allPoints.Count; i++)
			{
				Component val = allPoints[i];
				if (Object.op_Implicit((Object)(object)val) && !IsCompletedLikeState(ReadStateName(val)) && (!skipActivated || !IsMarkedActivated(val)))
				{
					list3.Add(val);
				}
			}
			if (list3.Count == 0)
			{
				return list2;
			}
			List<(Component, int, float)> list4 = new List<(Component, int, float)>();
			for (int j = 0; j < list3.Count; j++)
			{
				Component val2 = list3[j];
				if (TryGetSpawnPathLength(val2, spawnPos, _spawnPathCache, _spawnPathInvalid, out var length))
				{
					list4.Add((val2, ((Object)val2).GetInstanceID(), length));
				}
			}
			if (list4.Count == 0)
			{
				return list2;
			}
			List<(Component, int, float)> list5 = new List<(Component, int, float)>(list4);
			int num = -1;
			if (_firstAnchorId.HasValue)
			{
				num = FindIndexById(list5, _firstAnchorId.Value);
			}
			var (val3, num2, _) = ((num >= 0) ? list5[num] : PickByMinSpawn(list5));
			if (!_firstAnchorId.HasValue)
			{
				_firstAnchorId = num2;
			}
			List<(Component, int, float)> list6 = new List<(Component, int, float)>();
			for (int k = 0; k < list4.Count; k++)
			{
				if (list4[k].Item2 != num2)
				{
					list6.Add(list4[k]);
				}
			}
			list2.Add(val3);
			if (list6.Count == 0)
			{
				_ = Time.realtimeSinceStartup;
				return list2;
			}
			int num3 = -1;
			if (_lastAnchorId.HasValue)
			{
				num3 = FindIndexById(list6, _lastAnchorId.Value);
			}
			var (last, num4, _) = ((num3 >= 0) ? list6[num3] : PickByMinSpawn(list6));
			if (!_lastAnchorId.HasValue)
			{
				_lastAnchorId = num4;
			}
			List<Component> middleCandidates = new List<Component>();
			for (int l = 0; l < list6.Count; l++)
			{
				if (list6[l].Item2 != num4)
				{
					middleCandidates.Add(list6[l].Item1);
				}
			}
			List<Component> bestMiddle = null;
			float bestTotal = float.MaxValue;
			bool[] used;
			List<Component> curOrder;
			if (middleCandidates.Count == 0)
			{
				if (TryGetEdgePathLength(val3, last, _edgePathCache, _edgePathInvalid, out var length2))
				{
					bestTotal = length2;
					bestMiddle = new List<Component>();
				}
			}
			else
			{
				used = new bool[middleCandidates.Count];
				curOrder = new List<Component>(middleCandidates.Count);
				Dfs(val3, 0f);
			}
			if (bestMiddle == null)
			{
				return new List<Component>();
			}
			for (int m = 0; m < bestMiddle.Count; m++)
			{
				list2.Add(bestMiddle[m]);
			}
			list2.Add(last);
			_ = Time.realtimeSinceStartup;
			return list2;
			void Dfs(Component prev, float costSoFar)
			{
				if (!(costSoFar > bestTotal + 0.0001f))
				{
					if (curOrder.Count == middleCandidates.Count)
					{
						if (TryGetEdgePathLength(prev, last, _edgePathCache, _edgePathInvalid, out var length3))
						{
							float num6 = costSoFar + length3;
							if (num6 + 0.0001f < bestTotal || (Mathf.Abs(num6 - bestTotal) <= 0.0001f && IsBetterSameCostOrder(curOrder, bestMiddle)))
							{
								bestTotal = num6;
								bestMiddle = new List<Component>(curOrder);
							}
						}
					}
					else
					{
						for (int num7 = 0; num7 < middleCandidates.Count; num7++)
						{
							if (!used[num7])
							{
								Component val4 = middleCandidates[num7];
								if (TryGetEdgePathLength(prev, val4, _edgePathCache, _edgePathInvalid, out var length4))
								{
									used[num7] = true;
									curOrder.Add(val4);
									Dfs(val4, costSoFar + length4);
									curOrder.RemoveAt(curOrder.Count - 1);
									used[num7] = false;
								}
							}
						}
					}
				}
			}
			static int FindIndexById(List<(Component ep, int id, float spawnPath)> list, int id)
			{
				for (int num9 = 0; num9 < list.Count; num9++)
				{
					if (list[num9].id == id)
					{
						return num9;
					}
				}
				return -1;
			}
			static bool IsBetterSameCostOrder(List<Component> current, List<Component>? best)
			{
				if (best == null)
				{
					return true;
				}
				int num5 = Math.Min(current.Count, best.Count);
				for (int n = 0; n < num5; n++)
				{
					int instanceID = ((Object)current[n]).GetInstanceID();
					int instanceID2 = ((Object)best[n]).GetInstanceID();
					if (instanceID != instanceID2)
					{
						return instanceID < instanceID2;
					}
				}
				return current.Count < best.Count;
			}
			static (Component ep, int id, float spawnPath) PickByMinSpawn(List<(Component ep, int id, float spawnPath)> list)
			{
				(Component, int, float) result = list[0];
				for (int num8 = 1; num8 < list.Count; num8++)
				{
					(Component, int, float) tuple3 = list[num8];
					if (tuple3.Item3 + 0.0001f < result.Item3 || (Mathf.Abs(tuple3.Item3 - result.Item3) <= 0.0001f && tuple3.Item2 < result.Item2))
					{
						result = tuple3;
					}
				}
				return result;
			}
		}

		public List<Component> BuildPlanDiscoverAllFixedAnchors(List<Component> allPoints, Vector3 spawnPos, bool skipActivated)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			float realtimeSinceStartup = Time.realtimeSinceStartup;
			List<Component> list2 = new List<Component>();
			if (allPoints == null || allPoints.Count == 0)
			{
				return list2;
			}
			if (spawnPos == Vector3.zero)
			{
				return list2;
			}
			if (!TryGetGlobalAnchorsNoCache(allPoints, spawnPos, out Component firstAnchor, out Component tailAnchor) || (Object)(object)firstAnchor == (Object)null)
			{
				return list2;
			}
			List<Component> list3 = new List<Component>(allPoints.Count);
			for (int i = 0; i < allPoints.Count; i++)
			{
				Component val = allPoints[i];
				if (Object.op_Implicit((Object)(object)val) && !IsCompletedLikeState(ReadStateName(val)) && (!skipActivated || !IsMarkedActivated(val)))
				{
					list3.Add(val);
				}
			}
			if (list3.Count == 0)
			{
				return list2;
			}
			List<(Component, int, float)> list4 = new List<(Component, int, float)>();
			for (int j = 0; j < list3.Count; j++)
			{
				Component val2 = list3[j];
				if (TryGetSpawnPathLength(val2, spawnPos, _spawnPathCache, _spawnPathInvalid, out var length))
				{
					list4.Add((val2, ((Object)val2).GetInstanceID(), length));
				}
			}
			if (list4.Count == 0)
			{
				return list2;
			}
			int globalFirstId = ((Object)firstAnchor).GetInstanceID();
			int globalTailId = (((Object)(object)tailAnchor != (Object)null) ? ((Object)tailAnchor).GetInstanceID() : int.MinValue);
			bool num = list4.Any<(Component, int, float)>(((Component ep, int id, float spawnPath) x) => x.id == globalFirstId);
			bool flag = (Object)(object)tailAnchor != (Object)null && globalTailId != globalFirstId && list4.Any<(Component, int, float)>(((Component ep, int id, float spawnPath) x) => x.id == globalTailId);
			(Component, int, float)? tuple = null;
			if (num)
			{
				tuple = list4.First<(Component, int, float)>(((Component ep, int id, float spawnPath) x) => x.id == globalFirstId);
			}
			else
			{
				List<(Component, int, float)> list5 = (flag ? list4.Where<(Component, int, float)>(((Component ep, int id, float spawnPath) x) => x.id != globalTailId).ToList() : list4);
				if (list5.Count == 0)
				{
					list5 = list4;
				}
				tuple = PickByMinSpawn(list5);
			}
			Component item = tuple.Value.Item1;
			int item2 = tuple.Value.Item2;
			list2.Add(item);
			bool flag2 = flag && globalTailId != item2;
			List<Component> middleCandidates = new List<Component>();
			for (int k = 0; k < list4.Count; k++)
			{
				(Component, int, float) tuple2 = list4[k];
				if (tuple2.Item2 != item2 && (!flag2 || tuple2.Item2 != globalTailId))
				{
					middleCandidates.Add(tuple2.Item1);
				}
			}
			Component tail = (flag2 ? list4.First<(Component, int, float)>(((Component ep, int id, float spawnPath) x) => x.id == globalTailId).Item1 : null);
			List<Component> bestMiddle = null;
			float bestTotal = float.MaxValue;
			bool[] used;
			List<Component> curOrder;
			if (middleCandidates.Count == 0)
			{
				float length2;
				if ((Object)(object)tail == (Object)null)
				{
					bestTotal = 0f;
					bestMiddle = new List<Component>();
				}
				else if (TryGetEdgePathLength(item, tail, _edgePathCache, _edgePathInvalid, out length2))
				{
					bestTotal = length2;
					bestMiddle = new List<Component>();
				}
			}
			else
			{
				used = new bool[middleCandidates.Count];
				curOrder = new List<Component>(middleCandidates.Count);
				Dfs(item, 0f);
			}
			if (bestMiddle == null)
			{
				return new List<Component>();
			}
			for (int l = 0; l < bestMiddle.Count; l++)
			{
				list2.Add(bestMiddle[l]);
			}
			if ((Object)(object)tail != (Object)null)
			{
				list2.Add(tail);
			}
			string.Join(" -> ", from x in list2
				where (Object)(object)x != (Object)null
				select ((Object)x.gameObject).name);
			if ((Object)(object)tail != (Object)null)
			{
				_ = ((Object)tail.gameObject).name;
			}
			_ = Time.realtimeSinceStartup;
			return list2;
			void Dfs(Component prev, float costSoFar)
			{
				if (!(costSoFar > bestTotal + 0.0001f))
				{
					if (curOrder.Count == middleCandidates.Count)
					{
						float num3 = costSoFar;
						if ((Object)(object)tail != (Object)null)
						{
							if (!TryGetEdgePathLength(prev, tail, _edgePathCache, _edgePathInvalid, out var length3))
							{
								return;
							}
							num3 += length3;
						}
						if (num3 + 0.0001f < bestTotal || (Mathf.Abs(num3 - bestTotal) <= 0.0001f && IsBetterSameCostOrder(curOrder, bestMiddle)))
						{
							bestTotal = num3;
							bestMiddle = new List<Component>(curOrder);
						}
					}
					else
					{
						for (int n = 0; n < middleCandidates.Count; n++)
						{
							if (!used[n])
							{
								Component val3 = middleCandidates[n];
								if (TryGetEdgePathLength(prev, val3, _edgePathCache, _edgePathInvalid, out var length4))
								{
									used[n] = true;
									curOrder.Add(val3);
									Dfs(val3, costSoFar + length4);
									curOrder.RemoveAt(curOrder.Count - 1);
									used[n] = false;
								}
							}
						}
					}
				}
			}
			static bool IsBetterSameCostOrder(List<Component> current, List<Component>? best)
			{
				if (best == null)
				{
					return true;
				}
				int num2 = Math.Min(current.Count, best.Count);
				for (int m = 0; m < num2; m++)
				{
					int instanceID = ((Object)current[m]).GetInstanceID();
					int instanceID2 = ((Object)best[m]).GetInstanceID();
					if (instanceID != instanceID2)
					{
						return instanceID < instanceID2;
					}
				}
				return current.Count < best.Count;
			}
			static (Component ep, int id, float spawnPath) PickByMinSpawn(List<(Component ep, int id, float spawnPath)> list)
			{
				(Component, int, float) result = list[0];
				for (int num4 = 1; num4 < list.Count; num4++)
				{
					(Component, int, float) tuple3 = list[num4];
					if (tuple3.Item3 + 0.0001f < result.Item3 || (Mathf.Abs(tuple3.Item3 - result.Item3) <= 0.0001f && tuple3.Item2 < result.Item2))
					{
						result = tuple3;
					}
				}
				return result;
			}
		}

		private static long MakeDirectedKey(int fromId, int toId)
		{
			return (long)(((ulong)(uint)fromId << 32) | (uint)toId);
		}

		private bool TryGetPathLength(Vector3 from, Vector3 to, out float length)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Expected O, but got Unknown
			//IL_0031: 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_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			length = 0f;
			try
			{
				if (!TrySampleNavPoint(from, out var sampled))
				{
					return false;
				}
				if (!TrySampleNavPoint(to, out var sampled2))
				{
					return false;
				}
				NavMeshPath val = new NavMeshPath();
				if (!NavMesh.CalculatePath(sampled, sampled2, -1, val))
				{
					return false;
				}
				if ((int)val.status != 0)
				{
					return false;
				}
				Vector3[] corners = val.corners;
				if (corners == null || corners.Length == 0)
				{
					return false;
				}
				if (corners.Length == 1)
				{
					length = 0f;
					return true;
				}
				float num = 0f;
				for (int i = 1; i < corners.Length; i++)
				{
					num += Vector3.Distance(corners[i - 1], corners[i]);
				}
				length = num;
				return true;
			}
			catch
			{
				return false;
			}
		}

		private static bool TrySampleNavPoint(Vector3 pos, out Vector3 sampled)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: 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)
			sampled = pos;
			NavMeshHit val = default(NavMeshHit);
			if (NavMesh.SamplePosition(pos, ref val, 3f, -1))
			{
				sampled = ((NavMeshHit)(ref val)).position;
				return true;
			}
			if (NavMesh.SamplePosition(pos, ref val, 10f, -1))
			{
				sampled = ((NavMeshHit)(ref val)).position;
				return true;
			}
			return false;
		}

		private bool TryGetSpawnPathLength(Component ep, Vector3 spawnPos, Dictionary<int, float> cache, HashSet<int> invalid, out float length)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			length = 0f;
			if (!Object.op_Implicit((Object)(object)ep))
			{
				return false;
			}
			int instanceID = ((Object)ep).GetInstanceID();
			if (cache.TryGetValue(instanceID, out length))
			{
				return true;
			}
			if (invalid.Contains(instanceID))
			{
				return false;
			}
			if (TryGetPathLength(spawnPos, ep.transform.position, out length))
			{
				cache[instanceID] = length;
				return true;
			}
			invalid.Add(instanceID);
			return false;
		}

		private bool TryGetEdgePathLength(Component from, Component to, Dictionary<long, float> cache, HashSet<long> invalid, out float length)
		{
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			length = 0f;
			if (!Object.op_Implicit((Object)(object)from) || !Object.op_Implicit((Object)(object)to))
			{
				return false;
			}
			int instanceID = ((Object)from).GetInstanceID();
			int instanceID2 = ((Object)to).GetInstanceID();
			if (instanceID == instanceID2)
			{
				length = 0f;
				return true;
			}
			long num = MakeDirectedKey(instanceID, instanceID2);
			if (cache.TryGetValue(num, out length))
			{
				return true;
			}
			if (invalid.Contains(num))
			{
				return false;
			}
			if (TryGetPathLength(from.transform.position, to.transform.position, out length))
			{
				cache[num] = length;
				return true;
			}
			invalid.Add(num);
			return false;
		}
	}
}
namespace REPO_Active.Reflection
{
	public sealed class ExtractionPointInvoker
	{
		public bool InvokeOnClick(Component ep)
		{
			if ((Object)(object)ep == (Object)null)
			{
				return false;
			}
			try
			{
				MethodInfo method = ((object)ep).GetType().GetMethod("OnClick", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (method == null)
				{
					return false;
				}
				object[] parameters = BuildDefaultArgs(method);
				method.Invoke(ep, parameters);
				return true;
			}
			catch (Exception)
			{
				return false;
			}
		}

		private static object[]? BuildDefaultArgs(MethodInfo mi)
		{
			try
			{
				ParameterInfo[] parameters = mi.GetParameters();
				if (parameters == null || parameters.Length == 0)
				{
					return null;
				}
				object[] array = new object[parameters.Length];
				for (int i = 0; i < parameters.Length; i++)
				{
					ParameterInfo parameterInfo = parameters[i];
					if (parameterInfo.HasDefaultValue)
					{
						array[i] = parameterInfo.DefaultValue;
						continue;
					}
					Type type = parameterInfo.ParameterType;
					if (type.IsByRef)
					{
						type = type.GetElementType() ?? type;
					}
					if (!type.IsValueType)
					{
						array[i] = null;
						continue;
					}
					try
					{
						array[i] = Activator.CreateInstance(type);
					}
					catch
					{
						array[i] = null;
					}
				}
				return array;
			}
			catch
			{
				return null;
			}
		}
	}
}