Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of StorageNetwork v1.0.0
StorageNetwork.dll
Decompiled 16 hours ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using TMPro; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.Events; using UnityEngine.Rendering; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")] [assembly: AssemblyCompany("StorageNetwork")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("StorageNetwork")] [assembly: AssemblyTitle("StorageNetwork")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace StorageNetwork { internal enum ChestRole { None, Input, Storage } internal static class ChestConfig { internal const float MinRange = 2f; internal const float MaxRange = 100f; private static readonly int RoleKey = StringExtensionMethods.GetStableHashCode("SN_Role"); private static readonly int TagsKey = StringExtensionMethods.GetStableHashCode("SN_Tags"); private static readonly int RangeKey = StringExtensionMethods.GetStableHashCode("SN_Range"); private static readonly int LockedKey = StringExtensionMethods.GetStableHashCode("SN_TypeLocked"); private static readonly int LegacyItemTagsKey = StringExtensionMethods.GetStableHashCode("SN_ItemTags"); internal static readonly int InUseKey = StringExtensionMethods.GetStableHashCode("InUse"); internal static float DefaultRange => Mathf.Clamp(Plugin.NetworkRange.Value, 2f, 100f); internal static ZDO GetZDO(Container c) { if ((Object)(object)c == (Object)null) { return null; } ZNetView component = ((Component)c).GetComponent<ZNetView>(); if ((Object)(object)component == (Object)null || !component.IsValid()) { return null; } return component.GetZDO(); } internal static bool TryGetId(Container c, out ZDOID id) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) ZDO zDO = GetZDO(c); id = zDO?.m_uid ?? ZDOID.None; return zDO != null; } internal static bool IsEligible(Container c) { if (GetZDO(c) == null) { return false; } if ((Object)(object)((Component)c).GetComponent<TombStone>() != (Object)null) { return false; } if (!Plugin.AllowMovingContainers.Value) { if ((Object)(object)((Component)c).GetComponentInParent<Ship>() != (Object)null) { return false; } if ((Object)(object)((Component)c).GetComponentInParent<Vagon>() != (Object)null) { return false; } } return true; } internal static bool EnsureOwner(Container c) { ZNetView val = (((Object)(object)c != (Object)null) ? ((Component)c).GetComponent<ZNetView>() : null); if ((Object)(object)val == (Object)null || !val.IsValid()) { return false; } if (!val.IsOwner()) { val.ClaimOwnership(); } return val.IsOwner(); } internal static bool IsInUseByOthers(Container c) { ZDO zDO = GetZDO(c); if (zDO != null) { return zDO.GetInt(InUseKey, 0) == 1; } return false; } internal static ChestRole GetRole(Container c) { ZDO zDO = GetZDO(c); if (zDO == null) { return ChestRole.None; } return zDO.GetInt(RoleKey, 0) switch { 2 => ChestRole.Storage, 1 => ChestRole.Input, _ => ChestRole.None, }; } internal static bool SetRole(Container c, ChestRole role) { if (IsLocked(c) || !EnsureOwner(c)) { return false; } GetZDO(c).Set(RoleKey, (int)role, false); return true; } internal static bool IsLocked(Container c) { ZDO zDO = GetZDO(c); if (zDO != null) { return zDO.GetInt(LockedKey, 0) == 1; } return false; } internal static void SetLocked(Container c, bool locked) { if (EnsureOwner(c)) { GetZDO(c).Set(LockedKey, locked ? 1 : 0, false); } } internal static bool HasCustomRange(Container c) { ZDO zDO = GetZDO(c); if (zDO != null) { return zDO.GetFloat(RangeKey, 0f) > 0f; } return false; } internal static float GetRange(Container c) { ZDO zDO = GetZDO(c); float num = ((zDO != null) ? zDO.GetFloat(RangeKey, 0f) : 0f); if (!(num > 0f)) { return DefaultRange; } return Mathf.Clamp(num, 2f, 100f); } internal static void SetRange(Container c, float range) { if (EnsureOwner(c)) { GetZDO(c).Set(RangeKey, (range > 0f) ? Mathf.Clamp(range, 2f, 100f) : 0f); } } internal static List<string> GetTags(Container c) { ZDO zDO = GetZDO(c); if (zDO != null) { return TagDatabase.ParseList(zDO.GetString(TagsKey, "")); } return new List<string>(); } internal static void SetTags(Container c, IEnumerable<string> tags) { if (EnsureOwner(c)) { GetZDO(c).Set(TagsKey, TagDatabase.JoinList(tags)); } } internal static Dictionary<string, List<string>> GetLegacyItemTags(Container c) { Dictionary<string, List<string>> dictionary = new Dictionary<string, List<string>>(StringComparer.OrdinalIgnoreCase); ZDO zDO = GetZDO(c); if (zDO == null) { return dictionary; } string text = zDO.GetString(LegacyItemTagsKey, ""); if (string.IsNullOrEmpty(text)) { return dictionary; } string[] array = text.Split(new char[1] { ';' }); foreach (string text2 in array) { int num = text2.IndexOf('='); if (num > 0) { string text3 = text2.Substring(0, num).Trim(); if (text3.Length != 0) { dictionary[text3] = TagDatabase.ParseList(text2.Substring(num + 1)); } } } return dictionary; } internal static void ClearLegacyItemTags(Container c) { if (EnsureOwner(c)) { GetZDO(c).Set(LegacyItemTagsKey, ""); } } internal static string Describe(Container c) { string text = DescribeRole(c); if (text == null || !IsLocked(c)) { return text; } return text + " (type locked)"; } private static string DescribeRole(Container c) { switch (GetRole(c)) { case ChestRole.Input: return $"Input chest ({GetRange(c):0}m)"; case ChestRole.Storage: { List<string> tags = GetTags(c); if (tags.Count != 0) { return "Storage: " + string.Join(", ", tags.ToArray()); } return "Storage (no tags)"; } default: return null; } } } internal class ContainerTracker : MonoBehaviour { private static readonly HashSet<Container> Tracked = new HashSet<Container>(); private Container _container; private void Awake() { _container = ((Component)this).GetComponent<Container>(); if ((Object)(object)_container != (Object)null) { Tracked.Add(_container); } } private void OnDestroy() { if ((Object)(object)_container != (Object)null) { Tracked.Remove(_container); } } internal static List<Container> All() { List<Container> list = new List<Container>(Tracked.Count); foreach (Container item in Tracked) { if ((Object)(object)item != (Object)null) { list.Add(item); } } return list; } internal static List<Container> InRange(Vector3 origin, float range) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) List<Container> list = new List<Container>(); float num = range * range; foreach (Container item in Tracked) { if (!((Object)(object)item == (Object)null)) { Vector3 val = ((Component)item).transform.position - origin; if (!(((Vector3)(ref val)).sqrMagnitude > num) && ChestConfig.IsEligible(item)) { list.Add(item); } } } return list; } } internal class FlashManager : MonoBehaviour { private static readonly HashSet<ZDOID> Flashing = new HashSet<ZDOID>(); private static readonly HashSet<string> Selected = new HashSet<string>(StringComparer.OrdinalIgnoreCase); private static float _startTime; private float _nextAttach; internal static int FlashingCount => Flashing.Count; internal static IEnumerable<string> SelectedPrefabs => Selected; internal static bool IsSelected(string prefab) { return Selected.Contains(prefab); } internal static bool IsFlashing(ZDOID id) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) return Flashing.Contains(id); } internal static bool IsFlashing(Container c) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) if (ChestConfig.TryGetId(c, out var id)) { return Flashing.Contains(id); } return false; } internal static void Set(IEnumerable<string> prefabs, IEnumerable<ZDOID> chests) { Selected.Clear(); Flashing.Clear(); if (prefabs != null) { Selected.UnionWith(prefabs); } if (chests != null) { Flashing.UnionWith(chests); } if (Flashing.Count == 0) { Selected.Clear(); } _startTime = Time.time; } internal static void Clear() { Selected.Clear(); Flashing.Clear(); } private void Update() { //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)Player.m_localPlayer == (Object)null) { if (Flashing.Count > 0) { Clear(); } } else { if (Flashing.Count == 0) { return; } if ((Object)(object)InventoryGui.instance != (Object)null && InventoryGui.IsVisible()) { Container val = Patches.CurrentContainer(InventoryGui.instance); if ((Object)(object)val != (Object)null && ChestConfig.TryGetId(val, out var id) && Flashing.Remove(id) && Flashing.Count == 0) { Selected.Clear(); } } float value = Plugin.FlashTimeout.Value; if (value > 0f && Time.time - _startTime > value) { Clear(); } else { if (Time.time < _nextAttach) { return; } _nextAttach = Time.time + 0.5f; foreach (Container item in ContainerTracker.All()) { if (ChestConfig.TryGetId(item, out var id2) && Flashing.Contains(id2) && (Object)(object)((Component)item).GetComponent<FlashEffect>() == (Object)null) { ((Component)item).gameObject.AddComponent<FlashEffect>().Init(id2); } } } } } } internal class FlashEffect : MonoBehaviour { private static readonly int EmissionColor = Shader.PropertyToID("_EmissionColor"); private static Material _beamMaterial; private static bool _beamMaterialSearched; private ZDOID _id; private GameObject _fx; private Light _light; private LineRenderer _beam; private Renderer[] _renderers = (Renderer[])(object)new Renderer[0]; private MaterialPropertyBlock[] _originalBlocks = (MaterialPropertyBlock[])(object)new MaterialPropertyBlock[0]; private MaterialPropertyBlock _block; internal void Init(ZDOID id) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Expected O, but got Unknown //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: 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_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0223: Unknown result type (might be due to invalid IL or missing references) //IL_022d: Expected O, but got Unknown //IL_01b7: Unknown result type (might be due to invalid IL or missing references) //IL_01c4: Unknown result type (might be due to invalid IL or missing references) //IL_01c5: Unknown result type (might be due to invalid IL or missing references) //IL_01cf: Unknown result type (might be due to invalid IL or missing references) //IL_01d4: 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) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_024d: Unknown result type (might be due to invalid IL or missing references) //IL_0253: Expected O, but got Unknown _id = id; Color value = Plugin.FlashColor.Value; _renderers = Array.FindAll(((Component)this).GetComponentsInChildren<Renderer>(), (Renderer r) => r is MeshRenderer || r is SkinnedMeshRenderer); Vector3 val = ((Component)this).transform.position + Vector3.up; if (_renderers.Length != 0) { Bounds bounds = _renderers[0].bounds; Renderer[] renderers = _renderers; foreach (Renderer val2 in renderers) { ((Bounds)(ref bounds)).Encapsulate(val2.bounds); } ((Vector3)(ref val))..ctor(((Bounds)(ref bounds)).center.x, ((Bounds)(ref bounds)).max.y, ((Bounds)(ref bounds)).center.z); } _fx = new GameObject("StorageNetwork_Flash"); _fx.transform.position = val + Vector3.up * 0.3f; _fx.transform.SetParent(((Component)this).transform, true); _light = _fx.AddComponent<Light>(); _light.type = (LightType)2; _light.color = value; _light.range = 4f; _light.shadows = (LightShadows)0; if (Plugin.FlashBeam.Value && (Object)(object)BeamMaterial() != (Object)null) { _beam = _fx.AddComponent<LineRenderer>(); ((Renderer)_beam).sharedMaterial = _beamMaterial; _beam.useWorldSpace = true; _beam.positionCount = 2; _beam.SetPosition(0, val); _beam.SetPosition(1, val + Vector3.up * 12f); _beam.startWidth = 0.15f; _beam.endWidth = 0.02f; ((Renderer)_beam).shadowCastingMode = (ShadowCastingMode)0; ((Renderer)_beam).receiveShadows = false; } if (Plugin.FlashGlow.Value) { _block = new MaterialPropertyBlock(); _originalBlocks = (MaterialPropertyBlock[])(object)new MaterialPropertyBlock[_renderers.Length]; for (int num2 = 0; num2 < _renderers.Length; num2++) { _originalBlocks[num2] = new MaterialPropertyBlock(); _renderers[num2].GetPropertyBlock(_originalBlocks[num2]); } } else { _renderers = (Renderer[])(object)new Renderer[0]; } } private static Material BeamMaterial() { //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Expected O, but got Unknown if (_beamMaterialSearched) { return _beamMaterial; } _beamMaterialSearched = true; string[] array = new string[4] { "Sprites/Default", "UI/Default", "Legacy Shaders/Particles/Additive", "Unlit/Color" }; for (int i = 0; i < array.Length; i++) { Shader val = Shader.Find(array[i]); if (!((Object)(object)val == (Object)null)) { _beamMaterial = new Material(val); break; } } if ((Object)(object)_beamMaterial == (Object)null) { Plugin.Log.LogWarning((object)"No shader found for the flash beam; only the light will be shown."); } return _beamMaterial; } private void Update() { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003b: 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_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: 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) //IL_00bf: 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_0107: Unknown result type (might be due to invalid IL or missing references) if (!FlashManager.IsFlashing(_id)) { Object.Destroy((Object)(object)this); return; } float num = 0.5f + 0.5f * Mathf.Sin(Time.time * 6f); Color value = Plugin.FlashColor.Value; if ((Object)(object)_light != (Object)null) { _light.intensity = 0.6f + 2.4f * num; } if ((Object)(object)_beam != (Object)null) { Color startColor = default(Color); ((Color)(ref startColor))..ctor(value.r, value.g, value.b, 0.2f + 0.7f * num); _beam.startColor = startColor; _beam.endColor = new Color(value.r, value.g, value.b, 0f); } for (int i = 0; i < _renderers.Length; i++) { Renderer val = _renderers[i]; if (!((Object)(object)val == (Object)null)) { val.GetPropertyBlock(_block); _block.SetColor(EmissionColor, value * (0.15f + 0.6f * num)); val.SetPropertyBlock(_block); } } } private void OnDestroy() { for (int i = 0; i < _renderers.Length; i++) { if ((Object)(object)_renderers[i] != (Object)null) { _renderers[i].SetPropertyBlock(_originalBlocks[i]); } } if ((Object)(object)_fx != (Object)null) { Object.Destroy((Object)(object)_fx); } } } internal static class GlobalItemTags { internal enum SyncMode { NotReady, Host, Client, ClientLocalOnly } private const string RpcRequest = "StorageNetwork_ItemTags_Request"; private const string RpcFull = "StorageNetwork_ItemTags_Full"; private const string RpcSet = "StorageNetwork_ItemTags_Set"; private const string RpcChanged = "StorageNetwork_ItemTags_Changed"; private const float ServerReplyTimeout = 10f; private static readonly Dictionary<string, List<string>> Rules = new Dictionary<string, List<string>>(StringComparer.OrdinalIgnoreCase); private static ZRoutedRpc _registeredOn; private static string _savePath; private static bool _requested; private static float _requestTime; internal static SyncMode Mode { get; private set; } = SyncMode.NotReady; internal static bool Ready => Mode != SyncMode.NotReady; internal static int Revision { get; private set; } internal static string StatusText => Mode switch { SyncMode.NotReady => "Waiting for the world's item tags...", SyncMode.ClientLocalOnly => "The server doesn't run Storage Network: item tags are saved on this PC only.", _ => null, }; internal static void Tick() { //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Expected O, but got Unknown if ((Object)(object)ZNet.instance == (Object)null || ZRoutedRpc.instance == null) { if (Mode != SyncMode.NotReady || _registeredOn != null) { Reset(); } return; } if (_registeredOn != ZRoutedRpc.instance) { Register(); } if (ZNet.instance.IsServer()) { if (Mode != SyncMode.Host) { InitHost(); } } else { if (Mode == SyncMode.Client || (Object)(object)Player.m_localPlayer == (Object)null) { return; } if (!_requested) { long num = ServerPeerId(); if (num != 0L) { _requested = true; _requestTime = Time.unscaledTime; ZRoutedRpc.instance.InvokeRoutedRPC(num, "StorageNetwork_ItemTags_Request", new object[1] { (object)new ZPackage() }); } } else if (Mode == SyncMode.NotReady && Time.unscaledTime - _requestTime > 10f) { Plugin.Log.LogWarning((object)"No reply from the server for item tags; it probably doesn't run Storage Network. Using a local table."); _savePath = Path.Combine(FolderPath(), "_server-without-mod.itemtags.txt"); Load(); Mode = SyncMode.ClientLocalOnly; Revision++; } } } private static void Reset() { Rules.Clear(); Mode = SyncMode.NotReady; _registeredOn = null; _savePath = null; _requested = false; Revision++; } private static void Register() { ZRoutedRpc instance = ZRoutedRpc.instance; instance.Register<ZPackage>("StorageNetwork_ItemTags_Request", (Action<long, ZPackage>)OnRequest); instance.Register<ZPackage>("StorageNetwork_ItemTags_Full", (Action<long, ZPackage>)OnFull); instance.Register<ZPackage>("StorageNetwork_ItemTags_Set", (Action<long, ZPackage>)OnSet); instance.Register<ZPackage>("StorageNetwork_ItemTags_Changed", (Action<long, ZPackage>)OnChanged); _registeredOn = instance; } private static void InitHost() { string worldName = ZNet.instance.GetWorldName(); if (!string.IsNullOrEmpty(worldName)) { _savePath = Path.Combine(FolderPath(), SafeFileName(worldName) + ".itemtags.txt"); Load(); Mode = SyncMode.Host; Revision++; Plugin.Log.LogInfo((object)$"World item tags: {Rules.Count} rules from {_savePath}"); } } internal static bool TryGet(string prefab, out List<string> tags) { return Rules.TryGetValue(prefab, out tags); } internal static IEnumerable<string> AllUsedTags() { return Rules.Values.SelectMany((List<string> v) => v); } internal static void Set(string prefab, List<string> tags) { if (string.IsNullOrEmpty(prefab) || !Ready) { return; } Apply(prefab, tags); switch (Mode) { case SyncMode.Host: Save(); ZRoutedRpc.instance.InvokeRoutedRPC(0L, "StorageNetwork_ItemTags_Changed", new object[1] { Pack(prefab, tags) }); break; case SyncMode.Client: { long num = ServerPeerId(); if (num != 0L) { ZRoutedRpc.instance.InvokeRoutedRPC(num, "StorageNetwork_ItemTags_Set", new object[1] { Pack(prefab, tags) }); } else { Plugin.Log.LogWarning((object)"Not connected to the server; item tag change was not sent."); } break; } case SyncMode.ClientLocalOnly: Save(); break; } } internal static void MigrateLegacy(Container c) { if (!Ready || (Object)(object)c == (Object)null) { return; } Dictionary<string, List<string>> legacyItemTags = ChestConfig.GetLegacyItemTags(c); if (legacyItemTags.Count == 0) { return; } int num = 0; foreach (KeyValuePair<string, List<string>> item in legacyItemTags) { if (!Rules.ContainsKey(item.Key)) { Set(item.Key, item.Value); num++; } } ChestConfig.ClearLegacyItemTags(c); Plugin.Log.LogInfo((object)$"Moved {num} item tag rule(s) from a chest into the world-wide table"); } private static void OnRequest(long sender, ZPackage _) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Expected O, but got Unknown if (!ZNet.instance.IsServer()) { return; } if (Mode != SyncMode.Host) { InitHost(); } ZPackage val = new ZPackage(); val.Write(Rules.Count); foreach (KeyValuePair<string, List<string>> rule in Rules) { val.Write(rule.Key); val.Write(TagDatabase.JoinList(rule.Value)); } ZRoutedRpc.instance.InvokeRoutedRPC(sender, "StorageNetwork_ItemTags_Full", new object[1] { val }); } private static void OnFull(long sender, ZPackage pkg) { if (!ZNet.instance.IsServer()) { Rules.Clear(); int num = pkg.ReadInt(); for (int i = 0; i < num; i++) { string key = pkg.ReadString(); Rules[key] = TagDatabase.ParseList(pkg.ReadString()); } if (Mode == SyncMode.ClientLocalOnly) { Plugin.Log.LogInfo((object)"Server replied late; switching from local to world-wide item tags."); } Mode = SyncMode.Client; _savePath = null; Revision++; } } private static void OnSet(long sender, ZPackage pkg) { if (ZNet.instance.IsServer()) { if (Mode != SyncMode.Host) { InitHost(); } Unpack(pkg, out var prefab, out var tags); Apply(prefab, tags); Save(); ZRoutedRpc.instance.InvokeRoutedRPC(0L, "StorageNetwork_ItemTags_Changed", new object[1] { Pack(prefab, tags) }); } } private static void OnChanged(long sender, ZPackage pkg) { if (!ZNet.instance.IsServer()) { Unpack(pkg, out var prefab, out var tags); Apply(prefab, tags); } } private static long ServerPeerId() { if ((Object)(object)ZNet.instance == (Object)null) { return 0L; } foreach (ZNetPeer peer in ZNet.instance.GetPeers()) { if (peer != null && peer.m_uid != 0L) { return peer.m_uid; } } return 0L; } private static void Apply(string prefab, List<string> tags) { if (tags == null) { Rules.Remove(prefab); } else { Rules[prefab] = new List<string>(tags); } Revision++; } private static ZPackage Pack(string prefab, List<string> tags) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Expected O, but got Unknown ZPackage val = new ZPackage(); val.Write(prefab); val.Write(tags == null); val.Write((tags == null) ? "" : TagDatabase.JoinList(tags)); return val; } private static void Unpack(ZPackage pkg, out string prefab, out List<string> tags) { prefab = pkg.ReadString(); bool flag = pkg.ReadBool(); string csv = pkg.ReadString(); tags = (flag ? null : TagDatabase.ParseList(csv)); } private static string FolderPath() { string text = Path.Combine(Path.Combine(Paths.ConfigPath, "StorageNetwork"), "worlds"); Directory.CreateDirectory(text); return text; } private static string SafeFileName(string name) { StringBuilder stringBuilder = new StringBuilder(name.Length); char[] invalidFileNameChars = Path.GetInvalidFileNameChars(); foreach (char c in name) { stringBuilder.Append((Array.IndexOf(invalidFileNameChars, c) >= 0) ? '_' : c); } return stringBuilder.ToString(); } private static void Load() { Rules.Clear(); if (_savePath == null || !File.Exists(_savePath)) { return; } try { string[] array = File.ReadAllLines(_savePath); for (int i = 0; i < array.Length; i++) { string text = array[i].Trim(); if (text.Length != 0 && !text.StartsWith("#")) { int num = text.IndexOf('='); if (num > 0) { Rules[text.Substring(0, num).Trim()] = TagDatabase.ParseList(text.Substring(num + 1)); } } } } catch (Exception ex) { Plugin.Log.LogError((object)("Could not read item tags from " + _savePath + ": " + ex.Message)); } } private static void Save() { if (_savePath == null) { return; } try { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("# Storage Network world-wide item tags. Format: PrefabName=tagA,tagB"); stringBuilder.AppendLine("# An empty list after '=' means the item is deliberately untagged."); foreach (KeyValuePair<string, List<string>> item in Rules.OrderBy<KeyValuePair<string, List<string>>, string>((KeyValuePair<string, List<string>> k) => k.Key, StringComparer.OrdinalIgnoreCase)) { stringBuilder.Append(item.Key).Append('=').AppendLine(TagDatabase.JoinList(item.Value)); } string text = _savePath + ".tmp"; File.WriteAllText(text, stringBuilder.ToString()); if (File.Exists(_savePath)) { File.Delete(_savePath); } File.Move(text, _savePath); } catch (Exception ex) { Plugin.Log.LogError((object)("Could not save item tags to " + _savePath + ": " + ex.Message)); } } } internal static class NetworkCrafting { private enum Source { Station, PlayerPosition } private static int _depth; private static Source _source; private static int _cacheFrame = -1; private static Source _cacheSource; private static CraftingStation _cacheStation; private static List<Container> _cacheChests = new List<Container>(); private static readonly Dictionary<string, int> CountCache = new Dictionary<string, int>(); internal static bool Active => _depth > 0; internal static void Patch(Harmony harmony) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Expected O, but got Unknown //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Expected O, but got Unknown //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Expected O, but got Unknown //IL_0144: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Expected O, but got Unknown //IL_01d2: Unknown result type (might be due to invalid IL or missing references) //IL_01d9: Expected O, but got Unknown //IL_023f: Unknown result type (might be due to invalid IL or missing references) //IL_0246: Expected O, but got Unknown //IL_02d0: Unknown result type (might be due to invalid IL or missing references) //IL_02d7: Expected O, but got Unknown HarmonyMethod finalizer = new HarmonyMethod(typeof(NetworkCrafting), "ExitFinalizer", (Type[])null); int num = 0; HarmonyMethod prefix = new HarmonyMethod(typeof(NetworkCrafting), "EnterRecipePrefix", (Type[])null); foreach (MethodInfo item in Methods(typeof(Player), "HaveRequirementItems", "HaveRequirements").Where(FirstParamIsRecipe)) { num += TryPatch(harmony, item, prefix, null, finalizer); } HarmonyMethod prefix2 = new HarmonyMethod(typeof(NetworkCrafting), "EnterPiecePrefix", (Type[])null); foreach (MethodInfo item2 in Methods(typeof(Player), "HaveRequirements").Where(FirstParamIsPiece)) { num += TryPatch(harmony, item2, prefix2, null, finalizer); } HarmonyMethod prefix3 = new HarmonyMethod(typeof(NetworkCrafting), "EnterAutoPrefix", (Type[])null); foreach (MethodInfo item3 in Methods(typeof(Player), "ConsumeResources").Concat(Methods(typeof(InventoryGui), "SetupRequirement"))) { num += TryPatch(harmony, item3, prefix3, null, finalizer); } HarmonyMethod postfix = new HarmonyMethod(typeof(NetworkCrafting), "SetupRequirementPostfix", (Type[])null); foreach (MethodInfo item4 in Methods(typeof(InventoryGui), "SetupRequirement")) { TryPatch(harmony, item4, null, postfix); } int num2 = 0; HarmonyMethod postfix2 = new HarmonyMethod(typeof(NetworkCrafting), "CountItemsPostfix", (Type[])null); foreach (MethodInfo item5 in Methods(typeof(Inventory), "CountItems").Where(FirstParamIsString)) { num2 += TryPatch(harmony, item5, null, postfix2); } int num3 = 0; HarmonyMethod prefix4 = new HarmonyMethod(typeof(NetworkCrafting), "RemoveItemPrefix", (Type[])null); foreach (MethodInfo item6 in from m in Methods(typeof(Inventory), "RemoveItem") where FirstParamIsString(m) && SecondParamIsInt(m) select m) { num3 += TryPatch(harmony, item6, prefix4); } if (num == 0 || num2 == 0 || num3 == 0) { Plugin.Log.LogWarning((object)$"Crafting from the network may not work: patched {num} crafting, {num2} counting and {num3} removing methods."); } else { Plugin.Log.LogInfo((object)$"Crafting from the network enabled ({num}/{num2}/{num3} methods patched)"); } } private static IEnumerable<MethodInfo> Methods(Type type, params string[] names) { return from m in AccessTools.GetDeclaredMethods(type) where names.Contains(m.Name) && !m.IsAbstract select m; } private static bool FirstParamIsRecipe(MethodInfo m) { ParameterInfo[] parameters = m.GetParameters(); if (parameters.Length >= 1) { return parameters[0].ParameterType == typeof(Recipe); } return false; } private static bool FirstParamIsPiece(MethodInfo m) { ParameterInfo[] parameters = m.GetParameters(); if (parameters.Length >= 1) { return parameters[0].ParameterType == typeof(Piece); } return false; } private static bool FirstParamIsString(MethodInfo m) { ParameterInfo[] parameters = m.GetParameters(); if (parameters.Length >= 1) { return parameters[0].ParameterType == typeof(string); } return false; } private static bool SecondParamIsInt(MethodInfo m) { ParameterInfo[] parameters = m.GetParameters(); if (parameters.Length >= 2) { return parameters[1].ParameterType == typeof(int); } return false; } private static int TryPatch(Harmony harmony, MethodInfo m, HarmonyMethod prefix = null, HarmonyMethod postfix = null, HarmonyMethod finalizer = null) { try { harmony.Patch((MethodBase)m, prefix, postfix, (HarmonyMethod)null, finalizer, (HarmonyMethod)null); return 1; } catch (Exception ex) { Plugin.Log.LogWarning((object)("Could not patch " + m.DeclaringType?.Name + "." + m.Name + ": " + ex.Message)); return 0; } } private static void EnterRecipePrefix(out bool __state) { __state = Enter(Source.Station); } private static void EnterPiecePrefix(out bool __state) { __state = Enter(Source.PlayerPosition); } private static void EnterAutoPrefix(out bool __state) { bool flag = (Object)(object)InventoryGui.instance != (Object)null && InventoryGui.IsVisible(); __state = Enter((!flag) ? Source.PlayerPosition : Source.Station); } private static bool Enter(Source source) { if (_depth > 0) { _depth++; return true; } if (!((source == Source.Station) ? Plugin.CraftFromNetwork.Value : Plugin.BuildFromNetwork.Value) || ChestsFor(source).Count == 0) { return false; } _source = source; _depth = 1; return true; } private static Exception ExitFinalizer(bool __state, Exception __exception) { if (__state && _depth > 0) { _depth--; } return __exception; } internal static List<Container> NetworkChests() { return ChestsFor(_source); } private static List<Container> ChestsFor(Source source) { //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return new List<Container>(); } CraftingStation val = ((source == Source.Station) ? localPlayer.GetCurrentCraftingStation() : null); if (Time.frameCount == _cacheFrame && source == _cacheSource && (Object)(object)val == (Object)(object)_cacheStation) { return _cacheChests; } _cacheFrame = Time.frameCount; _cacheSource = source; _cacheStation = val; CountCache.Clear(); if (source == Source.Station) { _cacheChests = (((Object)(object)val == (Object)null) ? new List<Container>() : ChestsFor(((Component)val).transform.position)); } else { _cacheChests = ChestsFor(((Component)localPlayer).transform.position); } return _cacheChests; } internal static List<Container> ChestsFor(Vector3 pos) { //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_001a: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) List<Container> list = new List<Container>(); HashSet<Container> hashSet = new HashSet<Container>(); foreach (Container item in ContainerTracker.InRange(pos, 100f)) { if (ChestConfig.GetRole(item) != ChestRole.Input || Vector3.Distance(pos, ((Component)item).transform.position) > ChestConfig.GetRange(item)) { continue; } if (hashSet.Add(item)) { list.Add(item); } foreach (SortService.Target item2 in SortService.FindTargets(item)) { if (hashSet.Add(item2.Container)) { list.Add(item2.Container); } } } list.Sort(delegate(Container a, Container b) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002d: 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_0037: Unknown result type (might be due to invalid IL or missing references) Vector3 val = ((Component)a).transform.position - pos; float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude; val = ((Component)b).transform.position - pos; return sqrMagnitude.CompareTo(((Vector3)(ref val)).sqrMagnitude); }); return list; } internal static bool InNetwork(CraftingStation station) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)station != (Object)null) { return ChestsFor(((Component)station).transform.position).Count > 0; } return false; } private static bool IsPlayerInventory(Inventory inv) { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer != (Object)null) { return inv == ((Humanoid)localPlayer).GetInventory(); } return false; } private static bool Matches(ItemData item, string name, int quality) { if (item.m_shared.m_name == name) { if (quality >= 0) { return item.m_quality == quality; } return true; } return false; } private static int CountIn(Inventory inv, string name, int quality) { if (inv == null) { return 0; } int num = 0; foreach (ItemData allItem in inv.GetAllItems()) { if (Matches(allItem, name, quality)) { num += allItem.m_stack; } } return num; } internal static int NetworkCount(string name, int quality) { List<Container> list = NetworkChests(); string key = name + "#" + quality; if (CountCache.TryGetValue(key, out var value)) { return value; } int num = 0; foreach (Container item in list) { num += CountIn(item.GetInventory(), name, quality); } CountCache[key] = num; return num; } private static void SetupRequirementPostfix(object[] __args) { if (!Active || !Plugin.ShowNetworkAmounts.Value) { return; } Transform val = null; Requirement val2 = null; foreach (object obj in __args) { Transform val3 = (Transform)((obj is Transform) ? obj : null); if (val3 != null && (Object)(object)val == (Object)null) { val = val3; continue; } Requirement val4 = (Requirement)((obj is Requirement) ? obj : null); if (val4 != null && val2 == null) { val2 = val4; } } if (!((Object)(object)val == (Object)null) && val2 != null && !((Object)(object)val2.m_resItem == (Object)null)) { TMP_Text val5 = FindAmountText(val); if (!((Object)(object)val5 == (Object)null) && int.TryParse(StripTags(val5.text).Trim(), out var result)) { string name = val2.m_resItem.m_itemData.m_shared.m_name; Player localPlayer = Player.m_localPlayer; int num = (((Object)(object)localPlayer != (Object)null) ? CountIn(((Humanoid)localPlayer).GetInventory(), name, -1) : 0) + NetworkCount(name, -1); val5.textWrappingMode = (TextWrappingModes)0; val5.overflowMode = (TextOverflowModes)0; val5.text = $"{result}<size=80%> / {num}</size>"; } } } private static TMP_Text FindAmountText(Transform root) { Transform val = root.Find("res_amount"); if ((Object)(object)val != (Object)null) { TMP_Text component = ((Component)val).GetComponent<TMP_Text>(); if ((Object)(object)component != (Object)null) { return component; } } TMP_Text[] componentsInChildren = ((Component)root).GetComponentsInChildren<TMP_Text>(true); foreach (TMP_Text val2 in componentsInChildren) { if (int.TryParse(StripTags(val2.text).Trim(), out var _)) { return val2; } } return null; } private static string StripTags(string text) { if (string.IsNullOrEmpty(text) || text.IndexOf('<') < 0) { return text ?? ""; } StringBuilder stringBuilder = new StringBuilder(text.Length); bool flag = false; foreach (char c in text) { switch (c) { case '<': flag = true; continue; case '>': flag = false; continue; } if (!flag) { stringBuilder.Append(c); } } return stringBuilder.ToString(); } private static void CountItemsPostfix(Inventory __instance, object[] __args, ref int __result) { if (Active && IsPlayerInventory(__instance)) { string text = __args[0] as string; if (!string.IsNullOrEmpty(text)) { int quality = ((__args.Length > 1 && __args[1] is int num) ? num : (-1)); __result += NetworkCount(text, quality); } } } private static void RemoveItemPrefix(Inventory __instance, object[] __args) { if (!Active || !IsPlayerInventory(__instance)) { return; } string text = __args[0] as string; if (string.IsNullOrEmpty(text) || !(__args[1] is int num) || num <= 0) { return; } int quality = ((__args.Length > 2 && __args[2] is int num2) ? num2 : (-1)); int num3 = CountIn(__instance, text, quality); if (num3 < num) { __args[1] = num3; int num4 = TakeFromNetwork(text, quality, num - num3); if (num4 > 0) { Plugin.Log.LogWarning((object)$"Crafting took {num - num3 - num4} of {num - num3} missing '{text}' from the network; {num4} could not be found."); } } } private static int TakeFromNetwork(string name, int quality, int amount) { foreach (Container item in NetworkChests()) { if (amount <= 0) { break; } Inventory inventory = item.GetInventory(); if (inventory == null || CountIn(inventory, name, quality) == 0 || ChestConfig.IsInUseByOthers(item) || !ChestConfig.EnsureOwner(item)) { continue; } foreach (ItemData item2 in (from i in inventory.GetAllItems() where Matches(i, name, quality) select i).ToList()) { if (amount <= 0) { break; } int num = Math.Min(amount, item2.m_stack); inventory.RemoveItem(item2, num); amount -= num; } } CountCache.Clear(); return amount; } } internal class NetworkPanel : MonoBehaviour { private enum Tab { Overview, ItemTags, Range } private const int Columns = 6; private const float Gap = 4f; private InventoryGui _builtFor; private RectTransform _root; private float _width; private bool _offsetDirty = true; private readonly List<TMP_InputField> _inputs = new List<TMP_InputField>(); private Container _current; private float _nextRefresh; private int _seenRevision = -1; private Tab _tab; private Button[] _roleButtons; private Button _lockButton; private Image _lockIcon; private GameObject _noneSection; private GameObject _storageSection; private GameObject _inputSection; private TMP_Text _info; private Button[] _tabButtons; private GameObject[] _tabPages; private List<string> _nearbyTags = new List<string>(); private List<string> _contentTags = new List<string>(); private List<KeyValuePair<string, string>> _chestItems = new List<KeyValuePair<string, string>>(); private TMP_InputField _ovSearch; private Button _ovSort; private bool _ovByCount; private RectTransform _ovContent; private readonly List<UiKit.Slot> _slots = new List<UiKit.Slot>(); private readonly Dictionary<string, SortService.OverviewEntry> _ovByPrefab = new Dictionary<string, SortService.OverviewEntry>(StringComparer.OrdinalIgnoreCase); private List<SortService.OverviewEntry> _overview = new List<SortService.OverviewEntry>(); private TMP_Text _ovEmpty; private TMP_Text _ovHover; private TMP_Text _ovFooter; private Button _ovStop; private TMP_Text _tagStatus; private TMP_InputField _tagSearch; private RectTransform _tagList; private string _tagListKey; private GameObject _editor; private TMP_Text _editorTitle; private TMP_Text _editorPreview; private TMP_InputField _editorTags; private RectTransform _editorChips; private string _editorChipsKey; private string _selectedPrefab; private TMP_Text _rangeCurrent; private TMP_Text _rangeValue; private TMP_Text _rangeChange; private TMP_Text _confirmText; private Slider _rangeSlider; private Button _rangeSave; private Button _rangeDefault; private GameObject _rangeButtons; private GameObject _rangeConfirm; private float _pendingRange; private List<SortService.Target> _dropped = new List<SortService.Target>(); private int _gained; private bool _confirmIsDefault; private TMP_Text _storageInfo; private TMP_InputField _storageTags; private RectTransform _storageChips; private string _storageChipsKey; internal static bool IsTyping { get; private set; } internal static bool Failed { get; private set; } private void Update() { Container val = ((Plugin.ClassicPanel.Value || Failed) ? null : VisibleContainer()); if ((Object)(object)val == (Object)null) { Hide(); } else if (EnsureBuilt()) { if ((Object)(object)val != (Object)(object)_current) { ResetFor(val); } if (!((Component)_root).gameObject.activeSelf) { ((Component)_root).gameObject.SetActive(true); } UpdatePlacement(); if (_seenRevision != GlobalItemTags.Revision || Time.unscaledTime >= _nextRefresh) { Refresh(); } UpdateFooter(); IsTyping = _inputs.Any((TMP_InputField i) => (Object)(object)i != (Object)null && i.isFocused); if (IsTyping && Input.GetKeyDown((KeyCode)27)) { Unfocus(); } } } private void Hide() { IsTyping = false; _current = null; if ((Object)(object)_root != (Object)null && ((Component)_root).gameObject.activeSelf) { Unfocus(); ((Component)_root).gameObject.SetActive(false); } } private void Unfocus() { foreach (TMP_InputField input in _inputs) { if ((Object)(object)input != (Object)null && input.isFocused) { input.DeactivateInputField(false); } } if ((Object)(object)EventSystem.current != (Object)null) { EventSystem.current.SetSelectedGameObject((GameObject)null); } IsTyping = false; } private static Container VisibleContainer() { if (!Plugin.ShowWindow.Value || (Object)(object)Player.m_localPlayer == (Object)null) { return null; } if ((Object)(object)InventoryGui.instance == (Object)null || !InventoryGui.IsVisible()) { return null; } Container val = Patches.CurrentContainer(InventoryGui.instance); if (!((Object)(object)val != (Object)null) || !ChestConfig.IsEligible(val)) { return null; } return val; } private bool EnsureBuilt() { if ((Object)(object)_root != (Object)null && (Object)(object)_builtFor == (Object)(object)InventoryGui.instance) { return true; } if ((Object)(object)_root != (Object)null) { Object.Destroy((Object)(object)((Component)_root).gameObject); } _root = null; _inputs.Clear(); _slots.Clear(); _current = null; try { Build(InventoryGui.instance); _builtFor = InventoryGui.instance; return true; } catch (Exception ex) { Plugin.Log.LogError((object)("Could not build the in-game Storage Network panel; using the classic panel instead.\n" + ex)); Failed = true; if ((Object)(object)_root != (Object)null) { Object.Destroy((Object)(object)((Component)_root).gameObject); } _root = null; return false; } } private void UpdatePlacement() { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) InventoryGui instance = InventoryGui.instance; if (_offsetDirty) { _offsetDirty = false; _root.anchoredPosition = new Vector2(ComputeOffsetX(instance), 0f); } float num = 620f; if ((Object)(object)instance.m_container != (Object)null && ((Component)instance.m_container).gameObject.activeInHierarchy) { Vector3[] array = (Vector3[])(object)new Vector3[4]; Vector3[] array2 = (Vector3[])(object)new Vector3[4]; instance.m_player.GetWorldCorners(array); instance.m_container.GetWorldCorners(array2); float y = ((Transform)instance.m_player).InverseTransformPoint(array[1]).y; float y2 = ((Transform)instance.m_player).InverseTransformPoint(array2[0]).y; if (y - y2 > 100f) { num = y - y2; } } num = Mathf.Max(num, 560f); Vector2 val = default(Vector2); ((Vector2)(ref val))..ctor(_width, num); if (_root.sizeDelta != val) { _root.sizeDelta = val; } } private float ComputeOffsetX(InventoryGui gui) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) Rect rect = gui.m_player.rect; float xMax = ((Rect)(ref rect)).xMax; float right = xMax; Vector3[] corners = (Vector3[])(object)new Vector3[4]; Scan(gui.m_player); Scan(gui.m_container); return right - xMax + 10f; void Scan(RectTransform parent) { //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)parent == (Object)null) && ((Component)parent).gameObject.activeInHierarchy) { RectTransform[] componentsInChildren = ((Component)parent).GetComponentsInChildren<RectTransform>(false); foreach (RectTransform val in componentsInChildren) { if (!((Object)(object)val == (Object)(object)_root) && !((Transform)val).IsChildOf((Transform)(object)_root)) { val.GetWorldCorners(corners); float x = ((Transform)gui.m_player).InverseTransformPoint(corners[2]).x; if (x > right && x < xMax + 220f) { right = x; } } } } } } private void ResetFor(Container c) { _offsetDirty = true; _current = c; Unfocus(); _selectedPrefab = null; _editor.SetActive(false); _storageTags.text = string.Join(", ", ChestConfig.GetTags(c).ToArray()); _ovSearch.text = ""; _tagSearch.text = ""; _tagListKey = null; _storageChipsKey = null; _editorChipsKey = null; _pendingRange = ChestConfig.GetRange(c); _rangeConfirm.SetActive(false); _nextRefresh = 0f; Refresh(); } private void Build(InventoryGui gui) { //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Expected O, but got Unknown //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Expected O, but got Unknown //IL_0183: Unknown result type (might be due to invalid IL or missing references) UiKit.Init(gui); _width = 6f * UiKit.SlotSize.x + 20f + 12f + 40f; GameObject val = UiKit.NewUi("StorageNetworkPanel", (Transform)(object)gui.m_player); val.AddComponent<NetworkPanelMarker>(); _root = (RectTransform)val.transform; RectTransform root = _root; RectTransform root2 = _root; Vector2 val2 = default(Vector2); ((Vector2)(ref val2))..ctor(1f, 1f); root2.anchorMax = val2; root.anchorMin = val2; _root.pivot = new Vector2(0f, 1f); _root.anchoredPosition = new Vector2(14f, 0f); _root.sizeDelta = new Vector2(_width, 620f); ((Graphic)UiKit.Panel(val, new Color(0.29f, 0.2f, 0.14f, 0.97f))).raycastTarget = true; VerticalLayoutGroup obj = val.AddComponent<VerticalLayoutGroup>(); ((LayoutGroup)obj).padding = new RectOffset(20, 20, 16, 20); ((HorizontalOrVerticalLayoutGroup)obj).spacing = 8f; ((HorizontalOrVerticalLayoutGroup)obj).childControlWidth = true; ((HorizontalOrVerticalLayoutGroup)obj).childControlHeight = true; ((HorizontalOrVerticalLayoutGroup)obj).childForceExpandWidth = true; ((HorizontalOrVerticalLayoutGroup)obj).childForceExpandHeight = false; Transform transform = UiKit.Row((Transform)(object)_root, 34f).transform; UiKit.Layout(UiKit.NewUi("Spacer", transform), -1f, 34f); UiKit.Layout((Component)(object)UiKit.Label(transform, "STORAGE NETWORK", 26f, UiKit.Orange, norse: true, (TextAlignmentOptions)514), -1f, -1f, 1f); _lockButton = UiKit.IconButton(transform, UiKit.LockSprite(closed: false), 34f, ToggleLock, out _lockIcon); Transform transform2 = UiKit.Row((Transform)(object)_root, 30f, 4f).transform; _roleButtons = (Button[])(object)new Button[3] { UiKit.MakeButton(transform2, "None", delegate { SetRole(ChestRole.None); }, -1f, 30f, 16f), UiKit.MakeButton(transform2, "Input", delegate { SetRole(ChestRole.Input); }, -1f, 30f, 16f), UiKit.MakeButton(transform2, "Storage", delegate { SetRole(ChestRole.Storage); }, -1f, 30f, 16f) }; UiKit.Divider((Transform)(object)_root); BuildNoneSection(); BuildStorageSection(); BuildInputSection(); val.SetActive(false); } private void BuildNoneSection() { //IL_0055: Unknown result type (might be due to invalid IL or missing references) _noneSection = UiKit.Column((Transform)(object)_root, 8f, "None"); UiKit.Layout(_noneSection, -1f, -1f, -1f, 1f); UiKit.Label(_noneSection.transform, "<color=#FFB04A>Input</color>: dump items here. They're sent to matching storage chests when you close it.\n\n<color=#FFB04A>Storage</color>: receives items whose tags match this chest's tags.", 17f, UiKit.TextColor, norse: false, (TextAlignmentOptions)513); } private void BuildStorageSection() { //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) _storageSection = UiKit.Column((Transform)(object)_root, 8f, "Storage"); UiKit.Layout(_storageSection, -1f, -1f, -1f, 1f); Transform transform = _storageSection.transform; _storageInfo = (TMP_Text)(object)UiKit.Label(transform, "", 15f, UiKit.Muted, norse: false, (TextAlignmentOptions)513); UiKit.Label(transform, "Chest tags (comma separated)", 18f, UiKit.Orange, norse: false, (TextAlignmentOptions)513); _storageTags = UiKit.MakeInput(transform, "e.g. PlainsFood, PlainsMobDrops"); _inputs.Add(_storageTags); Transform transform2 = UiKit.Row(transform, 34f).transform; UiKit.MakeButton(transform2, "Apply", delegate { ChestConfig.SetTags(_current, TagDatabase.ParseList(_storageTags.text)); _storageTags.text = string.Join(", ", ChestConfig.GetTags(_current).ToArray()); Unfocus(); RefreshSoon(); }); UiKit.MakeButton(transform2, "Revert", delegate { _storageTags.text = string.Join(", ", ChestConfig.GetTags(_current).ToArray()); Unfocus(); }); UiKit.Label(transform, "Tip: '" + Plugin.OverflowTag.Value + "' makes this an overflow chest. An item's prefab name (e.g. BlackMetalScrap) as a tag targets that exact item. Click a tag below to add it.", 14f, UiKit.Muted, norse: false, (TextAlignmentOptions)513); _storageChips = UiKit.MakeScroll(transform, 120f, out var _, 64f); AddChipGrid(_storageChips); } private void BuildInputSection() { //IL_006e: Unknown result type (might be due to invalid IL or missing references) _inputSection = UiKit.Column((Transform)(object)_root, 8f, "Input"); UiKit.Layout(_inputSection, -1f, -1f, -1f, 1f); Transform transform = _inputSection.transform; Transform transform2 = UiKit.Row(transform, 30f).transform; _info = (TMP_Text)(object)UiKit.Label(transform2, "", 16f, UiKit.TextColor, norse: false, (TextAlignmentOptions)513); _info.alignment = (TextAlignmentOptions)4097; UiKit.Layout((Component)(object)_info, -1f, -1f, 1f); UiKit.StyleAction(UiKit.MakeButton(transform2, "Sort now", delegate { SortService.SortInput(_current, quiet: false); RefreshSoon(); }, 120f, 30f, 16f)); Transform transform3 = UiKit.Row(transform, 30f, 4f).transform; _tabButtons = (Button[])(object)new Button[3] { UiKit.MakeButton(transform3, "Overview", delegate { SetTab(Tab.Overview); }, -1f, 30f, 16f), UiKit.MakeButton(transform3, "Item tags", delegate { SetTab(Tab.ItemTags); }, -1f, 30f, 16f), UiKit.MakeButton(transform3, "Range", delegate { SetTab(Tab.Range); }, -1f, 30f, 16f) }; _tabPages = (GameObject[])(object)new GameObject[3] { BuildOverviewPage(transform), BuildItemTagsPage(transform), BuildRangePage(transform) }; SetTab(_tab); } private GameObject BuildOverviewPage(Transform parent) { //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_0105: 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_011e: Expected O, but got Unknown //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_0158: 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) GameObject obj = UiKit.Column(parent, 6f, "Overview"); UiKit.Layout(obj, -1f, -1f, -1f, 1f); Transform transform = obj.transform; Transform transform2 = UiKit.Row(transform, 34f).transform; _ovSearch = UiKit.MakeInput(transform2, "Search items"); ((UnityEvent<string>)(object)_ovSearch.onValueChanged).AddListener((UnityAction<string>)delegate { RefreshOverviewSlots(); }); _inputs.Add(_ovSearch); _ovSort = UiKit.MakeButton(transform2, "By name", delegate { _ovByCount = !_ovByCount; UiKit.SetButtonText(_ovSort, _ovByCount ? "By count" : "By name"); RefreshOverviewSlots(); }, 110f, 34f, 15f); _ovContent = UiKit.MakeScroll(transform, 140f, out var _, UiKit.SlotSize.y + 4f); GridLayoutGroup obj2 = ((Component)_ovContent).gameObject.AddComponent<GridLayoutGroup>(); obj2.cellSize = UiKit.SlotSize; obj2.spacing = new Vector2(4f, 4f); ((LayoutGroup)obj2).padding = new RectOffset(2, 2, 2, 2); obj2.constraint = (Constraint)1; obj2.constraintCount = 6; _ovEmpty = (TMP_Text)(object)UiKit.Label(transform, "", 15f, UiKit.Muted, norse: false, (TextAlignmentOptions)513); _ovHover = (TMP_Text)(object)UiKit.Label(transform, " ", 15f, UiKit.TextColor, norse: false, (TextAlignmentOptions)513); UiKit.Layout((Component)(object)_ovHover, 20f); Transform transform3 = UiKit.Row(transform, 34f).transform; _ovFooter = (TMP_Text)(object)UiKit.Label(transform3, "", 14f, UiKit.Muted, norse: false, (TextAlignmentOptions)513); _ovFooter.alignment = (TextAlignmentOptions)4097; UiKit.Layout((Component)(object)_ovFooter, -1f, -1f, 1f); _ovStop = UiKit.MakeButton(transform3, "Stop", delegate { FlashManager.Clear(); UpdateSlotSelection(); }, 80f, 34f, 15f); return obj; } private GameObject BuildItemTagsPage(Transform parent) { //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_01c0: Unknown result type (might be due to invalid IL or missing references) //IL_01e4: Unknown result type (might be due to invalid IL or missing references) //IL_01ee: Expected O, but got Unknown //IL_0205: Unknown result type (might be due to invalid IL or missing references) GameObject obj = UiKit.Column(parent, 6f, "ItemTags"); UiKit.Layout(obj, -1f, -1f, -1f, 1f); Transform transform = obj.transform; _tagStatus = (TMP_Text)(object)UiKit.Label(transform, "", 14f, UiKit.Warn, norse: false, (TextAlignmentOptions)513); _tagSearch = UiKit.MakeInput(transform, "Search all items (2+ letters)"); ((UnityEvent<string>)(object)_tagSearch.onValueChanged).AddListener((UnityAction<string>)delegate { RebuildTagList(); }); _inputs.Add(_tagSearch); _tagList = UiKit.MakeScroll(transform, 110f, out var _, 90f); VerticalLayoutGroup obj2 = ((Component)_tagList).gameObject.AddComponent<VerticalLayoutGroup>(); ((HorizontalOrVerticalLayoutGroup)obj2).spacing = 2f; ((HorizontalOrVerticalLayoutGroup)obj2).childControlWidth = true; ((HorizontalOrVerticalLayoutGroup)obj2).childControlHeight = true; ((HorizontalOrVerticalLayoutGroup)obj2).childForceExpandWidth = true; ((HorizontalOrVerticalLayoutGroup)obj2).childForceExpandHeight = false; _editor = UiKit.Column(transform, 6f, "Editor"); Transform transform2 = _editor.transform; _editorTitle = (TMP_Text)(object)UiKit.Label(transform2, "", 20f, UiKit.Orange, norse: true, (TextAlignmentOptions)513); _editorTags = UiKit.MakeInput(transform2, "Tags, comma separated"); _inputs.Add(_editorTags); Transform transform3 = UiKit.Row(transform2, 34f).transform; UiKit.MakeButton(transform3, "Save", delegate { if (GlobalItemTags.Ready && _selectedPrefab != null) { GlobalItemTags.Set(_selectedPrefab, TagDatabase.ParseList(_editorTags.text)); Unfocus(); UpdateEditorState(); } }); UiKit.MakeButton(transform3, "Reset to defaults", delegate { if (GlobalItemTags.Ready && _selectedPrefab != null) { GlobalItemTags.Set(_selectedPrefab, null); SelectItem(_selectedPrefab); } }); UiKit.Label(transform2, "Item tags apply to every input chest in this world and replace the item's default tags.", 13f, UiKit.Muted, norse: false, (TextAlignmentOptions)513); GameObject val = UiKit.NewUi("Chips", transform2); _editorChips = (RectTransform)val.transform; AddChipGrid(_editorChips); _editorPreview = (TMP_Text)(object)UiKit.Label(transform2, "", 15f, UiKit.TextColor, norse: false, (TextAlignmentOptions)513); _editor.SetActive(false); return obj; } private GameObject BuildRangePage(Transform parent) { //IL_0043: 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_0168: 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_0232: Expected O, but got Unknown //IL_0251: Unknown result type (might be due to invalid IL or missing references) //IL_0270: Unknown result type (might be due to invalid IL or missing references) //IL_02b5: Unknown result type (might be due to invalid IL or missing references) //IL_0397: Unknown result type (might be due to invalid IL or missing references) GameObject obj = UiKit.Column(parent, 8f, "Range"); UiKit.Layout(obj, -1f, -1f, -1f, 1f); Transform transform = obj.transform; _rangeCurrent = (TMP_Text)(object)UiKit.Label(transform, "", 19f, UiKit.Orange, norse: false, (TextAlignmentOptions)513); Transform transform2 = UiKit.Row(transform, 34f).transform; UiKit.MakeButton(transform2, "-", delegate { SetPendingRange(_pendingRange - 1f); }, 38f, 34f, 20f); _rangeSlider = UiKit.MakeSlider(transform2, 2f, 100f, delegate(float v) { SetPendingRange(v); }); if ((Object)(object)_rangeSlider == (Object)null) { UiKit.Layout(UiKit.NewUi("Spacer", transform2), -1f, -1f, 1f); } UiKit.MakeButton(transform2, "+", delegate { SetPendingRange(_pendingRange + 1f); }, 38f, 34f, 20f); _rangeValue = (TMP_Text)(object)UiKit.Label(transform2, "", 19f, UiKit.Orange, norse: false, (TextAlignmentOptions)4100); UiKit.Layout((Component)(object)_rangeValue, -1f, 64f); _rangeChange = (TMP_Text)(object)UiKit.Label(transform, " ", 15f, UiKit.Muted, norse: false, (TextAlignmentOptions)513); _rangeButtons = UiKit.Row(transform, 36f); _rangeSave = UiKit.MakeButton(_rangeButtons.transform, "Save range", delegate { TryApplyRange(_pendingRange, isDefault: false); }); _rangeDefault = UiKit.MakeButton(_rangeButtons.transform, "Use default", delegate { TryApplyRange(ChestConfig.DefaultRange, isDefault: true); }); _rangeConfirm = UiKit.Column(transform, 8f, "Confirm"); ((LayoutGroup)_rangeConfirm.GetComponent<VerticalLayoutGroup>()).padding = new RectOffset(12, 12, 10, 12); ((Graphic)_rangeConfirm.AddComponent<Image>()).color = new Color(0.08f, 0.05f, 0.03f, 0.85f); UiKit.Layout((Component)(object)UiKit.Label(_rangeConfirm.transform, "Lower the range?", 22f, UiKit.Orange, norse: true, (TextAlignmentOptions)514), 28f); _confirmText = (TMP_Text)(object)UiKit.Label(_rangeConfirm.transform, "", 15f, UiKit.TextColor, norse: false, (TextAlignmentOptions)513); Transform transform3 = UiKit.Row(_rangeConfirm.transform, 34f).transform; UiKit.MakeButton(transform3, "Lower range", delegate { CommitRange(_pendingRange, _confirmIsDefault); }, -1f, 34f, 16f); UiKit.MakeButton(transform3, "Cancel", delegate { _rangeConfirm.SetActive(false); SetPendingRange(ChestConfig.GetRange(_current)); }, -1f, 34f, 16f); UiKit.MakeButton(_rangeConfirm.transform, "Make these chests flash", delegate { //IL_002a: Unknown result type (might be due to invalid IL or missing references) List<ZDOID> list = new List<ZDOID>(); foreach (SortService.Target item in _dropped) { if (ChestConfig.TryGetId(item.Container, out var id)) { list.Add(id); } } FlashManager.Set(null, list); }, -1f, 32f, 15f); _rangeConfirm.SetActive(false); UiKit.Label(transform, $"Storage chests within this distance of the input chest belong to its network ({2f:0}–{100f:0} m).", 14f, UiKit.Muted, norse: false, (TextAlignmentOptions)513); return obj; } private static void AddChipGrid(RectTransform content) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Expected O, but got Unknown //IL_0047: Unknown result type (might be due to invalid IL or missing references) GridLayoutGroup obj = ((Component)content).gameObject.AddComponent<GridLayoutGroup>(); obj.constraint = (Constraint)1; obj.constraintCount = 3; obj.spacing = new Vector2(4f, 4f); ((LayoutGroup)obj).padding = new RectOffset(2, 2, 2, 2); obj.cellSize = new Vector2(128f, 28f); } private void FitChipCells(RectTransform content) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) GridLayoutGroup component = ((Component)content).GetComponent<GridLayoutGroup>(); Rect rect = content.rect; float num = ((Rect)(ref rect)).width; if (num < 60f) { num = _width - 60f; } component.cellSize = new Vector2(Mathf.Floor((num - 4f - 8f) / 3f), 28f); } private void ToggleLock() { if (!((Object)(object)_current == (Object)null)) { ChestConfig.SetLocked(_current, !ChestConfig.IsLocked(_current)); RefreshSoon(); } } private void SetRole(ChestRole role) { if (!((Object)(object)_current == (Object)null) && ChestConfig.SetRole(_current, role)) { _pendingRange = ChestConfig.GetRange(_current); RefreshSoon(); } } private void SetTab(Tab tab) { _tab = tab; for (int i = 0; i < _tabPages.Length; i++) { _tabPages[i].SetActive(i == (int)tab); } for (int j = 0; j < _tabButtons.Length; j++) { UiKit.SetActiveStyle(_tabButtons[j], j == (int)tab); } Unfocus(); if ((Object)(object)_current != (Object)null && tab == Tab.Range) { _rangeConfirm.SetActive(false); SetPendingRange(ChestConfig.GetRange(_current)); } } private void RefreshSoon() { _nextRefresh = 0f; } private void Refresh() { //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: 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) _nextRefresh = Time.unscaledTime + 1f; _seenRevision = GlobalItemTags.Revision; if ((Object)(object)_current == (Object)null) { return; } GlobalItemTags.MigrateLegacy(_current); ChestRole role = ChestConfig.GetRole(_current); bool flag = ChestConfig.IsLocked(_current); for (int i = 0; i < _roleButtons.Length; i++) { UiKit.SetActiveStyle(_roleButtons[i], i == (int)role); ((Selectable)_roleButtons[i]).interactable = !flag || i == (int)role; } _lockIcon.sprite = UiKit.LockSprite(flag); ((Graphic)_lockIcon).color = (Color)(flag ? UiKit.Orange : new Color(UiKit.Muted.r, UiKit.Muted.g, UiKit.Muted.b, 0.75f)); _noneSection.SetActive(role == ChestRole.None); _storageSection.SetActive(role == ChestRole.Storage); _inputSection.SetActive(role == ChestRole.Input); float num = ((role == ChestRole.Input) ? ChestConfig.GetRange(_current) : ChestConfig.DefaultRange); HashSet<string> hashSet = TagDatabase.NewSet(); hashSet.UnionWith(GlobalItemTags.AllUsedTags()); int num2 = 0; foreach (Container item in ContainerTracker.InRange(((Component)_current).transform.position, num)) { if (!((Object)(object)item == (Object)(object)_current) && ChestConfig.GetRole(item) == ChestRole.Storage) { num2++; hashSet.UnionWith(ChestConfig.GetTags(item)); } } _nearbyTags = hashSet.OrderBy<string, string>((string x) => x, StringComparer.OrdinalIgnoreCase).ToList(); HashSet<string> hashSet2 = TagDatabase.NewSet(); HashSet<string> hashSet3 = TagDatabase.NewSet(); _chestItems = new List<KeyValuePair<string, string>>(); Inventory inventory = _current.GetInventory(); if (inventory != null) { foreach (ItemData allItem in inventory.GetAllItems()) { string text = TagDatabase.PrefabName(allItem); if (hashSet2.Add(text)) { _chestItems.Add(new KeyValuePair<string, string>(text, TagDatabase.DisplayName(allItem))); hashSet3.UnionWith(TagDatabase.GetDefaultTags(text)); } } } _chestItems.Sort((KeyValuePair<string, string> a, KeyValuePair<string, string> b) => string.Compare(a.Value, b.Value, StringComparison.OrdinalIgnoreCase)); _contentTags = hashSet3.OrderBy<string, string>((string x) => x, StringComparer.OrdinalIgnoreCase).ToList(); switch (role) { case ChestRole.Storage: RefreshStorage(); break; case ChestRole.Input: _info.text = string.Format("{0} storage chest{1} within <color=#FFB04A>{2:0} m</color>", num2, (num2 == 1) ? "" : "s", num); _overview = SortService.BuildOverview(_current); RefreshOverviewSlots(); RefreshItemTags(); RefreshRange(); break; } } private void RefreshStorage() { int num = SortService.InputsCovering(_current); _storageInfo.text = ((num == 0) ? "Not in range of any input chest." : string.Format("Part of {0} input chest network{1}.", num, (num == 1) ? "" : "s")); List<string> tags = _nearbyTags.Take(30).Concat(_contentTags.Take(60)).Distinct<string>(StringComparer.OrdinalIgnoreCase) .ToList(); RebuildChips(_storageChips, tags, ref _storageChipsKey, delegate(string tag) { _storageTags.text = AddTag(_storageTags.text, tag); }); } private void RebuildChips(RectTransform content, List<string> tags, ref string key, Action<string> onPick) { string text = string.Join("|", tags.ToArray()); if (text == key) { return; } key = text; FitChipCells(content); UiKit.Clear((Transform)(object)content); foreach (string tag in tags) { string captured = tag; UiKit.FlatButton((Transform)(object)content, tag, delegate { onPick(captured); }, 28f, 14f, (TextAlignmentOptions)514); } } private static string AddTag(string buffer, string tag) { List<string> list = TagDatabase.ParseList(buffer); if (!list.Contains<string>(tag, StringComparer.OrdinalIgnoreCase)) { list.Add(tag); } return string.Join(", ", list.ToArray()); } private void RefreshOverviewSlots() { if ((Object)(object)_ovContent == (Object)null) { return; } _ovByPrefab.Clear(); foreach (SortService.OverviewEntry item in _overview) { _ovByPrefab[item.Prefab] = item; } string q = _ovSearch.text.Trim(); IEnumerable<SortService.OverviewEntry> source = _overview; if (q.Length > 0) { source = source.Where((SortService.OverviewEntry e) => e.Display.IndexOf(q, StringComparison.OrdinalIgnoreCase) >= 0 || e.Prefab.IndexOf(q, StringComparison.OrdinalIgnoreCase) >= 0); } source = (_ovByCount ? source.OrderByDescending((SortService.OverviewEntry e) => e.Count).ThenBy<SortService.OverviewEntry, string>((SortService.OverviewEntry e) => e.Display, StringComparer.OrdinalIgnoreCase) : source.OrderBy<SortService.OverviewEntry, string>((SortService.OverviewEntry e) => e.Display, StringComparer.OrdinalIgnoreCase)); List<SortService.OverviewEntry> list = source.ToList(); while (_slots.Count < list.Count) { UiKit.Slot slot = UiKit.MakeSlot((Transform)(object)_ovContent); slot.Clicked = OnSlotClicked; slot.Hovered = OnSlotHovered; _slots.Add(slot); } for (int num = 0; num < _slots.Count; num++) { UiKit.Slot slot2 = _slots[num]; if (num >= list.Count) { ((Component)slot2).gameObject.SetActive(false); continue; } SortService.OverviewEntry overviewEntry = list[num]; ((Component)slot2).gameObject.SetActive(true); slot2.Prefab = overviewEntry.Prefab; if ((Object)(object)slot2.Icon != (Object)null) { ItemData val = TagDatabase.FindItemData(overviewEntry.Prefab); Sprite val2 = ((val != null) ? val.GetIcon() : null); slot2.Icon.sprite = val2; ((Behaviour)slot2.Icon).enabled = (Object)(object)val2 != (Object)null; } if ((Object)(object)slot2.Amount != (Object)null) { slot2.Amount.text = overviewEntry.Count.ToString(); } if ((Object)(object)slot2.Corner != (Object)null) { slot2.Corner.text = "x" + overviewEntry.Chests.Count; } slot2.SetSelected(FlashManager.IsSelected(overviewEntry.Prefab)); } _ovEmpty.text = ((_overview.Count == 0) ? "The storage chests in this network are empty." : ((list.Count == 0) ? "No items match your search." : "")); ((Component)_ovEmpty).gameObject.SetActive(_ovEmpty.text.Length > 0); } private void UpdateSlotSelection() { foreach (UiKit.Slot slot in _slots) { if (((Component)slot).gameObject.activeSelf) { slot.SetSelected(FlashManager.IsSelected(slot.Prefab)); } } } private void OnSlotHovered(UiKit.Slot slot, bool enter) { if (!enter || slot.Prefab == null || !_ovByPrefab.TryGetValue(slot.Prefab, out var value)) { _ovHover.text = " "; return; } int count = value.Chests.Count; _ovHover.text = string.Format("<color=#FFB04A>{0}</color>: {1:N0} in {2} chest{3}", value.Display, value.Count, count, (count == 1) ? "" : "s"); } private void OnSlotClicked(UiKit.Slot slot, bool additive) { string prefab = slot.Prefab; if (prefab == null) { return; } HashSet<string> hashSet = new HashSet<string>(FlashManager.SelectedPrefabs, StringComparer.OrdinalIgnoreCase); if (additive) { if (!hashSet.Remove(prefab)) { hashSet.Add(prefab); } } else if (hashSet.Count == 1 && hashSet.Contains(prefab)) { hashSet.Clear(); } else { hashSet.Clear(); hashSet.Add(prefab); } HashSet<ZDOID> hashSet2 = new HashSet<ZDOID>(); foreach (SortService.OverviewEntry item in _overview) { if (hashSet.Contains(item.Prefab)) { hashSet2.UnionWith(item.Chests); } } if (hashSet.Count == 0) { FlashManager.Clear(); } else { FlashManager.Set(hashSet, hashSet2); } UpdateSlotSelection(); } private void UpdateFooter() { if (!((Object)(object)_ovFooter == (Object)null) && _inputSection.activeSelf) { int flashingCount = FlashManager.FlashingCount; string text = ((flashingCount > 0) ? string.Format("{0} chest{1} flashing until opened.", flashingCount, (flashingCount == 1) ? " is" : "s are") : "Click an item to make its chests flash. Ctrl+Click to select several."); if (_ovFooter.text != text) { _ovFooter.text = text; UpdateSlotSelection(); } if (((Component)_ovStop).gameObject.activeSelf != flashingCount > 0) { ((Component)_ovStop).gameObject.SetActive(flashingCount > 0); } } } private void RefreshItemTags() { string statusText = GlobalItemTags.StatusText; _tagStatus.text = statusText ?? ""; ((Component)_tagStatus).gameObject.SetActive(statusText != null); RebuildTagList(); if (_selectedPrefab != null) { UpdateEditorState(); } } private void RebuildTagList() { //IL_0181: Unknown result type (might be due to invalid IL or missing references) string text = _tagSearch.text.Trim(); List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>(); string text3; if (text.Length >= 2) { foreach (ItemDrop item in TagDatabase.AllItems()) { string name = ((Object)((Component)item).gameObject).name; string text2 = TagDatabase.DisplayName(item.m_itemData); if (name.IndexOf(text, StringComparison.OrdinalIgnoreCase) >= 0 || text2.IndexOf(text, StringComparison.OrdinalIgnoreCase) >= 0) { list.Add(new KeyValuePair<string, string>(name, text2)); if (list.Count >= 60) { break; } } } list.Sort((KeyValuePair<string, string> a, KeyValuePair<string, string> b) => string.Compare(a.Value, b.Value, StringComparison.OrdinalIgnoreCase)); text3 = ((list.Count == 0) ? "No items found." : null); } else { list = _chestItems; text3 = ((list.Count == 0) ? "This chest is empty. Search to tag any item." : "In this chest:"); } string text4 = text + "#" + _selectedPrefab + "#" + string.Join("|", list.Select((KeyValuePair<string, string> r) => r.Key).ToArray()); if (text4 == _tagListKey) { return; } _tagListKey = text4; UiKit.Clear((Transform)(object)_tagList); if (text3 != null) { UiKit.Layout((Component)(object)UiKit.Label((Transform)(object)_tagList, text3, 14f, UiKit.Muted, norse: false, (TextAlignmentOptions)513), 22f); } foreach (KeyValuePair<string, string> item2 in list) { string prefab = item2.Key; bool flag = string.Equals(prefab, _selectedPrefab, StringComparison.OrdinalIgnoreCase); string text5 = (flag ? "<color=#FFB04A>" : "") + item2.Value + (flag ? "</color>" : "") + " <color=#A8987E><size=80%>" + prefab + "</size></color>"; UiKit.FlatButton((Transform)(object)_tagList, text5, delegate { SelectItem(prefab); }, 28f, 15f, (TextAlignmentOptions)4097); } } private void SelectItem(string prefab) { _selectedPrefab = prefab; SortService.ItemTags itemTags = SortService.ResolveTags(prefab); List<string> tags; HashSet<string> source = (GlobalItemTags.TryGet(prefab, out tags) ? itemTags.User : itemTags.Defaults); _editorTags.text = string.Join(", ", source.OrderBy<string, string>((string x) => x, StringComparer.OrdinalIgnoreCase).ToArray()); _editor.SetActive(true); Unfocus(); UpdateEditorState(); RebuildTagList(); } private void UpdateEditorState() { if (_selectedPrefab != null) { ItemData val = TagDatabase.FindItemData(_selectedPrefab); string text = ((val != null) ? TagDatabase.DisplayName(val) : _selectedPrefab); List<string> tags; bool flag = GlobalItemTags.TryGet(_selectedPrefab, out tags); _editorTitle.text = text + (flag ? " <size=65%><color=#CDB898>custom tags</color></size>" : " <size=65%><color=#CDB898>default tags</color></size>"); _editorPreview.text = SortService.Preview(_current, _selectedPrefab); RebuildChips(_editorChips, _nearbyTags.Take(12).ToList(), ref _editorChipsKey, delegate(string tag) { _editorTags.text = AddTag(_editorTags.text, tag); }); } } private void RefreshRange() { float range = ChestConfig.GetRange(_current); bool flag = ChestConfig.HasCustomRange(_current); _rangeCurrent.text = $"Current range: {range:0} m" + (flag ? "" : " <size=75%><color=#CDB898>(default)</color></size>"); UiKit.SetButtonText(_rangeDefault, $"Use default ({ChestConfig.DefaultRange:0} m)"); ((Selectable)_rangeDefault).interactable = flag; UpdateRangePreview(); } private void SetPendingRange(float value) { _pendingRange = Mathf.Clamp(Mathf.Round(value), 2f, 100f); if (_rangeConfirm.activeSelf) { _rangeConfirm.SetActive(false); } UpdateRangePreview(); } private void UpdateRangePreview() { //IL_013d: 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_00c8: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_current == (Object)null)) { float range = ChestConfig.GetRange(_current); if ((Object)(object)_rangeSlider != (Object)null) { _rangeSlider.SetValueWithoutNotify(_pendingRange); } _rangeValue.text = $"{_pendingRange:0} m"; _dropped = ((_pendingRange < range) ? SortService.StorageBetween(_current, _pendingRange, range) : new List<SortService.Target>()); _gained = ((_pendingRange > range) ? SortService.StorageBetween(_current, range, _pendingRange).Count : 0); if (_pendingRange < range) { ((Graphic)_rangeChange).color = ((_dropped.Count > 0) ? UiKit.Warn : UiKit.Muted); _rangeChange.text = ((_dropped.Count == 0) ? "No storage chests would leave the network." : string.Format("{0} storage chest{1} would leave the network.", _dropped.Count, (_dropped.Count == 1) ? "" : "s")); } else if (_pendingRange > range) { ((Graphic)_rangeChange).color = UiKit.Muted; _rangeChange.text = ((_gained == 0) ? "No extra storage chests in that range." : string.Format("{0} more storage chest{1} would join the network.", _gained, (_gained == 1) ? "" : "s")); } else { _rangeChange.text = " "; } ((Selectable)_rangeSave).interactable = Mathf.Abs(_pendingRange - range) > 0.01f; _rangeButtons.SetActive(!_rangeConfirm.activeSelf); } } private void TryApplyRange(float target, bool isDefault) { float range = ChestConfig.GetRange(_current); _pendingRange = target; UpdateRangePreview(); if (target < range - 0.01f && _dropped.Count > 0) { _confirmIsDefault = isDefault; StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append(string.Format("Going from {0:0} m to {1:0} m removes {2} storage chest{3} from this network:\n", range, target, _dropped.Count, (_dropped.Count == 1) ? "" : "s")); foreach (SortService.Target item in _dropped.Take(6)) { stringBuilder.Append(" • ").Append(item.Label()).Append('\n'); } if (_dropped.Count > 6) { stringBuilder.Append($" …and {_dropped.Count - 6} more\n"); } stringBuilder.Append("Their items stay where they are, but this input chest won't send anything there anymore."); _confirmText.text = stringBuilder.ToString(); _rangeConfirm.SetActive(true); _rangeButtons.SetActive(false); } else { CommitRange(target, isDefault); } } private void CommitRange(float target, bool isDefault) { ChestConfig.SetRange(_current, isDefault ? 0f : target); _rangeConfirm.SetActive(false); _pendingRange = ChestConfig.GetRange(_current); RefreshSoon(); RefreshRange(); } } internal class NetworkWindow : MonoBehaviour { private enum InputTab { Overview, ItemTags, Range } internal static bool IsTyping; private const int WindowId = 23166; private const float Width = 400f; private Rect _rect = new Rect(-1f, 90f, 400f, 10f); private bool _collapsed; private InputTab _tab; private Container _current; private float _nextRefresh; private int _seenRevision = -1; private int _storageCount; private List<string> _nearbyTags = new List<string>(); private List<string> _contentTags = new List<string>(); private string _chestTagsBuf = ""; private int _coveringInputs; private Vector2 _chipScroll; private string _search = ""; private string _lastSearch; private string _selectedPrefab; private string _itemTagsBuf = ""; private string _preview = ""; private bool _isCustom; private Vector2 _itemScroll; private List<KeyValuePair<string, string>> _chestItems = new List<KeyValuePair<string, string>>(); private readonly List<KeyValuePair<string, string>> _searchItems = new List<KeyValuePair<string, string>>(); private List<SortService.OverviewEntry> _overview = new List<SortService.OverviewEntry>(); private string _ovSearch = ""; private string _ovSearchApplied = ""; private bool _ovSortByCount; private Vector2 _ovScroll; private float _pendingRange; private float _previewedRange = -1f; private List<SortService.Target> _dropped = new List<SortService.Target>(); private int _gained; private bool _confirmLower; private bool _confirmIsDefault; private GUIStyle _wrap; private GUIStyle _header; private GUIStyle _small; private GUIStyle _chip; private GUIStyle _warn; private GUIStyle _row; private GUIStyle _rowSel; private GUIStyle _rowText; private GUIStyle _rowRight; private static bool IsLayout { get { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Invalid comparison between Unknown and I4 if (Event.current != null) { return (int)Event.current.type == 8; } return false; } } private void OnGUI() { //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0077: 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) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Expected O, but got Unknown //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) Container val = ((Plugin.ClassicPanel.Value || NetworkPanel.Failed) ? VisibleContainer() : null); if ((Object)(object)val == (Object)null) { IsTyping = false; _current = null; return; } if ((Object)(object)val != (Object)(object)_current) { ResetFor(val); } InitStyles(); float num = (float)Screen.height / 1080f * Plugin.UiScale.Value; GUI.matrix = Matrix4x4.TRS(Vector3.zero, Quaternion.identity, new Vector3(num, num, 1f)); if (((Rect)(ref _rect)).x < 0f) { ((Rect)(ref _rect)).x = (float)Screen.width / num - 400f - 30f; } ((Rect)(ref _rect)).height = 10f; _rect = GUILayout.Window(23166, _rect, new WindowFunction(DrawWindow), "Storage Network 1.0.0", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(400f) }); string nameOfFocusedControl = GUI.GetNameOfFocusedControl(); IsTyping = GUIUtility.keyboardControl != 0 && nameOfFocusedControl != null && nameOfFocusedControl.StartsWith("SN_"); } private static Container VisibleContainer() { if (!Plugin.ShowWindow.Value || (Object)(object)Player.m_localPlayer == (Object)null) { return null; } if ((Object)(object)InventoryGui.instance == (Object)null || !InventoryGui.IsVisible()) { return null; } Container val = Patches.CurrentContainer(InventoryGui.instance); if (!((Object)(object)val != (Object)null) || !ChestConfig.IsEligible(val)) { return null; } return val; } private void ResetFor(Container c) { _current = c; _chestTagsBuf = string.Join(", ", ChestConfig.GetTags(c).ToArray()); _selectedPrefab = null; _itemTagsBuf = ""; _preview = ""; _pendingRange = ChestConfig.GetRange(c); _previewedRange = -1f; _confirmLower = false; _nextRefresh = 0f; GUIUtility.keyboardControl = 0; } private void InitStyles() { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Expected O, but got Unknown //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Expected O, but got Unknown //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Expected O, but got Unknown //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: 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_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Expected O, but got Unknown //IL_00d9: Expected O, but got Unknown //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Expected O, but got Unknown //IL_010b: Expected O, but got Unknown //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_0144: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Expected O, but got Unknown //IL_0153: Expected O, but got Unknown //IL_0172: Unknown result type (might be due to invalid IL or missing references) //IL_01a0: Unknown result type (might be due to invalid IL or missing references) //IL_01b6: Unknown result type (might be due to invalid IL or missing references) //IL_01c0: Expected O, but got Unknown //IL_01df: Unknown result type (might be due to invalid IL or missing references) //IL_020d: Unknown result type (might be due to invalid IL or missing references) //IL_0227: Unknown result type (might be due to invalid IL or missing references) //IL_022c: Unknown result type (might be due to invalid IL or missing references) //IL_0238: Expected O, but got Unknown //IL_0243: 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_0254: Expected O, but got Unknown //IL_026e: Unknown result type (might be due to invalid IL or missing references) if (_wrap == null) { _wrap = new GUIStyle(GUI.skin.label) { wordWrap = true }; _small = new GUIStyle(GUI.skin.label) { wordWrap = true, fontSize = 11 }; _small.normal.textColor = new Color(0.8f, 0.8f, 0.8f); _header = new GUIStyle(GUI.skin.label) { fontStyle = (FontStyle)1 }; _header.normal.textColor = new Color(1f, 0.85f, 0.55f); _chip = new GUIStyle(GUI.skin.button) { fontSize = 11, padding = new RectOffset(4, 4, 2, 2) }; _warn = new GUIStyle(GUI.skin.box) { wordWrap = true, alignment = (TextAnchor)0, padding = new RectOffset(8, 8, 6, 6) }; _warn.normal.textColor = new Color(1f, 0.6f, 0.45f); _row = new GUIStyle(GUI.skin.label) { margin = new RectOffset(0, 0, 1, 1) }; _row.hover.background = MakeTex(new Color(1f, 1f, 1f, 0.08f)); _row.active.background = MakeTex(new Color(1f, 1f, 1f, 0.15f)); _rowSel = new GUIStyle(_row); _rowSel.normal.background = MakeTex(new Color(1f, 0.75f, 0.2f, 0.28f)); _rowSel.hover.background = MakeTex(new Color(1f, 0.75f, 0.2f, 0.36f)); _rowText = new GUIStyle(GUI.skin.label) { clipping = (TextClipping)1 }; _rowRight = new GUIStyle(GUI.skin.label) { alignment = (TextAnchor)2 }; _rowRight.normal.textColor = new Color(0.85f, 0.85f, 0.85f); } } private static void LayoutChanged() { GUIUtility.ExitGUI(); } private static Texture2D MakeTex(Color c) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: 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) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Expected O, but got Unknown Texture2D val = new Texture2D(1, 1) { hideFlags = (HideFlags)61 }; val.SetPixel(0, 0, c); val.Apply(); return val; } private void RefreshIfNeeded() { //IL_008d: Unknown result type (might be due to invalid IL or missing references) if (_seenRevision == GlobalItemTags.Revision && Time.unscaledTime < _nextRefresh) { return; } _nextRefresh = Time.unscaledTime + 1f; _seenRevision = GlobalItemTags.Revision; GlobalItemTags.MigrateLegacy(_current); ChestRole role = ChestConfig.GetRole(_current); float range = ((role == ChestRole.Input) ? ChestConfig.GetRange(_current) : ChestConfig.DefaultRange); HashSet<string> hashSet = TagDatabase.NewSet(); hashSet.UnionWith(GlobalItemTags.AllUsedTags()); _storageCount = 0; foreach (Container item in ContainerTracker.InRange(((Component)_current).transform.position, range)) { if (!((Object)(object)item == (Object)(object)_current) && ChestConfig.GetRole(item) == ChestRole.Storage) { _storageCount++; hashSet.UnionWith(ChestConfig.GetTags(item)); } } _nearbyTags = hashSet.OrderBy<string, string>((string t) => t, StringComparer.OrdinalIgnoreCase).ToList(); HashSet<string> hashSet2 = TagDatabase.NewSet(); HashSet<string> hashSet3 = TagDatabase.NewSet(); _chestItems = new List<KeyValuePair<string, string>>(); Inventory inventory = _current.GetInventory(); if (inventory != null) { foreach (ItemData allItem in inventory.GetAllItems()) { string text = TagDatabase.PrefabName(allItem); if (hashSet2.Add(text)) { _chestItems.Add(new KeyValuePair<string, string>(text, TagDatabase.DisplayName(allItem))); hashSet3.UnionWith(TagDatabase.GetDefaultTags(text)); } } } _chestItems.Sort((KeyValuePair<string, string> a, KeyValuePair<string, string> b) => string.Compare(a.Value, b.Value, StringComparison.OrdinalIgnoreCase)); _contentTags = hashSet3.OrderBy<string, string>((string t) => t, StringComparer.OrdinalIgnoreCase).ToList(); switch (role) { case ChestRole.Input: _overview = SortService.BuildOverview(_current); if (_selectedPrefab != null) { UpdateItemState(); } break; case ChestRole.Storage: _coveringInputs = SortService.InputsCovering(_current); break; } } private void DrawWindow(int id) { //IL_01cc: Unknown result type (might be due to invalid IL or missing references) if (IsLayout) { RefreshIfNeeded(); UpdateSearch(); _ovSearchApplied = _ovSearch.Trim(); } GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); GUILayout.Label((Localization.instance != null) ? Localization.instance.Localize(_current.m_name) : _current.m_name, _header, Array.Empty<GUILayoutOption>()); GUILayout.FlexibleSpace(); bool flag = ChestConfig.IsLocked(_current); bool flag2 = GUILayout.Toggle(flag, "Lock type", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(90f) }); if (flag2 != flag) { ChestConfig.SetLocked(_current, flag2); LayoutChanged(); } if (GUILayout.Button(_collapsed ? "Show" : "Hide", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(60f) })) { _collapsed = !_collapsed; LayoutChanged(); } GUILayout.EndHorizontal(); if (!_collapsed) { ChestRole role = ChestConfig.GetRole(_current); GUI.enabled = !flag; int num = GUILayout.Toolbar((int)role, new string[3] { "Not networked", "Input", "Storage" }, Array.Empty<GUILayoutOption>()); GUI.enabled = true; if (flag) { num = (int)role; } if (num != (int)role) { ChestConfig.SetRole(_current, (ChestRole)num); _pendingRange = ChestConfig.GetRange(_current); _nextRefresh = 0f; LayoutChanged(); } GUILayout.Space(6f); switch ((ChestRole)num) { case ChestRole.Input: DrawInput(); break; case ChestRole.Storage: DrawStorage(); break; default: GUILayout.Label("Input: dump items here; they are sent to matching storage chests when you close it.\nStorage: receives items whose tags match this chest's tags.", _wrap, Array.Empty<GUILayoutOption>()); break; } } GUI.DragWindow(new Rect(0f, 0f, 10000f, 22f)); } private void DrawStorage() { //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Unknown result type (might be d