Decompiled source of RechargeableDefibro Fix v1.0.2

RechargeableDefibroFix.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.CompilerServices;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Photon.Pun;
using UnityEngine;

[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: CompilationRelaxations(8)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace RechargeableDefibroFix;

[BepInPlugin("rechargeabledefibro.fix.runtime", "RechargeableDefibro Fix", "1.0.1")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public sealed class Plugin : BaseUnityPlugin
{
	internal static ManualLogSource Log;

	internal static ConfigEntry<bool> DebugLogging;

	internal static ConfigEntry<bool> ReplaceBatteryUpdate;

	internal static ConfigEntry<bool> SuppressBatteryErrors;

	internal static ConfigEntry<bool> KeepDefibroAfterUse;

	internal static ConfigEntry<bool> AllowRecharge;

	internal static ConfigEntry<bool> DisableAutoDrain;

	internal static ConfigEntry<bool> SuppressBatteryUi;

	internal static ConfigEntry<bool> ShowHeldBatteryUi;

	internal static ConfigEntry<bool> UseBatteryVisuals;

	internal static ConfigEntry<int> BatteryBars;

	internal static ConfigEntry<int> BatteryLifeOnSpawn;

	internal static ConfigEntry<int> BatteryLifeAfterUse;

	internal static ConfigEntry<float> ChargeMultiplier;

	private void Awake()
	{
		//IL_014f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0159: Expected O, but got Unknown
		//IL_0183: Unknown result type (might be due to invalid IL or missing references)
		//IL_018d: Expected O, but got Unknown
		//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c0: Expected O, but got Unknown
		//IL_01f4: Unknown result type (might be due to invalid IL or missing references)
		//IL_01fe: Expected O, but got Unknown
		//IL_0208: Unknown result type (might be due to invalid IL or missing references)
		Log = ((BaseUnityPlugin)this).Logger;
		DebugLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "DebugLogging", false, "Enable extra logs for RechargeableDefibro Fix.");
		ReplaceBatteryUpdate = ((BaseUnityPlugin)this).Config.Bind<bool>("Fixes", "ReplaceDefibroBatteryUpdate", true, "Use a safe battery update loop for Defibro instead of the vanilla ItemBattery.Update.");
		SuppressBatteryErrors = ((BaseUnityPlugin)this).Config.Bind<bool>("Fixes", "SuppressDefibroBatteryErrors", true, "Suppress Defibro ItemBattery exceptions after repairing the battery state.");
		KeepDefibroAfterUse = ((BaseUnityPlugin)this).Config.Bind<bool>("Defibro", "KeepDefibroAfterUse", true, "Keep Defibro as a rechargeable item after revive instead of letting it behave like a destroyed one.");
		AllowRecharge = ((BaseUnityPlugin)this).Config.Bind<bool>("Defibro", "AllowRecharge", true, "Allow charging stations to recharge Defibro.");
		DisableAutoDrain = ((BaseUnityPlugin)this).Config.Bind<bool>("Defibro", "DisableAutoDrain", true, "Prevent passive battery drain on Defibro.");
		SuppressBatteryUi = ((BaseUnityPlugin)this).Config.Bind<bool>("Defibro", "SuppressBatteryUi", false, "Legacy option for hiding Defibro battery UI when the safe update loop is disabled.");
		ShowHeldBatteryUi = ((BaseUnityPlugin)this).Config.Bind<bool>("Defibro", "ShowHeldBatteryUi", true, "Show the vanilla held-item battery UI for Defibro while using the safe update loop.");
		UseBatteryVisuals = ((BaseUnityPlugin)this).Config.Bind<bool>("Defibro", "UseBatteryVisuals", false, "Use vanilla battery bar visuals when the Defibro prefab has a BatteryVisualLogic component.");
		BatteryBars = ((BaseUnityPlugin)this).Config.Bind<int>("Defibro", "BatteryBars", 1, new ConfigDescription("Number of battery bars Defibro uses.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 10), new object[0]));
		BatteryLifeOnSpawn = ((BaseUnityPlugin)this).Config.Bind<int>("Defibro", "BatteryLifeOnSpawn", 100, new ConfigDescription("Battery life when Defibro is created.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), new object[0]));
		BatteryLifeAfterUse = ((BaseUnityPlugin)this).Config.Bind<int>("Defibro", "BatteryLifeAfterUse", 0, new ConfigDescription("Battery life after a revive is fired.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), new object[0]));
		ChargeMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Defibro", "ChargeMultiplier", 1f, new ConfigDescription("Multiplier for charging speed applied only to Defibro.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 10f), new object[0]));
		new Harmony("rechargeabledefibro.fix.runtime").PatchAll();
		((BaseUnityPlugin)this).Logger.LogInfo((object)"Patched RechargeableDefibro battery handling.");
	}
}
internal static class ModLog
{
	private static bool loggedMissingState;

	private static bool loggedSuppressedUpdate;

	private static bool loggedReactivated;

	public static void Debug(string message)
	{
		if (Plugin.DebugLogging != null && Plugin.DebugLogging.Value && Plugin.Log != null)
		{
			Plugin.Log.LogInfo((object)("[Debug] " + message));
		}
	}

	public static void Warning(string message)
	{
		if (Plugin.Log != null)
		{
			Plugin.Log.LogWarning((object)message);
		}
	}

	public static void MissingState()
	{
		if (!loggedMissingState)
		{
			Warning("RechargeableDefibro state component was not found.");
			loggedMissingState = true;
		}
	}

	public static void SuppressedUpdate(Exception ex)
	{
		if (loggedSuppressedUpdate)
		{
			Debug("Suppressed another Defibro ItemBattery exception: " + ex.GetType().Name);
			return;
		}
		Warning("Suppressed a Defibro ItemBattery exception after repairing the battery state: " + ex.GetType().Name);
		loggedSuppressedUpdate = true;
	}

	public static void Reactivated()
	{
		if (loggedReactivated)
		{
			Debug("Defibro reactivated after recharge.");
			return;
		}
		Debug("Defibro reactivated after recharge.");
		loggedReactivated = true;
	}
}
internal static class DefibroBattery
{
	private static readonly Type StateType = AccessTools.TypeByName("RechargeableDefibro.DefibroState");

	private static readonly FieldInfo StateIsDepleted = ((StateType == null) ? null : AccessTools.Field(StateType, "isDepleted"));

	private static readonly FieldInfo StateReviveFired = ((StateType == null) ? null : AccessTools.Field(StateType, "reviveFired"));

	private static readonly MethodInfo HardResetVisuals = AccessTools.Method(typeof(ItemReviveItem), "HardResetVisuals", (Type[])null, (Type[])null);

	private static readonly MethodInfo BatteryUpdateBarsMethod = AccessTools.Method(typeof(ItemBattery), "BatteryUpdateBars", (Type[])null, (Type[])null);

	private static readonly MethodInfo BatteryFullPercentChangeMethod = AccessTools.Method(typeof(ItemBattery), "BatteryFullPercentChange", (Type[])null, (Type[])null);

	private static readonly MethodInfo BatteryFullPercentChangeLogicMethod = AccessTools.Method(typeof(ItemBattery), "BatteryFullPercentChangeLogic", (Type[])null, (Type[])null);

	private static readonly FieldInfo SuppressBatteryUiField = AccessTools.Field(typeof(ItemBattery), "suppressBatteryUI");

	private static readonly FieldInfo DrainRateField = AccessTools.Field(typeof(ItemBattery), "drainRate");

	private static readonly FieldInfo DrainTimerField = AccessTools.Field(typeof(ItemBattery), "drainTimer");

	private static readonly FieldInfo ChargerListField = AccessTools.Field(typeof(ItemBattery), "chargerList");

	private static readonly FieldInfo ItemAttributesField = AccessTools.Field(typeof(ItemBattery), "itemAttributes");

	private static readonly FieldInfo PhotonViewField = AccessTools.Field(typeof(ItemBattery), "photonView");

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

	private static readonly FieldInfo PhysGrabObjectField = AccessTools.Field(typeof(ItemBattery), "physGrabObject");

	private static readonly FieldInfo MainCameraField = AccessTools.Field(typeof(ItemBattery), "mainCamera");

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

	private static readonly FieldInfo ChargeTimerField = AccessTools.Field(typeof(ItemBattery), "chargeTimer");

	private static readonly FieldInfo ChargeRateField = AccessTools.Field(typeof(ItemBattery), "chargeRate");

	private static readonly FieldInfo IsChargingField = AccessTools.Field(typeof(ItemBattery), "isCharging");

	private static readonly FieldInfo BatteryLifePrevField = AccessTools.Field(typeof(ItemBattery), "batteryLifePrev");

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

	private static readonly FieldInfo BatteryColorField = AccessTools.Field(typeof(ItemBattery), "batteryColor");

	private static readonly FieldInfo BatteryColorMediumField = AccessTools.Field(typeof(ItemBattery), "batteryColorMedium");

	private static readonly FieldInfo CurrentBarsField = AccessTools.Field(typeof(ItemBattery), "currentBars");

	private static readonly FieldInfo BatteryLifeCountBarsField = AccessTools.Field(typeof(ItemBattery), "batteryLifeCountBars");

	private static readonly FieldInfo BatteryLifeCountBarsPrevField = AccessTools.Field(typeof(ItemBattery), "batteryLifeCountBarsPrev");

	private static readonly FieldInfo MapToolActiveField = AccessTools.Field(typeof(MapToolController), "Active");

	private static readonly FieldInfo GrabbedPhysGrabObjectField = AccessTools.Field(typeof(PhysGrabber), "grabbedPhysGrabObject");

	private static readonly FieldInfo BatteryVisualCurrentBarsField = AccessTools.Field(typeof(BatteryVisualLogic), "currentBars");

	private static readonly FieldInfo InventorySpotBatteryVisualLogicField = AccessTools.Field(typeof(InventorySpot), "batteryVisualLogic");

	private static readonly FieldInfo ItemAttributesColorPresetField = AccessTools.Field(typeof(ItemAttributes), "colorPreset");

	private static readonly Type ColorPresetsType = AccessTools.TypeByName("ColorPresets");

	private static readonly MethodInfo ColorPresetGetColorLightMethod = ((ColorPresetsType == null) ? null : AccessTools.Method(ColorPresetsType, "GetColorLight", (Type[])null, (Type[])null));

	private static readonly MethodInfo ColorPresetGetColorMainMethod = ((ColorPresetsType == null) ? null : AccessTools.Method(ColorPresetsType, "GetColorMain", (Type[])null, (Type[])null));

	private static readonly Color DefaultBatteryColor = new Color(1f, 1f, 0f, 1f);

	private static readonly Color DefaultBatteryMediumColor = new Color(1f, 0.75f, 0f, 1f);

	public static bool IsDefibroBattery(ItemBattery battery)
	{
		if ((Object)(object)battery != (Object)null)
		{
			return (Object)(object)((Component)battery).GetComponent<ItemReviveItem>() != (Object)null;
		}
		return false;
	}

	public static void Repair(ItemBattery battery, bool initial)
	{
		if (IsDefibroBattery(battery))
		{
			int batteryBars = Mathf.Max(1, Plugin.BatteryBars.Value);
			battery.batteryBars = batteryBars;
			battery.isUnchargable = !Plugin.AllowRecharge.Value;
			BatteryVisualLogic batteryVisualLogic = GetBatteryVisualLogic(battery);
			battery.hasBatteryVisuals = Plugin.UseBatteryVisuals.Value && (Object)(object)batteryVisualLogic != (Object)null;
			SetField(SuppressBatteryUiField, battery, !ShouldShowHeldBatteryUi() || Plugin.SuppressBatteryUi.Value);
			if (Plugin.DisableAutoDrain.Value)
			{
				battery.autoDrain = false;
				battery.batteryDrainRate = 0f;
				SetField(DrainRateField, battery, 0f);
				SetField(DrainTimerField, battery, 0f);
			}
			if (GetChargerList(battery) == null)
			{
				SetField(ChargerListField, battery, new List<GameObject>());
			}
			if ((Object)(object)GetField<ItemAttributes>(ItemAttributesField, battery) == (Object)null)
			{
				SetField(ItemAttributesField, battery, ((Component)battery).GetComponent<ItemAttributes>());
			}
			if ((Object)(object)GetField<PhotonView>(PhotonViewField, battery) == (Object)null)
			{
				SetField(PhotonViewField, battery, ((Component)battery).GetComponent<PhotonView>());
			}
			if ((Object)(object)GetField<ItemEquippable>(ItemEquippableField, battery) == (Object)null)
			{
				SetField(ItemEquippableField, battery, GetItemEquippable(battery));
			}
			if ((Object)(object)GetPhysGrabObject(battery) == (Object)null)
			{
				SetField(PhysGrabObjectField, battery, ((Component)battery).GetComponentInChildren<PhysGrabObject>(true));
			}
			if ((Object)(object)GetField<Camera>(MainCameraField, battery) == (Object)null)
			{
				SetField(MainCameraField, battery, Camera.main);
			}
			if ((Object)(object)batteryVisualLogic == (Object)null)
			{
				SetField(BatteryVisualLogicField, battery, ((Component)battery).GetComponentInChildren<BatteryVisualLogic>(true));
			}
			if ((Object)(object)GetBatteryVisualLogic(battery) == (Object)null)
			{
				battery.hasBatteryVisuals = false;
			}
			if (initial && battery.batteryLife <= 1f)
			{
				battery.batteryLife = Plugin.BatteryLifeOnSpawn.Value;
			}
			battery.batteryLife = Mathf.Clamp(battery.batteryLife, 0f, 100f);
			ApplyVanillaBatteryColors(battery);
			ApplyCounts(battery, notifyChange: false);
		}
	}

	public static void Update(ItemBattery battery)
	{
		Repair(battery, initial: false);
		if (Plugin.AllowRecharge.Value && SemiFunc.IsMasterClientOrSingleplayer())
		{
			float field = GetField(ChargeTimerField, battery, 0f);
			float field2 = GetField(ChargeRateField, battery, 0f);
			bool field3 = GetField(IsChargingField, battery, fallback: false);
			if (field > 0f && battery.batteryLife < 100f)
			{
				SetField(IsChargingField, battery, true);
				battery.batteryLife = Mathf.Clamp(battery.batteryLife + field2 * Plugin.ChargeMultiplier.Value * Time.deltaTime, 0f, 100f);
				SetField(ChargeTimerField, battery, Mathf.Max(0f, field - Time.deltaTime));
			}
			else if (field2 != 0f || field3)
			{
				SetField(ChargeRateField, battery, 0f);
				SetField(ChargeTimerField, battery, 0f);
				SetField(IsChargingField, battery, false);
				GetChargerList(battery)?.Clear();
			}
		}
		ApplyCounts(battery, notifyChange: true);
		ReactivateIfReady(battery);
		ShowHeldBatteryUi(battery);
		if (battery.hasBatteryVisuals && (Object)(object)GetBatteryVisualLogic(battery) != (Object)null && BatteryUpdateBarsMethod != null)
		{
			BatteryUpdateBarsMethod.Invoke(battery, new object[1] { GetBatteryLifeInt(battery) });
		}
	}

	public static void SetAfterUse(ItemBattery battery)
	{
		if (IsDefibroBattery(battery) && Plugin.KeepDefibroAfterUse.Value)
		{
			Repair(battery, initial: false);
			battery.batteryLife = Mathf.Clamp(Plugin.BatteryLifeAfterUse.Value, 0, 100);
			SetField(BatteryLifePrevField, battery, -1f);
			battery.batteryActive = true;
			SetField(IsChargingField, battery, false);
			SetField(ChargeRateField, battery, 0f);
			SetField(ChargeTimerField, battery, 0f);
			ApplyCounts(battery, notifyChange: true);
			PhysGrabObject physGrabObject = GetPhysGrabObject(battery);
			if ((Object)(object)physGrabObject != (Object)null)
			{
				physGrabObject.dead = false;
			}
		}
	}

	public static bool SetBatteryLife(ItemBattery battery, int life)
	{
		if (!IsDefibroBattery(battery))
		{
			return true;
		}
		Repair(battery, initial: false);
		battery.batteryLife = Mathf.Clamp(life, 0, 100);
		SetField(BatteryLifePrevField, battery, -1f);
		ApplyCounts(battery, notifyChange: true);
		ReactivateIfReady(battery);
		return false;
	}

	public static bool CanRunBatteryVisualMethod(ItemBattery battery)
	{
		if (IsDefibroBattery(battery))
		{
			if (battery.hasBatteryVisuals && (Object)(object)GetBatteryVisualLogic(battery) != (Object)null)
			{
				return !Plugin.SuppressBatteryUi.Value;
			}
			return false;
		}
		return true;
	}

	public static bool CanCharge(ItemBattery battery)
	{
		if (!IsDefibroBattery(battery))
		{
			return true;
		}
		Repair(battery, initial: false);
		return Plugin.AllowRecharge.Value;
	}

	private static void ApplyCounts(ItemBattery battery, bool notifyChange)
	{
		int num = Mathf.Max(1, battery.batteryBars);
		int num2 = Mathf.Clamp(Mathf.RoundToInt(battery.batteryLife / (100f / (float)num)), 0, num);
		int field = GetField(BatteryLifeCountBarsPrevField, battery, GetBatteryLifeInt(battery));
		SetField(BatteryLifeCountBarsField, battery, num2);
		SetField(BatteryLifeIntField, battery, num2);
		SetField(CurrentBarsField, battery, num2);
		if (notifyChange && num2 != field)
		{
			NotifyBatteryChanged(battery, num2, field < num2);
			SetField(BatteryLifeCountBarsPrevField, battery, num2);
		}
		else
		{
			SetField(BatteryLifeCountBarsPrevField, battery, num2);
		}
	}

	private static void ReactivateIfReady(ItemBattery battery)
	{
		if (IsDepleted(battery) && !(battery.batteryLife < 99f))
		{
			SetDepleted(battery, value: false);
			SetReviveFired(battery, value: false);
			PhysGrabObject physGrabObject = GetPhysGrabObject(battery);
			if ((Object)(object)physGrabObject != (Object)null)
			{
				physGrabObject.dead = false;
			}
			ItemReviveItem component = ((Component)battery).GetComponent<ItemReviveItem>();
			if ((Object)(object)component != (Object)null && HardResetVisuals != null)
			{
				HardResetVisuals.Invoke(component, null);
			}
			ModLog.Reactivated();
		}
	}

	public static int GetBatteryLifeIntForUi(ItemBattery battery)
	{
		return Mathf.Clamp(GetBatteryLifeInt(battery), 0, Mathf.Max(1, ((Object)(object)battery == (Object)null) ? 1 : battery.batteryBars));
	}

	public static void BindInventorySpotVisual(InventorySpot spot)
	{
		if (!((Object)(object)spot == (Object)null) && spot.IsOccupied())
		{
			ItemBattery val = FindDefibroBattery((Component)(object)spot.CurrentItem);
			if (!((Object)(object)val == (Object)null))
			{
				Repair(val, initial: false);
				BatteryVisualLogic visualLogic = (BatteryVisualLogic)((InventorySpotBatteryVisualLogicField == null) ? null : /*isinst with value type is only supported in some contexts*/);
				ApplyBatteryVisual(visualLogic, val, rebuild: true);
			}
		}
	}

	public static ItemBattery FindDefibroBattery(Component component)
	{
		if ((Object)(object)component == (Object)null)
		{
			return null;
		}
		ItemBattery component2 = component.GetComponent<ItemBattery>();
		if (IsDefibroBattery(component2))
		{
			return component2;
		}
		ItemReviveItem val = component.GetComponent<ItemReviveItem>();
		if ((Object)(object)val == (Object)null)
		{
			val = component.GetComponentInParent<ItemReviveItem>(true);
		}
		if ((Object)(object)val == (Object)null)
		{
			val = component.GetComponentInChildren<ItemReviveItem>(true);
		}
		if ((Object)(object)val != (Object)null)
		{
			ItemBattery component3 = ((Component)val).GetComponent<ItemBattery>();
			if (IsDefibroBattery(component3))
			{
				return component3;
			}
		}
		ItemBattery componentInParent = component.GetComponentInParent<ItemBattery>(true);
		if (IsDefibroBattery(componentInParent))
		{
			return componentInParent;
		}
		ItemBattery componentInChildren = component.GetComponentInChildren<ItemBattery>(true);
		if (!IsDefibroBattery(componentInChildren))
		{
			return null;
		}
		return componentInChildren;
	}

	private static void ApplyVanillaBatteryColors(ItemBattery battery)
	{
		//IL_0032: Unknown result type (might be due to invalid IL or missing references)
		//IL_0037: Unknown result type (might be due to invalid IL or missing references)
		//IL_0038: Unknown result type (might be due to invalid IL or missing references)
		//IL_003d: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
		//IL_008c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0091: Unknown result type (might be due to invalid IL or missing references)
		//IL_009f: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00af: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
		ItemAttributes val = GetField<ItemAttributes>(ItemAttributesField, battery);
		if ((Object)(object)val == (Object)null)
		{
			val = ((Component)battery).GetComponent<ItemAttributes>();
			if ((Object)(object)val != (Object)null)
			{
				SetField(ItemAttributesField, battery, val);
			}
		}
		Color val2 = DefaultBatteryColor;
		Color val3 = DefaultBatteryMediumColor;
		object obj = ((ItemAttributesColorPresetField == null || (Object)(object)val == (Object)null) ? null : ItemAttributesColorPresetField.GetValue(val));
		if (obj != null && ColorPresetGetColorLightMethod != null && ColorPresetGetColorMainMethod != null)
		{
			try
			{
				Color val4 = (Color)ColorPresetGetColorLightMethod.Invoke(obj, null);
				Color val5 = (Color)ColorPresetGetColorMainMethod.Invoke(obj, null);
				if (IsVisibleColor(val4))
				{
					val2 = val4;
				}
				if (IsVisibleColor(val5))
				{
					val3 = val5;
				}
			}
			catch (Exception ex)
			{
				ModLog.Debug("Could not fetch Defibro battery colors from ColorPreset: " + ex.GetType().Name);
			}
		}
		SetField(BatteryColorField, battery, val2);
		SetField(BatteryColorMediumField, battery, val3);
	}

	private static bool IsVisibleColor(Color color)
	{
		if (color.a > 0.01f)
		{
			return color.r + color.g + color.b > 0.05f;
		}
		return false;
	}

	private static void ApplyBatteryVisual(BatteryVisualLogic visualLogic, ItemBattery battery, bool rebuild)
	{
		if ((Object)(object)visualLogic == (Object)null || (Object)(object)battery == (Object)null)
		{
			return;
		}
		try
		{
			if (!((Component)visualLogic).gameObject.activeSelf)
			{
				((Component)visualLogic).gameObject.SetActive(true);
			}
			if ((Object)(object)visualLogic.itemBattery != (Object)(object)battery)
			{
				visualLogic.itemBattery = battery;
				rebuild = true;
			}
			if (visualLogic.batteryBars != battery.batteryBars)
			{
				rebuild = true;
			}
			if (rebuild)
			{
				visualLogic.BatteryBarsSet();
			}
			visualLogic.BatteryBarsUpdate(GetBatteryLifeIntForUi(battery), true);
		}
		catch (Exception ex)
		{
			ModLog.Debug("Could not apply Defibro battery visual: " + ex.GetType().Name);
		}
	}

	private static int GetBatteryLifeInt(ItemBattery battery)
	{
		return GetField(BatteryLifeIntField, battery, 0);
	}

	private static bool ShouldShowHeldBatteryUi()
	{
		if (Plugin.ShowHeldBatteryUi != null)
		{
			return Plugin.ShowHeldBatteryUi.Value;
		}
		return false;
	}

	private static void ShowHeldBatteryUi(ItemBattery battery)
	{
		if (!ShouldShowHeldBatteryUi())
		{
			return;
		}
		try
		{
			if (SemiFunc.RunIsShop() || SemiFunc.RunIsArena() || ((Object)(object)MapToolController.instance != (Object)null && GetObjectField(MapToolActiveField, MapToolController.instance, fallback: false)))
			{
				return;
			}
			PhysGrabObject physGrabObject = GetPhysGrabObject(battery);
			PhysGrabObject val = (((Object)(object)PhysGrabber.instance == (Object)null) ? null : GetObjectField<PhysGrabObject>(GrabbedPhysGrabObjectField, PhysGrabber.instance));
			if ((Object)(object)physGrabObject == (Object)null || (Object)(object)PhysGrabber.instance == (Object)null || !PhysGrabber.instance.grabbed || (Object)(object)val != (Object)(object)physGrabObject)
			{
				return;
			}
			BatteryUI instance = BatteryUI.instance;
			if (!((Object)(object)instance == (Object)null) && !((Object)(object)instance.batteryVisualLogic == (Object)null))
			{
				BatteryVisualLogic batteryVisualLogic = instance.batteryVisualLogic;
				bool flag = (Object)(object)batteryVisualLogic.itemBattery != (Object)(object)battery;
				if (flag)
				{
					batteryVisualLogic.itemBattery = battery;
				}
				int objectField = GetObjectField(BatteryVisualCurrentBarsField, batteryVisualLogic, -1);
				if (flag || batteryVisualLogic.batteryBars != battery.batteryBars || objectField != GetBatteryLifeIntForUi(battery))
				{
					ApplyBatteryVisual(batteryVisualLogic, battery, rebuild: true);
				}
				else
				{
					ApplyBatteryVisual(batteryVisualLogic, battery, rebuild: false);
				}
				((SemiUI)instance).Show();
			}
		}
		catch (Exception ex)
		{
			ModLog.Debug("Could not show Defibro battery UI: " + ex.GetType().Name);
		}
	}

	private static void NotifyBatteryChanged(ItemBattery battery, int level, bool charging)
	{
		if (BatteryFullPercentChangeMethod == null)
		{
			SetField(BatteryLifeIntField, battery, level);
			SetField(CurrentBarsField, battery, level);
			return;
		}
		try
		{
			if ((Object)(object)GetField<PhotonView>(PhotonViewField, battery) == (Object)null && BatteryFullPercentChangeLogicMethod != null)
			{
				BatteryFullPercentChangeLogicMethod.Invoke(battery, new object[2] { level, charging });
			}
			else
			{
				BatteryFullPercentChangeMethod.Invoke(battery, new object[2] { level, charging });
			}
		}
		catch (Exception ex)
		{
			ModLog.Debug("Could not run Defibro battery change callback: " + ex.GetType().Name);
			SetField(BatteryLifeIntField, battery, level);
			SetField(CurrentBarsField, battery, level);
		}
	}

	private static List<GameObject> GetChargerList(ItemBattery battery)
	{
		return GetField<List<GameObject>>(ChargerListField, battery);
	}

	private static BatteryVisualLogic GetBatteryVisualLogic(ItemBattery battery)
	{
		BatteryVisualLogic field = GetField<BatteryVisualLogic>(BatteryVisualLogicField, battery);
		if (!((Object)(object)field != (Object)null))
		{
			return ((Component)battery).GetComponentInChildren<BatteryVisualLogic>(true);
		}
		return field;
	}

	private static PhysGrabObject GetPhysGrabObject(ItemBattery battery)
	{
		PhysGrabObject field = GetField<PhysGrabObject>(PhysGrabObjectField, battery);
		if ((Object)(object)field != (Object)null)
		{
			return field;
		}
		field = ((Component)battery).GetComponent<PhysGrabObject>();
		if ((Object)(object)field != (Object)null)
		{
			return field;
		}
		field = ((Component)battery).GetComponentInChildren<PhysGrabObject>(true);
		if (!((Object)(object)field != (Object)null))
		{
			return ((Component)battery).GetComponentInParent<PhysGrabObject>(true);
		}
		return field;
	}

	private static ItemEquippable GetItemEquippable(ItemBattery battery)
	{
		ItemEquippable component = ((Component)battery).GetComponent<ItemEquippable>();
		if ((Object)(object)component != (Object)null)
		{
			return component;
		}
		component = ((Component)battery).GetComponentInChildren<ItemEquippable>(true);
		if (!((Object)(object)component != (Object)null))
		{
			return ((Component)battery).GetComponentInParent<ItemEquippable>(true);
		}
		return component;
	}

	private static T GetField<T>(FieldInfo field, ItemBattery battery, T fallback = default(T))
	{
		if (field == null || (Object)(object)battery == (Object)null)
		{
			return fallback;
		}
		object value = field.GetValue(battery);
		if (value == null)
		{
			return fallback;
		}
		if (!(value is T))
		{
			return fallback;
		}
		return (T)value;
	}

	private static T GetObjectField<T>(FieldInfo field, object instance, T fallback = default(T))
	{
		if (field == null || instance == null)
		{
			return fallback;
		}
		object value = field.GetValue(instance);
		if (value == null)
		{
			return fallback;
		}
		if (!(value is T))
		{
			return fallback;
		}
		return (T)value;
	}

	private static void SetField(FieldInfo field, ItemBattery battery, object value)
	{
		if (field != null && (Object)(object)battery != (Object)null)
		{
			field.SetValue(battery, value);
		}
	}

	private static bool IsDepleted(ItemBattery battery)
	{
		Component state = GetState(battery);
		if ((Object)(object)state != (Object)null && StateIsDepleted != null)
		{
			return (bool)StateIsDepleted.GetValue(state);
		}
		return false;
	}

	private static void SetDepleted(ItemBattery battery, bool value)
	{
		Component state = GetState(battery);
		if ((Object)(object)state != (Object)null && StateIsDepleted != null)
		{
			StateIsDepleted.SetValue(state, value);
		}
	}

	private static void SetReviveFired(ItemBattery battery, bool value)
	{
		Component state = GetState(battery);
		if ((Object)(object)state != (Object)null && StateReviveFired != null)
		{
			StateReviveFired.SetValue(state, value);
		}
	}

	private static Component GetState(ItemBattery battery)
	{
		if (StateType == null || (Object)(object)battery == (Object)null)
		{
			ModLog.MissingState();
			return null;
		}
		Component component = ((Component)battery).GetComponent(StateType);
		if ((Object)(object)component != (Object)null)
		{
			return component;
		}
		return ((Component)battery).gameObject.AddComponent(StateType);
	}
}
[HarmonyPatch(typeof(ItemReviveItem), "Start")]
internal static class ItemReviveItemStartPatch
{
	private static void Postfix(ItemReviveItem __instance)
	{
		ItemBattery battery = (((Object)(object)__instance == (Object)null) ? null : ((Component)__instance).GetComponent<ItemBattery>());
		DefibroBattery.Repair(battery, initial: true);
	}
}
[HarmonyPatch(typeof(ItemReviveItem), "ReviveAndDestroy")]
internal static class ItemReviveItemReviveAndDestroyPatch
{
	private static void Postfix(ItemReviveItem __instance)
	{
		ItemBattery afterUse = (((Object)(object)__instance == (Object)null) ? null : ((Component)__instance).GetComponent<ItemBattery>());
		DefibroBattery.SetAfterUse(afterUse);
	}
}
[HarmonyPatch(typeof(ItemBattery), "Update")]
internal static class ItemBatteryUpdatePatch
{
	private static bool Prefix(ItemBattery __instance)
	{
		if (!DefibroBattery.IsDefibroBattery(__instance) || !Plugin.ReplaceBatteryUpdate.Value)
		{
			return true;
		}
		DefibroBattery.Update(__instance);
		return false;
	}

	private static Exception Finalizer(Exception __exception, ItemBattery __instance)
	{
		if (__exception == null || !DefibroBattery.IsDefibroBattery(__instance) || !Plugin.SuppressBatteryErrors.Value)
		{
			return __exception;
		}
		DefibroBattery.Repair(__instance, initial: false);
		ModLog.SuppressedUpdate(__exception);
		return null;
	}
}
[HarmonyPatch(typeof(InventorySpot), "StateOccupied")]
internal static class InventorySpotStateOccupiedPatch
{
	private static void Postfix(InventorySpot __instance)
	{
		DefibroBattery.BindInventorySpotVisual(__instance);
	}
}
[HarmonyPatch(typeof(Inventory), "GetBatteryStateFromInventorySpot")]
internal static class InventoryGetBatteryStateFromInventorySpotPatch
{
	private static void Postfix(Inventory __instance, int index, ref int __result)
	{
		if ((Object)(object)__instance == (Object)null)
		{
			return;
		}
		InventorySpot spotByIndex = __instance.GetSpotByIndex(index);
		if (!((Object)(object)spotByIndex == (Object)null) && spotByIndex.IsOccupied())
		{
			ItemEquippable currentItem = spotByIndex.CurrentItem;
			ItemBattery val = DefibroBattery.FindDefibroBattery((Component)(object)currentItem);
			if (!((Object)(object)val == (Object)null))
			{
				DefibroBattery.Repair(val, initial: false);
				__result = DefibroBattery.GetBatteryLifeIntForUi(val);
			}
		}
	}
}
[HarmonyPatch(typeof(ItemBattery), "SetBatteryLife")]
internal static class ItemBatterySetBatteryLifePatch
{
	private static bool Prefix(ItemBattery __instance, int _batteryLife)
	{
		return DefibroBattery.SetBatteryLife(__instance, _batteryLife);
	}
}
[HarmonyPatch(typeof(ItemBattery), "ChargeBattery")]
internal static class ItemBatteryChargeBatteryPatch
{
	private static bool Prefix(ItemBattery __instance)
	{
		return DefibroBattery.CanCharge(__instance);
	}

	private static void Postfix(ItemBattery __instance)
	{
		if (DefibroBattery.IsDefibroBattery(__instance))
		{
			DefibroBattery.Repair(__instance, initial: false);
		}
	}
}
[HarmonyPatch(typeof(ItemBattery), "BatteryLookAt")]
internal static class ItemBatteryLookAtPatch
{
	private static bool Prefix(ItemBattery __instance)
	{
		return DefibroBattery.CanRunBatteryVisualMethod(__instance);
	}
}
[HarmonyPatch(typeof(ItemBattery), "BatteryChargingVisuals")]
internal static class ItemBatteryChargingVisualsPatch
{
	private static bool Prefix(ItemBattery __instance)
	{
		return DefibroBattery.CanRunBatteryVisualMethod(__instance);
	}
}
[HarmonyPatch(typeof(ItemBattery), "BatteryUpdateBars")]
internal static class ItemBatteryUpdateBarsPatch
{
	private static bool Prefix(ItemBattery __instance)
	{
		return DefibroBattery.CanRunBatteryVisualMethod(__instance);
	}
}