Decompiled source of AnglersEye v0.1.0

plugins/AnglersEye/AnglersEye.dll

Decompiled 4 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using AnglersEye.Core;
using AnglersEye.Core.Model;
using AnglersEye.UI;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("assembly_valheim")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("AnglersEye")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("A fishing assistant: fish ID, smart bait, bite and struggle cues, catch forecast. Client-side.")]
[assembly: AssemblyFileVersion("0.1.0.0")]
[assembly: AssemblyInformationalVersion("0.1.0+c6687ef0c664fefa73a1920d8f374c8a51140e34")]
[assembly: AssemblyProduct("AnglersEye")]
[assembly: AssemblyTitle("AnglersEye")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.1.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
internal sealed class ConfigurationManagerAttributes
{
	public int? Order;

	public bool? IsAdvanced;

	public bool? Browsable;

	public bool? ReadOnly;
}
namespace AnglersEye
{
	[BepInPlugin("com.jumpingmushroom.anglerseye", "Angler's Eye", "0.1.0")]
	[BepInProcess("valheim.exe")]
	[BepInProcess("valheim.x86_64")]
	public sealed class AnglersEyePlugin : BaseUnityPlugin
	{
		public const string PluginGuid = "com.jumpingmushroom.anglerseye";

		public const string PluginName = "Angler's Eye";

		public const string PluginVersion = "0.1.0";

		internal static ManualLogSource Log;

		internal static AnglersEyePlugin Instance;

		private static readonly HashSet<string> Warned = new HashSet<string>();

		private Harmony _harmony;

		private void Awake()
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			Instance = this;
			PluginConfig.Bind(((BaseUnityPlugin)this).Config);
			ConsoleCommands.Register();
			_harmony = new Harmony("com.jumpingmushroom.anglerseye");
			_harmony.PatchAll(typeof(AnglersEyePlugin).Assembly);
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Angler's Eye 0.1.0 loaded.");
		}

		private void Update()
		{
			Runtime.Tick();
		}

		private void OnDestroy()
		{
			if (_harmony != null)
			{
				_harmony.UnpatchSelf();
			}
		}

		internal static void WarnOnce(string key, Exception e)
		{
			if (Warned.Add(key))
			{
				Log.LogWarning((object)(key + ": " + e));
			}
		}
	}
	public static class PluginConfig
	{
		public static ConfigEntry<bool> Enabled;

		public static ConfigEntry<bool> HoverInfo;

		public static ConfigEntry<bool> FloatLabel;

		public static ConfigEntry<bool> ShowOdds;

		public static ConfigEntry<bool> SmartBait;

		public static ConfigEntry<float> AimConeDegrees;

		public static ConfigEntry<bool> BiteCue;

		public static ConfigEntry<bool> BiteSound;

		public static ConfigEntry<float> BiteVolume;

		public static ConfigEntry<bool> StruggleIndicator;

		public static ConfigEntry<bool> Forecast;

		public static ConfigEntry<bool> SmartReel;

		public static ConfigEntry<bool> ExtendedHookWindow;

		public static ConfigEntry<float> HookWindowSeconds;

		public static ConfigEntry<float> Scale;

		public static ConfigEntry<float> OffsetX;

		public static ConfigEntry<float> OffsetY;

		public static ConfigEntry<bool> Verbose;

		private static ConfigurationManagerAttributes Attr(int order, bool advanced = false)
		{
			return new ConfigurationManagerAttributes
			{
				Order = order,
				IsAdvanced = advanced
			};
		}

		public static bool Toggle(Feature f)
		{
			return f switch
			{
				Feature.HoverInfo => HoverInfo.Value, 
				Feature.FloatLabel => FloatLabel.Value, 
				Feature.SmartBait => SmartBait.Value, 
				Feature.BiteCue => BiteCue.Value, 
				Feature.StruggleIndicator => StruggleIndicator.Value, 
				Feature.Forecast => Forecast.Value, 
				Feature.SmartReel => SmartReel.Value, 
				Feature.HookWindow => ExtendedHookWindow.Value, 
				_ => false, 
			};
		}

		public static void Bind(ConfigFile cfg)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Expected O, but got Unknown
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Expected O, but got Unknown
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Expected O, but got Unknown
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Expected O, but got Unknown
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Expected O, but got Unknown
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0139: Expected O, but got Unknown
			//IL_0161: Unknown result type (might be due to invalid IL or missing references)
			//IL_016b: Expected O, but got Unknown
			//IL_0193: Unknown result type (might be due to invalid IL or missing references)
			//IL_019d: Expected O, but got Unknown
			//IL_01d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e1: Expected O, but got Unknown
			//IL_0209: Unknown result type (might be due to invalid IL or missing references)
			//IL_0213: Expected O, but got Unknown
			//IL_023b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0245: Expected O, but got Unknown
			//IL_026d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0277: Expected O, but got Unknown
			//IL_029f: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a9: Expected O, but got Unknown
			//IL_02e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ed: Expected O, but got Unknown
			//IL_0327: Unknown result type (might be due to invalid IL or missing references)
			//IL_0331: Expected O, but got Unknown
			//IL_036b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0375: Expected O, but got Unknown
			//IL_03af: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b9: Expected O, but got Unknown
			//IL_03e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ea: Expected O, but got Unknown
			Enabled = cfg.Bind<bool>("1 - General", "Enabled", true, new ConfigDescription("Master switch for everything Angler's Eye shows or does.", (AcceptableValueBase)null, new object[1] { Attr(100) }));
			HoverInfo = cfg.Bind<bool>("2 - Identify", "HoverInfo", true, new ConfigDescription("When you look at a fish, add its stars and the bait it takes to the hover text: how many you carry, or ✖ if none.", (AcceptableValueBase)null, new object[1] { Attr(90) }));
			FloatLabel = cfg.Bind<bool>("2 - Identify", "FloatLabel", true, new ConfigDescription("Show a small label above your float naming the fish heading for it, and whether your bait works on it.", (AcceptableValueBase)null, new object[1] { Attr(89) }));
			ShowOdds = cfg.Bind<bool>("2 - Identify", "ShowOdds", false, new ConfigDescription("Also show the bait's chance per nibble, e.g. 'Cold bait 60%'.", (AcceptableValueBase)null, new object[1] { Attr(88) }));
			SmartBait = cfg.Bind<bool>("3 - Bait", "SmartBait", true, new ConfigDescription("On cast, equip the carried bait that works best on the fish you're aiming at. Tells you if you carry none.", (AcceptableValueBase)null, new object[1] { Attr(80) }));
			AimConeDegrees = cfg.Bind<float>("3 - Bait", "AimConeDegrees", 10f, new ConfigDescription("How far off your aim (in degrees) a fish can be and still count as the one you're aiming at.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(3f, 30f), new object[1] { Attr(79) }));
			BiteCue = cfg.Bind<bool>("4 - Cues", "BiteCue", true, new ConfigDescription("Show 'BITE!' in the fishing panel while a nibble can be hooked.", (AcceptableValueBase)null, new object[1] { Attr(70) }));
			BiteSound = cfg.Bind<bool>("4 - Cues", "BiteSound", true, new ConfigDescription("Play a short sound on a nibble you can hook. Needs BiteCue on.", (AcceptableValueBase)null, new object[1] { Attr(69) }));
			BiteVolume = cfg.Bind<float>("4 - Cues", "BiteVolume", 0.7f, new ConfigDescription("Volume of the bite sound.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), new object[1] { Attr(68) }));
			StruggleIndicator = cfg.Bind<bool>("4 - Cues", "StruggleIndicator", true, new ConfigDescription("While a fish is hooked, show REEL when it's calm and WAIT (with a bar counting down the struggle) when it's struggling.", (AcceptableValueBase)null, new object[1] { Attr(67) }));
			Forecast = cfg.Bind<bool>("5 - Forecast", "Forecast", true, new ConfigDescription("Estimate whether you have the stamina to land the fish: can land, tight or unlikely.", (AcceptableValueBase)null, new object[1] { Attr(60) }));
			SmartReel = cfg.Bind<bool>("6 - Assists", "SmartReel", false, new ConfigDescription("While you hold Block, only reel while the fish is calm. Stamina costs stay vanilla. Fishing skill won't rise while it's waiting out a struggle.", (AcceptableValueBase)null, new object[1] { Attr(50) }));
			ExtendedHookWindow = cfg.Bind<bool>("6 - Assists", "ExtendedHookWindow", false, new ConfigDescription("Give yourself longer than vanilla's 0.5 s to hook a nibble.", (AcceptableValueBase)null, new object[1] { Attr(49) }));
			HookWindowSeconds = cfg.Bind<float>("6 - Assists", "HookWindowSeconds", 1f, new ConfigDescription("Hook window when ExtendedHookWindow is on.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 1.5f), new object[1] { Attr(48) }));
			Scale = cfg.Bind<float>("7 - UI", "Scale", 1f, new ConfigDescription("Size of the fishing panel and the float label.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 2f), new object[1] { Attr(40) }));
			OffsetX = cfg.Bind<float>("7 - UI", "OffsetX", 0f, new ConfigDescription("Horizontal nudge of the fishing panel from its spot above the stamina bar, in pixels (positive is right).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-1500f, 1500f), new object[1] { Attr(39) }));
			OffsetY = cfg.Bind<float>("7 - UI", "OffsetY", 0f, new ConfigDescription("Vertical nudge of the fishing panel from its spot above the stamina bar, in pixels (positive is up).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-1000f, 1000f), new object[1] { Attr(38) }));
			Verbose = cfg.Bind<bool>("8 - Logging", "Verbose", false, new ConfigDescription("Log smart bait and compat decisions to the BepInEx log.", (AcceptableValueBase)null, new object[1] { Attr(5, advanced: true) }));
		}
	}
}
namespace AnglersEye.UI
{
	internal static class BiteCue
	{
		private static readonly string[] Candidates = new string[2] { "UI_Craft_Finish_01", "Ui_Click_01" };

		private const float RetryLookupAfter = 30f;

		private static float _until;

		private static float _nextLookup;

		private static bool _warnedMissing;

		private static AudioClip _clip;

		private static AudioSource _source;

		public static bool Active => Time.time < _until;

		public static void Fire()
		{
			if (Features.On(Feature.BiteCue))
			{
				_until = Time.time + ReelPolicy.HookWindow(Features.On(Feature.HookWindow), PluginConfig.HookWindowSeconds.Value);
				if (PluginConfig.BiteSound.Value)
				{
					Play();
				}
			}
		}

		private static void Play()
		{
			if ((Object)(object)_clip == (Object)null && Time.time >= _nextLookup)
			{
				_nextLookup = Time.time + 30f;
				Dictionary<string, AudioClip> dictionary = new Dictionary<string, AudioClip>();
				AudioClip[] array = Resources.FindObjectsOfTypeAll<AudioClip>();
				foreach (AudioClip val in array)
				{
					if ((Object)(object)val != (Object)null && !dictionary.ContainsKey(((Object)val).name))
					{
						dictionary[((Object)val).name] = val;
					}
				}
				string[] candidates = Candidates;
				foreach (string key in candidates)
				{
					if (dictionary.TryGetValue(key, out _clip))
					{
						break;
					}
				}
				if ((Object)(object)_clip == (Object)null && !_warnedMissing)
				{
					_warnedMissing = true;
					AnglersEyePlugin.Log.LogWarning((object)"Angler's Eye: no bite sound found; the visual cue still works.");
				}
			}
			if (!((Object)(object)_clip == (Object)null))
			{
				if ((Object)(object)_source == (Object)null)
				{
					_source = ((Component)AnglersEyePlugin.Instance).gameObject.AddComponent<AudioSource>();
					_source.playOnAwake = false;
					_source.spatialBlend = 0f;
				}
				if ((Object)(object)AudioMan.instance != (Object)null && (Object)(object)_source.outputAudioMixerGroup == (Object)null)
				{
					_source.outputAudioMixerGroup = AudioMan.instance.m_guiMixer;
				}
				_source.PlayOneShot(_clip, PluginConfig.BiteVolume.Value);
			}
		}
	}
	internal static class FishingPanel
	{
		private const float Gap = 6f;

		private const float MinWidth = 170f;

		private const float TextSize = 20f;

		private const float BigSize = 30f;

		private const float StarSize = 18f;

		private const float BarHeight = 5f;

		private static readonly int VisibleHash = Animator.StringToHash("Visible");

		private static readonly Vector3[] Corners = (Vector3[])(object)new Vector3[4];

		private static readonly List<Image> StarPool = new List<Image>();

		private static RectTransform _root;

		private static RectTransform _titleRow;

		private static RectTransform _bodyRow;

		private static RectTransform _bodyCol;

		private static RectTransform _bar;

		private static RectTransform _barFill;

		private static TextMeshProUGUI _title;

		private static TextMeshProUGUI _body;

		private static TextMeshProUGUI _forecast;

		private static Image _barFillImage;

		private static Hud _builtFor;

		public static void Show(PanelView v)
		{
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0175: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			if (v == null || !Ensure())
			{
				Hide();
				return;
			}
			bool flag = v.Title != null;
			SetActive(_titleRow, flag);
			if (flag)
			{
				bool starsDrawn = UiUtil.Stars(_titleRow, StarPool, v.Level, 1, 18f);
				UiUtil.SetText((TMP_Text)(object)_title, UiUtil.NameWithLevel(v.Title, v.Level, starsDrawn));
			}
			bool flag2 = v.Body != null;
			bool flag3 = v.Forecast != null;
			SetActive(_bodyRow, flag2 || flag3);
			SetActive(_bodyCol, flag2);
			if (flag2)
			{
				UiUtil.SetText((TMP_Text)(object)_body, v.Body);
				((Graphic)_body).color = Palette.For(v.BodyTone);
				((TMP_Text)_body).fontSize = (v.BodyIsBig ? 30f : 20f);
				((TMP_Text)_body).fontStyle = (FontStyles)(v.BodyIsBig ? 1 : 0);
			}
			SetActive(_bar, flag2 && v.Bar.HasValue);
			if (flag2 && v.Bar.HasValue)
			{
				_barFill.anchorMax = new Vector2(v.Bar.Value, 1f);
				((Graphic)_barFillImage).color = Palette.For(v.BodyTone);
			}
			SetActive(((TMP_Text)_forecast).rectTransform, flag3);
			if (flag3)
			{
				UiUtil.SetText((TMP_Text)(object)_forecast, v.Forecast);
				((Graphic)_forecast).color = Palette.For(v.ForecastTone);
			}
			SetActive(_root, on: true);
			Place(_builtFor);
		}

		public static void Hide()
		{
			if ((Object)(object)_root != (Object)null)
			{
				SetActive(_root, on: false);
			}
		}

		private static void SetActive(RectTransform rt, bool on)
		{
			if (((Component)rt).gameObject.activeSelf != on)
			{
				((Component)rt).gameObject.SetActive(on);
			}
		}

		private static bool Ensure()
		{
			//IL_008d: 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_00a8: 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_011a: Expected O, but got Unknown
			//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0265: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02df: Unknown result type (might be due to invalid IL or missing references)
			Hud instance = Hud.instance;
			if ((Object)(object)instance == (Object)null || (Object)(object)instance.m_staminaBar2Root == (Object)null || (Object)(object)((Transform)instance.m_staminaBar2Root).parent == (Object)null)
			{
				return false;
			}
			if ((Object)(object)_root != (Object)null && (Object)(object)_builtFor == (Object)(object)instance)
			{
				return true;
			}
			StarPool.Clear();
			_root = UiUtil.Rect("AnglersEyePanel", ((Transform)instance.m_staminaBar2Root).parent);
			RectTransform root = _root;
			RectTransform root2 = _root;
			Vector2 val = default(Vector2);
			((Vector2)(ref val))..ctor(0.5f, 0.5f);
			root2.anchorMax = val;
			root.anchorMin = val;
			_root.pivot = new Vector2(0.5f, 0f);
			Image obj = ((Component)_root).gameObject.AddComponent<Image>();
			obj.sprite = UiUtil.Frame;
			obj.type = (Type)1;
			((Graphic)obj).raycastTarget = false;
			LayoutElement obj2 = ((Component)_root).gameObject.AddComponent<LayoutElement>();
			obj2.ignoreLayout = true;
			obj2.minWidth = 170f;
			VerticalLayoutGroup obj3 = ((Component)_root).gameObject.AddComponent<VerticalLayoutGroup>();
			((LayoutGroup)obj3).padding = new RectOffset(16, 16, 8, 10);
			((HorizontalOrVerticalLayoutGroup)obj3).spacing = 0f;
			((LayoutGroup)obj3).childAlignment = (TextAnchor)1;
			bool childControlWidth = (((HorizontalOrVerticalLayoutGroup)obj3).childControlHeight = true);
			((HorizontalOrVerticalLayoutGroup)obj3).childControlWidth = childControlWidth;
			childControlWidth = (((HorizontalOrVerticalLayoutGroup)obj3).childForceExpandHeight = false);
			((HorizontalOrVerticalLayoutGroup)obj3).childForceExpandWidth = childControlWidth;
			ContentSizeFitter obj4 = ((Component)_root).gameObject.AddComponent<ContentSizeFitter>();
			obj4.horizontalFit = (FitMode)2;
			obj4.verticalFit = (FitMode)2;
			_titleRow = Row("Title", (Transform)(object)_root, 4f);
			_title = UiUtil.OutlinedText((Transform)(object)_titleRow, "Name", 20f, (TextAlignmentOptions)514);
			((Graphic)_title).color = Palette.Normal;
			_bodyRow = Row("Body", (Transform)(object)_root, 18f);
			_bodyCol = UiUtil.Rect("State", (Transform)(object)_bodyRow);
			VerticalLayoutGroup obj5 = ((Component)_bodyCol).gameObject.AddComponent<VerticalLayoutGroup>();
			((HorizontalOrVerticalLayoutGroup)obj5).spacing = 1f;
			((LayoutGroup)obj5).childAlignment = (TextAnchor)4;
			childControlWidth = (((HorizontalOrVerticalLayoutGroup)obj5).childControlHeight = true);
			((HorizontalOrVerticalLayoutGroup)obj5).childControlWidth = childControlWidth;
			((HorizontalOrVerticalLayoutGroup)obj5).childForceExpandWidth = true;
			((HorizontalOrVerticalLayoutGroup)obj5).childForceExpandHeight = false;
			_body = UiUtil.OutlinedText((Transform)(object)_bodyCol, "Text", 20f, (TextAlignmentOptions)514);
			_bar = UiUtil.Rect("StruggleBar", (Transform)(object)_bodyCol);
			Image obj6 = ((Component)_bar).gameObject.AddComponent<Image>();
			obj6.sprite = UiUtil.White;
			((Graphic)obj6).color = Palette.Track;
			((Graphic)obj6).raycastTarget = false;
			LayoutElement obj7 = ((Component)_bar).gameObject.AddComponent<LayoutElement>();
			float minHeight = (obj7.preferredHeight = 5f);
			obj7.minHeight = minHeight;
			_barFill = UiUtil.Rect("Fill", (Transform)(object)_bar);
			_barFill.anchorMin = Vector2.zero;
			_barFill.anchorMax = Vector2.one;
			val = (_barFill.offsetMin = (_barFill.offsetMax = Vector2.zero));
			_barFillImage = ((Component)_barFill).gameObject.AddComponent<Image>();
			_barFillImage.sprite = UiUtil.White;
			((Graphic)_barFillImage).raycastTarget = false;
			_forecast = UiUtil.OutlinedText((Transform)(object)_bodyRow, "Forecast", 20f, (TextAlignmentOptions)514);
			_builtFor = instance;
			return true;
		}

		private static RectTransform Row(string name, Transform parent, float spacing)
		{
			RectTransform obj = UiUtil.Rect(name, parent);
			HorizontalLayoutGroup obj2 = ((Component)obj).gameObject.AddComponent<HorizontalLayoutGroup>();
			((HorizontalOrVerticalLayoutGroup)obj2).spacing = spacing;
			((LayoutGroup)obj2).childAlignment = (TextAnchor)4;
			bool childControlWidth = (((HorizontalOrVerticalLayoutGroup)obj2).childControlHeight = true);
			((HorizontalOrVerticalLayoutGroup)obj2).childControlWidth = childControlWidth;
			childControlWidth = (((HorizontalOrVerticalLayoutGroup)obj2).childForceExpandHeight = false);
			((HorizontalOrVerticalLayoutGroup)obj2).childForceExpandWidth = childControlWidth;
			return obj;
		}

		private static void Place(Hud hud)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: 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_009e: 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_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: 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_0109: Unknown result type (might be due to invalid IL or missing references)
			RectTransform val = (RectTransform)((Transform)_root).parent;
			hud.m_staminaBar2Root.GetWorldCorners(Corners);
			float num = (Corners[0].x + Corners[2].x) * 0.5f;
			float z = Corners[0].z;
			float num2 = Top(top: Top(top: Corners[1].y, bar: hud.m_eitrBarRoot, anim: hud.m_eitrAnimator), bar: hud.m_adrenalineBarRoot, anim: hud.m_adrenalineAnimator);
			Vector3 val2 = ((Transform)val).InverseTransformPoint(new Vector3(num, num2, z));
			Rect rect = val.rect;
			Vector2 center = ((Rect)(ref rect)).center;
			_root.anchoredPosition = new Vector2(val2.x - center.x + PluginConfig.OffsetX.Value, val2.y - center.y + 6f + PluginConfig.OffsetY.Value);
			((Transform)_root).localScale = Vector3.one * PluginConfig.Scale.Value;
		}

		private static float Top(RectTransform bar, Animator anim, float top)
		{
			if ((Object)(object)bar == (Object)null || !((Component)bar).gameObject.activeInHierarchy || (Object)(object)anim == (Object)null || !((Behaviour)anim).isActiveAndEnabled || (Object)(object)anim.runtimeAnimatorController == (Object)null || !anim.GetBool(VisibleHash))
			{
				return top;
			}
			bar.GetWorldCorners(Corners);
			return Mathf.Max(top, Corners[1].y);
		}
	}
	internal static class FloatLabel
	{
		private const float Above = 0.8f;

		private const float TextSize = 20f;

		private const float StarSize = 18f;

		private static readonly List<Image> StarPool = new List<Image>();

		private static RectTransform _root;

		private static TextMeshProUGUI _name;

		private static TextMeshProUGUI _bait;

		private static Hud _builtFor;

		public static void Update(FishingSnapshot s)
		{
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: 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_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: 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)
			//IL_0085: 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_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cd: 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_01fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0208: Unknown result type (might be due to invalid IL or missing references)
			//IL_0217: Unknown result type (might be due to invalid IL or missing references)
			if (!Features.On(Feature.FloatLabel) || (Object)(object)s.Float == (Object)null || (Object)(object)s.Catch != (Object)null || (Object)(object)s.Subject == (Object)null)
			{
				Hide();
				return;
			}
			Camera mainCamera = Utils.GetMainCamera();
			if ((Object)(object)mainCamera == (Object)null)
			{
				Hide();
				return;
			}
			Vector3 val = Utils.WorldToScreenPointScaled(mainCamera, ((Component)s.Float).transform.position + Vector3.up * 0.8f);
			if (val.z < 0f || val.x < 0f || val.x > (float)Screen.width || val.y < 0f || val.y > (float)Screen.height)
			{
				Hide();
			}
			else
			{
				if (!Ensure())
				{
					return;
				}
				FishInfo fishInfo = FishCatalog.For(s.Subject);
				int quality = FishCatalog.Quality(s.Subject);
				string bait = s.Float.GetBait();
				bool flag = false;
				foreach (BaitOption bait2 in fishInfo.Baits)
				{
					if (bait2.BaitId == bait)
					{
						flag = true;
						break;
					}
				}
				BaitAdvice baitAdvice = Tackle.Advise(s.Player, fishInfo);
				string neededBait = ((baitAdvice != null) ? baitAdvice.Best.BaitName : "?");
				bool starsDrawn = UiUtil.Stars(_root, StarPool, quality, 1, 18f);
				UiUtil.SetText((TMP_Text)(object)_name, UiUtil.NameWithLevel(fishInfo.Name, quality, starsDrawn));
				UiUtil.SiblingIndex(((TMP_Text)_bait).transform, ((Transform)_root).childCount - 1);
				UiUtil.SetText((TMP_Text)(object)_bait, Labels.OnFloat(flag, neededBait, UiUtil.Glyphs));
				((Graphic)_bait).color = (flag ? Palette.Normal : Palette.Bad);
				if (!((Component)_root).gameObject.activeSelf)
				{
					((Component)_root).gameObject.SetActive(true);
				}
				((Transform)_root).position = val;
				((Transform)_root).localScale = Vector3.one * PluginConfig.Scale.Value;
			}
		}

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

		private static bool Ensure()
		{
			//IL_0073: 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)
			Hud instance = Hud.instance;
			if ((Object)(object)instance == (Object)null || (Object)(object)instance.m_crosshair == (Object)null)
			{
				return false;
			}
			if ((Object)(object)_root != (Object)null && (Object)(object)_builtFor == (Object)(object)instance)
			{
				return true;
			}
			StarPool.Clear();
			_root = UiUtil.Rect("AnglersEyeFloatLabel", ((Component)instance.m_crosshair).transform.parent);
			_root.pivot = new Vector2(0.5f, 0f);
			HorizontalLayoutGroup obj = ((Component)_root).gameObject.AddComponent<HorizontalLayoutGroup>();
			((HorizontalOrVerticalLayoutGroup)obj).spacing = 3f;
			((LayoutGroup)obj).childAlignment = (TextAnchor)4;
			bool childControlWidth = (((HorizontalOrVerticalLayoutGroup)obj).childControlHeight = true);
			((HorizontalOrVerticalLayoutGroup)obj).childControlWidth = childControlWidth;
			childControlWidth = (((HorizontalOrVerticalLayoutGroup)obj).childForceExpandHeight = false);
			((HorizontalOrVerticalLayoutGroup)obj).childForceExpandWidth = childControlWidth;
			ContentSizeFitter obj2 = ((Component)_root).gameObject.AddComponent<ContentSizeFitter>();
			obj2.horizontalFit = (FitMode)2;
			obj2.verticalFit = (FitMode)2;
			_name = UiUtil.OutlinedText((Transform)(object)_root, "Name", 20f, (TextAlignmentOptions)514);
			((Graphic)_name).color = Palette.Normal;
			_bait = UiUtil.OutlinedText((Transform)(object)_root, "Bait", 20f, (TextAlignmentOptions)514);
			_builtFor = instance;
			return true;
		}
	}
	internal static class Palette
	{
		public static readonly Color Normal = new Color(0.93f, 0.91f, 0.86f, 1f);

		public static readonly Color Good = new Color(0.56f, 0.87f, 0.42f, 1f);

		public static readonly Color Warn = new Color(1f, 0.71f, 0.24f, 1f);

		public static readonly Color Bad = new Color(0.97f, 0.43f, 0.36f, 1f);

		public static readonly Color Bite = new Color(1f, 0.9f, 0.3f, 1f);

		public static readonly Color Frame = new Color(0.08f, 0.07f, 0.06f, 0.78f);

		public static readonly Color FrameLine = new Color(0.78f, 0.63f, 0.31f, 0.9f);

		public static readonly Color Track = new Color(0f, 0f, 0f, 0.55f);

		public static Color For(Tone t)
		{
			//IL_001a: 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_0026: 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)
			return (Color)(t switch
			{
				Tone.Good => Good, 
				Tone.Warn => Warn, 
				Tone.Bad => Bad, 
				Tone.Bite => Bite, 
				_ => Normal, 
			});
		}
	}
	internal static class UiUtil
	{
		private static Sprite _white;

		private static Sprite _frame;

		private static Glyphs _glyphs;

		private static TMP_FontAsset _glyphFont;

		private static EnemyHud _starFor;

		private static Sprite _star;

		private static Color _starColor = Color.white;

		private const int FrameSize = 32;

		private const float FrameRadius = 6f;

		private const float FrameLine = 1.25f;

		private const int FrameBorder = 8;

		public static Sprite White
		{
			get
			{
				//IL_0017: Unknown result type (might be due to invalid IL or missing references)
				//IL_001d: Expected O, but got Unknown
				//IL_003f: 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_007d: Unknown result type (might be due to invalid IL or missing references)
				//IL_008c: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)_white != (Object)null)
				{
					return _white;
				}
				Texture2D val = new Texture2D(4, 4, (TextureFormat)4, false);
				Color32[] array = (Color32[])(object)new Color32[16];
				for (int i = 0; i < array.Length; i++)
				{
					array[i] = new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue);
				}
				val.SetPixels32(array);
				val.Apply();
				((Object)val).hideFlags = (HideFlags)61;
				_white = Sprite.Create(val, new Rect(0f, 0f, 4f, 4f), new Vector2(0.5f, 0.5f), 4f);
				((Object)_white).hideFlags = (HideFlags)61;
				return _white;
			}
		}

		public static TMP_FontAsset Font
		{
			get
			{
				Hud instance = Hud.instance;
				if (!((Object)(object)instance != (Object)null) || !((Object)(object)instance.m_hoverName != (Object)null))
				{
					return null;
				}
				return ((TMP_Text)instance.m_hoverName).font;
			}
		}

		public static Glyphs Glyphs
		{
			get
			{
				TMP_FontAsset f = Font;
				if (_glyphs == null || (Object)(object)f != (Object)(object)_glyphFont)
				{
					_glyphFont = f;
					_glyphs = (((Object)(object)f == (Object)null) ? Glyphs.Ascii() : Glyphs.Resolve((char c) => f.HasCharacter(c, false, false)));
				}
				return _glyphs;
			}
		}

		public static Sprite Frame
		{
			get
			{
				//IL_0019: Unknown result type (might be due to invalid IL or missing references)
				//IL_001f: Expected O, but got Unknown
				//IL_015f: Unknown result type (might be due to invalid IL or missing references)
				//IL_016e: 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_0098: 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_00e6: Unknown result type (might be due to invalid IL or missing references)
				//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
				//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
				//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
				//IL_010e: 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_0115: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)_frame != (Object)null)
				{
					return _frame;
				}
				Texture2D val = new Texture2D(32, 32, (TextureFormat)4, false);
				((Texture)val).wrapMode = (TextureWrapMode)1;
				((Texture)val).filterMode = (FilterMode)1;
				Color32[] array = (Color32[])(object)new Color32[1024];
				float num = 16f;
				for (int i = 0; i < 32; i++)
				{
					for (int j = 0; j < 32; j++)
					{
						float num2 = Mathf.Abs((float)j + 0.5f - num) - (num - 6f);
						float num3 = Mathf.Abs((float)i + 0.5f - num) - (num - 6f);
						Vector2 val2 = new Vector2(Mathf.Max(num2, 0f), Mathf.Max(num3, 0f));
						float num4 = ((Vector2)(ref val2)).magnitude + Mathf.Min(Mathf.Max(num2, num3), 0f) - 6f;
						float num5 = Mathf.Clamp01(0.5f - num4);
						float num6 = Mathf.Clamp01(num4 + 1.25f + 0.5f);
						Color val3 = Color.Lerp(Palette.Frame, Palette.FrameLine, num6);
						val3.a *= num5;
						array[i * 32 + j] = Color32.op_Implicit(val3);
					}
				}
				val.SetPixels32(array);
				val.Apply();
				((Object)val).hideFlags = (HideFlags)61;
				_frame = Sprite.Create(val, new Rect(0f, 0f, 32f, 32f), new Vector2(0.5f, 0.5f), 100f, 0u, (SpriteMeshType)0, new Vector4(8f, 8f, 8f, 8f));
				((Object)_frame).hideFlags = (HideFlags)61;
				return _frame;
			}
		}

		public static Sprite Star
		{
			get
			{
				//IL_008b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0090: Unknown result type (might be due to invalid IL or missing references)
				EnemyHud instance = EnemyHud.instance;
				if ((Object)(object)instance == (Object)null)
				{
					return null;
				}
				if ((Object)(object)_starFor != (Object)(object)instance)
				{
					_starFor = instance;
					_star = null;
					Transform val = (((Object)(object)instance.m_baseHud != (Object)null) ? instance.m_baseHud.transform.Find("level_2") : null);
					if ((Object)(object)val != (Object)null)
					{
						Image[] componentsInChildren = ((Component)val).GetComponentsInChildren<Image>(true);
						foreach (Image val2 in componentsInChildren)
						{
							if (!((Object)(object)val2.sprite == (Object)null))
							{
								_star = val2.sprite;
								_starColor = ((Graphic)val2).color;
								break;
							}
						}
					}
				}
				return _star;
			}
		}

		public static RectTransform Rect(string name, Transform parent)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: 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_003d: Expected O, but got Unknown
			RectTransform val = (RectTransform)new GameObject(name, new Type[1] { typeof(RectTransform) })
			{
				layer = ((Component)parent).gameObject.layer
			}.transform;
			((Transform)val).SetParent(parent, false);
			return val;
		}

		public static TextMeshProUGUI Text(Transform parent, string name, float size, TextAlignmentOptions align)
		{
			//IL_0048: 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)
			RectTransform obj = Rect(name, parent);
			((Component)obj).gameObject.SetActive(false);
			TextMeshProUGUI val = ((Component)obj).gameObject.AddComponent<TextMeshProUGUI>();
			TMP_FontAsset font = Font;
			if ((Object)(object)font != (Object)null)
			{
				((TMP_Text)val).font = font;
			}
			((Component)obj).gameObject.SetActive(true);
			((TMP_Text)val).fontSize = size;
			((TMP_Text)val).alignment = align;
			((TMP_Text)val).textWrappingMode = (TextWrappingModes)0;
			((TMP_Text)val).richText = true;
			((Graphic)val).raycastTarget = false;
			((Graphic)val).color = new Color(0.9f, 0.9f, 0.9f, 1f);
			return val;
		}

		public static TextMeshProUGUI OutlinedText(Transform parent, string name, float size, TextAlignmentOptions align)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			TextMeshProUGUI val = Text(parent, name, size, align);
			Hud instance = Hud.instance;
			TMP_Text val2 = (TMP_Text)(object)(((Object)(object)instance != (Object)null) ? instance.m_hoverName : null);
			if ((Object)(object)val2 != (Object)null && (Object)(object)val2.font == (Object)(object)((TMP_Text)val).font && (Object)(object)val2.fontSharedMaterial != (Object)null)
			{
				((TMP_Text)val).fontSharedMaterial = val2.fontSharedMaterial;
			}
			else
			{
				((TMP_Text)val).outlineWidth = 0.2f;
				((TMP_Text)val).outlineColor = new Color32((byte)0, (byte)0, (byte)0, byte.MaxValue);
			}
			return val;
		}

		public static bool Stars(RectTransform row, List<Image> pool, int quality, int first, float size)
		{
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			int num = quality - 1;
			Sprite val = ((num > 0) ? Star : null);
			if ((Object)(object)val == (Object)null)
			{
				num = 0;
			}
			while (pool.Count < num)
			{
				RectTransform obj = Rect("Star" + pool.Count, (Transform)(object)row);
				Image val2 = ((Component)obj).gameObject.AddComponent<Image>();
				((Graphic)val2).raycastTarget = false;
				val2.preserveAspect = true;
				LayoutElement obj2 = ((Component)obj).gameObject.AddComponent<LayoutElement>();
				float minWidth = (obj2.preferredWidth = size);
				obj2.minWidth = minWidth;
				minWidth = (obj2.preferredHeight = size);
				obj2.minHeight = minWidth;
				pool.Add(val2);
			}
			for (int i = 0; i < pool.Count; i++)
			{
				bool flag = i < num;
				if (((Component)pool[i]).gameObject.activeSelf != flag)
				{
					((Component)pool[i]).gameObject.SetActive(flag);
				}
				if (flag)
				{
					pool[i].sprite = val;
					((Graphic)pool[i]).color = _starColor;
					SiblingIndex(((Component)pool[i]).transform, first + i);
				}
			}
			if (quality > 1)
			{
				return (Object)(object)val != (Object)null;
			}
			return true;
		}

		public static void SiblingIndex(Transform t, int index)
		{
			if (t.GetSiblingIndex() != index)
			{
				t.SetSiblingIndex(index);
			}
		}

		public static string NameWithLevel(string name, int quality, bool starsDrawn)
		{
			string text = (starsDrawn ? "" : Labels.Level(quality));
			if (text.Length != 0)
			{
				return name + " " + text;
			}
			return name;
		}

		public static string Printable(string s, TMP_Text t)
		{
			if (s != null && s.IndexOf('…') >= 0 && (Object)(object)t.font != (Object)null && !t.font.HasCharacter('…', false, false))
			{
				return s.Replace("…", "...");
			}
			return s;
		}

		public static void SetText(TMP_Text t, string s)
		{
			s = Printable(s, t);
			if (t.text != s)
			{
				t.text = s;
			}
		}
	}
}
namespace AnglersEye.Patches
{
	[HarmonyPatch]
	internal static class CastPatches
	{
		[HarmonyPrefix]
		[HarmonyPatch(typeof(Attack), "StartDraw")]
		private static void StartDraw(Humanoid character, ItemData weapon)
		{
			Run(character, weapon);
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Attack), "Start")]
		private static void Start(Humanoid character, ItemData weapon)
		{
			Run(character, weapon);
		}

		private static void Run(Humanoid character, ItemData weapon)
		{
			try
			{
				SmartBait.BeforeCast(character, weapon);
			}
			catch (Exception e)
			{
				AnglersEyePlugin.WarnOnce("SmartBait", e);
			}
		}
	}
	[HarmonyPatch(typeof(Fish), "GetHoverText")]
	internal static class HoverPatch
	{
		private static void Postfix(Fish __instance, ref string __result)
		{
			try
			{
				if (Features.On(Feature.HoverInfo) && !__instance.IsOutOfWater() && !((Object)(object)Player.m_localPlayer == (Object)null))
				{
					FishInfo info = FishCatalog.For(__instance);
					BaitAdvice a = Tackle.Advise(Player.m_localPlayer, info);
					__result += Labels.HoverSuffix(FishCatalog.Quality(__instance), a, UiUtil.Glyphs, PluginConfig.ShowOdds.Value);
				}
			}
			catch (Exception e)
			{
				AnglersEyePlugin.WarnOnce("HoverPatch", e);
			}
		}
	}
	[HarmonyPatch(typeof(FishingFloat), "RPC_Nibble")]
	internal static class NibblePatch
	{
		private static void Prefix(FishingFloat __instance, out float __state)
		{
			__state = __instance.m_nibbleTime;
		}

		private static void Postfix(FishingFloat __instance, bool correctBait, float __state)
		{
			try
			{
				if (correctBait && __instance.m_nibbleTime != __state && FishingState.IsLocal(__instance))
				{
					BiteCue.Fire();
				}
			}
			catch (Exception e)
			{
				AnglersEyePlugin.WarnOnce("NibblePatch", e);
			}
		}
	}
	[HarmonyPatch]
	internal static class ReelPatches
	{
		[ThreadStatic]
		private static bool _suppressBlock;

		[HarmonyPrefix]
		[HarmonyPatch(typeof(FishingFloat), "FixedUpdate")]
		private static void FloatUpdatePrefix(FishingFloat __instance)
		{
			_suppressBlock = false;
			try
			{
				if (Features.On(Feature.SmartReel) && FishingState.IsLocal(__instance))
				{
					Fish val = __instance.GetCatch();
					_suppressBlock = ReelPolicy.SuppressReel(smartReel: true, (Object)(object)val != (Object)null, (Object)(object)val != (Object)null && val.IsEscaping());
				}
			}
			catch (Exception e)
			{
				AnglersEyePlugin.WarnOnce("SmartReel", e);
			}
		}

		[HarmonyFinalizer]
		[HarmonyPatch(typeof(FishingFloat), "FixedUpdate")]
		private static void FloatUpdateFinalizer()
		{
			_suppressBlock = false;
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Humanoid), "IsBlocking")]
		private static bool IsBlockingPrefix(ref bool __result)
		{
			if (!_suppressBlock)
			{
				return true;
			}
			__result = false;
			return false;
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(FishingFloat), "TryToHook")]
		private static bool TryToHookPrefix(FishingFloat __instance)
		{
			try
			{
				if (!Features.On(Feature.HookWindow) || !FishingState.IsLocal(__instance))
				{
					return true;
				}
				float window = ReelPolicy.HookWindow(extended: true, PluginConfig.HookWindowSeconds.Value);
				if ((Object)(object)__instance.m_nibbler != (Object)null && ReelPolicy.InHookWindow(Time.time, __instance.m_nibbleTime, window) && (Object)(object)__instance.GetCatch() == (Object)null)
				{
					__instance.Message("$msg_fishing_hooked", true);
					__instance.SetCatch(__instance.m_nibbler);
					__instance.m_nibbler = null;
					Game.instance.IncrementPlayerStat((PlayerStatType)158, 1f, false);
				}
				return false;
			}
			catch (Exception e)
			{
				AnglersEyePlugin.WarnOnce("HookWindow", e);
				return true;
			}
		}
	}
}
namespace AnglersEye.Core
{
	internal static class Compat
	{
		public static CompatVerdict Verdict { get; private set; }

		public static bool IsOff(Feature f)
		{
			if (Verdict != null)
			{
				return Verdict.IsOff(f);
			}
			return false;
		}

		public static void EnsureEvaluated()
		{
			if (Verdict != null || (Object)(object)ZNetScene.instance == (Object)null)
			{
				return;
			}
			HashSet<string> pluginGuids = new HashSet<string>(Chainloader.PluginInfos.Keys);
			Dictionary<string, IList<string>> foreignPatchOwners = new Dictionary<string, IList<string>>
			{
				{
					"FishingFloat.FixedUpdate",
					Owners(typeof(FishingFloat), "FixedUpdate")
				},
				{
					"FishingFloat.TryToHook",
					Owners(typeof(FishingFloat), "TryToHook")
				},
				{
					"Fish.GetStaminaUse",
					Owners(typeof(Fish), "GetStaminaUse")
				}
			};
			Verdict = CompatRules.Evaluate(pluginGuids, foreignPatchOwners);
			foreach (string reason in Verdict.Reasons)
			{
				AnglersEyePlugin.Log.LogInfo((object)("Angler's Eye compat: " + reason));
			}
		}

		private static IList<string> Owners(Type type, string method)
		{
			List<string> list = new List<string>();
			MethodBase methodBase = AccessTools.Method(type, method, (Type[])null, (Type[])null);
			Patches val = ((methodBase != null) ? Harmony.GetPatchInfo(methodBase) : null);
			if (val == null)
			{
				return list;
			}
			foreach (string owner in val.Owners)
			{
				if (owner != "com.jumpingmushroom.anglerseye" && !list.Contains(owner))
				{
					list.Add(owner);
				}
			}
			return list;
		}
	}
	internal static class ConsoleCommands
	{
		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static ConsoleEvent <>9__0_0;

			public static Func<FishInfo, string> <>9__3_0;

			public static Func<BaitOption, string> <>9__3_1;

			internal void <Register>b__0_0(ConsoleEventArgs args)
			{
				if (((args.Length > 1) ? args[1].ToLowerInvariant() : "") == "fish")
				{
					Fish(args.Context);
				}
				else
				{
					Status(args.Context);
				}
			}

			internal string <Fish>b__3_0(FishInfo f)
			{
				return f.Prefab;
			}

			internal string <Fish>b__3_1(BaitOption b)
			{
				return b.BaitName + " " + Labels.Odds(b.Chance);
			}
		}

		public static void Register()
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//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_0029: Expected O, but got Unknown
			object obj = <>c.<>9__0_0;
			if (obj == null)
			{
				ConsoleEvent val = delegate(ConsoleEventArgs args)
				{
					if (((args.Length > 1) ? args[1].ToLowerInvariant() : "") == "fish")
					{
						Fish(args.Context);
					}
					else
					{
						Status(args.Context);
					}
				};
				<>c.<>9__0_0 = val;
				obj = (object)val;
			}
			new ConsoleCommand("anglerseye", "Angler's Eye: feature and compat status (fish = bait table for every fish)", (ConsoleEvent)obj, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
		}

		internal static void Say(Terminal ctx, string line)
		{
			if ((Object)(object)ctx != (Object)null)
			{
				ctx.AddString(line);
			}
			AnglersEyePlugin.Log.LogInfo((object)line);
		}

		private static void Status(Terminal ctx)
		{
			try
			{
				Say(ctx, "Angler's Eye 0.1.0" + (PluginConfig.Enabled.Value ? "" : " (disabled)") + ": " + FishCatalog.All.Count + " fish known.");
				List<string> list = new List<string>();
				List<string> list2 = new List<string>();
				foreach (Feature value in Enum.GetValues(typeof(Feature)))
				{
					if (value != Feature.None)
					{
						(Features.On(value) ? list : list2).Add(CompatRules.Describe(value));
					}
				}
				Say(ctx, "Angler's Eye:   on: " + ((list.Count > 0) ? string.Join(", ", list) : "nothing"));
				Say(ctx, "Angler's Eye:   off: " + ((list2.Count > 0) ? string.Join(", ", list2) : "nothing"));
				if (Compat.Verdict == null)
				{
					Say(ctx, "Angler's Eye:   compat: not checked yet (load a world)");
					return;
				}
				if (Compat.Verdict.Reasons.Count == 0)
				{
					Say(ctx, "Angler's Eye:   compat: no other fishing mods found");
					return;
				}
				foreach (string reason in Compat.Verdict.Reasons)
				{
					Say(ctx, "Angler's Eye:   compat: " + reason);
				}
			}
			catch (Exception ex)
			{
				Say(ctx, "Angler's Eye: couldn't show status: " + ex.Message);
				AnglersEyePlugin.WarnOnce("anglerseye status", ex);
			}
		}

		private static void Fish(Terminal ctx)
		{
			try
			{
				RodParams rod = FishCatalog.Rod;
				Say(ctx, "Angler's Eye:   float: reel " + rod.PullStaminaUse + "/s x" + rod.PullStaminaUseMaxSkillMultiplier + " at max skill, speed " + rod.PullLineSpeed + "-" + rod.PullLineSpeedMaxSkill + " m/s, hooked drain " + rod.HookedStaminaPerSec + "-" + rod.HookedStaminaPerSecMaxSkill + "/s, range " + FishCatalog.FloatRange + "m");
				foreach (FishInfo item in FishCatalog.All.Values.OrderBy<FishInfo, string>((FishInfo f) => f.Prefab, StringComparer.Ordinal))
				{
					FishParams fishParams = item.Params;
					string text = ((item.Baits.Count == 0) ? "no bait" : string.Join(", ", item.Baits.Select((BaitOption b) => b.BaitName + " " + Labels.Odds(b.Chance))));
					Say(ctx, "Angler's Eye:   " + item.Prefab + " " + item.Name + ": " + text + " | stamina " + fishParams.StaminaUse + "/" + fishParams.EscapeStaminaUse + ", struggle " + fishParams.EscapeMin + "-" + fishParams.EscapeMax + " +" + fishParams.EscapeMaxPerLevel + "/level, pause " + fishParams.EscapeWaitMin + "-" + fishParams.EscapeWaitMax + "s");
				}
			}
			catch (Exception ex)
			{
				Say(ctx, "Angler's Eye: couldn't list fish: " + ex.Message);
				AnglersEyePlugin.WarnOnce("anglerseye fish", ex);
			}
		}
	}
	internal static class Features
	{
		public static bool On(Feature f)
		{
			if (PluginConfig.Enabled.Value && PluginConfig.Toggle(f))
			{
				return !Compat.IsOff(f);
			}
			return false;
		}
	}
	internal sealed class FishInfo
	{
		public string Prefab;

		public string NameToken;

		public List<BaitOption> Baits;

		public FishParams Params;

		public string Name
		{
			get
			{
				if (Localization.instance == null)
				{
					return NameToken;
				}
				return Localization.instance.Localize(NameToken);
			}
		}
	}
	internal static class FishCatalog
	{
		private static readonly Dictionary<string, FishInfo> ByPrefab = new Dictionary<string, FishInfo>();

		private static readonly HashSet<string> BaitAmmoTypes = new HashSet<string>();

		private static ZNetScene _builtFor;

		public static RodParams Rod = new RodParams();

		public static float FloatRange = 10f;

		public static float MaxDistance = 30f;

		public static IReadOnlyDictionary<string, FishInfo> All
		{
			get
			{
				EnsureBuilt();
				return ByPrefab;
			}
		}

		public static void EnsureBuilt()
		{
			ZNetScene instance = ZNetScene.instance;
			if ((Object)(object)instance == (Object)null || (Object)(object)instance == (Object)(object)_builtFor)
			{
				return;
			}
			ByPrefab.Clear();
			BaitAmmoTypes.Clear();
			foreach (GameObject prefab in instance.m_prefabs)
			{
				if (!((Object)(object)prefab == (Object)null))
				{
					Fish component = prefab.GetComponent<Fish>();
					if ((Object)(object)component != (Object)null)
					{
						ByPrefab[((Object)prefab).name] = Build(((Object)prefab).name, component);
					}
					FishingFloat component2 = prefab.GetComponent<FishingFloat>();
					if ((Object)(object)component2 != (Object)null)
					{
						ReadFloat(component2);
					}
				}
			}
			_builtFor = instance;
		}

		public static FishInfo For(Fish f)
		{
			EnsureBuilt();
			string prefabName = Utils.GetPrefabName(((Component)f).gameObject);
			if (!ByPrefab.TryGetValue(prefabName, out var value))
			{
				value = Build(prefabName, f);
				ByPrefab[prefabName] = value;
			}
			return value;
		}

		public static bool IsBaitAmmoType(string ammoType)
		{
			EnsureBuilt();
			if (!string.IsNullOrEmpty(ammoType))
			{
				return BaitAmmoTypes.Contains(ammoType);
			}
			return false;
		}

		public static int Quality(Fish f)
		{
			ItemDrop val = (((Object)(object)f.m_itemDrop != (Object)null) ? f.m_itemDrop : ((Component)f).GetComponent<ItemDrop>());
			if (!((Object)(object)val != (Object)null))
			{
				return 1;
			}
			return Math.Max(1, val.m_itemData.m_quality);
		}

		private static FishInfo Build(string prefab, Fish f)
		{
			List<BaitOption> list = new List<BaitOption>();
			foreach (BaitSetting bait in f.m_baits)
			{
				if (bait != null && !((Object)(object)bait.m_bait == (Object)null))
				{
					string name = bait.m_bait.m_itemData.m_shared.m_name;
					string baitName = ((Localization.instance != null) ? Localization.instance.Localize(name) : name);
					list.Add(new BaitOption(((Object)bait.m_bait).name, baitName, bait.m_chance));
					string ammoType = bait.m_bait.m_itemData.m_shared.m_ammoType;
					if (!string.IsNullOrEmpty(ammoType))
					{
						BaitAmmoTypes.Add(ammoType);
					}
				}
			}
			return new FishInfo
			{
				Prefab = prefab,
				NameToken = f.m_name,
				Baits = list,
				Params = new FishParams
				{
					StaminaUse = f.m_staminaUse,
					EscapeStaminaUse = f.m_escapeStaminaUse,
					EscapeMin = f.m_escapeMin,
					EscapeMax = f.m_escapeMax,
					EscapeMaxPerLevel = f.m_escapeMaxPerLevel,
					EscapeWaitMin = f.m_escapeWaitMin,
					EscapeWaitMax = f.m_escapeWaitMax
				}
			};
		}

		private static void ReadFloat(FishingFloat ff)
		{
			Rod = new RodParams
			{
				PullStaminaUse = ff.m_pullStaminaUse,
				PullStaminaUseMaxSkillMultiplier = ff.m_pullStaminaUseMaxSkillMultiplier,
				PullLineSpeed = ff.m_pullLineSpeed,
				PullLineSpeedMaxSkill = ff.m_pullLineSpeedMaxSkill,
				HookedStaminaPerSec = ff.m_hookedStaminaPerSec,
				HookedStaminaPerSecMaxSkill = ff.m_hookedStaminaPerSecMaxSkill
			};
			FloatRange = ff.m_range;
			MaxDistance = ff.m_maxDistance;
		}
	}
	internal sealed class FishingSnapshot
	{
		public Player Player;

		public ItemData Rod;

		public bool RodEquipped;

		public FishingFloat Float;

		public Fish Catch;

		public bool Escaping;

		public float RemainingEscape;

		public float EscapeTotal;

		public float LineLength;

		public Fish Subject;
	}
	internal static class FishingState
	{
		public static readonly FishingSnapshot Current = new FishingSnapshot();

		private const float NearbyRadius = 10f;

		private static readonly StruggleTracker Struggle = new StruggleTracker();

		public static bool IsLocal(FishingFloat ff)
		{
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || (Object)(object)ff == (Object)null || (Object)(object)ff.m_nview == (Object)null || !ff.m_nview.IsValid())
			{
				return false;
			}
			long num = ff.m_nview.GetZDO().GetLong(ZDOVars.s_rodOwner, 0L);
			ZDOID zDOID = ((Character)localPlayer).GetZDOID();
			return num == ((ZDOID)(ref zDOID)).UserID;
		}

		public static FishingFloat LocalFloat()
		{
			foreach (FishingFloat allInstance in FishingFloat.GetAllInstances())
			{
				if (IsLocal(allInstance))
				{
					return allInstance;
				}
			}
			return null;
		}

		public static void Refresh()
		{
			FishingSnapshot current = Current;
			Player val = (current.Player = Player.m_localPlayer);
			current.Rod = (((Object)(object)val != (Object)null) ? ((Humanoid)val).GetCurrentWeapon() : null);
			current.RodEquipped = Tackle.IsRod(current.Rod);
			current.Float = (((Object)(object)val != (Object)null) ? LocalFloat() : null);
			current.Catch = (((Object)(object)current.Float != (Object)null) ? current.Float.GetCatch() : null);
			current.Escaping = (Object)(object)current.Catch != (Object)null && current.Catch.IsEscaping();
			current.RemainingEscape = (((Object)(object)current.Catch != (Object)null) ? Mathf.Max(0f, current.Catch.m_escapeTime) : 0f);
			current.EscapeTotal = Struggle.Update((Object)(object)current.Catch != (Object)null, current.Escaping, current.RemainingEscape);
			current.LineLength = (((Object)(object)current.Float != (Object)null) ? current.Float.m_lineLength : 0f);
			current.Subject = (((Object)(object)current.Float != (Object)null && (Object)(object)current.Catch == (Object)null) ? SubjectFor(current.Float) : null);
		}

		private static Fish SubjectFor(FishingFloat ff)
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: 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)
			if ((Object)(object)ff.m_nibbler != (Object)null && Time.time - ff.m_nibbleTime < 2f)
			{
				return ff.m_nibbler;
			}
			Fish result = null;
			float num = Mathf.Min(ff.m_range, 10f);
			Vector3 position = ((Component)ff).transform.position;
			foreach (IMonoUpdater instance in Fish.Instances)
			{
				Fish val = (Fish)(object)((instance is Fish) ? instance : null);
				if (!((Object)(object)val == (Object)null) && !val.IsOutOfWater())
				{
					if ((Object)(object)val.m_waypointFF == (Object)(object)ff)
					{
						return val;
					}
					float num2 = Vector3.Distance(((Component)val).transform.position, position);
					if (num2 <= num)
					{
						num = num2;
						result = val;
					}
				}
			}
			return result;
		}
	}
	internal static class Runtime
	{
		private const float AimInterval = 0.25f;

		private static float _nextAim;

		private static FishSighting _aim;

		private static BaitAdvice _aimAdvice;

		public static void Tick()
		{
			try
			{
				FishCatalog.EnsureBuilt();
				Compat.EnsureEvaluated();
				FishingState.Refresh();
				UpdatePanel(FishingState.Current);
				FloatLabel.Update(FishingState.Current);
			}
			catch (Exception e)
			{
				AnglersEyePlugin.WarnOnce("Runtime.Tick", e);
				FishingPanel.Hide();
				FloatLabel.Hide();
			}
		}

		private static void UpdatePanel(FishingSnapshot s)
		{
			if (!PluginConfig.Enabled.Value || (Object)(object)s.Player == (Object)null || !s.RodEquipped)
			{
				FishingPanel.Hide();
				return;
			}
			if ((Object)(object)s.Catch != (Object)null)
			{
				Verdict? v = (Features.On(Feature.Forecast) ? new Verdict?(Forecast(s, s.Catch, hooked: true)) : ((Verdict?)null));
				FishingPanel.Show(PanelView.Hooked(FishCatalog.For(s.Catch).Name, FishCatalog.Quality(s.Catch), s.Escaping, Features.On(Feature.StruggleIndicator), s.RemainingEscape, s.EscapeTotal, v));
				return;
			}
			if ((Object)(object)s.Float != (Object)null && BiteCue.Active)
			{
				FishingPanel.Show(((Object)(object)s.Subject != (Object)null) ? PanelView.Bite(FishCatalog.For(s.Subject).Name, FishCatalog.Quality(s.Subject)) : PanelView.Bite(null, 0));
				return;
			}
			if ((Object)(object)s.Float != (Object)null)
			{
				if (!Features.On(Feature.Forecast) && !Features.On(Feature.FloatLabel))
				{
					FishingPanel.Hide();
					return;
				}
				if ((Object)(object)s.Subject == (Object)null)
				{
					FishingPanel.Show(PanelView.Waiting(null, 0, null));
					return;
				}
				Verdict? v2 = (Features.On(Feature.Forecast) ? new Verdict?(Forecast(s, s.Subject, hooked: false)) : ((Verdict?)null));
				FishingPanel.Show(PanelView.Waiting(FishCatalog.For(s.Subject).Name, FishCatalog.Quality(s.Subject), v2));
				return;
			}
			if (!Features.On(Feature.SmartBait))
			{
				FishingPanel.Hide();
				return;
			}
			if (Time.time >= _nextAim)
			{
				_nextAim = Time.time + 0.25f;
				_aim = Targeting.Aim(s.Player);
				_aimAdvice = ((_aim != null && FishCatalog.All.TryGetValue(_aim.Species, out var value)) ? Tackle.Advise(s.Player, value) : null);
			}
			if (_aim == null || !FishCatalog.All.TryGetValue(_aim.Species, out var value2))
			{
				FishingPanel.Hide();
			}
			else
			{
				FishingPanel.Show(PanelView.Target(value2.Name, _aim.Quality, _aimAdvice, PluginConfig.ShowOdds.Value));
			}
		}

		private static Verdict Forecast(FishingSnapshot s, Fish f, bool hooked)
		{
			FishInfo fishInfo = FishCatalog.For(f);
			return CatchForecast.Estimate(FishCatalog.Rod, fishInfo.Params, FishCatalog.Quality(f), s.LineLength, ((Character)s.Player).GetSkillFactor((SkillType)104), s.Player.GetStamina(), hooked, hooked ? s.RemainingEscape : 0f).Verdict;
		}
	}
	internal static class SmartBait
	{
		private const float RepeatMessageAfter = 15f;

		private static string _lastMessageText;

		private static float _lastMessageTime = -15f;

		public static void BeforeCast(Humanoid character, ItemData weapon)
		{
			Player val = (Player)(object)((character is Player) ? character : null);
			if ((Object)(object)val == (Object)null || (Object)(object)val != (Object)(object)Player.m_localPlayer || !Features.On(Feature.SmartBait) || !Tackle.IsRod(weapon))
			{
				return;
			}
			FishSighting fishSighting = Targeting.Aim(val);
			if (fishSighting == null || !FishCatalog.All.TryGetValue(fishSighting.Species, out var value))
			{
				return;
			}
			BaitAdvice baitAdvice = Tackle.Advise(val, value);
			if (baitAdvice == null)
			{
				return;
			}
			if (!baitAdvice.Carried)
			{
				string text = Labels.NeedsBait(value.Name, baitAdvice.Best.BaitName);
				if (text != _lastMessageText || Time.time - _lastMessageTime > 15f)
				{
					_lastMessageText = text;
					_lastMessageTime = Time.time;
					((Character)val).Message((MessageType)2, text, 0, (Sprite)null, false);
				}
				return;
			}
			string ammoType = weapon.m_shared.m_ammoType;
			ItemData val2 = VanillaChoice(val, ammoType);
			if (val2 != null && (Object)(object)val2.m_dropPrefab != (Object)null && ((Object)val2.m_dropPrefab).name == baitAdvice.Best.BaitId)
			{
				return;
			}
			ItemData ammoItem = ((Humanoid)val).GetInventory().GetAmmoItem(ammoType, baitAdvice.Best.BaitId);
			if (ammoItem != null)
			{
				bool flag = ((Humanoid)val).EquipItem(ammoItem, false);
				if (PluginConfig.Verbose.Value)
				{
					AnglersEyePlugin.Log.LogInfo((object)("Angler's Eye: smart bait " + value.Prefab + " -> " + baitAdvice.Best.BaitId + (flag ? "" : " (equip refused)")));
				}
			}
		}

		private static ItemData VanillaChoice(Player p, string type)
		{
			ItemData ammoItem = ((Humanoid)p).GetAmmoItem();
			if (ammoItem != null && ((Humanoid)p).GetInventory().ContainsItem(ammoItem) && ammoItem.m_shared.m_ammoType == type)
			{
				return ammoItem;
			}
			return ((Humanoid)p).GetInventory().GetAmmoItem(type, (string)null);
		}
	}
	internal static class Tackle
	{
		private static readonly Dictionary<string, int> _carried = new Dictionary<string, int>();

		private static int _carriedFrame = -1;

		private static Player _carriedFor;

		public static bool IsRod(ItemData w)
		{
			if (w != null)
			{
				return FishCatalog.IsBaitAmmoType(w.m_shared.m_ammoType);
			}
			return false;
		}

		public static IReadOnlyDictionary<string, int> Carried(Player p)
		{
			if (_carriedFrame == Time.frameCount && (Object)(object)_carriedFor == (Object)(object)p)
			{
				return _carried;
			}
			_carried.Clear();
			foreach (ItemData allItem in ((Humanoid)p).GetInventory().GetAllItems())
			{
				if (!((Object)(object)allItem.m_dropPrefab == (Object)null))
				{
					_carried.TryGetValue(((Object)allItem.m_dropPrefab).name, out var value);
					_carried[((Object)allItem.m_dropPrefab).name] = value + allItem.m_stack;
				}
			}
			_carriedFrame = Time.frameCount;
			_carriedFor = p;
			return _carried;
		}

		public static BaitAdvice Advise(Player p, FishInfo info)
		{
			if (info != null)
			{
				return BaitAdvisor.Advise(info.Baits, Carried(p));
			}
			return null;
		}
	}
	internal static class Targeting
	{
		private static readonly List<FishSighting> Buffer = new List<FishSighting>();

		public static FishSighting Aim(Player p)
		{
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			GameCamera instance = GameCamera.instance;
			if ((Object)(object)p == (Object)null || (Object)(object)instance == (Object)null)
			{
				return null;
			}
			FishSighting crosshair = null;
			GameObject hoverObject = ((Humanoid)p).GetHoverObject();
			Fish val = (((Object)(object)hoverObject != (Object)null) ? hoverObject.GetComponentInParent<Fish>() : null);
			if ((Object)(object)val != (Object)null && !val.IsOutOfWater())
			{
				crosshair = Sight(val);
			}
			Buffer.Clear();
			foreach (IMonoUpdater instance2 in Fish.Instances)
			{
				Fish val2 = (Fish)(object)((instance2 is Fish) ? instance2 : null);
				if (!((Object)(object)val2 == (Object)null) && !val2.IsOutOfWater() && !val2.IsHooked())
				{
					Buffer.Add(Sight(val2));
				}
			}
			Transform transform = ((Component)instance).transform;
			return TargetPicker.Pick(crosshair, V(transform.position), V(transform.forward), PluginConfig.AimConeDegrees.Value, FishCatalog.MaxDistance, Buffer);
		}

		public static FishSighting Sight(Fish f)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			return new FishSighting(Utils.GetPrefabName(((Component)f).gameObject), FishCatalog.Quality(f), V(((Component)f).transform.position));
		}

		private static Vec3 V(Vector3 v)
		{
			//IL_0000: 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_000c: Unknown result type (might be due to invalid IL or missing references)
			return new Vec3(v.x, v.y, v.z);
		}
	}
}
namespace AnglersEye.Core.Model
{
	public sealed class BaitOption
	{
		public readonly string BaitId;

		public readonly string BaitName;

		public readonly float Chance;

		public BaitOption(string baitId, string baitName, float chance)
		{
			BaitId = baitId;
			BaitName = baitName;
			Chance = chance;
		}
	}
	public sealed class BaitAdvice
	{
		public BaitOption Best;

		public bool Carried;

		public int CarriedCount;
	}
	public static class BaitAdvisor
	{
		public static BaitAdvice Advise(IReadOnlyList<BaitOption> table, IReadOnlyDictionary<string, int> carried)
		{
			List<BaitOption> list = Merge(table);
			if (list.Count == 0)
			{
				return null;
			}
			list.Sort(delegate(BaitOption a, BaitOption b)
			{
				if (a.Chance == b.Chance)
				{
					return string.CompareOrdinal(a.BaitId, b.BaitId);
				}
				float chance = b.Chance;
				return chance.CompareTo(a.Chance);
			});
			BaitOption baitOption = null;
			int num = 0;
			foreach (BaitOption item in list)
			{
				if (carried != null && carried.TryGetValue(item.BaitId, out var value) && value > 0 && (baitOption == null || item.Chance > baitOption.Chance || (item.Chance == baitOption.Chance && value > num)))
				{
					baitOption = item;
					num = value;
				}
			}
			if (baitOption != null)
			{
				return new BaitAdvice
				{
					Best = baitOption,
					Carried = true,
					CarriedCount = num
				};
			}
			return new BaitAdvice
			{
				Best = list[0],
				Carried = false,
				CarriedCount = 0
			};
		}

		private static List<BaitOption> Merge(IReadOnlyList<BaitOption> table)
		{
			List<BaitOption> list = new List<BaitOption>();
			if (table == null)
			{
				return list;
			}
			Dictionary<string, int> dictionary = new Dictionary<string, int>();
			foreach (BaitOption item in table)
			{
				if (item != null && !string.IsNullOrEmpty(item.BaitId))
				{
					if (dictionary.TryGetValue(item.BaitId, out var value))
					{
						BaitOption baitOption = list[value];
						list[value] = new BaitOption(baitOption.BaitId, baitOption.BaitName, 1f - (1f - baitOption.Chance) * (1f - item.Chance));
					}
					else
					{
						dictionary[item.BaitId] = list.Count;
						list.Add(item);
					}
				}
			}
			return list;
		}
	}
	public sealed class RodParams
	{
		public float PullStaminaUse = 10f;

		public float PullStaminaUseMaxSkillMultiplier = 0.2f;

		public float PullLineSpeed = 1f;

		public float PullLineSpeedMaxSkill = 2f;

		public float HookedStaminaPerSec = 1f;

		public float HookedStaminaPerSecMaxSkill = 0.2f;
	}
	public sealed class FishParams
	{
		public float StaminaUse = 1f;

		public float EscapeStaminaUse = 2f;

		public float EscapeMin = 0.5f;

		public float EscapeMax = 3f;

		public float EscapeMaxPerLevel = 1.5f;

		public float EscapeWaitMin = 0.75f;

		public float EscapeWaitMax = 4f;
	}
	public enum Verdict
	{
		Likely,
		Tight,
		Unlikely
	}
	public struct Forecast
	{
		public readonly float Cost;

		public readonly Verdict Verdict;

		public Forecast(float cost, Verdict verdict)
		{
			Cost = cost;
			Verdict = verdict;
		}
	}
	public static class CatchForecast
	{
		public const float LandedAt = 0.5f;

		public const float Margin = 1.25f;

		public static Forecast Estimate(RodParams rod, FishParams fish, int quality, float lineLength, float skillFactor, float stamina, bool hooked, float remainingEscape)
		{
			float t = Math.Min(1f, Math.Max(0f, skillFactor));
			int num = Math.Max(1, quality);
			float val = Lerp(rod.PullLineSpeed, rod.PullLineSpeedMaxSkill, t);
			float num2 = Math.Max(0f, lineLength - 0.5f) / Math.Max(0.0001f, val);
			float num3 = Math.Max(0f, (fish.EscapeMin + fish.EscapeMax + (float)num * fish.EscapeMaxPerLevel) / 2f);
			float num4 = (fish.EscapeWaitMin + fish.EscapeWaitMax) / 2f;
			float num5 = (hooked ? Math.Max(0f, remainingEscape) : num3);
			if (num2 > 0f)
			{
				if (num4 <= 0f)
				{
					return new Forecast(float.PositiveInfinity, Verdict.Unlikely);
				}
				float num6 = num4 / (num4 + num3);
				num5 += num2 / num6;
			}
			float num7 = rod.PullStaminaUse + fish.StaminaUse * (float)num;
			float num8 = Lerp(num7, num7 * rod.PullStaminaUseMaxSkillMultiplier, t) * num2;
			float num9 = Lerp(rod.HookedStaminaPerSec, rod.HookedStaminaPerSecMaxSkill, t) * num5;
			float cost = num8 + num9;
			return new Forecast(cost, Judge(cost, stamina));
		}

		public static Verdict Judge(float cost, float stamina)
		{
			if (stamina >= cost * 1.25f)
			{
				return Verdict.Likely;
			}
			if (!(stamina >= cost))
			{
				return Verdict.Unlikely;
			}
			return Verdict.Tight;
		}

		private static float Lerp(float a, float b, float t)
		{
			return a + (b - a) * t;
		}
	}
	[Flags]
	public enum Feature
	{
		None = 0,
		HoverInfo = 1,
		FloatLabel = 2,
		SmartBait = 4,
		BiteCue = 8,
		StruggleIndicator = 0x10,
		Forecast = 0x20,
		SmartReel = 0x40,
		HookWindow = 0x80
	}
	public sealed class CompatVerdict
	{
		public Feature Disabled;

		public readonly List<string> Reasons = new List<string>();

		public bool IsOff(Feature f)
		{
			return (Disabled & f) != 0;
		}
	}
	public static class CompatRules
	{
		public const string Hooked = "Azumatt.Hooked";

		public const string TrollingFishing = "sighsorry.TrollingFishing";

		public const string FixedUpdate = "FishingFloat.FixedUpdate";

		public const string TryToHook = "FishingFloat.TryToHook";

		public const string GetStaminaUse = "Fish.GetStaminaUse";

		private static readonly KeyValuePair<Feature, string>[] Names = new KeyValuePair<Feature, string>[8]
		{
			new KeyValuePair<Feature, string>(Feature.HoverInfo, "hover info"),
			new KeyValuePair<Feature, string>(Feature.FloatLabel, "float label"),
			new KeyValuePair<Feature, string>(Feature.SmartBait, "smart bait"),
			new KeyValuePair<Feature, string>(Feature.BiteCue, "bite cue"),
			new KeyValuePair<Feature, string>(Feature.StruggleIndicator, "struggle indicator"),
			new KeyValuePair<Feature, string>(Feature.Forecast, "forecast"),
			new KeyValuePair<Feature, string>(Feature.SmartReel, "smart reel"),
			new KeyValuePair<Feature, string>(Feature.HookWindow, "extended hook window")
		};

		public static CompatVerdict Evaluate(ICollection<string> pluginGuids, IDictionary<string, IList<string>> foreignPatchOwners)
		{
			CompatVerdict compatVerdict = new CompatVerdict();
			if (pluginGuids.Contains("Azumatt.Hooked"))
			{
				Off(compatVerdict, Feature.SmartBait | Feature.BiteCue | Feature.StruggleIndicator | Feature.Forecast | Feature.SmartReel | Feature.HookWindow, "Hooked (Azumatt.Hooked)");
			}
			if (pluginGuids.Contains("sighsorry.TrollingFishing"))
			{
				Off(compatVerdict, Feature.SmartBait | Feature.Forecast | Feature.SmartReel | Feature.HookWindow, "Trolling Fishing (sighsorry.TrollingFishing)");
			}
			Patched(compatVerdict, foreignPatchOwners, "FishingFloat.FixedUpdate", Feature.SmartReel);
			Patched(compatVerdict, foreignPatchOwners, "FishingFloat.TryToHook", Feature.HookWindow);
			Patched(compatVerdict, foreignPatchOwners, "Fish.GetStaminaUse", Feature.Forecast);
			return compatVerdict;
		}

		public static string Describe(Feature f)
		{
			List<string> list = new List<string>();
			KeyValuePair<Feature, string>[] names = Names;
			for (int i = 0; i < names.Length; i++)
			{
				KeyValuePair<Feature, string> keyValuePair = names[i];
				if ((f & keyValuePair.Key) != Feature.None)
				{
					list.Add(keyValuePair.Value);
				}
			}
			return string.Join(", ", list);
		}

		private static void Patched(CompatVerdict v, IDictionary<string, IList<string>> owners, string method, Feature f)
		{
			if (owners != null && owners.TryGetValue(method, out var value) && value != null && value.Count > 0)
			{
				Off(v, f, string.Join(", ", value) + " patches " + method);
			}
		}

		private static void Off(CompatVerdict v, Feature f, string who)
		{
			v.Disabled |= f;
			v.Reasons.Add(who + ": " + Describe(f) + " off");
		}
	}
	public sealed class Glyphs
	{
		public string Star;

		public string Yes;

		public string No;

		public string Sep;

		public static Glyphs Unicode()
		{
			return new Glyphs
			{
				Star = "★",
				Yes = "✔",
				No = "✖",
				Sep = "·"
			};
		}

		public static Glyphs Ascii()
		{
			return new Glyphs
			{
				Star = "*",
				Yes = "+",
				No = "x",
				Sep = "-"
			};
		}

		public static Glyphs Resolve(Func<char, bool> hasChar)
		{
			Glyphs glyphs = Unicode();
			Glyphs glyphs2 = Ascii();
			return new Glyphs
			{
				Star = Pick(glyphs.Star, glyphs2.Star, hasChar),
				Yes = Pick(glyphs.Yes, glyphs2.Yes, hasChar),
				No = Pick(glyphs.No, glyphs2.No, hasChar),
				Sep = Pick(glyphs.Sep, glyphs2.Sep, hasChar)
			};
		}

		private static string Pick(string unicode, string ascii, Func<char, bool> hasChar)
		{
			foreach (char arg in unicode)
			{
				if (!hasChar(arg))
				{
					return ascii;
				}
			}
			return unicode;
		}
	}
	public static class Labels
	{
		public static string Stars(int quality, Glyphs g)
		{
			if (quality <= 1)
			{
				return "";
			}
			StringBuilder stringBuilder = new StringBuilder();
			for (int i = 1; i < quality; i++)
			{
				stringBuilder.Append(g.Star);
			}
			return stringBuilder.ToString();
		}

		public static string Level(int quality)
		{
			if (quality <= 1)
			{
				return "";
			}
			return "Lv " + quality;
		}

		public static string Odds(float chance)
		{
			return (int)Math.Round(chance * 100f) + "%";
		}

		public static string Bait(BaitAdvice a, Glyphs g, bool showOdds)
		{
			string text = a.Best.BaitName + (showOdds ? (" " + Odds(a.Best.Chance)) : "");
			if (!a.Carried)
			{
				return text + " " + g.No;
			}
			return text + " " + g.Yes + " (x" + a.CarriedCount + ")";
		}

		public static string HoverSuffix(int quality, BaitAdvice a, Glyphs g, bool showOdds)
		{
			string text = ((quality > 1) ? (" " + Stars(quality, g)) : "");
			if (a != null)
			{
				text = text + "\nBait: " + Bait(a, g, showOdds);
			}
			return text;
		}

		public static string OnFloat(bool baitWorks, string neededBait, Glyphs g)
		{
			return " " + g.Sep + (baitWorks ? " bait ok" : (" needs " + neededBait));
		}

		public static string NeedsBait(string fish, string bait)
		{
			return "Angler's Eye: " + fish + " needs " + bait;
		}
	}
	public enum Tone
	{
		Normal,
		Good,
		Warn,
		Bad,
		Bite
	}
	public sealed class PanelView
	{
		public const string WaitingText = "Waiting…";

		public readonly string Title;

		public readonly int Level;

		public readonly string Body;

		public readonly Tone BodyTone;

		public readonly bool BodyIsBig;

		public readonly float? Bar;

		public readonly string Forecast;

		public readonly Tone ForecastTone;

		private PanelView(string title, int level, string body, Tone bodyTone, bool bodyIsBig, float? bar, Verdict? v)
		{
			Title = title;
			Level = level;
			Body = body;
			BodyTone = bodyTone;
			BodyIsBig = bodyIsBig;
			Bar = bar;
			Forecast = (v.HasValue ? WordFor(v.Value) : null);
			ForecastTone = (v.HasValue ? ToneFor(v.Value) : Tone.Normal);
		}

		public static PanelView Target(string name, int quality, BaitAdvice a, bool showOdds)
		{
			if (a == null)
			{
				return new PanelView(name, quality, null, Tone.Normal, bodyIsBig: false, null, null);
			}
			string text = a.Best.BaitName + (showOdds ? (" " + Labels.Odds(a.Best.Chance)) : "");
			if (!a.Carried)
			{
				return new PanelView(name, quality, "needs " + text, Tone.Bad, bodyIsBig: false, null, null);
			}
			return new PanelView(name, quality, text + " (" + a.CarriedCount + ")", Tone.Normal, bodyIsBig: false, null, null);
		}

		public static PanelView Waiting(string name, int quality, Verdict? v)
		{
			if (name == null)
			{
				return new PanelView("Waiting…", 0, null, Tone.Normal, bodyIsBig: false, null, null);
			}
			return new PanelView(name, quality, "Waiting…", Tone.Normal, bodyIsBig: false, null, v);
		}

		public static PanelView Bite(string name, int quality)
		{
			return new PanelView(name, (name != null) ? quality : 0, "BITE!", Tone.Bite, bodyIsBig: true, null, null);
		}

		public static PanelView Hooked(string name, int quality, bool struggling, bool showStruggle, float remainingEscape, float escapeTotal, Verdict? v)
		{
			if (!showStruggle)
			{
				if (!v.HasValue)
				{
					return null;
				}
				return new PanelView(name, quality, null, Tone.Normal, bodyIsBig: false, null, v);
			}
			if (struggling)
			{
				return new PanelView(name, quality, "WAIT", Tone.Warn, bodyIsBig: true, StruggleFraction(remainingEscape, escapeTotal), v);
			}
			return new PanelView(name, quality, "REEL", Tone.Good, bodyIsBig: true, null, v);
		}

		public static float StruggleFraction(float remaining, float total)
		{
			if (total <= 0f)
			{
				return 0f;
			}
			return Math.Min(1f, Math.Max(0f, remaining / total));
		}

		public static string WordFor(Verdict v)
		{
			return v switch
			{
				Verdict.Likely => "can land", 
				Verdict.Tight => "tight", 
				_ => "unlikely", 
			};
		}

		public static Tone ToneFor(Verdict v)
		{
			return v switch
			{
				Verdict.Likely => Tone.Good, 
				Verdict.Tight => Tone.Warn, 
				_ => Tone.Bad, 
			};
		}
	}
	public static class ReelPolicy
	{
		public const float VanillaHookWindow = 0.5f;

		public const float MaxHookWindow = 1.5f;

		public static bool SuppressReel(bool smartReel, bool hooked, bool escaping)
		{
			return smartReel && hooked && escaping;
		}

		public static float HookWindow(bool extended, float seconds)
		{
			if (!extended)
			{
				return 0.5f;
			}
			return Math.Min(1.5f, Math.Max(0.5f, seconds));
		}

		public static bool InHookWindow(float now, float nibbleTime, float window)
		{
			return now - nibbleTime < window;
		}
	}
	public sealed class StruggleTracker
	{
		private bool _wasEscaping;

		private float _lastRemaining;

		public float Total { get; private set; }

		public float Update(bool hasCatch, bool escaping, float remaining)
		{
			if (!hasCatch)
			{
				Total = 0f;
				_wasEscaping = false;
				_lastRemaining = 0f;
				return Total;
			}
			if (escaping && (!_wasEscaping || remaining > _lastRemaining))
			{
				Total = remaining;
			}
			_wasEscaping = escaping;
			_lastRemaining = remaining;
			return Total;
		}
	}
	public sealed class FishSighting
	{
		public readonly string Species;

		public readonly int Quality;

		public readonly Vec3 Position;

		public FishSighting(string species, int quality, Vec3 position)
		{
			Species = species;
			Quality = quality;
			Position = position;
		}
	}
	public static class TargetPicker
	{
		public static FishSighting Pick(FishSighting crosshair, Vec3 origin, Vec3 aim, float coneDegrees, float range, IReadOnlyList<FishSighting> fish)
		{
			if (crosshair != null)
			{
				return crosshair;
			}
			if (fish == null || fish.Count == 0)
			{
				return null;
			}
			return InCone(origin, aim, coneDegrees, range, fish) ?? MostCommon(origin, range, fish);
		}

		private static FishSighting InCone(Vec3 origin, Vec3 aim, float coneDegrees, float range, IReadOnlyList<FishSighting> fish)
		{
			float num = (float)Math.Sqrt(aim.X * aim.X + aim.Z * aim.Z);
			if (num < 0.0001f)
			{
				return null;
			}
			double num2 = Math.Cos((double)coneDegrees * Math.PI / 180.0);
			FishSighting result = null;
			float num3 = float.MaxValue;
			foreach (FishSighting item in fish)
			{
				Vec3 vec = item.Position - origin;
				float length = vec.Length;
				if (!(length > range))
				{
					float lengthXZ = vec.LengthXZ;
					if (((lengthXZ < 0.0001f) ? 1.0 : ((double)((vec.X * aim.X + vec.Z * aim.Z) / (lengthXZ * num)))) >= num2 && length < num3)
					{
						result = item;
						num3 = length;
					}
				}
			}
			return result;
		}

		private static FishSighting MostCommon(Vec3 origin, float range, IReadOnlyList<FishSighting> fish)
		{
			Dictionary<string, int> dictionary = new Dictionary<string, int>();
			Dictionary<string, FishSighting> dictionary2 = new Dictionary<string, FishSighting>();
			Dictionary<string, float> dictionary3 = new Dictionary<string, float>();
			foreach (FishSighting item in fish)
			{
				float length = (item.Position - origin).Length;
				if (!(length > range))
				{
					dictionary.TryGetValue(item.Species, out var value);
					dictionary[item.Species] = value + 1;
					if (!dictionary3.TryGetValue(item.Species, out var value2) || length < value2)
					{
						dictionary3[item.Species] = length;
						dictionary2[item.Species] = item;
					}
				}
			}
			FishSighting fishSighting = null;
			int num = 0;
			float num2 = 0f;
			foreach (KeyValuePair<string, int> item2 in dictionary)
			{
				float num3 = dictionary3[item2.Key];
				if (fishSighting == null || item2.Value > num || (item2.Value == num && num3 < num2))
				{
					fishSighting = dictionary2[item2.Key];
					num = item2.Value;
					num2 = num3;
				}
			}
			return fishSighting;
		}
	}
	public struct Vec3
	{
		public readonly float X;

		public readonly float Y;

		public readonly float Z;

		public float Length => (float)Math.Sqrt(X * X + Y * Y + Z * Z);

		public float LengthXZ => (float)Math.Sqrt(X * X + Z * Z);

		public Vec3(float x, float y, float z)
		{
			X = x;
			Y = y;
			Z = z;
		}

		public static Vec3 operator -(Vec3 a, Vec3 b)
		{
			return new Vec3(a.X - b.X, a.Y - b.Y, a.Z - b.Z);
		}
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}