Decompiled source of ShipLootTotal v1.1.2

ShipLootTotal.dll

Decompiled 2 months ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using TMPro;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("ShipLootTotal")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ShipLootTotal")]
[assembly: AssemblyCopyright("Copyright ©  2025")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("03969134-fca5-435b-9dc6-2366b8fb8b9b")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace ShipLootTotal;

[BepInPlugin("DaanSmoki.LethalCompany.ShipLootTotal", "Ship Loot Total", "1.1.2")]
public class Plugin : BaseUnityPlugin
{
	public const string PluginGuid = "DaanSmoki.LethalCompany.ShipLootTotal";

	public const string PluginName = "Ship Loot Total";

	public const string PluginVersion = "1.1.2";

	internal static ManualLogSource Log;

	internal static Harmony Harmony;

	internal static float _lastScanPostfixAt = -999f;

	internal static bool SuppressNextHudSfx = false;

	internal static bool SuppressHudSfxActive = false;

	internal static ConfigEntry<float> PopupDuration;

	private void Awake()
	{
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		//IL_001a: Expected O, but got Unknown
		Log = ((BaseUnityPlugin)this).Logger;
		Harmony = new Harmony("DaanSmoki.LethalCompany.ShipLootTotal");
		PopupDuration = ((BaseUnityPlugin)this).Config.Bind<float>("General", "PopupDuration", 3f, "How long (in seconds) the popup stays visible after scanning.");
		Harmony.PatchAll();
		ScrapValueSyncPatcher.Apply(Harmony);
		Log.LogInfo((object)"Ship Loot Total 1.1.2 loaded.");
	}
}
[HarmonyPatch(typeof(HUDManager))]
public static class Patch_HUD_PingScan
{
	[HarmonyPostfix]
	[HarmonyPatch("PingScan_performed")]
	public static void Postfix(CallbackContext context)
	{
		try
		{
			if (!((CallbackContext)(ref context)).performed || Time.time - Plugin._lastScanPostfixAt < 0.25f)
			{
				return;
			}
			Plugin._lastScanPostfixAt = Time.time;
			object localPlayerController = Utils.GetLocalPlayerController();
			if (localPlayerController != null && Utils.IsPlayerInShip(localPlayerController))
			{
				Utils.InvalidateGrabbablesCache();
				int num = Utils.SumShipScrapValues();
				HUDHelper.ShowStable("Total in Ship: " + num);
				if (Plugin.Log != null)
				{
					Plugin.Log.LogInfo((object)("ShipLootTotal: PingScan -> total=" + num));
				}
			}
		}
		catch (Exception ex)
		{
			if (Plugin.Log != null)
			{
				Plugin.Log.LogError((object)ex);
			}
		}
	}
}
[HarmonyPatch]
public static class Patch_HUD_Display_SilentGate
{
	[CompilerGenerated]
	private sealed class <TargetMethods>d__0 : IEnumerable<MethodBase>, IEnumerable, IEnumerator<MethodBase>, IDisposable, IEnumerator
	{
		private int <>1__state;

		private MethodBase <>2__current;

		private int <>l__initialThreadId;

		MethodBase IEnumerator<MethodBase>.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		object IEnumerator.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		[DebuggerHidden]
		public <TargetMethods>d__0(int <>1__state)
		{
			this.<>1__state = <>1__state;
			<>l__initialThreadId = Environment.CurrentManagedThreadId;
		}

		[DebuggerHidden]
		void IDisposable.Dispose()
		{
			<>1__state = -2;
		}

		private bool MoveNext()
		{
			switch (<>1__state)
			{
			default:
				return false;
			case 0:
			{
				<>1__state = -1;
				Type type = AccessTools.TypeByName("HUDManager");
				if (type == null)
				{
					return false;
				}
				MethodInfo methodInfo = AccessTools.Method(type, "DisplayGlobalNotification", new Type[1] { typeof(string) }, (Type[])null);
				if (methodInfo != null)
				{
					<>2__current = methodInfo;
					<>1__state = 1;
					return true;
				}
				break;
			}
			case 1:
				<>1__state = -1;
				break;
			}
			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();
		}

		[DebuggerHidden]
		IEnumerator<MethodBase> IEnumerable<MethodBase>.GetEnumerator()
		{
			if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId)
			{
				<>1__state = 0;
				return this;
			}
			return new <TargetMethods>d__0(0);
		}

		[DebuggerHidden]
		IEnumerator IEnumerable.GetEnumerator()
		{
			return ((IEnumerable<MethodBase>)this).GetEnumerator();
		}
	}

	[IteratorStateMachine(typeof(<TargetMethods>d__0))]
	private static IEnumerable<MethodBase> TargetMethods()
	{
		//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
		return new <TargetMethods>d__0(-2);
	}

	private static void Prefix()
	{
		Plugin.SuppressHudSfxActive = Plugin.SuppressNextHudSfx;
		Plugin.SuppressNextHudSfx = false;
	}

	private static void Postfix()
	{
		Plugin.SuppressHudSfxActive = false;
	}
}
internal static class HUDHelper
{
	private static Type _hudType;

	private static object _hudInstance;

	private static MethodInfo _miDisplayGlobal;

	public static void ShowStable(string bodyText)
	{
		try
		{
			object hUDManager = GetHUDManager();
			if (hUDManager == null)
			{
				if (Plugin.Log != null)
				{
					Plugin.Log.LogWarning((object)"HUDHelper: HUDManager.Instance not found.");
				}
				return;
			}
			Plugin.SuppressNextHudSfx = true;
			HudHideHelper.PrepareForShow(hUDManager);
			if (_miDisplayGlobal == null || _miDisplayGlobal.DeclaringType == null)
			{
				_miDisplayGlobal = hUDManager.GetType().GetMethod("DisplayGlobalNotification", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(string) }, null);
			}
			if (_miDisplayGlobal != null)
			{
				_miDisplayGlobal.Invoke(hUDManager, new object[1] { bodyText });
				HudHideHelper.HideAfterSeconds((Plugin.PopupDuration != null) ? Plugin.PopupDuration.Value : 3f);
				if (Plugin.Log != null)
				{
					Plugin.Log.LogInfo((object)"HUDHelper: Used DisplayGlobalNotification(string) [silent].");
				}
			}
			else if (Plugin.Log != null)
			{
				Plugin.Log.LogWarning((object)"HUDHelper: DisplayGlobalNotification(string) not found.");
			}
		}
		catch (Exception ex)
		{
			if (Plugin.Log != null)
			{
				Plugin.Log.LogWarning((object)("HUDHelper.ShowStable failed: " + ex.GetType().Name + ": " + ex.Message));
			}
		}
	}

	internal static object GetHUDManager()
	{
		//IL_0077: Unknown result type (might be due to invalid IL or missing references)
		//IL_0082: Expected O, but got Unknown
		//IL_008f: Unknown result type (might be due to invalid IL or missing references)
		//IL_009a: Expected O, but got Unknown
		if (_hudType == null)
		{
			_hudType = AccessTools.TypeByName("HUDManager");
			if (_hudType == null)
			{
				return null;
			}
		}
		PropertyInfo propertyInfo = _hudType.GetProperty("Instance", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic) ?? _hudType.GetProperty("instance", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
		object obj = ((propertyInfo != null) ? propertyInfo.GetValue(null) : null);
		bool flag = _hudInstance is Object && (Object)_hudInstance == (Object)null;
		bool flag2 = obj is Object && (Object)obj == (Object)null;
		if (_hudInstance == null || flag || (!flag2 && _hudInstance != obj))
		{
			_hudInstance = obj;
			HudAudioLocator.Reset();
		}
		return _hudInstance;
	}
}
internal static class HudHideHelper
{
	[CompilerGenerated]
	private sealed class <HideCoroutine>d__5 : IEnumerator<object>, IDisposable, IEnumerator
	{
		private int <>1__state;

		private object <>2__current;

		public float seconds;

		public object hud;

		object IEnumerator<object>.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		object IEnumerator.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		[DebuggerHidden]
		public <HideCoroutine>d__5(int <>1__state)
		{
			this.<>1__state = <>1__state;
		}

		[DebuggerHidden]
		void IDisposable.Dispose()
		{
			<>1__state = -2;
		}

		private bool MoveNext()
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Expected O, but got Unknown
			switch (<>1__state)
			{
			default:
				return false;
			case 0:
				<>1__state = -1;
				<>2__current = (object)new WaitForSeconds(seconds);
				<>1__state = 1;
				return true;
			case 1:
				<>1__state = -1;
				try
				{
					FieldInfo field = hud.GetType().GetField("globalNotificationCoroutine", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					if (field != null)
					{
						object? value = field.GetValue(hud);
						Coroutine val = (Coroutine)((value is Coroutine) ? value : null);
						object obj = hud;
						MonoBehaviour val2 = (MonoBehaviour)((obj is MonoBehaviour) ? obj : null);
						if (val != null && (Object)(object)val2 != (Object)null)
						{
							val2.StopCoroutine(val);
							field.SetValue(hud, null);
						}
					}
					EnsureCachedParts(hud);
					if ((Object)(object)_tmp != (Object)null)
					{
						((TMP_Text)_tmp).text = string.Empty;
					}
					if ((Object)(object)_panelGO != (Object)null)
					{
						CanvasGroup obj2 = _panelGO.GetComponent<CanvasGroup>() ?? _panelGO.AddComponent<CanvasGroup>();
						obj2.alpha = 0f;
						obj2.interactable = false;
						obj2.blocksRaycasts = false;
					}
				}
				catch (Exception ex)
				{
					if (Plugin.Log != null)
					{
						Plugin.Log.LogWarning((object)("HudHideHelper: hide failed: " + ex.Message));
					}
				}
				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 static Coroutine _hideRoutine;

	private static GameObject _panelGO;

	private static TextMeshProUGUI _tmp;

	public static void PrepareForShow(object hud)
	{
		try
		{
			EnsureCachedParts(hud);
			if ((Object)(object)_panelGO != (Object)null)
			{
				if (!_panelGO.activeSelf)
				{
					_panelGO.SetActive(true);
				}
				CanvasGroup obj = _panelGO.GetComponent<CanvasGroup>() ?? _panelGO.AddComponent<CanvasGroup>();
				obj.alpha = 1f;
				obj.interactable = false;
				obj.blocksRaycasts = false;
			}
			if ((Object)(object)_tmp != (Object)null)
			{
				PropertyInfo property = ((object)_tmp).GetType().GetProperty("alpha");
				if (property != null)
				{
					property.SetValue(_tmp, 1f);
				}
			}
		}
		catch
		{
		}
	}

	public static void HideAfterSeconds(float seconds)
	{
		object hUDManager = HUDHelper.GetHUDManager();
		if (hUDManager == null)
		{
			return;
		}
		MonoBehaviour val = (MonoBehaviour)((hUDManager is MonoBehaviour) ? hUDManager : null);
		if (!((Object)(object)val == (Object)null))
		{
			if (_hideRoutine != null)
			{
				val.StopCoroutine(_hideRoutine);
			}
			_hideRoutine = val.StartCoroutine(HideCoroutine(hUDManager, seconds));
		}
	}

	[IteratorStateMachine(typeof(<HideCoroutine>d__5))]
	private static IEnumerator HideCoroutine(object hud, float seconds)
	{
		//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
		return new <HideCoroutine>d__5(0)
		{
			hud = hud,
			seconds = seconds
		};
	}

	private static void EnsureCachedParts(object hud)
	{
		if ((Object)(object)_panelGO != (Object)null && (Object)(object)_tmp != (Object)null)
		{
			return;
		}
		if (_panelGO != null && (Object)(object)_panelGO == (Object)null)
		{
			_panelGO = null;
		}
		if (_tmp != null && (Object)(object)_tmp == (Object)null)
		{
			_tmp = null;
		}
		if ((Object)(object)_panelGO != (Object)null && (Object)(object)_tmp != (Object)null)
		{
			return;
		}
		Type type = hud.GetType();
		if ((Object)(object)_tmp == (Object)null)
		{
			FieldInfo field = type.GetField("globalNotificationText", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			_tmp = (TextMeshProUGUI)((field != null) ? /*isinst with value type is only supported in some contexts*/: null);
		}
		if (!((Object)(object)_panelGO == (Object)null))
		{
			return;
		}
		FieldInfo field2 = type.GetField("globalNotificationBackground", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		object obj = ((field2 != null) ? field2.GetValue(hud) : null);
		GameObject val = (GameObject)((obj is GameObject) ? obj : null);
		if ((Object)(object)val != (Object)null)
		{
			_panelGO = val;
		}
		else
		{
			Component val2 = (Component)((obj is Component) ? obj : null);
			if ((Object)(object)val2 != (Object)null)
			{
				_panelGO = val2.gameObject;
			}
		}
		if ((Object)(object)_panelGO == (Object)null && (Object)(object)_tmp != (Object)null && (Object)(object)((TMP_Text)_tmp).transform != (Object)null)
		{
			Transform parent = ((TMP_Text)_tmp).transform.parent;
			if ((Object)(object)parent != (Object)null)
			{
				_panelGO = ((Component)parent).gameObject;
			}
		}
	}
}
internal static class HudAudioLocator
{
	private static AudioSource _cached;

	private static Type _hudType;

	private static object _hudInstance;

	public static void Reset()
	{
		_cached = null;
		_hudType = null;
		_hudInstance = null;
	}

	public static AudioSource GetHudAudio()
	{
		//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00af: Expected O, but got Unknown
		//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c7: Expected O, but got Unknown
		if (_cached != null && (Object)(object)_cached == (Object)null)
		{
			_cached = null;
		}
		if ((Object)(object)_cached != (Object)null)
		{
			return _cached;
		}
		if (_hudType == null)
		{
			_hudType = AccessTools.TypeByName("HUDManager");
		}
		if (_hudType == null)
		{
			return null;
		}
		PropertyInfo propertyInfo = _hudType.GetProperty("Instance", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic) ?? _hudType.GetProperty("instance", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
		object obj = ((propertyInfo != null) ? propertyInfo.GetValue(null) : null);
		bool flag = _hudInstance is Object && (Object)_hudInstance == (Object)null;
		bool flag2 = obj is Object && (Object)obj == (Object)null;
		if (_hudInstance == null || flag || (!flag2 && _hudInstance != obj))
		{
			_hudInstance = obj;
			_cached = null;
		}
		if (_hudInstance == null)
		{
			return null;
		}
		FieldInfo fieldInfo = _hudType.GetField("UIAudio", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) ?? _hudType.GetField("uiAudio", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		if (fieldInfo != null)
		{
			object? value = fieldInfo.GetValue(_hudInstance);
			_cached = (AudioSource)((value is AudioSource) ? value : null);
		}
		if ((Object)(object)_cached == (Object)null)
		{
			PropertyInfo propertyInfo2 = _hudType.GetProperty("UIAudio", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) ?? _hudType.GetProperty("uiAudio", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (propertyInfo2 != null)
			{
				object? value2 = propertyInfo2.GetValue(_hudInstance);
				_cached = (AudioSource)((value2 is AudioSource) ? value2 : null);
			}
		}
		if ((Object)(object)_cached == (Object)null)
		{
			object hudInstance = _hudInstance;
			Component val = (Component)((hudInstance is Component) ? hudInstance : null);
			if ((Object)(object)val != (Object)null)
			{
				_cached = val.GetComponentInChildren<AudioSource>(true);
			}
		}
		return _cached;
	}
}
[HarmonyPatch(typeof(AudioSource), "PlayOneShot", new Type[] { typeof(AudioClip) })]
public static class Patch_AudioSource_PlayOneShot_1
{
	private static bool Prefix(AudioSource __instance)
	{
		if (!Plugin.SuppressHudSfxActive)
		{
			return true;
		}
		AudioSource hudAudio = HudAudioLocator.GetHudAudio();
		if ((Object)(object)hudAudio != (Object)null && (Object)(object)__instance == (Object)(object)hudAudio)
		{
			return false;
		}
		return true;
	}
}
[HarmonyPatch(typeof(AudioSource), "PlayOneShot", new Type[]
{
	typeof(AudioClip),
	typeof(float)
})]
public static class Patch_AudioSource_PlayOneShot_2
{
	private static bool Prefix(AudioSource __instance)
	{
		if (!Plugin.SuppressHudSfxActive)
		{
			return true;
		}
		AudioSource hudAudio = HudAudioLocator.GetHudAudio();
		if ((Object)(object)hudAudio != (Object)null && (Object)(object)__instance == (Object)(object)hudAudio)
		{
			return false;
		}
		return true;
	}
}
[HarmonyPatch(typeof(HUDManager), "Awake")]
public static class Patch_HUD_Awake_ResetAudioLocator
{
	private static void Postfix()
	{
		HudAudioLocator.Reset();
	}
}
internal static class Utils
{
	private static Type _grabType;

	private static FieldInfo _fi_itemProps;

	private static FieldInfo _fi_scrapValue;

	private static FieldInfo _fi_isInShipRoom;

	private static FieldInfo _fi_isInElevator;

	private static FieldInfo _fi_ip_isScrap;

	private static FieldInfo _fi_ip_scrapValue;

	private static FieldInfo _fi_isHeld;

	private static FieldInfo _fi_isPocketed;

	private static FieldInfo _fi_playerHeldBy;

	private static Type _sorType;

	private static Type _gnmType;

	private static Type _pcbType;

	private static PropertyInfo _pi_SOR_Instance;

	private static FieldInfo _fi_SOR_localPlayerController;

	private static PropertyInfo _pi_SOR_localPlayerController;

	private static PropertyInfo _pi_GNM_Instance;

	private static FieldInfo _fi_GNM_localPlayerController;

	private static PropertyInfo _pi_GNM_localPlayerController;

	private static FieldInfo _fi_PCB_isInHangar;

	private static FieldInfo _fi_PCB_isInShip;

	private static FieldInfo _fi_PCB_isLocal;

	private static FieldInfo _fi_PCB_isOwner;

	private static Object[] _grabbablesCache = (Object[])(object)new Object[0];

	private static float _lastCacheAt = -999f;

	private const float CacheWindowSeconds = 2f;

	private static Bounds _shipBounds;

	private static float _shipBoundsLastBuild = -999f;

	private const float ShipBoundsRebuildSeconds = 3f;

	private const float ShipBoundsPadding = 8f;

	private static readonly string[] _shipNameNeedles = new string[2] { "ship", "hangar" };

	private const int ParentHeuristicMaxDepth = 24;

	public static object GetLocalPlayerController()
	{
		if (_sorType == null)
		{
			_sorType = AccessTools.TypeByName("StartOfRound");
			if (_sorType != null)
			{
				_pi_SOR_Instance = _sorType.GetProperty("Instance", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				_fi_SOR_localPlayerController = _sorType.GetField("localPlayerController", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				_pi_SOR_localPlayerController = _sorType.GetProperty("localPlayerController", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			}
		}
		if (_sorType != null && _pi_SOR_Instance != null)
		{
			object value = _pi_SOR_Instance.GetValue(null);
			if (value != null)
			{
				object obj = ((_fi_SOR_localPlayerController != null) ? _fi_SOR_localPlayerController.GetValue(value) : null);
				if (obj == null && _pi_SOR_localPlayerController != null)
				{
					obj = _pi_SOR_localPlayerController.GetValue(value);
				}
				if (obj != null)
				{
					return obj;
				}
			}
		}
		if (_gnmType == null)
		{
			_gnmType = AccessTools.TypeByName("GameNetworkManager");
			if (_gnmType != null)
			{
				_pi_GNM_Instance = _gnmType.GetProperty("Instance", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				_fi_GNM_localPlayerController = _gnmType.GetField("localPlayerController", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				_pi_GNM_localPlayerController = _gnmType.GetProperty("localPlayerController", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			}
		}
		if (_gnmType != null && _pi_GNM_Instance != null)
		{
			object value2 = _pi_GNM_Instance.GetValue(null);
			if (value2 != null)
			{
				object obj2 = ((_fi_GNM_localPlayerController != null) ? _fi_GNM_localPlayerController.GetValue(value2) : null);
				if (obj2 == null && _pi_GNM_localPlayerController != null)
				{
					obj2 = _pi_GNM_localPlayerController.GetValue(value2);
				}
				if (obj2 != null)
				{
					return obj2;
				}
			}
		}
		return null;
	}

	public static bool IsPlayerInShip(object playerControllerB)
	{
		//IL_016a: Unknown result type (might be due to invalid IL or missing references)
		//IL_016f: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c8: Unknown result type (might be due to invalid IL or missing references)
		//IL_01cd: Unknown result type (might be due to invalid IL or missing references)
		//IL_01dd: Unknown result type (might be due to invalid IL or missing references)
		if (playerControllerB == null)
		{
			return false;
		}
		if (_pcbType == null)
		{
			_pcbType = playerControllerB.GetType();
			_fi_PCB_isInHangar = _pcbType.GetField("isInHangarShipRoom", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			_fi_PCB_isInShip = _pcbType.GetField("isInShipRoom", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			_fi_PCB_isLocal = _pcbType.GetField("isLocalPlayer", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			_fi_PCB_isOwner = _pcbType.GetField("IsOwner", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		}
		bool? flag = ((_fi_PCB_isLocal != null) ? ((bool?)_fi_PCB_isLocal.GetValue(playerControllerB)) : null);
		if (flag.HasValue && !flag.Value)
		{
			return false;
		}
		bool? flag2 = ((_fi_PCB_isOwner != null) ? ((bool?)_fi_PCB_isOwner.GetValue(playerControllerB)) : null);
		if (flag2.HasValue && !flag2.Value)
		{
			return false;
		}
		bool? flag3 = ((_fi_PCB_isInHangar != null) ? ((bool?)_fi_PCB_isInHangar.GetValue(playerControllerB)) : null);
		if (flag3.HasValue && flag3.Value)
		{
			return true;
		}
		bool? flag4 = ((_fi_PCB_isInShip != null) ? ((bool?)_fi_PCB_isInShip.GetValue(playerControllerB)) : null);
		if (flag4.HasValue)
		{
			return flag4.Value;
		}
		Bounds shipBounds = GetShipBounds();
		Transform val = null;
		Component val2 = (Component)((playerControllerB is Component) ? playerControllerB : null);
		if ((Object)(object)val2 != (Object)null)
		{
			val = val2.transform;
		}
		else
		{
			PropertyInfo property = _pcbType.GetProperty("transform");
			if (property != null)
			{
				object? value = property.GetValue(playerControllerB, null);
				val = (Transform)((value is Transform) ? value : null);
			}
		}
		if ((Object)(object)val != (Object)null && ((Bounds)(ref shipBounds)).size != Vector3.zero)
		{
			return ((Bounds)(ref shipBounds)).Contains(val.position);
		}
		return false;
	}

	private static Transform GetShipRootTransform()
	{
		if (_sorType == null)
		{
			return null;
		}
		object obj = ((_pi_SOR_Instance != null) ? _pi_SOR_Instance.GetValue(null) : null);
		if (obj == null)
		{
			return null;
		}
		FieldInfo field = _sorType.GetField("shipRoom", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		if (field != null)
		{
			object? value = field.GetValue(obj);
			GameObject val = (GameObject)((value is GameObject) ? value : null);
			if ((Object)(object)val != (Object)null)
			{
				return val.transform;
			}
		}
		FieldInfo field2 = _sorType.GetField("hangarShip", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		if (field2 != null)
		{
			object? value2 = field2.GetValue(obj);
			GameObject val2 = (GameObject)((value2 is GameObject) ? value2 : null);
			if ((Object)(object)val2 != (Object)null)
			{
				return val2.transform;
			}
		}
		FieldInfo field3 = _sorType.GetField("shipFloor", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		if (field3 != null)
		{
			object? value3 = field3.GetValue(obj);
			GameObject val3 = (GameObject)((value3 is GameObject) ? value3 : null);
			if ((Object)(object)val3 != (Object)null)
			{
				return val3.transform;
			}
		}
		return null;
	}

	private static Bounds GetShipBounds()
	{
		//IL_003d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0017: Unknown result type (might be due to invalid IL or missing references)
		//IL_001c: 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_0028: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
		//IL_00df: Unknown result type (might be due to invalid IL or missing references)
		//IL_006a: Unknown result type (might be due to invalid IL or missing references)
		//IL_006f: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
		//IL_0080: Unknown result type (might be due to invalid IL or missing references)
		if (Time.time - _shipBoundsLastBuild <= 3f && ((Bounds)(ref _shipBounds)).size != Vector3.zero)
		{
			return _shipBounds;
		}
		_shipBoundsLastBuild = Time.time;
		_shipBounds = default(Bounds);
		Transform shipRootTransform = GetShipRootTransform();
		if ((Object)(object)shipRootTransform == (Object)null)
		{
			return _shipBounds;
		}
		Collider[] componentsInChildren = ((Component)shipRootTransform).GetComponentsInChildren<Collider>(true);
		if (componentsInChildren != null && componentsInChildren.Length != 0)
		{
			_shipBounds = componentsInChildren[0].bounds;
			for (int i = 1; i < componentsInChildren.Length; i++)
			{
				((Bounds)(ref _shipBounds)).Encapsulate(componentsInChildren[i].bounds);
			}
			((Bounds)(ref _shipBounds)).Expand(8f);
		}
		if (((Bounds)(ref _shipBounds)).size == Vector3.zero)
		{
			if (Plugin.Log != null)
			{
				Plugin.Log.LogInfo((object)"[ShipLootTotal] Ship bounds empty, scheduling delayed rebuild.");
			}
			new GameObject("ShipBoundsRebuilder").AddComponent<ShipBoundsRebuilder>();
		}
		return _shipBounds;
	}

	private static Object[] GetGrabbables()
	{
		//IL_014f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0154: Unknown result type (might be due to invalid IL or missing references)
		if (_grabType == null)
		{
			_grabType = AccessTools.TypeByName("GrabbableObject");
			if (_grabType != null)
			{
				_fi_itemProps = _grabType.GetField("itemProperties", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				_fi_scrapValue = _grabType.GetField("scrapValue", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				_fi_isInShipRoom = _grabType.GetField("isInShipRoom", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				_fi_isInElevator = _grabType.GetField("isInElevator", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				_fi_isHeld = _grabType.GetField("isHeld", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				_fi_isPocketed = _grabType.GetField("isPocketed", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				_fi_playerHeldBy = _grabType.GetField("playerHeldBy", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			}
		}
		if (_grabType == null)
		{
			return (Object[])(object)new Object[0];
		}
		if (Time.time - _lastCacheAt > 2f || _grabbablesCache == null)
		{
			_lastCacheAt = Time.time;
			Object[] array = Object.FindObjectsOfType(_grabType);
			if (array == null || array.Length == 0)
			{
				Object[] array2 = Resources.FindObjectsOfTypeAll(_grabType);
				if (array2 != null && array2.Length != 0)
				{
					List<Object> list = new List<Object>(array2.Length);
					for (int i = 0; i < array2.Length; i++)
					{
						Object obj = array2[i];
						Component val = (Component)(object)((obj is Component) ? obj : null);
						if (!((Object)(object)val == (Object)null))
						{
							Scene scene = val.gameObject.scene;
							if (((Scene)(ref scene)).IsValid())
							{
								list.Add(array2[i]);
							}
						}
					}
					array = list.ToArray();
				}
			}
			_grabbablesCache = (Object[])((array != null) ? ((Array)array) : ((Array)new Object[0]));
		}
		return _grabbablesCache;
	}

	public static int SumShipScrapValues()
	{
		//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
		//IL_0404: Unknown result type (might be due to invalid IL or missing references)
		//IL_0409: Unknown result type (might be due to invalid IL or missing references)
		//IL_040d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0412: 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_0339: Unknown result type (might be due to invalid IL or missing references)
		//IL_033e: Unknown result type (might be due to invalid IL or missing references)
		//IL_034e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0376: Unknown result type (might be due to invalid IL or missing references)
		//IL_037b: Unknown result type (might be due to invalid IL or missing references)
		//IL_037e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0383: Unknown result type (might be due to invalid IL or missing references)
		//IL_0387: Unknown result type (might be due to invalid IL or missing references)
		//IL_0393: Unknown result type (might be due to invalid IL or missing references)
		//IL_0395: Unknown result type (might be due to invalid IL or missing references)
		Object[] grabbables = GetGrabbables();
		if (grabbables == null || grabbables.Length == 0)
		{
			return 0;
		}
		if (_fi_ip_isScrap == null || _fi_ip_scrapValue == null)
		{
			Object val = null;
			for (int i = 0; i < grabbables.Length; i++)
			{
				if (grabbables[i] != (Object)null)
				{
					val = grabbables[i];
					break;
				}
			}
			if (val != (Object)null && _fi_itemProps != null)
			{
				object value = _fi_itemProps.GetValue(val);
				if (value != null)
				{
					Type type = value.GetType();
					if (_fi_ip_isScrap == null)
					{
						_fi_ip_isScrap = type.GetField("isScrap", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					}
					if (_fi_ip_scrapValue == null)
					{
						_fi_ip_scrapValue = type.GetField("scrapValue", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					}
				}
			}
		}
		int num = 0;
		Bounds shipBounds = GetShipBounds();
		Transform shipRootTransform = GetShipRootTransform();
		foreach (Object val2 in grabbables)
		{
			if (val2 == (Object)null)
			{
				continue;
			}
			Transform val3 = ((((val2 is Component) ? val2 : null) != (Object)null) ? ((Component)val2).transform : null);
			bool flag = false;
			int num2 = 0;
			if (!(_fi_itemProps != null))
			{
				continue;
			}
			object value2 = _fi_itemProps.GetValue(val2);
			if (value2 != null && _fi_ip_isScrap != null)
			{
				object value3 = _fi_ip_isScrap.GetValue(value2);
				if (value3 is bool && (bool)value3)
				{
					flag = true;
				}
			}
			if (!flag)
			{
				continue;
			}
			if (_fi_ip_scrapValue != null)
			{
				object value4 = _fi_ip_scrapValue.GetValue(value2);
				if (value4 is int)
				{
					num2 = Math.Max(num2, (int)value4);
				}
			}
			if (_fi_scrapValue != null)
			{
				object value5 = _fi_scrapValue.GetValue(val2);
				if (value5 is int)
				{
					num2 = Math.Max(num2, (int)value5);
				}
			}
			if (num2 <= 0)
			{
				continue;
			}
			if (_fi_isHeld != null)
			{
				object value6 = _fi_isHeld.GetValue(val2);
				if (value6 is bool && (bool)value6)
				{
					continue;
				}
			}
			if (_fi_isPocketed != null)
			{
				object value7 = _fi_isPocketed.GetValue(val2);
				if (value7 is bool && (bool)value7)
				{
					continue;
				}
			}
			bool flag2 = false;
			if (_fi_isInShipRoom != null)
			{
				object value8 = _fi_isInShipRoom.GetValue(val2);
				if (value8 is bool && (bool)value8)
				{
					flag2 = true;
				}
			}
			if (!flag2 && _fi_isInElevator != null)
			{
				object value9 = _fi_isInElevator.GetValue(val2);
				if (value9 is bool && (bool)value9)
				{
					flag2 = true;
				}
			}
			if (!flag2 && (Object)(object)val3 != (Object)null)
			{
				int num3 = 0;
				Transform val4 = val3;
				while ((Object)(object)val4 != (Object)null && num3 < 24)
				{
					string name = ((Object)val4).name;
					if (!string.IsNullOrEmpty(name))
					{
						string text = name.ToLowerInvariant();
						for (int k = 0; k < _shipNameNeedles.Length; k++)
						{
							if (text.IndexOf(_shipNameNeedles[k], StringComparison.Ordinal) >= 0)
							{
								flag2 = true;
								break;
							}
						}
						if (flag2)
						{
							break;
						}
					}
					val4 = val4.parent;
					num3++;
				}
			}
			if (!flag2 && (Object)(object)val3 != (Object)null && ((Bounds)(ref shipBounds)).size != Vector3.zero && ((Bounds)(ref shipBounds)).Contains(val3.position))
			{
				flag2 = true;
			}
			if (!flag2 && (Object)(object)shipRootTransform != (Object)null && (Object)(object)val3 != (Object)null)
			{
				Vector3 position = val3.position;
				Vector3 position2 = shipRootTransform.position;
				position.y = position2.y;
				if (Vector3.Distance(position, position2) < 30f)
				{
					flag2 = true;
				}
			}
			if (flag2)
			{
				num += num2;
			}
		}
		if (Plugin.Log != null)
		{
			ManualLogSource log = Plugin.Log;
			string[] obj = new string[6]
			{
				"[DEBUG] Total=",
				num.ToString(),
				", Objects=",
				grabbables.Length.ToString(),
				", Bounds=",
				null
			};
			Bounds shipBounds2 = GetShipBounds();
			Vector3 size = ((Bounds)(ref shipBounds2)).size;
			obj[5] = ((object)(Vector3)(ref size)).ToString();
			log.LogInfo((object)string.Concat(obj));
		}
		return num;
	}

	public static void InvalidateGrabbablesCache()
	{
		_grabbablesCache = (Object[])(object)new Object[0];
		_lastCacheAt = -999f;
	}
}
internal static class ScrapValueSyncPatcher
{
	public static void Apply(Harmony harmony)
	{
		//IL_010e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0115: Expected O, but got Unknown
		Type type = AccessTools.TypeByName("GrabbableObject");
		if (type == null)
		{
			if (Plugin.Log != null)
			{
				Plugin.Log.LogWarning((object)"ScrapValueSyncPatcher: GrabbableObject type not found.");
			}
			return;
		}
		BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
		MethodInfo[] methods = type.GetMethods(bindingAttr);
		string[] array = new string[5] { "ClientRpc", "SetScrap", "SyncScrap", "UpdateScrap", "ScrapValue" };
		int num = 0;
		foreach (MethodInfo methodInfo in methods)
		{
			string text = methodInfo.Name.ToLowerInvariant();
			if (text.IndexOf("scrap", StringComparison.Ordinal) < 0)
			{
				continue;
			}
			ParameterInfo[] parameters = methodInfo.GetParameters();
			if (parameters.Length == 0 || parameters[0].ParameterType != typeof(int))
			{
				continue;
			}
			bool flag = false;
			for (int j = 0; j < array.Length; j++)
			{
				if (text.IndexOf(array[j].ToLowerInvariant(), StringComparison.Ordinal) >= 0)
				{
					flag = true;
					break;
				}
			}
			if (!flag)
			{
				continue;
			}
			try
			{
				HarmonyMethod val = new HarmonyMethod(typeof(ScrapValueSyncPatcher).GetMethod("ScrapValuePostfix", BindingFlags.Static | BindingFlags.NonPublic));
				harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				num++;
			}
			catch (Exception ex)
			{
				if (Plugin.Log != null)
				{
					Plugin.Log.LogWarning((object)("ScrapValueSyncPatcher: failed to patch " + methodInfo.Name + " : " + ex.Message));
				}
			}
		}
		if (Plugin.Log != null)
		{
			Plugin.Log.LogInfo((object)("ScrapValueSyncPatcher: patched " + num + " scrap sync method(s)."));
		}
	}

	private static void ScrapValuePostfix(object __instance, object[] __args)
	{
		try
		{
			if (__instance == null || __args == null || __args.Length == 0)
			{
				return;
			}
			object obj = __args[0];
			if (obj is int)
			{
				int num = (int)obj;
				FieldInfo field = __instance.GetType().GetField("scrapValue", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (field != null)
				{
					field.SetValue(__instance, num);
					Utils.InvalidateGrabbablesCache();
				}
			}
		}
		catch
		{
		}
	}
}
public class ShipBoundsRebuilder : MonoBehaviour
{
	[CompilerGenerated]
	private sealed class <Start>d__0 : IEnumerator<object>, IDisposable, IEnumerator
	{
		private int <>1__state;

		private object <>2__current;

		public ShipBoundsRebuilder <>4__this;

		object IEnumerator<object>.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		object IEnumerator.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		[DebuggerHidden]
		public <Start>d__0(int <>1__state)
		{
			this.<>1__state = <>1__state;
		}

		[DebuggerHidden]
		void IDisposable.Dispose()
		{
			<>1__state = -2;
		}

		private bool MoveNext()
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Expected O, but got Unknown
			int num = <>1__state;
			ShipBoundsRebuilder shipBoundsRebuilder = <>4__this;
			switch (num)
			{
			default:
				return false;
			case 0:
				<>1__state = -1;
				<>2__current = (object)new WaitForSeconds(5f);
				<>1__state = 1;
				return true;
			case 1:
			{
				<>1__state = -1;
				Utils.InvalidateGrabbablesCache();
				object obj = typeof(Utils).GetMethod("GetShipBounds", BindingFlags.Static | BindingFlags.NonPublic).Invoke(null, null);
				if (Plugin.Log != null)
				{
					Plugin.Log.LogInfo((object)("[ShipLootTotal] Delayed ship bounds rebuilt: " + obj));
				}
				Object.Destroy((Object)(object)((Component)shipBoundsRebuilder).gameObject);
				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();
		}
	}

	[IteratorStateMachine(typeof(<Start>d__0))]
	private IEnumerator Start()
	{
		//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
		return new <Start>d__0(0)
		{
			<>4__this = this
		};
	}
}
[HarmonyPatch(typeof(StartOfRound), "SyncAlreadyHeldObjectsClientRpc")]
public static class Patch_SOR_AfterHeldSync
{
	private static void Postfix()
	{
		Plugin._lastScanPostfixAt = -999f;
	}
}