Decompiled source of SkillCatchUp v1.0.0

SkillCatchUp.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("SkillCatchUp")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("SkillCatchUp")]
[assembly: AssemblyTitle("SkillCatchUp")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace SkillCatchUp
{
	internal static class ArrowSprite
	{
		internal const int Size = 64;

		private const int Samples = 4;

		private const float Outline = 0.07f;

		private const float OutlineShade = 0.06f;

		private static readonly Vector2[] Shape = (Vector2[])(object)new Vector2[7]
		{
			new Vector2(0.5f, 0.89f),
			new Vector2(0.85f, 0.49f),
			new Vector2(0.63f, 0.49f),
			new Vector2(0.63f, 0.11f),
			new Vector2(0.37f, 0.11f),
			new Vector2(0.37f, 0.49f),
			new Vector2(0.15f, 0.49f)
		};

		private static Sprite sprite;

		internal static Sprite Get()
		{
			//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_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: 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_007c: Expected O, but got Unknown
			if ((Object)(object)sprite != (Object)null)
			{
				return sprite;
			}
			Texture2D val = new Texture2D(64, 64, (TextureFormat)4, true)
			{
				name = "SkillCatchUp_arrow",
				wrapMode = (TextureWrapMode)1,
				filterMode = (FilterMode)2
			};
			val.SetPixels32(Rasterize());
			val.Apply(true, true);
			sprite = Sprite.Create(val, new Rect(0f, 0f, 64f, 64f), new Vector2(0.5f, 0.5f), 100f);
			((Object)sprite).name = "SkillCatchUp_arrow";
			return sprite;
		}

		internal static Color32[] Rasterize()
		{
			//IL_00eb: 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_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			Color32[] array = (Color32[])(object)new Color32[4096];
			Vector2 point = default(Vector2);
			for (int i = 0; i < 64; i++)
			{
				for (int j = 0; j < 64; j++)
				{
					int num = 0;
					int num2 = 0;
					for (int k = 0; k < 4; k++)
					{
						for (int l = 0; l < 4; l++)
						{
							((Vector2)(ref point))..ctor(((float)j + ((float)l + 0.5f) / 4f) / 64f, ((float)i + ((float)k + 0.5f) / 4f) / 64f);
							if (Inside(point))
							{
								num++;
								num2++;
							}
							else if (DistanceToEdge(point) <= 0.07f)
							{
								num2++;
							}
						}
					}
					if (num2 != 0)
					{
						float num3 = 16f;
						byte b = (byte)Mathf.RoundToInt(255f * Mathf.Lerp(0.06f, 1f, (float)num / (float)num2));
						array[i * 64 + j] = new Color32(b, b, b, (byte)Mathf.RoundToInt(255f * (float)num2 / num3));
					}
				}
			}
			return array;
		}

		private static bool Inside(Vector2 point)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: 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_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: 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_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			bool flag = false;
			int num = 0;
			int num2 = Shape.Length - 1;
			while (num < Shape.Length)
			{
				Vector2 val = Shape[num];
				Vector2 val2 = Shape[num2];
				if (val.y > point.y != val2.y > point.y && point.x < (val2.x - val.x) * (point.y - val.y) / (val2.y - val.y) + val.x)
				{
					flag = !flag;
				}
				num2 = num++;
			}
			return flag;
		}

		private static float DistanceToEdge(Vector2 point)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: 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_0052: 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_005b: 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)
			float num = float.MaxValue;
			int num2 = 0;
			int num3 = Shape.Length - 1;
			while (num2 < Shape.Length)
			{
				Vector2 val = Shape[num3];
				Vector2 val2 = Shape[num2] - val;
				float num4 = Mathf.Clamp01(Vector2.Dot(point - val, val2) / ((Vector2)(ref val2)).sqrMagnitude);
				Vector2 val3 = point - (val + val2 * num4);
				float magnitude = ((Vector2)(ref val3)).magnitude;
				if (magnitude < num)
				{
					num = magnitude;
				}
				num3 = num2++;
			}
			return num;
		}
	}
	[BepInPlugin("qua8ion.valheim.skillcatchup", "SkillCatchUp", "1.0.0")]
	public class SkillCatchUpPlugin : BaseUnityPlugin
	{
		public const string PluginGuid = "qua8ion.valheim.skillcatchup";

		public const string PluginName = "SkillCatchUp";

		public const string PluginVersion = "1.0.0";

		internal static ManualLogSource Log;

		internal static ConfigEntry<bool> Enabled;

		internal static ConfigEntry<float> StartMultiplier;

		internal static ConfigEntry<float> EndMultiplier;

		internal static ConfigEntry<bool> KeepHighestTarget;

		internal static ConfigEntry<bool> ShowInSkillsDialog;

		internal static ConfigEntry<bool> ShowLostSkills;

		internal static ConfigEntry<Color> TargetColor;

		internal static ConfigEntry<bool> NotifyRecovered;

		internal static ConfigEntry<bool> LogSnapshots;

		private void Awake()
		{
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Expected O, but got Unknown
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Expected O, but got Unknown
			//IL_0149: Unknown result type (might be due to invalid IL or missing references)
			//IL_0182: Unknown result type (might be due to invalid IL or missing references)
			//IL_0187: Unknown result type (might be due to invalid IL or missing references)
			//IL_0197: Expected O, but got Unknown
			//IL_0197: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a7: Expected O, but got Unknown
			//IL_01b6: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Remember skill levels on death and speed up regaining them.");
			LogSnapshots = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "LogSnapshots", true, "Write the remembered targets to the BepInEx log on every death.");
			StartMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Boost", "StartMultiplier", 10f, new ConfigDescription("Skill gain multiplier at level 0. It goes down in a straight line as the skill gets closer to its remembered level.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 100f), Array.Empty<object>()));
			EndMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Boost", "EndMultiplier", 3f, new ConfigDescription("Skill gain multiplier right before the remembered level is reached. After that the skill gains at normal speed.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 100f), Array.Empty<object>()));
			KeepHighestTarget = ((BaseUnityPlugin)this).Config.Bind<bool>("Boost", "KeepHighestTarget", true, "What happens if you die again before catching up. true: every skill keeps the highest level it was ever remembered at. false: the remembered levels are overwritten with the levels you had at the moment of this death.");
			ShowInSkillsDialog = ((BaseUnityPlugin)this).Config.Bind<bool>("Interface", "ShowInSkillsDialog", true, "Skills window: an arrow on the icon of every boosted skill, a bar up to the remembered level and its number.");
			ShowLostSkills = ((BaseUnityPlugin)this).Config.Bind<bool>("Interface", "ShowLostSkills", true, "List skills that were wiped on death in the skills window right away, at level 0, instead of waiting until they are used again.");
			TargetColor = ((BaseUnityPlugin)this).Config.Bind<Color>("Interface", "TargetColor", new Color(0.6f, 0.902f, 0.35f, 1f), "Colour of the arrow, the target bar and the target number.");
			NotifyRecovered = ((BaseUnityPlugin)this).Config.Bind<bool>("Interface", "NotifyRecovered", true, "Show a message when a skill gets back to its remembered level.");
			Harmony val = new Harmony("qua8ion.valheim.skillcatchup");
			Apply(val, typeof(Player_OnDeath_Patch));
			Apply(val, typeof(Skills_RaiseSkill_Patch));
			Apply(val, typeof(SkillsDialog_Setup_Patch));
		}

		private static void Apply(Harmony harmony, Type patch)
		{
			try
			{
				harmony.CreateClassProcessor(patch).Patch();
			}
			catch (Exception ex)
			{
				Log.LogError((object)("Could not apply " + patch.Name + ", this part of the mod is off: " + ex));
			}
		}

		internal static string Text(string russian, string english)
		{
			if (Localization.instance == null || !(Localization.instance.GetSelectedLanguage() == "Russian"))
			{
				return english;
			}
			return russian;
		}
	}
	[HarmonyPatch(typeof(Player), "OnDeath")]
	internal static class Player_OnDeath_Patch
	{
		private static void Prefix(Player __instance)
		{
			try
			{
				if (SkillCatchUpPlugin.Enabled.Value && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && ((Character)__instance).IsOwner() && !((Character)__instance).IsDead())
				{
					Targets.Snapshot(__instance);
				}
			}
			catch (Exception ex)
			{
				SkillCatchUpPlugin.Log.LogError((object)("Snapshot on death failed: " + ex));
			}
		}
	}
	[HarmonyPatch(typeof(Skills), "RaiseSkill")]
	internal static class Skills_RaiseSkill_Patch
	{
		private static void Prefix(Skills __instance, SkillType skillType, ref float factor, out float __state)
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			__state = 0f;
			try
			{
				Player localPlayer = Player.m_localPlayer;
				if (SkillCatchUpPlugin.Enabled.Value && !((Object)(object)localPlayer == (Object)null) && !((Object)(object)((Character)localPlayer).GetSkills() != (Object)(object)__instance))
				{
					factor *= Targets.Multiplier(localPlayer, skillType, out var target, out var below);
					if (below)
					{
						__state = target;
					}
				}
			}
			catch (Exception ex)
			{
				SkillCatchUpPlugin.Log.LogError((object)("Boost failed: " + ex));
			}
		}

		private unsafe static void Postfix(Skills __instance, SkillType skillType, float __state)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (!(__state <= 0f) && SkillCatchUpPlugin.NotifyRecovered.Value)
				{
					Skill val = Targets.Find(__instance, skillType);
					if (val != null && !Recovery.IsBelow(Targets.Position(val), __state))
					{
						((Character)Player.m_localPlayer).Message((MessageType)1, SkillCatchUpPlugin.Text("Навык восстановлен", "Skill recovered") + ": $skill_" + ((object)(*(SkillType*)(&skillType))/*cast due to .constrained prefix*/).ToString().ToLower() + " " + (int)val.m_level, 0, (val.m_info != null) ? val.m_info.m_icon : null, false);
					}
				}
			}
			catch (Exception ex)
			{
				SkillCatchUpPlugin.Log.LogError((object)("Recovery message failed: " + ex));
			}
		}
	}
	[HarmonyPatch(typeof(SkillsDialog), "Setup")]
	internal static class SkillsDialog_Setup_Patch
	{
		private static void Prefix(Player player)
		{
			try
			{
				SkillsUi.RestoreRows(player);
			}
			catch (Exception ex)
			{
				SkillCatchUpPlugin.Log.LogError((object)("Restoring skill rows failed: " + ex));
			}
		}

		private static void Postfix(Player player, List<GameObject> ___m_elements)
		{
			try
			{
				SkillsUi.Decorate(player, ___m_elements);
			}
			catch (Exception ex)
			{
				SkillCatchUpPlugin.Log.LogError((object)("Skills window decoration failed: " + ex));
			}
		}
	}
	internal static class Recovery
	{
		internal const float MaxLevel = 100f;

		private const float Epsilon = 0.0005f;

		internal static bool IsBelow(float position, float target)
		{
			if (target > 0f)
			{
				return position < target - 0.0005f;
			}
			return false;
		}

		internal static float Multiplier(float position, float target, float start, float end)
		{
			if (!IsBelow(position, target))
			{
				return 1f;
			}
			float num = Math.Max(0f, position) / target;
			float val = start + (end - start) * num;
			return Math.Max(1f, val);
		}

		internal static Dictionary<int, float> Merge(Dictionary<int, float> old, IEnumerable<KeyValuePair<int, float>> atDeath, bool keepHighest)
		{
			Dictionary<int, float> dictionary = new Dictionary<int, float>();
			if (keepHighest && old != null)
			{
				foreach (KeyValuePair<int, float> item in old)
				{
					dictionary[item.Key] = item.Value;
				}
			}
			foreach (KeyValuePair<int, float> item2 in atDeath)
			{
				float num = Math.Min(100f, item2.Value);
				if (!(num <= 0f) && (!dictionary.TryGetValue(item2.Key, out var value) || num > value))
				{
					dictionary[item2.Key] = num;
				}
			}
			return dictionary;
		}

		internal static string Serialize(Dictionary<int, float> targets)
		{
			StringBuilder stringBuilder = new StringBuilder();
			foreach (KeyValuePair<int, float> target in targets)
			{
				if (!(target.Value <= 0f))
				{
					if (stringBuilder.Length > 0)
					{
						stringBuilder.Append(';');
					}
					stringBuilder.Append(target.Key.ToString(CultureInfo.InvariantCulture));
					stringBuilder.Append('=');
					stringBuilder.Append(target.Value.ToString("0.###", CultureInfo.InvariantCulture));
				}
			}
			return stringBuilder.ToString();
		}

		internal static Dictionary<int, float> Parse(string raw)
		{
			Dictionary<int, float> dictionary = new Dictionary<int, float>();
			if (string.IsNullOrEmpty(raw))
			{
				return dictionary;
			}
			string[] array = raw.Split(new char[1] { ';' });
			foreach (string text in array)
			{
				int num = text.IndexOf('=');
				if (num > 0 && int.TryParse(text.Substring(0, num), NumberStyles.Integer, CultureInfo.InvariantCulture, out var result) && float.TryParse(text.Substring(num + 1), NumberStyles.Float, CultureInfo.InvariantCulture, out var result2) && !float.IsNaN(result2) && !(result2 <= 0f))
				{
					dictionary[result] = Math.Min(100f, result2);
				}
			}
			return dictionary;
		}
	}
	internal static class SkillsUi
	{
		private const string BarName = "catchup_target";

		private const string TextName = "catchup_targettext";

		private const string ArrowName = "catchup_arrow";

		private const float BarAlpha = 0.35f;

		private const float CapWidth = 2f;

		private const float TargetFontSize = 13f;

		private const float ArrowSize = 14f;

		private const float ArrowOut = 3f;

		internal static void RestoreRows(Player player)
		{
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Expected I4, but got Unknown
			if ((Object)(object)player == (Object)null || !SkillCatchUpPlugin.Enabled.Value || !SkillCatchUpPlugin.ShowInSkillsDialog.Value || !SkillCatchUpPlugin.ShowLostSkills.Value)
			{
				return;
			}
			Skills skills = ((Character)player).GetSkills();
			HashSet<int> hashSet = new HashSet<int>();
			foreach (Skill skill in skills.GetSkillList())
			{
				if (skill.m_info != null)
				{
					hashSet.Add((int)skill.m_info.m_skill);
				}
			}
			foreach (KeyValuePair<int, float> item in Targets.Read(player))
			{
				if (!hashSet.Contains(item.Key) && HasDefinition(skills, (SkillType)item.Key))
				{
					skills.GetSkillLevel((SkillType)item.Key);
				}
			}
		}

		private static bool HasDefinition(Skills skills, SkillType skillType)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			foreach (SkillDef skill in skills.m_skills)
			{
				if (skill.m_skill == skillType)
				{
					return true;
				}
			}
			return false;
		}

		internal static void Decorate(Player player, List<GameObject> elements)
		{
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Expected I4, but got Unknown
			if ((Object)(object)player == (Object)null || elements == null)
			{
				return;
			}
			bool flag = SkillCatchUpPlugin.Enabled.Value && SkillCatchUpPlugin.ShowInSkillsDialog.Value;
			Dictionary<int, float> dictionary = Targets.Read(player);
			List<Skill> skillList = ((Character)player).GetSkills().GetSkillList();
			for (int i = 0; i < elements.Count && i < skillList.Count; i++)
			{
				GameObject val = elements[i];
				Skill val2 = skillList[i];
				if (!((Object)(object)val == (Object)null) && val2.m_info != null)
				{
					float value = 0f;
					float position = Targets.Position(val2);
					bool boosted = flag && dictionary.TryGetValue((int)val2.m_info.m_skill, out value) && Recovery.IsBelow(position, value);
					Apply(val.transform, boosted, value);
				}
			}
		}

		private static void Apply(Transform element, bool boosted, float target)
		{
			//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_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Expected O, but got Unknown
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: 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_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			Transform val = element.Find("catchup_target");
			Transform val2 = element.Find("levelbar/catchup_targettext");
			Transform val3 = element.Find("icon_bkg/catchup_arrow");
			if (!boosted)
			{
				SetActive(val, active: false);
				SetActive(val2, active: false);
				SetActive(val3, active: false);
				return;
			}
			Color value = SkillCatchUpPlugin.TargetColor.Value;
			if ((Object)(object)val == (Object)null)
			{
				val = CreateBar(element);
			}
			if ((Object)(object)val != (Object)null)
			{
				RectTransform val4 = (RectTransform)val;
				RectTransform val5 = (RectTransform)val.GetChild(0);
				val5.SetSizeWithCurrentAnchors((Axis)0, val4.sizeDelta.x * Mathf.Clamp01(target / 100f));
				((Graphic)((Component)val5).GetComponent<Image>()).color = new Color(value.r, value.g, value.b, value.a * 0.35f);
				((Graphic)((Component)((Transform)val5).GetChild(0)).GetComponent<Image>()).color = value;
				SetActive(val, active: true);
			}
			if ((Object)(object)val2 == (Object)null)
			{
				val2 = CreateText(element);
			}
			if ((Object)(object)val2 != (Object)null)
			{
				TMP_Text component = ((Component)val2).GetComponent<TMP_Text>();
				component.text = ((int)target).ToString(CultureInfo.InvariantCulture);
				((Graphic)component).color = value;
				SetActive(val2, active: true);
			}
			if ((Object)(object)val3 == (Object)null)
			{
				val3 = CreateArrow(element);
			}
			if ((Object)(object)val3 != (Object)null)
			{
				((Graphic)((Component)val3).GetComponent<Image>()).color = value;
				SetActive(val3, active: true);
			}
		}

		private static void SetActive(Transform transform, bool active)
		{
			if ((Object)(object)transform != (Object)null && ((Component)transform).gameObject.activeSelf != active)
			{
				((Component)transform).gameObject.SetActive(active);
			}
		}

		private static RectTransform NewChild(string name, Transform parent, params Type[] components)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Expected O, but got Unknown
			//IL_004d: 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_005b: Expected O, but got Unknown
			GameObject val = new GameObject(name, new Type[1] { typeof(RectTransform) });
			val.layer = ((Component)parent).gameObject.layer;
			foreach (Type type in components)
			{
				val.AddComponent(type);
			}
			RectTransform val2 = (RectTransform)val.transform;
			((Transform)val2).SetParent(parent, false);
			return val2;
		}

		private static Transform CreateBar(Transform element)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: 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_00a1: 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_00cb: 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_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0169: Unknown result type (might be due to invalid IL or missing references)
			//IL_017e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0193: Unknown result type (might be due to invalid IL or missing references)
			//IL_019e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: Unknown result type (might be due to invalid IL or missing references)
			Transform obj = element.Find("levelbar_total");
			RectTransform val = (RectTransform)(object)((obj is RectTransform) ? obj : null);
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			RectTransform val2 = NewChild("catchup_target", element);
			val2.anchorMin = val.anchorMin;
			val2.anchorMax = val.anchorMax;
			val2.pivot = val.pivot;
			val2.anchoredPosition = val.anchoredPosition;
			val2.sizeDelta = val.sizeDelta;
			((Transform)val2).SetSiblingIndex(((Transform)val).GetSiblingIndex() + 1);
			RectTransform val3 = NewChild("bar", (Transform)(object)val2, typeof(Image));
			val3.anchorMin = new Vector2(0f, 0f);
			val3.anchorMax = new Vector2(0f, 1f);
			val3.pivot = new Vector2(0f, 0.5f);
			val3.anchoredPosition = Vector2.zero;
			val3.sizeDelta = Vector2.zero;
			Image component = ((Component)val3).GetComponent<Image>();
			((Graphic)component).raycastTarget = false;
			Transform val4 = ((Transform)val).Find("bar");
			Image val5 = (((Object)(object)val4 != (Object)null) ? ((Component)val4).GetComponent<Image>() : null);
			if ((Object)(object)val5 != (Object)null)
			{
				component.sprite = val5.sprite;
				component.type = val5.type;
			}
			RectTransform obj2 = NewChild("cap", (Transform)(object)val3, typeof(Image));
			obj2.anchorMin = new Vector2(1f, 0f);
			obj2.anchorMax = new Vector2(1f, 1f);
			obj2.pivot = new Vector2(1f, 0.5f);
			obj2.anchoredPosition = Vector2.zero;
			obj2.sizeDelta = new Vector2(2f, 0f);
			((Graphic)((Component)obj2).GetComponent<Image>()).raycastTarget = false;
			return (Transform)(object)val2;
		}

		private static Transform CreateText(Transform element)
		{
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			Transform val = element.Find("levelbar/leveltext");
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			GameObject obj = Object.Instantiate<GameObject>(((Component)val).gameObject, val.parent);
			((Object)obj).name = "catchup_targettext";
			TMP_Text component = obj.GetComponent<TMP_Text>();
			component.alignment = (TextAlignmentOptions)516;
			component.margin = new Vector4(0f, 0f, 4f, 0f);
			component.enableAutoSizing = false;
			component.fontSize = 13f;
			((Graphic)component).raycastTarget = false;
			return obj.transform;
		}

		private static Transform CreateArrow(Transform element)
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: 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)
			Transform val = element.Find("icon_bkg");
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			RectTransform obj = NewChild("catchup_arrow", val, typeof(Image));
			obj.anchorMin = new Vector2(1f, 1f);
			obj.anchorMax = new Vector2(1f, 1f);
			obj.pivot = new Vector2(1f, 1f);
			obj.anchoredPosition = new Vector2(3f, 3f);
			obj.sizeDelta = new Vector2(14f, 14f);
			Image component = ((Component)obj).GetComponent<Image>();
			component.sprite = ArrowSprite.Get();
			((Graphic)component).raycastTarget = false;
			return (Transform)(object)obj;
		}
	}
	internal static class Targets
	{
		internal const string DataKey = "qua8ion.skillcatchup.targets";

		private static string cachedRaw = "";

		private static Dictionary<int, float> cached = new Dictionary<int, float>();

		internal static Dictionary<int, float> Read(Player player)
		{
			if (!player.m_customData.TryGetValue("qua8ion.skillcatchup.targets", out var value) || value == null)
			{
				value = "";
			}
			if (value != cachedRaw)
			{
				cached = Recovery.Parse(value);
				cachedRaw = value;
			}
			return cached;
		}

		private static void Write(Player player, Dictionary<int, float> targets)
		{
			string text = Recovery.Serialize(targets);
			if (text.Length == 0)
			{
				player.m_customData.Remove("qua8ion.skillcatchup.targets");
			}
			else
			{
				player.m_customData["qua8ion.skillcatchup.targets"] = text;
			}
			cached = targets;
			cachedRaw = text;
		}

		internal static float Position(Skill skill)
		{
			return skill.m_level + skill.GetLevelPercentage();
		}

		internal static Skill Find(Skills skills, SkillType skillType)
		{
			//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)
			foreach (Skill skill in skills.GetSkillList())
			{
				if (skill.m_info != null && skill.m_info.m_skill == skillType)
				{
					return skill;
				}
			}
			return null;
		}

		internal static void Snapshot(Player player)
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Expected I4, but got Unknown
			List<KeyValuePair<int, float>> list = new List<KeyValuePair<int, float>>();
			foreach (Skill skill in ((Character)player).GetSkills().GetSkillList())
			{
				if (skill.m_info != null)
				{
					list.Add(new KeyValuePair<int, float>((int)skill.m_info.m_skill, Position(skill)));
				}
			}
			Dictionary<int, float> dictionary = Recovery.Merge(Read(player), list, SkillCatchUpPlugin.KeepHighestTarget.Value);
			Write(player, dictionary);
			if (SkillCatchUpPlugin.LogSnapshots.Value)
			{
				SkillCatchUpPlugin.Log.LogInfo((object)("Death: remembered targets for " + dictionary.Count + " skills (" + (SkillCatchUpPlugin.KeepHighestTarget.Value ? "keeping the highest" : "overwritten") + "): " + Recovery.Serialize(dictionary)));
			}
		}

		internal static float Multiplier(Player player, SkillType skillType, out float target, out bool below)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Expected I4, but got Unknown
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			target = 0f;
			below = false;
			if (!Read(player).TryGetValue((int)skillType, out target))
			{
				return 1f;
			}
			Skill val = Find(((Character)player).GetSkills(), skillType);
			float position = ((val != null) ? Position(val) : 0f);
			below = Recovery.IsBelow(position, target);
			return Recovery.Multiplier(position, target, SkillCatchUpPlugin.StartMultiplier.Value, SkillCatchUpPlugin.EndMultiplier.Value);
		}
	}
}