Decompiled source of AchievementProgress v1.1.1

plugins\AchievementProgress.dll

Decompiled 2 weeks 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 AchievementProgress.Config;
using AchievementProgress.Core;
using AchievementProgress.UI;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")]
[assembly: AssemblyCompany("AchievementProgress")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.1.1.0")]
[assembly: AssemblyInformationalVersion("1.1.1")]
[assembly: AssemblyProduct("Valheim Achievement Progress")]
[assembly: AssemblyTitle("AchievementProgress")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.1.1.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace AchievementProgress
{
	[BepInPlugin("com.pedro.achievementprogress", "AchievementProgress", "1.1.1")]
	public class Plugin : BaseUnityPlugin
	{
		public const string PluginGUID = "com.pedro.achievementprogress";

		public const string PluginName = "AchievementProgress";

		public const string PluginVersion = "1.0.0";

		internal static ManualLogSource Logger;

		private Harmony _harmony;

		private void Awake()
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Expected O, but got Unknown
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Expected O, but got Unknown
			Logger = ((BaseUnityPlugin)this).Logger;
			ModConfig.Bind(((BaseUnityPlugin)this).Config);
			if (!ModConfig.Enabled.Value)
			{
				Logger.LogInfo((object)"[AchievementProgress] Deshabilitado en config.");
				return;
			}
			GameObject val = new GameObject("AchievementProgressManager");
			Object.DontDestroyOnLoad((Object)val);
			val.AddComponent<ProgressWatcher>();
			val.AddComponent<AchievementTracker>();
			_harmony = new Harmony("com.pedro.achievementprogress");
			_harmony.PatchAll();
			Logger.LogInfo((object)"[AchievementProgress] v1.1.1 cargado (solo cliente).");
		}

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

		public static void LogInfo(string message)
		{
			ManualLogSource logger = Logger;
			if (logger != null)
			{
				logger.LogInfo((object)message);
			}
		}

		public static void LogDebug(string message)
		{
			if (Logger != null && ModConfig.EnableDebugLogs != null && ModConfig.EnableDebugLogs.Value)
			{
				Logger.LogInfo((object)("[DEBUG] " + message));
			}
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "com.pedro.achievementprogress";

		public const string PLUGIN_NAME = "AchievementProgress";

		public const string PLUGIN_VERSION = "1.1.1";
	}
}
namespace AchievementProgress.UI
{
	public sealed class AchievementTracker : MonoBehaviour
	{
		private struct PinBlock
		{
			public string Id;

			public string Header;

			public string Goals;
		}

		private const int MaxGoalRowsPerPin = 8;

		private const float RowIconSize = 32f;

		private const float HeaderBtn = 22f;

		private const float UnpinSize = 22f;

		private const float MaxPanelHeight = 420f;

		private GUIStyle _panelStyle;

		private GUIStyle _innerStyle;

		private GUIStyle _titleStyle;

		private GUIStyle _labelStyle;

		private GUIStyle _hintStyle;

		private GUIStyle _buttonStyle;

		private GUIStyle _iconButtonStyle;

		private GUIStyle _unpinButtonStyle;

		private GUIStyle _pickerRowStyle;

		private Texture2D _panelBg;

		private Texture2D _innerBg;

		private Texture2D _accentBg;

		private Texture2D _buttonBg;

		private Texture2D _buttonHoverBg;

		private Texture2D _dangerBg;

		private Texture2D _rowBg;

		private Texture2D _rowAltBg;

		private string _cachedBody = "";

		private float _nextRefresh;

		private bool _dragging;

		private bool _dragMoved;

		private Vector2 _dragOffset;

		private float _runtimePosX;

		private float _runtimePosY;

		private bool _hasRuntimePos;

		private bool _pickerOpen;

		private Vector2 _pickerScroll;

		private Vector2 _bodyScroll;

		private string _statusMessage = "";

		private float _statusExpire;

		private readonly List<IncompleteGoal> _goalBuffer = new List<IncompleteGoal>(16);

		private readonly List<TrackedAchievement> _pickerList = new List<TrackedAchievement>(128);

		private readonly List<PinBlock> _pinBlocks = new List<PinBlock>(3);

		private void Update()
		{
			if (!ModConfig.Enabled.Value || !ModConfig.EnableDirectionalIndicator.Value)
			{
				_cachedBody = "";
				_pinBlocks.Clear();
				return;
			}
			if ((Object)(object)Player.m_localPlayer == (Object)null || !AchievementCatalog.IsReady)
			{
				_cachedBody = "";
				_pinBlocks.Clear();
				return;
			}
			if ((Object)(object)Hud.instance != (Object)null && Hud.instance.m_userHidden)
			{
				_cachedBody = "";
				return;
			}
			float num = (IsPauseMenuVisible() ? 0.12f : 0.35f);
			if (!(Time.unscaledTime < _nextRefresh))
			{
				_nextRefresh = Time.unscaledTime + num;
				PinnedAchievements.PruneInvalid();
				RebuildPinBlocks();
			}
		}

		private void OnGUI()
		{
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Invalid comparison between Unknown and I4
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Invalid comparison between Unknown and I4
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bd: 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_02b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_034a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0340: Unknown result type (might be due to invalid IL or missing references)
			//IL_035f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0364: Unknown result type (might be due to invalid IL or missing references)
			//IL_046d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0386: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_041b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0400: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d9: Unknown result type (might be due to invalid IL or missing references)
			if (!ModConfig.Enabled.Value || !ModConfig.EnableDirectionalIndicator.Value || (Object)(object)Player.m_localPlayer == (Object)null)
			{
				return;
			}
			bool flag = IsPauseMenuVisible();
			if (ModConfig.IndicatorAutoHideOverlays.Value && IsBlockingGameUiVisible(excludePauseMenu: true))
			{
				_pickerOpen = false;
				return;
			}
			if (!flag)
			{
				_pickerOpen = false;
			}
			if (PinnedAchievements.Ids.Count <= 0 && !flag)
			{
				return;
			}
			Event current = Event.current;
			if (!flag && (int)current.type != 7 && (int)current.type != 8)
			{
				return;
			}
			EnsureStyles();
			float value = ModConfig.IndicatorWidth.Value;
			float num = (_pickerOpen ? 420f : Mathf.Clamp(EstimateContentHeight(flag, value), 72f, 420f));
			ResolvePosition(value, num, out var posX, out var posY);
			float num2 = (flag ? 34f : 0f);
			Rect val = default(Rect);
			Rect val2 = default(Rect);
			Rect val3 = default(Rect);
			if (flag)
			{
				float num3 = posY + num - 22f - 6f;
				((Rect)(ref val))..ctor(posX + 10f, num3, 22f, 22f);
				if (_pickerOpen)
				{
					((Rect)(ref val3))..ctor(posX + 10f + 22f + 6f, num3, 72f, 22f);
					((Rect)(ref val2))..ctor(posX + 10f + 22f + 84f, num3, value - 22f - 100f, 22f);
				}
				else
				{
					((Rect)(ref val2))..ctor(posX + 10f + 22f + 6f, num3, value - 22f - 22f, 22f);
				}
			}
			HandleDragging(flag, ref posX, ref posY, value, num, val, val2, val3);
			if (flag)
			{
				float num4 = posY + num - 22f - 6f;
				((Rect)(ref val))..ctor(posX + 10f, num4, 22f, 22f);
				if (_pickerOpen)
				{
					((Rect)(ref val3))..ctor(posX + 10f + 22f + 6f, num4, 72f, 22f);
					((Rect)(ref val2))..ctor(posX + 10f + 22f + 84f, num4, value - 22f - 100f, 22f);
				}
				else
				{
					((Rect)(ref val2))..ctor(posX + 10f + 22f + 6f, num4, value - 22f - 22f, 22f);
				}
			}
			Rect rect = default(Rect);
			((Rect)(ref rect))..ctor(posX, posY, value, num);
			DrawPanel(rect);
			GUI.Label(new Rect(posX + 12f, posY + 8f, value - 24f, 18f), _pickerOpen ? "<b>Elegir logro</b>" : "<b>Seguimiento</b>", _titleStyle);
			GUI.DrawTexture(new Rect(posX + 10f, posY + 28f, value - 20f, 2f), (Texture)(object)_accentBg);
			Rect contentRect = default(Rect);
			((Rect)(ref contentRect))..ctor(posX + 8f, posY + 36f, value - 16f, num - 36f - num2 - 8f);
			if (_pickerOpen && flag)
			{
				DrawPickerInside(contentRect);
			}
			else
			{
				DrawPinnedContent(contentRect, flag);
			}
			if (flag)
			{
				bool flag2 = PinnedAchievements.CanPinMore();
				Color color = GUI.color;
				if (!flag2 && !_pickerOpen)
				{
					GUI.color = new Color(1f, 1f, 1f, 0.4f);
				}
				string text = (_pickerOpen ? "←" : "+");
				if (GUI.Button(val, text, _iconButtonStyle))
				{
					if (_pickerOpen)
					{
						_pickerOpen = false;
					}
					else if (flag2)
					{
						_pickerOpen = true;
						_pickerScroll = Vector2.zero;
						RebuildPickerList();
					}
					else
					{
						ShowStatus("Máximo 3 logros");
					}
				}
				GUI.color = color;
				if (_pickerOpen && GUI.Button(val3, "Cerrar", _buttonStyle))
				{
					_pickerOpen = false;
				}
				if (GUI.Button(val2, "Restablecer posición", _buttonStyle))
				{
					ResetToAnchor();
				}
			}
			if (!string.IsNullOrEmpty(_statusMessage) && Time.unscaledTime < _statusExpire)
			{
				GUI.Label(new Rect(posX + 10f, posY + num + 2f, value - 20f, 16f), "<color=#f0c987>" + _statusMessage + "</color>", _hintStyle);
			}
		}

		private float EstimateContentHeight(bool pauseMenuOpen, float width)
		{
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Expected O, but got Unknown
			//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_0053: Unknown result type (might be due to invalid IL or missing references)
			float num = 44f;
			if (_pinBlocks.Count == 0)
			{
				num += 40f;
			}
			else
			{
				foreach (PinBlock pinBlock in _pinBlocks)
				{
					num += 26f;
					Vector2 val = _labelStyle.CalcSize(new GUIContent(pinBlock.Goals));
					num += Mathf.Min(val.y + 8f, 120f);
					num += 8f;
				}
			}
			if (pauseMenuOpen)
			{
				num += 40f;
			}
			return num;
		}

		private void DrawPinnedContent(Rect contentRect, bool pauseMenuOpen)
		{
			//IL_000d: 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)
			//IL_0069: Expected O, but got Unknown
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Expected O, but got Unknown
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_016b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0201: Unknown result type (might be due to invalid IL or missing references)
			//IL_01af: Unknown result type (might be due to invalid IL or missing references)
			if (_pinBlocks.Count == 0)
			{
				GUI.Label(contentRect, "<color=#cbb892>Ningún logro fijado</color>\n<color=#8f7e5c>Pulsa + para elegir (máx. 3)</color>", _labelStyle);
				return;
			}
			float num = 4f;
			foreach (PinBlock pinBlock2 in _pinBlocks)
			{
				num += 26f;
				num += _labelStyle.CalcHeight(new GUIContent(pinBlock2.Goals), ((Rect)(ref contentRect)).width - 8f) + 10f;
			}
			Rect val = default(Rect);
			((Rect)(ref val))..ctor(0f, 0f, ((Rect)(ref contentRect)).width - 16f, Mathf.Max(((Rect)(ref contentRect)).height, num));
			_bodyScroll = GUI.BeginScrollView(contentRect, _bodyScroll, val);
			float num2 = 2f;
			Rect row = default(Rect);
			for (int i = 0; i < _pinBlocks.Count; i++)
			{
				PinBlock pinBlock = _pinBlocks[i];
				float num3 = _labelStyle.CalcHeight(new GUIContent(pinBlock.Goals), ((Rect)(ref val)).width - 4f);
				((Rect)(ref row))..ctor(2f, num2, ((Rect)(ref val)).width - 4f, 24f);
				DrawRowBg(row, i % 2 == 0);
				GUI.Label(new Rect(((Rect)(ref row)).x + 6f, ((Rect)(ref row)).y + 2f, ((Rect)(ref row)).width - 22f - 12f, 20f), pinBlock.Header, _labelStyle);
				if (pauseMenuOpen && GUI.Button(new Rect(((Rect)(ref row)).xMax - 22f - 2f, ((Rect)(ref row)).y + 1f, 22f, 22f), "×", _unpinButtonStyle))
				{
					PinnedAchievements.Unpin(pinBlock.Id);
					RebuildPinBlocks();
					ShowStatus("Logro quitado");
				}
				num2 += 26f;
				GUI.Label(new Rect(8f, num2, ((Rect)(ref val)).width - 12f, num3), pinBlock.Goals, _labelStyle);
				num2 += num3 + 10f;
			}
			GUI.EndScrollView();
		}

		private void DrawPickerInside(Rect contentRect)
		{
			//IL_0047: 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_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: 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_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_018b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ff: Unknown result type (might be due to invalid IL or missing references)
			float num = 44f;
			float num2 = Mathf.Max(((Rect)(ref contentRect)).height, (float)_pickerList.Count * num + 4f);
			Rect val = default(Rect);
			((Rect)(ref val))..ctor(0f, 0f, ((Rect)(ref contentRect)).width - 16f, num2);
			_pickerScroll = GUI.BeginScrollView(contentRect, _pickerScroll, val);
			Rect row = default(Rect);
			for (int i = 0; i < _pickerList.Count; i++)
			{
				TrackedAchievement trackedAchievement = _pickerList[i];
				if ((Object)(object)trackedAchievement?.Source == (Object)null)
				{
					continue;
				}
				((Rect)(ref row))..ctor(2f, (float)i * num, ((Rect)(ref val)).width - 4f, num - 3f);
				DrawRowBg(row, i % 2 == 0);
				Sprite icon = AchievementCatalog.GetIcon(trackedAchievement.Source);
				DrawSprite(new Rect(((Rect)(ref row)).x + 4f, ((Rect)(ref row)).y + 6f, 32f, 32f), icon);
				string text = AchievementCatalog.LocalizeNameForTracker(trackedAchievement.Source);
				FormatPickerProgress(trackedAchievement, out var statusLine, out var complete, out var canPin);
				GUI.Label(new Rect(((Rect)(ref row)).x + 42f, ((Rect)(ref row)).y + 3f, ((Rect)(ref row)).width - 110f, num - 6f), "<b><color=#f5ecd7>" + text + "</color></b>\n" + statusLine, _pickerRowStyle);
				if (canPin)
				{
					if (GUI.Button(new Rect(((Rect)(ref row)).xMax - 58f, ((Rect)(ref row)).y + 10f, 54f, 24f), "Fijar", _buttonStyle))
					{
						if (PinnedAchievements.Pin(trackedAchievement.Id))
						{
							_pickerOpen = false;
							RebuildPinBlocks();
							ShowStatus("Logro fijado");
						}
						else
						{
							ShowStatus("Máximo 3 logros");
						}
					}
				}
				else if (complete)
				{
					GUI.Label(new Rect(((Rect)(ref row)).xMax - 70f, ((Rect)(ref row)).y + 12f, 66f, 20f), "<color=#8fca6e>Hecho</color>", _hintStyle);
				}
			}
			GUI.EndScrollView();
		}

		private static void FormatPickerProgress(TrackedAchievement tracked, out string statusLine, out bool complete, out bool canPin)
		{
			complete = (Object)(object)tracked.Source != (Object)null && tracked.Source.m_unlocked;
			canPin = !complete && !PinnedAchievements.IsPinned(tracked.Id);
			if (complete)
			{
				statusLine = "<color=#8fca6e>Completado</color>";
				return;
			}
			ProgressReader.GetProgress(tracked, out var current, out var total, out var completedParts, out var totalParts);
			if (totalParts > 1)
			{
				int num = Mathf.Max(0, totalParts - completedParts);
				if (num <= 0)
				{
					statusLine = $"<color=#e8c878>{completedParts}/{totalParts}</color>  <color=#8fca6e>casi listo</color>";
				}
				else
				{
					statusLine = $"<color=#e8c878>{completedParts}/{totalParts}</color>  <color=#c9a27a>faltan {num}</color>";
				}
			}
			else if (total > 0.01f)
			{
				float num2 = Mathf.Max(0f, total - current);
				if (num2 <= 0.01f)
				{
					statusLine = "<color=#e8c878>" + ProgressReader.FormatAmount(current) + " / " + ProgressReader.FormatAmount(total) + "</color>";
				}
				else
				{
					statusLine = "<color=#e8c878>" + ProgressReader.FormatAmount(current) + " / " + ProgressReader.FormatAmount(total) + "</color>  <color=#c9a27a>faltan " + ProgressReader.FormatAmount(num2) + "</color>";
				}
			}
			else
			{
				statusLine = "<color=#c9a27a>Sin progreso</color>";
			}
		}

		private void RebuildPickerList()
		{
			_pickerList.Clear();
			if (!AchievementCatalog.IsReady)
			{
				return;
			}
			foreach (TrackedAchievement item in AchievementCatalog.All)
			{
				if (!((Object)(object)item?.Source == (Object)null) && !ModConfig.IsAchievementDisabled(item.Id) && !PinnedAchievements.IsPinned(item.Id))
				{
					_pickerList.Add(item);
				}
			}
			_pickerList.Sort(delegate(TrackedAchievement a, TrackedAchievement b)
			{
				bool flag = (Object)(object)a.Source != (Object)null && a.Source.m_unlocked;
				bool flag2 = (Object)(object)b.Source != (Object)null && b.Source.m_unlocked;
				return (flag != flag2) ? (flag ? 1 : (-1)) : string.Compare(AchievementCatalog.LocalizeNameForTracker(a.Source), AchievementCatalog.LocalizeNameForTracker(b.Source), StringComparison.OrdinalIgnoreCase);
			});
		}

		private void RebuildPinBlocks()
		{
			//IL_002c: 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_00cb: Unknown result type (might be due to invalid IL or missing references)
			_pinBlocks.Clear();
			_cachedBody = "";
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return;
			}
			Vector3 position = ((Component)localPlayer).transform.position;
			StringBuilder stringBuilder = new StringBuilder();
			foreach (TrackedAchievement item in PinnedAchievements.GetPinnedTracked())
			{
				if ((Object)(object)item.Source == (Object)null || item.Source.m_unlocked)
				{
					continue;
				}
				ProgressReader.GetProgress(item, out var _, out var _, out var completedParts, out var totalParts);
				string text = AchievementCatalog.LocalizeNameForTracker(item.Source);
				string text2 = "<color=#f5ecd7><b>" + text + "</b></color>";
				if (totalParts > 0)
				{
					text2 += $"  <color=#e8c878>({completedParts}/{totalParts})</color>";
				}
				ProgressReader.GetIncompleteGoals(item, position, _goalBuffer);
				int num = ProgressReader.CountIncompleteGoals(item);
				StringBuilder stringBuilder2 = new StringBuilder();
				if (_goalBuffer.Count == 0)
				{
					stringBuilder2.Append("<color=#8f7e5c>Sin objetivos pendientes</color>");
				}
				else
				{
					for (int i = 0; i < _goalBuffer.Count; i++)
					{
						IncompleteGoal incompleteGoal = _goalBuffer[i];
						if (incompleteGoal.RichLine)
						{
							stringBuilder2.Append(incompleteGoal.Label);
						}
						else
						{
							stringBuilder2.Append("<color=#dcc9a0>• ").Append(incompleteGoal.Label).Append("</color>");
							if (incompleteGoal.Total > 1.01f || incompleteGoal.Current > 0.01f)
							{
								stringBuilder2.Append("  <color=#a8926a>").Append(ProgressReader.FormatAmount(incompleteGoal.Current)).Append('/')
									.Append(ProgressReader.FormatAmount(incompleteGoal.Total))
									.Append("</color>");
							}
						}
						if (i < _goalBuffer.Count - 1)
						{
							stringBuilder2.Append('\n');
						}
					}
					if (num > _goalBuffer.Count)
					{
						stringBuilder2.Append("\n<color=#8f7e5c>…y ").Append(num - _goalBuffer.Count).Append(" más</color>");
					}
				}
				_pinBlocks.Add(new PinBlock
				{
					Id = item.Id,
					Header = text2,
					Goals = stringBuilder2.ToString()
				});
				if (stringBuilder.Length > 0)
				{
					stringBuilder.Append('\n');
				}
				stringBuilder.Append(text2).Append('\n').Append((object?)stringBuilder2);
			}
			_cachedBody = stringBuilder.ToString();
		}

		private void ShowStatus(string msg)
		{
			_statusMessage = msg;
			_statusExpire = Time.unscaledTime + 2.5f;
		}

		private void DrawPanel(Rect rect)
		{
			//IL_0034: 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_0089: Unknown result type (might be due to invalid IL or missing references)
			GUI.DrawTexture(new Rect(((Rect)(ref rect)).x - 2f, ((Rect)(ref rect)).y - 2f, ((Rect)(ref rect)).width + 4f, ((Rect)(ref rect)).height + 4f), (Texture)(object)_accentBg);
			GUI.Box(rect, GUIContent.none, _panelStyle);
			GUI.Box(new Rect(((Rect)(ref rect)).x + 3f, ((Rect)(ref rect)).y + 3f, ((Rect)(ref rect)).width - 6f, ((Rect)(ref rect)).height - 6f), GUIContent.none, _innerStyle);
		}

		private void DrawRowBg(Rect row, bool alt)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			GUI.DrawTexture(row, (Texture)(object)(alt ? _rowAltBg : _rowBg));
		}

		private static void DrawSprite(Rect rect, Sprite sprite)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: 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_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)sprite == (Object)null || (Object)(object)sprite.texture == (Object)null)
			{
				Color color = GUI.color;
				GUI.color = new Color(0.45f, 0.35f, 0.2f, 0.7f);
				GUI.DrawTexture(rect, (Texture)(object)Texture2D.whiteTexture);
				GUI.color = color;
			}
			else
			{
				Rect textureRect = sprite.textureRect;
				Rect val = default(Rect);
				((Rect)(ref val))..ctor(((Rect)(ref textureRect)).x / (float)((Texture)sprite.texture).width, ((Rect)(ref textureRect)).y / (float)((Texture)sprite.texture).height, ((Rect)(ref textureRect)).width / (float)((Texture)sprite.texture).width, ((Rect)(ref textureRect)).height / (float)((Texture)sprite.texture).height);
				GUI.DrawTextureWithTexCoords(rect, (Texture)(object)sprite.texture, val);
			}
		}

		private void EnsureStyles()
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: 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_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: Expected O, but got Unknown
			//IL_015a: Unknown result type (might be due to invalid IL or missing references)
			//IL_015f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0175: Expected O, but got Unknown
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0194: Unknown result type (might be due to invalid IL or missing references)
			//IL_019b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a7: Expected O, but got Unknown
			//IL_01c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01db: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0202: Expected O, but got Unknown
			//IL_0221: Unknown result type (might be due to invalid IL or missing references)
			//IL_0236: Unknown result type (might be due to invalid IL or missing references)
			//IL_023b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0242: Unknown result type (might be due to invalid IL or missing references)
			//IL_024a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0256: Expected O, but got Unknown
			//IL_0275: Unknown result type (might be due to invalid IL or missing references)
			//IL_028a: 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_0297: Unknown result type (might be due to invalid IL or missing references)
			//IL_029e: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b4: Expected O, but got Unknown
			//IL_02b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02da: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0305: Unknown result type (might be due to invalid IL or missing references)
			//IL_0316: Unknown result type (might be due to invalid IL or missing references)
			//IL_031c: Unknown result type (might be due to invalid IL or missing references)
			//IL_032b: Expected O, but got Unknown
			//IL_0332: Unknown result type (might be due to invalid IL or missing references)
			//IL_0337: Unknown result type (might be due to invalid IL or missing references)
			//IL_033f: Unknown result type (might be due to invalid IL or missing references)
			//IL_034b: Expected O, but got Unknown
			//IL_035f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0371: Unknown result type (might be due to invalid IL or missing references)
			//IL_0376: Unknown result type (might be due to invalid IL or missing references)
			//IL_037e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0385: Unknown result type (might be due to invalid IL or missing references)
			//IL_0396: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f7: Expected O, but got Unknown
			//IL_0402: Unknown result type (might be due to invalid IL or missing references)
			//IL_0407: Unknown result type (might be due to invalid IL or missing references)
			//IL_040e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0416: Unknown result type (might be due to invalid IL or missing references)
			//IL_041d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0429: Expected O, but got Unknown
			//IL_0448: Unknown result type (might be due to invalid IL or missing references)
			if (_panelStyle == null)
			{
				_panelBg = MakeTex(new Color(0.12f, 0.1f, 0.08f, 0.94f));
				_innerBg = MakeTex(new Color(0.22f, 0.17f, 0.11f, 0.55f));
				_accentBg = MakeTex(new Color(0.85f, 0.65f, 0.28f, 0.95f));
				_buttonBg = MakeTex(new Color(0.42f, 0.3f, 0.14f, 0.98f));
				_buttonHoverBg = MakeTex(new Color(0.58f, 0.42f, 0.18f, 1f));
				_dangerBg = MakeTex(new Color(0.55f, 0.22f, 0.16f, 0.95f));
				_rowBg = MakeTex(new Color(0.28f, 0.22f, 0.14f, 0.65f));
				_rowAltBg = MakeTex(new Color(0.32f, 0.25f, 0.16f, 0.55f));
				GUIStyle val = new GUIStyle(GUI.skin.box);
				val.normal.background = _panelBg;
				_panelStyle = val;
				GUIStyle val2 = new GUIStyle(GUI.skin.box);
				val2.normal.background = _innerBg;
				_innerStyle = val2;
				_titleStyle = new GUIStyle(GUI.skin.label)
				{
					alignment = (TextAnchor)0,
					fontSize = 14,
					richText = true,
					fontStyle = (FontStyle)1
				};
				_titleStyle.normal.textColor = new Color(0.96f, 0.9f, 0.72f, 1f);
				_labelStyle = new GUIStyle(GUI.skin.label)
				{
					alignment = (TextAnchor)0,
					fontSize = 12,
					richText = true,
					wordWrap = true
				};
				_labelStyle.normal.textColor = new Color(0.96f, 0.93f, 0.84f, 1f);
				_hintStyle = new GUIStyle(GUI.skin.label)
				{
					alignment = (TextAnchor)5,
					fontSize = 11,
					richText = true
				};
				_hintStyle.normal.textColor = new Color(0.85f, 0.75f, 0.55f, 1f);
				GUIStyle val3 = new GUIStyle(GUI.skin.button)
				{
					fontSize = 11,
					alignment = (TextAnchor)4,
					richText = true,
					padding = new RectOffset(4, 4, 2, 2)
				};
				val3.normal.background = _buttonBg;
				val3.normal.textColor = new Color(0.98f, 0.93f, 0.78f);
				val3.hover.background = _buttonHoverBg;
				val3.hover.textColor = Color.white;
				val3.active.background = _buttonHoverBg;
				val3.active.textColor = Color.white;
				_buttonStyle = val3;
				_iconButtonStyle = new GUIStyle(_buttonStyle)
				{
					fontSize = 16,
					fontStyle = (FontStyle)1
				};
				Texture2D background = MakeTex(new Color(0.72f, 0.3f, 0.2f, 1f));
				GUIStyle val4 = new GUIStyle(_buttonStyle)
				{
					fontSize = 14,
					fontStyle = (FontStyle)1
				};
				val4.normal.background = _dangerBg;
				val4.normal.textColor = new Color(1f, 0.92f, 0.85f);
				val4.hover.background = background;
				val4.hover.textColor = Color.white;
				val4.active.background = _dangerBg;
				val4.active.textColor = Color.white;
				_unpinButtonStyle = val4;
				_pickerRowStyle = new GUIStyle(GUI.skin.label)
				{
					alignment = (TextAnchor)3,
					fontSize = 11,
					richText = true,
					wordWrap = true
				};
				_pickerRowStyle.normal.textColor = new Color(0.96f, 0.93f, 0.84f, 1f);
			}
		}

		private static Texture2D MakeTex(Color c)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: 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)
			//IL_0012: 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_0021: Expected O, but got Unknown
			Texture2D val = new Texture2D(1, 1, (TextureFormat)4, false);
			val.SetPixel(0, 0, c);
			val.Apply();
			((Object)val).hideFlags = (HideFlags)61;
			return val;
		}

		private void HandleDragging(bool pauseMenuOpen, ref float posX, ref float posY, float width, float height, Rect ignoreA, Rect ignoreB, Rect ignoreC)
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Invalid comparison between Unknown and I4
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0169: Unknown result type (might be due to invalid IL or missing references)
			//IL_016f: Invalid comparison between Unknown and I4
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: 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_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: 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_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: 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)
			if (!pauseMenuOpen)
			{
				if (_dragging)
				{
					EndDrag(posX, posY, width, height);
				}
			}
			else
			{
				if (_pickerOpen)
				{
					return;
				}
				Event current = Event.current;
				Rect val = default(Rect);
				((Rect)(ref val))..ctor(posX, posY, width, height);
				if ((int)current.type == 0 && current.button == 0 && ((Rect)(ref val)).Contains(current.mousePosition))
				{
					if ((((Rect)(ref ignoreA)).width > 1f && ((Rect)(ref ignoreA)).Contains(current.mousePosition)) || (((Rect)(ref ignoreB)).width > 1f && ((Rect)(ref ignoreB)).Contains(current.mousePosition)) || (((Rect)(ref ignoreC)).width > 1f && ((Rect)(ref ignoreC)).Contains(current.mousePosition)))
					{
						return;
					}
					_dragging = true;
					_dragMoved = false;
					_dragOffset = current.mousePosition - new Vector2(posX, posY);
					current.Use();
				}
				if (_dragging && (int)current.type == 3)
				{
					Vector2 val2 = current.mousePosition - _dragOffset;
					if (Vector2.Distance(val2, new Vector2(posX, posY)) > 1f)
					{
						_dragMoved = true;
					}
					posX = val2.x;
					posY = val2.y;
					ClampPosition(ref posX, ref posY, width, height);
					_runtimePosX = posX;
					_runtimePosY = posY;
					_hasRuntimePos = true;
					current.Use();
				}
				if (_dragging && (int)current.type == 1)
				{
					EndDrag(posX, posY, width, height);
					current.Use();
				}
			}
		}

		private void EndDrag(float posX, float posY, float width, float height)
		{
			_dragging = false;
			ClampPosition(ref posX, ref posY, width, height);
			if (_dragMoved)
			{
				_runtimePosX = posX;
				_runtimePosY = posY;
				_hasRuntimePos = true;
				ModConfig.IndicatorUseCustomPosition.Value = true;
				ModConfig.IndicatorCustomNormX.Value = ((Screen.width > 0) ? (posX / (float)Screen.width) : 0f);
				ModConfig.IndicatorCustomNormY.Value = ((Screen.height > 0) ? (posY / (float)Screen.height) : 0f);
				ModConfig.Save();
			}
		}

		private void ResetToAnchor()
		{
			ModConfig.IndicatorUseCustomPosition.Value = false;
			ModConfig.IndicatorCustomNormX.Value = 0f;
			ModConfig.IndicatorCustomNormY.Value = 0f;
			_dragging = false;
			_dragMoved = false;
			_hasRuntimePos = false;
			ModConfig.Save();
		}

		private void ResolvePosition(float width, float height, out float posX, out float posY)
		{
			if (_hasRuntimePos && (_dragging || ModConfig.IndicatorUseCustomPosition.Value))
			{
				posX = _runtimePosX;
				posY = _runtimePosY;
				ClampPosition(ref posX, ref posY, width, height);
				return;
			}
			if (ModConfig.IndicatorUseCustomPosition.Value)
			{
				posX = Mathf.Clamp01(ModConfig.IndicatorCustomNormX.Value) * (float)Screen.width;
				posY = Mathf.Clamp01(ModConfig.IndicatorCustomNormY.Value) * (float)Screen.height;
				ClampPosition(ref posX, ref posY, width, height);
				_runtimePosX = posX;
				_runtimePosY = posY;
				_hasRuntimePos = true;
				return;
			}
			float value = ModConfig.IndicatorOffsetX.Value;
			float value2 = ModConfig.IndicatorOffsetY.Value;
			switch ((ModConfig.IndicatorAnchor.Value ?? "BelowHotbar").Trim().ToLowerInvariant())
			{
			case "belowhotbar":
			case "hotbar":
			case "below_equipment":
			{
				if (TryGetHotkeyBarScreenRect(out var imguiRect))
				{
					posX = ((Rect)(ref imguiRect)).x + (((Rect)(ref imguiRect)).width - width) * 0.5f + value;
					posY = ((Rect)(ref imguiRect)).yMax + value2;
					ClampPosition(ref posX, ref posY, width, height);
				}
				else
				{
					float num = Mathf.Clamp((float)Screen.height * 0.07f, 48f, 96f);
					float num2 = Mathf.Clamp((float)Screen.height * 0.02f, 8f, 40f);
					posX = ((float)Screen.width - width) * 0.5f + value;
					posY = num2 + num + value2;
					ClampPosition(ref posX, ref posY, width, height);
				}
				return;
			}
			case "topleft":
				posX = value;
				posY = value2;
				break;
			case "bottomleft":
				posX = value;
				posY = (float)Screen.height - height - value2;
				break;
			case "bottomright":
				posX = (float)Screen.width - width - value;
				posY = (float)Screen.height - height - value2;
				break;
			case "topright":
				posX = (float)Screen.width - width - value;
				posY = value2;
				break;
			default:
				posX = ((float)Screen.width - width) * 0.5f + value;
				posY = (float)Screen.height * 0.1f + value2;
				break;
			}
			ClampPosition(ref posX, ref posY, width, height);
		}

		private static bool TryGetHotkeyBarScreenRect(out Rect imguiRect)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_016a: Unknown result type (might be due to invalid IL or missing references)
			//IL_016f: Unknown result type (might be due to invalid IL or missing references)
			imguiRect = default(Rect);
			try
			{
				RectTransform val = null;
				HotkeyBar val2 = Object.FindObjectOfType<HotkeyBar>();
				if ((Object)(object)val2 != (Object)null && ((Behaviour)val2).isActiveAndEnabled)
				{
					Transform transform = ((Component)val2).transform;
					val = (RectTransform)(((object)((transform is RectTransform) ? transform : null)) ?? ((object)((Component)val2).GetComponent<RectTransform>()));
				}
				if ((Object)(object)val == (Object)null && (Object)(object)Hud.instance != (Object)null && (Object)(object)Hud.instance.m_actionBarRoot != (Object)null)
				{
					GameObject actionBarRoot = Hud.instance.m_actionBarRoot;
					if (actionBarRoot.activeInHierarchy)
					{
						val = (RectTransform)(((object)actionBarRoot.GetComponent<RectTransform>()) ?? ((object)/*isinst with value type is only supported in some contexts*/));
					}
				}
				if ((Object)(object)val == (Object)null)
				{
					return false;
				}
				Vector3[] array = (Vector3[])(object)new Vector3[4];
				val.GetWorldCorners(array);
				float num = array[0].x;
				float num2 = array[0].x;
				float num3 = array[0].y;
				float num4 = array[0].y;
				for (int i = 1; i < 4; i++)
				{
					num = Mathf.Min(num, array[i].x);
					num2 = Mathf.Max(num2, array[i].x);
					num3 = Mathf.Min(num3, array[i].y);
					num4 = Mathf.Max(num4, array[i].y);
				}
				float num5 = (float)Screen.height - num4;
				float num6 = (float)Screen.height - num3;
				imguiRect = new Rect(num, num5, num2 - num, num6 - num5);
				return ((Rect)(ref imguiRect)).width > 8f && ((Rect)(ref imguiRect)).height > 4f;
			}
			catch
			{
				return false;
			}
		}

		private static void ClampPosition(ref float posX, ref float posY, float width, float height)
		{
			posX = Mathf.Clamp(posX, 8f, Mathf.Max(8f, (float)Screen.width - width - 8f));
			posY = Mathf.Clamp(posY, 8f, Mathf.Max(8f, (float)Screen.height - height - 8f));
		}

		private static bool IsPauseMenuVisible()
		{
			try
			{
				return Menu.IsVisible();
			}
			catch
			{
				return false;
			}
		}

		private static bool IsBlockingGameUiVisible(bool excludePauseMenu)
		{
			try
			{
				if (InventoryGui.IsVisible())
				{
					return true;
				}
				if (!excludePauseMenu && Menu.IsVisible())
				{
					return true;
				}
				if (TextInput.IsVisible())
				{
					return true;
				}
				if (StoreGui.IsVisible())
				{
					return true;
				}
				if (Minimap.IsOpen())
				{
					return true;
				}
				if ((Object)(object)Chat.instance != (Object)null && Chat.instance.HasFocus())
				{
					return true;
				}
			}
			catch
			{
			}
			return false;
		}
	}
	public static class ToastNotifier
	{
		public static void Show(TrackedAchievement tracked, float delta, float current, float total)
		{
			if ((Object)(object)tracked?.Source == (Object)null || !ModConfig.EnableNotifications.Value)
			{
				return;
			}
			string text = AchievementCatalog.LocalizeName(tracked.Source);
			Sprite icon = AchievementCatalog.GetIcon(tracked.Source);
			string text2 = BuildBody(delta, current, total);
			if ((Object)(object)MessageHud.instance != (Object)null)
			{
				try
				{
					UnlockToastGate.BannerText = (ModConfig.ProgressBannerText.Value ?? "Nuevo progreso de logro: {name}").Replace("{name}", text);
					UnlockToastGate.BannerExpireTime = Time.unscaledTime + 8f;
					UnlockToastGate.FromMod = true;
					try
					{
						MessageHud.instance.QueueUnlockMsg(icon, text, text2);
					}
					finally
					{
						UnlockToastGate.FromMod = false;
					}
					if (ModConfig.ReplaceUnlockLogBanner.Value && !string.IsNullOrEmpty(UnlockToastGate.BannerText))
					{
						MessageHud.instance.ShowMessage((MessageType)1, UnlockToastGate.BannerText, 0, (Sprite)null, false, true);
					}
					Plugin.LogDebug("Toast: " + tracked.Id + " | " + text + " | " + text2);
					return;
				}
				catch (Exception ex)
				{
					Plugin.LogDebug("Toast falló (ignorado): " + ex.Message);
					return;
				}
			}
			Plugin.LogDebug("Toast (sin MessageHud): " + text + " " + text2);
		}

		private static string BuildBody(float delta, float current, float total)
		{
			int num = Mathf.Max(1, Mathf.RoundToInt(delta));
			int num2 = Mathf.RoundToInt(current);
			int num3 = Mathf.RoundToInt(total);
			bool value = ModConfig.ShowPlusDelta.Value;
			bool value2 = ModConfig.ShowTotal.Value;
			if (value && value2)
			{
				return $"+{num}  ·  {num2} / {num3}";
			}
			if (value)
			{
				return $"+{num}";
			}
			if (value2)
			{
				return $"{num2} / {num3}";
			}
			return $"{num2}";
		}
	}
	internal static class UnlockToastGate
	{
		public static bool FromMod;

		public static string BannerText;

		public static float BannerExpireTime;
	}
}
namespace AchievementProgress.Patches
{
	[HarmonyPatch(typeof(AchievementsGui), "CreateStatRow")]
	internal static class AchievementsGui_CreateStatRow_Patch
	{
		private static readonly FieldInfo PrefabField = AccessTools.Field(typeof(AchievementsGui), "m_achievementDetailsElementPrefab");

		private static readonly FieldInfo RootField = AccessTools.Field(typeof(AchievementsGui), "m_achievementDetailsListRoot");

		private static bool Prefix(AchievementsGui __instance, string statKey, float currentAmount, float totalAmount)
		{
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			if (!ModConfig.Enabled.Value || !ModConfig.RevealHiddenRequirements.Value)
			{
				return true;
			}
			try
			{
				object? obj = PrefabField?.GetValue(__instance);
				AchievementDetailUnlockCondition val = (AchievementDetailUnlockCondition)((obj is AchievementDetailUnlockCondition) ? obj : null);
				object? obj2 = RootField?.GetValue(__instance);
				Transform val2 = (Transform)((obj2 is Transform) ? obj2 : null);
				if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null)
				{
					return true;
				}
				AchievementDetailUnlockCondition val3 = Object.Instantiate<AchievementDetailUnlockCondition>(val, val2);
				((Component)val3).gameObject.SetActive(true);
				AchievementDetailUnlockCondition val4 = ((Component)val3).GetComponent<AchievementDetailUnlockCondition>() ?? val3;
				string text = statKey;
				if (Enum.TryParse<PlayerStatType>(statKey, out PlayerStatType _))
				{
					text = "$stat_" + statKey;
				}
				string text2 = text;
				try
				{
					if (Localization.instance != null)
					{
						text2 = Localization.instance.Localize(text);
					}
				}
				catch
				{
				}
				if (string.IsNullOrEmpty(text2))
				{
					text2 = text;
				}
				Color color = (Color)((currentAmount >= totalAmount) ? Color.green : new Color(0.92f, 0.88f, 0.78f, 1f));
				SetLabel((TMP_Text)(object)val4.StatName, text2, color);
				SetLabel((TMP_Text)(object)val4.Progress, FormatAmount(currentAmount) + " / " + FormatAmount(totalAmount), color);
				Plugin.LogDebug("Reveal row → " + text2 + " | " + FormatAmount(currentAmount) + " / " + FormatAmount(totalAmount));
				return false;
			}
			catch (Exception ex)
			{
				Plugin.LogInfo("CreateStatRow reveal falló, usando vanilla: " + ex.Message);
				return true;
			}
		}

		private static void SetLabel(TMP_Text label, string text, Color color)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)label == (Object)null))
			{
				label.text = text;
				((Graphic)label).color = color;
			}
		}

		private static string FormatAmount(float value)
		{
			if (Mathf.Abs(value - Mathf.Round(value)) < 0.001f)
			{
				return Mathf.RoundToInt(value).ToString();
			}
			return value.ToString("0.#");
		}
	}
	[HarmonyPatch(typeof(AchievementsGui), "OnOpenAchievementDetails")]
	internal static class AchievementsGui_OnOpenAchievementDetails_Patch
	{
		private static void Prefix(Achievement achievement, ref bool __state)
		{
			__state = false;
			if (ModConfig.Enabled.Value && ModConfig.RevealHiddenRequirements.Value && !((Object)(object)achievement == (Object)null) && achievement.m_isSecret && !achievement.m_unlocked)
			{
				__state = true;
				achievement.m_isSecret = false;
			}
		}

		private static void Finalizer(Achievement achievement, bool __state)
		{
			if (__state && (Object)(object)achievement != (Object)null)
			{
				achievement.m_isSecret = true;
			}
		}
	}
	[HarmonyPatch(typeof(Achievements))]
	internal static class AchievementsPatches
	{
		[HarmonyPostfix]
		[HarmonyPatch("AchievementEvent")]
		private static void AchievementEvent_Postfix(Achievement ach, bool showPopup)
		{
			if (!((Object)(object)ach == (Object)null) && ach.m_unlocked)
			{
				ProgressWatcher.Instance?.OnAchievementUnlocked(ach);
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch("Initialize")]
		private static void Initialize_Postfix()
		{
			AchievementCatalog.Rebuild();
			ProgressWatcher.Instance?.ResetSession();
			ProgressWatcher.Instance?.SeedProgressBaselines();
			Plugin.LogInfo("Achievements.Initialize → catálogo reconstruido.");
		}
	}
	[HarmonyPatch(typeof(Game))]
	internal static class GamePatches
	{
		[HarmonyPostfix]
		[HarmonyPatch("SpawnPlayer")]
		private static void SpawnPlayer_Postfix()
		{
			if (!AchievementCatalog.IsReady)
			{
				AchievementCatalog.Rebuild();
			}
			ProgressWatcher.Instance?.SeedProgressBaselines();
		}
	}
	[HarmonyPatch(typeof(MessageHud))]
	internal static class MessageHudPatches
	{
		private static readonly FieldInfo UnlockQueueField = AccessTools.Field(typeof(MessageHud), "m_unlockMsgQueue");

		private static readonly Type UnlockMsgType = AccessTools.Inner(typeof(MessageHud), "UnlockMsg");

		[HarmonyPrefix]
		[HarmonyPatch("QueueUnlockMsg")]
		private static bool QueueUnlockMsg_Prefix(MessageHud __instance, Sprite icon, string topic, string description)
		{
			if (!UnlockToastGate.FromMod)
			{
				return true;
			}
			try
			{
				object obj = UnlockQueueField?.GetValue(__instance);
				if (obj == null || UnlockMsgType == null)
				{
					return true;
				}
				object obj2 = Activator.CreateInstance(UnlockMsgType);
				UnlockMsgType.GetField("m_icon")?.SetValue(obj2, icon);
				string text = topic;
				string value = description;
				try
				{
					if (Localization.instance != null)
					{
						text = Localization.instance.Localize(topic);
						value = Localization.instance.Localize(description);
					}
				}
				catch
				{
				}
				UnlockMsgType.GetField("m_topic")?.SetValue(obj2, text);
				UnlockMsgType.GetField("m_description")?.SetValue(obj2, value);
				MethodInfo methodInfo = obj.GetType().GetMethod("Enqueue", new Type[1] { UnlockMsgType }) ?? obj.GetType().GetMethod("Enqueue");
				if (methodInfo == null)
				{
					return true;
				}
				methodInfo.Invoke(obj, new object[1] { obj2 });
				Plugin.LogDebug("Unlock toast encolado sin AddLog: " + text);
				return false;
			}
			catch (Exception ex)
			{
				Plugin.LogInfo("QueueUnlockMsg custom falló, usando vanilla: " + ex.Message);
				return true;
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch("ShowMessage")]
		private static void ShowMessage_Prefix(ref string text)
		{
			try
			{
				if (ModConfig.Enabled.Value && ModConfig.ReplaceUnlockLogBanner.Value && !string.IsNullOrEmpty(UnlockToastGate.BannerText))
				{
					if (Time.unscaledTime > UnlockToastGate.BannerExpireTime)
					{
						UnlockToastGate.BannerText = null;
					}
					else if (LooksLikeUnlockLogBanner(text))
					{
						text = UnlockToastGate.BannerText;
						UnlockToastGate.BannerText = null;
						Plugin.LogDebug("Banner reemplazado → " + text);
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.LogDebug("ShowMessage prefix falló (ignorado): " + ex.Message);
			}
		}

		private static bool LooksLikeUnlockLogBanner(string text)
		{
			if (string.IsNullOrEmpty(text))
			{
				return false;
			}
			string text2 = text.ToLowerInvariant();
			if (text2.Contains("registro de mensajes"))
			{
				return true;
			}
			if (text2.Contains("message log"))
			{
				return true;
			}
			if (text2.Contains("nuevos objetos"))
			{
				return true;
			}
			if (text2.Contains("new items unlocked"))
			{
				return true;
			}
			if (text2.Contains("new objects unlocked"))
			{
				return true;
			}
			if (text2.Contains("desbloqueados en el registro"))
			{
				return true;
			}
			if (text2.Contains("unlocked in the message"))
			{
				return true;
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(PlayerProfile))]
	internal static class PlayerProfilePatches
	{
		[HarmonyPrefix]
		[HarmonyPatch("IncrementStat", new Type[]
		{
			typeof(PlayerStatType),
			typeof(float),
			typeof(bool)
		})]
		private static void IncrementStat_Prefix(PlayerStatType stat, out float __state)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			__state = SafeGetStat(stat);
		}

		[HarmonyPostfix]
		[HarmonyPatch("IncrementStat", new Type[]
		{
			typeof(PlayerStatType),
			typeof(float),
			typeof(bool)
		})]
		private static void IncrementStat_Postfix(PlayerStatType stat, float __state)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			SafeEnqueueStat(stat, __state);
		}

		[HarmonyPrefix]
		[HarmonyPatch("SetStat")]
		private static void SetStat_Prefix(PlayerStatType stat, out float __state)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			__state = SafeGetStat(stat);
		}

		[HarmonyPostfix]
		[HarmonyPatch("SetStat")]
		private static void SetStat_Postfix(PlayerStatType stat, float __state)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			SafeEnqueueStat(stat, __state);
		}

		[HarmonyPrefix]
		[HarmonyPatch("IncrementStatEnemy")]
		private static void IncrementStatEnemy_Prefix(string name, out float __state)
		{
			__state = SafeGetDict(TrackedAchievement.DictChannel.Enemy, name);
		}

		[HarmonyPostfix]
		[HarmonyPatch("IncrementStatEnemy")]
		private static void IncrementStatEnemy_Postfix(string name, float __state)
		{
			SafeEnqueueDict(TrackedAchievement.DictChannel.Enemy, name, __state);
		}

		[HarmonyPrefix]
		[HarmonyPatch("IncrementStatItemPickup")]
		private static void IncrementStatItemPickup_Prefix(string name, out float __state)
		{
			__state = SafeGetDict(TrackedAchievement.DictChannel.ItemPickup, name);
		}

		[HarmonyPostfix]
		[HarmonyPatch("IncrementStatItemPickup")]
		private static void IncrementStatItemPickup_Postfix(string name, float __state)
		{
			SafeEnqueueDict(TrackedAchievement.DictChannel.ItemPickup, name, __state);
		}

		[HarmonyPrefix]
		[HarmonyPatch("IncrementStatItemCraft")]
		private static void IncrementStatItemCraft_Prefix(string name, out float __state)
		{
			__state = SafeGetDict(TrackedAchievement.DictChannel.ItemCraft, name);
		}

		[HarmonyPostfix]
		[HarmonyPatch("IncrementStatItemCraft")]
		private static void IncrementStatItemCraft_Postfix(string name, float __state)
		{
			SafeEnqueueDict(TrackedAchievement.DictChannel.ItemCraft, name, __state);
		}

		[HarmonyPrefix]
		[HarmonyPatch("IncrementStatPickable")]
		private static void IncrementStatPickable_Prefix(string name, out float __state)
		{
			__state = SafeGetDict(TrackedAchievement.DictChannel.Pickable, name);
		}

		[HarmonyPostfix]
		[HarmonyPatch("IncrementStatPickable")]
		private static void IncrementStatPickable_Postfix(string name, float __state)
		{
			SafeEnqueueDict(TrackedAchievement.DictChannel.Pickable, name, __state);
		}

		[HarmonyPrefix]
		[HarmonyPatch("IncrementStatFoodEaten")]
		private static void IncrementStatFoodEaten_Prefix(string name, out float __state)
		{
			__state = SafeGetDict(TrackedAchievement.DictChannel.FoodEaten, name);
		}

		[HarmonyPostfix]
		[HarmonyPatch("IncrementStatFoodEaten")]
		private static void IncrementStatFoodEaten_Postfix(string name, float __state)
		{
			SafeEnqueueDict(TrackedAchievement.DictChannel.FoodEaten, name, __state);
		}

		[HarmonyPrefix]
		[HarmonyPatch("IncrementStatBuildPiecePlaced")]
		private static void IncrementStatBuildPiecePlaced_Prefix(string name, out float __state)
		{
			__state = SafeGetDict(TrackedAchievement.DictChannel.PiecePlaced, name);
		}

		[HarmonyPostfix]
		[HarmonyPatch("IncrementStatBuildPiecePlaced")]
		private static void IncrementStatBuildPiecePlaced_Postfix(string name, float __state)
		{
			SafeEnqueueDict(TrackedAchievement.DictChannel.PiecePlaced, name, __state);
		}

		private static float SafeGetStat(PlayerStatType stat)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				return ProgressReader.GetStat(stat);
			}
			catch
			{
				return 0f;
			}
		}

		private static float SafeGetDict(TrackedAchievement.DictChannel channel, string name)
		{
			try
			{
				return ProgressReader.GetDictAmount(channel, name);
			}
			catch
			{
				return 0f;
			}
		}

		private static void SafeEnqueueStat(PlayerStatType stat, float before)
		{
			//IL_0000: 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)
			try
			{
				float stat2 = ProgressReader.GetStat(stat);
				ProgressWatcher.Instance?.EnqueueStatChange(stat, before, stat2);
			}
			catch (Exception ex)
			{
				Plugin.LogDebug("IncrementStat observe failed: " + ex.Message);
			}
		}

		private static void SafeEnqueueDict(TrackedAchievement.DictChannel channel, string name, float before)
		{
			try
			{
				float dictAmount = ProgressReader.GetDictAmount(channel, name);
				ProgressWatcher.Instance?.EnqueueDictChange(channel, name, before, dictAmount);
			}
			catch (Exception ex)
			{
				Plugin.LogDebug("DictStat observe failed: " + ex.Message);
			}
		}
	}
}
namespace AchievementProgress.Core
{
	public static class AchievementCatalog
	{
		private static readonly HashSet<string> SpamIds = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
		{
			"GrindTrees", "GrindBuild", "GrindHarvest", "GrindHoney", "GrindEat", "GrindCook", "GrindForager", "GrindSail", "GrindSailHelm", "KillAllCreatures",
			"KillAllCreaturesHard"
		};

		private static readonly HashSet<string> DirectionalIds = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "ExploreNSEW", "ExploreNSEWNoMap" };

		private static readonly List<TrackedAchievement> _all = new List<TrackedAchievement>();

		private static readonly Dictionary<PlayerStatType, List<TrackedAchievement>> _byStat = new Dictionary<PlayerStatType, List<TrackedAchievement>>();

		private static readonly Dictionary<string, List<TrackedAchievement>> _byDictKey = new Dictionary<string, List<TrackedAchievement>>(StringComparer.OrdinalIgnoreCase);

		private static readonly List<TrackedAchievement> _meta = new List<TrackedAchievement>();

		private static readonly List<TrackedAchievement> _directional = new List<TrackedAchievement>();

		public static bool IsReady { get; private set; }

		public static IReadOnlyList<TrackedAchievement> All => _all;

		public static IReadOnlyList<TrackedAchievement> Directional => _directional;

		public static void Rebuild()
		{
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: Unknown result type (might be due to invalid IL or missing references)
			_all.Clear();
			_byStat.Clear();
			_byDictKey.Clear();
			_meta.Clear();
			_directional.Clear();
			IsReady = false;
			if ((Object)(object)Achievements.m_instance == (Object)null)
			{
				Plugin.LogDebug("Catalog: Achievements.m_instance es null.");
				return;
			}
			foreach (AchievementList achievementList in Achievements.m_instance.m_achievementLists)
			{
				if (achievementList?.m_achievements == null)
				{
					continue;
				}
				foreach (Achievement achievement in achievementList.m_achievements)
				{
					if ((Object)(object)achievement == (Object)null || string.IsNullOrEmpty(achievement.m_id))
					{
						continue;
					}
					TrackedAchievement trackedAchievement = BuildTracked(achievement);
					_all.Add(trackedAchievement);
					if (DirectionalIds.Contains(trackedAchievement.Id))
					{
						_directional.Add(trackedAchievement);
					}
					if (trackedAchievement.Kind == ProgressKind.Meta)
					{
						_meta.Add(trackedAchievement);
					}
					foreach (TrackedAchievement.StatGoal statGoal in trackedAchievement.StatGoals)
					{
						if (!_byStat.TryGetValue(statGoal.Stat, out var value))
						{
							value = new List<TrackedAchievement>();
							_byStat[statGoal.Stat] = value;
						}
						if (!value.Contains(trackedAchievement))
						{
							value.Add(trackedAchievement);
						}
					}
					foreach (TrackedAchievement.DictGoal dictGoal in trackedAchievement.DictGoals)
					{
						string key = DictMapKey(dictGoal.Channel, dictGoal.Key);
						if (!_byDictKey.TryGetValue(key, out var value2))
						{
							value2 = new List<TrackedAchievement>();
							_byDictKey[key] = value2;
						}
						if (!value2.Contains(trackedAchievement))
						{
							value2.Add(trackedAchievement);
						}
					}
				}
			}
			IsReady = _all.Count > 0;
			Plugin.LogInfo($"Catalog: {_all.Count} logros indexados " + $"(counters={_all.Count((TrackedAchievement t) => t.Kind == ProgressKind.Counter)}, " + $"collections={_all.Count((TrackedAchievement t) => t.Kind == ProgressKind.Collection)}, " + $"meta={_meta.Count}, binary={_all.Count((TrackedAchievement t) => t.Kind == ProgressKind.Binary)}).");
		}

		public static bool TryGetByStat(PlayerStatType stat, out List<TrackedAchievement> list)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			return _byStat.TryGetValue(stat, out list);
		}

		public static bool TryGetByDict(TrackedAchievement.DictChannel channel, string key, out List<TrackedAchievement> list)
		{
			return _byDictKey.TryGetValue(DictMapKey(channel, key), out list);
		}

		public static bool TryGetById(string id, out TrackedAchievement tracked)
		{
			tracked = null;
			if (string.IsNullOrEmpty(id))
			{
				return false;
			}
			for (int i = 0; i < _all.Count; i++)
			{
				if (string.Equals(_all[i].Id, id, StringComparison.OrdinalIgnoreCase))
				{
					tracked = _all[i];
					return true;
				}
			}
			return false;
		}

		public static bool IsDirectional(string id)
		{
			if (!string.IsNullOrEmpty(id))
			{
				return DirectionalIds.Contains(id);
			}
			return false;
		}

		public static IEnumerable<TrackedAchievement> MetaAchievements()
		{
			return _meta;
		}

		private static string DictMapKey(TrackedAchievement.DictChannel channel, string key)
		{
			return $"{channel}:{key}";
		}

		private static TrackedAchievement BuildTracked(Achievement ach)
		{
			//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_005d: 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_0063: 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)
			TrackedAchievement trackedAchievement = new TrackedAchievement
			{
				Source = ach,
				Id = ach.m_id,
				UseSpamCooldown = SpamIds.Contains(ach.m_id)
			};
			if (ach.m_statTrigger != null)
			{
				foreach (PlayerStatRequirement item in ach.m_statTrigger)
				{
					trackedAchievement.StatGoals.Add(new TrackedAchievement.StatGoal
					{
						Stat = item.m_stat,
						Target = item.m_amountAboveEquals
					});
				}
			}
			AddDict(trackedAchievement, TrackedAchievement.DictChannel.Enemy, ach.m_enemyStatsTriggers);
			AddDict(trackedAchievement, TrackedAchievement.DictChannel.ItemPickup, ach.m_itemPickupTriggers);
			AddDict(trackedAchievement, TrackedAchievement.DictChannel.ItemCraft, ach.m_itemCraftTriggers);
			AddDict(trackedAchievement, TrackedAchievement.DictChannel.FoodEaten, ach.m_foodEatenTriggers);
			AddDict(trackedAchievement, TrackedAchievement.DictChannel.Pickable, ach.m_pickableTriggers);
			AddDict(trackedAchievement, TrackedAchievement.DictChannel.PiecePlaced, ach.m_piecePlacedTriggers);
			if (ach.m_otherAchievementTriggers != null)
			{
				foreach (Achievement otherAchievementTrigger in ach.m_otherAchievementTriggers)
				{
					if ((Object)(object)otherAchievementTrigger != (Object)null)
					{
						trackedAchievement.MetaGoals.Add(otherAchievementTrigger);
					}
				}
			}
			trackedAchievement.Kind = Classify(trackedAchievement);
			if ((trackedAchievement.Kind == ProgressKind.Collection || trackedAchievement.Kind == ProgressKind.Counter) && (SpamIds.Contains(trackedAchievement.Id) || trackedAchievement.Kind == ProgressKind.Collection))
			{
				trackedAchievement.UseSpamCooldown = SpamIds.Contains(trackedAchievement.Id) || trackedAchievement.DictGoals.Count > 8;
			}
			return trackedAchievement;
		}

		private static void AddDict(TrackedAchievement tracked, TrackedAchievement.DictChannel channel, List<EnemyStatRequirement> reqs)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			if (reqs == null)
			{
				return;
			}
			foreach (EnemyStatRequirement req in reqs)
			{
				if (!string.IsNullOrEmpty(req.m_stat))
				{
					tracked.DictGoals.Add(new TrackedAchievement.DictGoal
					{
						Channel = channel,
						Key = req.m_stat,
						Target = Mathf.Max(1f, req.m_amount)
					});
				}
			}
		}

		private static void AddDict(TrackedAchievement tracked, TrackedAchievement.DictChannel channel, List<DictStatRequirement> reqs)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			if (reqs == null)
			{
				return;
			}
			foreach (DictStatRequirement req in reqs)
			{
				if (!string.IsNullOrEmpty(req.m_stat))
				{
					tracked.DictGoals.Add(new TrackedAchievement.DictGoal
					{
						Channel = channel,
						Key = req.m_stat,
						Target = Mathf.Max(1f, req.m_amount)
					});
				}
			}
		}

		private static ProgressKind Classify(TrackedAchievement t)
		{
			if (t.MetaGoals.Count > 0 && t.StatGoals.Count == 0 && t.DictGoals.Count == 0)
			{
				return ProgressKind.Meta;
			}
			if (t.DictGoals.Count >= 2)
			{
				return ProgressKind.Collection;
			}
			if (t.StatGoals.Count >= 2 && t.StatGoals.All((TrackedAchievement.StatGoal g) => g.Target <= 1.01f) && t.DictGoals.Count == 0)
			{
				return ProgressKind.Collection;
			}
			if (t.StatGoals.Count >= 1 && t.StatGoals.Exists((TrackedAchievement.StatGoal g) => g.Target > 1.01f) && t.DictGoals.Count == 0)
			{
				return ProgressKind.Counter;
			}
			if (t.StatGoals.Count == 1 || t.DictGoals.Count == 1)
			{
				return ProgressKind.Binary;
			}
			if (t.DictGoals.Count > 0 || t.StatGoals.Count > 0)
			{
				return ProgressKind.Collection;
			}
			return ProgressKind.Binary;
		}

		public static string LocalizeName(Achievement ach)
		{
			if ((Object)(object)ach == (Object)null)
			{
				return "?";
			}
			if (ach.m_isSecret && !ach.m_unlocked && !ModConfig.RevealSecretsInToasts.Value)
			{
				return "???";
			}
			return LocalizeNameAlways(ach);
		}

		public static string LocalizeNameAlways(Achievement ach)
		{
			if ((Object)(object)ach == (Object)null)
			{
				return "?";
			}
			try
			{
				if (Localization.instance != null)
				{
					return Localization.instance.Localize(ach.m_name);
				}
			}
			catch
			{
			}
			if (!string.IsNullOrEmpty(ach.m_name))
			{
				return ach.m_name;
			}
			return ach.m_id;
		}

		public static Sprite GetIcon(Achievement ach)
		{
			if ((Object)(object)ach == (Object)null)
			{
				return null;
			}
			if (ach.m_unlocked || ModConfig.RevealSecretsInToasts.Value || !ach.m_isSecret || ModConfig.RevealHiddenRequirements.Value)
			{
				if (!((Object)(object)ach.m_icon != (Object)null))
				{
					return ach.m_iconLocked;
				}
				return ach.m_icon;
			}
			if (!((Object)(object)ach.m_iconLocked != (Object)null))
			{
				return ach.m_icon;
			}
			return ach.m_iconLocked;
		}

		public static string LocalizeNameForTracker(Achievement ach)
		{
			if ((Object)(object)ach == (Object)null)
			{
				return "?";
			}
			if (ModConfig.RevealHiddenRequirements.Value)
			{
				return LocalizeNameAlways(ach);
			}
			return LocalizeName(ach);
		}
	}
	internal static class DictKeyUtil
	{
		public static IEnumerable<string> Aliases(string key)
		{
			if (string.IsNullOrEmpty(key))
			{
				yield break;
			}
			HashSet<string> seen = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
			List<string> list = new List<string>();
			Add(key);
			if (key.StartsWith("$", StringComparison.Ordinal))
			{
				Add(key.Substring(1));
			}
			else
			{
				Add("$" + key);
			}
			Add(SafeLocalize(key));
			if (key.StartsWith("$", StringComparison.Ordinal))
			{
				Add(SafeLocalize(key.Substring(1)));
			}
			else
			{
				Add(SafeLocalize("$" + key));
			}
			foreach (string item in list)
			{
				yield return item;
			}
			void Add(string value)
			{
				if (!string.IsNullOrEmpty(value) && seen.Add(value))
				{
					list.Add(value);
				}
			}
		}

		public static bool TryGetValue(Dictionary<string, float> dict, string key, out float value)
		{
			value = 0f;
			if (dict == null || string.IsNullOrEmpty(key))
			{
				return false;
			}
			if (dict.TryGetValue(key, out value))
			{
				return true;
			}
			foreach (string item in Aliases(key))
			{
				if (dict.TryGetValue(item, out value))
				{
					return true;
				}
			}
			string text = SafeLocalize(key);
			if (string.IsNullOrEmpty(text))
			{
				return false;
			}
			foreach (KeyValuePair<string, float> item2 in dict)
			{
				if (string.Equals(item2.Key, text, StringComparison.OrdinalIgnoreCase) || string.Equals(SafeLocalize(item2.Key), text, StringComparison.OrdinalIgnoreCase))
				{
					value = item2.Value;
					return true;
				}
			}
			return false;
		}

		private static string SafeLocalize(string token)
		{
			if (string.IsNullOrEmpty(token))
			{
				return token;
			}
			try
			{
				if (Localization.instance == null)
				{
					return token;
				}
				string text = Localization.instance.Localize(token.StartsWith("$", StringComparison.Ordinal) ? token : ("$" + token));
				return string.IsNullOrEmpty(text) ? token : text;
			}
			catch
			{
				return token;
			}
		}
	}
	public static class DirectionalProgress
	{
		public const float ExploreThresholdMeters = 10350f;

		public static bool IsDirectionalAchievement(TrackedAchievement tracked)
		{
			if (tracked != null)
			{
				return AchievementCatalog.IsDirectional(tracked.Id);
			}
			return false;
		}

		public unsafe static string FormatIncompleteDirections(TrackedAchievement tracked, Vector3 pos)
		{
			//IL_003c: 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_006f: Unknown result type (might be due to invalid IL or missing references)
			if (tracked?.StatGoals == null || tracked.StatGoals.Count == 0)
			{
				return "";
			}
			StringBuilder stringBuilder = new StringBuilder();
			for (int i = 0; i < tracked.StatGoals.Count; i++)
			{
				TrackedAchievement.StatGoal statGoal = tracked.StatGoals[i];
				if (!(ProgressReader.GetStat(statGoal.Stat) >= statGoal.Target))
				{
					string value = CardinalLabel(((object)(*(PlayerStatType*)(&statGoal.Stat))/*cast due to .constrained prefix*/).ToString());
					int num = Mathf.RoundToInt(EstimateProgressToward(statGoal.Stat, pos) * 100f);
					string value2 = ((num >= 70) ? "#d4c48a" : "#8a7f6e");
					if (stringBuilder.Length > 0)
					{
						stringBuilder.Append("  ");
					}
					stringBuilder.Append("<color=").Append(value2).Append('>')
						.Append(value)
						.Append(num)
						.Append("%</color>");
				}
			}
			return stringBuilder.ToString();
		}

		public unsafe static float EstimateProgressToward(PlayerStatType stat, Vector3 pos)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			string text = ((object)(*(PlayerStatType*)(&stat))/*cast due to .constrained prefix*/).ToString().ToLowerInvariant();
			float num;
			if (text.Contains("north"))
			{
				num = pos.z;
			}
			else if (text.Contains("south"))
			{
				num = 0f - pos.z;
			}
			else if (text.Contains("east"))
			{
				num = pos.x;
			}
			else
			{
				if (!text.Contains("west"))
				{
					return 0f;
				}
				num = 0f - pos.x;
			}
			return Mathf.Clamp01(num / 10350f);
		}

		public static string CardinalLabel(string statName)
		{
			if (string.IsNullOrEmpty(statName))
			{
				return "?";
			}
			string text = statName.ToLowerInvariant();
			if (text.Contains("north"))
			{
				return "N";
			}
			if (text.Contains("south"))
			{
				return "S";
			}
			if (text.Contains("east"))
			{
				return "E";
			}
			if (text.Contains("west"))
			{
				return "W";
			}
			return statName.Substring(0, 1).ToUpperInvariant();
		}
	}
	public static class PinnedAchievements
	{
		public const int MaxPins = 3;

		private static readonly List<string> _ids = new List<string>(3);

		private static bool _loaded;

		public static IReadOnlyList<string> Ids
		{
			get
			{
				EnsureLoaded();
				return _ids;
			}
		}

		public static void EnsureLoaded()
		{
			if (!_loaded)
			{
				ReloadFromConfig();
			}
		}

		public static void ReloadFromConfig()
		{
			_ids.Clear();
			string[] array = (ModConfig.PinnedAchievementIds?.Value ?? "").Split(new char[3] { ',', ';', ' ' }, StringSplitOptions.RemoveEmptyEntries);
			foreach (string text in array)
			{
				string id = text.Trim();
				if (!string.IsNullOrEmpty(id) && !_ids.Exists((string x) => string.Equals(x, id, StringComparison.OrdinalIgnoreCase)))
				{
					_ids.Add(id);
					if (_ids.Count >= 3)
					{
						break;
					}
				}
			}
			_loaded = true;
		}

		public static bool IsPinned(string id)
		{
			if (string.IsNullOrEmpty(id))
			{
				return false;
			}
			EnsureLoaded();
			return _ids.Exists((string x) => string.Equals(x, id, StringComparison.OrdinalIgnoreCase));
		}

		public static bool CanPinMore()
		{
			EnsureLoaded();
			return _ids.Count < 3;
		}

		public static bool Pin(string id)
		{
			if (string.IsNullOrEmpty(id))
			{
				return false;
			}
			EnsureLoaded();
			if (IsPinned(id))
			{
				return true;
			}
			if (_ids.Count >= 3)
			{
				return false;
			}
			_ids.Add(id);
			Persist();
			return true;
		}

		public static bool Unpin(string id)
		{
			if (string.IsNullOrEmpty(id))
			{
				return false;
			}
			EnsureLoaded();
			if (_ids.RemoveAll((string x) => string.Equals(x, id, StringComparison.OrdinalIgnoreCase)) <= 0)
			{
				return false;
			}
			Persist();
			return true;
		}

		public static bool PruneInvalid()
		{
			EnsureLoaded();
			if (!AchievementCatalog.IsReady)
			{
				return false;
			}
			int count = _ids.Count;
			_ids.RemoveAll(delegate(string id)
			{
				if (!AchievementCatalog.TryGetById(id, out var tracked) || (Object)(object)tracked?.Source == (Object)null)
				{
					return true;
				}
				if (tracked.Source.m_unlocked)
				{
					return true;
				}
				return ModConfig.IsAchievementDisabled(id) ? true : false;
			});
			if (_ids.Count == count)
			{
				return false;
			}
			Persist();
			return true;
		}

		public static IEnumerable<TrackedAchievement> GetPinnedTracked()
		{
			EnsureLoaded();
			foreach (string id in _ids)
			{
				if (AchievementCatalog.TryGetById(id, out var tracked) && tracked != null)
				{
					yield return tracked;
				}
			}
		}

		private static void Persist()
		{
			if (ModConfig.PinnedAchievementIds != null)
			{
				ModConfig.PinnedAchievementIds.Value = string.Join(",", _ids);
				ModConfig.Save();
				Plugin.LogDebug("Pins guardados: " + ModConfig.PinnedAchievementIds.Value);
			}
		}

		public static void OnConfigChanged()
		{
			_loaded = false;
			ReloadFromConfig();
		}
	}
	public enum ProgressKind
	{
		Counter,
		Collection,
		Meta,
		Binary
	}
	public struct IncompleteGoal
	{
		public string Label;

		public float Current;

		public float Total;

		public bool RichLine;
	}
	public static class ProgressReader
	{
		public static PlayerStats GetAchievementStats()
		{
			Game instance = Game.instance;
			PlayerProfile val = ((instance != null) ? instance.GetPlayerProfile() : null);
			if (val?.m_playerStats == null || val.m_playerStats.Length < 2)
			{
				return null;
			}
			return val.m_playerStats[1];
		}

		public static float GetStat(PlayerStatType stat)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			PlayerStats achievementStats = GetAchievementStats();
			if (achievementStats == null)
			{
				return 0f;
			}
			return achievementStats[stat];
		}

		public static float GetDictAmount(TrackedAchievement.DictChannel channel, string key)
		{
			PlayerStats achievementStats = GetAchievementStats();
			if (achievementStats == null || string.IsNullOrEmpty(key))
			{
				return 0f;
			}
			Dictionary<string, float> dictionary = null;
			switch (channel)
			{
			case TrackedAchievement.DictChannel.Enemy:
				return GetEnemyAmount(achievementStats, key);
			case TrackedAchievement.DictChannel.ItemPickup:
				dictionary = achievementStats.m_itemPickupStats;
				break;
			case TrackedAchievement.DictChannel.ItemCraft:
				dictionary = achievementStats.m_itemCraftStats;
				break;
			case TrackedAchievement.DictChannel.FoodEaten:
				dictionary = achievementStats.m_foodEatenStats;
				break;
			case TrackedAchievement.DictChannel.Pickable:
				dictionary = achievementStats.m_pickableStats;
				break;
			case TrackedAchievement.DictChannel.PiecePlaced:
				dictionary = achievementStats.m_piecesPlacedStats;
				break;
			}
			if (dictionary != null && dictionary.TryGetValue(key, out var value))
			{
				return value;
			}
			return 0f;
		}

		private static float GetEnemyAmount(PlayerStats stats, string key)
		{
			if (stats.m_enemyStats == null)
			{
				return 0f;
			}
			float num = 0f;
			Dictionary<string, float>[] enemyStats = stats.m_enemyStats;
			foreach (Dictionary<string, float> dictionary in enemyStats)
			{
				if (dictionary != null && dictionary.TryGetValue(key, out var value))
				{
					num += value;
				}
			}
			return num;
		}

		public static void GetProgress(TrackedAchievement tracked, out float current, out float total, out int completedParts, out int totalParts)
		{
			//IL_0182: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			current = 0f;
			total = 0f;
			completedParts = 0;
			totalParts = 0;
			if (tracked == null)
			{
				return;
			}
			if (tracked.Kind == ProgressKind.Meta)
			{
				totalParts = tracked.MetaGoals.Count;
				foreach (Achievement metaGoal in tracked.MetaGoals)
				{
					if ((Object)(object)metaGoal != (Object)null && metaGoal.m_unlocked)
					{
						completedParts++;
					}
				}
				current = completedParts;
				total = totalParts;
				return;
			}
			if (tracked.Kind == ProgressKind.Counter && tracked.StatGoals.Count >= 1 && tracked.DictGoals.Count == 0)
			{
				float num = 0f;
				float num2 = 0f;
				foreach (TrackedAchievement.StatGoal statGoal in tracked.StatGoals)
				{
					float stat = GetStat(statGoal.Stat);
					num += Mathf.Min(stat, statGoal.Target);
					num2 += statGoal.Target;
					if (stat >= statGoal.Target)
					{
						completedParts++;
					}
				}
				current = num;
				total = num2;
				totalParts = tracked.StatGoals.Count;
				return;
			}
			totalParts = tracked.StatGoals.Count + tracked.DictGoals.Count;
			float num3 = 0f;
			float num4 = 0f;
			foreach (TrackedAchievement.StatGoal statGoal2 in tracked.StatGoals)
			{
				float stat2 = GetStat(statGoal2.Stat);
				num3 += Mathf.Min(stat2, statGoal2.Target);
				num4 += statGoal2.Target;
				if (stat2 >= statGoal2.Target)
				{
					completedParts++;
				}
			}
			foreach (TrackedAchievement.DictGoal dictGoal in tracked.DictGoals)
			{
				float dictAmount = GetDictAmount(dictGoal.Channel, dictGoal.Key);
				num3 += Mathf.Min(dictAmount, dictGoal.Target);
				num4 += dictGoal.Target;
				if (dictAmount >= dictGoal.Target)
				{
					completedParts++;
				}
			}
			if (tracked.Kind == ProgressKind.Collection)
			{
				current = completedParts;
				total = totalParts;
			}
			else
			{
				current = num3;
				total = ((num4 > 0f) ? num4 : ((float)totalParts));
			}
		}

		public static bool IsDirectionalComplete(TrackedAchievement tracked, PlayerStatType stat)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			foreach (TrackedAchievement.StatGoal statGoal in tracked.StatGoals)
			{
				if (EqualityComparer<PlayerStatType>.Default.Equals(statGoal.Stat, stat))
				{
					return GetStat(stat) >= statGoal.Target;
				}
			}
			return false;
		}

		public unsafe static void GetIncompleteGoals(TrackedAchievement tracked, Vector3 playerPos, List<IncompleteGoal> into, int maxRows = 8)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0188: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
			into?.Clear();
			if (tracked == null || into == null || maxRows <= 0)
			{
				return;
			}
			if (DirectionalProgress.IsDirectionalAchievement(tracked))
			{
				string text = DirectionalProgress.FormatIncompleteDirections(tracked, playerPos);
				if (!string.IsNullOrEmpty(text))
				{
					into.Add(new IncompleteGoal
					{
						Label = text,
						Current = 0f,
						Total = 0f,
						RichLine = true
					});
				}
				if (tracked.Id == "ExploreNSEWNoMap")
				{
					bool flag = false;
					try
					{
						flag = (Object)(object)Achievements.m_instance != (Object)null && Achievements.IsCleanNoMap();
					}
					catch
					{
						flag = false;
					}
					if (!flag)
					{
						into.Add(new IncompleteGoal
						{
							Label = "Requiere modificador: Sin mapa",
							Current = 0f,
							Total = 1f,
							RichLine = false
						});
					}
				}
				return;
			}
			if (tracked.Kind == ProgressKind.Meta)
			{
				foreach (Achievement metaGoal in tracked.MetaGoals)
				{
					if (!((Object)(object)metaGoal == (Object)null) && !metaGoal.m_unlocked)
					{
						if (into.Count >= maxRows)
						{
							break;
						}
						into.Add(new IncompleteGoal
						{
							Label = AchievementCatalog.LocalizeName(metaGoal),
							Current = 0f,
							Total = 1f,
							RichLine = false
						});
					}
				}
				return;
			}
			foreach (TrackedAchievement.StatGoal statGoal in tracked.StatGoals)
			{
				float stat = GetStat(statGoal.Stat);
				if (!(stat >= statGoal.Target))
				{
					if (into.Count >= maxRows)
					{
						break;
					}
					IncompleteGoal item = default(IncompleteGoal);
					PlayerStatType stat2 = statGoal.Stat;
					item.Label = LocalizeStatKey(((object)(*(PlayerStatType*)(&stat2))/*cast due to .constrained prefix*/).ToString());
					item.Current = stat;
					item.Total = statGoal.Target;
					item.RichLine = false;
					into.Add(item);
				}
			}
			foreach (TrackedAchievement.DictGoal dictGoal in tracked.DictGoals)
			{
				float dictAmount = GetDictAmount(dictGoal.Channel, dictGoal.Key);
				if (!(dictAmount >= dictGoal.Target))
				{
					if (into.Count >= maxRows)
					{
						break;
					}
					into.Add(new IncompleteGoal
					{
						Label = LocalizeDictKey(dictGoal.Key),
						Current = dictAmount,
						Total = dictGoal.Target,
						RichLine = false
					});
				}
			}
		}

		public static int CountIncompleteGoals(TrackedAchievement tracked)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			if (tracked == null)
			{
				return 0;
			}
			if (DirectionalProgress.IsDirectionalAchievement(tracked))
			{
				int num = 0;
				{
					foreach (TrackedAchievement.StatGoal statGoal in tracked.StatGoals)
					{
						if (GetStat(statGoal.Stat) < statGoal.Target)
						{
							num++;
						}
					}
					return num;
				}
			}
			if (tracked.Kind == ProgressKind.Meta)
			{
				int num2 = 0;
				{
					foreach (Achievement metaGoal in tracked.MetaGoals)
					{
						if ((Object)(object)metaGoal != (Object)null && !metaGoal.m_unlocked)
						{
							num2++;
						}
					}
					return num2;
				}
			}
			int num3 = 0;
			foreach (TrackedAchievement.StatGoal statGoal2 in tracked.StatGoals)
			{
				if (GetStat(statGoal2.Stat) < statGoal2.Target)
				{
					num3++;
				}
			}
			foreach (TrackedAchievement.DictGoal dictGoal in tracked.DictGoals)
			{
				if (GetDictAmount(dictGoal.Channel, dictGoal.Key) < dictGoal.Target)
				{
					num3++;
				}
			}
			return num3;
		}

		private static string LocalizeStatKey(string statKey)
		{
			string text = "$stat_" + statKey;
			try
			{
				if (Localization.instance != null)
				{
					string text2 = Localization.instance.Localize(text);
					if (!string.IsNullOrEmpty(text2) && text2 != text)
					{
						return text2;
					}
				}
			}
			catch
			{
			}
			return statKey;
		}

		private static string LocalizeDictKey(string key)
		{
			if (string.IsNullOrEmpty(key))
			{
				return "?";
			}
			try
			{
				if (Localization.instance != null)
				{
					string text = Localization.instance.Localize(key);
					if (!string.IsNullOrEmpty(text))
					{
						return text;
					}
				}
			}
			catch
			{
			}
			return key;
		}

		public static string FormatAmount(float value)
		{
			if (Mathf.Abs(value - Mathf.Round(value)) < 0.001f)
			{
				return Mathf.RoundToInt(value).ToString();
			}
			return value.ToString("0.#");
		}
	}
	public sealed class ProgressWatcher : MonoBehaviour
	{
		private struct PendingToast
		{
			public TrackedAchievement Tracked;

			public float Current;

			public float Total;
		}

		private struct StatEvent
		{
			public PlayerStatType Stat;

			public float Before;

			public float After;
		}

		private struct DictEvent
		{
			public TrackedAchievement.DictChannel Channel;

			public string Key;

			public float Before;

			public float After;
		}

		private readonly Dictionary<string, PendingToast> _pending = new Dictionary<string, PendingToast>();

		private readonly Dictionary<string, float> _coalesceDeadline = new Dictionary<string, float>();

		private readonly Dictionary<string, float> _lastShownCurrent = new Dictionary<string, float>();

		private readonly Queue<StatEvent> _statEvents = new Queue<StatEvent>();

		private readonly Queue<DictEvent> _dictEvents = new Queue<DictEvent>();

		private readonly object _eventLock = new object();

		public static ProgressWatcher Instance { get; private set; }

		private void Awake()
		{
			Instance = this;
		}

		private void OnDestroy()
		{
			if ((Object)(object)Instance == (Object)(object)this)
			{
				Instance = null;
			}
		}

		private void Update()
		{
			if (ModConfig.Enabled.Value)
			{
				if (!AchievementCatalog.IsReady && (Object)(object)Achievements.m_instance != (Object)null)
				{
					AchievementCatalog.Rebuild();
				}
				DrainDeferredEvents();
				if (ModConfig.EnableNotifications.Value)
				{
					FlushReadyPending();
				}
			}
		}

		public void EnqueueStatChange(PlayerStatType stat, float before, float after)
		{
			//IL_002c: 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)
			if (after <= before + 0.001f)
			{
				return;
			}
			lock (_eventLock)
			{
				_statEvents.Enqueue(new StatEvent
				{
					Stat = stat,
					Before = before,
					After = after
				});
			}
		}

		public void EnqueueDictChange(TrackedAchievement.DictChannel channel, string key, float before, float after)
		{
			if (string.IsNullOrEmpty(key) || after <= before + 0.001f)
			{
				return;
			}
			lock (_eventLock)
			{
				_dictEvents.Enqueue(new DictEvent
				{
					Channel = channel,
					Key = key,
					Before = before,
					After = after
				});
			}
		}

		private void DrainDeferredEvents()
		{
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			List<StatEvent> list = null;
			List<DictEvent> list2 = null;
			lock (_eventLock)
			{
				if (_statEvents.Count > 0)
				{
					list = new List<StatEvent>(_statEvents.Count);
					while (_statEvents.Count > 0)
					{
						list.Add(_statEvents.Dequeue());
					}
				}
				if (_dictEvents.Count > 0)
				{
					list2 = new List<DictEvent>(_dictEvents.Count);
					while (_dictEvents.Count > 0)
					{
						list2.Add(_dictEvents.Dequeue());
					}
				}
			}
			if (list != null)
			{
				foreach (StatEvent item in list)
				{
					ProcessStatChanged(item.Stat, item.Before, item.After);
				}
			}
			if (list2 == null)
			{
				return;
			}
			foreach (DictEvent item2 in list2)
			{
				ProcessDictChanged(item2.Channel, item2.Key, item2.Before, item2.After);
			}
		}

		private void ProcessStatChanged(PlayerStatType stat, float before, float after)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			if (!ShouldProcess())
			{
				return;
			}
			if (!AchievementCatalog.IsReady)
			{
				AchievementCatalog.Rebuild();
			}
			if (after <= before + 0.001f || !AchievementCatalog.TryGetByStat(stat, out var list))
			{
				return;
			}
			float num = after - before;
			foreach (TrackedAchievement item in list)
			{
				if (!ModConfig.HideCompletedRequirements.Value || !WasStatGoalAlreadyComplete(item, stat, before))
				{
					Evaluate(item, Mathf.Max(0.01f, num));
				}
			}
		}

		private void ProcessDictChanged(TrackedAchievement.DictChannel channel, string key, float before, float after)
		{
			if (!ShouldProcess() || string.IsNullOrEmpty(key))
			{
				return;
			}
			if (!AchievementCatalog.IsReady)
			{
				AchievementCatalog.Rebuild();
			}
			if (after <= before + 0.001f || !AchievementCatalog.TryGetByDict(channel, key, out var list))
			{
				return;
			}
			float num = after - before;
			foreach (TrackedAchievement item in list)
			{
				if (!ModConfig.HideCompletedRequirements.Value || !WasDictGoalAlreadyComplete(item, channel, key, before))
				{
					Evaluate(item, Mathf.Max(0.01f, num));
				}
			}
		}

		private static bool WasDictGoalAlreadyComplete(TrackedAchievement tracked, TrackedAchievement.DictChannel channel, string key, float before)
		{
			if (tracked?.DictGoals == null)
			{
				return false;
			}
			foreach (TrackedAchievement.DictGoal dictGoal in tracked.DictGoals)
			{
				if (dictGoal.Channel == channel && string.Equals(dictGoal.Key, key, StringComparison.OrdinalIgnoreCase))
				{
					return before >= dictGoal.Target;
				}
			}
			return false;
		}

		private static bool WasStatGoalAlreadyComplete(TrackedAchievement tracked, PlayerStatType stat, float before)
		{
			//IL_002c: 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)
			if (tracked?.StatGoals == null)
			{
				return false;
			}
			foreach (TrackedAchievement.StatGoal statGoal in tracked.StatGoals)
			{
				if (EqualityComparer<PlayerStatType>.Default.Equals(statGoal.Stat, stat))
				{
					return before >= statGoal.Target;
				}
			}
			return false;
		}

		public void SeedProgressBaselines()
		{
			if (!AchievementCatalog.IsReady)
			{
				return;
			}
			foreach (TrackedAchievement item in AchievementCatalog.All)
			{
				if (!((Object)(object)item?.Source == (Object)null))
				{
					ProgressReader.GetProgress(item, out var current2, out var _, out var _, out var _);
					_lastShownCurrent[item.Id] = current2;
				}
			}
			Plugin.LogDebug($"Baselines de progreso sembradas ({_lastShownCurrent.Count}).");
		}

		public void OnAchievementUnlocked(Achievement ach)
		{
			if (!ShouldProcess() || (Object)(object)ach == (Object)null)
			{
				return;
			}
			foreach (TrackedAchievement item in AchievementCatalog.MetaAchievements())
			{
				if ((Object)(object)item.Source != (Object)null && !item.Source.m_unlocked)
				{
					Evaluate(item, 1f);
				}
			}
			if (ModConfig.EnableBinaryUnlockToasts.Value)
			{
				TrackedAchievement trackedAchievement = FindById(ach.m_id);
				if (trackedAchievement != null && trackedAchievement.Kind == ProgressKind.Binary && !ModConfig.IsAchievementDisabled(trackedAchievement.Id))
				{
					ToastNotifier.Show(trackedAchievement, 1f, 1f, 1f);
				}
			}
		}

		private TrackedAchievement FindById(string id)
		{
			foreach (TrackedAchievement item in AchievementCatalog.All)
			{
				if (item.Id == id)
				{
					return item;
				}
			}
			return null;
		}

		private bool ShouldProcess()
		{
			if (ModConfig.Enabled.Value && ModConfig.EnableNotifications.Value && (Object)(object)Game.instance != (Object)null)
			{
				return (Object)(object)Player.m_localPlayer != (Object)null;
			}
			return false;
		}

		private void Evaluate(TrackedAchievement tracked, float estimateDelta)
		{
			if ((Object)(object)tracked?.Source == (Object)null || tracked.Source.m_unlocked || ModConfig.IsAchievementDisabled(tracked.Id))
			{
				return;
			}
			switch (tracked.Kind)
			{
			case ProgressKind.Counter:
				if (!ModConfig.EnableCounterToasts.Value)
				{
					return;
				}
				break;
			case ProgressKind.Collection:
				if (!ModConfig.EnableCollectionToasts.Value)
				{
					return;
				}
				break;
			case ProgressKind.Meta:
				if (!ModConfig.EnableMetaToasts.Value)
				{
					return;
				}
				break;
			case ProgressKind.Binary:
				return;
			}
			ProgressReader.GetProgress(tracked, out var current, out var total, out var _, out var _);
			if (total <= 0f)
			{
				return;
			}
			if (!_lastShownCurrent.TryGetValue(tracked.Id, out var value))
			{
				_lastShownCurrent[tracked.Id] = current;
			}
			else
			{
				if (current <= value + 0.001f)
				{
					return;
				}
				if (UsesCoalesceDelay(tracked))
				{
					if (!IsSailAchievement(tracked.Id) || !(current - value < 1f) || _pending.ContainsKey(tracked.Id))
					{
						ScheduleFinalToast(tracked, current, total);
					}
				}
				else
				{
					float delta = Mathf.Max(estimateDelta, current - value);
					ShowNow(tracked, delta, current, total);
				}
			}
		}

		private static bool IsSailAchievement(string id)
		{
			if (!(id == "GrindSail"))
			{
				return id == "GrindSailHelm";
			}
			return true;
		}

		private static bool UsesCoalesceDelay(TrackedAchievement tracked)
		{
			if (tracked == null)
			{
				return false;
			}
			if (!tracked.UseSpamCooldown && tracked.Kind != ProgressKind.Counter)
			{
				return IsSailAchievement(tracked.Id);
			}
			return true;
		}

		private float GetCooldownSeconds(TrackedAchievement tracked)
		{
			if (tracked != null && IsSailAchievement(tracked.Id))
			{
				return Mathf.Max(1f, ModConfig.SailCooldownSeconds.Value);
			}
			return Mathf.Max(0.1f, ModConfig.SpamCooldownSeconds.Value);
		}

		private void ScheduleFinalToast(TrackedAchievement tracked, float current, float total)
		{
			float cooldownSeconds = GetCooldownSeconds(tracked);
			_pending[tracked.Id] = new PendingToast
			{
				Tracked = tracked,
				Current = current,
				Total = total
			};
			_coalesceDeadline[tracked.Id] = Time.unscaledTime + cooldownSeconds;
		}

		private void FlushReadyPending()
		{
			if (_pending.Count == 0)
			{
				return;
			}
			float unscaledTime = Time.unscaledTime;
			List<string> list = new List<string>();
			foreach (KeyValuePair<string, PendingToast> item in _pending)
			{
				if (_coalesceDeadline.TryGetValue(item.Key, out var value) && unscaledTime >= value)
				{
					list.Add(item.Key);
				}
			}
			foreach (string item2 in list)
			{
				PendingToast pendingToast = _pending[item2];
				_pending.Remove(item2);
				_coalesceDeadline.Remove(item2);
				if (!((Object)(object)pendingToast.Tracked?.Source == (Object)null) && !pendingToast.Tracked.Source.m_unlocked)
				{
					_lastShownCurrent.TryGetValue(item2, out var value2);
					float num = Mathf.Max(0f, pendingToast.Current - value2);
					if (!(num < 0.001f))
					{
						ShowNow(pendingToast.Tracked, num, pendingToast.Current, pendingToast.Total);
					}
				}
			}
		}

		private void ShowNow(TrackedAchievement tracked, float delta, float current, float total)
		{
			ToastNotifier.Show(tracked, delta, current, total);
			_lastShownCurrent[tracked.Id] = current;
		}

		public void ResetSession()
		{
			_pending.Clear();
			_coalesceDeadline.Clear();
			_lastShownCurrent.Clear();
			lock (_eventLock)
			{
				_statEvents.Clear();
				_dictEvents.Clear();
			}
		}
	}
	public sealed class TrackedAchievement
	{
		public struct StatGoal
		{
			public PlayerStatType Stat;

			public float Target;
		}

		public struct DictGoal
		{
			public DictChannel Channel;

			public string Key;

			public float Target;
		}

		public enum DictChannel
		{
			Enemy,
			ItemPickup,
			ItemCraft,
			FoodEaten,
			Pickable,
			PiecePlaced
		}

		public Achievement Source;

		public string Id;

		public ProgressKind Kind;

		public bool UseSpamCooldown;

		public readonly List<StatGoal> StatGoals = new List<StatGoal>();

		public readonly List<DictGoal> DictGoals = new List<DictGoal>();

		public readonly List<Achievement> MetaGoals = new List<Achievement>();
	}
}
namespace AchievementProgress.Config
{
	public static class ModConfig
	{
		public static ConfigEntry<bool> Enabled;

		public static ConfigEntry<bool> EnableNotifications;

		public static ConfigEntry<bool> EnableDirectionalIndicator;

		public static ConfigEntry<string> PinnedAchievementIds;

		public static ConfigEntry<bool> RevealHiddenRequirements;

		public static ConfigEntry<bool> HideCompletedRequirements;

		public static ConfigEntry<string> IndicatorAnchor;

		public static ConfigEntry<float> IndicatorOffsetX;

		public static ConfigEntry<float> IndicatorOffsetY;

		public static ConfigEntry<float> IndicatorWidth;

		public static ConfigEntry<bool> IndicatorAutoHideOverlays;

		public static ConfigEntry<bool> IndicatorUseCustomPosition;

		public static ConfigEntry<float> IndicatorCustomNormX;

		public static ConfigEntry<float> IndicatorCustomNormY;

		private static ConfigFile _config;

		public static ConfigEntry<bool> EnableCounterToasts;

		public static ConfigEntry<bool> EnableCollectionToasts;

		public static ConfigEntry<bool> EnableMetaToasts;

		public static ConfigEntry<bool> EnableBinaryUnlockToasts;

		public static ConfigEntry<float> SpamCooldownSeconds;

		public static ConfigEntry<float> SailCooldownSeconds;

		public static ConfigEntry<bool> ShowPlusDelta;

		public static ConfigEntry<bool> ShowTotal;

		public static ConfigEntry<bool> RevealSecretsInToasts;

		public static ConfigEntry<bool> ReplaceUnlockLogBanner;

		public static ConfigEntry<string> ProgressBannerText;

		public static ConfigEntry<string> DisabledAchievementIds;

		public static ConfigEntry<bool> EnableDebugLogs;

		private static HashSet<string> _disabledIds;

		public static void Bind(ConfigFile config)
		{
			_config = config;
			Enabled = config.Bind<bool>("General", "Enabled", true, "Activa o desactiva el mod por completo.");
			EnableNotifications = config.Bind<bool>("General", "EnableNotifications", true, "Muestra notificaciones de progreso de logros.");
			EnableDirectionalIndicator = config.