diff options
Diffstat (limited to 'src/main/java/gregtech/api/gui')
48 files changed, 5736 insertions, 0 deletions
diff --git a/src/main/java/gregtech/api/gui/GT_Container.java b/src/main/java/gregtech/api/gui/GT_Container.java new file mode 100644 index 0000000000..851e1f6461 --- /dev/null +++ b/src/main/java/gregtech/api/gui/GT_Container.java @@ -0,0 +1,740 @@ +package gregtech.api.gui; + +import java.util.List; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.inventory.Container; +import net.minecraft.inventory.ICrafting; +import net.minecraft.inventory.IInventory; +import net.minecraft.inventory.Slot; +import net.minecraft.item.ItemStack; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.IFluidContainerItem; + +import gregtech.api.interfaces.IFluidAccess; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.util.GT_Log; +import gregtech.api.util.GT_Utility; + +/** + * The main Container class. It is used for all GregTech GUIs. + * <p> + * Never include this file in your mod - it will break your modpack. + */ +public class GT_Container extends Container { + + public IGregTechTileEntity mTileEntity; + public InventoryPlayer mPlayerInventory; + + public GT_Container(InventoryPlayer aPlayerInventory, IGregTechTileEntity aTileEntityInventory) { + + mTileEntity = aTileEntityInventory; + mPlayerInventory = aPlayerInventory; + mTileEntity.openInventory(); + } + + /** + * To add the Slots to your GUI + */ + public void addSlots(InventoryPlayer aPlayerInventory) { + // + } + + /** + * Amount of regular Slots in the GUI (so, non-HoloSlots) + */ + public int getSlotCount() { + return 0; + } + + /** + * Amount of ALL Slots in the GUI including HoloSlots and ArmorSlots, but excluding regular Player Slots + */ + protected final int getAllSlotCount() { + if (inventorySlots != null) { + if (doesBindPlayerInventory()) return inventorySlots.size() - 36; + return inventorySlots.size(); + } + return getSlotCount(); + } + + /** + * Start-Index of the usable Slots (the first non-HoloSlot) + */ + public int getSlotStartIndex() { + return 0; + } + + public int getShiftClickStartIndex() { + return getSlotStartIndex(); + } + + /** + * Amount of Slots in the GUI the player can Shift-Click into. Uses also getSlotStartIndex + */ + public int getShiftClickSlotCount() { + return 0; + } + + /** + * Is Player-Inventory visible? + */ + public boolean doesBindPlayerInventory() { + return true; + } + + /** + * Override this Function with something like "return mTileEntity.isUseableByPlayer(aPlayer);" + */ + @Override + public boolean canInteractWith(EntityPlayer aPlayer) { + return false; + } + + protected void bindPlayerInventory(InventoryPlayer aInventoryPlayer) { + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 9; j++) { + addSlotToContainer(new Slot(aInventoryPlayer, j + i * 9 + 9, 8 + j * 18, 84 + i * 18)); + } + } + + for (int i = 0; i < 9; i++) { + addSlotToContainer(new Slot(aInventoryPlayer, i, 8 + i * 18, 142)); + } + } + + @Override + public ItemStack slotClick(int aSlotIndex, int aMouseclick, int aShifthold, EntityPlayer aPlayer) { + mTileEntity.markDirty(); + + if (aSlotIndex >= 0) { + if (inventorySlots.get(aSlotIndex) == null || inventorySlots.get(aSlotIndex) instanceof GT_Slot_Holo) + return null; + if (!(inventorySlots.get(aSlotIndex) instanceof GT_Slot_Armor)) if (aSlotIndex < getAllSlotCount()) + if (aSlotIndex < getSlotStartIndex() || aSlotIndex >= getSlotStartIndex() + getSlotCount()) return null; + } + + try { + return super.slotClick(aSlotIndex, aMouseclick, aShifthold, aPlayer); + } catch (Throwable e) { + e.printStackTrace(GT_Log.err); + } + + // It looks like the rest of this code should ideally never be + // called, and might in fact never be called. + + ItemStack rStack = null; + InventoryPlayer aPlayerInventory = aPlayer.inventory; + Slot aSlot; + ItemStack tTempStack; + int tTempStackSize; + ItemStack aHoldStack; + + if ((aShifthold == 0 || aShifthold == 1) && (aMouseclick == 0 || aMouseclick == 1)) { + if (aSlotIndex == -999) { + if (aPlayerInventory.getItemStack() != null) { + if (aMouseclick == 0) { + aPlayer.dropPlayerItemWithRandomChoice(aPlayerInventory.getItemStack(), true); + aPlayerInventory.setItemStack(null); + } + if (aMouseclick == 1) { + aPlayer.dropPlayerItemWithRandomChoice( + aPlayerInventory.getItemStack() + .splitStack(1), + true); + if (aPlayerInventory.getItemStack().stackSize == 0) { + aPlayerInventory.setItemStack(null); + } + } + } + } else if (aShifthold == 1) { + aSlot = this.inventorySlots.get(aSlotIndex); + if (aSlot != null && aSlot.canTakeStack(aPlayer)) { + tTempStack = this.transferStackInSlot(aPlayer, aSlotIndex); + if (tTempStack != null) { + rStack = GT_Utility.copyOrNull(tTempStack); + if (aSlot.getStack() != null && aSlot.getStack() + .getItem() == tTempStack.getItem()) { + slotClick(aSlotIndex, aMouseclick, aShifthold, aPlayer); + } + } + } + } else { + if (aSlotIndex < 0) { + return null; + } + aSlot = this.inventorySlots.get(aSlotIndex); + if (aSlot != null) { + tTempStack = aSlot.getStack(); + ItemStack mouseStack = aPlayerInventory.getItemStack(); + if (tTempStack != null) { + rStack = GT_Utility.copyOrNull(tTempStack); + } + if (tTempStack == null) { + if (mouseStack != null && aSlot.isItemValid(mouseStack)) { + tTempStackSize = aMouseclick == 0 ? mouseStack.stackSize : 1; + if (tTempStackSize > aSlot.getSlotStackLimit()) { + tTempStackSize = aSlot.getSlotStackLimit(); + } + aSlot.putStack(mouseStack.splitStack(tTempStackSize)); + + if (mouseStack.stackSize == 0) { + aPlayerInventory.setItemStack(null); + } + } + } else if (aSlot.canTakeStack(aPlayer)) { + if (mouseStack == null) { + tTempStackSize = aMouseclick == 0 ? tTempStack.stackSize : (tTempStack.stackSize + 1) / 2; + aHoldStack = aSlot.decrStackSize(tTempStackSize); + aPlayerInventory.setItemStack(aHoldStack); + if (tTempStack.stackSize == 0) { + aSlot.putStack(null); + } + aSlot.onPickupFromSlot(aPlayer, aPlayerInventory.getItemStack()); + } else if (aSlot.isItemValid(mouseStack)) { + if (tTempStack.getItem() == mouseStack.getItem() + && tTempStack.getItemDamage() == mouseStack.getItemDamage() + && ItemStack.areItemStackTagsEqual(tTempStack, mouseStack)) { + tTempStackSize = aMouseclick == 0 ? mouseStack.stackSize : 1; + if (tTempStackSize > aSlot.getSlotStackLimit() - tTempStack.stackSize) { + tTempStackSize = aSlot.getSlotStackLimit() - tTempStack.stackSize; + } + if (tTempStackSize > mouseStack.getMaxStackSize() - tTempStack.stackSize) { + tTempStackSize = mouseStack.getMaxStackSize() - tTempStack.stackSize; + } + mouseStack.splitStack(tTempStackSize); + if (mouseStack.stackSize == 0) { + aPlayerInventory.setItemStack(null); + } + tTempStack.stackSize += tTempStackSize; + } else if (mouseStack.stackSize <= aSlot.getSlotStackLimit()) { + aSlot.putStack(mouseStack); + aPlayerInventory.setItemStack(tTempStack); + } + } else if (tTempStack.getItem() == mouseStack.getItem() && mouseStack.getMaxStackSize() > 1 + && (!tTempStack.getHasSubtypes() + || tTempStack.getItemDamage() == mouseStack.getItemDamage()) + && ItemStack.areItemStackTagsEqual(tTempStack, mouseStack)) { + tTempStackSize = tTempStack.stackSize; + + if (tTempStackSize > 0 + && tTempStackSize + mouseStack.stackSize <= mouseStack.getMaxStackSize()) { + mouseStack.stackSize += tTempStackSize; + tTempStack = aSlot.decrStackSize(tTempStackSize); + + if (tTempStack.stackSize == 0) { + aSlot.putStack(null); + } + + aSlot.onPickupFromSlot(aPlayer, aPlayerInventory.getItemStack()); + } + } + } + aSlot.onSlotChanged(); + } + } + // Did the player try to swap a slot with his hotbar using a + // number key from 1 to 9 + // aMouseclick == 0 means number 1, aMouseclick == 8 means number 9 + } else if (aShifthold == 2 && aMouseclick >= 0 && aMouseclick < 9) { + aSlot = this.inventorySlots.get(aSlotIndex); + + if (aSlot.canTakeStack(aPlayer)) { + // get the stack at the specified hotbar slot. + tTempStack = aPlayerInventory.getStackInSlot(aMouseclick); + boolean canSwap = tTempStack == null + || aSlot.inventory == aPlayerInventory && aSlot.isItemValid(tTempStack); + tTempStackSize = -1; + + if (!canSwap) { + tTempStackSize = aPlayerInventory.getFirstEmptyStack(); + canSwap = tTempStackSize > -1; + } + + if (canSwap && aSlot.getHasStack()) { + aHoldStack = aSlot.getStack(); + aPlayerInventory.setInventorySlotContents(aMouseclick, aHoldStack); + + if (tTempStack != null && (aSlot.inventory != aPlayerInventory || !aSlot.isItemValid(tTempStack))) { + if (tTempStackSize > -1) { + aPlayerInventory.addItemStackToInventory(tTempStack); + aSlot.decrStackSize(aHoldStack.stackSize); + aSlot.putStack(null); + aSlot.onPickupFromSlot(aPlayer, aHoldStack); + } + } else { + aSlot.decrStackSize(aHoldStack.stackSize); + aSlot.putStack(tTempStack); + aSlot.onPickupFromSlot(aPlayer, aHoldStack); + } + } else if (tTempStack != null && !aSlot.getHasStack() && aSlot.isItemValid(tTempStack)) { + aPlayerInventory.setInventorySlotContents(aMouseclick, null); + aSlot.putStack(tTempStack); + } + } + } else if (aShifthold == 3 && aPlayer.capabilities.isCreativeMode + && aPlayerInventory.getItemStack() == null + && aSlotIndex >= 0) { + aSlot = this.inventorySlots.get(aSlotIndex); + if (aSlot != null && aSlot.getHasStack()) { + tTempStack = GT_Utility.copyOrNull(aSlot.getStack()); + tTempStack.stackSize = tTempStack.getMaxStackSize(); + aPlayerInventory.setItemStack(tTempStack); + } + } + return rStack; + } + + @Override + public ItemStack transferStackInSlot(EntityPlayer aPlayer, int aSlotIndex) { + ItemStack stack = null; + Slot slotObject = inventorySlots.get(aSlotIndex); + + mTileEntity.markDirty(); + + // null checks and checks if the item can be stacked (maxStackSize > 1) + if (getSlotCount() > 0 && slotObject != null + && slotObject.getHasStack() + && !(slotObject instanceof GT_Slot_Holo)) { + ItemStack stackInSlot = slotObject.getStack(); + stack = GT_Utility.copyOrNull(stackInSlot); + + // TileEntity -> Player + if (aSlotIndex < getAllSlotCount()) { + if (doesBindPlayerInventory()) + if (!mergeItemStack(stackInSlot, getAllSlotCount(), getAllSlotCount() + 36, true)) { + return null; + } + // Player -> TileEntity + } else if (!mergeItemStack( + stackInSlot, + getShiftClickStartIndex(), + getShiftClickStartIndex() + getShiftClickSlotCount(), + false)) { + return null; + } + + if (stackInSlot.stackSize == 0) { + slotObject.putStack(null); + } else { + slotObject.onSlotChanged(); + } + } + return stack; + } + + /** + * merges provided ItemStack with the first avaliable one in the container/player inventory + */ + @Override + protected boolean mergeItemStack(ItemStack aStack, int aStartIndex, int aSlotCount, boolean reverseOrder) { + boolean transferredStack = false; + int slotIndex = aStartIndex; + + mTileEntity.markDirty(); + + if (reverseOrder) { + slotIndex = aSlotCount - 1; + } + + Slot slot; + ItemStack itemStack; + + if (aStack.isStackable()) { + while (aStack.stackSize > 0 + && (!reverseOrder && slotIndex < aSlotCount || reverseOrder && slotIndex >= aStartIndex)) { + slot = this.inventorySlots.get(slotIndex); + itemStack = slot.getStack(); + if (!(slot instanceof GT_Slot_Holo) && !(slot instanceof GT_Slot_Output) + && slot.isItemValid(aStack) + && itemStack != null + && itemStack.getItem() == aStack.getItem() + && (!aStack.getHasSubtypes() || aStack.getItemDamage() == itemStack.getItemDamage()) + && ItemStack.areItemStackTagsEqual(aStack, itemStack)) { + int combinedStackSize = itemStack.stackSize + aStack.stackSize; + if (itemStack.stackSize < mTileEntity.getInventoryStackLimit()) { + if (combinedStackSize <= aStack.getMaxStackSize()) { + aStack.stackSize = 0; + itemStack.stackSize = combinedStackSize; + slot.onSlotChanged(); + transferredStack = true; + } else if (itemStack.stackSize < aStack.getMaxStackSize()) { + aStack.stackSize -= aStack.getMaxStackSize() - itemStack.stackSize; + itemStack.stackSize = aStack.getMaxStackSize(); + slot.onSlotChanged(); + transferredStack = true; + } + } + } + + if (reverseOrder) { + --slotIndex; + } else { + ++slotIndex; + } + } + } + if (aStack.stackSize > 0) { + if (reverseOrder) { + slotIndex = aSlotCount - 1; + } else { + slotIndex = aStartIndex; + } + + while (!reverseOrder && slotIndex < aSlotCount || reverseOrder && slotIndex >= aStartIndex) { + slot = this.inventorySlots.get(slotIndex); + itemStack = slot.getStack(); + + if (slot.isItemValid(aStack) && itemStack == null) { + int quantityToTransfer = Math.min(aStack.stackSize, mTileEntity.getInventoryStackLimit()); + slot.putStack(GT_Utility.copyAmount(quantityToTransfer, aStack)); + slot.onSlotChanged(); + aStack.stackSize -= quantityToTransfer; + transferredStack = true; + break; + } + + if (reverseOrder) { + --slotIndex; + } else { + ++slotIndex; + } + } + } + + return transferredStack; + } + + @Override + protected Slot addSlotToContainer(Slot slot) { + try { + return super.addSlotToContainer(slot); + } catch (Throwable e) { + e.printStackTrace(GT_Log.err); + } + return slot; + } + + @Override + public void addCraftingToCrafters(ICrafting player) { + try { + super.addCraftingToCrafters(player); + } catch (Throwable e) { + e.printStackTrace(GT_Log.err); + } + } + + @Override + public List<ItemStack> getInventory() { + try { + return super.getInventory(); + } catch (Throwable e) { + e.printStackTrace(GT_Log.err); + } + return null; + } + + @Override + public void removeCraftingFromCrafters(ICrafting player) { + try { + super.removeCraftingFromCrafters(player); + } catch (Throwable e) { + e.printStackTrace(GT_Log.err); + } + } + + @Override + public void detectAndSendChanges() { + try { + super.detectAndSendChanges(); + } catch (Throwable e) { + e.printStackTrace(GT_Log.err); + } + } + + @Override + public boolean enchantItem(EntityPlayer player, int slotIndex) { + try { + return super.enchantItem(player, slotIndex); + } catch (Throwable e) { + e.printStackTrace(GT_Log.err); + } + return false; + } + + @Override + public Slot getSlotFromInventory(IInventory inventory, int slotIndex) { + try { + return super.getSlotFromInventory(inventory, slotIndex); + } catch (Throwable e) { + e.printStackTrace(GT_Log.err); + } + return null; + } + + @Override + public Slot getSlot(int slotIndex) { + try { + if (this.inventorySlots.size() > slotIndex) return super.getSlot(slotIndex); + } catch (Throwable e) { + e.printStackTrace(GT_Log.err); + } + return null; + } + + @Override + public boolean func_94530_a(ItemStack itemStack, Slot slot) { + try { + return super.func_94530_a(itemStack, slot); + } catch (Throwable e) { + e.printStackTrace(GT_Log.err); + } + return true; + } + + @Override + protected void retrySlotClick(int slotIndex, int mouseButton, boolean aShifthold, EntityPlayer player) { + try { + super.retrySlotClick(slotIndex, mouseButton, aShifthold, player); + } catch (Throwable e) { + e.printStackTrace(GT_Log.err); + } + } + + @Override + public void onContainerClosed(EntityPlayer player) { + try { + super.onContainerClosed(player); + mTileEntity.closeInventory(); + } catch (Throwable e) { + e.printStackTrace(GT_Log.err); + } + } + + @Override + public void onCraftMatrixChanged(IInventory inventory) { + try { + super.onCraftMatrixChanged(inventory); + } catch (Throwable e) { + e.printStackTrace(GT_Log.err); + } + } + + @Override + public void putStackInSlot(int slotIndex, ItemStack itemStack) { + try { + super.putStackInSlot(slotIndex, itemStack); + } catch (Throwable e) { + e.printStackTrace(GT_Log.err); + } + } + + @Override + public void putStacksInSlots(ItemStack[] itemStacks) { + try { + super.putStacksInSlots(itemStacks); + } catch (Throwable e) { + e.printStackTrace(GT_Log.err); + } + } + + @Override + public void updateProgressBar(int id, int value) { + try { + super.updateProgressBar(id, value); + } catch (Throwable e) { + e.printStackTrace(GT_Log.err); + } + } + + @Override + public short getNextTransactionID(InventoryPlayer inventoryPlayer) { + try { + return super.getNextTransactionID(inventoryPlayer); + } catch (Throwable e) { + e.printStackTrace(GT_Log.err); + } + return 0; + } + + @Override + public boolean isPlayerNotUsingContainer(EntityPlayer player) { + try { + return super.isPlayerNotUsingContainer(player); + } catch (Throwable e) { + e.printStackTrace(GT_Log.err); + } + return true; + } + + @Override + public void setPlayerIsPresent(EntityPlayer player, boolean value) { + try { + super.setPlayerIsPresent(player, value); + } catch (Throwable e) { + e.printStackTrace(GT_Log.err); + } + } + + @Override + protected void func_94533_d() { + try { + super.func_94533_d(); + } catch (Throwable e) { + e.printStackTrace(GT_Log.err); + } + } + + @Override + public boolean canDragIntoSlot(Slot slot) { + try { + return super.canDragIntoSlot(slot); + } catch (Throwable e) { + e.printStackTrace(GT_Log.err); + } + return true; + } + + protected static ItemStack handleFluidSlotClick(IFluidAccess aFluidAccess, EntityPlayer aPlayer, + boolean aProcessFullStack, boolean aCanDrain, boolean aCanFill) { + ItemStack tStackHeld = aPlayer.inventory.getItemStack(); + ItemStack tStackSizedOne = GT_Utility.copyAmount(1, tStackHeld); + if (tStackSizedOne == null || tStackHeld.stackSize == 0) return null; + FluidStack tInputFluid = aFluidAccess.get(); + FluidStack tFluidHeld = GT_Utility.getFluidForFilledItem(tStackSizedOne, true); + if (tFluidHeld != null && tFluidHeld.amount <= 0) tFluidHeld = null; + if (tInputFluid == null) { + // tank empty, consider fill only from now on + if (!aCanFill) + // cannot fill and nothing to take, bail out + return null; + if (tFluidHeld == null) + // no fluid to fill + return null; + return fillFluid(aFluidAccess, aPlayer, tFluidHeld, aProcessFullStack); + } + // tank not empty, both action possible + if (tFluidHeld != null && tInputFluid.amount < aFluidAccess.getCapacity()) { + // both nonnull and have space left for filling. + if (aCanFill) + // actually both pickup and fill is reasonable, but I'll go with fill here + return fillFluid(aFluidAccess, aPlayer, tFluidHeld, aProcessFullStack); + if (!aCanDrain) + // cannot take AND cannot fill, why make this call then? + return null; + // the slot does not allow filling, so try take some + return drainFluid(aFluidAccess, aPlayer, aProcessFullStack); + } else { + // cannot fill and there is something to take + if (!aCanDrain) + // but the slot does not allow taking, so bail out + return null; + return drainFluid(aFluidAccess, aPlayer, aProcessFullStack); + } + } + + protected static ItemStack drainFluid(IFluidAccess aFluidAccess, EntityPlayer aPlayer, boolean aProcessFullStack) { + FluidStack tTankStack = aFluidAccess.get(); + if (tTankStack == null) return null; + ItemStack tStackHeld = aPlayer.inventory.getItemStack(); + ItemStack tStackSizedOne = GT_Utility.copyAmount(1, tStackHeld); + if (tStackSizedOne == null || tStackHeld.stackSize == 0) return null; + int tOriginalFluidAmount = tTankStack.amount; + ItemStack tFilledContainer = GT_Utility.fillFluidContainer(tTankStack, tStackSizedOne, true, false); + if (tFilledContainer == null && tStackSizedOne.getItem() instanceof IFluidContainerItem tContainerItem) { + int tFilledAmount = tContainerItem.fill(tStackSizedOne, tTankStack, true); + if (tFilledAmount > 0) { + tFilledContainer = tStackSizedOne; + tTankStack.amount -= tFilledAmount; + } + } + if (tFilledContainer != null) { + if (aProcessFullStack) { + int tFilledAmount = tOriginalFluidAmount - tTankStack.amount; + /* + * work out how many more items we can fill one cell is already used, so account for that the round down + * behavior will left over a fraction of a cell worth of fluid the user then get to decide what to do + * with it it will not be too fancy if it spills out partially filled cells + */ + int tAdditionalParallel = Math.min(tStackHeld.stackSize - 1, tTankStack.amount / tFilledAmount); + tTankStack.amount -= tFilledAmount * tAdditionalParallel; + tFilledContainer.stackSize += tAdditionalParallel; + } + replaceCursorItemStack(aPlayer, tFilledContainer); + } + aFluidAccess.verifyFluidStack(); + return tFilledContainer; + } + + protected static ItemStack fillFluid(IFluidAccess aFluidAccess, EntityPlayer aPlayer, FluidStack aFluidHeld, + boolean aProcessFullStack) { + // we are not using aMachine.fill() here any more, so we need to check for fluid type here ourselves + if (aFluidAccess.get() != null && !aFluidAccess.get() + .isFluidEqual(aFluidHeld)) return null; + ItemStack tStackHeld = aPlayer.inventory.getItemStack(); + ItemStack tStackSizedOne = GT_Utility.copyAmount(1, tStackHeld); + if (tStackSizedOne == null) return null; + + int tFreeSpace = aFluidAccess.getCapacity() - (aFluidAccess.get() != null ? aFluidAccess.get().amount : 0); + if (tFreeSpace <= 0) + // no space left + return null; + + // find out how much fluid can be taken + // some cells cannot be partially filled + ItemStack tStackEmptied = null; + int tAmountTaken = 0; + if (tFreeSpace >= aFluidHeld.amount) { + // fully accepted - try take it from item now + // IFluidContainerItem is intentionally not checked here. it will be checked later + tStackEmptied = GT_Utility.getContainerForFilledItem(tStackSizedOne, false); + tAmountTaken = aFluidHeld.amount; + } + if (tStackEmptied == null && tStackSizedOne.getItem() instanceof IFluidContainerItem container) { + // either partially accepted, or is IFluidContainerItem + FluidStack tDrained = container.drain(tStackSizedOne, tFreeSpace, true); + if (tDrained != null && tDrained.amount > 0) { + // something is actually drained - change the cell and drop it to player + tStackEmptied = tStackSizedOne; + tAmountTaken = tDrained.amount; + } + } + if (tStackEmptied == null) + // somehow the cell refuse to give out that amount of fluid, no op then + return null; + + // find out how many fill can we do + // same round down behavior as above + // however here the fluid stack is not changed at all, so the exact code will slightly differ + int tParallel = aProcessFullStack ? Math.min(tFreeSpace / tAmountTaken, tStackHeld.stackSize) : 1; + if (aFluidAccess.get() == null) { + FluidStack tNewFillableStack = aFluidHeld.copy(); + tNewFillableStack.amount = tAmountTaken * tParallel; + aFluidAccess.set(tNewFillableStack); + } else { + aFluidAccess.addAmount(tAmountTaken * tParallel); + } + tStackEmptied.stackSize = tParallel; + replaceCursorItemStack(aPlayer, tStackEmptied); + return tStackEmptied; + } + + private static void replaceCursorItemStack(EntityPlayer aPlayer, ItemStack tStackResult) { + int tStackResultMaxStackSize = tStackResult.getMaxStackSize(); + while (tStackResult.stackSize > tStackResultMaxStackSize) { + aPlayer.inventory.getItemStack().stackSize -= tStackResultMaxStackSize; + GT_Utility.addItemToPlayerInventory(aPlayer, tStackResult.splitStack(tStackResultMaxStackSize)); + } + if (aPlayer.inventory.getItemStack().stackSize == tStackResult.stackSize) { + // every cell is mutated. it could just stay on the cursor. + aPlayer.inventory.setItemStack(tStackResult); + } else { + // some cells not mutated. The mutated cells must go into the inventory + // or drop into the world if there isn't enough space. + ItemStack tStackHeld = aPlayer.inventory.getItemStack(); + tStackHeld.stackSize -= tStackResult.stackSize; + GT_Utility.addItemToPlayerInventory(aPlayer, tStackResult); + } + } +} diff --git a/src/main/java/gregtech/api/gui/GT_ContainerMetaTile_Machine.java b/src/main/java/gregtech/api/gui/GT_ContainerMetaTile_Machine.java new file mode 100644 index 0000000000..a77f376e00 --- /dev/null +++ b/src/main/java/gregtech/api/gui/GT_ContainerMetaTile_Machine.java @@ -0,0 +1,244 @@ +package gregtech.api.gui; + +import java.util.List; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.inventory.ICrafting; +import net.minecraft.item.ItemStack; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import gregtech.api.interfaces.IConfigurationCircuitSupport; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.util.GT_Utility; + +/** + * NEVER INCLUDE THIS FILE IN YOUR MOD!!! + * <p/> + * The Container I use for all my MetaTileEntities + */ +public class GT_ContainerMetaTile_Machine extends GT_Container { + + public int mActive = 0, mMaxProgressTime = 0, mProgressTime = 0, mEnergy = 0, mSteam = 0, mSteamStorage = 0, + mStorage = 0, mOutput = 0, mInput = 0, mID = 0, mDisplayErrorCode = 0; + public long mEnergyLong = 0, mStorageLong = 0; + private int oActive = 0, oMaxProgressTime = 0, oProgressTime = 0, oEnergy = 0, oSteam = 0, oSteamStorage = 0, + oStorage = 0, oOutput = 0, oInput = 0, oID = 0, oDisplayErrorCode = 0; + private long oEnergyLong = 0, oStorageLong = 0; + protected int mTimer = 0; + protected Runnable circuitSlotClickCallback; + + public GT_ContainerMetaTile_Machine(InventoryPlayer aInventoryPlayer, IGregTechTileEntity aTileEntity) { + super(aInventoryPlayer, aTileEntity); + + mTileEntity = aTileEntity; + + if (mTileEntity != null && mTileEntity.getMetaTileEntity() != null) { + addSlots(aInventoryPlayer); + if (doesBindPlayerInventory()) bindPlayerInventory(aInventoryPlayer); + detectAndSendChanges(); + } else { + aInventoryPlayer.player.openContainer = aInventoryPlayer.player.inventoryContainer; + } + } + + public GT_ContainerMetaTile_Machine(InventoryPlayer aInventoryPlayer, IGregTechTileEntity aTileEntity, + boolean doesBindInventory) { + super(aInventoryPlayer, aTileEntity); + mTileEntity = aTileEntity; + + if (mTileEntity != null && mTileEntity.getMetaTileEntity() != null) { + addSlots(aInventoryPlayer); + if (doesBindPlayerInventory() && doesBindInventory) bindPlayerInventory(aInventoryPlayer); + detectAndSendChanges(); + } else { + aInventoryPlayer.player.openContainer = aInventoryPlayer.player.inventoryContainer; + } + } + + protected void addCircuitSlot() { + if (mTileEntity.getMetaTileEntity() instanceof IConfigurationCircuitSupport ccs) { + GT_Slot_Render slotCircuit = new GT_Slot_Render( + mTileEntity, + ccs.getCircuitSlot(), + ccs.getCircuitSlotX(), + ccs.getCircuitSlotY()); + addSlotToContainer(slotCircuit); + slotCircuit.setEnabled(ccs.allowSelectCircuit()); + } + } + + @Override + public void addSlots(InventoryPlayer aInventoryPlayer) { + addCircuitSlot(); + } + + @Override + public void detectAndSendChanges() { + super.detectAndSendChanges(); + if (mTileEntity.isClientSide() || mTileEntity.getMetaTileEntity() == null) return; + mStorage = (int) Math.min(Integer.MAX_VALUE, mTileEntity.getEUCapacity()); + mStorageLong = mTileEntity.getEUCapacity(); + mEnergy = (int) Math.min(Integer.MAX_VALUE, mTileEntity.getStoredEU()); + mEnergyLong = mTileEntity.getStoredEU(); + mSteamStorage = (int) Math.min(Integer.MAX_VALUE, mTileEntity.getSteamCapacity()); + mSteam = (int) Math.min(Integer.MAX_VALUE, mTileEntity.getStoredSteam()); + mOutput = (int) Math.min(Integer.MAX_VALUE, mTileEntity.getOutputVoltage()); + mInput = (int) Math.min(Integer.MAX_VALUE, mTileEntity.getInputVoltage()); + mDisplayErrorCode = mTileEntity.getErrorDisplayID(); + mProgressTime = mTileEntity.getProgress(); + mMaxProgressTime = mTileEntity.getMaxProgress(); + mActive = mTileEntity.isActive() ? 1 : 0; + mTimer++; + + for (ICrafting player : this.crafters) { + if (mTimer % 500 == 10 || oEnergy != mEnergy) { + player.sendProgressBarUpdate(this, 0, mEnergy & 65535); + player.sendProgressBarUpdate(this, 1, mEnergy >>> 16); + } + if (mTimer % 500 == 10 || oStorage != mStorage) { + player.sendProgressBarUpdate(this, 2, mStorage & 65535); + player.sendProgressBarUpdate(this, 3, mStorage >>> 16); + } + if (mTimer % 500 == 10 || oOutput != mOutput) { + player.sendProgressBarUpdate(this, 4, mOutput); + } + if (mTimer % 500 == 10 || oInput != mInput) { + player.sendProgressBarUpdate(this, 5, mInput); + } + if (mTimer % 500 == 10 || oDisplayErrorCode != mDisplayErrorCode) { + player.sendProgressBarUpdate(this, 6, mDisplayErrorCode); + } + if (mTimer % 500 == 10 || oProgressTime != mProgressTime) { + player.sendProgressBarUpdate(this, 11, mProgressTime & 65535); + player.sendProgressBarUpdate(this, 12, mProgressTime >>> 16); + } + if (mTimer % 500 == 10 || oMaxProgressTime != mMaxProgressTime) { + player.sendProgressBarUpdate(this, 13, mMaxProgressTime & 65535); + player.sendProgressBarUpdate(this, 14, mMaxProgressTime >>> 16); + } + if (mTimer % 500 == 10 || oID != mID) { + player.sendProgressBarUpdate(this, 15, mID); + } + if (mTimer % 500 == 10 || oActive != mActive) { + player.sendProgressBarUpdate(this, 16, mActive); + } + if (mTimer % 500 == 10 || oSteam != mSteam) { + player.sendProgressBarUpdate(this, 17, mSteam & 65535); + player.sendProgressBarUpdate(this, 18, mSteam >>> 16); + } + if (mTimer % 500 == 10 || oSteamStorage != mSteamStorage) { + player.sendProgressBarUpdate(this, 19, mSteamStorage & 65535); + player.sendProgressBarUpdate(this, 20, mSteamStorage >>> 16); + } + if (mTimer % 500 == 10 || oEnergyLong != mEnergyLong) { + player.sendProgressBarUpdate(this, 21, (int) mEnergyLong); + player.sendProgressBarUpdate(this, 22, (int) (mEnergyLong >>> 32)); + } + if (mTimer % 500 == 10 || oStorageLong != mStorageLong) { + player.sendProgressBarUpdate(this, 23, (int) mStorageLong); + player.sendProgressBarUpdate(this, 24, (int) (mStorageLong >>> 32)); + } + } + + oID = mID; + oSteam = mSteam; + oInput = mInput; + oActive = mActive; + oOutput = mOutput; + oEnergy = mEnergy; + oEnergyLong = mEnergyLong; + oStorage = mStorage; + oStorageLong = mStorageLong; + oSteamStorage = mSteamStorage; + oProgressTime = mProgressTime; + oMaxProgressTime = mMaxProgressTime; + oDisplayErrorCode = mDisplayErrorCode; + } + + @SideOnly(Side.CLIENT) + @Override + public void updateProgressBar(int id, int value) { + super.updateProgressBar(id, value); + switch (id) { + case 0 -> mEnergy = mEnergy & 0xffff0000 | value & 0x0000ffff; + case 1 -> mEnergy = mEnergy & 0x0000ffff | value << 16; + case 2 -> mStorage = mStorage & 0xffff0000 | value & 0x0000ffff; + case 3 -> mStorage = mStorage & 0x0000ffff | value << 16; + case 4 -> mOutput = value; + case 5 -> mInput = value; + case 6 -> mDisplayErrorCode = value; + case 11 -> mProgressTime = mProgressTime & 0xffff0000 | value; + case 12 -> mProgressTime = mProgressTime & 0x0000ffff | value << 16; + case 13 -> mMaxProgressTime = mMaxProgressTime & 0xffff0000 | value & 0x0000ffff; + case 14 -> mMaxProgressTime = mMaxProgressTime & 0x0000ffff | value << 16; + case 15 -> mID = value; + case 16 -> mActive = value; + case 17 -> mSteam = mSteam & 0xffff0000 | value & 0x0000ffff; + case 18 -> mSteam = mSteam & 0x0000ffff | value << 16; + case 19 -> mSteamStorage = mSteamStorage & 0xffff0000 | value & 0x0000ffff; + case 20 -> mSteamStorage = mSteamStorage & 0x0000ffff | value << 16; + case 21 -> mEnergyLong = mEnergyLong & 0xffffffff00000000L | value & 0x00000000ffffffffL; + case 22 -> mEnergyLong = mEnergyLong & 0x00000000ffffffffL | (long) value << 32; + case 23 -> mStorageLong = mStorageLong & 0xffffffff00000000L | value & 0x00000000ffffffffL; + case 24 -> mStorageLong = mStorageLong & 0x00000000ffffffffL | (long) value << 32; + } + } + + @Override + public boolean canInteractWith(EntityPlayer player) { + return mTileEntity.isUseableByPlayer(player); + } + + @Deprecated + public String trans(String aKey, String aEnglish) { + return GT_Utility.trans(aKey, aEnglish); + } + + public void setCircuitSlotClickCallback(Runnable circuitSlotClickCallback) { + this.circuitSlotClickCallback = circuitSlotClickCallback; + } + + @Override + public ItemStack slotClick(int aSlotNumber, int aMouseclick, int aShifthold, EntityPlayer aPlayer) { + if (mTileEntity.getMetaTileEntity() instanceof IConfigurationCircuitSupport) { + IMetaTileEntity machine = mTileEntity.getMetaTileEntity(); + IConfigurationCircuitSupport ccs = (IConfigurationCircuitSupport) machine; + if (ccs.allowSelectCircuit() && aSlotNumber == ccs.getCircuitGUISlot() && aMouseclick < 2) { + ItemStack newCircuit; + if (aShifthold == 1) { + if (aMouseclick == 0) { + if (circuitSlotClickCallback != null) circuitSlotClickCallback.run(); + return null; + } else { + // clear + newCircuit = null; + } + } else { + ItemStack cursorStack = aPlayer.inventory.getItemStack(); + List<ItemStack> tCircuits = ccs.getConfigurationCircuits(); + int index = GT_Utility.findMatchingStackInList(tCircuits, cursorStack); + if (index < 0) { + int curIndex = GT_Utility + .findMatchingStackInList(tCircuits, machine.getStackInSlot(ccs.getCircuitSlot())) + 1; + if (aMouseclick == 0) { + curIndex += 1; + } else { + curIndex -= 1; + } + curIndex = Math.floorMod(curIndex, tCircuits.size() + 1) - 1; + newCircuit = curIndex < 0 ? null : tCircuits.get(curIndex); + } else { + // set to whatever it is + newCircuit = tCircuits.get(index); + } + } + mTileEntity.setInventorySlotContents(ccs.getCircuitSlot(), newCircuit); + return newCircuit; + } + } + return super.slotClick(aSlotNumber, aMouseclick, aShifthold, aPlayer); + } +} diff --git a/src/main/java/gregtech/api/gui/GT_Container_1by1.java b/src/main/java/gregtech/api/gui/GT_Container_1by1.java new file mode 100644 index 0000000000..06efaee5ef --- /dev/null +++ b/src/main/java/gregtech/api/gui/GT_Container_1by1.java @@ -0,0 +1,30 @@ +package gregtech.api.gui; + +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.inventory.Slot; + +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; + +@Deprecated +public class GT_Container_1by1 extends GT_ContainerMetaTile_Machine { + + public GT_Container_1by1(InventoryPlayer aInventoryPlayer, IGregTechTileEntity aTileEntity) { + super(aInventoryPlayer, aTileEntity); + } + + @Override + public void addSlots(InventoryPlayer aInventoryPlayer) { + addSlotToContainer(new Slot(mTileEntity, 0, 80, 35)); + super.addSlots(aInventoryPlayer); + } + + @Override + public int getSlotCount() { + return 1; + } + + @Override + public int getShiftClickSlotCount() { + return 1; + } +} diff --git a/src/main/java/gregtech/api/gui/GT_Container_2by2.java b/src/main/java/gregtech/api/gui/GT_Container_2by2.java new file mode 100644 index 0000000000..4e3584a0a6 --- /dev/null +++ b/src/main/java/gregtech/api/gui/GT_Container_2by2.java @@ -0,0 +1,33 @@ +package gregtech.api.gui; + +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.inventory.Slot; + +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; + +@Deprecated +public class GT_Container_2by2 extends GT_ContainerMetaTile_Machine { + + public GT_Container_2by2(InventoryPlayer aInventoryPlayer, IGregTechTileEntity aTileEntity) { + super(aInventoryPlayer, aTileEntity); + } + + @Override + public void addSlots(InventoryPlayer aInventoryPlayer) { + addSlotToContainer(new Slot(mTileEntity, 0, 71, 26)); + addSlotToContainer(new Slot(mTileEntity, 1, 89, 26)); + addSlotToContainer(new Slot(mTileEntity, 2, 71, 44)); + addSlotToContainer(new Slot(mTileEntity, 3, 89, 44)); + super.addSlots(aInventoryPlayer); + } + + @Override + public int getSlotCount() { + return 4; + } + + @Override + public int getShiftClickSlotCount() { + return 4; + } +} diff --git a/src/main/java/gregtech/api/gui/GT_Container_3by3.java b/src/main/java/gregtech/api/gui/GT_Container_3by3.java new file mode 100644 index 0000000000..4c0f7f946b --- /dev/null +++ b/src/main/java/gregtech/api/gui/GT_Container_3by3.java @@ -0,0 +1,38 @@ +package gregtech.api.gui; + +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.inventory.Slot; + +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; + +@Deprecated +public class GT_Container_3by3 extends GT_ContainerMetaTile_Machine { + + public GT_Container_3by3(InventoryPlayer aInventoryPlayer, IGregTechTileEntity aTileEntity) { + super(aInventoryPlayer, aTileEntity); + } + + @Override + public void addSlots(InventoryPlayer aInventoryPlayer) { + addSlotToContainer(new Slot(mTileEntity, 0, 62, 17)); + addSlotToContainer(new Slot(mTileEntity, 1, 80, 17)); + addSlotToContainer(new Slot(mTileEntity, 2, 98, 17)); + addSlotToContainer(new Slot(mTileEntity, 3, 62, 35)); + addSlotToContainer(new Slot(mTileEntity, 4, 80, 35)); + addSlotToContainer(new Slot(mTileEntity, 5, 98, 35)); + addSlotToContainer(new Slot(mTileEntity, 6, 62, 53)); + addSlotToContainer(new Slot(mTileEntity, 7, 80, 53)); + addSlotToContainer(new Slot(mTileEntity, 8, 98, 53)); + super.addSlots(aInventoryPlayer); + } + + @Override + public int getSlotCount() { + return 9; + } + + @Override + public int getShiftClickSlotCount() { + return 9; + } +} diff --git a/src/main/java/gregtech/api/gui/GT_Container_4by4.java b/src/main/java/gregtech/api/gui/GT_Container_4by4.java new file mode 100644 index 0000000000..db5cde4cfe --- /dev/null +++ b/src/main/java/gregtech/api/gui/GT_Container_4by4.java @@ -0,0 +1,45 @@ +package gregtech.api.gui; + +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.inventory.Slot; + +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; + +@Deprecated +public class GT_Container_4by4 extends GT_ContainerMetaTile_Machine { + + public GT_Container_4by4(InventoryPlayer aInventoryPlayer, IGregTechTileEntity aTileEntity) { + super(aInventoryPlayer, aTileEntity); + } + + @Override + public void addSlots(InventoryPlayer aInventoryPlayer) { + addSlotToContainer(new Slot(mTileEntity, 0, 53, 8)); + addSlotToContainer(new Slot(mTileEntity, 1, 71, 8)); + addSlotToContainer(new Slot(mTileEntity, 2, 89, 8)); + addSlotToContainer(new Slot(mTileEntity, 3, 107, 8)); + addSlotToContainer(new Slot(mTileEntity, 4, 53, 26)); + addSlotToContainer(new Slot(mTileEntity, 5, 71, 26)); + addSlotToContainer(new Slot(mTileEntity, 6, 89, 26)); + addSlotToContainer(new Slot(mTileEntity, 7, 107, 26)); + addSlotToContainer(new Slot(mTileEntity, 8, 53, 44)); + addSlotToContainer(new Slot(mTileEntity, 9, 71, 44)); + addSlotToContainer(new Slot(mTileEntity, 10, 89, 44)); + addSlotToContainer(new Slot(mTileEntity, 11, 107, 44)); + addSlotToContainer(new Slot(mTileEntity, 12, 53, 62)); + addSlotToContainer(new Slot(mTileEntity, 13, 71, 62)); + addSlotToContainer(new Slot(mTileEntity, 14, 89, 62)); + addSlotToContainer(new Slot(mTileEntity, 15, 107, 62)); + super.addSlots(aInventoryPlayer); + } + + @Override + public int getSlotCount() { + return 16; + } + + @Override + public int getShiftClickSlotCount() { + return 16; + } +} diff --git a/src/main/java/gregtech/api/gui/GT_Container_BasicTank.java b/src/main/java/gregtech/api/gui/GT_Container_BasicTank.java new file mode 100644 index 0000000000..403de4bab5 --- /dev/null +++ b/src/main/java/gregtech/api/gui/GT_Container_BasicTank.java @@ -0,0 +1,138 @@ +package gregtech.api.gui; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.inventory.ICrafting; +import net.minecraft.inventory.Slot; +import net.minecraft.item.ItemStack; +import net.minecraftforge.fluids.FluidStack; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import gregtech.api.interfaces.IFluidAccess; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_BasicTank; +import gregtech.api.util.GT_Utility; + +/** + * NEVER INCLUDE THIS FILE IN YOUR MOD!!! + * <p/> + * The Container I use for all my Basic Tanks + */ +public class GT_Container_BasicTank extends GT_ContainerMetaTile_Machine { + + public int mContent = 0; + protected int oContent = 0; + + public GT_Container_BasicTank(InventoryPlayer aInventoryPlayer, IGregTechTileEntity aTileEntity) { + super(aInventoryPlayer, aTileEntity); + } + + /** + * Subclasses must ensure third slot (aSlotIndex==2) is drainable fluid display item slot. Otherwise, subclasses + * must intercept the appropriate the slotClick event and call super.slotClick(2, xxx) if necessary + */ + @Override + public void addSlots(InventoryPlayer aInventoryPlayer) { + addSlotToContainer(new Slot(mTileEntity, 0, 80, 17)); + addSlotToContainer(new GT_Slot_Output(mTileEntity, 1, 80, 53)); + addSlotToContainer(new GT_Slot_Render(mTileEntity, 2, 59, 42)); + } + + @Override + public ItemStack slotClick(int aSlotIndex, int aMouseclick, int aShifthold, EntityPlayer aPlayer) { + if (aSlotIndex == 2 && aMouseclick < 2) { + GT_MetaTileEntity_BasicTank tTank = (GT_MetaTileEntity_BasicTank) mTileEntity.getMetaTileEntity(); + if (mTileEntity.isClientSide()) { + /* + * While a logical client don't really need to process fluid cells upon click (it could have just wait + * for server side to send the result), doing so would result in every fluid interaction having a + * noticeable delay between clicking and changes happening even on single player. I'd imagine this lag + * to become only more severe when playing MP over ethernet, which would have much more latency than a + * memory connection + */ + Slot slot = inventorySlots.get(aSlotIndex); + tTank.setDrainableStack(GT_Utility.getFluidFromDisplayStack(slot.getStack())); + } + IFluidAccess tDrainableAccess = constructFluidAccess(tTank, false); + return handleFluidSlotClick( + tDrainableAccess, + aPlayer, + aMouseclick == 0, + true, + !tTank.isDrainableStackSeparate()); + } + return super.slotClick(aSlotIndex, aMouseclick, aShifthold, aPlayer); + } + + @Override + public void detectAndSendChanges() { + super.detectAndSendChanges(); + if (mTileEntity.isClientSide() || mTileEntity.getMetaTileEntity() == null) return; + if (((GT_MetaTileEntity_BasicTank) mTileEntity.getMetaTileEntity()).mFluid != null) + mContent = ((GT_MetaTileEntity_BasicTank) mTileEntity.getMetaTileEntity()).mFluid.amount; + else mContent = 0; + sendProgressBar(); + oContent = mContent; + } + + public void sendProgressBar() { + for (ICrafting player : this.crafters) { + if (mTimer % 500 == 0 || oContent != mContent) { + player.sendProgressBarUpdate(this, 100, mContent & 65535); + player.sendProgressBarUpdate(this, 101, mContent >>> 16); + } + } + } + + @Override + @SideOnly(Side.CLIENT) + public void updateProgressBar(int id, int value) { + super.updateProgressBar(id, value); + switch (id) { + case 100 -> mContent = mContent & 0xffff0000 | value & 0x0000ffff; + case 101 -> mContent = mContent & 0xffff | value << 16; + } + } + + @Override + public int getSlotCount() { + return 2; + } + + @Override + public int getShiftClickSlotCount() { + return 1; + } + + protected IFluidAccess constructFluidAccess(GT_MetaTileEntity_BasicTank aTank, boolean aIsFillableStack) { + return new BasicTankFluidAccess(aTank, aIsFillableStack); + } + + static class BasicTankFluidAccess implements IFluidAccess { + + protected final GT_MetaTileEntity_BasicTank mTank; + protected final boolean mIsFillableStack; + + public BasicTankFluidAccess(GT_MetaTileEntity_BasicTank aTank, boolean aIsFillableStack) { + this.mTank = aTank; + this.mIsFillableStack = aIsFillableStack; + } + + @Override + public void set(FluidStack stack) { + if (mIsFillableStack) mTank.setFillableStack(stack); + else mTank.setDrainableStack(stack); + } + + @Override + public FluidStack get() { + return mIsFillableStack ? mTank.getFillableStack() : mTank.getDrainableStack(); + } + + @Override + public int getCapacity() { + return mTank.getCapacity(); + } + } +} diff --git a/src/main/java/gregtech/api/gui/GT_Container_MultiMachine.java b/src/main/java/gregtech/api/gui/GT_Container_MultiMachine.java new file mode 100644 index 0000000000..142b84e008 --- /dev/null +++ b/src/main/java/gregtech/api/gui/GT_Container_MultiMachine.java @@ -0,0 +1,39 @@ +package gregtech.api.gui; + +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.inventory.Slot; + +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; + +/** + * NEVER INCLUDE THIS FILE IN YOUR MOD!!! + * <p/> + * The Container I use for all my Basic Machines + */ +@Deprecated +public class GT_Container_MultiMachine extends GT_ContainerMetaTile_Machine { + + public GT_Container_MultiMachine(InventoryPlayer aInventoryPlayer, IGregTechTileEntity aTileEntity) { + super(aInventoryPlayer, aTileEntity); + } + + public GT_Container_MultiMachine(InventoryPlayer aInventoryPlayer, IGregTechTileEntity aTileEntity, + boolean bindInventory) { + super(aInventoryPlayer, aTileEntity, bindInventory); + } + + @Override + public void addSlots(InventoryPlayer aInventoryPlayer) { + addSlotToContainer(new Slot(mTileEntity, 1, 152, 5)); + } + + @Override + public int getSlotCount() { + return 1; + } + + @Override + public int getShiftClickSlotCount() { + return 1; + } +} diff --git a/src/main/java/gregtech/api/gui/GT_GUIColorOverride.java b/src/main/java/gregtech/api/gui/GT_GUIColorOverride.java new file mode 100644 index 0000000000..304e792a2a --- /dev/null +++ b/src/main/java/gregtech/api/gui/GT_GUIColorOverride.java @@ -0,0 +1,92 @@ +package gregtech.api.gui; + +import java.util.concurrent.ExecutionException; + +import javax.annotation.Nonnull; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.resources.IResource; +import net.minecraft.util.ResourceLocation; + +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; +import com.google.common.util.concurrent.UncheckedExecutionException; + +import cpw.mods.fml.relauncher.FMLLaunchHandler; +import cpw.mods.fml.relauncher.Side; +import gregtech.api.GregTech_API; +import gregtech.api.util.ColorsMetadataSection; + +public class GT_GUIColorOverride { + + private static final Object NOT_FOUND = new Object(); + private static final LoadingCache<ResourceLocation, Object> cache = CacheBuilder.newBuilder() + .softValues() + .build(new CacheLoader<>() { + + @Override + public Object load(@Nonnull ResourceLocation key) throws Exception { + IResource ir = Minecraft.getMinecraft() + .getResourceManager() + .getResource(key); + if (ir.hasMetadata()) return ir.getMetadata("colors"); + // return a dummy + // object because + // LoadingCache + // doesn't like null + return NOT_FOUND; + } + }); + private static final GT_GUIColorOverride FALLBACK = new GT_GUIColorOverride(); + private ColorsMetadataSection cmSection; + + public static GT_GUIColorOverride get(String fullLocation) { + // see other get for more info + if (FMLLaunchHandler.side() != Side.CLIENT) return FALLBACK; + return new GT_GUIColorOverride(new ResourceLocation(fullLocation)); + } + + public static GT_GUIColorOverride get(ResourceLocation path) { + // use dummy fallback if there isn't such thing as a resource pack. + // #side() usually has two possible return value, but since this might be called by test code, it might + // also return null when in test env. Using #isClient will cause a NPE. A plain inequality test won't. + // FMLCommonHandler's #getSide() might trigger a NPE when in test env, so no. + if (FMLLaunchHandler.side() != Side.CLIENT) return FALLBACK; + return new GT_GUIColorOverride(path); + } + + private GT_GUIColorOverride() { + cmSection = null; + } + + private GT_GUIColorOverride(ResourceLocation resourceLocation) { + try { + Object metadata = cache.get(resourceLocation); + if (metadata != NOT_FOUND) cmSection = (ColorsMetadataSection) metadata; + } catch (ExecutionException | UncheckedExecutionException ignore) { + // make sure it doesn't cache a failing entry + cache.invalidate(resourceLocation); + } + } + + public int getTextColorOrDefault(String textType, int defaultColor) { + return sLoaded() ? cmSection.getTextColorOrDefault(textType, defaultColor) : defaultColor; + } + + public int getGuiTintOrDefault(String key, int defaultColor) { + return sLoaded() ? cmSection.getGuiTintOrDefault(key, defaultColor) : defaultColor; + } + + public boolean sGuiTintingEnabled() { + return sLoaded() ? cmSection.sGuiTintingEnabled() : GregTech_API.sColoredGUI; + } + + public boolean sLoaded() { + return cmSection != null; + } + + public static void onResourceManagerReload() { + cache.invalidateAll(); + } +} diff --git a/src/main/java/gregtech/api/gui/GT_GUIContainer.java b/src/main/java/gregtech/api/gui/GT_GUIContainer.java new file mode 100644 index 0000000000..639bd56162 --- /dev/null +++ b/src/main/java/gregtech/api/gui/GT_GUIContainer.java @@ -0,0 +1,99 @@ +package gregtech.api.gui; + +import static gregtech.GT_Mod.GT_FML_LOGGER; + +import net.minecraft.client.gui.inventory.GuiContainer; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.inventory.Container; +import net.minecraft.inventory.Slot; +import net.minecraft.util.ResourceLocation; + +import org.lwjgl.input.Mouse; + +/** + * NEVER INCLUDE THIS FILE IN YOUR MOD!!! + * <p/> + * Main GUI-Container-Class which basically contains the Code needed to prevent crashes from improperly Coded Items. + */ +public class GT_GUIContainer extends GuiContainer { + + public boolean mCrashed = false; + + public ResourceLocation mGUIbackground; + + public GT_GUIColorOverride colorOverride; + + public String mGUIbackgroundPath; + + public GT_GUIContainer(Container aContainer, String aGUIbackground) { + super(aContainer); + mGUIbackground = new ResourceLocation(mGUIbackgroundPath = aGUIbackground); + colorOverride = GT_GUIColorOverride.get(aGUIbackground); + } + + protected int getTextColorOrDefault(String textType, int defaultColor) { + return colorOverride.getTextColorOrDefault(textType, defaultColor); + } + + public int getLeft() { + return guiLeft; + } + + public int getTop() { + return guiTop; + } + + @Override + protected void drawGuiContainerForegroundLayer(int mouseX, int mouseY) { + // + } + + @Override + protected void drawGuiContainerBackgroundLayer(float parTicks, int mouseX, int mouseY) { + mc.renderEngine.bindTexture(mGUIbackground); + } + + @Override + public void drawScreen(int mouseX, int mouseY, float parTicks) { + try { + super.drawScreen(mouseX, mouseY, parTicks); + } catch (Throwable e) { + try { + Tessellator.instance.draw(); + } catch (Throwable f) { + // + } + } + } + + @Override + public void handleMouseInput() { + int delta = Mouse.getEventDWheel(); + if (delta != 0) { + int i = Mouse.getEventX() * this.width / this.mc.displayWidth; + int j = this.height - Mouse.getEventY() * this.height / this.mc.displayHeight - 1; + onMouseWheel(i, j, delta); + } + super.handleMouseInput(); + } + + protected void onMouseWheel(int mx, int my, int delta) {} + + public boolean isMouseOverSlot(int slotIndex, int mx, int my) { + int size = inventorySlots.inventorySlots.size(); + if (slotIndex < 0 || slotIndex >= size) { + // slot does not exist somehow. log and carry on + GT_FML_LOGGER.error("Slot {} required where only {} is present", slotIndex, size); + return false; + } + Slot slot = inventorySlots.getSlot(slotIndex); + return this.func_146978_c(slot.xDisplayPosition, slot.yDisplayPosition, 16, 16, mx, my); + } + + /* + * @Override protected void drawSlotInventory(Slot slot) { try { super.drawSlotInventory(slot); } catch(Throwable e) + * { try { Tessellator.instance.draw(); } catch(Throwable f) {} if (!mCrashed) { GT_Log.out. + * println("Clientside Slot drawing Crash prevented. Seems one Itemstack causes Problems with negative Damage Values or the Wildcard Damage Value. This is absolutely NOT a Bug of the GregTech-Addon, so don't even think about reporting it to me, it's a Bug of the Mod, which belongs to the almost-crash-causing Item, so bug that Mods Author and not me! Did you hear it? NOT ME!!!" + * ); e.printStackTrace(); mCrashed = true; } } } + */ +} diff --git a/src/main/java/gregtech/api/gui/GT_GUIContainerMetaTile_Machine.java b/src/main/java/gregtech/api/gui/GT_GUIContainerMetaTile_Machine.java new file mode 100644 index 0000000000..df395858a9 --- /dev/null +++ b/src/main/java/gregtech/api/gui/GT_GUIContainerMetaTile_Machine.java @@ -0,0 +1,271 @@ +package gregtech.api.gui; + +import java.util.List; + +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.renderer.entity.RenderItem; +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.inventory.Slot; +import net.minecraft.item.ItemStack; +import net.minecraft.util.StatCollector; + +import org.lwjgl.opengl.GL11; + +import gregtech.GT_Mod; +import gregtech.api.GregTech_API; +import gregtech.api.enums.Dyes; +import gregtech.api.enums.GT_Values; +import gregtech.api.gui.widgets.GT_GuiCoverTabLine; +import gregtech.api.gui.widgets.GT_GuiIcon; +import gregtech.api.gui.widgets.GT_GuiSlotTooltip; +import gregtech.api.gui.widgets.GT_GuiTabLine.DisplayStyle; +import gregtech.api.gui.widgets.GT_GuiTabLine.GT_GuiTabIconSet; +import gregtech.api.gui.widgets.GT_GuiTabLine.GT_ITabRenderer; +import gregtech.api.gui.widgets.GT_GuiTooltip; +import gregtech.api.gui.widgets.GT_GuiTooltipManager; +import gregtech.api.gui.widgets.GT_GuiTooltipManager.GT_IToolTipRenderer; +import gregtech.api.interfaces.IConfigurationCircuitSupport; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.MetaTileEntity; +import gregtech.api.net.GT_Packet_SetConfigurationCircuit; +import gregtech.api.util.GT_TooltipDataCache; +import gregtech.api.util.GT_Util; +import gregtech.api.util.GT_Utility; + +/** + * NEVER INCLUDE THIS FILE IN YOUR MOD!!! + * <p/> + * The GUI-Container I use for all my MetaTileEntities + */ +public class GT_GUIContainerMetaTile_Machine extends GT_GUIContainer implements GT_IToolTipRenderer, GT_ITabRenderer { + + public final GT_ContainerMetaTile_Machine mContainer; + + protected final GT_GuiTooltipManager mTooltipManager = new GT_GuiTooltipManager(); + protected final GT_TooltipDataCache mTooltipCache = new GT_TooltipDataCache(); + private static final String GHOST_CIRCUIT_TOOLTIP = "GT5U.machines.select_circuit.tooltip"; + + private final int guiTint; + + // Cover Tabs support. Subclasses can override display position, style and visuals by overriding setupCoverTabs + public GT_GuiCoverTabLine coverTabs; + private static final int COVER_TAB_LEFT = -16, COVER_TAB_TOP = 1, COVER_TAB_HEIGHT = 20, COVER_TAB_WIDTH = 18, + COVER_TAB_SPACING = 2; + private static final DisplayStyle COVER_TAB_X_DIR = DisplayStyle.NONE, COVER_TAB_Y_DIR = DisplayStyle.NORMAL; + private static final GT_GuiTabIconSet TAB_ICONSET = new GT_GuiTabIconSet( + GT_GuiIcon.TAB_NORMAL, + GT_GuiIcon.TAB_HIGHLIGHT, + GT_GuiIcon.TAB_DISABLED); + + public GT_GUIContainerMetaTile_Machine(GT_ContainerMetaTile_Machine aContainer, String aGUIbackground) { + super(aContainer, aGUIbackground); + mContainer = aContainer; + + DisplayStyle preferredDisplayStyle = GT_Mod.gregtechproxy.mCoverTabsVisible + ? (GT_Mod.gregtechproxy.mCoverTabsFlipped ? DisplayStyle.INVERSE : DisplayStyle.NORMAL) + : DisplayStyle.NONE; + setupCoverTabs(preferredDisplayStyle); + + // Only setup tooltips if they're currently enabled. + if (GT_Mod.gregtechproxy.mTooltipVerbosity > 0 || GT_Mod.gregtechproxy.mTooltipShiftVerbosity > 0) { + setupTooltips(); + } + + guiTint = getColorization(); + mContainer.setCircuitSlotClickCallback(this::openSelectCircuitDialog); + } + + public GT_GUIContainerMetaTile_Machine(InventoryPlayer aInventoryPlayer, IGregTechTileEntity aTileEntity, + String aGUIbackground) { + this(new GT_ContainerMetaTile_Machine(aInventoryPlayer, aTileEntity), aGUIbackground); + } + + /** + * Initialize the coverTabs object according to client preferences + */ + protected void setupCoverTabs(DisplayStyle preferredDisplayStyle) { + coverTabs = new GT_GuiCoverTabLine( + this, + COVER_TAB_LEFT, + COVER_TAB_TOP, + COVER_TAB_HEIGHT, + COVER_TAB_WIDTH, + COVER_TAB_SPACING, + COVER_TAB_X_DIR, + COVER_TAB_Y_DIR, + preferredDisplayStyle, + getTabBackground(), + getMachine().getBaseMetaTileEntity(), + getColorization()); + } + + @Override + public void drawScreen(int mouseX, int mouseY, float parTicks) { + super.drawScreen(mouseX, mouseY, parTicks); + if (mc.thePlayer.inventory.getItemStack() == null) { + GL11.glPushMatrix(); + GL11.glTranslatef(guiLeft, guiTop, 0.0F); + mTooltipManager.onTick(this, mouseX, mouseY); + GL11.glPopMatrix(); + } + } + + @Override + protected void drawGuiContainerBackgroundLayer(float parTicks, int mouseX, int mouseY) { + // Drawing tabs + coverTabs.drawTabs(parTicks, mouseX, mouseY); + + // Applying machine coloration, which subclasses rely on + GL11.glColor3ub((byte) ((guiTint >> 16) & 0xFF), (byte) ((guiTint >> 8) & 0xFF), (byte) (guiTint & 0xFF)); + + // Binding machine's own texture, which subclasses rely on being set + super.drawGuiContainerBackgroundLayer(parTicks, mouseX, mouseY); + } + + /** + * @return The color used to render this machine's GUI + */ + private int getColorization() { + Dyes dye = Dyes.dyeWhite; + if (this.colorOverride.sLoaded()) { + if (this.colorOverride.sGuiTintingEnabled()) { + dye = getDyeFromIndex(mContainer.mTileEntity.getColorization()); + return this.colorOverride.getGuiTintOrDefault(dye.mName, GT_Util.getRGBInt(dye.getRGBA())); + } + } else if (GregTech_API.sColoredGUI) { + if (GregTech_API.sMachineMetalGUI) { + dye = Dyes.MACHINE_METAL; + } else if (mContainer != null && mContainer.mTileEntity != null) { + dye = getDyeFromIndex(mContainer.mTileEntity.getColorization()); + } + } + return GT_Util.getRGBInt(dye.getRGBA()); + } + + private Dyes getDyeFromIndex(short index) { + return index != -1 ? Dyes.get(index) : Dyes.MACHINE_METAL; + } + + /** + * @return This machine's MetaTileEntity + */ + private MetaTileEntity getMachine() { + return (MetaTileEntity) mContainer.mTileEntity.getMetaTileEntity(); + } + + // Tabs support + + @Override + protected void mouseClicked(int mouseX, int mouseY, int mouseButton) { + super.mouseClicked(mouseX, mouseY, mouseButton); + // Check for clicked tabs + coverTabs.onMouseClicked(mouseX, mouseY, mouseButton); + } + + @Override + public void initGui() { + super.initGui(); + // Perform layout of tabs + coverTabs.onInit(); + } + + /** + * @return the background textures used by this machine GUI's tabs + */ + protected GT_GuiTabIconSet getTabBackground() { + return TAB_ICONSET; + } + + // Tooltips support + + /** + * Load data for and create appropriate tooltips for this machine. Only called when one of regular or shift tooltips + * are enabled. + */ + protected void setupTooltips() { + if (mContainer.mTileEntity.getMetaTileEntity() instanceof IConfigurationCircuitSupport ccs) { + if (ccs.allowSelectCircuit()) addToolTip( + new GT_GuiSlotTooltip( + mContainer.getSlot(ccs.getCircuitGUISlot()), + mTooltipCache.getData(GHOST_CIRCUIT_TOOLTIP))); + } + } + + // GT_IToolTipRenderer and GT_ITabRenderer implementations + @Override + public void drawHoveringText(List<String> text, int mouseX, int mouseY, FontRenderer font) { + super.drawHoveringText(text, mouseX, mouseY, font); + } + + @Override + public int getGuiTop() { + return guiTop; + } + + @Override + public int getGuiLeft() { + return guiLeft; + } + + @Override + public int getXSize() { + return xSize; + } + + @Override + public FontRenderer getFontRenderer() { + return fontRendererObj; + } + + @Override + public RenderItem getItemRenderer() { + return itemRender; + } + + @Override + public void addToolTip(GT_GuiTooltip toolTip) { + mTooltipManager.addToolTip(toolTip); + } + + @Override + public boolean removeToolTip(GT_GuiTooltip toolTip) { + return mTooltipManager.removeToolTip(toolTip); + } + + @Override + protected void onMouseWheel(int mx, int my, int delta) { + if (mContainer.mTileEntity.getMetaTileEntity() instanceof IConfigurationCircuitSupport ccs) { + Slot slotCircuit = mContainer.getSlot(ccs.getCircuitGUISlot()); + if (slotCircuit != null + && func_146978_c(slotCircuit.xDisplayPosition, slotCircuit.yDisplayPosition, 16, 16, mx, my)) { + // emulate click + handleMouseClick(slotCircuit, -1, delta > 0 ? 1 : 0, 0); + return; + } + } + super.onMouseWheel(mx, my, delta); + } + + private void openSelectCircuitDialog() { + IMetaTileEntity machine = mContainer.mTileEntity.getMetaTileEntity(); + IConfigurationCircuitSupport ccs = (IConfigurationCircuitSupport) machine; + List<ItemStack> circuits = ccs.getConfigurationCircuits(); + mc.displayGuiScreen( + new GT_GUIDialogSelectItem( + StatCollector.translateToLocal("GT5U.machines.select_circuit"), + machine.getStackForm(0), + this, + this::onCircuitSelected, + circuits, + GT_Utility.findMatchingStackInList(circuits, machine.getStackInSlot(ccs.getCircuitSlot())))); + } + + private void onCircuitSelected(ItemStack selected) { + GT_Values.NW.sendToServer(new GT_Packet_SetConfigurationCircuit(mContainer.mTileEntity, selected)); + // we will not do any validation on client side + // it doesn't get to actually decide what inventory contains anyway + IConfigurationCircuitSupport ccs = (IConfigurationCircuitSupport) mContainer.mTileEntity.getMetaTileEntity(); + mContainer.mTileEntity.setInventorySlotContents(ccs.getCircuitSlot(), selected); + } +} diff --git a/src/main/java/gregtech/api/gui/GT_GUIContainer_1by1.java b/src/main/java/gregtech/api/gui/GT_GUIContainer_1by1.java new file mode 100644 index 0000000000..5bd44668c5 --- /dev/null +++ b/src/main/java/gregtech/api/gui/GT_GUIContainer_1by1.java @@ -0,0 +1,42 @@ +package gregtech.api.gui; + +import static gregtech.api.enums.Mods.GregTech; + +import net.minecraft.entity.player.InventoryPlayer; + +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; + +@Deprecated +public class GT_GUIContainer_1by1 extends GT_GUIContainerMetaTile_Machine { + + private final String mName; + private final int textColor = this.getTextColorOrDefault("title", 0x404040); + + public GT_GUIContainer_1by1(InventoryPlayer aInventoryPlayer, IGregTechTileEntity aTileEntity, String aName) { + super( + new GT_Container_1by1(aInventoryPlayer, aTileEntity), + GregTech.getResourcePath("textures", "gui", "1by1.png")); + mName = aName; + } + + public GT_GUIContainer_1by1(InventoryPlayer aInventoryPlayer, IGregTechTileEntity aTileEntity, String aName, + String aBackground) { + super( + new GT_Container_1by1(aInventoryPlayer, aTileEntity), + GregTech.getResourcePath("textures", "gui", aBackground + "1by1.png")); + mName = aName; + } + + @Override + protected void drawGuiContainerForegroundLayer(int mouseX, int mouseY) { + fontRendererObj.drawString(mName, 8, 4, textColor); + } + + @Override + protected void drawGuiContainerBackgroundLayer(float parTicks, int mouseX, int mouseY) { + super.drawGuiContainerBackgroundLayer(parTicks, mouseX, mouseY); + int x = (width - xSize) / 2; + int y = (height - ySize) / 2; + drawTexturedModalRect(x, y, 0, 0, xSize, ySize); + } +} diff --git a/src/main/java/gregtech/api/gui/GT_GUIContainer_2by2.java b/src/main/java/gregtech/api/gui/GT_GUIContainer_2by2.java new file mode 100644 index 0000000000..107bcc3859 --- /dev/null +++ b/src/main/java/gregtech/api/gui/GT_GUIContainer_2by2.java @@ -0,0 +1,42 @@ +package gregtech.api.gui; + +import static gregtech.api.enums.Mods.GregTech; + +import net.minecraft.entity.player.InventoryPlayer; + +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; + +@Deprecated +public class GT_GUIContainer_2by2 extends GT_GUIContainerMetaTile_Machine { + + private final String mName; + private final int textColor = this.getTextColorOrDefault("title", 0x404040); + + public GT_GUIContainer_2by2(InventoryPlayer aInventoryPlayer, IGregTechTileEntity aTileEntity, String aName) { + super( + new GT_Container_2by2(aInventoryPlayer, aTileEntity), + GregTech.getResourcePath("textures", "gui", "2by2.png")); + mName = aName; + } + + public GT_GUIContainer_2by2(InventoryPlayer aInventoryPlayer, IGregTechTileEntity aTileEntity, String aName, + String aBackground) { + super( + new GT_Container_2by2(aInventoryPlayer, aTileEntity), + GregTech.getResourcePath("textures", "gui", aBackground + "2by2.png")); + mName = aName; + } + + @Override + protected void drawGuiContainerForegroundLayer(int mouseX, int mouseY) { + fontRendererObj.drawString(mName, 8, 4, textColor); + } + + @Override + protected void drawGuiContainerBackgroundLayer(float parTicks, int mouseX, int mouseY) { + super.drawGuiContainerBackgroundLayer(parTicks, mouseX, mouseY); + int x = (width - xSize) / 2; + int y = (height - ySize) / 2; + drawTexturedModalRect(x, y, 0, 0, xSize, ySize); + } +} diff --git a/src/main/java/gregtech/api/gui/GT_GUIContainer_3by3.java b/src/main/java/gregtech/api/gui/GT_GUIContainer_3by3.java new file mode 100644 index 0000000000..0c8b63664a --- /dev/null +++ b/src/main/java/gregtech/api/gui/GT_GUIContainer_3by3.java @@ -0,0 +1,42 @@ +package gregtech.api.gui; + +import static gregtech.api.enums.Mods.GregTech; + +import net.minecraft.entity.player.InventoryPlayer; + +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; + +@Deprecated +public class GT_GUIContainer_3by3 extends GT_GUIContainerMetaTile_Machine { + + private final String mName; + private final int textColor = this.getTextColorOrDefault("title", 0x404040); + + public GT_GUIContainer_3by3(InventoryPlayer aInventoryPlayer, IGregTechTileEntity aTileEntity, String aName) { + super( + new GT_Container_3by3(aInventoryPlayer, aTileEntity), + GregTech.getResourcePath("textures", "gui", "3by3.png")); + mName = aName; + } + + public GT_GUIContainer_3by3(InventoryPlayer aInventoryPlayer, IGregTechTileEntity aTileEntity, String aName, + String aBackground) { + super( + new GT_Container_3by3(aInventoryPlayer, aTileEntity), + GregTech.getResourcePath("textures", "gui", aBackground + "3by3.png")); + mName = aName; + } + + @Override + protected void drawGuiContainerForegroundLayer(int mouseX, int mouseY) { + fontRendererObj.drawString(mName, 8, 4, textColor); + } + + @Override + protected void drawGuiContainerBackgroundLayer(float parTicks, int mouseX, int mouseY) { + super.drawGuiContainerBackgroundLayer(parTicks, mouseX, mouseY); + int x = (width - xSize) / 2; + int y = (height - ySize) / 2; + drawTexturedModalRect(x, y, 0, 0, xSize, ySize); + } +} diff --git a/src/main/java/gregtech/api/gui/GT_GUIContainer_4by4.java b/src/main/java/gregtech/api/gui/GT_GUIContainer_4by4.java new file mode 100644 index 0000000000..9e5d7f7155 --- /dev/null +++ b/src/main/java/gregtech/api/gui/GT_GUIContainer_4by4.java @@ -0,0 +1,42 @@ +package gregtech.api.gui; + +import static gregtech.api.enums.Mods.GregTech; + +import net.minecraft.entity.player.InventoryPlayer; + +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; + +@Deprecated +public class GT_GUIContainer_4by4 extends GT_GUIContainerMetaTile_Machine { + + private final String mName; + private final int textColor = this.getTextColorOrDefault("title", 0x404040); + + public GT_GUIContainer_4by4(InventoryPlayer aInventoryPlayer, IGregTechTileEntity aTileEntity, String aName) { + super( + new GT_Container_4by4(aInventoryPlayer, aTileEntity), + GregTech.getResourcePath("textures", "gui", "4by4.png")); + mName = aName; + } + + public GT_GUIContainer_4by4(InventoryPlayer aInventoryPlayer, IGregTechTileEntity aTileEntity, String aName, + String aBackground) { + super( + new GT_Container_4by4(aInventoryPlayer, aTileEntity), + GregTech.getResourcePath("textures", "gui", aBackground + "4by4.png")); + mName = aName; + } + + @Override + protected void drawGuiContainerForegroundLayer(int mouseX, int mouseY) { + fontRendererObj.drawString(mName, 8, 4, textColor); + } + + @Override + protected void drawGuiContainerBackgroundLayer(float parTicks, int mouseX, int mouseY) { + super.drawGuiContainerBackgroundLayer(parTicks, mouseX, mouseY); + int x = (width - xSize) / 2; + int y = (height - ySize) / 2; + drawTexturedModalRect(x, y, 0, 0, xSize, ySize); + } +} diff --git a/src/main/java/gregtech/api/gui/GT_GUIContainer_BasicTank.java b/src/main/java/gregtech/api/gui/GT_GUIContainer_BasicTank.java new file mode 100644 index 0000000000..54aa42d2a3 --- /dev/null +++ b/src/main/java/gregtech/api/gui/GT_GUIContainer_BasicTank.java @@ -0,0 +1,47 @@ +package gregtech.api.gui; + +import static gregtech.api.enums.Mods.GregTech; + +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.util.StatCollector; + +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.util.GT_Utility; + +public class GT_GUIContainer_BasicTank extends GT_GUIContainerMetaTile_Machine { + + private final String mName; + private final int textColor = this.getTextColorOrDefault("text", 0xFAFAFF), + textColorTitle = this.getTextColorOrDefault("title", 0x404040), + textColorValue = this.getTextColorOrDefault("value", 0xFAFAFF); + + public GT_GUIContainer_BasicTank(InventoryPlayer aInventoryPlayer, IGregTechTileEntity aTileEntity, String aName) { + super( + new GT_Container_BasicTank(aInventoryPlayer, aTileEntity), + GregTech.getResourcePath("textures", "gui", "BasicTank.png")); + mName = aName; + } + + @Override + protected void drawGuiContainerForegroundLayer(int mouseX, int mouseY) { + fontRendererObj + .drawString(StatCollector.translateToLocal("container.inventory"), 8, ySize - 96 + 2, textColorTitle); + fontRendererObj.drawString(mName, 8, 6, textColorTitle); + if (mContainer != null) { + fontRendererObj.drawString("Liquid Amount", 10, 20, textColor); + fontRendererObj.drawString( + GT_Utility.parseNumberToString(((GT_Container_BasicTank) mContainer).mContent), + 10, + 30, + textColorValue); + } + } + + @Override + protected void drawGuiContainerBackgroundLayer(float parTicks, int mouseX, int mouseY) { + super.drawGuiContainerBackgroundLayer(parTicks, mouseX, mouseY); + int x = (width - xSize) / 2; + int y = (height - ySize) / 2; + drawTexturedModalRect(x, y, 0, 0, xSize, ySize); + } +} diff --git a/src/main/java/gregtech/api/gui/GT_GUIContainer_MultiMachine.java b/src/main/java/gregtech/api/gui/GT_GUIContainer_MultiMachine.java new file mode 100644 index 0000000000..3d9515b19a --- /dev/null +++ b/src/main/java/gregtech/api/gui/GT_GUIContainer_MultiMachine.java @@ -0,0 +1,173 @@ +package gregtech.api.gui; + +import static gregtech.api.enums.Mods.GregTech; + +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.item.ItemStack; + +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.util.GT_ModHandler; +import gregtech.api.util.GT_Utility; +import gregtech.common.items.GT_MetaGenerated_Tool_01; +import gregtech.common.tileentities.machines.multi.GT_MetaTileEntity_DrillerBase; +import gregtech.common.tileentities.machines.multi.GT_MetaTileEntity_LargeTurbine; + +/** + * NEVER INCLUDE THIS FILE IN YOUR MOD!!! + * <p/> + * The GUI-Container I use for all my Basic Machines + */ +@Deprecated +public class GT_GUIContainer_MultiMachine extends GT_GUIContainerMetaTile_Machine { + + final String mName; + private final int textColor = this.getTextColorOrDefault("text", 0xFAFAFF), + textColorTitle = this.getTextColorOrDefault("title", 0xFAFAFF); + + public GT_GUIContainer_MultiMachine(InventoryPlayer aInventoryPlayer, IGregTechTileEntity aTileEntity, String aName, + String aTextureFile) { + super( + new GT_Container_MultiMachine(aInventoryPlayer, aTileEntity), + GregTech.getResourcePath( + "textures", + "gui", + "multimachines", + aTextureFile == null ? "MultiblockDisplay" : aTextureFile)); + mName = aName; + } + + @Override + protected void drawGuiContainerForegroundLayer(int mouseX, int mouseY) { + + // If text is drawn iterate down GUI 8 pixels (height of characters). + int line_counter = 7; + int max_chars_per_line = 26; + + if (mName.length() > 26) { + + // Split the machine name into an array, so we can try fit it on one line but if not use more. + String[] split = mName.split(" "); + + int total_line_length = 0; + StringBuilder current_line = new StringBuilder(); + + int index = 0; + + for (String str : split) { + + total_line_length += str.length(); + + if (total_line_length > max_chars_per_line) { + fontRendererObj.drawString(current_line.toString(), 10, line_counter, textColorTitle); + line_counter += 8; + current_line = new StringBuilder(); + index = 0; + total_line_length = str.length(); + } + + if (index == 0) { + current_line.append(str); + } else { + current_line.append(" ") + .append(str); + } + index++; + } + fontRendererObj.drawString(current_line.toString(), 10, line_counter, textColorTitle); + } else { + fontRendererObj.drawString(mName, 10, line_counter, textColorTitle); + } + line_counter += 8; + + if (mContainer != null) { // (mWrench ? 0 : 1) | (mScrewdriver ? 0 : 2) | (mSoftHammer ? 0 : 4) | (mHardHammer ? + // 0 : 8) + // | (mSolderingTool ? 0 : 16) | (mCrowbar ? 0 : 32) | (mMachine ? 0 : 64)); + if ((mContainer.mDisplayErrorCode & 1) != 0) { + fontRendererObj.drawString(GT_Utility.trans("132", "Pipe is loose."), 10, line_counter, textColor); + line_counter += 8; + } + + if ((mContainer.mDisplayErrorCode & 2) != 0) { + fontRendererObj.drawString(GT_Utility.trans("133", "Screws are loose."), 10, line_counter, textColor); + line_counter += 8; + } + + if ((mContainer.mDisplayErrorCode & 4) != 0) { + fontRendererObj.drawString(GT_Utility.trans("134", "Something is stuck."), 10, line_counter, textColor); + line_counter += 8; + } + + if ((mContainer.mDisplayErrorCode & 8) != 0) { + fontRendererObj + .drawString(GT_Utility.trans("135", "Platings are dented."), 10, line_counter, textColor); + line_counter += 8; + } + + if ((mContainer.mDisplayErrorCode & 16) != 0) { + fontRendererObj + .drawString(GT_Utility.trans("136", "Circuitry burned out."), 10, line_counter, textColor); + line_counter += 8; + } + + if ((mContainer.mDisplayErrorCode & 32) != 0) { + fontRendererObj + .drawString(GT_Utility.trans("137", "That doesn't belong there."), 10, line_counter, textColor); + line_counter += 8; + } + + if ((mContainer.mDisplayErrorCode & 64) != 0) { + fontRendererObj + .drawString(GT_Utility.trans("138", "Incomplete Structure."), 10, line_counter, textColor); + line_counter += 8; + } + + if (mContainer.mDisplayErrorCode == 0) { + if (mContainer.mActive == 0) { + fontRendererObj + .drawString(GT_Utility.trans("139", "Hit with Soft Mallet"), 10, line_counter, textColor); + line_counter += 8; + fontRendererObj + .drawString(GT_Utility.trans("140", "to (re-)start the Machine"), 10, line_counter, textColor); + line_counter += 8; + fontRendererObj + .drawString(GT_Utility.trans("141", "if it doesn't start."), 10, line_counter, textColor); + } else { + fontRendererObj + .drawString(GT_Utility.trans("142", "Running perfectly."), 10, line_counter, textColor); + } + line_counter += 8; + if (mContainer.mTileEntity.getMetaTileEntity() instanceof GT_MetaTileEntity_DrillerBase) { + ItemStack tItem = mContainer.mTileEntity.getMetaTileEntity() + .getStackInSlot(1); + if (tItem == null + || !GT_Utility.areStacksEqual(tItem, GT_ModHandler.getIC2Item("miningPipe", 1L))) { + fontRendererObj + .drawString(GT_Utility.trans("143", "Missing Mining Pipe"), 10, line_counter, textColor); + } + } else if (mContainer.mTileEntity.getMetaTileEntity() instanceof GT_MetaTileEntity_LargeTurbine) { + ItemStack tItem = mContainer.mTileEntity.getMetaTileEntity() + .getStackInSlot(1); + if (tItem == null + || !(tItem.getItem() == GT_MetaGenerated_Tool_01.INSTANCE && tItem.getItemDamage() >= 170 + && tItem.getItemDamage() <= 177)) { + fontRendererObj + .drawString(GT_Utility.trans("144", "Missing Turbine Rotor"), 10, line_counter, textColor); + } + } + } + } + } + + @Deprecated + public String trans(String aKey, String aEnglish) { + return GT_Utility.trans(aKey, aEnglish); + } + + @Override + protected void drawGuiContainerBackgroundLayer(float parTicks, int mouseX, int mouseY) { + super.drawGuiContainerBackgroundLayer(parTicks, mouseX, mouseY); + int x = (width - xSize) / 2; + int y = (height - ySize) / 2; + drawTexturedModalRect(x, y, 0, 0, xSize, ySize); + } +} diff --git a/src/main/java/gregtech/api/gui/GT_GUICover.java b/src/main/java/gregtech/api/gui/GT_GUICover.java new file mode 100644 index 0000000000..5729ada685 --- /dev/null +++ b/src/main/java/gregtech/api/gui/GT_GUICover.java @@ -0,0 +1,55 @@ +package gregtech.api.gui; + +import net.minecraft.item.ItemStack; + +import gregtech.api.enums.GT_Values; +import gregtech.api.interfaces.tileentity.ICoverable; +import gregtech.api.net.GT_Packet_GtTileEntityGuiRequest; + +@Deprecated +public abstract class GT_GUICover extends GT_GUIScreen { + + public final ICoverable tile; + public int parentGuiId = -1; + + public GT_GUICover(ICoverable tile, int width, int height, ItemStack cover) { + super(width, height, cover == null ? "" : cover.getDisplayName()); + this.tile = tile; + headerIcon.setItem(cover); + } + + @Override + public void updateScreen() { + super.updateScreen(); + if (!tile.isUseableByPlayer(mc.thePlayer)) { + closeScreen(); + } + } + + /** + * The parent GUI to exit to. -1 is ignored. + * + * @param parentGuiId parent GUI ID + */ + public void setParentGuiId(int parentGuiId) { + this.parentGuiId = parentGuiId; + } + + @Override + public void closeScreen() { + // If this cover was given a guiId, tell the server to open it for us when this GUI closes. + if (parentGuiId != -1 && tile.isUseableByPlayer(mc.thePlayer)) { + GT_Values.NW.sendToServer( + new GT_Packet_GtTileEntityGuiRequest( + tile.getXCoord(), + tile.getYCoord(), + tile.getZCoord(), + parentGuiId, + tile.getWorld().provider.dimensionId, + mc.thePlayer.getEntityId())); + } else { + this.mc.displayGuiScreen(null); + this.mc.setIngameFocus(); + } + } +} diff --git a/src/main/java/gregtech/api/gui/GT_GUIDialogSelectItem.java b/src/main/java/gregtech/api/gui/GT_GUIDialogSelectItem.java new file mode 100644 index 0000000000..03a6fb2a70 --- /dev/null +++ b/src/main/java/gregtech/api/gui/GT_GUIDialogSelectItem.java @@ -0,0 +1,229 @@ +package gregtech.api.gui; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; + +import net.minecraft.client.gui.GuiButton; +import net.minecraft.client.gui.GuiScreen; +import net.minecraft.item.ItemStack; +import net.minecraft.util.StatCollector; + +import gregtech.api.gui.widgets.GT_GuiFakeItemButton; +import gregtech.api.gui.widgets.GT_GuiIcon; +import gregtech.api.gui.widgets.GT_GuiIconButton; +import gregtech.api.util.GT_Utility; + +@Deprecated +public class GT_GUIDialogSelectItem extends GT_GUIScreen { + + public static final int UNSELECTED = -1; + private static final int cols = 9; + private static final int rows = 3; + private final int textColor = this.getTextColorOrDefault("text", 0xff555555); + private final GuiScreen parent; + private final Consumer<ItemStack> selectedCallback; + // passed in stack + private final List<ItemStack> stacks; + // all slots not including btnCurrent + private final List<GT_GuiFakeItemButton> slots = new ArrayList<>(); + // the currently selected slot content + private final GT_GuiFakeItemButton btnCurrent = new GT_GuiFakeItemButton(this, 8, 25, GT_GuiIcon.SLOT_DARKGRAY) + .setMimicSlot(true); + private final boolean noDeselect; + private int selected; + private int scroll = 0; + private GT_GuiIconButton btnUp; + private GT_GuiIconButton btnDown; + + public GT_GUIDialogSelectItem(String header, ItemStack headerItem, GuiScreen parent, + Consumer<ItemStack> selectedCallback, List<ItemStack> stacks) { + this(header, headerItem, parent, selectedCallback, stacks, UNSELECTED); + } + + public GT_GUIDialogSelectItem(String header, ItemStack headerItem, GuiScreen parent, + Consumer<ItemStack> selectedCallback, List<ItemStack> stacks, int selected) { + this(header, headerItem, parent, selectedCallback, stacks, selected, false); + } + + /** + * Open a dialog to select an item from given list. Given callback may be called zero or more times depending on + * user action. + * + * @param header Header text + * @param headerItem ItemStack to use as Dialog icon + * @param parent open which GUIScreen when this dialog is closed. use null if it has no parent. + * @param selectedCallback callback upon selected + * @param stacks list to choose from + * @param selected preselected item. Use {@link #UNSELECTED} for unselected. Invalid selected will be + * clamped to 0 or highest index + * @param noDeselect true if player cannot deselect, false otherwise. If this is set to true, selectedCallback + * is guaranteed to be called with a nonnull stack + */ + public GT_GUIDialogSelectItem(String header, ItemStack headerItem, GuiScreen parent, + Consumer<ItemStack> selectedCallback, List<ItemStack> stacks, int selected, boolean noDeselect) { + super(176, 107, header); + this.noDeselect = noDeselect; + if (headerItem != null) this.headerIcon.setItem(headerItem); + this.parent = parent; + this.selectedCallback = selectedCallback; + this.stacks = stacks; + + if (stacks.size() > rows * cols) { + btnUp = new GT_GuiIconButton(this, 0, 134, 25, GT_GuiIcon.GREEN_ARROW_UP); + btnDown = new GT_GuiIconButton(this, 1, 152, 25, GT_GuiIcon.GREEN_ARROW_DOWN); + } + + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + slots.add( + new GT_GuiFakeItemButton(this, 8 + 18 * j, 44 + 18 * i, GT_GuiIcon.SLOT_GRAY).setMimicSlot(true)); + } + } + + setSelected(noDeselect ? Math.max(0, selected) : selected); + ensureSelectedDisplayed(); + } + + @Override + protected void onInitGui(int guiLeft, int guiTop, int gui_width, int gui_height) { + btnCurrent + .setX(8 + 2 + fontRendererObj.getStringWidth(StatCollector.translateToLocal("GT5U.gui.select.current"))); + } + + @Override + public void closeScreen() { + selectedCallback.accept(getCandidate(getSelected())); + mc.displayGuiScreen(parent); + if (parent == null) mc.setIngameFocus(); + } + + @Override + public void buttonClicked(GuiButton button) { + switch (button.id) { + case 0 -> { + setScroll(scroll - 1); + return; + } + case 1 -> { + setScroll(scroll + 1); + return; + } + } + super.buttonClicked(button); + } + + @Override + public void drawExtras(int mouseX, int mouseY, float parTicks) { + int y = 25 + (18 - getFontRenderer().FONT_HEIGHT) / 2; + getFontRenderer().drawString(StatCollector.translateToLocal("GT5U.gui.select.current"), 8, y, textColor); + super.drawExtras(mouseX, mouseY, parTicks); + } + + @Override + public void mouseClicked(int x, int y, int button) { + int mx = x - guiLeft, my = y - guiTop; + if (button == 0) { + if (btnCurrent.getBounds() + .contains(mx, my)) { + ensureSelectedDisplayed(); + return; + } + + for (int i = 0, slotsSize = slots.size(); i < slotsSize; i++) { + GT_GuiFakeItemButton slot = slots.get(i); + if (slot.getBounds() + .contains(mx, my)) { + setSelected(slotIndexToListIndex(i)); + return; + } + } + } else if (button == 1 && getSelected() >= 0) { + if (btnCurrent.getBounds() + .contains(mx, my)) { + setSelected(UNSELECTED); + return; + } + GT_GuiFakeItemButton slot = getSlot(listIndexToSlotIndex(getSelected())); + if (slot != null && slot.getBounds() + .contains(mx, my)) { + setSelected(UNSELECTED); + } + } + super.mouseClicked(x, y, button); + } + + @Override + public void onMouseWheel(int x, int y, int delta) { + if (delta < 0) setScroll(scroll + 1); + else if (delta > 0) setScroll(scroll - 1); + } + + private void fillSlots() { + for (int i = 0, j = scroll * cols; i < slots.size(); i++, j++) { + slots.get(i) + .setItem(getCandidate(j)) + .setBgIcon(j == getSelected() ? GT_GuiIcon.SLOT_DARKGRAY : GT_GuiIcon.SLOT_GRAY); + } + } + + private void ensureSelectedDisplayed() { + if (getSelected() < scroll * cols) { + setScroll(getSelected() / cols); + } else if (getSelected() > (scroll + rows) * cols) { + setScroll((getSelected() - (rows - 1) * cols) / cols); + } else { + // called nonetheless to update button enabled states + setScroll(scroll); + } + } + + private int slotIndexToListIndex(int index) { + int mapped = scroll * cols + index; + return mapped >= stacks.size() ? UNSELECTED : mapped; + } + + private int listIndexToSlotIndex(int index) { + return index - scroll * cols; + } + + public int getSelected() { + return selected; + } + + public void setSelected(int selected) { + if (selected == this.selected) return; + int newSelected = GT_Utility.clamp(selected, UNSELECTED, stacks.size() - 1); + + if (noDeselect && newSelected == UNSELECTED) return; + + GT_GuiFakeItemButton selectedSlot = getSlot(this.selected); + if (selectedSlot != null) selectedSlot.setBgIcon(GT_GuiIcon.SLOT_GRAY); + + this.selected = newSelected; + + btnCurrent.setItem(getCandidate(this.selected)); + + selectedSlot = getSlot(this.selected); + if (selectedSlot != null) selectedSlot.setBgIcon(GT_GuiIcon.SLOT_DARKGRAY); + } + + private void setScroll(int scroll) { + if (stacks.size() > rows * cols) { + int lo = 0; + int hi = (stacks.size() - rows * cols) / cols + 1; + this.scroll = GT_Utility.clamp(scroll, lo, hi); + btnUp.enabled = this.scroll != lo; + btnDown.enabled = this.scroll != hi; + } + fillSlots(); + } + + private ItemStack getCandidate(int listIndex) { + return listIndex < 0 || listIndex >= stacks.size() ? null : stacks.get(listIndex); + } + + private GT_GuiFakeItemButton getSlot(int slotIndex) { + return slotIndex < 0 || slotIndex >= slots.size() ? null : slots.get(slotIndex); + } +} diff --git a/src/main/java/gregtech/api/gui/GT_GUIScreen.java b/src/main/java/gregtech/api/gui/GT_GUIScreen.java new file mode 100644 index 0000000000..2ff2973792 --- /dev/null +++ b/src/main/java/gregtech/api/gui/GT_GUIScreen.java @@ -0,0 +1,327 @@ +package gregtech.api.gui; + +import java.util.ArrayList; +import java.util.List; + +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.gui.GuiButton; +import net.minecraft.client.gui.GuiScreen; +import net.minecraft.client.gui.GuiTextField; +import net.minecraft.client.renderer.RenderHelper; +import net.minecraft.client.renderer.entity.RenderItem; +import net.minecraft.util.ResourceLocation; + +import org.lwjgl.input.Mouse; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL12; + +import gregtech.api.enums.Dyes; +import gregtech.api.gui.widgets.GT_GuiFakeItemButton; +import gregtech.api.gui.widgets.GT_GuiIntegerTextBox; +import gregtech.api.gui.widgets.GT_GuiTooltip; +import gregtech.api.gui.widgets.GT_GuiTooltipManager; +import gregtech.api.gui.widgets.GT_GuiTooltipManager.GT_IToolTipRenderer; +import gregtech.api.interfaces.IGuiScreen; + +@Deprecated +public abstract class GT_GUIScreen extends GuiScreen implements GT_IToolTipRenderer, IGuiScreen { + + protected final GT_GuiTooltipManager ttManager = new GT_GuiTooltipManager(); + + protected int gui_width = 176; + protected int gui_height = 107; + protected int guiTop, guiLeft; + protected final boolean drawButtons = true; + protected final ResourceLocation mGUIbackgroundLocation; + + private GuiButton selectedButton; + private final GT_GUIColorOverride colorOverride; + private final int textColor; + private static final String guiTexturePath = "gregtech:textures/gui/GuiCover.png"; + + public String header; + public GT_GuiFakeItemButton headerIcon; + + protected final List<IGuiElement> elements = new ArrayList<>(); + protected final List<GT_GuiIntegerTextBox> textBoxes = new ArrayList<>(); + + public GT_GUIScreen(int width, int height, String header) { + this.gui_width = width; + this.gui_height = height; + this.header = header; + this.headerIcon = new GT_GuiFakeItemButton(this, 5, 5, null); + this.mGUIbackgroundLocation = new ResourceLocation(guiTexturePath); + this.colorOverride = GT_GUIColorOverride.get(guiTexturePath); + this.textColor = getTextColorOrDefault("title", 0xFF222222); + } + + @Override + public void initGui() { + guiLeft = (this.width - this.gui_width) / 2; + guiTop = (this.height - this.gui_height) / 2; + + for (IGuiElement element : elements) { + if (element instanceof GuiButton button) buttonList.add(button); + if (element instanceof GT_GuiIntegerTextBox) textBoxes.add((GT_GuiIntegerTextBox) element); + } + + onInitGui(guiLeft, guiTop, gui_width, gui_height); + + for (IGuiElement element : elements) { + element.onInit(); + } + super.initGui(); + } + + protected abstract void onInitGui(int guiLeft, int guiTop, int gui_width, int gui_height); + + protected int getTextColorOrDefault(String textType, int defaultColor) { + return colorOverride.getTextColorOrDefault(textType, defaultColor); + } + + public void onMouseWheel(int x, int y, int delta) {} + + @Override + public void handleMouseInput() { + int delta = Mouse.getEventDWheel(); + if (delta != 0) { + int i = Mouse.getEventX() * this.width / this.mc.displayWidth; + int j = this.height - Mouse.getEventY() * this.height / this.mc.displayHeight - 1; + onMouseWheel(i, j, delta); + } + super.handleMouseInput(); + } + + @Override + public void drawScreen(int mouseX, int mouseY, float parTicks) { + drawDefaultBackground(); + + drawBackground(mouseX, mouseY, parTicks); + + RenderHelper.disableStandardItemLighting(); + GL11.glDisable(GL11.GL_LIGHTING); + GL11.glDisable(GL11.GL_DEPTH_TEST); + GL11.glDisable(GL12.GL_RESCALE_NORMAL); + if (drawButtons) { + RenderHelper.enableGUIStandardItemLighting(); + for (IGuiElement e : elements) e.draw(mouseX, mouseY, parTicks); + } + GL11.glEnable(GL12.GL_RESCALE_NORMAL); + + GL11.glPushMatrix(); + GL11.glTranslatef(guiLeft, guiTop, 0.0F); + GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); + + GL11.glDisable(GL11.GL_LIGHTING); + drawForegroundLayer(mouseX, mouseY, parTicks); + GL11.glEnable(GL11.GL_LIGHTING); + + GL11.glPopMatrix(); + + GL11.glEnable(GL11.GL_LIGHTING); + GL11.glEnable(GL11.GL_DEPTH_TEST); + RenderHelper.enableStandardItemLighting(); + } + + public void drawForegroundLayer(int mouseX, int mouseY, float parTicks) { + drawExtras(mouseX, mouseY, parTicks); + ttManager.onTick(this, mouseX, mouseY); + } + + public void drawBackground(int mouseX, int mouseY, float parTicks) { + short[] color = Dyes.MACHINE_METAL.getRGBA(); + GL11.glColor3ub((byte) color[0], (byte) color[1], (byte) color[2]); + this.mc.renderEngine.bindTexture(mGUIbackgroundLocation); + drawTexturedModalRect(guiLeft, guiTop, 0, 0, gui_width, gui_height); + } + + public void drawExtras(int mouseX, int mouseY, float parTicks) { + this.fontRendererObj.drawString(header, 25, 9, textColor); + } + + @Override + public boolean doesGuiPauseGame() { + return false; + } + + public void closeScreen() { + this.mc.displayGuiScreen(null); + this.mc.setIngameFocus(); + } + + @Override + public void updateScreen() { + super.updateScreen(); + for (GuiTextField f : textBoxes) { + f.updateCursorCounter(); + } + } + + @Override + public void mouseClicked(int x, int y, int button) { + for (GT_GuiIntegerTextBox tBox : textBoxes) { + boolean hadFocus = tBox.isFocused(); + if (tBox.isEnabled() || hadFocus) tBox.mouseClicked(x, y, button); + + if (tBox.isFocused() && button == 1 && tBox.isEnabled()) // rightclick -> lcear it + tBox.setText("0"); + else if (hadFocus && !tBox.isFocused()) applyTextBox(tBox); + } + super.mouseClicked(x, y, button); + } + + @Override + public void keyTyped(char c, int key) { + GT_GuiIntegerTextBox focusedTextBox = null; + for (GT_GuiIntegerTextBox textBox : textBoxes) { + if (textBox.isFocused()) focusedTextBox = textBox; + } + + if (key == 1) { // esc + if (focusedTextBox != null) { + resetTextBox(focusedTextBox); + setFocusedTextBox(null); + } else { + closeScreen(); + // don't fall through to parent + } + return; + } + + if (c == '\t') { // tab + for (int i = 0; i < textBoxes.size(); i++) { + GT_GuiIntegerTextBox box = textBoxes.get(i); + if (box.isFocused()) { + applyTextBox(box); + setFocusedTextBox(((i + 1) < textBoxes.size()) ? textBoxes.get(i + 1) : null); + return; + } + } + if (!textBoxes.isEmpty()) setFocusedTextBox(textBoxes.get(0)); + return; + } + + if (focusedTextBox != null && focusedTextBox.textboxKeyTyped(c, key)) { + return; + } + + if (key == 28 && focusedTextBox != null) { // enter + applyTextBox(focusedTextBox); + setFocusedTextBox(null); + return; + } + + if (key == this.mc.gameSettings.keyBindInventory.getKeyCode()) { + if (focusedTextBox != null) { + applyTextBox(focusedTextBox); + setFocusedTextBox(null); + return; + } + closeScreen(); + return; + } + super.keyTyped(c, key); + } + + /** + * Button + */ + @Override + public void actionPerformed(GuiButton button) { + selectedButton = button; + } + + @Override + public void clearSelectedButton() { + selectedButton = null; + } + + @Override + public GuiButton getSelectedButton() { + return selectedButton; + } + + @Override + public void buttonClicked(GuiButton button) {} + + /** + * TextBoxes + */ + private void setFocusedTextBox(GT_GuiIntegerTextBox boxToFocus) { + for (GT_GuiIntegerTextBox textBox : textBoxes) { + textBox.setFocused(textBox.equals(boxToFocus) && textBox.isEnabled()); + } + } + + /** + * Given textbox's value might have changed. + */ + public void applyTextBox(GT_GuiIntegerTextBox box) {} + + /** + * Reset the given textbox to the last valid value, <b>NOT</b> 0. + */ + public void resetTextBox(GT_GuiIntegerTextBox box) {} + + /** + * GT_IToolTipRenderer + */ + @Override + public void drawHoveringText(List<String> text, int mouseX, int mouseY, FontRenderer render) { + super.drawHoveringText(text, mouseX, mouseY, render); + } + + @Override + public FontRenderer getFontRenderer() { + return super.fontRendererObj; + } + + @Override + public void addToolTip(GT_GuiTooltip toolTip) { + ttManager.addToolTip(toolTip); + } + + @Override + public boolean removeToolTip(GT_GuiTooltip toolTip) { + return ttManager.removeToolTip(toolTip); + } + + /** + * Junk + */ + @Override + public int getGuiTop() { + return guiTop; + } + + @Override + public int getGuiLeft() { + return guiLeft; + } + + @Override + public int getXSize() { + return gui_width; + } + + @Override + public int getYSize() { + return gui_height; + } + + @Override + public RenderItem getItemRenderer() { + return itemRender; + } + + @Override + public void addElement(IGuiElement element) { + if (elements.contains(element)) return; + elements.add(element); + } + + @Override + public boolean removeElement(IGuiElement element) { + return elements.remove(element); + } +} diff --git a/src/main/java/gregtech/api/gui/GT_Slot_Armor.java b/src/main/java/gregtech/api/gui/GT_Slot_Armor.java new file mode 100644 index 0000000000..1c48b01430 --- /dev/null +++ b/src/main/java/gregtech/api/gui/GT_Slot_Armor.java @@ -0,0 +1,30 @@ +package gregtech.api.gui; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.IInventory; +import net.minecraft.inventory.Slot; +import net.minecraft.item.ItemStack; + +public class GT_Slot_Armor extends Slot { + + final int mArmorType; + final EntityPlayer mPlayer; + + public GT_Slot_Armor(IInventory inventory, int slotIndex, int xPos, int yPos, int armorType, EntityPlayer aPlayer) { + super(inventory, slotIndex, xPos, yPos); + mArmorType = armorType; + mPlayer = aPlayer; + } + + @Override + public int getSlotStackLimit() { + return 1; + } + + @Override + public boolean isItemValid(ItemStack aStack) { + return aStack != null && aStack.getItem() != null + && aStack.getItem() + .isValidArmor(aStack, mArmorType, mPlayer); + } +} diff --git a/src/main/java/gregtech/api/gui/GT_Slot_DataOrb.java b/src/main/java/gregtech/api/gui/GT_Slot_DataOrb.java new file mode 100644 index 0000000000..115b50ddb8 --- /dev/null +++ b/src/main/java/gregtech/api/gui/GT_Slot_DataOrb.java @@ -0,0 +1,19 @@ +package gregtech.api.gui; + +import net.minecraft.inventory.IInventory; +import net.minecraft.inventory.Slot; +import net.minecraft.item.ItemStack; + +import gregtech.api.enums.ItemList; + +public class GT_Slot_DataOrb extends Slot { + + public GT_Slot_DataOrb(IInventory inventory, int slotIndex, int xPos, int yPos) { + super(inventory, slotIndex, xPos, yPos); + } + + @Override + public boolean isItemValid(ItemStack aStack) { + return ItemList.Tool_DataOrb.isStackEqual(aStack, false, true); + } +} diff --git a/src/main/java/gregtech/api/gui/GT_Slot_Holo.java b/src/main/java/gregtech/api/gui/GT_Slot_Holo.java new file mode 100644 index 0000000000..9b7b75f0b2 --- /dev/null +++ b/src/main/java/gregtech/api/gui/GT_Slot_Holo.java @@ -0,0 +1,77 @@ +package gregtech.api.gui; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.IInventory; +import net.minecraft.inventory.Slot; +import net.minecraft.item.ItemStack; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +public class GT_Slot_Holo extends Slot { + + public final int mSlotIndex; + public boolean mEnabled = true; + public boolean mCanInsertItem, mCanStackItem; + public int mMaxStacksize = 127; + + public GT_Slot_Holo(IInventory inventory, int slotIndex, int xPos, int yPos, boolean aCanInsertItem, + boolean aCanStackItem, int aMaxStacksize) { + super(inventory, slotIndex, xPos, yPos); + mCanInsertItem = aCanInsertItem; + mCanStackItem = aCanStackItem; + mMaxStacksize = aMaxStacksize; + mSlotIndex = slotIndex; + } + + @Override + public boolean isItemValid(ItemStack itemStack) { + return mCanInsertItem; + } + + @Override + public int getSlotStackLimit() { + return mMaxStacksize; + } + + @Override + public boolean getHasStack() { + return false; + } + + @Override + public ItemStack decrStackSize(int amount) { + if (!mCanStackItem) return null; + return super.decrStackSize(amount); + } + + @Override + public boolean canTakeStack(EntityPlayer player) { + return false; + } + + /** + * Sets if this slot should be ignored in event-processing. For example, highlight the slot on mouseOver. + * + * @param enabled if the slot should be enabled + */ + public void setEnabled(boolean enabled) { + mEnabled = enabled; + } + + /** + * Use this value to determine whether to ignore this slot in event processing + */ + public boolean isEnabled() { + return mEnabled; + } + + /** + * This function controls whether to highlight the slot on mouseOver. + */ + @Override + @SideOnly(Side.CLIENT) + public boolean func_111238_b() { + return isEnabled(); + } +} diff --git a/src/main/java/gregtech/api/gui/GT_Slot_Output.java b/src/main/java/gregtech/api/gui/GT_Slot_Output.java new file mode 100644 index 0000000000..7c883ea2d1 --- /dev/null +++ b/src/main/java/gregtech/api/gui/GT_Slot_Output.java @@ -0,0 +1,17 @@ +package gregtech.api.gui; + +import net.minecraft.inventory.IInventory; +import net.minecraft.inventory.Slot; +import net.minecraft.item.ItemStack; + +public class GT_Slot_Output extends Slot { + + public GT_Slot_Output(IInventory inventory, int slotIndex, int xPos, int yPos) { + super(inventory, slotIndex, xPos, yPos); + } + + @Override + public boolean isItemValid(ItemStack itemStack) { + return false; + } +} diff --git a/src/main/java/gregtech/api/gui/GT_Slot_Render.java b/src/main/java/gregtech/api/gui/GT_Slot_Render.java new file mode 100644 index 0000000000..ae03ce83ea --- /dev/null +++ b/src/main/java/gregtech/api/gui/GT_Slot_Render.java @@ -0,0 +1,24 @@ +package gregtech.api.gui; + +import net.minecraft.inventory.IInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntity; + +public class GT_Slot_Render extends GT_Slot_Holo { + + public GT_Slot_Render(IInventory inventory, int slotIndex, int xPos, int yPos) { + super(inventory, slotIndex, xPos, yPos, false, false, 0); + } + + /** + * NEI has a nice and "useful" Delete-All Function, which would delete the Content of this Slot. This is here to + * prevent that. + */ + @Override + public void putStack(ItemStack aStack) { + if (inventory instanceof TileEntity && ((TileEntity) inventory).getWorldObj().isRemote) { + inventory.setInventorySlotContents(getSlotIndex(), aStack); + } + onSlotChanged(); + } +} diff --git a/src/main/java/gregtech/api/gui/GUIHost.java b/src/main/java/gregtech/api/gui/GUIHost.java new file mode 100644 index 0000000000..bbb94317c4 --- /dev/null +++ b/src/main/java/gregtech/api/gui/GUIHost.java @@ -0,0 +1,56 @@ +package gregtech.api.gui; + +import java.util.Objects; + +import javax.annotation.Nonnull; + +import net.minecraft.item.ItemStack; + +import com.gtnewhorizons.modularui.api.screen.ITileWithModularUI; +import com.gtnewhorizons.modularui.api.screen.ModularWindow; +import com.gtnewhorizons.modularui.api.screen.UIBuildContext; + +public interface GUIHost extends ITileWithModularUI { + + @Nonnull + @Override + default ModularWindow createWindow(UIBuildContext uiContext) { + Objects.requireNonNull(uiContext); + GUIProvider<?> gui = getGUI(uiContext); + return gui.openGUI(uiContext); + } + + /** + * Width of the GUI when its being displayed + */ + default int getWidth() { + return 170; + } + + default int getHeight() { + return 192; + } + + @Nonnull + GUIProvider<?> getGUI(@Nonnull UIBuildContext uiContext); + + ItemStack getAsItem(); + + String getMachineName(); + + default boolean hasItemInput() { + return true; + } + + default boolean hasItemOutput() { + return true; + } + + default boolean hasFluidInput() { + return true; + } + + default boolean hasFluidOutput() { + return true; + } +} diff --git a/src/main/java/gregtech/api/gui/GUIProvider.java b/src/main/java/gregtech/api/gui/GUIProvider.java new file mode 100644 index 0000000000..6fec4aa52a --- /dev/null +++ b/src/main/java/gregtech/api/gui/GUIProvider.java @@ -0,0 +1,38 @@ +package gregtech.api.gui; + +import java.util.Objects; + +import javax.annotation.Nonnull; + +import com.gtnewhorizons.modularui.api.screen.ModularWindow; +import com.gtnewhorizons.modularui.api.screen.ModularWindow.Builder; +import com.gtnewhorizons.modularui.api.screen.UIBuildContext; + +public abstract class GUIProvider<T extends GUIHost> { + + @Nonnull + protected final T host; + + public GUIProvider(@Nonnull T host) { + this.host = host; + } + + @Nonnull + public ModularWindow openGUI(@Nonnull UIBuildContext uiContext) { + Builder builder = Objects.requireNonNull(ModularWindow.builder(host.getWidth(), host.getHeight())); + if (shouldBindPlayerInventory()) { + builder.bindPlayerInventory(uiContext.getPlayer()); + } + attachSynchHandlers(builder, uiContext); + addWidgets(builder, uiContext); + return Objects.requireNonNull(builder.build()); + } + + protected abstract void attachSynchHandlers(@Nonnull Builder builder, @Nonnull UIBuildContext uiContext); + + protected abstract void addWidgets(@Nonnull Builder builder, @Nonnull UIBuildContext uiContext); + + protected boolean shouldBindPlayerInventory() { + return true; + } +} diff --git a/src/main/java/gregtech/api/gui/modularui/FallbackableSteamTexture.java b/src/main/java/gregtech/api/gui/modularui/FallbackableSteamTexture.java new file mode 100644 index 0000000000..8de4bc4536 --- /dev/null +++ b/src/main/java/gregtech/api/gui/modularui/FallbackableSteamTexture.java @@ -0,0 +1,89 @@ +package gregtech.api.gui.modularui; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import net.minecraft.client.Minecraft; + +import com.gtnewhorizons.modularui.api.drawable.UITexture; +import com.gtnewhorizons.modularui.common.internal.network.NetworkUtils; + +import gregtech.api.enums.SteamVariant; + +public class FallbackableSteamTexture { + + private final SteamTexture candidate; + private final Object fallback; + private final Map<SteamVariant, Boolean> useFallbackMap = new HashMap<>(); + + private static final List<FallbackableSteamTexture> ALL_INSTANCES = new ArrayList<>(); + + public FallbackableSteamTexture(SteamTexture candidate, SteamTexture fallback) { + this(candidate, (Object) fallback); + } + + public FallbackableSteamTexture(SteamTexture candidate, FallbackableSteamTexture fallback) { + this(candidate, (Object) fallback); + } + + public FallbackableSteamTexture(SteamTexture fallback) { + this(null, fallback); + } + + private FallbackableSteamTexture(SteamTexture candidate, Object fallback) { + this.candidate = candidate; + this.fallback = fallback; + ALL_INSTANCES.add(this); + } + + public UITexture get(SteamVariant steamVariant) { + verifyCandidate(steamVariant); + if (useFallbackMap.get(steamVariant)) { + return castFallback(steamVariant); + } else { + return candidate.get(steamVariant); + } + } + + private void verifyCandidate(SteamVariant steamVariant) { + if (useFallbackMap.get(steamVariant) == null) { + boolean useFallback; + if (NetworkUtils.isDedicatedClient()) { + if (candidate == null) { + useFallback = true; + } else { + try { + Minecraft.getMinecraft() + .getResourceManager() + .getResource(candidate.get(steamVariant).location); + useFallback = false; + } catch (IOException e) { + useFallback = true; + } + } + } else { + useFallback = true; + } + useFallbackMap.put(steamVariant, useFallback); + } + } + + private UITexture castFallback(SteamVariant steamVariant) { + if (fallback instanceof SteamTexture) { + return ((SteamTexture) fallback).get(steamVariant); + } else if (fallback instanceof FallbackableSteamTexture) { + return ((FallbackableSteamTexture) fallback).get(steamVariant); + } else { + throw new RuntimeException("Unexpected type found for fallback: " + fallback.getClass()); + } + } + + public static void reload() { + for (FallbackableSteamTexture t : ALL_INSTANCES) { + t.useFallbackMap.clear(); + } + } +} diff --git a/src/main/java/gregtech/api/gui/modularui/GT_CoverUIBuildContext.java b/src/main/java/gregtech/api/gui/modularui/GT_CoverUIBuildContext.java new file mode 100644 index 0000000000..f98d6099fc --- /dev/null +++ b/src/main/java/gregtech/api/gui/modularui/GT_CoverUIBuildContext.java @@ -0,0 +1,74 @@ +package gregtech.api.gui.modularui; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraftforge.common.util.ForgeDirection; + +import com.gtnewhorizons.modularui.api.screen.UIBuildContext; + +import gregtech.api.interfaces.tileentity.ICoverable; + +public class GT_CoverUIBuildContext extends UIBuildContext { + + // cover data is not synced to client, while ID is + private final int coverID; + private final ForgeDirection side; + private final ICoverable tile; + private final boolean anotherWindow; + private final int guiColorization; + + /** + * @param player Player opened this UI + * @param coverID See {@link ICoverable#getCoverIDAtSide} + * @param side Side this cover is attached to + * @param tile Tile this cover is attached to + * @param anotherWindow If cover UI is shown on top of another window + * @param guiColorization The color used to render machine's GUI + */ + public GT_CoverUIBuildContext(EntityPlayer player, int coverID, ForgeDirection side, ICoverable tile, + boolean anotherWindow, int guiColorization) { + super(player); + this.coverID = coverID; + this.side = side; + this.tile = tile; + this.anotherWindow = anotherWindow; + this.guiColorization = guiColorization; + } + + /** + * @param player Player opened this UI + * @param coverID See {@link ICoverable#getCoverIDAtSide} + * @param side Side this cover is attached to + * @param tile Tile this cover is attached to + * @param anotherWindow If cover GUI is shown in opened on top of another window + */ + public GT_CoverUIBuildContext(EntityPlayer player, int coverID, ForgeDirection side, ICoverable tile, + boolean anotherWindow) { + this(player, coverID, side, tile, anotherWindow, tile.getGUIColorization()); + } + + public int getCoverID() { + return coverID; + } + + public ForgeDirection getCoverSide() { + return side; + } + + /** + * Note that this will return different object between client v.s. server side on SP. + */ + public ICoverable getTile() { + return tile; + } + + /** + * If cover GUI is shown in opened on top of another window. + */ + public boolean isAnotherWindow() { + return anotherWindow; + } + + public int getGuiColorization() { + return guiColorization; + } +} diff --git a/src/main/java/gregtech/api/gui/modularui/GT_UIInfos.java b/src/main/java/gregtech/api/gui/modularui/GT_UIInfos.java new file mode 100644 index 0000000000..89a0835f13 --- /dev/null +++ b/src/main/java/gregtech/api/gui/modularui/GT_UIInfos.java @@ -0,0 +1,188 @@ +package gregtech.api.gui.modularui; + +import java.util.HashMap; +import java.util.Map; +import java.util.function.Function; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.tileentity.TileEntity; +import net.minecraftforge.common.util.ForgeDirection; + +import com.gtnewhorizons.modularui.api.UIInfos; +import com.gtnewhorizons.modularui.api.screen.ITileWithModularUI; +import com.gtnewhorizons.modularui.api.screen.ModularUIContext; +import com.gtnewhorizons.modularui.api.screen.ModularWindow; +import com.gtnewhorizons.modularui.api.screen.UIBuildContext; +import com.gtnewhorizons.modularui.common.builder.UIBuilder; +import com.gtnewhorizons.modularui.common.builder.UIInfo; +import com.gtnewhorizons.modularui.common.internal.network.NetworkUtils; +import com.gtnewhorizons.modularui.common.internal.wrapper.ModularGui; +import com.gtnewhorizons.modularui.common.internal.wrapper.ModularUIContainer; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import gregtech.api.enums.GT_Values; +import gregtech.api.interfaces.tileentity.ICoverable; +import gregtech.api.interfaces.tileentity.IHasWorldObjectAndCoords; +import gregtech.api.net.GT_Packet_SendCoverData; +import gregtech.api.util.GT_CoverBehaviorBase; + +public class GT_UIInfos { + + public static void init() {} + + /** + * Generator for {@link UIInfo} which is responsible for registering and opening UIs. Unlike + * {@link com.gtnewhorizons.modularui.api.UIInfos#TILE_MODULAR_UI}, this accepts custom constructors for UI. <br> + * Do NOT run {@link UIBuilder#build} on-the-fly, otherwise MP client won't register UIs. Instead, store to static + * field, just like {@link #GTTileEntityDefaultUI}. Such mistake can be easily overlooked by testing only SP. + */ + public static final Function<ContainerConstructor, UIInfo<?, ?>> GTTileEntityUIFactory = containerConstructor -> UIBuilder + .of() + .container((player, world, x, y, z) -> { + TileEntity te = world.getTileEntity(x, y, z); + if (te instanceof ITileWithModularUI mui) { + return createTileEntityContainer(player, mui::createWindow, te::markDirty, containerConstructor); + } + return null; + }) + .gui(((player, world, x, y, z) -> { + if (!world.isRemote) return null; + TileEntity te = world.getTileEntity(x, y, z); + if (te instanceof ITileWithModularUI mui) { + return createTileEntityGuiContainer(player, mui::createWindow, containerConstructor); + } + return null; + })) + .build(); + + private static final UIInfo<?, ?> GTTileEntityDefaultUI = GTTileEntityUIFactory.apply(ModularUIContainer::new); + + private static final Map<ForgeDirection, UIInfo<?, ?>> coverUI = new HashMap<>(); + + static { + for (final ForgeDirection side : ForgeDirection.VALID_DIRECTIONS) { + coverUI.put( + side, + UIBuilder.of() + .container((player, world, x, y, z) -> { + final TileEntity te = world.getTileEntity(x, y, z); + if (!(te instanceof ICoverable gtTileEntity)) return null; + final GT_CoverBehaviorBase<?> cover = gtTileEntity.getCoverBehaviorAtSideNew(side); + return createCoverContainer( + player, + cover::createWindow, + te::markDirty, + gtTileEntity.getCoverIDAtSide(side), + side, + gtTileEntity); + }) + .gui((player, world, x, y, z) -> { + if (!world.isRemote) return null; + final TileEntity te = world.getTileEntity(x, y, z); + if (!(te instanceof ICoverable gtTileEntity)) return null; + final GT_CoverBehaviorBase<?> cover = gtTileEntity.getCoverBehaviorAtSideNew(side); + return createCoverGuiContainer( + player, + cover::createWindow, + gtTileEntity.getCoverIDAtSide(side), + side, + gtTileEntity); + }) + .build()); + } + } + + /** + * Opens TileEntity UI, created by {@link ITileWithModularUI#createWindow}. + */ + public static void openGTTileEntityUI(IHasWorldObjectAndCoords aTileEntity, EntityPlayer aPlayer) { + if (aTileEntity.isClientSide()) return; + GTTileEntityDefaultUI.open( + aPlayer, + aTileEntity.getWorld(), + aTileEntity.getXCoord(), + aTileEntity.getYCoord(), + aTileEntity.getZCoord()); + } + + /** + * Opens cover UI, created by {@link GT_CoverBehaviorBase#createWindow}. + */ + public static void openCoverUI(ICoverable tileEntity, EntityPlayer player, ForgeDirection side) { + if (tileEntity.isClientSide()) return; + + GT_Values.NW.sendToPlayer( + new GT_Packet_SendCoverData( + side, + tileEntity.getCoverIDAtSide(side), + tileEntity.getComplexCoverDataAtSide(side), + tileEntity), + (EntityPlayerMP) player); + + coverUI.get(side) + .open( + player, + tileEntity.getWorld(), + tileEntity.getXCoord(), + tileEntity.getYCoord(), + tileEntity.getZCoord()); + } + + /** + * Opens UI for player's item, created by + * {@link com.gtnewhorizons.modularui.api.screen.IItemWithModularUI#createWindow}. + */ + public static void openPlayerHeldItemUI(EntityPlayer player) { + if (NetworkUtils.isClient()) return; + UIInfos.PLAYER_HELD_ITEM_UI.open(player); + } + + private static ModularUIContainer createTileEntityContainer(EntityPlayer player, + Function<UIBuildContext, ModularWindow> windowCreator, Runnable onWidgetUpdate, + ContainerConstructor containerCreator) { + final UIBuildContext buildContext = new UIBuildContext(player); + final ModularWindow window = windowCreator.apply(buildContext); + if (window == null) return null; + return containerCreator.of(new ModularUIContext(buildContext, onWidgetUpdate), window); + } + + @SideOnly(Side.CLIENT) + private static ModularGui createTileEntityGuiContainer(EntityPlayer player, + Function<UIBuildContext, ModularWindow> windowCreator, ContainerConstructor containerConstructor) { + final ModularUIContainer container = createTileEntityContainer( + player, + windowCreator, + null, + containerConstructor); + if (container == null) return null; + return new ModularGui(container); + } + + private static ModularUIContainer createCoverContainer(EntityPlayer player, + Function<GT_CoverUIBuildContext, ModularWindow> windowCreator, Runnable onWidgetUpdate, int coverID, + ForgeDirection side, ICoverable tile) { + final GT_CoverUIBuildContext buildContext = new GT_CoverUIBuildContext(player, coverID, side, tile, false); + final ModularWindow window = windowCreator.apply(buildContext); + if (window == null) return null; + return new ModularUIContainer(new ModularUIContext(buildContext, onWidgetUpdate), window); + } + + @SideOnly(Side.CLIENT) + private static ModularGui createCoverGuiContainer(EntityPlayer player, + Function<GT_CoverUIBuildContext, ModularWindow> windowCreator, int coverID, ForgeDirection side, + ICoverable tile) { + final ModularUIContainer container = createCoverContainer(player, windowCreator, null, coverID, side, tile); + if (container == null) { + return null; + } + return new ModularGui(container); + } + + @FunctionalInterface + public interface ContainerConstructor { + + ModularUIContainer of(ModularUIContext context, ModularWindow mainWindow); + } +} diff --git a/src/main/java/gregtech/api/gui/modularui/GT_UITextures.java b/src/main/java/gregtech/api/gui/modularui/GT_UITextures.java new file mode 100644 index 0000000000..b200e16d47 --- /dev/null +++ b/src/main/java/gregtech/api/gui/modularui/GT_UITextures.java @@ -0,0 +1,488 @@ +package gregtech.api.gui.modularui; + +import static gregtech.api.enums.Mods.GregTech; + +import java.util.function.BiFunction; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +import com.gtnewhorizons.modularui.api.drawable.AdaptableUITexture; +import com.gtnewhorizons.modularui.api.drawable.FallbackableUITexture; +import com.gtnewhorizons.modularui.api.drawable.UITexture; + +public class GT_UITextures { + + public static final UITexture TRANSPARENT = UITexture.fullImage(GregTech.ID, "gui/picture/transparent"); + + public static final AdaptableUITexture BACKGROUND_SINGLEBLOCK_DEFAULT = AdaptableUITexture + .of(GregTech.ID, "gui/background/singleblock_default", 176, 166, 4); + public static final SteamTexture BACKGROUND_STEAM = SteamTexture + .adaptableTexture(GregTech.ID, "gui/background/%s", 176, 166, 4); + public static final UITexture BACKGROUND_FUSION_COMPUTER = UITexture + .fullImage(GregTech.ID, "gui/background/fusion_computer"); + public static final AdaptableUITexture BACKGROUND_TEXT_FIELD = AdaptableUITexture + .of(GregTech.ID, "gui/background/text_field", 142, 28, 1); + public static final AdaptableUITexture BACKGROUND_TEXT_FIELD_LIGHT_GRAY = AdaptableUITexture + .of(GregTech.ID, "gui/background/text_field_light_gray", 61, 12, 1); + public static final AdaptableUITexture BACKGROUND_NEI_SINGLE_RECIPE = AdaptableUITexture + .of(GregTech.ID, "gui/background/nei_single_recipe.png", 64, 64, 2); + + public static final SteamTexture SLOT_ITEM_STEAM = SteamTexture.fullImage(GregTech.ID, "gui/slot/item_%s"); + public static final SteamTexture SLOT_FLUID_STEAM = SteamTexture.fullImage(GregTech.ID, "gui/slot/fluid_%s"); + public static final AdaptableUITexture SLOT_DARK_GRAY = AdaptableUITexture + .of(GregTech.ID, "gui/slot/dark_gray", 18, 18, 1); + public static final AdaptableUITexture SLOT_MAINTENANCE = AdaptableUITexture + .of(GregTech.ID, "gui/slot/maintenance", 20, 20, 1); + public static final AdaptableUITexture SLOT_UPLIFTED = AdaptableUITexture + .of(GregTech.ID, "gui/slot/uplifted", 18, 18, 1); + + public static final UITexture OVERLAY_SLOT_ARROW_ME = UITexture.fullImage(GregTech.ID, "gui/overlay_slot/arrow_me"); + public static final UITexture OVERLAY_SLOT_PATTERN_ME = UITexture + .fullImage(GregTech.ID, "gui/overlay_slot/pattern_me"); + + public static final UITexture OVERLAY_SLOT_BEAKER_1 = UITexture.fullImage(GregTech.ID, "gui/overlay_slot/beaker_1"); + public static final UITexture OVERLAY_SLOT_BEAKER_2 = UITexture.fullImage(GregTech.ID, "gui/overlay_slot/beaker_2"); + public static final UITexture OVERLAY_SLOT_BEE_DRONE = UITexture + .fullImage(GregTech.ID, "gui/overlay_slot/bee_drone"); + public static final UITexture OVERLAY_SLOT_BEE_QUEEN = UITexture + .fullImage(GregTech.ID, "gui/overlay_slot/bee_queen"); + public static final UITexture OVERLAY_SLOT_BENDER = UITexture.fullImage(GregTech.ID, "gui/overlay_slot/bender"); + public static final UITexture OVERLAY_SLOT_BOX = UITexture.fullImage(GregTech.ID, "gui/overlay_slot/box"); + public static final UITexture OVERLAY_SLOT_BOXED = UITexture.fullImage(GregTech.ID, "gui/overlay_slot/boxed"); + public static final UITexture OVERLAY_SLOT_CANISTER = UITexture.fullImage(GregTech.ID, "gui/overlay_slot/canister"); + public static final SteamTexture OVERLAY_SLOT_CANISTER_STEAM = SteamTexture + .fullImage(GregTech.ID, "gui/overlay_slot/canister_%s"); + public static final UITexture OVERLAY_SLOT_CANNER = UITexture.fullImage(GregTech.ID, "gui/overlay_slot/canner"); + public static final UITexture OVERLAY_SLOT_CAULDRON = UITexture.fullImage(GregTech.ID, "gui/overlay_slot/cauldron"); + public static final UITexture OVERLAY_SLOT_CENTRIFUGE = UITexture + .fullImage(GregTech.ID, "gui/overlay_slot/centrifuge"); + public static final UITexture OVERLAY_SLOT_CENTRIFUGE_FLUID = UITexture + .fullImage(GregTech.ID, "gui/overlay_slot/centrifuge_fluid"); + public static final SteamTexture OVERLAY_SLOT_CENTRIFUGE_STEAM = SteamTexture + .fullImage(GregTech.ID, "gui/overlay_slot/centrifuge_%s"); + public static final UITexture OVERLAY_SLOT_CHARGER = UITexture.fullImage(GregTech.ID, "gui/overlay_slot/charger"); + public static final UITexture OVERLAY_SLOT_CHARGER_FLUID = UITexture + .fullImage(GregTech.ID, "gui/overlay_slot/charger_fluid"); + public static final UITexture OVERLAY_SLOT_CIRCUIT = UITexture.fullImage(GregTech.ID, "gui/overlay_slot/circuit"); + public static final SteamTexture OVERLAY_SLOT_COAL_STEAM = SteamTexture + .fullImage(GregTech.ID, "gui/overlay_slot/coal_%s"); + public static final UITexture OVERLAY_SLOT_COMPRESSOR = UITexture + .fullImage(GregTech.ID, "gui/overlay_slot/compressor"); + public static final SteamTexture OVERLAY_SLOT_COMPRESSOR_STEAM = SteamTexture + .fullImage(GregTech.ID, "gui/overlay_slot/compressor_%s"); + public static final UITexture OVERLAY_SLOT_CRUSHED_ORE = UITexture + .fullImage(GregTech.ID, "gui/overlay_slot/crushed_ore"); + public static final SteamTexture OVERLAY_SLOT_CRUSHED_ORE_STEAM = SteamTexture + .fullImage(GregTech.ID, "gui/overlay_slot/crushed_ore_%s"); + public static final UITexture OVERLAY_SLOT_CUTTER_SLICED = UITexture + .fullImage(GregTech.ID, "gui/overlay_slot/cutter_sliced"); + public static final UITexture OVERLAY_SLOT_DATA_ORB = UITexture.fullImage(GregTech.ID, "gui/overlay_slot/data_orb"); + public static final UITexture OVERLAY_SLOT_DATA_STICK = UITexture + .fullImage(GregTech.ID, "gui/overlay_slot/data_stick"); + public static final UITexture OVERLAY_SLOT_DUST = UITexture.fullImage(GregTech.ID, "gui/overlay_slot/dust"); + public static final SteamTexture OVERLAY_SLOT_DUST_STEAM = SteamTexture + .fullImage(GregTech.ID, "gui/overlay_slot/dust_%s"); + public static final SteamTexture OVERLAY_SLOT_BLOCK_STEAM = SteamTexture + .fullImage(GregTech.ID, "gui/overlay_slot/block_%s"); + public static final UITexture OVERLAY_SLOT_EXPLOSIVE = UITexture + .fullImage(GregTech.ID, "gui/overlay_slot/explosive"); + public static final UITexture OVERLAY_SLOT_EXTRUDER_SHAPE = UITexture + .fullImage(GregTech.ID, "gui/overlay_slot/extruder_shape"); + public static final UITexture OVERLAY_SLOT_FURNACE = UITexture.fullImage(GregTech.ID, "gui/overlay_slot/furnace"); + public static final SteamTexture OVERLAY_SLOT_FURNACE_STEAM = SteamTexture + .fullImage(GregTech.ID, "gui/overlay_slot/furnace_%s"); + public static final UITexture OVERLAY_SLOT_GEM = UITexture.fullImage(GregTech.ID, "gui/overlay_slot/gem"); + public static final UITexture OVERLAY_SLOT_HAMMER = UITexture.fullImage(GregTech.ID, "gui/overlay_slot/hammer"); + public static final SteamTexture OVERLAY_SLOT_HAMMER_STEAM = SteamTexture + .fullImage(GregTech.ID, "gui/overlay_slot/hammer_%s"); + public static final UITexture OVERLAY_SLOT_HEATER_1 = UITexture.fullImage(GregTech.ID, "gui/overlay_slot/heater_1"); + public static final UITexture OVERLAY_SLOT_HEATER_2 = UITexture.fullImage(GregTech.ID, "gui/overlay_slot/heater_2"); + public static final UITexture OVERLAY_SLOT_IMPLOSION = UITexture + .fullImage(GregTech.ID, "gui/overlay_slot/implosion"); + public static final UITexture OVERLAY_SLOT_IN = UITexture.fullImage(GregTech.ID, "gui/overlay_slot/in"); + public static final SteamTexture OVERLAY_SLOT_IN_STEAM = SteamTexture + .fullImage(GregTech.ID, "gui/overlay_slot/in_%s"); + public static final SteamTexture OVERLAY_SLOT_INGOT_STEAM = SteamTexture + .fullImage(GregTech.ID, "gui/overlay_slot/ingot_%s"); + public static final UITexture OVERLAY_SLOT_INT_CIRCUIT = UITexture + .fullImage(GregTech.ID, "gui/overlay_slot/int_circuit"); + public static final UITexture OVERLAY_SLOT_LENS = UITexture.fullImage(GregTech.ID, "gui/overlay_slot/lens"); + public static final UITexture OVERLAY_SLOT_MICROSCOPE = UITexture + .fullImage(GregTech.ID, "gui/overlay_slot/microscope"); + public static final UITexture OVERLAY_SLOT_MINING_PIPE = UITexture + .fullImage(GregTech.ID, "gui/overlay_slot/mining_pipe"); + public static final UITexture OVERLAY_SLOT_MOLD = UITexture.fullImage(GregTech.ID, "gui/overlay_slot/mold"); + public static final UITexture OVERLAY_SLOT_MOLECULAR_1 = UITexture + .fullImage(GregTech.ID, "gui/overlay_slot/molecular_1"); + public static final UITexture OVERLAY_SLOT_MOLECULAR_2 = UITexture + .fullImage(GregTech.ID, "gui/overlay_slot/molecular_2"); + public static final UITexture OVERLAY_SLOT_MOLECULAR_3 = UITexture + .fullImage(GregTech.ID, "gui/overlay_slot/molecular_3"); + public static final UITexture OVERLAY_SLOT_OUT = UITexture.fullImage(GregTech.ID, "gui/overlay_slot/out"); + public static final SteamTexture OVERLAY_SLOT_OUT_STEAM = SteamTexture + .fullImage(GregTech.ID, "gui/overlay_slot/out_%s"); + public static final UITexture OVERLAY_SLOT_PAGE_BLANK = UITexture + .fullImage(GregTech.ID, "gui/overlay_slot/page_blank"); + public static final UITexture OVERLAY_SLOT_PAGE_PRINTED = UITexture + .fullImage(GregTech.ID, "gui/overlay_slot/page_printed"); + public static final UITexture OVERLAY_SLOT_PRESS_1 = UITexture.fullImage(GregTech.ID, "gui/overlay_slot/press_1"); + public static final UITexture OVERLAY_SLOT_PRESS_2 = UITexture.fullImage(GregTech.ID, "gui/overlay_slot/press_2"); + public static final UITexture OVERLAY_SLOT_PRESS_3 = UITexture.fullImage(GregTech.ID, "gui/overlay_slot/press_3"); + public static final UITexture OVERLAY_SLOT_RECYCLE = UITexture.fullImage(GregTech.ID, "gui/overlay_slot/recycle"); + public static final UITexture OVERLAY_SLOT_ROD_1 = UITexture.fullImage(GregTech.ID, "gui/overlay_slot/rod_1"); + public static final UITexture OVERLAY_SLOT_ROD_2 = UITexture.fullImage(GregTech.ID, "gui/overlay_slot/rod_2"); + public static final UITexture OVERLAY_SLOT_SLICE_SHAPE = UITexture + .fullImage(GregTech.ID, "gui/overlay_slot/slice_shape"); + public static final UITexture OVERLAY_SLOT_SLICER_SLICED = UITexture + .fullImage(GregTech.ID, "gui/overlay_slot/slicer_sliced"); + public static final UITexture OVERLAY_SLOT_SQUARE = UITexture.fullImage(GregTech.ID, "gui/overlay_slot/square"); + public static final UITexture OVERLAY_SLOT_UUA = UITexture.fullImage(GregTech.ID, "gui/overlay_slot/uua"); + public static final UITexture OVERLAY_SLOT_UUM = UITexture.fullImage(GregTech.ID, "gui/overlay_slot/uum"); + public static final UITexture OVERLAY_SLOT_VIAL_1 = UITexture.fullImage(GregTech.ID, "gui/overlay_slot/vial_1"); + public static final UITexture OVERLAY_SLOT_VIAL_2 = UITexture.fullImage(GregTech.ID, "gui/overlay_slot/vial_2"); + public static final UITexture OVERLAY_SLOT_WIREMILL = UITexture.fullImage(GregTech.ID, "gui/overlay_slot/wiremill"); + public static final UITexture OVERLAY_SLOT_WRENCH = UITexture.fullImage(GregTech.ID, "gui/overlay_slot/wrench"); + public static final UITexture[] OVERLAY_SLOTS_NUMBER = IntStream.range(0, 12) + .mapToObj(i -> UITexture.fullImage(GregTech.ID, "gui/overlay_slot/number_" + i)) + .collect(Collectors.toList()) + .toArray(new UITexture[0]); + + public static final UITexture PROGRESSBAR_ARROW = UITexture.fullImage(GregTech.ID, "gui/progressbar/arrow"); + public static final SteamTexture PROGRESSBAR_ARROW_STEAM = SteamTexture + .fullImage(GregTech.ID, "gui/progressbar/arrow_%s"); + public static final SteamTexture PROGRESSBAR_ARROW_2_STEAM = SteamTexture + .fullImage(GregTech.ID, "gui/progressbar/arrow_2_%s"); + public static final UITexture PROGRESSBAR_ARROW_MULTIPLE = UITexture + .fullImage(GregTech.ID, "gui/progressbar/arrow_multiple"); + public static final UITexture PROGRESSBAR_ASSEMBLE = UITexture.fullImage(GregTech.ID, "gui/progressbar/assemble"); + public static final UITexture PROGRESSBAR_ASSEMBLY_LINE_1 = UITexture + .fullImage(GregTech.ID, "gui/progressbar/assemblyline_1"); + public static final UITexture PROGRESSBAR_ASSEMBLY_LINE_2 = UITexture + .fullImage(GregTech.ID, "gui/progressbar/assemblyline_2"); + public static final UITexture PROGRESSBAR_ASSEMBLY_LINE_3 = UITexture + .fullImage(GregTech.ID, "gui/progressbar/assemblyline_3"); + public static final UITexture PROGRESSBAR_BATH = UITexture.fullImage(GregTech.ID, "gui/progressbar/bath"); + public static final UITexture PROGRESSBAR_BENDING = UITexture.fullImage(GregTech.ID, "gui/progressbar/bending"); + public static final SteamTexture PROGRESSBAR_BOILER_EMPTY_STEAM = SteamTexture + .fullImage(GregTech.ID, "gui/progressbar/boiler_empty_%s"); + public static final UITexture PROGRESSBAR_BOILER_HEAT = UITexture + .fullImage(GregTech.ID, "gui/progressbar/boiler_heat"); + public static final UITexture PROGRESSBAR_BOILER_STEAM = UITexture + .fullImage(GregTech.ID, "gui/progressbar/boiler_steam"); + public static final UITexture PROGRESSBAR_BOILER_WATER = UITexture + .fullImage(GregTech.ID, "gui/progressbar/boiler_water"); + public static final UITexture PROGRESSBAR_CANNER = UITexture.fullImage(GregTech.ID, "gui/progressbar/canner"); + public static final UITexture PROGRESSBAR_CIRCUIT_ASSEMBLER = UITexture + .fullImage(GregTech.ID, "gui/progressbar/circuit_assembler"); + public static final UITexture PROGRESSBAR_COMPRESS = UITexture.fullImage(GregTech.ID, "gui/progressbar/compress"); + public static final SteamTexture PROGRESSBAR_COMPRESS_STEAM = SteamTexture + .fullImage(GregTech.ID, "gui/progressbar/compress_%s"); + public static final UITexture PROGRESSBAR_CUT = UITexture.fullImage(GregTech.ID, "gui/progressbar/cut"); + public static final UITexture PROGRESSBAR_EXTRACT = UITexture.fullImage(GregTech.ID, "gui/progressbar/extract"); + public static final SteamTexture PROGRESSBAR_EXTRACT_STEAM = SteamTexture + .fullImage(GregTech.ID, "gui/progressbar/extract_%s"); + public static final UITexture PROGRESSBAR_EXTRUDE = UITexture.fullImage(GregTech.ID, "gui/progressbar/extrude"); + public static final SteamTexture PROGRESSBAR_FUEL_STEAM = SteamTexture + .fullImage(GregTech.ID, "gui/progressbar/fuel_%s"); + public static final UITexture PROGRESSBAR_HAMMER = UITexture.fullImage(GregTech.ID, "gui/progressbar/hammer"); + public static final UITexture PROGRESSBAR_HAMMER_BASE = UITexture + .fullImage(GregTech.ID, "gui/progressbar/hammer_base"); + public static final SteamTexture PROGRESSBAR_HAMMER_STEAM = SteamTexture + .fullImage(GregTech.ID, "gui/progressbar/hammer_%s"); + public static final SteamTexture PROGRESSBAR_HAMMER_BASE_STEAM = SteamTexture + .fullImage(GregTech.ID, "gui/progressbar/hammer_base_%s"); + public static final UITexture PROGRESSBAR_LATHE = UITexture.fullImage(GregTech.ID, "gui/progressbar/lathe"); + public static final UITexture PROGRESSBAR_LATHE_BASE = UITexture + .fullImage(GregTech.ID, "gui/progressbar/lathe_base"); + public static final UITexture PROGRESSBAR_MACERATE = UITexture.fullImage(GregTech.ID, "gui/progressbar/macerate"); + public static final SteamTexture PROGRESSBAR_MACERATE_STEAM = SteamTexture + .fullImage(GregTech.ID, "gui/progressbar/macerate_%s"); + public static final UITexture PROGRESSBAR_MAGNET = UITexture.fullImage(GregTech.ID, "gui/progressbar/magnet"); + public static final UITexture PROGRESSBAR_MIXER = UITexture.fullImage(GregTech.ID, "gui/progressbar/mixer"); + public static final UITexture PROGRESSBAR_RECYCLE = UITexture.fullImage(GregTech.ID, "gui/progressbar/recycle"); + public static final UITexture PROGRESSBAR_SIFT = UITexture.fullImage(GregTech.ID, "gui/progressbar/sift"); + public static final UITexture PROGRESSBAR_SLICE = UITexture.fullImage(GregTech.ID, "gui/progressbar/slice"); + public static final UITexture PROGRESSBAR_STORED_EU = UITexture.fullImage(GregTech.ID, "gui/progressbar/stored_eu"); + public static final UITexture PROGRESSBAR_WIREMILL = UITexture.fullImage(GregTech.ID, "gui/progressbar/wiremill"); + + public static FallbackableUITexture fallbackableProgressbar(String name, UITexture fallback) { + return new FallbackableUITexture(UITexture.fullImage(GregTech.ID, "gui/progressbar/" + name), fallback); + } + + public static final UITexture TAB_COVER_NORMAL = UITexture.fullImage(GregTech.ID, "gui/tab/cover_normal"); + public static final UITexture TAB_COVER_HIGHLIGHT = UITexture.fullImage(GregTech.ID, "gui/tab/cover_highlight"); + public static final UITexture TAB_COVER_DISABLED = UITexture.fullImage(GregTech.ID, "gui/tab/cover_disabled"); + public static final SteamTexture TAB_COVER_STEAM_NORMAL = SteamTexture + .fullImage(GregTech.ID, "gui/tab/cover_%s_normal"); + public static final SteamTexture TAB_COVER_STEAM_HIGHLIGHT = SteamTexture + .fullImage(GregTech.ID, "gui/tab/cover_%s_highlight"); + public static final SteamTexture TAB_COVER_STEAM_DISABLED = SteamTexture + .fullImage(GregTech.ID, "gui/tab/cover_%s_disabled"); + public static final AdaptableUITexture TAB_TITLE = AdaptableUITexture.of(GregTech.ID, "gui/tab/title", 28, 28, 4); + public static final AdaptableUITexture TAB_TITLE_DARK = AdaptableUITexture + .of(GregTech.ID, "gui/tab/title_dark", 28, 28, 4); + public static final SteamTexture TAB_TITLE_STEAM = SteamTexture + .adaptableTexture(GregTech.ID, "gui/tab/title_%s", 28, 28, 4); + public static final SteamTexture TAB_TITLE_DARK_STEAM = SteamTexture + .adaptableTexture(GregTech.ID, "gui/tab/title_dark_%s", 28, 28, 4); + public static final AdaptableUITexture TAB_TITLE_ANGULAR = AdaptableUITexture + .of(GregTech.ID, "gui/tab/title_angular", 28, 28, 4); + public static final SteamTexture TAB_TITLE_ANGULAR_STEAM = SteamTexture + .adaptableTexture(GregTech.ID, "gui/tab/title_angular_%s", 28, 28, 4); + + public static final UITexture BUTTON_STANDARD = AdaptableUITexture + .of(GregTech.ID, "gui/button/standard", 18, 18, 1); + public static final UITexture BUTTON_STANDARD_PRESSED = AdaptableUITexture + .of(GregTech.ID, "gui/button/standard_pressed", 18, 18, 1); + public static final UITexture BUTTON_STANDARD_DISABLED = AdaptableUITexture + .of(GregTech.ID, "gui/button/standard_disabled", 18, 18, 1); + public static final UITexture BUTTON_STANDARD_TOGGLE = AdaptableUITexture + .of(GregTech.ID, "gui/button/standard_toggle", 18, 18, 1); + public static final UITexture BUTTON_STANDARD_TOGGLE_DISABLED = AdaptableUITexture + .of(GregTech.ID, "gui/button/standard_toggle_disabled", 18, 18, 1); + public static final UITexture BUTTON_COVER_NORMAL = UITexture.fullImage(GregTech.ID, "gui/button/cover_normal"); + public static final UITexture BUTTON_COVER_NORMAL_HOVERED = UITexture + .fullImage(GregTech.ID, "gui/button/cover_normal_hovered"); + public static final UITexture BUTTON_COVER_NORMAL_DISABLED = UITexture + .fullImage(GregTech.ID, "gui/button/cover_normal_disabled"); + + public static final UITexture OVERLAY_BUTTON_DISABLE = UITexture + .fullImage(GregTech.ID, "gui/overlay_button/disable"); + public static final UITexture OVERLAY_BUTTON_REDSTONE_OFF = UITexture + .fullImage(GregTech.ID, "gui/overlay_button/redstone_off"); + public static final UITexture OVERLAY_BUTTON_REDSTONE_ON = UITexture + .fullImage(GregTech.ID, "gui/overlay_button/redstone_on"); + public static final UITexture OVERLAY_BUTTON_POWER_SWITCH_ON = UITexture + .fullImage(GregTech.ID, "gui/overlay_button/power_switch_on"); + public static final UITexture OVERLAY_BUTTON_POWER_SWITCH_OFF = UITexture + .fullImage(GregTech.ID, "gui/overlay_button/power_switch_off"); + public static final UITexture OVERLAY_BUTTON_VOID_EXCESS_NONE = UITexture + .fullImage(GregTech.ID, "gui/overlay_button/void_excess_none"); + public static final UITexture OVERLAY_BUTTON_VOID_EXCESS_ITEM = UITexture + .fullImage(GregTech.ID, "gui/overlay_button/void_excess_item"); + public static final UITexture OVERLAY_BUTTON_VOID_EXCESS_FLUID = UITexture + .fullImage(GregTech.ID, "gui/overlay_button/void_excess_fluid"); + public static final UITexture OVERLAY_BUTTON_VOID_EXCESS_ALL = UITexture + .fullImage(GregTech.ID, "gui/overlay_button/void_excess_all"); + public static final UITexture OVERLAY_BUTTON_INPUT_SEPARATION_ON = UITexture + .fullImage(GregTech.ID, "gui/overlay_button/input_separation_on"); + public static final UITexture OVERLAY_BUTTON_INPUT_SEPARATION_ON_DISABLED = UITexture + .fullImage(GregTech.ID, "gui/overlay_button/input_separation_on_disabled"); + public static final UITexture OVERLAY_BUTTON_INPUT_SEPARATION_OFF = UITexture + .fullImage(GregTech.ID, "gui/overlay_button/input_separation_off"); + public static final UITexture OVERLAY_BUTTON_INPUT_SEPARATION_OFF_DISABLED = UITexture + .fullImage(GregTech.ID, "gui/overlay_button/input_separation_off_disabled"); + public static final UITexture OVERLAY_BUTTON_RECIPE_LOCKED = UITexture + .fullImage(GregTech.ID, "gui/overlay_button/recipe_locked"); + public static final UITexture OVERLAY_BUTTON_RECIPE_LOCKED_DISABLED = UITexture + .fullImage(GregTech.ID, "gui/overlay_button/recipe_locked_disabled"); + public static final UITexture OVERLAY_BUTTON_RECIPE_UNLOCKED = UITexture + .fullImage(GregTech.ID, "gui/overlay_button/recipe_unlocked"); + public static final UITexture OVERLAY_BUTTON_RECIPE_UNLOCKED_DISABLED = UITexture + .fullImage(GregTech.ID, "gui/overlay_button/recipe_unlocked_disabled"); + public static final UITexture OVERLAY_BUTTON_BATCH_MODE_ON = UITexture + .fullImage(GregTech.ID, "gui/overlay_button/batch_mode_on"); + public static final UITexture OVERLAY_BUTTON_BATCH_MODE_ON_DISABLED = UITexture + .fullImage(GregTech.ID, "gui/overlay_button/batch_mode_on_disabled"); + public static final UITexture OVERLAY_BUTTON_BATCH_MODE_OFF = UITexture + .fullImage(GregTech.ID, "gui/overlay_button/batch_mode_off"); + public static final UITexture OVERLAY_BUTTON_BATCH_MODE_OFF_DISABLED = UITexture + .fullImage(GregTech.ID, "gui/overlay_button/batch_mode_off_disabled"); + public static final UITexture OVERLAY_BUTTON_FORBIDDEN = UITexture + .fullImage(GregTech.ID, "gui/overlay_button/forbidden"); + public static final UITexture OVERLAY_BUTTON_LOCKED = UITexture + .fullImage(GregTech.ID, "gui/overlay_button/lock_small"); + public static final UITexture OVERLAY_BUTTON_DOWN_TIERING_ON = UITexture + .fullImage(GregTech.ID, "gui/overlay_button/down_tiering_on"); + public static final UITexture OVERLAY_BUTTON_DOWN_TIERING_OFF = UITexture + .fullImage(GregTech.ID, "gui/overlay_button/down_tiering_off"); + public static final UITexture OVERLAY_BUTTON_CHECKMARK = UITexture + .fullImage(GregTech.ID, "gui/overlay_button/checkmark"); + public static final UITexture OVERLAY_BUTTON_CROSS = UITexture.fullImage(GregTech.ID, "gui/overlay_button/cross"); + public static final UITexture OVERLAY_BUTTON_WHITELIST = UITexture + .fullImage(GregTech.ID, "gui/overlay_button/whitelist"); + public static final UITexture OVERLAY_BUTTON_BLACKLIST = UITexture + .fullImage(GregTech.ID, "gui/overlay_button/blacklist"); + public static final UITexture OVERLAY_BUTTON_PROGRESS = UITexture + .fullImage(GregTech.ID, "gui/overlay_button/progress"); + public static final UITexture OVERLAY_BUTTON_EXPORT = UITexture.fullImage(GregTech.ID, "gui/overlay_button/export"); + public static final UITexture OVERLAY_BUTTON_IMPORT = UITexture.fullImage(GregTech.ID, "gui/overlay_button/import"); + public static final UITexture OVERLAY_BUTTON_AUTOOUTPUT_ITEM = UITexture + .fullImage(GregTech.ID, "gui/overlay_button/autooutput_item"); + public static final UITexture OVERLAY_BUTTON_AUTOOUTPUT_FLUID = UITexture + .fullImage(GregTech.ID, "gui/overlay_button/autooutput_fluid"); + public static final UITexture OVERLAY_BUTTON_ALLOW_INPUT = UITexture + .fullImage(GregTech.ID, "gui/overlay_button/allow_input"); + public static final UITexture OVERLAY_BUTTON_ALLOW_OUTPUT = UITexture + .fullImage(GregTech.ID, "gui/overlay_button/allow_output"); + public static final UITexture OVERLAY_BUTTON_AUTOPULL_ME = UITexture + .fullImage(GregTech.ID, "gui/overlay_button/auto_pull_me"); + public static final UITexture OVERLAY_BUTTON_AUTOPULL_ME_DISABLED = UITexture + .fullImage(GregTech.ID, "gui/overlay_button/auto_pull_me_disabled"); + public static final UITexture OVERLAY_BUTTON_BLOCK_INPUT = UITexture + .fullImage(GregTech.ID, "gui/overlay_button/block_input"); + public static final UITexture OVERLAY_BUTTON_BLOCK_OUTPUT = UITexture + .fullImage(GregTech.ID, "gui/overlay_button/block_output"); + public static final UITexture OVERLAY_BUTTON_ARROW_GREEN_UP = UITexture + .fullImage(GregTech.ID, "gui/overlay_button/arrow_green_up"); + public static final UITexture OVERLAY_BUTTON_ARROW_GREEN_DOWN = UITexture + .fullImage(GregTech.ID, "gui/overlay_button/arrow_green_down"); + public static final UITexture OVERLAY_BUTTON_CYCLIC = UITexture.fullImage(GregTech.ID, "gui/overlay_button/cyclic"); + public static final UITexture OVERLAY_BUTTON_EMIT_ENERGY = UITexture + .fullImage(GregTech.ID, "gui/overlay_button/emit_energy"); + public static final UITexture OVERLAY_BUTTON_EMIT_REDSTONE = UITexture + .fullImage(GregTech.ID, "gui/overlay_button/emit_redstone"); + public static final UITexture OVERLAY_BUTTON_INVERT_REDSTONE = UITexture + .fullImage(GregTech.ID, "gui/overlay_button/invert_redstone"); + public static final UITexture OVERLAY_BUTTON_STOCKING_MODE = UITexture + .fullImage(GregTech.ID, "gui/overlay_button/stocking_mode"); + public static final UITexture OVERLAY_BUTTON_INVERT_FILTER = UITexture + .fullImage(GregTech.ID, "gui/overlay_button/invert_filter"); + public static final UITexture OVERLAY_BUTTON_NBT = UITexture.fullImage(GregTech.ID, "gui/overlay_button/nbt"); + public static final UITexture OVERLAY_BUTTON_PRINT = UITexture.fullImage(GregTech.ID, "gui/overlay_button/print"); + public static final UITexture OVERLAY_BUTTON_TRANSPOSE = UITexture + .fullImage(GregTech.ID, "gui/overlay_button/transpose"); + public static final UITexture OVERLAY_BUTTON_SORTING_MODE = UITexture + .fullImage(GregTech.ID, "gui/overlay_button/sorting_mode"); + public static final UITexture OVERLAY_BUTTON_ONE_STACK_LIMIT = UITexture + .fullImage(GregTech.ID, "gui/overlay_button/one_stack_limit"); + public static final UITexture OVERLAY_BUTTON_BOUNDING_BOX = UITexture + .fullImage(GregTech.ID, "gui/overlay_button/bounding_box"); + public static final UITexture OVERLAY_BUTTON_MINUS_SMALL = UITexture + .fullImage(GregTech.ID, "gui/overlay_button/minus_small"); + public static final UITexture OVERLAY_BUTTON_MINUS_LARGE = UITexture + .fullImage(GregTech.ID, "gui/overlay_button/minus_large"); + public static final UITexture OVERLAY_BUTTON_PLUS_SMALL = UITexture + .fullImage(GregTech.ID, "gui/overlay_button/plus_small"); + public static final UITexture OVERLAY_BUTTON_PLUS_LARGE = UITexture + .fullImage(GregTech.ID, "gui/overlay_button/plus_large"); + public static final UITexture OVERLAY_BUTTON_GATE_AND = UITexture + .fullImage(GregTech.ID, "gui/overlay_button/gate_and"); + public static final UITexture OVERLAY_BUTTON_GATE_NAND = UITexture + .fullImage(GregTech.ID, "gui/overlay_button/gate_nand"); + public static final UITexture OVERLAY_BUTTON_GATE_OR = UITexture + .fullImage(GregTech.ID, "gui/overlay_button/gate_or"); + public static final UITexture OVERLAY_BUTTON_GATE_NOR = UITexture + .fullImage(GregTech.ID, "gui/overlay_button/gate_nor"); + public static final UITexture OVERLAY_BUTTON_ANALOG = UITexture.fullImage(GregTech.ID, "gui/overlay_button/analog"); + public static final UITexture OVERLAY_BUTTON_LOCK = UITexture.fullImage(GregTech.ID, "gui/overlay_button/lock"); + public static final UITexture OVERLAY_BUTTON_INPUT_FROM_OUTPUT_SIDE = UITexture + .fullImage(GregTech.ID, "gui/overlay_button/input_from_output_side"); + public static final UITexture OVERLAY_BUTTON_TANK_VOID_EXCESS = UITexture + .fullImage(GregTech.ID, "gui/overlay_button/tank_void_excess"); + public static final UITexture OVERLAY_BUTTON_TANK_VOID_ALL = UITexture + .fullImage(GregTech.ID, "gui/overlay_button/tank_void_all"); + public static final UITexture OVERLAY_BUTTON_NEI = UITexture.fullImage(GregTech.ID, "gui/overlay_button/nei"); + public static final UITexture OVERLAY_BUTTON_USE_PROCESSING_STATE = UITexture + .fullImage(GregTech.ID, "gui/overlay_button/use_processing_state.png"); + public static final UITexture OVERLAY_BUTTON_USE_INVERTED_PROCESSING_STATE = UITexture + .fullImage(GregTech.ID, "gui/overlay_button/use_inverted_processing_state.png"); + public static final UITexture OVERLAY_BUTTON_CHUNK_LOADING = UITexture + .fullImage(GregTech.ID, "gui/overlay_button/chunkloading"); + public static final UITexture OVERLAY_BUTTON_CHUNK_LOADING_OFF = UITexture + .fullImage(GregTech.ID, "gui/overlay_button/chunkloading_off"); + public static final UITexture OVERLAY_BUTTON_WORK_AREA = UITexture + .fullImage(GregTech.ID, "gui/overlay_button/work_area"); + public static final UITexture OVERLAY_BUTTON_REPLACE_COBBLE_ON = UITexture + .fullImage(GregTech.ID, "gui/overlay_button/replace_cobble_on"); + public static final UITexture OVERLAY_BUTTON_REPLACE_COBBLE_OFF = UITexture + .fullImage(GregTech.ID, "gui/overlay_button/replace_cobble_off"); + public static final UITexture OVERLAY_BUTTON_RETRACT_PIPE = UITexture + .fullImage(GregTech.ID, "gui/overlay_button/retract_pipes"); + public static final UITexture OVERLAY_BUTTON_HOURGLASS = UITexture + .fullImage(GregTech.ID, "gui/overlay_button/hourglass"); + + /** + * Can adjust size as needed. + */ + public static final AdaptableUITexture PICTURE_SCREEN_BLACK = AdaptableUITexture + .of(GregTech.ID, "gui/picture/screen_black", 16, 16, 2); + + public static final UITexture PICTURE_RADIATION_WARNING = UITexture + .fullImage(GregTech.ID, "gui/picture/radiation_warning"); + public static final UITexture PICTURE_GT_LOGO_17x17_TRANSPARENT = UITexture + .fullImage(GregTech.ID, "gui/picture/gt_logo_17x17_transparent"); + public static final UITexture PICTURE_GT_LOGO_17x17_TRANSPARENT_GRAY = UITexture + .fullImage(GregTech.ID, "gui/picture/gt_logo_17x17_transparent_gray"); + public static final SteamTexture PICTURE_GT_LOGO_17x17_TRANSPARENT_STEAM = SteamTexture + .fullImage(GregTech.ID, "gui/picture/gt_logo_17x17_transparent_%s"); + public static final UITexture PICTURE_GT_LOGO_18x18 = UITexture.fullImage(GregTech.ID, "gui/picture/gt_logo_18x18"); + public static final UITexture PICTURE_GT_LOGO_19x19 = UITexture.fullImage(GregTech.ID, "gui/picture/gt_logo_19x19"); + public static final UITexture PICTURE_INFORMATION = UITexture.fullImage(GregTech.ID, "gui/picture/information"); + public static final UITexture PICTURE_STALLED_ELECTRICITY = UITexture + .fullImage(GregTech.ID, "gui/picture/stalled_electricity"); + public static final UITexture PICTURE_STALLED_STEAM = UITexture.fullImage(GregTech.ID, "gui/picture/stalled_steam"); + public static final BiFunction<Integer, Boolean, UITexture> PICTURE_ARROW_22_RED = (width, fromRight) -> UITexture + .partly( + GregTech.ID, + "gui/picture/arrow_22_red", + 87, + 22, + fromRight ? 87 - width : 0, + 0, + fromRight ? 87 : width, + 22); + public static final BiFunction<Integer, Boolean, UITexture> PICTURE_ARROW_22_BLUE = (width, fromRight) -> UITexture + .partly( + GregTech.ID, + "gui/picture/arrow_22_blue", + 87, + 22, + fromRight ? 87 - width : 0, + 0, + fromRight ? 87 : width, + 22); + public static final BiFunction<Integer, Boolean, UITexture> PICTURE_ARROW_22_WHITE = (width, fromRight) -> UITexture + .partly( + GregTech.ID, + "gui/picture/arrow_22_white", + 87, + 22, + fromRight ? 87 - width : 0, + 0, + fromRight ? 87 : width, + 22); + public static final BiFunction<Integer, Boolean, UITexture> PICTURE_ARROW_24_RED = (width, fromRight) -> UITexture + .partly( + GregTech.ID, + "gui/picture/arrow_24_red", + 69, + 24, + fromRight ? 69 - width : 0, + 0, + fromRight ? 69 : width, + 24); + public static final BiFunction<Integer, Boolean, UITexture> PICTURE_ARROW_24_BLUE = (width, fromRight) -> UITexture + .partly( + GregTech.ID, + "gui/picture/arrow_24_blue", + 69, + 24, + fromRight ? 69 - width : 0, + 0, + fromRight ? 69 : width, + 24); + public static final BiFunction<Integer, Boolean, UITexture> PICTURE_ARROW_24_WHITE = (width, fromRight) -> UITexture + .partly( + GregTech.ID, + "gui/picture/arrow_24_white", + 69, + 24, + fromRight ? 69 - width : 0, + 0, + fromRight ? 69 : width, + 24); + public static final UITexture PICTURE_FLUID_WINDOW = UITexture.fullImage(GregTech.ID, "gui/picture/fluid_window"); + public static final UITexture PICTURE_FLUID_TANK = UITexture.fullImage(GregTech.ID, "gui/picture/fluid_tank"); + public static final UITexture PICTURE_SLOTS_HOLO_3BY3 = UITexture + .fullImage(GregTech.ID, "gui/picture/slots_holo_3by3"); + public static final UITexture PICTURE_ARROW_DOUBLE = UITexture.fullImage(GregTech.ID, "gui/picture/arrow_double"); + public static final UITexture PICTURE_SUPER_BUFFER = UITexture.fullImage(GregTech.ID, "gui/picture/super_buffer"); + public static final UITexture PICTURE_SQUARE_LIGHT_GRAY = UITexture + .fullImage(GregTech.ID, "gui/picture/square_light_gray"); + public static final UITexture PICTURE_GAUGE = UITexture.fullImage(GregTech.ID, "gui/picture/gauge"); + public static final UITexture PICTURE_ITEM_IN = UITexture.fullImage(GregTech.ID, "gui/picture/item_in"); + public static final UITexture PICTURE_ITEM_OUT = UITexture.fullImage(GregTech.ID, "gui/picture/item_out"); + public static final UITexture PICTURE_FLUID_IN = UITexture.fullImage(GregTech.ID, "gui/picture/fluid_in"); + public static final UITexture PICTURE_FLUID_OUT = UITexture.fullImage(GregTech.ID, "gui/picture/fluid_out"); +} diff --git a/src/main/java/gregtech/api/gui/modularui/GUITextureSet.java b/src/main/java/gregtech/api/gui/modularui/GUITextureSet.java new file mode 100644 index 0000000000..18d7741421 --- /dev/null +++ b/src/main/java/gregtech/api/gui/modularui/GUITextureSet.java @@ -0,0 +1,156 @@ +package gregtech.api.gui.modularui; + +import java.util.function.Function; + +import com.gtnewhorizons.modularui.api.ModularUITextures; +import com.gtnewhorizons.modularui.api.drawable.AdaptableUITexture; +import com.gtnewhorizons.modularui.api.drawable.UITexture; + +import gregtech.api.enums.SteamVariant; + +/** + * Set of textures that is commonly used for GUI but can vary depending on "style" of machines, e.g. bronze steam or + * steel steam. <br> + * This has builder pattern; Textures you didn't specify will fall back to default ones. + */ +public class GUITextureSet { + + private UITexture mainBackground; + private UITexture itemSlot; + private UITexture fluidSlot; + private UITexture coverTabNormal; + private UITexture coverTabHighlight; + private UITexture coverTabDisabled; + private UITexture coverTabNormalFlipped; + private UITexture coverTabHighlightFlipped; + private UITexture coverTabDisabledFlipped; + private AdaptableUITexture titleTabNormal; + private AdaptableUITexture titleTabDark; + private AdaptableUITexture titleTabAngular; + private UITexture gregtechLogo; + + public static final GUITextureSet DEFAULT = new GUITextureSet() + .setMainBackground(GT_UITextures.BACKGROUND_SINGLEBLOCK_DEFAULT) + .setItemSlot(ModularUITextures.ITEM_SLOT) + .setFluidSlot(ModularUITextures.FLUID_SLOT) + .setCoverTab( + GT_UITextures.TAB_COVER_NORMAL, + GT_UITextures.TAB_COVER_HIGHLIGHT, + GT_UITextures.TAB_COVER_DISABLED) + .setTitleTab(GT_UITextures.TAB_TITLE, GT_UITextures.TAB_TITLE_DARK, GT_UITextures.TAB_TITLE_ANGULAR) + .setGregTechLogo(GT_UITextures.PICTURE_GT_LOGO_17x17_TRANSPARENT); + + public static final Function<SteamVariant, GUITextureSet> STEAM = steamVariant -> new GUITextureSet() + .setMainBackground(GT_UITextures.BACKGROUND_STEAM.get(steamVariant)) + .setItemSlot(GT_UITextures.SLOT_ITEM_STEAM.get(steamVariant)) + .setFluidSlot(GT_UITextures.SLOT_FLUID_STEAM.get(steamVariant)) + .setCoverTab( + GT_UITextures.TAB_COVER_STEAM_NORMAL.get(steamVariant), + GT_UITextures.TAB_COVER_STEAM_HIGHLIGHT.get(steamVariant), + GT_UITextures.TAB_COVER_STEAM_DISABLED.get(steamVariant)) + .setTitleTab( + GT_UITextures.TAB_TITLE_STEAM.getAdaptable(steamVariant), + GT_UITextures.TAB_TITLE_DARK_STEAM.getAdaptable(steamVariant), + GT_UITextures.TAB_TITLE_ANGULAR_STEAM.getAdaptable(steamVariant)) + .setGregTechLogo(GT_UITextures.PICTURE_GT_LOGO_17x17_TRANSPARENT_STEAM.get(steamVariant)); + + public GUITextureSet() {} + + // region setters + + public GUITextureSet setMainBackground(UITexture mainBackground) { + this.mainBackground = mainBackground; + return this; + } + + public GUITextureSet setItemSlot(UITexture itemSlot) { + this.itemSlot = itemSlot; + return this; + } + + public GUITextureSet setFluidSlot(UITexture fluidSlot) { + this.fluidSlot = fluidSlot; + return this; + } + + public GUITextureSet setCoverTab(UITexture coverNormal, UITexture coverHighlight, UITexture coverDisabled) { + this.coverTabNormal = coverNormal; + this.coverTabHighlight = coverHighlight; + this.coverTabDisabled = coverDisabled; + this.coverTabNormalFlipped = coverNormal.getFlipped(true, false); + this.coverTabHighlightFlipped = coverHighlight.getFlipped(true, false); + this.coverTabDisabledFlipped = coverDisabled.getFlipped(true, false); + return this; + } + + public GUITextureSet setTitleTab(AdaptableUITexture titleNormal, AdaptableUITexture titleDark, + AdaptableUITexture titleTabAngular) { + this.titleTabNormal = titleNormal; + this.titleTabDark = titleDark; + this.titleTabAngular = titleTabAngular; + return this; + } + + public GUITextureSet setGregTechLogo(UITexture gregtechLogo) { + this.gregtechLogo = gregtechLogo; + return this; + } + + // endregion + + // region getters + + public UITexture getMainBackground() { + return mainBackground != null ? mainBackground : DEFAULT.mainBackground; + } + + public UITexture getItemSlot() { + return itemSlot != null ? itemSlot : DEFAULT.itemSlot; + } + + public UITexture getFluidSlot() { + return fluidSlot != null ? fluidSlot : DEFAULT.fluidSlot; + } + + public UITexture getCoverTabNormal() { + return coverTabNormal != null ? coverTabNormal : DEFAULT.coverTabNormal; + } + + public UITexture getCoverTabHighlight() { + return coverTabHighlight != null ? coverTabHighlight : DEFAULT.coverTabHighlight; + } + + public UITexture getCoverTabDisabled() { + return coverTabDisabled != null ? coverTabDisabled : DEFAULT.coverTabDisabled; + } + + public UITexture getCoverTabNormalFlipped() { + return coverTabNormalFlipped != null ? coverTabNormalFlipped : DEFAULT.coverTabNormalFlipped; + } + + public UITexture getCoverTabHighlightFlipped() { + return coverTabHighlightFlipped != null ? coverTabHighlightFlipped : DEFAULT.coverTabHighlightFlipped; + } + + public UITexture getCoverTabDisabledFlipped() { + return coverTabDisabledFlipped != null ? coverTabDisabledFlipped : DEFAULT.coverTabDisabledFlipped; + } + + public AdaptableUITexture getTitleTabNormal() { + return titleTabNormal != null ? titleTabNormal : DEFAULT.titleTabNormal; + } + + public AdaptableUITexture getTitleTabDark() { + return titleTabDark != null ? titleTabDark : DEFAULT.titleTabDark; + } + + public AdaptableUITexture getTitleTabAngular() { + return titleTabAngular != null ? titleTabAngular : DEFAULT.titleTabAngular; + } + + public UITexture getGregTechLogo() { + return gregtechLogo != null ? gregtechLogo : DEFAULT.gregtechLogo; + } + + // endregion +} diff --git a/src/main/java/gregtech/api/gui/modularui/IDataFollowerWidget.java b/src/main/java/gregtech/api/gui/modularui/IDataFollowerWidget.java new file mode 100644 index 0000000000..393b8431e2 --- /dev/null +++ b/src/main/java/gregtech/api/gui/modularui/IDataFollowerWidget.java @@ -0,0 +1,50 @@ +package gregtech.api.gui.modularui; + +import java.util.function.Consumer; +import java.util.function.Function; + +import com.gtnewhorizons.modularui.api.widget.Widget; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import gregtech.api.util.ISerializableObject; +import gregtech.common.gui.modularui.widget.DataControllerWidget; + +/** + * Widget whose state is controlled by specific data. Data can be anything, e.g. {@link ISerializableObject} or machine + * recipe mode. <br> + * No widgets implementing this interface should not sync; Instead, {@link DataControllerWidget} will sync data, either + * when this widget triggers update on client or data update is detected on server. + * + * @param <T> Data type stored in the parent widget + * @param <U> State type stored in this widget + * @see DataControllerWidget + */ +@SuppressWarnings("UnusedReturnValue") +public interface IDataFollowerWidget<T, U> { + + /** + * Sets function to get widget state from provided data. This function will be called when client receives data from + * server and {@link DataControllerWidget} updates all children, including this widget. + */ + Widget setDataToStateGetter(Function<T, U> dataToStateGetter); + + /** + * Sets setter called when this widget gets action from player. Basically the same functionality with widgets that + * have getter/setter. + */ + Widget setStateSetter(Consumer<U> setter); + + /** + * Updates state of this widget with provided data. On server {@link DataControllerWidget} won't propagate data + * update to this widget, so this method is client-only. + */ + @SideOnly(Side.CLIENT) + void updateState(T data); + + /** + * Called on {@link Widget#onPostInit}. + */ + @SuppressWarnings("OverrideOnly") // So IntelliJ doesn't warn about the Widget#onPostInit link in the javadoc + default void onPostInit() {} +} diff --git a/src/main/java/gregtech/api/gui/modularui/SteamTexture.java b/src/main/java/gregtech/api/gui/modularui/SteamTexture.java new file mode 100644 index 0000000000..301671afe8 --- /dev/null +++ b/src/main/java/gregtech/api/gui/modularui/SteamTexture.java @@ -0,0 +1,62 @@ +package gregtech.api.gui.modularui; + +import com.gtnewhorizons.modularui.api.drawable.AdaptableUITexture; +import com.gtnewhorizons.modularui.api.drawable.UITexture; + +import gregtech.api.enums.SteamVariant; + +/** + * Wrapper for {@link UITexture}s used to ease in choosing between Bronze, Steel and Primitive textures. + */ +public class SteamTexture { + + private final UITexture bronzeTexture; + private final UITexture steelTexture; + private final UITexture primitiveTexture; + + private SteamTexture(UITexture bronzeTexture, UITexture steelTexture, UITexture primitiveTexture) { + this.bronzeTexture = bronzeTexture; + this.steelTexture = steelTexture; + this.primitiveTexture = primitiveTexture; + } + + public static SteamTexture fullImage(String mod, String location) { + return new SteamTexture( + UITexture.fullImage(mod, String.format(location, SteamVariant.BRONZE)), + UITexture.fullImage(mod, String.format(location, SteamVariant.STEEL)), + UITexture.fullImage(mod, String.format(location, SteamVariant.PRIMITIVE))); + } + + public static SteamTexture adaptableTexture(String mod, String location, int imageWidth, int imageHeight, + int borderWidthPixel) { + return new SteamTexture( + AdaptableUITexture + .of(mod, String.format(location, SteamVariant.BRONZE), imageWidth, imageHeight, borderWidthPixel), + AdaptableUITexture + .of(mod, String.format(location, SteamVariant.STEEL), imageWidth, imageHeight, borderWidthPixel), + AdaptableUITexture + .of(mod, String.format(location, SteamVariant.PRIMITIVE), imageWidth, imageHeight, borderWidthPixel)); + } + + public UITexture get(SteamVariant variant) { + return switch (variant) { + case BRONZE -> bronzeTexture; + case STEEL -> steelTexture; + case PRIMITIVE -> primitiveTexture; + default -> null; + }; + } + + public AdaptableUITexture getAdaptable(SteamVariant variant) { + return switch (variant) { + case BRONZE -> (AdaptableUITexture) bronzeTexture; + case STEEL -> (AdaptableUITexture) steelTexture; + case PRIMITIVE -> (AdaptableUITexture) primitiveTexture; + default -> null; + }; + } + + public UITexture get(boolean isHighPressure) { + return isHighPressure ? steelTexture : bronzeTexture; + } +} diff --git a/src/main/java/gregtech/api/gui/widgets/GT_CoverTickRateButton.java b/src/main/java/gregtech/api/gui/widgets/GT_CoverTickRateButton.java new file mode 100644 index 0000000000..883ffb4079 --- /dev/null +++ b/src/main/java/gregtech/api/gui/widgets/GT_CoverTickRateButton.java @@ -0,0 +1,82 @@ +package gregtech.api.gui.widgets; + +import static gregtech.api.gui.modularui.GT_UITextures.OVERLAY_BUTTON_HOURGLASS; +import static gregtech.common.covers.CoverInfo.MAX_TICK_RATE_ADDITION; + +import java.util.List; + +import net.minecraft.util.StatCollector; + +import org.jetbrains.annotations.NotNull; + +import com.google.common.collect.ImmutableList; +import com.gtnewhorizons.modularui.api.drawable.UITexture; +import com.gtnewhorizons.modularui.api.widget.IWidgetBuilder; +import com.gtnewhorizons.modularui.api.widget.Widget; +import com.gtnewhorizons.modularui.common.widget.ButtonWidget; +import com.gtnewhorizons.modularui.common.widget.FakeSyncWidget; + +import gregtech.api.gui.modularui.GT_UITextures; +import gregtech.common.covers.CoverInfo; + +public class GT_CoverTickRateButton extends ButtonWidget { + + private static final UITexture BACKGROUND = GT_UITextures.BUTTON_COVER_NORMAL.getSubArea(0, 0, 1, 0.5f); + + private final CoverInfo coverInfo; + private int clientTickRate; + private int tickRateAddition; + + public GT_CoverTickRateButton(@NotNull CoverInfo coverInfo, @NotNull IWidgetBuilder<?> builder) { + this.coverInfo = coverInfo; + this.clientTickRate = coverInfo.getTickRate(); + this.tickRateAddition = coverInfo.getTickRateAddition(); + + super.setBackground(BACKGROUND, OVERLAY_BUTTON_HOURGLASS); + super.setOnClick(this::onClick); + super.dynamicTooltip(this::dynamicTooltip); + super.attachSyncer( + new FakeSyncWidget.IntegerSyncer(this.coverInfo::getTickRate, integer -> clientTickRate = integer), + builder, + (widget, aInt) -> notifyTooltipChange()) + .attachSyncer( + new FakeSyncWidget.IntegerSyncer( + this.coverInfo::getTickRateAddition, + integer -> tickRateAddition = integer), + builder); + + } + + private void onClick(@NotNull ClickData clickData, @NotNull Widget widget) { + final int iterations = clickData.ctrl ? 5 : 1; + final boolean isDecreasing = clickData.mouseButton == 1; + + // Do five operations at once if Ctrl is held down. Since the actual increase granted by each invocation can be + // different on each call, just call the method several times rather than trying to do a bunch of weird math. + for (int i = 0; i < iterations; i++) { + coverInfo.adjustTickRateMultiplier(isDecreasing); + } + } + + private List<String> dynamicTooltip() { + final String boundsNotification; + + if (tickRateAddition == 0) { + boundsNotification = StatCollector.translateToLocal("gt.cover.info.button.bounds_notification.minimum"); + } else if (tickRateAddition >= MAX_TICK_RATE_ADDITION - 1) { + // Clamping can make tickRateAddition approach but never actually equal MAX_ADDITION, so we need this + // adjustment. + boundsNotification = StatCollector.translateToLocal("gt.cover.info.button.bounds_notification.maximum"); + } else { + boundsNotification = ""; + } + + return ImmutableList.of( + StatCollector.translateToLocalFormatted( + "gt.cover.info.button.tick_rate.1", + new CoverInfo.ClientTickRateFormatter(clientTickRate), + boundsNotification), + StatCollector.translateToLocal("gt.cover.info.button.tick_rate.2"), + StatCollector.translateToLocal("gt.cover.info.button.tick_rate.3")); + } +} diff --git a/src/main/java/gregtech/api/gui/widgets/GT_GuiCoverTabLine.java b/src/main/java/gregtech/api/gui/widgets/GT_GuiCoverTabLine.java new file mode 100644 index 0000000000..6f4eb0e2c2 --- /dev/null +++ b/src/main/java/gregtech/api/gui/widgets/GT_GuiCoverTabLine.java @@ -0,0 +1,179 @@ +package gregtech.api.gui.widgets; + +import java.awt.Rectangle; +import java.util.List; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.inventory.GuiContainer; +import net.minecraft.item.ItemStack; +import net.minecraft.util.EnumChatFormatting; +import net.minecraft.util.StatCollector; +import net.minecraftforge.common.util.ForgeDirection; + +import org.lwjgl.opengl.GL11; + +import codechicken.nei.api.API; +import codechicken.nei.api.INEIGuiAdapter; +import gregtech.api.enums.GT_Values; +import gregtech.api.gui.GT_GUIContainerMetaTile_Machine; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.net.GT_Packet_GtTileEntityGuiRequest; +import gregtech.common.GT_Proxy; + +/** + * Let's you access a GregTech IGregTechTileEntity's covers as tabs on the GUI's sides + */ +public class GT_GuiCoverTabLine extends GT_GuiTabLine { + + // Names of the block a cover could be on + private static final String[] SIDES = new String[] { "GT5U.interface.coverTabs.down", "GT5U.interface.coverTabs.up", + "GT5U.interface.coverTabs.north", "GT5U.interface.coverTabs.south", "GT5U.interface.coverTabs.west", + "GT5U.interface.coverTabs.east" }; + + // Not sure if there's a point in JIT translation but that's what this is + private final String[] translatedSides; + private final IGregTechTileEntity tile; + private final int colorization; + + /** + * Let's you access an IGregTechTileEntity's covers as tabs on the GUI's sides + * + * @param gui GT_ITabRenderer gui which this tab line attaches to + * @param tabLineLeft left position of the tab line in relation to the gui + * @param tabLineTop top position of the tab line in relation to the gui + * @param tabHeight height of a tab + * @param tabWidth width of a tab + * @param tabSpacing pixels between each tab + * @param xDir whether to extend the line horizontally to the right (NORMAL), the left (INVERSE) or not at + * all (NONE) + * @param yDir whether to extend the line vertically down (NORMAL), up (INVERSE) or not at all (NONE) + * @param displayMode whether to display on the left side of the GT_ITabRenderer (NORMAL), on it's right side + * (INVERSE) or not at all (NONE) + * @param tabBackground the set of textures used to draw this tab line's tab backgrounds + * @param tile The IGregTechTileEntity the covers of which we are accessing + * @param colorization The colorization of the GUI we are adding tabs to + */ + public GT_GuiCoverTabLine(GT_GUIContainerMetaTile_Machine gui, int tabLineLeft, int tabLineTop, int tabHeight, + int tabWidth, int tabSpacing, DisplayStyle xDir, DisplayStyle yDir, DisplayStyle displayMode, + GT_GuiTabIconSet tabBackground, IGregTechTileEntity tile, int colorization) { + super(gui, 6, tabLineLeft, tabLineTop, tabHeight, tabWidth, tabSpacing, xDir, yDir, displayMode, tabBackground); + this.tile = tile; + this.colorization = colorization; + this.translatedSides = new String[6]; + setupTabs(); + } + + /** + * Add a tab for each existing cover on this IGregTechTileEntity at creation time + */ + private void setupTabs() { + for (final ForgeDirection side : ForgeDirection.VALID_DIRECTIONS) { + final ItemStack cover = tile.getCoverItemAtSide(side); + if (cover != null) { + addCoverToTabs(side, cover); + } + } + } + + @Override + protected void drawBackground(float parTicks, int mouseX, int mouseY) { + // Apply this tile's coloration to draw the background + GL11.glColor3ub( + (byte) ((colorization >> 16) & 0xFF), + (byte) ((colorization >> 8) & 0xFF), + (byte) (colorization & 0xFF)); + super.drawBackground(parTicks, mouseX, mouseY); + } + + @Override + protected void tabClicked(int tabId, int mouseButton) { + if (mouseButton == 0 && mTabs[tabId].enabled) { + GT_Values.NW.sendToServer( + new GT_Packet_GtTileEntityGuiRequest( + this.tile.getXCoord(), + this.tile.getYCoord(), + this.tile.getZCoord(), + tabId + GT_Proxy.GUI_ID_COVER_SIDE_BASE, + this.tile.getWorld().provider.dimensionId, + Minecraft.getMinecraft().thePlayer.getEntityId(), + 0)); + } + } + + /** + * Add the cover on this side of the IGregTechTileEntity to the tabs + * + * @param side side to apply the cover to + * @param cover cover to add + */ + private void addCoverToTabs(ForgeDirection side, ItemStack cover) { + final boolean enabled = this.tile.getCoverBehaviorAtSideNew(side) + .hasCoverGUI(); + final int ordinalSide = side.ordinal(); + this.setTab(ordinalSide, cover, null, getTooltipForCoverTab(side, cover, enabled)); + this.setTabEnabled(ordinalSide, enabled); + } + + /** + * Decorate the cover's tooltips according to the side it's on and on whether the tab is enabled or not + * + * @param side side + * @param cover cover which tooltip to decorate + * @param enabled if the tab is enabled + * @return This cover tab's tooltip + */ + private String[] getTooltipForCoverTab(ForgeDirection side, ItemStack cover, boolean enabled) { + final List<String> tooltip = cover.getTooltip(Minecraft.getMinecraft().thePlayer, true); + tooltip.set( + 0, + (enabled ? EnumChatFormatting.UNDERLINE : EnumChatFormatting.DARK_GRAY) + getSideDescription(side) + + (enabled ? EnumChatFormatting.RESET + ": " : ": " + EnumChatFormatting.RESET) + + tooltip.get(0)); + return tooltip.toArray(new String[0]); + } + + /** + * Get the translated name for a side of the IGregTechTileEntity + * + * @param side side of the entity + * @return translated name for a side of the IGregTechTileEntity + */ + private String getSideDescription(ForgeDirection side) { + final int ordinalSide = side.ordinal(); + if (ordinalSide < SIDES.length) { + if (this.translatedSides[ordinalSide] == null) { + this.translatedSides[ordinalSide] = StatCollector.translateToLocal(SIDES[ordinalSide]); + } + return this.translatedSides[ordinalSide]; + } + return null; + } + + /** + * Hide any NEI slots that would intersect with a cover tab + */ + static class CoverTabLineNEIHandler extends INEIGuiAdapter { + + @Override + public boolean hideItemPanelSlot(GuiContainer gui, int x, int y, int w, int h) { + final Rectangle neiSlotArea = new Rectangle(x, y, w, h); + if (gui instanceof GT_GUIContainerMetaTile_Machine) { + final GT_GuiTabLine tabLine = ((GT_GUIContainerMetaTile_Machine) gui).coverTabs; + if (!tabLine.visible) { + return false; + } + for (int i = 0; i < tabLine.mTabs.length; i++) { + if (tabLine.mTabs[i] != null && tabLine.mTabs[i].getBounds() + .intersects(neiSlotArea)) { + return true; + } + } + } + return false; + } + } + + static { + API.registerNEIGuiHandler(new CoverTabLineNEIHandler()); + } +} diff --git a/src/main/java/gregtech/api/gui/widgets/GT_GuiFakeItemButton.java b/src/main/java/gregtech/api/gui/widgets/GT_GuiFakeItemButton.java new file mode 100644 index 0000000000..9f4287a65b --- /dev/null +++ b/src/main/java/gregtech/api/gui/widgets/GT_GuiFakeItemButton.java @@ -0,0 +1,162 @@ +package gregtech.api.gui.widgets; + +import java.awt.Rectangle; +import java.util.List; + +import net.minecraft.client.Minecraft; +import net.minecraft.item.ItemBlock; +import net.minecraft.item.ItemStack; + +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL12; + +import codechicken.lib.gui.GuiDraw; +import gregtech.api.interfaces.IGuiScreen; +import gregtech.api.util.GT_UtilityClient; + +public class GT_GuiFakeItemButton implements IGuiScreen.IGuiElement { + + private GT_GuiIcon bgIcon; + private ItemStack item; + private final IGuiScreen gui; + private int xPosition, yPosition; + private List<String> itemTooltips; + private final GT_GuiTooltip tooltip = new GT_GuiTooltip(null) { + + @Override + public List<String> getToolTipText() { + return itemTooltips; + } + + @Override + public boolean isDelayed() { + return false; + } + + @Override + public Rectangle getBounds() { + return GT_GuiFakeItemButton.this.getBounds(); + } + }; + private final Rectangle rectangle; + private boolean mimicSlot; + + public GT_GuiFakeItemButton(IGuiScreen gui, int x, int y, GT_GuiIcon bgIcon) { + this.gui = gui; + this.bgIcon = bgIcon; + item = null; + rectangle = new Rectangle(x, y, 18, 18); + gui.addElement(this); + } + + public GT_GuiFakeItemButton setItem(ItemStack i) { + item = i; + if (getMimicSlot()) updateTooltip(); + return this; + } + + private void updateTooltip() { + itemTooltips = item == null ? null : GT_UtilityClient.getTooltip(item, true); + } + + public ItemStack getItem() { + return item; + } + + public GT_GuiFakeItemButton setMimicSlot(boolean mimicSlot) { + if (mimicSlot != this.mimicSlot) { + if (mimicSlot) { + updateTooltip(); + gui.addToolTip(tooltip); + } else { + gui.removeToolTip(tooltip); + } + this.mimicSlot = mimicSlot; + } + return this; + } + + public boolean getMimicSlot() { + return mimicSlot; + } + + public GT_GuiIcon getBgIcon() { + return bgIcon; + } + + public GT_GuiFakeItemButton setBgIcon(GT_GuiIcon bgIcon) { + this.bgIcon = bgIcon; + return this; + } + + @Override + public void onInit() { + xPosition = rectangle.x + gui.getGuiLeft(); + yPosition = rectangle.y + gui.getGuiTop(); + } + + @Override + public void onRemoved() { + if (mimicSlot) gui.removeToolTip(tooltip); + } + + @Override + public void draw(int mouseX, int mouseY, float parTicks) { + GL11.glColor4f(1, 1, 1, 1); + GL11.glPushAttrib(GL11.GL_ENABLE_BIT); + GL11.glEnable(GL11.GL_BLEND); + GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); + + if (bgIcon != null) { + GT_GuiIcon.render(bgIcon, xPosition - 1, yPosition - 1, 18, 18, 0, true); + } + + if (item != null) { + if (item.getItem() instanceof ItemBlock) { + GL11.glPushAttrib(GL11.GL_ENABLE_BIT); + GL11.glEnable(GL12.GL_RESCALE_NORMAL); + } + gui.getItemRenderer() + .renderItemAndEffectIntoGUI( + gui.getFontRenderer(), + Minecraft.getMinecraft() + .getTextureManager(), + item, + xPosition, + yPosition); + + if (item.getItem() instanceof ItemBlock) GL11.glPopAttrib(); + } + + if (getMimicSlot()) if (getBounds().contains(mouseX - gui.getGuiLeft(), mouseY - gui.getGuiTop())) { + GL11.glDisable(GL11.GL_LIGHTING); + GL11.glDisable(GL11.GL_DEPTH_TEST); + GL11.glColorMask(true, true, true, false); + GuiDraw.drawGradientRect(xPosition, yPosition, 16, 16, 0x80ffffff, 0x80ffffff); + GL11.glColorMask(true, true, true, true); + // no glEnable, state will be recovered by glPopAttrib + } + + GL11.glPopAttrib(); + } + + public Rectangle getBounds() { + return rectangle; + } + + public void setX(int x) { + rectangle.x = x; + } + + public void setY(int y) { + rectangle.y = y; + } + + public void setWidth(int width) { + rectangle.width = width; + } + + public void setHeight(int height) { + rectangle.height = height; + } +} diff --git a/src/main/java/gregtech/api/gui/widgets/GT_GuiIcon.java b/src/main/java/gregtech/api/gui/widgets/GT_GuiIcon.java new file mode 100644 index 0000000000..66ab27356e --- /dev/null +++ b/src/main/java/gregtech/api/gui/widgets/GT_GuiIcon.java @@ -0,0 +1,157 @@ +package gregtech.api.gui.widgets; + +import static gregtech.api.enums.Mods.GregTech; + +import java.util.Arrays; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.util.ResourceLocation; + +import gregtech.api.interfaces.IGuiIcon; + +public enum GT_GuiIcon implements IGuiIcon { + + BUTTON_NORMAL(0, 0, 0), + BUTTON_DOWN(0, 32, 0), + BUTTON_HIGHLIGHT(0, 32 * 2, 0), + BUTTON_HIGHLIGHT_DOWN(0, 32 * 3, 0), + BUTTON_DISABLED(0, 32 * 4, 0), + + DISABLE(0, 0, 32), + REDSTONE_OFF(0, 32, 32), + REDSTONE_ON(0, 32 * 2, 32), + CHECKMARK(0, 32 * 3, 32), + CROSS(0, 32 * 4, 32), + WHITELIST(0, 32 * 5, 32), + BLACKLIST(0, 32 * 6, 32), + PROGRESS(0, 32 * 7, 32), + + EXPORT(0, 0, 32 * 2), + IMPORT(0, 32, 32 * 2), + ALLOW_INPUT(0, 32 * 2, 32 * 2), + BLOCK_INPUT(0, 32 * 3, 32 * 2), + GREEN_ARROW_UP(0, 32 * 4, 32 * 2), + GREEN_ARROW_DOWN(0, 32 * 5, 32 * 2), + CYCLIC(0, 32 * 6, 32 * 2), + + AND_GATE(0, 0, 32 * 3), + NAND_GATE(0, 32, 32 * 3), + OR_GATE(0, 32 * 2, 32 * 3), + NOR_GATE(0, 32 * 3, 32 * 3), + ANALOG_MODE(0, 32 * 4, 32 * 3), + + SLOT_DARKGRAY(1, 176, 0, 18, 18), + SLOT_GRAY(1, 176, 18, 18, 18), + + TAB_NORMAL(2, 0, 0, 18, 20), + TAB_HIGHLIGHT(2, 18, 0, 18, 20), + TAB_DISABLED(2, 18 * 2, 0, 18, 20), + TAB_NORMAL_BRONZE(2, 0, 20, 18, 20), + TAB_HIGHLIGHT_BRONZE(2, 18, 20, 18, 20), + TAB_DISABLED_BRONZE(2, 18 * 2, 20, 18, 20), + TAB_NORMAL_STEEL(2, 0, 2 * 20, 18, 20), + TAB_HIGHLIGHT_STEEL(2, 18, 2 * 20, 18, 20), + TAB_DISABLED_STEEL(2, 18 * 2, 2 * 20, 18, 20), + TAB_NORMAL_BRICK(2, 0, 3 * 20, 18, 20), + TAB_HIGHLIGHT_BRICK(2, 18, 3 * 20, 18, 20), + TAB_DISABLED_BRICK(2, 18 * 2, 3 * 20, 18, 20), + TAB_INFO_GRAY(2, 220, 0, 18, 20), + TAB_INFO_BLUE(2, 220 + 18, 0, 18, 20),; + + private static final int T_SIZE = 256; + private static ResourceLocation[] TEXTURES = { new ResourceLocation(GregTech.ID, "textures/gui/GuiButtons.png"), + new ResourceLocation(GregTech.ID, "textures/gui/GuiCover.png"), + new ResourceLocation(GregTech.ID, "textures/gui/GuiTabs.png"), }; + + public final int x, y, width, height; + public final IGuiIcon overlay; + private final int texID; + + GT_GuiIcon(int texID, int x, int y, int width, int height, IGuiIcon overlay) { + this.x = x; + this.y = y; + this.width = width; + this.height = height; + this.overlay = overlay; + this.texID = texID; + } + + GT_GuiIcon(int texID, int x, int y) { + this(texID, x, y, 32, 32, null); + } + + GT_GuiIcon(int texID, int x, int y, int width, int height) { + this(texID, x, y, width, height, null); + } + + public static void render(IGuiIcon icon, double x, double y, double width, double height, double zLevel, + boolean doDraw) { + render(icon, x, y, width, height, zLevel, doDraw, false); + } + + public static void render(IGuiIcon icon, double x, double y, double width, double height, double zLevel, + boolean doDraw, boolean flipHoritontally) { + Tessellator tess = Tessellator.instance; + if (doDraw) { + Minecraft.getMinecraft().renderEngine.bindTexture(TEXTURES[icon.getTexId()]); + tess.startDrawingQuads(); + } + double minU = (double) (icon.getX() + (flipHoritontally ? icon.getWidth() : 0)) / T_SIZE; + double maxU = (double) (icon.getX() + (flipHoritontally ? 0 : icon.getWidth())) / T_SIZE; + double minV = (double) icon.getY() / T_SIZE; + double maxV = (double) (icon.getY() + icon.getHeight()) / T_SIZE; + tess.addVertexWithUV(x, y + height, zLevel, minU, maxV); + tess.addVertexWithUV(x + width, y + height, zLevel, maxU, maxV); + tess.addVertexWithUV(x + width, y + 0, zLevel, maxU, minV); + tess.addVertexWithUV(x, y + 0, zLevel, minU, minV); + + if (icon.getOverlay() != null) render(icon.getOverlay(), x, y, width, height, zLevel, false); + + if (doDraw) tess.draw(); + } + + /** + * This is intended to enable addon mods to register additional textures. They can then add to this enum using + * EnumHelper.addEnum or by creating their enum that implements IGuiIcon (still requires adding a texture here) + * + * @param location location of the texture to add + */ + public static void addTextures(ResourceLocation... location) { + if (location == null || location.length == 0) return; + + int startIndex = TEXTURES.length; + TEXTURES = Arrays.copyOf(TEXTURES, location.length); + System.arraycopy(location, 0, TEXTURES, startIndex, location.length); + } + + @Override + public int getX() { + return this.x; + } + + @Override + public int getY() { + return this.y; + } + + @Override + public int getWidth() { + return this.width; + } + + @Override + public int getHeight() { + return this.height; + } + + @Override + public int getTexId() { + return this.texID; + } + + @Override + public IGuiIcon getOverlay() { + return this.overlay; + } +} diff --git a/src/main/java/gregtech/api/gui/widgets/GT_GuiIconButton.java b/src/main/java/gregtech/api/gui/widgets/GT_GuiIconButton.java new file mode 100644 index 0000000000..d4bfe31404 --- /dev/null +++ b/src/main/java/gregtech/api/gui/widgets/GT_GuiIconButton.java @@ -0,0 +1,114 @@ +package gregtech.api.gui.widgets; + +import java.awt.Rectangle; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiButton; + +import org.lwjgl.opengl.GL11; + +import gregtech.api.interfaces.IGuiScreen; + +public class GT_GuiIconButton extends GuiButton implements IGuiScreen.IGuiElement { + + public static final int DEFAULT_WIDTH = 16; + public static final int DEFAULT_HEIGHT = 16; + + protected GT_GuiIcon icon; + private final int x0; + private final int y0; + protected final IGuiScreen gui; + + private GT_GuiTooltip tooltip; + + public GT_GuiIconButton(IGuiScreen gui, int id, int x, int y, GT_GuiIcon icon) { + super(id, x, y, DEFAULT_WIDTH, DEFAULT_HEIGHT, ""); + this.gui = gui; + this.icon = icon; + this.x0 = x; + this.y0 = y; + gui.addElement(this); + } + + @Override + public void onInit() { + if (tooltip != null) gui.addToolTip(tooltip); + xPosition = x0 + gui.getGuiLeft(); + yPosition = y0 + gui.getGuiTop(); + } + + @Override + public void draw(int mouseX, int mouseY, float parTicks) { + drawButton(Minecraft.getMinecraft(), mouseX, mouseY); + } + + @Override + public void drawButton(Minecraft mc, int mouseX, int mouseY) { + if (this.tooltip != null) this.tooltip.enabled = true; + + if (this.visible) { + // moused over + this.field_146123_n = mouseX >= this.xPosition && mouseY >= this.yPosition + && mouseX < this.xPosition + width + && mouseY < this.yPosition + height; + + mouseDragged(mc, mouseX, mouseY); + + GL11.glPushAttrib(GL11.GL_ENABLE_BIT); + GL11.glEnable(GL11.GL_BLEND); + GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); + + int x = xPosition; + int y = yPosition; + if (!this.field_146123_n) { + // GL11.glColor4f(200F/255F, 210F/255F, 1, 1); + } else GL11.glColor4f(1, 1, 1, 1); + + GT_GuiIcon.render(getButtonTexture(this.field_146123_n), x, y, width, height, 0, true); + + GL11.glColor4f(1, 1, 1, 1); + if (icon != null) { + GT_GuiIcon.render(icon, x, y, width, height, 0, true); + } + + GL11.glPopAttrib(); + } + } + + @Override + public void mouseReleased(int mouseX, int mouseY) { + this.gui.clearSelectedButton(); + if (mousePressed(Minecraft.getMinecraft(), mouseX, mouseY)) this.gui.buttonClicked(this); + } + + public GT_GuiIcon getButtonTexture(boolean mouseOver) { + if (!enabled) return GT_GuiIcon.BUTTON_DISABLED; + if (this.equals(this.gui.getSelectedButton())) + return mouseOver ? GT_GuiIcon.BUTTON_HIGHLIGHT_DOWN : GT_GuiIcon.BUTTON_DOWN; + + return mouseOver ? GT_GuiIcon.BUTTON_HIGHLIGHT : GT_GuiIcon.BUTTON_NORMAL; + } + + public GT_GuiIcon getIcon() { + return icon; + } + + public GT_GuiIconButton setIcon(GT_GuiIcon icon) { + this.icon = icon; + return this; + } + + public GT_GuiTooltip getTooltip() { + return tooltip; + } + + public GT_GuiIconButton setTooltipText(String... text) { + if (tooltip == null) tooltip = new GT_GuiTooltip(getBounds(), text); + else tooltip.setToolTipText(text); + return this; + } + + public Rectangle getBounds() { + return new Rectangle(x0, y0, width, height); + } +} diff --git a/src/main/java/gregtech/api/gui/widgets/GT_GuiIconCheckButton.java b/src/main/java/gregtech/api/gui/widgets/GT_GuiIconCheckButton.java new file mode 100644 index 0000000000..5b5007fef3 --- /dev/null +++ b/src/main/java/gregtech/api/gui/widgets/GT_GuiIconCheckButton.java @@ -0,0 +1,43 @@ +package gregtech.api.gui.widgets; + +import gregtech.api.interfaces.IGuiScreen; + +public class GT_GuiIconCheckButton extends GT_GuiIconButton { + + private final GT_GuiIcon checkedIcon; + private final GT_GuiIcon normalIcon; + private final String checkedTooltip; + private final String normalTooltip; + private boolean checked = false; + + public GT_GuiIconCheckButton(IGuiScreen gui, int id, int x, int y, GT_GuiIcon checkedIcon, GT_GuiIcon normalIcon) { + this(gui, id, x, y, checkedIcon, normalIcon, null, null); + } + + public GT_GuiIconCheckButton(IGuiScreen gui, int id, int x, int y, GT_GuiIcon checkedIcon, GT_GuiIcon normalIcon, + String checkedTooltip, String normalTooltip) { + super(gui, id, x, y, normalIcon); + this.checkedIcon = checkedIcon; + this.normalIcon = normalIcon; + this.checkedTooltip = checkedTooltip; + this.normalTooltip = normalTooltip; + } + + @Override + public GT_GuiIcon getButtonTexture(boolean mouseOver) { + if (!enabled) return GT_GuiIcon.BUTTON_DISABLED; + if (this.equals(super.gui.getSelectedButton())) + return mouseOver ? GT_GuiIcon.BUTTON_HIGHLIGHT_DOWN : GT_GuiIcon.BUTTON_DOWN; + return mouseOver ? GT_GuiIcon.BUTTON_HIGHLIGHT : GT_GuiIcon.BUTTON_NORMAL; + } + + public boolean isChecked() { + return checked; + } + + public void setChecked(boolean checked) { + super.setIcon(checked ? checkedIcon : normalIcon); + super.setTooltipText(checked ? checkedTooltip : normalTooltip); + this.checked = checked; + } +} diff --git a/src/main/java/gregtech/api/gui/widgets/GT_GuiIntegerTextBox.java b/src/main/java/gregtech/api/gui/widgets/GT_GuiIntegerTextBox.java new file mode 100644 index 0000000000..2d3c7374bd --- /dev/null +++ b/src/main/java/gregtech/api/gui/widgets/GT_GuiIntegerTextBox.java @@ -0,0 +1,73 @@ +package gregtech.api.gui.widgets; + +import java.awt.Rectangle; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiTextField; + +import gregtech.api.interfaces.IGuiScreen; + +public class GT_GuiIntegerTextBox extends GuiTextField implements IGuiScreen.IGuiElement { + + private final int x0, y0; + private final IGuiScreen gui; + public final int id; + private boolean enabled; + + public GT_GuiIntegerTextBox(IGuiScreen gui, int id, int x, int y, int width, int height) { + super(Minecraft.getMinecraft().fontRenderer, x, y, width, height); + super.setText(""); + this.id = id; + x0 = x; + y0 = y; + this.gui = gui; + enabled = true; + gui.addElement(this); + } + + @Override + public void onInit() { + xPosition = x0 + gui.getGuiLeft(); + yPosition = y0 + gui.getGuiTop(); + } + + @Override + public void draw(int mouseX, int mouseY, float parTicks) { + super.drawTextBox(); + } + + public Rectangle getBounds() { + return new Rectangle(x0, y0, width, height); + } + + public boolean validChar(char c, int key) { + return Character.isDigit(c); + } + + @Override + public boolean textboxKeyTyped(char c, int key) { + if (validChar(c, key) || c == 1 + || c == 3 + || c == 22 + || c == 24 + || key == 14 + || key == 199 + || key == 203 + || key == 205 + || key == 207 + || key == 211) { + return super.textboxKeyTyped(c, key); + } + return false; + } + + @Override + public void setEnabled(boolean p_146184_1_) { + super.setEnabled(p_146184_1_); + enabled = p_146184_1_; + } + + public boolean isEnabled() { + return enabled; + } +} diff --git a/src/main/java/gregtech/api/gui/widgets/GT_GuiSlotTooltip.java b/src/main/java/gregtech/api/gui/widgets/GT_GuiSlotTooltip.java new file mode 100644 index 0000000000..015c8c7697 --- /dev/null +++ b/src/main/java/gregtech/api/gui/widgets/GT_GuiSlotTooltip.java @@ -0,0 +1,24 @@ +package gregtech.api.gui.widgets; + +import java.awt.Rectangle; + +import net.minecraft.inventory.Slot; + +import gregtech.api.util.GT_TooltipDataCache.TooltipData; + +public class GT_GuiSlotTooltip extends GT_GuiTooltip { + + private final Slot slot; + + public GT_GuiSlotTooltip(Slot slot, TooltipData data) { + super(new Rectangle(slot.xDisplayPosition - 1, slot.yDisplayPosition - 1, 18, 18), data); + this.slot = slot; + } + + @Override + protected void onTick() { + super.onTick(); + // If disabled by super, stay disabled. + this.enabled = this.enabled && this.slot.getStack() == null; + } +} diff --git a/src/main/java/gregtech/api/gui/widgets/GT_GuiSmartTooltip.java b/src/main/java/gregtech/api/gui/widgets/GT_GuiSmartTooltip.java new file mode 100644 index 0000000000..ffae5c30e6 --- /dev/null +++ b/src/main/java/gregtech/api/gui/widgets/GT_GuiSmartTooltip.java @@ -0,0 +1,27 @@ +package gregtech.api.gui.widgets; + +import java.awt.Rectangle; + +import gregtech.api.util.GT_TooltipDataCache.TooltipData; + +public class GT_GuiSmartTooltip extends GT_GuiTooltip { + + public interface TooltipVisibilityProvider { + + boolean shouldShowTooltip(); + } + + private final TooltipVisibilityProvider visibilityProvider; + + public GT_GuiSmartTooltip(Rectangle bounds, TooltipVisibilityProvider visibilityProvider, TooltipData data) { + super(bounds, data); + this.visibilityProvider = visibilityProvider; + } + + @Override + protected void onTick() { + super.onTick(); + // If disabled by super, stay disabled. + this.enabled = this.enabled && this.visibilityProvider.shouldShowTooltip(); + } +} diff --git a/src/main/java/gregtech/api/gui/widgets/GT_GuiTab.java b/src/main/java/gregtech/api/gui/widgets/GT_GuiTab.java new file mode 100644 index 0000000000..d06c2bd2eb --- /dev/null +++ b/src/main/java/gregtech/api/gui/widgets/GT_GuiTab.java @@ -0,0 +1,174 @@ +package gregtech.api.gui.widgets; + +import java.awt.Rectangle; + +import net.minecraft.client.Minecraft; +import net.minecraft.item.ItemBlock; +import net.minecraft.item.ItemStack; + +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL12; + +import gregtech.api.gui.widgets.GT_GuiTabLine.GT_GuiTabIconSet; +import gregtech.api.gui.widgets.GT_GuiTabLine.GT_ITabRenderer; +import gregtech.api.interfaces.IGuiIcon; + +/** + * A tab to be attached to a tab line + */ +public class GT_GuiTab { + + private static final int SLOT_SIZE = 18; + + public boolean visible = true, mousedOver, enabled = true; + + private Rectangle bounds; + private final GT_GuiTabIconSet tabBackground; + private final ItemStack item; + private final GT_ITabRenderer gui; + private GT_GuiTooltip tooltip; + private final IGuiIcon overlay; + private final boolean flipHorizontally; + + /** + * A tab to be attached to a tab line + * + * @param gui IGregTechTileEntity the tab line this tab belongs to is attached to + * @param id both the ID and position in the tab line of this tab. Not used, kept for compatibility. + * @param bounds bounds of this tab + * @param tabBackground set of background textures + * @param item item to draw atop the background texture, not colored + * @param overlay texture to draw atop the background texture, not colored + * @param tooltipText tooltip of this tab + * @param flipHorizontally whether to draw this tab on the right side of the IGregTechTileEntity + */ + public GT_GuiTab(GT_ITabRenderer gui, int id, Rectangle bounds, GT_GuiTabIconSet tabBackground, ItemStack item, + IGuiIcon overlay, String[] tooltipText, boolean flipHorizontally) { + this.gui = gui; + this.bounds = bounds; + this.item = item; + this.tabBackground = tabBackground; + this.overlay = overlay; + if (tooltipText != null) { + setTooltipText(tooltipText); + } + this.flipHorizontally = flipHorizontally; + } + + public GT_GuiTab(GT_ITabRenderer gui, int id, Rectangle bounds, GT_GuiTabIconSet tabBackground) { + this(gui, id, bounds, tabBackground, null, null, null, false); + } + + /** + * Set this tab's tooltip text + * + * @param text text to set + * @return This tab for chaining + */ + public GT_GuiTab setTooltipText(String... text) { + if (tooltip == null) { + tooltip = new GT_GuiTooltip(bounds, text); + gui.addToolTip(tooltip); + } else { + tooltip.setToolTipText(text); + } + return this; + } + + /** + * @return This tab's tooltip object + */ + public GT_GuiTooltip getTooltip() { + return tooltip; + } + + /** + * Draw the background texture for this tab + * + * @param mouseX not used, likely kept for backward compatibility + * @param mouseY not used, likely kept for backward compatibility + * @param parTicks not used, likely kept for backward compatibility + */ + public void drawBackground(int mouseX, int mouseY, float parTicks) { + if (this.visible) { + GT_GuiIcon.render( + getBackgroundTexture(), + bounds.x, + bounds.y, + bounds.width, + bounds.height, + 1, + true, + this.flipHorizontally); + } + } + + /** + * Draw overlay textures and items atop the background texture + * + * @param mouseX X mouse coordinate + * @param mouseY Y mouse coordinate + * @param parTicks not used, likely kept for backward compatibility + */ + public void drawOverlays(int mouseX, int mouseY, float parTicks) { + this.mousedOver = bounds.contains(mouseX, mouseY); + + if (this.tooltip != null) { + this.tooltip.enabled = this.visible; + } + + if (this.visible) { + if (overlay != null) { + GL11.glColor4f(1, 1, 1, 1); + GT_GuiIcon.render(overlay, bounds.x, bounds.y, bounds.width, bounds.height, 1, true); + } + if (item != null) { + GL11.glPushAttrib(GL11.GL_ENABLE_BIT); + + if (item.getItem() instanceof ItemBlock) { + GL11.glPushAttrib(GL11.GL_ENABLE_BIT); + GL11.glEnable(GL12.GL_RESCALE_NORMAL); + } + int margin = (bounds.height - SLOT_SIZE); + gui.getItemRenderer() + .renderItemAndEffectIntoGUI( + gui.getFontRenderer(), + Minecraft.getMinecraft() + .getTextureManager(), + item, + bounds.x + (this.flipHorizontally ? 0 : margin), + bounds.y + margin); + + if (item.getItem() instanceof ItemBlock) GL11.glPopAttrib(); + + GL11.glPopAttrib(); + } + } + } + + /** + * @return the texture this tab should currently use as it's background + */ + protected IGuiIcon getBackgroundTexture() { + if (!enabled) return tabBackground.disabled; + + return mousedOver ? tabBackground.highlight : tabBackground.normal; + } + + /** + * @return the screen space occupied by this tab + */ + public Rectangle getBounds() { + return this.bounds; + } + + /** + * Reposition this tab on the screen + * + * @param xPos X tab coordinate + * @param yPos Y tab coordinate + */ + public void setPosition(int xPos, int yPos) { + this.bounds = new Rectangle(xPos, yPos, bounds.width, bounds.height); + } +} diff --git a/src/main/java/gregtech/api/gui/widgets/GT_GuiTabLine.java b/src/main/java/gregtech/api/gui/widgets/GT_GuiTabLine.java new file mode 100644 index 0000000000..950478cdfa --- /dev/null +++ b/src/main/java/gregtech/api/gui/widgets/GT_GuiTabLine.java @@ -0,0 +1,274 @@ +package gregtech.api.gui.widgets; + +import java.awt.Rectangle; + +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.renderer.entity.RenderItem; +import net.minecraft.item.ItemStack; + +import org.lwjgl.opengl.GL11; + +import gregtech.api.interfaces.IGuiIcon; + +/** + * Draws clickable and configurable tabs on the left or right side of another GUI + */ +public class GT_GuiTabLine { + + /** + * Defines a set of textures a tab line can use to render it's tab backgrounds + */ + public static class GT_GuiTabIconSet { + + public IGuiIcon disabled; + public IGuiIcon normal; + public IGuiIcon highlight; + + public GT_GuiTabIconSet(IGuiIcon normalIcon, IGuiIcon highlightIcon, IGuiIcon disabledIcon) { + this.normal = normalIcon; + this.highlight = highlightIcon; + this.disabled = disabledIcon; + } + } + + /** + * Controls the rendering style of the tab line + */ + public enum DisplayStyle { + + NONE((byte) 0), + NORMAL((byte) 1), + INVERSE((byte) -1); + + private final byte value; + + DisplayStyle(byte value) { + this.value = value; + } + + public byte getValue() { + return value; + } + } + + /** + * A GUI should implement these methods as well as call the tab line's onMouseClicked, onInit and drawTabs for the + * tab line to attach to it properly. + */ + public interface GT_ITabRenderer { + + int getGuiLeft(); + + int getGuiTop(); + + int getXSize(); + + RenderItem getItemRenderer(); + + FontRenderer getFontRenderer(); + + void addToolTip(GT_GuiTooltip tooltip); + + boolean removeToolTip(GT_GuiTooltip tooltip); + } + + // The tabs are arranged according to their index in this array + protected final GT_GuiTab[] mTabs; + + private final int tabLineLeft; + private final int tabLineTop; + private final int tabHeight; + private final int tabWidth; + private final int tabSpacing; + + // In which direction to draw the tab line + private final DisplayStyle xDir; + private final DisplayStyle yDir; + + // Whether to display on the right side of the GT_ITabRenderer instead of left + protected final boolean flipHorizontally; + protected final boolean visible; + + private final GT_GuiTabIconSet tabBackground; + private final GT_ITabRenderer gui; + + /** + * Draws clickable and configurable tabs on the left or right side of a GT_ITabRenderer + * + * @param gui GT_ITabRenderer gui which this tab line attaches to + * @param numTabs number of tab positions in this tab line + * @param tabLineLeft left position of the tab line in relation to the gui + * @param tabLineTop top position of the tab line in relation to the gui + * @param tabHeight height of a tab + * @param tabWidth width of a tab + * @param tabSpacing pixels between each tab + * @param xDir whether to extend the line horizontally to the right (NORMAL), the left (INVERSE) or not at + * all (NONE) + * @param yDir whether to extend the line vertically down (NORMAL), up (INVERSE) or not at all (NONE) + * @param displayMode whether to display on the left side of the GT_ITabRenderer (NORMAL), on it's right side + * (INVERSE) or not at all (NONE) + * @param tabBackground the set of textures used to draw this tab line's tab backgrounds + */ + public GT_GuiTabLine(GT_ITabRenderer gui, int numTabs, int tabLineLeft, int tabLineTop, int tabHeight, int tabWidth, + int tabSpacing, DisplayStyle xDir, DisplayStyle yDir, DisplayStyle displayMode, + GT_GuiTabIconSet tabBackground) { + this.gui = gui; + this.mTabs = new GT_GuiTab[numTabs]; + this.tabLineLeft = tabLineLeft; + this.tabLineTop = tabLineTop; + this.tabHeight = tabHeight; + this.tabWidth = tabWidth; + this.tabSpacing = tabSpacing; + this.xDir = xDir; + this.yDir = yDir; + this.tabBackground = tabBackground; + this.flipHorizontally = displayMode == DisplayStyle.INVERSE; + this.visible = !(displayMode == DisplayStyle.NONE); + } + + /** + * Creates a new tab at the specified position with the given parameters. This class handles the positioning. + * + * @param tabId tab ID + * @param item item to draw atop the background texture, not colored + * @param overlay texture to draw atop the background texture, not colored + * @param text tooltip of this tab + */ + public void setTab(int tabId, ItemStack item, IGuiIcon overlay, String[] text) { + mTabs[tabId] = new GT_GuiTab( + this.gui, + tabId, + getBoundsForTab(tabId), + this.tabBackground, + item, + overlay, + text, + this.flipHorizontally); + } + + /** + * Get the bounds a given tab should occupy + * + * @param tabId tab ID + * @return tab bounds + */ + protected Rectangle getBoundsForTab(int tabId) { + return new Rectangle(getTabX(tabId), getTabY(tabId), this.tabWidth, this.tabHeight); + } + + /** + * Enable or disable a tab. Disabled tabs have a dark background. + * + * @param tabId tab ID + * @param enable true to enable, false to disable + */ + public void setTabEnabled(int tabId, boolean enable) { + if (mTabs[tabId] != null) { + mTabs[tabId].enabled = enable; + } + } + + /** + * Draw the tabs for this tab bar GT_ITabRenderer must call this method on drawGuiContainerBackgroundLayer or on + * drawScreen. + * + * @param parTicks + */ + public void drawTabs(float parTicks, int mouseX, int mouseY) { + if (this.visible) { + GL11.glPushAttrib(GL11.GL_ENABLE_BIT); + GL11.glEnable(GL11.GL_BLEND); + GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); + drawBackground(parTicks, mouseX, mouseY); + drawOverlays(parTicks, mouseX, mouseY); + GL11.glPopAttrib(); + } + } + + /** + * Draw the tab's backgrounds first + * + * @param parTicks not used, likely kept for compatibility + * @param mouseX mouse X position + * @param mouseY mouse Y position + */ + protected void drawOverlays(float parTicks, int mouseX, int mouseY) { + for (GT_GuiTab mTab : mTabs) { + if (mTab != null) { + mTab.drawOverlays(mouseX, mouseY, parTicks); + } + } + } + + /** + * Draw anything that overlays the tab's background texture + * + * @param parTicks not used, likely kept for compatibility + * @param mouseX mouse X position + * @param mouseY mouse Y position + */ + protected void drawBackground(float parTicks, int mouseX, int mouseY) { + for (GT_GuiTab mTab : mTabs) { + if (mTab != null) { + mTab.drawBackground(mouseX, mouseY, parTicks); + } + } + } + + /** + * Call tabClick for every tab that was clicked. GT_ITabRenderer must call this method on mouseClicked. + * + * @param mouseX mouse X position + * @param mouseY mouse Y position + * @param mouseButton which mouse button was used to click + */ + public void onMouseClicked(int mouseX, int mouseY, int mouseButton) { + for (int tabId = 0; tabId < mTabs.length; tabId++) { + if (mTabs[tabId] != null && mTabs[tabId].getBounds() + .contains(mouseX, mouseY)) { + tabClicked(tabId, mouseButton); + return; + } + } + } + + /** + * Act on a tab being clicked. + * + * @param tabId tab ID + * @param mouseButton which mouse button was used to click + */ + protected void tabClicked(int tabId, int mouseButton) {} + + /** + * Reposition ourselves whenever the GT_ITabRenderer does so. GT_ITabRenderer must call this method on Init. + */ + public void onInit() { + for (int i = 0; i < mTabs.length; i++) { + if (mTabs[i] != null) { + mTabs[i].setPosition(getTabX(i), getTabY(i)); + } + } + } + + /** + * Get the proper X position for a given tab + * + * @param tabId tab ID + * @return X position of the tab + */ + private int getTabX(int tabId) { + return this.gui.getGuiLeft() + (flipHorizontally ? (gui.getXSize() - tabLineLeft - tabWidth) : tabLineLeft) + + (tabId * (tabWidth + tabSpacing) * xDir.getValue()); + } + + /** + * Get the proper Y position for a given tab + * + * @param tabId tab ID + * @return Y position of the tab + */ + private int getTabY(int tabId) { + return this.gui.getGuiTop() + tabLineTop + (tabId * (tabHeight + tabSpacing) * yDir.getValue()); + } +} diff --git a/src/main/java/gregtech/api/gui/widgets/GT_GuiTooltip.java b/src/main/java/gregtech/api/gui/widgets/GT_GuiTooltip.java new file mode 100644 index 0000000000..fe20b2b57a --- /dev/null +++ b/src/main/java/gregtech/api/gui/widgets/GT_GuiTooltip.java @@ -0,0 +1,121 @@ +package gregtech.api.gui.widgets; + +import java.awt.Rectangle; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.lwjgl.input.Keyboard; + +import gregtech.api.util.GT_TooltipDataCache.TooltipData; + +public class GT_GuiTooltip { + + protected final Rectangle bounds; + protected TooltipData data; + private List<String> displayedText; + public boolean enabled = true; + + /** + * Used to create a tooltip that will appear over the specified bounds. This will initially be a "static" tooltip + * that doesn't respect verbosity levels or respond to the shift key. + * + * @param bounds tooltip bounds + * @param text tooltip text + */ + public GT_GuiTooltip(Rectangle bounds, String... text) { + this.bounds = bounds; + setToolTipText(text); + } + + /** + * Used to create a tooltip that will appear over the specified bounds. This will initially be a "dynamic" tooltip + * that respects verbosity levels and responds to the shift key. + * + * @param bounds tooltip bounds + * @param data tooltip data + */ + public GT_GuiTooltip(Rectangle bounds, TooltipData data) { + this.bounds = bounds; + // Trust that the tooltips have already been formatted and colored, just make sure it has no nulls + this.data = sanitizeTooltipData(data); + } + + private TooltipData sanitizeTooltipData(TooltipData data) { + if (data.text == null) { + data.text = Collections.emptyList(); + } + if (data.shiftText == null) { + data.shiftText = Collections.emptyList(); + } + return data; + } + + /** + * Called before the tooltip manager checks whether this tooltip is enabled + */ + protected void onTick() { + // Switch which of our 2 stored texts we're displaying now. + this.displayedText = Keyboard.isKeyDown(Keyboard.KEY_LSHIFT) ? this.data.shiftText : this.data.text; + // If this text is empty, let's not display a tooltip at all. + this.enabled = this.displayedText.size() != 0; + } + + /** + * Called once this tooltip has been determined to be enabled + */ + protected void updateText() {} + + /** + * Used to set a "static" tooltip that doesn't respect verbosity levels or respond to the shift key + * + * @param text tooltip text + */ + public void setToolTipText(String... text) { + this.data = formatTooltip(text); + this.displayedText = data.text; + } + + /** + * Used to set a "dynamic" tooltip that respects verbosity levels and responds to the shift key + * + * @param data tooltip data + */ + public void setToolTipText(TooltipData data) { + // Trust that the tooltips have already been formatted and colored, just make sure it has no nulls + this.data = sanitizeTooltipData(data); + } + + /** + * Apply tooltip colors in case the text doesn't contain them and return as tooltip data + * + * @param text text to apply the colors to + * @return colored tooltip lines as list + */ + protected TooltipData formatTooltip(String[] text) { + List<String> list; + if (text != null) { + list = new ArrayList<>(text.length); + for (String s : text) { + if (s == null) continue; + if (list.isEmpty()) list.add("\u00a7f" + s); + else list.add("\u00a77" + s); + } + } else { + list = Collections.emptyList(); + } + return new TooltipData(list, list); + } + + public List<String> getToolTipText() { + return this.displayedText; + } + + public Rectangle getBounds() { + return bounds; + } + + public boolean isDelayed() { + return true; + } +} diff --git a/src/main/java/gregtech/api/gui/widgets/GT_GuiTooltipManager.java b/src/main/java/gregtech/api/gui/widgets/GT_GuiTooltipManager.java new file mode 100644 index 0000000000..4304ca14fc --- /dev/null +++ b/src/main/java/gregtech/api/gui/widgets/GT_GuiTooltipManager.java @@ -0,0 +1,80 @@ +package gregtech.api.gui.widgets; + +import java.util.ArrayList; +import java.util.List; + +import net.minecraft.client.gui.FontRenderer; + +public class GT_GuiTooltipManager { + + public interface GT_IToolTipRenderer { + + int getGuiLeft(); + + int getGuiTop(); + + int getXSize(); + + FontRenderer getFontRenderer(); + + void drawHoveringText(List<String> text, int mouseX, int mouseY, FontRenderer font); + } + + private static final long DELAY = 5; + private int mouseStopped; + private int lastMouseX = -1; + private int lastMouseY = -1; + private final List<GT_GuiTooltip> tips = new ArrayList<>(); + + public void addToolTip(GT_GuiTooltip tip) { + if (tip != null && !tips.contains(tip)) tips.add(tip); + } + + public boolean removeToolTip(GT_GuiTooltip tip) { + return tips.remove(tip); + } + + public final void onTick(GT_IToolTipRenderer render, int mouseX, int mouseY) { + if ((Math.abs(mouseX - lastMouseX) < 2) && (Math.abs(mouseY - lastMouseY) < 2)) { + mouseStopped = Math.min(mouseStopped + 1, 50); + } else { + mouseStopped = 0; + } + + lastMouseX = mouseX; + lastMouseY = mouseY; + + mouseX -= render.getGuiLeft(); + mouseY -= render.getGuiTop(); + for (GT_GuiTooltip tip : tips) { + // Give the tooltip the opportunity to decide whether they should be enabled + tip.onTick(); + if (tip.enabled && (!tip.isDelayed() || mouseStopped > DELAY) + && tip.getBounds() + .contains(mouseX, mouseY)) { + tip.updateText(); + drawTooltip(tip, mouseX, mouseY, render); + break; + } + } + } + + private void drawTooltip(GT_GuiTooltip tip, int mouseX, int mouseY, GT_IToolTipRenderer render) { + List<String> text = tip.getToolTipText(); + if (text == null) return; + + if (mouseX > render.getGuiLeft() + render.getXSize() / 2) { + int maxWidth = 0; + for (String s : text) { + int w = render.getFontRenderer() + .getStringWidth(s); + if (w > maxWidth) { + maxWidth = w; + } + } + mouseX -= (maxWidth + 18); + } + + render.drawHoveringText(text, mouseX, mouseY, render.getFontRenderer()); + } +} diff --git a/src/main/java/gregtech/api/gui/widgets/GT_LockedWhileActiveButton.java b/src/main/java/gregtech/api/gui/widgets/GT_LockedWhileActiveButton.java new file mode 100644 index 0000000000..9a93a8fadf --- /dev/null +++ b/src/main/java/gregtech/api/gui/widgets/GT_LockedWhileActiveButton.java @@ -0,0 +1,90 @@ +package gregtech.api.gui.widgets; + +import java.util.Arrays; +import java.util.List; +import java.util.function.BiConsumer; +import java.util.function.Supplier; + +import net.minecraft.util.StatCollector; + +import org.jetbrains.annotations.NotNull; + +import com.google.common.collect.ImmutableList; +import com.gtnewhorizons.modularui.api.drawable.IDrawable; +import com.gtnewhorizons.modularui.api.screen.ModularWindow; +import com.gtnewhorizons.modularui.api.widget.Widget; +import com.gtnewhorizons.modularui.common.widget.ButtonWidget; +import com.gtnewhorizons.modularui.common.widget.FakeSyncWidget; + +import gregtech.api.gui.modularui.GT_UITextures; +import gregtech.api.interfaces.tileentity.IMachineProgress; + +public class GT_LockedWhileActiveButton extends ButtonWidget { + + @NotNull + private final IMachineProgress machine; + + public GT_LockedWhileActiveButton(@NotNull IMachineProgress machine, @NotNull ModularWindow.Builder builder) { + super(); + this.machine = machine; + + super.attachSyncer( + new FakeSyncWidget.BooleanSyncer(machine::isActive, a -> {}), + builder, + (widget, aBoolean) -> widget.notifyTooltipChange()); + + super.dynamicTooltip(this::generateTooltip); + } + + @NotNull + @Override + public ButtonWidget setOnClick(@NotNull BiConsumer<ClickData, Widget> clickAction) { + return super.setOnClick((clickData, widget) -> { + if (!machine.isActive()) { + clickAction.accept(clickData, widget); + } + }); + } + + @NotNull + @Override + public Widget setBackground(@NotNull IDrawable... drawables) { + return super.setBackground(() -> appendLockedOverlay(drawables)); + } + + @NotNull + @Override + public Widget setBackground(@NotNull Supplier<IDrawable[]> drawablesSupplier) { + return super.setBackground(() -> appendLockedOverlay(drawablesSupplier.get())); + } + + @NotNull + @Override + public Widget dynamicTooltip(@NotNull Supplier<List<String>> dynamicTooltip) { + return super.dynamicTooltip(() -> { + ImmutableList.Builder<String> tooltips = ImmutableList.<String>builder() + .addAll(dynamicTooltip.get()); + tooltips.addAll(generateTooltip()); + + return tooltips.build(); + }); + } + + @NotNull + private IDrawable[] appendLockedOverlay(@NotNull IDrawable[] drawables) { + if (machine.isActive()) { + final IDrawable[] copy = Arrays.copyOf(drawables, drawables.length + 1); + copy[drawables.length] = GT_UITextures.OVERLAY_BUTTON_LOCKED; + return copy; + } + return drawables; + } + + @NotNull + private List<String> generateTooltip() { + if (machine.isActive()) { + return ImmutableList.of(StatCollector.translateToLocal("GT5U.gui.button.forbidden_while_running")); + } + return ImmutableList.of(); + } +} |