Niko666.H3UD.dll

Decompiled 21 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using FistVR;
using Microsoft.CodeAnalysis;
using Sodalite;
using Sodalite.Api;
using UnityEngine;
using UnityEngine.Rendering;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyCompany("Niko666")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("A HUD for H3VR: health, weapon ammo and reserve, a compass with TNH supply and hold point indications, and the run score. Every panel can be customized (somewhat).")]
[assembly: AssemblyFileVersion("1.0.1.0")]
[assembly: AssemblyInformationalVersion("1.0.1")]
[assembly: AssemblyProduct("Niko666.H3UD")]
[assembly: AssemblyTitle("H3UD")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.1.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace BepInEx
{
	[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
	[Conditional("CodeGeneration")]
	internal sealed class BepInAutoPluginAttribute : Attribute
	{
		public BepInAutoPluginAttribute(string id = null, string name = null, string version = null)
		{
		}
	}
}
namespace BepInEx.Preloader.Core.Patching
{
	[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
	[Conditional("CodeGeneration")]
	internal sealed class PatcherAutoPluginAttribute : Attribute
	{
		public PatcherAutoPluginAttribute(string id = null, string name = null, string version = null)
		{
		}
	}
}
namespace Niko666.H3UD
{
	internal static class DotFont
	{
		public const int GlyphW = 5;

		public const int GlyphH = 7;

		public const int Advance = 6;

		private const int First = 32;

		private const int Last = 126;

		private const int Count = 95;

		public const int DegreeIndex = 95;

		public const int MultiplyIndex = 96;

		private static readonly byte[] Bits = new byte[679]
		{
			0, 0, 0, 0, 0, 0, 0, 4, 4, 4,
			4, 4, 0, 4, 10, 10, 0, 0, 0, 0,
			0, 10, 10, 31, 10, 31, 10, 10, 14, 17,
			1, 2, 4, 0, 4, 25, 25, 2, 4, 8,
			19, 19, 12, 20, 12, 21, 18, 18, 13, 4,
			4, 0, 0, 0, 0, 0, 2, 4, 8, 8,
			8, 4, 2, 8, 4, 2, 2, 2, 4, 8,
			0, 21, 14, 31, 14, 21, 0, 0, 4, 4,
			31, 4, 4, 0, 0, 0, 0, 0, 12, 12,
			8, 0, 0, 0, 14, 0, 0, 0, 0, 0,
			0, 0, 0, 12, 12, 1, 2, 2, 4, 8,
			8, 16, 14, 17, 19, 21, 25, 17, 14, 4,
			12, 4, 4, 4, 4, 14, 14, 17, 1, 2,
			4, 8, 31, 31, 2, 4, 2, 1, 17, 14,
			2, 6, 10, 18, 31, 2, 2, 31, 16, 30,
			1, 1, 17, 14, 6, 8, 16, 30, 17, 17,
			14, 31, 1, 2, 4, 8, 8, 8, 14, 17,
			17, 14, 17, 17, 14, 14, 17, 17, 15, 1,
			2, 12, 0, 12, 12, 0, 12, 12, 0, 14,
			17, 1, 2, 4, 0, 4, 2, 4, 8, 16,
			8, 4, 2, 0, 0, 31, 0, 31, 0, 0,
			8, 4, 2, 1, 2, 4, 8, 14, 17, 1,
			2, 4, 0, 4, 0, 17, 10, 4, 10, 17,
			0, 14, 17, 17, 31, 17, 17, 17, 30, 17,
			17, 30, 17, 17, 30, 14, 17, 16, 16, 16,
			17, 14, 30, 17, 17, 17, 17, 17, 30, 31,
			16, 16, 30, 16, 16, 31, 31, 16, 16, 30,
			16, 16, 16, 14, 17, 16, 23, 17, 17, 14,
			17, 17, 17, 31, 17, 17, 17, 14, 4, 4,
			4, 4, 4, 14, 7, 2, 2, 2, 2, 18,
			12, 17, 18, 20, 24, 20, 18, 17, 16, 16,
			16, 16, 16, 16, 31, 17, 27, 21, 21, 17,
			17, 17, 17, 25, 21, 19, 17, 17, 17, 14,
			17, 17, 17, 17, 17, 14, 30, 17, 17, 30,
			16, 16, 16, 14, 17, 17, 17, 21, 18, 13,
			30, 17, 17, 30, 20, 18, 17, 15, 16, 16,
			14, 1, 1, 30, 31, 4, 4, 4, 4, 4,
			4, 17, 17, 17, 17, 17, 17, 14, 17, 17,
			17, 17, 17, 10, 4, 17, 17, 17, 21, 21,
			27, 17, 17, 17, 10, 4, 10, 17, 17, 17,
			17, 10, 4, 4, 4, 4, 31, 1, 2, 4,
			8, 16, 31, 7, 4, 4, 4, 4, 4, 7,
			14, 17, 1, 2, 4, 0, 4, 28, 4, 4,
			4, 4, 4, 28, 14, 17, 1, 2, 4, 0,
			4, 0, 0, 0, 0, 0, 0, 31, 14, 17,
			1, 2, 4, 0, 4, 14, 17, 17, 31, 17,
			17, 17, 30, 17, 17, 30, 17, 17, 30, 14,
			17, 16, 16, 16, 17, 14, 30, 17, 17, 17,
			17, 17, 30, 31, 16, 16, 30, 16, 16, 31,
			31, 16, 16, 30, 16, 16, 16, 14, 17, 16,
			23, 17, 17, 14, 17, 17, 17, 31, 17, 17,
			17, 14, 4, 4, 4, 4, 4, 14, 7, 2,
			2, 2, 2, 18, 12, 17, 18, 20, 24, 20,
			18, 17, 16, 16, 16, 16, 16, 16, 31, 17,
			27, 21, 21, 17, 17, 17, 17, 25, 21, 19,
			17, 17, 17, 14, 17, 17, 17, 17, 17, 14,
			30, 17, 17, 30, 16, 16, 16, 14, 17, 17,
			17, 21, 18, 13, 30, 17, 17, 30, 20, 18,
			17, 15, 16, 16, 14, 1, 1, 30, 31, 4,
			4, 4, 4, 4, 4, 17, 17, 17, 17, 17,
			17, 14, 17, 17, 17, 17, 17, 10, 4, 17,
			17, 17, 21, 21, 27, 17, 17, 17, 10, 4,
			10, 17, 17, 17, 17, 10, 4, 4, 4, 4,
			31, 1, 2, 4, 8, 16, 31, 14, 17, 1,
			2, 4, 0, 4, 4, 4, 4, 4, 4, 4,
			4, 14, 17, 1, 2, 4, 0, 4, 14, 10,
			14, 0, 0, 0, 0, 14, 10, 14, 0, 0,
			0, 0, 0, 17, 10, 4, 10, 17, 0
		};

		public static int Row(int index, int row)
		{
			if (index < 0 || row < 0 || row >= 7)
			{
				return 0;
			}
			int num = index * 7 + row;
			if (num < 0 || num >= Bits.Length)
			{
				return 0;
			}
			return Bits[num];
		}

		public static int IndexOf(char c)
		{
			switch (c)
			{
			case '°':
				return 95;
			case '×':
			case '∗':
				return 96;
			case 'a':
			case 'b':
			case 'c':
			case 'd':
			case 'e':
			case 'f':
			case 'g':
			case 'h':
			case 'i':
			case 'j':
			case 'k':
			case 'l':
			case 'm':
			case 'n':
			case 'o':
			case 'p':
			case 'q':
			case 'r':
			case 's':
			case 't':
			case 'u':
			case 'v':
			case 'w':
			case 'x':
			case 'y':
			case 'z':
				c = (char)(c - 32);
				break;
			}
			int num = c - 32;
			if (num < 0 || num >= 95)
			{
				return 31;
			}
			return num;
		}

		public static int Measure(string s)
		{
			if (string.IsNullOrEmpty(s))
			{
				return 0;
			}
			return s.Length * 6 - 1;
		}

		public static bool IsAscii(string s)
		{
			if (s == null)
			{
				return true;
			}
			foreach (char c in s)
			{
				if (c < ' ' || c > '~')
				{
					return false;
				}
			}
			return true;
		}

		public static string Art(char c)
		{
			int index = IndexOf(c);
			StringBuilder stringBuilder = new StringBuilder();
			for (int i = 0; i < 7; i++)
			{
				int num = Row(index, i);
				for (int j = 0; j < 5; j++)
				{
					stringBuilder.Append(((num & (1 << 4 - j)) != 0) ? '#' : '.');
				}
				if (i < 6)
				{
					stringBuilder.Append('|');
				}
			}
			return stringBuilder.ToString();
		}
	}
	internal class DotSurface
	{
		public readonly int W;

		public readonly int H;

		public readonly Color32[] Px;

		public bool Dirty;

		public DotSurface(int w, int h)
		{
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			W = Mathf.Max(1, w);
			H = Mathf.Max(1, h);
			Px = (Color32[])(object)new Color32[W * H];
			Clear(new Color32((byte)0, (byte)0, (byte)0, (byte)0));
		}

		public int Index(int x, int y)
		{
			return (H - 1 - y) * W + x;
		}

		public void Clear(Color32 c)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			for (int i = 0; i < Px.Length; i++)
			{
				Px[i] = c;
			}
			Dirty = true;
		}

		public void Plot(int x, int y, Color32 c)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			if (x >= 0 && y >= 0 && x < W && y < H)
			{
				Px[Index(x, y)] = c;
				Dirty = true;
			}
		}

		public void Fill(int x, int y, int w, int h, Color32 c)
		{
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			int num = Mathf.Max(0, x);
			int num2 = Mathf.Max(0, y);
			int num3 = Mathf.Min(W, x + w);
			int num4 = Mathf.Min(H, y + h);
			for (int i = num2; i < num4; i++)
			{
				for (int j = num; j < num3; j++)
				{
					Px[Index(j, i)] = c;
				}
			}
			Dirty = true;
		}

		public void Frame(int x, int y, int w, int h, Color32 c)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			HLine(x, y, w, c);
			HLine(x, y + h - 1, w, c);
			VLine(x, y, h, c);
			VLine(x + w - 1, y, h, c);
		}

		public void HLine(int x, int y, int len, Color32 c)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			for (int i = 0; i < len; i++)
			{
				Plot(x + i, y, c);
			}
		}

		public void VLine(int x, int y, int len, Color32 c)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			for (int i = 0; i < len; i++)
			{
				Plot(x, y + i, c);
			}
		}

		public int Glyph(int x, int y, char ch, Color32 c)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			int index = DotFont.IndexOf(ch);
			for (int i = 0; i < 7; i++)
			{
				int num = DotFont.Row(index, i);
				for (int j = 0; j < 5; j++)
				{
					if ((num & (1 << 4 - j)) != 0)
					{
						Plot(x + j, y + i, c);
					}
				}
			}
			return 6;
		}

		public int Text(int x, int y, string s, Color32 c)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			if (string.IsNullOrEmpty(s))
			{
				return x;
			}
			int num = x;
			for (int i = 0; i < s.Length; i++)
			{
				num = ((s[i] != ' ') ? (num + Glyph(num, y, s[i], c)) : (num + 6));
			}
			return num;
		}

		public int TextWidth(string s)
		{
			return DotFont.Measure(s);
		}

		public void TextRight(int rightX, int y, string s, Color32 c)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			Text(rightX - TextWidth(s), y, s, c);
		}

		public void TextCenter(int centerX, int y, string s, Color32 c)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			Text(centerX - TextWidth(s) / 2, y, s, c);
		}

		public void TriangleDown(int cx, int y, int size, Color32 c)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			for (int i = 0; i < size; i++)
			{
				int num = (size - i) / 2;
				HLine(cx - num, y + i, num * 2 + 1, c);
			}
		}
	}
	internal class DotCanvas
	{
		public readonly DotSurface Surf;

		private Texture2D _tex;

		public int W => Surf.W;

		public int H => Surf.H;

		public Texture2D Texture => _tex;

		public DotCanvas(string name, int w, int h)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Expected O, but got Unknown
			Surf = new DotSurface(w, h);
			_tex = new Texture2D(w, h, (TextureFormat)4, false);
			((Object)_tex).name = name;
			((Texture)_tex).filterMode = (FilterMode)0;
			((Texture)_tex).wrapMode = (TextureWrapMode)1;
			((Object)_tex).hideFlags = (HideFlags)61;
		}

		public void Clear(Color32 c)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			Surf.Clear(c);
		}

		public void Apply()
		{
			if (Surf.Dirty && !((Object)(object)_tex == (Object)null))
			{
				_tex.SetPixels32(Surf.Px);
				_tex.Apply(false);
				Surf.Dirty = false;
			}
		}

		public void Release()
		{
			if ((Object)(object)_tex != (Object)null)
			{
				Object.Destroy((Object)(object)_tex);
				_tex = null;
			}
		}
	}
	public enum FontMode
	{
		Dots,
		Vanilla
	}
	public enum PartId
	{
		Compass,
		Status,
		Score,
		Ammo,
		Health,
		Reload,
		Count
	}
	[BepInPlugin("Niko666.H3UD", "H3UD", "1.0.1")]
	[BepInProcess("h3vr.exe")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class H3udPlugin : BaseUnityPlugin
	{
		public const string Guid = "Niko666.H3UD";

		public static H3udPlugin Instance;

		public static string PluginDir;

		public static ManualLogSource Log;

		internal static HudSettings S;

		private ConfigEntry<bool> _enabled;

		private ConfigEntry<float> _dotSize;

		private ConfigEntry<float> _distance;

		private ConfigEntry<float> _lift;

		private ConfigEntry<float> _lagMs;

		private ConfigEntry<float> _plateAlpha;

		private ConfigEntry<string> _textColor;

		private ConfigEntry<string> _accentColor;

		private ConfigEntry<string> _backgroundColor;

		private ConfigEntry<bool> _onTop;

		private ConfigEntry<FontMode> _font;

		private ConfigEntry<float> _vanillaSize;

		private ConfigEntry<float> _yaw;

		private ConfigEntry<float> _pitch;

		private ConfigEntry<float> _roll;

		private ConfigEntry<float> _curveRadius;

		private ConfigEntry<float> _scanRadius;

		private ConfigEntry<bool> _horizonLock;

		private ConfigEntry<float> _adjustGain;

		private ConfigEntry<float> _compassFov;

		private ConfigEntry<bool> _compassMarkers;

		private ConfigEntry<float> _markerBand;

		private ConfigEntry<float> _markerOffset;

		private ConfigEntry<bool> _debugHeights;

		private ConfigEntry<bool> _ammoReserve;

		private ConfigEntry<float> _reserveScanMs;

		private ConfigEntry<float> _fuelScanCm;

		private ConfigEntry<bool> _healthBar;

		private ConfigEntry<float> _dataHz;

		private readonly ConfigEntry<bool>[] _partOn = new ConfigEntry<bool>[6];

		private readonly ConfigEntry<float>[] _partX = new ConfigEntry<float>[6];

		private readonly ConfigEntry<float>[] _partY = new ConfigEntry<float>[6];

		private readonly ConfigEntry<float>[] _partZ = new ConfigEntry<float>[6];

		private readonly ConfigEntry<int>[] _partW = new ConfigEntry<int>[6];

		private readonly ConfigEntry<int>[] _partH = new ConfigEntry<int>[6];

		private HudRig _rig;

		private bool _settingsDirty = true;

		private bool _labelsDirty = true;

		private float _nextCfgPoll;

		private DateTime _cfgStamp = DateTime.MinValue;

		private static readonly string[] PartTitles = new string[6] { "Compass", "Status", "Score", "Ammo", "Health", "Reload" };

		internal static bool DebugHeights;

		private static WristMenuSectionProxy _pageMain;

		private static WristMenuSectionProxy _pagePanels;

		private static WristMenuButton _btnMaster;

		private static WristMenuButton _btnLayout;

		private static WristMenuButton _btnSizeUp;

		private static WristMenuButton _btnSizeDown;

		private static WristMenuButton _btnDistUp;

		private static WristMenuButton _btnDistDown;

		private static WristMenuButton _btnPitchUp;

		private static WristMenuButton _btnPitchDown;

		private static WristMenuButton _btnCurveUp;

		private static WristMenuButton _btnCurveDown;

		private static readonly WristMenuButton[] _btnPart = (WristMenuButton[])(object)new WristMenuButton[6];

		private void Awake()
		{
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			try
			{
				PluginDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
			}
			catch
			{
				PluginDir = null;
			}
			bool num = CfgFilePredatesColors();
			BindConfig();
			if (num)
			{
				MigratePlateAlpha();
			}
			HookConfig();
			if (_enabled.Value)
			{
				EnsureRig();
			}
			InstallWristPage();
			Log.LogInfo((object)"H3UD ready. Watch this log for 'wrist menu page installed' and 'layout saved' after placing a panel by hand.");
		}

		private void HookConfig()
		{
			Hook<bool>(_enabled);
			Hook<float>(_distance);
			Hook<float>(_lift);
			Hook<float>(_dotSize);
			Hook<float>(_lagMs);
			Hook<float>(_plateAlpha);
			Hook<string>(_textColor);
			Hook<string>(_accentColor);
			Hook<string>(_backgroundColor);
			Hook<float>(_yaw);
			Hook<float>(_pitch);
			Hook<float>(_roll);
			Hook<float>(_curveRadius);
			Hook<float>(_scanRadius);
			Hook<bool>(_onTop);
			Hook<FontMode>(_font);
			Hook<float>(_vanillaSize);
			Hook<float>(_dataHz);
			Hook<float>(_reserveScanMs);
			Hook<float>(_fuelScanCm);
			Hook<float>(_compassFov);
			Hook<bool>(_compassMarkers);
			Hook<float>(_markerBand);
			Hook<float>(_markerOffset);
			Hook<bool>(_debugHeights);
			Hook<bool>(_ammoReserve);
			Hook<bool>(_healthBar);
			Hook<bool>(_horizonLock);
			Hook<float>(_adjustGain);
			for (int i = 0; i < 6; i++)
			{
				Hook<bool>(_partOn[i]);
				Hook<float>(_partX[i]);
				Hook<float>(_partY[i]);
				Hook<float>(_partZ[i]);
				Hook<int>(_partW[i]);
				Hook<int>(_partH[i]);
			}
		}

		private void Hook<T>(ConfigEntry<T> entry)
		{
			if (entry != null)
			{
				entry.SettingChanged += OnSettingChanged;
			}
		}

		private bool CfgFilePredatesColors()
		{
			try
			{
				if (!File.Exists(((BaseUnityPlugin)this).Config.ConfigFilePath))
				{
					return false;
				}
				return File.ReadAllText(((BaseUnityPlugin)this).Config.ConfigFilePath).IndexOf("BackgroundColor", StringComparison.OrdinalIgnoreCase) < 0;
			}
			catch
			{
				return false;
			}
		}

		private void MigratePlateAlpha()
		{
			if (_plateAlpha.Value > 0.8f)
			{
				_plateAlpha.Value = 0.35f;
			}
			((BaseUnityPlugin)this).Config.Save();
			Log.LogInfo((object)"config migrated: PlateAlpha reset to the shipped 0.35 and colour keys added");
		}

		private void OnSettingChanged(object sender, EventArgs e)
		{
			_settingsDirty = true;
			_labelsDirty = true;
		}

		private void BindConfig()
		{
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Expected O, but got Unknown
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Expected O, but got Unknown
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Expected O, but got Unknown
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Expected O, but got Unknown
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0157: Expected O, but got Unknown
			//IL_023d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0247: Expected O, but got Unknown
			//IL_027c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0286: Expected O, but got Unknown
			//IL_02bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c5: Expected O, but got Unknown
			//IL_02fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0304: Expected O, but got Unknown
			//IL_0339: Unknown result type (might be due to invalid IL or missing references)
			//IL_0343: Expected O, but got Unknown
			//IL_0378: Unknown result type (might be due to invalid IL or missing references)
			//IL_0382: Expected O, but got Unknown
			//IL_03d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e2: Expected O, but got Unknown
			//IL_0417: Unknown result type (might be due to invalid IL or missing references)
			//IL_0421: Expected O, but got Unknown
			//IL_0456: Unknown result type (might be due to invalid IL or missing references)
			//IL_0460: Expected O, but got Unknown
			//IL_0495: Unknown result type (might be due to invalid IL or missing references)
			//IL_049f: Expected O, but got Unknown
			//IL_04d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_04de: Expected O, but got Unknown
			//IL_0576: Unknown result type (might be due to invalid IL or missing references)
			//IL_0580: Expected O, but got Unknown
			//IL_05b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_05bf: Expected O, but got Unknown
			_enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("1 General", "Enabled", true, "Master switch for the whole HUD.");
			_distance = ((BaseUnityPlugin)this).Config.Bind<float>("2 HUD", "Distance", 0.7f, new ConfigDescription("How far in front of the eyes the HUD floats, in metres.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.2f, 3f), new object[0]));
			_lift = ((BaseUnityPlugin)this).Config.Bind<float>("2 HUD", "Lift", 0f, new ConfigDescription("Moves the whole HUD up or down relative to the eye line, in metres.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-1f, 1f), new object[0]));
			_dotSize = ((BaseUnityPlugin)this).Config.Bind<float>("2 HUD", "DotSize", 0.0014f, new ConfigDescription("Size of one dot of the dot-matrix face, in metres (0.0014 = 10 mm tall glyphs).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.0004f, 0.01f), new object[0]));
			_lagMs = ((BaseUnityPlugin)this).Config.Bind<float>("2 HUD", "LagMs", 120f, new ConfigDescription("How long the HUD trails behind head rotation, in milliseconds (0 = locked).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1500f), new object[0]));
			_plateAlpha = ((BaseUnityPlugin)this).Config.Bind<float>("2 HUD", "PlateAlpha", 0.35f, new ConfigDescription("Opacity of the plate behind each panel (0 = none, 1 = solid).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), new object[0]));
			_textColor = ((BaseUnityPlugin)this).Config.Bind<string>("2 HUD", "TextColor", "FFB028", "Values and numbers, as hex RRGGBB or AARRGGBB.");
			_accentColor = ((BaseUnityPlugin)this).Config.Bind<string>("2 HUD", "AccentColor", "FFB028", "Labels and frames, as hex RRGGBB or AARRGGBB.");
			_backgroundColor = ((BaseUnityPlugin)this).Config.Bind<string>("2 HUD", "BackgroundColor", "000000", "Plate colour behind the panels, as hex RRGGBB or AARRGGBB.");
			_onTop = ((BaseUnityPlugin)this).Config.Bind<bool>("2 HUD", "AlwaysOnTop", true, "true = the HUD draws over walls and scenery, false = the world occludes it.");
			_font = ((BaseUnityPlugin)this).Config.Bind<FontMode>("2 HUD", "Font", FontMode.Dots, "Dots = the built-in dot-matrix face, Vanilla = the game's own font.");
			_vanillaSize = ((BaseUnityPlugin)this).Config.Bind<float>("2 HUD", "VanillaFontSize", 0.0026f, new ConfigDescription("Text size used when Font = Vanilla.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.0005f, 0.05f), new object[0]));
			_dataHz = ((BaseUnityPlugin)this).Config.Bind<float>("2 HUD", "RefreshHz", 30f, new ConfigDescription("How many times a second game data is re-read and the panels redrawn.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 60f), new object[0]));
			_yaw = ((BaseUnityPlugin)this).Config.Bind<float>("2 HUD", "Yaw", 0f, new ConfigDescription("Turns the whole HUD left or right, in degrees.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-180f, 180f), new object[0]));
			_pitch = ((BaseUnityPlugin)this).Config.Bind<float>("2 HUD", "Pitch", 0f, new ConfigDescription("Tilts the whole HUD up or down, in degrees.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-180f, 180f), new object[0]));
			_roll = ((BaseUnityPlugin)this).Config.Bind<float>("2 HUD", "Roll", 0f, new ConfigDescription("Rotates the whole HUD around your line of sight, in degrees.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-180f, 180f), new object[0]));
			_curveRadius = ((BaseUnityPlugin)this).Config.Bind<float>("2 HUD", "CurveRadius", 0.9f, new ConfigDescription("Wraps the HUD on a cylinder this many metres away; 0 = flat screen.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 20f), new object[0]));
			_horizonLock = ((BaseUnityPlugin)this).Config.Bind<bool>("2 HUD", "HorizonLock", false, "true = the HUD only follows your heading and stays level when you look up or down.");
			_adjustGain = ((BaseUnityPlugin)this).Config.Bind<float>("2 HUD", "AdjustGain", 0.3f, new ConfigDescription("How fast a panel edge follows the hand in adjust mode (1 = one to one, 0.3 = a third as fast).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.05f, 2f), new object[0]));
			_scanRadius = ((BaseUnityPlugin)this).Config.Bind<float>("2 HUD", "ScanRadiusCm", 0f, new ConfigDescription("Fallback radius for counting carried ammunition; 0 = belt slots and hands only.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 250f), new object[0]));
			_compassFov = ((BaseUnityPlugin)this).Config.Bind<float>("3 Compass", "WindowDegrees", 150f, new ConfigDescription("How many degrees of bearing the compass ribbon shows.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(10f, 360f), new object[0]));
			_markerBand = ((BaseUnityPlugin)this).Config.Bind<float>("3 Compass", "LevelBandCm", 100f, new ConfigDescription("Objectives within this height difference count as the same floor and get no arrow, in centimetres.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 600f), new object[0]));
			_markerOffset = ((BaseUnityPlugin)this).Config.Bind<float>("3 Compass", "HeightOffsetCm", 0f, new ConfigDescription("Shifts the height baseline used by the markers, in centimetres; only needed if a map's spawn points sit high or low.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-300f, 300f), new object[0]));
			_debugHeights = ((BaseUnityPlugin)this).Config.Bind<bool>("3 Compass", "DebugHeights", false, "Log the marker height calculation every 30 s - only needed when an arrow points the wrong way on some map.");
			_compassMarkers = ((BaseUnityPlugin)this).Config.Bind<bool>("3 Compass", "ShowObjectives", true, "Draw Take and Hold hold points (H) and supply points (S) on the compass.");
			_ammoReserve = ((BaseUnityPlugin)this).Config.Bind<bool>("4 Ammo", "ShowReserve", true, "Show how much matching ammunition is left on the body (RES line).");
			_reserveScanMs = ((BaseUnityPlugin)this).Config.Bind<float>("4 Ammo", "ReserveScanMs", 400f, new ConfigDescription("How often (ms) the fallback radius sweep re-lists nearby ammunition; higher is cheaper. Ignored when ScanRadiusCm is 0.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(100f, 5000f), new object[0]));
			_fuelScanCm = ((BaseUnityPlugin)this).Config.Bind<float>("4 Ammo", "FuelScanCm", 0f, new ConfigDescription("Radius (cm) the spare fuel-cell sweep looks around you; 0 = only quickbelt slots and items carried on the player.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 300f), new object[0]));
			_healthBar = ((BaseUnityPlugin)this).Config.Bind<bool>("5 Health", "ShowBar", true, "Draw the health gauge under the number.");
			BindPart(PartId.Compass, "6 Compass Panel", on: true, 0f, 0.26f, 0f, 480, 40);
			BindPart(PartId.Status, "7 Status Panel", on: true, 0f, 0.22f, 0f, 210, 14);
			BindPart(PartId.Score, "8 Score Panel", on: true, -0.37f, -0.26f, 0f, 132, 24);
			BindPart(PartId.Ammo, "9 Ammo Panel", on: true, 0.36f, -0.285f, 0f, 172, 46);
			BindPart(PartId.Health, "10 Health Panel", on: true, -0.37f, -0.3f, 0f, 132, 26);
			BindPart(PartId.Reload, "11 Reload Panel", on: true, 0f, -0.15f, 0f, 138, 16);
		}

		private void BindPart(PartId id, string section, bool on, float x, float y, float z, int w, int h)
		{
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Expected O, but got Unknown
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Expected O, but got Unknown
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Expected O, but got Unknown
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Expected O, but got Unknown
			//IL_0149: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Expected O, but got Unknown
			string text = PartTitles[(int)id];
			_partOn[(int)id] = ((BaseUnityPlugin)this).Config.Bind<bool>(section, "Enabled", on, "Show the " + text.ToLowerInvariant() + " panel.");
			_partX[(int)id] = ((BaseUnityPlugin)this).Config.Bind<float>(section, "OffsetX", x, new ConfigDescription("Panel offset to the right of the HUD centre, in metres.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-2f, 2f), new object[0]));
			_partY[(int)id] = ((BaseUnityPlugin)this).Config.Bind<float>(section, "OffsetY", y, new ConfigDescription("Panel offset above the HUD centre, in metres.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-1.5f, 1.5f), new object[0]));
			_partZ[(int)id] = ((BaseUnityPlugin)this).Config.Bind<float>(section, "OffsetZ", z, new ConfigDescription("Panel offset away from the player, in metres.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-1f, 1f), new object[0]));
			_partW[(int)id] = ((BaseUnityPlugin)this).Config.Bind<int>(section, "WidthDots", w, new ConfigDescription("Panel width in dots (bigger = more room, not stretched letters).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(24, 480), new object[0]));
			_partH[(int)id] = ((BaseUnityPlugin)this).Config.Bind<int>(section, "HeightDots", h, new ConfigDescription("Panel height in dots.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(8, 160), new object[0]));
		}

		private void Update()
		{
			PollConfigFile();
			if (_enabled.Value)
			{
				EnsureRig();
			}
			if ((Object)(object)_rig != (Object)null && _settingsDirty)
			{
				_settingsDirty = false;
				S = ResolveSettings();
				_rig.ApplySettings(S);
				_rig.SetVisible(_enabled.Value);
			}
			if (_labelsDirty)
			{
				_labelsDirty = false;
				RefreshLabels();
			}
		}

		private void PollConfigFile()
		{
			if (Time.unscaledTime < _nextCfgPoll)
			{
				return;
			}
			_nextCfgPoll = Time.unscaledTime + 1f;
			try
			{
				DateTime lastWriteTimeUtc = File.GetLastWriteTimeUtc(((BaseUnityPlugin)this).Config.ConfigFilePath);
				if (_cfgStamp == DateTime.MinValue)
				{
					_cfgStamp = lastWriteTimeUtc;
				}
				else if (!(lastWriteTimeUtc == _cfgStamp))
				{
					_cfgStamp = lastWriteTimeUtc;
					((BaseUnityPlugin)this).Config.Reload();
					_settingsDirty = true;
					_labelsDirty = true;
					Log.LogInfo((object)"config file changed, reloaded");
				}
			}
			catch (Exception ex)
			{
				Log.LogWarning((object)("config reload failed: " + ex.Message));
			}
		}

		private void EnsureRig()
		{
			if (!((Object)(object)_rig != (Object)null))
			{
				_rig = HudRig.Create();
				_settingsDirty = true;
			}
		}

		private HudSettings ResolveSettings()
		{
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: Unknown result type (might be due to invalid IL or missing references)
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_0145: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			HudSettings result = new HudSettings
			{
				Enabled = _enabled.Value,
				OnTop = _onTop.Value,
				VanillaFont = (_font.Value == FontMode.Vanilla),
				CompassMarkers = _compassMarkers.Value,
				AmmoReserve = _ammoReserve.Value,
				HealthBar = _healthBar.Value,
				DotSize = _dotSize.Value,
				Distance = _distance.Value,
				Lift = _lift.Value,
				LagMs = _lagMs.Value,
				PlateAlpha = _plateAlpha.Value,
				Text = HudMath.ParseHexColor(_textColor.Value, new Color32(byte.MaxValue, (byte)176, (byte)40, byte.MaxValue)),
				Accent = HudMath.ParseHexColor(_accentColor.Value, new Color32(byte.MaxValue, (byte)176, (byte)40, byte.MaxValue)),
				Background = HudMath.ParseHexColor(_backgroundColor.Value, new Color32((byte)0, (byte)0, (byte)0, byte.MaxValue)),
				VanillaSize = _vanillaSize.Value,
				Yaw = _yaw.Value,
				Pitch = _pitch.Value,
				Roll = _roll.Value,
				CurveRadius = _curveRadius.Value,
				ScanRadius = _scanRadius.Value / 100f,
				CompassFov = _compassFov.Value,
				MarkerBand = _markerBand.Value / 100f,
				MarkerOffset = _markerOffset.Value / 100f
			};
			DebugHeights = _debugHeights.Value;
			HudData.NearRefreshSeconds = Mathf.Max(0.1f, _reserveScanMs.Value / 1000f);
			HudData.FuelScanRadius = _fuelScanCm.Value / 100f;
			result.DataInterval = 1f / Mathf.Max(1f, _dataHz.Value);
			result.HorizonLock = _horizonLock.Value;
			result.AdjustGain = _adjustGain.Value;
			result.PartOn = new bool[6];
			result.OffX = new float[6];
			result.OffY = new float[6];
			result.OffZ = new float[6];
			result.SizeW = new int[6];
			result.SizeH = new int[6];
			for (int i = 0; i < 6; i++)
			{
				result.PartOn[i] = _partOn[i] != null && _partOn[i].Value;
				result.OffX[i] = ((_partX[i] != null) ? _partX[i].Value : 0f);
				result.OffY[i] = ((_partY[i] != null) ? _partY[i].Value : 0f);
				result.OffZ[i] = ((_partZ[i] != null) ? _partZ[i].Value : 0f);
				result.SizeW[i] = ((_partW[i] != null) ? _partW[i].Value : 0);
				result.SizeH[i] = ((_partH[i] != null) ? _partH[i].Value : 0);
			}
			return result;
		}

		private void InstallWristPage()
		{
			try
			{
				_pageMain = WristMenuAPI.CreateSection("H3UD");
				_btnMaster = NewButton(_pageMain, "HUD", delegate
				{
					ToggleMaster();
				});
				_btnLayout = NewButton(_pageMain, "Adjust panels", delegate
				{
					ToggleLayoutEdit();
				});
				_btnSizeDown = NewButton(_pageMain, "Size -", delegate
				{
					Nudge(_dotSize, -0.0001f, 0.0004f, 0.01f);
				});
				_btnSizeUp = NewButton(_pageMain, "Size +", delegate
				{
					Nudge(_dotSize, 0.0001f, 0.0004f, 0.01f);
				});
				_btnDistDown = NewButton(_pageMain, "Dist -", delegate
				{
					Nudge(_distance, -0.02f, 0.2f, 3f);
				});
				_btnDistUp = NewButton(_pageMain, "Dist +", delegate
				{
					Nudge(_distance, 0.02f, 0.2f, 3f);
				});
				_btnPitchDown = NewButton(_pageMain, "Pitch -", delegate
				{
					Nudge(_pitch, -2f, -90f, 90f);
				});
				_btnPitchUp = NewButton(_pageMain, "Pitch +", delegate
				{
					Nudge(_pitch, 2f, -90f, 90f);
				});
				_btnCurveDown = NewButton(_pageMain, "Curve -", delegate
				{
					NudgeCurve(-0.1f);
				});
				_btnCurveUp = NewButton(_pageMain, "Curve +", delegate
				{
					NudgeCurve(0.1f);
				});
				_pagePanels = WristMenuAPI.CreateSection("H3UD Panels");
				for (int num = 0; num < 6; num++)
				{
					int captured = num;
					_btnPart[captured] = NewButton(_pagePanels, PartTitles[num], delegate
					{
						TogglePart((PartId)captured);
					});
				}
				NewButton(_pagePanels, "Reset layout", delegate
				{
					ResetLayout();
				});
				RefreshLabels();
				Log.LogInfo((object)"wrist menu pages installed: H3UD + H3UD Panels");
			}
			catch (Exception ex)
			{
				Log.LogWarning((object)("wrist menu page failed (Sodalite missing or moved?): " + ex.Message));
			}
		}

		private static WristMenuButton NewButton(WristMenuSectionProxy section, string label, Action onClick)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Expected O, but got Unknown
			WristMenuButton val = new WristMenuButton(label, Click(onClick));
			val.OnCreate += delegate
			{
				if ((Object)(object)Instance != (Object)null)
				{
					Instance.RefreshLabels();
				}
			};
			if (section != null)
			{
				section.Buttons.Add(val);
			}
			return val;
		}

		private static ButtonClickEvent Click(Action a)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Expected O, but got Unknown
			return (ButtonClickEvent)delegate
			{
				try
				{
					a();
				}
				catch (Exception ex)
				{
					Log.LogWarning((object)("H3UD button failed: " + ex.Message));
				}
				Boop();
			};
		}

		private static void Boop()
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				FVRPlayerBody currentPlayerBody = GM.CurrentPlayerBody;
				if ((Object)(object)currentPlayerBody != (Object)null)
				{
					SM.PlayGlobalUISound((GlobalUISound)1, ((Component)currentPlayerBody).transform.position);
				}
			}
			catch
			{
			}
		}

		private void ToggleMaster()
		{
			_enabled.Value = !_enabled.Value;
			((BaseUnityPlugin)this).Config.Save();
			if (!_enabled.Value && (Object)(object)_rig != (Object)null)
			{
				_rig.SetEditing(on: false);
			}
			_settingsDirty = true;
			_labelsDirty = true;
			Log.LogInfo((object)("HUD " + (_enabled.Value ? "shown" : "hidden") + " from the wrist menu"));
		}

		private void TogglePart(PartId id)
		{
			ConfigEntry<bool> val = _partOn[(int)id];
			if (val != null)
			{
				val.Value = !val.Value;
				((BaseUnityPlugin)this).Config.Save();
				_settingsDirty = true;
				_labelsDirty = true;
				Log.LogInfo((object)(PartTitles[(int)id] + " panel " + (val.Value ? "on" : "off")));
			}
		}

		private void ToggleFont()
		{
			_font.Value = ((_font.Value == FontMode.Dots) ? FontMode.Vanilla : FontMode.Dots);
			((BaseUnityPlugin)this).Config.Save();
			_settingsDirty = true;
			_labelsDirty = true;
			Log.LogInfo((object)("font mode: " + _font.Value));
		}

		private void Nudge(ConfigEntry<float> entry, float delta, float lo, float hi)
		{
			if (entry != null)
			{
				entry.Value = Mathf.Clamp(entry.Value + delta, lo, hi);
				((BaseUnityPlugin)this).Config.Save();
				_settingsDirty = true;
				_labelsDirty = true;
				Log.LogInfo((object)(((ConfigEntryBase)entry).Definition.Key + " = " + entry.Value.ToString("0.####")));
			}
		}

		private void NudgeCurve(float delta)
		{
			float num = Mathf.Clamp(_curveRadius.Value + delta, 0f, 20f);
			if (num < 0.15f)
			{
				num = 0f;
			}
			_curveRadius.Value = num;
			((BaseUnityPlugin)this).Config.Save();
			_settingsDirty = true;
			_labelsDirty = true;
			Log.LogInfo((object)("CurveRadius = " + ((num <= 0f) ? "off (flat)" : (num.ToString("0.0") + " m"))));
		}

		private void ToggleLayoutEdit()
		{
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_rig == (Object)null)
			{
				EnsureRig();
			}
			if ((Object)(object)_rig == (Object)null)
			{
				return;
			}
			if (!_rig.Editing)
			{
				_rig.SetEditing(on: true);
				_settingsDirty = true;
				_labelsDirty = true;
				Log.LogInfo((object)"adjust mode on: W band = width, H band = height, MOVE box = position");
				return;
			}
			for (int i = 0; i < 6; i++)
			{
				Vector3 val = _rig.OffsetOf((PartId)i);
				_partX[i].Value = val.x;
				_partY[i].Value = val.y;
				_rig.SizeOf((PartId)i, out var w, out var h);
				if (w > 0)
				{
					_partW[i].Value = w;
				}
				if (h > 0)
				{
					_partH[i].Value = h;
				}
			}
			_rig.SetEditing(on: false);
			((BaseUnityPlugin)this).Config.Save();
			_settingsDirty = true;
			_labelsDirty = true;
			string text = "";
			for (int j = 0; j < 6; j++)
			{
				text = text + "\n  " + PartTitles[j] + ": X " + _partX[j].Value.ToString("0.000") + "  Y " + _partY[j].Value.ToString("0.000") + "  " + _partW[j].Value + "x" + _partH[j].Value;
			}
			Log.LogInfo((object)("layout saved:" + text));
		}

		private void ResetLayout()
		{
			if ((Object)(object)_rig != (Object)null)
			{
				_rig.SetEditing(on: false);
			}
			float[] array = new float[6] { 0f, 0f, -0.37f, 0.36f, -0.37f, 0f };
			float[] array2 = new float[6] { 0.26f, 0.22f, -0.26f, -0.285f, -0.3f, -0.15f };
			int[] array3 = new int[6] { 480, 210, 132, 172, 132, 138 };
			int[] array4 = new int[6] { 40, 14, 24, 46, 26, 16 };
			for (int i = 0; i < 6; i++)
			{
				_partX[i].Value = array[i];
				_partY[i].Value = array2[i];
				_partZ[i].Value = 0f;
				_partW[i].Value = array3[i];
				_partH[i].Value = array4[i];
			}
			_distance.Value = 0.7f;
			_dotSize.Value = 0.0014f;
			_roll.Value = 0f;
			_yaw.Value = 0f;
			_pitch.Value = 0f;
			_curveRadius.Value = 0.9f;
			((BaseUnityPlugin)this).Config.Save();
			_settingsDirty = true;
			_labelsDirty = true;
			Log.LogInfo((object)"layout reset to the shipped defaults");
		}

		private void RefreshLabels()
		{
			try
			{
				if (_btnMaster != null)
				{
					_btnMaster.Text = (_enabled.Value ? "HUD: ON" : "HUD: OFF");
				}
				for (int i = 0; i < 6; i++)
				{
					WristMenuButton val = _btnPart[i];
					if (val != null)
					{
						bool flag = _partOn[i] != null && _partOn[i].Value;
						val.Text = PartTitles[i] + ": " + (flag ? "ON" : "OFF");
					}
				}
				if (_btnLayout != null)
				{
					_btnLayout.Text = (((Object)(object)_rig != (Object)null && _rig.Editing) ? "Finish adjust" : "Adjust panels");
				}
				if (_btnSizeUp != null)
				{
					_btnSizeUp.Text = "Size + " + Mathf.RoundToInt(_dotSize.Value * 1000f) + "mm";
				}
				if (_btnDistUp != null)
				{
					_btnDistUp.Text = "Dist + " + Mathf.RoundToInt(_distance.Value * 100f) + "cm";
				}
				if (_btnPitchUp != null)
				{
					_btnPitchUp.Text = "Pitch + " + Mathf.RoundToInt(_pitch.Value) + "d";
				}
				if (_btnCurveUp != null)
				{
					_btnCurveUp.Text = ((_curveRadius.Value <= 0.01f) ? "Curve + off" : ("Curve + " + _curveRadius.Value.ToString("0.0") + "m"));
				}
			}
			catch (Exception ex)
			{
				Log.LogWarning((object)("label refresh failed: " + ex.Message));
			}
		}
	}
	internal struct HudMarker
	{
		public float Bearing;

		public float Distance;

		public float Height;

		public bool IsHold;
	}
	internal struct HudSnapshot
	{
		public bool BodyOk;

		public float Health;

		public float MaxHealth;

		public bool WeaponOk;

		public bool NoAmmoModel;

		public int HandTag;

		public bool TwoWeapons;

		public string WeaponName;

		public string RoundName;

		public bool HasMag;

		public bool HasClip;

		public bool HasBelt;

		public bool BeltInBox;

		public int MagRounds;

		public int MagCapacity;

		public bool IsFuel;

		public int FuelPercent;

		public int ChamberLive;

		public int ChamberCount;

		public int ClipRounds;

		public int ClipCapacity;

		public int BeltRounds;

		public int ReserveRounds;

		public int ReserveMags;

		public int ReserveFuelPercent;

		public int WeaponChambers;

		public bool HeldAmmoOk;

		public bool AmmoWins;

		public string HeldAmmoName;

		public string HeldAmmoRound;

		public int HeldAmmoRounds;

		public int HeldAmmoCapacity;

		public FireArmRoundType WeaponRoundType;

		public FireArmMagazineType WeaponMagType;

		public FireArmClipType WeaponClipType;

		public int HeldKind;

		public FireArmRoundType HeldRoundType;

		public FireArmMagazineType HeldMagType;

		public FireArmClipType HeldClipType;

		public int HeldFits;

		public bool HeldItemOk;

		public string HeldItemName;

		public string HeldItemKind;

		public string HeldItemFeature;

		public string HeldItemExtra;

		public float Heading;

		public bool TnhOk;

		public int Score;

		public int Mult;

		public int Level;

		public int MaxLevels;

		public int Tokens;

		public string PhaseName;

		public string HoldStateName;

		public float HoldTimer;

		public int HoldNumber;

		public int HoldTotal;

		public int HoldPhaseNumber;

		public int HoldPhaseTotal;

		public float HoldDistance;

		public float HoldBearing;

		public bool HoldOk;

		public HudMarker[] Markers;

		public int MarkerCount;
	}
	internal static class HudData
	{
		private const int MaxMarkers = 8;

		private static HudMarker[] _markers = new HudMarker[8];

		private static bool _warned;

		private static readonly Transform[] _handT = (Transform[])(object)new Transform[2];

		private static readonly FVRViveHand[] _handC = (FVRViveHand[])(object)new FVRViveHand[2];

		private static float _handNext;

		private static FVRFireArm _cylGun;

		private static RevolverCylinder _cylCache;

		private static int _lastLoggedWeapon = -1;

		private static string _lastNextLog = "";

		private static readonly HashSet<int> _seen = new HashSet<int>();

		private static FVRQuickBeltSlot[] _slotCache;

		private static float _slotNext;

		private static readonly List<FVRFireArmMagazine> _fuelList = new List<FVRFireArmMagazine>();

		internal static float FuelScanRadius;

		private static float _fuelNext;

		internal static float NearRefreshSeconds = 0.4f;

		private static readonly List<FVRPhysicalObject> _nearList = new List<FVRPhysicalObject>();

		private static float _nearNext;

		private static float _nearRadius = -1f;

		private static FVRFireArm _nearWeapon;

		private static float _nextHeightLog;

		private static float _nextFuelLog;

		private static readonly RaycastHit[] _floorHits = (RaycastHit[])(object)new RaycastHit[32];

		private static readonly int[] ScoreWeights = new int[15]
		{
			12000, 12, 1, 12, 300, 100, 100, 100, 100, 1,
			250, 12, 1, 1, 250
		};

		private static readonly bool[] ScoreCounted = new bool[15]
		{
			true, true, false, true, true, true, true, false, false, false,
			false, true, false, false, false
		};

		public static HudSnapshot Collect(float scanRadiusMetres)
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			HudSnapshot s = new HudSnapshot
			{
				Markers = _markers,
				MarkerCount = 0
			};
			try
			{
				CollectBody(ref s);
				FVRFireArm val = HeldFireArm();
				CollectWeapon(ref s, val, out var roundType);
				CollectReserve(ref s, val, roundType, scanRadiusMetres);
				if (s.IsFuel)
				{
					LogFuelSweep(s);
				}
				HudSnapshot s2 = default(HudSnapshot);
				float dist = float.MaxValue;
				bool ammoOk = CollectHeldAmmo(ref s2, out dist);
				HudSnapshot into = default(HudSnapshot);
				float dist2 = float.MaxValue;
				bool itemOk = CollectHeldItem(ref into, out dist2);
				float weaponDist = (((Object)(object)val == (Object)null) ? float.MaxValue : HeadDistance(((Component)val).transform));
				switch (PanelOwner(s.WeaponOk, weaponDist, ammoOk, dist, itemOk, dist2))
				{
				case 1:
					AdoptHeld(ref s, s2);
					break;
				case 2:
					s.HeldItemOk = !string.IsNullOrEmpty(into.HeldItemName);
					s.HeldItemName = into.HeldItemName;
					s.HeldItemKind = into.HeldItemKind;
					s.HeldItemFeature = into.HeldItemFeature;
					s.HeldItemExtra = into.HeldItemExtra;
					break;
				}
				CollectTnh(ref s);
				CollectHeading(ref s);
			}
			catch (Exception ex)
			{
				if (!_warned)
				{
					_warned = true;
					H3udPlugin.Log.LogWarning((object)("HUD data read failed (reported once): " + ex.Message));
				}
			}
			return s;
		}

		internal static int PanelOwner(bool weaponOk, float weaponDist, bool ammoOk, float ammoDist, bool itemOk, float itemDist)
		{
			if (weaponOk && weaponDist <= ammoDist && weaponDist <= itemDist)
			{
				return 0;
			}
			if (ammoOk && ammoDist <= itemDist)
			{
				return 1;
			}
			if (itemOk)
			{
				return 2;
			}
			if (ammoOk)
			{
				return 1;
			}
			return 0;
		}

		private static void CollectBody(ref HudSnapshot s)
		{
			FVRPlayerBody currentPlayerBody = GM.CurrentPlayerBody;
			if (!((Object)(object)currentPlayerBody == (Object)null))
			{
				s.BodyOk = true;
				s.Health = currentPlayerBody.Health;
				s.MaxHealth = ((currentPlayerBody.m_startingHealth > 0f) ? currentPlayerBody.m_startingHealth : 100f);
			}
		}

		private static int StackSize(FVRFireArmRound round)
		{
			int num = 1;
			try
			{
				if (round.ProxyRounds != null)
				{
					num += round.ProxyRounds.Count;
				}
			}
			catch
			{
			}
			return num;
		}

		private static FVRViveHand Hand(bool right)
		{
			FVRPlayerBody currentPlayerBody = GM.CurrentPlayerBody;
			if ((Object)(object)currentPlayerBody == (Object)null)
			{
				return null;
			}
			Transform val = (right ? currentPlayerBody.RightHand : currentPlayerBody.LeftHand);
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			int num = ((!right) ? 1 : 0);
			float unscaledTime = Time.unscaledTime;
			if (unscaledTime < _handNext && val == _handT[num] && (Object)(object)_handC[num] != (Object)null)
			{
				return _handC[num];
			}
			_handT[num] = val;
			_handC[num] = ((Component)val).GetComponent<FVRViveHand>();
			_handNext = unscaledTime + 1f;
			return _handC[num];
		}

		public static FVRFireArm HeldFireArm()
		{
			FVRFireArm val = FireArmIn(right: true);
			FVRFireArm val2 = FireArmIn(right: false);
			if ((Object)(object)val == (Object)null)
			{
				return val2;
			}
			if ((Object)(object)val2 == (Object)null)
			{
				return val;
			}
			if (val == val2)
			{
				return val;
			}
			if (!(AimScore(val2) > AimScore(val)))
			{
				return val;
			}
			return val2;
		}

		private static float AimScore(FVRFireArm fa)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				FVRPlayerBody currentPlayerBody = GM.CurrentPlayerBody;
				if ((Object)(object)currentPlayerBody == (Object)null || (Object)(object)currentPlayerBody.Head == (Object)null)
				{
					return 0f;
				}
				Vector3 position = currentPlayerBody.Head.position;
				Vector3 val = ((Component)fa).transform.position - position;
				if (((Vector3)(ref val)).sqrMagnitude < 0.0001f)
				{
					return 0f;
				}
				return Vector3.Dot(((Vector3)(ref val)).normalized, currentPlayerBody.Head.forward);
			}
			catch
			{
				return 0f;
			}
		}

		private static FVRFireArm FireArmIn(bool right)
		{
			FVRViveHand val = Hand(right);
			if ((Object)(object)val == (Object)null || (Object)(object)val.CurrentInteractable == (Object)null)
			{
				return null;
			}
			FVRInteractiveObject currentInteractable = val.CurrentInteractable;
			return (FVRFireArm)(object)((currentInteractable is FVRFireArm) ? currentInteractable : null);
		}

		private static void CollectWeapon(ref HudSnapshot s, FVRFireArm fa, out FireArmRoundType roundType)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Expected I4, but got Unknown
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_02dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0248: Unknown result type (might be due to invalid IL or missing references)
			//IL_024f: Invalid comparison between Unknown and I4
			roundType = (FireArmRoundType)0;
			if ((Object)(object)fa == (Object)null)
			{
				return;
			}
			s.WeaponOk = true;
			roundType = (FireArmRoundType)(int)fa.RoundType;
			s.WeaponRoundType = fa.RoundType;
			s.WeaponMagType = fa.MagazineType;
			s.WeaponClipType = fa.ClipType;
			s.WeaponName = WeaponName(fa);
			FVRFireArm val = FireArmIn(right: true);
			FVRFireArm val2 = FireArmIn(right: false);
			s.HandTag = (((s.TwoWeapons = (Object)(object)val != (Object)null && (Object)(object)val2 != (Object)null && val != val2) && fa == val2) ? 1 : 0);
			if ((Object)(object)fa.Magazine != (Object)null)
			{
				s.HasMag = true;
				s.MagRounds = fa.Magazine.m_numRounds;
				s.MagCapacity = fa.Magazine.m_capacity;
				if (IsFuelMag(fa.Magazine))
				{
					s.IsFuel = true;
					s.FuelPercent = FuelPercentOf(fa.Magazine);
				}
			}
			if ((Object)(object)fa.Clip != (Object)null)
			{
				s.HasClip = true;
				s.ClipRounds = fa.Clip.m_numRounds;
				s.ClipCapacity = fa.Clip.m_capacity;
			}
			if (fa.FChambers != null)
			{
				s.ChamberCount = fa.FChambers.Count;
				for (int i = 0; i < fa.FChambers.Count; i++)
				{
					FVRFireArmChamber val3 = fa.FChambers[i];
					if (!((Object)(object)val3 == (Object)null) && !((Object)(object)val3.m_round == (Object)null) && !val3.IsSpent)
					{
						s.ChamberLive++;
					}
				}
			}
			if (fa.UsesBelts || fa.UsesBeltBoxes || fa.HasBelt)
			{
				s.HasBelt = true;
				try
				{
					if ((Object)(object)fa.BeltDD != (Object)null)
					{
						s.BeltRounds = fa.BeltDD.NumRoundsOnBelt;
					}
				}
				catch
				{
				}
				try
				{
					s.BeltInBox = (Object)(object)fa.Magazine != (Object)null && fa.Magazine.IsBeltBox;
				}
				catch
				{
				}
			}
			FVRFireArmChamber[] componentsInChildren = ((Component)fa).GetComponentsInChildren<FVRFireArmChamber>(true);
			if (componentsInChildren != null)
			{
				foreach (FVRFireArmChamber val4 in componentsInChildren)
				{
					if (!((Object)(object)val4 == (Object)null) && !((Object)(object)val4.m_round == (Object)null) && !val4.IsSpent && !IsFiringChamber(fa, val4) && (int)val4.m_round.RoundType == (int)roundType)
					{
						s.WeaponChambers++;
					}
				}
			}
			if (!s.IsFuel && (fa is sblp || fa is FlameThrower))
			{
				s.IsFuel = true;
				s.FuelPercent = 0;
			}
			s.NoAmmoModel = !s.HasMag && !s.HasClip && !s.HasBelt && (fa.FChambers == null || fa.FChambers.Count == 0);
			LogWeaponShape(fa);
			if (NextRoundClass(fa, out var cls))
			{
				s.RoundName = RoundName(roundType, cls);
			}
			else
			{
				s.RoundName = CaliberName(roundType);
			}
		}

		private static bool IsFiringChamber(FVRFireArm fa, FVRFireArmChamber ch)
		{
			if (fa.FChambers == null)
			{
				return false;
			}
			for (int i = 0; i < fa.FChambers.Count; i++)
			{
				if (fa.FChambers[i] == ch)
				{
					return true;
				}
			}
			return false;
		}

		private static RevolverCylinder CylinderOf(FVRFireArm fa)
		{
			if (fa == _cylGun)
			{
				return _cylCache;
			}
			_cylGun = fa;
			_cylCache = ((Component)fa).GetComponentInChildren<RevolverCylinder>();
			return _cylCache;
		}

		private unsafe static void LogNextPick(int barrel, FireArmRoundClass cls)
		{
			if (H3udPlugin.Log != null && H3udPlugin.DebugHeights)
			{
				string text = barrel + "/" + ((object)(*(FireArmRoundClass*)(&cls))/*cast due to .constrained prefix*/).ToString();
				if (!(text == _lastNextLog))
				{
					_lastNextLog = text;
					H3udPlugin.Log.LogInfo((object)("next round: barrel " + barrel + " class " + ((object)(*(FireArmRoundClass*)(&cls))/*cast due to .constrained prefix*/).ToString()));
				}
			}
		}

		private static void LogWeaponShape(FVRFireArm fa)
		{
			if (H3udPlugin.Log == null || !H3udPlugin.DebugHeights)
			{
				return;
			}
			int instanceID = ((Object)fa).GetInstanceID();
			if (instanceID == _lastLoggedWeapon)
			{
				return;
			}
			_lastLoggedWeapon = instanceID;
			string text = "";
			int num = 0;
			BreakActionWeapon val = (BreakActionWeapon)(object)((fa is BreakActionWeapon) ? fa : null);
			if ((Object)(object)val != (Object)null && val.Barrels != null)
			{
				num = val.Barrels.Length;
				text = " fireAll=" + val.FireAllBarrels + " cur=" + val.m_curBarrel;
				for (int i = 0; i < val.Barrels.Length; i++)
				{
					BreakActionBarrel val2 = val.Barrels[i];
					string text2 = ((val2 == null) ? "?" : ((((Object)(object)val2.Chamber != (Object)null && val2.Chamber.IsFull && !val2.Chamber.IsSpent) ? ("L:" + (((Object)(object)val2.Chamber.m_round != (Object)null) ? HudMath.RoundClassAbbrev(((object)Unsafe.As<FireArmRoundClass, FireArmRoundClass>(ref val2.Chamber.m_round.RoundClass)/*cast due to .constrained prefix*/).ToString()) : "?")) : (((Object)(object)val2.Chamber != (Object)null && val2.Chamber.IsFull) ? "SPENT" : "empty")) + (val2.m_isHammerCocked ? "+cocked" : "")));
					text = text + " b" + i + "=" + text2;
				}
			}
			H3udPlugin.Log.LogInfo((object)("weapon shape: class=" + ((object)fa).GetType().Name + " chambers=" + ((fa.FChambers != null) ? fa.FChambers.Count : 0) + " barrels=" + num + " cylinder=" + ((Object)(object)CylinderOf(fa) != (Object)null) + text));
		}

		public static int DerringerBarrelPick(int curBarrel, int barrelCount, int loadedMask)
		{
			if (barrelCount <= 0)
			{
				return -1;
			}
			int num = Mathf.Clamp(curBarrel, 0, barrelCount - 1);
			for (int i = 0; i < barrelCount; i++)
			{
				int num2 = (num + i) % barrelCount;
				if ((loadedMask & (1 << num2)) != 0)
				{
					return num2;
				}
			}
			return -1;
		}

		public static int BreakActionBarrelIndex(int cockedMask, int loadedMask, int barrelCount)
		{
			if (barrelCount <= 0)
			{
				return -1;
			}
			_ = 32;
			for (int i = 0; i < barrelCount; i++)
			{
				if ((cockedMask & (1 << i)) != 0 && (loadedMask & (1 << i)) != 0)
				{
					return i;
				}
			}
			for (int j = 0; j < barrelCount; j++)
			{
				if ((loadedMask & (1 << j)) != 0)
				{
					return j;
				}
			}
			return -1;
		}

		private static bool LiveClass(FVRFireArmChamber ch, out FireArmRoundClass cls)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Expected I4, but got Unknown
			cls = (FireArmRoundClass)0;
			if ((Object)(object)ch == (Object)null || (Object)(object)ch.m_round == (Object)null || ch.IsSpent)
			{
				return false;
			}
			cls = (FireArmRoundClass)(int)ch.m_round.RoundClass;
			return true;
		}

		private static bool NextRoundClass(FVRFireArm fa, out FireArmRoundClass cls)
		{
			//IL_0258: Unknown result type (might be due to invalid IL or missing references)
			//IL_025e: Expected I4, but got Unknown
			//IL_02aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b0: Expected I4, but got Unknown
			cls = (FireArmRoundClass)0;
			if (fa.FChambers != null && fa.FChambers.Count > 0)
			{
				Derringer val = (Derringer)(object)((fa is Derringer) ? fa : null);
				if ((Object)(object)val != (Object)null && val.Barrels != null && val.Barrels.Count > 0)
				{
					int num = 0;
					for (int i = 0; i < val.Barrels.Count && i < 16; i++)
					{
						DBarrel val2 = val.Barrels[i];
						if (val2 != null && LiveClass(val2.Chamber, out var _))
						{
							num |= 1 << i;
						}
					}
					int num2 = DerringerBarrelPick(val.m_curBarrel, val.Barrels.Count, num);
					if (num2 >= 0 && LiveClass(val.Barrels[num2].Chamber, out cls))
					{
						LogNextPick(num2, cls);
						return true;
					}
				}
				BreakActionWeapon val3 = (BreakActionWeapon)(object)((fa is BreakActionWeapon) ? fa : null);
				if ((Object)(object)val3 != (Object)null && val3.Barrels != null && !val3.FireAllBarrels)
				{
					int num3 = 0;
					int num4 = 0;
					for (int j = 0; j < val3.Barrels.Length && j < 16; j++)
					{
						BreakActionBarrel val4 = val3.Barrels[j];
						if (val4 != null)
						{
							if (LiveClass(val4.Chamber, out var _))
							{
								num4 |= 1 << j;
							}
							if (val4.m_isHammerCocked)
							{
								num3 |= 1 << j;
							}
						}
					}
					int num5 = BreakActionBarrelIndex(num3, num4, val3.Barrels.Length);
					if (num5 >= 0 && LiveClass(val3.Barrels[num5].Chamber, out cls))
					{
						LogNextPick(num5, cls);
						return true;
					}
				}
				RevolverCylinder val5 = CylinderOf(fa);
				if ((Object)(object)val5 != (Object)null)
				{
					int closestChamberIndex = val5.GetClosestChamberIndex();
					if (closestChamberIndex >= 0 && closestChamberIndex < fa.FChambers.Count && LiveClass(fa.FChambers[closestChamberIndex], out cls))
					{
						return true;
					}
				}
				for (int k = 0; k < fa.FChambers.Count; k++)
				{
					if (LiveClass(fa.FChambers[k], out cls))
					{
						return true;
					}
				}
			}
			if ((Object)(object)fa.Magazine != (Object)null && fa.Magazine.LoadedRounds != null)
			{
				FVRLoadedRound[] loadedRounds = fa.Magazine.LoadedRounds;
				for (int num6 = loadedRounds.Length - 1; num6 >= 0; num6--)
				{
					if (loadedRounds[num6] != null)
					{
						cls = (FireArmRoundClass)(int)loadedRounds[num6].LR_Class;
						return true;
					}
				}
			}
			if ((Object)(object)fa.Clip != (Object)null && fa.Clip.LoadedRounds != null)
			{
				FVRLoadedRound[] loadedRounds2 = fa.Clip.LoadedRounds;
				for (int num7 = loadedRounds2.Length - 1; num7 >= 0; num7--)
				{
					if (loadedRounds2[num7] != null)
					{
						cls = (FireArmRoundClass)(int)loadedRounds2[num7].LR_Class;
						return true;
					}
				}
			}
			return false;
		}

		private static void CollectReserve(ref HudSnapshot s, FVRFireArm weapon, FireArmRoundType roundType, float scanRadius)
		{
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: 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_0302: Unknown result type (might be due to invalid IL or missing references)
			//IL_026f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0403: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_0225: Unknown result type (might be due to invalid IL or missing references)
			//IL_022c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0231: Unknown result type (might be due to invalid IL or missing references)
			//IL_0236: Unknown result type (might be due to invalid IL or missing references)
			if (!s.WeaponOk)
			{
				return;
			}
			_seen.Clear();
			s.ReserveRounds += s.WeaponChambers;
			if ((Object)(object)weapon != (Object)null)
			{
				SecondaryMagazineSlot[] secondaryMagazineSlots = weapon.SecondaryMagazineSlots;
				if (secondaryMagazineSlots != null)
				{
					for (int i = 0; i < secondaryMagazineSlots.Length; i++)
					{
						if (secondaryMagazineSlots[i] != null && !((Object)(object)secondaryMagazineSlots[i].Magazine == (Object)null))
						{
							CountItem((FVRPhysicalObject)(object)secondaryMagazineSlots[i].Magazine, ref s, roundType, allowMounted: true);
						}
					}
				}
			}
			FVRPlayerBody currentPlayerBody = GM.CurrentPlayerBody;
			if ((Object)(object)currentPlayerBody == (Object)null)
			{
				return;
			}
			List<FVRQuickBeltSlot> quickbeltSlots = currentPlayerBody.QuickbeltSlots;
			if (quickbeltSlots != null)
			{
				for (int j = 0; j < quickbeltSlots.Count; j++)
				{
					FVRQuickBeltSlot val = quickbeltSlots[j];
					if (!((Object)(object)val == (Object)null))
					{
						CountItem(val.CurObject, ref s, roundType);
						FVRInteractiveObject heldObject = val.HeldObject;
						CountItem((FVRPhysicalObject)(object)((heldObject is FVRPhysicalObject) ? heldObject : null), ref s, roundType);
					}
				}
			}
			if (_slotCache == null || Time.unscaledTime >= _slotNext)
			{
				_slotNext = Time.unscaledTime + 1f;
				_slotCache = ((Component)currentPlayerBody).GetComponentsInChildren<FVRQuickBeltSlot>(true);
			}
			FVRQuickBeltSlot[] slotCache = _slotCache;
			foreach (FVRQuickBeltSlot val2 in slotCache)
			{
				if (!((Object)(object)val2 == (Object)null))
				{
					CountItem(val2.CurObject, ref s, roundType);
					FVRInteractiveObject heldObject2 = val2.HeldObject;
					CountItem((FVRPhysicalObject)(object)((heldObject2 is FVRPhysicalObject) ? heldObject2 : null), ref s, roundType);
				}
			}
			Vector3 val4;
			if (s.IsFuel)
			{
				FVRPhysicalObject[] componentsInChildren = ((Component)currentPlayerBody).GetComponentsInChildren<FVRPhysicalObject>(true);
				for (int l = 0; l < componentsInChildren.Length; l++)
				{
					CountItem(componentsInChildren[l], ref s, roundType);
				}
				Transform head = currentPlayerBody.Head;
				float unscaledTime = Time.unscaledTime;
				if (FuelScanRadius <= 0.01f)
				{
					_fuelList.Clear();
				}
				else if (unscaledTime >= _fuelNext)
				{
					_fuelNext = unscaledTime + 1f;
					_fuelList.Clear();
					FVRFireArmMagazine[] array = Object.FindObjectsOfType<FVRFireArmMagazine>();
					foreach (FVRFireArmMagazine val3 in array)
					{
						if ((Object)(object)val3 == (Object)null || (Object)(object)val3.FireArm != (Object)null || !IsFuelMag(val3))
						{
							continue;
						}
						float num = FuelScanRadius * FuelScanRadius;
						if ((Object)(object)head != (Object)null)
						{
							val4 = ((Component)val3).transform.position - head.position;
							if (((Vector3)(ref val4)).sqrMagnitude > num)
							{
								continue;
							}
						}
						_fuelList.Add(val3);
					}
				}
				for (int n = 0; n < _fuelList.Count; n++)
				{
					CountItem((FVRPhysicalObject)(object)_fuelList[n], ref s, roundType);
				}
			}
			FVRViveHand val5 = Hand(right: true);
			if ((Object)(object)val5 != (Object)null && (Object)(object)val5.CurrentInteractable != (Object)null && !(val5.CurrentInteractable is FVRFireArm))
			{
				FVRInteractiveObject currentInteractable = val5.CurrentInteractable;
				CountItem((FVRPhysicalObject)(object)((currentInteractable is FVRPhysicalObject) ? currentInteractable : null), ref s, roundType);
			}
			FVRViveHand val6 = Hand(right: false);
			if ((Object)(object)val6 != (Object)null && (Object)(object)val6.CurrentInteractable != (Object)null && !(val6.CurrentInteractable is FVRFireArm))
			{
				FVRInteractiveObject currentInteractable2 = val6.CurrentInteractable;
				CountItem((FVRPhysicalObject)(object)((currentInteractable2 is FVRPhysicalObject) ? currentInteractable2 : null), ref s, roundType);
			}
			Transform head2 = currentPlayerBody.Head;
			if ((Object)(object)head2 == (Object)null || scanRadius <= 0.01f)
			{
				return;
			}
			float unscaledTime2 = Time.unscaledTime;
			if (_nearList == null || unscaledTime2 >= _nearNext || _nearWeapon != weapon || Mathf.Abs(_nearRadius - scanRadius) > 0.001f)
			{
				_nearWeapon = weapon;
				_nearRadius = scanRadius;
				_nearNext = unscaledTime2 + NearRefreshSeconds;
				float num2 = scanRadius * scanRadius;
				FVRPhysicalObject[] array2 = Object.FindObjectsOfType<FVRPhysicalObject>();
				_nearList.Clear();
				foreach (FVRPhysicalObject val7 in array2)
				{
					if ((Object)(object)val7 == (Object)null || (object)val7 == weapon)
					{
						continue;
					}
					if ((Object)(object)val7.QuickbeltSlot == (Object)null)
					{
						val4 = ((Component)val7).transform.position - head2.position;
						if (((Vector3)(ref val4)).sqrMagnitude >= num2)
						{
							continue;
						}
					}
					_nearList.Add(val7);
				}
			}
			for (int num4 = 0; num4 < _nearList.Count; num4++)
			{
				CountItem(_nearList[num4], ref s, roundType);
			}
		}

		private static void CountItem(FVRPhysicalObject obj, ref HudSnapshot s, FireArmRoundType roundType)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			CountItem(obj, ref s, roundType, allowMounted: false);
		}

		private static void CountItem(FVRPhysicalObject obj, ref HudSnapshot s, FireArmRoundType roundType, bool allowMounted)
		{
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: 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_0062: Invalid comparison between Unknown and I4
			//IL_01dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)obj == (Object)null || obj is FVRFireArm || !_seen.Add(((Object)obj).GetInstanceID()))
			{
				return;
			}
			FVRFireArmMagazine val = (FVRFireArmMagazine)(object)((obj is FVRFireArmMagazine) ? obj : null);
			if ((Object)(object)val != (Object)null)
			{
				if (!allowMounted && (Object)(object)val.FireArm != (Object)null)
				{
					return;
				}
				if (IsFuelMag(val))
				{
					if (((int)s.WeaponMagType == 0 || (int)val.MagazineType <= 0 || val.MagazineType == s.WeaponMagType) && !(val.FuelAmountLeft <= 0f))
					{
						s.ReserveFuelPercent += FuelPercentOf(val);
						s.ReserveMags++;
					}
				}
				else if (val.RoundType == roundType && val.m_numRounds > 0)
				{
					s.ReserveRounds += val.m_numRounds;
					s.ReserveMags++;
				}
				return;
			}
			FVRFireArmClip val2 = (FVRFireArmClip)(object)((obj is FVRFireArmClip) ? obj : null);
			if ((Object)(object)val2 != (Object)null)
			{
				if ((allowMounted || !((Object)(object)val2.FireArm != (Object)null)) && val2.RoundType == roundType)
				{
					s.ReserveRounds += val2.m_numRounds;
				}
				return;
			}
			Speedloader val3 = (Speedloader)(object)((obj is Speedloader) ? obj : null);
			if ((Object)(object)val3 != (Object)null)
			{
				if (val3.Chambers == null)
				{
					return;
				}
				for (int i = 0; i < val3.Chambers.Count; i++)
				{
					SpeedloaderChamber val4 = val3.Chambers[i];
					if (!((Object)(object)val4 == (Object)null) && val4.IsLoaded && val4.Type == roundType)
					{
						s.ReserveRounds++;
					}
				}
				return;
			}
			FVRFireArmBeltSegment val5 = (FVRFireArmBeltSegment)(object)((obj is FVRFireArmBeltSegment) ? obj : null);
			if ((Object)(object)val5 != (Object)null)
			{
				if (val5.RoundList == null)
				{
					return;
				}
				for (int j = 0; j < val5.RoundList.Count; j++)
				{
					if (val5.RoundList[j] != null)
					{
						s.ReserveRounds++;
					}
				}
			}
			else
			{
				FVRFireArmRound val6 = (FVRFireArmRound)(object)((obj is FVRFireArmRound) ? obj : null);
				if ((Object)(object)val6 != (Object)null && val6.RoundType == roundType && !val6.IsSpent)
				{
					s.ReserveRounds += StackSize(val6);
				}
			}
		}

		private static bool CollectHeldAmmo(ref HudSnapshot s, out float dist)
		{
			dist = float.MaxValue;
			FVRViveHand val = Hand(right: true);
			FVRViveHand val2 = Hand(right: false);
			HudSnapshot s2 = default(HudSnapshot);
			HudSnapshot s3 = default(HudSnapshot);
			float dist2 = float.MaxValue;
			float dist3 = float.MaxValue;
			bool flag = (Object)(object)val != (Object)null && TryHeldAmmo(val, ref s2, out dist2);
			bool flag2 = (Object)(object)val2 != (Object)null && TryHeldAmmo(val2, ref s3, out dist3);
			if (!flag && !flag2)
			{
				return false;
			}
			HudSnapshot src = ((!flag) ? s3 : ((!flag2) ? s2 : (PreferRight(dist2, dist3) ? s2 : s3)));
			dist = ((flag && flag2) ? Mathf.Min(dist2, dist3) : (flag ? dist2 : dist3));
			CopyHeld(ref s, src);
			return true;
		}

		public static int UrgencyFor(int kind)
		{
			return AmmoState.Urgency(kind switch
			{
				1 => HudDebug.SampleLowAmmo(), 
				2 => HudDebug.SampleEmptyAmmo(), 
				3 => HudDebug.SampleNoAmmo(), 
				4 => HudDebug.SampleSingleShot(loaded: true), 
				5 => HudDebug.SampleSingleShot(loaded: false), 
				_ => HudDebug.Sample(), 
			});
		}

		public static bool PreferRight(float distRight, float distLeft)
		{
			return distLeft >= distRight;
		}

		private static bool CollectHeldItem(ref HudSnapshot into, out float dist)
		{
			//IL_0183: Unknown result type (might be due to invalid IL or missing references)
			//IL_0188: Unknown result type (might be due to invalid IL or missing references)
			//IL_018a: Unknown result type (might be due to invalid IL or missing references)
			//IL_018d: Invalid comparison between Unknown and I4
			//IL_0136: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_018f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0193: Invalid comparison between Unknown and I4
			//IL_019f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0195: Unknown result type (might be due to invalid IL or missing references)
			//IL_0199: Invalid comparison between Unknown and I4
			float num = float.MaxValue;
			FVRPhysicalObject val = null;
			for (int i = 0; i < 2; i++)
			{
				FVRViveHand val2 = Hand(i == 0);
				if ((Object)(object)val2 == (Object)null)
				{
					continue;
				}
				FVRInteractiveObject currentInteractable = val2.CurrentInteractable;
				FVRPhysicalObject val3 = (FVRPhysicalObject)(object)((currentInteractable is FVRPhysicalObject) ? currentInteractable : null);
				if (!((Object)(object)val3 == (Object)null) && !(val3 is FVRFireArm) && !(val3 is FVRFireArmMagazine) && !(val3 is FVRFireArmClip) && !(val3 is FVRFireArmRound) && !(val3 is Speedloader) && !(val3 is FVRFireArmBeltSegment))
				{
					float num2 = HeadDistance(((Component)val3).transform);
					if (num2 < num)
					{
						num = num2;
						val = val3;
					}
				}
			}
			dist = num;
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			FVRObject objectWrapper = val.ObjectWrapper;
			into.HeldItemName = (((Object)(object)objectWrapper != (Object)null && !string.IsNullOrEmpty(objectWrapper.DisplayName)) ? objectWrapper.DisplayName : ((Object)val).name);
			into.HeldItemKind = (((Object)(object)objectWrapper != (Object)null) ? SplitWords(((object)Unsafe.As<ObjectCategory, ObjectCategory>(ref objectWrapper.Category)/*cast due to .constrained prefix*/).ToString()) : "ITEM");
			into.HeldItemFeature = string.Empty;
			into.HeldItemExtra = string.Empty;
			FVRFireArmAttachment val4 = (FVRFireArmAttachment)(object)((val is FVRFireArmAttachment) ? val : null);
			if ((Object)(object)val4 != (Object)null)
			{
				if ((Object)(object)objectWrapper != (Object)null && (int)objectWrapper.TagAttachmentFeature != 0)
				{
					into.HeldItemFeature = SplitWords(((object)Unsafe.As<OTagAttachmentFeature, OTagAttachmentFeature>(ref objectWrapper.TagAttachmentFeature)/*cast due to .constrained prefix*/).ToString());
				}
				into.HeldItemExtra = SplitWords(((object)Unsafe.As<FVRFireArmAttachementMountType, FVRFireArmAttachementMountType>(ref val4.Type)/*cast due to .constrained prefix*/).ToString());
				return true;
			}
			if ((Object)(object)objectWrapper == (Object)null)
			{
				return true;
			}
			ObjectCategory category = objectWrapper.Category;
			if ((int)category == 7)
			{
				goto IL_01c1;
			}
			if ((int)category != 10)
			{
				if ((int)category == 20)
				{
					goto IL_01c1;
				}
			}
			else
			{
				into.HeldItemFeature = Tag<OTagMeleeStyle>(objectWrapper.TagMeleeStyle);
				into.HeldItemExtra = Tag<OTagMeleeHandedness>(objectWrapper.TagMeleeHandedness);
			}
			goto IL_01e3;
			IL_01c1:
			into.HeldItemFeature = Tag<OTagThrownType>(objectWrapper.TagThrownType);
			into.HeldItemExtra = Tag<OTagThrownDamageType>(objectWrapper.TagThrownDamageType);
			goto IL_01e3;
			IL_01e3:
			return true;
		}

		private static string Tag<T>(T tag) where T : struct
		{
			string text = tag.ToString();
			if (!(text == "None"))
			{
				return SplitWords(text);
			}
			return string.Empty;
		}

		private static string SplitWords(string s)
		{
			if (string.IsNullOrEmpty(s))
			{
				return string.Empty;
			}
			StringBuilder stringBuilder = new StringBuilder(s.Length + 6);
			for (int i = 0; i < s.Length; i++)
			{
				char c = s[i];
				if (c == '_')
				{
					stringBuilder.Append(' ');
					continue;
				}
				if (i > 0 && char.IsUpper(c) && !char.IsUpper(s[i - 1]))
				{
					stringBuilder.Append(' ');
				}
				stringBuilder.Append(char.ToUpperInvariant(c));
			}
			return stringBuilder.ToString();
		}

		private static bool IsFuelMag(FVRFireArmMagazine mag)
		{
			if ((Object)(object)mag != (Object)null)
			{
				if (!(mag.m_startingFuel > 0f))
				{
					return mag.FuelAmountLeft > 0f;
				}
				return true;
			}
			return false;
		}

		private static int FuelPercentOf(FVRFireArmMagazine mag)
		{
			if ((Object)(object)mag == (Object)null)
			{
				return 0;
			}
			float num = ((mag.m_startingFuel > 0f) ? mag.m_startingFuel : Mathf.Max(mag.FuelAmountLeft, 1f));
			return Mathf.Clamp(Mathf.RoundToInt(mag.FuelAmountLeft / num * 100f), 0, 100);
		}

		private static void CopyHeld(ref HudSnapshot dst, HudSnapshot src)
		{
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			dst.HeldAmmoOk = src.HeldAmmoOk;
			dst.HeldAmmoName = src.HeldAmmoName;
			dst.HeldAmmoRound = src.HeldAmmoRound;
			dst.HeldAmmoRounds = src.HeldAmmoRounds;
			dst.HeldAmmoCapacity = src.HeldAmmoCapacity;
			dst.HeldKind = src.HeldKind;
			dst.HeldRoundType = src.HeldRoundType;
			dst.HeldMagType = src.HeldMagType;
			dst.HeldClipType = src.HeldClipType;
		}

		internal static void AdoptHeld(ref HudSnapshot s, HudSnapshot ammo)
		{
			CopyHeld(ref s, ammo);
			s.HeldAmmoOk = true;
			s.HeldFits = LoadCheck(s, ammo);
			s.AmmoWins = s.WeaponOk;
		}

		internal static int LoadCheck(HudSnapshot gun, HudSnapshot ammo)
		{
			//IL_001c: 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_0032: 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_0050: 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_0044: 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_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			if (!gun.WeaponOk)
			{
				return 0;
			}
			switch (ammo.HeldKind)
			{
			case 1:
				if ((int)ammo.HeldMagType != 0 || (int)gun.WeaponMagType != 0)
				{
					if (ammo.HeldMagType != gun.WeaponMagType)
					{
						return -1;
					}
					return 1;
				}
				if (ammo.HeldRoundType != gun.WeaponRoundType)
				{
					return -1;
				}
				return 1;
			case 2:
				if ((int)ammo.HeldClipType != 0 || (int)gun.WeaponClipType != 0)
				{
					if (ammo.HeldClipType != gun.WeaponClipType)
					{
						return -1;
					}
					return 1;
				}
				if (ammo.HeldRoundType != gun.WeaponRoundType)
				{
					return -1;
				}
				return 1;
			default:
				if (ammo.HeldRoundType != gun.WeaponRoundType)
				{
					return -1;
				}
				return 1;
			}
		}

		private static float HeadDistance(Transform t)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				FVRPlayerBody currentPlayerBody = GM.CurrentPlayerBody;
				if ((Object)(object)t != (Object)null && (Object)(object)currentPlayerBody != (Object)null && (Object)(object)currentPlayerBody.Head != (Object)null)
				{
					return Vector3.Distance(t.position, currentPlayerBody.Head.position);
				}
			}
			catch
			{
			}
			return float.MaxValue;
		}

		private static bool TryHeldAmmo(FVRViveHand hand, ref HudSnapshot s, out float dist)
		{
			//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_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0160: Unknown result type (might be due to invalid IL or missing references)
			//IL_0167: Unknown result type (might be due to invalid IL or missing references)
			//IL_016c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0195: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_023a: Unknown result type (might be due to invalid IL or missing references)
			//IL_023f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0264: Unknown result type (might be due to invalid IL or missing references)
			//IL_026a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_02af: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_0328: Unknown result type (might be due to invalid IL or missing references)
			//IL_032a: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f6: 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_02ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_036d: Unknown result type (might be due to invalid IL or missing references)
			//IL_036f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0364: Unknown result type (might be due to invalid IL or missing references)
			dist = float.MaxValue;
			if ((Object)(object)hand == (Object)null)
			{
				return false;
			}
			FVRInteractiveObject currentInteractable = hand.CurrentInteractable;
			FVRFireArmMagazine val = (FVRFireArmMagazine)(object)((currentInteractable is FVRFireArmMagazine) ? currentInteractable : null);
			if ((Object)(object)val != (Object)null)
			{
				s.HeldAmmoOk = true;
				s.HeldKind = 1;
				s.HeldMagType = val.MagazineType;
				s.HeldRoundType = val.RoundType;
				if (IsFuelMag(val))
				{
					s.HeldAmmoName = "FUEL CELL";
					s.HeldAmmoRounds = FuelPercentOf(val);
					s.HeldAmmoCapacity = 100;
					s.HeldAmmoRound = CaliberName(val.RoundType);
					dist = HeadDistance(((Component)val).transform);
					return true;
				}
				s.HeldAmmoName = "MAGAZINE";
				s.HeldAmmoRounds = val.m_numRounds;
				s.HeldAmmoCapacity = val.m_capacity;
				FireArmRoundClass cls = (FireArmRoundClass)0;
				if (val.LoadedRounds != null)
				{
					for (int num = val.LoadedRounds.Length - 1; num >= 0; num--)
					{
						if (val.LoadedRounds[num] != null)
						{
							cls = val.LoadedRounds[num].LR_Class;
							break;
						}
					}
				}
				s.HeldAmmoRound = ((val.m_numRounds > 0) ? RoundName(val.RoundType, cls) : CaliberName(val.RoundType));
				dist = HeadDistance(((Component)val).transform);
				return true;
			}
			FVRInteractiveObject currentInteractable2 = hand.CurrentInteractable;
			FVRFireArmClip val2 = (FVRFireArmClip)(object)((currentInteractable2 is FVRFireArmClip) ? currentInteractable2 : null);
			if ((Object)(object)val2 != (Object)null)
			{
				s.HeldAmmoOk = true;
				s.HeldKind = 2;
				s.HeldClipType = val2.ClipType;
				s.HeldRoundType = val2.RoundType;
				s.HeldAmmoName = "STRIP CLIP";
				s.HeldAmmoRounds = val2.m_numRounds;
				s.HeldAmmoCapacity = val2.m_capacity;
				FireArmRoundClass cls2 = (FireArmRoundClass)0;
				if (val2.LoadedRounds != null)
				{
					for (int num2 = val2.LoadedRounds.Length - 1; num2 >= 0; num2--)
					{
						if (val2.LoadedRounds[num2] != null)
						{
							cls2 = val2.LoadedRounds[num2].LR_Class;
							break;
						}
					}
				}
				s.HeldAmmoRound = ((val2.m_numRounds > 0) ? RoundName(val2.RoundType, cls2) : CaliberName(val2.RoundType));
				dist = HeadDistance(((Component)val2).transform);
				return true;
			}
			FVRInteractiveObject currentInteractable3 = hand.CurrentInteractable;
			FVRFireArmRound val3 = (FVRFireArmRound)(object)((currentInteractable3 is FVRFireArmRound) ? currentInteractable3 : null);
			if ((Object)(object)val3 != (Object)null && !val3.IsSpent)
			{
				s.HeldAmmoOk = true;
				s.HeldKind = 4;
				s.HeldRoundType = val3.RoundType;
				s.HeldAmmoName = "ROUNDS";
				s.HeldAmmoRounds = StackSize(val3);
				s.HeldAmmoCapacity = 0;
				s.HeldAmmoRound = RoundName(val3.RoundType, val3.RoundClass);
				dist = HeadDistance(((Component)val3).transform);
				return true;
			}
			FVRInteractiveObject currentInteractable4 = hand.CurrentInteractable;
			Speedloader val4 = (Speedloader)(object)((currentInteractable4 is Speedloader) ? currentInteractable4 : null);
			if ((Object)(object)val4 != (Object)null && val4.Chambers != null)
			{
				int num3 = 0;
				FireArmRoundType val5 = (FireArmRoundType)0;
				FireArmRoundClass cls3 = (FireArmRoundClass)0;
				bool flag = false;
				for (int i = 0; i < val4.Chambers.Count; i++)
				{
					SpeedloaderChamber val6 = val4.Chambers[i];
					if (!((Object)(object)val6 == (Object)null) && val6.IsLoaded)
					{
						num3++;
						if (!flag)
						{
							val5 = val6.Type;
							flag = true;
						}
						cls3 = val6.LoadedClass;
					}
				}
				s.HeldAmmoOk = true;
				s.HeldKind = 3;
				s.HeldRoundType = (FireArmRoundType)(flag ? ((int)val5) : 0);
				s.HeldAmmoName = "SPEEDLOADER";
				s.HeldAmmoRounds = num3;
				s.HeldAmmoCapacity = val4.Chambers.Count;
				s.HeldAmmoRound = ((!flag) ? string.Empty : ((num3 > 0) ? RoundName(val5, cls3) : CaliberName(val5)));
				dist = HeadDistance(((Component)val4).transform);
				return true;
			}
			return false;
		}

		private static void CollectHeading(ref HudSnapshot s)
		{
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			FVRPlayerBody currentPlayerBody = GM.CurrentPlayerBody;
			if ((Object)(object)currentPlayerBody != (Object)null && (Object)(object)currentPlayerBody.Head != (Object)null)
			{
				Vector3 forward = currentPlayerBody.Head.forward;
				s.Heading = HudMath.YawOf(forward);
				return;
			}
			Camera main = Camera.main;
			if ((Object)(object)main != (Object)null)
			{
				s.Heading = HudMath.YawOf(((Component)main).transform.forward);
			}
		}

		private static void CollectTnh(ref HudSnapshot s)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: 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_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0162: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			//IL_0178: Unknown result type (might be due to invalid IL or missing references)
			//IL_017d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0188: Unknown result type (might be due to invalid IL or missing references)
			//IL_018e: Unknown result type (might be due to invalid IL or missing references)
			//IL_019e: Unknown result type (might be due to invalid IL or missing references)
			//IL_019f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_023a: Unknown result type (might be due to invalid IL or missing references)
			//IL_023f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0241: Unknown result type (might be due to invalid IL or missing references)
			//IL_024d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0254: Unknown result type (might be due to invalid IL or missing references)
			//IL_0259: Unknown result type (might be due to invalid IL or missing references)
			//IL_0264: Unknown result type (might be due to invalid IL or missing references)
			//IL_026a: Unknown result type (might be due to invalid IL or missing references)
			//IL_028d: Unknown result type (might be due to invalid IL or missing references)
			//IL_028e: Unknown result type (might be due to invalid IL or missing references)
			TNH_Manager tNH_Manager = GM.TNH_Manager;
			if ((Object)(object)tNH_Manager == (Object)null)
			{
				return;
			}
			s.TnhOk = true;
			s.PhaseName = PhaseName(tNH_Manager.Phase);
			s.Level = tNH_Manager.m_level;
			s.MaxLevels = tNH_Manager.m_maxLevels;
			s.Tokens = tNH_Manager.m_numTokens;
			s.Mult = Multiplier();
			s.Score = ScoreFromNums(tNH_Manager.Nums, s.Mult);
			Transform val = (((Object)(object)GM.CurrentPlayerBody != (Object)null) ? GM.CurrentPlayerBody.Head : null);
			Vector3 val2 = (((Object)(object)val != (Object)null) ? val.position : Vector3.zero);
			float markerBand = H3udPlugin.S.MarkerBand;
			float markerOffset = H3udPlugin.S.MarkerOffset;
			float num = FloorUnderFeet(val2);
			bool haveHold = false;
			float num2 = 0f;
			float num3 = float.NaN;
			Vector3 holdPos = Vector3.zero;
			TNH_HoldPoint curHoldPoint = tNH_Manager.CurHoldPoint;
			s.HoldTotal = tNH_Manager.HoldPoints?.Count ?? 0;
			s.HoldNumber = tNH_Manager.m_curHoldIndex + 1;
			if ((Object)(object)curHoldPoint != (Object)null)
			{
				s.HoldOk = true;
				s.HoldStateName = HoldStateName(curHoldPoint.m_state);
				s.HoldTimer = curHoldPoint.m_tickDownToFailure;
				s.HoldPhaseNumber = curHoldPoint.m_phaseIndex;
				s.HoldPhaseTotal = curHoldPoint.m_maxPhases;
				Vector3 position = ((Component)curHoldPoint).transform.position;
				s.HoldDistance = Vector3.Distance(new Vector3(position.x, 0f, position.z), new Vector3(val2.x, 0f, val2.z));
				s.HoldBearing = HudMath.Bearing(val2, position);
				haveHold = true;
				num2 = HoldFloorY(curHoldPoint);
				holdPos = position;
				AddMarker(ref s, s.HoldBearing, s.HoldDistance, isHold: true, num2 - num + markerOffset, markerBand);
			}
			List<TNH_SupplyPoint> supplyPoints = tNH_Manager.SupplyPoints;
			List<int> activeSupplyPointIndicies = tNH_Manager.m_activeSupplyPointIndicies;
			if (supplyPoints != null && activeSupplyPointIndicies != null)
			{
				for (int i = 0; i < activeSupplyPointIndicies.Count; i++)
				{
					if (s.MarkerCount >= 8)
					{
						break;
					}
					int num4 = activeSupplyPointIndicies[i];
					if (num4 < 0 || num4 >= supplyPoints.Count)
					{
						continue;
					}
					TNH_SupplyPoint val3 = supplyPoints[num4];
					if (!((Object)(object)val3 == (Object)null))
					{
						Vector3 position2 = ((Component)val3).transform.position;
						float distance = Vector3.Distance(new Vector3(position2.x, 0f, position2.z), new Vector3(val2.x, 0f, val2.z));
						float num5 = SupplyFloorY(val3);
						if (float.IsNaN(num3))
						{
							num3 = num5;
						}
						AddMarker(ref s, HudMath.Bearing(val2, position2), distance, isHold: false, num5 - num + markerOffset, markerBand);
					}
				}
			}
			LogHeights(val2, num, haveHold, num2, holdPos, num3);
		}

		private unsafe static void LogFuelSweep(HudSnapshot s)
		{
			if (H3udPlugin.Log == null || !H3udPlugin.DebugHeights || Time.unscaledTime < _nextFuelLog)
			{
				return;
			}
			_nextFuelLog = Time.unscaledTime + 5f;
			string text = "";
			int num = 0;
			int num2 = 0;
			int num3 = 0;
			try
			{
				FVRPlayerBody currentPlayerBody = GM.CurrentPlayerBody;
				if ((Object)(object)currentPlayerBody != (Object)null)
				{
					if (currentPlayerBody.QuickbeltSlots != null)
					{
						num2 = currentPlayerBody.QuickbeltSlots.Count;
					}
					if (_slotCache == null)
					{
						_slotCache = ((Component)currentPlayerBody).GetComponentsInChildren<FVRQuickBeltSlot>(true);
					}
					FVRQuickBeltSlot[] slotCache = _slotCache;
					num3 = slotCache.Length;
					for (int i = 0; i < slotCache.Length && i < 12; i++)
					{
						FVRQuickBeltSlot val = slotCache[i];
						if (!((Object)(object)val == (Object)null))
						{
							FVRPhysicalObject curObject = val.CurObject;
							FVRFireArmMagazine val2 = (FVRFireArmMagazine)(object)((curObject is FVRFireArmMagazine) ? curObject : null);
							FVRInteractiveObject heldObject = val.HeldObject;
							FVRFireArmMagazine val3 = (FVRFireArmMagazine)(object)((heldObject is FVRFireArmMagazine) ? heldObject : null);
							FVRFireArmMagazine val4 = (((Object)(object)val2 != (Object)null) ? val2 : val3);
							string text2 = (((Object)(object)val.CurObject != (Object)null) ? ((object)val.CurObject).GetType().Name : (((Object)(object)val.HeldObject != (Object)null) ? ((object)val.HeldObject).GetType().Name : "empty"));
							if ((Object)(object)val4 == (Object)null)
							{
								text = text + " [" + i + ":" + text2 + "]";
								continue;
							}
							num++;
							text = text + " [" + i + ":" + ((object)val4).GetType().Name + " fuel=" + val4.FuelAmountLeft.ToString("0") + "/" + val4.m_startingFuel.ToString("0") + " type=" + ((object)Unsafe.As<FireArmMagazineType, FireArmMagazineType>(ref val4.MagazineType)/*cast due to .constrained prefix*/).ToString() + "]";
						}
					}
				}
			}
			catch
			{
			}
			H3udPlugin.Log.LogInfo((object)("fuel sweep: weaponMagType=" + ((object)(*(FireArmMagazineType*)(&s.WeaponMagType))/*cast due to .constrained prefix*/).ToString() + " listedSlots=" + num2 + " liveSlots=" + num3 + " withCell=" + num + " nearCells=" + _fuelList.Count + text + " => RES " + s.ReserveFuelPercent + "%  M" + s.ReserveMags));
		}

		private static void LogHeights(Vector3 eye, float feet, bool haveHold, float holdFloor, Vector3 holdPos, float supplyFloor)
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_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)
			if (H3udPlugin.Log == null || !H3udPlugin.DebugHeights || Time.unscaledTime < _nextHeightLog)
			{
				return;
			}
			_nextHeightLog = Time.unscaledTime + 30f;
			int num = 0;
			int num2 = 0;
			try
			{
				int num3 = Physics.RaycastNonAlloc(eye + Vector3.up * 0.05f, Vector3.down, _floorHits, 8f, -1, (QueryTriggerInteraction)1);
				num = num3;
				for (int i = 0; i < num3; i++)
				{
					if ((Object)(object)((RaycastHit)(ref _floorHits[i])).collider != (Object)null && SkipForFloor(((RaycastHit)(ref _floorHits[i])).collider))
					{
						num2++;
					}
				}
			}
			catch
			{
			}
			H3udPlugin.Log.LogInfo((object)("tnh heights: eye=" + eye.y.ToString("0.00") + " feet=" + feet.ToString("0.00") + " hits=" + num + "/" + num2 + " off=" + H3udPlugin.S.MarkerOffset.ToString("0.00") + " band=" + H3udPlugin.S.MarkerBand.ToString("0.00") + (haveHold ? (" holdFloor=" + holdFloor.ToString("0.00") + " dHold=" + (holdFloor - feet).ToString("0.00") + " holdPos=" + holdPos.y.ToString("0.00")) : " hold=-") + (float.IsNaN(supplyFloor) ? " supp=-" : (" suppFloor=" + supplyFloor.ToString("0.00") + " dSupp=" + (supplyFloor - feet).ToString("0.00")))));
		}

		private static float FloorUnderFeet(Vector3 eye)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: 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_0091: 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)
			try
			{
				int num = Physics.RaycastNonAlloc(eye + Vector3.up * 0.05f, Vector3.down, _floorHits, 8f, -1, (QueryTriggerInteraction)1);
				float num2 = float.MinValue;
				for (int i = 0; i < num; i++)
				{
					Collider collider = ((RaycastHit)(ref _floorHits[i])).collider;
					if (!((Object)(object)collider == (Object)null) && !SkipForFloor(collider))
					{
						float y = ((RaycastHit)(ref _floorHits[i])).point.y;
						if (y > num2)
						{
							num2 = y;
						}
					}
				}
				if (num2 > float.MinValue)
				{
					return num2;
				}
			}
			catch
			{
			}
			return eye.y - 1.55f;
		}

		private static bool SkipForFloor(Collider c)
		{
			try
			{
				FVRPlayerBody currentPlayerBody = GM.CurrentPlayerBody;
				if ((Object)(object)currentPlayerBody != (Object)null && ((Component)c).transform.IsChildOf(((Component)currentPlayerBody).transform))
				{
					return true;
				}
				if ((Object)(object)((Component)c).GetComponentInParent<FVRPhysicalObject>() != (Object)null)
				{
					return true;
				}
				if ((Object)(object)((Component)c).GetComponentInParent<FVRViveHand>() != (Object)null)
				{
					return true;
				}
			}
			catch
			{
			}
			return false;
		}

		priva