Decompiled source of QuickFill v1.5.0

BepInEx/plugins/QuickFill/QuickFill.dll

Decompiled 5 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 Kriona.Shared;
using Microsoft.CodeAnalysis;
using UnityEngine;

[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.5.0.0")]
[assembly: AssemblyInformationalVersion("1.5.0")]
[assembly: AssemblyProduct("Quick Fill")]
[assembly: AssemblyTitle("Quick Fill")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.5.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 QuickFill
{
	internal static class Fill
	{
		public static bool IsModifierHeld()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_001f: 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_002b: Unknown result type (might be due to invalid IL or missing references)
			KeyboardShortcut value = Plugin.ModifierKey.Value;
			KeyCode mainKey = ((KeyboardShortcut)(ref value)).MainKey;
			if ((int)mainKey == 0)
			{
				return false;
			}
			KeyCode otherSide = GetOtherSide(mainKey);
			if (!ZInput.GetKey(mainKey, false))
			{
				if ((int)otherSide != 0)
				{
					return ZInput.GetKey(otherSide, false);
				}
				return false;
			}
			return true;
		}

		private static KeyCode GetOtherSide(KeyCode key)
		{
			//IL_0000: 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_002c: Expected I4, but got Unknown
			return (KeyCode)((key - 303) switch
			{
				3 => 305, 
				2 => 306, 
				1 => 303, 
				0 => 304, 
				5 => 307, 
				4 => 308, 
				7 => 309, 
				6 => 310, 
				_ => 0, 
			});
		}

		public unsafe static string GetModifierName()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Expected I4, but got Unknown
			KeyboardShortcut value = Plugin.ModifierKey.Value;
			KeyCode mainKey = ((KeyboardShortcut)(ref value)).MainKey;
			switch (mainKey - 303)
			{
			case 2:
			case 3:
				return "Ctrl";
			case 0:
			case 1:
				return "Shift";
			case 4:
			case 5:
				return "Alt";
			case 6:
			case 7:
				return "Cmd";
			default:
				return ((object)(*(KeyCode*)(&mainKey))/*cast due to .constrained prefix*/).ToString();
			}
		}

		public static bool Repeat(Func<bool> addOne, int count)
		{
			bool result = false;
			for (int i = 0; i < count; i++)
			{
				if (!addOne())
				{
					break;
				}
				result = true;
			}
			return result;
		}
	}
	[HarmonyPatch(typeof(Switch), "Interact")]
	public static class SwitchInteractPatch
	{
		private static bool Prefix(Switch __instance, Humanoid character, bool hold, ref bool __result)
		{
			if (hold || __instance.m_onUse == null || !Fill.IsModifierHeld())
			{
				return true;
			}
			int space = GetSpace(__instance);
			if (space <= 0)
			{
				return true;
			}
			__result = Fill.Repeat(() => __instance.m_onUse.Invoke(__instance, character, (ItemData)null), space);
			return false;
		}

		private static int GetSpace(Switch sw)
		{
			Smelter componentInParent = ((Component)sw).GetComponentInParent<Smelter>();
			if ((Object)(object)componentInParent != (Object)null)
			{
				if (!componentInParent.m_nview.IsValid())
				{
					return 0;
				}
				if ((Object)(object)sw == (Object)(object)componentInParent.m_addOreSwitch)
				{
					return componentInParent.m_maxOre - componentInParent.GetQueueSize();
				}
				if ((Object)(object)sw == (Object)(object)componentInParent.m_addWoodSwitch)
				{
					return Mathf.FloorToInt((float)componentInParent.m_maxFuel - componentInParent.GetFuel());
				}
				return 0;
			}
			CookingStation componentInParent2 = ((Component)sw).GetComponentInParent<CookingStation>();
			if ((Object)(object)componentInParent2 != (Object)null && componentInParent2.m_nview.IsValid() && (Object)(object)sw == (Object)(object)componentInParent2.m_addFuelSwitch)
			{
				return Mathf.FloorToInt((float)componentInParent2.m_maxFuel - componentInParent2.GetFuel());
			}
			ShieldGenerator componentInParent3 = ((Component)sw).GetComponentInParent<ShieldGenerator>();
			if ((Object)(object)componentInParent3 != (Object)null && componentInParent3.m_nview.IsValid() && (Object)(object)sw == (Object)(object)componentInParent3.m_addFuelSwitch)
			{
				return Mathf.FloorToInt((float)componentInParent3.m_maxFuel - componentInParent3.GetFuel());
			}
			return 0;
		}
	}
	[HarmonyPatch(typeof(Fireplace), "Interact")]
	public static class FireplaceInteractPatch
	{
		private static bool filling;

		private static bool Prefix(Fireplace __instance, Humanoid user, bool hold, ref bool alt, ref bool __result)
		{
			if (filling || hold || !Fill.IsModifierHeld())
			{
				return true;
			}
			alt = true;
			if (!__instance.m_canRefill || __instance.m_infiniteFuel || !__instance.m_nview.IsValid())
			{
				return true;
			}
			float num = __instance.m_nview.GetZDO().GetFloat(ZDOVars.s_fuel, 0f);
			int num2 = Mathf.FloorToInt(__instance.m_maxFuel) - Mathf.CeilToInt(num);
			if (num2 <= 0)
			{
				return true;
			}
			filling = true;
			try
			{
				__result = Fill.Repeat(() => __instance.Interact(user, false, true), num2);
			}
			finally
			{
				filling = false;
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(Player), "FindHoverObject")]
	public static class StationHoverPatch
	{
		private static void Postfix(Player __instance, ref GameObject hover)
		{
			//IL_00c4: 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)
			if ((Object)(object)hover == (Object)null || (Object)(object)hover.GetComponentInParent<Switch>() != (Object)null)
			{
				return;
			}
			Hoverable componentInParent = hover.GetComponentInParent<Hoverable>();
			Smelter componentInParent2 = hover.GetComponentInParent<Smelter>();
			CookingStation componentInParent3 = hover.GetComponentInParent<CookingStation>();
			ShieldGenerator componentInParent4 = hover.GetComponentInParent<ShieldGenerator>();
			Switch first;
			Switch second;
			bool vertical;
			if ((Object)(object)componentInParent2 != (Object)null && componentInParent == null)
			{
				first = componentInParent2.m_addOreSwitch;
				second = componentInParent2.m_addWoodSwitch;
				vertical = false;
			}
			else if ((Object)(object)componentInParent3 != (Object)null && (Object)(object)componentInParent3.m_addFoodSwitch != (Object)null && (object)componentInParent == componentInParent3)
			{
				first = componentInParent3.m_addFoodSwitch;
				second = componentInParent3.m_addFuelSwitch;
				vertical = true;
			}
			else
			{
				if (!((Object)(object)componentInParent4 != (Object)null) || componentInParent4.m_enableAttack || (object)componentInParent != componentInParent4)
				{
					return;
				}
				first = componentInParent4.m_addFuelSwitch;
				second = null;
				vertical = false;
			}
			if (GetHitPoint(__instance, out var point))
			{
				Switch val = PickSwitch(first, second, point, hover.transform.up, vertical);
				if ((Object)(object)val != (Object)null)
				{
					hover = ((Component)val).gameObject;
				}
			}
		}

		private static bool GetHitPoint(Player player, out Vector3 point)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: 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)
			RaycastHit[] raycastHoverHits = player.m_raycastHoverHits;
			for (int i = 0; i < raycastHoverHits.Length; i++)
			{
				RaycastHit val = raycastHoverHits[i];
				if ((Object)(object)((RaycastHit)(ref val)).collider == (Object)null)
				{
					break;
				}
				if (!Object.op_Implicit((Object)(object)((RaycastHit)(ref val)).collider.attachedRigidbody) || !((Object)(object)((Component)((RaycastHit)(ref val)).collider.attachedRigidbody).gameObject == (Object)(object)((Component)player).gameObject))
				{
					point = ((RaycastHit)(ref val)).point;
					return true;
				}
			}
			point = Vector3.zero;
			return false;
		}

		private static Switch PickSwitch(Switch first, Switch second, Vector3 point, Vector3 up, bool vertical)
		{
			//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_0032: 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_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: 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)
			//IL_004f: 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_0045: 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_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: 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_006c: 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_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: 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_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			bool flag = IsUsable(first);
			bool flag2 = IsUsable(second);
			if (!flag || !flag2)
			{
				if (!flag)
				{
					if (!flag2)
					{
						return null;
					}
					return second;
				}
				return first;
			}
			Vector3 position = ((Component)first).transform.position;
			Vector3 position2 = ((Component)second).transform.position;
			Vector3 val = position2 - position;
			Vector3 val2 = (vertical ? Vector3.Project(val, up) : Vector3.ProjectOnPlane(val, up));
			if (((Vector3)(ref val2)).sqrMagnitude < 0.0001f)
			{
				val2 = val;
			}
			Vector3 val3 = (position + position2) / 2f;
			if (!(Vector3.Dot(point - val3, val2) < 0f))
			{
				return second;
			}
			return first;
		}

		private static bool IsUsable(Switch sw)
		{
			if ((Object)(object)sw != (Object)null)
			{
				return ((Component)sw).gameObject.activeInHierarchy;
			}
			return false;
		}
	}
	[BepInPlugin("kriona.QuickFill", "Quick Fill", "1.5.0")]
	public class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "kriona.QuickFill";

		public const string PluginName = "Quick Fill";

		public const string PluginVersion = "1.5.0";

		public static ConfigEntry<KeyboardShortcut> ModifierKey;

		private Harmony harmony;

		private ConfigWatcher watcher;

		private void Awake()
		{
			//IL_001a: 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_005a: Expected O, but got Unknown
			ModifierKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("General", "ModifierKey", new KeyboardShortcut((KeyCode)304, Array.Empty<KeyCode>()), "Key to hold while pressing the use key to fill a station - a Unity KeyCode name, e.g. LeftShift, LeftControl or LeftAlt. Either side of Ctrl, Shift, Alt and Command counts, and None turns the fill off");
			watcher = new ConfigWatcher(((BaseUnityPlugin)this).Config, ((BaseUnityPlugin)this).Logger, "Quick Fill");
			harmony = new Harmony("kriona.QuickFill");
			harmony.PatchAll();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Quick Fill 1.5.0 loaded");
		}

		private void Update()
		{
			watcher.Update();
		}

		private void OnDestroy()
		{
			watcher?.Dispose();
			Harmony obj = harmony;
			if (obj != null)
			{
				obj.UnpatchSelf();
			}
		}
	}
	internal static class Tooltip
	{
		public static string FillLine(string action)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			KeyboardShortcut value = Plugin.ModifierKey.Value;
			if ((int)((KeyboardShortcut)(ref value)).MainKey == 0)
			{
				return "";
			}
			return Localization.instance.Localize("\n[<color=yellow><b>" + Fill.GetModifierName() + " + $KEY_Use</b></color>] " + action);
		}
	}
	[HarmonyPatch(typeof(Smelter), "OnHoverAddOre")]
	public static class SmelterOreTooltipPatch
	{
		private static void Postfix(ref string __result)
		{
			__result += Tooltip.FillLine("Fill");
		}
	}
	[HarmonyPatch(typeof(Smelter), "OnHoverAddFuel")]
	public static class SmelterFuelTooltipPatch
	{
		private static void Postfix(Smelter __instance, ref string __result)
		{
			__result += Tooltip.FillLine("Fill with " + __instance.m_fuelItem.m_itemData.m_shared.m_name);
		}
	}
	[HarmonyPatch(typeof(CookingStation), "OnHoverFuelSwitch")]
	public static class CookingStationFuelTooltipPatch
	{
		private static void Postfix(CookingStation __instance, ref string __result)
		{
			__result += Tooltip.FillLine("Fill with " + __instance.m_fuelItem.m_itemData.m_shared.m_name);
		}
	}
	[HarmonyPatch(typeof(ShieldGenerator), "OnHoverAddFuel")]
	public static class ShieldGeneratorFuelTooltipPatch
	{
		private static void Postfix(ref string __result)
		{
			__result += Tooltip.FillLine("Fill with $piece_shieldgenerator_fuelname");
		}
	}
	[HarmonyPatch(typeof(Fireplace), "GetHoverText")]
	public static class FireplaceTooltipPatch
	{
		private static void Postfix(Fireplace __instance, ref string __result)
		{
			if (__instance.m_canRefill && !__instance.m_infiniteFuel && __instance.m_nview.IsValid())
			{
				__result += Tooltip.FillLine("Fill with " + __instance.m_fuelItem.m_itemData.m_shared.m_name);
			}
		}
	}
}
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 + ")";
		}
	}
}