don't look at this code, it's truly terrible

This commit is contained in:
Ellpeck 2020-04-16 02:48:58 +02:00
parent f7957bfc0a
commit 3646fc4611
10 changed files with 324 additions and 41 deletions

View file

@ -3,6 +3,7 @@ package de.ellpeck.prettypipes;
import com.mojang.datafixers.types.Func;
import de.ellpeck.prettypipes.blocks.pipe.*;
import de.ellpeck.prettypipes.items.ExtractionModuleItem;
import de.ellpeck.prettypipes.items.IModule;
import de.ellpeck.prettypipes.items.ModuleTier;
import de.ellpeck.prettypipes.items.WrenchItem;
import de.ellpeck.prettypipes.network.PipeNetwork;
@ -91,7 +92,9 @@ public final class Registry {
event.getRegistry().registerAll(
pipeContainer = (ContainerType<PipeContainer>) IForgeContainerType.create((windowId, inv, data) -> {
PipeTileEntity tile = Utility.getTileEntity(PipeTileEntity.class, inv.player.world, data.readBlockPos());
return tile != null ? new PipeContainer(pipeContainer, windowId, inv.player, tile) : null;
int openModule = data.readInt();
IModule module = openModule < 0 ? null : (IModule) tile.modules.getStackInSlot(openModule).getItem();
return tile != null ? new PipeContainer(pipeContainer, windowId, inv.player, tile, module) : null;
}).setRegistryName("pipe")
);
}

View file

@ -70,7 +70,10 @@ public class PipeBlock extends ContainerBlock {
if (!tile.isConnectedInventory())
return ActionResultType.PASS;
if (!worldIn.isRemote)
NetworkHooks.openGui((ServerPlayerEntity) player, tile, pos);
NetworkHooks.openGui((ServerPlayerEntity) player, tile.createContainer(-1), buf -> {
buf.writeBlockPos(pos);
buf.writeInt(-1);
});
return ActionResultType.SUCCESS;
}

View file

@ -7,21 +7,33 @@ import net.minecraft.inventory.container.ContainerType;
import net.minecraft.inventory.container.Slot;
import net.minecraft.item.ItemStack;
import net.minecraftforge.items.SlotItemHandler;
import org.apache.commons.lang3.Range;
import javax.annotation.Nullable;
public class PipeContainer extends Container {
public PipeContainer(@Nullable ContainerType<?> type, int id, PlayerEntity player, PipeTileEntity tile) {
super(type, id);
for (int i = 0; i < 3; i++)
this.addSlot(new SlotItemHandler(tile.modules, i, 62 + i * 18, 17));
public final PipeTileEntity tile;
public final IModule openModule;
public PipeContainer(@Nullable ContainerType<?> type, int id, PlayerEntity player, PipeTileEntity tile, IModule openModule) {
super(type, id);
this.tile = tile;
this.openModule = openModule;
if (openModule == null) {
for (int i = 0; i < 3; i++)
this.addSlot(new SlotItemHandler(tile.modules, i, 62 + i * 18, 17 + 32));
} else {
for (Slot slot : openModule.getContainerSlots(tile, this))
this.addSlot(slot);
}
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, 89 + l * 18));
this.addSlot(new Slot(player.inventory, j1 + l * 9 + 9, 8 + j1 * 18, 89 + l * 18 + 32));
for (int i1 = 0; i1 < 9; ++i1)
this.addSlot(new Slot(player.inventory, i1, 8 + i1 * 18, 147));
this.addSlot(new Slot(player.inventory, i1, 8 + i1 * 18, 147 + 32));
}
@Override
@ -31,8 +43,7 @@ public class PipeContainer extends Container {
@Override
public ItemStack transferStackInSlot(PlayerEntity player, int slotIndex) {
// change this to the amount of slots that we have
int inventoryStart = 3;
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;
@ -42,17 +53,29 @@ public class PipeContainer extends Container {
ItemStack newStack = slot.getStack();
ItemStack currentStack = newStack.copy();
inv:
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;
if (this.openModule == null) {
if (newStack.getItem() instanceof IModule) {
if (!this.mergeItemStack(newStack, 0, 3, false))
return ItemStack.EMPTY;
break inv;
}
} else {
// bleh
Range<Integer> range = this.openModule.getShiftClickSlots(this.tile, this, newStack);
if (range != null) {
if (!this.mergeItemStack(newStack, range.getMinimum(), range.getMaximum(), false))
return ItemStack.EMPTY;
break inv;
}
}
// end custom code
else if (slotIndex >= inventoryStart && slotIndex <= inventoryEnd) {
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)) {
@ -73,5 +96,4 @@ public class PipeContainer extends Container {
}
return ItemStack.EMPTY;
}
}

View file

@ -1,21 +1,43 @@
package de.ellpeck.prettypipes.blocks.pipe;
import com.mojang.blaze3d.platform.GlStateManager;
import com.mojang.blaze3d.systems.RenderSystem;
import de.ellpeck.prettypipes.PrettyPipes;
import de.ellpeck.prettypipes.Registry;
import de.ellpeck.prettypipes.items.IModule;
import de.ellpeck.prettypipes.packets.PacketButton;
import de.ellpeck.prettypipes.packets.PacketHandler;
import net.minecraft.client.audio.SimpleSound;
import net.minecraft.client.gui.AbstractGui;
import net.minecraft.client.gui.screen.inventory.ContainerScreen;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.inventory.container.ClickType;
import net.minecraft.inventory.container.Slot;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.SoundEvents;
import net.minecraft.util.text.ITextComponent;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class PipeGui extends ContainerScreen<PipeContainer> {
private static final ResourceLocation TEXTURE = new ResourceLocation(PrettyPipes.ID, "textures/gui/pipe.png");
private final List<Tab> tabs = new ArrayList<>();
private int lastTabAmount;
public PipeGui(PipeContainer screenContainer, PlayerInventory inv, ITextComponent titleIn) {
super(screenContainer, inv, titleIn);
this.xSize = 176;
this.ySize = 171;
this.ySize = 171 + 32;
}
@Override
protected void init() {
super.init();
this.initTabs();
}
@Override
@ -27,16 +49,110 @@ public class PipeGui extends ContainerScreen<PipeContainer> {
@Override
protected void drawGuiContainerForegroundLayer(int mouseX, int mouseY) {
this.font.drawString(this.title.getFormattedText(), 8, 6, 4210752);
this.font.drawString(this.playerInventory.getDisplayName().getFormattedText(), 8, this.ySize - 96 + 2, 4210752);
this.font.drawString(this.title.getFormattedText(), 8, 6 + 32, 4210752);
if (this.container.openModule != null)
this.container.openModule.drawContainerGuiForeground(this.container.tile, this.container, this, mouseX, mouseY);
for (Tab tab : this.tabs)
tab.drawForeground(mouseX, mouseY);
}
@Override
protected void drawGuiContainerBackgroundLayer(float partialTicks, int mouseX, int mouseY) {
this.getMinecraft().getTextureManager().bindTexture(TEXTURE);
this.blit(this.guiLeft, this.guiTop, 0, 0, 176, 171);
this.blit(this.guiLeft, this.guiTop + 32, 0, 0, 176, 171);
for (int i = 0; i < 3; i++)
this.blit(this.guiLeft + 61 + i * 18, this.guiTop + 16, 176, 62, 18, 18);
for (Tab tab : this.tabs)
tab.draw();
if (this.container.openModule == null) {
for (int i = 0; i < 3; i++)
this.blit(this.guiLeft + 61 + i * 18, this.guiTop + 32 + 16, 176, 62, 18, 18);
} else {
this.container.openModule.drawContainerGuiBackground(this.container.tile, this.container, this, mouseX, mouseY);
}
}
@Override
protected void handleMouseClick(Slot slotIn, int slotId, int mouseButton, ClickType type) {
super.handleMouseClick(slotIn, slotId, mouseButton, type);
// this might cause unnecessary tab initializations, but
// it's a pretty cheap operation so it should be fine
if (slotIn != null)
this.initTabs();
}
@Override
public boolean mouseClicked(double x, double y, int button) {
for (Tab tab : this.tabs) {
if (tab.onClicked(x, y, button))
return true;
}
return super.mouseClicked(x, y, button);
}
private void initTabs() {
this.tabs.clear();
this.tabs.add(new Tab(new ItemStack(Registry.pipeBlock), null, 0, -1));
for (int i = 0; i < this.container.tile.modules.getSlots(); i++) {
ItemStack stack = this.container.tile.modules.getStackInSlot(i);
if (stack.isEmpty())
continue;
IModule module = (IModule) stack.getItem();
if (module.hasContainerTab(this.container.tile, this.container))
this.tabs.add(new Tab(stack, module, this.tabs.size(), i));
}
}
private class Tab {
private final ItemStack moduleStack;
private final IModule module;
private final int index;
private final int x;
private final int y;
public Tab(ItemStack moduleStack, IModule module, int tabIndex, int index) {
this.moduleStack = moduleStack;
this.module = module;
this.index = index;
this.x = PipeGui.this.guiLeft + 5 + tabIndex * 28;
this.y = PipeGui.this.guiTop;
}
private void draw() {
int y = 2;
int v = 0;
int height = 30;
int itemOffset = 9;
if (this.module == PipeGui.this.container.openModule) {
y = 0;
v = 30;
height = 32;
itemOffset = 7;
}
PipeGui.this.blit(this.x, this.y + y, 176, v, 28, height);
PipeGui.this.itemRenderer.renderItemIntoGUI(this.moduleStack, this.x + 6, this.y + itemOffset);
PipeGui.this.getMinecraft().getTextureManager().bindTexture(TEXTURE);
}
private void drawForeground(int mouseX, int mouseY) {
if (mouseX < this.x || mouseY < this.y || mouseX >= this.x + 28 || mouseY >= this.y + 32)
return;
PipeGui.this.renderTooltip(this.moduleStack.getDisplayName().getFormattedText(), mouseX - PipeGui.this.guiLeft, mouseY - PipeGui.this.guiTop);
}
private boolean onClicked(double mouseX, double mouseY, int button) {
if (this.module == PipeGui.this.container.openModule)
return false;
if (button != 0)
return false;
if (mouseX < this.x || mouseY < this.y || mouseX >= this.x + 28 || mouseY >= this.y + 32)
return false;
PacketHandler.sendToServer(new PacketButton(PipeGui.this.container.tile.getPos(), PacketButton.ButtonResult.PIPE_TAB, this.index));
PipeGui.this.getMinecraft().getSoundHandler().play(SimpleSound.master(SoundEvents.UI_BUTTON_CLICK, 1));
return true;
}
}
}

View file

@ -32,12 +32,21 @@ import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;
public class PipeTileEntity extends TileEntity implements INamedContainerProvider, ITickableTileEntity {
public class PipeTileEntity extends TileEntity implements ITickableTileEntity {
public final ItemStackHandler modules = new ItemStackHandler(3) {
@Override
public boolean isItemValid(int slot, @Nonnull ItemStack stack) {
return stack.getItem() instanceof IModule;
Item item = stack.getItem();
if (!(item instanceof IModule))
return false;
IModule module = (IModule) item;
return PipeTileEntity.this.streamModules().allMatch(m -> module.isCompatible(PipeTileEntity.this, m) && m.isCompatible(PipeTileEntity.this, module));
}
@Override
public int getSlotLimit(int slot) {
return 1;
}
};
public final List<PipeItem> items = new ArrayList<>();
@ -46,17 +55,6 @@ public class PipeTileEntity extends TileEntity implements INamedContainerProvide
super(Registry.pipeTileEntity);
}
@Override
public ITextComponent getDisplayName() {
return new TranslationTextComponent("container." + PrettyPipes.ID + ".pipe");
}
@Nullable
@Override
public Container createMenu(int window, PlayerInventory inv, PlayerEntity player) {
return new PipeContainer(Registry.pipeContainer, window, player, this);
}
@Override
public CompoundNBT write(CompoundNBT compound) {
compound.put("modules", this.modules.serializeNBT());
@ -141,16 +139,35 @@ public class PipeTileEntity extends TileEntity implements INamedContainerProvide
return Arrays.stream(Direction.values()).anyMatch(this::isConnectedInventory);
}
private Stream<IModule> streamModules() {
public Stream<IModule> streamModules() {
Stream.Builder<IModule> builder = Stream.builder();
for (int i = 0; i < this.modules.getSlots(); i++) {
ItemStack stack = this.modules.getStackInSlot(i);
if (stack.isEmpty())
continue;
Item item = stack.getItem();
if (item instanceof IModule)
builder.accept((IModule) item);
builder.accept((IModule) stack.getItem());
}
return builder.build();
}
public INamedContainerProvider createContainer(int openModule) {
ItemStack moduleStack = openModule < 0 ? null : this.modules.getStackInSlot(openModule);
return new INamedContainerProvider() {
@Override
public ITextComponent getDisplayName() {
if (moduleStack != null)
return moduleStack.getDisplayName();
return new TranslationTextComponent("container." + PrettyPipes.ID + ".pipe");
}
@Nullable
@Override
public Container createMenu(int window, PlayerInventory inv, PlayerEntity player) {
IModule module = moduleStack == null ? null : (IModule) moduleStack.getItem();
return new PipeContainer(Registry.pipeContainer, window, player, PipeTileEntity.this, module);
}
};
}
}

View file

@ -1,5 +1,6 @@
package de.ellpeck.prettypipes.items;
import de.ellpeck.prettypipes.blocks.pipe.PipeContainer;
import de.ellpeck.prettypipes.blocks.pipe.PipeTileEntity;
import de.ellpeck.prettypipes.network.PipeNetwork;
import net.minecraft.item.ItemStack;
@ -39,4 +40,14 @@ public class ExtractionModuleItem extends ModuleItem {
public boolean canAcceptItem(PipeTileEntity tile, ItemStack stack) {
return false;
}
@Override
public boolean isCompatible(PipeTileEntity tile, IModule other) {
return !(other instanceof ExtractionModuleItem);
}
@Override
public boolean hasContainerTab(PipeTileEntity tile, PipeContainer container) {
return true;
}
}

View file

@ -1,9 +1,18 @@
package de.ellpeck.prettypipes.items;
import de.ellpeck.prettypipes.blocks.pipe.PipeContainer;
import de.ellpeck.prettypipes.blocks.pipe.PipeGui;
import de.ellpeck.prettypipes.blocks.pipe.PipeTileEntity;
import net.minecraft.inventory.container.Slot;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.items.IItemHandler;
import org.apache.commons.lang3.Range;
import java.util.Collections;
import java.util.List;
public interface IModule {
@ -14,4 +23,24 @@ public interface IModule {
boolean isAvailableDestination(PipeTileEntity tile, ItemStack stack, IItemHandler destination);
int getPriority(PipeTileEntity tile);
boolean hasContainerTab(PipeTileEntity tile, PipeContainer container);
boolean isCompatible(PipeTileEntity tile, IModule other);
default List<Slot> getContainerSlots(PipeTileEntity tile, PipeContainer container) {
return Collections.emptyList();
}
default Range<Integer> getShiftClickSlots(PipeTileEntity tile, PipeContainer container, ItemStack newStack) {
return null;
}
@OnlyIn(Dist.CLIENT)
default void drawContainerGuiBackground(PipeTileEntity tile, PipeContainer container, PipeGui gui, int mouseX, int mouseY) {
}
@OnlyIn(Dist.CLIENT)
default void drawContainerGuiForeground(PipeTileEntity tile, PipeContainer container, PipeGui gui, int mouseX, int mouseY) {
}
}

View file

@ -1,12 +1,13 @@
package de.ellpeck.prettypipes.items;
import de.ellpeck.prettypipes.Registry;
import de.ellpeck.prettypipes.blocks.pipe.PipeContainer;
import de.ellpeck.prettypipes.blocks.pipe.PipeTileEntity;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraftforge.items.IItemHandler;
public class ModuleItem extends Item implements IModule {
public abstract class ModuleItem extends Item implements IModule {
public ModuleItem() {
super(new Properties().group(Registry.GROUP).maxStackSize(16));
}
@ -30,4 +31,9 @@ public class ModuleItem extends Item implements IModule {
public int getPriority(PipeTileEntity tile) {
return 0;
}
@Override
public boolean hasContainerTab(PipeTileEntity tile, PipeContainer container) {
return false;
}
}

View file

@ -0,0 +1,75 @@
package de.ellpeck.prettypipes.packets;
import de.ellpeck.prettypipes.Utility;
import de.ellpeck.prettypipes.blocks.pipe.PipeTileEntity;
import de.ellpeck.prettypipes.items.IModule;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.ServerPlayerEntity;
import net.minecraft.network.PacketBuffer;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.math.BlockPos;
import net.minecraftforge.fml.network.NetworkEvent;
import net.minecraftforge.fml.network.NetworkHooks;
import org.apache.logging.log4j.util.TriConsumer;
import java.util.function.BiConsumer;
import java.util.function.Supplier;
public class PacketButton {
private BlockPos pos;
private ButtonResult result;
private int[] data;
public PacketButton(BlockPos pos, ButtonResult result, int... data) {
this.pos = pos;
this.result = result;
this.data = data;
}
private PacketButton() {
}
public static PacketButton fromBytes(PacketBuffer buf) {
PacketButton packet = new PacketButton();
packet.pos = buf.readBlockPos();
packet.result = ButtonResult.values()[buf.readByte()];
packet.data = buf.readVarIntArray();
return packet;
}
public static void toBytes(PacketButton packet, PacketBuffer buf) {
buf.writeBlockPos(packet.pos);
buf.writeByte(packet.result.ordinal());
buf.writeVarIntArray(packet.data);
}
@SuppressWarnings("Convert2Lambda")
public static void onMessage(PacketButton message, Supplier<NetworkEvent.Context> ctx) {
ctx.get().enqueueWork(new Runnable() {
@Override
public void run() {
PlayerEntity player = ctx.get().getSender();
message.result.action.accept(message.pos, message.data, player);
}
});
ctx.get().setPacketHandled(true);
}
public enum ButtonResult {
PIPE_TAB((pos, data, player) -> {
PipeTileEntity tile = Utility.getTileEntity(PipeTileEntity.class, player.world, pos);
NetworkHooks.openGui((ServerPlayerEntity) player, tile.createContainer(data[0]), buf -> {
buf.writeBlockPos(pos);
buf.writeInt(data[0]);
});
});
public final TriConsumer<BlockPos, int[], PlayerEntity> action;
ButtonResult(TriConsumer<BlockPos, int[], PlayerEntity> action) {
this.action = action;
}
}
}

View file

@ -19,6 +19,7 @@ public final class PacketHandler {
public static void setup() {
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);
}
public static void sendToAllLoaded(World world, BlockPos pos, Object message) {
@ -29,7 +30,7 @@ public final class PacketHandler {
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) {
network.send(PacketDistributor.SERVER.noArg(), message);
}
}