From f9c5ea86f7460548441f8a55275c5cb53fee35e9 Mon Sep 17 00:00:00 2001 From: Ellpeck Date: Sat, 9 May 2020 13:40:46 +0200 Subject: [PATCH] finished the crafting terminal! --- .../prettypipes/packets/PacketButton.java | 6 ++ .../terminal/CraftingTerminalBlock.java | 27 ++++--- .../terminal/CraftingTerminalTileEntity.java | 76 +++++++++++++++++++ .../terminal/ItemTerminalTileEntity.java | 19 +++-- .../containers/CraftingTerminalGui.java | 12 +-- .../assets/prettypipes/lang/en_us.json | 1 + 6 files changed, 115 insertions(+), 26 deletions(-) diff --git a/src/main/java/de/ellpeck/prettypipes/packets/PacketButton.java b/src/main/java/de/ellpeck/prettypipes/packets/PacketButton.java index e8714b6..d77db91 100644 --- a/src/main/java/de/ellpeck/prettypipes/packets/PacketButton.java +++ b/src/main/java/de/ellpeck/prettypipes/packets/PacketButton.java @@ -8,6 +8,7 @@ import de.ellpeck.prettypipes.misc.ItemFilter.IFilteredContainer; import de.ellpeck.prettypipes.pipe.PipeTileEntity; import de.ellpeck.prettypipes.pipe.containers.AbstractPipeContainer; import de.ellpeck.prettypipes.pipe.modules.stacksize.StackSizeModuleItem; +import de.ellpeck.prettypipes.terminal.CraftingTerminalTileEntity; import de.ellpeck.prettypipes.terminal.ItemTerminalTileEntity; import net.minecraft.client.Minecraft; import net.minecraft.entity.player.PlayerEntity; @@ -109,6 +110,11 @@ public class PacketButton { STACK_SIZE_AMOUNT((pos, data, player) -> { AbstractPipeContainer container = (AbstractPipeContainer) player.openContainer; StackSizeModuleItem.setMaxStackSize(container.moduleStack, data[0]); + }), + CRAFT_TERMINAL_REQUEST((pos, data, player) -> { + CraftingTerminalTileEntity tile = Utility.getTileEntity(CraftingTerminalTileEntity.class, player.world, pos); + boolean all = data[0] > 0; + tile.requestCraftingItems(player, all); }); public final TriConsumer action; diff --git a/src/main/java/de/ellpeck/prettypipes/terminal/CraftingTerminalBlock.java b/src/main/java/de/ellpeck/prettypipes/terminal/CraftingTerminalBlock.java index c6acce9..704fa56 100644 --- a/src/main/java/de/ellpeck/prettypipes/terminal/CraftingTerminalBlock.java +++ b/src/main/java/de/ellpeck/prettypipes/terminal/CraftingTerminalBlock.java @@ -27,20 +27,23 @@ public class CraftingTerminalBlock extends ItemTerminalBlock { BlockPos pos = pipePos.offset(direction); CraftingTerminalTileEntity tile = Utility.getTileEntity(CraftingTerminalTileEntity.class, world, pos); if (tile != null) { - int lowestFitting = -1; - for (int i = 0; i < tile.craftItems.getSlots(); i++) { - ItemStack stack = tile.getRequestedCraftItem(i); - if (!ItemHandlerHelper.canItemStacksStackRelaxed(stack, item.stack)) - continue; - if (lowestFitting < 0 || stack.getCount() < tile.getRequestedCraftItem(lowestFitting).getCount()) - lowestFitting = i; - } ItemStack remain = item.stack; - if (lowestFitting >= 0) { - remain = tile.craftItems.insertItem(lowestFitting, item.stack, false); - if (remain.isEmpty()) - return ItemStack.EMPTY; + int lowestFitting = -1; + do { + for (int i = 0; i < tile.craftItems.getSlots(); i++) { + ItemStack stack = tile.getRequestedCraftItem(i); + if (!ItemHandlerHelper.canItemStacksStackRelaxed(stack, remain)) + continue; + if (lowestFitting < 0 || stack.getCount() < tile.getRequestedCraftItem(lowestFitting).getCount()) + lowestFitting = i; + } + if (lowestFitting >= 0) { + remain = tile.craftItems.insertItem(lowestFitting, remain, false); + if (remain.isEmpty()) + return ItemStack.EMPTY; + } } + while (lowestFitting >= 0); return ItemHandlerHelper.insertItemStacked(tile.items, remain, false); } return item.stack; diff --git a/src/main/java/de/ellpeck/prettypipes/terminal/CraftingTerminalTileEntity.java b/src/main/java/de/ellpeck/prettypipes/terminal/CraftingTerminalTileEntity.java index 0eb3756..ec2abab 100644 --- a/src/main/java/de/ellpeck/prettypipes/terminal/CraftingTerminalTileEntity.java +++ b/src/main/java/de/ellpeck/prettypipes/terminal/CraftingTerminalTileEntity.java @@ -2,6 +2,12 @@ package de.ellpeck.prettypipes.terminal; import de.ellpeck.prettypipes.PrettyPipes; import de.ellpeck.prettypipes.Registry; +import de.ellpeck.prettypipes.misc.EquatableItemStack; +import de.ellpeck.prettypipes.misc.ItemEqualityType; +import de.ellpeck.prettypipes.network.NetworkItem; +import de.ellpeck.prettypipes.network.NetworkLocation; +import de.ellpeck.prettypipes.network.NetworkLock; +import de.ellpeck.prettypipes.network.PipeNetwork; import de.ellpeck.prettypipes.terminal.containers.CraftingTerminalContainer; import de.ellpeck.prettypipes.terminal.containers.ItemTerminalContainer; import net.minecraft.entity.player.PlayerEntity; @@ -10,10 +16,18 @@ import net.minecraft.inventory.container.Container; import net.minecraft.item.ItemStack; import net.minecraft.nbt.CompoundNBT; import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.Style; +import net.minecraft.util.text.TextFormatting; import net.minecraft.util.text.TranslationTextComponent; import net.minecraftforge.items.ItemStackHandler; +import org.apache.commons.lang3.mutable.MutableInt; +import org.apache.commons.lang3.tuple.Pair; import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; public class CraftingTerminalTileEntity extends ItemTerminalTileEntity { @@ -28,6 +42,68 @@ public class CraftingTerminalTileEntity extends ItemTerminalTileEntity { return this.craftItems.getStackInSlot(slot); } + public void requestCraftingItems(PlayerEntity player, boolean all) { + PipeNetwork network = PipeNetwork.get(this.world); + network.startProfile("terminal_request_crafting"); + this.updateItems(); + + // this is the amount of items required for each ingredient when crafting ONE + Map requiredItems = new HashMap<>(); + for (int i = 0; i < this.craftItems.getSlots(); i++) { + ItemStack requested = this.getRequestedCraftItem(i); + if (requested.isEmpty()) + continue; + MutableInt amount = requiredItems.computeIfAbsent(new EquatableItemStack(requested), s -> new MutableInt()); + amount.add(1); + } + // the highest amount we can craft with the items we have + int lowestAvailable = Integer.MAX_VALUE; + for (Map.Entry entry : requiredItems.entrySet()) { + EquatableItemStack stack = entry.getKey(); + NetworkItem item = this.networkItems.get(stack); + if (item != null) { + // total amount of available items of this type + int available = 0; + for (NetworkLocation location : item.getLocations()) { + for (int slot : location.getStackSlots(this.world, stack.stack, ItemEqualityType.NBT)) { + ItemStack inSlot = location.getItemHandler(this.world).extractItem(slot, Integer.MAX_VALUE, true); + if (inSlot.isEmpty()) + continue; + inSlot.shrink(network.getLockedAmount(location.getPos(), slot)); + available += inSlot.getCount(); + } + } + // divide the total by the amount required to get the amount that + // we have available for each crafting slot that contains this item + available /= entry.getValue().intValue(); + int fit = stack.stack.getMaxStackSize() - stack.stack.getCount(); + if (available > fit) + available = fit; + if (available < lowestAvailable) + lowestAvailable = available; + } else { + lowestAvailable = 0; + } + if (lowestAvailable <= 0) + player.sendMessage(new TranslationTextComponent("info." + PrettyPipes.ID + ".not_found", stack.stack.getDisplayName()).setStyle(new Style().setColor(TextFormatting.RED))); + } + if (lowestAvailable > 0) { + // if we're only crafting one item, pretend we only have enough for one + if (!all) + lowestAvailable = 1; + for (int i = 0; i < this.craftItems.getSlots(); i++) { + ItemStack requested = this.getRequestedCraftItem(i); + if (requested.isEmpty()) + continue; + requested = requested.copy(); + requested.setCount(lowestAvailable); + this.requestItemImpl(requested); + } + player.sendMessage(new TranslationTextComponent("info." + PrettyPipes.ID + ".sending_ingredients", lowestAvailable).setStyle(new Style().setColor(TextFormatting.GREEN))); + } + network.endProfile(); + } + @Override public CompoundNBT write(CompoundNBT compound) { compound.put("craft_items", this.craftItems.serializeNBT()); diff --git a/src/main/java/de/ellpeck/prettypipes/terminal/ItemTerminalTileEntity.java b/src/main/java/de/ellpeck/prettypipes/terminal/ItemTerminalTileEntity.java index 063deb4..13f4ad0 100644 --- a/src/main/java/de/ellpeck/prettypipes/terminal/ItemTerminalTileEntity.java +++ b/src/main/java/de/ellpeck/prettypipes/terminal/ItemTerminalTileEntity.java @@ -138,8 +138,19 @@ public class ItemTerminalTileEntity extends TileEntity implements INamedContaine public void requestItem(PlayerEntity player, ItemStack stack) { PipeNetwork network = PipeNetwork.get(this.world); network.startProfile("terminal_request_item"); - EquatableItemStack equatable = new EquatableItemStack(stack); this.updateItems(); + int requested = this.requestItemImpl(stack); + if (requested > 0) { + player.sendMessage(new TranslationTextComponent("info." + PrettyPipes.ID + ".sending", requested, stack.getDisplayName()).setStyle(new Style().setColor(TextFormatting.GREEN))); + } else { + player.sendMessage(new TranslationTextComponent("info." + PrettyPipes.ID + ".not_found", stack.getDisplayName()).setStyle(new Style().setColor(TextFormatting.RED))); + } + network.endProfile(); + } + + protected int requestItemImpl(ItemStack stack) { + PipeNetwork network = PipeNetwork.get(this.world); + EquatableItemStack equatable = new EquatableItemStack(stack); NetworkItem item = this.networkItems.get(equatable); if (item != null) { int remain = stack.getCount(); @@ -161,11 +172,9 @@ public class ItemTerminalTileEntity extends TileEntity implements INamedContaine } } } - player.sendMessage(new TranslationTextComponent("info." + PrettyPipes.ID + ".sending", stack.getCount() - remain, stack.getDisplayName()).setStyle(new Style().setColor(TextFormatting.GREEN))); - } else { - player.sendMessage(new TranslationTextComponent("info." + PrettyPipes.ID + ".not_found", stack.getDisplayName()).setStyle(new Style().setColor(TextFormatting.RED))); + return stack.getCount() - remain; } - network.endProfile(); + return 0; } private PlayerEntity[] getLookingPlayers() { diff --git a/src/main/java/de/ellpeck/prettypipes/terminal/containers/CraftingTerminalGui.java b/src/main/java/de/ellpeck/prettypipes/terminal/containers/CraftingTerminalGui.java index 5179206..4018250 100644 --- a/src/main/java/de/ellpeck/prettypipes/terminal/containers/CraftingTerminalGui.java +++ b/src/main/java/de/ellpeck/prettypipes/terminal/containers/CraftingTerminalGui.java @@ -1,6 +1,7 @@ package de.ellpeck.prettypipes.terminal.containers; import de.ellpeck.prettypipes.PrettyPipes; +import de.ellpeck.prettypipes.packets.PacketButton; import de.ellpeck.prettypipes.packets.PacketHandler; import de.ellpeck.prettypipes.packets.PacketRequest; import de.ellpeck.prettypipes.terminal.CraftingTerminalTileEntity; @@ -25,15 +26,8 @@ public class CraftingTerminalGui extends ItemTerminalGui { protected void init() { super.init(); this.requestButton = this.addButton(new Button(this.guiLeft + 8, this.guiTop + 100, 50, 20, I18n.format("info." + PrettyPipes.ID + ".request"), button -> { - CraftingTerminalTileEntity tile = this.getCraftingContainer().getTile(); - for (int i = 0; i < tile.craftItems.getSlots(); i++) { - ItemStack stack = tile.getRequestedCraftItem(i); - if (stack.isEmpty()) - continue; - stack = stack.copy(); - stack.setCount(1); - PacketHandler.sendToServer(new PacketRequest(this.container.tile.getPos(), stack, 1)); - } + int all = hasShiftDown() ? 1 : 0; + PacketHandler.sendToServer(new PacketButton(this.container.tile.getPos(), PacketButton.ButtonResult.CRAFT_TERMINAL_REQUEST, all)); })); this.requestButton.active = !this.getCraftingContainer().craftInventory.isEmpty(); } diff --git a/src/main/resources/assets/prettypipes/lang/en_us.json b/src/main/resources/assets/prettypipes/lang/en_us.json index be4cb6d..19560d9 100644 --- a/src/main/resources/assets/prettypipes/lang/en_us.json +++ b/src/main/resources/assets/prettypipes/lang/en_us.json @@ -50,6 +50,7 @@ "info.prettypipes.request": "Request", "info.prettypipes.not_found": "%s not found", "info.prettypipes.sending": "Sending %s %s", + "info.prettypipes.sending_ingredients": "Sending %s sets of ingredients", "info.prettypipes.order": "Order by %s", "info.prettypipes.order.amount": "Amount", "info.prettypipes.order.name": "Name",