Decompiled source of HiveinInventory v1.4.1

BeehiveInventory.dll

Decompiled 3 days ago
using System;
using System.Collections;
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 BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("BeehiveInventory")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("BeehiveInventory")]
[assembly: AssemblyTitle("BeehiveInventory")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.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 BeehiveInventory
{
	[BepInPlugin("haruhi.peak.beehiveinventory", "Beehive Inventory", "1.0.0")]
	public sealed class BeehiveInventoryPlugin : BaseUnityPlugin
	{
		public const string ModGuid = "haruhi.peak.beehiveinventory";

		public const string ModName = "Beehive Inventory";

		public const string ModVersion = "1.0.0";

		internal static ManualLogSource Log;

		internal static ushort? BeehiveItemId;

		private void Awake()
		{
			Log = ((BaseUnityPlugin)this).Logger;
			try
			{
				Harmony.CreateAndPatchAll(typeof(BeehiveInventoryPlugin).Assembly, "haruhi.peak.beehiveinventory");
				Log.LogInfo((object)"[Beehive Inventory] loaded.");
			}
			catch (Exception arg)
			{
				Log.LogError((object)string.Format("[{0}] Harmony patching failed: {1}", "Beehive Inventory", arg));
			}
			TryWarmupBeehivePrefab();
		}

		private void Update()
		{
			if (!BeehiveItemId.HasValue)
			{
				TryWarmupBeehivePrefab();
			}
		}

		private static void TryWarmupBeehivePrefab()
		{
			try
			{
				ushort itemId;
				Item val = TryFindBeehivePrefab(out itemId);
				if (!((Object)(object)val == (Object)null))
				{
					BeehiveItemId = itemId;
					if (EnsureBeehiveIsStorable(val))
					{
						Log.LogInfo((object)string.Format("[{0}] Beehive unlocked for inventory/backpack. itemID={1}", "Beehive Inventory", itemId));
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = Log;
				if (log != null)
				{
					log.LogDebug((object)("[Beehive Inventory] warmup failed (will retry): " + ex.Message));
				}
			}
		}

		internal static bool IsBeehiveItemId(ushort itemId)
		{
			if (BeehiveItemId.HasValue && itemId == BeehiveItemId.Value)
			{
				return true;
			}
			try
			{
				Item val = default(Item);
				if (ItemDatabase.TryGetItem(itemId, ref val) && (Object)(object)val != (Object)null)
				{
					return IsBeehivePrefab(val);
				}
			}
			catch
			{
			}
			return false;
		}

		internal static bool IsBeehivePrefab(Item item)
		{
			try
			{
				string text = ((Object)item).name ?? string.Empty;
				if (text.IndexOf("Beehive", StringComparison.OrdinalIgnoreCase) >= 0)
				{
					return true;
				}
				ItemUIData uIData = item.UIData;
				if (uIData != null)
				{
					FieldInfo fieldInfo = AccessTools.Field(((object)uIData).GetType(), "itemName");
					if (fieldInfo != null)
					{
						string text2 = fieldInfo.GetValue(uIData) as string;
						if (!string.IsNullOrWhiteSpace(text2) && text2.IndexOf("Beehive", StringComparison.OrdinalIgnoreCase) >= 0)
						{
							return true;
						}
					}
				}
			}
			catch
			{
			}
			return false;
		}

		internal static Item? TryFindBeehivePrefab(out ushort itemId)
		{
			itemId = 0;
			if (BeehiveItemId.HasValue)
			{
				try
				{
					Item val = default(Item);
					if (ItemDatabase.TryGetItem(BeehiveItemId.Value, ref val) && (Object)(object)val != (Object)null)
					{
						itemId = val.itemID;
						return val;
					}
				}
				catch
				{
				}
			}
			ItemDatabase val2 = Resources.FindObjectsOfTypeAll<ItemDatabase>().FirstOrDefault();
			if ((Object)(object)val2 == (Object)null)
			{
				return null;
			}
			Type type = ((object)val2).GetType();
			FieldInfo fieldInfo = AccessTools.Field(type, "itemLookup");
			if (fieldInfo != null && fieldInfo.GetValue(val2) is IDictionary dictionary)
			{
				foreach (DictionaryEntry item in dictionary)
				{
					object? value = item.Value;
					Item val3 = (Item)((value is Item) ? value : null);
					if (val3 != null && (Object)(object)val3 != (Object)null && IsBeehivePrefab(val3))
					{
						itemId = val3.itemID;
						return val3;
					}
				}
			}
			PropertyInfo propertyInfo = AccessTools.Property(type, "Objects");
			if (propertyInfo != null && propertyInfo.GetValue(val2) is IEnumerable enumerable)
			{
				foreach (object item2 in enumerable)
				{
					Item val4 = (Item)((item2 is Item) ? item2 : null);
					if (val4 != null && (Object)(object)val4 != (Object)null && IsBeehivePrefab(val4))
					{
						itemId = val4.itemID;
						return val4;
					}
				}
			}
			FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (FieldInfo fieldInfo2 in fields)
			{
				try
				{
					object value2 = fieldInfo2.GetValue(val2);
					if (!(value2 is IEnumerable enumerable2))
					{
						continue;
					}
					foreach (object item3 in enumerable2)
					{
						Item val5 = (Item)((item3 is Item) ? item3 : null);
						if (val5 != null && (Object)(object)val5 != (Object)null && IsBeehivePrefab(val5))
						{
							itemId = val5.itemID;
							return val5;
						}
					}
				}
				catch
				{
				}
			}
			return null;
		}

		internal static bool EnsureBeehiveIsStorable(Item beehivePrefab)
		{
			bool flag = false;
			try
			{
				ItemUIData uIData = beehivePrefab.UIData;
				if (uIData != null)
				{
					flag |= TrySetBoolMember(uIData, "canDrop", value: true);
					flag |= TrySetBoolMember(uIData, "canThrow", value: true);
					flag |= EnableBoolMembersByKeywords(uIData, new string[8] { "inventory", "backpack", "store", "stow", "pocket", "slot", "stash", "carry" });
				}
			}
			catch
			{
			}
			try
			{
				flag |= EnableBoolMembersByKeywords(beehivePrefab, new string[7] { "inventory", "backpack", "store", "stow", "pocket", "slot", "stash" });
			}
			catch
			{
			}
			try
			{
				flag |= ClearRestrictiveItemTags(beehivePrefab);
			}
			catch
			{
			}
			return flag;
		}

		private static bool TrySetBoolMember(object target, string memberName, bool value)
		{
			Type type = target.GetType();
			FieldInfo fieldInfo = AccessTools.Field(type, memberName);
			if (fieldInfo != null && fieldInfo.FieldType == typeof(bool))
			{
				bool flag = (bool)fieldInfo.GetValue(target);
				if (flag != value)
				{
					fieldInfo.SetValue(target, value);
					return true;
				}
				return false;
			}
			PropertyInfo propertyInfo = AccessTools.Property(type, memberName);
			if (propertyInfo != null && propertyInfo.PropertyType == typeof(bool) && propertyInfo.CanWrite)
			{
				bool flag2 = (bool)propertyInfo.GetValue(target, null);
				if (flag2 != value)
				{
					propertyInfo.SetValue(target, value, null);
					return true;
				}
				return false;
			}
			return false;
		}

		private static bool EnableBoolMembersByKeywords(object target, string[] keywords)
		{
			bool result = false;
			Type type = target.GetType();
			FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (FieldInfo fieldInfo in fields)
			{
				if (fieldInfo.FieldType != typeof(bool) || !HasKeyword(fieldInfo.Name, keywords))
				{
					continue;
				}
				try
				{
					if (!(bool)fieldInfo.GetValue(target))
					{
						fieldInfo.SetValue(target, true);
						result = true;
					}
				}
				catch
				{
				}
			}
			PropertyInfo[] properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (PropertyInfo propertyInfo in properties)
			{
				if (propertyInfo.PropertyType != typeof(bool) || !propertyInfo.CanRead || !propertyInfo.CanWrite || !HasKeyword(propertyInfo.Name, keywords))
				{
					continue;
				}
				try
				{
					if (!(bool)propertyInfo.GetValue(target, null))
					{
						propertyInfo.SetValue(target, true, null);
						result = true;
					}
				}
				catch
				{
				}
			}
			return result;
			static bool HasKeyword(string name, string[] kws)
			{
				string name2 = name;
				return kws.Any((string k) => name2.IndexOf(k, StringComparison.OrdinalIgnoreCase) >= 0);
			}
		}

		private static bool ClearRestrictiveItemTags(Item item)
		{
			Type type = ((object)item).GetType();
			FieldInfo fieldInfo = AccessTools.Field(type, "itemTags");
			if (fieldInfo == null)
			{
				return false;
			}
			object value = fieldInfo.GetValue(item);
			if (value == null)
			{
				return false;
			}
			Type fieldType = fieldInfo.FieldType;
			if (!fieldType.IsEnum)
			{
				return false;
			}
			ulong num = Convert.ToUInt64(value);
			ulong num2 = num;
			foreach (object value2 in Enum.GetValues(fieldType))
			{
				string text = Enum.GetName(fieldType, value2) ?? string.Empty;
				if (!string.IsNullOrWhiteSpace(text))
				{
					bool flag = text.IndexOf("No", StringComparison.OrdinalIgnoreCase) >= 0 && (text.IndexOf("Inventory", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("Backpack", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("Store", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("Stow", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("Pocket", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("Slot", StringComparison.OrdinalIgnoreCase) >= 0);
					flag |= text.IndexOf("Cannot", StringComparison.OrdinalIgnoreCase) >= 0 && (text.IndexOf("Store", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("Stow", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("Inventory", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("Backpack", StringComparison.OrdinalIgnoreCase) >= 0);
					flag |= text.IndexOf("Unstorable", StringComparison.OrdinalIgnoreCase) >= 0;
					if (flag | (text.IndexOf("NotStorable", StringComparison.OrdinalIgnoreCase) >= 0))
					{
						ulong num3 = Convert.ToUInt64(value2);
						num2 &= ~num3;
					}
				}
			}
			if (num2 == num)
			{
				return false;
			}
			fieldInfo.SetValue(item, Enum.ToObject(fieldType, num2));
			return true;
		}
	}
	[HarmonyPatch(typeof(Player), "AddItem")]
	internal static class Player_AddItem_BeehiveRetryPatch
	{
		[ThreadStatic]
		private static bool _reentry;

		private static void Postfix(Player __instance, ushort itemID, ItemInstanceData instanceData, ref ItemSlot slot, ref bool __result)
		{
			if (__result || _reentry || !BeehiveInventoryPlugin.IsBeehiveItemId(itemID))
			{
				return;
			}
			try
			{
				_reentry = true;
				ushort itemId;
				Item val = BeehiveInventoryPlugin.TryFindBeehivePrefab(out itemId);
				if ((Object)(object)val != (Object)null)
				{
					BeehiveInventoryPlugin.BeehiveItemId = itemId;
					BeehiveInventoryPlugin.EnsureBeehiveIsStorable(val);
				}
				ItemSlot val2 = default(ItemSlot);
				if (__instance.AddItem(itemID, instanceData, ref val2))
				{
					slot = val2;
					__result = true;
					BeehiveInventoryPlugin.Log.LogInfo((object)$"[Beehive Inventory] Retry succeeded: Beehive stored (slot {slot.itemSlotID}).");
				}
				else
				{
					BeehiveInventoryPlugin.Log.LogWarning((object)"[Beehive Inventory] Retry failed: still cannot store Beehive. Game update might have changed checks.");
				}
			}
			catch (Exception arg)
			{
				BeehiveInventoryPlugin.Log.LogError((object)$"[Beehive Inventory] Error while retrying AddItem for Beehive: {arg}");
			}
			finally
			{
				_reentry = false;
			}
		}
	}
}