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;
}
}
}
}