Decompiled source of Portable Cart Tools v1.0.0

CartToolsStandalone.dll

Decompiled 10 hours ago
using System;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;

[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("Portable Cart Tools")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("CartToolsStandalone")]
[assembly: AssemblyTitle("CartToolsStandalone")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace UL.CartToolsStandalone
{
	[BepInPlugin("ul.carttools.standalone", "Portable Cart Tools", "1.0.0")]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "ul.carttools.standalone";

		public const string PluginName = "Portable Cart Tools";

		public const string PluginVersion = "1.0.0";

		internal const bool EnableInventoryIconFixInternal = true;

		internal const bool ProtectStoredBatteryInternal = true;

		internal const bool PreventStoredBatteryAnimationInternal = true;

		internal const bool UseFallbackInventoryIconsInternal = true;

		internal static ManualLogSource Log;

		internal static ConfigEntry<bool> EnableStandaloneCannon;

		internal static ConfigEntry<bool> EnableStandaloneLaser;

		internal static ConfigEntry<bool> EnableInventoryStorage;

		internal static ConfigEntry<bool> DebugLogging;

		private Harmony harmony;

		private void Awake()
		{
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			EnableStandaloneCannon = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnableStandaloneCannon", true, "Allow cart cannon items to activate without being inside a cart.");
			EnableStandaloneLaser = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnableStandaloneLaser", true, "Allow cart laser items to activate without being inside a cart.");
			EnableInventoryStorage = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnableInventoryStorage", true, "Allow cart cannon and cart laser to be stored in player slot inventory. Experimental. Host-only compatibility must be verified.");
			DebugLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "DebugLogging", false, "Enable detailed cart-tool diagnostics for icon assignment, battery guards, and inventory UI refreshes.");
			harmony = new Harmony("ul.carttools.standalone");
			harmony.PatchAll();
			((BaseUnityPlugin)this).Logger.LogInfo((object)string.Format("{0} {1} loaded. StandaloneCannon={2}, StandaloneLaser={3}, InventoryStorage={4}, DebugLogging={5}", "Portable Cart Tools", "1.0.0", EnableStandaloneCannon.Value, EnableStandaloneLaser.Value, EnableInventoryStorage.Value, DebugLogging.Value));
			if (EnableInventoryStorage.Value)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)"Experimental inventory storage uses ItemEquippable on the local item GameObject. Vanilla clients without this mod may not be able to store cart tools because InventorySpot checks GetComponent<ItemEquippable>() locally.");
			}
		}

		private void OnDestroy()
		{
			Harmony obj = harmony;
			if (obj != null)
			{
				obj.UnpatchSelf();
			}
		}
	}
	[HarmonyPatch(typeof(ItemCartCannonMain), "Start")]
	internal static class ItemCartCannonMainStartPatch
	{
		private static void Postfix(ItemCartCannonMain __instance)
		{
			if (Object.op_Implicit((Object)(object)__instance) && StandaloneCartTool.ShouldEnableFor(__instance))
			{
				if (Plugin.EnableInventoryStorage.Value)
				{
					CartToolInventoryStorage.TrySetup(__instance);
				}
				if (!Object.op_Implicit((Object)(object)((Component)__instance).GetComponent<StandaloneCartTool>()))
				{
					((Component)__instance).gameObject.AddComponent<StandaloneCartTool>();
				}
			}
		}
	}
	[HarmonyPatch(typeof(InventorySpot), "EquipItem")]
	internal static class InventorySpotEquipItemPatch
	{
		private static void Prefix(ItemEquippable item)
		{
			CartToolInventoryStorage.EnsureIconForEquippable(item, "before inventory equip");
		}

		private static void Postfix(InventorySpot __instance)
		{
			if (Object.op_Implicit((Object)(object)__instance) && Object.op_Implicit((Object)(object)__instance.CurrentItem))
			{
				CartToolInventoryStorage.EnsureIconForEquippable(__instance.CurrentItem, "after inventory equip");
				__instance.UpdateUI();
			}
		}
	}
	[HarmonyPatch(typeof(InventorySpot), "UpdateUI")]
	internal static class InventorySpotUpdateUIPatch
	{
		private static void Prefix(InventorySpot __instance)
		{
			if (Object.op_Implicit((Object)(object)__instance) && Object.op_Implicit((Object)(object)__instance.CurrentItem))
			{
				CartToolInventoryStorage.EnsureIconForEquippable(__instance.CurrentItem, "before inventory UI refresh");
			}
		}
	}
	[HarmonyPatch(typeof(ItemBattery), "Update")]
	internal static class ItemBatteryUpdatePatch
	{
		private static void Prefix(ItemBattery __instance)
		{
			CartToolStoredBatteryGuard.PreventFalseStoredDrain(__instance);
		}

		private static void Postfix(ItemBattery __instance)
		{
			CartToolStoredBatteryGuard.RestoreAutoDrainIfNeeded(__instance);
		}
	}
	[HarmonyPatch(typeof(ItemBattery), "RemoveFullBar")]
	internal static class ItemBatteryRemoveFullBarPatch
	{
		private static bool Prefix(ItemBattery __instance)
		{
			return !CartToolStoredBatteryGuard.ShouldSuppressStoredBatteryRemoval(__instance);
		}
	}
	internal static class CartToolInventoryStorage
	{
		private const string CannonIconResource = "UL.CartToolsStandalone.Assets.Icons.cart_cannon_icon.png";

		private const string LaserIconResource = "UL.CartToolsStandalone.Assets.Icons.cart_laser_icon.png";

		private static readonly FieldInfo ItemAttributesEquippableField = AccessTools.Field(typeof(ItemAttributes), "itemEquippable");

		private static readonly FieldInfo ItemBatteryEquippableField = AccessTools.Field(typeof(ItemBattery), "itemEquippable");

		private static readonly FieldInfo ItemToggleEquippableField = AccessTools.Field(typeof(ItemToggle), "itemEquippable");

		private static readonly FieldInfo ItemAttributesHasIconField = AccessTools.Field(typeof(ItemAttributes), "hasIcon");

		private static Sprite customCannonIcon;

		private static Sprite customLaserIcon;

		internal static void EnsureIconForEquippable(ItemEquippable itemEquippable, string reason)
		{
			if (!Object.op_Implicit((Object)(object)itemEquippable))
			{
				return;
			}
			ItemCartCannonMain component = ((Component)itemEquippable).GetComponent<ItemCartCannonMain>();
			if (Object.op_Implicit((Object)(object)component))
			{
				bool flag = Object.op_Implicit((Object)(object)((Component)component).GetComponent<ItemCartCannon>());
				bool flag2 = Object.op_Implicit((Object)(object)((Component)component).GetComponent<ItemCartLaser>());
				if (flag || flag2)
				{
					ConfigureInventoryIcon(component, itemEquippable, flag2 ? "laser" : "cannon", reason);
				}
			}
		}

		internal static void TrySetup(ItemCartCannonMain cannonMain)
		{
			bool flag = Object.op_Implicit((Object)(object)((Component)cannonMain).GetComponent<ItemCartCannon>());
			bool flag2 = Object.op_Implicit((Object)(object)((Component)cannonMain).GetComponent<ItemCartLaser>());
			string text = (flag2 ? "laser" : (flag ? "cannon" : "unknown"));
			if (!flag && !flag2)
			{
				return;
			}
			PhysGrabObject component = ((Component)cannonMain).GetComponent<PhysGrabObject>();
			if (!Object.op_Implicit((Object)(object)component))
			{
				Plugin.Log.LogWarning((object)("Inventory storage skipped for " + ((Object)cannonMain).name + ": missing PhysGrabObject."));
				return;
			}
			ItemEquippable val = ((Component)component).GetComponent<ItemEquippable>();
			if (!Object.op_Implicit((Object)(object)val))
			{
				val = ((Component)component).gameObject.AddComponent<ItemEquippable>();
				Plugin.Log.LogInfo((object)("Added experimental ItemEquippable to cart " + text + ": " + ((Object)cannonMain).name + "."));
			}
			else
			{
				Plugin.Log.LogInfo((object)("Cart " + text + " already has ItemEquippable: " + ((Object)cannonMain).name + "."));
			}
			RefreshCachedEquippable(cannonMain, val);
			ConfigureInventoryIcon(cannonMain, val, text, "startup");
			if (!Object.op_Implicit((Object)(object)((Component)cannonMain).GetComponent<CartToolStoredBatteryGuard>()))
			{
				((Component)cannonMain).gameObject.AddComponent<CartToolStoredBatteryGuard>();
				DebugLog("Enabled cart " + text + " stored battery protection for " + ((Object)cannonMain).name + ".");
			}
			StandaloneCartTool component2 = ((Component)cannonMain).GetComponent<StandaloneCartTool>();
			if (Object.op_Implicit((Object)(object)component2))
			{
				component2.EnsureVirtualCart();
			}
		}

		private static void RefreshCachedEquippable(ItemCartCannonMain cannonMain, ItemEquippable itemEquippable)
		{
			SetCachedEquippable((Component)(object)((Component)cannonMain).GetComponent<ItemAttributes>(), ItemAttributesEquippableField, itemEquippable, "ItemAttributes", ((Object)cannonMain).name);
			SetCachedEquippable((Component)(object)((Component)cannonMain).GetComponent<ItemBattery>(), ItemBatteryEquippableField, itemEquippable, "ItemBattery", ((Object)cannonMain).name);
			SetCachedEquippable((Component)(object)((Component)cannonMain).GetComponent<ItemToggle>(), ItemToggleEquippableField, itemEquippable, "ItemToggle", ((Object)cannonMain).name);
		}

		private static void SetCachedEquippable(Component component, FieldInfo field, ItemEquippable itemEquippable, string componentName, string itemName)
		{
			if (Object.op_Implicit((Object)(object)component))
			{
				if (field == null)
				{
					Plugin.Log.LogWarning((object)("Inventory storage could not refresh " + componentName + " on " + itemName + ": itemEquippable field not found."));
				}
				else
				{
					field.SetValue(component, itemEquippable);
				}
			}
		}

		private static void ConfigureInventoryIcon(ItemCartCannonMain cannonMain, ItemEquippable itemEquippable, string itemType, string reason)
		{
			ItemAttributes component = ((Component)itemEquippable).GetComponent<ItemAttributes>();
			if (!Object.op_Implicit((Object)(object)component))
			{
				component = ((Component)cannonMain).GetComponent<ItemAttributes>();
			}
			DebugLog("Inventory icon diagnostics (" + reason + ") for cart " + itemType + ": item=" + ((Object)cannonMain).name + ", equippableGO=" + ((Object)((Component)itemEquippable).gameObject).name + ", attributesGO=" + (Object.op_Implicit((Object)(object)component) ? ((Object)((Component)component).gameObject).name : "missing") + ", iconBefore=" + ((Object.op_Implicit((Object)(object)component) && Object.op_Implicit((Object)(object)component.icon)) ? "set" : "null") + ".");
			if (!Object.op_Implicit((Object)(object)component))
			{
				Plugin.Log.LogWarning((object)("Inventory icon setup skipped for " + ((Object)cannonMain).name + ": missing ItemAttributes."));
				return;
			}
			Sprite customIcon = GetCustomIcon(itemType == "laser");
			if (Object.op_Implicit((Object)(object)customIcon))
			{
				string text = (Object.op_Implicit((Object)(object)component.icon) ? ((Object)component.icon).name : "null");
				component.icon = customIcon;
				itemEquippable.ItemIcon = customIcon;
				MarkHasIcon(component, ((Object)cannonMain).name);
				DebugLog("Inventory icon assigned custom PNG for cart " + itemType + ": " + ((Object)cannonMain).name + ". attributesGO=" + ((Object)((Component)component).gameObject).name + ", before=" + text + ", after=" + (Object.op_Implicit((Object)(object)component.icon) ? ((Object)component.icon).name : "null") + ", fallbackUsed=False.");
				return;
			}
			if (Object.op_Implicit((Object)(object)component.icon) && IsCustomIcon(component.icon))
			{
				itemEquippable.ItemIcon = component.icon;
				MarkHasIcon(component, ((Object)cannonMain).name);
				DebugLog("Inventory icon already has custom PNG for cart " + itemType + ": " + ((Object)cannonMain).name + ".");
				return;
			}
			if (Object.op_Implicit((Object)(object)component.icon))
			{
				itemEquippable.ItemIcon = component.icon;
				MarkHasIcon(component, ((Object)cannonMain).name);
				DebugLog("Inventory icon reused from ItemAttributes for cart " + itemType + ": " + ((Object)cannonMain).name + ".");
				return;
			}
			SemiIconMaker componentInChildren = ((Component)cannonMain).GetComponentInChildren<SemiIconMaker>(true);
			if (Object.op_Implicit((Object)(object)componentInChildren))
			{
				Sprite val = componentInChildren.CreateIconFromRenderTexture(((Object)((Component)cannonMain).gameObject).name.Replace("(Clone)", string.Empty).ToLowerInvariant());
				if (Object.op_Implicit((Object)(object)val))
				{
					component.icon = val;
					itemEquippable.ItemIcon = val;
					MarkHasIcon(component, ((Object)cannonMain).name);
					DebugLog("Inventory icon generated for cart " + itemType + ": " + ((Object)cannonMain).name + ".");
					return;
				}
			}
			Sprite val2 = FindFallbackSprite((Component)(object)cannonMain);
			if (!Object.op_Implicit((Object)(object)val2))
			{
				val2 = CreateFallbackIcon(itemType == "laser");
			}
			if (Object.op_Implicit((Object)(object)val2))
			{
				component.icon = val2;
				itemEquippable.ItemIcon = val2;
				MarkHasIcon(component, ((Object)cannonMain).name);
				Plugin.Log.LogWarning((object)("Inventory icon used fallback sprite for cart " + itemType + ": " + ((Object)cannonMain).name + "."));
			}
			else
			{
				Plugin.Log.LogWarning((object)("Inventory icon setup found no icon source for cart " + itemType + ": " + ((Object)cannonMain).name + ". Slot icon may remain blank."));
			}
		}

		private static Sprite GetCustomIcon(bool isLaser)
		{
			if (isLaser)
			{
				if (customLaserIcon == null)
				{
					customLaserIcon = LoadEmbeddedIcon("UL.CartToolsStandalone.Assets.Icons.cart_laser_icon.png", "cart laser");
				}
				return customLaserIcon;
			}
			if (customCannonIcon == null)
			{
				customCannonIcon = LoadEmbeddedIcon("UL.CartToolsStandalone.Assets.Icons.cart_cannon_icon.png", "cart cannon");
			}
			return customCannonIcon;
		}

		private static Sprite LoadEmbeddedIcon(string resourceName, string label)
		{
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Expected O, but got Unknown
			//IL_0154: Unknown result type (might be due to invalid IL or missing references)
			//IL_0163: Unknown result type (might be due to invalid IL or missing references)
			using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName);
			if (stream == null)
			{
				Plugin.Log.LogWarning((object)("Custom inventory icon resource missing for " + label + ": " + resourceName + "."));
				return null;
			}
			byte[] array = new byte[stream.Length];
			int num;
			for (int i = 0; i < array.Length; i += num)
			{
				num = stream.Read(array, i, array.Length - i);
				if (num <= 0)
				{
					break;
				}
			}
			DebugLog($"Custom inventory icon stream found for {label}: {resourceName}, length={array.Length}.");
			Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false);
			bool flag = ImageConversion.LoadImage(val, array, false);
			DebugLog($"Custom inventory icon texture load for {label}: loaded={flag}, bytes={array.Length}, size={((Texture)val).width}x{((Texture)val).height}.");
			if (!flag)
			{
				Plugin.Log.LogWarning((object)("Custom inventory icon failed to decode for " + label + ": " + resourceName + "."));
				return null;
			}
			((Object)val).name = resourceName;
			Sprite val2 = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), (float)Mathf.Max(((Texture)val).width, ((Texture)val).height));
			if (!Object.op_Implicit((Object)(object)val2))
			{
				Plugin.Log.LogWarning((object)("Custom inventory icon sprite creation failed for " + label + ": " + resourceName + "."));
				return null;
			}
			((Object)val2).name = resourceName;
			Plugin.Log.LogInfo((object)$"Loaded custom inventory icon for {label}: {resourceName} ({((Texture)val).width}x{((Texture)val).height}).");
			return val2;
		}

		private static bool IsCustomIcon(Sprite sprite)
		{
			if (Object.op_Implicit((Object)(object)sprite))
			{
				if (!(((Object)sprite).name == "UL.CartToolsStandalone.Assets.Icons.cart_cannon_icon.png"))
				{
					return ((Object)sprite).name == "UL.CartToolsStandalone.Assets.Icons.cart_laser_icon.png";
				}
				return true;
			}
			return false;
		}

		private static Sprite FindFallbackSprite(Component root)
		{
			SpriteRenderer componentInChildren = root.GetComponentInChildren<SpriteRenderer>(true);
			if (Object.op_Implicit((Object)(object)componentInChildren) && Object.op_Implicit((Object)(object)componentInChildren.sprite))
			{
				return componentInChildren.sprite;
			}
			return null;
		}

		private static Sprite CreateFallbackIcon(bool isLaser)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: 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_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: 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_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			Texture2D val = new Texture2D(64, 64, (TextureFormat)4, false);
			Color val2 = default(Color);
			((Color)(ref val2))..ctor(0f, 0f, 0f, 0f);
			Color color = (isLaser ? new Color(0.2f, 0.85f, 1f, 1f) : new Color(1f, 0.45f, 0.12f, 1f));
			Color white = Color.white;
			for (int i = 0; i < 64; i++)
			{
				for (int j = 0; j < 64; j++)
				{
					val.SetPixel(j, i, val2);
				}
			}
			DrawRect(val, 10, 28, 44, 10, color);
			DrawRect(val, 44, 23, 10, 20, color);
			DrawRect(val, 16, 24, 12, 18, color);
			DrawRect(val, 48, 30, 8, 6, white);
			DrawRect(val, isLaser ? 55 : 6, 31, 8, 4, color);
			val.Apply();
			return Sprite.Create(val, new Rect(0f, 0f, 64f, 64f), new Vector2(0.5f, 0.5f), 64f);
		}

		private static void DrawRect(Texture2D texture, int x, int y, int width, int height, Color color)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			for (int i = y; i < y + height; i++)
			{
				for (int j = x; j < x + width; j++)
				{
					if (j >= 0 && j < ((Texture)texture).width && i >= 0 && i < ((Texture)texture).height)
					{
						texture.SetPixel(j, i, color);
					}
				}
			}
		}

		private static void MarkHasIcon(ItemAttributes attributes, string itemName)
		{
			if (ItemAttributesHasIconField == null)
			{
				Plugin.Log.LogWarning((object)("Inventory icon setup could not mark hasIcon on " + itemName + ": hasIcon field not found."));
			}
			else
			{
				ItemAttributesHasIconField.SetValue(attributes, true);
			}
		}

		private static void DebugLog(string message)
		{
			if (Plugin.DebugLogging.Value)
			{
				Plugin.Log.LogInfo((object)message);
			}
		}
	}
	internal sealed class CartToolStoredBatteryGuard : MonoBehaviour
	{
		private static readonly FieldInfo ItemEquippableIsEquippedField = AccessTools.Field(typeof(ItemEquippable), "isEquipped");

		private static readonly FieldInfo ItemEquippableIsEquippingField = AccessTools.Field(typeof(ItemEquippable), "isEquipping");

		private static readonly FieldInfo ItemEquippableEquippedSpotField = AccessTools.Field(typeof(ItemEquippable), "equippedSpot");

		private static readonly FieldInfo ItemBatteryLifeIntField = AccessTools.Field(typeof(ItemBattery), "batteryLifeInt");

		private static readonly FieldInfo ItemBatteryVisualLogicField = AccessTools.Field(typeof(ItemBattery), "batteryVisualLogic");

		private static ItemBattery autoDrainSuppressedBattery;

		private static bool autoDrainSuppressedPreviousValue;

		private ItemCartCannonMain cannonMain;

		private ItemBattery battery;

		private ItemEquippable itemEquippable;

		private string itemType;

		private float storedBatteryLife;

		private int storedBatteryLifeInt;

		private bool hasStoredSnapshot;

		private bool loggedProtectionActive;

		internal static void PreventFalseStoredDrain(ItemBattery itemBattery)
		{
			if (!Object.op_Implicit((Object)(object)itemBattery))
			{
				return;
			}
			CartToolStoredBatteryGuard component = ((Component)itemBattery).GetComponent<CartToolStoredBatteryGuard>();
			if (Object.op_Implicit((Object)(object)component) && component.IsStored())
			{
				autoDrainSuppressedBattery = itemBattery;
				autoDrainSuppressedPreviousValue = itemBattery.autoDrain;
				if (itemBattery.autoDrain)
				{
					itemBattery.autoDrain = false;
					component.RefreshSnapshotIfNeeded();
				}
			}
		}

		internal static bool ShouldSuppressStoredBatteryRemoval(ItemBattery itemBattery)
		{
			if (!Object.op_Implicit((Object)(object)itemBattery))
			{
				return false;
			}
			CartToolStoredBatteryGuard component = ((Component)itemBattery).GetComponent<CartToolStoredBatteryGuard>();
			if (!Object.op_Implicit((Object)(object)component) || !component.IsStoredOrEquipping())
			{
				return false;
			}
			component.RefreshSnapshotIfNeeded();
			component.RestoreSnapshotAndVisuals();
			if (Plugin.DebugLogging.Value)
			{
				Plugin.Log.LogInfo((object)("Suppressed stored cart " + component.itemType + " battery bar removal for " + ((Object)component).name + "."));
			}
			return true;
		}

		internal static void RestoreAutoDrainIfNeeded(ItemBattery itemBattery)
		{
			if (!((Object)(object)autoDrainSuppressedBattery != (Object)(object)itemBattery))
			{
				itemBattery.autoDrain = autoDrainSuppressedPreviousValue;
				autoDrainSuppressedBattery = null;
			}
		}

		private void Awake()
		{
			cannonMain = ((Component)this).GetComponent<ItemCartCannonMain>();
			battery = ((Component)this).GetComponent<ItemBattery>();
			itemEquippable = ((Component)this).GetComponent<ItemEquippable>();
			itemType = (Object.op_Implicit((Object)(object)((Component)this).GetComponent<ItemCartLaser>()) ? "laser" : "cannon");
			if (ItemEquippableIsEquippedField == null)
			{
				Plugin.Log.LogWarning((object)("Cart tool battery guard missing reflection field: ItemEquippable.isEquipped on " + ((Object)this).name + "."));
			}
			if (ItemEquippableIsEquippingField == null)
			{
				Plugin.Log.LogWarning((object)("Cart tool battery guard missing reflection field: ItemEquippable.isEquipping on " + ((Object)this).name + "."));
			}
			if (ItemEquippableEquippedSpotField == null)
			{
				Plugin.Log.LogWarning((object)("Cart tool battery guard missing reflection field: ItemEquippable.equippedSpot on " + ((Object)this).name + "."));
			}
			if (ItemBatteryLifeIntField == null)
			{
				Plugin.Log.LogWarning((object)("Cart tool battery guard missing reflection field: ItemBattery.batteryLifeInt on " + ((Object)this).name + "."));
			}
			if (ItemBatteryVisualLogicField == null)
			{
				Plugin.Log.LogWarning((object)("Cart tool battery guard missing reflection field: ItemBattery.batteryVisualLogic on " + ((Object)this).name + "."));
			}
		}

		private void LateUpdate()
		{
			if (!Object.op_Implicit((Object)(object)cannonMain) || !Object.op_Implicit((Object)(object)battery))
			{
				return;
			}
			if (!Object.op_Implicit((Object)(object)itemEquippable))
			{
				itemEquippable = ((Component)this).GetComponent<ItemEquippable>();
			}
			if (!IsStored())
			{
				hasStoredSnapshot = false;
				return;
			}
			RefreshSnapshotIfNeeded();
			int batteryLifeInt = GetBatteryLifeInt(battery);
			if (battery.batteryLife < storedBatteryLife || batteryLifeInt < storedBatteryLifeInt)
			{
				RestoreSnapshotAndVisuals();
				return;
			}
			storedBatteryLife = battery.batteryLife;
			storedBatteryLifeInt = batteryLifeInt;
		}

		private static bool IsEquipped(ItemEquippable itemEquippable)
		{
			if (ItemEquippableIsEquippedField == null)
			{
				return false;
			}
			return (bool)ItemEquippableIsEquippedField.GetValue(itemEquippable);
		}

		private static bool IsEquipping(ItemEquippable itemEquippable)
		{
			if (ItemEquippableIsEquippingField == null)
			{
				return false;
			}
			return (bool)ItemEquippableIsEquippingField.GetValue(itemEquippable);
		}

		private static bool HasEquippedSpot(ItemEquippable itemEquippable)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Expected O, but got Unknown
			if (ItemEquippableEquippedSpotField == null)
			{
				return false;
			}
			return Object.op_Implicit((Object)(InventorySpot)ItemEquippableEquippedSpotField.GetValue(itemEquippable));
		}

		private bool IsStored()
		{
			if (!Object.op_Implicit((Object)(object)itemEquippable))
			{
				itemEquippable = ((Component)this).GetComponent<ItemEquippable>();
			}
			if (Object.op_Implicit((Object)(object)itemEquippable))
			{
				return IsEquipped(itemEquippable);
			}
			return false;
		}

		private bool IsStoredOrEquipping()
		{
			if (!Object.op_Implicit((Object)(object)itemEquippable))
			{
				itemEquippable = ((Component)this).GetComponent<ItemEquippable>();
			}
			if (Object.op_Implicit((Object)(object)itemEquippable))
			{
				if (!IsEquipped(itemEquippable) && !IsEquipping(itemEquippable))
				{
					return HasEquippedSpot(itemEquippable);
				}
				return true;
			}
			return false;
		}

		private void RefreshSnapshotIfNeeded()
		{
			if (hasStoredSnapshot)
			{
				return;
			}
			storedBatteryLife = battery.batteryLife;
			storedBatteryLifeInt = GetBatteryLifeInt(battery);
			hasStoredSnapshot = true;
			if (!loggedProtectionActive)
			{
				loggedProtectionActive = true;
				if (Plugin.DebugLogging.Value)
				{
					Plugin.Log.LogInfo((object)$"Cart {itemType} storage battery protection active for {((Object)this).name}: preserving {storedBatteryLifeInt} bars.");
				}
			}
		}

		private void RestoreSnapshotAndVisuals()
		{
			battery.batteryLife = storedBatteryLife;
			SetBatteryLifeInt(battery, storedBatteryLifeInt);
			BatteryVisualLogic batteryVisualLogic = GetBatteryVisualLogic(battery);
			if (Object.op_Implicit((Object)(object)batteryVisualLogic))
			{
				batteryVisualLogic.BatteryBarsUpdate(storedBatteryLifeInt, true);
			}
		}

		private static int GetBatteryLifeInt(ItemBattery itemBattery)
		{
			if (ItemBatteryLifeIntField == null)
			{
				return Mathf.RoundToInt(itemBattery.batteryLife);
			}
			return (int)ItemBatteryLifeIntField.GetValue(itemBattery);
		}

		private static void SetBatteryLifeInt(ItemBattery itemBattery, int value)
		{
			if (ItemBatteryLifeIntField != null)
			{
				ItemBatteryLifeIntField.SetValue(itemBattery, value);
			}
		}

		private static BatteryVisualLogic GetBatteryVisualLogic(ItemBattery itemBattery)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Expected O, but got Unknown
			if (ItemBatteryVisualLogicField == null)
			{
				return null;
			}
			return (BatteryVisualLogic)ItemBatteryVisualLogicField.GetValue(itemBattery);
		}
	}
	internal sealed class StandaloneCartTool : MonoBehaviour
	{
		private static readonly FieldInfo ImpactDetectorField = AccessTools.Field(typeof(ItemCartCannonMain), "impactDetector");

		private static readonly FieldInfo CurrentCartField = AccessTools.Field(typeof(PhysGrabObjectImpactDetector), "currentCart");

		private static readonly FieldInfo TimerInCartField = AccessTools.Field(typeof(PhysGrabObjectImpactDetector), "timerInCart");

		private ItemCartCannonMain cannonMain;

		private PhysGrabObjectImpactDetector impactDetector;

		private GameObject virtualCartObject;

		private PhysGrabCart virtualCart;

		private bool applyingVirtualCart;

		internal static bool ShouldEnableFor(ItemCartCannonMain cannonMain)
		{
			bool num = Object.op_Implicit((Object)(object)((Component)cannonMain).GetComponent<ItemCartCannon>());
			bool flag = Object.op_Implicit((Object)(object)((Component)cannonMain).GetComponent<ItemCartLaser>());
			if (num && Plugin.EnableStandaloneCannon.Value)
			{
				return true;
			}
			if (flag && Plugin.EnableStandaloneLaser.Value)
			{
				return true;
			}
			return false;
		}

		private void Awake()
		{
			cannonMain = ((Component)this).GetComponent<ItemCartCannonMain>();
		}

		private void Start()
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			impactDetector = (PhysGrabObjectImpactDetector)ImpactDetectorField.GetValue(cannonMain);
			if (!Object.op_Implicit((Object)(object)impactDetector))
			{
				Plugin.Log.LogWarning((object)("Standalone setup skipped for " + ((Object)this).name + ": missing PhysGrabObjectImpactDetector."));
				((Behaviour)this).enabled = false;
			}
			else
			{
				CreateVirtualCart();
			}
		}

		private void LateUpdate()
		{
			ApplyVirtualCartIfNeeded();
		}

		private void FixedUpdate()
		{
			ApplyVirtualCartIfNeeded();
		}

		private void OnDestroy()
		{
			if (Object.op_Implicit((Object)(object)virtualCartObject))
			{
				Object.Destroy((Object)(object)virtualCartObject);
			}
		}

		private void CreateVirtualCart()
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			//IL_003d: 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_0067: Unknown result type (might be due to invalid IL or missing references)
			virtualCartObject = new GameObject(((Object)this).name + " Standalone Cart Anchor");
			virtualCartObject.transform.SetParent(((Component)this).transform, false);
			virtualCartObject.transform.localPosition = Vector3.zero;
			virtualCartObject.transform.localRotation = Quaternion.identity;
			virtualCartObject.transform.localScale = Vector3.one;
			virtualCart = virtualCartObject.AddComponent<PhysGrabCart>();
			((Behaviour)virtualCart).enabled = false;
		}

		private void ApplyVirtualCartIfNeeded()
		{
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Expected O, but got Unknown
			if (applyingVirtualCart || !Object.op_Implicit((Object)(object)impactDetector) || !Object.op_Implicit((Object)(object)virtualCart))
			{
				if (Object.op_Implicit((Object)(object)impactDetector) && !Object.op_Implicit((Object)(object)virtualCart))
				{
					EnsureVirtualCart();
				}
			}
			else if (ShouldEnableFor(cannonMain))
			{
				PhysGrabCart val = (PhysGrabCart)CurrentCartField.GetValue(impactDetector);
				if (!Object.op_Implicit((Object)(object)val) || !((Object)(object)val != (Object)(object)virtualCart))
				{
					applyingVirtualCart = true;
					CurrentCartField.SetValue(impactDetector, virtualCart);
					TimerInCartField.SetValue(impactDetector, 0.2f);
					impactDetector.inCart = true;
					applyingVirtualCart = false;
				}
			}
		}

		internal void EnsureVirtualCart()
		{
			if (Object.op_Implicit((Object)(object)virtualCart))
			{
				return;
			}
			if (Object.op_Implicit((Object)(object)virtualCartObject))
			{
				virtualCart = virtualCartObject.GetComponent<PhysGrabCart>();
				if (Object.op_Implicit((Object)(object)virtualCart))
				{
					((Behaviour)virtualCart).enabled = false;
					return;
				}
			}
			CreateVirtualCart();
			Plugin.Log.LogInfo((object)("Recreated standalone cart anchor for " + ((Object)this).name + "."));
		}
	}
}