Files
Applied-Energistics-2-Unoff…/src/main/java/appeng/client/gui/AEBaseGui.java
T

1189 lines
45 KiB
Java

/*
* This file is part of Applied Energistics 2. Copyright (c) 2013 - 2015, AlgorithmX2, All rights reserved. Applied
* Energistics 2 is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
* Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any
* later version. Applied Energistics 2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
* Public License for more details. You should have received a copy of the GNU Lesser General Public License along with
* Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
*/
package appeng.client.gui;
import static appeng.client.gui.implementations.GuiMEMonitorable.keyBindPickBlockAction;
import static appeng.server.ServerHelper.CONTAINER_INTERACTION_KEY;
import java.io.IOException;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.client.renderer.RenderHelper;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.texture.TextureMap;
import net.minecraft.inventory.Container;
import net.minecraft.inventory.Slot;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumChatFormatting;
import net.minecraft.util.IIcon;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.StringUtils;
import net.minecraftforge.client.event.GuiScreenEvent;
import net.minecraftforge.common.MinecraftForge;
import org.jetbrains.annotations.NotNull;
import org.lwjgl.input.Keyboard;
import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL12;
import com.google.common.base.Joiner;
import com.google.common.base.Stopwatch;
import appeng.api.config.TerminalFontSize;
import appeng.api.events.GuiScrollEvent;
import appeng.api.storage.data.IAEFluidStack;
import appeng.api.storage.data.IAEStack;
import appeng.client.gui.slots.VirtualMEPhantomSlot;
import appeng.client.gui.slots.VirtualMESlot;
import appeng.client.gui.widgets.GuiQuantityButton;
import appeng.client.gui.widgets.GuiScrollbar;
import appeng.client.gui.widgets.ITooltip;
import appeng.client.render.AppEngRenderItem;
import appeng.client.render.StackSizeRenderer;
import appeng.client.render.TranslatedRenderItem;
import appeng.container.AEBaseContainer;
import appeng.container.slot.AppEngCraftingSlot;
import appeng.container.slot.AppEngSlot;
import appeng.container.slot.AppEngSlot.hasCalculatedValidness;
import appeng.container.slot.OptionalSlotFake;
import appeng.container.slot.OptionalSlotRestrictedInput;
import appeng.container.slot.SlotCraftingTerm;
import appeng.container.slot.SlotDisabled;
import appeng.container.slot.SlotFake;
import appeng.container.slot.SlotInaccessible;
import appeng.container.slot.SlotOutput;
import appeng.container.slot.SlotPatternTerm;
import appeng.container.slot.SlotRestrictedInput;
import appeng.container.slot.SlotRestrictedInput.PlacableItemType;
import appeng.core.AEConfig;
import appeng.core.AELog;
import appeng.core.AppEng;
import appeng.core.localization.GuiColors;
import appeng.core.localization.GuiText;
import appeng.core.sync.network.NetworkHandler;
import appeng.core.sync.packets.PacketClickOrDragFakeSlot;
import appeng.core.sync.packets.PacketInventoryAction;
import appeng.core.sync.packets.PacketSwapSlots;
import appeng.helpers.ICustomButtonProvider;
import appeng.helpers.InventoryAction;
import appeng.integration.IntegrationRegistry;
import appeng.integration.IntegrationType;
import appeng.integration.modules.NEI;
import appeng.util.Platform;
import codechicken.lib.gui.GuiDraw;
import codechicken.nei.VisiblityData;
import codechicken.nei.api.INEIGuiHandler;
import codechicken.nei.api.TaggedInventoryArea;
import cpw.mods.fml.common.Loader;
import cpw.mods.fml.common.Optional;
@Optional.Interface(modid = "NotEnoughItems", iface = "codechicken.nei.api.INEIGuiHandler")
public abstract class AEBaseGui extends GuiContainer implements IGuiTooltipHandler, INEIGuiHandler {
private static class AEGuiTooltip {
private int shiftX = 0;
private int shiftY = 0;
private int x = 0;
private int y = 0;
public String[] lines = null;
public void set(final int x, final int y, final String message) {
set(x, y, message != null && !message.isEmpty() ? message.split("\n") : null);
}
public void set(final int x, final int y, final String[] lines) {
this.lines = lines;
this.x = this.shiftX + x;
this.y = this.shiftY + y;
}
public void shift(int shiftX, int shiftY) {
this.shiftX = shiftX;
this.shiftY = shiftY;
}
public void draw() {
if (!isEmpty()) {
List<String> list = new ArrayList<>();
list.add(this.lines[0] + GuiDraw.TOOLTIP_LINESPACE);
for (int i = 1; i < this.lines.length; i++) {
list.add(EnumChatFormatting.GRAY + this.lines[i].replace("\u00a0", " "));
}
GuiDraw.drawMultilineTip(this.x + 12, this.y - 12, list);
this.lines = null;
}
}
public boolean isEmpty() {
return this.lines == null || this.lines.length == 0;
}
}
private static boolean switchingGuis;
// drag y
protected final Set<Slot> draggedSlots = new HashSet<>();
public static final AppEngRenderItem aeRenderItem = new AppEngRenderItem();
public static final TranslatedRenderItem translatedRenderItem = new TranslatedRenderItem();
private final AEGuiTooltip currentToolTip = new AEGuiTooltip();
private GuiScrollbar scrollBar = null;
private boolean disableShiftClick = false;
private Stopwatch dbl_clickTimer = Stopwatch.createStarted();
private ItemStack dbl_whichItem;
private Slot bl_clicked;
private boolean subGui;
private final List<VirtualMESlot> virtualSlots = new ArrayList<>();
private final List<VirtualMESlot> draggedVirtualSlots = new ArrayList<>();
private VirtualMESlot hoveredVirtualSlot = null;
private @Nullable ItemStack holdingNEIItem = null;
public AEBaseGui(final Container container) {
super(container);
this.subGui = switchingGuis;
switchingGuis = false;
aeRenderItem.parent = this;
}
protected static String join(final Collection<String> toolTip, final String delimiter) {
final Joiner joiner = Joiner.on(delimiter);
return joiner.join(toolTip);
}
protected int getQty(final GuiButton btn) {
if (btn instanceof GuiQuantityButton quantityButton) {
return quantityButton.getQuantity();
}
try {
final DecimalFormat df = new DecimalFormat("+#;-#");
final String plain = StringUtils.stripControlCodes(btn.displayString);
return df.parse(plain).intValue();
} catch (final ParseException e) {
return 0;
}
}
public boolean isSubGui() {
return this.subGui;
}
@Override
public void initGui() {
super.initGui();
this.virtualSlots.clear();
}
protected void registerVirtualSlots(VirtualMESlot slot) {
virtualSlots.add(slot);
}
@SuppressWarnings("unchecked")
protected List<Slot> getInventorySlots() {
return this.inventorySlots.inventorySlots;
}
@Override
public void drawScreen(final int mouseX, final int mouseY, final float btn) {
super.drawScreen(mouseX, mouseY, btn);
for (final Object c : this.buttonList) {
if (c instanceof ITooltip) {
handleTooltip(mouseX, mouseY, (ITooltip) c);
}
}
this.currentToolTip.draw();
}
protected void handleUpgradeSlotTooltip(final int mouseX, final int mouseY) {}
protected void handleTooltip(int mouseX, int mouseY, ITooltip tooltip) {
final int x = tooltip.xPos();
final int y = tooltip.yPos();
if (tooltip.isVisible() && x < mouseX
&& x + tooltip.getWidth() > mouseX
&& y < mouseY
&& y + tooltip.getHeight() > mouseY) {
drawTooltip(x + 11, Math.max(y, 15) + 4, tooltip.getMessage());
}
}
@Deprecated
public void drawTooltip(final int x, final int y, final int forceWidth, final String message) {
drawTooltip(x, y, message);
}
public void drawTooltip(final int x, final int y, final String message) {
if (message != null && !message.isEmpty()) {
drawTooltip(x, y, message.split("\n"));
}
}
public void drawTooltip(final int x, final int y, final String[] lines) {
if (lines != null && lines.length > 0) {
this.currentToolTip.set(x, y, lines);
}
}
/**
* Utility to add the vertices of a rectangle to an active Tesselator tesselation. The rectangle is defined to be
* between points (x0, y0)..(x1, y1) and have corresponding texture coordinates (u0, v0)..(u1, v1).
*/
public void addTexturedRectToTesselator(float x0, float y0, float x1, float y1, float zLevel, float u0, float v0,
float u1, float v1) {
final Tessellator tessellator = Tessellator.instance;
tessellator.addVertexWithUV(x0, y1, this.zLevel, u0, v1);
tessellator.addVertexWithUV(x1, y1, this.zLevel, u1, v1);
tessellator.addVertexWithUV(x1, y0, this.zLevel, u1, v0);
tessellator.addVertexWithUV(x0, y0, this.zLevel, u0, v0);
}
/**
* Like {@link net.minecraft.client.gui.Gui#drawTexturedModalRect(int, int, int, int, int, int)} but draws the
* texture in 9 patches, stretching the middle patch in X&Y directions. The north, east, west and south patches are
* stretched along one axis, and the corner patches are rendered in 1:1 scale to preserve corner texture quality. A
* 256x256 GUI texture size is assumed like in the vanilla function.
*
* @see <a href="https://developer.android.com/develop/ui/views/graphics/drawables#nine-patch">Android documentation
* for a more detailed description.</a>
* @param x X coordinate of the drawn rectangle of the screen
* @param y Y coordinate of the drawn rectangle of the screen
* @param width Width of the drawn rectangle of the screen
* @param height Height of the drawn rectangle of the screen
* @param textureX X coordinate of the top-left pixel in the texture
* @param textureY Y coordinate of the top-left pixel in the texture
* @param textureW Width of texture fragment to draw
* @param textureH Height of texture fragment to draw
*/
public void drawTextured9PatchRect(int x, int y, int width, int height, int textureX, int textureY, int textureW,
int textureH) {
final float uvScale = 1.0f / 256.0f;
// On-screen thirds (use texture thirds as corner sizes)
// 03 = 0/3, 13 = 1/3, etc.
final float x03 = x;
final float x13 = x + textureW / 3f;
final float x23 = x + width - textureW / 3f;
final float x33 = x + width;
final float y03 = y;
final float y13 = y + textureH / 3f;
final float y23 = y + height - textureH / 3f;
final float y33 = y + height;
// Texture UV thirds (uniformly scaled 3x3 grid)
final float u03 = uvScale * textureX;
final float u13 = uvScale * (textureX + textureW / 3f);
final float u23 = uvScale * (textureX + 2 * textureW / 3f);
final float u33 = uvScale * (textureX + textureW);
final float v03 = uvScale * textureY;
final float v13 = uvScale * (textureY + textureH / 3f);
final float v23 = uvScale * (textureY + 2 * textureH / 3f);
final float v33 = uvScale * (textureY + textureH);
Tessellator tessellator = Tessellator.instance;
tessellator.startDrawingQuads();
// top row
addTexturedRectToTesselator(x03, y03, x13, y13, this.zLevel, u03, v03, u13, v13); // top-left
addTexturedRectToTesselator(x13, y03, x23, y13, this.zLevel, u13, v03, u23, v13); // top-middle
addTexturedRectToTesselator(x23, y03, x33, y13, this.zLevel, u23, v03, u33, v13); // top-right
// middle row
addTexturedRectToTesselator(x03, y13, x13, y23, this.zLevel, u03, v13, u13, v23); // middle-left
addTexturedRectToTesselator(x13, y13, x23, y23, this.zLevel, u13, v13, u23, v23); // middle-middle
addTexturedRectToTesselator(x23, y13, x33, y23, this.zLevel, u23, v13, u33, v23); // middle-right
// bottom row
addTexturedRectToTesselator(x03, y23, x13, y33, this.zLevel, u03, v23, u13, v33); // bottom-left
addTexturedRectToTesselator(x13, y23, x23, y33, this.zLevel, u13, v23, u23, v33); // bottom-middle
addTexturedRectToTesselator(x23, y23, x33, y33, this.zLevel, u23, v23, u33, v33); // bottom-right
tessellator.draw();
}
@Override
protected final void drawGuiContainerForegroundLayer(final int x, final int y) {
final int ox = this.guiLeft;
final int oy = this.guiTop;
GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
if (this.getScrollBar() != null) {
this.getScrollBar().draw(this);
}
this.currentToolTip.shift(ox, oy);
this.drawFG(ox, oy, x, y);
this.currentToolTip.shift(0, 0);
this.hoveredVirtualSlot = null;
this.drawVirtualSlots(this.virtualSlots, x, y);
}
public abstract void drawFG(int offsetX, int offsetY, int mouseX, int mouseY);
@Override
protected final void drawGuiContainerBackgroundLayer(final float f, final int x, final int y) {
final int ox = this.guiLeft;
final int oy = this.guiTop;
GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
this.drawBG(ox, oy, x, y);
final List<Slot> slots = this.getInventorySlots();
for (final Slot slot : slots) {
if (slot instanceof OptionalSlotFake fs) {
if (fs.renderDisabled()) {
if (fs.isEnabled()) {
this.drawTexturedModalRect(
ox + fs.xDisplayPosition - 1,
oy + fs.yDisplayPosition - 1,
fs.getSourceX() - 1,
fs.getSourceY() - 1,
18,
18);
} else {
GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS);
GL11.glColor4f(1.0F, 1.0F, 1.0F, 0.4F);
GL11.glEnable(GL11.GL_BLEND);
this.drawTexturedModalRect(
ox + fs.xDisplayPosition - 1,
oy + fs.yDisplayPosition - 1,
fs.getSourceX() - 1,
fs.getSourceY() - 1,
18,
18);
GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
GL11.glPopAttrib();
}
}
}
}
}
@Override
protected void mouseClicked(final int xCoord, final int yCoord, final int btn) {
this.draggedSlots.clear();
this.draggedVirtualSlots.clear();
this.holdingNEIItem = null;
final VirtualMESlot virtualSlot = getVirtualMESlotUnderMouse();
if (virtualSlot != null && this.handleVirtualSlotClick(
virtualSlot,
btn == this.mc.gameSettings.keyBindPickBlock.getKeyCode() + 100 ? keyBindPickBlockAction : btn))
return;
if (btn == 1) {
for (final GuiButton guibutton : this.buttonList) {
if (guibutton.mousePressed(this.mc, xCoord, yCoord)) {
super.mouseClicked(xCoord, yCoord, 0);
return;
}
}
}
if (this.getScrollBar() != null) {
this.getScrollBar().click(this, xCoord - this.guiLeft, yCoord - this.guiTop);
}
super.mouseClicked(xCoord, yCoord, btn);
}
@Override
protected void keyTyped(char typedChar, int keyCode) {
if (keyCode == this.mc.gameSettings.keyBindPickBlock.getKeyCode()) {
final VirtualMESlot virtualSlot = getVirtualMESlotUnderMouse();
if (virtualSlot != null && this.handleVirtualSlotClick(virtualSlot, keyBindPickBlockAction)) return;
}
if (this.isCloseKey(keyCode)) {
this.flushPendingSync();
}
super.keyTyped(typedChar, keyCode);
}
@Override
public boolean handleDragNDrop(GuiContainer gui, int mouseX, int mouseY, ItemStack draggedStack, int button) {
this.draggedSlots.clear();
this.holdingNEIItem = draggedStack;
return tryClickOrDragSlot(mouseX, mouseY, draggedStack, button);
}
private boolean tryClickOrDragSlot(int mouseX, int mouseY, @Nullable ItemStack itemstack, int mouseButton) {
Slot slot = this.getSlot(mouseX, mouseY);
if (slot != null && this.draggedSlots.add(slot)) {
return handleClickOrDragSlot(slot, itemstack, mouseButton);
}
return false;
}
protected boolean handleClickOrDragSlot(@NotNull Slot slot, @Nullable ItemStack stack, int mouseButton) {
if (slot instanceof SlotFake slotFake) {
handleClickOrDragFakeSlot(slotFake, stack, mouseButton);
return true;
}
return false;
}
private void handleClickOrDragFakeSlot(@NotNull SlotFake slot, @Nullable ItemStack stack, int mouseButton) {
boolean isSingle = mouseButton == 1;
if (isSingle && stack != null) {
stack = stack.copy();
stack.stackSize = 1;
}
NetworkHandler.instance.sendToServer(new PacketClickOrDragFakeSlot(stack, slot.slotNumber, mouseButton != 1));
ItemStack stackInSlot = slot.getStack();
if (isSingle && stackInSlot != null) {
if (stack != null && stackInSlot.isItemEqual(stack)
&& ItemStack.areItemStackTagsEqual(stackInSlot, stack)) {
stack.stackSize = Math.min(stackInSlot.stackSize + stack.stackSize, stack.getMaxStackSize());
} else if (stack == null) {
stackInSlot.stackSize -= 1;
if (stackInSlot.stackSize <= 0) {
slot.putStack(null);
} else {
slot.putStack(stackInSlot);
}
return;
}
}
slot.putStack(stack);
}
protected ItemStack getStackFromHand() {
final ItemStack phantom = IntegrationRegistry.INSTANCE.isEnabled(IntegrationType.NEI)
? NEI.instance.getDraggingPhantomItem()
: null;
return phantom != null ? phantom : this.mc.thePlayer.inventory.getItemStack();
}
protected boolean handleVirtualSlotClick(final VirtualMESlot slot, final int mouseButton) {
if (slot instanceof VirtualMEPhantomSlot vSlot) {
this.handlePhantomSlotInteraction(vSlot, mouseButton);
// Prevent double dragging
if (this.getStackFromHand() != null && !this.draggedVirtualSlots.contains(this.hoveredVirtualSlot)) {
this.draggedVirtualSlots.add(this.hoveredVirtualSlot);
}
}
return false;
}
protected void handleDragVirtualSlot(VirtualMESlot slot, int mouseButton) {
if (slot instanceof VirtualMEPhantomSlot patternSlot) {
this.handlePhantomSlotInteraction(patternSlot, mouseButton);
}
}
private void handlePhantomSlotInteraction(VirtualMEPhantomSlot slot, int mouseButton) {
slot.handleMouseClicked(this.getStackFromHand(), isCtrlKeyDown(), mouseButton);
}
@Override
protected void mouseClickMove(final int x, final int y, final int c, final long d) {
final ItemStack holding = this.holdingNEIItem != null ? this.holdingNEIItem
: this.mc.thePlayer.inventory.getItemStack();
// Hold left or right mouse button
if (c == 0 || c == 1) {
// Update hovered slot
for (VirtualMESlot slot : virtualSlots) {
if (slot.isHovered(x - this.guiLeft + 1, y - this.guiTop + 1)) {
this.hoveredVirtualSlot = slot;
break;
}
}
if (holding != null && this.hoveredVirtualSlot != null
&& !this.draggedVirtualSlots.contains(this.hoveredVirtualSlot)) {
this.draggedVirtualSlots.add(this.hoveredVirtualSlot);
this.handleDragVirtualSlot(this.hoveredVirtualSlot, c);
}
}
if (this.getScrollBar() != null) {
this.getScrollBar().clickMove(y - this.guiTop);
}
final Slot slot = this.getSlot(x, y);
if (slot != null && this.draggedSlots.add(slot)) {
if (handleClickOrDragSlot(slot, holding, c)) {
return;
}
}
super.mouseClickMove(x, y, c, d);
}
@Override
protected void handleMouseClick(final Slot slot, final int slotIdx, final int clickedButton, final int clickType) {
if (clickType == 0 && this.draggedSlots.add(slot)) {
final ItemStack holding = this.holdingNEIItem != null ? this.holdingNEIItem
: this.mc.thePlayer.inventory.getItemStack();
if (this.handleClickOrDragSlot(slot, holding, clickedButton)) {
return;
}
}
if (slot instanceof SlotPatternTerm) {
if (clickType == 6) {
return; // prevent weird double clicks..
}
try {
NetworkHandler.instance.sendToServer(((SlotPatternTerm) slot).getRequest(isShiftKeyDown()));
} catch (final IOException e) {
AELog.debug(e);
}
} else if (slot instanceof SlotCraftingTerm) {
if (clickType == 6) {
return; // prevent weird double clicks..
}
InventoryAction action = null;
if (isShiftKeyDown()) {
action = InventoryAction.CRAFT_SHIFT;
} else {
// Craft stack on right-click, craft single on left-click
action = (clickType == 1) ? InventoryAction.CRAFT_STACK : InventoryAction.CRAFT_ITEM;
}
final PacketInventoryAction p = new PacketInventoryAction(action, slotIdx, 0);
NetworkHandler.instance.sendToServer(p);
return;
}
if (Keyboard.isKeyDown(Keyboard.KEY_SPACE)) {
if (this.enableSpaceClicking() && !(slot instanceof SlotPatternTerm)) {
int slotNum = this.getInventorySlots().size();
if (slot != null) {
slotNum = slot.slotNumber;
}
((AEBaseContainer) this.inventorySlots).setTargetStack(null);
final PacketInventoryAction p = new PacketInventoryAction(InventoryAction.MOVE_REGION, slotNum, 0);
NetworkHandler.instance.sendToServer(p);
return;
}
}
if (!this.disableShiftClick && isShiftKeyDown()) {
this.disableShiftClick = true;
if (this.dbl_whichItem == null || this.bl_clicked != slot
|| this.dbl_clickTimer.elapsed(TimeUnit.MILLISECONDS) > 150) {
// some simple double click logic.
this.bl_clicked = slot;
this.dbl_clickTimer = Stopwatch.createStarted();
if (slot != null) {
this.dbl_whichItem = slot.getHasStack() ? slot.getStack().copy() : null;
} else {
this.dbl_whichItem = null;
}
} else if (this.dbl_whichItem != null) {
// a replica of the weird broken vanilla feature.
final List<Slot> slots = this.getInventorySlots();
for (final Slot inventorySlot : slots) {
if (inventorySlot != null && inventorySlot.canTakeStack(this.mc.thePlayer)
&& inventorySlot.getHasStack()
&& inventorySlot.inventory == slot.inventory
&& Container.func_94527_a(inventorySlot, this.dbl_whichItem, true)) {
this.handleMouseClick(inventorySlot, inventorySlot.slotNumber, clickedButton, 1);
}
}
}
// Handle Virtual Phantom Slot Shift click interaction
if (this.inventorySlots instanceof AEBaseContainer baseContainer) {
if (slot instanceof AppEngSlot appEngSlot && baseContainer.isValidSrcSlotForTransfer(appEngSlot)) {
ItemStack stackInSlot = appEngSlot.getStack();
final List<AppEngSlot> selectedSlots = baseContainer
.getValidDestinationSlots(appEngSlot.isPlayerSide(), stackInSlot);
if (selectedSlots.isEmpty() && appEngSlot.isPlayerSide()
&& this.shouldShiftClickFillVirtualPhantomSlot(slot)
&& baseContainer.getValidDestinationFakeSlot(stackInSlot) == null) {
for (VirtualMESlot vmeSlot : this.virtualSlots) {
if (vmeSlot instanceof VirtualMEPhantomSlot vmepSlot && vmepSlot.getAEStack() == null) {
vmepSlot.handleMouseClicked(stackInSlot, isCtrlKeyDown(), clickType);
break;
}
}
}
}
}
this.disableShiftClick = false;
}
super.handleMouseClick(slot, slotIdx, clickedButton, clickType);
}
protected boolean shouldShiftClickFillVirtualPhantomSlot(final Slot slot) {
return true;
}
@Override
protected boolean checkHotbarKeys(final int keyCode) {
if (this.mc.thePlayer.inventory.getItemStack() == null && theSlot != null) {
for (int j = 0; j < 9; ++j) {
if (keyCode == this.mc.gameSettings.keyBindsHotbar[j].getKeyCode()) {
final List<Slot> slots = this.getInventorySlots();
for (final Slot s : slots) {
if (s.getSlotIndex() == j
&& s.inventory == ((AEBaseContainer) this.inventorySlots).getPlayerInv()) {
if (!s.canTakeStack(((AEBaseContainer) this.inventorySlots).getPlayerInv().player)) {
return false;
}
}
}
if (theSlot.getSlotStackLimit() == 64) {
this.handleMouseClick(theSlot, theSlot.slotNumber, j, 2);
return true;
} else {
for (final Slot s : slots) {
if (s.getSlotIndex() == j
&& s.inventory == ((AEBaseContainer) this.inventorySlots).getPlayerInv()) {
NetworkHandler.instance
.sendToServer(new PacketSwapSlots(s.slotNumber, theSlot.slotNumber));
return true;
}
}
}
}
}
}
return false;
}
@Override
public void onGuiClosed() {
this.flushPendingSync();
super.onGuiClosed();
this.subGui = true; // in case the gui is reopened later ( i'm looking at you NEI )
aeRenderItem.parent = null;
}
@Override
public void updateScreen() {
super.updateScreen();
if (this.inventorySlots instanceof AEBaseContainer container) {
container.tickClientSync();
}
}
protected void closeGui() {
this.flushPendingSync();
this.mc.thePlayer.closeScreen();
}
private void flushPendingSync() {
if (this.inventorySlots instanceof AEBaseContainer container) {
container.getSyncManager().flushClient();
}
}
protected boolean isCloseKey(final int keyCode) {
return keyCode == Keyboard.KEY_ESCAPE || keyCode == this.mc.gameSettings.keyBindInventory.getKeyCode();
}
@Nullable
protected Slot getSlot(final int mouseX, final int mouseY) {
final List<Slot> slots = this.getInventorySlots();
for (final Slot slot : slots) {
// isPointInRegion
if (this.func_146978_c(slot.xDisplayPosition, slot.yDisplayPosition, 16, 16, mouseX, mouseY)) {
return slot;
}
}
return null;
}
public abstract void drawBG(int offsetX, int offsetY, int mouseX, int mouseY);
private static boolean hasLwjgl3 = Loader.isModLoaded("lwjgl3ify");
@Override
public void handleMouseInput() {
super.handleMouseInput();
int wheel = Mouse.getEventDWheel();
if (wheel == 0) {
return;
}
if (!hasLwjgl3) {
// LWJGL2 reports different scroll values for every platform, 120 for one tick on Windows.
// LWJGL3 reports the delta in exact scroll ticks.
// Round away from zero to avoid dropping small scroll events
if (wheel > 0) {
wheel = (int) Platform.ceilDiv(wheel, 120);
} else {
wheel = -(int) Platform.ceilDiv(-wheel, 120);
}
}
final int x = Mouse.getEventX() * this.width / this.mc.displayWidth;
final int y = this.height - Mouse.getEventY() * this.height / this.mc.displayHeight - 1;
if (MinecraftForge.EVENT_BUS.post(new GuiScrollEvent(this, x, y, wheel))) {
return;
}
if (!this.mouseWheelEvent(x, y, wheel)) {
if (this.getScrollBar() != null) {
final GuiScrollbar scrollBar = this.getScrollBar();
if (x > this.guiLeft && y - this.guiTop > scrollBar.getTop()
&& x <= this.guiLeft + this.xSize
&& y - this.guiTop <= scrollBar.getTop() + scrollBar.getHeight()) {
this.getScrollBar().wheel(wheel);
}
}
}
}
/**
* @param x Current mouse X coordinate
* @param y Current mouse Y coordinate
* @param wheel Wheel movement normalized to units of 1
* @return If the event was handled
*/
protected boolean mouseWheelEvent(final int x, final int y, final int wheel) {
return false;
}
protected boolean enableSpaceClicking() {
return true;
}
public void bindTexture(final String base, final String file) {
final ResourceLocation loc = new ResourceLocation(base, "textures/" + file);
this.mc.getTextureManager().bindTexture(loc);
}
public void drawItem(final int x, final int y, final ItemStack is) {
this.zLevel = 100.0F;
itemRender.zLevel = 100.0F;
GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS);
GL11.glEnable(GL11.GL_LIGHTING);
GL11.glEnable(GL12.GL_RESCALE_NORMAL);
GL11.glEnable(GL11.GL_DEPTH_TEST);
GL11.glTranslatef(0.0f, 0.0f, 101.0f);
RenderHelper.enableGUIStandardItemLighting();
itemRender.renderItemAndEffectIntoGUI(this.fontRendererObj, this.mc.renderEngine, is, x, y);
GL11.glTranslatef(0.0f, 0.0f, -101.0f);
GL11.glPopAttrib();
itemRender.zLevel = 0.0F;
this.zLevel = 0.0F;
}
protected String getGuiDisplayName(final String in) {
return this.hasCustomInventoryName() ? this.getInventoryName() : in;
}
private boolean hasCustomInventoryName() {
if (this.inventorySlots instanceof AEBaseContainer) {
return ((AEBaseContainer) this.inventorySlots).getCustomName() != null;
}
return false;
}
private String getInventoryName() {
return ((AEBaseContainer) this.inventorySlots).getCustomName();
}
public void drawTextureOnSlot(Slot s, int icon, float opacity) {
if (icon < 0) return; // no icon to draw.
this.bindTexture("guis/states.png");
GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS);
final Tessellator tessellator = Tessellator.instance;
try {
final int uv_y = (int) Math.floor((double) icon / 16);
final int uv_x = icon - uv_y * 16;
GL11.glEnable(GL11.GL_BLEND);
GL11.glDisable(GL11.GL_LIGHTING);
GL11.glEnable(GL11.GL_TEXTURE_2D);
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
GL11.glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
final float par1 = s.xDisplayPosition;
final float par2 = s.yDisplayPosition;
final float par3 = uv_x * 16;
final float par4 = uv_y * 16;
tessellator.startDrawingQuads();
tessellator.setColorRGBA_F(1.0f, 1.0f, 1.0f, opacity);
final float f1 = 0.00390625F;
final float f = 0.00390625F;
final float par6 = 16;
tessellator.addVertexWithUV(par1 + 0, par2 + par6, this.zLevel, (par3 + 0) * f, (par4 + par6) * f1);
final float par5 = 16;
tessellator.addVertexWithUV(par1 + par5, par2 + par6, this.zLevel, (par3 + par5) * f, (par4 + par6) * f1);
tessellator.addVertexWithUV(par1 + par5, par2 + 0, this.zLevel, (par3 + par5) * f, (par4 + 0) * f1);
tessellator.addVertexWithUV(par1 + 0, par2 + 0, this.zLevel, (par3 + 0) * f, (par4 + 0) * f1);
tessellator.setColorRGBA_F(1.0f, 1.0f, 1.0f, 1.0f);
tessellator.draw();
} catch (final Exception ignored) {}
GL11.glPopAttrib();
}
public void bindTexture(final String file) {
final ResourceLocation loc = new ResourceLocation(AppEng.MOD_ID, "textures/" + file);
this.mc.getTextureManager().bindTexture(loc);
}
public void bindTexture(final ResourceLocation loc) {
mc.getTextureManager().bindTexture(loc);
}
/**
* Draw slot
*/
public void func_146977_a(final Slot s) {
if (s instanceof SlotFake slotFake) {
this.drawSlotWithAEFont(slotFake);
return;
} else if (s instanceof AppEngSlot aeSlot) {
try {
final ItemStack is = s.getStack();
if (aeSlot.getBackgroundIconIndex() != null && is == null) {
IIcon iicon = aeSlot.getBackgroundIconIndex();
GL11.glDisable(GL11.GL_LIGHTING);
GL11.glEnable(GL11.GL_BLEND);
this.mc.getTextureManager().bindTexture(TextureMap.locationItemsTexture);
this.drawTexturedModelRectFromIcon(aeSlot.xDisplayPosition, aeSlot.yDisplayPosition, iicon, 16, 16);
GL11.glDisable(GL11.GL_BLEND);
GL11.glEnable(GL11.GL_LIGHTING);
} else if ((aeSlot.renderIconWithItem() || is == null) && aeSlot.shouldDisplay()) {
this.drawTextureOnSlot(s, aeSlot.getIcon(), aeSlot.getOpacityOfIcon());
}
if (is != null) {
if (aeSlot.getIsValid() == hasCalculatedValidness.NotAvailable) {
boolean isValid = s.isItemValid(is) || s instanceof SlotOutput
|| s instanceof AppEngCraftingSlot
|| s instanceof SlotDisabled
|| s instanceof SlotInaccessible
|| s instanceof SlotRestrictedInput;
if (isValid && s instanceof SlotRestrictedInput) {
try {
isValid = ((SlotRestrictedInput) s).isValid(is, this.mc.theWorld);
} catch (final Exception err) {
AELog.debug(err);
}
}
aeSlot.setIsValid(isValid ? hasCalculatedValidness.Valid : hasCalculatedValidness.Invalid);
}
if (aeSlot.getIsValid() == hasCalculatedValidness.Invalid) {
this.zLevel = 100.0F;
itemRender.zLevel = 100.0F;
GL11.glDisable(GL11.GL_LIGHTING);
drawRect(
s.xDisplayPosition,
s.yDisplayPosition,
16 + s.xDisplayPosition,
16 + s.yDisplayPosition,
GuiColors.ItemSlotOverlayInvalid.getColor());
GL11.glEnable(GL11.GL_LIGHTING);
this.zLevel = 0.0F;
itemRender.zLevel = 0.0F;
}
}
this.drawSlotWithAEFont(aeSlot);
return;
} catch (final Exception err) {
AELog.warn("[AppEng] AE prevented crash while drawing slot: " + err.toString());
}
}
// do the usual for non-ME Slots.
super.func_146977_a(s);
}
private void drawSlotWithAEFont(AppEngSlot aeSlot) {
aeSlot.setDisplay(true);
// Set stack size to 1 to disable standard stack size drawing
final ItemStack stackToDraw = aeSlot.getStack();
long stackSize = 0;
if (stackToDraw != null) {
stackSize = aeSlot instanceof SlotRestrictedInput rSlot ? rSlot.getStackSize() : stackToDraw.stackSize;
stackToDraw.stackSize = 1;
}
// Draw slot
super.func_146977_a(aeSlot);
// Draw stack size
if (stackSize > 1) {
boolean useAEFont = aeSlot instanceof SlotFake || aeSlot instanceof OptionalSlotRestrictedInput
|| (aeSlot instanceof SlotRestrictedInput restrictedInput
&& restrictedInput.getItemType() == PlacableItemType.ENCODED_PATTERN);
TerminalFontSize fontSize = useAEFont ? AEConfig.instance.getTerminalFontSize() : null;
GL11.glTranslatef(0.0f, 0.0f, 300);
GL11.glDisable(GL11.GL_LIGHTING);
GL11.glDisable(GL11.GL_BLEND);
StackSizeRenderer.drawStackSize(
aeSlot.xDisplayPosition,
aeSlot.yDisplayPosition,
StackSizeRenderer.getToBeRenderedStackSize(stackSize, fontSize),
this.mc.fontRenderer,
fontSize);
GL11.glEnable(GL11.GL_LIGHTING);
GL11.glTranslatef(0.0f, 0.0f, -300);
}
// Restore stack size
if (stackToDraw != null) {
stackToDraw.stackSize = (int) Math.min(stackSize, Integer.MAX_VALUE);
}
aeSlot.setDisplay(false);
}
protected GuiScrollbar getScrollBar() {
return this.scrollBar;
}
protected void setScrollBar(final GuiScrollbar myScrollBar) {
this.scrollBar = myScrollBar;
}
public static final synchronized boolean isSwitchingGuis() {
return switchingGuis;
}
public static final synchronized void setSwitchingGuis(final boolean switchingGuis) {
AEBaseGui.switchingGuis = switchingGuis;
}
protected void addItemTooltip(ItemStack is, List<String> lineList) {
if (isShiftKeyDown()) {
List<String> l = is.getTooltip(this.mc.thePlayer, this.mc.gameSettings.advancedItemTooltips);
if (!l.isEmpty()) l.remove(0);
lineList.addAll(l);
} else {
lineList.add(GuiText.HoldShiftForTooltip.getLocal());
}
}
// Accessors for protected GUI methods to make them reusable in widget classes
public FontRenderer getFontRenderer() {
return fontRendererObj;
}
@Override
public void drawHorizontalLine(int startX, int endX, int y, int color) {
super.drawHorizontalLine(startX, endX, y, color);
}
@Override
public void drawVerticalLine(int x, int startY, int endY, int color) {
super.drawVerticalLine(x, startY, endY, color);
}
@Override
public void drawGradientRect(int left, int top, int right, int bottom, int startColor, int endColor) {
super.drawGradientRect(left, top, right, bottom, startColor, endColor);
}
@Override
public void renderToolTip(ItemStack itemIn, int x, int y) {
super.renderToolTip(itemIn, x, y);
}
@Override
public void drawCreativeTabHoveringText(String tabName, int mouseX, int mouseY) {
super.drawCreativeTabHoveringText(tabName, mouseX, mouseY);
}
public void drawHoveringText(List<String> textLines, int x, int y) {
super.func_146283_a(textLines, x, y);
}
@Override
public void drawHoveringText(List<String> textLines, int x, int y, FontRenderer font) {
super.drawHoveringText(textLines, x, y, font);
}
public boolean isMouseOverRect(int left, int top, int right, int bottom, int pointX, int pointY) {
return super.func_146978_c(left, top, right, bottom, pointX, pointY);
}
public int getGuiLeft() {
return guiLeft;
}
public int getGuiTop() {
return guiTop;
}
public int getXSize() {
return xSize;
}
public int getYSize() {
return ySize;
}
public static boolean isCtrlKeyDown() {
int keyCode = CONTAINER_INTERACTION_KEY.getKeyCode();
if (keyCode < 0) {
// In vanilla code, mouse buttons are registered as keyCodes with their values offset by -100.
return Mouse.isButtonDown(keyCode + 100);
} else {
return Keyboard.isKeyDown(keyCode);
}
}
private void drawVirtualSlots(@Nonnull List<VirtualMESlot> slots, int mouseX, int mouseY) {
final int x = mouseX - this.guiLeft + 1;
final int y = mouseY - this.guiTop + 1;
GL11.glPushAttrib(GL11.GL_ENABLE_BIT | GL11.GL_COLOR_BUFFER_BIT | GL11.GL_LIGHTING_BIT);
for (VirtualMESlot slot : slots) {
boolean isHovered = slot.drawStackAndOverlay(this.mc, x, y);
if (isHovered) {
this.hoveredVirtualSlot = slot;
}
}
GL11.glPopAttrib();
}
public @Nullable VirtualMESlot getVirtualMESlotUnderMouse() {
return this.hoveredVirtualSlot;
}
public void initCustomButtons(int xOffset, int yOffset) {
if (inventorySlots instanceof AEBaseContainer abc && abc.getTarget() instanceof ICustomButtonProvider icbp)
icbp.initCustomButtons(
this.guiLeft,
this.guiTop,
this.xSize,
this.ySize,
xOffset,
yOffset,
this.buttonList);
}
public boolean actionPerformedCustomButtons(final GuiButton btn) {
if (inventorySlots instanceof AEBaseContainer abc && abc.getTarget() instanceof ICustomButtonProvider icbp)
return icbp.actionPerformedCustomButtons(btn);
return false;
}
@Override
public List<String> handleItemTooltip(final ItemStack stack, final int mouseX, final int mouseY,
final List<String> currentToolTip) {
VirtualMESlot hoveredSlot = this.getVirtualMESlotUnderMouse();
if (hoveredSlot == null) return currentToolTip;
if (hoveredSlot.getAEStack() instanceof IAEFluidStack afs) {
if (currentToolTip.isEmpty()) {
currentToolTip.add(afs.getDisplayName());
} else {
currentToolTip.set(0, afs.getDisplayName());
}
}
return currentToolTip;
}
@Override
public ItemStack getHoveredStack() {
VirtualMESlot hoveredSlot = this.getVirtualMESlotUnderMouse();
if (hoveredSlot == null) return null;
IAEStack<?> hoveredAEStack = hoveredSlot.getAEStack();
if (hoveredAEStack == null) return null;
return hoveredAEStack.getItemStackForNEI();
}
@Override
public VisiblityData modifyVisiblity(GuiContainer gui, VisiblityData currentVisibility) {
return currentVisibility;
}
@Override
public Iterable<Integer> getItemSpawnSlots(GuiContainer gui, ItemStack item) {
return Collections.emptyList();
}
@Override
public List<TaggedInventoryArea> getInventoryAreas(GuiContainer gui) {
return null;
}
@Override
public boolean hideItemPanelSlot(GuiContainer gui, int x, int y, int w, int h) {
return false;
}
public void triggerActionPerformed(final GuiButton btn) {
GuiScreenEvent.ActionPerformedEvent.Pre event = new GuiScreenEvent.ActionPerformedEvent.Pre(
this,
btn,
this.buttonList);
if (MinecraftForge.EVENT_BUS.post(event)) return;
event.button.func_146113_a(this.mc.getSoundHandler());
this.actionPerformed(event.button);
if (this.equals(this.mc.currentScreen)) MinecraftForge.EVENT_BUS
.post(new GuiScreenEvent.ActionPerformedEvent.Post(this, event.button, this.buttonList));
}
}