Decompiled source of FavoriteItems v1.2.0

plugins/FavoriteItems.dll

Decompiled a month ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using FavoriteItems.API;
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: AssemblyTitle("FavoriteItems")]
[assembly: AssemblyDescription("Favorite inventory stacks and an integration API for Valheim")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("FavoriteItems")]
[assembly: AssemblyCopyright("Copyright (c) 2026 Ronaldo Donizeti")]
[assembly: ComVisible(false)]
[assembly: Guid("8c58b898-40d5-4c74-912d-cd2af0abf1f0")]
[assembly: AssemblyFileVersion("1.2.0.0")]
[assembly: AssemblyInformationalVersion("1.2.0")]
[assembly: AssemblyVersion("1.2.0.0")]
[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 FavoriteItems
{
	internal static class EquipmentAndQuickSlotsIntegration
	{
		internal const string PluginGuid = "randyknapp.mods.equipmentandquickslots";

		private static MethodInfo _isSlotCell;

		private static bool _warned;

		internal static void Initialize()
		{
			Type type = Type.GetType("EquipmentAndQuickSlots.API, EquipmentAndQuickSlots", throwOnError: false);
			if (type == null)
			{
				FavoriteItemsPlugin.Log.LogInfo((object)"EquipmentAndQuickSlots was not detected; favorite protection remains active.");
				return;
			}
			_isSlotCell = type.GetMethod("IsSlotCell", BindingFlags.Static | BindingFlags.Public, null, new Type[3]
			{
				typeof(int),
				typeof(int),
				typeof(string).MakeByRefType()
			}, null);
			if (_isSlotCell == null)
			{
				FavoriteItemsPlugin.Log.LogWarning((object)"EquipmentAndQuickSlots was detected, but the IsSlotCell API is unavailable.");
				return;
			}
			FavoriteItemsApi.RegisterProtectionProvider("randyknapp.mods.equipmentandquickslots", IsProtectedSlot);
			FavoriteItemsPlugin.Log.LogInfo((object)"Automatic EquipmentAndQuickSlots slot protection is active.");
		}

		internal static void Shutdown()
		{
			FavoriteItemsApi.UnregisterProtectionProvider("randyknapp.mods.equipmentandquickslots");
			_isSlotCell = null;
			_warned = false;
		}

		internal static bool IsProtectedSlot(ItemData item)
		{
			if (item == null || _isSlotCell == null || !FavoriteItemsPlugin.ProtectEquipmentAndQuickSlots.Value)
			{
				return false;
			}
			try
			{
				object[] parameters = new object[3]
				{
					item.m_gridPos.x,
					item.m_gridPos.y,
					null
				};
				return (bool)_isSlotCell.Invoke(null, parameters);
			}
			catch (Exception ex)
			{
				if (!_warned)
				{
					_warned = true;
					FavoriteItemsPlugin.Log.LogWarning((object)("Failed to query the EquipmentAndQuickSlots API: " + ex.Message));
				}
				return false;
			}
		}
	}
	internal static class ExtraSlotsIntegration
	{
		internal const string PluginGuid = "shudnal.ExtraSlots";

		private static MethodInfo _isItemInSlot;

		private static bool _warned;

		internal static void Initialize()
		{
			Type type = Type.GetType("ExtraSlots.API, ExtraSlots", throwOnError: false);
			if (type == null)
			{
				FavoriteItemsPlugin.Log.LogInfo((object)"ExtraSlots was not detected; favorite protection remains active.");
				return;
			}
			_isItemInSlot = type.GetMethod("IsItemInSlot", BindingFlags.Static | BindingFlags.Public, null, new Type[1] { typeof(ItemData) }, null);
			if (_isItemInSlot == null || _isItemInSlot.ReturnType != typeof(bool))
			{
				FavoriteItemsPlugin.Log.LogWarning((object)"ExtraSlots was detected, but the IsItemInSlot API is unavailable.");
				return;
			}
			FavoriteItemsApi.RegisterProtectionProvider("shudnal.ExtraSlots", IsProtectedSlot);
			FavoriteItemsPlugin.Log.LogInfo((object)"Optional ExtraSlots slot protection is available.");
		}

		internal static void Shutdown()
		{
			FavoriteItemsApi.UnregisterProtectionProvider("shudnal.ExtraSlots");
			_isItemInSlot = null;
			_warned = false;
		}

		internal static bool IsProtectedSlot(ItemData item)
		{
			if (item == null || _isItemInSlot == null || !FavoriteItemsPlugin.ProtectExtraSlots.Value)
			{
				return false;
			}
			try
			{
				return (bool)_isItemInSlot.Invoke(null, new object[1] { item });
			}
			catch (Exception ex)
			{
				if (!_warned)
				{
					_warned = true;
					FavoriteItemsPlugin.Log.LogWarning((object)("Failed to query the ExtraSlots API: " + ex.Message));
				}
				return false;
			}
		}
	}
	[HarmonyPatch(typeof(InventoryGrid), "OnLeftDown")]
	internal static class FavoriteInputPatches
	{
		private static readonly MethodInfo GetButtonPosMethod = AccessTools.Method(typeof(InventoryGrid), "GetButtonPos", new Type[1] { typeof(GameObject) }, (Type[])null);

		[HarmonyPriority(800)]
		private static bool Prefix(InventoryGrid __instance, UIInputHandler __0)
		{
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			if (!FavoriteItemsPlugin.Enabled.Value || !AltIsPressed() || (Object)(object)__0 == (Object)null)
			{
				return true;
			}
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || __instance.GetInventory() != ((Humanoid)localPlayer).GetInventory() || GetButtonPosMethod == null)
			{
				return true;
			}
			try
			{
				Vector2i val = (Vector2i)GetButtonPosMethod.Invoke(__instance, new object[1] { ((Component)__0).gameObject });
				ItemData itemAt = __instance.GetInventory().GetItemAt(val.x, val.y);
				if (itemAt == null)
				{
					return true;
				}
				if (!FavoriteItemsApi.TryToggleFavorite(itemAt, out var isFavorite))
				{
					return true;
				}
				FavoriteManager.Notify(localPlayer, itemAt, isFavorite);
				return false;
			}
			catch (Exception ex)
			{
				FavoriteItemsPlugin.Log.LogWarning((object)("Could not toggle favorite state: " + ex.Message));
				return true;
			}
		}

		private static bool AltIsPressed()
		{
			if (!ZInput.GetKey((KeyCode)308, true))
			{
				return ZInput.GetKey((KeyCode)307, true);
			}
			return true;
		}
	}
	[BepInPlugin("com.ronaldo.valheim.favoriteitems", "FavoriteItems", "1.2.0")]
	[BepInProcess("valheim.exe")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public sealed class FavoriteItemsPlugin : BaseUnityPlugin
	{
		public const string PluginGuid = "com.ronaldo.valheim.favoriteitems";

		public const string PluginName = "FavoriteItems";

		public const string PluginVersion = "1.2.0";

		internal static ManualLogSource Log;

		internal static ConfigEntry<bool> Enabled;

		internal static ConfigEntry<bool> ShowMarker;

		internal static ConfigEntry<bool> ShowMessages;

		internal static ConfigEntry<bool> ProtectEquipmentAndQuickSlots;

		internal static ConfigEntry<bool> ProtectExtraSlots;

		private Harmony _harmony;

		private void Awake()
		{
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enables Alt-click favorite toggling, the visual marker, and quick-stack protection.");
			ShowMarker = ((BaseUnityPlugin)this).Config.Bind<bool>("Visual", "ShowMarker", true, "Shows a subtle star in the corner of favorite stacks.");
			ShowMessages = ((BaseUnityPlugin)this).Config.Bind<bool>("Visual", "ShowMessages", true, "Shows a short message when an item is favorited or unfavorited.");
			ProtectEquipmentAndQuickSlots = ((BaseUnityPlugin)this).Config.Bind<bool>("Compatibility", "ProtectEquipmentAndQuickSlots", false, "Automatically protects items in EquipmentAndQuickSlots special slots, even when they are not favorited.");
			ProtectExtraSlots = ((BaseUnityPlugin)this).Config.Bind<bool>("Compatibility", "ProtectExtraSlots", false, "Automatically protects items in ExtraSlots special slots, even when they are not favorited.");
			_harmony = new Harmony("com.ronaldo.valheim.favoriteitems");
			_harmony.PatchAll(typeof(FavoriteItemsPlugin).Assembly);
			EquipmentAndQuickSlotsIntegration.Initialize();
			ExtraSlotsIntegration.Initialize();
			GorilaChestIntegration.Initialize(_harmony);
			Log.LogInfo((object)"FavoriteItems 1.2.0 loaded. Use Alt+left-click to toggle favorites.");
		}

		private void OnDestroy()
		{
			EquipmentAndQuickSlotsIntegration.Shutdown();
			ExtraSlotsIntegration.Shutdown();
			ProtectionRegistry.Clear();
			FavoriteItemsApi.Shutdown();
			FavoriteVisualPatches.Cleanup();
			if (_harmony != null)
			{
				_harmony.UnpatchSelf();
			}
		}
	}
	internal static class FavoriteManager
	{
		internal const string FavoriteKey = "com.ronaldo.valheim.favoriteitems.favorite";

		internal static bool IsFavorite(ItemData item)
		{
			if (item != null && item.m_customData != null && item.m_customData.TryGetValue("com.ronaldo.valheim.favoriteitems.favorite", out var value))
			{
				return value == "1";
			}
			return false;
		}

		internal static bool SetFavorite(ItemData item, bool favorite)
		{
			if (item == null)
			{
				return false;
			}
			if (item.m_customData == null)
			{
				item.m_customData = new Dictionary<string, string>();
			}
			if (favorite)
			{
				item.m_customData["com.ronaldo.valheim.favoriteitems.favorite"] = "1";
			}
			else
			{
				item.m_customData.Remove("com.ronaldo.valheim.favoriteitems.favorite");
			}
			return favorite;
		}

		internal static void Notify(Player player, ItemData item, bool favorite)
		{
			if (!((Object)(object)player == (Object)null) && item != null && FavoriteItemsPlugin.ShowMessages.Value)
			{
				string text = ((item.m_shared != null) ? item.m_shared.m_name : "item");
				if (Localization.instance != null)
				{
					text = Localization.instance.Localize(text);
				}
				((Character)player).Message((MessageType)2, favorite ? ("★ Favorite: " + text) : ("☆ Removed from favorites: " + text), 0, (Sprite)null, false);
			}
		}
	}
	[HarmonyPatch(typeof(InventoryGrid), "UpdateGui")]
	internal static class FavoriteVisualPatches
	{
		private const string MarkerName = "FavoriteItems_Star";

		private static readonly List<GameObject> CreatedMarkers = new List<GameObject>();

		[HarmonyPriority(0)]
		private static void Postfix(InventoryGrid __instance, List<InventoryElement> ___m_elements)
		{
			if (___m_elements == null)
			{
				return;
			}
			Inventory inventory = __instance.GetInventory();
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || inventory != ((Humanoid)localPlayer).GetInventory())
			{
				return;
			}
			for (int i = 0; i < ___m_elements.Count; i++)
			{
				InventoryElement val = ___m_elements[i];
				if (!((Object)(object)val == (Object)null))
				{
					Transform val2 = ((Component)val).transform.Find("FavoriteItems_Star");
					if ((Object)(object)val2 != (Object)null)
					{
						((Component)val2).gameObject.SetActive(false);
					}
				}
			}
			if (!FavoriteItemsPlugin.Enabled.Value || !FavoriteItemsPlugin.ShowMarker.Value)
			{
				return;
			}
			int width = inventory.GetWidth();
			List<ItemData> allItems = inventory.GetAllItems();
			for (int j = 0; j < allItems.Count; j++)
			{
				ItemData val3 = allItems[j];
				if (!FavoriteManager.IsFavorite(val3))
				{
					continue;
				}
				int num = val3.m_gridPos.y * width + val3.m_gridPos.x;
				if (num < 0 || num >= ___m_elements.Count)
				{
					continue;
				}
				InventoryElement val4 = ___m_elements[num];
				if (!((Object)(object)val4 == (Object)null))
				{
					GameObject val5 = EnsureMarker(val4);
					if ((Object)(object)val5 != (Object)null)
					{
						val5.SetActive(true);
					}
				}
			}
		}

		private static GameObject EnsureMarker(InventoryElement element)
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Expected O, but got Unknown
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			Transform val = ((Component)element).transform.Find("FavoriteItems_Star");
			if ((Object)(object)val != (Object)null)
			{
				return ((Component)val).gameObject;
			}
			GameObject val2 = new GameObject("FavoriteItems_Star", new Type[1] { typeof(RectTransform) });
			val2.transform.SetParent(((Component)element).transform, false);
			val2.transform.SetAsLastSibling();
			RectTransform component = val2.GetComponent<RectTransform>();
			component.anchorMin = Vector2.zero;
			component.anchorMax = Vector2.one;
			component.offsetMin = Vector2.zero;
			component.offsetMax = Vector2.zero;
			TextMeshProUGUI val3 = val2.AddComponent<TextMeshProUGUI>();
			((TMP_Text)val3).text = "★";
			((TMP_Text)val3).fontSize = 14f;
			((TMP_Text)val3).fontStyle = (FontStyles)1;
			((TMP_Text)val3).alignment = (TextAlignmentOptions)260;
			((TMP_Text)val3).margin = new Vector4(0f, 1f, 2f, 0f);
			((Graphic)val3).color = new Color(1f, 0.78f, 0.15f, 0.95f);
			((Graphic)val3).raycastTarget = false;
			if ((Object)(object)element.m_amount != (Object)null)
			{
				((TMP_Text)val3).font = element.m_amount.font;
				((TMP_Text)val3).fontSharedMaterial = element.m_amount.fontSharedMaterial;
			}
			CreatedMarkers.Add(val2);
			return val2;
		}

		internal static void Cleanup()
		{
			for (int i = 0; i < CreatedMarkers.Count; i++)
			{
				if ((Object)(object)CreatedMarkers[i] != (Object)null)
				{
					Object.Destroy((Object)(object)CreatedMarkers[i]);
				}
			}
			CreatedMarkers.Clear();
		}
	}
	internal static class GorilaChestIntegration
	{
		internal const string PluginGuid = "dev.trentini.gorilachestmod";

		internal static void Initialize(Harmony harmony)
		{
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Expected O, but got Unknown
			Type type = Type.GetType("GorilaChestMod.QuickStack, GorilaChestMod", throwOnError: false);
			if (type == null)
			{
				FavoriteItemsPlugin.Log.LogInfo((object)"GorilaChestMod was not detected; favorites and the visual marker remain active.");
				return;
			}
			MethodInfo methodInfo = AccessTools.Method(type, "CanMove", new Type[3]
			{
				typeof(Player),
				typeof(Inventory),
				typeof(ItemData)
			}, (Type[])null);
			MethodInfo methodInfo2 = AccessTools.Method(typeof(GorilaChestIntegration), "CanMovePostfix", (Type[])null, (Type[])null);
			if (methodInfo == null || methodInfo2 == null || methodInfo.ReturnType != typeof(bool))
			{
				FavoriteItemsPlugin.Log.LogWarning((object)"GorilaChestMod was detected, but QuickStack.CanMove has changed; protection was not applied.");
				return;
			}
			harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			FavoriteItemsPlugin.Log.LogInfo((object)"GorilaChestMod quick-stack protection is active.");
		}

		public static void CanMovePostfix(ItemData __2, ref bool __result)
		{
			if (__result && __2 != null && FavoriteItemsApi.ShouldPreventAutomaticMove(__2))
			{
				__result = false;
			}
		}
	}
	internal static class ProtectionRegistry
	{
		private sealed class ProviderEntry
		{
			internal string OwnerId;

			internal Func<ItemData, bool> Provider;
		}

		private static readonly object SyncRoot = new object();

		private static readonly Dictionary<string, Func<ItemData, bool>> Providers = new Dictionary<string, Func<ItemData, bool>>(StringComparer.Ordinal);

		private static readonly HashSet<string> WarnedProviders = new HashSet<string>(StringComparer.Ordinal);

		internal static bool Register(string ownerId, Func<ItemData, bool> provider)
		{
			if (string.IsNullOrWhiteSpace(ownerId) || provider == null)
			{
				return false;
			}
			lock (SyncRoot)
			{
				Providers[ownerId] = provider;
				WarnedProviders.Remove(ownerId);
			}
			return true;
		}

		internal static bool Unregister(string ownerId)
		{
			if (string.IsNullOrWhiteSpace(ownerId))
			{
				return false;
			}
			lock (SyncRoot)
			{
				WarnedProviders.Remove(ownerId);
				return Providers.Remove(ownerId);
			}
		}

		internal static bool IsProtected(ItemData item)
		{
			if (item == null)
			{
				return false;
			}
			ProviderEntry[] array;
			lock (SyncRoot)
			{
				array = new ProviderEntry[Providers.Count];
				int num = 0;
				foreach (KeyValuePair<string, Func<ItemData, bool>> provider in Providers)
				{
					ProviderEntry providerEntry = new ProviderEntry();
					providerEntry.OwnerId = provider.Key;
					providerEntry.Provider = provider.Value;
					array[num++] = providerEntry;
				}
			}
			for (int i = 0; i < array.Length; i++)
			{
				try
				{
					if (array[i].Provider(item))
					{
						return true;
					}
				}
				catch (Exception ex)
				{
					bool flag;
					lock (SyncRoot)
					{
						flag = WarnedProviders.Add(array[i].OwnerId);
					}
					if (flag)
					{
						LogWarning("Protection provider '" + array[i].OwnerId + "' failed: " + ex.Message);
					}
				}
			}
			return false;
		}

		internal static void Clear()
		{
			lock (SyncRoot)
			{
				Providers.Clear();
				WarnedProviders.Clear();
			}
		}

		private static void LogWarning(string message)
		{
			if (FavoriteItemsPlugin.Log != null)
			{
				FavoriteItemsPlugin.Log.LogWarning((object)message);
			}
		}
	}
	internal static class StackSafetyPatches
	{
		internal sealed class StackSnapshot
		{
			internal readonly List<StackEntry> Entries = new List<StackEntry>();
		}

		internal sealed class StackEntry
		{
			internal ItemData Item;

			internal int Amount;
		}

		[HarmonyPatch(typeof(Inventory), "AddItem", new Type[] { typeof(ItemData) })]
		internal static class AddItemWholePatch
		{
			private static void Prefix(Inventory __instance, ItemData __0, out StackSnapshot __state)
			{
				__state = null;
				if (!FavoriteItemsPlugin.Enabled.Value || !FavoriteManager.IsFavorite(__0) || __instance == null || __0.m_shared == null)
				{
					return;
				}
				StackSnapshot stackSnapshot = new StackSnapshot();
				List<ItemData> allItems = __instance.GetAllItems();
				for (int i = 0; i < allItems.Count; i++)
				{
					ItemData val = allItems[i];
					if (val != null && val.m_shared != null && val.IsSameType(__0) && val.m_stack < val.m_shared.m_maxStackSize)
					{
						StackEntry stackEntry = new StackEntry();
						stackEntry.Item = val;
						stackEntry.Amount = val.m_stack;
						stackSnapshot.Entries.Add(stackEntry);
					}
				}
				__state = stackSnapshot;
			}

			private static void Postfix(StackSnapshot __state)
			{
				if (__state == null)
				{
					return;
				}
				for (int i = 0; i < __state.Entries.Count; i++)
				{
					StackEntry stackEntry = __state.Entries[i];
					if (stackEntry.Item != null && stackEntry.Item.m_stack > stackEntry.Amount)
					{
						FavoriteManager.SetFavorite(stackEntry.Item, favorite: true);
					}
				}
			}
		}

		[HarmonyPatch(typeof(Inventory), "AddItem", new Type[]
		{
			typeof(ItemData),
			typeof(int),
			typeof(int),
			typeof(int),
			typeof(bool)
		})]
		internal static class AddItemAtPositionPatch
		{
			private static void Prefix(Inventory __instance, ItemData __0, int __1, int __2, int __3)
			{
				if (FavoriteItemsPlugin.Enabled.Value && FavoriteManager.IsFavorite(__0) && __instance != null && __0 != null && __0.m_shared != null && __1 > 0)
				{
					ItemData itemAt = __instance.GetItemAt(__2, __3);
					if (itemAt != null && itemAt.IsSameType(__0) && itemAt.m_shared != null && itemAt.m_stack < itemAt.m_shared.m_maxStackSize)
					{
						FavoriteManager.SetFavorite(itemAt, favorite: true);
					}
				}
			}
		}
	}
}
namespace FavoriteItems.API
{
	public static class FavoriteItemsApi
	{
		public const int ApiVersion = 1;

		public static bool IsEnabled
		{
			get
			{
				if (FavoriteItemsPlugin.Enabled != null)
				{
					return FavoriteItemsPlugin.Enabled.Value;
				}
				return false;
			}
		}

		public static event Action<ItemData, bool> FavoriteChanged;

		public static bool IsFavorite(ItemData item)
		{
			return FavoriteManager.IsFavorite(item);
		}

		public static bool ShouldPreventAutomaticMove(ItemData item)
		{
			if (!IsEnabled || item == null)
			{
				return false;
			}
			if (!FavoriteManager.IsFavorite(item))
			{
				return ProtectionRegistry.IsProtected(item);
			}
			return true;
		}

		public static bool TrySetFavorite(ItemData item, bool favorite)
		{
			if (!IsEnabled || item == null)
			{
				return false;
			}
			if (FavoriteManager.IsFavorite(item) == favorite)
			{
				return true;
			}
			FavoriteManager.SetFavorite(item, favorite);
			RaiseFavoriteChanged(item, favorite);
			return true;
		}

		public static bool TryToggleFavorite(ItemData item, out bool isFavorite)
		{
			isFavorite = FavoriteManager.IsFavorite(item);
			if (!IsEnabled || item == null)
			{
				return false;
			}
			isFavorite = !isFavorite;
			FavoriteManager.SetFavorite(item, isFavorite);
			RaiseFavoriteChanged(item, isFavorite);
			return true;
		}

		public static bool RegisterProtectionProvider(string ownerId, Func<ItemData, bool> provider)
		{
			return ProtectionRegistry.Register(ownerId, provider);
		}

		public static bool UnregisterProtectionProvider(string ownerId)
		{
			return ProtectionRegistry.Unregister(ownerId);
		}

		internal static void Shutdown()
		{
			FavoriteItemsApi.FavoriteChanged = null;
		}

		private static void RaiseFavoriteChanged(ItemData item, bool favorite)
		{
			Action<ItemData, bool> favoriteChanged = FavoriteItemsApi.FavoriteChanged;
			if (favoriteChanged == null)
			{
				return;
			}
			Delegate[] invocationList = favoriteChanged.GetInvocationList();
			for (int i = 0; i < invocationList.Length; i++)
			{
				try
				{
					((Action<ItemData, bool>)invocationList[i])(item, favorite);
				}
				catch (Exception ex)
				{
					if (FavoriteItemsPlugin.Log != null)
					{
						FavoriteItemsPlugin.Log.LogWarning((object)("A FavoriteChanged subscriber failed: " + ex.Message));
					}
				}
			}
		}
	}
}