using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.Globalization; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using HarmonyLib; using Microsoft.CodeAnalysis; using SpaceCraft; using TMPro; using UnityEngine; using UnityEngine.InputSystem; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = "")] [assembly: AssemblyCompany("PlayerInventoryStacks")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("PlayerInventoryStacks")] [assembly: AssemblyTitle("PlayerInventoryStacks")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace PlayerInventoryStacks { internal static class Backpacks { private static readonly HashSet Ids = new HashSet(); private static readonly FieldInfo LockTime = typeof(WorldObject).GetField("_lockInInventoryTime", BindingFlags.Instance | BindingFlags.NonPublic); internal static void Clear() { Ids.Clear(); } internal static void Register(int id) { if (id > 0) { Ids.Add(id); } } internal static bool IsPlayer(Inventory inventory) { if (inventory != null) { return Ids.Contains(inventory.GetId()); } return false; } internal static string Key(WorldObject item) { //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: 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) //IL_00f0: 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_0161: Unknown result type (might be due to invalid IL or missing references) //IL_0177: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Unknown result type (might be due to invalid IL or missing references) if (item == null) { throw new ArgumentNullException("item"); } StringBuilder b; if (item.GetLinkedInventoryId() == 0) { List secondaryInventoriesId = item.GetSecondaryInventoriesId(); if ((secondaryInventoriesId == null || secondaryInventoriesId.Count <= 0) && item.GetLinkedWorldObject() == 0 && (float)LockTime.GetValue(item) == 0f) { b = new StringBuilder(); Add(item.GetGroup().GetId()); Add(item.GetText()); Add(item.GetSetting()); Add(item.GetGeneticTraitType()); Add(item.GetGeneticTraitValue()); Color color = item.GetColor(); Add(color.r); Add(color.g); Add(color.b); Add(color.a); Add(item.GetEnergy()); Add(item.GetGrowth()); Add(item.GetHunger()); Add(item.GetPetTime()); Vector2Int count = item.GetCount(); Add(((Vector2Int)(ref count)).x); count = item.GetCount(); Add(((Vector2Int)(ref count)).y); Add(item.GetPlanetLinkedHash()); List linkedGroups = item.GetLinkedGroups(); Add(linkedGroups?.Count ?? 0); if (linkedGroups != null) { foreach (Group item2 in linkedGroups) { Add(item2.GetId()); } } List panelsId = item.GetPanelsId(); Add(panelsId?.Count ?? 0); if (panelsId != null) { foreach (int item3 in panelsId) { Add(item3); } } return b.ToString(); } } return "unique:" + item.GetId(); void Add(object value) { string text = Convert.ToString(value, CultureInfo.InvariantCulture) ?? ""; b.Append(text.Length).Append(':').Append(text) .Append('|'); } } internal static List> Layout(Inventory inventory) { return StackLayout.Create(inventory.GetInsideWorldObjects(), Key); } internal static bool FullFor(Inventory inventory, WorldObject item) { if (!IsPlayer(inventory)) { return inventory.IsFull(); } if (item == null) { return Layout(inventory).Count >= inventory.GetSize(); } if (inventory.ContainWorldObject(item)) { return false; } return !StackLayout.CanAdd(inventory.GetInsideWorldObjects(), item, inventory.GetSize(), Key); } internal static bool FullForGroup(Inventory inventory, Group group) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Expected O, but got Unknown return FullFor(inventory, new WorldObject(0, group)); } internal static bool FitsCraft(Inventory inventory, List ingredients, Group output, bool freeCraft) { //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Expected O, but got Unknown List list = inventory.GetInsideWorldObjects().ToList(); if (!freeCraft) { foreach (Group group in ingredients) { int num = list.FindLastIndex((WorldObject item) => item.GetGroup() == group); if (num >= 0) { list.RemoveAt(num); } } } return StackLayout.CanAdd(list, new WorldObject(0, output), inventory.GetSize(), Key); } } [BepInPlugin("local.planetcrafter.playerinventorystacks", "Player Inventory Stacks", "1.0.0")] [BepInProcess("Planet Crafter.exe")] public sealed class Plugin : BaseUnityPlugin { public const string Id = "local.planetcrafter.playerinventorystacks"; private Harmony harmony; private void Awake() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected O, but got Unknown harmony = new Harmony("local.planetcrafter.playerinventorystacks"); try { harmony.PatchAll(typeof(Plugin).Assembly); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Player Inventory Stacks 1.0.0 loaded: 64 items per backpack stack; containers unchanged."); } catch (Exception ex) { harmony.UnpatchSelf(); ((BaseUnityPlugin)this).Logger.LogError((object)("Player Inventory Stacks could not patch this game version; all its patches were removed. " + ex)); } } private void OnDestroy() { Harmony obj = harmony; if (obj != null) { obj.UnpatchSelf(); } } } [HarmonyPatch(typeof(InventoriesHandler), "OnNetworkSpawn")] internal static class ResetWorld { private static void Prefix() { Backpacks.Clear(); } } [HarmonyPatch(typeof(PlayerBackpack), "SetInventory")] internal static class RegisterBackpack { private static void Prefix(Inventory _playerInventory) { if (_playerInventory != null) { Backpacks.Register(_playerInventory.GetId()); } } } [HarmonyPatch(typeof(PlayerMainController), "InitPlayerClientRpc")] internal static class RegisterClientBackpack { private static void Prefix(int inventoryId) { Backpacks.Register(inventoryId); } } [HarmonyPatch(typeof(SavedDataHandler), "LoadSavedData")] internal static class RegisterSavedBackpacks { private static void Postfix(SavedDataHandler __instance) { List lastLoadedPlayerData = __instance.GetLastLoadedPlayerData(); if (lastLoadedPlayerData == null) { return; } foreach (JsonablePlayerState item in lastLoadedPlayerData) { Backpacks.Register(item.inventoryId); } } } [HarmonyPatch(typeof(Inventory), "IsFull")] internal static class InventoryFull { private static bool Prefix(Inventory __instance, ref bool __result) { if (!Backpacks.IsPlayer(__instance)) { return true; } __result = Backpacks.Layout(__instance).Count >= __instance.GetSize(); return false; } } [HarmonyPatch(typeof(Inventory), "AddItemInInventory")] internal static class AddItemCapacity { private static IEnumerable Transpiler(IEnumerable instructions) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Expected O, but got Unknown return PatchTools.ReplaceFull(instructions, (IEnumerable)(object)new CodeInstruction[1] { new CodeInstruction(OpCodes.Ldarg_1, (object)null) }, "FullFor"); } } [HarmonyPatch(typeof(Inventory), "DropObjectsIfNotEnoughSpace")] internal static class BackpackShrink { private static bool Prefix(Inventory __instance, Vector3 dropPosition, bool removeOnly, ref List __result) { //IL_0065: Unknown result type (might be due to invalid IL or missing references) if (!Backpacks.IsPlayer(__instance)) { return true; } List list = Backpacks.Layout(__instance).Skip(Math.Max(0, __instance.GetSize())).SelectMany((StackLayout.Stack s) => s.Items) .ToList(); foreach (WorldObject item in list) { if (!removeOnly) { WorldObjectsHandler.Instance.DropOnFloor(item, dropPosition, 0f, true, false, 0); } __instance.RemoveItem(item); } __result = list; return false; } } [HarmonyPatch(typeof(InventoryDisplayer), "SetInventoryBlocks")] internal static class DisplayStacks { private static void Prefix(Inventory ____inventory, ref ReadOnlyCollection inventoryWorldObjects, out List> __state) { __state = null; if (Backpacks.IsPlayer(____inventory)) { __state = Backpacks.Layout(____inventory); inventoryWorldObjects = __state.Select((StackLayout.Stack s) => s.Items[0]).ToList().AsReadOnly(); } } private static void Postfix(Inventory ____inventory, GridLayoutGroup ____grid, List> __state) { //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0090: 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_009b: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: 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_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) if (__state == null) { return; } InventoryBlock[] componentsInChildren = ((Component)____grid).GetComponentsInChildren(); componentsInChildren = componentsInChildren.Skip(Math.Max(0, componentsInChildren.Length - ____inventory.GetSize())).ToArray(); for (int i = 0; i < Math.Min(componentsInChildren.Length, __state.Count); i++) { int count = __state[i].Items.Count; if (count > 1) { GameObject val = new GameObject("PlayerStackCount", new Type[2] { typeof(RectTransform), typeof(TextMeshProUGUI) }); val.transform.SetParent(((Component)componentsInChildren[i]).transform, false); RectTransform val2 = (RectTransform)val.transform; val2.anchorMin = Vector2.zero; val2.anchorMax = Vector2.one; val2.offsetMin = new Vector2(3f, 3f); val2.offsetMax = new Vector2(-5f, -3f); TextMeshProUGUI component = val.GetComponent(); ((TMP_Text)component).font = TMP_Settings.defaultFontAsset; ((TMP_Text)component).text = count.ToString(); ((TMP_Text)component).fontSize = 22f; ((TMP_Text)component).fontStyle = (FontStyles)1; ((Graphic)component).color = Color.white; ((TMP_Text)component).alignment = (TextAlignmentOptions)1028; ((Graphic)component).raycastTarget = false; ((TMP_Text)component).textWrappingMode = (TextWrappingModes)0; ((TMP_Text)component).outlineWidth = 0.22f; ((TMP_Text)component).outlineColor = new Color32((byte)0, (byte)0, (byte)0, byte.MaxValue); } } } } internal static class PatchTools { internal static readonly MethodInfo IsFull = AccessTools.Method(typeof(Inventory), "IsFull", (Type[])null, (Type[])null); internal static IEnumerable ReplaceFull(IEnumerable source, IEnumerable loadCandidate, string helper, int expected = 1) { //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Expected O, but got Unknown List list = new List(); int num = 0; foreach (CodeInstruction item in source) { if (CodeInstructionExtensions.Calls(item, IsFull)) { List list2 = loadCandidate.Select((Func)((CodeInstruction c) => new CodeInstruction(c))).ToList(); list2[0].labels.AddRange(item.labels); list2[0].blocks.AddRange(item.blocks); list.AddRange(list2); list.Add(new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(Backpacks), helper, (Type[])null, (Type[])null))); num++; } else { list.Add(item); } } if (num != expected) { throw new InvalidOperationException($"Expected {expected} capacity checks, found {num}."); } return list; } internal static WorldObject ActionItem(Component component) { WorldObjectAssociated componentInParent = component.GetComponentInParent(); if (componentInParent == null) { return null; } return componentInParent.GetWorldObject(); } internal static IEnumerable ActionCapacity(IEnumerable source, FieldInfo owner = null) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Expected O, but got Unknown //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Expected O, but got Unknown //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Expected O, but got Unknown List list = new List { new CodeInstruction(OpCodes.Ldarg_0, (object)null) }; if (owner != null) { list.Add(new CodeInstruction(OpCodes.Ldfld, (object)owner)); } list.Add(new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(PatchTools), "ActionItem", (Type[])null, (Type[])null))); return ReplaceFull(source, list, "FullFor"); } } [HarmonyPatch(typeof(ActionMinable), "OnAction")] internal static class StartMiningCapacity { private static IEnumerable Transpiler(IEnumerable instructions) { return PatchTools.ActionCapacity(instructions); } } [HarmonyPatch] internal static class FinishMiningCapacity { private static MethodBase TargetMethod() { return AccessTools.EnumeratorMoveNext((MethodBase)AccessTools.Method(typeof(ActionMinable), "FinishMining", (Type[])null, (Type[])null)); } private static IEnumerable Transpiler(IEnumerable instructions, MethodBase original) { return PatchTools.ActionCapacity(instructions, AccessTools.Field(original.DeclaringType, "<>4__this")); } } [HarmonyPatch(typeof(ActionGrabable), "OnAction")] internal static class GrabCapacity { private static IEnumerable Transpiler(IEnumerable instructions) { return PatchTools.ActionCapacity(instructions); } } [HarmonyPatch(typeof(CraftManager), "TryToCraftInInventory")] internal static class CraftCapacity { private static bool Prefix(PlayerMainController playerController, GroupItem groupItem, ref bool __result) { Inventory inventory = playerController.GetPlayerBackpack().GetInventory(); if (!Backpacks.IsPlayer(inventory)) { return true; } bool freeCraft = Managers.GetManager().GetCurrentGameSettings().GetFreeCraft(); if (Backpacks.FitsCraft(inventory, ((Group)groupItem).GetRecipe().GetIngredientsGroupInRecipe(), (Group)(object)groupItem, freeCraft)) { return true; } Managers.GetManager().DisplayCursorText("UI_InventoryFull", 2f, "", "", false); __result = false; return false; } private static IEnumerable Transpiler(IEnumerable instructions) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Expected O, but got Unknown return PatchTools.ReplaceFull(instructions, (IEnumerable)(object)new CodeInstruction[1] { new CodeInstruction(OpCodes.Ldarg_2, (object)null) }, "FullForGroup", 2); } } [HarmonyPatch(typeof(WorldObjectsHandler), "RetrieveResourcesFromDeconstructionServerRpc")] internal static class DeconstructionCapacity { private static IEnumerable Transpiler(IEnumerable instructions) { //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Expected O, but got Unknown List list = instructions.ToList(); int num = list.FindIndex((CodeInstruction c) => CodeInstructionExtensions.Calls(c, PatchTools.IsFull)); int num2 = ((num < 0) ? (-1) : list.FindLastIndex(num, (CodeInstruction c) => CodeInstructionExtensions.Calls(c, AccessTools.Method(typeof(WorldObject), "GetGroup", (Type[])null, (Type[])null)))); if (num2 <= 0 || !CodeInstructionExtensions.IsLdloc(list[num2 - 1], (LocalBuilder)null)) { throw new InvalidOperationException("Could not identify deconstruction resource local."); } return PatchTools.ReplaceFull(list, (IEnumerable)(object)new CodeInstruction[1] { new CodeInstruction(list[num2 - 1].opcode, list[num2 - 1].operand) }, "FullFor"); } } [HarmonyPatch(typeof(ActionPanelDeconstruct), "Deconstruct")] internal static class PanelCapacity { private static IEnumerable Transpiler(IEnumerable instructions, MethodBase original) { //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Expected O, but got Unknown //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Expected O, but got Unknown var list = (from local in original.GetMethodBody().LocalVariables select new { local = local, field = local.LocalType.GetField("group", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) } into pair where pair.field?.FieldType == typeof(Group) select pair).ToList(); if (list.Count != 1) { throw new InvalidOperationException("Could not identify panel ingredient local."); } var anon = list[0]; return PatchTools.ReplaceFull(instructions, (IEnumerable)(object)new CodeInstruction[2] { new CodeInstruction(OpCodes.Ldloc, (object)anon.local.LocalIndex), new CodeInstruction(OpCodes.Ldfld, (object)anon.field) }, "FullForGroup"); } } [HarmonyPatch(typeof(InventoriesHandler), "AnInventoryHasBeenClicked")] internal static class QuickTransferKey { internal static bool IsPressed(PlayerInputDispatcher input, Inventory source) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) if (input.IsPressingAccessibilityKey()) { return true; } if (Keyboard.current == null || !Keyboard.current.shiftKey.isPressed) { return false; } WindowsHandler manager = Managers.GetManager(); UiWindow windowViaUiId = manager.GetWindowViaUiId(manager.GetOpenedUi()); UiWindowContainer val = (UiWindowContainer)(object)((windowViaUiId is UiWindowContainer) ? windowViaUiId : null); if ((Object)(object)val != (Object)null) { if (!Backpacks.IsPlayer(source)) { return Backpacks.IsPlayer(val.GetOtherInventory(source)); } return true; } return false; } private static IEnumerable Transpiler(IEnumerable instructions) { //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Expected O, but got Unknown //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Expected O, but got Unknown List list = new List(); int num = 0; MethodInfo methodInfo = AccessTools.Method(typeof(PlayerInputDispatcher), "IsPressingAccessibilityKey", (Type[])null, (Type[])null); foreach (CodeInstruction instruction in instructions) { if (CodeInstructionExtensions.Calls(instruction, methodInfo)) { CodeInstruction val = new CodeInstruction(OpCodes.Ldarg_1, (object)null); val.labels.AddRange(instruction.labels); val.blocks.AddRange(instruction.blocks); list.Add(val); list.Add(new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(QuickTransferKey), "IsPressed", (Type[])null, (Type[])null))); num++; } else { list.Add(instruction); } } if (num != 1) { throw new InvalidOperationException("Could not identify inventory quick-transfer key check."); } return list; } } internal static class StackLayout { internal sealed class Stack { internal readonly List Items = new List(); } internal const int Limit = 64; internal static List> Create(IEnumerable items, Func key) { List> list = new List>(); Dictionary> dictionary = new Dictionary>(StringComparer.Ordinal); foreach (T item in items) { string key2 = key(item); if (!dictionary.TryGetValue(key2, out var value) || value.Items.Count == 64) { value = (dictionary[key2] = new Stack()); list.Add(value); } value.Items.Add(item); } return list; } internal static bool CanAdd(IEnumerable items, T candidate, int slots, Func key) { List> list = Create(items, key); if (list.Count < slots) { return true; } if (list.Count > slots) { return false; } string text = key(candidate); foreach (Stack item in list) { if (item.Items.Count < 64 && key(item.Items[0]) == text) { return true; } } return false; } } }