Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of Portable Cart Tools v1.0.0
CartToolsStandalone.dll
Decompiled 10 hours agousing 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 + ".")); } } }