Decompiled source of ExtractionConfirm v1.0.0

plugins/ExtractionConfirm.dll

Decompiled 8 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using ExitGames.Client.Photon;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Photon.Pun;
using Photon.Realtime;
using UnityEngine;
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("ExtractionConfirm")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+6db82c7aedec6d3546a3bf6d75c7a0bba7122f54")]
[assembly: AssemblyProduct("ExtractionConfirm")]
[assembly: AssemblyTitle("ExtractionConfirm")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[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 ExtractionConfirm
{
	internal sealed class ConfirmButton : MonoBehaviour
	{
		private const string VisualName = "Shop Button Visual";

		private static readonly Color LitColor = new Color(1f, 0.5f, 0f);

		private static readonly Color DenyColor = new Color(1f, 0f, 0f, 1f);

		private ExtractionPoint _extractionPoint;

		private StaticGrabObject _grabObject;

		private Transform _visual;

		private Vector3 _baseScale;

		private Material _material;

		private Action _onPress;

		private bool _wasPressed;

		private float _animEval;

		private bool _animating;

		private float _flashTimer;

		public void Setup(ExtractionPoint extractionPoint, Transform head, StaticGrabObject grabObject, Action onPress)
		{
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			_extractionPoint = extractionPoint;
			_grabObject = grabObject;
			_onPress = onPress;
			_visual = FindDeep(head, "Shop Button Visual") ?? head;
			if ((Object)(object)_visual == (Object)null)
			{
				return;
			}
			_baseScale = _visual.localScale;
			MeshRenderer component = ((Component)_visual).GetComponent<MeshRenderer>();
			if ((Object)(object)component != (Object)null)
			{
				_material = ((Renderer)component).material;
				if ((Object)(object)_material != (Object)null && _material.HasProperty("_EmissionColor"))
				{
					_material.SetColor("_EmissionColor", LitColor);
				}
			}
		}

		private static Transform FindDeep(Transform root, string name)
		{
			if ((Object)(object)root == (Object)null)
			{
				return null;
			}
			Transform[] componentsInChildren = ((Component)root).GetComponentsInChildren<Transform>(true);
			foreach (Transform val in componentsInChildren)
			{
				if ((Object)(object)val != (Object)null && ((Object)val).name == name)
				{
					return val;
				}
			}
			return null;
		}

		private void Update()
		{
			if (!((Object)(object)_extractionPoint == (Object)null))
			{
				bool flag = ConfirmGate.IsLocallyGrabbed(_grabObject);
				if (flag && !_wasPressed)
				{
					Press();
				}
				_wasPressed = flag;
				Animate();
				TickFlash();
			}
		}

		private void TickFlash()
		{
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			if (!(_flashTimer <= 0f))
			{
				_flashTimer -= Time.deltaTime;
				if (!(_flashTimer > 0f) && (Object)(object)_material != (Object)null && _material.HasProperty("_EmissionColor"))
				{
					_material.SetColor("_EmissionColor", LitColor);
				}
			}
		}

		public void Flash()
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			_flashTimer = 0.7f;
			if ((Object)(object)_material != (Object)null && _material.HasProperty("_EmissionColor"))
			{
				_material.SetColor("_EmissionColor", DenyColor);
			}
		}

		private void Press()
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			_animEval = 0f;
			_animating = true;
			try
			{
				if (_extractionPoint.soundButton != null)
				{
					_extractionPoint.soundButton.Play(_visual.position, 1f, 1f, 1f, 1f);
				}
			}
			catch
			{
			}
		}

		private void Animate()
		{
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			if (!_animating || (Object)(object)_extractionPoint == (Object)null)
			{
				return;
			}
			_animEval = Mathf.Clamp01(_animEval + Time.deltaTime * 2f);
			AnimationCurve buttonPressAnimationCurve = _extractionPoint.buttonPressAnimationCurve;
			float num = ((buttonPressAnimationCurve != null) ? buttonPressAnimationCurve.Evaluate(_animEval) : _animEval);
			float num2 = Mathf.Lerp(0.1f, num, 0.5f);
			if ((Object)(object)_visual != (Object)null)
			{
				_visual.localScale = new Vector3(_baseScale.x, _baseScale.y * num2, _baseScale.z);
			}
			if ((Object)(object)_material != (Object)null && _material.HasProperty("_EmissionColor"))
			{
				_material.SetColor("_EmissionColor", Color.Lerp(LitColor, Color.white, num));
			}
			if (_animEval >= 1f)
			{
				_animating = false;
				if ((Object)(object)_visual != (Object)null)
				{
					_visual.localScale = _baseScale;
				}
			}
		}
	}
	internal static class ConfirmGate
	{
		private sealed class HoldState
		{
			public bool Confirmed;

			public bool Released;

			public bool TextApplied;

			public float LastConfirmTime = -99f;

			public string TubeTextOriginal;

			public Color TubeColorOriginal;

			public string ButtonHintOriginal;

			public ConfirmButton Button;

			public Transform Anchor;
		}

		public const byte ConfirmEventCode = 177;

		public const byte ValidationEventCode = 178;

		private const float ConfirmDebounce = 0.35f;

		private const string HoldText = "CONFIRM";

		private const string ButtonHint = "Confirm extraction";

		private static readonly Color HoldColor = new Color(1f, 0.5f, 0f);

		private static readonly Vector3 StandPosition = new Vector3(2.08f, 1.03f, 2.03f);

		private static readonly HashSet<string> ReportedErrors = new HashSet<string>();

		private static readonly HashSet<string> ReportedReasons = new HashSet<string>();

		private static readonly Dictionary<ExtractionPoint, HoldState> Holds = new Dictionary<ExtractionPoint, HoldState>();

		private static FieldInfo _currentState;

		private static FieldInfo _isShop;

		private static FieldInfo _shopStation;

		private static FieldInfo _tubeTextString;

		private static FieldInfo _tubeTextColor;

		private static FieldInfo _buttonOriginalMaterial;

		private static FieldInfo _buttonDenyActive;

		private static FieldInfo _buttonDenyLerp;

		private static FieldInfo _haulCurrent;

		private static FieldInfo _roundDirectorInstance;

		private static FieldInfo _roundCurrentHaul;

		private static FieldInfo _grabbedStaticGrabObject;

		private static MethodInfo _tubeScreenTextChange;

		private static MethodInfo _stateSet;

		private static GameObject _standTemplate;

		private static bool _hostSettingKnown;

		private static bool _hostUsesAuto = true;

		private static int _hostAmount;

		private static float _nextValidationPush;

		private static ManualLogSource Log => ExtractionConfirmPlugin.Log;

		private static ConfirmSettings Settings => ExtractionConfirmPlugin.Settings;

		public static bool Resolve(Type extractionPointType)
		{
			try
			{
				_currentState = AccessTools.Field(extractionPointType, "currentState");
				_isShop = AccessTools.Field(extractionPointType, "isShop");
				_shopStation = AccessTools.Field(extractionPointType, "shopStation");
				_tubeTextString = AccessTools.Field(extractionPointType, "tubeScreenTextString");
				_tubeTextColor = AccessTools.Field(extractionPointType, "tubeScreenTextColor");
				_buttonOriginalMaterial = AccessTools.Field(extractionPointType, "buttonOriginalMaterial");
				_buttonDenyActive = AccessTools.Field(extractionPointType, "buttonDenyActive");
				_buttonDenyLerp = AccessTools.Field(extractionPointType, "buttonDenyLerp");
				_haulCurrent = AccessTools.Field(extractionPointType, "haulCurrent");
				_tubeScreenTextChange = AccessTools.Method(extractionPointType, "TubeScreenTextChange", (Type[])null, (Type[])null);
				_stateSet = AccessTools.Method(extractionPointType, "StateSet", new Type[1] { typeof(State) }, (Type[])null);
				Type type = AccessTools.TypeByName("PhysGrabber");
				_grabbedStaticGrabObject = ((type != null) ? AccessTools.Field(type, "grabbedStaticGrabObject") : null);
				Type type2 = AccessTools.TypeByName("RoundDirector");
				if (type2 != null)
				{
					_roundDirectorInstance = AccessTools.Field(type2, "instance");
					_roundCurrentHaul = AccessTools.Field(type2, "currentHaul");
				}
				bool flag = _currentState != null && _isShop != null && _tubeTextString != null && _tubeTextColor != null && _buttonOriginalMaterial != null && _tubeScreenTextChange != null && _grabbedStaticGrabObject != null;
				if (!flag)
				{
					ManualLogSource log = Log;
					if (log != null)
					{
						log.LogError((object)("Missing members: " + $"currentState={_currentState != null}, isShop={_isShop != null}, " + $"tubeScreenTextString={_tubeTextString != null}, " + $"tubeScreenTextColor={_tubeTextColor != null}, " + $"buttonOriginalMaterial={_buttonOriginalMaterial != null}, " + $"TubeScreenTextChange={_tubeScreenTextChange != null}, " + $"PhysGrabber.grabbedStaticGrabObject={_grabbedStaticGrabObject != null}"));
					}
				}
				return flag;
			}
			catch (Exception arg)
			{
				ManualLogSource log2 = Log;
				if (log2 != null)
				{
					log2.LogError((object)$"Failed to resolve game members: {arg}");
				}
				return false;
			}
		}

		public static bool ShouldSkipTransition(ExtractionPoint ep, State newState)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Invalid comparison between Unknown and I4
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Invalid comparison between Unknown and I4
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Invalid comparison between Unknown and I4
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Invalid comparison between Unknown and I4
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Invalid comparison between Unknown and I4
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Invalid comparison between Unknown and I4
			if ((Object)(object)ep == (Object)null || _currentState == null)
			{
				return false;
			}
			HoldState holdState = Get(ep);
			if ((int)newState == 4)
			{
				if (!IsHolding(ep))
				{
					RestoreTubeText(ep, holdState);
					return false;
				}
				if (holdState.Confirmed)
				{
					holdState.Confirmed = false;
					RestoreTubeText(ep, holdState);
					return false;
				}
				ApplyHoldVisuals(ep, holdState);
				return true;
			}
			if ((int)newState == 6 || (int)newState == 7 || (int)newState == 5 || (int)newState == 1 || (int)newState == 9)
			{
				holdState.Confirmed = false;
				RestoreTubeText(ep, holdState);
			}
			return false;
		}

		public static bool HandleButtonPress(ExtractionPoint ep)
		{
			if ((Object)(object)ep == (Object)null || _currentState == null)
			{
				return false;
			}
			if (IsHolding(ep))
			{
				ConfirmExtraction(ep);
				return true;
			}
			if (!IsRequirementMet(ep))
			{
				DenyPress(ep);
			}
			return false;
		}

		public static void ConfirmExtraction(ExtractionPoint ep)
		{
			if ((Object)(object)ep == (Object)null || _currentState == null)
			{
				return;
			}
			HoldState holdState = Get(ep);
			if (Time.time - holdState.LastConfirmTime < 0.35f)
			{
				return;
			}
			holdState.LastConfirmTime = Time.time;
			if (!IsHolding(ep))
			{
				return;
			}
			if (SemiFunc.IsMultiplayer() && SemiFunc.IsNotMasterClient())
			{
				if (RaiseConfirmRequest(ep))
				{
					ManualLogSource log = Log;
					if (log != null)
					{
						log.LogInfo((object)"Confirmation press - requested the countdown from the host");
					}
				}
				else
				{
					holdState.Confirmed = true;
				}
			}
			else
			{
				holdState.Confirmed = true;
				ManualLogSource log2 = Log;
				if (log2 != null)
				{
					log2.LogInfo((object)"Extraction confirmed - countdown starting");
				}
			}
		}

		public static bool IsHolding(ExtractionPoint ep)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Invalid comparison between Unknown and I4
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Invalid comparison between Unknown and I4
			if ((Object)(object)ep == (Object)null || IsShop(ep))
			{
				return false;
			}
			State val = (State)_currentState.GetValue(ep);
			if ((int)val != 3)
			{
				return (int)val == 8;
			}
			return true;
		}

		public static bool IsLocallyGrabbed(StaticGrabObject grabObject)
		{
			try
			{
				PhysGrabber instance = PhysGrabber.instance;
				if ((Object)(object)instance == (Object)null || (Object)(object)grabObject == (Object)null)
				{
					return false;
				}
				return _grabbedStaticGrabObject.GetValue(instance) == grabObject;
			}
			catch
			{
				return false;
			}
		}

		private static bool IsShop(ExtractionPoint ep)
		{
			return (bool)_isShop.GetValue(ep);
		}

		public static void Tick(ExtractionPoint ep)
		{
			if ((Object)(object)ep == (Object)null)
			{
				return;
			}
			HoldState holdState = Get(ep);
			EnsureButton(ep);
			if (!IsHolding(ep))
			{
				if (holdState.Confirmed)
				{
					holdState.Confirmed = false;
				}
				holdState.Released = false;
				RestoreTubeText(ep, holdState);
			}
			else
			{
				ApplyHoldVisuals(ep, holdState);
				ReleaseHold(ep, holdState);
				ArmButton(ep);
				WatchPress(ep, holdState);
			}
		}

		private static void ReleaseHold(ExtractionPoint ep, HoldState hold)
		{
			if (!hold.Confirmed || hold.Released || _stateSet == null)
			{
				return;
			}
			try
			{
				hold.Released = true;
				_stateSet.Invoke(ep, new object[1] { (object)(State)4 });
				if (hold.Confirmed)
				{
					hold.Released = false;
				}
			}
			catch (Exception ex)
			{
				ReportPatchError("ReleaseHold", ex);
				hold.Released = false;
			}
		}

		private static void ArmButton(ExtractionPoint ep)
		{
			try
			{
				StaticGrabObject buttonGrabObject = ep.buttonGrabObject;
				if ((Object)(object)buttonGrabObject != (Object)null && !((Behaviour)buttonGrabObject).enabled)
				{
					((Behaviour)buttonGrabObject).enabled = true;
				}
				if ((Object)(object)ep.buttonLight != (Object)null && !((Behaviour)ep.buttonLight).enabled)
				{
					((Behaviour)ep.buttonLight).enabled = true;
				}
				MeshRenderer button = ep.button;
				object? obj = _buttonOriginalMaterial?.GetValue(ep);
				Material val = (Material)((obj is Material) ? obj : null);
				if ((Object)(object)button != (Object)null && (Object)(object)val != (Object)null && (Object)(object)((Renderer)button).material != (Object)(object)val)
				{
					((Renderer)button).material = val;
				}
			}
			catch (Exception ex)
			{
				ReportPatchError("ArmButton", ex);
			}
		}

		private static void WatchPress(ExtractionPoint ep, HoldState hold)
		{
			if (hold.Confirmed)
			{
				return;
			}
			try
			{
				if (IsLocallyGrabbed(ep.buttonGrabObject))
				{
					ConfirmExtraction(ep);
				}
			}
			catch (Exception ex)
			{
				ReportPatchError("WatchPress", ex);
			}
		}

		public static void Pump()
		{
			if (_currentState == null)
			{
				return;
			}
			ExtractionPoint[] array;
			try
			{
				array = Object.FindObjectsOfType<ExtractionPoint>(true);
			}
			catch (Exception ex)
			{
				ReportPatchError("FindObjectsOfType", ex);
				return;
			}
			ExtractionPoint[] array2 = array;
			foreach (ExtractionPoint val in array2)
			{
				if (!((Object)(object)val == (Object)null))
				{
					EnsureButton(val);
					Tick(val);
				}
			}
			if (SemiFunc.IsMultiplayer() && PhotonNetwork.IsMasterClient)
			{
				PushValidationSetting();
			}
		}

		public static void PreparePoint(ExtractionPoint ep)
		{
			try
			{
				if (!((Object)(object)ep == (Object)null))
				{
					EnsureButton(ep);
				}
			}
			catch (Exception ex)
			{
				ReportPatchError("PreparePoint", ex);
			}
		}

		public static void EnsureButton(ExtractionPoint ep)
		{
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: Expected O, but got Unknown
			//IL_0157: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0160: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			//IL_022c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0231: Unknown result type (might be due to invalid IL or missing references)
			//IL_0250: Unknown result type (might be due to invalid IL or missing references)
			//IL_0252: 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)
			//IL_0264: Unknown result type (might be due to invalid IL or missing references)
			//IL_0205: Unknown result type (might be due to invalid IL or missing references)
			//IL_020f: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)ep == (Object)null)
			{
				return;
			}
			HoldState holdState = Get(ep);
			if ((Object)(object)holdState.Button != (Object)null || SemiFunc.RunIsShop())
			{
				return;
			}
			GameObject val = EnsureStandTemplate(ep);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			try
			{
				GameObject val2 = Object.Instantiate<GameObject>(val, ((Component)ep).transform, false);
				((Object)val2).name = "ExtractionConfirmStand";
				val2.SetActive(true);
				Transform val3 = FindDeep(val2.transform, "Shop Button");
				if ((Object)(object)val3 == (Object)null)
				{
					ManualLogSource log = Log;
					if (log != null)
					{
						log.LogWarning((object)"The shop stand has no 'Shop Button'; keeping the regular button.");
					}
					Object.Destroy((Object)(object)val2);
					return;
				}
				Neutralise(val2.transform);
				Transform val4 = (((Object)(object)ep.button != (Object)null) ? ((Component)ep.button).transform : null);
				if ((Object)(object)val4 == (Object)null)
				{
					ManualLogSource log2 = Log;
					if (log2 != null)
					{
						log2.LogWarning((object)"The extraction point has no button to move; keeping the stand where it spawned.");
					}
					Object.Destroy((Object)(object)val2);
					return;
				}
				Vector3 standPosition = StandPosition;
				if ((Object)(object)holdState.Anchor == (Object)null)
				{
					GameObject val5 = new GameObject("ExtractionConfirmAnchor");
					val5.transform.SetParent(((Component)ep).transform, false);
					val5.transform.localPosition = standPosition - val4.localPosition;
					val5.transform.localRotation = Quaternion.identity;
					holdState.Anchor = val5.transform;
					Transform val6 = (((Object)(object)ep.buttonDenyTransform != (Object)null) ? ep.buttonDenyTransform : val4.parent);
					if ((Object)(object)val6 != (Object)null)
					{
						val6.SetParent(val5.transform, false);
					}
				}
				Vector3 val7 = ((Component)ep).transform.TransformPoint(standPosition);
				if (Vector3.Distance(val4.position, val7) > 0.05f)
				{
					ManualLogSource log3 = Log;
					if (log3 != null)
					{
						log3.LogWarning((object)($"The button did not move to the corner: at {val4.position}, expected {val7}. " + "buttonDenyTransform is probably no longer the button's parent."));
					}
				}
				Vector3 localPosition = val3.localPosition;
				val2.transform.SetParent(((Component)ep).transform, false);
				val2.transform.localPosition = standPosition - localPosition;
				val2.transform.localRotation = Quaternion.identity;
				((Renderer)ep.button).enabled = false;
				ConfirmButton confirmButton = ((Component)val3).gameObject.AddComponent<ConfirmButton>();
				confirmButton.Setup(ep, val3, ep.buttonGrabObject, delegate
				{
					ConfirmExtraction(ep);
				});
				holdState.Button = confirmButton;
			}
			catch (Exception ex)
			{
				ReportPatchError("EnsureButton", ex);
			}
		}

		private static GameObject EnsureStandTemplate(ExtractionPoint ep)
		{
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_standTemplate != (Object)null)
			{
				return _standTemplate;
			}
			object? obj = _shopStation?.GetValue(ep);
			Transform val = (Transform)((obj is Transform) ? obj : null);
			if ((Object)(object)val == (Object)null && (Object)(object)ep != (Object)null)
			{
				val = ((Component)ep).transform.Find("Scale/Shop Station");
			}
			if ((Object)(object)val == (Object)null)
			{
				ReportReason("this extraction point has no Shop Station and none was cached yet");
				return null;
			}
			GameObject obj2 = Object.Instantiate<GameObject>(((Component)val).gameObject);
			((Object)obj2).name = "ExtractionConfirmTemplate";
			obj2.SetActive(false);
			obj2.transform.position = new Vector3(0f, -5000f, 0f);
			Object.DontDestroyOnLoad((Object)(object)obj2);
			_standTemplate = obj2;
			return _standTemplate;
		}

		private static void Neutralise(Transform root)
		{
			Transform[] componentsInChildren = ((Component)root).GetComponentsInChildren<Transform>(true);
			foreach (Transform val in componentsInChildren)
			{
				MonoBehaviour[] components = ((Component)val).GetComponents<MonoBehaviour>();
				for (int j = 0; j < components.Length; j++)
				{
					((Behaviour)components[j]).enabled = false;
				}
				AudioSource[] components2 = ((Component)val).GetComponents<AudioSource>();
				for (int j = 0; j < components2.Length; j++)
				{
					((Behaviour)components2[j]).enabled = false;
				}
			}
		}

		private static Transform FindDeep(Transform root, string name)
		{
			if ((Object)(object)root == (Object)null)
			{
				return null;
			}
			Transform[] componentsInChildren = ((Component)root).GetComponentsInChildren<Transform>(true);
			foreach (Transform val in componentsInChildren)
			{
				if ((Object)(object)val != (Object)null && ((Object)val).name == name)
				{
					return val;
				}
			}
			return null;
		}

		private static void ReportReason(string reason)
		{
			if (ReportedReasons.Add(reason))
			{
				ManualLogSource log = Log;
				if (log != null)
				{
					log.LogWarning((object)("No confirm button: " + reason));
				}
			}
		}

		private static void ApplyHoldVisuals(ExtractionPoint ep, HoldState hold)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			if (hold.TextApplied)
			{
				return;
			}
			try
			{
				hold.TubeTextOriginal = _tubeTextString.GetValue(ep) as string;
				hold.TubeColorOriginal = (Color)_tubeTextColor.GetValue(ep);
				hold.TextApplied = true;
				SetTubeText(ep, "CONFIRM", HoldColor);
				StaticGrabObject buttonGrabObject = ep.buttonGrabObject;
				if ((Object)(object)buttonGrabObject != (Object)null)
				{
					hold.ButtonHintOriginal = buttonGrabObject.hoverText;
					buttonGrabObject.hoverText = "Confirm extraction";
				}
				if (SemiFunc.IsMultiplayer())
				{
					ExtractionConfirmPlugin.Instance?.EnsureNetworkHook();
				}
			}
			catch (Exception ex)
			{
				hold.TextApplied = false;
				ReportPatchError("ApplyHoldVisuals", ex);
			}
		}

		private static void RestoreTubeText(ExtractionPoint ep, HoldState hold)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			if (hold == null || !hold.TextApplied)
			{
				return;
			}
			hold.TextApplied = false;
			try
			{
				if (hold.TubeTextOriginal != null)
				{
					SetTubeText(ep, hold.TubeTextOriginal, hold.TubeColorOriginal);
				}
				if (hold.ButtonHintOriginal != null && (Object)(object)ep.buttonGrabObject != (Object)null)
				{
					ep.buttonGrabObject.hoverText = hold.ButtonHintOriginal;
				}
				hold.ButtonHintOriginal = null;
			}
			catch (Exception ex)
			{
				ReportPatchError("RestoreTubeText", ex);
			}
		}

		private static void SetTubeText(ExtractionPoint ep, string text, Color color)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			_tubeScreenTextChange.Invoke(ep, new object[2]
			{
				text ?? string.Empty,
				color
			});
		}

		private static HoldState Get(ExtractionPoint ep)
		{
			if (Holds.Count > 16)
			{
				PruneDestroyed();
			}
			if (!Holds.TryGetValue(ep, out var value))
			{
				value = new HoldState();
				Holds.Add(ep, value);
			}
			return value;
		}

		private static void PruneDestroyed()
		{
			List<ExtractionPoint> list = null;
			foreach (KeyValuePair<ExtractionPoint, HoldState> hold in Holds)
			{
				if ((Object)(object)hold.Key == (Object)null)
				{
					if (list == null)
					{
						list = new List<ExtractionPoint>();
					}
					list.Add(hold.Key);
				}
			}
			if (list == null)
			{
				return;
			}
			foreach (ExtractionPoint item in list)
			{
				Holds.Remove(item);
			}
		}

		public static int RequiredHaul(ExtractionPoint ep)
		{
			if (_hostSettingKnown && SemiFunc.IsMultiplayer() && !SemiFunc.IsMasterClient())
			{
				if (!_hostUsesAuto)
				{
					return _hostAmount;
				}
				return ep.haulGoal;
			}
			if (Settings.ValidationAuto.Value && Settings.ValidationAmount.Value == 0f)
			{
				return ep.haulGoal;
			}
			return Mathf.Clamp(Mathf.RoundToInt(Settings.ValidationAmount.Value), 0, 100000);
		}

		public static bool IsRequirementMet(ExtractionPoint ep)
		{
			try
			{
				return CurrentHaul(ep) >= RequiredHaul(ep);
			}
			catch (Exception ex)
			{
				ReportPatchError("IsRequirementMet", ex);
				return true;
			}
		}

		private static int CurrentHaul(ExtractionPoint ep)
		{
			if (_haulCurrent != null)
			{
				object value = _haulCurrent.GetValue(ep);
				if (value != null)
				{
					return Convert.ToInt32(value);
				}
			}
			object obj = _roundDirectorInstance?.GetValue(null);
			if (obj != null)
			{
				object obj2 = _roundCurrentHaul?.GetValue(obj);
				if (obj2 != null)
				{
					return Convert.ToInt32(obj2);
				}
			}
			return 0;
		}

		private static void DenyPress(ExtractionPoint ep)
		{
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				_buttonDenyLerp?.SetValue(ep, 0f);
				_buttonDenyActive?.SetValue(ep, true);
				if ((Object)(object)ep.button != (Object)null && (Object)(object)ep.buttonDenyMaterial != (Object)null)
				{
					((Renderer)ep.button).material = ep.buttonDenyMaterial;
				}
				if ((Object)(object)ep.buttonLight != (Object)null)
				{
					((Behaviour)ep.buttonLight).enabled = true;
				}
				if (ep.soundCancel != null)
				{
					ep.soundCancel.Play(((Component)ep).transform.position, 1f, 1f, 1f, 1f);
				}
				HoldState holdState = Get(ep);
				if ((Object)(object)holdState.Button != (Object)null)
				{
					holdState.Button.Flash();
				}
				ManualLogSource log = Log;
				if (log != null)
				{
					log.LogInfo((object)$"Denied: haul {CurrentHaul(ep)} of {RequiredHaul(ep)} required.");
				}
			}
			catch (Exception ex)
			{
				ReportPatchError("DenyPress", ex);
			}
		}

		private static void PushValidationSetting()
		{
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Expected O, but got Unknown
			if (Time.unscaledTime < _nextValidationPush)
			{
				return;
			}
			_nextValidationPush = Time.unscaledTime + 5f;
			try
			{
				bool flag = Settings.ValidationAuto.Value && Settings.ValidationAmount.Value == 0f;
				int num = Mathf.Clamp(Mathf.RoundToInt(Settings.ValidationAmount.Value), 0, 100000);
				_hostUsesAuto = flag;
				_hostAmount = num;
				_hostSettingKnown = true;
				PhotonNetwork.RaiseEvent((byte)178, (object)new object[2]
				{
					flag ? "Auto" : "Fixed",
					num
				}, new RaiseEventOptions(), SendOptions.SendReliable);
			}
			catch (Exception ex)
			{
				ReportPatchError("PushValidationSetting", ex);
			}
		}

		private static void ApplyHostSetting(object[] payload)
		{
			if (payload != null && payload.Length >= 2)
			{
				_hostUsesAuto = Convert.ToString(payload[0]).Trim().Equals("Auto", StringComparison.OrdinalIgnoreCase);
				_hostAmount = Convert.ToInt32(payload[1]);
				_hostSettingKnown = true;
				ManualLogSource log = Log;
				if (log != null)
				{
					log.LogInfo((object)("Using the host's validation setting: " + (_hostUsesAuto ? "Auto" : ("Fixed " + _hostAmount))));
				}
			}
		}

		private static bool RaiseConfirmRequest(ExtractionPoint ep)
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Expected O, but got Unknown
			PhotonView component = ((Component)ep).GetComponent<PhotonView>();
			if ((Object)(object)component == (Object)null)
			{
				ManualLogSource log = Log;
				if (log != null)
				{
					log.LogWarning((object)"Extraction point has no PhotonView; cannot reach the host");
				}
				return false;
			}
			PhotonNetwork.RaiseEvent((byte)177, (object)new object[1] { component.ViewID }, new RaiseEventOptions(), SendOptions.SendReliable);
			return true;
		}

		public static void OnPhotonEvent(EventData eventData)
		{
			try
			{
				if (eventData == null)
				{
					return;
				}
				if (eventData.Code == 178)
				{
					ApplyHostSetting(eventData.CustomData as object[]);
				}
				else
				{
					if (eventData.Code != 177 || !PhotonNetwork.IsMasterClient || !(eventData.CustomData is object[] array) || array.Length < 1)
					{
						return;
					}
					PhotonView val = PhotonView.Find(Convert.ToInt32(array[0]));
					if ((Object)(object)val == (Object)null)
					{
						return;
					}
					ExtractionPoint component = ((Component)val).GetComponent<ExtractionPoint>();
					if (!((Object)(object)component == (Object)null) && IsHolding(component))
					{
						Get(component).Confirmed = true;
						ManualLogSource log = Log;
						if (log != null)
						{
							log.LogInfo((object)"Confirmation received from a player - countdown starting");
						}
					}
				}
			}
			catch (Exception ex)
			{
				ReportPatchError("OnPhotonEvent", ex);
			}
		}

		public static void ReportPatchError(string where, Exception ex)
		{
			if (ReportedErrors.Add(where))
			{
				ManualLogSource log = Log;
				if (log != null)
				{
					log.LogError((object)$"Patch error in {where}: {ex}");
				}
			}
		}
	}
	[BepInPlugin("com.repo.extractionconfirm", "ExtractionConfirm", "1.0.0")]
	[BepInProcess("REPO.exe")]
	public class ExtractionConfirmPlugin : BaseUnityPlugin, IOnEventCallback
	{
		public const string PluginGuid = "com.repo.extractionconfirm";

		public const string PluginName = "ExtractionConfirm";

		public const string PluginVersion = "1.0.0";

		public static ExtractionConfirmPlugin Instance;

		public static ManualLogSource Log;

		public static ConfirmSettings Settings;

		private Harmony _harmony;

		private bool _networkHookInstalled;

		private void Awake()
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Expected O, but got Unknown
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			Settings = new ConfirmSettings(((BaseUnityPlugin)this).Config);
			Log.LogInfo((object)"ExtractionConfirm 1.0.0 loaded");
			try
			{
				_harmony = new Harmony("com.repo.extractionconfirm");
				ApplyPatches(_harmony);
			}
			catch (Exception arg)
			{
				Log.LogError((object)$"Failed to initialise: {arg}");
			}
			try
			{
				ModRunner.Start();
			}
			catch (Exception arg2)
			{
				Log.LogError((object)$"Failed to start the runner: {arg2}");
			}
		}

		private void Update()
		{
			ModRunner.Tick();
		}

		private static void ApplyPatches(Harmony harmony)
		{
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Expected O, but got Unknown
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Expected O, but got Unknown
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0139: Expected O, but got Unknown
			//IL_0175: Unknown result type (might be due to invalid IL or missing references)
			//IL_0182: Expected O, but got Unknown
			//IL_01da: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e7: Expected O, but got Unknown
			Type type = AccessTools.TypeByName("ExtractionPoint");
			if (type == null)
			{
				Log.LogError((object)"ExtractionPoint type not found - ExtractionConfirm is inactive.");
				return;
			}
			if (!ConfirmGate.Resolve(type))
			{
				Log.LogError((object)"ExtractionPoint members missing - ExtractionConfirm is inactive.");
				return;
			}
			MethodInfo methodInfo = AccessTools.Method(type, "StateSet", (Type[])null, (Type[])null);
			if (methodInfo == null)
			{
				Log.LogError((object)"ExtractionPoint.StateSet not found - ExtractionConfirm is inactive.");
				return;
			}
			harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(ExtractionPatches), "StateSetPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			MethodInfo methodInfo2 = AccessTools.Method(type, "OnClick", (Type[])null, (Type[])null);
			MethodInfo methodInfo3 = AccessTools.Method(type, "Start", Type.EmptyTypes, (Type[])null);
			MethodInfo methodInfo4 = AccessTools.Method(type, "Update", Type.EmptyTypes, (Type[])null);
			List<string> list = new List<string> { "ExtractionPoint.StateSet" };
			if (methodInfo2 != null)
			{
				harmony.Patch((MethodBase)methodInfo2, new HarmonyMethod(typeof(ExtractionPatches), "OnClickPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				list.Add("ExtractionPoint.OnClick");
			}
			else
			{
				Log.LogWarning((object)"ExtractionPoint.OnClick not found - a press of the extraction point's own button may not register.");
			}
			if (methodInfo3 != null)
			{
				harmony.Patch((MethodBase)methodInfo3, new HarmonyMethod(typeof(ExtractionPatches), "StartPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				list.Add("ExtractionPoint.Start");
			}
			else
			{
				Log.LogWarning((object)"ExtractionPoint.Start not found - no per-point startup report.");
			}
			if (methodInfo4 != null)
			{
				harmony.Patch((MethodBase)methodInfo4, (HarmonyMethod)null, new HarmonyMethod(typeof(ExtractionPatches), "UpdatePostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				list.Add("ExtractionPoint.Update");
			}
			Type type2 = AccessTools.TypeByName("ChatManager");
			MethodInfo methodInfo5 = ((type2 != null) ? AccessTools.Method(type2, "Update", Type.EmptyTypes, (Type[])null) : null);
			if (methodInfo5 != null)
			{
				harmony.Patch((MethodBase)methodInfo5, (HarmonyMethod)null, new HarmonyMethod(typeof(ExtractionPatches), "ChatUpdatePostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				list.Add("ChatManager.Update");
			}
			else
			{
				Log.LogWarning((object)"ChatManager.Update not found - the mod keeps no per-frame heartbeat.");
			}
			Log.LogInfo((object)("Patched " + string.Join(", ", list.ToArray())));
		}

		internal void EnsureNetworkHook()
		{
			if (!_networkHookInstalled)
			{
				_networkHookInstalled = true;
				PhotonNetwork.AddCallbackTarget((object)this);
			}
		}

		public void OnEvent(EventData eventData)
		{
			try
			{
				ConfirmGate.OnPhotonEvent(eventData);
			}
			catch (Exception ex)
			{
				ConfirmGate.ReportPatchError("OnEvent", ex);
			}
		}
	}
	public class ConfirmSettings
	{
		public readonly ConfigEntry<bool> ValidationAuto;

		public readonly ConfigEntry<float> ValidationAmount;

		public ConfirmSettings(ConfigFile config)
		{
			ValidationAuto = config.Bind<bool>("Validation", "Auto", true, "True validates against the game's own haul goal. False uses Amount instead. Changing Amount turns this off automatically. In multiplayer the host's setting always wins.");
			ValidationAmount = config.Bind<float>("Validation", "Amount", 0f, "Fixed validation target, 0 to 100000. Changing this turns Auto off. Leave it at 0 to keep using the game's target. In multiplayer the host's value is what everyone uses.");
			ValidationAmount.SettingChanged += delegate
			{
				if (ValidationAmount.Value != 0f)
				{
					ValidationAuto.Value = false;
				}
			};
		}
	}
	public static class ExtractionPatches
	{
		public static bool StateSetPrefix(ExtractionPoint __instance, State newState)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				return !ConfirmGate.ShouldSkipTransition(__instance, newState);
			}
			catch (Exception ex)
			{
				ConfirmGate.ReportPatchError("StateSet", ex);
				return true;
			}
		}

		public static bool OnClickPrefix(ExtractionPoint __instance)
		{
			try
			{
				return !ConfirmGate.HandleButtonPress(__instance);
			}
			catch (Exception ex)
			{
				ConfirmGate.ReportPatchError("OnClick", ex);
				return true;
			}
		}

		public static void StartPrefix(ExtractionPoint __instance)
		{
			try
			{
				ConfirmGate.PreparePoint(__instance);
			}
			catch (Exception ex)
			{
				ConfirmGate.ReportPatchError("Start", ex);
			}
		}

		public static void UpdatePostfix(ExtractionPoint __instance)
		{
			try
			{
				ConfirmGate.Tick(__instance);
			}
			catch (Exception ex)
			{
				ConfirmGate.ReportPatchError("Update", ex);
			}
		}

		public static void ChatUpdatePostfix()
		{
			try
			{
				ModRunner.Tick();
			}
			catch (Exception ex)
			{
				ConfirmGate.ReportPatchError("ChatUpdate", ex);
			}
		}
	}
	internal static class ModRunner
	{
		private const float PumpInterval = 0.5f;

		private static bool _subscribed;

		private static float _nextPump;

		public static void Start()
		{
			if (!_subscribed)
			{
				_subscribed = true;
				SceneManager.sceneLoaded += OnSceneLoaded;
			}
		}

		public static void Stop()
		{
			if (_subscribed)
			{
				_subscribed = false;
				SceneManager.sceneLoaded -= OnSceneLoaded;
			}
		}

		private static void OnSceneLoaded(Scene scene, LoadSceneMode mode)
		{
			try
			{
				Pump();
			}
			catch (Exception ex)
			{
				ConfirmGate.ReportPatchError("SceneLoaded", ex);
			}
		}

		public static void Tick()
		{
			if (!(Time.unscaledTime < _nextPump))
			{
				Pump();
			}
		}

		private static void Pump()
		{
			_nextPump = Time.unscaledTime + 0.5f;
			try
			{
				ConfirmGate.Pump();
			}
			catch (Exception ex)
			{
				ConfirmGate.ReportPatchError("ModRunner", ex);
			}
		}
	}
}