Please disclose if your mod was created primarily 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 DetectStorage v0.1.0
BepInEx\plugins\Detect\Detect.dll
Decompiled 3 weeks agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using Detect.Net; using Detect.Pieces; using HarmonyLib; using Jotunn; using Jotunn.Configs; using Jotunn.Entities; using Jotunn.Managers; using UnityEngine; using UnityEngine.Rendering; [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: AssemblyVersion("0.0.0.0")] namespace Detect { [BepInPlugin("saad.detect", "Detect Storage", "0.1.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { public const string ModGuid = "saad.detect"; public const string ModName = "Detect Storage"; public const string ModVersion = "0.1.0"; public const string DetectCategoryName = "Detect"; private Harmony _harmony; public static Plugin Instance { get; private set; } public static ConfigEntry<float> HubScanRadius { get; private set; } public static ConfigEntry<float> SortButtonCooldownSeconds { get; private set; } public static ConfigEntry<bool> HubShowRadiusRing { get; private set; } private void Awake() { //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Expected O, but got Unknown Instance = this; HubScanRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Hub", "ScanRadiusMeters", 20f, "Radius in meters used by Detect Hub to find Detect Chests."); SortButtonCooldownSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Hub", "SortButtonCooldownSeconds", 0.5f, "Client-side cooldown for Sort button clicks."); HubShowRadiusRing = ((BaseUnityPlugin)this).Config.Bind<bool>("Hub", "ShowRadiusRing", true, "Show a visible radius ring around Detect Hubs."); _harmony = new Harmony("saad.detect"); _harmony.PatchAll(); PrefabManager.OnVanillaPrefabsAvailable += RegisterPieces; } private void OnDestroy() { PrefabManager.OnVanillaPrefabsAvailable -= RegisterPieces; Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } private static void RegisterPieces() { //IL_001b: Unknown result type (might be due to invalid IL or missing references) PrefabManager.OnVanillaPrefabsAvailable -= RegisterPieces; PieceManager.Instance.AddPieceCategory("Detect"); DetectHub.RegisterPiece(); DetectChest.RegisterPiece(); ((BaseUnityPlugin)Instance).Logger.LogInfo((object)"Detect Storage: pieces and category registered."); } } } namespace Detect.UI { [HarmonyPatch] public static class ChestFilterPatch { private static readonly FieldInfo CurrentContainerField = AccessTools.Field(typeof(InventoryGui), "m_currentContainer") ?? AccessTools.Field(typeof(InventoryGui), "m_container"); private static bool _filterSelectionMode; private static DetectChest _activeChest; [HarmonyPatch(typeof(InventoryGui), "Update")] [HarmonyPostfix] private static void InventoryGui_Update_Postfix(InventoryGui __instance) { DetectChest detectChest = DetectChest.FromContainer(GetOpenContainer(__instance)); if ((Object)(object)detectChest == (Object)null && _filterSelectionMode) { DisableFilterMode(); } if (IsFilterKeyPressed() && !((Object)(object)detectChest == (Object)null)) { if (_filterSelectionMode && _activeChest == detectChest) { DisableFilterMode(); Logger.LogInfo((object)"Detect Chest: filter selection mode disabled."); ShowCenterMessage("Detect filter mode OFF"); } else { _filterSelectionMode = true; _activeChest = detectChest; Logger.LogInfo((object)"Detect Chest: filter selection mode enabled. Click an item to set filter, click empty slot to clear."); ShowCenterMessage("Detect filter mode ON - click item/empty"); } } } [HarmonyPatch(typeof(InventoryGui), "Hide")] [HarmonyPostfix] private static void InventoryGui_Hide_Postfix() { DisableFilterMode(); } [HarmonyPatch(typeof(InventoryGui), "OnSelectedItem")] [HarmonyPostfix] private static void InventoryGui_OnSelectedItem_Postfix(InventoryGui __instance, InventoryGrid grid, ItemData item, Vector2i pos, Modifier mod) { ApplyFilterFromPickedItem(__instance, item); } [HarmonyPatch(typeof(InventoryGui), "OnRightClickItem")] [HarmonyPostfix] private static void InventoryGui_OnRightClickItem_Postfix(InventoryGui __instance, InventoryGrid grid, ItemData item, Vector2i pos) { ApplyFilterFromPickedItem(__instance, item); } private static void ApplyFilterFromPickedItem(InventoryGui gui, ItemData item) { if (_filterSelectionMode && !((Object)(object)_activeChest == (Object)null) && _activeChest.IsUsable()) { if (DetectChest.FromContainer(GetOpenContainer(gui)) != _activeChest) { DisableFilterMode(); return; } string text = (((Object)(object)item?.m_dropPrefab != (Object)null) ? ((Object)item.m_dropPrefab).name : (item?.m_shared?.m_name ?? string.Empty)); _activeChest.RequestSetFilterFromClient(text); ShowCenterMessage(string.IsNullOrEmpty(text) ? "Detect filter cleared" : ("Detect filter set: " + item.m_shared.m_name)); DisableFilterMode(); } } private static Container GetOpenContainer(InventoryGui gui) { object? obj = CurrentContainerField?.GetValue(gui); return (Container)((obj is Container) ? obj : null); } private static void DisableFilterMode() { _filterSelectionMode = false; _activeChest = null; } private static bool IsFilterKeyPressed() { if (Input.GetKeyDown((KeyCode)102)) { return true; } try { return ZInput.GetKeyDown((KeyCode)102, false); } catch { return false; } } private static void ShowCenterMessage(string message) { if (!string.IsNullOrEmpty(message) && !((Object)(object)MessageHud.instance == (Object)null)) { MessageHud.instance.ShowMessage((MessageType)2, message, 0, (Sprite)null, false); } } } [HarmonyPatch] public static class HubSortButtonPatch { private static readonly FieldInfo CurrentContainerField = AccessTools.Field(typeof(InventoryGui), "m_currentContainer") ?? AccessTools.Field(typeof(InventoryGui), "m_container"); private const KeyCode SortHotkey = 103; private static DetectHub _boundHub; private static float _nextAllowedSortTriggerTime; [HarmonyPatch(typeof(InventoryGui), "Hide")] [HarmonyPostfix] private static void InventoryGui_Hide_Postfix() { _boundHub = null; } [HarmonyPatch(typeof(InventoryGui), "Update")] [HarmonyPriority(0)] [HarmonyPostfix] private static void InventoryGui_Update_Postfix(InventoryGui __instance) { Container openContainer = GetOpenContainer(__instance); _boundHub = (((Object)(object)openContainer == (Object)null) ? null : (((Component)openContainer).GetComponent<DetectHub>() ?? ((Component)openContainer).GetComponentInParent<DetectHub>())); if (!((Object)(object)_boundHub == (Object)null) && IsSortHotkeyPressed() && !(Time.time < _nextAllowedSortTriggerTime)) { _nextAllowedSortTriggerTime = Time.time + Mathf.Max(0.1f, Plugin.SortButtonCooldownSeconds?.Value ?? 0.5f); Logger.LogInfo((object)"Detect: hotkey sort triggered."); _boundHub.RequestSortFromClient(); ShowCenterMessage("Detect: sorting..."); } } private static Container GetOpenContainer(InventoryGui gui) { object? obj = CurrentContainerField?.GetValue(gui); return (Container)((obj is Container) ? obj : null); } private static bool IsSortHotkeyPressed() { if (Input.GetKeyDown((KeyCode)103)) { return true; } try { return ZInput.GetKeyDown((KeyCode)103, false); } catch { return false; } } private static void ShowCenterMessage(string message) { if (!string.IsNullOrEmpty(message) && !((Object)(object)MessageHud.instance == (Object)null)) { MessageHud.instance.ShowMessage((MessageType)2, message, 0, (Sprite)null, false); } } } } namespace Detect.Pieces { public class DetectChest : MonoBehaviour { public const string PiecePrefabName = "piece_detect_chest"; public const string FilterZdoKey = "detect_filter_item"; private const string VanillaSourcePiece = "piece_chest_wood"; private const string VanillaLargestChestPiece = "piece_chest_blackmetal"; private static readonly HashSet<DetectChest> ActiveChests = new HashSet<DetectChest>(); private static readonly MethodInfo InventoryChangedMethod = AccessTools.Method(typeof(Inventory), "Changed", (Type[])null, (Type[])null); private static readonly MethodInfo ContainerSaveMethod = AccessTools.Method(typeof(Container), "Save", (Type[])null, (Type[])null); private static readonly MethodInfo AddItemByNameMethod = AccessTools.Method(typeof(Inventory), "AddItem", new Type[7] { typeof(string), typeof(int), typeof(int), typeof(int), typeof(long), typeof(string), typeof(bool) }, (Type[])null); private static readonly MethodInfo AddItemWithPositionMethod = AccessTools.Method(typeof(Inventory), "AddItem", new Type[4] { typeof(ItemData), typeof(int), typeof(int), typeof(int) }, (Type[])null); private static bool _registered; private Container _container; private ZNetView _nview; public Container Container => _container; public ZNetView NetView => _nview; private void Awake() { _container = ((Component)this).GetComponent<Container>(); _nview = ((Component)this).GetComponent<ZNetView>(); if ((Object)(object)_nview != (Object)null) { _nview.Register<string>("Detect_RequestFilterSet", (Action<long, string>)RPC_RequestSetFilter); } } private void OnEnable() { ActiveChests.Add(this); } private void OnDisable() { ActiveChests.Remove(this); } public static void RegisterPiece() { //IL_0037: 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_0080: Expected O, but got Unknown //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Expected O, but got Unknown if (!_registered) { GameObject val = PrefabManager.Instance.CreateClonedPrefab("piece_detect_chest", "piece_chest_wood"); if ((Object)(object)val == (Object)null) { Logger.LogError((object)"Detect: failed to clone prefab piece_chest_wood for Detect Chest."); return; } ConfigurePrefab(val); PieceConfig val2 = new PieceConfig(); val2.Name = "Detect Chest"; val2.Description = "Filtered storage for one item type."; val2.PieceTable = "_HammerPieceTable"; val2.Category = "Detect"; val2.Requirements = (RequirementConfig[])(object)new RequirementConfig[1] { new RequirementConfig("Wood", 5, 0, true) }; PieceConfig val3 = val2; PieceManager.Instance.AddPiece(new CustomPiece(val, true, val3)); _registered = true; Logger.LogInfo((object)"Detect Chest registered."); } } private static void ConfigurePrefab(GameObject prefab) { Piece component = prefab.GetComponent<Piece>(); if ((Object)(object)component != (Object)null) { component.m_name = "Detect Chest"; component.m_description = "Accepts one configured item type."; component.m_craftingStation = null; } Container component2 = prefab.GetComponent<Container>(); if ((Object)(object)component2 != (Object)null) { component2.m_name = "Detect Chest"; ApplyLargestVanillaChestSize(component2); } DetectChest detectChest = default(DetectChest); if (!prefab.TryGetComponent<DetectChest>(ref detectChest)) { prefab.AddComponent<DetectChest>(); } StationExtension[] componentsInChildren = prefab.GetComponentsInChildren<StationExtension>(true); for (int i = 0; i < componentsInChildren.Length; i++) { Object.DestroyImmediate((Object)(object)componentsInChildren[i]); } CraftingStation[] componentsInChildren2 = prefab.GetComponentsInChildren<CraftingStation>(true); for (int i = 0; i < componentsInChildren2.Length; i++) { Object.DestroyImmediate((Object)(object)componentsInChildren2[i]); } } private static void ApplyLargestVanillaChestSize(Container detectContainer) { int width = 8; int height = 4; GameObject prefab = PrefabManager.Instance.GetPrefab("piece_chest_blackmetal"); Container val = default(Container); if ((Object)(object)prefab != (Object)null && prefab.TryGetComponent<Container>(ref val)) { width = val.m_width; height = val.m_height; } detectContainer.m_width = width; detectContainer.m_height = height; } public bool IsUsable() { if ((Object)(object)_container != (Object)null && (Object)(object)_nview != (Object)null) { return _nview.IsValid(); } return false; } public string GetFilterPrefabName() { ZNetView nview = _nview; ZDO obj = ((nview != null) ? nview.GetZDO() : null); return ((obj != null) ? obj.GetString("detect_filter_item", string.Empty) : null) ?? string.Empty; } public bool HasFilter() { return !string.IsNullOrEmpty(GetFilterPrefabName()); } public bool AcceptsItem(ItemData item) { if (item == null) { return false; } string filterPrefabName = GetFilterPrefabName(); if (string.IsNullOrEmpty(filterPrefabName)) { return false; } string itemKey = GetItemKey(item); if (!string.IsNullOrEmpty(itemKey)) { return string.Equals(itemKey, filterPrefabName, StringComparison.Ordinal); } return false; } public void RequestSetFilterFromClient(string itemPrefabName) { if (IsUsable()) { Logger.LogInfo((object)("Detect Chest: sending filter set request '" + (itemPrefabName ?? string.Empty) + "'.")); DetectRPC.RequestChestFilterSet(_nview, itemPrefabName); } } public void SetFilterServer(string itemPrefabName) { ZNetView nview = _nview; ZDO val = ((nview != null) ? nview.GetZDO() : null); if (val != null) { val.Set("detect_filter_item", itemPrefabName ?? string.Empty); ContainerSaveMethod?.Invoke(_container, null); MethodInfo inventoryChangedMethod = InventoryChangedMethod; if ((object)inventoryChangedMethod != null) { Container container = _container; inventoryChangedMethod.Invoke((container != null) ? container.GetInventory() : null, null); } Logger.LogInfo((object)("Detect Chest: server filter set to '" + (itemPrefabName ?? string.Empty) + "'.")); } } public static DetectChest FromContainer(Container container) { object obj; if (!((Object)(object)container == (Object)null)) { obj = ((Component)container).GetComponent<DetectChest>(); if (obj == null) { return ((Component)container).GetComponentInParent<DetectChest>(); } } else { obj = null; } return (DetectChest)obj; } public static List<DetectChest> GetInRange(Vector3 center, float radius) { //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_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) List<DetectChest> list = new List<DetectChest>(); float num = radius * radius; foreach (DetectChest activeChest in ActiveChests) { if (!((Object)(object)activeChest == (Object)null) && activeChest.IsUsable()) { Vector3 val = ((Component)activeChest).transform.position - center; if (((Vector3)(ref val)).sqrMagnitude <= num) { list.Add(activeChest); } } } list.Sort(delegate(DetectChest left, DetectChest right) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: 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_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) Vector3 val2 = ((Component)left).transform.position - center; float sqrMagnitude = ((Vector3)(ref val2)).sqrMagnitude; val2 = ((Component)right).transform.position - center; float sqrMagnitude2 = ((Vector3)(ref val2)).sqrMagnitude; return sqrMagnitude.CompareTo(sqrMagnitude2); }); return list; } public bool CanAcceptStack(ItemData item, int stackAmount) { if (item == null || stackAmount <= 0 || !AcceptsItem(item)) { return false; } Container container = _container; Inventory val = ((container != null) ? container.GetInventory() : null); if (val == null) { return false; } return CanInventoryFitStack(val, item, stackAmount); } public bool TryStoreStackServer(ItemData item, int stackAmount) { if (!DetectRPC.IsServer() || !CanAcceptStack(item, stackAmount)) { return false; } Container container = _container; Inventory val = ((container != null) ? container.GetInventory() : null); if (val == null) { return false; } string itemKey = GetItemKey(item); if (string.IsNullOrEmpty(itemKey)) { return false; } if (!TryAddStack(val, item, stackAmount, itemKey)) { Logger.LogWarning((object)$"Detect Chest: failed to add stack '{itemKey}' x{stackAmount}."); return false; } InventoryChangedMethod?.Invoke(val, null); ContainerSaveMethod?.Invoke(_container, null); return true; } private void RPC_RequestSetFilter(long sender, string itemPrefabName) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) if (DetectRPC.IsServer() && IsUsable()) { if (!DetectRPC.IsSenderCloseEnough(sender, ((Component)this).transform.position, 8f)) { Logger.LogWarning((object)$"Detect Chest filter denied: sender {sender} is too far or unresolved."); return; } Logger.LogInfo((object)$"Detect Chest: filter RPC accepted from sender {sender} with value '{itemPrefabName ?? string.Empty}'."); SetFilterServer(itemPrefabName); } } private static bool CanInventoryFitStack(Inventory inventory, ItemData item, int stackAmount) { int num = stackAmount; string itemKey = GetItemKey(item); if (string.IsNullOrEmpty(itemKey)) { return false; } foreach (ItemData allItem in inventory.GetAllItems()) { if (allItem == null || (Object)(object)allItem.m_dropPrefab == (Object)null) { continue; } string itemKey2 = GetItemKey(allItem); if (string.IsNullOrEmpty(itemKey2) || !string.Equals(itemKey2, itemKey, StringComparison.Ordinal)) { continue; } int num2 = Mathf.Max(0, allItem.m_shared.m_maxStackSize - allItem.m_stack); if (num2 > 0) { num -= num2; if (num <= 0) { return true; } } } int num3 = Mathf.Max(1, item.m_shared.m_maxStackSize); num -= inventory.GetEmptySlots() * num3; return num <= 0; } private static bool TryAddStack(Inventory inventory, ItemData sourceItem, int stackAmount, string prefabName) { if (sourceItem == null || stackAmount <= 0 || string.IsNullOrEmpty(prefabName)) { return false; } if (AddItemByNameMethod != null && AddItemByNameMethod.Invoke(inventory, new object[7] { prefabName, stackAmount, sourceItem.m_quality, sourceItem.m_variant, sourceItem.m_crafterID, sourceItem.m_crafterName ?? string.Empty, false }) is ItemData) { return true; } if (AddItemWithPositionMethod != null) { ItemData val = sourceItem.Clone(); val.m_stack = stackAmount; object obj = AddItemWithPositionMethod.Invoke(inventory, new object[4] { val, stackAmount, -1, -1 }); bool flag = default(bool); int num; if (obj is bool) { flag = (bool)obj; num = 1; } else { num = 0; } return (byte)((uint)num & (flag ? 1u : 0u)) != 0; } return false; } private static string GetItemKey(ItemData item) { if (item == null) { return string.Empty; } if (!((Object)(object)item.m_dropPrefab != (Object)null) || string.IsNullOrEmpty(((Object)item.m_dropPrefab).name)) { return item.m_shared?.m_name ?? string.Empty; } return ((Object)item.m_dropPrefab).name; } } public class DetectHub : MonoBehaviour { public const string PiecePrefabName = "piece_detect_hub"; private const string VanillaSourcePiece = "piece_chest_wood"; private const int RadiusRingSegments = 96; private const float RadiusRingHeight = 0.05f; private static bool _registered; private static readonly MethodInfo InventoryChangedMethod = AccessTools.Method(typeof(Inventory), "Changed", (Type[])null, (Type[])null); private static readonly MethodInfo ContainerSaveMethod = AccessTools.Method(typeof(Container), "Save", (Type[])null, (Type[])null); private static readonly MethodInfo RemoveItemMethod = AccessTools.Method(typeof(Inventory), "RemoveItem", new Type[2] { typeof(ItemData), typeof(int) }, (Type[])null); private static readonly FieldInfo PlacementGhostField = AccessTools.Field(typeof(Player), "m_placementGhost"); private Container _container; private ZNetView _nview; private LineRenderer _radiusRenderer; private float _radiusRingLastValue = -1f; public Container Container => _container; public ZNetView NetView => _nview; private void Awake() { _container = ((Component)this).GetComponent<Container>(); _nview = ((Component)this).GetComponent<ZNetView>(); if ((Object)(object)_nview != (Object)null) { _nview.Register("Detect_RequestSort", (Action<long>)RPC_RequestSort); } SetupRadiusRing(); } private void Update() { UpdateRadiusRing(); } public static void RegisterPiece() { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Expected O, but got Unknown //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Expected O, but got Unknown //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Expected O, but got Unknown //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Expected O, but got Unknown if (!_registered) { GameObject val = PrefabManager.Instance.CreateClonedPrefab("piece_detect_hub", "piece_chest_wood"); if ((Object)(object)val == (Object)null) { Logger.LogError((object)"Detect: failed to clone prefab piece_chest_wood for Detect Hub."); return; } ConfigurePrefab(val); PieceConfig val2 = new PieceConfig(); val2.Name = "Detect Hub"; val2.Description = "Stores loot and sorts it into nearby Detect Chests."; val2.PieceTable = "_HammerPieceTable"; val2.Category = "Detect"; val2.Requirements = (RequirementConfig[])(object)new RequirementConfig[2] { new RequirementConfig("Wood", 20, 0, true), new RequirementConfig("Stone", 20, 0, true) }; PieceConfig val3 = val2; PieceManager.Instance.AddPiece(new CustomPiece(val, true, val3)); _registered = true; Logger.LogInfo((object)"Detect Hub registered."); } } private static void ConfigurePrefab(GameObject prefab) { Piece component = prefab.GetComponent<Piece>(); if ((Object)(object)component != (Object)null) { component.m_name = "Detect Hub"; component.m_description = "Drop loot here, then click Sort."; component.m_craftingStation = null; } Container component2 = prefab.GetComponent<Container>(); if ((Object)(object)component2 != (Object)null) { component2.m_name = "Detect Hub"; } DetectHub detectHub = default(DetectHub); if (!prefab.TryGetComponent<DetectHub>(ref detectHub)) { prefab.AddComponent<DetectHub>(); } StationExtension[] componentsInChildren = prefab.GetComponentsInChildren<StationExtension>(true); for (int i = 0; i < componentsInChildren.Length; i++) { Object.DestroyImmediate((Object)(object)componentsInChildren[i]); } CraftingStation[] componentsInChildren2 = prefab.GetComponentsInChildren<CraftingStation>(true); for (int i = 0; i < componentsInChildren2.Length; i++) { Object.DestroyImmediate((Object)(object)componentsInChildren2[i]); } } public float GetScanRadius() { return Mathf.Max(0.5f, Plugin.HubScanRadius?.Value ?? 10f); } public bool IsUsable() { if ((Object)(object)_container != (Object)null && (Object)(object)_nview != (Object)null) { return _nview.IsValid(); } return false; } public void RequestSortFromClient() { if (!IsUsable()) { Logger.LogWarning((object)"Detect Hub: sort request ignored, hub is not usable."); return; } Logger.LogInfo((object)"Detect Hub: sending sort RPC request."); DetectRPC.RequestHubSort(_nview); } private void RPC_RequestSort(long sender) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) if (!DetectRPC.IsServer() || !IsUsable()) { Logger.LogWarning((object)"Detect Hub: server RPC sort ignored (not server or unusable)."); return; } if (!DetectRPC.IsSenderCloseEnough(sender, ((Component)this).transform.position, 8f)) { Logger.LogWarning((object)$"Detect Hub sort denied: sender {sender} is too far or unresolved."); return; } Logger.LogInfo((object)$"Detect Hub: sort RPC accepted from sender {sender}."); ExecuteSortServer(); } private void ExecuteSortServer() { //IL_0020: Unknown result type (might be due to invalid IL or missing references) Inventory inventory = _container.GetInventory(); if (inventory == null) { Logger.LogWarning((object)"Detect Hub: sort aborted, hub inventory is null."); return; } List<DetectChest> inRange = DetectChest.GetInRange(((Component)this).transform.position, GetScanRadius()); if (inRange.Count == 0) { Logger.LogInfo((object)"Detect Hub: no Detect Chest found in range."); return; } List<ItemData> list = new List<ItemData>(inventory.GetAllItems()); bool flag = false; foreach (ItemData item in list) { if (item == null || item.m_stack <= 0) { continue; } int stack = item.m_stack; foreach (DetectChest item2 in inRange) { if (!((Object)(object)item2 == (Object)null) && item2.IsUsable() && item2.CanAcceptStack(item, stack) && item2.TryStoreStackServer(item, stack)) { if (RemoveItemMethod != null) { RemoveItemMethod.Invoke(inventory, new object[2] { item, stack }); } else { inventory.RemoveItem(item, stack); } flag = true; break; } } } if (flag) { InventoryChangedMethod?.Invoke(inventory, null); ContainerSaveMethod?.Invoke(_container, null); Logger.LogInfo((object)"Detect Hub: sorting moved items successfully."); } else { Logger.LogInfo((object)"Detect Hub: sorting completed but no stack could be moved."); } } private void SetupRadiusRing() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_0032: 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_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Expected O, but got Unknown //IL_00f0: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("DetectHubRadiusRing"); val.transform.SetParent(((Component)this).transform, false); val.transform.localPosition = new Vector3(0f, 0.05f, 0f); val.transform.localRotation = Quaternion.identity; _radiusRenderer = val.AddComponent<LineRenderer>(); _radiusRenderer.loop = true; _radiusRenderer.useWorldSpace = false; _radiusRenderer.positionCount = 96; _radiusRenderer.widthMultiplier = 0.03f; _radiusRenderer.textureMode = (LineTextureMode)0; ((Renderer)_radiusRenderer).shadowCastingMode = (ShadowCastingMode)0; ((Renderer)_radiusRenderer).receiveShadows = false; ((Renderer)_radiusRenderer).enabled = false; Material val2 = new Material(Shader.Find("Unlit/Color") ?? Shader.Find("Sprites/Default")); val2.color = new Color(0.35f, 1f, 0.35f, 0.75f); ((Renderer)_radiusRenderer).material = val2; } private void UpdateRadiusRing() { //IL_00a3: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_radiusRenderer == (Object)null) { return; } ConfigEntry<bool> hubShowRadiusRing = Plugin.HubShowRadiusRing; if ((hubShowRadiusRing != null && !hubShowRadiusRing.Value) || !ShouldShowBuildRadius()) { ((Renderer)_radiusRenderer).enabled = false; return; } ((Renderer)_radiusRenderer).enabled = true; float num = Mathf.Max(0.5f, GetScanRadius()); if (!Mathf.Approximately(num, _radiusRingLastValue)) { _radiusRingLastValue = num; for (int i = 0; i < 96; i++) { float num2 = (float)i / 96f * (float)Math.PI * 2f; float num3 = Mathf.Cos(num2) * num; float num4 = Mathf.Sin(num2) * num; _radiusRenderer.SetPosition(i, new Vector3(num3, 0f, num4)); } } } private static bool ShouldShowBuildRadius() { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return false; } object? obj = PlacementGhostField?.GetValue(localPlayer); GameObject val = (GameObject)((obj is GameObject) ? obj : null); if ((Object)(object)val == (Object)null) { return false; } string text = ((Object)val).name; int num = text.IndexOf("(Clone)", StringComparison.Ordinal); if (num >= 0) { text = text.Substring(0, num).Trim(); } if (!string.Equals(text, "piece_detect_hub", StringComparison.Ordinal)) { return string.Equals(text, "piece_detect_chest", StringComparison.Ordinal); } return true; } } } namespace Detect.Net { public static class DetectRPC { public const string HubSortRequest = "Detect_RequestSort"; public const string ChestFilterRequest = "Detect_RequestFilterSet"; private static readonly MethodInfo GetPeerMethod = AccessTools.Method(typeof(ZNet), "GetPeer", new Type[1] { typeof(long) }, (Type[])null); private static readonly FieldInfo PeerRefPosField = AccessTools.Field(typeof(ZNetPeer), "m_refPos"); public static void RequestHubSort(ZNetView nview) { if (!((Object)(object)nview == (Object)null) && nview.IsValid()) { nview.InvokeRPC("Detect_RequestSort", Array.Empty<object>()); } } public static void RequestChestFilterSet(ZNetView nview, string filterPrefabName) { if (!((Object)(object)nview == (Object)null) && nview.IsValid()) { nview.InvokeRPC("Detect_RequestFilterSet", new object[1] { filterPrefabName ?? string.Empty }); } } public static bool IsServer() { if ((Object)(object)ZNet.instance != (Object)null) { return ZNet.instance.IsServer(); } return false; } public static bool IsSenderCloseEnough(long sender, Vector3 point, float maxDistance) { //IL_0054: 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) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)ZNet.instance == (Object)null) { return false; } float num = maxDistance * maxDistance; object obj = GetPeerMethod?.Invoke(ZNet.instance, new object[1] { sender }); if (obj != null && PeerRefPosField != null) { Vector3 val = (Vector3)PeerRefPosField.GetValue(obj) - point; return ((Vector3)(ref val)).sqrMagnitude <= num; } if (ZNet.instance.IsServer() && !ZNet.instance.IsDedicated()) { return true; } return false; } } }