using System; using System.Collections; 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.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using TMPro; using Unity.Netcode; using UnityEngine; using UnityEngine.InputSystem; 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("ved-gaur.cruiserscan")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.1.0")] [assembly: AssemblyInformationalVersion("1.0.1+dc21fea1f827d4bd9d9b160ebdc8e976036b5ca4")] [assembly: AssemblyProduct("CruiserScan")] [assembly: AssemblyTitle("ved-gaur.cruiserscan")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.1.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.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] [Microsoft.CodeAnalysis.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] [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 CruiserScan { internal static class CruiserHud { [CompilerGenerated] private sealed class d__11 : IEnumerator, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__11(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSeconds(CruiserScan.DisplayDuration.Value); <>1__state = 1; return true; case 1: { <>1__state = -1; GameObject? counterObject = _counterObject; if (counterObject != null) { counterObject.SetActive(false); } _displayCoroutine = null; return false; } } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private const string HudCanvasPath = "/Systems/UI/Canvas/IngamePlayerHUD"; private const string VanillaValueCounterPath = "/Systems/UI/Canvas/IngamePlayerHUD/BottomMiddle/ValueCounter"; private static GameObject? _counterObject; private static TextMeshProUGUI? _text; private static Coroutine? _displayCoroutine; public static void Show(CruiserStats stats) { EnsureCreated(); ApplyPosition(); if (!((Object)(object)_counterObject == (Object)null) && !((Object)(object)_text == (Object)null)) { ((TMP_Text)_text).fontSize = CruiserScan.FontSize.Value; ((TMP_Text)_text).text = $"Cruiser: ${stats.TotalValue} | {stats.ItemCount} items"; _counterObject.SetActive(true); if (_displayCoroutine != null) { ((MonoBehaviour)GameNetworkManager.Instance).StopCoroutine(_displayCoroutine); } _displayCoroutine = ((MonoBehaviour)GameNetworkManager.Instance).StartCoroutine(ValueCoroutine()); } } public static void Hide() { GameObject? counterObject = _counterObject; if (counterObject != null) { counterObject.SetActive(false); } } private static void EnsureCreated() { //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Expected O, but got Unknown if ((Object)(object)_counterObject != (Object)null && (Object)(object)_text != (Object)null) { return; } GameObject val = GameObject.Find("/Systems/UI/Canvas/IngamePlayerHUD"); GameObject val2 = GameObject.Find("/Systems/UI/Canvas/IngamePlayerHUD/BottomMiddle/ValueCounter"); if ((Object)(object)val == (Object)null) { CruiserScan.Logger.LogError((object)"Failed to find IngamePlayerHUD."); return; } if ((Object)(object)val2 == (Object)null) { CruiserScan.Logger.LogError((object)"Failed to find vanilla ValueCounter."); return; } TextMeshProUGUI componentInChildren = val2.GetComponentInChildren(true); if ((Object)(object)componentInChildren == (Object)null) { CruiserScan.Logger.LogError((object)"Failed to find ValueCounter TMP text."); return; } _counterObject = new GameObject("CruiserScanCounter", new Type[1] { typeof(RectTransform) }); _counterObject.transform.SetParent(val.transform, false); _text = _counterObject.AddComponent(); CopyTextStyle(componentInChildren, _text); ConfigureLayout(); ApplyPosition(); _counterObject.SetActive(false); } private static void ConfigureLayout() { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_0091: 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) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: 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_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_counterObject == (Object)null) && !((Object)(object)_text == (Object)null)) { RectTransform component = _counterObject.GetComponent(); component.anchorMin = new Vector2(0f, 1f); component.anchorMax = new Vector2(0f, 1f); component.pivot = new Vector2(0f, 1f); component.sizeDelta = new Vector2(100f, 100f); RectTransform rectTransform = ((TMP_Text)_text).rectTransform; rectTransform.anchorMin = Vector2.zero; rectTransform.anchorMax = Vector2.one; rectTransform.pivot = new Vector2(0.5f, 0.5f); rectTransform.offsetMin = Vector2.zero; rectTransform.offsetMax = Vector2.zero; ((Transform)rectTransform).localPosition = Vector3.zero; ((Transform)rectTransform).localRotation = Quaternion.identity; ((Transform)rectTransform).localScale = Vector3.one; } } private static void CopyTextStyle(TextMeshProUGUI source, TextMeshProUGUI target) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0032: 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) ((TMP_Text)target).font = ((TMP_Text)source).font; ((TMP_Text)target).fontSharedMaterial = ((TMP_Text)source).fontSharedMaterial; ((TMP_Text)target).spriteAsset = ((TMP_Text)source).spriteAsset; ((Graphic)target).color = ((Graphic)source).color; ((TMP_Text)target).outlineColor = ((TMP_Text)source).outlineColor; ((TMP_Text)target).outlineWidth = ((TMP_Text)source).outlineWidth; ((TMP_Text)target).fontStyle = ((TMP_Text)source).fontStyle; ((TMP_Text)target).characterSpacing = ((TMP_Text)source).characterSpacing; ((TMP_Text)target).wordSpacing = ((TMP_Text)source).wordSpacing; ((TMP_Text)target).lineSpacing = ((TMP_Text)source).lineSpacing; ((TMP_Text)target).paragraphSpacing = ((TMP_Text)source).paragraphSpacing; ((TMP_Text)target).enableAutoSizing = false; ((TMP_Text)target).fontSize = CruiserScan.FontSize.Value; ((TMP_Text)target).fontSizeMin = ((TMP_Text)source).fontSizeMin; ((TMP_Text)target).fontSizeMax = ((TMP_Text)source).fontSizeMax; ((TMP_Text)target).alignment = (TextAlignmentOptions)513; ((TMP_Text)target).enableWordWrapping = false; ((TMP_Text)target).overflowMode = (TextOverflowModes)0; ((Graphic)target).raycastTarget = false; } private static void ApplyPosition() { //IL_002e: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_counterObject == (Object)null)) { RectTransform component = _counterObject.GetComponent(); component.anchoredPosition = new Vector2(CruiserScan.OffsetX.Value, CruiserScan.OffsetY.Value); } } [IteratorStateMachine(typeof(d__11))] private static IEnumerator ValueCoroutine() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__11(0); } } internal static class CruiserPersistence { private const string CruiserObjectName = "CompanyCruiser(Clone)"; private const string ShipObjectPath = "Environment/HangarShip"; private static readonly HashSet PersistedShipItems = new HashSet(); public static void MarkCurrentShipItemsAsPersisted() { PersistedShipItems.Clear(); HashSet hashSet = new HashSet(); AddDescendantGrabbables(GameObject.Find("Environment/HangarShip"), hashSet); AddDescendantGrabbables(GameObject.Find("CompanyCruiser(Clone)"), hashSet); foreach (GrabbableObject item in hashSet) { if (!((Object)(object)item.itemProperties == (Object)null) && item.itemProperties.isScrap && !((Object)(object)((NetworkBehaviour)item).NetworkObject == (Object)null) && ((NetworkBehaviour)item).NetworkObject.IsSpawned) { PersistedShipItems.Add(((NetworkBehaviour)item).NetworkObjectId); } } } public static bool IsPersisted(GrabbableObject grabbable) { if ((Object)(object)((NetworkBehaviour)grabbable).NetworkObject == (Object)null || !((NetworkBehaviour)grabbable).NetworkObject.IsSpawned) { return false; } return PersistedShipItems.Contains(((NetworkBehaviour)grabbable).NetworkObjectId); } public static void Clear() { PersistedShipItems.Clear(); } private static void AddDescendantGrabbables(GameObject? root, HashSet foundItems) { if ((Object)(object)root == (Object)null) { return; } GrabbableObject[] componentsInChildren = root.GetComponentsInChildren(true); foreach (GrabbableObject val in componentsInChildren) { if ((Object)(object)val != (Object)null) { foundItems.Add(val); } } } } [HarmonyPatch(typeof(RoundManager))] internal static class RoundManagerPatch { [HarmonyPostfix] [HarmonyPatch("DespawnPropsAtEndOfRound")] private static void AfterDespawnPropsAtEndOfRound() { CruiserPersistence.MarkCurrentShipItemsAsPersisted(); } } [HarmonyPatch(typeof(GameNetworkManager))] internal static class GameNetworkManagerPatch { [HarmonyPostfix] [HarmonyPatch("StartDisconnect")] private static void AfterStartDisconnect() { CruiserPersistence.Clear(); } } [BepInPlugin("ved-gaur.cruiserscan", "CruiserScan", "1.0.1")] public class CruiserScan : BaseUnityPlugin { public static CruiserScan Instance { get; private set; } internal static ManualLogSource Logger { get; private set; } internal static Harmony? Harmony { get; set; } internal static ConfigEntry OffsetX { get; private set; } internal static ConfigEntry OffsetY { get; private set; } internal static ConfigEntry FontSize { get; private set; } internal static ConfigEntry DisplayDuration { get; private set; } internal static ConfigEntry ExcludeKnifeItem { get; private set; } internal static ConfigEntry ExcludeShotgunItem { get; private set; } internal static ConfigEntry ExcludePersistedItems { get; private set; } private void Awake() { Logger = ((BaseUnityPlugin)this).Logger; Instance = this; OffsetX = ((BaseUnityPlugin)this).Config.Bind("Display", "OffsetX", 20f, "Extra horizontal offset from the default position."); OffsetY = ((BaseUnityPlugin)this).Config.Bind("Display", "OffsetY", 50f, "Extra vertical offset from the default position."); FontSize = ((BaseUnityPlugin)this).Config.Bind("Display", "FontSize", 18f, "Font size for the text."); DisplayDuration = ((BaseUnityPlugin)this).Config.Bind("Display", "DisplayDuration", 3f, "How long the text stays visible for after scanning."); ExcludeKnifeItem = ((BaseUnityPlugin)this).Config.Bind("Filtering", "ExcludeKnifeItem", true, "Whether to exclude butcher knife from the scan."); ExcludeShotgunItem = ((BaseUnityPlugin)this).Config.Bind("Filtering", "ExcludeShotgunItem", true, "Whether to exclude shotgun from the scan."); ExcludePersistedItems = ((BaseUnityPlugin)this).Config.Bind("Filtering", "ExcludePersistedItems", true, "Whether to exclude items that were picked up in previous rounds."); Patch(); Logger.LogInfo((object)"ved-gaur.cruiserscan v1.0.1 has loaded!"); } internal static void Patch() { //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_0017: Expected O, but got Unknown if (Harmony == null) { Harmony = new Harmony("ved-gaur.cruiserscan"); } Logger.LogDebug((object)"Patching..."); Harmony.PatchAll(); Logger.LogDebug((object)"Finished patching!"); } internal static void Unpatch() { Logger.LogDebug((object)"Unpatching..."); Harmony? harmony = Harmony; if (harmony != null) { harmony.UnpatchSelf(); } Logger.LogDebug((object)"Finished unpatching!"); } } [HarmonyPatch(typeof(HUDManager))] internal static class HUDManagerPatch { private static FieldInfo? _playerPingingScanField; private static float _pingBeforeScan; private static bool _candidateScanInput; [HarmonyPostfix] [HarmonyPatch("Awake")] private static void OnHudAwake() { _playerPingingScanField = AccessTools.Field(typeof(HUDManager), "playerPingingScan"); if (_playerPingingScanField == null) { CruiserScan.Logger.LogError((object)"Failed to find HUDManager.playerPingingScan."); } } [HarmonyPrefix] [HarmonyPatch("PingScan_performed")] private static void BeforePingScan(HUDManager __instance, in CallbackContext context) { //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) _candidateScanInput = false; _pingBeforeScan = 0f; if (_playerPingingScanField == null || (Object)(object)GameNetworkManager.Instance.localPlayerController == (Object)null) { return; } CallbackContext val = context; if (((CallbackContext)(ref val)).performed) { object value = _playerPingingScanField.GetValue(__instance); if (value is float) { float pingBeforeScan = (float)value; _pingBeforeScan = pingBeforeScan; _candidateScanInput = true; } } } [HarmonyPostfix] [HarmonyPatch("PingScan_performed")] private static void AfterPingScan(HUDManager __instance) { if (!_candidateScanInput || _playerPingingScanField == null) { return; } object value = _playerPingingScanField.GetValue(__instance); if (value is float) { float num = (float)value; if (_pingBeforeScan <= -1f && num > _pingBeforeScan) { CruiserStats stats = CruiserValueCalculator.CalculateStats(); CruiserHud.Show(stats); } } } } internal readonly struct CruiserStats { public int TotalValue { get; } public int ItemCount { get; } public CruiserStats(int totalValue, int itemCount) { TotalValue = totalValue; ItemCount = itemCount; } } internal static class CruiserValueCalculator { private const string CruiserPath = "CompanyCruiser(Clone)"; private const string KitchenKnifeName = "Kitchen knife"; private const string ShotgunName = "Double-barrel"; public static CruiserStats CalculateStats() { GameObject val = GameObject.Find("CompanyCruiser(Clone)"); if ((Object)(object)val == (Object)null) { return new CruiserStats(0, 0); } ScanNodeProperties[] array = (from node in val.GetComponentsInChildren(true).Where(IsCountableGrabbable).Select(GetScanNode) .Where(IsCountableScrapNode) select (node)).ToArray(); int totalValue = array.Sum((ScanNodeProperties node) => node.scrapValue); int itemCount = array.Length; return new CruiserStats(totalValue, itemCount); } private static ScanNodeProperties? GetScanNode(GrabbableObject grabbable) { return ((Component)grabbable).GetComponentInChildren(true); } private static bool IsCountableGrabbable(GrabbableObject grabbable) { if (CruiserScan.ExcludePersistedItems.Value && (grabbable.scrapPersistedThroughRounds || CruiserPersistence.IsPersisted(grabbable))) { return false; } GiftBoxItem val = (GiftBoxItem)(object)((grabbable is GiftBoxItem) ? grabbable : null); if (val != null && val.hasUsedGift) { return false; } return true; } private static bool IsCountableScrapNode(ScanNodeProperties? node) { if ((Object)(object)node == (Object)null) { return false; } if (node.scrapValue <= 0) { return false; } if (CruiserScan.ExcludeKnifeItem.Value && node.headerText == "Kitchen knife") { return false; } if (CruiserScan.ExcludeShotgunItem.Value && node.headerText == "Double-barrel") { return false; } return true; } } public static class MyPluginInfo { public const string PLUGIN_GUID = "ved-gaur.cruiserscan"; public const string PLUGIN_NAME = "CruiserScan"; public const string PLUGIN_VERSION = "1.0.1"; } }