Decompiled source of SharedUpgradesHelper v1.1.0

SharedUpgradesHelper.dll

Decompiled a week ago
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.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: IgnoresAccessChecksTo("")]
[assembly: AssemblyCompany("Omniscye")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("SharedUpgradesHelper")]
[assembly: AssemblyTitle("SharedUpgradesHelper")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.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 SharedUpgradesHelper
{
	[BepInPlugin("Omniscye.SharedUpgradesHelper", "SharedUpgradesHelper", "1.0")]
	public class SharedUpgradesHelper : BaseUnityPlugin
	{
		internal static SharedUpgradesHelper Instance { get; private set; }

		internal static ManualLogSource Logger => Instance._logger;

		private ManualLogSource _logger => ((BaseUnityPlugin)this).Logger;

		internal Harmony? Harmony { get; set; }

		private void Awake()
		{
			Instance = this;
			((Component)this).gameObject.transform.parent = null;
			((Object)((Component)this).gameObject).hideFlags = (HideFlags)61;
			Patch();
			Logger.LogInfo((object)$"{((BaseUnityPlugin)this).Info.Metadata.GUID} v{((BaseUnityPlugin)this).Info.Metadata.Version} has loaded!");
		}

		internal void Patch()
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Expected O, but got Unknown
			//IL_0026: Expected O, but got Unknown
			if (Harmony == null)
			{
				Harmony val = new Harmony(((BaseUnityPlugin)this).Info.Metadata.GUID);
				Harmony val2 = val;
				Harmony = val;
			}
			Harmony.PatchAll();
		}

		internal void Unpatch()
		{
			Harmony? harmony = Harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}

		private void Update()
		{
		}
	}
}
namespace RepoMods.AutoHostSharedUpgrade
{
	[BepInPlugin("repo.autohost.sharedupgrades", "AutoHost Shared Upgrades", "4.1.2")]
	public class AutoHostSharedUpgradePlugin : BaseUnityPlugin
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static LogCallback <0>__OnLogMessage;
		}

		[CompilerGenerated]
		private sealed class <LobbyDestroyerCoroutine>d__16 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public AutoHostSharedUpgradePlugin <>4__this;

			private WaitForSeconds <wait>5__1;

			private int <destroyed>5__2;

			private Exception <e>5__3;

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

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

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

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<wait>5__1 = null;
				<e>5__3 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0026: Unknown result type (might be due to invalid IL or missing references)
				//IL_0030: Expected O, but got Unknown
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<wait>5__1 = new WaitForSeconds(2f);
					break;
				case 1:
					<>1__state = -1;
					if (!SharedUpgradesDetected || !InLobbyLevel || !LobbyDestroyArmed || Time.time - LobbyEnterTime < 0.5f)
					{
						break;
					}
					try
					{
						<destroyed>5__2 = DestroyAllUpgradesInScene();
						if (<destroyed>5__2 > 0)
						{
							TotalDestroyed += <destroyed>5__2;
							ManualLogSource logS = LogS;
							if (logS != null)
							{
								logS.LogInfo((object)$"\ud83d\udc80 Nuked {<destroyed>5__2} upgrade(s) in Lobby (session total: {TotalDestroyed})");
							}
						}
					}
					catch (Exception ex)
					{
						<e>5__3 = ex;
						ManualLogSource logS2 = LogS;
						if (logS2 != null)
						{
							logS2.LogError((object)("Upgrade destroyer error: " + <e>5__3.Message));
						}
					}
					break;
				}
				<>2__current = <wait>5__1;
				<>1__state = 1;
				return true;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		public const string PluginGuid = "repo.autohost.sharedupgrades";

		public const string PluginName = "AutoHost Shared Upgrades";

		public const string PluginVersion = "4.1.2";

		internal static ManualLogSource LogS;

		internal static Harmony HarmonyInstance;

		internal static bool SharedUpgradesDetected;

		internal static bool InLobbyLevel;

		internal static bool ShopSeenThisRun;

		internal static bool LobbyDestroyArmed;

		internal static float LobbyEnterTime;

		internal static int TotalDestroyed;

		private const float DestroyTickSeconds = 2f;

		private const float PostLobbyGrace = 0.5f;

		private void Awake()
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Expected O, but got Unknown
			LogS = ((BaseUnityPlugin)this).Logger;
			HarmonyInstance = new Harmony("repo.autohost.sharedupgrades");
			object obj = <>O.<0>__OnLogMessage;
			if (obj == null)
			{
				LogCallback val = OnLogMessage;
				<>O.<0>__OnLogMessage = val;
				obj = (object)val;
			}
			Application.logMessageReceived += (LogCallback)obj;
			TryProbeForSharedUpgradesTypes();
			HarmonyInstance.PatchAll(Assembly.GetExecutingAssembly());
			LogS.LogInfo((object)string.Format("{0} {1} loaded. SharedUpgradesDetected={2}", "AutoHost Shared Upgrades", "4.1.2", SharedUpgradesDetected));
			((MonoBehaviour)this).StartCoroutine(LobbyDestroyerCoroutine());
		}

		private void OnDestroy()
		{
			//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)
			//IL_001c: Expected O, but got Unknown
			object obj = <>O.<0>__OnLogMessage;
			if (obj == null)
			{
				LogCallback val = OnLogMessage;
				<>O.<0>__OnLogMessage = val;
				obj = (object)val;
			}
			Application.logMessageReceived -= (LogCallback)obj;
			try
			{
				Harmony harmonyInstance = HarmonyInstance;
				if (harmonyInstance != null)
				{
					harmonyInstance.UnpatchSelf();
				}
			}
			catch
			{
			}
		}

		private static void OnLogMessage(string condition, string stackTrace, LogType type)
		{
			if (string.IsNullOrEmpty(condition))
			{
				return;
			}
			string text = condition.ToLowerInvariant();
			if (!SharedUpgradesDetected && (text.Contains("sharedupgrades") || text.Contains("shared upgrade")))
			{
				SharedUpgradesDetected = true;
				ManualLogSource logS = LogS;
				if (logS != null)
				{
					logS.LogInfo((object)"SharedUpgrades detected via console log message.");
				}
			}
			if (text.Contains("level - shop") || text.Contains("level-shop"))
			{
				ShopSeenThisRun = true;
				InLobbyLevel = false;
				LobbyDestroyArmed = false;
				TotalDestroyed = 0;
				ManualLogSource logS2 = LogS;
				if (logS2 != null)
				{
					logS2.LogInfo((object)"SHOP DETECTED. Will arm destroyer when we reach Lobby.");
				}
			}
			else if (text.Contains("level - lobby") || text.Contains("level-lobby"))
			{
				InLobbyLevel = true;
				LobbyEnterTime = Time.time;
				LobbyDestroyArmed = ShopSeenThisRun;
				TotalDestroyed = 0;
				if (LobbyDestroyArmed)
				{
					ManualLogSource logS3 = LogS;
					if (logS3 != null)
					{
						logS3.LogInfo((object)"LOBBY DETECTED after SHOP. Upgrade destroyer ARMED (2s intervals). \ud83d\udc80");
					}
				}
				else
				{
					ManualLogSource logS4 = LogS;
					if (logS4 != null)
					{
						logS4.LogInfo((object)"LOBBY DETECTED (no shop this run) — destroyer NOT armed.");
					}
				}
			}
			else
			{
				if (!text.Contains("level-") && !text.Contains("level - "))
				{
					return;
				}
				if (InLobbyLevel || LobbyDestroyArmed)
				{
					ManualLogSource logS5 = LogS;
					if (logS5 != null)
					{
						logS5.LogInfo((object)$"Left Lobby — destroyer disarmed. Total destroyed this session: {TotalDestroyed}");
					}
					TotalDestroyed = 0;
				}
				InLobbyLevel = false;
				LobbyDestroyArmed = false;
			}
		}

		[IteratorStateMachine(typeof(<LobbyDestroyerCoroutine>d__16))]
		private IEnumerator LobbyDestroyerCoroutine()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <LobbyDestroyerCoroutine>d__16(0)
			{
				<>4__this = this
			};
		}

		private static int DestroyAllUpgradesInScene()
		{
			return DestroyUpgradesByItemAttributes();
		}

		private static int DestroyUpgradesByItemAttributes()
		{
			int num = 0;
			Type type = AccessTools.TypeByName("ItemAttributes");
			if (type == null)
			{
				return 0;
			}
			Object[] array = Object.FindObjectsOfType(type);
			if (array == null || array.Length == 0)
			{
				return 0;
			}
			Object[] array2 = array;
			foreach (Object val in array2)
			{
				Component val2 = (Component)(object)((val is Component) ? val : null);
				if ((Object)(object)val2 == (Object)null || (Object)(object)val2.gameObject == (Object)null || !IsUpgradeType(val2))
				{
					continue;
				}
				string itemName = GetItemName(val2);
				try
				{
					ZeroPurchasedUpgradeStat(itemName);
				}
				catch
				{
				}
				try
				{
					Object.DestroyImmediate((Object)(object)val2.gameObject);
					num++;
					ManualLogSource logS = LogS;
					if (logS != null)
					{
						logS.LogInfo((object)("\ud83d\udc80 NUKED upgrade '" + itemName + "' from Lobby!"));
					}
				}
				catch (Exception ex)
				{
					ManualLogSource logS2 = LogS;
					if (logS2 != null)
					{
						logS2.LogWarning((object)("Failed to destroy upgrade '" + itemName + "': " + ex.Message));
					}
				}
			}
			return num;
		}

		private static int DestroyUpgradesByName()
		{
			int num = 0;
			string[] source = new string[6] { "upgrade", "Upgrade", "UPGRADE", "item_upgrade", "Item_Upgrade", "SharedUpgrade" };
			GameObject[] array = Object.FindObjectsOfType<GameObject>();
			GameObject[] array2 = array;
			foreach (GameObject val in array2)
			{
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				string goName = ((Object)val).name.ToLowerInvariant();
				if (!source.Any((string p) => goName.Contains(p.ToLowerInvariant())))
				{
					continue;
				}
				Component component = val.GetComponent(AccessTools.TypeByName("ItemAttributes"));
				if (!((Object)(object)component != (Object)null) || !IsUpgradeType(component))
				{
					continue;
				}
				try
				{
					ZeroPurchasedUpgradeStat(GetItemName(component));
				}
				catch
				{
				}
				try
				{
					Object.DestroyImmediate((Object)(object)val);
					num++;
					ManualLogSource logS = LogS;
					if (logS != null)
					{
						logS.LogInfo((object)("DESTROYED upgrade by name '" + ((Object)val).name + "' in Lobby! \ud83d\udc80\ud83d\udd0d"));
					}
				}
				catch
				{
					try
					{
						Object.Destroy((Object)(object)val);
						num++;
					}
					catch
					{
					}
				}
			}
			return num;
		}

		private static int DestroyUpgradesByTag()
		{
			int num = 0;
			string[] array = new string[4] { "Upgrade", "Item", "Pickup", "Purchasable" };
			string[] array2 = array;
			foreach (string text in array2)
			{
				try
				{
					GameObject[] array3 = GameObject.FindGameObjectsWithTag(text);
					GameObject[] array4 = array3;
					foreach (GameObject val in array4)
					{
						if ((Object)(object)val == (Object)null)
						{
							continue;
						}
						Component component = val.GetComponent(AccessTools.TypeByName("ItemAttributes"));
						if (!((Object)(object)component != (Object)null) || !IsUpgradeType(component))
						{
							continue;
						}
						try
						{
							ZeroPurchasedUpgradeStat(GetItemName(component));
						}
						catch
						{
						}
						try
						{
							Object.DestroyImmediate((Object)(object)val);
							num++;
							ManualLogSource logS = LogS;
							if (logS != null)
							{
								logS.LogInfo((object)("DESTROYED upgrade by tag '" + text + "' in Lobby! \ud83d\udc80\ud83c\udff7\ufe0f"));
							}
						}
						catch
						{
							try
							{
								Object.Destroy((Object)(object)val);
								num++;
							}
							catch
							{
							}
						}
					}
				}
				catch
				{
				}
			}
			return num;
		}

		private static string GetItemName(Component itemAttributes)
		{
			try
			{
				object obj = AccessTools.Field(((object)itemAttributes).GetType(), "item")?.GetValue(itemAttributes);
				if (obj != null)
				{
					return AccessTools.Field(obj.GetType(), "itemAssetName")?.GetValue(obj)?.ToString() ?? "Unknown";
				}
			}
			catch
			{
			}
			return "Unknown";
		}

		private static void ZeroPurchasedUpgradeStat(string itemAssetName)
		{
			if (string.IsNullOrEmpty(itemAssetName))
			{
				return;
			}
			try
			{
				Type type = AccessTools.TypeByName("StatsManager");
				if (type == null)
				{
					return;
				}
				object obj = AccessTools.Field(type, "instance")?.GetValue(null);
				if (obj != null && AccessTools.Field(type, "itemsPurchased")?.GetValue(obj) is IDictionary dictionary)
				{
					if (!dictionary.Contains(itemAssetName))
					{
						dictionary.Add(itemAssetName, 0);
					}
					else
					{
						dictionary[itemAssetName] = 0;
					}
					ManualLogSource logS = LogS;
					if (logS != null)
					{
						logS.LogInfo((object)("AutoHost: zeroed itemsPurchased for '" + itemAssetName + "' (prevents next-level respawn, no KeyNotFound)."));
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource logS2 = LogS;
				if (logS2 != null)
				{
					logS2.LogWarning((object)("AutoHost: ZeroPurchasedUpgradeStat('" + itemAssetName + "') failed: " + ex.Message));
				}
			}
		}

		private static void TryProbeForSharedUpgradesTypes()
		{
			try
			{
				Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
				foreach (Assembly assembly in assemblies)
				{
					string name = assembly.GetName().Name;
					if (!string.IsNullOrEmpty(name) && (name.IndexOf("SharedUpgrades", StringComparison.OrdinalIgnoreCase) >= 0 || name.IndexOf("Shared Upgrade", StringComparison.OrdinalIgnoreCase) >= 0))
					{
						SharedUpgradesDetected = true;
						ManualLogSource logS = LogS;
						if (logS != null)
						{
							logS.LogInfo((object)("SharedUpgrades detected via assembly name: " + name));
						}
						break;
					}
					foreach (Type item in assembly.GetTypesSafe())
					{
						string text = item.FullName ?? item.Name;
						if (text.IndexOf("SharedUpgrades", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("Shared Upgrade", StringComparison.OrdinalIgnoreCase) >= 0)
						{
							SharedUpgradesDetected = true;
							ManualLogSource logS2 = LogS;
							if (logS2 != null)
							{
								logS2.LogInfo((object)("SharedUpgrades detected via type: " + text));
							}
							return;
						}
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource logS3 = LogS;
				if (logS3 != null)
				{
					logS3.LogDebug((object)("Probe for SharedUpgrades types failed: " + ex.Message));
				}
			}
		}

		internal static bool ShouldAutoApply()
		{
			if (!SharedUpgradesDetected)
			{
				return false;
			}
			try
			{
				Type type = AccessTools.TypeByName("SemiFunc");
				MethodInfo methodInfo = AccessTools.Method(type, "IsMasterClientOrSingleplayer", (Type[])null, (Type[])null);
				if (type != null && methodInfo != null)
				{
					return (bool)methodInfo.Invoke(null, null);
				}
			}
			catch
			{
			}
			return true;
		}

		internal static void TryAutoUseUpgrade(Component itemAttributes)
		{
			if ((Object)(object)itemAttributes == (Object)null)
			{
				return;
			}
			GameObject gameObject = itemAttributes.gameObject;
			if ((Object)(object)gameObject == (Object)null || !IsUpgradeType(itemAttributes))
			{
				return;
			}
			if (!DeductMoneyForUpgrade(itemAttributes))
			{
				ManualLogSource logS = LogS;
				if (logS != null)
				{
					logS.LogWarning((object)"AutoHost: Cannot afford upgrade, skipping auto-apply");
				}
				return;
			}
			Type type = AccessTools.TypeByName("ItemToggle");
			Component val = ((type != null) ? gameObject.GetComponent(type) : null);
			int num = -1;
			if ((Object)(object)val != (Object)null)
			{
				try
				{
					Type type2 = AccessTools.TypeByName("SemiFunc");
					MethodInfo methodInfo = AccessTools.Method(type2, "PhotonViewIDPlayerAvatarLocal", (Type[])null, (Type[])null);
					if (methodInfo != null)
					{
						num = (int)methodInfo.Invoke(null, null);
					}
					AccessTools.Field(type, "playerTogglePhotonID")?.SetValue(val, num);
					ManualLogSource logS2 = LogS;
					if (logS2 != null)
					{
						logS2.LogInfo((object)$"AutoHost: set ItemToggle.playerTogglePhotonID={num}");
					}
				}
				catch (Exception ex)
				{
					ManualLogSource logS3 = LogS;
					if (logS3 != null)
					{
						logS3.LogWarning((object)("AutoHost: set photonID failed: " + ex.Message));
					}
				}
			}
			if ((Object)(object)val != (Object)null)
			{
				string[] array = new string[6] { "RPC_UseToggle", "Use", "UseItem", "ToggleUse", "Activate", "Consume" };
				string[] array2 = array;
				foreach (string text in array2)
				{
					MethodInfo method = type.GetMethod(text, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(int) }, null);
					MethodInfo method2 = type.GetMethod(text, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null);
					try
					{
						if (method != null && num != -1)
						{
							method.Invoke(val, new object[1] { num });
							ManualLogSource logS4 = LogS;
							if (logS4 != null)
							{
								logS4.LogInfo((object)("AutoHost: ItemToggle." + text + "(int) -> OK"));
							}
							ScrubUpgradeFromDelivery(itemAttributes);
							try
							{
								ZeroPurchasedUpgradeStat(GetItemName(itemAttributes));
								return;
							}
							catch
							{
								return;
							}
						}
						if (method2 != null)
						{
							method2.Invoke(val, null);
							ManualLogSource logS5 = LogS;
							if (logS5 != null)
							{
								logS5.LogInfo((object)("AutoHost: ItemToggle." + text + "() -> OK"));
							}
							ScrubUpgradeFromDelivery(itemAttributes);
							try
							{
								ZeroPurchasedUpgradeStat(GetItemName(itemAttributes));
								return;
							}
							catch
							{
								return;
							}
						}
					}
					catch (Exception ex2)
					{
						ManualLogSource logS6 = LogS;
						if (logS6 != null)
						{
							logS6.LogWarning((object)("AutoHost: ItemToggle." + text + " failed: " + ex2.Message));
						}
					}
				}
			}
			int num2 = 0;
			Component[] components = gameObject.GetComponents<Component>();
			foreach (Component val2 in components)
			{
				if ((Object)(object)val2 == (Object)null)
				{
					continue;
				}
				Type type3 = ((object)val2).GetType();
				if (!type3.Name.StartsWith("ItemUpgrade", StringComparison.Ordinal))
				{
					continue;
				}
				try
				{
					if ((Object)(object)val != (Object)null)
					{
						FieldInfo fieldInfo = AccessTools.Field(type3, "itemToggle");
						if (fieldInfo != null && fieldInfo.GetValue(val2) == null)
						{
							fieldInfo.SetValue(val2, val);
						}
					}
				}
				catch
				{
				}
				MethodInfo method3 = type3.GetMethod("Upgrade", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null);
				if (method3 == null)
				{
					continue;
				}
				try
				{
					method3.Invoke(val2, null);
					ManualLogSource logS7 = LogS;
					if (logS7 != null)
					{
						logS7.LogInfo((object)("AutoHost: " + type3.Name + ".Upgrade() -> OK"));
					}
					num2++;
				}
				catch (Exception ex3)
				{
					ManualLogSource logS8 = LogS;
					if (logS8 != null)
					{
						logS8.LogWarning((object)("AutoHost: " + type3.Name + ".Upgrade() threw: " + ex3.Message));
					}
				}
			}
			if (num2 == 0)
			{
				ManualLogSource logS9 = LogS;
				if (logS9 != null)
				{
					logS9.LogWarning((object)"AutoHost: No ItemUpgrade* components found to apply.");
				}
				return;
			}
			ScrubUpgradeFromDelivery(itemAttributes);
			try
			{
				ZeroPurchasedUpgradeStat(GetItemName(itemAttributes));
			}
			catch
			{
			}
		}

		private static bool DeductMoneyForUpgrade(Component itemAttributes)
		{
			try
			{
				FieldInfo fieldInfo = AccessTools.Field(((object)itemAttributes).GetType(), "value");
				if (fieldInfo == null)
				{
					return false;
				}
				int num = (int)fieldInfo.GetValue(itemAttributes);
				Type type = AccessTools.TypeByName("SemiFunc");
				MethodInfo methodInfo = AccessTools.Method(type, "StatGetRunCurrency", (Type[])null, (Type[])null);
				MethodInfo methodInfo2 = AccessTools.Method(type, "StatSetRunCurrency", (Type[])null, (Type[])null);
				if (methodInfo == null || methodInfo2 == null)
				{
					return false;
				}
				int num2 = (int)methodInfo.Invoke(null, null);
				if (num2 < num)
				{
					ManualLogSource logS = LogS;
					if (logS != null)
					{
						logS.LogWarning((object)$"AutoHost: Not enough currency ({num2}) for item cost ({num})");
					}
					return false;
				}
				int num3 = num2 - num;
				methodInfo2.Invoke(null, new object[1] { num3 });
				ManualLogSource logS2 = LogS;
				if (logS2 != null)
				{
					logS2.LogInfo((object)$"AutoHost: Deducted ${num} from currency ({num2} -> {num3})");
				}
				try
				{
					Type type2 = AccessTools.TypeByName("StatsManager");
					object obj = AccessTools.Field(type2, "instance")?.GetValue(null);
					if (obj != null)
					{
						object obj2 = AccessTools.Field(((object)itemAttributes).GetType(), "item")?.GetValue(itemAttributes);
						if (obj2 != null)
						{
							string text = AccessTools.Field(obj2.GetType(), "itemAssetName")?.GetValue(obj2)?.ToString();
							if (!string.IsNullOrEmpty(text))
							{
								AccessTools.Method(type2, "ItemPurchase", (Type[])null, (Type[])null)?.Invoke(obj, new object[1] { text });
								AccessTools.Method(type2, "AddItemsUpgradesPurchased", (Type[])null, (Type[])null)?.Invoke(obj, new object[1] { text });
								ManualLogSource logS3 = LogS;
								if (logS3 != null)
								{
									logS3.LogInfo((object)("AutoHost: Updated stats for purchase: " + text));
								}
							}
						}
					}
				}
				catch (Exception ex)
				{
					ManualLogSource logS4 = LogS;
					if (logS4 != null)
					{
						logS4.LogWarning((object)("AutoHost: Stats update failed: " + ex.Message));
					}
				}
				return true;
			}
			catch (Exception ex2)
			{
				ManualLogSource logS5 = LogS;
				if (logS5 != null)
				{
					logS5.LogError((object)("AutoHost: Money deduction failed: " + ex2.Message));
				}
				return false;
			}
		}

		private static void ScrubUpgradeFromDelivery(Component itemAttributes)
		{
			try
			{
				Type type = AccessTools.TypeByName("ShopManager");
				object value = AccessTools.Field(type, "instance").GetValue(null);
				if (value == null)
				{
					return;
				}
				FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				int num = 0;
				object obj = null;
				try
				{
					obj = AccessTools.Field(((object)itemAttributes).GetType(), "item")?.GetValue(itemAttributes);
				}
				catch
				{
				}
				FieldInfo[] array = fields;
				foreach (FieldInfo fieldInfo in array)
				{
					Type fieldType = fieldInfo.FieldType;
					if (!typeof(IList).IsAssignableFrom(fieldType))
					{
						continue;
					}
					IList list = (IList)fieldInfo.GetValue(value);
					if (list == null || list.Count == 0)
					{
						continue;
					}
					List<int> list2 = new List<int>();
					for (int j = 0; j < list.Count; j++)
					{
						object obj3 = list[j];
						if (obj3 == null)
						{
							continue;
						}
						bool flag = false;
						if (obj3 == itemAttributes)
						{
							flag = true;
						}
						else
						{
							try
							{
								Type type2 = obj3.GetType();
								object obj4 = AccessTools.Field(type2, "item")?.GetValue(obj3);
								if (obj4 != null && obj != null && obj4 == obj)
								{
									flag = true;
								}
							}
							catch
							{
							}
						}
						if (flag)
						{
							list2.Add(j);
						}
					}
					for (int num2 = list2.Count - 1; num2 >= 0; num2--)
					{
						list.RemoveAt(list2[num2]);
						num++;
					}
				}
				if (num > 0)
				{
					ManualLogSource logS = LogS;
					if (logS != null)
					{
						logS.LogInfo((object)$"AutoHost: scrubbed upgrade from delivery lists (removed {num}).");
					}
				}
				else
				{
					ManualLogSource logS2 = LogS;
					if (logS2 != null)
					{
						logS2.LogDebug((object)"AutoHost: no delivery entries to scrub (likely already cleaned by base game).");
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource logS3 = LogS;
				if (logS3 != null)
				{
					logS3.LogWarning((object)("AutoHost: ScrubUpgradeFromDelivery failed: " + ex.Message));
				}
			}
		}

		private static bool IsUpgradeType(Component itemAttributes)
		{
			try
			{
				object obj = AccessTools.Field(((object)itemAttributes).GetType(), "item")?.GetValue(itemAttributes);
				if (obj == null)
				{
					return false;
				}
				FieldInfo fieldInfo = AccessTools.Field(obj.GetType(), "itemType");
				if (fieldInfo == null)
				{
					return false;
				}
				string a = fieldInfo.GetValue(obj)?.ToString();
				return string.Equals(a, "item_upgrade", StringComparison.Ordinal);
			}
			catch
			{
				return false;
			}
		}
	}
	internal static class ReflectionSafe
	{
		public static IEnumerable<Type> GetTypesSafe(this Assembly asm)
		{
			try
			{
				return asm.GetTypes();
			}
			catch
			{
				return Enumerable.Empty<Type>();
			}
		}
	}
	[HarmonyPatch]
	internal static class Patch_DestroyFirst
	{
		private static MethodBase TargetMethod()
		{
			Type type = AccessTools.TypeByName("ExtractionPoint");
			return AccessTools.Method(type, "DestroyTheFirstPhysObjectsInShopList", (Type[])null, (Type[])null);
		}

		private static void Prefix()
		{
			if (!AutoHostSharedUpgradePlugin.ShouldAutoApply())
			{
				return;
			}
			try
			{
				Type type = AccessTools.TypeByName("ShopManager");
				object value = AccessTools.Field(type, "instance").GetValue(null);
				IList<Component> list = (IList<Component>)AccessTools.Field(type, "shoppingList").GetValue(value);
				if (list != null && list.Count != 0)
				{
					Component val = list[0];
					FieldInfo fieldInfo = AccessTools.Field(((object)val).GetType(), "value");
					int num = ((fieldInfo != null) ? ((int)fieldInfo.GetValue(val)) : 0);
					Type type2 = AccessTools.TypeByName("SemiFunc");
					MethodInfo methodInfo = ((type2 != null) ? AccessTools.Method(type2, "StatGetRunCurrency", (Type[])null, (Type[])null) : null);
					int num2 = ((methodInfo != null) ? ((int)methodInfo.Invoke(null, null)) : int.MaxValue);
					if (num2 - num >= 0)
					{
						AutoHostSharedUpgradePlugin.TryAutoUseUpgrade(val);
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource logS = AutoHostSharedUpgradePlugin.LogS;
				if (logS != null)
				{
					logS.LogWarning((object)("[Patch_DestroyFirst] " + ex.Message));
				}
			}
		}
	}
	[HarmonyPatch]
	internal static class Patch_DestroyAll
	{
		private static MethodBase TargetMethod()
		{
			Type type = AccessTools.TypeByName("ExtractionPoint");
			return AccessTools.Method(type, "DestroyAllPhysObjectsInShoppingList", (Type[])null, (Type[])null);
		}

		private static void Prefix()
		{
			if (!AutoHostSharedUpgradePlugin.ShouldAutoApply())
			{
				return;
			}
			try
			{
				Type type = AccessTools.TypeByName("ShopManager");
				object value = AccessTools.Field(type, "instance").GetValue(null);
				IEnumerable<Component> enumerable = (IEnumerable<Component>)AccessTools.Field(type, "shoppingList").GetValue(value);
				if (enumerable == null)
				{
					return;
				}
				Type type2 = AccessTools.TypeByName("SemiFunc");
				MethodInfo methodInfo = ((type2 != null) ? AccessTools.Method(type2, "StatGetRunCurrency", (Type[])null, (Type[])null) : null);
				int num = ((methodInfo != null) ? ((int)methodInfo.Invoke(null, null)) : int.MaxValue);
				foreach (Component item in enumerable.ToList())
				{
					if ((Object)(object)item == (Object)null)
					{
						continue;
					}
					FieldInfo fieldInfo = AccessTools.Field(((object)item).GetType(), "value");
					int num2 = ((fieldInfo != null) ? ((int)fieldInfo.GetValue(item)) : 0);
					if (num - num2 < 0)
					{
						continue;
					}
					bool flag = false;
					try
					{
						int num3 = num;
						AutoHostSharedUpgradePlugin.TryAutoUseUpgrade(item);
						int num4 = ((methodInfo != null) ? ((int)methodInfo.Invoke(null, null)) : num);
						if (num4 < num3)
						{
							num = num4;
							flag = true;
						}
					}
					catch (Exception ex)
					{
						ManualLogSource logS = AutoHostSharedUpgradePlugin.LogS;
						if (logS != null)
						{
							logS.LogWarning((object)("AutoHost: Error in TryAutoUseUpgrade: " + ex.Message));
						}
					}
					if (!flag)
					{
						num -= num2;
					}
				}
			}
			catch (Exception ex2)
			{
				ManualLogSource logS2 = AutoHostSharedUpgradePlugin.LogS;
				if (logS2 != null)
				{
					logS2.LogWarning((object)("[Patch_DestroyAll] " + ex2.Message));
				}
			}
		}
	}
	[HarmonyPatch]
	internal static class Patch_SemiFunc_StatGetItemsPurchased
	{
		private static MethodBase TargetMethod()
		{
			Type type = AccessTools.TypeByName("SemiFunc");
			return AccessTools.Method(type, "StatGetItemsPurchased", new Type[1] { typeof(string) }, (Type[])null);
		}

		private static bool Prefix(ref int __result, string itemName)
		{
			try
			{
				if (string.IsNullOrEmpty(itemName))
				{
					__result = 0;
					return false;
				}
				Type type = AccessTools.TypeByName("StatsManager");
				object obj = AccessTools.Field(type, "instance")?.GetValue(null);
				if (!(AccessTools.Field(type, "itemsPurchased")?.GetValue(obj) is IDictionary dictionary))
				{
					__result = 0;
					return false;
				}
				if (!dictionary.Contains(itemName))
				{
					dictionary[itemName] = 0;
					__result = 0;
					return false;
				}
				return true;
			}
			catch
			{
				__result = 0;
				return false;
			}
		}
	}
}