Decompiled source of WisplightUpgrades v1.0.1

WisplightUpgrades.dll

Decompiled 16 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using ConditionalConfigSync;
using HarmonyLib;
using ItemDataManager;
using Jewelcrafting;
using Jewelcrafting.GemEffects;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("WisplightUpgrades")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.1.0")]
[assembly: AssemblyInformationalVersion("1.0.1")]
[assembly: AssemblyProduct("WisplightUpgrades")]
[assembly: AssemblyTitle("WisplightUpgrades")]
[assembly: AssemblyVersion("1.0.1.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[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 WisplightUpgrades
{
	[BepInPlugin("com.dreich.wisplightupgrades", "Wisplight Upgrades", "1.0.1")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class WisplightUpgradesPlugin : BaseUnityPlugin
	{
		public const string Guid = "com.dreich.wisplightupgrades";

		public const string Name = "Wisplight Upgrades";

		public const string Version = "1.0.1";

		internal const string ConfigSyncGuid = "_shudnal.ConditionalConfigSync";

		internal const string JewelcraftingGuid = "org.bepinex.plugins.jewelcrafting";

		internal static bool ConfigSyncAvailable;

		internal static bool JewelcraftingAvailable;

		private static ConfigEntry<bool> ConfigLockedEntry;

		internal static ConfigEntry<int> MaxLevel;

		internal static ConfigEntry<string> UpgradeCost;

		internal static ConfigEntry<string> ReferenceGem;

		internal static ConfigEntry<float> FailRefundMin;

		internal static ConfigEntry<float> FailRefundMax;

		internal static ConfigEntry<int> RequiredTableLevel;

		internal static ConfigEntry<float> RangePerLevel;

		private void Awake()
		{
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Expected O, but got Unknown
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Expected O, but got Unknown
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Expected O, but got Unknown
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Expected O, but got Unknown
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			//IL_0160: 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_01bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c5: Expected O, but got Unknown
			//IL_0221: Unknown result type (might be due to invalid IL or missing references)
			//IL_0227: Expected O, but got Unknown
			ConfigSyncAvailable = Chainloader.PluginInfos.ContainsKey("_shudnal.ConditionalConfigSync");
			if (ConfigSyncAvailable)
			{
				ConfigSyncCompat.Initialize("com.dreich.wisplightupgrades", "Wisplight Upgrades", "1.0.1");
			}
			JewelcraftingAvailable = Chainloader.PluginInfos.ContainsKey("org.bepinex.plugins.jewelcrafting");
			ConfigLockedEntry = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Lock Configuration", true, "If on, the configuration is locked and can be changed by server admins only. Requires ConditionalConfigSync.");
			if (ConfigSyncAvailable)
			{
				ConfigSyncCompat.AddLockingConfigEntry(ConfigLockedEntry);
			}
			MaxLevel = BindShared("Upgrades", "MaxLevel", 3, new ConfigDescription("How many times a Wisplight can be upgraded. With Jewelcrafting, the first three upgrades match the Simple, Advanced and Perfect gem tiers, and any upgrades past the third use the Perfect chance.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 10), Array.Empty<object>()));
			UpgradeCost = BindShared("Upgrades", "UpgradeCost", "Wisp:5,Silver:5,BlackCore:1", new ConfigDescription("Materials for the first upgrade, as comma-separated ItemPrefab:Amount pairs. Later upgrades cost more: the second upgrade costs twice these amounts, the third three times, and so on.", (AcceptableValueBase)null, Array.Empty<object>()));
			ReferenceGem = BindShared("Upgrades", "ReferenceGemColor", "Purple", new ConfigDescription("Jewelcrafting only. Gem color whose cutting chances the upgrades use, taken from Jewelcrafting's Socket Upgrade Chances settings and adjusted by the Jewelcrafting skill. The first upgrade uses the Simple gem chance, the second the Advanced gem chance and the third the Perfect gem chance. Purple is Spinel. A failed upgrade destroys the Wisplight and gives back a random share of the materials put into it.", (AcceptableValueBase)null, Array.Empty<object>()));
			FailRefundMin = BindShared("Upgrades", "FailRefundMinPercent", 25f, new ConfigDescription("Jewelcrafting only. Smallest share, in percent, of each material put into the Wisplight that is given back when an upgrade fails. Counts the Wisplight's own crafting materials, every upgrade it already had, and the failed attempt.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>()));
			FailRefundMax = BindShared("Upgrades", "FailRefundMaxPercent", 75f, new ConfigDescription("Jewelcrafting only. Largest share, in percent, of each material given back when an upgrade fails. Each material rolls its own amount between the minimum and this value.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>()));
			RequiredTableLevel = BindShared("Upgrades", "RequiredTableLevel", 1, new ConfigDescription("Level of the upgrade station needed for every Wisplight upgrade: the Gemcutters Table with Jewelcrafting, the Workbench without it.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 10), Array.Empty<object>()));
			RangePerLevel = BindShared("Mist", "RangeIncreasePerLevel", 25f, new ConfigDescription("Percent added to the Wisplight's mist clearing radius for each upgrade level.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 200f), Array.Empty<object>()));
			MaxLevel.SettingChanged += delegate
			{
				WisplightUpgrade.Apply();
			};
			UpgradeCost.SettingChanged += delegate
			{
				WisplightUpgrade.Apply();
			};
			Harmony val = (ZenUICompat.Harmony = new Harmony("com.dreich.wisplightupgrades"));
			val.PatchAll();
			if (JewelcraftingAvailable)
			{
				JewelcraftingCompat.PatchSockets(val);
			}
		}

		private ConfigEntry<T> BindShared<T>(string section, string key, T defaultValue, ConfigDescription description)
		{
			ConfigEntry<T> val = ((BaseUnityPlugin)this).Config.Bind<T>(section, key, defaultValue, description);
			if (ConfigSyncAvailable)
			{
				ConfigSyncCompat.AddConfigEntry<T>(val, serverControlled: true);
			}
			return val;
		}
	}
	internal static class ConfigSyncCompat
	{
		private static object configSync;

		[MethodImpl(MethodImplOptions.NoInlining)]
		internal static void Initialize(string guid, string name, string version)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: 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_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Expected O, but got Unknown
			configSync = (object)new ConfigSync(guid)
			{
				DisplayName = name,
				CurrentVersion = version,
				MinimumRequiredVersion = version,
				ModRequired = false,
				ModRequirementMode = (ModRequirementMode)1
			};
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		internal static void AddLockingConfigEntry(ConfigEntry<bool> entry)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			((ConditionalConfigSync)(ConfigSync)configSync).AddLockingConfigEntry<bool>(entry);
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		internal static void AddConfigEntry<T>(ConfigEntry<T> entry, bool serverControlled)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			((ConditionalConfigSync)(ConfigSync)configSync).AddConfigEntry<T>(entry, (ConfigSyncMode)((!serverControlled) ? 2 : 0));
		}
	}
	internal static class JewelcraftingCompat
	{
		private const string SkillName = "Jewelcrafting";

		private static MethodInfo factorMethod;

		private static MethodInfo raiseMethod;

		private static bool skillLookupDone;

		private static FieldInfo displayGemChanceField;

		private static bool displayLookupDone;

		[MethodImpl(MethodImplOptions.NoInlining)]
		internal static void PatchSockets(Harmony harmony)
		{
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Expected O, but got Unknown
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Expected O, but got Unknown
			try
			{
				MethodInfo methodInfo = AccessTools.Method(typeof(Socketable), "SaveSocketsInventory", (Type[])null, (Type[])null);
				MethodInfo methodInfo2 = AccessTools.Method(typeof(Socketable), "ReadInventory", (Type[])null, (Type[])null);
				harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(AccessTools.Method(typeof(JewelcraftingCompat), "SaveSocketsPostfix", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				harmony.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, new HarmonyMethod(AccessTools.Method(typeof(JewelcraftingCompat), "ReadSocketsPostfix", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
			catch
			{
			}
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		private static void SaveSocketsPostfix(Socketable __instance, Inventory inv)
		{
			try
			{
				SocketLevels.Save(((ItemData)__instance).Item, inv);
			}
			catch
			{
			}
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		private static void ReadSocketsPostfix(Socketable __instance, Inventory __result)
		{
			try
			{
				SocketLevels.Restore(((ItemData)__instance).Item, __result);
			}
			catch
			{
			}
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		internal static void ShowCuttingChance(InventoryGui gui, float chance)
		{
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			if (!displayLookupDone)
			{
				displayLookupDone = true;
				Type type = typeof(Jewelcrafting).Assembly.GetType("Jewelcrafting.GemStones+ChangeDisplay");
				displayGemChanceField = ((type != null) ? AccessTools.Field(type, "displayGemChance") : null);
			}
			int num = Mathf.RoundToInt(chance * 100f);
			string text = ((num >= 100) ? "" : Localization.instance.Localize("$jc_gem_cutting_warning", new string[1] { num.ToString(CultureInfo.InvariantCulture) }));
			gui.m_itemCraftType.text = text;
			((Component)gui.m_itemCraftType).gameObject.SetActive(true);
			try
			{
				gui.m_itemCraftType.textWrappingMode = (TextWrappingModes)1;
			}
			catch
			{
			}
			try
			{
				if (displayGemChanceField != null && !(bool)displayGemChanceField.GetValue(null))
				{
					RectTransform component = ((Component)gui.m_recipeDecription).GetComponent<RectTransform>();
					component.sizeDelta = new Vector2(component.sizeDelta.x, component.sizeDelta.y - 30f);
					component.anchoredPosition = new Vector2(component.anchoredPosition.x, component.anchoredPosition.y + 15f);
					displayGemChanceField.SetValue(null, true);
				}
			}
			catch
			{
			}
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		internal static CraftingStation GemcuttersTable()
		{
			GameObject gemcuttersTable = API.GetGemcuttersTable();
			if (!((Object)(object)gemcuttersTable != (Object)null))
			{
				return null;
			}
			return gemcuttersTable.GetComponent<CraftingStation>();
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		internal static List<string> SocketedGemPrefabs(ItemData item)
		{
			List<string> list = new List<string>();
			List<GemInfo> gems = API.GetGems(item);
			if (gems == null)
			{
				return list;
			}
			foreach (GemInfo item2 in gems)
			{
				list.Add(item2?.gemPrefab);
			}
			return list;
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		internal static float WisplightPower(Player player)
		{
			return Utils.GetEffect(player, (Effect)88);
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		internal static float CuttingChance(Player player, string gemName, out bool found)
		{
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Invalid comparison between Unknown and I4
			found = Jewelcrafting.gemUpgradeChances.TryGetValue(gemName, out var value);
			float num = (found ? (Mathf.Clamp(value.Value, 0f, 100f) / 100f) : 1f);
			if (!found || (Object)(object)player == (Object)null)
			{
				return num;
			}
			float num2 = SkillFactor(player) * (float)Jewelcrafting.upgradeChanceIncrease.Value / 100f;
			num = (((int)Jewelcrafting.additiveSkillBonus.Value != 1) ? (num * (1f + num2)) : (num + num2));
			return num + Utils.GetEffect(player, (Effect)78) / 100f;
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		private static void FindSkillMethods()
		{
			if (!skillLookupDone)
			{
				skillLookupDone = true;
				Type type = typeof(Jewelcrafting).Assembly.GetType("SkillManager.SkillExtensions");
				factorMethod = type?.GetMethod("GetSkillFactor", BindingFlags.Static | BindingFlags.Public, null, new Type[2]
				{
					typeof(Character),
					typeof(string)
				}, null);
				raiseMethod = type?.GetMethod("RaiseSkill", BindingFlags.Static | BindingFlags.Public, null, new Type[3]
				{
					typeof(Character),
					typeof(string),
					typeof(float)
				}, null);
			}
		}

		private static float SkillFactor(Player player)
		{
			FindSkillMethods();
			if (factorMethod == null)
			{
				return 0f;
			}
			try
			{
				return (float)factorMethod.Invoke(null, new object[2] { player, "Jewelcrafting" });
			}
			catch
			{
				return 0f;
			}
		}

		internal static void RaiseSkill(Player player)
		{
			FindSkillMethods();
			if (raiseMethod == null)
			{
				return;
			}
			try
			{
				raiseMethod.Invoke(null, new object[3] { player, "Jewelcrafting", 1f });
			}
			catch
			{
			}
		}
	}
	internal static class ZenUICompat
	{
		internal static Harmony Harmony;

		private static bool attempted;

		internal static void TryPatch()
		{
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Expected O, but got Unknown
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Expected O, but got Unknown
			if (attempted || Harmony == null)
			{
				return;
			}
			attempted = true;
			try
			{
				Type type = AccessTools.TypeByName("ZenUI.Section.CraftingPanel");
				if (!(type == null))
				{
					MethodInfo methodInfo = AccessTools.Method(type, "InventoryGui_AddRecipeToList", (Type[])null, (Type[])null);
					if (methodInfo != null)
					{
						Harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(AccessTools.Method(typeof(ZenUICompat), "AddRecipePrefix", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
					}
					MethodInfo methodInfo2 = AccessTools.Method(type, "GetRecipeItemClone", (Type[])null, (Type[])null);
					if (methodInfo2 != null)
					{
						Harmony.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, new HarmonyMethod(AccessTools.Method(typeof(ZenUICompat), "ClonePostfix", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
					}
				}
			}
			catch
			{
			}
		}

		private static bool AddRecipePrefix(Recipe recipe, ItemData item)
		{
			if (item == null)
			{
				return !WisplightUpgrade.IsOwnRecipe(recipe);
			}
			return true;
		}

		private static void ClonePostfix(Recipe recipe, ItemData __result)
		{
			int num = WisplightUpgrade.LevelOf(recipe);
			if (num > 0 && __result != null)
			{
				__result.m_quality = num;
			}
		}
	}
	internal static class WisplightUpgrade
	{
		internal const string PrefabName = "Demister";

		private const string WorkbenchPrefab = "piece_workbench";

		private static Recipe recipe;

		private static ItemDrop demister;

		private static readonly List<Recipe> levelRecipes = new List<Recipe>();

		private static readonly Dictionary<Recipe, int> recipeLevels = new Dictionary<Recipe, int>();

		internal static Recipe Recipe => recipe;

		internal static bool IsOwnRecipe(Recipe candidate)
		{
			if ((Object)(object)candidate != (Object)null)
			{
				if (candidate != recipe)
				{
					return recipeLevels.ContainsKey(candidate);
				}
				return true;
			}
			return false;
		}

		internal static int LevelOf(Recipe candidate)
		{
			if (!((Object)(object)candidate != (Object)null) || !recipeLevels.TryGetValue(candidate, out var value))
			{
				return 0;
			}
			return value;
		}

		internal static bool IsWisplight(ItemData item)
		{
			if (item != null && item.m_shared != null && (Object)(object)demister != (Object)null)
			{
				return item.m_shared.m_name == demister.m_itemData.m_shared.m_name;
			}
			return false;
		}

		internal static bool IsWisplightRecipe(Recipe candidate)
		{
			if ((Object)(object)candidate != (Object)null && (Object)(object)candidate.m_item != (Object)null && (Object)(object)demister != (Object)null)
			{
				return candidate.m_item.m_itemData.m_shared.m_name == demister.m_itemData.m_shared.m_name;
			}
			return false;
		}

		private static CraftingStation UpgradeStation()
		{
			if (WisplightUpgradesPlugin.JewelcraftingAvailable)
			{
				return JewelcraftingCompat.GemcuttersTable();
			}
			if ((Object)(object)ZNetScene.instance == (Object)null)
			{
				return null;
			}
			GameObject prefab = ZNetScene.instance.GetPrefab("piece_workbench");
			if (!((Object)(object)prefab != (Object)null))
			{
				return null;
			}
			return prefab.GetComponent<CraftingStation>();
		}

		internal static void Apply()
		{
			try
			{
				ObjectDB instance = ObjectDB.instance;
				if ((Object)(object)instance == (Object)null)
				{
					return;
				}
				GameObject itemPrefab = instance.GetItemPrefab("Demister");
				demister = (((Object)(object)itemPrefab != (Object)null) ? itemPrefab.GetComponent<ItemDrop>() : null);
				if ((Object)(object)demister == (Object)null)
				{
					return;
				}
				demister.m_itemData.m_shared.m_maxQuality = 1 + WisplightUpgradesPlugin.MaxLevel.Value;
				CraftingStation val = UpgradeStation();
				if ((Object)(object)val == (Object)null)
				{
					return;
				}
				Requirement[] requirements = BuildRequirements(instance);
				recipeLevels.Clear();
				if (!WisplightUpgradesPlugin.JewelcraftingAvailable)
				{
					if ((Object)(object)recipe == (Object)null)
					{
						recipe = CreateRecipe("Recipe_WisplightUpgrade");
					}
					Configure(recipe, val, requirements, upgradeTabOnly: true);
					if (!instance.m_recipes.Contains(recipe))
					{
						instance.m_recipes.Add(recipe);
					}
					return;
				}
				int value = WisplightUpgradesPlugin.MaxLevel.Value;
				for (int i = 0; i < Mathf.Max(value, levelRecipes.Count); i++)
				{
					if (i >= levelRecipes.Count)
					{
						levelRecipes.Add(null);
					}
					if (i >= value)
					{
						if ((Object)(object)levelRecipes[i] != (Object)null)
						{
							instance.m_recipes.Remove(levelRecipes[i]);
						}
						continue;
					}
					if ((Object)(object)levelRecipes[i] == (Object)null)
					{
						levelRecipes[i] = CreateRecipe("Recipe_WisplightUpgrade_" + (i + 1).ToString(CultureInfo.InvariantCulture));
					}
					Recipe val2 = levelRecipes[i];
					Configure(val2, val, requirements, upgradeTabOnly: false);
					recipeLevels[val2] = i + 1;
					if (!instance.m_recipes.Contains(val2))
					{
						instance.m_recipes.Add(val2);
					}
				}
				recipe = ((levelRecipes.Count > 0) ? levelRecipes[0] : null);
			}
			catch
			{
			}
		}

		private static Recipe CreateRecipe(string name)
		{
			Recipe obj = ScriptableObject.CreateInstance<Recipe>();
			((Object)obj).name = name;
			return obj;
		}

		private static void Configure(Recipe target, CraftingStation station, Requirement[] requirements, bool upgradeTabOnly)
		{
			target.m_item = demister;
			target.m_amount = 1;
			target.m_enabled = true;
			target.m_noCraftOnlyUpgrade = upgradeTabOnly;
			target.m_craftingStation = station;
			target.m_minStationLevel = 1;
			target.m_resources = requirements;
		}

		private static Requirement[] BuildRequirements(ObjectDB db)
		{
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: 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_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Expected O, but got Unknown
			List<Requirement> list = new List<Requirement>();
			string[] array = (WisplightUpgradesPlugin.UpgradeCost.Value ?? "").Split(new char[1] { ',' });
			for (int i = 0; i < array.Length; i++)
			{
				string text = array[i].Trim();
				if (text.Length == 0)
				{
					continue;
				}
				string[] array2 = text.Split(new char[1] { ':' });
				if (array2.Length == 2 && int.TryParse(array2[1].Trim(), NumberStyles.Integer, CultureInfo.InvariantCulture, out var result) && result > 0)
				{
					string text2 = array2[0].Trim();
					GameObject itemPrefab = db.GetItemPrefab(text2);
					ItemDrop val = (((Object)(object)itemPrefab != (Object)null) ? itemPrefab.GetComponent<ItemDrop>() : null);
					if (!((Object)(object)val == (Object)null))
					{
						list.Add(new Requirement
						{
							m_resItem = val,
							m_amount = result,
							m_amountPerLevel = result,
							m_recover = false
						});
					}
				}
			}
			return list.ToArray();
		}

		private static void AddInvested(Dictionary<string, int> invested, Requirement requirement, int amount)
		{
			if (requirement != null && !((Object)(object)requirement.m_resItem == (Object)null) && amount > 0)
			{
				string name = ((Object)((Component)requirement.m_resItem).gameObject).name;
				invested.TryGetValue(name, out var value);
				invested[name] = value + amount;
			}
		}

		internal static Dictionary<string, int> RollRefund(int attemptedQuality)
		{
			Dictionary<string, int> dictionary = new Dictionary<string, int>();
			ObjectDB instance = ObjectDB.instance;
			if ((Object)(object)instance != (Object)null)
			{
				foreach (Recipe recipe in instance.m_recipes)
				{
					if (!IsOwnRecipe(recipe) && IsWisplightRecipe(recipe) && recipe.m_resources != null)
					{
						Requirement[] resources = recipe.m_resources;
						foreach (Requirement val in resources)
						{
							AddInvested(dictionary, val, val?.m_amount ?? 0);
						}
						break;
					}
				}
			}
			if ((Object)(object)WisplightUpgrade.recipe != (Object)null && WisplightUpgrade.recipe.m_resources != null)
			{
				for (int j = 2; j <= attemptedQuality; j++)
				{
					Requirement[] resources = WisplightUpgrade.recipe.m_resources;
					foreach (Requirement val2 in resources)
					{
						AddInvested(dictionary, val2, (val2 != null) ? val2.GetAmount(j) : 0);
					}
				}
			}
			float num = Mathf.Min(WisplightUpgradesPlugin.FailRefundMin.Value, WisplightUpgradesPlugin.FailRefundMax.Value) / 100f;
			float num2 = Mathf.Max(WisplightUpgradesPlugin.FailRefundMin.Value, WisplightUpgradesPlugin.FailRefundMax.Value) / 100f;
			Dictionary<string, int> dictionary2 = new Dictionary<string, int>();
			foreach (KeyValuePair<string, int> item in dictionary)
			{
				int num3 = Mathf.RoundToInt((float)item.Value * Random.Range(num, num2));
				if (num3 > 0)
				{
					dictionary2[item.Key] = num3;
				}
			}
			return dictionary2;
		}

		private static string ReferenceGemName(int upgrade)
		{
			string text = (WisplightUpgradesPlugin.ReferenceGem.Value ?? "").Trim().ToLowerInvariant();
			if (upgrade <= 1)
			{
				return "$jc_" + text + "_socket";
			}
			if (upgrade == 2)
			{
				return "$jc_adv_" + text + "_socket";
			}
			return "$jc_perfect_" + text + "_socket";
		}

		internal static float SuccessChance(Player player, int upgrade)
		{
			if (!WisplightUpgradesPlugin.JewelcraftingAvailable)
			{
				return 1f;
			}
			string gemName = ReferenceGemName(upgrade);
			try
			{
				bool found;
				return Mathf.Clamp01(JewelcraftingCompat.CuttingChance(player, gemName, out found));
			}
			catch
			{
				return 1f;
			}
		}

		internal static int EquippedLevel(Player player)
		{
			int num = 0;
			foreach (ItemData allItem in ((Humanoid)player).GetInventory().GetAllItems())
			{
				if (allItem.m_equipped)
				{
					if (IsWisplight(allItem))
					{
						num = Mathf.Max(num, allItem.m_quality - 1);
					}
					if (WisplightUpgradesPlugin.JewelcraftingAvailable)
					{
						num = Mathf.Max(num, SocketLevels.HighestLevel(allItem));
					}
				}
			}
			return num;
		}

		internal static float RangeFor(Player player, float defaultRange)
		{
			float num = defaultRange;
			if (WisplightUpgradesPlugin.JewelcraftingAvailable)
			{
				try
				{
					float num2 = JewelcraftingCompat.WisplightPower(player);
					if (num2 > 0f)
					{
						num = num2;
					}
				}
				catch
				{
				}
			}
			return num * (1f + WisplightUpgradesPlugin.RangePerLevel.Value / 100f * (float)EquippedLevel(player));
		}
	}
	internal static class SocketLevels
	{
		internal const string Key = "WisplightUpgrades_SocketLevels";

		private static int SlotIndex(ItemData item, int width)
		{
			return item.m_gridPos.x + item.m_gridPos.y * width;
		}

		internal static Dictionary<int, int> Read(ItemData host)
		{
			Dictionary<int, int> dictionary = new Dictionary<int, int>();
			if (host == null || host.m_customData == null || !host.m_customData.TryGetValue("WisplightUpgrades_SocketLevels", out var value))
			{
				return dictionary;
			}
			string[] array = value.Split(new char[1] { ',' });
			for (int i = 0; i < array.Length; i++)
			{
				string[] array2 = array[i].Split(new char[1] { ':' });
				if (array2.Length == 2 && int.TryParse(array2[0], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result) && int.TryParse(array2[1], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result2) && result2 > 1)
				{
					dictionary[result] = result2;
				}
			}
			return dictionary;
		}

		internal static void Save(ItemData host, Inventory inventory)
		{
			if (host == null || host.m_customData == null || inventory == null)
			{
				return;
			}
			int width = Mathf.Max(1, inventory.GetWidth());
			List<string> list = new List<string>();
			foreach (ItemData allItem in inventory.GetAllItems())
			{
				if (WisplightUpgrade.IsWisplight(allItem) && allItem.m_quality > 1)
				{
					list.Add(SlotIndex(allItem, width).ToString(CultureInfo.InvariantCulture) + ":" + allItem.m_quality.ToString(CultureInfo.InvariantCulture));
				}
			}
			if (list.Count == 0)
			{
				host.m_customData.Remove("WisplightUpgrades_SocketLevels");
			}
			else
			{
				host.m_customData["WisplightUpgrades_SocketLevels"] = string.Join(",", list.ToArray());
			}
		}

		internal static void Restore(ItemData host, Inventory inventory)
		{
			if (inventory == null)
			{
				return;
			}
			Dictionary<int, int> dictionary = Read(host);
			if (dictionary.Count == 0)
			{
				return;
			}
			int width = Mathf.Max(1, inventory.GetWidth());
			foreach (ItemData allItem in inventory.GetAllItems())
			{
				if (WisplightUpgrade.IsWisplight(allItem) && dictionary.TryGetValue(SlotIndex(allItem, width), out var value))
				{
					allItem.m_quality = value;
				}
			}
		}

		internal static int HighestLevel(ItemData host)
		{
			Dictionary<int, int> dictionary = Read(host);
			if (dictionary.Count == 0)
			{
				return 0;
			}
			List<string> list;
			try
			{
				list = JewelcraftingCompat.SocketedGemPrefabs(host);
			}
			catch
			{
				return 0;
			}
			int num = 0;
			foreach (KeyValuePair<int, int> item in dictionary)
			{
				if (item.Key >= 0 && item.Key < list.Count && !(list[item.Key] != "Demister"))
				{
					num = Mathf.Max(num, item.Value - 1);
				}
			}
			return num;
		}
	}
	internal class WisplightRange : MonoBehaviour
	{
		private static readonly int RangeKey = StringExtensionMethods.GetStableHashCode("WisplightUpgrades_Range");

		private ZNetView nview;

		private ParticleSystemForceField forceField;

		private float defaultRange;

		private bool spawnedLocally;

		private float nextUpdate;

		private void Awake()
		{
			nview = ((Component)this).GetComponent<ZNetView>();
			forceField = ((Component)this).GetComponentInChildren<ParticleSystemForceField>(true);
			if ((Object)(object)forceField != (Object)null)
			{
				defaultRange = forceField.endRange;
			}
			spawnedLocally = (Object)(object)nview != (Object)null && nview.IsValid() && nview.IsOwner();
		}

		private void Update()
		{
			if (!spawnedLocally || (Object)(object)forceField == (Object)null || (Object)(object)nview == (Object)null || !nview.IsValid() || !nview.IsOwner() || Time.time < nextUpdate)
			{
				return;
			}
			nextUpdate = Time.time + 0.5f;
			Player localPlayer = Player.m_localPlayer;
			if (!((Object)(object)localPlayer == (Object)null))
			{
				float num = WisplightUpgrade.RangeFor(localPlayer, defaultRange);
				ZDO zDO = nview.GetZDO();
				if (!Mathf.Approximately(zDO.GetFloat(RangeKey, 0f), num))
				{
					zDO.Set(RangeKey, num);
				}
			}
		}

		private void LateUpdate()
		{
			if (!((Object)(object)forceField == (Object)null) && !((Object)(object)nview == (Object)null) && nview.IsValid())
			{
				float num = nview.GetZDO().GetFloat(RangeKey, 0f);
				if (num > 0f && !Mathf.Approximately(forceField.endRange, num))
				{
					forceField.endRange = num;
				}
			}
		}
	}
	[HarmonyPatch(typeof(ObjectDB), "Awake")]
	internal static class RegisterUpgradePatch
	{
		[HarmonyPriority(0)]
		private static void Postfix()
		{
			WisplightUpgrade.Apply();
			ZenUICompat.TryPatch();
		}
	}
	[HarmonyPatch(typeof(ZNetScene), "Awake")]
	internal static class SceneSetupPatch
	{
		private static void Postfix(ZNetScene __instance)
		{
			GameObject prefab = __instance.GetPrefab("demister_ball");
			if ((Object)(object)prefab != (Object)null && (Object)(object)prefab.GetComponent<WisplightRange>() == (Object)null)
			{
				prefab.AddComponent<WisplightRange>();
			}
			WisplightUpgrade.Apply();
		}
	}
	[HarmonyPatch(typeof(Recipe), "GetRequiredStationLevel")]
	internal static class RequiredTableLevelPatch
	{
		private static void Postfix(Recipe __instance, ref int __result)
		{
			if (WisplightUpgrade.IsOwnRecipe(__instance))
			{
				__result = Mathf.Max(1, WisplightUpgradesPlugin.RequiredTableLevel.Value);
			}
		}
	}
	[HarmonyPatch(typeof(InventoryGui), "UpdateRecipeList")]
	internal static class UpgradeOnlyAtStationPatch
	{
		private static void Prefix(InventoryGui __instance, List<Recipe> recipes)
		{
			if (recipes != null && !((Object)(object)WisplightUpgrade.Recipe == (Object)null) && __instance.InUpradeTab())
			{
				bool keepOwnRecipe = !WisplightUpgradesPlugin.JewelcraftingAvailable;
				recipes.RemoveAll((Recipe candidate) => WisplightUpgrade.IsWisplightRecipe(candidate) && (!keepOwnRecipe || !WisplightUpgrade.IsOwnRecipe(candidate)));
			}
		}
	}
	[HarmonyPatch(typeof(InventoryGui), "AddRecipeToList")]
	internal static class CraftTabUpgradePatch
	{
		private static readonly MethodInfo AddRecipeToList = AccessTools.Method(typeof(InventoryGui), "AddRecipeToList", (Type[])null, (Type[])null);

		[HarmonyPriority(800)]
		private static bool Prefix(InventoryGui __instance, Player player, Recipe recipe, ItemData item)
		{
			if (item != null || !WisplightUpgrade.IsOwnRecipe(recipe))
			{
				return true;
			}
			if (!WisplightUpgradesPlugin.JewelcraftingAvailable || (Object)(object)player == (Object)null || !__instance.InCraftTab())
			{
				return false;
			}
			try
			{
				int num = WisplightUpgrade.LevelOf(recipe);
				ItemData val = null;
				foreach (ItemData allItem in ((Humanoid)player).GetInventory().GetAllItems())
				{
					if (WisplightUpgrade.IsWisplight(allItem) && allItem.m_quality < allItem.m_shared.m_maxQuality && allItem.m_quality == num)
					{
						val = allItem;
						break;
					}
				}
				if (val != null)
				{
					bool flag = player.NoCostCheat() || player.HaveRequirements(recipe, false, val.m_quality + 1, 1);
					AddRecipeToList.Invoke(__instance, new object[4] { player, recipe, val, flag });
				}
			}
			catch
			{
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(InventoryGui), "DoCrafting")]
	internal static class UpgradeAttemptPatch
	{
		private static readonly FieldRef<InventoryGui, Recipe> CraftRecipe = AccessTools.FieldRefAccess<InventoryGui, Recipe>("m_craftRecipe");

		private static readonly FieldRef<InventoryGui, ItemData> CraftUpgradeItem = AccessTools.FieldRefAccess<InventoryGui, ItemData>("m_craftUpgradeItem");

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

		[HarmonyPriority(800)]
		private static bool Prefix(InventoryGui __instance, Player player)
		{
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Recipe val = CraftRecipe.Invoke(__instance);
				ItemData val2 = CraftUpgradeItem.Invoke(__instance);
				if ((Object)(object)val == (Object)null || val2 == null || (Object)(object)player == (Object)null || !WisplightUpgrade.IsWisplight(val2))
				{
					return true;
				}
				if (!WisplightUpgrade.IsOwnRecipe(val))
				{
					return false;
				}
				if (!WisplightUpgradesPlugin.JewelcraftingAvailable)
				{
					return true;
				}
				int num = val2.m_quality + 1;
				if (num > val2.m_shared.m_maxQuality)
				{
					return true;
				}
				bool flag = player.NoCostCheat();
				if (!flag && !player.HaveRequirements(val, false, num, 1))
				{
					return true;
				}
				if (!((Humanoid)player).GetInventory().ContainsItem(val2))
				{
					return true;
				}
				JewelcraftingCompat.RaiseSkill(player);
				if (Random.value < WisplightUpgrade.SuccessChance(player, val2.m_quality))
				{
					return true;
				}
				if (!flag)
				{
					player.ConsumeResources(val.m_resources, num, -1, 1);
				}
				Dictionary<string, int> dictionary = WisplightUpgrade.RollRefund(num);
				Inventory inventory = ((Humanoid)player).GetInventory();
				if (((Humanoid)player).IsItemEquiped(val2))
				{
					((Humanoid)player).UnequipItem(val2, false);
				}
				inventory.RemoveItem(val2);
				foreach (KeyValuePair<string, int> item in dictionary)
				{
					inventory.AddItem(item.Key, item.Value, 1, 0, 0L, "", new Vector2i(-1, -1), false, true, true);
				}
				((Character)player).Message((MessageType)2, (dictionary.Count > 0) ? "Wisplight upgrade failed and the Wisplight was destroyed. Some materials were recovered." : "Wisplight upgrade failed and the Wisplight was destroyed.", 0, (Sprite)null, false);
				UpdateCraftingPanel?.Invoke(__instance, new object[1] { false });
				return false;
			}
			catch
			{
				return true;
			}
		}
	}
	[HarmonyPatch(typeof(InventoryGui), "UpdateRecipe")]
	internal static class SuccessChanceDisplayPatch
	{
		private static readonly FieldInfo SelectedRecipeField = AccessTools.Field(typeof(InventoryGui), "m_selectedRecipe");

		private static PropertyInfo recipeProperty;

		private static PropertyInfo itemProperty;

		[HarmonyPriority(0)]
		[HarmonyAfter(new string[] { "org.bepinex.plugins.jewelcrafting" })]
		private static void Postfix(InventoryGui __instance, Player player)
		{
			try
			{
				if (!WisplightUpgradesPlugin.JewelcraftingAvailable || (Object)(object)WisplightUpgrade.Recipe == (Object)null || SelectedRecipeField == null || (Object)(object)__instance.m_recipeDecription == (Object)null || (Object)(object)__instance.m_itemCraftType == (Object)null)
				{
					return;
				}
				object value = SelectedRecipeField.GetValue(__instance);
				if (value == null)
				{
					return;
				}
				if (recipeProperty == null || itemProperty == null)
				{
					Type type = value.GetType();
					recipeProperty = AccessTools.Property(type, "Recipe");
					itemProperty = AccessTools.Property(type, "ItemData");
					if (recipeProperty == null || itemProperty == null)
					{
						return;
					}
				}
				object? value2 = recipeProperty.GetValue(value, null);
				if (WisplightUpgrade.IsOwnRecipe((Recipe)((value2 is Recipe) ? value2 : null)))
				{
					object? value3 = itemProperty.GetValue(value, null);
					ItemData val = (ItemData)((value3 is ItemData) ? value3 : null);
					if (val != null && val.m_quality < val.m_shared.m_maxQuality)
					{
						JewelcraftingCompat.ShowCuttingChance(__instance, WisplightUpgrade.SuccessChance(player, val.m_quality));
					}
				}
			}
			catch
			{
			}
		}
	}
}