diff --git a/src/core/scala/mrtjp/projectred/core/inventory/BaseInventory.java b/src/core/scala/mrtjp/projectred/core/inventory/BaseInventory.java new file mode 100644 index 000000000..6e68f0dcf --- /dev/null +++ b/src/core/scala/mrtjp/projectred/core/inventory/BaseInventory.java @@ -0,0 +1,54 @@ +package mrtjp.projectred.core.inventory; + +import net.minecraft.inventory.Inventory; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.nbt.ListNBT; + +/** + * Simple extension of default vanilla Inventory class that allows for proper saving and loading + * to a CompoundNBT. Default implementation does not load items back into their original slots. + *

+ * Use BaseInventory#save and BaseInventory#load instead of Inventory#createTag and Inventory#fromTag + */ +public class BaseInventory extends Inventory { + + private static final String TAG_ITEMS = "items"; + private static final String TAG_SLOT = "slot"; + private static final String TAG_ITEM_COUNT = "item_count"; + + public BaseInventory(int size) { + super(size); + } + + public void save(CompoundNBT tag) { + ListNBT list = new ListNBT(); + for (int i = 0; i < getContainerSize(); i++) { + ItemStack stack = getItem(i); + if (!stack.isEmpty()) { + CompoundNBT itemTag = new CompoundNBT(); + itemTag.putInt(TAG_SLOT, i); + stack.save(itemTag); + list.add(itemTag); + } + } + tag.put(TAG_ITEMS, list); + tag.putInt(TAG_ITEM_COUNT, list.size()); + } + + public void load(CompoundNBT tag) { + clearContent(); + ListNBT list = tag.getList(TAG_ITEMS, 10); + for (int i = 0; i < list.size(); i++) { + CompoundNBT itemTag = list.getCompound(i); + int slot = itemTag.contains("index") ? itemTag.getInt("index") : itemTag.getInt(TAG_SLOT); //TODO remove legacy support + if (slot >= 0 && slot < getContainerSize()) { + setItem(slot, ItemStack.of(itemTag)); + } + } + } + + public static int getItemCount(CompoundNBT tag) { + return tag.contains(TAG_ITEM_COUNT) ? tag.getInt(TAG_ITEM_COUNT) : tag.getList(TAG_ITEMS, 10).size(); //TODO remove legacy support + } +} diff --git a/src/core/scala/mrtjp/projectred/lib/InventoryLib.java b/src/core/scala/mrtjp/projectred/lib/InventoryLib.java index a487f75d5..50422506d 100644 --- a/src/core/scala/mrtjp/projectred/lib/InventoryLib.java +++ b/src/core/scala/mrtjp/projectred/lib/InventoryLib.java @@ -1,9 +1,13 @@ package mrtjp.projectred.lib; +import net.minecraft.entity.player.PlayerInventory; import net.minecraft.inventory.IInventory; +import net.minecraft.inventory.container.Slot; import net.minecraft.item.ItemStack; import net.minecraft.util.NonNullList; +import java.util.function.Consumer; + public class InventoryLib { public static void injectItemStack(IInventory inventory, ItemStack stack, boolean reverse) { @@ -66,4 +70,43 @@ private static void injectItemStack(IInventory inventory, ItemStack stack, int s public static boolean areStackable(ItemStack a, ItemStack b) { return ItemStack.isSame(a, b) && ItemStack.tagMatches(a, b) && a.getMaxStackSize() > 1 && b.getMaxStackSize() > 1; } + + public static void addPlayerInventory(PlayerInventory playerInventory, int x, int y, Consumer slotConsumer) { + addInventory(playerInventory, 9, x, y, 9, 3, slotConsumer); // Inventory (0 - 26) + addInventory(playerInventory, 0, x, y + 58, 9, 1, slotConsumer); // Hotbar slots (27 - 35) + } + + public static void addPlayerInventory(PlayerInventory playerInventory, int x, int y, SlotFactory slotFactory, Consumer slotConsumer) { + addInventory(playerInventory, 9, x, y, 9, 3, slotFactory, slotConsumer); // Inventory (0 - 26) + addInventory(playerInventory, 0, x, y + 58, 9, 1, slotFactory, slotConsumer); // Hotbar slots (27 - 35) + } + + public static void addInventory(IInventory inventory, int i, int x, int y, int columns, int rows, Consumer slotConsumer) { + addInventory(inventory, i, x, y, columns, rows, Slot::new, slotConsumer); + } + + /** + * Creates a grid of slots for a container with standard spacing. + * + * @param inventory The inventory backing the slots + * @param i Inventory index of the first slot + * @param x X position of the top left slot + * @param y Y position of the top left slot + * @param columns Number of columns in the grid + * @param rows Number of rows in the grid + * @param slotFactory Factory for creating the slots + * @param slotConsumer Consumer for the slots (typically Container.addSlot(...)) + */ + public static void addInventory(IInventory inventory, int i, int x, int y, int columns, int rows, SlotFactory slotFactory, Consumer slotConsumer) { + for (int c = 0; c < columns; c++) { + for (int r = 0; r < rows; r++) { + slotConsumer.accept(slotFactory.createSlot(inventory, i + (r * columns + c), x + c * 18, y + r * 18)); + } + } + } + + @FunctionalInterface + public interface SlotFactory { + Slot createSlot(IInventory inventory, int index, int x, int y); + } }