diff options
Diffstat (limited to 'src')
8 files changed, 446 insertions, 20 deletions
diff --git a/src/main/java/de/cowtipper/cowlection/Cowlection.java b/src/main/java/de/cowtipper/cowlection/Cowlection.java index 4aefd5b..e15ab52 100644 --- a/src/main/java/de/cowtipper/cowlection/Cowlection.java +++ b/src/main/java/de/cowtipper/cowlection/Cowlection.java @@ -4,6 +4,7 @@ import de.cowtipper.cowlection.command.MooCommand; import de.cowtipper.cowlection.command.ReplyCommand; import de.cowtipper.cowlection.command.ShrugCommand; import de.cowtipper.cowlection.command.TabCompletableCommand; +import de.cowtipper.cowlection.config.CredentialStorage; import de.cowtipper.cowlection.config.MooConfig; import de.cowtipper.cowlection.handler.DungeonCache; import de.cowtipper.cowlection.handler.FriendsHandler; @@ -40,6 +41,7 @@ public class Cowlection { private File configDir; private File modsDir; private MooConfig config; + private CredentialStorage moo; private FriendsHandler friendsHandler; private VersionChecker versionChecker; private ChatHelper chatHelper; @@ -94,6 +96,10 @@ public class Cowlection { return config; } + public CredentialStorage getMoo() { + return moo; + } + public FriendsHandler getFriendsHandler() { return friendsHandler; } diff --git a/src/main/java/de/cowtipper/cowlection/command/MooCommand.java b/src/main/java/de/cowtipper/cowlection/command/MooCommand.java index 881a446..edbfc62 100644 --- a/src/main/java/de/cowtipper/cowlection/command/MooCommand.java +++ b/src/main/java/de/cowtipper/cowlection/command/MooCommand.java @@ -150,8 +150,8 @@ public class MooCommand extends CommandBase { //region sub commands: Best friends, friends & other players private void handleStalking(String[] args) throws CommandException { - if (!Utils.isValidUuid(MooConfig.moo)) { - throw new MooCommandException("You haven't set your Hypixel API key yet. Use " + EnumChatFormatting.DARK_RED + "/api new" + EnumChatFormatting.RED + " to request a new API key from Hypixel or use " + EnumChatFormatting.DARK_RED + "/" + this.getCommandName() + " apikey <key>" + EnumChatFormatting.RED + " to manually set your existing API key."); + if (!CredentialStorage.isMooValid) { + throw new MooCommandException("You haven't set your Hypixel API key yet or the API key is invalid. Use " + EnumChatFormatting.DARK_RED + "/api new" + EnumChatFormatting.RED + " to request a new API key from Hypixel or use " + EnumChatFormatting.DARK_RED + "/" + this.getCommandName() + " apikey <key>" + EnumChatFormatting.RED + " to manually set your existing API key."); } if (args.length != 2) { throw new WrongUsageException("/" + getCommandName() + " stalk <playerName>"); @@ -302,8 +302,8 @@ public class MooCommand extends CommandBase { //region sub commands: SkyBlock private void handleStalkingSkyBlock(String[] args) throws CommandException { - if (!Utils.isValidUuid(MooConfig.moo)) { - throw new MooCommandException("You haven't set your Hypixel API key yet. Use " + EnumChatFormatting.DARK_RED + "/api new" + EnumChatFormatting.RED + " to request a new API key from Hypixel or use " + EnumChatFormatting.DARK_RED + "/" + this.getCommandName() + " apikey <key>" + EnumChatFormatting.RED + " to manually set your existing API key."); + if (!CredentialStorage.isMooValid) { + throw new MooCommandException("You haven't set your Hypixel API key yet or the API key is invalid. Use " + EnumChatFormatting.DARK_RED + "/api new" + EnumChatFormatting.RED + " to request a new API key from Hypixel or use " + EnumChatFormatting.DARK_RED + "/" + this.getCommandName() + " apikey <key>" + EnumChatFormatting.RED + " to manually set your existing API key."); } if (args.length != 2) { throw new WrongUsageException("/" + getCommandName() + " skyblockstalk <playerName>"); @@ -480,7 +480,11 @@ public class MooCommand extends CommandBase { main.getChatHelper().sendMessage(sbStats); } else { String cause = (hySBStalking != null) ? hySBStalking.getCause() : null; - throw new ApiContactException("Hypixel", "couldn't stalk " + EnumChatFormatting.DARK_RED + stalkedPlayer.getName() + EnumChatFormatting.RED + (cause != null ? " (Reason: " + EnumChatFormatting.DARK_RED + cause + EnumChatFormatting.RED + ")" : "") + "."); + String reason = ""; + if (cause != null) { + reason = " (Reason: " + EnumChatFormatting.DARK_RED + cause + EnumChatFormatting.RED + ")"; + } + throw new ApiContactException("Hypixel", "couldn't stalk " + EnumChatFormatting.DARK_RED + stalkedPlayer.getName() + EnumChatFormatting.RED + reason + "."); } }); } @@ -603,7 +607,7 @@ public class MooCommand extends CommandBase { String firstSentence; EnumChatFormatting color; EnumChatFormatting colorSecondary; - if (Utils.isValidUuid(MooConfig.moo)) { + if (CredentialStorage.isMooValid) { firstSentence = "You already set your Hypixel API key."; color = EnumChatFormatting.GREEN; colorSecondary = EnumChatFormatting.DARK_GREEN; @@ -616,9 +620,8 @@ public class MooCommand extends CommandBase { } else { String key = args[1]; if (Utils.isValidUuid(key)) { - MooConfig.moo = key; - main.getConfig().syncFromFields(); - main.getChatHelper().sendMessage(EnumChatFormatting.GREEN, "Updated API key!"); + main.getChatHelper().sendMessage(EnumChatFormatting.YELLOW, "Validating API key..."); + main.getMoo().setMooIfValid(key, true); } else { throw new SyntaxErrorException("That doesn't look like a valid API key..."); } diff --git a/src/main/java/de/cowtipper/cowlection/config/CredentialStorage.java b/src/main/java/de/cowtipper/cowlection/config/CredentialStorage.java new file mode 100644 index 0000000..c7cf35f --- /dev/null +++ b/src/main/java/de/cowtipper/cowlection/config/CredentialStorage.java @@ -0,0 +1,73 @@ +package de.cowtipper.cowlection.config; + +import de.cowtipper.cowlection.Cowlection; +import de.cowtipper.cowlection.util.ApiUtils; +import de.cowtipper.cowlection.util.Utils; +import net.minecraft.util.EnumChatFormatting; +import net.minecraftforge.common.config.Configuration; +import net.minecraftforge.common.config.Property; + +/** + * Key and secret holder in its own file to avoid people leaking their keys accidentally. + */ +public class CredentialStorage { + public static String moo; + public static boolean isMooValid; + private Property propMoo; + private Property propIsMooValid; + private final Configuration cfg; + + public CredentialStorage(Configuration configuration) { + cfg = configuration; + initConfig(); + } + + private void initConfig() { + cfg.load(); + propMoo = cfg.get(Configuration.CATEGORY_CLIENT, + "moo", "", "Don't share this with anybody! Do not edit this entry manually either!", Utils.VALID_UUID_PATTERN) + .setShowInGui(false); + propMoo.setLanguageKey(Cowlection.MODID + ".config." + propMoo.getName()); + + propIsMooValid = cfg.get(Configuration.CATEGORY_CLIENT, + "isMooValid", false, "Is the value valid?") + .setShowInGui(false); + moo = propMoo.getString(); + isMooValid = propIsMooValid.getBoolean(); + if (cfg.hasChanged()) { + cfg.save(); + } + } + + public void setMooIfValid(String moo, boolean commandTriggered) { + ApiUtils.fetchApiKeyInfo(moo, hyApiKey -> { + if (hyApiKey != null && hyApiKey.isSuccess()) { + // api key is valid! + Cowlection.getInstance().getMoo().setMoo(moo); + if (commandTriggered) { + Cowlection.getInstance().getChatHelper().sendMessage(EnumChatFormatting.GREEN, "Successfully verified API key ✔"); + } + } else if (commandTriggered) { + // api key is invalid + String cause = hyApiKey != null ? hyApiKey.getCause() : null; + Cowlection.getInstance().getChatHelper().sendMessage(EnumChatFormatting.RED, "Failed to verify API key: " + (cause != null ? cause : "unknown cause :c")); + } + }); + } + + private void setMoo(String moo) { + CredentialStorage.moo = moo; + propMoo.set(moo); + setMooValidity(true); + } + + public void setMooValidity(boolean isMooValid) { + CredentialStorage.isMooValid = isMooValid; + propIsMooValid.set(isMooValid); + cfg.save(); + } + + public Property getPropIsMooValid() { + return propIsMooValid; + } +} diff --git a/src/main/java/de/cowtipper/cowlection/config/MooConfigCategory.java b/src/main/java/de/cowtipper/cowlection/config/MooConfigCategory.java new file mode 100644 index 0000000..ea2eb37 --- /dev/null +++ b/src/main/java/de/cowtipper/cowlection/config/MooConfigCategory.java @@ -0,0 +1,145 @@ +package de.cowtipper.cowlection.config; + +import de.cowtipper.cowlection.Cowlection; +import de.cowtipper.cowlection.config.gui.MooConfigPreview; +import net.minecraft.util.EnumChatFormatting; +import net.minecraftforge.common.config.Property; +import net.minecraftforge.fml.client.config.GuiSlider; + +import java.util.*; + +/** + * A config category, contains elements and logic for one specific config category + */ +public class MooConfigCategory { + private final String displayName; + private final String configName; + private String menuDisplayName; + private final List<SubCategory> subCategories; + + public MooConfigCategory(String displayName, String configName) { + this.displayName = displayName; + this.configName = configName; + this.menuDisplayName = displayName; + subCategories = new ArrayList<>(); + } + + public void setMenuDisplayName(String menuDisplayName) { + this.menuDisplayName = menuDisplayName; + } + + public String getDisplayName() { + return displayName; + } + + public String getConfigName() { + return this.configName; + } + + public String getMenuDisplayName() { + return menuDisplayName; + } + + public List<SubCategory> getSubCategories() { + return subCategories; + } + + public SubCategory addSubCategory(String subCatName) { + SubCategory subCategory = new SubCategory(subCatName); + subCategories.add(subCategory); + return subCategory; + } + + + public static class SubCategory { + private final String displayName; + private final List<String> explanations = new ArrayList<>(); + private final List<Property> configEntries = new ArrayList<>(); + private final Map<String, GuiSliderExtra> guiSliderExtras = new HashMap<>(); + /** + * Index 0: preview for sub category + * Index >0: preview for one specific property + */ + private final Map<Integer, MooConfigPreview> previews = new HashMap<>(); + + public SubCategory(String subCatName) { + this.displayName = subCatName; + } + + public Property addConfigEntry(Property configEntry, MooConfigPreview configEntryPreview) { + Property property = addConfigEntry(configEntry); + addPropertyPreview(property, configEntryPreview); + return property; + } + + public Property addConfigEntry(Property property, String prefix, String suffix, GuiSlider.ISlider onChangeSliderValue) { + guiSliderExtras.put(property.getLanguageKey(), new GuiSliderExtra(prefix, suffix, onChangeSliderValue)); + return addConfigEntry(property); + } + + public Property addConfigEntry(Property configEntry) { + configEntry.setLanguageKey(Cowlection.MODID + ".config." + configEntry.getName()); + configEntries.add(configEntry); + return configEntry; + } + + public void addPropertyPreview(Property property, MooConfigPreview preview) { + int propId = configEntries.indexOf(property); + if (propId > -1) { + this.previews.put(propId + 1, preview); + } + } + + public void addExplanations(String... explanations) { + if (this.explanations.isEmpty()) { + // first line is only used for the explanations tooltips, not for in-text: + this.explanations.add(EnumChatFormatting.DARK_GREEN + "❢ " + EnumChatFormatting.GOLD + EnumChatFormatting.BOLD + displayName); + } + this.explanations.addAll(Arrays.asList(explanations)); + } + + public String getDisplayName() { + return displayName; + } + + public List<String> getExplanations() { + return explanations; + } + + public List<Property> getConfigEntries() { + return configEntries; + } + + public GuiSliderExtra getGuiSliderExtra(String propertyKey) { + return guiSliderExtras.get(propertyKey); + } + + public Map<Integer, MooConfigPreview> getPreviews() { + return previews; + } + + public static class GuiSliderExtra { + private final String prefix; + private final String suffix; + private final GuiSlider.ISlider onChangeSliderValue; + + public GuiSliderExtra(String prefix, String suffix, GuiSlider.ISlider onChangeSliderValue) { + this.prefix = prefix; + this.suffix = suffix; + this.onChangeSliderValue = onChangeSliderValue; + } + + public String getPrefix() { + return prefix != null ? prefix : ""; + } + + public String getSuffix() { + return suffix != null ? suffix : ""; + } + + public GuiSlider.ISlider getOnChangeSliderValue() { + return onChangeSliderValue; + } + } + } +} diff --git a/src/main/java/de/cowtipper/cowlection/listener/ChatListener.java b/src/main/java/de/cowtipper/cowlection/listener/ChatListener.java index e2d2316..318907d 100644 --- a/src/main/java/de/cowtipper/cowlection/listener/ChatListener.java +++ b/src/main/java/de/cowtipper/cowlection/listener/ChatListener.java @@ -87,9 +87,8 @@ public class ChatListener { // Your new API key is 00000000-0000-0000-0000-000000000000 String moo = text.substring(20, 56); if (Utils.isValidUuid(moo)) { - MooConfig.moo = moo; - main.getConfig().syncFromFields(); - main.getChatHelper().sendMessage(EnumChatFormatting.GREEN, "Saved your API key in " + Cowlection.MODNAME + " config!"); + main.getChatHelper().sendMessage(EnumChatFormatting.YELLOW, "Verifying the new API key..."); + main.getMoo().setMooIfValid(moo, true); } } } diff --git a/src/main/java/de/cowtipper/cowlection/util/ApiUtils.java b/src/main/java/de/cowtipper/cowlection/util/ApiUtils.java index 442c940..03e4a14 100644 --- a/src/main/java/de/cowtipper/cowlection/util/ApiUtils.java +++ b/src/main/java/de/cowtipper/cowlection/util/ApiUtils.java @@ -6,11 +6,8 @@ import com.google.gson.JsonSyntaxException; import com.mojang.util.UUIDTypeAdapter; import de.cowtipper.cowlection.Cowlection; import de.cowtipper.cowlection.command.exception.ThrowingConsumer; -import de.cowtipper.cowlection.config.MooConfig; -import de.cowtipper.cowlection.data.Friend; -import de.cowtipper.cowlection.data.HyPlayerData; -import de.cowtipper.cowlection.data.HySkyBlockStats; -import de.cowtipper.cowlection.data.HyStalkingData; +import de.cowtipper.cowlection.config.CredentialStorage; +import de.cowtipper.cowlection.data.*; import de.cowtipper.cowlection.event.ApiErrorEvent; import net.minecraftforge.common.MinecraftForge; import org.apache.http.HttpStatus; @@ -79,7 +76,7 @@ public class ApiUtils { } private static HyStalkingData stalkPlayer(Friend friend) { - try (BufferedReader reader = makeApiCall(String.format(ONLINE_STATUS_URL, MooConfig.moo, UUIDTypeAdapter.fromUUID(friend.getUuid())))) { + try (BufferedReader reader = makeApiCall(String.format(ONLINE_STATUS_URL, CredentialStorage.moo, UUIDTypeAdapter.fromUUID(friend.getUuid())))) { if (reader != null) { return GsonUtils.fromJson(reader, HyStalkingData.class); } @@ -94,7 +91,7 @@ public class ApiUtils { } private static HySkyBlockStats stalkSkyBlockStats(Friend friend) { - try (BufferedReader reader = makeApiCall(String.format(SKYBLOCK_STATS_URL, MooConfig.moo, UUIDTypeAdapter.fromUUID(friend.getUuid())))) { + try (BufferedReader reader = makeApiCall(String.format(SKYBLOCK_STATS_URL, CredentialStorage.moo, UUIDTypeAdapter.fromUUID(friend.getUuid())))) { if (reader != null) { return GsonUtils.fromJson(reader, HySkyBlockStats.class); } @@ -109,7 +106,7 @@ public class ApiUtils { } private static HyPlayerData stalkHyPlayer(Friend stalkedPlayer) { - try (BufferedReader reader = makeApiCall(String.format(PLAYER_URL, MooConfig.moo, UUIDTypeAdapter.fromUUID(stalkedPlayer.getUuid())))) { + try (BufferedReader reader = makeApiCall(String.format(PLAYER_URL, CredentialStorage.moo, UUIDTypeAdapter.fromUUID(stalkedPlayer.getUuid())))) { if (reader != null) { return GsonUtils.fromJson(reader, HyPlayerData.class); } diff --git a/src/main/java/de/cowtipper/cowlection/util/GuiHelper.java b/src/main/java/de/cowtipper/cowlection/util/GuiHelper.java new file mode 100644 index 0000000..a80b1ba --- /dev/null +++ b/src/main/java/de/cowtipper/cowlection/util/GuiHelper.java @@ -0,0 +1,198 @@ +package de.cowtipper.cowlection.util; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.gui.Gui; +import net.minecraft.client.gui.GuiScreen; +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.minecraftforge.common.ForgeVersion; +import net.minecraftforge.fml.client.config.GuiUtils; + +import java.util.ArrayList; +import java.util.List; + +public final class GuiHelper extends GuiScreen { + private static GuiHelper instance; + + private GuiHelper() { + this.mc = Minecraft.getMinecraft(); + this.fontRendererObj = mc.fontRendererObj; + this.itemRender = mc.getRenderItem(); + } + + private static GuiHelper getInstance() { + if (instance == null) { + instance = new GuiHelper(); + } + return instance; + } + + /** + * Draw a 1 pixel wide horizontal line. Args: startX, endX, y, color + */ + public static void drawThinHorizontalLine(int startX, int endX, int y, int color) { + if (endX < startX) { + int i = startX; + startX = endX; + endX = i; + } + GlStateManager.pushMatrix(); + int scaleDivisor = 2; + GlStateManager.scale(1f / scaleDivisor, 1f / scaleDivisor, 0); + Gui.drawRect(startX * scaleDivisor, y * scaleDivisor, (endX + 1) * scaleDivisor, y * scaleDivisor + 1, color); + GlStateManager.popMatrix(); + } + + /** + * Draws a sprite from assets/textures/gui/container/stats_icons.png + * <p> + * from: GuiStats#drawSprite + */ + public static void drawSprite(int x, int y, int width, int height, float zLevel) { + GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); + Minecraft.getMinecraft().getTextureManager().bindTexture(statIcons); + float magicNumber = 0.0078125F; + int iconSize = 18; + Tessellator tessellator = Tessellator.getInstance(); + WorldRenderer worldrenderer = tessellator.getWorldRenderer(); + worldrenderer.begin(7, DefaultVertexFormats.POSITION_TEX); + worldrenderer.pos(x, y + iconSize, zLevel).tex((float) (width) * magicNumber, (float) (height + iconSize) * magicNumber).endVertex(); + worldrenderer.pos(x + iconSize, y + iconSize, zLevel).tex((float) (width + iconSize) * magicNumber, (float) (height + iconSize) * magicNumber).endVertex(); + worldrenderer.pos(x + iconSize, y, zLevel).tex((float) (width + iconSize) * magicNumber, (float) (height) * magicNumber).endVertex(); + worldrenderer.pos(x, y, zLevel).tex((float) (width) * magicNumber, (float) (height) * magicNumber).endVertex(); + tessellator.draw(); + } + + public static void drawHoveringText(List<String> textLines, int mouseX, int mouseY, int screenWidth, int screenHeight, int maxTextWidth) { + if (ForgeVersion.getBuildVersion() < 1808) { + // we're running a forge version from before 24 March 2016 (http://files.minecraftforge.net/maven/net/minecraftforge/forge/index_1.8.9.html for reference) + // using mc built-in method + getInstance().width = screenWidth; + getInstance().height = screenHeight; + drawHoveringText(textLines, mouseX, mouseY, screenWidth, screenHeight, maxTextWidth, getInstance().fontRendererObj); + } else { + // we're on a newer forge version, so we can use the improved tooltip rendering directly added in 1.8.9-11.15.1.1808 (released 03/24/16 09:25 PM) in this pull request: https://github.com/MinecraftForge/MinecraftForge/pull/2649 + GuiUtils.drawHoveringText(textLines, mouseX, mouseY, screenWidth, screenHeight, maxTextWidth, getInstance().fontRendererObj); + } + } + + /** + * Fixed method for forge versions older than 1.8.9-11.15.1.1808 + * + * @see GuiUtils#drawHoveringText + */ + 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 + 12; + 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<>(); + 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 - 12; + 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; + Gui.drawRect(tooltipX - 3, tooltipY - 4, tooltipX + tooltipTextWidth + 3, tooltipY - 3, backgroundColor); + Gui.drawRect(tooltipX - 3, tooltipY + tooltipHeight + 3, tooltipX + tooltipTextWidth + 3, tooltipY + tooltipHeight + 4, backgroundColor); + Gui.drawRect(tooltipX - 3, tooltipY - 3, tooltipX + tooltipTextWidth + 3, tooltipY + tooltipHeight + 3, backgroundColor); + Gui.drawRect(tooltipX - 4, tooltipY - 3, tooltipX - 3, tooltipY + tooltipHeight + 3, backgroundColor); + Gui.drawRect(tooltipX + tooltipTextWidth + 3, tooltipY - 3, tooltipX + tooltipTextWidth + 4, tooltipY + tooltipHeight + 3, backgroundColor); + final int borderColorStart = 0x505000FF; + final int borderColorEnd = (borderColorStart & 0xFEFEFE) >> 1 | borderColorStart & 0xFF000000; + Gui.drawRect(tooltipX - 3, tooltipY - 3 + 1, tooltipX - 3 + 1, tooltipY + tooltipHeight + 3 - 1, borderColorStart); + Gui.drawRect(tooltipX + tooltipTextWidth + 2, tooltipY - 3 + 1, tooltipX + tooltipTextWidth + 3, tooltipY + tooltipHeight + 3 - 1, borderColorStart); + Gui.drawRect(tooltipX - 3, tooltipY - 3, tooltipX + tooltipTextWidth + 3, tooltipY - 3 + 1, borderColorStart); + Gui.drawRect(tooltipX - 3, tooltipY + tooltipHeight + 2, tooltipX + tooltipTextWidth + 3, tooltipY + tooltipHeight + 3, 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(); + } + } +} diff --git a/src/main/java/de/cowtipper/cowlection/util/Utils.java b/src/main/java/de/cowtipper/cowlection/util/Utils.java index 24e6b7b..3cf77b5 100644 --- a/src/main/java/de/cowtipper/cowlection/util/Utils.java +++ b/src/main/java/de/cowtipper/cowlection/util/Utils.java @@ -250,4 +250,9 @@ public final class Utils { } return tierColor; } + + + public static String booleanToSymbol(boolean value) { + return value ? EnumChatFormatting.GREEN + "✔" : EnumChatFormatting.RED + "✘"; + } } |