using System; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using BepInEx; using GameNetcodeStuff; using HarmonyLib; 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("FastSlots")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("FastSlots")] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("a72f02b8-2b77-417b-b41a-dc8936c5b39a")] [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")] namespace FastSlots; [BepInPlugin("FastSlots", "FastSlots", "1.0.2")] public class FastSlotsPlugin : BaseUnityPlugin { private void Awake() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) new Harmony("FastSlots").PatchAll(); } } [HarmonyPatch(typeof(PlayerControllerB), "Update")] public static class PlayerUpdatePatch { private static readonly MethodInfo SwitchToItemSlot = AccessTools.Method(typeof(PlayerControllerB), "SwitchToItemSlot", new Type[2] { typeof(int), typeof(GrabbableObject) }, (Type[])null); private static readonly Key[] SlotKeys; [HarmonyPostfix] private static void Postfix(PlayerControllerB __instance) { if (IsControllable(__instance)) { Keyboard current = Keyboard.current; if (current != null) { Traverse t = Traverse.Create((object)__instance); TryPlayEmote(__instance, current, t); TrySwitchSlot(__instance, current, t); } } } private static bool IsControllable(PlayerControllerB p) { return ((NetworkBehaviour)p).IsOwner && p.isPlayerControlled && !p.isTypingChat && !p.quickMenuManager.isMenuOpen; } private static void TryPlayEmote(PlayerControllerB p, Keyboard kb, Traverse t) { int num = (((ButtonControl)kb.downArrowKey).wasPressedThisFrame ? 1 : (((ButtonControl)kb.upArrowKey).wasPressedThisFrame ? 2 : (-1))); if (num != -1) { t.Method("StartPerformingEmoteServerRpc", Array.Empty()).GetValue(); p.playerBodyAnimator.SetInteger("emoteNumber", num); } } private static void TrySwitchSlot(PlayerControllerB p, Keyboard kb, Traverse t) { if (CanSwitchSlot(p, t)) { int pressedSlot = GetPressedSlot(kb); if (pressedSlot != -1 && pressedSlot < p.ItemSlots.Length && pressedSlot != p.currentItemSlot) { PerformSlotSwitch(p, t, pressedSlot); } } } private static bool CanSwitchSlot(PlayerControllerB p, Traverse t) { return t.Field("timeSinceSwitchingSlots").GetValue() >= 0.3f && !p.isGrabbingObjectAnimation && !p.inSpecialInteractAnimation && !p.twoHanded && !p.activatingItem && !t.Field("throwingObject").GetValue(); } private static int GetPressedSlot(Keyboard kb) { for (int i = 0; i < SlotKeys.Length; i++) { if (((ButtonControl)kb[SlotKeys[i]]).wasPressedThisFrame) { return i; } } return -1; } private static void PerformSlotSwitch(PlayerControllerB p, Traverse t, int slot) { ShipBuildModeManager instance = ShipBuildModeManager.Instance; if (instance != null) { instance.CancelBuildMode(true); } p.playerBodyAnimator.SetBool("GrabValidated", false); SwitchToItemSlot.Invoke(p, new object[2] { slot, null }); t.Method("SwitchToSlotServerRpc", new object[1] { slot }).GetValue(); GrabbableObject currentlyHeldObjectServer = p.currentlyHeldObjectServer; if (currentlyHeldObjectServer != null) { AudioSource component = ((Component)currentlyHeldObjectServer).gameObject.GetComponent(); if (component != null) { component.PlayOneShot(currentlyHeldObjectServer.itemProperties.grabSFX, 0.6f); } } t.Field("timeSinceSwitchingSlots").SetValue((object)0f); } static PlayerUpdatePatch() { Key[] array = new Key[7]; RuntimeHelpers.InitializeArray(array, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/); SlotKeys = (Key[])(object)array; } } [HarmonyPatch(typeof(PlayerControllerB), "PerformEmote")] public static class EmotePatch { private static readonly Key[] BlockedKeys = (Key[])(object)new Key[2] { (Key)41, (Key)42 }; [HarmonyPrefix] private static bool Prefix() { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) Keyboard current = Keyboard.current; if (current == null) { return true; } Key[] blockedKeys = BlockedKeys; foreach (Key val in blockedKeys) { if (((ButtonControl)current[val]).isPressed) { return false; } } return true; } }