Decompiled source of ValHUD v1.2.1

plugins/ValHUD.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using TMPro;
using UnityEngine;
using UnityEngine.TextCore.LowLevel;
using UnityEngine.UI;
using ValHUD.UI;
using ValHUD.Widgets;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("0.0.0.0")]
namespace ValHUD
{
	internal class DivisionRule
	{
		public const string DefaultText = "100:10, 200:20, 25";

		public static readonly DivisionRule Default = Parse("100:10, 200:20, 25");

		private readonly List<float> _limits = new List<float>();

		private readonly List<float> _steps = new List<float>();

		private float _fallback = 25f;

		public float StepFor(float max)
		{
			for (int i = 0; i < _limits.Count; i++)
			{
				if (max <= _limits[i])
				{
					return _steps[i];
				}
			}
			return _fallback;
		}

		public static DivisionRule Parse(string text)
		{
			DivisionRule divisionRule = new DivisionRule();
			bool flag = true;
			string[] array = (text ?? "").Split(new char[1] { ',' });
			foreach (string text2 in array)
			{
				string text3 = text2.Trim();
				if (text3.Length != 0)
				{
					string[] array2 = text3.Split(new char[1] { ':' });
					float v3;
					if (array2.Length == 2 && TryF(array2[0], out var v) && TryF(array2[1], out var v2) && v2 > 0f)
					{
						divisionRule._limits.Add(v);
						divisionRule._steps.Add(v2);
					}
					else if (array2.Length == 1 && TryF(array2[0], out v3) && v3 > 0f)
					{
						divisionRule._fallback = v3;
					}
					else
					{
						flag = false;
					}
				}
			}
			divisionRule.SortByLimit();
			if (!flag)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("ValHUD: could not read DivisionRule \"" + text + "\", using \"100:10, 200:20, 25\"."));
				}
				return (text == "100:10, 200:20, 25") ? divisionRule : Parse("100:10, 200:20, 25");
			}
			return divisionRule;
		}

		private void SortByLimit()
		{
			for (int i = 1; i < _limits.Count; i++)
			{
				int num = i;
				while (num > 0 && _limits[num] < _limits[num - 1])
				{
					float value = _limits[num];
					_limits[num] = _limits[num - 1];
					_limits[num - 1] = value;
					float value2 = _steps[num];
					_steps[num] = _steps[num - 1];
					_steps[num - 1] = value2;
					num--;
				}
			}
		}

		private static bool TryF(string s, out float v)
		{
			return float.TryParse(s.Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out v);
		}
	}
	internal sealed class ConfigurationManagerAttributes
	{
		public int? Order;

		public bool? Browsable;

		public bool? HideSettingName;

		public bool? HideDefaultButton;

		public Action<ConfigEntryBase> CustomDrawer;
	}
	internal abstract class ElementConfig
	{
		protected readonly ConfigFile Cfg;

		protected readonly string Section;

		private int _order = 1000;

		public readonly List<ConfigEntryBase> LayoutOnly = new List<ConfigEntryBase>();

		public readonly List<ConfigEntryBase> All = new List<ConfigEntryBase>();

		protected ConfigEntry<float> TextOutlineWidth;

		protected ConfigEntry<float> TextShadowOffset;

		protected ConfigEntry<float> TextShadowSoftness;

		protected ConfigEntry<Color> TextOutlineColor;

		protected ConfigEntry<Color> TextShadowColor;

		protected ConfigEntry<bool> TextShadow;

		protected ConfigEntry<bool> ShadowEnabled;

		protected ConfigEntry<bool> GlowEnabled;

		protected ConfigEntry<Color> ShadowColor;

		protected ConfigEntry<Color> GlowColor;

		protected ConfigEntry<float> ShadowOffsetX;

		protected ConfigEntry<float> ShadowOffsetY;

		protected ConfigEntry<float> GlowSize;

		protected ConfigEntry<float> GlowIntensity;

		protected ElementConfig(ConfigFile cfg, string section)
		{
			Cfg = cfg;
			Section = section;
		}

		protected ConfigEntry<float> F(string key, float def, float min, float max, string desc, bool layout = false)
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Expected O, but got Unknown
			ConfigEntry<float> val = Cfg.Bind<float>(Section, key, def, new ConfigDescription(desc, (AcceptableValueBase)(object)new AcceptableValueRange<float>(min, max), new object[1] { NextOrder() }));
			Track((ConfigEntryBase)(object)val, layout);
			return val;
		}

		protected ConfigEntry<T> B<T>(string key, T def, string desc, bool layout = false)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Expected O, but got Unknown
			ConfigEntry<T> val = Cfg.Bind<T>(Section, key, def, new ConfigDescription(desc, (AcceptableValueBase)null, new object[1] { NextOrder() }));
			Track((ConfigEntryBase)(object)val, layout);
			return val;
		}

		private ConfigurationManagerAttributes NextOrder()
		{
			return new ConfigurationManagerAttributes
			{
				Order = _order--
			};
		}

		private void Track(ConfigEntryBase e, bool layout)
		{
			All.Add(e);
			if (layout)
			{
				LayoutOnly.Add(e);
			}
		}

		protected void BindText(string what, TextStyle d)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			TextOutlineWidth = F("TextOutlineWidth", d.OutlineWidth, 0f, 1f, "Dark outline around " + what + "; it keeps the text readable on bright backgrounds such as snow. 0 = none, 0.2 = thin, 0.5 = thick.");
			TextOutlineColor = B<Color>("TextOutlineColor", d.OutlineColor, "Color of the outline around " + what + " (see TextOutlineWidth).");
			TextShadow = B("TextShadow", d.Shadow, "Drop shadow under " + what + ". TextShadowOffset and TextShadowSoftness shape it.");
			TextShadowColor = B<Color>("TextShadowColor", d.ShadowColor, "Color of the shadow under " + what + "; its alpha (the last two digits) is how dark it is.");
			TextShadowOffset = F("TextShadowOffset", d.ShadowOffset, 0f, 1f, "How far the shadow of " + what + " falls, down and to the right. 0 = right under the text.");
			TextShadowSoftness = F("TextShadowSoftness", d.ShadowSoftness, 0f, 1f, "Blur of the shadow under " + what + ": 0 = sharp, 1 = very soft.");
		}

		protected TextStyle ResolveText(Color color)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			return new TextStyle
			{
				Color = color,
				OutlineWidth = TextOutlineWidth.Value,
				OutlineColor = TextOutlineColor.Value,
				Shadow = TextShadow.Value,
				ShadowColor = TextShadowColor.Value,
				ShadowOffset = TextShadowOffset.Value,
				ShadowSoftness = TextShadowSoftness.Value
			};
		}

		protected void BindEffects(EffectSpec d)
		{
			//IL_0026: 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)
			ShadowEnabled = B("ShadowEnabled", d.Shadow, "Drop shadow under this element's shape (the texts have their own, see TextShadow).");
			ShadowColor = B<Color>("ShadowColor", d.ShadowColor, "Color of the drop shadow; its alpha (the last two digits) is how dark it is.");
			ShadowOffsetX = F("ShadowOffsetX", d.ShadowOffset.x, -30f, 30f, "How far the drop shadow falls sideways (positive = right). It falls the same way on screen even when the element is rotated, vertical or reversed.");
			ShadowOffsetY = F("ShadowOffsetY", d.ShadowOffset.y, -30f, 30f, "How far the drop shadow falls up or down (negative = down).");
			GlowEnabled = B("GlowEnabled", d.Glow, "Soft glow around this element's shape. GlowColor, GlowSize and GlowIntensity shape it.");
			GlowColor = B<Color>("GlowColor", d.GlowColor, "Color of the glow; its alpha (the last two digits) is how strong it is. Example: FFD27F73 = warm gold at about 45 %.");
			GlowSize = F("GlowSize", d.GlowSize, 1f, 80f, "How far the glow spreads out from the edge.");
			GlowIntensity = F("GlowIntensity", d.GlowIntensity, 0f, 3f, "How the glow fades: 1 = evenly from GlowColor to transparent; up to 3 = brighter, with a solid band close to the edge; below 1 = fainter.");
		}

		protected EffectSpec ResolveEffects()
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			return new EffectSpec
			{
				Shadow = ShadowEnabled.Value,
				ShadowColor = ShadowColor.Value,
				ShadowOffset = new Vector2(ShadowOffsetX.Value, ShadowOffsetY.Value),
				Glow = GlowEnabled.Value,
				GlowColor = GlowColor.Value,
				GlowSize = GlowSize.Value,
				GlowIntensity = GlowIntensity.Value
			};
		}
	}
	internal class BarConfig : ElementConfig
	{
		public readonly ConfigEntry<bool> Visible;

		public readonly ConfigEntry<bool> ShowValue;

		public readonly ConfigEntry<bool> ShowIcon;

		public readonly ConfigEntry<bool> ScaleLengthWithMax;

		public readonly ConfigEntry<bool> ShineEnabled;

		public readonly ConfigEntry<bool> Divisions;

		public readonly ConfigEntry<bool> ForceVisible;

		public readonly ConfigEntry<bool> AutoHide;

		public readonly ConfigEntry<float> AutoHideDelay;

		public readonly ConfigEntry<float> FadeTime;

		public readonly ConfigEntry<HudAnchor> Anchor;

		public readonly ConfigEntry<float> X;

		public readonly ConfigEntry<float> Y;

		public readonly ConfigEntry<float> Rotation;

		public readonly ConfigEntry<float> Length;

		public readonly ConfigEntry<float> Thickness;

		public readonly ConfigEntry<float> StartSlant;

		public readonly ConfigEntry<float> EndSlant;

		public readonly ConfigEntry<float> ScaleFullAt;

		public readonly ConfigEntry<float> OutlineThickness;

		public readonly ConfigEntry<float> ValueFontSize;

		public readonly ConfigEntry<float> ValueX;

		public readonly ConfigEntry<float> ValueY;

		public readonly ConfigEntry<float> IconX;

		public readonly ConfigEntry<float> IconY;

		public readonly ConfigEntry<float> IconSize;

		public readonly ConfigEntry<float> ShineStrength;

		public readonly ConfigEntry<float> DivisionWidth;

		public readonly ConfigEntry<BarOrientation> Orientation;

		public readonly ConfigEntry<FillDirection> Direction;

		public readonly ConfigEntry<BarEnd> StartShape;

		public readonly ConfigEntry<BarEnd> EndShape;

		public readonly ConfigEntry<GradientDirection> Gradient;

		public readonly ConfigEntry<Color> Color;

		public readonly ConfigEntry<Color> ColorEnd;

		public readonly ConfigEntry<Color> Background;

		public readonly ConfigEntry<Color> OutlineColor;

		public readonly ConfigEntry<Color> TrailColor;

		public readonly ConfigEntry<Color> ValueColor;

		public readonly ConfigEntry<Color> IconColor;

		public readonly ConfigEntry<Color> DivisionColor;

		public readonly ConfigEntry<string> ValueFormat;

		public readonly ConfigEntry<string> IconFile;

		public readonly ConfigEntry<string> DivisionRuleText;

		public readonly ConfigEntry<BarPoint> ValueAttach;

		public readonly ConfigEntry<BarPoint> IconAttach;

		public readonly ConfigEntry<bool> IconShadow;

		public readonly ConfigEntry<bool> IconGlow;

		public readonly ConfigEntry<Color> IconShadowColor;

		public readonly ConfigEntry<Color> IconOutlineColor;

		public readonly ConfigEntry<Color> IconGlowColor;

		public readonly ConfigEntry<float> IconShadowOffsetX;

		public readonly ConfigEntry<float> IconShadowOffsetY;

		public readonly ConfigEntry<float> IconOutlineWidth;

		public readonly ConfigEntry<float> IconGlowSize;

		public readonly ConfigEntry<float> IconGlowIntensity;

		public readonly ConfigEntry<TextAlign> ValueAlign;

		public BarConfig(ConfigFile cfg, string section, BarSpec d, bool optional = false)
			: base(cfg, section)
		{
			//IL_0294: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_032f: Unknown result type (might be due to invalid IL or missing references)
			//IL_034c: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0446: Unknown result type (might be due to invalid IL or missing references)
			//IL_0547: Unknown result type (might be due to invalid IL or missing references)
			//IL_05ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_0688: Unknown result type (might be due to invalid IL or missing references)
			//IL_06c2: Unknown result type (might be due to invalid IL or missing references)
			Visible = B("Visible", def: true, "Shows this bar. Eitr and adrenaline only appear while your character has some (like the vanilla bars); use ForceVisible to see them anyway while designing.");
			if (optional)
			{
				ForceVisible = B("ForceVisible", def: false, "For designing your HUD: shows this bar filled to 75 % even when your character has none, so you can place and style it. Only the drawing changes; your real values are never touched. Turn it off when you are done. Not saved in layouts.");
			}
			AutoHide = B("AutoHide", d.AutoHide, "Hides this bar while it has nothing to show, like the vanilla stamina bar does. Health, Stamina and Eitr hide when they are full and come back as soon as they drop. Adrenaline hides when it is 0 and appears as soon as you gain some. Off = the bar is always shown. Turn it off while you place and style the bar. Not saved in layouts, so loading a layout never changes it.");
			AutoHideDelay = F("AutoHideDelay", d.AutoHideDelay, 0f, 30f, "AutoHide only: seconds the bar stays after it becomes full (or empty, for adrenaline) before it starts to fade. Example: 3 = you still see it for 3 seconds. 0 = it starts fading right away. Not saved in layouts.");
			FadeTime = F("FadeTime", d.FadeTime, 0f, 5f, "AutoHide only: seconds the bar takes to fade out and back in. 0 = it disappears and reappears instantly. Not saved in layouts.");
			Anchor = B("Anchor", d.Anchor, "The screen point this bar is positioned from: a corner, the middle of the top or bottom edge, or the Center. X and Y move the bar away from it. Example: BottomCenter with X = 0 and Y = 100 puts the bar's start in the middle of the screen, 100 above the bottom edge. Picking the nearest corner or edge keeps the bar there on any screen size.", layout: true);
			X = F("X", d.X, -4000f, 4000f, "Horizontal distance from Anchor to the bar's start, the end where the fill begins (positive = right). Every distance is multiplied by General > Scale. With FillDirection = Reversed, the start of a horizontal bar is its right end.", layout: true);
			Y = F("Y", d.Y, -4000f, 4000f, "Vertical distance from Anchor to the bar's start (positive = up). With FillDirection = Reversed, the start of a vertical bar is its top end.", layout: true);
			Rotation = F("Rotation", d.Rotation, -180f, 180f, "Turns the whole bar, with its value and icon, around its start, in degrees (positive = counter-clockwise). Example: 90 makes a horizontal bar point up; 5 or -5 gives it a slight tilt.", layout: true);
			Orientation = B("Orientation", d.Orientation, "Horizontal or Vertical. Together with FillDirection it sets which way the bar fills: Horizontal + Normal = left to right, Horizontal + Reversed = right to left, Vertical + Normal = bottom to top, Vertical + Reversed = top to bottom.");
			Direction = B("FillDirection", d.Direction, "Normal or Reversed: which end the bar fills from (Orientation lists the four combinations). StartShape is always the end where the fill begins and EndShape the far end, so a reversed bar keeps its shapes pointing the right way.");
			Length = F("Length", d.Length, 20f, 2000f, "Length of the bar along its fill direction. With ScaleLengthWithMax on, this is the longest it gets.");
			Thickness = F("Thickness", d.Thickness, 2f, 200f, "How thick the bar is, across its fill direction.");
			StartShape = B("StartShape", d.StartShape, "Shape of the end where the fill starts: Flat |, Forward /, Backward \\, Notch > (cut into the bar) or Point < (a tip sticking out). StartSlant sets how far the shape reaches into the bar.");
			StartSlant = F("StartSlant", d.StartSlant, 0f, 300f, "How far the start shape reaches into the bar (0 = flat). For Point and Notch, about half the Thickness looks balanced.");
			EndShape = B("EndShape", d.EndShape, "Shape of the far end: Flat |, Forward /, Backward \\, Notch < (cut into the bar) or Point > (a tip sticking out). EndSlant sets how far it reaches. Examples: Forward on both ends with the same slant = a parallelogram; Point on both ends = a long hexagon.");
			EndSlant = F("EndSlant", d.EndSlant, 0f, 300f, "How far the far-end shape reaches into the bar (0 = flat). For Point and Notch, about half the Thickness looks balanced.");
			ScaleLengthWithMax = B("ScaleLengthWithMax", def: false, "Makes the bar grow with your max value, like the vanilla bars: its length is Length x (max / ScaleFullAt), never more than Length. Example: Length 600 and ScaleFullAt 300 with 150 max health = a bar 300 long; from 300 max health on, it stays at 600.");
			ScaleFullAt = F("ScaleFullAt", d.ScaleFullAt, 10f, 2000f, "ScaleLengthWithMax only: the max value at which the bar reaches its full Length. Lower = it reaches full length sooner.");
			Color = B<Color>("Color", d.Color, "Fill color. With a Gradient, the color the gradient starts from (ColorEnd is where it ends).");
			ColorEnd = B<Color>("ColorEnd", d.ColorEnd, "Second fill color, only used when Gradient is not None.");
			Gradient = B("Gradient", d.Gradient, "How Color and ColorEnd blend. None = solid Color. Horizontal = along the bar: Color at the start, ColorEnd at the far end (it follows FillDirection). Vertical = across the bar's thickness: Color on one edge, ColorEnd on the other.");
			Background = B<Color>("BackgroundColor", d.Background, "Color of the empty part of the bar, behind the fill. Colors are RRGGBBAA: the last two digits are the opacity, e.g. 0000008C = black at 55 %, 00000000 = invisible.");
			OutlineThickness = F("OutlineThickness", d.OutlineThickness, 0f, 30f, "A solid line around the whole bar, drawn outside its edge so it never covers the fill (0 = none). OutlineColor sets its color.");
			OutlineColor = B<Color>("OutlineColor", d.OutlineColor, "Color of the outline (see OutlineThickness).");
			TrailColor = B<Color>("TrailColor", d.TrailColor, "When you lose health or use stamina, the part you lost stays visible in this color for about half a second, then slides down to the new value (like the vanilla bars). A low alpha makes it subtle; alpha 00 turns it off.");
			Divisions = B("Divisions", d.Divisions, "Draws marks across the bar every N points, like a ruler, so you can read the value at a glance. DivisionRule picks N from the max value.");
			DivisionRuleText = B("DivisionRule", "100:10, 200:20, 25", "How far apart the marks are, depending on the bar's max value. Format: limit:step pairs, then one step for anything above. Example \"100:10, 200:20, 25\": max up to 100 = a mark every 10, up to 200 = every 20, above 200 = every 25. The order of the pairs does not matter. A rule that can't be read falls back to the default (the log says so).");
			DivisionColor = B<Color>("DivisionColor", d.DivisionColor, "Color of the division marks (see Divisions).");
			DivisionWidth = F("DivisionWidth", d.DivisionWidth, 0.5f, 10f, "Width of each division mark.");
			ShowValue = B("ShowValue", def: true, "Shows the bar's number. ValueFormat sets what it says; ValueAttach, ValueAlign, ValueX and ValueY where it sits.");
			ValueFormat = B("ValueFormat", "{0}", "What the number says: {0} = current value, {1} = max. Examples: \"{0}\" shows 85, \"{0}/{1}\" shows 85/120, \"{0} HP\" shows 85 HP. Any other text is shown as written. A format that can't be used falls back to {0} (the log says so).");
			ValueFontSize = F("ValueFontSize", d.ValueFontSize, 6f, 96f, "Size of the number.");
			ValueColor = B<Color>("ValueColor", d.Text.Color, "Color of the number.");
			ValueAttach = B("ValueAttach", d.ValueAttach, "Which point of the bar the number is placed from, as seen on screen: Left, Right, Top or Bottom = the middle of that side; Center = the middle of the bar, on top of the fill. It follows the bar as its length changes. Picking one puts the number just outside that side and sets ValueAlign to match; ValueX and ValueY then fine-tune it.");
			ValueAlign = B("ValueAlign", d.ValueAlign, "Which part of the number sits on its point: Left = it starts there and grows to the right, Right = it ends there and grows to the left, Center = centered on it. Example: a number to the right of the bar reads best with Left, one to its left with Right.");
			ValueX = F("ValueX", d.ValueX, -2000f, 2000f, "Moves the number sideways from its ValueAttach point (positive = right). It turns with the bar's Rotation.");
			ValueY = F("ValueY", d.ValueY, -2000f, 2000f, "Moves the number up or down from its ValueAttach point (positive = up). It turns with the bar's Rotation.");
			ShowIcon = B("ShowIcon", def: true, "Shows the bar's icon: the PNG in IconFile, or the built-in one.");
			IconFile = B("IconFile", d.IconFile, "A PNG in plugins/ValHUD/icons, e.g. \"first-aid.png\" (.png can be left out; subfolders work, e.g. \"mine/heart.png\"). Draw it white on a transparent background: IconColor tints it. Empty = the built-in icon (a cross, a bolt or a ring). A missing file also falls back to the built-in icon (the log says so).");
			IconSize = F("IconSize", d.IconSize, 2f, 200f, "Size of the icon.");
			IconColor = B<Color>("IconColor", d.IconColor, "Color the icon is tinted with. White keeps a PNG's own colors.");
			IconAttach = B("IconAttach", d.IconAttach, "Which point of the bar the icon is placed from, as seen on screen: Left, Right, Top or Bottom = the middle of that side; Center = the middle of the bar. Picking one puts the icon just outside that side; IconX and IconY then fine-tune it.");
			IconX = F("IconX", d.IconX, -2000f, 2000f, "Moves the icon sideways from its IconAttach point (positive = right).");
			IconY = F("IconY", d.IconY, -2000f, 2000f, "Moves the icon up or down from its IconAttach point (positive = up).");
			IconShadow = B("IconShadow", d.IconShadow, "Drop shadow under the icon, separate from the bar's own shadow.");
			IconShadowColor = B<Color>("IconShadowColor", d.IconShadowColor, "Color of the icon's drop shadow.");
			IconShadowOffsetX = F("IconShadowOffsetX", d.IconShadowOffset.x, -20f, 20f, "How far the icon's shadow falls sideways (positive = right).");
			IconShadowOffsetY = F("IconShadowOffsetY", d.IconShadowOffset.y, -20f, 20f, "How far the icon's shadow falls up or down (negative = down).");
			IconOutlineWidth = F("IconOutlineWidth", d.IconOutlineWidth, 0f, 10f, "A solid line around the icon's own shape (it follows the drawing, not a box). 0 = none. PNG icons only.");
			IconOutlineColor = B<Color>("IconOutlineColor", d.IconOutlineColor, "Color of the icon's outline.");
			IconGlow = B("IconGlow", d.IconGlow, "A soft glow around the icon's own shape, separate from the bar's glow. PNG icons only.");
			IconGlowColor = B<Color>("IconGlowColor", d.IconGlowColor, "Color of the icon's glow; its alpha (the last two digits) is how strong it is.");
			IconGlowSize = F("IconGlowSize", d.IconGlowSize, 1f, 40f, "How far the icon's glow spreads.");
			IconGlowIntensity = F("IconGlowIntensity", d.IconGlowIntensity, 0f, 3f, "How the icon's glow fades: 1 = soft; up to 3 = brighter and more solid near the icon; below 1 = fainter.");
			BindText("the value", d.Text);
			BindEffects(d.Fx);
			ShineEnabled = B("ShineEnabled", d.Fx.Shine, "A glossy look on the fill: a light band across the top and a soft shade along the bottom, like glass.");
			ShineStrength = F("ShineStrength", d.Fx.ShineStrength, 0f, 1f, "How strong the shine is: 0 = none, 1 = strongest.");
		}

		public BarSpec Resolve()
		{
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_0132: Unknown result type (might be due to invalid IL or missing references)
			//IL_0137: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: Unknown result type (might be due to invalid IL or missing references)
			//IL_0159: Unknown result type (might be due to invalid IL or missing references)
			//IL_0176: Unknown result type (might be due to invalid IL or missing references)
			//IL_017b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a9: 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_02e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0303: Unknown result type (might be due to invalid IL or missing references)
			//IL_0308: Unknown result type (might be due to invalid IL or missing references)
			//IL_0314: Unknown result type (might be due to invalid IL or missing references)
			//IL_0319: Unknown result type (might be due to invalid IL or missing references)
			//IL_0337: Unknown result type (might be due to invalid IL or missing references)
			//IL_034d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0352: Unknown result type (might be due to invalid IL or missing references)
			BarSpec barSpec = new BarSpec
			{
				Visible = Visible.Value,
				ShowValue = ShowValue.Value,
				ShowIcon = ShowIcon.Value,
				AutoHide = AutoHide.Value,
				AutoHideDelay = AutoHideDelay.Value,
				FadeTime = FadeTime.Value,
				ValueFormat = ValueFormat.Value,
				ScaleLengthWithMax = ScaleLengthWithMax.Value,
				ScaleFullAt = ScaleFullAt.Value,
				Gradient = Gradient.Value,
				TrailColor = TrailColor.Value,
				IconFile = IconFile.Value,
				Divisions = Divisions.Value,
				DivisionRule = DivisionRule.Parse(DivisionRuleText.Value),
				IconShadow = IconShadow.Value,
				IconShadowColor = IconShadowColor.Value,
				IconShadowOffset = new Vector2(IconShadowOffsetX.Value, IconShadowOffsetY.Value),
				IconOutlineWidth = IconOutlineWidth.Value,
				IconOutlineColor = IconOutlineColor.Value,
				IconGlow = IconGlow.Value,
				IconGlowColor = IconGlowColor.Value,
				IconGlowSize = IconGlowSize.Value,
				IconGlowIntensity = IconGlowIntensity.Value,
				DivisionColor = DivisionColor.Value,
				DivisionWidth = DivisionWidth.Value
			};
			barSpec.Fx = ResolveEffects();
			barSpec.Fx.Shine = ShineEnabled.Value;
			barSpec.Fx.ShineStrength = ShineStrength.Value;
			barSpec.Anchor = Anchor.Value;
			barSpec.X = X.Value;
			barSpec.Y = Y.Value;
			barSpec.Rotation = Rotation.Value;
			barSpec.Orientation = Orientation.Value;
			barSpec.Direction = Direction.Value;
			barSpec.Length = Length.Value;
			barSpec.Thickness = Thickness.Value;
			barSpec.StartShape = StartShape.Value;
			barSpec.StartSlant = StartSlant.Value;
			barSpec.EndShape = EndShape.Value;
			barSpec.EndSlant = EndSlant.Value;
			barSpec.ValueFontSize = ValueFontSize.Value;
			barSpec.Color = Color.Value;
			barSpec.ColorEnd = ColorEnd.Value;
			barSpec.Background = Background.Value;
			barSpec.OutlineColor = OutlineColor.Value;
			barSpec.OutlineThickness = OutlineThickness.Value;
			barSpec.Text = ResolveText(ValueColor.Value);
			barSpec.IconColor = IconColor.Value;
			barSpec.IconSize = IconSize.Value;
			barSpec.ValueAttach = ValueAttach.Value;
			barSpec.ValueAlign = ValueAlign.Value;
			barSpec.ValueX = ValueX.Value;
			barSpec.ValueY = ValueY.Value;
			barSpec.IconAttach = IconAttach.Value;
			barSpec.IconX = IconX.Value;
			barSpec.IconY = IconY.Value;
			return barSpec;
		}

		public void ResetValuePlacement()
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			float num = Mathf.Max(4f, ValueFontSize.Value * 0.3f);
			Vector2 val = Outward(ValueAttach.Value);
			ValueX.Value = val.x * num;
			ValueY.Value = val.y * (num + ValueFontSize.Value * 0.5f);
			ValueAlign.Value = ((!(val.x > 0f)) ? ((!(val.x < 0f)) ? TextAlign.Center : TextAlign.Right) : TextAlign.Left);
		}

		public void ResetIconPlacement()
		{
			//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_0046: 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)
			float num = Mathf.Max(4f, ValueFontSize.Value * 0.3f) + IconSize.Value * 0.5f;
			Vector2 val = Outward(IconAttach.Value);
			IconX.Value = val.x * num;
			IconY.Value = val.y * num;
		}

		private static Vector2 Outward(BarPoint p)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: 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_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: 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_003e: 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)
			return (Vector2)(p switch
			{
				BarPoint.Left => Vector2.left, 
				BarPoint.Right => Vector2.right, 
				BarPoint.Top => Vector2.up, 
				BarPoint.Bottom => Vector2.down, 
				_ => Vector2.zero, 
			});
		}

		public static void CopyGeometry(BarSpec from, BarSpec to)
		{
			to.Anchor = from.Anchor;
			to.X = from.X;
			to.Y = from.Y;
			to.Rotation = from.Rotation;
			to.Orientation = from.Orientation;
			to.Direction = from.Direction;
			to.Length = from.Length;
			to.Thickness = from.Thickness;
			to.StartShape = from.StartShape;
			to.StartSlant = from.StartSlant;
			to.EndShape = from.EndShape;
			to.EndSlant = from.EndSlant;
			to.ValueFontSize = from.ValueFontSize;
			to.ValueAttach = from.ValueAttach;
			to.ValueAlign = from.ValueAlign;
			to.ValueX = from.ValueX;
			to.ValueY = from.ValueY;
			to.IconAttach = from.IconAttach;
			to.IconX = from.IconX;
			to.IconY = from.IconY;
			to.IconSize = from.IconSize;
		}
	}
	internal class PowerGlowConfig : ElementConfig
	{
		public readonly string Key;

		public readonly ConfigEntry<bool> UseOwnGlow;

		public readonly ConfigEntry<Color> Tint;

		public readonly ConfigEntry<Color> OutlineColor;

		public readonly ConfigEntry<float> Radius;

		public readonly ConfigEntry<float> Strength;

		public readonly ConfigEntry<float> OutlineWidth;

		public PowerGlowConfig(ConfigFile cfg, string section, string key, string boss, Color tint, float radius, float strength, float outlineWidth, Color outlineColor)
			: base(cfg, section)
		{
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			Key = key;
			UseOwnGlow = B("UseOwnGlow", def: true, "On: while " + boss + "'s power is selected, its glow uses the GlowColor, GlowSize and GlowIntensity below. Off: it uses the glow of 05. Forsaken Power. Either way the glow only shows when 05. Forsaken Power has GlowEnabled or GlowWhenReady on. OutlineWidth and OutlineColor below apply in both cases.");
			Tint = B<Color>("GlowColor", tint, "Glow color for " + boss + "; its alpha (the last two digits) is how strong it is.");
			Radius = F("GlowSize", radius, 1f, 80f, "How far the glow spreads around " + boss + "'s icon.");
			Strength = F("GlowIntensity", strength, 0f, 3f, "How " + boss + "'s glow fades: 1 = evenly to transparent; up to 3 = brighter, with a solid band close to the icon; below 1 = fainter.");
			OutlineWidth = F("OutlineWidth", outlineWidth, 0f, 12f, "A solid line around " + boss + "'s icon, following its shape (0 = none). Helps an icon that gets lost against the slot or the world. It is used whether UseOwnGlow is on or off.");
			OutlineColor = B<Color>("OutlineColor", outlineColor, "Color of the line around " + boss + "'s icon (see OutlineWidth).");
		}
	}
	internal class SlotConfig : ElementConfig
	{
		private readonly bool _guardian;

		public readonly ConfigEntry<bool> Visible;

		public readonly ConfigEntry<bool> ShowBackground;

		public readonly ConfigEntry<GlowAround> GlowAround;

		public readonly ConfigEntry<bool> ShowName;

		public readonly ConfigEntry<bool> GlowWhenReady;

		public readonly ConfigEntry<bool> ReadyGlowPulse;

		public readonly ConfigEntry<bool> CustomIcons;

		public readonly ConfigEntry<bool> ShowWhenEmpty;

		public readonly ConfigEntry<bool> ApplyStyleToOtherFoods;

		public readonly ConfigEntry<EdibleStyle> EdibleStyle;

		public readonly ConfigEntry<BlinkSpeed> BlinkSpeed;

		public readonly ConfigEntry<float> EdibleOpacity;

		public readonly ConfigEntry<HudAnchor> Anchor;

		public readonly ConfigEntry<float> X;

		public readonly ConfigEntry<float> Y;

		public readonly ConfigEntry<float> Rotation;

		public readonly ConfigEntry<float> Size;

		public readonly ConfigEntry<float> BorderWidth;

		public readonly ConfigEntry<float> IconSize;

		public readonly ConfigEntry<float> IconX;

		public readonly ConfigEntry<float> IconY;

		public readonly ConfigEntry<float> LabelFontSize;

		public readonly ConfigEntry<float> LabelX;

		public readonly ConfigEntry<float> LabelY;

		public readonly ConfigEntry<float> NameFontSize;

		public readonly ConfigEntry<float> NameX;

		public readonly ConfigEntry<float> NameY;

		public readonly ConfigEntry<SlotShape> Shape;

		public readonly ConfigEntry<GradientDirection> Gradient;

		public readonly ConfigEntry<Color> Color;

		public readonly ConfigEntry<Color> ColorEnd;

		public readonly ConfigEntry<Color> BorderColor;

		public readonly ConfigEntry<Color> TextColor;

		public readonly ConfigEntry<Color> EmptyMarkerColor;

		public SlotConfig(ConfigFile cfg, string section, SlotSpec d, bool isGuardian)
			: base(cfg, section)
		{
			//IL_0152: Unknown result type (might be due to invalid IL or missing references)
			//IL_016f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0295: Unknown result type (might be due to invalid IL or missing references)
			//IL_0486: Unknown result type (might be due to invalid IL or missing references)
			_guardian = isGuardian;
			string text = (isGuardian ? "power" : "food");
			string text2 = (isGuardian ? "cooldown" : "timer");
			Visible = B("Visible", def: true, "Shows this " + text + " slot.");
			Anchor = B("Anchor", d.Anchor, "The screen point this slot is positioned from: a corner, the middle of the top or bottom edge, or the Center. X and Y move the slot's center away from it. Example: BottomCenter with X = -170 and Y = 220 = left of the middle, 220 above the bottom edge.", layout: true);
			X = F("X", d.X, -4000f, 4000f, "Horizontal distance from Anchor to the slot's center (positive = right). Every distance is multiplied by General > Scale.", layout: true);
			Y = F("Y", d.Y, -4000f, 4000f, "Vertical distance from Anchor to the slot's center (positive = up).", layout: true);
			Rotation = F("Rotation", d.Rotation, -180f, 180f, "Turns the whole slot, with its icon and texts, around its center, in degrees (positive = counter-clockwise).", layout: true);
			Size = F("Size", d.Size, 16f, 600f, "Width and height of the slot. The icon and texts have their own sizes and positions, measured from the slot's center.");
			Shape = B("Shape", d.Shape, "Diamond, Square or Circle.");
			ShowBackground = B("ShowBackground", d.ShowBackground, "Draws the slot's fill and border. Off = only the icon and its texts float on screen; GlowAround = Icon then makes the glow hug the icon.");
			Color = B<Color>("Color", d.Color, "Fill color. With a Gradient, the color the gradient starts from (ColorEnd is where it ends).");
			ColorEnd = B<Color>("ColorEnd", d.ColorEnd, "Second fill color, only used when Gradient is not None.");
			Gradient = B("Gradient", d.Gradient, "How Color and ColorEnd blend. None = solid Color. Horizontal = Color on the left, ColorEnd on the right. Vertical = Color at the top, ColorEnd at the bottom (both turn with Rotation).");
			BorderWidth = F("BorderWidth", d.BorderWidth, 0f, 30f, "Thickness of the border, drawn inside the slot's edge (0 = none). The fill shrinks to fit inside it, so a see-through fill is never tinted by the border.");
			BorderColor = B<Color>("BorderColor", d.BorderColor, "Color of the border (see BorderWidth).");
			IconSize = F("IconSize", d.IconSize, 2f, 400f, "Size of the " + text + " icon. About 35 to 45 % of Size fits most shapes.");
			IconX = F("IconX", d.IconX, -1000f, 1000f, "Moves the icon sideways from the slot's center (positive = right).");
			IconY = F("IconY", d.IconY, -1000f, 1000f, "Moves the icon up or down from the slot's center (positive = up).");
			if (isGuardian)
			{
				CustomIcons = B("CustomIcons", d.CustomIcons, "Uses your own picture for a Forsaken power when plugins/ValHUD/icons/powers/<power>.png exists, e.g. GP_Eikthyr.png or GP_TheElder.png. The file names are the same in every game language; the first time you select a power, the log says which name it looks for.");
			}
			TextColor = B<Color>("TextColor", d.Text.Color, "Color of this slot's texts (the " + text2 + (isGuardian ? " and the name)." : ")."));
			LabelFontSize = F("LabelFontSize", d.LabelFontSize, 4f, 120f, "Size of the " + text2 + ".");
			LabelX = F("LabelX", d.LabelX, -1000f, 1000f, "Moves the " + text2 + " sideways from the slot's center (positive = right).");
			LabelY = F("LabelY", d.LabelY, -1000f, 1000f, "Moves the " + text2 + " up or down from the slot's center (positive = up).");
			if (isGuardian)
			{
				ShowName = B("ShowName", d.ShowName, "Shows the power's name, in the game's language.");
				NameFontSize = F("NameFontSize", d.NameFontSize, 4f, 120f, "Size of the power's name.");
				NameX = F("NameX", d.NameX, -1000f, 1000f, "Moves the name sideways from the slot's center (positive = right).");
				NameY = F("NameY", d.NameY, -1000f, 1000f, "Moves the name up or down from the slot's center (positive = up).");
			}
			BindText(isGuardian ? "the cooldown and name" : "the timer", d.Text);
			BindEffects(d.Fx);
			GlowAround = B("GlowAround", d.GlowAround, "What the glow follows: Slot = a halo around the slot's shape; Icon = a glow around the icon's own drawing (any PNG or game icon). Icon looks best with ShowBackground off.");
			if (isGuardian)
			{
				GlowWhenReady = B("GlowWhenReady", d.GlowWhenReady, "Shows the glow only while the power can be used, as a \"ready\" signal. GlowEnabled shows it all the time and wins over this. If the selected boss has UseOwnGlow on (sections 05.a to 05.g), that boss's glow color and size are used.");
				ReadyGlowPulse = B("ReadyGlowPulse", d.ReadyGlowPulse, "GlowWhenReady only: the ready glow pulses slowly (about every 2 seconds) instead of staying still.");
			}
			EmptyMarkerColor = B<Color>("EmptyMarkerColor", d.EmptyMarkerColor, "Color of the thin ring drawn when the slot has no " + text + ". Alpha 00 hides the ring.");
			if (!isGuardian)
			{
				EdibleStyle = B("EdibleStyle", d.EdibleStyle, "How the food icon shows that you can eat that food again (the game allows it when less than half its time is left). Dim = the icon drops to EdibleOpacity. Blink = the icon pulses, with the cycle time set by BlinkSpeed. None = the icon never changes.");
				BlinkSpeed = B("BlinkSpeed", d.BlinkSpeed, "EdibleStyle = Blink only: time of one blink cycle. Vanilla = same as the vanilla HUD (about 1.3 seconds), TwiceVanilla = twice as slow (about 2.5 seconds), ThreeTimesVanilla = three times as slow (about 3.8 seconds).");
				EdibleOpacity = F("EdibleOpacity", d.EdibleOpacity, 0f, 1f, "EdibleStyle = Dim only: opacity of the icon once the food can be eaten again. 1 = no change, 0.5 = half see-through, 0 = invisible.");
				ShowWhenEmpty = B("ShowWhenEmpty", d.ShowWhenEmpty, "Draws this slot even when it has no food, with the empty ring. Off = the slot only appears while it holds a food.");
				ApplyStyleToOtherFoods = B("ApplyStyleToOtherFoods", def: false, "Button: switch it on to copy this slot's whole look (shape, size, colors, icon, texts and effects) to the other food slots. Visible, Anchor, X and Y are not copied, so every slot keeps its place. It switches itself back off.");
			}
		}

		public SlotSpec Resolve()
		{
			//IL_004b: 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_01c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01db: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_020a: Unknown result type (might be due to invalid IL or missing references)
			SlotSpec slotSpec = new SlotSpec
			{
				Visible = Visible.Value,
				ShowName = (ShowName != null && ShowName.Value),
				Gradient = Gradient.Value,
				EmptyMarkerColor = EmptyMarkerColor.Value,
				EdibleStyle = ((EdibleStyle != null) ? EdibleStyle.Value : ValHUD.EdibleStyle.None),
				EdibleOpacity = ((EdibleOpacity != null) ? EdibleOpacity.Value : 1f),
				BlinkSpeed = ((BlinkSpeed != null) ? BlinkSpeed.Value : ValHUD.BlinkSpeed.Vanilla),
				ShowWhenEmpty = (ShowWhenEmpty == null || ShowWhenEmpty.Value),
				GlowWhenReady = (GlowWhenReady != null && GlowWhenReady.Value),
				ReadyGlowPulse = (ReadyGlowPulse == null || ReadyGlowPulse.Value),
				CustomIcons = (CustomIcons == null || CustomIcons.Value),
				ShowBackground = ShowBackground.Value,
				GlowAround = GlowAround.Value
			};
			slotSpec.Fx = ResolveEffects();
			slotSpec.Fx.Shine = false;
			slotSpec.Anchor = Anchor.Value;
			slotSpec.X = X.Value;
			slotSpec.Y = Y.Value;
			slotSpec.Size = Size.Value;
			slotSpec.Shape = Shape.Value;
			slotSpec.Rotation = Rotation.Value;
			slotSpec.Color = Color.Value;
			slotSpec.ColorEnd = ColorEnd.Value;
			slotSpec.BorderColor = BorderColor.Value;
			slotSpec.BorderWidth = BorderWidth.Value;
			slotSpec.Text = ResolveText(TextColor.Value);
			slotSpec.IconSize = IconSize.Value;
			slotSpec.IconX = IconX.Value;
			slotSpec.IconY = IconY.Value;
			slotSpec.LabelFontSize = LabelFontSize.Value;
			slotSpec.LabelX = LabelX.Value;
			slotSpec.LabelY = LabelY.Value;
			if (_guardian)
			{
				slotSpec.NameFontSize = NameFontSize.Value;
				slotSpec.NameX = NameX.Value;
				slotSpec.NameY = NameY.Value;
			}
			return slotSpec;
		}

		public void CopyStyleTo(SlotConfig other)
		{
			HashSet<string> hashSet = new HashSet<string> { "Visible", "Anchor", "X", "Y", "ApplyStyleToOtherFoods" };
			foreach (ConfigEntryBase item in All)
			{
				string key = item.Definition.Key;
				if (hashSet.Contains(key))
				{
					continue;
				}
				foreach (ConfigEntryBase item2 in other.All)
				{
					if (item2.Definition.Key == key)
					{
						item2.BoxedValue = item.BoxedValue;
						break;
					}
				}
			}
		}
	}
	internal class ResolvedHud
	{
		public BarSpec Health;

		public BarSpec Stamina;

		public BarSpec Eitr;

		public BarSpec Adrenaline;

		public SlotSpec Guardian;

		public readonly List<SlotSpec> Foods = new List<SlotSpec>();
	}
	internal static class HudConfig
	{
		public enum ChangeKind
		{
			Ignore,
			Relayout,
			Rebuild
		}

		public const int FoodCount = 3;

		private const string General = "00. General";

		private const string Vanilla = "92. Vanilla HUD";

		public static ConfigEntry<bool> Enabled;

		public static ConfigEntry<float> Scale;

		public static ConfigEntry<float> OffsetX;

		public static ConfigEntry<float> OffsetY;

		public static ConfigEntry<string> NumbersFont;

		public static ConfigEntry<string> TextFont;

		public static ConfigEntry<bool> NumbersBold;

		public static ConfigEntry<bool> TextBold;

		public static ConfigEntry<KeyboardShortcut> EditModeKey;

		public static ConfigEntry<bool> ShowGrid;

		public static ConfigEntry<bool> SnapToGrid;

		public static ConfigEntry<float> GridSize;

		public static BarConfig Health;

		public static BarConfig Stamina;

		public static BarConfig Eitr;

		public static BarConfig Adrenaline;

		public static SlotConfig Guardian;

		public static readonly Dictionary<string, PowerGlowConfig> PowerGlows = new Dictionary<string, PowerGlowConfig>();

		public static readonly List<SlotConfig> Foods = new List<SlotConfig>();

		public static ConfigEntry<bool> HideHealth;

		public static ConfigEntry<bool> HideStamina;

		public static ConfigEntry<bool> HideEitr;

		public static ConfigEntry<bool> HideAdrenaline;

		public static ConfigEntry<bool> HideFood;

		public static ConfigEntry<bool> HideGuardian;

		public static ConfigEntry<bool> HideHealthPanel;

		private static ConfigFile _cfg;

		private static readonly HashSet<ConfigEntryBase> _layoutOnly = new HashSet<ConfigEntryBase>();

		private static bool _suppress;

		private static bool _holding;

		private static bool _heldSaveOnSet;

		public static ConfigEntry<string> Layout;

		private static ConfigEntry<string> LayoutBaseline;

		public static readonly List<ElementConfig> Elements = new List<ElementConfig>();

		private static readonly List<ConfigEntryBase> _layoutEntries = new List<ConfigEntryBase>();

		private static readonly HashSet<ConfigEntryBase> _layoutEntrySet = new HashSet<ConfigEntryBase>();

		private static string _fingerprint;

		public const string DefaultLayout = "DarthVladi";

		private const string BundledPrefix = "ValHUD.layouts.";

		private static Dictionary<string, string> _bundled;

		private static readonly HashSet<string> NotInLayouts = new HashSet<string> { "ApplyStyleToOtherFoods", "ForceVisible", "AutoHide", "AutoHideDelay", "FadeTime" };

		public static string CurrentLayout => Layout.Value ?? "";

		public static bool IsModified
		{
			get
			{
				if (CurrentLayout.Length == 0)
				{
					return true;
				}
				if (_fingerprint == null)
				{
					_fingerprint = Fingerprint();
				}
				return LayoutBaseline.Value != CurrentLayout + "|" + _fingerprint;
			}
		}

		public static void Bind(ConfigFile cfg)
		{
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Expected O, but got Unknown
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Expected O, but got Unknown
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Expected O, but got Unknown
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Expected O, but got Unknown
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: Expected O, but got Unknown
			//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_0203: Unknown result type (might be due to invalid IL or missing references)
			//IL_020d: Expected O, but got Unknown
			//IL_024a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0251: Unknown result type (might be due to invalid IL or missing references)
			//IL_0285: Unknown result type (might be due to invalid IL or missing references)
			//IL_028c: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0302: Unknown result type (might be due to invalid IL or missing references)
			_cfg = cfg;
			LayoutFile layoutFile = LegacyKeys.FromOldConfig(cfg.ConfigFilePath);
			PresetData presetData = Presets.Get(HudPreset.Defaults);
			Enabled = cfg.Bind<bool>("00. General", "Enabled", true, "Turns the custom HUD on or off. Off brings the vanilla HUD back, which is handy to compare.");
			Scale = MovesOnly<float>(cfg.Bind<float>("00. General", "Scale", 0.7f, new ConfigDescription("Size of the whole HUD: every element and every distance (X, Y and the offsets inside each element) is multiplied by it. Example: 0.7 is the default; 1 makes everything about 40 % bigger.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 4f), Array.Empty<object>())));
			OffsetX = MovesOnly<float>(cfg.Bind<float>("00. General", "OffsetX", 0f, new ConfigDescription("Moves every element sideways at once (positive = right). Handy to fit the whole HUD to a very wide or narrow screen.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-2000f, 2000f), Array.Empty<object>())));
			OffsetY = MovesOnly<float>(cfg.Bind<float>("00. General", "OffsetY", 0f, new ConfigDescription("Moves every element up or down at once (positive = up).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-2000f, 2000f), Array.Empty<object>())));
			string[] array = FontManager.Available("RussoOne-Regular.ttf");
			string[] array2 = FontManager.Available("Game");
			NumbersFont = cfg.Bind<string>("00. General", "NumberFont", "RussoOne-Regular.ttf", new ConfigDescription("Font for numbers: bar values, food timers and the power's cooldown. Game = the game's own font. To add one, put a .ttf or .otf file in plugins/ValHUD (or plugins/ValHUD/fonts) and restart the game. Letters the font lacks come from the game font.", (AcceptableValueBase)(object)new AcceptableValueList<string>(array), Array.Empty<object>()));
			TextFont = cfg.Bind<string>("00. General", "TextFont", "Game", new ConfigDescription("Font for names (the Forsaken power's name). Game = the game's own font. To add one, put a .ttf or .otf file in plugins/ValHUD (or plugins/ValHUD/fonts) and restart the game. Letters the font lacks come from the game font.", (AcceptableValueBase)(object)new AcceptableValueList<string>(array2), Array.Empty<object>()));
			NumbersBold = cfg.Bind<bool>("00. General", "NumberBold", false, "Bold numbers: bar values, food timers and the power's cooldown. Some fonts have no bold of their own, and then it is drawn thicker artificially.");
			TextBold = cfg.Bind<bool>("00. General", "TextBold", true, "Bold names (the Forsaken power's name). Some fonts have no bold of their own, and then it is drawn thicker artificially.");
			EditModeKey = cfg.Bind<KeyboardShortcut>("00. General", "EditModeKey", new KeyboardShortcut((KeyCode)289, Array.Empty<KeyCode>()), "Key that opens edit mode in game: drag the HUD elements with the mouse, nudge them with the arrow keys and turn them with the mouse wheel. Press it again to keep the changes, or Esc to undo them. Change it if another mod uses the same key. Not saved in layouts.");
			ShowGrid = cfg.Bind<bool>("00. General", "ShowGrid", true, "Edit mode: draws a grid over the screen to line elements up. Its lines start at the middle of the screen, so the center lines are always there. You can switch it on and off with G while editing. Not saved in layouts.");
			GridSize = cfg.Bind<float>("00. General", "GridSize", 20f, new ConfigDescription("Edit mode: distance between grid lines, in the same units as X and Y (so it grows and shrinks with General > Scale). Also the step of SnapToGrid. Example: 20 = a line every 20. Not saved in layouts.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 200f), Array.Empty<object>()));
			SnapToGrid = cfg.Bind<bool>("00. General", "SnapToGrid", true, "Edit mode: while you drag an element, its edges and its center jump to the nearest grid line, so elements line up exactly. Hold Ctrl while dragging to move freely, or press S while editing to switch it on and off. The arrow keys never snap. Works with the grid hidden too. Not saved in layouts.");
			BindLayoutSettings(cfg);
			Palette palette = presetData.Palette;
			Health = Register(new BarConfig(cfg, "01. Health Bar", BarDefaults(presetData.Health, palette.Health, palette.HealthEnd, palette, "first-aid.png", 3f)));
			Stamina = Register(new BarConfig(cfg, "02. Stamina Bar", BarDefaults(presetData.Stamina, palette.Stamina, palette.StaminaEnd, palette, "sneaker-move.png")));
			Eitr = Register(new BarConfig(cfg, "03. Eitr Bar", BarDefaults(presetData.Eitr, palette.Eitr, palette.EitrEnd, palette, "sparkle.png"), optional: true));
			Adrenaline = Register(new BarConfig(cfg, "04. Adrenaline Bar", BarDefaults(presetData.Adrenaline, palette.Adrenaline, palette.AdrenalineEnd, palette, "fire.png"), optional: true));
			Guardian = Register(new SlotConfig(cfg, "05. Forsaken Power", SlotDefaults(presetData.Guardian, palette, presetData.GuardianShowName, guardian: true), isGuardian: true));
			BindPowerGlows(cfg);
			for (int i = 0; i < 3; i++)
			{
				Foods.Add(Register(new SlotConfig(cfg, $"{6 + i:00}. Food {i + 1}", SlotDefaults(presetData.Foods[i], palette, showName: false, guardian: false), isGuardian: false)));
			}
			HideHealth = cfg.Bind<bool>("92. Vanilla HUD", "HideHealth", true, "Hides the vanilla health bar (your Health Bar replaces it).");
			HideStamina = cfg.Bind<bool>("92. Vanilla HUD", "HideStamina", true, "Hides the vanilla stamina bar (your Stamina Bar replaces it).");
			HideEitr = cfg.Bind<bool>("92. Vanilla HUD", "HideEitr", true, "Hides the vanilla eitr bar (your Eitr Bar replaces it).");
			HideAdrenaline = cfg.Bind<bool>("92. Vanilla HUD", "HideAdrenaline", true, "Hides the vanilla adrenaline bar (your Adrenaline Bar replaces it).");
			HideFood = cfg.Bind<bool>("92. Vanilla HUD", "HideFood", true, "Hides the vanilla food icons, their timers and the fork icon (your Food slots replace them).");
			HideGuardian = cfg.Bind<bool>("92. Vanilla HUD", "HideGuardianPower", true, "Hides the vanilla Forsaken power icon (your Forsaken Power slot replaces it).");
			HideHealthPanel = cfg.Bind<bool>("92. Vanilla HUD", "HideHealthPanel", true, "Hides the whole vanilla health and food panel, its decorations included. Turn it off only if you want to see that panel next to your HUD.");
			if (layoutFile != null)
			{
				ApplyLegacyConfig(layoutFile);
			}
			StartLayouts();
		}

		public static ResolvedHud Resolve()
		{
			ResolvedHud resolvedHud = new ResolvedHud
			{
				Health = Health.Resolve(),
				Stamina = Stamina.Resolve(),
				Eitr = Eitr.Resolve(),
				Adrenaline = Adrenaline.Resolve(),
				Guardian = Guardian.Resolve()
			};
			for (int i = 0; i < 3; i++)
			{
				resolvedHud.Foods.Add(Foods[i].Resolve());
			}
			return resolvedHud;
		}

		public static ChangeKind OnSettingChanged(ConfigEntryBase entry)
		{
			if (_suppress || (object)entry == EditModeKey || (object)entry == ShowGrid || (object)entry == GridSize || (object)entry == SnapToGrid)
			{
				return ChangeKind.Ignore;
			}
			ChangeKind? changeKind = HandleLayoutEntry(entry);
			if (changeKind.HasValue)
			{
				return changeKind.Value;
			}
			BarConfig[] array = new BarConfig[4] { Health, Stamina, Eitr, Adrenaline };
			foreach (BarConfig barConfig in array)
			{
				if ((object)entry == barConfig.ValueAttach)
				{
					Quiet(barConfig.ResetValuePlacement);
					_fingerprint = null;
					return ChangeKind.Rebuild;
				}
				if ((object)entry == barConfig.IconAttach)
				{
					Quiet(barConfig.ResetIconPlacement);
					_fingerprint = null;
					return ChangeKind.Rebuild;
				}
			}
			for (int j = 0; j < Foods.Count; j++)
			{
				if ((object)entry == Foods[j].ApplyStyleToOtherFoods)
				{
					if (!Foods[j].ApplyStyleToOtherFoods.Value)
					{
						return ChangeKind.Ignore;
					}
					ApplyFoodStyle(j);
					return ChangeKind.Rebuild;
				}
			}
			OnLayoutValueChanged(entry);
			return _layoutOnly.Contains(entry) ? ChangeKind.Relayout : ChangeKind.Rebuild;
		}

		private static void ApplyFoodStyle(int source)
		{
			bool saveOnConfigSet = _cfg.SaveOnConfigSet;
			_suppress = true;
			_cfg.SaveOnConfigSet = false;
			try
			{
				for (int i = 0; i < Foods.Count; i++)
				{
					if (i != source)
					{
						Foods[source].CopyStyleTo(Foods[i]);
					}
				}
				Foods[source].ApplyStyleToOtherFoods.Value = false;
			}
			finally
			{
				_cfg.SaveOnConfigSet = saveOnConfigSet;
				_suppress = false;
				_cfg.Save();
			}
			_fingerprint = null;
			Plugin.Log.LogInfo((object)$"ValHUD: Food {source + 1} style copied to the other food slots.");
		}

		public static void HoldSaves()
		{
			if (!_holding)
			{
				_holding = true;
				_heldSaveOnSet = _cfg.SaveOnConfigSet;
				_cfg.SaveOnConfigSet = false;
			}
		}

		public static void ReleaseSaves(bool save)
		{
			if (!_holding)
			{
				return;
			}
			_holding = false;
			_cfg.SaveOnConfigSet = _heldSaveOnSet;
			if (!save)
			{
				return;
			}
			try
			{
				_cfg.Save();
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("ValHUD: could not write the settings file (" + ex.Message + "); the changes apply until the game closes."));
			}
		}

		private static void BindPowerGlows(ConfigFile cfg)
		{
			//IL_01e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0208: Unknown result type (might be due to invalid IL or missing references)
			(string, string, string, float, float, float, string)[] array = new(string, string, string, float, float, float, string)[7]
			{
				("GP_Eikthyr", "Eikthyr", "00BEFFFF", 10f, 0.5f, 0.1f, "000000FF"),
				("GP_TheElder", "The Elder", "008000FF", 10f, 0.5f, 0f, "000000FF"),
				("GP_Bonemass", "Bonemass", "95B536FF", 20f, 0.5f, 4f, "000000FF"),
				("GP_Moder", "Moder", "910000FF", 10f, 1.5f, 4f, "000000FF"),
				("GP_Yagluth", "Yagluth", "B930E3FF", 16.5f, 1f, 3f, "000000FF"),
				("GP_Queen", "The Queen", "8A7232FF", 10f, 0.5f, 0.5f, "000000FF"),
				("GP_Fader", "Fader", "009800FF", 10f, 0.5f, 0.5f, "000000FF")
			};
			Color tint = default(Color);
			Color outlineColor = default(Color);
			for (int i = 0; i < array.Length; i++)
			{
				ColorUtility.TryParseHtmlString("#" + array[i].Item3, ref tint);
				ColorUtility.TryParseHtmlString("#" + array[i].Item7, ref outlineColor);
				string section = $"05.{(char)(97 + i)} Glow - {array[i].Item2}";
				PowerGlows[array[i].Item1] = Register(new PowerGlowConfig(cfg, section, array[i].Item1, array[i].Item2, tint, array[i].Item4, array[i].Item5, array[i].Item6, outlineColor));
			}
		}

		private static T Register<T>(T e) where T : ElementConfig
		{
			Elements.Add(e);
			foreach (ConfigEntryBase item in e.LayoutOnly)
			{
				_layoutOnly.Add(item);
			}
			return e;
		}

		private static ConfigEntry<T> MovesOnly<T>(ConfigEntry<T> e)
		{
			_layoutOnly.Add((ConfigEntryBase)(object)e);
			return e;
		}

		private static ConfigEntry<float> F(string section, string key, float def, float min, float max, string desc)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Expected O, but got Unknown
			return _cfg.Bind<float>(section, key, def, new ConfigDescription(desc, (AcceptableValueBase)(object)new AcceptableValueRange<float>(min, max), Array.Empty<object>()));
		}

		private static BarSpec BarDefaults(BarSpec geom, Color c, Color end, Palette pal, string icon, float autoHideDelay = 1f)
		{
			//IL_0007: 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_000e: 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_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0064: 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)
			//IL_0074: 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_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			BarSpec barSpec = new BarSpec
			{
				Color = c,
				ColorEnd = end,
				Background = pal.BarBackground,
				OutlineColor = pal.BarOutline,
				OutlineThickness = pal.BarOutlineWidth,
				IconColor = pal.Text,
				IconFile = icon,
				AutoHideDelay = autoHideDelay
			};
			BarConfig.CopyGeometry(geom, barSpec);
			barSpec.Text.Color = pal.Text;
			barSpec.Fx.GlowColor = UiUtil.WithAlpha(c, 0.45f);
			barSpec.IconGlowColor = UiUtil.WithAlpha(c, 0.55f);
			return barSpec;
		}

		private static SlotSpec SlotDefaults(SlotGeom g, Palette pal, bool showName, bool guardian)
		{
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: 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_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			SlotSpec slotSpec = new SlotSpec
			{
				Anchor = g.Anchor,
				X = g.X,
				Y = g.Y,
				Size = g.Size,
				Shape = g.Shape,
				Rotation = g.Rotation,
				ShowName = showName,
				Color = pal.SlotColor,
				ColorEnd = pal.SlotColorEnd,
				BorderColor = pal.BorderColor,
				BorderWidth = pal.BorderWidth
			};
			slotSpec.Text.Color = pal.Text;
			slotSpec.Fx.GlowColor = UiUtil.WithAlpha(pal.BorderColor, 0.45f);
			LayoutDefaults.ApplySlot(slotSpec, guardian);
			return slotSpec;
		}

		public static IEnumerable<ConfigEntryBase> LayoutEntries()
		{
			return _layoutEntries;
		}

		public static bool IsBuiltIn(string name)
		{
			return BundledLayout(name) != null;
		}

		public static List<string> BuiltInNames()
		{
			return Bundled().Keys.Where((string n) => BundledLayout(n) != null).OrderBy<string, string>((string n) => n, StringComparer.OrdinalIgnoreCase).ToList();
		}

		private static Dictionary<string, string> Bundled()
		{
			if (_bundled != null)
			{
				return _bundled;
			}
			_bundled = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
			try
			{
				Assembly assembly = typeof(HudConfig).Assembly;
				string[] manifestResourceNames = assembly.GetManifestResourceNames();
				foreach (string text in manifestResourceNames)
				{
					if (!text.StartsWith("ValHUD.layouts.", StringComparison.Ordinal) || !text.EndsWith(".json", StringComparison.OrdinalIgnoreCase))
					{
						continue;
					}
					using Stream stream = assembly.GetManifestResourceStream(text);
					using StreamReader streamReader = new StreamReader(stream);
					_bundled[text.Substring("ValHUD.layouts.".Length, text.Length - "ValHUD.layouts.".Length - 5)] = streamReader.ReadToEnd();
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("ValHUD: could not read the bundled layouts (" + ex.Message + ")."));
			}
			return _bundled;
		}

		private static string BundledLayout(string name)
		{
			name = name?.Trim() ?? "";
			if (name.Length == 0 || !Bundled().TryGetValue(name, out var value))
			{
				return null;
			}
			return LayoutStore.Exists(name) ? null : value;
		}

		private static void BindLayoutSettings(ConfigFile cfg)
		{
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Expected O, but got Unknown
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Expected O, but got Unknown
			Layout = cfg.Bind<string>("00. General", "Layout", "DarthVladi", new ConfigDescription("The layout you are using: one of the built-in layouts or one you saved. A layout stores every element's settings plus Scale, the offsets and the fonts. Use the panel in the settings window (F1) to load, save, save as, revert or delete. Without the settings window: write a layout name here while the game is closed, and it is loaded at startup.", (AcceptableValueBase)null, new object[1]
			{
				new ConfigurationManagerAttributes
				{
					Order = 1000,
					CustomDrawer = LayoutPanel.Draw,
					HideSettingName = true,
					HideDefaultButton = true
				}
			}));
			LayoutBaseline = cfg.Bind<string>("00. General", "LayoutBaseline", "", new ConfigDescription("Internal: lets ValHUD tell whether the current layout has unsaved changes. Do not edit.", (AcceptableValueBase)null, new object[1]
			{
				new ConfigurationManagerAttributes
				{
					Browsable = false
				}
			}));
		}

		private static void StartLayouts()
		{
			ConfigEntryBase[] array = (ConfigEntryBase[])(object)new ConfigEntryBase[7]
			{
				(ConfigEntryBase)Scale,
				(ConfigEntryBase)OffsetX,
				(ConfigEntryBase)OffsetY,
				(ConfigEntryBase)NumbersFont,
				(ConfigEntryBase)TextFont,
				(ConfigEntryBase)NumbersBold,
				(ConfigEntryBase)TextBold
			};
			foreach (ConfigEntryBase e in array)
			{
				AddLayoutEntry(e);
			}
			foreach (ElementConfig element in Elements)
			{
				foreach (ConfigEntryBase item in element.All)
				{
					if (!NotInLayouts.Contains(item.Definition.Key))
					{
						AddLayoutEntry(item);
					}
				}
			}
			try
			{
				Directory.CreateDirectory(LayoutStore.Dir);
				Plugin.Log.LogInfo((object)("ValHUD: layouts folder: " + LayoutStore.Dir));
				string text = LayoutBaseline.Value ?? "";
				string a = (text.Contains("|") ? text.Substring(0, text.LastIndexOf('|')) : "");
				if (text.Length == 0)
				{
					if (!_layoutEntries.All((ConfigEntryBase x) => object.Equals(x.BoxedValue, x.DefaultValue)))
					{
						Quiet(delegate
						{
							Layout.Value = "";
						});
						return;
					}
					LoadLayout(CurrentLayout, out var ok);
					if (!ok)
					{
						MarkSaved();
					}
				}
				else if (CurrentLayout.Length > 0 && !string.Equals(a, CurrentLayout, StringComparison.Ordinal))
				{
					Plugin.Log.LogInfo((object)("ValHUD: loading layout \"" + CurrentLayout + "\" (changed in the config file)."));
					bool ok2;
					string text2 = LoadLayout(CurrentLayout, out ok2);
					if (!ok2)
					{
						Plugin.Log.LogWarning((object)("ValHUD: " + text2));
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("ValHUD: layout setup failed, the HUD keeps its current values (" + ex.Message + ")."));
			}
		}

		private static void ApplyLegacyConfig(LayoutFile legacy)
		{
			int n = 0;
			Quiet(delegate
			{
				BarConfig[] array = new BarConfig[4] { Health, Stamina, Eitr, Adrenaline };
				foreach (BarConfig barConfig in array)
				{
					ConfigEntryBase[] array2 = (ConfigEntryBase[])(object)new ConfigEntryBase[6]
					{
						(ConfigEntryBase)barConfig.StartShape,
						(ConfigEntryBase)barConfig.StartSlant,
						(ConfigEntryBase)barConfig.EndShape,
						(ConfigEntryBase)barConfig.EndSlant,
						(ConfigEntryBase)barConfig.ValueAttach,
						(ConfigEntryBase)barConfig.IconAttach
					};
					foreach (ConfigEntryBase val in array2)
					{
						if (legacy.TryGet(val.Definition.Section, val.Definition.Key, out var value))
						{
							val.SetSerializedValue(value);
							n++;
						}
					}
				}
				foreach (SlotConfig food in Foods)
				{
					if (legacy.TryGet(((ConfigEntryBase)food.EdibleStyle).Definition.Section, ((ConfigEntryBase)food.EdibleStyle).Definition.Key, out var value2))
					{
						((ConfigEntryBase)food.EdibleStyle).SetSerializedValue(value2);
						n++;
					}
				}
			});
			if (n > 0)
			{
				Plugin.Log.LogInfo((object)$"ValHUD: translated {n} bar settings from an older version.");
			}
		}

		private static void AddLayoutEntry(ConfigEntryBase e)
		{
			if (_layoutEntrySet.Add(e))
			{
				_layoutEntries.Add(e);
			}
		}

		private static ChangeKind? HandleLayoutEntry(ConfigEntryBase entry)
		{
			if ((object)entry == LayoutBaseline)
			{
				return ChangeKind.Ignore;
			}
			if ((object)entry != Layout)
			{
				return null;
			}
			string currentLayout = CurrentLayout;
			string previous = BaselineName();
			bool ok;
			string text = LoadLayout(currentLayout, out ok);
			if (!ok)
			{
				Plugin.Log.LogWarning((object)("ValHUD: " + text));
				Quiet(delegate
				{
					Layout.Value = previous;
				});
			}
			return ChangeKind.Rebuild;
		}

		private static void OnLayoutValueChanged(ConfigEntryBase entry)
		{
			if (_layoutEntrySet.Contains(entry))
			{
				_fingerprint = null;
			}
		}

		public static string LoadLayout(string name, out bool ok)
		{
			ok = false;
			try
			{
				name = (name ?? "").Trim();
				if (name.Length == 0)
				{
					return "No layout name given.";
				}
				string error = null;
				string text = BundledLayout(name);
				LayoutFile f;
				LoadStatus status;
				if (text != null)
				{
					f = LayoutStore.FromJson(text);
					status = LoadStatus.Ok;
					name = Bundled().Keys.First((string k) => string.Equals(k, name, StringComparison.OrdinalIgnoreCase));
				}
				else
				{
					f = LayoutStore.TryLoad(name, out status, out error);
				}
				switch (status)
				{
				case LoadStatus.Missing:
					return "There is no layout called \"" + name + "\".";
				case LoadStatus.Corrupt:
					LayoutStore.Quarantine(name);
					return "\"" + name + "\" could not be read (" + error + "). It was renamed to \"" + name + ".json.corrupt\"; your HUD was not changed.";
				default:
				{
					if (LegacyKeys.Migrate(f))
					{
						Plugin.Log.LogInfo((object)("ValHUD: layout \"" + name + "\" uses older settings; they were translated."));
					}
					string canonical = ((text != null) ? name : LayoutStore.Sanitize(name));
					int applied = 0;
					Quiet(delegate
					{
						ResetLayoutEntries();
						applied = Apply(f);
						Layout.Value = canonical;
					});
					MarkSaved();
					ValHudController.RequestRebuild();
					ok = true;
					Plugin.Log.LogInfo((object)$"ValHUD: layout \"{canonical}\" loaded ({applied} settings).");
					return "Loaded \"" + canonical + "\".";
				}
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("ValHUD: loading \"" + name + "\" failed (" + ex.Message + ")."));
				return "Loading \"" + name + "\" failed: " + ex.Message;
			}
		}

		public static string SaveLayout(out bool ok)
		{
			ok = false;
			string currentLayout = CurrentLayout;
			if (currentLayout.Length == 0)
			{
				return "This layout has no name yet: use Save as.";
			}
			if (IsBuiltIn(currentLayout))
			{
				return "Built-in layouts can't be changed: use Save as to keep your version.";
			}
			return WriteLayout(currentLayout, BasedOnOf(currentLayout), out ok);
		}

		public static string SaveLayoutAs(string wanted, out bool ok)
		{
			ok = false;
			string name = LayoutStore.Sanitize(wanted);
			if (name.Length == 0)
			{
				return LayoutStore.IsReservedName(wanted) ? ("\"" + wanted?.Trim() + "\" is a name Windows keeps for devices (CON, NUL, COM1...). Choose another name.") : "Type a name first.";
			}
			if (IsBuiltIn(name))
			{
				return "\"" + name + "\" is the name of a built-in layout. Choose another name.";
			}
			string basedOn = (IsBuiltIn(CurrentLayout) ? CurrentLayout : BasedOnOf(CurrentLayout));
			string result = WriteLayout(name, basedOn, out ok);
			if (ok)
			{
				Quiet(delegate
				{
					Layout.Value = name;
				});
				MarkSaved();
			}
			return result;
		}

		public static string RevertLayout(out bool ok)
		{
			ok = false;
			if (CurrentLayout.Length == 0)
			{
				return "This layout was never saved, so there is nothing to go back to.";
			}
			return LoadLayout(CurrentLayout, out ok);
		}

		public static string DeleteLayout(string name, out bool ok)
		{
			ok = false;
			if (IsBuiltIn(name))
			{
				return "Built-in layouts can't be deleted.";
			}
			if (!LayoutStore.Delete(name, out var error))
			{
				return "Could not delete \"" + name + "\": " + error;
			}
			if (string.Equals(name, CurrentLayout, StringComparison.OrdinalIgnoreCase))
			{
				Quiet(delegate
				{
					Layout.Value = "";
				});
			}
			ok = true;
			Plugin.Log.LogInfo((object)("ValHUD: layout \"" + name + "\" deleted."));
			return "Deleted \"" + name + "\".";
		}

		private static string WriteLayout(string name, string basedOn, out bool ok)
		{
			LayoutFile layoutFile = new LayoutFile
			{
				Name = name,
				BasedOn = (basedOn ?? ""),
				ModVersion = "1.2.1"
			};
			foreach (ConfigEntryBase layoutEntry in _layoutEntries)
			{
				layoutFile.Set(layoutEntry.Definition.Section, layoutEntry.Definition.Key, layoutEntry.GetSerializedValue());
			}
			ok = LayoutStore.Save(layoutFile, name, out var error);
			if (!ok)
			{
				return "Could not save \"" + name + "\": " + error;
			}
			if (string.Equals(name, CurrentLayout, StringComparison.Ordinal))
			{
				MarkSaved();
			}
			Plugin.Log.LogInfo((object)$"ValHUD: layout \"{name}\" saved ({layoutFile.Count} settings).");
			return "Saved \"" + name + "\".";
		}

		private static int Apply(LayoutFile f)
		{
			int num = 0;
			foreach (ConfigEntryBase layoutEntry in _layoutEntries)
			{
				if (f.TryGet(layoutEntry.Definition.Section, layoutEntry.Definition.Key, out var value))
				{
					try
					{
						layoutEntry.SetSerializedValue(value);
						num++;
					}
					catch (Exception ex)
					{
						Plugin.Log.LogWarning((object)("ValHUD: skipped [" + layoutEntry.Definition.Section + "] " + layoutEntry.Definition.Key + " (" + ex.Message + ")."));
					}
				}
			}
			return num;
		}

		private static string BasedOnOf(string name)
		{
			if (name.Length == 0 || IsBuiltIn(name))
			{
				return name;
			}
			LoadStatus status;
			string error;
			LayoutFile layoutFile = LayoutStore.TryLoad(name, out status, out error);
			return (status == LoadStatus.Ok) ? layoutFile.BasedOn : "";
		}

		private static void MarkSaved()
		{
			_fingerprint = Fingerprint();
			string baseline = CurrentLayout + "|" + _fingerprint;
			Quiet(delegate
			{
				LayoutBaseline.Value = baseline;
			});
		}

		private static string BaselineName()
		{
			string text = LayoutBaseline.Value ?? "";
			int num = text.LastIndexOf('|');
			return (num > 0) ? text.Substring(0, num) : "";
		}

		private static string Fingerprint()
		{
			ulong num = 14695981039346656037uL;
			foreach (ConfigEntryBase layoutEntry in _layoutEntries)
			{
				string s = layoutEntry.Definition.Section + "\u0001" + layoutEntry.Definition.Key + "\u0001" + layoutEntry.GetSerializedValue() + "\n";
				byte[] bytes = Encoding.UTF8.GetBytes(s);
				foreach (byte b in bytes)
				{
					num ^= b;
					num *= 1099511628211L;
				}
			}
			return num.ToString("x16");
		}

		private static void ResetLayoutEntries()
		{
			foreach (ConfigEntryBase layoutEntry in _layoutEntries)
			{
				layoutEntry.BoxedValue = layoutEntry.DefaultValue;
			}
		}

		private static void Quiet(Action action)
		{
			bool suppress = _suppress;
			bool saveOnConfigSet = _cfg.SaveOnConfigSet;
			_suppress = true;
			_cfg.SaveOnConfigSet = false;
			try
			{
				action();
			}
			finally
			{
				_cfg.SaveOnConfigSet = saveOnConfigSet;
				_suppress = suppress;
				if (!suppress)
				{
					_cfg.Save();
				}
			}
		}
	}
	public enum HudAnchor
	{
		BottomLeft,
		TopLeft,
		BottomRight,
		TopRight,
		BottomCenter,
		TopCenter,
		Center
	}
	public enum SlotShape
	{
		Diamond,
		Square,
		Circle
	}
	public enum BarOrientation
	{
		Horizontal,
		Vertical
	}
	public enum FillDirection
	{
		Normal,
		Reversed
	}
	public enum BarEnd
	{
		Flat,
		Forward,
		Backward,
		Notch,
		Point
	}
	public enum GradientDirection
	{
		None,
		Horizontal,
		Vertical
	}
	public enum GlowAround
	{
		Slot,
		Icon
	}
	public enum BarPoint
	{
		Left,
		Center,
		Right,
		Top,
		Bottom
	}
	public enum TextAlign
	{
		Left,
		Center,
		Right
	}
	public enum EdibleStyle
	{
		None,
		Dim,
		Blink
	}
	public enum BlinkSpeed
	{
		Vanilla,
		TwiceVanilla,
		ThreeTimesVanilla
	}
	public enum HudPreset
	{
		Custom,
		Defaults
	}
	internal class TextStyle
	{
		public Color Color = Color.white;

		public Color OutlineColor = Color.black;

		public Color ShadowColor = new Color(0f, 0f, 0f, 0.8f);

		public float OutlineWidth = 0.2f;

		public float ShadowOffset = 0.6f;

		public float ShadowSoftness = 0.3f;

		public bool Shadow = true;

		public string MaterialKey => $"{OutlineWidth:0.###}|{ColorUtility.ToHtmlStringRGBA(OutlineColor)}|{Shadow}|{ColorUtility.ToHtmlStringRGBA(ShadowColor)}|{ShadowOffset:0.###}|{ShadowSoftness:0.###}";
	}
	internal class EffectSpec
	{
		public bool Shadow = true;

		public bool Glow;

		public bool Shine = true;

		public Color ShadowColor = new Color(0f, 0f, 0f, 0.6f);

		public Color GlowColor = new Color(1f, 0.85f, 0.5f, 0.45f);

		public Vector2 ShadowOffset = new Vector2(3f, -3f);

		public float GlowSize = 12f;

		public float ShineStrength = 0.35f;

		public float GlowIntensity = 1f;
	}
	internal class BarSpec
	{
		public bool Visible = true;

		public bool AutoHide;

		public float AutoHideDelay = 1f;

		public float FadeTime = 0.3f;

		public HudAnchor Anchor = HudAnchor.BottomLeft;

		public float X;

		public float Y;

		public float Length = 300f;

		public float Thickness = 32f;

		public float StartSlant;

		public float EndSlant;

		public float ValueFontSize = 22f;

		public float Rotation;

		public BarOrientation Orientation;

		public FillDirection Direction;

		public BarEnd StartShape;

		public BarEnd EndShape;

		public Color Color = Color.red;

		public Color ColorEnd = Color.red;

		public Color Background = new Color(0f, 0f, 0f, 0.55f);

		public GradientDirection Gradient = GradientDirection.Vertical;

		public float OutlineThickness;

		public Color OutlineColor = Color.black;

		public Color TrailColor = new Color(1f, 0.95f, 0.85f, 0.5f);

		public bool ShowValue = true;

		public bool ShowIcon = true;

		public bool ScaleLengthWithMax;

		public float ScaleFullAt = 300f;

		public string ValueFormat = "{0}";

		public string IconFile = "";

		public BarPoint ValueAttach = BarPoint.Right;

		public BarPoint IconAttach = BarPoint.Right;

		public TextAlign ValueAlign = TextAlign.Left;

		public float ValueX;

		public float ValueY;

		public float IconX;

		public float IconY;

		public float IconSize = 15f;

		public Color IconColor = Color.white;

		public bool IconShadow = true;

		public bool IconGlow = true;

		public Color IconShadowColor = new Color(0f, 0f, 0f, 0.7f);

		public Color IconOutlineColor = new Color(0f, 0f, 0f, 0.85f);

		public Color IconGlowColor = new Color(1f, 1f, 1f, 0.5f);

		public Vector2 IconShadowOffset = new Vector2(2f, -2f);

		public float IconOutlineWidth = 1.5f;

		public float IconGlowSize = 8f;

		public float IconGlowIntensity = 1f;

		public TextStyle Text = new TextStyle();

		public EffectSpec Fx = new EffectSpec();

		public bool Divisions = true;

		public DivisionRule DivisionRule = DivisionRule.Default;

		public Color DivisionColor = new Color(0f, 0f, 0f, 0.55f);

		public float DivisionWidth = 2f;

		public bool Reversed => Direction == FillDirection.Reversed;

		public bool Vertical => Orientation == BarOrientation.Vertical;
	}
	internal class SlotSpec
	{
		public bool Visible = true;

		public bool ShowName = true;

		public HudAnchor Anchor = HudAnchor.BottomLeft;

		public float X;

		public float Y;

		public float Size = 100f;

		public float BorderWidth;

		public float Rotation;

		public SlotShape Shape;

		public Color Color = Color.black;

		public Color ColorEnd = Color.black;

		public Color BorderColor = Color.white;

		public GradientDirection Gradient = GradientDirection.Vertical;

		public float IconX;

		public float IconY;

		public float IconSize;

		public float LabelX;

		public float LabelY;

		public float LabelFontSize;

		public float NameX;

		public float NameY;

		public float NameFontSize;

		public TextStyle Text = new TextStyle();

		public EffectSpec Fx = new EffectSpec();

		public bool ShowWhenEmpty = true;

		public EdibleStyle EdibleStyle = EdibleStyle.Blink;

		public BlinkSpeed BlinkSpeed = BlinkSpeed.Vanilla;

		public float EdibleOpacity = 0.5f;

		public bool GlowWhenReady;

		public bool ReadyGlowPulse = true;

		public bool CustomIcons = true;

		public bool ShowBackground = true;

		public GlowAround GlowAround = GlowAround.Slot;

		public Color EmptyMarkerColor = new Color(1f, 1f, 1f, 0.12f);
	}
	internal class Palette
	{
		public Color SlotColor;

		public Color SlotColorEnd;

		public Color BorderColor;

		public float BorderWidth;

		public float BarOutlineWidth;

		public Color BarOutline;

		public Color Health;

		public Color HealthEnd;

		public Color Stamina;

		public Color StaminaEnd;

		public Color Eitr;

		public Color EitrEnd;

		public Color Adrenaline;

		public Color AdrenalineEnd;

		public Color BarBackground;

		public Color Text;
	}
	internal class SlotGeom
	{
		public HudAnchor Anchor;

		public float X;

		public float Y;

		public float Size;

		public float Rotation;

		public SlotShape Shape;
	}
	internal class PresetData
	{
		public SlotGeom Guardian;

		public bool GuardianShowName;

		public SlotGeom[] Foods;

		public BarSpec Health;

		public BarSpec Stamina;

		public BarSpec Eitr;

		public BarSpec Adrenaline;

		public Palette Palette;
	}
	internal static class LayoutDefaults
	{
		private struct SlotTable
		{
			public float Icon;

			public float IconY;

			public float Label;

			public float LabelY;

			public float Name;

			public float NameY;

			public SlotTable(float icon, float iconY, float label, float labelY, float name, float nameY)
			{
				Icon = icon;
				IconY = iconY;
				Label = label;
				LabelY = labelY;
				Name = name;
				NameY = nameY;
			}
		}

		private static readonly SlotTable Diamond = new SlotTable(0.34f, 0.12f, 0.2f, -0.2f, 0.085f, -0.25f);

		private static readonly SlotTable Square = new SlotTable(0.46f, 0.1f, 0.22f, -0.28f, 0.1f, -0.33f);

		private static readonly SlotTable Circle = new SlotTable(0.44f, 0.1f, 0.22f, -0.27f, 0.1f, -0.31f);

		private const float MinLabel = 17f;

		private const float MinName = 13f;

		public static void ApplyBar(BarSpec s)
		{
			float valueFontSize = s.ValueFontSize;
			float num = Mathf.Max(4f, valueFontSize * 0.3f);
			float num2 = (s.IconSize = valueFontSize * 0.7f);
			s.IconAttach = (s.ValueAttach = ((!s.Vertical) ? ((!s.Reversed) ? BarPoint.Right : BarPoint.Left) : (s.Reversed ? BarPoint.Bottom : BarPoint.Top)));
			float num3 = (s.Reversed ? (-1f) : 1f);
			if (s.Vertical)
			{
				s.IconX = 0f;
				s.IconY = num3 * (num + num2 * 0.5f);
				s.ValueX = 0f;
				s.ValueY = num3 * (num + num2 + valueFontSize * 0.25f + valueFontSize * 0.55f);
				s.ValueAlign = TextAlign.Center;
			}
			else
			{
				s.IconX = num3 * (num + num2 * 0.5f);
				s.IconY = 0f;
				s.ValueX = num3 * (num + num2 + valueFontSize * 0.3f);
				s.ValueY = 0f;
				s.ValueAlign = (s.Reversed ? TextAlign.Right : TextAlign.Left);
			}
		}

		public static void ApplySlot(SlotSpec s, bool guardian)
		{
			SlotTable slotTable = ((s.Shape == SlotShape.Square) ? Square : ((s.Shape == SlotShape.Circle) ? Circle : Diamond));
			float size = s.Size;
			s.IconSize = size * slotTable.Icon;
			s.IconX = 0f;
			s.IconY = size * slotTable.IconY;
			s.LabelFontSize = Mathf.Max(17f, size * slotTable.Label);
			s.LabelX = 0f;
			s.LabelY = size * slotTable.LabelY;
			s.NameFontSize = Mathf.Max(13f, size * slotTable.Name);
			s.NameX = 0f;
			s.NameY = size * slotTable.NameY;
			if (guardian && s.ShowName)
			{
				s.LabelY = s.NameY + s.NameFontSize * 1.2f;
			}
		}
	}
	internal static class LayoutPanel
	{
		private const int Columns = 3;

		private const float ConfirmSeconds = 4f;

		private const string Warn = "#FFB74D";

		private const string Good = "#81C784";

		private const string Bad = "#E57373";

		private const string Dim = "#A8A8A8";

		private static string _newName;

		private static string _message = "";

		private static string _messageColor = "#A8A8A8";

		private static string _armed;

		private static float _armedUntil;

		private static List<string> _saved = new List<string>();

		private static List<string> _builtInNames = new List<string>();

		private static float _listedAt = -100f;

		private static GUIStyle _text;

		public static void Draw(ConfigEntryBase entry)
		{
			bool enabled = GUI.enabled;
			try
			{
				DrawPanel();
			}
			catch (Exception ex)
			{
				GUILayout.Label("ValHUD layout panel error: " + ex.Message, Array.Empty<GUILayoutOption>());
			}
			finally
			{
				GUI.enabled = enabled;
			}
		}

		private static void DrawPanel()
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Expected O, but got Unknown
			if (_text == null)
			{
				_text = new GUIStyle(GUI.skin.label)
				{
					richText = true,
					wordWrap = true
				};
			}
			if (Time.unscaledTime - _listedAt > 2f)
			{
				_saved = LayoutStore.List();
				_builtInNames = HudConfig.BuiltInNames();
				_listedAt = Time.unscaledTime;
			}
			if (_armed != null && Time.unscaledTime > _armedUntil)
			{
				_armed = null;
			}
			string current = HudConfig.CurrentLayout;
			bool flag = current.Length > 0;
			bool isModified = HudConfig.IsModified;
			bool flag2 = flag && _builtInNames.Any((string n) => string.Equals(n, current, StringComparison.OrdinalIgnoreCase));
			if (_newName == null)
			{
				_newName = Suggest(current, flag2);
			}
			GUILayout.BeginVertical(GUI.skin.box, Array.Empty<GUILayoutOption>());
			string text = ((!flag) ? "not saved yet" : (flag2 ? "built-in, read-only" : "your layout"));
			Text("<size=15><b>Layout: " + Esc(flag ? current : "(unsaved)") + "</b></size>   " + Color("#A8A8A8", text));
			if (!flag)
			{
				Text(Color("#FFB74D", "● These values are not in any layout yet. Type a name below and press Save as to keep them."));
			}
			else if (!isModified)
			{
				Text(Color("#81C784", "✓ No unsaved changes."));
			}
			else if (flag2)
			{
				Text(Color("#FFB74D", "● Modified. A built-in layout can't be overwritten: Save as to keep your version, or Revert to drop it."));
			}
			else
			{
				Text(Color("#FFB74D", "● Unsaved changes. Save writes them to \"" + Esc(current) + "\"; Revert drops them."));
			}
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUI.enabled = flag && !flag2 && isModified;
			if (GUILayout.Button("Save", Array.Empty<GUILayoutOption>()))
			{
				Done(HudConfig.SaveLayout(out var ok), ok);
			}
			GUI.enabled = flag && isModified;
			if (GUILayout.Button(Label("revert", "Revert"), Array.Empty<GUILayoutOption>()) && Confirm("revert", "Click Revert again to drop your changes and reload \"" + current + "\"."))
			{
				Done(HudConfig.RevertLayout(out var ok2), ok2);
			}
			GUI.enabled = flag && !flag2;
			if (GUILayout.Button(Label("delete", "Delete"), Array.Empty<GUILayoutOption>()) && Confirm("delete", "Click Delete again to delete \"" + current + "\" for good."))
			{
				Done(HudConfig.DeleteLayout(current, out var ok3), ok3);
			}
			GUI.enabled = true;
			GUILayout.EndHorizontal();
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label("New name:", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(false) });
			_newName = GUILayout.TextField(_newName ?? "", 64, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.MinWidth(160f) });
			if (GUILayout.Button(Label("saveas", "Save as"), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(false) }))
			{
				SaveAs();
			}
			GUILayout.EndHorizontal();
			Text(Color("#A8A8A8", "Save as copies what you see into a new layout and switches to it. The layout you started from is not changed."));
			Text("<b>Built-in layouts</b>");
			Grid(_builtInNames, current, isModified);
			Text("<b>Your layouts</b>");
			if (_saved.Count == 0)
			{
				Text(Color("#A8A8A8", "None yet. Use Save as to create one."));
			}
			else
			{
				Grid(_saved, current, isModified);
			}
			Text(Color("#A8A8A8", "Click a layout to load it. To share one, send its .json file; to use a friend's, put it in the layouts folder."));
			if (GUILayout.Button("Open layouts folder", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(false) }))
			{
				OpenFolder();
			}
			if (_message.Length > 0)
			{
				Text(Color(_messageColor, Esc(_message)));
			}
			GUILayout.EndVertical();
		}

		private static void Grid(List<string> names, string current, bool modified)
		{
			for (int i = 0; i < names.Count; i += 3)
			{
				GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
				for (int j = i; j < i + 3; j++)
				{
					if (j >= names.Count)
					{
						GUILayout.Label("", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) });
						continue;
					}
					string text = names[j];
					bool flag = string.Equals(text, current, StringComparison.OrdinalIgnoreCase);
					GUI.enabled = !flag;
					string key = "load:" + text;
					if (GUILayout.Button(flag ? ("● " + text) : Label(key, text), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) }) && (!modified || Confirm(key, "Your unsaved changes will be lost. Click \"" + text + "\" again to load it.")))
					{
						Done(HudConfig.LoadLayout(text, out var ok), ok);
						if (ok)
						{
							_newName = null;
						}
					}
					GUI.enabled = true;
				}
				GUILayout.EndHorizontal();
			}
		}

		private static void SaveAs()
		{
			string name = LayoutStore.Sanitize(_newName);
			if (!_saved.Any((string n) => string.Equals(n, name, StringComparison.OrdinalIgnoreCase)) || string.Equals(name, HudConfig.CurrentLayout, StringComparison.OrdinalIgnoreCase) || Confirm("saveas", "\"" + name + "\" already exists. Click Save as again to replace it."))
			{
				Done(HudConfig.SaveLayoutAs(_newName, out var ok), ok);
			}
		}

		private static void OpenFolder()
		{
			try
			{
				Directory.CreateDirectory(LayoutStore.Dir);
				Application.OpenURL("file:///" + LayoutStore.Dir.Replace('\\', '/'));
			}
			catch (Exception ex)
			{
				Done("Could not open the folder: " + ex.Message, ok: false);
			}
		}

		private static string Suggest(string current, bool builtIn)
		{
			if (current.Length == 0)
			{
				return "My Layout";
			}
			return builtIn ? ("My " + current) : (current + " copy");
		}

		private static bool Confirm(string key, string prompt)
		{
			if (_armed == key && Time.unscaledTime <= _armedUntil)
			{
				_armed = null;
				return true;
			}
			_armed = key;
			_armedUntil = Time.unscaledTime + 4f;
			_message = prompt;
			_messageColor = "#FFB74D";
			return false;
		}

		private static string Label(string key, string text)
		{
			return (_armed == key) ? "Click again to confirm" : text;
		}

		private static void Done(string message, bool ok)
		{
			_message = message ?? "";
			_messageColor = (ok ? "#81C784" : "#E57373");
			_armed = null;
			_listedAt = -100f;
		}

		private static void Text(string richText)
		{
			GUILayout.Label(richText, _text, Array.Empty<GUILayoutOption>());
		}

		private static string Color(string hex, string text)
		{
			return "<color=" + hex + ">" + text + "</color>";
		}

		private static string Esc(string s)
		{
			return (s ?? "").Replace("<", "‹").Replace(">", "›");
		}
	}
	internal static class LegacyKeys
	{
		public static bool MigrateSection(Dictionary<string, string> k)
		{
			bool result = false;
			if (k.TryGetValue("SlantStyle", out var value) && !k.ContainsKey("StartShape"))
			{
				string value3;
				string value2 = (k.TryGetValue("SlantAmount", out value3) ? value3 : "0");
				if (value == "PointEnd")
				{
					k["StartShape"] = "Flat";
					k["StartSlant"] = "0";
					k["EndShape"] = "Point";
					k["EndSlant"] = value2;
				}
				else
				{
					k["StartShape"] = ((value == "None") ? "Flat" : value);
					k["StartSlant"] = value2;
					k["EndShape"] = "Flat";
					k["EndSlant"] = "0";
				}
				result = true;
			}
			string value4;
			bool flag = k.TryGetValue("FillDirection", out value4) && value4 == "Reversed";
			string value5;
			bool flag2 = k.TryGetValue("Orientation", out value5) && value5 == "Vertical";
			string[] array = new string[2] { "ValueAttach", "IconAttach" };
			foreach (string key in array)
			{
				if (k.TryGetValue(key, out var value6) && (!(value6 != "Start") || !(value6 != "End")))
				{
					bool flag3 = (value6 == "End") ^ flag;
					k[key] = ((!flag2) ? (flag3 ? "Right" : "Left") : (flag3 ? "Top" : "Bottom"));
					result = true;
				}
			}
			if (k.TryGetValue("BlinkWhenEdible", out var value7) && !k.ContainsKey("EdibleStyle") && string.Equals(value7.Trim(), "false", StringComparison.OrdinalIgnoreCase))
			{
				k["EdibleStyle"] = "None";
				result = true;
			}
			return result;
		}

		public static bool Migrate(LayoutFile f)
		{
			bool flag = false;
			foreach (Dictionary<string, string> value in f.Values.Values)
			{
				flag |= MigrateSection(value);
			}
			return flag;
		}

		public static LayoutFile FromOldConfig(string path)
		{
			try
			{
				if (!File.Exists(path))
				{
					return null;
				}
				LayoutFile layoutFile = new LayoutFile();
				string text = null;
				string[] array = File.ReadAllLines(path);
				foreach (string text2 in array)
				{
					string text3 = text2.Trim();
					if (text3.Length == 0 || text3.StartsWith("#"))
					{
						continue;
					}
					if (text3.StartsWith("[") && text3.EndsWith("]"))
					{
						text = text3.Substring(1, text3.Length - 2).Trim();
						continue;
					}
					int num = text3.IndexOf('=');
					if (text != null && num > 0)
					{
						layoutFile.Set(text, text3.Substring(0, num).Trim(), text3.Substring(num + 1).Trim());
					}
				}
				return Migrate(layoutFile) ? layoutFile : null;
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("ValHUD: could not check the config for old settings (" + ex.Message + ")."));
				return null;
			}
		}
	}
	internal static class Presets
	{
		private static readonly Dictionary<HudPreset, PresetData> _cache = new Dictionary<HudPreset, PresetData>();

		private static readonly Palette ForgedIronPalette = new Palette
		{
			SlotColor = C("0D0B09E6"),
			SlotColorEnd = C("2A2017E6"),
			BorderColor = C("B08D57FF"),
			BorderWidth = 3f,
			BarOutline = C("B08D57FF"),
			BarOutlineWidth = 2f,
			Health = C("D32F2FFF"),
			HealthEnd = C("8B1A1AFF"),
			Stamina = C("FFB900FF"),
			StaminaEnd = C("E07B00FF"),
			Eitr = C("A07CFFFF"),
			EitrEnd = C("5E3BD6FF"),
			Adrenaline = C("FF8C00FF"),
			AdrenalineEnd = C("D96500FF"),
			BarBackground = C("0000008C"),
			Text = C("F7F1E5FF")
		};

		public static PresetData Get(HudPreset p)
		{
			if (p == HudPreset.Custom)
			{
				return null;
			}
			if (!_cache.TryGetValue(p, out var value))
			{
				value = Build(p);
				if (value != null)
				{
					BarSpec[] array = new BarSpec[4] { value.Health, value.Stamina, value.Eitr, value.Adrenaline };
					foreach (BarSpec s in array)
					{
						LayoutDefaults.ApplyBar(s);
					}
				}
				_cache[p] = value;
			}
			return value;
		}

		private static Color C(string hex)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: 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)
			Color result = default(Color);
			ColorUtility.TryParseHtmlString("#" + hex, ref result);
			return result;
		}

		private static SlotGeom G(HudAnchor a, float x, float y, float size, SlotShape shape, float rot)
		{
			return new SlotGeom
			{
				Anchor = a,
				X = x,
				Y = y,
				Size = size,
				Shape = shape,
				Rotation = rot
			};
		}

		private static BarSpec B(HudAnchor a, float x, float y, float length, float thickness, float font, BarEnd start, float startSlant, BarEnd end, float endSlant, BarOrientation o, FillDirection d, float rot)
		{
			return new BarSpec
			{
				Anchor = a,
				X = x,
				Y = y,
				Length = length,
				Thickness = thickness,
				ValueFontSize = font,
				StartShape = start,
				StartSlant = startSlant,
				EndShape = end,
				EndSlant = endSlant,
				Orientation = o,
				Direction = d,
				Rotation = rot
			};
		}

		private static PresetData Build(HudPreset p)
		{
			if (p == HudPreset.Defaults)
			{
				PresetData presetData = new PresetData();
				presetData.Guardian = G(HudAnchor.BottomCenter, 0f, 97.1f, 137.1f, SlotShape.Circle, 0f);
				presetData.GuardianShowName = false;
				presetData.Foods = new SlotGeom[3]
				{
					G(HudAnchor.BottomCenter, -171.4f, 221.4f, 100f, SlotShape.Diamond, 0f),
					G(HudAnchor.BottomCenter, 0f, 221.4f, 100f, SlotShape.Diamond, 0f),
					G(HudAnchor.BottomCenter, 171.4f, 221.4f, 100f, SlotShape.Diamond, 0f)
				};
				presetData.Health = B(HudAnchor.BottomCenter, -85.7f, 114.3f, 742.9f, 42.9f, 34.3f, BarEnd.Flat, 0f, BarEnd.Point, 20f, BarOrientation.Horizontal, FillDirection.Reversed, 0f);
				presetData.Stamina = B(HudAnchor.BottomCenter, 85.7f, 114.3f, 600f, 31.4f, 28.6f, BarEnd.Flat, 0f, BarEnd.Point, 15.7f, BarOrientation.Horizontal, FillDirection.Normal, 0f);
				presetData.Eitr = B(HudAnchor.BottomCenter, -85.7f, 68.6f, 600f, 14.3f, 20f, BarEnd.Flat, 0f, BarEnd.Point, 8.6f, BarOrientation.Horizontal, FillDirection.Reversed, 0f);
				presetData.Adrenaline = B(HudAnchor.BottomCenter, 85.7f, 68.6f, 485.7f, 14.3f, 20f, BarEnd.Flat, 0f, BarEnd.Point, 8.6f, BarOrientation.Horizontal, FillDirection.Normal, 0f);
				presetData.Palette = ForgedIronPalette;
				return presetData;
			}
			return null;
		}
	}
	internal static class FontManager
	{
		public const string GameFont = "Game";

		public const string DefaultNumberFont = "RussoOne-Regular.ttf";

		public const string FontsFolder = "fonts";

		private static TMP_FontAsset _game;

		private static TMP_FontAsset _gameNumbers;

		private static TMP_FontAsset _gameNames;

		private static readonly Dictionary<string, TMP_FontAsset> _loaded = new Dictionary<string, TMP_FontAsset>(StringComparer.OrdinalIgnoreCase);

		private static readonly Dictionary<string, Material> _materials = new Dictionary<string, Material>();

		private static readonly HashSet<Material> _owned = new HashSet<Material>()