Decompiled source of DoorLootFix v1.0.1

BepInEx/plugins/DoorLootFix.dll

Decompiled 20 hours ago
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<MonoBehaviour>(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<InteractTrigger>(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<GrabbableObject>(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<int, State> States = new Dictionary<int, State>(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.");
	}
}