Decompiled source of PerspexModpack v1.2.20

BepInEx/plugins/Building.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
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.RegularExpressions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using HarmonyLib;
using JetBrains.Annotations;
using Microsoft.CodeAnalysis;
using ServerSync;
using SkillManager;
using TMPro;
using UnityEngine;

[assembly: Guid("9BF5432D-9518-4D36-A6C2-A8C62D36B921")]
[assembly: ComVisible(false)]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCopyright("Copyright ©  2021")]
[assembly: AssemblyProduct("Building")]
[assembly: AssemblyCompany("")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyDescription("https://valheim.thunderstore.io/package/Smoothbrain/Building")]
[assembly: AssemblyTitle("Building")]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: CompilationRelaxations(8)]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyConfiguration("")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[<977eed0d-c853-44d0-91ff-4cb8fe69933a>Embedded]
	internal sealed class <977eed0d-c853-44d0-91ff-4cb8fe69933a>EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[<977eed0d-c853-44d0-91ff-4cb8fe69933a>Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class <d01731d2-401a-4d69-91d0-be2439379d5f>NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public <d01731d2-401a-4d69-91d0-be2439379d5f>NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public <d01731d2-401a-4d69-91d0-be2439379d5f>NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[<977eed0d-c853-44d0-91ff-4cb8fe69933a>Embedded]
	[CompilerGenerated]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class <938d2326-56ad-4947-9bb0-9ced4308b262>NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public <938d2326-56ad-4947-9bb0-9ced4308b262>NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
}
namespace Building
{
	[BepInIncompatibility("org.bepinex.plugins.valheim_plus")]
	[BepInPlugin("org.bepinex.plugins.building", "Building", "1.2.5")]
	[<d01731d2-401a-4d69-91d0-be2439379d5f>Nullable(0)]
	[<938d2326-56ad-4947-9bb0-9ced4308b262>NullableContext(1)]
	public class Building : BaseUnityPlugin
	{
		[<938d2326-56ad-4947-9bb0-9ced4308b262>NullableContext(0)]
		private enum Toggle
		{
			On = 1,
			Off = 0
		}

		[<938d2326-56ad-4947-9bb0-9ced4308b262>NullableContext(0)]
		private class ConfigurationManagerAttributes
		{
			[UsedImplicitly]
			public bool? ShowRangeAsPercent;
		}

		[<938d2326-56ad-4947-9bb0-9ced4308b262>NullableContext(0)]
		[HarmonyPatch(typeof(Player), "UpdatePlacement")]
		private static class ChangeStaminaUsage
		{
			private static float stamina;

			[<938d2326-56ad-4947-9bb0-9ced4308b262>NullableContext(1)]
			private static void Prefix(Player __instance, [<d01731d2-401a-4d69-91d0-be2439379d5f>Nullable(2)] out ItemData __state)
			{
				__state = ((Humanoid)__instance).GetRightItem();
				if (__state?.m_shared.m_name == "$item_hammer")
				{
					stamina = __state.m_shared.m_attack.m_attackStamina;
					Attack attack = __state.m_shared.m_attack;
					attack.m_attackStamina *= Mathf.Max(0f, 1f - ((Character)(object)__instance).GetSkillFactor("Building") * (float)staminaReductionPerLevel.Value);
				}
			}

			[<938d2326-56ad-4947-9bb0-9ced4308b262>NullableContext(2)]
			private static void Finalizer(ItemData __state)
			{
				if (__state?.m_shared.m_name == "$item_hammer")
				{
					__state.m_shared.m_attack.m_attackStamina = stamina;
				}
			}
		}

		[<938d2326-56ad-4947-9bb0-9ced4308b262>NullableContext(0)]
		[HarmonyPatch(typeof(WearNTear), "OnPlaced")]
		public class AddZDO
		{
			public static bool forFree;

			[<938d2326-56ad-4947-9bb0-9ced4308b262>NullableContext(1)]
			[UsedImplicitly]
			private static void Postfix(WearNTear __instance)
			{
				((Component)__instance).GetComponent<ZNetView>().GetZDO().Set("BuildingSkill Level", ((Character)(object)Player.m_localPlayer).GetSkillFactor("Building"));
				__instance.m_health *= 1f + ((Component)__instance).GetComponent<ZNetView>().GetZDO().GetFloat("BuildingSkill Level", 0f) * (healthFactor.Value - 1f);
				if (freeBuildLevelRequirement.Value > 0)
				{
					forFree = Random.Range((float)freeBuildLevelRequirement.Value / 100f, 5.5f) <= ((Character)(object)Player.m_localPlayer).GetSkillFactor("Building");
				}
				((Component)__instance).GetComponent<ZNetView>().GetZDO().Set("BuildingSkill FreeBuild", forFree);
				if (((Humanoid)Player.m_localPlayer).GetRightItem() != null && !((Humanoid)Player.m_localPlayer).GetRightItem().m_shared.m_name.ToLower().Contains("blueprint"))
				{
					((Character)(object)Player.m_localPlayer).RaiseSkill("Building");
				}
			}
		}

		[<938d2326-56ad-4947-9bb0-9ced4308b262>NullableContext(0)]
		[HarmonyPatch(typeof(WearNTear), "Awake")]
		private class IncreaseHealth
		{
			[<938d2326-56ad-4947-9bb0-9ced4308b262>NullableContext(1)]
			[UsedImplicitly]
			private static void Prefix(WearNTear __instance)
			{
				float health = __instance.m_health;
				float num = 1f;
				ZDO zDO = ((Component)__instance).GetComponent<ZNetView>().GetZDO();
				__instance.m_health = health * (num + ((zDO != null) ? new float?(zDO.GetFloat("BuildingSkill Level", 0f)) : null) * (healthFactor.Value - 1f)).GetValueOrDefault(1f);
			}
		}

		[<938d2326-56ad-4947-9bb0-9ced4308b262>NullableContext(0)]
		[HarmonyPatch(typeof(WearNTear), "GetMaterialProperties")]
		private class BuildHigher
		{
			[UsedImplicitly]
			[<938d2326-56ad-4947-9bb0-9ced4308b262>NullableContext(1)]
			private static void Postfix(WearNTear __instance, ref float maxSupport, ref float minSupport, ref float horizontalLoss, ref float verticalLoss)
			{
				ZNetView nview = __instance.m_nview;
				float? obj;
				if (nview == null)
				{
					obj = null;
				}
				else
				{
					ZDO zDO = nview.GetZDO();
					obj = ((zDO != null) ? new float?(zDO.GetFloat("BuildingSkill Level", 0f)) : null);
				}
				float num = obj ?? ((Character)(object)Player.m_localPlayer)?.GetSkillFactor("Building") ?? 0f;
				maxSupport *= 1f + num * (maximumSupportFactor.Value - 1f);
				horizontalLoss *= 1f - num * (1f - supportLossFactor.Value);
				verticalLoss *= 1f - num * (1f - supportLossFactor.Value);
			}
		}

		[<938d2326-56ad-4947-9bb0-9ced4308b262>NullableContext(0)]
		[HarmonyPatch(typeof(Player), "UpdatePlacement")]
		private class ResetFlag
		{
			private static void Finalizer()
			{
				AddZDO.forFree = false;
			}
		}

		[HarmonyPatch(typeof(Player), "ConsumeResources")]
		[<938d2326-56ad-4947-9bb0-9ced4308b262>NullableContext(0)]
		private class BuildingIsFree
		{
			private class SkipConsumeResourcesException : Exception
			{
			}

			[HarmonyPriority(800)]
			private static void Prefix()
			{
				if (AddZDO.forFree)
				{
					throw new SkipConsumeResourcesException();
				}
			}

			[<938d2326-56ad-4947-9bb0-9ced4308b262>NullableContext(1)]
			[return: <d01731d2-401a-4d69-91d0-be2439379d5f>Nullable(2)]
			private static Exception Finalizer(Exception __exception)
			{
				if (!(__exception is SkipConsumeResourcesException))
				{
					return __exception;
				}
				return null;
			}
		}

		[HarmonyPatch(typeof(Piece), "DropResources")]
		[<938d2326-56ad-4947-9bb0-9ced4308b262>NullableContext(0)]
		private class RecoverResources
		{
			[<938d2326-56ad-4947-9bb0-9ced4308b262>NullableContext(1)]
			private static bool Prefix(Piece __instance)
			{
				return !((Component)__instance).GetComponent<ZNetView>().GetZDO().GetBool("BuildingSkill FreeBuild", false);
			}
		}

		[<d01731d2-401a-4d69-91d0-be2439379d5f>Nullable(0)]
		[HarmonyPatch(typeof(Player), "UpdatePlacement")]
		private static class ReduceHammerDurabilityLoss
		{
			private static bool reduced;

			private static void Prefix(Player __instance)
			{
				reduced = false;
				if (durabilityUsageLevelRequirement.Value > 0 && (float)durabilityUsageLevelRequirement.Value <= ((Character)(object)__instance).GetSkillFactor("Building") * 100f)
				{
					ItemData rightItem = ((Humanoid)__instance).GetRightItem();
					if (rightItem != null)
					{
						SharedData shared = rightItem.m_shared;
						shared.m_useDurabilityDrain *= 0.7f;
						reduced = true;
					}
				}
			}

			private static void Finalizer(Player __instance)
			{
				ItemData rightItem = ((Humanoid)__instance).GetRightItem();
				if (rightItem != null && reduced)
				{
					SharedData shared = rightItem.m_shared;
					shared.m_useDurabilityDrain /= 0.7f;
				}
			}
		}

		private const string ModName = "Building";

		private const string ModVersion = "1.2.5";

		private const string ModGUID = "org.bepinex.plugins.building";

		private static readonly ConfigSync configSync = new ConfigSync("org.bepinex.plugins.building")
		{
			DisplayName = "Building",
			CurrentVersion = "1.2.5",
			MinimumRequiredVersion = "1.2.5"
		};

		private static ConfigEntry<Toggle> serverConfigLocked = null;

		private static ConfigEntry<float> maximumSupportFactor = null;

		private static ConfigEntry<float> supportLossFactor = null;

		private static ConfigEntry<float> healthFactor = null;

		private static ConfigEntry<int> freeBuildLevelRequirement = null;

		private static ConfigEntry<int> durabilityUsageLevelRequirement = null;

		private static ConfigEntry<float> experienceGainedFactor = null;

		private static ConfigEntry<int> experienceLoss = null;

		private static ConfigEntry<int> staminaReductionPerLevel = null;

		private static Skill building = null;

		private ConfigEntry<T> config<[<d01731d2-401a-4d69-91d0-be2439379d5f>Nullable(2)] T>(string group, string name, T value, ConfigDescription description, bool synchronizedSetting = true)
		{
			ConfigEntry<T> val = ((BaseUnityPlugin)this).Config.Bind<T>(group, name, value, description);
			configSync.AddConfigEntry<T>(val).SynchronizedConfig = synchronizedSetting;
			return val;
		}

		private ConfigEntry<T> config<[<d01731d2-401a-4d69-91d0-be2439379d5f>Nullable(2)] T>(string group, string name, T value, string description, bool synchronizedSetting = true)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Expected O, but got Unknown
			return config(group, name, value, new ConfigDescription(description, (AcceptableValueBase)null, Array.Empty<object>()), synchronizedSetting);
		}

		public void Awake()
		{
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Expected O, but got Unknown
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Expected O, but got Unknown
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Expected O, but got Unknown
			//IL_0169: Unknown result type (might be due to invalid IL or missing references)
			//IL_0174: Expected O, but got Unknown
			//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b8: Expected O, but got Unknown
			//IL_01db: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e6: Expected O, but got Unknown
			//IL_0214: Unknown result type (might be due to invalid IL or missing references)
			//IL_021f: Expected O, but got Unknown
			//IL_027f: Unknown result type (might be due to invalid IL or missing references)
			//IL_028a: Expected O, but got Unknown
			//IL_02d7: Unknown result type (might be due to invalid IL or missing references)
			building = new Skill("Building", "building-icon.png");
			building.Description.English("Increases the health of pieces built by you and you can build higher.");
			building.Name.German("Bauen");
			building.Description.German("Erhöht die Lebenspunkte von Bauten, die von dir errichtet wurden und du kannst höher bauen.");
			building.Configurable = false;
			serverConfigLocked = config("1 - General", "Lock Configuration", Toggle.On, "If on, the configuration is locked and can be changed by server admins only.");
			configSync.AddLockingConfigEntry<Toggle>(serverConfigLocked);
			maximumSupportFactor = config("2 - Building", "Maximum Support Factor", 1.5f, new ConfigDescription("Maximum support factor for building pieces at skill level 100.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 5f), Array.Empty<object>()));
			supportLossFactor = config("2 - Building", "Support Loss Factor", 0.75f, new ConfigDescription("Support loss factor for vertical and horizontal building at skill level 100.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.01f, 1f), Array.Empty<object>()));
			healthFactor = config("2 - Building", "Health Factor", 3f, new ConfigDescription("Health factor for building pieces at skill level 100.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 10f), Array.Empty<object>()));
			freeBuildLevelRequirement = config("2 - Building", "Free Build Level Requirement", 50, new ConfigDescription("Minimum required skill level to be able to receive free building pieces. 0 is disabled.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), new object[1]
			{
				new ConfigurationManagerAttributes
				{
					ShowRangeAsPercent = false
				}
			}));
			durabilityUsageLevelRequirement = config("2 - Building", "Durability Increase Level Requirement", 30, new ConfigDescription("Minimum required skill level to reduce the durability usage of hammers by 30%. 0 is disabled.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), new object[1]
			{
				new ConfigurationManagerAttributes
				{
					ShowRangeAsPercent = false
				}
			}));
			staminaReductionPerLevel = config("2 - Building", "Stamina Reduction per Level", 1, new ConfigDescription("Reduces the stamina usage while building. Percentage stamina reduction per level. 0 is disabled.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>()));
			experienceGainedFactor = config("3 - Other", "Skill Experience Gain Factor", 1f, new ConfigDescription("Factor for experience gained for the building skill.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.01f, 5f), Array.Empty<object>()));
			experienceGainedFactor.SettingChanged += [<938d2326-56ad-4947-9bb0-9ced4308b262>NullableContext(0)] (object _, EventArgs _) =>
			{
				building.SkillGainFactor = experienceGainedFactor.Value;
			};
			building.SkillGainFactor = experienceGainedFactor.Value;
			experienceLoss = config("3 - Other", "Skill Experience Loss", 0, new ConfigDescription("How much experience to lose in the building skill on death.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>()));
			experienceLoss.SettingChanged += [<938d2326-56ad-4947-9bb0-9ced4308b262>NullableContext(0)] (object _, EventArgs _) =>
			{
				building.SkillLoss = experienceLoss.Value;
			};
			building.SkillLoss = experienceLoss.Value;
			Assembly executingAssembly = Assembly.GetExecutingAssembly();
			new Harmony("org.bepinex.plugins.building").PatchAll(executingAssembly);
		}
	}
}
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[<e52d898c-2dea-414b-a39e-63ce1f453974>Embedded]
	internal sealed class <e52d898c-2dea-414b-a39e-63ce1f453974>EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	[<e52d898c-2dea-414b-a39e-63ce1f453974>Embedded]
	internal sealed class <1725a767-56f4-45e7-970f-3089dc995b62>NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public <1725a767-56f4-45e7-970f-3089dc995b62>NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public <1725a767-56f4-45e7-970f-3089dc995b62>NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[<e52d898c-2dea-414b-a39e-63ce1f453974>Embedded]
	[CompilerGenerated]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class <4cd033a6-260d-4d69-97cc-f94c181d531a>NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public <4cd033a6-260d-4d69-97cc-f94c181d531a>NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[<e52d898c-2dea-414b-a39e-63ce1f453974>Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	[CompilerGenerated]
	internal sealed class <10b0b599-e852-4dce-b713-4e0984a2c333>RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public <10b0b599-e852-4dce-b713-4e0984a2c333>RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace SkillManager
{
	[<4cd033a6-260d-4d69-97cc-f94c181d531a>NullableContext(1)]
	[<1725a767-56f4-45e7-970f-3089dc995b62>Nullable(0)]
	[PublicAPI]
	internal class Skill
	{
		[<1725a767-56f4-45e7-970f-3089dc995b62>Nullable(0)]
		public static class LocalizationCache
		{
			private static readonly Dictionary<string, Localization> localizations = new Dictionary<string, Localization>();

			internal static void LocalizationPostfix(Localization __instance, string language)
			{
				string key = localizations.FirstOrDefault([<4cd033a6-260d-4d69-97cc-f94c181d531a>NullableContext(0)] (KeyValuePair<string, Localization> l) => l.Value == __instance).Key;
				if (key != null)
				{
					localizations.Remove(key);
				}
				if (!localizations.ContainsKey(language))
				{
					localizations.Add(language, __instance);
				}
			}

			public static Localization ForLanguage([<1725a767-56f4-45e7-970f-3089dc995b62>Nullable(2)] string language = null)
			{
				//IL_0024: Unknown result type (might be due to invalid IL or missing references)
				//IL_002a: Expected O, but got Unknown
				if (localizations.TryGetValue(language ?? PlayerPrefs.GetString("language", "English"), out var value))
				{
					return value;
				}
				value = new Localization();
				if (language != null)
				{
					value.SetupLanguage(language);
				}
				return value;
			}
		}

		[PublicAPI]
		[<1725a767-56f4-45e7-970f-3089dc995b62>Nullable(0)]
		public class LocalizeKey
		{
			private static readonly List<LocalizeKey> keys = new List<LocalizeKey>();

			public readonly string Key;

			public readonly Dictionary<string, string> Localizations = new Dictionary<string, string>();

			public LocalizeKey(string key)
			{
				Key = key.Replace("$", "");
				keys.Add(this);
			}

			public void Alias(string alias)
			{
				Localizations.Clear();
				if (!alias.Contains("$"))
				{
					alias = "$" + alias;
				}
				Localizations["alias"] = alias;
				Localization.instance.AddWord(Key, Localization.instance.Localize(alias));
			}

			public LocalizeKey English(string key)
			{
				return addForLang("English", key);
			}

			public LocalizeKey Swedish(string key)
			{
				return addForLang("Swedish", key);
			}

			public LocalizeKey French(string key)
			{
				return addForLang("French", key);
			}

			public LocalizeKey Italian(string key)
			{
				return addForLang("Italian", key);
			}

			public LocalizeKey German(string key)
			{
				return addForLang("German", key);
			}

			public LocalizeKey Spanish(string key)
			{
				return addForLang("Spanish", key);
			}

			public LocalizeKey Russian(string key)
			{
				return addForLang("Russian", key);
			}

			public LocalizeKey Romanian(string key)
			{
				return addForLang("Romanian", key);
			}

			public LocalizeKey Bulgarian(string key)
			{
				return addForLang("Bulgarian", key);
			}

			public LocalizeKey Macedonian(string key)
			{
				return addForLang("Macedonian", key);
			}

			public LocalizeKey Finnish(string key)
			{
				return addForLang("Finnish", key);
			}

			public LocalizeKey Danish(string key)
			{
				return addForLang("Danish", key);
			}

			public LocalizeKey Norwegian(string key)
			{
				return addForLang("Norwegian", key);
			}

			public LocalizeKey Icelandic(string key)
			{
				return addForLang("Icelandic", key);
			}

			public LocalizeKey Turkish(string key)
			{
				return addForLang("Turkish", key);
			}

			public LocalizeKey Lithuanian(string key)
			{
				return addForLang("Lithuanian", key);
			}

			public LocalizeKey Czech(string key)
			{
				return addForLang("Czech", key);
			}

			public LocalizeKey Hungarian(string key)
			{
				return addForLang("Hungarian", key);
			}

			public LocalizeKey Slovak(string key)
			{
				return addForLang("Slovak", key);
			}

			public LocalizeKey Polish(string key)
			{
				return addForLang("Polish", key);
			}

			public LocalizeKey Dutch(string key)
			{
				return addForLang("Dutch", key);
			}

			public LocalizeKey Portuguese_European(string key)
			{
				return addForLang("Portuguese_European", key);
			}

			public LocalizeKey Portuguese_Brazilian(string key)
			{
				return addForLang("Portuguese_Brazilian", key);
			}

			public LocalizeKey Chinese(string key)
			{
				return addForLang("Chinese", key);
			}

			public LocalizeKey Japanese(string key)
			{
				return addForLang("Japanese", key);
			}

			public LocalizeKey Korean(string key)
			{
				return addForLang("Korean", key);
			}

			public LocalizeKey Hindi(string key)
			{
				return addForLang("Hindi", key);
			}

			public LocalizeKey Thai(string key)
			{
				return addForLang("Thai", key);
			}

			public LocalizeKey Abenaki(string key)
			{
				return addForLang("Abenaki", key);
			}

			public LocalizeKey Croatian(string key)
			{
				return addForLang("Croatian", key);
			}

			public LocalizeKey Georgian(string key)
			{
				return addForLang("Georgian", key);
			}

			public LocalizeKey Greek(string key)
			{
				return addForLang("Greek", key);
			}

			public LocalizeKey Serbian(string key)
			{
				return addForLang("Serbian", key);
			}

			public LocalizeKey Ukrainian(string key)
			{
				return addForLang("Ukrainian", key);
			}

			private LocalizeKey addForLang(string lang, string value)
			{
				Localizations[lang] = value;
				if (Localization.instance.GetSelectedLanguage() == lang)
				{
					Localization.instance.AddWord(Key, value);
				}
				else if (lang == "English" && !Localization.instance.m_translations.ContainsKey(Key))
				{
					Localization.instance.AddWord(Key, value);
				}
				return this;
			}

			[HarmonyPriority(300)]
			internal static void AddLocalizedKeys(Localization __instance, string language)
			{
				foreach (LocalizeKey key in keys)
				{
					string value2;
					if (key.Localizations.TryGetValue(language, out var value) || key.Localizations.TryGetValue("English", out value))
					{
						__instance.AddWord(key.Key, value);
					}
					else if (key.Localizations.TryGetValue("alias", out value2))
					{
						__instance.AddWord(key.Key, Localization.instance.Localize(value2));
					}
				}
			}
		}

		[<4cd033a6-260d-4d69-97cc-f94c181d531a>NullableContext(0)]
		private class ConfigurationManagerAttributes
		{
			[<1725a767-56f4-45e7-970f-3089dc995b62>Nullable(2)]
			[UsedImplicitly]
			public string Category;
		}

		[<4cd033a6-260d-4d69-97cc-f94c181d531a>NullableContext(0)]
		[HarmonyPatch(typeof(Skills), "IsSkillValid")]
		private static class Patch_Skills_IsSkillValid
		{
			private static void Postfix(SkillType type, ref bool __result)
			{
				//IL_000a: Unknown result type (might be due to invalid IL or missing references)
				if (!__result && skills.ContainsKey(type))
				{
					__result = true;
				}
			}
		}

		private static readonly Dictionary<SkillType, Skill> skills;

		internal static readonly Dictionary<string, Skill> skillByName;

		private readonly string skillName;

		private readonly string internalSkillName;

		private readonly SkillDef skillDef;

		public readonly LocalizeKey Name;

		public readonly LocalizeKey Description;

		private float skillEffectFactor = 1f;

		private int skillLoss = 5;

		public bool Configurable;

		private static bool InitializedTerminal;

		[<1725a767-56f4-45e7-970f-3089dc995b62>Nullable(2)]
		private static Localization _english;

		[<1725a767-56f4-45e7-970f-3089dc995b62>Nullable(2)]
		private static BaseUnityPlugin _plugin;

		private static bool hasConfigSync;

		[<1725a767-56f4-45e7-970f-3089dc995b62>Nullable(2)]
		private static object _configSync;

		public float SkillGainFactor
		{
			get
			{
				return skillDef.m_increseStep;
			}
			set
			{
				skillDef.m_increseStep = value;
				this.SkillGainFactorChanged?.Invoke(value);
			}
		}

		public float SkillEffectFactor
		{
			get
			{
				return skillEffectFactor;
			}
			set
			{
				skillEffectFactor = value;
				this.SkillEffectFactorChanged?.Invoke(value);
			}
		}

		public int SkillLoss
		{
			get
			{
				return skillLoss;
			}
			set
			{
				skillLoss = value;
				this.SkillLossChanged?.Invoke(value);
			}
		}

		private static Localization english => _english ?? (_english = LocalizationCache.ForLanguage("English"));

		private static BaseUnityPlugin plugin
		{
			get
			{
				//IL_0041: Unknown result type (might be due to invalid IL or missing references)
				//IL_0046: Unknown result type (might be due to invalid IL or missing references)
				//IL_004c: Expected O, but got Unknown
				object obj = _plugin;
				if (obj == null)
				{
					BaseUnityPlugin val = (BaseUnityPlugin)Chainloader.ManagerObject.GetComponent((Type)Assembly.GetExecutingAssembly().DefinedTypes.First([<4cd033a6-260d-4d69-97cc-f94c181d531a>NullableContext(0)] (TypeInfo t) => t.IsClass && typeof(BaseUnityPlugin).IsAssignableFrom(t)));
					_plugin = val;
					obj = (object)val;
				}
				return (BaseUnityPlugin)obj;
			}
		}

		[<1725a767-56f4-45e7-970f-3089dc995b62>Nullable(2)]
		private static object configSync
		{
			[<4cd033a6-260d-4d69-97cc-f94c181d531a>NullableContext(2)]
			get
			{
				if (_configSync == null && hasConfigSync)
				{
					Type type = Assembly.GetExecutingAssembly().GetType("ServerSync.ConfigSync");
					if ((object)type != null)
					{
						_configSync = Activator.CreateInstance(type, plugin.Info.Metadata.GUID + " SkillManager");
						type.GetField("CurrentVersion").SetValue(_configSync, plugin.Info.Metadata.Version.ToString());
						type.GetProperty("IsLocked").SetValue(_configSync, true);
					}
					else
					{
						hasConfigSync = false;
					}
				}
				return _configSync;
			}
		}

		[<1725a767-56f4-45e7-970f-3089dc995b62>Nullable(2)]
		[method: <4cd033a6-260d-4d69-97cc-f94c181d531a>NullableContext(2)]
		[field: <1725a767-56f4-45e7-970f-3089dc995b62>Nullable(2)]
		public event Action<float> SkillGainFactorChanged;

		[<1725a767-56f4-45e7-970f-3089dc995b62>Nullable(2)]
		[method: <4cd033a6-260d-4d69-97cc-f94c181d531a>NullableContext(2)]
		[field: <1725a767-56f4-45e7-970f-3089dc995b62>Nullable(2)]
		public event Action<float> SkillEffectFactorChanged;

		[<1725a767-56f4-45e7-970f-3089dc995b62>Nullable(2)]
		[method: <4cd033a6-260d-4d69-97cc-f94c181d531a>NullableContext(2)]
		[field: <1725a767-56f4-45e7-970f-3089dc995b62>Nullable(2)]
		public event Action<float> SkillLossChanged;

		public Skill(string englishName, string icon)
			: this(englishName, loadSprite(icon, 64, 64))
		{
		}

		public Skill(string englishName, Sprite icon)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: 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_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Expected O, but got Unknown
			SkillType val = fromName(englishName);
			string text = new Regex("[^a-zA-Z]").Replace(englishName, "_");
			skills[val] = this;
			skillByName[englishName] = this;
			skillDef = new SkillDef
			{
				m_description = "$skilldesc_" + text,
				m_icon = icon,
				m_increseStep = 1f,
				m_skill = val
			};
			internalSkillName = text;
			skillName = englishName;
			Name = new LocalizeKey("skill_" + ((object)(SkillType)(ref val)).ToString()).English(englishName);
			Description = new LocalizeKey("skilldesc_" + text);
		}

		public static SkillType fromName(string englishName)
		{
			return (SkillType)Math.Abs(StringExtensionMethods.GetStableHashCode(englishName));
		}

		static Skill()
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: 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_0065: Expected O, but got Unknown
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Expected O, but got Unknown
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Expected O, but got Unknown
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Expected O, but got Unknown
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_0155: Expected O, but got Unknown
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			//IL_0183: Unknown result type (might be due to invalid IL or missing references)
			//IL_019e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ab: Expected O, but got Unknown
			//IL_01ab: Expected O, but got Unknown
			//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_01da: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e7: Expected O, but got Unknown
			//IL_0214: Unknown result type (might be due to invalid IL or missing references)
			//IL_0231: Unknown result type (might be due to invalid IL or missing references)
			//IL_023c: Expected O, but got Unknown
			//IL_023c: Expected O, but got Unknown
			skills = new Dictionary<SkillType, Skill>();
			skillByName = new Dictionary<string, Skill>();
			InitializedTerminal = false;
			hasConfigSync = true;
			Harmony val = new Harmony("org.bepinex.helpers.skillmanager");
			val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(FejdStartup), "Awake", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(Skill), "Patch_FejdStartup", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(Skills), "GetSkillDef", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(Skill), "Patch_Skills_GetSkillDef", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(Skills), "CheatRaiseSkill", (Type[])null, (Type[])null), new HarmonyMethod(AccessTools.DeclaredMethod(typeof(Skill), "Patch_Skills_CheatRaiseskill", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(Skills), "CheatResetSkill", (Type[])null, (Type[])null), new HarmonyMethod(AccessTools.DeclaredMethod(typeof(Skill), "Patch_Skills_CheatResetSkill", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(Localization), "LoadCSV", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(LocalizeKey), "AddLocalizedKeys", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(Terminal), "InitTerminal", (Type[])null, (Type[])null), new HarmonyMethod(AccessTools.DeclaredMethod(typeof(Skill), "Patch_Terminal_InitTerminal_Prefix", (Type[])null, (Type[])null)), new HarmonyMethod(AccessTools.DeclaredMethod(typeof(Skill), "Patch_Terminal_InitTerminal", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(Localization), "SetupLanguage", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(LocalizationCache), "LocalizationPostfix", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(Skills), "OnDeath", (Type[])null, (Type[])null), new HarmonyMethod(AccessTools.DeclaredMethod(typeof(Skill), "Patch_Skills_OnDeath_Prefix", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(Skill), "Patch_Skills_OnDeath_Finalizer", (Type[])null, (Type[])null)), (HarmonyMethod)null);
		}

		private static void Patch_FejdStartup()
		{
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Expected O, but got Unknown
			//IL_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: Expected O, but got Unknown
			//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01af: Expected O, but got Unknown
			foreach (Skill skill in skills.Values)
			{
				if (skill.Configurable)
				{
					string key = skill.Name.Key;
					string group = new Regex("['[\"\\]]").Replace(english.Localize(key), "").Trim();
					string category = Localization.instance.Localize(key).Trim();
					ConfigEntry<float> skillGain = config(group, "Skill gain factor", skill.SkillGainFactor, new ConfigDescription("The rate at which you gain experience for the skill.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.01f, 5f), new object[1]
					{
						new ConfigurationManagerAttributes
						{
							Category = category
						}
					}));
					skill.SkillGainFactor = skillGain.Value;
					skillGain.SettingChanged += [<4cd033a6-260d-4d69-97cc-f94c181d531a>NullableContext(0)] (object _, EventArgs _) =>
					{
						skill.SkillGainFactor = skillGain.Value;
					};
					ConfigEntry<float> skillEffect = config(group, "Skill effect factor", skill.SkillEffectFactor, new ConfigDescription("The power of the skill, based on the default power.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.01f, 5f), new object[1]
					{
						new ConfigurationManagerAttributes
						{
							Category = category
						}
					}));
					skill.SkillEffectFactor = skillEffect.Value;
					skillEffect.SettingChanged += [<4cd033a6-260d-4d69-97cc-f94c181d531a>NullableContext(0)] (object _, EventArgs _) =>
					{
						skill.SkillEffectFactor = skillEffect.Value;
					};
					ConfigEntry<int> skillLoss = config(group, "Skill loss", skill.skillLoss, new ConfigDescription("How much experience to lose on death.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), new object[1]
					{
						new ConfigurationManagerAttributes
						{
							Category = category
						}
					}));
					skill.skillLoss = skillLoss.Value;
					skillLoss.SettingChanged += [<4cd033a6-260d-4d69-97cc-f94c181d531a>NullableContext(0)] (object _, EventArgs _) =>
					{
						skill.skillLoss = skillLoss.Value;
					};
				}
			}
		}

		private static void Patch_Skills_GetSkillDef([<1725a767-56f4-45e7-970f-3089dc995b62>Nullable(2)] ref SkillDef __result, List<SkillDef> ___m_skills, SkillType type)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			if (__result == null)
			{
				SkillDef val = GetSkillDef(type);
				if (val != null)
				{
					___m_skills.Add(val);
					__result = val;
				}
			}
		}

		private static bool Patch_Skills_CheatRaiseskill(Skills __instance, string name, float value, Player ___m_player)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			foreach (SkillType key in skills.Keys)
			{
				SkillType current = key;
				Skill skill = skills[current];
				if (string.Equals(skill.internalSkillName, name, StringComparison.CurrentCultureIgnoreCase))
				{
					Skill skill2 = __instance.GetSkill(current);
					skill2.m_level += value;
					skill2.m_level = Mathf.Clamp(skill2.m_level, 0f, 100f);
					((Character)___m_player).Message((MessageType)1, "Skill increased " + Localization.instance.Localize("$skill_" + ((object)(SkillType)(ref current)).ToString()) + ": " + (int)skill2.m_level, 0, skill2.m_info.m_icon);
					Console.instance.Print("Skill " + skill.internalSkillName + " = " + skill2.m_level);
					return false;
				}
			}
			return true;
		}

		private static bool Patch_Skills_CheatResetSkill(Skills __instance, string name)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: 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_0036: Unknown result type (might be due to invalid IL or missing references)
			foreach (SkillType key in skills.Keys)
			{
				Skill skill = skills[key];
				if (string.Equals(skill.internalSkillName, name, StringComparison.CurrentCultureIgnoreCase))
				{
					__instance.ResetSkill(key);
					Console.instance.Print("Skill " + skill.internalSkillName + " reset");
					return false;
				}
			}
			return true;
		}

		private static void Patch_Skills_OnDeath_Prefix(Skills __instance, [<1725a767-56f4-45e7-970f-3089dc995b62>Nullable(new byte[] { 2, 1 })] ref Dictionary<SkillType, Skill> __state)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			if (__state == null)
			{
				__state = new Dictionary<SkillType, Skill>();
			}
			foreach (KeyValuePair<SkillType, Skill> skill in skills)
			{
				if (__instance.m_skillData.TryGetValue(skill.Key, out var value))
				{
					__state[skill.Key] = value;
					if (skill.Value.skillLoss > 0)
					{
						Skill obj = value;
						obj.m_level -= value.m_level * (float)skill.Value.SkillLoss / 100f;
						value.m_accumulator = 0f;
					}
					__instance.m_skillData.Remove(skill.Key);
				}
			}
		}

		private static void Patch_Skills_OnDeath_Finalizer(Skills __instance, [<1725a767-56f4-45e7-970f-3089dc995b62>Nullable(new byte[] { 2, 1 })] ref Dictionary<SkillType, Skill> __state)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			if (__state == null)
			{
				return;
			}
			foreach (KeyValuePair<SkillType, Skill> item in __state)
			{
				__instance.m_skillData[item.Key] = item.Value;
			}
			__state = null;
		}

		private static void Patch_Terminal_InitTerminal_Prefix()
		{
			InitializedTerminal = Terminal.m_terminalInitialized;
		}

		private static void Patch_Terminal_InitTerminal()
		{
			if (!InitializedTerminal)
			{
				AddSkill(Terminal.commands["raiseskill"]);
				AddSkill(Terminal.commands["resetskill"]);
			}
			static void AddSkill(ConsoleCommand command)
			{
				//IL_001a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0024: Expected O, but got Unknown
				ConsoleOptionsFetcher fetcher = command.m_tabOptionsFetcher;
				command.m_tabOptionsFetcher = (ConsoleOptionsFetcher)([<4cd033a6-260d-4d69-97cc-f94c181d531a>NullableContext(0)] () =>
				{
					List<string> list = fetcher.Invoke();
					list.AddRange(skills.Values.Select([<4cd033a6-260d-4d69-97cc-f94c181d531a>NullableContext(0)] (Skill skill) => skill.internalSkillName));
					return list;
				});
			}
		}

		[<4cd033a6-260d-4d69-97cc-f94c181d531a>NullableContext(2)]
		private static SkillDef GetSkillDef(SkillType skillType)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			if (!skills.ContainsKey(skillType))
			{
				return null;
			}
			return skills[skillType].skillDef;
		}

		private static byte[] ReadEmbeddedFileBytes(string name)
		{
			using MemoryStream memoryStream = new MemoryStream();
			Assembly.GetExecutingAssembly().GetManifestResourceStream(Assembly.GetExecutingAssembly().GetName().Name + "." + name).CopyTo(memoryStream);
			return memoryStream.ToArray();
		}

		private static Texture2D loadTexture(string name)
		{
			//IL_0002: 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_001d: Expected O, but got Unknown
			//IL_001f: Expected O, but got Unknown
			Texture2D val = new Texture2D(0, 0);
			ImageConversion.LoadImage(val, ReadEmbeddedFileBytes("icons." + name));
			return val;
		}

		private static Sprite loadSprite(string name, int width, int height)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			return Sprite.Create(loadTexture(name), new Rect(0f, 0f, (float)width, (float)height), Vector2.zero);
		}

		private static ConfigEntry<T> config<[<1725a767-56f4-45e7-970f-3089dc995b62>Nullable(2)] T>(string group, string name, T value, ConfigDescription description)
		{
			ConfigEntry<T> val = plugin.Config.Bind<T>(group, name, value, description);
			configSync?.GetType().GetMethod("AddConfigEntry").MakeGenericMethod(typeof(T))
				.Invoke(configSync, new object[1] { val });
			return val;
		}

		private static ConfigEntry<T> config<[<1725a767-56f4-45e7-970f-3089dc995b62>Nullable(2)] T>(string group, string name, T value, string description)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Expected O, but got Unknown
			return config(group, name, value, new ConfigDescription(description, (AcceptableValueBase)null, Array.Empty<object>()));
		}
	}
	[<4cd033a6-260d-4d69-97cc-f94c181d531a>NullableContext(1)]
	[<1725a767-56f4-45e7-970f-3089dc995b62>Nullable(0)]
	[PublicAPI]
	internal static class SkillExtensions
	{
		public static float GetSkillFactor(this Character character, string name)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			return character.GetSkillFactor(Skill.fromName(name)) * Skill.skillByName[name].SkillEffectFactor;
		}

		public static float GetSkillFactor(this Skills skills, string name)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			return skills.GetSkillFactor(Skill.fromName(name)) * Skill.skillByName[name].SkillEffectFactor;
		}

		public static void RaiseSkill(this Character character, string name, float value = 1f)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			character.RaiseSkill(Skill.fromName(name), value);
		}

		public static void RaiseSkill(this Skills skill, string name, float value = 1f)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			skill.RaiseSkill(Skill.fromName(name), value);
		}

		public static void LowerSkill(this Character character, string name, float factor = 1f)
		{
			character.GetSkills().LowerSkill(name, factor);
		}

		public static void LowerSkill(this Skills skills, string name, float factor)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			if (factor > 0f && skills.m_skillData.TryGetValue(Skill.fromName(name), out var value))
			{
				Skill obj = value;
				obj.m_level -= value.m_level * factor;
				value.m_accumulator = 0f;
			}
		}
	}
}
namespace Microsoft.CodeAnalysis
{
	[Microsoft.CodeAnalysis.Embedded]
	[CompilerGenerated]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[Microsoft.CodeAnalysis.Embedded]
	[CompilerGenerated]
	[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;
		}
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	[Microsoft.CodeAnalysis.Embedded]
	[CompilerGenerated]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

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

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace ServerSync
{
	[PublicAPI]
	internal abstract class OwnConfigEntryBase
	{
		public object? LocalBaseValue;

		public bool SynchronizedConfig = true;

		public abstract ConfigEntryBase BaseConfig { get; }
	}
	[PublicAPI]
	internal class SyncedConfigEntry<T> : OwnConfigEntryBase
	{
		public readonly ConfigEntry<T> SourceConfig;

		public override ConfigEntryBase BaseConfig => (ConfigEntryBase)(object)SourceConfig;

		public T Value
		{
			get
			{
				return SourceConfig.Value;
			}
			set
			{
				SourceConfig.Value = value;
			}
		}

		public SyncedConfigEntry(ConfigEntry<T> sourceConfig)
		{
			SourceConfig = sourceConfig;
			base..ctor();
		}

		public void AssignLocalValue(T value)
		{
			if (LocalBaseValue == null)
			{
				Value = value;
			}
			else
			{
				LocalBaseValue = value;
			}
		}
	}
	internal abstract class CustomSyncedValueBase
	{
		public object? LocalBaseValue;

		public readonly string Identifier;

		public readonly Type Type;

		private object? boxedValue;

		protected bool localIsOwner;

		public readonly int Priority;

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

		public event Action? ValueChanged;

		protected CustomSyncedValueBase(ConfigSync configSync, string identifier, Type type, int priority)
		{
			Priority = priority;
			Identifier = identifier;
			Type = type;
			configSync.AddCustomValue(this);
			localIsOwner = configSync.IsSourceOfTruth;
			configSync.SourceOfTruthChanged += delegate(bool truth)
			{
				localIsOwner = truth;
			};
		}
	}
	[PublicAPI]
	internal sealed class CustomSyncedValue<T> : CustomSyncedValueBase
	{
		public T Value
		{
			get
			{
				return (T)base.BoxedValue;
			}
			set
			{
				base.BoxedValue = value;
			}
		}

		public CustomSyncedValue(ConfigSync configSync, string identifier, T value = default(T), int priority = 0)
			: base(configSync, identifier, typeof(T), priority)
		{
			Value = value;
		}

		public void AssignLocalValue(T value)
		{
			if (localIsOwner)
			{
				Value = value;
			}
			else
			{
				LocalBaseValue = value;
			}
		}
	}
	internal class ConfigurationManagerAttributes
	{
		[UsedImplicitly]
		public bool? ReadOnly = false;
	}
	[PublicAPI]
	internal class ConfigSync
	{
		[HarmonyPatch(typeof(ZRpc), "HandlePackage")]
		private static class SnatchCurrentlyHandlingRPC
		{
			public static ZRpc? currentRpc;

			[HarmonyPrefix]
			private static void Prefix(ZRpc __instance)
			{
				currentRpc = __instance;
			}
		}

		[HarmonyPatch(typeof(ZNet), "Awake")]
		internal static class RegisterRPCPatch
		{
			[HarmonyPostfix]
			private static void Postfix(ZNet __instance)
			{
				isServer = __instance.IsServer();
				foreach (ConfigSync configSync2 in configSyncs)
				{
					ZRoutedRpc.instance.Register<ZPackage>(configSync2.Name + " ConfigSync", (Action<long, ZPackage>)configSync2.RPC_FromOtherClientConfigSync);
					if (isServer)
					{
						configSync2.InitialSyncDone = true;
						Debug.Log((object)("Registered '" + configSync2.Name + " ConfigSync' RPC - waiting for incoming connections"));
					}
				}
				if (isServer)
				{
					((MonoBehaviour)__instance).StartCoroutine(WatchAdminListChanges());
				}
				static void SendAdmin(List<ZNetPeer> peers, bool isAdmin)
				{
					ZPackage package = ConfigsToPackage(null, null, new PackageEntry[1]
					{
						new PackageEntry
						{
							section = "Internal",
							key = "lockexempt",
							type = typeof(bool),
							value = isAdmin
						}
					});
					ConfigSync configSync = configSyncs.First();
					if (configSync != null)
					{
						((MonoBehaviour)ZNet.instance).StartCoroutine(configSync.sendZPackage(peers, package));
					}
				}
				static IEnumerator WatchAdminListChanges()
				{
					MethodInfo listContainsId = AccessTools.DeclaredMethod(typeof(ZNet), "ListContainsId", (Type[])null, (Type[])null);
					SyncedList adminList = (SyncedList)AccessTools.DeclaredField(typeof(ZNet), "m_adminList").GetValue(ZNet.instance);
					List<string> CurrentList = new List<string>(adminList.GetList());
					while (true)
					{
						yield return (object)new WaitForSeconds(30f);
						if (!adminList.GetList().SequenceEqual(CurrentList))
						{
							CurrentList = new List<string>(adminList.GetList());
							List<ZNetPeer> adminPeer = ZNet.instance.GetPeers().Where(delegate(ZNetPeer p)
							{
								string hostName = p.m_rpc.GetSocket().GetHostName();
								return ((object)listContainsId == null) ? adminList.Contains(hostName) : ((bool)listContainsId.Invoke(ZNet.instance, new object[2] { adminList, hostName }));
							}).ToList();
							List<ZNetPeer> nonAdminPeer = ZNet.instance.GetPeers().Except(adminPeer).ToList();
							SendAdmin(nonAdminPeer, isAdmin: false);
							SendAdmin(adminPeer, isAdmin: true);
						}
					}
				}
			}
		}

		[HarmonyPatch(typeof(ZNet), "OnNewConnection")]
		private static class RegisterClientRPCPatch
		{
			[HarmonyPostfix]
			private static void Postfix(ZNet __instance, ZNetPeer peer)
			{
				if (__instance.IsServer())
				{
					return;
				}
				foreach (ConfigSync configSync in configSyncs)
				{
					peer.m_rpc.Register<ZPackage>(configSync.Name + " ConfigSync", (Action<ZRpc, ZPackage>)configSync.RPC_FromServerConfigSync);
				}
			}
		}

		private class ParsedConfigs
		{
			public readonly Dictionary<OwnConfigEntryBase, object?> configValues = new Dictionary<OwnConfigEntryBase, object>();

			public readonly Dictionary<CustomSyncedValueBase, object?> customValues = new Dictionary<CustomSyncedValueBase, object>();
		}

		[HarmonyPatch(typeof(ZNet), "Shutdown")]
		private class ResetConfigsOnShutdown
		{
			[HarmonyPostfix]
			private static void Postfix()
			{
				ProcessingServerUpdate = true;
				foreach (ConfigSync configSync in configSyncs)
				{
					configSync.resetConfigsFromServer();
					configSync.IsSourceOfTruth = true;
					configSync.InitialSyncDone = false;
				}
				ProcessingServerUpdate = false;
			}
		}

		[HarmonyPatch(typeof(ZNet), "RPC_PeerInfo")]
		private class SendConfigsAfterLogin
		{
			private class BufferingSocket : ZPlayFabSocket, ISocket
			{
				public volatile bool finished = false;

				public volatile int versionMatchQueued = -1;

				public readonly List<ZPackage> Package = new List<ZPackage>();

				public readonly ISocket Original;

				public BufferingSocket(ISocket original)
				{
					Original = original;
					((ZPlayFabSocket)this)..ctor();
				}

				public bool IsConnected()
				{
					return Original.IsConnected();
				}

				public ZPackage Recv()
				{
					return Original.Recv();
				}

				public int GetSendQueueSize()
				{
					return Original.GetSendQueueSize();
				}

				public int GetCurrentSendRate()
				{
					return Original.GetCurrentSendRate();
				}

				public bool IsHost()
				{
					return Original.IsHost();
				}

				public void Dispose()
				{
					Original.Dispose();
				}

				public bool GotNewData()
				{
					return Original.GotNewData();
				}

				public void Close()
				{
					Original.Close();
				}

				public string GetEndPointString()
				{
					return Original.GetEndPointString();
				}

				public void GetAndResetStats(out int totalSent, out int totalRecv)
				{
					Original.GetAndResetStats(ref totalSent, ref totalRecv);
				}

				public void GetConnectionQuality(out float localQuality, out float remoteQuality, out int ping, out float outByteSec, out float inByteSec)
				{
					Original.GetConnectionQuality(ref localQuality, ref remoteQuality, ref ping, ref outByteSec, ref inByteSec);
				}

				public ISocket Accept()
				{
					return Original.Accept();
				}

				public int GetHostPort()
				{
					return Original.GetHostPort();
				}

				public bool Flush()
				{
					return Original.Flush();
				}

				public string GetHostName()
				{
					return Original.GetHostName();
				}

				public void VersionMatch()
				{
					if (finished)
					{
						Original.VersionMatch();
					}
					else
					{
						versionMatchQueued = Package.Count;
					}
				}

				public void Send(ZPackage pkg)
				{
					//IL_0057: Unknown result type (might be due to invalid IL or missing references)
					//IL_005d: Expected O, but got Unknown
					int pos = pkg.GetPos();
					pkg.SetPos(0);
					int num = pkg.ReadInt();
					if ((num == StringExtensionMethods.GetStableHashCode("PeerInfo") || num == StringExtensionMethods.GetStableHashCode("RoutedRPC") || num == StringExtensionMethods.GetStableHashCode("ZDOData")) && !finished)
					{
						ZPackage val = new ZPackage(pkg.GetArray());
						val.SetPos(pos);
						Package.Add(val);
					}
					else
					{
						pkg.SetPos(pos);
						Original.Send(pkg);
					}
				}
			}

			[HarmonyPrefix]
			[HarmonyPriority(800)]
			private static void Prefix(ref Dictionary<Assembly, BufferingSocket>? __state, ZNet __instance, ZRpc rpc)
			{
				//IL_0078: Unknown result type (might be due to invalid IL or missing references)
				//IL_007e: Invalid comparison between Unknown and I4
				if (!__instance.IsServer())
				{
					return;
				}
				BufferingSocket bufferingSocket = new BufferingSocket(rpc.GetSocket());
				AccessTools.DeclaredField(typeof(ZRpc), "m_socket").SetValue(rpc, bufferingSocket);
				object? obj = AccessTools.DeclaredMethod(typeof(ZNet), "GetPeer", new Type[1] { typeof(ZRpc) }, (Type[])null).Invoke(__instance, new object[1] { rpc });
				ZNetPeer val = (ZNetPeer)((obj is ZNetPeer) ? obj : null);
				if (val != null && (int)ZNet.m_onlineBackend > 0)
				{
					FieldInfo fieldInfo = AccessTools.DeclaredField(typeof(ZNetPeer), "m_socket");
					object? value = fieldInfo.GetValue(val);
					ZPlayFabSocket val2 = (ZPlayFabSocket)((value is ZPlayFabSocket) ? value : null);
					if (val2 != null)
					{
						typeof(ZPlayFabSocket).GetField("m_remotePlayerId").SetValue(bufferingSocket, val2.m_remotePlayerId);
					}
					fieldInfo.SetValue(val, bufferingSocket);
				}
				if (__state == null)
				{
					__state = new Dictionary<Assembly, BufferingSocket>();
				}
				__state[Assembly.GetExecutingAssembly()] = bufferingSocket;
			}

			[HarmonyPostfix]
			private static void Postfix(Dictionary<Assembly, BufferingSocket> __state, ZNet __instance, ZRpc rpc)
			{
				ZRpc rpc2 = rpc;
				ZNet __instance2 = __instance;
				Dictionary<Assembly, BufferingSocket> __state2 = __state;
				ZNetPeer peer;
				if (__instance2.IsServer())
				{
					object obj = AccessTools.DeclaredMethod(typeof(ZNet), "GetPeer", new Type[1] { typeof(ZRpc) }, (Type[])null).Invoke(__instance2, new object[1] { rpc2 });
					peer = (ZNetPeer)((obj is ZNetPeer) ? obj : null);
					if (peer == null)
					{
						SendBufferedData();
					}
					else
					{
						((MonoBehaviour)__instance2).StartCoroutine(sendAsync());
					}
				}
				void SendBufferedData()
				{
					if (rpc2.GetSocket() is BufferingSocket bufferingSocket)
					{
						AccessTools.DeclaredField(typeof(ZRpc), "m_socket").SetValue(rpc2, bufferingSocket.Original);
						object? obj2 = AccessTools.DeclaredMethod(typeof(ZNet), "GetPeer", new Type[1] { typeof(ZRpc) }, (Type[])null).Invoke(__instance2, new object[1] { rpc2 });
						ZNetPeer val = (ZNetPeer)((obj2 is ZNetPeer) ? obj2 : null);
						if (val != null)
						{
							AccessTools.DeclaredField(typeof(ZNetPeer), "m_socket").SetValue(val, bufferingSocket.Original);
						}
					}
					BufferingSocket bufferingSocket2 = __state2[Assembly.GetExecutingAssembly()];
					bufferingSocket2.finished = true;
					for (int i = 0; i < bufferingSocket2.Package.Count; i++)
					{
						if (i == bufferingSocket2.versionMatchQueued)
						{
							bufferingSocket2.Original.VersionMatch();
						}
						bufferingSocket2.Original.Send(bufferingSocket2.Package[i]);
					}
					if (bufferingSocket2.Package.Count == bufferingSocket2.versionMatchQueued)
					{
						bufferingSocket2.Original.VersionMatch();
					}
				}
				IEnumerator sendAsync()
				{
					foreach (ConfigSync configSync in configSyncs)
					{
						List<PackageEntry> entries = new List<PackageEntry>();
						if (configSync.CurrentVersion != null)
						{
							entries.Add(new PackageEntry
							{
								section = "Internal",
								key = "serverversion",
								type = typeof(string),
								value = configSync.CurrentVersion
							});
						}
						MethodInfo listContainsId = AccessTools.DeclaredMethod(typeof(ZNet), "ListContainsId", (Type[])null, (Type[])null);
						SyncedList adminList = (SyncedList)AccessTools.DeclaredField(typeof(ZNet), "m_adminList").GetValue(ZNet.instance);
						entries.Add(new PackageEntry
						{
							section = "Internal",
							key = "lockexempt",
							type = typeof(bool),
							value = (((object)listContainsId == null) ? ((object)adminList.Contains(rpc2.GetSocket().GetHostName())) : listContainsId.Invoke(ZNet.instance, new object[2]
							{
								adminList,
								rpc2.GetSocket().GetHostName()
							}))
						});
						ZPackage package = ConfigsToPackage(configSync.allConfigs.Select((OwnConfigEntryBase c) => c.BaseConfig), configSync.allCustomValues, entries, partial: false);
						yield return ((MonoBehaviour)__instance2).StartCoroutine(configSync.sendZPackage(new List<ZNetPeer> { peer }, package));
					}
					SendBufferedData();
				}
			}
		}

		private class PackageEntry
		{
			public string section = null;

			public string key = null;

			public Type type = null;

			public object? value;
		}

		[HarmonyPatch(typeof(ConfigEntryBase), "GetSerializedValue")]
		private static class PreventSavingServerInfo
		{
			[HarmonyPrefix]
			private static bool Prefix(ConfigEntryBase __instance, ref string __result)
			{
				OwnConfigEntryBase ownConfigEntryBase = configData(__instance);
				if (ownConfigEntryBase == null || isWritableConfig(ownConfigEntryBase))
				{
					return true;
				}
				__result = TomlTypeConverter.ConvertToString(ownConfigEntryBase.LocalBaseValue, __instance.SettingType);
				return false;
			}
		}

		[HarmonyPatch(typeof(ConfigEntryBase), "SetSerializedValue")]
		private static class PreventConfigRereadChangingValues
		{
			[HarmonyPrefix]
			private static bool Prefix(ConfigEntryBase __instance, string value)
			{
				OwnConfigEntryBase ownConfigEntryBase = configData(__instance);
				if (ownConfigEntryBase == null || ownConfigEntryBase.LocalBaseValue == null)
				{
					return true;
				}
				try
				{
					ownConfigEntryBase.LocalBaseValue = TomlTypeConverter.ConvertToValue(value, __instance.SettingType);
				}
				catch (Exception ex)
				{
					Debug.LogWarning((object)$"Config value of setting \"{__instance.Definition}\" could not be parsed and will be ignored. Reason: {ex.Message}; Value: {value}");
				}
				return false;
			}
		}

		private class InvalidDeserializationTypeException : Exception
		{
			public string expected = null;

			public string received = null;

			public string field = "";
		}

		public static bool ProcessingServerUpdate;

		public readonly string Name;

		public string? DisplayName;

		public string? CurrentVersion;

		public string? MinimumRequiredVersion;

		public bool ModRequired = false;

		private bool? forceConfigLocking;

		private bool isSourceOfTruth = true;

		private static readonly HashSet<ConfigSync> configSyncs;

		private readonly HashSet<OwnConfigEntryBase> allConfigs = new HashSet<OwnConfigEntryBase>();

		private HashSet<CustomSyncedValueBase> allCustomValues = new HashSet<CustomSyncedValueBase>();

		private static bool isServer;

		private static bool lockExempt;

		private OwnConfigEntryBase? lockedConfig = null;

		private const byte PARTIAL_CONFIGS = 1;

		private const byte FRAGMENTED_CONFIG = 2;

		private const byte COMPRESSED_CONFIG = 4;

		private readonly Dictionary<string, SortedDictionary<int, byte[]>> configValueCache = new Dictionary<string, SortedDictionary<int, byte[]>>();

		private readonly List<KeyValuePair<long, string>> cacheExpirations = new List<KeyValuePair<long, string>>();

		private static long packageCounter;

		public bool IsLocked
		{
			get
			{
				bool? flag = forceConfigLocking;
				bool num;
				if (!flag.HasValue)
				{
					if (lockedConfig == null)
					{
						goto IL_0052;
					}
					num = ((IConvertible)lockedConfig.BaseConfig.BoxedValue).ToInt32(CultureInfo.InvariantCulture) != 0;
				}
				else
				{
					num = flag.GetValueOrDefault();
				}
				if (!num)
				{
					goto IL_0052;
				}
				int result = ((!lockExempt) ? 1 : 0);
				goto IL_0053;
				IL_0053:
				return (byte)result != 0;
				IL_0052:
				result = 0;
				goto IL_0053;
			}
			set
			{
				forceConfigLocking = value;
			}
		}

		public bool IsAdmin => lockExempt || isSourceOfTruth;

		public bool IsSourceOfTruth
		{
			get
			{
				return isSourceOfTruth;
			}
			private set
			{
				if (value != isSourceOfTruth)
				{
					isSourceOfTruth = value;
					this.SourceOfTruthChanged?.Invoke(value);
				}
			}
		}

		public bool InitialSyncDone { get; private set; } = false;


		public event Action<bool>? SourceOfTruthChanged;

		private event Action? lockedConfigChanged;

		static ConfigSync()
		{
			ProcessingServerUpdate = false;
			configSyncs = new HashSet<ConfigSync>();
			lockExempt = false;
			packageCounter = 0L;
			RuntimeHelpers.RunClassConstructor(typeof(VersionCheck).TypeHandle);
		}

		public ConfigSync(string name)
		{
			Name = name;
			configSyncs.Add(this);
			new VersionCheck(this);
		}

		public SyncedConfigEntry<T> AddConfigEntry<T>(ConfigEntry<T> configEntry)
		{
			ConfigEntry<T> configEntry2 = configEntry;
			OwnConfigEntryBase ownConfigEntryBase = configData((ConfigEntryBase)(object)configEntry2);
			SyncedConfigEntry<T> syncedEntry = ownConfigEntryBase as SyncedConfigEntry<T>;
			if (syncedEntry == null)
			{
				syncedEntry = new SyncedConfigEntry<T>(configEntry2);
				AccessTools.DeclaredField(typeof(ConfigDescription), "<Tags>k__BackingField").SetValue(((ConfigEntryBase)configEntry2).Description, new object[1]
				{
					new ConfigurationManagerAttributes()
				}.Concat(((ConfigEntryBase)configEntry2).Description.Tags ?? Array.Empty<object>()).Concat(new SyncedConfigEntry<T>[1] { syncedEntry }).ToArray());
				configEntry2.SettingChanged += delegate
				{
					if (!ProcessingServerUpdate && syncedEntry.SynchronizedConfig)
					{
						Broadcast(ZRoutedRpc.Everybody, (ConfigEntryBase)configEntry2);
					}
				};
				allConfigs.Add(syncedEntry);
			}
			return syncedEntry;
		}

		public SyncedConfigEntry<T> AddLockingConfigEntry<T>(ConfigEntry<T> lockingConfig) where T : IConvertible
		{
			if (lockedConfig != null)
			{
				throw new Exception("Cannot initialize locking ConfigEntry twice");
			}
			lockedConfig = AddConfigEntry<T>(lockingConfig);
			lockingConfig.SettingChanged += delegate
			{
				this.lockedConfigChanged?.Invoke();
			};
			return (SyncedConfigEntry<T>)lockedConfig;
		}

		internal void AddCustomValue(CustomSyncedValueBase customValue)
		{
			CustomSyncedValueBase customValue2 = customValue;
			if (allCustomValues.Select((CustomSyncedValueBase v) => v.Identifier).Concat(new string[1] { "serverversion" }).Contains(customValue2.Identifier))
			{
				throw new Exception("Cannot have multiple settings with the same name or with a reserved name (serverversion)");
			}
			allCustomValues.Add(customValue2);
			allCustomValues = new HashSet<CustomSyncedValueBase>(allCustomValues.OrderByDescending((CustomSyncedValueBase v) => v.Priority));
			customValue2.ValueChanged += delegate
			{
				if (!ProcessingServerUpdate)
				{
					Broadcast(ZRoutedRpc.Everybody, customValue2);
				}
			};
		}

		private void RPC_FromServerConfigSync(ZRpc rpc, ZPackage package)
		{
			lockedConfigChanged += serverLockedSettingChanged;
			IsSourceOfTruth = false;
			if (HandleConfigSyncRPC(0L, package, clientUpdate: false))
			{
				InitialSyncDone = true;
			}
		}

		private void RPC_FromOtherClientConfigSync(long sender, ZPackage package)
		{
			HandleConfigSyncRPC(sender, package, clientUpdate: true);
		}

		private bool HandleConfigSyncRPC(long sender, ZPackage package, bool clientUpdate)
		{
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Expected O, but got Unknown
			//IL_0250: Unknown result type (might be due to invalid IL or missing references)
			//IL_0257: Expected O, but got Unknown
			//IL_01ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f1: Expected O, but got Unknown
			try
			{
				if (isServer && IsLocked)
				{
					ZRpc? currentRpc = SnatchCurrentlyHandlingRPC.currentRpc;
					object obj;
					if (currentRpc == null)
					{
						obj = null;
					}
					else
					{
						ISocket socket = currentRpc.GetSocket();
						obj = ((socket != null) ? socket.GetHostName() : null);
					}
					string text = (string)obj;
					if (text != null)
					{
						MethodInfo methodInfo = AccessTools.DeclaredMethod(typeof(ZNet), "ListContainsId", (Type[])null, (Type[])null);
						SyncedList val = (SyncedList)AccessTools.DeclaredField(typeof(ZNet), "m_adminList").GetValue(ZNet.instance);
						if (!(((object)methodInfo == null) ? val.Contains(text) : ((bool)methodInfo.Invoke(ZNet.instance, new object[2] { val, text }))))
						{
							return false;
						}
					}
				}
				cacheExpirations.RemoveAll(delegate(KeyValuePair<long, string> kv)
				{
					if (kv.Key < DateTimeOffset.Now.Ticks)
					{
						configValueCache.Remove(kv.Value);
						return true;
					}
					return false;
				});
				byte b = package.ReadByte();
				if ((b & 2u) != 0)
				{
					long num = package.ReadLong();
					string text2 = sender.ToString() + num;
					if (!configValueCache.TryGetValue(text2, out SortedDictionary<int, byte[]> value))
					{
						value = new SortedDictionary<int, byte[]>();
						configValueCache[text2] = value;
						cacheExpirations.Add(new KeyValuePair<long, string>(DateTimeOffset.Now.AddSeconds(60.0).Ticks, text2));
					}
					int key = package.ReadInt();
					int num2 = package.ReadInt();
					value.Add(key, package.ReadByteArray());
					if (value.Count < num2)
					{
						return false;
					}
					configValueCache.Remove(text2);
					package = new ZPackage(value.Values.SelectMany((byte[] a) => a).ToArray());
					b = package.ReadByte();
				}
				ProcessingServerUpdate = true;
				if ((b & 4u) != 0)
				{
					byte[] buffer = package.ReadByteArray();
					MemoryStream stream = new MemoryStream(buffer);
					MemoryStream memoryStream = new MemoryStream();
					using (DeflateStream deflateStream = new DeflateStream(stream, CompressionMode.Decompress))
					{
						deflateStream.CopyTo(memoryStream);
					}
					package = new ZPackage(memoryStream.ToArray());
					b = package.ReadByte();
				}
				if ((b & 1) == 0)
				{
					resetConfigsFromServer();
				}
				ParsedConfigs parsedConfigs = ReadConfigsFromPackage(package);
				ConfigFile val2 = null;
				bool saveOnConfigSet = false;
				foreach (KeyValuePair<OwnConfigEntryBase, object> configValue in parsedConfigs.configValues)
				{
					if (!isServer && configValue.Key.LocalBaseValue == null)
					{
						configValue.Key.LocalBaseValue = configValue.Key.BaseConfig.BoxedValue;
					}
					if (val2 == null)
					{
						val2 = configValue.Key.BaseConfig.ConfigFile;
						saveOnConfigSet = val2.SaveOnConfigSet;
						val2.SaveOnConfigSet = false;
					}
					configValue.Key.BaseConfig.BoxedValue = configValue.Value;
				}
				if (val2 != null)
				{
					val2.SaveOnConfigSet = saveOnConfigSet;
					val2.Save();
				}
				foreach (KeyValuePair<CustomSyncedValueBase, object> customValue in parsedConfigs.customValues)
				{
					if (!isServer)
					{
						CustomSyncedValueBase key2 = customValue.Key;
						if (key2.LocalBaseValue == null)
						{
							key2.LocalBaseValue = customValue.Key.BoxedValue;
						}
					}
					customValue.Key.BoxedValue = customValue.Value;
				}
				Debug.Log((object)string.Format("Received {0} configs and {1} custom values from {2} for mod {3}", parsedConfigs.configValues.Count, parsedConfigs.customValues.Count, (isServer || clientUpdate) ? $"client {sender}" : "the server", DisplayName ?? Name));
				if (!isServer)
				{
					serverLockedSettingChanged();
				}
				return true;
			}
			finally
			{
				ProcessingServerUpdate = false;
			}
		}

		private ParsedConfigs ReadConfigsFromPackage(ZPackage package)
		{
			ParsedConfigs parsedConfigs = new ParsedConfigs();
			Dictionary<string, OwnConfigEntryBase> dictionary = allConfigs.Where((OwnConfigEntryBase c) => c.SynchronizedConfig).ToDictionary((OwnConfigEntryBase c) => c.BaseConfig.Definition.Section + "_" + c.BaseConfig.Definition.Key, (OwnConfigEntryBase c) => c);
			Dictionary<string, CustomSyncedValueBase> dictionary2 = allCustomValues.ToDictionary((CustomSyncedValueBase c) => c.Identifier, (CustomSyncedValueBase c) => c);
			int num = package.ReadInt();
			for (int i = 0; i < num; i++)
			{
				string text = package.ReadString();
				string text2 = package.ReadString();
				string text3 = package.ReadString();
				Type type = Type.GetType(text3);
				if (text3 == "" || type != null)
				{
					object obj;
					try
					{
						obj = ((text3 == "") ? null : ReadValueWithTypeFromZPackage(package, type));
					}
					catch (InvalidDeserializationTypeException ex)
					{
						Debug.LogWarning((object)("Got unexpected struct internal type " + ex.received + " for field " + ex.field + " struct " + text3 + " for " + text2 + " in section " + text + " for mod " + (DisplayName ?? Name) + ", expecting " + ex.expected));
						continue;
					}
					OwnConfigEntryBase value2;
					if (text == "Internal")
					{
						CustomSyncedValueBase value;
						if (text2 == "serverversion")
						{
							if (obj?.ToString() != CurrentVersion)
							{
								Debug.LogWarning((object)("Received server version is not equal: server version = " + (obj?.ToString() ?? "null") + "; local version = " + (CurrentVersion ?? "unknown")));
							}
						}
						else if (text2 == "lockexempt")
						{
							if (obj is bool flag)
							{
								lockExempt = flag;
							}
						}
						else if (dictionary2.TryGetValue(text2, out value))
						{
							if ((text3 == "" && (!value.Type.IsValueType || Nullable.GetUnderlyingType(value.Type) != null)) || GetZPackageTypeString(value.Type) == text3)
							{
								parsedConfigs.customValues[value] = obj;
								continue;
							}
							Debug.LogWarning((object)("Got unexpected type " + text3 + " for internal value " + text2 + " for mod " + (DisplayName ?? Name) + ", expecting " + value.Type.AssemblyQualifiedName));
						}
					}
					else if (dictionary.TryGetValue(text + "_" + text2, out value2))
					{
						Type type2 = configType(value2.BaseConfig);
						if ((text3 == "" && (!type2.IsValueType || Nullable.GetUnderlyingType(type2) != null)) || GetZPackageTypeString(type2) == text3)
						{
							parsedConfigs.configValues[value2] = obj;
							continue;
						}
						Debug.LogWarning((object)("Got unexpected type " + text3 + " for " + text2 + " in section " + text + " for mod " + (DisplayName ?? Name) + ", expecting " + type2.AssemblyQualifiedName));
					}
					else
					{
						Debug.LogWarning((object)("Received unknown config entry " + text2 + " in section " + text + " for mod " + (DisplayName ?? Name) + ". This may happen if client and server versions of the mod do not match."));
					}
					continue;
				}
				Debug.LogWarning((object)("Got invalid type " + text3 + ", abort reading of received configs"));
				return new ParsedConfigs();
			}
			return parsedConfigs;
		}

		private static bool isWritableConfig(OwnConfigEntryBase config)
		{
			OwnConfigEntryBase config2 = config;
			ConfigSync configSync = configSyncs.FirstOrDefault((ConfigSync cs) => cs.allConfigs.Contains(config2));
			if (configSync == null)
			{
				return true;
			}
			return configSync.IsSourceOfTruth || !config2.SynchronizedConfig || config2.LocalBaseValue == null || (!configSync.IsLocked && (config2 != configSync.lockedConfig || lockExempt));
		}

		private void serverLockedSettingChanged()
		{
			foreach (OwnConfigEntryBase allConfig in allConfigs)
			{
				configAttribute<ConfigurationManagerAttributes>(allConfig.BaseConfig).ReadOnly = !isWritableConfig(allConfig);
			}
		}

		private void resetConfigsFromServer()
		{
			ConfigFile val = null;
			bool saveOnConfigSet = false;
			foreach (OwnConfigEntryBase item in allConfigs.Where((OwnConfigEntryBase config) => config.LocalBaseValue != null))
			{
				if (val == null)
				{
					val = item.BaseConfig.ConfigFile;
					saveOnConfigSet = val.SaveOnConfigSet;
					val.SaveOnConfigSet = false;
				}
				item.BaseConfig.BoxedValue = item.LocalBaseValue;
				item.LocalBaseValue = null;
			}
			if (val != null)
			{
				val.SaveOnConfigSet = saveOnConfigSet;
			}
			foreach (CustomSyncedValueBase item2 in allCustomValues.Where((CustomSyncedValueBase config) => config.LocalBaseValue != null))
			{
				item2.BoxedValue = item2.LocalBaseValue;
				item2.LocalBaseValue = null;
			}
			lockedConfigChanged -= serverLockedSettingChanged;
			serverLockedSettingChanged();
		}

		private IEnumerator<bool> distributeConfigToPeers(ZNetPeer peer, ZPackage package)
		{
			ZNetPeer peer2 = peer;
			ZRoutedRpc rpc = ZRoutedRpc.instance;
			if (rpc == null)
			{
				yield break;
			}
			byte[] data = package.GetArray();
			if (data != null && data.LongLength > 250000)
			{
				int fragments = (int)(1 + (data.LongLength - 1) / 250000);
				long packageIdentifier = ++packageCounter;
				int fragment = 0;
				while (fragment < fragments)
				{
					foreach (bool item in waitForQueue())
					{
						yield return item;
					}
					if (peer2.m_socket.IsConnected())
					{
						ZPackage fragmentedPackage = new ZPackage();
						fragmentedPackage.Write((byte)2);
						fragmentedPackage.Write(packageIdentifier);
						fragmentedPackage.Write(fragment);
						fragmentedPackage.Write(fragments);
						fragmentedPackage.Write(data.Skip(250000 * fragment).Take(250000).ToArray());
						SendPackage(fragmentedPackage);
						if (fragment != fragments - 1)
						{
							yield return true;
						}
						int num = fragment + 1;
						fragment = num;
						continue;
					}
					break;
				}
				yield break;
			}
			foreach (bool item2 in waitForQueue())
			{
				yield return item2;
			}
			SendPackage(package);
			void SendPackage(ZPackage pkg)
			{
				string text = Name + " ConfigSync";
				if (isServer)
				{
					peer2.m_rpc.Invoke(text, new object[1] { pkg });
				}
				else
				{
					rpc.InvokeRoutedRPC(peer2.m_server ? 0 : peer2.m_uid, text, new object[1] { pkg });
				}
			}
			IEnumerable<bool> waitForQueue()
			{
				float timeout = Time.time + 30f;
				while (peer2.m_socket.GetSendQueueSize() > 20000)
				{
					if (Time.time > timeout)
					{
						Debug.Log((object)$"Disconnecting {peer2.m_uid} after 30 seconds config sending timeout");
						peer2.m_rpc.Invoke("Error", new object[1] { (object)(ConnectionStatus)5 });
						ZNet.instance.Disconnect(peer2);
						break;
					}
					yield return false;
				}
			}
		}

		private IEnumerator sendZPackage(long target, ZPackage package)
		{
			if (!Object.op_Implicit((Object)(object)ZNet.instance))
			{
				return Enumerable.Empty<object>().GetEnumerator();
			}
			List<ZNetPeer> list = (List<ZNetPeer>)AccessTools.DeclaredField(typeof(ZRoutedRpc), "m_peers").GetValue(ZRoutedRpc.instance);
			if (target != ZRoutedRpc.Everybody)
			{
				list = list.Where((ZNetPeer p) => p.m_uid == target).ToList();
			}
			return sendZPackage(list, package);
		}

		private IEnumerator sendZPackage(List<ZNetPeer> peers, ZPackage package)
		{
			ZPackage package2 = package;
			if (!Object.op_Implicit((Object)(object)ZNet.instance))
			{
				yield break;
			}
			byte[] rawData = package2.GetArray();
			if (rawData != null && rawData.LongLength > 10000)
			{
				ZPackage compressedPackage = new ZPackage();
				compressedPackage.Write((byte)4);
				MemoryStream output = new MemoryStream();
				using (DeflateStream deflateStream = new DeflateStream(output, CompressionLevel.Optimal))
				{
					deflateStream.Write(rawData, 0, rawData.Length);
				}
				compressedPackage.Write(output.ToArray());
				package2 = compressedPackage;
			}
			List<IEnumerator<bool>> writers = (from peer in peers
				where peer.IsReady()
				select peer into p
				select distributeConfigToPeers(p, package2)).ToList();
			writers.RemoveAll((IEnumerator<bool> writer) => !writer.MoveNext());
			while (writers.Count > 0)
			{
				yield return null;
				writers.RemoveAll((IEnumerator<bool> writer) => !writer.MoveNext());
			}
		}

		private void Broadcast(long target, params ConfigEntryBase[] configs)
		{
			if (!IsLocked || isServer)
			{
				ZPackage package = ConfigsToPackage(configs);
				ZNet instance = ZNet.instance;
				if (instance != null)
				{
					((MonoBehaviour)instance).StartCoroutine(sendZPackage(target, package));
				}
			}
		}

		private void Broadcast(long target, params CustomSyncedValueBase[] customValues)
		{
			if (!IsLocked || isServer)
			{
				ZPackage package = ConfigsToPackage(null, customValues);
				ZNet instance = ZNet.instance;
				if (instance != null)
				{
					((MonoBehaviour)instance).StartCoroutine(sendZPackage(target, package));
				}
			}
		}

		private static OwnConfigEntryBase? configData(ConfigEntryBase config)
		{
			return config.Description.Tags?.OfType<OwnConfigEntryBase>().SingleOrDefault();
		}

		public static SyncedConfigEntry<T>? ConfigData<T>(ConfigEntry<T> config)
		{
			return ((ConfigEntryBase)config).Description.Tags?.OfType<SyncedConfigEntry<T>>().SingleOrDefault();
		}

		private static T configAttribute<T>(ConfigEntryBase config)
		{
			return config.Description.Tags.OfType<T>().First();
		}

		private static Type configType(ConfigEntryBase config)
		{
			return configType(config.SettingType);
		}

		private static Type configType(Type type)
		{
			return type.IsEnum ? Enum.GetUnderlyingType(type) : type;
		}

		private static ZPackage ConfigsToPackage(IEnumerable<ConfigEntryBase>? configs = null, IEnumerable<CustomSyncedValueBase>? customValues = null, IEnumerable<PackageEntry>? packageEntries = null, bool partial = true)
		{
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Expected O, but got Unknown
			List<ConfigEntryBase> list = configs?.Where((ConfigEntryBase config) => configData(config).SynchronizedConfig).ToList() ?? new List<ConfigEntryBase>();
			List<CustomSyncedValueBase> list2 = customValues?.ToList() ?? new List<CustomSyncedValueBase>();
			ZPackage val = new ZPackage();
			val.Write((byte)(partial ? 1 : 0));
			val.Write(list.Count + list2.Count + (packageEntries?.Count() ?? 0));
			foreach (PackageEntry item in packageEntries ?? Array.Empty<PackageEntry>())
			{
				AddEntryToPackage(val, item);
			}
			foreach (CustomSyncedValueBase item2 in list2)
			{
				AddEntryToPackage(val, new PackageEntry
				{
					section = "Internal",
					key = item2.Identifier,
					type = item2.Type,
					value = item2.BoxedValue
				});
			}
			foreach (ConfigEntryBase item3 in list)
			{
				AddEntryToPackage(val, new PackageEntry
				{
					section = item3.Definition.Section,
					key = item3.Definition.Key,
					type = configType(item3),
					value = item3.BoxedValue
				});
			}
			return val;
		}

		private static void AddEntryToPackage(ZPackage package, PackageEntry entry)
		{
			package.Write(entry.section);
			package.Write(entry.key);
			package.Write((entry.value == null) ? "" : GetZPackageTypeString(entry.type));
			AddValueToZPackage(package, entry.value);
		}

		private static string GetZPackageTypeString(Type type)
		{
			return type.AssemblyQualifiedName;
		}

		private static void AddValueToZPackage(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)
						{
							AddValueToZPackage(package, 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(GetZPackageTypeString(fieldInfo.FieldType));
						AddValueToZPackage(package, fieldInfo.GetValue(value));
					}
					return;
				}
			}
			ZRpc.Serialize(new object[1] { value }, ref package);
		}

		private static object ReadValueWithTypeFromZPackage(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 != GetZPackageTypeString(fieldInfo.FieldType))
					{
						throw new InvalidDeserializationTypeException
						{
							received = text,
							expected = GetZPackageTypeString(fieldInfo.FieldType),
							field = fieldInfo.Name
						};
					}
					fieldInfo.SetValue(uninitializedObject, ReadValueWithTypeFromZPackage(package, 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 = ReadValueWithTypeFromZPackage(package, 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] { ReadValueWithTypeFromZPackage(package, 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.First();
		}
	}
	[PublicAPI]
	[HarmonyPatch]
	internal class VersionCheck
	{
		private static readonly HashSet<VersionCheck> versionChecks;

		private static readonly Dictionary<string, string> notProcessedNames;

		public string Name;

		private string? displayName;

		private string? currentVersion;

		private string? minimumRequiredVersion;

		public bool ModRequired = true;

		private string? ReceivedCurrentVersion;

		private string? ReceivedMinimumRequiredVersion;

		private readonly List<ZRpc> ValidatedClients = new List<ZRpc>();

		private ConfigSync? ConfigSync;

		public string DisplayName
		{
			get
			{
				return displayName ?? Name;
			}
			set
			{
				displayName = value;
			}
		}

		public string CurrentVersion
		{
			get
			{
				return currentVersion ?? "0.0.0";
			}
			set
			{
				currentVersion = value;
			}
		}

		public string MinimumRequiredVersion
		{
			get
			{
				return minimumRequiredVersion ?? (ModRequired ? CurrentVersion : "0.0.0");
			}
			set
			{
				minimumRequiredVersion = value;
			}
		}

		private static void PatchServerSync()
		{
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Expected O, but got Unknown
			Patches patchInfo = PatchProcessor.GetPatchInfo((MethodBase)AccessTools.DeclaredMethod(typeof(ZNet), "Awake", (Type[])null, (Type[])null));
			if (patchInfo != null && patchInfo.Postfixes.Count((Patch p) => p.PatchMethod.DeclaringType == typeof(ConfigSync.RegisterRPCPatch)) > 0)
			{
				return;
			}
			Harmony val = new Harmony("org.bepinex.helpers.ServerSync");
			foreach (Type item in from t in typeof(ConfigSync).GetNestedTypes(BindingFlags.NonPublic).Concat(new Type[1] { typeof(VersionCheck) })
				where t.IsClass
				select t)
			{
				val.PatchAll(item);
			}
		}

		static VersionCheck()
		{
			versionChecks = new HashSet<VersionCheck>();
			notProcessedNames = new Dictionary<string, string>();
			typeof(ThreadingHelper).GetMethod("StartSyncInvoke").Invoke(ThreadingHelper.Instance, new object[1]
			{
				new Action(PatchServerSync)
			});
		}

		public VersionCheck(string name)
		{
			Name = name;
			ModRequired = true;
			versionChecks.Add(this);
		}

		public VersionCheck(ConfigSync configSync)
		{
			ConfigSync = configSync;
			Name = ConfigSync.Name;
			versionChecks.Add(this);
		}

		public void Initialize()
		{
			ReceivedCurrentVersion = null;
			ReceivedMinimumRequiredVersion = null;
			if (ConfigSync != null)
			{
				Name = ConfigSync.Name;
				DisplayName = ConfigSync.DisplayName;
				CurrentVersion = ConfigSync.CurrentVersion;
				MinimumRequiredVersion = ConfigSync.MinimumRequiredVersion;
				ModRequired = ConfigSync.ModRequired;
			}
		}

		private bool IsVersionOk()
		{
			if (ReceivedMinimumRequiredVersion == null || ReceivedCurrentVersion == null)
			{
				return !ModRequired;
			}
			bool flag = new Version(CurrentVersion) >= new Version(ReceivedMinimumRequiredVersion);
			bool flag2 = new Version(ReceivedCurrentVersion) >= new Version(MinimumRequiredVersion);
			return flag && flag2;
		}

		private string ErrorClient()
		{
			if (ReceivedMinimumRequiredVersion == null)
			{
				return DisplayName + " is not installed on the server.";
			}
			return (new Version(CurrentVersion) >= new Version(ReceivedMinimumRequiredVersion)) ? (DisplayName + " may not be higher than version " + ReceivedCurrentVersion + ". You have version " + CurrentVersion + ".") : (DisplayName + " needs to be at least version " + ReceivedMinimumRequiredVersion + ". You have version " + CurrentVersion + ".");
		}

		private string ErrorServer(ZRpc rpc)
		{
			return "Disconnect: The client (" + rpc.GetSocket().GetHostName() + ") doesn't have the correct " + DisplayName + " version " + MinimumRequiredVersion;
		}

		private string Error(ZRpc? rpc = null)
		{
			return (rpc == null) ? ErrorClient() : ErrorServer(rpc);
		}

		private static VersionCheck[] GetFailedClient()
		{
			return versionChecks.Where((VersionCheck check) => !check.IsVersionOk()).ToArray();
		}

		private static VersionCheck[] GetFailedServer(ZRpc rpc)
		{
			ZRpc rpc2 = rpc;
			return versionChecks.Where((VersionCheck check) => check.ModRequired && !check.ValidatedClients.Contains(rpc2)).ToArray();
		}

		private static void Logout()
		{
			Game.instance.Logout(true, true);
			AccessTools.DeclaredField(typeof(ZNet), "m_connectionStatus").SetValue(null, (object)(ConnectionStatus)3);
		}

		private static void DisconnectClient(ZRpc rpc)
		{
			rpc.Invoke("Error", new object[1] { 3 });
		}

		private static void CheckVersion(ZRpc rpc, ZPackage pkg)
		{
			CheckVersion(rpc, pkg, null);
		}

		private static void CheckVersion(ZRpc rpc, ZPackage pkg, Action<ZRpc, ZPackage>? original)
		{
			string text = pkg.ReadString();
			string text2 = pkg.ReadString();
			string text3 = pkg.ReadString();
			bool flag = false;
			foreach (VersionCheck versionCheck in versionChecks)
			{
				if (!(text != versionCheck.Name))
				{
					Debug.Log((object)("Received " + versionCheck.DisplayName + " version " + text3 + " and minimum version " + text2 + " from the " + (ZNet.instance.IsServer() ? "client" : "server") + "."));
					versionCheck.ReceivedMinimumRequiredVersion = text2;
					versionCheck.ReceivedCurrentVersion = text3;
					if (ZNet.instance.IsServer() && versionCheck.IsVersionOk())
					{
						versionCheck.ValidatedClients.Add(rpc);
					}
					flag = true;
				}
			}
			if (flag)
			{
				return;
			}
			pkg.SetPos(0);
			if (original != null)
			{
				original(rpc, pkg);
				if (pkg.GetPos() == 0)
				{
					notProcessedNames.Add(text, text3);
				}
			}
		}

		[HarmonyPatch(typeof(ZNet), "RPC_PeerInfo")]
		[HarmonyPrefix]
		private static bool RPC_PeerInfo(ZRpc rpc, ZNet __instance)
		{
			VersionCheck[] array = (__instance.IsServer() ? GetFailedServer(rpc) : GetFailedClient());
			if (array.Length == 0)
			{
				return true;
			}
			VersionCheck[] array2 = array;
			foreach (VersionCheck versionCheck in array2)
			{
				Debug.LogWarning((object)versionCheck.Error(rpc));
			}
			if (__instance.IsServer())
			{
				DisconnectClient(rpc);
			}
			else
			{
				Logout();
			}
			return false;
		}

		[HarmonyPatch(typeof(ZNet), "OnNewConnection")]
		[HarmonyPrefix]
		private static void RegisterAndCheckVersion(ZNetPeer peer, ZNet __instance)
		{
			//IL_018e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0195: Expected O, but got Unknown
			notProcessedNames.Clear();
			IDictionary dictionary = (IDictionary)typeof(ZRpc).GetField("m_functions", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(peer.m_rpc);
			if (dictionary.Contains(StringExtensionMethods.GetStableHashCode("ServerSync VersionCheck")))
			{
				object obj = dictionary[StringExtensionMethods.GetStableHashCode("ServerSync VersionCheck")];
				Action<ZRpc, ZPackage> action = (Action<ZRpc, ZPackage>)obj.GetType().GetField("m_action", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(obj);
				peer.m_rpc.Register<ZPackage>("ServerSync VersionCheck", (Action<ZRpc, ZPackage>)delegate(ZRpc rpc, ZPackage pkg)
				{
					CheckVersion(rpc, pkg, action);
				});
			}
			else
			{
				peer.m_rpc.Register<ZPackage>("ServerSync VersionCheck", (Action<ZRpc, ZPackage>)CheckVersion);
			}
			foreach (VersionCheck versionCheck in versionChecks)
			{
				versionCheck.Initialize();
				if (versionCheck.ModRequired || __instance.IsServer())
				{
					Debug.Log((object)("Sending " + versionCheck.DisplayName + " version " + versionCheck.CurrentVersion + " and minimum version " + versionCheck.MinimumRequiredVersion + " to the " + (__instance.IsServer() ? "client" : "server") + "."));
					ZPackage val = new ZPackage();
					val.Write(versionCheck.Name);
					val.Write(versionCheck.MinimumRequiredVersion);
					val.Write(versionCheck.CurrentVersion);
					peer.m_rpc.Invoke("ServerSync VersionCheck", new object[1] { val });
				}
			}
		}

		[HarmonyPatch(typeof(ZNet), "Disconnect")]
		[HarmonyPrefix]
		private static void RemoveDisconnected(ZNetPeer peer, ZNet __instance)
		{
			if (!__instance.IsServer())
			{
				return;
			}
			foreach (VersionCheck versionCheck in versionChecks)
			{
				versionCheck.ValidatedClients.Remove(peer.m_rpc);
			}
		}

		[HarmonyPatch(typeof(FejdStartup), "ShowConnectError")]
		[HarmonyPostfix]
		private static void ShowConnectionError(FejdStartup __instance)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Invalid comparison between Unknown and I4
			//IL_0186: Unknown result type (might be due to invalid IL or missing references)
			//IL_018b: 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_01de: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_020a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0219: Unknown result type (might be due to invalid IL or missing references)
			//IL_021e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0229: Unknown result type (might be due to invalid IL or missing references)
			if (!__instance.m_connectionFailedPanel.activeSelf || (int)ZNet.GetConnectionStatus() != 3)
			{
				return;
			}
			bool flag = false;
			VersionCheck[] failedClient = GetFailedClient();
			if (failedClient.Length != 0)
			{
				string text = string.Join("\n", failedClient.Select((VersionCheck check) => check.Error()));
				TMP_Text connectionFailedError = __instance.m_connectionFailedError;
				connectionFailedError.text = connectionFailedError.text + "\n" + text;
				flag = true;
			}
			foreach (KeyValuePair<string, string> item in notProcessedNames.OrderBy<KeyValuePair<string, string>, string>((KeyValuePair<string, string> kv) => kv.Key))
			{
				if (!__instance.m_connectionFailedError.text.Contains(item.Key))
				{
					TMP_Text connectionFailedError2 = __instance.m_connectionFailedError;
					connectionFailedError2.text = connectionFailedError2.text + "\nServer expects you to have " + item.Key + " (Version: " + item.Value + ") installed.";
					flag = true;
				}
			}
			if (flag)
			{
				RectTransform component = ((Component)__instance.m_connectionFailedPanel.transform.Find("Image")).GetComponent<RectTransform>();
				Vector2 sizeDelta = component.sizeDelta;
				sizeDelta.x = 675f;
				component.sizeDelta = sizeDelta;
				__instance.m_connectionFailedError.ForceMeshUpdate(false, false);
				float num = __instance.m_connectionFailedError.renderedHeight + 105f;
				RectTransform component2 = ((Component)((Component)component).transform.Find("ButtonOk")).GetComponent<RectTransform>();
				component2.anchoredPosition = new Vector2(component2.anchoredPosition.x, component2.anchoredPosition.y - (num - component.sizeDelta.y) / 2f);
				sizeDelta = component.sizeDelta;
				sizeDelta.y = num;
				component.sizeDelta = sizeDelta;
			}
		}
	}
}

BepInEx/plugins/BuildingDemolish.dll

Decompiled a day ago
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using TMPro;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("BuildingDemolish")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("BuildingDemolish")]
[assembly: AssemblyCopyright("Copyright ©  2026")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("5d65d6a3-c00b-4cf1-a8e3-55e65f6deb37")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("1.0.0.0")]
public class AedenthornUtils
{
	public static bool IgnoreKeyPresses(bool extra = false)
	{
		if (!extra)
		{
			if (!((Object)(object)ZNetScene.instance == (Object)null) && !((Object)(object)Player.m_localPlayer == (Object)null) && !Minimap.IsOpen() && !Console.IsVisible() && !TextInput.IsVisible() && !ZNet.instance.InPasswordDialog())
			{
				Chat instance = Chat.instance;
				if (instance == null)
				{
					return false;
				}
				return instance.HasFocus();
			}
			return true;
		}
		if (!((Object)(object)ZNetScene.instance == (Object)null) && !((Object)(object)Player.m_localPlayer == (Object)null) && !Minimap.IsOpen() && !Console.IsVisible() && !TextInput.IsVisible() && !ZNet.instance.InPasswordDialog())
		{
			Chat instance2 = Chat.instance;
			if ((instance2 == null || !instance2.HasFocus()) && !StoreGui.IsVisible() && !InventoryGui.IsVisible() && !Menu.IsVisible())
			{
				TextViewer instance3 = TextViewer.instance;
				if (instance3 == null)
				{
					return false;
				}
				return instance3.IsVisible();
			}
		}
		return true;
	}

	public static bool CheckKeyDown(string value)
	{
		try
		{
			return Input.GetKeyDown(value.ToLower());
		}
		catch
		{
			return false;
		}
	}

	public static bool CheckKeyHeld(string value, bool req = true)
	{
		try
		{
			return Input.GetKey(value.ToLower());
		}
		catch
		{
			return !req;
		}
	}
}
namespace BuildingDemolish;

[BepInPlugin("aedenthorn.BuildingDemolish", "Building Demolish", "0.6.0")]
public class BepInExPlugin : BaseUnityPlugin
{
	[HarmonyPatch(typeof(Terminal), "InputText")]
	private static class InputText_Patch
	{
		private static bool Prefix(Terminal __instance)
		{
			if (!modEnabled.Value)
			{
				return true;
			}
			string text = ((TMP_InputField)__instance.m_input).text;
			if (text.ToLower().Equals(typeof(BepInExPlugin).Namespace.ToLower() + " reset"))
			{
				((BaseUnityPlugin)context).Config.Reload();
				((BaseUnityPlugin)context).Config.Save();
				__instance.AddString(text);
				__instance.AddString(((BaseUnityPlugin)context).Info.Metadata.Name + " config reloaded");
				return false;
			}
			if (text.ToLower().Equals(typeof(BepInExPlugin).Namespace.ToLower() + " demolish"))
			{
				__instance.AddString(text);
				int num = DemolishPieces(destroyRadius.Value);
				__instance.AddString($"{((BaseUnityPlugin)context).Info.Metadata.Name} demolished {num} pieces");
				return false;
			}
			if (text.ToLower().StartsWith(typeof(BepInExPlugin).Namespace.ToLower() + " demolish "))
			{
				__instance.AddString(text);
				if (int.TryParse(text.Split(new char[1] { ' ' })[2], out var result))
				{
					int num2 = DemolishPieces(result);
					__instance.AddString($"{((BaseUnityPlugin)context).Info.Metadata.Name} demolished {num2} pieces");
				}
				else
				{
					__instance.AddString(((BaseUnityPlugin)context).Info.Metadata.Name + " syntax error");
				}
				return false;
			}
			return true;
		}
	}

	private static readonly bool isDebug = true;

	private static BepInExPlugin context;

	public static ConfigEntry<bool> modEnabled;

	public static ConfigEntry<int> nexusID;

	public static ConfigEntry<bool> allowDestroyUncreated;

	public static ConfigEntry<bool> requireCraftingStation;

	public static ConfigEntry<float> destroyRadius;

	public static ConfigEntry<string> hotKey;

	public static int destroyMask = LayerMask.GetMask(new string[7] { "Default", "static_solid", "Default_small", "piece", "piece_nonsolid", "terrain", "vehicle" });

	public static void Dbgl(string str = "", bool pref = true)
	{
		if (isDebug)
		{
			Debug.Log((object)((pref ? (typeof(BepInExPlugin).Namespace + " ") : "") + str));
		}
	}

	private void Awake()
	{
		context = this;
		modEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enable this mod");
		nexusID = ((BaseUnityPlugin)this).Config.Bind<int>("General", "NexusID", 516, "Nexus mod ID for updates");
		destroyRadius = ((BaseUnityPlugin)this).Config.Bind<float>("General", "DestroyRadius", 20f, "Radius of destruction");
		allowDestroyUncreated = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "AllowDestroyUncreated", false, "Allow destroying buildings not created by any player");
		requireCraftingStation = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "RequireCraftingStation", true, "Require a nearby crafting station to destroy corresponding pieces (this is a vanilla requirement)");
		hotKey = ((BaseUnityPlugin)this).Config.Bind<string>("General", "HotKey", ";", "Hotkey to initiate destruction");
		if (modEnabled.Value)
		{
			Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), (string)null);
		}
	}

	private void Update()
	{
		if (!AedenthornUtils.IgnoreKeyPresses(extra: true) && AedenthornUtils.CheckKeyDown(hotKey.Value))
		{
			int num = DemolishPieces(destroyRadius.Value);
			Dbgl($"Demolished {num} pieces.");
		}
	}

	private static int DemolishPieces(float radius)
	{
		//IL_0018: Unknown result type (might be due to invalid IL or missing references)
		//IL_007d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0093: Unknown result type (might be due to invalid IL or missing references)
		//IL_0139: Unknown result type (might be due to invalid IL or missing references)
		//IL_0145: Unknown result type (might be due to invalid IL or missing references)
		//IL_016f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0174: Unknown result type (might be due to invalid IL or missing references)
		Player localPlayer = Player.m_localPlayer;
		if (!Object.op_Implicit((Object)(object)localPlayer))
		{
			return 0;
		}
		int num = 0;
		Collider[] array = Physics.OverlapSphere(((Component)localPlayer).transform.position, radius, destroyMask);
		for (int i = 0; i < array.Length; i++)
		{
			Piece componentInParent = ((Component)array[i]).GetComponentInParent<Piece>();
			if (!Object.op_Implicit((Object)(object)componentInParent) || (!componentInParent.IsCreator() && (componentInParent.GetCreator() != 0L || !allowDestroyUncreated.Value)) || !componentInParent.m_canBeRemoved || Location.IsInsideNoBuildLocation(((Component)componentInParent).transform.position) || !PrivateArea.CheckAccess(((Component)componentInParent).transform.position, 0f, true, false) || (requireCraftingStation.Value && !Traverse.Create((object)localPlayer).Method("CheckCanRemovePiece", new object[1] { componentInParent }).GetValue<bool>()))
			{
				continue;
			}
			ZNetView component = ((Component)componentInParent).GetComponent<ZNetView>();
			if (!((Object)(object)component == (Object)null) && componentInParent.CanBeRemoved())
			{
				num++;
				WearNTear component2 = ((Component)componentInParent).GetComponent<WearNTear>();
				if (Object.op_Implicit((Object)(object)component2))
				{
					component2.Remove(false);
					continue;
				}
				component.ClaimOwnership();
				componentInParent.DropResources((HitData)null);
				componentInParent.m_placeEffect.Create(((Component)componentInParent).transform.position, ((Component)componentInParent).transform.rotation, ((Component)componentInParent).gameObject.transform, 1f, -1);
				localPlayer.m_removeEffects.Create(((Component)componentInParent).transform.position, Quaternion.identity, (Transform)null, 1f, -1);
				ZNetScene.instance.Destroy(((Component)componentInParent).gameObject);
			}
		}
		return num;
	}
}

BepInEx/plugins/GroupCoinSplit.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using Groups;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("GroupCoinSplit")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("GroupCoinSplit")]
[assembly: AssemblyCopyright("Copyright ©  2026")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("632effe9-d4d8-49a4-9193-7a12b43e51ee")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("1.0.0.0")]
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;
		}
	}
}
namespace GroupCoinSplit
{
	internal static class GcsFlags
	{
		public const string PlayerDropped = "gcs_player_dropped";

		public const string MobLoot = "gcs_mob_loot";
	}
	internal static class PrefabName
	{
		public static string Of(GameObject go)
		{
			if ((Object)(object)go == (Object)null)
			{
				return "";
			}
			string text = ((Object)go).name ?? "";
			if (!text.EndsWith("(Clone)", StringComparison.Ordinal))
			{
				return text;
			}
			return text.Replace("(Clone)", "").Trim();
		}
	}
	[HarmonyPatch]
	internal static class MarkPlayerDroppedCoinsPatch
	{
		private static MethodBase TargetMethod()
		{
			List<MethodInfo> list = (from m in typeof(ItemDrop).GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)
				where m.Name == "DropItem"
				where m.ReturnType == typeof(GameObject) || m.ReturnType == typeof(ItemDrop)
				select m).ToList();
			if (list.Count > 0)
			{
				return list.FirstOrDefault((MethodInfo m) => m.GetParameters().Any((ParameterInfo p) => p.ParameterType == typeof(ItemData))) ?? list[0];
			}
			return AccessTools.Method(typeof(ItemDrop), "DropItem", (Type[])null, (Type[])null);
		}

		[HarmonyPostfix]
		private static void Postfix(object __result)
		{
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				GameObject val = null;
				GameObject val2 = (GameObject)((__result is GameObject) ? __result : null);
				if (val2 != null)
				{
					val = val2;
				}
				else
				{
					ItemDrop val3 = (ItemDrop)((__result is ItemDrop) ? __result : null);
					if (val3 != null)
					{
						val = ((Component)val3).gameObject;
					}
				}
				if ((Object)(object)val == (Object)null || !string.Equals(PrefabName.Of(val), "Coins", StringComparison.OrdinalIgnoreCase))
				{
					return;
				}
				ZNetView component = val.GetComponent<ZNetView>();
				if (!((Object)(object)component == (Object)null) && component.IsValid())
				{
					ZDO zDO = component.GetZDO();
					if (zDO != null)
					{
						zDO.Set("gcs_player_dropped", 1);
						GroupCoinSplitPlugin.Dbg($"Flagged Coins as PLAYER_DROPPED zdo={zDO.m_uid}");
					}
				}
			}
			catch
			{
			}
		}
	}
	[HarmonyPatch(typeof(CharacterDrop))]
	internal static class CharacterDropScopePatch
	{
		private static int _depth;

		private static MethodBase[] _targets = Array.Empty<MethodBase>();

		internal static bool InMobDropScope => _depth > 0;

		[HarmonyPrepare]
		private static bool Prepare()
		{
			try
			{
				_targets = (from m in typeof(CharacterDrop).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
					where m.ReturnType == typeof(void)
					select m).Where(delegate(MethodInfo m)
				{
					string name = m.Name;
					bool flag = name.IndexOf("Drop", StringComparison.OrdinalIgnoreCase) >= 0;
					bool flag2 = name.IndexOf("Item", StringComparison.OrdinalIgnoreCase) >= 0;
					bool flag3 = name.IndexOf("Loot", StringComparison.OrdinalIgnoreCase) >= 0;
					return flag && (flag2 || flag3);
				}).Cast<MethodBase>().ToArray();
				if (_targets.Length == 0)
				{
					GroupCoinSplitPlugin.LogWarning("[GCS] CharacterDrop drop methods not found on this build. MOB_LOOT flagging will be limited (coins may be treated as NOT mob loot).");
					return false;
				}
				GroupCoinSplitPlugin.LogInfo("[GCS] CharacterDrop scope targets: " + string.Join(" | ", _targets.Select((MethodBase t) => t.Name + "(" + string.Join(", ", from p in t.GetParameters()
					select p.ParameterType.Name) + ")")));
				return true;
			}
			catch (Exception arg)
			{
				GroupCoinSplitPlugin.LogError($"[GCS] CharacterDropScopePatch.Prepare error: {arg}");
				return false;
			}
		}

		private static IEnumerable<MethodBase> TargetMethods()
		{
			return _targets;
		}

		[HarmonyPrefix]
		private static void Prefix()
		{
			_depth++;
		}

		[HarmonyFinalizer]
		private static Exception? Finalizer(Exception? __exception)
		{
			_depth = Math.Max(0, _depth - 1);
			return __exception;
		}
	}
	[HarmonyPatch(typeof(ItemDrop), "Awake")]
	internal static class MarkMobLootCoinsOnAwakePatch
	{
		[HarmonyPostfix]
		private static void Postfix(ItemDrop __instance)
		{
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if ((Object)(object)__instance == (Object)null || !CharacterDropScopePatch.InMobDropScope)
				{
					return;
				}
				GameObject gameObject = ((Component)__instance).gameObject;
				if ((Object)(object)gameObject == (Object)null || !string.Equals(PrefabName.Of(gameObject), "Coins", StringComparison.OrdinalIgnoreCase))
				{
					return;
				}
				ZNetView component = gameObject.GetComponent<ZNetView>();
				if (!((Object)(object)component == (Object)null) && component.IsValid())
				{
					ZDO zDO = component.GetZDO();
					if (zDO != null)
					{
						zDO.Set("gcs_mob_loot", 1);
						GroupCoinSplitPlugin.Dbg($"Marked Coins as MOB_LOOT zdo={zDO.m_uid}");
					}
				}
			}
			catch
			{
			}
		}
	}
	[HarmonyPatch]
	internal static class HumanoidPickupClientPatch
	{
		[CompilerGenerated]
		private sealed class <DoSplitNextFrame>d__6 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public Player looter;

			public int totalGained;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <DoSplitNextFrame>d__6(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0123: Unknown result type (might be due to invalid IL or missing references)
				//IL_0128: Unknown result type (might be due to invalid IL or missing references)
				//IL_014a: Unknown result type (might be due to invalid IL or missing references)
				//IL_014f: Unknown result type (might be due to invalid IL or missing references)
				//IL_01dc: Unknown result type (might be due to invalid IL or missing references)
				//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
				//IL_03ca: Unknown result type (might be due to invalid IL or missing references)
				//IL_03cf: Unknown result type (might be due to invalid IL or missing references)
				//IL_03d9: Unknown result type (might be due to invalid IL or missing references)
				//IL_03de: Unknown result type (might be due to invalid IL or missing references)
				//IL_03e3: Unknown result type (might be due to invalid IL or missing references)
				//IL_03ee: Unknown result type (might be due to invalid IL or missing references)
				//IL_0403: Unknown result type (might be due to invalid IL or missing references)
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>2__current = null;
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					try
					{
						if (GroupCoinSplitPlugin.CfgMode == null || GroupCoinSplitPlugin.CfgMode.Value == DivisionMode.None)
						{
							return false;
						}
						if (!API.IsLoaded())
						{
							GroupCoinSplitPlugin.Dbg("DoSplit: Groups API not loaded -> skip");
							return false;
						}
						List<PlayerReference> list = API.GroupPlayers();
						if (list == null || list.Count <= 1)
						{
							GroupCoinSplitPlugin.Dbg("DoSplit: no group or only one member -> skip");
							return false;
						}
						Dictionary<long, Player> dictionary = (Player.GetAllPlayers() ?? new List<Player>()).Where((Player pl) => (Object)(object)pl != (Object)null).GroupBy(delegate(Player pl)
						{
							//IL_0001: Unknown result type (might be due to invalid IL or missing references)
							//IL_0006: Unknown result type (might be due to invalid IL or missing references)
							ZDOID zDOID4 = ((Character)pl).GetZDOID();
							return ((ZDOID)(ref zDOID4)).UserID;
						}).ToDictionary((IGrouping<long, Player> g) => g.Key, (IGrouping<long, Player> g) => g.First());
						ZDOID zDOID = ((Character)looter).GetZDOID();
						long userID = ((ZDOID)(ref zDOID)).UserID;
						float value = GroupCoinSplitPlugin.CfgRange.Value;
						Vector3 position = ((Component)looter).transform.position;
						List<long> list2 = list.Select((PlayerReference r) => r.peerId).Distinct().ToList();
						if (!list2.Contains(userID))
						{
							list2.Add(userID);
						}
						List<Player> list3 = new List<Player>();
						foreach (long item in list2)
						{
							if (dictionary.TryGetValue(item, out var value2) && !((Object)(object)value2 == (Object)null) && !(((Character)value2).GetHealth() <= 0f) && Vector3.Distance(((Component)value2).transform.position, position) <= value)
							{
								list3.Add(value2);
							}
						}
						if (!list3.Contains(looter))
						{
							list3.Add(looter);
						}
						list3 = list3.Distinct().OrderBy(delegate(Player pl)
						{
							//IL_0001: Unknown result type (might be due to invalid IL or missing references)
							//IL_0006: Unknown result type (might be due to invalid IL or missing references)
							ZDOID zDOID3 = ((Character)pl).GetZDOID();
							return ((ZDOID)(ref zDOID3)).UserID;
						}).ToList();
						if (list3.Count <= 1)
						{
							GroupCoinSplitPlugin.Dbg("DoSplit: recipients<=1 after range -> skip");
							return false;
						}
						DivisionMode value3 = GroupCoinSplitPlugin.CfgMode.Value;
						Dictionary<long, int> dictionary2 = ComputeShares(userID, list3.Select(delegate(Player r)
						{
							//IL_0001: Unknown result type (might be due to invalid IL or missing references)
							//IL_0006: Unknown result type (might be due to invalid IL or missing references)
							ZDOID zDOID2 = ((Character)r).GetZDOID();
							return ((ZDOID)(ref zDOID2)).UserID;
						}).ToList(), value3, totalGained);
						int value4;
						int num = (dictionary2.TryGetValue(userID, out value4) ? value4 : totalGained);
						int num2 = totalGained - num;
						if (num2 <= 0)
						{
							GroupCoinSplitPlugin.Dbg($"DoSplit: nothing to give away (myShare={num}, total={totalGained})");
							return false;
						}
						if (!RemoveCoins(looter, num2))
						{
							GroupCoinSplitPlugin.LogWarning($"DoSplit: failed to remove {num2} Coins from looter inventory. Aborting distribution.");
							return false;
						}
						GroupCoinSplitPlugin.Dbg($"DoSplit: removed from looter={num2}. Will drop for others.");
						foreach (KeyValuePair<long, int> item2 in dictionary2.OrderBy((KeyValuePair<long, int> k) => k.Key))
						{
							long key = item2.Key;
							int value5 = item2.Value;
							if (key != userID && value5 > 0 && dictionary.TryGetValue(key, out var value6) && !((Object)(object)value6 == (Object)null))
							{
								Vector3 pos = ((Component)value6).transform.position + Random.insideUnitSphere * 0.5f;
								pos.y = ((Component)value6).transform.position.y + 0.2f;
								DropCoinsAt(pos, value5);
								GroupCoinSplitPlugin.Dbg($"DoSplit: dropped {value5} near uid={key}");
							}
						}
					}
					catch (Exception arg)
					{
						GroupCoinSplitPlugin.LogError($"DoSplit error: {arg}");
					}
					return false;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		private static int _coinsBefore;

		private static bool _armed;

		private static bool _eligibleObject;

		private static MethodBase TargetMethod()
		{
			return typeof(Humanoid).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault(delegate(MethodInfo x)
			{
				if (x.Name != "Pickup")
				{
					return false;
				}
				ParameterInfo[] parameters = x.GetParameters();
				return parameters.Length == 3 && parameters[0].ParameterType == typeof(GameObject) && parameters[1].ParameterType == typeof(bool) && parameters[2].ParameterType == typeof(bool);
			}) ?? AccessTools.Method(typeof(Humanoid), "Pickup", (Type[])null, (Type[])null);
		}

		[HarmonyPrefix]
		private static void Prefix(Humanoid __instance, GameObject go, bool autoequip, bool autoPickupDelay)
		{
			try
			{
				_armed = false;
				_eligibleObject = false;
				Player val = (Player)(object)((__instance is Player) ? __instance : null);
				if (val == null || (Object)(object)val != (Object)(object)Player.m_localPlayer || (Object)(object)go == (Object)null || GroupCoinSplitPlugin.CfgMode == null || GroupCoinSplitPlugin.CfgMode.Value == DivisionMode.None || !string.Equals(PrefabName.Of(go), "Coins", StringComparison.OrdinalIgnoreCase))
				{
					return;
				}
				ZNetView component = go.GetComponent<ZNetView>();
				if ((Object)(object)component == (Object)null || !component.IsValid())
				{
					return;
				}
				ZDO zDO = component.GetZDO();
				if (zDO != null)
				{
					if (zDO.GetInt("gcs_player_dropped", 0) == 1)
					{
						GroupCoinSplitPlugin.Dbg("PickupCoins: IGNORE (player_dropped=1)");
						return;
					}
					if (zDO.GetInt("gcs_mob_loot", 0) != 1)
					{
						GroupCoinSplitPlugin.Dbg("PickupCoins: IGNORE (not mob loot)");
						return;
					}
					_coinsBefore = CountCoins(val);
					_armed = true;
					_eligibleObject = true;
					GroupCoinSplitPlugin.Dbg($"PickupCoins: armed coinsBefore={_coinsBefore}");
				}
			}
			catch (Exception arg)
			{
				GroupCoinSplitPlugin.LogError($"Pickup Prefix error: {arg}");
			}
		}

		[HarmonyPostfix]
		private static void Postfix(Humanoid __instance, GameObject go, bool autoequip, bool autoPickupDelay)
		{
			try
			{
				if (!_armed || !_eligibleObject)
				{
					return;
				}
				_armed = false;
				Player val = (Player)(object)((__instance is Player) ? __instance : null);
				if (val != null && !((Object)(object)val != (Object)(object)Player.m_localPlayer))
				{
					int num = CountCoins(val);
					int num2 = num - _coinsBefore;
					if (num2 <= 0)
					{
						GroupCoinSplitPlugin.Dbg($"PickupCoins: gained<=0 (before={_coinsBefore}, after={num}) -> skip");
						return;
					}
					GroupCoinSplitPlugin.Dbg($"PickupCoins: gained={num2} (before={_coinsBefore}, after={num})");
					((MonoBehaviour)val).StartCoroutine(DoSplitNextFrame(val, num2));
				}
			}
			catch (Exception arg)
			{
				GroupCoinSplitPlugin.LogError($"Pickup Postfix error: {arg}");
			}
		}

		[IteratorStateMachine(typeof(<DoSplitNextFrame>d__6))]
		private static IEnumerator DoSplitNextFrame(Player looter, int totalGained)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <DoSplitNextFrame>d__6(0)
			{
				looter = looter,
				totalGained = totalGained
			};
		}

		private static Dictionary<long, int> ComputeShares(long looterUid, List<long> recipientUids, DivisionMode mode, int total)
		{
			List<long> list = (from u in recipientUids.Where((long u) => u > 0).Distinct()
				orderby u
				select u).ToList();
			Dictionary<long, int> dictionary = new Dictionary<long, int>();
			if (list.Count == 0 || total <= 0)
			{
				return dictionary;
			}
			int count = list.Count;
			int num = total / count;
			int num2 = total % count;
			if (num <= 0)
			{
				dictionary[looterUid] = total;
				return dictionary;
			}
			for (int i = 0; i < list.Count; i++)
			{
				int num3 = num;
				switch (mode)
				{
				case DivisionMode.EvenRemainderToPicker:
					if (list[i] == looterUid)
					{
						num3 += num2;
					}
					break;
				case DivisionMode.RoundRobin:
					if (i < num2)
					{
						num3++;
					}
					break;
				}
				if (num3 > 0)
				{
					dictionary[list[i]] = num3;
				}
			}
			return dictionary;
		}

		private static int CountCoins(Player p)
		{
			try
			{
				Inventory inventory = ((Humanoid)p).GetInventory();
				if (inventory == null)
				{
					return 0;
				}
				return inventory.CountItems("Coins", -1, true);
			}
			catch
			{
				return 0;
			}
		}

		private static bool RemoveCoins(Player p, int amount)
		{
			try
			{
				if (amount <= 0)
				{
					return true;
				}
				Inventory inventory = ((Humanoid)p).GetInventory();
				if (inventory == null)
				{
					return false;
				}
				int num = inventory.CountItems("Coins", -1, true);
				inventory.RemoveItem("Coins", amount, -1, true);
				int num2 = inventory.CountItems("Coins", -1, true);
				return num - num2 >= amount;
			}
			catch
			{
				return false;
			}
		}

		private static void DropCoinsAt(Vector3 pos, int amount)
		{
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (amount <= 0 || (Object)(object)ObjectDB.instance == (Object)null)
				{
					return;
				}
				GameObject itemPrefab = ObjectDB.instance.GetItemPrefab("Coins");
				if ((Object)(object)itemPrefab == (Object)null)
				{
					return;
				}
				ItemDrop component = itemPrefab.GetComponent<ItemDrop>();
				if ((Object)(object)component == (Object)null)
				{
					return;
				}
				ItemData val = component.m_itemData.Clone();
				val.m_stack = amount;
				MethodInfo methodInfo = typeof(ItemDrop).GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault(delegate(MethodInfo x)
				{
					if (x.Name != "DropItem")
					{
						return false;
					}
					ParameterInfo[] parameters = x.GetParameters();
					return parameters.Length >= 4 && parameters[0].ParameterType == typeof(ItemData) && parameters[1].ParameterType == typeof(int) && parameters[2].ParameterType == typeof(Vector3) && parameters[3].ParameterType == typeof(Quaternion);
				});
				object obj = null;
				obj = ((!(methodInfo != null)) ? AccessTools.Method(typeof(ItemDrop), "DropItem", (Type[])null, (Type[])null)?.Invoke(null, new object[4]
				{
					val,
					amount,
					pos,
					Quaternion.identity
				}) : methodInfo.Invoke(null, new object[4]
				{
					val,
					amount,
					pos,
					Quaternion.identity
				}));
				GameObject val2 = null;
				GameObject val3 = (GameObject)((obj is GameObject) ? obj : null);
				if (val3 != null)
				{
					val2 = val3;
				}
				else
				{
					ItemDrop val4 = (ItemDrop)((obj is ItemDrop) ? obj : null);
					if (val4 != null)
					{
						val2 = ((Component)val4).gameObject;
					}
				}
				if ((Object)(object)val2 == (Object)null)
				{
					return;
				}
				ZNetView component2 = val2.GetComponent<ZNetView>();
				if ((Object)(object)component2 != (Object)null && component2.IsValid())
				{
					ZDO zDO = component2.GetZDO();
					if (zDO != null)
					{
						zDO.Set("gcs_player_dropped", 1);
					}
				}
			}
			catch
			{
			}
		}
	}
	public enum DivisionMode
	{
		None,
		EvenRemainderToPicker,
		RoundRobin
	}
	[BepInPlugin("twentyonez.groupcoinsplit", "Group Coin Split (Client Only)", "2.0.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class GroupCoinSplitPlugin : BaseUnityPlugin
	{
		public const string ModGuid = "twentyonez.groupcoinsplit";

		public const string ModName = "Group Coin Split (Client Only)";

		public const string ModVersion = "2.0.0";

		internal static GroupCoinSplitPlugin I;

		internal static ConfigEntry<bool> CfgEnabled;

		internal static ConfigEntry<DivisionMode> CfgMode;

		internal static ConfigEntry<float> CfgRange;

		internal static ConfigEntry<bool> CfgDebug;

		private Harmony _harmony;

		private void Awake()
		{
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Expected O, but got Unknown
			I = this;
			CfgEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Se true, o client redistribui Coins (loot de mobs) dropando perto dos colegas do grupo.");
			CfgMode = ((BaseUnityPlugin)this).Config.Bind<DivisionMode>("General", "DivisionMode", DivisionMode.EvenRemainderToPicker, "None: sem divisão\nEvenRemainderToPicker: divide igualmente, resto fica com quem pegou\nRoundRobin: resto distribuído 1 a 1 (ordem estável por UID)");
			CfgRange = ((BaseUnityPlugin)this).Config.Bind<float>("General", "RangeMeters", 20f, "Raio (em metros) para considerar membros do grupo próximos.");
			CfgDebug = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "DebugLog", false, "Se true, escreve logs de debug no client (e no server também, se o mod estiver instalado lá).");
			_harmony = new Harmony("twentyonez.groupcoinsplit");
			_harmony.PatchAll();
			LogInfo($"Loaded. Enabled={CfgEnabled.Value} Mode={CfgMode.Value} Range={CfgRange.Value} Debug={CfgDebug.Value}");
		}

		internal static bool Enabled()
		{
			if (CfgEnabled != null && CfgEnabled.Value)
			{
				return CfgMode.Value != DivisionMode.None;
			}
			return false;
		}

		internal static void LogInfo(string msg)
		{
			if ((Object)(object)I != (Object)null)
			{
				((BaseUnityPlugin)I).Logger.LogInfo((object)msg);
			}
			else
			{
				Debug.Log((object)("[GCS] " + msg));
			}
		}

		internal static void LogWarning(string msg)
		{
			if ((Object)(object)I != (Object)null)
			{
				((BaseUnityPlugin)I).Logger.LogWarning((object)msg);
			}
			else
			{
				Debug.LogWarning((object)("[GCS] " + msg));
			}
		}

		internal static void LogError(string msg)
		{
			if ((Object)(object)I != (Object)null)
			{
				((BaseUnityPlugin)I).Logger.LogError((object)msg);
			}
			else
			{
				Debug.LogError((object)("[GCS] " + msg));
			}
		}

		internal static void Dbg(string msg)
		{
			if (CfgDebug != null && CfgDebug.Value)
			{
				LogInfo("[DBG] " + msg);
			}
		}
	}
}

BepInEx/plugins/Hearthstone.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Jotunn;
using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Managers;
using Jotunn.Utils;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("Valheim HearthStone Mod")]
[assembly: AssemblyDescription("Adds a ConsumableItem that will bring you home")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("HearthStone")]
[assembly: AssemblyCopyright("Copyright ©  2022")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("97d58a4d-8886-44f9-ba81-73da0e389949")]
[assembly: AssemblyFileVersion("1.0.5.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.5.0")]
[module: UnverifiableCode]
namespace Hearthstone;

[BepInPlugin("twentyoneZ.mods.Hearthstone_Revolution", "Hearthstone Revolution by TwentyOneZ", "1.0.5")]
[BepInDependency("com.jotunn.jotunn", "2.9.0")]
public class Hearthstone : BaseUnityPlugin
{
	[HarmonyPatch(typeof(Player), "OnDeath")]
	private static class Patch_Player_OnDeath
	{
		private static void Prefix(Player __instance)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if ((Object)(object)__instance != (Object)null && (Object)(object)__instance == (Object)(object)Player.m_localPlayer)
				{
					SetLastDeathPosition(((Component)__instance).transform.position);
				}
			}
			catch (Exception ex)
			{
				Debug("Failed to capture last death position: " + ex.Message);
			}
		}
	}

	[HarmonyPatch(typeof(TombStone), "Interact")]
	private static class Patch_TombStone_Interact_ClearLastDeath
	{
		private static void Postfix(TombStone __instance, Humanoid __0, bool __1, bool __2, ref bool __result)
		{
			try
			{
				bool flag = __1;
				if (__result && !flag)
				{
					Player val = (Player)(object)((__0 is Player) ? __0 : null);
					if (val != null && !((Object)(object)val != (Object)(object)Player.m_localPlayer))
					{
						ClearLastDeathPosition();
						Debug("Cleared last death position after tombstone interaction.");
					}
				}
			}
			catch (Exception ex)
			{
				Debug("TombStone.Interact postfix failed: " + ex.Message);
			}
		}
	}

	[HarmonyPatch(typeof(Humanoid), "UseItem")]
	private static class Patch_Humanoid_UseItem
	{
		private static bool Prefix(Humanoid __instance, Inventory inventory, ItemData item, bool fromInventoryGui)
		{
			//IL_0189: Unknown result type (might be due to invalid IL or missing references)
			//IL_018e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0190: Unknown result type (might be due to invalid IL or missing references)
			//IL_0192: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_028c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0291: Unknown result type (might be due to invalid IL or missing references)
			//IL_0293: Unknown result type (might be due to invalid IL or missing references)
			//IL_0295: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0203: Unknown result type (might be due to invalid IL or missing references)
			//IL_0208: Unknown result type (might be due to invalid IL or missing references)
			//IL_0213: Unknown result type (might be due to invalid IL or missing references)
			//IL_021b: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_0242: Unknown result type (might be due to invalid IL or missing references)
			//IL_0244: Unknown result type (might be due to invalid IL or missing references)
			//IL_0249: Unknown result type (might be due to invalid IL or missing references)
			//IL_024e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0259: Unknown result type (might be due to invalid IL or missing references)
			//IL_0261: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if ((Object)(object)__instance == (Object)null || item == null)
				{
					return true;
				}
				Player val = (Player)(object)((__instance is Player) ? __instance : null);
				if (val == null)
				{
					return true;
				}
				if ((Object)(object)val != (Object)(object)Player.m_localPlayer)
				{
					return true;
				}
				string text = item.m_shared?.m_name;
				if (string.IsNullOrEmpty(text))
				{
					return true;
				}
				bool flag = text == "Hearthstone";
				bool flag2 = text == "Marketstone";
				bool flag3 = text == "Deathstone" || text == "LastDeathStone";
				if (!flag && !flag2 && !flag3)
				{
					return true;
				}
				if (!((Humanoid)val).IsTeleportable() && !allowTeleportWithoutRestriction.Value)
				{
					((Character)val).Message((MessageType)2, "You can't teleport carrying those items", 0, (Sprite)null);
					return false;
				}
				if (val.IsTargeted() && !allowTeleportWhileTargeted.Value)
				{
					((Character)val).Message((MessageType)2, "You can't teleport while spotted by anyone", 0, (Sprite)null);
					return false;
				}
				if (((Character)val).IsEncumbered() && !allowTeleportWhileEncumbered.Value)
				{
					((Character)val).Message((MessageType)2, "You can't teleport while encumbered", 0, (Sprite)null);
					return false;
				}
				if (((Character)val).InWater() && !allowTeleportWhileInWater.Value)
				{
					((Character)val).Message((MessageType)2, "You can't teleport while in water", 0, (Sprite)null);
					return false;
				}
				if (needsToBeResting.Value && !((Character)val).GetSEMan().HaveStatusEffect(StringExtensionMethods.GetStableHashCode("Resting")))
				{
					((Character)val).Message((MessageType)2, "You have to be resting to teleport", 0, (Sprite)null);
					return false;
				}
				if (flag)
				{
					Vector3 hearthStonePosition = GetHearthStonePosition();
					if (hearthStonePosition == Vector3.zero)
					{
						((Character)val).Message((MessageType)2, "You need to set hearthstone spawn point", 0, (Sprite)null);
						return false;
					}
					ConsumeOne(val, inventory, item);
					((Character)val).TeleportTo(hearthStonePosition, ((Component)val).transform.rotation, true);
					return false;
				}
				if (flag2)
				{
					LocationInstance val2 = default(LocationInstance);
					if (ZoneSystem.instance.FindClosestLocation("Vendor_BlackForest", Vector3.zero, ref val2))
					{
						Vector3 val3 = val2.m_position + Vector3.up;
						ConsumeOne(val, inventory, item);
						((Character)val).TeleportTo(val3, ((Component)val).transform.rotation, true);
						return false;
					}
					Vector3 val4 = default(Vector3);
					if (ZoneSystem.instance.GetLocationIcon("Vendor_BlackForest", ref val4))
					{
						Vector3 val3 = val4 + Vector3.up;
						ConsumeOne(val, inventory, item);
						((Character)val).TeleportTo(val3, ((Component)val).transform.rotation, true);
						return false;
					}
					((Character)val).Message((MessageType)2, "I have to find the market first.", 0, (Sprite)null);
					return false;
				}
				if (flag3)
				{
					Vector3 lastDeathPosition = GetLastDeathPosition();
					if (lastDeathPosition == Vector3.zero)
					{
						((Character)val).Message((MessageType)2, "No death position recorded yet.", 0, (Sprite)null);
						return false;
					}
					ConsumeOne(val, inventory, item);
					((Character)val).TeleportTo(lastDeathPosition + Vector3.up, ((Component)val).transform.rotation, true);
					return false;
				}
				return true;
			}
			catch (Exception arg)
			{
				Debug.Log((object)$"[Hearthstone] UseItem failed: {arg}");
				return true;
			}
		}

		private static void ConsumeOne(Player p, Inventory inventory, ItemData item)
		{
			Inventory val = inventory ?? ((Humanoid)p).GetInventory();
			if (val != null && item.m_stack > 0)
			{
				val.RemoveItem(item, 1);
			}
		}
	}

	public const string sharedName = "Hearthstone";

	public const string sharedLastDeathName = "LastDeathStone";

	public const string PluginGUID = "twentyoneZ.mods.Hearthstone_Revolution";

	private Harmony harmony = new Harmony("twentyoneZ.mods.Hearthstone_Revolution");

	public static ConfigEntry<string> item1;

	public static ConfigEntry<string> item2;

	public static ConfigEntry<string> item3;

	public static ConfigEntry<int> itemCost1;

	public static ConfigEntry<int> itemCost2;

	public static ConfigEntry<int> itemCost3;

	public static ConfigEntry<bool> allowTeleportWithoutRestriction;

	public static ConfigEntry<bool> allowTeleportWhileTargeted;

	public static ConfigEntry<bool> allowTeleportWhileEncumbered;

	public static ConfigEntry<bool> allowTeleportWhileInWater;

	public static ConfigEntry<bool> needsToBeResting;

	public static ConfigEntry<bool> writeDebugOutput;

	private static CustomItem m_hearthStoneItem;

	private static CustomItem m_lastDeathStoneItem;

	private static string m_lastPositionString;

	private static string m_lastDeathPositionString;

	private const string ZdoKey_HearthPos = "HS_HearthPos";

	public static bool IsOwner { get; set; }

	private static string PositionFile
	{
		get
		{
			string text = Path.Combine(Paths.ConfigPath, "Hearthstone");
			Directory.CreateDirectory(text);
			long num = 0L;
			try
			{
				if ((Object)(object)Player.m_localPlayer != (Object)null)
				{
					num = Player.m_localPlayer.GetPlayerID();
				}
			}
			catch
			{
				num = 0L;
			}
			if (num == 0L)
			{
				return Path.Combine(text, "HSPosition.txt");
			}
			return Path.Combine(text, $"HSPosition_{num}.txt");
		}
	}

	private static string LastDeathPositionFile
	{
		get
		{
			string text = Path.Combine(Paths.ConfigPath, "Hearthstone");
			Directory.CreateDirectory(text);
			long num = 0L;
			try
			{
				if ((Object)(object)Player.m_localPlayer != (Object)null)
				{
					num = Player.m_localPlayer.GetPlayerID();
				}
			}
			catch
			{
				num = 0L;
			}
			if (num == 0L)
			{
				return Path.Combine(text, "HSLastDeath.txt");
			}
			return Path.Combine(text, $"HSLastDeath_{num}.txt");
		}
	}

	private static ZNetView GetLocalPlayerNView()
	{
		try
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return null;
			}
			ZNetView component = ((Component)localPlayer).GetComponent<ZNetView>();
			if ((Object)(object)component != (Object)null)
			{
				return component;
			}
			FieldInfo fieldInfo = AccessTools.Field(typeof(Character), "m_nview");
			if (fieldInfo != null)
			{
				object? value = fieldInfo.GetValue(localPlayer);
				component = (ZNetView)((value is ZNetView) ? value : null);
				if ((Object)(object)component != (Object)null)
				{
					return component;
				}
			}
			return null;
		}
		catch
		{
			return null;
		}
	}

	public static void Debug(string value)
	{
		if (writeDebugOutput.Value)
		{
			Logger.LogMessage((object)value);
		}
	}

	private void Awake()
	{
		//IL_0046: 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_0053: Expected O, but got Unknown
		//IL_0053: Unknown result type (might be due to invalid IL or missing references)
		//IL_005d: Expected O, but got Unknown
		//IL_0081: Unknown result type (might be due to invalid IL or missing references)
		//IL_0086: Unknown result type (might be due to invalid IL or missing references)
		//IL_008e: Expected O, but got Unknown
		//IL_008e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0098: Expected O, but got Unknown
		//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cd: Expected O, but got Unknown
		//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d7: Expected O, but got Unknown
		//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
		//IL_0101: Unknown result type (might be due to invalid IL or missing references)
		//IL_0109: Expected O, but got Unknown
		//IL_0109: Unknown result type (might be due to invalid IL or missing references)
		//IL_0113: Expected O, but got Unknown
		//IL_013b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0140: Unknown result type (might be due to invalid IL or missing references)
		//IL_0148: Expected O, but got Unknown
		//IL_0148: Unknown result type (might be due to invalid IL or missing references)
		//IL_0152: Expected O, but got Unknown
		//IL_0176: Unknown result type (might be due to invalid IL or missing references)
		//IL_017b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0183: Expected O, but got Unknown
		//IL_0183: Unknown result type (might be due to invalid IL or missing references)
		//IL_018d: Expected O, but got Unknown
		//IL_01b1: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
		//IL_01be: Expected O, but got Unknown
		//IL_01be: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c8: Expected O, but got Unknown
		//IL_01ec: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f1: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f9: Expected O, but got Unknown
		//IL_01f9: Unknown result type (might be due to invalid IL or missing references)
		//IL_0203: Expected O, but got Unknown
		//IL_0227: Unknown result type (might be due to invalid IL or missing references)
		//IL_022c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0234: Expected O, but got Unknown
		//IL_0234: Unknown result type (might be due to invalid IL or missing references)
		//IL_023e: Expected O, but got Unknown
		//IL_0262: Unknown result type (might be due to invalid IL or missing references)
		//IL_0267: Unknown result type (might be due to invalid IL or missing references)
		//IL_026f: Expected O, but got Unknown
		//IL_026f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0279: Expected O, but got Unknown
		//IL_029d: Unknown result type (might be due to invalid IL or missing references)
		//IL_02a2: Unknown result type (might be due to invalid IL or missing references)
		//IL_02aa: Expected O, but got Unknown
		//IL_02aa: Unknown result type (might be due to invalid IL or missing references)
		//IL_02b4: Expected O, but got Unknown
		//IL_02d8: Unknown result type (might be due to invalid IL or missing references)
		//IL_02dd: Unknown result type (might be due to invalid IL or missing references)
		//IL_02e5: Expected O, but got Unknown
		//IL_02e5: Unknown result type (might be due to invalid IL or missing references)
		//IL_02ef: Expected O, but got Unknown
		((BaseUnityPlugin)this).Config.SaveOnConfigSet = true;
		((BaseUnityPlugin)this).Config.SettingChanged += delegate
		{
			GenerateRecipe();
		};
		item1 = ((BaseUnityPlugin)this).Config.Bind<string>("General", "RecipeItem1", "Stone", new ConfigDescription("Recipe item 1 - leave blank for none", (AcceptableValueBase)null, new object[1] { (object)new ConfigurationManagerAttributes
		{
			IsAdminOnly = true
		} }));
		itemCost1 = ((BaseUnityPlugin)this).Config.Bind<int>("General", "itemCost1", 2, new ConfigDescription("Amount of item 1 required to craft the Hearthstone", (AcceptableValueBase)null, new object[1] { (object)new ConfigurationManagerAttributes
		{
			IsAdminOnly = true
		} }));
		item2 = ((BaseUnityPlugin)this).Config.Bind<string>("General", "RecipeItem2", "Coins", new ConfigDescription("Recipe item 2 - leave blank for none", (AcceptableValueBase)null, new object[1] { (object)new ConfigurationManagerAttributes
		{
			IsAdminOnly = true
		} }));
		itemCost2 = ((BaseUnityPlugin)this).Config.Bind<int>("General", "itemCost2", 10, new ConfigDescription("Amount of item 2 required to craft the Hearthstone", (AcceptableValueBase)null, new object[1] { (object)new ConfigurationManagerAttributes
		{
			IsAdminOnly = true
		} }));
		item3 = ((BaseUnityPlugin)this).Config.Bind<string>("General", "RecipeItem3", "Carrot", new ConfigDescription("Recipe item 3 - leave blank for none", (AcceptableValueBase)null, new object[1] { (object)new ConfigurationManagerAttributes
		{
			IsAdminOnly = true
		} }));
		itemCost3 = ((BaseUnityPlugin)this).Config.Bind<int>("General", "itemCost3", 5, new ConfigDescription("Amount of item 3 required to craft the Hearthstone", (AcceptableValueBase)null, new object[1] { (object)new ConfigurationManagerAttributes
		{
			IsAdminOnly = true
		} }));
		writeDebugOutput = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "writeDebugOutput", true, new ConfigDescription("Write debug output?", (AcceptableValueBase)null, new object[1] { (object)new ConfigurationManagerAttributes
		{
			IsAdminOnly = true
		} }));
		allowTeleportWithoutRestriction = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "allowTeleportWithoutRestriction", false, new ConfigDescription("Allow teleport without restriction", (AcceptableValueBase)null, new object[1] { (object)new ConfigurationManagerAttributes
		{
			IsAdminOnly = true
		} }));
		allowTeleportWhileTargeted = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "allowTeleportWhileTargeted", true, new ConfigDescription("Allow teleport while targeted", (AcceptableValueBase)null, new object[1] { (object)new ConfigurationManagerAttributes
		{
			IsAdminOnly = true
		} }));
		allowTeleportWhileEncumbered = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "allowTeleportWhileEncumbered", false, new ConfigDescription("Allow teleport while encumbered", (AcceptableValueBase)null, new object[1] { (object)new ConfigurationManagerAttributes
		{
			IsAdminOnly = true
		} }));
		allowTeleportWhileInWater = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "allowTeleportWhileInWater", false, new ConfigDescription("Allow teleport while in water", (AcceptableValueBase)null, new object[1] { (object)new ConfigurationManagerAttributes
		{
			IsAdminOnly = true
		} }));
		needsToBeResting = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "needsToBeResting", true, new ConfigDescription("Require to be resting to teleport (make a safe campfire and sit around)", (AcceptableValueBase)null, new object[1] { (object)new ConfigurationManagerAttributes
		{
			IsAdminOnly = true
		} }));
		harmony.PatchAll();
		PrefabManager.OnVanillaPrefabsAvailable += AddOrUpdateHearthStoneItem;
		ItemManager.OnItemsRegistered += ItemManager_OnItemsRegistered;
		SynchronizationManager.OnConfigurationSynchronized += SynchronizationManager_OnConfigurationSynchronized;
		SynchronizationManager.OnAdminStatusChanged += SynchronizationManager_OnAdminStatusChanged;
	}

	private void SynchronizationManager_OnAdminStatusChanged()
	{
		Debug(SynchronizationManager.Instance.PlayerIsAdmin ? "No Admin anymore" : "You are admin");
	}

	private void SynchronizationManager_OnConfigurationSynchronized(object sender, ConfigurationSynchronizationEventArgs e)
	{
		Debug(e.InitialSynchronization ? "Recieved Initial Config" : "Updated Config");
		GenerateRecipe();
	}

	private void Update()
	{
		Player localPlayer = Player.m_localPlayer;
		if ((Object)(object)localPlayer == (Object)null)
		{
			return;
		}
		GameObject hoverObject = ((Humanoid)localPlayer).GetHoverObject();
		if (!((Object)(object)hoverObject == (Object)null))
		{
			Interactable componentInParent = hoverObject.GetComponentInParent<Interactable>();
			if (IsOwner && componentInParent is Bed && Input.GetKeyDown((KeyCode)112))
			{
				SetHearthStonePosition();
				((Character)Player.m_localPlayer).Message((MessageType)2, "You have updated your HearthStone location", 0, (Sprite)null);
			}
		}
	}

	private void ItemManager_OnItemsRegistered()
	{
		ItemManager.OnItemsRegistered -= ItemManager_OnItemsRegistered;
		GenerateRecipe();
	}

	private void GenerateRecipe()
	{
		List<Requirement> rqs;
		if ((m_hearthStoneItem != null || m_lastDeathStoneItem != null) && ObjectDB.instance.m_items.Any())
		{
			EnsureRecipe(m_hearthStoneItem, "Recipe_Hearthstone");
			EnsureRecipe(m_lastDeathStoneItem, "Recipe_LastDeathStone");
			rqs = new List<Requirement>();
			AddRq(item1, itemCost1);
			AddRq(item2, itemCost2);
			AddRq(item3, itemCost3);
			CustomItem hearthStoneItem = m_hearthStoneItem;
			object obj;
			if (hearthStoneItem == null)
			{
				obj = null;
			}
			else
			{
				CustomRecipe recipe = hearthStoneItem.Recipe;
				obj = ((recipe != null) ? recipe.Recipe : null);
			}
			if ((Object)obj != (Object)null)
			{
				m_hearthStoneItem.Recipe.Recipe.m_resources = rqs.ToArray();
			}
			CustomItem lastDeathStoneItem = m_lastDeathStoneItem;
			object obj2;
			if (lastDeathStoneItem == null)
			{
				obj2 = null;
			}
			else
			{
				CustomRecipe recipe2 = lastDeathStoneItem.Recipe;
				obj2 = ((recipe2 != null) ? recipe2.Recipe : null);
			}
			if ((Object)obj2 != (Object)null)
			{
				m_lastDeathStoneItem.Recipe.Recipe.m_resources = rqs.ToArray();
			}
		}
		void AddRq(ConfigEntry<string> item, ConfigEntry<int> amount)
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Expected O, but got Unknown
			try
			{
				if (item != null && !string.IsNullOrEmpty(item.Value) && amount.Value > 0)
				{
					ItemDrop component = ObjectDB.instance.GetItemPrefab(item.Value).GetComponent<ItemDrop>();
					if ((Object)(object)component != (Object)null)
					{
						rqs.Add(new Requirement
						{
							m_amount = amount.Value,
							m_resItem = component
						});
					}
				}
			}
			catch (Exception ex)
			{
				Debug(ex.Message);
			}
		}
		static void EnsureRecipe(CustomItem ci, string recipeName)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Expected O, but got Unknown
			if (ci != null && ci.Recipe == null)
			{
				Recipe obj3 = ScriptableObject.CreateInstance<Recipe>();
				((Object)obj3).name = recipeName;
				obj3.m_item = ci.ItemDrop;
				CustomRecipe recipe3 = new CustomRecipe(obj3, true, true)
				{
					FixRequirementReferences = true
				};
				ci.Recipe = recipe3;
			}
		}
	}

	private void AddOrUpdateHearthStoneItem()
	{
		//IL_0079: Unknown result type (might be due to invalid IL or missing references)
		//IL_007e: Unknown result type (might be due to invalid IL or missing references)
		//IL_008a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0095: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00af: Expected O, but got Unknown
		//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c2: Expected O, but got Unknown
		//IL_011b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0125: Expected O, but got Unknown
		//IL_013a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0144: Expected O, but got Unknown
		//IL_01c6: Unknown result type (might be due to invalid IL or missing references)
		//IL_01cb: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e2: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ed: Unknown result type (might be due to invalid IL or missing references)
		//IL_0204: Unknown result type (might be due to invalid IL or missing references)
		//IL_021d: Expected O, but got Unknown
		//IL_0222: Unknown result type (might be due to invalid IL or missing references)
		//IL_022c: Expected O, but got Unknown
		if (m_hearthStoneItem != null)
		{
			return;
		}
		AssetBundle val = AssetUtils.LoadAssetBundleFromResources("hs", typeof(Hearthstone).Assembly);
		if ((Object)(object)val == (Object)null)
		{
			Logger.LogWarning((object)"Bundle could not be loaded!");
			return;
		}
		GameObject val2 = val.LoadAsset<GameObject>("Assets/_Custom/Hearthstone.prefab");
		if ((Object)(object)val2 == (Object)null)
		{
			Logger.LogWarning((object)"Prefab could not be loaded!");
			return;
		}
		ItemDrop component = val2.GetComponent<ItemDrop>();
		SharedData shared = component.m_itemData.m_shared;
		if (shared == null)
		{
			Logger.LogWarning((object)"Shared ItemData could not be loaded!");
			return;
		}
		ItemConfig val3 = new ItemConfig
		{
			Name = shared.m_name,
			Requirements = BuildRequirementConfigs(),
			Icons = shared.m_icons,
			Description = shared.m_description
		};
		m_hearthStoneItem = new CustomItem(val, "Assets/_Custom/Hearthstone.prefab", true, val3);
		ItemManager.Instance.AddItem(m_hearthStoneItem);
		try
		{
			if (m_lastDeathStoneItem == null)
			{
				GameObject val4 = PrefabManager.Instance.CreateClonedPrefab("LastDeathStone", val2);
				ItemDrop component2 = val4.GetComponent<ItemDrop>();
				if ((Object)(object)component2 == (Object)null)
				{
					Debug("LastDeathStone clone has no ItemDrop component!");
					return;
				}
				if (component2.m_itemData == null)
				{
					component2.m_itemData = new ItemData();
				}
				if (component2.m_itemData.m_shared == null)
				{
					component2.m_itemData.m_shared = new SharedData();
				}
				component2.m_itemData.m_dropPrefab = val4;
				if (component2.m_itemData.m_shared.m_icons == null || component2.m_itemData.m_shared.m_icons.Length == 0)
				{
					component2.m_itemData.m_shared.m_icons = component.m_itemData.m_shared.m_icons;
				}
				component2.m_itemData.m_shared.m_name = "Pedra do Último Óbito";
				component2.m_itemData.m_shared.m_description = "Retorna você ao local onde morreu pela última vez.";
				ItemConfig val5 = new ItemConfig
				{
					Name = component2.m_itemData.m_shared.m_name,
					Requirements = BuildRequirementConfigs(),
					Icons = component2.m_itemData.m_shared.m_icons,
					Description = component2.m_itemData.m_shared.m_description
				};
				m_lastDeathStoneItem = new CustomItem(val4, true, val5);
				ItemManager.Instance.AddItem(m_lastDeathStoneItem);
			}
		}
		catch (Exception arg)
		{
			Debug($"Failed to create Last Death Stone: {arg}");
		}
		GenerateRecipe();
	}

	private static RequirementConfig[] BuildRequirementConfigs()
	{
		//IL_0025: Unknown result type (might be due to invalid IL or missing references)
		//IL_002a: 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_004f: Expected O, but got Unknown
		//IL_006e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0073: 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_0098: Expected O, but got Unknown
		//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e1: Expected O, but got Unknown
		List<RequirementConfig> list = new List<RequirementConfig>();
		if (itemCost1.Value > 0 && !string.IsNullOrEmpty(item1.Value))
		{
			list.Add(new RequirementConfig
			{
				Amount = itemCost1.Value,
				Item = item1.Value
			});
		}
		if (itemCost2.Value > 0 && !string.IsNullOrEmpty(item2.Value))
		{
			list.Add(new RequirementConfig
			{
				Amount = itemCost2.Value,
				Item = item2.Value
			});
		}
		if (itemCost3.Value > 0 && !string.IsNullOrEmpty(item3.Value))
		{
			list.Add(new RequirementConfig
			{
				Amount = itemCost3.Value,
				Item = item3.Value
			});
		}
		return list.ToArray();
	}

	private static ZDO GetLocalPlayerZDO()
	{
		try
		{
			ZNetView localPlayerNView = GetLocalPlayerNView();
			if ((Object)(object)localPlayerNView == (Object)null)
			{
				return null;
			}
			return localPlayerNView.GetZDO();
		}
		catch
		{
			return null;
		}
	}

	private static bool TryGetHearthPosFromZDO(out Vector3 pos)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_001f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0024: Unknown result type (might be due to invalid IL or missing references)
		//IL_0029: Unknown result type (might be due to invalid IL or missing references)
		//IL_002f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0034: Unknown result type (might be due to invalid IL or missing references)
		pos = Vector3.zero;
		try
		{
			ZDO localPlayerZDO = GetLocalPlayerZDO();
			if (localPlayerZDO == null)
			{
				return false;
			}
			pos = localPlayerZDO.GetVec3("HS_HearthPos", Vector3.zero);
			return pos != Vector3.zero;
		}
		catch
		{
			return false;
		}
	}

	private static void SetHearthPosToZDO(Vector3 pos)
	{
		//IL_0011: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			ZDO localPlayerZDO = GetLocalPlayerZDO();
			if (localPlayerZDO != null)
			{
				localPlayerZDO.Set("HS_HearthPos", pos);
			}
		}
		catch
		{
		}
	}

	public static Vector3 GetHearthStonePosition()
	{
		//IL_0066: Unknown result type (might be due to invalid IL or missing references)
		//IL_006b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0009: Unknown result type (might be due to invalid IL or missing references)
		//IL_006e: Unknown result type (might be due to invalid IL or missing references)
		//IL_006f: Unknown result type (might be due to invalid IL or missing references)
		//IL_002a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0081: Unknown result type (might be due to invalid IL or missing references)
		//IL_007b: Unknown result type (might be due to invalid IL or missing references)
		//IL_005d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0062: Unknown result type (might be due to invalid IL or missing references)
		if (TryGetHearthPosFromZDO(out var pos))
		{
			return pos;
		}
		CultureInfo provider = new CultureInfo("en-US");
		Vector3 zero = Vector3.zero;
		string hearthStonePositionString = GetHearthStonePositionString();
		if (string.IsNullOrEmpty(hearthStonePositionString))
		{
			return zero;
		}
		string[] array = hearthStonePositionString.Split(new char[1] { '|' });
		try
		{
			zero = new Vector3(float.Parse(array[0], provider), float.Parse(array[1], provider), float.Parse(array[2], provider));
		}
		catch
		{
			zero = Vector3.zero;
		}
		if (zero != Vector3.zero)
		{
			SetHearthPosToZDO(zero);
		}
		return zero;
	}

	private static string GetHearthStonePositionString()
	{
		if (string.IsNullOrEmpty(m_lastPositionString) && File.Exists(PositionFile))
		{
			m_lastPositionString = File.ReadAllText(PositionFile);
		}
		return m_lastPositionString;
	}

	private static void SetHearthStonePosition()
	{
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		//IL_001c: Unknown result type (might be due to invalid IL or missing references)
		Player localPlayer = Player.m_localPlayer;
		if (!((Object)(object)localPlayer == (Object)null))
		{
			Vector3 position = ((Component)localPlayer).transform.position;
			SetHearthPosToZDO(position);
			CultureInfo cultureInfo = new CultureInfo("en-US");
			string text = position.x.ToString(cultureInfo) + "|" + position.y.ToString(cultureInfo) + "|" + position.z.ToString(cultureInfo);
			File.WriteAllText(PositionFile, text);
			m_lastPositionString = text;
		}
	}

	public static Vector3 GetLastDeathPosition()
	{
		//IL_000b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		//IL_0057: 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_001f: Unknown result type (might be due to invalid IL or missing references)
		//IL_005f: Unknown result type (might be due to invalid IL or missing references)
		//IL_004e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0053: Unknown result type (might be due to invalid IL or missing references)
		CultureInfo provider = new CultureInfo("en-US");
		Vector3 zero = Vector3.zero;
		string lastDeathPositionString = GetLastDeathPositionString();
		if (string.IsNullOrEmpty(lastDeathPositionString))
		{
			return zero;
		}
		string[] array = lastDeathPositionString.Split(new char[1] { '|' });
		try
		{
			return new Vector3(float.Parse(array[0], provider), float.Parse(array[1], provider), float.Parse(array[2], provider));
		}
		catch
		{
			return Vector3.zero;
		}
	}

	private static string GetLastDeathPositionString()
	{
		if (string.IsNullOrEmpty(m_lastDeathPositionString) && File.Exists(LastDeathPositionFile))
		{
			m_lastDeathPositionString = File.ReadAllText(LastDeathPositionFile);
		}
		return m_lastDeathPositionString;
	}

	public static void SetLastDeathPosition(Vector3 position)
	{
		CultureInfo cultureInfo = new CultureInfo("en-US");
		string text = position.x.ToString(cultureInfo) + "|" + position.y.ToString(cultureInfo) + "|" + position.z.ToString(cultureInfo);
		File.WriteAllText(LastDeathPositionFile, text);
		m_lastDeathPositionString = text;
	}

	private static bool IsResting(Player p)
	{
		try
		{
			string[] array = new string[4] { "InRestingArea", "InComfortZone", "InShelter", "InSafeZone" };
			foreach (string text in array)
			{
				MethodInfo methodInfo = AccessTools.Method(((object)p).GetType(), text, (Type[])null, (Type[])null);
				if (methodInfo != null && methodInfo.ReturnType == typeof(bool) && methodInfo.GetParameters().Length == 0)
				{
					return (bool)methodInfo.Invoke(p, null);
				}
			}
			return true;
		}
		catch
		{
			return true;
		}
	}

	public static void ClearLastDeathPosition()
	{
		try
		{
			m_lastDeathPositionString = null;
			if (File.Exists(LastDeathPositionFile))
			{
				File.Delete(LastDeathPositionFile);
			}
		}
		catch (Exception ex)
		{
			Debug("Failed to clear last death position: " + ex.Message);
		}
	}
}
internal class Patches
{
	[HarmonyPatch(typeof(Bed), "GetHoverText")]
	private static class Bed_GetHoverText_Patch
	{
		private static void Postfix(Bed __instance, ref string __result, ZNetView ___m_nview)
		{
			if ((Object)(object)Player.m_localPlayer == (Object)null)
			{
				Hearthstone.IsOwner = false;
			}
			else if (___m_nview.GetZDO().GetLong("owner", 0L) == Player.m_localPlayer.GetPlayerID() || __instance.IsCurrent())
			{
				Hearthstone.IsOwner = true;
				__result += "\n[<color=yellow><b>P</b></color>] Set hearthstone";
			}
			else
			{
				Hearthstone.IsOwner = false;
			}
		}
	}

	[HarmonyPatch(typeof(ItemStand), "CanAttach")]
	public static class AttachPatch
	{
		[HarmonyPostfix]
		private static void Postfix(ItemStand __instance, ItemData item, ref bool __result)
		{
			if (!__result)
			{
				string text = item?.m_shared?.m_name;
				if (!string.IsNullOrEmpty(text))
				{
					__result = text == "Hearthstone";
				}
			}
		}
	}
}

BepInEx/plugins/Professions.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using HarmonyLib;
using JetBrains.Annotations;
using Microsoft.CodeAnalysis;
using Professions;
using ServerSync;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("Professions")]
[assembly: AssemblyDescription("https://valheim.thunderstore.io/package/Smoothbrain/Professions")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Professions")]
[assembly: AssemblyCopyright("Copyright ©  2022")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("6A561CBA-69AC-46B3-9095-15E99C3121EC")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

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

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
public class ProfessionPanel : MonoBehaviour
{
	[Header("Stuff To replace")]
	public Image SelectionBKG;

	public Image ContentBkg;

	public Text header;

	public Image linebreak;

	public Text description;

	[Header("Skill Element")]
	public GameObject SkillElementGO;

	public Skill_Element skill_element;

	public RectTransform panelToInstantiateIn;

	public GameObject InstantiateSkill(Sprite icon, string title, string desc, string buttontext)
	{
		GameObject obj = Object.Instantiate<GameObject>(SkillElementGO, (Transform)(object)panelToInstantiateIn);
		Skill_Element component = obj.GetComponent<Skill_Element>();
		component.m_icon.sprite = icon;
		component.m_desc.text = desc;
		component.m_Title.text = title;
		component.buttontxt.text = buttontext;
		return obj;
	}

	public void Awake()
	{
		Transform parent = ((Component)this).transform.parent.parent.parent;
		Image component = ((Component)parent.Find("Menu/MenuRoot/Menu/ornament")).gameObject.GetComponent<Image>();
		Image component2 = ((Component)parent.Find("Inventory_screen/root/Player/Bkg")).gameObject.GetComponent<Image>();
		TMP_FontAsset font = ((TMP_Text)((Component)parent.Find("Inventory_screen/root/Player/Armor/ac_text")).gameObject.GetComponent<TextMeshProUGUI>()).font;
		description.font = font.sourceFontFile;
		header.font = font.sourceFontFile;
		header.text = "Select Profession";
		linebreak.sprite = component.sprite;
		ContentBkg.sprite = component2.sprite;
		((Graphic)ContentBkg).material = ((Graphic)component2).material;
		((Graphic)SelectionBKG).material = ((Graphic)component2).material;
		SelectionBKG.sprite = component2.sprite;
	}
}
public class Skill_Element : MonoBehaviour
{
	[Header("Stuff To replace")]
	public Image m_icon;

	public Text m_Title;

	public Text m_desc;

	public Button Select;

	public Text buttontxt;

	public Image[] configOptions;

	private Text[] _configTexts;

	public global::Professions.Professions.Profession profession;

	public static Sprite blockUsage;

	public static Sprite blockExperience;

	public static GameObject tooltipPrefab;

	public void Awake()
	{
		//IL_0021: Unknown result type (might be due to invalid IL or missing references)
		//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
		//IL_00af: Unknown result type (might be due to invalid IL or missing references)
		//IL_0118: Unknown result type (might be due to invalid IL or missing references)
		//IL_0123: Unknown result type (might be due to invalid IL or missing references)
		//IL_012e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0138: Unknown result type (might be due to invalid IL or missing references)
		Button component = ((Component)((Component)Menu.instance).transform.Find("MenuRoot/ExitConfirm/dialog/Button_yes")).GetComponent<Button>();
		((Selectable)Select).spriteState = ((Selectable)component).spriteState;
		((Selectable)Select).transition = (Transition)2;
		((Component)Select).GetComponent<Image>().sprite = ((Component)component).GetComponent<Image>().sprite;
		Image[] array = configOptions;
		for (int i = 0; i < array.Length; i++)
		{
			((Component)array[i]).GetComponent<UITooltip>().m_tooltipPrefab = tooltipPrefab;
		}
		_configTexts = (Text[])(object)new Text[configOptions.Length];
		for (int j = 0; j < configOptions.Length; j++)
		{
			Image val = configOptions[j];
			((Behaviour)val).enabled = false;
			GameObject val2 = new GameObject("ConfigText");
			val2.transform.SetParent(((Component)val).transform, false);
			Text val3 = val2.AddComponent<Text>();
			val3.font = Resources.GetBuiltinResource<Font>("Arial.ttf");
			val3.alignment = (TextAnchor)4;
			((Graphic)val3).raycastTarget = false;
			val3.text = "";
			val3.resizeTextForBestFit = true;
			val3.resizeTextMinSize = 10;
			val3.resizeTextMaxSize = 30;
			RectTransform rectTransform = ((Graphic)val3).rectTransform;
			rectTransform.anchorMin = Vector2.zero;
			rectTransform.anchorMax = Vector2.one;
			rectTransform.offsetMin = Vector2.zero;
			rectTransform.offsetMax = Vector2.zero;
			_configTexts[j] = val3;
			((Component)val).GetComponent<UITooltip>().m_tooltipPrefab = tooltipPrefab;
		}
	}

	public void UpdateImageDisplay(global::Professions.Professions.ProfessionToggle toggle)
	{
		//IL_0079: Unknown result type (might be due to invalid IL or missing references)
		//IL_007e: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
		//IL_0131: Unknown result type (might be due to invalid IL or missing references)
		int num = 0;
		for (int i = 0; i < configOptions.Length; i++)
		{
			((Component)configOptions[i]).gameObject.SetActive(false);
			if (_configTexts != null && i < _configTexts.Length && (Object)(object)_configTexts[i] != (Object)null)
			{
				_configTexts[i].text = "";
			}
		}
		if (!((Object)(object)Player.m_localPlayer == (Object)null))
		{
			SkillType skillTypeFromProfession = global::Professions.Professions.GetSkillTypeFromProfession(profession);
			bool flag = Helper.getActiveProfessions().Contains(profession);
			float num2 = 0f;
			Dictionary<global::Professions.Professions.Profession, float> inactiveProfessions = Helper.getInactiveProfessions();
			if (inactiveProfessions != null && inactiveProfessions.TryGetValue(profession, out var value) && value > 0f)
			{
				num2 = value;
			}
			float num3 = 0f;
			Skill value2 = null;
			bool flag2 = Player.m_localPlayer.m_skills?.m_skillData != null && Player.m_localPlayer.m_skills.m_skillData.TryGetValue(skillTypeFromProfession, out value2) && value2 != null;
			if (flag2)
			{
				num3 = value2.m_level;
			}
			float num4 = ((!flag && num2 > 0f) ? num2 : ((!flag) ? (flag2 ? num3 : 0f) : (flag2 ? num3 : Player.m_localPlayer.m_skills.GetSkill(skillTypeFromProfession).m_level)));
			int num5 = Mathf.FloorToInt(num4);
			switch (toggle)
			{
			case global::Professions.Professions.ProfessionToggle.BlockUsage:
			{
				UITooltip component2 = ((Component)configOptions[num]).GetComponent<UITooltip>();
				component2.m_text = "If you do not pick this profession, you will not be able to perform these actions.";
				component2.m_topic = "Usage blocked";
				((Component)configOptions[num]).gameObject.SetActive(true);
				_configTexts[num].text = num5.ToString();
				num++;
				break;
			}
			case global::Professions.Professions.ProfessionToggle.BlockExperience:
			{
				UITooltip component = ((Component)configOptions[num]).GetComponent<UITooltip>();
				component.m_text = "If you do not pick this profession, you will still be able to perform these actions, but will not gain experience.";
				component.m_topic = "Experience blocked";
				((Component)configOptions[num]).gameObject.SetActive(true);
				_configTexts[num].text = num5.ToString();
				num++;
				break;
			}
			}
		}
	}

	public void Toggle(bool selected, bool maxProfessionsReached)
	{
		if (selected)
		{
			((Selectable)Select).interactable = global::Professions.Professions.allowUnselect.Value == global::Professions.Professions.Toggle.On;
			buttontxt.text = ((global::Professions.Professions.allowUnselect.Value == global::Professions.Professions.Toggle.On) ? "Unlearn" : "Selected");
		}
		else
		{
			((Selectable)Select).interactable = true;
			buttontxt.text = (maxProfessionsReached ? "Unlock" : "Select");
		}
	}
}
namespace Professions
{
	public static class Blockers
	{
		[HarmonyPatch(typeof(InventoryGui), "UpdateRecipe")]
		private class BlockBlacksmithing
		{
			private static bool CheckBlacksmithingItem(SharedData item)
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				//IL_0007: Unknown result type (might be due to invalid IL or missing references)
				//IL_0009: Unknown result type (might be due to invalid IL or missing references)
				//IL_0047: Expected I4, but got Unknown
				//IL_0053: Unknown result type (might be due to invalid IL or missing references)
				//IL_0059: Invalid comparison between Unknown and I4
				ItemType itemType = item.m_itemType;
				bool flag;
				switch (itemType - 4)
				{
				case 0:
				case 1:
				case 2:
				case 3:
				case 7:
				case 8:
				case 10:
				case 13:
					flag = true;
					break;
				default:
					flag = false;
					break;
				}
				if (!flag)
				{
					if ((int)item.m_itemType == 3)
					{
						return !item.m_attack.m_consumeItem;
					}
					return false;
				}
				return true;
			}

			[HarmonyPriority(0)]
			private static void Postfix(InventoryGui __instance)
			{
				if (__instance.InCraftTab() || __instance.InUpradeTab())
				{
					ItemDrop val = ((RecipeDataPair)(ref __instance.m_selectedRecipe)).Recipe?.m_item;
					if (val != null && CheckBlacksmithingItem(val.m_itemData.m_shared) && !isAllowed(Professions.Profession.Blacksmithing))
					{
						((Selectable)__instance.m_craftButton).interactable = false;
						((TMP_Text)((Component)__instance.m_craftButton).GetComponentInChildren<TextMeshProUGUI>()).text = "You cannot perform this action, because you are not a blacksmith.";
					}
				}
			}
		}

		[HarmonyPatch]
		public static class BlockBlacksmithingSmelter
		{
			private static IEnumerable<MethodInfo> TargetMethods()
			{
				return new MethodInfo[2]
				{
					AccessTools.DeclaredMethod(typeof(Smelter), "OnAddOre", (Type[])null, (Type[])null),
					AccessTools.DeclaredMethod(typeof(Smelter), "OnAddFuel", (Type[])null, (Type[])null)
				};
			}

			private static bool Prefix(Smelter __instance, ref bool __result)
			{
				switch (((Component)__instance).GetComponent<Piece>()?.m_name)
				{
				case "$piece_smelter":
				case "$piece_blastfurnace":
					if (isAllowed(Professions.Profession.Blacksmithing))
					{
						return true;
					}
					__result = false;
					((Character)Player.m_localPlayer).Message((MessageType)2, "You cannot perform this action, because you are not a blacksmith.", 0, (Sprite)null);
					return false;
				case "$piece_windmill":
					if (isAllowed(Professions.Profession.Farming))
					{
						return true;
					}
					__result = false;
					((Character)Player.m_localPlayer).Message((MessageType)2, "You cannot perform this action, because you are not a farmer.", 0, (Sprite)null);
					return false;
				default:
					return true;
				}
			}
		}

		[HarmonyPatch(typeof(PieceTable), "SetCategory")]
		private class BlockBuilding
		{
			private static bool Prefix(int index)
			{
				if ((index != 2 && index != 3) || isAllowed(Professions.Profession.Building))
				{
					return true;
				}
				((Character)Player.m_localPlayer).Message((MessageType)2, "You cannot perform this action, because you are not a builder.", 0, (Sprite)null);
				return false;
			}
		}

		[HarmonyPatch(typeof(PieceTable), "PrevCategory")]
		private class BlockBuildingHotkeyPrev
		{
			private static void Postfix(PieceTable __instance)
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				//IL_0007: Unknown result type (might be due to invalid IL or missing references)
				//IL_0009: Unknown result type (might be due to invalid IL or missing references)
				//IL_000b: Invalid comparison between Unknown and I4
				PieceCategory selectedCategory = __instance.m_selectedCategory;
				bool flag = selectedCategory - 2 <= 1;
				if (flag && !isAllowed(Professions.Profession.Building))
				{
					__instance.PrevCategory();
				}
			}
		}

		[HarmonyPatch(typeof(PieceTable), "NextCategory")]
		private class BlockBuildingHotkeyNext
		{
			private static void Postfix(PieceTable __instance)
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				//IL_0007: Unknown result type (might be due to invalid IL or missing references)
				//IL_0009: Unknown result type (might be due to invalid IL or missing references)
				//IL_000b: Invalid comparison between Unknown and I4
				PieceCategory selectedCategory = __instance.m_selectedCategory;
				bool flag = selectedCategory - 2 <= 1;
				if (flag && !isAllowed(Professions.Profession.Building))
				{
					__instance.NextCategory();
				}
			}
		}

		[HarmonyPatch(typeof(InventoryGui), "UpdateRecipe")]
		private class BlockCookingCrafting
		{
			[HarmonyPriority(0)]
			private static void Postfix(InventoryGui __instance)
			{
				ItemDrop val = ((RecipeDataPair)(ref __instance.m_selectedRecipe)).Recipe?.m_item;
				if (val == null)
				{
					return;
				}
				if (!(val.m_itemData.m_shared.m_food > 0f) || !(val.m_itemData.m_shared.m_foodStamina > 0f))
				{
					ItemDrop appendToolTip = val.m_itemData.m_shared.m_appendToolTip;
					if (!Object.op_Implicit((Object)(object)((appendToolTip != null) ? ((Component)appendToolTip).GetComponent<Feast>() : null)))
					{
						return;
					}
				}
				if (!isAllowed(Professions.Profession.Cooking))
				{
					((Selectable)__instance.m_craftButton).interactable = false;
					((TMP_Text)((Component)__instance.m_craftButton).GetComponentInChildren<TextMeshProUGUI>()).text = "You cannot perform this action, because you are not a cook.";
				}
			}
		}

		[HarmonyPatch(typeof(CookingStation), "Interact")]
		private class BlockCookingStation
		{
			private static bool Prefix()
			{
				if (isAllowed(Professions.Profession.Cooking))
				{
					return true;
				}
				((Character)Player.m_localPlayer).Message((MessageType)2, "You cannot perform this action, because you are not a cook.", 0, (Sprite)null);
				return false;
			}
		}

		[HarmonyPatch(typeof(ItemData), "IsEquipable")]
		private class BlockFarmingCultivator
		{
			private static void Postfix(ItemData __instance, ref bool __result)
			{
				if (__instance.m_shared.m_name == "$item_cultivator" && !isAllowed(Professions.Profession.Farming))
				{
					__result = false;
				}
			}
		}

		[HarmonyPatch(typeof(Pickable), "Interact")]
		private class BlockFarmingPickingPlants
		{
			private static bool Prefix(Pickable __instance)
			{
				if (!__instance.m_nview.GetZDO().GetBool("Farming Custom Grown", false) || isAllowed(Professions.Profession.Farming))
				{
					return true;
				}
				((Character)Player.m_localPlayer).Message((MessageType)2, "You cannot perform this action, because you are not a farmer.", 0, (Sprite)null);
				return false;
			}
		}

		[HarmonyPatch(typeof(Plant), "Grow")]
		private class SaveCustomGrownPlantState
		{
			[CompilerGenerated]
			private sealed class <Transpiler>d__1 : IEnumerable<CodeInstruction>, IEnumerable, IEnumerator<CodeInstruction>, IDisposable, IEnumerator
			{
				private int <>1__state;

				private CodeInstruction <>2__current;

				private int <>l__initialThreadId;

				private IEnumerable<CodeInstruction> instructions;

				public IEnumerable<CodeInstruction> <>3__instructions;

				private MethodInfo <transferInfo>5__2;

				private MethodInfo <instantiator>5__3;

				private IEnumerator<CodeInstruction> <>7__wrap3;

				private CodeInstruction <instruction>5__5;

				CodeInstruction IEnumerator<CodeInstruction>.Current
				{
					[DebuggerHidden]
					get
					{
						return <>2__current;
					}
				}

				object IEnumerator.Current
				{
					[DebuggerHidden]
					get
					{
						return <>2__current;
					}
				}

				[DebuggerHidden]
				public <Transpiler>d__1(int <>1__state)
				{
					this.<>1__state = <>1__state;
					<>l__initialThreadId = Environment.CurrentManagedThreadId;
				}

				[DebuggerHidden]
				void IDisposable.Dispose()
				{
					int num = <>1__state;
					if (num == -3 || (uint)(num - 1) <= 1u)
					{
						try
						{
						}
						finally
						{
							<>m__Finally1();
						}
					}
					<transferInfo>5__2 = null;
					<instantiator>5__3 = null;
					<>7__wrap3 = null;
					<instruction>5__5 = null;
					<>1__state = -2;
				}

				private bool MoveNext()
				{
					//IL_011b: Unknown result type (might be due to invalid IL or missing references)
					//IL_0125: Expected O, but got Unknown
					try
					{
						switch (<>1__state)
						{
						default:
							return false;
						case 0:
							<>1__state = -1;
							<transferInfo>5__2 = AccessTools.DeclaredMethod(typeof(SaveCustomGrownPlantState), "TransferInfo", (Type[])null, (Type[])null);
							<instantiator>5__3 = typeof(Object).GetMethods().First((MethodInfo m) => m.Name == "Instantiate" && m.IsGenericMethodDefinition && (from p in m.GetParameters().Skip(1)
								select p.ParameterType).SequenceEqual(new Type[2]
							{
								typeof(Vector3),
								typeof(Quaternion)
							})).MakeGenericMethod(typeof(GameObject));
							<>7__wrap3 = instructions.GetEnumerator();
							<>1__state = -3;
							break;
						case 1:
							<>1__state = -3;
							if (<instruction>5__5.opcode == OpCodes.Call && CodeInstructionExtensions.OperandIs(<instruction>5__5, (MemberInfo)<instantiator>5__3))
							{
								<>2__current = new CodeInstruction(OpCodes.Call, (object)<transferInfo>5__2);
								<>1__state = 2;
								return true;
							}
							goto IL_0138;
						case 2:
							{
								<>1__state = -3;
								goto IL_0138;
							}
							IL_0138:
							<instruction>5__5 = null;
							break;
						}
						if (<>7__wrap3.MoveNext())
						{
							<instruction>5__5 = <>7__wrap3.Current;
							<>2__current = <instruction>5__5;
							<>1__state = 1;
							return true;
						}
						<>m__Finally1();
						<>7__wrap3 = null;
						return false;
					}
					catch
					{
						//try-fault
						((IDisposable)this).Dispose();
						throw;
					}
				}

				bool IEnumerator.MoveNext()
				{
					//ILSpy generated this explicit interface implementation from .override directive in MoveNext
					return this.MoveNext();
				}

				private void <>m__Finally1()
				{
					<>1__state = -1;
					if (<>7__wrap3 != null)
					{
						<>7__wrap3.Dispose();
					}
				}

				[DebuggerHidden]
				void IEnumerator.Reset()
				{
					throw new NotSupportedException();
				}

				[DebuggerHidden]
				IEnumerator<CodeInstruction> IEnumerable<CodeInstruction>.GetEnumerator()
				{
					<Transpiler>d__1 <Transpiler>d__;
					if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId)
					{
						<>1__state = 0;
						<Transpiler>d__ = this;
					}
					else
					{
						<Transpiler>d__ = new <Transpiler>d__1(0);
					}
					<Transpiler>d__.instructions = <>3__instructions;
					return <Transpiler>d__;
				}

				[DebuggerHidden]
				IEnumerator IEnumerable.GetEnumerator()
				{
					return ((IEnumerable<CodeInstruction>)this).GetEnumerator();
				}
			}

			private static GameObject TransferInfo(GameObject pickable)
			{
				pickable.GetComponent<ZNetView>().GetZDO().Set("Farming Custom Grown", true);
				return pickable;
			}

			[IteratorStateMachine(typeof(<Transpiler>d__1))]
			private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
			{
				//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
				return new <Transpiler>d__1(-2)
				{
					<>3__instructions = instructions
				};
			}
		}

		[HarmonyPatch]
		public static class BlockLumberjacking
		{
			private static IEnumerable<MethodInfo> TargetMethods()
			{
				return new MethodInfo[3]
				{
					AccessTools.DeclaredMethod(typeof(TreeLog), "Damage", (Type[])null, (Type[])null),
					AccessTools.DeclaredMethod(typeof(TreeBase), "Damage", (Type[])null, (Type[])null),
					AccessTools.DeclaredMethod(typeof(Destructible), "Damage", (Type[])null, (Type[])null)
				};
			}

			private static void Prefix(object __instance, HitData hit)
			{
				//IL_0025: Unknown result type (might be due to invalid IL or missing references)
				//IL_002b: Invalid comparison between Unknown and I4
				if (isAllowed(Professions.Profession.Lumberjacking) || !((Object)(object)hit.GetAttacker() == (Object)(object)Player.m_localPlayer))
				{
					return;
				}
				Destructible val = (Destructible)((__instance is Destructible) ? __instance : null);
				if (val == null || (int)val.m_destructibleType == 2)
				{
					if (!(__instance is TreeLog) && !(__instance is TreeBase))
					{
						hit.m_damage.m_slash = 0f;
					}
					((Character)Player.m_localPlayer).Message((MessageType)2, "You cannot perform this action, because you are not a lumberjack.", 0, (Sprite)null);
					hit.m_damage.m_chop = 0f;
				}
			}
		}

		[HarmonyPatch]
		public static class BlockMining
		{
			private static IEnumerable<MethodInfo> TargetMethods()
			{
				return new MethodInfo[3]
				{
					AccessTools.DeclaredMethod(typeof(MineRock), "Damage", (Type[])null, (Type[])null),
					AccessTools.DeclaredMethod(typeof(MineRock5), "Damage", (Type[])null, (Type[])null),
					AccessTools.DeclaredMethod(typeof(Destructible), "Damage", (Type[])null, (Type[])null)
				};
			}

			private static void Prefix(object __instance, HitData hit)
			{
				//IL_0025: Unknown result type (might be due to invalid IL or missing references)
				//IL_002a: Unknown result type (might be due to invalid IL or missing references)
				//IL_002b: 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_0032: Invalid comparison between Unknown and I4
				//IL_0034: Unknown result type (might be due to invalid IL or missing references)
				//IL_0035: Unknown result type (might be due to invalid IL or missing references)
				//IL_003d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0043: Invalid comparison between Unknown and I4
				if (isAllowed(Professions.Profession.Mining) || !((Object)(object)hit.GetAttacker() == (Object)(object)Player.m_localPlayer))
				{
					return;
				}
				Destructible val = (Destructible)((__instance is Destructible) ? __instance : null);
				if (val != null)
				{
					DamageModifiers damages = val.m_damages;
					if ((int)damages.m_pickaxe <= 0 || (int)damages.m_chop != 0 || (int)val.m_destructibleType == 2)
					{
						return;
					}
				}
				((Character)Player.m_localPlayer).Message((MessageType)2, "You cannot perform this action, because you are not a miner.", 0, (Sprite)null);
				hit.m_damage.m_pickaxe = 0f;
			}
		}

		[HarmonyPatch(typeof(Character), "Damage")]
		private class BlockRanching
		{
			private static bool Prefix(Character __instance, HitData hit)
			{
				if (!__instance.IsTamed() || isAllowed(Professions.Profession.Ranching) || (Object)(object)hit.GetAttacker() != (Object)(object)Player.m_localPlayer)
				{
					return true;
				}
				((Character)Player.m_localPlayer).Message((MessageType)2, "You cannot perform this action, because you are not a rancher.", 0, (Sprite)null);
				return false;
			}
		}

		[HarmonyPatch(typeof(ShipControlls), "Interact")]
		private class BlockSailing
		{
			private static bool Prefix()
			{
				if (isAllowed(Professions.Profession.Sailing))
				{
					return true;
				}
				((Character)Player.m_localPlayer).Message((MessageType)2, "You cannot perform this action, because you are not a sailor.", 0, (Sprite)null);
				return false;
			}
		}

		[HarmonyPatch(typeof(CraftingStation), "Interact")]
		private class BlockAlchemyStation
		{
			private static bool Prefix(CraftingStation __instance)
			{
				if (!((Object)__instance).name.StartsWith("opalchemy", StringComparison.Ordinal) || isAllowed(Professions.Profession.Alchemy))
				{
					return true;
				}
				((Character)Player.m_localPlayer).Message((MessageType)2, "You cannot perform this action, because you are not an alchemist.", 0, (Sprite)null);
				return false;
			}
		}

		[HarmonyPatch(typeof(Incinerator), "OnIncinerate")]
		private class BlockAlchemyIncinerator
		{
			private static bool Prefix(Incinerator __instance)
			{
				if (!((Object)__instance).name.StartsWith("opcauldron", StringComparison.Ordinal) || isAllowed(Professions.Profession.Alchemy))
				{
					return true;
				}
				((Character)Player.m_localPlayer).Message((MessageType)2, "You cannot perform this action, because you are not an alchemist.", 0, (Sprite)null);
				return false;
			}
		}

		[HarmonyPatch(typeof(CraftingStation), "Interact")]
		private class BlockGemcuttersTable
		{
			private static bool Prefix(CraftingStation __instance)
			{
				if (!((Object)__instance).name.StartsWith("op_transmution_table", StringComparison.Ordinal) || isAllowed(Professions.Profession.Jewelcrafting))
				{
					return true;
				}
				((Character)Player.m_localPlayer).Message((MessageType)2, "You cannot perform this action, because you are not a jeweler.", 0, (Sprite)null);
				return false;
			}
		}

		[HarmonyPatch(typeof(Pickable), "Interact")]
		private class BlockForaging
		{
			private class SkipForagingException : Exception
			{
			}

			[HarmonyPriority(800)]
			private static void Prefix(Pickable __instance)
			{
				if (__instance.m_respawnTimeMinutes == 0f || ((Object)__instance.m_itemPrefab).name == "Wood" || isAllowed(Professions.Profession.Foraging))
				{
					return;
				}
				((Character)Player.m_localPlayer).Message((MessageType)2, "You cannot perform this action, because you are not a forager.", 0, (Sprite)null);
				throw new SkipForagingException();
			}

			private static Exception? Finalizer(Exception __exception)
			{
				if (!(__exception is SkipForagingException))
				{
					return __exception;
				}
				return null;
			}
		}

		[HarmonyPatch(typeof(Minimap), "Explore", new Type[]
		{
			typeof(Vector3),
			typeof(float)
		})]
		private class BlockExploration
		{
			[HarmonyPriority(800)]
			private static bool Prefix()
			{
				return isAllowed(Professions.Profession.Exploration);
			}
		}

		private static bool isAllowed(Professions.Profession profession)
		{
			if (Professions.blockOtherProfessions[profession].Value == Professions.ProfessionToggle.BlockUsage)
			{
				return Helper.getActiveProfessions().Contains(profession);
			}
			return true;
		}
	}
	public static class Helper
	{
		private static byte[] ReadEmbeddedFileBytes(string name)
		{
			using MemoryStream memoryStream = new MemoryStream();
			Assembly.GetExecutingAssembly().GetManifestResourceStream("Professions." + name)?.CopyTo(memoryStream);
			return memoryStream.ToArray();
		}

		private static Texture2D loadTexture(string name)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Expected O, but got Unknown
			return new Texture2D(1, 1);
		}

		public static Sprite loadSprite(string name, int width, int height)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			return Sprite.Create(loadTexture(name), new Rect(0f, 0f, (float)width, (float)height), Vector2.zero);
		}

		public static string getHumanFriendlyTime(int seconds)
		{
			TimeSpan timeSpan = TimeSpan.FromSeconds(seconds);
			if (timeSpan.TotalSeconds < 60.0)
			{
				return "less than 1 minute";
			}
			string text = "";
			if (timeSpan.TotalDays >= 1.0)
			{
				text = text + $"{(int)timeSpan.TotalDays} day" + ((timeSpan.TotalDays >= 2.0) ? "s" : "");
			}
			if (timeSpan.Hours >= 1)
			{
				if (timeSpan.TotalDays >= 1.0)
				{
					text += " and ";
				}
				text = text + $"{timeSpan.Hours} hour" + ((timeSpan.Hours >= 2) ? "s" : "");
			}
			if (timeSpan.Minutes >= 1)
			{
				if (timeSpan.TotalDays >= 1.0 || timeSpan.Hours >= 1)
				{
					text += " and ";
				}
				text = text + $"{timeSpan.Minutes} minute" + ((timeSpan.Minutes >= 2) ? "s" : "");
			}
			return text;
		}

		public static HashSet<Professions.Profession> getActiveProfessions()
		{
			HashSet<Professions.Profession> hashSet = new HashSet<Professions.Profession>();
			if (Player.m_localPlayer.m_customData.TryGetValue("Professions Active", out var value))
			{
				string[] array = value.Split(new char[1] { ',' });
				for (int i = 0; i < array.Length; i++)
				{
					if (Enum.TryParse<Professions.Profession>(array[i], out var result))
					{
						hashSet.Add(result);
					}
				}
			}
			return hashSet;
		}

		public static Dictionary<Professions.Profession, float> getInactiveProfessions()
		{
			Dictionary<Professions.Profession, float> dictionary = ((Professions.Profession[])Enum.GetValues(typeof(Professions.Profession))).ToDictionary((Professions.Profession p) => p, (Professions.Profession _) => 0f);
			foreach (Professions.Profession activeProfession in getActiveProfessions())
			{
				dictionary.Remove(activeProfession);
			}
			if (Player.m_localPlayer.m_customData.TryGetValue("Professions Inactive", out var value))
			{
				string[] array = value.Split(new char[1] { ',' });
				for (int i = 0; i < array.Length; i++)
				{
					string[] array2 = array[i].Split(new char[1] { ':' });
					if (Enum.TryParse<Professions.Profession>(array2[0], out var result))
					{
						float result2 = 0f;
						if (array2.Length > 1)
						{
							float.TryParse(array2[1], NumberStyles.Float, CultureInfo.InvariantCulture, out result2);
						}
						dictionary[result] = result2;
					}
				}
			}
			return dictionary;
		}

		public static void storeActiveProfessions(HashSet<Professions.Profession> professions)
		{
			if (professions.Count == 0)
			{
				Player.m_localPlayer.m_customData.Remove("Professions Active");
				return;
			}
			Player.m_localPlayer.m_customData["Professions Active"] = string.Join(",", professions.Select((Professions.Profession p) => p.ToString()));
		}

		public static void storeInactiveProfessions(Dictionary<Professions.Profession, float> professions)
		{
			if (professions.Count((KeyValuePair<Professions.Profession, float> kv) => kv.Value > 0f) == 0)
			{
				Player.m_localPlayer.m_customData.Remove("Professions Inactive");
				return;
			}
			Player.m_localPlayer.m_customData["Professions Inactive"] = string.Join(",", from kv in professions
				where kv.Value > 0f
				select $"{kv.Key}:{kv.Value.ToString(CultureInfo.InvariantCulture)}");
		}
	}
	[BepInPlugin("org.bepinex.plugins.professions", "Professions", "1.4.5")]
	[BepInIncompatibility("org.bepinex.plugins.valheim_plus")]
	public class Professions : BaseUnityPlugin
	{
		public enum Toggle
		{
			On = 1,
			Off = 0
		}

		public enum ProfessionToggle
		{
			Ignored,
			BlockExperience,
			BlockUsage
		}

		public enum Profession
		{
			Blacksmithing,
			Building,
			Cooking,
			Farming,
			Lumberjacking,
			Mining,
			Ranching,
			Sailing,
			Alchemy,
			Jewelcrafting,
			Foraging,
			Exploration
		}

		private class ConfigurationManagerAttributes
		{
			[UsedImplicitly]
			public bool? Browsable;

			[UsedImplicitly]
			public int? Order;
		}

		[HarmonyPatch(typeof(ZNet), "OnNewConnection")]
		private static class AddRPCs
		{
			[CompilerGenerated]
			private static class <>O
			{
				public static Method <0>__onServerTimeRequest;

				public static Action<ZRpc, long> <1>__onServerTimeReceived;
			}

			private static void Postfix(ZNet __instance, ZNetPeer peer)
			{
				//IL_0023: Unknown result type (might be due to invalid IL or missing references)
				//IL_0028: Unknown result type (might be due to invalid IL or missing references)
				//IL_002e: Expected O, but got Unknown
				if (__instance.IsServer())
				{
					ZRpc rpc = peer.m_rpc;
					object obj = <>O.<0>__onServerTimeRequest;
					if (obj == null)
					{
						Method val = onServerTimeRequest;
						<>O.<0>__onServerTimeRequest = val;
						obj = (object)val;
					}
					rpc.Register("Professions GetServerTime", (Method)obj);
				}
				else
				{
					peer.m_rpc.Register<long>("Professions GetServerTime", (Action<ZRpc, long>)onServerTimeReceived);
				}
			}
		}

		[HarmonyPatch(typeof(Menu), "Update")]
		private class PreventMainMenu
		{
			public static bool AllowMainMenu = true;

			private static bool Prefix()
			{
				if (!professionPanelInstance.activeSelf)
				{
					return AllowMainMenu;
				}
				return false;
			}
		}

		[HarmonyPatch(typeof(Hud), "Awake")]
		public static class InstantiateSelectPanel
		{
			private static void Prefix(Hud __instance)
			{
				Transform transform = __instance.m_rootObject.transform;
				professionPanelInstance = Object.Instantiate<GameObject>(professionPanel, transform, false);
				professionPanelInstance.SetActive(false);
				professionPanelInstance.transform.SetSiblingIndex(((Component)MessageHud.instance).transform.GetSiblingIndex());
				Skill_Element.tooltipPrefab = InventoryGui.instance.m_playerGrid.m_elementPrefab.GetComponent<UITooltip>().m_tooltipPrefab;
			}
		}

		[HarmonyPatch(typeof(Skills), "Awake")]
		public static class PopulateSelectPanel
		{
			private static void Postfix(Skills __instance)
			{
				//IL_008a: Unknown result type (might be due to invalid IL or missing references)
				//IL_008f: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
				//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
				//IL_00fd: 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_019b: Expected O, but got Unknown
				//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
				Skills __instance2 = __instance;
				if (!Object.op_Implicit((Object)(object)Professions.professionPanelInstance))
				{
					return;
				}
				GameObject? professionPanelInstance = Professions.professionPanelInstance;
				ProfessionPanel professionPanel = ((professionPanelInstance != null) ? professionPanelInstance.GetComponent<ProfessionPanel>() : null);
				if (professionPanel == null || ((Transform)professionPanel.panelToInstantiateIn).childCount != 0)
				{
					return;
				}
				professionPanelElements.Clear();
				Profession[] array = (Profession[])Enum.GetValues(typeof(Profession));
				foreach (Profession profession in array)
				{
					SkillType skillType = fromProfession(profession);
					Skill skill = __instance2.GetSkill(skillType);
					if (skill.m_info == null)
					{
						__instance2.m_skillData.Remove(skillType);
						continue;
					}
					Sprite icon = skill.m_info.m_icon;
					Localization instance = Localization.instance;
					SkillType val = fromProfession(profession);
					GameObject val2 = professionPanel.InstantiateSkill(icon, instance.Localize(("$skill_" + ((object)(SkillType)(ref val)).ToString()).ToLowerInvariant()), professionDescriptions[profession], "Select");
					professionPanelElements[profession] = val2;
					val2.SetActive(blockOtherProfessions[profession].Value != ProfessionToggle.Ignored);
					Skill_Element component = val2.GetComponent<Skill_Element>();
					component.profession = profession;
					((UnityEvent)component.Select.onClick).AddListener((UnityAction)delegate
					{
						//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
						//IL_0112: Unknown result type (might be due to invalid IL or missing references)
						//IL_033e: Unknown result type (might be due to invalid IL or missing references)
						//IL_030b: Unknown result type (might be due to invalid IL or missing references)
						//IL_0279: Unknown result type (might be due to invalid IL or missing references)
						//IL_027e: Unknown result type (might be due to invalid IL or missing references)
						//IL_02a2: Unknown result type (might be due to invalid IL or missing references)
						//IL_02a7: Unknown result type (might be due to invalid IL or missing references)
						if (Helper.getActiveProfessions().Contains(profession))
						{
							if (allowUnselect.Value == Toggle.On && professionChangeCooldown.Value > 0f && Player.m_localPlayer.m_customData.TryGetValue("Professions LastProfessionChange", out var value))
							{
								int num = int.Parse(value) + (int)(professionChangeCooldown.Value * 3600f) - (int)((DateTimeOffset)serverTime).ToUnixTimeSeconds();
								if (num > 0)
								{
									((Character)Player.m_localPlayer).Message((MessageType)2, "You can change your profession in " + Helper.getHumanFriendlyTime(num) + ".", 0, (Sprite)null);
									return;
								}
							}
							Dictionary<Profession, float> inactiveProfessions = Helper.getInactiveProfessions();
							float level = __instance2.GetSkill(skillType).m_level;
							float value2 = ((resetLevelOnUnselect.Value == Toggle.On) ? (level * 0.5f) : level);
							inactiveProfessions[profession] = value2;
							Helper.storeInactiveProfessions(inactiveProfessions);
							HashSet<Profession> activeProfessions = Helper.getActiveProfessions();
							activeProfessions.Remove(profession);
							Helper.storeActiveProfessions(activeProfessions);
							Player.m_localPlayer.m_skills.m_skillData.Remove(skillType);
							Player.m_localPlayer.m_customData["Professions LastProfessionChange"] = ((DateTimeOffset)serverTime).ToUnixTimeSeconds().ToString();
						}
						else
						{
							if (!Player.m_localPlayer.m_knownStations.TryGetValue("Professions extraProfessionsSlots", out var value3))
							{
								Player.m_localPlayer.m_knownStations["Professions extraProfessionsSlots"] = 0;
								value3 = 0;
							}
							HashSet<Profession> hashSet = Helper.getActiveProfessions() ?? new HashSet<Profession>();
							int num2 = maximumAllowedProfessions.Value + value3;
							if (!hashSet.Contains(profession) && hashSet.Count >= num2)
							{
								Inventory inventory = ((Humanoid)Player.m_localPlayer).GetInventory();
								if (inventory == null)
								{
									return;
								}
								int num3 = RequiredTrophies(num2);
								ItemData val3 = FindItemBySharedName(inventory, "craftsman trophy", num3);
								if (val3 == null)
								{
									((Character)Player.m_localPlayer).Message((MessageType)2, $"You need Craftsman Trophy x {num3:#}.", 0, (Sprite)null);
									return;
								}
								for (int j = 0; j < num3; j++)
								{
									((Humanoid)Player.m_localPlayer).GetInventory().RemoveOneItem(val3);
								}
								Player.m_localPlayer.StartEmote("cheer", true);
								((Character)Player.m_localPlayer).Message((MessageType)2, $"Consumed Craftsman Trophy x {num3:#}.", 0, (Sprite)null);
								Object.Instantiate<GameObject>(ZNetScene.instance.GetPrefab("vfx_Potion_stamina_medium"), ((Component)Player.m_localPlayer).transform.position, Quaternion.identity);
								Object.Instantiate<GameObject>(ZNetScene.instance.GetPrefab("vfx_WishbonePing"), ((Component)Player.m_localPlayer).transform.position, Quaternion.identity);
								Player.m_localPlayer.m_knownStations["Professions extraProfessionsSlots"] = value3 + 1;
								value3++;
								num2 = maximumAllowedProfessions.Value + value3;
							}
							Dictionary<Profession, float> dictionary = Helper.getInactiveProfessions() ?? new Dictionary<Profession, float>();
							if (dictionary.TryGetValue(profession, out var value4))
							{
								Player.m_localPlayer.m_skills.GetSkill(skillType).m_level = value4;
								dictionary.Remove(profession);
								Helper.storeInactiveProfessions(dictionary);
							}
							else
							{
								Player.m_localPlayer.m_skills.GetSkill(skillType).m_level = 1f;
							}
							hashSet.Add(profession);
							Helper.storeActiveProfessions(hashSet);
						}
						UpdateSelectPanelSelections();
					});
				}
			}
		}

		[HarmonyPatch(typeof(Skills), "RaiseSkill")]
		private class PreventExperience
		{
			private static bool Prefix(SkillType skillType)
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				Profession? profession = fromSkill(skillType);
				if (profession.HasValue)
				{
					Profession valueOrDefault = profession.GetValueOrDefault();
					if (!Helper.getActiveProfessions().Contains(valueOrDefault))
					{
						return blockOtherProfessions[valueOrDefault].Value == ProfessionToggle.Ignored;
					}
				}
				return true;
			}
		}

		[HarmonyPatch]
		private class DisablePlayerInputInProfessionMenu
		{
			private static IEnumerable<MethodInfo> TargetMethods()
			{
				return new MethodInfo[2]
				{
					AccessTools.DeclaredMethod(typeof(StoreGui), "IsVisible", (Type[])null, (Type[])null),
					AccessTools.DeclaredMethod(typeof(TextInput), "IsVisible", (Type[])null, (Type[])null)
				};
			}

			private static void Postfix(ref bool __result)
			{
				GameObject? professionPanelInstance = Professions.professionPanelInstance;
				if (professionPanelInstance != null && professionPanelInstance.activeSelf)
				{
					__result = true;
				}
			}
		}

		private const string ModName = "Professions";

		private const string ModVersion = "1.4.5";

		private const string ModGUID = "org.bepinex.plugins.professions";

		private static readonly ConfigSync configSync = new ConfigSync("org.bepinex.plugins.professions")
		{
			DisplayName = "Professions",
			CurrentVersion = "1.4.5",
			MinimumRequiredVersion = "1.4.5"
		};

		private static ConfigEntry<Toggle> serverConfigLocked = null;

		private static ConfigEntry<KeyboardShortcut> professionPanelHotkey = null;

		private static ConfigEntry<int> maximumAllowedProfessions = null;

		public static ConfigEntry<Toggle> allowUnselect = null;

		private static ConfigEntry<Toggle> resetLevelOnUnselect = null;

		private static ConfigEntry<float> professionChangeCooldown = null;

		public static readonly Dictionary<Profession, ConfigEntry<ProfessionToggle>> blockOtherProfessions = new Dictionary<Profession, ConfigEntry<ProfessionToggle>>();

		private static DateTime serverTime = DateTime.Now;

		private int configOrder;

		private static readonly Dictionary<Profession, string> professionDescriptions = new Dictionary<Profession, string>
		{
			{
				Profession.Blacksmithing,
				"A blacksmith uses the smelter and forge to smelt ore and craft armor and weapons."
			},
			{
				Profession.Building,
				"A builder uses the hammer to construct floors, walls and roofs for shelter."
			},
			{
				Profession.Cooking,
				"A cook creates lavish meals."
			},
			{
				Profession.Farming,
				"A farmer uses the cultivator to cultivate land to plant crops and harvest them."
			},
			{
				Profession.Lumberjacking,
				"A lumberjack uses an axe to cut trees to collect all kind of woods."
			},
			{
				Profession.Mining,
				"A miner uses a pickaxe to mine stone and ore."
			},
			{
				Profession.Ranching,
				"A rancher can tame certain animals and breed them for their meat."
			},
			{
				Profession.Sailing,
				"A sailor uses ships to explore the vast ocean and discover new islands."
			},
			{
				Profession.Alchemy,
				"An alchemist creates powerful potions, flasks and elixirs."
			},
			{
				Profession.Jewelcrafting,
				"A jeweler cuts powerful magic gems and adds sockets to equipment."
			},
			{
				Profession.Foraging,
				"A forager collects berries and mushrooms."
			},
			{
				Profession.Exploration,
				"An explorer explores the world and searches treasure chests."
			}
		};

		private static GameObject professionPanel = null;

		private static GameObject? professionPanelInstance;

		private static readonly Dictionary<Profession, GameObject> professionPanelElements = new Dictionary<Profession, GameObject>();

		private readonly Assembly? bepinexConfigManager = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault((Assembly a) => a.GetName().Name == "ConfigurationManager");

		private ConfigEntry<T> config<T>(string group, string name, T value, ConfigDescription description, bool synchronizedSetting = true)
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Expected O, but got Unknown
			description = new ConfigDescription(description.Description, description.AcceptableValues, CollectionExtensions.AddItem<object>((IEnumerable<object>)description.Tags, (object)new ConfigurationManagerAttributes
			{
				Order = configOrder--
			}).ToArray());
			ConfigEntry<T> val = ((BaseUnityPlugin)this).Config.Bind<T>(group, name, value, description);
			configSync.AddConfigEntry<T>(val).SynchronizedConfig = synchronizedSetting;
			return val;
		}

		private ConfigEntry<T> config<T>(string group, string name, T value, string description, bool synchronizedSetting = true)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Expected O, but got Unknown
			return config(group, name, value, new ConfigDescription(description, (AcceptableValueBase)null, Array.Empty<object>()), synchronizedSetting);
		}

		private static SkillType fromProfession(Profession profession)
		{
			//IL_000c: 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_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			return (SkillType)(profession switch
			{
				Profession.Cooking => 105, 
				Profession.Farming => 106, 
				_ => Math.Abs(StringExtensionMethods.GetStableHashCode(profession.ToString())), 
			});
		}

		private static Profession? fromSkill(SkillType skill)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			return ((IEnumerable<Profession>)(Profession[])Enum.GetValues(typeof(Profession))).Select((Func<Profession, Profession?>)((Profession p) => p)).FirstOrDefault((Profession? p) => skill == fromProfession(p.Value));
		}

		public void Awake()
		{
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Expected O, but got Unknown
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Expected O, but got Unknown
			//IL_014e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0159: Expected O, but got Unknown
			//IL_0170: Unknown result type (might be due to invalid IL or missing references)
			//IL_0220: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Type configManagerType = bepinexConfigManager?.GetType("ConfigurationManager.ConfigurationManager");
				object configManager = ((configManagerType == null) ? null : Chainloader.ManagerObject.GetComponent(configManagerType));
				serverConfigLocked = config("1 - General", "Lock Configuration", Toggle.On, "If on, the configuration is locked and can be changed by server admins only.");
				configSync.AddLockingConfigEntry<Toggle>(serverConfigLocked);
				maximumAllowedProfessions = config("1 - General", "Maximum Number of Professions", 1, new ConfigDescription("Sets the maximum number of professions a player is allowed to have at the same time.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 5), Array.Empty<object>()));
				allowUnselect = config("1 - General", "Allow Profession Change", Toggle.Off, "If on, players can unselect professions and select new ones.");
				ConfigurationManagerAttributes changeCooldownAttributes = new ConfigurationManagerAttributes
				{
					Browsable = (allowUnselect.Value == Toggle.On)
				};
				allowUnselect.SettingChanged += delegate
				{
					changeCooldownAttributes.Browsable = allowUnselect.Value == Toggle.On;
					reloadConfigDisplay();
				};
				resetLevelOnUnselect = config("1 - General", "Reset Level on Unlearn", Toggle.On, new ConfigDescription("If on, the skill level of a profession is reset, if you unlearn it.", (AcceptableValueBase)null, new object[1] { changeCooldownAttributes }));
				professionChangeCooldown = config("1 - General", "Profession Change Cooldown", 0f, new ConfigDescription("Time between profession changes. Uses real time hours. Use 0 to disable this.", (AcceptableValueBase)null, new object[1] { changeCooldownAttributes }));
				professionPanelHotkey = config<KeyboardShortcut>("1 - General", "Profession Panel Hotkey", new KeyboardShortcut((KeyCode)112, Array.Empty<KeyCode>()), "Key or key combination to open the profession panel.", synchronizedSetting: false);
				Profession[] array = (Profession[])Enum.GetValues(typeof(Profession));
				foreach (Profession profession in array)
				{
					blockOtherProfessions[profession] = config("2 - Professions", $"{profession} behaviour", ProfessionToggle.BlockExperience, "Ignored: The skill is not considered a profession and can be used by everyone.\nBlock Experience: If you did not pick the skills profession, you will not get any experience for this skill.\nBlock Usage: If you did not pick the skills profession, you will not be able to perform the action that would grant you experience for the skill.");
					blockOtherProfessions[profession].SettingChanged += delegate
					{
						if (professionPanelElements.TryGetValue(profession, out GameObject value))
						{
							value.SetActive(blockOtherProfessions[profession].Value != ProfessionToggle.Ignored);
						}
					};
				}
				Assembly executingAssembly = Assembly.GetExecutingAssembly();
				new Harmony("org.bepinex.plugins.professions").PatchAll(executingAssembly);
				professionPanel = LoadAssetBundle("professionSelect").LoadAsset<GameObject>("ProfessionPanel");
				Skill_Element.blockExperience = Helper.loadSprite("blockxp.png", 1, 1);
				Skill_Element.blockUsage = Helper.loadSprite("blockusage.png", 1, 1);
				void reloadConfigDisplay()
				{
					configManagerType?.GetMethod("BuildSettingList").Invoke(configManager, Array.Empty<object>());
				}
			}
			catch (Exception arg)
			{
				Debug.LogError((object)$"Professions Awake failed. Shutting down, to prevent further issues with the professions. Exception:\n{arg}");
				Application.Quit();
			}
		}

		private static void onServerTimeReceived(ZRpc? rpc, long time)
		{
			serverTime = new DateTime(time);
		}

		private static void onServerTimeRequest(ZRpc rpc)
		{
			rpc.Invoke("Professions GetServerTime", new object[1] { DateTime.Now.Ticks });
		}

		private static void requestServerTime()
		{
			if (ZNet.instance.IsServer())
			{
				onServerTimeReceived(null, DateTime.Now.Ticks);
			}
			else
			{
				ZNet.instance.GetServerPeer().m_rpc.Invoke("Professions GetServerTime", Array.Empty<object>());
			}
		}

		private void Update()
		{
			//IL_0013: 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)
			PreventMainMenu.AllowMainMenu = true;
			if (Player.m_localPlayer == null)
			{
				return;
			}
			KeyboardShortcut value = professionPanelHotkey.Value;
			if (((KeyboardShortcut)(ref value)).IsDown() && (professionPanelInstance.activeSelf || ((Character)Player.m_localPlayer).TakeInput()))
			{
				professionPanelInstance.SetActive(!professionPanelInstance.activeSelf);
				if (professionPanelInstance.activeSelf)
				{
					UpdateSelectPanelSelections();
					requestServerTime();
				}
			}
			if (professionPanelInstance.activeSelf && Input.GetKey((KeyCode)27))
			{
				professionPanelInstance.SetActive(false);
				PreventMainMenu.AllowMainMenu = false;
			}
		}

		public static SkillType GetSkillTypeFromProfession(Profession profession)
		{
			//IL_000c: 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_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			return (SkillType)(profession switch
			{
				Profession.Cooking => 105, 
				Profession.Farming => 106, 
				_ => Math.Abs(StringExtensionMethods.GetStableHashCode(profession.ToString())), 
			});
		}

		private static void UpdateSelectPanelSelections()
		{
			HashSet<Profession> activeProfessions = Helper.getActiveProfessions();
			if (!Player.m_localPlayer.m_knownStations.TryGetValue("Professions extraProfessionsSlots", out var value))
			{
				Player.m_localPlayer.m_knownStations["Professions extraProfessionsSlots"] = 0;
				value = 0;
			}
			foreach (KeyValuePair<Profession, GameObject> professionPanelElement in professionPanelElements)
			{
				Skill_Element component = professionPanelElement.Value.GetComponent<Skill_Element>();
				component.Toggle(activeProfessions.Contains(professionPanelElement.Key), activeProfessions.Count >= maximumAllowedProfessions.Value + value);
				component.UpdateImageDisplay(blockOtherProfessions[professionPanelElement.Key].Value);
			}
			int num = RequiredTrophies(maximumAllowedProfessions.Value + value);
			professionPanelInstance.GetComponent<ProfessionPanel>().description.text = string.Format("You have {0} / {1} professions selected.\nYou need Craftsman Trophy x {2} to unlock another profession.\nYou are{3} allowed to change your professions{4}.", activeProfessions.Count, maximumAllowedProfessions.Value + value, num, (allowUnselect.Value == Toggle.Off) ? " not" : "", (professionChangeCooldown.Value > 0f && allowUnselect.Value == Toggle.On) ? (" every " + Helper.getHumanFriendlyTime((int)(professionChangeCooldown.Value * 3600f))) : "");
			string text = ((resetLevelOnUnselect.Value == Toggle.On) ? "Relearn at 50% of your previous level." : "Relearn at 100% of your previous level.");
			professionPanelInstance.GetComponent<ProfessionPanel>().description.text = $"You have {activeProfessions.Count} / {maximumAllowedProfessions.Value + value} professions selected.\n" + $"You need Craftsman Trophy x {num} to unlock another profession.\n" + "You are" + ((allowUnselect.Value == Toggle.Off) ? " not" : "") + " allowed to change your professions" + ((professionChangeCooldown.Value > 0f && allowUnselect.Value == Toggle.On) ? (" every " + Helper.getHumanFriendlyTime((int)(professionChangeCooldown.Value * 3600f))) : "") + ".\n" + text;
		}

		private static AssetBundle LoadAssetBundle(string bundleName)
		{
			string bundleName2 = bundleName;
			string name = typeof(Professions).Assembly.GetManifestResourceNames().Single((string s) => s.EndsWith(bundleName2));
			return AssetBundle.LoadFromStream(typeof(Professions).Assembly.GetManifestResourceStream(name));
		}

		private static int RequiredTrophies(int allowed)
		{
			if (allowed <= 0)
			{
				return 0;
			}
			return allowed switch
			{
				1 => 2, 
				2 => 3, 
				3 => 5, 
				4 => 9, 
				5 => 16, 
				6 => 30, 
				7 => 60, 
				8 => 120, 
				9 => 240, 
				10 => 480, 
				11 => 1000, 
				_ => Mathf.CeilToInt(0.97657f * Mathf.Pow(2f, (float)allowed)), 
			};
		}

		private static ItemData FindItemBySharedName(Inventory inv, string lowerName, int minStack)
		{
			for (int i = 0; i < inv.GetHeight(); i++)
			{
				for (int j = 0; j < inv.GetWidth(); j++)
				{
					ItemData itemAt = inv.GetItemAt(j, i);
					if (itemAt != null && itemAt.m_shared?.m_name != null && itemAt.m_shared.m_name.ToLower() == lowerName && itemAt.m_stack >= minStack)
					{
						return itemAt;
					}
				}
			}
			return null;
		}
	}
}
namespace ServerSync
{
	[PublicAPI]
	internal abstract class OwnConfigEntryBase
	{
		public object? LocalBaseValue;

		public bool SynchronizedConfig = true;

		public abstract ConfigEntryBase BaseConfig { get; }
	}
	[PublicAPI]
	internal class SyncedConfigEntry<T> : OwnConfigEntryBase
	{
		public readonly ConfigEntry<T> SourceConfig;

		public override ConfigEntryBase BaseConfig => (ConfigEntryBase)(object)SourceConfig;

		public T Value
		{
			get
			{
				return SourceConfig.Value;
			}
			set
			{
				SourceConfig.Value = value;
			}
		}

		public SyncedConfigEntry(ConfigEntry<T> sourceConfig)
		{
			SourceConfig = sourceConfig;
		}

		public void AssignLocalValue(T value)
		{
			if (LocalBaseValue == null)
			{
				Value = value;
			}
			else
			{
				LocalBaseValue = value;
			}
		}
	}
	internal abstract class CustomSyncedValueBase
	{
		public object? LocalBaseValue;

		public readonly string Identifier;

		public readonly Type Type;

		private object? boxedValue;

		protected bool localIsOwner;

		public readonly int Priority;

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

		public event Action? ValueChanged;

		protected CustomSyncedValueBase(ConfigSync configSync, string identifier, Type type, int priority)
		{
			Priority = priority;
			Identifier = identifier;
			Type = type;
			configSync.AddCustomValue(this);
			localIsOwner = configSync.IsSourceOfTruth;
			configSync.SourceOfTruthChanged += delegate(bool truth)
			{
				localIsOwner = truth;
			};
		}
	}
	[PublicAPI]
	internal sealed class CustomSyncedValue<T> : CustomSyncedValueBase
	{
		public T Value
		{
			get
			{
				return (T)base.BoxedValue;
			}
			set
			{
				base.BoxedValue = value;
			}
		}

		public CustomSyncedValue(ConfigSync configSync, string identifier, T value = default(T), int priority = 0)
			: base(configSync, identifier, typeof(T), priority)
		{
			Value = value;
		}

		public void AssignLocalValue(T value)
		{
			if (localIsOwner)
			{
				Value = value;
			}
			else
			{
				LocalBaseValue = value;
			}
		}
	}
	internal class ConfigurationManagerAttributes
	{
		[UsedImplicitly]
		public bool? ReadOnly = false;
	}
	[PublicAPI]
	internal class ConfigSync
	{
		[HarmonyPatch(typeof(ZRpc), "HandlePackage")]
		private static class SnatchCurrentlyHandlingRPC
		{
			public static ZRpc? currentRpc;

			[HarmonyPrefix]
			private static void Prefix(ZRpc __instance)
			{
				currentRpc = __instance;
			}
		}

		[HarmonyPatch(typeof(ZNet), "Awake")]
		internal static class RegisterRPCPatch
		{
			[HarmonyPostfix]
			private static void Postfix(ZNet __instance)
			{
				isServer = __instance.IsServer();
				foreach (ConfigSync configSync2 in configSyncs)
				{
					ZRoutedRpc.instance.Register<ZPackage>(configSync2.Name + " ConfigSync", (Action<long, ZPackage>)configSync2.RPC_FromOtherClientConfigSync);
					if (isServer)
					{
						configSync2.InitialSyncDone = true;
						Debug.Log((object)("Registered '" + configSync2.Name + " ConfigSync' RPC - waiting for incoming connections"));
					}
				}
				if (isServer)
				{
					((MonoBehaviour)__instance).StartCoroutine(WatchAdminListChanges());
				}
				static void SendAdmin(List<ZNetPeer> peers, bool isAdmin)
				{
					ZPackage package = ConfigsToPackage(null, null, new PackageEntry[1]
					{
						new PackageEntry
						{
							section = "Internal",
							key = "lockexempt",
							type = typeof(bool),
							value = isAdmin
						}
					});
					ConfigSync configSync = configSyncs.First();
					if (configSync != null)
					{
						((MonoBehaviour)ZNet.instance).StartCoroutine(configSync.sendZPackage(peers, package));
					}
				}
				static IEnumerator WatchAdminListChanges()
				{
					SyncedList adminList = (SyncedList)AccessTools.DeclaredField(typeof(ZNet), "m_adminList").GetValue(ZNet.instance);
					List<string> CurrentList = new List<string>(adminList.GetList());
					while (true)
					{
						yield return (object)new WaitForSeconds(30f);
						if (!adminList.GetList().SequenceEqual(CurrentList))
						{
							CurrentList = new List<string>(adminList.GetList());
							List<ZNetPeer> adminPeer = (from p in ZNet.instance.GetPeers()
								where adminList.Contains(p.m_rpc.GetSocket().GetHostName())
								select p).ToList();
							List<ZNetPeer> nonAdminPeer = ZNet.instance.GetPeers().Except(adminPeer).ToList();
							SendAdmin(nonAdminPeer, isAdmin: false);
							SendAdmin(adminPeer, isAdmin: true);
						}
					}
				}
			}
		}

		[HarmonyPatch(typeof(ZNet), "OnNewConnection")]
		private static class RegisterClientRPCPatch
		{
			[HarmonyPostfix]
			private static void Postfix(ZNet __instance, ZNetPeer peer)
			{
				if (__instance.IsServer())
				{
					return;
				}
				foreach (ConfigSync configSync in configSyncs)
				{
					peer.m_rpc.Register<ZPackage>(configSync.Name + " ConfigSync", (Action<ZRpc, ZPackage>)configSync.RPC_FromServerConfigSync);
				}
			}
		}

		private class ParsedConfigs
		{
			public readonly Dictionary<OwnConfigEntryBase, object?> configValues = new Dictionary<OwnConfigEntryBase, object>();

			public readonly Dictionary<CustomSyncedValueBase, object?> customValues = new Dictionary<CustomSyncedValueBase, object>();
		}

		[HarmonyPatch(typeof(ZNet), "Shutdown")]
		private class ResetConfigsOnShutdown
		{
			[HarmonyPostfix]
			private static void Postfix()
			{
				ProcessingServerUpdate = true;
				foreach (ConfigSync configSync in configSyncs)
				{
					configSync.resetConfigsFromServer();
					configSync.IsSourceOfTruth = true;
					configSync.InitialSyncDone = false;
				}
				ProcessingServerUpdate = false;
			}
		}

		[HarmonyPatch(typeof(ZNet), "RPC_PeerInfo")]
		private class SendConfigsAfterLogin
		{
			private class BufferingSocket : ISocket
			{
				public volatile bool finished = false;

				public volatile int versionMatchQueued = -1;

				public readonly List<ZPackage> Package = new List<ZPackage>();

				public readonly ISocket Original;

				public BufferingSocket(ISocket original)
				{
					Original = original;
				}

				public bool IsConnected()
				{
					return Original.IsConnected();
				}

				public ZPackage Recv()
				{
					return Original.Recv();
				}

				public int GetSendQueueSize()
				{
					return Original.GetSendQueueSize();
				}

				public int GetCurrentSendRate()
				{
					return Original.GetCurrentSendRate();
				}

				public bool IsHost()
				{
					return Original.IsHost();
				}

				public void Dispose()
				{
					Original.Dispose();
				}

				public bool GotNewData()
				{
					return Original.GotNewData();
				}

				public void Close()
				{
					Original.Close();
				}

				public string GetEndPointString()
				{
					return Original.GetEndPointString();
				}

				public void GetAndResetStats(out int totalSent, out int totalRecv)
				{
					Original.GetAndResetStats(ref totalSent, ref totalRecv);
				}

				public void GetConnectionQuality(out float localQuality, out float remoteQuality, out int ping, out float outByteSec, out float inByteSec)
				{
					Original.GetConnectionQuality(ref localQuality, ref remoteQuality, ref ping, ref outByteSec, ref inByteSec);
				}

				public ISocket Accept()
				{
					return Original.Accept();
				}

				public int GetHostPort()
				{
					return Original.GetHostPort();
				}

				public bool Flush()
				{
					return Original.Flush();
				}

				public string GetHostName()
				{
					return Original.GetHostName();
				}

				public void VersionMatch()
				{
					if (finished)
					{
						Original.VersionMatch();
					}
					else
					{
						versionMatchQueued = Package.Count;
					}
				}

				public void Send(ZPackage pkg)
				{
					//IL_0057: Unknown result type (might be due to invalid IL or missing references)
					//IL_005d: Expected O, but got Unknown
					int pos = pkg.GetPos();
					pkg.SetPos(0);
					int num = pkg.ReadInt();
					if ((num == StringExtensionMethods.GetStableHashCode("PeerInfo") || num == StringExtensionMethods.GetStableHashCode("RoutedRPC") || num == StringExtensionMethods.GetStableHashCode("ZDOData")) && !finished)
					{
						ZPackage val = new ZPackage(pkg.GetArray());
						val.SetPos(pos);
						Package.Add(val);
					}
					else
					{
						pkg.SetPos(pos);
						Original.Send(pkg);
					}
				}
			}

			[HarmonyPriority(800)]
			[HarmonyPrefix]
			private static void Prefix(ref Dictionary<Assembly, BufferingSocket>? __state, ZNet __instance, ZRpc rpc)
			{
				//IL_0078: Unknown result type (might be due to invalid IL or missing references)
				//IL_007e: Invalid comparison between Unknown and I4
				if (__instance.IsServer())
				{
					BufferingSocket value = new BufferingSocket(rpc.GetSocket());
					AccessTools.DeclaredField(typeof(ZRpc), "m_socket").SetValue(rpc, value);
					object? obj = AccessTools.DeclaredMethod(typeof(ZNet), "GetPeer", new Type[1] { typeof(ZRpc) }, (Type[])null).Invoke(__instance, new object[1] { rpc });
					ZNetPeer val = (ZNetPeer)((obj is ZNetPeer) ? obj : null);
					if (val != null && (int)ZNet.m_onlineBackend > 0)
					{
						AccessTools.DeclaredField(typeof(ZNetPeer), "m_socket").SetValue(val, value);
					}
					if (__state == null)
					{
						__state = new Dictionary<Assembly, BufferingSocket>();
					}
					__state[Assembly.GetExecutingAssembly()] = value;
				}
			}

			[HarmonyPostfix]
			private static void Postfix(Dictionary<Assembly, BufferingSocket> __state, ZNet __instance, ZRpc rpc)
			{
				ZRpc rpc2 = rpc;
				ZNet __instance2 = __instance;
				Dictionary<Assembly, BufferingSocket> __state2 = __state;
				ZNetPeer peer;
				if (__instance2.IsServer())
				{
					object obj = AccessTools.DeclaredMethod(typeof(ZNet), "GetPeer", new Type[1] { typeof(ZRpc) }, (Type[])null).Invoke(__instance2, new object[1] { rpc2 });
					peer = (ZNetPeer)((obj is ZNetPeer) ? obj : null);
					if (peer == null)
					{
						SendBufferedData();
					}
					else
					{
						((MonoBehaviour)__instance2).StartCoroutine(sendAsync());
					}
				}
				void SendBufferedData()
				{
					if (rpc2.GetSocket() is BufferingSocket bufferingSocket)
					{
						AccessTools.DeclaredField(typeof(ZRpc), "m_socket").SetValue(rpc2, bufferingSocket.Original);
						object? obj2 = AccessTools.DeclaredMethod(typeof(ZNet), "GetPeer", new Type[1] { typeof(ZRpc) }, (Type[])null).Invoke(__instance2, new object[1] { rpc2 });
						ZNetPeer val = (ZNetPeer)((obj2 is ZNetPeer) ? obj2 : null);
						if (val != null)
						{
							AccessTools.DeclaredField(typeof(ZNetPeer), "m_socket").SetValue(val, bufferingSocket.Original);
						}
					}
					BufferingSocket bufferingSocket2 = __state2[Assembly.GetExecutingAssembly()];
					bufferingSocket2.finished = true;
					for (int i = 0; i < bufferingSocket2.Package.Count; i++)
					{
						if (i == bufferingSocket2.versionMatchQueued)
						{
							bufferingSocket2.Original.VersionMatch();
						}
						bufferingSocket2.Original.Send(bufferingSocket2.Package[i]);
					}
					if (bufferingSocket2.Package.Count == bufferingSocket2.versionMatchQueued)
					{
						bufferingSocket2.Original.VersionMatch();
					}
				}
				IEnumerator sendAsync()
				{
					foreach (ConfigSync configSync in configSyncs)
					{
						List<PackageEntry> entries = new List<PackageEntry>();
						if (configSync.CurrentVersion != null)
						{
							entries.Add(new PackageEntry
							{
								section = "Internal",
								key = "serverversion",
								type = typeof(string),
								value = configSync.CurrentVersion
							});
						}
						MethodInfo listContainsId = AccessTools.DeclaredMethod(typeof(ZNet), "ListContainsId", (Type[])null, (Type[])null);
						SyncedList adminList = (SyncedList)AccessTools.DeclaredField(typeof(ZNet), "m_adminList").GetValue(ZNet.instance);
						entries.Add(new PackageEntry
						{
							section = "Internal",
							key = "lockexempt",
							type = typeof(bool),
							value = (((object)listContainsId == null) ? ((object)adminList.Contains(rpc2.GetSocket().GetHostName())) : listContainsId.Invoke(ZNet.instance, new object[2]
							{
								adminList,
								rpc2.GetSocket().GetHostName()
							}))
						});
						ZPackage package = ConfigsToPackage(configSync.allConfigs.Select((OwnConfigEntryBase c) => c.BaseConfig), configSync.allCustomValues, entries, partial: false);
						yield return ((MonoBehaviour)__instance2).StartCoroutine(configSync.sendZPackage(new List<ZNetPeer> { peer }, package));
					}
					SendBufferedData();
				}
			}
		}

		private class PackageEntry
		{
			public string section = null;

			public string key = null;

			public Type type = null;

			public object? value;
		}

		[HarmonyPatch(typeof(ConfigEntryBase), "GetSerializedValue")]
		private static class PreventSavingServerInfo
		{
			[HarmonyPrefix]
			private static bool Prefix(ConfigEntryBase __instance, ref string __result)
			{
				OwnConfigEntryBase ownConfigEntryBase = configData(__instance);
				if (ownConfigEntryBase == null || isWritableConfig(ownConfigEntryBase))
				{
					return true;
				}
				__result = TomlTypeConverter.ConvertToString(ownConfigEntryBase.LocalBaseValue, __instance.SettingType);
				return false;
			}
		}

		[HarmonyPatch(typeof(ConfigEntryBase), "SetSerializedValue")]
		private static class PreventConfigRereadChangingValues
		{
			[HarmonyPrefix]
			private static bool Prefix(ConfigEntryBase __instance, string value)
			{
				OwnConfigEntryBase ownConfigEntryBase = configData(__instance);
				if (ownConfigEntryBase == null || ownConfigEntryBase.LocalBaseValue == null)
				{
					return true;
				}
				try
				{
					ownConfigEntryBase.LocalBaseValue = TomlTypeConverter.ConvertToValue(value, __instance.SettingType);
				}
				catch (Exception ex)
				{
					Debug.LogWarning((object)$"Config value of setting \"{__instance.Definition}\" could not be parsed and will be ignored. Reason: {ex.Message}; Value: {value}");
				}
				return false;
			}
		}

		private class InvalidDeserializationTypeException : Exception
		{
			public string expected = null;

			public string received = null;

			public string field = "";
		}

		public static bool ProcessingServerUpdate;

		public readonly string Name;

		public string? DisplayName;

		public string? CurrentVersion;

		public string? MinimumRequiredVersion;

		public bool ModRequired = false;

		private bool? forceConfigLocking;

		private bool isSourceOfTruth = true;

		private static readonly HashSet<ConfigSync> configSyncs;

		private readonly HashSet<OwnConfigEntryBase> allConfigs = new HashSet<OwnConfigEntryBase>();

		private HashSet<CustomSyncedValueBase> allCustomValues = new HashSet<CustomSyncedValueBase>();

		private static bool isServer;

		private static bool lockExempt;

		private OwnConfigEntryBase? lockedConfig = null;

		private const byte PARTIAL_CONFIGS = 1;

		private const byte FRAGMENTED_CONFIG = 2;

		private const byte COMPRESSED_CONFIG = 4;

		private readonly Dictionary<string, SortedDictionary<int, byte[]>> configValueCache = new Dictionary<string, SortedDictionary<int, byte[]>>();

		private readonly List<KeyValuePair<long, string>> cacheExpirations = new List<KeyValuePair<long, string>>();

		private static long packageCounter;

		public bool IsLocked
		{
			get
			{
				bool? flag = forceConfigLocking;
				bool num;
				if (!flag.HasValue)
				{
					if (lockedConfig == null)
					{
						goto IL_0052;
					}
					num = ((IConvertible)lockedConfig.BaseConfig.BoxedValue).ToInt32(CultureInfo.InvariantCulture) != 0;
				}
				else
				{
					num = flag.GetValueOrDefault();
				}
				if (!num)
				{
					goto IL_0052;
				}
				int result = ((!lockExempt) ? 1 : 0);
				goto IL_0053;
				IL_0053:
				return (byte)result != 0;
				IL_0052:
				result = 0;
				goto IL_0053;
			}
			set
			{
				forceConfigLocking = value;
			}
		}

		public bool IsAdmin => lockExempt || isSourceOfTruth;

		public bool IsSourceOfTruth
		{
			get
			{
				return isSourceOfTruth;
			}
			private set
			{
				if (value != isSourceOfTruth)
				{
					isSourceOfTruth = value;
					this.SourceOfTruthChanged?.Invoke(value);
				}
			}
		}

		public bool InitialSyncDone { get; private set; } = false;


		public event Action<bool>? SourceOfTruthChanged;

		private event Action? lockedConfigChanged;

		static ConfigSync()
		{
			ProcessingServerUpdate = false;
			configSyncs = new HashSet<ConfigSync>();
			lockExempt = false;
			packageCounter = 0L;
			RuntimeHelpers.RunClassConstructor(typeof(VersionCheck).TypeHandle);
		}

		public ConfigSync(string name)
		{
			Name = name;
			configSyncs.Add(this);
			new VersionCheck(this);
		}

		public SyncedConfigEntry<T> AddConfigEntry<T>(ConfigEntry<T> configEntry)
		{
			ConfigEntry<T> configEntry2 = configEntry;
			OwnConfigEntryBase ownConfigEntryBase = configData((ConfigEntryBase)(object)configEntry2);
			SyncedConfigEntry<T> syncedEntry = ownConfigEntryBase as SyncedConfigEntry<T>;
			if (syncedEntry == null)
			{
				syncedEntry = new SyncedConfigEntry<T>(configEntry2);
				AccessTools.DeclaredField(typeof(ConfigDescription), "<Tags>k__BackingField").SetValue(((ConfigEntryBase)configEntry2).Description, new object[1]
				{
					new ConfigurationManagerAttributes()
				}.Concat(((ConfigEntryBase)configEntry2).Description.Tags ?? Array.Empty<object>()).Concat(new SyncedConfigEntry<T>[1] { syncedEntry }).ToArray());
				configEntry2.SettingChanged += delegate
				{
					if (!ProcessingServerUpdate && syncedEntry.SynchronizedConfig)
					{
						Broadcast(ZRoutedRpc.Everybody, (ConfigEntryBase)configEntry2);
					}
				};
				allConfigs.Add(syncedEntry);
			}
			return syncedEntry;
		}

		public SyncedConfigEntry<T> AddLockingConfigEntry<T>(ConfigEntry<T> lockingConfig) where T : IConvertible
		{
			if (lockedConfig != null)
			{
				throw new Exception("Cannot initialize locking ConfigEntry twice");
			}
			lockedConfig = AddConfigEntry<T>(lockingConfig);
			lockingConfig.SettingChanged += delegate
			{
				this.lockedConfigChanged?.Invoke();
			};
			return (SyncedConfigEntry<T>)lockedConfig;
		}

		internal void AddCustomValue(CustomSyncedValueBase customValue)
		{
			CustomSyncedValueBase customValue2 = customValue;
			if (allCustomValues.Select((CustomSyncedValueBase v) => v.Identifier).Concat(new string[1] { "serverversion" }).Contains(customValue2.Identifier))
			{
				throw new Exception("Cannot have multiple settings with the same name or with a reserved name (serverversion)");
			}
			allCustomValues.Add(customValue2);
			allCustomValues = new HashSet<CustomSyncedValueBase>(allCustomValues.OrderByDescending((CustomSyncedValueBase v) => v.Priority));
			customValue2.ValueChanged += delegate
			{
				if (!ProcessingServerUpdate)
				{
					Broadcast(ZRoutedRpc.Everybody, customValue2);
				}
			};
		}

		private void RPC_FromServerConfigSync(ZRpc rpc, ZPackage package)
		{
			lockedConfigChanged += serverLockedSettingChanged;
			IsSourceOfTruth = false;
			if (HandleConfigSyncRPC(0L, package, clientUpdate: false))
			{
				InitialSyncDone = true;
			}
		}

		private void RPC_FromOtherClientConfigSync(long sender, ZPackage package)
		{
			HandleConfigSyncRPC(sender, package, clientUpdate: true);
		}

		private bool HandleConfigSyncRPC(long sender, ZPackage package, bool clientUpdate)
		{
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Expected O, but got Unknown
			//IL_024e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0255: Expected O, but got Unknown
			//IL_01e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ef: Expected O, but got Unknown
			try
			{
				if (isServer && IsLocked)
				{
					ZRpc? currentRpc = SnatchCurrentlyHandlingRPC.currentRpc;
					object obj;
					if (currentRpc == null)
					{
						obj = null;
					}
					else
					{
						ISocket socket = currentRpc.GetSocket();
						obj = ((socket != null) ? socket.GetHostName() : null);
					}
					string text = (string)obj;
					if (text != null)
					{
						MethodInfo methodInfo = AccessTools.DeclaredMethod(typeof(ZNet), "ListContainsId", (Type[])null, (Type[])null);
						SyncedList val = (SyncedList)AccessTools.DeclaredField(typeof(ZNet), "m_adminList").GetValue(ZNet.instance);
						if (!(((object)methodInfo == null) ? val.Contains(text) : ((bool)methodInfo.Invoke(ZNet.instance, new object[2] { val, text }))))
						{
							return false;
						}
					}
				}
				cacheExpirations.RemoveAll(delegate(KeyValuePair<long, string> kv)
				{
					if (kv.Key < DateTimeOffset.Now.Ticks)
					{
						configValueCache.Remove(kv.Value);
						return true;
					}
					return false;
				});
				byte b = package.ReadByte();
				if ((b & 2u) != 0)
				{
					long num = package.ReadLong();
					string text2 = sender.ToString() + num;
					if (!configValueCache.TryGetValue(text2, out SortedDictionary<int, byte[]> value))
					{
						value = new SortedDictionary<int, byte[]>();
						configValueCache[text2] = value;
						cacheExpirations.Add(new KeyValuePair<long, string>(DateTimeOffset.Now.AddSeconds(60.0).Ticks, text2));
					}
					int key = package.ReadInt();
					int num2 = package.ReadInt();
					value.Add(key, package.ReadByteArray());
					if (value.Count < num2)
					{
						return false;
					}
					configValueCache.Remove(text2);
					package = new ZPackage(value.Values.SelectMany((byte[] a) => a).ToArray());
					b = package.ReadByte();
				}
				ProcessingServerUpdate = true;
				if ((b & 4u) != 0)
				{
					byte[] buffer = package.ReadByteArray();
					MemoryStream stream = new MemoryStream(buffer);
					MemoryStream memoryStream = new MemoryStream();
					using (DeflateStream deflateStream = new DeflateStream(stream, CompressionMode.Decompress))
					{
						deflateStream.CopyTo(memoryStream);
					}
					package = new ZPackage(memoryStream.ToArray());
					b = package.ReadByte();
				}
				if ((b & 1) == 0)
				{
					resetConfigsFromServer();
				}
				ParsedConfigs parsedConfigs = ReadConfigsFromPackage(package);
				foreach (KeyValuePair<OwnConfigEntryBase, object> configValue in parsedConfigs.configValues)
				{
					if (!isServer && configValue.Key.LocalBaseValue == null)
					{
						configValue.Key.LocalBaseValue = configValue.Key.BaseConfig.BoxedValue;
					}
					configValue.Key.BaseConfig.BoxedValue = configValue.Value;
				}
				foreach (KeyValuePair<CustomSyncedValueBase, object> customValue in parsedConfigs.customValues)
				{
					if (!isServer)
					{
						CustomSyncedValueBase key2 = customValue.Key;
						if (key2.LocalBaseValue == null)
						{
							key2.LocalBaseValue = customValue.Key.BoxedValue;
						}
					}
					customValue.Key.BoxedValue = customValue.Value;
				}
				Debug.Log((object)string.Format("Received {0} configs and {1} custom values from {2} for mod {3}", parsedConfigs.configValues.Count, parsedConfigs.customValues.Count, (isServer || clientUpdate) ? $"client {sender}" : "the server", DisplayName ?? Name));
				if (!isServer)
				{
					serverLockedSettingChanged();
				}
				return true;
			}
			finally
			{
				ProcessingServerUpdate = false;
			}
		}

		private ParsedConfigs ReadConfigsFromPackage(ZPackage package)
		{
			ParsedConfigs parsedConfigs = new ParsedConfigs();
			Dictionary<string, OwnConfigEntryBase> dictionary = allConfigs.Where((OwnConfigEntryBase c) => c.SynchronizedConfig).ToDictionary((OwnConfigEntryBase c) => c.BaseConfig.Definition.Section + "_" + c.BaseConfig.Definition.Key, (OwnConfigEntryBase c) => c);
			Dictionary<string, CustomSyncedValueBase> dictionary2 = allCustomValues.ToDictionary((CustomSyncedValueBase c) => c.Identifier, (CustomSyncedValueBase c) => c);
			int num = package.ReadInt();
			for (int i = 0; i < num; i++)
			{
				string text = package.ReadString();
				string text2 = package.ReadString();
				string text3 = package.ReadString();
				Type type = Type.GetType(text3);
				if (text3 == "" || type != null)
				{
					object obj;
					try
					{
						obj = ((text3 == "") ? null : ReadValueWithTypeFromZPackage(package, type));
					}
					catch (InvalidDeserializationTypeException ex)
					{
						Debug.LogWarning((object)("Got unexpected struct internal type " + ex.received + " for field " + ex.field + " struct " + text3 + " for " + text2 + " in section " + text + " for mod " + (DisplayName ?? Name) + ", expecting " + ex.expected));
						continue;
					}
					OwnConfigEntryBase value2;
					if (text == "Internal")
					{
						CustomSyncedValueBase value;
						if (text2 == "serverversion")
						{
							if (obj?.ToString() != CurrentVersion)
							{
								Debug.LogWarning((object)("Received server version is not equal: server version = " + (obj?.ToString() ?? "null") + "; local version = " + (CurrentVersion ?? "unknown")));
							}
						}
						else if (text2 == "lockexempt")
						{
							if (obj is bool flag)
							{
								lockExempt = flag;
							}
						}
						else if (dictionary2.TryGetValue(text2, out value))
						{
							if ((text3 == "" && (!value.Type.IsValueType || Nullable.GetUnderlyingType(value.Type) != null)) || GetZPackageTypeString(value.Type) == text3)
							{
								parsedConfigs.customValues[value] = obj;
								continue;
							}
							Debug.LogWarning((object)("Got unexpected type " + text3 + " for internal value " + text2 + " for mod " + (DisplayName ?? Name) + ", expecting " + value.Type.AssemblyQualifiedName));
						}
					}
					else if (dictionary.TryGetValue(text + "_" + text2, out value2))
					{
						Type type2 = configType(value2.BaseConfig);
						if ((text3 == "" && (!type2.IsValueType || Nullable.GetUnderlyingType(type2) != null)) || GetZPackageTypeString(type2) == text3)
						{
							parsedConfigs.configValues[value2] = obj;
							continue;
						}
						Debug.LogWarning((object)("Got unexpected type " + text3 + " for " + text2 + " in section " + text + " for mod " + (DisplayName ?? Name) + ", expecting " + type2.AssemblyQualifiedName));
					}
					else
					{
						Debug.LogWarning((object)("Received unknown config entry " + text2 + " in section " + text + " for mod " + (DisplayName ?? Name) + ". This may happen if client and server versions of the mod do not match."));
					}
					continue;
				}
				Debug.LogWarning((object)("Got invalid type " + text3 + ", abort reading of received configs"));
				return new ParsedConfigs();
			}
			return parsedConfigs;
		}

		private static bool isWritableConfig(OwnConfigEntryBase config)
		{
			OwnConfigEntryBase config2 = config;
			ConfigSync configSync = configSyncs.FirstOrDefault((ConfigSync cs) => cs.allConfigs.Contains(config2));
			if (configSync == null)
			{
				return true;
			}
			return configSync.IsSourceOfTruth || !config2.SynchronizedConfig || config2.LocalBaseValue == null || (!configSync.IsLocked && (config2 != configSync.lockedConfig || lockExempt));
		}

		private void serverLockedSettingChanged()
		{
			foreach (OwnConfigEntryBase allConfig in allConfigs)
			{
				configAttribute<ConfigurationManagerAttributes>(allConfig.BaseConfig).ReadOnly = !isWritableConfig(allConfig);
			}
		}

		private void resetConfigsFromServer()
		{
			foreach (OwnConfigEntryBase item in allConfigs.Where((OwnConfigEntryBase config) => config.LocalBaseValue != null))
			{
				item.BaseConfig.BoxedValue = item.LocalBaseValue;
				item.LocalBaseValue = null;
			}
			foreach (CustomSyncedValueBase item2 in allCustomValues.Where((CustomSyncedValueBase config) => config.LocalBaseValue != null))
			{
				item2.BoxedValue = item2.LocalBaseValue;
				item2.LocalBaseValue = null;
			}
			lockedConfigChanged -= serverLockedSettingChanged;
			serverLockedSettingChanged();
		}

		private IEnumerator<bool> distributeConfigToPeers(ZNetPeer peer, ZPackage package)
		{
			ZNetPeer peer2 = peer;
			ZRoutedRpc rpc = ZRoutedRpc.instance;
			if (rpc == null)
			{
				yield break;
			}
			byte[] data = package.GetArray();
			if (data != null && data.LongLength > 250000)
			{
				int fragments = (int)(1 + (data.LongLength - 1) / 250000);
				long packageIdentifier = ++packageCounter;
				int fragment = 0;
				while (fragment < fragments)
				{
					foreach (bool item in waitForQueue())
					{
						yield return item;
					}
					if (peer2.m_socket.IsConnected())
					{
						ZPackage fragmentedPackage = new ZPackage();
						fragmentedPackage.Write((byte)2);
						fragmentedPackage.Write(packageIdentifier);
						fragmentedPackage.Write(fragment);
						fragmentedPackage.Write(fragments);
						fragmentedPackage.Write(data.Skip(250000 * fragment).Take(250000).ToArray());
						SendPackage(fragmentedPackage);
						if (fragment != fragments - 1)
						{
							yield return true;
						}
						int num = fragment + 1;
						fragment = num;
						continue;
					}
					break;
				}
				yield break;
			}
			foreach (bool item2 in waitForQueue())
			{
				yield return item2;
			}
			SendPackage(package);
			void SendPackage(ZPackage pkg)
			{
				string text = Name + " ConfigSync";
				if (isServer)
				{
					peer2.m_rpc.Invoke(text, new object[1] { pkg });
				}
				else
				{
					rpc.InvokeRoutedRPC(peer2.m_server ? 0 : peer2.m_uid, text, new object[1] { pkg });
				}
			}
			IEnumerable<bool> waitForQueue()
			{
				float timeout = Time.time + 30f;
				while (peer2.m_socket.GetSendQueueSize() > 20000)
				{
					if (Time.time > timeout)
					{
						Debug.Log((object)$"Disconnecting {peer2.m_uid} after 30 seconds config sending timeout");
						peer2.m_rpc.Invoke("Error", new object[1] { (object)(ConnectionStatus)5 });
						ZNet.instance.Disconnect(peer2);
						break;
					}
					yield return false;
				}
			}
		}

		private IEnumerator sendZPackage(long target, ZPackage package)
		{
			if (!Object.op_Implicit((Object)(object)ZNet.instance))
			{
				return Enumerable.Empty<object>().GetEnumerator();
			}
			List<ZNetPeer> list = (List<ZNetPeer>)AccessTools.DeclaredField(typeof(ZRoutedRpc), "m_peers").GetValue(ZRoutedRpc.instance);
			if (target != ZRoutedRpc.Everybody)
			{
				list = list.Where((ZNetPeer p) => p.m_uid == target).ToList();
			}
			return sendZPackage(list, package);
		}

		private IEnumerator sendZPackage(List<ZNetPeer> peers, ZPackage package)
		{
			ZPackage package2 = package;
			if (!Object.op_Implicit((Object)(object)ZNet.instance))
			{
				yield break;
			}
			byte[] rawData = package2.GetArray();
			if (rawData != null && rawData.LongLength > 10000)
			{
				ZPackage compressedPackage = new ZPackage();
				compressedPackage.Write((byte)4);
				MemoryStream output = new MemoryStream();
				using (DeflateStream deflateStream = new DeflateStream(output, CompressionLevel.Optimal))
				{
					deflateStream.Write(rawData, 0, rawData.Length);
				}
				compressedPackage.Write(output.ToArray());
				package2 = compressedPackage;
			}
			List<IEnumerator<bool>> writers = (from peer in peers
				where peer.IsReady()
				select peer into p
				select distributeConfigToPeers(p, package2)).ToList();
			writers.RemoveAll((IEnumerator<bool> writer) => !writer.MoveNext());
			while (writers.Count > 0)
			{
				yield return null;
				writers.RemoveAll((IEnumerator<bool> writer) => !writer.MoveNext());
			}
		}

		private void Broadcast(long target, params ConfigEntryBase[] configs)
		{
			if (!IsLocked || isServer)
			{
				ZPackage package = ConfigsToPackage(configs);
				ZNet instance = ZNet.instance;
				if (instance != null)
				{
					((MonoBehaviour)instance).StartCoroutine(sendZPackage(target, package));
				}
			}
		}

		private void Broadcast(long target, params CustomSyncedValueBase[] customValues)
		{
			if (!IsLocked || isServer)
			{
				ZPackage package = ConfigsToPackage(null, customValues);
				ZNet instance = ZNet.instance;
				if (instance != null)
				{
					((MonoBehaviour)instance).StartCoroutine(sendZPackage(target, package));
				}
			}
		}

		private static OwnConfigEntryBase? configData(ConfigEntryBase config)
		{
			return config.Description.Tags?.OfType<OwnConfigEntryBase>().SingleOrDefault();
		}

		public static SyncedConfigEntry<T>? ConfigData<T>(ConfigEntry<T> config)
		{
			return ((ConfigEntryBase)config).Description.Tags?.OfType<SyncedConfigEntry<T>>().SingleOrDefault();
		}

		private static T configAttribute<T>(ConfigEntryBase config)
		{
			return config.Description.Tags.OfType<T>().First();
		}

		private static Type configType(ConfigEntryBase config)
		{
			return configType(config.SettingType);
		}

		private static Type configType(Type type)
		{
			return type.IsEnum ? Enum.GetUnderlyingType(type) : type;
		}

		private static ZPackage ConfigsToPackage(IEnumerable<ConfigEntryBase>? configs = null, IEnumerable<CustomSyncedValueBase>? customValues = null, IEnumerable<PackageEntry>? packageEntries = null, bool partial = true)
		{
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Expected O, but got Unknown
			List<ConfigEntryBase> list = configs?.Where((ConfigEntryBase config) => configData(config).SynchronizedConfig).ToList() ?? new List<ConfigEntryBase>();
			List<CustomSyncedValueBase> list2 = customValues?.ToList() ?? new List<CustomSyncedValueBase>();
			ZPackage val = new ZPackage();
			val.Write((byte)(partial ? 1 : 0));
			val.Write(list.Count + list2.Count + (packageEntries?.Count() ?? 0));
			foreach (PackageEntry item in packageEntries ?? Array.Empty<PackageEntry>())
			{
				AddEntryToPackage(val, item);
			}
			foreach (CustomSyncedValueBase item2 in list2)
			{
				AddEntryToPackage(val, new PackageEntry
				{
					section = "Internal",
					key = item2.Identifier,
					type = item2.Type,
					value = item2.BoxedValue
				});
			}
			foreach (ConfigEntryBase item3 in list)
			{
				AddEntryToPackage(val, new PackageEntry
				{
					section = item3.Definition.Section,
					key = item3.Definition.Key,
					type = configType(item3),
					value = item3.BoxedValue
				});
			}
			return val;
		}

		private static void AddEntryToPackage(ZPackage package, PackageEntry entry)
		{
			package.Write(entry.section);
			package.Write(entry.key);
			package.Write((entry.value == null) ? "" : GetZPackageTypeString(entry.type));
			AddValueToZPackage(package, entry.value);
		}

		private static string GetZPackageTypeString(Type type)
		{
			return type.AssemblyQualifiedName;
		}

		private static void AddValueToZPackage(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)
						{
							AddValueToZPackage(package, 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(GetZPackageTypeString(fieldInfo.FieldType));
						AddValueToZPackage(package, fieldInfo.GetValue(value));
					}
					return;
				}
			}
			ZRpc.Serialize(new object[1] { value }, ref package);
		}

		private static object ReadValueWithTypeFromZPackage(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 != GetZPackageTypeString(fieldInfo.FieldType))
					{
						throw new InvalidDeserializationTypeException
						{
							received = text,
							expected = GetZPackageTypeString(fieldInfo.FieldType),
							field = fieldInfo.Name
						};
					}
					fieldInfo.SetValue(uninitializedObject, ReadValueWithTypeFromZPackage(package, 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 = ReadValueWithTypeFromZPackage(package, 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] { ReadValueWithTypeFromZPackage(package, 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.First();
		}
	}
	[PublicAPI]
	[HarmonyPatch]
	internal class VersionCheck
	{
		private static readonly HashSet<VersionCheck> versionChecks;

		private static readonly Dictionary<string, string> notProcessedNames;

		public string Name;

		private string? displayName;

		private string? currentVersion;

		private string? minimumRequiredVersion;

		public bool ModRequired = true;

		private string? ReceivedCurrentVersion;

		private string? ReceivedMinimumRequiredVersion;

		private readonly List<ZRpc> ValidatedClients = new List<ZRpc>();

		private ConfigSync? ConfigSync;

		public string DisplayName
		{
			get
			{
				return displayName ?? Name;
			}
			set
			{
				displayName = value;
			}
		}

		public string CurrentVersion
		{
			get
			{
				return currentVersion ?? "0.0.0";
			}
			set
			{
				currentVersion = value;
			}
		}

		public string MinimumRequiredVersion
		{
			get
			{
				return minimumRequiredVersion ?? (ModRequired ? CurrentVersion : "0.0.0");
			}
			set
			{
				minimumRequiredVersion = value;
			}
		}

		private static void PatchServerSync()
		{
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Expected O, but got Unknown
			Patches patchInfo = PatchProcessor.GetPatchInfo((MethodBase)AccessTools.DeclaredMethod(typeof(ZNet), "Awake", (Type[])null, (Type[])null));
			if (patchInfo != null && patchInfo.Postfixes.Count((Patch p) => p.PatchMethod.DeclaringType == typeof(ConfigSync.RegisterRPCPatch)) > 0)
			{
				return;
			}
			Harmony val = new Harmony("org.bepinex.helpers.ServerSync");
			foreach (Type item in from t in typeof(ConfigSync).GetNestedTypes(BindingFlags.NonPublic).Concat(new Type[1] { typeof(VersionCheck) })
				where t.IsClass
				select t)
			{
				val.PatchAll(item);
			}
		}

		static VersionCheck()
		{
			versionChecks = new HashSet<VersionCheck>();
			notProcessedNames = new Dictionary<string, string>();
			typeof(ThreadingHelper).GetMethod("StartSyncInvoke").Invoke(ThreadingHelper.Instance, new object[1]
			{
				new Action(PatchServerSync)
			});
		}

		public VersionCheck(string name)
		{
			Name = name;
			ModRequired = true;
			versionChecks.Add(this);
		}

		public VersionCheck(ConfigSync configSync)
		{
			ConfigSync = configSync;
			Name = ConfigSync.Name;
			versionChecks.Add(this);
		}

		public void Initialize()
		{
			ReceivedCurrentVersion = null;
			ReceivedMinimumRequiredVersion = null;
			if (ConfigSync != null)
			{
				Name = ConfigSync.Name;
				DisplayName = ConfigSync.DisplayName;
				CurrentVersion = ConfigSync.CurrentVersion;
				MinimumRequiredVersion = ConfigSync.MinimumRequiredVersion;
				ModRequired = ConfigSync.ModRequired;
			}
		}

		private bool IsVersionOk()
		{
			if (ReceivedMinimumRequiredVersion == null || ReceivedCurrentVersion == null)
			{
				return !ModRequired;
			}
			bool flag = new Version(CurrentVersion) >= new Version(ReceivedMinimumRequiredVersion);
			bool flag2 = new Version(ReceivedCurrentVersion) >= new Version(MinimumRequiredVersion);
			return flag && flag2;
		}

		private string ErrorClient()
		{
			if (ReceivedMinimumRequiredVersion == null)
			{
				return "Mod " + DisplayName + " must not be installed.";
			}
			return (new Version(CurrentVersion) >= new Version(ReceivedMinimumRequiredVersion)) ? ("Mod " + DisplayName + " requires maximum " + ReceivedCurrentVersion + ". Installed is version " + CurrentVersion + ".") : ("Mod " + DisplayName + " requires minimum " + ReceivedMinimumRequiredVersion + ". Installed is version " + CurrentVersion + ".");
		}

		private string ErrorServer(ZRpc rpc)
		{
			return "Disconnect: The client (" + rpc.GetSocket().GetHostName() + ") doesn't have the correct " + DisplayName + " version " + MinimumRequiredVersion;
		}

		private string Error(ZRpc? rpc = null)
		{
			return (rpc == null) ? ErrorClient() : ErrorServer(rpc);
		}

		private static VersionCheck[] GetFailedClient()
		{
			return versionChecks.Where((VersionCheck check) => !check.IsVersionOk()).ToArray();
		}

		private static VersionCheck[] GetFailedServer(ZRpc rpc)
		{
			ZRpc rpc2 = rpc;
			return versionChecks.Where((VersionCheck check) => check.ModRequired && !check.ValidatedClients.Contains(rpc2)).ToArray();
		}

		private static void Logout()
		{
			Game.instance.Logout(true, true);
			AccessTools.DeclaredField(typeof(ZNet), "m_connectionStatus").SetValue(null, (object)(ConnectionStatus)3);
		}

		private static void DisconnectClient(ZRpc rpc)
		{
			rpc.Invoke("Error", new object[1] { 3 });
		}

		private static void CheckVersion(ZRpc rpc, ZPackage pkg)
		{
			CheckVersion(rpc, pkg, null);
		}

		private static void CheckVersion(ZRpc rpc, ZPackage pkg, Action<ZRpc, ZPackage>? original)
		{
			string text = pkg.ReadString();
			string text2 = pkg.ReadString();
			string text3 = pkg.ReadString();
			bool flag = false;
			foreach (VersionCheck versionCheck in versionChecks)
			{
				if (!(text != versionCheck.Name))
				{
					Debug.Log((object)("Received " + versionCheck.DisplayName + " version " + text3 + " and minimum version " + text2 + " from the " + (ZNet.instance.IsServer() ? "client" : "server") + "."));
					versionCheck.ReceivedMinimumRequiredVersion = text2;
					versionCheck.ReceivedCurrentVersion = text3;
					if (ZNet.instance.IsServer() && versionCheck.IsVersionOk())
					{
						versionCheck.ValidatedClients.Add(rpc);
					}
					flag = true;
				}
			}
			if (flag)
			{
				return;
			}
			pkg.SetPos(0);
			if (original != null)
			{
				original(rpc, pkg);
				if (pkg.GetPos() == 0)
				{
					notProcessedNames.Add(text, text3);
				}
			}
		}

		[HarmonyPatch(typeof(ZNet), "RPC_PeerInfo")]
		[HarmonyPrefix]
		private static bool RPC_PeerInfo(ZRpc rpc, ZNet __instance)
		{
			VersionCheck[] array = (__instance.IsServer() ? GetFailedServer(rpc) : GetFailedClient());
			if (array.Length == 0)
			{
				return true;
			}
			VersionCheck[] array2 = array;
			foreach (VersionCheck versionCheck in array2)
			{
				Debug.LogWarnin

BepInEx/plugins/RepairRequiresCoins.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("RepairRequiresCoins")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("RepairRequiresCoins")]
[assembly: AssemblyTitle("RepairRequiresCoins")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
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;
		}
	}
}
namespace RepairRequiresMats
{
	[BepInPlugin("aedenthorn.RepairRequiresMats", "Repair Requires Mats", "0.5.0")]
	public class BepInExPlugin : BaseUnityPlugin
	{
		[HarmonyPatch(typeof(InventoryGui), "RepairOneItem")]
		private static class InventoryGui_RepairOneItem_Patch
		{
			private static void Postfix(InventoryGui __instance)
			{
				if (modEnabled.Value)
				{
					Traverse.Create((object)__instance).Method("UpdateRepair", Array.Empty<object>()).GetValue();
				}
			}
		}

		[HarmonyPatch(typeof(UITooltip), "LateUpdate")]
		private static class UITooltip_LateUpdate_Patch
		{
			private static void Postfix(UITooltip __instance, UITooltip ___m_current, GameObject ___m_tooltip)
			{
				//IL_002f: Unknown result type (might be due to invalid IL or missing references)
				//IL_003e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0043: Unknown result type (might be due to invalid IL or missing references)
				if (modEnabled.Value && !((Object)(object)___m_current != (Object)(object)__instance) && !((Object)(object)___m_tooltip == (Object)null) && IsRepairTooltipOwner(__instance))
				{
					___m_tooltip.transform.position = Input.mousePosition + new Vector3(-200f, -100f);
					if (showAllRepairsInToolTip.Value && !string.IsNullOrEmpty(cachedRepairTooltip))
					{
						SetTooltipText(___m_tooltip, cachedRepairTooltip);
					}
				}
			}
		}

		[HarmonyPatch(typeof(InventoryGui), "UpdateRepair")]
		private static class InventoryGui_UpdateRepair_Patch
		{
			private static void Postfix(InventoryGui __instance, ref List<ItemData> ___m_tempWornItems)
			{
				if (!modEnabled.Value)
				{
					return;
				}
				if ((Object)(object)Player.m_localPlayer == (Object)null)
				{
					cachedRepairTooltip = null;
					return;
				}
				if (___m_tempWornItems == null || !___m_tempWornItems.Any())
				{
					cachedRepairTooltip = null;
					return;
				}
				List<RepairItemData> list = new List<RepairItemData>();
				List<RepairItemData> list2 = new List<RepairItemData>();
				List<RepairItemData> list3 = new List<RepairItemData>();
				List<RepairItemData> list4 = new List<RepairItemData>();
				List<string> list5 = new List<string>();
				foreach (ItemData ___m_tempWornItem in ___m_tempWornItems)
				{
					if (!Traverse.Create((object)__instance).Method("CanRepair", new object[1] { ___m_tempWornItem }).GetValue<bool>())
					{
						list4.Add(new RepairItemData(___m_tempWornItem));
						continue;
					}
					List<Requirement> list6 = RepairReqs(___m_tempWornItem);
					if (list6 == null)
					{
						list.Add(new RepairItemData(___m_tempWornItem));
						continue;
					}
					List<string> list7 = new List<string>();
					foreach (Requirement item in list6)
					{
						if (item?.m_resItem?.m_itemData?.m_shared != null && item.m_amount != 0)
						{
							list7.Add($"{item.m_amount}/{((Humanoid)Player.m_localPlayer).GetInventory().CountItems(item.m_resItem.m_itemData.m_shared.m_name, -1, true)} {Localization.instance.Localize(item.m_resItem.m_itemData.m_shared.m_name)}");
						}
					}
					bool flag = true;
					foreach (Requirement item2 in list6)
					{
						if (item2?.m_resItem?.m_itemData?.m_shared != null)
						{
							int amount = item2.m_amount;
							if (((Humanoid)Player.m_localPlayer).GetInventory().CountItems(item2.m_resItem.m_itemData.m_shared.m_name, -1, true) < amount)
							{
								flag = false;
								break;
							}
						}
					}
					if (!flag)
					{
						list3.Add(new RepairItemData(___m_tempWornItem, list7));
					}
					else
					{
						list2.Add(new RepairItemData(___m_tempWornItem, list7));
					}
				}
				orderedWornItems = new List<ItemData>();
				foreach (RepairItemData item3 in list)
				{
					list5.Add("<color=#" + hasEnoughTooltipColor.Value + ">" + Localization.instance.Localize(item3.item.m_shared.m_name) + ": Free</color>");
					orderedWornItems.Add(item3.item);
				}
				foreach (RepairItemData item4 in list2)
				{
					list5.Add("<color=#" + hasEnoughTooltipColor.Value + ">" + Localization.instance.Localize(item4.item.m_shared.m_name) + ": " + string.Join(", ", item4.reqstring) + "</color>");
					orderedWornItems.Add(item4.item);
				}
				foreach (RepairItemData item5 in list3)
				{
					list5.Add("<color=#" + notEnoughTooltipColor.Value + ">" + Localization.instance.Localize(item5.item.m_shared.m_name) + ": " + string.Join(", ", item5.reqstring) + "</color>");
					orderedWornItems.Add(item5.item);
				}
				foreach (RepairItemData item6 in list4)
				{
					orderedWornItems.Add(item6.item);
				}
				___m_tempWornItems = new List<ItemData>(orderedWornItems);
				if (showAllRepairsInToolTip.Value)
				{
					if (list5.Count == 0)
					{
						cachedRepairTooltip = null;
						return;
					}
					cachedRepairTooltip = "<b><color=#" + titleTooltipColor.Value + ">" + Localization.instance.Localize("$inventory_repairbutton") + "</color></b>\n" + string.Join("\n", list5);
				}
			}
		}

		[HarmonyPatch(typeof(InventoryGui), "CanRepair")]
		private static class InventoryGui_CanRepair_Patch
		{
			private static void Postfix(ItemData item, ref bool __result)
			{
				if (!modEnabled.Value || !Environment.StackTrace.Contains("RepairOneItem") || Environment.StackTrace.Contains("HaveRepairableItems") || !__result || item?.m_shared == null || !((Object)(object)Player.m_localPlayer != (Object)null) || orderedWornItems.Count <= 0)
				{
					return;
				}
				if (orderedWornItems[0] != item)
				{
					__result = false;
					return;
				}
				List<Requirement> list = RepairReqs(item, log: true);
				if (list == null)
				{
					return;
				}
				List<string> list2 = new List<string>();
				foreach (Requirement item2 in list)
				{
					if (item2?.m_resItem?.m_itemData?.m_shared != null)
					{
						list2.Add($"{item2.m_amount}/{((Humanoid)Player.m_localPlayer).GetInventory().CountItems(item2.m_resItem.m_itemData.m_shared.m_name, -1, true)} {Localization.instance.Localize(item2.m_resItem.m_itemData.m_shared.m_name)}");
					}
				}
				bool flag = true;
				foreach (Requirement item3 in list)
				{
					if (item3?.m_resItem?.m_itemData?.m_shared != null)
					{
						int amount = item3.m_amount;
						if (((Humanoid)Player.m_localPlayer).GetInventory().CountItems(item3.m_resItem.m_itemData.m_shared.m_name, -1, true) < amount)
						{
							flag = false;
							break;
						}
					}
				}
				string text;
				if (flag)
				{
					Player.m_localPlayer.ConsumeResources(list.ToArray(), 1, -1, 1);
					text = "Used " + string.Join(", ", list2) + " to repair " + Localization.instance.Localize(item.m_shared.m_name);
					__result = true;
				}
				else
				{
					text = "Require " + string.Join(", ", list2) + " to repair " + Localization.instance.Localize(item.m_shared.m_name);
					__result = false;
				}
				((Character)Player.m_localPlayer).Message((MessageType)1, text, 0, (Sprite)null);
				Dbgl(text);
			}
		}

		[HarmonyPatch(typeof(Terminal), "InputText")]
		private static class InputText_Patch
		{
			private static bool Prefix(Terminal __instance)
			{
				if (!modEnabled.Value)
				{
					return true;
				}
				string text = "";
				try
				{
					object value = Traverse.Create((object)__instance).Field("m_input").GetValue();
					InputField val = (InputField)((value is InputField) ? value : null);
					if (val != null)
					{
						text = val.text ?? "";
					}
					else
					{
						TMP_InputField val2 = (TMP_InputField)((value is TMP_InputField) ? value : null);
						if (val2 != null)
						{
							text = val2.text ?? "";
						}
					}
				}
				catch
				{
				}
				if (string.IsNullOrWhiteSpace(text))
				{
					return true;
				}
				if (text.Trim().ToLower().Equals("repairmod reset"))
				{
					((BaseUnityPlugin)context).Config.Reload();
					((BaseUnityPlugin)context).Config.Save();
					Traverse.Create((object)__instance).Method("AddString", new object[1] { text }).GetValue();
					Traverse.Create((object)__instance).Method("AddString", new object[1] { "Repair Items config reloaded" }).GetValue();
					return false;
				}
				return true;
			}
		}

		private static bool isDebug = true;

		public static ConfigEntry<bool> modEnabled;

		public static ConfigEntry<bool> showAllRepairsInToolTip;

		public static ConfigEntry<float> materialRequirementMult;

		public static ConfigEntry<string> titleTooltipColor;

		public static ConfigEntry<string> hasEnoughTooltipColor;

		public static ConfigEntry<string> notEnoughTooltipColor;

		public static ConfigEntry<int> nexusID;

		private static List<ItemData> orderedWornItems = new List<ItemData>();

		private static BepInExPlugin context;

		private static string cachedRepairTooltip = null;

		private static Assembly epicLootAssembly;

		private static MethodInfo epicLootIsMagic;

		private static MethodInfo epicLootGetRarity;

		private static MethodInfo epicLootGetEnchantCosts;

		public static void Dbgl(string str = "", bool pref = true)
		{
			if (isDebug)
			{
				Debug.Log((object)((pref ? (typeof(BepInExPlugin).Namespace + " ") : "") + str));
			}
		}

		private void Awake()
		{
			context = this;
			modEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enable this mod");
			nexusID = ((BaseUnityPlugin)this).Config.Bind<int>("General", "NexusID", 215, "Nexus mod ID for updates");
			showAllRepairsInToolTip = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ShowAllRepairsInToolTip", true, "Show all repairs in tooltip when hovering over repair button.");
			titleTooltipColor = ((BaseUnityPlugin)this).Config.Bind<string>("General", "TitleTooltipColor", "FFFFFFFF", "Color to use in tooltip title.");
			hasEnoughTooltipColor = ((BaseUnityPlugin)this).Config.Bind<string>("General", "HasEnoughTooltipColor", "FFFFFFFF", "Color to use in tooltip for items with enough resources to repair.");
			notEnoughTooltipColor = ((BaseUnityPlugin)this).Config.Bind<string>("General", "NotEnoughTooltipColor", "FF0000FF", "Color to use in tooltip for items with NOT enough resources to repair.");
			materialRequirementMult = ((BaseUnityPlugin)this).Config.Bind<float>("General", "MaterialRequirementMult", 0.5f, "Multiplier for amount of each material required.");
			Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), (string)null);
		}

		private void Start()
		{
			if (Chainloader.PluginInfos.ContainsKey("randyknapp.mods.epicloot"))
			{
				epicLootAssembly = ((object)Chainloader.PluginInfos["randyknapp.mods.epicloot"].Instance).GetType().Assembly;
				epicLootIsMagic = epicLootAssembly.GetType("EpicLoot.ItemDataExtensions")?.GetMethod("IsMagic", BindingFlags.Static | BindingFlags.Public, null, new Type[1] { typeof(ItemData) }, null);
				epicLootGetRarity = epicLootAssembly.GetType("EpicLoot.ItemDataExtensions")?.GetMethod("GetRarity", BindingFlags.Static | BindingFlags.Public);
				epicLootGetEnchantCosts = epicLootAssembly.GetType("EpicLoot.Crafting.EnchantTabController")?.GetMethod("GetEnchantCosts", BindingFlags.Static | BindingFlags.Public);
				Dbgl($"Loaded Epic Loot assembly; epicLootIsMagic {epicLootIsMagic != null}, epicLootGetRarity {epicLootGetRarity != null}, epicLootGetEnchantCosts {epicLootGetEnchantCosts != null}");
			}
		}

		private static Button GetRepairButton()
		{
			InventoryGui instance = InventoryGui.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return null;
			}
			try
			{
				return Traverse.Create((object)instance).Field("m_repairButton").GetValue<Button>();
			}
			catch
			{
				return null;
			}
		}

		private static bool IsRepairTooltipOwner(UITooltip ownerTooltipComponent)
		{
			Button repairButton = GetRepairButton();
			if ((Object)(object)repairButton == (Object)null || (Object)(object)ownerTooltipComponent == (Object)null)
			{
				return false;
			}
			return (Object)(object)((Component)ownerTooltipComponent).transform == (Object)(object)((Component)repairButton).transform;
		}

		private static void SetTooltipText(GameObject tooltipRoot, string value)
		{
			if ((Object)(object)tooltipRoot == (Object)null)
			{
				return;
			}
			Text componentInChildren = tooltipRoot.GetComponentInChildren<Text>(true);
			if ((Object)(object)componentInChildren != (Object)null)
			{
				componentInChildren.supportRichText = true;
				componentInChildren.alignment = (TextAnchor)7;
				componentInChildren.text = value;
				return;
			}
			TMP_Text componentInChildren2 = tooltipRoot.GetComponentInChildren<TMP_Text>(true);
			if ((Object)(object)componentInChildren2 != (Object)null)
			{
				componentInChildren2.richText = true;
				componentInChildren2.alignment = (TextAlignmentOptions)1026;
				componentInChildren2.text = value;
			}
			else
			{
				Dbgl("[TOOLTIP] No Text/TMP_Text found under tooltip root.");
			}
		}

		private static List<Requirement> RepairReqs(ItemData item, bool log = false)
		{
			//IL_0181: Unknown result type (might be due to invalid IL or missing references)
			//IL_0186: 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_01ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d4: Expected O, but got Unknown
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Expected O, but got Unknown
			float maxDurability = item.GetMaxDurability();
			if (maxDurability <= 0f)
			{
				return null;
			}
			float num = (maxDurability - item.m_durability) / maxDurability;
			Recipe recipe = ObjectDB.instance.GetRecipe(item);
			if ((Object)(object)recipe == (Object)null)
			{
				return null;
			}
			List<Requirement> list = new List<Requirement>(recipe.m_resources);
			bool flag = false;
			if (epicLootAssembly != null && epicLootIsMagic != null)
			{
				try
				{
					MethodInfo methodInfo = epicLootIsMagic;
					object[] parameters = (object[])(object)new ItemData[1] { item };
					flag = (bool)methodInfo.Invoke(null, parameters);
				}
				catch
				{
				}
			}
			if (flag && epicLootGetRarity != null && epicLootGetEnchantCosts != null)
			{
				try
				{
					MethodInfo methodInfo2 = epicLootGetRarity;
					object[] parameters = (object[])(object)new ItemData[1] { item };
					int num2 = (int)methodInfo2.Invoke(null, parameters);
					foreach (KeyValuePair<ItemDrop, int> item2 in (List<KeyValuePair<ItemDrop, int>>)epicLootGetEnchantCosts.Invoke(null, new object[2] { item, num2 }))
					{
						list.Add(new Requirement
						{
							m_amount = item2.Value,
							m_resItem = item2.Key
						});
					}
				}
				catch
				{
				}
			}
			List<Requirement> list2 = new List<Requirement>();
			for (int i = 0; i < list.Count; i++)
			{
				if (list[i]?.m_resItem?.m_itemData?.m_shared == null)
				{
					continue;
				}
				Requirement val = new Requirement
				{
					m_resItem = list[i].m_resItem,
					m_amount = list[i].m_amount,
					m_amountPerLevel = list[i].m_amountPerLevel,
					m_recover = list[i].m_recover
				};
				int num3 = 0;
				for (int num4 = item.m_quality; num4 > 0; num4--)
				{
					if (val.m_resItem.m_itemData.m_shared.m_name.ToLower().Contains("item_coins"))
					{
						num3 += val.GetAmount(num4);
					}
				}
				int num5 = Mathf.RoundToInt((float)num3 * num * materialRequirementMult.Value);
				if (num5 > 0)
				{
					val.m_amount = num5;
					list2.Add(val);
				}
			}
			if (!list2.Any())
			{
				return null;
			}
			return list2;
		}
	}
	internal class RepairItemData : ItemData
	{
		public List<string> reqstring;

		public ItemData item;

		public RepairItemData(ItemData item, List<string> reqstring = null)
		{
			this.reqstring = reqstring;
			this.item = item;
		}
	}
}

BepInEx/plugins/UsefulTrophiesXP.dll

Decompiled a day ago
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Configuration;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using EpicMMOSystem;
using HarmonyLib;
using UnityEngine;
using ValheimLegends;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("ClassLibrary1")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ClassLibrary1")]
[assembly: AssemblyCopyright("Copyright ©  2021")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("fba93479-93ac-43d9-8ef2-cfb83bdb7b6d")]
[assembly: AssemblyFileVersion("1.1.1.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("1.1.1.0")]
namespace UsefulTrophiesXP
{
	[HarmonyPatch(typeof(Humanoid), "UseItem")]
	internal class UseItemPatch
	{
		public static bool Prefix(Player __instance, [HarmonyArgument(0)] Inventory inventory, [HarmonyArgument(1)] ItemData item, [HarmonyArgument(2)] bool fromInventoryGui, Inventory ___m_inventory, ZSyncAnimation ___m_zanim)
		{
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			string name = item.m_shared.m_name;
			if (name.Contains("$item_trophy_"))
			{
				string text = name.Substring(13);
				if (inventory == null)
				{
					inventory = ___m_inventory;
				}
				if (!inventory.ContainsItem(item))
				{
					return false;
				}
				GameObject hoverObject = ((Humanoid)__instance).GetHoverObject();
				if (!((Object)(object)hoverObject == (Object)null) && !fromInventoryGui)
				{
					Interactable componentInParent = hoverObject.GetComponentInParent<Interactable>();
					if (componentInParent is ItemStand || componentInParent is OfferingBowl)
					{
						return true;
					}
				}
				float num = 10f;
				if (UsefulTrophiesXP.TrophyXPDict.TryGetValue(text, out var value))
				{
					num = value * UsefulTrophiesXP.ExperienceModifier;
				}
				else
				{
					Debug.Log((object)("Unknown trophy for " + text + "!"));
				}
				inventory.RemoveOneItem(item);
				Player.m_localPlayer.m_skillLevelupEffects.Create(((Character)Player.m_localPlayer).GetHeadPoint(), Quaternion.identity, (Transform)null, 1f, -1);
				ValheimLegends.shouldUseGuardianPower = false;
				((ZSyncAnimation)typeof(Player).GetField("m_zanim", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(Player.m_localPlayer)).SetSpeed(2f);
				((ZSyncAnimation)typeof(Player).GetField("m_zanim", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(Player.m_localPlayer)).SetTrigger("gpower");
				LevelSystem.Instance.AddExp((int)num, false);
				((Character)__instance).Message((MessageType)1, $"Experience received: {num}", 0, (Sprite)null);
				return false;
			}
			return true;
		}
	}
	[BepInPlugin("gg.khairex.usefultrophies.twentyonez.EpicMMOPatch", "Useful Trophies Mod by Khairex, EpicMMO XP Patch by TwentyOneZ", "2.0.1")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInProcess("valheim.exe")]
	public class UsefulTrophiesXP : BaseUnityPlugin
	{
		public const string Id = "gg.khairex.usefultrophies.twentyonez.EpicMMOPatch";

		public static bool EnableSellingTrophies = true;

		public static float ExperienceModifier = 1f;

		public static Dictionary<string, float> TrophyXPDict = new Dictionary<string, float>
		{
			{ "deer", 40f },
			{ "boar", 133f },
			{ "neck", 400f },
			{ "greydwarf", 1200f },
			{ "greydwarfbrute", 1500f },
			{ "greydwarfshaman", 1200f },
			{ "skeleton", 800f },
			{ "skeletonpoison", 1500f },
			{ "troll", 1000f },
			{ "surtling", 2600f },
			{ "leech", 1800f },
			{ "draugr", 1500f },
			{ "draugrelite", 5000f },
			{ "blob", 1800f },
			{ "wraith", 5000f },
			{ "abomination", 200f },
			{ "wolf", 3500f },
			{ "fenring", 4000f },
			{ "hatchling", 3000f },
			{ "sgolem", 14000f },
			{ "ulv", 4000f },
			{ "cultist", 4000f },
			{ "goblin", 4500f },
			{ "goblinbrute", 13000f },
			{ "goblinshaman", 4000f },
			{ "lox", 7000f },
			{ "growth", 6000f },
			{ "deathsquito", 6000f },
			{ "serpent", 1500f },
			{ "hare", 400f },
			{ "gjall", 3600f },
			{ "tick", 4800f },
			{ "dvergr", 6000f },
			{ "seeker", 18000f },
			{ "seekerbrute", 25000f },
			{ "eikthyr", 200f },
			{ "elder", 500f },
			{ "bonemass", 900f },
			{ "dragonqueen", 1400f },
			{ "goblinking", 3000f },
			{ "seekerqueen", 4500f },
			{ "ghost", 2500f },
			{ "bjorn", 3000f },
			{ "skeleton_hildir", 6000f },
			{ "cultist_hildir", 8000f },
			{ "bjorn_undead", 3500f },
			{ "shamanbro", 9000f },
			{ "brutebro", 9000f },
			{ "asksvin", 8000f },
			{ "bonemaw", 12000f },
			{ "fallenvalkyrie", 15000f },
			{ "charredarcher", 9000f },
			{ "morgen", 12000f },
			{ "volture", 9000f },
			{ "charredmage", 12000f },
			{ "charredmelee", 10000f },
			{ "fader", 20000f }
		};

		public static Dictionary<string, int> TrophyGoldValueDict = new Dictionary<string, int>
		{
			{ "deer", 15 },
			{ "boar", 10 },
			{ "neck", 10 },
			{ "greydwarf", 10 },
			{ "greydwarfbrute", 15 },
			{ "greydwarfshaman", 15 },
			{ "skeleton", 10 },
			{ "skeletonpoison", 15 },
			{ "troll", 50 },
			{ "surtling", 15 },
			{ "leech", 15 },
			{ "draugr", 15 },
			{ "draugrelite", 30 },
			{ "blob", 20 },
			{ "wraith", 30 },
			{ "abomination", 100 },
			{ "wolf", 25 },
			{ "fenring", 30 },
			{ "hatchling", 35 },
			{ "sgolem", 100 },
			{ "ulv", 50 },
			{ "cultist", 50 },
			{ "goblin", 35 },
			{ "goblinbrute", 50 },
			{ "goblinshaman", 50 },
			{ "lox", 150 },
			{ "growth", 50 },
			{ "deathsquito", 25 },
			{ "serpent", 250 },
			{ "hare", 40 },
			{ "gjall", 150 },
			{ "tick", 50 },
			{ "dvergr", 30 },
			{ "seeker", 50 },
			{ "seekerbrute", 100 },
			{ "eikthyr", 50 },
			{ "elder", 100 },
			{ "bonemass", 150 },
			{ "dragonqueen", 200 },
			{ "goblinking", 250 },
			{ "seekerqueen", 300 },
			{ "ghost", 30 },
			{ "bjorn", 50 },
			{ "skeleton_hildir", 50 },
			{ "cultist_hildir", 50 },
			{ "bjorn_undead", 50 },
			{ "shamanbro", 100 },
			{ "brutebro", 100 },
			{ "asksvin", 100 },
			{ "bonemaw", 250 },
			{ "fallenvalkyrie", 200 },
			{ "charredarcher", 120 },
			{ "morgen", 150 },
			{ "volture", 100 },
			{ "charredmage", 150 },
			{ "charredmelee", 120 },
			{ "fader", 300 }
		};

		public Harmony Harmony { get; } = new Harmony("gg.khairex.usefultrophies.twentyonez.EpicMMOPatch");


		private void Awake()
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected O, but got Unknown
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Expected O, but got Unknown
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Expected O, but got Unknown
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: Expected O, but got Unknown
			ConfigDefinition val = new ConfigDefinition("GoldValue", "EnableSellingTrophies");
			EnableSellingTrophies = ((BaseUnityPlugin)this).Config.Bind<bool>(val, true, (ConfigDescription)null).Value;
			ConfigDefinition val2 = new ConfigDefinition("XPModifier", "ExperienceModifier");
			ExperienceModifier = ((BaseUnityPlugin)this).Config.Bind<float>(val2, 1f, (ConfigDescription)null).Value;
			List<ConfigDefinition> list = new List<ConfigDefinition>();
			foreach (string key in TrophyXPDict.Keys)
			{
				list.Add(new ConfigDefinition("ExpScaling", key));
			}
			foreach (ConfigDefinition item in list)
			{
				TrophyXPDict[item.Key] = ((BaseUnityPlugin)this).Config.Bind<float>(item, TrophyXPDict[item.Key], (ConfigDescription)null).Value;
			}
			List<ConfigDefinition> list2 = new List<ConfigDefinition>();
			foreach (string key2 in TrophyGoldValueDict.Keys)
			{
				list2.Add(new ConfigDefinition("GoldValue", key2));
			}
			foreach (ConfigDefinition item2 in list2)
			{
				TrophyGoldValueDict[item2.Key] = ((BaseUnityPlugin)this).Config.Bind<int>(item2, TrophyGoldValueDict[item2.Key], (ConfigDescription)null).Value;
			}
			Harmony.PatchAll();
		}
	}
}
namespace UsefulTrophiesXP.Properties
{
	[CompilerGenerated]
	[GeneratedCode("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.2.0.0")]
	internal sealed class Settings : ApplicationSettingsBase
	{
		private static Settings defaultInstance = (Settings)(object)SettingsBase.Synchronized((SettingsBase)(object)new Settings());

		public static Settings Default => defaultInstance;
	}
}

BepInEx/plugins/VLDamageFix.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using EpicMMOSystem;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("ValheimLegends")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ValheimLegends")]
[assembly: AssemblyCopyright("Copyright ©  2021")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("f0baf009-4135-4368-9987-850698809493")]
[assembly: AssemblyFileVersion("0.4.9.3")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.4.9.3")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace ValheimLegends
{
	public class AnimationClipOverrides : List<KeyValuePair<AnimationClip, AnimationClip>>
	{
		public AnimationClip this[string name]
		{
			get
			{
				return Find((KeyValuePair<AnimationClip, AnimationClip> x) => ((Object)x.Key).name == name).Value;
			}
			set
			{
				int num = FindIndex((KeyValuePair<AnimationClip, AnimationClip> x) => ((Object)x.Key).name == name);
				if (num != -1)
				{
					base[num] = new KeyValuePair<AnimationClip, AnimationClip>(base[num].Key, value);
				}
			}
		}

		public AnimationClipOverrides(int capacity)
			: base(capacity)
		{
		}
	}
	public class Class_Berserker
	{
		private static int Script_Layermask = LayerMask.GetMask(new string[7] { "Default", "static_solid", "Default_small", "piece_nonsolid", "vehicle", "viewblock", "piece" });

		private static int Player_Layermask = LayerMask.GetMask(new string[6] { "Default", "static_solid", "Default_small", "piece_nonsolid", "terrain", "vehicle" });

		private static GameObject GO_CastFX;

		public static void Execute_Dash(Player player, ref float altitude, ref Rigidbody playerBody)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: 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_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: Unknown result type (might be due to invalid IL or missing references)
			//IL_0149: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			//IL_0162: Unknown result type (might be due to invalid IL or missing references)
			//IL_0167: Unknown result type (might be due to invalid IL or missing references)
			//IL_016f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0174: Unknown result type (might be due to invalid IL or missing references)
			//IL_017c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_0645: Unknown result type (might be due to invalid IL or missing references)
			//IL_0659: Unknown result type (might be due to invalid IL or missing references)
			//IL_065b: Unknown result type (might be due to invalid IL or missing references)
			//IL_061a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0621: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d2: 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_01de: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0205: Unknown result type (might be due to invalid IL or missing references)
			//IL_0211: Unknown result type (might be due to invalid IL or missing references)
			//IL_028e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0299: Unknown result type (might be due to invalid IL or missing references)
			//IL_029e: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0637: Unknown result type (might be due to invalid IL or missing references)
			//IL_0241: Unknown result type (might be due to invalid IL or missing references)
			//IL_0248: Unknown result type (might be due to invalid IL or missing references)
			//IL_0221: Unknown result type (might be due to invalid IL or missing references)
			//IL_0235: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0271: Unknown result type (might be due to invalid IL or missing references)
			//IL_0276: Unknown result type (might be due to invalid IL or missing references)
			//IL_0364: Unknown result type (might be due to invalid IL or missing references)
			//IL_0366: Unknown result type (might be due to invalid IL or missing references)
			//IL_0373: Unknown result type (might be due to invalid IL or missing references)
			//IL_037a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0381: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0305: Unknown result type (might be due to invalid IL or missing references)
			//IL_030c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0313: Unknown result type (might be due to invalid IL or missing references)
			//IL_0318: Unknown result type (might be due to invalid IL or missing references)
			//IL_0325: Unknown result type (might be due to invalid IL or missing references)
			//IL_0326: Unknown result type (might be due to invalid IL or missing references)
			//IL_032d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0332: Unknown result type (might be due to invalid IL or missing references)
			//IL_0343: Unknown result type (might be due to invalid IL or missing references)
			//IL_0345: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ae: Expected O, but got Unknown
			//IL_03b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_03bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_04ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_04d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_04e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_04e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_04e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_04ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_04f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_04f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0505: Unknown result type (might be due to invalid IL or missing references)
			//IL_050a: Unknown result type (might be due to invalid IL or missing references)
			//IL_05bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_05c4: Unknown result type (might be due to invalid IL or missing references)
			Object.Instantiate<GameObject>(ZNetScene.instance.GetPrefab("sfx_perfectblock"), ((Component)player).transform.position, Quaternion.identity);
			Object.Instantiate<GameObject>(ZNetScene.instance.GetPrefab("vfx_stonegolem_attack_hit"), ((Component)player).transform.position, Quaternion.identity);
			float num = ((IEnumerable<Skill>)((Character)player).GetSkills().GetSkillList()).FirstOrDefault((Func<Skill, bool>)((Skill x) => x.m_info == ValheimLegends.DisciplineSkillDef)).m_level * (1f + Mathf.Clamp(LevelSystem.Instance.getAddPhysicDamage(0) / 40f + LevelSystem.Instance.getAddAttackSpeed(0) / 40f, 0f, 0.5f));
			float num2 = 0.6f + num * 0.015f * VL_GlobalConfigs.g_DamageModifer * VL_GlobalConfigs.c_berserkerDash;
			if (((Character)player).GetSEMan().HaveStatusEffect(StringExtensionMethods.GetStableHashCode("SE_VL_Berserk")) || ((Character)player).GetSEMan().HaveStatusEffect(StringExtensionMethods.GetStableHashCode("SE_VL_Execute")))
			{
				SE_Berserk sE_Berserk = (SE_Berserk)(object)((Character)player).GetSEMan().GetStatusEffect(StringExtensionMethods.GetStableHashCode("SE_VL_Berserk"));
				if ((Object)(object)sE_Berserk != (Object)null)
				{
					num2 *= sE_Berserk.damageModifier;
				}
			}
			Vector3 lookDir = ((Character)player).GetLookDir();
			lookDir.y = 0f;
			((Component)player).transform.rotation = Quaternion.LookRotation(lookDir);
			Vector3 val = default(Vector3);
			Vector3 forward = ((Component)player).transform.forward;
			Vector3 position = ((Component)player).transform.position;
			Vector3 val2 = ((Component)player).transform.position;
			val2.y += 0.1f;
			List<int> list = new List<int>();
			float num3 = 1f;
			int i;
			for (i = 0; i <= 10; i++)
			{
				RaycastHit val3 = default(RaycastHit);
				bool flag = false;
				for (int j = 0; j <= 10; j++)
				{
					Vector3 val4 = Vector3.MoveTowards(((Component)player).transform.position, ((Component)player).transform.position + forward * 100f, (float)i + (float)j * 0.1f);
					val4.y = val2.y;
					if (val4.y < ZoneSystem.instance.GetGroundHeight(val4))
					{
						val2.y = ZoneSystem.instance.GetGroundHeight(val4) + 1f;
						val4.y = val2.y;
					}
					flag = Physics.SphereCast(val4, 0.05f, forward, ref val3, float.PositiveInfinity, Script_Layermask);
					if (flag && Object.op_Implicit((Object)(object)((RaycastHit)(ref val3)).collider))
					{
						val = ((RaycastHit)(ref val3)).point;
						break;
					}
				}
				position = Vector3.MoveTowards(((Component)player).transform.position, ((Component)player).transform.position + forward * 100f, (float)i);
				position.y = ((ZoneSystem.instance.GetSolidHeight(position) - ZoneSystem.instance.GetGroundHeight(position) <= 1f) ? ZoneSystem.instance.GetSolidHeight(position) : ZoneSystem.instance.GetGroundHeight(position));
				if (flag && Vector3.Distance(new Vector3(position.x, val2.y, position.z), val) <= 1f)
				{
					val2 = Vector3.MoveTowards(val, val2, 1f);
					Object.Instantiate<GameObject>(ZNetScene.instance.GetPrefab("vfx_beehive_hit"), val2, Quaternion.identity);
					break;
				}
				Object.Instantiate<GameObject>(ZNetScene.instance.GetPrefab("vfx_beehive_hit"), val2, Quaternion.identity);
				((Vector3)(ref val2))..ctor(position.x, val2.y, position.z);
				foreach (Character allCharacter in Character.GetAllCharacters())
				{
					HitData val5 = new HitData();
					val5.m_damage = ((Humanoid)player).GetCurrentWeapon().GetDamage();
					if (((Character)player).GetSEMan().HaveStatusEffect(StringExtensionMethods.GetStableHashCode("SE_VL_DruidFenringForm")) && Class_Monk.PlayerIsBareHanded && val5.m_damage.m_blunt > 0f)
					{
						float num4 = ((IEnumerable<Skill>)((Character)player).GetSkills().GetSkillList()).FirstOrDefault((Func<Skill, bool>)((Skill x) => x.m_info == ValheimLegends.DisciplineSkillDef)).m_level * (1f + Mathf.Clamp(LevelSystem.Instance.getAddPhysicDamage(0) / 40f + LevelSystem.Instance.getAddAttackSpeed(0) / 40f, 0f, 0.5f));
						float num5 = (float)LevelSystem.Instance.getLevel() * (1f + num4 / 80f) * 0.25f;
						val5.m_damage.m_blunt += num5;
						val5.m_damage.m_slash += num5;
					}
					val5.ApplyModifier(Random.Range(0.8f, 1.2f) * num2 / num3);
					val5.m_point = allCharacter.GetCenterPoint();
					val5.m_dir = ((Component)allCharacter).transform.position - position;
					val5.m_skill = ValheimLegends.DisciplineSkill;
					float num6 = Vector3.Distance(((Component)allCharacter).transform.position, position);
					if (!BaseAI.IsEnemy(allCharacter, (Character)(object)player) || !(num6 <= 3f) || list.Contains(((Object)allCharacter).GetInstanceID()))
					{
						continue;
					}
					SE_Execute sE_Execute = (SE_Execute)(object)((Character)player).GetSEMan().GetStatusEffect(StringExtensionMethods.GetStableHashCode("SE_VL_Execute"));
					if ((Object)(object)sE_Execute != (Object)null)
					{
						val5.ApplyModifier(sE_Execute.damageBonus);
						sE_Execute.hitCount--;
						if (sE_Execute.hitCount <= 0)
						{
							((Character)player).GetSEMan().RemoveStatusEffect((StatusEffect)(object)sE_Execute, false);
						}
					}
					num3 += 0.6f;
					allCharacter.Damage(val5);
					Object.Instantiate<GameObject>(ZNetScene.instance.GetPrefab("fx_crit"), allCharacter.GetCenterPoint(), Quaternion.identity);
					list.Add(((Object)allCharacter).GetInstanceID());
				}
			}
			list.Clear();
			if (i > 10 && ZoneSystem.instance.GetSolidHeight(val2) - val2.y <= 2f)
			{
				val2.y = ZoneSystem.instance.GetSolidHeight(val2);
			}
			playerBody.position = val2;
			altitude = 0f;
			((Component)player).transform.rotation = Quaternion.LookRotation(forward);
		}

		public static void Process_Input(Player player, ref float altitude)
		{
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: 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_01e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0524: Unknown result type (might be due to invalid IL or missing references)
			new Random();
			if (VL_Utility.Ability3_Input_Down)
			{
				if (!((Character)player).GetSEMan().HaveStatusEffect(StringExtensionMethods.GetStableHashCode("SE_VL_Ability3_CD")))
				{
					if (player.GetStamina() > VL_Utility.GetDashCost(player))
					{
						StatusEffect val = (StatusEffect)(object)(SE_Ability3_CD)(object)ScriptableObject.CreateInstance(typeof(SE_Ability3_CD));
						val.m_ttl = VL_Utility.GetDashCooldown(player);
						((Character)player).GetSEMan().AddStatusEffect(val, false, 0, 0f);
						((Character)player).UseStamina(VL_Utility.GetDashCost(player));
						((ZSyncAnimation)typeof(Player).GetField("m_zanim", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(player)).SetTrigger("swing_longsword2");
						Object.Instantiate<GameObject>(ZNetScene.instance.GetPrefab("vfx_Potion_stamina_medium"), ((Component)player).transform.position, Quaternion.identity);
						ValheimLegends.isChargingDash = true;
						ValheimLegends.dashCounter = 0;
						((Character)player).RaiseSkill(ValheimLegends.DisciplineSkill, VL_Utility.GetDashSkillGain(player));
					}
					else
					{
						((Character)player).Message((MessageType)1, "Not enough stamina for Dash: (" + player.GetStamina().ToString("#.#") + "/" + VL_Utility.GetDashCost(player) + ")", 0, (Sprite)null);
					}
				}
				else
				{
					((Character)player).Message((MessageType)1, "Ability not ready", 0, (Sprite)null);
				}
			}
			else if (VL_Utility.Ability2_Input_Down)
			{
				if (!((Character)player).GetSEMan().HaveStatusEffect(StringExtensionMethods.GetStableHashCode("SE_VL_Ability2_CD")))
				{
					if (player.GetStamina() > VL_Utility.GetBerserkCost(player))
					{
						StatusEffect val2 = (StatusEffect)(object)(SE_Ability2_CD)(object)ScriptableObject.CreateInstance(typeof(SE_Ability2_CD));
						val2.m_ttl = VL_Utility.GetBerserkCooldown(player);
						((Character)player).GetSEMan().AddStatusEffect(val2, false, 0, 0f);
						((Character)player).UseStamina(VL_Utility.GetBerserkCost(player));
						ValheimLegends.shouldUseGuardianPower = false;
						player.StartEmote("challenge", true);
						Object.Instantiate<GameObject>(ZNetScene.instance.GetPrefab("fx_GP_Stone"), ((Character)player).GetCenterPoint(), Quaternion.identity);
						float num = ((IEnumerable<Skill>)((Character)player).GetSkills().GetSkillList()).FirstOrDefault((Func<Skill, bool>)((Skill x) => x.m_info == ValheimLegends.AlterationSkillDef)).m_level * (1f + Mathf.Clamp(LevelSystem.Instance.getAddCriticalChance(0) / 40f + LevelSystem.Instance.getAddMagicDamage(0) / 80f, 0f, 0.5f));
						SE_Berserk sE_Berserk = (SE_Berserk)(object)ScriptableObject.CreateInstance(typeof(SE_Berserk));
						((StatusEffect)sE_Berserk).m_ttl = SE_Berserk.m_baseTTL;
						sE_Berserk.speedModifier = 1.2f + 0.006f * num;
						sE_Berserk.damageModifier = 1.2f + 0.006f * num * VL_GlobalConfigs.g_DamageModifer * VL_GlobalConfigs.c_berserkerBerserk;
						sE_Berserk.healthAbsorbPercent = 0.2f + 0.002f * num;
						((Character)player).GetSEMan().AddStatusEffect((StatusEffect)(object)sE_Berserk, false, 0, 0f);
						((Character)player).RaiseSkill(ValheimLegends.AlterationSkill, VL_Utility.GetBerserkSkillGain(player));
					}
					else
					{
						((Character)player).Message((MessageType)1, "Not enough stamina for Berserk: (" + player.GetStamina().ToString("#.#") + "/" + VL_Utility.GetBerserkCost(player) + ")", 0, (Sprite)null);
					}
				}
				else
				{
					((Character)player).Message((MessageType)1, "Ability not ready", 0, (Sprite)null);
				}
			}
			else
			{
				if (!VL_Utility.Ability1_Input_Down)
				{
					return;
				}
				if (!((Character)player).GetSEMan().HaveStatusEffect(StringExtensionMethods.GetStableHashCode("SE_VL_Ability1_CD")))
				{
					if (player.GetStamina() > VL_Utility.GetExecuteCost(player))
					{
						StatusEffect val3 = (StatusEffect)(object)(SE_Ability1_CD)(object)ScriptableObject.CreateInstance(typeof(SE_Ability1_CD));
						val3.m_ttl = VL_Utility.GetExecuteCooldown(player);
						((Character)player).GetSEMan().AddStatusEffect(val3, false, 0, 0f);
						((Character)player).UseStamina(VL_Utility.GetExecuteCost(player));
						player.StartEmote("point", true);
						Object.Instantiate<GameObject>(ZNetScene.instance.GetPrefab("fx_backstab"), ((Character)player).GetCenterPoint(), Quaternion.identity);
						float num2 = ((IEnumerable<Skill>)((Character)player).GetSkills().GetSkillList()).FirstOrDefault((Func<Skill, bool>)((Skill x) => x.m_info == ValheimLegends.DisciplineSkillDef)).m_level * (1f + Mathf.Clamp(LevelSystem.Instance.getAddPhysicDamage(0) / 40f + LevelSystem.Instance.getAddAttackSpeed(0) / 40f, 0f, 0.5f));
						SE_Execute sE_Execute = (SE_Execute)(object)ScriptableObject.CreateInstance(typeof(SE_Execute));
						sE_Execute.hitCount = Mathf.RoundToInt(3f + 0.04f * num2);
						sE_Execute.damageBonus = 1.4f + 0.005f * num2 * VL_GlobalConfigs.g_DamageModifer * VL_GlobalConfigs.c_berserkerExecute;
						sE_Execute.staggerForce = 1.5f + 0.005f * num2;
						if (((Character)player).GetSEMan().HaveStatusEffect(StringExtensionMethods.GetStableHashCode("SE_VL_Execute")))
						{
							StatusEffect statusEffect = ((Character)player).GetSEMan().GetStatusEffect(StringExtensionMethods.GetStableHashCode("SE_VL_Execute"));
							((Character)player).GetSEMan().RemoveStatusEffect(statusEffect, false);
						}
						((Character)player).GetSEMan().AddStatusEffect((StatusEffect)(object)sE_Execute, false, 0, 0f);
						((Character)player).RaiseSkill(ValheimLegends.DisciplineSkill, VL_Utility.GetExecuteSkillGain(player));
					}
					else
					{
						((Character)player).Message((MessageType)1, "Not enough stamina for Execute: (" + player.GetStamina().ToString("#.#") + "/" + VL_Utility.GetExecuteCost(player) + ")", 0, (Sprite)null);
					}
				}
				else
				{
					((Character)player).Message((MessageType)1, "Ability not ready", 0, (Sprite)null);
				}
			}
		}
	}
	public class Class_Druid
	{
		private static int Script_Layermask = LayerMask.GetMask(new string[11]
		{
			"Default", "static_solid", "Default_small", "piece_nonsolid", "terrain", "vehicle", "piece", "viewblock", "character", "character_net",
			"character_ghost"
		});

		private static GameObject GO_CastFX;

		private static GameObject GO_Root;

		private static Projectile P_Root;

		private static StatusEffect SE_Root;

		private static GameObject GO_RootDefender;

		private static int rootCount;

		private static int rootTotal;

		private static int rootCountTrigger;

		public static bool canDoubleJump = true;

		public static readonly int SE_FENRING_HASH = StringExtensionMethods.GetStableHashCode("SE_VL_DruidFenringForm");

		public static readonly int SE_CULTIST_HASH = StringExtensionMethods.GetStableHashCode("SE_VL_DruidCultistForm");

		private static readonly MethodInfo MI_GetRightItem = AccessTools.Method(typeof(Humanoid), "GetRightItem", (Type[])null, (Type[])null);

		private static readonly MethodInfo MI_GetLeftItem = AccessTools.Method(typeof(Humanoid), "GetLeftItem", (Type[])null, (Type[])null);

		private static readonly FieldInfo FI_RightItem = AccessTools.Field(typeof(Humanoid), "m_rightItem");

		private static readonly FieldInfo FI_LeftItem = AccessTools.Field(typeof(Humanoid), "m_leftItem");

		private static readonly MethodInfo MI_UpdateEquipmentVisuals = AccessTools.Method(typeof(Humanoid), "UpdateEquipmentVisuals", (Type[])null, (Type[])null);

		public static void Process_FenringForm(Player player, float altitude, ref Rigidbody playerBody)
		{
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			if (ZInput.GetButtonDown("Jump") && !((Character)player).IsDead() && !((Character)player).InAttack() && !((Character)player).IsEncumbered() && !((Character)player).InDodge() && !((Character)player).IsKnockedBack())
			{
				if (!((Character)player).IsOnGround() && canDoubleJump)
				{
					Vector3 velocity = ((Character)player).GetVelocity();
					velocity.y = 0f;
					playerBody.linearVelocity = velocity * 2f + new Vector3(0f, 8f, 0f);
					canDoubleJump = false;
					altitude = 0f;
					((ZSyncAnimation)typeof(Player).GetField("m_zanim", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(player)).SetTrigger("jump");
				}
				else if (((Character)player).IsOnGround())
				{
					canDoubleJump = true;
				}
			}
			if (VL_Utility.Ability1_Input_Down)
			{
				VL_AbilityBorrow.Ranger_ShadowStalk(player);
			}
			else if (VL_Utility.Ability2_Input_Down)
			{
				if (((Character)player).IsBlocking())
				{
					TryActivate_HumanForm(player, forced: false);
				}
				else
				{
					VL_AbilityBorrow.Valkyrie_Stagger(player);
				}
			}
			else if (VL_Utility.Ability3_Input_Down)
			{
				VL_AbilityBorrow.Berserker_Dash(player);
			}
		}

		public static void Process_Input(Player player, float altitude, ref Rigidbody playerBody)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_03bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			//IL_017b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			//IL_0790: Unknown result type (might be due to invalid IL or missing references)
			//IL_079c: Unknown result type (might be due to invalid IL or missing references)
			//IL_07a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_07a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_07aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01be: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01de: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0205: Unknown result type (might be due to invalid IL or missing references)
			//IL_020a: Unknown result type (might be due to invalid IL or missing references)
			//IL_028e: Unknown result type (might be due to invalid IL or missing references)
			//IL_029f: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0197: Unknown result type (might be due to invalid IL or missing references)
			//IL_019d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_07d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_07dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_07e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_07eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_05c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_05cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_05d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_08f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_08f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0909: Unknown result type (might be due to invalid IL or missing references)
			//IL_090b: Unknown result type (might be due to invalid IL or missing references)
			//IL_07f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_07f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_07f9: Expected O, but got Unknown
			//IL_0828: Unknown result type (might be due to invalid IL or missing references)
			//IL_082d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0834: Unknown result type (might be due to invalid IL or missing references)
			//IL_0839: Unknown result type (might be due to invalid IL or missing references)
			//IL_0841: Unknown result type (might be due to invalid IL or missing references)
			//IL_084d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0852: Unknown result type (might be due to invalid IL or missing references)
			//IL_085c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0883: Unknown result type (might be due to invalid IL or missing references)
			//IL_07d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0600: Unknown result type (might be due to invalid IL or missing references)
			//IL_060b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0615: Unknown result type (might be due to invalid IL or missing references)
			//IL_061a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0620: Unknown result type (might be due to invalid IL or missing references)
			//IL_062a: Unknown result type (might be due to invalid IL or missing references)
			//IL_062f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0634: Unknown result type (might be due to invalid IL or missing references)
			//IL_0636: Unknown result type (might be due to invalid IL or missing references)
			//IL_063b: Unknown result type (might be due to invalid IL or missing references)
			//IL_064b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0651: Unknown result type (might be due to invalid IL or missing references)
			//IL_0657: Unknown result type (might be due to invalid IL or missing references)
			//IL_065d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0662: Unknown result type (might be due to invalid IL or missing references)
			//IL_06e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_06fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_06ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_05ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_05f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_05f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0467: Unknown result type (might be due to invalid IL or missing references)
			//IL_0473: Unknown result type (might be due to invalid IL or missing references)
			//IL_0478: Unknown result type (might be due to invalid IL or missing references)
			//IL_047b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0481: Unknown result type (might be due to invalid IL or missing references)
			//IL_09ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_0a10: Unknown result type (might be due to invalid IL or missing references)
			//IL_0a15: Unknown result type (might be due to invalid IL or missing references)
			//IL_0733: Unknown result type (might be due to invalid IL or missing references)
			//IL_073d: Unknown result type (might be due to invalid IL or missing references)
			//IL_071a: Unknown result type (might be due to invalid IL or missing references)
			//IL_071f: Unknown result type (might be due to invalid IL or missing references)
			//IL_04b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_04b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_04bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_04c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_12d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_12d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_12fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_1302: Unknown result type (might be due to invalid IL or missing references)
			//IL_1390: Unknown result type (might be due to invalid IL or missing references)
			//IL_0a8b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0a91: Unknown result type (might be due to invalid IL or missing references)
			//IL_0a9b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0aa0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0aab: Unknown result type (might be due to invalid IL or missing references)
			//IL_0ab5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0aba: Unknown result type (might be due to invalid IL or missing references)
			//IL_0abf: Unknown result type (might be due to invalid IL or missing references)
			//IL_0ac2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0ace: Unknown result type (might be due to invalid IL or missing references)
			//IL_0ad4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0ade: Unknown result type (might be due to invalid IL or missing references)
			//IL_0ae3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0aee: Unknown result type (might be due to invalid IL or missing references)
			//IL_0af8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b02: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b07: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b0c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b0f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b1b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b21: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b2b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b35: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b3a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b3f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b42: Unknown result type (might be due to invalid IL or missing references)
			//IL_04c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_04c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_04d0: Expected O, but got Unknown
			//IL_052b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0530: Unknown result type (might be due to invalid IL or missing references)
			//IL_0537: Unknown result type (might be due to invalid IL or missing references)
			//IL_053c: Unknown result type (might be due to invalid IL or missing references)
			//IL_04a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0fd1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b56: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b5b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0567: Unknown result type (might be due to invalid IL or missing references)
			//IL_0573: Unknown result type (might be due to invalid IL or missing references)
			//IL_0578: Unknown result type (might be due to invalid IL or missing references)
			//IL_0582: Unknown result type (might be due to invalid IL or missing references)
			//IL_05a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0c6a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0c6f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0beb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0bf0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0c35: Unknown result type (might be due to invalid IL or missing references)
			//IL_0c3a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0c47: Unknown result type (might be due to invalid IL or missing references)
			//IL_144c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0d04: Unknown result type (might be due to invalid IL or missing references)
			//IL_0d0f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0d19: Unknown result type (might be due to invalid IL or missing references)
			//IL_0d1e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0d24: Unknown result type (might be due to invalid IL or missing references)
			//IL_0d50: Unknown result type (might be due to invalid IL or missing references)
			//IL_0d5b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0d87: Unknown result type (might be due to invalid IL or missing references)
			//IL_0d8c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0d91: Unknown result type (might be due to invalid IL or missing references)
			//IL_0d96: Unknown result type (might be due to invalid IL or missing references)
			//IL_0d99: Unknown result type (might be due to invalid IL or missing references)
			//IL_0d9a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0e8f: Unknown result type (might be due to invalid IL or missing references)
			//IL_112e: Unknown result type (might be due to invalid IL or missing references)
			//IL_1139: Unknown result type (might be due to invalid IL or missing references)
			//IL_113e: Unknown result type (might be due to invalid IL or missing references)
			//IL_1143: Unknown result type (might be due to invalid IL or missing references)
			//IL_0e6f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0e74: Unknown result type (might be due to invalid IL or missing references)
			//IL_0e3a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0e3f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0e4c: Unknown result type (might be due to invalid IL or missing references)
			//IL_11c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_11c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_11e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_11ea: Unknown result type (might be due to invalid IL or missing references)
			if (((Character)player).GetSEMan().HaveStatusEffect(SE_FENRING_HASH))
			{
				Process_FenringForm(player, altitude, ref playerBody);
				return;
			}
			new Random();
			Vector3 val = default(Vector3);
			if (VL_Utility.Ability3_Input_Down)
			{
				if (!((Character)player).GetSEMan().HaveStatusEffect(StringExtensionMethods.GetStableHashCode("SE_VL_Ability3_CD")))
				{
					ValheimLegends.shouldUseGuardianPower = false;
					if (player.GetStamina() >= VL_Utility.GetRootCost && !ValheimLegends.isChanneling)
					{
						ValheimLegends.isChanneling = true;
						ValheimLegends.channelingBlocksMovement = false;
						StatusEffect val2 = (StatusEffect)(object)(SE_Ability3_CD)(object)ScriptableObject.CreateInstance(typeof(SE_Ability3_CD));
						val2.m_ttl = VL_Utility.GetRootCooldownTime;
						((Character)player).GetSEMan().AddStatusEffect(val2, false, 0, 0f);
						((Character)player).UseStamina(VL_Utility.GetRootCost);
						player.StartEmote("point", true);
						float num = ((IEnumerable<Skill>)((Character)player).GetSkills().GetSkillList()).FirstOrDefault((Func<Skill, bool>)((Skill x) => x.m_info == ValheimLegends.ConjurationSkillDef)).m_level * (1f + Mathf.Clamp(LevelSystem.Instance.getAddStamina(0) / 200f + LevelSystem.Instance.getAddMagicDamage(0) / 80f, 0f, 0.5f));
						rootCount = 0;
						rootCountTrigger = 16 - Mathf.RoundToInt(0.05f * num - 7.5f * (LevelSystem.Instance.getAddMagicDamage(0) / 80f));
						rootTotal = 0;
						Vector3 val3 = ((Component)player).transform.right * 2.5f;
						if (Random.Range(0f, 1f) < 0.5f)
						{
							val3 *= -1f;
						}
						val = ((Component)player).transform.position + ((Component)player).transform.up * 3f + ((Character)player).GetLookDir() * 2f + val3;
						GO_Root = Object.Instantiate<GameObject>(ZNetScene.instance.GetPrefab("gdking_root_projectile"), new Vector3(val.x, val.y, val.z), Quaternion.identity);
						P_Root = GO_Root.GetComponent<Projectile>();
						((Object)P_Root).name = "VL_DruidRoot";
						P_Root.m_respawnItemOnHit = false;
						P_Root.m_spawnOnHit = null;
						P_Root.m_ttl = 35f;
						P_Root.m_gravity = 0f;
						P_Root.m_rayRadius = 0.1f;
						Traverse.Create((object)P_Root).Field("m_skill").SetValue((object)ValheimLegends.ConjurationSkill);
						Vector3 lookDir = ((Character)player).GetLookDir();
						if (((Vector3)(ref lookDir)).sqrMagnitude > 1E-06f)
						{
							((Component)P_Root).transform.localRotation = Quaternion.LookRotation(((Character)player).GetLookDir());
						}
						GO_Root.transform.localScale = Vector3.one * 1.5f;
						((Character)player).RaiseSkill(ValheimLegends.ConjurationSkill, VL_Utility.GetRootSkillGain);
					}
					else
					{
						((Character)player).Message((MessageType)1, "Not enough stamina to channel Root: (" + player.GetStamina().ToString("#.#") + "/" + VL_Utility.GetRootCost + ")", 0, (Sprite)null);
					}
				}
				else
				{
					((Character)player).Message((MessageType)1, "Ability not ready", 0, (Sprite)null);
				}
			}
			else if (VL_Utility.Ability3_Input_Pressed && player.GetStamina() > VL_Utility.GetRootCostPerUpdate && ValheimLegends.isChanneling)
			{
				rootCount++;
				VL_Utility.SetTimer();
				((Character)player).UseStamina(VL_Utility.GetRootCostPerUpdate * (float)rootTotal);
				ValheimLegends.isChanneling = true;
				if (rootCount < rootCountTrigger)
				{
					return;
				}
				((Character)player).RaiseSkill(ValheimLegends.ConjurationSkill, 0.06f);
				float num2 = ((IEnumerable<Skill>)((Character)player).GetSkills().GetSkillList()).FirstOrDefault((Func<Skill, bool>)((Skill x) => x.m_info == ValheimLegends.ConjurationSkillDef)).m_level * (1f + Mathf.Clamp(LevelSystem.Instance.getAddStamina(0) / 200f + LevelSystem.Instance.getAddMagicDamage(0) / 80f, 0f, 0.5f));
				rootCount = 0;
				if ((Object)(object)GO_Root != (Object)null && (Object)(object)GO_Root.transform != (Object)null)
				{
					RaycastHit val4 = default(RaycastHit);
					Vector3 position = ((Component)player).transform.position;
					Vector3 val5 = ((!Physics.Raycast(((Character)player).GetEyePoint(), ((Character)player).GetLookDir(), ref val4, float.PositiveInfinity, Script_Layermask) || !Object.op_Implicit((Object)(object)((RaycastHit)(ref val4)).collider)) ? (position + ((Character)player).GetLookDir() * 1000f) : ((RaycastHit)(ref val4)).point);
					HitData val6 = new HitData();
					val6.m_damage.m_pierce = Random.Range(10f + 0.6f * num2, 15f + 1.2f * num2) * VL_GlobalConfigs.g_DamageModifer * VL_GlobalConfigs.c_druidVines;
					val6.m_pushForce = 2f;
					rootTotal++;
					Vector3 val7 = Vector3.MoveTowards(GO_Root.transform.position, val5, 1f);
					if ((Object)(object)P_Root != (Object)null && ((Object)P_Root).name == "VL_DruidRoot")
					{
						P_Root.Setup((Character)(object)player, (val7 - GO_Root.transform.position) * 75f, -1f, val6, (ItemData)null, (ItemData)null);
						Traverse.Create((object)P_Root).Field("m_skill").SetValue((object)ValheimLegends.ConjurationSkill);
					}
				}
				GO_Root = null;
				Vector3 val8 = ((Component)player).transform.right * 2.5f;
				if (Random.Range(0f, 1f) < 0.5f)
				{
					val8 *= -1f;
				}
				val = ((Component)player).transform.position + ((Component)player).transform.up * 3f + ((Character)player).GetLookDir() * 2f + val8;
				GO_Root = Object.Instantiate<GameObject>(ZNetScene.instance.GetPrefab("gdking_root_projectile"), new Vector3(val.x, val.y, val.z), Quaternion.identity);
				P_Root = GO_Root.GetComponent<Projectile>();
				((Object)P_Root).name = "VL_DruidRoot";
				P_Root.m_respawnItemOnHit = false;
				P_Root.m_spawnOnHit = null;
				P_Root.m_ttl = rootCountTrigger + 1;
				P_Root.m_gravity = 0f;
				P_Root.m_rayRadius = 0.1f;
				Traverse.Create((object)P_Root).Field("m_skill").SetValue((object)ValheimLegends.ConjurationSkill);
				Vector3 lookDir2 = ((Character)player).GetLookDir();
				if (((Vector3)(ref lookDir2)).sqrMagnitude > 1E-06f)
				{
					((Component)P_Root).transform.localRotation = Quaternion.LookRotation(((Character)player).GetLookDir());
				}
				GO_Root.transform.localScale = Vector3.one * 1.5f;
			}
			else if ((VL_Utility.Ability3_Input_Up || player.GetStamina() <= VL_Utility.GetRootCostPerUpdate) && ValheimLegends.isChanneling)
			{
				if ((Object)(object)GO_Root != (Object)null && (Object)(object)GO_Root.transform != (Object)null)
				{
					RaycastHit val9 = default(RaycastHit);
					Vector3 position2 = ((Component)player).transform.position;
					Vector3 val10 = ((!Physics.Raycast(((Character)player).GetEyePoint(), ((Character)player).GetLookDir(), ref val9, float.PositiveInfinity, Script_Layermask) || !Object.op_Implicit((Object)(object)((RaycastHit)(ref val9)).collider)) ? (position2 + ((Character)player).GetLookDir() * 1000f) : ((RaycastHit)(ref val9)).point);
					HitData val11 = new HitData();
					val11.m_damage.m_pierce = 10f;
					val11.m_pushForce = 10f;
					val11.SetAttacker((Character)(object)player);
					Vector3 val12 = Vector3.MoveTowards(GO_Root.transform.position, val10, 1f);
					P_Root.Setup((Character)(object)player, (val12 - GO_Root.transform.position) * 65f, -1f, val11, (ItemData)null, (ItemData)null);
					Traverse.Create((object)P_Root).Field("m_skill").SetValue((object)ValheimLegends.ConjurationSkill);
				}
				rootTotal = 0;
				GO_Root = null;
				ValheimLegends.isChanneling = false;
				ValheimLegends.channelingBlocksMovement = true;
			}
			else if (VL_Utility.Ability2_Input_Down)
			{
				if (((Character)player).IsBlocking())
				{
					TryActivate_FenringForm(player);
				}
				else if (!((Character)player).GetSEMan().HaveStatusEffect(StringExtensionMethods.GetStableHashCode("SE_VL_Ability2_CD")))
				{
					if (player.GetStamina() >= VL_Utility.GetDefenderCost)
					{
						Vector3 lookDir3 = ((Character)player).GetLookDir();
						lookDir3.y = 0f;
						((Component)player).transform.rotation = Quaternion.LookRotation(lookDir3);
						ValheimLegends.shouldUseGuardianPower = false;
						StatusEffect val13 = (StatusEffect)(object)(SE_Ability2_CD)(object)ScriptableObject.CreateInstance(typeof(SE_Ability2_CD));
						val13.m_ttl = VL_Utility.GetDefenderCooldownTime;
						((Character)player).GetSEMan().AddStatusEffect(val13, false, 0, 0f);
						((Character)player).UseStamina(VL_Utility.GetDefenderCost);
						float num3 = ((IEnumerable<Skill>)((Character)player).GetSkills().GetSkillList()).FirstOrDefault((Func<Skill, bool>)((Skill x) => x.m_info == ValheimLegends.ConjurationSkillDef)).m_level * (1f + Mathf.Clamp(LevelSystem.Instance.getAddStamina(0) / 200f + LevelSystem.Instance.getAddMagicDamage(0) / 80f, 0f, 0.5f));
						((ZSyncAnimation)typeof(Player).GetField("m_zanim", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(Player.m_localPlayer)).SetTrigger("gpower");
						Object.Instantiate<GameObject>(ZNetScene.instance.GetPrefab("vfx_WishbonePing"), ((Component)player).transform.position, Quaternion.identity);
						GameObject prefab = ZNetScene.instance.GetPrefab("TentaRoot");
						CharacterTimedDestruction component = prefab.GetComponent<CharacterTimedDestruction>();
						if ((Object)(object)component != (Object)null)
						{
							component.m_timeoutMin = 24f + 0.3f * num3;
							component.m_timeoutMax = component.m_timeoutMin;
							component.m_triggerOnAwake = true;
							((Behaviour)component).enabled = true;
						}
						List<Vector3> list = new List<Vector3>();
						list.Clear();
						val = ((Component)player).transform.position + ((Character)player).GetLookDir() * 5f + ((Component)player).transform.right * 5f;
						list.Add(val);
						val = ((Component)player).transform.position + ((Character)player).GetLookDir() * 5f + ((Component)player).transform.right * 5f * -1f;
						list.Add(val);
						val = ((Component)player).transform.position + ((Character)player).GetLookDir() * 5f * -1f;
						list.Add(val);
						for (int i = 0; i < list.Count; i++)
						{
							GO_RootDefender = Object.Instantiate<GameObject>(prefab, list[i], Quaternion.identity);
							Character component2 = GO_RootDefender.GetComponent<Character>();
							if ((Object)(object)component2 != (Object)null)
							{
								SE_RootsBuff sE_RootsBuff = (SE_RootsBuff)(object)ScriptableObject.CreateInstance(typeof(SE_RootsBuff));
								((StatusEffect)sE_RootsBuff).m_ttl = SE_RootsBuff.m_baseTTL;
								sE_RootsBuff.damageModifier = 0.5f + 0.015f * num3 * VL_GlobalConfigs.g_DamageModifer * VL_GlobalConfigs.c_druidDefenders;
								sE_RootsBuff.staminaRegen = 0.5f + 0.05f * num3;
								sE_RootsBuff.summoner = player;
								sE_RootsBuff.centerPoint = ((Component)player).transform.position;
								component2.GetSEMan().AddStatusEffect((StatusEffect)(object)sE_RootsBuff, false, 0, 0f);
								component2.SetMaxHealth(30f + 6f * num3);
								((Component)component2).transform.localScale = (0.75f + 0.005f * num3) * Vector3.one;
								component2.m_faction = (Faction)0;
								component2.SetTamed(true);
							}
							Object.Instantiate<GameObject>(ZNetScene.instance.GetPrefab("vfx_Potion_stamina_medium"), ((Component)component2).transform.position, Quaternion.identity);
						}
						GameObject prefab2 = ZNetScene.instance.GetPrefab("VL_Deathsquit");
						CharacterTimedDestruction component3 = prefab2.GetComponent<CharacterTimedDestruction>();
						if ((Object)(object)component3 != (Object)null)
						{
							component3.m_timeoutMin = 24f + 0.3f * num3;
							component3.m_timeoutMax = component3.m_timeoutMin;
							component3.m_triggerOnAwake = true;
							((Behaviour)component3).enabled = true;
						}
						int num4 = 2 + Mathf.RoundToInt(0.05f * num3);
						for (int j = 0; j < num4; j++)
						{
							val = ((Component)player).transform.position + ((Component)player).transform.up * 4f + (((Character)player).GetLookDir() * Random.Range(0f - (5f + 0.1f * num3), 5f + 0.1f * num3) + ((Component)player).transform.right * Random.Range(0f - (5f + 0.1f * num3), 5f + 0.1f * num3));
							Character component4 = Object.Instantiate<GameObject>(prefab2, val, Quaternion.identity).GetComponent<Character>();
							component4.m_name = "Drusquito";
							if ((Object)(object)component4 != (Object)null)
							{
								SE_Companion sE_Companion = (SE_Companion)(object)ScriptableObject.CreateInstance(typeof(SE_Companion));
								((StatusEffect)sE_Companion).m_ttl = 60f;
								sE_Companion.damageModifier = 0.05f + 0.0075f * num3 * VL_GlobalConfigs.g_DamageModifer * VL_GlobalConfigs.c_druidDefenders;
								sE_Companion.summoner = player;
								component4.GetSEMan().AddStatusEffect((StatusEffect)(object)sE_Companion, false, 0, 0f);
								((Component)component4).transform.localScale = (0.4f + 0.005f * num3) * Vector3.one;
								component4.m_faction = (Faction)0;
								component4.SetTamed(true);
							}
							Object.Instantiate<GameObject>(ZNetScene.instance.GetPrefab("fx_float_hitwater"), ((Component)component4).transform.position, Quaternion.identity);
						}
						((Character)player).RaiseSkill(ValheimLegends.ConjurationSkill, VL_Utility.GetDefenderSkillGain);
					}
					else
					{
						((Character)player).Message((MessageType)1, "Not enough stamina to summon root defenders: (" + player.GetStamina().ToString("#.#") + "/" + VL_Utility.GetDefenderCost + ")", 0, (Sprite)null);
					}
				}
				else
				{
					((Character)player).Message((MessageType)1, "Ability not ready", 0, (Sprite)null);
				}
			}
			else if (VL_Utility.Ability1_Input_Down)
			{
				if (!((Character)player).GetSEMan().HaveStatusEffect(StringExtensionMethods.GetStableHashCode("SE_VL_Ability1_CD")))
				{
					if (((Character)player).IsBlocking())
					{
						Inventory inventory = ((Humanoid)player).GetInventory();
						if (inventory == null)
						{
							return;
						}
						int requiredAmount = 1;
						string text = "AncientSeed";
						ItemData val14 = VL_Utility.FindItemByPrefabName(inventory, text, requiredAmount);
						if (val14 == null)
						{
							((Character)player).Message((MessageType)2, "You need an Ancient Seed to create a Spirit Binding Vial.", 0, (Sprite)null);
							return;
						}
						if (player.GetStamina() < VL_Utility.GetRegenerationCost)
						{
							((Character)player).Message((MessageType)1, "Not enough stamina to Create Spirit Binding Vial: (" + player.GetStamina().ToString("#.#") + "/" + VL_Utility.GetRegenerationCost.ToString("#.#") + ")", 0, (Sprite)null);
							return;
						}
						((Character)player).RaiseSkill(ValheimLegends.AlterationSkill, VL_Utility.GetRegenerationSkillGain);
						StatusEffect val15 = (StatusEffect)(object)(SE_Ability1_CD)(object)ScriptableObject.CreateInstance(typeof(SE_Ability1_CD));
						float num5 = ((IEnumerable<Skill>)((Character)player).GetSkills().GetSkillList()).FirstOrDefault((Func<Skill, bool>)((Skill x) => x.m_info == ValheimLegends.AlterationSkillDef)).m_level * (1f + Mathf.Clamp(LevelSystem.Instance.getAddCriticalChance(0) / 40f + LevelSystem.Instance.getAddMagicDamage(0) / 80f, 0f, 0.5f));
						val15.m_ttl = VL_Utility.GetHealCooldownTime * 20f / (1f + num5 / 150f);
						((Character)player).GetSEMan().AddStatusEffect(val15, false, 0, 0f);
						((Character)player).UseStamina(VL_Utility.GetRegenerationCost);
						inventory.RemoveOneItem(val14);
						if ((Object)(object)ZNetScene.instance == (Object)null)
						{
							Debug.Log((object)"ZNetScene not ready.");
							return;
						}
						GameObject prefab3 = ZNetScene.instance.GetPrefab("questitem_wraiths_breath");
						if ((Object)(object)prefab3 == (Object)null)
						{
							Debug.Log((object)"Prefab not found: questitem_wraiths_breath");
							return;
						}
						ItemDrop component5 = prefab3.GetComponent<ItemDrop>();
						if ((Object)(object)component5 == (Object)null)
						{
							Debug.Log((object)"Prefab has no ItemDrop: questitem_wraiths_breath");
							return;
						}
						ItemData val16 = component5.m_itemData.Clone();
						if (!inventory.AddItem(val16))
						{
							ItemDrop.DropItem(val16, 1, ((Component)player).transform.position + ((Component)player).transform.forward, Quaternion.identity);
							((Character)player).Message((MessageType)1, "Inventory full. Dropped Spirit Binding Vial on the ground.", 0, (Sprite)null);
						}
						else
						{
							((Character)player).Message((MessageType)1, "Consumed 1 " + text + " to create a " + val16.m_shared.m_name + ".", 0, (Sprite)null);
						}
						player.StartEmote("cheer", true);
						Object.Instantiate<GameObject>(ZNetScene.instance.GetPrefab("vfx_Potion_stamina_medium"), ((Component)player).transform.position, Quaternion.identity);
						Object.Instantiate<GameObject>(ZNetScene.instance.GetPrefab("vfx_WishbonePing"), ((Component)player).transform.position, Quaternion.identity);
					}
					else if (player.GetStamina() >= VL_Utility.GetRegenerationCost)
					{
						StatusEffect val17 = (StatusEffect)(object)(SE_Ability1_CD)(object)ScriptableObject.CreateInstance(typeof(SE_Ability1_CD));
						val17.m_ttl = VL_Utility.GetRegenerationCooldownTime;
						((Character)player).GetSEMan().AddStatusEffect(val17, false, 0, 0f);
						((Character)player).UseStamina(VL_Utility.GetRegenerationCost);
						float num6 = ((IEnumerable<Skill>)((Character)player).GetSkills().GetSkillList()).FirstOrDefault((Func<Skill, bool>)((Skill x) => x.m_info == ValheimLegends.AlterationSkillDef)).m_level * (1f + Mathf.Clamp(LevelSystem.Instance.getAddCriticalChance(0) / 40f + LevelSystem.Instance.getAddMagicDamage(0) / 80f, 0f, 0.5f));
						player.StartEmote("cheer", true);
						GO_CastFX = Object.Instantiate<GameObject>(ZNetScene.instance.GetPrefab("fx_guardstone_permitted_add"), ((Character)player).GetCenterPoint(), Quaternion.identity);
						GO_CastFX = Object.Instantiate<GameObject>(ZNetScene.instance.GetPrefab("vfx_WishbonePing"), ((Component)player).transform.position, Quaternion.identity);
						SE_Regeneration sE_Regeneration = (SE_Regeneration)(object)ScriptableObject.CreateInstance(typeof(SE_Regeneration));
						((StatusEffect)sE_Regeneration).m_ttl = SE_Regeneration.m_baseTTL;
						((StatusEffect)sE_Regeneration).m_icon = ZNetScene.instance.GetPrefab("TrophyGreydwarfShaman").GetComponent<ItemDrop>().m_itemData.GetIcon();
						sE_Regeneration.m_HealAmount = 0.5f + 0.4f * num6 * VL_GlobalConfigs.g_DamageModifer * VL_GlobalConfigs.c_druidRegen;
						sE_Regeneration.doOnce = false;
						List<Character> list2 = new List<Character>();
						list2.Clear();
						Character.GetCharactersInRange(((Character)player).GetCenterPoint(), 30f + 0.2f * num6, list2);
						foreach (Character item in list2)
						{
							if (!BaseAI.IsEnemy((Character)(object)player, item))
							{
								if ((Object)(object)item == (Object)(object)Player.m_localPlayer)
								{
									item.GetSEMan().AddStatusEffect((StatusEffect)(object)sE_Regeneration, true, 0, 0f);
								}
								else if (item.IsPlayer())
								{
									item.GetSEMan().AddStatusEffect(StringExtensionMethods.GetStableHashCode(((Object)sE_Regeneration).name), true, 0, 0f);
								}
								else
								{
									item.GetSEMan().AddStatusEffect((StatusEffect)(object)sE_Regeneration, true, 0, 0f);
								}
							}
						}
						((Character)player).RaiseSkill(ValheimLegends.AlterationSkill, VL_Utility.GetRegenerationSkillGain);
					}
					else
					{
						((Character)player).Message((MessageType)1, "Not enough stamina to for Regeneration: (" + player.GetStamina().ToString("#.#") + "/" + VL_Utility.GetRegenerationCost + ")", 0, (Sprite)null);
					}
				}
				else
				{
					((Character)player).Message((MessageType)1, "Ability not ready", 0, (Sprite)null);
				}
			}
			else
			{
				ValheimLegends.isChanneling = false;
				ValheimLegends.channelingBlocksMovement = true;
			}
		}

		public static void TryActivate_HumanForm(Player player, bool forced)
		{
			//IL_0253: Unknown result type (might be due to invalid IL or missing references)
			//IL_0258: Unknown result type (might be due to invalid IL or missing references)
			//IL_0297: Unknown result type (might be due to invalid IL or missing references)
			//IL_029c: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ce: Unknown result type (might be due to invalid IL or missing references)
			SEMan sEMan = ((Character)player).GetSEMan();
			if (sEMan == null)
			{
				return;
			}
			bool flag = sEMan.HaveStatusEffect(SE_FENRING_HASH);
			bool flag2 = sEMan.HaveStatusEffect(SE_CULTIST_HASH);
			if (!flag && !flag2)
			{
				((Character)player).Message((MessageType)1, "Already human.", 0, (Sprite)null);
				return;
			}
			float getDefenderCost = VL_Utility.GetDefenderCost;
			if (!forced)
			{
				if (player.GetStamina() < getDefenderCost)
				{
					((Character)player).Message((MessageType)1, $"Not enough stamina: ({player.GetStamina():#.#}/{getDefenderCost:#.#})", 0, (Sprite)null);
					return;
				}
				if (sEMan.HaveStatusEffect(StringExtensionMethods.GetStableHashCode("SE_VL_Shapeshift_CD")))
				{
					((Character)player).Message((MessageType)1, "Can't shapeshift again yet.", 0, (Sprite)null);
					return;
				}
			}
			else
			{
				((Character)player).Message((MessageType)1, "Ran out of Eitr to sustain the shapeshifting.", 0, (Sprite)null);
			}
			StatusEffect val = (StatusEffect)(object)(SE_Shapeshift_CD)(object)ScriptableObject.CreateInstance(typeof(SE_Shapeshift_CD));
			float num = ((IEnumerable<Skill>)((Character)player).GetSkills().GetSkillList()).FirstOrDefault((Func<Skill, bool>)((Skill x) => x.m_info == ValheimLegends.AlterationSkillDef)).m_level * (1f + Mathf.Clamp(LevelSystem.Instance.getAddCriticalChance(0) / 40f + LevelSystem.Instance.getAddMagicDamage(0) / 80f, 0f, 0.5f));
			val.m_ttl = 180f - 60f * (num / 150f) - 60f * (LevelSystem.Instance.getAddMagicDamage(0) / 80f);
			if (!forced)
			{
				val.m_ttl = 30f - 14.25f * (num / 150f) - 14.25f * (LevelSystem.Instance.getAddMagicDamage(0) / 80f);
				((Character)player).UseStamina(getDefenderCost);
			}
			sEMan.AddStatusEffect(val, false, 0, 0f);
			if (flag)
			{
				sEMan.RemoveStatusEffect(SE_FENRING_HASH, false);
			}
			if (flag2)
			{
				sEMan.RemoveStatusEffect(SE_CULTIST_HASH, false);
			}
			ForceWeaponRefresh(player);
			ValheimLegends.NameCooldowns();
			if (ValheimLegends.abilitiesStatus != null)
			{
				foreach (RectTransform item in ValheimLegends.abilitiesStatus)
				{
					if ((Object)(object)((Component)item).gameObject != (Object)null)
					{
						Object.Destroy((Object)(object)((Component)item).gameObject);
					}
				}
				ValheimLegends.abilitiesStatus.Clear();
			}
			ValheimLegends.shouldUseGuardianPower = false;
			ZSyncAnimation val2 = (ZSyncAnimation)(typeof(Player).GetField("m_zanim", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(player));
			if ((int)val2 != 0)
			{
				val2.SetTrigger("gpower");
			}
			if ((Object)(object)ZNetScene.instance != (Object)null)
			{
				GameObject prefab = ZNetScene.instance.GetPrefab("vfx_odin_despawn");
				if (Object.op_Implicit((Object)(object)prefab))
				{
					Object.Instantiate<GameObject>(prefab, ((Component)player).transform.position, Quaternion.identity);
				}
				prefab = ZNetScene.instance.GetPrefab("sfx_wraith_death");
				if (Object.op_Implicit((Object)(object)prefab))
				{
					Object.Instantiate<GameObject>(prefab, ((Component)player).transform.position, Quaternion.identity);
				}
			}
		}

		private static void TryActivate_FenringForm(Player player)
		{
			//IL_020b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0210: Unknown result type (might be due to invalid IL or missing references)
			//IL_024f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0254: Unknown result type (might be due to invalid IL or missing references)
			//IL_0281: Unknown result type (might be due to invalid IL or missing references)
			//IL_0286: Unknown result type (might be due to invalid IL or missing references)
			SEMan sEMan = ((Character)player).GetSEMan();
			if (sEMan == null)
			{
				return;
			}
			if (sEMan.HaveStatusEffect(SE_FENRING_HASH))
			{
				TryActivate_HumanForm(player, forced: false);
				return;
			}
			if (sEMan.HaveStatusEffect(SE_CULTIST_HASH))
			{
				((Character)player).Message((MessageType)1, "Already transformed (Cultist).", 0, (Sprite)null);
				return;
			}
			float getDefenderCost = VL_Utility.GetDefenderCost;
			if (player.GetStamina() < getDefenderCost)
			{
				((Character)player).Message((MessageType)1, $"Not enough stamina: ({player.GetStamina():#.#}/{getDefenderCost:#.#})", 0, (Sprite)null);
				return;
			}
			if (sEMan.HaveStatusEffect(StringExtensionMethods.GetStableHashCode("SE_VL_Shapeshift_CD")))
			{
				((Character)player).Message((MessageType)1, "Can't shapeshift again yet.", 0, (Sprite)null);
				return;
			}
			StatusEffect val = (StatusEffect)(object)(SE_Shapeshift_CD)(object)ScriptableObject.CreateInstance(typeof(SE_Shapeshift_CD));
			float num = ((IEnumerable<Skill>)((Character)player).GetSkills().GetSkillList()).FirstOrDefault((Func<Skill, bool>)((Skill x) => x.m_info == ValheimLegends.AlterationSkillDef)).m_level * (1f + Mathf.Clamp(LevelSystem.Instance.getAddCriticalChance(0) / 40f + LevelSystem.Instance.getAddMagicDamage(0) / 80f, 0f, 0.5f));
			val.m_ttl = 30f - 14.25f * (num / 150f) - 14.25f * (LevelSystem.Instance.getAddMagicDamage(0) / 80f);
			sEMan.AddStatusEffect(val, false, 0, 0f);
			((Character)player).UseStamina(getDefenderCost);
			SE_DruidFenringForm sE_DruidFenringForm = (SE_DruidFenringForm)(object)ScriptableObject.CreateInstance(typeof(SE_DruidFenringForm));
			sEMan.AddStatusEffect((StatusEffect)(object)sE_DruidFenringForm, false, 0, 0f);
			ValheimLegends.NameCooldowns();
			if (ValheimLegends.abilitiesStatus != null)
			{
				foreach (RectTransform item in ValheimLegends.abilitiesStatus)
				{
					if ((Object)(object)((Component)item).gameObject != (Object)null)
					{
						Object.Destroy((Object)(object)((Component)item).gameObject);
					}
				}
				ValheimLegends.abilitiesStatus.Clear();
			}
			ValheimLegends.shouldUseGuardianPower = false;
			ZSyncAnimation val2 = (ZSyncAnimation)(typeof(Player).GetField("m_zanim", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(player));
			if ((int)val2 != 0)
			{
				val2.SetTrigger("gpower");
			}
			if ((Object)(object)ZNetScene.instance != (Object)null)
			{
				GameObject prefab = ZNetScene.instance.GetPrefab("vfx_odin_despawn");
				if (Object.op_Implicit((Object)(object)prefab))
				{
					Object.Instantiate<GameObject>(prefab, ((Component)player).transform.position, Quaternion.identity);
				}
				prefab = ZNetScene.instance.GetPrefab("sfx_wraith_death");
				if (Object.op_Implicit((Object)(object)prefab))
				{
					Object.Instantiate<GameObject>(prefab, ((Component)player).transform.position, Quaternion.identity);
				}
			}
		}

		private static void TryActivate_CultistForm(Player player)
		{
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0162: Unknown result type (might be due to invalid IL or missing references)
			//IL_0182: Unknown result type (might be due to invalid IL or missing references)
			//IL_0187: Unknown result type (might be due to invalid IL or missing references)
			SEMan sEMan = ((Character)player).GetSEMan();
			if (sEMan == null)
			{
				return;
			}
			if (sEMan.HaveStatusEffect(SE_FENRING_HASH) || sEMan.HaveStatusEffect(SE_CULTIST_HASH))
			{
				((Character)player).Message((MessageType)1, "Already transformed.", 0, (Sprite)null);
				return;
			}
			float getDefenderCost = VL_Utility.GetDefenderCost;
			if (player.GetStamina() < getDefenderCost)
			{
				((Character)player).Message((MessageType)1, $"Not enough stamina: ({player.GetStamina():#.#}/{getDefenderCost})", 0, (Sprite)null);
				return;
			}
			((Character)player).UseStamina(getDefenderCost);
			SE_DruidCultistForm sE_DruidCultistForm = (SE_DruidCultistForm)(object)ScriptableObject.CreateInstance(typeof(SE_DruidCultistForm));
			((StatusEffect)sE_DruidCultistForm).m_ttl = SE_DruidCultistForm.BaseTTL;
			ValheimLegends.shouldUseGuardianPower = false;
			Object.Instantiate<GameObject>(ZNetScene.instance.GetPrefab("vfx_odin_despawn"), ((Component)player).transform.position, Quaternion.identity);
			Object.Instantiate<GameObject>(ZNetScene.instance.GetPrefab("sfx_wraith_death"), ((Component)player).transform.position, Quaternion.identity);
			sEMan.AddStatusEffect((StatusEffect)(object)sE_DruidCultistForm, true, 0, 0f);
			((ZSyncAnimation)typeof(Player).GetField("m_zanim", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(player)).SetTrigger("gpower");
			((ZSyncAnimation)typeof(Player).GetField("m_zanim", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(Player.m_localPlayer)).SetSpeed(2f);
			Object.Instantiate<GameObject>(ZNetScene.instance.GetPrefab("vfx_odin_despawn"), ((Component)player).transform.position, Quaternion.identity);
			Object.Instantiate<GameObject>(ZNetScene.instance.GetPrefab("sfx_wraith_death"), ((Component)player).transform.position, Quaternion.identity);
			((Character)player).Message((MessageType)1, "Transformed: Cultist Form", 0, (Sprite)null);
		}

		public static ItemData GetRightItemSafe(Player player)
		{
			if ((Object)(object)player == (Object)null)
			{
				return null;
			}
			try
			{
				if (MI_GetRightItem != null)
				{
					object? obj = MI_GetRightItem.Invoke(player, null);
					return (ItemData)((obj is ItemData) ? obj : null);
				}
			}
			catch
			{
			}
			try
			{
				if (FI_RightItem != null)
				{
					object? value = FI_RightItem.GetValue(player);
					return (ItemData)((value is ItemData) ? value : null);
				}
			}
			catch
			{
			}
			try
			{
				return ((Humanoid)player).GetCurrentWeapon();
			}
			catch
			{
				return null;
			}
		}

		private static ItemData GetLeftItemSafe(Player player)
		{
			if ((Object)(object)player == (Object)null)
			{
				return null;
			}
			try
			{
				if (MI_GetLeftItem != null)
				{
					object? obj = MI_GetLeftItem.Invoke(player, null);
					return (ItemData)((obj is ItemData) ? obj : null);
				}
			}
			catch
			{
			}
			try
			{
				if (FI_LeftItem != null)
				{
					object? value = FI_LeftItem.GetValue(player);
					return (ItemData)((value is ItemData) ? value : null);
				}
			}
			catch
			{
			}
			return null;
		}

		private static void ForceWeaponRefresh(Player player)
		{
			if ((Object)(object)player == (Object)null)
			{
				return;
			}
			ZNetView component = ((Component)player).GetComponent<ZNetView>();
			if ((Object)(object)component == (Object)null || !component.IsOwner())
			{
				return;
			}
			ItemData rightItemSafe = GetRightItemSafe(player);
			ItemData leftItemSafe = GetLeftItemSafe(player);
			if (rightItemSafe != null)
			{
				((Humanoid)player).UnequipItem(rightItemSafe, true);
				((Humanoid)player).EquipItem(rightItemSafe, true);
				return;
			}
			if (leftItemSafe != null)
			{
				((Humanoid)player).UnequipItem(leftItemSafe, true);
				((Humanoid)player).EquipItem(leftItemSafe, true);
				return;
			}
			try
			{
				Inventory inventory = ((Humanoid)player).GetInventory();
				if (inventory == null)
				{
					return;
				}
				ItemData val = null;
				foreach (ItemData allItem in inventory.GetAllItems())
				{
					if (allItem != null && allItem.IsEquipable())
					{
						val = allItem;
						if (((Humanoid)player).EquipItem(val, true))
						{
							((Humanoid)player).UnequipItem(val, true);
							break;
						}
						val = null;
					}
				}
			}
			catch (Exception ex)
			{
				Debug.LogWarning((object)("[VL] ForceWeaponRefresh inventory fallback failed: " + ex));
			}
		}
	}
	public class Class_Duelist
	{
		private static int ScriptChar_Layermask = LayerMask.GetMask(new string[11]
		{
			"Default", "static_solid", "Default_small", "piece_nonsolid", "terrain", "vehicle", "piece", "viewblock", "character", "character_net",
			"character_ghost"
		});

		private static GameObject GO_CastFX;

		private static GameObject GO_QuickShot;

		private static Projectile P_QuickShot;

		public static ItemDrop coinsItem;

		public static List<int> challengedDeath = new List<int>();

		public static List<int> challengedMastery = new List<int>();

		public static void Execute_Slash(Player player)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: 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_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: 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_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0145: Unknown result type (might be due to invalid IL or missing references)
			//IL_0150: Unknown result type (might be due to invalid IL or missing references)
			//IL_0155: Unknown result type (might be due to invalid IL or missing references)
			//IL_015a: Unknown result type (might be due to invalid IL or missing references)
			//IL_017c: Unknown result type (might be due to invalid IL or missing references)
			//IL_017d: Unknown result type (might be due to invalid IL or missing references)
			//IL_018f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0195: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ab: Expected O, but got Unknown
			//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0201: Unknown result type (might be due to invalid IL or missing references)
			//IL_0206: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c8: Unknown result type (might be due to invalid IL or missing references)
			Object.Instantiate<GameObject>(ZNetScene.instance.GetPrefab("fx_VL_BlinkStrike"), ((Character)player).GetCenterPoint() + ((Character)player).GetLookDir() * 3f, Quaternion.LookRotation(((Character)player).GetLookDir()));
			float num = ((IEnumerable<Skill>)((Character)player).GetSkills().GetSkillList()).FirstOrDefault((Func<Skill, bool>)((Skill x) => x.m_info == ValheimLegends.DisciplineSkillDef)).m_level * (1f + Mathf.Clamp(LevelSystem.Instance.getAddPhysicDamage(0) / 40f + LevelSystem.Instance.getAddAttackSpeed(0) / 40f, 0f, 0.5f));
			float num2 = (1.25f + num / 300f) * VL_GlobalConfigs.g_DamageModifer * VL_GlobalConfigs.c_duelistSeismicSlash;
			Vector3 forward = ((Component)player).transform.forward;
			forward.y = 0f;
			((Vector3)(ref forward)).Normalize();
			float num3 = 7f;
			float num4 = Mathf.Cos(90f * 0.5f * (MathF.PI / 180f));
			List<Character> list = new List<Character>();
			Character.GetCharactersInRange(((Component)player).transform.position, num3, list);
			foreach (Character item in list)
			{
				if (!BaseAI.IsEnemy((Character)(object)player, item))
				{
					continue;
				}
				Vector3 val = ((Component)item).transform.position - ((Component)player).transform.position;
				val.y = 0f;
				if (((Vector3)(ref val)).magnitude > num3)
				{
					continue;
				}
				((Vector3)(ref val)).Normalize();
				if (Vector3.Dot(forward, val) < num4 || !VL_Utility.LOS_IsValid(item, item.GetEyePoint(), ((Character)player).GetEyePoint()))
				{
					continue;
				}
				HitData val2 = new HitData();
				val2.m_damage = ((Humanoid)player).GetCurrentWeapon().GetDamage();
				val2.ApplyModifier(Random.Range(1.8f, 2.2f) * num2);
				val2.m_pushForce = 25f + 0.1f * num;
				val2.m_point = item.GetEyePoint();
				val2.m_dir = forward;
				val2.m_skill = ValheimLegends.DisciplineSkill;
				item.Damage(val2);
				if (challengedMastery.Contains(((Object)item).GetInstanceID()))
				{
					challengedMastery.Remove(((Object)item).GetInstanceID());
					int num5 = Mathf.CeilToInt(Mathf.Sqrt(item.GetMaxHealth()) + (1f + LevelSystem.Instance.getAddCriticalChance(0) / 40f) * Mathf.Sqrt(item.GetMaxHealth()));
					if (((Humanoid)player).GetInventory().CanAddItem(ValheimLegends.coinsItem.m_itemData.m_dropPrefab, num5))
					{
						((Humanoid)player).GetInventory().AddItem(ValheimLegends.coinsItem.m_itemData.m_dropPrefab, num5);
					}
					else
					{
						ItemDrop.DropItem(ValheimLegends.coinsItem.m_itemData, num5, ((Component)player).transform.position, Quaternion.identity);
					}
					((Character)player).Message((MessageType)1, $"Spoiled {num5:#} coins from {item.GetHoverName()}!", 0, (Sprite)null);
				}
			}
		}

		public static void Process_Input(Player player, ref Rigidbody playerBody)
		{
			//IL_03ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_03cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_059c: Unknown result type (might be due to invalid IL or missing references)
			//IL_05a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_05c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_05c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0609: 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_00d2: Invalid comparison between Unknown and I4
			//IL_0729: Unknown result type (might be due to invalid IL or missing references)
			//IL_0735: Unknown result type (might be due to invalid IL or missing references)
			//IL_073c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0747: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Invalid comparison between Unknown and I4
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Invalid comparison between Unknown and I4
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Invalid comparison between Unknown and I4
			//IL_07ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_07f5: Expected O, but got Unknown
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Invalid comparison between Unknown and I4
			//IL_02ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02da: Unknown result type (might be due to invalid IL or missing references)
			//IL_0301: Unknown result type (might be due to invalid IL or missing references)
			//IL_0311: Unknown result type (might be due to invalid IL or missing references)
			//IL_0e4e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0e72: Unknown result type (might be due to invalid IL or missing references)
			//IL_0e77: Unknown result type (might be due to invalid IL or missing references)
			//IL_0e8c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0e97: Unknown result type (might be due to invalid IL or missing references)
			//IL_0ea1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0ea6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0eac: Unknown result type (might be due to invalid IL or missing references)
			//IL_0eb6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0ebb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0ec0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0ed2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0ed7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0ef1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0ef4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0ef9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0f17: Unknown result type (might be due to invalid IL or missing references)
			//IL_0f19: Unknown result type (might be due to invalid IL or missing references)
			//IL_0fa3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0fa5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0faa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0fcd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0fd9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0fe0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0fe6: Unknown result type (might be due to invalid IL or missing references)
			//IL_088e: Unknown result type (might be due to invalid IL or missing references)
			//IL_089a: Unknown result type (might be due to invalid IL or missing references)
			//IL_1016: Unknown result type (might be due to invalid IL or missing references)
			//IL_101c: Unknown result type (might be due to invalid IL or missing references)
			//IL_1026: Unknown result type (might be due to invalid IL or missing references)
			//IL_102b: Unknown result type (might be due to invalid IL or missing references)
			//IL_1030: Unknown result type (might be due to invalid IL or missing references)
			//IL_1032: Unknown result type (might be due to invalid IL or missing references)
			//IL_1039: Expected O, but got Unknown
			//IL_1098: Unknown result type (might be due to invalid IL or missing references)
			//IL_109d: Unknown result type (might be due to invalid IL or missing references)
			//IL_10a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_10a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_10ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_10b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_10b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_10c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_10c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_10d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_10fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_1117: Unknown result type (might be due to invalid IL or missing references)
			//IL_100e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0a3c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0a41: Unknown result type (might be due to invalid IL or missing references)
			//IL_0a5d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0a62: Unknown result type (might be due to invalid IL or missing references)
			//IL_09f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_09fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0a19: Unknown result type (might be due to invalid IL or missing references)
			//IL_0a1e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b5b: Unknown result type (might be due to invalid IL or missing references)
			new Random();
			if (VL_Utility.Ability3_Input_Down)
			{
				if (challengedDeath == null)
				{
					challengedDeath = new List<int>();
					challengedDeath.Clear();
				}
				if (challengedDeath.Count > 50)
				{
					challengedDeath.Clear();
				}
				if (challengedMastery == null)
				{
					challengedMastery = new List<int>();
					challengedMastery.Clear();
				}
				if (challengedMastery.Count > 50)
				{
					challengedMastery.Clear();
				}
				if (!((Character)player).GetSEMan().HaveStatusEffect(StringExtensionMethods.GetStableHashCode("SE_VL_Ability3_CD")))
				{
					if (((Character)player).IsBlocking())
					{
						if (Traverse.Create((object)player).Field("m_leftItem").GetValue<ItemData>() == null && ((Humanoid)player).GetCurrentWeapon() != null && (int)((Humanoid)player).GetCurrentWeapon().m_shared.m_itemType != 14 && ((int)((Humanoid)player).GetCurrentWeapon().m_shared.m_skillType == 1 || (int)((Humanoid)player).GetCurrentWeapon().m_shared.m_skillType == 2 || (int)((Humanoid)player).GetCurrentWeapon().m_shared.m_skillType == 7 || (int)((Humanoid)player).GetCurrentWeapon().m_shared.m_skillType == 5))
						{
							float num = ((Humanoid)player).GetCurrentWeapon().GetMaxDurability() * (1f - ((Humanoid)player).GetCurrentWeapon().GetDurabilityPercentage());
							if (num > 0f)
							{
								float num2 = num * 4f * (1f - LevelSystem.Instance.getStaminaReduction(0) / 100f);
								float num3 = num;
								if (player.GetStamina() < num2)
								{
									num3 = player.GetStamina() / (4f * (1f - LevelSystem.Instance.getStaminaReduction(0) / 100f));
								}
								float num4 = ((IEnumerable<Skill>)((Character)player).GetSkills().GetSkillList()).FirstOrDefault((Func<Skill, bool>)((Skill x) => x.m_info == ValheimLegends.DisciplineSkillDef)).m_level * (1f + Mathf.Clamp(LevelSystem.Instance.getAddPhysicDamage(0) / 40f + LevelSystem.Instance.getAddAttackSpeed(0) / 40f, 0f, 0.5f));
								StatusEffect val = (StatusEffect)(object)(SE_Ability3_CD)(object)ScriptableObject.CreateInstance(typeof(SE_Ability3_CD));
								val.m_ttl = 60f + num3 * 2f * (1f - LevelSystem.Instance.getAddCriticalChance(0) / 40f);
								((Character)player).GetSEMan().AddStatusEffect(val, false, 0, 0f);
								((Character)player).UseStamina(num3 * 10f * (1f - LevelSystem.Instance.getAddCriticalChance(0) / 40f) * (1f - num4 / 300f));
								ItemData currentWeapon = ((Humanoid)player).GetCurrentWeapon();
								currentWeapon.m_durability += num3;
								Object.Instantiate<GameObject>(ZNetScene.instance.GetPrefab("fx_VL_BlinkStrike"), ((Character)player).GetCenterPoint() + ((Character)player).GetLookDir() * 3f, Quaternion.LookRotation(((Character)player).GetLookDir()));
								((ZSyncAnimation)typeof(Player).GetField("m_zanim", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(player)).SetTrigger("knife_stab1");
								((Character)player).RaiseSkill(ValheimLegends.DisciplineSkill, VL_Utility.GetBlinkStrikeSkillGain);
							}
							else
							{
								((Character)player).Message((MessageType)1, "You don't need to Sharpen you weapon.", 0, (Sprite)null);
							}
						}
						else
						{
							((Character)player).Message((MessageType)1, "You can only Sharpen an equipped bladed single one-handed weapon (swords, knives, axes or spears).", 0, (Sprite)null);
						}
					}
					else if (player.GetStamina() >= VL_Utility.GetBlinkStrikeCost)
					{
						StatusEffect val2 = (StatusEffect)(object)(SE_Ability3_CD)(object)ScriptableObject.CreateInstance(typeof(SE_Ability3_CD));
						val2.m_ttl = VL_Utility.GetBlinkStrikeCooldownTime;
						((Character)player).GetSEMan().AddStatusEffect(val2, false, 0, 0f);
						((Character)player).UseStamina(VL_Utility.GetBlinkStrikeCost);
						((ZSyncAnimation)typeof(Player).GetField("m_zanim", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(player)).SetTrigger("knife_stab1");
						ValheimLegends.isChanneling = true;
						ValheimLegends.isChargingDash = true;
						ValheimLegends.dashCounter = 0;
						((Character)player).RaiseSkill(ValheimLegends.DisciplineSkill, VL_Utility.GetBlinkStrikeSkillGain);
					}
					else
					{
						((Character)player).Message((MessageType)1, "Not enough stamina for S. Slash : (" + player.GetStamina().ToString("#.#") + "/" + VL_Utility.GetBlinkStrikeCost + ")", 0, (Sprite)null);
					}
				}
				else
				{
					((Character)player).Message((MessageType)1, "Ability not ready", 0, (Sprite)null);
				}
			}
			else if (VL_Utility.Ability2_Input_Down)
			{
				if (challengedDeath == null)
				{
					challengedDeath = new List<int>();
					challengedDeath.Clear();
				}
				if (challengedDeath.Count > 50)
				{
					challengedDeath.Clear();
				}
				if (challengedMastery == null)
				{
					challengedMastery = new List<int>();
					challengedMastery.Clear();
				}
				if (challengedMastery.Count > 50)
				{
					challengedMastery.Clear();
				}
				if (!((Character)player).GetSEMan().HaveStatusEffect(StringExtensionMethods.GetStableHashCode("SE_VL_Ability2_CD")))
				{
					if (player.GetStamina() >= VL_Utility.GetRiposteCost)
					{
						StatusEffect val3 = (StatusEffect)(object)(SE_Ability2_CD)(object)ScriptableObject.CreateInstance(typeof(SE_Ability2_CD));
						val3.m_ttl = VL_Utility.GetRiposteCooldownTime;
						((Character)player).GetSEMan().AddStatusEffect(val3, false, 0, 0f);
						((Character)player).UseStamina(VL_Utility.GetRiposteCost);
						_ = ((IEnumerable<Skill>)((Character)player).GetSkills().GetSkillList()).FirstOrDefault((Func<Skill, bool>)((Skill x) => x.m_info == ValheimLegends.DisciplineSkillDef)).m_level;
						Mathf.Clamp(LevelSystem.Instance.getAddPhysicDamage(0) / 40f + LevelSystem.Instance.getAddAttackSpeed(0) / 40f, 0f, 0.5f);
						GO_CastFX = Object.Instantiate<GameObject>(ZNetScene.instance.GetPrefab("sfx_perfectblock"), ((Component)player).transform.position, Quaternion.identity);
						GO_CastFX = Object.Instantiate<GameObject>(ZNetScene.instance.GetPrefab("fx_backstab"), ((Character)player).GetCenterPoint(), Quaternion.identity);
						SE_Riposte sE_Riposte = (SE_Riposte)(object)ScriptableObject.CreateInstance(typeof(SE_Riposte));
						sE_Riposte.playerBody = playerBody;
						((Character)player).GetSEMan().AddStatusEffect((StatusEffect)(object)sE_Riposte, false, 0, 0f);
						((Character)player).RaiseSkill(ValheimLegends.DisciplineSkill, VL_Utility.GetRiposteSkillGain);
					}
					else
					{
						((Character)player).Message((MessageType)1, "Not enough stamina for Riposte: (" + player.GetStamina().ToString("#.#") + "/" + VL_Utility.GetRiposteCost + ")", 0, (Sprite)null);
					}
				}
				else
				{
					((Character)player).Message((MessageType)1, "Ability not ready", 0, (Sprite)null);
				}
			}
			else if (VL_Utility.Ability1_Input_Down)
			{
				if (challengedDeath == null)
				{
					challengedDeath = new List<int>();
					challengedDeath.Clear();
				}
				if (challengedDeath.Count > 50)
				{
					challengedDeath.Clear();
				}
				if (challengedMastery == null)
				{
					challengedMastery = new List<int>();
					challengedMastery.Clear();
				}
				if (challengedMastery.Count > 50)
				{
					challengedMastery.Clear();
				}
				if (!((Character)player).GetSEMan().HaveStatusEffect(StringExtensionMethods.GetStableHashCode("SE_VL_Ability1_CD")))
				{
					ValheimLegends.DefineCoins();
					if (!((Object)(object)ValheimLegends.coinsItem != (Object)null))
					{
						return;
					}
					if (((Character)player).IsBlocking())
					{
						RaycastHit val4 = default(RaycastHit);
						_ = ((Component)player).transform.position;
						Physics.SphereCast(((Character)player).GetEyePoint(), 0.2f, ((Character)player).GetLookDir(), ref val4, 200f, ScriptChar_Layermask);
						VL_Utility.SetTimer();
						if ((Object)(object)((RaycastHit)(ref val4)).collider != (Object)null && (Object)(object)((Component)((RaycastHit)(ref val4)).collider).gameObject != (Object)null)
						{
							Character val5 = null;
							((Component)((RaycastHit)(ref val4)).collider).gameObject.TryGetComponent<Character>(ref val5);
							bool flag = (Object)(object)val5 != (Object)null;
							List<Component> list = new List<Component>();
							list.Clear();
							((Component)((RaycastHit)(ref val4)).collider).gameObject.GetComponents<Component>(list);
							if ((Object)(object)val5 == (Object)null)
							{
								val5 = (Character)((Component)((RaycastHit)(ref val4)).collider).GetComponentInParent(typeof(Character));
								flag = (Object)(object)val5 != (Object)null;
								if ((Object)(object)val5 == (Object)null)
								{
									val5 = ((Component)((RaycastHit)(ref val4)).collider).GetComponentInChildren<Character>();
									flag = (Object)(object)val5 != (Object)null;
								}
							}
							if (flag && !val5.IsPlayer())
							{
								int instanceID = ((Object)val5).GetInstanceID();
								if ((challengedDeath != null && challengedDeath.Contains(instanceID)) || (challengedMastery != null && challengedMastery.Contains(instanceID)))
								{
									((Character)player).Message((MessageType)1, val5.GetHoverName() + " was already challenged!", 0, (Sprite)null);
								}
								else if (Vector3.Distance(((Component)player).transform.position, ((Component)val5).transform.position) <= 70f)
								{
									if (player.GetStamina() >= VL_Utility.GetQuickShotCost)
									{
										int num5 = Mathf.CeilToInt(Mathf.Sqrt(val5.GetMaxHealth()));
										if (((Humanoid)player).GetInventory() != null && ((Humanoid)player).GetInventory().HaveItem(ValheimLegends.coinsItem.m_itemData.m_shared.m_name, true) && ((Humanoid)player).GetInventory().CountItems("$item_coins", -1, true) >= num5)
										{
											ItemData val6 = null;
											ItemData val7 = null;
											for (int i = 0; i < ((Humanoid)player).GetInventory().GetHeight(); i++)
											{
												if (val7 != null)
												{
													break;
												}
												for (int j = 0; j < ((Humanoid)player).GetInventory().GetWidth(); j++)
												{
													val6 = ((Humanoid)player).GetInventory().GetItemAt(j, i);
													if (val6 != null)
													{
														if (val6.m_shared.m_name == "$item_coins" && ((Humanoid)player).GetInventory().GetItemAt(j, i).m_stack >= num5)
														{
															val7 = val6;
														}
														if (val7 != null)
														{
															break;
														}
													}
												}
											}
											for (int k = 0; k < num5; k++)
											{
												Player localPlayer = Player.m_localPlayer;
												if (localPlayer != null)
												{
													((Humanoid)localPlayer).GetInventory().RemoveOneItem(val7);
												}
											}
											((Character)player).UseStamina(VL_Utility.GetQuickShotCost);
											if (num5 < LevelSystem.Instance.getLevel())
											{
												Object.Instantiate<GameObject>(ZNetScene.instance.GetPrefab("sfx_coins_destroyed"), val5.GetCenterPoint(), Quaternion.identity);
												Object.Instantiate<GameObject>(ZNetScene.instance.GetPrefab("vfx_coin_stack_destroyed"), val5.GetCenterPoint(), Quaternion.identity);
											}
											else
											{
												Object.Instantiate<GameObject>(ZNetScene.instance.GetPrefab("sfx_coins_pile_destroyed"), val5.GetCenterPoint(), Quaternion.identity);
												Object.Instantiate<GameObject>(ZNetScene.instance.GetPrefab("vfx_coin_pile_destroyed"), val5.GetCenterPoint(), Quaternion.identity);
											}
											player.StartEmote("point", true);
											((Character)player).Message((MessageType)1, "Challenged " + val5.GetHoverName() + " to a duel worth of " + num5.ToString("#") + " coins!", 0, (Sprite)null);
											if (val5.IsOwner())
											{
												if (Random.value < 0.33f)
												{
													((Character)player).Message((MessageType)2, "Duel of Mastery!", 1, ValheimLegends.RiposteIcon);
													challengedMastery.Add(((Object)val5).GetInstanceID());
												}
												else
												{
													((Character)player).Message((MessageType)2, "Duel to the Death!", 1, ZNetScene.instance.GetPrefab("TrophySkeleton").GetComponent<ItemDrop>().m_itemData.GetIcon());
													challengedDeath.Add(((Object)val5).GetInstanceID());
												}
											}
											else
											{
												((Character)player).Message((MessageType)2, "Duel of Mastery!", 1, ValheimLegends.RiposteIcon);
												challengedMastery.Add(((Object)val5).GetInstanceID());
											}
											((Character)player).RaiseSkill(ValheimLegends.DisciplineSkill, VL_Utility.GetQuickShotSkillGain);
											StatusEffect val8 = (StatusEffect)(object)(SE_Ability1_CD)(object)ScriptableObject.CreateInstance(typeof(SE_Ability1_CD));
											val8.m_ttl = VL_Utility.GetQuickShotCooldownTime * 3f;
											((Character)player).GetSEMan().AddStatusEffect(val8, false, 0, 0f);
										}
										else
										{
											((Character)player).Message((MessageType)1, "You need " + num5.ToString("#") + " coins to challenge " + val5.GetHoverName() + ".", 0, (Sprite)null);
										}
									}
									else
									{
										((Character)player).Message((MessageType)1, "Not enough stamina for Challenge: (" + player.GetStamina().ToString("#.#") + "/" + VL_Utility.GetBackstabCost + ")", 0, (Sprite)null);
									}
								}
								else
								{
									((Character)player).Message((MessageType)1, val5.GetHoverName() + " is too far away to challenge!", 0, (Sprite)null);
								}
							}
							else
							{
								((Character)player).Message((MessageType)1, "Invalid target", 0, (Sprite)null);
							}
						}
						else
						{
							((Character)player).Message((MessageType)1, "No target", 0, (Sprite)null);
						}
					}
					else if (!((Character)player).GetSEMan().HaveStatusEffect(StringExtensionMethods.GetStableHashCode("SE_VL_Ability1_CD")))
					{
						if (player.GetStamina() >= VL_Utility.GetQuickShotCost)
						{
							if (((Humanoid)player).GetInventory() != null && ((Humanoid)player).GetInventory().HaveItem(ValheimLegends.coinsItem.m_itemData.m_shared.m_name, true))
							{
								ItemData val9 = null;
								ItemData val10 = null;
								for (int l = 0; l < ((Humanoid)player).GetInventory().GetHeight(); l++)
								{
									if (val10 != null)
									{
										break;
									}
									for (int m = 0; m < ((Humanoid)player).GetInventory().GetWidth(); m++)
									{
										val9 = ((Humanoid)player).GetInventory().GetItemAt(m, l);
										if (val9 != null)
										{
											if (val9.m_shared.m_name == "$item_coins" && ((Humanoid)player).GetInventory().GetItemAt(m, l).m_stack >= 0)
											{
												val10 = val9;
											}
											if (val10 != null)
											{
												break;
											}
										}
									}
								}
								Player localPlayer2 = Player.m_localPlayer;
								if (localPlayer2 != null)
								{
									((Humanoid)localPlayer2).GetInventory().RemoveOneItem(val10);
								}
								float num6 = ((IEnumerable<Skill>)((Character)player).GetSkills().GetSkillList()).FirstOrDefault((Func<Skill, bool>)((Skill x) => x.m_info == ValheimLegends.DisciplineSkillDef)).m_level * (1f + Mathf.Clamp(LevelSystem.Instance.getAddPhysicDamage(0) / 40f + LevelSystem.Instance.getAddAttackSpeed(0) / 40f, 0f, 0.5f));
								StatusEffect val11 = (StatusEffect)(object)(SE_Ability1_CD)(object)ScriptableObject.CreateInstance(typeof(SE_Ability1_CD));
								val11.m_ttl = VL_Utility.GetQuickShotCooldownTime;
								((Character)player).GetSEMan().AddStatusEffect(val11, false, 0, 0f);
								((Character)player).UseStamina(VL_Utility.GetQuickShotCost + 0.5f * num6);
								((ZSyncAnimation)typeof(Player).GetField("m_zanim", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(player)).SetTrigger("interact");
								GO_CastFX = Object.Instantiate<GameObject>(ZNetScene.instance.GetPrefab("sfx_smelter_add"), ((Component)player).transform.position, Quaternion.identity);
								Vector3 val12 = ((Component)player).transform.position + ((Component)player).transform.up * 1.2f + ((Character)player).GetLookDir() * 0.5f;
								Object.Instantiate<GameObject>(ZNetScene.instance.GetPrefab("sfx_coins_destroyed"), ((Character)player).GetCenterPoint(), Quaternion.identity);
								GO_CastFX = Object.Instantiate<GameObject>(ZNetScene.instance.GetPrefab("fx_VL_Q