Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of CraftingStorageLink v1.5.1
CraftingStorageLink.dll
Decompiled 3 weeks agousing 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); } } } } }