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 | |
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')
10 files changed, 1614 insertions, 0 deletions
diff --git a/src/main/java/de/torui/coflsky/gui/GUIType.java b/src/main/java/de/torui/coflsky/gui/GUIType.java new file mode 100644 index 0000000..586ac72 --- /dev/null +++ b/src/main/java/de/torui/coflsky/gui/GUIType.java @@ -0,0 +1,6 @@ +package de.torui.coflsky.gui; + +public enum GUIType { + TFM, + COFL +} 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; + int tooltipHeight = 8; + + if (textLines.size() > 1) { + tooltipHeight += (textLines.size() - 1) * 10; + if (textLines.size() > titleLinesCount) { + tooltipHeight += 2; // gap between title lines and next lines + } + } + + if (tooltipY + tooltipHeight + 6 > screenHeight) { + tooltipY = screenHeight - tooltipHeight - 6; + } + + final int zLevel = 300; + final int backgroundColor = 0xF0100010; + drawGradientRect(zLevel, tooltipX - 3, tooltipY - 4, tooltipX + tooltipTextWidth + 3, tooltipY - 3, backgroundColor, backgroundColor); + drawGradientRect(zLevel, tooltipX - 3, tooltipY + tooltipHeight + 3, tooltipX + tooltipTextWidth + 3, tooltipY + tooltipHeight + 4, backgroundColor, backgroundColor); + drawGradientRect(zLevel, tooltipX - 3, tooltipY - 3, tooltipX + tooltipTextWidth + 3, tooltipY + tooltipHeight + 3, backgroundColor, backgroundColor); + drawGradientRect(zLevel, tooltipX - 4, tooltipY - 3, tooltipX - 3, tooltipY + tooltipHeight + 3, backgroundColor, backgroundColor); + drawGradientRect(zLevel, tooltipX + tooltipTextWidth + 3, tooltipY - 3, tooltipX + tooltipTextWidth + 4, tooltipY + tooltipHeight + 3, backgroundColor, backgroundColor); + final int borderColorStart = 0x505000FF; + final int borderColorEnd = (borderColorStart & 0xFEFEFE) >> 1 | borderColorStart & 0xFF000000; + drawGradientRect(zLevel, tooltipX - 3, tooltipY - 3 + 1, tooltipX - 3 + 1, tooltipY + tooltipHeight + 3 - 1, borderColorStart, borderColorEnd); + drawGradientRect(zLevel, tooltipX + tooltipTextWidth + 2, tooltipY - 3 + 1, tooltipX + tooltipTextWidth + 3, tooltipY + tooltipHeight + 3 - 1, borderColorStart, borderColorEnd); + drawGradientRect(zLevel, tooltipX - 3, tooltipY - 3, tooltipX + tooltipTextWidth + 3, tooltipY - 3 + 1, borderColorStart, borderColorStart); + drawGradientRect(zLevel, tooltipX - 3, tooltipY + tooltipHeight + 2, tooltipX + tooltipTextWidth + 3, tooltipY + tooltipHeight + 3, borderColorEnd, borderColorEnd); + + for (int lineNumber = 0; lineNumber < textLines.size(); ++lineNumber) { + String line = textLines.get(lineNumber); + font.drawStringWithShadow(line, (float) tooltipX, (float) tooltipY, -1); + + if (lineNumber + 1 == titleLinesCount) { + tooltipY += 2; + } + + tooltipY += 10; + } + + GlStateManager.enableLighting(); + GlStateManager.enableDepth(); + RenderHelper.enableStandardItemLighting(); + GlStateManager.enableRescaleNormal(); + } + } + + public static void drawGradientRect(int zLevel, int left, int top, int right, int bottom, int startColor, int endColor) { + float startAlpha = (float) (startColor >> 24 & 255) / 255.0F; + float startRed = (float) (startColor >> 16 & 255) / 255.0F; + float startGreen = (float) (startColor >> 8 & 255) / 255.0F; + float startBlue = (float) (startColor & 255) / 255.0F; + float endAlpha = (float) (endColor >> 24 & 255) / 255.0F; + float endRed = (float) (endColor >> 16 & 255) / 255.0F; + float endGreen = (float) (endColor >> 8 & 255) / 255.0F; + float endBlue = (float) (endColor & 255) / 255.0F; + + GlStateManager.disableTexture2D(); + GlStateManager.enableBlend(); + GlStateManager.disableAlpha(); + GlStateManager.tryBlendFuncSeparate(770, 771, 1, 0); + GlStateManager.shadeModel(7425); + + Tessellator tessellator = Tessellator.getInstance(); + WorldRenderer worldrenderer = tessellator.getWorldRenderer(); + worldrenderer.begin(7, DefaultVertexFormats.POSITION_COLOR); + worldrenderer.pos(right, top, zLevel).color(startRed, startGreen, startBlue, startAlpha).endVertex(); + worldrenderer.pos(left, top, zLevel).color(startRed, startGreen, startBlue, startAlpha).endVertex(); + worldrenderer.pos(left, bottom, zLevel).color(endRed, endGreen, endBlue, endAlpha).endVertex(); + worldrenderer.pos(right, bottom, zLevel).color(endRed, endGreen, endBlue, endAlpha).endVertex(); + tessellator.draw(); + + GlStateManager.shadeModel(7424); + GlStateManager.disableBlend(); + GlStateManager.enableAlpha(); + GlStateManager.enableTexture2D(); + } +} diff --git a/src/main/java/de/torui/coflsky/gui/bingui/helper/RenderUtils.java b/src/main/java/de/torui/coflsky/gui/bingui/helper/RenderUtils.java new file mode 100644 index 0000000..64b2594 --- /dev/null +++ b/src/main/java/de/torui/coflsky/gui/bingui/helper/RenderUtils.java @@ -0,0 +1,367 @@ +package de.torui.coflsky.gui.bingui.helper; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.renderer.RenderHelper; +import net.minecraft.client.renderer.entity.RenderItem; +import net.minecraft.item.ItemStack; +import org.jetbrains.annotations.NotNull; +import org.lwjgl.opengl.GL11; + +import java.awt.*; + + +/** + * Created by ForBai + */ +public class RenderUtils { + public static Minecraft mc = Minecraft.getMinecraft(); + + //draw a rectangle + public static void drawRect(float x, float y, float width, float height, int color) { + float alpha = (float) (color >> 24 & 255) / 255.0F; + float red = (float) (color >> 16 & 255) / 255.0F; + float green = (float) (color >> 8 & 255) / 255.0F; + float blue = (float) (color & 255) / 255.0F; + GL11.glEnable(GL11.GL_BLEND); + GL11.glDisable(GL11.GL_TEXTURE_2D); + GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); + GL11.glColor4f(red, green, blue, alpha); + GL11.glBegin(GL11.GL_QUADS); + GL11.glVertex2d(x, y); + GL11.glVertex2d(x, y + height); + GL11.glVertex2d(x + width, y + height); + GL11.glVertex2d(x + width, y); + GL11.glEnd(); + GL11.glEnable(GL11.GL_TEXTURE_2D); + GL11.glDisable(GL11.GL_BLEND); + } + + + //draws an outlined rectangle with a given color and size and a given line width + public static void drawRectOutline(int x, int y, int width, int height, float lineWidth, Color color) { + GL11.glEnable(GL11.GL_BLEND); + GL11.glDisable(GL11.GL_TEXTURE_2D); + GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); + setColor(color); + GL11.glLineWidth(lineWidth); + GL11.glBegin(GL11.GL_LINE_LOOP); + GL11.glVertex2d(x, y); + GL11.glVertex2d(x + width, y); + GL11.glVertex2d(x + width, y + height); + GL11.glVertex2d(x, y + height); + GL11.glEnd(); + GL11.glEnable(GL11.GL_TEXTURE_2D); + GL11.glDisable(GL11.GL_BLEND); + } + + //draws a circle with a given radius and thickness + public static void drawCircle(int x, int y, int radius, Color color) { + GL11.glEnable(GL11.GL_BLEND); + GL11.glDisable(GL11.GL_TEXTURE_2D); + GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); + setColor(color); + GL11.glBegin(GL11.GL_TRIANGLE_FAN); + GL11.glVertex2d(x, y); + for (int i = 0; i <= 360; i++) { + GL11.glVertex2d(x + Math.sin(i * Math.PI / 180) * radius, y + Math.cos(i * Math.PI / 180) * radius); + } + GL11.glEnd(); + GL11.glEnable(GL11.GL_TEXTURE_2D); + GL11.glDisable(GL11.GL_BLEND); + } + + //draws a circle outline with a given radius and thickness + public static void drawCircleOutline(int x, int y, float radius, float thickness, Color color) { + GL11.glEnable(GL11.GL_BLEND); + GL11.glDisable(GL11.GL_TEXTURE_2D); + GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); + setColor(color); + GL11.glBegin(GL11.GL_LINE_LOOP); + for (int i = 0; i <= 360; i++) { + GL11.glVertex2d(x + Math.sin(i * Math.PI / 180) * radius, y + Math.cos(i * Math.PI / 180) * radius); + } + GL11.glEnd(); + GL11.glEnable(GL11.GL_TEXTURE_2D); + GL11.glDisable(GL11.GL_BLEND); + } + + //draws line from x1,y1 to x2,y2 with a given color and thickness + public static void drawLine(float x1, float y1, float x2, float y2, float thickness, Color color) { + GL11.glEnable(GL11.GL_BLEND); + GL11.glDisable(GL11.GL_TEXTURE_2D); + GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); + setColor(color); + GL11.glLineWidth(thickness); + GL11.glBegin(GL11.GL_LINES); + GL11.glVertex2d(x1, y1); + GL11.glVertex2d(x2, y2); + GL11.glEnd(); + GL11.glEnable(GL11.GL_TEXTURE_2D); + GL11.glDisable(GL11.GL_BLEND); + } + + //draws a triangle from x1,y1 to x2,y2 to x3,y3 + public static void drawTriangle(int x, int y, int x2, int y2, int x3, int y3, Color color) { + GL11.glEnable(GL11.GL_BLEND); + GL11.glDisable(GL11.GL_TEXTURE_2D); + GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); + setColor(color); + GL11.glBegin(GL11.GL_TRIANGLES); + GL11.glVertex2d(x, y); + GL11.glVertex2d(x2, y2); + GL11.glVertex2d(x3, y3); + GL11.glEnd(); + GL11.glEnable(GL11.GL_TEXTURE_2D); + GL11.glDisable(GL11.GL_BLEND); + } + + //draws a triangle outline from x1,y1 to x2,y2 to x3,y3 + public static void drawTriangleOutline(int x, int y, int x2, int y2, int x3, int y3, Color color) { + GL11.glEnable(GL11.GL_BLEND); + GL11.glDisable(GL11.GL_TEXTURE_2D); + GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); + setColor(color); + GL11.glBegin(GL11.GL_LINE_LOOP); + GL11.glVertex2d(x, y); + GL11.glVertex2d(x2, y2); + GL11.glVertex2d(x3, y3); + GL11.glEnd(); + GL11.glEnable(GL11.GL_TEXTURE_2D); + GL11.glDisable(GL11.GL_BLEND); + } + + //draws an arc with a given radius, start angle, and end angle + public static void drawArc(int x, int y, int radius, int startAngle, int endAngle, Color color) { + GL11.glEnable(GL11.GL_BLEND); + GL11.glDisable(GL11.GL_TEXTURE_2D); + GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); + setColor(color); + GL11.glBegin(GL11.GL_TRIANGLE_FAN); + GL11.glVertex2d(x, y); + for (int i = startAngle; i <= endAngle; i++) { + GL11.glVertex2d(x + Math.sin(i * Math.PI / 180) * radius, y + Math.cos(i * Math.PI / 180) * radius); + } + GL11.glEnd(); + GL11.glEnable(GL11.GL_TEXTURE_2D); + GL11.glDisable(GL11.GL_BLEND); + } + + + //draw a loading circle with a given radius, thickness, and speed + public static void drawLoadingCircle(float x, float y, float radius, float thickness, float speed, Color color) { + GL11.glEnable(GL11.GL_BLEND); + GL11.glDisable(GL11.GL_TEXTURE_2D); + GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); + setColor(color); + GL11.glLineWidth(thickness); + GL11.glBegin(GL11.GL_LINE_STRIP); + for (int i = 0; i <= 360; i++) { + GL11.glVertex2d(x + Math.sin((i + speed) * Math.PI / 180) * radius, y + Math.cos((i + speed) * Math.PI / 180) * radius); + } + GL11.glEnd(); + GL11.glEnable(GL11.GL_TEXTURE_2D); + GL11.glDisable(GL11.GL_BLEND); + } + + //draws a rounded rectangle with a given radius and color and size + public static void drawRoundedRect(int x, int y, int width, int height, int radius, @NotNull Color color) { + + //draw the two rectangles + drawRect(x + radius, y, width - radius * 2, height, color.getRGB()); + drawRect(x, y + radius, radius, height - radius * 2, color.getRGB()); + drawRect(x + width - radius, y + radius, radius, height - radius * 2, color.getRGB()); + + //drawRect(x + radius, y, width - radius - radius, height, color.getRGB()); + //drawRect(x, y + radius, width, height - radius - radius, color.getRGB()); + //draw the circles + drawArc(x + radius, y + radius, radius, 180, 270, color); + drawArc(x + width - radius, y + radius, radius, 90, 180, color); + drawArc(x + radius, y + height - radius, radius, 270, 360, color); + drawArc(x + width - radius, y + height - radius, radius, 0, 90, color); + + //drawCircle(x + radius, y + radius, radius, color); + //drawCircle(x + width - radius, y + radius, radius, color); + //drawCircle(x + radius, y + height - radius, radius, color); + //drawCircle(x + width - radius, y + height - radius, radius, color); + + //drawRectOutline(x, y, width, height, 1, Color.GREEN); + } + + //draws a gradient rectangle with a given color and size + public static void drawGradientRect(int x, int y, int width, int height, Color color1, Color color2) { + GL11.glEnable(GL11.GL_BLEND); + GL11.glDisable(GL11.GL_TEXTURE_2D); + GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); + GL11.glShadeModel(GL11.GL_SMOOTH); + GL11.glBegin(GL11.GL_QUADS); + setColor(color1); + GL11.glVertex2d(x, y); + GL11.glVertex2d(x + width, y); + setColor(color2); + GL11.glVertex2d(x + width, y + height); + GL11.glVertex2d(x, y + height); + GL11.glEnd(); + GL11.glShadeModel(GL11.GL_FLAT); + GL11.glEnable(GL11.GL_TEXTURE_2D); + GL11.glDisable(GL11.GL_BLEND); + } + + + public static void drawString(String text, int x, int y, Color color) { + setColor(color); + mc.fontRendererObj.drawString(text, x, y, color.getRGB()); + } + + public static void drawStringWithShadow(String text, int x, int y, Color color) { + setColor(color); + mc.fontRendererObj.drawStringWithShadow(text, x, y, color.getRGB()); + } + + public static void drawCenteredString(String text, int x, int y, Color color) { + setColor(color); + mc.fontRendererObj.drawString(text, x - mc.fontRendererObj.getStringWidth(text) / 2, y, color.getRGB()); + } + + public static void drawCenteredStringWithShadow(String text, int x, int y, Color color) { + setColor(color); + mc.fontRendererObj.drawStringWithShadow(text, x - mc.fontRendererObj.getStringWidth(text) / 2, y, color.getRGB()); + } + + //draws a string with custom scale + public static void drawString(String text, int x, int y, Color color, int scale) { + setColor(color); + FontRenderer fr = mc.fontRendererObj; + fr.drawString(text, x, y, color.getRGB()); + } + + //draws a string with custom scale and shadow + public static void drawStringWithShadow(String text, int x, int y, Color color, int scale) { + setColor(color); + FontRenderer fr = mc.fontRendererObj; + fr.drawStringWithShadow(text, x, y, color.getRGB()); + } + + public static void drawCenteredString(String text, int x, int y, Color color, int scale) { + setColor(color); + FontRenderer fr = mc.fontRendererObj; + fr.drawString(text, x - fr.getStringWidth(text) / 2, y, color.getRGB()); + } + + public static void drawCenteredStringWithShadow(String text, int x, int y, Color color, int scale) { + setColor(color); + FontRenderer fr = mc.fontRendererObj; + fr.drawStringWithShadow(text, x - fr.getStringWidth(text) / 2, y, color.getRGB()); + } + + public static void drawCenteredStringWithShadow(String text, int x, int y, Color color, int scale, boolean centered) { + setColor(color); + FontRenderer fr = mc.fontRendererObj; + if (centered) { + fr.drawStringWithShadow(text, x - fr.getStringWidth(text) / 2, y, color.getRGB()); + } else { + fr.drawStringWithShadow(text, x, y, color.getRGB()); + } + } + + //draws an ItemStack at a given position with a given scale + public static void drawItemStack(ItemStack itemStack, int x, int y, float scale) { + GL11.glPushMatrix(); + GL11.glScalef(scale, scale, scale); + mc.getRenderItem().renderItemIntoGUI(itemStack, x, y); + GL11.glPopMatrix(); + } + + public static void drawItemStackWithText(ItemStack stack, int x, int y, String text) { + if (stack == null) return; + RenderItem itemRender = Minecraft.getMinecraft().getRenderItem(); + setColor(Color.WHITE); + RenderHelper.enableGUIStandardItemLighting(); + itemRender.zLevel = -145; + itemRender.renderItemAndEffectIntoGUI(stack, x, y); + itemRender.renderItemOverlayIntoGUI(Minecraft.getMinecraft().fontRendererObj, stack, x, y, text); + itemRender.zLevel = 0; + RenderHelper.disableStandardItemLighting(); + } + + public static void drawItemStack(ItemStack stack, int x, int y) { + drawItemStackWithText(stack, x, y, null); + } + + public static void drawItemStack(ItemStack itemStack, int x, int y, float scaleX, float scaleY) { + GL11.glPushMatrix(); + GL11.glScalef(scaleX, scaleY, 0); + drawItemStack(itemStack, x, y); + GL11.glPopMatrix(); + } + + //draw centered ItemStack at a given position with a given scale + public static void drawCenteredItemStack(ItemStack itemStack, int x, int y, float scale) { + GL11.glPushMatrix(); + GL11.glScalef(scale, scale, scale); + drawItemStack(itemStack, (int) (x - (scale / 2)), (int) (y - (scale / 2))); + GL11.glPopMatrix(); + } + + //draw a check mar with a given color and size using lines + public static void drawCheckMark(int x, int y, int size, Color color) { + GL11.glPushMatrix(); + GL11.glEnable(GL11.GL_BLEND); + GL11.glDisable(GL11.GL_TEXTURE_2D); + GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); + GL11.glLineWidth(2); + setColor(color); + GL11.glBegin(GL11.GL_LINES); + GL11.glVertex2d(x, y + size / 2); + GL11.glVertex2d(x + size / 2, y + size); + GL11.glVertex2d(x + size / 2, y + size); + GL11.glVertex2d(x + size, y); + GL11.glEnd(); + GL11.glEnable(GL11.GL_TEXTURE_2D); + GL11.glDisable(GL11.GL_BLEND); + GL11.glPopMatrix(); + } + + //draw a cross mark with a given color and start and end points + public static void drawCrossMark(int x, int y, int x2, int y2, Color color) { + GL11.glPushMatrix(); + GL11.glEnable(GL11.GL_BLEND); + GL11.glDisable(GL11.GL_TEXTURE_2D); + GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); + GL11.glLineWidth(2); + setColor(color); + GL11.glBegin(GL11.GL_LINES); + GL11.glVertex2d(x, y); + GL11.glVertex2d(x2, y2); + GL11.glVertex2d(x2, y); + GL11.glVertex2d(x, y2); + GL11.glEnd(); + GL11.glEnable(GL11.GL_TEXTURE_2D); + GL11.glDisable(GL11.GL_BLEND); + GL11.glPopMatrix(); + } + + + //set alpha of color + public static Color setAlpha(Color color, int alpha) { + return new Color(color.getRed(), color.getGreen(), color.getBlue(), alpha); + } + + //set color + public static void setColor(int color) { + float alpha = (float) (color >> 24 & 255) / 255.0F; + float red = (float) (color >> 16 & 255) / 255.0F; + float green = (float) (color >> 8 & 255) / 255.0F; + float blue = (float) (color & 255) / 255.0F; + GL11.glColor4f(red, green, blue, alpha); + } + + public static void setColor(Color color) { + setColor(color.getRGB()); + } + + //rotate + public static void rotate(float angle) { + GL11.glRotatef(angle, 0.0F, 0.0F, 1.0F); + } +} diff --git a/src/main/java/de/torui/coflsky/gui/tfm/ButtonRemapper.java b/src/main/java/de/torui/coflsky/gui/tfm/ButtonRemapper.java new file mode 100644 index 0000000..2d48434 --- /dev/null +++ b/src/main/java/de/torui/coflsky/gui/tfm/ButtonRemapper.java @@ -0,0 +1,338 @@ +package de.torui.coflsky.gui.tfm; + +import de.torui.coflsky.CoflSky; +import de.torui.coflsky.WSCommandHandler; +import de.torui.coflsky.gui.GUIType; +import de.torui.coflsky.handlers.EventHandler; +import de.torui.coflsky.handlers.EventRegistry; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.gui.GuiScreen; +import net.minecraft.client.gui.ScaledResolution; +import net.minecraft.client.gui.inventory.GuiChest; +import net.minecraft.client.gui.inventory.GuiContainer; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.inventory.ContainerChest; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.util.EnumChatFormatting; +import net.minecraftforge.client.event.GuiScreenEvent; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.relauncher.ReflectionHelper; +import org.lwjgl.input.Mouse; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import static net.minecraft.client.gui.Gui.drawRect; + +public class ButtonRemapper { + private static ButtonRemapper instance; + private final static int BUY_BUTTON_SLOT = 31; + private final static int ITEM_SLOT = 13; + private final static int CONFIRM_BUTTON_SLOT = 11; + private final static int CANCEL_CONFIRM_SLOT = 15; + private final static int BACK_BUTTON_SLOT = 49; + private final static double SCALE_VALUE = 2.0d; + private final static Pattern BED_TIME_PATTERN = Pattern.compile("Can buy in: (.*)"); + + private final Method drawItemMethod; + private final Method renderToolTipMethod; + + private ButtonRemapper() { + // drawItemStack obfuscated + String[] methodNames = new String[]{"drawItemStack", "func_146982_a"}; + drawItemMethod = ReflectionHelper.findMethod(GuiContainer.class, null, methodNames, ItemStack.class, int.class, int.class, String.class); + drawItemMethod.setAccessible(true); + // obfuscated renderToolTip method + methodNames = new String[]{"renderToolTip", "func_146285_a"}; + renderToolTipMethod = ReflectionHelper.findMethod(GuiScreen.class, null, methodNames, ItemStack.class, int.class, int.class); + } + + public static ButtonRemapper getInstance() { + if (instance == null) { + instance = new ButtonRemapper(); + } + return instance; + } + + 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(BUY_BUTTON_SLOT, currentScreen); + if (bedStack == null || !bedStack.getItem().equals(Item.getByNameOrId("minecraft:bed"))) { + return false; + } + + ItemStack itemStack = getItem(ITEM_SLOT, currentScreen); + if (itemStack == null) { + return false; + } + List<String> itemTooltip = itemStack.getTooltip(Minecraft.getMinecraft().thePlayer, false); + for (String data : itemTooltip) { + Matcher matcher = BED_TIME_PATTERN.matcher(EnumChatFormatting.getTextWithoutFormattingCodes(data)); + if (!matcher.find()) { + continue; + } + String timeData = matcher.group(1); + if (!timeData.equals("Soon!")) { + return true; + } + } + return false; + } + + private int[] getBuyBoxDimensions() { + int centerX = getGuiCenterX(); + int centerY = getGuiCenterY(); + double multiplier = 0.1; + return new int[]{(int) (centerX - (centerX * multiplier)), (int) (centerY + (centerY * multiplier)), + (int) (centerX + (centerX * multiplier)), (int) (centerY - (centerY * multiplier))}; + } + + private int[] getCancelBoxDimensions() { + int centerX = getGuiCenterX(); + int centerY = (int) (getGuiCenterY() * 1.25); + double multiplier = 0.05; + return new int[]{(int) (centerX - (centerX * multiplier)), (int) (centerY + (centerY * multiplier)), + (int) (centerX + (centerX * multiplier)), (int) (centerY - (centerY * multiplier))}; + } + + @SuppressWarnings("SameParameterValue") + private void drawBoxWithShadow(int leftX, int topY, int rightX, int bottomY, int colour, int shadowSize, int shadowColour) { + drawRect(leftX - shadowSize, topY + shadowSize, rightX + shadowSize, bottomY - shadowSize, shadowColour); + drawRect(leftX, topY, rightX, bottomY, colour); + } + + private void drawTfmBox(boolean isConfirm) { + String titleText; + if (isConfirm) { + titleText = "Cofl - Confirm Purchase"; + } else { + titleText = "Cofl - Auction View"; + } + int outerBox = 0xff4f4f4f; // gray colour + // draw the outer tfm box + drawBoxWithShadow((int) (getGuiCenterX() * 0.5), (int) (getGuiCenterY() * 1.6), (int) (getGuiCenterX() * 1.5), (int) (getGuiCenterY() * 0.4), outerBox, 1, 0xff000000); + Minecraft.getMinecraft().fontRendererObj.drawStringWithShadow(titleText, (int) (getGuiCenterX() * 0.55), (int) (getGuiCenterY() * 0.45), 0xFFFFFFFF); + } + + private void renderTooltip(GuiChest chest, ItemStack item) { + ToolTipHelper toolTipData = new ToolTipHelper(item); + int toolTipY = getGuiCenterY() - (toolTipData.determineHeight() / 2); + int toolTipX = (int) (getGuiCenterX() * 1.25) - (toolTipData.determineWidth() / 2); + if (toolTipX < getGuiCenterX()) { + toolTipX = getGuiCenterX() + 10; + } + try { + renderToolTipMethod.invoke(chest, item, toolTipX, toolTipY); + } catch (IllegalAccessException | InvocationTargetException e) { + e.printStackTrace(); + } + } + + private void renderItem(GuiChest chest, ItemStack item) { + GlStateManager.pushMatrix(); + GlStateManager.scale(SCALE_VALUE, SCALE_VALUE, 0); + int itemX = (int) ((getGuiCenterX() - 16) / SCALE_VALUE); + int itemY = (int) ((getGuiCenterY() - 16) / SCALE_VALUE); + try { + drawItemMethod.invoke(chest, item, itemX, itemY, null); + } catch (IllegalAccessException | InvocationTargetException e) { + e.printStackTrace(); + } + GlStateManager.popMatrix(); + } + + private void drawBuyBox(boolean shouldBeRed) { + int colour = shouldBeRed ? 255 << 16 : 255 << 8; + colour += 128 << 24; + int[] dim = getBuyBoxDimensions(); + drawBoxWithShadow(dim[0], dim[1], dim[2], dim[3], colour, 1, 0xff000000); + } + + private void drawCancelBox() { + int colour = 0x7FFF0000; + int[] dim = getCancelBoxDimensions(); + drawBoxWithShadow(dim[0], dim[1], dim[2], dim[3], colour, 1, 0xff000000); + } + + public void drawProfitInfo() { + FontRenderer font = Minecraft.getMinecraft().fontRendererObj; + String text = WSCommandHandler.flipHandler.lastClickedFlipMessage; + + if (text == null) { + return; + } + + StringBuilder current = new StringBuilder(); + int lineNo = 0; + for (int i = 0; i < text.length(); i++) { + char character = text.charAt(i); + current.append(character); + if (current.length() > 50 && character == ' ') { + font.drawStringWithShadow(current.toString(), (int) (getGuiCenterX() * 0.55), (int) (getGuiCenterY() * 0.5 + (15 * lineNo)), 0xFF8F8F8F); + current = new StringBuilder(); + lineNo++; + } + } + font.drawStringWithShadow(current.toString(), (int) (getGuiCenterX() * 0.55), (int) (getGuiCenterY() * 0.5 + (15 * lineNo)), 0xFF8F8F8F); + } + + private void drawBox(GuiChest chest, boolean shouldBeRed, boolean isConfirm) { + GlStateManager.pushMatrix(); + // in front of the items displayed on screen + GlStateManager.translate(0, 0, 512.0D); + ItemStack item = getItem(ITEM_SLOT, chest); + + drawTfmBox(isConfirm); + drawBuyBox(shouldBeRed); + drawCancelBox(); + + if (item != null) { + drawProfitInfo(); + renderItem(chest, item); + renderTooltip(chest, item); + } + + GlStateManager.popMatrix(); + } + + private int getGuiCenterX() { + ScaledResolution resolution = new ScaledResolution(Minecraft.getMinecraft()); + return resolution.getScaledWidth() / 2; + } + + private int getGuiCenterY() { + ScaledResolution resolution = new ScaledResolution(Minecraft.getMinecraft()); + return resolution.getScaledHeight() / 2; + } + + private boolean isInBox(int x, int y) { + int[] dim = getBuyBoxDimensions(); + return x > dim[0] && x < dim[2] + && y > dim[3] && y < dim[1]; + } + + private boolean isInCancelBox(int x, int y) { + int[] dim = getCancelBoxDimensions(); + return x > dim[0] && x < dim[2] + && y > dim[3] && y < dim[1]; + } + + public void drawBuyButton(GuiChest currentScreen) { + if (!shouldDrawGui(currentScreen)) { + return; + } + drawBox(currentScreen, waitingForBed(currentScreen), false); + } + + public boolean shouldDrawGui(GuiChest currentScreen) { + ItemStack stack = getItem(BUY_BUTTON_SLOT, currentScreen); + return stack != null && (stack.getItem().equals(Item.getByNameOrId("minecraft:bed")) || stack.getItem().equals(Item.getByNameOrId("minecraft:gold_nugget"))); + } + + public void drawConfirmButton(GuiChest currentScreen) { + drawBox(currentScreen, false, true); + } + + private boolean shouldSkip(GuiScreen screen) { + return !(screen instanceof GuiChest) || CoflSky.config.purchaseOverlay != GUIType.TFM || !EventHandler.isInSkyblock; + } + + @SubscribeEvent + public void onPostRenderEvent(GuiScreenEvent.DrawScreenEvent.Post event) { + if (shouldSkip(event.gui)) { + return; + } + + GuiChest auctionView = (GuiChest) event.gui; + ContainerChest container = (ContainerChest) auctionView.inventorySlots; + String containerName = container.getLowerChestInventory().getDisplayName().getUnformattedText(); + if (containerName.trim().equals("BIN Auction View")) { + drawBuyButton(auctionView); + } else if (containerName.trim().equals("Confirm Purchase")) { + drawConfirmButton(auctionView); + } + } + + private void clickSlot(int windowId, int slot) { + Minecraft.getMinecraft().playerController.windowClick(windowId, + slot, 2, 3, Minecraft.getMinecraft().thePlayer); + } + + private void handleBuyClick(GuiChest currentScreen, GuiScreenEvent.MouseInputEvent.Pre event) { + if (waitingForBed(currentScreen) || !shouldDrawGui(currentScreen)) { + return; + } + event.setCanceled(true); + clickSlot(currentScreen.inventorySlots.windowId, BUY_BUTTON_SLOT); + } + + private void handleConfirmClick(GuiChest currentScreen, int windowId) { + clickSlot(windowId, CONFIRM_BUTTON_SLOT); + } + + private void handlePositiveClick(GuiScreen screen, GuiScreenEvent.MouseInputEvent.Pre event) { + if (shouldSkip(screen)) { + return; + } + + GuiChest auctionView = (GuiChest) screen; + ContainerChest container = (ContainerChest) auctionView.inventorySlots; + String containerName = container.getLowerChestInventory().getDisplayName().getUnformattedText(); + if (containerName.trim().equals("BIN Auction View")) { + handleBuyClick(auctionView, event); + } else if (containerName.trim().equals("Confirm Purchase")) { + handleConfirmClick(auctionView, container.windowId); + event.setCanceled(true); + } + } + + private void doCancelClick(ContainerChest chest, int slotId) { + clickSlot(chest.windowId, slotId); + } + + private void handleCancelClick(GuiScreen screen, GuiScreenEvent.MouseInputEvent.Pre event) { + if (shouldSkip(screen)) { + return; + } + + GuiChest auctionView = (GuiChest) screen; + ContainerChest container = (ContainerChest) auctionView.inventorySlots; + String containerName = container.getLowerChestInventory().getDisplayName().getUnformattedText(); + if (containerName.trim().equals("BIN Auction View")) { + doCancelClick(container, BACK_BUTTON_SLOT); + } else if (containerName.trim().equals("Confirm Purchase")) { + doCancelClick(container, CANCEL_CONFIRM_SLOT); + } else { + return; + } + event.setCanceled(true); + } + + @SubscribeEvent + public void onMouseClicked(GuiScreenEvent.MouseInputEvent.Pre event) { + if (!Mouse.getEventButtonState()) { + return; + } + GuiScreen screen = event.gui; + if (screen == null) { + return; + } + int x = Mouse.getEventX() * screen.width / Minecraft.getMinecraft().displayWidth; + int y = screen.height - Mouse.getEventY() * screen.height / Minecraft.getMinecraft().displayHeight - 1; + if (isInBox(x, y)) { + handlePositiveClick(screen, event); + } else if (isInCancelBox(x, y)) { + handleCancelClick(screen, event); + } + } + +} diff --git a/src/main/java/de/torui/coflsky/gui/tfm/ChatMessageSendHandler.java b/src/main/java/de/torui/coflsky/gui/tfm/ChatMessageSendHandler.java new file mode 100644 index 0000000..da1376e --- /dev/null +++ b/src/main/java/de/torui/coflsky/gui/tfm/ChatMessageSendHandler.java @@ -0,0 +1,32 @@ +package de.torui.coflsky.gui.tfm; + +import de.torui.coflsky.FlipperChatCommand; +import de.torui.coflsky.WSCommandHandler; +import io.netty.channel.*; +import net.minecraft.client.Minecraft; +import net.minecraft.network.play.client.C01PacketChatMessage; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.common.network.FMLNetworkEvent; + +@ChannelHandler.Sharable +public class ChatMessageSendHandler extends ChannelOutboundHandlerAdapter { + @Override + public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) { + if (msg instanceof C01PacketChatMessage) { + if (FlipperChatCommand.useChatOnlyMode) { + String message = ((C01PacketChatMessage) msg).getMessage(); + if (!message.startsWith("/")) { + WSCommandHandler.Execute("/cofl chat " + message, Minecraft.getMinecraft().thePlayer); + return; + } + } + } + ctx.write(msg, promise); + } + + @SubscribeEvent + public void connect(FMLNetworkEvent.ClientConnectedToServerEvent event) { + ChannelPipeline pipeline = event.manager.channel().pipeline(); + pipeline.addBefore("packet_handler", this.getClass().getName(), this); + } +} diff --git a/src/main/java/de/torui/coflsky/gui/tfm/ToolTipHelper.java b/src/main/java/de/torui/coflsky/gui/tfm/ToolTipHelper.java new file mode 100644 index 0000000..34e855e --- /dev/null +++ b/src/main/java/de/torui/coflsky/gui/tfm/ToolTipHelper.java @@ -0,0 +1,55 @@ +package de.torui.coflsky.gui.tfm; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.item.ItemStack; +import net.minecraft.util.EnumChatFormatting; + +import java.util.List; + +public class ToolTipHelper { + Minecraft mc; + ItemStack stack; + List<String> toolTipLines; + FontRenderer font; + + public ToolTipHelper(ItemStack stack) { + mc = Minecraft.getMinecraft(); + this.stack = stack; + toolTipLines = stack.getTooltip(this.mc.thePlayer, this.mc.gameSettings.advancedItemTooltips); + for (int i = 0; i < toolTipLines.size(); ++i) { + if (i == 0) { + toolTipLines.set(i, stack.getRarity().rarityColor + toolTipLines.get(i)); + } else { + toolTipLines.set(i, EnumChatFormatting.GRAY + toolTipLines.get(i)); + } + } + + font = stack.getItem().getFontRenderer(stack); + if (font == null) { + font = mc.fontRendererObj; + } + } + + public int determineWidth() { + int width = 0; + + for (String textLine : toolTipLines) { + int textWidth = font.getStringWidth(textLine); + if (textWidth > width) { + width = textWidth; + } + } + + return width; + } + + public int determineHeight() { + int height = 8; + if (toolTipLines.size() > 1) { + height += (toolTipLines.size() - 1) * 10; + } + return height; + } + +} |