Decompiled source of Extract Crystals In Levels v1.0.0

ExtractCrystalsInLevels.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Photon.Pun;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("ExtractCrystalsInLevels")]
[assembly: AssemblyDescription("Mod for Extracting Power Crystals In Levels! Developed by Jettcodey.")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Jettcodey")]
[assembly: AssemblyProduct("ExtractCrystalsInLevels")]
[assembly: AssemblyCopyright("Copyright © Jettcodey 2025")]
[assembly: ComVisible(false)]
[assembly: Guid("b52829e7-88b6-4158-ba1b-23566c7cf06b")]
[assembly: AssemblyFileVersion("1.0.0")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace ExtractCrystalsInLevels
{
	[BepInPlugin("Jettcodey.ExtractCrystalsInLevels", "ExtractCrystalsInLevels", "1.0.0")]
	public class Plugin : BaseUnityPlugin
	{
		private ConfigEntry<bool> enableKeyPressMethod;

		private ConfigEntry<KeyCode> collectKey;

		private ConfigEntry<bool> enableExtractionMethod;

		private ConfigEntry<bool> enableMod;

		private static Dictionary<string, string> powerCrystalNameMap = new Dictionary<string, string>
		{
			{ "Energy Crystal", "Item Power Crystal" },
			{ "Power Crystal", "Item Power Crystal" },
			{ "Crystal", "Item Power Crystal" }
		};

		internal static Plugin Instance { get; private set; } = null;


		internal static ManualLogSource? Logger { get; private set; }

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

		private Harmony? _harmony { get; set; }

		private void Awake()
		{
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Expected O, but got Unknown
			Instance = this;
			Logger = ((BaseUnityPlugin)this).Logger;
			((Component)this).gameObject.transform.parent = null;
			((Object)((Component)this).gameObject).hideFlags = (HideFlags)61;
			Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject);
			enableMod = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnableMod", true, "Enable/disable the mod");
			enableKeyPressMethod = ((BaseUnityPlugin)this).Config.Bind<bool>("Methods", "EnableKeyPressMethod", false, "Enable key press method (grab and press key to collect)");
			collectKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Methods", "CollectKey", (KeyCode)117, "Key to collect power crystals (key press method)");
			enableExtractionMethod = ((BaseUnityPlugin)this).Config.Bind<bool>("Methods", "EnableExtractionMethod", true, "Enable extraction method (bring to extraction point)");
			if (!enableMod.Value)
			{
				Logger.LogInfo((object)"ExtractCrystalsInLevels mod is disabled in config");
				return;
			}
			PowerCrystalPatches.InitializeConfig(enableMod.Value, enableKeyPressMethod.Value, collectKey.Value, enableExtractionMethod.Value);
			_harmony = new Harmony("Jettcodey.ExtractCrystalsInLevels");
			_harmony.PatchAll();
			Logger.LogInfo((object)"Plugin ExtractCrystalsInLevels v1.0.0 loaded successfully.");
		}

		public static string GetPowerCrystalKey(string displayName)
		{
			if (powerCrystalNameMap.ContainsKey(displayName))
			{
				return powerCrystalNameMap[displayName];
			}
			if (displayName.ToLower().Contains("crystal"))
			{
				return "Item Power Crystal";
			}
			return displayName;
		}

		private void Update()
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			if (!enableMod.Value || !enableKeyPressMethod.Value || !Input.GetKeyDown(collectKey.Value))
			{
				return;
			}
			PlayerController val = PlayerController.instance;
			if ((Object)(object)val == (Object)null)
			{
				val = Object.FindObjectOfType<PlayerController>();
			}
			if ((Object)(object)val == (Object)null || (Object)(object)val.playerAvatarScript == (Object)null)
			{
				return;
			}
			PhysGrabber component = ((Component)val.playerAvatarScript).GetComponent<PhysGrabber>();
			if ((Object)(object)component == (Object)null || !component.grabbed)
			{
				return;
			}
			PhysGrabObject grabbedPhysGrabObject = component.grabbedPhysGrabObject;
			if ((Object)(object)grabbedPhysGrabObject == (Object)null)
			{
				return;
			}
			ItemAttributes component2 = ((Component)grabbedPhysGrabObject).GetComponent<ItemAttributes>();
			if (!((Object)(object)component2 == (Object)null))
			{
				Logger.LogDebug((object)("Holding: " + component2.itemName));
				string powerCrystalKey = GetPowerCrystalKey(component2.itemName);
				if (powerCrystalKey != component2.itemName || component2.itemName.IndexOf("Crystal", StringComparison.OrdinalIgnoreCase) >= 0)
				{
					Logger.LogDebug((object)"Crystal Detected! Attempting collection...");
					PowerCrystalPatches.KeyPressMethod_CollectPowerCrystal(grabbedPhysGrabObject, component2, val.playerAvatarScript);
				}
				else
				{
					Logger.LogWarning((object)("Item '" + component2.itemName + "' was not recognized as a Power Crystal."));
				}
			}
		}
	}
	[HarmonyPatch]
	public static class PowerCrystalPatches
	{
		private static bool modEnabled = true;

		private static bool keyPressMethodEnabled = false;

		private static KeyCode collectKey = (KeyCode)117;

		private static bool extractionMethodEnabled = true;

		private const int MAX_CRYSTALS_PER_RUN = 10;

		public static void InitializeConfig(bool modEnabledValue, bool keyPressMethodEnabledValue, KeyCode collectKeyValue, bool extractionMethodEnabledValue)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			modEnabled = modEnabledValue;
			keyPressMethodEnabled = keyPressMethodEnabledValue;
			collectKey = collectKeyValue;
			extractionMethodEnabled = extractionMethodEnabledValue;
			Plugin.Logger.LogDebug((object)("CrystalAutoApply config loaded - " + $"Mod: {modEnabled}, " + $"KeyPressMethod: {keyPressMethodEnabled}, " + $"CollectKey: {collectKey}, " + $"ExtractionMethod: {extractionMethodEnabled}"));
		}

		private static int GetCurrentRunCrystalCount()
		{
			try
			{
				if ((Object)(object)StatsManager.instance != (Object)null)
				{
					string[] array = new string[4] { "Item Power Crystal", "Power Crystal", "Energy Crystal", "Crystal" };
					string[] array2 = array;
					foreach (string key in array2)
					{
						if (StatsManager.instance.itemsPurchased.ContainsKey(key))
						{
							return StatsManager.instance.itemsPurchased[key];
						}
					}
					if (StatsManager.instance.runStats.ContainsKey("chargingStationCharge"))
					{
						return StatsManager.instance.runStats["chargingStationCharge"];
					}
				}
				return 0;
			}
			catch (Exception arg)
			{
				Plugin.Logger.LogError((object)$"Error getting current crystal count: {arg}");
				return 0;
			}
		}

		private static bool CanCollectMoreCrystals()
		{
			int currentRunCrystalCount = GetCurrentRunCrystalCount();
			bool flag = currentRunCrystalCount < 10;
			if (!flag)
			{
				Debug.Log((object)$"Cannot collect more crystals: {currentRunCrystalCount}/{10} limit reached");
			}
			return flag;
		}

		private static void ShowLimitNotification(PlayerAvatar playerAvatar)
		{
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				string text = $"Charging Station Full! ({10}/{10})";
				Type type = Type.GetType("ItemInfoExtraUI, Assembly-CSharp");
				if (!(type != null))
				{
					return;
				}
				PropertyInfo property = type.GetProperty("instance", BindingFlags.Static | BindingFlags.Public);
				if (!(property != null))
				{
					return;
				}
				object value = property.GetValue(null);
				if (value != null)
				{
					MethodInfo method = type.GetMethod("ItemInfoText", new Type[2]
					{
						typeof(string),
						typeof(Color)
					});
					if (method != null)
					{
						method.Invoke(value, new object[2]
						{
							text,
							Color.yellow
						});
					}
				}
			}
			catch (Exception arg)
			{
				Plugin.Logger.LogError((object)$"Error showing limit notification: {arg}");
			}
		}

		[HarmonyPatch(typeof(PhysGrabObject), "Update")]
		[HarmonyPostfix]
		private static void PhysGrabObject_Update_Postfix(PhysGrabObject __instance)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			if (!modEnabled || !keyPressMethodEnabled)
			{
				return;
			}
			try
			{
				if ((Object)(object)__instance == (Object)null || !__instance.grabbedLocal || !Input.GetKeyDown(collectKey))
				{
					return;
				}
				if (!CanCollectMoreCrystals())
				{
					try
					{
						PlayerAvatar val = ((__instance.playerGrabbing.Count > 0) ? __instance.playerGrabbing[0].playerAvatar : null);
						if ((Object)(object)val != (Object)null && (Object)(object)val.photonView != (Object)null && val.photonView.IsMine)
						{
							ShowLimitNotification(val);
						}
						return;
					}
					catch (Exception arg)
					{
						Plugin.Logger.LogError((object)$"Error showing limit notification: {arg}");
						return;
					}
				}
				ItemAttributes component = ((Component)__instance).GetComponent<ItemAttributes>();
				if ((Object)(object)component == (Object)null || (Object)(object)component.item == (Object)null)
				{
					return;
				}
				FieldInfo field = ((object)component.item).GetType().GetField("itemType");
				if (field != null)
				{
					object value = field.GetValue(component.item);
					if (value.ToString() == "power_crystal" && __instance.playerGrabbing.Count > 0)
					{
						PlayerAvatar playerAvatar = __instance.playerGrabbing[0].playerAvatar;
						if ((Object)(object)playerAvatar != (Object)null)
						{
							KeyPressMethod_CollectPowerCrystal(__instance, component, playerAvatar);
						}
					}
				}
				else if (component.itemName != null && component.itemName.ToLower().Contains("crystal") && __instance.playerGrabbing.Count > 0)
				{
					PlayerAvatar playerAvatar2 = __instance.playerGrabbing[0].playerAvatar;
					if ((Object)(object)playerAvatar2 != (Object)null)
					{
						KeyPressMethod_CollectPowerCrystal(__instance, component, playerAvatar2);
					}
				}
			}
			catch (Exception arg2)
			{
				Plugin.Logger.LogError((object)$"Error in PhysGrabObject Patch: {arg2}");
			}
		}

		public static void KeyPressMethod_CollectPowerCrystal(PhysGrabObject powerCrystal, ItemAttributes itemAttributes, PlayerAvatar playerAvatar)
		{
			try
			{
				if (!CanCollectMoreCrystals())
				{
					Plugin.Logger.LogInfo((object)"Crystal limit reached, skipping collection");
					if ((Object)(object)playerAvatar.photonView != (Object)null && playerAvatar.photonView.IsMine)
					{
						ShowLimitNotification(playerAvatar);
					}
				}
				else
				{
					if (!GameManager.Multiplayer())
					{
						return;
					}
					string itemName = itemAttributes.itemName;
					string text = Plugin.GetPowerCrystalKey(itemName);
					if ((Object)(object)itemAttributes.item != (Object)null)
					{
						FieldInfo field = typeof(ItemAttributes).GetField("itemAssetName", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
						if (field != null)
						{
							string text2 = field.GetValue(itemAttributes) as string;
							if (!string.IsNullOrEmpty(text2) && text2.Contains("PowerCrystal"))
							{
								text = "Item Power Crystal";
							}
						}
					}
					Plugin.Logger.LogInfo((object)("Key Press method: Display Name='" + itemName + "', Dictionary Key='" + text + "'"));
					KeyPressMethod_UpdatePowerCrystalStats(text, itemName, playerAvatar);
					KeyPressMethod_RemovePowerCrystal(powerCrystal, playerAvatar);
				}
			}
			catch (Exception arg)
			{
				Plugin.Logger.LogError((object)$"Error collecting Power Crystal (key press method): {arg}");
			}
		}

		private static void KeyPressMethod_UpdatePowerCrystalStats(string itemKey, string displayName, PlayerAvatar playerAvatar)
		{
			try
			{
				if (GameManager.Multiplayer() && !PhotonNetwork.IsMasterClient)
				{
					return;
				}
				Plugin.Logger.LogDebug((object)("Key Press method: Updating Power Crystal stats: " + displayName));
				if (!((Object)(object)StatsManager.instance != (Object)null))
				{
					return;
				}
				if (!StatsManager.instance.itemsPurchased.ContainsKey(itemKey))
				{
					string text = null;
					foreach (string key in StatsManager.instance.itemsPurchased.Keys)
					{
						if (key.Contains("Power Crystal") || key.Contains("PowerCrystal"))
						{
							text = key;
							break;
						}
					}
					if (text != null)
					{
						itemKey = text;
						Plugin.Logger.LogDebug((object)("Found alternative key: " + itemKey));
					}
					else
					{
						StatsManager.instance.itemsPurchased[itemKey] = 0;
						StatsManager.instance.itemsPurchasedTotal[itemKey] = 0;
						Plugin.Logger.LogDebug((object)("Added new key to dictionary: " + itemKey));
					}
				}
				int num = (StatsManager.instance.itemsPurchased.ContainsKey(itemKey) ? StatsManager.instance.itemsPurchased[itemKey] : 0);
				int num2 = (StatsManager.instance.itemsPurchasedTotal.ContainsKey(itemKey) ? StatsManager.instance.itemsPurchasedTotal[itemKey] : 0);
				if (num >= 10)
				{
					Plugin.Logger.LogInfo((object)$"Already at crystal limit: {num}/{10}");
					return;
				}
				StatsManager.instance.itemsPurchased[itemKey] = num + 1;
				StatsManager.instance.itemsPurchasedTotal[itemKey] = num2 + 1;
				Plugin.Logger.LogInfo((object)$"Updated stats for '{itemKey}': Purchased={StatsManager.instance.itemsPurchased[itemKey]}, Total={StatsManager.instance.itemsPurchasedTotal[itemKey]}");
				KeyPressMethod_UpdateChargingStationStats(itemKey, num + 1);
				if (GameManager.Multiplayer() && (Object)(object)PunManager.instance != (Object)null)
				{
					PunManager.instance.UpdateStat("itemsPurchased", itemKey, StatsManager.instance.itemsPurchased[itemKey]);
					PunManager.instance.UpdateStat("itemsPurchasedTotal", itemKey, StatsManager.instance.itemsPurchasedTotal[itemKey]);
					KeyPressMethod_UpdateChargingStationMultiplayer(num + 1);
				}
				KeyPressMethod_UpdateChargingStationVisuals(num + 1);
				if ((Object)(object)playerAvatar.photonView != (Object)null && playerAvatar.photonView.IsMine)
				{
					ShowCollectionNotification(playerAvatar, displayName, fromExtraction: false, num + 1);
				}
			}
			catch (Exception arg)
			{
				Plugin.Logger.LogError((object)$"Error updating Power Crystal stats (key press method): {arg}");
			}
		}

		private static void KeyPressMethod_UpdateChargingStationStats(string itemKey, int newCrystalCount)
		{
			try
			{
				newCrystalCount = Mathf.Min(newCrystalCount, 10);
				if (StatsManager.instance.runStats.ContainsKey("chargingStationCharge"))
				{
					StatsManager.instance.runStats["chargingStationCharge"] = newCrystalCount;
				}
				else
				{
					StatsManager.instance.runStats.Add("chargingStationCharge", newCrystalCount);
				}
				int num = 100;
				int num2 = 10;
				int num3 = Mathf.Min(newCrystalCount * num2, num);
				int num4 = num;
				if (StatsManager.instance.runStats.ContainsKey("chargingStationChargeTotal"))
				{
					num4 = StatsManager.instance.runStats["chargingStationChargeTotal"];
				}
				else
				{
					StatsManager.instance.runStats.Add("chargingStationChargeTotal", num3);
				}
				if (num4 < num3)
				{
					StatsManager.instance.runStats["chargingStationChargeTotal"] = num3;
				}
				Plugin.Logger.LogInfo((object)string.Format("Updated charging station: Crystals={0}/{1}, Capacity={2}", newCrystalCount, 10, StatsManager.instance.runStats["chargingStationChargeTotal"]));
				if (StatsManager.instance.itemDictionary.ContainsKey(itemKey))
				{
					Item val = StatsManager.instance.itemDictionary[itemKey];
					if ((Object)(object)val != (Object)null)
					{
						StatsManager.instance.SetItemPurchase(val, newCrystalCount);
					}
				}
			}
			catch (Exception arg)
			{
				Plugin.Logger.LogError((object)$"Error updating charging station stats (key press method): {arg}");
			}
		}

		private static void KeyPressMethod_UpdateChargingStationMultiplayer(int newCrystalCount)
		{
			try
			{
				newCrystalCount = Mathf.Min(newCrystalCount, 10);
				ChargingStation instance = ChargingStation.instance;
				if (!((Object)(object)instance != (Object)null) || !PhotonNetwork.IsMasterClient)
				{
					return;
				}
				int num = 40;
				float num2 = Mathf.Clamp01((float)newCrystalCount / 10f);
				int num3 = Mathf.RoundToInt(num2 * (float)num);
				PhotonView component = ((Component)instance).GetComponent<PhotonView>();
				if ((Object)(object)component != (Object)null)
				{
					MethodInfo method = typeof(ChargingStation).GetMethod("ChargingStationSegmentChangedRPC", BindingFlags.Instance | BindingFlags.NonPublic);
					if (method != null)
					{
						method.Invoke(instance, new object[1] { (byte)num3 });
					}
				}
			}
			catch (Exception arg)
			{
				Plugin.Logger.LogError((object)$"Error updating charging station multiplayer: {arg}");
			}
		}

		private static void KeyPressMethod_UpdateChargingStationVisuals(int newCrystalCount)
		{
			try
			{
				newCrystalCount = Mathf.Min(newCrystalCount, 10);
				ChargingStation instance = ChargingStation.instance;
				if ((Object)(object)instance != (Object)null)
				{
					FieldInfo field = typeof(ChargingStation).GetField("chargeInt", BindingFlags.Instance | BindingFlags.NonPublic);
					if (field != null)
					{
						field.SetValue(instance, newCrystalCount);
					}
					FieldInfo field2 = typeof(ChargingStation).GetField("chargeTotal", BindingFlags.Instance | BindingFlags.NonPublic);
					if (field2 != null)
					{
						int num = Mathf.Min(newCrystalCount * 10, 100);
						field2.SetValue(instance, num);
					}
					FieldInfo field3 = typeof(ChargingStation).GetField("chargeFloat", BindingFlags.Instance | BindingFlags.NonPublic);
					if (field3 != null)
					{
						field3.SetValue(instance, (float)newCrystalCount / 10f);
					}
					FieldInfo field4 = typeof(ChargingStation).GetField("chargeSegmentCurrent", BindingFlags.Instance | BindingFlags.NonPublic);
					if (field4 != null)
					{
						field4.SetValue(instance, Mathf.RoundToInt((float)newCrystalCount / 10f * 40f));
					}
					FieldInfo field5 = typeof(ChargingStation).GetField("chargeScaleTarget", BindingFlags.Instance | BindingFlags.NonPublic);
					if (field5 != null)
					{
						field5.SetValue(instance, (float)newCrystalCount / 10f);
					}
					Plugin.Logger.LogInfo((object)$"Updated charging station visuals: {newCrystalCount}/{10} crystals");
				}
			}
			catch (Exception arg)
			{
				Plugin.Logger.LogError((object)$"Error updating charging station visuals: {arg}");
			}
		}

		[HarmonyPatch(typeof(ChargingStation), "Start")]
		[HarmonyPostfix]
		private static void ChargingStation_Start_Postfix(ChargingStation __instance)
		{
			try
			{
				Plugin.Logger.LogDebug((object)"Charging Station initialized");
				if ((Object)(object)StatsManager.instance != (Object)null && StatsManager.instance.itemsPurchased.ContainsKey("Item Power Crystal"))
				{
					int newCrystalCount = Mathf.Min(StatsManager.instance.itemsPurchased["Item Power Crystal"], 10);
					KeyPressMethod_UpdateChargingStationVisuals(newCrystalCount);
				}
			}
			catch (Exception arg)
			{
				Plugin.Logger.LogError((object)$"Error in ChargingStation Start patch: {arg}");
			}
		}

		private static void KeyPressMethod_RemovePowerCrystal(PhysGrabObject powerCrystal, PlayerAvatar playerAvatar)
		{
			try
			{
				PhysGrabber component = ((Component)playerAvatar).GetComponent<PhysGrabber>();
				if ((Object)(object)component != (Object)null && (Object)(object)component.grabbedPhysGrabObject == (Object)(object)powerCrystal)
				{
					MethodInfo method = typeof(PhysGrabber).GetMethod("ReleaseObject", BindingFlags.Instance | BindingFlags.Public);
					if (method != null)
					{
						method.Invoke(component, new object[2]
						{
							powerCrystal.photonView.ViewID,
							1f
						});
					}
					else
					{
						component.grabbed = false;
						component.grabbedPhysGrabObject = null;
					}
				}
				if (powerCrystal.playerGrabbing.Contains(component))
				{
					powerCrystal.playerGrabbing.Remove(component);
				}
				if (GameManager.Multiplayer())
				{
					if (PhotonNetwork.IsMasterClient)
					{
						powerCrystal.DestroyPhysGrabObject();
					}
				}
				else
				{
					powerCrystal.DestroyPhysGrabObject();
				}
				Plugin.Logger.LogDebug((object)"Power Crystal removed from scene (key press method)");
			}
			catch (Exception arg)
			{
				Plugin.Logger.LogError((object)$"Error removing Power Crystal (key press method): {arg}");
			}
		}

		[HarmonyPatch(typeof(RoundDirector), "Update")]
		[HarmonyPrefix]
		private static bool RoundDirector_Update_Prefix(RoundDirector __instance)
		{
			try
			{
				__instance.currentHaul = 0;
				__instance.currentHaulMax = 0;
				if (__instance.dollarHaulList == null)
				{
					return true;
				}
				if (__instance.dollarHaulList.Count <= 0)
				{
					return true;
				}
				List<GameObject> list = new List<GameObject>();
				List<GameObject> list2 = new List<GameObject>();
				for (int i = 0; i < __instance.dollarHaulList.Count; i++)
				{
					GameObject val = __instance.dollarHaulList[i];
					if ((Object)(object)val == (Object)null)
					{
						list.Add(val);
						continue;
					}
					ValuableObject component = val.GetComponent<ValuableObject>();
					if ((Object)(object)component == (Object)null)
					{
						list.Add(val);
					}
					else
					{
						list2.Add(val);
					}
				}
				foreach (GameObject item in list2)
				{
					if (!((Object)(object)item == (Object)null))
					{
						ValuableObject component2 = item.GetComponent<ValuableObject>();
						if (!((Object)(object)component2 == (Object)null))
						{
							__instance.currentHaul += (int)component2.dollarValueCurrent;
							__instance.currentHaulMax += (int)component2.dollarValueOriginal;
						}
					}
				}
				foreach (GameObject item2 in list)
				{
					__instance.dollarHaulList.Remove(item2);
				}
				return false;
			}
			catch (Exception arg)
			{
				Plugin.Logger.LogError((object)$"Error in while trying to fix/patch RoundDirector.Update: {arg}");
				return true;
			}
		}

		[HarmonyPatch(typeof(ExtractionPoint), "DestroyTheFirstPhysObjectsInHaulList")]
		[HarmonyPrefix]
		private static bool ExtractionPoint_DestroyTheFirstPhysObjectsInHaulList_Prefix(ExtractionPoint __instance)
		{
			if (!modEnabled || !extractionMethodEnabled)
			{
				return true;
			}
			try
			{
				ProcessPowerCrystalsInExtractionArea(__instance);
				return true;
			}
			catch (Exception arg)
			{
				Plugin.Logger.LogError((object)$"Error in Power Crystal extraction (first): {arg}");
				return true;
			}
		}

		[HarmonyPatch(typeof(ExtractionPoint), "DestroyAllPhysObjectsInHaulList")]
		[HarmonyPrefix]
		private static bool ExtractionPoint_DestroyAllPhysObjectsInHaulList_Prefix(ExtractionPoint __instance)
		{
			if (!modEnabled || !extractionMethodEnabled)
			{
				return true;
			}
			try
			{
				ProcessPowerCrystalsInExtractionArea(__instance);
				return true;
			}
			catch (Exception arg)
			{
				Plugin.Logger.LogError((object)$"Error in Power Crystal bulk extraction: {arg}");
				return true;
			}
		}

		private static void ProcessPowerCrystalsInExtractionArea(ExtractionPoint extractionPoint)
		{
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (!CanCollectMoreCrystals())
				{
					Plugin.Logger.LogInfo((object)"Crystal limit reached, skipping extraction processing");
					return;
				}
				ItemAttributes[] array = Object.FindObjectsOfType<ItemAttributes>();
				ItemAttributes[] array2 = array;
				foreach (ItemAttributes val in array2)
				{
					if (!CanCollectMoreCrystals())
					{
						Plugin.Logger.LogInfo((object)"Crystal limit reached during extraction processing");
						break;
					}
					if ((Object)(object)val == (Object)null || (Object)(object)val.item == (Object)null)
					{
						continue;
					}
					FieldInfo field = ((object)val.item).GetType().GetField("itemType");
					if (field == null)
					{
						continue;
					}
					object value = field.GetValue(val.item);
					if (value.ToString() != "power_crystal")
					{
						continue;
					}
					RoomVolumeCheck component = ((Component)val).GetComponent<RoomVolumeCheck>();
					if ((Object)(object)component == (Object)null)
					{
						continue;
					}
					bool flag = false;
					foreach (RoomVolume currentRoom in component.CurrentRooms)
					{
						if (!((Object)(object)currentRoom != (Object)null) || !currentRoom.Extraction)
						{
							continue;
						}
						Collider component2 = ((Component)currentRoom).GetComponent<Collider>();
						if ((Object)(object)component2 != (Object)null)
						{
							Bounds bounds = component2.bounds;
							if (((Bounds)(ref bounds)).Contains(((Component)val).transform.position))
							{
								flag = true;
								break;
							}
						}
					}
					if (flag)
					{
						HandlePowerCrystalExtraction(((Component)val).gameObject, val, extractionPoint);
					}
				}
			}
			catch (Exception arg)
			{
				Plugin.Logger.LogError((object)$"Error processing power crystals in extraction area: {arg}");
			}
		}

		private static void HandlePowerCrystalExtraction(GameObject powerCrystalObject, ItemAttributes itemAttributes, ExtractionPoint extractionPoint)
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if ((Object)(object)powerCrystalObject == (Object)null || (Object)(object)itemAttributes == (Object)null)
				{
					return;
				}
				if (!CanCollectMoreCrystals())
				{
					Plugin.Logger.LogInfo((object)"Crystal limit reached, skipping extraction");
					return;
				}
				PlayerAvatar val = FindClosestPlayer(((Component)extractionPoint).transform.position);
				if (!((Object)(object)val == (Object)null))
				{
					string itemName = itemAttributes.itemName;
					string powerCrystalKey = Plugin.GetPowerCrystalKey(itemName);
					Plugin.Logger.LogError((object)("Extraction method: Processing Power Crystal: " + itemName));
					UpdatePowerCrystalStats(powerCrystalKey, itemName, val);
					if ((Object)(object)RoundDirector.instance != (Object)null && RoundDirector.instance.dollarHaulList != null)
					{
						RoundDirector.instance.dollarHaulList.Remove(powerCrystalObject);
					}
					PhysGrabObject component = powerCrystalObject.GetComponent<PhysGrabObject>();
					if ((Object)(object)component != (Object)null)
					{
						component.DestroyPhysGrabObject();
					}
					else
					{
						Object.Destroy((Object)(object)powerCrystalObject);
					}
					Plugin.Logger.LogInfo((object)("Power Crystal extracted: " + itemName));
				}
			}
			catch (Exception arg)
			{
				Plugin.Logger.LogError((object)$"Error handling power crystal extraction: {arg}");
			}
		}

		private static void UpdatePowerCrystalStats(string itemKey, string displayName, PlayerAvatar playerAvatar)
		{
			try
			{
				if (GameManager.Multiplayer() && !PhotonNetwork.IsMasterClient)
				{
					return;
				}
				Plugin.Logger.LogInfo((object)("Updating Power Crystal stats: " + displayName));
				if (!((Object)(object)StatsManager.instance != (Object)null))
				{
					return;
				}
				if (!StatsManager.instance.itemsPurchased.ContainsKey(itemKey))
				{
					StatsManager.instance.itemsPurchased[itemKey] = 0;
					StatsManager.instance.itemsPurchasedTotal[itemKey] = 0;
				}
				int num = StatsManager.instance.itemsPurchased[itemKey];
				int num2 = StatsManager.instance.itemsPurchasedTotal[itemKey];
				if (num >= 10)
				{
					Plugin.Logger.LogInfo((object)$"Already at crystal limit: {num}/{10}");
					return;
				}
				StatsManager.instance.itemsPurchased[itemKey] = num + 1;
				StatsManager.instance.itemsPurchasedTotal[itemKey] = num2 + 1;
				Plugin.Logger.LogInfo((object)$"Updated stats for '{itemKey}': Purchased={StatsManager.instance.itemsPurchased[itemKey]}/{10}, Total={StatsManager.instance.itemsPurchasedTotal[itemKey]}");
				UpdateChargingStationStats(itemKey, num + 1);
				if (GameManager.Multiplayer() && (Object)(object)PunManager.instance != (Object)null)
				{
					PunManager.instance.UpdateStat("itemsPurchased", itemKey, StatsManager.instance.itemsPurchased[itemKey]);
					PunManager.instance.UpdateStat("itemsPurchasedTotal", itemKey, StatsManager.instance.itemsPurchasedTotal[itemKey]);
				}
				UpdateChargingStationVisuals(num + 1);
				if ((Object)(object)playerAvatar.photonView != (Object)null && playerAvatar.photonView.IsMine)
				{
					ShowCollectionNotification(playerAvatar, displayName, fromExtraction: true, num + 1);
				}
			}
			catch (Exception arg)
			{
				Plugin.Logger.LogError((object)$"Error updating Power Crystal stats (extraction method): {arg}");
			}
		}

		private static void UpdateChargingStationStats(string itemKey, int newCrystalCount)
		{
			try
			{
				newCrystalCount = Mathf.Min(newCrystalCount, 10);
				if (StatsManager.instance.runStats.ContainsKey("chargingStationCharge"))
				{
					StatsManager.instance.runStats["chargingStationCharge"] = newCrystalCount;
				}
				else
				{
					StatsManager.instance.runStats.Add("chargingStationCharge", newCrystalCount);
				}
				int num = 100;
				int num2 = 10;
				int num3 = Mathf.Min(newCrystalCount * num2, num);
				int num4 = num;
				if (StatsManager.instance.runStats.ContainsKey("chargingStationChargeTotal"))
				{
					num4 = StatsManager.instance.runStats["chargingStationChargeTotal"];
				}
				else
				{
					StatsManager.instance.runStats.Add("chargingStationChargeTotal", num3);
				}
				if (num4 < num3)
				{
					StatsManager.instance.runStats["chargingStationChargeTotal"] = num3;
				}
				Plugin.Logger.LogInfo((object)string.Format("Updated charging station: Crystals={0}/{1}, Capacity={2}", newCrystalCount, 10, StatsManager.instance.runStats["chargingStationChargeTotal"]));
				if (StatsManager.instance.itemDictionary.ContainsKey(itemKey))
				{
					Item val = StatsManager.instance.itemDictionary[itemKey];
					if ((Object)(object)val != (Object)null)
					{
						StatsManager.instance.SetItemPurchase(val, newCrystalCount);
					}
				}
			}
			catch (Exception arg)
			{
				Plugin.Logger.LogError((object)$"Error updating charging station stats (extraction method): {arg}");
			}
		}

		private static void UpdateChargingStationVisuals(int newCrystalCount)
		{
			try
			{
				newCrystalCount = Mathf.Min(newCrystalCount, 10);
				ChargingStation instance = ChargingStation.instance;
				if ((Object)(object)instance != (Object)null)
				{
					FieldInfo field = typeof(ChargingStation).GetField("chargeInt", BindingFlags.Instance | BindingFlags.NonPublic);
					if (field != null)
					{
						field.SetValue(instance, newCrystalCount);
					}
					Plugin.Logger.LogInfo((object)$"Updated charging station visuals: {newCrystalCount}/{10} crystals");
				}
			}
			catch (Exception arg)
			{
				Plugin.Logger.LogError((object)$"Error updating charging station visuals (extraction method): {arg}");
			}
		}

		private static PlayerAvatar FindClosestPlayer(Vector3 position)
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				PlayerAvatar result = null;
				float num = float.MaxValue;
				if (GameManager.Multiplayer())
				{
					foreach (PlayerAvatar player in GameDirector.instance.PlayerList)
					{
						if (!((Object)(object)player == (Object)null) && !player.isDisabled)
						{
							float num2 = Vector3.Distance(((Component)player).transform.position, position);
							if (num2 < num)
							{
								num = num2;
								result = player;
							}
						}
					}
				}
				else
				{
					PlayerController instance = PlayerController.instance;
					if ((Object)(object)instance != (Object)null && (Object)(object)instance.playerAvatarScript != (Object)null)
					{
						result = instance.playerAvatarScript;
					}
				}
				return result;
			}
			catch (Exception)
			{
				return null;
			}
		}

		private static void ShowCollectionNotification(PlayerAvatar playerAvatar, string crystalName, bool fromExtraction, int newCount)
		{
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				string text = (fromExtraction ? "Extracted" : "Collected");
				string text2 = $"{crystalName} {text}! ({newCount}/{10} to Charging Station)";
				Type type = Type.GetType("ItemInfoExtraUI, Assembly-CSharp");
				if (type != null)
				{
					PropertyInfo property = type.GetProperty("instance", BindingFlags.Static | BindingFlags.Public);
					if (property != null)
					{
						object value = property.GetValue(null);
						if (value != null)
						{
							MethodInfo method = type.GetMethod("ItemInfoText", new Type[2]
							{
								typeof(string),
								typeof(Color)
							});
							if (method != null)
							{
								Color val = ((newCount < 10) ? Color.green : Color.yellow);
								method.Invoke(value, new object[2] { text2, val });
								return;
							}
						}
					}
				}
				Plugin.Logger.LogInfo((object)text2);
			}
			catch (Exception arg)
			{
				Debug.LogError((object)$"Error showing notification: {arg}");
			}
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "Jettcodey.ExtractCrystalsInLevels";

		public const string PLUGIN_NAME = "ExtractCrystalsInLevels";

		public const string PLUGIN_VERSION = "1.0.0";
	}
}