diff --git a/src/main/java/de/ellpeck/prettypipes/misc/ItemFilter.java b/src/main/java/de/ellpeck/prettypipes/misc/ItemFilter.java index db7ac75..f6c947c 100644 --- a/src/main/java/de/ellpeck/prettypipes/misc/ItemFilter.java +++ b/src/main/java/de/ellpeck/prettypipes/misc/ItemFilter.java @@ -76,7 +76,7 @@ public class ItemFilter extends ItemStackHandler { } else if (id == 1 && this.canPopulateFromInventories) { // populate filter from inventories for (Direction direction : Direction.values()) { - IItemHandler handler = this.pipe.getItemHandler(direction); + IItemHandler handler = this.pipe.getItemHandler(direction, false); if (handler == null) continue; for (int i = 0; i < handler.getSlots(); i++) { @@ -104,7 +104,7 @@ public class ItemFilter extends ItemStackHandler { .collect(Collectors.toList()); for (int i = 0; i < this.getSlots(); i++) { ItemStack filter = this.getStackInSlot(i); - if(filter.isEmpty()) + if (filter.isEmpty()) continue; boolean equal = ItemStack.areItemsEqual(stack, filter); if (modifiers.isEmpty()) { diff --git a/src/main/java/de/ellpeck/prettypipes/misc/ItemTerminalWidget.java b/src/main/java/de/ellpeck/prettypipes/misc/ItemTerminalWidget.java index d2912b5..d323b7d 100644 --- a/src/main/java/de/ellpeck/prettypipes/misc/ItemTerminalWidget.java +++ b/src/main/java/de/ellpeck/prettypipes/misc/ItemTerminalWidget.java @@ -18,29 +18,23 @@ import java.util.List; public class ItemTerminalWidget extends Widget { private static final ResourceLocation FONT = new ResourceLocation(PrettyPipes.ID, "unicode"); - private final ItemStack stack; private final ItemTerminalGui screen; public final int gridX; public final int gridY; - public boolean hidden; + public boolean selected; + public ItemStack stack = ItemStack.EMPTY; - public ItemTerminalWidget(int xIn, int yIn, int gridX, int gridY, ItemStack stack, ItemTerminalGui screen) { - super(xIn, yIn, 16, 16, stack.getDisplayName().getFormattedText()); + public ItemTerminalWidget(int xIn, int yIn, int gridX, int gridY, ItemTerminalGui screen) { + super(xIn, yIn, 16, 16, ""); this.gridX = gridX; this.gridY = gridY; - this.stack = stack; this.screen = screen; } @Override - protected boolean clicked(double x, double y) { - return false; - } - - @Override - public void render(int mouseX, int mouseY, float partialTicks) { - if (!this.hidden) - super.render(mouseX, mouseY, partialTicks); + public void onClick(double x, double y) { + this.screen.streamWidgets().forEach(w -> w.selected = false); + this.selected = true; } @Override @@ -49,6 +43,8 @@ public class ItemTerminalWidget extends Widget { ItemRenderer renderer = mc.getItemRenderer(); this.setBlitOffset(100); renderer.zLevel = 100; + if (this.selected) + fill(this.x, this.y, this.x + 16, this.y + 16, -2130706433); RenderSystem.enableDepthTest(); renderer.renderItemAndEffectIntoGUI(mc.player, this.stack, this.x, this.y); int amount = this.stack.getCount(); @@ -69,7 +65,7 @@ public class ItemTerminalWidget extends Widget { @Override public void renderToolTip(int mouseX, int mouseY) { - if (this.isHovered()) { + if (this.visible && this.isHovered()) { FontRenderer font = this.stack.getItem().getFontRenderer(this.stack); if (font == null) font = this.screen.getMinecraft().fontRenderer; diff --git a/src/main/java/de/ellpeck/prettypipes/network/NetworkItem.java b/src/main/java/de/ellpeck/prettypipes/network/NetworkItem.java index d9e426f..c081001 100644 --- a/src/main/java/de/ellpeck/prettypipes/network/NetworkItem.java +++ b/src/main/java/de/ellpeck/prettypipes/network/NetworkItem.java @@ -3,14 +3,11 @@ package de.ellpeck.prettypipes.network; import de.ellpeck.prettypipes.misc.EquatableItemStack; import net.minecraft.item.ItemStack; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; +import java.util.*; public class NetworkItem { - private final Set locations = new HashSet<>(); + private final List locations = new ArrayList<>(); private final EquatableItemStack item; private int amount; @@ -19,8 +16,13 @@ public class NetworkItem { } public void add(NetworkLocation location, ItemStack stack) { - this.locations.add(location); this.amount += stack.getCount(); + if (!this.locations.contains(location)) + this.locations.add(location); + } + + public Collection getLocations() { + return this.locations; } public ItemStack asStack() { diff --git a/src/main/java/de/ellpeck/prettypipes/network/NetworkLocation.java b/src/main/java/de/ellpeck/prettypipes/network/NetworkLocation.java index f446958..77e80a8 100644 --- a/src/main/java/de/ellpeck/prettypipes/network/NetworkLocation.java +++ b/src/main/java/de/ellpeck/prettypipes/network/NetworkLocation.java @@ -9,6 +9,7 @@ import net.minecraftforge.items.IItemHandler; import org.apache.commons.lang3.tuple.Pair; import java.util.*; +import java.util.stream.Collectors; public class NetworkLocation { @@ -31,14 +32,13 @@ public class NetworkLocation { this.items.put(slot, stack); } - public int getStackSlot(ItemStack stack) { + public List getStackSlots(ItemStack stack) { if (this.isEmpty()) - return -1; - for (Map.Entry entry : this.items.entrySet()) { - if (entry.getValue().isItemEqual(stack)) - return entry.getKey(); - } - return -1; + return Collections.emptyList(); + return this.items.entrySet().stream() + .filter(e -> e.getValue().isItemEqual(stack)) + .map(Map.Entry::getKey) + .collect(Collectors.toList()); } public int getItemAmount(ItemStack stack, boolean compareTag) { diff --git a/src/main/java/de/ellpeck/prettypipes/network/PipeItem.java b/src/main/java/de/ellpeck/prettypipes/network/PipeItem.java index 6d10b9f..4a51ad7 100644 --- a/src/main/java/de/ellpeck/prettypipes/network/PipeItem.java +++ b/src/main/java/de/ellpeck/prettypipes/network/PipeItem.java @@ -172,7 +172,7 @@ public class PipeItem implements INBTSerializable, ILiquidContainer private ItemStack store(PipeTileEntity currPipe) { Direction dir = Utility.getDirectionFromOffset(this.destInventory, this.getDestPipe()); - IItemHandler handler = currPipe.getItemHandler(dir); + IItemHandler handler = currPipe.getItemHandler(dir, true); if (handler == null) return this.stack; return ItemHandlerHelper.insertItemStacked(handler, this.stack, false); diff --git a/src/main/java/de/ellpeck/prettypipes/network/PipeNetwork.java b/src/main/java/de/ellpeck/prettypipes/network/PipeNetwork.java index da113f1..d46f482 100644 --- a/src/main/java/de/ellpeck/prettypipes/network/PipeNetwork.java +++ b/src/main/java/de/ellpeck/prettypipes/network/PipeNetwork.java @@ -188,7 +188,7 @@ public class PipeNetwork implements ICapabilitySerializable, GraphL if (!pipe.canNetworkSee()) continue; for (Direction dir : Direction.values()) { - IItemHandler handler = pipe.getItemHandler(dir); + IItemHandler handler = pipe.getItemHandler(dir, false); if (handler == null) continue; // check if this handler already exists (double-connected pipes, double chests etc.) diff --git a/src/main/java/de/ellpeck/prettypipes/packets/PacketHandler.java b/src/main/java/de/ellpeck/prettypipes/packets/PacketHandler.java index 71a059c..a683e34 100644 --- a/src/main/java/de/ellpeck/prettypipes/packets/PacketHandler.java +++ b/src/main/java/de/ellpeck/prettypipes/packets/PacketHandler.java @@ -21,6 +21,7 @@ public final class PacketHandler { network.registerMessage(0, PacketItemEnterPipe.class, PacketItemEnterPipe::toBytes, PacketItemEnterPipe::fromBytes, PacketItemEnterPipe::onMessage); network.registerMessage(1, PacketButton.class, PacketButton::toBytes, PacketButton::fromBytes, PacketButton::onMessage); network.registerMessage(2, PacketNetworkItems.class, PacketNetworkItems::toBytes, PacketNetworkItems::fromBytes, PacketNetworkItems::onMessage); + network.registerMessage(3, PacketRequest.class, PacketRequest::toBytes, PacketRequest::fromBytes, PacketRequest::onMessage); } public static void sendToAllLoaded(World world, BlockPos pos, Object message) { diff --git a/src/main/java/de/ellpeck/prettypipes/packets/PacketNetworkItems.java b/src/main/java/de/ellpeck/prettypipes/packets/PacketNetworkItems.java index ca0502a..db2be74 100644 --- a/src/main/java/de/ellpeck/prettypipes/packets/PacketNetworkItems.java +++ b/src/main/java/de/ellpeck/prettypipes/packets/PacketNetworkItems.java @@ -44,7 +44,9 @@ public class PacketNetworkItems { public static void toBytes(PacketNetworkItems packet, PacketBuffer buf) { buf.writeVarInt(packet.items.size()); for (ItemStack stack : packet.items) { - buf.writeItemStack(stack); + ItemStack copy = stack.copy(); + copy.setCount(1); + buf.writeItemStack(copy); buf.writeVarInt(stack.getCount()); } } diff --git a/src/main/java/de/ellpeck/prettypipes/packets/PacketRequest.java b/src/main/java/de/ellpeck/prettypipes/packets/PacketRequest.java new file mode 100644 index 0000000..36935be --- /dev/null +++ b/src/main/java/de/ellpeck/prettypipes/packets/PacketRequest.java @@ -0,0 +1,56 @@ +package de.ellpeck.prettypipes.packets; + +import de.ellpeck.prettypipes.Utility; +import de.ellpeck.prettypipes.terminal.ItemTerminalTileEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.network.PacketBuffer; +import net.minecraft.util.math.BlockPos; +import net.minecraftforge.fml.network.NetworkEvent; + +import java.util.function.Supplier; + +public class PacketRequest { + + private BlockPos pos; + private ItemStack stack; + private int amount; + + public PacketRequest(BlockPos pos, ItemStack stack, int amount) { + this.pos = pos; + this.stack = stack; + this.amount = amount; + } + + private PacketRequest() { + + } + + public static PacketRequest fromBytes(PacketBuffer buf) { + PacketRequest packet = new PacketRequest(); + packet.pos = buf.readBlockPos(); + packet.stack = buf.readItemStack(); + packet.amount = buf.readVarInt(); + return packet; + } + + public static void toBytes(PacketRequest packet, PacketBuffer buf) { + buf.writeBlockPos(packet.pos); + buf.writeItemStack(packet.stack); + buf.writeVarInt(packet.amount); + } + + @SuppressWarnings("Convert2Lambda") + public static void onMessage(PacketRequest message, Supplier ctx) { + ctx.get().enqueueWork(new Runnable() { + @Override + public void run() { + PlayerEntity player = ctx.get().getSender(); + ItemTerminalTileEntity tile = Utility.getTileEntity(ItemTerminalTileEntity.class, player.world, message.pos); + message.stack.setCount(message.amount); + tile.requestItem(player, message.stack); + } + }); + ctx.get().setPacketHandled(true); + } +} diff --git a/src/main/java/de/ellpeck/prettypipes/pipe/IPipeConnectable.java b/src/main/java/de/ellpeck/prettypipes/pipe/IPipeConnectable.java index 6fdf34d..a1752e4 100644 --- a/src/main/java/de/ellpeck/prettypipes/pipe/IPipeConnectable.java +++ b/src/main/java/de/ellpeck/prettypipes/pipe/IPipeConnectable.java @@ -4,9 +4,13 @@ import net.minecraft.block.BlockState; import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; +import net.minecraftforge.items.IItemHandler; public interface IPipeConnectable { ConnectionType getConnectionType(World world, BlockPos pos, BlockState state, BlockPos pipePos, Direction direction); + default IItemHandler getItemHandler(World world, BlockPos pos, BlockState state, BlockPos pipePos, Direction direction, boolean force) { + return null; + } } diff --git a/src/main/java/de/ellpeck/prettypipes/pipe/PipeBlock.java b/src/main/java/de/ellpeck/prettypipes/pipe/PipeBlock.java index 75c04b0..21d680b 100644 --- a/src/main/java/de/ellpeck/prettypipes/pipe/PipeBlock.java +++ b/src/main/java/de/ellpeck/prettypipes/pipe/PipeBlock.java @@ -72,7 +72,7 @@ public class PipeBlock extends ContainerBlock implements IPipeConnectable { PipeTileEntity tile = Utility.getTileEntity(PipeTileEntity.class, worldIn, pos); if (tile == null) return ActionResultType.PASS; - if (!tile.isConnectedInventory()) + if (!tile.isConnectedInventory(false)) return ActionResultType.PASS; if (!worldIn.isRemote) NetworkHooks.openGui((ServerPlayerEntity) player, tile, pos); @@ -185,7 +185,7 @@ public class PipeBlock extends ContainerBlock implements IPipeConnectable { public static void onStateChanged(World world, BlockPos pos, BlockState newState) { PipeTileEntity tile = Utility.getTileEntity(PipeTileEntity.class, world, pos); - if (tile != null && !tile.isConnectedInventory()) + if (tile != null && !tile.isConnectedInventory(false)) Utility.dropInventory(tile, tile.modules); PipeNetwork network = PipeNetwork.get(world); diff --git a/src/main/java/de/ellpeck/prettypipes/pipe/PipeTileEntity.java b/src/main/java/de/ellpeck/prettypipes/pipe/PipeTileEntity.java index 47e613f..a195dc6 100644 --- a/src/main/java/de/ellpeck/prettypipes/pipe/PipeTileEntity.java +++ b/src/main/java/de/ellpeck/prettypipes/pipe/PipeTileEntity.java @@ -133,13 +133,13 @@ public class PipeTileEntity extends TileEntity implements INamedContainerProvide return this.getBlockState().get(PipeBlock.DIRECTIONS.get(dir)).isConnected(); } - public BlockPos getAvailableDestination(ItemStack stack, boolean internal, boolean preventOversending) { + public BlockPos getAvailableDestination(ItemStack stack, boolean force, boolean preventOversending) { if (!this.canWork()) return null; - if (!internal && this.streamModules().anyMatch(m -> !m.getRight().canAcceptItem(m.getLeft(), this, stack))) + if (!force && this.streamModules().anyMatch(m -> !m.getRight().canAcceptItem(m.getLeft(), this, stack))) return null; for (Direction dir : Direction.values()) { - IItemHandler handler = this.getItemHandler(dir); + IItemHandler handler = this.getItemHandler(dir, force); if (handler == null) continue; if (!ItemHandlerHelper.insertItem(handler, stack, true).isEmpty()) @@ -185,27 +185,37 @@ public class PipeTileEntity extends TileEntity implements INamedContainerProvide return this.streamModules().allMatch(m -> m.getRight().canPipeWork(m.getLeft(), this)); } - public IItemHandler getItemHandler(Direction dir) { + public IItemHandler getItemHandler(Direction dir, boolean force) { if (!this.isConnected(dir)) return null; - TileEntity tile = this.world.getTileEntity(this.pos.offset(dir)); - if (tile == null) - return null; - // if we don't do this, then chests get really weird - if (tile instanceof ChestTileEntity) { - BlockState state = this.world.getBlockState(tile.getPos()); - if (state.getBlock() instanceof ChestBlock) - return new InvWrapper(ChestBlock.func_226916_a_((ChestBlock) state.getBlock(), state, this.world, tile.getPos(), true)); + BlockPos pos = this.pos.offset(dir); + TileEntity tile = this.world.getTileEntity(pos); + if (tile != null) { + // if we don't do this, then chests get really weird + if (tile instanceof ChestTileEntity) { + BlockState state = this.world.getBlockState(tile.getPos()); + if (state.getBlock() instanceof ChestBlock) + return new InvWrapper(ChestBlock.func_226916_a_((ChestBlock) state.getBlock(), state, this.world, tile.getPos(), true)); + } + IItemHandler handler = tile.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, dir.getOpposite()).orElse(null); + if (handler != null) + return handler; } - return tile.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, dir.getOpposite()).orElse(null); + BlockState state = this.world.getBlockState(pos); + if (state.getBlock() instanceof IPipeConnectable) { + IItemHandler handler = ((IPipeConnectable) state.getBlock()).getItemHandler(this.world, pos, state, this.pos, dir, force); + if (handler != null) + return handler; + } + return null; } - public boolean isConnectedInventory(Direction dir) { - return this.getItemHandler(dir) != null; + public boolean isConnectedInventory(Direction dir, boolean force) { + return this.getItemHandler(dir, force) != null; } - public boolean isConnectedInventory() { - return Arrays.stream(Direction.values()).anyMatch(this::isConnectedInventory); + public boolean isConnectedInventory(boolean force) { + return Arrays.stream(Direction.values()).anyMatch(dir -> this.isConnectedInventory(dir, force)); } public boolean canNetworkSee() { diff --git a/src/main/java/de/ellpeck/prettypipes/pipe/modules/extraction/ExtractionModuleItem.java b/src/main/java/de/ellpeck/prettypipes/pipe/modules/extraction/ExtractionModuleItem.java index d77a924..49ef83c 100644 --- a/src/main/java/de/ellpeck/prettypipes/pipe/modules/extraction/ExtractionModuleItem.java +++ b/src/main/java/de/ellpeck/prettypipes/pipe/modules/extraction/ExtractionModuleItem.java @@ -33,13 +33,13 @@ public class ExtractionModuleItem extends ModuleItem { public void tick(ItemStack module, PipeTileEntity tile) { if (tile.getWorld().getGameTime() % this.speed != 0) return; - if(!tile.canWork()) + if (!tile.canWork()) return; ItemFilter filter = new ItemFilter(this.filterSlots, module, tile); PipeNetwork network = PipeNetwork.get(tile.getWorld()); for (Direction dir : Direction.values()) { - IItemHandler handler = tile.getItemHandler(dir); + IItemHandler handler = tile.getItemHandler(dir, false); if (handler == null) continue; for (int j = 0; j < handler.getSlots(); j++) { diff --git a/src/main/java/de/ellpeck/prettypipes/pipe/modules/retrieval/RetrievalModuleItem.java b/src/main/java/de/ellpeck/prettypipes/pipe/modules/retrieval/RetrievalModuleItem.java index 1108381..1b3ef2a 100644 --- a/src/main/java/de/ellpeck/prettypipes/pipe/modules/retrieval/RetrievalModuleItem.java +++ b/src/main/java/de/ellpeck/prettypipes/pipe/modules/retrieval/RetrievalModuleItem.java @@ -58,14 +58,13 @@ public class RetrievalModuleItem extends ModuleItem { for (NetworkLocation location : locations) { if (location.pipePos.equals(tile.getPos())) continue; - int slot = location.getStackSlot(filtered); - if (slot < 0) - continue; - // try to extract from that location's inventory and send the item - ItemStack stack = location.handler.extractItem(slot, this.maxExtraction, true); - if (network.routeItemToLocation(location.pipePos, location.pos, tile.getPos(), dest, speed -> new PipeItem(stack, speed))) { - location.handler.extractItem(slot, stack.getCount(), false); - return; + for (int slot : location.getStackSlots(filtered)) { + // try to extract from that location's inventory and send the item + ItemStack stack = location.handler.extractItem(slot, this.maxExtraction, true); + if (network.routeItemToLocation(location.pipePos, location.pos, tile.getPos(), dest, speed -> new PipeItem(stack, speed))) { + location.handler.extractItem(slot, stack.getCount(), false); + return; + } } } } diff --git a/src/main/java/de/ellpeck/prettypipes/terminal/ItemTerminalBlock.java b/src/main/java/de/ellpeck/prettypipes/terminal/ItemTerminalBlock.java index 79f1650..416c3cf 100644 --- a/src/main/java/de/ellpeck/prettypipes/terminal/ItemTerminalBlock.java +++ b/src/main/java/de/ellpeck/prettypipes/terminal/ItemTerminalBlock.java @@ -20,6 +20,7 @@ import net.minecraft.util.math.BlockRayTraceResult; import net.minecraft.world.IBlockReader; import net.minecraft.world.World; import net.minecraftforge.fml.network.NetworkHooks; +import net.minecraftforge.items.IItemHandler; import javax.annotation.Nullable; @@ -30,8 +31,6 @@ public class ItemTerminalBlock extends ContainerBlock implements IPipeConnectabl @Override public ActionResultType onBlockActivated(BlockState state, World worldIn, BlockPos pos, PlayerEntity player, Hand handIn, BlockRayTraceResult result) { - if (!player.getHeldItem(handIn).isEmpty()) - return ActionResultType.PASS; ItemTerminalTileEntity tile = Utility.getTileEntity(ItemTerminalTileEntity.class, worldIn, pos); if (tile == null) return ActionResultType.PASS; @@ -53,6 +52,16 @@ public class ItemTerminalBlock extends ContainerBlock implements IPipeConnectabl return ConnectionType.CONNECTED; } + @Override + public IItemHandler getItemHandler(World world, BlockPos pos, BlockState state, BlockPos pipePos, Direction direction, boolean force) { + if (force) { + ItemTerminalTileEntity tile = Utility.getTileEntity(ItemTerminalTileEntity.class, world, pos); + if (tile != null) + return tile.items; + } + return null; + } + @Override public BlockRenderType getRenderType(BlockState state) { return BlockRenderType.MODEL; diff --git a/src/main/java/de/ellpeck/prettypipes/terminal/ItemTerminalTileEntity.java b/src/main/java/de/ellpeck/prettypipes/terminal/ItemTerminalTileEntity.java index 5d2a92e..9a3149e 100644 --- a/src/main/java/de/ellpeck/prettypipes/terminal/ItemTerminalTileEntity.java +++ b/src/main/java/de/ellpeck/prettypipes/terminal/ItemTerminalTileEntity.java @@ -6,6 +6,7 @@ import de.ellpeck.prettypipes.Utility; import de.ellpeck.prettypipes.misc.EquatableItemStack; import de.ellpeck.prettypipes.network.NetworkItem; import de.ellpeck.prettypipes.network.NetworkLocation; +import de.ellpeck.prettypipes.network.PipeItem; import de.ellpeck.prettypipes.network.PipeNetwork; import de.ellpeck.prettypipes.packets.PacketHandler; import de.ellpeck.prettypipes.packets.PacketNetworkItems; @@ -24,10 +25,14 @@ import net.minecraft.tileentity.TileEntityType; import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; 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.minecraft.world.server.ServerWorld; import net.minecraftforge.items.ItemStackHandler; import org.apache.commons.lang3.mutable.MutableInt; +import org.apache.commons.lang3.tuple.Pair; +import org.apache.commons.lang3.tuple.Triple; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -39,10 +44,11 @@ public class ItemTerminalTileEntity extends TileEntity implements INamedContaine public final ItemStackHandler items = new ItemStackHandler(12) { @Override public boolean isItemValid(int slot, @Nonnull ItemStack stack) { - return slot >= 6; + return true; } }; - public Collection networkItems; + public Map networkItems; + private Queue> pendingRequests = new ArrayDeque<>(); public ItemTerminalTileEntity() { super(Registry.itemTerminalTileEntity); @@ -67,13 +73,20 @@ public class ItemTerminalTileEntity extends TileEntity implements INamedContaine this.items.extractItem(i, extracted.getCount(), false); break; } + + if (!this.pendingRequests.isEmpty()) { + Triple request = this.pendingRequests.remove(); + NetworkLocation location = request.getLeft(); + int slot = request.getMiddle(); + int amount = request.getRight(); + ItemStack extracted = location.handler.extractItem(slot, amount, true); + if (network.routeItemToLocation(location.pipePos, location.pos, pipe.getPos(), this.pos, speed -> new PipeItem(extracted, speed))) + location.handler.extractItem(slot, extracted.getCount(), false); + } } if (this.world.getGameTime() % 100 == 0) { - PlayerEntity[] lookingPlayers = this.world.getPlayers().stream() - .filter(p -> p.openContainer instanceof ItemTerminalContainer) - .filter(p -> ((ItemTerminalContainer) p.openContainer).tile == this) - .toArray(PlayerEntity[]::new); + PlayerEntity[] lookingPlayers = this.getLookingPlayers(); if (lookingPlayers.length > 0) this.updateItems(lookingPlayers); } @@ -91,18 +104,54 @@ public class ItemTerminalTileEntity extends TileEntity implements INamedContaine public void updateItems(PlayerEntity... playersToSync) { this.networkItems = this.collectItems(); - List clientItems = this.networkItems.stream().map(NetworkItem::asStack).collect(Collectors.toList()); - for (PlayerEntity player : playersToSync) { - if (!(player.openContainer instanceof ItemTerminalContainer)) - continue; - ItemTerminalTileEntity tile = ((ItemTerminalContainer) player.openContainer).tile; - if (tile != this) - continue; - PacketHandler.sendTo(player, new PacketNetworkItems(clientItems)); + if (playersToSync.length > 0) { + List clientItems = this.networkItems.values().stream().map(NetworkItem::asStack).collect(Collectors.toList()); + for (PlayerEntity player : playersToSync) { + if (!(player.openContainer instanceof ItemTerminalContainer)) + continue; + ItemTerminalTileEntity tile = ((ItemTerminalContainer) player.openContainer).tile; + if (tile != this) + continue; + PacketHandler.sendTo(player, new PacketNetworkItems(clientItems)); + } } } - private Collection collectItems() { + public void requestItem(PlayerEntity player, ItemStack stack) { + PipeNetwork network = PipeNetwork.get(this.world); + network.startProfile("terminal_request_item"); + EquatableItemStack equatable = new EquatableItemStack(stack); + NetworkItem item = this.networkItems.get(equatable); + if (item != null) { + int remain = stack.getCount(); + locations: + for (NetworkLocation location : item.getLocations()) { + for (int slot : location.getStackSlots(stack)) { + ItemStack extracted = location.handler.extractItem(slot, remain, true); + if (!extracted.isEmpty()) { + this.pendingRequests.add(Triple.of(location, slot, extracted.getCount())); + remain -= extracted.getCount(); + if (remain <= 0) + break locations; + } + } + } + player.sendMessage(new TranslationTextComponent("info." + PrettyPipes.ID + ".sending", stack.getCount() - remain, stack.getDisplayName()).setStyle(new Style().setColor(TextFormatting.GREEN))); + this.updateItems(player); + } else { + player.sendMessage(new TranslationTextComponent("info." + PrettyPipes.ID + ".not_found", stack.getDisplayName()).setStyle(new Style().setColor(TextFormatting.RED))); + } + network.endProfile(); + } + + private PlayerEntity[] getLookingPlayers() { + return this.world.getPlayers().stream() + .filter(p -> p.openContainer instanceof ItemTerminalContainer) + .filter(p -> ((ItemTerminalContainer) p.openContainer).tile == this) + .toArray(PlayerEntity[]::new); + } + + private Map collectItems() { PipeNetwork network = PipeNetwork.get(this.world); network.startProfile("terminal_collect_items"); PipeTileEntity pipe = this.getConnectedPipe(); @@ -115,7 +164,7 @@ public class ItemTerminalTileEntity extends TileEntity implements INamedContaine } } network.endProfile(); - return items.values(); + return items; } @Override diff --git a/src/main/java/de/ellpeck/prettypipes/terminal/containers/ItemTerminalGui.java b/src/main/java/de/ellpeck/prettypipes/terminal/containers/ItemTerminalGui.java index 4b7d38e..97cf9ea 100644 --- a/src/main/java/de/ellpeck/prettypipes/terminal/containers/ItemTerminalGui.java +++ b/src/main/java/de/ellpeck/prettypipes/terminal/containers/ItemTerminalGui.java @@ -2,17 +2,29 @@ package de.ellpeck.prettypipes.terminal.containers; import de.ellpeck.prettypipes.PrettyPipes; import de.ellpeck.prettypipes.misc.ItemTerminalWidget; +import de.ellpeck.prettypipes.packets.PacketHandler; +import de.ellpeck.prettypipes.packets.PacketRequest; import net.minecraft.client.gui.screen.inventory.ContainerScreen; import net.minecraft.client.gui.widget.Widget; +import net.minecraft.client.gui.widget.button.Button; +import net.minecraft.client.resources.I18n; import net.minecraft.entity.player.PlayerInventory; import net.minecraft.item.ItemStack; import net.minecraft.util.ResourceLocation; import net.minecraft.util.text.ITextComponent; import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; +import java.util.stream.Stream; public class ItemTerminalGui extends ContainerScreen { private static final ResourceLocation TEXTURE = new ResourceLocation(PrettyPipes.ID, "textures/gui/item_terminal.png"); + private List items; + private Button minusButton; + private Button plusButton; + private Button requestButton; + private int requestAmount = 1; public ItemTerminalGui(ItemTerminalContainer screenContainer, PlayerInventory inv, ITextComponent titleIn) { super(screenContainer, inv, titleIn); @@ -20,16 +32,65 @@ public class ItemTerminalGui extends ContainerScreen { this.ySize = 236; } + @Override + protected void init() { + super.init(); + this.plusButton = this.addButton(new Button(this.guiLeft + this.xSize / 2 - 7 + 12, this.guiTop + 103, 12, 12, "+", button -> { + int modifier = requestModifier(); + if (modifier > 1 && this.requestAmount == 1) { + this.requestAmount = modifier; + } else { + this.requestAmount += modifier; + } + if (this.requestAmount > 384) + this.requestAmount = 384; + })); + this.minusButton = this.addButton(new Button(this.guiLeft + this.xSize / 2 - 7 - 24, this.guiTop + 103, 12, 12, "-", button -> { + this.requestAmount -= requestModifier(); + if (this.requestAmount < 1) + this.requestAmount = 1; + })); + this.minusButton.active = false; + this.requestButton = this.addButton(new Button(this.guiLeft + this.xSize / 2 - 7 - 25, this.guiTop + 115, 50, 20, I18n.format("info." + PrettyPipes.ID + ".request"), button -> { + Optional widget = this.streamWidgets().filter(w -> w.selected).findFirst(); + if (!widget.isPresent()) + return; + ItemStack stack = widget.get().stack.copy(); + stack.setCount(1); + PacketHandler.sendToServer(new PacketRequest(this.container.tile.getPos(), stack, this.requestAmount)); + this.requestAmount = 1; + })); + this.requestButton.active = false; + for (int y = 0; y < 4; y++) { + for (int x = 0; x < 9; x++) + this.addButton(new ItemTerminalWidget(this.guiLeft + 8 + x * 18, this.guiTop + 18 + y * 18, x, y, this)); + } + } + + @Override + public void tick() { + super.tick(); + this.requestButton.active = this.streamWidgets().anyMatch(w -> w.selected); + this.plusButton.active = this.requestAmount < 384; + this.minusButton.active = this.requestAmount > 1; + } + public void updateItemList(List items) { - this.buttons.removeIf(w -> w instanceof ItemTerminalWidget); - int x = 0; - int y = 0; - for (ItemStack stack : items) { - this.buttons.add(new ItemTerminalWidget(this.guiLeft + 8 + x * 18, this.guiTop + 18 + y * 18, x, y, stack, this)); - x++; - if (x > 8) { - x = 0; - y++; + this.items = items; + this.updateWidgets(0); + } + + private void updateWidgets(int scrollOffset) { + List widgets = this.streamWidgets().collect(Collectors.toList()); + for (int i = 0; i < widgets.size(); i++) { + ItemTerminalWidget widget = widgets.get(i); + int index = i + scrollOffset * 9; + if (index >= this.items.size()) { + widget.stack = ItemStack.EMPTY; + widget.visible = false; + } else { + widget.stack = this.items.get(index); + widget.visible = true; } } } @@ -49,6 +110,9 @@ public class ItemTerminalGui extends ContainerScreen { protected void drawGuiContainerForegroundLayer(int mouseX, int mouseY) { this.font.drawString(this.playerInventory.getDisplayName().getFormattedText(), 8, this.ySize - 96 + 2, 4210752); this.font.drawString(this.title.getFormattedText(), 8, 6, 4210752); + + String amount = String.valueOf(this.requestAmount); + this.font.drawString(amount, (this.xSize - this.font.getStringWidth(amount)) / 2F - 7, 106, 4210752); } @Override @@ -57,9 +121,19 @@ public class ItemTerminalGui extends ContainerScreen { this.blit(this.guiLeft, this.guiTop, 0, 0, this.xSize, this.ySize); } - // public overload for ItemTerminalWidget - @Override - public void renderTooltip(ItemStack stack, int x, int y) { - super.renderTooltip(stack, x, y); + public Stream streamWidgets() { + return this.buttons.stream() + .filter(w -> w instanceof ItemTerminalWidget) + .map(w -> (ItemTerminalWidget) w); + } + + private static int requestModifier() { + if (hasControlDown()) { + return 10; + } else if (hasShiftDown()) { + return 64; + } else { + return 1; + } } } diff --git a/src/main/resources/assets/prettypipes/lang/en_us.json b/src/main/resources/assets/prettypipes/lang/en_us.json index 5cdb048..f0929bb 100644 --- a/src/main/resources/assets/prettypipes/lang/en_us.json +++ b/src/main/resources/assets/prettypipes/lang/en_us.json @@ -36,6 +36,7 @@ "block.prettypipes.pipe": "Pipe", "itemGroup.prettypipes": "Pretty Pipes", "container.prettypipes.pipe": "Pipe", + "container.prettypipes.item_terminal": "Item Terminal", "info.prettypipes.whitelist": "Allowed", "info.prettypipes.blacklist": "Disallowed", "info.prettypipes.shift": "Hold Shift for info", @@ -43,5 +44,8 @@ "info.prettypipes.populate.description": "Filters items from adjacent inventories", "info.prettypipes.max_stack_size": "Maximum item amount", "info.prettypipes.limit_to_max_on": "Limit to one stack", - "info.prettypipes.limit_to_max_off": "Don't limit to one stack" + "info.prettypipes.limit_to_max_off": "Don't limit to one stack", + "info.prettypipes.request": "Request", + "info.prettypipes.not_found": "%s not found", + "info.prettypipes.sending": "Sending %s %s" } \ No newline at end of file