Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of GoodItemScan v2.2.0
GoodItemScan.dll
Decompiled 3 weeks agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; 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.Configuration; using BepInEx.Logging; using GameNetcodeStuff; using GoodItemScan.Patches; using HarmonyLib; using Microsoft.CodeAnalysis; using MonoMod.RuntimeDetour; using TMPro; using TestAccountCore.KotlinSharp.Extensions; using UnityEngine; using UnityEngine.InputSystem; 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: IgnoresAccessChecksTo("AmazingAssets.TerrainToMesh")] [assembly: IgnoresAccessChecksTo("Assembly-CSharp-firstpass")] [assembly: IgnoresAccessChecksTo("Assembly-CSharp")] [assembly: IgnoresAccessChecksTo("ClientNetworkTransform")] [assembly: IgnoresAccessChecksTo("com.olegknyazev.softmask")] [assembly: IgnoresAccessChecksTo("DissonanceVoip")] [assembly: IgnoresAccessChecksTo("EasyTextEffects")] [assembly: IgnoresAccessChecksTo("Facepunch Transport for Netcode for GameObjects")] [assembly: IgnoresAccessChecksTo("Facepunch.Steamworks.Win64")] [assembly: IgnoresAccessChecksTo("Unity.AI.Navigation")] [assembly: IgnoresAccessChecksTo("Unity.Animation.Rigging")] [assembly: IgnoresAccessChecksTo("Unity.Animation.Rigging.DocCodeExamples")] [assembly: IgnoresAccessChecksTo("Unity.Burst")] [assembly: IgnoresAccessChecksTo("Unity.Burst.Unsafe")] [assembly: IgnoresAccessChecksTo("Unity.Collections")] [assembly: IgnoresAccessChecksTo("Unity.Collections.LowLevel.ILSupport")] [assembly: IgnoresAccessChecksTo("Unity.InputSystem")] [assembly: IgnoresAccessChecksTo("Unity.InputSystem.ForUI")] [assembly: IgnoresAccessChecksTo("Unity.Jobs")] [assembly: IgnoresAccessChecksTo("Unity.Mathematics")] [assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.Common")] [assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.MetricTypes")] [assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStats")] [assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStatsMonitor.Component")] [assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStatsMonitor.Configuration")] [assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStatsMonitor.Implementation")] [assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStatsReporting")] [assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetworkProfiler.Runtime")] [assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetworkSolutionInterface")] [assembly: IgnoresAccessChecksTo("Unity.Netcode.Components")] [assembly: IgnoresAccessChecksTo("Unity.Netcode.Runtime")] [assembly: IgnoresAccessChecksTo("Unity.Networking.Transport")] [assembly: IgnoresAccessChecksTo("Unity.ProBuilder.Csg")] [assembly: IgnoresAccessChecksTo("Unity.ProBuilder")] [assembly: IgnoresAccessChecksTo("Unity.ProBuilder.KdTree")] [assembly: IgnoresAccessChecksTo("Unity.ProBuilder.Poly2Tri")] [assembly: IgnoresAccessChecksTo("Unity.ProBuilder.Stl")] [assembly: IgnoresAccessChecksTo("Unity.Profiling.Core")] [assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.Core.Runtime")] [assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.Core.ShaderLibrary")] [assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.HighDefinition.Config.Runtime")] [assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.HighDefinition.Runtime")] [assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.ShaderGraph.ShaderGraphLibrary")] [assembly: IgnoresAccessChecksTo("Unity.Services.Authentication")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Analytics")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Components")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Configuration")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Device")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Environments")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Environments.Internal")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Internal")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Networking")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Registration")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Scheduler")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Telemetry")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Threading")] [assembly: IgnoresAccessChecksTo("Unity.Services.QoS")] [assembly: IgnoresAccessChecksTo("Unity.Services.Relay")] [assembly: IgnoresAccessChecksTo("Unity.TextMeshPro")] [assembly: IgnoresAccessChecksTo("Unity.Timeline")] [assembly: IgnoresAccessChecksTo("Unity.VisualEffectGraph.Runtime")] [assembly: IgnoresAccessChecksTo("UnityEngine.ARModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.NVIDIAModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.UI")] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("TestAccount666.GoodItemScan")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyDescription("Yet another scan mod")] [assembly: AssemblyFileVersion("2.2.0.0")] [assembly: AssemblyInformationalVersion("2.2.0+03503e41babeb6af120e331af8b0b884c538b573")] [assembly: AssemblyProduct("GoodItemScan")] [assembly: AssemblyTitle("TestAccount666.GoodItemScan")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("2.2.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [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; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class ExtensionMarkerAttribute : Attribute { private readonly string <Name>k__BackingField; public string Name => <Name>k__BackingField; public ExtensionMarkerAttribute(string name) { <Name>k__BackingField = name; } } } namespace GoodItemScan { public enum AnimationType { VANILLA, GOOD, FADE, DOUBLE_RING } [Tooltip("This class is for mods like LGU that want to modify the scanner")] public static class CheatsAPI { public static int additionalDistance; public static int additionalEnemyDistance; public static int noLineOfSightDistance; } public readonly struct Color : IEquatable<Color> { public float Red { get; } public float Green { get; } public float Blue { get; } public Color UnityColor => new Color(Red, Green, Blue); public Color(float red, float green, float blue) { Red = red; Green = green; Blue = blue; } public static Color FromHex(string hex) { if (hex == null) { throw new ArgumentNullException("hex"); } ReadOnlySpan<char> readOnlySpan = hex.AsSpan().TrimStart('#'); if (readOnlySpan.Length != 6) { throw new ArgumentException("Hex string must be 6 characters long", "hex"); } byte b = byte.Parse(readOnlySpan.Slice(0, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture); byte b2 = byte.Parse(readOnlySpan.Slice(2, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture); byte b3 = byte.Parse(readOnlySpan.Slice(4, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture); return new Color((float)(int)b / 255f, (float)(int)b2 / 255f, (float)(int)b3 / 255f); } public override string ToString() { int num = (int)Math.Round(Math.Clamp(Red, 0f, 1f) * 255f); int num2 = (int)Math.Round(Math.Clamp(Green, 0f, 1f) * 255f); int num3 = (int)Math.Round(Math.Clamp(Blue, 0f, 1f) * 255f); return $"#{num:X2}{num2:X2}{num3:X2}"; } public override bool Equals(object? obj) { return obj is Color other && Equals(other); } public bool Equals(Color other) { return Red.Equals(other.Red) && Green.Equals(other.Green) && Blue.Equals(other.Blue); } public override int GetHashCode() { return HashCode.Combine(Red, Green, Blue); } public static bool operator ==(Color left, Color right) { return left.Equals(right); } public static bool operator !=(Color left, Color right) { return !left.Equals(right); } } public static class ComponentCache { public static (GrabbableObject? Grabbable, EnemyAI? Enemy, TerminalAccessibleObject? Terminal) GetComponents(GameObject parent) { if (!ConfigManager.useNodeCache.Value) { return GetUncachedComponents(parent); } ScanNodeComponents scanNodeComponents = default(ScanNodeComponents); if (parent.TryGetComponent<ScanNodeComponents>(ref scanNodeComponents)) { return scanNodeComponents.Components; } return KotlinStyleExtensions.Also<(GrabbableObject, EnemyAI, TerminalAccessibleObject)>(GetUncachedComponents(parent), (Action<(GrabbableObject, EnemyAI, TerminalAccessibleObject)>)parent.AddComponent<ScanNodeComponents>().Cache); } private static (GrabbableObject? Grabbable, EnemyAI? Enemy, TerminalAccessibleObject? Terminal) GetUncachedComponents(GameObject parent) { GrabbableObject item = default(GrabbableObject); parent.TryGetComponent<GrabbableObject>(ref item); EnemyAI item2 = default(EnemyAI); parent.TryGetComponent<EnemyAI>(ref item2); TerminalAccessibleObject item3 = default(TerminalAccessibleObject); parent.TryGetComponent<TerminalAccessibleObject>(ref item3); return (Grabbable: item, Enemy: item2, Terminal: item3); } } public static class ConfigManager { public static ConfigEntry<bool> holdToScan = null; public static ConfigEntry<bool> preferClosestNodes = null; public static ConfigEntry<bool> alwaysRescan = null; public static ConfigEntry<int> scanNodesHardLimit = null; public static ConfigEntry<float> scanNodeDelay = null; public static ConfigEntry<bool> useNodeCache = null; public static ConfigEntry<bool> alwaysCheckForLineOfSight = null; public static ConfigEntry<int> scanNodesGroupSize = null; public static ConfigEntry<bool> updateScanNodeText = null; public static ConfigEntry<bool> calculateDistance = null; public static ConfigEntry<bool> sendDebugMessages = null; public static ConfigEntry<bool> showOpenedBlastDoorScanNode = null; public static ConfigEntry<bool> addBoxCollidersToInvalidScanNodes = null; public static ConfigEntry<bool> hideEmptyScanNodeSubText = null; public static ConfigEntry<int> totalAddWaitMultiplier = null; public static ConfigEntry<float> updateTimer = null; public static ConfigEntry<bool> fixLandmineScanNode = null; public static readonly Dictionary<NodeType, ConfigEntry<AnimationType>> APPEAR_ANIMATION_TYPES = new Dictionary<NodeType, ConfigEntry<AnimationType>>(); public static readonly Dictionary<NodeType, ConfigEntry<float>> APPEAR_ANIMATION_SPEEDS = new Dictionary<NodeType, ConfigEntry<float>>(); public static readonly Dictionary<NodeType, ConfigEntry<AnimationType>> DISAPPEAR_ANIMATION_TYPES = new Dictionary<NodeType, ConfigEntry<AnimationType>>(); public static readonly Dictionary<NodeType, ConfigEntry<float>> DISAPPEAR_ANIMATION_SPEEDS = new Dictionary<NodeType, ConfigEntry<float>>(); public static readonly Dictionary<NodeType, Color> TEXT_COLORS = new Dictionary<NodeType, Color>(); public static readonly Dictionary<NodeType, Color> TEXT_BACKGROUND_COLORS = new Dictionary<NodeType, Color>(); public static readonly Dictionary<NodeType, Color> CIRCLE_COLORS = new Dictionary<NodeType, Color>(); public static ConfigEntry<int> scanNodeScreenTime = null; internal static void Initialize(ConfigFile configFile) { //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Expected O, but got Unknown //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Expected O, but got Unknown //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Expected O, but got Unknown //IL_01c9: Unknown result type (might be due to invalid IL or missing references) //IL_01d3: Expected O, but got Unknown //IL_0201: Unknown result type (might be due to invalid IL or missing references) //IL_020b: Expected O, but got Unknown //IL_04cd: Unknown result type (might be due to invalid IL or missing references) //IL_04d7: Expected O, but got Unknown //IL_02eb: Unknown result type (might be due to invalid IL or missing references) //IL_02f5: Expected O, but got Unknown //IL_0362: Unknown result type (might be due to invalid IL or missing references) //IL_036c: Expected O, but got Unknown preferClosestNodes = configFile.Bind<bool>("General", "Prefer Closest Nodes", true, "If true, will prefer scanning the closest nodes first. This might cause performance issues."); alwaysRescan = configFile.Bind<bool>("General", "Always Rescan", true, "If true, will always start a fresh scan. This removes all previously scanned nodes from the UI."); scanNodesHardLimit = configFile.Bind<int>("General", "Scan Nodes Hard Limit", 60, new ConfigDescription("Defines the maximum amount of scan nodes on screen. If you feel like your screen is cluttered, try lowering this value.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(30, 666), Array.Empty<object>())); scanNodeDelay = configFile.Bind<float>("General", "Scan Node Delay", 0.1f, new ConfigDescription("Defines the delay between each scan node being added to the UI. This will look stupid if set too high. This value is divided by 100.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); useNodeCache = configFile.Bind<bool>("General", "Use Cache", true, "May increase performance, at the cost of ram usage. If true, the components a scan node's validity check needs are cached on the scan node's parent. If false, they will be looked up every time."); alwaysCheckForLineOfSight = configFile.Bind<bool>("General", "Always Check For Line Of Sight", false, "If true, will check for line of sight every frame. Enabling this could cause performance issues. Vanilla value is true."); scanNodesGroupSize = configFile.Bind<int>("General", "Scan Node Group Size", 32, new ConfigDescription("Will use \"Scan Node Hard Limit\" divided by \"this value\" to determine how many canvases will be created. This should be between a quarter and half of \"Scan Node Hard Limit\". This is also used to determine how many nodes will be scanned/updated per frame.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 666), Array.Empty<object>())); updateScanNodeText = configFile.Bind<bool>("General", "Update Scan Node Text", true, "If true, will update the scan node text. This is useful, if you, for example, have a mod that updates the value of an item."); calculateDistance = configFile.Bind<bool>("General", "Calculate Distance", false, "If true, will perform additional distance calculations. If false, use viewport as distance. Set to `true`, if you don't mind slightly worse performance and want accurate distance calculations."); sendDebugMessages = configFile.Bind<bool>("Debug", "Send Debug Messages", false, "If set to true, will spam your log with debug messages."); showOpenedBlastDoorScanNode = configFile.Bind<bool>("Special Cases", "Show opened blast door scan node", true, "If set to true, will allow you to scan nodes of opened blast doors (Vanilla value: false) Enabling this could improve performance."); addBoxCollidersToInvalidScanNodes = configFile.Bind<bool>("Special Cases", "Add BoxColliders To Invalid Scan Nodes", false, "If true, will add BoxColliers to ScanNodes that do not have one. It is not recommended to enable this. This feature was also never tested, so it might not even work."); hideEmptyScanNodeSubText = configFile.Bind<bool>("Special Cases", "Hide Empty Scan Node Sub Text", true, "I true, will hide the rectangle beneath the item name, if there's no text to be displayed."); totalAddWaitMultiplier = configFile.Bind<int>("Special Cases", "Total Add Wait Multiplier", 100, new ConfigDescription("This multiplier is used to define the wait time between adding more to the total displayed value. The lower this number, the faster the animation is updated. The lower this number, the less will be added per updated. For a vanilla-ish feeling, set this to 48.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 100), Array.Empty<object>())); updateTimer = configFile.Bind<float>("Special Cases", "Scan Node Update Timer", 0.6f, new ConfigDescription("This value is used to have a cooldown between scan node updates (Like position updates). The lower this number, the more often it will get updated.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 12f), Array.Empty<object>())); fixLandmineScanNode = configFile.Bind<bool>("Special Cases", "Fix Landmine ScanNode", true, "Fixes Landmines being scannable after exploding."); holdToScan = configFile.Bind<bool>("General", "Hold To Scan", false, "If true, holding the scan button will continuously scan."); NodeType[] enumValues = GetEnumValues<NodeType>(); foreach (NodeType type in enumValues) { if (type == NodeType.UNKNOWN) { continue; } string text = type.ToFriendlyName(); APPEAR_ANIMATION_TYPES[type] = configFile.Bind<AnimationType>("Visuals", text + " Appear Animation Type", AnimationType.GOOD, "The appear animation type to use for this node type."); APPEAR_ANIMATION_SPEEDS[type] = configFile.Bind<float>("Visuals", text + " Appear Animation Speed", 0.6f, new ConfigDescription("The appear animation speed to use for this node type.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 2f), Array.Empty<object>())); DISAPPEAR_ANIMATION_TYPES[type] = configFile.Bind<AnimationType>("Visuals", text + " Disappear Animation Type", AnimationType.GOOD, "The disappear animation type to use for this node type."); DISAPPEAR_ANIMATION_SPEEDS[type] = configFile.Bind<float>("Visuals", text + " Disappear Animation Speed", 0.6f, new ConfigDescription("The disappear animation speed to use for this node type.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 2f), Array.Empty<object>())); ConfigEntry<string> val = KotlinStyleExtensions.Also<ConfigEntry<string>>(configFile.Bind<string>("Visuals", text + " Text Color", type.DefaultTextColor().ToString(), "The color to use for this node type's text."), (Action<ConfigEntry<string>>)delegate(ConfigEntry<string> c) { c.SettingChanged += delegate { TEXT_COLORS[type] = Color.FromHex(c.Value); }; }); TEXT_COLORS[type] = Color.FromHex(val.Value); ConfigEntry<string> val2 = KotlinStyleExtensions.Also<ConfigEntry<string>>(configFile.Bind<string>("Visuals", text + " Text Background Color", type.DefaultTextBackgroundColor().ToString(), "The color to use for this node type's text background."), (Action<ConfigEntry<string>>)delegate(ConfigEntry<string> c) { c.SettingChanged += delegate { TEXT_BACKGROUND_COLORS[type] = Color.FromHex(c.Value); }; }); TEXT_BACKGROUND_COLORS[type] = Color.FromHex(val2.Value); ConfigEntry<string> val3 = KotlinStyleExtensions.Also<ConfigEntry<string>>(configFile.Bind<string>("Visuals", text + " Circle Color", type.DefaultCircleColor().ToString(), "The color to use for this node type's circles."), (Action<ConfigEntry<string>>)delegate(ConfigEntry<string> c) { c.SettingChanged += delegate { CIRCLE_COLORS[type] = Color.FromHex(c.Value); }; }); CIRCLE_COLORS[type] = Color.FromHex(val3.Value); } scanNodeScreenTime = configFile.Bind<int>("Visuals", "Scan Node Screen Time", 0, new ConfigDescription("The amount of seconds the scan node will be displayed on screen. This is used to determine how long the scan node will be displayed on screen. 0 = infinite", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 60), Array.Empty<object>())); } private static T[] GetEnumValues<T>() { return (T[])Enum.GetValues(typeof(T)); } } [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency("TestAccount666.TestAccountCore", "1.18.0")] [BepInPlugin("TestAccount666.GoodItemScan", "GoodItemScan", "2.2.0")] public class GoodItemScan : BaseUnityPlugin { public static readonly List<Hook> Hooks = new List<Hook>(); public static RectTransform originalRectTransform = null; public static ScanObjectInfo scanObject = null; public static Scanner? scanner; internal static AssetBundle assetBundle; public static GoodItemScan Instance { get; private set; } = null; internal static ManualLogSource Logger { get; private set; } = null; internal static Harmony? Harmony { get; set; } private void Awake() { Logger = ((BaseUnityPlugin)this).Logger; Instance = this; assetBundle = AssetBundle.LoadFromFile(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "GoodItemScan.AssetBundle")); ConfigManager.Initialize(((BaseUnityPlugin)this).Config); ConfigManager.scanNodesHardLimit.SettingChanged += delegate { SetIncreasedMaximumScanNodes(HUDManager.Instance); }; Patch(); HUDManagerPatch.InitMonoMod(); UnpatchHdLethalCompany(); Logger.LogInfo((object)"TestAccount666.GoodItemScan v2.2.0 has loaded!"); } private static void UnpatchHdLethalCompany() { MethodInfo methodInfo = AccessTools.DeclaredMethod(typeof(HUDManager), "UpdateScanNodes", (Type[])null, (Type[])null); Patches patchInfo = Harmony.GetPatchInfo((MethodBase)methodInfo); if (patchInfo == null) { return; } Patch[] array = patchInfo.Postfixes.ToArray(); foreach (Patch val in array) { if (val != null && val.owner.ToLower().Contains("hdlethalcompany")) { Harmony? harmony = Harmony; if (harmony != null) { harmony.Unpatch((MethodBase)methodInfo, (HarmonyPatchType)2, val.owner); } Logger.LogInfo((object)"Found HDLethalCompany patch!"); Logger.LogInfo((object)$"Unpatched {methodInfo} method!"); } } } internal static void Patch() { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown if (Harmony == null) { Harmony = new Harmony("TestAccount666.GoodItemScan"); } LogDebug("Patching..."); Harmony.PatchAll(); LogDebug("Finished patching!"); } internal static void Unpatch() { LogDebug("Unpatching..."); Harmony? harmony = Harmony; if (harmony != null) { harmony.UnpatchSelf(); } foreach (Hook hook in Hooks) { hook.Undo(); } LogDebug("Finished unpatching!"); } internal static void SetIncreasedMaximumScanNodes(HUDManager? hudManager) { if (!((Object)(object)hudManager == (Object)null)) { RectTransform[] scanElements = hudManager.scanElements; foreach (RectTransform val in scanElements) { hudManager.scanNodes.Remove(val); ((Component)val).gameObject.SetActive(false); } hudManager.scanNodesHit = Array.Empty<RaycastHit>(); hudManager.scanElements = Array.Empty<RectTransform>(); scanner?.FillInScanNodes(GetOriginal()); } } internal static ScanObjectInfo GetOriginal() { if (Object.op_Implicit((Object)(object)scanObject)) { return scanObject; } return KotlinStyleExtensions.Also<ScanObjectInfo>((from asset in assetBundle.LoadAllAssets() where asset is GameObject let gameObject1 = (GameObject)(object)((asset is GameObject) ? asset : null) let scanObjectInfo = gameObject1.GetComponent<ScanObjectInfo>() where Object.op_Implicit((Object)(object)scanObjectInfo) select scanObjectInfo).First(), (Action<ScanObjectInfo>)delegate(ScanObjectInfo obj) { scanObject = obj; }); } internal static void LogDebug(object data) { if (ConfigManager.sendDebugMessages.Value) { Logger.LogInfo(data); } } internal static void LogDebug(Func<object> data) { if (ConfigManager.sendDebugMessages.Value) { Logger.LogInfo(data()); } } } public class ScannedNode { private ScanNodeProperties? _scanNodeProperties; internal long _scanTimeStamp = -1L; public Vector3 viewPoint; public Vector3 lastKnownPosition = Vector3.zero; public GameObject scanNodeParent = null; public readonly int canvasIndex; public readonly ScanObjectInfo scanObject; public ScanNodeProperties ScanNodeProperties { get { return _scanNodeProperties ?? null; } set { _scanNodeProperties = value; if (Object.op_Implicit((Object)(object)value)) { scanNodeParent = ((Component)((Component)value).transform.parent).gameObject; } } } public long ScanTimeStamp => _scanTimeStamp; public NodeType NodeType => ScanNodeProperties.nodeType.ToNodeType(); public RectTransform RectTransform => scanObject.mainRectTransform; public TextMeshProUGUI Header => scanObject.header; public TextMeshProUGUI Footer => scanObject.footer; public GameObject SubTextBox => ((Component)scanObject.footerBackground).gameObject; public bool HasScanNode => (Object)(object)_scanNodeProperties != (Object)null && Object.op_Implicit((Object)(object)_scanNodeProperties); public ScannedNode(ScanObjectInfo scanObject, int canvasIndex) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) this.canvasIndex = canvasIndex; this.scanObject = scanObject; base..ctor(); } } public enum NodeType { UNKNOWN = -1, TOOL, ENEMY, SCRAP } public static class NodeTypeExtensions { [SpecialName] public sealed class <G>$78FA61F72D34BA5A738598239CA56B23 { [SpecialName] public static class <M>$B9BEC052AB23CE2DC4C37EAE403BE62B { } [ExtensionMarker("<M>$B9BEC052AB23CE2DC4C37EAE403BE62B")] public string ToFriendlyName() { throw new NotSupportedException(); } [ExtensionMarker("<M>$B9BEC052AB23CE2DC4C37EAE403BE62B")] public Color DefaultTextColor() { throw new NotSupportedException(); } [ExtensionMarker("<M>$B9BEC052AB23CE2DC4C37EAE403BE62B")] public Color DefaultTextBackgroundColor() { throw new NotSupportedException(); } [ExtensionMarker("<M>$B9BEC052AB23CE2DC4C37EAE403BE62B")] public Color DefaultCircleColor() { throw new NotSupportedException(); } [ExtensionMarker("<M>$B9BEC052AB23CE2DC4C37EAE403BE62B")] public Color TextColor() { throw new NotSupportedException(); } [ExtensionMarker("<M>$B9BEC052AB23CE2DC4C37EAE403BE62B")] public Color TextBackgroundColor() { throw new NotSupportedException(); } [ExtensionMarker("<M>$B9BEC052AB23CE2DC4C37EAE403BE62B")] public Color CircleColor() { throw new NotSupportedException(); } } public static string ToFriendlyName(this NodeType nodeType) { string text = nodeType.ToString(); return text.Substring(0, 1).ToUpper() + text.Substring(1); } public static Color DefaultTextColor(this NodeType nodeType) { if (1 == 0) { } Color result = nodeType switch { NodeType.TOOL => new Color(0f, 0f, 0f), NodeType.ENEMY => new Color(0f, 0f, 0f), NodeType.SCRAP => new Color(0f, 0f, 0f), _ => new Color(0f, 0f, 0f), }; if (1 == 0) { } return result; } public static Color DefaultTextBackgroundColor(this NodeType nodeType) { if (1 == 0) { } Color result = nodeType switch { NodeType.TOOL => new Color(0.043137256f, 22f / 85f, 0.69803923f), NodeType.ENEMY => new Color(64f / 85f, 2f / 85f, 0f), NodeType.SCRAP => new Color(0.14509805f, 0.5019608f, 0f), _ => new Color(0f, 0f, 0f), }; if (1 == 0) { } return result; } public static Color DefaultCircleColor(this NodeType nodeType) { if (1 == 0) { } Color result = nodeType switch { NodeType.TOOL => new Color(0.043137256f, 0f, 0.69803923f), NodeType.ENEMY => new Color(1f, 2f / 51f, 0f), NodeType.SCRAP => new Color(0.21960784f, 57f / 85f, 0f), _ => new Color(0f, 0f, 0f), }; if (1 == 0) { } return result; } public static Color TextColor(this NodeType nodeType) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) return ConfigManager.TEXT_COLORS[nodeType].UnityColor; } public static Color TextBackgroundColor(this NodeType nodeType) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) return ConfigManager.TEXT_BACKGROUND_COLORS[nodeType].UnityColor; } public static Color CircleColor(this NodeType nodeType) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) return ConfigManager.CIRCLE_COLORS[nodeType].UnityColor; } public static NodeType ToNodeType(this int value) { try { return (NodeType)value; } catch { return NodeType.UNKNOWN; } } } public class Scanner { public static readonly int DISPLAY_ANIMATOR_HASH = Animator.StringToHash("display"); private static readonly int _SCAN_ANIMATOR_HASH = Animator.StringToHash("scan"); private static readonly int _ANIMATION_SPEED_ANIMATOR_HASH = Animator.StringToHash("AnimationSpeed"); private static readonly int _APPEAR_ANIMATION_TYPE_ANIMATOR_HASH = Animator.StringToHash("AppearAnimationType"); private static readonly int _DISAPPEAR_ANIMATION_TYPE_ANIMATOR_HASH = Animator.StringToHash("DisappearAnimationType"); private static readonly int _VISIBLE_ANIMATOR_HASH = Animator.StringToHash("Visible"); private static readonly int _IDLE_STATE_HASH = Animator.StringToHash("Idle"); private Coroutine? _scanCoroutine; private Coroutine? _nodeVisibilityCheckCoroutine; private readonly List<ScannedNode> _scannedNodesToRemove = new List<ScannedNode>(); public readonly HashSet<ScannedNode> activeNodes = new HashSet<ScannedNode>(); private readonly ScrapTracker _scrapTracker = new ScrapTracker(); private readonly ScannerUI _ui = new ScannerUI(); private float _updateTimer = 0.05f; private Rect _cachedScreenRect; private Camera? _cachedCamera; private RectTransform _screenRectTransform = null; private RectTransform ScreenRectTransform { get { if (Object.op_Implicit((Object)(object)_screenRectTransform)) { return _screenRectTransform; } HUDManager instance = HUDManager.Instance; if (!Object.op_Implicit((Object)(object)instance)) { return null; } GameObject gameObject = ((Component)instance.playerScreenShakeAnimator).gameObject; return _screenRectTransform = gameObject.GetComponent<RectTransform>(); } } public void FillInScanNodes(ScanObjectInfo scanObject) { if (!Object.op_Implicit((Object)(object)scanObject)) { scanObject = GoodItemScan.GetOriginal(); } if (!Object.op_Implicit((Object)(object)scanObject)) { GoodItemScan.Logger.LogError((object)"ScanObjectInfo is null!"); } DisableAllScanElements(); _ui.Initialize(scanObject); _nodeVisibilityCheckCoroutine = null; } public void Scan() { //IL_007c: Unknown result type (might be due to invalid IL or missing references) PlayerControllerB localPlayerController = StartOfRound.Instance.localPlayerController; if (!Object.op_Implicit((Object)(object)localPlayerController)) { return; } HUDManager instance = HUDManager.Instance; if (Object.op_Implicit((Object)(object)instance) && instance.CanPlayerScan() && !((double)instance.playerPingingScan > -1.0)) { ResetScanState(instance); Transform transform = ((Component)localPlayerController.gameplayCamera).transform; ((Component)instance.scanEffectAnimator).transform.position = transform.position; instance.scanEffectAnimator.SetTrigger(_SCAN_ANIMATOR_HASH); instance.UIAudio.PlayOneShot(instance.scanSFX); GoodItemScan.LogDebug("Scan Initiated!"); ScanNodeProperties[] foundScanNodes = Object.FindObjectsByType<ScanNodeProperties>((FindObjectsInactive)0, (FindObjectsSortMode)0); GoodItemScan.LogDebug(() => $"Got '{foundScanNodes.Length}' nodes!"); _scanCoroutine = ((MonoBehaviour)instance).StartCoroutine(ScanNodesRoutine(localPlayerController, foundScanNodes)); } } private void ResetScanState(HUDManager hudManager) { if (_scanCoroutine != null) { ((MonoBehaviour)hudManager).StopCoroutine(_scanCoroutine); } if (ConfigManager.alwaysRescan.Value) { DisableAllScanElements(); _scrapTracker.Reset(); } hudManager.playerPingingScan = 0.3f; } public void DisableAllScanElements() { foreach (ScannedNode item in activeNodes.ToHashSet()) { DisableScanNode(item); } _scannedNodesToRemove.Clear(); _ui.ClearUpdateSets(); HUDManager instance = HUDManager.Instance; if (_nodeVisibilityCheckCoroutine != null && (Object)(object)instance != (Object)null) { ((MonoBehaviour)instance).StopCoroutine(_nodeVisibilityCheckCoroutine); } _nodeVisibilityCheckCoroutine = null; } private IEnumerator ScanNodesRoutine(PlayerControllerB localPlayer, ScanNodeProperties[] scanNodes) { if (ConfigManager.preferClosestNodes.Value) { Vector3 playerPos = ((Component)localPlayer).transform.position; scanNodes = scanNodes.OrderBy(delegate(ScanNodeProperties val2) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) Vector3 val = playerPos - ((Component)val2).transform.position; return ((Vector3)(ref val)).sqrMagnitude; }).ToArray(); } yield return null; int currentScanNodeCount = 0; int processedNodesThisFrame = 0; int maxPerFrame = ConfigManager.scanNodesGroupSize.Value; int hardLimit = ConfigManager.scanNodesHardLimit.Value; ScanNodeProperties[] array = scanNodes; foreach (ScanNodeProperties node in array) { if (!Object.op_Implicit((Object)(object)node)) { continue; } if (processedNodesThisFrame >= maxPerFrame) { yield return null; processedNodesThisFrame = 0; } processedNodesThisFrame++; Vector3 viewPoint = localPlayer.gameplayCamera.WorldToViewportPoint(((Component)node).transform.position); if (!ScanValidator.IsNodeVisible(node, viewPoint, forceCheckLos: true)) { continue; } currentScanNodeCount++; if (currentScanNodeCount > hardLimit) { GoodItemScan.LogDebug(() => $"Hard Limit of {hardLimit} reached!"); break; } ((MonoBehaviour)localPlayer).StartCoroutine(AddScanNodeToUI(node, viewPoint, currentScanNodeCount)); } } private IEnumerator AddScanNodeToUI(ScanNodeProperties node, Vector3 viewPoint, int currentScanNodeCount) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) yield return (object)new WaitForSeconds(ConfigManager.scanNodeDelay.Value / 100f * (float)currentScanNodeCount); yield return null; HUDManager hudManager = HUDManager.Instance; if (!Object.op_Implicit((Object)(object)hudManager) || !Object.op_Implicit((Object)(object)node)) { yield break; } GoodItemScan.LogDebug(() => $"Scanning node '{currentScanNodeCount}'! ({node.headerText};{node.subText})"); ScannedNode? scannedNode = AssignNodeToUIElement(node); if (scannedNode != null) { KotlinStyleExtensions.Also<ScannedNode>(scannedNode, (Action<ScannedNode>)delegate(ScannedNode scannedNode2) { //IL_0016: 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) scannedNode2._scanTimeStamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); scannedNode2.viewPoint = viewPoint; RefreshPositionCache(); UpdateScanNodePosition(scannedNode2); ActivateScanElement(hudManager, scannedNode2); }); } } public ScannedNode? AssignNodeToUIElement(ScanNodeProperties node) { if ((Object)(object)HUDManager.Instance == (Object)null) { return null; } foreach (ScannedNode activeNode in activeNodes) { if ((Object)(object)activeNode.ScanNodeProperties != (Object)(object)node) { continue; } return null; } ScannedNode? scannedNode = _ui.DequeueNode(); return (scannedNode != null) ? KotlinStyleExtensions.Also<ScannedNode>(scannedNode, (Action<ScannedNode>)delegate(ScannedNode scannedNode2) { scannedNode2.ScanNodeProperties = node; activeNodes.Add(scannedNode2); }) : null; } public void UpdateScanNodes() { HUDManager instance = HUDManager.Instance; if (!Object.op_Implicit((Object)(object)instance)) { return; } HandlePendingRemovals(); _scrapTracker.UpdateDisplay(instance, activeNodes.Count > 0); if (activeNodes.Count <= 0) { return; } _updateTimer -= Time.deltaTime; if (_updateTimer > 0f) { return; } _updateTimer = ConfigManager.updateTimer.Value / 100f; if (_nodeVisibilityCheckCoroutine != null) { return; } long num = (long)ConfigManager.scanNodeScreenTime.Value * 1000L; long num2 = ((num > 0) ? DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() : 0); foreach (ScannedNode activeNode in activeNodes) { if (!activeNode.HasScanNode) { HandleMissingNode(activeNode); } else if (num > 0 && (activeNode.NodeType != NodeType.SCRAP || _scrapTracker._scannedValue <= _scrapTracker._scannedValueDisplayed) && num2 - activeNode._scanTimeStamp >= num) { ((MonoBehaviour)instance).StartCoroutine(DisableScanNodeWithAnimation(activeNode)); } else { _ui.canvasesToUpdate[activeNode.canvasIndex].Add(activeNode); } } if (_ui.TotalNodesToUpdate > 0) { _nodeVisibilityCheckCoroutine = ((MonoBehaviour)instance).StartCoroutine(UpdateScanNodesRoutine()); } } private void HandlePendingRemovals() { if (_scannedNodesToRemove.Count > 0) { _scannedNodesToRemove.ForEach(DisableScanNode); _scannedNodesToRemove.Clear(); } } private IEnumerator UpdateScanNodesRoutine() { foreach (HashSet<ScannedNode> set in _ui.canvasesToUpdate.Where((HashSet<ScannedNode> hashSet) => hashSet.Count > 0)) { foreach (ScannedNode scannedNode in set) { if (!ScanValidator.IsNodeVisible(scannedNode.ScanNodeProperties, scannedNode.viewPoint, forceCheckLos: false)) { HandleMissingNode(scannedNode); } else { if (!ConfigManager.updateScanNodeText.Value) { continue; } ScanNodeProperties node = scannedNode.ScanNodeProperties; if (Object.op_Implicit((Object)(object)node)) { ((TMP_Text)scannedNode.Header).text = node.headerText; ((TMP_Text)scannedNode.Footer).text = node.subText; if (ConfigManager.hideEmptyScanNodeSubText.Value) { scannedNode.SubTextBox.SetActive(!string.IsNullOrWhiteSpace(node.subText)); } } } } set.Clear(); yield return null; } _nodeVisibilityCheckCoroutine = null; } private void RefreshPositionCache() { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) RectTransform screenRectTransform = ScreenRectTransform; if (!Object.op_Implicit((Object)(object)screenRectTransform)) { return; } _cachedScreenRect = screenRectTransform.rect; StartOfRound instance = StartOfRound.Instance; if (!Object.op_Implicit((Object)(object)instance)) { _cachedCamera = null; return; } PlayerControllerB localPlayerController = instance.localPlayerController; if (!Object.op_Implicit((Object)(object)localPlayerController)) { _cachedCamera = null; } else { _cachedCamera = localPlayerController.gameplayCamera; } } private IEnumerator DisableScanNodeWithAnimation(ScannedNode scannedNode) { if (scannedNode == null) { yield break; } KotlinStyleExtensions.Also<Animator>(scannedNode.scanObject.animator, (Action<Animator>)delegate(Animator a) { a.SetFloat(_ANIMATION_SPEED_ANIMATOR_HASH, ConfigManager.DISAPPEAR_ANIMATION_SPEEDS[scannedNode.NodeType].Value); a.SetInteger(_DISAPPEAR_ANIMATION_TYPE_ANIMATOR_HASH, (int)ConfigManager.DISAPPEAR_ANIMATION_TYPES[scannedNode.NodeType].Value); a.SetBool(_VISIBLE_ANIMATOR_HASH, false); }); yield return (object)new WaitUntil((Func<bool>)delegate { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) int result; if (scannedNode.HasScanNode) { AnimatorStateInfo currentAnimatorStateInfo = scannedNode.scanObject.animator.GetCurrentAnimatorStateInfo(0); result = ((((AnimatorStateInfo)(ref currentAnimatorStateInfo)).shortNameHash == _IDLE_STATE_HASH) ? 1 : 0); } else { result = 1; } return (byte)result != 0; }); if (scannedNode.HasScanNode) { HandleMissingNode(scannedNode); } } private void HandleMissingNode(ScannedNode scannedNode) { if (scannedNode != null) { ScanNodeProperties scanNodeProperties = scannedNode.ScanNodeProperties; if ((Object)(object)scanNodeProperties != (Object)null && Object.op_Implicit((Object)(object)scanNodeProperties)) { _scrapTracker.RemoveScrap(scanNodeProperties); } _scannedNodesToRemove.Add(scannedNode); } } private void UpdateScanNodePosition(ScannedNode scannedNode) { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_cachedCamera == (Object)null)) { ScanNodeProperties scanNodeProperties = scannedNode.ScanNodeProperties; if (Object.op_Implicit((Object)(object)scanNodeProperties)) { Vector3 val = (scannedNode.viewPoint = _cachedCamera.WorldToViewportPoint(((Component)scanNodeProperties).transform.position)); Vector3 val2 = default(Vector3); ((Vector3)(ref val2))..ctor(((Rect)(ref _cachedScreenRect)).xMin + ((Rect)(ref _cachedScreenRect)).width * val.x, ((Rect)(ref _cachedScreenRect)).yMin + ((Rect)(ref _cachedScreenRect)).height * val.y, val.z); scannedNode.lastKnownPosition = val2; scannedNode.RectTransform.anchoredPosition = Vector2.op_Implicit(val2); } } } public void ActivateScanElement(HUDManager hudManager, ScannedNode scannedNode) { //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) ScanNodeProperties node = scannedNode.ScanNodeProperties; if (!Object.op_Implicit((Object)(object)node)) { return; } NodeType nodeType = KotlinStyleExtensions.Also<NodeType>(scannedNode.NodeType, (Action<NodeType>)delegate(NodeType t) { if (t == NodeType.SCRAP) { _scrapTracker.AddScrap(node); } }); ScanObjectInfo scanObject = scannedNode.scanObject; ((Component)scanObject.mainRectTransform).gameObject.SetActive(true); scanObject.animator.SetFloat(_ANIMATION_SPEED_ANIMATOR_HASH, ConfigManager.APPEAR_ANIMATION_SPEEDS[nodeType].Value); scanObject.animator.SetInteger(_APPEAR_ANIMATION_TYPE_ANIMATOR_HASH, (int)ConfigManager.APPEAR_ANIMATION_TYPES[nodeType].Value); scanObject.animator.SetBool(_VISIBLE_ANIMATOR_HASH, true); scanObject.SetTextColor(nodeType.TextColor()); scanObject.SetTextBackgroundColor(nodeType.TextBackgroundColor()); scanObject.SetCircleColor(nodeType.CircleColor()); ((TMP_Text)scannedNode.Header).text = node.headerText; ((TMP_Text)scannedNode.Footer).text = node.subText; if (node.creatureScanID != -1) { hudManager.AttemptScanNewCreature(node.creatureScanID); } if (ConfigManager.hideEmptyScanNodeSubText.Value) { scannedNode.SubTextBox.SetActive(!string.IsNullOrWhiteSpace(node.subText)); } } private void DisableScanNode(ScannedNode scannedNode) { if (Object.op_Implicit((Object)(object)scannedNode.RectTransform)) { ((Component)scannedNode.RectTransform).gameObject.SetActive(false); } scannedNode.ScanNodeProperties = null; activeNodes.Remove(scannedNode); _ui.EnqueueNode(scannedNode); } internal void LateUpdate() { if (activeNodes.Count <= 0) { return; } if (!Object.op_Implicit((Object)(object)_cachedCamera)) { RefreshPositionCache(); } foreach (ScannedNode activeNode in activeNodes) { UpdateScanNodePosition(activeNode); } } } public class ScannerUI { internal readonly List<GameObject> _canvases = new List<GameObject>(); internal readonly List<RectTransform> _canvasRectTransforms = new List<RectTransform>(); private readonly List<Queue<ScannedNode>> _freeNodes = new List<Queue<ScannedNode>>(); public readonly List<HashSet<ScannedNode>> canvasesToUpdate = new List<HashSet<ScannedNode>>(); public int CanvasCount => _canvases.Count; public int TotalNodesToUpdate => canvasesToUpdate.Sum((HashSet<ScannedNode> set) => set.Count); public void Clear() { _canvases.ForEach((Action<GameObject>)Object.Destroy); _canvases.Clear(); _canvasRectTransforms.Clear(); _freeNodes.Clear(); canvasesToUpdate.Clear(); } public void Initialize(ScanObjectInfo scanObject) { //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Expected O, but got Unknown Clear(); int value = ConfigManager.scanNodesHardLimit.Value; int value2 = ConfigManager.scanNodesGroupSize.Value; int num = Mathf.CeilToInt((float)value / (float)value2); GoodItemScan.LogDebug($"Built {num} canvases!"); if (num > 6) { GoodItemScan.Logger.LogWarning((object)($"Your max size ({value}) is considerably higher than your maxPerFrame ({value2}) setting! " + "This will cause the scanner to appear laggy! Try maxSize / maxPerFrame to be lower than 6!")); } for (int i = 0; i < num; i++) { canvasesToUpdate.Add(new HashSet<ScannedNode>()); } GameObject val = GameObject.Find("Systems/UI/Canvas"); Canvas parentCanvas = val.GetComponent<Canvas>(); Transform objectScanner = val.transform.Find("ObjectScanner"); for (int j = 0; j < num; j++) { GameObject val2 = KotlinStyleExtensions.Also<GameObject>(new GameObject($"ScanCanvas_{j}", new Type[2] { typeof(RectTransform), typeof(Canvas) }), (Action<GameObject>)delegate(GameObject obj) { obj.transform.SetParent(objectScanner, false); obj.layer = 5; RectTransform item = KotlinStyleExtensions.Also<RectTransform>(obj.GetComponent<RectTransform>(), (Action<RectTransform>)delegate(RectTransform rt) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_000e: 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_0026: Unknown result type (might be due to invalid IL or missing references) rt.anchorMin = Vector2.zero; rt.anchorMax = Vector2.one; rt.offsetMin = Vector2.zero; rt.offsetMax = Vector2.zero; }); _canvasRectTransforms.Add(item); }); _canvases.Add(val2); _freeNodes.Add(new Queue<ScannedNode>()); KotlinStyleExtensions.Also<Canvas>(val2.GetComponent<Canvas>(), (Action<Canvas>)delegate(Canvas canvasComp) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)parentCanvas)) { canvasComp.renderMode = parentCanvas.renderMode; canvasComp.worldCamera = parentCanvas.worldCamera; canvasComp.planeDistance = parentCanvas.planeDistance; canvasComp.sortingLayerName = parentCanvas.sortingLayerName; canvasComp.sortingOrder = parentCanvas.sortingOrder; } }); int canvasSize = Mathf.Min(value2, value - j * value2); PopulateCanvas(scanObject, canvasSize, j, val2); } SetupHUDLayout(); } private void PopulateCanvas(ScanObjectInfo scanObject, int canvasSize, int index, GameObject canvasObj) { Transform canvasTransform = canvasObj.transform; UsefulExtensions.Times(canvasSize, (Action)delegate { //IL_0012: 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) ScanObjectInfo scanObject2 = KotlinStyleExtensions.Let<GameObject, ScanObjectInfo>(KotlinStyleExtensions.Also<GameObject>(Object.Instantiate<GameObject>(((Component)scanObject).gameObject, canvasTransform.position, canvasTransform.rotation, canvasTransform), (Action<GameObject>)delegate(GameObject obj) { obj.gameObject.SetActive(false); }), (Func<GameObject, ScanObjectInfo>)((GameObject obj) => obj.GetComponent<ScanObjectInfo>())); _freeNodes[index].Enqueue(new ScannedNode(scanObject2, index)); }); } private static void SetupHUDLayout() { GameObject val = GameObject.Find("Systems/UI/Canvas"); if ((Object)(object)val == (Object)null || !Object.op_Implicit((Object)(object)val)) { return; } Transform val2 = val.transform.Find("ObjectScanner"); if (!((Object)(object)val2 == (Object)null) && Object.op_Implicit((Object)(object)val2)) { val2.SetSiblingIndex(3); Transform val3 = val2.Find("GlobalScanInfo"); if ((Object)(object)val3 != (Object)null && Object.op_Implicit((Object)(object)val3)) { val3.SetAsLastSibling(); } } } public ScannedNode? DequeueNode() { foreach (Queue<ScannedNode> freeNode in _freeNodes) { if (!freeNode.TryDequeue(out var result)) { continue; } return result; } return null; } public void EnqueueNode(ScannedNode node) { if (node.canvasIndex < _freeNodes.Count) { _freeNodes[node.canvasIndex].Enqueue(node); } } public void ClearUpdateSets() { canvasesToUpdate.ForEach(delegate(HashSet<ScannedNode> set) { set.Clear(); }); } } public sealed class ScanNodeComponents : MonoBehaviour { private GrabbableObject? _grabbable; private EnemyAI? _enemy; private TerminalAccessibleObject? _terminal; public (GrabbableObject? Grabbable, EnemyAI? Enemy, TerminalAccessibleObject? Terminal) Components => (Grabbable: _grabbable, Enemy: _enemy, Terminal: _terminal); public void Cache(GrabbableObject? grabbable, EnemyAI? enemy, TerminalAccessibleObject? terminal) { _grabbable = grabbable; _enemy = enemy; _terminal = terminal; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Cache((GrabbableObject? Grabbable, EnemyAI? Enemy, TerminalAccessibleObject? Terminal) cache) { Cache(cache.Grabbable, cache.Enemy, cache.Terminal); } } public class ScanObjectInfo : MonoBehaviour { public Image[] circles; public TextMeshProUGUI header; public RectTransform headerBackground; public Image headerImage; public TextMeshProUGUI footer; public RectTransform footerBackground; public Image footerImage; public RectTransform mainRectTransform; public Animator animator; public void SetTextColor(Color color) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) ((Graphic)header).color = color; ((Graphic)footer).color = color; } public void SetTextBackgroundColor(Color color) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) ((Graphic)headerImage).color = color; ((Graphic)footerImage).color = color; } public void SetCircleColor(Color color) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) Image[] array = circles; foreach (Image val in array) { ((Graphic)val).color = color; } } } public static class ScanValidator { private static readonly Vector3[] _CORNERS_BUFFER = (Vector3[])(object)new Vector3[8]; public static bool IsNodeVisible(ScanNodeProperties node, Vector3 viewPoint, bool forceCheckLos) { //IL_0001: 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_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) if (!IsNodeOnScreen(viewPoint)) { return false; } if (!Object.op_Implicit((Object)(object)node)) { return false; } PlayerControllerB localPlayerController = StartOfRound.Instance.localPlayerController; Vector3 position = ((Component)localPlayerController.gameplayCamera).transform.position; float num = CalculateDistance(viewPoint, ((Component)node).transform.position, position); int num2 = node.maxRange + ((node.nodeType.ToNodeType() == NodeType.ENEMY) ? CheatsAPI.additionalEnemyDistance : CheatsAPI.additionalDistance); if (num2 < node.maxRange) { num2 = int.MaxValue; } if (num > (float)num2 || num < (float)node.minRange) { return false; } if ((forceCheckLos || ConfigManager.alwaysCheckForLineOfSight.Value) && num > (float)CheatsAPI.noLineOfSightDistance && !HasLineOfSight(node, position)) { return false; } return IsScanNodeValid(node); } public static bool IsNodeOnScreen(Vector3 viewPoint) { //IL_0001: 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) //IL_002f: Unknown result type (might be due to invalid IL or missing references) float x = viewPoint.x; int result; if (x >= 0f && x <= 1f) { x = viewPoint.y; if (x >= 0f && x <= 1f) { result = ((viewPoint.z > 0f) ? 1 : 0); goto IL_003f; } } result = 0; goto IL_003f; IL_003f: return (byte)result != 0; } public static float CalculateDistance(Vector3 viewPoint, Vector3 objectPosition, Vector3 cameraPosition) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0016: 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) return ConfigManager.calculateDistance.Value ? Vector3.Distance(objectPosition, cameraPosition) : viewPoint.z; } public static bool HasLineOfSight(ScanNodeProperties node, Vector3 cameraPosition) { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: 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_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: 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_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) if (!node.requiresLineOfSight) { return true; } if (!TryGetOrAddBoxCollider(node, out BoxCollider boxCollider)) { return false; } Bounds bounds = ((Collider)boxCollider).bounds; Vector3 min = ((Bounds)(ref bounds)).min; Vector3 max = ((Bounds)(ref bounds)).max; _CORNERS_BUFFER[0] = max; _CORNERS_BUFFER[1] = new Vector3(max.x, max.y, min.z); _CORNERS_BUFFER[2] = new Vector3(max.x, min.y, max.z); _CORNERS_BUFFER[3] = new Vector3(max.x, min.y, min.z); _CORNERS_BUFFER[4] = new Vector3(min.x, max.y, max.z); _CORNERS_BUFFER[5] = new Vector3(min.x, max.y, min.z); _CORNERS_BUFFER[6] = new Vector3(min.x, min.y, max.z); _CORNERS_BUFFER[7] = min; Vector3[] cORNERS_BUFFER = _CORNERS_BUFFER; foreach (Vector3 val in cORNERS_BUFFER) { if (!Physics.Linecast(cameraPosition, val, 256, (QueryTriggerInteraction)1)) { return true; } } return false; } private static bool TryGetOrAddBoxCollider(ScanNodeProperties node, out BoxCollider boxCollider) { if (((Component)node).TryGetComponent<BoxCollider>(ref boxCollider)) { return true; } GoodItemScan.Logger.LogError((object)(node.headerText + " has no BoxCollider!")); if (!ConfigManager.addBoxCollidersToInvalidScanNodes.Value) { return false; } GoodItemScan.Logger.LogError((object)"Adding a BoxCollider!"); boxCollider = ((Component)node).gameObject.AddComponent<BoxCollider>(); return true; } public static bool IsScanNodeValid(ScanNodeProperties node) { Transform parent = ((Component)node).transform.parent; GameObject val = ((parent != null) ? ((Component)parent).gameObject : null); if (!Object.op_Implicit((Object)(object)val)) { return false; } (GrabbableObject, EnemyAI, TerminalAccessibleObject) components = ComponentCache.GetComponents(val); return IsScanNodeValid(components.Item1, components.Item2, components.Item3); } public static bool IsScanNodeValid(GrabbableObject? grabbable, EnemyAI? enemy, TerminalAccessibleObject? terminal) { if (grabbable != null && Object.op_Implicit((Object)(object)grabbable) && (grabbable.isHeld || grabbable.isHeldByEnemy || grabbable.deactivated)) { return false; } if (enemy != null && Object.op_Implicit((Object)(object)enemy) && enemy.isEnemyDead) { return false; } if (ConfigManager.showOpenedBlastDoorScanNode.Value) { return true; } if (terminal == null || !Object.op_Implicit((Object)(object)terminal) || !terminal.isBigDoor) { return true; } return terminal != null && !terminal.isDoorOpen && terminal.isPoweredOn; } } public class ScrapTracker { private int _scannedAmount; internal int _scannedValue; internal int _scannedValueDisplayed; private float _addToDisplayTotalInterval = 0.35f; public bool HasScrap => _scannedAmount > 0; public void Reset() { _scannedAmount = 0; _scannedValue = 0; _scannedValueDisplayed = 0; _addToDisplayTotalInterval = 0.35f; } public void AddScrap(ScanNodeProperties node) { if (node != null && node.nodeType == 2 && node.scrapValue > 0) { _scannedAmount++; _scannedValue += node.scrapValue; } } public void RemoveScrap(ScanNodeProperties node) { if (node != null && node.nodeType == 2 && node.scrapValue > 0) { _scannedAmount--; _scannedValue = Mathf.Clamp(_scannedValue - node.scrapValue, 0, 10000); } } public void UpdateDisplay(HUDManager hudManager, bool hasActiveNodes) { if (!hasActiveNodes || _scannedAmount <= 0) { ((TMP_Text)hudManager.totalValueText).text = "$0"; _scannedAmount = 0; _scannedValue = 0; _scannedValueDisplayed = 0; _addToDisplayTotalInterval = 0.35f; hudManager.scanInfoAnimator.SetBool(Scanner.DISPLAY_ANIMATOR_HASH, false); return; } hudManager.scanInfoAnimator.SetBool(Scanner.DISPLAY_ANIMATOR_HASH, _scannedValue != 0); if (_scannedValueDisplayed >= _scannedValue || _scannedValueDisplayed >= 10000) { return; } _addToDisplayTotalInterval -= Time.deltaTime; if (!(_addToDisplayTotalInterval > 0f)) { _addToDisplayTotalInterval = 0.08525f * ((float)ConfigManager.totalAddWaitMultiplier.Value / 100f); _scannedValueDisplayed = (int)Mathf.Clamp(Mathf.MoveTowards((float)_scannedValueDisplayed, (float)_scannedValue, (1500f + (float)(_scannedValue * ConfigManager.totalAddWaitMultiplier.Value) / 100f) * Time.deltaTime), 0f, 10000f); ((TMP_Text)hudManager.totalValueText).text = $"${_scannedValueDisplayed}"; if (_scannedValueDisplayed < _scannedValue && _scannedValueDisplayed < 10000) { hudManager.UIAudio.PlayOneShot(hudManager.addToScrapTotalSFX); } else { hudManager.UIAudio.PlayOneShot(hudManager.finishAddingToTotalSFX); } } } } public static class MyPluginInfo { public const string PLUGIN_GUID = "TestAccount666.GoodItemScan"; public const string PLUGIN_NAME = "GoodItemScan"; public const string PLUGIN_VERSION = "2.2.0"; } } namespace GoodItemScan.Patches { [HarmonyPatch(typeof(HUDManager))] public static class HUDManagerPatch { internal static void InitMonoMod() { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Expected O, but got Unknown //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Expected O, but got Unknown //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Expected O, but got Unknown //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0141: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Expected O, but got Unknown //IL_0185: Unknown result type (might be due to invalid IL or missing references) //IL_0194: Unknown result type (might be due to invalid IL or missing references) //IL_0195: Unknown result type (might be due to invalid IL or missing references) //IL_019f: Expected O, but got Unknown GoodItemScan.Hooks.Add(new Hook((MethodBase)AccessTools.Method(typeof(HUDManager), "AssignNodeToUIElement", (Type[])null, (Type[])null), (Delegate)new Action<Action<HUDManager, ScanNodeProperties>, HUDManager, ScanNodeProperties>(DontAssignNodeToUIElement), new HookConfig { Priority = -99 })); GoodItemScan.Hooks.Add(new Hook((MethodBase)AccessTools.Method(typeof(HUDManager), "AssignNewNodes", (Type[])null, (Type[])null), (Delegate)new Action<Action<HUDManager, PlayerControllerB>, HUDManager, PlayerControllerB>(DontAssignNewNodes), new HookConfig { Priority = -99 })); GoodItemScan.Hooks.Add(new Hook((MethodBase)AccessTools.Method(typeof(HUDManager), "MeetsScanNodeRequirements", (Type[])null, (Type[])null), (Delegate)new Func<Func<HUDManager, ScanNodeProperties, PlayerControllerB, bool>, HUDManager, ScanNodeProperties, PlayerControllerB, bool>(MeetsScanNodeRequirements), new HookConfig { Priority = -99 })); GoodItemScan.Hooks.Add(new Hook((MethodBase)AccessTools.Method(typeof(HUDManager), "NodeIsNotVisible", (Type[])null, (Type[])null), (Delegate)new Func<Func<HUDManager, ScanNodeProperties, int, bool>, HUDManager, ScanNodeProperties, int, bool>(NodeIsAlwaysVisible), new HookConfig { Priority = -99 })); GoodItemScan.Hooks.Add(new Hook((MethodBase)AccessTools.Method(typeof(HUDManager), "UpdateScanNodes", (Type[])null, (Type[])null), (Delegate)new Action<Action<HUDManager, PlayerControllerB>, HUDManager, PlayerControllerB>(UpdateScanNodes), new HookConfig { Priority = -99 })); } private static void DontAssignNodeToUIElement(Action<HUDManager, ScanNodeProperties> orig, HUDManager self, ScanNodeProperties node) { } private static void DontAssignNewNodes(Action<HUDManager, PlayerControllerB> orig, HUDManager self, PlayerControllerB playerScript) { } private static bool MeetsScanNodeRequirements(Func<HUDManager, ScanNodeProperties, PlayerControllerB, bool> orig, HUDManager self, ScanNodeProperties node, PlayerControllerB playerScript) { return true; } private static bool NodeIsAlwaysVisible(Func<HUDManager, ScanNodeProperties, int, bool> orig, HUDManager self, ScanNodeProperties node, int elementIndex) { return false; } private static void UpdateScanNodes(Action<HUDManager, PlayerControllerB> orig, HUDManager self, PlayerControllerB playerScript) { GoodItemScan.scanner?.UpdateScanNodes(); } [HarmonyPatch("DisableAllScanElements")] [HarmonyPrefix] private static bool RedirectDisableAllScanElements() { GoodItemScan.scanner?.DisableAllScanElements(); return false; } [HarmonyPatch("PingScan_performed")] [HarmonyPrefix] private static bool PingScanPerformed(ref CallbackContext context) { if (!((CallbackContext)(ref context)).performed) { return false; } HUDManager instance = HUDManager.Instance; if (!Object.op_Implicit((Object)(object)instance)) { return false; } instance.PingHUDElement(instance.Compass, 1f, 0.8f, 0.12f); GoodItemScan.scanner?.Scan(); return false; } [HarmonyPatch("Start")] [HarmonyPostfix] private static void AfterHudManagerAwake(HUDManager __instance) { GoodItemScan.scanner = new Scanner(); GoodItemScan.SetIncreasedMaximumScanNodes(__instance); RegisterHoldScan(); } private static void RegisterHoldScan() { Coroutine pingScanRoutine = null; InputAction val = InputSystem.actions.FindAction("PingScan", false); val.started += delegate { if (pingScanRoutine != null) { ((MonoBehaviour)HUDManager.Instance).StopCoroutine(pingScanRoutine); pingScanRoutine = null; } if (ConfigManager.holdToScan.Value) { pingScanRoutine = ((MonoBehaviour)HUDManager.Instance).StartCoroutine(PingScanRoutine()); } }; val.canceled += delegate { if (pingScanRoutine != null) { ((MonoBehaviour)HUDManager.Instance).StopCoroutine(pingScanRoutine); pingScanRoutine = null; } }; } private static IEnumerator PingScanRoutine() { HUDManager hudManager = HUDManager.Instance; while (true) { yield return (object)new WaitUntil((Func<bool>)(() => hudManager.CanPlayerScan() && (double)hudManager.playerPingingScan <= -1.0)); HUDManager.Instance.PingHUDElement(HUDManager.Instance.Compass, 1f, 0.8f, 0.12f); GoodItemScan.scanner?.Scan(); yield return null; } } [HarmonyPatch("OnDisable")] [HarmonyPostfix] private static void ResetCheatsAPI() { CheatsAPI.additionalEnemyDistance = 0; CheatsAPI.additionalDistance = 0; CheatsAPI.noLineOfSightDistance = 0; } } [HarmonyPatch(typeof(Landmine))] public static class LandminePatch { [HarmonyPatch("Detonate")] [HarmonyPostfix] public static void DisableLandmineScanNode(Landmine __instance) { if (ConfigManager.fixLandmineScanNode.Value) { Transform val = ((Component)__instance).transform.parent.Find("ScanNode"); if (Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)((Component)val).gameObject)) { Object.Destroy((Object)(object)((Component)val).gameObject); } } } } [HarmonyPatch(typeof(PlayerControllerB))] public static class PlayerPatch { [HarmonyPatch("LateUpdate")] [HarmonyPostfix] public static void AfterPlayerLateUpdate(PlayerControllerB __instance) { PlayerControllerB localPlayerController = StartOfRound.Instance.localPlayerController; if (!((Object)(object)__instance != (Object)(object)localPlayerController)) { GoodItemScan.scanner?.LateUpdate(); } } } [HarmonyPatch(typeof(StoryLog))] public class StoryLogPatch { [HarmonyPatch("RemoveLogCollectible")] [HarmonyPostfix] public static void DisableScanNode(StoryLog __instance) { BoxCollider[] componentsInChildren = ((Component)__instance).GetComponentsInChildren<BoxCollider>(); foreach (BoxCollider val in componentsInChildren) { Object.Destroy((Object)(object)((Component)val).gameObject); } } } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class IgnoresAccessChecksToAttribute : Attribute { public IgnoresAccessChecksToAttribute(string assemblyName) { } } }