Decompiled source of Better Lockpicker v1.0.0

BepInEx/plugins/BetterLockpicker.dll

Decompiled 3 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using BetterLockpicker.Config;
using GameNetcodeStuff;
using HarmonyLib;
using LethalConfig;
using LethalConfig.ConfigItems;
using LethalNetworkAPI;
using LethalNetworkAPI.Utils;
using Microsoft.CodeAnalysis;
using Unity.Collections;
using Unity.Netcode;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("BetterLockpicker")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Mod for Lethal Company, that enhance Lockpicker")]
[assembly: AssemblyFileVersion("1.1.8.0")]
[assembly: AssemblyInformationalVersion("1.1.8")]
[assembly: AssemblyProduct("BetterLockpicker")]
[assembly: AssemblyTitle("BetterLockpicker")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.1.8.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
internal static class LethalConfigCompat
{
	[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
	internal static void Register(ConfigEntry<bool> boolConfigEntry)
	{
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		//IL_0023: Expected O, but got Unknown
		if (Chainloader.PluginInfos.ContainsKey("ainavt.lc.lethalconfig"))
		{
			LethalConfigManager.SkipAutoGenFor((ConfigEntryBase)(object)boolConfigEntry);
			LethalConfigManager.AddConfigItem((BaseConfigItem)new BoolCheckBoxConfigItem(boolConfigEntry, false));
		}
	}

	[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
	internal static void Register(ConfigEntry<int> intConfigEntry)
	{
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		//IL_0023: Expected O, but got Unknown
		if (Chainloader.PluginInfos.ContainsKey("ainavt.lc.lethalconfig"))
		{
			LethalConfigManager.SkipAutoGenFor((ConfigEntryBase)(object)intConfigEntry);
			LethalConfigManager.AddConfigItem((BaseConfigItem)new IntInputFieldConfigItem(intConfigEntry, false));
		}
	}

	[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
	internal static void Register(ConfigEntry<float> floatConfigEntry)
	{
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		//IL_0023: Expected O, but got Unknown
		if (Chainloader.PluginInfos.ContainsKey("ainavt.lc.lethalconfig"))
		{
			LethalConfigManager.SkipAutoGenFor((ConfigEntryBase)(object)floatConfigEntry);
			LethalConfigManager.AddConfigItem((BaseConfigItem)new FloatInputFieldConfigItem(floatConfigEntry, false));
		}
	}

	[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
	internal static void Register(ConfigEntry<string> stringConfigEntry)
	{
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		//IL_0023: Expected O, but got Unknown
		if (Chainloader.PluginInfos.ContainsKey("ainavt.lc.lethalconfig"))
		{
			LethalConfigManager.SkipAutoGenFor((ConfigEntryBase)(object)stringConfigEntry);
			LethalConfigManager.AddConfigItem((BaseConfigItem)new TextInputFieldConfigItem(stringConfigEntry, false));
		}
	}
}
namespace BetterLockpicker
{
	internal static class LockpickerNetSync
	{
		private struct Pending
		{
			public ulong PickerNetId;

			public ulong DoorNetId;

			public float LockingTime;

			public bool TemporaryLockingAtStart;

			public float ReceivedAt;
		}

		[CompilerGenerated]
		private static class <>O
		{
			public static HandleNamedMessageDelegate <0>__OnLockingStarted;
		}

		[CompilerGenerated]
		private sealed class <InitWhenReady>d__7 : IEnumerator<object>, IEnumerator, IDisposable
		{
			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 <InitWhenReady>d__7(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

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

			private bool MoveNext()
			{
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					goto IL_003b;
				case 1:
					<>1__state = -1;
					goto IL_003b;
				case 2:
					{
						<>1__state = -1;
						goto IL_0066;
					}
					IL_003b:
					if ((Object)(object)NetworkManager.Singleton == (Object)null)
					{
						<>2__current = null;
						<>1__state = 1;
						return true;
					}
					TryRegisterHandlers();
					goto IL_0066;
					IL_0066:
					if ((Object)(object)NetworkManager.Singleton != (Object)null)
					{
						<>2__current = null;
						<>1__state = 2;
						return true;
					}
					_registeredForCurrentNm = false;
					_nmInstanceId = 0;
					_pendingByPicker.Clear();
					_pendingByDoor.Clear();
					goto IL_003b;
				}
			}

			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 const string MsgLockingStarted = "BetterLockpicker_LockingStarted_v1";

		private const float PendingTtlSeconds = 10f;

		private static bool _registeredForCurrentNm;

		private static int _nmInstanceId;

		private static readonly Dictionary<ulong, Pending> _pendingByPicker = new Dictionary<ulong, Pending>();

		private static readonly Dictionary<ulong, Pending> _pendingByDoor = new Dictionary<ulong, Pending>();

		[IteratorStateMachine(typeof(<InitWhenReady>d__7))]
		internal static IEnumerator InitWhenReady()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <InitWhenReady>d__7(0);
		}

		private static void TryRegisterHandlers()
		{
			//IL_0062: 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_006d: Expected O, but got Unknown
			NetworkManager singleton = NetworkManager.Singleton;
			if ((Object)(object)singleton == (Object)null)
			{
				return;
			}
			int instanceID = ((Object)singleton).GetInstanceID();
			if (!_registeredForCurrentNm || _nmInstanceId != instanceID)
			{
				_registeredForCurrentNm = true;
				_nmInstanceId = instanceID;
				_pendingByPicker.Clear();
				_pendingByDoor.Clear();
				CustomMessagingManager customMessagingManager = singleton.CustomMessagingManager;
				object obj = <>O.<0>__OnLockingStarted;
				if (obj == null)
				{
					HandleNamedMessageDelegate val = OnLockingStarted;
					<>O.<0>__OnLockingStarted = val;
					obj = (object)val;
				}
				customMessagingManager.RegisterNamedMessageHandler("BetterLockpicker_LockingStarted_v1", (HandleNamedMessageDelegate)obj);
			}
		}

		internal static void SendLockingStartedToAll(ulong pickerNetId, ulong doorNetId, float lockingTime)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: 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_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			NetworkManager singleton = NetworkManager.Singleton;
			if ((Object)(object)singleton == (Object)null || !singleton.IsServer)
			{
				return;
			}
			FastBufferWriter val = default(FastBufferWriter);
			((FastBufferWriter)(ref val))..ctor(20, (Allocator)2, -1);
			try
			{
				((FastBufferWriter)(ref val)).WriteValueSafe<ulong>(ref pickerNetId, default(ForPrimitives));
				((FastBufferWriter)(ref val)).WriteValueSafe<ulong>(ref doorNetId, default(ForPrimitives));
				((FastBufferWriter)(ref val)).WriteValueSafe<float>(ref lockingTime, default(ForPrimitives));
				singleton.CustomMessagingManager.SendNamedMessageToAll("BetterLockpicker_LockingStarted_v1", val, (NetworkDelivery)3);
			}
			finally
			{
				((IDisposable)(FastBufferWriter)(ref val)).Dispose();
			}
		}

		internal static bool TryConsumePending(ulong pickerNetId, ulong doorNetId, out float lockingTime, out bool temporaryLockingAtStart)
		{
			CleanupExpired();
			if (_pendingByPicker.TryGetValue(pickerNetId, out var value) && value.DoorNetId == doorNetId)
			{
				lockingTime = value.LockingTime;
				temporaryLockingAtStart = value.TemporaryLockingAtStart;
				RemovePending(value);
				return true;
			}
			lockingTime = 0f;
			temporaryLockingAtStart = false;
			return false;
		}

		internal static bool TryConsumePendingDoor(ulong doorNetId, out float lockingTime, out bool temporaryLockingAtStart)
		{
			CleanupExpired();
			if (_pendingByDoor.TryGetValue(doorNetId, out var value))
			{
				lockingTime = value.LockingTime;
				temporaryLockingAtStart = value.TemporaryLockingAtStart;
				RemovePending(value);
				return true;
			}
			lockingTime = 0f;
			temporaryLockingAtStart = false;
			return false;
		}

		internal static bool TryPeekPendingDoor(ulong doorNetId, out float lockingTime, out bool temporaryLockingAtStart)
		{
			CleanupExpired();
			if (_pendingByDoor.TryGetValue(doorNetId, out var value))
			{
				lockingTime = value.LockingTime;
				temporaryLockingAtStart = value.TemporaryLockingAtStart;
				return true;
			}
			lockingTime = 0f;
			temporaryLockingAtStart = false;
			return false;
		}

		private static void OnLockingStarted(ulong senderClientId, FastBufferReader reader)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: 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_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			ulong num = default(ulong);
			((FastBufferReader)(ref reader)).ReadValueSafe<ulong>(ref num, default(ForPrimitives));
			ulong num2 = default(ulong);
			((FastBufferReader)(ref reader)).ReadValueSafe<ulong>(ref num2, default(ForPrimitives));
			float lockingTime = default(float);
			((FastBufferReader)(ref reader)).ReadValueSafe<float>(ref lockingTime, default(ForPrimitives));
			bool temporaryLockingAtStart = Plugin.TemporaryLockingVar?.Value ?? ConfigSettings.TemporaryLocking;
			Pending pending = default(Pending);
			pending.PickerNetId = num;
			pending.DoorNetId = num2;
			pending.LockingTime = lockingTime;
			pending.TemporaryLockingAtStart = temporaryLockingAtStart;
			pending.ReceivedAt = Time.realtimeSinceStartup;
			Pending pending2 = pending;
			_pendingByPicker[num] = pending2;
			_pendingByDoor[num2] = pending2;
			TryApplyNow(pending2);
		}

		private static void CleanupExpired()
		{
			if (_pendingByDoor.Count == 0)
			{
				return;
			}
			float realtimeSinceStartup = Time.realtimeSinceStartup;
			List<ulong> list = null;
			foreach (KeyValuePair<ulong, Pending> item in _pendingByDoor)
			{
				if (realtimeSinceStartup - item.Value.ReceivedAt > 10f)
				{
					if (list == null)
					{
						list = new List<ulong>();
					}
					list.Add(item.Key);
				}
			}
			if (list == null)
			{
				return;
			}
			foreach (ulong item2 in list)
			{
				if (_pendingByDoor.TryGetValue(item2, out var value))
				{
					RemovePending(value);
				}
			}
		}

		private static void RemovePending(Pending p)
		{
			_pendingByDoor.Remove(p.DoorNetId);
			_pendingByPicker.Remove(p.PickerNetId);
		}

		private static void TryApplyNow(Pending p)
		{
			NetworkManager singleton = NetworkManager.Singleton;
			if ((Object)(object)singleton == (Object)null || !singleton.SpawnManager.SpawnedObjects.TryGetValue(p.DoorNetId, out var value))
			{
				return;
			}
			DoorLock componentInChildren = ((Component)value).GetComponentInChildren<DoorLock>();
			if (!((Object)(object)componentInChildren == (Object)null))
			{
				LockPicker val = null;
				if (singleton.SpawnManager.SpawnedObjects.TryGetValue(p.PickerNetId, out var value2))
				{
					val = ((Component)value2).GetComponent<LockPicker>();
				}
				if ((Object)(object)val != (Object)null)
				{
					LockpickerState.RegisterLockingSession(val, componentInChildren, p.LockingTime, p.TemporaryLockingAtStart);
				}
				else
				{
					LockpickerState.RegisterLockingDoor(componentInChildren, p.LockingTime, p.TemporaryLockingAtStart);
				}
				bool doLockDoor = singleton.IsClient && !singleton.IsServer;
				LockpickerTiming.ApplyLockingSettings(componentInChildren, p.LockingTime, doLockDoor);
				RemovePending(p);
			}
		}
	}
	internal static class LockpickerState
	{
		private struct LockingSession
		{
			public DoorLock Door;

			public float LockingTime;

			public bool TemporaryLockingAtStart;

			public LockingSession(DoorLock door, float lockingTime, bool temporaryLockingAtStart)
			{
				Door = door;
				LockingTime = lockingTime;
				TemporaryLockingAtStart = temporaryLockingAtStart;
			}
		}

		private static readonly Dictionary<LockPicker, LockingSession> _lockingSessions = new Dictionary<LockPicker, LockingSession>();

		private static readonly Dictionary<DoorLock, float> _lockingDoorTimes = new Dictionary<DoorLock, float>();

		private static readonly Dictionary<DoorLock, bool> _lockingDoorTemporary = new Dictionary<DoorLock, bool>();

		private static readonly HashSet<DoorLock> _lockingDoors = new HashSet<DoorLock>();

		public static void RegisterLockingSession(LockPicker picker, DoorLock door, float lockingTime, bool temporaryLockingAtStart)
		{
			if (!((Object)(object)picker == (Object)null) && !((Object)(object)door == (Object)null))
			{
				if (_lockingSessions.TryGetValue(picker, out var value) && (Object)(object)value.Door != (Object)null)
				{
					ClearLockingDoor(value.Door);
				}
				_lockingSessions[picker] = new LockingSession(door, lockingTime, temporaryLockingAtStart);
				RegisterLockingDoor(door, lockingTime, temporaryLockingAtStart);
			}
		}

		public static void RegisterLockingDoor(DoorLock door, float lockingTime, bool temporaryLockingAtStart)
		{
			if (!((Object)(object)door == (Object)null))
			{
				_lockingDoors.Add(door);
				_lockingDoorTimes[door] = lockingTime;
				_lockingDoorTemporary[door] = temporaryLockingAtStart;
			}
		}

		public static bool TryGetLockingDoor(LockPicker picker, out DoorLock door)
		{
			if ((Object)(object)picker != (Object)null && _lockingSessions.TryGetValue(picker, out var value) && (Object)(object)value.Door != (Object)null)
			{
				door = value.Door;
				return true;
			}
			door = null;
			return false;
		}

		public static bool TryGetLockingSession(LockPicker picker, out DoorLock door, out float lockingTime, out bool temporaryLockingAtStart)
		{
			if ((Object)(object)picker != (Object)null && _lockingSessions.TryGetValue(picker, out var value) && (Object)(object)value.Door != (Object)null)
			{
				door = value.Door;
				lockingTime = value.LockingTime;
				temporaryLockingAtStart = value.TemporaryLockingAtStart;
				return true;
			}
			door = null;
			lockingTime = 0f;
			temporaryLockingAtStart = false;
			return false;
		}

		public static bool TryGetLockingDoorTime(DoorLock door, out float lockingTime)
		{
			if ((Object)(object)door != (Object)null && _lockingDoorTimes.TryGetValue(door, out lockingTime))
			{
				return true;
			}
			lockingTime = 0f;
			return false;
		}

		public static bool TryGetLockingDoorTemporary(DoorLock door, out bool temporaryLockingAtStart)
		{
			if ((Object)(object)door != (Object)null && _lockingDoorTemporary.TryGetValue(door, out temporaryLockingAtStart))
			{
				return true;
			}
			temporaryLockingAtStart = false;
			return false;
		}

		public static bool HasLockingSession(LockPicker picker)
		{
			if ((Object)(object)picker != (Object)null)
			{
				return _lockingSessions.ContainsKey(picker);
			}
			return false;
		}

		public static bool IsLockingDoor(DoorLock door)
		{
			if ((Object)(object)door != (Object)null)
			{
				return _lockingDoors.Contains(door);
			}
			return false;
		}

		public static void ClearLockingDoor(DoorLock door)
		{
			if (!((Object)(object)door == (Object)null))
			{
				_lockingDoors.Remove(door);
				_lockingDoorTimes.Remove(door);
				_lockingDoorTemporary.Remove(door);
			}
		}

		public static void ClearLockingSession(LockPicker picker)
		{
			if (!((Object)(object)picker == (Object)null))
			{
				if (_lockingSessions.TryGetValue(picker, out var value) && (Object)(object)value.Door != (Object)null)
				{
					ClearLockingDoor(value.Door);
				}
				_lockingSessions.Remove(picker);
			}
		}
	}
	internal static class LockpickerTiming
	{
		internal static ulong GetDoorNetworkId(DoorLock door)
		{
			if ((Object)(object)door == (Object)null)
			{
				return 0uL;
			}
			NetworkObject componentInParent = ((Component)door).GetComponentInParent<NetworkObject>();
			if (!((Object)(object)componentInParent != (Object)null))
			{
				return 0uL;
			}
			return componentInParent.NetworkObjectId;
		}

		internal static void ApplyUnlockingSettings(DoorLock door, float seconds)
		{
			float seconds2 = Mathf.Max(0.1f, seconds);
			SetCountdown(door, seconds2, preserveProgress: false);
		}

		internal static void ApplyLockingSettings(DoorLock door, float seconds, bool doLockDoor)
		{
			float num = Mathf.Max(0.1f, seconds);
			if (doLockDoor)
			{
				door.LockDoor(num);
			}
			SetCountdown(door, num, preserveProgress: true);
			InteractTrigger component = ((Component)door).GetComponent<InteractTrigger>();
			if ((Object)(object)component != (Object)null)
			{
				bool temporaryLockingAtStart;
				bool flag = LockpickerState.TryGetLockingDoorTemporary(door, out temporaryLockingAtStart) && temporaryLockingAtStart;
				component.holdTip = (flag ? "Blocking door" : "Locking door");
				component.timeToHold = num;
			}
		}

		internal static void SetCountdown(DoorLock door, float seconds, bool preserveProgress)
		{
			if ((Object)(object)door == (Object)null)
			{
				return;
			}
			seconds = Mathf.Max(0.1f, seconds);
			if (!preserveProgress || Mathf.Abs(door.lockPickTimeLeft - door.maxTimeLeft) < 0.001f)
			{
				door.maxTimeLeft = seconds;
				door.lockPickTimeLeft = seconds;
			}
			else
			{
				float num = door.lockPickTimeLeft / Mathf.Max(0.01f, door.maxTimeLeft);
				door.maxTimeLeft = seconds;
				door.lockPickTimeLeft = Mathf.Clamp(seconds * num, 0f, seconds);
			}
			if ((Object)(object)door.twinDoor != (Object)null)
			{
				DoorLock twinDoor = door.twinDoor;
				if (!preserveProgress || Mathf.Abs(twinDoor.lockPickTimeLeft - twinDoor.maxTimeLeft) < 0.001f)
				{
					twinDoor.maxTimeLeft = seconds;
					twinDoor.lockPickTimeLeft = seconds;
				}
				else
				{
					float num2 = twinDoor.lockPickTimeLeft / Mathf.Max(0.01f, twinDoor.maxTimeLeft);
					twinDoor.maxTimeLeft = seconds;
					twinDoor.lockPickTimeLeft = Mathf.Clamp(seconds * num2, 0f, seconds);
				}
				InteractTrigger component = ((Component)twinDoor).GetComponent<InteractTrigger>();
				if ((Object)(object)component != (Object)null)
				{
					component.timeToHold = seconds;
				}
			}
		}
	}
	[BepInPlugin("Azx.BetterLockpicker", "Better Lockpicker", "1.0.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "Azx.BetterLockpicker";

		public const string PluginName = "Better Lockpicker";

		public const string PluginVersion = "1.0.0";

		internal static ManualLogSource Log;

		internal static Harmony Harmony;

		internal static Plugin Instance;

		internal static LNetworkVariable<bool> CanLockDoorsVar;

		internal static LNetworkVariable<bool> TemporaryLockingVar;

		internal static LNetworkVariable<int> LockingTimeVar;

		internal static LNetworkVariable<int> UnlockingTimeVar;

		private void Awake()
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Expected O, but got Unknown
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			Harmony = new Harmony("Azx.BetterLockpicker");
			ConfigSettings.Init((BaseUnityPlugin)(object)this);
			CanLockDoorsVar = LNetworkVariable<bool>.Connect("Azx.BetterLockpicker.CanLockDoors", ConfigSettings.CanLockDoors, (LNetworkVariableWritePerms)0, (Action<bool, bool>)delegate(bool oldV, bool newV)
			{
				Log.LogDebug((object)$"CanLockDoors sync: {oldV} -> {newV}");
			});
			TemporaryLockingVar = LNetworkVariable<bool>.Connect("Azx.BetterLockpicker.TemporaryLocking", ConfigSettings.TemporaryLocking, (LNetworkVariableWritePerms)0, (Action<bool, bool>)delegate(bool oldV, bool newV)
			{
				Log.LogDebug((object)$"TemporaryLocking sync: {oldV} -> {newV}");
			});
			LockingTimeVar = LNetworkVariable<int>.Connect("Azx.BetterLockpicker.LockingTime", ConfigSettings.LockingTime, (LNetworkVariableWritePerms)0, (Action<int, int>)delegate(int oldV, int newV)
			{
				Log.LogDebug((object)$"LockingTime sync: {oldV} -> {newV}");
			});
			UnlockingTimeVar = LNetworkVariable<int>.Connect("Azx.BetterLockpicker.UnlockingTime", ConfigSettings.UnlockingTime, (LNetworkVariableWritePerms)0, (Action<int, int>)delegate(int oldV, int newV)
			{
				Log.LogDebug((object)$"UnlockingTime sync: {oldV} -> {newV}");
			});
			LNetworkUtils.OnNetworkStart += delegate(bool isServer)
			{
				if (isServer)
				{
					if (CanLockDoorsVar != null)
					{
						CanLockDoorsVar.Value = ConfigSettings.CanLockDoors;
					}
					if (TemporaryLockingVar != null)
					{
						TemporaryLockingVar.Value = ConfigSettings.TemporaryLocking;
					}
					if (LockingTimeVar != null)
					{
						LockingTimeVar.Value = ConfigSettings.LockingTime;
					}
					if (UnlockingTimeVar != null)
					{
						UnlockingTimeVar.Value = ConfigSettings.UnlockingTime;
					}
				}
			};
			Harmony.PatchAll();
			((MonoBehaviour)this).StartCoroutine(LockpickerNetSync.InitWhenReady());
			Log.LogInfo((object)"Better Lockpicker 1.0.0 loaded.");
		}

		internal static bool IsHost()
		{
			if (Object.op_Implicit((Object)(object)NetworkManager.Singleton))
			{
				if (!NetworkManager.Singleton.IsServer)
				{
					return NetworkManager.Singleton.IsHost;
				}
				return true;
			}
			return false;
		}
	}
	public static class PluginInfo
	{
		public const string PLUGIN_GUID = "BetterLockpicker";

		public const string PLUGIN_NAME = "BetterLockpicker";

		public const string PLUGIN_VERSION = "1.1.8";
	}
}
namespace BetterLockpicker.Patches
{
	public static class LockpickerPatches
	{
		[HarmonyPatch(typeof(LockPicker), "ItemActivate")]
		internal static class LockPicker_ItemActivate_Patch
		{
			private static readonly MethodInfo GetLockPickerDoorPositionMethod = AccessTools.Method(typeof(LockPicker), "GetLockPickerDoorPosition", (Type[])null, (Type[])null);

			private static readonly MethodInfo PlaceOnDoorMethod = AccessTools.Method(typeof(LockPicker), "PlaceOnDoor", new Type[2]
			{
				typeof(DoorLock),
				typeof(bool)
			}, (Type[])null);

			private static readonly FieldInfo PlaceOnLockPicker1Field = AccessTools.Field(typeof(LockPicker), "placeOnLockPicker1");

			private static void Postfix(LockPicker __instance, bool used, bool buttonDown)
			{
				//IL_0050: Unknown result type (might be due to invalid IL or missing references)
				//IL_0060: Unknown result type (might be due to invalid IL or missing references)
				//IL_0065: 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)
				//IL_00f4: 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)
				if (!buttonDown || (Object)(object)((GrabbableObject)__instance).playerHeldBy == (Object)null || !((NetworkBehaviour)__instance).IsOwner || !((GrabbableObject)__instance).isHeld)
				{
					return;
				}
				LNetworkVariable<bool> canLockDoorsVar = Plugin.CanLockDoorsVar;
				if ((canLockDoorsVar != null) ? (!canLockDoorsVar.Value) : ConfigSettings.CanLockDoors)
				{
					return;
				}
				PlayerControllerB playerHeldBy = ((GrabbableObject)__instance).playerHeldBy;
				RaycastHit val = default(RaycastHit);
				if (!Physics.Raycast(new Ray(((Component)playerHeldBy.gameplayCamera).transform.position, ((Component)playerHeldBy.gameplayCamera).transform.forward), ref val, 3f, 2816))
				{
					return;
				}
				DoorLock component = ((Component)((RaycastHit)(ref val)).transform).GetComponent<DoorLock>();
				if (!((Object)(object)component == (Object)null) && !component.isPickingLock && !component.isLocked)
				{
					AnimatedObjectTrigger component2 = ((Component)component).GetComponent<AnimatedObjectTrigger>();
					if (!((Object)(object)component2 != (Object)null) || !component2.boolValue)
					{
						Vector3 val2 = (Vector3)GetLockPickerDoorPositionMethod.Invoke(__instance, new object[1] { component });
						bool flag = (bool)PlaceOnLockPicker1Field.GetValue(__instance);
						playerHeldBy.DiscardHeldObject(true, ((NetworkBehaviour)component).NetworkObject, val2, true);
						__instance.PlaceLockPickerServerRpc(NetworkObjectReference.op_Implicit(((NetworkBehaviour)component).NetworkObject), flag);
						PlaceOnDoorMethod.Invoke(__instance, new object[2] { component, flag });
					}
				}
			}
		}

		[HarmonyPatch(typeof(LockPicker), "PlaceOnDoor")]
		internal static class LockPicker_PlaceOnDoor_Patch
		{
			private struct PrefixState
			{
				public bool DoorWasLockedBefore;

				public ulong DoorNetId;

				public ulong PickerNetId;
			}

			private static void Prefix(LockPicker __instance, DoorLock doorScript, out PrefixState __state)
			{
				__state = new PrefixState
				{
					DoorWasLockedBefore = ((Object)(object)doorScript != (Object)null && doorScript.isLocked),
					DoorNetId = (((Object)(object)doorScript != (Object)null) ? LockpickerTiming.GetDoorNetworkId(doorScript) : 0),
					PickerNetId = (((Object)(object)__instance != (Object)null) ? ((NetworkBehaviour)__instance).NetworkObjectId : 0)
				};
			}

			private static void Postfix(LockPicker __instance, DoorLock doorScript, bool lockPicker1, PrefixState __state)
			{
				if ((Object)(object)__instance == (Object)null || (Object)(object)doorScript == (Object)null)
				{
					return;
				}
				if (__state.PickerNetId != 0L && __state.DoorNetId != 0L && LockpickerNetSync.TryConsumePending(__state.PickerNetId, __state.DoorNetId, out var lockingTime, out var temporaryLockingAtStart))
				{
					LockpickerState.RegisterLockingSession(__instance, doorScript, lockingTime, temporaryLockingAtStart);
					bool doLockDoor = (Object)(object)NetworkManager.Singleton == (Object)null || (NetworkManager.Singleton.IsClient && !NetworkManager.Singleton.IsServer);
					LockpickerTiming.ApplyLockingSettings(doorScript, lockingTime, doLockDoor);
				}
				else if (LockpickerState.HasLockingSession(__instance) || LockpickerState.IsLockingDoor(doorScript))
				{
					float num = Plugin.LockingTimeVar?.Value ?? ConfigSettings.LockingTime;
					bool temporaryLockingAtStart2 = Plugin.TemporaryLockingVar?.Value ?? ConfigSettings.TemporaryLocking;
					float lockingTime3;
					if (LockpickerState.TryGetLockingSession(__instance, out var _, out var lockingTime2, out var temporaryLockingAtStart3))
					{
						if (lockingTime2 > 0.01f)
						{
							num = lockingTime2;
						}
						temporaryLockingAtStart2 = temporaryLockingAtStart3;
					}
					else if (LockpickerState.TryGetLockingDoorTime(doorScript, out lockingTime3) && lockingTime3 > 0.01f)
					{
						num = lockingTime3;
						if (LockpickerState.TryGetLockingDoorTemporary(doorScript, out var temporaryLockingAtStart4))
						{
							temporaryLockingAtStart2 = temporaryLockingAtStart4;
						}
					}
					LockpickerState.RegisterLockingSession(__instance, doorScript, num, temporaryLockingAtStart2);
					bool doLockDoor2 = (Object)(object)NetworkManager.Singleton == (Object)null || (NetworkManager.Singleton.IsClient && !NetworkManager.Singleton.IsServer);
					LockpickerTiming.ApplyLockingSettings(doorScript, num, doLockDoor2);
				}
				else if (__state.DoorWasLockedBefore)
				{
					LockpickerTiming.ApplyUnlockingSettings(doorScript, Plugin.UnlockingTimeVar?.Value ?? ConfigSettings.UnlockingTime);
					LockpickerState.ClearLockingSession(__instance);
				}
				else
				{
					LNetworkVariable<bool> canLockDoorsVar = Plugin.CanLockDoorsVar;
					if (!((canLockDoorsVar != null) ? (!canLockDoorsVar.Value) : ConfigSettings.CanLockDoors))
					{
						float num2 = Mathf.Max(0.1f, (float)(Plugin.LockingTimeVar?.Value ?? ConfigSettings.LockingTime));
						bool temporaryLockingAtStart5 = Plugin.TemporaryLockingVar?.Value ?? ConfigSettings.TemporaryLocking;
						LockpickerState.RegisterLockingSession(__instance, doorScript, num2, temporaryLockingAtStart5);
						bool doLockDoor3 = (Object)(object)NetworkManager.Singleton == (Object)null || (NetworkManager.Singleton.IsClient && !NetworkManager.Singleton.IsServer);
						LockpickerTiming.ApplyLockingSettings(doorScript, num2, doLockDoor3);
					}
				}
			}
		}

		[HarmonyPatch(typeof(LockPicker), "FinishPickingLock")]
		internal static class LockPicker_FinishPickingLock_Patch
		{
			private struct FinishState
			{
				public DoorLock Door;

				public float LockingTime;

				public bool TemporaryLockingAtStart;
			}

			private static void Prefix(LockPicker __instance, out FinishState __state)
			{
				__state = default(FinishState);
				if (LockpickerState.TryGetLockingSession(__instance, out var door, out var lockingTime, out var temporaryLockingAtStart))
				{
					__state.Door = door;
					__state.LockingTime = lockingTime;
					__state.TemporaryLockingAtStart = temporaryLockingAtStart;
				}
			}

			private static void Postfix(LockPicker __instance, FinishState __state)
			{
				if (!((Object)(object)__state.Door == (Object)null))
				{
					LockpickerState.ClearLockingSession(__instance);
					if (!__state.TemporaryLockingAtStart)
					{
						float num = Mathf.Max(0.1f, (__state.LockingTime > 0.01f) ? __state.LockingTime : ((float)(Plugin.LockingTimeVar?.Value ?? ConfigSettings.LockingTime)));
						__state.Door.LockDoor(num);
					}
				}
			}
		}

		[HarmonyPatch(typeof(LockPicker), "EquipItem")]
		internal static class LockPicker_EquipItem_Patch
		{
			private static void Postfix(LockPicker __instance)
			{
				if (LockpickerState.TryGetLockingDoor(__instance, out var door))
				{
					LockpickerState.ClearLockingSession(__instance);
					if ((Object)(object)door != (Object)null && door.isLocked)
					{
						door.UnlockDoorSyncWithServer();
					}
				}
			}
		}

		[HarmonyPatch(typeof(DoorLock), "Update")]
		internal static class DoorLock_Update_Patch
		{
			private static void Postfix(DoorLock __instance)
			{
				if ((Object)(object)__instance == (Object)null)
				{
					return;
				}
				if (LockpickerState.IsLockingDoor(__instance) && (!__instance.isLocked || !__instance.isPickingLock))
				{
					LockpickerState.ClearLockingDoor(__instance);
				}
				else
				{
					if (!__instance.isLocked || !__instance.isPickingLock)
					{
						return;
					}
					ulong doorNetworkId = LockpickerTiming.GetDoorNetworkId(__instance);
					if (!LockpickerState.IsLockingDoor(__instance) && doorNetworkId != 0L && LockpickerNetSync.TryConsumePendingDoor(doorNetworkId, out var lockingTime, out var temporaryLockingAtStart) && lockingTime > 0.01f)
					{
						LockpickerState.RegisterLockingDoor(__instance, lockingTime, temporaryLockingAtStart);
						bool doLockDoor = (Object)(object)NetworkManager.Singleton == (Object)null || (NetworkManager.Singleton.IsClient && !NetworkManager.Singleton.IsServer);
						LockpickerTiming.ApplyLockingSettings(__instance, lockingTime, doLockDoor);
					}
					if (LockpickerState.IsLockingDoor(__instance) && LockpickerState.TryGetLockingDoorTime(__instance, out var lockingTime2) && lockingTime2 > 0.01f)
					{
						InteractTrigger component = ((Component)__instance).GetComponent<InteractTrigger>();
						if (Mathf.Abs(__instance.maxTimeLeft - lockingTime2) > 0.05f || ((Object)(object)component != (Object)null && Mathf.Abs(component.timeToHold - lockingTime2) > 0.05f))
						{
							LockpickerTiming.ApplyLockingSettings(__instance, lockingTime2, doLockDoor: false);
						}
						if ((Object)(object)component != (Object)null)
						{
							bool temporaryLockingAtStart2;
							string arg = ((LockpickerState.TryGetLockingDoorTemporary(__instance, out temporaryLockingAtStart2) && temporaryLockingAtStart2) ? "Blocking door" : "Locking door");
							component.disabledHoverTip = $"{arg}: {(int)__instance.lockPickTimeLeft} sec.";
						}
					}
				}
			}
		}

		[HarmonyPatch(typeof(LockPicker), "PlaceLockPickerServerRpc")]
		internal static class LockPicker_PlaceLockPickerServerRpc_Patch
		{
			private struct RpcState
			{
				public bool IsServerStage;

				public bool DoorWasLockedBefore;

				public ulong DoorNetId;
			}

			private static readonly FieldInfo RpcExecStageField = AccessTools.Field(typeof(NetworkBehaviour), "__rpc_exec_stage");

			private static void Prefix(LockPicker __instance, NetworkObjectReference doorObject, bool lockPicker1, out RpcState __state)
			{
				__state = default(RpcState);
				__state.IsServerStage = IsServerRpcStage(__instance);
				NetworkObject val = default(NetworkObject);
				if (__state.IsServerStage && ((NetworkObjectReference)(ref doorObject)).TryGet(ref val, (NetworkManager)null) && !((Object)(object)val == (Object)null))
				{
					__state.DoorNetId = val.NetworkObjectId;
					DoorLock componentInChildren = ((Component)val).GetComponentInChildren<DoorLock>();
					__state.DoorWasLockedBefore = (Object)(object)componentInChildren != (Object)null && componentInChildren.isLocked;
				}
			}

			private static void Postfix(LockPicker __instance, NetworkObjectReference doorObject, bool lockPicker1, RpcState __state)
			{
				NetworkObject val = default(NetworkObject);
				if (__state.IsServerStage && ((NetworkObjectReference)(ref doorObject)).TryGet(ref val, (NetworkManager)null) && !((Object)(object)val == (Object)null))
				{
					DoorLock componentInChildren = ((Component)val).GetComponentInChildren<DoorLock>();
					if (!((Object)(object)componentInChildren == (Object)null) && !__state.DoorWasLockedBefore)
					{
						float num = Mathf.Max(0.1f, (float)(Plugin.LockingTimeVar?.Value ?? ConfigSettings.LockingTime));
						bool temporaryLockingAtStart = Plugin.TemporaryLockingVar?.Value ?? ConfigSettings.TemporaryLocking;
						LockpickerState.RegisterLockingSession(__instance, componentInChildren, num, temporaryLockingAtStart);
						LockpickerTiming.ApplyLockingSettings(componentInChildren, num, doLockDoor: true);
						LockpickerNetSync.SendLockingStartedToAll(((NetworkBehaviour)__instance).NetworkObjectId, __state.DoorNetId, num);
					}
				}
			}

			private static bool IsServerRpcStage(LockPicker instance)
			{
				if ((Object)(object)instance == (Object)null)
				{
					return false;
				}
				if (RpcExecStageField != null)
				{
					object value = RpcExecStageField.GetValue(instance);
					if (value != null)
					{
						return value.ToString() == "Server";
					}
				}
				NetworkManager singleton = NetworkManager.Singleton;
				if ((Object)(object)singleton != (Object)null)
				{
					return singleton.IsServer;
				}
				return false;
			}
		}

		private const int DoorMask = 2816;
	}
}
namespace BetterLockpicker.Config
{
	internal static class ConfigSettings
	{
		private static ConfigEntry<bool> _canLockDoors;

		private static ConfigEntry<bool> _temporaryLocking;

		private static ConfigEntry<int> _lockingTime;

		private static ConfigEntry<int> _unlockingTime;

		private static readonly bool _default_canLockDoors = true;

		private static readonly bool _default_temporaryLocking = false;

		private static readonly int _default_lockingTime = 30;

		private static readonly int _default_unlockingTime = 30;

		internal static bool CanLockDoors = _default_canLockDoors;

		internal static bool TemporaryLocking = _default_temporaryLocking;

		internal static int LockingTime = _default_lockingTime;

		internal static int UnlockingTime = _default_unlockingTime;

		internal static void Init(BaseUnityPlugin plugin)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Expected O, but got Unknown
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Expected O, but got Unknown
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Expected O, but got Unknown
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Expected O, but got Unknown
			ConfigFile config = plugin.Config;
			_canLockDoors = config.Bind<bool>("Locking Doors", "CanLockDoors", _default_canLockDoors, new ConfigDescription("When enabled, lockpickers can be used to lock doors.", (AcceptableValueBase)null, Array.Empty<object>()));
			_temporaryLocking = config.Bind<bool>("Locking Doors", "Temporary Locking", _default_temporaryLocking, new ConfigDescription("When enabled, lockpickers can only hold doors shut while attached to the door. When the lockpicker detaches from the door, the door will always be unlocked.", (AcceptableValueBase)null, Array.Empty<object>()));
			_lockingTime = config.Bind<int>("Locking Doors", "LockingTime", _default_lockingTime, new ConfigDescription("The time it takes to lock a door (in seconds).", (AcceptableValueBase)null, Array.Empty<object>()));
			_unlockingTime = config.Bind<int>("Unlocking Doors", "UnlockingTime", _default_unlockingTime, new ConfigDescription("The time it takes to unlock a door (in seconds).", (AcceptableValueBase)null, Array.Empty<object>()));
			LethalConfigCompat.Register(_canLockDoors);
			LethalConfigCompat.Register(_temporaryLocking);
			LethalConfigCompat.Register(_lockingTime);
			LethalConfigCompat.Register(_unlockingTime);
			_canLockDoors.SettingChanged += OnCanLockDoorsChanged;
			_temporaryLocking.SettingChanged += OnTemporaryLockingChanged;
			_lockingTime.SettingChanged += OnLockingTimeChanged;
			_unlockingTime.SettingChanged += OnUnlockingTimeChanged;
			UpdateCanLockDoors();
			UpdateTemporaryLocking();
			UpdateLockingTime();
			UpdateUnlockingTime();
		}

		private static void OnCanLockDoorsChanged(object sender, EventArgs e)
		{
			UpdateCanLockDoors();
		}

		private static void OnTemporaryLockingChanged(object sender, EventArgs e)
		{
			UpdateTemporaryLocking();
		}

		private static void OnLockingTimeChanged(object sender, EventArgs e)
		{
			UpdateLockingTime();
		}

		private static void OnUnlockingTimeChanged(object sender, EventArgs e)
		{
			UpdateUnlockingTime();
		}

		private static void UpdateCanLockDoors()
		{
			CanLockDoors = _canLockDoors?.Value ?? _default_canLockDoors;
			if (Plugin.IsHost() && Plugin.CanLockDoorsVar != null)
			{
				Plugin.CanLockDoorsVar.Value = CanLockDoors;
			}
		}

		private static void UpdateTemporaryLocking()
		{
			TemporaryLocking = _temporaryLocking?.Value ?? _default_temporaryLocking;
			if (Plugin.IsHost() && Plugin.TemporaryLockingVar != null)
			{
				Plugin.TemporaryLockingVar.Value = TemporaryLocking;
			}
		}

		private static void UpdateLockingTime()
		{
			LockingTime = _lockingTime?.Value ?? _default_lockingTime;
			if (Plugin.IsHost() && Plugin.LockingTimeVar != null)
			{
				Plugin.LockingTimeVar.Value = LockingTime;
			}
		}

		private static void UpdateUnlockingTime()
		{
			UnlockingTime = _unlockingTime?.Value ?? _default_unlockingTime;
			if (Plugin.IsHost() && Plugin.UnlockingTimeVar != null)
			{
				Plugin.UnlockingTimeVar.Value = UnlockingTime;
			}
		}
	}
}