Decompiled source of balrond extra skills v0.1.0

plugins/BalrondExtraSkills.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
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;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using JetBrains.Annotations;
using LitJson2;
using Microsoft.CodeAnalysis;
using ServerSync;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("BalrondExtraSkills")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("BalrondExtraSkills")]
[assembly: AssemblyCopyright("")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("f6d55ca3-92c3-4d6a-bf40-9e8f52c5a331")]
[assembly: AssemblyFileVersion("0.1.4.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.1.4.0")]
[module: UnverifiableCode]
public static class BalrondHashCompat
{
	private static readonly MethodInfo _getStableHashCodeStringBool;

	private static readonly MethodInfo _getStableHashCodeString;

	private static readonly bool _initialized;

	static BalrondHashCompat()
	{
		try
		{
			Type typeFromHandle = typeof(StringExtensionMethods);
			_getStableHashCodeStringBool = typeFromHandle.GetMethod("GetStableHashCode", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[2]
			{
				typeof(string),
				typeof(bool)
			}, null);
			_getStableHashCodeString = typeFromHandle.GetMethod("GetStableHashCode", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(string) }, null);
			_initialized = true;
		}
		catch
		{
			_initialized = false;
		}
	}

	public static int StableHash(string value)
	{
		if (value == null)
		{
			return 0;
		}
		try
		{
			if (_getStableHashCodeStringBool != null)
			{
				return (int)_getStableHashCodeStringBool.Invoke(null, new object[2] { value, false });
			}
			if (_getStableHashCodeString != null)
			{
				return (int)_getStableHashCodeString.Invoke(null, new object[1] { value });
			}
		}
		catch
		{
		}
		return FallbackStableHash(value);
	}

	private static int FallbackStableHash(string value)
	{
		int num = 5381;
		int num2 = num;
		for (int i = 0; i < value.Length; i += 2)
		{
			num = ((num << 5) + num) ^ value[i];
			if (i == value.Length - 1)
			{
				break;
			}
			num2 = ((num2 << 5) + num2) ^ value[i + 1];
		}
		return num + num2 * 1566083941;
	}
}
namespace BalrondExtraSkills
{
	public static class BalrondDamageHub
	{
		private sealed class Box<T>
		{
			public T Value;

			public Box(T v)
			{
				Value = v;
			}
		}

		[HarmonyPatch(typeof(Character), "ApplyDamage")]
		private static class Character_ApplyDamage_Patch
		{
			[HarmonyPrefix]
			private static void Prefix(Character __instance)
			{
				Player val = (Player)(object)((__instance is Player) ? __instance : null);
				if (val != null && !((Object)(object)val != (Object)(object)Player.m_localPlayer))
				{
					float health = ((Character)val).GetHealth();
					s_preHealth.Remove(__instance);
					s_preHealth.Add(__instance, new Box<float>(health));
				}
			}

			[HarmonyPostfix]
			private static void Postfix(Character __instance, HitData hit)
			{
				Player val = (Player)(object)((__instance is Player) ? __instance : null);
				if (val != null && !((Object)(object)val != (Object)(object)Player.m_localPlayer) && s_preHealth.TryGetValue(__instance, out var value))
				{
					float value2 = value.Value;
					float health = ((Character)val).GetHealth();
					s_preHealth.Remove(__instance);
					float num = value2 - health;
					if (!(num <= 0f))
					{
						FortitudeSkill.OnDamageTaken(val, hit, num);
						ArcanaSkill.OnDamageTaken(val, hit, num, wasBlocking: false, wasPerfectBlock: false);
					}
				}
			}
		}

		private static readonly ConditionalWeakTable<Character, Box<float>> s_preHealth = new ConditionalWeakTable<Character, Box<float>>();

		internal static bool IsElemental(HitData hit)
		{
			if (hit == null)
			{
				return false;
			}
			return hit.m_damage.m_fire > 0f || hit.m_damage.m_frost > 0f || hit.m_damage.m_lightning > 0f;
		}
	}
	internal static class BalrondIconUtil
	{
		private static Sprite _placeholder;

		internal static Sprite Placeholder
		{
			get
			{
				//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
				//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
				//IL_0021: Unknown result type (might be due to invalid IL or missing references)
				//IL_0027: Expected O, but got Unknown
				//IL_003e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0067: Unknown result type (might be due to invalid IL or missing references)
				//IL_0076: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)_placeholder != (Object)null)
				{
					return _placeholder;
				}
				try
				{
					Texture2D val = new Texture2D(1, 1, (TextureFormat)4, false);
					val.SetPixel(0, 0, new Color(0f, 0f, 0f, 0f));
					val.Apply(false, true);
					_placeholder = Sprite.Create(val, new Rect(0f, 0f, 1f, 1f), new Vector2(0.5f, 0.5f));
					((Object)_placeholder).name = "BalrondExtraSkills_PlaceholderIcon";
				}
				catch
				{
					_placeholder = Sprite.Create(Texture2D.blackTexture, new Rect(0f, 0f, 1f, 1f), new Vector2(0.5f, 0.5f));
				}
				return _placeholder;
			}
		}
	}
	internal static class BalrondSkillLevelupMessagePatch
	{
		[HarmonyPatch(typeof(Player), "Message", new Type[]
		{
			typeof(MessageType),
			typeof(string),
			typeof(int),
			typeof(Sprite)
		})]
		private static class Player_Message_SkillupTokenFix
		{
			[HarmonyPrefix]
			private static void Prefix(ref string msg)
			{
				//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
				//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
				if (string.IsNullOrEmpty(msg) || !msg.StartsWith("$msg_skillup"))
				{
					return;
				}
				int num = msg.IndexOf("$skill_");
				if (num < 0)
				{
					return;
				}
				int i = num + 7;
				int num2 = i;
				for (; i < msg.Length; i++)
				{
					char c = msg[i];
					if (c < '0' || c > '9')
					{
						break;
					}
				}
				if (i == num2)
				{
					return;
				}
				string s = msg.Substring(num2, i - num2);
				if (!int.TryParse(s, out var result))
				{
					return;
				}
				SkillType key = (SkillType)result;
				if (BalrondSkillSystem.Registered.TryGetValue(key, out var value) && value != null)
				{
					PropertyInfo propertyInfo = AccessTools.Property(value.GetType(), "NameToken");
					string text;
					if (propertyInfo != null)
					{
						text = propertyInfo.GetValue(value, null) as string;
					}
					else
					{
						PropertyInfo propertyInfo2 = AccessTools.Property(value.GetType(), "NameTokenKey");
						text = ((propertyInfo2 != null) ? (propertyInfo2.GetValue(value, null) as string) : null);
					}
					if (string.IsNullOrEmpty(text))
					{
						text = "$tag_skill_" + (value.InternalKey ?? "skill") + "_bal";
					}
					msg = msg.Substring(0, num) + text + msg.Substring(i);
				}
			}
		}
	}
	public static class BalrondSkillSystem
	{
		[HarmonyPatch(typeof(SkillsDialog), "Setup")]
		private static class SkillsDialog_Setup_CustomNames_Patch
		{
			[HarmonyPostfix]
			private static void Postfix(SkillsDialog __instance)
			{
				//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
				//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
				try
				{
					if ((Object)(object)__instance == (Object)null)
					{
						return;
					}
					FieldInfo fieldInfo = AccessTools.Field(typeof(SkillsDialog), "m_elements");
					if (fieldInfo == null || !(fieldInfo.GetValue(__instance) is List<GameObject> list))
					{
						return;
					}
					foreach (GameObject item in list)
					{
						if ((Object)(object)item == (Object)null || !item.activeInHierarchy)
						{
							continue;
						}
						Transform val = Utils.FindChild(item.transform, "name", (IterativeSearchType)0);
						if ((Object)(object)val == (Object)null)
						{
							continue;
						}
						TMP_Text component = ((Component)val).GetComponent<TMP_Text>();
						if ((Object)(object)component == (Object)null)
						{
							continue;
						}
						int num = TryParseBracketedSkillId(component.text);
						if (num == -1)
						{
							continue;
						}
						SkillType key = (SkillType)num;
						if (!Registered.TryGetValue(key, out var value) || value == null)
						{
							continue;
						}
						string text = ((Localization.instance != null) ? Localization.instance.Localize(value.NameToken) : value.NameToken);
						if (!string.IsNullOrEmpty(text) && text.StartsWith("[") && text.EndsWith("]"))
						{
							text = value.SkillNameEnglish;
						}
						component.text = text;
						Transform val2 = Utils.FindChild(item.transform, "icon", (IterativeSearchType)0);
						if ((Object)(object)val2 != (Object)null)
						{
							Image component2 = ((Component)val2).GetComponent<Image>();
							if ((Object)(object)component2 != (Object)null)
							{
								component2.sprite = value.Icon;
							}
						}
					}
				}
				catch
				{
				}
			}

			private static int TryParseBracketedSkillId(string text)
			{
				if (string.IsNullOrEmpty(text))
				{
					return -1;
				}
				int num = text.IndexOf("[skill_", StringComparison.OrdinalIgnoreCase);
				if (num < 0)
				{
					return -1;
				}
				int num2 = num + "[skill_".Length;
				int num3 = text.IndexOf(']', num2);
				if (num3 < 0)
				{
					return -1;
				}
				string s = text.Substring(num2, num3 - num2);
				int result;
				return int.TryParse(s, out result) ? result : (-1);
			}
		}

		[HarmonyPatch(typeof(Skills), "IsSkillValid")]
		private static class Skills_IsSkillValid_Patch
		{
			[HarmonyPrefix]
			private static bool Prefix(SkillType type, ref bool __result)
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				if (!IsCustomSkill(type))
				{
					return true;
				}
				__result = true;
				return false;
			}
		}

		[HarmonyPatch(typeof(Skills), "GetSkillDef")]
		private static class Skills_GetSkillDef_Patch
		{
			[HarmonyPostfix]
			private static void Postfix(Skills __instance, SkillType type, ref SkillDef __result)
			{
				//IL_0011: Unknown result type (might be due to invalid IL or missing references)
				//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_0029: 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_002f: Unknown result type (might be due to invalid IL or missing references)
				//IL_003b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0047: Unknown result type (might be due to invalid IL or missing references)
				//IL_0053: Expected O, but got Unknown
				if (__result == null && Registered.TryGetValue(type, out var value))
				{
					__result = new SkillDef
					{
						m_skill = type,
						m_icon = value.Icon,
						m_description = value.DescToken,
						m_increseStep = 1f
					};
					EnsureDefsInSkillsList(__instance);
				}
			}
		}

		[HarmonyPatch(typeof(Skills), "Awake")]
		private static class Skills_Awake_Patch
		{
			[HarmonyPostfix]
			private static void Postfix(Skills __instance)
			{
				try
				{
					EnsureDefsInSkillsList(__instance);
				}
				catch
				{
				}
			}
		}

		[HarmonyPatch(typeof(Player), "Awake")]
		private static class Player_Awake_SeedCustomSkills_Patch
		{
			[HarmonyPostfix]
			private static void Postfix(Player __instance)
			{
				EnsureAllSeeded(__instance);
			}
		}

		[HarmonyPatch(typeof(Player), "Load")]
		private static class Player_Load_SeedCustomSkills_Patch
		{
			[HarmonyPostfix]
			private static void Postfix(Player __instance)
			{
				EnsureAllSeeded(__instance);
			}
		}

		[HarmonyPatch(typeof(Skills), "CheatRaiseSkill")]
		private static class Skills_CheatRaiseSkill_Patch
		{
			[HarmonyPrefix]
			private static bool Prefix(Skills __instance, string name, float value, bool showMessage)
			{
				//IL_0040: Unknown result type (might be due to invalid IL or missing references)
				//IL_0088: Unknown result type (might be due to invalid IL or missing references)
				//IL_00be: Unknown result type (might be due to invalid IL or missing references)
				//IL_0144: Unknown result type (might be due to invalid IL or missing references)
				//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
				//IL_0161: Unknown result type (might be due to invalid IL or missing references)
				//IL_0168: Expected O, but got Unknown
				//IL_016a: Unknown result type (might be due to invalid IL or missing references)
				//IL_011f: Unknown result type (might be due to invalid IL or missing references)
				try
				{
					if (string.IsNullOrEmpty(name))
					{
						return true;
					}
					string key = SanitizeKey(name);
					if (!ByAlias.TryGetValue(key, out var value2))
					{
						return true;
					}
					if (!Registered.TryGetValue(value2, out var value3))
					{
						return true;
					}
					object? obj = FI_Skills_m_player?.GetValue(__instance);
					Player val = (Player)((obj is Player) ? obj : null);
					if ((Object)(object)val != (Object)null)
					{
						EnsureDefsInSkillsList(__instance, forceRefresh: true);
						EnsureSkillSeeded(__instance, value2);
					}
					if (!(FI_Skills_m_skillData?.GetValue(__instance) is Dictionary<SkillType, Skill> dictionary))
					{
						return false;
					}
					if (!dictionary.TryGetValue(value2, out var value4) || value4 == null)
					{
						if (MI_Skills_GetSkill != null)
						{
							MI_Skills_GetSkill.Invoke(__instance, new object[1] { value2 });
							if (!(FI_Skills_m_skillData.GetValue(__instance) is Dictionary<SkillType, Skill> dictionary2) || !dictionary2.TryGetValue(value2, out value4) || value4 == null)
							{
								return false;
							}
						}
						else
						{
							SkillDef skillDef = __instance.GetSkillDef(value2);
							if (skillDef == null)
							{
								return false;
							}
							value4 = (dictionary[value2] = new Skill(skillDef));
							FI_Skills_m_skillData.SetValue(__instance, dictionary);
						}
					}
					value4.m_level = Mathf.Clamp(value4.m_level + value, 0f, 100f);
					value4.m_accumulator = 0f;
					if (showMessage && (Object)(object)val != (Object)null)
					{
						((Character)val).Message((MessageType)1, $"Skill increased {value3.SkillNameEnglish}: {(int)value4.m_level}", 0, value3.Icon);
					}
					Console instance = Console.instance;
					if (instance != null)
					{
						instance.Print($"Skill {value3.SkillNameEnglish} = {(int)value4.m_level}");
					}
					return false;
				}
				catch
				{
					return true;
				}
			}
		}

		[HarmonyPatch(typeof(Skills), "CheatResetSkill")]
		private static class Skills_CheatResetSkill_Patch
		{
			[HarmonyPrefix]
			private static bool Prefix(Skills __instance, string name)
			{
				//IL_0038: 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)
				try
				{
					if (string.IsNullOrEmpty(name))
					{
						return true;
					}
					string key = SanitizeKey(name);
					if (!ByAlias.TryGetValue(key, out var value))
					{
						return true;
					}
					if (!Registered.TryGetValue(value, out var value2))
					{
						return true;
					}
					__instance.ResetSkill(value);
					Console instance = Console.instance;
					if (instance != null)
					{
						instance.Print("Skill " + value2.SkillNameEnglish + " reset");
					}
					return false;
				}
				catch
				{
					return true;
				}
			}
		}

		public static readonly Dictionary<SkillType, BaseSkill> Registered = new Dictionary<SkillType, BaseSkill>();

		private static readonly Dictionary<string, SkillType> ByAlias = new Dictionary<string, SkillType>();

		private static readonly FieldInfo FI_Skills_m_skillData = AccessTools.Field(typeof(Skills), "m_skillData");

		private static readonly FieldInfo FI_Skills_m_player = AccessTools.Field(typeof(Skills), "m_player");

		private static readonly MethodInfo MI_Skills_GetSkill = AccessTools.Method(typeof(Skills), "GetSkill", new Type[1] { typeof(SkillType) }, (Type[])null);

		public static void RegisterSkill(BaseSkill skill)
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Invalid comparison between Unknown and I4
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: 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_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Expected I4, but got Unknown
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Expected I4, but got Unknown
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Expected I4, but got Unknown
			//IL_0146: Unknown result type (might be due to invalid IL or missing references)
			if (skill == null)
			{
				throw new ArgumentNullException("skill");
			}
			string text = SanitizeKey(skill.InternalKey);
			if (string.IsNullOrEmpty(text))
			{
				text = SanitizeKey(skill.SkillNameEnglish);
			}
			if ((int)skill.SkillType == 0)
			{
				skill.SkillType = GetFixedSkillType(skill);
			}
			if (Registered.TryGetValue(skill.SkillType, out var value))
			{
				throw new InvalidOperationException($"[BalrondExtraSkills] Skill ID collision: {(int)skill.SkillType} is already used by '{value.InternalKey}', cannot register '{skill.InternalKey}'.");
			}
			Registered.Add(skill.SkillType, skill);
			AddAlias(text, skill.SkillType);
			AddAlias(skill.SkillNameEnglish, skill.SkillType);
			AddAlias(skill.NameToken, skill.SkillType);
			AddAlias("skill_" + (int)skill.SkillType, skill.SkillType);
			Debug.Log((object)$"[BalrondExtraSkills] Registered skill: {skill.SkillNameEnglish} (internal: {text}, type {(int)skill.SkillType})");
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer != (Object)null)
			{
				EnsureDefsInSkillsList(((Character)localPlayer).GetSkills());
				EnsureSkillSeeded(((Character)localPlayer).GetSkills(), skill.SkillType);
			}
		}

		public static bool IsCustomSkill(SkillType type)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			return Registered.ContainsKey(type);
		}

		internal static bool IsSkillEnabled(SkillType type)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			if (!Registered.TryGetValue(type, out var value) || value == null)
			{
				return true;
			}
			return Launch.Settings?.IsSkillEnabled(value.FixedSkillId) ?? true;
		}

		internal static float GetSkillGainMultiplier(SkillType type)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			if (!Registered.TryGetValue(type, out var value) || value == null)
			{
				return 1f;
			}
			ExtraSkillsConfig settings = Launch.Settings;
			if (settings == null)
			{
				return 1f;
			}
			return Mathf.Max(0f, settings.GetSkillGainMultiplier(value.FixedSkillId));
		}

		internal static float GetSkillEffectMultiplier(SkillType type)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			if (!Registered.TryGetValue(type, out var value) || value == null)
			{
				return 1f;
			}
			ExtraSkillsConfig settings = Launch.Settings;
			if (settings == null)
			{
				return 1f;
			}
			return Mathf.Max(0f, settings.GetSkillEffectMultiplier(value.FixedSkillId));
		}

		public static void RaiseSkill(Player player, SkillType type, float amount)
		{
			//IL_0025: 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_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)player == (Object)null || amount <= 0f)
			{
				return;
			}
			if (IsCustomSkill(type))
			{
				if (!IsSkillEnabled(type))
				{
					return;
				}
				float skillGainMultiplier = GetSkillGainMultiplier(type);
				if (skillGainMultiplier <= 0f)
				{
					return;
				}
				amount *= skillGainMultiplier;
				if (amount <= 0f || float.IsNaN(amount) || float.IsInfinity(amount))
				{
					return;
				}
			}
			Skills skills = ((Character)player).GetSkills();
			if (!((Object)(object)skills == (Object)null))
			{
				EnsureDefsInSkillsList(skills);
				EnsureSkillSeeded(skills, type);
				skills.RaiseSkill(type, amount);
			}
		}

		public static void NotifyAssetsReady()
		{
			try
			{
				Player localPlayer = Player.m_localPlayer;
				if ((Object)(object)localPlayer != (Object)null)
				{
					EnsureDefsInSkillsList(((Character)localPlayer).GetSkills(), forceRefresh: true);
				}
				Player[] array = Object.FindObjectsOfType<Player>();
				foreach (Player val in array)
				{
					if (!((Object)(object)val == (Object)null))
					{
						EnsureDefsInSkillsList(((Character)val).GetSkills(), forceRefresh: true);
					}
				}
			}
			catch
			{
			}
		}

		private static SkillType GetFixedSkillType(BaseSkill skill)
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			int fixedSkillId = skill.FixedSkillId;
			if (fixedSkillId < 10000 || fixedSkillId > 39999)
			{
				Debug.LogWarning((object)$"[BalrondExtraSkills] Skill '{skill.InternalKey}' uses ID outside recommended range 10000-39999: {fixedSkillId}");
			}
			return (SkillType)fixedSkillId;
		}

		private static void AddAlias(string raw, SkillType type)
		{
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			string text = SanitizeKey(raw);
			if (string.IsNullOrEmpty(text))
			{
				return;
			}
			if (ByAlias.TryGetValue(text, out var value))
			{
				if (value != type)
				{
					Debug.LogWarning((object)("[BalrondExtraSkills] Alias collision for '" + raw + "' -> '" + text + "'"));
				}
			}
			else
			{
				ByAlias.Add(text, type);
			}
		}

		private static string SanitizeKey(string s)
		{
			if (string.IsNullOrEmpty(s))
			{
				return "";
			}
			s = s.Trim().ToLowerInvariant();
			s = s.Replace("$", "");
			s = s.Replace(" ", "");
			s = s.Replace("-", "");
			s = s.Replace("_", "");
			return s;
		}

		private static void EnsureDefsInSkillsList(Skills skills, bool forceRefresh = false)
		{
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: 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_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: 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_00df: Expected O, but got Unknown
			if ((Object)(object)skills == (Object)null)
			{
				return;
			}
			List<SkillDef> skills2 = skills.m_skills;
			if (skills2 == null)
			{
				return;
			}
			foreach (KeyValuePair<SkillType, BaseSkill> item in Registered)
			{
				SkillType key = item.Key;
				BaseSkill value = item.Value;
				SkillDef val = null;
				for (int i = 0; i < skills2.Count; i++)
				{
					SkillDef val2 = skills2[i];
					if (val2 != null && val2.m_skill == key)
					{
						val = val2;
						break;
					}
				}
				if (val == null)
				{
					skills2.Add(new SkillDef
					{
						m_skill = key,
						m_icon = value.Icon,
						m_description = value.DescToken,
						m_increseStep = 1f
					});
				}
				else if (forceRefresh)
				{
					val.m_icon = value.Icon;
					val.m_description = value.DescToken;
				}
			}
		}

		private static void EnsureSkillSeeded(Skills skills, SkillType type)
		{
			//IL_0045: 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_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Expected O, but got Unknown
			if ((Object)(object)skills == (Object)null || FI_Skills_m_skillData == null)
			{
				return;
			}
			try
			{
				if (!(FI_Skills_m_skillData.GetValue(skills) is Dictionary<SkillType, Skill> dictionary) || dictionary.ContainsKey(type))
				{
					return;
				}
				if (MI_Skills_GetSkill != null)
				{
					MI_Skills_GetSkill.Invoke(skills, new object[1] { type });
					return;
				}
				SkillDef skillDef = skills.GetSkillDef(type);
				if (skillDef != null)
				{
					dictionary[type] = new Skill(skillDef);
					FI_Skills_m_skillData.SetValue(skills, dictionary);
				}
			}
			catch
			{
			}
		}

		private static void EnsureAllSeeded(Player player)
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)player == (Object)null)
			{
				return;
			}
			Skills skills = ((Character)player).GetSkills();
			if ((Object)(object)skills == (Object)null)
			{
				return;
			}
			EnsureDefsInSkillsList(skills);
			foreach (KeyValuePair<SkillType, BaseSkill> item in Registered)
			{
				EnsureSkillSeeded(skills, item.Key);
			}
		}
	}
	public class BalrondTranslator
	{
		public static Dictionary<string, Dictionary<string, string>> translations = new Dictionary<string, Dictionary<string, string>>();

		public static Dictionary<string, string> getLanguage(string language)
		{
			Dictionary<string, string> result = null;
			try
			{
				result = translations[language];
			}
			catch (Exception)
			{
			}
			return result;
		}
	}
	internal static class PickaxeStaminaReduction
	{
		internal static class Patches
		{
			[HarmonyPatch]
			private static class Attack_GetAttackStamina_Patch
			{
				private static MethodBase TargetMethod()
				{
					return AccessTools.Method(typeof(Attack), "GetAttackStamina", (Type[])null, (Type[])null);
				}

				private static bool Prepare()
				{
					return TargetMethod() != null;
				}

				[HarmonyPostfix]
				private static void Postfix(Attack __instance, ref float __result)
				{
					//IL_009d: Unknown result type (might be due to invalid IL or missing references)
					//IL_00a4: Invalid comparison between Unknown and I4
					if (__instance == null || __result <= 0f)
					{
						return;
					}
					object? obj = FI_AttackCharacter?.GetValue(__instance);
					Humanoid val = (Humanoid)((obj is Humanoid) ? obj : null);
					Player val2 = (Player)(object)((val is Player) ? val : null);
					if ((Object)(object)val2 == (Object)null || (Object)(object)val2 != (Object)(object)Player.m_localPlayer)
					{
						return;
					}
					object? obj2 = FI_AttackWeapon?.GetValue(__instance);
					ItemData val3 = (ItemData)((obj2 is ItemData) ? obj2 : null);
					if (val3?.m_shared != null && (int)val3.m_shared.m_skillType == 12)
					{
						float pickaxeAttackCostMultiplier = GetPickaxeAttackCostMultiplier(val2);
						__result *= pickaxeAttackCostMultiplier;
						if (__result < 0f)
						{
							__result = 0f;
						}
					}
				}
			}

			[HarmonyPatch(typeof(Player), "UseStamina")]
			private static class Player_UseStamina_Fallback_Patch
			{
				private static bool _useFallback;

				private static bool _initialized;

				private static void EnsureInit()
				{
					if (!_initialized)
					{
						_initialized = true;
						_useFallback = AccessTools.Method(typeof(Attack), "GetAttackStamina", (Type[])null, (Type[])null) == null;
					}
				}

				[HarmonyPrefix]
				private static void Prefix(Player __instance, ref float v)
				{
					EnsureInit();
					if (_useFallback && !((Object)(object)__instance == (Object)null) && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && !(v <= 0f))
					{
					}
				}
			}

			private static readonly FieldInfo FI_AttackCharacter = AccessTools.Field(typeof(Attack), "m_character");

			private static readonly FieldInfo FI_AttackWeapon = AccessTools.Field(typeof(Attack), "m_weapon");
		}

		private static float GetPickaxeAttackCostMultiplier(Player player)
		{
			if ((Object)(object)player == (Object)null)
			{
				return 1f;
			}
			ExtraSkillsConfig settings = Launch.Settings;
			if (settings != null && !settings.PickaxeStaminaReductionEnabled.Value)
			{
				return 1f;
			}
			Skills skills = ((Character)player).GetSkills();
			float num = ((skills != null) ? skills.GetSkillLevel((SkillType)12) : 0f);
			if (num <= 0f)
			{
				return 1f;
			}
			float num2 = Mathf.Clamp01(num / 100f);
			float num3 = settings?.PickaxeStaminaReductionMultiplier.Value ?? 1f;
			float num4 = settings?.PickaxeMaxReductionAt100.Value ?? 0.25f;
			float num5 = settings?.PickaxeMinCostMultiplier.Value ?? 0.2f;
			float num6 = num2 * Mathf.Clamp01(num4) * Mathf.Max(0f, num3);
			float num7 = 1f - num6;
			if (num7 < Mathf.Clamp01(num5))
			{
				num7 = Mathf.Clamp01(num5);
			}
			return num7;
		}
	}
	public abstract class BaseSkill
	{
		public readonly int FixedSkillId;

		public readonly string InternalKey;

		public readonly string SkillNameEnglish;

		public readonly string DescriptionEnglish;

		private Sprite _icon;

		private readonly string _iconAssetName;

		public SkillType SkillType { get; internal set; } = (SkillType)0;

		public Sprite Icon => ((Object)(object)_icon != (Object)null) ? _icon : BalrondIconUtil.Placeholder;

		public string IconAssetName => _iconAssetName;

		public string NameToken => "$tag_skill_" + InternalKey + "_bal";

		public string DescToken => "$tag_skill_" + InternalKey + "_bal_description";

		protected BaseSkill(int fixedSkillId, string internalKey, string englishName, string englishDescription, string iconAssetName)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			if (fixedSkillId <= 0)
			{
				throw new ArgumentOutOfRangeException("fixedSkillId", "Skill ID must be greater than 0.");
			}
			FixedSkillId = fixedSkillId;
			InternalKey = internalKey ?? throw new ArgumentNullException("internalKey");
			SkillNameEnglish = englishName ?? throw new ArgumentNullException("englishName");
			DescriptionEnglish = englishDescription ?? "";
			_iconAssetName = iconAssetName ?? "";
			if (!string.IsNullOrEmpty(_iconAssetName))
			{
				_icon = ModResourceLoader.skillIcons.Find((Sprite x) => ((Object)x).name == _iconAssetName);
			}
			try
			{
				BalrondSkillSystem.RegisterSkill(this);
			}
			catch (Exception arg)
			{
				Debug.LogWarning((object)$"[BalrondExtraSkills] Failed to auto-register skill '{englishName}': {arg}");
			}
		}

		public void SetIcon(Sprite icon)
		{
			if ((Object)(object)icon != (Object)null)
			{
				_icon = icon;
			}
		}
	}
	public class DatabaseAddMethods
	{
		public void AddItems(List<GameObject> items)
		{
			foreach (GameObject item in items)
			{
				AddItem(item);
			}
		}

		public void AddRecipes(List<Recipe> recipes)
		{
			foreach (Recipe recipe in recipes)
			{
				AddRecipe(recipe);
			}
		}

		public void AddStatuseffects(List<StatusEffect> statusEffects)
		{
			foreach (StatusEffect statusEffect in statusEffects)
			{
				AddStatus(statusEffect);
			}
		}

		private bool IsObjectDBValid()
		{
			return (Object)(object)ObjectDB.instance != (Object)null && ObjectDB.instance.m_items.Count != 0 && ObjectDB.instance.m_recipes.Count != 0 && (Object)(object)ObjectDB.instance.GetItemPrefab("Amber") != (Object)null;
		}

		private void AddStatus(StatusEffect status)
		{
			if (!IsObjectDBValid())
			{
				return;
			}
			if ((Object)(object)status != (Object)null)
			{
				if ((Object)(object)ObjectDB.instance.GetStatusEffect(status.m_nameHash) == (Object)null)
				{
					ObjectDB.instance.m_StatusEffects.Add(status);
				}
				else
				{
					Debug.Log((object)(Launch.projectName + ":  " + ((Object)status).name + " - Status already in the game"));
				}
			}
			else
			{
				Debug.LogError((object)(Launch.projectName + ":  " + ((Object)status).name + " - Status not found"));
			}
		}

		private void AddRecipe(Recipe recipe)
		{
			if (!IsObjectDBValid())
			{
				return;
			}
			if ((Object)(object)recipe != (Object)null)
			{
				if ((Object)(object)ObjectDB.instance.m_recipes.Find((Recipe x) => ((Object)x).name == ((Object)recipe).name) == (Object)null)
				{
					if ((Object)(object)recipe.m_item != (Object)null)
					{
						ObjectDB.instance.m_recipes.Add(recipe);
					}
				}
				else
				{
					Debug.Log((object)(Launch.projectName + ":  " + ((Object)recipe).name + " - Recipe with this name already in the Game"));
				}
			}
			else
			{
				Debug.LogError((object)(Launch.projectName + ":  " + ((Object)recipe).name + " - Recipe not found"));
			}
		}

		private void AddItem(GameObject newPrefab)
		{
			if (!IsObjectDBValid())
			{
				return;
			}
			ItemDrop component = newPrefab.GetComponent<ItemDrop>();
			if ((Object)(object)component != (Object)null)
			{
				if ((Object)(object)ObjectDB.instance.GetItemPrefab(((Object)newPrefab).name) == (Object)null)
				{
					ObjectDB.instance.m_items.Add(newPrefab);
					Dictionary<int, GameObject> dictionary = (Dictionary<int, GameObject>)typeof(ObjectDB).GetField("m_itemByHash", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(ObjectDB.instance);
					dictionary[((Object)newPrefab).name.GetHashCode()] = newPrefab;
				}
				else
				{
					Debug.Log((object)(Launch.projectName + ": " + ((Object)newPrefab).name + " - ItemDrop already exist"));
				}
			}
			else
			{
				Debug.LogError((object)(Launch.projectName + ": " + ((Object)newPrefab).name + " - ItemDrop not found on prefab"));
			}
		}
	}
	[Serializable]
	public class MappedEffectList
	{
		public List<EffectInfo> pieceEffect;

		public List<EffectInfo> destroyedEffects;

		public List<EffectInfo> hitEffects;

		public List<EffectInfo> switchEffect;

		public List<EffectInfo> blockEffect;

		public List<EffectInfo> equipEffect;

		public List<EffectInfo> hitEffect;

		public List<EffectInfo> hitTerrainEffect;

		public List<EffectInfo> holdStartEffect;

		public List<EffectInfo> startEffect;

		public List<EffectInfo> trailStartEffect;

		public List<EffectInfo> triggerEffect;

		public List<EffectInfo> unequipEffect;

		public EffectList createEffectListFromInfo(List<EffectInfo> list)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Expected O, but got Unknown
			EffectList val = new EffectList();
			List<EffectData> list2 = new List<EffectData>();
			val.m_effectPrefabs = list2.ToArray();
			return val;
		}

		private EffectData createEffectData(EffectInfo info)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Expected O, but got Unknown
			EffectData val = new EffectData();
			val.m_inheritParentRotation = info.inheritRotation;
			val.m_multiplyParentVisualScale = info.multiplyScale;
			val.m_childTransform = info.childName;
			val.m_inheritParentScale = info.inheritScale;
			val.m_variant = info.variant;
			val.m_scale = info.scale;
			val.m_attach = info.attach;
			val.m_follow = info.follow;
			val.m_prefab = ZNetScene.instance.m_prefabs.Find((GameObject x) => ((Object)x).name == info.name);
			return val;
		}
	}
	[Serializable]
	public struct EffectInfo
	{
		public string name;

		public bool enabled;

		public int variant;

		public bool attach;

		public bool follow;

		public bool inheritRotation;

		public bool inheritScale;

		public bool multiplyScale;

		public bool radnomRotation;

		public bool scale;

		public string childName;

		public EffectInfo(string name, bool enabled = true, int variant = -1, bool attach = false, bool follow = false, bool inheritRotation = false, bool inheritScale = false, bool multiplyScale = false, bool radnomRotation = false, bool scale = false, string childName = null)
		{
			this.name = name;
			this.enabled = enabled;
			this.variant = variant;
			this.attach = attach;
			this.follow = follow;
			this.inheritRotation = inheritRotation;
			this.inheritScale = inheritScale;
			this.multiplyScale = multiplyScale;
			this.radnomRotation = radnomRotation;
			this.scale = scale;
			this.childName = childName;
		}
	}
	public sealed class ModResourceLoader
	{
		public AssetBundle assetBundle;

		public readonly List<GameObject> itemPrefabs = new List<GameObject>();

		public readonly List<GameObject> otherPrefabs = new List<GameObject>();

		public static List<Sprite> skillIcons = new List<Sprite>();

		public void loadAssets()
		{
			assetBundle = GetAssetBundleFromResources("balrondextraskills");
			if ((Object)(object)assetBundle == (Object)null)
			{
				Debug.LogWarning((object)(Launch.projectName + " AssetBundle not found (embedded resource endswith 'BalrondExtraSkills')."));
				return;
			}
			string basePath = "Assets/Custom/BalrondExtraSkills/";
			LoadSkillIcons();
			loadItems(basePath);
			loadOther(basePath);
		}

		public void AddPrefabsToZnetScene(ZNetScene zNetScene)
		{
			if (!((Object)(object)zNetScene == (Object)null))
			{
				validateAddedPrefabs(itemPrefabs, zNetScene);
				validateAddedPrefabs(otherPrefabs, zNetScene);
				zNetScene.m_prefabs.RemoveAll((GameObject x) => (Object)(object)x == (Object)null);
			}
		}

		public void AddItemsToObjectDB()
		{
			if ((Object)(object)ObjectDB.instance == (Object)null || ObjectDB.instance.m_items == null)
			{
				return;
			}
			for (int i = 0; i < itemPrefabs.Count; i++)
			{
				GameObject go = itemPrefabs[i];
				if (!((Object)(object)go == (Object)null) && !((Object)(object)ObjectDB.instance.m_items.Find((GameObject x) => (Object)(object)x != (Object)null && ((Object)x).name == ((Object)go).name) != (Object)null))
				{
					ObjectDB.instance.m_items.Add(go);
				}
			}
		}

		private void loadItems(string basePath)
		{
			string mainPath = basePath + "Items/";
			string[] nameList = new string[0];
			addNewPrefabToCollection(nameList, mainPath, itemPrefabs, "item", requireZNetView: false);
		}

		private void loadOther(string basePath)
		{
			string mainPath = basePath + "Other/";
			string[] nameList = new string[0];
			addNewPrefabToCollection(nameList, mainPath, otherPrefabs, "other", requireZNetView: false);
		}

		private void validateAddedPrefabs(List<GameObject> list, ZNetScene zNetScene)
		{
			if (list == null || (Object)(object)zNetScene == (Object)null)
			{
				return;
			}
			for (int i = 0; i < list.Count; i++)
			{
				GameObject val = list[i];
				if (!((Object)(object)val == (Object)null))
				{
					int key = BalrondHashCompat.StableHash(((Object)val).name);
					if (zNetScene.m_namedPrefabs.ContainsKey(key))
					{
						Debug.LogWarning((object)("DUPLICATE: " + ((Object)val).name));
					}
					else
					{
						zNetScene.m_prefabs.Add(val);
					}
				}
			}
		}

		private void addNewPrefabToCollection(string[] nameList, string mainPath, List<GameObject> prefabList, string typeName, bool requireZNetView)
		{
			if ((Object)(object)assetBundle == (Object)null || nameList == null || nameList.Length == 0)
			{
				return;
			}
			foreach (string text in nameList)
			{
				if (!string.IsNullOrEmpty(text))
				{
					GameObject val = assetBundle.LoadAsset<GameObject>(mainPath + text + ".prefab");
					if ((Object)(object)val == (Object)null)
					{
						Debug.LogWarning((object)("Could not find " + typeName + " with name: " + text + " at " + mainPath));
					}
					else if (requireZNetView && (Object)(object)val.GetComponent<ZNetView>() == (Object)null)
					{
						Debug.LogWarning((object)("Prefab has no ZNetView (skipped): " + text));
					}
					else
					{
						ShaderReplacment.Replace(val);
						prefabList.Add(val);
					}
				}
			}
		}

		public void LoadSkillIcons()
		{
			skillIcons.Clear();
			if ((Object)(object)assetBundle == (Object)null)
			{
				return;
			}
			try
			{
				Sprite[] array = assetBundle.LoadAllAssets<Sprite>();
				if (array == null || array.Length == 0)
				{
					Debug.LogWarning((object)(Launch.projectName + " No Sprite assets found in assetbundle."));
					return;
				}
				foreach (Sprite val in array)
				{
					if (!((Object)(object)val == (Object)null))
					{
						skillIcons.Add(val);
					}
				}
			}
			catch (Exception ex)
			{
				Debug.LogWarning((object)(Launch.projectName + " LoadSkillIcons failed: " + ex));
			}
		}

		public static Sprite GetSkillIconByName(string iconName)
		{
			if (string.IsNullOrEmpty(iconName))
			{
				return null;
			}
			for (int i = 0; i < skillIcons.Count; i++)
			{
				Sprite val = skillIcons[i];
				if ((Object)(object)val != (Object)null && ((Object)val).name == iconName)
				{
					return val;
				}
			}
			return null;
		}

		private static AssetBundle GetAssetBundleFromResources(string filenameSuffix)
		{
			Assembly executingAssembly = Assembly.GetExecutingAssembly();
			string text = null;
			string[] manifestResourceNames = executingAssembly.GetManifestResourceNames();
			foreach (string text2 in manifestResourceNames)
			{
				if (text2.EndsWith(filenameSuffix, StringComparison.OrdinalIgnoreCase))
				{
					text = text2;
					break;
				}
			}
			if (text == null)
			{
				return null;
			}
			using Stream stream = executingAssembly.GetManifestResourceStream(text);
			if (stream == null)
			{
				return null;
			}
			return AssetBundle.LoadFromStream(stream);
		}
	}
	public class ShaderReplacment
	{
		public static List<GameObject> prefabsToReplaceShader = new List<GameObject>();

		public static List<Material> materialsInPrefabs = new List<Material>();

		public string[] shaderlist = new string[49]
		{
			"Custom/AlphaParticle", "Custom/Blob", "Custom/Bonemass", "Custom/Clouds", "Custom/Creature", "Custom/Decal", "Custom/Distortion", "Custom/Flow", "Custom/FlowOpaque", "Custom/Grass",
			"Custom/GuiScroll", "Custom/Heightmap", "Custom/icon", "Custom/InteriorSide", "Custom/LitGui", "Custom/LitParticles", "Custom/mapshader", "Custom/ParticleDecal", "Custom/Piece", "Custom/Player",
			"Custom/Rug", "Custom/ShadowBlob", "Custom/SkyboxProcedural", "Custom/SkyObject", "Custom/StaticRock", "Custom/Tar", "Custom/Trilinearmap", "Custom/UI/BGBlur", "Custom/Vegetation", "Custom/Water",
			"Custom/WaterBottom", "Custom/WaterMask", "Custom/Yggdrasil", "Custom/Yggdrasil/root", "Hidden/BlitCopyHDRTonemap", "Hidden/Dof/DepthOfFieldHdr", "Hidden/Dof/DX11Dof", "Hidden/Internal-Loading", "Hidden/Internal-UIRDefaultWorld", "Hidden/SimpleClear",
			"Hidden/SunShaftsComposite", "Lux Lit Particles/ Bumped", "Lux Lit Particles/ Tess Bumped", "Particles/Standard Surface2", "Particles/Standard Unlit2", "Standard TwoSided", "ToonDeferredShading2017", "Unlit/DepthWrite", "Unlit/Lighting"
		};

		public static List<Shader> shaders = new List<Shader>();

		private static readonly HashSet<Shader> CachedShaders = new HashSet<Shader>();

		public static bool debug = true;

		public static Shader findShader(string name)
		{
			Shader[] array = Resources.FindObjectsOfTypeAll<Shader>();
			if (array.Length == 0)
			{
				Debug.LogWarning((object)"SHADER LIST IS EMPTY!");
				return null;
			}
			if (debug)
			{
			}
			return shaders.Find((Shader x) => ((Object)x).name == name);
		}

		public static Shader GetShaderByName(string name)
		{
			return shaders.Find((Shader x) => ((Object)x).name == name.Trim());
		}

		public static void debugShaderList(List<Shader> shadersRes)
		{
			foreach (Shader shadersRe in shadersRes)
			{
				Debug.LogWarning((object)("SHADER NAME IS: " + ((Object)shadersRe).name));
			}
			debug = false;
		}

		public static void Replace(GameObject gameObject)
		{
			prefabsToReplaceShader.Add(gameObject);
			GetMaterialsInPrefab(gameObject);
		}

		public static void GetMaterialsInPrefab(GameObject gameObject)
		{
			Renderer[] componentsInChildren = gameObject.GetComponentsInChildren<Renderer>(true);
			Renderer[] array = componentsInChildren;
			foreach (Renderer val in array)
			{
				Material[] sharedMaterials = val.sharedMaterials;
				if (sharedMaterials == null || sharedMaterials.Length == 0)
				{
					continue;
				}
				Material[] array2 = sharedMaterials;
				foreach (Material val2 in array2)
				{
					if ((Object)(object)val2 != (Object)null)
					{
						materialsInPrefabs.Add(val2);
					}
				}
			}
		}

		public static void getMeShaders()
		{
			AssetBundle[] array = Resources.FindObjectsOfTypeAll<AssetBundle>();
			AssetBundle[] array2 = array;
			foreach (AssetBundle val in array2)
			{
				IEnumerable<Shader> enumerable3;
				try
				{
					IEnumerable<Shader> enumerable2;
					if (!val.isStreamedSceneAssetBundle || !Object.op_Implicit((Object)(object)val))
					{
						IEnumerable<Shader> enumerable = val.LoadAllAssets<Shader>();
						enumerable2 = enumerable;
					}
					else
					{
						enumerable2 = from shader in ((IEnumerable<string>)val.GetAllAssetNames()).Select((Func<string, Shader>)val.LoadAsset<Shader>)
							where (Object)(object)shader != (Object)null
							select shader;
					}
					enumerable3 = enumerable2;
				}
				catch (Exception)
				{
					continue;
				}
				if (enumerable3 == null)
				{
					continue;
				}
				foreach (Shader item in enumerable3)
				{
					CachedShaders.Add(item);
				}
			}
		}

		public static void runMaterialFix()
		{
			getMeShaders();
			shaders.AddRange(CachedShaders);
			foreach (Material materialsInPrefab in materialsInPrefabs)
			{
				Shader shader = materialsInPrefab.shader;
				if (!((Object)(object)shader == (Object)null))
				{
					string name = ((Object)shader).name;
					if (!(name == "Standard") && !name.Contains("ScrollingTex") && name.Contains("Balrond"))
					{
						setProperValue(materialsInPrefab, name);
					}
				}
			}
		}

		private static void setProperValue(Material material, string shaderName)
		{
			string name = shaderName.Replace("Balrond", "Custom");
			name = checkNaming(name);
			Shader shaderByName = GetShaderByName(name);
			if (!((Object)(object)shaderByName == (Object)null))
			{
				material.shader = shaderByName;
			}
		}

		private static string checkNaming(string name)
		{
			string result = name;
			if (name.Contains("Bumped"))
			{
				result = name.Replace("Custom", "Lux Lit Particles");
			}
			if (name.Contains("Tess Bumped"))
			{
				result = name.Replace("Custom", "Lux Lit Particles");
			}
			if (name.Contains("Standard Surface"))
			{
				result = name.Replace("Custom", "Particles");
				result = result.Replace("Standard Surface2", "Standard Surface");
			}
			if (name.Contains("Standard Unlit"))
			{
				result = name.Replace("Custom", "Particles");
				result = result.Replace("Standard Unlit", "Standard Unlit2");
				result = result.Replace("Standard Unlit22", "Standard Unlit2");
			}
			return result;
		}
	}
	public class TableMapper
	{
		public static CraftingStation cauldron;

		public static CraftingStation workbench;

		public static CraftingStation heavyWorkbench;

		public static CraftingStation forge;

		public static CraftingStation ironworks;

		public static CraftingStation blackforge;

		public static CraftingStation stoneCutter;

		public static CraftingStation artisian;

		public static CraftingStation magetable;

		public static CraftingStation runeforge;

		public static CraftingStation tannery;

		public static CraftingStation fletcher;

		public static CraftingStation grill;

		public static CraftingStation alchemylab;

		public static CraftingStation shamantable;

		public static CraftingStation foodtable;

		public static List<GameObject> pieces = new List<GameObject>();

		public static void setupTables(List<GameObject> list)
		{
			pieces = list;
			prepareTables();
		}

		private static CraftingStation FindStation(List<GameObject> list, string name, string replacement = "piece_workbench")
		{
			GameObject val = list.Find((GameObject x) => ((Object)x).name == name);
			if ((Object)(object)val != (Object)null)
			{
				return val.GetComponent<CraftingStation>();
			}
			if ((Object)(object)val == (Object)null)
			{
				val = list.Find((GameObject x) => ((Object)x).name == replacement);
				if ((Object)(object)val != (Object)null)
				{
					return val.GetComponent<CraftingStation>();
				}
			}
			Debug.LogWarning((object)("TableMapper - Station not found: " + name));
			return null;
		}

		private static void prepareTables()
		{
			cauldron = FindStation(pieces, "piece_cauldron");
			workbench = FindStation(pieces, "piece_workbench");
			heavyWorkbench = FindStation(pieces, "piece_heavy_workbench_bal");
			forge = FindStation(pieces, "forge");
			ironworks = FindStation(pieces, "piece_metalworks_bal", "forge");
			blackforge = FindStation(pieces, "blackforge");
			stoneCutter = FindStation(pieces, "piece_stonecutter");
			artisian = FindStation(pieces, "piece_artisanstation");
			runeforge = FindStation(pieces, "piece_runeforge_bal", "blackforge");
			magetable = FindStation(pieces, "piece_magetable");
			fletcher = FindStation(pieces, "piece_fletcher_bal");
			shamantable = FindStation(pieces, "piece_shamantable_bal", "piece_magetable");
			foodtable = FindStation(pieces, "piece_preptable");
			alchemylab = FindStation(pieces, "piece_MeadCauldron");
		}
	}
	public class JsonLoader
	{
		public string defaultPath = string.Empty;

		public void loadJson()
		{
			LoadTranslations();
			justDefaultPath();
		}

		public void justDefaultPath()
		{
			string configPath = Paths.ConfigPath;
			string text = Path.Combine(configPath, "BalrondExtraSkills-translation/");
			defaultPath = text;
		}

		public void createDefaultPath()
		{
			string configPath = Paths.ConfigPath;
			string text = Path.Combine(configPath, "BalrondExtraSkills-translation/");
			if (!Directory.Exists(text))
			{
				CreateFolder(text);
			}
			else
			{
				Debug.Log((object)("BalrondExtraSkills: Folder already exists: " + text));
			}
			defaultPath = text;
		}

		private string[] jsonFilePath(string folderName, string extension)
		{
			string configPath = Paths.ConfigPath;
			string text = Path.Combine(configPath, "BalrondExtraSkills-translation/");
			if (!Directory.Exists(text))
			{
				CreateFolder(text);
			}
			else
			{
				Debug.Log((object)("BalrondExtraSkills: Folder already exists: " + text));
			}
			string[] files = Directory.GetFiles(text, extension);
			Debug.Log((object)("BalrondExtraSkills:" + folderName + " Json Files Found: " + files.Length));
			return files;
		}

		private static void CreateFolder(string path)
		{
			try
			{
				Directory.CreateDirectory(path);
				Debug.Log((object)"BalrondExtraSkills: Folder created successfully.");
			}
			catch (Exception ex)
			{
				Debug.Log((object)("BalrondExtraSkills: Error creating folder: " + ex.Message));
			}
		}

		private void LoadTranslations()
		{
			int num = 0;
			string[] array = jsonFilePath("Translation", "*.json");
			foreach (string text in array)
			{
				string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(text);
				string json = File.ReadAllText(text);
				JsonData jsonData = JsonMapper.ToObject(json);
				Dictionary<string, string> dictionary = new Dictionary<string, string>();
				foreach (string key in jsonData.Keys)
				{
					dictionary[key] = jsonData[key].ToString();
				}
				if (dictionary != null)
				{
					BalrondTranslator.translations.Add(fileNameWithoutExtension, dictionary);
					Debug.Log((object)("BalrondExtraSkills: Json Files Language: " + fileNameWithoutExtension));
					num++;
				}
				else
				{
					Debug.LogError((object)("BalrondExtraSkills: Loading FAILED file: " + text));
				}
			}
			Debug.Log((object)("BalrondExtraSkills: Translation JsonFiles Loaded: " + num));
		}
	}
	[BepInPlugin("balrond.astafaraios.BalrondExtraSkills", "BalrondExtraSkills", "0.1.4")]
	public sealed class Launch : BaseUnityPlugin
	{
		[HarmonyPatch(typeof(ZNetScene), "Awake")]
		private static class ZNetScene_Awake_Path
		{
			private static bool ranFix;

			private static void Prefix(ZNetScene __instance)
			{
				try
				{
					if ((Object)(object)__instance == (Object)null || modResourceLoader == null)
					{
						return;
					}
					modResourceLoader.AddPrefabsToZnetScene(__instance);
					if (!ranFix)
					{
						ZNet val = Object.FindObjectOfType<ZNet>();
						if (!((Object)(object)val != (Object)null) || !val.IsDedicated())
						{
							ShaderReplacment.runMaterialFix();
							ranFix = true;
						}
					}
				}
				catch (Exception arg)
				{
					Debug.LogError((object)string.Format("[{0}] ZNetScene_Awake_Path failed: {1}", "BalrondExtraSkills", arg));
				}
			}
		}

		[HarmonyPatch(typeof(ObjectDB), "Awake")]
		private static class ObjectDB_Awake_Path
		{
			private static void Postfix()
			{
				try
				{
					if (IsObjectDBValid() && modResourceLoader != null)
					{
						modResourceLoader.AddItemsToObjectDB();
					}
				}
				catch (Exception arg)
				{
					Debug.LogError((object)string.Format("[{0}] ObjectDB_Awake_Path failed: {1}", "BalrondExtraSkills", arg));
				}
			}
		}

		[HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")]
		private static class Object_CopyOtherDB_Path
		{
			private static void Postfix()
			{
				try
				{
					if (IsObjectDBValid() && modResourceLoader != null)
					{
						modResourceLoader.AddItemsToObjectDB();
					}
				}
				catch (Exception arg)
				{
					Debug.LogError((object)string.Format("[{0}] Object_CopyOtherDB_Path failed: {1}", "BalrondExtraSkills", arg));
				}
			}
		}

		private Harmony harmony;

		internal static Launch Instance;

		internal static Harmony HarmonyInstance;

		internal static ConfigSync ConfigSyncInstance;

		internal static ExtraSkillsConfig Settings;

		public const string PluginGUID = "balrond.astafaraios.BalrondExtraSkills";

		public const string PluginName = "BalrondExtraSkills";

		public const string PluginVersion = "0.1.4";

		public static readonly ModResourceLoader modResourceLoader = new ModResourceLoader();

		public static readonly JsonLoader jsonLoader = new JsonLoader();

		public static readonly string projectName = "[BalrondExtraSkills]";

		public const bool Enabled = true;

		public const bool DebugLog = false;

		private void Awake()
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Expected O, but got Unknown
			Instance = this;
			try
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)"[BES bootstrap 1/8] Launch.Awake entered.");
				bool flag = false;
				((BaseUnityPlugin)this).Logger.LogInfo((object)"[BES bootstrap 2/8] Initializing Harmony.");
				harmony = new Harmony("balrond.astafaraios.BalrondExtraSkills");
				HarmonyInstance = harmony;
				((BaseUnityPlugin)this).Logger.LogInfo((object)"[BES bootstrap 3/8] Initializing ServerSync and configuration.");
				ConfigSyncInstance = new ConfigSync("balrond.astafaraios.BalrondExtraSkills")
				{
					DisplayName = "BalrondExtraSkills",
					CurrentVersion = "0.1.4",
					MinimumRequiredVersion = "0.1.4"
				};
				Settings = new ExtraSkillsConfig((BaseUnityPlugin)(object)this, ConfigSyncInstance);
				ConfigSyncInstance.AddLockingConfigEntry<bool>(Settings.LockConfiguration);
				((BaseUnityPlugin)this).Logger.LogInfo((object)"[BES bootstrap 4/8] Loading translation data.");
				try
				{
					if (jsonLoader != null)
					{
						jsonLoader.loadJson();
					}
					else
					{
						((BaseUnityPlugin)this).Logger.LogWarning((object)"BalrondExtraSkills: jsonLoader is null.");
					}
				}
				catch (Exception ex)
				{
					((BaseUnityPlugin)this).Logger.LogError((object)("BalrondExtraSkills: Failed to load json data. " + ex));
				}
				((BaseUnityPlugin)this).Logger.LogInfo((object)"[BES bootstrap 5/8] Applying Harmony patches.");
				harmony.PatchAll();
				((BaseUnityPlugin)this).Logger.LogInfo((object)"[BES bootstrap 6/8] Loading embedded assets.");
				try
				{
					if (modResourceLoader != null)
					{
						modResourceLoader.loadAssets();
					}
					else
					{
						((BaseUnityPlugin)this).Logger.LogWarning((object)"BalrondExtraSkills: modResourceLoader is null.");
					}
				}
				catch (Exception ex2)
				{
					((BaseUnityPlugin)this).Logger.LogError((object)("BalrondExtraSkills: Failed to load assets. " + ex2));
				}
				((BaseUnityPlugin)this).Logger.LogInfo((object)"[BES bootstrap 7/8] Registering custom skills.");
				RegisterSkillsSafe();
				((BaseUnityPlugin)this).Logger.LogInfo((object)"[BES bootstrap 8/8] Refreshing skill assets and definitions.");
				try
				{
					BalrondSkillSystem.NotifyAssetsReady();
				}
				catch (Exception ex3)
				{
					((BaseUnityPlugin)this).Logger.LogError((object)("BalrondExtraSkills: Failed during NotifyAssetsReady. " + ex3));
				}
				((BaseUnityPlugin)this).Logger.LogInfo((object)"BalrondExtraSkills 0.1.4 loaded with ServerSync.");
			}
			catch (Exception ex4)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("[BES bootstrap FATAL] Startup failed after Launch was instantiated. Full exception follows:\n" + ex4));
				throw;
			}
		}

		private void OnDestroy()
		{
			try
			{
				if (harmony != null)
				{
					harmony.UnpatchSelf();
				}
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("BalrondExtraSkills: Failed during OnDestroy unpatch. " + ex));
			}
			finally
			{
				Settings = null;
				ConfigSyncInstance = null;
				HarmonyInstance = null;
				harmony = null;
				Instance = null;
			}
		}

		private void RegisterSkillsSafe()
		{
			TryRegisterSkill(() => VitalitySkill.Instance, "VitalitySkill");
			TryRegisterSkill(() => ArcanaSkill.Instance, "ArcanaSkill");
			TryRegisterSkill(() => FortitudeSkill.Instance, "FortitudeSkill");
			TryRegisterSkill(() => EnduranceSkill.Instance, "EnduranceSkill");
			TryRegisterSkill(() => HaulingSkill.Instance, "HaulingSkill");
			TryRegisterSkill(() => ExplorationSkill.Instance, "ExplorationSkill");
		}

		private void TryRegisterSkill(Func<BaseSkill> getter, string skillName)
		{
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Invalid comparison between Unknown and I4
			try
			{
				if (getter == null)
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)("BalrondExtraSkills: Skill getter for " + skillName + " is null."));
					return;
				}
				BaseSkill baseSkill = getter();
				if (baseSkill == null)
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)("BalrondExtraSkills: Skill instance for " + skillName + " is null."));
				}
				else if ((int)baseSkill.SkillType == 0)
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)("BalrondExtraSkills: Skill " + skillName + " has SkillType.None after initialization. Check FixedSkillId / registration."));
				}
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("BalrondExtraSkills: Failed to initialize skill " + skillName + ". " + ex));
			}
		}

		public static bool IsObjectDBValid()
		{
			try
			{
				return (Object)(object)ObjectDB.instance != (Object)null && ObjectDB.instance.m_items != null && ObjectDB.instance.m_items.Count != 0 && (Object)(object)ObjectDB.instance.GetItemPrefab("Amber") != (Object)null;
			}
			catch
			{
				return false;
			}
		}
	}
	internal sealed class ExtraSkillsConfig
	{
		internal const float DefaultVitalityHealthBonusAt100 = 10f;

		internal const float DefaultVitalityFoodXpPerHealth = 0.01f;

		internal const float DefaultVitalityMaxFoodXpPerEat = 2f;

		internal const float DefaultVitalitySleepXpPerWake = 0.25f;

		internal const float DefaultVitalitySleepAwardCooldownSeconds = 2f;

		internal const float DefaultArcanaEitrBonusAt100 = 10f;

		internal const float DefaultArcanaFoodXpPerEitr = 0.02f;

		internal const float DefaultArcanaMaxFoodXpPerEat = 2f;

		internal const float DefaultArcanaXpPerElementalDamage = 0.01f;

		internal const float DefaultArcanaMaxXpPerHit = 1f;

		internal const float DefaultArcanaDotEnvironmentXpMultiplier = 0.5f;

		internal const float DefaultEnduranceStaminaBonusAt100 = 20f;

		internal const float DefaultEnduranceMinStaminaUseToTrigger = 5f;

		internal const float DefaultEnduranceXpFractionOfLastUse = 0.02f;

		internal const float DefaultEnduranceMaxXpPerExhaust = 5f;

		internal const float DefaultEnduranceRecoverThresholdFraction = 0.25f;

		internal const float DefaultEnduranceExhaustedStaminaThreshold = 1f;

		internal const float DefaultExplorationBaseRadius = 100f;

		internal const float DefaultExplorationBonusRadiusAt100 = 100f;

		internal const float DefaultExplorationMinRadius = 50f;

		internal const float DefaultExplorationMaxRadius = 300f;

		internal const float DefaultExplorationXpPerSuccessfulPass = 0.08f;

		internal const float DefaultExplorationMinTimeBetweenAwards = 1f;

		internal const float DefaultFortitudeArmorBonusAt100 = 10f;

		internal const float DefaultFortitudeXpPerHpLost = 0.016f;

		internal const float DefaultFortitudeMaxXpPerHit = 1f;

		internal const float DefaultFortitudeElementalXpMultiplier = 0.5f;

		internal const float DefaultHaulingCarryWeightBonusAt100 = 50f;

		internal const float DefaultHaulingWeightRatioThreshold = 0.9f;

		internal const float DefaultHaulingRunXpFraction = 0.2f;

		internal const float DefaultHaulingSneakXpFraction = 0.25f;

		internal const float DefaultHaulingJumpXpFraction = 0.35f;

		internal const float DefaultHaulingMaxFactorPerTrigger = 0.35f;

		internal const float DefaultHaulingFallbackMaxCarryWeight = 300f;

		internal const float DefaultMiningPickaxeBonusAt100 = 0.25f;

		internal const float DefaultWoodcuttingChopBonusAt100 = 0.25f;

		internal const float DefaultWoodcuttingMinChopToConsider = 0.001f;

		internal const float DefaultWoodcuttingVirtualChopMaxConvertAt100 = 0.12f;

		internal const bool DefaultWoodcuttingVirtualChopOnlyIfNoChopDamage = true;

		internal const float DefaultPickaxeMaxReductionAt100 = 0.25f;

		internal const float DefaultPickaxeMinCostMultiplier = 0.2f;

		private readonly BaseUnityPlugin _plugin;

		private readonly ConfigSync _configSync;

		internal ConfigEntry<bool> LockConfiguration { get; private set; }

		internal ConfigEntry<bool> VitalityEnabled { get; private set; }

		internal ConfigEntry<float> VitalityGainMultiplier { get; private set; }

		internal ConfigEntry<float> VitalityEffectMultiplier { get; private set; }

		internal ConfigEntry<float> VitalityHealthBonusAt100 { get; private set; }

		internal ConfigEntry<float> VitalityFoodXpPerHealth { get; private set; }

		internal ConfigEntry<float> VitalityMaxFoodXpPerEat { get; private set; }

		internal ConfigEntry<float> VitalitySleepXpPerWake { get; private set; }

		internal ConfigEntry<float> VitalitySleepAwardCooldownSeconds { get; private set; }

		internal ConfigEntry<bool> ArcanaEnabled { get; private set; }

		internal ConfigEntry<float> ArcanaGainMultiplier { get; private set; }

		internal ConfigEntry<float> ArcanaEffectMultiplier { get; private set; }

		internal ConfigEntry<float> ArcanaEitrBonusAt100 { get; private set; }

		internal ConfigEntry<float> ArcanaFoodXpPerEitr { get; private set; }

		internal ConfigEntry<float> ArcanaMaxFoodXpPerEat { get; private set; }

		internal ConfigEntry<float> ArcanaXpPerElementalDamage { get; private set; }

		internal ConfigEntry<float> ArcanaMaxXpPerHit { get; private set; }

		internal ConfigEntry<bool> ArcanaCountDotAndEnvironment { get; private set; }

		internal ConfigEntry<float> ArcanaDotEnvironmentXpMultiplier { get; private set; }

		internal ConfigEntry<bool> EnduranceEnabled { get; private set; }

		internal ConfigEntry<float> EnduranceGainMultiplier { get; private set; }

		internal ConfigEntry<float> EnduranceEffectMultiplier { get; private set; }

		internal ConfigEntry<float> EnduranceStaminaBonusAt100 { get; private set; }

		internal ConfigEntry<float> EnduranceMinStaminaUseToTrigger { get; private set; }

		internal ConfigEntry<float> EnduranceXpFractionOfLastUse { get; private set; }

		internal ConfigEntry<float> EnduranceMaxXpPerExhaust { get; private set; }

		internal ConfigEntry<float> EnduranceRecoverThresholdFraction { get; private set; }

		internal ConfigEntry<float> EnduranceExhaustedStaminaThreshold { get; private set; }

		internal ConfigEntry<bool> ExplorationEnabled { get; private set; }

		internal ConfigEntry<float> ExplorationGainMultiplier { get; private set; }

		internal ConfigEntry<float> ExplorationEffectMultiplier { get; private set; }

		internal ConfigEntry<float> ExplorationBaseRadius { get; private set; }

		internal ConfigEntry<float> ExplorationBonusRadiusAt100 { get; private set; }

		internal ConfigEntry<float> ExplorationMinRadius { get; private set; }

		internal ConfigEntry<float> ExplorationMaxRadius { get; private set; }

		internal ConfigEntry<float> ExplorationXpPerSuccessfulPass { get; private set; }

		internal ConfigEntry<float> ExplorationMinTimeBetweenAwards { get; private set; }

		internal ConfigEntry<bool> FortitudeEnabled { get; private set; }

		internal ConfigEntry<float> FortitudeGainMultiplier { get; private set; }

		internal ConfigEntry<float> FortitudeEffectMultiplier { get; private set; }

		internal ConfigEntry<float> FortitudeArmorBonusAt100 { get; private set; }

		internal ConfigEntry<float> FortitudeXpPerHpLost { get; private set; }

		internal ConfigEntry<float> FortitudeMaxXpPerHit { get; private set; }

		internal ConfigEntry<float> FortitudeElementalXpMultiplier { get; private set; }

		internal ConfigEntry<bool> HaulingEnabled { get; private set; }

		internal ConfigEntry<float> HaulingGainMultiplier { get; private set; }

		internal ConfigEntry<float> HaulingEffectMultiplier { get; private set; }

		internal ConfigEntry<float> HaulingCarryWeightBonusAt100 { get; private set; }

		internal ConfigEntry<float> HaulingWeightRatioThreshold { get; private set; }

		internal ConfigEntry<float> HaulingRunXpFraction { get; private set; }

		internal ConfigEntry<float> HaulingSneakXpFraction { get; private set; }

		internal ConfigEntry<float> HaulingJumpXpFraction { get; private set; }

		internal ConfigEntry<float> HaulingMaxFactorPerTrigger { get; private set; }

		internal ConfigEntry<float> HaulingFallbackMaxCarryWeight { get; private set; }

		internal ConfigEntry<bool> MiningBonusEnabled { get; private set; }

		internal ConfigEntry<float> MiningBonusMultiplier { get; private set; }

		internal ConfigEntry<float> MiningPickaxeBonusAt100 { get; private set; }

		internal ConfigEntry<bool> WoodcuttingBonusEnabled { get; private set; }

		internal ConfigEntry<float> WoodcuttingBonusMultiplier { get; private set; }

		internal ConfigEntry<float> WoodcuttingChopBonusAt100 { get; private set; }

		internal ConfigEntry<float> WoodcuttingMinChopToConsider { get; private set; }

		internal ConfigEntry<bool> WoodcuttingVirtualChopEnabled { get; private set; }

		internal ConfigEntry<float> WoodcuttingVirtualChopMultiplier { get; private set; }

		internal ConfigEntry<float> WoodcuttingVirtualChopMaxConvertAt100 { get; private set; }

		internal ConfigEntry<bool> WoodcuttingVirtualChopOnlyIfNoChopDamage { get; private set; }

		internal ConfigEntry<bool> PickaxeStaminaReductionEnabled { get; private set; }

		internal ConfigEntry<float> PickaxeStaminaReductionMultiplier { get; private set; }

		internal ConfigEntry<float> PickaxeMaxReductionAt100 { get; private set; }

		internal ConfigEntry<float> PickaxeMinCostMultiplier { get; private set; }

		internal ExtraSkillsConfig(BaseUnityPlugin plugin, ConfigSync configSync)
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Expected O, but got Unknown
			_plugin = plugin;
			_configSync = configSync;
			LockConfiguration = _plugin.Config.Bind<bool>("1 - General", "Lock Configuration", true, new ConfigDescription("If enabled, synchronized settings are controlled by the server while connected.", (AcceptableValueBase)null, Array.Empty<object>()));
			VitalityEnabled = Synced("2 - Vitality", "Enabled", value: true, "Enable Vitality gameplay effects and XP gain. The skill remains registered so existing save data is preserved.");
			VitalityGainMultiplier = SyncedMultiplier("2 - Vitality", "XP Gain Multiplier", 1f, "Global multiplier applied after Vitality's event-specific XP calculation. 1 = original rate, 0 = no XP gain.");
			VitalityEffectMultiplier = SyncedMultiplier("2 - Vitality", "Effect Multiplier", 1f, "Multiplier applied to Vitality's configured health bonus. 1 = configured base bonus.");
			VitalityHealthBonusAt100 = SyncedRange("2 - Vitality", "Health Bonus At Skill 100", 10f, 0f, 10000f, "Base maximum-health bonus at Vitality 100 before Effect Multiplier. Original value: 10.");
			VitalityFoodXpPerHealth = SyncedRange("2 - Vitality", "Food XP Per Health", 0.01f, 0f, 100f, "Vitality XP factor per point of health on successfully eaten food, before XP Gain Multiplier. Original value: 0.01.");
			VitalityMaxFoodXpPerEat = SyncedRange("2 - Vitality", "Max Food XP Per Eat", 2f, 0f, 10000f, "Maximum raw Vitality XP awarded by one food consumption before XP Gain Multiplier. Original value: 2.");
			VitalitySleepXpPerWake = SyncedRange("2 - Vitality", "Sleep XP Per Wake", 0.25f, 0f, 10000f, "Raw Vitality XP awarded after waking, before XP Gain Multiplier. Original value: 0.25.");
			VitalitySleepAwardCooldownSeconds = SyncedRange("2 - Vitality", "Sleep Award Cooldown Seconds", 2f, 0f, 3600f, "Minimum time between wake XP awards. Original value: 2 seconds.");
			ArcanaEnabled = Synced("3 - Arcana", "Enabled", value: true, "Enable Arcana gameplay effects and XP gain. The skill remains registered so existing save data is preserved.");
			ArcanaGainMultiplier = SyncedMultiplier("3 - Arcana", "XP Gain Multiplier", 1f, "Global multiplier applied after Arcana's event-specific XP calculation. 1 = original rate, 0 = no XP gain.");
			ArcanaEffectMultiplier = SyncedMultiplier("3 - Arcana", "Effect Multiplier", 1f, "Multiplier applied to Arcana's configured Eitr bonus. 1 = configured base bonus.");
			ArcanaEitrBonusAt100 = SyncedRange("3 - Arcana", "Eitr Bonus At Skill 100", 10f, 0f, 10000f, "Base maximum-Eitr bonus at Arcana 100 before Effect Multiplier. Original value: 10.");
			ArcanaFoodXpPerEitr = SyncedRange("3 - Arcana", "Food XP Per Eitr", 0.02f, 0f, 100f, "Arcana XP factor per point of Eitr on successfully eaten food, before XP Gain Multiplier. Original value: 0.02.");
			ArcanaMaxFoodXpPerEat = SyncedRange("3 - Arcana", "Max Food XP Per Eat", 2f, 0f, 10000f, "Maximum raw Arcana XP from one Eitr food before XP Gain Multiplier. Original value: 2.");
			ArcanaXpPerElementalDamage = SyncedRange("3 - Arcana", "XP Per Elemental Damage", 0.01f, 0f, 100f, "Raw Arcana XP per point of qualifying elemental damage before DoT/environment and global XP multipliers. Original value: 0.01.");
			ArcanaMaxXpPerHit = SyncedRange("3 - Arcana", "Max XP Per Hit", 1f, 0f, 10000f, "Maximum raw Arcana XP from one qualifying damage event before global XP Gain Multiplier. Original value: 1.");
			ArcanaCountDotAndEnvironment = Synced("3 - Arcana", "Count DoT And Environment", value: true, "Allow Arcana XP from configured elemental damage-over-time and environmental hit types.");
			ArcanaDotEnvironmentXpMultiplier = SyncedRange("3 - Arcana", "DoT And Environment XP Multiplier", 0.5f, 0f, 1f, "Multiplier used only for Arcana DoT/environment hits. Original value: 0.5. 0 disables those awards, 1 grants full direct-hit XP.");
			EnduranceEnabled = Synced("4 - Endurance", "Enabled", value: true, "Enable Endurance gameplay effects and XP gain. The skill remains registered so existing save data is preserved.");
			EnduranceGainMultiplier = SyncedMultiplier("4 - Endurance", "XP Gain Multiplier", 1f, "Global multiplier applied after Endurance's exhaustion XP calculation. 1 = original rate, 0 = no XP gain.");
			EnduranceEffectMultiplier = SyncedMultiplier("4 - Endurance", "Effect Multiplier", 1f, "Multiplier applied to Endurance's configured stamina bonus. 1 = configured base bonus.");
			EnduranceStaminaBonusAt100 = SyncedRange("4 - Endurance", "Stamina Bonus At Skill 100", 20f, 0f, 10000f, "Base maximum-stamina bonus at Endurance 100 before Effect Multiplier. Original value: 20.");
			EnduranceMinStaminaUseToTrigger = SyncedRange("4 - Endurance", "Minimum Stamina Use To Trigger", 5f, 0f, 10000f, "An exhaustion-causing action must request more than this much stamina to award Endurance XP. Original value: 5.");
			EnduranceXpFractionOfLastUse = SyncedRange("4 - Endurance", "XP Fraction Of Last Use", 0.02f, 0f, 10f, "Fraction of the exhaustion-causing stamina cost converted to raw Endurance XP. Original value: 0.02.");
			EnduranceMaxXpPerExhaust = SyncedRange("4 - Endurance", "Max XP Per Exhaustion", 5f, 0f, 10000f, "Maximum raw Endurance XP per exhaustion event before XP Gain Multiplier. Original value: 5.");
			EnduranceRecoverThresholdFraction = SyncedRange("4 - Endurance", "Recovery Threshold Fraction", 0.25f, 0f, 1f, "Fraction of maximum stamina that must be recovered before another exhaustion award can occur. Original value: 0.25.");
			EnduranceExhaustedStaminaThreshold = SyncedRange("4 - Endurance", "Exhausted Stamina Threshold", 1f, 0f, 100f, "Stamina at or below this value counts as exhaustion when crossing down from a positive value. Original value: 1.");
			ExplorationEnabled = Synced("5 - Exploration", "Enabled", value: true, "Enable Exploration gameplay effects and XP gain. Disabled means the minimap radius is left untouched by this mod.");
			ExplorationGainMultiplier = SyncedMultiplier("5 - Exploration", "XP Gain Multiplier", 1f, "Global multiplier applied to Exploration XP. 1 = original rate, 0 = no XP gain.");
			ExplorationEffectMultiplier = SyncedMultiplier("5 - Exploration", "Effect Multiplier", 1f, "Multiplier applied to Exploration's configured bonus radius. 1 = configured base bonus.");
			ExplorationBaseRadius = SyncedRange("5 - Exploration", "Base Explore Radius", 100f, 0f, 10000f, "Base radius used by the Exploration calculation while the skill is enabled. Original value: 100.");
			ExplorationBonusRadiusAt100 = SyncedRange("5 - Exploration", "Bonus Radius At Skill 100", 100f, 0f, 10000f, "Additional discovery radius at Exploration 100 before Effect Multiplier. Original value: 100.");
			ExplorationMinRadius = SyncedRange("5 - Exploration", "Minimum Explore Radius", 50f, 0f, 10000f, "Lower clamp for the radius produced by this mod. Original value: 50.");
			ExplorationMaxRadius = SyncedRange("5 - Exploration", "Maximum Explore Radius", 300f, 0f, 10000f, "Upper clamp for the radius produced by this mod. Original value: 300.");
			ExplorationXpPerSuccessfulPass = SyncedRange("5 - Exploration", "XP Per Successful Explore Pass", 0.08f, 0f, 10000f, "Raw XP awarded when an exploration pass reveals at least one new map pixel, before XP Gain Multiplier. Original value: 0.08.");
			ExplorationMinTimeBetweenAwards = SyncedRange("5 - Exploration", "Minimum Time Between Awards", 1f, 0f, 3600f, "Anti-spam cooldown in seconds between Exploration XP awards. Original value: 1 second.");
			FortitudeEnabled = Synced("6 - Fortitude", "Enabled", value: true, "Enable Fortitude gameplay effects and XP gain. The skill remains registered so existing save data is preserved.");
			FortitudeGainMultiplier = SyncedMultiplier("6 - Fortitude", "XP Gain Multiplier", 1f, "Global multiplier applied after Fortitude's damage XP calculation. 1 = original rate, 0 = no XP gain.");
			FortitudeEffectMultiplier = SyncedMultiplier("6 - Fortitude", "Effect Multiplier", 1f, "Multiplier applied to Fortitude's configured armor bonus. 1 = configured base bonus.");
			FortitudeArmorBonusAt100 = SyncedRange("6 - Fortitude", "Armor Bonus At Skill 100", 10f, 0f, 10000f, "Base armor bonus at Fortitude 100 before Effect Multiplier. Original value: 10.");
			FortitudeXpPerHpLost = SyncedRange("6 - Fortitude", "XP Per HP Lost", 0.016f, 0f, 100f, "Raw Fortitude XP per point of actual post-mitigation HP lost, before other multipliers. Original value: 0.016.");
			FortitudeMaxXpPerHit = SyncedRange("6 - Fortitude", "Max XP Per Hit", 1f, 0f, 10000f, "Maximum raw Fortitude XP from one damage event before global XP Gain Multiplier. Original value: 1.");
			FortitudeElementalXpMultiplier = SyncedRange("6 - Fortitude", "Elemental Damage XP Multiplier", 0.5f, 0f, 10f, "Additional multiplier applied to Fortitude XP for elemental hits. Original value: 0.5.");
			HaulingEnabled = Synced("7 - Hauling", "Enabled", value: true, "Enable Hauling gameplay effects and XP gain. The skill remains registered so existing save data is preserved.");
			HaulingGainMultiplier = SyncedMultiplier("7 - Hauling", "XP Gain Multiplier", 1f, "Global multiplier applied after Hauling's piggy-backed XP calculation. 1 = original rate, 0 = no XP gain.");
			HaulingEffectMultiplier = SyncedMultiplier("7 - Hauling", "Effect Multiplier", 1f, "Multiplier applied to Hauling's configured carry-weight bonus. 1 = configured base bonus.");
			HaulingCarryWeightBonusAt100 = SyncedRange("7 - Hauling", "Carry Weight Bonus At Skill 100", 50f, 0f, 10000f, "Base carry-weight bonus at Hauling 100 before Effect Multiplier. Original behavior equals 50 at skill 100.");
			HaulingWeightRatioThreshold = SyncedRange("7 - Hauling", "Weight Ratio Threshold", 0.9f, 0f, 10f, "Current weight / max carry weight required to gain Hauling XP. Original value: 0.90.");
			HaulingRunXpFraction = SyncedRange("7 - Hauling", "Run XP Fraction", 0.2f, 0f, 10f, "Fraction of a qualifying Run skill accumulator gain converted into Hauling gain. Original value: 0.20.");
			HaulingSneakXpFraction = SyncedRange("7 - Hauling", "Sneak XP Fraction", 0.25f, 0f, 10f, "Fraction of a qualifying Sneak skill accumulator gain converted into Hauling gain. Original value: 0.25.");
			HaulingJumpXpFraction = SyncedRange("7 - Hauling", "Jump XP Fraction", 0.35f, 0f, 10f, "Fraction of a qualifying Jump skill accumulator gain converted into Hauling gain. Original value: 0.35.");
			HaulingMaxFactorPerTrigger = SyncedRange("7 - Hauling", "Max Factor Per Trigger", 0.35f, 0f, 10000f, "Safety cap on the raw factor passed to Hauling RaiseSkill for one piggy-backed trigger. Original value: 0.35.");
			HaulingFallbackMaxCarryWeight = SyncedRange("7 - Hauling", "Fallback Max Carry Weight", 300f, 1f, 100000f, "Fallback used only if no compatible Player GetMaxCarry* method can be resolved. Original vanilla fallback: 300.");
			MiningBonusEnabled = Synced("8 - Vanilla Skill Bonuses", "Mining Damage Bonus Enabled", value: true, "Enable the extra pickaxe damage scaling based on the vanilla Pickaxes skill.");
			MiningBonusMultiplier = SyncedMultiplier("8 - Vanilla Skill Bonuses", "Mining Damage Bonus Multiplier", 1f, "Multiplier applied to the configured Mining damage bonus. 1 = configured base bonus.");
			MiningPickaxeBonusAt100 = SyncedRange("8 - Vanilla Skill Bonuses", "Mining Pickaxe Bonus At Skill 100", 0.25f, 0f, 10f, "Additional pickaxe damage fraction at Pickaxes 100 before the bonus multiplier. Original value: 0.25 (+25%).");
			WoodcuttingBonusEnabled = Synced("8 - Vanilla Skill Bonuses", "Woodcutting Chop Bonus Enabled", value: true, "Enable the extra chop damage scaling based on the vanilla WoodCutting skill.");
			WoodcuttingBonusMultiplier = SyncedMultiplier("8 - Vanilla Skill Bonuses", "Woodcutting Chop Bonus Multiplier", 1f, "Multiplier applied to the configured Woodcutting chop bonus. 1 = configured base bonus.");
			WoodcuttingChopBonusAt100 = SyncedRange("8 - Vanilla Skill Bonuses", "Woodcutting Chop Bonus At Skill 100", 0.25f, 0f, 10f, "Additional chop damage fraction at WoodCutting 100 before the bonus multiplier. Original value: 0.25 (+25%).");
			WoodcuttingMinChopToConsider = SyncedRange("8 - Vanilla Skill Bonuses", "Woodcutting Minimum Chop To Scale", 0.001f, 0f, 1000f, "Minimum existing chop damage required before the direct Woodcutting chop bonus is applied. Original value: 0.001.");
			WoodcuttingVirtualChopEnabled = Synced("8 - Vanilla Skill Bonuses", "Woodcutting Virtual Chop Enabled", value: true, "Enable conversion of physical damage into tree-only chop damage based on the vanilla WoodCutting skill.");
			WoodcuttingVirtualChopMultiplier = SyncedMultiplier("8 - Vanilla Skill Bonuses", "Woodcutting Virtual Chop Multiplier", 1f, "Multiplier applied to the configured virtual-chop conversion. 1 = configured base conversion.");
			WoodcuttingVirtualChopMaxConvertAt100 = SyncedRange("8 - Vanilla Skill Bonuses", "Woodcutting Virtual Chop At Skill 100", 0.12f, 0f, 10f, "Fraction of qualifying physical damage converted to extra chop damage at WoodCutting 100 before multiplier. Original value: 0.12 (12%).");
			WoodcuttingVirtualChopOnlyIfNoChopDamage = Synced("8 - Vanilla Skill Bonuses", "Woodcutting Virtual Chop Only If No Chop Damage", value: true, "If true, virtual chop is added only when the hit has no existing chop damage. Original value: true.");
			PickaxeStaminaReductionEnabled = Synced("8 - Vanilla Skill Bonuses", "Pickaxe Stamina Reduction Enabled", value: true, "Enable pickaxe attack stamina reduction based on the vanilla Pickaxes skill.");
			PickaxeStaminaReductionMultiplier = SyncedMultiplier("8 - Vanilla Skill Bonuses", "Pickaxe Stamina Reduction Multiplier", 1f, "Multiplier applied to the configured pickaxe stamina reduction. 1 = configured base reduction.");
			PickaxeMaxReductionAt100 = SyncedRange("8 - Vanilla Skill Bonuses", "Pickaxe Max Reduction At Skill 100", 0.25f, 0f, 1f, "Base stamina-cost reduction fraction at Pickaxes 100 before multiplier. Original value: 0.25 (25%).");
			PickaxeMinCostMultiplier = SyncedRange("8 - Vanilla Skill Bonuses", "Pickaxe Minimum Cost Multiplier", 0.2f, 0f, 1f, "Lowest allowed final pickaxe stamina-cost multiplier. Original value: 0.20, meaning cost can never fall below 20% of base.");
		}

		private ConfigEntry<T> Synced<T>(string group, string name, T value, string description)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Expected O, but got Unknown
			ConfigEntry<T> val = _plugin.Config.Bind<T>(group, name, value, new ConfigDescription(description, (AcceptableValueBase)null, Array.Empty<object>()));
			SyncedConfigEntry<T> syncedConfigEntry = _configSync.AddConfigEntry<T>(val);
			syncedConfigEntry.SynchronizedConfig = true;
			return val;
		}

		private ConfigEntry<float> SyncedMultiplier(string group, string name, float value, string description)
		{
			return SyncedRange(group, name, value, 0f, 10f, description);
		}

		private ConfigEntry<float> SyncedRange(string group, string name, float value, float min, float max, string description)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Expected O, but got Unknown
			ConfigDescription val = new ConfigDescription(description, (AcceptableValueBase)(object)new AcceptableValueRange<float>(min, max), Array.Empty<object>());
			ConfigEntry<float> val2 = _plugin.Config.Bind<float>(group, name, value, val);
			SyncedConfigEntry<float> syncedConfigEntry = _configSync.AddConfigEntry<float>(val2);
			syncedConfigEntry.SynchronizedConfig = true;
			return val2;
		}

		internal bool IsSkillEnabled(int fixedSkillId)
		{
			return fixedSkillId switch
			{
				15001 => VitalityEnabled.Value, 
				15002 => ArcanaEnabled.Value, 
				15003 => EnduranceEnabled.Value, 
				15004 => ExplorationEnabled.Value, 
				15005 => FortitudeEnabled.Value, 
				15006 => HaulingEnabled.Value, 
				_ => true, 
			};
		}

		internal float GetSkillGainMultiplier(int fixedSkillId)
		{
			return fixedSkillId switch
			{
				15001 => VitalityGainMultiplier.Value, 
				15002 => ArcanaGainMultiplier.Value, 
				15003 => EnduranceGainMultiplier.Value, 
				15004 => ExplorationGainMultiplier.Value, 
				15005 => FortitudeGainMultiplier.Value, 
				15006 => HaulingGainMultiplier.Value, 
				_ => 1f, 
			};
		}

		internal float GetSkillEffectMultiplier(int fixedSkillId)
		{
			return fixedSkillId switch
			{
				15001 => VitalityEffectMultiplier.Value, 
				15002 => ArcanaEffectMultiplier.Value, 
				15003 => EnduranceEffectMultiplier.Value, 
				15004 => ExplorationEffectMultiplier.Value, 
				15005 => FortitudeEffectMultiplier.Value, 
				15006 => HaulingEffectMultiplier.Value, 
				_ => 1f, 
			};
		}
	}
	public sealed class ArcanaSkill : BaseSkill
	{
		internal static class ArcanaPatches
		{
			[HarmonyPatch(typeof(Player), "GetTotalFoodValue")]
			public static class HealthIncreasePatches
			{
				public static void Postfix(Player __instance, ref float hp, ref float stamina, ref float eitr)
				{
					int bonusEitr = GetBonusEitr(__instance);
					if (bonusEitr > 0)
					{
						eitr += bonusEitr;
					}
				}
			}

			[HarmonyPatch(typeof(Player), "EatFood")]
			[HarmonyPostfix]
			private static void Player_EatFood_Postfix(Player __instance, ItemData item, ref bool __result)
			{
				if (__result && !((Object)(object)__instance == (Object)null) && item != null && item.m_shared != null)
				{
					float foodEitr = item.m_shared.m_foodEitr;
					if (!(foodEitr <= 0f))
					{
						RaiseFromFood(__instance, foodEitr);
					}
				}
			}
		}

		private static ArcanaSkill _instance;

		public static ArcanaSkill Instance => _instance ?? (_instance = new ArcanaSkill());

		internal static bool CountDotAndEnvironment => Launch.Settings == null || Launch.Settings.ArcanaCountDotAndEnvironment.Value;

		internal static float DotEnvironmentXpMultiplier => (Launch.Settings != null) ? Launch.Settings.ArcanaDotEnvironmentXpMultiplier.Value : 0.5f;

		private ArcanaSkill()
			: base(15002, "arcanaskill", "Arcana", "Increases your base maximum Eitr. Improves by eating Eitr food and taking elemental damage.", "arcana")
		{
		}

		internal static int GetBonusEitr(Player player)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)player == (Object)null)
			{
				return 0;
			}
			if (!BalrondSkillSystem.IsSkillEnabled(Instance.SkillType))
			{
				return 0;
			}
			Skills skills = ((Character)player).GetSkills();
			if ((Object)(object)skills == (Object)null)
			{
				return 0;
			}
			float skillLevel = skills.GetSkillLevel(Instance.SkillType);
			if (skillLevel <= 0f)
			{
				return 0;
			}
			float num = Launch.Settings?.ArcanaEitrBonusAt100.Value ?? 10f;
			float skillEffectMultiplier = BalrondSkillSystem.GetSkillEffectMultiplier(Instance.SkillType);
			float num2 = Mathf.Max(0f, num) / 10f;
			return Mathf.FloorToInt(skillLevel / 10f * num2 * skillEffectMultiplier);
		}

		private static void RaiseFromFood(Player player, float foodEitr)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)player == (Object)null) && !((Object)(object)player != (Object)(object)Player.m_localPlayer) && BalrondSkillSystem.IsSkillEnabled(Instance.SkillType) && !(foodEitr <= 0f))
			{
				ExtraSkillsConfig settings = Launch.Settings;
				float num = settings?.ArcanaFoodXpPerEitr.Value ?? 0.02f;
				float num2 = settings?.ArcanaMaxFoodXpPerEat.Value ?? 2f;
				float num3 = foodEitr * Mathf.Max(0f, num);
				num3 = Mathf.Min(num3, Mathf.Max(0f, num2));
				if (!(num3 <= 0f))
				{
					BalrondSkillSystem.RaiseSkill(player, Instance.SkillType, num3);
				}
			}
		}

		private static float GetElementalXpMultiplier(HitData hit)
		{
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: 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_006d: 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_00b6: Expected I4, but got Unknown
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: 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_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Invalid comparison between Unknown and I4
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Invalid comparison between Unknown and I4
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Invalid comparison between Unknown and I4
			if (hit == null)
			{
				return 0f;
			}
			if (!(hit.m_damage.m_fire > 0f) && !(hit.m_damage.m_frost > 0f) && !(hit.m_damage.m_lightning > 0f))
			{
				return 0f;
			}
			HitType hitType = hit.m_hitType;
			HitType val = hitType;
			switch (val - 3)
			{
			case 0:
			case 1:
			case 5:
			case 7:
			case 8:
			case 9:
			case 10:
			case 11:
			case 12:
			case 14:
			case 15:
				return 0f;
			default:
			{
				HitType hitType2 = hit.m_hitType;
				HitType val2 = hitType2;
				if (val2 - 5 <= 2 || (int)val2 == 9 || (int)val2 == 21)
				{
					if (!CountDotAndEnvironment)
					{
						return 0f;
					}
					return Mathf.Clamp01(DotEnvironmentXpMultiplier);
				}
				if (hit.HaveAttacker() && (Object)(object)hit.GetAttacker() != (Object)null)
				{
					return 1f;
				}
				return 0f;
			}
			}
		}

		internal static void OnDamageTaken(Player player, HitData originalHit, float hpLost, bool wasBlocking, bool wasPerfectBlock)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)player == (Object)null || (Object)(object)player != (Object)(object)Player.m_localPlayer || !BalrondSkillSystem.IsSkillEnabled(Instance.SkillType))
			{
				return;
			}
			float elementalXpMultiplier = GetElementalXpMultiplier(originalHit);
			if (elementalXpMultiplier <= 0f)
			{
				return;
			}
			float num = originalHit.m_damage.m_fire + originalHit.m_damage.m_frost + originalHit.m_damage.m_lightning;
			if (!(num <= 0f))
			{
				ExtraSkillsConfig settings = Launch.Settings;
				float num2 = settings?.ArcanaXpPerElementalDamage.Value ?? 0.01f;
				float num3 = settings?.ArcanaMaxXpPerHit.Value ?? 1f;
				float num4 = num * Mathf.Max(0f, num2) * elementalXpMultiplier;
				num4 = Mathf.Min(num4, Mathf.Max(0f, num3));
				if (!(num4 <= 0f))
				{
					BalrondSkillSystem.RaiseSkill(player, Instance.SkillType, num4);
				}
			}
		}
	}
	public sealed class EnduranceSkill : BaseSkill
	{
		internal static class EndurancePatches
		{
			[HarmonyPatch(typeof(Player), "GetTotalFoodValue")]
			public static class StaminaIncreasePatch
			{
				public static void Postfix(Player __instance, ref float hp, ref float stamina, ref float eitr)
				{
					float bonusStamina = GetBonusStamina(__instance);
					if (bonusStamina > 0f)
					{
						stamina += bonusStamina;
					}
				}
			}

			[HarmonyPatch(typeof(Player), "UseStamina")]
			private static class Player_UseStamina_Patch
			{
				[HarmonyPrefix]
				private static void Prefix(Player __instance, [HarmonyArgument(0)] float v, out float __state)
				{
					__state = 0f;
					if (!((Object)(object)__instance == (Object)null) && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer))
					{
						__state = __instance.GetStamina();
					}
				}

				[HarmonyPostfix]
				private static void Postfix(Player __instance, [HarmonyArgument(0)] float v, float __state)
				{
					if (!((Object)(object)__instance == (Object)null) && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer))
					{
						float stamina = __instance.GetStamina();
						OnStaminaUsed(__instance, __state, stamina, v);
					}
				}
			}
		}

		private static EnduranceSkill _instance;

		private static bool _lockedOut;

		public static EnduranceSkill Instance => _instance ?? (_instance = new EnduranceSkill());

		private EnduranceSkill()
			: base(15003, "enduranceskill", "Endurance", "Increases your base maximum stamina. Improves when you push yourself to exhaustion.", "endurance")
		{
		}

		internal static float GetBonusStamina(Player player)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)player == (Object)null)
			{
				return 0f;
			}
			if (!BalrondSkillSystem.IsSkillEnabled(Instance.SkillType))
			{
				return 0f;
			}
			Skills skills = ((Character)player).GetSkills();
			if ((Object)(object)skills == (Object)null)
			{
				return 0f;
			}
			float skillLevel = skills.GetSkillLevel(Instance.SkillType);
			if (skillLevel <= 0f)
			{
				return 0f;
			}
			float num = Launch.Settings?.EnduranceStaminaBonusAt100.Value ?? 20f;
			float skillEffectMultiplier = BalrondSkillSystem.GetSkillEffectMultiplier(Instance.SkillType);
			return skillLevel / 100f * Mathf.Max(0f, num) * skillEffectMultiplier;
		}

		internal static void OnStaminaUsed(Player player, float staminaBefore, float staminaAfter, float amountUsedRequested)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)player == (Object)null || (Object)(object)player != (Object)(object)Player.m_localPlayer || !BalrondSkillSystem.IsSkillEnabled(Instance.SkillType))
			{
				return;
			}
			ExtraSkillsConfig settings = Launch.Settings;
			float num = settings?.EnduranceRecoverThresholdFraction.Value ?? 0.25f;
			float num2 = settings?.EnduranceExhaustedStaminaThreshold.Value ?? 1f;
			float num3 = settings?.EnduranceMinStaminaUseToTrigger.Value ?? 5f;
			float num4 = settings?.EnduranceXpFractionOfLastUse.Value ?? 0.02f;
			float num5 = settings?.EnduranceMaxXpPerExhaust.Value ?? 5f;
			num = Mathf.Clamp01(num);
			num2 = Mathf.Max(0f, num2);
			num3 = Mathf.Max(0f, num3);
			num4 = Mathf.Max(0f, num4);
			num5 = Mathf.Max(0f, num5);
			if (_lockedOut)
			{
				float maxStamina = ((Character)player).GetMaxStamina();
				if (!(maxStamina > 0f) || !(staminaAfter >= maxStamina * num))
				{
					return;
				}
				_lockedOut = false;
			}
			if (!(staminaBefore > 0f) || !(staminaAfter <= num2))
			{
				return;
			}
			float num6 = Mathf.Max(0f, amountUsedRequested);
			num6 = Mathf.Min(num6, staminaBefore);
			if (num6 <= num3)
			{
				_lockedOut = true;
				return;
			}
			float num7 = num6 * num4;
			if (num7 > num5)
			{
				num7 = num5;
			}
			if (num7 > 0f)
			{
				BalrondSkillSystem.RaiseSkill(player, Instance.SkillType, num7);
			}
			_lockedOut = true;
		}
	}
	public sealed class ExplorationSkill : BaseSkill
	{
		internal static class ExplorationPatches
		{
			[HarmonyPatch(typeof(Minimap), "Explore", new Type[]
			{
				typeof(Vector3),
				typeof(float)
			})]
			private static class Minimap_Explore_VectorRadius_Patch
			{
				[HarmonyPrefix]
				private static void Prefix(Minimap __instance, Vector3 p, ref float radius)
				{
					//IL_0020: Unknown result type (might be due to invalid IL or missing references)
					//IL_0027: 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_0031: 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)
					s_passForLocalPlayer = false;
					s_anyNewPixelThisPass = false;
					Player localPlayer = Player.m_localPlayer;
					if (!((Object)(object)localPlayer == (Object)null))
					{
						Vector3 val = p - ((Component)localPlayer).transform.position;
						if (!(((Vector3)(ref val)).sqrMagnitude > 4f) && BalrondSkillSystem.IsSkillEnabled(Instance.SkillType))
						{
							s_passForLocalPlayer = true;
							radius = GetExploreRadiusFor(localPlayer);
						}
					}
				}

				[HarmonyPostfix]
				private static void Postfix(Minimap __instance, Vector3 p, float radius)
				{
					//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
					if (!s_passForLocalPlayer || !s_anyNewPixelThisPass)
					{
						return;
					}
					Player localPlayer = Player.m_localPlayer;
					if ((Object)(object)localPlayer == (Object)null || ((Character)localPlayer).IsDead() || ((Character)localPlayer).InCutscene() || ((Character)localPlayer).InIntro() || s_inAward || Time.time < s_nextAllowedAwardTime)
					{
						return;
					}
					try
					{
						s_inAward = true;
						ExtraSkillsConfig settings = Launch.Settings;
						float num = settings?.ExplorationXpPerSuccessfulPass.Value ?? 0.08f;
						float num2 = settings?.ExplorationMinTimeBetweenAwards.Value ?? 1f;
						num = Mathf.Max(0f, num);
						num2 = Mathf.Max(0f, num2);
						if (num > 0f)
						{
							BalrondSkillSystem.RaiseSkill(localPlayer, Instance.SkillType, num);
						}
						s_nextAllowedAwardTime = Time.time + num2;
					}
					finally
					{
						s_inAward = false;
					}
				}
			}

			[HarmonyPatch(typeof(Minimap), "Explore", new Type[]
			{
				typeof(int),
				typeof(int)
			})]
			private static class Minimap_Explore_Pixel_Patch
			{
				[HarmonyPostfix]
				private static void Postfix(bool __result)
				{
					if (s_passForLocalPlayer && __result)
					{
						s_anyNewPixelThisPass = true;
					}
				}
			}
		}

		private static ExplorationSkill _instance;

		private static bool s_inAward;

		private static bool s_passForLocalPlayer;

		private static bool s_anyNewPixelThisPass;

		private static float s_nextAllowedAwardTime;

		public static ExplorationSkill Instance => _instance ?? (_instance = new ExplorationSkill());

		private ExplorationSkill()
			: base(15004, "explorationskill", "Exploration", "Increases your map discovery range. Improves when you uncover new areas.", "exploration")
		{
		}

		private static float GetExploreRadiusFor(Player player)
		{
			//IL_00ed: 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)
			ExtraSkillsConfig settings = Launch.Settings;
			float num = settings?.ExplorationBaseRadius.Value ?? 100f;
			float num2 = settings?.ExplorationBonusRadiusAt100.Value ?? 100f;
			float num3 = settings?.ExplorationMinRadius.Value ?? 50f;
			float num4 = settings?.ExplorationMaxRadius.Value ?? 300f;
			num = Mathf.Max(0f, num);
			num2 = Mathf.Max(0f, num2);
			num3 = Mathf.Max(0f, num3);
			num4 = Mathf.Max(0f, num4);
			if (num4 < num3)
			{
				float num5 = num4;
				num4 = num3;
				num3 = num5;
			}
			if ((Object)(object)player == (Object)null)
			{
				return Mathf.Clamp(num, num3, num4);
			}
			Skills skills = ((Character)player).GetSkills();
			if ((Object)(object)skills == (Object)null)
			{
				return Mathf.Clamp(num, num3, num4);
			}
			float skillLevel = skills.GetSkillLevel(Instance.SkillType);
			float num6 = Mathf.Clamp01(skillLevel / 100f);
			float skillEffectMultiplier = BalrondSkillSystem.GetSkillEffectMultiplier(Instance.SkillType);
			float num7 = num + num2 * num6 * skillEffectMultiplier;
			return Mathf.Clamp(num7, num3, num4);
		}
	}
	public sealed class FortitudeSkill : BaseSkill
	{
		[HarmonyPatch(type