Files
TinkersConstruct/src/main/java/tconstruct/tools/gui/CraftingStationGui.java
T
2025-11-23 13:23:06 +08:00

549 lines
19 KiB
Java

package tconstruct.tools.gui;
import java.awt.Rectangle;
import java.util.Collections;
import java.util.List;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.GuiTextField;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.inventory.IInventory;
import net.minecraft.inventory.Slot;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.StatCollector;
import net.minecraft.world.World;
import org.lwjgl.opengl.GL11;
import codechicken.nei.VisiblityData;
import codechicken.nei.api.INEIGuiHandler;
import codechicken.nei.api.TaggedInventoryArea;
import cpw.mods.fml.common.Optional;
import tconstruct.TConstruct;
import tconstruct.library.TConstructRegistry;
import tconstruct.library.crafting.PatternBuilder;
import tconstruct.library.modifier.IModifyable;
import tconstruct.library.tools.ToolMaterial;
import tconstruct.library.util.HarvestLevels;
import tconstruct.tools.logic.CraftingStationLogic;
import tconstruct.util.network.CraftingStationDumpPacket;
@Optional.Interface(iface = "codechicken.nei.api.INEIGuiHandler", modid = "NotEnoughItems")
public class CraftingStationGui extends GuiContainer implements INEIGuiHandler {
/*
* Slider/slots related. Taken & adapted from Tinkers Construct 1.12 under the MIT License
*/
private static final ResourceLocation gui_inventory = new ResourceLocation("tinker", "textures/gui/generic.png");
public static final GuiElementScalable slotElement = new GuiElementScalable(7, 7, 18, 18, 64, 64);
public static final GuiElementScalable slotEmptyElement = new GuiElementScalable(7 + 18, 7, 18, 18, 64, 64);
private static final GuiElementDuex sliderNormal = new GuiElementDuex(7, 25, 10, 15, 64, 64);
private static final GuiElementDuex sliderLow = new GuiElementDuex(17, 25, 10, 15, 64, 64);
private static final GuiElementDuex sliderHigh = new GuiElementDuex(27, 25, 10, 15, 64, 64);
private static final GuiElementDuex sliderTop = new GuiElementDuex(43, 7, 12, 1, 64, 64);
private static final GuiElementDuex sliderBottom = new GuiElementDuex(43, 38, 12, 1, 64, 64);
private static final GuiElementScalable sliderBackground = new GuiElementScalable(43, 8, 12, 30, 64, 64);
private static final GuiElementScalable textBackground = new GuiElementScalable(7 + 18, 7, 18, 10, 64, 64);
private final GuiSliderWidget slider = new GuiSliderWidget(
sliderNormal,
sliderHigh,
sliderLow,
sliderTop,
sliderBottom,
sliderBackground);
private final GuiBorderWidget border = new GuiBorderWidget();
private int firstSlotId;
private int lastSlotId;
private int chestSlotCount;
/* end slider/slots */
private static final ResourceLocation background = new ResourceLocation("tinker", "textures/gui/tinkertable.png");
private static final ResourceLocation description = new ResourceLocation("tinker", "textures/gui/description.png");
private static final ResourceLocation icons = new ResourceLocation("tinker", "textures/gui/icons.png");
public boolean active;
// Panel positions
public String toolName;
public GuiTextField text;
public String title, body;
CraftingStationLogic logic;
private int craftingLeft = 0;
private int craftingTop = 0;
private int craftingTextLeft = 0;
private int descLeft = 0;
private int descTop = 0;
private int descTextLeft = 0;
private int chestLeft = 0;
private int chestTop = 0;
private int chestWidth = 0;
private int chestHeight = 0;
public CraftingStationGui(InventoryPlayer inventory, CraftingStationLogic logic, World world, int x, int y, int z) {
super(logic.getGuiContainer(inventory, world, x, y, z));
this.logic = logic;
title = "\u00A7n" + StatCollector.translateToLocal("gui.toolforge1");
body = StatCollector.translateToLocal("gui.toolforge2");
toolName = "";
}
@Override
public void initGui() {
super.initGui();
this.xSize = 176;
this.ySize = 166;
this.guiLeft = (this.width - this.xSize) / 2;
this.guiTop = (this.height - this.ySize) / 2;
this.craftingLeft = this.guiLeft;
this.craftingTop = this.guiTop;
if (logic.tinkerTable) {
this.descLeft = this.guiLeft + 176;
this.descTop = this.craftingTop;
}
if (logic.chest != null) {
updateChest();
} else {
slider.hide();
}
this.craftingTextLeft = this.craftingLeft - this.guiLeft;
this.descTextLeft = this.descLeft - this.guiLeft;
// Add dump button if chest is connected
this.buttonList.clear();
if (logic.chest != null) {
int bothOffset = 0;
if (logic.slotCount > 54) bothOffset += 12;
bothOffset += 122;
this.buttonList.add(new GuiButtonDump(0, this.guiLeft + bothOffset + 159, this.guiTop + 5));
}
}
@Override
protected void actionPerformed(GuiButton button) {
if (button.id == 0 && logic.chest != null) {
TConstruct.packetPipeline.sendToServer(new CraftingStationDumpPacket());
}
}
@Override
protected void drawGuiContainerForegroundLayer(int par1, int par2) {
if (logic.chest != null) {
if (logic.chest.get() instanceof TileEntity te) {
if (te.getWorldObj().getTileEntity(te.xCoord, te.yCoord, te.zCoord) == null
&& te.getWorldObj().isRemote) {
mc.thePlayer.closeScreen();
return;
}
}
this.fontRendererObj
.drawString(StatCollector.translateToLocal(logic.chest.get().getInventoryName()), 8, 6, 0x202020);
}
this.fontRendererObj.drawString(
StatCollector.translateToLocal(logic.tinkerTable ? "crafters.TinkerTable" : logic.getInvName()),
craftingTextLeft + 8,
6,
0x202020);
this.fontRendererObj
.drawString(StatCollector.translateToLocal("container.inventory"), craftingTextLeft + 8, 72, 0x202020);
if (logic.tinkerTable) {
if (logic.isStackInSlot(0)) // output slot = modified item
drawToolStats(logic.getStackInSlot(0));
else if (logic.isStackInSlot(5)) { // center slot if no output item
// other slots empty?
if (!logic.isStackInSlot(1) && !logic.isStackInSlot(2)
&& !logic.isStackInSlot(3)
&& !logic.isStackInSlot(4)
&& !logic.isStackInSlot(6)
&& !logic.isStackInSlot(7)
&& !logic.isStackInSlot(8)
&& !logic.isStackInSlot(9))
drawToolStats(logic.getStackInSlot(5));
else drawToolInformation();
} else drawToolInformation();
}
}
void drawToolStats(ItemStack stack) {
if (stack.getItem() instanceof IModifyable) ToolStationGuiHelper.drawToolStats(stack, descTextLeft + 10, 0);
int matID = PatternBuilder.instance.getPartID(stack);
if (matID != Short.MAX_VALUE && matID > 0) {
ToolMaterial material = TConstructRegistry.getMaterial(matID);
if (material != null) drawMaterialStats(material);
}
}
void drawToolInformation() {
int offsetX = descTextLeft + 63;
this.drawCenteredString(fontRendererObj, title, offsetX, 8, 0xffffff);
fontRendererObj.drawSplitString(body, offsetX - 56, 24, 115, 0xffffff);
}
protected void drawMaterialStats(ToolMaterial materialEnum) {
final int baseX = descTextLeft + 8;
final int baseY = 8;
String centerTitle = "\u00A7n" + materialEnum.localizedName();
drawCenteredString(this.fontRendererObj, centerTitle, baseX + 55, baseY, 16777215);
this.fontRendererObj.drawString(
StatCollector.translateToLocal("gui.partcrafter4") + materialEnum.durability(),
baseX,
baseY + 16,
16777215);
this.fontRendererObj.drawString(
StatCollector.translateToLocal("gui.partcrafter5") + materialEnum.handleDurability() + "x",
baseX,
baseY + 27,
16777215);
this.fontRendererObj.drawString(
StatCollector.translateToLocal("gui.partcrafter6") + materialEnum.toolSpeed() / 100f,
baseX,
baseY + 38,
16777215);
this.fontRendererObj.drawString(
StatCollector.translateToLocal("gui.partcrafter7")
+ HarvestLevels.getHarvestLevelName(materialEnum.harvestLevel()),
baseX,
baseY + 49,
16777215);
int attack = materialEnum.attack();
String heart = attack == 2 ? StatCollector.translateToLocal("gui.partcrafter8")
: StatCollector.translateToLocal("gui.partcrafter9");
if (attack % 2 == 0) this.fontRendererObj.drawString(
StatCollector.translateToLocal("gui.partcrafter10") + attack / 2 + heart,
baseX,
baseY + 60,
0xffffff);
else this.fontRendererObj.drawString(
StatCollector.translateToLocal("gui.partcrafter10") + attack / 2f + heart,
baseX,
baseY + 60,
0xffffff);
}
@Override
protected void drawGuiContainerBackgroundLayer(float partialTicks, int mouseX, int mouseY) {
// Draw the background
GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
this.mc.getTextureManager().bindTexture(background);
this.drawTexturedModalRect(this.craftingLeft, this.craftingTop, 0, 0, 176, 166);
if (active) {
this.drawTexturedModalRect(this.craftingLeft + 62, this.craftingTop, 0, 166, 112, 22);
}
this.mc.getTextureManager().bindTexture(icons);
// Draw the slots
if (logic.tinkerTable && !logic.isStackInSlot(5))
this.drawTexturedModalRect(this.craftingLeft + 47, this.craftingTop + 33, 0, 233, 18, 18);
GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
this.mc.getTextureManager().bindTexture(gui_inventory);
if (hasChest()) {
chestLeft += border.w;
chestTop += border.h;
border.draw();
int x = chestLeft;
int y = chestTop;
final int midW = chestWidth - border.w * 2;
if (shouldDrawName()) {
textBackground.drawScaledX(chestLeft, chestTop, midW);
y += textBackground.h;
}
drawChestSlots(x, y);
// slider
if (slider.isEnabled()) {
slider.update(mouseX, mouseY, !isMouseOverFullSlot(mouseX, mouseY) && isMouseInChest(mouseX, mouseY));
slider.draw();
updateChestSlots();
}
chestLeft -= border.w;
chestTop -= border.h;
}
// Draw description
if (logic.tinkerTable) {
GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
this.mc.getTextureManager().bindTexture(description);
this.drawTexturedModalRect(this.descLeft, this.descTop, 0, 0, 126, 172);
}
}
@Override
public VisiblityData modifyVisiblity(GuiContainer gui, VisiblityData currentVisibility) {
currentVisibility.showWidgets = width - xSize >= 107;
if (guiLeft < 58) {
currentVisibility.showStateButtons = false;
}
return currentVisibility;
}
@Override
public Iterable<Integer> getItemSpawnSlots(GuiContainer gui, ItemStack item) {
return null;
}
@Override
public List<TaggedInventoryArea> getInventoryAreas(GuiContainer gui) {
return Collections.emptyList();
}
@Override
public boolean handleDragNDrop(GuiContainer gui, int mousex, int mousey, ItemStack draggedStack, int button) {
return false;
}
@Override
public boolean hideItemPanelSlot(GuiContainer gui, int x, int y, int w, int h) {
final int cw = (logic.chest != null ? chestWidth : 0);
if (logic.chest != null) {
final Rectangle blah = new Rectangle(x, y, w, h);
final Rectangle chestRectangle = new Rectangle(
chestLeft,
chestTop,
chestWidth,
chestHeight + (shouldDrawName() ? textBackground.y : 0) + (border.h * 2));
if (chestRectangle.intersects(blah)) return true;
}
if (y + h - 4 < guiTop || y + 4 > guiTop + ySize) return false;
return x - w - 4 >= guiLeft + cw && x + 4 <= guiLeft + xSize + cw + (logic.tinkerTable ? 126 : 0);
}
public boolean hasChest() {
return logic.chest != null;
}
public boolean isMouseInChest(int mouseX, int mouseY) {
final int xMod = (slider.isEnabled() ? slider.width : 0) + border.w;
final int yMod = (shouldDrawName() ? textBackground.y : 0) + (border.h * 2);
return mouseX >= (this.chestLeft - xMod) && mouseX < (chestLeft + chestWidth + xMod)
&& mouseY >= (this.chestTop - yMod)
&& mouseY < (chestTop + chestHeight + yMod);
}
public boolean isMouseOverFullSlot(int mouseX, int mouseY) {
for (final Slot slot : inventorySlots.inventorySlots) {
if (isMouseOverSlot(slot, mouseX, mouseY) && slot.getHasStack()) {
return true;
}
}
return false;
}
protected boolean shouldDrawName() {
return this.logic.chest != null && this.logic.chest.get().getInventoryName() != null
&& !this.logic.chest.get().getInventoryName().isEmpty();
}
@Override
public void func_146977_a /* drawSlot */(Slot slot) {
if (!slot.func_111238_b /* isEnabled */()) return;
super.func_146977_a(slot);
}
public boolean shouldDrawSlot(Slot slot) {
if (!(slot instanceof ChestSlot chestSlot)) return true;
// all visible
if (!slider.isEnabled()) return true;
return firstSlotId <= chestSlot.getVisualIndex() && lastSlotId > chestSlot.getVisualIndex();
}
@Override
public boolean isMouseOverSlot(Slot slotIn, int mouseX, int mouseY) {
return super.isMouseOverSlot(slotIn, mouseX, mouseY) && shouldDrawSlot(slotIn);
}
private int getDisplayedRows() {
return chestHeight / slotElement.h;
}
private int calcCappedYSize(int max) {
int h = slotElement.h * logic.invRows;
// not higher than the max
while (h > max) {
h -= slotElement.h;
}
return h;
}
public int getChestWidth() {
return chestWidth;
}
// updatePosition
public void updateChest() {
chestHeight = calcCappedYSize(CraftingStationGui.slotElement.h * 10);
chestSlotCount = logic.slotCount;
// slider needed?
if (getDisplayedRows() < logic.invRows) {
slider.enable();
} else {
slider.disable();
}
chestWidth = logic.invColumns * CraftingStationGui.slotElement.w + 2 * border.w
+ (slider.isEnabled() ? slider.width : 0);
chestLeft = guiLeft - chestWidth;
chestTop = guiTop;
// Leaving out the xSize increase by chestSize and adjusting where it's used, because otherwise it shifts both
// the bookmarks and item panel
// way too far out. If anything (mouseClick, for example) relies on xSize, you'll need to hack it like below.
// xSize += guiLeft - chestLeft;
guiLeft = chestLeft;
border.setPosition(chestLeft, chestTop);
border.setSize(chestWidth, chestHeight + (shouldDrawName() ? textBackground.h : 0) + 2 * border.h);
slider.show();
slider.setPosition(
chestLeft + logic.invColumns * slotElement.w + border.w,
chestTop + (shouldDrawName() ? textBackground.h : 0) + border.h);
slider.setSize(chestHeight);
slider.setSliderParameters(0, logic.invRows - getDisplayedRows(), 1);
updateChestSlots();
}
@Override
protected void mouseClicked(int x, int y, int button) {
// Hacks
final int height = ySize;
if (logic.chest != null && x >= guiLeft && x <= guiLeft + chestWidth) {
ySize = border.height;
}
xSize += chestWidth;
super.mouseClicked(x, y, button);
xSize -= chestWidth;
ySize = height;
}
@Override
protected void mouseMovedOrUp(int x, int y, int button) {
// Hacks
final int height = ySize;
if (logic.chest != null && x >= guiLeft && x <= guiLeft + chestWidth) {
ySize = border.height;
}
xSize += chestWidth;
super.mouseMovedOrUp(x, y, button);
xSize -= chestWidth;
ySize = height;
}
// updates slot visibility
protected void updateChestSlots() {
if (!hasChest()) return;
final IInventory secondInventory = logic.getSecondInventory();
int xOffset = border.w;
int yOffset = border.h;
if (shouldDrawName()) {
yOffset += textBackground.h;
}
firstSlotId = slider.getValue() * logic.invColumns;
lastSlotId = Math.min(chestSlotCount, firstSlotId + getDisplayedRows() * logic.invColumns);
for (Object o : inventorySlots.inventorySlots) {
if (!(o instanceof ChestSlot slot)) continue;
if (shouldDrawSlot(slot)) {
slot.enable();
// calc position of the slot
final int offset = slot.getVisualIndex() - firstSlotId;
final int x = (offset % logic.invColumns) * CraftingStationGui.slotElement.w;
final int y = (offset / logic.invColumns) * CraftingStationGui.slotElement.h;
slot.xDisplayPosition = x + xOffset + 1 /*- this.chestWidth*/;
slot.yDisplayPosition = y + yOffset + 1;
} else {
slot.disable();
slot.xDisplayPosition = 0;
slot.yDisplayPosition = 0;
}
}
}
// drawSlots
protected void drawChestSlots(int xPos, int yPos) {
if (!hasChest()) return;
int width = logic.invColumns * slotElement.w;
int height = chestHeight - border.h * 2;
int fullRows = (lastSlotId - firstSlotId) / logic.invColumns;
int slotsLeft = (lastSlotId - firstSlotId) % logic.invColumns;
int y; // We use it after the loop
for (y = 0; y < fullRows * slotElement.h && y < height; y += slotElement.h) {
slotElement.drawScaledX(xPos, yPos + y, width);
}
// draw partial row and unused slots
if (slotsLeft > 0) {
slotElement.drawScaledX(xPos, yPos + y, slotsLeft * slotElement.w);
// empty slots that don't exist
slotEmptyElement.drawScaledX(xPos + slotsLeft * slotElement.w, yPos + y, width - slotsLeft * slotElement.w);
}
}
/*
* Hide the deprecated stuff at the bottom
*/
@Deprecated
public static final int CHEST_WIDTH = 116;
}