Decompiled source of Stackable Items v0.1.0

plugins/com.atomic.stackableitems.dll

Decompiled 2 hours ago
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using FishNet.Connection;
using FishNet.Object;
using FishNet.Object.Synchronizing;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("com.atomic.stackableitems")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.1.0.0")]
[assembly: AssemblyInformationalVersion("0.1.0")]
[assembly: AssemblyProduct("com.atomic.stackableitems")]
[assembly: AssemblyTitle("StackableItems")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.1.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
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;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace BepInEx
{
	[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
	[Conditional("CodeGeneration")]
	[Embedded]
	internal sealed class BepInAutoPluginAttribute : Attribute
	{
		public BepInAutoPluginAttribute(string? id = null, string? name = null, string? version = null)
		{
		}
	}
}
namespace BepInEx.Preloader.Core.Patching
{
	[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
	[Conditional("CodeGeneration")]
	[Embedded]
	internal sealed class PatcherAutoPluginAttribute : Attribute
	{
		public PatcherAutoPluginAttribute(string? id = null, string? name = null, string? version = null)
		{
		}
	}
}
namespace Microsoft.CodeAnalysis
{
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace StackableItems
{
	[BepInPlugin("com.atomic.stackableitems", "StackableItems", "0.1.0")]
	public class Plugin : BaseUnityPlugin
	{
		private Harmony harmony;

		public static ConfigEntry<int> MaxStackSize;

		public const string Id = "com.atomic.stackableitems";

		internal static ManualLogSource Log { get; private set; }

		public static string Name => "StackableItems";

		public static string Version => "0.1.0";

		private void Awake()
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Expected O, but got Unknown
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			MaxStackSize = ((BaseUnityPlugin)this).Config.Bind<int>("General", "Max Stack Size", 64, new ConfigDescription("The maximum amount of objects you can have in a given slot. The more you have, the more data can be tracked per player.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 100), Array.Empty<object>()));
			harmony = new Harmony("com.atomic.stackableitems");
			harmony.PatchAll();
		}
	}
	public static class StackManager
	{
		public static Item ItemBeingStored;

		public static byte LastRemovedSlot = byte.MaxValue;

		public static Dictionary<ulong, Dictionary<byte, List<Item>>> ServerStacks = new Dictionary<ulong, Dictionary<byte, List<Item>>>();

		public static Dictionary<ulong, Dictionary<byte, List<Item>>> ClientStacks = new Dictionary<ulong, Dictionary<byte, List<Item>>>();

		public static int MaxStackSize => Plugin.MaxStackSize.Value;

		private static ulong GetSteamID(PlayerInventory inv)
		{
			Player player = inv._player;
			if (player == null)
			{
				return 0uL;
			}
			return player.SteamID;
		}

		public static int GetStackCount(PlayerInventory inv, byte index)
		{
			ulong steamID = GetSteamID(inv);
			if (steamID == 0L)
			{
				return 0;
			}
			if (((NetworkBehaviour)inv).IsServerInitialized && ServerStacks.TryGetValue(steamID, out Dictionary<byte, List<Item>> value) && value.TryGetValue(index, out var value2))
			{
				return value2.Count;
			}
			if (((NetworkBehaviour)inv).Owner != (NetworkConnection)null && ((NetworkBehaviour)inv).Owner.IsLocalClient && ClientStacks.TryGetValue(steamID, out Dictionary<byte, List<Item>> value3) && value3.TryGetValue(index, out var value4))
			{
				return value4.Count;
			}
			return 0;
		}

		public static void PushServerStack(PlayerInventory inv, byte index, Item item)
		{
			ulong steamID = GetSteamID(inv);
			if (steamID != 0L)
			{
				if (!ServerStacks.TryGetValue(steamID, out Dictionary<byte, List<Item>> value))
				{
					value = new Dictionary<byte, List<Item>>();
					ServerStacks[steamID] = value;
				}
				if (!value.TryGetValue(index, out var value2))
				{
					value2 = (value[index] = new List<Item>());
				}
				if (value2.Count < MaxStackSize - 1)
				{
					value2.Add(item);
				}
			}
		}

		public static Item PopServerStack(PlayerInventory inv, byte index)
		{
			ulong steamID = GetSteamID(inv);
			if (steamID == 0L)
			{
				return null;
			}
			if (ServerStacks.TryGetValue(steamID, out Dictionary<byte, List<Item>> value) && value.TryGetValue(index, out var value2) && value2.Count > 0)
			{
				Item result = value2[value2.Count - 1];
				value2.RemoveAt(value2.Count - 1);
				return result;
			}
			return null;
		}

		public static void SyncClientStack(PlayerInventory inv, byte index, Item newItem, Item oldItem)
		{
			ulong steamID = GetSteamID(inv);
			if (steamID != 0L)
			{
				if (!ClientStacks.TryGetValue(steamID, out Dictionary<byte, List<Item>> value))
				{
					value = new Dictionary<byte, List<Item>>();
					ClientStacks[steamID] = value;
				}
				if (!value.TryGetValue(index, out var value2))
				{
					value2 = (value[index] = new List<Item>());
				}
				if ((Object)(object)newItem == (Object)null)
				{
					value2.Clear();
				}
				else if (value2.Count > 0 && (Object)(object)value2[value2.Count - 1] == (Object)(object)newItem)
				{
					value2.RemoveAt(value2.Count - 1);
				}
				else if ((Object)(object)oldItem != (Object)null && (Object)(object)oldItem != (Object)(object)newItem)
				{
					value2.Add(oldItem);
				}
			}
		}
	}
	[Serializable]
	public class SavedPlayerStacks
	{
		public ulong SteamID { get; set; }

		public List<SavedItem> StackedItems { get; set; } = new List<SavedItem>();
	}
	[Serializable]
	public class StackSaveFile
	{
		public List<SavedPlayerStacks> Players { get; set; } = new List<SavedPlayerStacks>();
	}
	public static class StackSaveManager
	{
		private static readonly string SaveFolder = Path.Combine(Paths.ConfigPath, "StackableItems", "Saves");

		private static Dictionary<ulong, List<SavedItem>> PendingRestores = new Dictionary<ulong, List<SavedItem>>();

		public static void Save()
		{
			if (SaveManager.CurServerSave == null)
			{
				return;
			}
			foreach (Player player in PlayerManager.Players)
			{
				SavePlayer(player);
			}
		}

		public static void SavePlayer(Player player)
		{
			if (SaveManager.CurServerSave == null)
			{
				return;
			}
			StackSaveFile stackSaveFile = ReadFile(SaveManager.CurServerSave.Name);
			stackSaveFile.Players.RemoveAll((SavedPlayerStacks playerStacks) => playerStacks.SteamID == player.SteamID);
			SavedPlayerStacks savedPlayerStacks = new SavedPlayerStacks
			{
				SteamID = player.SteamID
			};
			if (StackManager.ServerStacks.TryGetValue(player.SteamID, out Dictionary<byte, List<Item>> value))
			{
				foreach (KeyValuePair<byte, List<Item>> item in value)
				{
					foreach (Item item2 in item.Value)
					{
						if ((Object)(object)item2 != (Object)null)
						{
							savedPlayerStacks.StackedItems.Add(SaveManager.ItemToSavedItem(item.Key, item2));
						}
					}
				}
			}
			if (savedPlayerStacks.StackedItems.Count > 0)
			{
				stackSaveFile.Players.Add(savedPlayerStacks);
			}
			Write(SaveManager.CurServerSave.Name, stackSaveFile);
		}

		public static void Load()
		{
			PendingRestores.Clear();
			if (SaveManager.CurServerSave == null)
			{
				return;
			}
			StackSaveFile stackSaveFile = ReadFile(SaveManager.CurServerSave.Name);
			foreach (SavedPlayerStacks player in stackSaveFile.Players)
			{
				PendingRestores[player.SteamID] = new List<SavedItem>(player.StackedItems);
			}
		}

		private static StackSaveFile ReadFile(string serverName)
		{
			string path = GetPath(serverName);
			if (!File.Exists(path))
			{
				return new StackSaveFile();
			}
			try
			{
				string text = File.ReadAllText(path);
				StackSaveFile stackSaveFile = JsonConvert.DeserializeObject<StackSaveFile>(text);
				return stackSaveFile ?? new StackSaveFile();
			}
			catch
			{
				return new StackSaveFile();
			}
		}

		public static List<SavedItem> GetPending(ulong steamID)
		{
			if (!PendingRestores.TryGetValue(steamID, out List<SavedItem> value))
			{
				return null;
			}
			PendingRestores.Remove(steamID);
			return value;
		}

		public static void SetStats(Item item, SavedItem savedItem)
		{
			item._cookness.Value = savedItem.Cookness;
			item._bettingMultiplier.Value = savedItem.BettingMultiplier;
			item._killScoreMultiplier.Value = savedItem.KillScoreMultiplier;
			item._curSkin.Value = savedItem.SkinIndex;
			if ((Object)(object)item._weapon != (Object)null)
			{
				item._weapon._attachments._syncedSight.Value = savedItem.Sight;
				item._weapon._attachments._syncedBarrelAttachment.Value = savedItem.BarrelAttachment;
				item._weapon._attachments._syncedBulletIndex.Value = savedItem.AmmoType;
				item._weapon._attachments._syncedExtendedMag.Value = savedItem.ExtendedMag;
				item._weapon._attachments._syncedLaserSight.Value = savedItem.LaserSight;
			}
			if ((Object)(object)item._melee != (Object)null)
			{
				item._melee._syncedSharpnessIndex.Value = savedItem.Sharpness;
			}
			if ((Object)(object)item._creature != (Object)null)
			{
				((Item)item._creature)._syncedRandomWeight.Value = savedItem.Weight;
			}
		}

		public static void Delete(string serverName)
		{
			string path = GetPath(serverName);
			if (File.Exists(path))
			{
				File.Delete(path);
			}
		}

		private static void Write(string serverName, StackSaveFile saveFile)
		{
			try
			{
				Directory.CreateDirectory(SaveFolder);
				string path = GetPath(serverName);
				string contents = JsonConvert.SerializeObject((object)saveFile, (Formatting)1);
				File.WriteAllText(path, contents);
			}
			catch
			{
			}
		}

		private static string GetPath(string serverName)
		{
			string text = serverName;
			char[] invalidFileNameChars = Path.GetInvalidFileNameChars();
			foreach (char oldChar in invalidFileNameChars)
			{
				text = text.Replace(oldChar, '_');
			}
			return Path.Combine(SaveFolder, text + ".json");
		}
	}
	[HarmonyPatch]
	public static class StackableItemsPatches
	{
		[HarmonyPrefix]
		[HarmonyPatch(typeof(PlayerInventory), "ServerTryStoreHeldItem")]
		public static void ServerTryStoreHeldItem_Prefix(Item item)
		{
			StackManager.ItemBeingStored = item;
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(PlayerInventory), "ServerTryStoreHeldItem")]
		public static void ServerTryStoreHeldItem_Postfix()
		{
			StackManager.ItemBeingStored = null;
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(PlayerInventory), "ResolveHeldItemReplacement")]
		public static void ResolveHeldItemReplacement_Prefix(Item item)
		{
			StackManager.ItemBeingStored = item;
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(PlayerInventory), "ResolveHeldItemReplacement")]
		public static void ResolveHeldItemReplacement_Postfix()
		{
			StackManager.ItemBeingStored = null;
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(PlayerInventory), "LocalTrySelectSlot")]
		public static void LocalTrySelectSlot_Prefix(PlayerInventory __instance)
		{
			StackManager.ItemBeingStored = __instance._player.Holding.HeldItem;
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(PlayerInventory), "LocalTrySelectSlot")]
		public static void LocalTrySelectSlot_Postfix()
		{
			StackManager.ItemBeingStored = null;
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(PlayerInventory), "UpdateHeldItem")]
		public static void UpdateHeldItem_Prefix(PlayerInventory __instance)
		{
			StackManager.ItemBeingStored = __instance._player.Holding.HeldItem;
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(PlayerInventory), "UpdateHeldItem")]
		public static void UpdateHeldItem_Postfix()
		{
			StackManager.ItemBeingStored = null;
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(PlayerInventory), "GetOpenSlot")]
		public static bool GetOpenSlot(PlayerInventory __instance, int selected, ref int __result)
		{
			if ((Object)(object)StackManager.ItemBeingStored != (Object)null)
			{
				string text = ((Object)StackManager.ItemBeingStored).name.Replace("(Clone)", "").Trim();
				for (byte b = 0; b < __instance._availableSlots.Count; b++)
				{
					Item val = __instance._items[b];
					if ((Object)(object)val != (Object)null)
					{
						string text2 = ((Object)val).name.Replace("(Clone)", "").Trim();
						int num = 1 + StackManager.GetStackCount(__instance, b);
						if (text2 == text && num < StackManager.MaxStackSize)
						{
							__result = b;
							return false;
						}
					}
				}
			}
			return true;
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(PlayerInventory), "AddItem")]
		public static bool AddItem(PlayerInventory __instance, byte index, Item item)
		{
			if (!((NetworkBehaviour)__instance).IsServerInitialized || (Object)(object)item == (Object)null)
			{
				return true;
			}
			Item val = __instance._items[index];
			__instance._items[index] = item;
			if ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)item)
			{
				StackManager.PushServerStack(__instance, index, val);
			}
			return false;
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(PlayerInventory), "LoadFromSave")]
		public static void LoadFromSave(PlayerInventory __instance)
		{
			//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)
			if (!((NetworkBehaviour)__instance).IsServerInitialized || (Object)(object)__instance._player == (Object)null)
			{
				return;
			}
			ulong steamID = __instance._player.SteamID;
			List<SavedItem> pending = StackSaveManager.GetPending(steamID);
			if (pending == null || pending.Count == 0)
			{
				return;
			}
			if (!StackManager.ServerStacks.TryGetValue(steamID, out Dictionary<byte, List<Item>> value))
			{
				value = new Dictionary<byte, List<Item>>();
				StackManager.ServerStacks[steamID] = value;
			}
			foreach (SavedItem item in pending)
			{
				Item spawnable = GameInfo.GetSpawnable(item.ItemID);
				if (!Object.op_Implicit((Object)(object)spawnable))
				{
					continue;
				}
				Item val = ItemManager.Instance.SpawnNewItem(spawnable, SpawnManager.PlayerSpawnPos, Quaternion.identity);
				StackSaveManager.SetStats(val, item);
				if ((Object)(object)val.Creature != (Object)null)
				{
					val.Creature.ServerKillOnSpawn();
					if (item.IsDripCreature)
					{
						val.Creature.SetDrip();
					}
				}
				val.SetSyncedHolder(__instance._player, true);
				val.PutInInventory();
				if (!value.TryGetValue(item.InventorySlot, out var value2))
				{
					value2 = new List<Item>();
					value[item.InventorySlot] = value2;
				}
				value2.Add(val);
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(PlayerInventory), "RemoveItem")]
		public static bool RemoveItem(PlayerInventory __instance, Item item)
		{
			if (!((NetworkBehaviour)__instance).IsServerInitialized || (Object)(object)item == (Object)null)
			{
				return true;
			}
			byte b = byte.MaxValue;
			foreach (KeyValuePair<byte, Item> item2 in __instance._items)
			{
				if ((Object)(object)item2.Value == (Object)(object)item)
				{
					b = item2.Key;
					break;
				}
			}
			StackManager.LastRemovedSlot = b;
			if (b != byte.MaxValue)
			{
				Item val = StackManager.PopServerStack(__instance, b);
				if ((Object)(object)val != (Object)null)
				{
					__instance._items[b] = val;
					return false;
				}
			}
			return true;
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(PlayerInventory), "RemoveItem")]
		public static void RemoveItem_Postfix(PlayerInventory __instance, Item item)
		{
			if (StackManager.LastRemovedSlot != byte.MaxValue && ((NetworkBehaviour)__instance).Owner.IsLocalClient)
			{
				__instance.ApplySlot((int)StackManager.LastRemovedSlot);
				StackManager.LastRemovedSlot = byte.MaxValue;
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Item), "DestroyByEating")]
		public static void EatItem(Item __instance)
		{
			Player lastHolder = __instance.LastHolder;
			PlayerInventory val = ((lastHolder != null) ? lastHolder.Inventory : null);
			if ((Object)(object)val != (Object)null)
			{
				val.ApplySlot(val._localCurSlot);
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(PlayerInventory), "ServerDropAll")]
		public static void ServerDropAll(PlayerInventory __instance, Vector3 pos, Quaternion rot)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: 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_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: 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_00b4: 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_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			if (!((NetworkBehaviour)__instance).IsServerInitialized)
			{
				return;
			}
			Player player = __instance._player;
			ulong num = ((player != null) ? player.SteamID : 0);
			if (num == 0L || !StackManager.ServerStacks.TryGetValue(num, out Dictionary<byte, List<Item>> value))
			{
				return;
			}
			Vector3 val = Vector3.zero;
			foreach (KeyValuePair<byte, List<Item>> item in value)
			{
				foreach (Item item2 in item.Value)
				{
					if ((Object)(object)item2 != (Object)null)
					{
						val += Vector3.up * item2.ModelHeight;
						item2.SetSyncedHolder((Player)null, false);
						if (!item2.RigidbodySync.IsSimulatedLocal)
						{
							item2.RigidbodySync.StartSimulateLocal(pos + val, rot);
						}
						else
						{
							((Component)item2).transform.position = pos + val;
							item2.Rig.linearVelocity = Vector3.zero;
							item2.Rig.angularVelocity = Vector3.zero;
						}
						val += Vector3.up * item2.ModelHeight;
					}
				}
				item.Value.Clear();
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(PlayerInventory), "OnItemsChange")]
		public static void OnItemsChange(PlayerInventory __instance, SyncDictionaryOperation op, byte index, Item item, bool asServer)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Invalid comparison between Unknown and I4
			if (!asServer && (int)op == 3 && ((NetworkBehaviour)__instance).Owner != (NetworkConnection)null && ((NetworkBehaviour)__instance).Owner.IsLocalClient)
			{
				Item item2 = __instance._itemSlots[index].Item;
				StackManager.SyncClientStack(__instance, index, item, item2);
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(PlayerInventory), "OnStopServer")]
		public static void OnStopServer(PlayerInventory __instance)
		{
			if ((Object)(object)__instance._player != (Object)null)
			{
				StackSaveManager.SavePlayer(__instance._player);
				ulong steamID = __instance._player.SteamID;
				StackManager.ServerStacks.Remove(steamID);
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(PlayerInventory), "OnStopClient")]
		public static void OnStopClient(PlayerInventory __instance)
		{
			Player player = __instance._player;
			ulong num = ((player != null) ? player.SteamID : 0);
			if (num != 0L)
			{
				StackManager.ClientStacks.Remove(num);
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(InventorySlot), "SetItem")]
		public static void SetItem(InventorySlot __instance, Item item)
		{
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)item == (Object)null)
			{
				((TMP_Text)__instance._itemText).text = "";
				return;
			}
			PlayerInventory inventory = Player.LocalPlayer.Inventory;
			if ((Object)(object)inventory == (Object)null)
			{
				return;
			}
			byte b = byte.MaxValue;
			for (byte b2 = 0; b2 < inventory._itemSlots.Count; b2++)
			{
				if ((Object)(object)inventory._itemSlots[b2] == (Object)(object)__instance)
				{
					b = b2;
					break;
				}
			}
			if (b == byte.MaxValue)
			{
				return;
			}
			int num = StackManager.GetStackCount(inventory, b) + 1;
			if (num > 1)
			{
				if ((Object)(object)item.Mesh == (Object)null)
				{
					((TMP_Text)__instance._itemText).text = $"{((Object)item).name} ({num}x)";
				}
				else
				{
					((TMP_Text)__instance._itemText).text = $"{num}x";
					((Graphic)__instance._itemText).color = Color.white;
				}
				((Component)__instance._itemText).gameObject.SetActive(true);
			}
			else if ((Object)(object)item.Mesh != (Object)null)
			{
				((TMP_Text)__instance._itemText).text = "";
			}
			((TMP_Text)__instance._itemText).transform.SetAsLastSibling();
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(SaveManager), "SaveServer")]
		public static void SaveServer()
		{
			StackSaveManager.Save();
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(SaveManager), "OnServerLoaded")]
		public static void OnServerLoaded()
		{
			StackSaveManager.Load();
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(SaveManager), "DeleteServer")]
		public static void DeleteServer()
		{
			if (SaveManager.CurServerSave != null)
			{
				StackSaveManager.Delete(SaveManager.CurServerSave.Name);
			}
		}
	}
}
namespace System.Diagnostics.CodeAnalysis
{
	[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class ConstantExpectedAttribute : Attribute
	{
		public object? Min { get; set; }

		public object? Max { get; set; }
	}
	[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Interface | AttributeTargets.Delegate, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class ExperimentalAttribute : Attribute
	{
		public string DiagnosticId { get; }

		public string? UrlFormat { get; set; }

		public ExperimentalAttribute(string diagnosticId)
		{
			DiagnosticId = diagnosticId;
		}
	}
	[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)]
	[ExcludeFromCodeCoverage]
	internal sealed class MemberNotNullAttribute : Attribute
	{
		public string[] Members { get; }

		public MemberNotNullAttribute(string member)
		{
			Members = new string[1] { member };
		}

		public MemberNotNullAttribute(params string[] members)
		{
			Members = members;
		}
	}
	[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)]
	[ExcludeFromCodeCoverage]
	internal sealed class MemberNotNullWhenAttribute : Attribute
	{
		public bool ReturnValue { get; }

		public string[] Members { get; }

		public MemberNotNullWhenAttribute(bool returnValue, string member)
		{
			ReturnValue = returnValue;
			Members = new string[1] { member };
		}

		public MemberNotNullWhenAttribute(bool returnValue, params string[] members)
		{
			ReturnValue = returnValue;
			Members = members;
		}
	}
	[AttributeUsage(AttributeTargets.Constructor, AllowMultiple = false, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class SetsRequiredMembersAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class StringSyntaxAttribute : Attribute
	{
		public const string CompositeFormat = "CompositeFormat";

		public const string DateOnlyFormat = "DateOnlyFormat";

		public const string DateTimeFormat = "DateTimeFormat";

		public const string EnumFormat = "EnumFormat";

		public const string GuidFormat = "GuidFormat";

		public const string Json = "Json";

		public const string NumericFormat = "NumericFormat";

		public const string Regex = "Regex";

		public const string TimeOnlyFormat = "TimeOnlyFormat";

		public const string TimeSpanFormat = "TimeSpanFormat";

		public const string Uri = "Uri";

		public const string Xml = "Xml";

		public string Syntax { get; }

		public object?[] Arguments { get; }

		public StringSyntaxAttribute(string syntax)
		{
			Syntax = syntax;
			Arguments = new object[0];
		}

		public StringSyntaxAttribute(string syntax, params object?[] arguments)
		{
			Syntax = syntax;
			Arguments = arguments;
		}
	}
	[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class UnscopedRefAttribute : Attribute
	{
	}
}
namespace System.Runtime.Versioning
{
	[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Interface | AttributeTargets.Delegate, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class RequiresPreviewFeaturesAttribute : Attribute
	{
		public string? Message { get; }

		public string? Url { get; set; }

		public RequiresPreviewFeaturesAttribute()
		{
		}

		public RequiresPreviewFeaturesAttribute(string? message)
		{
			Message = message;
		}
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
	[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class CallerArgumentExpressionAttribute : Attribute
	{
		public string ParameterName { get; }

		public CallerArgumentExpressionAttribute(string parameterName)
		{
			ParameterName = parameterName;
		}
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class CollectionBuilderAttribute : Attribute
	{
		public Type BuilderType { get; }

		public string MethodName { get; }

		public CollectionBuilderAttribute(Type builderType, string methodName)
		{
			BuilderType = builderType;
			MethodName = methodName;
		}
	}
	[AttributeUsage(AttributeTargets.All, AllowMultiple = true, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class CompilerFeatureRequiredAttribute : Attribute
	{
		public const string RefStructs = "RefStructs";

		public const string RequiredMembers = "RequiredMembers";

		public string FeatureName { get; }

		public bool IsOptional { get; set; }

		public CompilerFeatureRequiredAttribute(string featureName)
		{
			FeatureName = featureName;
		}
	}
	[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class InterpolatedStringHandlerArgumentAttribute : Attribute
	{
		public string[] Arguments { get; }

		public InterpolatedStringHandlerArgumentAttribute(string argument)
		{
			Arguments = new string[1] { argument };
		}

		public InterpolatedStringHandlerArgumentAttribute(params string[] arguments)
		{
			Arguments = arguments;
		}
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class InterpolatedStringHandlerAttribute : Attribute
	{
	}
	[EditorBrowsable(EditorBrowsableState.Never)]
	[ExcludeFromCodeCoverage]
	internal static class IsExternalInit
	{
	}
	[AttributeUsage(AttributeTargets.Method, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class ModuleInitializerAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class OverloadResolutionPriorityAttribute : Attribute
	{
		public int Priority { get; }

		public OverloadResolutionPriorityAttribute(int priority)
		{
			Priority = priority;
		}
	}
	[AttributeUsage(AttributeTargets.Parameter, Inherited = true, AllowMultiple = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class ParamCollectionAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class RequiredMemberAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
	[EditorBrowsable(EditorBrowsableState.Never)]
	[ExcludeFromCodeCoverage]
	internal sealed class RequiresLocationAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Event | AttributeTargets.Interface, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class SkipLocalsInitAttribute : Attribute
	{
	}
}