using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using 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;
}
}
}