Decompiled source of CraftFromChests v1.0.1

CraftFromChests.dll

Decompiled 5 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("CraftFromChests")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("CraftFromChests")]
[assembly: AssemblyTitle("CraftFromChests")]
[assembly: AssemblyVersion("1.0.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 CraftFromChests
{
	[BepInPlugin("GamerOff02.craftfromchests", "Craft From Chests", "1.0.1")]
	public class Plugin : BaseUnityPlugin
	{
		public const string GUID = "GamerOff02.craftfromchests";

		internal static ConfigEntry<bool> Enabled;

		internal static ConfigEntry<bool> DebugLog;

		internal static ConfigEntry<float> Radius;

		internal static ManualLogSource Log;

		private void Awake()
		{
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Включить мод");
			Radius = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Radius", 20f, "Радиус (в метрах) вокруг игрока, в котором ищутся сундуки");
			DebugLog = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "DebugLog", false, "Писать в лог, сколько сундуков найдено (для диагностики)");
			Harmony val = new Harmony("GamerOff02.craftfromchests");
			Type[] types = typeof(Plugin).Assembly.GetTypes();
			foreach (Type type in types)
			{
				if (type.GetCustomAttributes(typeof(HarmonyPatch), inherit: true).Length != 0)
				{
					try
					{
						val.CreateClassProcessor(type).Patch();
						Log.LogInfo((object)("Patched: " + type.Name));
					}
					catch (Exception ex)
					{
						Log.LogError((object)("FAILED patch " + type.Name + ": " + ex.Message));
					}
				}
			}
			Log.LogInfo((object)"Craft From Chests loaded");
		}
	}
	internal static class Chests
	{
		private static readonly MethodInfo SaveMethod = AccessTools.Method(typeof(Container), "Save", (Type[])null, (Type[])null);

		private static readonly MethodInfo CheckAccessMethod = AccessTools.Method(typeof(Container), "CheckAccess", new Type[1] { typeof(long) }, (Type[])null);

		private static readonly FieldInfo AllContainersField = typeof(Container).GetFields(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault((FieldInfo f) => f.FieldType == typeof(List<Container>));

		public static int CraftDepth;

		public static bool Suppress;

		private static List<Container> _cache = new List<Container>();

		private static float _cacheTime = -10f;

		private static float _lastLog = -10f;

		private static bool _accessErrorLogged;

		public static bool InCraftContext
		{
			get
			{
				if (CraftDepth > 0)
				{
					return !Suppress;
				}
				return false;
			}
		}

		public static List<Container> Nearby()
		{
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: 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)
			Player localPlayer = Player.m_localPlayer;
			if (!Plugin.Enabled.Value || (Object)(object)localPlayer == (Object)null)
			{
				return new List<Container>();
			}
			if (Time.time - _cacheTime < 0.5f)
			{
				return _cache;
			}
			_cacheTime = Time.time;
			List<Container> list = ((AllContainersField != null) ? (AllContainersField.GetValue(null) as List<Container>) : null);
			if (list == null || list.Count == 0)
			{
				list = Object.FindObjectsOfType<Container>().ToList();
			}
			List<Container> list2 = new List<Container>();
			int num = 0;
			float value = Plugin.Radius.Value;
			Vector3 position = ((Component)localPlayer).transform.position;
			long playerID = localPlayer.GetPlayerID();
			foreach (Container item in list)
			{
				if ((Object)(object)item == (Object)null || item.GetInventory() == null)
				{
					continue;
				}
				ZNetView component = ((Component)item).GetComponent<ZNetView>();
				if (!((Object)(object)component == (Object)null) && component.IsValid() && !(Vector3.Distance(((Component)item).transform.position, position) > value))
				{
					num++;
					if (HasAccess(item, playerID))
					{
						list2.Add(item);
					}
				}
			}
			if (Plugin.DebugLog.Value && Time.time - _lastLog > 5f)
			{
				_lastLog = Time.time;
				Plugin.Log.LogInfo((object)$"Containers: total={list.Count}, in radius={num}, accessible={list2.Count}");
			}
			_cache = list2;
			return list2;
		}

		private static bool HasAccess(Container c, long playerId)
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (CheckAccessMethod != null && !(bool)CheckAccessMethod.Invoke(c, new object[1] { playerId }))
				{
					return false;
				}
				if (!PrivateArea.CheckAccess(((Component)c).transform.position, 0f, false, false))
				{
					return false;
				}
				return true;
			}
			catch (Exception ex)
			{
				if (!_accessErrorLogged)
				{
					_accessErrorLogged = true;
					Plugin.Log.LogWarning((object)("Access check failed: " + ex.Message));
				}
				return false;
			}
		}

		public static int RawCount(Inventory inv, string name, int quality = -1)
		{
			bool suppress = Suppress;
			Suppress = true;
			try
			{
				return inv.CountItems(name, quality, true);
			}
			finally
			{
				Suppress = suppress;
			}
		}

		public static int Count(string name, int quality = -1)
		{
			int num = 0;
			foreach (Container item in Nearby())
			{
				num += RawCount(item.GetInventory(), name, quality);
			}
			return num;
		}

		public static int Remove(string name, int amount, int quality = -1)
		{
			int num = amount;
			foreach (Container item in Nearby())
			{
				if (num <= 0)
				{
					break;
				}
				Inventory inventory = item.GetInventory();
				int num2 = RawCount(inventory, name, quality);
				if (num2 > 0)
				{
					int num3 = Math.Min(num2, num);
					ZNetView component = ((Component)item).GetComponent<ZNetView>();
					if ((Object)(object)component != (Object)null)
					{
						component.ClaimOwnership();
					}
					inventory.RemoveItem(name, num3, quality, true);
					if (SaveMethod != null)
					{
						SaveMethod.Invoke(item, null);
					}
					num -= num3;
				}
			}
			_cacheTime = -10f;
			return amount - num;
		}

		public static bool Enough(Player player, Requirement[] reqs, int quality, int multiplier)
		{
			Inventory inventory = ((Humanoid)player).GetInventory();
			foreach (Requirement val in reqs)
			{
				if ((Object)(object)val.m_resItem == (Object)null)
				{
					continue;
				}
				int num = val.GetAmount(quality) * multiplier;
				if (num > 0)
				{
					string name = val.m_resItem.m_itemData.m_shared.m_name;
					if (RawCount(inventory, name) + Count(name) < num)
					{
						return false;
					}
				}
			}
			return true;
		}

		public static bool IsPlayerInventory(Inventory inv)
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer != (Object)null)
			{
				return inv == ((Humanoid)localPlayer).GetInventory();
			}
			return false;
		}
	}
	[HarmonyPatch]
	internal static class CraftContext_Patch
	{
		private static readonly string[] InventoryGuiNames = new string[4] { "UpdateRecipe", "SetRecipe", "UpdateRecipeList", "SetupRequirement" };

		private static readonly string[] HudNames = new string[4] { "UpdateBuild", "UpdatePieceBuildStatus", "SetupPieceInfo", "UpdatePieceList" };

		private static IEnumerable<MethodBase> TargetMethods()
		{
			foreach (MethodInfo declaredMethod in AccessTools.GetDeclaredMethods(typeof(InventoryGui)))
			{
				if (InventoryGuiNames.Contains(declaredMethod.Name))
				{
					yield return declaredMethod;
				}
			}
			foreach (MethodInfo declaredMethod2 in AccessTools.GetDeclaredMethods(typeof(Hud)))
			{
				if (HudNames.Contains(declaredMethod2.Name))
				{
					yield return declaredMethod2;
				}
			}
		}

		[HarmonyPriority(800)]
		private static void Prefix()
		{
			Chests.CraftDepth++;
		}

		[HarmonyPriority(0)]
		private static void Finalizer()
		{
			if (Chests.CraftDepth > 0)
			{
				Chests.CraftDepth--;
			}
		}
	}
	[HarmonyPatch(typeof(Inventory), "CountItems")]
	internal static class CountItems_Patch
	{
		[HarmonyPriority(0)]
		private static void Postfix(Inventory __instance, ref int __result, object[] __args)
		{
			if (Chests.InCraftContext && Chests.IsPlayerInventory(__instance) && __args[0] is string name)
			{
				int quality = ((__args.Length > 1 && __args[1] is int) ? ((int)__args[1]) : (-1));
				__result += Chests.Count(name, quality);
			}
		}
	}
	[HarmonyPatch(typeof(Inventory), "HaveItem")]
	internal static class HaveItem_Patch
	{
		[HarmonyPriority(0)]
		private static void Postfix(Inventory __instance, ref bool __result, object[] __args)
		{
			if (!__result && Chests.InCraftContext && Chests.IsPlayerInventory(__instance) && __args[0] is string name && Chests.Count(name) > 0)
			{
				__result = true;
			}
		}
	}
	[HarmonyPatch(typeof(Player), "HaveRequirementItems")]
	internal static class HaveRequirementItems_Patch
	{
		[HarmonyPriority(0)]
		private static void Postfix(Player __instance, ref bool __result, object[] __args)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Expected O, but got Unknown
			if (__result || (Object)(object)__instance != (Object)(object)Player.m_localPlayer)
			{
				return;
			}
			try
			{
				Recipe val = (Recipe)__args[0];
				int quality = (int)__args[2];
				int multiplier = ((__args.Length <= 3 || !(__args[3] is int)) ? 1 : ((int)__args[3]));
				if (Chests.Enough(__instance, val.m_resources, quality, multiplier))
				{
					__result = true;
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("HaveRequirementItems: " + ex.Message));
			}
		}
	}
	[HarmonyPatch(typeof(Player), "HaveRequirements", new Type[]
	{
		typeof(Piece),
		typeof(RequirementMode)
	})]
	internal static class HaveRequirementsPiece_Patch
	{
		[HarmonyPriority(0)]
		private static void Postfix(Player __instance, ref bool __result, Piece piece, RequirementMode mode)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			if (__result || (int)mode != 0 || (Object)(object)__instance != (Object)(object)Player.m_localPlayer)
			{
				return;
			}
			try
			{
				if ((!((Object)(object)piece.m_craftingStation != (Object)null) || Object.op_Implicit((Object)(object)CraftingStation.HaveBuildStationInRange(piece.m_craftingStation.m_name, ((Component)__instance).transform.position))) && (string.IsNullOrEmpty(piece.m_dlc) || DLCMan.instance.IsDLCInstalled(piece.m_dlc)) && Chests.Enough(__instance, piece.m_resources, 1, 1))
				{
					__result = true;
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("HaveRequirements(Piece): " + ex.Message));
			}
		}
	}
	[HarmonyPatch(typeof(Player), "ConsumeResources")]
	internal static class ConsumeResources_Patch
	{
		[HarmonyPriority(800)]
		private static void Prefix(Player __instance, object[] __args)
		{
			if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer)
			{
				return;
			}
			try
			{
				Requirement[] obj = (Requirement[])__args[0];
				int num = (int)__args[1];
				int quality = ((__args.Length > 2 && __args[2] is int) ? ((int)__args[2]) : (-1));
				int num2 = ((__args.Length <= 3 || !(__args[3] is int)) ? 1 : ((int)__args[3]));
				Inventory inventory = ((Humanoid)__instance).GetInventory();
				Requirement[] array = obj;
				foreach (Requirement val in array)
				{
					if ((Object)(object)val.m_resItem == (Object)null)
					{
						continue;
					}
					int num3 = val.GetAmount(num) * num2;
					if (num3 <= 0)
					{
						continue;
					}
					string name = val.m_resItem.m_itemData.m_shared.m_name;
					int num4 = num3 - Chests.RawCount(inventory, name, quality);
					if (num4 > 0)
					{
						int num5 = Chests.Remove(name, num4, quality);
						if (Plugin.DebugLog.Value)
						{
							Plugin.Log.LogInfo((object)$"Took {num5}/{num4} x {name} from chests");
						}
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("ConsumeResources: " + ex.Message));
			}
		}
	}
}