using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; 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 HarmonyLib; using JetBrains.Annotations; using Microsoft.CodeAnalysis; using UnityEngine; using UnityEngine.UI; [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("LootLens")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("4.0.3.0")] [assembly: AssemblyInformationalVersion("4.0.3+5b855474c872e5e21e42242ff0a4237575a37199")] [assembly: AssemblyProduct("LootLens")] [assembly: AssemblyTitle("LootLens")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("4.0.3.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.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 LootLens { public static class ConfigManager { private const float MaxRadius = 100f; public static ConfigEntry scanValuables; public static ConfigEntry onlyDiscoveredValuables; public static ConfigEntry scanEnemies; public static ConfigEntry scanHeads; public static ConfigEntry scanItems; public static ConfigEntry scanCosmetics; public static ConfigEntry scanCartsVehicles; public static ConfigEntry scanCustom; public static ConfigEntry scanRadius; public static ConfigEntry multiplayerReveal; public static ConfigEntry radiusValuables; public static ConfigEntry radiusEnemies; public static ConfigEntry radiusHeads; public static ConfigEntry radiusItems; public static ConfigEntry radiusCosmetics; public static ConfigEntry radiusCartsVehicles; public static ConfigEntry radiusCustom; public static ConfigEntry boxFillOpacity; private static bool _initialized; public static float MaxScanRadius { get { float value = scanRadius.Value; float num = 0f; if (scanValuables.Value) { num = Mathf.Max(num, (radiusValuables.Value > 0f) ? radiusValuables.Value : value); } if (scanEnemies.Value) { num = Mathf.Max(num, (radiusEnemies.Value > 0f) ? radiusEnemies.Value : value); } if (scanHeads.Value) { num = Mathf.Max(num, (radiusHeads.Value > 0f) ? radiusHeads.Value : value); } if (scanItems.Value) { num = Mathf.Max(num, (radiusItems.Value > 0f) ? radiusItems.Value : value); } if (scanCosmetics.Value) { num = Mathf.Max(num, (radiusCosmetics.Value > 0f) ? radiusCosmetics.Value : value); } if (scanCartsVehicles.Value) { num = Mathf.Max(num, (radiusCartsVehicles.Value > 0f) ? radiusCartsVehicles.Value : value); } if (scanCustom.Value) { num = Mathf.Max(num, (radiusCustom.Value > 0f) ? radiusCustom.Value : value); } return Mathf.Min(num, 100f); } } internal static void Initialize(Plugin plugin) { //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Expected O, but got Unknown //IL_0224: Unknown result type (might be due to invalid IL or missing references) //IL_022e: Expected O, but got Unknown if (!_initialized) { _initialized = true; AcceptableValueRange range = new AcceptableValueRange(0f, 100f); AcceptableValueRange val = new AcceptableValueRange(2f, 100f); AcceptableValueRange val2 = new AcceptableValueRange(0f, 1f); scanRadius = ((BaseUnityPlugin)plugin).Config.Bind("General", "Scan Radius", 10f, new ConfigDescription("Detection radius around the player (metres)", (AcceptableValueBase)(object)val, Array.Empty())); multiplayerReveal = ((BaseUnityPlugin)plugin).Config.Bind("General", "Multiplayer Reveal", true, "Reveal scanned valuables on other players' minimaps via RPC"); scanValuables = ((BaseUnityPlugin)plugin).Config.Bind("Object Types", "Valuables", true, "Show boxes on valuable objects"); onlyDiscoveredValuables = ((BaseUnityPlugin)plugin).Config.Bind("Object Types", "Only Discovered Valuables", false, "Skip valuables that have not been discovered yet"); scanEnemies = ((BaseUnityPlugin)plugin).Config.Bind("Object Types", "Enemies", true, "Show boxes on enemies"); scanHeads = ((BaseUnityPlugin)plugin).Config.Bind("Object Types", "Player Heads", true, "Show boxes on dead player heads"); scanItems = ((BaseUnityPlugin)plugin).Config.Bind("Object Types", "Items", true, "Show boxes on equippable items"); scanCosmetics = ((BaseUnityPlugin)plugin).Config.Bind("Object Types", "Cosmetics", true, "Show boxes on cosmetic objects"); scanCartsVehicles = ((BaseUnityPlugin)plugin).Config.Bind("Object Types", "Carts and Vehicles", false, "Show boxes on carts and driveable vehicles (disabled by default to reduce clutter)"); scanCustom = ((BaseUnityPlugin)plugin).Config.Bind("Object Types", "Custom", true, "Show boxes on objects with a custom discover component"); scanRadiusDesc(plugin, "Valuables", out radiusValuables, range); scanRadiusDesc(plugin, "Enemies", out radiusEnemies, range); scanRadiusDesc(plugin, "Player Heads", out radiusHeads, range); scanRadiusDesc(plugin, "Items", out radiusItems, range); scanRadiusDesc(plugin, "Cosmetics", out radiusCosmetics, range); scanRadiusDesc(plugin, "Carts and Vehicles", out radiusCartsVehicles, range); scanRadiusDesc(plugin, "Custom", out radiusCustom, range); boxFillOpacity = ((BaseUnityPlugin)plugin).Config.Bind("Display", "Box Fill Opacity", 0.15f, new ConfigDescription("Alpha of the box fill colour — 0 = invisible, 1 = solid (corners are unaffected)", (AcceptableValueBase)(object)val2, Array.Empty())); } } private static void scanRadiusDesc(Plugin plugin, string key, out ConfigEntry entry, AcceptableValueRange range) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Expected O, but got Unknown entry = ((BaseUnityPlugin)plugin).Config.Bind("Radius Overrides", key, 0f, new ConfigDescription("Detection radius override for " + key + " (0 = use global Scan Radius)", (AcceptableValueBase)(object)range, Array.Empty())); } } [HarmonyPatch] public class Patches { private static FieldInfo _waitTimerField; private static FieldInfo _waitTimeField; private static FieldInfo _animLerpField; private static FieldInfo _middleField; private static readonly Dictionary _middleImageCache = new Dictionary(); [HarmonyPatch(typeof(PlayerController), "Update")] [HarmonyPostfix] private static void PlayerControllerUpdatePostfix() { Scanner.Update(); } [HarmonyPatch(typeof(ValuableDiscoverGraphic), "Update")] [HarmonyPostfix] private static void ValuableDiscoverGraphicUpdatePostfix(ValuableDiscoverGraphic __instance) { //IL_0173: Unknown result type (might be due to invalid IL or missing references) //IL_017a: Expected O, but got Unknown //IL_01b1: Unknown result type (might be due to invalid IL or missing references) //IL_01b6: Unknown result type (might be due to invalid IL or missing references) //IL_01b8: Unknown result type (might be due to invalid IL or missing references) //IL_01cb: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance.target == (Object)null) { return; } if ((object)_waitTimerField == null) { _waitTimerField = AccessTools.Field(typeof(ValuableDiscoverGraphic), "waitTimer"); } if ((object)_waitTimeField == null) { _waitTimeField = AccessTools.Field(typeof(ValuableDiscoverGraphic), "waitTime"); } if ((object)_animLerpField == null) { _animLerpField = AccessTools.Field(typeof(ValuableDiscoverGraphic), "animLerp"); } if ((object)_middleField == null) { _middleField = AccessTools.Field(typeof(ValuableDiscoverGraphic), "middle"); } if (_waitTimerField == null || _waitTimeField == null || _animLerpField == null) { return; } float num = (float)_waitTimerField.GetValue(__instance); if (Scanner.currentlyVisible.Contains(((Object)__instance.target).GetInstanceID())) { if (num <= 0f) { _waitTimerField.SetValue(__instance, (float)_waitTimeField.GetValue(__instance)); _animLerpField.SetValue(__instance, 1f); } } else if (num > 0f) { _waitTimerField.SetValue(__instance, 0f); } if (_middleField == null) { return; } int instanceID = ((Object)__instance).GetInstanceID(); if (!_middleImageCache.TryGetValue(instanceID, out var value) || (Object)(object)value == (Object)null) { RectTransform val = (RectTransform)_middleField.GetValue(__instance); value = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponent() : null); _middleImageCache[instanceID] = value; } if (!((Object)(object)value == (Object)null)) { float value2 = ConfigManager.boxFillOpacity.Value; Color color = ((Graphic)value).color; if (color.a != value2) { color.a = value2; ((Graphic)value).color = color; } } } } [BepInPlugin("LootLens", "LootLens", "4.0.3")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { internal static ManualLogSource Logger; private readonly Harmony harmony = new Harmony("LootLens"); internal static bool isCustomDiscoverStateLibLoaded; private void Awake() { Logger = ((BaseUnityPlugin)this).Logger; ConfigManager.Initialize(this); harmony.PatchAll(typeof(Patches)); Logger.LogInfo((object)$"Patched {harmony.GetPatchedMethods().Count()} methods!"); isCustomDiscoverStateLibLoaded = Chainloader.PluginInfos.ContainsKey("Kistras-CustomDiscoverStateLib"); if (!isCustomDiscoverStateLibLoaded) { Logger.LogInfo((object)"CustomDiscoverStateLib not loaded — falling back to Reminder graphic."); } Logger.LogInfo((object)"LootLens v4.0.3 loaded."); } } public class Scanner { private const State DiscoverValuableState = 0; private const State DiscoverEnemyState = 2; private static State discoverHeadState = NewCustomState(new Color(1f, 0f, 0.067f, 0.17f), new Color(1f, 0.1f, 0.067f, 0.75f)); private static State discoverItemState = NewCustomState(new Color(0f, 0.5f, 0.8f, 0.17f), new Color(0.1f, 0.6f, 0.9f, 0.75f)); private static State discoverCosmeticState = NewCustomState(new Color(0.1f, 0.8f, 0.5f, 0.17f), new Color(0.2f, 0.9f, 0.6f, 0.75f)); private static State discoverCartState = NewCustomState(new Color(0.8f, 0.6f, 0.1f, 0.17f), new Color(0.9f, 0.7f, 0.2f, 0.75f)); public static readonly HashSet currentlyVisible = new HashSet(); private static readonly HashSet seenThisSweep = new HashSet(); private const float SweepInterval = 0.25f; private static float lastSweepTime = 0f; private static bool isInitialized = false; private static State NewCustomState(Color middle, Color corner) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) if (Plugin.isCustomDiscoverStateLibLoaded) { try { Type type = AccessTools.TypeByName("CustomDiscoverStateLib.CustomDiscoverState"); if (type != null) { MethodInfo methodInfo = AccessTools.Method(type, "AddNewDiscoverGraphic", (Type[])null, (Type[])null); if (methodInfo != null) { return (State)methodInfo.Invoke(null, new object[2] { middle, corner }); } } } catch (Exception ex) { Plugin.Logger.LogError((object)("CustomDiscoverState error: " + ex.Message)); } } return (State)1; } private static void Initialize() { if (!isInitialized) { isInitialized = true; Plugin.Logger.LogInfo((object)"LootLens scanner initialized"); } } [CanBeNull] private static T GetComponentOfType(Collider col) where T : Component { return ((Component)col).GetComponentInParent() ?? ((Component)col).GetComponentInChildren(); } [CanBeNull] private static PhysGrabObject GetPhysGrab(TComponent component, Collider collider) where TComponent : MonoBehaviour { object obj = component; ValuableObject val = (ValuableObject)((obj is ValuableObject) ? obj : null); PhysGrabObject val5; if (val == null) { object obj2 = component; ItemAttributes val2 = (ItemAttributes)((obj2 is ItemAttributes) ? obj2 : null); if (val2 == null) { object obj3 = component; EnemyRigidbody val3 = (EnemyRigidbody)((obj3 is EnemyRigidbody) ? obj3 : null); if (val3 == null) { object obj4 = component; CosmeticWorldObject val4 = (CosmeticWorldObject)((obj4 is CosmeticWorldObject) ? obj4 : null); val5 = ((val4 != null) ? val4.physGrabObject : ((PhysGrabCart)(/*isinst with value type is only supported in some contexts*/?)).physGrabObject); } else { val5 = val3.physGrabObject; } } else { val5 = val2.physGrabObject; } } else { val5 = val.physGrabObject; } return val5 ?? ((Component)(object)component).GetComponentInParent() ?? ((Component)((Component)(object)component).transform.root).GetComponentInChildren(); } private static bool IsInFOV(Vector3 worldPos, Plane[] frustumPlanes) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) Bounds val = default(Bounds); ((Bounds)(ref val))..ctor(worldPos, Vector3.one * 0.5f); return GeometryUtility.TestPlanesAABB(frustumPlanes, val); } private static bool HasLineOfSight(Vector3 from, Vector3 to) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_001a: 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_001d: Unknown result type (might be due to invalid IL or missing references) Vector3 val = to - from; float magnitude = ((Vector3)(ref val)).magnitude; if (magnitude < 0.1f) { return true; } return !Physics.Raycast(from, val / magnitude, magnitude - 0.3f, -5, (QueryTriggerInteraction)1); } public static void Update() { //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_0187: Unknown result type (might be due to invalid IL or missing references) //IL_018d: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: Unknown result type (might be due to invalid IL or missing references) //IL_01a9: Unknown result type (might be due to invalid IL or missing references) //IL_01bf: Unknown result type (might be due to invalid IL or missing references) //IL_01c5: Unknown result type (might be due to invalid IL or missing references) //IL_01db: Unknown result type (might be due to invalid IL or missing references) //IL_01e1: Unknown result type (might be due to invalid IL or missing references) //IL_023b: Unknown result type (might be due to invalid IL or missing references) //IL_023d: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)LevelGenerator.Instance == (Object)null || !LevelGenerator.Instance.Generated || SemiFunc.MenuLevel()) { return; } if (!isInitialized) { Initialize(); } if (Time.time - lastSweepTime < 0.25f) { return; } lastSweepTime = Time.time; Camera main = Camera.main; if ((Object)(object)main == (Object)null || (Object)(object)PlayerController.instance == (Object)null) { return; } Vector3 position = ((Component)main).transform.position; Plane[] frustumPlanes = GeometryUtility.CalculateFrustumPlanes(main); Collider[] array = Physics.OverlapSphere(position, ConfigManager.MaxScanRadius); seenThisSweep.Clear(); Collider[] array2 = array; foreach (Collider val in array2) { if ((Object)(object)val == (Object)null || (Object)(object)((Component)val).transform == (Object)null) { continue; } Vector3 position2 = ((Component)val).transform.position; if (!IsInFOV(position2, frustumPlanes) || !HasLineOfSight(position, position2)) { continue; } PhysGrabObjectImpactDetector componentOfType = GetComponentOfType(val); if (((Object)(object)componentOfType != (Object)null && componentOfType.inCart) || (!ConfigManager.scanCartsVehicles.Value && ((Object)(object)GetComponentOfType(val) != (Object)null || (Object)(object)GetComponentOfType(val) != (Object)null)) || TryScanItem(val, ConfigManager.scanValuables, position, ConfigManager.radiusValuables, (State)0) || TryScanItem(val, ConfigManager.scanEnemies, position, ConfigManager.radiusEnemies, (State)2) || TryScanItem(val, ConfigManager.scanHeads, position, ConfigManager.radiusHeads, discoverHeadState) || TryScanItem(val, ConfigManager.scanItems, position, ConfigManager.radiusItems, discoverItemState) || TryScanItem(val, ConfigManager.scanCosmetics, position, ConfigManager.radiusCosmetics, discoverCosmeticState) || TryScanItem(val, ConfigManager.scanCartsVehicles, position, ConfigManager.radiusCartsVehicles, discoverCartState) || TryScanItem(val, ConfigManager.scanCartsVehicles, position, ConfigManager.radiusCartsVehicles, discoverCartState)) { continue; } ValuableDiscoverCustom componentOfType2 = GetComponentOfType(val); if (!((Object)(object)componentOfType2 != (Object)null) || !ConfigManager.scanCustom.Value) { continue; } float num = ((ConfigManager.radiusCustom.Value > 0f) ? ConfigManager.radiusCustom.Value : ConfigManager.scanRadius.Value); if (!(Vector3.Distance(position2, position) <= num)) { continue; } PhysGrabObject componentOfType3 = GetComponentOfType(val); if ((Object)(object)componentOfType3 != (Object)null) { int instanceID = ((Object)componentOfType3).GetInstanceID(); seenThisSweep.Add(instanceID); if (!currentlyVisible.Contains(instanceID)) { ValuableDiscover.instance.New(componentOfType3, (State)3, componentOfType2); } } } currentlyVisible.RemoveWhere((int id) => !seenThisSweep.Contains(id)); foreach (int item in seenThisSweep) { currentlyVisible.Add(item); } } private static bool TryScanItem(Collider collider, ConfigEntry shouldScan, Vector3 camPos, ConfigEntry radiusOverride, State state) where TComponent : MonoBehaviour { //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) if (!shouldScan.Value) { return false; } TComponent componentOfType = GetComponentOfType(collider); if ((Object)(object)componentOfType == (Object)null) { return false; } float num = ((radiusOverride.Value > 0f) ? radiusOverride.Value : ConfigManager.scanRadius.Value); if (Vector3.Distance(((Component)(object)componentOfType).transform.position, camPos) > num) { return false; } if (ConfigManager.onlyDiscoveredValuables.Value) { object obj = componentOfType; ValuableObject val = (ValuableObject)((obj is ValuableObject) ? obj : null); if (val != null && !val.discovered) { return false; } } PhysGrabObject physGrab = GetPhysGrab(componentOfType, collider); if ((Object)(object)physGrab == (Object)null) { return true; } int instanceID = ((Object)physGrab).GetInstanceID(); seenThisSweep.Add(instanceID); if (currentlyVisible.Contains(instanceID)) { return true; } if (ConfigManager.multiplayerReveal.Value) { object obj2 = componentOfType; ValuableObject val2 = (ValuableObject)((obj2 is ValuableObject) ? obj2 : null); if (val2 != null && !val2.discovered) { val2.Discover(state); goto IL_00fe; } } ValuableDiscover.instance.New(physGrab, state, GetComponentOfType(collider)); goto IL_00fe; IL_00fe: return true; } public static bool IsOnCooldown() { return false; } public static float GetRemainingCooldown() { return 0f; } } public static class MyPluginInfo { public const string PLUGIN_GUID = "LootLens"; public const string PLUGIN_NAME = "LootLens"; public const string PLUGIN_VERSION = "4.0.3"; } }