diff options
| author | matthias-luger <58751503+matthias-luger@users.noreply.github.com> | 2023-02-17 17:32:26 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-02-17 17:32:26 +0100 |
| commit | 8f3bce7d6fe41e85f2654f7557bbb564305e58b5 (patch) | |
| tree | 4bae9237e3c0b87bf27e5f590f4c0ca91b145cab /src/main/java/de/torui/coflsky/gui/bingui | |
| parent | e43d5685fdf0d436d5836d06c5d3f15da674e7df (diff) | |
| download | COFL-8f3bce7d6fe41e85f2654f7557bbb564305e58b5.tar.gz COFL-8f3bce7d6fe41e85f2654f7557bbb564305e58b5.tar.bz2 COFL-8f3bce7d6fe41e85f2654f7557bbb564305e58b5.zip | |
Add TFM Purchase UI to Mod (#78)
* Add TFM Purchase UI to Mod
* fix up opening flips by hotkey
fix up flip message in tfm ui
* readded check if the auction should be drawn
mod doesnt crash anymore if a non flip auction is opened
* added /cofl set gui command
changed gui title
* added /fc toggle command
dont store toggle locally
* rename purchaseOverlay config
removed unused code
renamed gui command to /cofl set ahbuygui
* fix message not available if flip opened by mouse
fix old message shown for non flip auctions
* added /cofl setGui command
added cofl purchase gui
* Add sound on flip
* Fixed new flip sound
Optimized cofl gui
Removed flickering of default mc gui
Move mouse to middle on screen open
* remove unused code
* remove debug code
* don't open guis if not in skyblock
* fix sound being null
* fix bed flips
fix opening /cofl blocked
* remove logging
* Rewrote cofl gui to render before the chest gui opens
* - fix bed flips
- invalidate best flips after open
* - fix scrolling
* - fix description not updating
- case insensitive commands
- fix up , at the end of the message
* - add gui if item was already bought
- fix bug that invalidated too many flips
- added missing "break"
* fix merge error
* add .vscode to gitignore
formatting
* fix formatting issue
* - remove comment
- remove emty line
Diffstat (limited to 'src/main/java/de/torui/coflsky/gui/bingui')
6 files changed, 1183 insertions, 0 deletions
diff --git a/src/main/java/de/torui/coflsky/gui/bingui/BinGuiCurrent.java b/src/main/java/de/torui/coflsky/gui/bingui/BinGuiCurrent.java new file mode 100644 index 0000000..ef5ec9c --- /dev/null +++ b/src/main/java/de/torui/coflsky/gui/bingui/BinGuiCurrent.java @@ -0,0 +1,415 @@ +package de.torui.coflsky.gui.bingui; + + +import de.torui.coflsky.CoflSky; +import de.torui.coflsky.gui.GUIType; +import de.torui.coflsky.gui.bingui.helper.ColorPallet; +import de.torui.coflsky.gui.bingui.helper.RenderUtils; +import de.torui.coflsky.handlers.EventHandler; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiScreen; +import net.minecraft.client.gui.inventory.GuiChest; +import net.minecraft.command.NumberInvalidException; +import net.minecraft.init.Items; +import net.minecraft.inventory.ContainerChest; +import net.minecraft.inventory.IInventory; +import net.minecraft.item.Item; +import net.minecraft.item.ItemArmor; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; +import net.minecraft.util.ChatComponentText; +import net.minecraft.util.EnumChatFormatting; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.client.event.ClientChatReceivedEvent; +import net.minecraftforge.client.event.GuiOpenEvent; +import net.minecraftforge.client.event.GuiScreenEvent; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.fml.common.eventhandler.EventPriority; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.common.gameevent.TickEvent; +import org.lwjgl.input.Mouse; + +import java.awt.event.MouseWheelEvent; +import java.util.Base64; +import java.util.List; +import java.util.Locale; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class BinGuiCurrent extends GuiChest { + private String message; + private String[] lore; + private ItemStack itemStack; + private String buyText = "Buy(You can click anywhere)"; + private BuyState buyState = BuyState.INIT; + private int pixelsScrolled = 0; + private boolean wasMouseDown; + private boolean isRendered = false; + private boolean hasInitialMouseSet = false; + + // set if the auction was already bought + private String buyer = null; + + private static final Pattern CAN_BUY_IN_MATCHER = Pattern.compile("Can buy in: (.*)"); + private static final Pattern BUYER_MATCHER = Pattern.compile("Buyer: (.*)"); + + private GuiChest chestGui; + + public BinGuiCurrent(IInventory playerInventory, IInventory chestInventory, String message, String extraData) { + super(chestInventory, playerInventory); + this.message = message; + this.lore = new String[]{"Loading..."}; + if (extraData.length() >= 32) { + itemStack = getSkull("Name", "00000000-0000-0000-0000-000000000000", extraData); + } else { + itemStack = new ItemStack(getItemByText(extraData)); + //if it is an armor item, we color it black + if (itemStack.getItem() == null) return; + if (itemStack.getItem() instanceof ItemArmor && (itemStack.getItem() == Items.leather_helmet || itemStack.getItem() == Items.leather_chestplate || itemStack.getItem() == Items.leather_leggings || itemStack.getItem() == Items.leather_boots)) { + ((ItemArmor) itemStack.getItem()).setColor(itemStack, 0); + } + } + MinecraftForge.EVENT_BUS.register(this); + } + + private boolean shouldSkip(GuiScreen screen) { + return !(screen instanceof GuiChest) || CoflSky.config.purchaseOverlay != GUIType.COFL || !EventHandler.isInSkyblock; + } + + @SubscribeEvent(priority = EventPriority.HIGHEST) + public void onGuiOpen(GuiOpenEvent event) { + + if (event.gui == null) { + resetGUI(); + } + + isRendered = false; + GuiScreen gui = event.gui; + + if (message == null || message.isEmpty()) { + return; + } + + if (shouldSkip(gui)) { + return; + } + + GuiChest chest = (GuiChest) gui; + + IInventory inventory = ((ContainerChest) chest.inventorySlots).getLowerChestInventory(); + if (inventory == null) return; + + String guiName = inventory.getDisplayName().getUnformattedText().trim(); + if (guiName.equalsIgnoreCase("BIN Auction View") || guiName.equalsIgnoreCase("Confirm Purchase")) { + this.chestGui = (GuiChest) event.gui; + this.inventorySlots = ((GuiChest) event.gui).inventorySlots; + event.gui = this; + } + } + + @SubscribeEvent(priority = EventPriority.HIGHEST) + public void onDrawGuiScreen(GuiScreenEvent.DrawScreenEvent.Pre event) { + isRendered = false; + GuiScreen gui = event.gui; + + if (message == null || message.isEmpty()) { + return; + } + + if (shouldSkip(gui)) { + return; + } + + GuiChest chest = (GuiChest) gui; + + IInventory inventory = ((ContainerChest) chest.inventorySlots).getLowerChestInventory(); + if (inventory == null) return; + + String guiName = inventory.getDisplayName().getUnformattedText().trim(); + if (guiName.equalsIgnoreCase("auction view")) { + return; + } + + ItemStack item = inventory.getStackInSlot(13); + if (item == null) return; + + String[] tooltip = item.getTooltip(mc.thePlayer, false).toArray(new String[0]); + + itemStack = item; + + if (guiName.equalsIgnoreCase("BIN Auction View")) { + lore = tooltip; + buyer = isAlreadyBought(tooltip); + } + if (guiName.equalsIgnoreCase("BIN Auction View") && buyState == BuyState.PURCHASE) { + if (waitingForBed(chest)) { + Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText("[§1C§6oflnet§f]§7: §cBed is not purchasable yet.")); + buyState = BuyState.INIT; + } else { + mc.playerController.windowClick(this.chestGui.inventorySlots.windowId, 31, 2, 3, mc.thePlayer); + wasMouseDown = false; + buyState = BuyState.CONFIRM; + } + } else if (guiName.equalsIgnoreCase("Confirm Purchase") && buyState == BuyState.BUYING) { + mc.playerController.windowClick(this.chestGui.inventorySlots.windowId, 11, 2, 3, mc.thePlayer); + resetGUI(); + } + } + + @Override + public void drawScreen(int mouseX, int mouseY, float partialTicks) { + Mouse.setGrabbed(false); + isRendered = true; + + int screenWidth = this.width; + int screenHeight = this.height; + + int width = mc.fontRendererObj.getStringWidth(message) > 500 ? mc.fontRendererObj.getStringWidth(message) + 5 : 500; + int height = 300; + + //RenderUtils.drawRoundedRect(screenWidth / 2, 10 + 5 + 14 + 5 + (height - 100) + 5, (width - 10) / 2 + 20, 60, 5, ColorPallet.SUCCESS.getColor()); + if (!hasInitialMouseSet) { + Mouse.setCursorPosition(mc.displayWidth / 2, mc.displayHeight / 2); + hasInitialMouseSet = true; + } + + //if (lore.length > 25) { + // height = 300 + (lore.length - 25) * 10; + //} + + //first i draw the main background + RenderUtils.drawRoundedRect(screenWidth / 2 - width / 2, 10, width, height, 10, ColorPallet.PRIMARY.getColor()); + + //next i draw the title + RenderUtils.drawRoundedRect(screenWidth / 2 - width / 2 + 5, 10 + 5, (width - 10), 14, 5, ColorPallet.SECONDARY.getColor()); + RenderUtils.drawString(message, screenWidth / 2 - width / 2 + 7, 10 + 8, ColorPallet.WHITE.getColor()); + + //now i draw the backround of the icon + RenderUtils.drawRoundedRect(screenWidth / 2 - width / 2 + 5, 10 + 5 + 14 + 5, 20, 20, 5, ColorPallet.TERTIARY.getColor()); + + //now i draw the icon + if (itemStack == null) { + //draw a question mark in the icon + RenderUtils.drawString("?", screenWidth / 2 - width / 2 + 5 + 5, 10 + 5 + 14 + 5 + 2, ColorPallet.WHITE.getColor(), 40); + } else { + RenderUtils.drawItemStack(itemStack, screenWidth / 2 - width / 2 + 5 + 2, 10 + 5 + 14 + 5 + 2); + } + + + //draw the backorund for the lore + RenderUtils.drawRoundedRect(screenWidth / 2 - width / 2 + 5 + 20 + 5, 10 + 5 + 14 + 5, (width - 10) - 25, (height - 100), 5, ColorPallet.SECONDARY.getColor()); + + //draw the lore, every line that is out of the lore background will not be drawn + int y = 10 + 5 + 14 + 5 + 2; + for (int i = 0; i < lore.length; i++) { + if (y + pixelsScrolled > 10 + 5 + 14 + 5 && y + pixelsScrolled < 10 + 5 + 14 + 5 + (height - 100)) { + RenderUtils.drawString(lore[i], screenWidth / 2 - width / 2 + 5 + 20 + 5 + 2, y + pixelsScrolled, ColorPallet.WHITE.getColor()); + } + y += 10; + } + + + //now i draw the buttons buy and sell under the lore + //cancel button + RenderUtils.drawRoundedRect(screenWidth / 2 - width / 2 + 5, 10 + 5 + 14 + 5 + (height - 100) + 5, (width - 10) / 2 - 25, 60, 5, ColorPallet.ERROR.getColor()); + RenderUtils.drawString("Cancel", screenWidth / 2 - width / 2 + 5 + 5, 10 + 5 + 14 + 5 + (height - 100) + 5 + 5, ColorPallet.WHITE.getColor(), 40); + if (isMouseOverCancel(mouseX, mouseY, screenWidth, screenHeight, width, height)) { + RenderUtils.drawRoundedRect(screenWidth / 2 - width / 2 + 5, 10 + 5 + 14 + 5 + (height - 100) + 5, (width - 10) / 2 - 25, 60, 5, RenderUtils.setAlpha(ColorPallet.WHITE.getColor(), 100)); + RenderUtils.drawString("Cancel", screenWidth / 2 - width / 2 + 5 + 5, 10 + 5 + 14 + 5 + (height - 100) + 5 + 5, ColorPallet.WHITE.getColor(), 40); + if (isClicked()) { + //play a anvilsound + mc.thePlayer.playSound("random.anvil_land", 1, 1); + resetGUI(); + mc.thePlayer.closeScreen(); + } + } + + + //buy button + if (buyer == null) { + RenderUtils.drawRoundedRect(screenWidth / 2 - width / 2 + 5 + (width - 10) / 2 - 20, 10 + 5 + 14 + 5 + (height - 100) + 5, (width - 10) / 2 + 20, 60, 5, ColorPallet.SUCCESS.getColor()); + RenderUtils.drawString(buyText, screenWidth / 2 - width / 2 + 5 + (width - 10) / 2 + 5 - 20, 10 + 5 + 14 + 5 + (height - 100) + 5 + 5, ColorPallet.WHITE.getColor(), 40); + } else { + RenderUtils.drawRoundedRect(screenWidth / 2 - width / 2 + 5 + (width - 10) / 2 - 20, 10 + 5 + 14 + 5 + (height - 100) + 5, (width - 10) / 2 + 20, 60, 5, ColorPallet.WARNING.getColor()); + RenderUtils.drawString(getAlreadyBoughtText(buyer), screenWidth / 2 - width / 2 + 5 + (width - 10) / 2 + 5 - 20, 10 + 5 + 14 + 5 + (height - 100) + 5 + 5, ColorPallet.WHITE.getColor(), 40); + } + if (!isMouseOverCancel(mouseX, mouseY, screenWidth, screenHeight, width, height)) { + if (buyer == null) { + RenderUtils.drawRoundedRect(screenWidth / 2 - width / 2 + 5 + (width - 10) / 2 - 20, 10 + 5 + 14 + 5 + (height - 100) + 5, (width - 10) / 2 + 20, 60, 5, RenderUtils.setAlpha(ColorPallet.WHITE.getColor(), 50)); + RenderUtils.drawString(buyText, screenWidth / 2 - width / 2 + 5 + (width - 10) / 2 + 5 - 20, 10 + 5 + 14 + 5 + (height - 100) + 5 + 5, ColorPallet.WHITE.getColor(), 40); + } + if (isClicked() && buyer == null) { + if (buyState == BuyState.INIT) { + //play a sound + mc.thePlayer.playSound("random.click", 1, 1); + buyText = "Click again to confirm"; + buyState = BuyState.PURCHASE; + } else if (buyState == BuyState.CONFIRM) { + mc.thePlayer.playSound("random.click", 1, 1); + buyText = "Buying"; + buyState = BuyState.BUYING; + } + } + } + + } + + public String getAlreadyBoughtText(String buyer) { + return "§5§o§7Bought by §b" + buyer; + } + + @SubscribeEvent + public void onGuiMouseInput(GuiScreenEvent.MouseInputEvent event) { + if (event.gui instanceof BinGuiCurrent) { + int dwheel = Mouse.getDWheel(); + pixelsScrolled += dwheel / 4; + } + } + + public void resetGUI() { + buyState = BuyState.INIT; + buyText = "Buy (You can click anywhere)"; + itemStack = null; + hasInitialMouseSet = false; + isRendered = false; + Mouse.setGrabbed(true); + MinecraftForge.EVENT_BUS.unregister(this); + } + + public static Item getItemByText(String id) { + try { + ResourceLocation resourcelocation = new ResourceLocation(id); + if (!Item.itemRegistry.containsKey(resourcelocation)) { + throw new NumberInvalidException("block.notFound", resourcelocation); + } + Item item = Item.itemRegistry.getObject(resourcelocation); + if (item == null) { + throw new NumberInvalidException("block.notFound", resourcelocation); + } + return item; + } catch (Exception e) { + System.out.println("Error: " + e.getMessage()); + return null; + } + + } + + public static ItemStack getSkull(String displayName, String uuid, String value) { + String url = "https://textures.minecraft.net/texture/" + value; + ItemStack render = new ItemStack(Items.skull, 1, 3); + + NBTTagCompound skullOwner = new NBTTagCompound(); + skullOwner.setString("Id", uuid); + skullOwner.setString("Name", uuid); + + byte[] encodedData = Base64.getEncoder().encode(String.format("{textures:{SKIN:{url:\"%s\"}}}", url).getBytes()); + NBTTagCompound textures_0 = new NBTTagCompound(); + textures_0.setString("Value", new String(encodedData)); + + NBTTagList textures = new NBTTagList(); + textures.appendTag(textures_0); + + NBTTagCompound display = new NBTTagCompound(); + display.setString("Name", displayName); + + NBTTagCompound tag = new NBTTagCompound(); + tag.setTag("display", display); + + NBTTagCompound properties = new NBTTagCompound(); + properties.setTag("textures", textures); + skullOwner.setTag("Properties", properties); + tag.setTag("SkullOwner", skullOwner); + render.setTagCompound(tag); + return render; + } + + @SubscribeEvent + public void onChatEvent(ClientChatReceivedEvent event) { + String message = event.message.getFormattedText().toLowerCase(Locale.ROOT); + if ( + message.contains("you have bought") || + message.contains("you don't have enough coins") || + message.contains("this auction wasn't found") || + message.contains("there was an error with the auction house") || + message.contains("you didn't participate in this auction") || + message.contains("you claimed") || + message.contains("you purchased") || + message.contains("you cannot view this auction") + ) { + //close the gui + resetGUI(); + mc.thePlayer.closeScreen(); + } + } + + public ItemStack getItem(int slotNum, GuiChest currentScreen) { + ContainerChest container = (ContainerChest) currentScreen.inventorySlots; + return container.getSlot(slotNum).getStack(); + } + + public boolean waitingForBed(GuiChest currentScreen) { + ItemStack bedStack = getItem(31, currentScreen); + if (bedStack == null || !bedStack.getItem().equals(Item.getByNameOrId("minecraft:bed"))) { + return false; + } + + ItemStack itemStack = getItem(13, currentScreen); + if (itemStack == null) { + return false; + } + List<String> itemTooltip = itemStack.getTooltip(Minecraft.getMinecraft().thePlayer, false); + for (String data : itemTooltip) { + Matcher matcher = CAN_BUY_IN_MATCHER.matcher(EnumChatFormatting.getTextWithoutFormattingCodes(data)); + if (!matcher.find()) { + continue; + } + String timeData = matcher.group(1); + if (timeData.equals("Soon!")) { + return true; + } + } + return false; + } + + public String isAlreadyBought(String[] tooltip) { + for (String data : tooltip) { + Matcher matcher = BUYER_MATCHER.matcher(EnumChatFormatting.getTextWithoutFormattingCodes(data)); + if (!matcher.find()) { + continue; + } + return data.replaceAll("§5§o§7Buyer: ", ""); + } + return null; + } + + private static boolean isMouseOverCancel(int mouseX, int mouseY, int screenWidth, int screenHeight, int width, int height) { + return mouseX > screenWidth / 2 - width / 2 + 5 && mouseX < screenWidth / 2 - width / 2 + 5 + (width - 10) / 2 - 25 && mouseY > 10 + 5 + 14 + 5 + (height - 100) + 5 && mouseY < 10 + 5 + 14 + 5 + (height - 100) + 5 + 60; + } + + private static boolean isMouseOverAccept(int mouseX, int mouseY, int screenWidth, int screenHeight, int width, int height) { + return mouseX > screenWidth / 2 - width / 2 + 5 + (width - 10) / 2 - 20 && mouseX < (screenWidth / 2 - width / 2 + 5 + (width - 10) / 2 - 20) + (width - 10) / 2 + 20 && mouseY > 10 + 5 + 14 + 5 + (height - 100) + 5 && mouseY < 10 + 5 + 14 + 5 + (height - 100) + 5 + 60; + } + + public boolean isClicked() { + return wasMouseDown && !Mouse.isButtonDown(0); + } + + @SubscribeEvent + public void onRenderEvent(TickEvent.RenderTickEvent event) { + if (Minecraft.getMinecraft() == null) return; + if (event.phase == TickEvent.Phase.END) { + wasMouseDown = Mouse.isButtonDown(0); + } + } + + @SubscribeEvent + public void onMouseClicked(GuiScreenEvent.MouseInputEvent.Pre event) { + if (!Mouse.getEventButtonState()) { + return; + } + if (isRendered) { + event.setCanceled(true); + } + } +} diff --git a/src/main/java/de/torui/coflsky/gui/bingui/BinGuiManager.java b/src/main/java/de/torui/coflsky/gui/bingui/BinGuiManager.java new file mode 100644 index 0000000..db0b110 --- /dev/null +++ b/src/main/java/de/torui/coflsky/gui/bingui/BinGuiManager.java @@ -0,0 +1,19 @@ +package de.torui.coflsky.gui.bingui; + +import de.torui.coflsky.CoflSky; +import de.torui.coflsky.gui.GUIType; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.inventory.GuiChest; +import org.lwjgl.input.Mouse; + +public class BinGuiManager { + + public static void openNewFlipGui(String message, String extraData) { + if( CoflSky.config.purchaseOverlay != GUIType.COFL){ + return; + } + GuiChest currentGui = new BinGuiCurrent(Minecraft.getMinecraft().thePlayer.inventory, null, message, extraData); + Mouse.setGrabbed(false); + Minecraft.getMinecraft().displayGuiScreen(currentGui); + } +}
\ No newline at end of file diff --git a/src/main/java/de/torui/coflsky/gui/bingui/BuyState.java b/src/main/java/de/torui/coflsky/gui/bingui/BuyState.java new file mode 100644 index 0000000..7e935e2 --- /dev/null +++ b/src/main/java/de/torui/coflsky/gui/bingui/BuyState.java @@ -0,0 +1,8 @@ +package de.torui.coflsky.gui.bingui; + +public enum BuyState { + INIT, + PURCHASE, + CONFIRM, + BUYING +} diff --git a/src/main/java/de/torui/coflsky/gui/bingui/helper/ColorPallet.java b/src/main/java/de/torui/coflsky/gui/bingui/helper/ColorPallet.java new file mode 100644 index 0000000..c67f9be --- /dev/null +++ b/src/main/java/de/torui/coflsky/gui/bingui/helper/ColorPallet.java @@ -0,0 +1,25 @@ +package de.torui.coflsky.gui.bingui.helper; + +import java.awt.*; + +public enum ColorPallet { + //could be changed through a config or something + PRIMARY(new Color(34, 40, 49, 255)), + SECONDARY(new Color(57, 62, 70, 255)), + TERTIARY(new Color(0, 173, 181, 255)), + WHITE(new Color(238, 238, 238, 255)), + ERROR(new Color(178, 30, 30, 255)), + SUCCESS(new Color(114, 208, 0, 255)), + WARNING(new Color(208, 121, 22, 255)), + INFO(new Color(204, 253, 233, 255)); + + private Color color; + + ColorPallet(Color color) { + this.color = color; + } + + public Color getColor() { + return color; + } +} diff --git a/src/main/java/de/torui/coflsky/gui/bingui/helper/GuiUtilsClone.java b/src/main/java/de/torui/coflsky/gui/bingui/helper/GuiUtilsClone.java new file mode 100644 index 0000000..d59d3af --- /dev/null +++ b/src/main/java/de/torui/coflsky/gui/bingui/helper/GuiUtilsClone.java @@ -0,0 +1,349 @@ +/* + * Forge Mod Loader + * Copyright (c) 2012-2014 cpw. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the GNU Lesser Public License v2.1 + * which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * + * Contributors (this class): + * bspkrs - implementation + */ + +package de.torui.coflsky.gui.bingui.helper; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.RenderHelper; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.WorldRenderer; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.util.ResourceLocation; +import org.lwjgl.opengl.GL11; + +import java.util.ArrayList; +import java.util.List; + +/** + * This class provides several methods and constants used by the Config GUI classes. + * + * @author bspkrs + */ +public class GuiUtilsClone { + public static final String UNDO_CHAR = "\u21B6"; + public static final String RESET_CHAR = "\u2604"; + public static final String VALID = "\u2714"; + public static final String INVALID = "\u2715"; + + public static int[] colorCodes = new int[]{0, 170, 43520, 43690, 11141120, 11141290, 16755200, 11184810, 5592405, 5592575, 5635925, 5636095, 16733525, 16733695, 16777045, 16777215, + 0, 42, 10752, 10794, 2752512, 2752554, 2763264, 2763306, 1381653, 1381695, 1392405, 1392447, 4134165, 4134207, 4144917, 4144959}; + + public static int getColorCode(char c, boolean isLighter) { + return colorCodes[isLighter ? "0123456789abcdef".indexOf(c) : "0123456789abcdef".indexOf(c) + 16]; + } + + /** + * Draws a textured box of any size (smallest size is borderSize * 2 square) based on a fixed size textured box with continuous borders + * and filler. It is assumed that the desired texture ResourceLocation object has been bound using + * Minecraft.getMinecraft().getTextureManager().bindTexture(resourceLocation). + * + * @param x x axis offset + * @param y y axis offset + * @param u bound resource location image x offset + * @param v bound resource location image y offset + * @param width the desired box width + * @param height the desired box height + * @param textureWidth the width of the box texture in the resource location image + * @param textureHeight the height of the box texture in the resource location image + * @param borderSize the size of the box's borders + * @param zLevel the zLevel to draw at + */ + public static void drawContinuousTexturedBox(int x, int y, int u, int v, int width, int height, int textureWidth, int textureHeight, + int borderSize, float zLevel) { + drawContinuousTexturedBox(x, y, u, v, width, height, textureWidth, textureHeight, borderSize, borderSize, borderSize, borderSize, zLevel); + } + + /** + * Draws a textured box of any size (smallest size is borderSize * 2 square) based on a fixed size textured box with continuous borders + * and filler. The provided ResourceLocation object will be bound using + * Minecraft.getMinecraft().getTextureManager().bindTexture(resourceLocation). + * + * @param res the ResourceLocation object that contains the desired image + * @param x x axis offset + * @param y y axis offset + * @param u bound resource location image x offset + * @param v bound resource location image y offset + * @param width the desired box width + * @param height the desired box height + * @param textureWidth the width of the box texture in the resource location image + * @param textureHeight the height of the box texture in the resource location image + * @param borderSize the size of the box's borders + * @param zLevel the zLevel to draw at + */ + public static void drawContinuousTexturedBox(ResourceLocation res, int x, int y, int u, int v, int width, int height, int textureWidth, int textureHeight, + int borderSize, float zLevel) { + drawContinuousTexturedBox(res, x, y, u, v, width, height, textureWidth, textureHeight, borderSize, borderSize, borderSize, borderSize, zLevel); + } + + /** + * Draws a textured box of any size (smallest size is borderSize * 2 square) based on a fixed size textured box with continuous borders + * and filler. The provided ResourceLocation object will be bound using + * Minecraft.getMinecraft().getTextureManager().bindTexture(resourceLocation). + * + * @param res the ResourceLocation object that contains the desired image + * @param x x axis offset + * @param y y axis offset + * @param u bound resource location image x offset + * @param v bound resource location image y offset + * @param width the desired box width + * @param height the desired box height + * @param textureWidth the width of the box texture in the resource location image + * @param textureHeight the height of the box texture in the resource location image + * @param topBorder the size of the box's top border + * @param bottomBorder the size of the box's bottom border + * @param leftBorder the size of the box's left border + * @param rightBorder the size of the box's right border + * @param zLevel the zLevel to draw at + */ + public static void drawContinuousTexturedBox(ResourceLocation res, int x, int y, int u, int v, int width, int height, int textureWidth, int textureHeight, + int topBorder, int bottomBorder, int leftBorder, int rightBorder, float zLevel) { + Minecraft.getMinecraft().getTextureManager().bindTexture(res); + drawContinuousTexturedBox(x, y, u, v, width, height, textureWidth, textureHeight, topBorder, bottomBorder, leftBorder, rightBorder, zLevel); + } + + /** + * Draws a textured box of any size (smallest size is borderSize * 2 square) based on a fixed size textured box with continuous borders + * and filler. It is assumed that the desired texture ResourceLocation object has been bound using + * Minecraft.getMinecraft().getTextureManager().bindTexture(resourceLocation). + * + * @param x x axis offset + * @param y y axis offset + * @param u bound resource location image x offset + * @param v bound resource location image y offset + * @param width the desired box width + * @param height the desired box height + * @param textureWidth the width of the box texture in the resource location image + * @param textureHeight the height of the box texture in the resource location image + * @param topBorder the size of the box's top border + * @param bottomBorder the size of the box's bottom border + * @param leftBorder the size of the box's left border + * @param rightBorder the size of the box's right border + * @param zLevel the zLevel to draw at + */ + public static void drawContinuousTexturedBox(int x, int y, int u, int v, int width, int height, int textureWidth, int textureHeight, + int topBorder, int bottomBorder, int leftBorder, int rightBorder, float zLevel) { + GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); + GlStateManager.enableBlend(); + GlStateManager.tryBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, 1, 0); + + int fillerWidth = textureWidth - leftBorder - rightBorder; + int fillerHeight = textureHeight - topBorder - bottomBorder; + int canvasWidth = width - leftBorder - rightBorder; + int canvasHeight = height - topBorder - bottomBorder; + int xPasses = canvasWidth / fillerWidth; + int remainderWidth = canvasWidth % fillerWidth; + int yPasses = canvasHeight / fillerHeight; + int remainderHeight = canvasHeight % fillerHeight; + + // Draw Border + // Top Left + drawTexturedModalRect(x, y, u, v, leftBorder, topBorder, zLevel); + // Top Right + drawTexturedModalRect(x + leftBorder + canvasWidth, y, u + leftBorder + fillerWidth, v, rightBorder, topBorder, zLevel); + // Bottom Left + drawTexturedModalRect(x, y + topBorder + canvasHeight, u, v + topBorder + fillerHeight, leftBorder, bottomBorder, zLevel); + // Bottom Right + drawTexturedModalRect(x + leftBorder + canvasWidth, y + topBorder + canvasHeight, u + leftBorder + fillerWidth, v + topBorder + fillerHeight, rightBorder, bottomBorder, zLevel); + + for (int i = 0; i < xPasses + (remainderWidth > 0 ? 1 : 0); i++) { + // Top Border + drawTexturedModalRect(x + leftBorder + (i * fillerWidth), y, u + leftBorder, v, (i == xPasses ? remainderWidth : fillerWidth), topBorder, zLevel); + // Bottom Border + drawTexturedModalRect(x + leftBorder + (i * fillerWidth), y + topBorder + canvasHeight, u + leftBorder, v + topBorder + fillerHeight, (i == xPasses ? remainderWidth : fillerWidth), bottomBorder, zLevel); + + // Throw in some filler for good measure + for (int j = 0; j < yPasses + (remainderHeight > 0 ? 1 : 0); j++) + drawTexturedModalRect(x + leftBorder + (i * fillerWidth), y + topBorder + (j * fillerHeight), u + leftBorder, v + topBorder, (i == xPasses ? remainderWidth : fillerWidth), (j == yPasses ? remainderHeight : fillerHeight), zLevel); + } + + // Side Borders + for (int j = 0; j < yPasses + (remainderHeight > 0 ? 1 : 0); j++) { + // Left Border + drawTexturedModalRect(x, y + topBorder + (j * fillerHeight), u, v + topBorder, leftBorder, (j == yPasses ? remainderHeight : fillerHeight), zLevel); + // Right Border + drawTexturedModalRect(x + leftBorder + canvasWidth, y + topBorder + (j * fillerHeight), u + leftBorder + fillerWidth, v + topBorder, rightBorder, (j == yPasses ? remainderHeight : fillerHeight), zLevel); + } + } + + public static void drawTexturedModalRect(int x, int y, int u, int v, int width, int height, float zLevel) { + float uScale = 1f / 0x100; + float vScale = 1f / 0x100; + Tessellator tessellator = Tessellator.getInstance(); + WorldRenderer wr = tessellator.getWorldRenderer(); + wr.begin(7, DefaultVertexFormats.POSITION_TEX); + wr.pos(x, y + height, zLevel).tex(u * uScale, ((v + height) * vScale)).endVertex(); + wr.pos(x + width, y + height, zLevel).tex((u + width) * uScale, ((v + height) * vScale)).endVertex(); + wr.pos(x + width, y, zLevel).tex((u + width) * uScale, (v * vScale)).endVertex(); + wr.pos(x, y, zLevel).tex(u * uScale, (v * vScale)).endVertex(); + tessellator.draw(); + } + + /** + * Draws a tooltip box on the screen with text in it. + * Automatically positions the box relative to the mouse to match Mojang's implementation. + * Automatically wraps text when there is not enough space on the screen to display the text without wrapping. + * Can have a maximum width set to avoid creating very wide tooltips. + * + * @param textLines the lines of text to be drawn in a hovering tooltip box. + * @param mouseX the mouse X position + * @param mouseY the mouse Y position + * @param screenWidth the available screen width for the tooltip to drawn in + * @param screenHeight the available screen height for the tooltip to drawn in + * @param maxTextWidth the maximum width of the text in the tooltip box. + * Set to a negative number to have no max width. + * @param font the font for drawing the text in the tooltip box + */ + public static void drawHoveringText(List<String> textLines, final int mouseX, final int mouseY, final int screenWidth, final int screenHeight, final int maxTextWidth, FontRenderer font) { + if (!textLines.isEmpty()) { + GlStateManager.disableRescaleNormal(); + RenderHelper.disableStandardItemLighting(); + GlStateManager.disableLighting(); + GlStateManager.disableDepth(); + int tooltipTextWidth = 0; + + for (String textLine : textLines) { + int textLineWidth = font.getStringWidth(textLine); + + if (textLineWidth > tooltipTextWidth) { + tooltipTextWidth = textLineWidth; + } + } + + boolean needsWrap = false; + + int titleLinesCount = 1; + int tooltipX = mouseX + 4; + if (tooltipX + tooltipTextWidth + 4 > screenWidth) { + tooltipX = mouseX - 16 - tooltipTextWidth; + if (tooltipX < 4) // if the tooltip doesn't fit on the screen + { + if (mouseX > screenWidth / 2) { + tooltipTextWidth = mouseX - 12 - 8; + } else { + tooltipTextWidth = screenWidth - 16 - mouseX; + } + needsWrap = true; + } + } + + if (maxTextWidth > 0 && tooltipTextWidth > maxTextWidth) { + tooltipTextWidth = maxTextWidth; + needsWrap = true; + } + + if (needsWrap) { + int wrappedTooltipWidth = 0; + List<String> wrappedTextLines = new ArrayList<String>(); + for (int i = 0; i < textLines.size(); i++) { + String textLine = textLines.get(i); + List<String> wrappedLine = font.listFormattedStringToWidth(textLine, tooltipTextWidth); + if (i == 0) { + titleLinesCount = wrappedLine.size(); + } + + for (String line : wrappedLine) { + int lineWidth = font.getStringWidth(line); + if (lineWidth > wrappedTooltipWidth) { + wrappedTooltipWidth = lineWidth; + } + wrappedTextLines.add(line); + } + } + tooltipTextWidth = wrappedTooltipWidth; + textLines = wrappedTextLines; + + if (mouseX > screenWidth / 2) { + tooltipX = mouseX - 16 - tooltipTextWidth; + } else { + tooltipX = mouseX + 12; + } + } + + int tooltipY = mouseY + 4; |
