using System; using System.Collections; 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 System.Security; using System.Security.Permissions; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using TMPro; using UnityEngine; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("StoreAndCraft")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+90e867a18187e478d916d898790b505a6bfe1b78")] [assembly: AssemblyProduct("StoreAndCraft")] [assembly: AssemblyTitle("StoreAndCraft")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] namespace StoreAndCraft; public class ModConfig { public const int ProtocolVersion = 1; public ConfigEntry LockConfig { get; } public ConfigEntry ModEnabled { get; } public ConfigEntry StoreEnabled { get; } public ConfigEntry CraftEnabled { get; } public ConfigEntry MustHaveExisting { get; } public ConfigEntry LeaveOneItem { get; } public ConfigEntry IgnoreHotbar { get; } public ConfigEntry HighlightOnStore { get; } public ConfigEntry PingOnStore { get; } public ConfigEntry PlayerDumpRange { get; } public ConfigEntry StoreRange { get; } public ConfigEntry CraftRange { get; } public ConfigEntry IntakeInterval { get; } public ConfigEntry PauseSeconds { get; } public ConfigEntry MaxTransfersPerTick { get; } public ConfigEntry DumpKey { get; } public ConfigEntry HoverStoreKey { get; } public ConfigEntry PauseKey { get; } public ConfigEntry SearchKey { get; } public ConfigEntry PreventPullKey { get; } public ConfigEntry RenameKey { get; } public ModConfig(ConfigFile file) { //IL_01d1: Unknown result type (might be due to invalid IL or missing references) //IL_01fb: Unknown result type (might be due to invalid IL or missing references) //IL_022b: Unknown result type (might be due to invalid IL or missing references) //IL_0252: Unknown result type (might be due to invalid IL or missing references) //IL_0282: Unknown result type (might be due to invalid IL or missing references) //IL_02b2: Unknown result type (might be due to invalid IL or missing references) LockConfig = file.Bind("1 - General", "LockConfig", true, "If enabled, gameplay settings come from the server and clients cannot override them."); ModEnabled = file.Bind("1 - General", "ModEnabled", true, "Turns the whole mod on or off without uninstalling."); StoreEnabled = file.Bind("2 - Store", "StoreEnabled", true, "If enabled, ground items can be auto-stored and dump / middle-click store works."); CraftEnabled = file.Bind("3 - Craft", "CraftEnabled", true, "If enabled, crafting and building can use items stored in nearby chests."); MustHaveExisting = file.Bind("2 - Store", "MustHaveExisting", true, "If enabled, a chest only accepts an item if that item is already inside it. Empty chests will not vacuum new item types."); LeaveOneItem = file.Bind("3 - Craft", "LeaveOneItem", true, "If enabled, crafting/building leaves 1 item in each chest so auto-store can keep filling that stack."); IgnoreHotbar = file.Bind("2 - Store", "IgnoreHotbar", true, "If enabled, dump will not move items from the hotbar (first inventory row)."); HighlightOnStore = file.Bind("2 - Store", "HighlightOnStore", true, "If enabled, a chest flashes when something is stored into it."); PingOnStore = file.Bind("2 - Store", "PingOnStore", false, "If enabled, a map ping is placed on the chest after a store."); PlayerDumpRange = file.Bind("2 - Store", "PlayerDumpRange", 8f, "Fallback dump / middle-click range in meters (player to chest). YAML dumpRange overrides this."); StoreRange = file.Bind("2 - Store", "StoreRange", 10f, "Fallback auto-store range in meters (item on ground to chest). YAML storeRange overrides this."); CraftRange = file.Bind("3 - Craft", "CraftRange", 20f, "Fallback craft/build range in meters (player to chest). YAML craftRange overrides this."); IntakeInterval = file.Bind("2 - Store", "IntakeInterval", 5f, "Seconds between automatic scans for ground items. Lower = snappier, higher = less CPU."); PauseSeconds = file.Bind("2 - Store", "PauseSeconds", 10f, "How many seconds auto-store stays paused after the pause hotkey."); MaxTransfersPerTick = file.Bind("1 - General", "MaxTransfersPerTick", 8, "Maximum item moves per frame. Raise only if storing feels too slow."); DumpKey = file.Bind("4 - Keys", "DumpKey", new KeyboardShortcut((KeyCode)46, Array.Empty()), "Hotkey: move allowed inventory stacks into nearby chests that already hold those items."); HoverStoreKey = file.Bind("4 - Keys", "HoverStoreKey", new KeyboardShortcut((KeyCode)325, Array.Empty()), "Hotkey: store the inventory item under the cursor. If no item is hovered, dumps all allowed stacks."); PauseKey = file.Bind("4 - Keys", "PauseKey", new KeyboardShortcut((KeyCode)112, (KeyCode[])(object)new KeyCode[1] { (KeyCode)308 }), "Hotkey: pause auto-store for PauseSeconds."); SearchKey = file.Bind("4 - Keys", "SearchKey", new KeyboardShortcut((KeyCode)121, Array.Empty()), "Hold this key and click an inventory item to ping the nearest chest that contains it."); PreventPullKey = file.Bind("4 - Keys", "PreventPullKey", new KeyboardShortcut((KeyCode)111, (KeyCode[])(object)new KeyCode[1] { (KeyCode)308 }), "Hotkey: locally disable pulling from chests for crafting/building."); RenameKey = file.Bind("4 - Keys", "RenameKey", new KeyboardShortcut((KeyCode)101, (KeyCode[])(object)new KeyCode[1] { (KeyCode)308 }), "Look at a chest and hold this combo instead of opening it. Shift+E (Valheim alt-use) also renames. The custom name is shown on hover."); } public void WriteToPackage(ZPackage pkg) { pkg.Write(LockConfig.Value); pkg.Write(ModEnabled.Value); pkg.Write(StoreEnabled.Value); pkg.Write(CraftEnabled.Value); pkg.Write(MustHaveExisting.Value); pkg.Write(LeaveOneItem.Value); pkg.Write(PlayerDumpRange.Value); pkg.Write(StoreRange.Value); pkg.Write(CraftRange.Value); pkg.Write(IntakeInterval.Value); pkg.Write(PauseSeconds.Value); pkg.Write(MaxTransfersPerTick.Value); } public void ReadFromPackage(ZPackage pkg) { LockConfig.Value = pkg.ReadBool(); ModEnabled.Value = pkg.ReadBool(); StoreEnabled.Value = pkg.ReadBool(); CraftEnabled.Value = pkg.ReadBool(); MustHaveExisting.Value = pkg.ReadBool(); LeaveOneItem.Value = pkg.ReadBool(); PlayerDumpRange.Value = pkg.ReadSingle(); StoreRange.Value = pkg.ReadSingle(); CraftRange.Value = pkg.ReadSingle(); IntakeInterval.Value = pkg.ReadSingle(); PauseSeconds.Value = pkg.ReadSingle(); MaxTransfersPerTick.Value = pkg.ReadInt(); } } internal sealed class PieceRule { public bool? Store; public bool? Craft; public float? StoreRange; public float? CraftRange; public float? DumpRange; public readonly List Allow = new List(); public readonly List Deny = new List(); } internal static class RulesFile { private static readonly Dictionary Pieces = new Dictionary(StringComparer.OrdinalIgnoreCase); public static float? DefaultStoreRange { get; private set; } public static float? DefaultCraftRange { get; private set; } public static float? DefaultDumpRange { get; private set; } public static string Path => System.IO.Path.Combine(Paths.ConfigPath, "StoreAndCraft.rules.yml"); public static void LoadOrCreate() { try { if (!File.Exists(Path)) { File.WriteAllText(Path, DefaultText(), Encoding.UTF8); } Parse(File.ReadAllLines(Path)); Plugin.Log.LogInfo((object)("StoreAndCraft rules loaded (" + Pieces.Count + " piece entries).")); } catch (Exception ex) { Plugin.Log.LogWarning((object)("StoreAndCraft rules failed: " + ex.Message)); } } public static PieceRule Get(string piecePrefab) { if (string.IsNullOrEmpty(piecePrefab)) { return null; } if (!Pieces.TryGetValue(piecePrefab, out var value)) { return null; } return value; } public static bool AllowsStore(string piecePrefab, ItemData item) { return Allows(piecePrefab, item, store: true); } public static bool AllowsCraft(string piecePrefab, string sharedName) { PieceRule pieceRule = Get(piecePrefab); if (pieceRule != null && pieceRule.Craft.HasValue && !pieceRule.Craft.Value) { return false; } if (pieceRule == null) { return true; } return MatchesLists(pieceRule, sharedName, null); } public static bool AllowsCraft(string piecePrefab, ItemData item) { return Allows(piecePrefab, item, store: false); } private static bool Allows(string piecePrefab, ItemData item, bool store) { PieceRule pieceRule = Get(piecePrefab); if (pieceRule == null) { return true; } if (store && pieceRule.Store.HasValue && !pieceRule.Store.Value) { return false; } if (!store && pieceRule.Craft.HasValue && !pieceRule.Craft.Value) { return false; } return MatchesLists(pieceRule, ItemIds.SharedName(item), item); } private static bool MatchesLists(PieceRule rule, string sharedName, ItemData item) { if (rule.Deny.Count > 0) { foreach (string item2 in rule.Deny) { if (item != null && ItemIds.Matches(item, item2)) { return false; } if (item == null && NamesEqual(sharedName, item2)) { return false; } } } if (rule.Allow.Count == 0) { return true; } foreach (string item3 in rule.Allow) { if (item != null && ItemIds.Matches(item, item3)) { return true; } if (item == null && NamesEqual(sharedName, item3)) { return true; } } return false; } private static bool NamesEqual(string sharedName, string token) { if (string.IsNullOrEmpty(sharedName) || string.IsNullOrEmpty(token)) { return false; } if (string.Equals(sharedName, token, StringComparison.OrdinalIgnoreCase)) { return true; } string b = ItemIds.SharedFromToken(token); return string.Equals(sharedName, b, StringComparison.OrdinalIgnoreCase); } public static float StoreRange(string piecePrefab, float fallback) { PieceRule pieceRule = Get(piecePrefab); if (pieceRule != null && pieceRule.StoreRange.HasValue) { return pieceRule.StoreRange.Value; } if (DefaultStoreRange.HasValue) { return DefaultStoreRange.Value; } return fallback; } public static float CraftRange(string piecePrefab, float fallback) { PieceRule pieceRule = Get(piecePrefab); if (pieceRule != null && pieceRule.CraftRange.HasValue) { return pieceRule.CraftRange.Value; } if (DefaultCraftRange.HasValue) { return DefaultCraftRange.Value; } return fallback; } public static float DumpRange(string piecePrefab, float fallback) { PieceRule pieceRule = Get(piecePrefab); if (pieceRule != null && pieceRule.DumpRange.HasValue) { return pieceRule.DumpRange.Value; } if (DefaultDumpRange.HasValue) { return DefaultDumpRange.Value; } return fallback; } public static float MaxScanRange(float cfgStore, float cfgCraft, float cfgDump) { float num = Mathf.Max(new float[3] { cfgStore, cfgCraft, cfgDump }); if (DefaultStoreRange.HasValue) { num = Mathf.Max(num, DefaultStoreRange.Value); } if (DefaultCraftRange.HasValue) { num = Mathf.Max(num, DefaultCraftRange.Value); } if (DefaultDumpRange.HasValue) { num = Mathf.Max(num, DefaultDumpRange.Value); } foreach (PieceRule value in Pieces.Values) { if (value.StoreRange.HasValue) { num = Mathf.Max(num, value.StoreRange.Value); } if (value.CraftRange.HasValue) { num = Mathf.Max(num, value.CraftRange.Value); } if (value.DumpRange.HasValue) { num = Mathf.Max(num, value.DumpRange.Value); } } return num; } private static void Parse(string[] lines) { Pieces.Clear(); DefaultStoreRange = null; DefaultCraftRange = null; DefaultDumpRange = null; string text = null; PieceRule pieceRule = null; string text2 = null; bool flag = false; for (int i = 0; i < lines.Length; i++) { string text3 = lines[i]; int num = text3.IndexOf('#'); if (num >= 0) { text3 = text3.Substring(0, num); } if (string.IsNullOrWhiteSpace(text3)) { continue; } int j; for (j = 0; j < text3.Length && text3[j] == ' '; j++) { } text3 = text3.Trim(); if (j == 0 && text3.EndsWith(":") && !text3.Equals("defaults:", StringComparison.OrdinalIgnoreCase) && !text3.Equals("pieces:", StringComparison.OrdinalIgnoreCase)) { continue; } if (text3.Equals("defaults:", StringComparison.OrdinalIgnoreCase)) { flag = true; text = null; pieceRule = null; text2 = null; } else if (text3.Equals("pieces:", StringComparison.OrdinalIgnoreCase)) { flag = false; text = null; pieceRule = null; text2 = null; } else if (flag) { if (SplitKv(text3, out var key, out var value)) { if (key.Equals("storeRange", StringComparison.OrdinalIgnoreCase)) { DefaultStoreRange = ParseFloat(value); } else if (key.Equals("craftRange", StringComparison.OrdinalIgnoreCase)) { DefaultCraftRange = ParseFloat(value); } else if (key.Equals("dumpRange", StringComparison.OrdinalIgnoreCase)) { DefaultDumpRange = ParseFloat(value); } } } else if (j <= 2 && text3.EndsWith(":") && j < 4 && !IsKeyValue(text3)) { text = text3.TrimEnd(new char[1] { ':' }).Trim(); pieceRule = new PieceRule(); Pieces[text] = pieceRule; text2 = null; } else { if (pieceRule == null) { continue; } if (text3.Equals("allow:", StringComparison.OrdinalIgnoreCase)) { text2 = "allow"; continue; } if (text3.Equals("deny:", StringComparison.OrdinalIgnoreCase)) { text2 = "deny"; continue; } if (text3.StartsWith("- ")) { string item = text3.Substring(2).Trim().Trim(new char[1] { '"' }); if (text2 == "allow") { pieceRule.Allow.Add(item); } else if (text2 == "deny") { pieceRule.Deny.Add(item); } continue; } text2 = null; if (SplitKv(text3, out var key2, out var value2)) { if (key2.Equals("store", StringComparison.OrdinalIgnoreCase)) { pieceRule.Store = ParseBool(value2); } else if (key2.Equals("craft", StringComparison.OrdinalIgnoreCase)) { pieceRule.Craft = ParseBool(value2); } else if (key2.Equals("storeRange", StringComparison.OrdinalIgnoreCase)) { pieceRule.StoreRange = ParseFloat(value2); } else if (key2.Equals("craftRange", StringComparison.OrdinalIgnoreCase)) { pieceRule.CraftRange = ParseFloat(value2); } else if (key2.Equals("dumpRange", StringComparison.OrdinalIgnoreCase)) { pieceRule.DumpRange = ParseFloat(value2); } } } } } private static bool IsKeyValue(string line) { int num = line.IndexOf(':'); if (num > 0) { return num < line.Length - 1; } return false; } private static bool SplitKv(string line, out string key, out string value) { key = null; value = null; int num = line.IndexOf(':'); if (num <= 0) { return false; } key = line.Substring(0, num).Trim(); value = line.Substring(num + 1).Trim().Trim(new char[1] { '"' }); return key.Length > 0; } private static bool ParseBool(string value) { if (!value.Equals("true", StringComparison.OrdinalIgnoreCase) && !value.Equals("yes", StringComparison.OrdinalIgnoreCase)) { return value.Equals("on", StringComparison.OrdinalIgnoreCase); } return true; } private static float ParseFloat(string value) { if (float.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out var result)) { return result; } return 0f; } private static string DefaultText() { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("# StoreAndCraft rules"); stringBuilder.AppendLine("# File: BepInEx/config/StoreAndCraft.rules.yml"); stringBuilder.AppendLine("# Distances are in meters. Saving this file on the server reloads and syncs."); stringBuilder.AppendLine("#"); stringBuilder.AppendLine("# storeRange = how far a chest pulls items from the ground"); stringBuilder.AppendLine("# dumpRange = how far dump / middle-click can send items from the player to a chest"); stringBuilder.AppendLine("# craftRange = how far crafting and building can pull materials from a chest"); stringBuilder.AppendLine("# store/craft = true/false to allow storing or crafting from that piece"); stringBuilder.AppendLine("# allow = only these items (prefab name like Wood, or $item_wood). Empty = all items."); stringBuilder.AppendLine("# deny = never store/craft these items"); stringBuilder.AppendLine(); stringBuilder.AppendLine("defaults:"); stringBuilder.AppendLine(" storeRange: 10"); stringBuilder.AppendLine(" dumpRange: 12"); stringBuilder.AppendLine(" craftRange: 20"); stringBuilder.AppendLine(); stringBuilder.AppendLine("pieces:"); stringBuilder.AppendLine(" piece_chest:"); stringBuilder.AppendLine(" store: true"); stringBuilder.AppendLine(" craft: true"); stringBuilder.AppendLine(" piece_chest_wood:"); stringBuilder.AppendLine(" store: true"); stringBuilder.AppendLine(" craft: true"); stringBuilder.AppendLine(" # storeRange: 15"); stringBuilder.AppendLine(" # dumpRange: 15"); stringBuilder.AppendLine(" # craftRange: 25"); return stringBuilder.ToString(); } } internal static class RequirementBridge { public static int CountNearby(Player player, string sharedName) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)player == (Object)null || Plugin.Settings == null || string.IsNullOrEmpty(sharedName)) { return 0; } return NearbyIndex.CountItem(((Component)player).transform.position, 0f, sharedName, Plugin.Settings.LeaveOneItem.Value); } public static bool SenderInRange(long sender, Vector3 target, float range) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)ZNet.instance == (Object)null) { return true; } ZNetPeer peer = ZNet.instance.GetPeer(sender); if (peer == null) { return true; } float num = 6f; return Vector3.Distance(peer.m_refPos, target) <= range + num; } } internal static class StagingPull { public static bool PullingEnabled = true; private static float _retryCraftAt; private static bool _retryCraft; public static bool Active { get { if (Plugin.Settings != null && Plugin.Settings.ModEnabled.Value && Plugin.Settings.CraftEnabled.Value) { return PullingEnabled; } return false; } } public static void Tick() { if (_retryCraft && !(Time.time < _retryCraftAt)) { _retryCraft = false; InventoryGui instance = InventoryGui.instance; Player localPlayer = Player.m_localPlayer; if (!((Object)(object)instance == (Object)null) && !((Object)(object)localPlayer == (Object)null) && !((Object)(object)Refs.CraftRecipe(instance) == (Object)null)) { AccessToolsDoCraft(instance, localPlayer); } } } public static bool EnsureRecipe(Player player, Recipe recipe, int amount, out bool waiting) { waiting = false; if (!Active || (Object)(object)player == (Object)null || (Object)(object)recipe == (Object)null || recipe.m_resources == null) { return true; } return PullRequirements(player, recipe.m_resources, (!((Object)(object)recipe.m_item != (Object)null)) ? 1 : recipe.m_item.m_itemData.m_quality, -1, amount, out waiting); } public static bool EnsurePiece(Player player, Piece piece, out bool waiting) { waiting = false; if (!Active || (Object)(object)player == (Object)null || (Object)(object)piece == (Object)null || piece.m_resources == null) { return true; } return PullRequirements(player, piece.m_resources, 1, -1, 1, out waiting); } public static bool PullRequirements(Player player, Requirement[] requirements, int qualityLevel, int itemQuality, int multiplier, out bool waiting) { //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Unknown result type (might be due to invalid IL or missing references) waiting = false; if ((Object)(object)player == (Object)null || requirements == null) { return true; } Inventory inventory = ((Humanoid)player).GetInventory(); if (inventory == null) { return true; } NearbyIndex.Tick(); bool value = Plugin.Settings.LeaveOneItem.Value; float value2 = Plugin.Settings.CraftRange.Value; Vector3 position = ((Component)player).transform.position; bool result = true; foreach (Requirement val in requirements) { if (val == null || (Object)(object)val.m_resItem == (Object)null) { continue; } int num = val.GetAmount(qualityLevel) * Mathf.Max(1, multiplier); if (num <= 0) { continue; } string text = ((val.m_resItem.m_itemData != null) ? val.m_resItem.m_itemData.m_shared.m_name : null); if (string.IsNullOrEmpty(text)) { continue; } int num2 = inventory.CountItems(text, itemQuality, true); int num3 = num - num2; if (num3 <= 0) { continue; } foreach (Container item in NearbyIndex.Current) { if (num3 <= 0) { break; } if ((Object)(object)item == (Object)null) { continue; } string piecePrefab = ContainerFilter.PiecePrefab(item); if (!RulesFile.AllowsCraft(piecePrefab, text)) { continue; } float num4 = RulesFile.CraftRange(piecePrefab, value2); if (!(ContainerFilter.Distance(position, ((Component)item).transform.position) > num4)) { ZNetView val2 = Refs.View(item); if ((Object)(object)val2 == (Object)null || !val2.IsOwner()) { TransferService.Withdraw(item, text, num3, inventory, value); result = false; waiting = true; } else { int num5 = TransferService.Withdraw(item, text, num3, inventory, value); num3 -= num5; } } } } return result; } public static void ScheduleCraftRetry() { _retryCraft = true; _retryCraftAt = Time.time + 0.2f; } private static void AccessToolsDoCraft(InventoryGui gui, Player player) { MethodInfo methodInfo = AccessTools.Method(typeof(InventoryGui), "DoCrafting", (Type[])null, (Type[])null); if (methodInfo != null) { methodInfo.Invoke(gui, new object[1] { player }); } } } internal static class Hotkeys { public static void Tick() { //IL_004b: 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_0081: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) if (Plugin.Settings == null || !Plugin.Settings.ModEnabled.Value || Console.IsVisible() || ((Object)(object)Chat.instance != (Object)null && Chat.instance.HasFocus()) || TextInput.IsVisible()) { return; } if (KeyUtil.Down(Plugin.Settings.DumpKey.Value)) { InventoryDump.DumpNearby(); } if (KeyUtil.Down(Plugin.Settings.HoverStoreKey.Value)) { HoverStore.TryStoreHovered(); } if (KeyUtil.Down(Plugin.Settings.PauseKey.Value)) { AutoIntake.TogglePause(); } if (KeyUtil.Down(Plugin.Settings.RenameKey.Value)) { ChestRename.TryOpen(); } if (KeyUtil.Down(Plugin.Settings.PreventPullKey.Value)) { StagingPull.PullingEnabled = !StagingPull.PullingEnabled; Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer != (Object)null) { string text = (StagingPull.PullingEnabled ? Loc.T("on", "an") : Loc.T("off", "aus")); ((Character)localPlayer).Message((MessageType)2, Loc.T("Chest pulling " + text + ".", "Truhen-Ziehen " + text + "."), 0, (Sprite)null, false); } } } public static bool SearchHeld() { //IL_0011: Unknown result type (might be due to invalid IL or missing references) if (Plugin.Settings != null) { return KeyUtil.Held(Plugin.Settings.SearchKey.Value); } return false; } } internal static class HoverStore { public static ItemData GetHoveredPlayerItem() { InventoryGui instance = InventoryGui.instance; if ((Object)(object)instance == (Object)null || !InventoryGui.IsVisible() || (Object)(object)instance.m_playerGrid == (Object)null) { return null; } ItemData val = FromGrid(instance.m_playerGrid); if (val != null) { return val; } return FromGridByMouse(instance.m_playerGrid); } public static void TryStoreHovered() { if (Plugin.Settings == null || !Plugin.Settings.StoreEnabled.Value) { return; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return; } if (!InventoryGui.IsVisible()) { ((Character)localPlayer).Message((MessageType)2, Loc.T("Open your inventory and middle-click an item.", "Inventar öffnen und mit mittlerer Maustaste auf ein Item klicken."), 0, (Sprite)null, false); return; } ItemData hoveredPlayerItem = GetHoveredPlayerItem(); if (hoveredPlayerItem != null) { if (InventoryDump.StoreOne(hoveredPlayerItem)) { ((Character)localPlayer).Message((MessageType)1, Loc.T("Stored hovered item.", "Gehovertes Item eingelagert."), 0, (Sprite)null, false); } } else { InventoryDump.DumpNearby(); } } private static ItemData FromGrid(InventoryGrid grid) { //IL_0048: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)grid == (Object)null) { return null; } MethodInfo methodInfo = AccessTools.Method(typeof(InventoryGrid), "GetHoveredElement", (Type[])null, (Type[])null); if (methodInfo == null) { return null; } object? obj = methodInfo.Invoke(grid, null); InventoryElement val = (InventoryElement)((obj is InventoryElement) ? obj : null); if ((Object)(object)val == (Object)null) { return null; } return grid.GetItem(val.Position); } private static ItemData FromGridByMouse(InventoryGrid grid) { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0078: 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_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)grid == (Object)null) { return null; } FieldInfo fieldInfo = AccessTools.Field(typeof(InventoryGrid), "m_elements"); if (fieldInfo == null) { return null; } if (!(fieldInfo.GetValue(grid) is IList list)) { return null; } Vector3 mousePosition = Input.mousePosition; foreach (object item2 in list) { InventoryElement val = (InventoryElement)((item2 is InventoryElement) ? item2 : null); if ((Object)(object)val == (Object)null) { continue; } RectTransform elementRectTransform = val.GetElementRectTransform(); if ((Object)(object)elementRectTransform == (Object)null) { continue; } Vector2 val2 = Vector2.op_Implicit(((Transform)elementRectTransform).InverseTransformPoint(mousePosition)); Rect rect = elementRectTransform.rect; if (((Rect)(ref rect)).Contains(val2)) { ItemData item = grid.GetItem(val.Position); if (item != null) { return item; } } } return null; } } internal static class KeyUtil { public static bool Down(KeyboardShortcut shortcut) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) if ((int)((KeyboardShortcut)(ref shortcut)).MainKey == 0) { return false; } if (!MainDown(((KeyboardShortcut)(ref shortcut)).MainKey)) { return false; } foreach (KeyCode modifier in ((KeyboardShortcut)(ref shortcut)).Modifiers) { if (!Held(modifier)) { return false; } } return true; } public static bool Held(KeyboardShortcut shortcut) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) if ((int)((KeyboardShortcut)(ref shortcut)).MainKey == 0) { return false; } if (!MainHeld(((KeyboardShortcut)(ref shortcut)).MainKey)) { return false; } return ModifiersHeld(shortcut); } public static bool ModifiersHeld(KeyboardShortcut shortcut) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) bool result = false; foreach (KeyCode modifier in ((KeyboardShortcut)(ref shortcut)).Modifiers) { result = true; if (!Held(modifier)) { return false; } } return result; } public static string Format(KeyboardShortcut shortcut) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) if ((int)((KeyboardShortcut)(ref shortcut)).MainKey == 0) { return string.Empty; } List list = new List(); foreach (KeyCode modifier in ((KeyboardShortcut)(ref shortcut)).Modifiers) { list.Add(Nice(modifier)); } list.Add(Nice(((KeyboardShortcut)(ref shortcut)).MainKey)); return string.Join("+", list.ToArray()); } private unsafe static string Nice(KeyCode key) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Expected I4, but got Unknown switch (key - 303) { case 4: case 5: return "Alt"; case 0: case 1: return "Shift"; case 2: case 3: return "Ctrl"; default: return ((object)(*(KeyCode*)(&key))/*cast due to .constrained prefix*/).ToString(); } } private static bool MainDown(KeyCode key) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) int num = MouseIndex(key); if (num >= 0) { return Input.GetMouseButtonDown(num); } return Input.GetKeyDown(key); } private static bool MainHeld(KeyCode key) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) int num = MouseIndex(key); if (num >= 0) { return Input.GetMouseButton(num); } return Input.GetKey(key); } private static bool Held(KeyCode key) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) int num = MouseIndex(key); if (num >= 0) { return Input.GetMouseButton(num); } return Input.GetKey(key); } private static int MouseIndex(KeyCode key) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Expected I4, but got Unknown return (key - 323) switch { 0 => 0, 1 => 1, 2 => 2, 3 => 3, 4 => 4, 5 => 5, 6 => 6, _ => -1, }; } } internal static class Loc { public static string T(string en, string de) { return en; } } internal static class AdminUtil { public static bool IsServer() { if ((Object)(object)ZNet.instance != (Object)null) { return ZNet.instance.IsServer(); } return false; } public static bool CanEditSettings() { ZNet instance = ZNet.instance; if ((Object)(object)instance == (Object)null) { return true; } if (instance.IsDedicated()) { return false; } if (instance.IsServer()) { return true; } if (ConfigSync.ServerGrantedEdit) { return true; } return instance.LocalPlayerIsAdminOrHost(); } } internal static class ConfigSync { public const string RpcSyncName = "KAC_SyncConfig"; public const string RpcRequestName = "KAC_RequestConfig"; public const string HandshakeName = "KAC_Hello"; public static bool IsApplyingRemoteConfig { get; private set; } public static bool Registered { get; private set; } public static bool HasReceivedConfig { get; private set; } public static bool ServerGrantedEdit { get; private set; } public static void Register() { if (ZRoutedRpc.instance != null) { if (!Registered) { ZRoutedRpc.instance.Register("KAC_SyncConfig", (Action)RPC_ReceiveConfig); ZRoutedRpc.instance.Register("KAC_RequestConfig", (Action)RPC_RequestConfig); ZRoutedRpc.instance.Register("KAC_Hello", (Action)RPC_Hello); Registered = true; Plugin.Log.LogInfo((object)"StoreAndCraft RPCs registered."); } if (AdminUtil.IsServer()) { HasReceivedConfig = true; ServerGrantedEdit = true; BroadcastConfig(); } else if (!HasReceivedConfig) { RequestConfigFromServer(); } } } public static void BroadcastConfig() { if (!AdminUtil.IsServer() || (Object)(object)ZNet.instance == (Object)null || Plugin.Settings == null) { return; } foreach (ZNetPeer peer in ZNet.instance.GetPeers()) { if (peer != null && peer.IsReady()) { SendToPeer(peer.m_uid); } } } public static void SendToPeer(long peerId) { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Expected O, but got Unknown if (AdminUtil.IsServer() && ZRoutedRpc.instance != null && Plugin.Settings != null) { bool flag = PeerIsAdmin(((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetPeer(peerId) : null); ZPackage val = new ZPackage(); val.Write(ModConfigProtocol()); val.Write(flag); Plugin.Settings.WriteToPackage(val); ZRoutedRpc.instance.InvokeRoutedRPC(peerId, "KAC_SyncConfig", new object[1] { val }); } } public static void RequestConfigFromServer() { if (!AdminUtil.IsServer() && ZRoutedRpc.instance != null) { ZRoutedRpc.instance.InvokeRoutedRPC(0L, "KAC_RequestConfig", Array.Empty()); } } private static int ModConfigProtocol() { return 1; } public static bool PeerIsAdmin(ZNetPeer peer) { if (peer?.m_rpc == null || (Object)(object)ZNet.instance == (Object)null) { return false; } try { ISocket socket = peer.m_rpc.GetSocket(); if (socket == null) { return false; } string hostName = socket.GetHostName(); return !string.IsNullOrEmpty(hostName) && ZNet.instance.IsAdmin(hostName); } catch { return false; } } private static void RPC_ReceiveConfig(long sender, ZPackage pkg) { if (AdminUtil.IsServer() || pkg == null || Plugin.Settings == null) { return; } int num = pkg.ReadInt(); if (num != 1) { Plugin.Log.LogWarning((object)("StoreAndCraft config protocol mismatch: " + num)); return; } ServerGrantedEdit = pkg.ReadBool(); IsApplyingRemoteConfig = true; try { Plugin.Settings.ReadFromPackage(pkg); HasReceivedConfig = true; } finally { IsApplyingRemoteConfig = false; } } private static void RPC_RequestConfig(long sender) { if (AdminUtil.IsServer()) { SendToPeer(sender); } } private static void RPC_Hello(long sender, int protocol, int major) { if (AdminUtil.IsServer()) { VersionGate.Accept(sender, protocol, major); SendToPeer(sender); } } } internal class ConfigSyncRetry : MonoBehaviour { private float _nextRequest; private int _attempts; private void Update() { if (AdminUtil.IsServer() || ConfigSync.HasReceivedConfig) { ((Behaviour)this).enabled = false; } else if (ConfigSync.Registered && ZRoutedRpc.instance != null && !((Object)(object)ZNet.instance == (Object)null) && !(Time.time < _nextRequest)) { _attempts++; _nextRequest = Time.time + 2f; ConfigSync.RequestConfigFromServer(); VersionGate.SendHello(); if (_attempts == 1 || _attempts % 5 == 0) { Plugin.Log.LogInfo((object)("StoreAndCraft: waiting for server config (attempt " + _attempts + ")...")); } } } } internal static class ConfigWatch { private static FileSystemWatcher _watcher; private static float _reloadAt; private static bool _pending; public static void Start() { if (_watcher != null) { return; } try { _watcher = new FileSystemWatcher(Paths.ConfigPath); _watcher.Filter = "StoreAndCraft.*"; _watcher.NotifyFilter = NotifyFilters.FileName | NotifyFilters.Size | NotifyFilters.LastWrite; _watcher.Changed += OnChanged; _watcher.Created += OnChanged; _watcher.EnableRaisingEvents = true; Plugin.Log.LogInfo((object)("StoreAndCraft config watcher on " + Paths.ConfigPath)); } catch (Exception ex) { Plugin.Log.LogWarning((object)("StoreAndCraft config watcher failed: " + ex.Message)); } } public static void Tick() { if (_pending && !(Time.unscaledTime < _reloadAt)) { _pending = false; Reload(); } } private static void OnChanged(object sender, FileSystemEventArgs e) { _pending = true; _reloadAt = Time.unscaledTime + 0.4f; } private static void Reload() { try { if ((Object)(object)Plugin.Instance != (Object)null) { ((BaseUnityPlugin)Plugin.Instance).Config.Reload(); } RulesFile.LoadOrCreate(); if (AdminUtil.IsServer()) { ConfigSync.BroadcastConfig(); } Plugin.Log.LogInfo((object)"StoreAndCraft config/rules reloaded from disk."); } catch (Exception ex) { Plugin.Log.LogWarning((object)("StoreAndCraft reload failed: " + ex.Message)); } } } internal static class TransferService { private struct PendingMove { public Container Chest; public ItemDrop Drop; public ItemData Item; public Inventory From; public int Amount; public float Deadline; public bool Withdraw; public string SharedName; public bool LeaveOne; } public const string RpcRemove = "KAC_Remove"; public const string RpcDeposit = "KAC_Deposit"; public const string RpcGrant = "KAC_Grant"; public const string RpcStoreDrop = "KAC_StoreDrop"; private static readonly Queue Queue = new Queue(); private static readonly Dictionary ClaimThrottle = new Dictionary(); private static bool _grantRegistered; public static void RegisterGrant() { if (!_grantRegistered && ZRoutedRpc.instance != null) { ZRoutedRpc.instance.Register("KAC_Grant", (Action)RPC_Grant); _grantRegistered = true; } } public static void Tick() { int num = ((Plugin.Settings != null) ? Plugin.Settings.MaxTransfersPerTick.Value : 8); int num2 = 0; int count = Queue.Count; while (Queue.Count > 0 && num2 < num && count-- > 0) { PendingMove pendingMove = Queue.Dequeue(); if (!(Time.time > pendingMove.Deadline) && !((Object)(object)pendingMove.Chest == (Object)null) && ContainerFilter.IsUsable(pendingMove.Chest)) { if (!TryOwner(pendingMove.Chest, claim: true)) { Queue.Enqueue(pendingMove); break; } Execute(pendingMove); num2++; } } } public static bool StoreItem(Container chest, Inventory from, ItemData item, int amount) { if ((Object)(object)chest == (Object)null || from == null || item == null || amount <= 0) { return false; } if (TryOwner(chest, claim: true)) { return DepositLocal(chest, from, item, amount); } InvokeDeposit(chest, item, amount); Enqueue(new PendingMove { Chest = chest, From = from, Item = item, Amount = amount, Deadline = Time.time + 2f }); return true; } public static bool StoreDrop(Container chest, ItemDrop drop) { //IL_0099: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)chest == (Object)null || (Object)(object)drop == (Object)null || drop.m_itemData == null) { return false; } ZNetView val = Refs.View(drop); if (TryOwner(chest, claim: true) && (Object)(object)val != (Object)null && val.IsOwner()) { return StoreDropLocal(chest, drop); } if ((Object)(object)val != (Object)null && val.IsValid()) { drop.RequestOwn(); } ZNetView val2 = Refs.View(chest); if ((Object)(object)val2 != (Object)null && val2.IsValid() && (Object)(object)val != (Object)null && val.GetZDO() != null) { val2.InvokeRPC("KAC_StoreDrop", new object[1] { val.GetZDO().m_uid }); } Enqueue(new PendingMove { Chest = chest, Drop = drop, Amount = drop.m_itemData.m_stack, Deadline = Time.time + 2.5f }); return true; } public static int Withdraw(Container chest, string sharedName, int amount, Inventory playerInv, bool leaveOne) { if ((Object)(object)chest == (Object)null || playerInv == null || amount <= 0 || string.IsNullOrEmpty(sharedName)) { return 0; } if (TryOwner(chest, claim: true)) { return WithdrawLocal(chest, sharedName, amount, playerInv, leaveOne); } ZNetView val = Refs.View(chest); if ((Object)(object)val != (Object)null && val.IsValid()) { val.InvokeRPC("KAC_Remove", new object[3] { sharedName, amount, leaveOne ? 1 : 0 }); } Enqueue(new PendingMove { Chest = chest, From = playerInv, SharedName = sharedName, Amount = amount, LeaveOne = leaveOne, Withdraw = true, Deadline = Time.time + 2f }); return 0; } public static void RegisterOn(Container container) { ZNetView nv = Refs.View(container); if ((Object)(object)nv == (Object)null || !nv.IsValid()) { return; } TryRegister(nv, "KAC_Remove", delegate { nv.Register("KAC_Remove", (Action)delegate(long sender, string name, int amount, int leaveOne) { OnRemove(container, sender, name, amount, leaveOne != 0); }); }); TryRegister(nv, "KAC_Deposit", delegate { nv.Register("KAC_Deposit", (Action)delegate(long sender, ZPackage pkg) { OnDeposit(container, sender, pkg); }); }); TryRegister(nv, "KAC_StoreDrop", delegate { nv.Register("KAC_StoreDrop", (Action)delegate(long sender, ZDOID dropId) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) OnStoreDrop(container, sender, dropId); }); }); } private static void TryRegister(ZNetView nv, string name, Action register) { try { register(); } catch (Exception ex) { Plugin.Log.LogDebug((object)("RPC register " + name + ": " + ex.Message)); } } internal static void OnRemove(Container container, long sender, string sharedName, int amount, bool leaveOne) { //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Expected O, but got Unknown ZNetView val = Refs.View(container); if ((Object)(object)container == (Object)null || (Object)(object)val == (Object)null || !val.IsOwner() || amount <= 0 || !ValidateRpc(container, sender, (Plugin.Settings != null) ? Plugin.Settings.CraftRange.Value : 20f) || !RulesFile.AllowsCraft(ContainerFilter.PiecePrefab(container), sharedName)) { return; } Inventory inventory = container.GetInventory(); if (inventory != null) { int num = inventory.CountItems(sharedName, -1, true); if (leaveOne && num > 0) { num--; } int num2 = Mathf.Min(amount, num); if (num2 > 0) { inventory.RemoveItem(sharedName, num2, -1, true); ZPackage val2 = new ZPackage(); val2.Write(sharedName); val2.Write(num2); ZRoutedRpc.instance.InvokeRoutedRPC(sender, "KAC_Grant", new object[1] { val2 }); } } } internal static void OnDeposit(Container container, long sender, ZPackage pkg) { ZNetView val = Refs.View(container); if ((Object)(object)container == (Object)null || (Object)(object)val == (Object)null || !val.IsOwner() || pkg == null || !ValidateRpc(container, sender, MaxStoreRange())) { return; } string text = pkg.ReadString(); int num = pkg.ReadInt(); int num2 = pkg.ReadInt(); int num3 = pkg.ReadInt(); long num4 = pkg.ReadLong(); string text2 = pkg.ReadString(); if (num <= 0) { return; } Inventory inventory = container.GetInventory(); if (inventory == null) { return; } ItemData val2 = inventory.AddItem(text, num, num2, num3, num4, text2, false, false); if (val2 != null) { if (!RulesFile.AllowsStore(ContainerFilter.PiecePrefab(container), val2)) { inventory.RemoveItem(val2, val2.m_stack); } else { Highlight(container); } } } internal static void OnStoreDrop(Container container, long sender, ZDOID dropId) { //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) ZNetView val = Refs.View(container); if ((Object)(object)container == (Object)null || (Object)(object)val == (Object)null || !val.IsOwner() || (Object)(object)ZNetScene.instance == (Object)null || !ValidateRpc(container, sender, MaxStoreRange())) { return; } GameObject val2 = ZNetScene.instance.FindInstance(dropId); if ((Object)(object)val2 == (Object)null) { return; } ItemDrop component = val2.GetComponent(); if (!((Object)(object)component == (Object)null) && component.m_itemData != null && RulesFile.AllowsStore(ContainerFilter.PiecePrefab(container), component.m_itemData) && !(Vector3.Distance(((Component)component).transform.position, ((Component)container).transform.position) > MaxStoreRange() + 6f)) { ZNetView val3 = Refs.View(component); if ((Object)(object)val3 != (Object)null && !val3.IsOwner()) { component.RequestOwn(); } else { StoreDropLocal(container, component); } } } private static void RPC_Grant(long sender, ZPackage pkg) { Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null) && pkg != null) { string text = pkg.ReadString(); int num = pkg.ReadInt(); GameObject val = ItemIds.PrefabFromToken(text); if ((Object)(object)val == (Object)null) { val = (((Object)(object)ObjectDB.instance != (Object)null) ? ObjectDB.instance.GetItemPrefab(text) : null); } if (!((Object)(object)val == (Object)null)) { ((Humanoid)localPlayer).GetInventory().AddItem(val, num); } } } private static bool Execute(PendingMove op) { if ((Object)(object)op.Drop != (Object)null) { ZNetView val = Refs.View(op.Drop); if ((Object)(object)val != (Object)null && !val.IsOwner()) { op.Drop.RequestOwn(); Queue.Enqueue(op); return false; } return StoreDropLocal(op.Chest, op.Drop); } if (op.Withdraw) { return WithdrawLocal(op.Chest, op.SharedName, op.Amount, op.From, op.LeaveOne) > 0; } return DepositLocal(op.Chest, op.From, op.Item, op.Amount); } private static bool DepositLocal(Container chest, Inventory from, ItemData item, int amount) { Inventory inventory = chest.GetInventory(); if (inventory == null || item == null) { return false; } int num = Mathf.Min(amount, item.m_stack); if (num <= 0 || !inventory.CanAddItem(item, num)) { return false; } ItemData val = item.Clone(); val.m_stack = num; if (!inventory.AddItem(val)) { return false; } from.RemoveItem(item, num); Highlight(chest); return true; } private static bool StoreDropLocal(Container chest, ItemDrop drop) { if ((Object)(object)drop == (Object)null || drop.m_itemData == null) { return false; } Inventory inventory = chest.GetInventory(); if (inventory == null || !inventory.CanAddItem(drop.m_itemData, drop.m_itemData.m_stack)) { return false; } ItemData val = drop.m_itemData.Clone(); if (!inventory.AddItem(val)) { return false; } ZNetView val2 = Refs.View(drop); if ((Object)(object)val2 != (Object)null && val2.IsValid() && (Object)(object)ZNetScene.instance != (Object)null) { ZNetScene.instance.Destroy(((Component)drop).gameObject); } else { Object.Destroy((Object)(object)((Component)drop).gameObject); } Highlight(chest); return true; } private static int WithdrawLocal(Container chest, string sharedName, int amount, Inventory playerInv, bool leaveOne) { Inventory inventory = chest.GetInventory(); if (inventory == null || playerInv == null) { return 0; } int num = inventory.CountItems(sharedName, -1, true); if (leaveOne && num > 0) { num--; } int num2 = Mathf.Min(amount, num); if (num2 <= 0) { return 0; } GameObject val = ItemIds.PrefabFromToken(sharedName); if ((Object)(object)val == (Object)null && (Object)(object)ObjectDB.instance != (Object)null) { val = ObjectDB.instance.GetItemPrefab(sharedName); } if ((Object)(object)val == (Object)null) { return 0; } if (!playerInv.CanAddItem(val, num2)) { while (num2 > 0 && !playerInv.CanAddItem(val, num2)) { num2--; } if (num2 <= 0) { return 0; } } if (!playerInv.AddItem(val, num2)) { return 0; } inventory.RemoveItem(sharedName, num2, -1, true); return num2; } private static float MaxStoreRange() { if (Plugin.Settings == null) { return 12f; } return RulesFile.MaxScanRange(Plugin.Settings.StoreRange.Value, Plugin.Settings.CraftRange.Value, Plugin.Settings.PlayerDumpRange.Value); } private static bool ValidateRpc(Container container, long sender, float range) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) if (!ContainerFilter.IsUsable(container)) { return false; } if (!PrivateArea.CheckAccess(((Component)container).transform.position, 0f, false, true)) { return false; } if (!RequirementBridge.SenderInRange(sender, ((Component)container).transform.position, range)) { return false; } return true; } private static bool TryOwner(Container chest, bool claim) { ZNetView val = Refs.View(chest); if ((Object)(object)val == (Object)null || !val.IsValid()) { return false; } if (val.IsOwner()) { return true; } if (!claim) { return false; } int instanceID = ((Object)chest).GetInstanceID(); if (ClaimThrottle.TryGetValue(instanceID, out var value) && Time.time < value) { return false; } val.ClaimOwnership(); ClaimThrottle[instanceID] = Time.time + 0.35f; return val.IsOwner(); } private static void InvokeDeposit(Container chest, ItemData item, int amount) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected O, but got Unknown ZNetView val = Refs.View(chest); if (!((Object)(object)val == (Object)null) && val.IsValid() && item != null) { ZPackage val2 = new ZPackage(); val2.Write(ItemIds.PrefabName(item) ?? ItemIds.SharedName(item) ?? ""); val2.Write(amount); val2.Write(item.m_quality); val2.Write(item.m_variant); val2.Write(item.m_crafterID); val2.Write(item.m_crafterName ?? ""); val.InvokeRPC("KAC_Deposit", new object[1] { val2 }); } } private static void Enqueue(PendingMove op) { if (Queue.Count <= 80) { Queue.Enqueue(op); } } public static void Highlight(Container chest) { //IL_0061: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)chest == (Object)null || Plugin.Settings == null) { return; } if (Plugin.Settings.HighlightOnStore.Value) { WearNTear component = ((Component)chest).GetComponent(); if ((Object)(object)component != (Object)null) { component.Highlight(); } } if (Plugin.Settings.PingOnStore.Value && (Object)(object)Chat.instance != (Object)null) { Chat.instance.SendPing(((Component)chest).transform.position); } } } internal class VersionGate : MonoBehaviour { public const int Major = 1; public const float GraceSeconds = 12f; private static readonly Dictionary Deadline = new Dictionary(); private static readonly HashSet Verified = new HashSet(); public static void OnPeerReady(long peerId) { if (AdminUtil.IsServer() && peerId != 0L && !Verified.Contains(peerId) && !Deadline.ContainsKey(peerId)) { Deadline[peerId] = Time.time + 12f; } } public static void Accept(long peerId, int protocol, int major) { if (AdminUtil.IsServer()) { if (protocol != 1 || major != 1) { Plugin.Log.LogWarning((object)("StoreAndCraft: rejecting peer " + peerId + " (protocol " + protocol + "/" + 1 + ", major " + major + "/" + 1 + ").")); Kick(peerId); } else { Verified.Add(peerId); Deadline.Remove(peerId); } } } public static void SendHello() { if (!AdminUtil.IsServer() && ZRoutedRpc.instance != null) { ZRoutedRpc.instance.InvokeRoutedRPC(0L, "KAC_Hello", new object[2] { 1, 1 }); } } private void Update() { if (!AdminUtil.IsServer() || (Object)(object)ZNet.instance == (Object)null || Deadline.Count == 0) { return; } List list = new List(); foreach (KeyValuePair item in Deadline) { if (!Verified.Contains(item.Key) && Time.time >= item.Value) { list.Add(item.Key); } } foreach (long item2 in list) { Deadline.Remove(item2); Plugin.Log.LogWarning((object)("StoreAndCraft: kicking peer " + item2 + " (missing StoreAndCraft or handshake timeout).")); Kick(item2); } } private static void Kick(long peerId) { if (!((Object)(object)ZNet.instance == (Object)null)) { ZNetPeer peer = ZNet.instance.GetPeer(peerId); if (peer != null) { ZNet.instance.Disconnect(peer); } } } } [HarmonyPatch(typeof(Container), "Interact")] internal static class ContainerInteractRenamePatch { private static bool Prefix(Container __instance, Humanoid character, bool hold, bool alt, ref bool __result) { if (hold || (Object)(object)character != (Object)(object)Player.m_localPlayer) { return true; } if (!ChestRename.WantsRename(alt)) { return true; } if (!ChestRename.TryOpen(__instance, warnIfMissing: false)) { return true; } __result = true; return false; } } [HarmonyPatch(typeof(Container), "GetHoverName")] internal static class ContainerHoverNamePatch { private static void Postfix(Container __instance, ref string __result) { string text = ChestNames.Get(__instance); if (!string.IsNullOrEmpty(text)) { __result = text; } } } [HarmonyPatch(typeof(Container), "GetHoverText")] internal static class ContainerHoverTextPatch { private static void Postfix(Container __instance, ref string __result) { if (string.IsNullOrEmpty(__result)) { return; } string text = ChestNames.Get(__instance); if (!string.IsNullOrEmpty(text)) { string text2 = Refs.VanillaHoverName(__instance); if (!string.IsNullOrEmpty(text2) && Localization.instance != null) { text2 = Localization.instance.Localize(text2); } if (!string.IsNullOrEmpty(text2) && __result.StartsWith(text2)) { __result = text + __result.Substring(text2.Length); } else if (__result.IndexOf(text, StringComparison.Ordinal) < 0) { __result = text + "\n" + __result; } } __result = __result + "\n[" + ChestRename.PromptLabel() + "] Rename"; } } [HarmonyPatch(typeof(Inventory))] internal static class InventoryCountPatches { internal static int Skip; [HarmonyPostfix] [HarmonyPatch("CountItems")] private static void CountItemsPostfix(Inventory __instance, string name, int quality, bool matchWorldLevel, ref int __result) { if (Skip > 0 || !StagingPull.Active) { return; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || ((Humanoid)localPlayer).GetInventory() != __instance || string.IsNullOrEmpty(name)) { return; } Skip++; try { __result += RequirementBridge.CountNearby(localPlayer, name); } finally { Skip--; } } [HarmonyPostfix] [HarmonyPatch("HaveItem", new Type[] { typeof(string), typeof(bool) })] private static void HaveItemPostfix(Inventory __instance, string name, bool matchWorldLevel, ref bool __result) { if (__result || Skip > 0 || !StagingPull.Active) { return; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || ((Humanoid)localPlayer).GetInventory() != __instance) { return; } Skip++; try { __result = RequirementBridge.CountNearby(localPlayer, name) > 0; } finally { Skip--; } } } [HarmonyPatch(typeof(Container), "Awake")] internal static class ContainerAwakePatch { private static void Postfix(Container __instance) { TransferService.RegisterOn(__instance); if ((Object)(object)((Component)__instance).GetComponent() == (Object)null) { ((Component)__instance).gameObject.AddComponent(); } } } [HarmonyPatch(typeof(Game), "Start")] internal static class GameStartPatch { private static void Postfix(Game __instance) { ConfigSync.Register(); TransferService.RegisterGrant(); VersionGate.SendHello(); if ((Object)(object)__instance != (Object)null && (Object)(object)((Component)__instance).GetComponent() == (Object)null) { ((Component)__instance).gameObject.AddComponent(); } if ((Object)(object)__instance != (Object)null && (Object)(object)((Component)__instance).GetComponent() == (Object)null) { ((Component)__instance).gameObject.AddComponent(); } } } [HarmonyPatch(typeof(ZNet), "RPC_PeerInfo")] internal static class PeerInfoPatch { private static void Postfix(ZRpc rpc) { if (!AdminUtil.IsServer() || rpc == null || (Object)(object)ZNet.instance == (Object)null) { return; } foreach (ZNetPeer peer in ZNet.instance.GetPeers()) { if (peer != null && peer.m_rpc == rpc) { VersionGate.OnPeerReady(peer.m_uid); ConfigSync.SendToPeer(peer.m_uid); break; } } } } [HarmonyPatch(typeof(Player), "OnSpawned")] internal static class PlayerSpawnedPatch { private static void Postfix(Player __instance) { if (!((Object)(object)__instance == (Object)null) && ((Character)__instance).IsOwner() && !AdminUtil.IsServer()) { VersionGate.SendHello(); if (!ConfigSync.HasReceivedConfig) { ConfigSync.RequestConfigFromServer(); } } } } [HarmonyPatch(typeof(Terminal), "InitTerminal")] internal static class TerminalInitPatch { private static bool _added; private static void Postfix() { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Expected O, but got Unknown //IL_002e: Unknown result type (might be due to invalid IL or missing references) if (!_added) { _added = true; new ConsoleCommand("storesearch", "Find an item in nearby containers", new ConsoleEvent(SearchPing.OnCommand), false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); } } } [HarmonyPatch] internal static class PlayerCraftPatches { [HarmonyPrefix] [HarmonyPatch(typeof(Player), "ConsumeResources")] private static void ConsumeResourcesPrefix(Player __instance, Requirement[] requirements, int qualityLevel, int itemQuality, int multiplier) { if (!((Object)(object)__instance == (Object)null) && ((Character)__instance).IsOwner() && StagingPull.Active) { StagingPull.PullRequirements(__instance, requirements, qualityLevel, itemQuality, multiplier, out var _); } } [HarmonyPrefix] [HarmonyPatch(typeof(InventoryGui), "DoCrafting")] private static bool DoCraftingPrefix(InventoryGui __instance, Player player) { Recipe val = Refs.CraftRecipe(__instance); if (!StagingPull.Active || (Object)(object)player == (Object)null || (Object)(object)__instance == (Object)null || (Object)(object)val == (Object)null) { return true; } int amount = ((!Refs.MultiCrafting(__instance)) ? 1 : Mathf.Max(1, __instance.m_multiCraftAmount)); StagingPull.EnsureRecipe(player, val, amount, out var waiting); if (waiting) { StagingPull.ScheduleCraftRetry(); return false; } return true; } [HarmonyPrefix] [HarmonyPatch(typeof(Player), "TryPlacePiece")] private static bool TryPlacePiecePrefix(Player __instance, Piece piece, ref bool __result) { if (!StagingPull.Active || (Object)(object)__instance == (Object)null || (Object)(object)piece == (Object)null) { return true; } StagingPull.EnsurePiece(__instance, piece, out var waiting); if (waiting) { __result = false; return false; } return true; } } [HarmonyPatch(typeof(InventoryGui), "SetupRequirement")] internal static class CraftUiHintPatch { private static readonly Color Flash = new Color(1f, 0.92f, 0.2f, 1f); private static void Postfix(Transform elementRoot, Requirement req, Player player, bool craft, int quality, int craftMultiplier, bool __result) { //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) if (!__result || !StagingPull.Active || (Object)(object)player == (Object)null || req == null || (Object)(object)req.m_resItem == (Object)null || (Object)(object)elementRoot == (Object)null) { return; } string text = ((req.m_resItem.m_itemData != null) ? req.m_resItem.m_itemData.m_shared.m_name : null); if (string.IsNullOrEmpty(text)) { return; } InventoryCountPatches.Skip++; try { ((Humanoid)player).GetInventory().CountItems(text, -1, true); } finally { InventoryCountPatches.Skip--; } if (RequirementBridge.CountNearby(player, text) <= 0) { return; } TMP_Text[] componentsInChildren = ((Component)elementRoot).GetComponentsInChildren(true); foreach (TMP_Text val in componentsInChildren) { if (!((Object)(object)val == (Object)null)) { ((Graphic)val).color = Color.Lerp(((Graphic)val).color, Flash, 0.65f); } } } } [HarmonyPatch(typeof(InventoryGui), "OnSelectedItem")] internal static class SearchClickPatch { private static bool Prefix(ItemData item) { if (item == null || !Hotkeys.SearchHeld()) { return true; } SearchPing.PingItem(item); return false; } } [BepInPlugin("com.morda.storeandcraft", "StoreAndCraft", "1.0.0")] public class Plugin : BaseUnityPlugin { public const string ModGuid = "com.morda.storeandcraft"; public const string ModName = "StoreAndCraft"; public const string ModVersion = "1.0.0"; public const string ModAuthor = "Morda"; private Harmony _harmony; internal static Plugin Instance { get; private set; } internal static ManualLogSource Log { get; private set; } internal static ModConfig Settings { get; private set; } private void Awake() { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Expected O, but got Unknown Instance = this; Log = ((BaseUnityPlugin)this).Logger; Settings = new ModConfig(((BaseUnityPlugin)this).Config); RulesFile.LoadOrCreate(); ConfigWatch.Start(); _harmony = new Harmony("com.morda.storeandcraft"); _harmony.PatchAll(Assembly.GetExecutingAssembly()); ((BaseUnityPlugin)this).Logger.LogInfo((object)"StoreAndCraft v1.0.0 by Morda loaded."); } private void Update() { ConfigWatch.Tick(); TransferService.Tick(); if (!((Object)(object)Player.m_localPlayer == (Object)null)) { NearbyIndex.Tick(); AutoIntake.Tick(); StagingPull.Tick(); } } private void LateUpdate() { if (!((Object)(object)Player.m_localPlayer == (Object)null)) { Hotkeys.Tick(); } } private void OnDestroy() { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } if ((Object)(object)Instance == (Object)(object)this) { Instance = null; } } } internal static class Refs { private static readonly FieldInfo ItemDropNview = AccessTools.Field(typeof(ItemDrop), "m_nview"); private static readonly FieldInfo ItemDropInstances = AccessTools.Field(typeof(ItemDrop), "s_instances"); private static readonly FieldInfo ContainerNview = AccessTools.Field(typeof(Container), "m_nview"); private static readonly FieldInfo ContainerName = AccessTools.Field(typeof(Container), "m_name"); private static readonly FieldInfo GuiRecipe = AccessTools.Field(typeof(InventoryGui), "m_craftRecipe"); private static readonly FieldInfo GuiMulti = AccessTools.Field(typeof(InventoryGui), "m_multiCrafting"); public static ZNetView View(Container container) { if ((Object)(object)container == (Object)null) { return null; } if (ContainerNview != null) { object? value = ContainerNview.GetValue(container); ZNetView val = (ZNetView)((value is ZNetView) ? value : null); if ((Object)(object)val != (Object)null) { return val; } } return ((Component)container).GetComponent(); } public static string VanillaHoverName(Container container) { if ((Object)(object)container == (Object)null || ContainerName == null) { return null; } return ContainerName.GetValue(container) as string; } public static ZNetView View(ItemDrop drop) { if ((Object)(object)drop == (Object)null) { return null; } if (ItemDropNview != null) { object? value = ItemDropNview.GetValue(drop); ZNetView val = (ZNetView)((value is ZNetView) ? value : null); if ((Object)(object)val != (Object)null) { return val; } } return ((Component)drop).GetComponent(); } public static List Drops() { if (ItemDropInstances == null) { return null; } return ItemDropInstances.GetValue(null) as List; } public static Recipe CraftRecipe(InventoryGui gui) { if (!((Object)(object)gui != (Object)null) || !(GuiRecipe != null)) { return null; } object? value = GuiRecipe.GetValue(gui); return (Recipe)((value is Recipe) ? value : null); } public static bool MultiCrafting(InventoryGui gui) { if ((Object)(object)gui == (Object)null || GuiMulti == null) { return false; } object value = GuiMulti.GetValue(gui); if (value is bool) { return (bool)value; } return false; } } internal static class AutoIntake { private static float _next; public static float PauseUntil { get; set; } public static bool Paused => Time.time < PauseUntil; public static void TogglePause() { if (Plugin.Settings != null) { if (Paused) { PauseUntil = 0f; Tell(Loc.T("Auto-store resumed.", "Auto-Einlagern wieder an.")); } else { PauseUntil = Time.time + Plugin.Settings.PauseSeconds.Value; Tell(Loc.T("Auto-store paused for " + Plugin.Settings.PauseSeconds.Value + "s.", "Auto-Einlagern pausiert für " + Plugin.Settings.PauseSeconds.Value + "s.")); } } } public static void Tick() { //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Unknown result type (might be due to invalid IL or missing references) //IL_0196: Unknown result type (might be due to invalid IL or missing references) //IL_019f: Unknown result type (might be due to invalid IL or missing references) //IL_01c0: Unknown result type (might be due to invalid IL or missing references) if (Plugin.Settings == null || !Plugin.Settings.ModEnabled.Value || !Plugin.Settings.StoreEnabled.Value || Paused) { return; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || ((Character)localPlayer).IsDead() || ((Character)localPlayer).IsTeleporting() || Time.time < _next) { return; } _next = Time.time + Mathf.Max(1f, Plugin.Settings.IntakeInterval.Value); List list = Refs.Drops(); if (list == null) { return; } int num = 0; int value = Plugin.Settings.MaxTransfersPerTick.Value; Vector3 position = ((Component)localPlayer).transform.position; foreach (ItemDrop item in list) { if (num >= value) { break; } if ((Object)(object)item == (Object)null || item.m_itemData == null) { continue; } ZNetView val = Refs.View(item); if ((Object)(object)val == (Object)null || !val.IsValid() || item.IsPiece() || !item.CanPickup(true)) { continue; } float value2 = Plugin.Settings.StoreRange.Value; Container val2 = null; float num2 = float.MaxValue; foreach (Container item2 in NearbyIndex.Current) { if (!((Object)(object)item2 == (Object)null)) { float num3 = RulesFile.StoreRange(ContainerFilter.PiecePrefab(item2), value2); float num4 = ContainerFilter.Distance(((Component)item).transform.position, ((Component)item2).transform.position); if (!(num4 > num3) && !(ContainerFilter.Distance(position, ((Component)item2).transform.position) > NearbyIndex.ScanRange()) && ChestPicker.CanAccept(item2, item.m_itemData, ((Component)item).transform.position, Plugin.Settings.MustHaveExisting.Value) && num4 < num2) { num2 = num4; val2 = item2; } } } if (!((Object)(object)val2 == (Object)null) && TransferService.StoreDrop(val2, item)) { num++; } } } private static void Tell(string msg) { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer != (Object)null) { ((Character)localPlayer).Message((MessageType)2, msg, 0, (Sprite)null, false); } } } internal static class ChestNames { public const string ZdoKey = "kac_label"; public const int MaxLength = 32; public static bool CanRename(Container container) { ZNetView val = Refs.View(container); if ((Object)(object)val != (Object)null && val.IsValid()) { return val.GetZDO() != null; } return false; } public static string Get(Container container) { ZNetView val = Refs.View(container); if ((Object)(object)val == (Object)null || !val.IsValid() || val.GetZDO() == null) { return null; } string text = val.GetZDO().GetString("kac_label", string.Empty); if (!string.IsNullOrEmpty(text)) { return text; } return null; } public static bool Set(Container container, string name) { ZNetView val = Refs.View(container); if ((Object)(object)val == (Object)null || !val.IsValid() || val.GetZDO() == null) { return false; } if (!val.IsOwner()) { val.ClaimOwnership(); } val.GetZDO().Set("kac_label", Sanitize(name)); return true; } public static string Sanitize(string name) { if (string.IsNullOrEmpty(name)) { return string.Empty; } name = name.Trim(); if (name.Length > 32) { name = name.Substring(0, 32); } return name; } public static Container Hovered() { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return null; } GameObject hoverObject = ((Humanoid)localPlayer).GetHoverObject(); Container val = (((Object)(object)hoverObject != (Object)null) ? hoverObject.GetComponentInParent() : null); if ((Object)(object)val != (Object)null) { return val; } Piece hoveringPiece = localPlayer.GetHoveringPiece(); if (!((Object)(object)hoveringPiece != (Object)null)) { return null; } return ((Component)hoveringPiece).GetComponent(); } } internal class ChestRenameReceiver : MonoBehaviour, TextReceiver { public string GetText() { return ChestNames.Get(((Component)this).GetComponent()) ?? string.Empty; } public void SetText(string text) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) Container component = ((Component)this).GetComponent(); if (!((Object)(object)component == (Object)null) && PrivateArea.CheckAccess(((Component)component).transform.position, 0f, false, true)) { ChestNames.Set(component, text); } } } internal static class ChestPicker { public static Container FindStoreTarget(Vector3 origin, ItemData item, bool mustExist) { //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) if (item == null) { return null; } float fallback = ((Plugin.Settings != null) ? Plugin.Settings.PlayerDumpRange.Value : 8f); Container result = null; float num = float.MaxValue; foreach (Container item2 in NearbyIndex.Current) { if (!((Object)(object)item2 == (Object)null)) { float num2 = RulesFile.DumpRange(ContainerFilter.PiecePrefab(item2), fallback); float num3 = ContainerFilter.Distance(origin, ((Component)item2).transform.position); if (!(num3 > num2) && CanAccept(item2, item, origin, mustExist) && num3 < num) { num = num3; result = item2; } } } return result; } public static bool CanAccept(Container chest, ItemData item, Vector3 from, bool mustExist) { if ((Object)(object)chest == (Object)null || item == null) { return false; } Inventory inventory = chest.GetInventory(); if (inventory == null || !inventory.CanAddItem(item, item.m_stack)) { return false; } if (!RulesFile.AllowsStore(ContainerFilter.PiecePrefab(chest), item)) { return false; } if (mustExist) { string text = ItemIds.SharedName(item); if (string.IsNullOrEmpty(text) || inventory.CountItems(text, -1, true) <= 0) { return false; } } return true; } public static List FindHolding(Vector3 origin, float range, string sharedName) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) List list = new List(); if (string.IsNullOrEmpty(sharedName)) { return list; } foreach (Container item in NearbyIndex.Within(origin, range)) { Inventory inventory = item.GetInventory(); if (inventory != null && inventory.CountItems(sharedName, -1, true) > 0) { list.Add(item); } } list.Sort((Container a, Container b) => ContainerFilter.Distance(origin, ((Component)a).transform.position).CompareTo(ContainerFilter.Distance(origin, ((Component)b).transform.position))); return list; } } internal static class ChestRename { public static bool WantsRename(bool alt) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_003a: 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_004d: Invalid comparison between Unknown and I4 //IL_004f: Unknown result type (might be due to invalid IL or missing references) if (Plugin.Settings == null || !Plugin.Settings.ModEnabled.Value) { return false; } if (alt) { return true; } KeyboardShortcut value = Plugin.Settings.RenameKey.Value; if ((int)((KeyboardShortcut)(ref value)).MainKey == 0) { return false; } if (!KeyUtil.ModifiersHeld(value)) { return false; } if ((int)((KeyboardShortcut)(ref value)).MainKey != 101) { return KeyUtil.Held(value); } return true; } public static bool TryOpen(Container container = null, bool warnIfMissing = true) { //IL_004c: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return false; } if ((Object)(object)container == (Object)null) { container = ChestNames.Hovered(); } if ((Object)(object)container == (Object)null || !ChestNames.CanRename(container)) { if (warnIfMissing) { ((Character)localPlayer).Message((MessageType)2, "Look at a chest, then press the rename key.", 0, (Sprite)null, false); } return false; } if (!PrivateArea.CheckAccess(((Component)container).transform.position, 0f, false, true)) { ((Character)localPlayer).Message((MessageType)2, "No access to this chest.", 0, (Sprite)null, false); return false; } ChestRenameReceiver chestRenameReceiver = ((Component)container).GetComponent(); if ((Object)(object)chestRenameReceiver == (Object)null) { chestRenameReceiver = ((Component)container).gameObject.AddComponent(); } if ((Object)(object)TextInput.instance == (Object)null) { return false; } TextInput.instance.RequestText((TextReceiver)(object)chestRenameReceiver, "Rename chest", 32); return true; } public static string PromptLabel() { //IL_0017: Unknown result type (might be due to invalid IL or missing references) if (Plugin.Settings == null) { return "Alt+E"; } string text = KeyUtil.Format(Plugin.Settings.RenameKey.Value); if (!string.IsNullOrEmpty(text)) { return text; } return "Shift+E"; } } internal static class InventoryDump { public static void DumpNearby() { //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) if (Plugin.Settings == null || !Plugin.Settings.ModEnabled.Value || !Plugin.Settings.StoreEnabled.Value) { return; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return; } Inventory inventory = ((Humanoid)localPlayer).GetInventory(); if (inventory == null) { return; } NearbyIndex.Rescan(((Component)localPlayer).transform.position, NearbyIndex.ScanRange()); List list = new List(inventory.GetAllItems()); int num = 0; foreach (ItemData item in list) { if (ShouldDump(item, inventory)) { Container val = ChestPicker.FindStoreTarget(((Component)localPlayer).transform.position, item, Plugin.Settings.MustHaveExisting.Value); if (!((Object)(object)val == (Object)null) && TransferService.StoreItem(val, inventory, item, item.m_stack)) { num++; } } } ((Character)localPlayer).Message((MessageType)1, (num > 0) ? Loc.T("Stored " + num + " stacks.", num + " Stapel eingelagert.") : Loc.T("Nothing to store.", "Nichts einzulagern."), 0, (Sprite)null, false); } public static bool StoreOne(ItemData item) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || item == null || Plugin.Settings == null) { return false; } Inventory inventory = ((Humanoid)localPlayer).GetInventory(); if (inventory == null) { return false; } NearbyIndex.Rescan(((Component)localPlayer).transform.position, NearbyIndex.ScanRange()); Container val = ChestPicker.FindStoreTarget(((Component)localPlayer).transform.position, item, Plugin.Settings.MustHaveExisting.Value); if ((Object)(object)val == (Object)null) { ((Character)localPlayer).Message((MessageType)2, Loc.T("No matching chest.", "Keine passende Truhe."), 0, (Sprite)null, false); return false; } return TransferService.StoreItem(val, inventory, item, item.m_stack); } public static bool ShouldDump(ItemData item, Inventory inv) { if (item == null || item.m_stack <= 0) { return false; } if (item.m_equipped) { return false; } if (Plugin.Settings.IgnoreHotbar.Value && item.m_gridPos.y == 0) { return false; } return true; } } internal static class SearchPing { public static void PingItem(ItemData item) { if (item != null) { Search(ItemIds.SharedName(item), ItemIds.PrefabName(item)); } } public static void OnCommand(ConsoleEventArgs args) { string text = ((args != null && args.Length > 1) ? args[1] : null); if (string.IsNullOrEmpty(text)) { ItemData hoveredPlayerItem = HoverStore.GetHoveredPlayerItem(); if (hoveredPlayerItem != null) { PingItem(hoveredPlayerItem); } else { Tell(Loc.T("Usage: storesearch ", "Nutzung: storesearch ")); } } else { Search(text, text); } } public static void Search(string sharedOrToken, string prefabHint) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return; } string text = ItemIds.SharedFromToken(sharedOrToken); NearbyIndex.Rescan(((Component)localPlayer).transform.position, NearbyIndex.ScanRange()); List list = ChestPicker.FindHolding(((Component)localPlayer).transform.position, NearbyIndex.ScanRange(), text); if (list.Count == 0 && !string.IsNullOrEmpty(prefabHint)) { string text2 = ItemIds.SharedFromToken(prefabHint); if (text2 != text) { list = ChestPicker.FindHolding(((Component)localPlayer).transform.position, NearbyIndex.ScanRange(), text2); } } if (list.Count == 0) { Tell(Loc.T("No nearby chest has that item.", "Keine nahe Truhe hat dieses Item.")); return; } Container val = list[0]; int num = 0; foreach (Container item in list) { Inventory inventory = item.GetInventory(); if (inventory != null) { num += inventory.CountItems(text, -1, true); } } TransferService.Highlight(val); if ((Object)(object)Chat.instance != (Object)null) { Chat.instance.SendPing(((Component)val).transform.position); } string text3 = prefabHint; if (Localization.instance != null && !string.IsNullOrEmpty(text)) { text3 = Localization.instance.Localize(text); } Tell(Loc.T(text3 + ": " + num + " in " + list.Count + " chest(s).", text3 + ": " + num + " in " + list.Count + " Truhe(n).")); } private static void Tell(string msg) { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer != (Object)null) { ((Character)localPlayer).Message((MessageType)2, msg, 0, (Sprite)null, false); } } } internal static class ContainerFilter { public static bool IsUsable(Container container) { if ((Object)(object)container == (Object)null) { return false; } ZNetView val = Refs.View(container); if ((Object)(object)val == (Object)null || !val.IsValid()) { return false; } if (container.GetInventory() == null) { return false; } if ((Object)(object)((Component)container).GetComponent() == (Object)null) { return false; } return true; } public static string PiecePrefab(Container container) { Piece val = (((Object)(object)container != (Object)null) ? ((Component)container).GetComponent() : null); if ((Object)(object)val == (Object)null) { return null; } return ItemIds.StripClone(((Object)((Component)val).gameObject).name); } public static bool PlayerMayUse(Container container, Vector3 from) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) if (!IsUsable(container)) { return false; } if (!PrivateArea.CheckAccess(((Component)container).transform.position, 0f, false, true)) { return false; } return true; } public static float Distance(Vector3 a, Vector3 b) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) return Vector3.Distance(a, b); } } internal static class ItemIds { public static string PrefabName(ItemData item) { if (item == null) { return null; } if ((Object)(object)item.m_dropPrefab != (Object)null) { return StripClone(((Object)item.m_dropPrefab).name); } if (item.m_shared == null || string.IsNullOrEmpty(item.m_shared.m_name) || (Object)(object)ObjectDB.instance == (Object)null) { return SharedName(item); } GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(item.m_shared); if ((Object)(object)itemPrefab != (Object)null) { item.m_dropPrefab = itemPrefab; return StripClone(((Object)itemPrefab).name); } return SharedName(item); } public static string SharedName(ItemData item) { if (item?.m_shared == null) { return null; } return item.m_shared.m_name; } public static string StripClone(string name) { if (string.IsNullOrEmpty(name)) { return name; } return name.Replace("(Clone)", string.Empty).Trim(); } public static bool Matches(ItemData item, string token) { if (item == null || string.IsNullOrEmpty(token)) { return false; } if (string.Equals(PrefabName(item), token, StringComparison.OrdinalIgnoreCase)) { return true; } if (string.Equals(SharedName(item), token, StringComparison.OrdinalIgnoreCase)) { return true; } if (Localization.instance != null && item.m_shared != null && string.Equals(Localization.instance.Localize(item.m_shared.m_name), token, StringComparison.OrdinalIgnoreCase)) { return true; } return false; } public static GameObject PrefabFromToken(string token) { if (string.IsNullOrEmpty(token) || (Object)(object)ObjectDB.instance == (Object)null) { return null; } GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(token); if ((Object)(object)itemPrefab != (Object)null) { return itemPrefab; } foreach (GameObject item in ObjectDB.instance.m_items) { if ((Object)(object)item == (Object)null) { continue; } ItemDrop component = item.GetComponent(); if (component?.m_itemData?.m_shared != null) { if (string.Equals(component.m_itemData.m_shared.m_name, token, StringComparison.OrdinalIgnoreCase)) { return item; } if (Localization.instance != null && string.Equals(Localization.instance.Localize(component.m_itemData.m_shared.m_name), token, StringComparison.OrdinalIgnoreCase)) { return item; } } } return null; } public static string SharedFromToken(string token) { GameObject val = PrefabFromToken(token); if ((Object)(object)val == (Object)null) { return token; } ItemDrop component = val.GetComponent(); if (component?.m_itemData?.m_shared == null) { return token; } return component.m_itemData.m_shared.m_name; } } internal static class NearbyIndex { private static readonly List Cached = new List(); private static float _nextScan; private static Vector3 _lastOrigin; private const float RescanMove = 1.5f; public static IReadOnlyList Current => Cached; public static void Tick() { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || Plugin.Settings == null || !Plugin.Settings.ModEnabled.Value) { Cached.Clear(); return; } float range = ScanRange(); Vector3 position = ((Component)localPlayer).transform.position; bool flag = Vector3.Distance(position, _lastOrigin) > 1.5f; if (!(Time.time < _nextScan) || flag || Cached.Count <= 0) { Rescan(position, range); _lastOrigin = position; _nextScan = Time.time + 0.6f; } } public static float ScanRange() { if (Plugin.Settings == null) { return 20f; } return RulesFile.MaxScanRange(Plugin.Settings.StoreRange.Value, Plugin.Settings.CraftRange.Value, Plugin.Settings.PlayerDumpRange.Value); } public static void Rescan(Vector3 origin, float range) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) Cached.Clear(); if (range <= 0f) { return; } Collider[] array = Physics.OverlapSphere(origin, range); HashSet hashSet = new HashSet(); Collider[] array2 = array; foreach (Collider val in array2) { if ((Object)(object)val == (Object)null) { continue; } Container componentInParent = ((Component)val).GetComponentInParent(); if (!((Object)(object)componentInParent == (Object)null)) { int instanceID = ((Object)componentInParent).GetInstanceID(); if (hashSet.Add(instanceID) && ContainerFilter.PlayerMayUse(componentInParent, origin)) { Cached.Add(componentInParent); } } } } public static List Within(Vector3 origin, float range) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) List list = new List(); foreach (Container item in Cached) { if (!((Object)(object)item == (Object)null) && ContainerFilter.Distance(origin, ((Component)item).transform.position) <= range) { list.Add(item); } } return list; } public static int CountItem(Vector3 origin, float range, string sharedName, bool leaveOne) { //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) if (string.IsNullOrEmpty(sharedName)) { return 0; } int num = 0; float fallback = ((Plugin.Settings != null) ? Plugin.Settings.CraftRange.Value : range); foreach (Container item in Cached) { if ((Object)(object)item == (Object)null) { continue; } string piecePrefab = ContainerFilter.PiecePrefab(item); float num2 = RulesFile.CraftRange(piecePrefab, fallback); if (ContainerFilter.Distance(origin, ((Component)item).transform.position) > num2) { continue; } Inventory inventory = item.GetInventory(); if (inventory != null && RulesFile.AllowsCraft(piecePrefab, sharedName)) { int num3 = inventory.CountItems(sharedName, -1, true); if (leaveOne && num3 > 0) { num3--; } if (num3 > 0) { num += num3; } } } return num; } }