Decompiled source of Extraction v0.2.37

plugins/Extraction/DoorLockpickPlus.dll

Decompiled 19 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using GameNetcodeStuff;
using HarmonyLib;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Rendering;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("ScrapVisbility")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ScrapVisbility")]
[assembly: AssemblyCopyright("Copyright ©  2026")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("8a6853bd-bdc9-4741-95c7-5aa2c8c6a6f9")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace DoorLockpickPlus;

[BepInPlugin("YourFurnace.DoorLockpickPlus", "DoorLockpickPlus", "1.3.8")]
public class DoorLockpickPlus : BaseUnityPlugin
{
	private const string modGUID = "YourFurnace.DoorLockpickPlus";

	private const string modName = "DoorLockpickPlus";

	private const string modVersion = "1.3.8";

	private readonly Harmony harmony = new Harmony("YourFurnace.DoorLockpickPlus");

	internal static DoorLockpickPlus Instance;

	internal static ManualLogSource Log;

	internal static ConfigEntry<bool> EnableNormalDoorLockpicking;

	internal static ConfigEntry<bool> EnableBigDoorHacking;

	internal static ConfigEntry<bool> EnableBigDoorInPersonClose;

	internal static ConfigEntry<bool> DebugRollLogging;

	internal static ConfigEntry<bool> EnableLockpickSounds;

	internal static ConfigEntry<float> NormalDoorPickTime;

	internal static ConfigEntry<float> NormalDoorSuccessChance;

	internal static ConfigEntry<float> BigDoorHackTime;

	internal static ConfigEntry<float> BigDoorSuccessChance;

	internal static ConfigEntry<float> BigDoorCloseTime;

	internal static ConfigEntry<float> RetryCooldown;

	internal static ConfigEntry<float> FailFlashTime;

	internal static ConfigEntry<float> LockpickSoundVolume;

	internal static ConfigEntry<float> NormalDoorTriggerWidth;

	internal static ConfigEntry<float> NormalDoorTriggerHeight;

	internal static ConfigEntry<float> NormalDoorTriggerDepth;

	internal static ConfigEntry<float> DoorTintStrength;

	internal static ConfigEntry<float> DoorOverlayAlpha;

	internal static ConfigEntry<float> DoorEmissionStrength;

	internal static ConfigEntry<float> DoorLightStrength;

	internal static ConfigEntry<float> NormalDoorVisualMultiplier;

	internal static ConfigEntry<float> BigDoorVisualMultiplier;

	private float nextScanTime = 0f;

	private void Awake()
	{
		Instance = this;
		Log = ((BaseUnityPlugin)this).Logger;
		EnableNormalDoorLockpicking = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enable normal door lockpicking", true, "Adds a normal Lethal Company E hold prompt to locked normal doors.");
		EnableBigDoorHacking = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enable big door prying", true, "Adds a normal Lethal Company E hold prompt to closed terminal controlled big doors.");
		EnableBigDoorInPersonClose = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enable big door in-person close", true, "Adds a normal Lethal Company E hold prompt to close open terminal controlled big doors.");
		EnableLockpickSounds = ((BaseUnityPlugin)this).Config.Bind<bool>("Audio", "Enable lockpick sounds", true, "Plays the base game lockpicking sound while holding E on a locked normal door.");
		LockpickSoundVolume = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "Lockpick sound volume", 0.75f, "Volume for lockpick, success, and fail sounds.");
		NormalDoorPickTime = ((BaseUnityPlugin)this).Config.Bind<float>("Normal Doors", "Normal door pick time", 10f, "Seconds required to lockpick a normal locked door.");
		NormalDoorSuccessChance = ((BaseUnityPlugin)this).Config.Bind<float>("Normal Doors", "Normal door success chance", 0.5f, "Chance to unlock a normal locked door. 0.50 means 50%.");
		BigDoorHackTime = ((BaseUnityPlugin)this).Config.Bind<float>("Big Doors", "Big door pry time", 25f, "Seconds required to pry open a terminal controlled big door.");
		BigDoorSuccessChance = ((BaseUnityPlugin)this).Config.Bind<float>("Big Doors", "Big door pry success chance", 0.33f, "Chance to pry open a terminal controlled big door. 0.33 means 33%.");
		BigDoorCloseTime = ((BaseUnityPlugin)this).Config.Bind<float>("Big Doors", "Big door close time", 2f, "Seconds required to close an open terminal controlled big door in person. This is always successful.");
		RetryCooldown = ((BaseUnityPlugin)this).Config.Bind<float>("Safety", "Retry cooldown", 2f, "Cooldown after a lockpick or pry attempt finishes. Helps prevent retry race conditions.");
		FailFlashTime = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "Fail flash time", 1.5f, "How long a failed door flashes red.");
		DebugRollLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "Debug roll logging", true, "Logs lockpick and pry rolls to the BepInEx console. Leave this on while playtesting.");
		NormalDoorTriggerWidth = ((BaseUnityPlugin)this).Config.Bind<float>("Trigger Sizes", "Normal door trigger width", 2.25f, "Minimum width of the invisible lockpick interaction trigger on normal doors.");
		NormalDoorTriggerHeight = ((BaseUnityPlugin)this).Config.Bind<float>("Trigger Sizes", "Normal door trigger height", 3.5f, "Minimum height of the invisible lockpick interaction trigger on normal doors.");
		NormalDoorTriggerDepth = ((BaseUnityPlugin)this).Config.Bind<float>("Trigger Sizes", "Normal door trigger depth", 2.25f, "Minimum depth of the invisible lockpick interaction trigger on normal doors.");
		DoorTintStrength = ((BaseUnityPlugin)this).Config.Bind<float>("Door Visuals", "Door tint strength", 0.55f, "How much the real door mesh is tinted while lockpicking or failing. This belongs to DoorLockpickPlus only.");
		DoorOverlayAlpha = ((BaseUnityPlugin)this).Config.Bind<float>("Door Visuals", "Door overlay alpha", 0.18f, "Transparent overlay strength for the door mesh. Lower this if the highlight is too solid.");
		DoorEmissionStrength = ((BaseUnityPlugin)this).Config.Bind<float>("Door Visuals", "Door emission strength", 1.15f, "Emission pushed into the door material while highlighted.");
		DoorLightStrength = ((BaseUnityPlugin)this).Config.Bind<float>("Door Visuals", "Door light strength", 0.55f, "Point light strength while highlighted.");
		NormalDoorVisualMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Door Visuals", "Normal door visual multiplier", 1.35f, "Extra brightness multiplier for normal doors. Raise this if normal doors are too faint.");
		BigDoorVisualMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Door Visuals", "Big door visual multiplier", 0.35f, "Brightness multiplier for big doors. Lower this if big doors are too bright.");
		harmony.PatchAll();
		Log.LogInfo((object)"DoorLockpickPlus 1.3.8 loaded. Scene-safe big door commands and fixed door highlights enabled.");
	}

	private void OnDestroy()
	{
		harmony.UnpatchSelf();
	}

	private void Update()
	{
		if (!(Time.time < nextScanTime))
		{
			nextScanTime = Time.time + 1f;
			AttachToNormalDoors();
			AttachToBigDoors();
		}
	}

	private void AttachToNormalDoors()
	{
		if (EnableNormalDoorLockpicking == null || !EnableNormalDoorLockpicking.Value)
		{
			return;
		}
		DoorLock[] array = Object.FindObjectsOfType<DoorLock>();
		DoorLock[] array2 = array;
		foreach (DoorLock val in array2)
		{
			if (!((Object)(object)val == (Object)null) && (Object)(object)((Component)val).GetComponent<NormalDoorLockpickTarget>() == (Object)null)
			{
				NormalDoorLockpickTarget normalDoorLockpickTarget = ((Component)val).gameObject.AddComponent<NormalDoorLockpickTarget>();
				normalDoorLockpickTarget.Init(val);
			}
		}
	}

	private void AttachToBigDoors()
	{
		if ((EnableBigDoorHacking == null || !EnableBigDoorHacking.Value) && (EnableBigDoorInPersonClose == null || !EnableBigDoorInPersonClose.Value))
		{
			return;
		}
		TerminalAccessibleObject[] array = Object.FindObjectsOfType<TerminalAccessibleObject>();
		TerminalAccessibleObject[] array2 = array;
		foreach (TerminalAccessibleObject val in array2)
		{
			if (!((Object)(object)val == (Object)null) && BigDoorUtil.IsProbablyBigDoor(val) && (Object)(object)((Component)val).GetComponent<BigDoorLockpickTarget>() == (Object)null)
			{
				BigDoorLockpickTarget bigDoorLockpickTarget = ((Component)val).gameObject.AddComponent<BigDoorLockpickTarget>();
				bigDoorLockpickTarget.Init(val);
			}
		}
	}

	internal static void ShowTip(string header, string body, bool warning)
	{
		try
		{
			HUDManager val = Object.FindObjectOfType<HUDManager>();
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			MethodInfo methodInfo = AccessTools.Method(typeof(HUDManager), "DisplayTip", new Type[5]
			{
				typeof(string),
				typeof(string),
				typeof(bool),
				typeof(bool),
				typeof(string)
			}, (Type[])null);
			if (methodInfo != null)
			{
				methodInfo.Invoke(val, new object[5] { header, body, warning, false, "DoorLockpickPlus" });
				return;
			}
			MethodInfo methodInfo2 = AccessTools.Method(typeof(HUDManager), "DisplayTip", (Type[])null, (Type[])null);
			if (methodInfo2 == null)
			{
				return;
			}
			ParameterInfo[] parameters = methodInfo2.GetParameters();
			object[] array = new object[parameters.Length];
			int num = 0;
			for (int i = 0; i < parameters.Length; i++)
			{
				Type parameterType = parameters[i].ParameterType;
				if (parameterType == typeof(string))
				{
					switch (num)
					{
					case 0:
						array[i] = header;
						break;
					case 1:
						array[i] = body;
						break;
					default:
						array[i] = "DoorLockpickPlus";
						break;
					}
					num++;
				}
				else if (parameterType == typeof(bool))
				{
					array[i] = warning;
				}
				else
				{
					array[i] = null;
				}
			}
			methodInfo2.Invoke(val, array);
		}
		catch
		{
		}
	}

	internal static Color YellowHighlight()
	{
		//IL_0015: 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_001d: Unknown result type (might be due to invalid IL or missing references)
		return new Color(1f, 0.78f, 0.08f, 1f);
	}

	internal static Color RedHighlight()
	{
		//IL_0015: 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_001d: Unknown result type (might be due to invalid IL or missing references)
		return new Color(1f, 0.12f, 0.08f, 1f);
	}
}
internal class NormalDoorLockpickTarget : MonoBehaviour
{
	[CompilerGenerated]
	private sealed class <EndOfFrameUnlockGuard>d__21 : IEnumerator<object>, IDisposable, IEnumerator
	{
		private int <>1__state;

		private object <>2__current;

		public NormalDoorLockpickTarget <>4__this;

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

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

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

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

		private bool MoveNext()
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Expected O, but got Unknown
			switch (<>1__state)
			{
			default:
				return false;
			case 0:
				<>1__state = -1;
				break;
			case 1:
				<>1__state = -1;
				<>4__this.MaintainDoorUnlockedState();
				break;
			}
			if (<>4__this.unlockedByThisMod && (Object)(object)<>4__this.door != (Object)null)
			{
				<>2__current = (object)new WaitForEndOfFrame();
				<>1__state = 1;
				return true;
			}
			return false;
		}

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

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

	private DoorLock door;

	private DoorVisualHighlighter highlighter;

	private DoorAudioController audioController;

	private readonly List<InteractTrigger> vanillaTriggers = new List<InteractTrigger>();

	private readonly Dictionary<InteractTrigger, TriggerSnapshot> vanillaSnapshots = new Dictionary<InteractTrigger, TriggerSnapshot>();

	private GameObject customTriggerObject;

	private InteractTrigger customTrigger;

	private float cooldownUntil = 0f;

	private float redFlashUntil = 0f;

	private bool resolvingAttempt = false;

	private bool unlockedByThisMod = false;

	private bool unlockGuardStarted = false;

	private bool unlockMethodsCalled = false;

	private bool wasHoldingLockpick = false;

	public void Init(DoorLock targetDoor)
	{
		//IL_0009: Unknown result type (might be due to invalid IL or missing references)
		//IL_000e: Unknown result type (might be due to invalid IL or missing references)
		//IL_002c: Unknown result type (might be due to invalid IL or missing references)
		door = targetDoor;
		Bounds doorFocusBounds = GetDoorFocusBounds();
		highlighter = ((Component)this).gameObject.AddComponent<DoorVisualHighlighter>();
		highlighter.Init(((Component)this).gameObject, doorFocusBounds, bigDoor: false);
		audioController = ((Component)this).gameObject.AddComponent<DoorAudioController>();
		audioController.Init(door);
		CacheVanillaTriggers();
		CreateCustomTrigger();
	}

	private Bounds GetDoorFocusBounds()
	{
		//IL_0009: Unknown result type (might be due to invalid IL or missing references)
		//IL_000e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0018: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00be: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
		Bounds bounds = default(Bounds);
		((Bounds)(ref bounds))..ctor(((Component)this).transform.position, Vector3.one * 2f);
		bool hasBounds = false;
		if ((Object)(object)door != (Object)null && (Object)(object)door.doorTrigger != (Object)null)
		{
			BoundsUtil.EncapsulateTransformBounds(((Component)door.doorTrigger).transform, ref bounds, ref hasBounds);
		}
		if ((Object)(object)door != (Object)null && (Object)(object)door.doorTriggerB != (Object)null)
		{
			BoundsUtil.EncapsulateTransformBounds(((Component)door.doorTriggerB).transform, ref bounds, ref hasBounds);
		}
		if (!hasBounds)
		{
			bounds = BoundsUtil.GetBounds(((Component)this).gameObject);
			return bounds;
		}
		return bounds;
	}

	private void CacheVanillaTriggers()
	{
		TryAddVanillaTrigger(door.doorTrigger);
		TryAddVanillaTrigger(door.doorTriggerB);
		InteractTrigger[] componentsInChildren = ((Component)door).GetComponentsInChildren<InteractTrigger>(true);
		InteractTrigger[] array = componentsInChildren;
		foreach (InteractTrigger trigger in array)
		{
			TryAddVanillaTrigger(trigger);
		}
	}

	private void TryAddVanillaTrigger(InteractTrigger trigger)
	{
		if (!((Object)(object)trigger == (Object)null) && !vanillaTriggers.Contains(trigger))
		{
			vanillaTriggers.Add(trigger);
			vanillaSnapshots[trigger] = new TriggerSnapshot(trigger);
		}
	}

	private void CreateCustomTrigger()
	{
		//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_000e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0018: Expected O, but got Unknown
		//IL_0025: Unknown result type (might be due to invalid IL or missing references)
		//IL_003b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0067: Unknown result type (might be due to invalid IL or missing references)
		//IL_0088: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00be: Unknown result type (might be due to invalid IL or missing references)
		Bounds doorFocusBounds = GetDoorFocusBounds();
		customTriggerObject = new GameObject("DoorLockpickPlus_NormalDoor_InteractTrigger");
		customTriggerObject.transform.position = ((Bounds)(ref doorFocusBounds)).center;
		customTriggerObject.transform.rotation = Quaternion.identity;
		BoxCollider val = customTriggerObject.AddComponent<BoxCollider>();
		((Collider)val).isTrigger = true;
		val.size = new Vector3(Mathf.Max(DoorLockpickPlus.NormalDoorTriggerWidth.Value, ((Bounds)(ref doorFocusBounds)).size.x + 1f), Mathf.Max(DoorLockpickPlus.NormalDoorTriggerHeight.Value, ((Bounds)(ref doorFocusBounds)).size.y + 0.8f), Mathf.Max(DoorLockpickPlus.NormalDoorTriggerDepth.Value, ((Bounds)(ref doorFocusBounds)).size.z + 1f));
		InteractTriggerUtil.MakeGameObjectARealInteractTrigger(customTriggerObject);
		customTrigger = customTriggerObject.AddComponent<InteractTrigger>();
		InteractTriggerUtil.ConfigureBaseTrigger(customTrigger);
		InteractTriggerUtil.CopyIconFromTriggers(customTrigger, vanillaTriggers);
		InteractTriggerUtil.AddInteractListener(customTrigger, OnDoorInteract);
		customTriggerObject.SetActive(false);
	}

	private void Update()
	{
		//IL_0106: Unknown result type (might be due to invalid IL or missing references)
		//IL_013d: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)door == (Object)null)
		{
			ClearAll();
			return;
		}
		if (unlockedByThisMod)
		{
			StopLockpickLoopIfNeeded();
			MaintainDoorUnlockedState();
			ConfigureUnlockedVanillaTriggers();
			SetCustomTriggerActive(active: false);
			highlighter.Clear();
			return;
		}
		if (!IsLocked())
		{
			StopLockpickLoopIfNeeded();
			ConfigureUnlockedVanillaTriggers();
			SetCustomTriggerActive(active: false);
			highlighter.Clear();
			return;
		}
		DisableVanillaTriggersWhileLocked();
		UpdateCustomTriggerPosition();
		bool flag = Time.time < cooldownUntil;
		bool flag2 = (Object)(object)customTrigger != (Object)null && customTrigger.isBeingHeldByPlayer;
		ConfigureCustomTrigger(flag);
		UpdateLockpickLoop(flag2 && !flag && !resolvingAttempt);
		if (Time.time < redFlashUntil)
		{
			highlighter.Apply(DoorLockpickPlus.RedHighlight(), 1f, enableLight: true, DoorLockpickPlus.NormalDoorVisualMultiplier.Value);
		}
		else if (flag2 || resolvingAttempt)
		{
			highlighter.Apply(DoorLockpickPlus.YellowHighlight(), 1f, enableLight: true, DoorLockpickPlus.NormalDoorVisualMultiplier.Value);
		}
		else
		{
			highlighter.Clear();
		}
	}

	private void LateUpdate()
	{
		if (unlockedByThisMod)
		{
			MaintainDoorUnlockedState();
		}
	}

	[IteratorStateMachine(typeof(<EndOfFrameUnlockGuard>d__21))]
	private IEnumerator EndOfFrameUnlockGuard()
	{
		//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
		return new <EndOfFrameUnlockGuard>d__21(0)
		{
			<>4__this = this
		};
	}

	private void UpdateLockpickLoop(bool shouldPlay)
	{
		if (DoorLockpickPlus.EnableLockpickSounds == null || !DoorLockpickPlus.EnableLockpickSounds.Value)
		{
			StopLockpickLoopIfNeeded();
		}
		else if (shouldPlay)
		{
			if (!wasHoldingLockpick)
			{
				wasHoldingLockpick = true;
				if ((Object)(object)audioController != (Object)null)
				{
					audioController.StartLockpickLoop();
				}
			}
		}
		else
		{
			StopLockpickLoopIfNeeded();
		}
	}

	private void StopLockpickLoopIfNeeded()
	{
		if (wasHoldingLockpick)
		{
			wasHoldingLockpick = false;
			if ((Object)(object)audioController != (Object)null)
			{
				audioController.StopLockpickLoop();
			}
		}
	}

	private void UpdateCustomTriggerPosition()
	{
		//IL_0018: Unknown result type (might be due to invalid IL or missing references)
		//IL_001d: Unknown result type (might be due to invalid IL or missing references)
		//IL_002b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0041: Unknown result type (might be due to invalid IL or missing references)
		//IL_0071: Unknown result type (might be due to invalid IL or missing references)
		//IL_0092: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)customTriggerObject == (Object)null))
		{
			Bounds doorFocusBounds = GetDoorFocusBounds();
			customTriggerObject.transform.position = ((Bounds)(ref doorFocusBounds)).center;
			customTriggerObject.transform.rotation = Quaternion.identity;
			BoxCollider component = customTriggerObject.GetComponent<BoxCollider>();
			if ((Object)(object)component != (Object)null)
			{
				component.size = new Vector3(Mathf.Max(DoorLockpickPlus.NormalDoorTriggerWidth.Value, ((Bounds)(ref doorFocusBounds)).size.x + 1f), Mathf.Max(DoorLockpickPlus.NormalDoorTriggerHeight.Value, ((Bounds)(ref doorFocusBounds)).size.y + 0.8f), Mathf.Max(DoorLockpickPlus.NormalDoorTriggerDepth.Value, ((Bounds)(ref doorFocusBounds)).size.z + 1f));
			}
			InteractTriggerUtil.MakeGameObjectARealInteractTrigger(customTriggerObject);
		}
	}

	private void ConfigureCustomTrigger(bool inCooldown)
	{
		if (!((Object)(object)customTrigger == (Object)null))
		{
			InteractTriggerUtil.ConfigureBaseTrigger(customTrigger);
			customTrigger.interactable = !inCooldown && !resolvingAttempt;
			customTrigger.timeToHold = Mathf.Max(0.1f, DoorLockpickPlus.NormalDoorPickTime.Value);
			customTrigger.hoverTip = (inCooldown ? "Lockpick cooling down..." : "Pick lock");
			customTrigger.holdTip = "Lockpicking...";
			SetCustomTriggerActive(active: true);
		}
	}

	private void SetCustomTriggerActive(bool active)
	{
		if ((Object)(object)customTriggerObject != (Object)null && customTriggerObject.activeSelf != active)
		{
			customTriggerObject.SetActive(active);
		}
	}

	private void DisableVanillaTriggersWhileLocked()
	{
		foreach (InteractTrigger vanillaTrigger in vanillaTriggers)
		{
			if (!((Object)(object)vanillaTrigger == (Object)null))
			{
				vanillaTrigger.interactable = false;
				vanillaTrigger.hoverTip = "Locked";
				vanillaTrigger.holdTip = "Locked";
			}
		}
	}

	private void RestoreVanillaTriggers()
	{
		foreach (KeyValuePair<InteractTrigger, TriggerSnapshot> vanillaSnapshot in vanillaSnapshots)
		{
			if ((Object)(object)vanillaSnapshot.Key != (Object)null)
			{
				vanillaSnapshot.Value.Restore(vanillaSnapshot.Key);
			}
		}
	}

	private void OnDoorInteract(PlayerControllerB player)
	{
		if ((Object)(object)door == (Object)null || (Object)(object)player == (Object)null)
		{
			return;
		}
		StopLockpickLoopIfNeeded();
		if (!IsLocked())
		{
			return;
		}
		if (resolvingAttempt || Time.time < cooldownUntil)
		{
			DoorLockpickPlus.ShowTip("Lockpick", "Wait a moment before trying again.", warning: true);
			return;
		}
		resolvingAttempt = true;
		float num = Mathf.Clamp01(DoorLockpickPlus.NormalDoorSuccessChance.Value);
		float num2 = Random.Range(0f, 1f);
		bool flag = num2 <= num;
		if (DoorLockpickPlus.DebugRollLogging != null && DoorLockpickPlus.DebugRollLogging.Value && DoorLockpickPlus.Log != null)
		{
			DoorLockpickPlus.Log.LogInfo((object)("Normal door lockpick roll: " + num2.ToString("0.000") + " / chance " + num.ToString("0.000") + " / success " + flag));
		}
		if (flag)
		{
			unlockedByThisMod = true;
			unlockMethodsCalled = false;
			CallKeyStyleUnlockOnce();
			MaintainDoorUnlockedState();
			ConfigureUnlockedVanillaTriggers();
			SetCustomTriggerActive(active: false);
			if ((Object)(object)audioController != (Object)null)
			{
				audioController.PlayUnlockSoundOnce();
			}
			if (!unlockGuardStarted)
			{
				unlockGuardStarted = true;
				((MonoBehaviour)this).StartCoroutine(EndOfFrameUnlockGuard());
			}
			DoorLockpickPlus.ShowTip("Lockpick Success", "The door unlocked.", warning: false);
			cooldownUntil = Time.time + 0.5f;
		}
		else
		{
			if ((Object)(object)audioController != (Object)null)
			{
				audioController.PlayFailSoundOnce();
			}
			DoorLockpickPlus.ShowTip("Lockpick Failed", "The lock held. Try again.", warning: true);
			redFlashUntil = Time.time + Mathf.Max(0.1f, DoorLockpickPlus.FailFlashTime.Value);
			cooldownUntil = Time.time + Mathf.Max(0.1f, DoorLockpickPlus.RetryCooldown.Value);
		}
		resolvingAttempt = false;
	}

	private bool IsLocked()
	{
		if ((Object)(object)door == (Object)null)
		{
			return false;
		}
		return door.isLocked;
	}

	private void CallKeyStyleUnlockOnce()
	{
		if (!((Object)(object)door == (Object)null) && !unlockMethodsCalled)
		{
			unlockMethodsCalled = true;
			CallUnlockMethodsOnDoor(door);
			if ((Object)(object)door.twinDoor != (Object)null)
			{
				CallUnlockMethodsOnDoor(door.twinDoor);
			}
		}
	}

	private void CallUnlockMethodsOnDoor(DoorLock targetDoor)
	{
		if (!((Object)(object)targetDoor == (Object)null) && !ReflectionUtil.CallNoArgExact(targetDoor, "UnlockDoorSyncWithServer"))
		{
			ReflectionUtil.CallNoArgExact(targetDoor, "UnlockDoor");
			ReflectionUtil.CallNoArgExact(targetDoor, "UnlockDoorServerRpc");
		}
	}

	private void MaintainDoorUnlockedState()
	{
		MaintainDoorUnlockedStateFor(door);
		if ((Object)(object)door != (Object)null && (Object)(object)door.twinDoor != (Object)null)
		{
			MaintainDoorUnlockedStateFor(door.twinDoor);
		}
	}

	private void MaintainDoorUnlockedStateFor(DoorLock targetDoor)
	{
		if (!((Object)(object)targetDoor == (Object)null))
		{
			targetDoor.isLocked = false;
			targetDoor.isPickingLock = false;
			targetDoor.lockPickTimeLeft = 0f;
			targetDoor.canBeLocked = false;
			if ((Object)(object)targetDoor.doorTrigger != (Object)null)
			{
				targetDoor.doorTrigger.interactable = true;
				targetDoor.doorTrigger.timeToHoldSpeedMultiplier = 1f;
				targetDoor.doorTrigger.timeToHold = targetDoor.defaultTimeToHold;
			}
			if ((Object)(object)targetDoor.doorTriggerB != (Object)null)
			{
				targetDoor.doorTriggerB.interactable = true;
				targetDoor.doorTriggerB.timeToHoldSpeedMultiplier = 1f;
				targetDoor.doorTriggerB.timeToHold = targetDoor.defaultTimeToHold;
			}
		}
	}

	private void ConfigureUnlockedVanillaTriggers()
	{
		ConfigureUnlockedVanillaTriggersFor(door);
		if ((Object)(object)door != (Object)null && (Object)(object)door.twinDoor != (Object)null)
		{
			ConfigureUnlockedVanillaTriggersFor(door.twinDoor);
		}
	}

	private void ConfigureUnlockedVanillaTriggersFor(DoorLock targetDoor)
	{
		if (!((Object)(object)targetDoor == (Object)null))
		{
			if ((Object)(object)targetDoor.doorTrigger != (Object)null)
			{
				targetDoor.doorTrigger.interactable = true;
				targetDoor.doorTrigger.oneHandedItemAllowed = true;
				targetDoor.doorTrigger.twoHandedItemAllowed = true;
				targetDoor.doorTrigger.timeToHoldSpeedMultiplier = 1f;
				targetDoor.doorTrigger.timeToHold = targetDoor.defaultTimeToHold;
			}
			if ((Object)(object)targetDoor.doorTriggerB != (Object)null)
			{
				targetDoor.doorTriggerB.interactable = true;
				targetDoor.doorTriggerB.oneHandedItemAllowed = true;
				targetDoor.doorTriggerB.twoHandedItemAllowed = true;
				targetDoor.doorTriggerB.timeToHoldSpeedMultiplier = 1f;
				targetDoor.doorTriggerB.timeToHold = targetDoor.defaultTimeToHold;
			}
		}
	}

	private void ClearAll()
	{
		StopLockpickLoopIfNeeded();
		RestoreVanillaTriggers();
		if ((Object)(object)customTriggerObject != (Object)null)
		{
			Object.Destroy((Object)(object)customTriggerObject);
			customTriggerObject = null;
		}
		if ((Object)(object)highlighter != (Object)null)
		{
			highlighter.Clear();
		}
	}

	private void OnDestroy()
	{
		ClearAll();
	}
}
internal class BigDoorLockpickTarget : MonoBehaviour
{
	[CompilerGenerated]
	private sealed class <ExecuteBigDoorCommand>d__20 : IEnumerator<object>, IDisposable, IEnumerator
	{
		private int <>1__state;

		private object <>2__current;

		public bool targetOpen;

		public BigDoorLockpickTarget <>4__this;

		private bool <beforeOpen>5__1;

		private bool <afterTerminal>5__2;

		private bool <actualOpen>5__3;

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

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

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

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

		private bool MoveNext()
		{
			//IL_0224: Unknown result type (might be due to invalid IL or missing references)
			//IL_022e: Expected O, but got Unknown
			//IL_0294: Unknown result type (might be due to invalid IL or missing references)
			//IL_029e: Expected O, but got Unknown
			//IL_0188: Unknown result type (might be due to invalid IL or missing references)
			//IL_0192: Expected O, but got Unknown
			switch (<>1__state)
			{
			default:
				return false;
			case 0:
				<>1__state = -1;
				if ((Object)(object)<>4__this.bigDoor == (Object)null)
				{
					<>4__this.resolvingAttempt = false;
					return false;
				}
				<beforeOpen>5__1 = BigDoorUtil.IsOpen(<>4__this.bigDoor);
				if (<beforeOpen>5__1 == targetOpen)
				{
					if (targetOpen)
					{
						DoorLockpickPlus.ShowTip("Big Door", "The big door is already open.", warning: false);
					}
					else
					{
						DoorLockpickPlus.ShowTip("Big Door", "The big door is already closed.", warning: false);
					}
					<>4__this.cooldownUntil = Time.time + 0.5f;
					<>4__this.resolvingAttempt = false;
					return false;
				}
				if (DoorLockpickPlus.DebugRollLogging != null && DoorLockpickPlus.DebugRollLogging.Value && DoorLockpickPlus.Log != null)
				{
					DoorLockpickPlus.Log.LogInfo((object)("Big door command start. targetOpen=" + targetOpen + " beforeOpen=" + <beforeOpen>5__1 + " code=" + BigDoorUtil.GetObjectCode(<>4__this.bigDoor)));
				}
				BigDoorUtil.ClearCooldown(<>4__this.bigDoor);
				BigDoorUtil.SendTerminalCommand(<>4__this.bigDoor);
				<>2__current = (object)new WaitForSeconds(0.35f);
				<>1__state = 1;
				return true;
			case 1:
				<>1__state = -1;
				if ((Object)(object)<>4__this.bigDoor == (Object)null)
				{
					<>4__this.resolvingAttempt = false;
					return false;
				}
				<afterTerminal>5__2 = BigDoorUtil.IsOpen(<>4__this.bigDoor);
				if (<afterTerminal>5__2 != targetOpen)
				{
					BigDoorUtil.ClearCooldown(<>4__this.bigDoor);
					BigDoorUtil.ForceSetOpen(<>4__this.bigDoor, targetOpen);
					<>2__current = (object)new WaitForSeconds(0.2f);
					<>1__state = 2;
					return true;
				}
				goto IL_023f;
			case 2:
				<>1__state = -1;
				goto IL_023f;
			case 3:
				{
					<>1__state = -1;
					break;
				}
				IL_023f:
				if ((Object)(object)<>4__this.bigDoor != (Object)null && BigDoorUtil.IsOpen(<>4__this.bigDoor) != targetOpen)
				{
					BigDoorUtil.ForceSetOpen(<>4__this.bigDoor, targetOpen);
					<>2__current = (object)new WaitForSeconds(0.1f);
					<>1__state = 3;
					return true;
				}
				break;
			}
			<actualOpen>5__3 = (Object)(object)<>4__this.bigDoor != (Object)null && BigDoorUtil.IsOpen(<>4__this.bigDoor);
			if (DoorLockpickPlus.DebugRollLogging != null && DoorLockpickPlus.DebugRollLogging.Value && DoorLockpickPlus.Log != null)
			{
				DoorLockpickPlus.Log.LogInfo((object)("Big door command end. targetOpen=" + targetOpen + " actualOpen=" + <actualOpen>5__3));
			}
			if (<actualOpen>5__3 == targetOpen)
			{
				if (targetOpen)
				{
					DoorLockpickPlus.ShowTip("Pry Success", "The big door opened.", warning: false);
				}
				else
				{
					DoorLockpickPlus.ShowTip("Big Door Closed", "The big door closed.", warning: false);
				}
			}
			else
			{
				DoorLockpickPlus.ShowTip("Door Command Failed", "The command ran but the door did not reach the expected state.", warning: true);
			}
			<>4__this.cooldownUntil = Time.time + 0.5f;
			<>4__this.resolvingAttempt = false;
			return false;
		}

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

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

	private TerminalAccessibleObject bigDoor;

	private DoorVisualHighlighter highlighter;

	private readonly List<InteractTrigger> triggers = new List<InteractTrigger>();

	private readonly List<GameObject> triggerObjects = new List<GameObject>();

	private float cooldownUntil = 0f;

	private float redFlashUntil = 0f;

	private bool resolvingAttempt = false;

	private float nextTriggerRefreshTime = 0f;

	private int lastBoundsSignature = 0;

	public void Init(TerminalAccessibleObject targetDoor)
	{
		//IL_000e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0013: Unknown result type (might be due to invalid IL or missing references)
		//IL_0031: Unknown result type (might be due to invalid IL or missing references)
		bigDoor = targetDoor;
		Bounds bounds = BoundsUtil.GetBounds(((Component)this).gameObject);
		highlighter = ((Component)this).gameObject.AddComponent<DoorVisualHighlighter>();
		highlighter.Init(((Component)this).gameObject, bounds, bigDoor: true);
		RebuildSurfaceTriggers();
	}

	private void Update()
	{
		//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
		//IL_010c: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)bigDoor == (Object)null || (Object)(object)((Component)bigDoor).gameObject == (Object)null)
		{
			Clear();
			return;
		}
		if (!((Component)bigDoor).gameObject.activeInHierarchy)
		{
			Clear();
			return;
		}
		if (Time.time >= nextTriggerRefreshTime)
		{
			nextTriggerRefreshTime = Time.time + 0.75f;
			RebuildSurfaceTriggersIfNeeded();
		}
		bool isOpen = BigDoorUtil.IsOpen(bigDoor);
		bool inCooldown = Time.time < cooldownUntil;
		bool flag = AnyTriggerHeld();
		UpdateTriggerTransforms();
		ConfigureTriggers(isOpen, inCooldown);
		if (Time.time < redFlashUntil)
		{
			highlighter.Apply(DoorLockpickPlus.RedHighlight(), 1f, enableLight: true, DoorLockpickPlus.BigDoorVisualMultiplier.Value);
		}
		else if (flag || resolvingAttempt)
		{
			highlighter.Apply(DoorLockpickPlus.YellowHighlight(), 1f, enableLight: true, DoorLockpickPlus.BigDoorVisualMultiplier.Value);
		}
		else
		{
			highlighter.Clear();
		}
	}

	private bool AnyTriggerHeld()
	{
		for (int i = 0; i < triggers.Count; i++)
		{
			if ((Object)(object)triggers[i] != (Object)null && triggers[i].isBeingHeldByPlayer)
			{
				return true;
			}
		}
		return false;
	}

	private void RebuildSurfaceTriggersIfNeeded()
	{
		//IL_0023: Unknown result type (might be due to invalid IL or missing references)
		List<Bounds> individualVisualBounds = BoundsUtil.GetIndividualVisualBounds(((Component)this).gameObject, bigDoor: true);
		if (individualVisualBounds.Count == 0)
		{
			individualVisualBounds.Add(BoundsUtil.GetBounds(((Component)this).gameObject));
		}
		int num = Mathf.Clamp(individualVisualBounds.Count, 1, 8);
		int boundsSignature = GetBoundsSignature(individualVisualBounds, num);
		if (num != triggerObjects.Count || boundsSignature != lastBoundsSignature)
		{
			RebuildSurfaceTriggers();
		}
	}

	private int GetBoundsSignature(List<Bounds> boundsList, int count)
	{
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0022: 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_005c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0079: Unknown result type (might be due to invalid IL or missing references)
		//IL_0096: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
		int num = 17;
		num = num * 31 + count;
		for (int i = 0; i < count && i < boundsList.Count; i++)
		{
			Bounds val = boundsList[i];
			num = num * 31 + Mathf.RoundToInt(((Bounds)(ref val)).center.x * 10f);
			num = num * 31 + Mathf.RoundToInt(((Bounds)(ref val)).center.y * 10f);
			num = num * 31 + Mathf.RoundToInt(((Bounds)(ref val)).center.z * 10f);
			num = num * 31 + Mathf.RoundToInt(((Bounds)(ref val)).size.x * 10f);
			num = num * 31 + Mathf.RoundToInt(((Bounds)(ref val)).size.y * 10f);
			num = num * 31 + Mathf.RoundToInt(((Bounds)(ref val)).size.z * 10f);
		}
		return num;
	}

	private void RebuildSurfaceTriggers()
	{
		//IL_0053: Unknown result type (might be due to invalid IL or missing references)
		//IL_0087: Unknown result type (might be due to invalid IL or missing references)
		DestroyTriggers();
		if (!((Object)(object)bigDoor == (Object)null) && !((Object)(object)((Component)bigDoor).gameObject == (Object)null))
		{
			List<Bounds> individualVisualBounds = BoundsUtil.GetIndividualVisualBounds(((Component)this).gameObject, bigDoor: true);
			if (individualVisualBounds.Count == 0)
			{
				individualVisualBounds.Add(BoundsUtil.GetBounds(((Component)this).gameObject));
			}
			int num = Mathf.Clamp(individualVisualBounds.Count, 1, 8);
			lastBoundsSignature = GetBoundsSignature(individualVisualBounds, num);
			for (int i = 0; i < num; i++)
			{
				CreateSurfaceTrigger(i, individualVisualBounds[i]);
			}
			UpdateTriggerTransforms();
		}
	}

	private void CreateSurfaceTrigger(int index, Bounds bounds)
	{
		//IL_0012: Unknown result type (might be due to invalid IL or missing references)
		//IL_0018: Expected O, but got Unknown
		//IL_0053: Unknown result type (might be due to invalid IL or missing references)
		GameObject val = new GameObject("DoorLockpickPlus_BigDoor_SurfaceTrigger_" + index);
		if ((Object)(object)bigDoor != (Object)null)
		{
			val.transform.SetParent(((Component)bigDoor).transform, true);
		}
		BoxCollider val2 = val.AddComponent<BoxCollider>();
		((Collider)val2).isTrigger = true;
		ConfigureSurfaceBox(val2, bounds);
		InteractTriggerUtil.MakeGameObjectARealInteractTrigger(val);
		InteractTrigger val3 = val.AddComponent<InteractTrigger>();
		InteractTriggerUtil.ConfigureBaseTrigger(val3);
		InteractTriggerUtil.CopyIconFromScene(val3);
		InteractTriggerUtil.AddInteractListener(val3, OnBigDoorInteract);
		triggerObjects.Add(val);
		triggers.Add(val3);
	}

	private void UpdateTriggerTransforms()
	{
		//IL_004f: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
		//IL_0100: Unknown result type (might be due to invalid IL or missing references)
		//IL_0129: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)bigDoor == (Object)null || (Object)(object)((Component)bigDoor).gameObject == (Object)null)
		{
			return;
		}
		List<Bounds> individualVisualBounds = BoundsUtil.GetIndividualVisualBounds(((Component)this).gameObject, bigDoor: true);
		if (individualVisualBounds.Count == 0)
		{
			individualVisualBounds.Add(BoundsUtil.GetBounds(((Component)this).gameObject));
		}
		int num = Mathf.Min(triggerObjects.Count, individualVisualBounds.Count);
		for (int i = 0; i < num; i++)
		{
			GameObject val = triggerObjects[i];
			if (!((Object)(object)val == (Object)null))
			{
				if ((Object)(object)val.transform.parent != (Object)(object)((Component)bigDoor).transform)
				{
					val.transform.SetParent(((Component)bigDoor).transform, true);
				}
				Transform transform = val.transform;
				Bounds val2 = individualVisualBounds[i];
				transform.position = ((Bounds)(ref val2)).center;
				val.transform.rotation = Quaternion.identity;
				BoxCollider component = val.GetComponent<BoxCollider>();
				if ((Object)(object)component != (Object)null)
				{
					ConfigureSurfaceBox(component, individualVisualBounds[i]);
				}
				InteractTriggerUtil.MakeGameObjectARealInteractTrigger(val);
			}
		}
	}

	private void ConfigureSurfaceBox(BoxCollider box, Bounds bounds)
	{
		//IL_0011: Unknown result type (might be due to invalid IL or missing references)
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		//IL_001e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0035: Unknown result type (might be due to invalid IL or missing references)
		//IL_004c: Unknown result type (might be due to invalid IL or missing references)
		//IL_005d: 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)
		if (!((Object)(object)box == (Object)null))
		{
			Vector3 size = ((Bounds)(ref bounds)).size;
			size.x = Mathf.Max(0.6f, size.x);
			size.y = Mathf.Max(1.2f, size.y);
			size.z = Mathf.Max(0.45f, size.z);
			box.center = Vector3.zero;
			box.size = size;
		}
	}

	private void ConfigureTriggers(bool isOpen, bool inCooldown)
	{
		bool flag = false;
		float timeToHold = 1f;
		string hoverTip = "";
		string holdTip = "";
		if (isOpen && DoorLockpickPlus.EnableBigDoorInPersonClose.Value)
		{
			flag = true;
			timeToHold = Mathf.Max(0.1f, DoorLockpickPlus.BigDoorCloseTime.Value);
			hoverTip = (inCooldown ? "Door controls cooling down..." : "Close big door");
			holdTip = "Closing door...";
		}
		else if (!isOpen && DoorLockpickPlus.EnableBigDoorHacking.Value)
		{
			flag = true;
			timeToHold = Mathf.Max(0.1f, DoorLockpickPlus.BigDoorHackTime.Value);
			hoverTip = (inCooldown ? "Pry attempt cooling down..." : "Pry open big door");
			holdTip = "Attempting to pry open...";
		}
		for (int i = 0; i < triggers.Count; i++)
		{
			InteractTrigger val = triggers[i];
			if (!((Object)(object)val == (Object)null))
			{
				InteractTriggerUtil.ConfigureBaseTrigger(val);
				val.interactable = flag && !inCooldown && !resolvingAttempt;
				val.timeToHold = timeToHold;
				val.hoverTip = hoverTip;
				val.holdTip = holdTip;
			}
		}
	}

	private void OnBigDoorInteract(PlayerControllerB player)
	{
		if ((Object)(object)bigDoor == (Object)null || (Object)(object)player == (Object)null)
		{
			resolvingAttempt = false;
			return;
		}
		if (resolvingAttempt || Time.time < cooldownUntil)
		{
			DoorLockpickPlus.ShowTip("Door Controls", "Wait a moment before trying again.", warning: true);
			return;
		}
		resolvingAttempt = true;
		bool flag = BigDoorUtil.IsOpen(bigDoor);
		if (DoorLockpickPlus.DebugRollLogging != null && DoorLockpickPlus.DebugRollLogging.Value && DoorLockpickPlus.Log != null)
		{
			DoorLockpickPlus.Log.LogInfo((object)("Big door interact on " + ((Object)bigDoor).name + " / current open " + flag));
		}
		if (flag)
		{
			((MonoBehaviour)this).StartCoroutine(ExecuteBigDoorCommand(targetOpen: false));
			return;
		}
		float num = Mathf.Clamp01(DoorLockpickPlus.BigDoorSuccessChance.Value);
		float num2 = Random.Range(0f, 1f);
		bool flag2 = num2 <= num;
		if (DoorLockpickPlus.DebugRollLogging != null && DoorLockpickPlus.DebugRollLogging.Value && DoorLockpickPlus.Log != null)
		{
			DoorLockpickPlus.Log.LogInfo((object)("Big door pry roll: " + num2.ToString("0.000") + " / chance " + num.ToString("0.000") + " / success " + flag2));
		}
		if (flag2)
		{
			((MonoBehaviour)this).StartCoroutine(ExecuteBigDoorCommand(targetOpen: true));
			return;
		}
		DoorLockpickPlus.ShowTip("Pry Failed", "You failed to pry it open. Try again.", warning: true);
		redFlashUntil = Time.time + Mathf.Max(0.1f, DoorLockpickPlus.FailFlashTime.Value);
		cooldownUntil = Time.time + Mathf.Max(0.1f, DoorLockpickPlus.RetryCooldown.Value);
		resolvingAttempt = false;
	}

	[IteratorStateMachine(typeof(<ExecuteBigDoorCommand>d__20))]
	private IEnumerator ExecuteBigDoorCommand(bool targetOpen)
	{
		//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
		return new <ExecuteBigDoorCommand>d__20(0)
		{
			<>4__this = this,
			targetOpen = targetOpen
		};
	}

	private void DestroyTriggers()
	{
		for (int i = 0; i < triggerObjects.Count; i++)
		{
			if ((Object)(object)triggerObjects[i] != (Object)null)
			{
				Object.Destroy((Object)(object)triggerObjects[i]);
			}
		}
		triggerObjects.Clear();
		triggers.Clear();
	}

	private void Clear()
	{
		resolvingAttempt = false;
		if ((Object)(object)highlighter != (Object)null)
		{
			highlighter.Clear();
		}
		DestroyTriggers();
	}

	private void OnDisable()
	{
		resolvingAttempt = false;
		DestroyTriggers();
	}

	private void OnDestroy()
	{
		Clear();
	}
}
internal class DoorAudioController : MonoBehaviour
{
	private DoorLock door;

	private AudioSource source;

	private AudioClip pickingClip;

	private AudioClip unlockClip;

	private AudioClip failClip;

	public void Init(DoorLock targetDoor)
	{
		door = targetDoor;
		source = ((Component)this).gameObject.GetComponent<AudioSource>();
		if ((Object)(object)source == (Object)null)
		{
			source = ((Component)this).gameObject.AddComponent<AudioSource>();
		}
		source.playOnAwake = false;
		source.loop = false;
		source.spatialBlend = 1f;
		source.rolloffMode = (AudioRolloffMode)1;
		source.minDistance = 1f;
		source.maxDistance = 18f;
		source.dopplerLevel = 0f;
		source.spatialize = false;
		pickingClip = AudioUtil.GetAudioClip(door, new string[3] { "pickingLockSFX", "pickLockSFX", "lockpickSFX" });
		unlockClip = AudioUtil.GetAudioClip(door, new string[3] { "unlockSFX", "unlockDoorSFX", "doorUnlockSFX" });
		failClip = AudioUtil.GetAudioClip(door, new string[3] { "doorLockSFX", "lockedDoorSFX", "lockSFX" });
	}

	public void StartLockpickLoop()
	{
		if (!((Object)(object)source == (Object)null) && !((Object)(object)pickingClip == (Object)null))
		{
			float volume = ((DoorLockpickPlus.LockpickSoundVolume != null) ? Mathf.Clamp01(DoorLockpickPlus.LockpickSoundVolume.Value) : 0.75f);
			if (source.isPlaying && (Object)(object)source.clip == (Object)(object)pickingClip && source.loop)
			{
				source.volume = volume;
				return;
			}
			source.Stop();
			source.clip = pickingClip;
			source.loop = true;
			source.volume = volume;
			source.Play();
		}
	}

	public void StopLockpickLoop()
	{
		if (!((Object)(object)source == (Object)null) && (Object)(object)source.clip == (Object)(object)pickingClip && source.loop)
		{
			source.Stop();
			source.loop = false;
			source.clip = null;
		}
	}

	public void PlayUnlockSoundOnce()
	{
		StopLockpickLoop();
		PlayOneShotClean(unlockClip);
	}

	public void PlayFailSoundOnce()
	{
		StopLockpickLoop();
		PlayOneShotClean(failClip);
	}

	private void PlayOneShotClean(AudioClip clip)
	{
		if (!((Object)(object)source == (Object)null) && !((Object)(object)clip == (Object)null))
		{
			float num = ((DoorLockpickPlus.LockpickSoundVolume != null) ? Mathf.Clamp01(DoorLockpickPlus.LockpickSoundVolume.Value) : 0.75f);
			source.loop = false;
			source.clip = null;
			source.Stop();
			source.PlayOneShot(clip, num);
		}
	}

	private void OnDestroy()
	{
		if ((Object)(object)source != (Object)null)
		{
			source.Stop();
		}
	}
}
internal class DoorVisualHighlighter : MonoBehaviour
{
	private readonly List<Renderer> renderers = new List<Renderer>();

	private readonly Dictionary<Renderer, MaterialPropertyBlock> blocks = new Dictionary<Renderer, MaterialPropertyBlock>();

	private readonly List<GameObject> overlayObjects = new List<GameObject>();

	private readonly List<Material> overlayMaterials = new List<Material>();

	private GameObject lightObject;

	private Light lightSource;

	private bool isBigDoor;

	public void Init(GameObject root, Bounds focusBounds, bool bigDoor)
	{
		//IL_000a: Unknown result type (might be due to invalid IL or missing references)
		isBigDoor = bigDoor;
		CacheRenderers(root, focusBounds, bigDoor);
		CreateOverlayMeshes();
		CreateLight();
		if (DoorLockpickPlus.Log != null)
		{
			string text = (((Object)(object)root != (Object)null) ? ((Object)root).name : "null");
			DoorLockpickPlus.Log.LogInfo((object)("DoorLockpickPlus visual renderers for " + text + ": " + renderers.Count));
		}
	}

	private void CacheRenderers(GameObject root, Bounds focusBounds, bool bigDoor)
	{
		//IL_0037: Unknown result type (might be due to invalid IL or missing references)
		//IL_0070: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
		//IL_011a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0124: Expected O, but got Unknown
		renderers.Clear();
		blocks.Clear();
		if ((Object)(object)root == (Object)null)
		{
			return;
		}
		List<Renderer> list = new List<Renderer>();
		CollectRendererCandidates(root.transform, focusBounds, bigDoor, list);
		if (!bigDoor && list.Count == 0 && (Object)(object)root.transform.parent != (Object)null)
		{
			CollectRendererCandidates(root.transform.parent, focusBounds, bigDoor, list);
		}
		if (!bigDoor && list.Count == 0 && (Object)(object)root.transform.parent != (Object)null && (Object)(object)root.transform.parent.parent != (Object)null)
		{
			CollectRendererCandidates(root.transform.parent.parent, focusBounds, bigDoor, list);
		}
		for (int i = 0; i < list.Count; i++)
		{
			Renderer val = list[i];
			if (!((Object)(object)val == (Object)null) && !renderers.Contains(val))
			{
				renderers.Add(val);
				blocks[val] = new MaterialPropertyBlock();
			}
		}
	}

	private void CollectRendererCandidates(Transform root, Bounds focusBounds, bool bigDoor, List<Renderer> output)
	{
		//IL_0024: Unknown result type (might be due to invalid IL or missing references)
		//IL_0025: Unknown result type (might be due to invalid IL or missing references)
		//IL_0072: Unknown result type (might be due to invalid IL or missing references)
		//IL_0088: Unknown result type (might be due to invalid IL or missing references)
		//IL_008d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0091: Unknown result type (might be due to invalid IL or missing references)
		//IL_0098: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)root == (Object)null || output == null)
		{
			return;
		}
		Renderer[] componentsInChildren = ((Component)root).GetComponentsInChildren<Renderer>(true);
		Bounds val = focusBounds;
		((Bounds)(ref val)).Expand(bigDoor ? 4f : 5f);
		Renderer[] array = componentsInChildren;
		foreach (Renderer val2 in array)
		{
			if (!RendererUtil.IsVisibleDoorRenderer(val2, bigDoor))
			{
				continue;
			}
			if (!bigDoor && !((Bounds)(ref val)).Intersects(val2.bounds))
			{
				Bounds bounds = val2.bounds;
				float num = Vector3.Distance(((Bounds)(ref bounds)).center, ((Bounds)(ref focusBounds)).center);
				if (num > 5.5f)
				{
					continue;
				}
			}
			if (!output.Contains(val2))
			{
				output.Add(val2);
			}
		}
	}

	private void CreateOverlayMeshes()
	{
		foreach (Renderer renderer in renderers)
		{
			if ((Object)(object)renderer == (Object)null)
			{
				continue;
			}
			MeshFilter component = ((Component)renderer).GetComponent<MeshFilter>();
			if ((Object)(object)component != (Object)null && (Object)(object)component.sharedMesh != (Object)null)
			{
				CreateMeshOverlay(renderer, component.sharedMesh);
				continue;
			}
			SkinnedMeshRenderer val = (SkinnedMeshRenderer)(object)((renderer is SkinnedMeshRenderer) ? renderer : null);
			if ((Object)(object)val != (Object)null && (Object)(object)val.sharedMesh != (Object)null)
			{
				CreateSkinnedMeshOverlay(val);
			}
		}
	}

	private void CreateMeshOverlay(Renderer originalRenderer, Mesh mesh)
	{
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_000c: Expected O, but got Unknown
		//IL_0025: Unknown result type (might be due to invalid IL or missing references)
		//IL_0036: Unknown result type (might be due to invalid IL or missing references)
		//IL_0047: Unknown result type (might be due to invalid IL or missing references)
		//IL_0051: Unknown result type (might be due to invalid IL or missing references)
		//IL_0085: Unknown result type (might be due to invalid IL or missing references)
		GameObject val = new GameObject("DoorLockpickPlus_OverlayMesh");
		val.transform.SetParent(((Component)originalRenderer).transform, false);
		val.transform.localPosition = Vector3.zero;
		val.transform.localRotation = Quaternion.identity;
		val.transform.localScale = Vector3.one * 1.006f;
		val.layer = ((Component)originalRenderer).gameObject.layer;
		MeshFilter val2 = val.AddComponent<MeshFilter>();
		val2.sharedMesh = mesh;
		MeshRenderer val3 = val.AddComponent<MeshRenderer>();
		Material item = (((Renderer)val3).sharedMaterial = CreateOverlayMaterial(Color.clear));
		((Renderer)val3).shadowCastingMode = (ShadowCastingMode)0;
		((Renderer)val3).receiveShadows = false;
		((Renderer)val3).enabled = false;
		overlayObjects.Add(val);
		overlayMaterials.Add(item);
	}

	private void CreateSkinnedMeshOverlay(SkinnedMeshRenderer originalRenderer)
	{
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_000c: Expected O, but got Unknown
		//IL_0025: Unknown result type (might be due to invalid IL or missing references)
		//IL_0036: Unknown result type (might be due to invalid IL or missing references)
		//IL_0047: Unknown result type (might be due to invalid IL or missing references)
		//IL_0051: Unknown result type (might be due to invalid IL or missing references)
		//IL_009d: Unknown result type (might be due to invalid IL or missing references)
		GameObject val = new GameObject("DoorLockpickPlus_OverlaySkinnedMesh");
		val.transform.SetParent(((Component)originalRenderer).transform, false);
		val.transform.localPosition = Vector3.zero;
		val.transform.localRotation = Quaternion.identity;
		val.transform.localScale = Vector3.one * 1.006f;
		val.layer = ((Component)originalRenderer).gameObject.layer;
		SkinnedMeshRenderer val2 = val.AddComponent<SkinnedMeshRenderer>();
		val2.sharedMesh = originalRenderer.sharedMesh;
		val2.bones = originalRenderer.bones;
		val2.rootBone = originalRenderer.rootBone;
		Material item = (((Renderer)val2).sharedMaterial = CreateOverlayMaterial(Color.clear));
		((Renderer)val2).shadowCastingMode = (ShadowCastingMode)0;
		((Renderer)val2).receiveShadows = false;
		((Renderer)val2).enabled = false;
		overlayObjects.Add(val);
		overlayMaterials.Add(item);
	}

	private Material CreateOverlayMaterial(Color color)
	{
		//IL_0057: Unknown result type (might be due to invalid IL or missing references)
		//IL_005d: Expected O, but got Unknown
		//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
		Shader val = Shader.Find("Sprites/Default");
		if ((Object)(object)val == (Object)null)
		{
			val = Shader.Find("Particles/Standard Unlit");
		}
		if ((Object)(object)val == (Object)null)
		{
			val = Shader.Find("Unlit/Color");
		}
		if ((Object)(object)val == (Object)null)
		{
			val = Shader.Find("Standard");
		}
		Material val2 = new Material(val);
		((Object)val2).name = "DoorLockpickPlus_OverlayMaterial";
		val2.renderQueue = 3100;
		if (val2.HasProperty("_SrcBlend"))
		{
			val2.SetInt("_SrcBlend", 5);
		}
		if (val2.HasProperty("_DstBlend"))
		{
			val2.SetInt("_DstBlend", 10);
		}
		if (val2.HasProperty("_ZWrite"))
		{
			val2.SetInt("_ZWrite", 0);
		}
		if (val2.HasProperty("_Cull"))
		{
			val2.SetInt("_Cull", 0);
		}
		SetMaterialColor(val2, color, 1f);
		return val2;
	}

	private void CreateLight()
	{
		//IL_0007: Unknown result type (might be due to invalid IL or missing references)
		//IL_0011: Expected O, but got Unknown
		//IL_0034: Unknown result type (might be due to invalid IL or missing references)
		lightObject = new GameObject("DoorLockpickPlus_HighlightLight");
		lightObject.transform.SetParent(((Component)this).transform, false);
		lightObject.transform.localPosition = Vector3.zero;
		lightSource = lightObject.AddComponent<Light>();
		lightSource.type = (LightType)2;
		lightSource.range = 4f;
		lightSource.intensity = 0f;
		lightSource.shadows = (LightShadows)0;
		lightSource.renderMode = (LightRenderMode)1;
		((Behaviour)lightSource).enabled = false;
	}

	public void Apply(Color color, float strength, bool enableLight, float multiplier)
	{
		//IL_0091: 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_00a0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
		//IL_0103: Unknown result type (might be due to invalid IL or missing references)
		//IL_0112: Unknown result type (might be due to invalid IL or missing references)
		//IL_0121: Unknown result type (might be due to invalid IL or missing references)
		//IL_0130: Unknown result type (might be due to invalid IL or missing references)
		//IL_0160: Unknown result type (might be due to invalid IL or missing references)
		//IL_0161: Unknown result type (might be due to invalid IL or missing references)
		//IL_0234: Unknown result type (might be due to invalid IL or missing references)
		//IL_0239: Unknown result type (might be due to invalid IL or missing references)
		//IL_0248: Unknown result type (might be due to invalid IL or missing references)
		//IL_0259: Unknown result type (might be due to invalid IL or missing references)
		//IL_0268: Unknown result type (might be due to invalid IL or missing references)
		//IL_026d: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
		float num = ((DoorLockpickPlus.DoorTintStrength != null) ? Mathf.Clamp01(DoorLockpickPlus.DoorTintStrength.Value) : 0.55f);
		float num2 = ((DoorLockpickPlus.DoorOverlayAlpha != null) ? Mathf.Clamp01(DoorLockpickPlus.DoorOverlayAlpha.Value) : 0.18f);
		float num3 = ((DoorLockpickPlus.DoorEmissionStrength != null) ? Mathf.Max(0f, DoorLockpickPlus.DoorEmissionStrength.Value) : 1.15f);
		float num4 = ((DoorLockpickPlus.DoorLightStrength != null) ? Mathf.Max(0f, DoorLockpickPlus.DoorLightStrength.Value) : 0.55f);
		float num5 = Mathf.Max(0f, multiplier);
		Color val = Color.Lerp(Color.white, color, num * num5);
		Color val2 = color * num3 * strength * num5;
		foreach (Renderer renderer in renderers)
		{
			if (!((Object)(object)renderer == (Object)null))
			{
				MaterialPropertyBlock val3 = blocks[renderer];
				renderer.GetPropertyBlock(val3);
				val3.SetColor("_Color", val);
				val3.SetColor("_BaseColor", val);
				val3.SetColor("_EmissionColor", val2);
				val3.SetColor("_EmissiveColor", val2);
				renderer.SetPropertyBlock(val3);
			}
		}
		Color color2 = color;
		color2.a = num2 * num5;
		for (int i = 0; i < overlayObjects.Count; i++)
		{
			GameObject val4 = overlayObjects[i];
			if (!((Object)(object)val4 == (Object)null))
			{
				Renderer component = val4.GetComponent<Renderer>();
				if ((Object)(object)component != (Object)null)
				{
					component.enabled = true;
				}
				if (i < overlayMaterials.Count && (Object)(object)overlayMaterials[i] != (Object)null)
				{
					SetMaterialColor(overlayMaterials[i], color2, num5);
				}
			}
		}
		if ((Object)(object)lightSource != (Object)null)
		{
			Bounds acceptedRendererBounds = GetAcceptedRendererBounds();
			((Component)lightSource).transform.position = ((Bounds)(ref acceptedRendererBounds)).center;
			lightSource.color = color;
			Light obj = lightSource;
			Vector3 extents = ((Bounds)(ref acceptedRendererBounds)).extents;
			obj.range = Mathf.Clamp(((Vector3)(ref extents)).magnitude * (isBigDoor ? 0.75f : 1.05f), 1.5f, isBigDoor ? 5.5f : 7f);
			lightSource.intensity = (enableLight ? Mathf.Clamp(num4 * strength * num5, 0f, isBigDoor ? 1.2f : 2.5f) : 0f);
			((Behaviour)lightSource).enabled = enableLight && renderers.Count > 0;
		}
	}

	public void Clear()
	{
		foreach (Renderer renderer in renderers)
		{
			if (!((Object)(object)renderer == (Object)null))
			{
				renderer.SetPropertyBlock((MaterialPropertyBlock)null);
			}
		}
		for (int i = 0; i < overlayObjects.Count; i++)
		{
			GameObject val = overlayObjects[i];
			if (!((Object)(object)val == (Object)null))
			{
				Renderer component = val.GetComponent<Renderer>();
				if ((Object)(object)component != (Object)null)
				{
					component.enabled = false;
				}
			}
		}
		if ((Object)(object)lightSource != (Object)null)
		{
			((Behaviour)lightSource).enabled = false;
			lightSource.intensity = 0f;
		}
	}

	private Bounds GetAcceptedRendererBounds()
	{
		//IL_0009: Unknown result type (might be due to invalid IL or missing references)
		//IL_000e: Unknown result type (might be due to invalid IL or missing references)
		//IL_007c: Unknown result type (might be due to invalid IL or missing references)
		//IL_007d: 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_0057: Unknown result type (might be due to invalid IL or missing references)
		//IL_0048: Unknown result type (might be due to invalid IL or missing references)
		//IL_004d: Unknown result type (might be due to invalid IL or missing references)
		Bounds bounds = default(Bounds);
		((Bounds)(ref bounds))..ctor(((Component)this).transform.position, Vector3.one);
		bool flag = false;
		for (int i = 0; i < renderers.Count; i++)
		{
			Renderer val = renderers[i];
			if (!((Object)(object)val == (Object)null))
			{
				if (!flag)
				{
					bounds = val.bounds;
					flag = true;
				}
				else
				{
					((Bounds)(ref bounds)).Encapsulate(val.bounds);
				}
			}
		}
		return bounds;
	}

	private void SetMaterialColor(Material mat, Color color, float multiplier)
	{
		//IL_0025: Unknown result type (might be due to invalid IL or missing references)
		//IL_0043: Unknown result type (might be due to invalid IL or missing references)
		//IL_0061: 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)
		if (!((Object)(object)mat == (Object)null))
		{
			if (mat.HasProperty("_Color"))
			{
				mat.SetColor("_Color", color);
			}
			if (mat.HasProperty("_BaseColor"))
			{
				mat.SetColor("_BaseColor", color);
			}
			if (mat.HasProperty("_EmissionColor"))
			{
				mat.SetColor("_EmissionColor", color * (1f + multiplier));
			}
		}
	}

	private void OnDestroy()
	{
		Clear();
		for (int i = 0; i < overlayObjects.Count; i++)
		{
			if ((Object)(object)overlayObjects[i] != (Object)null)
			{
				Object.Destroy((Object)(object)overlayObjects[i]);
			}
		}
		overlayObjects.Clear();
		for (int j = 0; j < overlayMaterials.Count; j++)
		{
			if ((Object)(object)overlayMaterials[j] != (Object)null)
			{
				Object.Destroy((Object)(object)overlayMaterials[j]);
			}
		}
		overlayMaterials.Clear();
		if ((Object)(object)lightObject != (Object)null)
		{
			Object.Destroy((Object)(object)lightObject);
			lightObject = null;
		}
	}
}
internal class TriggerSnapshot
{
	private readonly string hoverTip;

	private readonly string holdTip;

	private readonly bool interactable;

	private readonly bool holdInteraction;

	private readonly float timeToHold;

	private readonly float timeToHoldSpeedMultiplier;

	private readonly bool oneHandedItemAllowed;

	private readonly bool twoHandedItemAllowed;

	private readonly bool interactCooldown;

	private readonly float cooldownTime;

	private readonly bool triggerOnce;

	public TriggerSnapshot(InteractTrigger trigger)
	{
		hoverTip = trigger.hoverTip;
		holdTip = trigger.holdTip;
		interactable = trigger.interactable;
		holdInteraction = trigger.holdInteraction;
		timeToHold = trigger.timeToHold;
		timeToHoldSpeedMultiplier = trigger.timeToHoldSpeedMultiplier;
		oneHandedItemAllowed = trigger.oneHandedItemAllowed;
		twoHandedItemAllowed = trigger.twoHandedItemAllowed;
		interactCooldown = trigger.interactCooldown;
		cooldownTime = trigger.cooldownTime;
		triggerOnce = trigger.triggerOnce;
	}

	public void Restore(InteractTrigger trigger)
	{
		trigger.hoverTip = hoverTip;
		trigger.holdTip = holdTip;
		trigger.interactable = interactable;
		trigger.holdInteraction = holdInteraction;
		trigger.timeToHold = timeToHold;
		trigger.timeToHoldSpeedMultiplier = timeToHoldSpeedMultiplier;
		trigger.oneHandedItemAllowed = oneHandedItemAllowed;
		trigger.twoHandedItemAllowed = twoHandedItemAllowed;
		trigger.interactCooldown = interactCooldown;
		trigger.cooldownTime = cooldownTime;
		trigger.triggerOnce = triggerOnce;
	}
}
internal static class InteractTriggerUtil
{
	private static readonly FieldInfo onInteractField = AccessTools.Field(typeof(InteractTrigger), "onInteract");

	private static readonly FieldInfo onInteractEarlyField = AccessTools.Field(typeof(InteractTrigger), "onInteractEarly");

	private static readonly FieldInfo onStopInteractField = AccessTools.Field(typeof(InteractTrigger), "onStopInteract");

	private static readonly FieldInfo holdingInteractEventField = AccessTools.Field(typeof(InteractTrigger), "holdingInteractEvent");

	private static readonly FieldInfo onCancelAnimationField = AccessTools.Field(typeof(InteractTrigger), "onCancelAnimation");

	public static void MakeGameObjectARealInteractTrigger(GameObject obj)
	{
		if (!((Object)(object)obj == (Object)null))
		{
			TrySetTag(obj, "InteractTrigger");
			obj.layer = LayerUtil.InteractableLayer();
			Collider component = obj.GetComponent<Collider>();
			if ((Object)(object)component != (Object)null)
			{
				component.isTrigger = true;
			}
			Renderer component2 = obj.GetComponent<Renderer>();
			if ((Object)(object)component2 != (Object)null)
			{
				component2.enabled = false;
			}
		}
	}

	private static void TrySetTag(GameObject obj, string tag)
	{
		try
		{
			obj.tag = tag;
		}
		catch
		{
		}
	}

	public static void ConfigureBaseTrigger(InteractTrigger trigger)
	{
		if (!((Object)(object)trigger == (Object)null))
		{
			MakeGameObjectARealInteractTrigger(((Component)trigger).gameObject);
			trigger.interactable = true;
			trigger.oneHandedItemAllowed = true;
			trigger.twoHandedItemAllowed = true;
			trigger.holdInteraction = true;
			trigger.timeToHoldSpeedMultiplier = 1f;
			trigger.interactCooldown = true;
			trigger.cooldownTime = 0.5f;
			trigger.triggerOnce = false;
			trigger.stopAnimationString = "SA_stopAnimation";
			trigger.animationWaitTime = 2f;
			trigger.lockPlayerPosition = true;
			trigger.disableTriggerMesh = true;
			EnsureEventObject(trigger, onInteractField);
			EnsureEventObject(trigger, onInteractEarlyField);
			EnsureEventObject(trigger, onStopInteractField);
			EnsureEventObject(trigger, holdingInteractEventField);
			EnsureEventObject(trigger, onCancelAnimationField);
			CopyIconFromScene(trigger);
		}
	}

	public static void CopyIconFromTriggers(InteractTrigger target, List<InteractTrigger> templates)
	{
		if ((Object)(object)target == (Object)null)
		{
			return;
		}
		if (templates != null)
		{
			for (int i = 0; i < templates.Count; i++)
			{
				InteractTrigger val = templates[i];
				if (!((Object)(object)val == (Object)null) && !((Object)(object)val == (Object)(object)target))
				{
					if ((Object)(object)val.hoverIcon != (Object)null)
					{
						target.hoverIcon = val.hoverIcon;
					}
					if ((Object)(object)val.disabledHoverIcon != (Object)null)
					{
						target.disabledHoverIcon = val.disabledHoverIcon;
					}
					if ((Object)(object)target.hoverIcon != (Object)null)
					{
						return;
					}
				}
			}
		}
		CopyIconFromScene(target);
	}

	public static void CopyIconFromScene(InteractTrigger target)
	{
		if ((Object)(object)target == (Object)null || (Object)(object)target.hoverIcon != (Object)null)
		{
			return;
		}
		InteractTrigger[] array = Object.FindObjectsOfType<InteractTrigger>();
		foreach (InteractTrigger val in array)
		{
			if (!((Object)(object)val == (Object)null) && !((Object)(object)val == (Object)(object)target) && (Object)(object)val.hoverIcon != (Object)null)
			{
				target.hoverIcon = val.hoverIcon;
				target.disabledHoverIcon = (((Object)(object)val.disabledHoverIcon != (Object)null) ? val.disabledHoverIcon : val.hoverIcon);
				break;
			}
		}
	}

	private static object EnsureEventObject(InteractTrigger trigger, FieldInfo field)
	{
		try
		{
			if ((Object)(object)trigger == (Object)null || field == null)
			{
				return null;
			}
			object obj = field.GetValue(trigger);
			if (obj == null)
			{
				obj = Activator.CreateInstance(field.FieldType);
				field.SetValue(trigger, obj);
			}
			return obj;
		}
		catch
		{
			return null;
		}
	}

	public static void AddInteractListener(InteractTrigger trigger, Action<PlayerControllerB> callback)
	{
		try
		{
			if ((Object)(object)trigger == (Object)null || callback == null || onInteractField == null)
			{
				return;
			}
			object obj = EnsureEventObject(trigger, onInteractField);
			if (obj == null)
			{
				return;
			}
			UnityAction<PlayerControllerB> val = callback.Invoke;
			MethodInfo method = obj.GetType().GetMethod("AddListener", new Type[1] { typeof(UnityAction<PlayerControllerB>) });
			if (method != null)
			{
				method.Invoke(obj, new object[1] { val });
				return;
			}
			MethodInfo[] methods = obj.GetType().GetMethods();
			foreach (MethodInfo methodInfo in methods)
			{
				if (!(methodInfo.Name != "AddListener"))
				{
					ParameterInfo[] parameters = methodInfo.GetParameters();
					if (parameters.Length == 1)
					{
						methodInfo.Invoke(obj, new object[1] { val });
						break;
					}
				}
			}
		}
		catch (Exception ex)
		{
			if (DoorLockpickPlus.Log != null)
			{
				DoorLockpickPlus.Log.LogWarning((object)("Failed to add InteractTrigger listener: " + ex.Message));
			}
		}
	}
}
internal static class BigDoorUtil
{
	public static bool IsProbablyBigDoor(TerminalAccessibleObject obj)
	{
		if ((Object)(object)obj == (Object)null)
		{
			return false;
		}
		if (obj.isBigDoor)
		{
			return true;
		}
		string text = ((Object)((Component)obj).gameObject).name.ToLowerInvariant();
		if (text.Contains("bigdoor") || text.Contains("big door"))
		{
			return true;
		}
		Transform parent = ((Component)obj).transform.parent;
		while ((Object)(object)parent != (Object)null)
		{
			string text2 = ((Object)parent).name.ToLowerInvariant();
			if (text2.Contains("bigdoor") || text2.Contains("big door"))
			{
				return true;
			}
			parent = parent.parent;
		}
		return false;
	}

	public static bool IsOpen(TerminalAccessibleObject obj)
	{
		if ((Object)(object)obj == (Object)null)
		{
			return false;
		}
		return ReflectionUtil.GetBoolFieldExact(obj, "isDoorOpen");
	}

	public static string GetObjectCode(TerminalAccessibleObject obj)
	{
		if ((Object)(object)obj == (Object)null)
		{
			return "";
		}
		try
		{
			if (!string.IsNullOrEmpty(obj.objectCode))
			{
				return obj.objectCode;
			}
		}
		catch
		{
		}
		return "";
	}

	public static void ClearCooldown(TerminalAccessibleObject obj)
	{
		if (!((Object)(object)obj == (Object)null))
		{
			ReflectionUtil.SetBoolFieldExact(obj, "inCooldown", value: false);
			ReflectionUtil.SetFloatFieldExact(obj, "currentCooldownTimer", 0f);
		}
	}

	public static void SendTerminalCommand(TerminalAccessibleObject obj)
	{
		if (!((Object)(object)obj == (Object)null))
		{
			ClearCooldown(obj);
			ReflectionUtil.CallNoArgExact(obj, "CallFunctionFromTerminal");
		}
	}

	public static void ForceSetOpen(TerminalAccessibleObject obj, bool open)
	{
		if (!((Object)(object)obj == (Object)null))
		{
			ClearCooldown(obj);
			ReflectionUtil.SetBoolFieldExact(obj, "isDoorOpen", open);
			ReflectionUtil.CallBoolArgExact(obj, "SetDoorOpen", open);
			ReflectionUtil.CallBoolArgExact(obj, "SetDoorLocalClient", open);
			ReflectionUtil.CallBoolArgExact(obj, "SetDoorOpenClientRpc", open);
			ReflectionUtil.CallBoolArgExact(obj, "SetDoorOpenServerRpc", open);
			ReflectionUtil.SetBoolFieldExact(obj, "isDoorOpen", open);
		}
	}
}
internal static class AudioUtil
{
	public static AudioClip GetAudioClip(object instance, string[] fieldNames)
	{
		if (instance == null || fieldNames == null)
		{
			return null;
		}
		for (int i = 0; i < fieldNames.Length; i++)
		{
			AudioClip fieldValueExact = ReflectionUtil.GetFieldValueExact<AudioClip>(instance, fieldNames[i]);
			if ((Object)(object)fieldValueExact != (Object)null)
			{
				return fieldValueExact;
			}
		}
		return null;
	}
}
internal static class RendererUtil
{
	public static bool IsVisibleDoorRenderer(Renderer renderer, bool bigDoor)
	{
		//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)renderer == (Object)null)
		{
			return false;
		}
		if (!renderer.enabled || !((Component)renderer).gameObject.activeInHierarchy)
		{
			return false;
		}
		string lowerName = ((Object)((Component)renderer).gameObject).name.ToLowerInvariant();
		string text = GetPath(((Component)renderer).transform).ToLowerInvariant();
		string text2 = ((object)renderer).GetType().Name.ToLowerInvariant();
		if (text2.Contains("particle") || text2.Contains("line") || text2.Contains("trail"))
		{
			return false;
		}
		if (ShouldSkipVisualName(lowerName) || ShouldSkipVisualName(text))
		{
			return false;
		}
		Bounds bounds = renderer.bounds;
		Vector3 size = ((Bounds)(ref bounds)).size;
		if (((Vector3)(ref size)).sqrMagnitude <= 0.0001f)
		{
			return false;
		}
		MeshFilter component = ((Component)renderer).GetComponent<MeshFilter>();
		SkinnedMeshRenderer val = (SkinnedMeshRenderer)(object)((renderer is SkinnedMeshRenderer) ? renderer : null);
		if (((Object)(object)component == (Object)null || (Object)(object)component.sharedMesh == (Object)null) && ((Object)(object)val == (Object)null || (Object)(object)val.sharedMesh == (Object)null))
		{
			return false;
		}
		if (bigDoor && (text.Contains("doorcode") || text.Contains("map") || text.Contains("screen") || text.Contains("ui")))
		{
			return false;
		}
		return true;
	}

	private static bool ShouldSkipVisualName(string lowerName)
	{
		if (string.IsNullOrEmpty(lowerName))
		{
			return false;
		}
		return lowerName.Contains("trigger") || lowerName.Contains("collider") || lowerName.Contains("collision") || lowerName.Contains("hitbox") || lowerName.Contains("lockpickplus") || lowerName.Contains("interact") || lowerName.Contains("scan") || lowerName.Contains("node") || lowerName.Contains("radar") || lowerName.Contains("code") || lowerName.Contains("ui") || lowerName.Contains("audio") || lowerName.Contains("light") || lowerName.Contains("particle") || lowerName.Contains("spark") || lowerName.Contains("nav") || lowerName.Contains("bounds");
	}

	private static string GetPath(Transform transform)
	{
		if ((Object)(object)transform == (Object)null)
		{
			return "";
		}
		string text = ((Object)transform).name;
		Transform parent = transform.parent;
		int num = 0;
		while ((Object)(object)parent != (Object)null && num < 12)
		{
			text = ((Object)parent).name + "/" + text;
			parent = parent.parent;
			num++;
		}
		return text;
	}
}
internal static class LayerUtil
{
	public static int InteractableLayer()
	{
		int num = LayerMask.NameToLayer("InteractableObject");
		if (num >= 0)
		{
			return num;
		}
		num = LayerMask.NameToLayer("Interactable");
		if (num >= 0)
		{
			return num;
		}
		return 0;
	}
}
internal static class BoundsUtil
{
	public static Bounds GetBounds(GameObject root)
	{
		//IL_002d: 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_000f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0014: Unknown result type (might be due to invalid IL or missing references)
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		//IL_001e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0175: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
		//IL_0095: Unknown result type (might be due to invalid IL or missing references)
		//IL_0085: Unknown result type (might be due to invalid IL or missing references)
		//IL_008a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0158: Unknown result type (might be due to invalid IL or missing references)
		//IL_015d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0167: Unknown result type (might be due to invalid IL or missing references)
		//IL_016c: 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_014d: Unknown result type (might be due to invalid IL or missing references)
		//IL_014e: Unknown result type (might be due to invalid IL or missing references)
		//IL_012a: Unknown result type (might be due to invalid IL or missing references)
		//IL_011a: Unknown result type (might be due to invalid IL or missing references)
		//IL_011f: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)root == (Object)null)
		{
			return new Bounds(Vector3.zero, Vector3.one);
		}
		Bounds bounds = default(Bounds);
		((Bounds)(ref bounds))..ctor(root.transform.position, Vector3.one);
		bool flag = false;
		Renderer[] componentsInChildren = root.GetComponentsInChildren<Renderer>(true);
		Renderer[] array = componentsInChildren;
		foreach (Renderer val in array)
		{
			if (RendererUtil.IsVisibleDoorRenderer(val, bigDoor: true) || RendererUtil.IsVisibleDoorRenderer(val, bigDoor: false))
			{
				if (!flag)
				{
					bounds = val.bounds;
					flag = true;
				}
				else
				{
					((Bounds)(ref bounds)).Encapsulate(val.bounds);
				}
			}
		}
		if (flag)
		{
			return bounds;
		}
		Collider[] componentsInChildren2 = root.GetComponentsInChildren<Collider>(true);
		Collider[] array2 = componentsInChildren2;
		foreach (Collider val2 in array2)
		{
			if ((Object)(object)val2 == (Object)null)
			{
				continue;
			}
			string lowerName = ((Object)((Component)val2).gameObject).name.ToLowerInvariant();
			if (!ShouldSkipBoundsName(lowerName))
			{
				if (!flag)
				{
					bounds = val2.bounds;
					flag = true;
				}
				else
				{
					((Bounds)(ref bounds)).Encapsulate(val2.bounds);
				}
			}
		}
		if (flag)
		{
			return bounds;
		}
		return new Bounds(root.transform.position, Vector3.one * 3f);
	}

	public static List<Bounds> GetIndividualVisualBounds(GameObject root, bool bigDoor)
	{
		//IL_0049: 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_0052: Unknown result type (might be due to invalid IL or missing references)
		//IL_0057: Unknown result type (might be due to invalid IL or missing references)
		//IL_009c: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a1: 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_00aa: Unknown result type (might be due to invalid IL or missing references)
		//IL_0074: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
		List<Bounds> list = new List<Bounds>();
		if ((Object)(object)root == (Object)null)
		{
			return list;
		}
		Renderer[] componentsInChildren = root.GetComponentsInChildren<Renderer>(true);
		Renderer[] array = componentsInChildren;
		Vector3 size;
		foreach (Renderer val in array)
		{
			if (RendererUtil.IsVisibleDoorRenderer(val, bigDoor))
			{
				Bounds bounds = val.bounds;
				size = ((Bounds)(ref bounds)).size;
				if (!(((Vector3)(ref size)).sqrMagnitude <= 0.0001f))
				{
					list.Add(bounds);
				}
			}
		}
		if (list.Count == 0)
		{
			Bounds bounds2 = GetBounds(root);
			size = ((Bounds)(ref bounds2)).size;
			if (((Vector3)(ref size)).sqrMagnitude > 0.0001f)
			{
				list.Add(bounds2);
			}
		}
		return list;
	}

	public static void EncapsulateTransformBounds(Transform transform, ref Bounds bounds, ref bool hasBounds)
	{
		//IL_0046: Unknown result type (might be due to invalid IL or missing references)
		//IL_0033: Unknown result type (might be due to invalid IL or missing references)
		//IL_0038: Unknown result type (might be due to invalid IL or missing references)
		//IL_008a: Unknown result type (might be due to invalid IL or missing references)
		//IL_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)
		if ((Object)(object)transform == (Object)null)
		{
			return;
		}
		Collider component = ((Component)transform).GetComponent<Collider>();
		if ((Object)(object)component != (Object)null)
		{
			if (!hasBounds)
			{
				bounds = component.bounds;
				hasBounds = true;
			}
			else
			{
				((Bounds)(ref bounds)).Encapsulate(component.bounds);
			}
			return;
		}
		Renderer component2 = ((Component)transform).GetComponent<Renderer>();
		if ((Object)(object)component2 != (Object)null)
		{
			if (!hasBounds)
			{
				bounds = component2.bounds;
				hasBounds = true;
			}
			else
			{
				((Bounds)(ref bounds)).Encapsulate(component2.bounds);
			}
		}
	}

	private static bool ShouldSkipBoundsName(string lowerName)
	{
		if (string.IsNullOrEmpty(lowerName))
		{
			return false;
		}
		return lowerName.Contains("trigger") || lowerName.Contains("lockpickplus") || lowerName.Contains("interact") || lowerName.Contains("scan") || lowerName.Contains("node") || lowerName.Contains("ui") || lowerName.Contains("audio") || lowerName.Contains("light");
	}
}
internal static class ReflectionUtil
{
	public static T GetFieldValueExact<T>(object instance, string fieldName) where T : class
	{
		try
		{
			if (instance == null)
			{
				return null;
			}
			FieldInfo field = instance.GetType().GetField(fieldName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (field == null)
			{
				return null;
			}
			object value = field.GetValue(instance);
			return value as T;
		}
		catch
		{
			return null;
		}
	}

	public static bool GetBoolFieldExact(object instance, string fieldName)
	{
		try
		{
			if (instance == null)
			{
				return false;
			}
			FieldInfo field = instance.GetType().GetField(fieldName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (field == null || field.FieldType != typeof(bool))
			{
				return false;
			}
			object value = field.GetValue(instance);
			if (value is bool)
			{
				return (bool)value;
			}
		}
		catch
		{
		}
		return false;
	}

	public static void SetBoolFieldExact(object instance, string fieldName, bool value)
	{
		try
		{
			if (instance != null)
			{
				FieldInfo field = instance.GetType().GetField(fieldName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (!(field == null) && !(field.FieldType != typeof(bool)))
				{
					field.SetValue(instance, value);
				}
			}
		}
		catch
		{
		}
	}

	public static void SetFloatFieldExact(object instance, string fieldName, float value)
	{
		try
		{
			if (instance != null)
			{
				FieldInfo field = instance.GetType().GetField(fieldName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (!(field == null) && !(field.FieldType != typeof(float)))
				{
					field.SetValue(instance, value);
				}
			}
		}
		catch
		{
		}
	}

	public static bool CallNoArgExact(object instance, string methodName)
	{
		try
		{
			if (instance == null)
			{
				return false;
			}
			MethodInfo method = instance.GetType().GetMethod(methodName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (method == null || method.GetParameters().Length != 0)
			{
				return false;
			}
			method.Invoke(instance, null);
			return true;
		}
		catch
		{
			return false;
		}
	}

	public static bool CallBoolArgExact(object instance, string methodName, bool value)
	{
		try
		{
			if (instance == null)
			{
				return false;
			}
			MethodInfo method = instance.GetType().GetMethod(methodName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (method == null)
			{
				return false;
			}
			ParameterInfo[] parameters = method.GetParameters();
			if (parameters.Length != 1 || parameters[0].ParameterType != typeof(bool))
			{
				return false;
			}
			method.Invoke(instance, new object[1] { value });
			return true;
		}
		catch
		{
			return false;
		}
	}
}

plugins/Extraction/Extraction.dll

Decompiled 19 hours 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.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using GameNetcodeStuff;
using HarmonyLib;
using Unity.Collections;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.Rendering;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("ScrapVisbility")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ScrapVisbility")]
[assembly: AssemblyCopyright("Copyright ©  2026")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("8a6853bd-bdc9-4741-95c7-5aa2c8c6a6f9")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace Extraction;

[BepInPlugin("robert.lethalcompany.extraction", "Extraction", "0.2.37")]
public sealed class Plugin : BaseUnityPlugin
{
	private struct CubeShape
	{
		public Vector3 Center;

		public Vector3 Size;

		public CubeShape(Vector3 center, Vector3 size)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			Center = center;
			Size = size;
		}
	}

	private struct DynamicBoundarySegment
	{
		public int Axis;

		public int Sign;

		public float FixedCoord;

		public float FromCoord;

		public float ToCoord;

		public DynamicBoundarySegment(int axis, int sign, float fixedCoord, float fromCoord, float toCoord)
		{
			Axis = axis;
			Sign = sign;
			FixedCoord = fixedCoord;
			FromCoord = fromCoord;
			ToCoord = toCoord;
		}
	}

	private struct ShipDoorAudioState
	{
		internal readonly bool Mute;

		internal readonly float Volume;

		internal ShipDoorAudioState(bool mute, float volume)
		{
			Mute = mute;
			Volume = volume;
		}
	}

	private sealed class ScrapGlowState
	{
		private readonly GrabbableObject _item;

		private readonly Dictionary<Renderer, MaterialPropertyBlock> _originalBlocks = new Dictionary<Renderer, MaterialPropertyBlock>();

		private GameObject _lightObject;

		internal ScrapGlowState(GrabbableObject item)
		{
			_item = item;
		}

		internal void Apply()
		{
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Expected O, but got Unknown
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Expected O, but got Unknown
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bd: Expected O, but got Unknown
			//IL_01e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_0212: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_item == (Object)null)
			{
				return;
			}
			Renderer[] componentsInChildren = ((Component)_item).GetComponentsInChildren<Renderer>(true);
			Color val = default(Color);
			((Color)(ref val))..ctor(1f, 0.03f, 0.02f, 1f);
			float num = Mathf.Max(0f, (_cubeScrapGlowEmissionStrength != null) ? _cubeScrapGlowEmissionStrength.Value : 4f);
			Color val2 = val * Mathf.Max(1f, num);
			Renderer[] array = componentsInChildren;
			foreach (Renderer val3 in array)
			{
				if (!((Object)(object)val3 == (Object)null) && val3.enabled && !(val3 is ParticleSystemRenderer))
				{
					MaterialPropertyBlock val4 = new MaterialPropertyBlock();
					val3.GetPropertyBlock(val4);
					_originalBlocks[val3] = val4;
					MaterialPropertyBlock val5 = new MaterialPropertyBlock();
					val3.GetPropertyBlock(val5);
					val5.SetColor("_Color", val);
					val5.SetColor("_BaseColor", val);
					val5.SetColor("_TintColor", val);
					val5.SetColor("_MainColor", val);
					val5.SetColor("_EmissionColor", val2);
					val5.SetColor("_EmissiveColor", val2);
					val5.SetFloat("_UseEmissiveIntensity", 1f);
					val5.SetFloat("_EmissiveIntensity", num);
					val3.SetPropertyBlock(val5);
				}
			}
			float num2 = Mathf.Max(0f, (_cubeScrapGlowLightIntensity != null) ? _cubeScrapGlowLightIntensity.Value : 1.25f);
			if (num2 > 0f)
			{
				_lightObject = new GameObject("Extraction_CubeScrap_RedGlowLight");
				_lightObject.transform.SetParent(((Component)_item).transform, false);
				_lightObject.transform.localPosition = Vector3.up * 0.15f;
				Light val6 = _lightObject.AddComponent<Light>();
				val6.type = (LightType)2;
				val6.color = val;
				val6.intensity = num2;
				val6.range = Mathf.Max(0.25f, (_cubeScrapGlowLightRange != null) ? _cubeScrapGlowLightRange.Value : 2.25f);
				val6.shadows = (LightShadows)0;
				val6.renderMode = (LightRenderMode)1;
			}
		}

		internal void Restore()
		{
			foreach (KeyValuePair<Renderer, MaterialPropertyBlock> originalBlock in _originalBlocks)
			{
				if ((Object)(object)originalBlock.Key != (Object)null)
				{
					originalBlock.Key.SetPropertyBlock(originalBlock.Value);
				}
			}
			_originalBlocks.Clear();
			if ((Object)(object)_lightObject != (Object)null)
			{
				Object.Destroy((Object)(object)_lightObject);
				_lightObject = null;
			}
		}
	}

	internal sealed class ScrapValueHighlighter : MonoBehaviour
	{
		private GrabbableObject item;

		private GameObject textObject;

		private TextMesh textMesh;

		private MeshRenderer textRenderer;

		private Material textMaterial;

		private GameObject lightObject;

		private Light glowLight;

		private readonly List<Renderer> targetRenderers = new List<Renderer>();

		private readonly Dictionary<Renderer, MaterialPropertyBlock> blocks = new Dictionary<Renderer, MaterialPropertyBlock>();

		private int lastValue = -999999;

		private string lastName = string.Empty;

		private Color lastColor = Color.clear;

		private bool textVisible;

		private float lastGoodTextVisibleTime;

		private static readonly FieldInfo fieldIsHeld = typeof(GrabbableObject).GetField("isHeld", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

		private static readonly FieldInfo fieldIsPocketed = typeof(GrabbableObject).GetField("isPocketed", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

		private static readonly FieldInfo fieldIsHeldByEnemy = typeof(GrabbableObject).GetField("isHeldByEnemy", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

		private static readonly FieldInfo fieldPlayerHeldBy = typeof(GrabbableObject).GetField("playerHeldBy", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

		private static readonly FieldInfo fieldCurrentlyHeldObjectServer = typeof(PlayerControllerB).GetField("currentlyHeldObjectServer", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

		private static readonly FieldInfo fieldCurrentlyHeldObject = typeof(PlayerControllerB).GetField("currentlyHeldObject", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

		internal void Init(GrabbableObject grabbable)
		{
			item = grabbable;
			CacheTargetRenderers();
			CreateText();
			CreateApparatusLight();
			SetVisualsActive(active: false);
		}

		private void CacheTargetRenderers()
		{
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Expected O, but got Unknown
			targetRenderers.Clear();
			blocks.Clear();
			if ((Object)(object)item == (Object)null)
			{
				return;
			}
			Renderer[] componentsInChildren = ((Component)item).GetComponentsInChildren<Renderer>(true);
			Renderer[] array = componentsInChildren;
			foreach (Renderer val in array)
			{
				if (!((Object)(object)val == (Object)null))
				{
					string lowerName = ((Object)((Component)val).gameObject).name.ToLowerInvariant();
					if (!ShouldSkipRenderer(val, lowerName))
					{
						targetRenderers.Add(val);
						blocks[val] = new MaterialPropertyBlock();
					}
				}
			}
		}

		private bool ShouldSkipRenderer(Renderer renderer, string lowerName)
		{
			if ((Object)(object)renderer == (Object)null)
			{
				return true;
			}
			if (!renderer.enabled)
			{
				return true;
			}
			if (string.IsNullOrEmpty(lowerName))
			{
				lowerName = ((Object)((Component)renderer).gameObject).name.ToLowerInvariant();
			}
			string text = ((object)renderer).GetType().Name.ToLowerInvariant();
			if (text.Contains("particle") || text.Contains("trail") || text.Contains("line"))
			{
				return true;
			}
			if (lowerName.Contains("scan") || lowerName.Contains("scannode") || lowerName.Contains("scan node") || lowerName.Contains("trigger") || lowerName.Contains("collider") || lowerName.Contains("collision") || lowerName.Contains("hitbox") || lowerName.Contains("interact") || lowerName.Contains("scrapvisibility") || lowerName.Contains("mapdot") || lowerName.Contains("radar") || lowerName.Contains("audio") || lowerName.Contains("sound") || lowerName.Contains("light") || lowerName.Contains("vfx") || lowerName.Contains("sfx"))
			{
				return true;
			}
			return false;
		}

		private void CreateText()
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Expected O, but got Unknown
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_019d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a7: Expected O, but got Unknown
			//IL_01ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f7: Expected O, but got Unknown
			//IL_028b: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b7: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)textObject != (Object)null)
			{
				return;
			}
			textObject = new GameObject("ScrapVisibility_3DText");
			textObject.transform.SetParent(GetScrapTextRoot(), false);
			textObject.transform.position = ((Component)this).transform.position + Vector3.up * 0.5f;
			textObject.transform.rotation = Quaternion.identity;
			textObject.transform.localScale = Vector3.one;
			textMesh = textObject.AddComponent<TextMesh>();
			textMesh.text = string.Empty;
			textMesh.alignment = (TextAlignment)1;
			textMesh.anchor = (TextAnchor)4;
			textMesh.fontSize = 90;
			textMesh.characterSize = 0.022f;
			textMesh.color = Color.white;
			Font builtinResource = Resources.GetBuiltinResource<Font>("Arial.ttf");
			if ((Object)(object)builtinResource != (Object)null)
			{
				textMesh.font = builtinResource;
			}
			textRenderer = textObject.GetComponent<MeshRenderer>();
			if ((Object)(object)textRenderer == (Object)null)
			{
				textRenderer = textObject.AddComponent<MeshRenderer>();
			}
			if ((Object)(object)textMesh.font != (Object)null && (Object)(object)textMesh.font.material != (Object)null)
			{
				textMaterial = new Material(textMesh.font.material);
			}
			else
			{
				Shader val = Shader.Find("GUI/Text Shader");
				if ((Object)(object)val == (Object)null)
				{
					val = Shader.Find("Unlit/Transparent");
				}
				if ((Object)(object)val == (Object)null)
				{
					val = Shader.Find("Sprites/Default");
				}
				textMaterial = new Material(val);
			}
			((Object)textMaterial).name = "ScrapVisibility_ReadableTextMaterial";
			textMaterial.renderQueue = 3000;
			if (textMaterial.HasProperty("_Cull"))
			{
				textMaterial.SetInt("_Cull", 0);
			}
			if (textMaterial.HasProperty("_ZWrite"))
			{
				textMaterial.SetInt("_ZWrite", 0);
			}
			if (textMaterial.HasProperty("_Color"))
			{
				textMaterial.SetColor("_Color", Color.white);
			}
			if (textMaterial.HasProperty("_FaceColor"))
			{
				textMaterial.SetColor("_FaceColor", Color.white);
			}
			((Renderer)textRenderer).sharedMaterial = textMaterial;
			((Renderer)textRenderer).shadowCastingMode = (ShadowCastingMode)0;
			((Renderer)textRenderer).receiveShadows = false;
		}

		private void CreateApparatusLight()
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Expected O, but got Unknown
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)lightObject != (Object)null))
			{
				lightObject = new GameObject("ScrapVisibility_ApparatusStyleLight");
				lightObject.transform.SetParent(((Component)this).transform, false);
				lightObject.transform.localPosition = Vector3.zero;
				glowLight = lightObject.AddComponent<Light>();
				glowLight.type = (LightType)2;
				glowLight.color = Color.white;
				glowLight.intensity = 6f;
				glowLight.range = 6f;
				((Behaviour)glowLight).enabled = false;
				glowLight.shadows = (LightShadows)2;
				glowLight.renderMode = (LightRenderMode)1;
				glowLight.cullingMask = -1;
				glowLight.bounceIntensity = 1.2f;
			}
		}

		private void LateUpdate()
		{
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)item == (Object)null)
			{
				DestroySelf();
				return;
			}
			if ((Object)(object)item.itemProperties == (Object)null)
			{
				ClearGlow();
				SetVisualsActive(active: false);
				return;
			}
			PlayerControllerB localPlayer = GetLocalPlayer();
			if ((Object)(object)localPlayer == (Object)null || !localPlayer.isPlayerControlled || localPlayer.isPlayerDead)
			{
				ClearGlow();
				SetVisualsActive(active: false);
				return;
			}
			if (IsHeldByAnyone(localPlayer))
			{
				ClearGlow();
				SetVisualsActive(active: false);
				return;
			}
			if (!((Component)item).gameObject.activeInHierarchy)
			{
				ClearGlow();
				SetVisualsActive(active: false);
				return;
			}
			if (!TryGetBounds(out var bounds))
			{
				ClearGlow();
				SetVisualsActive(active: false);
				return;
			}
			float num = Vector3.Distance(((Component)localPlayer).transform.position, ((Bounds)(ref bounds)).center);
			if (_scrapVisibilityMaxDistance != null && num > _scrapVisibilityMaxDistance.Value)
			{
				ClearGlow();
				SetVisualsActive(active: false);
			}
			else
			{
				UpdateVisuals(bounds, num);
				SetVisualsActive(active: true);
			}
		}

		private PlayerControllerB GetLocalPlayer()
		{
			if ((Object)(object)GameNetworkManager.Instance == (Object)null)
			{
				return null;
			}
			return GameNetworkManager.Instance.localPlayerController;
		}

		private bool IsHeldByAnyone(PlayerControllerB localPlayer)
		{
			if (GetBoolField(fieldIsHeld))
			{
				return true;
			}
			if (GetBoolField(fieldIsPocketed))
			{
				return true;
			}
			if (GetBoolField(fieldIsHeldByEnemy))
			{
				return true;
			}
			if (GetObjectField(fieldPlayerHeldBy) != null)
			{
				return true;
			}
			if ((Object)(object)localPlayer != (Object)null)
			{
				object playerObjectField = GetPlayerObjectField(localPlayer, fieldCurrentlyHeldObjectServer);
				object playerObjectField2 = GetPlayerObjectField(localPlayer, fieldCurrentlyHeldObject);
				if (playerObjectField == item || playerObjectField2 == item)
				{
					return true;
				}
			}
			Transform parent = ((Component)item).transform.parent;
			if ((Object)(object)parent != (Object)null)
			{
				string text = ((Object)parent).name.ToLowerInvariant();
				if (text.Contains("player") || text.Contains("hand") || text.Contains("hold") || text.Contains("itemholder") || text.Contains("pocket"))
				{
					return true;
				}
			}
			return false;
		}

		private bool GetBoolField(FieldInfo field)
		{
			if (field == null || (Object)(object)item == (Object)null)
			{
				return false;
			}
			object value = field.GetValue(item);
			bool flag = default(bool);
			int num;
			if (value is bool)
			{
				flag = (bool)value;
				num = 1;
			}
			else
			{
				num = 0;
			}
			return (byte)((uint)num & (flag ? 1u : 0u)) != 0;
		}

		private object GetObjectField(FieldInfo field)
		{
			if (field == null || (Object)(object)item == (Object)null)
			{
				return null;
			}
			return field.GetValue(item);
		}

		private object GetPlayerObjectField(PlayerControllerB player, FieldInfo field)
		{
			if (field == null || (Object)(object)player == (Object)null)
			{
				return null;
			}
			return field.GetValue(player);
		}

		private bool TryGetBounds(out Bounds bounds)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			bounds = new Bounds(((Component)this).transform.position, Vector3.one * 0.25f);
			bool flag = false;
			foreach (Renderer targetRenderer in targetRenderers)
			{
				if ((Object)(object)targetRenderer == (Object)null)
				{
					continue;
				}
				string lowerName = ((Object)((Component)targetRenderer).gameObject).name.ToLowerInvariant();
				if (!ShouldSkipRenderer(targetRenderer, lowerName) && ((Component)targetRenderer).gameObject.activeInHierarchy)
				{
					if (!flag)
					{
						bounds = targetRenderer.bounds;
						flag = true;
					}
					else
					{
						((Bounds)(ref bounds)).Encapsulate(targetRenderer.bounds);
					}
				}
			}
			return flag;
		}

		private void UpdateVisuals(Bounds bounds, float distance)
		{
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: 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_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: 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_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01af: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01be: Unknown result type (might be due to invalid IL or missing references)
			//IL_015f: 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)
			bool flag = (Object)(object)item.itemProperties != (Object)null && item.itemProperties.isScrap;
			int num = Mathf.Max(0, item.scrapValue);
			string text = "Item";
			if ((Object)(object)item.itemProperties != (Object)null && !string.IsNullOrEmpty(item.itemProperties.itemName))
			{
				text = item.itemProperties.itemName;
			}
			Color scrapDisplayColor = GetScrapDisplayColor(flag, num);
			if (ScrapIsRegisteredInsideCubeForVisuals(item))
			{
				((Color)(ref scrapDisplayColor))..ctor(1f, 0.03f, 0.02f, 1f);
			}
			float num2 = 0.78f + Mathf.Sin(Time.time * GetPulseSpeed()) * 0.22f;
			Color tintColor = Color.Lerp(Color.white, scrapDisplayColor, GetTintStrength());
			tintColor.a = 1f;
			Color emissionColor = scrapDisplayColor * GetEmissionStrength() * num2;
			emissionColor.a = 1f;
			ApplyGlow(tintColor, emissionColor);
			if (num != lastValue || text != lastName || scrapDisplayColor != lastColor)
			{
				lastValue = num;
				lastName = text;
				lastColor = scrapDisplayColor;
				if ((Object)(object)textMesh != (Object)null)
				{
					if (flag)
					{
						textMesh.text = text + "\n$" + num;
					}
					else
					{
						textMesh.text = text;
					}
				}
			}
			UpdateApparatusLight(bounds, flag, num, scrapDisplayColor, num2);
			UpdateText(bounds, distance, scrapDisplayColor);
		}

		private void UpdateApparatusLight(Bounds bounds, bool isScrap, int value, Color color, float pulse)
		{
			//IL_0029: 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)
			if (!((Object)(object)glowLight == (Object)null))
			{
				float lightMultiplierForItem = GetLightMultiplierForItem(isScrap, value);
				((Component)glowLight).transform.position = ((Bounds)(ref bounds)).center;
				glowLight.color = color;
				glowLight.intensity = GetLightIntensity() * lightMultiplierForItem * pulse;
				glowLight.range = GetLightRange() * lightMultiplierForItem;
				glowLight.bounceIntensity = 1.5f + lightMultiplierForItem * 0.35f;
			}
		}

		private float GetLightMultiplierForItem(bool isScrap, int value)
		{
			if (!isScrap)
			{
				return 1.25f;
			}
			if (value >= 300)
			{
				return 2.25f;
			}
			if (value >= 150)
			{
				return 1.8f;
			}
			if (value >= 100)
			{
				return 1.45f;
			}
			if (value >= 50)
			{
				return 1.15f;
			}
			return 0.9f;
		}

		private void ApplyGlow(Color tintColor, Color emissionColor)
		{
			//IL_008e: 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_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Expected O, but got Unknown
			if (_showScrapModelGlow == null || !_showScrapModelGlow.Value)
			{
				ClearGlow();
				return;
			}
			foreach (Renderer targetRenderer in targetRenderers)
			{
				if (!((Object)(object)targetRenderer == (Object)null))
				{
					if (!blocks.TryGetValue(targetRenderer, out var value))
					{
						value = new MaterialPropertyBlock();
						blocks[targetRenderer] = value;
					}
					targetRenderer.GetPropertyBlock(value);
					value.SetColor("_Color", tintColor);
					value.SetColor("_BaseColor", tintColor);
					value.SetColor("_EmissionColor", emissionColor);
					value.SetColor("_EmissiveColor", emissionColor);
					targetRenderer.SetPropertyBlock(value);
				}
			}
		}

		private void ClearGlow()
		{
			foreach (Renderer targetRenderer in targetRenderers)
			{
				if (!((Object)(object)targetRenderer == (Object)null))
				{
					targetRenderer.SetPropertyBlock((MaterialPropertyBlock)null);
				}
			}
		}

		private void UpdateText(Bounds bounds, float distance, Color color)
		{
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: 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_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)textObject == (Object)null || (Object)(object)textMesh == (Object)null)
			{
				return;
			}
			Transform scrapTextRoot = GetScrapTextRoot();
			if ((Object)(object)textObject.transform.parent != (Object)(object)scrapTextRoot)
			{
				textObject.transform.SetParent(scrapTextRoot, true);
			}
			textObject.transform.position = GetStableLabelPosition(bounds);
			Camera main = Camera.main;
			if ((Object)(object)main != (Object)null)
			{
				textObject.transform.rotation = ((Component)main).transform.rotation;
			}
			textVisible = IsObjectVisibleForText(bounds);
			textMesh.characterSize = GetTextSize();
			textObject.transform.localScale = Vector3.one;
			textMesh.color = color;
			if ((Object)(object)textMaterial != (Object)null)
			{
				if (textMaterial.HasProperty("_Color"))
				{
					textMaterial.SetColor("_Color", color);
				}
				if (textMaterial.HasProperty("_FaceColor"))
				{
					textMaterial.SetColor("_FaceColor", color);
				}
			}
		}

		private Vector3 GetStableLabelPosition(Bounds bounds)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			return ((Bounds)(ref bounds)).center + Vector3.up * (((Bounds)(ref bounds)).extents.y + GetTextHeightOffset());
		}

		private Vector3 GetParentScaleCompensatedLocalScale(float desiredWorldScale)
		{
			//IL_003d: 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_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: 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_0075: Unknown result type (might be due to invalid IL or missing references)
			Transform val = (((Object)(object)textObject != (Object)null) ? textObject.transform.parent : null);
			if ((Object)(object)val == (Object)null)
			{
				return Vector3.one * desiredWorldScale;
			}
			Vector3 lossyScale = val.lossyScale;
			return new Vector3(desiredWorldScale / SafeSignedScale(lossyScale.x), desiredWorldScale / SafeSignedScale(lossyScale.y), desiredWorldScale / SafeSignedScale(lossyScale.z));
		}

		private float SafeSignedScale(float value)
		{
			if (Mathf.Abs(value) < 0.001f)
			{
				return (value < 0f) ? (-0.001f) : 0.001f;
			}
			return value;
		}

		private bool IsObjectVisibleForText(Bounds bounds)
		{
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: 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_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			//IL_0146: Unknown result type (might be due to invalid IL or missing references)
			//IL_014b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_015a: 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_0166: Unknown result type (might be due to invalid IL or missing references)
			//IL_016b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0170: Unknown result type (might be due to invalid IL or missing references)
			//IL_0178: Unknown result type (might be due to invalid IL or missing references)
			//IL_0179: Unknown result type (might be due to invalid IL or missing references)
			//IL_017f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0191: Unknown result type (might be due to invalid IL or missing references)
			//IL_0196: Unknown result type (might be due to invalid IL or missing references)
			//IL_019e: Unknown result type (might be due to invalid IL or missing references)
			//IL_019f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01de: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0200: 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_020a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0212: Unknown result type (might be due to invalid IL or missing references)
			//IL_0213: Unknown result type (might be due to invalid IL or missing references)
			//IL_0219: Unknown result type (might be due to invalid IL or missing references)
			//IL_0220: Unknown result type (might be due to invalid IL or missing references)
			//IL_0227: 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_0239: Unknown result type (might be due to invalid IL or missing references)
			//IL_023a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0241: Unknown result type (might be due to invalid IL or missing references)
			//IL_0248: Unknown result type (might be due to invalid IL or missing references)
			//IL_024f: 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_0259: Unknown result type (might be due to invalid IL or missing references)
			//IL_026c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0271: Unknown result type (might be due to invalid IL or missing references)
			//IL_0276: Unknown result type (might be due to invalid IL or missing references)
			if (_hideScrapTextBehindWalls == null || !_hideScrapTextBehindWalls.Value)
			{
				return true;
			}
			Camera main = Camera.main;
			if ((Object)(object)main == (Object)null)
			{
				return true;
			}
			Vector3 center = ((Bounds)(ref bounds)).center;
			Vector3 extents = ((Bounds)(ref bounds)).extents;
			Vector3[] array = (Vector3[])(object)new Vector3[15]
			{
				center,
				center + new Vector3(0f, extents.y, 0f),
				center - new Vector3(0f, extents.y, 0f),
				center + new Vector3(extents.x, 0f, 0f),
				center - new Vector3(extents.x, 0f, 0f),
				center + new Vector3(0f, 0f, extents.z),
				center - new Vector3(0f, 0f, extents.z),
				center + new Vector3(extents.x, extents.y, extents.z),
				center + new Vector3(0f - extents.x, extents.y, extents.z),
				center + new Vector3(extents.x, extents.y, 0f - extents.z),
				center + new Vector3(0f - extents.x, extents.y, 0f - extents.z),
				center + new Vector3(extents.x, 0f - extents.y, extents.z),
				center + new Vector3(0f - extents.x, 0f - extents.y, extents.z),
				center + new Vector3(extents.x, 0f - extents.y, 0f - extents.z),
				center + new Vector3(0f - extents.x, 0f - extents.y, 0f - extents.z)
			};
			Vector3[] array2 = array;
			foreach (Vector3 point in array2)
			{
				if (PointIsOnScreenAndNotBlocked(main, point))
				{
					lastGoodTextVisibleTime = Time.time;
					return true;
				}
			}
			float num = ((_scrapTextVisibilityGraceTime != null) ? Mathf.Max(0f, _scrapTextVisibilityGraceTime.Value) : 0.2f);
			return Time.time - lastGoodTextVisibleTime <= num;
		}

		private bool PointIsOnScreenAndNotBlocked(Camera cam, Vector3 point)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: 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_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: 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_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: 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_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0196: Unknown result type (might be due to invalid IL or missing references)
			//IL_019b: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = cam.WorldToViewportPoint(point);
			if (val.z < 0f)
			{
				return false;
			}
			float num = ((_scrapScreenEdgeMargin != null) ? Mathf.Clamp(_scrapScreenEdgeMargin.Value, 0f, 0.35f) : 0.12f);
			if (val.x < 0f - num || val.x > 1f + num)
			{
				return false;
			}
			if (val.y < 0f - num || val.y > 1f + num)
			{
				return false;
			}
			Vector3 position = ((Component)cam).transform.position;
			Vector3 val2 = point - position;
			float magnitude = ((Vector3)(ref val2)).magnitude;
			if (magnitude <= 0.05f)
			{
				return true;
			}
			Vector3 normalized = ((Vector3)(ref val2)).normalized;
			position += normalized * 0.25f;
			float num2 = ((_scrapTextOcclusionPadding != null) ? Mathf.Clamp(_scrapTextOcclusionPadding.Value, 0.01f, 1f) : 0.12f);
			float num3 = Mathf.Max(0.05f, magnitude - num2);
			RaycastHit[] array = Physics.RaycastAll(position, normalized, num3, -1, (QueryTriggerInteraction)1);
			if (array == null || array.Length == 0)
			{
				return true;
			}
			Array.Sort(array, (RaycastHit a, RaycastHit b) => ((RaycastHit)(ref a)).distance.CompareTo(((RaycastHit)(ref b)).distance));
			PlayerControllerB localPlayer = GetLocalPlayer();
			RaycastHit[] array2 = array;
			for (int i = 0; i < array2.Length; i++)
			{
				RaycastHit val3 = array2[i];
				if ((Object)(object)((RaycastHit)(ref val3)).collider == (Object)null)
				{
					continue;
				}
				Transform transform = ((Component)((RaycastHit)(ref val3)).collider).transform;
				if ((Object)(object)textObject != (Object)null && transform.IsChildOf(textObject.transform))
				{
					continue;
				}
				if (transform.IsChildOf(((Component)item).transform))
				{
					return true;
				}
				GrabbableObject componentInParent = ((Component)((RaycastHit)(ref val3)).collider).GetComponentInParent<GrabbableObject>();
				if ((Object)(object)componentInParent == (Object)(object)item)
				{
					return true;
				}
				if ((!((Object)(object)localPlayer != (Object)null) || !transform.IsChildOf(((Component)localPlayer).transform)) && !((Object)(object)componentInParent != (Object)null))
				{
					string text = ((Object)transform).name.ToLowerInvariant();
					if (!text.Contains("player") && !text.Contains("camera") && !text.Contains("hand") && !text.Contains("itemholder") && !text.Contains("held") && !text.Contains("helmet") && !text.Contains("scan") && !text.Contains("trigger"))
					{
						return false;
					}
				}
			}
			return true;
		}

		private void SetVisualsActive(bool active)
		{
			bool flag = active && textVisible && _showScrapValueText != null && _showScrapValueText.Value;
			bool enabled = active && _showScrapLight != null && _showScrapLight.Value;
			if ((Object)(object)textObject != (Object)null && textObject.activeSelf != flag)
			{
				textObject.SetActive(flag);
			}
			if ((Object)(object)glowLight != (Object)null)
			{
				((Behaviour)glowLight).enabled = enabled;
			}
		}

		private float GetTintStrength()
		{
			if (_scrapTintStrength == null)
			{
				return 1f;
			}
			return Mathf.Clamp01(_scrapTintStrength.Value);
		}

		private float GetEmissionStrength()
		{
			if (_scrapEmissionStrength == null)
			{
				return 5.5f;
			}
			return Mathf.Clamp(_scrapEmissionStrength.Value, 0f, 12f);
		}

		private float GetPulseSpeed()
		{
			if (_scrapPulseSpeed == null)
			{
				return 2.8f;
			}
			return Mathf.Max(0f, _scrapPulseSpeed.Value);
		}

		private float GetLightIntensity()
		{
			if (_scrapLightIntensity == null)
			{
				return 6f;
			}
			return Mathf.Clamp(_scrapLightIntensity.Value, 0f, 30f);
		}

		private float GetLightRange()
		{
			if (_scrapLightRange == null)
			{
				return 6f;
			}
			return Mathf.Clamp(_scrapLightRange.Value, 0f, 20f);
		}

		private float GetTextSize()
		{
			if (_scrapTextSize == null)
			{
				return 0.022f;
			}
			return Mathf.Clamp(_scrapTextSize.Value, 0.005f, 0.14f);
		}

		private float GetTextHeightOffset()
		{
			if (_scrapTextHeightOffset == null)
			{
				return 0.22f;
			}
			return Mathf.Clamp(_scrapTextHeightOffset.Value, 0f, 2f);
		}

		internal void DestroySelf()
		{
			ClearGlow();
			if ((Object)(object)textObject != (Object)null)
			{
				Object.Destroy((Object)(object)textObject);
				textObject = null;
			}
			if ((Object)(object)lightObject != (Object)null)
			{
				Object.Destroy((Object)(object)lightObject);
				lightObject = null;
			}
			if ((Object)(object)textMaterial != (Object)null)
			{
				Object.Destroy((Object)(object)textMaterial);
				textMaterial = null;
			}
			Object.Destroy((Object)(object)this);
		}

		private void OnDestroy()
		{
			ClearGlow();
			if ((Object)(object)textObject != (Object)null)
			{
				Object.Destroy((Object)(object)textObject);
			}
			if ((Object)(object)lightObject != (Object)null)
			{
				Object.Destroy((Object)(object)lightObject);
			}
			if ((Object)(object)textMaterial != (Object)null)
			{
				Object.Destroy((Object)(object)textMaterial);
			}
		}
	}

	[HarmonyPatch(typeof(EntranceTeleport), "StartOpeningEntrance")]
	private static class EntranceTeleport_StartOpeningEntrance_Patch
	{
		private static bool Prefix(EntranceTeleport __instance)
		{
			if (_disableFacilityExitInteractions == null || !_disableFacilityExitInteractions.Value)
			{
				return true;
			}
			ForceFacilityExitInteractionsDisabled();
			D("Blocked facility entrance/fire-exit interaction: " + GetEntranceDebugName(__instance));
			return false;
		}
	}

	[HarmonyPatch(typeof(EntranceTeleport), "TeleportPlayer")]
	private static class EntranceTeleport_TeleportPlayer_Patch
	{
		private static bool Prefix(EntranceTeleport __instance)
		{
			if (_disableFacilityExitInteractions == null || !_disableFacilityExitInteractions.Value)
			{
				return true;
			}
			ForceFacilityExitInteractionsDisabled();
			D("Blocked facility entrance/fire-exit teleport: " + GetEntranceDebugName(__instance));
			return false;
		}
	}

	[HarmonyPatch(typeof(StartOfRound), "OpenShipDoors")]
	private static class StartOfRound_OpenShipDoors_Patch
	{
		private static void Postfix()
		{
			if (_keepShipDoorsClosed != null && _keepShipDoorsClosed.Value && !IsAtTheCompany())
			{
				ForceShipDoorsClosedNow();
				D("OpenShipDoors ran normally. Extraction hides the moving vanilla ship door and keeps the closed-door overlay.");
			}
		}
	}

	[HarmonyPatch(typeof(StartOfRound), "openingDoorsSequence")]
	private static class StartOfRound_OpeningDoorsSequence_Patch
	{
		private static void Postfix()
		{
			if (_keepShipDoorsClosed != null && _keepShipDoorsClosed.Value && !IsAtTheCompany())
			{
				ForceShipDoorsClosedNow();
				D("openingDoorsSequence ran normally. Extraction hides the moving vanilla ship door and keeps the closed-door overlay.");
			}
		}
	}

	[HarmonyPatch(typeof(HangarShipDoor), "SetDoorOpen")]
	private static class HangarShipDoor_SetDoorOpen_Patch
	{
		private static void Postfix(HangarShipDoor __instance)
		{
			if (_keepShipDoorsClosed != null && _keepShipDoorsClosed.Value && !IsAtTheCompany())
			{
				ForceShipDoorsClosedNow();
			}
		}
	}

	[HarmonyPatch(typeof(HangarShipDoor), "PlayDoorAnimation")]
	private static class HangarShipDoor_PlayDoorAnimation_Patch
	{
		private static void Postfix(HangarShipDoor __instance)
		{
			if (_keepShipDoorsClosed != null && _keepShipDoorsClosed.Value && !IsAtTheCompany())
			{
				ForceShipDoorsClosedNow();
			}
		}
	}

	[HarmonyPatch(typeof(StartOfRound), "ShipLeave")]
	private static class StartOfRound_ShipLeave_Patch
	{
		private static void Prefix()
		{
			D("StartOfRound.ShipLeave prefix fired.");
			LocalShipLeavePrefix();
		}
	}

	[HarmonyPatch(typeof(StartOfRound), "ShipHasLeft")]
	private static class StartOfRound_ShipHasLeft_Patch
	{
		private static void Postfix()
		{
			D("StartOfRound.ShipHasLeft postfix fired.");
			ApplyPendingQuotaValueOnHost("StartOfRound.ShipHasLeft postfix");
			ResetRoundState();
		}
	}

	[HarmonyPatch(typeof(HUDManager), "FillEndGameStats")]
	private static class HUDManager_FillEndGameStats_Patch
	{
		private static void Prefix()
		{
			D("HUDManager.FillEndGameStats prefix fired.");
			ApplyPendingQuotaValueOnHost("HUDManager.FillEndGameStats prefix");
		}
	}

	[HarmonyPatch(typeof(RoundManager), "FinishGeneratingNewLevelClientRpc")]
	private static class RoundManager_FinishGeneratingNewLevelClientRpc_Patch
	{
		private static void Postfix()
		{
			NotifyPlayersFinishedGeneratingNewLevel();
		}
	}

	[HarmonyPatch(typeof(TimeOfDay), "VoteShipToLeaveEarly")]
	private static class TimeOfDay_VoteShipToLeaveEarly_Patch
	{
		private static bool Prefix()
		{
			if (!BaseGameSpectatorVoteToLeaveDisabled())
			{
				return true;
			}
			D("Blocked vanilla dead-spectator vote to leave early because DisableBaseGameSpectatorVoteToLeave is true.");
			if ((Object)(object)HUDManager.Instance != (Object)null)
			{
				HUDManager.Instance.DisplayTip("Vote to leave disabled", "The vanilla spectator vote to leave early is disabled by this mod.", false, false, "LC_Tip1");
			}
			return false;
		}

		private static void Postfix()
		{
			if (!BaseGameSpectatorVoteToLeaveDisabled())
			{
				ObserveBaseGameVoteToLeave("local vanilla VoteShipToLeaveEarly called");
			}
		}
	}

	[HarmonyPatch(typeof(TimeOfDay), "SetShipLeaveEarlyServerRpc")]
	private static class TimeOfDay_SetShipLeaveEarlyServerRpc_Patch
	{
		private static bool Prefix()
		{
			if (!BaseGameSpectatorVoteToLeaveDisabled())
			{
				return true;
			}
			D("Blocked vanilla SetShipLeaveEarlyServerRpc because DisableBaseGameSpectatorVoteToLeave is true.");
			return false;
		}
	}

	[HarmonyPatch(typeof(TimeOfDay), "AddVoteForShipToLeaveEarlyClientRpc")]
	private static class TimeOfDay_AddVoteForShipToLeaveEarlyClientRpc_Patch
	{
		private static void Postfix()
		{
			if (!BaseGameSpectatorVoteToLeaveDisabled())
			{
				ObserveBaseGameVoteToLeave("vanilla AddVoteForShipToLeaveEarlyClientRpc fired");
			}
		}
	}

	[HarmonyPatch(typeof(TimeOfDay), "SetShipLeaveEarlyClientRpc")]
	private static class TimeOfDay_SetShipLeaveEarlyClientRpc_Patch
	{
		private static void Postfix()
		{
			if (!BaseGameSpectatorVoteToLeaveDisabled())
			{
				ObserveBaseGameVoteToLeave("vanilla SetShipLeaveEarlyClientRpc fired");
			}
		}
	}

	[HarmonyPatch(typeof(HUDManager), "DisplaySpectatorVoteTip")]
	private static class HUDManager_DisplaySpectatorVoteTip_Patch
	{
		private static bool Prefix()
		{
			return !BaseGameSpectatorVoteToLeaveDisabled();
		}
	}

	[HarmonyPatch(typeof(HUDManager), "AddPlayerChatMessageServerRpc")]
	private static class HUDManager_AddPlayerChatMessageServerRpc_Patch
	{
		private static bool Prefix(string chatMessage, int playerId)
		{
			try
			{
				if (!IsServer())
				{
					return true;
				}
				return !HandleChatCommand(chatMessage, playerId);
			}
			catch (Exception arg)
			{
				Log.LogWarning((object)$"[Extraction] Chat command handler failed: {arg}");
				return true;
			}
		}
	}

	[HarmonyPatch(typeof(HUDManager), "PingScan_performed")]
	private static class HUDManager_PingScan_performed_Patch
	{
		private static bool Prefix()
		{
			bool flag = ShouldBlockManualScanner();
			if (flag)
			{
				D("Blocked manual right click scan because integrated scrap visibility is enabled.");
			}
			return !flag;
		}
	}

	[CompilerGenerated]
	private sealed class <ApplyRoundStartCubeTeleportLocalCoroutine>d__429 : IEnumerator<object>, IDisposable, IEnumerator
	{
		private int <>1__state;

		private object <>2__current;

		public int token;

		public Vector3 position;

		public string source;

		private int <attempt>5__1;

		private PlayerControllerB <player>5__2;

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

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

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

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

		private bool MoveNext()
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Expected O, but got Unknown
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			switch (<>1__state)
			{
			default:
				return false;
			case 0:
				<>1__state = -1;
				<attempt>5__1 = 0;
				goto IL_017b;
			case 1:
				<>1__state = -1;
				goto IL_007e;
			case 2:
				{
					<>1__state = -1;
					goto IL_007e;
				}
				IL_007e:
				if (_cubeExtractionPassed || ((Object)(object)StartOfRound.Instance != (Object)null && StartOfRound.Instance.shipIsLeaving))
				{
					break;
				}
				<player>5__2 = StartOfRound.Instance?.localPlayerController;
				if (!((Object)(object)<player>5__2 == (Object)null) && <player>5__2.isPlayerControlled && !<player>5__2.isPlayerDead && !<player>5__2.disconnectedMidGame)
				{
					TeleportLocalPlayer(position, toShip: false);
					_localAppliedRoundStartCubeTeleportToken = token;
					_localPendingRoundStartCubeTeleportToken = -1;
					D($"Applied round-start cube teleport locally. token={token}, source={source}, attempt={<attempt>5__1 + 1}, pos={position}");
					return false;
				}
				<attempt>5__1++;
				goto IL_017b;
				IL_017b:
				if (<attempt>5__1 < 28)
				{
					if (<attempt>5__1 > 0)
					{
						<>2__current = (object)new WaitForSeconds(0.25f);
						<>1__state = 1;
						return true;
					}
					<>2__current = null;
					<>1__state = 2;
					return true;
				}
				break;
			}
			if (_localPendingRoundStartCubeTeleportToken == token)
			{
				_localPendingRoundStartCubeTeleportToken = -1;
			}
			D($"Failed to apply round-start cube teleport locally before retry attempts ended. token={token}, source={source}");
			return false;
		}

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

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

	[CompilerGenerated]
	private sealed class <ClientCubeVisualRefreshRoutine>d__419 : IEnumerator<object>, IDisposable, IEnumerator
	{
		private int <>1__state;

		private object <>2__current;

		public Vector3 center;

		private int <i>5__1;

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

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

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

		[DebuggerHidden]
		void IDisposable.Dispose()
		{
			int num = <>1__state;
			if (num == -3 || num == 1)
			{
				try
				{
				}
				finally
				{
					<>m__Finally1();
				}
			}
			<>1__state = -2;
		}

		private bool MoveNext()
		{
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Expected O, but got Unknown
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			bool result;
			try
			{
				switch (<>1__state)
				{
				default:
					result = false;
					goto end_IL_0000;
				case 0:
					<>1__state = -1;
					_clientCubeVisualRefreshRunning = true;
					<>1__state = -3;
					<i>5__1 = 0;
					break;
				case 1:
					<>1__state = -3;
					if (_hasCube)
					{
						if ((Object)(object)_cubeVisual == (Object)null)
						{
							CreateOrMoveCubeVisual(center);
						}
						else
						{
							if (!_cubeVisual.activeSelf)
							{
								_cubeVisual.SetActive(true);
							}
							ForceCubeVisualVisible();
							UpdateCubePulseVisual(force: true);
						}
						D($"Client forced Extraction Area visual visibility nudge {<i>5__1 + 1}/6. visualExists={(Object)(object)_cubeVisual != (Object)null}, active={(Object)(object)_cubeVisual != (Object)null && _cubeVisual.activeSelf}, dynamicReady={_cubeDynamicFootprintReady}, cells={_cubeDynamicFootprintCells.Count}");
						<i>5__1++;
						break;
					}
					result = false;
					<>m__Finally1();
					goto end_IL_0000;
				}
				if (<i>5__1 < 6)
				{
					<>2__current = (object)new WaitForSeconds(0.75f);
					<>1__state = 1;
					result = true;
				}
				else
				{
					<>m__Finally1();
					result = false;
				}
				end_IL_0000:;
			}
			catch
			{
				//try-fault
				((IDisposable)this).Dispose();
				throw;
			}
			return result;
		}

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

		private void <>m__Finally1()
		{
			<>1__state = -1;
			_clientCubeVisualRefreshRunning = false;
		}

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

	[CompilerGenerated]
	private sealed class <EmptyCoroutine>d__398 : IEnumerator<object>, IDisposable, IEnumerator
	{
		private int <>1__state;

		private object <>2__current;

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

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

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

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

		private bool MoveNext()
		{
			if (<>1__state != 0)
			{
				return false;
			}
			<>1__state = -1;
			return false;
		}

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

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

	[CompilerGenerated]
	private sealed class <KeepShipDoorsClosedWhileRunning>d__399 : IEnumerator<object>, IDisposable, IEnumerator
	{
		private int <>1__state;

		private object <>2__current;

		public IEnumerator original;

		public string source;

		private bool <moveNext>5__1;

		private object <current>5__2;

		private Exception <ex>5__3;

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

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

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

		[DebuggerHidden]
		void IDisposable.Dispose()
		{
			<current>5__2 = null;
			<ex>5__3 = null;
			<>1__state = -2;
		}

		private bool MoveNext()
		{
			switch (<>1__state)
			{
			default:
				return false;
			case 0:
				<>1__state = -1;
				if (original == null)
				{
					return false;
				}
				break;
			case 1:
				<>1__state = -1;
				ForceShipDoorsClosedNow();
				<current>5__2 = null;
				break;
			}
			try
			{
				<moveNext>5__1 = original.MoveNext();
				<current>5__2 = (<moveNext>5__1 ? original.Current : null);
			}
			catch (Exception ex)
			{
				<ex>5__3 = ex;
				D("Ship door coroutine wrapper from " + source + " failed: " + <ex>5__3.Message);
				throw;
			}
			ForceShipDoorsClosedNow();
			if (<moveNext>5__1)
			{
				<>2__current = <current>5__2;
				<>1__state = 1;
				return true;
			}
			ForceShipDoorsClosedNow();
			return false;
		}

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

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

	[CompilerGenerated]
	private sealed class <MaintainLocalInsideFactoryStateCoroutine>d__453 : IEnumerator<object>, IDisposable, IEnumerator
	{
		private int <>1__state;

		private object <>2__current;

		public float seconds;

		private float <end>5__1;

		private PlayerControllerB <player>5__2;

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

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

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

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

		private bool MoveNext()
		{
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Expected O, but got Unknown
			switch (<>1__state)
			{
			default:
				return false;
			case 0:
				<>1__state = -1;
				<end>5__1 = Time.realtimeSinceStartup + Mathf.Max(0.25f, seconds);
				break;
			case 1:
				<>1__state = -1;
				<player>5__2 = null;
				break;
			}
			if (Time.realtimeSinceStartup < <end>5__1)
			{
				<player>5__2 = StartOfRound.Instance?.localPlayerController;
				if ((Object)(object)<player>5__2 == (Object)null || <player>5__2.isPlayerDead || <player>5__2.disconnectedMidGame)
				{
					return false;
				}
				if ((Object)(object)StartOfRound.Instance != (Object)null && StartOfRound.Instance.shipIsLeaving)
				{
					return false;
				}
				ApplyPlayerInsideFactoryState(<player>5__2);
				<>2__current = (object)new WaitForSeconds(0.2f);
				<>1__state = 1;
				return true;
			}
			return false;
		}

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

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

	[CompilerGenerated]
	private sealed class <RoundStartFacilityTeleportRoutine>d__357 : IEnumerator<object>, IDisposable, IEnumerator
	{
		private int <>1__state;

		private object <>2__current;

		public string reason;

		private float <delay>5__1;

		private float <waitForLandingMax>5__2;

		private float <landingWaitStart>5__3;

		private int <token>5__4;

		private float <retrySeconds>5__5;

		private float <retryInterval>5__6;

		private float <endTime>5__7;

		private string <destination>5__8;

		private int <pass>5__9;

		private int <sent>5__10;

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

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

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

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

		private bool MoveNext()
		{
			//IL_0163: Unknown result type (might be due to invalid IL or missing references)
			//IL_016d: Expected O, but got Unknown
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Expected O, but got Unknown
			//IL_039e: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a8: Expected O, but got Unknown
			switch (<>1__state)
			{
			default:
				return false;
			case 0:
				<>1__state = -1;
				if (!IsServer() || !_hasCube || (Object)(object)StartOfRound.Instance == (Object)null)
				{
					return false;
				}
				_roundStartTeleportRoutineRunning = true;
				<delay>5__1 = Mathf.Max(0f, (_roundStartTeleportDelay != null) ? _roundStartTeleportDelay.Value : 1.25f);
				if (<delay>5__1 > 0f)
				{
					<>2__current = (object)new WaitForSeconds(<delay>5__1);
					<>1__state = 1;
					return true;
				}
				<>2__current = null;
				<>1__state = 2;
				return true;
			case 1:
				<>1__state = -1;
				goto IL_00de;
			case 2:
				<>1__state = -1;
				goto IL_00de;
			case 3:
				<>1__state = -1;
				goto IL_017e;
			case 4:
				{
					<>1__state = -1;
					break;
				}
				IL_00de:
				<waitForLandingMax>5__2 = Mathf.Max(0f, (_roundStartTeleportWaitForLandingSeconds != null) ? _roundStartTeleportWaitForLandingSeconds.Value : 12f);
				<landingWaitStart>5__3 = Time.realtimeSinceStartup;
				goto IL_017e;
				IL_017e:
				if (!IsRoundStartFacilityTeleportMomentSafe())
				{
					if (!(<waitForLandingMax>5__2 <= 0f) && !(Time.realtimeSinceStartup - <landingWaitStart>5__3 >= <waitForLandingMax>5__2))
					{
						<>2__current = (object)new WaitForSeconds(0.25f);
						<>1__state = 3;
						return true;
					}
					D($"Round-start teleport landing wait expired after {<waitForLandingMax>5__2:0.0}s. Applying anyway.");
				}
				if (!IsServer() || !_hasCube || (Object)(object)StartOfRound.Instance == (Object)null || StartOfRound.Instance.shipIsLeaving || _cubeExtractionPassed)
				{
					_roundStartTeleportRoutineRunning = false;
					return false;
				}
				_roundStartCubeTeleportToken++;
				<token>5__4 = _roundStartCubeTeleportToken;
				_roundStartTeleportTargetsByClient.Clear();
				<retrySeconds>5__5 = Mathf.Max(2f, (_roundStartTeleportRetrySeconds != null) ? _roundStartTeleportRetrySeconds.Value : 12f);
				<retryInterval>5__6 = Mathf.Clamp((_roundStartTeleportRetryInterval != null) ? _roundStartTeleportRetryInterval.Value : 0.75f, 0.15f, 3f);
				<endTime>5__7 = Time.realtimeSinceStartup + <retrySeconds>5__5;
				_roundStartCubeTeleportWindowOpen = true;
				_roundStartCubeTeleportWindowEndTime = <endTime>5__7;
				<destination>5__8 = (RoundStartTeleportUsesCube() ? "the Extraction Area" : "random facility spot");
				D($"Started token-safe round-start facility teleport token={<token>5__4}, destination={<destination>5__8}, reason={reason}, retrySeconds={<retrySeconds>5__5:0.0}, interval={<retryInterval>5__6:0.00}");
				<pass>5__9 = 0;
				break;
			}
			if (Time.realtimeSinceStartup <= <endTime>5__7)
			{
				<pass>5__9++;
				if (IsServer() && _hasCube && !((Object)(object)StartOfRound.Instance == (Object)null) && !StartOfRound.Instance.shipIsLeaving && !_cubeExtractionPassed)
				{
					<sent>5__10 = TeleportAllControlledPlayersIntoFacilityOnHost(<token>5__4, reason, <pass>5__9);
					if (<pass>5__9 == 1 || <sent>5__10 > 0)
					{
						D($"Round-start teleport pass {<pass>5__9} sent/applied token={<token>5__4} to {<sent>5__10} living controlled player(s).");
					}
					BroadcastCubePosition();
					<>2__current = (object)new WaitForSeconds(<retryInterval>5__6);
					<>1__state = 4;
					return true;
				}
			}
			_roundStartCubeTeleportWindowOpen = false;
			_roundStartCubeTeleportWindowEndTime = 0f;
			_roundStartTeleportRoutineRunning = false;
			BroadcastCubePosition();
			D($"Round-start facility teleport retry window closed. token={<token>5__4}");
			return false;
		}

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

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

	[CompilerGenerated]
	private sealed class <SpawnCubeAfterFrame>d__197 : IEnumerator<object>, IDisposable, IEnumerator
	{
		private int <>1__state;

		private object <>2__current;

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

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

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

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

		private bool MoveNext()
		{
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Unknown result type (might be due to invalid IL or missing references)
			//IL_0162: Unknown result type (might be due to invalid IL or missing references)
			//IL_0177: Unknown result type (might be due to invalid IL or missing references)
			switch (<>1__state)
			{
			default:
				return false;
			case 0:
				<>1__state = -1;
				<>2__current = null;
				<>1__state = 1;
				return true;
			case 1:
				<>1__state = -1;
				_processedThisTakeoff = false;
				_cubeEffectiveHeightOverride = -1f;
				_cubeExtractionPassed = false;
				_earlyExtractionCountdownActive = false;
				_earlyExtractionCountdownEndTime = 0f;
				_earlyExtractionCountdownSecondsRemaining = 0;
				_earlyExtractionTriggered = false;
				ClearBaseGameSpectatorVoteToLeaveState("round cube spawn start", resetVanillaTimeOfDayFields: true);
				CaptureNormalShipLeaveAutomaticallyTime("round cube spawn start");
				_earlyVoteEligible = false;
				_earlyVoteCount = 0;
				_earlyVoteRequired = 0;
				_localEarlyVoteSubmitted = false;
				_earlyVoteRosterKey = string.Empty;
				_earlyExtractionVotes.Clear();
				_lastEarlyVoteSyncSignature = string.Empty;
				_currentCubeScrapRawValue = 0;
				_currentCubeScrapCount = 0;
				_roundStartCubeTeleportWindowOpen = false;
				_roundStartCubeTeleportWindowEndTime = 0f;
				_roundStartTeleportRequested = false;
				_roundStartTeleportFloorReady = false;
				_roundStartTeleportStarted = false;
				_roundStartTeleportRoutineRunning = false;
				_cubePostReadyPlacementFinalized = false;
				_roundStartTeleportRequestTime = 0f;
				_roundStartTeleportRequestReason = string.Empty;
				_roundStartTeleportTargetsByClient.Clear();
				_lastInsideFactoryBestEffortTimeByClient.Clear();
				_lastInsideAudioLightingBestEffortTimeByClient.Clear();
				_cachedInteriorEntranceReachabilityAnchors.Clear();
				_cachedInteriorEntranceReachabilityAnchorsFrame = -1;
				_localPendingRoundStartCubeTeleportToken = -1;
				_localAppliedRoundStartCubeTeleportToken = -1;
				if (IsServer())
				{
					_cubeCenter = PickCubePosition();
					_hasCube = true;
					D($"Host picked Extraction Area center: {_cubeCenter}");
					CreateOrMoveCubeVisual(_cubeCenter);
					BroadcastCubePosition();
					if (_teleportPlayersToCubeOnRoundStart.Value)
					{
						RequestRoundStartCubeTeleport("round start cube placed");
					}
				}
				else
				{
					D("Client finished dungeon generation. Waiting for host cube sync.");
				}
				return false;
			}
		}

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

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

	public const string ModGuid = "robert.lethalcompany.extraction";

	public const string ModName = "Extraction";

	public const string ModVersion = "0.2.37";

	private const string MsgCubeSync = "Extraction_CubeSync_v1";

	private const string MsgTeleport = "Extraction_Teleport_v1";

	private const string MsgQuotaSync = "Extraction_QuotaSync_v1";

	private const string MsgCubeClosed = "Extraction_CubeClosed_v1";

	private const string MsgEarlyVoteRequest = "Extraction_EarlyVoteRequest_v1";

	private const string MsgEarlyVoteSync = "Extraction_EarlyVoteSync_v1";

	private const string MsgRoundStartCubeTeleport = "Extraction_RoundStartCubeTeleport_v1";

	internal static Plugin Instance;

	internal static ManualLogSource Log;

	private static Harmony _harmony;

	private static ConfigEntry<bool> _debugLogging;

	private static ConfigEntry<bool> _enableDebugCommands;

	private static ConfigEntry<bool> _hostOnlyDebugCommands;

	private static ConfigEntry<float> _cubeSize;

	private static ConfigEntry<float> _cubeHeight;

	private static ConfigEntry<float> _cubeVisualAlpha;

	private static ConfigEntry<float> _groundSnapRayStartHeight;

	private static ConfigEntry<float> _groundSnapRayDistance;

	private static ConfigEntry<bool> _applyCompanyBuyingRate;

	private static ConfigEntry<bool> _requireAllControlledPlayersAlive;

	private static ConfigEntry<int> _minDistanceFromShip;

	private static ConfigEntry<float> _cubePlacementWallClearance;

	private static ConfigEntry<float> _cubePlacementFloorInset;

	private static ConfigEntry<float> _cubePlacementMaxFloorDrop;

	private static ConfigEntry<float> _cubePlacementSearchRadius;

	private static ConfigEntry<float> _cubePlacementSearchStep;

	private static ConfigEntry<int> _cubePlacementMaxCandidates;

	private static ConfigEntry<bool> _cubePlacementRejectDangerTriggers;

	private static ConfigEntry<bool> _cubePlacementRequireNavMesh;

	private static ConfigEntry<bool> _cubePlacementRequireReachablePathFromEntrance;

	private static ConfigEntry<bool> _cubePlacementRejectBackfaceGeometry;

	private static ConfigEntry<bool> _cubePlacementPreferScrapSpawnAnchors;

	private static ConfigEntry<bool> _cubePlacementUseEntrancesAndFireExitsOnly;

	private static ConfigEntry<bool> _adaptiveForcefieldBounds;

	private static ConfigEntry<bool> _adaptiveForcefieldDynamicFootprint;

	private static ConfigEntry<bool> _adaptiveForcefieldFreezeShapeAfterBuild;

	private static ConfigEntry<bool> _adaptiveForcefieldSimplifyMesh;

	private static ConfigEntry<float> _adaptiveForcefieldClearance;

	private static ConfigEntry<float> _adaptiveForcefieldMinimumSide;

	private static ConfigEntry<float> _adaptiveForcefieldFloorProbeStep;

	private static ConfigEntry<float> _adaptiveForcefieldBoundaryInset;

	private static ConfigEntry<bool> _showInsideCubeHud;

	private static ConfigEntry<bool> _showInsideCubeTips;

	private static ConfigEntry<bool> _teleportPlayersToCubeOnRoundStart;

	private static ConfigEntry<bool> _roundStartTeleportToCube;

	private static ConfigEntry<float> _roundStartTeleportDelay;

	private static ConfigEntry<float> _roundStartTeleportRetrySeconds;

	private static ConfigEntry<float> _roundStartTeleportRetryInterval;

	private static ConfigEntry<float> _roundStartTeleportMaxWaitForFloorReady;

	private static ConfigEntry<float> _roundStartTeleportMaintainInsideSeconds;

	private static ConfigEntry<float> _roundStartTeleportWaitForLandingSeconds;

	private static ConfigEntry<bool> _enableCubeLight;

	private static ConfigEntry<float> _cubeLightIntensity;

	private static ConfigEntry<float> _cubeLightRange;

	private static ConfigEntry<bool> _enableCubeScrapGlow;

	private static ConfigEntry<float> _cubeScrapGlowRefreshInterval;

	private static ConfigEntry<float> _cubeScrapGlowEmissionStrength;

	private static ConfigEntry<float> _cubeScrapGlowLightIntensity;

	private static ConfigEntry<float> _cubeScrapGlowLightRange;

	private static ConfigEntry<bool> _enableEarlyExtractionVote;

	private static ConfigEntry<KeyCode> _earlyExtractionVoteKey;

	private static ConfigEntry<float> _earlyExtractionVoteSyncInterval;

	private static ConfigEntry<float> _earlyExtractionCountdownSeconds;

	private static ConfigEntry<bool> _disableBaseGameSpectatorVoteToLeave;

	private static ConfigEntry<bool> _keepShipDoorsClosed;

	private static ConfigEntry<bool> _disableFacilityExitInteractions;

	private static ConfigEntry<bool> _enableScrapVisibility;

	private static ConfigEntry<bool> _disableManualRightClickScan;

	private static ConfigEntry<bool> _showScrapValueText;

	private static ConfigEntry<bool> _showScrapModelGlow;

	private static ConfigEntry<bool> _showScrapLight;

	private static ConfigEntry<bool> _hideScrapTextBehindWalls;

	private static ConfigEntry<float> _scrapVisibilityMaxDistance;

	private static ConfigEntry<float> _scrapVisibilityRefreshInterval;

	private static ConfigEntry<float> _scrapTextSize;

	private static ConfigEntry<float> _scrapTextHeightOffset;

	private static ConfigEntry<float> _scrapTintStrength;

	private static ConfigEntry<float> _scrapEmissionStrength;

	private static ConfigEntry<float> _scrapLightIntensity;

	private static ConfigEntry<float> _scrapLightRange;

	private static ConfigEntry<float> _scrapPulseSpeed;

	private static ConfigEntry<float> _scrapTextOcclusionPadding;

	private static ConfigEntry<float> _scrapScreenEdgeMargin;

	private static ConfigEntry<float> _scrapTextVisibilityGraceTime;

	private static GameObject _cubeVisual;

	private static string _cubeVisualMeshSignature = string.Empty;

	private static bool _clientCubeVisualRefreshRunning;

	private static GameObject _cubeLightObject;

	private static GameObject _shipDoorClosedOverlay;

	private static GameObject _shipDoorFallbackPanel;

	private static Material _shipDoorFallbackMaterial;

	private static bool _shipDoorOverlaySourceMissingLogged;

	private static readonly Dictionary<Renderer, bool> _shipDoorOriginalRendererStates = new Dictionary<Renderer, bool>();

	private static readonly Dictionary<Component, ShipDoorAudioState> _shipDoorOriginalAudioStates = new Dictionary<Component, ShipDoorAudioState>();

	private static readonly Dictionary<GrabbableObject, ScrapGlowState> _glowingCubeScrap = new Dictionary<GrabbableObject, ScrapGlowState>();

	private static bool _localPlayerInsideCube;

	private static float _cubeScrapGlowTimer;

	private GUIStyle _insideCubeHudStyle;

	private static Vector3 _cubeCenter;

	private static Vector3 _cubeDimensions = new Vector3(6f, 6f, 6f);

	private static float _cubeEffectiveHeightOverride = -1f;

	private static bool _cubeDynamicFootprintReady;

	private static float _cubeDynamicFootprintCellSize = 0.75f;

	private static float _cubeDynamicFootprintBottomY;

	private static float _cubeDynamicFootprintHorizontalSize = 6f;

	private static float _cubeDynamicFootprintHeight = 6f;

	private static Bounds _cubeDynamicFootprintBounds;

	private static readonly HashSet<int> _cubeDynamicFootprintCells = new HashSet<int>();

	private static bool _cubeDynamicFootprintLocked;

	private static Vector3 _cubeDynamicFootprintLockedCenter;

	private static float _cubeDynamicFootprintLockedSize;

	private static float _cubeDynamicFootprintLockedHeight;

	private static float _cubeDynamicFootprintLockedCellSize;

	private static Mesh _cubeDynamicFootprintSurfaceMesh;

	private static Mesh _cubeDynamicFootprintFrameMesh;

	private static Mesh _cubeDynamicFootprintBandMesh;

	private static bool _hasCube;

	private static bool _processedThisTakeoff;

	private static bool _messagesRegistered;

	private static bool _clientConnectCallbackRegistered;

	private static RoundManager _eventSubscribedRoundManager;

	private static bool _cubeExtractionPassed;

	private static float _cubeScrapValueTimer;

	private static int _currentCubeScrapRawValue;

	private static int _currentCubeScrapCount;

	private static int _pendingQuotaValue;

	private static int _pendingRawValue;

	private static int _pendingItemCount;

	private static bool _pendingQuotaApplied;

	private static Transform _scrapTextRoot;

	private static float _scrapVisibilityAttachTimer;

	private static readonly HashSet<int> _earlyExtractionVotes = new HashSet<int>();

	private static bool _earlyVoteEligible;

	private static int _earlyVoteCount;

	private static int _earlyVoteRequired;

	private static bool _localEarlyVoteSubmitted;

	private static bool _earlyExtractionCountdownActive;

	private static float _earlyExtractionCountdownEndTime;

	private static int _earlyExtractionCountdownSecondsRemaining;

	private static bool _earlyExtractionTriggered;

	private static bool _baseGameVoteToLeaveUrgencyActive;

	private static bool _baseGameVoteToLeaveObserved;

	private static bool _normalShipLeaveAutomaticallyTimeCaptured;

	private static float _normalShipLeaveAutomaticallyTime = -1f;

	private static string _earlyVoteRosterKey = string.Empty;

	private static string _lastEarlyVoteSyncSignature = string.Empty;

	private static float _earlyVoteSyncTimer;

	private static bool _roundStartCubeTeleportWindowOpen;

	private static int _roundStartCubeTeleportToken;

	private static int _localAppliedRoundStartCubeTeleportToken = -1;

	private static int _localPendingRoundStartCubeTeleportToken = -1;

	private static float _roundStartCubeTeleportWindowEndTime;

	private static bool _roundStartTeleportRequested;

	private static bool _roundStartTeleportFloorReady;

	private static bool _roundStartTeleportStarted;

	private static float _roundStartTeleportRequestTime;

	private static string _roundStartTeleportRequestReason = string.Empty;

	private static bool _roundStartTeleportRoutineRunning;

	private static bool _cubePostReadyPlacementFinalized;

	private static readonly Dictionary<ulong, Vector3> _roundStartTeleportTargetsByClient = new Dictionary<ulong, Vector3>();

	private static readonly Dictionary<ulong, float> _lastInsideFactoryBestEffortTimeByClient = new Dictionary<ulong, float>();

	private static readonly Dictionary<ulong, float> _lastInsideAudioLightingBestEffortTimeByClient = new Dictionary<ulong, float>();

	private static Type _audioReverbTriggerType;

	private static bool _audioReverbTriggerTypeSearched;

	private static readonly List<Vector3> _cachedInteriorEntranceReachabilityAnchors = new List<Vector3>();

	private static int _cachedInteriorEntranceReachabilityAnchorsFrame = -1;

	private static bool _legacyInputFailureLogged;

	private static bool _inputSystemFailureLogged;

	private static bool _navMeshReflectionInitialized;

	private static bool _navMeshReflectionAvailable;

	private static bool _navMeshUnavailableLogged;

	private static Type _navMeshType;

	private static Type _navMeshHitType;

	private static MethodInfo _navMeshSamplePositionMethod;

	private static Type _navMeshPathType;

	private static MethodInfo _navMeshCalculatePathMethod;

	private static PropertyInfo _navMeshPathStatusProperty;

	private static bool _navMeshPathUnavailableLogged;

	private static bool _entrancePathUnavailableLogged;

	private static PropertyInfo _navMeshHitPositionProperty;

	private static FieldInfo _navMeshHitPositionField;

	private float _lateSyncTimer;

	private float _exitInteractionClampTimer;

	private void Awake()
	{
		//IL_0c17: Unknown result type (might be due to invalid IL or missing references)
		//IL_0c21: Expected O, but got Unknown
		Instance = this;
		Log = ((BaseUnityPlugin)this).Logger;
		_debugLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "DebugLogging", true, "Write detailed Extraction logs to the BepInEx console/log file.");
		_enableDebugCommands = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "EnableChatDebugCommands", true, "Enables chat commands: tpcube, endday, cubepos, countcube, extractionhelp.");
		_hostOnlyDebugCommands = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "HostOnlyDebugCommands", true, "Only the host can use debug commands.");
		_cubeSize = ((BaseUnityPlugin)this).Config.Bind<float>("Cube", "CubeSizeMeters", 6f, "Horizontal size of the Extraction Area in meters. This controls width and depth only.");
		_cubeHeight = ((BaseUnityPlugin)this).Config.Bind<float>("Cube", "CubeHeightMeters", 6f, "Requested roof height of the Extraction Area in meters. The mod will try to place the area where this full height fits. If it cannot, it retries at 80% height steps.");
		_cubeVisualAlpha = ((BaseUnityPlugin)this).Config.Bind<float>("Cube", "CubeVisualAlpha", 0.1f, "Transparency of the Extraction Area visual. 0 is invisible. 1 is solid. Default is 0.1.");
		_groundSnapRayStartHeight = ((BaseUnityPlugin)this).Config.Bind<float>("Cube", "GroundSnapRayStartHeight", 6f, "How far above the picked node to start the downward floor snap ray.");
		_groundSnapRayDistance = ((BaseUnityPlugin)this).Config.Bind<float>("Cube", "GroundSnapRayDistance", 20f, "How far below the picked node to search for floor when placing the Extraction Area.");
		_minDistanceFromShip = ((BaseUnityPlugin)this).Config.Bind<int>("Cube", "MinimumDistanceFromShip", 25, "Try to place the Extraction Area at least this many meters from the ship/elevator transform.");
		_cubePlacementWallClearance = ((BaseUnityPlugin)this).Config.Bind<float>("Cube", "CubePlacementWallClearanceMeters", 2.5f, "Extra empty space required past the Extraction Area footprint when choosing a spawn position. Higher values keep the placement farther from walls and map edges.");
		_cubePlacementFloorInset = ((BaseUnityPlugin)this).Config.Bind<float>("Cube", "CubePlacementFloorSampleInsetMeters", 0.2f, "How far inside the Extraction Area edge the floor safety samples are checked. Smaller values are stricter near voids and ledges.");
		_cubePlacementMaxFloorDrop = ((BaseUnityPlugin)this).Config.Bind<float>("Cube", "CubePlacementMaxFloorDropMeters", 1.25f, "Maximum allowed drop from an inside AI node to the snapped floor. Prevents snapping the Extraction Area down into pits, lower catwalk kill boxes, or the void.");
		_cubePlacementSearchRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Cube", "CubePlacementSearchRadiusMeters", 12f, "How far around each inside AI node to search for a centered safe cube position.");
		_cubePlacementSearchStep = ((BaseUnityPlugin)this).Config.Bind<float>("Cube", "CubePlacementSearchStepMeters", 1.5f, "Grid step used while searching around an inside AI node for a safe cube position.");
		_cubePlacementMaxCandidates = ((BaseUnityPlugin)this).Config.Bind<int>("Cube", "CubePlacementMaxCandidates", 8000, "Maximum number of cube placement candidates to test before using the safest emergency fallback.");
		_cubePlacementRejectDangerTriggers = ((BaseUnityPlugin)this).Config.Bind<bool>("Cube", "CubePlacementRejectDangerTriggers", true, "Reject cube positions overlapping kill boxes, death triggers, out-of-bounds triggers, pits, or other dangerous trigger volumes.");
		_cubePlacementRequireNavMesh = ((BaseUnityPlugin)this).Config.Bind<bool>("Cube", "CubePlacementRequireNavMesh", true, "Require the Extraction Area teleport spot to be close to the facility navmesh when Unity exposes it. This helps prevent out-of-map or unreachable placements.");
		_cubePlacementRequireReachablePathFromEntrance = ((BaseUnityPlugin)this).Config.Bind<bool>("Cube", "CubePlacementRequireReachablePathFromEntrance", true, "Require the Extraction Area center/player spawn spot to have a complete NavMesh path from an interior entrance. This is the main guard against inaccessible prefab corners, voids, and out-of-map rooms.");
		_cubePlacementRejectBackfaceGeometry = ((BaseUnityPlugin)this).Config.Bind<bool>("Cube", "CubePlacementRejectBackfaceGeometry", true, "Reject spots where physics rays detect the player is on the back side of one-sided level geometry. This catches many out-of-bounds/backside-wall cases.");
		_cubePlacementPreferScrapSpawnAnchors = ((BaseUnityPlugin)this).Config.Bind<bool>("Cube", "CubePlacementPreferScrapSpawnAnchors", true, "Legacy fallback only. Ignored when CubePlacementUseEntrancesAndFireExitsOnly is true.");
		_cubePlacementUseEntrancesAndFireExitsOnly = ((BaseUnityPlugin)this).Config.Bind<bool>("Cube", "CubePlacementUseEntrancesAndFireExitsOnly", true, "If true, the Extraction Area only spawns at the real underground/interior side of main entrances and fire exits. This avoids slow wide-area searches, surface door spawns, and unreachable prefab corners.");
		_adaptiveForcefieldBounds = ((BaseUnityPlugin)this).Config.Bind<bool>("Cube", "AdaptiveForcefieldBounds", true, "If true, the Extraction Area forcefield uses adaptive environment shaping instead of clipping through walls, ledges, pits, and non-navmesh space. Props are ignored.");
		_adaptiveForcefieldDynamicFootprint = ((BaseUnityPlugin)this).Config.Bind<bool>("Cube", "AdaptiveForcefieldDynamicFootprint", true, "If true, the Extraction Area uses a connected navmesh footprint that can form L shapes and wrap around invalid walkable space instead of only resizing as a box.");
		_adaptiveForcefieldFreezeShapeAfterBuild = ((BaseUnityPlugin)this).Config.Bind<bool>("Cube", "AdaptiveForcefieldFreezeShapeAfterBuild", true, "If true, the Extraction Area calculates its dynamic footprint once when spawned, then never recalculates it until the Extraction Area is moved for a new round.");
		_adaptiveForcefieldSimplifyMesh = ((BaseUnityPlugin)this).Config.Bind<bool>("Cube", "AdaptiveForcefieldSimplifyMesh", true, "If true, merges dynamic forcefield cell slices into long faces and main corners after the footprint is finalized.");
		_adaptiveForcefieldClearance = ((BaseUnityPlugin)this).Config.Bind<float>("Cube", "AdaptiveForcefieldClearanceMeters", 0.18f, "Gap kept between the forcefield wall and nearby level geometry or ceiling when adaptive bounds are enabled.");
		_adaptiveForcefieldMinimumSide = ((BaseUnityPlugin)this).Config.Bind<float>("Cube", "AdaptiveForcefieldMinimumSideMeters", 1.25f, "Smallest horizontal side the Extraction Area forcefield may shrink to when adaptive bounds are enabled.");
		_adaptiveForcefieldFloorProbeStep = ((BaseUnityPlugin)this).Config.Bind<float>("Cube", "AdaptiveForcefieldFloorProbeStepMeters", 0.45f, "Step size used to stop the adaptive Extraction Area bounds before non-navmesh cells, floor gaps, pits, or unsupported catwalk edges.");
		_adaptiveForcefieldBoundaryInset = ((BaseUnityPlugin)this).Config.Bind<float>("Cube", "AdaptiveForcefieldBoundaryInsetMeters", 0f, "Deprecated. Boundary inset is ignored and kept at 0 so the forcefield footprint is not artificially shrunken.");
		if (_adaptiveForcefieldBoundaryInset != null && _adaptiveForcefieldBoundaryInset.Value > 0f)
		{
			_adaptiveForcefieldBoundaryInset.Value = 0f;
		}
		_showInsideCubeHud = ((BaseUnityPlugin)this).Config.Bind<bool>("HUD", "ShowInsideCubeHud", true, "Show an on-screen message while your local player is inside the Extraction Area.");
		_showInsideCubeTips = ((BaseUnityPlugin)this).Config.Bind<bool>("HUD", "ShowInsideCubeEnterExitTips", true, "Legacy config. No longer used because cube detection now only updates the HUD overlay.");
		_teleportPlayersToCubeOnRoundStart = ((BaseUnityPlugin)this).Config.Bind<bool>("Rules", "TeleportPlayersToCubeOnRoundStart", true, "Master toggle for round-start facility teleport. If false, players stay wherever vanilla puts them.");
		_roundStartTeleportToCube = ((BaseUnityPlugin)this).Config.Bind<bool>("Rules", "RoundStartTeleportToCube", true, "If true, round-start teleport sends players to the Extraction Area. If false, players are sent to a random safe facility position and must find the Extraction Area.");
		_roundStartTeleportDelay = ((BaseUnityPlugin)this).Config.Bind<float>("Rules", "RoundStartCubeTeleportDelaySeconds", 1.25f, "Delay after the game reports players finished generating the floor before the teleport routine begins.");
		_roundStartTeleportRetrySeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Rules", "RoundStartCubeTeleportRetrySeconds", 12f, "How long the host keeps resending the same round-start teleport token. Clients only apply that token once.");
		_roundStartTeleportRetryInterval = ((BaseUnityPlugin)this).Config.Bind<float>("Rules", "RoundStartCubeTeleportRetryIntervalSeconds", 0.75f, "How often the host resends the same round-start teleport token during the retry window.");
		_roundStartTeleportMaxWaitForFloorReady = ((BaseUnityPlugin)this).Config.Bind<float>("Rules", "RoundStartCubeTeleportMaxWaitForFloorReadySeconds", 45f, "Fallback only. If the game never fires the fully-ready level callback, start round-start facility teleport after this many seconds.");
		_roundStartTeleportMaintainInsideSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Rules", "RoundStartMaintainInsideStateSeconds", 8f, "After round-start teleport, keep reapplying inside-factory player flags for this long to stop vanilla from snapping players back to ship state.");
		_roundStartTeleportWaitForLandingSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Rules", "RoundStartWaitForLandingMaxSeconds", 12f, "Maximum extra time to wait for the ship/round start state before applying the facility teleport.");
		_enableCubeLight = ((BaseUnityPlugin)this).Config.Bind<bool>("Visuals", "EnableCubeLight", true, "Adds a yellow point light inside the Extraction Area.");
		_cubeLightIntensity = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "CubeLightIntensity", 2.2f, "Point light intensity for the Extraction Area.");
		_cubeLightRange = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "CubeLightRange", 7.5f, "Point light range for the Extraction Area.");
		_enableCubeScrapGlow = ((BaseUnityPlugin)this).Config.Bind<bool>("Visuals", "EnableCubeScrapGlow", true, "Loose scrap currently inside the Extraction Area glows red. This is visual only.");
		_cubeScrapGlowRefreshInterval = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "CubeScrapGlowRefreshInterval", 0.15f, "How often to refresh red glow state for scrap inside the Extraction Area.");
		_cubeScrapGlowEmissionStrength = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "CubeScrapGlowEmissionStrength", 4f, "Red emission strength used on scrap that is inside the Extraction Area.");
		_cubeScrapGlowLightIntensity = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "CubeScrapGlowLightIntensity", 1.25f, "Small red point light intensity on scrap that is inside the Extraction Area. Set to 0 to disable item lights.");
		_cubeScrapGlowLightRange = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "CubeScrapGlowLightRange", 2.25f, "Small red point light range on scrap that is inside the Extraction Area.");
		_enableEarlyExtractionVote = ((BaseUnityPlugin)this).Config.Bind<bool>("Rules", "EnableEarlyExtractionVote", true, "If true, all living players can vote from inside the Extraction Area to extract early.");
		_earlyExtractionVoteKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Rules", "EarlyExtractionVoteKey", (KeyCode)114, "Key used to vote for early extraction while all living players are inside the Extraction Area.");
		_earlyExtractionVoteSyncInterval = ((BaseUnityPlugin)this).Config.Bind<float>("Rules", "EarlyExtractionVoteSyncInterval", 0.2f, "How often the host refreshes the early extraction vote HUD state while eligible.");
		_earlyExtractionCountdownSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Rules", "EarlyExtractionCountdownSeconds", 10f, "Seconds to wait after all required Extraction Area votes are in before early extraction starts. If anyone leaves the Extraction Area during this countdown, voting resets.");
		_disableBaseGameSpectatorVoteToLeave = ((BaseUnityPlugin)this).Config.Bind<bool>("Rules", "DisableBaseGameSpectatorVoteToLeave", false, "If true, blocks the vanilla dead-spectator vote to leave early. This does not affect the Extraction Area early extraction vote.");
		_keepShipDoorsClosed = ((BaseUnityPlugin)this).Config.Bind<bool>("Rules", "KeepShipDoorsClosed", true, "If true, players see and collide with a closed ship door overlay and the door buttons are disabled. Vanilla door coroutines are allowed to run so level loading does not get stuck.");
		_disableFacilityExitInteractions = ((BaseUnityPlugin)this).Config.Bind<bool>("Rules", "DisableFacilityExitInteractions", true, "If true, main entrances and fire exits cannot be used and their interact prompts are hidden. Players must leave through the Extraction Area.");
		if (Mathf.Approximately(_cubeSize.Value, 3f))
		{
			_cubeSize.Value = 6f;
		}
		if (Mathf.Approximately(_cubeVisualAlpha.Value, 0.5f))
		{
			_cubeVisualAlpha.Value = 0.1f;
		}
		if (Mathf.Approximately(_cubePlacementWallClearance.Value, 0.65f) || Mathf.Approximately(_cubePlacementWallClearance.Value, 1.75f))
		{
			_cubePlacementWallClearance.Value = 2.5f;
		}
		if (Mathf.Approximately(_cubePlacementFloorInset.Value, 0.45f))
		{
			_cubePlacementFloorInset.Value = 0.2f;
		}
		if (_cubePlacementMaxCandidates.Value == 4500)
		{
			_cubePlacementMaxCandidates.Value = 8000;
		}
		if (Mathf.Approximately(_cubePlacementSearchRadius.Value, 9f))
		{
			_cubePlacementSearchRadius.Value = 12f;
		}
		if (Mathf.Approximately(_roundStartTeleportDelay.Value, 2.5f) || Mathf.Approximately(_roundStartTeleportDelay.Value, 0.75f))
		{
			_roundStartTeleportDelay.Value = 1.25f;
		}
		if (Mathf.Approximately(_roundStartTeleportRetrySeconds.Value, 0f) || Mathf.Approximately(_roundStartTeleportRetrySeconds.Value, 16f) || Mathf.Approximately(_roundStartTeleportRetrySeconds.Value, 28f))
		{
			_roundStartTeleportRetrySeconds.Value = 12f;
		}
		if (Mathf.Approximately(_roundStartTeleportRetryInterval.Value, 0f) || Mathf.Approximately(_roundStartTeleportRetryInterval.Value, 1f))
		{
			_roundStartTeleportRetryInterval.Value = 0.75f;
		}
		_enableScrapVisibility = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enable integrated scrap visibility", true, "If true, the Extraction Area uses the original ScrapVisibility highlighter code inside this plugin. This includes tools/non-scrap items.");
		_disableManualRightClickScan = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Disable manual right click scan", true, "If true, normal right click scan is blocked.");
		_showScrapModelGlow = ((BaseUnityPlugin)this).Config.Bind<bool>("Display", "Show model glow", true, "Tints the real item model.");
		_showScrapValueText = ((BaseUnityPlugin)this).Config.Bind<bool>("Display", "Show 3D text", true, "Show item name and value above scrap, and item names above tools/non-scrap items.");
		_showScrapLight = ((BaseUnityPlugin)this).Config.Bind<bool>("Display", "Show apparatus style light", true, "Adds a real 3D point light to items.");
		_hideScrapTextBehindWalls = ((BaseUnityPlugin)this).Config.Bind<bool>("Display", "Hide text behind walls", true, "If true, text label hides when the item itself is blocked by walls.");
		_scrapVisibilityMaxDistance = ((BaseUnityPlugin)this).Config.Bind<float>("Visibility", "Max display distance", 120f, "Maximum distance for item highlights and labels.");
		_scrapVisibilityRefreshInterval = ((BaseUnityPlugin)this).Config.Bind<float>("Performance", "Refresh interval", 1f, "How often the mod searches for items.");
		_scrapTintStrength = ((BaseUnityPlugin)this).Config.Bind<float>("Display", "Tint strength", 1f, "How strongly the model gets tinted.");
		_scrapEmissionStrength = ((BaseUnityPlugin)this).Config.Bind<float>("Display", "Emission strength", 5.5f, "How strongly the material emission is pushed.");
		_scrapTextSize = ((BaseUnityPlugin)this).Config.Bind<float>("Display", "Text size", 0.022f, "Base size of the 3D text above items.");
		_scrapTextHeightOffset = ((BaseUnityPlugin)this).Config.Bind<float>("Display", "Text height offset", 0.38f, "How far above the item the text floats.");
		_scrapLightIntensity = ((BaseUnityPlugin)this).Config.Bind<float>("Display", "Light intensity", 6f, "Base brightness of the apparatus style light.");
		_scrapLightRange = ((BaseUnityPlugin)this).Config.Bind<float>("Display", "Light range", 6f, "Base range of the apparatus style light.");
		_scrapPulseSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("Display", "Pulse speed", 2.8f, "How fast the glow pulses.");
		_scrapTextOcclusionPadding = ((BaseUnityPlugin)this).Config.Bind<float>("Display", "Text occlusion padding", 0.12f, "How much of the end of the ray to ignore when checking if the item is blocked.");
		_scrapScreenEdgeMargin = ((BaseUnityPlugin)this).Config.Bind<float>("Display", "Screen edge margin", 0.12f, "Extra margin around the screen so text still shows near the edge/peripheral view.");
		_scrapTextVisibilityGraceTime = ((BaseUnityPlugin)this).Config.Bind<float>("Display", "Text visibility grace time", 0.2f, "How long text stays visible after one bad raycast. Helps stop flicker while moving.");
		_applyCompanyBuyingRate = ((BaseUnityPlugin)this).Config.Bind<bool>("Payout", "ApplyCompanyBuyingRate", false, "If true, cube scrap payout is multiplied by the current company buying rate. If false, full scrap value goes toward quota.");
		_requireAllControlledPlayersAlive = ((BaseUnityPlugin)this).Config.Bind<bool>("Rules", "RequireAllControlledPlayersAlive", false, "If true, extraction and Extraction Area payout only work when every controlled connected player is alive. If false, Extraction Area payout works as long as at least one controlled player is alive.");
		_harmony = new Harmony("robert.lethalcompany.extraction");
		_harmony.PatchAll();
		D("Plugin loaded. Harmony patches applied.");
	}

	private void Update()
	{
		EnsureMessageHandlers();
		EnsureRoundManagerEventSubscription();
		UpdateInsideCubeHudState();
		UpdateCubeScrapValueCacheLoop();
		UpdateEarlyExtractionVoteSystem();
		HandleEarlyExtractionVoteInput();
		UpdateQueuedRoundStartCubeTeleportFallback();
		UpdateBaseGameVoteToLeaveUrgencyState();
		UpdateShipDoorsLockedClosed();
		UpdateFacilityExitInteractionsLocked();
		UpdateCubePulseVisual();
		UpdateScrapVisibilityLoop();
		if (_enableScrapVisibility == null || !_enableScrapVisibility.Value)
		{
			UpdateCubeScrapGlowLoop();
		}
		else if (_glowingCubeScrap.Count > 0)
		{
			ClearAllCubeScrapGlow();
		}
		if (IsServer() && _hasCube && (Object)(object)NetworkManager.Singleton != (Object)null)
		{
			_lateSyncTimer += Time.deltaTime;
			if (_lateSyncTimer >= 5f)
			{
				_lateSyncTimer = 0f;
				BroadcastCubePosition();
			}
		}
	}

	private void OnGUI()
	{
		//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ea: Expected O, but got Unknown
		//IL_0045: Unknown result type (might be due to invalid IL or missing references)
		//IL_004f: Expected O, but got Unknown
		//IL_0088: Unknown result type (might be due to invalid IL or missing references)
		//IL_023c: Unknown result typ

plugins/Extraction/RandomSuit.dll

Decompiled 19 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("ScrapVisbility")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ScrapVisbility")]
[assembly: AssemblyCopyright("Copyright ©  2026")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("8a6853bd-bdc9-4741-95c7-5aa2c8c6a6f9")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace YourFurnace.RandomStartSuit;

[BepInPlugin("YourFurnace.RandomStartSuit", "RandomStartSuit", "1.1.0")]
public class Plugin : BaseUnityPlugin
{
	private sealed class Assignment
	{
		public ulong ClientId;

		public int PlayerIndex;

		public int SuitId;

		public string SuitName;

		public float ResendUntil;

		public float NextResend;
	}

	private sealed class SuitChoice
	{
		public int SuitId;

		public string SuitName;

		public object UnlockableItem;
	}

	[CompilerGenerated]
	private sealed class <GetAllPlayerScripts>d__38 : IEnumerable<object>, IEnumerable, IEnumerator<object>, IDisposable, IEnumerator
	{
		private int <>1__state;

		private object <>2__current;

		private int <>l__initialThreadId;

		private object startOfRound;

		public object <>3__startOfRound;

		private object <playersObject>5__1;

		private IEnumerable <players>5__2;

		private IEnumerator <>s__3;

		private object <player>5__4;

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

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

		[DebuggerHidden]
		public <GetAllPlayerScripts>d__38(int <>1__state)
		{
			this.<>1__state = <>1__state;
			<>l__initialThreadId = Environment.CurrentManagedThreadId;
		}

		[DebuggerHidden]
		void IDisposable.Dispose()
		{
			int num = <>1__state;
			if (num == -3 || num == 1)
			{
				try
				{
				}
				finally
				{
					<>m__Finally1();
				}
			}
			<playersObject>5__1 = null;
			<players>5__2 = null;
			<>s__3 = null;
			<player>5__4 = null;
			<>1__state = -2;
		}

		private bool MoveNext()
		{
			try
			{
				int num = <>1__state;
				if (num != 0)
				{
					if (num != 1)
					{
						return false;
					}
					<>1__state = -3;
					goto IL_00de;
				}
				<>1__state = -1;
				if (startOfRound == null)
				{
					return false;
				}
				<playersObject>5__1 = GetMemberValue(startOfRound, startOfRound.GetType(), "allPlayerScripts");
				<players>5__2 = <playersObject>5__1 as IEnumerable;
				if (<players>5__2 == null)
				{
					return false;
				}
				<>s__3 = <players>5__2.GetEnumerator();
				<>1__state = -3;
				goto IL_00e6;
				IL_00de:
				<player>5__4 = null;
				goto IL_00e6;
				IL_00e6:
				if (<>s__3.MoveNext())
				{
					<player>5__4 = <>s__3.Current;
					if (<player>5__4 != null)
					{
						<>2__current = <player>5__4;
						<>1__state = 1;
						return true;
					}
					goto IL_00de;
				}
				<>m__Finally1();
				<>s__3 = null;
				return false;
			}
			catch
			{
				//try-fault
				((IDisposable)this).Dispose();
				throw;
			}
		}

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

		private void <>m__Finally1()
		{
			<>1__state = -1;
			if (<>s__3 is IDisposable disposable)
			{
				disposable.Dispose();
			}
		}

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

		[DebuggerHidden]
		IEnumerator<object> IEnumerable<object>.GetEnumerator()
		{
			<GetAllPlayerScripts>d__38 <GetAllPlayerScripts>d__;
			if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId)
			{
				<>1__state = 0;
				<GetAllPlayerScripts>d__ = this;
			}
			else
			{
				<GetAllPlayerScripts>d__ = new <GetAllPlayerScripts>d__38(0);
			}
			<GetAllPlayerScripts>d__.startOfRound = <>3__startOfRound;
			return <GetAllPlayerScripts>d__;
		}

		[DebuggerHidden]
		IEnumerator IEnumerable.GetEnumerator()
		{
			return ((IEnumerable<object>)this).GetEnumerator();
		}
	}

	private const string PluginGuid = "YourFurnace.RandomStartSuit";

	private const string PluginName = "RandomStartSuit";

	private const string PluginVersion = "1.1.0";

	private static ManualLogSource Log;

	private static readonly BindingFlags Flags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;

	private readonly Dictionary<ulong, Assignment> assignmentsByClientId = new Dictionary<ulong, Assignment>();

	private ConfigEntry<string> allowedSuitsCsv;

	private ConfigEntry<float> firstAssignmentDelay;

	private ConfigEntry<float> rescanInterval;

	private ConfigEntry<float> serverResendSeconds;

	private ConfigEntry<float> serverResendInterval;

	private ConfigEntry<bool> onlyAssignInShipLobby;

	private ConfigEntry<bool> useUnlockableSuitRpcFirst;

	private ConfigEntry<bool> useStartOfRoundRpcFallback;

	private ConfigEntry<bool> setPlayerSuitFieldsAsBackup;

	private ConfigEntry<bool> logDebug;

	private Random rng;

	private int currentStartOfRoundId;

	private float nextScanTime;

	private void Awake()
	{
		Log = ((BaseUnityPlugin)this).Logger;
		rng = new Random();
		allowedSuitsCsv = ((BaseUnityPlugin)this).Config.Bind<string>("Suit Selection", "Allowed suit names", "FemaleBlue,FemaleClothed,FemaleLime,FemaleOrange,FemalePink,FemaleStar,RealMan", "Comma separated exact unlockable names. FemaleBlue will NOT match FemaleBlueOpen. FemaleStar will NOT match FemaleStarOpen.");
		firstAssignmentDelay = ((BaseUnityPlugin)this).Config.Bind<float>("Assignment", "First assignment delay seconds", 3f, "How long to wait after StartOfRound exists before assigning suits.");
		rescanInterval = ((BaseUnityPlugin)this).Config.Bind<float>("Assignment", "Rescan interval seconds", 2f, "How often the host checks for players without assigned suits.");
		serverResendSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Assignment", "Server resend seconds", 12f, "How long the host keeps reapplying the picked suit. This fights vanilla or other mods setting default suit after spawn.");
		serverResendInterval = ((BaseUnityPlugin)this).Config.Bind<float>("Assignment", "Server resend interval seconds", 1f, "How often the host reapplies during the resend window.");
		onlyAssignInShipLobby = ((BaseUnityPlugin)this).Config.Bind<bool>("Assignment", "Only assign while in ship lobby", true, "Recommended true. Stops suit changing after landing.");
		useUnlockableSuitRpcFirst = ((BaseUnityPlugin)this).Config.Bind<bool>("Apply", "Use UnlockableSuit RPC first", true, "Recommended true. This matches the original working approach. It calls SwitchSuitClientRpc on the matching UnlockableSuit object by suit ID.");
		useStartOfRoundRpcFallback = ((BaseUnityPlugin)this).Config.Bind<bool>("Apply", "Use StartOfRound RPC fallback", true, "Uses StartOfRound suit switching only if the UnlockableSuit object method cannot be found.");
		setPlayerSuitFieldsAsBackup = ((BaseUnityPlugin)this).Config.Bind<bool>("Apply", "Set player suit fields as backup", false, "Leave false unless the suit still does not show. Direct fields can fight Netcode if done too early.");
		logDebug = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "Log debug info", true, "Logs parsed whitelist, allowed exact unlockable matches, chosen suit, and apply method calls.");
		SceneManager.sceneLoaded += OnSceneLoaded;
		((BaseUnityPlugin)this).Logger.LogInfo((object)"RandomStartSuit 1.1.0 loaded. Exact comma whitelist. UnlockablesList based. No suit rack required.");
	}

	private void OnDestroy()
	{
		SceneManager.sceneLoaded -= OnSceneLoaded;
	}

	private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
	{
		if (IsMenuScene(((Scene)(ref scene)).name))
		{
			assignmentsByClientId.Clear();
			currentStartOfRoundId = 0;
		}
		nextScanTime = Time.realtimeSinceStartup + Mathf.Max(0.1f, firstAssignmentDelay.Value);
	}

	private void Update()
	{
		try
		{
			if (!IsHostOrServer())
			{
				return;
			}
			object startOfRound = GetStartOfRound();
			if (startOfRound == null)
			{
				return;
			}
			int instanceId = GetInstanceId(startOfRound);
			if (instanceId != currentStartOfRoundId)
			{
				currentStartOfRoundId = instanceId;
				assignmentsByClientId.Clear();
				nextScanTime = Time.realtimeSinceStartup + Mathf.Max(0.1f, firstAssignmentDelay.Value);
				DebugLog("New StartOfRound detected. Assignment state cleared.");
			}
			else if (IsSafeAssignTime(startOfRound))
			{
				if (Time.realtimeSinceStartup >= nextScanTime)
				{
					nextScanTime = Time.realtimeSinceStartup + Mathf.Max(0.25f, rescanInterval.Value);
					AssignMissingPlayers(startOfRound);
				}
				ResendAssignments(startOfRound);
			}
		}
		catch (Exception ex)
		{
			Log.LogWarning((object)("RandomStartSuit update failed safely: " + ShortException(ex)));
		}
	}

	private void AssignMissingPlayers(object startOfRound)
	{
		List<SuitChoice> allowedSuitsFromUnlockables = GetAllowedSuitsFromUnlockables(startOfRound);
		if (allowedSuitsFromUnlockables.Count == 0)
		{
			Log.LogWarning((object)"No allowed exact suit names were found in StartOfRound.unlockablesList.");
			Log.LogWarning((object)("Raw config value: " + allowedSuitsCsv.Value));
			LogAvailableSuitLikeUnlockables(startOfRound);
			return;
		}
		foreach (object allPlayerScript in GetAllPlayerScripts(startOfRound))
		{
			if (IsRealPlayer(allPlayerScript))
			{
				ulong playerClientId = GetPlayerClientId(allPlayerScript);
				int playerIndex = GetPlayerIndex(startOfRound, allPlayerScript);
				if (playerIndex >= 0 && !assignmentsByClientId.ContainsKey(playerClientId))
				{
					SuitChoice suitChoice = allowedSuitsFromUnlockables[rng.Next(allowedSuitsFromUnlockables.Count)];
					Assignment assignment = new Assignment
					{
						ClientId = playerClientId,
						PlayerIndex = playerIndex,
						SuitId = suitChoice.SuitId,
						SuitName = suitChoice.SuitName,
						ResendUntil = Time.realtimeSinceStartup + Mathf.Max(0f, serverResendSeconds.Value),
						NextResend = 0f
					};
					assignmentsByClientId[playerClientId] = assignment;
					Log.LogInfo((object)("Assigned " + PlayerLabel(allPlayerScript) + " playerIndex=" + playerIndex + " clientId=" + playerClientId + " exactSuit=" + suitChoice.SuitName + " suitID=" + suitChoice.SuitId));
					ApplyAssignment(startOfRound, assignment, "initial");
				}
			}
		}
	}

	private void ResendAssignments(object startOfRound)
	{
		float realtimeSinceStartup = Time.realtimeSinceStartup;
		float num = Mathf.Max(0.25f, serverResendInterval.Value);
		foreach (Assignment item in assignmentsByClientId.Values.ToList())
		{
			if (!(realtimeSinceStartup > item.ResendUntil) && !(realtimeSinceStartup < item.NextResend))
			{
				item.NextResend = realtimeSinceStartup + num;
				ApplyAssignment(startOfRound, item, "resend");
			}
		}
	}

	private void ApplyAssignment(object startOfRound, Assignment assignment, string reason)
	{
		if (startOfRound == null || assignment == null)
		{
			return;
		}
		object obj = FindPlayerByClientIdOrIndex(startOfRound, assignment.ClientId, assignment.PlayerIndex);
		bool flag = false;
		if (useUnlockableSuitRpcFirst.Value)
		{
			object obj2 = FindUnlockableSuitObjectById(assignment.SuitId);
			if (obj2 != null)
			{
				flag |= InvokeSuitMethod(obj2, "SwitchSuitClientRpc", assignment.PlayerIndex, assignment.SuitId, obj);
				flag |= InvokeSuitMethod(obj2, "SwitchSuitServerRpc", assignment.PlayerIndex, assignment.SuitId, obj);
				flag |= InvokeSuitMethod(obj2, "SwitchSuitToThis", assignment.PlayerIndex, assignment.SuitId, obj);
			}
			else
			{
				DebugLog("No UnlockableSuit component object found for suitID=" + assignment.SuitId + " " + assignment.SuitName);
			}
		}
		if (!flag && useStartOfRoundRpcFallback.Value)
		{
			flag |= InvokeSuitMethod(startOfRound, "SwitchSuitClientRpc", assignment.PlayerIndex, assignment.SuitId, obj);
			flag |= InvokeSuitMethod(startOfRound, "SwitchSuitServerRpc", assignment.PlayerIndex, assignment.SuitId, obj);
			flag |= InvokeSuitMethod(startOfRound, "SwitchSuitForPlayer", assignment.PlayerIndex, assignment.SuitId, obj);
		}
		if (setPlayerSuitFieldsAsBackup.Value && obj != null)
		{
			SetPlayerSuitFields(obj, assignment.SuitId);
		}
		DebugLog("Apply " + reason + " playerIndex=" + assignment.PlayerIndex + " clientId=" + assignment.ClientId + " suit=" + assignment.SuitName + " id=" + assignment.SuitId + " applied=" + flag);
	}

	private List<SuitChoice> GetAllowedSuitsFromUnlockables(object startOfRound)
	{
		HashSet<string> hashSet = ParseWhitelist(allowedSuitsCsv.Value);
		bool flag = hashSet.Contains("all");
		DebugLog("Raw whitelist config: " + allowedSuitsCsv.Value);
		DebugLog("Parsed whitelist tokens: " + string.Join(", ", hashSet.ToArray()));
		List<SuitChoice> list = new List<SuitChoice>();
		IList unlockablesList = GetUnlockablesList(startOfRound);
		if (unlockablesList == null)
		{
			Log.LogWarning((object)"Could not read StartOfRound.unlockablesList.unlockables.");
			return list;
		}
		for (int i = 0; i < unlockablesList.Count; i++)
		{
			object obj = unlockablesList[i];
			if (obj == null)
			{
				continue;
			}
			string unlockableName = GetUnlockableName(obj);
			if (!string.IsNullOrWhiteSpace(unlockableName))
			{
				string item = Normalize(unlockableName);
				if (flag || hashSet.Contains(item))
				{
					list.Add(new SuitChoice
					{
						SuitId = i,
						SuitName = unlockableName,
						UnlockableItem = obj
					});
				}
			}
		}
		if (list.Count > 0)
		{
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.Append("Allowed exact unlockable matches: ");
			foreach (SuitChoice item2 in list)
			{
				stringBuilder.Append("[").Append(item2.SuitName).Append(" id=")
					.Append(item2.SuitId)
					.Append("] ");
			}
			Log.LogInfo((object)stringBuilder.ToString());
		}
		return list;
	}

	private static HashSet<string> ParseWhitelist(string csv)
	{
		HashSet<string> hashSet = new HashSet<string>();
		if (string.IsNullOrWhiteSpace(csv))
		{
			return hashSet;
		}
		string[] array = csv.Split(new char[6] { ',', ';', '|', '\n', '\r', '\t' }, StringSplitOptions.RemoveEmptyEntries);
		string[] array2 = array;
		foreach (string text in array2)
		{
			string text2 = text.Trim().Trim(new char[1] { '"' }).Trim(new char[1] { '\'' });
			string text3 = Normalize(text2);
			if (!string.IsNullOrWhiteSpace(text3))
			{
				hashSet.Add(text3);
			}
		}
		return hashSet;
	}

	private void LogAvailableSuitLikeUnlockables(object startOfRound)
	{
		IList unlockablesList = GetUnlockablesList(startOfRound);
		if (unlockablesList == null)
		{
			return;
		}
		StringBuilder stringBuilder = new StringBuilder();
		stringBuilder.Append("Available suit-like unlockables: ");
		for (int i = 0; i < unlockablesList.Count; i++)
		{
			object obj = unlockablesList[i];
			if (obj == null)
			{
				continue;
			}
			string unlockableName = GetUnlockableName(obj);
			if (!string.IsNullOrWhiteSpace(unlockableName))
			{
				string text = unlockableName.ToLowerInvariant();
				if (text.Contains("female") || text.Contains("suit") || text.Contains("realman"))
				{
					stringBuilder.Append("[").Append(unlockableName).Append(" id=")
						.Append(i)
						.Append("] ");
				}
			}
		}
		Log.LogWarning((object)stringBuilder.ToString());
	}

	private static IList GetUnlockablesList(object startOfRound)
	{
		if (startOfRound == null)
		{
			return null;
		}
		object memberValue = GetMemberValue(startOfRound, startOfRound.GetType(), "unlockablesList");
		if (memberValue == null)
		{
			return null;
		}
		object memberValue2 = GetMemberValue(memberValue, memberValue.GetType(), "unlockables");
		return memberValue2 as IList;
	}

	private static string GetUnlockableName(object unlockable)
	{
		if (unlockable == null)
		{
			return null;
		}
		return GetMemberValue(unlockable, unlockable.GetType(), "unlockableName")?.ToString();
	}

	private static object FindUnlockableSuitObjectById(int suitId)
	{
		Component[] array = Resources.FindObjectsOfTypeAll<Component>();
		Component[] array2 = array;
		foreach (Component val in array2)
		{
			if ((Object)(object)val == (Object)null)
			{
				continue;
			}
			Type type = ((object)val).GetType();
			if (IsUnlockableSuitType(type))
			{
				int intMember = GetIntMember(val, type, "suitID", -1);
				if (intMember == suitId)
				{
					return val;
				}
			}
		}
		return null;
	}

	private bool InvokeSuitMethod(object target, string methodName, int playerIndex, int suitId, object player)
	{
		if (target == null)
		{
			return false;
		}
		Type type = target.GetType();
		MethodInfo[] methods = type.GetMethods(Flags);
		bool result = false;
		MethodInfo[] array = methods;
		foreach (MethodInfo methodInfo in array)
		{
			if (!(methodInfo.Name != methodName) && TryBuildMethodArgs(methodInfo, playerIndex, suitId, player, out var args))
			{
				try
				{
					methodInfo.Invoke(target, args);
					result = true;
					DebugLog("Called " + type.FullName + "." + methodInfo.Name + "(" + ArgsToString(args) + ") for suitID=" + suitId);
				}
				catch (Exception ex)
				{
					DebugLog("Call failed " + type.FullName + "." + methodInfo.Name + ": " + ShortException(ex));
				}
			}
		}
		return result;
	}

	private static bool TryBuildMethodArgs(MethodInfo method, int playerIndex, int suitId, object player, out object[] args)
	{
		ParameterInfo[] parameters = method.GetParameters();
		args = new object[parameters.Length];
		for (int i = 0; i < parameters.Length; i++)
		{
			ParameterInfo parameterInfo = parameters[i];
			Type parameterType = parameterInfo.ParameterType;
			Type type = Nullable.GetUnderlyingType(parameterType) ?? parameterType;
			string text = (parameterInfo.Name ?? string.Empty).ToLowerInvariant();
			if (player != null && parameterType.IsAssignableFrom(player.GetType()))
			{
				args[i] = player;
			}
			else if (type == typeof(int))
			{
				if (text.Contains("suit") || text.Contains("unlockable") || i == 1)
				{
					args[i] = suitId;
				}
				else
				{
					args[i] = playerIndex;
				}
			}
			else if (type == typeof(uint))
			{
				if (text.Contains("suit") || text.Contains("unlockable") || i == 1)
				{
					args[i] = (uint)Mathf.Max(0, suitId);
				}
				else
				{
					args[i] = (uint)Mathf.Max(0, playerIndex);
				}
			}
			else if (type == typeof(ulong))
			{
				if (text.Contains("suit") || text.Contains("unlockable") || i == 1)
				{
					args[i] = (ulong)Mathf.Max(0, suitId);
				}
				else
				{
					args[i] = (ulong)Mathf.Max(0, playerIndex);
				}
			}
			else if (type == typeof(bool))
			{
				args[i] = false;
			}
			else if (type == typeof(float))
			{
				args[i] = 0f;
			}
			else if (parameterType.IsValueType)
			{
				args[i] = Activator.CreateInstance(parameterType);
			}
			else
			{
				args[i] = null;
			}
		}
		return true;
	}

	private static void SetPlayerSuitFields(object player, int suitId)
	{
		if (player != null)
		{
			Type type = player.GetType();
			string[] array = new string[6] { "suitID", "suitId", "currentSuitID", "currentSuitId", "syncedSuitID", "syncedSuitId" };
			foreach (string name in array)
			{
				SetMemberValue(player, type, name, suitId);
			}
		}
	}

	private static object GetStartOfRound()
	{
		Type type = Type.GetType("StartOfRound, Assembly-CSharp");
		if (type == null)
		{
			return null;
		}
		object memberValue = GetMemberValue(null, type, "Instance");
		if (memberValue != null)
		{
			return memberValue;
		}
		memberValue = GetMemberValue(null, type, "instance");
		if (memberValue != null)
		{
			return memberValue;
		}
		Object[] array = Resources.FindObjectsOfTypeAll(type);
		if (array != null && array.Length != 0)
		{
			return array[0];
		}
		return null;
	}

	[IteratorStateMachine(typeof(<GetAllPlayerScripts>d__38))]
	private static IEnumerable<object> GetAllPlayerScripts(object startOfRound)
	{
		//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
		return new <GetAllPlayerScripts>d__38(-2)
		{
			<>3__startOfRound = startOfRound
		};
	}

	private static object FindPlayerByClientIdOrIndex(object startOfRound, ulong clientId, int fallbackIndex)
	{
		int num = 0;
		foreach (object allPlayerScript in GetAllPlayerScripts(startOfRound))
		{
			if (GetPlayerClientId(allPlayerScript) == clientId)
			{
				return allPlayerScript;
			}
			if (fallbackIndex >= 0 && num == fallbackIndex)
			{
				return allPlayerScript;
			}
			num++;
		}
		return null;
	}

	private static int GetPlayerIndex(object startOfRound, object player)
	{
		if (startOfRound == null || player == null)
		{
			return -1;
		}
		int num = 0;
		foreach (object allPlayerScript in GetAllPlayerScripts(startOfRound))
		{
			if (allPlayerScript == player)
			{
				return num;
			}
			num++;
		}
		return -1;
	}

	private static bool IsRealPlayer(object player)
	{
		if (player == null)
		{
			return false;
		}
		Type type = player.GetType();
		bool boolMember = GetBoolMember(player, type, "isPlayerControlled", fallback: false);
		bool boolMember2 = GetBoolMember(player, type, "isPlayerDead", fallback: false);
		return boolMember && !boolMember2;
	}

	private static ulong GetPlayerClientId(object player)
	{
		if (player == null)
		{
			return 0uL;
		}
		Type type = player.GetType();
		string[] array = new string[3] { "actualClientId", "playerClientId", "clientId" };
		foreach (string name in array)
		{
			object memberValue = GetMemberValue(player, type, name);
			if (memberValue != null)
			{
				try
				{
					return Convert.ToUInt64(memberValue, CultureInfo.InvariantCulture);
				}
				catch
				{
				}
			}
		}
		return 0uL;
	}

	private static bool IsSafeAssignTime(object startOfRound)
	{
		if (startOfRound == null)
		{
			return false;
		}
		if (!IsNetworkActive())
		{
			return false;
		}
		if (!NetworkManager.Singleton.IsServer && !NetworkManager.Singleton.IsHost)
		{
			return false;
		}
		if (!PluginInstanceOnlyAssignInLobby())
		{
			return true;
		}
		Type type = startOfRound.GetType();
		bool boolMember = GetBoolMember(startOfRound, type, "shipHasLanded", fallback: false);
		bool boolMember2 = GetBoolMember(startOfRound, type, "shipIsLeaving", fallback: false);
		bool boolMember3 = GetBoolMember(startOfRound, type, "inShipPhase", fallback: true);
		return !boolMember && !boolMember2 && boolMember3;
	}

	private static bool PluginInstanceOnlyAssignInLobby()
	{
		try
		{
			Plugin plugin = Object.FindObjectOfType<Plugin>();
			return (Object)(object)plugin == (Object)null || plugin.onlyAssignInShipLobby == null || plugin.onlyAssignInShipLobby.Value;
		}
		catch
		{
			return true;
		}
	}

	private static bool IsNetworkActive()
	{
		try
		{
			NetworkManager singleton = NetworkManager.Singleton;
			return (Object)(object)singleton != (Object)null && singleton.IsListening && !singleton.ShutdownInProgress;
		}
		catch
		{
			return false;
		}
	}

	private static bool IsHostOrServer()
	{
		try
		{
			NetworkManager singleton = NetworkManager.Singleton;
			return (Object)(object)singleton != (Object)null && singleton.IsListening && (singleton.IsHost || singleton.IsServer);
		}
		catch
		{
			return false;
		}
	}

	private static bool IsMenuScene(string sceneName)
	{
		if (string.IsNullOrWhiteSpace(sceneName))
		{
			return false;
		}
		string text = sceneName.ToLowerInvariant();
		return text.Contains("menu") || text.Contains("main");
	}

	private static bool IsUnlockableSuitType(Type type)
	{
		if (type == null)
		{
			return false;
		}
		string text = type.Name ?? string.Empty;
		string text2 = type.FullName ?? string.Empty;
		return text.Equals("UnlockableSuit", StringComparison.OrdinalIgnoreCase) || text2.EndsWith(".UnlockableSuit", StringComparison.OrdinalIgnoreCase);
	}

	private static string Normalize(string text)
	{
		if (string.IsNullOrWhiteSpace(text))
		{
			return string.Empty;
		}
		StringBuilder stringBuilder = new StringBuilder(text.Length);
		foreach (char c in text)
		{
			if (char.IsLetterOrDigit(c))
			{
				stringBuilder.Append(char.ToLowerInvariant(c));
			}
		}
		return stringBuilder.ToString();
	}

	private static object GetMemberValue(object instance, Type type, string name)
	{
		if (type == null || string.IsNullOrWhiteSpace(name))
		{
			return null;
		}
		try
		{
			FieldInfo field = type.GetField(name, Flags);
			if (field != null)
			{
				return field.GetValue(instance);
			}
			PropertyInfo property = type.GetProperty(name, Flags);
			if (property != null && property.GetIndexParameters().Length == 0)
			{
				return property.GetValue(instance, null);
			}
		}
		catch
		{
		}
		return null;
	}

	private static void SetMemberValue(object instance, Type type, string name, object value)
	{
		if (instance == null || type == null || string.IsNullOrWhiteSpace(name))
		{
			return;
		}
		try
		{
			FieldInfo field = type.GetField(name, Flags);
			if (field != null)
			{
				object value2 = Convert.ChangeType(value, Nullable.GetUnderlyingType(field.FieldType) ?? field.FieldType, CultureInfo.InvariantCulture);
				field.SetValue(instance, value2);
				return;
			}
			PropertyInfo property = type.GetProperty(name, Flags);
			if (property != null && property.CanWrite)
			{
				object value3 = Convert.ChangeType(value, Nullable.GetUnderlyingType(property.PropertyType) ?? property.PropertyType, CultureInfo.InvariantCulture);
				property.SetValue(instance, value3, null);
			}
		}
		catch
		{
		}
	}

	private static int GetIntMember(object instance, Type type, string name, int fallback)
	{
		object memberValue = GetMemberValue(instance, type, name);
		if (memberValue == null)
		{
			return fallback;
		}
		try
		{
			return Convert.ToInt32(memberValue, CultureInfo.InvariantCulture);
		}
		catch
		{
			return fallback;
		}
	}

	private static bool GetBoolMember(object instance, Type type, string name, bool fallback)
	{
		object memberValue = GetMemberValue(instance, type, name);
		if (memberValue == null)
		{
			return fallback;
		}
		try
		{
			return Convert.ToBoolean(memberValue, CultureInfo.InvariantCulture);
		}
		catch
		{
			return fallback;
		}
	}

	private static int GetInstanceId(object obj)
	{
		Object val = (Object)((obj is Object) ? obj : null);
		return (val != (Object)null) ? val.GetInstanceID() : 0;
	}

	private static string PlayerLabel(object player)
	{
		if (player == null)
		{
			return "<null player>";
		}
		object memberValue = GetMemberValue(player, player.GetType(), "playerUsername");
		if (memberValue != null && !string.IsNullOrWhiteSpace(memberValue.ToString()))
		{
			return memberValue.ToString();
		}
		Object val = (Object)((player is Object) ? player : null);
		if (val != (Object)null)
		{
			return val.name;
		}
		return player.ToString();
	}

	private void DebugLog(string msg)
	{
		if (logDebug != null && logDebug.Value)
		{
			Log.LogInfo((object)msg);
		}
	}

	private static string ArgsToString(object[] args)
	{
		if (args == null)
		{
			return string.Empty;
		}
		return string.Join(", ", args.Select((object a) => (a == null) ? "null" : a.ToString()).ToArray());
	}

	private static string ShortException(Exception ex)
	{
		if (ex == null)
		{
			return "<null exception>";
		}
		while (ex.InnerException != null)
		{
			ex = ex.InnerException;
		}
		return ex.GetType().Name + ": " + ex.Message;
	}
}