Decompiled source of SkillProgress v1.0.0

BepInEx/plugins/SkillProgress/SkillProgress.dll

Decompiled 3 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
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: IgnoresAccessChecksTo("assembly_valheim")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("Kriona")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("Copyright (c) 2026 Kriona Hagen - MIT License")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("Skill Progress")]
[assembly: AssemblyTitle("Skill Progress")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[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 SkillProgress
{
	[BepInPlugin("kriona.SkillProgress", "Skill Progress", "1.0.0")]
	public class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "kriona.SkillProgress";

		public const string PluginName = "Skill Progress";

		public const string PluginVersion = "1.0.0";

		private readonly SkillBars bars = new SkillBars();

		private Harmony harmony;

		private void Awake()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected O, but got Unknown
			harmony = new Harmony("kriona.SkillProgress");
			harmony.PatchAll();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Skill Progress 1.0.0 loaded");
		}

		private void LateUpdate()
		{
			bars.Update();
		}

		private void OnDestroy()
		{
			bars.Destroy();
			Harmony obj = harmony;
			if (obj != null)
			{
				obj.UnpatchSelf();
			}
		}
	}
	public class SkillBars
	{
		private const float Gap = 4f;

		private const float ShowSeconds = 3f;

		private const float FadeSeconds = 0.5f;

		private static readonly Dictionary<SkillType, float> trainedTimes = new Dictionary<SkillType, float>();

		private static Skills trainedSkills;

		private readonly List<SkillType> shown = new List<SkillType>();

		private readonly List<SkillRow> rows = new List<SkillRow>();

		private readonly List<SkillType> expired = new List<SkillType>();

		private GameObject root;

		public static void Trained(Skills skills, SkillType skillType)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)skills != (Object)(object)trainedSkills)
			{
				trainedSkills = skills;
				trainedTimes.Clear();
			}
			trainedTimes[skillType] = Time.time;
		}

		public static void Maxed(SkillType skillType)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			trainedTimes.Remove(skillType);
		}

		public void Update()
		{
			//IL_00b5: 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_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			Hud instance = Hud.instance;
			if ((Object)(object)localPlayer == (Object)null || (Object)(object)instance == (Object)null)
			{
				return;
			}
			if ((Object)(object)root == (Object)null)
			{
				Create(instance);
			}
			UpdateShown(localPlayer);
			bool flag = shown.Count > 0;
			if (root.activeSelf != flag)
			{
				root.SetActive(flag);
			}
			if (!flag)
			{
				return;
			}
			while (rows.Count < shown.Count)
			{
				rows.Add(new SkillRow(root.transform, instance));
			}
			for (int i = 0; i < rows.Count; i++)
			{
				if (i < shown.Count)
				{
					SkillType val = shown[i];
					rows[i].Show(trainedSkills.GetSkill(val), GetAlpha(trainedTimes[val]), i);
				}
				else
				{
					rows[i].Hide();
				}
			}
			Position(instance, localPlayer);
		}

		public void Destroy()
		{
			if ((Object)(object)root != (Object)null)
			{
				Object.Destroy((Object)(object)root);
			}
		}

		private static float GetAlpha(float trainedTime)
		{
			float num = Time.time - trainedTime;
			if (num < 3f)
			{
				return 1f;
			}
			return Mathf.Clamp01(1f - (num - 3f) / 0.5f);
		}

		private void UpdateShown(Player player)
		{
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: 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_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)trainedSkills == (Object)null || (Object)(object)trainedSkills.m_player != (Object)(object)player)
			{
				shown.Clear();
				return;
			}
			expired.Clear();
			foreach (KeyValuePair<SkillType, float> trainedTime in trainedTimes)
			{
				if (GetAlpha(trainedTime.Value) <= 0f)
				{
					expired.Add(trainedTime.Key);
				}
				else if (!shown.Contains(trainedTime.Key))
				{
					shown.Add(trainedTime.Key);
				}
			}
			foreach (SkillType item in expired)
			{
				trainedTimes.Remove(item);
			}
			shown.RemoveAll((SkillType type) => !trainedTimes.ContainsKey(type));
		}

		private void Create(Hud hud)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Expected O, but got Unknown
			//IL_0055: 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_0065: 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_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			rows.Clear();
			root = new GameObject("SkillProgress", new Type[1] { typeof(RectTransform) });
			root.transform.SetParent(hud.m_rootObject.transform, false);
			RectTransform val = (RectTransform)root.transform;
			val.anchorMin = new Vector2(0.5f, 0.5f);
			val.anchorMax = new Vector2(0.5f, 0.5f);
			val.pivot = new Vector2(0.5f, 1f);
			val.sizeDelta = Vector2.zero;
		}

		private void Position(Hud hud, Player player)
		{
			//IL_0018: 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_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: 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_0050: 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_0065: 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_0073: 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_008a: Unknown result type (might be due to invalid IL or missing references)
			Transform parent = root.transform.parent;
			Vector3 bottomCenter = GetBottomCenter(hud.m_staminaBar2Root, parent);
			if (((Character)player).GetMaxEitr() > 0f && ((Component)hud.m_eitrBarRoot).gameObject.activeInHierarchy)
			{
				Vector3 bottomCenter2 = GetBottomCenter(hud.m_eitrBarRoot, parent);
				Rect rect = hud.m_staminaBar2Root.rect;
				float num = ((Rect)(ref rect)).width * 0.5f;
				if (bottomCenter2.y < bottomCenter.y && Mathf.Abs(bottomCenter2.x - bottomCenter.x) < num)
				{
					bottomCenter.y = bottomCenter2.y;
				}
			}
			root.transform.localPosition = new Vector3(bottomCenter.x, bottomCenter.y - 4f, 0f);
		}

		private static Vector3 GetBottomCenter(RectTransform bar, Transform space)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: 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_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: 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_003c: 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_003f: Unknown result type (might be due to invalid IL or missing references)
			Rect rect = bar.rect;
			Vector3 val = ((Transform)bar).localPosition + new Vector3(((Rect)(ref rect)).center.x, ((Rect)(ref rect)).yMin, 0f);
			Vector3 val2 = ((Transform)bar).parent.TransformPoint(val);
			return space.InverseTransformPoint(val2);
		}
	}
	[HarmonyPatch(typeof(Skills), "RaiseSkill")]
	public static class RaiseSkillPatch
	{
		private static void Prefix(Skills __instance, SkillType skillType, out (float level, float accumulator)? __state)
		{
			//IL_0007: 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)
			__state = null;
			if ((int)skillType != 0 && !((Object)(object)__instance.m_player == (Object)null) && !((Object)(object)__instance.m_player != (Object)(object)Player.m_localPlayer))
			{
				Skill skill = __instance.GetSkill(skillType);
				__state = (skill.m_level, skill.m_accumulator);
			}
		}

		private static void Postfix(Skills __instance, SkillType skillType, (float level, float accumulator)? __state)
		{
			//IL_000b: 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_003a: Unknown result type (might be due to invalid IL or missing references)
			if (__state.HasValue)
			{
				Skill skill = __instance.GetSkill(skillType);
				if (skill.m_level == __state.Value.level && skill.m_accumulator == __state.Value.accumulator)
				{
					SkillBars.Maxed(skillType);
				}
				else
				{
					SkillBars.Trained(__instance, skillType);
				}
			}
		}
	}
	public class SkillRow
	{
		public const float Height = 20f;

		private const float BarWidth = 100f;

		private const float BarHeight = 5f;

		private const float IconSize = 18f;

		private const float IconGap = 4f;

		private const float TextGap = 6f;

		private const float FontSize = 14f;

		private static readonly Color BackgroundColor = new Color(0f, 0f, 0f, 0.6f);

		private static readonly Color FillColor = new Color(0.45f, 0.75f, 1f, 1f);

		private readonly GameObject root;

		private readonly CanvasGroup group;

		private readonly RectTransform fill;

		private readonly Image icon;

		private readonly TextMeshProUGUI text;

		private SkillType shownType;

		private string shownName;

		private int shownLevel = -1;

		private int shownTenths = -1;

		public SkillRow(Transform parent, Hud hud)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Expected O, but got Unknown
			//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_0099: 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_00ae: 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_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: 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_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Unknown result type (might be due to invalid IL or missing references)
			//IL_0184: 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_01ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_01be: Unknown result type (might be due to invalid IL or missing references)
			//IL_0205: Unknown result type (might be due to invalid IL or missing references)
			//IL_021a: Unknown result type (might be due to invalid IL or missing references)
			//IL_022f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0244: Unknown result type (might be due to invalid IL or missing references)
			//IL_0258: Unknown result type (might be due to invalid IL or missing references)
			//IL_027a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0280: Expected O, but got Unknown
			//IL_031d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0332: Unknown result type (might be due to invalid IL or missing references)
			//IL_0347: Unknown result type (might be due to invalid IL or missing references)
			//IL_035c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0370: Unknown result type (might be due to invalid IL or missing references)
			root = new GameObject("SkillRow", new Type[1] { typeof(RectTransform) });
			root.transform.SetParent(parent, false);
			root.SetActive(false);
			group = root.AddComponent<CanvasGroup>();
			group.blocksRaycasts = false;
			group.interactable = false;
			RectTransform val = (RectTransform)root.transform;
			val.anchorMin = new Vector2(0.5f, 0.5f);
			val.anchorMax = new Vector2(0.5f, 0.5f);
			val.pivot = new Vector2(0.5f, 1f);
			val.sizeDelta = new Vector2(100f, 20f);
			Image obj = CreateImage("Background", root.transform);
			((Graphic)obj).color = BackgroundColor;
			RectTransform rectTransform = ((Graphic)obj).rectTransform;
			rectTransform.anchorMin = new Vector2(0f, 0.5f);
			rectTransform.anchorMax = new Vector2(1f, 0.5f);
			rectTransform.pivot = new Vector2(0.5f, 0.5f);
			rectTransform.sizeDelta = new Vector2(0f, 5f);
			Image val2 = CreateImage("Fill", (Transform)(object)rectTransform);
			((Graphic)val2).color = FillColor;
			fill = ((Graphic)val2).rectTransform;
			fill.anchorMin = Vector2.zero;
			fill.anchorMax = new Vector2(0f, 1f);
			fill.offsetMin = Vector2.zero;
			fill.offsetMax = Vector2.zero;
			icon = CreateImage("Icon", root.transform);
			icon.preserveAspect = true;
			RectTransform rectTransform2 = ((Graphic)icon).rectTransform;
			rectTransform2.anchorMin = new Vector2(0f, 0.5f);
			rectTransform2.anchorMax = new Vector2(0f, 0.5f);
			rectTransform2.pivot = new Vector2(1f, 0.5f);
			rectTransform2.sizeDelta = new Vector2(18f, 18f);
			rectTransform2.anchoredPosition = new Vector2(-4f, 0f);
			GameObject val3 = new GameObject("Text", new Type[1] { typeof(RectTransform) });
			val3.transform.SetParent(root.transform, false);
			text = val3.AddComponent<TextMeshProUGUI>();
			((TMP_Text)text).font = hud.m_healthText.font;
			((TMP_Text)text).fontSharedMaterial = hud.m_healthText.fontSharedMaterial;
			((TMP_Text)text).fontSize = 14f;
			((TMP_Text)text).alignment = (TextAlignmentOptions)4097;
			((TMP_Text)text).textWrappingMode = (TextWrappingModes)0;
			((Graphic)text).raycastTarget = false;
			RectTransform rectTransform3 = ((TMP_Text)text).rectTransform;
			rectTransform3.anchorMin = new Vector2(1f, 0.5f);
			rectTransform3.anchorMax = new Vector2(1f, 0.5f);
			rectTransform3.pivot = new Vector2(0f, 0.5f);
			rectTransform3.sizeDelta = new Vector2(300f, 20f);
			rectTransform3.anchoredPosition = new Vector2(6f, 0f);
		}

		public void Show(Skill skill, float alpha, int index)
		{
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			if (!root.activeSelf)
			{
				root.SetActive(true);
			}
			group.alpha = alpha;
			root.transform.localPosition = new Vector3(0f, (float)(-index) * 20f, 0f);
			SetProgress(skill);
		}

		public void Hide()
		{
			if (root.activeSelf)
			{
				root.SetActive(false);
			}
		}

		private static Image CreateImage(string name, Transform parent)
		{
			//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)
			GameObject val = new GameObject(name, new Type[1] { typeof(RectTransform) });
			val.transform.SetParent(parent, false);
			Image obj = val.AddComponent<Image>();
			((Graphic)obj).raycastTarget = false;
			return obj;
		}

		private unsafe void SetProgress(Skill skill)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: 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)
			float levelPercentage = skill.GetLevelPercentage();
			fill.anchorMax = new Vector2(levelPercentage, 1f);
			SkillType skill2 = skill.m_info.m_skill;
			if (skill2 != shownType)
			{
				shownType = skill2;
				shownName = Localization.instance.Localize("$skill_" + ((object)(*(SkillType*)(&skill2))/*cast due to .constrained prefix*/).ToString().ToLower());
				icon.sprite = skill.m_info.m_icon;
				((Behaviour)icon).enabled = (Object)(object)icon.sprite != (Object)null;
				shownLevel = -1;
			}
			int num = (int)skill.m_level;
			int num2 = Mathf.FloorToInt(levelPercentage * 1000f);
			if (num != shownLevel || num2 != shownTenths)
			{
				shownLevel = num;
				shownTenths = num2;
				((TMP_Text)text).text = shownName + " " + num + "  " + ((float)num2 / 10f).ToString("0.0") + "%";
			}
		}
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}
namespace Kriona.Shared
{
	internal class ConfigMirror
	{
		private readonly ConfigFile config;

		private readonly Action changed;

		private bool syncing;

		public ConfigMirror(ConfigFile config, Action changed)
		{
			this.config = config;
			this.changed = changed;
			config.SaveOnConfigSet = false;
			config.SettingChanged += OnSettingChanged;
		}

		public ConfigEntry<T> Bind<T>(string section, string key, T defaultValue, string description, AcceptableValueBase acceptableValues, int? order, string displayName)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Expected O, but got Unknown
			ConfigurationManagerAttributes configurationManagerAttributes = new ConfigurationManagerAttributes();
			configurationManagerAttributes.Order = order;
			configurationManagerAttributes.DispName = displayName;
			return config.Bind<T>(section, key, defaultValue, new ConfigDescription(description, acceptableValues, new object[1] { configurationManagerAttributes }));
		}

		public void Remove(ConfigEntryBase entry)
		{
			config.Remove(entry.Definition);
		}

		public void Sync(Action apply)
		{
			syncing = true;
			try
			{
				apply();
			}
			finally
			{
				syncing = false;
			}
		}

		public static void SetDisplayName(ConfigEntryBase entry, string displayName)
		{
			object[] tags = entry.Description.Tags;
			for (int i = 0; i < tags.Length; i++)
			{
				if (tags[i] is ConfigurationManagerAttributes configurationManagerAttributes)
				{
					configurationManagerAttributes.DispName = displayName;
				}
			}
		}

		private void OnSettingChanged(object sender, SettingChangedEventArgs args)
		{
			if (!syncing)
			{
				changed();
			}
		}
	}
	internal sealed class ConfigurationManagerAttributes
	{
		public int? Order;

		public string DispName;
	}
	internal class ConfigWatcher : IDisposable
	{
		private const float ReloadDelay = 0.5f;

		private readonly string path;

		private readonly Action reload;

		private readonly ManualLogSource log;

		private readonly string pluginName;

		private readonly FileSystemWatcher watcher;

		private string knownContents;

		private volatile bool fileChanged;

		private float reloadTime = -1f;

		public ConfigWatcher(string path, Action reload, ManualLogSource log, string pluginName)
		{
			this.path = path;
			this.reload = reload;
			this.log = log;
			this.pluginName = pluginName;
			Remember();
			try
			{
				watcher = new FileSystemWatcher(Path.GetDirectoryName(path), Path.GetFileName(path));
				watcher.NotifyFilter = NotifyFilters.FileName | NotifyFilters.Size | NotifyFilters.LastWrite;
				watcher.Changed += delegate
				{
					fileChanged = true;
				};
				watcher.Created += delegate
				{
					fileChanged = true;
				};
				watcher.Renamed += delegate
				{
					fileChanged = true;
				};
				watcher.EnableRaisingEvents = true;
			}
			catch (Exception ex)
			{
				watcher = null;
				log.LogWarning((object)("Couldn't watch " + path + " for changes, so changes made to it while Valheim is running aren't read: " + ex.Message));
			}
		}

		public ConfigWatcher(ConfigFile config, ManualLogSource log, string pluginName)
			: this(config.ConfigFilePath, delegate
			{
				ReloadConfig(config);
			}, log, pluginName)
		{
		}

		private static void ReloadConfig(ConfigFile config)
		{
			bool saveOnConfigSet = config.SaveOnConfigSet;
			config.SaveOnConfigSet = false;
			try
			{
				config.Reload();
			}
			finally
			{
				config.SaveOnConfigSet = saveOnConfigSet;
			}
			if (saveOnConfigSet && !MatchesFile(config))
			{
				config.Save();
			}
		}

		private static bool MatchesFile(ConfigFile config)
		{
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Expected O, but got Unknown
			Dictionary<ConfigDefinition, string> dictionary = new Dictionary<ConfigDefinition, string>();
			string text = string.Empty;
			string[] array = File.ReadAllLines(config.ConfigFilePath);
			for (int i = 0; i < array.Length; i++)
			{
				string text2 = array[i].Trim();
				if (text2.StartsWith("#"))
				{
					continue;
				}
				if (text2.StartsWith("[") && text2.EndsWith("]"))
				{
					text = text2.Substring(1, text2.Length - 2);
					continue;
				}
				string[] array2 = text2.Split(new char[1] { '=' }, 2);
				if (array2.Length == 2)
				{
					dictionary[new ConfigDefinition(text, array2[0].Trim())] = array2[1].Trim();
				}
			}
			foreach (KeyValuePair<ConfigDefinition, ConfigEntryBase> item in config)
			{
				if (!dictionary.TryGetValue(item.Key, out var value))
				{
					return false;
				}
				try
				{
					if (!object.Equals(TomlTypeConverter.ConvertToValue(value, item.Value.SettingType), item.Value.BoxedValue))
					{
						return false;
					}
				}
				catch (Exception)
				{
					return false;
				}
			}
			return true;
		}

		public void Update()
		{
			if (fileChanged)
			{
				fileChanged = false;
				reloadTime = Time.realtimeSinceStartup + 0.5f;
			}
			if (reloadTime < 0f || Time.realtimeSinceStartup < reloadTime)
			{
				return;
			}
			reloadTime = -1f;
			string text;
			try
			{
				text = File.ReadAllText(path);
			}
			catch (FileNotFoundException)
			{
				return;
			}
			catch (IOException)
			{
				reloadTime = Time.realtimeSinceStartup + 0.5f;
				return;
			}
			if (text == knownContents)
			{
				return;
			}
			reload();
			Remember();
			if (pluginName != null)
			{
				log.LogInfo((object)("Reloaded " + Path.GetFileName(path)));
				MessageHud instance = MessageHud.instance;
				if (instance != null)
				{
					instance.ShowMessage((MessageType)1, pluginName + ": config reloaded", 0, (Sprite)null, false, true);
				}
			}
		}

		public void Remember()
		{
			try
			{
				knownContents = File.ReadAllText(path);
			}
			catch (IOException)
			{
				knownContents = null;
			}
		}

		public void Dispose()
		{
			watcher?.Dispose();
		}
	}
	internal class StateEntries
	{
		public const string Inherit = "inherit";

		private static readonly AcceptableValueList<string> values = new AcceptableValueList<string>(new string[3] { "inherit", "true", "false" });

		private readonly ConfigMirror mirror;

		private readonly string help;

		private readonly Dictionary<string, ConfigEntry<string>> entries = new Dictionary<string, ConfigEntry<string>>(StringComparer.OrdinalIgnoreCase);

		private readonly HashSet<string> set = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

		public StateEntries(ConfigMirror mirror, string help)
		{
			this.mirror = mirror;
			this.help = help;
		}

		public void Set(string section, string key, string displayName, bool? state)
		{
			string entryName = GetEntryName(key, displayName);
			if (entries.TryGetValue(key, out var value) && ((ConfigEntryBase)value).Definition.Section != section)
			{
				mirror.Remove((ConfigEntryBase)(object)value);
				entries.Remove(key);
				value = null;
			}
			if (value == null)
			{
				try
				{
					value = mirror.Bind(section, key, "inherit", "Prefab " + key + " - " + help, (AcceptableValueBase)(object)values, null, entryName);
				}
				catch (ArgumentException)
				{
					return;
				}
				entries[key] = value;
			}
			else
			{
				ConfigMirror.SetDisplayName((ConfigEntryBase)(object)value, entryName);
			}
			value.Value = Format(state);
			set.Add(key);
		}

		public void RemoveUnset()
		{
			List<string> list = new List<string>();
			foreach (KeyValuePair<string, ConfigEntry<string>> entry in entries)
			{
				if (!set.Contains(entry.Key))
				{
					mirror.Remove((ConfigEntryBase)(object)entry.Value);
					list.Add(entry.Key);
				}
			}
			foreach (string item in list)
			{
				entries.Remove(item);
			}
			set.Clear();
		}

		public bool TryGetState(string key, out bool? state)
		{
			state = null;
			if (!entries.TryGetValue(key, out var value))
			{
				return false;
			}
			if (bool.TryParse(value.Value, out var result))
			{
				state = result;
			}
			return true;
		}

		public static string Format(bool? state)
		{
			if (!state.HasValue)
			{
				return "inherit";
			}
			if (!state.Value)
			{
				return "false";
			}
			return "true";
		}

		private static string GetEntryName(string key, string displayName)
		{
			string text = displayName.Trim();
			if (text.Length == 0 || text.Equals(key, StringComparison.OrdinalIgnoreCase))
			{
				return key;
			}
			return text + " (" + key + ")";
		}
	}
}