Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of ChestPeek v1.1.0
BepInEx/plugins/ChestPeek/ChestPeek.dll
Decompiled a day agousing System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; 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.1.0.0")] [assembly: AssemblyInformationalVersion("1.1.0")] [assembly: AssemblyProduct("Chest Peek")] [assembly: AssemblyTitle("Chest Peek")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.1.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 ChestPeek { internal static class ChestColors { private enum Fill { Partial, Empty, Full } private static readonly HashSet<string> Chests = new HashSet<string> { "piece_chest_wood", "piece_chest", "piece_chest_private", "piece_chest_barrel", "piece_chest_blackmetal", "piece_chest_grausten", "piece_chest_warderobe" }; private static readonly Dictionary<string, Vector2[][]> Regions = new Dictionary<string, Vector2[][]> { { "woodchest", new Vector2[2][] { (Vector2[])(object)new Vector2[4] { new Vector2(0.46f, 0.77f), new Vector2(0.76f, 0.77f), new Vector2(0.76f, 1f), new Vector2(0.46f, 1f) }, (Vector2[])(object)new Vector2[9] { new Vector2(0.0095f, 0.6895f), new Vector2(0.0116f, 0.6054f), new Vector2(0.012f, 0.5919f), new Vector2(0.0138f, 0.5888f), new Vector2(0.0491f, 0.599f), new Vector2(0.0692f, 0.6237f), new Vector2(0.0689f, 0.6613f), new Vector2(0.045f, 0.6858f), new Vector2(0.0113f, 0.6931f) } } } }; private const int RegionScale = 4; private const float MaskStart = 0.25f; private const float MaskFull = 0.5f; private const float TintBrightness = 0.75f; private static readonly int MainTexId = Shader.PropertyToID("_MainTex"); private static readonly int MetallicTexId = Shader.PropertyToID("_MetallicTex"); private static readonly int MetalColorId = Shader.PropertyToID("_MetalColor"); private static readonly Dictionary<Material, Material> emptyMaterials = new Dictionary<Material, Material>(); private static readonly Dictionary<Material, Material> fullMaterials = new Dictionary<Material, Material>(); private static readonly Dictionary<Material, Material> originals = new Dictionary<Material, Material>(); private static Color? emptyColor; private static Color? fullColor; private static readonly HashSet<Container> changed = new HashSet<Container>(); public static void Track(Container container) { if (container.m_inventory != null && IsChest(container)) { Inventory inventory = container.m_inventory; inventory.m_onChanged = (Action)Delegate.Combine(inventory.m_onChanged, (Action)delegate { changed.Add(container); }); } } public static void Loaded(Container container) { if (container.m_inventory != null && IsChest(container)) { changed.Add(container); } } public static void Update() { if (changed.Count == 0) { return; } foreach (Container item in changed) { Apply(item); } changed.Clear(); } public static void Refresh() { emptyColor = ParseColor(Plugin.EmptyColor.Value, ((ConfigEntryBase)Plugin.EmptyColor).Definition.Key); fullColor = ParseColor(Plugin.FullColor.Value, ((ConfigEntryBase)Plugin.FullColor).Definition.Key); List<Material> list = new List<Material>(originals.Keys); emptyMaterials.Clear(); fullMaterials.Clear(); Container[] array = Object.FindObjectsByType<Container>((FindObjectsSortMode)0); foreach (Container val in array) { if (val.m_inventory != null && IsChest(val)) { Apply(val); } } foreach (Material item in list) { originals.Remove(item); Object.Destroy((Object)(object)item.mainTexture); Object.Destroy((Object)(object)item); } } private static bool IsChest(Container container) { if ((Object)(object)container.m_rootObjectOverride == (Object)null) { return Chests.Contains(Utils.GetPrefabName(((Component)container).gameObject)); } return false; } private static void Apply(Container container) { //IL_00a9: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)container == (Object)null) { return; } Fill fill = GetFill(container.m_inventory); Color? val = fill switch { Fill.Full => fullColor, Fill.Empty => emptyColor, _ => null, }; Renderer[] componentsInChildren = ((Component)container).GetComponentsInChildren<Renderer>(true); foreach (Renderer val2 in componentsInChildren) { Material[] sharedMaterials = val2.sharedMaterials; bool flag = false; for (int j = 0; j < sharedMaterials.Length; j++) { if (!((Object)(object)sharedMaterials[j] == (Object)null)) { Material value; Material val3 = (originals.TryGetValue(sharedMaterials[j], out value) ? value : sharedMaterials[j]); Material val4 = val3; if (val.HasValue) { val4 = GetTinted(val3, (fill == Fill.Empty) ? emptyMaterials : fullMaterials, val.Value) ?? val3; } if ((Object)(object)val4 != (Object)(object)sharedMaterials[j]) { sharedMaterials[j] = val4; flag = true; } } } if (flag) { val2.sharedMaterials = sharedMaterials; } } } private static Fill GetFill(Inventory inventory) { if (inventory.NrOfItems() == 0) { return Fill.Empty; } if (inventory.GetEmptySlots() > 0) { return Fill.Partial; } foreach (ItemData allItem in inventory.GetAllItems()) { if (allItem.m_stack < allItem.m_shared.m_maxStackSize) { return Fill.Partial; } } return Fill.Full; } private static Color? ParseColor(string text, string setting) { //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) text = (text ?? "").Trim(); if (text.Length == 0) { return null; } Color value = default(Color); if (!text.StartsWith("#") && text.Length == 6 && ColorUtility.TryParseHtmlString("#" + text, ref value)) { return value; } Color value2 = default(Color); if (ColorUtility.TryParseHtmlString(text, ref value2)) { return value2; } Plugin.Log.LogWarning((object)(setting + " \"" + text + "\" isn't a color - use a hex color like #FF4040 or a name like red, or leave it blank")); return null; } private static Material GetTinted(Material original, Dictionary<Material, Material> cache, Color color) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) if (cache.TryGetValue(original, out var value)) { return value; } value = (cache[original] = MakeTinted(original, color)); if ((Object)(object)value != (Object)null) { originals[value] = original; } return value; } private static Material MakeTinted(Material original, Color color) { //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0162: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Expected O, but got Unknown //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_0190: Unknown result type (might be due to invalid IL or missing references) //IL_01ba: Unknown result type (might be due to invalid IL or missing references) //IL_01c1: Expected O, but got Unknown //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_0131: 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) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_01fb: Unknown result type (might be due to invalid IL or missing references) if (original.HasProperty(MainTexId)) { Texture texture = original.GetTexture(MainTexId); Texture2D val = (Texture2D)(object)((texture is Texture2D) ? texture : null); if (val != null) { int num = ((!Regions.ContainsKey(((Object)original).name)) ? 1 : 4); int num2 = ((Texture)val).width * num; int num3 = ((Texture)val).height * num; float[] weights = GetWeights(original, num2, num3); if (weights == null) { return null; } Color32[] array = ReadPixels((Texture)(object)val, num2, num3, linear: false); float num4 = 0f; float num5 = 0f; for (int i = 0; i < array.Length; i++) { num4 += weights[i]; num5 += Luminance(array[i]) * weights[i]; } if (num4 < 1f) { return null; } float num6 = Mathf.Max(num5 / num4, 0.01f); for (int j = 0; j < array.Length; j++) { if (!(weights[j] <= 0f)) { float num7 = Mathf.Min(1f, Luminance(array[j]) / num6 * 0.75f); Color val2 = color * num7; val2.a = (float)(int)array[j].a / 255f; array[j] = Color32.op_Implicit(Color.Lerp(Color32.op_Implicit(array[j]), val2, weights[j])); } } Texture2D val3 = new Texture2D(num2, num3, (TextureFormat)4, true, false); ((Object)val3).name = ((Object)val).name + " (Chest Peek)"; ((Texture)val3).filterMode = ((Texture)val).filterMode; ((Texture)val3).wrapMode = ((Texture)val).wrapMode; ((Texture)val3).anisoLevel = ((Texture)val).anisoLevel; val3.SetPixels32(array); val3.Apply(true, true); Material val4 = new Material(original); ((Object)val4).name = ((Object)original).name + " (Chest Peek)"; val4.SetTexture(MainTexId, (Texture)(object)val3); if (val4.HasProperty(MetalColorId)) { val4.SetColor(MetalColorId, Color.white); } return val4; } } return null; } private static float[] GetWeights(Material material, int width, int height) { //IL_0053: Unknown result type (might be due to invalid IL or missing references) float[] array = new float[width * height]; if (Regions.TryGetValue(((Object)material).name, out var value)) { Vector2 point = default(Vector2); for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { ((Vector2)(ref point))..ctor(((float)j + 0.5f) / (float)width, ((float)i + 0.5f) / (float)height); Vector2[][] array2 = value; for (int k = 0; k < array2.Length; k++) { if (Contains(array2[k], point)) { array[i * width + j] = 1f; break; } } } } return array; } if (!material.HasProperty(MetallicTexId)) { return null; } Texture texture = material.GetTexture(MetallicTexId); if ((Object)(object)texture == (Object)null) { return null; } Color32[] array3 = ReadPixels(texture, width, height, linear: true); for (int l = 0; l < array3.Length; l++) { array[l] = Mathf.SmoothStep(0f, 1f, Mathf.InverseLerp(0.25f, 0.5f, (float)(int)array3[l].r / 255f)); } return array; } private static bool Contains(Vector2[] polygon, Vector2 point) { //IL_000e: 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_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_001d: 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_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_003c: 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_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_0056: 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_0065: 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) bool flag = false; int num = 0; int num2 = polygon.Length - 1; while (num < polygon.Length) { Vector2 val = polygon[num]; Vector2 val2 = polygon[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 Color32[] ReadPixels(Texture source, int width, int height, bool linear) { //IL_0029: 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) //IL_003d: 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_0061: Expected O, but got Unknown RenderTexture temporary = RenderTexture.GetTemporary(width, height, 0, (RenderTextureFormat)0, (RenderTextureReadWrite)(linear ? 1 : 2)); RenderTexture active = RenderTexture.active; Graphics.Blit(source, temporary); RenderTexture.active = temporary; Texture2D val = new Texture2D(width, height, (TextureFormat)4, false, linear); val.ReadPixels(new Rect(0f, 0f, (float)width, (float)height), 0, 0); RenderTexture.active = active; RenderTexture.ReleaseTemporary(temporary); Color32[] pixels = val.GetPixels32(); Object.Destroy((Object)val); return pixels; } private static float Luminance(Color32 pixel) { //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_0020: Unknown result type (might be due to invalid IL or missing references) return (0.299f * (float)(int)pixel.r + 0.587f * (float)(int)pixel.g + 0.114f * (float)(int)pixel.b) / 255f; } } [HarmonyPatch(typeof(Container), "Awake")] public static class ContainerAwakePatch { private static void Postfix(Container __instance) { ChestColors.Track(__instance); } } [HarmonyPatch(typeof(Container), "Load")] public static class ContainerLoadPatch { private static void Postfix(Container __instance, bool __result) { if (__result) { ChestColors.Loaded(__instance); } } } [HarmonyPatch(typeof(Container), "GetHoverText")] public static class ContainerContentsPatch { private const int MaxLines = 12; private static void Postfix(Container __instance, ref string __result) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) if (__instance.m_checkGuardStone && !PrivateArea.CheckAccess(((Component)__instance).transform.position, 0f, false, false)) { return; } Dictionary<string, int> dictionary = new Dictionary<string, int>(); foreach (ItemData allItem in __instance.m_inventory.GetAllItems()) { string key = Localization.instance.Localize(allItem.m_shared.m_name); dictionary[key] = (dictionary.TryGetValue(key, out var value) ? value : 0) + allItem.m_stack; } if (dictionary.Count != 0) { List<KeyValuePair<string, int>> list = (from pair in dictionary orderby pair.Value descending, pair.Key select pair).ToList(); int num = ((list.Count > 12) ? 11 : list.Count); StringBuilder stringBuilder = new StringBuilder("\n"); for (int num2 = 0; num2 < num; num2++) { stringBuilder.Append("\n" + list[num2].Key + " <color=orange>x" + list[num2].Value + "</color>"); } if (num < list.Count) { stringBuilder.Append("\n<color=#a0a0a0>+" + (list.Count - num) + " more</color>"); } __result += stringBuilder.ToString(); } } } [BepInPlugin("kriona.ChestPeek", "Chest Peek", "1.1.0")] public class Plugin : BaseUnityPlugin { public const string PluginGuid = "kriona.ChestPeek"; public const string PluginName = "Chest Peek"; public const string PluginVersion = "1.1.0"; public static ConfigEntry<string> EmptyColor; public static ConfigEntry<string> FullColor; internal static ManualLogSource Log; private Harmony harmony; private ConfigWatcher watcher; private void Awake() { //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; EmptyColor = ((BaseUnityPlugin)this).Config.Bind<string>("Chest Colors", "EmptyColor", "", "Color of a chest's metal fittings, or the wood chest's rope rings and front circle, when it holds nothing - a hex color like #00FF00 or a name like green, or blank to leave them unchanged"); FullColor = ((BaseUnityPlugin)this).Config.Bind<string>("Chest Colors", "FullColor", "#FFFF00", "Color of a chest's metal fittings, or the wood chest's rope rings and front circle, when every slot holds a full stack - a hex color like #FFFF00 or a name like yellow, or blank to leave them unchanged"); ChestColors.Refresh(); ((BaseUnityPlugin)this).Config.SettingChanged += OnSettingChanged; watcher = new ConfigWatcher(((BaseUnityPlugin)this).Config, ((BaseUnityPlugin)this).Logger, "Chest Peek"); harmony = new Harmony("kriona.ChestPeek"); harmony.PatchAll(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Chest Peek 1.1.0 loaded"); } private void Update() { watcher.Update(); ChestColors.Update(); } private void OnSettingChanged(object sender, SettingChangedEventArgs args) { ChestColors.Refresh(); } private void OnDestroy() { ((BaseUnityPlugin)this).Config.SettingChanged -= OnSettingChanged; watcher?.Dispose(); Harmony obj = harmony; if (obj != null) { obj.UnpatchSelf(); } } } } 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 + ")"; } } }