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 GuildChest v1.1.1
BepInEx/plugins/GuildChest/GuildChest.Core.dll
Decompiled 3 days agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using Microsoft.CodeAnalysis; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")] [assembly: AssemblyCompany("GuildChest.Core")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.1.1.0")] [assembly: AssemblyInformationalVersion("1.1.1+cf8384c482f04f6c0dbd198ddf18e16e717a54d7")] [assembly: AssemblyProduct("GuildChest.Core")] [assembly: AssemblyTitle("GuildChest.Core")] [assembly: AssemblyVersion("1.1.1.0")] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } } namespace GuildChest.Core { public enum AccessResult { Accepted, Busy, UnknownChest, InvalidSession, StaleRevision, InvalidSequence, AccessDenied, InvalidInventory, ItemMismatch, InvalidDimensions } public sealed class StoreSnapshot { public byte[] Inventory { get; } public long Revision { get; } public StoreSnapshot(byte[] inventory, long revision) { Inventory = (byte[])inventory.Clone(); Revision = revision; } } public sealed class Lease { internal long Sequence; internal byte[]? LastPayload; public long Peer { get; } public string Chest { get; } public string Token { get; } = Guid.NewGuid().ToString("N"); public double ExpiresAt { get; internal set; } public Lease(long peer, string chest, double expiresAt) { Peer = peer; Chest = chest; ExpiresAt = expiresAt; } } public sealed class SharedStore { public const double LeaseSeconds = 30.0; private readonly HashSet<string> chests = new HashSet<string>(StringComparer.Ordinal); private byte[] inventory; private long revision; private readonly Dictionary<string, byte[]> receipts = new Dictionary<string, byte[]>(StringComparer.Ordinal); private readonly Queue<string> receiptOrder = new Queue<string>(); public Lease? ActiveLease { get; private set; } public int ChestCount => chests.Count; public SharedStore(byte[] savedInventory, long savedRevision) { inventory = (byte[])savedInventory.Clone(); revision = savedRevision; } public StoreSnapshot Snapshot() { return new StoreSnapshot(inventory, revision); } public bool Register(string chest) { return chests.Add(chest); } public bool Contains(string chest) { return chests.Contains(chest); } public AccessResult Open(long peer, string chest, double now, out Lease? lease) { Expire(now); lease = null; if (!chests.Contains(chest)) { return AccessResult.UnknownChest; } if (ActiveLease != null) { if (ActiveLease.Peer != peer || ActiveLease.Chest != chest) { return AccessResult.Busy; } ActiveLease.ExpiresAt = now + 30.0; lease = ActiveLease; return AccessResult.Accepted; } Lease lease2 = (ActiveLease = new Lease(peer, chest, now + 30.0)); lease = lease2; return AccessResult.Accepted; } public AccessResult Commit(long peer, string token, long expectedRevision, long sequence, byte[] payload, double now) { if (TryReplay(peer, token, sequence, payload, out var result)) { return result; } if (!Authorized(peer, token, now)) { return AccessResult.InvalidSession; } Lease activeLease = ActiveLease; if (sequence == activeLease.Sequence && activeLease.LastPayload != null) { if (!payload.SequenceEqual(activeLease.LastPayload)) { return AccessResult.InvalidSequence; } return AccessResult.Accepted; } if (sequence != activeLease.Sequence + 1) { return AccessResult.InvalidSequence; } if (expectedRevision != revision) { return AccessResult.StaleRevision; } inventory = (byte[])payload.Clone(); revision++; activeLease.Sequence = sequence; activeLease.LastPayload = (byte[])payload.Clone(); activeLease.ExpiresAt = now + 30.0; string text = ReceiptKey(peer, token, sequence); receipts.Add(text, (byte[])payload.Clone()); receiptOrder.Enqueue(text); while (receiptOrder.Count > 256) { receipts.Remove(receiptOrder.Dequeue()); } return AccessResult.Accepted; } private static string ReceiptKey(long peer, string token, long sequence) { return $"{peer}/{token}/{sequence}"; } public bool TryReplay(long peer, string token, long sequence, byte[] payload, out AccessResult result) { result = AccessResult.InvalidSession; if (!receipts.TryGetValue(ReceiptKey(peer, token, sequence), out byte[] value)) { return false; } result = ((!value.SequenceEqual(payload)) ? AccessResult.InvalidSequence : AccessResult.Accepted); return true; } public bool Heartbeat(long peer, string token, double now) { if (!Authorized(peer, token, now)) { return false; } ActiveLease.ExpiresAt = now + 30.0; return true; } public bool Close(long peer, string token) { Lease? activeLease = ActiveLease; if (activeLease == null || activeLease.Peer != peer || ActiveLease.Token != token) { return false; } ActiveLease = null; return true; } public void Disconnect(long peer) { Lease? activeLease = ActiveLease; if (activeLease != null && activeLease.Peer == peer) { ActiveLease = null; } } public void Expire(double now) { if (ActiveLease != null && now >= ActiveLease.ExpiresAt) { ActiveLease = null; } } public bool Authorized(long peer, string token, double now) { Expire(now); Lease? activeLease = ActiveLease; if (activeLease != null && activeLease.Peer == peer) { return ActiveLease.Token == token; } return false; } public bool Remove(string chest) { if (!chests.Remove(chest)) { return false; } if (ActiveLease?.Chest == chest) { ActiveLease = null; } return true; } } public enum TransferPhase { AwaitingAcknowledgement, Accepted, Applied, Rejected, Completed } public sealed class TransferLifecycle { public TransferPhase Phase { get; private set; } public bool Acknowledge(bool accepted) { if (Phase != TransferPhase.AwaitingAcknowledgement) { return false; } Phase = (accepted ? TransferPhase.Accepted : TransferPhase.Rejected); return true; } public bool TryApply(Action mutation) { if (Phase != TransferPhase.Accepted) { return false; } mutation(); Phase = TransferPhase.Applied; return true; } public bool Finish() { if (Phase != TransferPhase.Applied && Phase != TransferPhase.Rejected) { return false; } Phase = TransferPhase.Completed; return true; } } public sealed class TransferCompletion { private Action<bool, string>? callback; private readonly Action<Exception> logError; public bool IsCompleted { get; private set; } public TransferCompletion(Action<bool, string>? callback, Action<Exception> logError) { this.callback = callback; this.logError = logError; } public void Complete(bool accepted, string reason) { if (IsCompleted) { return; } IsCompleted = true; Action<bool, string> action = callback; callback = null; try { action?.Invoke(accepted, reason); } catch (Exception obj) { logError(obj); } } } }
BepInEx/plugins/GuildChest/GuildChest.dll
Decompiled 3 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.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using GuildChest.Core; using HarmonyLib; using Jotunn.Configs; using Jotunn.Entities; using Jotunn.Managers; using Jotunn.Utils; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyCompany("GuildChest")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.1.1.0")] [assembly: AssemblyInformationalVersion("1.1.1+cf8384c482f04f6c0dbd198ddf18e16e717a54d7")] [assembly: AssemblyProduct("GuildChest")] [assembly: AssemblyTitle("GuildChest")] [assembly: AssemblyVersion("1.1.1.0")] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } } namespace GuildChest { internal static class AutoStoreAdapter { private sealed class Bindings { internal readonly MethodInfo Query; internal readonly MethodInfo Store; internal readonly MethodInfo Success; internal readonly MethodInfo ClearPending; internal readonly MethodInfo Ping; internal readonly MethodInfo StoreAll; internal readonly MethodInfo StoreSingle; internal readonly FieldInfo Pings; internal readonly Func<float> Range; internal readonly (MethodInfo Target, string Prefix)[] Hooks; internal Bindings(Type plugin) { Assembly assembly = plugin.Assembly; Type type = StorageBindings.Type(assembly, "AzuAutoStore.Util.Functions"); Type type2 = StorageBindings.Type(assembly, "AzuAutoStore.Util.Boxes"); Type type3 = StorageBindings.Type(assembly, "AzuAutoStore.Interfaces.VanillaContainers"); Type type4 = StorageBindings.Type(assembly, "AzuAutoStore.Interfaces.IContainer"); ContainerBindings.Validate(type3, crafting: false); Query = StorageBindings.NearbyQuery(type2); Store = StorageBindings.Method(type, "StoreToContainer", typeof(int), new Type[3] { type4, typeof(ItemData), typeof(Inventory) }); Success = StorageBindings.Method(type, "StoreSuccess", typeof(void), new Type[1] { typeof(int) }); ClearPending = StorageBindings.Method(type, "ClearPendingSends", typeof(void), Type.EmptyTypes); Ping = StorageBindings.Method(type, "PingContainer", typeof(void), new Type[1] { typeof(GameObject) }); StoreAll = StorageBindings.Method(type3, "TryStore", typeof(int), Type.EmptyTypes); StoreSingle = StorageBindings.Method(type3, "TryStoreThisItem", typeof(int), new Type[2] { typeof(ItemData), typeof(Inventory) }); Pings = StorageBindings.Field(type2, "ContainersToPing"); if (!Pings.IsStatic || !typeof(IList).IsAssignableFrom(Pings.FieldType)) { throw new InvalidOperationException("Unsupported AutoStore ping collection."); } Range = StorageBindings.Setting<float>(plugin, "PlayerRange"); Hooks = new(MethodInfo, string)[4] { (Store, "StoreContainer"), (StorageBindings.Method(type, "TryStore", typeof(bool), new Type[4] { typeof(Container), typeof(ItemData).MakeByRefType(), typeof(bool), typeof(bool) }), "StoreDirect"), (StorageBindings.Method(type, "TryStore", typeof(void), Type.EmptyTypes), "Begin"), (StorageBindings.Method(type, "TryStoreThisItem", typeof(void), new Type[2] { typeof(ItemData), typeof(Inventory) }), "Begin") }; } } internal const string PluginId = "Azumatt.AzuAutoStore"; private static Bindings? bindings; private static Bindings Api => bindings ?? throw new InvalidOperationException("AutoStore adapter is unavailable."); private static IList Pings => (IList)Api.Pings.GetValue(null); internal static float Range => Api.Range(); internal static void Install(Harmony harmony, Type plugin) { Bindings bindings = new Bindings(plugin); StorageBindings.Patch(harmony, typeof(AutoStoreAdapter), bindings.Hooks); AutoStoreAdapter.bindings = bindings; } internal static List<object> Nearby(Player player) { return ((IEnumerable)Api.Query.Invoke(null, new object[2] { player, Range })).Cast<object>().ToList(); } internal static int Store(object container, ItemData? item, Inventory? inventory) { return (int)Api.Store.Invoke(null, new object[3] { container, item, inventory }); } internal static void Success(int count) { Api.Success.Invoke(null, new object[1] { count }); } internal static void ClearPending() { Pings.Clear(); Api.ClearPending.Invoke(null, null); } private static bool Begin(object[] __args) { return AutoStoreBatch.Begin(__args); } private static bool StoreDirect(Container nearbyContainer, ref bool __result) { if (!Plugin.IsGuild(nearbyContainer) || (Object)(object)nearbyContainer == (Object)(object)InventoryAccess.ScopedChest) { return true; } __result = false; return false; } private static bool StoreContainer(object container, ItemData? singleItem, Inventory? inv, ref int __result) { if (!Plugin.IsGuild(ContainerBindings.ContainerFor(container))) { return !Client.Pending; } __result = 0; StoreGuild(container, singleItem, inv, null); return false; } internal static bool StoreGuild(object container, ItemData? singleItem, Inventory? inv, Action? completed) { Container chest = ContainerBindings.ContainerFor(container); if (bindings == null || Client.Pending || Client.Opening) { return false; } int stored = 0; return GuildChestStorage.TryTransfer(chest, delegate(Inventory player, Inventory shared) { ItemData val = null; if (singleItem != null) { Inventory inventory = ((Humanoid)Player.m_localPlayer).GetInventory(); if (inv != inventory || !inventory.ContainsItem(singleItem)) { return; } val = player.GetItemAt(singleItem.m_gridPos.x, singleItem.m_gridPos.y); } using (new InventoryAccess.StagingScope(Player.m_localPlayer, chest, player, shared)) { try { stored = (int)((singleItem == null) ? Api.StoreAll.Invoke(container, null) : Api.StoreSingle.Invoke(container, new object[2] { val, player })); } finally { Pings.Remove(container); } } }, delegate(bool accepted, string reason) { //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_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) try { if (accepted && stored > 0) { Plugin.Message($"Stored {stored} items in guild storage."); if (Object.op_Implicit((Object)(object)chest)) { Api.Ping.Invoke(null, new object[1] { ((Component)chest).gameObject }); if (Object.op_Implicit((Object)(object)InventoryGui.instance)) { AccessTools.FieldRefAccess<InventoryGui, EffectList>("m_moveItemEffects").Invoke(InventoryGui.instance).Create(((Component)chest).transform.position, Quaternion.identity, (Transform)null, 1f, -1, default(ZDOID)); } } } else if (!accepted) { Plugin.Message("Guild auto-store failed: " + reason); } } finally { completed?.Invoke(); } }); } } internal static class AutoStoreBatch { private sealed class Batch { internal Player Player; internal Inventory Inventory; internal ItemData? Item; internal List<object> Destinations; internal int Index; internal int OrdinaryStored; internal bool Waiting; internal bool UsedGuild; } private static Batch? active; internal static void Reset() { active = null; } private static bool Available(object wrapper, Player player, bool guild) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0020: 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) GameObject val = ContainerBindings.ObjectFor(wrapper); if (!Object.op_Implicit((Object)(object)val) || Vector3.Distance(val.transform.position, ((Component)player).transform.position) > (guild ? Math.Min(AutoStoreAdapter.Range, Plugin.AutomationRange.Value) : AutoStoreAdapter.Range)) { return false; } ZNetView component = val.GetComponent<ZNetView>(); if (!Object.op_Implicit((Object)(object)component) || component.IsValid()) { return PrivateArea.CheckAccess(val.transform.position, 0f, false, true); } return false; } internal static bool Begin(object[] __args) { if (active != null || Client.Pending || Client.Opening) { return false; } Player localPlayer = Player.m_localPlayer; if (!Object.op_Implicit((Object)(object)localPlayer) || ((Character)localPlayer).IsDead() || ((Character)localPlayer).IsTeleporting()) { return true; } Inventory inventory = ((Humanoid)localPlayer).GetInventory(); ItemData val = (ItemData)((__args.Length == 0) ? null : /*isinst with value type is only supported in some contexts*/); if (__args.Length != 0 && (val == null || __args[1] != inventory || !inventory.ContainsItem(val))) { return false; } try { List<object> list = AutoStoreAdapter.Nearby(localPlayer); if (!list.Any((object destination) => Plugin.IsGuild(ContainerBindings.ContainerFor(destination)))) { return true; } AutoStoreAdapter.ClearPending(); active = new Batch { Player = localPlayer, Inventory = inventory, Item = val, Destinations = list }; Tick(); } catch (Exception exception) { Reset(); Plugin.Error(exception); } return false; } private static void Flush(Batch batch) { int ordinaryStored = batch.OrdinaryStored; batch.OrdinaryStored = 0; AutoStoreAdapter.Success(ordinaryStored); } internal static void Tick() { Batch batch = active; if (batch == null || batch.Waiting || Client.Pending || Client.Opening) { return; } try { if (!Object.op_Implicit((Object)(object)batch.Player) || (Object)(object)batch.Player != (Object)(object)Player.m_localPlayer || ((Character)batch.Player).IsDead() || ((Character)batch.Player).IsTeleporting() || ((Humanoid)batch.Player).GetInventory() != batch.Inventory || (batch.Item != null && !batch.Inventory.ContainsItem(batch.Item))) { Flush(batch); Reset(); return; } while (batch.Index < batch.Destinations.Count) { object obj = batch.Destinations[batch.Index++]; bool flag = Plugin.IsGuild(ContainerBindings.ContainerFor(obj)); if ((flag && batch.UsedGuild) || !Available(obj, batch.Player, flag)) { continue; } if (!flag) { batch.OrdinaryStored += AutoStoreAdapter.Store(obj, batch.Item, (batch.Item == null) ? null : batch.Inventory); if (batch.Item != null && !batch.Inventory.ContainsItem(batch.Item)) { break; } continue; } Flush(batch); batch.UsedGuild = true; batch.Waiting = true; if (!AutoStoreAdapter.StoreGuild(obj, batch.Item, (batch.Item == null) ? null : batch.Inventory, delegate { if (active == batch) { batch.Waiting = false; } })) { batch.Waiting = false; } return; } Flush(batch); Reset(); } catch (Exception exception) { Reset(); AutoStoreAdapter.ClearPending(); Plugin.Error(exception); } } } internal static class BuildingContinuation { private sealed class Intent { internal Player Player; internal Piece Piece; internal ItemData Tool; internal Vector3 Position; internal Vector3 PlayerPosition; internal Quaternion Rotation; internal float Started; internal bool Ready; } private static Intent? pending; private static bool replaying; private static readonly MethodInfo updateGhost = AccessTools.Method(typeof(Player), "UpdatePlacementGhost", new Type[1] { typeof(bool) }, (Type[])null); private static GameObject Ghost(Player player) { return AccessTools.FieldRefAccess<Player, GameObject>("m_placementGhost").Invoke(player); } internal static void Reset() { pending = null; replaying = false; } private static bool MatchesContext(Intent intent) { //IL_0082: 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) if (Object.op_Implicit((Object)(object)intent.Player) && (Object)(object)intent.Player == (Object)(object)Player.m_localPlayer && !((Character)intent.Player).IsDead() && !((Character)intent.Player).IsTeleporting() && ((Character)intent.Player).InPlaceMode() && (Object)(object)intent.Player.GetSelectedPiece() == (Object)(object)intent.Piece && ((Humanoid)intent.Player).RightItem == intent.Tool && Vector3.Distance(((Component)intent.Player).transform.position, intent.PlayerPosition) <= 0.5f) { return Time.unscaledTime - intent.Started <= 30f; } return false; } private static bool Matches(Intent intent) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) if (!MatchesContext(intent)) { return false; } GameObject val = Ghost(intent.Player); if (Object.op_Implicit((Object)(object)val) && val.activeInHierarchy && Vector3.Distance(val.transform.position, intent.Position) <= 0.1f) { return Quaternion.Angle(val.transform.rotation, intent.Rotation) <= 1f; } return false; } internal static bool TryPlace(Player player, Piece piece) { //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) if (replaying) { bool result = pending != null && (Object)(object)pending.Piece == (Object)(object)piece && Matches(pending); Reset(); return result; } if (pending != null || Client.Pending || Client.Opening) { return false; } if (player.NoCostCheat() || ZoneSystem.instance.GetGlobalKey(piece.FreeBuildKey())) { return true; } GameObject val = Ghost(player); ItemData rightItem = ((Humanoid)player).RightItem; if (!((Character)player).InPlaceMode() || (Object)(object)player.GetSelectedPiece() != (Object)(object)piece || !Object.op_Implicit((Object)(object)val) || rightItem == null) { return true; } updateGhost.Invoke(player, new object[1] { true }); if ((int)player.GetPlacementStatus() != 0 || !val.activeInHierarchy) { return true; } Intent intent = new Intent { Player = player, Piece = piece, Tool = rightItem, Position = val.transform.position, Rotation = val.transform.rotation, PlayerPosition = ((Component)player).transform.position, Started = Time.unscaledTime }; pending = intent; if (MaterialSupply.Supply(piece.m_resources, 0, 1, onlyOne: false, building: true, delegate { if (pending == intent) { intent.Ready = true; } })) { return false; } pending = null; return true; } internal static void BeforeUpdate(Player player, bool takeInput) { //IL_0059: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)player != (Object)(object)Player.m_localPlayer || pending == null) { return; } if (!takeInput || !MatchesContext(pending) || Hud.IsPieceSelectionVisible()) { Reset(); return; } updateGhost.Invoke(player, new object[1] { false }); if (!Matches(pending) || (int)player.GetPlacementStatus() != 0) { Reset(); } else if (!pending.Ready) { if (!Client.Pending && !Client.Opening) { Reset(); } } else if (!Client.Pending && !Client.Opening) { AccessTools.FieldRefAccess<Player, float>("m_placePressedTime").Invoke(player) = Time.time; replaying = true; } } internal static void AfterUpdate(Player player) { if (!((Object)(object)player != (Object)(object)Player.m_localPlayer) && replaying) { Reset(); AccessTools.FieldRefAccess<Player, float>("m_placePressedTime").Invoke(player) = -9999f; } } } internal static class ChestAppearance { internal const string DecorationName = "GuildChestCoins"; internal static void Apply(GameObject prefab) { //IL_0037: 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_0055: Unknown result type (might be due to invalid IL or missing references) //IL_01b0: Unknown result type (might be due to invalid IL or missing references) //IL_01b5: Unknown result type (might be due to invalid IL or missing references) //IL_01e9: Unknown result type (might be due to invalid IL or missing references) //IL_01ee: Unknown result type (might be due to invalid IL or missing references) //IL_030a: Unknown result type (might be due to invalid IL or missing references) //IL_030f: Unknown result type (might be due to invalid IL or missing references) //IL_0205: Unknown result type (might be due to invalid IL or missing references) //IL_01f7: Unknown result type (might be due to invalid IL or missing references) //IL_0221: Unknown result type (might be due to invalid IL or missing references) //IL_022d: Unknown result type (might be due to invalid IL or missing references) //IL_0239: Unknown result type (might be due to invalid IL or missing references) //IL_023e: Unknown result type (might be due to invalid IL or missing references) //IL_0328: Unknown result type (might be due to invalid IL or missing references) //IL_033e: Unknown result type (might be due to invalid IL or missing references) //IL_034a: Unknown result type (might be due to invalid IL or missing references) //IL_0354: Unknown result type (might be due to invalid IL or missing references) //IL_036c: Unknown result type (might be due to invalid IL or missing references) //IL_02a6: Unknown result type (might be due to invalid IL or missing references) //IL_02ab: Unknown result type (might be due to invalid IL or missing references) Renderer[] componentsInChildren = prefab.GetComponentsInChildren<Renderer>(true); for (int i = 0; i < componentsInChildren.Length; i++) { Material[] materials = componentsInChildren[i].materials; foreach (Material val in materials) { if (val.HasProperty("_Color")) { val.color *= new Color(1f, 0.78f, 0.3f, 1f); } } } GameObject prefab2 = PrefabManager.Instance.GetPrefab("Coins"); MeshFilter val2 = (Object.op_Implicit((Object)(object)prefab2) ? ((IEnumerable<MeshFilter>)prefab2.GetComponentsInChildren<MeshFilter>(true)).FirstOrDefault((Func<MeshFilter, bool>)((MeshFilter filter) => Object.op_Implicit((Object)(object)filter.sharedMesh) && ((Object)filter.sharedMesh).name == "coin")) : null); MeshRenderer val3 = (Object.op_Implicit((Object)(object)val2) ? ((Component)val2).GetComponent<MeshRenderer>() : null); MeshFilter val4 = ((IEnumerable<MeshFilter>)prefab.GetComponentsInChildren<MeshFilter>(true)).FirstOrDefault((Func<MeshFilter, bool>)((MeshFilter filter) => Object.op_Implicit((Object)(object)filter.sharedMesh) && ((Object)filter.sharedMesh).name == "ironchest")); Container component = prefab.GetComponent<Container>(); MeshFilter val5 = (Object.op_Implicit((Object)(object)component.m_closed) ? component.m_closed.GetComponent<MeshFilter>() : null); MeshFilter val6 = (Object.op_Implicit((Object)(object)component.m_open) ? component.m_open.GetComponent<MeshFilter>() : null); if (!Object.op_Implicit((Object)(object)val2) || !Object.op_Implicit((Object)(object)val3) || !val2.sharedMesh.isReadable || !Object.op_Implicit((Object)(object)val4) || !Object.op_Implicit((Object)(object)val5) || !Object.op_Implicit((Object)(object)val6) || !val4.sharedMesh.isReadable || !val5.sharedMesh.isReadable) { Plugin.LogWarning("Guild chest coin decorations unavailable: expected vanilla coin or chest meshes are missing."); return; } List<CombineInstance> list = new List<CombineInstance>(); Bounds bounds = val4.sharedMesh.bounds; int[] array = new int[2] { -1, 1 }; foreach (int num in array) { Quaternion rotation = Quaternion.Euler(90f * (float)num, 0f, 0f); float num2 = ((num < 0) ? ((Bounds)(ref bounds)).min.z : ((Bounds)(ref bounds)).max.z); AddCoin(list, val2.sharedMesh, val4.sharedMesh, new Vector3(((Bounds)(ref bounds)).center.x, ((Bounds)(ref bounds)).center.y, num2), rotation, 0.46f); float[] array2 = new float[2] { -0.55f, 0.55f }; foreach (float num3 in array2) { float[] array3 = new float[2] { 0.38f, 0.72f }; foreach (float num5 in array3) { AddCoin(list, val2.sharedMesh, val4.sharedMesh, new Vector3(num3, num5, num2), rotation, 0.13f); } } } AddDecoration(((Component)val4).transform, Combine("GuildChestCoinSeals", list), val3); List<CombineInstance> list2 = new List<CombineInstance>(); Bounds bounds2 = val5.sharedMesh.bounds; for (int num6 = -2; num6 <= 2; num6++) { AddCoin(list2, val2.sharedMesh, val5.sharedMesh, new Vector3(((Bounds)(ref bounds2)).center.x + (float)num6 * 0.23f, ((Bounds)(ref bounds2)).max.y, ((Bounds)(ref bounds2)).center.z), Quaternion.Euler(0f, (float)num6 * 18f, 0f), (num6 == 0) ? 0.23f : 0.17f); } Mesh mesh = Combine("GuildChestCoinLid", list2); AddDecoration(((Component)val5).transform, mesh, val3); AddDecoration(((Component)val6).transform, mesh, val3); } private static void AddCoin(List<CombineInstance> instances, Mesh coin, Mesh mountingMesh, Vector3 surface, Quaternion rotation, float diameter) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: 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_0028: 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) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_003f: 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_0043: Unknown result type (might be due to invalid IL or missing references) //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_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0073: 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_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_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_008d: 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_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009a: 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) Bounds bounds = coin.bounds; float num = diameter / Mathf.Max(((Bounds)(ref bounds)).size.x, ((Bounds)(ref bounds)).size.z); Vector3 val = rotation * Vector3.up; surface = FindSurface(mountingMesh, surface, val); Vector3 val2 = surface + val * (((Bounds)(ref bounds)).extents.y * num - 0.001f); CombineInstance item = default(CombineInstance); ((CombineInstance)(ref item)).mesh = coin; ((CombineInstance)(ref item)).transform = Matrix4x4.TRS(val2 - rotation * (((Bounds)(ref bounds)).center * num), rotation, Vector3.one * num); instances.Add(item); } private static Vector3 FindSurface(Mesh mesh, Vector3 surface, Vector3 outward) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_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_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0060: 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_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006a: 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_006e: 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_0086: 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_008d: 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_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0125: 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_0117: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_011f: 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_00b1: 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_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: 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_00de: Unknown result type (might be due to invalid IL or missing references) Vector3 val = surface + outward; Vector3 val2 = -outward; Vector3[] vertices = mesh.vertices; int[] triangles = mesh.triangles; float num = float.PositiveInfinity; for (int i = 0; i < triangles.Length; i += 3) { Vector3 val3 = vertices[triangles[i]]; Vector3 val4 = vertices[triangles[i + 1]] - val3; Vector3 val5 = vertices[triangles[i + 2]] - val3; Vector3 val6 = Vector3.Cross(val2, val5); float num2 = Vector3.Dot(val4, val6); if (Mathf.Abs(num2) < 1E-06f) { continue; } Vector3 val7 = val - val3; float num3 = Vector3.Dot(val7, val6) / num2; if (num3 < 0f || num3 > 1f) { continue; } Vector3 val8 = Vector3.Cross(val7, val4); float num4 = Vector3.Dot(val2, val8) / num2; if (!(num4 < 0f) && !(num3 + num4 > 1f)) { float num5 = Vector3.Dot(val5, val8) / num2; if (num5 >= 0f && num5 < num) { num = num5; } } } if (!float.IsPositiveInfinity(num)) { return val + val2 * num; } return surface; } private static Mesh Combine(string name, List<CombineInstance> coins) { //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_0019: Expected O, but got Unknown Mesh val = new Mesh { name = name }; val.CombineMeshes(coins.ToArray()); return val; } private static void AddDecoration(Transform parent, Mesh mesh, MeshRenderer source) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_001b: 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_0047: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("GuildChestCoins") { layer = ((Component)parent).gameObject.layer }; val.transform.SetParent(parent, false); val.AddComponent<MeshFilter>().sharedMesh = mesh; MeshRenderer obj = val.AddComponent<MeshRenderer>(); ((Renderer)obj).sharedMaterials = ((Renderer)source).sharedMaterials; ((Renderer)obj).shadowCastingMode = ((Renderer)source).shadowCastingMode; ((Renderer)obj).receiveShadows = ((Renderer)source).receiveShadows; } } internal enum QuickAction { None, Stack, Take, Automation } internal static class Client { private sealed class OpenRequest { internal Container Chest; internal Player Player; internal Inventory Inventory; internal ZDOID Id; internal long Sequence; internal float Started; internal QuickAction Action; internal Action<Inventory, Inventory>? Transfer; internal TransferCompletion? Completion; } internal sealed class Transaction { internal readonly Inventory PlayerStage; internal readonly List<ItemData> PlayerOriginals; internal readonly Dictionary<ItemData, ItemData> Bindings = new Dictionary<ItemData, ItemData>(); internal readonly Inventory SharedStage; internal readonly byte[] PlayerBefore; internal byte[] Request = Array.Empty<byte>(); internal long Sequence; internal TransferCompletion? Completed; internal readonly TransferLifecycle Lifecycle = new TransferLifecycle(); internal readonly Player Owner; internal readonly Inventory PlayerInventory; internal long ReplyRevision; internal byte[] ReplyInventory = Array.Empty<byte>(); internal string ReplyReason = ""; private List<ItemData> removed = new List<ItemData>(); private bool notified; internal Transaction() { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Expected O, but got Unknown Owner = Player.m_localPlayer; PlayerInventory = ((Humanoid)Owner).GetInventory(); Inventory playerInventory = PlayerInventory; PlayerBefore = InventoryCodec.Save(playerInventory); PlayerOriginals = playerInventory.GetAllItems().ToList(); PlayerStage = InventoryCodec.Clone(playerInventory); SharedStage = InventoryCodec.Clone(View); for (int i = 0; i < PlayerOriginals.Count; i++) { Bindings.Add(PlayerStage.GetAllItems()[i], PlayerOriginals[i]); } } internal void Apply() { //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)Owner) || (Object)(object)Owner != (Object)(object)Player.m_localPlayer || ((Humanoid)Owner).GetInventory() != PlayerInventory) { throw new InvalidOperationException("The original player inventory is no longer available."); } List<ItemData> list = ((IEnumerable<ItemData>)PlayerStage.GetAllItems()).Select((Func<ItemData, ItemData>)delegate(ItemData staged) { if (!Bindings.TryGetValue(staged, out ItemData value2)) { ItemData obj = staged.Clone(); obj.m_equipped = false; return obj; } return value2; }).ToList(); HashSet<ItemData> remaining = new HashSet<ItemData>(list); removed = PlayerOriginals.Where((ItemData item) => !remaining.Contains(item)).ToList(); List<ItemData> allItems = PlayerInventory.GetAllItems(); if (allItems.Capacity < list.Count) { allItems.Capacity = list.Count; } foreach (ItemData allItem in PlayerStage.GetAllItems()) { if (Bindings.TryGetValue(allItem, out ItemData value)) { value.m_stack = allItem.m_stack; value.m_gridPos = allItem.m_gridPos; } } allItems.Clear(); allItems.AddRange(list); } internal void Notify() { if (notified) { return; } notified = true; foreach (ItemData item in removed) { Effect(delegate { ((Humanoid)Owner).RemoveEquipAction(item); }); Effect(delegate { ((Humanoid)Owner).UnequipItem(item, false); }); } Effect(delegate { InventoryCodec.Changed(PlayerInventory); }); } } internal static Container? Chest; internal static Inventory? View; private static OpenRequest? opening; private static long openRequest; private static ZDOID chestId; private static string token = ""; private static long revision; private static long sequence; private static float nextHeartbeat; private static float nextRetry; private static float lastReply; private static bool closeWanted; private static bool deferredDeath; private static Transaction? transaction; private static bool finishing; private static bool resetting; internal static bool Applying; internal static bool Pending => transaction != null; internal static bool HasSession => token.Length != 0; internal static bool Opening => opening != null; internal static Container? CurrentContainer { get { if (!Object.op_Implicit((Object)(object)InventoryGui.instance)) { return null; } return AccessTools.FieldRefAccess<InventoryGui, Container>("m_currentContainer").Invoke(InventoryGui.instance); } } internal static bool GuildUi => Owns(CurrentContainer); internal static bool Owns(Container? container) { if (HasSession && Object.op_Implicit((Object)(object)container)) { return (Object)(object)container == (Object)(object)Chest; } return false; } internal static bool Open(Container container, QuickAction action = QuickAction.None) { return OpenCore(container, action, null, null); } private static bool OpenCore(Container container, QuickAction action, Action<Inventory, Inventory>? transfer, TransferCompletion? completion) { //IL_004d: 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_0079: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) if (Pending || Opening || HasSession || finishing || resetting) { Plugin.Message("The guild inventory is busy."); return false; } if (!Object.op_Implicit((Object)(object)Player.m_localPlayer) || ((Character)Player.m_localPlayer).IsDead() || !PrivateArea.CheckAccess(((Component)container).transform.position, 0f, true, false)) { return false; } ZDO zDO = ((Component)container).GetComponent<ZNetView>().GetZDO(); if (zDO == null) { return false; } chestId = zDO.m_uid; opening = new OpenRequest { Chest = container, Player = Player.m_localPlayer, Inventory = ((Humanoid)Player.m_localPlayer).GetInventory(), Id = chestId, Sequence = ++openRequest, Started = Time.unscaledTime, Action = action, Transfer = transfer, Completion = completion }; lastReply = Time.unscaledTime; try { Send((action == QuickAction.Automation) ? Operation.OpenAutomation : Operation.Open, "", openRequest); } catch (Exception exception) { opening = null; Plugin.Error(exception); return false; } return true; } internal static bool Transfer(Container container, Action<Inventory, Inventory> action, Action<bool, string>? completed) { //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Expected O, but got Unknown if (Pending || Opening || finishing || resetting || !Object.op_Implicit((Object)(object)Player.m_localPlayer) || ((Character)Player.m_localPlayer).IsDead() || ((Character)Player.m_localPlayer).IsTeleporting()) { return false; } if (HasSession && !Owns(container)) { return false; } TransferCompletion val = new TransferCompletion(completed, (Action<Exception>)Plugin.Error); if (Owns(container)) { StageAutomation(action, val); return true; } return OpenCore(container, QuickAction.Automation, action, val); } private static void StageAutomation(Action<Inventory, Inventory> action, TransferCompletion completed) { try { if (!Object.op_Implicit((Object)(object)Player.m_localPlayer) || ((Character)Player.m_localPlayer).IsDead() || ((Character)Player.m_localPlayer).IsTeleporting()) { throw new InvalidOperationException("The player is no longer available for this transfer."); } Transaction transaction = new Transaction { Completed = completed }; action(transaction.PlayerStage, transaction.SharedStage); if (!Submit(transaction)) { if (closeWanted) { Close(); } completed.Complete(true, "No items transferred."); } } catch (Exception ex) { Plugin.Error(ex); if (!Pending) { if (closeWanted) { Close(); } completed.Complete(false, ex.Message); } } } private static void Send(Operation operation, string sessionToken, long requestSequence, ZDOID? target = null) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) Plugin.RequestRpc.SendPackage(Plugin.ServerId, Protocol.Header(operation, (ZDOID)(((??)target) ?? chestId), sessionToken, requestSequence)); } private static void ReleaseGrant(ZDOID id, string receivedToken) { //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) //IL_003f: 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) if (receivedToken.Length != 0 && receivedToken != token && (opening == null || opening.Id != id)) { Effect(delegate { //IL_000a: Unknown result type (might be due to invalid IL or missing references) Send(Operation.Close, receivedToken, 0L, id); }); } } private static bool Valid(OpenRequest request) { if (Object.op_Implicit((Object)(object)request.Chest) && Object.op_Implicit((Object)(object)request.Player) && (Object)(object)request.Player == (Object)(object)Player.m_localPlayer && !((Character)request.Player).IsDead() && !((Character)request.Player).IsTeleporting()) { return ((Humanoid)request.Player).GetInventory() == request.Inventory; } return false; } private static void CancelOpen(string reason) { OpenRequest openRequest = opening; opening = null; if (openRequest != null) { if (openRequest.Completion != null) { openRequest.Completion.Complete(false, reason); } else { Plugin.Message(reason); } } } private static bool Effect(Action action) { try { action(); return true; } catch (Exception exception) { Plugin.Error(exception); return false; } } internal static IEnumerator Receive(long sender, ZPackage package) { try { Handle(sender, package); } catch (Exception exception) { Plugin.Error(exception); Plugin.Message("Guild Chest could not read the host response."); } yield break; } private unsafe static void Handle(long sender, ZPackage package) { //IL_015d: 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) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_0273: Unknown result type (might be due to invalid IL or missing references) //IL_0274: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_031d: 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_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_02c7: Unknown result type (might be due to invalid IL or missing references) //IL_02ca: Invalid comparison between Unknown and I4 //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_02ef: Unknown result type (might be due to invalid IL or missing references) //IL_02fe: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Unknown result type (might be due to invalid IL or missing references) //IL_019f: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Invalid comparison between Unknown and I4 if (!Object.op_Implicit((Object)(object)ZNet.instance) || sender != Plugin.ServerId || package.Size() > 1052672) { return; } Operation operation = (Operation)package.ReadInt(); ZDOID val = package.ReadZDOID(); string text = package.ReadString(); long num = package.ReadLong(); AccessResult val2 = (AccessResult)package.ReadInt(); long replyRevision = package.ReadLong(); byte[] array = package.ReadByteArray(); string text2 = ((package.GetPos() < package.Size()) ? package.ReadString() : ((object)(*(AccessResult*)(&val2))/*cast due to .constrained prefix*/).ToString()); switch (operation) { case Operation.Peek: StoragePreview.ReceiveSnapshot(val, num, val2, replyRevision, array); return; case Operation.Open: case Operation.OpenAutomation: { if (opening == null || val != opening.Id || num != opening.Sequence || operation != (Operation)((opening.Action == QuickAction.Automation) ? 5 : 0)) { if ((int)val2 == 0) { ReleaseGrant(val, text); } return; } OpenRequest openRequest = opening; opening = null; if (!Valid(openRequest)) { if ((int)val2 == 0) { ReleaseGrant(val, text); } TransferCompletion? completion = openRequest.Completion; if (completion != null) { completion.Complete(false, "The player or guild chest is no longer available."); } return; } if ((int)val2 != 0) { TransferCompletion? completion2 = openRequest.Completion; if (completion2 != null) { completion2.Complete(false, text2); } Plugin.Message(((int)val2 == 1) ? "Someone is using the guild inventory." : ("Guild Chest: " + text2)); return; } Inventory view; try { view = InventoryCodec.Read(array); } catch (Exception ex) { ReleaseGrant(val, text); Reset(); TransferCompletion? completion3 = openRequest.Completion; if (completion3 != null) { completion3.Complete(false, ex.Message); } Plugin.Message("Guild Chest: " + ex.Message); return; } chestId = val; Chest = openRequest.Chest; token = text; sequence = 0L; revision = replyRevision; View = view; lastReply = Time.unscaledTime; nextHeartbeat = lastReply + 5f; InventoryAccess.Protect(View); InventoryAccess.ContainerInventory.Invoke(Chest) = View; if (openRequest.Action == QuickAction.Automation) { closeWanted = true; StageAutomation(openRequest.Transfer, openRequest.Completion); } else if (openRequest.Action == QuickAction.None) { if (!Effect(delegate { InventoryGui.instance.Show(Chest, 1); })) { Close(); } } else { closeWanted = true; Bulk(openRequest.Action == QuickAction.Take); } return; } } if (val != chestId || text != token || !HasSession) { return; } lastReply = Time.unscaledTime; switch (operation) { case Operation.Commit: { if (Client.transaction == null || num != Client.transaction.Sequence) { break; } Transaction transaction = Client.transaction; if (transaction.Lifecycle.Acknowledge((int)val2 == 0)) { transaction.ReplyRevision = replyRevision; transaction.ReplyInventory = array; transaction.ReplyReason = text2; if ((int)val2 != 0) { Plugin.LogWarning($"Transfer {num} rejected by host: {val2}. {text2}"); } Finish(transaction); } break; } case Operation.Heartbeat: if ((int)val2 != 0) { closeWanted = true; if (!Pending) { Close(); } } break; } } private static void Finish(Transaction finished) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Invalid comparison between Unknown and I4 //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Invalid comparison between Unknown and I4 if (finishing || transaction != finished) { return; } bool flag = (int)finished.Lifecycle.Phase == 1 || (int)finished.Lifecycle.Phase == 2; finishing = true; try { if (flag) { try { finished.Lifecycle.TryApply((Action)finished.Apply); } catch (Exception exception) { Plugin.Error(exception); nextRetry = Time.unscaledTime + 2f; return; } revision = finished.ReplyRevision; Applying = true; finished.Notify(); if (!Effect(delegate { if (View != null) { InventoryCodec.Replace(View, InventoryCodec.Read(finished.ReplyInventory)); } })) { closeWanted = true; } if (!Effect(delegate { StoragePreview.RefreshSnapshot(finished.ReplyInventory, finished.ReplyRevision); })) { closeWanted = true; } } else { Effect(delegate { Plugin.Message("Transfer rejected: " + finished.ReplyReason + " Your items have not moved."); }); closeWanted = true; } transaction = null; Effect(ClearDrag); if (deferredDeath && Object.op_Implicit((Object)(object)Player.m_localPlayer)) { deferredDeath = false; Effect(delegate { ((Character)Player.m_localPlayer).OnDeath(); }); closeWanted = true; } if (closeWanted || !Object.op_Implicit((Object)(object)Chest)) { Close(); } finished.Lifecycle.Finish(); } finally { Applying = false; finishing = false; } TransferCompletion? completed = finished.Completed; if (completed != null) { completed.Complete(flag, finished.ReplyReason); } } internal static void Close() { if (Pending) { closeWanted = true; return; } if (HasSession && Object.op_Implicit((Object)(object)ZNet.instance) && ZRoutedRpc.instance != null) { Effect(delegate { Send(Operation.Close, token, sequence); }); } Reset(); } internal static void Reset() { //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Invalid comparison between Unknown and I4 OpenRequest openRequest = opening; Transaction transaction = Client.transaction; Chest = null; opening = null; View = null; token = ""; Client.transaction = null; closeWanted = false; deferredDeath = false; resetting = true; try { if (openRequest != null) { TransferCompletion? completion = openRequest.Completion; if (completion != null) { completion.Complete(false, "The guild inventory session ended before it opened."); } } if (transaction != null) { TransferCompletion? completed = transaction.Completed; if (completed != null) { completed.Complete((int)transaction.Lifecycle.Phase == 2, "The session ended before transfer completion. A sent transfer may already have been accepted by the host."); } } } finally { resetting = false; } } internal static bool DeferDeath(Player player) { if ((Object)(object)player != (Object)(object)Player.m_localPlayer || !Pending) { return false; } deferredDeath = true; closeWanted = true; return true; } internal static void Tick() { //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Invalid comparison between Unknown and I4 //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Invalid comparison between Unknown and I4 //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_0162: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)ZNet.instance) || !Object.op_Implicit((Object)(object)ZNetScene.instance)) { return; } float unscaledTime = Time.unscaledTime; if (opening != null && !Valid(opening)) { CancelOpen("The player or guild chest is no longer available."); } else if (opening != null && unscaledTime - opening.Started > 30f) { CancelOpen("Guild Chest host did not respond."); } if (!HasSession) { return; } if (unscaledTime >= nextHeartbeat) { Effect(delegate { Send(Operation.Heartbeat, token, sequence); }); nextHeartbeat = unscaledTime + 5f; } if (Pending) { if (!(unscaledTime >= nextRetry)) { return; } Transaction current = transaction; nextRetry = unscaledTime + 2f; if ((int)current.Lifecycle.Phase == 1 || (int)current.Lifecycle.Phase == 2) { Finish(current); return; } Effect(delegate { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Expected O, but got Unknown Plugin.RequestRpc.SendPackage(Plugin.ServerId, new ZPackage(current.Request)); }); } else if (!Object.op_Implicit((Object)(object)Chest) || !Object.op_Implicit((Object)(object)Player.m_localPlayer) || ((Character)Player.m_localPlayer).IsDead() || unscaledTime - lastReply > 35f || Vector3.Distance(((Component)Chest).transform.position, ((Component)Player.m_localPlayer).transform.position) > 4f) { Close(); } } private static bool Submit(Transaction candidate) { //IL_00cd: Unknown result type (might be due to invalid IL or missing references) foreach (ItemData allItem in candidate.SharedStage.GetAllItems()) { allItem.m_equipped = false; } byte[] array = InventoryCodec.Save(candidate.SharedStage); if (array.SequenceEqual(InventoryCodec.Save(View))) { Effect(ClearDrag); return false; } byte[] array2 = InventoryCodec.Save(candidate.PlayerStage); if (array.Length > 1048576 || array2.Length > 1048576) { throw new InvalidOperationException("This transfer exceeds the supported inventory size."); } candidate.Sequence = ++sequence; ZPackage val = Protocol.Header(Operation.Commit, chestId, token, candidate.Sequence); val.Write(revision); val.Write(candidate.PlayerStage.GetWidth()); val.Write(candidate.PlayerStage.GetHeight()); val.Write(candidate.PlayerBefore); val.Write(array); val.Write(array2); candidate.Request = val.GetArray(); transaction = candidate; nextRetry = Time.unscaledTime + 2f; Effect(ClearDrag); Effect(delegate { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Expected O, but got Unknown Plugin.RequestRpc.SendPackage(Plugin.ServerId, new ZPackage(candidate.Request)); }); return true; } internal static void Bulk(bool take) { if (HasSession && !Pending && Object.op_Implicit((Object)(object)Player.m_localPlayer) && !((Character)Player.m_localPlayer).IsTeleporting()) { Transaction transaction = new Transaction(); if (take) { transaction.PlayerStage.MoveAll(transaction.SharedStage); } else { transaction.SharedStage.StackAll(transaction.PlayerStage, false); } if (!Submit(transaction) && closeWanted) { Close(); } } } internal static void ClearDrag() { if (Object.op_Implicit((Object)(object)InventoryGui.instance)) { AccessTools.Method(typeof(InventoryGui), "SetupDragItem", (Type[])null, (Type[])null).Invoke(InventoryGui.instance, new object[3] { null, null, 1 }); } } internal static bool Select(InventoryGui gui, InventoryGrid grid, ItemData? item, Vector2i position, Modifier modifier) { //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Invalid comparison between Unknown and I4 //IL_0173: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Invalid comparison between Unknown and I4 //IL_015a: Unknown result type (might be due to invalid IL or missing references) if (Pending) { return false; } if (!GuildUi) { return true; } if (((Character)Player.m_localPlayer).IsTeleporting()) { return false; } Inventory inventory = grid.GetInventory(); Inventory val = AccessTools.FieldRefAccess<InventoryGui, Inventory>("m_dragInventory").Invoke(gui); ItemData val2 = AccessTools.FieldRefAccess<InventoryGui, ItemData>("m_dragItem").Invoke(gui); bool flag = Object.op_Implicit((Object)(object)AccessTools.FieldRefAccess<InventoryGui, GameObject>("m_dragGo").Invoke(gui)); if ((int)modifier == 3 && inventory == View) { Plugin.Message("Move the item into your inventory before dropping it."); return false; } if (flag && (val == View || inventory == View)) { if (val2 == null || !val.ContainsItem(val2)) { ClearDrag(); return false; } if (val != inventory && (val2.m_shared.m_questItem || (item != null && item.m_shared.m_questItem))) { return false; } Transaction transaction = new Transaction(); Inventory val3 = ((val == View) ? transaction.SharedStage : transaction.PlayerStage); Inventory val4 = ((inventory == View) ? transaction.SharedStage : transaction.PlayerStage); ItemData itemAt = val3.GetItemAt(val2.m_gridPos.x, val2.m_gridPos.y); int num = AccessTools.FieldRefAccess<InventoryGui, int>("m_dragAmount").Invoke(gui); ref Inventory reference = ref AccessTools.FieldRefAccess<InventoryGrid, Inventory>("m_inventory").Invoke(grid); Inventory val5 = reference; try { reference = val4; grid.DropItem(val3, itemAt, num, position); } finally { reference = val5; } Submit(transaction); return false; } if ((int)modifier == 2 && item != null) { if (item.m_shared.m_questItem) { return false; } Transaction transaction2 = new Transaction(); Inventory val6 = ((inventory == View) ? transaction2.SharedStage : transaction2.PlayerStage); Inventory obj = ((inventory == View) ? transaction2.PlayerStage : transaction2.SharedStage); ItemData itemAt2 = val6.GetItemAt(item.m_gridPos.x, item.m_gridPos.y); obj.MoveItemToThis(val6, itemAt2); Submit(transaction2); return false; } return true; } } [HarmonyPatch(typeof(Container), "Awake")] internal static class GuildInventoryRegistrationPatch { private static void Postfix(Container __instance) { InventoryAccess.Track(__instance); } } [HarmonyPatch(typeof(Container), "GetInventory")] internal static class GuildInventoryAccessPatch { private static bool Prefix(Container __instance, ref Inventory __result) { if (!Plugin.IsGuild(__instance)) { return true; } __result = InventoryAccess.InventoryFor(__instance); return false; } } [HarmonyPatch(typeof(ZNetView), "IsOwner")] internal static class AutomationOwnerPatch { private static bool Prefix(ZNetView __instance, ref bool __result) { if (!Object.op_Implicit((Object)(object)InventoryAccess.ScopedChest) || (Object)(object)((Component)InventoryAccess.ScopedChest).GetComponent<ZNetView>() != (Object)(object)__instance) { return true; } __result = true; return false; } } [HarmonyPatch] internal static class GuildUiInventoryScopePatch { private static IEnumerable<MethodBase> TargetMethods() { return new string[3] { "Show", "UpdateContainer", "UpdateContainerWeight" }.Select((string name) => AccessTools.Method(typeof(InventoryGui), name, (Type[])null, (Type[])null)); } private static void Prefix(ref bool __state) { StorageScopes.Enter(StorageScope.Ui, ref __state); } private static void Finalizer(bool __state) { StorageScopes.Exit(StorageScope.Ui, __state); } } [HarmonyPatch] internal static class CraftyPreviewScopePatch { private static IEnumerable<MethodBase> TargetMethods() { MethodInfo[] methods = typeof(Player).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (MethodInfo methodInfo in methods) { if (methodInfo.Name == "HaveRequirements" || methodInfo.Name == "HaveRequirementItems") { yield return methodInfo; } } yield return AccessTools.Method(typeof(InventoryGui), "SetupRequirement", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(InventoryGui), "SetupRequirementList", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(Hud), "SetupPieceInfo", (Type[])null, (Type[])null); } [HarmonyPriority(800)] private static void Prefix(ref bool __state) { StorageScopes.Enter(StorageScope.Preview, ref __state); } private static void Finalizer(bool __state) { StorageScopes.Exit(StorageScope.Preview, __state); } } [HarmonyPatch(typeof(InventoryGui), "DoCrafting")] internal static class GuildCraftingSupplyPatch { [HarmonyPriority(800)] private static bool Prefix(InventoryGui __instance, Player player, ref bool __state) { if (Client.Pending || Client.Opening) { return false; } Recipe recipe = AccessTools.FieldRefAccess<InventoryGui, Recipe>("m_craftRecipe").Invoke(__instance); ItemData upgrade = AccessTools.FieldRefAccess<InventoryGui, ItemData>("m_craftUpgradeItem").Invoke(__instance); bool multi = AccessTools.FieldRefAccess<InventoryGui, bool>("m_multiCrafting").Invoke(__instance); int amount = ((!multi) ? 1 : AccessTools.FieldRefAccess<InventoryGui, int>("m_multiCraftAmount").Invoke(__instance)); CraftingStation station = player.GetCurrentCraftingStation(); if (Object.op_Implicit((Object)(object)recipe) && !player.NoCostCheat() && !ZoneSystem.instance.GetGlobalKey((GlobalKeys)25) && MaterialSupply.SupplyCrafting(recipe, (upgrade == null) ? 1 : (upgrade.m_quality + 1), amount, delegate { if (Object.op_Implicit((Object)(object)__instance) && Object.op_Implicit((Object)(object)player) && !((Character)player).IsDead() && !((Character)player).IsTeleporting() && !((Object)(object)player.GetCurrentCraftingStation() != (Object)(object)station) && !((Object)(object)AccessTools.FieldRefAccess<InventoryGui, Recipe>("m_craftRecipe").Invoke(__instance) != (Object)(object)recipe) && AccessTools.FieldRefAccess<InventoryGui, ItemData>("m_craftUpgradeItem").Invoke(__instance) == upgrade && AccessTools.FieldRefAccess<InventoryGui, bool>("m_multiCrafting").Invoke(__instance) == multi && (!multi || AccessTools.FieldRefAccess<InventoryGui, int>("m_multiCraftAmount").Invoke(__instance) == amount)) { AccessTools.Method(typeof(InventoryGui), "DoCrafting", (Type[])null, (Type[])null).Invoke(__instance, new object[1] { player }); } })) { return false; } StorageScopes.Enter(StorageScope.Consumption, ref __state); return true; } private static void Finalizer(bool __state) { StorageScopes.Exit(StorageScope.Consumption, __state); } } [HarmonyPatch(typeof(Player), "TryPlacePiece")] internal static class GuildBuildingSupplyPatch { [HarmonyPriority(800)] private static bool Prefix(Player __instance, Piece piece, ref bool __result) { if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer) { return true; } bool num = BuildingContinuation.TryPlace(__instance, piece); if (!num) { __result = false; } return num; } } [HarmonyPatch(typeof(Player), "UpdatePlacement")] internal static class GuildBuildingResumePatch { private static void Prefix(Player __instance, bool takeInput) { BuildingContinuation.BeforeUpdate(__instance, takeInput); } private static void Finalizer(Player __instance) { BuildingContinuation.AfterUpdate(__instance); } } [HarmonyPatch(typeof(Player), "ConsumeResources")] internal static class GuildConsumptionScopePatch { private static void Prefix(ref bool __state) { StorageScopes.Enter(StorageScope.Consumption, ref __state); } private static void Finalizer(bool __state) { StorageScopes.Exit(StorageScope.Consumption, __state); } } internal static class GuardedInventoryMethods { private static readonly HashSet<string> names = new HashSet<string> { "AddItem", "CanAddItem", "MoveAll", "StackAll", "MoveItemToThis", "RemoveItem", "RemoveOneItem", "RemoveAll", "RemoveUnequipped", "Load", "MoveInventoryToGrave", "HaveEmptySlot" }; private static readonly MethodInfo[] methods = (from method in typeof(Inventory).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) where names.Contains(method.Name) select method).ToArray(); internal static bool Blocked(Inventory inventory, object[] arguments) { if (InventoryAccess.Blocked(inventory)) { return true; } foreach (object obj in arguments) { Inventory val = (Inventory)((obj is Inventory) ? obj : null); if (val != null && InventoryAccess.Blocked(val)) { return true; } } return false; } internal static IEnumerable<MethodBase> WithReturn(Type result) { return methods.Where((MethodInfo method) => method.ReturnType == result); } } [HarmonyPatch] internal static class GuildInventoryBoolGuard { private static IEnumerable<MethodBase> TargetMethods() { return GuardedInventoryMethods.WithReturn(typeof(bool)); } [HarmonyPriority(800)] private static bool Prefix(Inventory __instance, object[] __args, ref bool __result) { if (!GuardedInventoryMethods.Blocked(__instance, __args)) { return true; } __result = false; return false; } } [HarmonyPatch] internal static class GuildInventoryIntGuard { private static IEnumerable<MethodBase> TargetMethods() { return GuardedInventoryMethods.WithReturn(typeof(int)); } [HarmonyPriority(800)] private static bool Prefix(Inventory __instance, object[] __args, ref int __result) { if (!GuardedInventoryMethods.Blocked(__instance, __args)) { return true; } __result = 0; return false; } } [HarmonyPatch] internal static class GuildInventoryItemGuard { private static IEnumerable<MethodBase> TargetMethods() { return GuardedInventoryMethods.WithReturn(typeof(ItemData)); } [HarmonyPriority(800)] private static bool Prefix(Inventory __instance, object[] __args, ref ItemData? __result) { if (!GuardedInventoryMethods.Blocked(__instance, __args)) { return true; } __result = null; return false; } } [HarmonyPatch] internal static class GuildInventoryVoidGuard { private static IEnumerable<MethodBase> TargetMethods() { return GuardedInventoryMethods.WithReturn(typeof(void)); } [HarmonyPriority(800)] private static bool Prefix(Inventory __instance, object[] __args) { return !GuardedInventoryMethods.Blocked(__instance, __args); } } internal static class CraftyBoxesAdapter { private sealed class Bindings { internal readonly MethodInfo Query; internal readonly MethodInfo ShouldPrevent; internal readonly MethodInfo CanPull; internal readonly MethodInfo Invalidate; internal readonly FieldInfo Totals; internal readonly FieldInfo ContainersHavingAny; internal readonly Func<float> Range; internal readonly Func<int> LeaveOne; internal readonly (MethodInfo Target, string Prefix)[] Hooks; internal Bindings(Type plugin) { Assembly assembly = plugin.Assembly; Type type = StorageBindings.Type(assembly, "AzuCraftyBoxes.Util.Functions.Boxes"); Type type2 = StorageBindings.Type(assembly, "AzuCraftyBoxes.Util.Functions.MiscFunctions"); Type type3 = StorageBindings.Type(assembly, "AzuCraftyBoxes.Util.Functions.UiItemBank"); Type type4 = StorageBindings.Type(assembly, "AzuCraftyBoxes.IContainers.VanillaContainer"); Type type5 = StorageBindings.Type(assembly, "AzuCraftyBoxes.IContainers.IContainer"); ContainerBindings.Validate(type4, crafting: true); Query = StorageBindings.NearbyQuery(type); ShouldPrevent = StorageBindings.Method(type2, "ShouldPrevent", typeof(bool), Type.EmptyTypes); CanPull = StorageBindings.Method(type, "CanItemBePulled", typeof(bool), new Type[3] { typeof(string), typeof(string), typeof(string) }); Invalidate = StorageBindings.Method(type, "InvalidateCounts", typeof(void), Type.EmptyTypes); Totals = StorageBindings.Field(type3, "_totals"); ContainersHavingAny = StorageBindings.Field(type3, "_containersHavingAny"); FieldInfo[] array = new FieldInfo[2] { Totals, ContainersHavingAny }; foreach (FieldInfo fieldInfo in array) { if (!fieldInfo.IsStatic || !typeof(IDictionary).IsAssignableFrom(fieldInfo.FieldType)) { throw new InvalidOperationException("Unsupported CraftyBoxes UI count cache."); } } Range = StorageBindings.Setting<float>(plugin, "mRange"); LeaveOne = StorageBindings.Setting<int>(plugin, "leaveOne"); Hooks = new(MethodInfo, string)[5] { (StorageBindings.Method(type4, "ItemCount", typeof(int), new Type[1] { typeof(string) }), "Count"), (StorageBindings.Method(type4, "GetInventory", typeof(Inventory), Type.EmptyTypes), "GetInventory"), (StorageBindings.Method(type4, "ProcessContainerInventory", typeof(int), new Type[3] { typeof(string), typeof(int), typeof(int) }), "Consume"), (StorageBindings.Method(type4, "RemoveItem", typeof(void), new Type[2] { typeof(string), typeof(int) }), "Remove"), (StorageBindings.Method(type, "MemoUsable", typeof(bool), new Type[1] { typeof(List<>).MakeGenericType(type5) }), "Memo") }; } } internal const string PluginId = "Azumatt.AzuCraftyBoxes"; private static Bindings? bindings; internal static bool Installed => bindings != null; private static Bindings Api => bindings ?? throw new InvalidOperationException("CraftyBoxes adapter is unavailable."); internal static bool LeaveOne => Api.LeaveOne() != 0; internal static void Install(Harmony harmony, Type plugin) { Bindings bindings = new Bindings(plugin); StorageBindings.Patch(harmony, typeof(CraftyBoxesAdapter), bindings.Hooks); CraftyBoxesAdapter.bindings = bindings; } internal static List<object> Nearby() { if (!Installed || !Object.op_Implicit((Object)(object)Player.m_localPlayer) || (bool)Api.ShouldPrevent.Invoke(null, null)) { return new List<object>(); } return ((IEnumerable)Api.Query.Invoke(null, new object[2] { Player.m_localPlayer, Api.Range() })).Cast<object>().ToList(); } internal static bool Pullable(object wrapper, string prefab) { MethodInfo canPull = Api.CanPull; object[] parameters = new string[3] { ContainerBindings.PrefabFor(wrapper), prefab, "" }; return (bool)canPull.Invoke(null, parameters); } internal static void InvalidateCounts() { if (Installed) { Api.Invalidate.Invoke(null, null); (Api.Totals.GetValue(null) as IDictionary)?.Clear(); (Api.ContainersHavingAny.GetValue(null) as IDictionary)?.Clear(); } } private static bool Count(object __instance, string name, ref int __result) { Container val = ContainerBindings.ContainerFor(__instance); if (!Plugin.IsGuild(val)) { return true; } Inventory? obj = StoragePreview.For(val); __result = ((obj != null) ? obj.CountItems(name, -1, true) : 0); return false; } private static bool GetInventory(object __instance, ref Inventory __result) { Container val = ContainerBindings.ContainerFor(__instance); if (!Plugin.IsGuild(val)) { return true; } Inventory val2 = StoragePreview.For(val); if (val2 == null) { __result = InventoryAccess.InventoryFor(val); } else { __result = InventoryCodec.Clone(val2); InventoryAccess.Protect(__result); } return false; } private static bool Consume(object __instance, int totalAmount, ref int __result) { if (!Plugin.IsGuild(ContainerBindings.ContainerFor(__instance))) { return true; } __result = totalAmount; return false; } private static bool Remove(object __instance) { return !Plugin.IsGuild(ContainerBindings.ContainerFor(__instance)); } private static bool Memo(ref bool __result) { if (StorageScopes.PreviewDepth > 0 && StorageScopes.ConsumptionDepth == 0) { return true; } __result = false; return false; } } public static class GuildChestStorage { public static bool IsGuildChest(Container container) { return Plugin.IsGuild(container); } public static bool TryTransfer(Container chest, Action<Inventory, Inventory> transfer, Action<bool, string>? completed = null) { if (!Plugin.IsGuild(chest) || transfer == null) { return false; } return Client.Transfer(chest, transfer, completed); } } internal static class Host { private const string ItemsKey = "gc_inventory_v1"; private const string RevisionKey = "gc_revision"; internal static SharedStore? Store; private static ZDO? state; private static ZDOMan? manager; private static float nextPeerCheck; private static string automationToken = ""; private static readonly Dictionary<int, float> wardRadii = new Dictionary<int, float>(); private static readonly HashSet<ZDOID> wards = new HashSet<ZDOID>(); internal static bool IsServer { get { if (Object.op_Implicit((Object)(object)ZNet.instance)) { return ZNet.instance.IsServer(); } return false; } } private static IEnumerable<ZDO> Objects => AccessTools.FieldRefAccess<ZDOMan, Dictionary<ZDOID, ZDO>>("m_objectsByID").Invoke(ZDOMan.instance).Values; internal static bool IsState(ZDO zdo) { return zdo.GetPrefab() == Plugin.StateHash; } internal static void Initialize() { //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Expected O, but got Unknown if (!IsServer || ZNet.m_loadError || !Object.op_Implicit((Object)(object)ZNetScene.instance) || !Object.op_Implicit((Object)(object)ZNetScene.instance.GetPrefab("GuildChestWorldState")) || (manager == ZDOMan.instance && Store != null)) { return; } manager = ZDOMan.instance; List<ZDO> list = Objects.Where(IsState).ToList(); if (list.Count > 1) { throw new InvalidOperationException("Multiple Guild Chest world state records; refusing to overwrite them."); } state = list.SingleOrDefault() ?? manager.CreateNewZDO(Vector3.zero, Plugin.StateHash); state.Persistent = true; state.Type = (ObjectType)2; state.SetPrefab(Plugin.StateHash); state.SetOwner(ZNet.GetUID()); int num = state.GetInt("gc_schema", 1); if (num != 1) { throw new InvalidOperationException($"Unsupported Guild Chest save schema {num}."); } byte[] array = InventoryCodec.Save(InventoryCodec.Empty()); Store = new SharedStore(state.GetByteArray("gc_inventory_v1", array), state.GetLong("gc_revision", 0L)); wardRadii.Clear(); wards.Clear(); foreach (KeyValuePair<int, GameObject> item in AccessTools.FieldRefAccess<ZNetScene, Dictionary<int, GameObject>>("m_namedPrefabs").Invoke(ZNetScene.instance)) { PrivateArea component = item.Value.GetComponent<PrivateArea>(); if (Object.op_Implicit((Object)(object)component)) { wardRadii[item.Key] = component.m_radius; } } foreach (ZDO @object in Objects) { Register(@object); } Persist(); Plugin.LogInfo($"Guild Chest authority ready: {Store.ChestCount} chests; Valheim {Version.GetVersionString(false)}."); } internal static void Persist() { if (IsServer && Store != null && state != null) { StoreSnapshot val = Store.Snapshot(); state.Set("gc_schema", 1); state.Set("gc_inventory_v1", val.Inventory); state.Set("gc_revision", val.Revision); } } internal static void Register(ZDO zdo) { //IL_0050: Unknown result type (might be due to invalid IL or missing references) if (IsServer && Store != null) { if (zdo.GetPrefab() == Plugin.ChestHash) { Store.Register(((object)Unsafe.As<ZDOID, ZDOID>(ref zdo.m_uid)/*cast due to .constrained prefix*/).ToString()); } if (wardRadii.ContainsKey(zdo.GetPrefab())) { wards.Add(zdo.m_uid); } } } internal static void Destroyed(ZDO zdo) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) if (IsServer && Store != null && state != null) { wards.Remove(zdo.m_uid); if (zdo.GetPrefab() == Plugin.ChestHash && Store.Remove(((object)Unsafe.As<ZDOID, ZDOID>(ref zdo.m_uid)/*cast due to .constrained prefix*/).ToString())) { Persist(); } } } internal static void Tick() { if (!IsServer) { return; } if (manager != ZDOMan.instance) { Reset(); } else { if (Store == null) { return; } Store.Expire((double)Time.unscaledTime); if (!(Time.unscaledTime < nextPeerCheck)) { nextPeerCheck = Time.unscaledTime + 1f; Lease activeLease = Store.ActiveLease; if (activeLease != null && activeLease.Peer != ZNet.GetUID() && ZNet.instance.GetPeer(activeLease.Peer) == null) { Store.Disconnect(activeLease.Peer); } } } } internal static void Reset() { Store = null; state = null; manager = null; wards.Clear(); wardRadii.Clear(); automationToken = ""; } internal static IEnumerator Receive(long sender, ZPackage package) { try { Handle(sender, package); } catch (Exception exception) { Plugin.Error(exception); } yield break; } private unsafe static void Handle(long sender, ZPackage package) { //IL_0394: Unknown result type (might be due to invalid IL or missing references) //IL_039f: Unknown result type (might be due to invalid IL or missing references) //IL_03a2: Invalid comparison between Unknown and I4 //IL_03ab: Unknown result type (might be due to invalid IL or missing references) //IL_03ae: Invalid comparison between Unknown and I4 //IL_03b7: Unknown result type (might be due to invalid IL or missing references) //IL_0410: Unknown result type (might be due to invalid IL or missing references) //IL_041d: Unknown result type (might be due to invalid IL or missing references) //IL_0424: Expected I4, but got Unknown //IL_0442: Unknown result type (might be due to invalid IL or missing references) //IL_03d1: Unknown result type (might be due to invalid IL or missing references) //IL_03e4: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0046: 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_0063: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: 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) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0376: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_0382: 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_015c: Unknown result type (might be due to invalid IL or missing references) //IL_0299: Unknown result type (might be due to invalid IL or missing references) //IL_02de: Unknown result type (might be due to invalid IL or missing references) //IL_02e3: Unknown result type (might be due to invalid IL or missing references) //IL_017b: Unknown result type (might be due to invalid IL or missing references) //IL_02fe: Unknown result type (might be due to invalid IL or missing references) //IL_01b0: Unknown result type (might be due to invalid IL or missing references) //IL_0225: Unknown result type (might be due to invalid IL or missing references) //IL_020c: 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_0213: Unknown result type (might be due to invalid IL or missing references) //IL_035f: Unknown result type (might be due to invalid IL or missing references) if (!IsServer || Store == null || state == null || package.Size() > 3149824 || (sender != ZNet.GetUID() && ZNet.instance.GetPeer(sender) == null)) { return; } Operation operation = (Operation)package.ReadInt(); ZDOID val = package.ReadZDOID(); string text = package.ReadString(); long num = package.ReadLong(); ZDO zDO = ZDOMan.instance.GetZDO(val); AccessResult val2 = (AccessResult)3; string text2 = text; string text3 = "The inventory session is no longer valid. Reopen the chest."; try { switch (operation) { case Operation.Close: val2 = (AccessResult)((!Store.Close(sender, text)) ? 3 : 0); break; case Operation.Commit: { long num2 = package.ReadLong(); int num3 = package.ReadInt(); int num4 = package.ReadInt(); byte[] oldPlayer = package.ReadByteArray(); byte[] array = package.ReadByteArray(); byte[] newPlayer = package.ReadByteArray(); AccessResult val4 = default(AccessResult); if (Store.TryReplay(sender, text, num, array, ref val4)) { val2 = val4; break; } if (zDO == null || zDO.GetPrefab() != Plugin.ChestHash) { val2 = (AccessResult)2; text3 = "The chest no longer exists on the server."; break; } if (!HasAccess(sender, zDO, text == automationToken)) { val2 = (AccessResult)6; text3 = "The server denied access: check your distance and ward permissions."; break; } if (!Store.Authorized(sender, text, (double)Time.unscaledTime) || Store.ActiveLease.Chest != ((object)(*(ZDOID*)(&val))/*cast due to .constrained prefix*/).ToString()) { val2 = (AccessResult)3; break; } if (num3 < 1 || num3 > 16 || num4 < 1 || num4 > 32) { val2 = (AccessResult)9; text3 = $"Unsupported player inventory dimensions: {num3} x {num4}."; break; } if (num2 != Store.Snapshot().Revision) { val2 = (AccessResult)4; text3 = "The shared inventory changed. Reopen the chest."; break; } Inventory oldShared = ReadInventory(Store.Snapshot().Inventory, "stored guild inventory"); Inventory newShared = ReadInventory(array, "guild inventory after transfer"); if (InventoryCodec.Conserves(oldShared, oldPlayer, newShared, newPlayer, num3, num4)) { val2 = Store.Commit(sender, text, num2, num, array, (double)Time.unscaledTime); if ((int)val2 == 0) { Persist(); } } else { val2 = (AccessResult)8; text3 = "The transfer changes item quantities or types; check inventory mods on client and server."; } break; } default: if (zDO != null && zDO.GetPrefab() == Plugin.ChestHash && HasAccess(sender, zDO, operation == Operation.Peek || operation == Operation.OpenAutomation || (text == automationToken && text.Length > 0))) { Store.Register(((object)(*(ZDOID*)(&val))/*cast due to .constrained prefix*/).ToString()); switch (operation) { case Operation.Peek: val2 = (AccessResult)0; break; case Operation.Open: case Operation.OpenAutomation: { ReadInventory(Store.Snapshot().Inventory, "stored guild inventory"); Lease val3 = default(Lease); val2 = Store.Open(sender, ((object)(*(ZDOID*)(&val))/*cast due to .constrained prefix*/).ToString(), (double)Time.unscaledTime, ref val3); text2 = ((val3 != null) ? val3.Token : null) ?? ""; if ((int)val2 == 0) { automationToken = ((operation == Operation.OpenAutomation) ? text2 : ""); } break; } case Operation.Heartbeat: { Lease activeLease = Store.ActiveLease; if (((activeLease != null) ? activeLease.Chest : null) == ((object)(*(ZDOID*)(&val))/*cast due to .constrained prefix*/).ToString()) { val2 = (AccessResult)((!Store.Heartbeat(sender, text, (double)Time.unscaledTime)) ? 3 : 0); } break; } } } else if (zDO == null || zDO.GetPrefab() != Plugin.ChestHash) { val2 = (AccessResult)2; text3 = "The chest no longer exists on the server."; } else { val2 = (AccessResult)6; text3 = "The server denied access: check your distance and ward permissions."; } break; } } catch (Exception ex) { Plugin.Error(ex); val2 = (AccessResult)7; text3 = ex.Message; } if ((int)val2 == 1) { text3 = "Another player is using the guild inventory."; } if ((int)val2 == 5) { text3 = "The transfer request is out of order. Reopen the chest."; } if ((int)val2 != 0) { Plugin.LogWarning($"{operation} rejected: {val2}; peer={sender}, chest={val}, request={num}. {text3}"); } StoreSnapshot val5 = Store.Snapshot(); ZPackage val6 = Protocol.Header(operation, val, text2, num); val6.Write((int)val2); val6.Write(val5.Revision); val6.Write(val5.Inventory); val6.Write(((int)val2 == 0) ? "" : text3); Plugin.ReplyRpc.SendPackage(sender, val6); } private static Inventory ReadInventory(byte[] bytes, string context, int width = 8, int height = 4) { try { return InventoryCodec.Read(bytes, width, height); } catch (Exception ex) { throw new InvalidOperationException("Cannot read " + context + ": " + ex.Message, ex); } } private static bool HasAccess(long sender, ZDO chest, bool automation = false) { //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0081: 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_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) long playerID; Vector3 position; if (sender == ZNet.GetUID()) { if (!Object.op_Implicit((Object)(object)Player.m_localPlayer)) { return false; } playerID = Player.m_localPlayer.GetPlayerID(); position = ((Component)Player.m_localPlayer).transform.position; } else { ZNetPeer peer = ZNet.instance.GetPeer(sender); ZDO val = ((peer == null) ? null : ZDOMan.instance.GetZDO(peer.m_characterID)); if (val == null || val.GetBool(ZDOVars.s_dead, false)) { return false; } playerID = peer.m_playerID; position = val.GetPosition(); } if (Vector3.Distance(position, chest.GetPosition()) > (automation ? Plugin.AutomationRange.Value : 6f)) { return false; } bool flag = false; bool flag2 = false; foreach (ZDOID ward in wards) { ZDO zDO = ZDOMan.instance.GetZDO(ward); if (zDO == null || !wardRadii.TryGetValue(zDO.GetPrefab(), out var value) || !zDO.GetBool(ZDOVars.s_enabled, false) || Utils.DistanceXZ(zDO.GetPosition(), chest.GetPosition()) >= value) { continue; } flag = true; if (zDO.GetLong(ZDOVars.s_creator, 0L) == playerID) { flag2 = true; } int num = zDO.GetInt(ZDOVars.s_permitted, 0); for (int i = 0; i < num; i++) { if (zDO.GetLong("pu_id" + i, 0L) == playerID) { flag2 = true; } } } return !flag || flag2; } } internal static class InventoryAccess { internal sealed class StagingScope : IDisposable { private readonly Player player; private readonly Container chest; private readonly Inventory originalPlayer; private readonly Inventory originalChest; private readonly Container? previousChest; private readonly Inventory? previousShared; private bool disposed; internal StagingScope(Player player, Container chest, Inventory personal, Inventory shared) { this.player = player; this.chest = chest; originalPlayer = PlayerInventory.Invoke((Humanoid)(object)player); originalChest = ContainerInventory.Invoke(chest); previousChest = ScopedChest; previousShared = scopedShared; PlayerInventory.Invoke((Humanoid)(object)player) = personal; ContainerInventory.Invoke(chest) = shared; ScopedChest = chest; scopedShared = shared; } public void Dispose() { if (!disposed) { disposed = true; PlayerInventory.Invoke((Humanoid)(object)player) = originalPlayer; ContainerInventory.Invoke(chest) = originalChest; ScopedChest = previousChest; scopedShared = previousShared; } } } private static readonly ConditionalWeakTable<Inventory, object> protectedInventories = new ConditionalWeakTable<Inventory, object>(); private static readonly object marker = new object(); internal static readonly FieldRef<Container, Inventory> ContainerInventory = AccessTools.FieldRefAccess<Container, Inventory>("m_inventory"); private static readonly FieldRef<Humanoid, Inventory> PlayerInventory = AccessTools.FieldRefAccess<Humanoid, Inventory>("m_inventory"); private static Inventory? scopedShared; internal static Container? ScopedChest { get; private set; } internal static void Protect(Inventory inventory) { protectedInventories.GetValue(inventory, (Inventory _) => marker); } internal static bool Blocked(Inventory inventory) { if (!protectedInventories.TryGetValue(inventory, out object _)) { if (Client.Pending && !Client.Applying && Object.op_Implicit((Object)(object)Player.m_localPlayer)) { return inventory == ((Humanoid)Player.m_localPlayer).GetInventory(); } return false; } return true; } private static Inventory Unavailable() { //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_0013: Expected O, but got Unknown //IL_0014: Expected O, but got Unknown Inventory val = new Inventory("Guild Chest (transaction required)", (Sprite)null, 0, 0); Protect(val); return val; } internal static void Track(Container container) { if (Plugin.IsGuild(container)) { ContainerInventory.Invoke(container) = Unavailable(); } } internal static Inventory InventoryFor(Container container) { if ((Object)(object)container == (Object)(object)ScopedChest) { return scopedShared; } if (StorageScopes.UiDepth > 0 && Client.Owns(container)) { return Client.View; } Inventory val = ContainerInventory.Invoke(container); if (val != Client.View && val.GetWidth() == 0) { return val; } return Unavailable(); } } internal static class InventoryCodec { private sealed class Entry { internal int Hash; internal ItemData Item; internal string UnchangedKey = ""; internal string QuantityKey => $"{Hash}:{Item.m_quality}:{Item.m_variant}:{Item.m_worldLevel}"; } internal const int MaxBytes = 1048576; private static readonly MethodInfo changed = AccessTools.Method(typeof(Inventory), "Changed", new Type[2] { typeof(bool), typeof(bool) }, (Type[])null); internal static byte[] Save(Inventory inventory) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown ZPackage val = new ZPackage(); inventory.Save(val); return val.GetArray(); } internal static Inventory Empty(int width = 8, int height = 4) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Expected O, but got Unknown return new Inventory("Guild Chest", (Sprite)null, width, height); } internal static Inventory Read(byte[] bytes, int width = 8, int height = 4) { Inventory val = Empty(width, height); foreach (Entry item2 in ReadEntries(bytes, width, height)) { ItemData item = item2.Item; GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(item2.Hash); if (!Object.op_Implicit((Object)(object)itemPrefab) || !Object.op_Implicit((Object)(object)itemPrefab.GetComponent<ItemDrop>())) { throw new InvalidOperationException($"Missing shared-storage item prefab {item2.Hash}; install the item's mod on both client and server."); } item.m_dropPrefab = itemPrefab; item.m_shared = itemPrefab.GetComponent<ItemDrop>().m_itemData.m_shared; if (item.m_stack > item.m_shared.m_maxStackSize) { throw new InvalidOperationException($"Invalid item {((Object)itemPrefab).name}: stack {item.m_stack} exceeds server maximum {item.m_shared.m_maxStackSize}."); } val.GetAllItems().Add(item); } Changed(val); return val; } private static List<Entry> ReadEntries(byte[] bytes, int width, int height) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown if (bytes.Length > 1048576) { throw new InvalidOperationException("Inventory exceeds the supported package size."); } ZPackage val = new ZPackage(bytes); int num = val.ReadInt(); if (num != 109 && num != 110) { throw new InvalidOperationException($"Unsupported inventory format {num}; saved data has been retained."); } int num2 = val.ReadUShort(); if (num2 > width * height) { throw new InvalidOperationException("Too many inventory entries."); } List<Entry> list = new List<Entry>(); HashSet<int> hashSet = new HashSet<int>(); for (int i = 0; i < num2; i++) { int pos = val.GetPos(); var (num3, val2) = ItemData.Load(val, (Item)num); if (val2.m_stack <= 0 || val2.m_quality < 1 || val2.m_gridPos.x < 0 || val2.m_gridPos.x >= width || val2.m_gridPos.y < 0 || val2.m_gridPos.y >= height || !hashSet.Add(val2.m_gridPos.y * width + val2.m_gridPos.x)) { throw new InvalidOperationException($"Invalid item prefab {num3}: stack {val2.m_stack}, quality {val2.m_quality}, slot ({val2.m_gridPos.x}, {val2.m_gridPos.y}) in {width} x {height} inventory, or duplicate slot."); } byte[] array = new byte[val.GetPos() - pos]; Array.Copy(bytes, pos, array, 0, array.Length); array[4] = 0; array[5] = 0; list.Add(new Entry { Hash = num3, Item = val2, UnchangedKey = Convert.ToBase64String(array) }); } if (val.GetPos() != val.Size()) { throw new InvalidOperationException("Unexpected trailing inventory data."); } return list; } internal static Inventory Clone(Inventory source) { //IL_0018: 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_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Expected O, but got Unknown //IL_0059: Expected O, but got Unknown Inventory val = new Inventory(source.GetName(), source.GetBkg(), source.GetWidth(), source.GetHeight()); val.GetAllItems().AddRange(from item in source.GetAllItems() select item.Clone()); Changed(val); return val; } internal static void Replace(Inventory target, Inventory source) { target.GetAllItems().Clear(); target.GetAllItems().AddRange(from item in source.GetAllItems() select item.Clone()); Changed(target); } internal static void Changed(Inventory inventory) { changed.Invoke(inventory, new object[2] { false, false }); } internal static bool Conserves(Inventory oldShared, byte[] oldPlayer, Inventory newShared, byte[] newPlayer, int width, int height) { List<Entry> list = PlayerEntries(oldPlayer, "player inventory before transfer"); List<Entry> list2 = PlayerEntries(newPlayer, "player inventory after transfer"); Dictionary<string, long> dictionary = Count(SharedEntries(oldShared).Concat(list)); Dictionary<string, long> after = Count(SharedEntries(newShared).Concat(list2)); if (dictionary.Count != after.Count || !dictionary.All((KeyValuePair<string, long> pair) => after.TryGetValue(pair.Key, out var value) && value == pair.Value)) { return false; } IOrderedEnumerable<string> first = (from entry in list.Where(MissingPrefab) select entry.UnchangedKey).OrderBy<string, string>((string key) => key, StringComparer.Ordinal); IOrderedEnumerable<string> second = (from entry in list2.Where(MissingPrefab) select entry.UnchangedKey).OrderBy<string, string>((string key) => key, StringComparer.Ordinal); return first.SequenceEqual(second); static Dictionary<string, long> Count(IEnumerable<Entry> items) { return (from entry in items group entry by entry.QuantityKey).ToDictionary((IGrouping<string, Entry> group) => group.Key, (IGrouping<string, Entry> group) => ((IEnumerable<Entry>)group).Sum((Func<Entry, long>)((Entry entry) => entry.Item.m_stack))); } static bool MissingPrefab(Entry entry) { GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(entry.Hash); if (Object.op_Implicit((Object)(object)itemPrefab)) { return !Object.op_Implicit((Object)(object)itemPrefab.GetComponent<ItemDrop>()); } return true; } List<Entry> PlayerEntries(byte[] bytes, string context) { try { return ReadEntries(bytes, width, height); } catch (Exception ex) { throw new InvalidOperationException("Cannot read " + context + ": " + ex.Message, ex); } } static IEnumerable<Entry> SharedEntries(Inventory inventory) { return from item in inventory.GetAllItems() select new Entry { Hash = StringExtensionMethods.GetStableHashCode(((Object)item.m_dropPrefab).name), Item = item }; } } } internal sealed class MaterialRequest { internal readonly Requirement[] Requirements; internal readonly int Quality; internal readonly int Multiplier; internal readonly bool OnlyOne; internal readonly bool Building; internal readonly Recipe? Recipe; internal MaterialRequest(Requirement[] requirements, int quality, int multiplier, bool onlyOne, bool building, Recipe? recipe = null) { Requirements = requirements; Quality = quality; Multiplier = multiplier; OnlyOne = onlyOne; Building = building; Recipe = recipe; } } internal static class MaterialPlanner { internal sealed class MaterialNeed { internal readonly string Name; internal readonly int Amount; internal readonly int Quality; internal MaterialNeed(string name, int amount, int quality = -1) { Name = name; Amount = amount; Quality = quality; } } private static int Takeable(int count, bool leaveOne) { return Math.Max(0, count - (leaveOne ? 1 : 0)); } private static List<MaterialNeed