Decompiled source of MoreCrossbows v1.2.9

plugins\MoreCrossbows.dll

Decompiled 3 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using Common;
using HarmonyLib;
using Jotunn;
using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Managers;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using SimpleJson;
using UnityEngine;

[assembly: AssemblyFileVersion("1.2.9")]
[assembly: Guid("e3243d22-4307-4008-ba36-9f326008cde5")]
[assembly: ComVisible(false)]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCopyright("Copyright probablykory © 2023")]
[assembly: AssemblyProduct("MoreCrossbows")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyDescription("https://valheim.thunderstore.io/package/probablykory/MoreCrossbows/")]
[assembly: AssemblyTitle("MoreCrossbows")]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: CompilationRelaxations(8)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("probablykory")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.2.9.0")]
[module: <f4117c6f-0570-4ed1-a416-2af4fafa758a>RefSafetyRules(11)]
[module: UnverifiableCode]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[<265f15d2-d8f1-4bde-90e5-27763607df86>Embedded]
	internal sealed class <265f15d2-d8f1-4bde-90e5-27763607df86>EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[<265f15d2-d8f1-4bde-90e5-27763607df86>Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class <f4117c6f-0570-4ed1-a416-2af4fafa758a>RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public <f4117c6f-0570-4ed1-a416-2af4fafa758a>RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace MoreCrossbows
{
	public static class Extensions
	{
		private static HashSet<CustomRecipe> hashsetRecipes;

		private static Dictionary<string, CustomPrefab> prefabsDict;

		public static bool Remove(this ObjectDB instance, string prefabName)
		{
			if (string.IsNullOrEmpty(prefabName))
			{
				return false;
			}
			GameObject itemPrefab = instance.GetItemPrefab(prefabName);
			if ((Object)(object)itemPrefab != (Object)null)
			{
				instance.m_items.Remove(itemPrefab);
				instance.m_itemByHash.Remove(StringExtensionMethods.GetStableHashCode(((Object)itemPrefab).name));
				return true;
			}
			return false;
		}

		public static Recipe GetRecipe(this List<Recipe> list, Recipe recipe)
		{
			int num = ObjectDB.instance.m_recipes.IndexOf(recipe);
			if (num > -1)
			{
				return list[num];
			}
			string name = ((object)recipe).ToString();
			return ((IEnumerable<Recipe>)ObjectDB.instance.m_recipes).FirstOrDefault((Func<Recipe, bool>)((Recipe r) => name.Equals(((object)r).ToString())));
		}

		public static bool Update(this CustomRecipe recipe, RecipeConfig newRecipe)
		{
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Expected O, but got Unknown
			//IL_01f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0202: Expected O, but got Unknown
			if (hashsetRecipes == null)
			{
				hashsetRecipes = AccessTools.Field(typeof(ItemManager), "Recipes").GetValue(ItemManager.Instance) as HashSet<CustomRecipe>;
				Get.Plugin.LogDebugOnly("Recipes Hashset value retrieved: {hashsetRecipes}");
			}
			Recipe recipe2 = ObjectDB.instance.m_recipes.GetRecipe(recipe.Recipe);
			if ((Object)(object)recipe2 == (Object)null)
			{
				if (hashsetRecipes != null && hashsetRecipes.Contains(recipe))
				{
					IPlugin plugin = Get.Plugin;
					object obj;
					if (recipe == null)
					{
						obj = null;
					}
					else
					{
						Recipe recipe3 = recipe.Recipe;
						obj = ((recipe3 != null) ? ((Object)recipe3).name : null);
					}
					plugin.LogDebugOnly("Removing and re-adding recipe " + (string?)obj + " in ItemManager.");
					ItemManager.Instance.RemoveRecipe(recipe);
					ItemManager.Instance.AddRecipe(new CustomRecipe(newRecipe));
					return true;
				}
				IPlugin plugin2 = Get.Plugin;
				object obj2;
				if (recipe == null)
				{
					obj2 = null;
				}
				else
				{
					Recipe recipe4 = recipe.Recipe;
					obj2 = ((recipe4 != null) ? ((Object)recipe4).name : null);
				}
				plugin2.LogError("Error updating recipe " + (string?)obj2 + ", did not find existing recipe in ObjectDB or ItemManager");
				return false;
			}
			IPlugin plugin3 = Get.Plugin;
			object obj3;
			if (recipe == null)
			{
				obj3 = null;
			}
			else
			{
				Recipe recipe5 = recipe.Recipe;
				obj3 = ((recipe5 != null) ? ((Object)recipe5).name : null);
			}
			plugin3.LogDebugOnly("Updating recipe " + (string?)obj3 + " in place.");
			recipe2.m_amount = newRecipe.Amount;
			recipe2.m_minStationLevel = newRecipe.MinStationLevel;
			GameObject prefab = PrefabManager.Instance.GetPrefab(newRecipe.CraftingStation);
			recipe2.m_craftingStation = ((prefab != null) ? prefab.GetComponent<CraftingStation>() : null);
			Get.Plugin.LogDebugOnly($"... setting cs to {recipe2.m_craftingStation}.");
			recipe2.m_resources = newRecipe.GetRequirements();
			Requirement[] resources = recipe2.m_resources;
			foreach (Requirement val in resources)
			{
				GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(((Object)val.m_resItem).name.Replace("JVLmock_", ""));
				if ((Object)(object)itemPrefab != (Object)null)
				{
					val.m_resItem = itemPrefab.GetComponent<ItemDrop>();
				}
			}
			if (hashsetRecipes != null)
			{
				hashsetRecipes.Remove(recipe);
				hashsetRecipes.Add(new CustomRecipe(recipe2, false, false));
			}
			return true;
		}

		public static bool PrefabExists(this PrefabManager instance, string name)
		{
			bool result = false;
			if (string.IsNullOrEmpty(name))
			{
				return result;
			}
			if (prefabsDict == null)
			{
				PropertyInfo propertyInfo = ((object)PrefabManager.Instance).GetType().GetMembers(BindingFlags.Instance | BindingFlags.NonPublic).FirstOrDefault((MemberInfo m) => m.Name == "Prefabs") as PropertyInfo;
				if (propertyInfo != null && propertyInfo.GetValue(PrefabManager.Instance) is Dictionary<string, CustomPrefab> dictionary)
				{
					prefabsDict = dictionary;
				}
			}
			if (prefabsDict != null)
			{
				result = prefabsDict.ContainsKey(name);
			}
			return result;
		}

		public static void ApplyToAll(this ItemDrop itemDrop, Action<ItemData> callback)
		{
			callback(itemDrop.m_itemData);
			string name = itemDrop.m_itemData.m_shared.m_name;
			Inventory[] source = (from c in Player.s_players.Select((Player p) => ((Humanoid)p).GetInventory()).Concat(from c in Object.FindObjectsOfType<Container>()
					select c.GetInventory())
				where c != null
				select c).ToArray();
			foreach (ItemData item in (from i in (from p in ObjectDB.instance.m_items
					select p.GetComponent<ItemDrop>() into c
					where Object.op_Implicit((Object)(object)c) && Object.op_Implicit((Object)(object)((Component)c).GetComponent<ZNetView>())
					select c).Concat(ItemDrop.s_instances)
				select i.m_itemData).Concat(source.SelectMany((Inventory i) => i.GetAllItems())))
			{
				if (item.m_shared.m_name == name)
				{
					callback(item);
				}
			}
		}

		public static object Cast(this Type Type, object data)
		{
			ParameterExpression parameterExpression = Expression.Parameter(typeof(object), "data");
			return Expression.Lambda(Expression.Block(Expression.Convert(Expression.Convert(parameterExpression, data.GetType()), Type)), parameterExpression).Compile().DynamicInvoke(data);
		}
	}
	internal class Feature
	{
		public bool RequiresUpdate { get; protected set; }

		public bool LoadedInGame { get; protected set; }

		public bool EnabledByDefault { get; set; }

		public string Name { get; set; }

		public string Category { get; set; }

		public string Description { get; set; }

		public FeatureType Type { get; set; }

		public string Table { get; set; }

		public int MinTableLevel { get; set; } = 1;


		public string Requirements { get; set; }

		public int Amount { get; set; } = 1;


		public List<string> DependencyNames { get; set; }

		public ConfigEntry<bool> EnabledConfigEntry { get; protected set; }

		public Entries Entries { get; protected set; }

		public Feature(string name)
		{
			Name = name;
			LoadedInGame = false;
			DependencyNames = new List<string>();
		}

		public virtual bool Initialize()
		{
			return false;
		}

		public virtual bool Load()
		{
			return false;
		}

		public virtual bool Unload()
		{
			return false;
		}

		public virtual bool Update()
		{
			return false;
		}

		public virtual string FetchTableEntryValue()
		{
			string a = Entries?.Table?.Value;
			if (string.Equals(a, "Custom") && Entries?.TableCustomName != null)
			{
				return Entries.TableCustomName.Value;
			}
			return Table;
		}
	}
	internal class FeatureItem : Feature
	{
		private CustomItem _customItem;

		public new ItemEntries Entries { get; protected set; }

		public string AoePrefabName { get; set; }

		public string AssetPath { get; set; }

		public string Damages { get; set; } = string.Empty;


		public int Knockback { get; set; }

		public AmmunitionType AmmoType { get; set; }

		public FeatureItem(string name)
			: base(name)
		{
		}

		private void OnEntrySettingChanged(object sender, EventArgs e)
		{
			Get.Plugin.LogDebugOnly("OnEntrySettingChanged fired on feature " + base.Name);
			base.RequiresUpdate = true;
		}

		private void OnEnabledSettingChanged(object sender, EventArgs e)
		{
			Get.Plugin.LogDebugOnly("OnEnabledSettingChanged fired on feature " + base.Name);
			Entries.SetVisibility(base.EnabledConfigEntry.Value);
			base.RequiresUpdate = true;
			SharedDrawers.ReloadConfigDisplay();
		}

		public override string FetchTableEntryValue()
		{
			string a = Entries?.Table?.Value;
			if (string.Equals(a, "Custom") && Entries?.TableCustomName != null)
			{
				return Entries.TableCustomName.Value;
			}
			return base.Table;
		}

		public override bool Initialize()
		{
			if (!string.IsNullOrEmpty(base.Category) && !string.IsNullOrEmpty(base.Description))
			{
				base.EnabledConfigEntry = MoreCrossbows.Instance.Config(base.Category, "Enable" + base.Name, base.EnabledByDefault, base.Description);
				base.EnabledConfigEntry.SettingChanged += OnEnabledSettingChanged;
				Entries = ItemEntries.GetFromFeature(MoreCrossbows.Instance, this, base.EnabledConfigEntry.Value);
				Entries.AddSettingsChangedHandler(OnEntrySettingChanged);
			}
			return true;
		}

		public override bool Update()
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Expected O, but got Unknown
			base.RequiresUpdate = false;
			RecipeConfig newRecipe = new RecipeConfig
			{
				Item = Entries.Name,
				CraftingStation = CraftingStations.GetInternalName(FetchTableEntryValue()),
				RepairStation = CraftingStations.GetInternalName(FetchTableEntryValue()),
				MinStationLevel = ((Entries != null) ? Entries.MinTableLevel.Value : base.MinTableLevel),
				Amount = ((Entries != null) ? Entries.Amount.Value : base.Amount),
				Requirements = RequirementsEntry.Deserialize(Entries?.Requirements?.Value ?? base.Requirements)
			};
			IPlugin plugin = Get.Plugin;
			CustomItem customItem = _customItem;
			object obj;
			if (customItem == null)
			{
				obj = null;
			}
			else
			{
				ItemDrop itemDrop = customItem.ItemDrop;
				obj = ((itemDrop != null) ? ((Object)itemDrop).name : null);
			}
			plugin.LogDebugOnly("Updating recipe for " + (string?)obj);
			Get.Plugin.LogDebugOnly("... table: " + CraftingStations.GetInternalName(FetchTableEntryValue()) + " level " + ((Entries != null) ? Entries.MinTableLevel.Value : base.MinTableLevel));
			Get.Plugin.LogDebugOnly("... reqs: " + ((Entries != null) ? Entries.Requirements.Value : base.Requirements));
			_customItem.Recipe.Update(newRecipe);
			Get.Plugin.LogDebugOnly("Overwriting damages of " + base.Name + " with : " + Entries.Damages.Value);
			setDamage(DamagesDict.Deserialize(Entries.Damages.Value), AoePrefabName);
			return true;
		}

		public override bool Load()
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Expected O, but got Unknown
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Expected O, but got Unknown
			Get.Plugin.LogDebugOnly("Loading item " + base.Name);
			ItemConfig val = new ItemConfig
			{
				CraftingStation = CraftingStations.GetInternalName(FetchTableEntryValue()),
				RepairStation = CraftingStations.GetInternalName(FetchTableEntryValue()),
				MinStationLevel = ((Entries != null) ? Entries.MinTableLevel.Value : base.MinTableLevel),
				Amount = ((Entries != null) ? Entries.Amount.Value : base.Amount),
				Requirements = RequirementsEntry.Deserialize(Entries?.Requirements?.Value ?? base.Requirements)
			};
			_customItem = new CustomItem(MoreCrossbows.Instance.assetBundle, AssetPath, true, val);
			setDamage(DamagesDict.Deserialize((Entries != null) ? Entries.Damages.Value : Damages), AoePrefabName);
			_customItem.ItemDrop.m_itemData.m_shared.m_attackForce = Knockback;
			if (AmmoType == AmmunitionType.Arrow)
			{
				_customItem.ItemDrop.m_itemData.m_shared.m_ammoType = "$ammo_arrows";
			}
			else if (AmmoType == AmmunitionType.Bolt)
			{
				_customItem.ItemDrop.m_itemData.m_shared.m_ammoType = "$ammo_bolts";
			}
			ItemManager.Instance.AddItem(_customItem);
			base.RequiresUpdate = false;
			base.LoadedInGame = true;
			return true;
		}

		public override bool Unload()
		{
			Get.Plugin.LogDebugOnly("Unloading item " + base.Name);
			ItemManager.Instance.RemoveItem(base.Name);
			ObjectDB.instance.Remove(base.Name);
			base.LoadedInGame = false;
			base.RequiresUpdate = false;
			return true;
		}

		private void setDamage(Dictionary<string, int> dmgs, string aoePrefabName)
		{
			_customItem.ItemDrop.m_itemData.m_shared.m_damages.m_damage = (dmgs.ContainsKey(DamageTypes.Damage) ? dmgs[DamageTypes.Damage] : 0);
			_customItem.ItemDrop.m_itemData.m_shared.m_damages.m_blunt = (dmgs.ContainsKey(DamageTypes.Blunt) ? dmgs[DamageTypes.Blunt] : 0);
			_customItem.ItemDrop.m_itemData.m_shared.m_damages.m_slash = (dmgs.ContainsKey(DamageTypes.Slash) ? dmgs[DamageTypes.Slash] : 0);
			_customItem.ItemDrop.m_itemData.m_shared.m_damages.m_pierce = (dmgs.ContainsKey(DamageTypes.Pierce) ? dmgs[DamageTypes.Pierce] : 0);
			_customItem.ItemDrop.m_itemData.m_shared.m_damages.m_chop = (dmgs.ContainsKey(DamageTypes.Chop) ? dmgs[DamageTypes.Chop] : 0);
			_customItem.ItemDrop.m_itemData.m_shared.m_damages.m_pickaxe = (dmgs.ContainsKey(DamageTypes.Pickaxe) ? dmgs[DamageTypes.Pickaxe] : 0);
			_customItem.ItemDrop.m_itemData.m_shared.m_damages.m_fire = (dmgs.ContainsKey(DamageTypes.Fire) ? dmgs[DamageTypes.Fire] : 0);
			_customItem.ItemDrop.m_itemData.m_shared.m_damages.m_frost = (dmgs.ContainsKey(DamageTypes.Frost) ? dmgs[DamageTypes.Frost] : 0);
			_customItem.ItemDrop.m_itemData.m_shared.m_damages.m_lightning = (dmgs.ContainsKey(DamageTypes.Lightning) ? dmgs[DamageTypes.Lightning] : 0);
			_customItem.ItemDrop.m_itemData.m_shared.m_damages.m_poison = (dmgs.ContainsKey(DamageTypes.Poison) ? dmgs[DamageTypes.Poison] : 0);
			_customItem.ItemDrop.m_itemData.m_shared.m_damages.m_spirit = (dmgs.ContainsKey(DamageTypes.Spirit) ? dmgs[DamageTypes.Spirit] : 0);
			if (string.IsNullOrEmpty(aoePrefabName))
			{
				return;
			}
			GameObject prefab = PrefabManager.Instance.GetPrefab(aoePrefabName);
			if ((Object)(object)prefab != (Object)null)
			{
				Get.Plugin.LogDebugOnly("seting aoe dmg of " + ((Object)_customItem.ItemDrop).name);
				Aoe component = prefab.GetComponent<Aoe>();
				if ((Object)(object)component != (Object)null)
				{
					float num = _customItem.ItemDrop.m_itemData.m_shared.m_damages.m_frost / 3f;
					component.m_damage.m_frost = num * 2f;
					_customItem.ItemDrop.m_itemData.m_shared.m_damages.m_frost = num;
					component.m_damage.m_fire = _customItem.ItemDrop.m_itemData.m_shared.m_damages.m_fire;
					component.m_damage.m_lightning = _customItem.ItemDrop.m_itemData.m_shared.m_damages.m_lightning;
					component.m_damage.m_poison = _customItem.ItemDrop.m_itemData.m_shared.m_damages.m_poison;
					component.m_damage.m_spirit = _customItem.ItemDrop.m_itemData.m_shared.m_damages.m_spirit;
				}
			}
		}
	}
	internal class FeatureRecipe : Feature
	{
		public FeatureRecipe(string name)
			: base(name)
		{
		}

		private void OnEntrySettingChanged(object sender, EventArgs e)
		{
			Get.Plugin.LogDebugOnly("OnEntrySettingChanged fired on feature " + base.Name);
			base.RequiresUpdate = true;
		}

		private void OnEnabledSettingChanged(object sender, EventArgs e)
		{
			Get.Plugin.LogDebugOnly("OnEnabledSettingChanged fired on feature " + base.Name);
			base.Entries.SetVisibility(base.EnabledConfigEntry.Value);
			base.RequiresUpdate = true;
			SharedDrawers.ReloadConfigDisplay();
		}

		public override bool Initialize()
		{
			base.EnabledConfigEntry = MoreCrossbows.Instance.Config(base.Category, "Enable" + base.Name, base.EnabledByDefault, base.Description);
			base.EnabledConfigEntry.SettingChanged += OnEnabledSettingChanged;
			base.Entries = Entries.GetFromFeature(MoreCrossbows.Instance, this, null, base.EnabledConfigEntry.Value);
			base.Entries.AddSettingsChangedHandler(OnEntrySettingChanged);
			return true;
		}

		public override bool Update()
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Expected O, but got Unknown
			base.RequiresUpdate = false;
			RecipeConfig newRecipe = new RecipeConfig
			{
				Item = base.Entries.Name,
				CraftingStation = CraftingStations.GetInternalName(FetchTableEntryValue()),
				RepairStation = CraftingStations.GetInternalName(FetchTableEntryValue()),
				MinStationLevel = ((base.Entries != null) ? base.Entries.MinTableLevel.Value : base.MinTableLevel),
				Amount = ((base.Entries != null) ? base.Entries.Amount.Value : base.Amount),
				Requirements = RequirementsEntry.Deserialize(base.Entries?.Requirements?.Value ?? base.Requirements)
			};
			CustomRecipe recipe = ItemManager.Instance.GetRecipe("CraftEarly" + base.Name);
			Get.Plugin.LogDebugOnly("Updating recipe " + base.Entries.Name);
			Get.Plugin.LogDebugOnly(("... reqs: " + base.Entries != null) ? base.Entries.Requirements.Value : base.Requirements);
			recipe.Update(newRecipe);
			base.RequiresUpdate = false;
			return true;
		}

		public override bool Load()
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Expected O, but got Unknown
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Expected O, but got Unknown
			Get.Plugin.LogDebugOnly("Loading recipe for " + base.Name);
			RecipeConfig val = new RecipeConfig
			{
				Name = "CraftEarly" + base.Entries.Name,
				Item = base.Entries.Name,
				CraftingStation = CraftingStations.GetInternalName(FetchTableEntryValue()),
				RepairStation = CraftingStations.GetInternalName(FetchTableEntryValue()),
				MinStationLevel = base.Entries.MinTableLevel.Value,
				Amount = base.Entries.Amount.Value,
				Requirements = RequirementsEntry.Deserialize(base.Entries.Requirements.Value)
			};
			ItemManager.Instance.AddRecipe(new CustomRecipe(val));
			base.RequiresUpdate = false;
			base.LoadedInGame = true;
			return true;
		}

		public override bool Unload()
		{
			Get.Plugin.LogDebugOnly("Unloading recipe for " + base.Name);
			ItemManager.Instance.RemoveRecipe("CraftEarly" + base.Name);
			base.LoadedInGame = false;
			base.RequiresUpdate = false;
			return true;
		}
	}
	public enum FeatureType
	{
		Crossbow,
		Arrow,
		Bolt
	}
	public enum AmmunitionType
	{
		None,
		Arrow,
		Bolt
	}
	public static class DamageTypes
	{
		public static string Damage => "Damage";

		public static string Blunt => "Blunt";

		public static string Slash => "Slash";

		public static string Pierce => "Pierce";

		public static string Chop => "Chop";

		public static string Pickaxe => "Pickaxe";

		public static string Fire => "Fire";

		public static string Frost => "Frost";

		public static string Lightning => "Lightning";

		public static string Poison => "Poison";

		public static string Spirit => "Spirit";

		public static string[] GetValues()
		{
			return new string[11]
			{
				Damage, Blunt, Slash, Pierce, Chop, Pickaxe, Fire, Frost, Lightning, Poison,
				Spirit
			};
		}
	}
	public class AcceptableKeysString : AcceptableValueBase
	{
		public virtual string[] AcceptableKeys { get; }

		public AcceptableKeysString(params string[] acceptableKeys)
			: base(typeof(string))
		{
			if (acceptableKeys == null)
			{
				throw new ArgumentNullException("acceptableValues");
			}
			if (acceptableKeys.Length == 0)
			{
				throw new ArgumentException("At least one acceptable key is needed", "AcceptableKeys");
			}
			AcceptableKeys = acceptableKeys;
		}

		public override object Clamp(object value)
		{
			return value;
		}

		public override bool IsValid(object value)
		{
			if (value is string)
			{
				return !string.IsNullOrEmpty((string)value);
			}
			return false;
		}

		public override string ToDescriptionString()
		{
			return "# Acceptable keys: " + string.Join(", ", AcceptableKeys.Select((string x) => x.ToString()).ToArray());
		}
	}
	public static class DamagesDict
	{
		public static Dictionary<string, int> Deserialize(string dmgs)
		{
			if (string.IsNullOrEmpty(dmgs))
			{
				return null;
			}
			return dmgs.Split(new char[1] { ',' }).Select(delegate(string d)
			{
				string[] array = d.Split(new char[1] { ':' });
				int result;
				int result2;
				return (array.Length > 1) ? new KeyValuePair<string, int>(array[0], (!int.TryParse(array[1], out result)) ? 1 : result) : new KeyValuePair<string, int>("Damage", (!int.TryParse(array[0], out result2)) ? 1 : result2);
			}).ToDictionary((KeyValuePair<string, int> kvp) => kvp.Key, (KeyValuePair<string, int> kvp) => kvp.Value);
		}

		public static string Serialize(Dictionary<string, int> dmgs)
		{
			return string.Join(",", dmgs.Select((KeyValuePair<string, int> d) => $"{d.Key}:{d.Value}"));
		}
	}
	internal class Entries
	{
		public static Dictionary<ConfigurationManagerAttributes, Entries> SavedAttributes = new Dictionary<ConfigurationManagerAttributes, Entries>();

		private static AcceptableValueList<string> AcceptableTableValues = new AcceptableValueList<string>(CraftingStations.GetAcceptableValueList().AcceptableValues.Concat(new string[1] { "Custom" }).ToArray());

		protected bool visible = true;

		private Action<object, EventArgs> _action;

		public string Name { get; set; } = string.Empty;


		public ConfigEntry<string> Table { get; set; }

		public ConfigEntry<string> TableCustomName { get; set; }

		public ConfigEntry<int> MinTableLevel { get; set; }

		public ConfigEntry<int> Amount { get; set; }

		public ConfigEntry<string> Requirements { get; set; }

		public static bool IsTableCustom(string table)
		{
			string value;
			return !CraftingStations.GetNames().TryGetValue(table, out value);
		}

		public static ConfigurationManagerAttributes GetAttribute(Entries entries, bool isAdminOnly = true, bool isBrowsable = true, Action<ConfigEntryBase> customDrawer = null)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Expected O, but got Unknown
			ConfigurationManagerAttributes val = new ConfigurationManagerAttributes
			{
				Browsable = isBrowsable,
				IsAdminOnly = isAdminOnly,
				CustomDrawer = customDrawer
			};
			SavedAttributes.Add(val, entries);
			return val;
		}

		public static void UpdateBrowsable()
		{
			foreach (KeyValuePair<ConfigurationManagerAttributes, Entries> savedAttribute in SavedAttributes)
			{
				savedAttribute.Key.Browsable = savedAttribute.Value.visible;
			}
			Get.Plugin.LogDebugOnly("UpdateBrowsable called.");
			foreach (Entries item in SavedAttributes.Values.Distinct())
			{
				object? obj = ((ConfigEntryBase)item.TableCustomName).Description.Tags.FirstOrDefault((object x) => x is ConfigurationManagerAttributes);
				ConfigurationManagerAttributes val = (ConfigurationManagerAttributes)((obj is ConfigurationManagerAttributes) ? obj : null);
				if (val != null)
				{
					val.Browsable = IsTableCustom(item.Table.Value) && item.visible;
					IPlugin plugin = Get.Plugin;
					string[] obj2 = new string[5]
					{
						item.Name,
						": ",
						item.Table.Value,
						", browsable: ",
						null
					};
					bool? browsable = val.Browsable;
					obj2[4] = browsable.ToString();
					plugin.LogDebugOnly(string.Concat(obj2));
				}
			}
		}

		public static Entries GetFromFeature(IPlugin instance, Feature config, Entries entries = null, bool visible = true)
		{
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Expected O, but got Unknown
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Expected O, but got Unknown
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Expected O, but got Unknown
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0178: Expected O, but got Unknown
			//IL_01cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d5: Expected O, but got Unknown
			bool hasUpgrades = config.Type == FeatureType.Crossbow;
			if (entries == null)
			{
				entries = new Entries();
			}
			entries.visible = visible;
			entries.Name = config.Name;
			entries.Table = instance.Config(entries.Name, "Table", config.Table, new ConfigDescription("Crafting station where " + entries.Name + " is available.", (AcceptableValueBase)(object)AcceptableTableValues, new object[1] { GetAttribute(entries, isAdminOnly: true, visible) }));
			entries.TableCustomName = instance.Config(entries.Name, "Table (Custom Name)", IsTableCustom(config.Table) ? config.Table : "", new ConfigDescription("If custom, the name of the crafting station where " + entries.Name + " is available.", (AcceptableValueBase)null, new object[1] { GetAttribute(entries, isAdminOnly: true, IsTableCustom(config.Table) && visible) }));
			entries.MinTableLevel = instance.Config(entries.Name, "Table Level", config.MinTableLevel, new ConfigDescription("Level of crafting station required to craft " + entries.Name + ".", (AcceptableValueBase)null, new object[1] { GetAttribute(entries, entries.visible) }));
			entries.Amount = instance.Config(entries.Name, "Amount", config.Amount, new ConfigDescription("The amount of " + entries.Name + " created.", (AcceptableValueBase)null, new object[1] { GetAttribute(entries, entries.visible) }));
			entries.Requirements = instance.Config(entries.Name, "Requirements", config.Requirements, new ConfigDescription("The required items to craft " + entries.Name + ".", (AcceptableValueBase)(object)new AcceptableValueConfigNote("You must use valid spawn item codes."), new object[1] { GetAttribute(entries, entries.visible, isBrowsable: true, SharedDrawers.DrawReqConfigTable(hasUpgrades)) }));
			entries.Table.SettingChanged += OnTableSettingChanged;
			return entries;
		}

		private static void OnTableSettingChanged(object sender, EventArgs e)
		{
			UpdateBrowsable();
			SharedDrawers.ReloadConfigDisplay();
		}

		public void SetVisibility(bool visible)
		{
			this.visible = visible;
			UpdateBrowsable();
		}

		protected void OnSettingChanged(object sender, EventArgs e)
		{
			if (_action != null)
			{
				_action(sender, e);
			}
		}

		public virtual void AddSettingsChangedHandler(Action<object, EventArgs> action)
		{
			_action = action;
			Table.SettingChanged += OnSettingChanged;
			MinTableLevel.SettingChanged += OnSettingChanged;
			Amount.SettingChanged += OnSettingChanged;
			Requirements.SettingChanged += OnSettingChanged;
		}

		public virtual void RemoveSettingsChangedHandler()
		{
			Table.SettingChanged -= OnSettingChanged;
			MinTableLevel.SettingChanged -= OnSettingChanged;
			Amount.SettingChanged -= OnSettingChanged;
			Requirements.SettingChanged -= OnSettingChanged;
			_action = null;
		}
	}
	internal class ItemEntries : Entries
	{
		public ConfigEntry<string> Damages { get; set; }

		public override void AddSettingsChangedHandler(Action<object, EventArgs> action)
		{
			base.AddSettingsChangedHandler(action);
			Damages.SettingChanged += base.OnSettingChanged;
		}

		public override void RemoveSettingsChangedHandler()
		{
			base.RemoveSettingsChangedHandler();
			Damages.SettingChanged -= base.OnSettingChanged;
		}

		public static ItemEntries GetFromFeature(IPlugin instance, FeatureItem config, bool visible = true)
		{
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Expected O, but got Unknown
			ItemEntries entries = new ItemEntries();
			entries = (ItemEntries)Entries.GetFromFeature(instance, config, entries, visible);
			entries.Damages = instance.Config(entries.Name, "Damages", config.Damages, new ConfigDescription("The damage done by " + entries.Name + ".", (AcceptableValueBase)(object)new AcceptableKeysString(DamageTypes.GetValues()), new object[1] { Entries.GetAttribute(entries, isAdminOnly: true, entries.visible, DamagesEntry.DrawDamagesConfigTable()) }));
			return entries;
		}
	}
	public class DamagesConfig
	{
		public string Prefab;

		public int Duration;
	}
	public static class DamagesEntry
	{
		public static DamagesConfig[] Deserialize(string dmgs)
		{
			return dmgs.Split(new char[1] { ',' }).Select(delegate(string r)
			{
				string[] array = r.Split(new char[1] { ':' });
				int result;
				return new DamagesConfig
				{
					Prefab = array[0],
					Duration = ((array.Length <= 1 || !int.TryParse(array[1], out result)) ? 1 : result)
				};
			}).ToArray();
		}

		public static string Serialize(DamagesConfig[] dmgs)
		{
			return string.Join(",", dmgs.Select((DamagesConfig r) => $"{r.Prefab}:{r.Duration}"));
		}

		public static Action<ConfigEntryBase> DrawDamagesConfigTable()
		{
			return delegate(ConfigEntryBase cfg)
			{
				//IL_005c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0061: Unknown result type (might be due to invalid IL or missing references)
				//IL_007f: Expected O, but got Unknown
				//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
				//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
				//IL_00e0: Expected O, but got Unknown
				//IL_0104: Unknown result type (might be due to invalid IL or missing references)
				//IL_0109: Unknown result type (might be due to invalid IL or missing references)
				//IL_011e: Expected O, but got Unknown
				//IL_014e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0153: Unknown result type (might be due to invalid IL or missing references)
				//IL_0168: Expected O, but got Unknown
				List<DamagesConfig> list = new List<DamagesConfig>();
				bool flag = false;
				int rightColumnWidth = SharedDrawers.GetRightColumnWidth();
				GUILayout.BeginVertical(Array.Empty<GUILayoutOption>());
				foreach (DamagesConfig item in Deserialize((string)cfg.BoxedValue).ToList())
				{
					GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
					string text = GUILayout.TextField(item.Prefab, new GUIStyle(GUI.skin.textField)
					{
						fixedWidth = rightColumnWidth - 56 - 21 - 21 - 9
					}, Array.Empty<GUILayoutOption>());
					string text2 = (string.IsNullOrEmpty(text) ? item.Prefab : text);
					flag = flag || text2 != item.Prefab;
					int num = item.Duration;
					if (int.TryParse(GUILayout.TextField(num.ToString(), new GUIStyle(GUI.skin.textField)
					{
						fixedWidth = 56f
					}, Array.Empty<GUILayoutOption>()), out var result) && result != num)
					{
						num = result;
						flag = true;
					}
					if (GUILayout.Button("x", new GUIStyle(GUI.skin.button)
					{
						fixedWidth = 21f
					}, Array.Empty<GUILayoutOption>()))
					{
						flag = true;
					}
					else
					{
						list.Add(new DamagesConfig
						{
							Prefab = text2,
							Duration = num
						});
					}
					if (GUILayout.Button("+", new GUIStyle(GUI.skin.button)
					{
						fixedWidth = 21f
					}, Array.Empty<GUILayoutOption>()))
					{
						flag = true;
						list.Add(new DamagesConfig
						{
							Prefab = "<Damage Type>",
							Duration = 120
						});
					}
					GUILayout.EndHorizontal();
				}
				GUILayout.EndVertical();
				if (flag)
				{
					cfg.BoxedValue = Serialize(list.ToArray());
				}
			};
		}
	}
	[Flags]
	public enum VisualEffectCondition : uint
	{
		IsSkill = 0xFFFu,
		Swords = 1u,
		Knives = 2u,
		Clubs = 3u,
		Polearms = 4u,
		Spears = 5u,
		Blocking = 6u,
		Axes = 7u,
		Bows = 8u,
		Unarmed = 0xBu,
		Pickaxes = 0xCu,
		WoodCutting = 0xDu,
		Crossbows = 0xEu,
		IsItem = 0xFF000u,
		Helmet = 0x6000u,
		Chest = 0x7000u,
		Legs = 0xB000u,
		Hands = 0xC000u,
		Shoulder = 0x11000u,
		Tool = 0x13000u,
		GenericExtraAttributes = 0xFF000000u,
		Blackmetal = 0x40000000u,
		TwoHanded = 0x80000000u,
		SpecificExtraAttributes = 0xF00000u,
		Hammer = 0x113000u,
		Hoe = 0x213000u,
		Buckler = 0x100006u,
		Towershield = 0x200006u,
		FineWoodBow = 0x100008u,
		BowHuntsman = 0x200008u,
		BowDraugrFang = 0x300008u,
		Arbalest = 0x10000Eu,
		CrossbowWood = 0x20000Eu,
		CrossbowBronze = 0x30000Eu,
		CrossbowIron = 0x40000Eu,
		CrossbowSilver = 0x50000Eu,
		CrossbowBlackmetal = 0x60000Eu,
		PickaxeIron = 0x10000Cu,
		Club = 0x100003u
	}
	public static class JewelcraftingPatches
	{
		private static FieldInfo effectPrefabsByTypeInfo;

		private static Type vecType;

		public static void Initialize(Harmony harmony, BaseUnityPlugin jewelcrafting)
		{
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Expected O, but got Unknown
			if (harmony == null || (Object)(object)jewelcrafting == (Object)null)
			{
				throw new ArgumentNullException("Attempted to initialize without harmony, jewelcrafting or both.");
			}
			Assembly assembly = ((object)jewelcrafting).GetType().Assembly;
			MethodInfo method = assembly.GetType("Jewelcrafting.GemEffects.VisualEffects").GetMethod("prefabDict");
			MethodInfo method2 = typeof(JewelcraftingPatches).GetMethod("VisualEffectsPrefabDictPostfix", BindingFlags.Static | BindingFlags.NonPublic);
			if (method != null && method2 != null)
			{
				harmony.Patch((MethodBase)method, (HarmonyMethod)null, new HarmonyMethod(method2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
			else
			{
				Get.Plugin.LogWarning($"Found Jewelcrafting but unable to patch. method = {method}, postfix = {method2}");
			}
			List<string[]> list = new List<string[]>();
			list.Add(new string[3]
			{
				"Perfect_Yellow_Socket",
				VisualEffectCondition.CrossbowIron.ToString(),
				"jc_echo_ironxbow"
			});
			list.Add(new string[3]
			{
				"Perfect_Red_Socket",
				VisualEffectCondition.CrossbowIron.ToString(),
				"jc_endlessarrows_ironxbow"
			});
			list.Add(new string[3]
			{
				"Perfect_Purple_Socket",
				VisualEffectCondition.CrossbowIron.ToString(),
				"jc_masterarcher_ironxbow"
			});
			list.Add(new string[3]
			{
				"Perfect_Green_Socket",
				VisualEffectCondition.CrossbowIron.ToString(),
				"jc_necromancer_ironxbow"
			});
			list.Add(new string[3]
			{
				"Perfect_Yellow_Socket",
				VisualEffectCondition.CrossbowSilver.ToString(),
				"jc_echo_silverxbow"
			});
			list.Add(new string[3]
			{
				"Perfect_Red_Socket",
				VisualEffectCondition.CrossbowSilver.ToString(),
				"jc_endlessarrows_silverxbow"
			});
			list.Add(new string[3]
			{
				"Perfect_Purple_Socket",
				VisualEffectCondition.CrossbowSilver.ToString(),
				"jc_masterarcher_silverxbow"
			});
			list.Add(new string[3]
			{
				"Perfect_Green_Socket",
				VisualEffectCondition.CrossbowSilver.ToString(),
				"jc_necromancer_silverxbow"
			});
			list.Add(new string[3]
			{
				"Perfect_Yellow_Socket",
				VisualEffectCondition.CrossbowBlackmetal.ToString(),
				"jc_echo_blackmetalxbow"
			});
			list.Add(new string[3]
			{
				"Perfect_Red_Socket",
				VisualEffectCondition.CrossbowBlackmetal.ToString(),
				"jc_endlessarrows_blackmetalxbow"
			});
			list.Add(new string[3]
			{
				"Perfect_Purple_Socket",
				VisualEffectCondition.CrossbowBlackmetal.ToString(),
				"jc_masterarcher_blackmetalxbow"
			});
			list.Add(new string[3]
			{
				"Perfect_Green_Socket",
				VisualEffectCondition.CrossbowBlackmetal.ToString(),
				"jc_necromancer_blackmetalxbow"
			});
			List<string[]> toLoad = list;
			Type? obj = assembly?.GetType("Jewelcrafting.GemEffects.VisualEffects");
			if (vecType == null)
			{
				vecType = assembly?.GetType("Jewelcrafting.VisualEffectCondition");
			}
			if ((obj?.GetField("attachEffectPrefabs", BindingFlags.Static | BindingFlags.Public))?.GetValue(null) is IDictionary effectPrefabs)
			{
				LoadPrefabs(effectPrefabs, toLoad);
			}
			else
			{
				Get.Plugin.LogDebugOnly("Unable to invoke attachEffectPrefabs, not found.");
			}
		}

		private static void LoadPrefabs(IDictionary effectPrefabs, List<string[]> toLoad)
		{
			foreach (string[] item in toLoad)
			{
				string text = item[0];
				string text2 = item[2];
				VisualEffectCondition visualEffectCondition = (VisualEffectCondition)Enum.Parse(typeof(VisualEffectCondition), item[1]);
				GameObject val = MoreCrossbows.Instance.assetBundle.LoadAsset<GameObject>(text2);
				if ((Object)(object)val == (Object)null)
				{
					Get.Plugin.LogWarning("Prefab " + text2 + " did not load correctly");
				}
				if (effectPrefabs.Contains(text))
				{
					if (effectPrefabs[text] is IDictionary dictionary && !dictionary.Contains(vecType.Cast(visualEffectCondition)))
					{
						Get.Plugin.LogDebugOnly($"Adding: {visualEffectCondition} {val} to effectPrefabs[{text}]");
						dictionary.Add(vecType.Cast(visualEffectCondition), val);
					}
					else
					{
						Get.Plugin.LogDebugOnly($"effectPrefabs[{text}] already contains a {visualEffectCondition} key, skipping.");
					}
					continue;
				}
				Get.Plugin.LogWarning("attachEffectPrefabs does not contain " + text + " key; Aborting.");
				break;
			}
		}

		private static void VisualEffectsPrefabDictPostfix(ref Dictionary<string, GameObject[]> __result, SharedData shared)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Invalid comparison between Unknown and I4
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			if (__result == null || (int)shared.m_skillType != 14)
			{
				return;
			}
			VisualEffectCondition visualEffectCondition = SkillKey(shared);
			int num = ((__result != null) ? __result.Count : 0);
			if (effectPrefabsByTypeInfo == null || vecType == null)
			{
				Assembly obj = ((object)MoreCrossbows.Instance.jewelcrafting)?.GetType().Assembly;
				Type type = obj?.GetType("Jewelcrafting.GemEffects.VisualEffects");
				vecType = obj?.GetType("Jewelcrafting.VisualEffectCondition");
				effectPrefabsByTypeInfo = type?.GetField("effectPrefabsByType", BindingFlags.Static | BindingFlags.NonPublic);
			}
			if (effectPrefabsByTypeInfo?.GetValue(null) is IDictionary dictionary)
			{
				if (dictionary[vecType.Cast(visualEffectCondition)] is Dictionary<string, GameObject[]> dictionary2 && dictionary2.Count > 0)
				{
					Get.Plugin.LogDebugOnly($"Patched visual effects lookup by skill, type = {shared.m_itemType}, key = {visualEffectCondition}, results = {num}");
					__result = dictionary2;
				}
			}
			else
			{
				Get.Plugin.LogWarning("Failed to find Jewelcrafting.GemEffects.VisualEffects.effectPrefabsByType via reflection.");
			}
		}

		private static VisualEffectCondition SkillKey(SharedData shared)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Invalid comparison between Unknown and I4
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Invalid comparison between Unknown and I4
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Invalid comparison between Unknown and I4
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Expected I4, but got Unknown
			return (VisualEffectCondition)(shared.m_skillType | (((int)shared.m_skillType == 14 && shared.m_name.Contains("$item_crossbow_iron")) ? 4194318 : 0) | (((int)shared.m_skillType == 14 && shared.m_name.Contains("$item_crossbow_silver")) ? 5242894 : 0) | (((int)shared.m_skillType == 14 && shared.m_name.Contains("$item_crossbow_blackmetal")) ? 6291470 : 0));
		}
	}
	public static class TooltipHelper
	{
		public static string Damage(float damage)
		{
			return string.Concat(new string[3]
			{
				"<color=orange>",
				Mathf.RoundToInt(damage).ToString(),
				"</color>"
			});
		}

		public static string GetAoeTooltipForItem(ItemData item, Aoe aoe)
		{
			StringBuilder stringBuilder = new StringBuilder(256);
			stringBuilder.Append(Environment.NewLine + Environment.NewLine + "$area_of_effect ");
			int num = Mathf.RoundToInt(aoe.m_hitInterval);
			if ((float)num * 2f < aoe.m_ttl)
			{
				if (num == 1)
				{
					stringBuilder.Append("($per_second) ");
				}
				else if (num >= 2)
				{
					stringBuilder.Append("($every " + num + " $seconds) ");
				}
			}
			if (aoe.m_damage.m_damage != 0f)
			{
				stringBuilder.Append(Environment.NewLine + "$inventory_damage: " + Damage(aoe.m_damage.m_damage));
			}
			if (aoe.m_damage.m_blunt != 0f)
			{
				stringBuilder.Append(Environment.NewLine + "$inventory_blunt: " + Damage(aoe.m_damage.m_blunt));
			}
			if (aoe.m_damage.m_slash != 0f)
			{
				stringBuilder.Append(Environment.NewLine + "$inventory_slash: " + Damage(aoe.m_damage.m_slash));
			}
			if (aoe.m_damage.m_pierce != 0f)
			{
				stringBuilder.Append(Environment.NewLine + "$inventory_pierce: " + Damage(aoe.m_damage.m_pierce));
			}
			if (aoe.m_damage.m_fire != 0f)
			{
				stringBuilder.Append(Environment.NewLine + "$inventory_fire: " + Damage(aoe.m_damage.m_fire));
			}
			if (aoe.m_damage.m_frost != 0f)
			{
				stringBuilder.Append(Environment.NewLine + "$inventory_frost: " + Damage(aoe.m_damage.m_frost));
			}
			if (aoe.m_damage.m_lightning != 0f)
			{
				stringBuilder.Append(Environment.NewLine + "$inventory_lightning: " + Damage(aoe.m_damage.m_lightning));
			}
			if (aoe.m_damage.m_poison != 0f)
			{
				stringBuilder.Append(Environment.NewLine + "$inventory_poison: " + Damage(aoe.m_damage.m_poison));
			}
			if (aoe.m_damage.m_spirit != 0f)
			{
				stringBuilder.Append(Environment.NewLine + "$inventory_spirit: " + Damage(aoe.m_damage.m_spirit));
			}
			return stringBuilder.ToString();
		}
	}
	[HarmonyPatch(typeof(ItemData), "GetTooltip", new Type[]
	{
		typeof(ItemData),
		typeof(int),
		typeof(bool),
		typeof(float)
	})]
	[HarmonyPriority(800)]
	public static class GetTooltipPatch
	{
		public static string Postfix(string __result, ItemData item)
		{
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Invalid comparison between Unknown and I4
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Invalid comparison between Unknown and I4
			StringBuilder stringBuilder = new StringBuilder(256);
			stringBuilder.Append(__result);
			if (Object.op_Implicit((Object)(object)item.m_shared.m_attack.m_attackProjectile))
			{
				Projectile component = item.m_shared.m_attack.m_attackProjectile.GetComponent<Projectile>();
				if ((Object)(object)component != (Object)null && Object.op_Implicit((Object)(object)component.m_spawnOnHit))
				{
					Aoe component2 = component.m_spawnOnHit.GetComponent<Aoe>();
					if ((Object)(object)component2 != (Object)null && ((int)item.m_shared.m_itemType == 3 || (int)item.m_shared.m_itemType == 9))
					{
						stringBuilder.Append(TooltipHelper.GetAoeTooltipForItem(item, component2));
					}
				}
			}
			return stringBuilder.ToString();
		}
	}
	[BepInPlugin("probablykory.MoreCrossbows", "MoreCrossbows", "1.2.9")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	internal class MoreCrossbows : BaseUnityPlugin, IPlugin
	{
		public const string PluginAuthor = "probablykory";

		public const string PluginName = "MoreCrossbows";

		public const string PluginVersion = "1.2.9";

		public const string PluginGUID = "probablykory.MoreCrossbows";

		private static ConfigEntry<bool> isDebugEnabled = null;

		internal static MoreCrossbows Instance;

		internal AssetBundle assetBundle = AssetUtils.LoadAssetBundleFromResources("crossbows");

		internal Harmony harmony;

		internal BaseUnityPlugin jewelcrafting;

		private List<Feature> _features = new List<Feature>();

		private static Dictionary<string, string> DefaultEnglishLanguageStrings = new Dictionary<string, string>
		{
			{ "$area_of_effect", "Area effect" },
			{ "$every", "every" },
			{ "$seconds", "seconds" },
			{ "$per_second", "per second" },
			{ "$item_crossbow_wood", "Wooden crossbow" },
			{ "$item_crossbow_wood_description", "A crudely-made but powerful weapon." },
			{ "$item_crossbow_bronze", "Bronze crossbow" },
			{ "$item_crossbow_bronze_description", "A powerful weapon, forged in bronze." },
			{ "$item_crossbow_iron", "Iron crossbow" },
			{ "$item_crossbow_iron_description", "An accurate, powerful messenger of death." },
			{ "$item_crossbow_silver", "Silver crossbow" },
			{ "$item_crossbow_silver_description", "A sleek weapon, crafted from the mountain top." },
			{ "$item_crossbow_blackmetal", "Blackmetal crossbow" },
			{ "$item_crossbow_blackmetal_description", "A vicious thing.  Handle with care." },
			{ "$item_bolt_wood", "Wood bolt" },
			{ "$item_bolt_wood_description", "A brittle crossbow bolt of sharpened wood." },
			{ "$item_bolt_fire", "Fire bolt" },
			{ "$item_bolt_fire_description", "A piercing bolt of fire." },
			{ "$item_bolt_silver", "Silver bolt" },
			{ "$item_bolt_silver_description", "A bolt to calm restless spirits." },
			{ "$item_bolt_poison", "Poison bolt" },
			{ "$item_bolt_poison_description", "A bitter dose for your enemies." },
			{ "$item_bolt_frost", "Frost bolt" },
			{ "$item_bolt_frost_description", "A piercing bolt of ice." },
			{ "$item_bolt_lightning", "Lightning bolt" },
			{ "$item_bolt_lightning_description", "Noone can know when or where it will strike." },
			{ "$item_arrow_lightning", "Lightning arrow" },
			{ "$item_arrow_lightning_description", "Noone can know when or where it will strike." },
			{ "$item_bolt_surtling", "Surtling bolt" },
			{ "$item_bolt_surtling_description", "Do not use indoors." },
			{ "$item_bolt_ooze", "Ooze bolt" },
			{ "$item_bolt_ooze_description", "The stench is unbearable..." },
			{ "$item_bolt_bile", "Bile bolt" },
			{ "$item_bolt_bile_description", "Handle with care." },
			{ "$item_bolt_ice", "Ice bolt" },
			{ "$item_bolt_ice_description", "Heart of the frozen mountain." },
			{ "$item_bolt_flametal", "Flametal bolt" },
			{ "$item_bolt_flametal_description", "Do not use indoors." }
		};

		public ManualLogSource Logger { get; private set; } = Logger.CreateLogSource("MoreCrossbows");


		public bool Debug
		{
			get
			{
				if (isDebugEnabled == null)
				{
					return true;
				}
				return isDebugEnabled.Value;
			}
		}

		private void Awake()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected O, but got Unknown
			harmony = new Harmony("probablykory.MoreCrossbows");
			harmony.PatchAll(typeof(GetTooltipPatch));
			isDebugEnabled = this.Config("1 - General", "Debugging Enabled", value: false, "If on, mod will output alot more information in the debug log level.");
			Instance = this;
			((BaseUnityPlugin)this).Config.SaveOnConfigSet = true;
			CheckForJewelcrafting();
			InitializeFeatures();
			AddDefaultLocalizations();
			SynchronizationManager.OnConfigurationSynchronized += OnConfigurationSynchronized;
			PrefabManager.OnVanillaPrefabsAvailable += OnVanillaPrefabsAvailable;
			LocalizationManager.OnLocalizationAdded += OnLocalizationAdded;
			((BaseUnityPlugin)this).Config.ConfigReloaded += OnConfigReloaded;
			new ConfigWatcher(this);
		}

		private void CheckForJewelcrafting()
		{
			if (Chainloader.PluginInfos.TryGetValue("org.bepinex.plugins.jewelcrafting", out var value) && Object.op_Implicit((Object)(object)value.Instance))
			{
				jewelcrafting = value.Instance;
				this.LogInfo("Patching customized crossbow gem effects for Jewelcrafting.");
				JewelcraftingPatches.Initialize(harmony, jewelcrafting);
			}
		}

		private void OnConfigReloaded(object sender, EventArgs e)
		{
			this.LogDebugOnly("Config reloaded received.");
			AddOrRemoveFeatures();
		}

		private void OnConfigurationSynchronized(object sender, ConfigurationSynchronizationEventArgs e)
		{
			this.LogDebugOnly("Configuration Sync received.");
			AddOrRemoveFeatures();
		}

		private void OnVanillaPrefabsAvailable()
		{
			this.LogDebugOnly("Vanilla Prefabs Available received.");
			AddOrRemoveFeatures();
		}

		private void OnDestroy()
		{
			this.LogDebugOnly("OnDestroy called.");
			SynchronizationManager.OnConfigurationSynchronized -= OnConfigurationSynchronized;
			PrefabManager.OnVanillaPrefabsAvailable -= OnVanillaPrefabsAvailable;
		}

		private void RegisterCustomPrefab(AssetBundle bundle, string assetName)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Expected O, but got Unknown
			string text = assetName.Replace(".prefab", "");
			if (!string.IsNullOrEmpty(text) && !PrefabManager.Instance.PrefabExists(text))
			{
				CustomPrefab val = new CustomPrefab(bundle, assetName, true);
				this.LogDebugOnly("Registering " + ((Object)val.Prefab).name);
				if (val != null && val.IsValid())
				{
					PrefabExtension.FixReferences(val.Prefab, true);
					PrefabManager.Instance.AddPrefab(val);
				}
			}
		}

		private void AddOrRemoveFeatures()
		{
			bool flag = true;
			int num = 0;
			int num2 = 0;
			int num3 = 0;
			foreach (Feature feature in _features)
			{
				bool flag2 = false;
				if (feature.EnabledConfigEntry == null)
				{
					flag2 = flag;
				}
				else
				{
					flag2 = feature.EnabledConfigEntry.Value;
					flag = flag && flag2;
				}
				this.LogDebugOnly("DEBUG: allFeaturesEnabled = " + flag);
				this.LogDebugOnly("DEBUG: Feature " + feature.Name + " is " + (flag2 ? "enabled" : "disabled") + " and " + (feature.LoadedInGame ? "Loaded" : "Unloaded"));
				if (flag2 != feature.LoadedInGame)
				{
					if (flag2)
					{
						if (feature.DependencyNames.Count > 0)
						{
							foreach (string dependencyName in feature.DependencyNames)
							{
								RegisterCustomPrefab(assetBundle, dependencyName);
							}
						}
						feature.Load();
						num++;
					}
					else
					{
						feature.Unload();
						num2++;
					}
				}
				else if (feature.LoadedInGame && feature.RequiresUpdate)
				{
					feature.Update();
					num3++;
				}
			}
			string text = "";
			if (num > 0)
			{
				text = string.Format("{0} feature{1} loaded", num, (num > 1) ? "s" : "");
				text = ((num2 <= 0) ? (text + ".") : (text + " and "));
			}
			if (num2 > 0)
			{
				text += string.Format("{0} feature{1} unloaded.", num2, (num2 > 1) ? "s" : "");
			}
			if (num3 > 0)
			{
				if (text.Length > 0)
				{
					text += "  ";
				}
				text += string.Format("{0} feature{1} updated.", num3, (num3 > 1) ? "s" : "");
			}
			if (text.Length > 0)
			{
				this.LogInfo(text);
			}
			Entries.UpdateBrowsable();
		}

		private void AddDefaultLocalizations()
		{
			this.LogDebugOnly("AddLocalizations called.");
			CustomLocalization localization = LocalizationManager.Instance.GetLocalization();
			string text = "English";
			localization.AddTranslation(ref text, DefaultEnglishLanguageStrings);
		}

		private void OnLocalizationAdded()
		{
			this.LogDebugOnly("Localization Added received.");
			string location = ((object)Instance).GetType().Assembly.Location;
			char directorySeparatorChar = Path.DirectorySeparatorChar;
			string text = location.Replace(directorySeparatorChar + "MoreCrossbows.dll", "");
			if (Paths.PluginPath.Equals(text))
			{
				text = Utility.CombinePaths(new string[2]
				{
					Paths.PluginPath,
					"MoreCrossbows"
				});
			}
			string text2 = Utility.CombinePaths(new string[4] { text, "Translations", "English", "english.json" });
			string directoryName = Path.GetDirectoryName(text2);
			if (!Directory.Exists(directoryName) || !File.Exists(text2))
			{
				Directory.CreateDirectory(directoryName);
				string contents = SimpleJson.SerializeObject((object)DefaultEnglishLanguageStrings);
				File.WriteAllText(text2, contents);
				this.LogDebugOnly("Default localizations written to " + text2);
			}
			LocalizationManager.OnLocalizationAdded -= OnLocalizationAdded;
		}

		private void InitializeFeatures()
		{
			_features.Add(new FeatureItem("CrossbowWood")
			{
				Category = "2 - Crossbows",
				Description = "Adds a new Wooden Crossbow weapon",
				EnabledByDefault = true,
				AssetPath = "Assets/PrefabInstance/CrossbowWood.prefab",
				Type = FeatureType.Crossbow,
				AmmoType = AmmunitionType.Bolt,
				Table = "Workbench",
				MinTableLevel = 2,
				Requirements = "Wood:20:5,Stone:8:2,LeatherScraps:8:2",
				Damages = "Pierce:27",
				Knockback = 80,
				DependencyNames = new List<string> { "sfx_wood_crossbow_fire.prefab" }
			});
			_features.Add(new FeatureItem("CrossbowBronze")
			{
				Category = "2 - Crossbows",
				Description = "Adds a new Bronze Crossbow weapon",
				EnabledByDefault = true,
				AssetPath = "Assets/PrefabInstance/CrossbowBronze.prefab",
				Type = FeatureType.Crossbow,
				AmmoType = AmmunitionType.Bolt,
				Table = "Forge",
				MinTableLevel = 1,
				Requirements = "Wood:10:5,FineWood:4:2,Bronze:10:5,DeerHide:2:1",
				Damages = "Pierce:42",
				Knockback = 100,
				DependencyNames = new List<string> { "sfx_bronze_crossbow_fire.prefab" }
			});
			_features.Add(new FeatureItem("CrossbowIron")
			{
				Category = "2 - Crossbows",
				Description = "Adds a new Iron Crossbow weapon",
				EnabledByDefault = true,
				AssetPath = "Assets/PrefabInstance/CrossbowIron.prefab",
				Type = FeatureType.Crossbow,
				AmmoType = AmmunitionType.Bolt,
				Table = "Forge",
				MinTableLevel = 2,
				Requirements = "Wood:10:5,ElderBark:4:2,Iron:20:10,Root:1",
				Damages = "Pierce:57",
				Knockback = 120
			});
			_features.Add(new FeatureItem("CrossbowSilver")
			{
				Category = "2 - Crossbows",
				Description = "Adds a new Silver Crossbow weapon",
				EnabledByDefault = true,
				AssetPath = "Assets/PrefabInstance/CrossbowSilver.prefab",
				Type = FeatureType.Crossbow,
				AmmoType = AmmunitionType.Bolt,
				Table = "Forge",
				MinTableLevel = 3,
				Requirements = "Wood:10:4,Silver:10:5,Iron:10:5,WolfHairBundle:6",
				Damages = "Pierce:72",
				Knockback = 140
			});
			_features.Add(new FeatureItem("CrossbowBlackmetal")
			{
				Category = "2 - Crossbows",
				Description = "Adds a new Blackmetal Crossbow weapon",
				EnabledByDefault = true,
				AssetPath = "Assets/PrefabInstance/CrossbowBlackmetal.prefab",
				Type = FeatureType.Crossbow,
				AmmoType = AmmunitionType.Bolt,
				Table = "Forge",
				MinTableLevel = 4,
				Requirements = "FineWood:10:5,BlackMetal:16:8,Iron:8:4,LoxPelt:2:1",
				Damages = "Pierce:92",
				Knockback = 160
			});
			_features.Add(new FeatureItem("BoltWood")
			{
				Category = "4 - Bolts",
				Description = "Adds new wood bolts",
				EnabledByDefault = true,
				AssetPath = "Assets/PrefabInstance/BoltWood.prefab",
				Type = FeatureType.Bolt,
				Amount = 20,
				Table = "Workbench",
				MinTableLevel = 2,
				Requirements = "Wood:8",
				Damages = "Pierce:22",
				DependencyNames = new List<string> { "arbalest_projectile_wood.prefab" }
			});
			_features.Add(new FeatureItem("BoltFire")
			{
				Category = "4 - Bolts",
				Description = "Adds new fire bolts",
				EnabledByDefault = true,
				AssetPath = "Assets/PrefabInstance/BoltFire.prefab",
				Type = FeatureType.Bolt,
				Amount = 20,
				Table = "Workbench",
				MinTableLevel = 2,
				Requirements = "Wood:8,Resin:8,Feathers:2",
				Damages = "Pierce:11,Fire:22",
				DependencyNames = new List<string> { "arbalest_projectile_fire.prefab" }
			});
			_features.Add(new FeatureItem("BoltSilver")
			{
				Category = "4 - Bolts",
				Description = "Adds new silver bolts",
				EnabledByDefault = true,
				AssetPath = "Assets/PrefabInstance/BoltSilver.prefab",
				Type = FeatureType.Bolt,
				Amount = 20,
				Table = "Forge",
				MinTableLevel = 3,
				Requirements = "Wood:8,Silver:1,Feathers:2",
				Damages = "Pierce:52,Spirit:20",
				DependencyNames = new List<string> { "arbalest_projectile_wood.prefab" }
			});
			_features.Add(new FeatureItem("BoltPoison")
			{
				Category = "4 - Bolts",
				Description = "Adds new poison bolts",
				EnabledByDefault = true,
				AssetPath = "Assets/PrefabInstance/BoltPoison.prefab",
				Type = FeatureType.Bolt,
				Amount = 20,
				Table = "Workbench",
				MinTableLevel = 3,
				Requirements = "Wood:8,Obsidian:4,Feathers:2,Ooze:2",
				Damages = "Pierce:26,Poison:52",
				DependencyNames = new List<string> { "arbalest_projectile_poison.prefab" }
			});
			_features.Add(new FeatureItem("BoltFrost")
			{
				Category = "4 - Bolts",
				Description = "Adds new frost bolts",
				EnabledByDefault = true,
				AssetPath = "Assets/PrefabInstance/BoltFrost.prefab",
				Type = FeatureType.Bolt,
				Amount = 20,
				Table = "Workbench",
				MinTableLevel = 4,
				Requirements = "Wood:8,Obsidian:4,Feathers:2,FreezeGland:1",
				Damages = "Pierce:26,Frost:52",
				DependencyNames = new List<string> { "arbalest_projectile_frost.prefab" }
			});
			_features.Add(new FeatureItem("BoltLightning")
			{
				Category = "4 - Bolts",
				Description = "Adds new lightning bolts",
				EnabledByDefault = false,
				AssetPath = "Assets/PrefabInstance/BoltLightning.prefab",
				Type = FeatureType.Bolt,
				Amount = 20,
				Table = "BlackForge",
				MinTableLevel = 2,
				Requirements = "Wood:8,Feathers:2,Eitr:1",
				Damages = "Pierce:36,Lightning:62",
				DependencyNames = new List<string> { "sfx_lightning_hit.prefab", "arbalest_projectile_lightning.prefab" }
			});
			_features.Add(new FeatureItem("ArrowLightning")
			{
				Category = "3 - Arrows",
				Description = "Adds new lightning arrows",
				EnabledByDefault = false,
				AssetPath = "Assets/PrefabInstance/ArrowLightning.prefab",
				Type = FeatureType.Arrow,
				Amount = 20,
				Table = "BlackForge",
				MinTableLevel = 2,
				Requirements = "Wood:8,Feathers:2,Eitr:1",
				Damages = "Pierce:36,Lightning:62",
				DependencyNames = new List<string> { "sfx_lightning_hit.prefab", "arbalest_projectile_lightning.prefab" }
			});
			_features.Add(new FeatureItem("BoltOoze")
			{
				Category = "5 - Area Effect Bolts",
				Description = "Adds new Ooze bomb bolts.  These cause the same Ooze explosions as bombs. Damage set here is applied to both projectile & explosion.",
				EnabledByDefault = false,
				AssetPath = "Assets/PrefabInstance/BoltOoze.prefab",
				Type = FeatureType.Bolt,
				Amount = 10,
				Table = "Workbench",
				MinTableLevel = 1,
				Requirements = "Wood:4,Feathers:1,LeatherScraps:5,Ooze:5",
				Damages = "Pierce:5,Poison:40",
				AoePrefabName = "oozebomb_explosion",
				DependencyNames = new List<string> { "arbalest_projectile_ooze.prefab" }
			});
			_features.Add(new FeatureItem("BoltSurtling")
			{
				Category = "5 - Area Effect Bolts",
				Description = "Adds new Surtling bolts.  Damage set here is applied to both projectile & explosion.",
				EnabledByDefault = false,
				AssetPath = "Assets/PrefabInstance/BoltSurtling.prefab",
				Type = FeatureType.Bolt,
				Amount = 10,
				Table = "Forge",
				MinTableLevel = 4,
				Requirements = "Wood:4,Feathers:1,SurtlingCore:3,Iron:1",
				Damages = "Pierce:22,Fire:18",
				AoePrefabName = "firebolt_explosion",
				DependencyNames = new List<string> { "arbalest_projectile_surtling.prefab", "firebolt_explosion.prefab" }
			});
			_features.Add(new FeatureItem("BoltBile")
			{
				Category = "5 - Area Effect Bolts",
				Description = "Adds new Bile bomb bolts.  These cause the same Bile explosions as bombs. Damage set here is applied to both projectile & explosion.",
				EnabledByDefault = false,
				AssetPath = "Assets/PrefabInstance/BoltBile.prefab",
				Type = FeatureType.Bolt,
				Amount = 10,
				Table = "Workbench",
				MinTableLevel = 1,
				Requirements = "Wood:4,Feathers:1,Sap:3,Bilebag:3",
				Damages = "Pierce:22,Fire:15,Poison:30",
				AoePrefabName = "bilebomb_explosion",
				DependencyNames = new List<string> { "arbalest_projectile_bile.prefab" }
			});
			_features.Add(new FeatureItem("BoltIce")
			{
				Category = "5 - Area Effect Bolts",
				Description = "Adds new Ice bolts which strike an area with frost damage.  Damage set here is SPLIT between projectile & explosion.",
				EnabledByDefault = false,
				AssetPath = "Assets/PrefabInstance/BoltIce.prefab",
				Type = FeatureType.Bolt,
				Amount = 10,
				Table = "Forge",
				MinTableLevel = 4,
				Requirements = "Wood:4,Feathers:1,FreezeGland:3,BlackMetal:1",
				Damages = "Pierce:22,Frost:62",
				AoePrefabName = "icebolt_explosion",
				DependencyNames = new List<string> { "arbalest_projectile_ice.prefab", "icebolt_explosion.prefab" }
			});
			_features.Add(new FeatureItem("BoltFlametal")
			{
				Category = "5 - Area Effect Bolts",
				Description = "Adds new Flametal bolts.  Hits all targets very hard.  Damage set here is applied ONLY to projectile.",
				EnabledByDefault = false,
				AssetPath = "Assets/PrefabInstance/BoltFlametal.prefab",
				Type = FeatureType.Bolt,
				Amount = 10,
				Table = "BlackForge",
				MinTableLevel = 2,
				Requirements = "Flametal:1,Feathers:1,Eitr:3,SurtlingCore:3",
				Damages = "Blunt:22,Pierce:22,Fire:102",
				DependencyNames = new List<string> { "arbalest_projectile_flametal.prefab", "firebolt_explosion.prefab" }
			});
			_features.Add(new FeatureRecipe("BoltBone")
			{
				Category = "4 - Bolts",
				Description = "Enables bone bolts to be craftable earlier",
				EnabledByDefault = true,
				Type = FeatureType.Bolt,
				Table = "Workbench",
				MinTableLevel = 2,
				Requirements = "BoneFragments:8,Feathers:2",
				Amount = 20
			});
			_features.Add(new FeatureRecipe("BoltIron")
			{
				Category = "4 - Bolts",
				Description = "Enables iron bolts to be craftable earlier",
				EnabledByDefault = true,
				Type = FeatureType.Bolt,
				Table = "Forge",
				MinTableLevel = 2,
				Requirements = "Wood:8,Iron:1,Feathers:2",
				Amount = 20
			});
			_features.Add(new FeatureRecipe("BoltBlackmetal")
			{
				Category = "4 - Bolts",
				Description = "Enables blackmetal bolts to be craftable earlier",
				EnabledByDefault = true,
				Type = FeatureType.Bolt,
				Table = "Forge",
				MinTableLevel = 4,
				Requirements = "Wood:8,BlackMetal:2,Feathers:2",
				Amount = 20
			});
			foreach (Feature feature in _features)
			{
				feature.Initialize();
			}
		}

		ConfigFile IPlugin.get_Config()
		{
			return ((BaseUnityPlugin)this).Config;
		}
	}
}
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 Common
{
	internal class AcceptableValueConfigNote : AcceptableValueBase
	{
		public virtual string Note { get; }

		public AcceptableValueConfigNote(string note)
			: base(typeof(string))
		{
			if (string.IsNullOrEmpty(note))
			{
				throw new ArgumentException("A string with atleast 1 character is needed", "Note");
			}
			Note = note;
		}

		public override object Clamp(object value)
		{
			return value;
		}

		public override bool IsValid(object value)
		{
			return !string.IsNullOrEmpty(value as string);
		}

		public override string ToDescriptionString()
		{
			return "# Note: " + Note;
		}
	}
	internal static class ConfigHelper
	{
		public static ConfigurationManagerAttributes GetAdminOnlyFlag()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Expected O, but got Unknown
			return new ConfigurationManagerAttributes
			{
				IsAdminOnly = true
			};
		}

		public static ConfigurationManagerAttributes GetTags(Action<ConfigEntryBase> action)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Expected O, but got Unknown
			return new ConfigurationManagerAttributes
			{
				CustomDrawer = action
			};
		}

		public static ConfigurationManagerAttributes GetTags()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected O, but got Unknown
			return new ConfigurationManagerAttributes();
		}

		public static ConfigEntry<T> Config<T>(this IPlugin instance, string group, string name, T value, ConfigDescription description)
		{
			return instance.Config.Bind<T>(group, name, value, description);
		}

		public static ConfigEntry<T> Config<T>(this IPlugin instance, string group, string name, T value, string description)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Expected O, but got Unknown
			return instance.Config(group, name, value, new ConfigDescription(description, (AcceptableValueBase)null, new object[1] { GetAdminOnlyFlag() }));
		}
	}
	internal static class RequirementsEntry
	{
		public static RequirementConfig[] Deserialize(string reqs)
		{
			return ((IEnumerable<string>)reqs.Split(new char[1] { ',' })).Select((Func<string, RequirementConfig>)delegate(string r)
			{
				//IL_0012: Unknown result type (might be due to invalid IL or missing references)
				//IL_0017: Unknown result type (might be due to invalid IL or missing references)
				//IL_0020: Unknown result type (might be due to invalid IL or missing references)
				//IL_003c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0058: Unknown result type (might be due to invalid IL or missing references)
				//IL_0060: Expected O, but got Unknown
				string[] array = r.Split(new char[1] { ':' });
				int result;
				int result2;
				return new RequirementConfig
				{
					Item = array[0],
					Amount = ((array.Length <= 1 || !int.TryParse(array[1], out result)) ? 1 : result),
					AmountPerLevel = ((array.Length > 2 && int.TryParse(array[2], out result2)) ? result2 : 0),
					Recover = true
				};
			}).ToArray();
		}

		public static string Serialize(RequirementConfig[] reqs)
		{
			return string.Join(",", reqs.Select((RequirementConfig r) => (r.AmountPerLevel <= 0) ? $"{r.Item}:{r.Amount}" : $"{r.Item}:{r.Amount}:{r.AmountPerLevel}"));
		}
	}
	internal static class SharedDrawers
	{
		private static BaseUnityPlugin configManager;

		private static BaseUnityPlugin GetConfigManager()
		{
			if ((Object)(object)configManager == (Object)null && Chainloader.PluginInfos.TryGetValue("com.bepis.bepinex.configurationmanager", out var value) && Object.op_Implicit((Object)(object)value.Instance))
			{
				configManager = value.Instance;
			}
			return configManager;
		}

		public static int GetRightColumnWidth()
		{
			int result = 130;
			BaseUnityPlugin val = GetConfigManager();
			if ((Object)(object)val != (Object)null)
			{
				PropertyInfo propertyInfo = ((object)val)?.GetType().GetProperty("RightColumnWidth", BindingFlags.Instance | BindingFlags.NonPublic);
				if (propertyInfo != null)
				{
					result = (int)propertyInfo.GetValue(val);
				}
			}
			return result;
		}

		public static void ReloadConfigDisplay()
		{
			BaseUnityPlugin val = GetConfigManager();
			if ((Object)(object)val != (Object)null)
			{
				object obj = ((object)val).GetType()?.GetProperty("DisplayingWindow")?.GetValue(val);
				if (obj is bool && (bool)obj)
				{
					((object)val).GetType().GetMethod("BuildSettingList").Invoke(val, Array.Empty<object>());
				}
			}
		}

		public static Action<ConfigEntryBase> DrawReqConfigTable(bool hasUpgrades = false)
		{
			return delegate(ConfigEntryBase cfg)
			{
				//IL_005c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0061: Unknown result type (might be due to invalid IL or missing references)
				//IL_008d: Expected O, but got Unknown
				//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
				//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ee: Expected O, but got Unknown
				//IL_0163: Unknown result type (might be due to invalid IL or missing references)
				//IL_0168: Unknown result type (might be due to invalid IL or missing references)
				//IL_017d: Expected O, but got Unknown
				//IL_0125: Unknown result type (might be due to invalid IL or missing references)
				//IL_012a: Unknown result type (might be due to invalid IL or missing references)
				//IL_013f: Expected O, but got Unknown
				//IL_0184: Unknown result type (might be due to invalid IL or missing references)
				//IL_0189: Unknown result type (might be due to invalid IL or missing references)
				//IL_0191: Unknown result type (might be due to invalid IL or missing references)
				//IL_0199: Unknown result type (might be due to invalid IL or missing references)
				//IL_01a6: Expected O, but got Unknown
				//IL_01b5: Unknown result type (might be due to invalid IL or missing references)
				//IL_01ba: Unknown result type (might be due to invalid IL or missing references)
				//IL_01cf: Expected O, but got Unknown
				//IL_01d4: Unknown result type (might be due to invalid IL or missing references)
				//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
				//IL_01e4: Unknown result type (might be due to invalid IL or missing references)
				//IL_01f0: Expected O, but got Unknown
				List<RequirementConfig> list = new List<RequirementConfig>();
				bool flag = false;
				int rightColumnWidth = GetRightColumnWidth();
				GUILayout.BeginVertical(Array.Empty<GUILayoutOption>());
				foreach (RequirementConfig item in RequirementsEntry.Deserialize((string)cfg.BoxedValue).ToList())
				{
					GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
					string text = GUILayout.TextField(item.Item, new GUIStyle(GUI.skin.textField)
					{
						fixedWidth = rightColumnWidth - 33 - (hasUpgrades ? 37 : 0) - 21 - 21 - 12
					}, Array.Empty<GUILayoutOption>());
					string text2 = (string.IsNullOrEmpty(text) ? item.Item : text);
					flag = flag || text2 != item.Item;
					int num = item.Amount;
					if (int.TryParse(GUILayout.TextField(num.ToString(), new GUIStyle(GUI.skin.textField)
					{
						fixedWidth = 33f
					}, Array.Empty<GUILayoutOption>()), out var result) && result != num)
					{
						num = result;
						flag = true;
					}
					int num2 = item.AmountPerLevel;
					if (hasUpgrades && int.TryParse(GUILayout.TextField(num2.ToString(), new GUIStyle(GUI.skin.textField)
					{
						fixedWidth = 33f
					}, Array.Empty<GUILayoutOption>()), out var result2) && result2 != num2)
					{
						num2 = result2;
						flag = true;
					}
					if (GUILayout.Button("x", new GUIStyle(GUI.skin.button)
					{
						fixedWidth = 21f
					}, Array.Empty<GUILayoutOption>()))
					{
						flag = true;
					}
					else
					{
						list.Add(new RequirementConfig
						{
							Item = text2,
							Amount = num,
							AmountPerLevel = num2
						});
					}
					if (GUILayout.Button("+", new GUIStyle(GUI.skin.button)
					{
						fixedWidth = 21f
					}, Array.Empty<GUILayoutOption>()))
					{
						flag = true;
						list.Add(new RequirementConfig
						{
							Item = "<Prefab Name>",
							Amount = 1
						});
					}
					GUILayout.EndHorizontal();
				}
				GUILayout.EndVertical();
				if (flag)
				{
					cfg.BoxedValue = RequirementsEntry.Serialize(list.ToArray());
				}
			};
		}
	}
	internal class ConfigWatcher
	{
		private BaseUnityPlugin configurationManager;

		private IPlugin plugin;

		public ConfigWatcher(IPlugin plugin)
		{
			if (plugin == null)
			{
				throw new ArgumentNullException("plugin");
			}
			this.plugin = plugin;
			CheckForConfigManager();
		}

		private void InitializeWatcher()
		{
			string fileName = Path.GetFileName(plugin.Config.ConfigFilePath);
			new Watcher(Path.GetDirectoryName(plugin.Config.ConfigFilePath), fileName).FileChanged += OnFileChanged;
			Get.Plugin.LogDebugOnly("File system watcher initialized.");
		}

		private void CheckForConfigManager()
		{
			PluginInfo value;
			if (GUIManager.IsHeadless())
			{
				InitializeWatcher();
			}
			else if (Chainloader.PluginInfos.TryGetValue("com.bepis.bepinex.configurationmanager", out value) && Object.op_Implicit((Object)(object)value.Instance))
			{
				configurationManager = value.Instance;
				Get.Plugin.LogDebugOnly("Configuration manager found, hooking DisplayingWindowChanged");
				EventInfo @event = ((object)configurationManager).GetType().GetEvent("DisplayingWindowChanged");
				if (@event != null)
				{
					Action<object, object> action = OnConfigManagerDisplayingWindowChanged;
					Delegate handler = Delegate.CreateDelegate(@event.EventHandlerType, action.Target, action.Method);
					@event.AddEventHandler(configurationManager, handler);
				}
			}
			else
			{
				InitializeWatcher();
			}
		}

		private void OnFileChanged(object sender, FileSystemEventArgs e)
		{
			string configFilePath = plugin.Config.ConfigFilePath;
			if (!File.Exists(configFilePath))
			{
				return;
			}
			try
			{
				plugin.Config.SaveOnConfigSet = false;
				plugin.Config.Reload();
				plugin.Config.SaveOnConfigSet = true;
			}
			catch
			{
				Get.Plugin.LogError("There was an issue with your " + Path.GetFileName(configFilePath) + " file.");
				Get.Plugin.LogError("Please check the format and spelling.");
			}
		}

		private void OnConfigManagerDisplayingWindowChanged(object sender, object e)
		{
			if (!(bool)((object)configurationManager).GetType().GetProperty("DisplayingWindow").GetValue(configurationManager, null))
			{
				plugin.Config.SaveOnConfigSet = false;
				plugin.Config.Reload();
				plugin.Config.SaveOnConfigSet = true;
			}
		}
	}
	internal class CustomSyncedValueBase
	{
		private class Patches
		{
			[HarmonyPatch(typeof(ZNet), "Shutdown")]
			[HarmonyPostfix]
			private static void ZNet_Shutdown()
			{
				if (ZNetExtension.IsClientInstance(ZNet.instance))
				{
					foreach (CustomSyncedValueBase syncedValue in SyncedValues)
					{
						syncedValue.OnResetFromServer();
					}
					return;
				}
				foreach (CustomSyncedValueBase syncedValue2 in SyncedValues)
				{
					syncedValue2.OnServerShutdown();
				}
			}
		}

		public readonly string Name;

		public readonly Type Type;

		private object? boxedValue;

		public object? LocalBaseValue;

		private CustomRPC customRPC;

		private static readonly HashSet<CustomSyncedValueBase> SyncedValues = new HashSet<CustomSyncedValueBase>();

		private static Harmony harmony = null;

		public bool IsSourceOfTruth { get; private set; } = true;


		public object? BoxedValue
		{
			get
			{
				return boxedValue;
			}
			set
			{
				boxedValue = value;
				this.ValueChanged?.Invoke(this, value);
			}
		}

		public event Action<object, object>? ValueChanged;

		protected CustomSyncedValueBase(string name, Type type, object? initialValue)
		{
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Expected O, but got Unknown
			//IL_00af: Expected O, but got Unknown
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Expected O, but got Unknown
			Name = name;
			Type = type;
			SyncedValues.Add(this);
			if (harmony == null)
			{
				harmony = (Harmony)AccessTools.Field(typeof(Main), "Harmony").GetValue(null);
				harmony.PatchAll(typeof(Patches));
				Get.Plugin.LogDebugOnly("Jotunn's harmony instance obtained, CustomSyncedValueBase+Patches applied.");
			}
			boxedValue = initialValue;
			customRPC = NetworkManager.Instance.AddRPC(Name + "_CustomSyncedValue_RPC", new CoroutineHandler(OnServerReceive), new CoroutineHandler(OnClientReceive));
			SynchronizationManager.Instance.AddInitialSynchronization(customRPC, (Func<ZPackage>)GetPackage);
		}

		public void SendPackage()
		{
			if ((Object)(object)ZNet.instance == (Object)null)
			{
				Get.Plugin.LogDebugOnly("SendPackage called but am not connected.");
			}
			if (!SynchronizationManager.Instance.PlayerIsAdmin)
			{
				Get.Plugin.LogDebugOnly("SendPackage called but Player is not admin.");
			}
			if ((Object)(object)ZNet.instance != (Object)null && SynchronizationManager.Instance.PlayerIsAdmin)
			{
				ZPackage package = GetPackage();
				if (ZNetExtension.IsClientInstance(ZNet.instance))
				{
					customRPC.SendPackage(ZRoutedRpc.instance.GetServerPeerID(), package);
				}
				else
				{
					customRPC.SendPackage(ZNet.instance.m_peers, package);
				}
			}
		}

		private ZPackage GetPackage()
		{
			return new PackageEntry
			{
				key = Name,
				type = Type,
				value = boxedValue
			}.ToPackage();
		}

		private IEnumerator OnServerReceive(long sender, ZPackage package)
		{
			Get.Plugin.LogDebugOnly($"Server received RPC: {sender} {package}");
			yield return null;
			ParsedEntries parsedEntries = package.ReadEntries();
			if (parsedEntries.Count > 0 && parsedEntries.TryGetValue(Name, out var value))
			{
				BoxedValue = (LocalBaseValue = value.value);
				Get.Plugin.LogDebugOnly($"Set local and boxed: {value.value}");
				customRPC.SendPackage(ZNet.instance.m_peers.Where((ZNetPeer x) => x.m_uid != sender).ToList(), package);
			}
			else
			{
				OnReceiveError(parsedEntries);
			}
		}

		private IEnumerator OnClientReceive(long sender, ZPackage package)
		{
			Get.Plugin.LogDebugOnly($"Client received RPC: {sender} {package}");
			yield return null;
			ParsedEntries parsedEntries = package.ReadEntries();
			if (parsedEntries.Count > 0 && parsedEntries.TryGetValue(Name, out var value))
			{
				IsSourceOfTruth = false;
				if (LocalBaseValue == null)
				{
					LocalBaseValue = BoxedValue;
				}
				BoxedValue = value.value;
				Get.Plugin.LogDebugOnly($"Set source of truth: {IsSourceOfTruth}, {Environment.NewLine}local: {LocalBaseValue} {Environment.NewLine}boxed: {BoxedValue}");
			}
			else
			{
				OnReceiveError(parsedEntries);
			}
		}

		private void OnReceiveError(ParsedEntries entries)
		{
			Get.Plugin.LogWarning(Name + "_CustomSyncedValue_RPC recieved package without expected key: " + Name);
			string text = "";
			foreach (KeyValuePair<string, PackageEntry> entry in entries)
			{
				text += $"{entry.Key} - {entry.Value.type} - {entry.Value.value?.ToString()} {Environment.NewLine}";
			}
			Get.Plugin.LogWarning("Result: " + Environment.NewLine + text);
		}

		private void OnResetFromServer()
		{
			BoxedValue = LocalBaseValue;
			IsSourceOfTruth = true;
			LocalBaseValue = null;
		}

		private void OnServerShutdown()
		{
		}
	}
	internal sealed class CustomSyncedValue<T> : CustomSyncedValueBase
	{
		public T Value
		{
			get
			{
				return (T)base.BoxedValue;
			}
			set
			{
				base.BoxedValue = value;
				if (base.BoxedValue != null)
				{
					SendPackage();
				}
			}
		}

		public CustomSyncedValue(string name, T value = default(T))
			: base(name, typeof(T), value)
		{
		}

		public void AssignLocalValue(T value)
		{
			if (base.IsSourceOfTruth && SynchronizationManager.Instance.PlayerIsAdmin)
			{
				Value = value;
			}
			else
			{
				LocalBaseValue = value;
			}
		}
	}
	internal class ParsedEntries : Dictionary<string, PackageEntry>
	{
	}
	internal class PackageEntry
	{
		public string key;

		public Type type;

		public object? value;
	}
	internal class InvalidDeserializationTypeException : Exception
	{
		public string expected;

		public string received;

		public string field = "";
	}
	internal static class PackageUtils
	{
		public static string GetPackageTypeString(Type type)
		{
			return type.AssemblyQualifiedName;
		}

		public static void AddValue(this ZPackage package, object? value)
		{
			Type type = value?.GetType();
			if (value is Enum)
			{
				value = ((IConvertible)value).ToType(Enum.GetUnderlyingType(value.GetType()), CultureInfo.InvariantCulture);
			}
			else
			{
				if (value is ICollection collection)
				{
					package.Write(collection.Count);
					{
						foreach (object item in collection)
						{
							package.AddValue(item);
						}
						return;
					}
				}
				if ((object)type != null && type.IsValueType && !type.IsPrimitive)
				{
					FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					package.Write(fields.Length);
					FieldInfo[] array = fields;
					foreach (FieldInfo fieldInfo in array)
					{
						package.Write(GetPackageTypeString(fieldInfo.FieldType));
						package.AddValue(fieldInfo.GetValue(value));
					}
					return;
				}
			}
			ZRpc.Serialize(new object[1] { value }, ref package);
		}

		public static void AddEntry(this ZPackage package, PackageEntry entry)
		{
			package.Write(entry.key);
			package.Write((entry.value == null) ? "" : GetPackageTypeString(entry.type));
			package.AddValue(entry.value);
		}

		public static ZPackage ToPackage(this PackageEntry packageEntry)
		{
			return new List<PackageEntry> { packageEntry }.ToPackage();
		}

		public static ZPackage ToPackage(this IEnumerable<PackageEntry> packageEntries)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected O, but got Unknown
			ZPackage val = new ZPackage();
			val.Write(packageEntries?.Count() ?? 0);
			foreach (PackageEntry item in packageEntries ?? Array.Empty<PackageEntry>())
			{
				val.AddEntry(item);
			}
			return val;
		}

		public static object ReadValueWithType(this ZPackage package, Type type)
		{
			if ((object)type != null && type.IsValueType && !type.IsPrimitive && !type.IsEnum)
			{
				FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				int num = package.ReadInt();
				if (num != fields.Length)
				{
					throw new InvalidDeserializationTypeException
					{
						received = $"(field count: {num})",
						expected = $"(field count: {fields.Length})"
					};
				}
				object uninitializedObject = FormatterServices.GetUninitializedObject(type);
				FieldInfo[] array = fields;
				foreach (FieldInfo fieldInfo in array)
				{
					string text = package.ReadString();
					if (text != GetPackageTypeString(fieldInfo.FieldType))
					{
						throw new InvalidDeserializationTypeException
						{
							received = text,
							expected = GetPackageTypeString(fieldInfo.FieldType),
							field = fieldInfo.Name
						};
					}
					fieldInfo.SetValue(uninitializedObject, package.ReadValueWithType(fieldInfo.FieldType));
				}
				return uninitializedObject;
			}
			if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Dictionary<, >))
			{
				int num2 = package.ReadInt();
				IDictionary dictionary = (IDictionary)Activator.CreateInstance(type);
				Type type2 = typeof(KeyValuePair<, >).MakeGenericType(type.GenericTypeArguments);
				FieldInfo field = type2.GetField("key", BindingFlags.Instance | BindingFlags.NonPublic);
				FieldInfo field2 = type2.GetField("value", BindingFlags.Instance | BindingFlags.NonPublic);
				for (int j = 0; j < num2; j++)
				{
					object obj = package.ReadValueWithType(type2);
					dictionary.Add(field.GetValue(obj), field2.GetValue(obj));
				}
				return dictionary;
			}
			if (type != typeof(List<string>) && type.IsGenericType)
			{
				Type type3 = typeof(ICollection<>).MakeGenericType(type.GenericTypeArguments[0]);
				if ((object)type3 != null && type3.IsAssignableFrom(type))
				{
					int num3 = package.ReadInt();
					object obj2 = Activator.CreateInstance(type);
					MethodInfo method = type3.GetMethod("Add");
					for (int k = 0; k < num3; k++)
					{
						method.Invoke(obj2, new object[1] { package.ReadValueWithType(type.GenericTypeArguments[0]) });
					}
					return obj2;
				}
			}
			ParameterInfo parameterInfo = (ParameterInfo)FormatterServices.GetUninitializedObject(typeof(ParameterInfo));
			AccessTools.DeclaredField(typeof(ParameterInfo), "ClassImpl").SetValue(parameterInfo, type);
			List<object> source = new List<object>();
			ZRpc.Deserialize(new ParameterInfo[2] { null, parameterInfo }, package, ref source);
			return source.FirstOrDefault();
		}

		public static ParsedEntries ReadEntries(this ZPackage package)
		{
			ParsedEntries parsedEntries = new ParsedEntries();
			int num = package.ReadInt();
			for (int i = 0; i < num; i++)
			{
				string key = package.ReadString();
				string text = package.ReadString();
				Type type = Type.GetType(text);
				if (text == "" || type != null)
				{
					object obj;
					try
					{
						obj = ((text == "") ? null : package.ReadValueWithType(type));
					}
					catch (InvalidDeserializationTypeException ex)
					{
						Get.Plugin.LogWarning("Got unexpected struct internal type " + ex.received + " for field " + ex.field + " struct " + text);
						continue;
					}
					if (obj != null)
					{
						parsedEntries[key] = new PackageEntry
						{
							key = key,
							type = type,
							value = obj
						};
					}
					continue;
				}
				Get.Plugin.LogWarning("Got invalid type " + text + ", abort reading of received configs");
				return new ParsedEntries();
			}
			return parsedEntries;
		}

		public static void Test()
		{
		}
	}
	internal interface IPlugin
	{
		ConfigFile Config { get; }

		bool Debug { get; }

		ManualLogSource Logger { get; }
	}
	internal static class LoggingExtensions
	{
		private static readonly Dictionary<string, ManualLogSource> logSources = new Dictionary<string, ManualLogSource>();

		internal static ManualLogSource GetLogger(this IPlugin mod)
		{
			if (mod.Debug)
			{
				Type declaringType = new StackFrame(2).GetMethod().DeclaringType;
				if (!logSources.TryGetValue(declaringType.FullName, out var value))
				{
					value = Logger.CreateLogSource(declaringType.FullName);
					logSources.Add(declaringType.FullName, value);
				}
				return value;
			}
			return mod.Logger;
		}

		public static void LogDebugOnly(this IPlugin mod, object data)
		{
			if (mod.Debug)
			{
				mod.GetLogger().LogDebug(data);
			}
		}

		public static void LogDebug(this IPlugin mod, object data)
		{
			if (mod.Debug)
			{
				mod.GetLogger().LogDebug(data);
			}
			else
			{
				mod.Logger.LogDebug(data);
			}
		}

		public static void LogInfo(this IPlugin mod, object data)
		{
			if (mod.Debug)
			{
				mod.GetLogger().LogInfo(data);
			}
			else
			{
				mod.Logger.LogInfo(data);
			}
		}

		public static void LogMessage(this IPlugin mod, object data)
		{
			if (mod.Debug)
			{
				mod.GetLogger().LogMessage(data);
			}
			else
			{
				mod.Logger.LogMessage(data);
			}
		}

		public static void LogWarning(this IPlugin mod, object data)
		{
			if (mod.Debug)
			{
				mod.GetLogger().LogWarning(data);
			}
			else
			{
				mod.Logger.LogWarning(data);
			}
		}

		public static void LogError(this IPlugin mod, object data)
		{
			if (mod.Debug)
			{
				mod.GetLogger().LogError(data);
			}
			else
			{
				mod.Logger.LogError(data);
			}
		}

		public static void LogFatal(this IPlugin mod, object data)
		{
			if (mod.Debug)
			{
				mod.GetLogger().LogFatal(data);
			}
			else
			{
				mod.Logger.LogFatal(data);
			}
		}
	}
	internal static class Get
	{
		private static IPlugin cachedModRef;

		public static IPlugin Plugin
		{
			get
			{
				if (cachedModRef == null)
				{
					cachedModRef = AccessTools.Field((from p in new StackFrame(0).GetMethod().DeclaringType.Assembly.GetTypes()
						where typeof(IPlugin).IsAssignableFrom(p)
						select p).FirstOrDefault(), "Instance").GetValue(null) as IPlugin;
					cachedModRef.LogDebugOnly("Caching static mod reference");
				}
				return cachedModRef;
			}
		}
	}
	internal class Watcher
	{
		private FileSystemWatcher fileSystemWatcher;

		public bool EnableRaisingEvents
		{
			get
			{
				if (fileSystemWatcher != null)
				{
					return fileSystemWatcher.EnableRaisingEvents;
				}
				return false;
			}
			set
			{
				if (fileSystemWatcher != null)
				{
					fileSystemWatcher.EnableRaisingEvents = value;
				}
			}
		}

		public event Action<object, FileSystemEventArgs>? FileChanged;

		public Watcher(string path, string filter)
		{
			if (path == null)
			{
				throw new ArgumentNullException("path");
			}
			if (filter == null)
			{
				throw new ArgumentNullException("filter");
			}
			Get.Plugin.LogDebugOnly("Watcher created for " + path + ", " + filter);
			fileSystemWatcher = new FileSystemWatcher(path, filter);
			fileSystemWatcher.Changed += OnCreatedChangedOrRenamed;
			fileSystemWatcher.Created += OnCreatedChangedOrRenamed;
			fileSystemWatcher.Renamed += OnCreatedChangedOrRenamed;
			fileSystemWatcher.IncludeSubdirectories = true;
			fileSystemWatcher.SynchronizingObject = ThreadingHelper.SynchronizingObject;
			fileSystemWatcher.EnableRaisingEvents = true;
		}

		private void OnCreatedChangedOrRenamed(object sender, FileSystemEventArgs args)
		{
			Get.Plugin.LogDebugOnly($"OnCreatedChangedOrRenamed triggered {args.Name}, {args.ChangeType}");
			this.FileChanged?.Invoke(sender, args);
		}
	}
}