item terminal, part 1

This commit is contained in:
Ellpeck 2020-05-07 18:30:40 +02:00
parent d4031c19e1
commit ae74359ed5
19 changed files with 641 additions and 63 deletions

View file

@ -23,6 +23,10 @@ import de.ellpeck.prettypipes.pipe.modules.retrieval.RetrievalModuleItem;
import de.ellpeck.prettypipes.pipe.modules.stacksize.StackSizeModuleContainer;
import de.ellpeck.prettypipes.pipe.modules.stacksize.StackSizeModuleGui;
import de.ellpeck.prettypipes.pipe.modules.stacksize.StackSizeModuleItem;
import de.ellpeck.prettypipes.terminal.ItemTerminalBlock;
import de.ellpeck.prettypipes.terminal.ItemTerminalTileEntity;
import de.ellpeck.prettypipes.terminal.containers.ItemTerminalContainer;
import de.ellpeck.prettypipes.terminal.containers.ItemTerminalGui;
import net.minecraft.block.Block;
import net.minecraft.client.gui.ScreenManager;
import net.minecraft.client.renderer.RenderType;
@ -77,10 +81,14 @@ public final class Registry {
public static Block pipeBlock;
public static TileEntityType<PipeTileEntity> pipeTileEntity;
public static ContainerType<MainPipeContainer> pipeContainer;
public static Block itemTerminalBlock;
public static TileEntityType<ItemTerminalTileEntity> itemTerminalTileEntity;
public static ContainerType<ItemTerminalContainer> itemTerminalContainer;
public static EntityType<PipeFrameEntity> pipeFrameEntity;
public static ContainerType<MainPipeContainer> pipeContainer;
public static ContainerType<ExtractionModuleContainer> extractionModuleContainer;
public static ContainerType<FilterModuleContainer> filterModuleContainer;
public static ContainerType<RetrievalModuleContainer> retrievalModuleContainer;
@ -89,7 +97,8 @@ public final class Registry {
@SubscribeEvent
public static void registerBlocks(RegistryEvent.Register<Block> event) {
event.getRegistry().registerAll(
pipeBlock = new PipeBlock().setRegistryName("pipe")
pipeBlock = new PipeBlock().setRegistryName("pipe"),
itemTerminalBlock = new ItemTerminalBlock().setRegistryName("item_terminal")
);
}
@ -118,7 +127,8 @@ public final class Registry {
@SubscribeEvent
public static void registerTiles(RegistryEvent.Register<TileEntityType<?>> event) {
event.getRegistry().registerAll(
pipeTileEntity = (TileEntityType<PipeTileEntity>) TileEntityType.Builder.create(PipeTileEntity::new, pipeBlock).build(null).setRegistryName("pipe")
pipeTileEntity = (TileEntityType<PipeTileEntity>) TileEntityType.Builder.create(PipeTileEntity::new, pipeBlock).build(null).setRegistryName("pipe"),
itemTerminalTileEntity = (TileEntityType<ItemTerminalTileEntity>) TileEntityType.Builder.create(ItemTerminalTileEntity::new, itemTerminalBlock).build(null).setRegistryName("item_terminal")
);
}
@ -132,8 +142,8 @@ public final class Registry {
@SubscribeEvent
public static void registerContainers(RegistryEvent.Register<ContainerType<?>> event) {
event.getRegistry().registerAll(
// this needs to be registered manually since it doesn't send the module slot
pipeContainer = (ContainerType<MainPipeContainer>) IForgeContainerType.create((windowId, inv, data) -> new MainPipeContainer(pipeContainer, windowId, inv.player, data.readBlockPos())).setRegistryName("pipe"),
itemTerminalContainer = (ContainerType<ItemTerminalContainer>) IForgeContainerType.create((windowId, inv, data) -> new ItemTerminalContainer(itemTerminalContainer, windowId, inv.player, data.readBlockPos())).setRegistryName("item_terminal"),
extractionModuleContainer = createPipeContainer("extraction_module"),
filterModuleContainer = createPipeContainer("filter_module"),
retrievalModuleContainer = createPipeContainer("retrieval_module"),
@ -180,6 +190,7 @@ public final class Registry {
RenderingRegistry.registerEntityRenderingHandler(pipeFrameEntity, PipeFrameRenderer::new);
ScreenManager.registerFactory(pipeContainer, MainPipeGui::new);
ScreenManager.registerFactory(itemTerminalContainer, ItemTerminalGui::new);
ScreenManager.registerFactory(extractionModuleContainer, ExtractionModuleGui::new);
ScreenManager.registerFactory(filterModuleContainer, FilterModuleGui::new);
ScreenManager.registerFactory(retrievalModuleContainer, RetrievalModuleGui::new);

View file

@ -1,8 +1,12 @@
package de.ellpeck.prettypipes;
import de.ellpeck.prettypipes.items.IModule;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.resources.I18n;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.inventory.InventoryHelper;
import net.minecraft.inventory.container.Container;
import net.minecraft.inventory.container.Slot;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.Direction;
@ -10,8 +14,11 @@ import net.minecraft.util.math.BlockPos;
import net.minecraft.util.text.*;
import net.minecraft.world.World;
import net.minecraftforge.items.IItemHandler;
import org.apache.commons.lang3.tuple.Pair;
import java.util.List;
import java.util.function.Function;
import java.util.stream.IntStream;
public final class Utility {
@ -43,4 +50,51 @@ public final class Utility {
tooltip.add(new TranslationTextComponent("info." + PrettyPipes.ID + ".shift").setStyle(new Style().setColor(TextFormatting.DARK_GRAY)));
}
}
public static ItemStack transferStackInSlot(Container container, IMergeItemStack merge, PlayerEntity player, int slotIndex, Function<ItemStack, Pair<Integer, Integer>> predicate) {
int inventoryStart = (int) container.inventorySlots.stream().filter(slot -> slot.inventory != player.inventory).count();
int inventoryEnd = inventoryStart + 26;
int hotbarStart = inventoryEnd + 1;
int hotbarEnd = hotbarStart + 8;
Slot slot = container.inventorySlots.get(slotIndex);
if (slot != null && slot.getHasStack()) {
ItemStack newStack = slot.getStack();
ItemStack currentStack = newStack.copy();
if (slotIndex >= inventoryStart) {
// shift into this container here
// mergeItemStack with the slots that newStack should go into
// return an empty stack if mergeItemStack fails
Pair<Integer, Integer> slots = predicate.apply(newStack);
if (slots != null) {
if (!merge.mergeItemStack(newStack, slots.getLeft(), slots.getRight(), false))
return ItemStack.EMPTY;
}
// end custom code
else if (slotIndex >= inventoryStart && slotIndex <= inventoryEnd) {
if (!merge.mergeItemStack(newStack, hotbarStart, hotbarEnd + 1, false))
return ItemStack.EMPTY;
} else if (slotIndex >= inventoryEnd + 1 && slotIndex < hotbarEnd + 1 && !merge.mergeItemStack(newStack, inventoryStart, inventoryEnd + 1, false)) {
return ItemStack.EMPTY;
}
} else if (!merge.mergeItemStack(newStack, inventoryStart, hotbarEnd + 1, false)) {
return ItemStack.EMPTY;
}
if (newStack.isEmpty()) {
slot.putStack(ItemStack.EMPTY);
} else {
slot.onSlotChanged();
}
if (newStack.getCount() == currentStack.getCount())
return ItemStack.EMPTY;
slot.onTake(player, newStack);
return currentStack;
}
return ItemStack.EMPTY;
}
public interface IMergeItemStack {
boolean mergeItemStack(ItemStack stack, int startIndex, int endIndex, boolean reverseDirection);
}
}

View file

@ -68,7 +68,7 @@ public class PipeFrameEntity extends ItemFrameEntity implements IEntityAdditiona
ItemStack stack = this.getDisplayedItem();
if (!stack.isEmpty()) {
List<NetworkLocation> items = network.getOrderedNetworkItems(node);
int amount = items.stream().mapToInt(i -> i.getItemAmount(stack)).sum();
int amount = items.stream().mapToInt(i -> i.getItemAmount(stack, false)).sum();
this.dataManager.set(AMOUNT, amount);
return;
}

View file

@ -0,0 +1,27 @@
package de.ellpeck.prettypipes.misc;
import net.minecraft.item.ItemStack;
import java.util.Objects;
public class EquatableItemStack {
public final ItemStack stack;
public EquatableItemStack(ItemStack stack) {
this.stack = stack;
}
public boolean equals(Object o) {
if (o instanceof EquatableItemStack) {
ItemStack other = ((EquatableItemStack) o).stack;
return ItemStack.areItemsEqual(this.stack, other) && ItemStack.areItemStackTagsEqual(this.stack, other);
}
return false;
}
@Override
public int hashCode() {
return Objects.hash(this.stack.getItem(), this.stack.getTag());
}
}

View file

@ -7,16 +7,16 @@ import net.minecraft.item.ItemStack;
import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.items.SlotItemHandler;
public class SlotFilter extends SlotItemHandler {
public SlotFilter(IItemHandler itemHandler, int index, int xPosition, int yPosition) {
public class FilterSlot extends SlotItemHandler {
public FilterSlot(IItemHandler itemHandler, int index, int xPosition, int yPosition) {
super(itemHandler, index, xPosition, yPosition);
}
public static boolean checkFilter(Container container, int slotId, PlayerEntity player) {
if (slotId >= 0 && slotId < container.inventorySlots.size()) {
Slot slot = container.getSlot(slotId);
if (slot instanceof SlotFilter) {
((SlotFilter) slot).slotClick(player);
if (slot instanceof FilterSlot) {
((FilterSlot) slot).slotClick(player);
return true;
}
}

View file

@ -1,7 +1,6 @@
package de.ellpeck.prettypipes.misc;
import de.ellpeck.prettypipes.PrettyPipes;
import de.ellpeck.prettypipes.items.IModule;
import de.ellpeck.prettypipes.packets.PacketButton;
import de.ellpeck.prettypipes.pipe.PipeTileEntity;
import de.ellpeck.prettypipes.pipe.modules.FilterModifierModule;
@ -25,7 +24,6 @@ import java.util.ArrayList;
import java.util.List;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class ItemFilter extends ItemStackHandler {
@ -47,7 +45,7 @@ public class ItemFilter extends ItemStackHandler {
public List<Slot> getSlots(int x, int y) {
List<Slot> slots = new ArrayList<>();
for (int i = 0; i < this.getSlots(); i++)
slots.add(new SlotFilter(this, i, x + i % 9 * 18, y + i / 9 * 18));
slots.add(new FilterSlot(this, i, x + i % 9 * 18, y + i / 9 * 18));
return slots;
}

View file

@ -0,0 +1,84 @@
package de.ellpeck.prettypipes.misc;
import com.mojang.blaze3d.systems.RenderSystem;
import de.ellpeck.prettypipes.PrettyPipes;
import de.ellpeck.prettypipes.terminal.containers.ItemTerminalGui;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.gui.screen.inventory.ContainerScreen;
import net.minecraft.client.gui.widget.Widget;
import net.minecraft.client.renderer.ItemRenderer;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.text.TextFormatting;
import net.minecraftforge.fml.client.gui.GuiUtils;
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 ItemTerminalWidget(int xIn, int yIn, int gridX, int gridY, ItemStack stack, ItemTerminalGui screen) {
super(xIn, yIn, 16, 16, stack.getDisplayName().getFormattedText());
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);
}
@Override
public void renderButton(int mouseX, int mouseY, float partialTicks) {
Minecraft mc = this.screen.getMinecraft();
ItemRenderer renderer = mc.getItemRenderer();
this.setBlitOffset(100);
renderer.zLevel = 100;
RenderSystem.enableDepthTest();
renderer.renderItemAndEffectIntoGUI(mc.player, this.stack, this.x, this.y);
int amount = this.stack.getCount();
String amountStrg = this.stack.getCount() >= 1000 ? amount / 1000 + "k" : String.valueOf(amount);
FontRenderer font = mc.getFontResourceManager().getFontRenderer(FONT);
renderer.renderItemOverlayIntoGUI(font, this.stack, this.x, this.y, amountStrg);
renderer.zLevel = 0;
this.setBlitOffset(0);
if (this.isHovered()) {
RenderSystem.disableDepthTest();
RenderSystem.colorMask(true, true, true, false);
this.fillGradient(this.x, this.y, this.x + 16, this.y + 16, -2130706433, -2130706433);
RenderSystem.colorMask(true, true, true, true);
RenderSystem.enableDepthTest();
}
}
@Override
public void renderToolTip(int mouseX, int mouseY) {
if (this.isHovered()) {
FontRenderer font = this.stack.getItem().getFontRenderer(this.stack);
if (font == null)
font = this.screen.getMinecraft().fontRenderer;
GuiUtils.preItemToolTip(this.stack);
List<String> tooltip = this.screen.getTooltipFromItem(this.stack);
if (this.stack.getCount() >= 1000)
tooltip.set(0, tooltip.get(0) + TextFormatting.BOLD + " (" + this.stack.getCount() + ')');
this.screen.renderTooltip(tooltip, mouseX, mouseY, font);
GuiUtils.postItemToolTip();
}
}
}

View file

@ -0,0 +1,36 @@
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;
public class NetworkItem {
private final Set<NetworkLocation> locations = new HashSet<>();
private final EquatableItemStack item;
private int amount;
public NetworkItem(EquatableItemStack item) {
this.item = item;
}
public void add(NetworkLocation location, ItemStack stack) {
this.locations.add(location);
this.amount += stack.getCount();
}
public ItemStack asStack() {
ItemStack stack = this.item.stack.copy();
stack.setCount(this.amount);
return stack;
}
@Override
public String toString() {
return "NetworkItem{" + "locations=" + this.locations + ", item=" + this.item + ", amount=" + this.amount + '}';
}
}

View file

@ -8,10 +8,7 @@ import net.minecraft.util.math.BlockPos;
import net.minecraftforge.items.IItemHandler;
import org.apache.commons.lang3.tuple.Pair;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
public class NetworkLocation {
@ -44,12 +41,16 @@ public class NetworkLocation {
return -1;
}
public int getItemAmount(ItemStack stack) {
public int getItemAmount(ItemStack stack, boolean compareTag) {
return this.items.values().stream()
.filter(i -> i.isItemEqual(stack))
.filter(i -> ItemStack.areItemsEqual(i, stack) && (!compareTag || ItemStack.areItemStackTagsEqual(i, stack)))
.mapToInt(ItemStack::getCount).sum();
}
public Collection<ItemStack> getItems() {
return this.items.values();
}
public boolean isEmpty() {
return this.items == null || this.items.isEmpty();
}

View file

@ -353,11 +353,11 @@ public class PipeNetwork implements ICapabilitySerializable<CompoundNBT>, GraphL
public void vertexRemoved(GraphVertexChangeEvent<BlockPos> e) {
}
private void startProfile(String name) {
public void startProfile(String name) {
this.world.getProfiler().startSection(() -> PrettyPipes.ID + ":pipe_network_" + name);
}
private void endProfile() {
public void endProfile() {
this.world.getProfiler().endSection();
}

View file

@ -20,14 +20,15 @@ public final class PacketHandler {
network = NetworkRegistry.newSimpleChannel(new ResourceLocation(PrettyPipes.ID, "network"), () -> VERSION, VERSION::equals, VERSION::equals);
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);
}
public static void sendToAllLoaded(World world, BlockPos pos, Object message) {
network.send(PacketDistributor.TRACKING_CHUNK.with(() -> world.getChunkAt(pos)), message);
}
public static void sendToAllAround(IWorld world, BlockPos pos, int range, Object message) {
network.send(PacketDistributor.NEAR.with(() -> new PacketDistributor.TargetPoint(pos.getX(), pos.getY(), pos.getZ(), range, world.getDimension().getType())), message);
public static void sendTo(PlayerEntity player, Object message) {
network.send(PacketDistributor.PLAYER.with(() -> (ServerPlayerEntity) player), message);
}
public static void sendToServer(Object message) {

View file

@ -0,0 +1,64 @@
package de.ellpeck.prettypipes.packets;
import de.ellpeck.prettypipes.Utility;
import de.ellpeck.prettypipes.network.PipeItem;
import de.ellpeck.prettypipes.pipe.PipeTileEntity;
import de.ellpeck.prettypipes.terminal.containers.ItemTerminalContainer;
import de.ellpeck.prettypipes.terminal.containers.ItemTerminalGui;
import net.minecraft.client.Minecraft;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.inventory.container.Container;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.network.PacketBuffer;
import net.minecraft.util.math.BlockPos;
import net.minecraftforge.fml.network.NetworkEvent;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Supplier;
public class PacketNetworkItems {
private List<ItemStack> items;
public PacketNetworkItems(List<ItemStack> items) {
this.items = items;
}
private PacketNetworkItems() {
}
public static PacketNetworkItems fromBytes(PacketBuffer buf) {
PacketNetworkItems client = new PacketNetworkItems();
client.items = new ArrayList<>();
for (int i = buf.readVarInt(); i > 0; i--) {
ItemStack stack = buf.readItemStack();
stack.setCount(buf.readVarInt());
client.items.add(stack);
}
return client;
}
public static void toBytes(PacketNetworkItems packet, PacketBuffer buf) {
buf.writeVarInt(packet.items.size());
for (ItemStack stack : packet.items) {
buf.writeItemStack(stack);
buf.writeVarInt(stack.getCount());
}
}
@SuppressWarnings("Convert2Lambda")
public static void onMessage(PacketNetworkItems message, Supplier<NetworkEvent.Context> ctx) {
ctx.get().enqueueWork(new Runnable() {
@Override
public void run() {
Minecraft mc = Minecraft.getInstance();
if (mc.currentScreen instanceof ItemTerminalGui)
((ItemTerminalGui) mc.currentScreen).updateItemList(message.items);
}
});
ctx.get().setPacketHandled(true);
}
}

View file

@ -2,7 +2,7 @@ package de.ellpeck.prettypipes.pipe.containers;
import de.ellpeck.prettypipes.Utility;
import de.ellpeck.prettypipes.items.IModule;
import de.ellpeck.prettypipes.misc.SlotFilter;
import de.ellpeck.prettypipes.misc.FilterSlot;
import de.ellpeck.prettypipes.pipe.PipeTileEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.inventory.container.ClickType;
@ -11,6 +11,7 @@ import net.minecraft.inventory.container.ContainerType;
import net.minecraft.inventory.container.Slot;
import net.minecraft.item.ItemStack;
import net.minecraft.util.math.BlockPos;
import org.apache.commons.lang3.tuple.Pair;
import javax.annotation.Nullable;
@ -45,50 +46,16 @@ public abstract class AbstractPipeContainer<T extends IModule> extends Container
@Override
public ItemStack transferStackInSlot(PlayerEntity player, int slotIndex) {
int inventoryStart = (int) this.inventorySlots.stream().filter(slot -> slot.inventory != player.inventory).count();
int inventoryEnd = inventoryStart + 26;
int hotbarStart = inventoryEnd + 1;
int hotbarEnd = hotbarStart + 8;
Slot slot = this.inventorySlots.get(slotIndex);
if (slot != null && slot.getHasStack()) {
ItemStack newStack = slot.getStack();
ItemStack currentStack = newStack.copy();
if (slotIndex >= inventoryStart) {
// shift into this container here
// mergeItemStack with the slots that newStack should go into
// return an empty stack if mergeItemStack fails
if (newStack.getItem() instanceof IModule) {
if (!this.mergeItemStack(newStack, 0, 3, false))
return ItemStack.EMPTY;
}
// end custom code
else if (slotIndex >= inventoryStart && slotIndex <= inventoryEnd) {
if (!this.mergeItemStack(newStack, hotbarStart, hotbarEnd + 1, false))
return ItemStack.EMPTY;
} else if (slotIndex >= inventoryEnd + 1 && slotIndex < hotbarEnd + 1 && !this.mergeItemStack(newStack, inventoryStart, inventoryEnd + 1, false)) {
return ItemStack.EMPTY;
}
} else if (!this.mergeItemStack(newStack, inventoryStart, hotbarEnd + 1, false)) {
return ItemStack.EMPTY;
}
if (newStack.isEmpty()) {
slot.putStack(ItemStack.EMPTY);
} else {
slot.onSlotChanged();
}
if (newStack.getCount() == currentStack.getCount())
return ItemStack.EMPTY;
slot.onTake(player, newStack);
return currentStack;
}
return ItemStack.EMPTY;
return Utility.transferStackInSlot(this, this::mergeItemStack, player, slotIndex, stack -> {
if (stack.getItem() instanceof IModule)
return Pair.of(0, 3);
return null;
});
}
@Override
public ItemStack slotClick(int slotId, int dragType, ClickType clickTypeIn, PlayerEntity player) {
if (SlotFilter.checkFilter(this, slotId, player))
if (FilterSlot.checkFilter(this, slotId, player))
return ItemStack.EMPTY;
return super.slotClick(slotId, dragType, clickTypeIn, player);
}

View file

@ -0,0 +1,60 @@
package de.ellpeck.prettypipes.terminal;
import de.ellpeck.prettypipes.Utility;
import de.ellpeck.prettypipes.pipe.ConnectionType;
import de.ellpeck.prettypipes.pipe.IPipeConnectable;
import de.ellpeck.prettypipes.pipe.PipeTileEntity;
import net.minecraft.block.BlockRenderType;
import net.minecraft.block.BlockState;
import net.minecraft.block.ContainerBlock;
import net.minecraft.block.SoundType;
import net.minecraft.block.material.Material;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.ServerPlayerEntity;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.ActionResultType;
import net.minecraft.util.Direction;
import net.minecraft.util.Hand;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.BlockRayTraceResult;
import net.minecraft.world.IBlockReader;
import net.minecraft.world.World;
import net.minecraftforge.fml.network.NetworkHooks;
import javax.annotation.Nullable;
public class ItemTerminalBlock extends ContainerBlock implements IPipeConnectable {
public ItemTerminalBlock() {
super(Properties.create(Material.ROCK).hardnessAndResistance(3).sound(SoundType.STONE));
}
@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;
if (!worldIn.isRemote) {
NetworkHooks.openGui((ServerPlayerEntity) player, tile, pos);
tile.updateItems(player);
}
return ActionResultType.SUCCESS;
}
@Nullable
@Override
public TileEntity createNewTileEntity(IBlockReader worldIn) {
return new ItemTerminalTileEntity();
}
@Override
public ConnectionType getConnectionType(World world, BlockPos pos, BlockState state, BlockPos pipePos, Direction direction) {
return ConnectionType.CONNECTED;
}
@Override
public BlockRenderType getRenderType(BlockState state) {
return BlockRenderType.MODEL;
}
}

View file

@ -0,0 +1,143 @@
package de.ellpeck.prettypipes.terminal;
import de.ellpeck.prettypipes.PrettyPipes;
import de.ellpeck.prettypipes.Registry;
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.PipeNetwork;
import de.ellpeck.prettypipes.packets.PacketHandler;
import de.ellpeck.prettypipes.packets.PacketNetworkItems;
import de.ellpeck.prettypipes.pipe.PipeTileEntity;
import de.ellpeck.prettypipes.terminal.containers.ItemTerminalContainer;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.entity.player.ServerPlayerEntity;
import net.minecraft.inventory.container.Container;
import net.minecraft.inventory.container.INamedContainerProvider;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.tileentity.ITickableTileEntity;
import net.minecraft.tileentity.TileEntity;
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.TranslationTextComponent;
import net.minecraft.world.server.ServerWorld;
import net.minecraftforge.items.ItemStackHandler;
import org.apache.commons.lang3.mutable.MutableInt;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.*;
import java.util.stream.Collectors;
public class ItemTerminalTileEntity extends TileEntity implements INamedContainerProvider, ITickableTileEntity {
public final ItemStackHandler items = new ItemStackHandler(12) {
@Override
public boolean isItemValid(int slot, @Nonnull ItemStack stack) {
return slot >= 6;
}
};
public Collection<NetworkItem> networkItems;
public ItemTerminalTileEntity() {
super(Registry.itemTerminalTileEntity);
}
@Override
public void tick() {
if (this.world.isRemote)
return;
PipeNetwork network = PipeNetwork.get(this.world);
PipeTileEntity pipe = this.getConnectedPipe();
if (pipe == null)
return;
if (this.world.getGameTime() % 10 == 0) {
for (int i = 6; i < 12; i++) {
ItemStack extracted = this.items.extractItem(i, Integer.MAX_VALUE, true);
if (extracted.isEmpty())
continue;
if (!network.tryInsertItem(pipe.getPos(), this.pos, extracted, true))
continue;
this.items.extractItem(i, extracted.getCount(), false);
break;
}
}
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);
if (lookingPlayers.length > 0)
this.updateItems(lookingPlayers);
}
}
private PipeTileEntity getConnectedPipe() {
PipeNetwork network = PipeNetwork.get(this.world);
for (Direction dir : Direction.values()) {
PipeTileEntity pipe = network.getPipe(this.pos.offset(dir));
if (pipe != null)
return pipe;
}
return null;
}
public void updateItems(PlayerEntity... playersToSync) {
this.networkItems = this.collectItems();
List<ItemStack> 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));
}
}
private Collection<NetworkItem> collectItems() {
PipeNetwork network = PipeNetwork.get(this.world);
network.startProfile("terminal_collect_items");
PipeTileEntity pipe = this.getConnectedPipe();
Map<EquatableItemStack, NetworkItem> items = new HashMap<>();
for (NetworkLocation location : network.getOrderedNetworkItems(pipe.getPos())) {
for (ItemStack stack : location.getItems()) {
EquatableItemStack equatable = new EquatableItemStack(stack);
NetworkItem item = items.computeIfAbsent(equatable, NetworkItem::new);
item.add(location, stack);
}
}
network.endProfile();
return items.values();
}
@Override
public CompoundNBT write(CompoundNBT compound) {
compound.put("items", this.items.serializeNBT());
return super.write(compound);
}
@Override
public void read(CompoundNBT compound) {
this.items.deserializeNBT(compound.getCompound("items"));
super.read(compound);
}
@Override
public ITextComponent getDisplayName() {
return new TranslationTextComponent("container." + PrettyPipes.ID + ".item_terminal");
}
@Nullable
@Override
public Container createMenu(int window, PlayerInventory inv, PlayerEntity player) {
return new ItemTerminalContainer(Registry.itemTerminalContainer, window, player, this.pos);
}
}

View file

@ -0,0 +1,57 @@
package de.ellpeck.prettypipes.terminal.containers;
import de.ellpeck.prettypipes.Utility;
import de.ellpeck.prettypipes.network.NetworkItem;
import de.ellpeck.prettypipes.packets.PacketHandler;
import de.ellpeck.prettypipes.packets.PacketNetworkItems;
import de.ellpeck.prettypipes.pipe.PipeTileEntity;
import de.ellpeck.prettypipes.terminal.ItemTerminalTileEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.ServerPlayerEntity;
import net.minecraft.inventory.container.ClickType;
import net.minecraft.inventory.container.Container;
import net.minecraft.inventory.container.ContainerType;
import net.minecraft.inventory.container.Slot;
import net.minecraft.item.ItemStack;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.server.ServerWorld;
import net.minecraftforge.items.SlotItemHandler;
import org.apache.commons.lang3.tuple.Pair;
import javax.annotation.Nullable;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
public class ItemTerminalContainer extends Container {
public final ItemTerminalTileEntity tile;
public ItemTerminalContainer(@Nullable ContainerType<?> type, int id, PlayerEntity player, BlockPos pos) {
super(type, id);
this.tile = Utility.getTileEntity(ItemTerminalTileEntity.class, player.world, pos);
for (int i = 0; i < 6; i++)
this.addSlot(new SlotItemHandler(this.tile.items, i, 8 + i % 3 * 18, 102 + i / 3 * 18));
for (int i = 0; i < 6; i++)
this.addSlot(new SlotItemHandler(this.tile.items, i + 6, 116 + i % 3 * 18, 102 + i / 3 * 18));
for (int l = 0; l < 3; ++l)
for (int j1 = 0; j1 < 9; ++j1)
this.addSlot(new Slot(player.inventory, j1 + l * 9 + 9, 8 + j1 * 18, 154 + l * 18));
for (int i1 = 0; i1 < 9; ++i1)
this.addSlot(new Slot(player.inventory, i1, 8 + i1 * 18, 212));
}
@Override
public ItemStack transferStackInSlot(PlayerEntity player, int slotIndex) {
return Utility.transferStackInSlot(this, this::mergeItemStack, player, slotIndex, stack -> {
return Pair.of(6, 12);
});
}
@Override
public boolean canInteractWith(PlayerEntity playerIn) {
return true;
}
}

View file

@ -0,0 +1,65 @@
package de.ellpeck.prettypipes.terminal.containers;
import de.ellpeck.prettypipes.PrettyPipes;
import de.ellpeck.prettypipes.misc.ItemTerminalWidget;
import net.minecraft.client.gui.screen.inventory.ContainerScreen;
import net.minecraft.client.gui.widget.Widget;
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;
public class ItemTerminalGui extends ContainerScreen<ItemTerminalContainer> {
private static final ResourceLocation TEXTURE = new ResourceLocation(PrettyPipes.ID, "textures/gui/item_terminal.png");
public ItemTerminalGui(ItemTerminalContainer screenContainer, PlayerInventory inv, ITextComponent titleIn) {
super(screenContainer, inv, titleIn);
this.xSize = 176 + 15;
this.ySize = 236;
}
public void updateItemList(List<ItemStack> 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++;
}
}
}
@Override
public void render(int mouseX, int mouseY, float partialTicks) {
this.renderBackground();
super.render(mouseX, mouseY, partialTicks);
for (Widget widget : this.buttons) {
if (widget instanceof ItemTerminalWidget)
widget.renderToolTip(mouseX, mouseY);
}
this.renderHoveredToolTip(mouseX, mouseY);
}
@Override
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);
}
@Override
protected void drawGuiContainerBackgroundLayer(float partialTicks, int mouseX, int mouseY) {
this.getMinecraft().getTextureManager().bindTexture(TEXTURE);
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);
}
}

View file

@ -0,0 +1,10 @@
{
"_comment": "Unicode fonts only",
"providers": [
{
"type": "legacy_unicode",
"sizes": "minecraft:font/glyph_sizes.bin",
"template": "minecraft:font/unicode_page_%s.png"
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB