Decompiled source of CraftingStorageLink v1.5.1

CraftingStorageLink.dll

Decompiled 3 weeks ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
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.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("CraftingStorageLink")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.5.1.0")]
[assembly: AssemblyInformationalVersion("1.5.1")]
[assembly: AssemblyProduct("CraftingStorageLink")]
[assembly: AssemblyTitle("CraftingStorageLink")]
[assembly: AssemblyVersion("1.5.1.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 CraftingStorageLink
{
	[BepInPlugin("com.custom.valheim.craftingstoragelink", "CraftingStorageLink", "1.5.1")]
	public sealed class CraftingStorageLinkPlugin : BaseUnityPlugin
	{
		private sealed class CraftContext
		{
			public readonly Player Player;

			public readonly Inventory PlayerInventory;

			public readonly CraftingStation Station;

			public readonly Recipe Recipe;

			public CraftContext(Player player, CraftingStation station, Recipe recipe)
			{
				Player = player;
				PlayerInventory = ((Humanoid)player).GetInventory();
				Station = station;
				Recipe = recipe;
			}
		}

		private sealed class BuildContext
		{
			public readonly Player Player;

			public readonly Inventory PlayerInventory;

			public readonly CraftingStation Station;

			public readonly Piece Piece;

			public readonly Vector3 Origin;

			public BuildContext(Player player, CraftingStation station, Piece piece)
			{
				//IL_0044: Unknown result type (might be due to invalid IL or missing references)
				//IL_0037: 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)
				Player = player;
				PlayerInventory = ((Humanoid)player).GetInventory();
				Station = station;
				Piece = piece;
				Origin = (((Object)(object)station != (Object)null) ? ((Component)station).transform.position : ((Component)player).transform.position);
			}
		}

		private sealed class PullItem
		{
			public readonly string Name;

			public readonly int Quality;

			public int Amount;

			public PullItem(string name, int quality, int amount)
			{
				Name = name;
				Quality = quality;
				Amount = amount;
			}
		}

		private sealed class PullPlan
		{
			public readonly Player Player;

			public readonly CraftingStation Station;

			public readonly Vector3 Origin;

			public readonly List<PullItem> Items = new List<PullItem>();

			public PullPlan(Player player, CraftingStation station, Vector3 origin)
			{
				//IL_0020: 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)
				Player = player;
				Station = station;
				Origin = origin;
			}

			public void Add(string name, int quality, int amount)
			{
				if (amount <= 0)
				{
					return;
				}
				for (int i = 0; i < Items.Count; i++)
				{
					PullItem pullItem = Items[i];
					if (pullItem.Name == name && pullItem.Quality == quality)
					{
						pullItem.Amount += amount;
						return;
					}
				}
				Items.Add(new PullItem(name, quality, amount));
			}
		}

		private sealed class ContainerCandidate
		{
			public readonly Container Container;

			public readonly float DistanceSqr;

			public ContainerCandidate(Container container, float distanceSqr)
			{
				Container = container;
				DistanceSqr = distanceSqr;
			}
		}

		private enum LinkContextKind
		{
			Disabled,
			RecipeRequirement,
			RecipeDisplay,
			Crafting,
			BuildRequirement,
			BuildHudDisplay,
			Placement
		}

		private sealed class LinkContext
		{
			public readonly LinkContextKind Kind;

			public readonly Player Player;

			public readonly Inventory PlayerInventory;

			public readonly CraftingStation Station;

			public readonly Recipe Recipe;

			public readonly Piece Piece;

			public readonly Vector3 Origin;

			public readonly bool HasOrigin;

			public readonly bool Enabled;

			private LinkContext(LinkContextKind kind)
			{
				Kind = kind;
				Enabled = false;
			}

			public LinkContext(LinkContextKind kind, Player player, CraftingStation station, Recipe recipe)
			{
				//IL_0059: 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_005e: Unknown result type (might be due to invalid IL or missing references)
				Kind = kind;
				Player = player;
				PlayerInventory = (((Object)(object)player != (Object)null) ? ((Humanoid)player).GetInventory() : null);
				Station = station;
				Recipe = recipe;
				Piece = null;
				Origin = (((Object)(object)station != (Object)null) ? ((Component)station).transform.position : Vector3.zero);
				HasOrigin = (Object)(object)station != (Object)null;
				Enabled = (Object)(object)player != (Object)null && PlayerInventory != null && HasOrigin;
			}

			public LinkContext(LinkContextKind kind, Player player, CraftingStation station, Piece piece)
			{
				//IL_006f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0074: Unknown result type (might be due to invalid IL or missing references)
				//IL_0062: 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)
				Kind = kind;
				Player = player;
				PlayerInventory = (((Object)(object)player != (Object)null) ? ((Humanoid)player).GetInventory() : null);
				Station = station;
				Recipe = null;
				Piece = piece;
				Origin = (((Object)(object)station != (Object)null) ? ((Component)station).transform.position : (((Object)(object)player != (Object)null) ? ((Component)player).transform.position : Vector3.zero));
				HasOrigin = (Object)(object)player != (Object)null;
				Enabled = (Object)(object)player != (Object)null && PlayerInventory != null && (Object)(object)piece != (Object)null && HasOrigin;
			}

			public static LinkContext Disabled(LinkContextKind kind)
			{
				return new LinkContext(kind);
			}
		}

		private sealed class ContextGuard
		{
			private readonly LinkContext _context;

			private bool _disposed;

			public ContextGuard(LinkContext context)
			{
				_context = context;
			}

			public void Dispose()
			{
				if (_disposed)
				{
					return;
				}
				_disposed = true;
				Stack<LinkContext> contextStack = GetContextStack();
				if (contextStack.Count == 0)
				{
					return;
				}
				if (contextStack.Peek() == _context)
				{
					contextStack.Pop();
					return;
				}
				Stack<LinkContext> stack = new Stack<LinkContext>();
				while (contextStack.Count > 0 && contextStack.Peek() != _context)
				{
					stack.Push(contextStack.Pop());
				}
				if (contextStack.Count > 0)
				{
					contextStack.Pop();
				}
				while (stack.Count > 0)
				{
					contextStack.Push(stack.Pop());
				}
			}
		}

		[HarmonyPatch(typeof(ZNet), "OnNewConnection")]
		private static class ZNetOnNewConnectionPatch
		{
			private static void Postfix(ZNet __instance, ZNetPeer peer)
			{
				RegisterConfigRpc(__instance, peer);
			}
		}

		[HarmonyPatch(typeof(Player), "HaveRequirements", new Type[]
		{
			typeof(Recipe),
			typeof(bool),
			typeof(int),
			typeof(int)
		})]
		private static class PlayerHaveRecipeRequirementsPatch
		{
			private static void Prefix(Player __instance, Recipe recipe, bool discover, ref ContextGuard __state)
			{
				__state = BeginRequirementCheck(__instance, recipe, discover);
			}

			private static void Postfix(ContextGuard __state)
			{
				__state?.Dispose();
			}

			private static Exception Finalizer(Exception __exception, ContextGuard __state)
			{
				__state?.Dispose();
				return __exception;
			}
		}

		[HarmonyPatch(typeof(InventoryGui), "SetupRequirement", new Type[]
		{
			typeof(Transform),
			typeof(Requirement),
			typeof(Player),
			typeof(bool),
			typeof(int),
			typeof(int)
		})]
		private static class InventoryGuiSetupRequirementPatch
		{
			private static void Prefix(InventoryGui __instance, Player player, ref ContextGuard __state)
			{
				__state = BeginRequirementDisplay(__instance, player);
			}

			private static void Postfix(ContextGuard __state)
			{
				__state?.Dispose();
			}

			private static Exception Finalizer(Exception __exception, ContextGuard __state)
			{
				__state?.Dispose();
				return __exception;
			}
		}

		[HarmonyPatch(typeof(InventoryGui), "DoCrafting", new Type[] { typeof(Player) })]
		private static class InventoryGuiDoCraftingPatch
		{
			private static void Prefix(InventoryGui __instance, Player player, ref ContextGuard __state)
			{
				__state = BeginCrafting(__instance, player);
			}

			private static void Postfix(ContextGuard __state)
			{
				__state?.Dispose();
			}

			private static Exception Finalizer(Exception __exception, ContextGuard __state)
			{
				__state?.Dispose();
				return __exception;
			}
		}

		[HarmonyPatch(typeof(Player), "HaveRequirements", new Type[]
		{
			typeof(Piece),
			typeof(RequirementMode)
		})]
		private static class PlayerHavePieceRequirementsPatch
		{
			private static void Prefix(Player __instance, Piece piece, RequirementMode mode, ref ContextGuard __state)
			{
				//IL_0003: Unknown result type (might be due to invalid IL or missing references)
				__state = BeginBuildRequirementCheck(__instance, piece, mode);
			}

			private static void Postfix(ContextGuard __state)
			{
				__state?.Dispose();
			}

			private static Exception Finalizer(Exception __exception, ContextGuard __state)
			{
				__state?.Dispose();
				return __exception;
			}
		}

		[HarmonyPatch(typeof(Player), "UpdatePlacement", new Type[]
		{
			typeof(bool),
			typeof(float)
		})]
		private static class PlayerUpdatePlacementPatch
		{
			private static void Prefix(Player __instance, ref ContextGuard __state)
			{
				__state = BeginPlacement(__instance);
			}

			private static void Postfix(ContextGuard __state)
			{
				__state?.Dispose();
			}

			private static Exception Finalizer(Exception __exception, ContextGuard __state)
			{
				__state?.Dispose();
				return __exception;
			}
		}

		[HarmonyPatch]
		private static class HudSetupPieceInfoPatch
		{
			private static IEnumerable<MethodBase> TargetMethods()
			{
				MethodInfo[] methods = typeof(Hud).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				int i = 0;
				while (i < methods.Length)
				{
					if (methods[i].Name == "SetupPieceInfo")
					{
						yield return methods[i];
					}
					int num = i + 1;
					i = num;
				}
			}

			private static void Prefix(object[] __args, ref ContextGuard __state)
			{
				__state = BeginBuildHudDisplay(Player.m_localPlayer, __args);
			}

			private static void Postfix(ContextGuard __state)
			{
				__state?.Dispose();
			}

			private static Exception Finalizer(Exception __exception, ContextGuard __state)
			{
				__state?.Dispose();
				return __exception;
			}
		}

		[HarmonyPatch(typeof(Inventory), "HaveItem", new Type[]
		{
			typeof(string),
			typeof(bool)
		})]
		private static class InventoryHaveItemPatch
		{
			private static void Postfix(Inventory __instance, string name, bool matchWorldLevel, ref bool __result)
			{
				//IL_0036: Unknown result type (might be due to invalid IL or missing references)
				if (!__result && __instance != null)
				{
					LinkContext currentContext = CurrentContext;
					if (IsBuildContext(currentContext) && currentContext.Enabled && __instance == currentContext.PlayerInventory)
					{
						__result = CountLinkedItem(currentContext.Player, currentContext.Station, currentContext.Origin, name, -1, matchWorldLevel, 1) > 0;
					}
				}
			}
		}

		[HarmonyPatch(typeof(Inventory), "CountItems", new Type[]
		{
			typeof(string),
			typeof(int),
			typeof(bool)
		})]
		private static class InventoryCountItemsPatch
		{
			private static void Postfix(Inventory __instance, string name, int quality, bool matchWorldLevel, ref int __result)
			{
				AddLinkedCount(__instance, name, quality, matchWorldLevel, ref __result);
			}
		}

		[HarmonyPatch(typeof(Player), "ConsumeResources", new Type[]
		{
			typeof(Requirement[]),
			typeof(int),
			typeof(int),
			typeof(int)
		})]
		private static class PlayerConsumeResourcesPatch
		{
			private static void Prefix(Player __instance, Requirement[] requirements, int qualityLevel, int itemQuality, int multiplier, ref PullPlan __state)
			{
				__state = CreatePullPlan(__instance, requirements, qualityLevel, itemQuality, multiplier);
			}

			private static void Postfix(PullPlan __state)
			{
				PayPullPlan(__state);
			}
		}

		public const string PluginGuid = "com.custom.valheim.craftingstoragelink";

		public const string PluginName = "CraftingStorageLink";

		public const string PluginVersion = "1.5.1";

		private static ConfigEntry<bool> _enabled;

		private static ConfigEntry<bool> _hammerBuildingEnabled;

		private static ConfigEntry<float> _radius;

		private static ConfigEntry<bool> _playerBuiltOnly;

		private static ConfigEntry<bool> _allowShipContainers;

		private static ConfigEntry<bool> _allowCartContainers;

		private static ConfigEntry<bool> _respectContainerAccess;

		private static ConfigEntry<bool> _respectWards;

		private static ConfigEntry<bool> _skipInUseContainers;

		private static ConfigEntry<bool> _claimOwnershipWhenPulling;

		private static ConfigEntry<bool> _respectMultiUserChestIgnore;

		private static ConfigEntry<bool> _debugLogging;

		private const string ConfigRpcName = "CSL_Config_v1";

		private const int ConfigProtocolVersion = 1;

		private static bool _serverConfigReceived;

		private static bool _serverEnabled;

		private static bool _serverHammerBuildingEnabled;

		private static float _serverRadius;

		private static bool _serverPlayerBuiltOnly;

		private static bool _serverAllowShipContainers;

		private static bool _serverAllowCartContainers;

		private static bool _serverRespectContainerAccess;

		private static bool _serverRespectWards;

		private static bool _serverSkipInUseContainers;

		private static bool _serverClaimOwnershipWhenPulling;

		private static bool _serverRespectMultiUserChestIgnore;

		private static ManualLogSource _log;

		private static FieldInfo _inventoryGuiCraftRecipeField;

		private static FieldInfo _inventoryGuiSelectedRecipeField;

		private static FieldInfo _inventoryGuiCurrentContainerField;

		private static FieldInfo _containerNViewField;

		private static MethodInfo _containerLoadMethod;

		private static MethodInfo _containerSaveMethod;

		private static MethodInfo _containerCheckAccessMethod;

		[ThreadStatic]
		private static Stack<LinkContext> _contextStack;

		private static Player _cachedPlayer;

		private static CraftingStation _cachedStation;

		private static Vector3 _cachedOrigin;

		private static bool _cachedOriginSet;

		private static int _cachedFrame = -1;

		private static List<ContainerCandidate> _cachedContainers;

		private Harmony _harmony;

		private static bool UseSyncedServerConfig
		{
			get
			{
				if (_serverConfigReceived && (Object)(object)ZNet.instance != (Object)null)
				{
					return !ZNet.instance.IsServer();
				}
				return false;
			}
		}

		private static bool EffectiveEnabled
		{
			get
			{
				if (!UseSyncedServerConfig)
				{
					return _enabled.Value;
				}
				return _serverEnabled;
			}
		}

		private static bool EffectiveHammerBuildingEnabled
		{
			get
			{
				if (!UseSyncedServerConfig)
				{
					return _hammerBuildingEnabled.Value;
				}
				return _serverHammerBuildingEnabled;
			}
		}

		private static float EffectiveRadius
		{
			get
			{
				if (!UseSyncedServerConfig)
				{
					return _radius.Value;
				}
				return _serverRadius;
			}
		}

		private static bool EffectivePlayerBuiltOnly
		{
			get
			{
				if (!UseSyncedServerConfig)
				{
					return _playerBuiltOnly.Value;
				}
				return _serverPlayerBuiltOnly;
			}
		}

		private static bool EffectiveAllowShipContainers
		{
			get
			{
				if (!UseSyncedServerConfig)
				{
					return _allowShipContainers.Value;
				}
				return _serverAllowShipContainers;
			}
		}

		private static bool EffectiveAllowCartContainers
		{
			get
			{
				if (!UseSyncedServerConfig)
				{
					return _allowCartContainers.Value;
				}
				return _serverAllowCartContainers;
			}
		}

		private static bool EffectiveRespectContainerAccess
		{
			get
			{
				if (!UseSyncedServerConfig)
				{
					return _respectContainerAccess.Value;
				}
				return _serverRespectContainerAccess;
			}
		}

		private static bool EffectiveRespectWards
		{
			get
			{
				if (!UseSyncedServerConfig)
				{
					return _respectWards.Value;
				}
				return _serverRespectWards;
			}
		}

		private static bool EffectiveSkipInUseContainers
		{
			get
			{
				if (!UseSyncedServerConfig)
				{
					return _skipInUseContainers.Value;
				}
				return _serverSkipInUseContainers;
			}
		}

		private static bool EffectiveClaimOwnershipWhenPulling
		{
			get
			{
				if (!UseSyncedServerConfig)
				{
					return _claimOwnershipWhenPulling.Value;
				}
				return _serverClaimOwnershipWhenPulling;
			}
		}

		private static bool EffectiveRespectMultiUserChestIgnore
		{
			get
			{
				if (!UseSyncedServerConfig)
				{
					return _respectMultiUserChestIgnore.Value;
				}
				return _serverRespectMultiUserChestIgnore;
			}
		}

		private static LinkContext CurrentContext
		{
			get
			{
				Stack<LinkContext> contextStack = GetContextStack();
				if (contextStack.Count <= 0)
				{
					return null;
				}
				return contextStack.Peek();
			}
		}

		private static Stack<LinkContext> GetContextStack()
		{
			if (_contextStack == null)
			{
				_contextStack = new Stack<LinkContext>();
			}
			return _contextStack;
		}

		private static ContextGuard PushContext(LinkContext context, LinkContextKind kind)
		{
			LinkContext linkContext = context ?? LinkContext.Disabled(kind);
			GetContextStack().Push(linkContext);
			return new ContextGuard(linkContext);
		}

		private void Awake()
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Expected O, but got Unknown
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Expected O, but got Unknown
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Expected O, but got Unknown
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Expected O, but got Unknown
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Expected O, but got Unknown
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Expected O, but got Unknown
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0145: Expected O, but got Unknown
			//IL_0166: Unknown result type (might be due to invalid IL or missing references)
			//IL_0170: Expected O, but got Unknown
			//IL_0191: Unknown result type (might be due to invalid IL or missing references)
			//IL_019b: Expected O, but got Unknown
			//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c6: Expected O, but got Unknown
			//IL_01e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f1: Expected O, but got Unknown
			//IL_02e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ed: Expected O, but got Unknown
			_log = ((BaseUnityPlugin)this).Logger;
			_enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("01 - General", "Enabled", true, new ConfigDescription("Enable crafting from storage linked to nearby crafting stations.", (AcceptableValueBase)null, Array.Empty<object>()));
			_hammerBuildingEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("01 - General", "HammerBuildingEnabled", true, new ConfigDescription("Allow Hammer/build-tool placement costs to count and consume resources from nearby storage. Station-required pieces link around that station; stationless pieces such as Workbenches and Campfires link around the player.", (AcceptableValueBase)null, Array.Empty<object>()));
			_radius = ((BaseUnityPlugin)this).Config.Bind<float>("02 - Linking", "Radius", 20f, new ConfigDescription("Radius in metres used to find storage containers. Crafting uses the active station; stationless Hammer pieces use the player position.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 100f), Array.Empty<object>()));
			_playerBuiltOnly = ((BaseUnityPlugin)this).Config.Bind<bool>("02 - Linking", "PlayerBuiltContainersOnly", true, new ConfigDescription("Ignore world-generated loot containers and only use containers attached to player-built pieces.", (AcceptableValueBase)null, Array.Empty<object>()));
			_allowShipContainers = ((BaseUnityPlugin)this).Config.Bind<bool>("02 - Linking", "AllowShipContainers", false, new ConfigDescription("Allow storage on ships to be linked. Disabled by default because moving networked containers are higher risk.", (AcceptableValueBase)null, Array.Empty<object>()));
			_allowCartContainers = ((BaseUnityPlugin)this).Config.Bind<bool>("02 - Linking", "AllowCartContainers", false, new ConfigDescription("Allow cart storage to be linked. Disabled by default because moving networked containers are higher risk.", (AcceptableValueBase)null, Array.Empty<object>()));
			_respectContainerAccess = ((BaseUnityPlugin)this).Config.Bind<bool>("03 - Safety", "RespectContainerAccess", true, new ConfigDescription("Do not use private/personal containers that the crafting player cannot access.", (AcceptableValueBase)null, Array.Empty<object>()));
			_respectWards = ((BaseUnityPlugin)this).Config.Bind<bool>("03 - Safety", "RespectWards", true, new ConfigDescription("Do not use containers blocked by ward/private-area access.", (AcceptableValueBase)null, Array.Empty<object>()));
			_skipInUseContainers = ((BaseUnityPlugin)this).Config.Bind<bool>("03 - Safety", "SkipInUseContainers", true, new ConfigDescription("Ignore containers that are in use by another player. The local player's currently open container remains eligible. Set this false only when your shared-container setup is transaction-safe.", (AcceptableValueBase)null, Array.Empty<object>()));
			_claimOwnershipWhenPulling = ((BaseUnityPlugin)this).Config.Bind<bool>("03 - Safety", "ClaimOwnershipWhenPulling", true, new ConfigDescription("If required, claim ZNetView ownership immediately before consuming from a linked container. Disable only for troubleshooting; non-owned containers will then be ignored.", (AcceptableValueBase)null, Array.Empty<object>()));
			_respectMultiUserChestIgnore = ((BaseUnityPlugin)this).Config.Bind<bool>("03 - Safety", "RespectMultiUserChestIgnore", true, new ConfigDescription("Honor MultiUserChest's MUC_Ignore flag when present on a container.", (AcceptableValueBase)null, Array.Empty<object>()));
			_debugLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("99 - Debug", "DebugLogging", false, "Log linked container discovery and resource pulls on this machine.");
			_inventoryGuiCraftRecipeField = AccessTools.Field(typeof(InventoryGui), "m_craftRecipe");
			_inventoryGuiSelectedRecipeField = AccessTools.Field(typeof(InventoryGui), "m_selectedRecipe");
			_inventoryGuiCurrentContainerField = AccessTools.Field(typeof(InventoryGui), "m_currentContainer");
			_containerNViewField = AccessTools.Field(typeof(Container), "m_nview");
			_containerLoadMethod = AccessTools.Method(typeof(Container), "Load", (Type[])null, (Type[])null);
			_containerSaveMethod = AccessTools.Method(typeof(Container), "Save", (Type[])null, (Type[])null);
			_containerCheckAccessMethod = AccessTools.Method(typeof(Container), "CheckAccess", new Type[1] { typeof(long) }, (Type[])null);
			_harmony = new Harmony("com.custom.valheim.craftingstoragelink");
			_harmony.PatchAll();
			((BaseUnityPlugin)this).Logger.LogInfo((object)string.Format("{0} {1} loaded. BepInEx-only build; crafting + hammer storage linking enabled; re-entrant compatibility contexts active; configured radius {2:0.#}m.", "CraftingStorageLink", "1.5.1", EffectiveRadius));
		}

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

		private static bool IsLocalEnabled(Player player)
		{
			if (_enabled == null || !EffectiveEnabled || (Object)(object)player == (Object)null)
			{
				return false;
			}
			if ((Object)(object)Player.m_localPlayer != (Object)null)
			{
				return (Object)(object)Player.m_localPlayer == (Object)(object)player;
			}
			return false;
		}

		private static Recipe GetCraftRecipe(InventoryGui gui)
		{
			if ((Object)(object)gui == (Object)null)
			{
				return null;
			}
			if (_inventoryGuiCraftRecipeField != null)
			{
				object? value = _inventoryGuiCraftRecipeField.GetValue(gui);
				Recipe val = (Recipe)((value is Recipe) ? value : null);
				if ((Object)(object)val != (Object)null)
				{
					return val;
				}
			}
			if (_inventoryGuiSelectedRecipeField == null)
			{
				return null;
			}
			try
			{
				object value2 = _inventoryGuiSelectedRecipeField.GetValue(gui);
				if (value2 == null)
				{
					return null;
				}
				Type type = value2.GetType();
				PropertyInfo property = type.GetProperty("Recipe", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (property != null)
				{
					object? value3 = property.GetValue(value2, null);
					return (Recipe)((value3 is Recipe) ? value3 : null);
				}
				FieldInfo field = type.GetField("Recipe", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				return (Recipe)((field != null) ? /*isinst with value type is only supported in some contexts*/: null);
			}
			catch (Exception ex)
			{
				DebugLog("Could not resolve InventoryGui.m_selectedRecipe: " + ex.Message);
				return null;
			}
		}

		private static CraftingStation GetActiveStation(Player player, Recipe recipe)
		{
			if (!IsLocalEnabled(player) || (Object)(object)recipe == (Object)null || (Object)(object)recipe.m_craftingStation == (Object)null)
			{
				return null;
			}
			return player.GetCurrentCraftingStation();
		}

		private static CraftingStation GetBuildStation(Player player, Piece piece)
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			if (!IsLocalEnabled(player) || !EffectiveHammerBuildingEnabled || (Object)(object)piece == (Object)null || (Object)(object)piece.m_craftingStation == (Object)null)
			{
				return null;
			}
			return CraftingStation.HaveBuildStationInRange(piece.m_craftingStation.m_name, ((Component)player).transform.position);
		}

		private static bool SupportsPiece(Piece piece)
		{
			if ((Object)(object)piece != (Object)null && piece.m_resources != null)
			{
				return piece.m_resources.Length != 0;
			}
			return false;
		}

		private static bool SupportsRecipe(Recipe recipe)
		{
			if ((Object)(object)recipe != (Object)null && (Object)(object)recipe.m_craftingStation != (Object)null)
			{
				return !recipe.m_requireOnlyOneIngredient;
			}
			return false;
		}

		private static ContextGuard BeginRequirementCheck(Player player, Recipe recipe, bool discover)
		{
			LinkContext context = null;
			if (!discover && SupportsRecipe(recipe))
			{
				CraftingStation activeStation = GetActiveStation(player, recipe);
				if ((Object)(object)activeStation != (Object)null)
				{
					context = new LinkContext(LinkContextKind.RecipeRequirement, player, activeStation, recipe);
				}
			}
			return PushContext(context, LinkContextKind.RecipeRequirement);
		}

		private static ContextGuard BeginRequirementDisplay(InventoryGui gui, Player player)
		{
			LinkContext context = null;
			if (IsLocalEnabled(player))
			{
				Recipe craftRecipe = GetCraftRecipe(gui);
				if ((Object)(object)craftRecipe == (Object)null || SupportsRecipe(craftRecipe))
				{
					CraftingStation currentCraftingStation = player.GetCurrentCraftingStation();
					if ((Object)(object)currentCraftingStation != (Object)null)
					{
						context = new LinkContext(LinkContextKind.RecipeDisplay, player, currentCraftingStation, craftRecipe);
					}
				}
			}
			return PushContext(context, LinkContextKind.RecipeDisplay);
		}

		private static ContextGuard BeginCrafting(InventoryGui gui, Player player)
		{
			LinkContext context = null;
			Recipe craftRecipe = GetCraftRecipe(gui);
			if (SupportsRecipe(craftRecipe))
			{
				CraftingStation activeStation = GetActiveStation(player, craftRecipe);
				if ((Object)(object)activeStation != (Object)null)
				{
					context = new LinkContext(LinkContextKind.Crafting, player, activeStation, craftRecipe);
				}
			}
			return PushContext(context, LinkContextKind.Crafting);
		}

		private static LinkContext CreateBuildContext(Player player, Piece piece, LinkContextKind kind, RequirementMode? mode = null)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Invalid comparison between Unknown and I4
			if (!IsLocalEnabled(player) || !EffectiveHammerBuildingEnabled || !SupportsPiece(piece))
			{
				return null;
			}
			if (mode.HasValue && (int)mode.Value == 1)
			{
				return null;
			}
			CraftingStation buildStation = GetBuildStation(player, piece);
			if ((Object)(object)piece.m_craftingStation != (Object)null && (Object)(object)buildStation == (Object)null)
			{
				return null;
			}
			return new LinkContext(kind, player, buildStation, piece);
		}

		private static ContextGuard BeginBuildRequirementCheck(Player player, Piece piece, RequirementMode mode)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			return PushContext(CreateBuildContext(player, piece, LinkContextKind.BuildRequirement, mode), LinkContextKind.BuildRequirement);
		}

		private static ContextGuard BeginPlacement(Player player)
		{
			PieceTable val = (((Object)(object)player != (Object)null) ? player.GetBuildTool() : null);
			Piece piece = (((Object)(object)val != (Object)null) ? val.GetSelectedPiece() : null);
			return PushContext(CreateBuildContext(player, piece, LinkContextKind.Placement), LinkContextKind.Placement);
		}

		private static ContextGuard BeginBuildHudDisplay(Player player, object[] args)
		{
			Piece val = null;
			if (args != null)
			{
				foreach (object obj in args)
				{
					val = (Piece)((obj is Piece) ? obj : null);
					if ((Object)(object)val != (Object)null)
					{
						break;
					}
				}
			}
			if ((Object)(object)val == (Object)null && (Object)(object)player != (Object)null)
			{
				PieceTable buildTool = player.GetBuildTool();
				val = (((Object)(object)buildTool != (Object)null) ? buildTool.GetSelectedPiece() : null);
			}
			return PushContext(CreateBuildContext(player, val, LinkContextKind.BuildHudDisplay), LinkContextKind.BuildHudDisplay);
		}

		private static bool IsBuildContext(LinkContext context)
		{
			if (context == null)
			{
				return false;
			}
			if (context.Kind != LinkContextKind.BuildRequirement && context.Kind != LinkContextKind.BuildHudDisplay)
			{
				return context.Kind == LinkContextKind.Placement;
			}
			return true;
		}

		private static bool ContextAllowsLinkedCounting(LinkContext context)
		{
			if (context == null || !context.Enabled)
			{
				return false;
			}
			if (context.Kind != LinkContextKind.RecipeRequirement && context.Kind != LinkContextKind.RecipeDisplay && context.Kind != LinkContextKind.BuildRequirement)
			{
				return context.Kind == LinkContextKind.BuildHudDisplay;
			}
			return true;
		}

		private static void AddLinkedCount(Inventory inventory, string itemName, int quality, bool matchWorldLevel, ref int result)
		{
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			LinkContext currentContext = CurrentContext;
			if (ContextAllowsLinkedCounting(currentContext) && !((Object)(object)currentContext.Player == (Object)null) && currentContext.HasOrigin && inventory != null && inventory == currentContext.PlayerInventory)
			{
				result += CountLinkedItem(currentContext.Player, currentContext.Station, currentContext.Origin, itemName, quality, matchWorldLevel, int.MaxValue);
			}
		}

		private static int CountLinkedItem(Player player, CraftingStation station, Vector3 origin, string itemName, int quality, bool matchWorldLevel, int stopAt)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			if (string.IsNullOrEmpty(itemName) || !IsLocalEnabled(player))
			{
				return 0;
			}
			int num = 0;
			List<ContainerCandidate> list = FindContainers(player, station, origin);
			for (int i = 0; i < list.Count; i++)
			{
				Container container = list[i].Container;
				Inventory loadedInventory = GetLoadedInventory(container);
				if (loadedInventory == null)
				{
					DebugLog("Linked container '" + (((container != null) ? ((Object)container).name : null) ?? "<null>") + "' had no readable inventory while counting " + itemName + ".");
					continue;
				}
				int num2 = loadedInventory.CountItems(itemName, quality, matchWorldLevel);
				if (num2 > 0)
				{
					DebugLog($"Counted {num2}x {itemName} in '{((Object)container).name}'.");
				}
				num += num2;
				if (num >= stopAt)
				{
					break;
				}
			}
			return num;
		}

		private static PullPlan CreatePullPlan(Player player, Requirement[] requirements, int qualityLevel, int itemQuality, int multiplier)
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			LinkContext currentContext = CurrentContext;
			if (currentContext == null || !currentContext.Enabled || (Object)(object)currentContext.Player != (Object)(object)player || !currentContext.HasOrigin || requirements == null || requirements.Length == 0)
			{
				return null;
			}
			Inventory inventory = ((Humanoid)player).GetInventory();
			if (inventory == null)
			{
				return null;
			}
			PullPlan pullPlan = new PullPlan(player, currentContext.Station, currentContext.Origin);
			foreach (Requirement val in requirements)
			{
				if (val == null || (Object)(object)val.m_resItem == (Object)null)
				{
					continue;
				}
				int num = val.GetAmount(qualityLevel) * multiplier;
				if (num > 0)
				{
					string name = val.m_resItem.m_itemData.m_shared.m_name;
					int num2 = inventory.CountItems(name, itemQuality, true);
					int num3 = num - num2;
					if (num3 > 0)
					{
						pullPlan.Add(name, itemQuality, num3);
					}
				}
			}
			if (pullPlan.Items.Count <= 0)
			{
				return null;
			}
			return pullPlan;
		}

		private static void PayPullPlan(PullPlan plan)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			if (plan == null || !IsLocalEnabled(plan.Player))
			{
				return;
			}
			List<ContainerCandidate> list = FindContainers(plan.Player, plan.Station, plan.Origin);
			for (int i = 0; i < plan.Items.Count; i++)
			{
				PullItem pullItem = plan.Items[i];
				int num = pullItem.Amount;
				for (int j = 0; j < list.Count; j++)
				{
					if (num <= 0)
					{
						break;
					}
					int num2 = PullFromContainer(plan.Player, plan.Station, plan.Origin, list[j].Container, pullItem.Name, pullItem.Quality, num);
					num -= num2;
				}
				if (num > 0)
				{
					ManualLogSource log = _log;
					if (log != null)
					{
						log.LogWarning((object)$"CraftingStorageLink could not pull {num}x {pullItem.Name}; a linked container may have changed during crafting.");
					}
				}
			}
			ClearContainerCache();
		}

		private static List<ContainerCandidate> FindContainers(Player player, CraftingStation station, Vector3 origin)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: 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_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val;
			if (_cachedFrame == Time.frameCount && (Object)(object)_cachedPlayer == (Object)(object)player && (Object)(object)_cachedStation == (Object)(object)station && _cachedOriginSet)
			{
				val = _cachedOrigin - origin;
				if (((Vector3)(ref val)).sqrMagnitude < 0.0001f && _cachedContainers != null)
				{
					return _cachedContainers;
				}
			}
			List<ContainerCandidate> list = new List<ContainerCandidate>();
			if (!IsLocalEnabled(player))
			{
				return list;
			}
			float num = Mathf.Max(1f, EffectiveRadius);
			float num2 = num * num;
			Container[] array;
			try
			{
				array = Object.FindObjectsByType<Container>((FindObjectsSortMode)0);
			}
			catch (Exception ex)
			{
				DebugLog("Container discovery failed: " + ex.Message);
				return list;
			}
			foreach (Container val2 in array)
			{
				if (!((Object)(object)val2 == (Object)null))
				{
					val = ((Component)val2).transform.position - origin;
					float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude;
					if (!(sqrMagnitude > num2) && IsEligibleContainer(player, val2))
					{
						list.Add(new ContainerCandidate(val2, sqrMagnitude));
					}
				}
			}
			list.Sort(delegate(ContainerCandidate a, ContainerCandidate b)
			{
				float distanceSqr = a.DistanceSqr;
				return distanceSqr.CompareTo(b.DistanceSqr);
			});
			_cachedFrame = Time.frameCount;
			_cachedPlayer = player;
			_cachedStation = station;
			_cachedOrigin = origin;
			_cachedOriginSet = true;
			_cachedContainers = list;
			string arg = (((Object)(object)station != (Object)null) ? station.m_name : "builder");
			DebugLog($"Found {list.Count} linked containers within {num:0.#}m of {arg}.");
			return list;
		}

		private static bool IsEligibleContainer(Player player, Container container)
		{
			//IL_01de: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)container == (Object)null || (Object)(object)player == (Object)null)
			{
				return false;
			}
			if ((Object)(object)((Component)container).GetComponentInParent<TombStone>() != (Object)null)
			{
				DebugLog("Rejected container '" + ((Object)container).name + "': tombstone.");
				return false;
			}
			if (!EffectiveAllowShipContainers && (Object)(object)((Component)container).GetComponentInParent<Ship>() != (Object)null)
			{
				DebugLog("Rejected container '" + ((Object)container).name + "': ship containers disabled.");
				return false;
			}
			if (!EffectiveAllowCartContainers && (Object)(object)container.m_wagon != (Object)null)
			{
				DebugLog("Rejected container '" + ((Object)container).name + "': cart containers disabled.");
				return false;
			}
			if (EffectivePlayerBuiltOnly)
			{
				long num = 0L;
				Piece componentInParent = ((Component)container).GetComponentInParent<Piece>();
				if ((Object)(object)componentInParent != (Object)null)
				{
					num = componentInParent.GetCreator();
				}
				if (num == 0L)
				{
					ZNetView containerView = GetContainerView(container);
					if ((Object)(object)containerView != (Object)null && containerView.IsValid() && containerView.GetZDO() != null)
					{
						num = containerView.GetZDO().GetLong(StringExtensionMethods.GetStableHashCode("creator"), 0L);
					}
				}
				if (num == 0L)
				{
					DebugLog("Rejected container '" + ((Object)container).name + "': no player creator on Piece or container ZDO.");
					return false;
				}
			}
			bool flag = container.IsInUse() || ((Object)(object)container.m_wagon != (Object)null && container.m_wagon.InUse());
			if (EffectiveSkipInUseContainers && flag && !IsLocallyOpenContainer(container))
			{
				DebugLog("Ignoring in-use linked container '" + ((Object)container).name + "': it is not the local player's currently open container.");
				return false;
			}
			if (EffectiveSkipInUseContainers && flag)
			{
				DebugLog("Allowing locally open linked container '" + ((Object)container).name + "'.");
			}
			if (EffectiveRespectContainerAccess && !CheckContainerAccess(container, player.GetPlayerID()))
			{
				DebugLog("Rejected container '" + ((Object)container).name + "': access check failed.");
				return false;
			}
			if (EffectiveRespectWards && container.m_checkGuardStone && !PrivateArea.CheckAccess(((Component)container).transform.position, 0f, false, false))
			{
				DebugLog("Rejected container '" + ((Object)container).name + "': ward/private-area access denied.");
				return false;
			}
			ZNetView containerView2 = GetContainerView(container);
			if ((Object)(object)containerView2 == (Object)null || !containerView2.IsValid() || containerView2.GetZDO() == null)
			{
				DebugLog("Rejected container '" + ((Object)container).name + "': invalid or unavailable ZNetView/ZDO.");
				return false;
			}
			if (EffectiveRespectMultiUserChestIgnore && containerView2.GetZDO().GetBool("MUC_Ignore", false))
			{
				DebugLog("Rejected container '" + ((Object)container).name + "': MUC_Ignore is set.");
				return false;
			}
			if (!EffectiveClaimOwnershipWhenPulling && !containerView2.IsOwner())
			{
				DebugLog("Rejected container '" + ((Object)container).name + "': local peer is not owner and ClaimOwnershipWhenPulling=false.");
				return false;
			}
			return true;
		}

		private static bool CheckContainerAccess(Container container, long playerId)
		{
			if ((Object)(object)container == (Object)null)
			{
				return false;
			}
			if (_containerCheckAccessMethod == null)
			{
				ManualLogSource log = _log;
				if (log != null)
				{
					log.LogWarning((object)"CraftingStorageLink could not resolve Container.CheckAccess; refusing to pull from this container while RespectContainerAccess is enabled.");
				}
				return false;
			}
			try
			{
				object obj = _containerCheckAccessMethod.Invoke(container, new object[1] { playerId });
				bool flag = default(bool);
				int num;
				if (obj is bool)
				{
					flag = (bool)obj;
					num = 1;
				}
				else
				{
					num = 0;
				}
				return (byte)((uint)num & (flag ? 1u : 0u)) != 0;
			}
			catch (Exception ex)
			{
				DebugLog("Container access check failed for '" + ((Object)container).name + "': " + ex.GetType().Name + ": " + ex.Message);
				return false;
			}
		}

		private static bool IsLocallyOpenContainer(Container container)
		{
			if ((Object)(object)container == (Object)null || (Object)(object)InventoryGui.instance == (Object)null || _inventoryGuiCurrentContainerField == null)
			{
				return false;
			}
			try
			{
				return _inventoryGuiCurrentContainerField.GetValue(InventoryGui.instance) == container;
			}
			catch
			{
				return false;
			}
		}

		private static ZNetView GetContainerView(Container container)
		{
			if ((Object)(object)container == (Object)null)
			{
				return null;
			}
			try
			{
				if (_containerNViewField != null)
				{
					object? value = _containerNViewField.GetValue(container);
					ZNetView val = (ZNetView)((value is ZNetView) ? value : null);
					if ((Object)(object)val != (Object)null)
					{
						return val;
					}
				}
			}
			catch
			{
			}
			ZNetView component = ((Component)container).GetComponent<ZNetView>();
			if ((Object)(object)component != (Object)null)
			{
				return component;
			}
			return ((Component)container).GetComponentInParent<ZNetView>();
		}

		private static Inventory GetLoadedInventory(Container container)
		{
			if ((Object)(object)container == (Object)null)
			{
				return null;
			}
			try
			{
				Inventory inventory = container.GetInventory();
				if (inventory != null)
				{
					return inventory;
				}
				_containerLoadMethod?.Invoke(container, null);
				return container.GetInventory();
			}
			catch (Exception ex)
			{
				DebugLog("Could not load linked container '" + ((Object)container).name + "': " + ex.GetType().Name + ": " + ex.Message);
				return null;
			}
		}

		private static void SaveContainer(Container container)
		{
			if ((Object)(object)container == (Object)null || _containerSaveMethod == null)
			{
				return;
			}
			try
			{
				_containerSaveMethod.Invoke(container, null);
			}
			catch (Exception ex)
			{
				DebugLog("Could not explicitly save linked container '" + ((Object)container).name + "': " + ex.GetType().Name + ": " + ex.Message);
			}
		}

		private static int PullFromContainer(Player player, CraftingStation station, Vector3 origin, Container container, string itemName, int quality, int requested)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			if (requested <= 0 || !IsEligibleContainer(player, container))
			{
				return 0;
			}
			float num = Mathf.Max(1f, EffectiveRadius);
			Vector3 val = ((Component)container).transform.position - origin;
			if (((Vector3)(ref val)).sqrMagnitude > num * num)
			{
				return 0;
			}
			try
			{
				ZNetView containerView = GetContainerView(container);
				if ((Object)(object)containerView == (Object)null || !containerView.IsValid())
				{
					return 0;
				}
				if (!containerView.IsOwner())
				{
					if (!EffectiveClaimOwnershipWhenPulling)
					{
						return 0;
					}
					containerView.ClaimOwnership();
				}
				Inventory loadedInventory = GetLoadedInventory(container);
				if (loadedInventory == null)
				{
					return 0;
				}
				int num2 = loadedInventory.CountItems(itemName, quality, true);
				int num3 = Math.Min(num2, requested);
				if (num3 <= 0)
				{
					return 0;
				}
				loadedInventory.RemoveItem(itemName, num3, quality, true);
				int num4 = loadedInventory.CountItems(itemName, quality, true);
				int num5 = Math.Max(0, num2 - num4);
				if (num5 > 0)
				{
					SaveContainer(container);
					DebugLog($"Pulled {num5}x {itemName} from '{((Object)container).name}'.");
				}
				return num5;
			}
			catch (Exception ex)
			{
				ManualLogSource log = _log;
				if (log != null)
				{
					log.LogWarning((object)("CraftingStorageLink skipped container '" + ((Object)container).name + "' during pull: " + ex.GetType().Name + ": " + ex.Message));
				}
				return 0;
			}
		}

		private static ZPackage BuildServerConfigPackage()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: 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_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Expected O, but got Unknown
			ZPackage val = new ZPackage();
			val.Write(1);
			val.Write("1.5.1");
			val.Write(_enabled.Value);
			val.Write(_hammerBuildingEnabled.Value);
			val.Write(_radius.Value);
			val.Write(_playerBuiltOnly.Value);
			val.Write(_allowShipContainers.Value);
			val.Write(_allowCartContainers.Value);
			val.Write(_respectContainerAccess.Value);
			val.Write(_respectWards.Value);
			val.Write(_skipInUseContainers.Value);
			val.Write(_claimOwnershipWhenPulling.Value);
			val.Write(_respectMultiUserChestIgnore.Value);
			return val;
		}

		private static void ReceiveServerConfig(ZRpc rpc, ZPackage pkg)
		{
			if (pkg == null || ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer()))
			{
				return;
			}
			try
			{
				int num = pkg.ReadInt();
				string text = pkg.ReadString();
				if (num != 1)
				{
					ManualLogSource log = _log;
					if (log != null)
					{
						log.LogWarning((object)$"CraftingStorageLink config protocol mismatch. Server={num}, client={1}.");
					}
					return;
				}
				_serverEnabled = pkg.ReadBool();
				_serverHammerBuildingEnabled = pkg.ReadBool();
				_serverRadius = pkg.ReadSingle();
				_serverPlayerBuiltOnly = pkg.ReadBool();
				_serverAllowShipContainers = pkg.ReadBool();
				_serverAllowCartContainers = pkg.ReadBool();
				_serverRespectContainerAccess = pkg.ReadBool();
				_serverRespectWards = pkg.ReadBool();
				_serverSkipInUseContainers = pkg.ReadBool();
				_serverClaimOwnershipWhenPulling = pkg.ReadBool();
				_serverRespectMultiUserChestIgnore = pkg.ReadBool();
				_serverConfigReceived = true;
				ClearContainerCache();
				ManualLogSource log2 = _log;
				if (log2 != null)
				{
					log2.LogInfo((object)$"Received CraftingStorageLink server settings from v{text}; radius {_serverRadius:0.#}m.");
				}
				if (!string.Equals(text, "1.5.1", StringComparison.Ordinal))
				{
					ManualLogSource log3 = _log;
					if (log3 != null)
					{
						log3.LogWarning((object)("CraftingStorageLink version differs from server. Server=" + text + ", client=1.5.1. Use the same DLL on both ends."));
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log4 = _log;
				if (log4 != null)
				{
					log4.LogWarning((object)("Could not read CraftingStorageLink server settings: " + ex.GetType().Name + ": " + ex.Message));
				}
			}
		}

		private static void RegisterConfigRpc(ZNet znet, ZNetPeer peer)
		{
			if ((Object)(object)znet == (Object)null || peer == null || peer.m_rpc == null)
			{
				return;
			}
			try
			{
				if (!znet.IsServer())
				{
					_serverConfigReceived = false;
				}
				peer.m_rpc.Register<ZPackage>("CSL_Config_v1", (Action<ZRpc, ZPackage>)ReceiveServerConfig);
				if (znet.IsServer())
				{
					peer.m_rpc.Invoke("CSL_Config_v1", new object[1] { BuildServerConfigPackage() });
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = _log;
				if (log != null)
				{
					log.LogWarning((object)("CraftingStorageLink config RPC registration failed: " + ex.GetType().Name + ": " + ex.Message));
				}
			}
		}

		private static void ClearContainerCache()
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			_cachedPlayer = null;
			_cachedStation = null;
			_cachedOrigin = Vector3.zero;
			_cachedOriginSet = false;
			_cachedFrame = -1;
			_cachedContainers = null;
		}

		private static void DebugLog(string message)
		{
			if (_debugLogging != null && _debugLogging.Value)
			{
				ManualLogSource log = _log;
				if (log != null)
				{
					log.LogInfo((object)message);
				}
			}
		}
	}
}