Decompiled source of AdvancedBIOCOM v1.0.0

AdvancedBIOCOM.dll

Decompiled 6 days ago
using System;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using Gear;
using HarmonyLib;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Player;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = "")]
[assembly: AssemblyCompany("AdvancedBIOCOM")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.1.0.0")]
[assembly: AssemblyInformationalVersion("0.1.0")]
[assembly: AssemblyProduct("AdvancedBIOCOM")]
[assembly: AssemblyTitle("AdvancedBIOCOM")]
[assembly: AssemblyVersion("0.1.0.0")]
namespace HoloAmmo;

[BepInPlugin("AdvancedBIOCOM", "Advanced BIOCOM", "1.0.0")]
public class Plugin : BasePlugin
{
	public const string GUID = "AdvancedBIOCOM";

	internal static ManualLogSource L;

	internal static ConfigEntry<bool> Enabled;

	internal static ConfigEntry<bool> ShowClip;

	internal static ConfigEntry<bool> ShowReserve;

	internal static ConfigEntry<bool> ShowBars;

	internal static ConfigEntry<bool> HideInMenus;

	internal static ConfigEntry<bool> FollowFov;

	internal static ConfigEntry<bool> HotReload;

	internal static ConfigEntry<bool> EmpEnabled;

	internal static ConfigEntry<bool> EmpIgnore;

	internal static Plugin Instance;

	internal static ConfigEntry<float> OffsetX;

	internal static ConfigEntry<float> OffsetY;

	internal static ConfigEntry<float> OffsetZ;

	internal static ConfigEntry<float> ScreenOffsetX;

	internal static ConfigEntry<float> ScreenOffsetY;

	internal static ConfigEntry<float> WidgetScale;

	internal static ConfigEntry<float> ClipFontSize;

	internal static ConfigEntry<float> ReserveFontSize;

	internal static ConfigEntry<int> BarCount;

	internal static ConfigEntry<float> BarWidth;

	internal static ConfigEntry<float> BarGap;

	internal static ConfigEntry<float> BarHeight;

	internal static ConfigEntry<float> ReserveOffsetY;

	internal static ConfigEntry<string> ClipColor;

	internal static ConfigEntry<string> ReserveColor;

	internal static ConfigEntry<string> LowColor;

	internal static ConfigEntry<int> LowPercent;

	internal static ConfigEntry<float> Opacity;

	internal static ConfigEntry<float> OutlineWidth;

	internal static ConfigEntry<float> ReferenceDistance;

	internal static ConfigEntry<float> ReferenceFov;

	internal static ConfigEntry<float> MinScale;

	internal static ConfigEntry<float> MaxScale;

	internal static ConfigEntry<float> AdsFovThreshold;

	internal static ConfigEntry<float> AdsViewportX;

	internal static ConfigEntry<float> AdsViewportY;

	internal static ConfigEntry<float> AdsOffsetX;

	internal static ConfigEntry<float> AdsOffsetY;

	internal static ConfigEntry<float> AdsScale;

	internal static ConfigEntry<float> SmoothSpeed;

	internal static ConfigEntry<bool> DebugLog;

	public override void Load()
	{
		//IL_0114: Unknown result type (might be due to invalid IL or missing references)
		//IL_011e: Expected O, but got Unknown
		//IL_0151: Unknown result type (might be due to invalid IL or missing references)
		//IL_015b: Expected O, but got Unknown
		//IL_037c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0386: Expected O, but got Unknown
		//IL_03b9: Unknown result type (might be due to invalid IL or missing references)
		//IL_03c3: Expected O, but got Unknown
		//IL_03f6: Unknown result type (might be due to invalid IL or missing references)
		//IL_0400: Expected O, but got Unknown
		//IL_050b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0515: Expected O, but got Unknown
		//IL_0548: Unknown result type (might be due to invalid IL or missing references)
		//IL_0552: Expected O, but got Unknown
		//IL_0628: Unknown result type (might be due to invalid IL or missing references)
		L = ((BasePlugin)this).Log;
		Instance = this;
		Enabled = ((BasePlugin)this).Config.Bind<bool>("1-General", "Enabled", true, "总开关。\nMaster switch.");
		HideInMenus = ((BasePlugin)this).Config.Bind<bool>("1-General", "HideInMenus", true, "打开地图/ESC 菜单/结束时隐藏。\nHide while the map, menu or end screen is open.");
		FollowFov = ((BasePlugin)this).Config.Bind<bool>("1-General", "FollowFov", true, "整体随距离和 FOV 缩放(开镜会放大)。\nScale with distance and FOV.");
		HotReload = ((BasePlugin)this).Config.Bind<bool>("1-General", "HotReload", true, "改完 cfg 存盘后立即生效,不用重启游戏(每秒检查一次)。\nReload the config live: saved edits apply within a second, no restart.");
		ShowClip = ((BasePlugin)this).Config.Bind<bool>("2-Content", "ShowClip", true, "显示弹匣数字。\nShow magazine count.");
		ShowReserve = ((BasePlugin)this).Config.Bind<bool>("2-Content", "ShowReserve", true, "显示备弹数字。\nShow reserve count.");
		ShowBars = ((BasePlugin)this).Config.Bind<bool>("2-Content", "ShowBars", true, "显示分段弹药条。\nShow segmented ammo bars.");
		BarCount = ((BasePlugin)this).Config.Bind<int>("2-Content", "BarCount", 4, new ConfigDescription("弹药条段数(0 = 不画)。\nNumber of ammo bars (0 = none).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 12), Array.Empty<object>()));
		WidgetScale = ((BasePlugin)this).Config.Bind<float>("3-Size", "WidgetScale", 1f, new ConfigDescription("整体大小倍率,微调时优先改这个。\nOverall size multiplier; the easiest knob for sizing.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.3f, 3f), Array.Empty<object>()));
		ClipFontSize = ((BasePlugin)this).Config.Bind<float>("3-Size", "ClipFontSize", 46f, "弹匣数字字号。\nClip font size.");
		ReserveFontSize = ((BasePlugin)this).Config.Bind<float>("3-Size", "ReserveFontSize", 26f, "备弹数字字号。\nReserve font size.");
		BarWidth = ((BasePlugin)this).Config.Bind<float>("3-Size", "BarWidth", 5f, "弹药条每段宽度。\nBar width.");
		BarGap = ((BasePlugin)this).Config.Bind<float>("3-Size", "BarGap", 6f, "弹药条段间距。\nGap between bars.");
		BarHeight = ((BasePlugin)this).Config.Bind<float>("3-Size", "BarHeight", 38f, "弹药条高度。\nBar height.");
		ReserveOffsetY = ((BasePlugin)this).Config.Bind<float>("3-Size", "ReserveOffsetY", -48f, "备弹相对弹匣数字的纵向偏移。\nReserve Y offset from the clip number.");
		OffsetX = ((BasePlugin)this).Config.Bind<float>("4-Position", "OffsetX", -0.02f, "武器局部 X 偏移(米)。往枪身方向调大。\nWeapon-local X offset (m).");
		OffsetY = ((BasePlugin)this).Config.Bind<float>("4-Position", "OffsetY", 0.02f, "武器局部 Y 偏移(米)。往上调大。\nWeapon-local Y offset (m).");
		OffsetZ = ((BasePlugin)this).Config.Bind<float>("4-Position", "OffsetZ", 0.15f, "武器局部 Z 偏移(米)。往远处调大。\nWeapon-local Z offset (m).");
		ScreenOffsetX = ((BasePlugin)this).Config.Bind<float>("4-Position", "ScreenOffsetX", 0f, "屏幕像素微调 X(腰射)。\nScreen-space X offset in pixels (hip fire).");
		ScreenOffsetY = ((BasePlugin)this).Config.Bind<float>("4-Position", "ScreenOffsetY", 0f, "屏幕像素微调 Y(腰射)。\nScreen-space Y offset in pixels (hip fire).");
		ClipColor = ((BasePlugin)this).Config.Bind<string>("5-Style", "ClipColor", "#FFFFFF", "弹匣数字颜色(#RRGGBB)。\nClip colour (#RRGGBB).");
		ReserveColor = ((BasePlugin)this).Config.Bind<string>("5-Style", "ReserveColor", "#D0D0D0", "备弹数字颜色。\nReserve colour.");
		LowColor = ((BasePlugin)this).Config.Bind<string>("5-Style", "LowColor", "#FF4A3D", "低弹时的颜色。\nLow-ammo colour.");
		LowPercent = ((BasePlugin)this).Config.Bind<int>("5-Style", "LowPercent", 25, new ConfigDescription("弹匣剩余百分比 ≤ 该值时变红。\nTurns red when the magazine is at or below this percentage.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>()));
		Opacity = ((BasePlugin)this).Config.Bind<float>("5-Style", "Opacity", 0.85f, new ConfigDescription("整体不透明度(1 = 完全不透明)。\nOverall opacity (1 = fully opaque).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 1f), Array.Empty<object>()));
		OutlineWidth = ((BasePlugin)this).Config.Bind<float>("5-Style", "OutlineWidth", 0.15f, new ConfigDescription("文字描边宽度(0 = 关闭)。\nText outline width (0 = off).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
		ReferenceDistance = ((BasePlugin)this).Config.Bind<float>("6-Scaling", "ReferenceDistance", 0.55f, "缩放参考距离(米)。\nReference distance (m).");
		ReferenceFov = ((BasePlugin)this).Config.Bind<float>("6-Scaling", "ReferenceFov", 60f, "缩放参考 FOV。\nReference FOV.");
		MinScale = ((BasePlugin)this).Config.Bind<float>("6-Scaling", "MinScale", 0.35f, "最小缩放。\nMinimum scale.");
		MaxScale = ((BasePlugin)this).Config.Bind<float>("6-Scaling", "MaxScale", 2.2f, "最大缩放。\nMaximum scale.");
		SmoothSpeed = ((BasePlugin)this).Config.Bind<float>("6-Scaling", "SmoothSpeed", 14f, "位置/缩放平滑速度,越大越跟手(8 更飘,20 几乎无延迟)。\nSmoothing speed; higher follows faster.");
		AdsFovThreshold = ((BasePlugin)this).Config.Bind<float>("7-ADS", "AdsFovThreshold", 55f, "FOV 低于该值判定为开镜。\nFOV below which aiming down sights is detected.");
		AdsViewportX = ((BasePlugin)this).Config.Bind<float>("7-ADS", "ViewportX", 0.3f, new ConfigDescription("开镜时 UI 的横向位置(屏宽百分比,0=最左)。\nADS anchor as a fraction of screen width.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
		AdsViewportY = ((BasePlugin)this).Config.Bind<float>("7-ADS", "ViewportY", 0.17f, new ConfigDescription("开镜时 UI 的纵向位置(屏高百分比,0=最下)。\nADS anchor as a fraction of screen height.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
		AdsOffsetX = ((BasePlugin)this).Config.Bind<float>("7-ADS", "AdsOffsetX", 0f, "开镜位置额外的像素偏移 X。\nExtra ADS pixel offset X.");
		AdsOffsetY = ((BasePlugin)this).Config.Bind<float>("7-ADS", "AdsOffsetY", 0f, "开镜位置额外的像素偏移 Y。\nExtra ADS pixel offset Y.");
		AdsScale = ((BasePlugin)this).Config.Bind<float>("7-ADS", "AdsScale", 0.85f, "开镜时的额外缩放倍率。\nExtra scale multiplier while aiming.");
		EmpEnabled = ((BasePlugin)this).Config.Bind<bool>("8-EMP", "Enabled", true, "检测 EMP MOD 的压制状态。\nDetect the EMP mod's suppression state.");
		EmpIgnore = ((BasePlugin)this).Config.Bind<bool>("8-EMP", "IgnoreEMP", false, "true = EMP 期间仍然显示本 UI;false = 跟随游戏一起被禁用(默认)。\ntrue = keep this UI visible during EMP; false = hide it like the rest of the HUD (default).");
		DebugLog = ((BasePlugin)this).Config.Bind<bool>("9-Debug", "LogEveryTwoSeconds", false, "每两秒把状态打到日志(排查用,平时关掉)。\nLog state every two seconds (debugging only).");
		try
		{
			new Harmony("AdvancedBIOCOM").PatchAll(typeof(HudVisibilityPatch));
			L.LogInfo((object)"[BIOCOM] Harmony patch applied (PlayerGuiLayer.SetVisible).");
		}
		catch (Exception ex)
		{
			L.LogWarning((object)("[BIOCOM] Harmony patch failed: " + ex.Message));
		}
		L.LogInfo((object)"[BIOCOM] v1.0.0 loaded.");
		((BasePlugin)this).AddComponent<HoloAmmoBehaviour>();
	}
}
public class HoloAmmoBehaviour : MonoBehaviour
{
	private RectTransform _canvasRect;

	private RectTransform _root;

	private TextMeshProUGUI _clip;

	private TextMeshProUGUI _reserve;

	private Image[] _bars;

	private Sprite _barSprite;

	private Vector2 _smoothPos;

	private float _smoothScale = 1f;

	private Vector2 _targetPos;

	private float _targetScale = 1f;

	private bool _wasVisible;

	private float _logTimer;

	private bool _warned;

	private string _lastGate = "";

	internal static bool HudVisible = true;

	private string _cfgPath;

	private DateTime _cfgStamp;

	private float _cfgTimer;

	private int _lastClip = int.MinValue;

	private int _lastClipMax = int.MinValue;

	private int _lastReserve = int.MinValue;

	private bool _lastLow;

	private bool _lastReloading;

	private bool _colorsReady;

	private Color _cClip = Color.white;

	private Color _cReserve = Color.gray;

	private Color _cLow = Color.red;

	private float _empPoll;

	private bool _empCached;

	private IntPtr _cachedItemPtr;

	private BulletWeapon _cachedBullet;

	private bool _hasCachedItem;

	private float _reservePoll;

	private int _cachedReserve = -1;

	private static bool _empResolved;

	private static object _empHudInstance;

	private static MethodInfo _empIsEmped;

	private static bool _empLast;

	private static float _empRetryAt;

	private static float _empClock;

	private static Color Parse(string hex, Color fallback)
	{
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0012: Unknown result type (might be due to invalid IL or missing references)
		//IL_0013: Unknown result type (might be due to invalid IL or missing references)
		//IL_001d: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			Color result = default(Color);
			if (!string.IsNullOrEmpty(hex) && ColorUtility.TryParseHtmlString(hex, ref result))
			{
				return result;
			}
		}
		catch
		{
		}
		return fallback;
	}

	private void LateUpdate()
	{
		//IL_028e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0294: Unknown result type (might be due to invalid IL or missing references)
		//IL_029b: Unknown result type (might be due to invalid IL or missing references)
		//IL_02a0: Unknown result type (might be due to invalid IL or missing references)
		//IL_024c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0251: Unknown result type (might be due to invalid IL or missing references)
		//IL_02cb: Unknown result type (might be due to invalid IL or missing references)
		//IL_02d1: Unknown result type (might be due to invalid IL or missing references)
		//IL_02d6: Unknown result type (might be due to invalid IL or missing references)
		//IL_02db: 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_02f2: Unknown result type (might be due to invalid IL or missing references)
		//IL_0336: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			if (!Plugin.Enabled.Value)
			{
				Hide();
				return;
			}
			CheckConfigReload();
			if (!EnsureUi())
			{
				return;
			}
			PlayerAgent localPlayerAgent = PlayerManager.GetLocalPlayerAgent();
			if ((Object)(object)localPlayerAgent == (Object)null)
			{
				Hide();
				return;
			}
			FirstPersonItemHolder fPItemHolder = localPlayerAgent.FPItemHolder;
			ItemEquippable val = ((fPItemHolder != null) ? fPItemHolder.WieldedItem : null);
			if ((Object)(object)val == (Object)null)
			{
				Hide();
				return;
			}
			IntPtr pointer = ((Il2CppObjectBase)val).Pointer;
			if (!_hasCachedItem || pointer != _cachedItemPtr)
			{
				_cachedItemPtr = pointer;
				_cachedBullet = ((Il2CppObjectBase)val).TryCast<BulletWeapon>();
				_hasCachedItem = true;
			}
			BulletWeapon cachedBullet = _cachedBullet;
			if ((Object)(object)cachedBullet == (Object)null)
			{
				Hide();
				return;
			}
			if (Plugin.DebugLog.Value)
			{
				_logTimer += Time.deltaTime;
				if (_logTimer >= 2f)
				{
					_logTimer = 0f;
					Plugin.L.LogInfo((object)string.Format("[BIOCOM] state: hudVisible={0} focus={1} gate={2}", HudVisible, Application.isFocused, Gate() ?? "-"));
				}
			}
			if (Plugin.HideInMenus.Value)
			{
				string text = Gate();
				if (text != null)
				{
					if (_lastGate != text)
					{
						_lastGate = text;
						Plugin.L.LogInfo((object)("[BIOCOM] hidden by: " + text));
					}
					Hide();
					return;
				}
				_lastGate = "";
			}
			int currentClip = ((ItemEquippable)cachedBullet).GetCurrentClip();
			int maxClip = ((ItemEquippable)cachedBullet).GetMaxClip();
			_reservePoll += Time.deltaTime;
			if (_reservePoll >= 0.1f)
			{
				_reservePoll = 0f;
				_cachedReserve = Reserve(val);
			}
			int cachedReserve = _cachedReserve;
			bool low = maxClip > 0 && (float)currentClip * 100f / (float)maxClip <= (float)Plugin.LowPercent.Value;
			bool isReloading = val.IsReloading;
			UpdateVisuals(currentClip, maxClip, cachedReserve, low, isReloading);
			if (!Position(val, out var cam))
			{
				Hide();
				return;
			}
			((Component)_root).gameObject.SetActive(true);
			ApplyScale(cam, val);
			if (!_wasVisible)
			{
				_smoothPos = _targetPos;
				_smoothScale = _targetScale;
			}
			else
			{
				float num = 1f - Mathf.Exp((0f - Mathf.Max(0.01f, Plugin.SmoothSpeed.Value)) * Time.deltaTime);
				_smoothPos = Vector2.Lerp(_smoothPos, _targetPos, num);
				_smoothScale = Mathf.Lerp(_smoothScale, _targetScale, num);
			}
			_wasVisible = true;
			Vector2 val2 = _root.anchoredPosition - _smoothPos;
			if (((Vector2)(ref val2)).sqrMagnitude > 0.04f)
			{
				_root.anchoredPosition = _smoothPos;
			}
			if (Math.Abs(((Transform)_root).localScale.x - _smoothScale) > 0.002f)
			{
				((Transform)_root).localScale = new Vector3(_smoothScale, _smoothScale, 1f);
			}
			ProbeTick(cam, val, currentClip, maxClip, cachedReserve);
		}
		catch (Exception ex)
		{
			if (!_warned)
			{
				_warned = true;
				Plugin.L.LogWarning((object)("[BIOCOM] tick failed: " + ex.GetType().Name + " " + ex.Message));
			}
			Hide();
		}
	}

	private string Gate()
	{
		if (Plugin.EmpEnabled.Value && !Plugin.EmpIgnore.Value)
		{
			_empPoll += Time.deltaTime;
			if (_empPoll >= 0.2f)
			{
				_empPoll = 0f;
				_empCached = EmpActive();
			}
			if (_empCached)
			{
				return "emp";
			}
		}
		if (!HudVisible)
		{
			return "hud-hidden";
		}
		if (!Application.isFocused)
		{
			return "unfocused";
		}
		return null;
	}

	private static bool EmpActive()
	{
		_empClock += Time.deltaTime;
		if (!_empResolved || (_empHudInstance == null && _empClock >= _empRetryAt))
		{
			_empResolved = true;
			_empRetryAt = _empClock + 10f;
			try
			{
				Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
				foreach (Assembly assembly in assemblies)
				{
					if (assembly.GetName().Name != "Inas07.EOSExt.EMP")
					{
						continue;
					}
					Type type = assembly.GetType("EOSExt.EMP.Impl.Handlers.EMPPlayerHudHandler");
					if (!(type == null))
					{
						PropertyInfo property = type.GetProperty("Instance", BindingFlags.Static | BindingFlags.Public);
						if (!(property == null))
						{
							_empHudInstance = property.GetValue(null);
							_empIsEmped = type.GetMethod("IsEMPed", BindingFlags.Instance | BindingFlags.Public);
							Plugin.L.LogInfo((object)("[BIOCOM] EMP bridge: instance=" + (_empHudInstance != null) + " method=" + (_empIsEmped != null)));
						}
					}
					break;
				}
			}
			catch (Exception ex)
			{
				Plugin.L.LogWarning((object)("[BIOCOM] EMP bridge failed: " + ex.Message));
			}
		}
		if (_empHudInstance == null || _empIsEmped == null)
		{
			return false;
		}
		try
		{
			bool flag = (bool)_empIsEmped.Invoke(_empHudInstance, null);
			if (flag != _empLast)
			{
				_empLast = flag;
				Plugin.L.LogInfo((object)("[BIOCOM] EMP state -> " + (flag ? "suppressed" : "normal")));
			}
			return flag;
		}
		catch
		{
			return false;
		}
	}

	private void CheckConfigReload()
	{
		if (!Plugin.HotReload.Value || Plugin.Instance == null)
		{
			return;
		}
		_cfgTimer += Time.deltaTime;
		if (_cfgTimer < 1f)
		{
			return;
		}
		_cfgTimer = 0f;
		try
		{
			if (_cfgPath == null)
			{
				_cfgPath = ((BasePlugin)Plugin.Instance).Config.ConfigFilePath;
			}
			if (string.IsNullOrEmpty(_cfgPath) || !File.Exists(_cfgPath))
			{
				return;
			}
			DateTime lastWriteTimeUtc = File.GetLastWriteTimeUtc(_cfgPath);
			if (!(lastWriteTimeUtc == _cfgStamp))
			{
				bool num = _cfgStamp == default(DateTime);
				_cfgStamp = lastWriteTimeUtc;
				if (!num)
				{
					((BasePlugin)Plugin.Instance).Config.Reload();
					RebuildUi();
					Plugin.L.LogInfo((object)"[BIOCOM] config reloaded from disk.");
				}
			}
		}
		catch (Exception ex)
		{
			Plugin.L.LogWarning((object)("[BIOCOM] config reload failed: " + ex.Message));
		}
	}

	private void RebuildUi()
	{
		try
		{
			if ((Object)(object)_root != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)_root).gameObject);
			}
		}
		catch
		{
		}
		_root = null;
		_clip = null;
		_reserve = null;
		_bars = null;
		_wasVisible = false;
		_colorsReady = false;
		_lastClip = int.MinValue;
	}

	private void ProbeTick(Camera cam, ItemEquippable item, int clip, int clipMax, int reserve)
	{
		if (Plugin.DebugLog.Value)
		{
			_logTimer += Time.deltaTime;
			if (!(_logTimer < 2f))
			{
				_logTimer = 0f;
				Plugin.L.LogInfo((object)$"[BIOCOM] clip={clip}/{clipMax} reserve={reserve} fov={cam.fieldOfView:0.0} ads={AdsBlend(cam):0.00} scale={_smoothScale:0.00} pos=({_smoothPos.x:0},{_smoothPos.y:0}) hudVisible={HudVisible} focus={Application.isFocused}");
			}
		}
	}

	private void UpdateVisuals(int clip, int clipMax, int reserve, bool low, bool reloading)
	{
		//IL_0013: Unknown result type (might be due to invalid IL or missing references)
		//IL_0018: Unknown result type (might be due to invalid IL or missing references)
		//IL_001d: Unknown result type (might be due to invalid IL or missing references)
		//IL_002d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0032: Unknown result type (might be due to invalid IL or missing references)
		//IL_0037: Unknown result type (might be due to invalid IL or missing references)
		//IL_0047: Unknown result type (might be due to invalid IL or missing references)
		//IL_004c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0051: Unknown result type (might be due to invalid IL or missing references)
		//IL_009b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0093: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
		//IL_0133: Unknown result type (might be due to invalid IL or missing references)
		//IL_019a: Unknown result type (might be due to invalid IL or missing references)
		//IL_028f: 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_0275: Unknown result type (might be due to invalid IL or missing references)
		//IL_027b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0288: Unknown result type (might be due to invalid IL or missing references)
		//IL_0290: Unknown result type (might be due to invalid IL or missing references)
		//IL_02a1: Unknown result type (might be due to invalid IL or missing references)
		if (!_colorsReady)
		{
			_cClip = Parse(Plugin.ClipColor.Value, Color.white);
			_cReserve = Parse(Plugin.ReserveColor.Value, Color.gray);
			_cLow = Parse(Plugin.LowColor.Value, Color.red);
			_colorsReady = true;
			_lastClip = int.MinValue;
			_lastReserve = int.MinValue;
			_lastLow = !low;
		}
		float num = Mathf.Clamp01(Plugin.Opacity.Value);
		Color val = (low ? _cLow : _cClip);
		Color cReserve = _cReserve;
		val.a *= num;
		cReserve.a *= num;
		bool flag = clip != _lastClip || clipMax != _lastClipMax;
		bool num2 = reserve != _lastReserve;
		bool flag2 = low != _lastLow;
		if (flag)
		{
			((TMP_Text)_clip).text = (Plugin.ShowClip.Value ? clip.ToString(CultureInfo.InvariantCulture) : "");
			LayoutBars();
		}
		if (flag || flag2)
		{
			((Graphic)_clip).color = val;
			((Component)_clip).gameObject.SetActive(Plugin.ShowClip.Value);
		}
		bool flag3 = Plugin.ShowReserve.Value && reserve >= 0;
		if (num2 || flag2 || flag)
		{
			((TMP_Text)_reserve).text = (flag3 ? reserve.ToString(CultureInfo.InvariantCulture) : "");
			((Graphic)_reserve).color = cReserve;
			((Component)_reserve).gameObject.SetActive(flag3);
		}
		_lastClip = clip;
		_lastClipMax = clipMax;
		_lastReserve = reserve;
		_lastLow = low;
		if (_bars == null || (!(flag || flag2 || reloading) && !_lastReloading))
		{
			return;
		}
		int num3 = Mathf.CeilToInt(((clipMax > 0) ? Mathf.Clamp01((float)clip / (float)clipMax) : 0f) * (float)_bars.Length);
		float num4 = (reloading ? (0.35f + 0.65f * Mathf.PingPong(Time.time * 2.5f, 1f)) : 1f);
		bool value = Plugin.ShowBars.Value;
		for (int i = 0; i < _bars.Length; i++)
		{
			Image val2 = _bars[i];
			if (!((Object)(object)val2 == (Object)null))
			{
				Color color = (Color)((i < num3) ? val : new Color(val.r, val.g, val.b, 0.18f * num));
				color.a *= num4;
				((Graphic)val2).color = color;
				((Component)val2).gameObject.SetActive(value);
			}
		}
		_lastReloading = reloading;
	}

	private void LayoutBars()
	{
		//IL_0062: Unknown result type (might be due to invalid IL or missing references)
		if (_bars == null || _bars.Length == 0)
		{
			return;
		}
		float value = Plugin.BarWidth.Value;
		float value2 = Plugin.BarGap.Value;
		float num = ((TMP_Text)_clip).preferredWidth + value2;
		for (int i = 0; i < _bars.Length; i++)
		{
			Image val = _bars[i];
			if (!((Object)(object)val == (Object)null))
			{
				((Graphic)val).rectTransform.anchoredPosition = new Vector2(num + (float)i * (value + value2), 0f);
			}
		}
	}

	private static float AdsBlend(Camera cam)
	{
		if ((Object)(object)cam == (Object)null)
		{
			return 0f;
		}
		if (!(cam.fieldOfView < Plugin.AdsFovThreshold.Value))
		{
			return 0f;
		}
		return 1f;
	}

	private static int Reserve(ItemEquippable item)
	{
		//IL_001d: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			PlayerBackpack localBackpack = PlayerBackpackManager.LocalBackpack;
			if (localBackpack == null)
			{
				return -1;
			}
			PlayerAmmoStorage ammoStorage = localBackpack.AmmoStorage;
			if (ammoStorage == null)
			{
				return -1;
			}
			return ammoStorage.GetBulletsInPack(item.AmmoType);
		}
		catch
		{
			return -1;
		}
	}

	private bool EnsureUi()
	{
		//IL_008e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0094: Expected O, but got Unknown
		//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
		//IL_0110: Unknown result type (might be due to invalid IL or missing references)
		//IL_0176: Unknown result type (might be due to invalid IL or missing references)
		//IL_0182: Unknown result type (might be due to invalid IL or missing references)
		//IL_0188: Expected O, but got Unknown
		//IL_018b: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b1: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
		//IL_0031: Unknown result type (might be due to invalid IL or missing references)
		//IL_0037: Expected O, but got Unknown
		//IL_0069: Unknown result type (might be due to invalid IL or missing references)
		//IL_0207: Unknown result type (might be due to invalid IL or missing references)
		//IL_020c: Unknown result type (might be due to invalid IL or missing references)
		//IL_022a: 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_0254: Unknown result type (might be due to invalid IL or missing references)
		//IL_0273: Unknown result type (might be due to invalid IL or missing references)
		//IL_029b: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)_clip != (Object)null && (Object)(object)_root != (Object)null)
		{
			return true;
		}
		if ((Object)(object)_canvasRect == (Object)null)
		{
			GameObject val = new GameObject("HoloAmmoCanvas");
			Object.DontDestroyOnLoad((Object)(object)val);
			Canvas obj = val.AddComponent<Canvas>();
			obj.renderMode = (RenderMode)0;
			obj.sortingOrder = 100;
			CanvasScaler obj2 = val.AddComponent<CanvasScaler>();
			obj2.uiScaleMode = (ScaleMode)1;
			obj2.referenceResolution = new Vector2(1920f, 1080f);
			obj2.matchWidthOrHeight = 0.5f;
			_canvasRect = val.GetComponent<RectTransform>();
		}
		GameObject val2 = new GameObject("HoloAmmoRoot");
		_root = val2.AddComponent<RectTransform>();
		((Transform)_root).SetParent((Transform)(object)_canvasRect, false);
		_root.anchorMin = new Vector2(0.5f, 0.5f);
		_root.anchorMax = new Vector2(0.5f, 0.5f);
		_root.pivot = new Vector2(0f, 0.5f);
		_root.sizeDelta = new Vector2(240f, 160f);
		_clip = MakeText("Clip", _root, Plugin.ClipFontSize.Value);
		_reserve = MakeText("Reserve", _root, Plugin.ReserveFontSize.Value);
		((TMP_Text)_reserve).rectTransform.anchoredPosition = new Vector2(2f, Plugin.ReserveOffsetY.Value);
		Texture2D val3 = new Texture2D(1, 1);
		val3.SetPixel(0, 0, Color.white);
		val3.Apply();
		_barSprite = Sprite.Create(val3, new Rect(0f, 0f, 1f, 1f), new Vector2(0.5f, 0.5f));
		int num = Mathf.Clamp(Plugin.BarCount.Value, 0, 12);
		_bars = (Image[])(object)new Image[num];
		for (int i = 0; i < num; i++)
		{
			GameObject val4 = new GameObject("Bar" + i);
			RectTransform obj3 = val4.AddComponent<RectTransform>();
			((Transform)obj3).SetParent((Transform)(object)_root, false);
			obj3.anchorMin = new Vector2(0f, 0.5f);
			obj3.anchorMax = new Vector2(0f, 0.5f);
			obj3.pivot = new Vector2(0f, 0.5f);
			obj3.sizeDelta = new Vector2(Plugin.BarWidth.Value, Plugin.BarHeight.Value);
			obj3.anchoredPosition = new Vector2((float)i * (Plugin.BarWidth.Value + Plugin.BarGap.Value), 0f);
			Image val5 = val4.AddComponent<Image>();
			val5.sprite = _barSprite;
			((Graphic)val5).raycastTarget = false;
			_bars[i] = val5;
		}
		Plugin.L.LogInfo((object)("[BIOCOM] UI built (bars=" + num + ")."));
		return true;
	}

	private TextMeshProUGUI MakeText(string name, RectTransform parent, float size)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_001f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0034: Unknown result type (might be due to invalid IL or missing references)
		//IL_0049: Unknown result type (might be due to invalid IL or missing references)
		//IL_005d: Unknown result type (might be due to invalid IL or missing references)
		//IL_009d: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
		GameObject val = new GameObject(name);
		RectTransform obj = val.AddComponent<RectTransform>();
		((Transform)obj).SetParent((Transform)(object)parent, false);
		obj.anchorMin = new Vector2(0f, 0.5f);
		obj.anchorMax = new Vector2(0f, 0.5f);
		obj.pivot = new Vector2(0f, 0.5f);
		obj.sizeDelta = new Vector2(200f, 80f);
		TextMeshProUGUI val2 = val.AddComponent<TextMeshProUGUI>();
		((TMP_Text)val2).font = TMP_Settings.defaultFontAsset;
		if ((Object)(object)((TMP_Text)val2).font == (Object)null)
		{
			Plugin.L.LogWarning((object)"[BIOCOM] TMP default font asset is null.");
		}
		((TMP_Text)val2).fontSize = size;
		((Graphic)val2).color = Color.white;
		((TMP_Text)val2).alignment = (TextAlignmentOptions)513;
		((TMP_Text)val2).enableWordWrapping = false;
		((Graphic)val2).raycastTarget = false;
		((TMP_Text)val2).text = "0";
		float value = Plugin.OutlineWidth.Value;
		if (value > 0f)
		{
			try
			{
				((TMP_Text)val2).outlineWidth = value;
				((TMP_Text)val2).outlineColor = new Color32((byte)0, (byte)0, (byte)0, (byte)170);
			}
			catch
			{
			}
		}
		return val2;
	}

	private void Hide()
	{
		_wasVisible = false;
		if ((Object)(object)_root != (Object)null && ((Component)_root).gameObject.activeSelf)
		{
			((Component)_root).gameObject.SetActive(false);
		}
	}

	private static float Distance(Camera cam, ItemEquippable item)
	{
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_0011: Unknown result type (might be due to invalid IL or missing references)
		return Vector3.Distance(((Component)cam).transform.position, ((Component)item).transform.position);
	}

	private void ApplyScale(Camera cam, ItemEquippable item)
	{
		float num = 1f;
		if (Plugin.FollowFov.Value)
		{
			float num2 = Mathf.Max(0.05f, Distance(cam, item));
			float num3 = Mathf.Max(1f, cam.fieldOfView);
			float num4 = Mathf.Tan(Plugin.ReferenceFov.Value * 0.5f * ((float)Math.PI / 180f));
			float num5 = Mathf.Tan(num3 * 0.5f * ((float)Math.PI / 180f));
			num = Plugin.ReferenceDistance.Value / num2 * (num4 / num5);
		}
		float num6 = AdsBlend(cam);
		if (num6 > 0f)
		{
			num *= Mathf.Lerp(1f, Plugin.AdsScale.Value, num6);
		}
		num *= Plugin.WidgetScale.Value;
		_targetScale = Mathf.Clamp(num, Plugin.MinScale.Value, Plugin.MaxScale.Value);
	}

	private bool Position(ItemEquippable item, out Camera cam)
	{
		//IL_0060: Unknown result type (might be due to invalid IL or missing references)
		//IL_0065: Unknown result type (might be due to invalid IL or missing references)
		//IL_006a: Unknown result type (might be due to invalid IL or missing references)
		//IL_006d: Unknown result type (might be due to invalid IL or missing references)
		//IL_006e: 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_0074: Unknown result type (might be due to invalid IL or missing references)
		//IL_0085: Unknown result type (might be due to invalid IL or missing references)
		//IL_0096: Unknown result type (might be due to invalid IL or missing references)
		//IL_010b: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
		//IL_0104: Unknown result type (might be due to invalid IL or missing references)
		//IL_0119: Unknown result type (might be due to invalid IL or missing references)
		//IL_011b: Unknown result type (might be due to invalid IL or missing references)
		cam = Camera.main;
		if ((Object)(object)cam == (Object)null)
		{
			Il2CppReferenceArray<Camera> allCameras = Camera.allCameras;
			if (allCameras != null && ((Il2CppArrayBase<Camera>)(object)allCameras).Length > 0)
			{
				cam = ((Il2CppArrayBase<Camera>)(object)allCameras)[0];
			}
		}
		if ((Object)(object)cam == (Object)null)
		{
			return false;
		}
		Vector3 val = ((Component)item).transform.TransformPoint(new Vector3(Plugin.OffsetX.Value, Plugin.OffsetY.Value, Plugin.OffsetZ.Value));
		Vector3 val2 = cam.WorldToScreenPoint(val);
		if (val2.z <= 0.05f)
		{
			return false;
		}
		Vector2 val3 = default(Vector2);
		((Vector2)(ref val3))..ctor(val2.x + Plugin.ScreenOffsetX.Value, val2.y + Plugin.ScreenOffsetY.Value);
		float num = AdsBlend(cam);
		if (num > 0f)
		{
			Vector2 val4 = default(Vector2);
			((Vector2)(ref val4))..ctor((float)Screen.width * Plugin.AdsViewportX.Value + Plugin.AdsOffsetX.Value, (float)Screen.height * Plugin.AdsViewportY.Value + Plugin.AdsOffsetY.Value);
			val3 = Vector2.Lerp(val3, val4, num);
		}
		Vector2 targetPos = default(Vector2);
		if (!RectTransformUtility.ScreenPointToLocalPointInRectangle(_canvasRect, val3, (Camera)null, ref targetPos))
		{
			return false;
		}
		_targetPos = targetPos;
		return true;
	}
}
[HarmonyPatch(typeof(PlayerGuiLayer), "SetVisible")]
internal static class HudVisibilityPatch
{
	[HarmonyPostfix]
	private static void Postfix(bool visible)
	{
		HoloAmmoBehaviour.HudVisible = visible;
		try
		{
			Plugin.L.LogDebug((object)("[BIOCOM] PlayerGuiLayer.SetVisible(" + visible + ")"));
		}
		catch
		{
		}
	}
}