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 NearbyCraftingForked v1.5.3
NearbyCraftingForked.dll
Decompiled 15 hours ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; 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; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("NearbyCraftingForked")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.5.3.0")] [assembly: AssemblyInformationalVersion("1.5.3+7fe9097ad78a24c415e18461ad353df0bdf1e4f1")] [assembly: AssemblyProduct("NearbyCraftingForked")] [assembly: AssemblyTitle("NearbyCraftingForked")] [assembly: AssemblyVersion("1.5.3.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [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 NearbyCraftingForked { [BepInPlugin("com.sonicdm.valheim.nearbycraftingforked", "Nearby Crafting Forked", "1.5.3")] public sealed class NearbyCraftingForkedPlugin : BaseUnityPlugin { public const string PluginGuid = "com.sonicdm.valheim.nearbycraftingforked"; public const string PluginName = "Nearby Crafting Forked"; public const string PluginVersion = "1.5.3"; internal static ConfigEntry<float> Range; internal static ConfigEntry<bool> Enabled; internal static ConfigEntry<bool> EnableBuilding; internal static ConfigEntry<bool> IgnoreMovingContainers; internal static ConfigEntry<bool> IgnoreObliterators; internal static ConfigEntry<bool> RequirePlayerPlacedContainer; internal static ConfigEntry<bool> FixRequirementIndicator; internal static ConfigEntry<bool> BalrondCompatibility; internal static ConfigEntry<bool> DebugLogging; internal static ConfigEntry<bool> DebugContainerDetails; internal static ConfigEntry<bool> EnableMassDeposit; internal static ConfigEntry<KeyboardShortcut> MassDepositHotkey; internal static ConfigEntry<bool> QuickDepositHighlightChests; internal static ConfigEntry<string> QuickDepositHighlightColor; internal static ConfigEntry<float> QuickDepositHighlightAlpha; internal static ConfigEntry<float> QuickDepositHighlightDurationSeconds; internal static ConfigEntry<KeyboardShortcut> ReloadConfigHotkey; internal static ConfigEntry<bool> AutoReloadConfig; internal static ConfigEntry<bool> StationFuelEnabled; internal static ConfigEntry<bool> EnableOreFromChests; internal static ConfigEntry<bool> ItemLocateEnabled; internal static ConfigEntry<int> ItemLocateMaxHighlights; internal static ConfigEntry<float> ItemLocateDurationSeconds; internal static ConfigEntry<string> ItemLocateGlowColor; internal static ConfigEntry<float> ItemLocateGlowAlpha; internal static ConfigEntry<bool> QuickDepositExcludeConsumables; internal static ConfigEntry<bool> QuickDepositExcludeAmmo; internal static ConfigEntry<bool> QuickDepositExcludeEquipment; internal static ConfigEntry<bool> QuickDepositExcludeUtility; internal static ConfigEntry<string> QuickDepositExcludedItemTypes; internal static ConfigEntry<string> QuickDepositExcludedItems; internal static ConfigEntry<string> QuickDepositAllowedItems; internal static ManualLogSource ModLogger; private Harmony? _harmony; private DateTime _configLastWriteUtc; private float _configWatchNextCheck; private DateTime _configPendingWriteUtc; private float _configPendingSince = -1f; internal static bool DebugEnabled { get { if (DebugLogging != null) { return DebugLogging.Value; } return false; } } internal static bool ContainerDebugEnabled { get { if (DebugEnabled && DebugContainerDetails != null) { return DebugContainerDetails.Value; } return false; } } private void Awake() { //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Expected O, but got Unknown //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Expected O, but got Unknown //IL_01a7: Unknown result type (might be due to invalid IL or missing references) //IL_0228: Unknown result type (might be due to invalid IL or missing references) //IL_0237: Expected O, but got Unknown //IL_0232: Unknown result type (might be due to invalid IL or missing references) //IL_023c: Expected O, but got Unknown //IL_026a: Unknown result type (might be due to invalid IL or missing references) //IL_0279: Expected O, but got Unknown //IL_0274: Unknown result type (might be due to invalid IL or missing references) //IL_027e: Expected O, but got Unknown //IL_0293: Unknown result type (might be due to invalid IL or missing references) //IL_0432: Unknown result type (might be due to invalid IL or missing references) //IL_0441: Expected O, but got Unknown //IL_043c: Unknown result type (might be due to invalid IL or missing references) //IL_0446: Expected O, but got Unknown //IL_0474: Unknown result type (might be due to invalid IL or missing references) //IL_0483: Expected O, but got Unknown //IL_047e: Unknown result type (might be due to invalid IL or missing references) //IL_0488: Expected O, but got Unknown //IL_04da: Unknown result type (might be due to invalid IL or missing references) //IL_04e9: Expected O, but got Unknown //IL_04e4: Unknown result type (might be due to invalid IL or missing references) //IL_04ee: Expected O, but got Unknown //IL_05ee: Unknown result type (might be due to invalid IL or missing references) //IL_05f8: Expected O, but got Unknown //IL_0713: Unknown result type (might be due to invalid IL or missing references) ModLogger = ((BaseUnityPlugin)this).Logger; Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enable Nearby Crafting."); EnableBuilding = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnableBuilding", true, "Allow building pieces to use materials from nearby containers."); Range = ((BaseUnityPlugin)this).Config.Bind<float>("General", "ContainerRange", 20f, new ConfigDescription("Maximum distance in metres from the player to a container.", (AcceptableValueBase)new AcceptableValueRange<float>(1f, 100f), Array.Empty<object>())); IgnoreMovingContainers = ((BaseUnityPlugin)this).Config.Bind<bool>("Containers", "IgnoreMovingContainers", true, "Ignore ships, and ignore carts that are currently attached or in use. Parked/idle carts stay usable for craft, build, deposit, fuel, and locate."); IgnoreObliterators = ((BaseUnityPlugin)this).Config.Bind<bool>("Containers", "IgnoreObliterators", true, "Ignore Obliterators (Incinerator). Prevents Quick Deposit and nearby crafting/building from using them."); RequirePlayerPlacedContainer = ((BaseUnityPlugin)this).Config.Bind<bool>("Containers", "RequirePlayerPlacedContainer", true, "Only use containers attached to a Piece (normally player-built storage), avoiding most world loot chests."); FixRequirementIndicator = ((BaseUnityPlugin)this).Config.Bind<bool>("UI", "FixRequirementIndicator", true, "Treat nearby-container materials as available when coloring crafting requirement indicators."); BalrondCompatibility = ((BaseUnityPlugin)this).Config.Bind<bool>("Compatibility", "BalrondConstructions", true, "Recognize storage prefabs where Container and Piece are siblings under the same prefab root (used by BalrondConstructions and some other build mods)."); DebugLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "DebugLogging", false, "Write Nearby Crafting diagnostic information to BepInEx LogOutput.log."); DebugContainerDetails = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "DebugContainerDetails", false, "When DebugLogging is enabled, include per-container cache/scan details. This can be noisy."); EnableMassDeposit = ((BaseUnityPlugin)this).Config.Bind<bool>("Quick Deposit", "Enabled", true, "Enable the nearby mass quick-deposit hotkey."); MassDepositHotkey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Quick Deposit", "Hotkey", new KeyboardShortcut((KeyCode)287, Array.Empty<KeyCode>()), "Hotkey used to quick-deposit matching inventory stacks into all eligible nearby containers. Default: F6."); QuickDepositHighlightChests = ((BaseUnityPlugin)this).Config.Bind<bool>("Quick Deposit", "HighlightChests", false, "Glow chests and parked carts that received items from Quick Deposit. Off by default. Color, opacity, and duration are HighlightColor / HighlightAlpha / HighlightDurationSeconds. Clear with 'nearby clear'."); QuickDepositHighlightColor = ((BaseUnityPlugin)this).Config.Bind<string>("Quick Deposit", "HighlightColor", "#248038", "Glow color as hex (#248038) or RGB (36,128,56 or 0.14,0.50,0.22). rgb()/rgba() pastes work. Use HighlightAlpha for opacity."); QuickDepositHighlightAlpha = ((BaseUnityPlugin)this).Config.Bind<float>("Quick Deposit", "HighlightAlpha", 1f, new ConfigDescription("Opacity of Quick Deposit chest glows. 0 is invisible, 1 is full intensity.", (AcceptableValueBase)new AcceptableValueRange<float>(0.05f, 1f), Array.Empty<object>())); QuickDepositHighlightDurationSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Quick Deposit", "HighlightDurationSeconds", 15f, new ConfigDescription("How long Quick Deposit chest glows last before auto-clear.", (AcceptableValueBase)new AcceptableValueRange<float>(1f, 120f), Array.Empty<object>())); ReloadConfigHotkey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("General", "ReloadConfigHotkey", KeyboardShortcut.Empty, "Optional hotkey to force-reload this mod's config from disk. Unset by default."); AutoReloadConfig = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "AutoReloadConfig", true, "Automatically reload this mod's config when the .cfg file changes on disk (edit in r2modman/Notepad, save, and it applies in-game)."); QuickDepositExcludeConsumables = ((BaseUnityPlugin)this).Config.Bind<bool>("Quick Deposit - Exclusions", "ExcludeConsumables", true, "Keep consumables such as food, meads and potions in the player inventory."); QuickDepositExcludeAmmo = ((BaseUnityPlugin)this).Config.Bind<bool>("Quick Deposit - Exclusions", "ExcludeAmmo", true, "Keep ammunition such as arrows and bolts in the player inventory."); QuickDepositExcludeEquipment = ((BaseUnityPlugin)this).Config.Bind<bool>("Quick Deposit - Exclusions", "ExcludeEquipment", true, "Keep weapons, armor, shields, tools, torches and other equipment in the player inventory."); QuickDepositExcludeUtility = ((BaseUnityPlugin)this).Config.Bind<bool>("Quick Deposit - Exclusions", "ExcludeUtility", true, "Keep Utility item types in the player inventory."); QuickDepositExcludedItemTypes = ((BaseUnityPlugin)this).Config.Bind<string>("Quick Deposit - Exclusions", "ExcludedItemTypes", "", "Additional ItemType names to exclude, comma-separated. Matching is case-insensitive. Example: Trophy,Misc"); QuickDepositExcludedItems = ((BaseUnityPlugin)this).Config.Bind<string>("Quick Deposit - Exclusions", "ExcludedItems", "", "Prefab, shared, or localized item names to exclude, comma-separated. Case-insensitive. * wildcards allowed. A leading * matches the display name and the first prefab word only — not descriptions or later words in a compound prefab (so *Berr* will not match Oatmeal). Example: Coins,DragonEgg,Oatmeal"); QuickDepositAllowedItems = ((BaseUnityPlugin)this).Config.Bind<string>("Quick Deposit - Exclusions", "AllowedItems", "", "Exceptions to exclusions: these items still quick-deposit even if their ItemType is excluded. Prefab, shared, or localized names, case-insensitive, * wildcards allowed. A leading * matches display name / first prefab word only (so *Berr* deposits berries, not Oatmeal). Example: Mushroom*,Honey,*Berr*"); StationFuelEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Station Fuel", "Enabled", true, "Pull fuel (and smelter ore) from nearby eligible containers when interacting with smelters, kilns, fires, torches, braziers, and similar stations."); EnableOreFromChests = ((BaseUnityPlugin)this).Config.Bind<bool>("Station Fuel", "EnableOreFromChests", true, "When Station Fuel is enabled, also pull smelter/kiln/blast-furnace cookable inputs (ore/scrap) from nearby containers."); ItemLocateEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Item Locate", "Enabled", true, "Enable the 'nearby' console/chat command to glow eligible chests and parked carts that contain an item."); ItemLocateMaxHighlights = ((BaseUnityPlugin)this).Config.Bind<int>("Item Locate", "MaxHighlights", 10, new ConfigDescription("Maximum chests/carts to glow (nearest first; farther matches are culled).", (AcceptableValueBase)new AcceptableValueRange<int>(1, 50), Array.Empty<object>())); ItemLocateDurationSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Item Locate", "DurationSeconds", 15f, new ConfigDescription("How long chest glows last before auto-clear.", (AcceptableValueBase)new AcceptableValueRange<float>(3f, 120f), Array.Empty<object>())); ItemLocateGlowColor = ((BaseUnityPlugin)this).Config.Bind<string>("Item Locate", "GlowColor", "#8C731A", "Glow color as hex (#8C731A) or RGB (140,115,26 or 0.55,0.45,0.10). rgb()/rgba() pastes work. Use GlowAlpha for opacity."); ItemLocateGlowAlpha = ((BaseUnityPlugin)this).Config.Bind<float>("Item Locate", "GlowAlpha", 1f, new ConfigDescription("Opacity of item-locate chest glows. 0 is invisible, 1 is full intensity.", (AcceptableValueBase)new AcceptableValueRange<float>(0.05f, 1f), Array.Empty<object>())); Range.SettingChanged += OnContainerSettingChanged; IgnoreMovingContainers.SettingChanged += OnContainerSettingChanged; IgnoreObliterators.SettingChanged += OnContainerSettingChanged; RequirePlayerPlacedContainer.SettingChanged += OnContainerSettingChanged; BalrondCompatibility.SettingChanged += OnContainerSettingChanged; Enabled.SettingChanged += OnEnabledChanged; _configLastWriteUtc = GetConfigWriteTimeUtc(); _configWatchNextCheck = 0f; _harmony = new Harmony("com.sonicdm.valheim.nearbycraftingforked"); try { _harmony.PatchAll(); ItemLocate.RegisterCommand(); ((BaseUnityPlugin)this).Logger.LogInfo((object)("Nearby Crafting Forked" + " 1.5.3 loaded.")); if (DebugEnabled) { Debug($"Config: Enabled={Enabled.Value}, EnableBuilding={EnableBuilding.Value}, Range={Range.Value:0.##}m, " + $"RequirePlayerPlacedContainer={RequirePlayerPlacedContainer.Value}, " + $"IgnoreMovingContainers={IgnoreMovingContainers.Value}, IgnoreObliterators={IgnoreObliterators.Value}, " + $"FixRequirementIndicator={FixRequirementIndicator.Value}, " + $"BalrondCompatibility={BalrondCompatibility.Value}, " + $"EnableMassDeposit={EnableMassDeposit.Value}, MassDepositHotkey={MassDepositHotkey.Value}, " + $"QDHighlight={QuickDepositHighlightChests.Value}, " + $"StationFuel={StationFuelEnabled.Value}, OreFromChests={EnableOreFromChests.Value}, " + $"ItemLocate={ItemLocateEnabled.Value}, " + $"DebugContainerDetails={DebugContainerDetails.Value}"); } } catch (Exception ex) { try { _harmony.UnpatchSelf(); } catch { } Enabled.Value = false; ((BaseUnityPlugin)this).Logger.LogError((object)("Nearby Crafting Forked" + " failed to apply its Harmony patches and has been disabled.")); ((BaseUnityPlugin)this).Logger.LogError((object)ex); } } private static void OnContainerSettingChanged(object? sender, EventArgs e) { NearbyContainers.InvalidateAll(); if (DebugEnabled) { Debug("Container-related configuration changed; caches invalidated."); } } private static void OnEnabledChanged(object? sender, EventArgs e) { ResetRuntimeState(); } internal static void ResetRuntimeState() { NearbyContainers.InvalidateAll(); RequirementUiCache.Clear(); BuildingPlacementState.Clear(); RecipeRequirementContext.Clear(); RecipeConsumptionRules.Clear(); CraftingContext.Clear(); ItemLocate.ClearHighlights(); } internal static void Debug(string message) { if (DebugEnabled) { ModLogger.LogInfo((object)("[DEBUG] " + message)); } } internal static void DebugContainer(string message) { if (ContainerDebugEnabled) { ModLogger.LogInfo((object)("[DEBUG-CONTAINER] " + message)); } } private unsafe void Update() { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Expected O, but got Unknown WatchConfigFileForChanges(); ItemLocate.Tick(); if (ReloadConfigHotkey != null) { KeyboardShortcut value = ReloadConfigHotkey.Value; object obj = KeyboardShortcut.Empty; if (!((object)(*(KeyboardShortcut*)(&value))/*cast due to .constrained prefix*/).Equals(obj) && ((KeyboardShortcut)(ref value)).IsDown()) { ReloadConfigFromDisk(notifyPlayer: true); } } if (Enabled == null || !Enabled.Value || EnableMassDeposit == null || !EnableMassDeposit.Value || MassDepositHotkey == null) { return; } KeyboardShortcut value2 = MassDepositHotkey.Value; if (((KeyboardShortcut)(ref value2)).IsDown()) { Player localPlayer = Player.m_localPlayer; if (!((Object)localPlayer == (Object)null)) { MassQuickDeposit(localPlayer); } } } private void WatchConfigFileForChanges() { if (AutoReloadConfig == null || !AutoReloadConfig.Value) { _configPendingSince = -1f; return; } float unscaledTime = Time.unscaledTime; if (unscaledTime < _configWatchNextCheck) { return; } _configWatchNextCheck = unscaledTime + 1f; DateTime configWriteTimeUtc = GetConfigWriteTimeUtc(); if (!(configWriteTimeUtc == DateTime.MinValue)) { if (configWriteTimeUtc == _configLastWriteUtc) { _configPendingSince = -1f; } else if (_configPendingSince < 0f || configWriteTimeUtc != _configPendingWriteUtc) { _configPendingWriteUtc = configWriteTimeUtc; _configPendingSince = unscaledTime; } else if (!(unscaledTime - _configPendingSince < 0.75f)) { _configLastWriteUtc = configWriteTimeUtc; _configPendingSince = -1f; ReloadConfigFromDisk(notifyPlayer: false); } } } private DateTime GetConfigWriteTimeUtc() { try { string configFilePath = ((BaseUnityPlugin)this).Config.ConfigFilePath; if (string.IsNullOrEmpty(configFilePath) || !File.Exists(configFilePath)) { return DateTime.MinValue; } return File.GetLastWriteTimeUtc(configFilePath); } catch { return DateTime.MinValue; } } private void ReloadConfigFromDisk(bool notifyPlayer) { //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Expected O, but got Unknown try { ((BaseUnityPlugin)this).Config.Reload(); _configLastWriteUtc = GetConfigWriteTimeUtc(); _configPendingSince = -1f; ResetRuntimeState(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Nearby Crafting Forked config reloaded from disk."); if (notifyPlayer) { Player localPlayer = Player.m_localPlayer; if (!((Object)localPlayer == (Object)null)) { ((Character)localPlayer).Message((MessageType)2, "Nearby Crafting: config reloaded", 0, (Sprite)null, false); } } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)"Nearby Crafting Forked failed to reload config from disk."); ((BaseUnityPlugin)this).Logger.LogError((object)ex); } } private static void MassQuickDeposit(Player player) { //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Expected O, but got Unknown //IL_01fd: Unknown result type (might be due to invalid IL or missing references) Inventory inventory = ((Humanoid)player).GetInventory(); if (inventory == null) { return; } List<Container> list = NearbyContainers.Get(player); if (list.Count == 0) { if (DebugEnabled) { Debug("Mass quick-deposit: no eligible nearby containers."); } return; } int num = 0; int num2 = 0; int num3 = 0; List<Container> list2 = new List<Container>(); for (int i = 0; i < list.Count; i++) { Container val = list[i]; if ((Object)val == (Object)null) { continue; } try { Inventory inventory2 = val.GetInventory(); if (inventory2 != null && inventory2 != inventory) { int num4 = QuickDepositIntoContainer(inventory, inventory2); num++; num3 += num4; if (num4 > 0) { num2++; list2.Add(val); } if (ContainerDebugEnabled) { DebugContainer($"Mass quick-deposit processed '{((Object)val).name}': moved={num4}."); } } } catch (Exception ex) { if (DebugEnabled) { Debug("Mass quick-deposit skipped '" + ((Object)val).name + "' after " + ex.GetType().Name + ": " + ex.Message); } } } NearbyContainers.InvalidateCounts(); if (DebugEnabled) { Debug($"Mass quick-deposit completed across {num} eligible container(s); receiving={num2}; moved={num3} total item(s)."); } string text = ((num3 > 0) ? string.Format("Quick Deposit: {0} item{1} deposited into {2} chest{3}", num3, (num3 == 1) ? "" : "s", num2, (num2 == 1) ? "" : "s") : "Quick Deposit: nothing to deposit"); ((Character)player).Message((MessageType)2, text, 0, (Sprite)null, false); if (QuickDepositHighlightChests != null && QuickDepositHighlightChests.Value && list2.Count > 0) { ItemLocate.HighlightContainers(list2, QuickDepositHighlightColor?.Value, new Color(0.14f, 0.5f, 0.22f, 1f), (QuickDepositHighlightDurationSeconds != null) ? QuickDepositHighlightDurationSeconds.Value : 15f, (QuickDepositHighlightAlpha != null) ? QuickDepositHighlightAlpha.Value : 1f); } } private static int QuickDepositIntoContainer(Inventory sourceInventory, Inventory targetInventory) { //IL_0087: Unknown result type (might be due to invalid IL or missing references) int num = 0; List<ItemData> list = new List<ItemData>(targetInventory.GetAllItems()); List<ItemData> list2 = new List<ItemData>(sourceInventory.GetAllItems()); for (int i = 0; i < list2.Count; i++) { ItemData val = list2[i]; if (val == null || val.m_shared == null || val.m_stack <= 0 || val.m_shared.m_maxStackSize <= 1) { continue; } if (IsQuickDepositExcluded(val)) { if (ContainerDebugEnabled) { DebugContainer($"Quick-deposit excluded '{val.m_shared.m_name}' ({val.m_shared.m_itemType})."); } continue; } List<ItemData> list3 = new List<ItemData>(); for (int j = 0; j < list.Count; j++) { ItemData val2 = list[j]; if (CanQuickStackTogether(val, val2)) { list3.Add(val2); } } if (list3.Count == 0) { continue; } for (int k = 0; k < list3.Count; k++) { if (val.m_stack <= 0) { break; } ItemData val3 = list3[k]; if (val3 == null || val3.m_shared == null) { continue; } int num2 = val3.m_shared.m_maxStackSize - val3.m_stack; if (num2 > 0) { int num3 = Math.Min(val.m_stack, num2); int stack = val.m_stack; targetInventory.MoveItemToThis(sourceInventory, val, num3, val3.m_gridPos.x, val3.m_gridPos.y); int num4 = Math.Max(0, stack - val.m_stack); num += num4; if (ContainerDebugEnabled && num4 > 0) { DebugContainer($"Quick-deposit merged {num4}x '{val.m_shared.m_name}' into existing stack at {val3.m_gridPos.x},{val3.m_gridPos.y}."); } } } while (val.m_stack > 0) { int num5 = -1; int num6 = -1; for (int l = 0; l < targetInventory.GetHeight(); l++) { if (num5 >= 0) { break; } for (int m = 0; m < targetInventory.GetWidth(); m++) { if (targetInventory.GetItemAt(m, l) == null) { num5 = m; num6 = l; break; } } } if (num5 < 0 || num6 < 0) { break; } int num7 = Math.Min(val.m_stack, val.m_shared.m_maxStackSize); int stack2 = val.m_stack; targetInventory.MoveItemToThis(sourceInventory, val, num7, num5, num6); int num8 = Math.Max(0, stack2 - val.m_stack); if (num8 <= 0) { break; } num += num8; if (ContainerDebugEnabled) { DebugContainer($"Quick-deposit moved {num8}x '{val.m_shared.m_name}' into empty slot {num5},{num6}."); } } } return num; } private unsafe static bool IsQuickDepositExcluded(ItemData item) { //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Invalid comparison between Unknown and I4 //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Invalid comparison between Unknown and I4 //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Invalid comparison between Unknown and I4 //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Invalid comparison between Unknown and I4 //IL_00e5: Unknown result type (might be due to invalid IL or missing references) if (item == null || item.m_shared == null) { return false; } if (QuickDepositExcludedItems != null && ItemMatchesCsv(item, QuickDepositExcludedItems.Value)) { return true; } if (QuickDepositAllowedItems != null && ItemMatchesCsv(item, QuickDepositAllowedItems.Value)) { if (ContainerDebugEnabled) { DebugContainer($"Quick-deposit allowed by exception '{item.m_shared.m_name}' ({item.m_shared.m_itemType})."); } return false; } ItemType itemType = item.m_shared.m_itemType; if (QuickDepositExcludeConsumables != null && QuickDepositExcludeConsumables.Value && (int)itemType == 2) { return true; } if (QuickDepositExcludeAmmo != null && QuickDepositExcludeAmmo.Value && ((int)itemType == 9 || (int)itemType == 23)) { return true; } if (QuickDepositExcludeUtility != null && QuickDepositExcludeUtility.Value && (int)itemType == 18) { return true; } if (QuickDepositExcludeEquipment != null && QuickDepositExcludeEquipment.Value && IsEquipmentItemType(itemType)) { return true; } if (QuickDepositExcludedItemTypes != null && CsvContains(QuickDepositExcludedItemTypes.Value, ((object)(*(ItemType*)(&itemType))/*cast due to .constrained prefix*/).ToString())) { return true; } return false; } private static bool ItemMatchesCsv(ItemData item, string csv) { if (string.IsNullOrWhiteSpace(csv) || item?.m_shared == null) { return false; } string[] array = csv.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < array.Length; i++) { string text = array[i].Trim(); if (text.Length > 0 && ItemMatchesFilterPattern(item, text)) { return true; } } return false; } private static bool ItemMatchesFilterPattern(ItemData item, string pattern) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected O, but got Unknown string name = item.m_shared.m_name; string localizedName = ItemLocate.GetLocalizedName(name); string text = null; if ((Object)item.m_dropPrefab != (Object)null) { text = ((Object)item.m_dropPrefab).name; } string leadingNameToken = GetLeadingNameToken(text); bool flag = pattern[0] == '*'; if (!string.IsNullOrEmpty(localizedName) && !IsCompoundPrefabDump(localizedName, text) && NameMatches(localizedName, pattern)) { return true; } if (!string.IsNullOrEmpty(leadingNameToken) && NameMatches(leadingNameToken, pattern)) { return true; } if (flag) { return false; } if (!string.IsNullOrEmpty(name) && NameMatches(name, pattern)) { return true; } if (!string.IsNullOrEmpty(name) && name[0] == '$' && NameMatches(name.Substring(1), pattern)) { return true; } if (!string.IsNullOrEmpty(text) && NameMatches(text, pattern)) { return true; } return false; } private static string GetLeadingNameToken(string name) { if (string.IsNullOrEmpty(name)) { return string.Empty; } int i; for (i = 1; i < name.Length; i++) { char c = name[i]; if (c == '_' || c == '-' || c == ' ' || char.IsUpper(c)) { break; } } return name.Substring(0, i); } private static bool IsCompoundPrefabDump(string candidate, string prefabName) { if (string.IsNullOrEmpty(candidate) || string.IsNullOrEmpty(prefabName)) { return false; } if (GetLeadingNameToken(prefabName).Length >= prefabName.Length) { return false; } return string.Equals(candidate.Replace(" ", string.Empty), prefabName, StringComparison.OrdinalIgnoreCase); } private static bool IsEquipmentItemType(ItemType itemType) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Expected I4, but got Unknown switch (itemType - 3) { case 0: case 1: case 2: case 3: case 4: case 8: case 9: case 11: case 12: case 14: case 16: case 19: case 21: return true; default: return false; } } private static bool CsvContains(string csv, string value) { if (string.IsNullOrWhiteSpace(csv) || string.IsNullOrWhiteSpace(value)) { return false; } string[] array = csv.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < array.Length; i++) { string text = array[i].Trim(); if (text.Length > 0 && NameMatches(value, text)) { return true; } } return false; } internal static bool NameMatches(string value, string pattern) { if (string.IsNullOrEmpty(pattern)) { return false; } if (pattern.IndexOf('*') < 0) { return string.Equals(value, pattern, StringComparison.OrdinalIgnoreCase); } string[] array = pattern.Split('*'); int num = 0; for (int i = 0; i < array.Length; i++) { string text = array[i]; if (text.Length == 0) { continue; } if (i == 0) { if (!value.StartsWith(text, StringComparison.OrdinalIgnoreCase)) { return false; } num = text.Length; continue; } if (i == array.Length - 1 && pattern[pattern.Length - 1] != '*') { if (!value.EndsWith(text, StringComparison.OrdinalIgnoreCase)) { return false; } return value.Length - text.Length >= num; } int num2 = value.IndexOf(text, num, StringComparison.OrdinalIgnoreCase); if (num2 < 0) { return false; } num = num2 + text.Length; } return true; } private static bool CanQuickStackTogether(ItemData source, ItemData target) { if (source == null || target == null || source.m_shared == null || target.m_shared == null) { return false; } if (source.m_shared.m_name != target.m_shared.m_name || source.m_quality != target.m_quality || source.m_variant != target.m_variant || source.m_worldLevel != target.m_worldLevel) { return false; } if (source.m_customData.Count != target.m_customData.Count) { return false; } foreach (KeyValuePair<string, string> customDatum in source.m_customData) { if (!target.m_customData.TryGetValue(customDatum.Key, out var value) || value != customDatum.Value) { return false; } } return true; } private void OnDestroy() { Range.SettingChanged -= OnContainerSettingChanged; IgnoreMovingContainers.SettingChanged -= OnContainerSettingChanged; IgnoreObliterators.SettingChanged -= OnContainerSettingChanged; RequirePlayerPlacedContainer.SettingChanged -= OnContainerSettingChanged; BalrondCompatibility.SettingChanged -= OnContainerSettingChanged; Enabled.SettingChanged -= OnEnabledChanged; ResetRuntimeState(); Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } } internal static class CraftingContext { internal static int Depth; internal static bool IsCrafting => Depth > 0; internal static void Clear() { Depth = 0; } } internal static class RecipeRequirementContext { internal static Player? Player; internal static Inventory? PlayerInventory; internal static int Depth; internal static bool IsActive { get { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown if (Depth > 0 && (Object)Player != (Object)null) { return PlayerInventory != null; } return false; } } internal static void Begin(Player player, bool discover) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Expected O, but got Unknown if (!discover && !((Object)player == (Object)null)) { if (Depth == 0) { Player = player; PlayerInventory = ((Humanoid)player).GetInventory(); } Depth++; } } internal static void End() { if (Depth > 0) { Depth--; if (Depth == 0) { Player = null; PlayerInventory = null; } } } internal static void Clear() { Depth = 0; Player = null; PlayerInventory = null; } } internal readonly struct RecipeConsumptionKey : IEquatable<RecipeConsumptionKey> { internal readonly Requirement[] Requirements; internal readonly int QualityLevel; internal RecipeConsumptionKey(Requirement[] requirements, int qualityLevel) { Requirements = requirements; QualityLevel = qualityLevel; } public bool Equals(RecipeConsumptionKey other) { if (Requirements == other.Requirements) { return QualityLevel == other.QualityLevel; } return false; } public override bool Equals(object? obj) { if (obj is RecipeConsumptionKey other) { return Equals(other); } return false; } public override int GetHashCode() { return (RuntimeHelpers.GetHashCode(Requirements) * 397) ^ QualityLevel; } } internal static class RecipeConsumptionRules { private static readonly Dictionary<RecipeConsumptionKey, HashSet<string>> AllowedNames = new Dictionary<RecipeConsumptionKey, HashSet<string>>(); private static HashSet<string>? _currentNames; private static Requirement[]? _currentRequirements; private static int _currentQualityLevel; private static int _beginDepth; internal static void Begin(Recipe recipe, int qualityLevel) { if (_beginDepth > 0) { _beginDepth++; return; } _currentRequirements = recipe?.m_resources; _currentQualityLevel = qualityLevel; _currentNames = new HashSet<string>(StringComparer.Ordinal); _beginDepth = 1; } internal static void Record(string name) { if (_currentNames != null && !string.IsNullOrEmpty(name)) { _currentNames.Add(name); } } internal static void Complete(bool success) { if (_beginDepth > 1) { _beginDepth--; return; } if (_beginDepth == 1 && success && _currentRequirements != null && _currentNames != null) { RecipeConsumptionKey key = new RecipeConsumptionKey(_currentRequirements, _currentQualityLevel); AllowedNames[key] = new HashSet<string>(_currentNames, StringComparer.Ordinal); if (NearbyCraftingForkedPlugin.DebugEnabled) { NearbyCraftingForkedPlugin.Debug($"Recorded {AllowedNames[key].Count} vanilla-consumed requirement name(s) " + $"for quality {_currentQualityLevel}."); } } _currentRequirements = null; _currentNames = null; _currentQualityLevel = 0; _beginDepth = 0; } internal static bool TryGet(Requirement[] requirements, int qualityLevel, out HashSet<string>? allowedNames) { if (requirements != null && AllowedNames.TryGetValue(new RecipeConsumptionKey(requirements, qualityLevel), out var value)) { allowedNames = value; return true; } allowedNames = null; return false; } internal static void Clear() { AllowedNames.Clear(); _currentRequirements = null; _currentNames = null; _currentQualityLevel = 0; _beginDepth = 0; } } internal static class BuildingPlacementState { private static Player? _lastPlacedPlayer; private static int _lastPlacedFrame = -1; internal static void MarkPlaced(Player player, bool placed) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Expected O, but got Unknown if (placed && !((Object)player == (Object)null)) { _lastPlacedPlayer = player; _lastPlacedFrame = Time.frameCount; if (NearbyCraftingForkedPlugin.DebugEnabled) { NearbyCraftingForkedPlugin.Debug($"Successful build placement marked for frame {_lastPlacedFrame}."); } } } internal static bool WasPlacedThisFrame(Player player) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Expected O, but got Unknown //IL_0023: Expected O, but got Unknown if ((Object)player != (Object)null && (Object)_lastPlacedPlayer == (Object)player) { return _lastPlacedFrame == Time.frameCount; } return false; } internal static void Clear() { _lastPlacedPlayer = null; _lastPlacedFrame = -1; } } internal readonly struct ItemCountKey : IEquatable<ItemCountKey> { internal readonly string Name; internal readonly int Quality; internal ItemCountKey(string name, int quality) { Name = name; Quality = quality; } public bool Equals(ItemCountKey other) { if (Quality == other.Quality) { return string.Equals(Name, other.Name, StringComparison.Ordinal); } return false; } public override bool Equals(object? obj) { if (obj is ItemCountKey other) { return Equals(other); } return false; } public override int GetHashCode() { return (((Name != null) ? StringComparer.Ordinal.GetHashCode(Name) : 0) * 397) ^ Quality; } } internal readonly struct CachedCount { internal readonly int Value; internal readonly float CreatedAt; internal readonly int ContainerGeneration; internal CachedCount(int value, float createdAt, int containerGeneration) { Value = value; CreatedAt = createdAt; ContainerGeneration = containerGeneration; } } internal readonly struct ContainerTraits { internal readonly Container Container; internal readonly bool HasPiece; internal readonly bool IsMoving; internal readonly bool IsIncinerator; internal ContainerTraits(Container container, bool hasPiece, bool isMoving, bool isIncinerator) { Container = container; HasPiece = hasPiece; IsMoving = isMoving; IsIncinerator = isIncinerator; } } internal readonly struct ContainerDistance { internal readonly Container Container; internal readonly float DistanceSq; internal ContainerDistance(Container container, float distanceSq) { Container = container; DistanceSq = distanceSq; } } internal static class NearbyContainers { private const float ContainerCacheLifetime = 0.5f; private const float CountCacheLifetime = 0.1f; private const float MovementRefreshDistanceSq = 1f; private static readonly List<Container> CachedContainers = new List<Container>(); private static readonly List<ContainerDistance> ScanBuffer = new List<ContainerDistance>(); private static readonly Dictionary<ItemCountKey, CachedCount> CountCache = new Dictionary<ItemCountKey, CachedCount>(); private static readonly Dictionary<int, ContainerTraits> TraitCache = new Dictionary<int, ContainerTraits>(); private static Player? _cachedPlayer; private static Vector3 _cachedPlayerPosition; private static float _containerCacheCreatedAt = -1000f; private static float _cachedRange = -1f; private static bool _cachedRequirePiece; private static bool _cachedIgnoreMoving; private static bool _cachedIgnoreObliterators; private static bool _cachedBalrondCompatibility; private static int _containerGeneration; internal static void InvalidateAll() { CachedContainers.Clear(); ScanBuffer.Clear(); CountCache.Clear(); TraitCache.Clear(); _cachedPlayer = null; _containerCacheCreatedAt = -1000f; _cachedRange = -1f; _containerGeneration++; } internal static void InvalidateCounts() { CountCache.Clear(); } private static bool ContainerCacheIsValid(Player player, float now) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Expected O, but got Unknown //IL_0015: Expected O, but got Unknown //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) if ((Object)_cachedPlayer != (Object)player) { return false; } if (now - _containerCacheCreatedAt >= 0.5f) { return false; } Vector3 val = ((Component)player).transform.position - _cachedPlayerPosition; if (((Vector3)(ref val)).sqrMagnitude >= 1f) { return false; } if (!Mathf.Approximately(_cachedRange, NearbyCraftingForkedPlugin.Range.Value)) { return false; } if (_cachedRequirePiece != NearbyCraftingForkedPlugin.RequirePlayerPlacedContainer.Value || _cachedIgnoreMoving != NearbyCraftingForkedPlugin.IgnoreMovingContainers.Value || _cachedIgnoreObliterators != NearbyCraftingForkedPlugin.IgnoreObliterators.Value || _cachedBalrondCompatibility != NearbyCraftingForkedPlugin.BalrondCompatibility.Value) { return false; } return true; } internal static List<Container> Get(Player player) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown if ((Object)player == (Object)null) { return CachedContainers; } float realtimeSinceStartup = Time.realtimeSinceStartup; if (ContainerCacheIsValid(player, realtimeSinceStartup)) { return CachedContainers; } RefreshContainerCache(player, realtimeSinceStartup); return CachedContainers; } private static void RefreshContainerCache(Player player, float now) { //IL_0042: 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_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Expected O, but got Unknown //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: 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_02b5: Unknown result type (might be due to invalid IL or missing references) //IL_02b6: Unknown result type (might be due to invalid IL or missing references) CachedContainers.Clear(); ScanBuffer.Clear(); CountCache.Clear(); PruneTraitCache(); float num = Mathf.Max(0f, NearbyCraftingForkedPlugin.Range.Value); float num2 = num * num; Vector3 position = ((Component)player).transform.position; float num3 = (NearbyCraftingForkedPlugin.DebugEnabled ? Time.realtimeSinceStartup : 0f); Container[] array = Object.FindObjectsByType<Container>((FindObjectsSortMode)0); Container[] array2 = array; foreach (Container val in array2) { if ((Object)val == (Object)null || !((Behaviour)val).isActiveAndEnabled) { continue; } Vector3 val2 = ((Component)val).transform.position - position; float sqrMagnitude = ((Vector3)(ref val2)).sqrMagnitude; if (sqrMagnitude > num2) { if (NearbyCraftingForkedPlugin.ContainerDebugEnabled) { NearbyCraftingForkedPlugin.DebugContainer($"Ignoring '{((Object)val).name}': outside {num:0.0}m range."); } continue; } ContainerTraits traits = GetTraits(val); if (NearbyCraftingForkedPlugin.IgnoreObliterators.Value && traits.IsIncinerator) { if (NearbyCraftingForkedPlugin.ContainerDebugEnabled) { NearbyCraftingForkedPlugin.DebugContainer("Ignoring '" + ((Object)val).name + "': Obliterator/Incinerator."); } continue; } if (NearbyCraftingForkedPlugin.RequirePlayerPlacedContainer.Value && !traits.HasPiece) { if (NearbyCraftingForkedPlugin.ContainerDebugEnabled) { NearbyCraftingForkedPlugin.DebugContainer("Ignoring '" + ((Object)val).name + "': not attached to a player-placeable Piece."); } continue; } if (ShouldIgnoreMovingContainer(val, traits)) { if (NearbyCraftingForkedPlugin.ContainerDebugEnabled) { NearbyCraftingForkedPlugin.DebugContainer("Ignoring '" + ((Object)val).name + "': moving container in active use (or ship)."); } continue; } try { if (val.GetInventory() == null) { continue; } } catch (Exception ex) { if (NearbyCraftingForkedPlugin.ContainerDebugEnabled) { NearbyCraftingForkedPlugin.DebugContainer("Skipping '" + ((Object)val).name + "': GetInventory threw " + ex.GetType().Name + ": " + ex.Message); } continue; } ScanBuffer.Add(new ContainerDistance(val, sqrMagnitude)); if (NearbyCraftingForkedPlugin.ContainerDebugEnabled) { NearbyCraftingForkedPlugin.DebugContainer($"Eligible '{((Object)val).name}' at {Mathf.Sqrt(sqrMagnitude):0.0}m."); } } ScanBuffer.Sort((ContainerDistance a, ContainerDistance b) => a.DistanceSq.CompareTo(b.DistanceSq)); for (int num4 = 0; num4 < ScanBuffer.Count; num4++) { CachedContainers.Add(ScanBuffer[num4].Container); } _cachedPlayer = player; _cachedPlayerPosition = position; _containerCacheCreatedAt = now; _cachedRange = NearbyCraftingForkedPlugin.Range.Value; _cachedRequirePiece = NearbyCraftingForkedPlugin.RequirePlayerPlacedContainer.Value; _cachedIgnoreMoving = NearbyCraftingForkedPlugin.IgnoreMovingContainers.Value; _cachedIgnoreObliterators = NearbyCraftingForkedPlugin.IgnoreObliterators.Value; _cachedBalrondCompatibility = NearbyCraftingForkedPlugin.BalrondCompatibility.Value; _containerGeneration++; if (NearbyCraftingForkedPlugin.DebugEnabled) { float num5 = (Time.realtimeSinceStartup - num3) * 1000f; NearbyCraftingForkedPlugin.Debug($"Container cache refreshed: scanned={array.Length}, eligible={CachedContainers.Count}, " + $"time={num5:0.00}ms."); } } private static void PruneTraitCache() { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Expected O, but got Unknown if (TraitCache.Count == 0) { return; } List<int> list = null; foreach (KeyValuePair<int, ContainerTraits> item in TraitCache) { if ((Object)item.Value.Container == (Object)null) { if (list == null) { list = new List<int>(); } list.Add(item.Key); } } if (list != null) { for (int i = 0; i < list.Count; i++) { TraitCache.Remove(list[i]); } } } private static bool ShouldIgnoreMovingContainer(Container container, ContainerTraits traits) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Expected O, but got Unknown if (!traits.IsMoving || NearbyCraftingForkedPlugin.IgnoreMovingContainers == null || !NearbyCraftingForkedPlugin.IgnoreMovingContainers.Value) { return false; } try { Vagon componentInParent = ((Component)container).GetComponentInParent<Vagon>(true); if ((Object)componentInParent != (Object)null) { if (componentInParent.InUse() || componentInParent.IsAttached()) { return true; } return false; } } catch { } return true; } private static bool HasPlayerPlacedPiece(Container container) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Expected O, but got Unknown try { if ((Object)((Component)container).GetComponentInParent<Piece>() != (Object)null) { return true; } if (!NearbyCraftingForkedPlugin.BalrondCompatibility.Value) { return false; } Transform root = ((Component)container).transform.root; if ((Object)root == (Object)null) { return false; } Piece[] componentsInChildren = ((Component)root).GetComponentsInChildren<Piece>(true); bool flag = componentsInChildren != null && componentsInChildren.Length != 0; if (flag && NearbyCraftingForkedPlugin.ContainerDebugEnabled) { NearbyCraftingForkedPlugin.DebugContainer("Accepted '" + ((Object)container).name + "' through sibling-Piece compatibility fallback (root='" + ((Object)root).name + "')."); } return flag; } catch (Exception ex) { if (NearbyCraftingForkedPlugin.ContainerDebugEnabled) { NearbyCraftingForkedPlugin.DebugContainer("Piece-layout inspection failed for '" + ((Object)container).name + "': " + ex.GetType().Name + ": " + ex.Message); } return false; } } private static ContainerTraits GetTraits(Container container) { //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Expected O, but got Unknown int instanceID = ((Object)container).GetInstanceID(); if (TraitCache.TryGetValue(instanceID, out var value) && (Object)(object)value.Container == (Object)(object)container && (value.HasPiece || !NearbyCraftingForkedPlugin.BalrondCompatibility.Value)) { return value; } bool hasPiece = HasPlayerPlacedPiece(container); bool flag = false; bool flag2 = false; try { if ((Object)((Component)container).GetComponentInParent<Incinerator>(true) != (Object)null) { flag2 = true; } } catch { } try { Component[] componentsInParent = ((Component)container).GetComponentsInParent<Component>(true); for (int i = 0; i < componentsInParent.Length; i++) { switch (((object)componentsInParent[i]).GetType().Name) { case "Ship": case "Vagon": case "Wagon": flag = true; break; case "Incinerator": flag2 = true; break; } if (flag && flag2) { break; } } } catch { } ContainerTraits containerTraits = new ContainerTraits(container, hasPiece, flag, flag2); TraitCache[instanceID] = containerTraits; return containerTraits; } internal static int CountCached(Player player, string sharedName, int quality = -1) { List<Container> containers = Get(player); float realtimeSinceStartup = Time.realtimeSinceStartup; ItemCountKey key = new ItemCountKey(sharedName, quality); if (CountCache.TryGetValue(key, out var value) && value.ContainerGeneration == _containerGeneration && realtimeSinceStartup - value.CreatedAt < 0.1f) { return value.Value; } int num = CountAcross(player, containers, sharedName, quality); CountCache[key] = new CachedCount(num, realtimeSinceStartup, _containerGeneration); return num; } internal static int CountFresh(Player player, string sharedName, int quality = -1) { return CountAcross(player, Get(player), sharedName, quality); } private static int CountAcross(Player player, List<Container> containers, string sharedName, int quality) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Expected O, but got Unknown Inventory inventory = ((Humanoid)player).GetInventory(); int num = ((quality >= 0) ? inventory.CountItems(sharedName, quality, true) : inventory.CountItems(sharedName, -1, true)); int num2 = num; for (int i = 0; i < containers.Count; i++) { Container val = containers[i]; if ((Object)val == (Object)null) { continue; } Inventory inventory2; try { inventory2 = val.GetInventory(); } catch { continue; } if (inventory2 != null) { int num3 = ((quality >= 0) ? inventory2.CountItems(sharedName, quality, true) : inventory2.CountItems(sharedName, -1, true)); num2 += num3; if (num3 > 0 && NearbyCraftingForkedPlugin.ContainerDebugEnabled) { NearbyCraftingForkedPlugin.DebugContainer($"Count '{sharedName}': '{((Object)val).name}' contributes {num3}."); } } } if (NearbyCraftingForkedPlugin.DebugEnabled) { NearbyCraftingForkedPlugin.Debug($"Count '{sharedName}' (quality={quality}): player={num}, " + $"nearby={num2 - num}, total={num2}."); } return num2; } internal static int CountNearbyOnly(Player player, string sharedName, int quality, bool matchWorldLevel) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Expected O, but got Unknown if ((Object)player == (Object)null || string.IsNullOrEmpty(sharedName)) { return 0; } List<Container> list = Get(player); int num = 0; for (int i = 0; i < list.Count; i++) { Container val = list[i]; if ((Object)val == (Object)null) { continue; } Inventory inventory; try { inventory = val.GetInventory(); } catch { continue; } if (inventory != null) { int num2 = inventory.CountItems(sharedName, quality, matchWorldLevel); num += num2; if (num2 > 0 && NearbyCraftingForkedPlugin.ContainerDebugEnabled) { NearbyCraftingForkedPlugin.DebugContainer($"Vanilla requirement count '{sharedName}': '{((Object)val).name}' contributes {num2}."); } } } return num; } private static Dictionary<string, int> AggregateRequirements(Requirement[] requirements, int qualityLevel, int multiplier, HashSet<string>? allowedNames = null) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Expected O, but got Unknown Dictionary<string, int> dictionary = new Dictionary<string, int>(StringComparer.Ordinal); foreach (Requirement val in requirements) { if ((Object)(val?.m_resItem) == (Object)null) { continue; } int num = val.GetAmount(qualityLevel) * multiplier; if (num <= 0) { continue; } string name = val.m_resItem.m_itemData.m_shared.m_name; int value; if (allowedNames != null && !allowedNames.Contains(name)) { if (NearbyCraftingForkedPlugin.DebugEnabled) { NearbyCraftingForkedPlugin.Debug("Skipping conditional requirement '" + name + "' during nearby consumption."); } } else if (dictionary.TryGetValue(name, out value)) { dictionary[name] = value + num; } else { dictionary.Add(name, num); } } return dictionary; } internal static bool CanPayPlayerOnly(Player player, Requirement[] requirements, int qualityLevel, int itemQuality, int multiplier, HashSet<string>? allowedNames = null) { Dictionary<string, int> dictionary = AggregateRequirements(requirements, qualityLevel, multiplier, allowedNames); Inventory inventory = ((Humanoid)player).GetInventory(); foreach (KeyValuePair<string, int> item in dictionary) { if (((itemQuality >= 0) ? inventory.CountItems(item.Key, itemQuality, true) : inventory.CountItems(item.Key, -1, true)) < item.Value) { return false; } } return true; } internal static bool CanPayCombined(Player player, Requirement[] requirements, int qualityLevel, int itemQuality, int multiplier, HashSet<string>? allowedNames = null) { foreach (KeyValuePair<string, int> item in AggregateRequirements(requirements, qualityLevel, multiplier, allowedNames)) { int num = CountFresh(player, item.Key, itemQuality); if (num < item.Value) { if (NearbyCraftingForkedPlugin.DebugEnabled) { NearbyCraftingForkedPlugin.Debug($"CanPayCombined=false for '{item.Key}': need={item.Value}, available={num}, " + $"qualityLevel={qualityLevel}, itemQuality={itemQuality}, multiplier={multiplier}."); } return false; } if (NearbyCraftingForkedPlugin.DebugEnabled) { NearbyCraftingForkedPlugin.Debug($"Combined requirement OK for '{item.Key}': need={item.Value}, available={num}."); } } return true; } internal static void Pay(Player player, Requirement[] requirements, int qualityLevel, int itemQuality, int multiplier, HashSet<string>? allowedNames = null) { //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Expected O, but got Unknown Dictionary<string, int> dictionary = AggregateRequirements(requirements, qualityLevel, multiplier, allowedNames); List<Container> list = Get(player); Inventory inventory = ((Humanoid)player).GetInventory(); foreach (KeyValuePair<string, int> item in dictionary) { string key = item.Key; int num = item.Value; int val = ((itemQuality >= 0) ? inventory.CountItems(key, itemQuality, true) : inventory.CountItems(key, -1, true)); int num2 = Math.Min(num, val); if (num2 > 0) { inventory.RemoveItem(key, num2, itemQuality, true); num -= num2; if (NearbyCraftingForkedPlugin.DebugEnabled) { NearbyCraftingForkedPlugin.Debug($"Consumed {num2}x '{key}' from player inventory; remaining={num}."); } } for (int i = 0; i < list.Count && num > 0; i++) { Container val2 = list[i]; if ((Object)val2 == (Object)null) { continue; } Inventory inventory2; try { inventory2 = val2.GetInventory(); } catch { continue; } if (inventory2 == null) { continue; } int val3 = ((itemQuality >= 0) ? inventory2.CountItems(key, itemQuality, true) : inventory2.CountItems(key, -1, true)); int num3 = Math.Min(num, val3); if (num3 > 0) { inventory2.RemoveItem(key, num3, itemQuality, true); num -= num3; if (NearbyCraftingForkedPlugin.DebugEnabled) { NearbyCraftingForkedPlugin.Debug($"Consumed {num3}x '{key}' from container '{((Object)val2).name}'; remaining={num}."); } } } if (num > 0) { NearbyCraftingForkedPlugin.ModLogger.LogWarning((object)($"Resource consumption ended with {num}x '{key}' unpaid. " + "Container contents may have changed during crafting.")); } } InvalidateCounts(); } internal static bool HaveBuildRequirementsCombined(Player player, Piece piece) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Expected O, but got Unknown if ((Object)piece == (Object)null || piece.m_resources == null) { return false; } Dictionary<string, int> dictionary = new Dictionary<string, int>(StringComparer.Ordinal); for (int i = 0; i < piece.m_resources.Length; i++) { Requirement val = piece.m_resources[i]; if (!((Object)(val?.m_resItem) == (Object)null) && val.m_amount > 0) { string name = val.m_resItem.m_itemData.m_shared.m_name; if (dictionary.TryGetValue(name, out var value)) { dictionary[name] = value + val.m_amount; } else { dictionary.Add(name, val.m_amount); } } } foreach (KeyValuePair<string, int> item in dictionary) { int num = CountCached(player, item.Key); if (num < item.Value) { if (NearbyCraftingForkedPlugin.DebugEnabled) { NearbyCraftingForkedPlugin.Debug("Build requirement failed for '" + ((Object)piece).name + "': '" + item.Key + "' " + $"needs={item.Value}, available={num}."); } return false; } } return true; } } internal readonly struct RequirementGraphicEntry { internal readonly Transform Root; internal readonly Graphic Graphic; internal RequirementGraphicEntry(Transform root, Graphic graphic) { Root = root; Graphic = graphic; } } internal static class RequirementUiCache { private static readonly Dictionary<int, RequirementGraphicEntry> Graphics = new Dictionary<int, RequirementGraphicEntry>(); internal static Graphic? GetAmountGraphic(Transform elementRoot) { //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Expected O, but got Unknown //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Expected O, but got Unknown //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Expected O, but got Unknown int instanceID = ((Object)elementRoot).GetInstanceID(); if (Graphics.TryGetValue(instanceID, out var value) && (Object)(object)value.Root == (Object)(object)elementRoot && (Object)value.Graphic != (Object)null) { return value.Graphic; } Transform val = elementRoot.Find("res_amount"); if ((Object)val == (Object)null) { return null; } Graphic component = ((Component)val).GetComponent<Graphic>(); if ((Object)component != (Object)null) { Graphics[instanceID] = new RequirementGraphicEntry(elementRoot, component); } return component; } internal static void Clear() { Graphics.Clear(); } } [HarmonyPatch(typeof(InventoryGui), "DoCrafting")] [HarmonyAfter(new string[] { "balrond.astafaraios.BalrondConstructions" })] internal static class DoCraftingContextPatch { private static void Prefix(ref bool __state) { __state = false; if (NearbyCraftingForkedPlugin.Enabled.Value) { CraftingContext.Depth++; __state = true; if (NearbyCraftingForkedPlugin.DebugEnabled) { NearbyCraftingForkedPlugin.Debug($"DoCrafting entered. CraftingContext.Depth={CraftingContext.Depth}."); } } } private static void Finalizer(bool __state, Exception? __exception) { if (__exception != null) { NearbyCraftingForkedPlugin.ModLogger.LogError((object)("DoCrafting threw " + __exception.GetType().Name + ": " + __exception.Message)); } if (__state && CraftingContext.Depth > 0) { CraftingContext.Depth--; if (NearbyCraftingForkedPlugin.DebugEnabled) { NearbyCraftingForkedPlugin.Debug($"DoCrafting exited. CraftingContext.Depth={CraftingContext.Depth}."); } } } } [HarmonyPatch(typeof(Player), "HaveRequirementItems", new Type[] { typeof(Recipe), typeof(bool), typeof(int), typeof(int) })] [HarmonyAfter(new string[] { "balrond.astafaraios.BalrondConstructions" })] internal static class HaveRequirementItemsPatch { [HarmonyPriority(800)] private static void Prefix(Player __instance, Recipe piece, bool discover, int qualityLevel, int amount) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Expected O, but got Unknown //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Expected O, but got Unknown if (!(!NearbyCraftingForkedPlugin.Enabled.Value || discover) && !((Object)__instance == (Object)null) && !((Object)piece == (Object)null)) { RecipeRequirementContext.Begin(__instance, discover); RecipeConsumptionRules.Begin(piece, qualityLevel); if (NearbyCraftingForkedPlugin.DebugEnabled) { NearbyCraftingForkedPlugin.Debug("Vanilla recipe check with nearby counts enabled for '" + ((Object)piece).name + "' " + $"(qualityLevel={qualityLevel}, amount={amount})."); } } } [HarmonyPriority(0)] private static void Postfix(Recipe piece, bool discover, ref bool __result) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Expected O, but got Unknown if (!(!NearbyCraftingForkedPlugin.Enabled.Value || discover) && !((Object)piece == (Object)null)) { RecipeConsumptionRules.Complete(__result); if (NearbyCraftingForkedPlugin.DebugEnabled) { NearbyCraftingForkedPlugin.Debug($"Vanilla recipe check result for '{((Object)piece).name}' with nearby counts: {__result}."); } } } private static Exception? Finalizer(Exception? __exception) { if (__exception != null) { RecipeConsumptionRules.Complete(success: false); } RecipeRequirementContext.End(); return __exception; } } [HarmonyPatch(typeof(Inventory), "CountItems", new Type[] { typeof(string), typeof(int), typeof(bool) })] [HarmonyAfter(new string[] { "balrond.astafaraios.BalrondConstructions" })] internal static class InventoryCountItemsRequirementPatch { [HarmonyPriority(0)] private static void Postfix(Inventory __instance, string name, int quality, bool matchWorldLevel, ref int __result) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Expected O, but got Unknown if (!NearbyCraftingForkedPlugin.Enabled.Value || !RecipeRequirementContext.IsActive || __instance == null || __instance != RecipeRequirementContext.PlayerInventory) { return; } Player player = RecipeRequirementContext.Player; if ((Object)player == (Object)null) { return; } RecipeConsumptionRules.Record(name); int num = NearbyContainers.CountNearbyOnly(player, name, quality, matchWorldLevel); if (num > 0) { int num2 = __result; __result += num; if (NearbyCraftingForkedPlugin.DebugEnabled) { NearbyCraftingForkedPlugin.Debug($"Vanilla CountItems augmented for '{name}': player={num2}, " + $"nearby={num}, total={__result}, quality={quality}, " + $"matchWorldLevel={matchWorldLevel}."); } } } } [HarmonyPatch(typeof(Player), "TryPlacePiece", new Type[] { typeof(Piece) })] [HarmonyAfter(new string[] { "balrond.astafaraios.BalrondConstructions" })] internal static class TryPlacePiecePatch { private static void Postfix(Player __instance, bool __result) { if (NearbyCraftingForkedPlugin.Enabled.Value && NearbyCraftingForkedPlugin.EnableBuilding.Value) { BuildingPlacementState.MarkPlaced(__instance, __result); } } } [HarmonyPatch(typeof(Player), "HaveRequirements", new Type[] { typeof(Piece), typeof(RequirementMode) })] [HarmonyAfter(new string[] { "balrond.astafaraios.BalrondConstructions" })] internal static class HaveBuildRequirementsPatch { [HarmonyPriority(0)] private static void Postfix(Player __instance, Piece piece, RequirementMode mode, ref bool __result) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Expected O, but got Unknown //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Expected O, but got Unknown //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Expected O, but got Unknown //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Expected O, but got Unknown if (!((!NearbyCraftingForkedPlugin.Enabled.Value || !NearbyCraftingForkedPlugin.EnableBuilding.Value) | __result) && !((Object)__instance == (Object)null) && !((Object)piece == (Object)null) && (int)mode == 0 && (!((Object)piece.m_craftingStation != (Object)null) || Object.op_Implicit((Object)CraftingStation.HaveBuildStationInRange(piece.m_craftingStation.m_name, ((Component)__instance).transform.position))) && NearbyContainers.HaveBuildRequirementsCombined(__instance, piece)) { __result = true; if (NearbyCraftingForkedPlugin.DebugEnabled) { NearbyCraftingForkedPlugin.Debug("HaveRequirements overridden to TRUE for build piece '" + ((Object)piece).name + "'."); } } } } [HarmonyPatch(typeof(Player), "ConsumeResources")] [HarmonyAfter(new string[] { "balrond.astafaraios.BalrondConstructions" })] internal static class ConsumeResourcesPatch { [HarmonyPriority(700)] private static bool Prefix(Player __instance, Requirement[] requirements, int qualityLevel, int itemQuality = -1, int multiplier = 1) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Expected O, but got Unknown bool flag = NearbyCraftingForkedPlugin.EnableBuilding.Value && BuildingPlacementState.WasPlacedThisFrame(__instance); bool flag2 = CraftingContext.IsCrafting || flag; if (!NearbyCraftingForkedPlugin.Enabled.Value || !flag2 || (Object)__instance == (Object)null || requirements == null) { return true; } HashSet<string> allowedNames = null; if (CraftingContext.IsCrafting) { if (RecipeConsumptionRules.TryGet(requirements, qualityLevel, out HashSet<string> allowedNames2) && allowedNames2 != null) { allowedNames = allowedNames2; if (NearbyCraftingForkedPlugin.DebugEnabled) { NearbyCraftingForkedPlugin.Debug($"Using vanilla-recorded requirement set for consumption: {allowedNames2.Count} name(s)."); } } else if (NearbyCraftingForkedPlugin.DebugEnabled) { NearbyCraftingForkedPlugin.Debug("No vanilla-recorded requirement set found for this craft; using unfiltered fallback."); } } if (NearbyContainers.CanPayPlayerOnly(__instance, requirements, qualityLevel, itemQuality, multiplier, allowedNames)) { if (NearbyCraftingForkedPlugin.DebugEnabled) { NearbyCraftingForkedPlugin.Debug("Player inventory can fully pay; using vanilla ConsumeResources (context=" + (flag ? "building" : "crafting") + ")."); } return true; } if (NearbyCraftingForkedPlugin.DebugEnabled) { NearbyCraftingForkedPlugin.Debug("ConsumeResources needs nearby storage for " + string.Format("{0}: requirements={1}, ", flag ? "building" : "crafting", requirements.Length) + $"qualityLevel={qualityLevel}, itemQuality={itemQuality}, multiplier={multiplier}."); } if (!NearbyContainers.CanPayCombined(__instance, requirements, qualityLevel, itemQuality, multiplier, allowedNames)) { if (NearbyCraftingForkedPlugin.DebugEnabled) { NearbyCraftingForkedPlugin.Debug("Combined pre-flight failed; falling back to vanilla without partial chest consumption."); } return true; } NearbyContainers.Pay(__instance, requirements, qualityLevel, itemQuality, multiplier, allowedNames); if (NearbyCraftingForkedPlugin.DebugEnabled) { NearbyCraftingForkedPlugin.Debug("Nearby Crafting completed resource consumption; skipping vanilla ConsumeResources."); } return false; } } [HarmonyPatch(typeof(InventoryGui), "SetupRequirement")] [HarmonyAfter(new string[] { "balrond.astafaraios.BalrondConstructions" })] internal static class SetupRequirementDisplayPatch { [HarmonyPriority(0)] private static void Postfix(Transform elementRoot, Requirement req, Player player, bool craft, int quality) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Expected O, but got Unknown //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Expected O, but got Unknown //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Expected O, but got Unknown //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Expected O, but got Unknown //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) if (!NearbyCraftingForkedPlugin.Enabled.Value || !NearbyCraftingForkedPlugin.FixRequirementIndicator.Value || (Object)elementRoot == (Object)null || (Object)(req?.m_resItem) == (Object)null || (Object)player == (Object)null) { return; } Graphic amountGraphic = RequirementUiCache.GetAmountGraphic(elementRoot); if ((Object)amountGraphic == (Object)null) { return; } Color color = amountGraphic.color; if (color == Color.white) { return; } int amount = req.GetAmount(quality); if (amount <= 0) { return; } string name = req.m_resItem.m_itemData.m_shared.m_name; int num = NearbyContainers.CountCached(player, name); if (num >= amount) { amountGraphic.color = Color.white; if (NearbyCraftingForkedPlugin.DebugEnabled) { NearbyCraftingForkedPlugin.Debug($"UI indicator corrected for '{name}': need={amount}, available={num}, " + $"previousColor={color}."); } } } } internal static class StationChestAssist { internal enum MoveToPlayerResult { Failed, InventoryFull, Moved } internal static readonly Func<Smelter, float>? SmelterGetFuel = CreateDelegate<Func<Smelter, float>>(typeof(Smelter), "GetFuel", Array.Empty<Type>()); internal static readonly Func<CookingStation, float>? CookingGetFuel = CreateDelegate<Func<CookingStation, float>>(typeof(CookingStation), "GetFuel", Array.Empty<Type>()); internal static readonly Func<ShieldGenerator, float>? ShieldGetFuel = CreateDelegate<Func<ShieldGenerator, float>>(typeof(ShieldGenerator), "GetFuel", Array.Empty<Type>()); internal static readonly Func<Smelter, int>? SmelterGetQueueSize = CreateDelegate<Func<Smelter, int>>(typeof(Smelter), "GetQueueSize", Array.Empty<Type>()); internal static readonly Func<Smelter, Inventory, ItemData>? SmelterFindCookableItem = CreateDelegate<Func<Smelter, Inventory, ItemData>>(typeof(Smelter), "FindCookableItem", new Type[1] { typeof(Inventory) }); private static readonly FieldInfo? FireplaceNview = AccessTools.Field(typeof(Fireplace), "m_nview"); internal static bool IsAssistEnabled { get { if (NearbyCraftingForkedPlugin.Enabled != null && NearbyCraftingForkedPlugin.Enabled.Value && NearbyCraftingForkedPlugin.StationFuelEnabled != null) { return NearbyCraftingForkedPlugin.StationFuelEnabled.Value; } return false; } } internal static void NotifyInventoryFull(Humanoid user) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown if (!((Object)user == (Object)null)) { ((Character)user).Message((MessageType)2, "$msg_noroom", 0, (Sprite)null, false); } } internal static MoveToPlayerResult TryMoveOneToPlayer(Inventory from, Inventory to, ItemData item) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Expected O, but got Unknown if (from == null || to == null || item == null || (Object)item.m_dropPrefab == (Object)null) { return MoveToPlayerResult.Failed; } GameObject dropPrefab = item.m_dropPrefab; if (!to.CanAddItem(dropPrefab, 1)) { return MoveToPlayerResult.InventoryFull; } if (!from.RemoveOneItem(item)) { return MoveToPlayerResult.Failed; } if (!to.AddItem(dropPrefab, 1)) { from.AddItem(dropPrefab, 1); return MoveToPlayerResult.InventoryFull; } return MoveToPlayerResult.Moved; } internal static bool TryPullOneToPlayer(Humanoid user, string sharedName) { //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Expected O, but got Unknown //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Expected O, but got Unknown //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Expected O, but got Unknown //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Expected O, but got Unknown //IL_0070: Expected O, but got Unknown if (!IsAssistEnabled || (Object)(object)user == (Object)null || string.IsNullOrEmpty(sharedName)) { return false; } Inventory inventory = user.GetInventory(); if (inventory == null) { return false; } if (inventory.HaveItem(sharedName, true)) { return false; } Player val = (Player)(object)((user is Player) ? user : null); if ((Object)val == (Object)null) { val = Player.m_localPlayer; } if ((Object)val == (Object)null || (Object)val != (Object)Player.m_localPlayer) { return false; } List<Container> list = NearbyContainers.Get(val); for (int i = 0; i < list.Count; i++) { Container val2 = list[i]; if ((Object)val2 == (Object)null) { continue; } Inventory inventory2; try { inventory2 = val2.GetInventory(); } catch { continue; } if (inventory2 == null) { continue; } ItemData item = inventory2.GetItem(sharedName, -1, false); if (item == null) { continue; } switch (TryMoveOneToPlayer(inventory2, inventory, item)) { case MoveToPlayerResult.InventoryFull: NotifyInventoryFull(user); return false; case MoveToPlayerResult.Moved: NearbyContainers.InvalidateCounts(); if (NearbyCraftingForkedPlugin.DebugEnabled) { NearbyCraftingForkedPlugin.Debug("Station fuel assist pulled 1x '" + sharedName + "' from '" + ((Object)val2).name + "'."); } return true; } } return false; } private static TDelegate? CreateDelegate<TDelegate>(Type type, string name, params Type[] parameters) where TDelegate : Delegate { MethodInfo methodInfo = ((parameters == null || parameters.Length == 0) ? AccessTools.Method(type, name, (Type[])null, (Type[])null) : AccessTools.Method(type, name, parameters, (Type[])null)); if (methodInfo == null) { return null; } return AccessTools.MethodDelegate<TDelegate>(methodInfo, (object)null, true); } internal static bool TryPullFuelItemDrop(Humanoid user, ItemDrop? fuelItem) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown if ((Object)fuelItem == (Object)null || fuelItem.m_itemData?.m_shared == null) { return false; } return TryPullOneToPlayer(user, fuelItem.m_itemData.m_shared.m_name); } internal static float GetFireplaceFuel(Fireplace fireplace) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Expected O, but got Unknown object? obj = FireplaceNview?.GetValue(fireplace); ZNetView val = (ZNetView)((obj is ZNetView) ? obj : null); if ((Object)val == (Object)null || !val.IsValid()) { return 0f; } return val.GetZDO().GetFloat(ZDOVars.s_fuel, 0f); } } [HarmonyPatch(typeof(Smelter), "OnAddFuel")] internal static class SmelterOnAddFuelPatch { private static void Prefix(Smelter __instance, Humanoid user, ItemData item) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Expected O, but got Unknown //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Expected O, but got Unknown if (StationChestAssist.IsAssistEnabled && item == null && !((Object)__instance == (Object)null) && !((Object)user == (Object)null)) { Func<Smelter, float> smelterGetFuel = StationChestAssist.SmelterGetFuel; if (smelterGetFuel == null || !(smelterGetFuel(__instance) > (float)(__instance.m_maxFuel - 1))) { StationChestAssist.TryPullFuelItemDrop(user, __instance.m_fuelItem); } } } } [HarmonyPatch(typeof(Smelter), "OnAddOre")] internal static class SmelterOnAddOrePatch { private static void Prefix(Smelter __instance, Humanoid user, ItemData item) { //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Expected O, but got Unknown //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Expected O, but got Unknown //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Expected O, but got Unknown //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Expected O, but got Unknown //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Expected O, but got Unknown //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Expected O, but got Unknown //IL_00b0: Expected O, but got Unknown Func<Smelter, Inventory, ItemData> smelterFindCookableItem = StationChestAssist.SmelterFindCookableItem; if (!StationChestAssist.IsAssistEnabled || NearbyCraftingForkedPlugin.EnableOreFromChests == null || !NearbyCraftingForkedPlugin.EnableOreFromChests.Value || item != null || (Object)__instance == (Object)null || (Object)user == (Object)null || smelterFindCookableItem == null) { return; } Func<Smelter, int> smelterGetQueueSize = StationChestAssist.SmelterGetQueueSize; if (smelterGetQueueSize != null && smelterGetQueueSize(__instance) >= __instance.m_maxOre) { return; } Inventory inventory = user.GetInventory(); if (inventory == null || smelterFindCookableItem(__instance, inventory) != null) { return; } Player val = (Player)(object)((user is Player) ? user : null); if ((Object)val == (Object)null) { val = Player.m_localPlayer; } if ((Object)val == (Object)null || (Object)val != (Object)Player.m_localPlayer) { return; } List<Container> list = NearbyContainers.Get(val); for (int i = 0; i < list.Count; i++) { Container val2 = list[i]; if ((Object)val2 == (Object)null) { continue; } Inventory inventory2; try { inventory2 = val2.GetInventory(); } catch { continue; } if (inventory2 == null) { continue; } ItemData val3 = smelterFindCookableItem(__instance, inventory2); if (val3 == null) { continue; } switch (StationChestAssist.TryMoveOneToPlayer(inventory2, inventory, val3)) { case StationChestAssist.MoveToPlayerResult.InventoryFull: StationChestAssist.NotifyInventoryFull(user); return; case StationChestAssist.MoveToPlayerResult.Moved: NearbyContainers.InvalidateCounts(); if (NearbyCraftingForkedPlugin.DebugEnabled) { NearbyCraftingForkedPlugin.Debug("Station ore assist pulled '" + val3.m_shared?.m_name + "' from '" + ((Object)val2).name + "'."); } return; } } } } [HarmonyPatch(typeof(Fireplace), "Interact")] internal static class FireplaceInteractPatch { private static void Prefix(Fireplace __instance, Humanoid user, bool hold, bool alt) { bool willAddFuel = FireplaceFuelAssist.WillInteractAddFuel(__instance, hold, alt); FireplaceFuelAssist.TryAssist(__instance, user, willAddFuel); } } internal static class FireplaceFuelAssist { internal static bool WillInteractAddFuel(Fireplace fireplace, bool hold, bool alt) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown if ((Object)fireplace == (Object)null || fireplace.m_infiniteFuel || !fireplace.m_canRefill) { return false; } float fireplaceFuel = StationChestAssist.GetFireplaceFuel(fireplace); if ((float)Mathf.CeilToInt(fireplaceFuel) >= fireplace.m_maxFuel) { return false; } if (fireplace.m_canTurnOff && !hold && !alt && fireplaceFuel > 0f) { return false; } return true; } internal static void TryAssist(Fireplace fireplace, Humanoid user, bool willAddFuel) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Expected O, but got Unknown //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Expected O, but got Unknown if (willAddFuel && StationChestAssist.IsAssistEnabled && !((Object)fireplace == (Object)null) && !((Object)user == (Object)null)) { StationChestAssist.TryPullFuelItemDrop(user, fireplace.m_fuelItem); } } } [HarmonyPatch(typeof(CookingStation), "OnAddFuelSwitch")] internal static class CookingStationOnAddFuelSwitchPatch { private static void Prefix(CookingStation __instance, Humanoid user, ItemData item) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Expected O, but got Unknown //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Expected O, but got Unknown if (StationChestAssist.IsAssistEnabled && item == null && !((Object)__instance == (Object)null) && !((Object)user == (Object)null) && __instance.m_useFuel) { Func<CookingStation, float> cookingGetFuel = StationChestAssist.CookingGetFuel; if (cookingGetFuel == null || !(cookingGetFuel(__instance) > (float)(__instance.m_maxFuel - 1))) { StationChestAssist.TryPullFuelItemDrop(user, __instance.m_fuelItem); } } } } [HarmonyPatch(typeof(ShieldGenerator), "OnAddFuel")] internal static class ShieldGeneratorOnAddFuelPatch { private static void Prefix(ShieldGenerator __instance, Humanoid user, ItemData item) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Expected O, but got Unknown //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Expected O, but got Unknown //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Expected O, but got Unknown if (!StationChestAssist.IsAssistEnabled || item != null || (Object)__instance == (Object)null || (Object)user == (Object)null) { return; } Func<ShieldGenerator, float> shieldGetFuel = StationChestAssist.ShieldGetFuel; if (shieldGetFuel != null && shieldGetFuel(__instance) >= (float)__instance.m_maxFuel) { return; } List<ItemDrop> fuelItems = __instance.m_fuelItems; if (fuelItems == null || fuelItems.Count == 0) { return; } Inventory inventory = user.GetInventory(); if (inventory == null) { return; } for (int i = 0; i < fuelItems.Count; i++) { ItemDrop val = fuelItems[i]; if (!((Object)val == (Object)null) && val.m_itemData?.m_shared != null) { string name = val.m_itemData.m_shared.m_name; if (inventory.HaveItem(name, true)) { return; } } } for (int j = 0; j < fuelItems.Count && !StationChestAssist.TryPullFuelItemDrop(user, fuelItems[j]); j++) { } } } internal static class ItemLocate { private sealed class HighlightedChest { private readonly List<RendererGlow> _renderers = new List<RendererGlow>(); internal static HighlightedChest? TryCreate(Container container) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Expected O, but got Unknown Renderer[] highlightRenderers = GetHighlightRenderers(container); if (highlightRenderers == null || highlightRenderers.Length == 0) { return null; } HighlightedChest highlightedChest = new HighlightedChest(); foreach (Renderer val in highlightRenderers) { if (!((Object)val == (Object)null) && !(val is ParticleSystemRenderer) && !(val is LineRenderer) && !(val is TrailRenderer)) { RendererGlow rendererGlow = RendererGlow.TryCreate(val); if (rendererGlow != null) { highlightedChest._renderers.Add(rendererGlow); } } } if (highlightedChest._renderers.Count == 0) { return null; } return highlightedChest; } private static Renderer[] GetHighlightRenderers(Container container) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Expected O, but got Unknown Component val = (Component)(object)container; try { Vagon componentInParent = ((Component)container).GetComponentInParent<Vagon>(true); if ((Object)componentInParent != (Object)null) { val = (Component)(object)componentInParent; } } catch { } return val.GetComponentsInChildren<Renderer>(true); } internal void ApplyGlow(Color color) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) for (int i = 0; i < _renderers.Count; i++) { _renderers[i].Apply(color); } } internal void Restore() { for (int i = 0; i < _renderers.Count; i++) { _renderers[i].Restore(); } _renderers.Clear(); } } private sealed class RendererGlow { private readonly Renderer _renderer; private readonly bool _usedMaterialInstances; private readonly Material[]? _originalSharedMaterials; private readonly Material[]? _instancedMaterials; private readonly Color[]? _originalEmission; private readonly bool[]? _hadEmissionKeyword; private RendererGlow(Renderer renderer, bool usedMaterialInstances, Material[]? originalSharedMaterials, Material[]? instancedMaterials, Color[]? originalEmission, bool[]? hadEmissionKeyword) { _renderer = renderer; _usedMaterialInstances = usedMaterialInstances; _originalSharedMaterials = originalSharedMaterials; _instancedMaterials = instancedMaterials; _originalEmission = originalEmission; _hadEmissionKeyword = hadEmissionKeyword; } internal static RendererGlow? TryCreate(Renderer renderer) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Expected O, but got Unknown //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Expected O, but got Unknown //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Expected O, but got Unknown //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Expected O, but got Unknown //IL_0142: Expected O, but got Unknown Material[] sharedMaterials = renderer.sharedMaterials; if (sharedMaterials == null || sharedMaterials.Length == 0) { return null; } renderer.GetPropertyBlock(PropertyBlock); PropertyBlock.SetColor("_EmissionColor", Color.black); renderer.SetPropertyBlock(PropertyBlock); if (SupportsEmissionViaPropertyBlock(renderer)) { return new RendererGlow(renderer, usedMaterialInstances: false, null, null, null, null); } Material[] array = (Material[])(object)new Material[sharedMaterials.Length]; Material[] array2 = (Material[])(object)new Material[sharedMaterials.Length]; Color[] array3 = (Color[])(object)new Color[sharedMaterials.Length]; bool[] array4 = new bool[sharedMaterials.Length]; bool flag = false; for (int i = 0; i < sharedMaterials.Length; i++) { Material val = (array[i] = sharedMaterials[i]); if ((Object)val == (Object)null) { array2[i] = val; continue; } Material val2 = (array2[i] = new Material(val)); array4[i] = val2.IsKeywordEnabled("_EMISSION"); if (val2.HasProperty("_EmissionColor")) { array3[i] = val2.GetColor("_EmissionColor"); val2.EnableKeyword("_EMISSION"); flag = true; } else { array3[i] = Color.black; } } if (!flag) { for (int j = 0; j < array2.Length; j++) { if ((Object)array2[j] != (Object)null && (Object)array2[j] != (Object)array[j]) { Object.Destroy((Object)(object)array2[j]); } } return null; } renderer.materials = array2; return new RendererGlow(renderer, usedMaterialInstances: true, array, array2, array3, array4); } private static bool SupportsEmissionViaPropertyBlock(Renderer renderer) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown Material[] sharedMaterials = renderer.sharedMaterials; foreach (Material val in sharedMaterials) { if ((Object)val != (Object)null && val.HasProperty("_EmissionColor")) { return true; } } return false; } internal void Apply(Color color) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Expected O, but got Unknown //IL_0084: Unknown result type (might be due to invalid IL or missing references) if ((Object)_renderer == (Object)null) { return; } if (!_usedMaterialInstances) { _renderer.GetPropertyBlock(PropertyBlock); PropertyBlock.SetColor("_EmissionColor", color); _renderer.SetPropertyBlock(PropertyBlock); } else { if (_instancedMaterials == null) { return; } for (int i = 0; i < _instancedMaterials.Length; i++) { Material val = _instancedMaterials[i]; if ((Object)val != (Object)null && val.HasProperty("_EmissionColor")) { val.SetColor("_EmissionColor", color); } } } } internal void Restore() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Expected O, but got Unknown //IL_00af: Unknown result type (might be due to invalid IL or missing references) if ((Object)_renderer == (Object)null) { return; } if (!_usedMaterialInstances) { _renderer.GetPropertyBlock(PropertyBlock); PropertyBlock.SetColor("_EmissionColor", Color.black); _renderer.SetPropertyBlock(PropertyBlock); return; } if (_originalSharedMaterials != null) { _renderer.sharedMaterials = _originalSharedMaterials; } if (_instancedMaterials == null) { return; } for (int i = 0; i < _instancedMaterials.Length; i++) { Material val = _instancedMaterials[i]; if (!((Object)val == (Object)null)) { if (_originalEmission != null && val.HasProperty("_EmissionColor")) { val.SetColor("_EmissionColor", _originalEmission[i]); } if (_hadEmissionKeyword != null && !_hadEmissionKeyword[i]) { val.DisableKeyword("_EMISSION"); } Object.Destroy((Object)(object)val); } } } } private const string EmissionColorProperty = "_EmissionColor"; private static readonly List<HighlightedChest> Active = new List<HighlightedChest>(); private static readonly MaterialPropertyBlock PropertyBlock = new MaterialPropertyBlock(); private static bool _commandRegistered; private static float _activeUntil = -1f; private static Color _baseGlow = new Color(0.55f, 0.45f, 0.1f, 1f); private static float _glowAlpha = 1f; private static Func<string, string> _localizeName; private static bool _localizeResolved; internal static void RegisterCommand() { if (!_commandRegistered) { _commandRegistered = true; RegisterOne("nearby", "[item|clear] Highlight nearby eligible chests and carts containing an item (or clear). No args uses held item."); RegisterOne("locate", "[item|clear] Alias for nearby — highlight chests and carts containing an item."); } } private static void RegisterOne(string command, string description) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Expected O, but got Unknown //IL_0018: Unknown result type (might be due to invalid IL or missing references) new ConsoleCommand(command, description, new ConsoleEvent(OnCommand), false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); } internal static void ClearHighlights() { for (int i = 0; i < Active.Count; i++) { Active[i].Restore(); } Active.Clear(); _activeUntil = -1f; } internal static void HighlightContainers(List<Container> containers, string? colorRaw, Color fallback, float durationSeconds, float alpha) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: 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_0052: Expected O, but got Unknown ClearHighlights(); if (containers == null || containers.Count == 0) { return; } _baseGlow = ParseGlowColor(colorRaw, fallback); _glowAlpha = Mathf.Clamp01(alpha); float num = Mathf.Clamp(durationSeconds, 1f, 120f); for (int i = 0; i < containers.Count; i++) { Container val = containers[i]; if (!((Object)val == (Object)null)) { HighlightedChest highlightedChest = HighlightedChest.TryCreate(val); if (highlightedChest != null) { Active.Add(highlightedChest); } } } if (Active.Count != 0) { _activeUntil = Time.realtimeSinceStartup + num; Tick(); if (NearbyCraftingForkedPlugin.DebugEnabled) { NearbyCraftingForkedPlugin.Debug($"Quick-deposit highlight: glowing={Active.Count}, duration={num:0.#}s."); } } } internal static void Tick() { //IL_008b: Unknown result type (might be due to invalid IL or missing references) if (Active.Count == 0) { return; } float realtimeSinceStartup = Time.realtimeSinceStartup; if (realtimeSinceStartup >= _activeUntil) { ClearHighlights(); return; } float num = (0.45f + 0.55f * (0.5f + 0.5f * Mathf.Sin(realtimeSinceStartup * 5f))) * _glowAlpha; Color color