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 LinkedStorage v1.1.0
LinkedStorage.dll
Decompiled 4 days ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Jotunn.Configs; using Jotunn.Entities; using Jotunn.Managers; using Jotunn.Utils; using Microsoft.CodeAnalysis; using TMPro; using UnityEngine; using UnityEngine.Audio; 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("LinkedStorage")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.1.0.0")] [assembly: AssemblyInformationalVersion("1.1.0")] [assembly: AssemblyProduct("LinkedStorage")] [assembly: AssemblyTitle("LinkedStorage")] [assembly: AssemblyVersion("1.1.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 LinkedStorage { internal static class ChestEdits { internal const byte Remove = 1; internal const byte Add = 2; internal const byte Done = 0; internal const byte NotOwner = 1; internal const byte Gone = 2; private static readonly Func<Container, bool> load = AccessTools.MethodDelegate<Func<Container, bool>>(AccessTools.Method(typeof(Container), "Load", (Type[])null, (Type[])null), (object)null, true); internal static ZPackage RemoveEdit(string key, int amount) { //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_0013: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown ZPackage val = new ZPackage(); val.Write((byte)1); val.Write(key); val.Write(amount); return val; } internal static ZPackage AddEdit(ItemData item) { //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_0013: Expected O, but got Unknown //IL_0014: Expected O, but got Unknown ZPackage val = new ZPackage(); val.Write((byte)2); ItemCodec.Write(val, item); return val; } internal static ZPackage Apply(ZDO zdo, ZPackage edit, bool asServer) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Expected O, but got Unknown ZPackage val = new ZPackage(); Container val2 = ((zdo != null && zdo.IsValid()) ? HubStorage.PrefabContainer(zdo) : null); if ((Object)(object)val2 == (Object)null) { val.Write((byte)2); return val; } if (!asServer && !zdo.IsOwner()) { val.Write((byte)1); return val; } ZNetView val3 = ((zdo.IsOwner() && (Object)(object)ZNetScene.instance != (Object)null) ? ZNetScene.instance.FindInstance(zdo) : null); Container val4 = (((Object)(object)val3 != (Object)null) ? ((Component)val3).GetComponentInChildren<Container>() : null); if ((Object)(object)val4 != (Object)null && val4.GetInventory() == null) { val4 = null; } if ((Object)(object)val4 != (Object)null) { load(val4); } Inventory val5 = (((Object)(object)val4 != (Object)null) ? val4.GetInventory() : HubStorage.Load(zdo, val2)); edit.SetPos(0); List<ItemData> list = new List<ItemData>(); if (edit.ReadByte() == 1) { string key = edit.ReadString(); int amount = edit.ReadInt(); list = ItemCodec.RemoveMatching(val5, key, amount); } else { ItemData val6 = ItemCodec.Read(edit); if (val6 != null) { string[] array = HubStorage.DrawerLabels(zdo); ItemData val7 = ((array != null && !array.Contains(val6.m_shared.m_name)) ? val6 : ItemCodec.AddWhatFits(val5, val6)); if (val7 != null) { list.Add(val7); } } } if ((Object)(object)val4 == (Object)null) { ZPackage val8 = new ZPackage(); val5.Save(val8); zdo.Set(ZDOVars.s_items, val8.GetArray()); } val.Write((byte)0); ItemCodec.WriteList(val, list); return val; } } internal static class DepositBlock { [HarmonyPatch(typeof(Container), "Awake")] private static class RegisterRpc { private static void Postfix(Container __instance) { ZNetView nview = view.Invoke(__instance); if ((Object)(object)nview == (Object)null || !nview.IsValid() || (Object)(object)((Component)__instance).GetComponent<LinkMirror>() != (Object)null) { return; } nview.Register<bool>("LinkedStorage_NoDeposit", (Action<long, bool>)delegate(long sender, bool blocked) { if (nview.IsOwner()) { nview.GetZDO().Set(HubStorage.NoDepositKey, blocked); } }); } } [HarmonyPatch(typeof(Container), "Interact")] private static class Toggle { [HarmonyPriority(800)] private static bool Prefix(Container __instance, Humanoid character, bool hold, ref bool __result) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Invalid comparison between Unknown and I4 if (hold || !ZInput.GetKey(Plugin.BlockKey.Value, true) || !Applies(__instance, out var nview)) { return true; } __result = true; ZDO zDO = nview.GetZDO(); bool flag = zDO.GetLong(ZDOVars.s_creator, 0L) == Game.instance.GetPlayerProfile().GetPlayerID(); if (!PrivateArea.CheckAccess(((Component)__instance).transform.position, 0f, true, false) || ((int)__instance.m_privacy == 0 && !flag) || (int)__instance.m_privacy == 1) { return false; } bool flag2 = !zDO.GetBool(HubStorage.NoDepositKey, false); nview.InvokeRPC("LinkedStorage_NoDeposit", new object[1] { flag2 }); ((Character)character).Message((MessageType)2, State(flag2), 0, (Sprite)null, false); return false; } } [HarmonyPatch(typeof(Hud), "UpdateCrosshair")] private static class HoverIcon { private static void Postfix(Hud __instance, Player player) { TMP_Text hoverName = (TMP_Text)(object)__instance.m_hoverName; GameObject hoverObject = ((Humanoid)player).GetHoverObject(); if ((Object)(object)hoverObject != (Object)null) { Hoverable componentInParent = hoverObject.GetComponentInParent<Hoverable>(); Container val = (Container)(object)((componentInParent is Container) ? componentInParent : null); if (val != null && hoverName.text.Length > 0 && Applies(val, out var nview) && Place(hoverName, nview.GetZDO().GetBool(HubStorage.NoDepositKey, false))) { return; } } if ((Object)(object)icon != (Object)null) { ((Component)icon).gameObject.SetActive(false); } } } private const string Rpc = "LinkedStorage_NoDeposit"; private static readonly FieldRef<Container, ZNetView> view = AccessTools.FieldRefAccess<Container, ZNetView>("m_nview"); private static bool? haveMarks; private static Image icon; private static GameObject cross; private static bool Applies(Container container, out ZNetView nview) { //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) nview = view.Invoke(container); if ((Object)(object)nview == (Object)null || !nview.IsValid() || !LinkClient.HubExists || (Object)(object)((Component)container).GetComponent<LinkMirror>() != (Object)null) { return false; } ZDO zDO = nview.GetZDO(); if ((Object)(object)HubStorage.PrefabContainer(zDO) != (Object)null) { return Vector3.Distance(zDO.GetPosition(), LinkClient.HubPos) <= LinkClient.Range; } return false; } private static string State(bool blocked) { if (!haveMarks.HasValue && (Object)(object)Hud.instance != (Object)null && (Object)(object)Hud.instance.m_hoverName != (Object)null && (Object)(object)((TMP_Text)Hud.instance.m_hoverName).font != (Object)null) { haveMarks = ((TMP_Text)Hud.instance.m_hoverName).font.HasCharacter('✅', true, true) && ((TMP_Text)Hud.instance.m_hoverName).font.HasCharacter('❌', true, true); if (!haveMarks.Value) { Plugin.Log.LogInfo((object)("Hover font " + ((Object)((TMP_Text)Hud.instance.m_hoverName).font).name + " has no ✅/❌; the deposit line says on/off.")); } } string text = ((haveMarks != true) ? (blocked ? "$linkedstorage_off" : "$linkedstorage_on") : (blocked ? "❌" : "✅")); return Localization.instance.Localize("$linkedstorage_deposits <color=" + (blocked ? "#FF5A5A" : "#5FA052") + ">" + text + "</color>"); } private static bool Place(TMP_Text text, bool blocked) { //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0056: 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_005d: 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_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_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)icon == (Object)null && !BuildIcon(text)) { return false; } text.ForceMeshUpdate(false, false); TMP_TextInfo textInfo = text.textInfo; int num = ((textInfo.lineCount > 0) ? textInfo.lineInfo[0].lastVisibleCharacterIndex : (-1)); if (num < 0) { return false; } TMP_LineInfo val = textInfo.lineInfo[0]; float num2 = val.ascender - val.descender; float num3 = num2 * 1.7f; RectTransform rectTransform = ((Graphic)icon).rectTransform; rectTransform.sizeDelta = new Vector2(num3, num3); ((Transform)rectTransform).localPosition = new Vector3(textInfo.characterInfo[num].topRight.x + num2 * 0.1f + num3 * 0.35f, (val.ascender + val.descender) / 2f, 0f); ((Graphic)icon).color = (Color)(blocked ? new Color(0.45f, 0.45f, 0.45f, 0.75f) : Color.white); cross.SetActive(blocked); ((Component)icon).gameObject.SetActive(true); return true; } private static bool BuildIcon(TMP_Text text) { //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Expected O, but got Unknown //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Expected O, but got Unknown //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_0135: 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_013b: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_019b: Unknown result type (might be due to invalid IL or missing references) object obj; if (!((Object)(object)ZNetScene.instance != (Object)null)) { obj = null; } else { GameObject prefab = ZNetScene.instance.GetPrefab("piece_linkedstorage_hub"); obj = ((prefab != null) ? prefab.GetComponent<Piece>() : null); } Piece val = (Piece)obj; if ((Object)(object)val == (Object)null || (Object)(object)val.m_icon == (Object)null) { return false; } GameObject val2 = new GameObject("LinkedStorage_hubIcon", new Type[1] { typeof(RectTransform) }); val2.transform.SetParent(text.transform, false); icon = val2.AddComponent<Image>(); icon.sprite = val.m_icon; icon.preserveAspect = true; ((Graphic)icon).raycastTarget = false; ((Graphic)icon).rectTransform.pivot = new Vector2(0.5f, 0.5f); cross = new GameObject("cross", new Type[1] { typeof(RectTransform) }); cross.transform.SetParent(val2.transform, false); RectTransform val3 = (RectTransform)cross.transform; val3.anchorMin = new Vector2(0.32f, 0.32f); val3.anchorMax = new Vector2(0.68f, 0.68f); Vector2 offsetMin = (val3.offsetMax = Vector2.zero); val3.offsetMin = offsetMin; TextMeshProUGUI obj2 = cross.AddComponent<TextMeshProUGUI>(); ((TMP_Text)obj2).font = text.font; ((TMP_Text)obj2).enableAutoSizing = true; ((TMP_Text)obj2).fontSizeMin = 4f; ((TMP_Text)obj2).fontSizeMax = 72f; ((TMP_Text)obj2).text = "❌"; ((Graphic)obj2).color = new Color(1f, 0.25f, 0.25f, 0.6f); ((TMP_Text)obj2).alignment = (TextAlignmentOptions)514; ((Graphic)obj2).raycastTarget = false; return true; } } internal static class Crafty { private const string Guid = "Azumatt.AzuCraftyBoxes"; internal static readonly int NoCraftyKey = StringExtensionMethods.GetStableHashCode("AzuCraftyBoxes_NoCrafty"); private static bool resolved; private static ConfigFile config; private static MethodInfo canPull; private static MethodInfo nearby; private static MethodInfo getInventory; private static MethodInfo itemCount; private static MethodInfo getPrefabName; private static readonly FieldRef<Container, ZNetView> containerView = AccessTools.FieldRefAccess<Container, ZNetView>("m_nview"); internal static bool Loaded { get { Resolve(); return config != null; } } internal static float Range { get { object obj = Setting("Container Range"); if (obj is float) { return (float)obj; } return 20f; } } private static bool LeaveOne => Setting("Leave One Item")?.ToString() == "On"; internal static bool ChestToggle => Setting("Container Toggle")?.ToString() != "Off"; private static void Resolve() { if (resolved) { return; } resolved = true; if (!Chainloader.PluginInfos.TryGetValue("Azumatt.AzuCraftyBoxes", out var value) || (Object)(object)value.Instance == (Object)null) { return; } Assembly assembly = ((object)value.Instance).GetType().Assembly; Type type = assembly.GetType("AzuCraftyBoxes.API"); Type type2 = assembly.GetType("AzuCraftyBoxes.IContainers.IContainer"); if (type == null || type2 == null) { Plugin.Log.LogWarning((object)"AzuCraftyBoxes found, but not its API; Storage Links won't feed crafting."); return; } canPull = type.GetMethod("CanItemBePulled", new Type[2] { typeof(string), typeof(string) }); nearby = type.GetMethod("GetNearbyContainers")?.MakeGenericMethod(typeof(Player)); getInventory = type2.GetMethod("GetInventory"); itemCount = type2.GetMethod("ItemCount"); getPrefabName = type2.GetMethod("GetPrefabName"); if (canPull == null || nearby == null || getInventory == null || itemCount == null || getPrefabName == null) { Plugin.Log.LogWarning((object)"AzuCraftyBoxes' API has changed; Storage Links won't feed crafting."); } else { config = value.Instance.Config; } } private static object Setting(string key) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown ConfigDefinition val = new ConfigDefinition("2 - CraftyBoxes", key); if (config == null || !config.ContainsKey(val)) { return null; } return config[val].BoxedValue; } internal static int PullMode(Player player) { if (!player.m_customData.TryGetValue("ACB_PreventPulling", out var value) || !int.TryParse(value, out var result) || result < 0 || result > 2) { return 1; } return result; } internal static void Register(Container container) { if (!Loaded) { return; } try { canPull.DeclaringType.GetMethod("AddContainer", new Type[1] { typeof(Container) })?.Invoke(null, new object[1] { container }); } catch (Exception ex) { Plugin.Log.LogWarning((object)("Couldn't register a Storage Link with AzuCraftyBoxes: " + ex.Message)); } } private static HashSet<Container> Registry() { return canPull.DeclaringType.Assembly.GetType("AzuCraftyBoxes.Util.Functions.Boxes")?.GetField("Containers", BindingFlags.Static | BindingFlags.NonPublic)?.GetValue(null) as HashSet<Container>; } internal static string Registered(Container container) { if (!Loaded) { return "no AzuCraftyBoxes"; } try { HashSet<Container> hashSet = Registry(); return (hashSet == null) ? "registry unknown" : (hashSet.Contains(container) ? "registered" : "NOT registered"); } catch (Exception ex) { return ex.Message; } } internal static HashSet<ZDOID> NearbyIds(Player player) { //IL_00fc: Unknown result type (might be due to invalid IL or missing references) HashSet<ZDOID> hashSet = new HashSet<ZDOID>(); if (!Loaded) { return hashSet; } try { HashSet<Inventory> hashSet2 = new HashSet<Inventory>(); foreach (object item in (IEnumerable)nearby.Invoke(null, new object[2] { player, Range })) { object? obj = getInventory.Invoke(item, null); Inventory val = (Inventory)((obj is Inventory) ? obj : null); if (val != null && !LinkMirror.IsMirror(val)) { hashSet2.Add(val); } } HashSet<Container> hashSet3 = Registry(); if (hashSet3 == null) { return hashSet; } foreach (Container item2 in hashSet3) { if (!((Object)(object)item2 == (Object)null) && hashSet2.Contains(item2.GetInventory())) { ZNetView val2 = containerView.Invoke(item2); if ((Object)(object)val2 != (Object)null && val2.IsValid()) { hashSet.Add(val2.GetZDO().m_uid); } } } } catch (Exception ex) { Plugin.Log.LogWarning((object)("Couldn't list AzuCraftyBoxes' chests: " + ex.Message)); } return hashSet; } internal static bool CanPull(string chestPrefab, string itemPrefab) { try { return canPull == null || (bool)canPull.Invoke(null, new object[2] { chestPrefab, itemPrefab }); } catch { return true; } } internal static int LocalCount(Player player, string sharedName, string itemPrefab) { if (!Loaded) { return 0; } int num = 0; try { foreach (object item in (IEnumerable)nearby.Invoke(null, new object[2] { player, Range })) { object? obj = getInventory.Invoke(item, null); if (!LinkMirror.IsMirror((Inventory)((obj is Inventory) ? obj : null)) && CanPull((string)getPrefabName.Invoke(item, null), itemPrefab)) { int num2 = (int)itemCount.Invoke(item, new object[1] { sharedName }); if (num2 > 0 && LeaveOne) { num2--; } num += Mathf.Max(0, num2); } } } catch (Exception ex) { Plugin.Log.LogWarning((object)("Couldn't count AzuCraftyBoxes' chests: " + ex.Message)); } return num; } } internal static class HubServer { private sealed class Job { internal long Sender; internal int RequestId; internal byte Op; internal long PlayerID; internal ZPackage Payload; internal readonly List<ItemData> Back = new List<ItemData>(); internal readonly List<ItemData> Unplaced = new List<ItemData>(); internal byte Status; internal byte Mode; internal ZPackage Snapshot; } private sealed class EditCall { internal byte Status = 2; internal List<ItemData> Items = new List<ItemData>(); } private sealed class SentSnapshot { internal long Version; internal readonly Dictionary<ZDOID, uint> Revisions = new Dictionary<ZDOID, uint>(); } internal const string BornKey = "LinkedStorage_born"; private static ZDOID hubId = ZDOID.None; private static readonly Queue<Job> jobs = new Queue<Job>(); private static int nextEdit; private static readonly Dictionary<int, ZPackage> results = new Dictionary<int, ZPackage>(); private static readonly Dictionary<int, byte> abandoned = new Dictionary<int, byte>(); internal static double LastBuildMs; private static readonly Dictionary<long, SentSnapshot> sent = new Dictionary<long, SentSnapshot>(); internal static ZDO Hub { get { //IL_0011: Unknown result type (might be due to invalid IL or missing references) if (!((ZDOID)(ref hubId)).IsNone()) { return ZDOMan.instance.GetZDO(hubId); } return null; } } internal static void Start(MonoBehaviour runner) { //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) hubId = ZDOID.None; HubStorage.ClearCache(); jobs.Clear(); results.Clear(); abandoned.Clear(); sent.Clear(); runner.StartCoroutine(WatchHubs()); runner.StartCoroutine(RunJobs()); } private static IEnumerator WatchHubs() { List<ZDO> found = new List<ZDO>(); while (true) { found.Clear(); int index = 0; while (!ZDOMan.instance.GetAllZDOsWithPrefabIterative("piece_linkedstorage_hub", found, ref index)) { yield return null; } ZDO val = found.Where((ZDO z) => z.IsValid()).OrderBy(delegate(ZDO z) { long num = z.GetLong("LinkedStorage_born", 0L); return (num <= 0) ? long.MaxValue : num; }).ThenBy((ZDO z) => ((ZDOID)(ref z.m_uid)).UserID) .ThenBy((ZDO z) => ((ZDOID)(ref z.m_uid)).ID) .FirstOrDefault(); ZDOID val2 = val?.m_uid ?? ZDOID.None; if (val2 != hubId) { hubId = val2; HubStorage.ClearCache(); Plugin.Log.LogInfo((object)((val != null) ? ($"Storage Hub at {val.GetPosition()} ({found.Count} placed: " + string.Join(", ", found.Select((ZDO z) => string.Format("{0} born {1}", z.GetPosition(), z.GetLong("LinkedStorage_born", 0L))).ToArray()) + ").") : "No Storage Hub in this world.")); SendHub(0L); } yield return (object)new WaitForSecondsRealtime(5f); } } internal static void SendHub(long target) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown //IL_0022: 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_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) ZDO hub = Hub; ZPackage val = new ZPackage(); val.Write(hub != null); val.Write(hub?.m_uid ?? ZDOID.None); val.Write((hub != null) ? hub.GetPosition() : Vector3.zero); val.Write(Plugin.HubRange); ZRoutedRpc.instance.InvokeRoutedRPC(target, "LinkedStorage_Hub", new object[1] { val }); } internal static void OnRequest(long sender, ZPackage pkg) { if (!((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.IsServer()) { Job job = new Job { Sender = sender, RequestId = pkg.ReadInt(), Op = pkg.ReadByte(), PlayerID = pkg.ReadLong(), Payload = pkg }; if (job.Op == 0) { SendHub(sender); } else { jobs.Enqueue(job); } } } internal static void OnEditResult(long sender, ZPackage pkg) { int key = pkg.ReadInt(); ZPackage val = pkg.ReadPackage(); if (abandoned.TryGetValue(key, out var value)) { abandoned.Remove(key); val.SetPos(0); if (val.ReadByte() == 0 && value == 1) { List<ItemData> list = ItemCodec.ReadList(val); Plugin.Log.LogWarning((object)$"A late chest edit returned {list.Count} stacks; putting them back into the hub."); Job job = new Job { Sender = 0L, Op = 3, PlayerID = 0L, Payload = null }; job.Unplaced.AddRange(list); jobs.Enqueue(job); } } else { results[key] = val; } } private static IEnumerator RunJobs() { while (true) { if (jobs.Count == 0) { yield return null; continue; } Job job = jobs.Dequeue(); Stack<IEnumerator> stack = new Stack<IEnumerator>(); stack.Push(Handle(job)); while (stack.Count > 0) { IEnumerator enumerator = stack.Peek(); bool flag; try { flag = enumerator.MoveNext(); } catch (Exception arg) { Plugin.Log.LogError((object)$"Storage request failed: {arg}"); job.Status = 3; break; } if (!flag) { stack.Pop(); } else if (enumerator.Current is IEnumerator item) { stack.Push(item); } else { yield return enumerator.Current; } } Reply(job); } } private static void Reply(Job job) { //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Expected O, but got Unknown //IL_00b7: Unknown result type (might be due to invalid IL or missing references) job.Back.AddRange(job.Unplaced); if (job.Sender == 0L) { if (job.Back.Count > 0) { Plugin.Log.LogError((object)string.Format("Lost {0} stacks returning to the hub: {1}.", job.Back.Count, string.Join(", ", job.Back.Select((ItemData i) => i.m_stack + " " + ItemCodec.PrefabName(i)).ToArray()))); } return; } ZPackage val = new ZPackage(); val.Write(job.RequestId); val.Write(job.Status); if (job.Op == 1) { val.Write((ZPackage)(((object)job.Snapshot) ?? ((object)new ZPackage()))); } else { ItemCodec.WriteList(val, job.Back); } ZRoutedRpc.instance.InvokeRoutedRPC(job.Sender, "LinkedStorage_Reply", new object[1] { val }); } private static IEnumerator Handle(Job job) { ZDO hub = Hub; if (hub == null) { job.Status = 1; ReadDeposit(job); yield break; } Vector3 position = hub.GetPosition(); if (job.PlayerID != 0L && !HubStorage.HasWardAccess(position, job.PlayerID)) { job.Status = 2; ReadDeposit(job); yield break; } switch (job.Op) { case 1: job.Snapshot = Snapshot(position, job.Sender, job.PlayerID, job.Payload.ReadLong()); break; case 2: yield return Take(job, position); break; case 3: ReadDeposit(job); yield return Deposit(job, position); break; } } private static void ReadDeposit(Job job) { if (job.Op == 3 && job.Payload != null && job.Unplaced.Count <= 0) { job.Mode = job.Payload.ReadByte(); job.Unplaced.AddRange(ItemCodec.ReadList(job.Payload)); } } private static ZPackage Snapshot(Vector3 hubPos, long sender, long playerID, long clientVersion) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) Stopwatch stopwatch = Stopwatch.StartNew(); try { return BuildSnapshot(hubPos, sender, playerID, clientVersion); } finally { LastBuildMs = stopwatch.Elapsed.TotalMilliseconds; } } private static ZPackage BuildSnapshot(Vector3 hubPos, long sender, long playerID, long clientVersion) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Expected O, but got Unknown //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: 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) List<HubStorage.Store> list = HubStorage.Stores(hubPos, Plugin.HubRange, playerID); long num = HubStorage.Version(list); ZPackage val = new ZPackage(); val.Write(num != clientVersion); if (num == clientVersion) { return val; } SentSnapshot value; Dictionary<ZDOID, uint> dictionary = ((sent.TryGetValue(sender, out value) && value.Version == clientVersion) ? value.Revisions : null); SentSnapshot sentSnapshot = new SentSnapshot { Version = num }; val.Write(num); val.Write(hubPos); val.Write(list.Count); foreach (HubStorage.Store item in list) { val.Write(item.PrefabName); val.Write(item.Zdo.m_uid); val.Write(item.Zdo.GetLong(ZDOVars.s_creator, 0L)); val.Write(item.Zdo.GetBool(Crafty.NoCraftyKey, false)); uint dataRevision = item.Zdo.DataRevision; sentSnapshot.Revisions[item.Zdo.m_uid] = dataRevision; uint value2; bool flag = dictionary != null && dictionary.TryGetValue(item.Zdo.m_uid, out value2) && value2 == dataRevision; val.Write(flag); if (!flag) { val.Write(HubStorage.PeekBytes(item)); } } sent[sender] = sentSnapshot; return val; } private static IEnumerator Take(Job job, Vector3 hubPos) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) List<KeyValuePair<string, int>> list = new List<KeyValuePair<string, int>>(); int num = job.Payload.ReadInt(); for (int i = 0; i < num; i++) { list.Add(new KeyValuePair<string, int>(job.Payload.ReadString(), job.Payload.ReadInt())); } HashSet<ZDOID> skip = new HashSet<ZDOID>(); int num2 = job.Payload.ReadInt(); for (int j = 0; j < num2; j++) { skip.Add(job.Payload.ReadZDOID()); } foreach (KeyValuePair<string, int> item in list) { string key = item.Key; int remaining = item.Value; foreach (HubStorage.Store item2 in HubStorage.Stores(hubPos, Plugin.HubRange, job.PlayerID)) { if (remaining <= 0) { break; } if (!skip.Contains(item2.Zdo.m_uid) && HubStorage.Peek(item2).GetAllItems().Any((ItemData item) => ItemCodec.Matches(item, key))) { EditCall call = new EditCall(); yield return RunEdit(item2.Zdo, ChestEdits.RemoveEdit(key, remaining), call); job.Back.AddRange(call.Items); remaining -= call.Items.Sum((ItemData val) => val.m_stack); } } } } private static IEnumerator Deposit(Job job, Vector3 hubPos) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) while (job.Unplaced.Count > 0) { ItemData left = job.Unplaced[0]; string name = left.m_shared.m_name; List<HubStorage.Store> list = new List<HubStorage.Store>(); List<HubStorage.Store> list2 = new List<HubStorage.Store>(); List<HubStorage.Store> list3 = new List<HubStorage.Store>(); foreach (HubStorage.Store item in HubStorage.Stores(hubPos, Plugin.HubRange, job.PlayerID)) { if (item.Labels != null && !item.Labels.Contains(name)) { continue; } Inventory val = HubStorage.Peek(item); if (ItemCodec.Room(val, left) == 0) { continue; } if (item.NoDeposit) { if (val.ContainsItemByName(name)) { list.Add(item); } else if (job.PlayerID == 0L) { list3.Add(item); } } else if (item.Labels != null || val.ContainsItemByName(name)) { list.Add(item); } else if (job.Mode == 0) { list2.Add(item); } } foreach (HubStorage.Store item2 in list.Concat(list2).Concat(list3)) { EditCall call = new EditCall(); yield return RunEdit(item2.Zdo, ChestEdits.AddEdit(left), call); if (call.Status == 0) { left = call.Items.FirstOrDefault(); if (left == null) { break; } job.Unplaced[0] = left; } } job.Unplaced.RemoveAt(0); if (left != null) { job.Back.Add(left); } } } private static IEnumerator RunEdit(ZDO zdo, ZPackage edit, EditCall call) { for (int attempt = 0; attempt < 3; attempt++) { if (!zdo.IsValid()) { break; } long owner = zdo.GetOwner(); ZPackage val; if (owner == 0L || owner == ZDOMan.GetSessionID() || ZNet.instance.GetPeer(owner) == null) { val = ChestEdits.Apply(zdo, edit, asServer: true); } else { int id = ++nextEdit; ZPackage val2 = new ZPackage(); val2.Write(id); val2.Write(zdo.m_uid); val2.Write(edit); ZRoutedRpc.instance.InvokeRoutedRPC(owner, "LinkedStorage_Edit", new object[1] { val2 }); float start = Time.realtimeSinceStartup; while (!results.ContainsKey(id)) { if (ZNet.instance.GetPeer(owner) == null || Time.realtimeSinceStartup - start > 30f) { Plugin.Log.LogWarning((object)$"Chest owner {owner} didn't answer; skipping that chest."); edit.SetPos(0); abandoned[id] = edit.ReadByte(); yield break; } yield return null; } val = results[id]; results.Remove(id); } val.SetPos(0); byte b = val.ReadByte(); if (b == 1) { yield return null; continue; } call.Status = b; if (b == 0) { call.Items = ItemCodec.ReadList(val); } break; } } } internal static class HubStorage { internal sealed class Store { internal ZDO Zdo; internal Container Prefab; internal string PrefabName; internal string[] Labels; internal float Distance; internal bool NoDeposit; } private sealed class Sweep { internal float At; internal Vector3 Hub; internal float Range; internal readonly List<ZDO> Chests = new List<ZDO>(); internal readonly List<ZDO> Wards = new List<ZDO>(); } private sealed class Cached { internal uint Revision; internal Inventory Inventory; internal byte[] Items; } internal static readonly int NoDepositKey = StringExtensionMethods.GetStableHashCode("LinkedStorage_noDeposit"); private static readonly int[] DrawerLabelKeys = new int[2] { StringExtensionMethods.GetStableHashCode("SimpleItemDrawer_type"), StringExtensionMethods.GetStableHashCode("SimpleItemDrawer_type2") }; private static readonly HashSet<string> DrawerPrefabs = new HashSet<string> { "piece_itemdrawer", "piece_itemdrawer_double" }; private static readonly Dictionary<int, KeyValuePair<Container, string>> containers = new Dictionary<int, KeyValuePair<Container, string>>(); private static Dictionary<int, float> wardRadii; private static readonly Action<ZDOMan, Vector2s, List<ZDO>, HashSet<SectorIndex>> findObjects = AccessTools.MethodDelegate<Action<ZDOMan, Vector2s, List<ZDO>, HashSet<SectorIndex>>>(AccessTools.Method(typeof(ZDOMan), "FindObjects", (Type[])null, (Type[])null), (object)null, true); private static readonly List<ZDO> nearBuffer = new List<ZDO>(); private const float SweepSeconds = 3f; private static Sweep sweep; private static readonly Dictionary<ZDOID, Cached> cache = new Dictionary<ZDOID, Cached>(); private static List<ZDO> Near(Vector3 point, float range) { //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_0025: 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_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0071: 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_00be: 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_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) nearBuffer.Clear(); HashSet<SectorIndex> arg = new HashSet<SectorIndex>(); Vector2s zone = ZoneSystem.GetZone(point - new Vector3(range, 0f, range)); Vector2s zone2 = ZoneSystem.GetZone(point + new Vector3(range, 0f, range)); for (int i = zone.x; i <= zone2.x; i++) { for (int j = zone.y; j <= zone2.y; j++) { findObjects(ZDOMan.instance, new Vector2s((short)i, (short)j), nearBuffer, arg); } } nearBuffer.RemoveAll((ZDO z) => z == null || !z.IsValid() || Vector3.Distance(z.GetPosition(), point) > range); return nearBuffer; } private static Sweep Swept(Vector3 hub, float range) { //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) float realtimeSinceStartup = Time.realtimeSinceStartup; if (sweep != null && realtimeSinceStartup - sweep.At < 3f && sweep.Hub == hub && sweep.Range == range) { return sweep; } if (wardRadii == null) { FindWards(); } sweep = new Sweep { At = realtimeSinceStartup, Hub = hub, Range = range }; foreach (ZDO item in Near(hub, range + ((wardRadii.Count > 0) ? wardRadii.Values.Max() : 0f))) { int prefab = item.GetPrefab(); string name; if (wardRadii.ContainsKey(prefab)) { sweep.Wards.Add(item); } else if ((Object)(object)ContainerOf(prefab, out name) != (Object)null) { sweep.Chests.Add(item); } } return sweep; } internal static List<Store> Stores(Vector3 hub, float range, long playerID) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0047: 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_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Invalid comparison between Unknown and I4 //IL_009a: Unknown result type (might be due to invalid IL or missing references) List<Store> list = new List<Store>(); Sweep sweep = Swept(hub, range); foreach (ZDO chest in sweep.Chests) { if (chest.IsValid()) { string name; Container val = ContainerOf(chest.GetPrefab(), out name); float num = Vector3.Distance(chest.GetPosition(), hub); if (!((Object)(object)val == (Object)null) && !(num > range) && (playerID == 0L || (((int)val.m_privacy != 0 || chest.GetLong(ZDOVars.s_creator, 0L) == playerID) && (int)val.m_privacy != 1 && (!val.m_checkGuardStone || HasWardAccess(sweep.Wards, chest.GetPosition(), playerID))))) { list.Add(new Store { Zdo = chest, Prefab = val, PrefabName = name, Labels = DrawerLabels(chest), Distance = num, NoDeposit = chest.GetBool(NoDepositKey, false) }); } } } list.Sort((Store a, Store b) => a.Distance.CompareTo(b.Distance)); return list; } private static Container ContainerOf(int prefabHash, out string name) { if (!containers.TryGetValue(prefabHash, out var value)) { GameObject val = (((Object)(object)ZNetScene.instance != (Object)null) ? ZNetScene.instance.GetPrefab(prefabHash) : null); Container val2 = null; if ((Object)(object)val != (Object)null && !Object.op_Implicit((Object)(object)val.GetComponent<PillarFx>()) && !Object.op_Implicit((Object)(object)val.GetComponent<TombStone>()) && (Object.op_Implicit((Object)(object)val.GetComponent<Piece>()) || Object.op_Implicit((Object)(object)val.GetComponent<Vagon>()))) { val2 = val.GetComponentInChildren<Container>(true); } value = new KeyValuePair<Container, string>(val2, ((Object)(object)val2 != (Object)null) ? ((Object)val).name : null); containers[prefabHash] = value; } name = value.Value; return value.Key; } internal static Inventory Load(ZDO zdo, Container prefab) { return Read(zdo, prefab, editable: true); } private static Inventory Read(ZDO zdo, Container prefab, bool editable) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Expected O, but got Unknown //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Expected O, but got Unknown //IL_0038: 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) //IL_003c: Invalid comparison between Unknown and I4 //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Expected O, but got Unknown //IL_0072: Unknown result type (might be due to invalid IL or missing references) Inventory val = new Inventory(prefab.m_name, (Sprite)null, prefab.m_width, prefab.m_height); byte[] byteArray = zdo.GetByteArray(ZDOVars.s_items, (byte[])null); if (byteArray == null) { return val; } ZPackage val2 = new ZPackage(byteArray); Item val3 = (Item)val2.ReadInt(); if ((int)val3 < 108) { val2.SetPos(0); val.Load(val2); return val; } int num = val2.ReadUShort(); List<ItemData> allItems = val.GetAllItems(); for (int i = 0; i < num; i++) { ItemData val4 = new ItemData(); GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(ItemData.Load(val2, val4, val3)); ItemDrop val5 = (((Object)(object)itemPrefab != (Object)null) ? itemPrefab.GetComponent<ItemDrop>() : null); if (!((Object)(object)val5 == (Object)null)) { if (editable) { allItems.Add(ItemCodec.Build(itemPrefab, val5, val4)); continue; } val4.m_shared = val5.m_itemData.m_shared; val4.m_dropPrefab = itemPrefab; allItems.Add(val4); } } return val; } internal static Inventory Peek(Store store) { return Cache(store).Inventory; } internal static byte[] PeekBytes(Store store) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Expected O, but got Unknown Cached cached = Cache(store); if (cached.Items == null) { ZPackage val = new ZPackage(); ItemCodec.WriteList(val, cached.Inventory.GetAllItems()); cached.Items = val.GetArray(); } return cached.Items; } private static Cached Cache(Store store) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) uint dataRevision = store.Zdo.DataRevision; if (!cache.TryGetValue(store.Zdo.m_uid, out var value) || value.Revision != dataRevision) { value = new Cached { Revision = dataRevision, Inventory = Read(store.Zdo, store.Prefab, editable: false) }; cache[store.Zdo.m_uid] = value; } return value; } internal static void ClearCache() { cache.Clear(); sweep = null; } internal static long Version(List<Store> stores) { long num = -3750763034362895579L; foreach (Store store in stores) { num = (num ^ ((ZDOID)(ref store.Zdo.m_uid)).UserID) * 1099511628211L; num = (num ^ ((ZDOID)(ref store.Zdo.m_uid)).ID) * 1099511628211L; num = (num ^ store.Zdo.DataRevision) * 1099511628211L; } if (num != 0L) { return num; } return 1L; } internal static Container PrefabContainer(ZDO zdo) { string name; return ContainerOf(zdo.GetPrefab(), out name); } internal static string[] DrawerLabels(ZDO zdo) { ContainerOf(zdo.GetPrefab(), out var name); if (name == null || !DrawerPrefabs.Contains(name)) { return null; } return (from k in DrawerLabelKeys select zdo.GetString(k, "") into s where s != "" select s).ToArray(); } internal static bool HasWardAccess(Vector3 hub, long playerID) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) return HasWardAccess(Swept(hub, Plugin.HubRange).Wards, hub, playerID); } private static bool HasWardAccess(List<ZDO> wards, Vector3 point, long playerID) { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) bool flag = false; foreach (ZDO ward in wards) { if (ward.IsValid() && wardRadii.TryGetValue(ward.GetPrefab(), out var value) && ward.GetBool(ZDOVars.s_enabled, false) && !(Utils.DistanceXZ(ward.GetPosition(), point) >= value)) { if (Permits(ward, playerID)) { return true; } flag = true; } } return !flag; } private static bool Permits(ZDO ward, long playerID) { if (ward.GetLong(ZDOVars.s_creator, 0L) == playerID) { return true; } int num = ward.GetInt(ZDOVars.s_permitted, 0); for (int i = 0; i < num; i++) { if (ward.GetLong("pu_id" + i, 0L) == playerID) { return true; } } return false; } private static void FindWards() { //IL_0041: Unknown result type (might be due to invalid IL or missing references) wardRadii = new Dictionary<int, float>(); foreach (GameObject prefab in ZNetScene.instance.m_prefabs) { PrivateArea val = (((Object)(object)prefab != (Object)null) ? prefab.GetComponent<PrivateArea>() : null); if ((Object)(object)val != (Object)null && (int)val.m_ownerFaction == 0) { wardRadii[StringExtensionMethods.GetStableHashCode(((Object)prefab).name)] = val.m_radius; } } } } internal static class ItemCodec { private static int itemVersion = -1; private static readonly Func<object, object> memberwiseClone = AccessTools.MethodDelegate<Func<object, object>>(AccessTools.Method(typeof(object), "MemberwiseClone", (Type[])null, (Type[])null), (object)null, true); private static int ItemVersion { get { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Expected O, but got Unknown //IL_0016: Unknown result type (might be due to invalid IL or missing references) if (itemVersion < 0) { ZPackage val = new ZPackage(); new Inventory("", (Sprite)null, 1, 1).Save(val); val.SetPos(0); itemVersion = val.ReadInt(); } return itemVersion; } } internal static string PrefabName(ItemData item) { if (!((Object)(object)item.m_dropPrefab != (Object)null)) { return ""; } return ((Object)item.m_dropPrefab).name; } internal static void Write(ZPackage pkg, ItemData item) { pkg.Write(PrefabName(item)); item.Save(pkg); } internal static ItemData Read(ZPackage pkg) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Expected O, but got Unknown //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) string text = pkg.ReadString(); ItemData val = new ItemData(); ItemData.Load(pkg, val, (Item)ItemVersion); GameObject val2 = (((Object)(object)ObjectDB.instance != (Object)null) ? ObjectDB.instance.GetItemPrefab(text) : null); ItemDrop val3 = (((Object)(object)val2 != (Object)null) ? val2.GetComponent<ItemDrop>() : null); if ((Object)(object)val3 == (Object)null) { return null; } ItemData obj = Build(val2, val3, val); obj.m_gridPos = new Vector2i(-1, -1); return obj; } internal static ItemData Build(GameObject prefab, ItemDrop drop, ItemData saved) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Expected O, but got Unknown //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) ItemData val = drop.m_itemData.Clone(); val.m_shared = (SharedData)memberwiseClone(val.m_shared); val.m_dropPrefab = prefab; val.m_stack = saved.m_stack; val.m_durability = saved.m_durability; val.m_quality = saved.m_quality; val.m_variant = saved.m_variant; val.m_crafterID = saved.m_crafterID; val.m_crafterName = saved.m_crafterName; val.m_customData = saved.m_customData; val.m_worldLevel = saved.m_worldLevel; val.m_pickedUp = saved.m_pickedUp; val.m_cheated = saved.m_cheated; val.m_gridPos = saved.m_gridPos; return val.Clone(); } internal static void WriteList(ZPackage pkg, ICollection<ItemData> items) { pkg.Write(items.Count); foreach (ItemData item in items) { Write(pkg, item); } } internal static List<ItemData> ReadList(ZPackage pkg) { int num = pkg.ReadInt(); List<ItemData> list = new List<ItemData>(num); for (int i = 0; i < num; i++) { ItemData val = Read(pkg); if (val != null) { list.Add(val); } } return list; } internal static string Key(ItemData item) { StringBuilder stringBuilder = new StringBuilder(PrefabName(item)); stringBuilder.Append('|').Append(item.m_quality).Append('|') .Append(item.m_variant) .Append('|') .Append(item.m_worldLevel); if (item.m_shared.m_useDurability) { stringBuilder.Append("|d").Append((int)(item.m_durability * 100f)); } if (item.m_customData != null && item.m_customData.Count > 0) { foreach (KeyValuePair<string, string> item2 in item.m_customData.OrderBy<KeyValuePair<string, string>, string>((KeyValuePair<string, string> kv) => kv.Key, StringComparer.Ordinal)) { stringBuilder.Append('|').Append(item2.Key).Append('=') .Append(item2.Value); } } return stringBuilder.ToString(); } internal static string NameKey(string sharedName) { return "@" + Game.m_worldLevel + "@" + sharedName; } internal static bool Matches(ItemData item, string key) { if (key.Length == 0 || key[0] != '@') { return Key(item) == key; } int num = key.IndexOf('@', 1); if (string.CompareOrdinal(item.m_shared.m_name, 0, key, num + 1, key.Length) == 0) { return item.m_worldLevel >= int.Parse(key.Substring(1, num - 1)); } return false; } internal static ItemData CloneStack(ItemData item, int stack) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) ItemData obj = item.Clone(); obj.m_stack = stack; obj.m_equipped = false; obj.m_gridPos = new Vector2i(-1, -1); return obj; } internal static int Room(Inventory inventory, ItemData item) { int maxStackSize = item.m_shared.m_maxStackSize; int num = inventory.GetWidth() * inventory.GetHeight() - inventory.NrOfItems(); int num2 = Mathf.Max(0, num) * maxStackSize; if (maxStackSize > 1) { foreach (ItemData allItem in inventory.GetAllItems()) { if (allItem.m_shared.m_name == item.m_shared.m_name && allItem.m_quality == item.m_quality && allItem.m_worldLevel == item.m_worldLevel && allItem.m_stack < maxStackSize) { num2 += maxStackSize - allItem.m_stack; } } } return num2; } internal static ItemData AddWhatFits(Inventory inventory, ItemData item) { int num = Mathf.Min(item.m_stack, Room(inventory, item)); if (num > 0) { inventory.AddItem(CloneStack(item, num)); } if (num >= item.m_stack) { return null; } return CloneStack(item, item.m_stack - num); } internal static List<ItemData> RemoveMatching(Inventory inventory, string key, int amount) { List<ItemData> list = new List<ItemData>(); foreach (ItemData item in inventory.GetAllItems().ToList()) { if (amount <= 0) { break; } if (Matches(item, key)) { int num = Mathf.Min(item.m_stack, amount); list.Add(CloneStack(item, num)); amount -= num; if (num == item.m_stack) { inventory.RemoveItem(item); } else { inventory.RemoveItem(item, num); } } } return list; } } internal static class LinkClient { internal sealed class Snapshot { internal sealed class Store { internal string Chest; internal ZDOID Id; internal long Creator; internal bool NoCrafty; internal List<ItemData> Items; } internal Vector3 HubPos; internal readonly List<Store> Stores = new List<Store>(); internal IEnumerable<ItemData> Items => Stores.SelectMany((Store s) => s.Items); } private sealed class DecodedChest { internal byte[] Bytes; internal List<ItemData> Items; } [HarmonyPatch(typeof(Game), "Logout")] private static class ReturnEscrowOnLogout { private static void Prefix() { foreach (List<ItemData> value in escrow.Values) { Give(value); } escrow.Clear(); waiting.Clear(); } } internal static bool HubKnown; internal static bool HubExists; internal static ZDOID HubId = ZDOID.None; internal static Vector3 HubPos; internal static float Range; private static int nextRequest; private static float lastHubAsk = -100f; private static readonly Dictionary<int, Action<byte, ZPackage>> waiting = new Dictionary<int, Action<byte, ZPackage>>(); private static readonly Dictionary<int, List<ItemData>> escrow = new Dictionary<int, List<ItemData>>(); internal static int LastSnapshotBytes; internal static int LastSnapshotStacks; private static Snapshot held; private static long heldVersion; private static Dictionary<ZDOID, DecodedChest> decoded = new Dictionary<ZDOID, DecodedChest>(); internal static bool Busy => waiting.Count > 0; internal static void Reset() { //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) HubKnown = (HubExists = false); HubId = ZDOID.None; ForgetSnapshot(); waiting.Clear(); escrow.Clear(); lastHubAsk = -100f; } internal static void OnHub(long sender, ZPackage pkg) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //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) HubKnown = true; HubExists = pkg.ReadBool(); HubId = pkg.ReadZDOID(); HubPos = pkg.ReadVector3(); Range = pkg.ReadSingle(); } internal static void Tick() { if (!HubKnown && ZRoutedRpc.instance != null && !((Object)(object)Player.m_localPlayer == (Object)null) && !(Time.realtimeSinceStartup - lastHubAsk < 3f)) { lastHubAsk = Time.realtimeSinceStartup; Send(0, null, null); } } private static void Send(byte op, Action<ZPackage> write, Action<byte, ZPackage> onReply) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Expected O, but got Unknown int num = ++nextRequest; ZPackage val = new ZPackage(); val.Write(num); val.Write(op); val.Write(Game.instance.GetPlayerProfile().GetPlayerID()); write?.Invoke(val); if (onReply != null) { waiting[num] = onReply; } ZRoutedRpc.instance.InvokeRoutedRPC("LinkedStorage_Request", new object[1] { val }); } internal static void OnReply(long sender, ZPackage pkg) { int key = pkg.ReadInt(); byte arg = pkg.ReadByte(); if (waiting.TryGetValue(key, out var value)) { waiting.Remove(key); value(arg, pkg); } } internal static void ForgetSnapshot() { held = null; decoded.Clear(); } private static DecodedChest Decode(ZDOID id, byte[] bytes) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Expected O, but got Unknown if (!decoded.TryGetValue(id, out var value) || !Same(value.Bytes, bytes)) { return new DecodedChest { Bytes = bytes, Items = ItemCodec.ReadList(new ZPackage(bytes)) }; } return value; } private static bool Same(byte[] a, byte[] b) { if (a.Length != b.Length) { return false; } for (int i = 0; i < a.Length; i++) { if (a[i] != b[i]) { return false; } } return true; } internal static void RequestSnapshot(Action<byte, Snapshot> done) { Send(1, delegate(ZPackage pkg) { pkg.Write((held != null) ? heldVersion : 0); }, delegate(byte status, ZPackage pkg) { //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00be: 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) ZPackage val = pkg.ReadPackage(); LastSnapshotBytes = val.Size(); if (status != 0) { done(status, new Snapshot()); } else if (!val.ReadBool()) { done(status, held ?? new Snapshot()); } else { Snapshot snapshot = new Snapshot(); long num = val.ReadLong(); snapshot.HubPos = val.ReadVector3(); int num2 = val.ReadInt(); Dictionary<ZDOID, DecodedChest> dictionary = new Dictionary<ZDOID, DecodedChest>(num2); for (int i = 0; i < num2; i++) { Snapshot.Store store = new Snapshot.Store { Chest = val.ReadString(), Id = val.ReadZDOID(), Creator = val.ReadLong(), NoCrafty = val.ReadBool() }; bool num3 = val.ReadBool(); DecodedChest value = null; if (num3 ? (!decoded.TryGetValue(store.Id, out value)) : ((value = Decode(store.Id, val.ReadByteArray())) == null)) { Plugin.Log.LogWarning((object)"Storage Hub snapshot out of step; asking again."); ForgetSnapshot(); RequestSnapshot(done); return; } dictionary[store.Id] = value; store.Items = value.Items; snapshot.Stores.Add(store); } decoded = dictionary; LastSnapshotStacks = snapshot.Stores.Sum((Snapshot.Store s) => s.Items.Count); held = snapshot; heldVersion = num; done(status, snapshot); } }); } internal static void Take(IList<KeyValuePair<string, int>> entries, Action<byte, List<ItemData>> done, ICollection<ZDOID> skip = null) { Send(2, delegate(ZPackage pkg) { //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) pkg.Write(entries.Count); foreach (KeyValuePair<string, int> entry in entries) { pkg.Write(entry.Key); pkg.Write(entry.Value); } pkg.Write(skip?.Count ?? 0); if (skip != null) { foreach (ZDOID item in skip) { pkg.Write(item); } } }, delegate(byte status, ZPackage pkg) { done(status, ItemCodec.ReadList(pkg)); }); } internal static void TakeToInventory(ItemData template, int amount, Action<byte, int> done) { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return; } amount = Mathf.Min(amount, ItemCodec.Room(((Humanoid)localPlayer).GetInventory(), template)); if (amount <= 0) { done?.Invoke(0, 0); return; } Take(new KeyValuePair<string, int>[1] { new KeyValuePair<string, int>(ItemCodec.Key(template), amount) }, delegate(byte status, List<ItemData> items) { done?.Invoke(status, Give(items)); }); } internal static int Give(List<ItemData> items) { //IL_004c: 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_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_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) Player localPlayer = Player.m_localPlayer; int num = 0; foreach (ItemData item in items) { num += item.m_stack; if (!((Object)(object)localPlayer == (Object)null)) { ItemData val = ItemCodec.AddWhatFits(((Humanoid)localPlayer).GetInventory(), item); if (val != null) { ItemDrop.DropItem(val, val.m_stack, ((Component)localPlayer).transform.position + ((Component)localPlayer).transform.forward + Vector3.up, Quaternion.identity); } } } return num; } internal static void Deposit(IList<KeyValuePair<ItemData, int>> picks, byte mode, Action<byte, int> done) { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return; } Inventory inventory = ((Humanoid)localPlayer).GetInventory(); List<ItemData> list = new List<ItemData>(); foreach (KeyValuePair<ItemData, int> pick in picks) { ItemData key = pick.Key; int num = Mathf.Min(pick.Value, key.m_stack); if (num > 0 && !key.m_equipped && inventory.ContainsItem(key)) { list.Add(ItemCodec.CloneStack(key, num)); if (num == key.m_stack) { inventory.RemoveItem(key); } else { inventory.RemoveItem(key, num); } } } DepositStacks(list, mode, done); } internal static void DepositStacks(List<ItemData> stacks, byte mode, Action<byte, int> done) { if (stacks.Count == 0) { done?.Invoke(0, 0); return; } int sent = stacks.Sum((ItemData s) => s.m_stack); int id = nextRequest + 1; escrow[id] = stacks; Send(3, delegate(ZPackage pkg) { pkg.Write(mode); ItemCodec.WriteList(pkg, stacks); }, delegate(byte status, ZPackage pkg) { escrow.Remove(id); List<ItemData> list = ItemCodec.ReadList(pkg); Give(list); done?.Invoke(status, sent - list.Sum((ItemData i) => i.m_stack)); }); } } internal sealed class LinkMirror : MonoBehaviour { [HarmonyPatch(typeof(Container), "Save")] private static class NeverSave { private static bool Prefix(Container __instance) { LinkMirror component = ((Component)__instance).GetComponent<LinkMirror>(); if ((Object)(object)component == (Object)null) { return true; } if (!rebuilding && component.hidden == null) { component.Reconcile(); } return false; } } [HarmonyPatch(typeof(Container), "Load")] private static class NeverLoad { private static bool Prefix(Container __instance, ref bool __result) { if ((Object)(object)((Component)__instance).GetComponent<LinkMirror>() == (Object)null) { return true; } __result = false; return false; } } [HarmonyPatch(typeof(Container), "OnDestroyed")] private static class NeverDrop { private static bool Prefix(Container __instance) { return (Object)(object)((Component)__instance).GetComponent<LinkMirror>() == (Object)null; } } internal const string ChildName = "LinkedStorage_mirror"; private const float RefreshSeconds = 4f; private const float FilterSeconds = 1f; private static readonly List<LinkMirror> all = new List<LinkMirror>(); private static bool rebuilding; private Container container; private ZNetView nview; private Pillar pillar; private Dictionary<string, int> baseline = new Dictionary<string, int>(); private List<ItemData> hidden; private LinkClient.Snapshot last; private LinkClient.Snapshot filledFrom; private string lastSkipped = ""; private float nextRefresh; private float nextFilter; private bool refreshing; private bool registered; internal static double LastFillMs; private static readonly FieldRef<Inventory, List<ItemData>> slots = AccessTools.FieldRefAccess<Inventory, List<ItemData>>("m_inventory"); private static readonly Action<Inventory, bool, bool> changed = AccessTools.MethodDelegate<Action<Inventory, bool, bool>>(AccessTools.Method(typeof(Inventory), "Changed", (Type[])null, (Type[])null), (object)null, true); private Inventory Inventory { get { if (!((Object)(object)container != (Object)null)) { return null; } return container.GetInventory(); } } private bool Useful { get { if (LinkClient.HubExists && Crafty.Loaded && (Object)(object)pillar != (Object)null) { return pillar.IsActive; } return false; } } private void Awake() { container = ((Component)this).GetComponent<Container>(); nview = ((Component)this).GetComponentInParent<ZNetView>(); pillar = ((Component)this).GetComponentInParent<Pillar>(); all.Add(this); } private void OnDestroy() { all.Remove(this); } internal static bool IsMirror(Inventory inventory) { if (inventory != null) { return all.Any((LinkMirror m) => m.Inventory == inventory); } return false; } private bool Carries(ItemData item) { if (!((Object)(object)pillar == (Object)null)) { return pillar.Carries(item); } return true; } private static IEnumerable<LinkMirror> Near(Player player) { return all.Where((LinkMirror m) => m.Inventory != null && m.hidden == null && Vector3.Distance(((Component)m).transform.position, ((Component)player).transform.position) <= Crafty.Range); } internal static bool AnyNear(Player player) { return Near(player).Any((LinkMirror m) => m.Inventory.NrOfItems() > 0); } internal static int CountNear(Player player, string sharedName) { return (from m in Near(player) select m.Inventory.CountItems(sharedName, -1, true)).DefaultIfEmpty(0).Max(); } internal static string Describe(Player player) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) List<string> list = new List<string>(); foreach (LinkMirror item in all) { if (item.Inventory == null) { continue; } float num = Vector3.Distance(((Component)item).transform.position, ((Component)player).transform.position); if (num > 60f) { continue; } string text = string.Join(", ", (from g in item.Inventory.GetAllItems().GroupBy(ItemCodec.PrefabName) orderby g.Key select $"{g.Key} {g.Sum((ItemData i) => i.m_stack)}").ToArray()); object[] obj = new object[4] { num, item.Useful, Crafty.Registered(item.container), null }; ZDO zDO = item.nview.GetZDO(); obj[3] = ((zDO != null) ? new long?(zDO.GetLong(ZDOVars.s_creator, 0L)) : ((long?)null)); list.Add(string.Format("mirror at {0:0} m (useful {1}, {2}, creator {3}): ", obj) + ((text == "") ? "empty" : text)); } if (list.Count <= 0) { return "No Storage Link mirror within 60 m."; } return string.Join("\n", list.ToArray()); } internal static void RefreshSoon() { foreach (LinkMirror item in all) { item.nextRefresh = 0f; } } private void Update() { //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) if (Inventory == null || (Object)(object)nview == (Object)null || !nview.IsValid()) { return; } if (!registered && nview.GetZDO().GetLong(ZDOVars.s_creator, 0L) != 0L) { registered = true; Crafty.Register(container); } if (refreshing || hidden != null) { return; } float realtimeSinceStartup = Time.realtimeSinceStartup; if (realtimeSinceStartup < nextRefresh && (last == null || realtimeSinceStartup < nextFilter)) { return; } Player player = Player.m_localPlayer; if ((Object)(object)player == (Object)null) { return; } float distance = Vector3.Distance(((Component)player).transform.position, ((Component)this).transform.position); bool flag = all.All((LinkMirror m) => (Object)(object)m == (Object)(object)this || m.Inventory == null || Vector3.Distance(((Component)player).transform.position, ((Component)m).transform.position) >= distance); if (!Useful || !flag || distance > Crafty.Range + 10f) { last = null; if (Inventory.NrOfItems() > 0) { Fill(null); } nextRefresh = realtimeSinceStartup + 2f; return; } if (realtimeSinceStartup < nextRefresh) { nextFilter = realtimeSinceStartup + 1f; Fill(last, onlyIfMoved: true); return; } refreshing = true; LinkClient.RequestSnapshot(delegate(byte status, LinkClient.Snapshot snapshot) { refreshing = false; nextRefresh = Time.realtimeSinceStartup + 4f; nextFilter = Time.realtimeSinceStartup + 1f; last = ((status == 0) ? snapshot : null); if ((Object)(object)this != (Object)null && hidden == null) { Fill(last); } }); } private unsafe void Fill(LinkClient.Snapshot snapshot, bool onlyIfMoved = false) { //IL_0129: Unknown result type (might be due to invalid IL or missing references) Inventory inventory = Inventory; List<ItemData> list = new List<ItemData>(); Player localPlayer = Player.m_localPlayer; HashSet<ZDOID> hashSet = ((snapshot != null && (Object)(object)localPlayer != (Object)null) ? Crafty.NearbyIds(localPlayer) : new HashSet<ZDOID>()); string text = string.Join(",", (from id in hashSet select ((object)(*(ZDOID*)(&id))/*cast due to .constrained prefix*/).ToString() into s orderby s select s).ToArray()); if (text == lastSkipped && (onlyIfMoved || (snapshot != null && snapshot == filledFrom))) { return; } lastSkipped = text; filledFrom = snapshot; if (snapshot != null && (Object)(object)localPlayer != (Object)null) { int num = Crafty.PullMode(localPlayer); long playerID = localPlayer.GetPlayerID(); Dictionary<string, bool> dictionary = new Dictionary<string, bool>(); foreach (LinkClient.Snapshot.Store store in snapshot.Stores) { if (num == 0 || (num == 2 && store.Creator != playerID) || (store.NoCrafty && Crafty.ChestToggle) || hashSet.Contains(store.Id)) { continue; } foreach (ItemData item in store.Items) { if (Carries(item)) { string text2 = ItemCodec.PrefabName(item); string key = store.Chest + "|" + text2; if (!dictionary.TryGetValue(key, out var value)) { value = (dictionary[key] = Crafty.CanPull(store.Chest, text2)); } if (value) { list.Add(item); } } } } } Rebuild(inventory, list); } private void Rebuild(Inventory inventory, List<ItemData> items) { //IL_00f4: 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) Stopwatch stopwatch = Stopwatch.StartNew(); Dictionary<string, KeyValuePair<ItemData, int>> dictionary = new Dictionary<string, KeyValuePair<ItemData, int>>(); List<string> list = new List<string>(); foreach (ItemData item in items) { string text = ItemCodec.Key(item); if (dictionary.TryGetValue(text, out var value)) { dictionary[text] = new KeyValuePair<ItemData, int>(value.Key, value.Value + item.m_stack); continue; } dictionary[text] = new KeyValuePair<ItemData, int>(item, item.m_stack); list.Add(text); } List<ItemData> list2 = new List<ItemData>(); int width = inventory.GetWidth(); foreach (string item2 in list) { ItemData val = ItemCodec.CloneStack(dictionary[item2].Key, dictionary[item2].Value); val.m_gridPos = new Vector2i(list2.Count % width, list2.Count / width); list2.Add(val); } rebuilding = true; try { inventory.SetHeight(Mathf.Max(4, list2.Count / width + 1)); List<ItemData> obj = slots.Invoke(inventory); obj.Clear(); obj.AddRange(list2); changed(inventory, arg2: false, arg3: false); } finally { rebuilding = false; } baseline = Counts(inventory); LastFillMs = stopwatch.Elapsed.TotalMilliseconds; } private static Dictionary<string, int> Counts(Inventory inventory) { Dictionary<string, int> dictionary = new Dictionary<string, int>(); foreach (ItemData allItem in inventory.GetAllItems()) { string key = ItemCodec.Key(allItem); dictionary[key] = (dictionary.TryGetValue(key, out var value) ? value : 0) + allItem.m_stack; } return dictionary; } internal static void HideAll() { foreach (LinkMirror item in all) { if (item.Inventory != null && item.hidden == null) { item.hidden = new List<ItemData>(slots.Invoke(item.Inventory)); item.SetItems(null); } } } internal static void ShowAll() { foreach (LinkMirror item in all) { if (item.hidden != null) { List<ItemData> items = item.hidden; item.hidden = null; if (item.Inventory != null) { item.SetItems(items); } } } } private void SetItems(List<ItemData> items) { rebuilding = true; try { List<ItemData> list = slots.Invoke(Inventory); list.Clear(); if (items != null) { list.AddRange(items); } changed(Inventory, arg2: false, arg3: false); } finally { rebuilding = false; } } private void Reconcile() { Dictionary<string, int> dictionary = Counts(Inventory); List<KeyValuePair<string, int>> list = new List<KeyValuePair<string, int>>(); foreach (KeyValuePair<string, int> item in baseline) { int value; int num = (dictionary.TryGetValue(item.Key, out value) ? value : 0); if (num < item.Value) { list.Add(new KeyValuePair<string, int>(item.Key, item.Value - num)); } } List<ItemData> list2 = new List<ItemData>(); foreach (ItemData item2 in Inventory.GetAllItems().ToList()) { string key = ItemCodec.Key(item2); int value2; int num2 = (baseline.TryGetValue(key, out value2) ? value2 : 0); int value3; int num3 = (dictionary.TryGetValue(key, out value3) ? value3 : 0) - num2; if (num3 > 0) { int num4 = Mathf.Min(num3, item2.m_stack); list2.Add(ItemCodec.CloneStack(item2, num4)); dictionary[key] -= num4; rebuilding = true; try { Inventory.RemoveItem(item2, num4); } finally { rebuilding = false; } } } baseline = Counts(Inventory); if (list.Count > 0) { int wanted = list.Sum((KeyValuePair<string, int> t) => t.Value); LinkClient.Take(list, delegate(byte status, List<ItemData> items) { int num5 = items.Sum((ItemData i) => i.m_stack); if (num5 < wanted) { Plugin.Log.LogWarning((object)$"Another mod used {wanted - num5} items from a Storage Link that the hub no longer had."); } RefreshSoon(); }, ((Object)(object)Player.m_localPlayer != (Object)null) ? Crafty.NearbyIds(Player.m_localPlayer) : null); } List<ItemData> list3 = (((Object)(object)pillar != (Object)null && !pillar.TakesDeposits) ? list2 : new List<ItemData>()); if (list3.Count > 0) { LinkClient.Give(list3); list2 = list2.Except(list3).ToList(); } if (list2.Count > 0) { LinkClient.DepositStacks(list2, 0, delegate { RefreshSoon(); }); } } } internal sealed class LsmModel { internal sealed class Node { internal string Name; internal Vector3 Position; internal Quaternion Rotation; internal Mesh Mesh; internal string[] Materials; } internal readonly List<Node> Nodes = new List<Node>(); private readonly Dictionary<string, KeyValuePair<Vector3, float>> markers = new Dictionary<string, KeyValuePair<Vector3, float>>(); internal Vector3 MarkerPosition(string name) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) return markers[name].Key; } internal float MarkerValue(string name) { return markers[name].Value; } internal static LsmModel Load(string file) { using Stream stream = typeof(LsmModel).Assembly.GetManifestResourceStream("LinkedStorage.Models." + file); if (stream == null) { throw new FileNotFoundException("embedded model missing", file); } using BinaryReader r = new BinaryReader(stream); return Read(r, file); } private static LsmModel Read(BinaryReader r, string file) { //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_025e: Unknown result type (might be due to invalid IL or missing references) //IL_0263: Unknown result type (might be due to invalid IL or missing references) //IL_026d: Unknown result type (might be due to invalid IL or missing references) //IL_019a: Unknown result type (might be due to invalid IL or missing references) //IL_019f: Unknown result type (might be due to invalid IL or missing references) //IL_01c3: Expected O, but got Unknown //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Unknown result type (might be due to invalid IL or missing references) if (Encoding.ASCII.GetString(r.ReadBytes(4)) != "LSM1") { throw new InvalidDataException(file + ": not an LSM1 file"); } LsmModel lsmModel = new LsmModel(); int num = r.ReadInt32(); for (int i = 0; i < num; i++) { Node node = new Node { Name = ReadString(r), Position = ReadVector(r) }; float[] array = new float[9]; for (int j = 0; j < 9; j++) { array[j] = r.ReadSingle(); } node.Rotation = Quaternion.LookRotation(new Vector3(array[2], array[5], array[8]), new Vector3(array[1], array[4], array[7])); int num2 = r.ReadInt32(); List<Vector3> list = new List<Vector3>(); List<Vector3> list2 = new List<Vector3>(); List<Vector2> list3 = new List<Vector2>(); List<int[]> list4 = new List<int[]>(); node.Materials = new string[num2]; for (int k = 0; k < num2; k++) { node.Materials[k] = ReadString(r); int count = list.Count; int num3 = r.ReadInt32(); for (int l = 0; l < num3; l++) { list.Add(ReadVector(r)); list2.Add(ReadVector(r)); list3.Add(new Vector2(r.ReadSingle(), r.ReadSingle())); } int num4 = r.ReadInt32(); int[] array2 = new int[num4]; for (int m = 0; m < num4; m++) { array2[m] = count + r.ReadInt32(); } list4.Add(array2); } Mesh val = new Mesh { name = "LinkedStorage_" + Path.GetFileNameWithoutExtension(file) + "_" + node.Name }; if (list.Count > 65535) { val.indexFormat = (IndexFormat)1; } val.SetVertices(list); val.SetNormals(list2); val.SetUVs(0, list3); val.subMeshCount = num2; for (int n = 0; n < num2; n++) { val.SetTriangles(list4[n], n); } val.RecalculateBounds(); node.Mesh = val; lsmModel.Nodes.Add(node); } int num5 = r.ReadInt32(); for (int num6 = 0; num6 < num5; num6++) { string key = ReadString(r); Vector3 key2 = ReadVector(r); lsmModel.markers[key] = new KeyValuePair<Vector3, float>(key2, r.ReadSingle()); } if (r.BaseStream.Position != r.BaseStream.Length) { throw new InvalidDataException(file + ": trailing bytes"); } return lsmModel; } private static Vector3 ReadVector(BinaryReader r) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) return new Vector3(r.ReadSingle(), r.ReadSingle(), r.ReadSingle()); } private static string ReadString(BinaryReader r) { return Encoding.UTF8.GetString(r.ReadBytes(r.ReadInt32())); } } internal static class Net { internal sealed class Runner : MonoBehaviour { } [HarmonyPatch(typeof(Game), "Start")] private static class GameStart { private static void Postfix() { ZRoutedRpc instance = ZRoutedRpc.instance; instance.Register<ZPackage>("LinkedStorage_Request", (Action<long, ZPackage>)HubServer.OnRequest); instance.Register<ZPackage>("LinkedStorage_Reply", (Action<long, ZPackage>)LinkClient.OnReply); instance.Register<ZPackage>("LinkedStorage_Edit", (Action<long, ZPackage>)OnEdit); instance.Register<ZPackage>("LinkedStorage_EditResult", (Action<long, ZPackage>)HubServer.OnEditResult); instance.Register<ZPackage>("LinkedStorage_Hub", (Action<long, ZPackage>)LinkClient.OnHub); LinkClient.Reset(); Runner runner = ((Component)ZNet.instance).gameObject.AddComponent<Runner>(); if (ZNet.instance.IsServer()) { HubServer.Start((MonoBehaviour)(object)runner); } } } internal const string Request = "LinkedStorage_Request"; internal const string Reply = "LinkedStorage_Reply"; internal const string Edit = "LinkedStorage_Edit"; internal const string EditResult = "LinkedStorage_EditResult"; internal const string Hub = "LinkedStorage_Hub"; internal const byte OpHub = 0; internal const byte OpSnapshot = 1; internal const byte OpTake = 2; internal const byte OpDeposit = 3; internal const byte Ok = 0; internal const byte NoHub = 1; internal const byte NoAccess = 2; internal const byte Failed = 3; private static void OnEdit(long sender, ZPackage pkg) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Expected O, but got Unknown int num = pkg.ReadInt(); ZDOID val = pkg.ReadZDOID(); ZPackage edit = pkg.ReadPackage(); ZPackage val2 = ChestEdits.Apply(ZDOMan.instance.GetZDO(val), edit, asServer: false); ZPackage val3 = new ZPackage(); val3.Write(num); val3.Write(val2); ZRoutedRpc.instance.InvokeRoutedRPC(sender, "LinkedStorage_EditResult", new object[1] { val3 }); } } internal sealed class Pillar : MonoBehaviour, Hoverable, Interactable { [HarmonyPatch(typeof(Player), "TryPlacePiece")] private static class OneHubPerWorld { private static bool Prefix(Player __instance, Piece piece, ref bool __result) { if ((Object)(object)piece == (Object)null || Utils.GetPrefabName(((Component)piece).gameObject) != "piece_linkedstorage_hub" || !LinkClient.HubExists) { return true; } ((Character)__instance).Message((MessageType)2, "$msg_linkedstorage_onehub", 0, (Sprite)null, false); __result = false; return false; } } [SerializeField] internal bool isHub; [SerializeField] internal bool isStone; private ZNetView nview; internal bool Restricted { get { if (isStone) { if (!((Object)(object)ZoneSystem.instance == (Object)null)) { return !ZoneSystem.instance.GetGlobalKey((GlobalKeys)35); } return true; } return false; } } internal bool TakesDeposits => !isStone; internal bool IsActive { get { //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) if (isHub) { if ((Object)(object)nview != (Object)null && nview.IsValid()) { return nview.GetZDO().m_uid == LinkClient.HubId; } return false; } return true; } } private string Name { get { if (!isHub) { if (!isStone) { return "$piece_linkedstorage_link"; } return "$piece_linkedstorage_stonelink"; } return "$piece_linkedstorage_hub"; } } internal bool Carries(ItemData item) { if (Restricted) { return item.m_shared.m_teleportable; } return true; } private void Awake() { nview = ((Component)this).GetComponent<ZNetView>(); if (isHub && (Object)(object)nview != (Object)null && nview.IsValid() && nview.IsOwner() && nview.GetZDO().GetLong("LinkedStorage_born", 0L) == 0L) { nview.GetZDO().Set("LinkedStorage_born", ZNet.instance.GetTime().Ticks); } } public string GetHoverName() { return Name; } public float GetHoverOffset() { return 0f; } public string GetHoverText() { //IL_004d: Unknown result type (might be due to invalid IL or missing references) string name = Name; name = ((!LinkClient.HubKnown) ? (name + "\n$msg_linkedstorage_connecting") : ((!LinkClient.HubExists) ? (name + "\n$msg_linkedstorage_nohub") : ((!IsActive) ? (name + "\n$msg_linkedstorage_secondhub") : (PrivateArea.CheckAccess(((Component)this).transform.position, 0f, false, false) ? (name + "\n[<color=yellow><b>$KEY_Use</b></color>] $piece_container_open") : (name + "\n$piece_noaccess"))))); return Localization.instance.Localize(name); } public bool Interact(Humanoid user, bool hold, bool alt) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) if (hold || !LinkClient.HubExists || !IsActive) { return false; } if (!PrivateArea.CheckAccess(((Component)this).transform.position, 0f, true, false)) { return true; } StorageWindow.Open(this); return true; } public bool UseItem(Humanoid user, ItemData item) { return false; } } internal sealed class PillarFx : MonoBehaviour { [SerializeField] internal Transform orbit; [SerializeField] internal Transform[] halos; [SerializeField] internal Transform floater; [SerializeField] internal Transform heart; [SerializeField] internal Light heartLight; [SerializeField] internal ParticleSystem embers; [SerializeField] internal AudioSource hum; [SerializeField] internal float emberScale = 1f; [SerializeField] internal float humScale = 1f; private Quaternion[] haloRest; private Vector3 floaterRest; private Vector3 heartRest; private Quaternion heartRestRotation; private float phase; private bool placed; private static bool warned; private void Start() { //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_0172: Unknown result type (might be due to invalid IL or missing references) //IL_0177: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Unknown result type (might be due to invalid IL or missing references) if (!warned && ((Object)(object)orbit == (Object)null || halos == null || (Object)(object)floater == (Object)null || (Object)(object)hum == (Object)null)) { warned = true; ManualLogSource log = Plugin.Log; object[] obj = new object[5] { ((Object)this).name, (Object)(object)orbit != (Object)null, null, null, null }; Transform[] array = halos; obj[2] = ((array != null) ? array.Length : 0); obj[3] = (Object)(object)floater != (Object)null; obj[4] = (Object)(object)hum != (Object)null; log.LogWarning((object)string.Format("{0}: pillar effect references missing (orbit {1}, halos {2}, tip {3}, hum {4}).", obj)); } Transform[] array2 = halos; haloRest = (Quaternion[])(object)new Quaternion[(array2 != null) ? array2.Length : 0]; for (int i = 0; i < haloRest.Length; i++) { haloRest[i] = halos[i].localRotation; } if ((Object)(object)floater != (Object)null) { floaterRest = floater.localPosition; Renderer val = default(Renderer); if (((Component)floater).TryGetComponent<Renderer>(ref val)) { val.sharedMaterials = val.sharedMaterials.Select(PillarMaterials.Unnoised).ToArray(); } } if ((Object)(object)heart != (Object)null) { heartRest = heart.localPosition; heartRestRotation = heart.localRotation; } phase = Random.Range(0f, 100f); ZNetView component = ((Component)this).GetComponent<ZNetView>(); placed = (Object)(object)component != (Object)null && component.IsValid(); if ((Object)(object)heartLight != (Object)null) { ((Behaviour)heartLight).enabled = placed; } if ((Object)(object)embers != (Object)null && !placed) { embers.Stop(true, (ParticleSystemStopBehavior)0); } if ((Object)(object)hum != (Object)null) { if (placed && (Object)(object)hum.clip != (Object)null) { hum.time = Random.Range(0f, hum.clip.length); hum.Play(); } else { ((Behaviour)hum).enabled = false; } } } private static float Noise(float t, float seed) { return 2f * Mathf.PerlinNoise(t * 0.18f, seed) - 1f; } internal string Describe() { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) string[] obj = new string[6] { string.Format("placed {0}, orbit {1}, ", placed, ((Object)(object)orbit != (Object)null) ? (orbit.localEulerAngles.y.ToString("0") + " deg") : "missing"), null, null, null, null, null }; Transform[] array = halos; obj[1] = string.Format("halos {0}, tip {1}, ", (array != null) ? array.Length : 0, ((Object)(object)floater != (Object)null) ? "ok" : "missing"); obj[2] = "hum "; obj[3] = (((Object)(object)hum == (Object)null) ? "missing" : (hum.isPlaying ? $"playing at {hum.volume:0.00}" : "silent")); obj[4] = ", light "; obj[5] = (((Object)(object)heartLight != (Object)null && ((Behaviour)heartLight).enabled) ? heartLight.intensity.ToString("0.00") : "off"); return string.Concat(obj); } private void Update() { //IL_0032: 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_00b1: 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_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_0211: Unknown result type (might be due to invalid IL or missing references) //IL_0216: Unknown result type (might be due to invalid IL or missing references) //IL_0226: Unknown result type (might be due to invalid IL or missing references) float num = Time.time + phase; if ((Object)(object)orbit != (Object)null) { orbit.localRotation = Quaternion.Euler(0f, num * 40f, 0f); } for (int i = 0; i < haloRest.Length; i++) { float num2 = ((i % 2 == 0) ? (-1f) : 1f); halos[i].localRotation = haloRest[i] * Quaternion.Euler(0f, num2 * num * 20f, 0f); } if ((Object)(object)floater != (Object)null) { floater.localPosition = floaterRest + Vector3.up * (0.05f * Mathf.Sin((float)Math.PI * 2f * num / 6f)); } if ((Object)(object)heart != (Object)null) { heart.localPosition = heartRest + Vector3.up * (Noise(num, 7.3f) * 0.42f); float t = num * 0.5f; heart.localRotation = Quaternion.Euler(Noise(t, 21.7f) * 20f, Noise(t, 31.9f) * 20f * 2f, Noise(t, 43.3f) * 20f) * heartRestRotation; } if (placed) { if ((Object)(object)heartLight != (Object)null) { float num3 = 0.5f - 0.5f * Mathf.Cos((float)Math.PI * 2f * Time.time / 5f); heartLight.intensity = 2f * Mathf.Lerp(0.85f, 1f, num3); } if ((Object)(object)hum != (Object)null) { hum.volume = Plugin.HumVolume * humScale; } if ((Object)(object)embers != (Object)null) { EmissionModule emission = embers.emission; ((EmissionModule)(ref emission)).rateOverTime = MinMaxCurve.op_Implicit(20f * emberScale); } } } } internal static class PillarMaterials { private static readonly Color LavaColor = new Color(1f, 0.3f, 0.04f); private static readonly Color RuneColor = new Color(0.2f, 1f, 0.4f); private const float RuneGlow = 1.5f; private static Material stone; private static Material flametal; private static Material lava; private static Material runes; private static Material halo; private static Material core; private static Material plainStone; private static Material plainStoneDark; private static Color coreEmission; private const string ValueNoise = "_VALUENOISEVERTEX_ON"; private static readonly Dictionary<Material, Material> unnoised = new Dictionary<Material, Material>(); internal static Material Get(string key) { switch (key) { case "stone": return stone; case "flametal": return flametal; case "lava": return lava; case "runes": return runes; case "halo": return halo; default: Plugin.Log.LogWarning((object)("Unknown material key '" + key + "' in a pillar model.")); return stone; } } internal static Material GetStony(string key) { if (!(key == "lava")) { if (key == "flametal") { return plainStoneDark; } return plainStone; } return lava; } internal static Material Unnoised(Material material) { //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Expected O, but got Unknown if ((Object)(object)material == (Object)null || (Object)(object)material.shader == (Object)null || ((Object)material.shader).name != "Custom/Piece" || ((Object)material).name.EndsWith("_still")) { return material; } if ((Object)(object)material == (Object)(object)lava || (Object)(object)material == (Object)(object)runes) { Still(material); return material; } if (!unnoised.TryGetValue(material, out var value)) { value = new Material(material) { name = ((Object)material).name + "_still" }; Still(value); unnoised[material] = value; } return value; } private static void Still(Material material) { material.DisableKeyword("_VALUENOISEVERTEX_ON"); string[] propertyNames = material.GetPropertyNames((MaterialPropertyType)0); foreach (string text in propertyNames) { if (text.IndexOf("ValueNoise", StringComparison.OrdinalIgnoreCase) >= 0) { material.SetFloat(text, 0f); } } } internal static void Load() { //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_007f: 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_008f: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Expected O, but got Unknown //IL_00a3: 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_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Expected O, but got Unknown //IL_00e8: 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_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Expected O, but got Unknown if (!((Object)(object)stone != (Object)null)) { stone = FindMaterial("Ashlands_Stone_Ashen_Rough_mat") ?? PieceMaterial("Piece_grausten_pillarbase_medium", "new"); flametal = PieceMaterial("Piece_flametal_pillar", "new") ?? stone; plainStone = PieceMaterial("Rock_3", "") ?? stone; plainStoneDark = new Material(plainStone) { name = "LinkedStorage_stone_dark", color = plainStone.color * 0.55f }; lava = new Material(stone) { name = "LinkedStorage_lava", color = new Color(0.12f, 0.04f, 0.01f) }; Glow(lava, null); Texture2D val = RuneGlyphs.Create(); runes = new Material(stone) { name = "LinkedStorage_runes", color = stone.color * 0.4f }; Glow(runes, (Texture)(object)val); halo = HaloMaterial((Texture)(object)val); Animate(0f); } } internal static void Animate(float time) { //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)stone == (Object)null) { return; } float num = 0.5f - 0.5f * Mathf.Cos((float)M