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 SkillProgress v1.0.0
BepInEx/plugins/SkillProgress/SkillProgress.dll
Decompiled 3 days agousing 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 + ")"; } } }