Decompiled source of UnifiedStorage v1.1.2
plugins\UnifiedStorage\UnifiedStorage.Core.dll
Decompiled 5 hours agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using Microsoft.CodeAnalysis; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")] [assembly: AssemblyCompany("UnifiedStorage.Core")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+1bfd7610fb9c5d1c7a459055f53ca382a8873b38")] [assembly: AssemblyProduct("UnifiedStorage.Core")] [assembly: AssemblyTitle("UnifiedStorage.Core")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class IsReadOnlyAttribute : Attribute { } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace UnifiedStorage.Core { public static class AggregationService { public static IReadOnlyList<AggregatedItem> Aggregate(IReadOnlyList<SourceStack> sourceStacks, Func<string, int>? resolveMaxStackSize = null) { Func<string, int> resolveMaxStackSize2 = resolveMaxStackSize; return (from item in (from s in sourceStacks where s.Amount > 0 group s by s.Key).Select(delegate(IGrouping<ItemKey, SourceStack> @group) { int num = ((resolveMaxStackSize2 != null) ? resolveMaxStackSize2(@group.Key.PrefabName) : @group.Max((SourceStack s) => s.StackSize)); if (num <= 0) { num = 1; } return new AggregatedItem { Key = @group.Key, DisplayName = (@group.Select((SourceStack s) => s.DisplayName).FirstOrDefault() ?? @group.Key.PrefabName), TotalAmount = @group.Sum((SourceStack s) => s.Amount), SourceCount = @group.Select((SourceStack s) => s.SourceId).Distinct().Count(), StackSize = num }; }) orderby item.DisplayName, item.TotalAmount descending select item).ToList(); } public static int CalculateVirtualSlots(IReadOnlyList<AggregatedItem> items) { return items.Sum((AggregatedItem i) => (i.StackSize <= 0) ? 1 : ((int)Math.Ceiling((double)i.TotalAmount / (double)i.StackSize))); } } public static class ChunkedTransfer { public static int ClampMeasuredMove(int requestedAmount, int beforeAmount, int afterAmount) { if (requestedAmount <= 0) { return 0; } int num = afterAmount - beforeAmount; if (num <= 0) { return 0; } return Math.Min(requestedAmount, num); } public static int Move(int requestedAmount, int maxChunkSize, Func<int, int> moveChunk) { if (moveChunk == null) { throw new ArgumentNullException("moveChunk"); } if (requestedAmount <= 0 || maxChunkSize <= 0) { return 0; } int num = requestedAmount; int num2 = 0; while (num > 0) { int num3 = Math.Min(maxChunkSize, num); int num4 = moveChunk(num3); if (num4 <= 0) { break; } if (num4 > num3) { num4 = num3; } num2 += num4; num -= num4; if (num4 < num3) { break; } } return num2; } } public sealed class ContainerSlot { public string SourceId { get; set; } = string.Empty; public int FreeSpace { get; set; } public float Distance { get; set; } } public static class DepositPlanner { public static DepositPlan Plan(IReadOnlyList<ContainerSlot> containers, int requestedAmount) { DepositPlan depositPlan = new DepositPlan { RequestedAmount = requestedAmount }; int num = Math.Max(0, requestedAmount); if (num <= 0 || containers.Count == 0) { return depositPlan; } int num2 = num; foreach (ContainerSlot item in (from c in containers where c.FreeSpace > 0 orderby c.Distance select c).ThenBy<ContainerSlot, string>((ContainerSlot c) => c.SourceId, StringComparer.Ordinal)) { if (num2 <= 0) { break; } int num3 = Math.Min(item.FreeSpace, num2); if (num3 > 0) { depositPlan.Deposits.Add(new PlannedDeposit { SourceId = item.SourceId, Amount = num3 }); num2 -= num3; } } depositPlan.PlannedAmount = num - num2; return depositPlan; } } public readonly struct ItemKey : IEquatable<ItemKey> { public string PrefabName { get; } public int Quality { get; } public int Variant { get; } public ItemKey(string prefabName, int quality, int variant) { PrefabName = prefabName ?? string.Empty; Quality = quality; Variant = variant; } public bool Equals(ItemKey other) { if (string.Equals(PrefabName, other.PrefabName, StringComparison.Ordinal) && Quality == other.Quality) { return Variant == other.Variant; } return false; } public override bool Equals(object? obj) { if (obj is ItemKey other) { return Equals(other); } return false; } public override int GetHashCode() { return ((17 * 23 + (PrefabName?.GetHashCode() ?? 0)) * 23 + Quality.GetHashCode()) * 23 + Variant.GetHashCode(); } } public sealed class AggregatedItem { public ItemKey Key { get; set; } public string DisplayName { get; set; } = string.Empty; public int TotalAmount { get; set; } public int SourceCount { get; set; } public int StackSize { get; set; } } public sealed class SearchResult { public IReadOnlyList<AggregatedItem> Items { get; set; } = Array.Empty<AggregatedItem>(); } public sealed class SourceStack { public ItemKey Key { get; set; } public string DisplayName { get; set; } = string.Empty; public int Amount { get; set; } public int StackSize { get; set; } public float Distance { get; set; } public string SourceId { get; set; } = string.Empty; } public sealed class PlannedTake { public string SourceId { get; set; } = string.Empty; public int Amount { get; set; } } public sealed class WithdrawPlan { public List<PlannedTake> Takes { get; set; } = new List<PlannedTake>(); public int RequestedAmount { get; set; } public int PlannedAmount { get; set; } } public sealed class PlannedDeposit { public string SourceId { get; set; } = string.Empty; public int Amount { get; set; } } public sealed class DepositPlan { public List<PlannedDeposit> Deposits { get; set; } = new List<PlannedDeposit>(); public int RequestedAmount { get; set; } public int PlannedAmount { get; set; } } public static class SearchService { public static SearchResult Filter(IReadOnlyList<AggregatedItem> items, string query) { if (items.Count == 0) { return new SearchResult(); } if (string.IsNullOrWhiteSpace(query)) { return new SearchResult { Items = items }; } string trimmed = query.Trim(); List<AggregatedItem> items2 = items.Where((AggregatedItem item) => item.DisplayName.IndexOf(trimmed, StringComparison.OrdinalIgnoreCase) >= 0).ToList(); return new SearchResult { Items = items2 }; } } public static class WithdrawPlanner { public static WithdrawPlan Plan(IReadOnlyList<SourceStack> sourceStacks, ItemKey key, int requestedAmount, int maxReceivable) { int val = Math.Max(0, requestedAmount); int num = Math.Max(0, Math.Min(val, maxReceivable)); int num2 = num; WithdrawPlan withdrawPlan = new WithdrawPlan { RequestedAmount = requestedAmount }; if (num2 <= 0) { return withdrawPlan; } foreach (SourceStack item in (from s in sourceStacks where s.Key.Equals(key) && s.Amount > 0 orderby s.Distance select s).ThenBy<SourceStack, string>((SourceStack s) => s.SourceId, StringComparer.Ordinal)) { if (num2 == 0) { break; } int num3 = Math.Min(item.Amount, num2); if (num3 > 0) { withdrawPlan.Takes.Add(new PlannedTake { SourceId = item.SourceId, Amount = num3 }); num2 -= num3; } } withdrawPlan.PlannedAmount = num - num2; return withdrawPlan; } } }
plugins\UnifiedStorage\UnifiedStorage.dll
Decompiled 5 hours ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Jotunn.Configs; using Jotunn.Entities; using Jotunn.Managers; using Microsoft.CodeAnalysis; using TMPro; using UnifiedStorage.Core; using UnifiedStorage.Mod.Config; using UnifiedStorage.Mod.Diagnostics; using UnifiedStorage.Mod.Domain; using UnifiedStorage.Mod.Models; using UnifiedStorage.Mod.Network; using UnifiedStorage.Mod.Patches; using UnifiedStorage.Mod.Pieces; using UnifiedStorage.Mod.Server; using UnifiedStorage.Mod.Session; using UnifiedStorage.Mod.Shared; using UnifiedStorage.Mod.UI; using UnityEngine; using UnityEngine.Events; 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("UnifiedStorage")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+1bfd7610fb9c5d1c7a459055f53ca382a8873b38")] [assembly: AssemblyProduct("UnifiedStorage")] [assembly: AssemblyTitle("UnifiedStorage")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace UnifiedStorage.Mod { [BepInPlugin("andre.valheim.unifiedstorage", "Unified Storage", "1.1.2")] [BepInDependency(/*Could not decode attribute arguments.*/)] public sealed class UnifiedStoragePlugin : BaseUnityPlugin { public const string PluginGuid = "andre.valheim.unifiedstorage"; public const string PluginName = "Unified Storage"; public const string PluginVersion = "1.1.2"; private const float WorldChangeRefreshMinInterval = 0.2f; private static bool _blockGameInput; private StorageConfig? _config; private StorageTrace? _trace; private Harmony? _harmony; private IContainerScanner? _scanner; private TerminalSessionService? _session; private TerminalAuthorityService? _authority; private TerminalRpcRoutes? _rpcRoutes; private UnifiedTerminalRegistrar? _pieceRegistrar; private TerminalUIManager? _ui; private bool _trackedInventoryDirty; private bool _isApplyingRefresh; private bool _wasDragging; private float _nextAllowedWorldRefreshAt; private string _lastSearch = string.Empty; private int _lastUiRevision = -1; internal static UnifiedStoragePlugin? Instance { get; private set; } private void Awake() { //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Expected O, but got Unknown Instance = this; _config = new StorageConfig(((BaseUnityPlugin)this).Config); _trace = new StorageTrace(((BaseUnityPlugin)this).Logger, _config); _scanner = new ContainerScanner(_config); _authority = new TerminalAuthorityService(_config, _scanner, ((BaseUnityPlugin)this).Logger); _rpcRoutes = new TerminalRpcRoutes(_authority, ((BaseUnityPlugin)this).Logger); _rpcRoutes.EnsureRegistered(); _session = new TerminalSessionService(_config, _scanner, _rpcRoutes, ((BaseUnityPlugin)this).Logger, _trace); _pieceRegistrar = new UnifiedTerminalRegistrar(_config, ((BaseUnityPlugin)this).Logger); _ui = new TerminalUIManager(); PrefabManager.OnVanillaPrefabsAvailable += OnVanillaPrefabsAvailable; _harmony = new Harmony("andre.valheim.unifiedstorage.patches"); _harmony.PatchAll(typeof(ContainerInteractPatch)); _harmony.PatchAll(typeof(InventoryAddItemPatch)); _harmony.PatchAll(typeof(InventoryAddItemAtPositionPatch)); _harmony.PatchAll(typeof(InventoryMoveItemToThisPatch)); _harmony.PatchAll(typeof(InventoryGuiHidePatch)); _harmony.PatchAll(typeof(InventoryGuiAwakePatch)); _harmony.PatchAll(typeof(InventoryGuiUpdatePatch)); _harmony.PatchAll(typeof(InventoryGridOnLeftClickPatch)); _harmony.PatchAll(typeof(InventoryGridOnRightClickPatch)); _harmony.PatchAll(typeof(InventoryGuiOnTakeAllPatch)); _harmony.PatchAll(typeof(InventoryGuiOnStackAllPatch)); _harmony.PatchAll(typeof(InventoryGuiOnDropOutsidePatch)); _harmony.PatchAll(typeof(InventoryChangedPatch)); _harmony.PatchAll(typeof(ZInputGetButtonPatch)); _harmony.PatchAll(typeof(ZInputGetButtonDownPatch)); _harmony.PatchAll(typeof(ZInputGetButtonUpPatch)); _harmony.PatchAll(typeof(ZInputGetKeyPatch)); _harmony.PatchAll(typeof(ZInputGetKeyDownPatch)); _harmony.PatchAll(typeof(ZInputGetKeyUpPatch)); _harmony.PatchAll(typeof(ContainerHoverTextPatch)); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Unified Storage v1.1.2 loaded."); } private void Update() { _rpcRoutes?.EnsureRegistered(); _authority?.Tick(); _session?.Tick(); TryProcessWorldChangeRefresh(); } private void OnDestroy() { PrefabManager.OnVanillaPrefabsAvailable -= OnVanillaPrefabsAvailable; Harmony? harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } _session?.EndSession(); _blockGameInput = false; Instance = null; } private void OnVanillaPrefabsAvailable() { _pieceRegistrar?.RegisterPiece(); } internal void TryHandleChestInteract(Container container, Humanoid character) { if (_session != null) { Player val = (Player)(object)((character is Player) ? character : null); if (val != null && !((Object)(object)val != (Object)(object)Player.m_localPlayer) && _session.HandleContainerInteract(container, val)) { _lastSearch = string.Empty; _ui?.ClearSearch(); } } } internal void OnInventoryGuiClosing() { _blockGameInput = false; _lastSearch = string.Empty; _trackedInventoryDirty = false; _isApplyingRefresh = false; _wasDragging = false; _lastUiRevision = -1; _session?.EndSession(); _ui?.Reset(); } internal void OnInventoryGuiAwake(InventoryGui gui) { _ui?.EnsureNativeUi(gui); } internal void OnInventoryGuiUpdate(InventoryGui gui) { if (_ui == null || _session == null) { return; } _ui.EnsureNativeUi(gui); _ui.UpdateChestInclusionToggle(gui); if (!_session.IsActive || !InventoryGui.IsVisible() || !gui.IsContainerOpen()) { _blockGameInput = false; _wasDragging = false; _ui.SetTakeAllButtonEnabled(gui, enabled: true); _ui.SetNativeUiVisible(visible: false); _ui.RestoreLayout(); _lastUiRevision = -1; return; } _ui.SetTakeAllButtonEnabled(gui, enabled: false); _ui.SetNativeUiVisible(visible: true); _ui.UpdateContainerName(gui); bool flag = ReflectionHelpers.IsDragInProgress(); if (flag && !_wasDragging) { OnContainerInteraction(); } _wasDragging = flag; _ui.ApplyExpandedLayout(gui, _session.ContentRows); if (_session.UiRevision != _lastUiRevision) { _lastUiRevision = _session.UiRevision; _ui.UpdateMetaText(_session.SlotsUsedVirtual, _session.SlotsTotalPhysical, _session.ChestsInRange); _ui.RefreshContainerGrid(gui); } _ui.UpdateSearchBinding(gui); UpdateSearchFocusState(); ProcessSearchChanges(gui); } internal static bool ShouldBlockGameInput() { return _blockGameInput; } internal bool IsUnifiedSessionActive() { if (_session != null) { return _session.IsActive; } return false; } internal bool ShouldBlockDeposit(Inventory targetInventory) { if (_session == null || !_session.IsActive || _session.IsApplyingProjection) { return false; } if (!_session.IsTerminalInventory(targetInventory)) { return false; } return _session.IsStorageFull; } internal int GetNearbyChestCount(Vector3 position) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) if (_scanner == null || _config == null) { return 0; } return _scanner.GetNearbyContainers(position, _config.ScanRadius.Value).Count; } internal void OnTrackedInventoryChanged(Inventory inventory) { if (!_isApplyingRefresh && _session != null && _session.IsActive && inventory != null && !_session.IsApplyingProjection && _session.IsTrackedInventory(inventory)) { _trackedInventoryDirty = true; } } internal void OnContainerInteraction() { if (_session != null && _session.IsActive && !((Object)(object)InventoryGui.instance == (Object)null)) { _trackedInventoryDirty = false; ExecuteSessionRefresh(delegate { _session.NotifyContainerInteraction(); }); _ui?.UpdateMetaText(_session.SlotsUsedVirtual, _session.SlotsTotalPhysical, _session.ChestsInRange); _ui?.RefreshContainerGrid(InventoryGui.instance); } } internal void OnInventoryGridInteraction(InventoryGrid grid) { if (_session != null && _session.IsActive && !((Object)(object)InventoryGui.instance == (Object)null) && !((Object)(object)grid == (Object)null)) { OnContainerInteraction(); } } private void ProcessSearchChanges(InventoryGui gui) { if (_ui != null && _session != null) { string searchText = _ui.SearchText; if (!string.Equals(searchText, _lastSearch, StringComparison.Ordinal)) { _lastSearch = searchText; _session.SetSearchQuery(_lastSearch); _ui.RefreshContainerGrid(gui); } } } private void UpdateSearchFocusState() { _blockGameInput = _ui != null && _ui.IsSearchFocused; } private void TryProcessWorldChangeRefresh() { if (_trackedInventoryDirty && _session != null && _session.IsActive && !((Object)(object)InventoryGui.instance == (Object)null) && InventoryGui.IsVisible() && InventoryGui.instance.IsContainerOpen() && !(Time.unscaledTime < _nextAllowedWorldRefreshAt) && !ReflectionHelpers.IsDragInProgress()) { _nextAllowedWorldRefreshAt = Time.unscaledTime + 0.2f; _trackedInventoryDirty = false; ExecuteSessionRefresh(delegate { _session.RefreshFromWorldChange(); }); _ui?.UpdateMetaText(_session.SlotsUsedVirtual, _session.SlotsTotalPhysical, _session.ChestsInRange); _ui?.RefreshContainerGrid(InventoryGui.instance); } } private void ExecuteSessionRefresh(Action refreshAction) { if (_isApplyingRefresh) { return; } _isApplyingRefresh = true; try { refreshAction(); } finally { _isApplyingRefresh = false; } } } } namespace UnifiedStorage.Mod.UI { public sealed class TerminalUIManager { private const int VisibleGridRows = 7; private const float FooterPanelBottomOffset = -70f; private const float FooterPanelHeight = 52f; private const float GridTopReserve = 124f; private const float ChestToggleTopOffset = -8f; private RectTransform? _nativeUiRoot; private TMP_Text? _metaText; private Image? _slotBarFill; private TMP_InputField? _searchInputField; private RectTransform? _chestToggleRoot; private Toggle? _chestIncludeToggle; private RectTransform? _containerRect; private Container? _boundChestForToggle; private Vector2 _originalContainerSize; private int _originalGridHeight; private Vector2 _originalGridOffsetMin; private Vector2 _originalGridOffsetMax; private bool _layoutCaptured; private bool _nativeBuilt; private bool _isApplyingChestToggle; private int _lastAppliedVisibleRows; public bool IsSearchFocused { get { if ((Object)(object)_searchInputField != (Object)null) { return _searchInputField.isFocused; } return false; } } public string SearchText { get { TMP_InputField? searchInputField = _searchInputField; return ((searchInputField != null) ? searchInputField.text : null) ?? string.Empty; } } public bool IsLayoutCaptured => _layoutCaptured; public event Action<string>? SearchValueChanged; public event Action<bool>? ChestToggleChanged; public void EnsureNativeUi(InventoryGui gui) { //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Expected O, but got Unknown //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: 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) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) if (!_nativeBuilt) { RectTransform containerRect = ReflectionHelpers.GetContainerRect(gui); if (!((Object)(object)containerRect == (Object)null)) { _containerRect = containerRect; TMP_Text containerName = ReflectionHelpers.GetContainerName(gui); GameObject val = new GameObject("US_NativePanel", new Type[1] { typeof(RectTransform) }); val.transform.SetParent((Transform)(object)containerRect, false); _nativeUiRoot = val.GetComponent<RectTransform>(); _nativeUiRoot.anchorMin = new Vector2(0f, 0f); _nativeUiRoot.anchorMax = new Vector2(1f, 0f); _nativeUiRoot.pivot = new Vector2(0.5f, 0f); _nativeUiRoot.anchoredPosition = new Vector2(0f, -70f); _nativeUiRoot.sizeDelta = new Vector2(0f, 52f); BuildSlotBar(val.transform, containerName); BuildSearchField(val.transform, containerName); EnsureChestToggleUi(containerRect, containerName); _nativeBuilt = true; SetNativeUiVisible(visible: false); SetChestToggleVisible(visible: false); } } } private void BuildSlotBar(Transform parent, TMP_Text? containerName) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Expected O, but got Unknown //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Expected O, but got Unknown //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_0174: Unknown result type (might be due to invalid IL or missing references) //IL_01a4: Unknown result type (might be due to invalid IL or missing references) //IL_01df: Unknown result type (might be due to invalid IL or missing references) //IL_01e5: Expected O, but got Unknown //IL_01fe: Unknown result type (might be due to invalid IL or missing references) //IL_0209: Unknown result type (might be due to invalid IL or missing references) //IL_021e: Unknown result type (might be due to invalid IL or missing references) //IL_0232: Unknown result type (might be due to invalid IL or missing references) //IL_029d: Unknown result type (might be due to invalid IL or missing references) float num = 20f; GameObject val = new GameObject("US_SlotBarBg", new Type[2] { typeof(RectTransform), typeof(Image) }); val.transform.SetParent(parent, false); RectTransform component = val.GetComponent<RectTransform>(); component.anchorMin = new Vector2(0f, 1f); component.anchorMax = new Vector2(1f, 1f); component.pivot = new Vector2(0.5f, 1f); component.anchoredPosition = new Vector2(0f, 0f); component.sizeDelta = new Vector2(-16f, num); Image component2 = val.GetComponent<Image>(); ((Graphic)component2).color = new Color(0f, 0f, 0f, 0.55f); ((Graphic)component2).raycastTarget = false; GameObject val2 = new GameObject("US_SlotBarFill", new Type[2] { typeof(RectTransform), typeof(Image) }); val2.transform.SetParent(val.transform, false); RectTransform component3 = val2.GetComponent<RectTransform>(); component3.anchorMin = new Vector2(0f, 0f); component3.anchorMax = new Vector2(0f, 1f); component3.pivot = new Vector2(0f, 0.5f); component3.offsetMin = new Vector2(2f, 2f); component3.offsetMax = new Vector2(2f, -2f); _slotBarFill = val2.GetComponent<Image>(); ((Graphic)_slotBarFill).color = new Color(0.85f, 0.75f, 0.2f, 0.85f); ((Graphic)_slotBarFill).raycastTarget = false; GameObject val3 = new GameObject("US_SlotLabel", new Type[2] { typeof(RectTransform), typeof(TextMeshProUGUI) }); val3.transform.SetParent(val.transform, false); RectTransform component4 = val3.GetComponent<RectTransform>(); component4.anchorMin = Vector2.zero; component4.anchorMax = Vector2.one; component4.offsetMin = new Vector2(6f, 0f); component4.offsetMax = new Vector2(-6f, 0f); _metaText = (TMP_Text?)(object)val3.GetComponent<TextMeshProUGUI>(); if ((Object)(object)containerName != (Object)null) { _metaText.font = containerName.font; _metaText.fontSharedMaterial = containerName.fontSharedMaterial; } _metaText.fontSize = 14f; ((Graphic)_metaText).color = new Color(1f, 1f, 1f, 0.95f); _metaText.alignment = (TextAlignmentOptions)514; ((Graphic)_metaText).raycastTarget = false; } private void BuildSearchField(Transform parent, TMP_Text? containerName) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Expected O, but got Unknown //IL_0048: 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) //IL_0072: 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_0093: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Expected O, but got Unknown //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_0174: Expected O, but got Unknown //IL_0192: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Unknown result type (might be due to invalid IL or missing references) //IL_01b4: Unknown result type (might be due to invalid IL or missing references) //IL_01ca: Unknown result type (might be due to invalid IL or missing references) //IL_01f9: Unknown result type (might be due to invalid IL or missing references) //IL_01fe: Unknown result type (might be due to invalid IL or missing references) //IL_0211: Unknown result type (might be due to invalid IL or missing references) //IL_0218: Unknown result type (might be due to invalid IL or missing references) //IL_0223: Unknown result type (might be due to invalid IL or missing references) //IL_022e: Unknown result type (might be due to invalid IL or missing references) //IL_0238: Unknown result type (might be due to invalid IL or missing references) //IL_028e: Unknown result type (might be due to invalid IL or missing references) //IL_02c9: Unknown result type (might be due to invalid IL or missing references) //IL_02ce: Unknown result type (might be due to invalid IL or missing references) //IL_02e1: Unknown result type (might be due to invalid IL or missing references) //IL_02e8: Unknown result type (might be due to invalid IL or missing references) //IL_02f3: Unknown result type (might be due to invalid IL or missing references) //IL_02fe: Unknown result type (might be due to invalid IL or missing references) //IL_0308: Unknown result type (might be due to invalid IL or missing references) //IL_036a: Unknown result type (might be due to invalid IL or missing references) float num = 22f; float num2 = -24f; GameObject val = new GameObject("US_SearchRow", new Type[1] { typeof(RectTransform) }); val.transform.SetParent(parent, false); RectTransform component = val.GetComponent<RectTransform>(); component.anchorMin = new Vector2(0f, 1f); component.anchorMax = new Vector2(1f, 1f); component.pivot = new Vector2(0.5f, 1f); component.anchoredPosition = new Vector2(0f, num2); component.sizeDelta = new Vector2(-16f, num); GameObject val2 = new GameObject("US_SearchInput", new Type[3] { typeof(RectTransform), typeof(Image), typeof(TMP_InputField) }); val2.transform.SetParent(val.transform, false); RectTransform component2 = val2.GetComponent<RectTransform>(); component2.anchorMin = Vector2.zero; component2.anchorMax = Vector2.one; component2.offsetMin = Vector2.zero; component2.offsetMax = Vector2.zero; ((Graphic)val2.GetComponent<Image>()).color = new Color(0f, 0f, 0f, 0.5f); _searchInputField = val2.GetComponent<TMP_InputField>(); GameObject val3 = new GameObject("Viewport", new Type[2] { typeof(RectTransform), typeof(RectMask2D) }); val3.transform.SetParent(val2.transform, false); RectTransform component3 = val3.GetComponent<RectTransform>(); component3.anchorMin = Vector2.zero; component3.anchorMax = Vector2.one; component3.offsetMin = new Vector2(8f, 2f); component3.offsetMax = new Vector2(-8f, -2f); GameObject val4 = new GameObject("Text", new Type[2] { typeof(RectTransform), typeof(TextMeshProUGUI) }); val4.transform.SetParent(val3.transform, false); RectTransform component4 = val4.GetComponent<RectTransform>(); component4.anchorMin = Vector2.zero; component4.anchorMax = Vector2.one; component4.offsetMin = Vector2.zero; component4.offsetMax = Vector2.zero; TextMeshProUGUI component5 = val4.GetComponent<TextMeshProUGUI>(); if ((Object)(object)containerName != (Object)null) { ((TMP_Text)component5).font = containerName.font; ((TMP_Text)component5).fontSharedMaterial = containerName.fontSharedMaterial; } ((TMP_Text)component5).fontSize = 14f; ((Graphic)component5).color = new Color(1f, 1f, 1f, 0.9f); ((TMP_Text)component5).alignment = (TextAlignmentOptions)4097; GameObject val5 = new GameObject("Placeholder", new Type[2] { typeof(RectTransform), typeof(TextMeshProUGUI) }); val5.transform.SetParent(val3.transform, false); RectTransform component6 = val5.GetComponent<RectTransform>(); component6.anchorMin = Vector2.zero; component6.anchorMax = Vector2.one; component6.offsetMin = Vector2.zero; component6.offsetMax = Vector2.zero; TextMeshProUGUI component7 = val5.GetComponent<TextMeshProUGUI>(); ((TMP_Text)component7).text = "Search items..."; if ((Object)(object)containerName != (Object)null) { ((TMP_Text)component7).font = containerName.font; ((TMP_Text)component7).fontSharedMaterial = containerName.fontSharedMaterial; } ((TMP_Text)component7).fontSize = 13f; ((Graphic)component7).color = new Color(1f, 1f, 1f, 0.35f); ((TMP_Text)component7).alignment = (TextAlignmentOptions)4097; ((TMP_Text)component7).fontStyle = (FontStyles)2; _searchInputField.textViewport = component3; _searchInputField.textComponent = (TMP_Text)(object)component5; _searchInputField.placeholder = (Graphic)(object)component7; _searchInputField.lineType = (LineType)0; ((UnityEvent<string>)(object)_searchInputField.onValueChanged).AddListener((UnityAction<string>)delegate(string value) { this.SearchValueChanged?.Invoke(value ?? string.Empty); }); } private void EnsureChestToggleUi(RectTransform container, TMP_Text? containerName) { //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Expected O, but got Unknown //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Expected O, but got Unknown //IL_014d: Unknown result type (might be due to invalid IL or missing references) //IL_0162: Unknown result type (might be due to invalid IL or missing references) //IL_0177: Unknown result type (might be due to invalid IL or missing references) //IL_0182: 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_01bc: Unknown result type (might be due to invalid IL or missing references) //IL_01eb: Unknown result type (might be due to invalid IL or missing references) //IL_01f0: Unknown result type (might be due to invalid IL or missing references) //IL_0202: Unknown result type (might be due to invalid IL or missing references) //IL_0213: Unknown result type (might be due to invalid IL or missing references) //IL_0228: Unknown result type (might be due to invalid IL or missing references) //IL_023d: Unknown result type (might be due to invalid IL or missing references) //IL_0248: Unknown result type (might be due to invalid IL or missing references) //IL_025c: Unknown result type (might be due to invalid IL or missing references) //IL_0283: 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) //IL_02b7: Unknown result type (might be due to invalid IL or missing references) //IL_02c9: Unknown result type (might be due to invalid IL or missing references) //IL_02da: Unknown result type (might be due to invalid IL or missing references) //IL_02ef: Unknown result type (might be due to invalid IL or missing references) //IL_0304: Unknown result type (might be due to invalid IL or missing references) //IL_0319: Unknown result type (might be due to invalid IL or missing references) //IL_032d: Unknown result type (might be due to invalid IL or missing references) //IL_039d: Unknown result type (might be due to invalid IL or missing references) //IL_0376: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_chestToggleRoot != (Object)null) || !((Object)(object)_chestIncludeToggle != (Object)null)) { GameObject val = new GameObject("US_ChestIncludeToggle", new Type[2] { typeof(RectTransform), typeof(Toggle) }); val.transform.SetParent((Transform)(object)container, false); _chestToggleRoot = val.GetComponent<RectTransform>(); _chestToggleRoot.anchorMin = new Vector2(1f, 1f); _chestToggleRoot.anchorMax = new Vector2(1f, 1f); _chestToggleRoot.pivot = new Vector2(1f, 1f); _chestToggleRoot.anchoredPosition = new Vector2(-14f, -8f); _chestToggleRoot.sizeDelta = new Vector2(190f, 20f); Toggle component = val.GetComponent<Toggle>(); ((Selectable)component).transition = (Transition)0; component.isOn = true; _chestIncludeToggle = component; GameObject val2 = new GameObject("Background", new Type[2] { typeof(RectTransform), typeof(Image) }); val2.transform.SetParent(val.transform, false); RectTransform component2 = val2.GetComponent<RectTransform>(); component2.anchorMin = new Vector2(0f, 0.5f); component2.anchorMax = new Vector2(0f, 0.5f); component2.pivot = new Vector2(0f, 0.5f); component2.anchoredPosition = Vector2.zero; component2.sizeDelta = new Vector2(16f, 16f); Image component3 = val2.GetComponent<Image>(); ((Graphic)component3).color = new Color(0f, 0f, 0f, 0.62f); GameObject val3 = new GameObject("Checkmark", new Type[2] { typeof(RectTransform), typeof(Image) }); val3.transform.SetParent(val2.transform, false); RectTransform component4 = val3.GetComponent<RectTransform>(); component4.anchorMin = new Vector2(0.5f, 0.5f); component4.anchorMax = new Vector2(0.5f, 0.5f); component4.pivot = new Vector2(0.5f, 0.5f); component4.anchoredPosition = Vector2.zero; component4.sizeDelta = new Vector2(11f, 11f); Image component5 = val3.GetComponent<Image>(); ((Graphic)component5).color = new Color(0.82f, 0.93f, 0.66f, 1f); GameObject val4 = new GameObject("Label", new Type[2] { typeof(RectTransform), typeof(TextMeshProUGUI) }); val4.transform.SetParent(val.transform, false); RectTransform component6 = val4.GetComponent<RectTransform>(); component6.anchorMin = new Vector2(0f, 0.5f); component6.anchorMax = new Vector2(1f, 0.5f); component6.pivot = new Vector2(0f, 0.5f); component6.anchoredPosition = new Vector2(22f, 0f); component6.sizeDelta = new Vector2(-22f, 18f); TextMeshProUGUI component7 = val4.GetComponent<TextMeshProUGUI>(); ((TMP_Text)component7).text = "Include In Unified"; if ((Object)(object)containerName != (Object)null) { ((TMP_Text)component7).font = containerName.font; ((TMP_Text)component7).fontSize = containerName.fontSize * 0.52f; ((Graphic)component7).color = ((Graphic)containerName).color; ((TMP_Text)component7).fontSharedMaterial = containerName.fontSharedMaterial; } else { ((TMP_Text)component7).fontSize = 14f; ((Graphic)component7).color = Color.white; } ((TMP_Text)component7).alignment = (TextAlignmentOptions)4097; ((Selectable)component).targetGraphic = (Graphic)(object)component3; component.graphic = (Graphic)(object)component5; ((UnityEvent<bool>)(object)component.onValueChanged).AddListener((UnityAction<bool>)OnChestIncludeToggleChanged); } } public void UpdateChestInclusionToggle(InventoryGui gui) { if ((Object)(object)_chestToggleRoot == (Object)null || (Object)(object)_chestIncludeToggle == (Object)null || !InventoryGui.IsVisible() || !gui.IsContainerOpen()) { _boundChestForToggle = null; SetChestToggleVisible(visible: false); return; } Container currentContainer = ReflectionHelpers.GetCurrentContainer(gui); if ((Object)(object)currentContainer == (Object)null || UnifiedTerminal.IsTerminal(currentContainer)) { _boundChestForToggle = null; SetChestToggleVisible(visible: false); return; } SetChestToggleVisible(visible: true); bool flag = ChestInclusionRules.IsIncludedInUnified(currentContainer); if (_boundChestForToggle != currentContainer || _chestIncludeToggle.isOn != flag) { _isApplyingChestToggle = true; _chestIncludeToggle.isOn = flag; _isApplyingChestToggle = false; _boundChestForToggle = currentContainer; } } private void OnChestIncludeToggleChanged(bool includeInUnified) { if (!_isApplyingChestToggle) { InventoryGui instance = InventoryGui.instance; Container val = (((Object)(object)instance != (Object)null) ? ReflectionHelpers.GetCurrentContainer(instance) : null); if (!((Object)(object)val == (Object)null) && !UnifiedTerminal.IsTerminal(val)) { ChestInclusionRules.TrySetIncludedInUnified(val, includeInUnified); this.ChestToggleChanged?.Invoke(includeInUnified); } } } public void UpdateContainerName(InventoryGui gui) { TMP_Text containerName = ReflectionHelpers.GetContainerName(gui); if ((Object)(object)containerName != (Object)null && !string.Equals(containerName.text, "Storage Interface", StringComparison.Ordinal)) { containerName.text = "Storage Interface"; } } public void UpdateMetaText(int slotsUsed, int slotsTotal, int chestCount) { //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_metaText != (Object)null) { _metaText.text = $"{slotsUsed} / {slotsTotal}"; } if ((Object)(object)_slotBarFill != (Object)null) { float num = ((slotsTotal > 0) ? Mathf.Clamp01((float)slotsUsed / (float)slotsTotal) : 0f); Transform parent = ((Component)_slotBarFill).transform.parent; RectTransform val = (RectTransform)(object)((parent is RectTransform) ? parent : null); float num2; if (!((Object)(object)val != (Object)null)) { num2 = 100f; } else { Rect rect = val.rect; num2 = ((Rect)(ref rect)).width - 4f; } float num3 = num2; ((Component)_slotBarFill).GetComponent<RectTransform>().sizeDelta = new Vector2(num3 * num, 0f); if (num >= 0.95f) { ((Graphic)_slotBarFill).color = new Color(0.85f, 0.25f, 0.2f, 0.85f); } else if (num >= 0.75f) { ((Graphic)_slotBarFill).color = new Color(0.9f, 0.6f, 0.15f, 0.85f); } else { ((Graphic)_slotBarFill).color = new Color(0.85f, 0.75f, 0.2f, 0.85f); } } } public void UpdateSearchBinding(InventoryGui gui) { if (!((Object)(object)_searchInputField == (Object)null) && _searchInputField.isFocused && (Input.GetKeyDown((KeyCode)13) || Input.GetKeyDown((KeyCode)271) || Input.GetKeyDown((KeyCode)27))) { _searchInputField.DeactivateInputField(false); } } public void ClearSearch() { if ((Object)(object)_searchInputField != (Object)null) { _searchInputField.text = string.Empty; } } public void ApplyExpandedLayout(InventoryGui gui, int contentRows) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_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) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_containerRect == (Object)null) { return; } InventoryGrid containerGrid = ReflectionHelpers.GetContainerGrid(gui); if ((Object)(object)containerGrid == (Object)null) { return; } if (!_layoutCaptured) { _originalContainerSize = _containerRect.sizeDelta; _originalGridHeight = ReflectionHelpers.GetGridHeight(containerGrid); RectTransform gridRoot = ReflectionHelpers.GetGridRoot(containerGrid); if ((Object)(object)gridRoot != (Object)null) { _originalGridOffsetMin = gridRoot.offsetMin; _originalGridOffsetMax = gridRoot.offsetMax; } _layoutCaptured = true; _lastAppliedVisibleRows = -1; } int num = Math.Max(1, Math.Min(contentRows, 7)); if (num != _lastAppliedVisibleRows) { _lastAppliedVisibleRows = num; ReflectionHelpers.SetGridHeight(containerGrid, num); float gridElementSpace = ReflectionHelpers.GetGridElementSpace(containerGrid); GameObject gridElementPrefab = ReflectionHelpers.GetGridElementPrefab(containerGrid); float num2 = 64f; RectTransform val = default(RectTransform); if ((Object)(object)gridElementPrefab != (Object)null && gridElementPrefab.TryGetComponent<RectTransform>(ref val)) { num2 = val.sizeDelta.y; } int num3 = Math.Max(0, num - _originalGridHeight); float num4 = (num2 + gridElementSpace) * (float)num3; _containerRect.sizeDelta = new Vector2(_originalContainerSize.x, _originalContainerSize.y + num4); RectTransform gridRoot2 = ReflectionHelpers.GetGridRoot(containerGrid); if ((Object)(object)gridRoot2 != (Object)null) { gridRoot2.offsetMax = new Vector2(_originalGridOffsetMax.x, -124f); gridRoot2.offsetMin = _originalGridOffsetMin; } } } public void RestoreLayout() { //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) if (!_layoutCaptured || (Object)(object)InventoryGui.instance == (Object)null) { return; } InventoryGrid containerGrid = ReflectionHelpers.GetContainerGrid(InventoryGui.instance); if ((Object)(object)containerGrid != (Object)null) { ReflectionHelpers.SetGridHeight(containerGrid, _originalGridHeight); RectTransform gridRoot = ReflectionHelpers.GetGridRoot(containerGrid); if ((Object)(object)gridRoot != (Object)null) { gridRoot.offsetMin = _originalGridOffsetMin; gridRoot.offsetMax = _originalGridOffsetMax; } Inventory inventory = containerGrid.GetInventory(); if (inventory != null) { containerGrid.UpdateInventory(inventory, Player.m_localPlayer, (ItemData)null); } } if ((Object)(object)_containerRect != (Object)null) { _containerRect.sizeDelta = _originalContainerSize; } _layoutCaptured = false; _lastAppliedVisibleRows = -1; } public void RefreshContainerGrid(InventoryGui gui) { InventoryGrid containerGrid = ReflectionHelpers.GetContainerGrid(gui); if (!((Object)(object)containerGrid == (Object)null)) { Inventory inventory = containerGrid.GetInventory(); if (inventory != null) { containerGrid.UpdateInventory(inventory, Player.m_localPlayer, (ItemData)null); } } } public void SetNativeUiVisible(bool visible) { if ((Object)(object)_nativeUiRoot != (Object)null) { ((Component)_nativeUiRoot).gameObject.SetActive(visible); } } public void SetChestToggleVisible(bool visible) { if ((Object)(object)_chestToggleRoot != (Object)null) { ((Component)_chestToggleRoot).gameObject.SetActive(visible); } } public void SetTakeAllButtonEnabled(InventoryGui gui, bool enabled) { Button takeAllButton = ReflectionHelpers.GetTakeAllButton(gui); if ((Object)(object)takeAllButton != (Object)null) { ((Selectable)takeAllButton).interactable = enabled; } } public void Reset() { ClearSearch(); _boundChestForToggle = null; SetNativeUiVisible(visible: false); SetChestToggleVisible(visible: false); RestoreLayout(); } } } namespace UnifiedStorage.Mod.Shared { public static class ReflectionHelpers { private static readonly FieldInfo? InventoryWidthField = typeof(Inventory).GetField("m_width", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); private static readonly FieldInfo? InventoryHeightField = typeof(Inventory).GetField("m_height", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); private static readonly MethodInfo? InventoryGetWidthMethod = typeof(Inventory).GetMethod("GetWidth", BindingFlags.Instance | BindingFlags.Public); private static readonly MethodInfo? InventoryGetHeightMethod = typeof(Inventory).GetMethod("GetHeight", BindingFlags.Instance | BindingFlags.Public); private static readonly MethodInfo? ContainerCheckAccessMethod = typeof(Container).GetMethod("CheckAccess", BindingFlags.Instance | BindingFlags.Public); private static readonly FieldInfo? ContainerNameField = typeof(Container).GetField("m_name", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); private static readonly MethodInfo? ContainerSetInUseMethod = typeof(Container).GetMethod("SetInUse", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(bool) }, null); private static readonly FieldInfo? ContainerInUseField = typeof(Container).GetField("m_inUse", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); private static readonly FieldInfo? DragItemField = typeof(InventoryGui).GetField("m_dragItem", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); private static readonly FieldInfo? ContainerRectField = AccessTools.Field(typeof(InventoryGui), "m_container"); private static readonly FieldInfo? CurrentContainerField = AccessTools.Field(typeof(InventoryGui), "m_currentContainer"); private static readonly FieldInfo? ContainerGridField = AccessTools.Field(typeof(InventoryGui), "m_containerGrid"); private static readonly FieldInfo? ContainerNameTextField = AccessTools.Field(typeof(InventoryGui), "m_containerName"); private static readonly FieldInfo? TakeAllButtonField = AccessTools.Field(typeof(InventoryGui), "m_takeAllButton"); private static readonly FieldInfo? GridRootField = AccessTools.Field(typeof(InventoryGrid), "m_gridRoot"); private static readonly FieldInfo? GridHeightField = AccessTools.Field(typeof(InventoryGrid), "m_height"); private static readonly FieldInfo? GridElementPrefabField = AccessTools.Field(typeof(InventoryGrid), "m_elementPrefab"); private static readonly FieldInfo? GridElementSpaceField = AccessTools.Field(typeof(InventoryGrid), "m_elementSpace"); private static readonly FieldInfo? InventoryItemListField = AccessTools.Field(typeof(Inventory), "m_inventory"); private static readonly MethodInfo? InventoryChangedMethod = typeof(Inventory).GetMethod("Changed", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); private static readonly MethodInfo?[] DropItemMethods = (from m in typeof(ItemDrop).GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic) where string.Equals(m.Name, "DropItem", StringComparison.Ordinal) select m).ToArray(); public static int GetInventoryWidth(Inventory inventory) { object obj; if (InventoryGetWidthMethod != null) { obj = InventoryGetWidthMethod.Invoke(inventory, null); if (obj is int) { return (int)obj; } } obj = InventoryWidthField?.GetValue(inventory); if (obj is int) { return (int)obj; } return 1; } public static int GetInventoryHeight(Inventory inventory) { object obj; if (InventoryGetHeightMethod != null) { obj = InventoryGetHeightMethod.Invoke(inventory, null); if (obj is int) { return (int)obj; } } obj = InventoryHeightField?.GetValue(inventory); if (obj is int) { return (int)obj; } return 1; } public static void SetInventorySize(Inventory inventory, int width, int height) { InventoryWidthField?.SetValue(inventory, width); InventoryHeightField?.SetValue(inventory, height); } public static bool CanAccess(Container container, Player player) { if (ContainerCheckAccessMethod == null) { return true; } ParameterInfo[] parameters = ContainerCheckAccessMethod.GetParameters(); if (parameters.Length == 1 && parameters[0].ParameterType == typeof(long)) { return (bool)ContainerCheckAccessMethod.Invoke(container, new object[1] { player.GetPlayerID() }); } if (parameters.Length == 0) { return (bool)ContainerCheckAccessMethod.Invoke(container, null); } return true; } public static void SetContainerDisplayName(Container container, string displayName) { if (ContainerNameField?.FieldType == typeof(string)) { ContainerNameField.SetValue(container, displayName); } } public static void ForceReleaseContainerUse(Container container) { try { ContainerSetInUseMethod?.Invoke(container, new object[1] { false }); } catch { } try { if (ContainerInUseField?.FieldType == typeof(bool)) { ContainerInUseField.SetValue(container, false); } } catch { } } public static string BuildContainerUid(Container container) { ZNetView component = ((Component)container).GetComponent<ZNetView>(); ZDO val = ((component != null) ? component.GetZDO() : null); if (val == null) { return ((Object)container).GetInstanceID().ToString(); } return ((object)(ZDOID)(ref val.m_uid)).ToString(); } public static bool MatchKey(ItemData item, ItemKey key) { if ((Object)(object)item?.m_dropPrefab != (Object)null && ((Object)item.m_dropPrefab).name == ((ItemKey)(ref key)).PrefabName && item.m_quality == ((ItemKey)(ref key)).Quality && item.m_variant == ((ItemKey)(ref key)).Variant) { return item.m_stack > 0; } return false; } public static int GetTotalAmount(Inventory inventory, ItemKey key) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) int num = 0; foreach (ItemData allItem in inventory.GetAllItems()) { if (MatchKey(allItem, key)) { num += allItem.m_stack; } } return num; } public static int TryAddItemMeasured(Inventory inventory, ItemKey key, ItemData stack, int requestedAmount) { //IL_0001: 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) int totalAmount = GetTotalAmount(inventory, key); inventory.AddItem(stack); int totalAmount2 = GetTotalAmount(inventory, key); return ChunkedTransfer.ClampMeasuredMove(requestedAmount, totalAmount, totalAmount2); } public static ItemData? CreateItemStack(ItemKey key, int amount) { ObjectDB instance = ObjectDB.instance; GameObject obj = ((instance != null) ? instance.GetItemPrefab(((ItemKey)(ref key)).PrefabName) : null); ItemDrop val = ((obj != null) ? obj.GetComponent<ItemDrop>() : null); if (val?.m_itemData == null) { return null; } ItemData obj2 = val.m_itemData.Clone(); obj2.m_quality = ((ItemKey)(ref key)).Quality; obj2.m_variant = ((ItemKey)(ref key)).Variant; obj2.m_stack = amount; return obj2; } public static int GetMaxStackSize(ItemKey key) { ObjectDB instance = ObjectDB.instance; GameObject obj = ((instance != null) ? instance.GetItemPrefab(((ItemKey)(ref key)).PrefabName) : null); return (((obj != null) ? obj.GetComponent<ItemDrop>() : null)?.m_itemData?.m_shared?.m_maxStackSize).GetValueOrDefault(1); } public static int ResolveMaxStackSize(string prefabName) { ObjectDB instance = ObjectDB.instance; GameObject obj = ((instance != null) ? instance.GetItemPrefab(prefabName) : null); return (((obj != null) ? obj.GetComponent<ItemDrop>() : null)?.m_itemData?.m_shared?.m_maxStackSize).GetValueOrDefault(1); } public static bool TryDropItem(ItemData item, int amount, Vector3 position, Quaternion rotation) { //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) MethodInfo[] dropItemMethods = DropItemMethods; foreach (MethodInfo methodInfo in dropItemMethods) { if (methodInfo == null) { continue; } ParameterInfo[] parameters = methodInfo.GetParameters(); try { if (parameters.Length == 4 && parameters[0].ParameterType == typeof(ItemData) && parameters[1].ParameterType == typeof(int) && parameters[2].ParameterType == typeof(Vector3) && parameters[3].ParameterType == typeof(Quaternion)) { methodInfo.Invoke(null, new object[4] { item, amount, position, rotation }); return true; } if (parameters.Length == 3 && parameters[0].ParameterType == typeof(ItemData) && parameters[1].ParameterType == typeof(int) && parameters[2].ParameterType == typeof(Vector3)) { methodInfo.Invoke(null, new object[3] { item, amount, position }); return true; } } catch { } } return false; } public static int GetSubgroupOrder(ItemKey key) { if (string.IsNullOrWhiteSpace(((ItemKey)(ref key)).PrefabName)) { return 999; } string text = ((ItemKey)(ref key)).PrefabName.ToLowerInvariant(); if (text.Contains("ore") || text.Contains("scrap") || text.Contains("metal") || text.Contains("ingot") || text.Contains("bar")) { return 10; } if (text.Contains("wood") || text.Contains("stone")) { return 20; } if (text.Contains("hide") || text.Contains("leather") || text.Contains("scale") || text.Contains("chitin")) { return 30; } if (text.Contains("food") || text.Contains("mead") || text.Contains("stew") || text.Contains("soup") || text.Contains("bread")) { return 40; } return 100; } public static List<ItemData>? GetInventoryItemList(Inventory inventory) { return InventoryItemListField?.GetValue(inventory) as List<ItemData>; } public static void AddItemDirectly(Inventory inventory, ItemData item, int x, int y) { //IL_0003: 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) item.m_gridPos = new Vector2i(x, y); List<ItemData> inventoryItemList = GetInventoryItemList(inventory); if (inventoryItemList != null) { inventoryItemList.Add(item); } else { inventory.AddItem(item); } } public static void NotifyInventoryChanged(Inventory inventory) { InventoryChangedMethod?.Invoke(inventory, null); } public static void ClearInventory(Inventory? inventory) { if (inventory == null) { return; } MethodInfo method = typeof(Inventory).GetMethod("RemoveAll", BindingFlags.Instance | BindingFlags.Public); if (method != null) { method.Invoke(inventory, null); return; } foreach (ItemData item in inventory.GetAllItems().ToList()) { inventory.RemoveItem(item, item.m_stack); } } public static bool IsDragInProgress() { if ((Object)(object)InventoryGui.instance == (Object)null || DragItemField == null) { return false; } object? value = DragItemField.GetValue(InventoryGui.instance); ItemData val = (ItemData)((value is ItemData) ? value : null); if (val != null) { return val.m_stack > 0; } return false; } public static RectTransform? GetContainerRect(InventoryGui gui) { object? obj = ContainerRectField?.GetValue(gui); return (RectTransform?)((obj is RectTransform) ? obj : null); } public static Container? GetCurrentContainer(InventoryGui gui) { object? obj = CurrentContainerField?.GetValue(gui); return (Container?)((obj is Container) ? obj : null); } public static InventoryGrid? GetContainerGrid(InventoryGui gui) { object? obj = ContainerGridField?.GetValue(gui); return (InventoryGrid?)((obj is InventoryGrid) ? obj : null); } public static TMP_Text? GetContainerName(InventoryGui gui) { object? obj = ContainerNameTextField?.GetValue(gui); return (TMP_Text?)((obj is TMP_Text) ? obj : null); } public static Button? GetTakeAllButton(InventoryGui gui) { object? obj = TakeAllButtonField?.GetValue(gui); return (Button?)((obj is Button) ? obj : null); } public static RectTransform? GetGridRoot(InventoryGrid grid) { object? obj = GridRootField?.GetValue(grid); return (RectTransform?)((obj is RectTransform) ? obj : null); } public static int GetGridHeight(InventoryGrid grid) { object obj = GridHeightField?.GetValue(grid); if (obj is int) { return (int)obj; } return 4; } public static void SetGridHeight(InventoryGrid grid, int height) { GridHeightField?.SetValue(grid, height); } public static float GetGridElementSpace(InventoryGrid grid) { object obj = GridElementSpaceField?.GetValue(grid); if (obj is float) { return (float)obj; } return 2f; } public static GameObject? GetGridElementPrefab(InventoryGrid grid) { object? obj = GridElementPrefabField?.GetValue(grid); return (GameObject?)((obj is GameObject) ? obj : null); } } } namespace UnifiedStorage.Mod.Session { public sealed class TerminalSessionService { private sealed class PendingReservation { public string TokenId { get; set; } = string.Empty; public ItemKey Key { get; set; } public int ReservedAmount { get; set; } public float ExpiresAt { get; set; } public bool CommitRequested { get; set; } } private sealed class PendingDeposit { public string RequestId { get; set; } = string.Empty; public ItemKey Key { get; set; } public int Amount { get; set; } } private struct CachedSortEntry { public string DisplayName; public int TypeOrder; public int SubgroupOrder; } private const float CloseGraceSeconds = 0.35f; private const float ReservationTtlSeconds = 3f; private const float TrackedChestRefreshSeconds = 1f; private const float OpenSessionRetryBaseSeconds = 0.5f; private const float OpenSessionRetryMaxSeconds = 8f; private readonly StorageConfig _config; private readonly IContainerScanner _scanner; private readonly TerminalRpcRoutes _routes; private readonly ManualLogSource _logger; private readonly StorageTrace _trace; private readonly Dictionary<ItemKey, int> _authoritativeTotals = new Dictionary<ItemKey, int>(); private readonly Dictionary<ItemKey, int> _displayedTotals = new Dictionary<ItemKey, int>(); private readonly Dictionary<ItemKey, ItemData> _prototypes = new Dictionary<ItemKey, ItemData>(); private readonly Dictionary<ItemKey, int> _stackSizes = new Dictionary<ItemKey, int>(); private readonly List<PendingReservation> _pendingReservations = new List<PendingReservation>(); private readonly List<PendingDeposit> _pendingDeposits = new List<PendingDeposit>(); private readonly Dictionary<ItemKey, CachedSortEntry> _sortCache = new Dictionary<ItemKey, CachedSortEntry>(); private List<KeyValuePair<ItemKey, int>> _sortedItems = new List<KeyValuePair<ItemKey, int>>(); private long _lastProjectedContentHash; private Container? _terminal; private Player? _player; private List<ChestHandle> _trackedChests = new List<ChestHandle>(); private string _sessionId = string.Empty; private string _terminalUid = string.Empty; private string _searchQuery = string.Empty; private float _scanRadius; private float _pendingCloseSince = -1f; private float _nextTrackedChestRefreshAt; private float _nextSnapshotRetryAt; private bool _isApplyingProjection; private bool _hasAuthoritativeSnapshot; private int _slotsTotalPhysical; private int _chestCount; private long _revision; private int _openSessionFailureCount; private int _originalInventoryWidth; private int _originalInventoryHeight; private int _contentRows; private int _uiRevision; public bool IsActive { get { if ((Object)(object)_terminal != (Object)null) { return (Object)(object)_player != (Object)null; } return false; } } public bool IsApplyingProjection => _isApplyingProjection; public int SlotsTotalPhysical => _slotsTotalPhysical; public int ChestsInRange => _chestCount; public int UiRevision => _uiRevision; public int ContentRows => _contentRows; public bool IsStorageFull { get { if (_slotsTotalPhysical > 0) { return SlotsUsedVirtual >= _slotsTotalPhysical; } return false; } } public int SlotsUsedVirtual { get { //IL_002a: Unknown result type (might be due to invalid IL or missing references) int num = 0; foreach (KeyValuePair<ItemKey, int> authoritativeTotal in _authoritativeTotals) { if (authoritativeTotal.Value > 0) { int value; int num2 = ((!_stackSizes.TryGetValue(authoritativeTotal.Key, out value) || value <= 0) ? 1 : value); num += (int)Math.Ceiling((double)authoritativeTotal.Value / (double)num2); } } return num; } } public TerminalSessionService(StorageConfig config, IContainerScanner scanner, TerminalRpcRoutes routes, ManualLogSource logger, StorageTrace trace) { _config = config; _scanner = scanner; _routes = routes; _logger = logger; _trace = trace; _routes.SessionSnapshotReceived += OnSessionSnapshotReceived; _routes.ReserveResultReceived += OnReserveResultReceived; _routes.ApplyResultReceived += OnApplyResultReceived; _routes.SessionDeltaReceived += OnSessionDeltaReceived; } public bool IsTerminalInventory(Inventory inventory) { if (!IsActive || (Object)(object)_terminal == (Object)null || inventory == null) { return false; } return inventory == _terminal.GetInventory(); } public bool IsTrackedInventory(Inventory inventory) { Inventory inventory2 = inventory; if (!IsActive || inventory2 == null || (Object)(object)_terminal == (Object)null) { return false; } Inventory inventory3 = _terminal.GetInventory(); if (inventory2 == inventory3) { return false; } return _trackedChests.Any((ChestHandle chest) => inventory2 == chest.Container.GetInventory()); } public bool HandleContainerInteract(Container container, Player player) { if (!UnifiedTerminal.IsTerminal(container)) { return false; } BeginSession(container, player); return true; } public void BeginSession(Container terminal, Player player) { EndSession(); ReflectionHelpers.ForceReleaseContainerUse(terminal); _terminal = terminal; _player = player; _searchQuery = string.Empty; _sessionId = string.Empty; _terminalUid = ReflectionHelpers.BuildContainerUid(terminal); _pendingCloseSince = -1f; _scanRadius = ((_config.TerminalRangeOverride.Value > 0f) ? _config.TerminalRangeOverride.Value : _config.ScanRadius.Value); CaptureOriginalInventorySize(terminal.GetInventory()); _revision = 0L; _slotsTotalPhysical = 0; _chestCount = 0; _hasAuthoritativeSnapshot = false; _openSessionFailureCount = 0; _nextSnapshotRetryAt = Time.unscaledTime; _pendingReservations.Clear(); _pendingDeposits.Clear(); _authoritativeTotals.Clear(); _displayedTotals.Clear(); _prototypes.Clear(); _stackSizes.Clear(); StorageTrace trace = _trace; Player? player2 = _player; trace.Dev(string.Format("Terminal opened by {0} (radius {1:0.0}m).", ((player2 != null) ? player2.GetPlayerName() : null) ?? "unknown", _scanRadius)); RefreshTrackedChestHandles(); RefreshTerminalInventoryFromAuthoritative(); RequestSessionSnapshot(); _uiRevision++; } public void Tick() { if (!IsActive || (Object)(object)_terminal == (Object)null) { return; } if ((Object)(object)InventoryGui.instance == (Object)null || !InventoryGui.IsVisible() || !InventoryGui.instance.IsContainerOpen()) { if (_pendingCloseSince < 0f) { _pendingCloseSince = Time.unscaledTime; } else if (Time.unscaledTime - _pendingCloseSince >= 0.35f) { EndSession(); } return; } _pendingCloseSince = -1f; if (Time.unscaledTime >= _nextTrackedChestRefreshAt) { RefreshTrackedChestHandles(); } if (!_hasAuthoritativeSnapshot && Time.unscaledTime >= _nextSnapshotRetryAt) { RequestSessionSnapshot(); } ExpireLocalReservations(); if (!ReflectionHelpers.IsDragInProgress()) { CommitPendingReservations(); } } public void SetSearchQuery(string query) { if (IsActive && !((Object)(object)_terminal == (Object)null)) { string text = query?.Trim() ?? string.Empty; if (!string.Equals(text, _searchQuery, StringComparison.Ordinal)) { _searchQuery = text; _lastProjectedContentHash = 0L; RefreshTerminalInventoryFromAuthoritative(); _uiRevision++; } } } public void NotifyContainerInteraction() { if (!IsActive || (Object)(object)_terminal == (Object)null) { return; } if (!IsSessionTerminal(_terminal)) { EndSession(); return; } Dictionary<ItemKey, int> dictionary = CaptureCurrentDisplayedTotals(); ApplyDisplayedDeltaAsOperations(dictionary); ReplaceDisplayedTotals(dictionary); if (!ReflectionHelpers.IsDragInProgress()) { CommitPendingReservations(); } } public void RefreshFromWorldChange() { if (IsActive && !((Object)(object)_terminal == (Object)null)) { if (!IsSessionTerminal(_terminal)) { EndSession(); } else { RequestSessionSnapshot(); } } } public void EndSession() { if (IsActive) { _trace.Dev("Terminal closed."); } if ((Object)(object)_terminal != (Object)null && !string.IsNullOrWhiteSpace(_terminalUid)) { _routes.RequestCloseSession(new CloseSessionRequestDto { RequestId = Guid.NewGuid().ToString("N"), SessionId = _sessionId, TerminalUid = _terminalUid, PlayerId = ResolveLocalPlayerId() }); } if ((Object)(object)_terminal != (Object)null) { ReflectionHelpers.ForceReleaseContainerUse(_terminal); ReflectionHelpers.ClearInventory(_terminal.GetInventory()); RestoreTerminalInventorySize(_terminal.GetInventory()); } _terminal = null; _player = null; _trackedChests.Clear(); _sessionId = string.Empty; _terminalUid = string.Empty; _searchQuery = string.Empty; _scanRadius = 0f; _pendingCloseSince = -1f; _nextTrackedChestRefreshAt = 0f; _nextSnapshotRetryAt = 0f; _pendingReservations.Clear(); _pendingDeposits.Clear(); _authoritativeTotals.Clear(); _displayedTotals.Clear(); _prototypes.Clear(); _stackSizes.Clear(); _sortCache.Clear(); _sortedItems.Clear(); _lastProjectedContentHash = 0L; _slotsTotalPhysical = 0; _chestCount = 0; _revision = 0L; _hasAuthoritativeSnapshot = false; _openSessionFailureCount = 0; _contentRows = 0; _uiRevision++; } private void OnSessionSnapshotReceived(OpenSessionResponseDto response) { if (!IsActive) { return; } if (!response.Success) { if (IsIdentityFailure(response.Reason)) { EndSession(); return; } _openSessionFailureCount = Math.Min(_openSessionFailureCount + 1, 8); _nextSnapshotRetryAt = Time.unscaledTime + GetRetryDelay(_openSessionFailureCount); } else if (CanApplySnapshot(response.Snapshot)) { ApplySnapshot(response.Snapshot); } } private void OnReserveResultReceived(ReserveWithdrawResultDto result) { //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) if (IsActive && CanApplySnapshot(result.Snapshot)) { if (result.Success && !string.IsNullOrWhiteSpace(result.TokenId) && result.ReservedAmount > 0) { _trace.Dev($"Withdrew {result.ReservedAmount}x {GetDisplayName(result.Key)}."); _pendingReservations.Add(new PendingReservation { TokenId = result.TokenId, Key = result.Key, ReservedAmount = result.ReservedAmount, ExpiresAt = Time.unscaledTime + 3f }); } ApplySnapshot(result.Snapshot); } } private void OnApplyResultReceived(ApplyResultDto result) { if (!IsActive) { return; } if (string.Equals(result.OperationType, "deposit", StringComparison.Ordinal)) { HandleDepositResult(result); } if (string.Equals(result.OperationType, "commit", StringComparison.Ordinal)) { if (result.Success) { RemovePendingToken(result.TokenId); } else { MarkPendingCommitAsRetryable(result.TokenId); RequestSessionSnapshot(); } } else if (string.Equals(result.OperationType, "cancel", StringComparison.Ordinal) && !result.Success) { RemovePendingToken(result.TokenId); RequestSessionSnapshot(); } if (CanApplySnapshot(result.Snapshot)) { ApplySnapshot(result.Snapshot); } else if (!result.Success) { RequestSessionSnapshot(); } } private void OnSessionDeltaReceived(SessionDeltaDto delta) { if (IsActive && string.Equals(delta.TerminalUid, _terminalUid, StringComparison.Ordinal) && (string.IsNullOrWhiteSpace(delta.SessionId) || string.IsNullOrWhiteSpace(_sessionId) || string.Equals(delta.SessionId, _sessionId, StringComparison.Ordinal)) && delta.Revision >= _revision) { ApplySnapshot(delta.Snapshot); } } private bool CanApplySnapshot(SessionSnapshotDto snapshot) { if (!IsActive || (Object)(object)_terminal == (Object)null) { return false; } if (!string.Equals(snapshot.TerminalUid, _terminalUid, StringComparison.Ordinal)) { return false; } if (!string.IsNullOrWhiteSpace(snapshot.SessionId) && !string.IsNullOrWhiteSpace(_sessionId) && !string.Equals(snapshot.SessionId, _sessionId, StringComparison.Ordinal)) { return false; } return true; } private void ApplySnapshot(SessionSnapshotDto snapshot) { //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Unknown result type (might be due to invalid IL or missing references) if (!CanApplySnapshot(snapshot) || snapshot.Revision < _revision) { return; } if (!string.IsNullOrWhiteSpace(snapshot.SessionId)) { _sessionId = snapshot.SessionId; } _revision = snapshot.Revision; _slotsTotalPhysical = snapshot.SlotsTotalPhysical; _chestCount = snapshot.ChestCount; _hasAuthoritativeSnapshot = true; _openSessionFailureCount = 0; _nextSnapshotRetryAt = Time.unscaledTime + 60f; int count = _authoritativeTotals.Count; _authoritativeTotals.Clear(); _stackSizes.Clear(); foreach (AggregatedItem item in snapshot.Items) { if (item.TotalAmount <= 0) { continue; } _authoritativeTotals[item.Key] = item.TotalAmount; _stackSizes[item.Key] = ((item.StackSize <= 0) ? 1 : item.StackSize); if (!_prototypes.ContainsKey(item.Key)) { ObjectDB instance = ObjectDB.instance; object obj; ItemKey key; if (instance == null) { obj = null; } else { key = item.Key; obj = instance.GetItemPrefab(((ItemKey)(ref key)).PrefabName); } ItemDrop val = ((obj != null) ? ((GameObject)obj).GetComponent<ItemDrop>() : null); if (val?.m_itemData != null) { ItemData val2 = val.m_itemData.Clone(); key = item.Key; val2.m_quality = ((ItemKey)(ref key)).Quality; key = item.Key; val2.m_variant = ((ItemKey)(ref key)).Variant; _prototypes[item.Key] = val2; } } } if (_authoritativeTotals.Count != count) { _sortCache.Clear(); } _trace.Dev($"Storage updated: {_chestCount} chest(s), {_authoritativeTotals.Count} item type(s)."); RefreshTrackedChestHandles(); RefreshTerminalInventoryFromAuthoritative(); _uiRevision++; } private void RefreshTerminalInventoryFromAuthoritative() { //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_0167: Unknown result type (might be due to invalid IL or missing references) //IL_01ad: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_terminal == (Object)null) { return; } Inventory inventory = _terminal.GetInventory(); if (inventory == null) { return; } long num = ComputeContentHash(); if (num == _lastProjectedContentHash) { return; } _lastProjectedContentHash = num; _isApplyingProjection = true; try { ReflectionHelpers.ClearInventory(inventory); _displayedTotals.Clear(); int num2 = Math.Max(1, ReflectionHelpers.GetInventoryWidth(inventory)); RebuildSortedItems(); int num3 = 0; foreach (KeyValuePair<ItemKey, int> sortedItem in _sortedItems) { int value; int num4 = ((!_stackSizes.TryGetValue(sortedItem.Key, out value) || value <= 0) ? 1 : value); num3 += (int)Math.Ceiling((double)sortedItem.Value / (double)num4); } int num5 = ((_slotsTotalPhysical > SlotsUsedVirtual) ? 1 : 0); int num6 = Math.Max(1, num3 + num5); _contentRows = Math.Max(1, (int)Math.Ceiling((float)num6 / (float)num2)); ReflectionHelpers.SetInventorySize(inventory, num2, _contentRows); int num7 = 0; foreach (KeyValuePair<ItemKey, int> sortedItem2 in _sortedItems) { int num8 = sortedItem2.Value; int value2; int num9 = ((!_stackSizes.TryGetValue(sortedItem2.Key, out value2) || value2 <= 0) ? 1 : value2); while (num8 > 0) { int num10 = Math.Min(num9, num8); ItemData val = CreateProjectedItem(sortedItem2.Key, num10, num9); if (val == null) { break; } int x = num7 % num2; int y = num7 / num2; ReflectionHelpers.AddItemDirectly(inventory, val, x, y); num7++; num8 -= num10; } _displayedTotals[sortedItem2.Key] = sortedItem2.Value - num8; } ReflectionHelpers.NotifyInventoryChanged(inventory); } finally { _isApplyingProjection = false; } } private long ComputeContentHash() { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) long num = 17L; foreach (KeyValuePair<ItemKey, int> authoritativeTotal in _authoritativeTotals) { long num2 = num * 31; ItemKey key = authoritativeTotal.Key; num = num2 + ((object)(ItemKey)(ref key)).GetHashCode(); num = num * 31 + authoritativeTotal.Value; } return num * 31 + _searchQuery.GetHashCode(); } private void RebuildSortedItems() { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) _sortedItems.Clear(); foreach (KeyValuePair<ItemKey, int> authoritativeTotal in _authoritativeTotals) { if (authoritativeTotal.Value > 0) { EnsureSortCacheEntry(authoritativeTotal.Key); if (MatchesSearch(_sortCache[authoritativeTotal.Key].DisplayName)) { _sortedItems.Add(authoritativeTotal); } } } _sortedItems.Sort(delegate(KeyValuePair<ItemKey, int> a, KeyValuePair<ItemKey, int> b) { //IL_0008: 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) CachedSortEntry cachedSortEntry = _sortCache[a.Key]; CachedSortEntry cachedSortEntry2 = _sortCache[b.Key]; int num = cachedSortEntry.TypeOrder.CompareTo(cachedSortEntry2.TypeOrder); if (num != 0) { return num; } num = cachedSortEntry.SubgroupOrder.CompareTo(cachedSortEntry2.SubgroupOrder); if (num != 0) { return num; } num = string.Compare(cachedSortEntry.DisplayName, cachedSortEntry2.DisplayName, StringComparison.OrdinalIgnoreCase); return (num != 0) ? num : b.Value.CompareTo(a.Value); }); } private void EnsureSortCacheEntry(ItemKey key) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) if (!_sortCache.ContainsKey(key)) { _sortCache[key] = new CachedSortEntry { DisplayName = GetDisplayName(key), TypeOrder = GetItemTypeOrder(key), SubgroupOrder = ReflectionHelpers.GetSubgroupOrder(key) }; } } private ItemData? CreateProjectedItem(ItemKey key, int amount, int maxStackSize) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) if (!_prototypes.TryGetValue(key, out ItemData value)) { ObjectDB instance = ObjectDB.instance; GameObject obj = ((instance != null) ? instance.GetItemPrefab(((ItemKey)(ref key)).PrefabName) : null); ItemDrop val = ((obj != null) ? obj.GetComponent<ItemDrop>() : null); if (val?.m_itemData == null) { return null; } value = val.m_itemData.Clone(); value.m_quality = ((ItemKey)(ref key)).Quality; value.m_variant = ((ItemKey)(ref key)).Variant; _prototypes[key] = value; } ItemData obj2 = value.Clone(); obj2.m_stack = amount; return obj2; } private bool MatchesSearch(string displayName) { if (!string.IsNullOrWhiteSpace(_searchQuery)) { return displayName.IndexOf(_searchQuery, StringComparison.OrdinalIgnoreCase) >= 0; } return true; } private void RefreshTrackedChestHandles() { //IL_003d: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_terminal == (Object)null) { _trackedChests.Clear(); _nextTrackedChestRefreshAt = Time.unscaledTime + 1f; } else { _trackedChests = _scanner.GetNearbyContainers(((Component)_terminal).transform.position, _scanRadius, _terminal).ToList(); _nextTrackedChestRefreshAt = Time.unscaledTime + 1f; } } private void ApplyDisplayedDeltaAsOperations(Dictionary<ItemKey, int> currentDisplayed) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_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_005b: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) HashSet<ItemKey> hashSet = new HashSet<ItemKey>(_displayedTotals.Keys); hashSet.UnionWith(currentDisplayed.Keys); foreach (ItemKey item in hashSet) { int value; int num = (_displayedTotals.TryGetValue(item, out value) ? value : 0); int value2; int num2 = (currentDisplayed.TryGetValue(item, out value2) ? value2 : 0) - num; if (num2 < 0) { RequestReserveWithdraw(item, -num2); } else if (num2 > 0) { RequestCancelAndOrDeposit(item, num2); } } } private void RequestReserveWithdraw(ItemKey key, int amount) { //IL_0071: Unknown result type (might be due to invalid IL or missing references) if (amount > 0) { _routes.RequestReserveWithdraw(new ReserveWithdrawRequestDto { RequestId = Guid.NewGuid().ToString("N"), SessionId = _sessionId, OperationId = Guid.NewGuid().ToString("N"), TerminalUid = _terminalUid, PlayerId = ResolveLocalPlayerId(), ExpectedRevision = _revision, Key = key, Amount = amount }); } } private void RequestCancelAndOrDeposit(ItemKey key, int amount) { //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_016a: Unknown result type (might be due to invalid IL or missing references) //IL_01dd: Unknown result type (might be due to invalid IL or missing references) if (amount <= 0) { return; } int num = amount; foreach (PendingReservation item in _pendingReservations.Where(delegate(PendingReservation r) { //IL_0001: 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_000a: Unknown result type (might be due to invalid IL or missing references) ItemKey key2 = r.Key; return ((ItemKey)(ref key2)).Equals(key) && r.ReservedAmount > 0; }).ToList()) { if (num <= 0) { break; } int num2 = Math.Min(num, item.ReservedAmount); if (num2 > 0) { _routes.RequestCancelReservation(new CancelReservationRequestDto { RequestId = Guid.NewGuid().ToString("N"), SessionId = _sessionId, OperationId = Guid.NewGuid().ToString("N"), TerminalUid = _terminalUid, PlayerId = ResolveLocalPlayerId(), TokenId = item.TokenId, Amount = num2 }); item.ReservedAmount -= num2; num -= num2; if (item.ReservedAmount <= 0) { _pendingReservations.Remove(item); } } } if (num > 0) { string requestId = Guid.NewGuid().ToString("N"); _pendingDeposits.Add(new PendingDeposit { RequestId = requestId, Key = key, Amount = num }); _routes.RequestDeposit(new DepositRequestDto { RequestId = requestId, SessionId = _sessionId, OperationId = Guid.NewGuid().ToString("N"), TerminalUid = _terminalUid, PlayerId = ResolveLocalPlayerId(), ExpectedRevision = _revision, Key = key, Amount = num }); } } private void CommitPendingReservations() { foreach (PendingReservation item in _pendingReservations.Where((PendingReservation r) => !r.CommitRequested && r.ReservedAmount > 0).ToList()) { _routes.RequestCommitReservation(new CommitReservationRequestDto { RequestId = Guid.NewGuid().ToString("N"), SessionId = _sessionId, OperationId = Guid.NewGuid().ToString("N"), TerminalUid = _terminalUid, TokenId = item.TokenId }); item.CommitRequested = true; } } private void ExpireLocalReservations() { float unscaledTime = Time.unscaledTime; bool flag = false; for (int num = _pendingReservations.Count - 1; num >= 0; num--) { if (!(_pendingReservations[num].ExpiresAt > unscaledTime)) { _pendingReservations.RemoveAt(num); flag = true; } } if (flag) { RequestSessionSnapshot(); } } private void RequestSessionSnapshot() { //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) if (IsActive && !((Object)(object)_terminal == (Object)null)) { _routes.RequestOpenSession(new OpenSessionRequestDto { RequestId = Guid.NewGuid().ToString("N"), SessionId = _sessionId, TerminalUid = _terminalUid, PlayerId = ResolveLocalPlayerId(), AnchorX = ((Component)_terminal).transform.position.x, AnchorY = ((Component)_terminal).transform.position.y, AnchorZ = ((Component)_terminal).transform.position.z, Radius = _scanRadius }); _nextSnapshotRetryAt = Time.unscaledTime + 0.5f; } } private Dictionary<ItemKey, int> CaptureCurrentDisplayedTotals() { //IL_0079: 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) Dictionary<ItemKey, int> dictionary = new Dictionary<ItemKey, int>(); if ((Object)(object)_terminal == (Object)null) { return dictionary; } Inventory inventory = _terminal.GetInventory(); if (inventory == null) { return dictionary; } ItemKey key = default(ItemKey); foreach (ItemData allItem in inventory.GetAllItems()) { if (!((Object)(object)allItem?.m_dropPrefab == (Object)null) && allItem.m_stack > 0) { ((ItemKey)(ref key))..ctor(((Object)allItem.m_dropPrefab).name, allItem.m_quality, allItem.m_variant); dictionary[key] = (dictionary.TryGetValue(key, out var value) ? (value + allItem.m_stack) : allItem.m_stack); } } return dictionary; } private void ReplaceDisplayedTotals(Dictionary<ItemKey, int> totals) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) _displayedTotals.Clear(); foreach (KeyValuePair<ItemKey, int> total in totals) { _displayedTotals[total.Key] = total.Value; } } private bool IsSessionTerminal(Container container) { if ((Object)(object)container != (Object)null && !string.IsNullOrWhiteSpace(_terminalUid)) { return string.Equals(ReflectionHelpers.BuildContainerUid(container), _terminalUid, StringComparison.Ordinal); } return false; } private void HandleDepositResult(ApplyResultDto result) { //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) ApplyResultDto result2 = result; PendingDeposit pendingDeposit = _pendingDeposits.FirstOrDefault((PendingDeposit p) => string.Equals(p.RequestId, result2.RequestId, StringComparison.Ordinal)); if (pendingDeposit != null) { _pendingDeposits.Remove(pendingDeposit); if (result2.Success) { _trace.Dev($"Deposited {result2.AppliedAmount}x {GetDisplayName(pendingDeposit.Key)}."); } else if (ShouldRestoreFailedDeposit(result2.Reason)) { RestoreToLocalPlayerInventory(pendingDeposit.Key, pendingDeposit.Amount); } } } private void RestoreToLocalPlayerInventory(ItemKey key, int amount) { //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_0021: 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) if (amount > 0 && !((Object)(object)_player == (Object)null)) { int num = ReflectionHelpers.GetMaxStackSize(key); if (num <= 0) { num = 1; } Inventory inventory = ((Humanoid)_player).GetInventory(); int num2 = ChunkedTransfer.Move(amount, num, (Func<int, int>)delegate(int chunkAmount) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) ItemData val = ReflectionHelpers.CreateItemStack(key, chunkAmount); return (val != null) ? ReflectionHelpers.TryAddItemMeasured(inventory, key, val, chunkAmount) : 0; }); int num3 = amount - num2; if (num3 > 0) { DropNearPlayer(key, num3); } } } private void DropNearPlayer(ItemKey key, int amount) { //IL_0013: 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_0044: Unknown result type (might be due to invalid IL or missing references) //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_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_player == (Object)null || amount <= 0) { return; } int num = ReflectionHelpers.GetMaxStackSize(key); if (num <= 0) { num = 1; } int num2 = amount; while (num2 > 0) { int num3 = Math.Min(num, num2); ItemData val = ReflectionHelpers.CreateItemStack(key, num3); if (val != null && ReflectionHelpers.TryDropItem(val, num3, ((Component)_player).transform.position + ((Component)_player).transform.forward + Vector3.up, Quaternion.identity)) { num2 -= num3; continue; } break; } } private void RemovePendingToken(string tokenId) { string tokenId2 = tokenId; if (!string.IsNullOrWhiteSpace(tokenId2)) { _pendingReservations.RemoveAll((PendingReservation r) => string.Equals(r.TokenId, tokenId2, StringComparison.Ordinal)); } } private void MarkPendingCommitAsRetryable(string tokenId) { string tokenId2 = tokenId; foreach (PendingReservation item in _pendingReservations.Where((PendingReservation r) => string.Equals(r.TokenId, tokenId2, StringComparison.Ordinal))) { item.CommitRequested = false; } } private long ResolveLocalPlayerId() { if (!((Object)(object)_player != (Object)null)) { return 0L; } return _player.GetPlayerID(); } private string GetDisplayName(ItemKey key) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) if (_prototypes.TryGetValue(key, out ItemData value)) { string name = value.m_shared.m_name; Localization instance = Localization.instance; string text = ((instance != null) ? instance.Localize(name) : null); if (string.IsNullOrEmpty(text)) { return name; } return text; } return ((ItemKey)(ref key)).PrefabName; } private int GetItemTypeOrder(ItemKey key) { //IL_0006: 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_001c: Expected I4, but got Unknown if (_prototypes.TryGetValue(key, out ItemData value)) { return (int)value.m_shared.m_itemType; } return int.MaxValue; } private void CaptureOriginalInventorySize(Inventory? inventory) { if (inventory == null) { _originalInventoryWidth = 8; _originalInventoryHeight = 4; } else { _originalInventoryWidth = ReflectionHelpers.GetInventoryWidth(inventory); _originalInventoryHeight = ReflectionHelpers.GetInventoryHeight(inventory); } } private void RestoreTerminalInventorySize(Inventory? inventory) { if (inventory != null && _originalInventoryWidth > 0 && _originalInventoryHeight > 0) { ReflectionHelpers.SetInventorySize(inventory, _originalInventoryWidth, _originalInventoryHeight); } } private static bool ShouldRestoreFailedDeposit(string reason) { if (!string.IsNullOrWhiteSpace(reason)) { switch (reason) { default: return reason == "Unable to resolve player identity"; case "Conflict": case "Player not found": case "Player has no matching item": case "Player/terminal has no matching item": case "Session not found": case "No storage space": case "Player identity mismatch": return true; } } return false; } private static bool IsIdentityFailure(string reason) { if (!(reason == "Player identity mismatch")) { return reason == "Unable to resolve player identity"; } return true; } private static float GetRetryDelay(int failureCount) { if (failureCount <= 0) { return 0.5f; } int num = Math.Min(6, failureCount - 1); float num2 = 0.5f * Mathf.Pow(2f, (float)num); return Mathf.Min(8f, num2); } } } namespace UnifiedStorage.Mod.Server { public static class ChestInclusionRules { private const string IncludeInUnifiedKey = "US_IncludeInUnified"; private static readonly HashSet<string> VanillaChestPrefabNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "piece_chest", "piece_chest_wood", "piece_chest_private", "piece_chest_blackmetal" }; public static bool IsVanillaChest(Container? container) { if ((Object)(object)container == (Object)null) { return false; } string item = NormalizePrefabName(((Object)((Component)container).gameObject).name); return VanillaChestPrefabNames.Contains(item); } public static bool IsIncludedInUnified(Container? container) { if ((Object)(object)container == (Object)null) { return false; } ZNetView component = ((Component)container).GetComponent<ZNetView>(); ZDO val = ((component != null) ? component.GetZDO() : null); if (val == null) { return true; } return val.GetBool("US_IncludeInUnified", true); } public static bool TrySetIncludedInUnified(Container? container, bool includeInUnified) { if ((Object)(object)container == (Object)null) { return false; } ZNetView component = ((Component)container).GetComponent<ZNetView>(); ZDO val = ((component != null) ? component.GetZDO() : null); if (val == null) { return false; } try { if ((Object)(object)component != (Object)null && !component.IsOwner()) { component.ClaimOwnership(); } } catch { } val.Set("US_IncludeInUnified", includeInUnified); return true; } private static string NormalizePrefabName(string name) { if (name.EndsWith("(Clone)", StringComparison.Ordinal)) { return name.Substring(0, name.Length - "(Clone)".Length); } return name; } } public sealed class ContainerScanner : IContainerScanner { private readonly StorageConfig _config; public ContainerScanner(StorageConfig config) { _config = config; } public IReadOnlyList<ChestHandle> GetNearbyContainers(Vector3 center, float radius, Container? ignoreContainer = null) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) Container ignoreContainer2 = ignoreContainer; int value = _config.MaxContainersScanned.Value; return (from handle in (from container in (from container in Object.FindObjectsByType<Container>((FindObjectsSortMode)0) where (Object)(object)container != (Object)null select container).Where(IsStaticChest) where (Object)(object)ignoreContainer2 == (Object)null || (Object)(object)container != (Object)(object)ignoreContainer2 where !UnifiedTerminal.IsTerminal(container) select container).Where(ChestInclusionRules.IsIncludedInUnified).Select(delegate(Container container) { //IL_0001: 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) float distance = Vector3.Distance(center, ((Component)container).transform.position); return new ChestHandle(BuildSourceId(container), container, distance); }) where handle.Distance <= radius orderby handle.Distance, handle.SourceId select handle).Take(value).ToList(); } private static bool IsStaticChest(Container container) { if (!((Component)container).gameObject.activeInHierarchy) { return false; } if ((Object)(object)((Component)container).GetComponentInParent<Vagon>() != (Object)null) { return false; } if ((Object)(object)((Component)container).GetComponentInParent<Ship>() != (Object)null) { return false; } return true; } private static string BuildSourceId(Container container) { ZNetView component = ((Component)container).GetComponent<ZNetView>(); ZDO val = ((component != null) ? component.GetZDO() : null); if (val != null) { return ((object)(ZDOID)(ref val.m_uid)).ToString(); } return ((Object)container).GetInstanceID().ToString(); } } public sealed class TerminalAuthorityService { private sealed class TerminalState { public string SessionId { get; set; } = string.Empty; public string TerminalUid { get; set; } = string.Empty; public Vector3 AnchorPosition { get; set; } public float Radius { get; set; } public long Revision { get; set; } public int SlotsTotalPhysical { get; set; } public int ChestCount { get; set; } public List<ChestHandle> Chests { get; set; } = new List<ChestHandle>(); public HashSet<long> Subscribers { get; } = new HashSet<long>(); public Dictionary<long, long> PeerPlayerIds { get; } = new Dictionary<long, long>(); public Dictionary<string, ReservationRecord> Reservations { get; } = new Dictionary<string, ReservationRecord>(StringComparer.Ordinal); public HashSet<string> ProcessedOperations { get; } = new HashSet<string>(StringComparer.Ordinal); public Queue<string> OperationOrder { get; } = new Queue<string>(); public bool SnapshotDirty { get; set; } = true; public float CachedSnapshotAt { get; set; } public SessionSnapshotDto? CachedSnapshot { get; set; } } private sealed class ReservationRecord { public string TokenId { get; set; } = string.Empty; public string SessionId { get; set; } = string.Empty; public long PeerId { get; set; } public ItemKey Key { get; set; } public int Amount { get; set; } public float ExpiresAt { get; set; } } private const float ReservationTtlSeconds = 3f; private const float SnapshotCacheSeconds = 0.2f; private const int MaxOperationHistory = 2048; private readonly object _sync = new object(); private readonly StorageConfig _config; private readonly IContainerScanner _scanner; private readonly ManualLogSource _logger; private readonly Dictionary<string, TerminalState> _states = new Dictionary<string, TerminalState>(StringComparer.Ordinal); public event Action<IReadOnlyCollection<long>, SessionDeltaDto>? DeltaReady; public TerminalAuthorityService(StorageConfig config, IContainerScanner scanner, ManualLogSource logger) { _config = config; _scanner = scanner; _logger = logger; } public void Tick() { //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_0175: Unknown result type (might be due to invalid IL or missing references) List<(IReadOnlyCollection<long>, SessionDeltaDto)> list = new List<(IReadOnlyCollection<long>, SessionDeltaDto)>(); lock (_sync) { if (_states.Count == 0) { return; } float now = Time.unscaledTime; foreach (TerminalState item in _states.Values.ToList()) { item.Subscribers.RemoveWhere((long peer) => !IsPeerConnected(peer)); foreach (long item2 in item.PeerPlayerIds.Keys.Where((long peer) => !IsPeerConnected(peer)).ToList()) { item.PeerPlayerIds.Remove(item2); } List<ReservationRecord> list2 = item.Reservations.Values.Where((ReservationRecord r) => r.ExpiresAt <= now || !IsPeerConnected(r.PeerId)).ToList(); bool flag = false; foreach (ReservationRecord item3 in list2) { int num = AddToChests(item, item3.Key, item3.Amount, null); int num2 = item3.Amount - num; if (num2 > 0) { DropNearTerminal(item, item3.Key, num2); } item.Reservations.Remove(item3.TokenId); flag = flag || num > 0 || num2 > 0; } if (flag) { MarkSnapshotDirty(item); item.Revision++; SessionSnapshotDto snapshot = BuildSnapshot(item); list.Add((item.Subscribers.ToList(), BuildDelta(item, snapshot))); } if (item.Subscribers.Count == 0 && item.Reservations.Count == 0) { _states.Remove(item.TerminalUid); } } } EmitDeltas(list); } public OpenSessionResponseDto HandleOpenSession(long sender, OpenSessionRequestDto request) { lock (_sync) { if (string.IsNullOrWhiteSpace(request.TerminalUid)) { return new OpenSessionResponseDto { RequestId = request.RequestId, Success = false, Reason = "Invalid terminal" }; } TerminalState orCreateState = GetOrCreateState(request); if (!TryResolveAndBindPlayerId(orCreateState, sender, request.PlayerId, out var resolvedPlayerId)) { return new OpenSessionResponseDto { RequestId = request.RequestId, Success = false, Reason = "Player identity mismatch" }; } if (resolvedPlayerId <= 0) { return new OpenSessionResponseDto { RequestId = request.RequestId, Success = false, Reason = "Unable to resolve player identity" }; } orCreateState.Subscribers.Add(sender); SessionSnapshotDto snapshot = BuildSnapshot(orCreateState); return new OpenSessionResponseDto { RequestId = request.RequestId, Success = true, Snapshot = snapshot }; } } public ReserveWithdrawResultDto HandleReserveWithdraw(long sender, ReserveWithdrawRequestDto request) { //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_01a8: Unknown result type (might be due to invalid IL or missing references) //IL_0244: Unknown result type (might be due to invalid IL or missing references) List<(IReadOnlyCollection<long>, SessionDeltaDto)> list = new List<(IReadOnlyCollection<long>, SessionDeltaDto)>(); ReserveWithdrawResultDto result; lock (_sync) { TerminalState state = GetState(request.TerminalUid); if (state == null) { return ReserveFailure(request, "Session not found", null, 0L); } if (IsDuplicateOperation(state, request.OperationId)) { return new ReserveWithdrawResultDto { RequestId = request.RequestId, Success = true, Reason = "Duplicate", Key = request.Key, Revision = state.Revision, Snapshot = BuildSnapshot(state) }; } if (request.ExpectedRevision >= 0 && request.ExpectedRevision != state.Revision) { return ReserveFailure(request, "Conflict", BuildSnapshot(state), state.Revision); } if (!TryGetMappedPlayerId(state, sender, request.PlayerId, out var playerId)) { return ReserveFailure(request, "Player identity mismatch", BuildSnapshot(state), state.Revision); } Player player = FindPlayerById(playerId); int num = RemoveFromChests(state, request.Key, request.Amount, player); if (num <= 0) { RememberOperation(state, request.OperationId); return ReserveFailure(request, "Not enough items", BuildSnapshot(state), state.Revision); } string text = Guid.NewGuid().ToString("N"); state.Reservations[text] = new ReservationRecord { TokenId = text, PeerId = sender, SessionId = (request.SessionId ?? string.Empty), Key = request.Key, Amount = num, ExpiresAt = Time.unscaledTime + 3f }; state.Revision++; MarkSnapshotDirty(state); RememberOperation(state, request.OperationId); SessionSnapshotDto snapshot = BuildSnapshot(state); list.Add((state.Subscribers.ToList(), BuildDelta(state, snapshot))); result = new ReserveWithdrawResultDto { RequestId = request.RequestId, Success = true, TokenId = text, Key = request.Key, ReservedAmount = num, Revision = state.Revision, Snapshot = snapshot }; } EmitDeltas(list); return result; } public ApplyResultDto HandleCommitReservation(long sender, CommitReservationRequestDto request) { lock (_sync) { TerminalState state = GetState(request.TerminalUid); if (state == null) { return ApplyFailure(request.RequestId, request.TokenId ?? "", "Session not found", null, 0L, "commit"); } if (IsDuplicateOperation(state, request.OperationId)) { return new ApplyResultDto { RequestId = request.RequestId, Success = true,