Decompiled source of InstantItemSlots v1.0.2

BepInEx/plugins/InstantItemSlots/InstantItemSlots.dll

Decompiled a day ago
using System;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using GameNetcodeStuff;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("CustomKeybinds")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("CustomKeybinds")]
[assembly: AssemblyCopyright("Copyright ©  2025")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("32460eb4-e201-4ed4-9723-296aac0d0d64")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.0.0.0")]
[BepInPlugin("kviks.instantitemslots", "Instant Item Slots", "1.4.0")]
public class InstantItemSlots : BaseUnityPlugin
{
	private static readonly BindingFlags BF = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;

	private ConfigEntry<bool> EnableMod;

	private ConfigEntry<bool> DebugLogs;

	private ConfigEntry<bool> BlockEmoteOnDigit1And2;

	private ConfigEntry<Key> DanceKey;

	private ConfigEntry<Key> PointKey;

	private ConfigEntry<int> DanceEmoteId;

	private ConfigEntry<int> PointEmoteId;

	private ConfigEntry<bool> InstantSlotSwitch;

	private ConfigEntry<float> SlotSwitchCooldownSeconds;

	private ConfigEntry<bool> AllowNumpadForSlots;

	private ConfigEntry<Key> Slot1Key;

	private ConfigEntry<Key> Slot2Key;

	private ConfigEntry<Key> Slot3Key;

	private ConfigEntry<Key> Slot4Key;

	private ConfigEntry<Key> Slot1AltKey;

	private ConfigEntry<Key> Slot2AltKey;

	private ConfigEntry<Key> Slot3AltKey;

	private ConfigEntry<Key> Slot4AltKey;

	private static MethodInfo _miSwitchToItemSlot;

	private static MethodInfo _miSwitchToItemSlotServerRpcInt;

	private static MethodInfo _miSwitchItemSlotsServerRpcBool;

	private static MethodInfo _miNextItemSlotBool;

	private static MethodInfo _miCheckConditionsForEmote;

	private static FieldInfo _fiTimeSinceStartingEmote;

	private static FieldInfo _fiTimeSinceSwitchingSlots;

	private static FieldInfo _fiInTerminalMenu;

	private static FieldInfo _fiIsGrabbingObjectAnimation;

	private static FieldInfo _fiInSpecialInteractAnimation;

	private static FieldInfo _fiThrowingObject;

	private static FieldInfo _fiActivatingItem;

	private static FieldInfo _fiJetpackControls;

	private static FieldInfo _fiDisablingJetpackControls;

	private static FieldInfo _fiIsTestingPlayer;

	private bool _emoteBindingsPatchedOnce;

	private float _lastPatchTryTime;

	private void Awake()
	{
		EnableMod = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnableMod", true, (ConfigDescription)null);
		DebugLogs = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "DebugLogs", false, (ConfigDescription)null);
		BlockEmoteOnDigit1And2 = ((BaseUnityPlugin)this).Config.Bind<bool>("Emotes", "BlockEmoteOnDigit1And2", true, (ConfigDescription)null);
		DanceKey = ((BaseUnityPlugin)this).Config.Bind<Key>("Emotes", "DanceKey", (Key)63, (ConfigDescription)null);
		PointKey = ((BaseUnityPlugin)this).Config.Bind<Key>("Emotes", "PointKey", (Key)64, (ConfigDescription)null);
		DanceEmoteId = ((BaseUnityPlugin)this).Config.Bind<int>("Emotes", "DanceEmoteId", 1, (ConfigDescription)null);
		PointEmoteId = ((BaseUnityPlugin)this).Config.Bind<int>("Emotes", "PointEmoteId", 2, (ConfigDescription)null);
		InstantSlotSwitch = ((BaseUnityPlugin)this).Config.Bind<bool>("Slots", "InstantSlotSwitch", true, (ConfigDescription)null);
		SlotSwitchCooldownSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Slots", "SlotSwitchCooldownSeconds", 0f, (ConfigDescription)null);
		AllowNumpadForSlots = ((BaseUnityPlugin)this).Config.Bind<bool>("Slots", "AllowNumpadForSlots", true, (ConfigDescription)null);
		Slot1Key = ((BaseUnityPlugin)this).Config.Bind<Key>("Slots", "Slot1Key", (Key)41, (ConfigDescription)null);
		Slot2Key = ((BaseUnityPlugin)this).Config.Bind<Key>("Slots", "Slot2Key", (Key)42, (ConfigDescription)null);
		Slot3Key = ((BaseUnityPlugin)this).Config.Bind<Key>("Slots", "Slot3Key", (Key)43, (ConfigDescription)null);
		Slot4Key = ((BaseUnityPlugin)this).Config.Bind<Key>("Slots", "Slot4Key", (Key)44, (ConfigDescription)null);
		Slot1AltKey = ((BaseUnityPlugin)this).Config.Bind<Key>("Slots", "Slot1AltKey", (Key)85, (ConfigDescription)null);
		Slot2AltKey = ((BaseUnityPlugin)this).Config.Bind<Key>("Slots", "Slot2AltKey", (Key)86, (ConfigDescription)null);
		Slot3AltKey = ((BaseUnityPlugin)this).Config.Bind<Key>("Slots", "Slot3AltKey", (Key)87, (ConfigDescription)null);
		Slot4AltKey = ((BaseUnityPlugin)this).Config.Bind<Key>("Slots", "Slot4AltKey", (Key)88, (ConfigDescription)null);
		CacheReflection();
	}

	private void Update()
	{
		//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
		//IL_012c: Unknown result type (might be due to invalid IL or missing references)
		//IL_014b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0170: Unknown result type (might be due to invalid IL or missing references)
		//IL_018f: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b4: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d3: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f8: Unknown result type (might be due to invalid IL or missing references)
		//IL_0217: Unknown result type (might be due to invalid IL or missing references)
		if (!EnableMod.Value)
		{
			return;
		}
		Keyboard current = Keyboard.current;
		if (current == null)
		{
			return;
		}
		PlayerControllerB localPlayer = GetLocalPlayer();
		if ((Object)(object)localPlayer == (Object)null)
		{
			return;
		}
		if (Time.unscaledTime - _lastPatchTryTime > 1f)
		{
			_lastPatchTryTime = Time.unscaledTime;
			if (BlockEmoteOnDigit1And2.Value && !_emoteBindingsPatchedOnce)
			{
				_emoteBindingsPatchedOnce = TryPatchEmoteDigitBindings();
			}
		}
		if (InstantSlotSwitch.Value)
		{
			ForceSlotCooldown(localPlayer, SlotSwitchCooldownSeconds.Value);
		}
		if (!IsInputBlocked(localPlayer))
		{
			if (Pressed(DanceKey.Value))
			{
				TryEmote(localPlayer, ClampEmoteId(DanceEmoteId.Value));
			}
			if (Pressed(PointKey.Value))
			{
				TryEmote(localPlayer, ClampEmoteId(PointEmoteId.Value));
			}
			if (Pressed(Slot1Key.Value) || (AllowNumpadForSlots.Value && Pressed(Slot1AltKey.Value)))
			{
				SwitchSlotExact(localPlayer, 0);
			}
			if (Pressed(Slot2Key.Value) || (AllowNumpadForSlots.Value && Pressed(Slot2AltKey.Value)))
			{
				SwitchSlotExact(localPlayer, 1);
			}
			if (Pressed(Slot3Key.Value) || (AllowNumpadForSlots.Value && Pressed(Slot3AltKey.Value)))
			{
				SwitchSlotExact(localPlayer, 2);
			}
			if (Pressed(Slot4Key.Value) || (AllowNumpadForSlots.Value && Pressed(Slot4AltKey.Value)))
			{
				SwitchSlotExact(localPlayer, 3);
			}
		}
	}

	private static int ClampEmoteId(int id)
	{
		if (id < 1)
		{
			return 1;
		}
		if (id > 99)
		{
			return 99;
		}
		return id;
	}

	private static bool Pressed(Key key)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0003: Invalid comparison between Unknown and I4
		//IL_0024: Unknown result type (might be due to invalid IL or missing references)
		if ((int)key == 0)
		{
			return false;
		}
		Keyboard current = Keyboard.current;
		if (current == null)
		{
			return false;
		}
		KeyControl val;
		try
		{
			val = current[key];
		}
		catch
		{
			return false;
		}
		return val != null && ((ButtonControl)val).wasPressedThisFrame;
	}

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

	private bool IsInputBlocked(PlayerControllerB p)
	{
		if ((Object)(object)p == (Object)null)
		{
			return true;
		}
		if (p.isTypingChat)
		{
			return true;
		}
		if (ReadBool(p, _fiInTerminalMenu))
		{
			return true;
		}
		if (ReadBool(p, _fiIsGrabbingObjectAnimation))
		{
			return true;
		}
		if (ReadBool(p, _fiInSpecialInteractAnimation))
		{
			return true;
		}
		if (ReadBool(p, _fiThrowingObject))
		{
			return true;
		}
		if (ReadBool(p, _fiActivatingItem))
		{
			return true;
		}
		if ((Object)(object)p.quickMenuManager != (Object)null && p.quickMenuManager.isMenuOpen)
		{
			return true;
		}
		if (ReadBool(p, _fiJetpackControls))
		{
			return true;
		}
		if (ReadBool(p, _fiDisablingJetpackControls))
		{
			return true;
		}
		return false;
	}

	private static bool ReadBool(PlayerControllerB p, FieldInfo fi)
	{
		if ((Object)(object)p == (Object)null || fi == null)
		{
			return false;
		}
		if (fi.FieldType != typeof(bool))
		{
			return false;
		}
		return (bool)fi.GetValue(p);
	}

	private static float ReadFloat(PlayerControllerB p, FieldInfo fi, float fallback)
	{
		if ((Object)(object)p == (Object)null || fi == null)
		{
			return fallback;
		}
		if (fi.FieldType != typeof(float))
		{
			return fallback;
		}
		return (float)fi.GetValue(p);
	}

	private static void WriteFloat(PlayerControllerB p, FieldInfo fi, float value)
	{
		if (!((Object)(object)p == (Object)null) && !(fi == null) && !(fi.FieldType != typeof(float)))
		{
			fi.SetValue(p, value);
		}
	}

	private void CacheReflection()
	{
		Type typeFromHandle = typeof(PlayerControllerB);
		_miSwitchToItemSlot = (from m in typeFromHandle.GetMethods(BF)
			where m.Name == "SwitchToItemSlot"
			orderby m.GetParameters().Length descending
			select m).FirstOrDefault(delegate(MethodInfo m)
		{
			ParameterInfo[] parameters2 = m.GetParameters();
			return parameters2.Length >= 1 && parameters2[0].ParameterType == typeof(int);
		});
		_miSwitchToItemSlotServerRpcInt = typeFromHandle.GetMethods(BF).FirstOrDefault(delegate(MethodInfo m)
		{
			if (!m.Name.Contains("ServerRpc"))
			{
				return false;
			}
			if (!m.Name.Contains("Switch") && !m.Name.Contains("ItemSlot"))
			{
				return false;
			}
			ParameterInfo[] parameters = m.GetParameters();
			return parameters.Length == 1 && parameters[0].ParameterType == typeof(int);
		});
		_miSwitchItemSlotsServerRpcBool = typeFromHandle.GetMethods(BF).FirstOrDefault((MethodInfo m) => m.Name == "SwitchItemSlotsServerRpc" && m.GetParameters().Length == 1 && m.GetParameters()[0].ParameterType == typeof(bool));
		_miNextItemSlotBool = typeFromHandle.GetMethods(BF).FirstOrDefault((MethodInfo m) => m.Name == "NextItemSlot" && m.GetParameters().Length == 1 && m.GetParameters()[0].ParameterType == typeof(bool) && m.ReturnType == typeof(int));
		_miCheckConditionsForEmote = typeFromHandle.GetMethod("CheckConditionsForEmote", BF);
		_fiTimeSinceStartingEmote = typeFromHandle.GetField("timeSinceStartingEmote", BF);
		_fiTimeSinceSwitchingSlots = typeFromHandle.GetField("timeSinceSwitchingSlots", BF);
		_fiInTerminalMenu = typeFromHandle.GetField("inTerminalMenu", BF);
		_fiIsGrabbingObjectAnimation = typeFromHandle.GetField("isGrabbingObjectAnimation", BF);
		_fiInSpecialInteractAnimation = typeFromHandle.GetField("inSpecialInteractAnimation", BF);
		_fiThrowingObject = typeFromHandle.GetField("throwingObject", BF);
		_fiActivatingItem = typeFromHandle.GetField("activatingItem", BF);
		_fiJetpackControls = typeFromHandle.GetField("jetpackControls", BF);
		_fiDisablingJetpackControls = typeFromHandle.GetField("disablingJetpackControls", BF);
		_fiIsTestingPlayer = typeFromHandle.GetField("isTestingPlayer", BF);
	}

	private void ForceSlotCooldown(PlayerControllerB p, float seconds)
	{
		if (!(_fiTimeSinceSwitchingSlots == null))
		{
			float num = Mathf.Max(0f, seconds);
			float num2 = ReadFloat(p, _fiTimeSinceSwitchingSlots, 999f);
			if (num2 < num)
			{
				WriteFloat(p, _fiTimeSinceSwitchingSlots, num);
			}
			else if (num == 0f)
			{
				WriteFloat(p, _fiTimeSinceSwitchingSlots, 999f);
			}
		}
	}

	private bool TryPatchEmoteDigitBindings()
	{
		try
		{
			if ((Object)(object)IngamePlayerSettings.Instance == (Object)null)
			{
				return false;
			}
			if ((Object)(object)IngamePlayerSettings.Instance.playerInput == (Object)null)
			{
				return false;
			}
			InputActionAsset actions = IngamePlayerSettings.Instance.playerInput.actions;
			if ((Object)(object)actions == (Object)null)
			{
				return false;
			}
			InputAction action = actions.FindAction("Emote1", false);
			InputAction action2 = actions.FindAction("Emote2", false);
			bool flag = PatchDigitBindings(action, 1);
			bool flag2 = PatchDigitBindings(action2, 2);
			if (DebugLogs.Value)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)$"Patched emote digit bindings: Emote1={flag}, Emote2={flag2}");
			}
			return flag || flag2;
		}
		catch (Exception ex)
		{
			if (DebugLogs.Value)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)ex);
			}
			return false;
		}
	}

	private static bool PatchDigitBindings(InputAction action, int digit)
	{
		//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0020: Unknown result type (might be due to invalid IL or missing references)
		//IL_0025: Unknown result type (might be due to invalid IL or missing references)
		//IL_002a: Unknown result type (might be due to invalid IL or missing references)
		if (action == null)
		{
			return false;
		}
		bool result = false;
		for (int i = 0; i < action.bindings.Count; i++)
		{
			InputBinding val = action.bindings[i];
			if (!((InputBinding)(ref val)).isComposite && !((InputBinding)(ref val)).isPartOfComposite)
			{
				string text = ((InputBinding)(ref val)).effectivePath ?? ((InputBinding)(ref val)).path ?? "";
				string text2 = ((InputBinding)(ref val)).groups ?? "";
				if ((text2.Contains("Keyboard") || text.Contains("<Keyboard>")) && (IsDigitBinding(text, digit) || IsNumpadDigitBinding(text, digit)))
				{
					InputActionRebindingExtensions.ApplyBindingOverride(action, i, "<Keyboard>/f24");
					result = true;
				}
			}
		}
		if (!action.enabled)
		{
			action.Enable();
		}
		return result;
	}

	private static bool IsDigitBinding(string path, int digit)
	{
		if (string.IsNullOrEmpty(path))
		{
			return false;
		}
		if (!path.Contains("<Keyboard>"))
		{
			return false;
		}
		return path.EndsWith("/" + digit, StringComparison.OrdinalIgnoreCase) || path.IndexOf("digit" + digit, StringComparison.OrdinalIgnoreCase) >= 0;
	}

	private static bool IsNumpadDigitBinding(string path, int digit)
	{
		if (string.IsNullOrEmpty(path))
		{
			return false;
		}
		if (!path.Contains("<Keyboard>"))
		{
			return false;
		}
		return path.IndexOf("numpad" + digit, StringComparison.OrdinalIgnoreCase) >= 0 || path.IndexOf("keypad" + digit, StringComparison.OrdinalIgnoreCase) >= 0;
	}

	private void TryEmote(PlayerControllerB p, int emoteId)
	{
		if ((Object)(object)p == (Object)null)
		{
			return;
		}
		bool flag = ReadBool(p, _fiIsTestingPlayer);
		if ((!((NetworkBehaviour)p).IsOwner || !p.isPlayerControlled || (((NetworkBehaviour)p).IsServer && !p.isHostPlayerObject)) && !flag)
		{
			return;
		}
		if (_miCheckConditionsForEmote != null)
		{
			bool flag2 = false;
			try
			{
				flag2 = (bool)_miCheckConditionsForEmote.Invoke(p, null);
			}
			catch
			{
				flag2 = true;
			}
			if (!flag2)
			{
				return;
			}
		}
		if (_fiTimeSinceStartingEmote != null)
		{
			float num = ReadFloat(p, _fiTimeSinceStartingEmote, 999f);
			if (num < 0.5f)
			{
				return;
			}
			WriteFloat(p, _fiTimeSinceStartingEmote, 0f);
		}
		p.performingEmote = true;
		if ((Object)(object)p.playerBodyAnimator != (Object)null)
		{
			p.playerBodyAnimator.SetInteger("emoteNumber", emoteId);
		}
		p.StartPerformingEmoteServerRpc();
	}

	private void SwitchSlotExact(PlayerControllerB p, int targetSlot)
	{
		if ((Object)(object)p == (Object)null || p.ItemSlots == null || p.ItemSlots.Length == 0)
		{
			return;
		}
		int num = p.ItemSlots.Length;
		if (targetSlot < 0 || targetSlot >= num)
		{
			return;
		}
		bool flag = ReadBool(p, _fiIsTestingPlayer);
		if ((!((NetworkBehaviour)p).IsOwner || !p.isPlayerControlled || (((NetworkBehaviour)p).IsServer && !p.isHostPlayerObject)) && !flag)
		{
			return;
		}
		ShipBuildModeManager.Instance.CancelBuildMode(true);
		if ((Object)(object)p.playerBodyAnimator != (Object)null)
		{
			p.playerBodyAnimator.SetBool("GrabValidated", false);
		}
		int currentItemSlot = p.currentItemSlot;
		if (currentItemSlot == targetSlot)
		{
			return;
		}
		if (_miSwitchToItemSlot != null)
		{
			ParameterInfo[] parameters = _miSwitchToItemSlot.GetParameters();
			try
			{
				if (parameters.Length == 2)
				{
					_miSwitchToItemSlot.Invoke(p, new object[2] { targetSlot, null });
				}
				else
				{
					_miSwitchToItemSlot.Invoke(p, new object[1] { targetSlot });
				}
			}
			catch (Exception ex)
			{
				if (DebugLogs.Value)
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)ex);
				}
			}
		}
		if (_miSwitchToItemSlotServerRpcInt != null)
		{
			try
			{
				_miSwitchToItemSlotServerRpcInt.Invoke(p, new object[1] { targetSlot });
				return;
			}
			catch (Exception ex2)
			{
				if (DebugLogs.Value)
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)ex2);
				}
			}
		}
		if (_miSwitchItemSlotsServerRpcBool != null && _miNextItemSlotBool != null)
		{
			int num2 = (targetSlot - currentItemSlot + num) % num;
			int num3 = (currentItemSlot - targetSlot + num) % num;
			bool flag2 = num2 <= num3;
			int num4 = Math.Min(num2, num3);
			try
			{
				for (int i = 0; i < num4; i++)
				{
					_miSwitchItemSlotsServerRpcBool.Invoke(p, new object[1] { flag2 });
				}
			}
			catch (Exception ex3)
			{
				if (DebugLogs.Value)
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)ex3);
				}
			}
		}
		if (InstantSlotSwitch.Value)
		{
			ForceSlotCooldown(p, SlotSwitchCooldownSeconds.Value);
		}
	}
}