Decompiled source of balrond extra skills v0.4.5

plugins/BalrondExtraSkills.dll

Decompiled 10 hours 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 BalrondExtraSkills.Compatibility;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using JetBrains.Annotations;
using LitJson2;
using Microsoft.CodeAnalysis;
using ServerSync;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
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: AssemblyProduct("BalrondExtraSkills")]
[assembly: ComVisible(false)]
[assembly: AssemblyFileVersion("0.4.4.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.4.4.0")]
[module: UnverifiableCode]
public static class BalrondHashCompat
{
	public static int StableHash(string value)
	{
		return (value != null) ? StringExtensionMethods.GetStableHashCode(value) : 0;
	}
}
namespace BalrondExtraSkills
{
	public static class BalrondDamageHub
	{
		[HarmonyPatch(typeof(Character), "ApplyDamage")]
		private static class Character_ApplyDamage_Patch
		{
			[HarmonyPrefix]
			private static void Prefix(Character __instance, out float __state)
			{
				__state = -1f;
				Player val = (Player)(object)((__instance is Player) ? __instance : null);
				if (!((Object)(object)val == (Object)null) && !((Object)(object)val != (Object)(object)Player.m_localPlayer))
				{
					__state = ((Character)val).GetHealth();
				}
			}

			[HarmonyPostfix]
			private static void Postfix(Character __instance, HitData hit, float __state)
			{
				if (__state < 0f)
				{
					return;
				}
				Player val = (Player)(object)((__instance is Player) ? __instance : null);
				if (!((Object)(object)val == (Object)null) && !((Object)(object)val != (Object)(object)Player.m_localPlayer))
				{
					float num = __state - ((Character)val).GetHealth();
					if (!(num <= 0f))
					{
						FortitudeSkill.OnDamageTaken(val, hit, num);
					}
				}
			}
		}
	}
	internal static class BalrondIconUtil
	{
		private static Sprite _placeholder;

		private static bool _attempted;

		internal static Sprite Placeholder
		{
			get
			{
				//IL_0030: Unknown result type (might be due to invalid IL or missing references)
				//IL_0036: Expected O, but got Unknown
				//IL_0059: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)_placeholder != (Object)null || _attempted)
				{
					return _placeholder;
				}
				_attempted = true;
				try
				{
					Texture2D val = new Texture2D(1, 1, (TextureFormat)4, false);
					((Object)val).name = "BalrondExtraSkills_PlaceholderTexture";
					val.SetPixel(0, 0, new Color(0f, 0f, 0f, 0f));
					val.Apply(false, true);
					_placeholder = CreateSpriteCompat(val);
					if ((Object)(object)_placeholder != (Object)null)
					{
						((Object)_placeholder).name = "BalrondExtraSkills_PlaceholderIcon";
					}
				}
				catch (Exception ex)
				{
					if (BesRuntime.Log != null)
					{
						BesRuntime.Log.LogWarning((object)("[BES] Could not create placeholder skill icon: " + ex.Message));
					}
				}
				return _placeholder;
			}
		}

		private static Sprite CreateSpriteCompat(Texture2D texture)
		{
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)texture == (Object)null)
			{
				return null;
			}
			MethodInfo[] methods = typeof(Sprite).GetMethods(BindingFlags.Static | BindingFlags.Public);
			foreach (MethodInfo methodInfo in methods)
			{
				if (!string.Equals(methodInfo.Name, "Create", StringComparison.Ordinal))
				{
					continue;
				}
				ParameterInfo[] parameters = methodInfo.GetParameters();
				if (parameters.Length < 3 || parameters[0].ParameterType != typeof(Texture2D) || parameters[1].ParameterType != typeof(Rect) || parameters[2].ParameterType != typeof(Vector2))
				{
					continue;
				}
				object[] array = new object[parameters.Length];
				array[0] = texture;
				array[1] = (object)new Rect(0f, 0f, (float)((Texture)texture).width, (float)((Texture)texture).height);
				array[2] = (object)new Vector2(0.5f, 0.5f);
				bool flag = true;
				for (int j = 3; j < parameters.Length; j++)
				{
					ParameterInfo parameterInfo = parameters[j];
					if (parameterInfo.HasDefaultValue)
					{
						array[j] = parameterInfo.DefaultValue;
						continue;
					}
					if (parameterInfo.ParameterType == typeof(float))
					{
						array[j] = 100f;
						continue;
					}
					if (parameterInfo.ParameterType == typeof(uint))
					{
						array[j] = 0u;
						continue;
					}
					if (parameterInfo.ParameterType == typeof(int))
					{
						array[j] = 0;
						continue;
					}
					if (parameterInfo.ParameterType == typeof(bool))
					{
						array[j] = false;
						continue;
					}
					if (parameterInfo.ParameterType.IsEnum)
					{
						array[j] = Activator.CreateInstance(parameterInfo.ParameterType);
						continue;
					}
					if (parameterInfo.ParameterType.IsValueType)
					{
						array[j] = Activator.CreateInstance(parameterInfo.ParameterType);
						continue;
					}
					flag = false;
					break;
				}
				if (flag)
				{
					try
					{
						object? obj = methodInfo.Invoke(null, array);
						return (Sprite)((obj is Sprite) ? obj : null);
					}
					catch
					{
					}
				}
			}
			return null;
		}
	}
	internal static class BalrondSkillLevelupMessagePatch
	{
		[HarmonyPatch(typeof(Player), "Message", new Type[]
		{
			typeof(MessageType),
			typeof(string),
			typeof(int),
			typeof(Sprite),
			typeof(bool)
		})]
		private static class Player_Message_SkillupTokenFix
		{
			[HarmonyPrefix]
			private static void Prefix(ref string msg)
			{
				//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
				//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
				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 || !int.TryParse(msg.Substring(num2, i - num2), out var result))
				{
					return;
				}
				SkillType key = (SkillType)result;
				if (BalrondSkillSystem.Registered.TryGetValue(key, out var value) && value != null)
				{
					string text = value.LocalizedName;
					if (string.IsNullOrEmpty(text))
					{
						text = value.SkillNameEnglish;
					}
					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]
			[HarmonyPriority(0)]
			private static void Postfix(SkillsDialog __instance)
			{
				//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
				//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
				//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
				try
				{
					if ((Object)(object)__instance == (Object)null || __instance.m_elements == null)
					{
						return;
					}
					Player localPlayer = Player.m_localPlayer;
					Skills val = (((Object)(object)localPlayer != (Object)null) ? ((Character)localPlayer).GetSkills() : null);
					List<Skill> list = (((Object)(object)val != (Object)null) ? val.GetSkillList() : null);
					if (list == null)
					{
						return;
					}
					int num = Mathf.Min(list.Count, __instance.m_elements.Count);
					for (int i = 0; i < num; i++)
					{
						Skill val2 = list[i];
						GameObject val3 = __instance.m_elements[i];
						if (val2 == null || val2.m_info == null || (Object)(object)val3 == (Object)null || !val3.activeInHierarchy)
						{
							continue;
						}
						SkillType skill = val2.m_info.m_skill;
						if (!Registered.TryGetValue(skill, out var value) || value == null)
						{
							continue;
						}
						Transform val4 = Utils.FindChild(val3.transform, "name", (IterativeSearchType)0);
						TMP_Text val5 = (((Object)(object)val4 != (Object)null) ? ((Component)val4).GetComponent<TMP_Text>() : null);
						if ((Object)(object)val5 != (Object)null)
						{
							val5.text = value.LocalizedName;
						}
						Transform val6 = Utils.FindChild(val3.transform, "icon", (IterativeSearchType)0);
						if ((Object)(object)val6 != (Object)null)
						{
							Image component = ((Component)val6).GetComponent<Image>();
							if ((Object)(object)component != (Object)null)
							{
								component.sprite = value.Icon;
							}
						}
					}
				}
				catch (Exception ex)
				{
					if (BesRuntime.Settings != null && BesRuntime.Settings.LogCompatibility.Value && BesRuntime.Log != null)
					{
						BesRuntime.Log.LogWarning((object)("[BES localization] Failed to refresh custom skill labels: " + ex.Message));
					}
				}
			}
		}

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

		[HarmonyPatch(typeof(Skills), "GetSkillDef")]
		private static class Skills_GetSkillDef_Patch
		{
			[HarmonyPrefix]
			[HarmonyPriority(800)]
			private static bool Prefix(Skills __instance, SkillType type, ref SkillDef __result)
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0010: Unknown result type (might be due to invalid IL or missing references)
				//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
				//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
				//IL_0097: Unknown result type (might be due to invalid IL or missing references)
				//IL_009c: Unknown result type (might be due to invalid IL or missing references)
				//IL_009d: Unknown result type (might be due to invalid IL or missing references)
				//IL_009e: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
				//IL_00af: Unknown result type (might be due to invalid IL or missing references)
				//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
				//IL_00c7: Expected O, but got Unknown
				//IL_010c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0060: Unknown result type (might be due to invalid IL or missing references)
				//IL_0065: Unknown result type (might be due to invalid IL or missing references)
				//IL_0156: Unknown result type (might be due to invalid IL or missing references)
				//IL_015b: Unknown result type (might be due to invalid IL or missing references)
				if (TryGetLegacyTarget(type, out var currentType) && Registered.TryGetValue(currentType, out var value) && value != null)
				{
					if ((Object)(object)__instance != (Object)null && __instance.m_skills != null)
					{
						for (int i = 0; i < __instance.m_skills.Count; i++)
						{
							SkillDef val = __instance.m_skills[i];
							if (val != null && val.m_skill == type)
							{
								return true;
							}
						}
					}
					__result = new SkillDef
					{
						m_skill = type,
						m_icon = value.Icon,
						m_description = value.DescToken,
						m_increseStep = 1f
					};
					return false;
				}
				if (!Registered.TryGetValue(type, out var value2) || value2 == null)
				{
					return true;
				}
				if (CollisionDisabled.Contains(type))
				{
					return true;
				}
				if (!IsSkillEnabled(type))
				{
					if ((Object)(object)__instance != (Object)null && __instance.m_skills != null)
					{
						for (int j = 0; j < __instance.m_skills.Count; j++)
						{
							SkillDef val2 = __instance.m_skills[j];
							if (val2 != null && val2.m_skill == type && !IsOurDefinition(val2, value2))
							{
								return true;
							}
						}
					}
					__result = CreateDefinition(value2);
					return false;
				}
				return true;
			}

			[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_002d: 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 (__result == null && Registered.TryGetValue(type, out var value) && value != null && !CollisionDisabled.Contains(type))
				{
					__result = CreateDefinition(value);
					if (IsSkillEnabled(type))
					{
						EnsureDefsInSkillsList(__instance);
					}
				}
			}
		}

		[HarmonyPatch(typeof(Skills), "GetSkillList")]
		private static class Skills_GetSkillList_FilterDisabledCustom_Patch
		{
			[HarmonyPostfix]
			private static void Postfix(ref List<Skill> __result)
			{
				//IL_0051: Unknown result type (might be due to invalid IL or missing references)
				//IL_0056: Unknown result type (might be due to invalid IL or missing references)
				//IL_005c: Unknown result type (might be due to invalid IL or missing references)
				//IL_008e: Unknown result type (might be due to invalid IL or missing references)
				if (__result == null || __result.Count == 0)
				{
					return;
				}
				for (int num = __result.Count - 1; num >= 0; num--)
				{
					Skill val = __result[num];
					if (val != null && val.m_info != null)
					{
						SkillType skill = val.m_info.m_skill;
						if (Registered.TryGetValue(skill, out var value) && value != null && IsOurDefinition(val.m_info, value) && !IsSkillEnabled(skill))
						{
							__result.RemoveAt(num);
						}
					}
				}
			}
		}

		[HarmonyPatch(typeof(Skills), "Awake")]
		private static class Skills_Awake_Patch
		{
			[HarmonyPrefix]
			[HarmonyPriority(800)]
			[HarmonyBefore(new string[] { "M2Valheim.SkillsReworked" })]
			private static void Prefix(Skills __instance)
			{
				try
				{
					EnsureDefsInSkillsList(__instance);
				}
				catch
				{
				}
			}

			[HarmonyPostfix]
			[HarmonyAfter(new string[] { "M2Valheim.SkillsReworked" })]
			private static void Postfix(Skills __instance)
			{
				try
				{
					EnsureDefsInSkillsList(__instance);
				}
				catch
				{
				}
			}
		}

		[HarmonyPatch(typeof(Skills), "Save", new Type[] { typeof(ZPackage) })]
		private static class Skills_Save_CustomSkillStorage_Patch
		{
			[HarmonyPrefix]
			[HarmonyPriority(800)]
			private static void Prefix(Skills __instance)
			{
				try
				{
					if (!((Object)(object)__instance == (Object)null))
					{
						EnsureDefsInSkillsList(__instance);
					}
				}
				catch (Exception ex)
				{
					if (BesRuntime.Log != null)
					{
						BesRuntime.Log.LogError((object)("[BES persistence] Failed to reconcile custom skills before Skills.Save: " + ex));
					}
				}
			}
		}

		[HarmonyPatch(typeof(Skills), "Load", new Type[] { typeof(ZPackage) })]
		private static class Skills_Load_CustomSkillStorage_Patch
		{
			[HarmonyPostfix]
			[HarmonyPriority(0)]
			private static void Postfix(Skills __instance)
			{
				//IL_003a: Unknown result type (might be due to invalid IL or missing references)
				try
				{
					if ((Object)(object)__instance == (Object)null)
					{
						return;
					}
					EnsureDefsInSkillsList(__instance);
					MigrateLegacySkillData(__instance);
					foreach (KeyValuePair<SkillType, BaseSkill> item in Registered)
					{
						EnsureSkillSeeded(__instance, item.Key);
					}
					InvalidateLoadedSkillCaches();
				}
				catch (Exception ex)
				{
					if (BesRuntime.Log != null)
					{
						BesRuntime.Log.LogError((object)("[BES persistence] Failed to reconcile custom skills after Skills.Load: " + ex));
					}
				}
			}
		}

		[HarmonyPatch(typeof(Player), "Awake")]
		private static class Player_Awake_CustomSkillDefinitionsOnly_Patch
		{
			[HarmonyPostfix]
			private static void Postfix(Player __instance)
			{
				try
				{
					if ((Object)(object)__instance != (Object)null)
					{
						EnsureDefsInSkillsList(((Character)__instance).GetSkills());
					}
				}
				catch
				{
				}
			}
		}

		[HarmonyPatch(typeof(Player), "Load")]
		[HarmonyAfter(new string[] { "M2Valheim.SkillsReworked" })]
		private static class Player_Load_SeedCustomSkills_Patch
		{
			[HarmonyPostfix]
			[HarmonyPriority(0)]
			private static void Postfix(Player __instance)
			{
				EnsureAllSeeded(__instance);
				BesSkillPersistence.RestoreAfterPlayerLoad(__instance);
				InvalidateLoadedSkillCaches();
				if (SkillRuntime.IsLocal(__instance))
				{
					BesSkillPersistence.LogState("LOAD", __instance);
				}
			}
		}

		[HarmonyPatch(typeof(Skills), "CheatRaiseSkill")]
		private static class Skills_CheatRaiseSkill_Patch
		{
			[HarmonyPrefix]
			[HarmonyPriority(800)]
			[HarmonyBefore(new string[] { "M2Valheim.SkillsReworked" })]
			private static bool Prefix(Skills __instance, ref string name, float value, bool showMessage)
			{
				//IL_0036: Unknown result type (might be due to invalid IL or missing references)
				//IL_005a: Unknown result type (might be due to invalid IL or missing references)
				//IL_006e: Unknown result type (might be due to invalid IL or missing references)
				//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
				//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
				//IL_0105: Unknown result type (might be due to invalid IL or missing references)
				//IL_0113: Unknown result type (might be due to invalid IL or missing references)
				//IL_0130: Unknown result type (might be due to invalid IL or missing references)
				//IL_0186: Unknown result type (might be due to invalid IL or missing references)
				try
				{
					if (string.IsNullOrEmpty(name))
					{
						return true;
					}
					if (!TryResolveCustomAlias(name, out var type))
					{
						return true;
					}
					if (!Registered.TryGetValue(type, out var value2) || value2 == null)
					{
						return true;
					}
					if (CollisionDisabled.Contains(type))
					{
						return true;
					}
					if (!IsSkillEnabled(type))
					{
						Console instance = Console.instance;
						if (instance != null)
						{
							instance.Print(BesLocalization.Format("$tag_bes_skill_disabled", value2.LocalizedName));
						}
						return false;
					}
					Player player = __instance.m_player;
					EnsureDefsInSkillsList(__instance, forceRefresh: true);
					EnsureSkillSeeded(__instance, type);
					if (SkillsReworkedCompat.IsActive && IsPlainEnduranceAlias(name, type))
					{
						return true;
					}
					if (SkillsReworkedCompat.IsActive && (Object)(object)player != (Object)null)
					{
						SkillsReworkedCompat.RefreshSkillMapping(player);
					}
					if (SkillsReworkedCompat.OwnsProgression(type))
					{
						name = NumericSkillName(type);
						return true;
					}
					if (__instance.m_skillData == null || !__instance.m_skillData.TryGetValue(type, out var value3) || value3 == null)
					{
						return false;
					}
					value3.m_level = Mathf.Clamp(value3.m_level + value, NegativeSkillsCompat.IsActive ? (-100f) : 0f, 100f);
					value3.m_accumulator = 0f;
					BesSkillPersistence.CaptureSkill(player, type);
					InvalidateLoadedSkillCaches();
					if (showMessage && (Object)(object)player != (Object)null)
					{
						((Character)player).Message((MessageType)1, BesLocalization.Format("$tag_bes_skill_increased", value2.LocalizedName, (int)value3.m_level), 0, value2.Icon, false);
					}
					Console instance2 = Console.instance;
					if (instance2 != null)
					{
						instance2.Print(BesLocalization.Format("$tag_bes_skill_value", value2.LocalizedName, (int)value3.m_level));
					}
					return false;
				}
				catch
				{
					return true;
				}
			}
		}

		[HarmonyPatch(typeof(Skills), "CheatResetSkill")]
		private static class Skills_CheatResetSkill_Patch
		{
			[HarmonyPrefix]
			[HarmonyPriority(800)]
			[HarmonyBefore(new string[] { "M2Valheim.SkillsReworked" })]
			private static bool Prefix(Skills __instance, ref string name)
			{
				//IL_0034: Unknown result type (might be due to invalid IL or missing references)
				//IL_0058: Unknown result type (might be due to invalid IL or missing references)
				//IL_006c: 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_00ce: Unknown result type (might be due to invalid IL or missing references)
				//IL_0100: Unknown result type (might be due to invalid IL or missing references)
				//IL_011b: Unknown result type (might be due to invalid IL or missing references)
				//IL_010e: Unknown result type (might be due to invalid IL or missing references)
				try
				{
					if (string.IsNullOrEmpty(name))
					{
						return true;
					}
					if (!TryResolveCustomAlias(name, out var type))
					{
						return true;
					}
					if (!Registered.TryGetValue(type, out var value) || value == null)
					{
						return true;
					}
					if (CollisionDisabled.Contains(type))
					{
						return true;
					}
					if (!IsSkillEnabled(type))
					{
						Console instance = Console.instance;
						if (instance != null)
						{
							instance.Print(BesLocalization.Format("$tag_bes_skill_disabled", value.LocalizedName));
						}
						return false;
					}
					Player player = __instance.m_player;
					EnsureDefsInSkillsList(__instance, forceRefresh: true);
					EnsureSkillSeeded(__instance, type);
					if (SkillsReworkedCompat.IsActive && IsPlainEnduranceAlias(name, type))
					{
						return true;
					}
					if (SkillsReworkedCompat.IsActive && (Object)(object)player != (Object)null)
					{
						SkillsReworkedCompat.RefreshSkillMapping(player);
					}
					if (SkillsReworkedCompat.OwnsProgression(type))
					{
						name = NumericSkillName(type);
						return true;
					}
					__instance.ResetSkill(type);
					Console instance2 = Console.instance;
					if (instance2 != null)
					{
						instance2.Print(BesLocalization.Format("$tag_bes_skill_reset", value.LocalizedName));
					}
					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 HashSet<SkillType> CollisionDisabled = new HashSet<SkillType>();

		private static readonly Dictionary<SkillType, SkillType> LegacySkillIds = new Dictionary<SkillType, SkillType>
		{
			{
				(SkillType)17876,
				(SkillType)15001
			},
			{
				(SkillType)32776,
				(SkillType)15002
			},
			{
				(SkillType)39487,
				(SkillType)15003
			},
			{
				(SkillType)39004,
				(SkillType)15005
			},
			{
				(SkillType)35846,
				(SkillType)15006
			}
		};

		internal static Skill GetSkillCompat(Skills skills, SkillType type)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			return ((Object)(object)skills == (Object)null) ? null : skills.GetSkill(type);
		}

		internal static SkillDef GetSkillDefCompat(Skills skills, SkillType type)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			return ((Object)(object)skills == (Object)null) ? null : skills.GetSkillDef(type);
		}

		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_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: 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)
			//IL_0117: Expected I4, but got Unknown
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_0137: Expected I4, but got Unknown
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0157: Unknown result type (might be due to invalid IL or missing references)
			//IL_0161: 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_0194: 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("BES" + skill.SkillNameEnglish, skill.SkillType);
			AddAlias("BES" + text, skill.SkillType);
			AddAlias(skill.NameToken, skill.SkillType);
			AddAlias("skill_" + (int)skill.SkillType, skill.SkillType);
			AddAlias(((int)skill.SkillType).ToString(), 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);
		}

		private static bool TryGetLegacyTarget(SkillType legacyType, out SkillType currentType)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			return LegacySkillIds.TryGetValue(legacyType, out currentType);
		}

		internal static bool IsCollisionDisabled(SkillType type)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			return CollisionDisabled.Contains(type);
		}

		internal static bool TryGetCustomSkill(SkillType type, out BaseSkill skill)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			return Registered.TryGetValue(type, out skill);
		}

		internal static bool IsSkillEnabled(SkillType type)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			if (!Registered.TryGetValue(type, out var value) || value == null)
			{
				return true;
			}
			if (CollisionDisabled.Contains(type))
			{
				return false;
			}
			return BesRuntime.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 = BesRuntime.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 = BesRuntime.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_001e: 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_0039: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)player == (Object)null) && !(amount <= 0f) && (!IsCustomSkill(type) || IsSkillEnabled(type)))
			{
				SkillXpRouter.Raise(player, type, amount, "BES custom skill");
			}
		}

		public static void NotifyAssetsReady()
		{
			try
			{
				Player localPlayer = Player.m_localPlayer;
				if ((Object)(object)localPlayer != (Object)null)
				{
					EnsureDefsInSkillsList(((Character)localPlayer).GetSkills(), forceRefresh: true);
					DualMasteryCompat.EnsureSkillVisible(((Character)localPlayer).GetSkills());
					SkillsReworkedCompat.RefreshSkillMapping(localPlayer);
				}
				foreach (Player allPlayer in Player.GetAllPlayers())
				{
					if (!((Object)(object)allPlayer == (Object)null))
					{
						EnsureDefsInSkillsList(((Character)allPlayer).GetSkills(), forceRefresh: true);
					}
				}
			}
			catch
			{
			}
		}

		internal static void NotifySkillEnablementChanged(SkillType type)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Expected I4, but got Unknown
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Expected I4, but got Unknown
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			if (!Registered.ContainsKey(type))
			{
				return;
			}
			bool flag = IsSkillEnabled(type);
			ResetRuntimeState(type);
			try
			{
				List<Player> allPlayers = Player.GetAllPlayers();
				for (int i = 0; i < allPlayers.Count; i++)
				{
					Player val = allPlayers[i];
					if (!((Object)(object)val == (Object)null))
					{
						Skills skills = ((Character)val).GetSkills();
						if (!((Object)(object)skills == (Object)null))
						{
							EnsureDefsInSkillsList(skills, forceRefresh: true);
							EnsureSkillSeeded(skills, type);
						}
					}
				}
				Player localPlayer = Player.m_localPlayer;
				if ((Object)(object)localPlayer != (Object)null)
				{
					SkillsReworkedCompat.RefreshSkillMapping(localPlayer);
				}
				TryRefreshOpenSkillsDialogs();
			}
			catch (Exception ex)
			{
				if (BesRuntime.Log != null)
				{
					BesRuntime.Log.LogWarning((object)("[BES skills] Failed to reconcile Enabled state for skill " + (int)type + ": " + ex.Message));
				}
			}
			if (BesRuntime.Log != null)
			{
				BesRuntime.Log.LogInfo((object)("[BES skills] " + ((Registered[type] != null) ? Registered[type].SkillNameEnglish : ((int)type).ToString()) + (flag ? " enabled and exposed to the game." : " disabled and removed from game-facing skill definitions.")));
			}
		}

		private static void TryRefreshOpenSkillsDialogs()
		{
			try
			{
				MethodInfo methodInfo = AccessTools.Method(typeof(SkillsDialog), "Setup", (Type[])null, (Type[])null);
				if (methodInfo == null)
				{
					return;
				}
				ParameterInfo[] parameters = methodInfo.GetParameters();
				SkillsDialog[] array = Resources.FindObjectsOfTypeAll<SkillsDialog>();
				foreach (SkillsDialog val in array)
				{
					if ((Object)(object)val == (Object)null || !((Component)val).gameObject.activeInHierarchy)
					{
						continue;
					}
					if (parameters.Length == 0)
					{
						methodInfo.Invoke(val, null);
					}
					else if (parameters.Length == 1 && parameters[0].ParameterType.IsAssignableFrom(typeof(Player)))
					{
						Player localPlayer = Player.m_localPlayer;
						if ((Object)(object)localPlayer != (Object)null)
						{
							methodInfo.Invoke(val, new object[1] { localPlayer });
						}
					}
				}
			}
			catch (Exception ex)
			{
				if (BesRuntime.Settings != null && BesRuntime.Settings.LogCompatibility.Value && BesRuntime.Log != null)
				{
					BesRuntime.Log.LogWarning((object)("[BES skills] Could not refresh an open Skills dialog after config change: " + ex.Message));
				}
			}
		}

		private static void ResetRuntimeState(SkillType type)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Expected I4, but got Unknown
			switch ((int)type)
			{
			case 15001:
				VitalitySkill.ResetRuntimeState();
				break;
			case 15002:
				ArcanaSkill.ResetRuntimeState();
				break;
			case 15003:
				EnduranceSkill.ResetRuntimeState();
				break;
			case 15004:
				ExplorationSkill.ResetRuntimeState();
				break;
			case 15005:
				FortitudeSkill.ResetRuntimeState();
				break;
			case 15006:
				HaulingSkill.ResetRuntimeState();
				break;
			case 15007:
				SailingSkill.ResetRuntimeState();
				break;
			case 15008:
				TamingSkill.ResetRuntimeState();
				break;
			}
		}

		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;
		}

		internal static bool TryResolveSkillIdentifier(string raw, out SkillType type)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Expected I4, but got Unknown
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Expected I4, but got Unknown
			type = (SkillType)0;
			if (string.IsNullOrWhiteSpace(raw))
			{
				return false;
			}
			string key = SanitizeKey(raw);
			if (ByAlias.TryGetValue(key, out var value))
			{
				type = (SkillType)(int)value;
				return true;
			}
			if (int.TryParse(raw.Trim(), out var result))
			{
				type = (SkillType)result;
				return true;
			}
			try
			{
				if (Enum.TryParse<SkillType>(raw.Trim(), ignoreCase: true, out SkillType result2))
				{
					type = (SkillType)(int)result2;
					return true;
				}
			}
			catch
			{
			}
			return false;
		}

		private static bool TryResolveCustomAlias(string raw, out SkillType type)
		{
			type = (SkillType)0;
			if (string.IsNullOrWhiteSpace(raw))
			{
				return false;
			}
			return ByAlias.TryGetValue(SanitizeKey(raw), out type) && Registered.ContainsKey(type);
		}

		private static bool IsPlainEnduranceAlias(string raw, SkillType type)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Invalid comparison between Unknown and I4
			return (int)type == 15003 && SanitizeKey(raw) == SanitizeKey("Endurance");
		}

		private static string NumericSkillName(SkillType type)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Expected I4, but got Unknown
			return ((int)type).ToString(CultureInfo.InvariantCulture);
		}

		private static bool IsOurDefinition(SkillDef def, BaseSkill skill)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			return def != null && skill != null && def.m_skill == skill.SkillType && string.Equals(def.m_description, skill.DescToken, StringComparison.Ordinal);
		}

		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_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Expected I4, but got Unknown
			//IL_01be: Unknown result type (might be due to invalid IL or missing references)
			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;
				bool flag = IsSkillEnabled(key);
				SkillDef val = null;
				SkillDef val2 = null;
				for (int num = skills2.Count - 1; num >= 0; num--)
				{
					SkillDef val3 = skills2[num];
					if (val3 != null && val3.m_skill == key)
					{
						if (IsOurDefinition(val3, value))
						{
							if (!flag)
							{
								skills2.RemoveAt(num);
							}
							else
							{
								val = val3;
							}
						}
						else
						{
							val2 = val3;
						}
					}
				}
				if (val2 != null)
				{
					if (CollisionDisabled.Add(key))
					{
						Debug.LogError((object)("[BalrondExtraSkills] CRITICAL skill ID collision: " + (int)key + " is already represented by another SkillDef. BES module '" + value.InternalKey + "' is disabled; the numeric ID will not be remapped."));
					}
				}
				else if (!CollisionDisabled.Contains(key) && flag)
				{
					if (val == null)
					{
						val = CreateDefinition(value);
						skills2.Add(val);
					}
					else if (forceRefresh)
					{
						val.m_icon = value.Icon;
						val.m_description = value.DescToken;
					}
					if (val != null && skills.m_skillData != null && skills.m_skillData.TryGetValue(key, out var value2) && value2 != null)
					{
						value2.m_info = val;
					}
				}
			}
		}

		private static SkillDef CreateDefinition(BaseSkill skill)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Expected O, but got Unknown
			if (skill == null)
			{
				return null;
			}
			return new SkillDef
			{
				m_skill = skill.SkillType,
				m_icon = skill.Icon,
				m_description = skill.DescToken,
				m_increseStep = 1f
			};
		}

		private static void MigrateLegacySkillData(Skills skills)
		{
			//IL_0217: Unknown result type (might be due to invalid IL or missing references)
			//IL_0249: Unknown result type (might be due to invalid IL or missing references)
			//IL_0250: Expected I4, but got Unknown
			//IL_0264: Unknown result type (might be due to invalid IL or missing references)
			//IL_026b: Expected I4, but got Unknown
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b1: Expected I4, but got Unknown
			//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cc: Expected I4, but got Unknown
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)skills == (Object)null || skills.m_skillData == null)
			{
				return;
			}
			foreach (KeyValuePair<SkillType, SkillType> legacySkillId in LegacySkillIds)
			{
				if (!skills.m_skillData.TryGetValue(legacySkillId.Key, out var value) || value == null || !Registered.TryGetValue(legacySkillId.Value, out var value2) || value2 == null || (value.m_info != null && !string.Equals(value.m_info.m_description, value2.DescToken, StringComparison.Ordinal)))
				{
					continue;
				}
				Skill value3 = null;
				skills.m_skillData.TryGetValue(legacySkillId.Value, out value3);
				if (value3 == null)
				{
					try
					{
						value3 = skills.GetSkill(legacySkillId.Value);
					}
					catch
					{
						value3 = null;
					}
				}
				if (value3 != null)
				{
					bool flag = Mathf.Approximately(value3.m_level, 0f) && Mathf.Approximately(value3.m_accumulator, 0f);
					bool flag2 = !Mathf.Approximately(value.m_level, 0f) || !Mathf.Approximately(value.m_accumulator, 0f);
					if (flag && flag2)
					{
						value3.m_level = value.m_level;
						value3.m_accumulator = value.m_accumulator;
						if (BesRuntime.Log != null)
						{
							BesRuntime.Log.LogInfo((object)("[BES persistence] Migrated legacy skill " + (int)legacySkillId.Key + " -> " + (int)legacySkillId.Value + " level=" + value.m_level.ToString(CultureInfo.InvariantCulture) + "."));
						}
					}
				}
				if (value3 != null)
				{
					skills.m_skillData.Remove(legacySkillId.Key);
				}
				else if (BesRuntime.Log != null)
				{
					BesRuntime.Log.LogWarning((object)("[BES persistence] Deferred legacy skill migration " + (int)legacySkillId.Key + " -> " + (int)legacySkillId.Value + ": target skill is unavailable."));
				}
			}
		}

		private static void EnsureSkillSeeded(Skills skills, SkillType type)
		{
			//IL_001c: 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_003e: 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)
			if (!((Object)(object)skills == (Object)null) && skills.m_skillData != null && IsCustomSkill(type) && !CollisionDisabled.Contains(type) && !skills.m_skillData.ContainsKey(type))
			{
				skills.GetSkill(type);
			}
		}

		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);
			}
			if (SkillRuntime.IsLocal(player))
			{
				DualMasteryCompat.EnsureSkillVisible(skills);
				SkillsReworkedCompat.RefreshSkillMapping(player);
			}
		}

		private static void InvalidateLoadedSkillCaches()
		{
			SkillRuntime.InvalidateAllLevelCache();
			TotalLevelService.Invalidate();
			ResourceCapacityBonus.Invalidate();
		}
	}
	public class BalrondTranslator
	{
		public static readonly Dictionary<string, Dictionary<string, string>> translations = new Dictionary<string, Dictionary<string, string>>(StringComparer.OrdinalIgnoreCase);

		public static Dictionary<string, string> getLanguage(string language)
		{
			if (string.IsNullOrEmpty(language))
			{
				return null;
			}
			translations.TryGetValue(language, out var value);
			return value;
		}

		public static Dictionary<string, string> GetMergedLanguage(string language)
		{
			Dictionary<string, string> dictionary = new Dictionary<string, string>(StringComparer.Ordinal);
			Dictionary<string, string> language2 = getLanguage("English");
			if (language2 != null)
			{
				foreach (KeyValuePair<string, string> item in language2)
				{
					dictionary[item.Key] = item.Value;
				}
			}
			if (!string.IsNullOrEmpty(language) && !string.Equals(language, "English", StringComparison.OrdinalIgnoreCase))
			{
				Dictionary<string, string> language3 = getLanguage(language);
				if (language3 != null)
				{
					foreach (KeyValuePair<string, string> item2 in language3)
					{
						dictionary[item2.Key] = item2.Value;
					}
				}
			}
			return (dictionary.Count > 0) ? dictionary : null;
		}
	}
	internal static class BesLocalization
	{
		private static readonly Dictionary<string, string> CoreEnglishFallback = new Dictionary<string, string>(StringComparer.Ordinal)
		{
			{ "skill_15001", "Vitality" },
			{ "skill_15002", "Arcana" },
			{ "skill_15003", "Endurance" },
			{ "skill_15004", "Exploration" },
			{ "skill_15005", "Fortitude" },
			{ "skill_15006", "Hauling" },
			{ "skill_15007", "Sailing" },
			{ "skill_15008", "Taming" },
			{ "tag_skill_vitalityskill_bal", "Vitality" },
			{ "tag_skill_vitalityskill_bal_description", "Raises maximum health and health regeneration." },
			{ "tag_skill_arcanaskill_bal", "Arcana" },
			{ "tag_skill_arcanaskill_bal_description", "Raises maximum Eitr and Eitr regeneration." },
			{ "tag_skill_enduranceskill_bal", "Endurance" },
			{ "tag_skill_enduranceskill_bal_description", "Raises maximum stamina and stamina regeneration." },
			{ "tag_skill_explorationskill_bal", "Exploration" },
			{ "tag_skill_explorationskill_bal_description", "Expands map discovery radius." },
			{ "tag_skill_fortitudeskill_bal", "Fortitude" },
			{ "tag_skill_fortitudeskill_bal_description", "Increases armor." },
			{ "tag_skill_haulingskill_bal", "Hauling" },
			{ "tag_skill_haulingskill_bal_description", "Increases carry weight." },
			{ "tag_skill_sailingskill_bal", "Sailing" },
			{ "tag_skill_sailingskill_bal_description", "Improves ship handling and reduces collision damage." },
			{ "tag_skill_tamingskill_bal", "Taming" },
			{ "tag_skill_tamingskill_bal_description", "Speeds basic taming. Progressing taming and successful breeding train the skill." }
		};

		internal static string Text(string token)
		{
			if (string.IsNullOrEmpty(token))
			{
				return string.Empty;
			}
			string text = ((token[0] == '$') ? token : ("$" + token));
			string text2 = text.Substring(1);
			try
			{
				if (Localization.instance != null)
				{
					string text3 = Localization.instance.Localize(text);
					if (!IsRawLocalizationResult(text3, text, text2))
					{
						return text3;
					}
				}
			}
			catch
			{
			}
			string text4 = English(text2);
			if (!string.IsNullOrEmpty(text4))
			{
				return text4;
			}
			return HumanizeKey(text2);
		}

		internal static string Format(string token, params object[] args)
		{
			string text = Text(token);
			try
			{
				return string.Format(CultureInfo.CurrentCulture, text, args ?? Array.Empty<object>());
			}
			catch
			{
				return text;
			}
		}

		internal static string English(string tokenOrKey, string fallback = "")
		{
			if (string.IsNullOrEmpty(tokenOrKey))
			{
				return fallback ?? string.Empty;
			}
			string key = ((tokenOrKey[0] == '$') ? tokenOrKey.Substring(1) : tokenOrKey);
			Dictionary<string, string> language = BalrondTranslator.getLanguage("English");
			if (language != null && language.TryGetValue(key, out var value) && !string.IsNullOrEmpty(value))
			{
				return value;
			}
			if (CoreEnglishFallback.TryGetValue(key, out var value2) && !string.IsNullOrEmpty(value2))
			{
				return value2;
			}
			return fallback ?? string.Empty;
		}

		private static bool IsRawLocalizationResult(string localized, string normalized, string key)
		{
			if (string.IsNullOrEmpty(localized))
			{
				return true;
			}
			if (string.Equals(localized, normalized, StringComparison.Ordinal))
			{
				return true;
			}
			if (string.Equals(localized, key, StringComparison.Ordinal))
			{
				return true;
			}
			if (string.Equals(localized, "[" + key + "]", StringComparison.Ordinal))
			{
				return true;
			}
			if (string.Equals(localized, "[" + normalized + "]", StringComparison.Ordinal))
			{
				return true;
			}
			return false;
		}

		private static string HumanizeKey(string key)
		{
			if (string.IsNullOrEmpty(key))
			{
				return string.Empty;
			}
			string text = key;
			if (text.StartsWith("tag_skill_", StringComparison.Ordinal))
			{
				text = text.Substring("tag_skill_".Length);
			}
			else if (text.StartsWith("tag_bes_", StringComparison.Ordinal))
			{
				text = text.Substring("tag_bes_".Length);
			}
			else if (text.StartsWith("skill_", StringComparison.Ordinal))
			{
				text = text.Substring("skill_".Length);
			}
			if (text.EndsWith("_description", StringComparison.Ordinal))
			{
				text = text.Substring(0, text.Length - "_description".Length);
			}
			if (text.EndsWith("_bal", StringComparison.Ordinal))
			{
				text = text.Substring(0, text.Length - 4);
			}
			text = text.Replace('_', ' ').Trim();
			if (text.Length == 0)
			{
				return key;
			}
			return char.ToUpperInvariant(text[0]) + text.Substring(1);
		}
	}
	internal static class BesSkillPersistence
	{
		[HarmonyPatch(typeof(Player), "Save", new Type[] { typeof(ZPackage) })]
		private static class Player_Save_BesSkillMirror_Patch
		{
			[HarmonyPrefix]
			[HarmonyPriority(800)]
			private static void Prefix(Player __instance)
			{
				CaptureAll(__instance);
				if (SkillRuntime.IsLocal(__instance))
				{
					LogState("SAVE", __instance);
				}
			}
		}

		[HarmonyPatch(typeof(Skills), "LowerAllSkills", new Type[] { typeof(float) })]
		private static class Skills_LowerAllSkills_BesSkillMirror_Patch
		{
			[HarmonyPostfix]
			[HarmonyPriority(0)]
			private static void Postfix(Skills __instance)
			{
				Player localPlayer = Player.m_localPlayer;
				if (!((Object)(object)localPlayer == (Object)null) && !((Object)(object)((Character)localPlayer).GetSkills() != (Object)(object)__instance))
				{
					CaptureAll(localPlayer);
				}
			}
		}

		[HarmonyPatch(typeof(Skills), "ResetSkill", new Type[] { typeof(SkillType) })]
		private static class Skills_ResetSkill_BesSkillMirror_Patch
		{
			[HarmonyPostfix]
			private static void Postfix(Skills __instance, SkillType skillType)
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0035: Unknown result type (might be due to invalid IL or missing references)
				if (BalrondSkillSystem.IsCustomSkill(skillType))
				{
					Player localPlayer = Player.m_localPlayer;
					if (!((Object)(object)localPlayer == (Object)null) && !((Object)(object)((Character)localPlayer).GetSkills() != (Object)(object)__instance))
					{
						CaptureSkill(localPlayer, skillType);
					}
				}
			}
		}

		private const string StatePrefix = "BES_SKILL_STATE_V1_";

		private static readonly FieldInfo PlayerCustomDataField = AccessTools.Field(typeof(Player), "m_customData");

		internal static void CaptureAll(Player player)
		{
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: 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)
			if ((Object)(object)player == (Object)null)
			{
				return;
			}
			Skills skills = ((Character)player).GetSkills();
			if ((Object)(object)skills == (Object)null || skills.m_skillData == null)
			{
				return;
			}
			IDictionary customData = GetCustomData(player);
			if (customData == null)
			{
				return;
			}
			foreach (KeyValuePair<SkillType, BaseSkill> item in BalrondSkillSystem.Registered)
			{
				SkillType key = item.Key;
				if (!BalrondSkillSystem.IsCollisionDisabled(key) && !SkillsReworkedCompat.OwnsProgression(key) && skills.m_skillData.TryGetValue(key, out var value) && value != null)
				{
					WriteState(customData, key, value.m_level, value.m_accumulator);
				}
			}
		}

		internal static void CaptureSkill(Player player, SkillType type)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)player == (Object)null || !BalrondSkillSystem.IsCustomSkill(type) || BalrondSkillSystem.IsCollisionDisabled(type) || SkillsReworkedCompat.OwnsProgression(type))
			{
				return;
			}
			Skills skills = ((Character)player).GetSkills();
			if (!((Object)(object)skills == (Object)null) && skills.m_skillData != null && skills.m_skillData.TryGetValue(type, out var value) && value != null)
			{
				IDictionary customData = GetCustomData(player);
				if (customData != null)
				{
					WriteState(customData, type, value.m_level, value.m_accumulator);
				}
			}
		}

		internal static void RestoreAfterPlayerLoad(Player player)
		{
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: 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_0096: 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_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bf: Expected I4, but got Unknown
			if ((Object)(object)player == (Object)null)
			{
				return;
			}
			Skills skills = ((Character)player).GetSkills();
			if ((Object)(object)skills == (Object)null || skills.m_skillData == null)
			{
				return;
			}
			IDictionary customData = GetCustomData(player);
			if (customData == null)
			{
				return;
			}
			foreach (KeyValuePair<SkillType, BaseSkill> item in BalrondSkillSystem.Registered)
			{
				SkillType key = item.Key;
				if (BalrondSkillSystem.IsCollisionDisabled(key) || SkillsReworkedCompat.OwnsProgression(key) || !TryReadState(customData, key, out var level, out var accumulator))
				{
					continue;
				}
				if (!skills.m_skillData.TryGetValue(key, out var value) || value == null)
				{
					try
					{
						value = skills.GetSkill(key);
					}
					catch
					{
						value = null;
					}
				}
				if (value == null)
				{
					continue;
				}
				bool flag = !Mathf.Approximately(value.m_level, 0f) || !Mathf.Approximately(value.m_accumulator, 0f);
				bool flag2 = !Mathf.Approximately(level, 0f) || !Mathf.Approximately(accumulator, 0f);
				if (!flag && flag2)
				{
					float num = (NegativeSkillsCompat.IsActive ? (-100f) : 0f);
					value.m_level = Mathf.Clamp(level, num, 100f);
					value.m_accumulator = Mathf.Max(0f, accumulator);
					if (BesRuntime.Log != null)
					{
						BesRuntime.Log.LogWarning((object)("[BES persistence] Recovered skill " + (int)key + " from player custom-data mirror at level " + value.m_level.ToString("0.###", CultureInfo.InvariantCulture) + "."));
					}
				}
			}
		}

		internal static void LogState(string phase, Player player)
		{
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Expected I4, but got Unknown
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0150: Unknown result type (might be due to invalid IL or missing references)
			ExtraSkillsConfig settings = BesRuntime.Settings;
			if (settings == null || !settings.LogCompatibility.Value || BesRuntime.Log == null || (Object)(object)player == (Object)null)
			{
				return;
			}
			Skills skills = ((Character)player).GetSkills();
			if ((Object)(object)skills == (Object)null || skills.m_skillData == null)
			{
				return;
			}
			StringBuilder stringBuilder = new StringBuilder(192);
			stringBuilder.Append("[BES persistence ").Append(phase).Append("] ");
			bool flag = true;
			foreach (KeyValuePair<SkillType, BaseSkill> item in BalrondSkillSystem.Registered)
			{
				SkillType key = item.Key;
				if (!flag)
				{
					stringBuilder.Append(" | ");
				}
				flag = false;
				stringBuilder.Append((int)key).Append('=');
				if (skills.m_skillData.TryGetValue(key, out var value) && value != null)
				{
					stringBuilder.Append(value.m_level.ToString("0.###", CultureInfo.InvariantCulture));
					stringBuilder.Append('/');
					stringBuilder.Append(value.m_accumulator.ToString("0.###", CultureInfo.InvariantCulture));
				}
				else
				{
					stringBuilder.Append("missing");
				}
				if (SkillsReworkedCompat.OwnsProgression(key))
				{
					stringBuilder.Append("(SR)");
				}
			}
			BesRuntime.Log.LogInfo((object)stringBuilder.ToString());
		}

		private static IDictionary GetCustomData(Player player)
		{
			try
			{
				return (PlayerCustomDataField != null) ? (PlayerCustomDataField.GetValue(player) as IDictionary) : null;
			}
			catch
			{
				return null;
			}
		}

		private static string Key(SkillType type)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Expected I4, but got Unknown
			return "BES_SKILL_STATE_V1_" + ((int)type).ToString(CultureInfo.InvariantCulture);
		}

		private static void WriteState(IDictionary data, SkillType type, float level, float accumulator)
		{
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			if (data != null && !float.IsNaN(level) && !float.IsInfinity(level))
			{
				if (float.IsNaN(accumulator) || float.IsInfinity(accumulator))
				{
					accumulator = 0f;
				}
				data[Key(type)] = level.ToString("R", CultureInfo.InvariantCulture) + "|" + accumulator.ToString("R", CultureInfo.InvariantCulture);
			}
		}

		private static bool TryReadState(IDictionary data, SkillType type, out float level, out float accumulator)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			level = 0f;
			accumulator = 0f;
			if (data == null)
			{
				return false;
			}
			object obj = data[Key(type)];
			if (obj == null)
			{
				return false;
			}
			string text = obj.ToString();
			if (string.IsNullOrEmpty(text))
			{
				return false;
			}
			int num = text.IndexOf('|');
			if (num <= 0 || num >= text.Length - 1)
			{
				return false;
			}
			if (!float.TryParse(text.Substring(0, num), NumberStyles.Float, CultureInfo.InvariantCulture, out var result))
			{
				return false;
			}
			if (!float.TryParse(text.Substring(num + 1), NumberStyles.Float, CultureInfo.InvariantCulture, out var result2))
			{
				return false;
			}
			if (float.IsNaN(result) || float.IsInfinity(result))
			{
				return false;
			}
			if (float.IsNaN(result2) || float.IsInfinity(result2))
			{
				result2 = 0f;
			}
			level = result;
			accumulator = result2;
			return true;
		}
	}
	internal static class BesSkillSaveGuard
	{
		private sealed class SaveState
		{
			internal readonly List<SkillType> EmptyKeys = new List<SkillType>();

			internal readonly List<TemporaryInfo> TemporaryInfos = new List<TemporaryInfo>();

			internal bool Restored;
		}

		private struct TemporaryInfo
		{
			internal Skill Skill;

			internal SkillDef Injected;

			internal SkillDef Original;
		}

		[HarmonyPatch(typeof(Skills), "Save", new Type[] { typeof(ZPackage) })]
		private static class Skills_Save_ValidateEntries_Patch
		{
			[HarmonyPrefix]
			[HarmonyPriority(0)]
			[HarmonyAfter(new string[] { "M2Valheim.SkillsReworked" })]
			private static void Prefix(Skills __instance, out SaveState __state)
			{
				//IL_014d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0151: Expected I4, but got Unknown
				//IL_0178: Unknown result type (might be due to invalid IL or missing references)
				//IL_017d: Unknown result type (might be due to invalid IL or missing references)
				//IL_01bb: Unknown result type (might be due to invalid IL or missing references)
				//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
				//IL_01c1: Unknown result type (might be due to invalid IL or missing references)
				//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
				//IL_01c8: Unknown result type (might be due to invalid IL or missing references)
				//IL_01d3: Unknown result type (might be due to invalid IL or missing references)
				//IL_01e0: Expected O, but got Unknown
				//IL_0220: Unknown result type (might be due to invalid IL or missing references)
				//IL_0224: Expected I4, but got Unknown
				//IL_0199: Unknown result type (might be due to invalid IL or missing references)
				//IL_019d: Expected I4, but got Unknown
				//IL_004c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0051: Unknown result type (might be due to invalid IL or missing references)
				//IL_006f: Unknown result type (might be due to invalid IL or missing references)
				//IL_007c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0080: Expected I4, but got Unknown
				//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
				//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
				//IL_0139: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
				//IL_0269: Unknown result type (might be due to invalid IL or missing references)
				//IL_026e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0276: Unknown result type (might be due to invalid IL or missing references)
				//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
				//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
				//IL_00f8: Expected I4, but got Unknown
				//IL_010c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0113: Expected I4, but got Unknown
				//IL_0295: Unknown result type (might be due to invalid IL or missing references)
				__state = new SaveState();
				if ((Object)(object)__instance == (Object)null || __instance.m_skillData == null)
				{
					return;
				}
				try
				{
					List<KeyValuePair<SkillType, Skill>> list = new List<KeyValuePair<SkillType, Skill>>(__instance.m_skillData);
					foreach (KeyValuePair<SkillType, Skill> item in list)
					{
						SkillType key = item.Key;
						Skill value = item.Value;
						if (value == null)
						{
							__state.EmptyKeys.Add(key);
							Warn("Null skill entry " + (int)key + " excluded from this save (no level or XP to serialize).");
							continue;
						}
						SkillDef info = value.m_info;
						if (info != null)
						{
							if (info.m_skill == key)
							{
								continue;
							}
							if (!BalrondSkillSystem.IsCustomSkill(key) || BalrondSkillSystem.IsCollisionDisabled(key))
							{
								Warn("Skill dictionary key " + (int)key + " has definition ID " + (int)info.m_skill + "; foreign mapping left unchanged.");
								continue;
							}
						}
						SkillDef val = null;
						try
						{
							val = __instance.GetSkillDef(key);
						}
						catch (Exception ex)
						{
							Warn("GetSkillDef(" + (int)key + ") failed: " + ex.Message);
						}
						if (val != null && val.m_skill == key)
						{
							value.m_info = val;
							Warn("Restored missing SkillDef for skill " + (int)key + ".");
							continue;
						}
						SkillDef val2 = new SkillDef
						{
							m_skill = key,
							m_description = "",
							m_increseStep = 1f
						};
						__state.TemporaryInfos.Add(new TemporaryInfo
						{
							Skill = value,
							Original = info,
							Injected = val2
						});
						value.m_info = val2;
						Warn("Skill " + (int)key + " has no registered definition; using a temporary save-only SkillDef to preserve its XP.");
					}
					for (int i = 0; i < __state.EmptyKeys.Count; i++)
					{
						SkillType key2 = __state.EmptyKeys[i];
						if (__instance.m_skillData.TryGetValue(key2, out var value2) && value2 == null)
						{
							__instance.m_skillData.Remove(key2);
						}
					}
				}
				catch (Exception ex2)
				{
					Restore(__instance, __state);
					if (BesRuntime.Log != null)
					{
						BesRuntime.Log.LogError((object)("[BES save guard] Pre-save validation failed: " + ex2));
					}
				}
			}

			[HarmonyPostfix]
			private static void Postfix(Skills __instance, SaveState __state)
			{
				Restore(__instance, __state);
			}

			[HarmonyFinalizer]
			private static Exception Finalizer(Skills __instance, SaveState __state, Exception __exception)
			{
				Restore(__instance, __state);
				if (__exception != null && BesRuntime.Log != null)
				{
					BesRuntime.Log.LogError((object)("[BES save guard] Skills.Save still failed after entry validation. Check other Harmony prefixes/transpilers and preceding skill-ID warnings. Patch owners: " + GetSavePatchOwners() + ". " + __exception));
				}
				return __exception;
			}
		}

		private static void Restore(Skills skills, SaveState state)
		{
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			if (state == null || state.Restored)
			{
				return;
			}
			state.Restored = true;
			for (int i = 0; i < state.TemporaryInfos.Count; i++)
			{
				TemporaryInfo temporaryInfo = state.TemporaryInfos[i];
				if (temporaryInfo.Skill != null && temporaryInfo.Skill.m_info == temporaryInfo.Injected)
				{
					temporaryInfo.Skill.m_info = temporaryInfo.Original;
				}
			}
			if ((Object)(object)skills == (Object)null || skills.m_skillData == null)
			{
				return;
			}
			for (int j = 0; j < state.EmptyKeys.Count; j++)
			{
				SkillType key = state.EmptyKeys[j];
				if (!skills.m_skillData.ContainsKey(key))
				{
					skills.m_skillData[key] = null;
				}
			}
		}

		private static string GetSavePatchOwners()
		{
			try
			{
				MethodInfo methodInfo = AccessTools.Method(typeof(Skills), "Save", new Type[1] { typeof(ZPackage) }, (Type[])null);
				Patches val = ((methodInfo != null) ? Harmony.GetPatchInfo((MethodBase)methodInfo) : null);
				return (val != null && val.Owners != null) ? string.Join(", ", val.Owners) : "none";
			}
			catch
			{
				return "unavailable";
			}
		}

		private static void Warn(string message)
		{
			if (BesRuntime.Log != null)
			{
				BesRuntime.Log.LogWarning((object)("[BES save guard] " + message));
			}
		}
	}
	internal static class BesBootstrap
	{
		internal static void Start(Launch plugin, ManualLogSource log)
		{
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: Expected O, but got Unknown
			if ((Object)(object)plugin == (Object)null)
			{
				throw new ArgumentNullException("plugin");
			}
			if (log == null)
			{
				throw new ArgumentNullException("log");
			}
			if (!BesRuntime.Started)
			{
				BesRuntime.Instance = plugin;
				BesRuntime.Log = log;
				log.LogInfo((object)"[BES bootstrap 1/8] Initializing ServerSync and configuration.");
				ConfigSync configSync = new ConfigSync("balrond.astafaraios.BalrondExtraSkills")
				{
					DisplayName = "BalrondExtraSkills",
					CurrentVersion = "0.4.5",
					MinimumRequiredVersion = "0.4.5"
				};
				ExtraSkillsConfig extraSkillsConfig = new ExtraSkillsConfig((BaseUnityPlugin)(object)plugin, configSync);
				configSync.AddLockingConfigEntry<bool>(extraSkillsConfig.LockConfiguration);
				BesRuntime.ConfigSyncInstance = configSync;
				BesRuntime.Settings = extraSkillsConfig;
				log.LogInfo((object)("[BES config] Bound configuration entries: Sailing=" + (extraSkillsConfig.SailingEnabled != null) + ", Taming=" + (extraSkillsConfig.TamingEnabled != null) + ", TotalHUD=" + (extraSkillsConfig.TotalHudEnabled != null) + "."));
				log.LogInfo((object)"[BES bootstrap 2/8] Initializing Harmony.");
				Harmony harmony = new Harmony("balrond.astafaraios.BalrondExtraSkills");
				BesRuntime.HarmonyInstance = harmony;
				log.LogInfo((object)"[BES bootstrap 3/8] Loading translation data.");
				RunStage(log, "translation loading", delegate
				{
					BesRuntime.JsonLoader = new JsonLoader();
					BesRuntime.JsonLoader.loadJson();
				});
				log.LogInfo((object)"[BES bootstrap 4/8] Applying Harmony patches for the current Valheim API.");
				RunStage(log, "Harmony compatibility registration", delegate
				{
					HarmonyCompat.PatchAssembly(harmony, typeof(Launch).Assembly, log);
				});
				RunStage(log, "Harmony diagnostics", delegate
				{
					PatchDiagnostics.Report(log);
				});
				RunStage(log, "localization refresh", TranslationPatches.RefreshCurrentLanguage);
				log.LogInfo((object)"[BES bootstrap 5/8] Loading embedded assets.");
				RunStage(log, "embedded asset loading", delegate
				{
					BesRuntime.ModResourceLoader = new ModResourceLoader();
					BesRuntime.ModResourceLoader.loadAssets();
				});
				log.LogInfo((object)"[BES bootstrap 6/8] Registering custom skills.");
				RegisterSkillsSafe(log);
				log.LogInfo((object)"[BES bootstrap 7/8] Refreshing skill assets and definitions.");
				RunStage(log, "skill definition refresh", BalrondSkillSystem.NotifyAssetsReady);
				log.LogInfo((object)"[BES bootstrap 8/8] Warming compatibility bridges and HUD.");
				RunStage(log, "SkillsReworked compatibility warmup", SkillsReworkedCompat.Warmup);
				RunStage(log, "OdinHorse compatibility warmup", OdinHorseCompat.Warmup);
				RunStage(log, "MonsterMayhem Taming compatibility warmup", MonsterMayhemTamingCompat.Warmup);
				RunStage(log, "Total Level HUD initialization", TotalLevelHud.Ensure);
				RunStage(log, "compatibility report", ReportCompatibility);
				BesRuntime.Started = true;
				log.LogInfo((object)"BalrondExtraSkills 0.4.5 loaded with ServerSync.");
			}
		}

		internal static void Stop()
		{
			SneakSpeedBonus.ResetRuntimeState();
			VitalitySkill.ResetRuntimeState();
			ArcanaSkill.ResetRuntimeState();
			EnduranceSkill.ResetRuntimeState();
			ExplorationSkill.ResetRuntimeState();
			FortitudeSkill.ResetRuntimeState();
			HaulingSkill.ResetRuntimeState();
			SailingSkill.ResetRuntimeState();
			TamingSkill.ResetRuntimeState();
			ResourceRegenerationBonus.ResetRuntimeState();
			SkillRuntime.InvalidateAllLevelCache();
			TotalLevelService.Invalidate();
			ResourceCapacityBonus.Invalidate();
			try
			{
				Harmony harmonyInstance = BesRuntime.HarmonyInstance;
				if (harmonyInstance != null)
				{
					harmonyInstance.UnpatchSelf();
				}
			}
			catch (Exception ex)
			{
				if (BesRuntime.Log != null)
				{
					BesRuntime.Log.LogError((object)("BalrondExtraSkills: Failed during Harmony shutdown. " + ex));
				}
			}
			finally
			{
				BesRuntime.Started = false;
				BesRuntime.Settings = null;
				BesRuntime.ConfigSyncInstance = null;
				BesRuntime.HarmonyInstance = null;
				BesRuntime.ModResourceLoader = null;
				BesRuntime.JsonLoader = null;
				BesRuntime.Log = null;
				BesRuntime.Instance = null;
			}
		}

		private static void RunStage(ManualLogSource log, string name, Action action)
		{
			if (action == null)
			{
				return;
			}
			try
			{
				action();
			}
			catch (Exception ex)
			{
				log.LogError((object)("[BES bootstrap] " + name + " failed. Remaining independent systems will continue. " + ex));
			}
		}

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

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

		private static void ReportCompatibility()
		{
			ExtraSkillsConfig settings = BesRuntime.Settings;
			ManualLogSource log = BesRuntime.Log;
			if (settings != null && log != null && settings.LogCompatibility.Value)
			{
				log.LogInfo((object)("[BES compatibility] BAO=" + ModPresenceCompat.IsBaoActive + ", MonsterMayhem=" + ModPresenceCompat.IsMonsterMayhemActive + " (Taming=" + MonsterMayhemTamingCompat.Status + "), SkillsReworked=" + SkillsReworkedCompat.IsActive + " (" + SkillsReworkedCompat.Version + "), DualMastery=" + ModPresenceCompat.IsDualMasteryActive + ", BetterArchery=" + ModPresenceCompat.IsBetterArcheryActive + ", OdinHorse=" + OdinHorseCompat.IsActive + " (" + OdinHorseCompat.Version + ", " + OdinHorseCompat.BindingStatus + "), Windstride=" + ModPresenceCompat.IsWindstrideBowAnimationsActive + ", NegativeSkills=" + NegativeSkillsCompat.IsActive + ", RuneforgingSkillId=" + 16050 + ", SRBindings={" + SkillsReworkedCompat.BindingStatus + "}"));
			}
		}
	}
	internal static class BesRuntime
	{
		internal static Launch Instance;

		internal static ManualLogSource Log;

		internal static Harmony HarmonyInstance;

		internal static ConfigSync ConfigSyncInstance;

		internal static ExtraSkillsConfig Settings;

		internal static ModResourceLoader ModResourceLoader;

		internal static JsonLoader JsonLoader;

		internal static bool Started;
	}
	internal sealed class ConfigurationManagerAttributes
	{
		public int? Order = null;

		public bool? Browsable = null;

		public string Category = null;

		public string DispName = null;

		public bool? IsAdvanced = null;

		public bool? ReadOnly = null;

		public bool? HideDefaultButton = null;

		public bool? ShowRangeAsPercent = null;

		public object DefaultValue = null;
	}
	internal static class PlayerActivitySampler
	{
		[HarmonyPatch(typeof(Player), "UpdateStats", new Type[] { typeof(float) })]
		private static class Player_UpdateStats_Patch
		{
			[HarmonyPostfix]
			private static void Postfix(Player __instance)
			{
				if (!((Object)(object)__instance == (Object)null) && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer))
				{
					SneakSpeedBonus.OnPlayerStatsUpdate(__instance);
					HaulingSkill.OnPlayerStatsUpdate(__instance);
					SailingSkill.OnPlayerStatsUpdate(__instance);
				}
			}
		}
	}
	internal static class ResourceCapacityBonus
	{
		[HarmonyPatch(typeof(Player), "GetTotalFoodValue")]
		private static class Player_GetTotalFoodValue_Patch
		{
			[HarmonyPostfix]
			private static void Postfix(Player __instance, ref float hp, ref float stamina, ref float eitr)
			{
				GetBonuses(__instance, out var hp2, out var stamina2, out var eitr2);
				hp = Mathf.Max(1f, hp + hp2);
				stamina = Mathf.Max(1f, stamina + stamina2);
				eitr = Mathf.Max(0f, eitr + eitr2);
			}
		}

		private const float CacheSeconds = 0.15f;

		private static Player s_player;

		private static float s_expiresAt;

		private static float s_hpBonus;

		private static float s_staminaBonus;

		private static float s_eitrBonus;

		private static void GetBonuses(Player player, out float hp, out float stamina, out float eitr)
		{
			if ((Object)(object)player == (Object)null)
			{
				hp = (stamina = (eitr = 0f));
				return;
			}
			bool flag = (Object)(object)player == (Object)(object)Player.m_localPlayer;
			if (flag && (Object)(object)s_player == (Object)(object)player && Time.unscaledTime < s_expiresAt)
			{
				hp = s_hpBonus;
				stamina = s_staminaBonus;
				eitr = s_eitrBonus;
				return;
			}
			hp = VitalitySkill.GetBonusHp(player);
			stamina = EnduranceSkill.GetBonusStamina(player);
			eitr = ArcanaSkill.GetBonusEitr(player);
			if (flag)
			{
				s_player = player;
				s_hpBonus = hp;
				s_staminaBonus = stamina;
				s_eitrBonus = eitr;
				s_expiresAt = Time.unscaledTime + 0.15f;
			}
		}

		internal static void Invalidate()
		{
			s_player = null;
			s_expiresAt = 0f;
		}
	}
	internal static class SkillFloorSystem
	{
		[HarmonyPatch(typeof(Skills), "RaiseSkill")]
		private static class Skills_RaiseSkill_Milestone_Patch
		{
			[HarmonyPostfix]
			private static void Postfix(Skills __instance, SkillType skillType)
			{
				//IL_0025: Unknown result type (might be due to invalid IL or missing references)
				//IL_0032: Unknown result type (might be due to invalid IL or missing references)
				//IL_0044: Unknown result type (might be due to invalid IL or missing references)
				Player localPlayer = Player.m_localPlayer;
				if (!((Object)(object)localPlayer == (Object)null) && !((Object)(object)((Character)localPlayer).GetSkills() != (Object)(object)__instance) && !SkillsReworkedCompat.OwnsProgression(skillType))
				{
					Skill skill = __instance.GetSkill(skillType);
					if (skill != null)
					{
						RefreshMilestone(localPlayer, skillType, skill.m_level);
					}
				}
			}
		}

		[HarmonyPatch(typeof(Player), "Load")]
		private static class PlayerLoadMilestonesPatch
		{
			[HarmonyPostfix]
			private static void Postfix(Player __instance)
			{
				if (SkillRuntime.IsLocal(__instance))
				{
					RefreshAllMilestones(__instance);
				}
			}
		}

		[HarmonyPatch(typeof(Skills), "LowerAllSkills", new Type[] { typeof(float) })]
		private static class Skills_LowerAllSkills_Floors_Patch
		{
			[HarmonyPostfix]
			[HarmonyPriority(0)]
			private static void Postfix(Skills __instance)
			{
				//IL_0075: Unknown result type (might be due to invalid IL or missing references)
				//IL_007a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0092: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
				//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
				ExtraSkillsConfig settings = BesRuntime.Settings;
				if (settings == null || !settings.SkillFloorsEnabled.Value)
				{
					return;
				}
				Player localPlayer = Player.m_localPlayer;
				if ((Object)(object)localPlayer == (Object)null || (Object)(object)((Character)localPlayer).GetSkills() != (Object)(object)__instance || __instance.m_skillData == null)
				{
					return;
				}
				foreach (KeyValuePair<SkillType, Skill> skillDatum in __instance.m_skillData)
				{
					SkillType key = skillDatum.Key;
					Skill value = skillDatum.Value;
					if (value != null && !SkillsReworkedCompat.OwnsProgression(key))
					{
						RefreshMilestone(localPlayer, key, value.m_level);
						int num = GetUnlockedFloor(localPlayer, key);
						if (settings.MasteredSkillProtection.Value && num >= 75)
						{
							num = 100;
						}
						if (value.m_level < (float)num)
						{
							value.m_level = num;
						}
					}
				}
			}
		}

		private const string Prefix = "BES_FLOOR_";

		private static readonly FieldInfo PlayerCustomDataField = AccessTools.Field(typeof(Player), "m_customData");

		internal static int GetUnlockedFloor(Player player, SkillType type)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Expected I4, but got Unknown
			if ((Object)(object)player == (Object)null)
			{
				return -100;
			}
			IDictionary customData = GetCustomData(player);
			if (customData == null)
			{
				return -100;
			}
			object obj = customData["BES_FLOOR_" + ((int)type).ToString(CultureInfo.InvariantCulture)];
			int result;
			return (obj != null && int.TryParse(obj.ToString(), out result)) ? result : (-100);
		}

		internal static void RefreshMilestone(Player player, SkillType type, float level)
		{
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Expected I4, but got Unknown
			ExtraSkillsConfig settings = BesRuntime.Settings;
			if (settings == null || !settings.SkillFloorsEnabled.Value || (Object)(object)player == (Object)null)
			{
				return;
			}
			int num = -100;
			if (level >= 100f)
			{
				num = 75;
			}
			else if (level >= 75f)
			{
				num = 50;
			}
			else if (level >= 50f)
			{
				num = 25;
			}
			else
			{
				if (!(level >= 25f))
				{
					return;
				}
				num = 0;
			}
			int unlockedFloor = GetUnlockedFloor(player, type);
			if (num > unlockedFloor)
			{
				IDictionary customData = GetCustomData(player);
				if (customData != null)
				{
					customData["BES_FLOOR_" + ((int)type).ToString(CultureInfo.InvariantCulture)] = num.ToString(CultureInfo.InvariantCulture);
				}
			}
		}

		internal static void RefreshAllMilestones(Player player)
		{
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			ExtraSkillsConfig settings = BesRuntime.Settings;
			if (settings == null || !settings.SkillFloorsEnabled.Value || (Object)(object)player == (Object)null)
			{
				return;
			}
			Skills skills = ((Character)player).GetSkills();
			if ((Object)(object)skills == (Object)null || skills.m_skillData == null)
			{
				return;
			}
			foreach (KeyValuePair<SkillType, Skill> skillDatum in skills.m_skillData)
			{
				if (skillDatum.Value != null && !SkillsReworkedCompat.OwnsProgression(skillDatum.Key))
				{
					RefreshMilestone(player, skillDatum.Key, skillDatum.Value.m_level);
				}
			}
		}

		private static IDictionary GetCustomData(Player player)
		{
			try
			{
				return (PlayerCustomDataField != null) ? (PlayerCustomDataField.GetValue(player) as IDictionary) : null;
			}
			catch
			{
				return null;
			}
		}
	}
	internal static class SkillRuntime
	{
		private struct LocalLevelCacheEntry
		{
			internal Player Player;

			internal float ExpiresAt;

			internal float Level;
		}

		private const float LocalLevelCacheSeconds = 0.15f;

		private static readonly Dictionary<SkillType, LocalLevelCacheEntry> LocalLevelCache = new Dictionary<SkillType, LocalLevelCacheEntry>();

		internal static float GetLevel(Player player, SkillType type, bool signed = true)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Invalid comparison between Unknown and I4
			//IL_0021: 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_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)player == (Object)null || (int)type == 0)
			{
				return 0f;
			}
			if (BalrondSkillSystem.IsCustomSkill(type) && !BalrondSkillSystem.IsSkillEnabled(type))
			{
				return 0f;
			}
			bool flag = IsLocal(player);
			if (flag && TryGetCachedLevel(player, type, out var level))
			{
				return signed ? Mathf.Clamp(level, -100f, 100f) : Mathf.Clamp(level, 0f, 100f);
			}
			Skills skills = ((Character)player).GetSkills();
			if ((Object)(object)skills == (Object)null)
			{
				return 0f;
			}
			if (!SkillsReworkedCompat.IsManaged(type) || !SkillsReworkedCompat.TryGetEffectiveSkillLevel(player, type, out level))
			{
				try
				{
					level = skills.GetSkillLevel(type);
				}
				catch
				{
					return 0f;
				}
			}
			level = SafeFinite(level);
			if (flag)
			{
				LocalLevelCache[type] = new LocalLevelCacheEntry
				{
					Player = player,
					ExpiresAt = Time.unscaledTime + 0.15f,
					Level = level
				};
			}
			if (!signed)
			{
				return Mathf.Clamp(level, 0f, 100f);
			}
			return Mathf.Clamp(level, -100f, 100f);
		}

		private static bool TryGetCachedLevel(Player player, SkillType type, out float level)
		{
			//IL_000d: 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)
			level = 0f;
			if (!LocalLevelCache.TryGetValue(type, out var value))
			{
				return false;
			}
			if ((Object)(object)value.Player != (Object)(object)player || Time.unscaledTime >= value.ExpiresAt)
			{
				LocalLevelCache.Remove(type);
				return false;
			}
			level = value.Level;
			return true;
		}

		internal static void InvalidateLevelCache(SkillType type)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			LocalLevelCache.Remove(type);
		}

		internal static void InvalidateAllLevelCache()
		{
			LocalLevelCache.Clear();
		}

		internal static float SignedFactor(Player player, SkillType type)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			return Mathf.Clamp(GetLevel(player, type) / 100f, -1f, 1f);
		}

		internal static float SignedFactor(float level)
		{
			return Mathf.Clamp(level / 100f, -1f, 1f);
		}

		internal static float PositiveFactor(Player player, SkillType type)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			return Mathf.Clamp01(GetLevel(player, type, signed: false) / 100f);
		}

		internal static bool IsLocal(Player player)
		{
			return (Object)(object)player != (Object)null && (Object)(object)player == (Object)(object)Player.m_localPlayer;
		}

		internal static float SafeFinite(float value, float fallback = 0f)
		{
			return (float.IsNaN(value) || float.IsInfinity(value)) ? fallback : value;
		}
	}
	internal static class SkillXpRouter
	{
		[HarmonyPatch(typeof(Skills), "RaiseSkill")]
		private static class Skills_RaiseSkill_GlobalMultiplier_Patch
		{
			[HarmonyPrefix]
			private static bool Prefix(SkillType skillType, ref float factor)
			{
				//IL_0018: 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_0033: 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_009b: Unknown result type (might be due to invalid IL or missing references)
				if (factor <= 0f)
				{
					return true;
				}
				if (BalrondSkillSystem.IsCustomSkill(skillType))
				{
					if (BalrondSkillSystem.IsCollisionDisabled(skillType))
					{
						return true;
					}
					if (!BalrondSkillSystem.IsSkillEnabled(skillType))
					{
						return false;
					}
					return true;
				}
				if (s_internalRaise)
				{
					return true;
				}
				ExtraSkillsConfig settings = BesRuntime.Settings;
				if (settings == null)
				{
					return true;
				}
				if (SkillsReworkedCompat.OwnsProgression(skillType))
				{
					return true;
				}
				factor *= Mathf.Max(0f, settings.GlobalXpMultiplier.Value) * Mathf.Max(0f, settings.GetXpMultiplier(skillType));
				return true;
			}

			[HarmonyPostfix]
			private static void Postfix(SkillType skillType)
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				SkillRuntime.InvalidateLevelCache(skillType);
				TotalLevelService.Invalidate();
				ResourceCapacityBonus.Invalidate();
			}
		}

		[ThreadStatic]
		private static bool s_internalRaise;

		internal unsafe static void Raise(Player player, SkillType type, float amount, string source = null)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Invalid comparison between Unknown and I4
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			if (!SkillRuntime.IsLocal(player) || amount <= 0f || (int)type == 0 || (BalrondSkillSystem.IsCustomSkill(type) && !BalrondSkillSystem.IsSkillEnabled(type)))
			{
				return;
			}
			ExtraSkillsConfig settings = BesRuntime.Settings;
			float num = ((settings != null) ? Mathf.Max(0f, settings.GlobalXpMultiplier.Value) : 1f);
			float num2 = ((settings != null) ? Mathf.Max(0f, settings.GetXpMultiplier(type)) : 1f);
			amount *= num * num2;
			if (amount <= 0f || float.IsNaN(amount) || float.IsInfinity(amount))
			{
				return;
			}
			Skills skills = ((Character)player).GetSkills();
			if (!((Object)(object)skills == (Object)null))
			{
				s_internalRaise = true;
				try
				{
					skills.RaiseSkill(type, amount);
				}
				finally
				{
					s_internalRaise = false;
				}
				if (settings != null && settings.LogSkillXpEvents.Value && BesRuntime.Log != null)
				{
					bool flag = SkillsReworkedCompat.IsManaged(type);
					BesRuntime.Log.LogInfo((object)((flag ? "[BES XP->SR RaiseSkill] " : "[BES XP] ") + ((object)(*(SkillType*)(&type))/*cast due to .constrained prefix*/).ToString() + " +" + amount.ToString("0.###") + " source=" + (source ?? "unknown")));
				}
			}
		}
	}
	internal enum TotalLevelProviderMode
	{
		Auto,
		NativeSkills,
		SkillsReworked
	}
	internal struct TotalLevelSnapshot
	{
		internal float ContinuousLevel;

		internal int WholeLevel;

		internal float Progress01;

		internal int SkillCount;

		internal bool SkillsReworkedPrimary;

		internal float SecondarySkillAverage;
	}
	internal static class TotalLevelService
	{
		private const float SnapshotCacheSeconds = 0.5f;

		private static readonly HashSet<SkillType> Seen = new HashSet<SkillType>();

		private static Player s_cachedPlayer;

		private static float s_cacheExpiresAt;

		private static TotalLevelSnapshot s_cachedSnapshot;

		internal static void Invalidate()
		{
			s_cachedPlayer = null;
			s_cacheExpiresAt = 0f;
		}

		internal static TotalLevelSnapshot Get(Player player)
		{
			if ((Object)(object)player != (Object)null && (Object)(object)s_cachedPlayer == (Object)(object)player && Time.unscaledTime < s_cacheExpiresAt)
			{
				return s_cachedSnapshot;
			}
			TotalLevelSnapshot native = GetNative(player);
			if ((Object)(object)player == (Object)null)
			{
				return native;
			}
			TotalLevelProviderMode totalLevelProviderMode = ((BesRuntime.Settings != null) ? BesRuntime.Settings.TotalLevelProvider.Value : TotalLevelProviderMode.Auto);
			if ((totalLevelProviderMode == TotalLevelProviderMode.SkillsReworked || (totalLevelProviderMode == TotalLevelProviderMode.Auto && SkillsReworkedCompat.IsActive)) && SkillsReworkedCompat.TryGetCharacterProgress(player, out var level, out var progress))
			{
				TotalLevelSnapshot totalLevelSnapshot = new TotalLevelSnapshot
				{
					ContinuousLevel = level + Mathf.Clamp01(progress),
					WholeLevel = Mathf.FloorToInt(level),
					Progress01 = Mathf.Clamp01(progress),
					SkillCount = native.SkillCount,
					SkillsReworkedPrimary = true,
					SecondarySkillAverage = native.ContinuousLevel
				};
				Cache(player, totalLevelSnapshot);
				return totalLevelSnapshot;
			}
			Cache(player, native);
			return native;
		}

		internal static TotalLevelSnapshot GetNative(Player player)
		{
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			TotalLevelSnapshot result = default(TotalLevelSnapshot);
			if ((Object)(object)player == (Object)null)
			{
				return result;
			}
			Skills skills = ((Character)player).GetSkills();
			if ((Object)(object)skills == (Object)null || skills.m_skills == null)
			{
				return result;
			}
			Seen.Clear();
			double num = 0.0;
			int num2 = 0;
			for (int i = 0; i < skills.m_skills.Count; i++)
			{
				SkillDef val = skills.m_skills[i];
				if (val == null)
				{
					continue;
				}
				SkillType skill = val.m_skill;
				if (!IsEligible(skill) || !Seen.Add(skill))
				{
					continue;
				}
				Skill skill2;
				try
				{
					skill2 = skills.GetSkill(skill);
				}
				catch
				{
					continue;
				}
				if (skill2 == null)
				{
					continue;
				}
				float num3 = 0f;
				float num4;
				if (SkillsReworkedCompat.IsActive && SkillsReworkedCompat.IsManaged(skill) && SkillsReworkedCompat.TryGetEffectiveSkillLevel(player, skill, out var level))
				{
					num4 = Mathf.Clamp(level, 0f, 100f);
					num3 = 0f;
				}
				else
				{
					num4 = Mathf.Clamp(skill2.m_level, -100f, 100f);
					try
					{
						num3 = Mathf.Clamp01(skill2.GetLevelPercentage());
					}
					catch
					{
						num3 = 0f;
					}
				}
				float num5 = num4 + num3;
				if (num4 >= 100f)
				{
					num5 = 100f;
				}
				num += (double)num5;
				num2++;
			}
			float num6 = ((num2 > 0) ? ((float)(num / (double)num2)) : 0f);
			int num7 = Mathf.FloorToInt(num6);
			float num8 = num6 - (float)num7;
			if (num8 < 0f)
			{
				num8 += 1f;
			}
			result.ContinuousLevel = num6;
			result.WholeLevel = num7;
			result.Progress01 = Mathf.Clamp01(num8);
			result.SkillCount = num2;
			result.SkillsReworkedPrimary = false;
			result.SecondarySkillAverage = num6;
			return result;
		}

		private static void Cache(Player player, TotalLevelSnapshot snapshot)
		{
			s_cachedPlayer = player;
			s_cachedSnapshot = snapshot;
			s_cacheExpiresAt = Time.unscaledTime + 0.5f;
		}

		private static bool IsEligible(SkillType type)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Invalid comparison between Unknown and I4
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			if ((int)type == 0 || (int)type == 999)
			{
				return false;
			}
			if (SkillsReworkedCompat.IsVirtualSkill(type))
			{
				return false;
			}
			if (BalrondSkillSystem.IsCustomSkill(type) && !BalrondSkillSystem.IsSkillEnabled(type))
			{
				return false;
			}
			ExtraSkillsConfig settings = BesRuntime.Settings;
			return settings == null || !settings.IsExcludedFromTotalLevel(type);
		}
	}
	internal static class VanillaSkillTypes
	{
		internal static readonly SkillType Fists = Resolve("Fists", "Unarmed");

		private static SkillType Resolve(params string[] names)
		{
			//IL_0046: 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_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			for (int i = 0; i < names.Length; i++)
			{
				try
				{
					object obj = Enum.Parse(typeof(SkillType), names[i], ignoreCase: true);
					if (obj != null)
					{
						return (SkillType)obj;
					}
				}
				catch
				{
				}
			}
			return (SkillType)0;
		}
	}
	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);
			}
		}

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