Decompiled source of FortifySkillsRedux v1.3.0

FortifySkillsRedux.dll

Decompiled 2 weeks ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using FortifySkillsRedux.Configs;
using FortifySkillsRedux.Extensions;
using HarmonyLib;
using Jotunn.Utils;
using TMPro;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("FortifySkillsRedux")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("FortifySkillsRedux")]
[assembly: AssemblyCopyright("Copyright ©  2023")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("b17a1148-6db3-4f0b-9e79-d760d18acf4d")]
[assembly: AssemblyFileVersion("1.3.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.3.0.0")]
[module: UnverifiableCode]
namespace FortifySkillsRedux
{
	internal class FortifySkillData
	{
		public static Dictionary<SkillType, FortifySkillData> s_FortifySkillValues = new Dictionary<SkillType, FortifySkillData>();

		public static Player s_AssociatedPlayer;

		public float FortifyLevel;

		public float FortifyAccumulator;

		public SkillDef Info;

		public string SkillName => GetLocalizedSkillName(this);

		public static bool IsSkillValid(SkillType skillType)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Invalid comparison between Unknown and I4
			if (Skills.IsSkillValid(skillType) && (int)skillType != 0)
			{
				return (int)skillType != 999;
			}
			return false;
		}

		public FortifySkillData(SkillDef skillDef)
		{
			FortifyAccumulator = 0f;
			FortifyLevel = 0f;
			Info = skillDef;
		}

		public FortifySkillData(SkillDef skillDef, float newLevel, float newAccumulator)
		{
			FortifyAccumulator = newAccumulator;
			FortifyLevel = newLevel;
			Info = skillDef;
		}

		public static void ResetFortifySkill(SkillType skillType)
		{
			//IL_0005: 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_0027: Unknown result type (might be due to invalid IL or missing references)
			if (s_FortifySkillValues.ContainsKey(skillType))
			{
				s_FortifySkillValues[skillType].FortifyLevel = 0f;
				s_FortifySkillValues[skillType].FortifyAccumulator = 0f;
			}
		}

		public static SkillType MapDummySkill(SkillType skillType)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			return (SkillType)(int.MaxValue - skillType);
		}

		public static string GetLocalizedSkillName(Skill skill)
		{
			return "$skill_" + ((object)(SkillType)(ref skill.m_info.m_skill)).ToString().ToLower();
		}

		public static string GetLocalizedSkillName(FortifySkillData fortSkill)
		{
			return "$skill_" + ((object)(SkillType)(ref fortSkill.Info.m_skill)).ToString().ToLower();
		}

		public static string LocalizeSkillName(SkillType skillType)
		{
			return "$skill_" + ((object)(SkillType)(ref skillType)).ToString().ToLower();
		}
	}
	[BepInPlugin("Searica.Valheim.FortifySkillsRedux", "FortifySkillsRedux", "1.3.0")]
	[BepInDependency("com.jotunn.jotunn", "2.21.3")]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	internal sealed class FortifySkillsRedux : BaseUnityPlugin
	{
		internal class SkillConfig
		{
			public ConfigEntry<float> XPMult;

			public ConfigEntry<float> FortifyLevelRate;
		}

		public const string PluginName = "FortifySkillsRedux";

		internal const string Author = "Searica";

		public const string PluginGUID = "Searica.Valheim.FortifySkillsRedux";

		public const string PluginVersion = "1.3.0";

		private static readonly string MainSection = ConfigManager.SetStringPriority("Global", 3);

		private static readonly string Mechanics = ConfigManager.SetStringPriority("Mechanics", 2);

		private static readonly string ModdedSkills = "Modded Skill Settings";

		internal static Dictionary<SkillType, SkillConfig> SkillConfigsMap = new Dictionary<SkillType, SkillConfig>();

		private static bool ShouldSave = false;

		internal static ConfigEntry<float> XPMult { get; private set; }

		internal static ConfigEntry<float> FortifyLevelRate { get; private set; }

		internal static ConfigEntry<float> FortifyXPRateMax { get; private set; }

		internal static ConfigEntry<bool> EnableIndividualSettings { get; private set; }

		internal static ConfigEntry<float> ModdedSkillXPMult { get; private set; }

		internal static ConfigEntry<float> ModdedSkillFortifyRate { get; private set; }

		public void Awake()
		{
			Log.Init(((BaseUnityPlugin)this).Logger);
			ConfigManager.Init("Searica.Valheim.FortifySkillsRedux", ((BaseUnityPlugin)this).Config);
			SetUpConfigEntries();
			Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), "Searica.Valheim.FortifySkillsRedux");
			Game.isModded = true;
			ConfigManager.SetupWatcher();
			ConfigManager.CheckForConfigManager();
			ConfigManager.OnConfigWindowClosed += delegate
			{
				if (ShouldSave)
				{
					ConfigManager.Save();
					ShouldSave = false;
				}
			};
		}

		public void OnDestroy()
		{
			ConfigManager.Save();
		}

		internal static void SetUpConfigEntries()
		{
			//IL_01be: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cb: Invalid comparison between Unknown and I4
			//IL_02d6: Unknown result type (might be due to invalid IL or missing references)
			Log.Verbosity = ConfigManager.BindConfig(MainSection, "Verbosity", LogLevel.Low, "Low will log basic information about the mod. Medium will log information that is useful for troubleshooting. High will log a lot of information, do not set it to this without good reason as it will slow down your game.", null, synced: false);
			Log.Verbosity.SettingChanged += delegate
			{
				if (!ShouldSave)
				{
					ShouldSave = true;
				}
			};
			EnableIndividualSettings = ConfigManager.BindConfig(MainSection, "IndividualSettings", value: false, "Used to toggle whether the XPMult value from the Mechanics section is used for all skills or if the XPMult values from the IndividualSKills section are used for each vanilla skill.");
			EnableIndividualSettings.SettingChanged += delegate
			{
				if (!ShouldSave)
				{
					ShouldSave = true;
				}
			};
			XPMult = ConfigManager.BindConfig(Mechanics, "XPMult", 1.5f, "Used to control the rate at which the active level increases, 1 = base game, 1.5 = 50% bonus xp awarded, 0.8 = 20% less xp awarded.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10f));
			XPMult.SettingChanged += delegate
			{
				if (!ShouldSave)
				{
					ShouldSave = true;
				}
			};
			FortifyLevelRate = ConfigManager.BindConfig(Mechanics, "FortifyXPPerLevelRate", 0.1f, "Used to control the rate at which the fortified skill XP increases PER LEVEL behind the active level. 0.1 = Will gain 10% XP for every level behind the active level. Note that this is a percentage of the XP earned towards the active skill before any XP multipliers have been applied.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f));
			FortifyLevelRate.SettingChanged += delegate
			{
				if (!ShouldSave)
				{
					ShouldSave = true;
				}
			};
			FortifyXPRateMax = ConfigManager.BindConfig(Mechanics, "FortifyXPRateMax", 0.8f, "Used to control the maximum rate of XP earned for the fortified skill. Caps FortifyXPPerLevelRate. Values less than 1 mean the fortify skill will always increase more slowly than the active level. 0.8 = Will gain a max of 80% of the XP gained for the active skill.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 2f));
			FortifyXPRateMax.SettingChanged += delegate
			{
				if (!ShouldSave)
				{
					ShouldSave = true;
				}
			};
			Log.LogInfo($"{Skills.s_allSkills.Count()} SkillTypes are defined in base game.", LogLevel.Medium);
			SkillType[] s_allSkills = Skills.s_allSkills;
			for (int i = 0; i < s_allSkills.Length; i++)
			{
				SkillType val = s_allSkills[i];
				if ((int)val == 0 || (int)val == 999)
				{
					continue;
				}
				string text = ((object)(SkillType)(ref val)).ToString();
				if (text == null)
				{
					continue;
				}
				Log.LogInfo("Adding " + text + " to config.", LogLevel.Medium);
				SkillConfig skillConfig = new SkillConfig();
				skillConfig.XPMult = ConfigManager.BindConfig(ConfigManager.SetStringPriority(text, 1), "XPMult", 1.5f, "XP Multiplier for " + text + " skill. Only used if IndividualSettings is set to true", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10f));
				skillConfig.FortifyLevelRate = ConfigManager.BindConfig(ConfigManager.SetStringPriority(text, 1), "FortifyXPPerLevelRate", 0.1f, "Used to control the rate at which the fortified skill XP increases PER LEVEL behind the active level for " + text + ". 0.1 = Will gain 10% XP for every level behind the active level. Note that this is a percentage of the XP earned towards the active skill before any XP multipliers have been applied. Only used if IndividualSettings is set to true.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f));
				skillConfig.XPMult.SettingChanged += delegate
				{
					if (!ShouldSave)
					{
						ShouldSave = true;
					}
				};
				skillConfig.FortifyLevelRate.SettingChanged += delegate
				{
					if (!ShouldSave)
					{
						ShouldSave = true;
					}
				};
				SkillConfigsMap.Add(val, skillConfig);
			}
			ModdedSkillXPMult = ConfigManager.BindConfig(ModdedSkills, "XPMult", 1f, "XP Multiplier for skills added by mods (default value is 1.0 since most skill mods have their own XP multiplier settings). Only used if IndividualSettings is set to true.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10f));
			ModdedSkillFortifyRate = ConfigManager.BindConfig(ModdedSkills, "FortifyXPPerLevelRate", 0.1f, "Used to control the rate at which the fortified skill XP increases PER LEVEL behind the active level. 0.1 = Will gain 10% XP for every level behind the active level. Note that this is a percentage of the XP earned towards the active skill before any XP multipliers have been applied. Only used if IndividualSettings is set to true.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f));
			ModdedSkillXPMult.SettingChanged += delegate
			{
				if (!ShouldSave)
				{
					ShouldSave = true;
				}
			};
			ModdedSkillFortifyRate.SettingChanged += delegate
			{
				if (!ShouldSave)
				{
					ShouldSave = true;
				}
			};
			ConfigManager.Save();
		}

		internal static float GetXPMult(Skill skill)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: 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)
			if (EnableIndividualSettings.Value)
			{
				SkillType skill2 = skill.m_info.m_skill;
				if (SkillConfigsMap.ContainsKey(skill2))
				{
					return SkillConfigsMap[skill2].XPMult.Value;
				}
				return ModdedSkillXPMult.Value;
			}
			return XPMult.Value;
		}

		internal static float GetFortifyRate(Skill skill)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: 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)
			if (EnableIndividualSettings.Value)
			{
				SkillType skill2 = skill.m_info.m_skill;
				if (SkillConfigsMap.ContainsKey(skill2))
				{
					return SkillConfigsMap[skill2].FortifyLevelRate.Value;
				}
				return ModdedSkillFortifyRate.Value;
			}
			return FortifyLevelRate.Value;
		}
	}
	internal enum LogLevel
	{
		Low,
		Medium,
		High
	}
	internal static class Log
	{
		private static ManualLogSource logSource;

		internal static ConfigEntry<LogLevel> Verbosity { get; set; }

		internal static LogLevel VerbosityLevel => Verbosity.Value;

		internal static bool IsVerbosityLow => Verbosity.Value >= LogLevel.Low;

		internal static bool IsVerbosityMedium => Verbosity.Value >= LogLevel.Medium;

		internal static bool IsVerbosityHigh => Verbosity.Value >= LogLevel.High;

		internal static void Init(ManualLogSource logSource)
		{
			Log.logSource = logSource;
		}

		internal static void LogDebug(object data)
		{
			logSource.LogDebug(data);
		}

		internal static void LogError(object data)
		{
			logSource.LogError(data);
		}

		internal static void LogFatal(object data)
		{
			logSource.LogFatal(data);
		}

		internal static void LogMessage(object data)
		{
			logSource.LogMessage(data);
		}

		internal static void LogWarning(object data)
		{
			logSource.LogWarning(data);
		}

		internal static void LogInfo(object data, LogLevel level = LogLevel.Low)
		{
			if (Verbosity == null || VerbosityLevel >= level)
			{
				logSource.LogInfo(data);
			}
		}
	}
	[HarmonyPatch(typeof(SkillsDialog))]
	public static class SkillsDialogPatch
	{
		[HarmonyPostfix]
		[HarmonyPatch("Setup")]
		private static void SkillsDialogSetupPostfix(SkillsDialog __instance, Player player)
		{
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: 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)
			Log.LogInfo("SkillsDialog.Setup.Postfix()", LogLevel.Medium);
			List<Skill> skillList = ((Character)player).GetSkills().GetSkillList();
			foreach (GameObject element in __instance.m_elements)
			{
				string text = element.GetComponentInChildren<UITooltip>().m_text;
				foreach (Skill item in skillList)
				{
					if (item.m_info.m_description == text)
					{
						if (FortifySkillData.s_FortifySkillValues.ContainsKey(item.m_info.m_skill))
						{
							string text2 = $" ({(int)FortifySkillData.s_FortifySkillValues[item.m_info.m_skill].FortifyLevel})";
							TMP_Text component = ((Component)Utils.FindChild(element.transform, "leveltext", (IterativeSearchType)0)).GetComponent<TMP_Text>();
							component.text += text2;
						}
						else
						{
							Log.LogInfo($"No Fortified skill for: {item.m_info.m_skill}", LogLevel.Medium);
						}
						break;
					}
				}
			}
		}
	}
	[HarmonyPatch(typeof(Skills))]
	public static class SkillsPatch
	{
		[HarmonyPrefix]
		[HarmonyPatch("Load")]
		private static void LoadPrefix(Skills __instance, ZPackage pkg)
		{
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: 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_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: 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_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_016d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: 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)
			Log.LogInfo("Skills.Load.Prefix()", LogLevel.Medium);
			int pos = pkg.GetPos();
			FortifySkillData.s_FortifySkillValues.Clear();
			FortifySkillData.s_AssociatedPlayer = __instance.m_player;
			int num = pkg.ReadInt();
			int num2 = pkg.ReadInt();
			for (int i = 0; i < num2; i++)
			{
				SkillType val = (SkillType)pkg.ReadInt();
				float num3 = pkg.ReadSingle();
				float newAccumulator = ((num >= 2) ? pkg.ReadSingle() : 0f);
				if (FortifySkillData.IsSkillValid(val))
				{
					Skill skill = __instance.GetSkill(val);
					if (skill?.m_info != null && !FortifySkillData.s_FortifySkillValues.ContainsKey(val))
					{
						Log.LogInfo("Fortify Skill initialized for: " + FortifySkillData.LocalizeSkillName(val) + " a.k.a " + skill.m_info?.m_description, LogLevel.Medium);
						FortifySkillData.s_FortifySkillValues[val] = new FortifySkillData(skill.m_info, num3 * 0.95f, 0f);
					}
					continue;
				}
				SkillType val2 = FortifySkillData.MapDummySkill(val);
				if (!FortifySkillData.IsSkillValid(val2))
				{
					Log.LogInfo("Unrecognized Fortify skill!", LogLevel.Medium);
					continue;
				}
				Skill skill2 = __instance.GetSkill(val2);
				if (skill2?.m_info != null)
				{
					if (Log.VerbosityLevel >= LogLevel.Medium)
					{
						string arg = FortifySkillData.LocalizeSkillName(val2);
						Log.LogInfo($"Fortify Skill mapped to: {arg} a.k.a {skill2.m_info?.m_description} @: {num3}");
					}
					FortifySkillData.s_FortifySkillValues[val2] = new FortifySkillData(skill2.m_info, num3, newAccumulator);
				}
			}
			pkg.SetPos(pos);
		}

		[HarmonyPrefix]
		[HarmonyPriority(700)]
		[HarmonyPatch("Save")]
		private static void SavePrefix(Skills __instance, out Dictionary<SkillType, Skill> __state)
		{
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Unknown result type (might be due to invalid IL or missing references)
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_0145: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_016f: Expected O, but got Unknown
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			//IL_0176: Unknown result type (might be due to invalid IL or missing references)
			//IL_0188: Unknown result type (might be due to invalid IL or missing references)
			//IL_019c: Expected O, but got Unknown
			//IL_01a4: Unknown result type (might be due to invalid IL or missing references)
			Log.LogInfo("Skills.Save.Prefix()", LogLevel.Medium);
			if ((Object)(object)FortifySkillData.s_AssociatedPlayer != (Object)(object)__instance.m_player)
			{
				__state = null;
				Log.LogInfo("New character: skip saving Fortified Skill data", LogLevel.Medium);
				return;
			}
			__state = new Dictionary<SkillType, Skill>();
			foreach (KeyValuePair<SkillType, Skill> skillDatum in __instance.m_skillData)
			{
				if (skillDatum.Value?.m_info != null)
				{
					Log.LogInfo("Copying " + FortifySkillData.LocalizeSkillName(skillDatum.Key) + " a.k.a " + skillDatum.Value.m_info.m_description, LogLevel.High);
					__state[skillDatum.Key] = skillDatum.Value;
				}
			}
			foreach (KeyValuePair<SkillType, FortifySkillData> s_FortifySkillValue in FortifySkillData.s_FortifySkillValues)
			{
				FortifySkillData value = s_FortifySkillValue.Value;
				if (value == null)
				{
					continue;
				}
				SkillDef info = value.Info;
				if (info != null)
				{
					_ = info.m_skill;
					if (0 == 0)
					{
						Log.LogInfo("Making dummy skill for " + FortifySkillData.LocalizeSkillName(s_FortifySkillValue.Key) + " a.k.a " + s_FortifySkillValue.Value.Info.m_description, LogLevel.High);
						SkillDef val = new SkillDef
						{
							m_skill = FortifySkillData.MapDummySkill(s_FortifySkillValue.Value.Info.m_skill),
							m_description = s_FortifySkillValue.Value.Info?.m_description
						};
						Skill value2 = new Skill(val)
						{
							m_accumulator = s_FortifySkillValue.Value.FortifyAccumulator,
							m_level = s_FortifySkillValue.Value.FortifyLevel
						};
						__instance.m_skillData[val.m_skill] = value2;
					}
				}
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch("Save")]
		private static void SavePostfix(Skills __instance, Dictionary<SkillType, Skill> __state)
		{
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			if (__state == null)
			{
				Log.LogInfo("No fortified skill data, skip removing dummy skills.", LogLevel.Medium);
				return;
			}
			Log.LogInfo("Reseting m_skillData to remove dummy skills.", LogLevel.Medium);
			__instance.m_skillData.Clear();
			foreach (KeyValuePair<SkillType, Skill> item in __state)
			{
				if (Log.VerbosityLevel >= LogLevel.High)
				{
					string text = FortifySkillData.LocalizeSkillName(item.Key);
					Log.LogInfo("Copying " + text + " a.k.a " + item.Value.m_info.m_description);
				}
				__instance.m_skillData[item.Key] = item.Value;
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch("ResetSkill")]
		private static void SkillResetSkill(SkillType skillType)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			FortifySkillData.ResetFortifySkill(skillType);
		}
	}
}
namespace FortifySkillsRedux.Patches
{
	[HarmonyPatch(typeof(Player))]
	internal static class PlayerPatch
	{
		[HarmonyPrefix]
		[HarmonyPatch("ResetCharacter")]
		internal static void ResetFortifySkills(Player __instance)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			foreach (SkillDef skill in __instance.m_skills.m_skills)
			{
				if (FortifySkillData.s_FortifySkillValues.ContainsKey(skill.m_skill))
				{
					FortifySkillData.ResetFortifySkill(skill.m_skill);
				}
			}
		}

		[HarmonyPrefix]
		[HarmonyPriority(0)]
		[HarmonyPatch("OnDeath")]
		private static void OnDeath()
		{
			if (ZoneSystem.instance.GetGlobalKey((GlobalKeys)17))
			{
				ZoneSystem.instance.m_globalKeysEnums.Remove((GlobalKeys)17);
			}
		}

		[HarmonyFinalizer]
		[HarmonyPriority(100)]
		[HarmonyPatch("OnDeath")]
		private static void OnDeathFinalizer(Player __instance)
		{
			//IL_0043: 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)
			Log.LogInfo("Finalizing skills on death", LogLevel.Medium);
			if (!Object.op_Implicit((Object)(object)__instance) || !Object.op_Implicit((Object)(object)__instance.m_skills))
			{
				return;
			}
			foreach (KeyValuePair<SkillType, Skill> skillDatum in __instance.m_skills.m_skillData)
			{
				if (FortifySkillData.s_FortifySkillValues.ContainsKey(skillDatum.Key))
				{
					FortifySkillData fortifySkillData = FortifySkillData.s_FortifySkillValues[skillDatum.Key];
					Log.LogInfo($"Setting {fortifySkillData.SkillName} to fortify level: {fortifySkillData.FortifyLevel}", LogLevel.Medium);
					skillDatum.Value.m_level = fortifySkillData.FortifyLevel;
					skillDatum.Value.m_accumulator = 0f;
				}
			}
		}
	}
	[HarmonyPatch(typeof(Skill))]
	public static class SkillPatch
	{
		[HarmonyPrefix]
		[HarmonyPriority(700)]
		[HarmonyPatch("Raise")]
		private static void RaiseFortifySkill(Skill __instance, ref float factor)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			Log.LogInfo("Raising XP for Fortified skill", LogLevel.Medium);
			float num = __instance.m_info.m_increseStep * factor;
			FortifySkillData fortifySkillData;
			if (FortifySkillData.s_FortifySkillValues.ContainsKey(__instance.m_info.m_skill))
			{
				fortifySkillData = FortifySkillData.s_FortifySkillValues[__instance.m_info.m_skill];
			}
			else
			{
				fortifySkillData = new FortifySkillData(__instance.m_info, __instance.m_level, 0f);
				FortifySkillData.s_FortifySkillValues[__instance.m_info.m_skill] = fortifySkillData;
			}
			if (!(fortifySkillData.FortifyLevel >= 100f))
			{
				fortifySkillData.FortifyAccumulator += num * Mathf.Clamp((__instance.m_level - fortifySkillData.FortifyLevel) * FortifySkillsRedux.GetFortifyRate(__instance), 0f, FortifySkillsRedux.FortifyXPRateMax.Value);
				Log.LogInfo("Fortify XP:" + fortifySkillData.FortifyAccumulator, LogLevel.Medium);
				if (fortifySkillData.FortifyAccumulator >= GetLevelUpXpRequirement(fortifySkillData.FortifyLevel))
				{
					LevelUpFortifySkill(fortifySkillData);
				}
			}
		}

		private static void LevelUpFortifySkill(FortifySkillData fortifySkill)
		{
			//IL_000d: 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_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			MessageType val = (MessageType)(((int)fortifySkill.FortifyLevel != 0) ? 1 : 2);
			fortifySkill.FortifyLevel = Mathf.Clamp(fortifySkill.FortifyLevel + 1f, 0f, 100f);
			fortifySkill.FortifyAccumulator = 0f;
			Log.LogInfo("Fortify level:" + fortifySkill.FortifyLevel, LogLevel.Medium);
			Player localPlayer = Player.m_localPlayer;
			GameObject prefab = ZNetScene.instance.GetPrefab("vfx_ColdBall_launch");
			GameObject prefab2 = localPlayer.m_skillLevelupEffects.m_effectPrefabs[1].m_prefab;
			Object.Instantiate<GameObject>(prefab, ((Character)localPlayer).GetHeadPoint(), Quaternion.Euler(-90f, 0f, 0f));
			Object.Instantiate<GameObject>(prefab2, ((Character)localPlayer).GetHeadPoint(), Quaternion.identity);
			((Character)localPlayer).Message(val, $"Fortified skill improved {fortifySkill.SkillName}: {(int)fortifySkill.FortifyLevel}", 0, fortifySkill.Info.m_icon);
		}

		private static float GetLevelUpXpRequirement(float level)
		{
			return Mathf.Pow(level + 1f, 1.5f) * 0.5f + 0.5f;
		}

		[HarmonyPrefix]
		[HarmonyPriority(100)]
		[HarmonyPatch("Raise")]
		private static void ActiveSkillXpMultiplier(Skill __instance, ref float factor)
		{
			Log.LogInfo("Applying active skill XP multiplier", LogLevel.Medium);
			factor *= FortifySkillsRedux.GetXPMult(__instance);
		}
	}
}
namespace FortifySkillsRedux.Extensions
{
	internal static class EventExtensions
	{
		public static void SafeInvoke(this Action events)
		{
			if (events == null)
			{
				return;
			}
			Delegate[] invocationList = events.GetInvocationList();
			for (int i = 0; i < invocationList.Length; i++)
			{
				Action action = (Action)invocationList[i];
				try
				{
					action();
				}
				catch (Exception ex)
				{
					Log.LogWarning($"Exception thrown at event {new StackFrame(1).GetMethod().Name} in {action.Method.DeclaringType.Name}.{action.Method.Name}:\n{ex}");
				}
			}
		}

		public static void SafeInvoke<TArg1>(this Action<TArg1> events, TArg1 arg1)
		{
			if (events == null)
			{
				return;
			}
			Delegate[] invocationList = events.GetInvocationList();
			for (int i = 0; i < invocationList.Length; i++)
			{
				Action<TArg1> action = (Action<TArg1>)invocationList[i];
				try
				{
					action(arg1);
				}
				catch (Exception ex)
				{
					Log.LogWarning($"Exception thrown at event {new StackFrame(1).GetMethod().Name} in {action.Method.DeclaringType.Name}.{action.Method.Name}:\n{ex}");
				}
			}
		}

		public static void SafeInvoke<TArg1, TArg2>(this Action<TArg1, TArg2> events, TArg1 arg1, TArg2 arg2)
		{
			if (events == null)
			{
				return;
			}
			Delegate[] invocationList = events.GetInvocationList();
			for (int i = 0; i < invocationList.Length; i++)
			{
				Action<TArg1, TArg2> action = (Action<TArg1, TArg2>)invocationList[i];
				try
				{
					action(arg1, arg2);
				}
				catch (Exception ex)
				{
					Log.LogWarning($"Exception thrown at event {new StackFrame(1).GetMethod().Name} in {action.Method.DeclaringType.Name}.{action.Method.Name}:\n{ex}");
				}
			}
		}

		public static void SafeInvoke<TEventArg>(this EventHandler<TEventArg> events, object sender, TEventArg arg1)
		{
			if (events == null)
			{
				return;
			}
			Delegate[] invocationList = events.GetInvocationList();
			for (int i = 0; i < invocationList.Length; i++)
			{
				EventHandler<TEventArg> eventHandler = (EventHandler<TEventArg>)invocationList[i];
				try
				{
					eventHandler(sender, arg1);
				}
				catch (Exception ex)
				{
					Log.LogWarning($"Exception thrown at event {new StackFrame(1).GetMethod().Name} in {eventHandler.Method.DeclaringType.Name}.{eventHandler.Method.Name}:\n{ex}");
				}
			}
		}
	}
}
namespace FortifySkillsRedux.Configs
{
	internal static class ConfigManager
	{
		private static string ConfigFileName;

		private static string ConfigFileFullPath;

		private static ConfigFile configFile;

		private static BaseUnityPlugin ConfigurationManager;

		private const string ConfigManagerGUID = "com.bepis.bepinex.configurationmanager";

		private static readonly ConfigurationManagerAttributes AdminConfig = new ConfigurationManagerAttributes
		{
			IsAdminOnly = true
		};

		private static readonly ConfigurationManagerAttributes ClientConfig = new ConfigurationManagerAttributes
		{
			IsAdminOnly = false
		};

		private const char ZWS = '\u200b';

		internal static event Action OnConfigWindowClosed;

		internal static event Action OnConfigFileReloaded;

		private static void InvokeOnConfigWindowClosed()
		{
			ConfigManager.OnConfigWindowClosed?.SafeInvoke();
		}

		private static void InvokeOnConfigFileReloaded()
		{
			ConfigManager.OnConfigFileReloaded?.SafeInvoke();
		}

		internal static ConfigEntry<T> BindConfig<T>(string section, string name, T value, string description, AcceptableValueBase acceptVals = null, bool synced = true)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Expected O, but got Unknown
			string extendedDescription = GetExtendedDescription(description, synced);
			return configFile.Bind<T>(section, name, value, new ConfigDescription(extendedDescription, acceptVals, new object[1] { synced ? AdminConfig : ClientConfig }));
		}

		internal static string SetStringPriority(string sectionName, int priority)
		{
			if (priority == 0)
			{
				return sectionName;
			}
			return new string('\u200b', priority) + sectionName;
		}

		internal static string GetExtendedDescription(string description, bool synchronizedSetting)
		{
			return description + (synchronizedSetting ? " [Synced with Server]" : " [Not Synced with Server]");
		}

		internal static void Init(string GUID, ConfigFile config, bool saveOnConfigSet = false)
		{
			configFile = config;
			configFile.SaveOnConfigSet = saveOnConfigSet;
			ConfigFileName = GUID + ".cfg";
			ConfigFileFullPath = Path.Combine(Paths.ConfigPath, ConfigFileName);
		}

		internal static bool DisableSaveOnConfigSet()
		{
			bool saveOnConfigSet = configFile.SaveOnConfigSet;
			configFile.SaveOnConfigSet = false;
			return saveOnConfigSet;
		}

		internal static void SaveOnConfigSet(bool value)
		{
			configFile.SaveOnConfigSet = value;
		}

		internal static void Save()
		{
			configFile.Save();
		}

		internal static void SetupWatcher()
		{
			FileSystemWatcher fileSystemWatcher = new FileSystemWatcher(Paths.ConfigPath, ConfigFileName);
			fileSystemWatcher.Changed += ReloadConfigFile;
			fileSystemWatcher.Created += ReloadConfigFile;
			fileSystemWatcher.Renamed += ReloadConfigFile;
			fileSystemWatcher.IncludeSubdirectories = true;
			fileSystemWatcher.SynchronizingObject = ThreadingHelper.SynchronizingObject;
			fileSystemWatcher.EnableRaisingEvents = true;
		}

		private static void ReloadConfigFile(object sender, FileSystemEventArgs e)
		{
			if (!File.Exists(ConfigFileFullPath))
			{
				return;
			}
			try
			{
				Log.LogInfo("Reloading config file");
				bool value = DisableSaveOnConfigSet();
				configFile.Reload();
				SaveOnConfigSet(value);
				InvokeOnConfigFileReloaded();
			}
			catch
			{
				Log.LogError("There was an issue loading your " + ConfigFileName);
				Log.LogError("Please check your config entries for spelling and format!");
			}
		}

		internal static void CheckForConfigManager()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Invalid comparison between Unknown and I4
			if ((int)SystemInfo.graphicsDeviceType != 4 && Chainloader.PluginInfos.TryGetValue("com.bepis.bepinex.configurationmanager", out var value) && Object.op_Implicit((Object)(object)value.Instance))
			{
				ConfigurationManager = value.Instance;
				Log.LogDebug("Configuration manager found, hooking DisplayingWindowChanged");
				EventInfo @event = ((object)ConfigurationManager).GetType().GetEvent("DisplayingWindowChanged");
				if (@event != null)
				{
					Action<object, object> action = OnConfigManagerDisplayingWindowChanged;
					Delegate handler = Delegate.CreateDelegate(@event.EventHandlerType, action.Target, action.Method);
					@event.AddEventHandler(ConfigurationManager, handler);
				}
			}
		}

		private static void OnConfigManagerDisplayingWindowChanged(object sender, object e)
		{
			if (!(bool)((object)ConfigurationManager).GetType().GetProperty("DisplayingWindow").GetValue(ConfigurationManager, null))
			{
				InvokeOnConfigWindowClosed();
			}
		}
	}
}