using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Logging; using GameNetcodeStuff; using HarmonyLib; using TMPro; using UnityEngine; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("DoorLootFix")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("DoorLootFix")] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("18ba3e78-ed87-48b3-9e3b-3e9246e42e4a")] [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 DoorLootFixMod; [HarmonyPatch(typeof(PlayerControllerB), "BeginGrabObject")] internal static class DoorLootFixBeginGrabPatch { private static readonly FieldInfo InteractableMask = AccessTools.Field(typeof(PlayerControllerB), "interactableObjectsMask"); private static readonly FieldInfo HoverTrig = AccessTools.Field(typeof(PlayerControllerB), "hoveringOverTrigger"); [HarmonyPrefix] private static void Prefix(PlayerControllerB __instance) { if (!IsLocal(__instance) || !DoorLootFixRuntime.TryGet(__instance, out var state) || (Object)(object)state?.Blocker == (Object)null) { return; } if (InteractableMask != null && !state.MaskSaved) { state.OriginalMask = (int)InteractableMask.GetValue(__instance); int layer = ((Component)state.Blocker).gameObject.layer; if (layer >= 0 && layer < 32) { int num = state.OriginalMask & ~(1 << layer); InteractableMask.SetValue(__instance, num); } state.MaskSaved = true; } HoverTrig?.SetValue(__instance, null); } [HarmonyPostfix] private static void Postfix(PlayerControllerB __instance) { Restore(__instance); } private static void Restore(PlayerControllerB p) { if (!((Object)(object)p == (Object)null) && !(InteractableMask == null) && DoorLootFixRuntime.TryGet(p, out var state) && state.MaskSaved) { InteractableMask.SetValue(p, state.OriginalMask); state.MaskSaved = false; } } private static bool IsLocal(PlayerControllerB p) { return (Object)(object)p != (Object)null && (Object)(object)GameNetworkManager.Instance != (Object)null && (Object)(object)GameNetworkManager.Instance.localPlayerController == (Object)(object)p; } } [HarmonyPatch(typeof(PlayerControllerB), "SetHoverTipAndCurrentInteractTrigger")] internal static class DoorLootFixHoverPatch { private static readonly FieldInfo CursorTipField = AccessTools.Field(typeof(PlayerControllerB), "cursorTip"); private static readonly FieldInfo IsGrabbableField = AccessTools.Field(typeof(GrabbableObject), "isGrabbable"); private static readonly RaycastHit[] RaycastBuffer = (RaycastHit[])(object)new RaycastHit[20]; [HarmonyPostfix] private static void Postfix(PlayerControllerB __instance) { if (!IsLocal(__instance)) { return; } InteractTrigger hoveringOverTrigger = __instance.hoveringOverTrigger; DoorLootFixRuntime.State state = DoorLootFixRuntime.Get(__instance); if (!IsBlocking(hoveringOverTrigger)) { ResetState(state); return; } GrabbableObject val = FindLootBehindBlocker(__instance, hoveringOverTrigger); if ((Object)(object)val == (Object)null) { ResetState(state); return; } state.Loot = val; state.Blocker = hoveringOverTrigger; int instanceID = ((Object)val).GetInstanceID(); if (state.LastAnnouncedLootId != instanceID) { state.LastAnnouncedLootId = instanceID; SetTip(__instance, "Grab : [E]"); } } private static void ResetState(DoorLootFixRuntime.State state) { if (state != null) { state.Loot = null; state.Blocker = null; state.LastAnnouncedLootId = -1; } } private static bool IsLocal(PlayerControllerB p) { return (Object)(object)p != (Object)null && (Object)(object)GameNetworkManager.Instance != (Object)null && (Object)(object)GameNetworkManager.Instance.localPlayerController == (Object)(object)p; } private static bool IsBlocking(InteractTrigger t) { if ((Object)(object)t == (Object)null) { return false; } if (HasParentComponentByName(((Component)t).transform, "EntranceTeleport")) { return true; } string text = ((Object)t).name.ToLowerInvariant(); return text.Contains("door") || text.Contains("entrance") || text.Contains("exit") || text.Contains("gate") || text.Contains("hatch") || text.Contains("lever") || text.Contains("button") || text.Contains("switch") || text.Contains("terminal") || text.Contains("panel") || text.Contains("teleport"); } private static bool HasParentComponentByName(Transform tr, string typeName) { if ((Object)(object)tr == (Object)null || string.IsNullOrEmpty(typeName)) { return false; } MonoBehaviour[] componentsInParent = ((Component)tr).GetComponentsInParent(true); for (int i = 0; i < componentsInParent.Length; i++) { if ((Object)(object)componentsInParent[i] != (Object)null && ((object)componentsInParent[i]).GetType().Name == typeName) { return true; } } return false; } private static GrabbableObject FindLootBehindBlocker(PlayerControllerB p, InteractTrigger blocker) { //IL_003d: 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) //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)p == (Object)null || (Object)(object)blocker == (Object)null || (Object)(object)p.gameplayCamera == (Object)null) { return null; } Transform transform = ((Component)p.gameplayCamera).transform; int num = Physics.RaycastNonAlloc(transform.position, transform.forward, RaycastBuffer, p.grabDistance, -1, (QueryTriggerInteraction)2); if (num == 0) { return null; } for (int i = 0; i < num - 1; i++) { for (int j = 0; j < num - i - 1; j++) { if (((RaycastHit)(ref RaycastBuffer[j])).distance > ((RaycastHit)(ref RaycastBuffer[j + 1])).distance) { RaycastHit val = RaycastBuffer[j]; RaycastBuffer[j] = RaycastBuffer[j + 1]; RaycastBuffer[j + 1] = val; } } } float num2 = float.MaxValue; float num3 = float.MaxValue; GrabbableObject val2 = null; for (int k = 0; k < num; k++) { RaycastHit val3 = RaycastBuffer[k]; Collider collider = ((RaycastHit)(ref val3)).collider; if ((Object)(object)collider == (Object)null) { continue; } InteractTrigger componentInParent = ((Component)collider).GetComponentInParent(true); if ((Object)(object)componentInParent != (Object)null && IsBlocking(componentInParent)) { if (((RaycastHit)(ref val3)).distance < num2) { num2 = ((RaycastHit)(ref val3)).distance; } continue; } GrabbableObject componentInParent2 = ((Component)collider).GetComponentInParent(true); if ((Object)(object)componentInParent2 != (Object)null && (Object)(object)componentInParent2.itemProperties != (Object)null && !componentInParent2.isHeld && !componentInParent2.isPocketed && (IsGrabbableField == null || (bool)IsGrabbableField.GetValue(componentInParent2)) && ((RaycastHit)(ref val3)).distance < num3) { num3 = ((RaycastHit)(ref val3)).distance; val2 = componentInParent2; } } if ((Object)(object)val2 == (Object)null || num3 > num2 + 0.18f) { return null; } return val2; } private static void SetTip(PlayerControllerB p, string text) { if (CursorTipField == null || (Object)(object)p == (Object)null) { return; } object value = CursorTipField.GetValue(p); if (value == null) { return; } TextMeshProUGUI val = (TextMeshProUGUI)((value is TextMeshProUGUI) ? value : null); if (val != null) { ((TMP_Text)val).text = text; return; } Text val2 = (Text)((value is Text) ? value : null); if (val2 != null) { val2.text = text; } else { value.GetType().GetProperty("text")?.SetValue(value, text, null); } } } [HarmonyPatch(typeof(PlayerControllerB), "LateUpdate")] internal static class DoorLootFixLateUpdatePatch { private static readonly FieldInfo CursorTipField = AccessTools.Field(typeof(PlayerControllerB), "cursorTip"); [HarmonyPostfix] private static void Postfix(PlayerControllerB __instance) { if (!((Object)(object)__instance == (Object)null) && !((Object)(object)GameNetworkManager.Instance == (Object)null) && !((Object)(object)GameNetworkManager.Instance.localPlayerController != (Object)(object)__instance) && DoorLootFixRuntime.TryGet(__instance, out var state) && (Object)(object)state?.Loot != (Object)null && (Object)(object)state?.Blocker != (Object)null) { SetTip(__instance, "Grab : [E]"); } } private static void SetTip(PlayerControllerB p, string text) { if (CursorTipField == null || (Object)(object)p == (Object)null) { return; } object value = CursorTipField.GetValue(p); if (value == null) { return; } TextMeshProUGUI val = (TextMeshProUGUI)((value is TextMeshProUGUI) ? value : null); if (val != null) { ((TMP_Text)val).text = text; return; } Text val2 = (Text)((value is Text) ? value : null); if (val2 != null) { val2.text = text; } else { value.GetType().GetProperty("text")?.SetValue(value, text, null); } } } internal static class DoorLootFixRuntime { internal sealed class State { public GrabbableObject Loot; public InteractTrigger Blocker; public int OriginalMask; public bool MaskSaved; public int LastAnnouncedLootId = -1; } private static readonly Dictionary States = new Dictionary(8); internal static State Get(PlayerControllerB p) { if ((Object)(object)p == (Object)null) { return null; } int instanceID = ((Object)p).GetInstanceID(); if (!States.TryGetValue(instanceID, out var value) || value == null) { value = new State(); States[instanceID] = value; } return value; } internal static bool TryGet(PlayerControllerB p, out State state) { state = null; if ((Object)(object)p == (Object)null) { return false; } return States.TryGetValue(((Object)p).GetInstanceID(), out state) && state != null; } internal static void Clear(PlayerControllerB p) { if ((Object)(object)p != (Object)null) { States.Remove(((Object)p).GetInstanceID()); } } } [BepInPlugin("maxteam.doorlootfix", "DoorLootFix", "1.0.1")] public sealed class Plugin : BaseUnityPlugin { public const string Guid = "maxteam.doorlootfix"; public const string Name = "DoorLootFix"; public const string Version = "1.0.1"; internal static ManualLogSource Log; private Harmony _harmony; private void Awake() { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; _harmony = new Harmony("maxteam.doorlootfix"); _harmony.PatchAll(); Log.LogInfo((object)"DoorLootFix v1.0.1 successfully loaded."); } }