Decompiled source of DropAndGrabOverhaul v0.2.9

plugins/bobabulkerENTERPRISE.DropAndGrabOverhaul.dll

Decompiled 9 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using System.Reflection.Emit;
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 DropAndGrabOverhaul.Compatibility;
using DropAndGrabOverhaul.Configuration;
using DropAndGrabOverhaul.Features;
using DropAndGrabOverhaul.Inputs;
using DropAndGrabOverhaul.Inventory;
using GameNetcodeStuff;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("bobabulkerENTERPRISE.DropAndGrabOverhaul")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.2.9.0")]
[assembly: AssemblyInformationalVersion("0.2.9+68161df5e1382b4ca19e7fb28c1a1a77851b0de2")]
[assembly: AssemblyProduct("bobabulkerENTERPRISE.DropAndGrabOverhaul")]
[assembly: AssemblyTitle("DropAndGrabOverhaul")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.2.9.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

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

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace BepInEx
{
	[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
	[Conditional("CodeGeneration")]
	[Embedded]
	internal sealed class BepInAutoPluginAttribute : Attribute
	{
		public BepInAutoPluginAttribute(string? id = null, string? name = null, string? version = null)
		{
		}
	}
}
namespace BepInEx.Preloader.Core.Patching
{
	[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
	[Conditional("CodeGeneration")]
	[Embedded]
	internal sealed class PatcherAutoPluginAttribute : Attribute
	{
		public PatcherAutoPluginAttribute(string? id = null, string? name = null, string? version = null)
		{
		}
	}
}
namespace Microsoft.CodeAnalysis
{
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace DropAndGrabOverhaul
{
	internal static class ModLog
	{
		private static ManualLogSource? source;

		public static void Initialize(ManualLogSource logSource)
		{
			source = logSource;
		}

		public static void Fatal(object data)
		{
			Write((LogLevel)1, data);
		}

		public static void Error(object data)
		{
			Write((LogLevel)2, data);
		}

		public static void Warning(object data)
		{
			Write((LogLevel)4, data);
		}

		public static void Message(object data)
		{
			Write((LogLevel)8, data);
		}

		public static void Info(object data)
		{
			Write((LogLevel)16, data);
		}

		public static void Debug(object data)
		{
			Write((LogLevel)32, data);
		}

		public static void Announce(object data)
		{
			ManualLogSource? obj = source;
			if (obj != null)
			{
				obj.LogInfo(data);
			}
		}

		private static void Write(LogLevel level, object data)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			if (source != null && LoggingConfiguration.IsEnabled(level))
			{
				source.Log(level, data);
			}
		}
	}
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInPlugin("bobabulkerENTERPRISE.DropAndGrabOverhaul", "DropAndGrabOverhaul", "0.2.9")]
	public class Plugin : BaseUnityPlugin
	{
		public const string Id = "bobabulkerENTERPRISE.DropAndGrabOverhaul";

		public static string Name => "DropAndGrabOverhaul";

		public static string Version => "0.2.9";

		private void Awake()
		{
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			ModLog.Initialize(((BaseUnityPlugin)this).Logger);
			LoggingConfiguration.Initialize(((BaseUnityPlugin)this).Config);
			ItemBlacklist.Initialize(((BaseUnityPlugin)this).Config);
			InputConfiguration.Initialize(((BaseUnityPlugin)this).Config);
			GrabConfiguration.Initialize(((BaseUnityPlugin)this).Config);
			PlaceConfiguration.Initialize(((BaseUnityPlugin)this).Config);
			new Harmony("bobabulkerENTERPRISE.DropAndGrabOverhaul").PatchAll(Assembly.GetExecutingAssembly());
			ModLog.Info("Plugin " + Name + " is loaded!");
		}
	}
	internal sealed class UpdateRunner : MonoBehaviour
	{
		private static UpdateRunner? instance;

		private const int MaxConsecutiveFailures = 3;

		private int consecutiveFailures;

		private bool faulted;

		private readonly CoroutineGate routineGate = new CoroutineGate();

		private DepositItemsDesk? cachedDesk;

		private bool deskSearched;

		internal static bool IsActive
		{
			get
			{
				if ((Object)(object)instance != (Object)null)
				{
					return !instance.faulted;
				}
				return false;
			}
		}

		internal static void EnsureCreated()
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Expected O, but got Unknown
			if (!((Object)(object)instance != (Object)null))
			{
				GameObject val = new GameObject("DropAndGrabOverhaulRunner");
				Object.DontDestroyOnLoad((Object)(object)val);
				instance = val.AddComponent<UpdateRunner>();
				ModLog.Info("UpdateRunner created via StartOfRound.Awake postfix");
			}
		}

		private void OnEnable()
		{
			SceneManager.sceneLoaded += OnSceneLoaded;
			SceneManager.sceneUnloaded += OnSceneUnloaded;
		}

		private void OnDisable()
		{
			SceneManager.sceneLoaded -= OnSceneLoaded;
			SceneManager.sceneUnloaded -= OnSceneUnloaded;
		}

		private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
		{
			consecutiveFailures = 0;
			faulted = false;
			ForgetDesk();
		}

		private void OnSceneUnloaded(Scene scene)
		{
			ForgetDesk();
		}

		private void ForgetDesk()
		{
			cachedDesk = null;
			deskSearched = false;
		}

		private void Update()
		{
			if (faulted)
			{
				return;
			}
			try
			{
				Tick();
				consecutiveFailures = 0;
			}
			catch (Exception arg)
			{
				consecutiveFailures++;
				ModLog.Error($"UpdateRunner failed ({consecutiveFailures}/{3}): {arg}");
				if (consecutiveFailures >= 3)
				{
					faulted = true;
					ModLog.Error("Too many consecutive failures - vanilla's drop handler takes over until the next scene.");
				}
			}
		}

		private void Tick()
		{
			PlayerControllerB val = StartOfRound.Instance?.localPlayerController;
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			if (!DropGuard.CanAcceptDropInput(val))
			{
				InputHandler.ResetDropKeyTracking();
				return;
			}
			if (InputHandler.WasDropKeyPressedThisFrame() && (Object)(object)ShipBuildModeManager.Instance != (Object)null && DropGuard.CanCancelBuildMode(val))
			{
				ShipBuildModeManager.Instance.CancelBuildMode(true);
			}
			if (IsHoveringDesk(val, out DepositItemsDesk desk))
			{
				if (!routineGate.IsRunning && InputHandler.WasDropKeyPressedThisFrame())
				{
					routineGate.Start((MonoBehaviour)(object)this, AutoPlaceRoutine.Run(val, desk));
				}
				InputHandler.ResetDropKeyTracking();
				return;
			}
			switch (InputHandler.Poll())
			{
			case DropGesture.Tap:
				if (DropGuard.CanDropHeldItemNow(val))
				{
					DropHeldItem(val);
				}
				break;
			case DropGesture.DoubleTap:
				StartDropAll(val, includeReservedSlots: false, ignoreBlacklist: false);
				break;
			case DropGesture.ForceDrop:
				StartDropAll(val, includeReservedSlots: false, ignoreBlacklist: true);
				break;
			case DropGesture.ForceDropReserved:
				StartDropAll(val, includeReservedSlots: true, ignoreBlacklist: true);
				break;
			}
		}

		private void DropHeldItem(PlayerControllerB player)
		{
			//IL_005c: 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_0035: 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)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			GrabbableObject currentlyHeldObjectServer = player.currentlyHeldObjectServer;
			if ((Object)(object)currentlyHeldObjectServer == (Object)null)
			{
				return;
			}
			DepositItemsDesk desk = GetDesk();
			if ((Object)(object)desk != (Object)null && (Object)(object)desk.triggerCollider != (Object)null)
			{
				Bounds bounds = ((Collider)desk.triggerCollider).bounds;
				if (((Bounds)(ref bounds)).Contains(((Component)currentlyHeldObjectServer).transform.position))
				{
					desk.PlaceItemOnCounter(player);
					return;
				}
			}
			player.DiscardHeldObject(false, (NetworkObject)null, default(Vector3), true);
		}

		private void StartDropAll(PlayerControllerB player, bool includeReservedSlots, bool ignoreBlacklist)
		{
			if (!routineGate.IsRunning)
			{
				List<(int, GrabbableObject)> itemSlots = InventoryAccessor.GetItemSlots(player, includeReservedSlots);
				if (itemSlots.Count > 0)
				{
					routineGate.Start((MonoBehaviour)(object)this, DropAllRoutine.Run(player, itemSlots, ignoreBlacklist));
				}
			}
		}

		private DepositItemsDesk? GetDesk()
		{
			if (!deskSearched)
			{
				deskSearched = true;
				cachedDesk = Object.FindObjectOfType<DepositItemsDesk>();
				ModLog.Info(((Object)(object)cachedDesk != (Object)null) ? "Company desk found" : "No company desk in this scene");
			}
			return cachedDesk;
		}

		private bool IsHoveringDesk(PlayerControllerB player, [NotNullWhen(true)] out DepositItemsDesk? desk)
		{
			desk = null;
			if ((Object)(object)player.hoveringOverTrigger == (Object)null)
			{
				return false;
			}
			DepositItemsDesk desk2 = GetDesk();
			if ((Object)(object)desk2 == (Object)null || (Object)(object)desk2.triggerScript == (Object)null)
			{
				return false;
			}
			if ((Object)(object)player.hoveringOverTrigger != (Object)(object)desk2.triggerScript)
			{
				return false;
			}
			desk = desk2;
			return true;
		}
	}
}
namespace DropAndGrabOverhaul.Patches
{
	[HarmonyPatch(typeof(StartOfRound), "Awake")]
	internal static class StartOfRoundPatch
	{
		[HarmonyPostfix]
		private static void Postfix()
		{
			UpdateRunner.EnsureCreated();
		}
	}
	[HarmonyPatch(typeof(PlayerControllerB), "Discard_performed")]
	internal static class DiscardPerformedPatch
	{
		[HarmonyPrefix]
		private static bool Prefix()
		{
			if (!UpdateRunner.IsActive || !InputHandler.IsDropActionAvailable)
			{
				return true;
			}
			if (DropGuard.IsControllerBuildModeStore())
			{
				return true;
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(InteractTrigger), "Interact")]
	internal static class GrabCooldownPatch
	{
		[HarmonyPrefix]
		private static void Prefix(InteractTrigger __instance)
		{
			if ((Object)(object)((Component)__instance).GetComponentInParent<GrabbableObject>() != (Object)null)
			{
				__instance.cooldownTime = GrabConfiguration.GrabDelay;
			}
		}
	}
	[HarmonyPatch(/*Could not decode attribute arguments.*/)]
	public static class GrabObjectDelayPatch
	{
		private const float FirstWaitSeconds = 0.1f;

		private const float AnimationOffsetSeconds = 0.2f;

		private const int ExpectedPatchCount = 2;

		public static float GetCooldownDecrease()
		{
			return 0.2f - GrabConfiguration.GrabDelay;
		}

		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Expected O, but got Unknown
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Expected O, but got Unknown
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Expected O, but got Unknown
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Expected O, but got Unknown
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Expected O, but got Unknown
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Expected O, but got Unknown
			MethodInfo methodInfo = AccessTools.Method(typeof(GrabObjectDelayPatch), "GetCooldownDecrease", (Type[])null, (Type[])null);
			List<CodeInstruction> list = new List<CodeInstruction>(instructions);
			List<CodeInstruction> list2 = new List<CodeInstruction>(list.Count + 8);
			int num = 0;
			for (int i = 0; i < list.Count; i++)
			{
				CodeInstruction val = list[i];
				list2.Add(val);
				if (!(val.opcode != OpCodes.Ldc_R4) && val.operand is float num2 && i + 1 < list.Count)
				{
					OpCode opcode = list[i + 1].opcode;
					if (num2 == 0.1f && opcode == OpCodes.Newobj)
					{
						list2.Add(new CodeInstruction(OpCodes.Call, (object)methodInfo));
						list2.Add(new CodeInstruction(OpCodes.Ldc_R4, (object)2f));
						list2.Add(new CodeInstruction(OpCodes.Div, (object)null));
						list2.Add(new CodeInstruction(OpCodes.Sub, (object)null));
						num++;
					}
					else if (num2 == 0.2f && opcode == OpCodes.Sub)
					{
						list2.Add(new CodeInstruction(OpCodes.Sub, (object)null));
						list2.Add(new CodeInstruction(OpCodes.Call, (object)methodInfo));
						num++;
					}
				}
			}
			if (num != 2)
			{
				ModLog.Warning($"GrabObjectDelayPatch matched {num} delay checkpoint(s), expected {2} - the game's GrabObject() IL probably changed, so it was left unpatched and the vanilla grab delay applies.");
				return list;
			}
			return list2;
		}
	}
}
namespace DropAndGrabOverhaul.Inventory
{
	internal static class InventoryAccessor
	{
		public static List<(int Slot, GrabbableObject Item)> GetItemSlots(PlayerControllerB? player, bool includeReservedSlots = true)
		{
			List<(int, GrabbableObject)> list = new List<(int, GrabbableObject)>();
			if (player?.ItemSlots == null)
			{
				return list;
			}
			for (int i = 0; i < player.ItemSlots.Length; i++)
			{
				GrabbableObject val = player.ItemSlots[i];
				if (!((Object)(object)val == (Object)null) && (includeReservedSlots || !IsReservedSlot(player, i)))
				{
					list.Add((i, val));
				}
			}
			return list;
		}

		public static bool IsReservedSlot(PlayerControllerB? player, int slot)
		{
			return ReservedItemSlotCompat.IsReservedSlot(player, slot);
		}
	}
}
namespace DropAndGrabOverhaul.Inputs
{
	internal enum DropGesture
	{
		None,
		Tap,
		DoubleTap,
		ForceDrop,
		ForceDropReserved
	}
	internal readonly struct DropTimings
	{
		public float DoubleTapWindow { get; }

		public float ForceDropHold { get; }

		public float ReservedSlotsHold { get; }

		public DropTimings(float doubleTapWindow, float forceDropHold, float reservedSlotsHold)
		{
			DoubleTapWindow = doubleTapWindow;
			ForceDropHold = forceDropHold;
			ReservedSlotsHold = reservedSlotsHold;
		}
	}
	internal sealed class DropGestureTracker
	{
		private float lastTapTime = float.NegativeInfinity;

		private bool holding;

		private float holdStartTime;

		private bool suppressUntilReleased;

		public DropGesture Update(float now, bool pressedThisFrame, bool isDown, in DropTimings timings)
		{
			if (suppressUntilReleased)
			{
				if (isDown)
				{
					return DropGesture.None;
				}
				suppressUntilReleased = false;
			}
			if (isDown)
			{
				if (!holding)
				{
					holding = true;
					holdStartTime = now;
				}
				float num = now - holdStartTime;
				if (num >= timings.ForceDropHold)
				{
					lastTapTime = float.NegativeInfinity;
					if (!(num >= timings.ForceDropHold + timings.ReservedSlotsHold))
					{
						return DropGesture.ForceDrop;
					}
					return DropGesture.ForceDropReserved;
				}
			}
			else
			{
				holding = false;
			}
			if (!pressedThisFrame)
			{
				return DropGesture.None;
			}
			if (now - lastTapTime < timings.DoubleTapWindow)
			{
				lastTapTime = float.NegativeInfinity;
				return DropGesture.DoubleTap;
			}
			lastTapTime = now;
			return DropGesture.Tap;
		}

		public void Reset(bool keyIsDown)
		{
			holding = false;
			lastTapTime = float.NegativeInfinity;
			suppressUntilReleased = keyIsDown;
		}
	}
	internal static class DropGuard
	{
		private const float SlotSwitchCooldownSeconds = 0.2f;

		private const int JetpackItemId = 13;

		public static bool CanAcceptDropInput(PlayerControllerB player)
		{
			if (!((NetworkBehaviour)player).IsOwner || !player.isPlayerControlled || (((NetworkBehaviour)player).IsServer && !player.isHostPlayerObject))
			{
				return false;
			}
			if (player.isTypingChat || player.inTerminalMenu || player.inSpecialInteractAnimation || player.activatingItem)
			{
				return false;
			}
			if ((Object)(object)player.quickMenuManager != (Object)null && player.quickMenuManager.isMenuOpen)
			{
				return false;
			}
			if (IsControllerBuildModeStore())
			{
				return false;
			}
			GrabbableObject currentlyHeldObjectServer = player.currentlyHeldObjectServer;
			bool flag = (player.jetpackControls || player.disablingJetpackControls) && (Object)(object)currentlyHeldObjectServer != (Object)null && currentlyHeldObjectServer.itemProperties.itemId == 13;
			return !flag;
		}

		public static bool IsControllerBuildModeStore()
		{
			StartOfRound instance = StartOfRound.Instance;
			ShipBuildModeManager instance2 = ShipBuildModeManager.Instance;
			if ((Object)(object)instance != (Object)null && (Object)(object)instance2 != (Object)null && instance.localPlayerUsingController)
			{
				return instance2.InBuildMode;
			}
			return false;
		}

		public static bool CanCancelBuildMode(PlayerControllerB player)
		{
			if (!player.isGrabbingObjectAnimation)
			{
				return player.timeSinceSwitchingSlots >= 0.2f;
			}
			return false;
		}

		public static bool CanDropHeldItemNow(PlayerControllerB player)
		{
			if (player.isHoldingObject && (Object)(object)player.currentlyHeldObjectServer != (Object)null && !player.isGrabbingObjectAnimation && !player.throwingObject)
			{
				return player.timeSinceSwitchingSlots >= 0.2f;
			}
			return false;
		}
	}
	internal static class InputHandler
	{
		private static readonly DropGestureTracker tracker = new DropGestureTracker();

		private const string DropActionName = "Discard";

		private static InputAction? dropAction;

		private static bool loggedMissingDropAction;

		public static bool IsDropActionAvailable => GetDropAction() != null;

		private static InputAction? GetDropAction()
		{
			if (dropAction != null)
			{
				return dropAction;
			}
			InputActionAsset actions = InputSystem.actions;
			if ((Object)(object)actions != (Object)null)
			{
				dropAction = actions.FindAction("Discard", false);
			}
			if (dropAction != null)
			{
				ModLog.Info("Using vanilla 'Discard' action as the drop key (currently bound to: " + InputActionRebindingExtensions.GetBindingDisplayString(dropAction, (DisplayStringOptions)0, (string)null) + ")");
			}
			else if (!loggedMissingDropAction)
			{
				loggedMissingDropAction = true;
				ModLog.Error("Could not find vanilla input action 'Discard' - drop-key features are disabled.");
			}
			return dropAction;
		}

		public static bool WasDropKeyPressedThisFrame()
		{
			InputAction? obj = GetDropAction();
			if (obj == null)
			{
				return false;
			}
			return obj.WasPressedThisFrame();
		}

		public static bool IsDropKeyPressed()
		{
			InputAction? obj = GetDropAction();
			if (obj == null)
			{
				return false;
			}
			return obj.IsPressed();
		}

		public static DropGesture Poll()
		{
			DropTimings timings = new DropTimings(InputConfiguration.DoubleTapWindow, InputConfiguration.ForceDropHoldDuration, InputConfiguration.ReservedSlotsHoldDuration);
			return tracker.Update(Time.time, WasDropKeyPressedThisFrame(), IsDropKeyPressed(), in timings);
		}

		public static void ResetDropKeyTracking()
		{
			tracker.Reset(IsDropKeyPressed());
		}
	}
}
namespace DropAndGrabOverhaul.Features
{
	internal sealed class CoroutineGate
	{
		private bool running;

		public bool IsRunning => running;

		public void Start(MonoBehaviour host, IEnumerator routine)
		{
			if (running || !((Behaviour)host).isActiveAndEnabled)
			{
				return;
			}
			running = true;
			try
			{
				host.StartCoroutine(Run(routine));
			}
			catch
			{
				running = false;
				throw;
			}
		}

		private IEnumerator Run(IEnumerator routine)
		{
			try
			{
				while (routine.MoveNext())
				{
					yield return routine.Current;
				}
			}
			finally
			{
				running = false;
			}
		}
	}
	internal static class RoutineSupport
	{
		private const float IdleTimeoutSeconds = 3f;

		public static bool IsBusy(PlayerControllerB player)
		{
			if (!player.isGrabbingObjectAnimation)
			{
				return player.throwingObject;
			}
			return true;
		}

		public static bool IsPlayerGone(PlayerControllerB player)
		{
			if (!((Object)(object)player == (Object)null) && !player.isPlayerDead)
			{
				return !player.isPlayerControlled;
			}
			return true;
		}

		public static bool ShouldKeepWaiting(PlayerControllerB player, float waitStart)
		{
			if (IsBusy(player) && !IsPlayerGone(player))
			{
				return Time.time - waitStart < 3f;
			}
			return false;
		}

		public static void SwitchToSlot(PlayerControllerB player, int slot)
		{
			bool flag = player.currentItemSlot != slot;
			player.SwitchToItemSlot(slot, (GrabbableObject)null);
			if (flag)
			{
				player.SwitchToSlotServerRpc(slot);
			}
		}
	}
	internal static class AutoPlaceRoutine
	{
		private const float DelayBetweenPlacementsSeconds = 0.2f;

		public static IEnumerator Run(PlayerControllerB player, DepositItemsDesk desk)
		{
			foreach (var itemSlot in InventoryAccessor.GetItemSlots(player, includeReservedSlots: false))
			{
				int slot = itemSlot.Slot;
				GrabbableObject item = itemSlot.Item;
				float waitStart = Time.time;
				while (RoutineSupport.ShouldKeepWaiting(player, waitStart))
				{
					yield return null;
				}
				if (RoutineSupport.IsPlayerGone(player) || (Object)(object)desk == (Object)null)
				{
					yield break;
				}
				if (RoutineSupport.IsBusy(player))
				{
					ModLog.Warning("Timed out waiting for the previous grab/placement to finish - stopping auto-place early to avoid desyncing the rest.");
					yield break;
				}
				if (!((Object)(object)item == (Object)null) && slot < player.ItemSlots.Length && !((Object)(object)player.ItemSlots[slot] != (Object)(object)item) && item.itemProperties.isScrap && !PlaceConfiguration.IsPlaceBlacklisted(item.itemProperties.itemName))
				{
					RoutineSupport.SwitchToSlot(player, slot);
					desk.PlaceItemOnCounter(player);
					yield return (object)new WaitForSeconds(0.2f);
				}
			}
		}
	}
	internal static class DropAllRoutine
	{
		public static IEnumerator Run(PlayerControllerB player, List<(int Slot, GrabbableObject Item)> items, bool ignoreBlacklist)
		{
			bool droppedReservedItem = false;
			foreach (var item2 in items)
			{
				int slot = item2.Slot;
				GrabbableObject item = item2.Item;
				float waitStart = Time.time;
				while (RoutineSupport.ShouldKeepWaiting(player, waitStart))
				{
					yield return null;
				}
				if (!RoutineSupport.IsPlayerGone(player))
				{
					if (RoutineSupport.IsBusy(player))
					{
						ModLog.Warning("Timed out waiting for the previous grab/drop to finish - stopping drop-all early to avoid desyncing the rest.");
						break;
					}
					if (!((Object)(object)item == (Object)null) && slot < player.ItemSlots.Length && !((Object)(object)player.ItemSlots[slot] != (Object)(object)item) && (ignoreBlacklist || !ItemBlacklist.IsBlacklisted(item.itemProperties.itemName)))
					{
						droppedReservedItem |= InventoryAccessor.IsReservedSlot(player, slot);
						RoutineSupport.SwitchToSlot(player, slot);
						player.DiscardHeldObject(false, (NetworkObject)null, default(Vector3), true);
					}
					continue;
				}
				yield break;
			}
			if (droppedReservedItem)
			{
				float lastWaitStart = Time.time;
				while (RoutineSupport.ShouldKeepWaiting(player, lastWaitStart))
				{
					yield return null;
				}
				if (!RoutineSupport.IsPlayerGone(player))
				{
					yield return (object)new WaitForEndOfFrame();
					yield return null;
					ReservedItemSlotCompat.RefreshHudAfterReservedDrop();
				}
			}
		}
	}
}
namespace DropAndGrabOverhaul.Configuration
{
	internal sealed class ItemNameList
	{
		public const string DefaultNames = "Walkie-talkie, Flashlight, Shovel, Lockpicker, Pro-flashlight, Stun grenade, Boombox, TZP-Inhalant, Zap gun, Jetpack, Extension ladder, Radar-booster, Spray paint, Weed killer, Belt bag, Stop sign, Yield sign, Kitchen knife, Shotgun, Ammo, Key, Medic Bag, Night Vision Goggles, Cat, Cat Food, IFireAxe, IBaseball bat, Plunger, Mega Flashlight, Firework Crate, Firework Rocket, Beacon, Emergency Flare, Pile of Glowsticks, Flip Lighter, Bullet Lighter, Impact flash, Jammer, Light crowbar, Military shotgun, Single shotgun, Gohei, Pink Guitar, Antique Candle, Industrial Flashlight";

		private readonly ConfigEntry<string> entry;

		private HashSet<string> names = new HashSet<string>();

		public ItemNameList(ConfigFile config, string section, string key, string description)
		{
			entry = config.Bind<string>(section, key, "Walkie-talkie, Flashlight, Shovel, Lockpicker, Pro-flashlight, Stun grenade, Boombox, TZP-Inhalant, Zap gun, Jetpack, Extension ladder, Radar-booster, Spray paint, Weed killer, Belt bag, Stop sign, Yield sign, Kitchen knife, Shotgun, Ammo, Key, Medic Bag, Night Vision Goggles, Cat, Cat Food, IFireAxe, IBaseball bat, Plunger, Mega Flashlight, Firework Crate, Firework Rocket, Beacon, Emergency Flare, Pile of Glowsticks, Flip Lighter, Bullet Lighter, Impact flash, Jammer, Light crowbar, Military shotgun, Single shotgun, Gohei, Pink Guitar, Antique Candle, Industrial Flashlight", description);
			entry.SettingChanged += delegate
			{
				Reload();
			};
			Reload();
		}

		public bool Contains(string itemName)
		{
			return names.Contains(itemName);
		}

		private void Reload()
		{
			HashSet<string> hashSet = new HashSet<string>();
			if (!string.IsNullOrWhiteSpace(entry.Value))
			{
				string[] array = entry.Value.Split(',');
				foreach (string text in array)
				{
					string text2 = text.Trim();
					if (text2.Length > 0)
					{
						hashSet.Add(text2);
					}
				}
			}
			names = hashSet;
		}
	}
	internal static class LoggingConfiguration
	{
		private static ConfigEntry<LogLevel>? logLevelsConfig;

		public static void Initialize(ConfigFile config)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			logLevelsConfig = config.Bind<LogLevel>("Logging", "LogLevels", (LogLevel)7, "Which of this mod's own log levels to show. Multiple values can be set at the same time by separating them with , (e.g. Warning, Info).");
			ModLog.Announce($"Logging levels enabled: {logLevelsConfig.Value}");
		}

		public static bool IsEnabled(LogLevel level)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Invalid comparison between Unknown and I4
			if (logLevelsConfig != null)
			{
				return (logLevelsConfig.Value & level) > 0;
			}
			return false;
		}
	}
	internal static class InputConfiguration
	{
		private static ConfigEntry<float> doubleTapWindow;

		private static ConfigEntry<float> forceDropHoldDuration;

		private static ConfigEntry<float> reservedSlotsHoldDuration;

		public static float DoubleTapWindow => doubleTapWindow.Value;

		public static float ForceDropHoldDuration => forceDropHoldDuration.Value;

		public static float ReservedSlotsHoldDuration => reservedSlotsHoldDuration.Value;

		public static void Initialize(ConfigFile config)
		{
			doubleTapWindow = config.Bind<float>("Input", "DoubleTapWindow", 0.2f, "Time window in seconds to detect double-tap on drop key.");
			forceDropHoldDuration = config.Bind<float>("Input", "ForceDropHoldDuration", 0.5f, "Hold drop key for this many seconds to force drop all items, ignoring blacklisted items.");
			reservedSlotsHoldDuration = config.Bind<float>("Input", "ReservedSlotsHoldDuration", 0.5f, "Only applies with ReservedItemSlotCore installed. Once the force drop has started, keep holding the drop key this many extra seconds to also drop the items in reserved item slots.");
		}
	}
	internal static class GrabConfiguration
	{
		private static ConfigEntry<float> grabDelay;

		public static float GrabDelay => grabDelay.Value;

		public static void Initialize(ConfigFile config)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Expected O, but got Unknown
			grabDelay = config.Bind<float>("Grab", "GrabDelay", 0.01f, new ConfigDescription("Delay in seconds between grabbing items from the ground. Vanilla default is 0.2 seconds.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.01f, 0.2f), Array.Empty<object>()));
		}
	}
	internal static class ItemBlacklist
	{
		private static ItemNameList items;

		public static void Initialize(ConfigFile config)
		{
			items = new ItemNameList(config, "Items", "BlacklistedItems", "Comma-separated list of item names that should NOT be dropped (Walkie-talkie, Flashlight, Shovel, etc.)");
		}

		public static bool IsBlacklisted(string itemName)
		{
			return items.Contains(itemName);
		}
	}
	internal static class PlaceConfiguration
	{
		private static ItemNameList placeBlacklist;

		public static void Initialize(ConfigFile config)
		{
			placeBlacklist = new ItemNameList(config, "Place", "PlaceBlacklistedItems", "Comma-separated list of item names that should NOT be automatically placed on the counter (Walkie-talkie, Flashlight, Shovel, etc.)");
		}

		public static bool IsPlaceBlacklisted(string itemName)
		{
			return placeBlacklist.Contains(itemName);
		}
	}
}
namespace DropAndGrabOverhaul.Compatibility
{
	internal static class ReservedItemSlotCompat
	{
		private const string PluginGuid = "FlipMods.ReservedItemSlotCore";

		private const string PlayerDataTypeName = "ReservedItemSlotCore.Data.ReservedPlayerData";

		private const string HudPatcherTypeName = "HUDPatcher";

		private static bool resolved;

		private static bool disabled;

		private static FieldInfo? allPlayerDataField;

		private static MethodInfo? isReservedItemSlotMethod;

		private static MethodInfo? updateHudMethod;

		private static bool warnedHudUnavailable;

		private static bool? isLoaded;

		public static bool IsLoaded
		{
			get
			{
				bool valueOrDefault = isLoaded == true;
				if (!isLoaded.HasValue)
				{
					valueOrDefault = Chainloader.PluginInfos.ContainsKey("FlipMods.ReservedItemSlotCore");
					isLoaded = valueOrDefault;
					return valueOrDefault;
				}
				return valueOrDefault;
			}
		}

		public static bool IsReservedSlot(PlayerControllerB? player, int slot)
		{
			if ((Object)(object)player == (Object)null || disabled || !IsLoaded)
			{
				return false;
			}
			EnsureResolved();
			if (allPlayerDataField == null || isReservedItemSlotMethod == null)
			{
				return false;
			}
			try
			{
				if (!(allPlayerDataField.GetValue(null) is IDictionary dictionary) || !dictionary.Contains(player))
				{
					return false;
				}
				object obj = dictionary[player];
				if (obj == null)
				{
					return false;
				}
				return (bool)isReservedItemSlotMethod.Invoke(obj, new object[1] { slot });
			}
			catch (Exception ex)
			{
				disabled = true;
				ModLog.Warning("ReservedItemSlotCore compat failed (" + ex.GetType().Name + ": " + ex.Message + ") - treating every slot as a main hotbar slot from now on.");
				return false;
			}
		}

		public static void RefreshHudAfterReservedDrop()
		{
			if (disabled || !IsLoaded)
			{
				return;
			}
			EnsureResolved();
			if (updateHudMethod == null)
			{
				if (!warnedHudUnavailable)
				{
					warnedHudUnavailable = true;
					ModLog.Warning("ReservedItemSlotCore's HUD refresh method couldn't be resolved (version change?) - reserved slot frames may look stale after a force drop.");
				}
				return;
			}
			try
			{
				updateHudMethod.Invoke(null, null);
			}
			catch (Exception ex)
			{
				ModLog.Warning("ReservedItemSlotCore HUD refresh failed (" + ex.GetType().Name + ": " + ex.Message + ") - reserved slot frames may look stale after a force drop until something else refreshes them.");
			}
		}

		private static void EnsureResolved()
		{
			if (resolved)
			{
				return;
			}
			resolved = true;
			Assembly assembly;
			try
			{
				assembly = ((object)Chainloader.PluginInfos["FlipMods.ReservedItemSlotCore"].Instance).GetType().Assembly;
			}
			catch (Exception ex)
			{
				ModLog.Warning("Failed to inspect ReservedItemSlotCore: " + ex.Message);
				return;
			}
			try
			{
				Type type = assembly.GetType("ReservedItemSlotCore.Data.ReservedPlayerData");
				allPlayerDataField = type?.GetField("allPlayerData", BindingFlags.Static | BindingFlags.Public);
				isReservedItemSlotMethod = type?.GetMethod("IsReservedItemSlot", BindingFlags.Instance | BindingFlags.Public, null, new Type[1] { typeof(int) }, null);
			}
			catch (Exception ex2)
			{
				ModLog.Warning("Failed to inspect ReservedItemSlotCore's slot API: " + ex2.Message);
			}
			if (allPlayerDataField == null || isReservedItemSlotMethod == null)
			{
				ModLog.Warning("ReservedItemSlotCore is installed but its API couldn't be resolved (version change?) - treating every slot as a main hotbar slot.");
			}
			try
			{
				updateHudMethod = Array.Find(assembly.GetTypes(), (Type t) => t.Name == "HUDPatcher")?.GetMethod("UpdateUI", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null);
			}
			catch (Exception ex3)
			{
				ModLog.Warning("Failed to inspect ReservedItemSlotCore for its HUD refresh method: " + ex3.Message);
			}
		}
	}
}
namespace System.Diagnostics.CodeAnalysis
{
	[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class ConstantExpectedAttribute : Attribute
	{
		public object? Min { get; set; }

		public object? Max { get; set; }
	}
	[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Interface | AttributeTargets.Delegate, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class ExperimentalAttribute : Attribute
	{
		public string DiagnosticId { get; }

		public string? UrlFormat { get; set; }

		public ExperimentalAttribute(string diagnosticId)
		{
			DiagnosticId = diagnosticId;
		}
	}
	[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)]
	[ExcludeFromCodeCoverage]
	internal sealed class MemberNotNullAttribute : Attribute
	{
		public string[] Members { get; }

		public MemberNotNullAttribute(string member)
		{
			Members = new string[1] { member };
		}

		public MemberNotNullAttribute(params string[] members)
		{
			Members = members;
		}
	}
	[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)]
	[ExcludeFromCodeCoverage]
	internal sealed class MemberNotNullWhenAttribute : Attribute
	{
		public bool ReturnValue { get; }

		public string[] Members { get; }

		public MemberNotNullWhenAttribute(bool returnValue, string member)
		{
			ReturnValue = returnValue;
			Members = new string[1] { member };
		}

		public MemberNotNullWhenAttribute(bool returnValue, params string[] members)
		{
			ReturnValue = returnValue;
			Members = members;
		}
	}
	[AttributeUsage(AttributeTargets.Constructor, AllowMultiple = false, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class SetsRequiredMembersAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class StringSyntaxAttribute : Attribute
	{
		public const string CompositeFormat = "CompositeFormat";

		public const string DateOnlyFormat = "DateOnlyFormat";

		public const string DateTimeFormat = "DateTimeFormat";

		public const string EnumFormat = "EnumFormat";

		public const string GuidFormat = "GuidFormat";

		public const string Json = "Json";

		public const string NumericFormat = "NumericFormat";

		public const string Regex = "Regex";

		public const string TimeOnlyFormat = "TimeOnlyFormat";

		public const string TimeSpanFormat = "TimeSpanFormat";

		public const string Uri = "Uri";

		public const string Xml = "Xml";

		public string Syntax { get; }

		public object?[] Arguments { get; }

		public StringSyntaxAttribute(string syntax)
		{
			Syntax = syntax;
			Arguments = new object[0];
		}

		public StringSyntaxAttribute(string syntax, params object?[] arguments)
		{
			Syntax = syntax;
			Arguments = arguments;
		}
	}
	[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class UnscopedRefAttribute : Attribute
	{
	}
}
namespace System.Runtime.Versioning
{
	[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Interface | AttributeTargets.Delegate, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class RequiresPreviewFeaturesAttribute : Attribute
	{
		public string? Message { get; }

		public string? Url { get; set; }

		public RequiresPreviewFeaturesAttribute()
		{
		}

		public RequiresPreviewFeaturesAttribute(string? message)
		{
			Message = message;
		}
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		internal IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
	[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class CallerArgumentExpressionAttribute : Attribute
	{
		public string ParameterName { get; }

		public CallerArgumentExpressionAttribute(string parameterName)
		{
			ParameterName = parameterName;
		}
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class CollectionBuilderAttribute : Attribute
	{
		public Type BuilderType { get; }

		public string MethodName { get; }

		public CollectionBuilderAttribute(Type builderType, string methodName)
		{
			BuilderType = builderType;
			MethodName = methodName;
		}
	}
	[AttributeUsage(AttributeTargets.All, AllowMultiple = true, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class CompilerFeatureRequiredAttribute : Attribute
	{
		public const string RefStructs = "RefStructs";

		public const string RequiredMembers = "RequiredMembers";

		public string FeatureName { get; }

		public bool IsOptional { get; set; }

		public CompilerFeatureRequiredAttribute(string featureName)
		{
			FeatureName = featureName;
		}
	}
	[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class InterpolatedStringHandlerArgumentAttribute : Attribute
	{
		public string[] Arguments { get; }

		public InterpolatedStringHandlerArgumentAttribute(string argument)
		{
			Arguments = new string[1] { argument };
		}

		public InterpolatedStringHandlerArgumentAttribute(params string[] arguments)
		{
			Arguments = arguments;
		}
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class InterpolatedStringHandlerAttribute : Attribute
	{
	}
	[EditorBrowsable(EditorBrowsableState.Never)]
	[ExcludeFromCodeCoverage]
	internal static class IsExternalInit
	{
	}
	[AttributeUsage(AttributeTargets.Method, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class ModuleInitializerAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class OverloadResolutionPriorityAttribute : Attribute
	{
		public int Priority { get; }

		public OverloadResolutionPriorityAttribute(int priority)
		{
			Priority = priority;
		}
	}
	[AttributeUsage(AttributeTargets.Parameter, Inherited = true, AllowMultiple = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class ParamCollectionAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class RequiredMemberAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
	[EditorBrowsable(EditorBrowsableState.Never)]
	[ExcludeFromCodeCoverage]
	internal sealed class RequiresLocationAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Event | AttributeTargets.Interface, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class SkipLocalsInitAttribute : Attribute
	{
	}
}