diff options
author | ThatGravyBoat <thatgravyboat@gmail.com> | 2021-07-06 15:10:29 -0230 |
---|---|---|
committer | ThatGravyBoat <thatgravyboat@gmail.com> | 2021-07-06 15:10:29 -0230 |
commit | 6d8e1e5659f64a4f9ba86d6ab5bbc8e688faf22a (patch) | |
tree | 7451e53ceeae3c324d83a7faba83ce80005e6f23 /src/main/java/com/thatgravyboat/skyblockhud | |
download | SkyblockHud-Death-Defied-6d8e1e5659f64a4f9ba86d6ab5bbc8e688faf22a.tar.gz SkyblockHud-Death-Defied-6d8e1e5659f64a4f9ba86d6ab5bbc8e688faf22a.tar.bz2 SkyblockHud-Death-Defied-6d8e1e5659f64a4f9ba86d6ab5bbc8e688faf22a.zip |
Initial Commit
Diffstat (limited to 'src/main/java/com/thatgravyboat/skyblockhud')
93 files changed, 9250 insertions, 0 deletions
diff --git a/src/main/java/com/thatgravyboat/skyblockhud/ComponentBuilder.java b/src/main/java/com/thatgravyboat/skyblockhud/ComponentBuilder.java new file mode 100644 index 0000000..e5299d5 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/ComponentBuilder.java @@ -0,0 +1,55 @@ +package com.thatgravyboat.skyblockhud; + +public class ComponentBuilder { + + public StringBuilder builder; + + public ComponentBuilder(){ + this.builder = new StringBuilder(); + } + + public ComponentBuilder apd(String text) { + return apd(text, '7'); + } + + public ComponentBuilder apd(String text, char[] colors) { + for (char color: colors) { + builder.append("\u00A7").append(color); + } + builder.append(text).append("\u00A7").append('r'); + return this; + } + + public ComponentBuilder apd(String text, char color) { + builder.append("\u00A7").append(color).append(text).append("\u00A7").append('r'); + return this; + } + + public ComponentBuilder nl(){ + builder.append("\n"); + return this; + } + + public ComponentBuilder nl(String text, char color){ + apd(text, color); + builder.append("\n"); + return this; + } + + public ComponentBuilder nl(String text, char[] colors){ + apd(text, colors); + builder.append("\n"); + return this; + } + + public ComponentBuilder nl(String text){ + apd(text); + builder.append("\n"); + return this; + } + + public String build() { + return builder.toString(); + } + +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/ComponentHandler.java b/src/main/java/com/thatgravyboat/skyblockhud/ComponentHandler.java new file mode 100644 index 0000000..3c671f0 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/ComponentHandler.java @@ -0,0 +1,124 @@ +package com.thatgravyboat.skyblockhud; + +import com.google.common.collect.ComparisonChain; +import com.google.common.collect.Ordering; +import com.thatgravyboat.skyblockhud.dungeons.DungeonHandler; +import com.thatgravyboat.skyblockhud.location.*; +import com.thatgravyboat.skyblockhud.seasons.SeasonDateHandler; +import net.minecraft.client.Minecraft; +import net.minecraft.client.network.NetworkPlayerInfo; +import net.minecraft.scoreboard.ScorePlayerTeam; +import net.minecraft.world.WorldSettings; +import net.minecraftforge.client.GuiIngameForge; +import net.minecraftforge.client.event.ClientChatReceivedEvent; +import net.minecraftforge.fml.common.eventhandler.EventPriority; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.common.gameevent.TickEvent; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +import java.util.Comparator; +import java.util.List; +import java.util.regex.Pattern; + +public class ComponentHandler { + public static final Pattern SCOREBOARD_CHARACTERS = Pattern.compile("[^]\\[a-z A-Z:0-9/'.()+\\d-ยง?]"); + private static final Ordering<NetworkPlayerInfo> sortingList = Ordering.from(new PlayerComparator()); + private static int ticksExisted = 0; + + @SubscribeEvent + public void onClientTick(TickEvent.ClientTickEvent event){ + Minecraft mc = Minecraft.getMinecraft(); + ticksExisted++; + boolean eventPass = false; + if (mc.theWorld != null) { + List<NetworkPlayerInfo> players = sortingList.sortedCopy(mc.thePlayer.sendQueue.getPlayerInfoMap()); + GuiIngameForge.renderObjective = !SkyblockHud.hasSkyblockScoreboard() || !SkyblockHud.config.misc.hideScoreboard; + if (players != null && SkyblockHud.hasSkyblockScoreboard()){ + + if (ticksExisted % 60 == 0) { + for (NetworkPlayerInfo player : players) { + if (player.getDisplayName() != null) { + String formattedTabListPlayer = SCOREBOARD_CHARACTERS.matcher(Utils.removeColor(player.getDisplayName().getFormattedText())).replaceAll(""); + if (LocationHandler.getCurrentLocation().equals(Locations.CATACOMBS)) { + if (formattedTabListPlayer.toLowerCase().contains("secrets found:")) + DungeonHandler.parseTotalSecrets(formattedTabListPlayer); + if (formattedTabListPlayer.toLowerCase().contains("deaths:")) + DungeonHandler.parseDeaths(formattedTabListPlayer); + if (formattedTabListPlayer.toLowerCase().contains("crypts:")) + DungeonHandler.parseCrypts(formattedTabListPlayer); + }else if (LocationHandler.getCurrentLocation().getCategory().equals(LocationCategory.DWARVENMINES)){ + if (formattedTabListPlayer.toLowerCase().contains("mithril powder:")){ + DwarvenMineHandler.parseMithril(formattedTabListPlayer); + } + }else if (LocationHandler.getCurrentLocation().getCategory().equals(LocationCategory.MUSHROOMDESERT)){ + if (formattedTabListPlayer.toLowerCase().contains("pelts:")){ + try { + FarmingIslandHandler.pelts = Integer.parseInt(formattedTabListPlayer.toLowerCase().replace("pelts:","").trim()); + }catch (Exception ignored){} + } + } + } + } + if (players.size() > 80) { + for (int i = 61; i <= 80; i++) { + if (players.get(i).getDisplayName() != null) { + String formattedTabListPlayer = SCOREBOARD_CHARACTERS.matcher(Utils.removeColor(players.get(i).getDisplayName().getFormattedText())).replaceAll(""); + if (formattedTabListPlayer.toLowerCase().contains("event:")) { + if (i < 80) { + if (players.get(i + 1).getDisplayName() != null) { + String secondLine = SCOREBOARD_CHARACTERS.matcher(Utils.removeColor(players.get(i + 1).getDisplayName().getFormattedText())).replaceAll(""); + SeasonDateHandler.setCurrentEvent(formattedTabListPlayer.replace("Event:", ""), secondLine); + eventPass = true; + } + } + } + } + if (i == 80 && !eventPass) { + SeasonDateHandler.setCurrentEvent("", ""); + } + } + } + } + if (LocationHandler.getCurrentLocation().getCategory().equals(LocationCategory.PARK)) { + if (players.size() >= 80) { + for (int i = 41; i <= 60; i++) { + if (players.get(i).getDisplayName() != null) { + String formattedTabListPlayer = SCOREBOARD_CHARACTERS.matcher(Utils.removeColor(players.get(i).getDisplayName().getFormattedText())).replaceAll(""); + if (LocationHandler.getCurrentLocation().getCategory().equals(LocationCategory.PARK)) { + if (formattedTabListPlayer.toLowerCase().contains("rain:")) { + ParkIslandHandler.parseRain(formattedTabListPlayer.toLowerCase()); + } + } + } + } + } + }else if (ParkIslandHandler.isRaining()) { + ParkIslandHandler.parseRain(null); + } + } + } + } + + @SubscribeEvent(priority = EventPriority.HIGHEST) + public void onStatusBar(ClientChatReceivedEvent event){ + if (event.type == 2){ + if (LocationHandler.getCurrentLocation().equals(Locations.CATACOMBS)) DungeonHandler.parseSecrets(event.message.getFormattedText()); + } + } + + @SideOnly(Side.CLIENT) + static class PlayerComparator implements Comparator<NetworkPlayerInfo> + { + private PlayerComparator() + { + } + + public int compare(NetworkPlayerInfo p_compare_1_, NetworkPlayerInfo p_compare_2_) + { + ScorePlayerTeam scoreplayerteam = p_compare_1_.getPlayerTeam(); + ScorePlayerTeam scoreplayerteam1 = p_compare_2_.getPlayerTeam(); + return ComparisonChain.start().compareTrueFirst(p_compare_1_.getGameType() != WorldSettings.GameType.SPECTATOR, p_compare_2_.getGameType() != WorldSettings.GameType.SPECTATOR).compare(scoreplayerteam != null ? scoreplayerteam.getRegisteredName() : "", scoreplayerteam1 != null ? scoreplayerteam1.getRegisteredName() : "").compare(p_compare_1_.getGameProfile().getName(), p_compare_2_.getGameProfile().getName()).result(); + } + } +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/GuiTextures.java b/src/main/java/com/thatgravyboat/skyblockhud/GuiTextures.java new file mode 100644 index 0000000..435c2a5 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/GuiTextures.java @@ -0,0 +1,37 @@ +package com.thatgravyboat.skyblockhud; + +import net.minecraft.util.ResourceLocation; + +public class GuiTextures { + + private GuiTextures() {} + + public static final ResourceLocation DISCORD = new ResourceLocation("skyblockhud:discord.png"); + public static final ResourceLocation TWITTER = new ResourceLocation("skyblockhud:twitter.png"); + + public static final ResourceLocation button_tex = new ResourceLocation("skyblockhud:button.png"); + + public static final ResourceLocation button_white = new ResourceLocation("skyblockhud:button_white.png"); + + public static final ResourceLocation BAR = new ResourceLocation("skyblockhud:core/bar.png"); + public static final ResourceLocation OFF = new ResourceLocation("skyblockhud:core/toggle_off.png"); + public static final ResourceLocation ONE = new ResourceLocation("skyblockhud:core/toggle_1.png"); + public static final ResourceLocation TWO = new ResourceLocation("skyblockhud:core/toggle_2.png"); + public static final ResourceLocation THREE = new ResourceLocation("skyblockhud:core/toggle_3.png"); + public static final ResourceLocation ON = new ResourceLocation("skyblockhud:core/toggle_on.png"); + + public static final ResourceLocation slider_off_cap = new ResourceLocation("skyblockhud:core/slider/slider_off_cap.png"); + public static final ResourceLocation slider_off_notch = new ResourceLocation("skyblockhud:core/slider/slider_off_notch.png"); + public static final ResourceLocation slider_off_segment = new ResourceLocation("skyblockhud:core/slider/slider_off_segment.png"); + public static final ResourceLocation slider_on_cap = new ResourceLocation("skyblockhud:core/slider/slider_on_cap.png"); + public static final ResourceLocation slider_on_notch = new ResourceLocation("skyblockhud:core/slider/slider_on_notch.png"); + public static final ResourceLocation slider_on_segment = new ResourceLocation("skyblockhud:core/slider/slider_on_segment.png"); + public static final ResourceLocation slider_button_new = new ResourceLocation("skyblockhud:core/slider/slider_button.png"); + + public static final ResourceLocation overlay = new ResourceLocation("skyblockhud","stats.png"); + public static final ResourceLocation dungeon = new ResourceLocation("skyblockhud","dungeon.png"); + public static final ResourceLocation playerStat = new ResourceLocation("skyblockhud","playerstats.png"); + public static final ResourceLocation bars = new ResourceLocation("skyblockhud","bars.png"); + public static final ResourceLocation mapOverlay = new ResourceLocation("skyblockhud","maps/map_overlay.png"); + +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/SkyblockHud.java b/src/main/java/com/thatgravyboat/skyblockhud/SkyblockHud.java new file mode 100644 index 0000000..a31889e --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/SkyblockHud.java @@ -0,0 +1,195 @@ +package com.thatgravyboat.skyblockhud; + +import com.google.common.collect.Sets; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.thatgravyboat.skyblockhud.api.LeaderboardGetter; +import com.thatgravyboat.skyblockhud.api.events.ProfileSwitchedEvent; +import com.thatgravyboat.skyblockhud.commands.Commands; +import com.thatgravyboat.skyblockhud.config.KeyBindings; +import com.thatgravyboat.skyblockhud.config.SBHConfig; +import com.thatgravyboat.skyblockhud.dungeons.DungeonHandler; +import com.thatgravyboat.skyblockhud.handlers.*; +import com.thatgravyboat.skyblockhud.location.DwarvenMineHandler; +import com.thatgravyboat.skyblockhud.location.FarmingIslandHandler; +import com.thatgravyboat.skyblockhud.location.IslandHandler; +import com.thatgravyboat.skyblockhud.location.LocationHandler; +import com.thatgravyboat.skyblockhud.overlay.DungeonOverlay; +import com.thatgravyboat.skyblockhud.overlay.OverlayHud; +import com.thatgravyboat.skyblockhud.overlay.RPGHud; +import com.thatgravyboat.skyblockhud.playerstats.ActionBarParsing; +import com.thatgravyboat.skyblockhud.seasons.SeasonDateHandler; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiScreen; +import net.minecraft.scoreboard.ScoreObjective; +import net.minecraft.scoreboard.Scoreboard; +import net.minecraftforge.client.event.ClientChatReceivedEvent; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.event.entity.player.ItemTooltipEvent; +import net.minecraftforge.fml.client.registry.ClientRegistry; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.Mod.EventHandler; +import net.minecraftforge.fml.common.event.FMLPostInitializationEvent; +import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; +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.Keyboard; + +import java.awt.*; +import java.awt.datatransfer.StringSelection; +import java.io.*; +import java.nio.charset.StandardCharsets; +import java.util.Set; + +@Mod(modid = SkyblockHud.MODID, version = SkyblockHud.VERSION) +public class SkyblockHud +{ + public static final String MODID = "skyblockhud"; + public static final String VERSION = "1.12"; + + public static SBHConfig config; + + private File configFile; + + private static final Set<String> SKYBLOCK_IN_ALL_LANGUAGES = Sets.newHashSet("SKYBLOCK","\u7A7A\u5C9B\u751F\u5B58"); + + private final Gson gson = new GsonBuilder().setPrettyPrinting().excludeFieldsWithoutExposeAnnotation().create(); + + private static File configDirectory; + + @EventHandler + public void preInit(FMLPreInitializationEvent event){ + MinecraftForge.EVENT_BUS.register(this); + MinecraftForge.EVENT_BUS.register(new LeaderboardGetter()); + MinecraftForge.EVENT_BUS.register(new SeasonDateHandler()); + MinecraftForge.EVENT_BUS.register(new LocationHandler()); + MinecraftForge.EVENT_BUS.register(new IslandHandler()); + MinecraftForge.EVENT_BUS.register(new TimeHandler()); + MinecraftForge.EVENT_BUS.register(new CurrencyHandler()); + MinecraftForge.EVENT_BUS.register(new SlayerHandler()); + MinecraftForge.EVENT_BUS.register(new DungeonHandler()); + MinecraftForge.EVENT_BUS.register(new DwarvenMineHandler()); + MinecraftForge.EVENT_BUS.register(new FarmingIslandHandler()); + + /* DISABLE UNTIL NEW SYSTEM + MinecraftForge.EVENT_BUS.register(new TrackerHandler()); + MinecraftForge.EVENT_BUS.register(new KillTrackerHandler()); + */ + MinecraftForge.EVENT_BUS.register(new HeldItemHandler()); + + ClientRegistry.registerKeyBinding(KeyBindings.map); + + MinecraftForge.EVENT_BUS.register(new ComponentHandler()); + MinecraftForge.EVENT_BUS.register(new ActionBarParsing()); + Commands.init(); + + configFile = new File(event.getModConfigurationDirectory(), "sbh-config.json"); + + if(configFile.exists()) { + try(BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(configFile), StandardCharsets.UTF_8))) { + config = gson.fromJson(reader, SBHConfig.class); + } catch(Exception ignored) { } + } + + + if(config == null) { + config = new SBHConfig(); + saveConfig(); + } + + configDirectory = event.getModConfigurationDirectory(); + + Runtime.getRuntime().addShutdownHook(new Thread(this::saveConfig)); + //Runtime.getRuntime().addShutdownHook(new Thread(() -> TrackerFileLoader.saveTrackerStatsFile(event.getModConfigurationDirectory()))); + } + + public void saveConfig() { + try { + configFile.createNewFile(); + + try(BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(configFile), StandardCharsets.UTF_8))) { + writer.write(gson.toJson(config)); + } + } catch(IOException ignored) {} + } + + @EventHandler + public void postInit(FMLPostInitializationEvent event){ + MinecraftForge.EVENT_BUS.register(new OverlayHud()); + MinecraftForge.EVENT_BUS.register(new RPGHud()); + MinecraftForge.EVENT_BUS.register(new DungeonOverlay()); + MinecraftForge.EVENT_BUS.register(new BossbarHandler()); + MinecraftForge.EVENT_BUS.register(new MapHandler()); + } + + /* DISABLE UNTIL NEW SYSTEM + + @EventHandler + public void loadComplete(FMLLoadCompleteEvent event){ + TrackerFileLoader.loadTrackersFile(); + + if (TrackerFileLoader.loadTrackerStatsFile(configDirectory)){ + TrackerFileLoader.saveTrackerStatsFile(configDirectory); + } + } + + @SubscribeEvent + public void onLeaveServer(FMLNetworkEvent.ClientDisconnectionFromServerEvent event){ + TrackerFileLoader.saveTrackerStatsFile(configDirectory); + } + + */ + + public static boolean hasSkyblockScoreboard() { + Minecraft mc = Minecraft.getMinecraft(); + + if (mc != null && mc.theWorld != null) { + Scoreboard scoreboard = mc.theWorld.getScoreboard(); + ScoreObjective sidebarObjective = scoreboard.getObjectiveInDisplaySlot(1); + if (sidebarObjective != null) { + String objectiveName = sidebarObjective.getDisplayName().replaceAll("(?i)\\u00A7.", ""); + for (String skyblock : SKYBLOCK_IN_ALL_LANGUAGES) { + if (objectiveName.startsWith(skyblock)) { + return true; + } + } + } + } + + return false; + } + + @SubscribeEvent + public void onTooltip(ItemTooltipEvent event){ + if (event.itemStack != null && Keyboard.isKeyDown(Keyboard.KEY_BACKSLASH)) { + try { + StringSelection clipboard = new StringSelection(event.itemStack.serializeNBT().toString()); + Toolkit.getDefaultToolkit().getSystemClipboard().setContents(clipboard, clipboard); + } catch (Exception ignored) { + } + } + } + + @SubscribeEvent(priority = EventPriority.HIGHEST) + public void onStatusBar(ClientChatReceivedEvent event){ + if (Utils.removeColor(event.message.getUnformattedText()).toLowerCase().trim().startsWith("your profile was changed to:")){ + MinecraftForge.EVENT_BUS.post(new ProfileSwitchedEvent()); + } + } + + public static GuiScreen screenToOpen = null; + private static int screenTicks = 0; + + @SubscribeEvent + public void onClientTick(TickEvent.ClientTickEvent event){ + if (screenToOpen != null){ + screenTicks++; + if (screenTicks == 5){ + Minecraft.getMinecraft().displayGuiScreen(screenToOpen); + screenTicks = 0; + screenToOpen = null; + } + } + } +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/SpecialColour.java b/src/main/java/com/thatgravyboat/skyblockhud/SpecialColour.java new file mode 100644 index 0000000..8501c9d --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/SpecialColour.java @@ -0,0 +1,95 @@ +package com.thatgravyboat.skyblockhud; + +import java.awt.*; + +public class SpecialColour { + + public static String special(int chromaSpeed, int alpha, int rgb) { + return special(chromaSpeed, alpha, (rgb & 0xFF0000) >> 16, (rgb & 0x00FF00) >> 8, (rgb & 0x0000FF)); + } + + private static final int RADIX = 10; + + public static String special(int chromaSpeed, int alpha, int r, int g, int b) { + StringBuilder sb = new StringBuilder(); + sb.append(Integer.toString(chromaSpeed, RADIX)).append(":"); + sb.append(Integer.toString(alpha, RADIX)).append(":"); + sb.append(Integer.toString(r, RADIX)).append(":"); + sb.append(Integer.toString(g, RADIX)).append(":"); + sb.append(Integer.toString(b, RADIX)); + return sb.toString(); + } + + private static int[] decompose(String csv) { + String[] split = csv.split(":"); + + int[] arr = new int[split.length]; + + + for(int i=0; i<split.length; i++) { + arr[i] = Integer.parseInt(split[split.length-1-i], RADIX); + } + return arr; + } + + public static int specialToSimpleRGB(String special) { + int[] d = decompose(special); + int r = d[2]; + int g = d[1]; + int b = d[0]; + int a = d[3]; + int chr = d[4]; + + return (a & 0xFF) << 24 | (r & 0xFF) << 16 | (g & 0xFF) << 8 | (b & 0xFF); + } + + public static int getSpeed(String special) { + return decompose(special)[4]; + } + + public static float getSecondsForSpeed(int speed) { + return (255-speed)/254f*(MAX_CHROMA_SECS-MIN_CHROMA_SECS)+MIN_CHROMA_SECS; + } + + private static final int MIN_CHROMA_SECS = 1; + private static final int MAX_CHROMA_SECS = 60; + + public static long startTime = -1; + public static int specialToChromaRGB(String special) { + if(startTime < 0) startTime = System.currentTimeMillis(); + + int[] d = decompose(special); + int chr = d[4]; + int a = d[3]; + int r = d[2]; + int g = d[1]; + int b = d[0]; + + float[] hsv = Color.RGBtoHSB(r, g, b, null); + + if(chr > 0) { + float seconds = getSecondsForSpeed(chr); + hsv[0] += (System.currentTimeMillis()-startTime)/1000f/seconds; + hsv[0] %= 1; + if(hsv[0] < 0) hsv[0] += 1; + } + + return (a & 0xFF) << 24 | (Color.HSBtoRGB(hsv[0], hsv[1], hsv[2]) & 0x00FFFFFF); + } + + public static int rotateHue(int argb, int degrees) { + int a = (argb >> 24) & 0xFF; + int r = (argb >> 16) & 0xFF; + int g = (argb >> 8) & 0xFF; + int b = (argb) & 0xFF; + + float[] hsv = Color.RGBtoHSB(r, g, b, null); + + hsv[0] += degrees/360f; + hsv[0] %= 1; + + return (a & 0xFF) << 24 | (Color.HSBtoRGB(hsv[0], hsv[1], hsv[2]) & 0x00FFFFFF); + } + + +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/Utils.java b/src/main/java/com/thatgravyboat/skyblockhud/Utils.java new file mode 100644 index 0000000..31f6aa8 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/Utils.java @@ -0,0 +1,247 @@ +package com.thatgravyboat.skyblockhud; + + +import net.minecraft.client.Minecraft; +import net.minecraft.client.entity.EntityPlayerSP; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.gui.ScaledResolution; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.WorldRenderer; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.init.Items; +import net.minecraft.item.Item; +import net.minecraftforge.client.event.RenderGameOverlayEvent; +import net.minecraftforge.fml.common.Loader; +import org.lwjgl.BufferUtils; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL14; + +import java.nio.FloatBuffer; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.LinkedList; + +public class Utils { + + private static LinkedList<Integer> guiScales = new LinkedList<>(); + private static ScaledResolution lastScale = new ScaledResolution(Minecraft.getMinecraft()); + //Labymod compatibility + private static FloatBuffer projectionMatrixOld = BufferUtils.createFloatBuffer(16); + private static FloatBuffer modelviewMatrixOld = BufferUtils.createFloatBuffer(16); + + + public static String removeColor(String input) { + return input.replaceAll("(?i)\\u00A7.", ""); + } + + public static String removeWhiteSpaceAndRemoveWord(String input, String replace) {return input.toLowerCase().replace( " ", "").replace(replace, ""); } + + public static boolean isPlayerHoldingRedstone(EntityPlayerSP player) { + if (!SkyblockHud.config.main.requireRedstone) return true; + ArrayList<Item> redstoneItems = new ArrayList<>(Arrays.asList(Items.redstone, Items.repeater, Items.comparator, Item.getByNameOrId("minecraft:redstone_torch"))); + if (player.getHeldItem()!=null) + return redstoneItems.contains(player.getHeldItem().getItem()); + return false; + } + + public static boolean inRangeInclusive(int value, int min, int max) { + return value <= max && value >= min; + } + + public static int whatRomanNumeral(String roman){ + switch (roman.toLowerCase()) { + case "i": return 1; + case "ii": return 2; + case "iii": return 3; + case "iv": return 4; + case "v": return 5; + case "vi": return 6; + case "vii": return 7; + case "viii": return 8; + case "ix": return 9; + case "x": return 10; + default: return 0; + } + } + + public static String intToRomanNumeral(int i){ + switch (i) { + case 1: return "I"; + case 2: return "II"; + case 3: return "III"; + case 4: return "IV"; + case 5: return "V"; + case 6: return "VI"; + case 7: return "VII"; + case 8: return "VIII"; + case 9: return "IX"; + case 10: return "X"; + default: return ""; + } + } + + public static boolean overlayShouldRender(RenderGameOverlayEvent.ElementType type, boolean... booleans){ + return overlayShouldRender(false, type, RenderGameOverlayEvent.ElementType.HOTBAR, booleans); + } + + public static boolean overlayShouldRender(boolean hideOnf3, RenderGameOverlayEvent.ElementType type, RenderGameOverlayEvent.ElementType checkType, boolean... booleans){ + Minecraft mc = Minecraft.getMinecraft(); + boolean shouldRender; + if (booleans.length > 1){ + for (boolean aBoolean : booleans) if (!aBoolean) return false; + shouldRender = true; + }else shouldRender = booleans.length != 1 || booleans[0]; + if (hideOnf3) { + if (mc.gameSettings.showDebugInfo || (mc.gameSettings.keyBindPlayerList.isKeyDown() && (!mc.isIntegratedServerRunning() || mc.thePlayer.sendQueue.getPlayerInfoMap().size() > 1))) { + return false; + } + } + return shouldRender && ((type == null && Loader.isModLoaded("labymod")) || type == checkType); + } + + public static void drawStringScaledMaxWidth(String str, FontRenderer fr, float x, float y, boolean shadow, int len, int colour) { + int strLen = fr.getStringWidth(str); + float factor = len/(float)strLen; + factor = Math.min(1, factor); + + drawStringScaled(str, fr, x, y, shadow, colour, factor); + } + + public static void drawStringScaled(String str, FontRenderer fr, float x, float y, boolean shadow, int colour, float factor) { + GlStateManager.scale(factor, factor, 1); + fr.drawString(str, x/factor, y/factor, colour, shadow); + GlStateManager.scale(1/factor, 1/factor, 1); + } + + public static void drawStringCenteredScaled(String str, FontRenderer fr, float x, float y, boolean shadow, int len, int colour) { + int strLen = fr.getStringWidth(str); + float factor = len/(float)strLen; + float fontHeight = 8*factor; + + drawStringScaled(str, fr, x-len/2f, y-fontHeight/2f, shadow, colour, factor); + } + + public static void drawTexturedRect(float x, float y, float width, float height, float uMin, float uMax, float vMin, float vMax, int filter) { + GlStateManager.enableTexture2D(); + GlStateManager.enableBlend(); + GL14.glBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA); + + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, filter); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, filter); + + Tessellator tessellator = Tessellator.getInstance(); + WorldRenderer worldrenderer = tessellator.getWorldRenderer(); + worldrenderer.begin(7, DefaultVertexFormats.POSITION_TEX); + worldrenderer + .pos(x, y+height, 0.0D) + .tex(uMin, vMax).endVertex(); + worldrenderer + .pos(x+width, y+height, 0.0D) + .tex(uMax, vMax).endVertex(); + worldrenderer + .pos(x+width, y, 0.0D) + .tex(uMax, vMin).endVertex(); + worldrenderer + .pos(x, y, 0.0D) + .tex(uMin, vMin).endVertex(); + tessellator.draw(); + + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST); + + GlStateManager.disableBlend(); + } + + public static void drawTexturedRect(float x, float y, float width, float height) { + drawTexturedRect(x, y, width, height, 0, 1, 0 , 1); + } + + public static void drawTexturedRect(float x, float y, float width, float height, int filter) { + drawTexturedRect(x, y, width, height, 0, 1, 0 , 1, filter); + } + + public static void drawTexturedRect(float x, float y, float width, float height, float uMin, float uMax, float vMin, float vMax) { + drawTexturedRect(x, y, width, height, uMin, uMax, vMin , vMax, GL11.GL_LINEAR); + } + + public static void resetGuiScale() { + guiScales.clear(); + } + + public static ScaledResolution peekGuiScale() { + return lastScale; + } + + public static ScaledResolution pushGuiScale(int scale) { + if(guiScales.size() == 0) { + if(Loader.isModLoaded("labymod")) { + GL11.glGetFloat(GL11.GL_PROJECTION_MATRIX, projectionMatrixOld); + GL11.glGetFloat(GL11.GL_MODELVIEW_MATRIX, modelviewMatrixOld); + } + } + + if(scale < 0) { + if(guiScales.size() > 0) { + guiScales.pop(); + } + } else { + if(scale == 0) { + guiScales.push(Minecraft.getMinecraft().gameSettings.guiScale); + } else { + guiScales.push(scale); + } + } + + int newScale = guiScales.size() > 0 ? Math.max(0, Math.min(4, guiScales.peek())) : Minecraft.getMinecraft().gameSettings.guiScale; + if(newScale == 0) newScale = Minecraft.getMinecraft().gameSettings.guiScale; + + int oldScale = Minecraft.getMinecraft().gameSettings.guiScale; + Minecraft.getMinecraft().gameSettings.guiScale = newScale; + ScaledResolution scaledresolution = new ScaledResolution(Minecraft.getMinecraft()); + Minecraft.getMinecraft().gameSettings.guiScale = oldScale; + + if(guiScales.size() > 0) { + GlStateManager.viewport(0, 0, Minecraft.getMinecraft().displayWidth, Minecraft.getMinecraft().displayHeight); + GlStateManager.matrixMode(GL11.GL_PROJECTION); + GlStateManager.loadIdentity(); + GlStateManager.ortho(0.0D, + scaledresolution.getScaledWidth_double(), + scaledresolution.getScaledHeight_double(), 0.0D, 1000.0D, 3000.0D); + GlStateManager.matrixMode(GL11.GL_MODELVIEW); + GlStateManager.loadIdentity(); + GlStateManager.translate(0.0F, 0.0F, -2000.0F); + } else { + if(Loader.isModLoaded("labymod") && projectionMatrixOld.limit() > 0 && modelviewMatrixOld.limit() > 0) { + GlStateManager.matrixMode(GL11.GL_PROJECTION); + GL11.glLoadMatrix(projectionMatrixOld); + GlStateManager.matrixMode(GL11.GL_MODELVIEW); + GL11.glLoadMatrix(modelviewMatrixOld); + } else { + GlStateManager.matrixMode(GL11.GL_PROJECTION); + GlStateManager.loadIdentity(); + GlStateManager.ortho(0.0D, + scaledresolution.getScaledWidth_double(), + scaledresolution.getScaledHeight_double(), 0.0D, 1000.0D, 3000.0D); + GlStateManager.matrixMode(GL11.GL_MODELVIEW); + GlStateManager.loadIdentity(); + GlStateManager.translate(0.0F, 0.0F, -2000.0F); + } + } + + lastScale = scaledresolution; + return scaledresolution; + } + + public static void drawStringCentered(String str, FontRenderer fr, float x, float y, boolean shadow, int colour) { + int strLen = fr.getStringWidth(str); + + float x2 = x - strLen/2f; + float y2 = y - fr.FONT_HEIGHT/2f; + + GL11.glTranslatef(x2, y2, 0); + fr.drawString(str, 0, 0, colour, shadow); + GL11.glTranslatef(-x2, -y2, 0); + } + +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/api/LeaderboardGetter.java b/src/main/java/com/thatgravyboat/skyblockhud/api/LeaderboardGetter.java new file mode 100644 index 0000000..58cede8 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/api/LeaderboardGetter.java @@ -0,0 +1,65 @@ +package com.thatgravyboat.skyblockhud.api; + +import com.thatgravyboat.skyblockhud.Utils; +import com.thatgravyboat.skyblockhud.api.events.SidebarLineUpdateEvent; +import com.thatgravyboat.skyblockhud.api.events.SidebarPostEvent; +import com.thatgravyboat.skyblockhud.api.events.SidebarPreGetEvent; +import net.minecraft.client.Minecraft; +import net.minecraft.scoreboard.Score; +import net.minecraft.scoreboard.ScoreObjective; +import net.minecraft.scoreboard.ScorePlayerTeam; +import net.minecraft.scoreboard.Scoreboard; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.common.gameevent.TickEvent; + +import java.util.*; +import java.util.stream.Collectors; + +import static com.thatgravyboat.skyblockhud.ComponentHandler.SCOREBOARD_CHARACTERS; + +public class LeaderboardGetter { + + private static Map<Integer, String> cachedScores = new HashMap<>(); + private static List<String> cachedScoresList = new ArrayList<>(); + + private static int ticks = 0; + + //This is really bad and should use the packet instead. + + @SubscribeEvent + public void onClientUpdate(TickEvent.ClientTickEvent event){ + if (event.phase.equals(TickEvent.Phase.START)) return; + ticks++; + if (ticks % 5 != 0) return; + + Minecraft mc = Minecraft.getMinecraft(); + if (mc.theWorld != null) { + Scoreboard scoreboard = mc.theWorld.getScoreboard(); + ScoreObjective sidebarObjective = scoreboard.getObjectiveInDisplaySlot(1); + + if (sidebarObjective != null && !MinecraftForge.EVENT_BUS.post(new SidebarPreGetEvent(scoreboard, sidebarObjective))) { + Collection<Score> scoreList = sidebarObjective.getScoreboard().getSortedScores(sidebarObjective); + Map<Integer, String> scores = scoreList.stream().collect(Collectors.toMap(Score::getScorePoints, this::getLine)); + + if (!cachedScores.equals(scores)) { + scores.forEach((score, name) -> { + if (cachedScores.get(score) == null || !cachedScores.get(score).equals(name)) { + MinecraftForge.EVENT_BUS.post(new SidebarLineUpdateEvent(name, SCOREBOARD_CHARACTERS.matcher(name).replaceAll("").trim(), score, scores.size(), scoreboard, sidebarObjective)); + } + }); + cachedScores = scores; + cachedScoresList = scores.values().stream().map(name -> SCOREBOARD_CHARACTERS.matcher(name).replaceAll("").trim()).collect(Collectors.toList()); + } + MinecraftForge.EVENT_BUS.post(new SidebarPostEvent(scoreboard, sidebarObjective, cachedScoresList)); + } + } + } + + public String getLine(Score score) { + ScorePlayerTeam scorePlayerTeam = score.getScoreScoreboard().getPlayersTeam(score.getPlayerName()); + return Utils.removeColor(ScorePlayerTeam.formatPlayerName(scorePlayerTeam, score.getPlayerName())); + } + + +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/api/events/ProfileSwitchedEvent.java b/src/main/java/com/thatgravyboat/skyblockhud/api/events/ProfileSwitchedEvent.java new file mode 100644 index 0000000..015388a --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/api/events/ProfileSwitchedEvent.java @@ -0,0 +1,7 @@ +package com.thatgravyboat.skyblockhud.api.events; + +import net.minecraftforge.fml.common.eventhandler.Event; + +public class ProfileSwitchedEvent extends Event { + +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/api/events/SidebarLineUpdateEvent.java b/src/main/java/com/thatgravyboat/skyblockhud/api/events/SidebarLineUpdateEvent.java new file mode 100644 index 0000000..2737ee9 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/api/events/SidebarLineUpdateEvent.java @@ -0,0 +1,22 @@ +package com.thatgravyboat.skyblockhud.api.events; + +import net.minecraft.scoreboard.ScoreObjective; +import net.minecraft.scoreboard.Scoreboard; +import net.minecraftforge.fml.common.eventhandler.Event; + +public class SidebarLineUpdateEvent extends Event { + + public String rawLine; + public String formattedLine; + public int position; + public Scoreboard scoreboard; + public ScoreObjective objective; + + public SidebarLineUpdateEvent(String rawLine, String formattedLine, int score, int max, Scoreboard scoreboard, ScoreObjective objective) { + this.rawLine = rawLine; + this.formattedLine = formattedLine; + this.position = max - score; + this.scoreboard = scoreboard; + this.objective = objective; + } +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/api/events/SidebarPostEvent.java b/src/main/java/com/thatgravyboat/skyblockhud/api/events/SidebarPostEvent.java new file mode 100644 index 0000000..b81859a --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/api/events/SidebarPostEvent.java @@ -0,0 +1,22 @@ +package com.thatgravyboat.skyblockhud.api.events; + +import net.minecraft.scoreboard.ScoreObjective; +import net.minecraft.scoreboard.Scoreboard; +import net.minecraftforge.fml.common.eventhandler.Event; + +import java.util.List; + +public class SidebarPostEvent extends Event { + + public Scoreboard scoreboard; + public ScoreObjective objective; + public List<String> scores; + public String[] arrayScores; + + public SidebarPostEvent(Scoreboard scoreboard, ScoreObjective objective, List<String> scores) { + this.scoreboard = scoreboard; + this.objective = objective; + this.scores = scores; + this.arrayScores = scores.toArray(new String[]{}); + } +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/api/events/SidebarPreGetEvent.java b/src/main/java/com/thatgravyboat/skyblockhud/api/events/SidebarPreGetEvent.java new file mode 100644 index 0000000..0db1895 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/api/events/SidebarPreGetEvent.java @@ -0,0 +1,18 @@ +package com.thatgravyboat.skyblockhud.api.events; + +import net.minecraft.scoreboard.ScoreObjective; +import net.minecraft.scoreboard.Scoreboard; +import net.minecraftforge.fml.common.eventhandler.Cancelable; +import net.minecraftforge.fml.common.eventhandler.Event; + +@Cancelable +public class SidebarPreGetEvent extends Event { + + public Scoreboard scoreboard; + public ScoreObjective objective; + + public SidebarPreGetEvent(Scoreboard scoreboard, ScoreObjective objective) { + this.scoreboard = scoreboard; + this.objective = objective; + } +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/commands/Commands.java b/src/main/java/com/thatgravyboat/skyblockhud/commands/Commands.java new file mode 100644 index 0000000..3ca82e7 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/commands/Commands.java @@ -0,0 +1,42 @@ +package com.thatgravyboat.skyblockhud.commands; + +import com.thatgravyboat.skyblockhud.SkyblockHud; +import com.thatgravyboat.skyblockhud.config.SBHConfigEditor; +import com.thatgravyboat.skyblockhud.core.GuiScreenElementWrapper; +import com.thatgravyboat.skyblockhud.handlers.MapHandler; +import com.thatgravyboat.skyblockhud.location.LocationHandler; +import net.minecraft.client.Minecraft; +import net.minecraft.command.ICommandSender; +import net.minecraftforge.client.ClientCommandHandler; +import org.apache.commons.lang3.StringUtils; + +public class Commands { + + private static final SimpleCommand.ProcessCommandRunnable settingsRunnable = new SimpleCommand.ProcessCommandRunnable() { + public void processCommand(ICommandSender sender, String[] args) { + if(args.length > 0) { + SkyblockHud.screenToOpen = new GuiScreenElementWrapper(new SBHConfigEditor(SkyblockHud.config, StringUtils.join(args, " "))); + } else { + SkyblockHud.screenToOpen = new GuiScreenElementWrapper(new SBHConfigEditor(SkyblockHud.config)); + } + } + }; + + private static final SimpleCommand settingsCommand = new SimpleCommand("sbh", settingsRunnable); + private static final SimpleCommand settingsCommand2 = new SimpleCommand("sbhsettings", settingsRunnable); + private static final SimpleCommand settingsCommand3 = new SimpleCommand("sbhud", settingsRunnable); + + private static final SimpleCommand mapCommand = new SimpleCommand("sbhmap", new SimpleCommand.ProcessCommandRunnable() { + public void processCommand(ICommandSender sender, String[] args) { + if (LocationHandler.getCurrentLocation().getCategory().getMap() != null) + SkyblockHud.screenToOpen = new MapHandler.MapScreen(); + } + }); + + public static void init(){ + ClientCommandHandler.instance.registerCommand(settingsCommand); + ClientCommandHandler.instance.registerCommand(settingsCommand2); + ClientCommandHandler.instance.registerCommand(settingsCommand3); + ClientCommandHandler.instance.registerCommand(mapCommand); + } +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/commands/SimpleCommand.java b/src/main/java/com/thatgravyboat/skyblockhud/commands/SimpleCommand.java new file mode 100644 index 0000000..7fc7920 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/commands/SimpleCommand.java @@ -0,0 +1,58 @@ +package com.thatgravyboat.skyblockhud.commands; + +import net.minecraft.command.CommandBase; +import net.minecraft.command.CommandException; +import net.minecraft.command.ICommandSender; +import net.minecraft.util.BlockPos; + +import java.util.List; + +/** + @author Moulberry + **/ +public class SimpleCommand extends CommandBase { + + private String commandName; + private ProcessCommandRunnable runnable; + private TabCompleteRunnable tabRunnable; + + public SimpleCommand(String commandName, ProcessCommandRunnable runnable) { + this.commandName = commandName; + this.runnable = runnable; + } + + public SimpleCommand(String commandName, ProcessCommandRunnable runnable, TabCompleteRunnable tabRunnable) { + this.commandName = commandName; + this.runnable = runnable; + this.tabRunnable = tabRunnable; + } + + public abstract static class ProcessCommandRunnable { + public abstract void processCommand(ICommandSender sender, String[] args); + } + + public abstract static class TabCompleteRunnable { + public abstract List<String> tabComplete(ICommandSender sender, String[] args, BlockPos pos); + } + + public boolean canCommandSenderUseCommand(ICommandSender sender) { + return true; + } + + public String getCommandName() { + return commandName; + } + + public String getCommandUsage(ICommandSender sender) { + return "/" + commandName; + } + + public void processCommand(ICommandSender sender, String[] args) throws CommandException { + runnable.processCommand(sender, args); + } + + public List<String> addTabCompletionOptions(ICommandSender sender, String[] args, BlockPos pos) { + if(tabRunnable != null) return tabRunnable.tabComplete(sender, args, pos); + return null; + } +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/config/KeyBindings.java b/src/main/java/com/thatgravyboat/skyblockhud/config/KeyBindings.java new file mode 100644 index 0000000..805b906 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/config/KeyBindings.java @@ -0,0 +1,9 @@ +package com.thatgravyboat.skyblockhud.config; + +import net.minecraft.client.settings.KeyBinding; + +public class KeyBindings { + public static KeyBinding map = new KeyBinding("Opens the big map.", 50, "SkyblockHud"); + +} + diff --git a/src/main/java/com/thatgravyboat/skyblockhud/config/SBHConfig.java b/src/main/java/com/thatgravyboat/skyblockhud/config/SBHConfig.java new file mode 100644 index 0000000..1f6e581 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/config/SBHConfig.java @@ -0,0 +1,486 @@ +package com.thatgravyboat.skyblockhud.config; + +import com.google.gson.annotations.Expose; +import com.thatgravyboat.skyblockhud.SkyblockHud; +import com.thatgravyboat.skyblockhud.core.GuiScreenElementWrapper; +import com.thatgravyboat.skyblockhud.core.config.Config; +import com.thatgravyboat.skyblockhud.core.config.Position; +import com.thatgravyboat.skyblockhud.core.config.annotations.*; +import com.thatgravyboat.skyblockhud.core.config.gui.GuiPositionEditor; +import net.minecraft.client.Minecraft; + +public class SBHConfig extends Config { + + private void editOverlay(String activeConfig, int width, int height, Position position) { + Minecraft.getMinecraft().displayGuiScreen( + new GuiPositionEditor(position, width, height, + () -> {}, + () -> {}, + () -> SkyblockHud.screenToOpen = new GuiScreenElementWrapper(new SBHConfigEditor(SkyblockHud.config, activeConfig)) + ) + ); + } + + @Override + public void executeRunnable(String runnableId) { + String activeConfigCategory = null; + if(Minecraft.getMinecraft().currentScreen instanceof GuiScreenElementWrapper) { + GuiScreenElementWrapper wrapper = (GuiScreenElementWrapper) Minecraft.getMinecraft().currentScreen; + if(wrapper.element instanceof SBHConfigEditor) { + activeConfigCategory = ((SBHConfigEditor)wrapper.element).getSelectedCategoryName(); + } + } + + switch (runnableId) { + case "rpg": + editOverlay(activeConfigCategory, 120, 47, rpg.rpgHudPosition); + return; + case "d1": + editOverlay(activeConfigCategory, 120, 32, dungeon.dungeonPlayer1); + return; + case "d2": + editOverlay(activeConfigCategory, 120, 32, dungeon.dungeonPlayer2); + return; + case "d3": + editOverlay(activeConfigCategory, 120, 32, dungeon.dungeonPlayer3); + return; + case "d4": + editOverlay(activeConfigCategory, 120, 32, dungeon.dungeonPlayer4); + return; + case "main": + editOverlay(activeConfigCategory, 1000, 34, main.mainHudPos); + return; + case "ultimate": + editOverlay(activeConfigCategory, 182, 5, dungeon.barPosition); + return; + case "map": + editOverlay(activeConfigCategory, 72, 72, map.miniMapPosition); + return; + case "tracker": + editOverlay(activeConfigCategory, 120, 70, trackers.trackerPosition); + return; + } + } + + @Expose + @Category( + name = "Misc Options", + desc = "Just a bunch of random options." + ) + public Misc misc = new Misc(); + + @Expose + @Category( + name = "Main Hud", + desc = "All Options for the main hud." + ) + public MainHud main = new MainHud(); + + @Expose + @Category( + name = "RPG Hud", + desc = "All Options for the RPG hud." + ) + public RPGHud rpg = new RPGHud(); + + @Expose + @Category( + name = "Dungeon Hud", + desc = "All Options for the Dungeon hud." + ) + public DungeonHud dungeon = new DungeonHud(); + + @Expose + @Category( + name = "Renderer", + desc = "All Options for rendering." + ) + public Renderer renderer = new Renderer(); + + @Expose + @Category( + name = "Map", + desc = "All Options for the Map." + ) + public Map map = new Map(); + + @Expose + @Category( + name = "Tracker", + desc = "All Options for the Trackers." + ) + public Trackers trackers = new Trackers(); + + public static class Misc { + @Expose + @ConfigOption( + name = "Hide Scoreboard", + desc = "Hides the scoreboard when in skyblock." + ) + @ConfigEditorBoolean + public boolean hideScoreboard = false; + } + + public static class MainHud { + @Expose + @ConfigOption( + name = "Main Hud Position", + desc = "" + ) + @ConfigEditorButton( + runnableId = "main", + buttonText = "Edit" + ) + public Position mainHudPos = new Position(0, 1, true, false); + + @Expose + @ConfigOption( + name = "Twelve Hour Clock", + desc = "Allows you to change the clock to be 12 hour instead of 24 hour." + ) + @ConfigEditorBoolean + public boolean twelveHourClock = false; + + @Expose + @ConfigOption( + name = "Shift hud with boss", + desc = "Shifts the hud when bossbar is visible." + ) + @ConfigEditorBoolean + public boolean bossShiftHud = true; + + @Expose + @ConfigOption( + name = "Require Redstone", + desc = "Allows to make it so that the redstone percentage requires you to hold a redstone item to show." + ) + @ConfigEditorBoolean + public boolean requireRedstone = true; + } + + public static class RPGHud { + @Expose + @ConfigOption( + name = "Show RPG Hud", + desc = "Allows you to show or hide the RPG Hud." + ) + @ConfigEditorBoolean + public boolean showRpgHud = true; + + @Expose + @ConfigOption( + name = "RPG Hud Position", + desc = "Allows you to change the position of the RPG Hud." + ) + @ConfigEditorButton( + runnableId = "rpg", + buttonText = "Edit" + ) + public Position rpgHudPosition = new Position(1, 1); + } + + public static class DungeonHud { + + @Expose + @ConfigOption( + name = "Dungeon Ultimate Bar", + desc = "" + ) + @ConfigEditorAccordion(id = 2) + public boolean ultimateBar = false; + + @Expose + @ConfigOption( + name = "Hide Ultimate Bar", + desc = "Hides the custom ultimate bar." + ) + @ConfigEditorBoolean() + @ConfigAccordionId(id = 2) + public boolean hideUltimateBar = false; + + @Expose + @ConfigOption( + name = "Bar Position", + desc = "Change the position of the bar." + ) + @ConfigEditorButton( + runnableId = "ultimate", + buttonText = "Edit" + ) + @ConfigAccordionId(id = 2) + public Position barPosition = new Position(0, 50, true, false); + + @Expose + @ConfigOption( + name = "Bar Loading Color", + desc = "The color of the bar when its loading." + ) + @ConfigEditorColour() + @ConfigAccordionId(id = 2) + public String barLoadColor = "159:0:0:0:255"; + + @Expose + @ConfigOption( + name = "Bar Full Color", + desc = "The color of the bar when its full." + ) + @ConfigEditorColour() + @ConfigAccordionId(id = 2) + public String barFullColor = "255:0:0:0:255"; + + @Expose + @ConfigOption( + name = "Bar Style", + desc = "Change the style of the bar" + ) + @ConfigEditorDropdown(values = {"No Notch", "6 Notch", "10 Notch", "12 Notch", "20 Notch"}) + @ConfigAccordionId(id = 2) + public int barStyle = 2; + + @Expose + @ConfigOption( + name = "Dungeon Players", + desc = "" + ) + @ConfigEditorAccordion(id = 1) + public boolean dungeonPlayerAccordion = false; + + @Expose + @ConfigOption( + name = "Hide Dungeon Players", + desc = "Allows you to hide the dungeon player hud" + ) + @ConfigEditorBoolean() + @ConfigAccordionId(id = 1) + public boolean hideDungeonPlayers = false; + + @Expose + @ConfigOption( + name = "Dungeon Player Opacity", + desc = "Allows you to change the opacity of the dungeon players." + ) + @ConfigEditorSlider(minValue = 0, maxValue = 100, minStep = 1) + @ConfigAccordionId(id = 1) + public int dungeonPlayerOpacity = 0; + + @Expose + @ConfigOption( + name = "Hide Dead Players", + desc = "Allows you to hide players that are dead or have left." + ) + @ConfigEditorBoolean() + @ConfigAccordionId(id = 1) + public boolean hideDeadDungeonPlayers = false; + + @Expose + @ConfigOption( + name = "Player Position 1", + desc = "Change the position of this dungeon player." + ) + @ConfigEditorButton( + runnableId = "d1", + buttonText = "Edit" + ) + @ConfigAccordionId(id = 1) + public Position dungeonPlayer1 = new Position(5, 5); + + + @Expose + @ConfigOption( + name = "Player Position 2", + desc = "Change the position of this dungeon player." + ) + @ConfigEditorButton( + runnableId = "d2", + buttonText = "Edit" + ) + @ConfigAccordionId(id = 1) + public Position dungeonPlayer2 = new Position(5, 42); + + @Expose + @ConfigOption( + name = "Player Position 3", + desc = "Change the position of this dungeon player." + ) + @ConfigEditorButton( + runnableId = "d3", + buttonText = "Edit" + ) + @ConfigAccordionId(id = 1) + public Position dungeonPlayer3 = new Position(5, 79); + + @Expose + @ConfigOption( + name = "Player Position 4", + desc = "Change the position of this dungeon player." + ) + @ConfigEditorButton( + runnableId = "d4", + buttonText = "Edit" + ) + @ConfigAccordionId(id = 1) + public Position dungeonPlayer4 = new Position(5, 116); + + } + + public static class Renderer { + @Expose + @ConfigOption( + name = "Hide Boss Bar", + desc = "Hides Boss Bar when certain conditions are met such as the name is just wither or it starts with objective:" + ) + @ConfigEditorBoolean + public boolean hideBossBar = true; + + @Expose + @ConfigOption( + name = "Hide XP Bar", + desc = "Hides xp bar." + ) + @ConfigEditorBoolean + public boolean hideXpBar = true; + + @Expose + @ConfigOption( + name = "Hide Food", + desc = "Hides food." + ) + @ConfigEditorBoolean + public boolean hideFood = true; + + @Expose + @ConfigOption( + name = "Hide air", + desc = "Hides air." + ) + @ConfigEditorBoolean + public boolean hideAir = true; + + @Expose + @ConfigOption( + name = "Hide hearts", + desc = "Hides hearts." + ) + @ConfigEditorBoolean + public boolean hideHearts = true; + + @Expose + @ConfigOption( + name = "Hide armor", + desc = "Hides armor." + ) + @ConfigEditorBoolean + public boolean hideArmor = true; + + @Expose + @ConfigOption( + name = "Hide Animal Hearts", + desc = "Hides Animal Hearts." + ) + @ConfigEditorBoolean + public boolean hideAnimalHearts = true; + } + + public static class Map { + @Expose + @ConfigOption( + name = "Show Player Location", + desc = "This feature is off by default as Hypixel's rules are so vague that this would fall under their disallowed modifications." + ) + @ConfigEditorBoolean + public boolean showPlayerLocation = false; + + @Expose + @ConfigOption( + name = "Show Mini-Map", + desc = "Shows the Mini-Map on your overlay if turned off you can still use /sbhmap to see the map in fullscreen." + ) + @ConfigEditorBoolean + public boolean showMiniMap = false; + + @Expose + @ConfigOption( + name = "Mini-Map Position", + desc = "Allows you to change the position of the Mini-Map." + ) + @ConfigEditorButton( + runnableId = "map", + buttonText = "Edit" + ) + public Position miniMapPosition = new Position(0, 100, false, false); + + @Expose + @ConfigOption( + name = "Icons", + desc = "" + ) + @ConfigEditorAccordion(id = 3) + public boolean icons = false; + + @Expose + @ConfigOption( + name = "NPC", + desc = "Show NPC Icons" + ) + @ConfigEditorBoolean() + @ConfigAccordionId(id = 3) + public boolean showNpcIcons = true; + + @Expose + @ConfigOption( + name = "Info", + desc = "Show Info Icons" + ) + @ConfigEditorBoolean() + @ConfigAccordionId(id = 3) + public boolean showInfoIcons = true; + + @Expose + @ConfigOption( + name = "Misc", + desc = "Show Misc Icons" + ) + @ConfigEditorBoolean() + @ConfigAccordionId(id = 3) + public boolean showMiscIcons = true; + + @Expose + @ConfigOption( + name = "Shops", + desc = "Show Shop Icons" + ) + @ConfigEditorBoolean() + @ConfigAccordionId(id = 3) + public boolean showShopIcons = true; + + @Expose + @ConfigOption( + name = "Quests", + desc = "Show Quest Icons" + ) + @ConfigEditorBoolean() + @ConfigAccordionId(id = 3) + public boolean showQuestIcons = false; + } + + public static class Trackers { + @Expose + @ConfigOption( + name = "Tracker Position", + desc = "Allows you to change the position of the Trackers." + ) + @ConfigEditorButton( + runnableId = "tracker", + buttonText = "Edit" + ) + public Position trackerPosition = new Position(-1, 200); + + @Expose + @ConfigOption( + name = "Hide Tracker", + desc = "It will still track the data just in case." + ) + @ConfigEditorBoolean() + public boolean hideTracker = false; + } +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/config/SBHConfigEditor.java b/src/main/java/com/thatgravyboat/skyblockhud/config/SBHConfigEditor.java new file mode 100644 index 0000000..4994a5d --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/config/SBHConfigEditor.java @@ -0,0 +1,597 @@ +package com.thatgravyboat.skyblockhud.config; + +import com.google.common.collect.Lists; +import com.thatgravyboat.skyblockhud.core.GlScissorStack; +import com.thatgravyboat.skyblockhud.core.GuiElement; +import com.thatgravyboat.skyblockhud.core.config.Config; +import com.thatgravyboat.skyblockhud.core.config.gui.GuiOptionEditor; +import com.thatgravyboat.skyblockhud.core.config.gui.GuiOptionEditorAccordion; +import com.thatgravyboat.skyblockhud.core.config.struct.ConfigProcessor; +import com.thatgravyboat.skyblockhud.core.util.lerp.LerpUtils; +import com.thatgravyboat.skyblockhud.core.util.lerp.LerpingInteger; +import com.thatgravyboat.skyblockhud.core.util.render.RenderUtils; +import com.thatgravyboat.skyblockhud.core.util.render.TextRenderUtils; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.gui.Gui; +import net.minecraft.client.gui.ScaledResolution; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.util.EnumChatFormatting; +import net.minecraft.util.ResourceLocation; +import org.lwjgl.input.Mouse; +import org.lwjgl.opengl.GL11; + +import java.awt.*; +import java.net.URI; +import java.util.*; +import java.util.List; + +import static com.thatgravyboat.skyblockhud.GuiTextures.*; + +public class SBHConfigEditor extends GuiElement { + + private static final ResourceLocation[] socialsIco = new ResourceLocation[] { + DISCORD, + TWITTER + }; + private static final String[] socialsLink = new String[] { + "https://discord.gg/moulberry", + "https://twitter.com/thatgravtboat/" + }; + + private final long openedMillis; + + private String selectedCategory = null; + + private final LerpingInteger optionsScroll = new LerpingInteger(0, 150); + private final LerpingInteger categoryScroll = new LerpingInteger(0, 150); + + private LinkedHashMap<String, ConfigProcessor.ProcessedCategory> processedConfig; + private HashMap<ConfigProcessor.ProcessedOption, ConfigProcessor.ProcessedCategory> categoryForOption = new HashMap<>(); + + public SBHConfigEditor(Config config) { + this(config, null); + } + + public SBHConfigEditor(Config config, String categoryOpen) { + this.openedMillis = System.currentTimeMillis(); + this.processedConfig = ConfigProcessor.create(config); + + for(ConfigProcessor.ProcessedCategory category : processedConfig.values()) { + for(ConfigProcessor.ProcessedOption option : category.options.values()) { + categoryForOption.put(option, category); + } + } + + if(categoryOpen != null) { + for(Map.Entry<String, ConfigProcessor.ProcessedCategory> category : processedConfig.entrySet()) { + if(category.getValue().name.equalsIgnoreCase(categoryOpen)) { + selectedCategory = category.getKey(); + break; + } + } + if(selectedCategory == null) { + for(Map.Entry<String, ConfigProcessor.ProcessedCategory> category : processedConfig.entrySet()) { + if(category.getValue().name.toLowerCase().startsWith(categoryOpen.toLowerCase())) { + selectedCategory = category.getKey(); + break; + } + } + } + if(selectedCategory == null) { + for(Map.Entry<String, ConfigProcessor.ProcessedCategory> category : processedConfig.entrySet()) { + if(category.getValue().name.toLowerCase().contains(categoryOpen.toLowerCase())) { + selectedCategory = category.getKey(); + break; + } + } + } + } + } + + private LinkedHashMap<String, ConfigProcessor.ProcessedCategory> getCurrentConfigEditing() { + return new LinkedHashMap<>(processedConfig); + } + + private LinkedHashMap<String, ConfigProcessor.ProcessedOption> getOptionsInCategory(ConfigProcessor.ProcessedCategory cat) { + return new LinkedHashMap<>(cat.options); + } + + public String getSelectedCategory() { + return selectedCategory; + } + + public String getSelectedCategoryName() { + return processedConfig.get(selectedCategory).name; + } + + private void setSelectedCategory(String category) { + selectedCategory = category; + optionsScroll.setValue(0); + } + + public void render() { + optionsScroll.tick(); + categoryScroll.tick(); + + List<String> tooltipToDisplay = null; + + long currentTime = System.currentTimeMillis(); + long delta = currentTime - openedMillis; + + ScaledResolution scaledResolution = new ScaledResolution(Minecraft.getMinecraft()); + int width = scaledResolution.getScaledWidth(); + int height = scaledResolution.getScaledHeight(); + int mouseX = Mouse.getX() * width / Minecraft.getMinecraft().displayWidth; + int mouseY = height - Mouse.getY() * height / Minecraft.getMinecraft().displayHeight - 1; + + float opacityFactor = LerpUtils.sigmoidZeroOne(delta/500f); + RenderUtils.drawGradientRect(0, 0, 0, width, height, + (int)(0x80*opacityFactor) << 24 | 0x101010, + (int)(0x90*opacityFactor) << 24 | 0x101010); + + int xSize = Math.min(scaledResolution.getScaledWidth()-100/scaledResolution.getScaleFactor(), 500); + int ySize = Math.min(scaledResolution.getScaledHeight()-100/scaledResolution.getScaleFactor(), 400); + + int x = (scaledResolution.getScaledWidth() - xSize)/2; + int y = (scaledResolution.getScaledHeight() - ySize)/2; + + int adjScaleFactor = Math.max(2, scaledResolution.getScaleFactor()); + + int openingXSize = xSize; + int openingYSize = ySize; + if(delta < 150) { + openingXSize = (int)(delta*xSize/150); + openingYSize = 5; + } else if(delta < 300) { + openingYSize = 5 + (int)(delta-150)*(ySize-5)/150; + } + RenderUtils.drawFloatingRectDark( + (scaledResolution.getScaledWidth() - openingXSize)/2, + (scaledResolution.getScaledHeight() - openingYSize)/2, + openingXSize, openingYSize); + GlScissorStack.clear(); + GlScissorStack.push((scaledResolution.getScaledWidth() - openingXSize)/2, + (scaledResolution.getScaledHeight() - openingYSize)/2, + (scaledResolution.getScaledWidth() + openingXSize)/2, + (scaledResolution.getScaledHeight() + openingYSize)/2, scaledResolution); + + RenderUtils.drawFloatingRectDark(x+5, y+5, xSize-10, 20, false); + + FontRenderer fr = Minecraft.getMinecraft().fontRendererObj; + TextRenderUtils.drawStringCenteredScaledMaxWidth("SkyBlockHud by "+EnumChatFormatting.RED+"ThatGravyBoat"+EnumChatFormatting.RESET+", config by "+EnumChatFormatting.DARK_PURPLE+"Moulberry", + fr, x+xSize/2f, y+15, false, 200, 0xa0a0a0); + + RenderUtils.drawFloatingRectDark(x+4, y+49-20, + 140, ySize-54+20, false); + + int innerPadding = 20/adjScaleFactor; + int innerLeft = x+4+innerPadding; + int innerRight = x+144-innerPadding; + int innerTop = y+49+innerPadding; + int innerBottom = y+ySize-5-innerPadding; + Gui.drawRect(innerLeft, innerTop, innerLeft+1, innerBottom, 0xff08080E); //Left + Gui.drawRect(innerLeft+1, innerTop, innerRight, innerTop+1, 0xff08080E); //Top + Gui.drawRect(innerRight-1, innerTop+1, innerRight, innerBottom, 0xff28282E); //Right + Gui.drawRect(innerLeft+1, innerBottom-1, innerRight-1, innerBottom, 0xff28282E); //Bottom + Gui.drawRect(innerLeft+1, innerTop+1, innerRight-1, innerBottom-1, 0x6008080E); //Middle + + GlScissorStack.push(0, innerTop+1, scaledResolution.getScaledWidth(), + innerBottom-1, scaledResolution); + + float catBarSize = 1; + int catY = -categoryScroll.getValue(); + + LinkedHashMap<String, ConfigProcessor.ProcessedCategory> currentConfigEditing = getCurrentConfigEditing(); + for(Map.Entry<String, ConfigProcessor.ProcessedCategory> entry : currentConfigEditing.entrySet()) { + String selectedCategory = getSelectedCategory(); + if(selectedCategory == null || !currentConfigEditing.containsKey(selectedCategory)) { + setSelectedCategory(entry.getKey()); + } + String catName = entry.getValue().name; + if(entry.getKey().equals(getSelectedCategory())) { + catName = EnumChatFormatting.DARK_AQUA.toString() + EnumChatFormatting.UNDERLINE + catName; + } else { + catName = EnumChatFormatting.GRAY + catName; + } + TextRenderUtils.drawStringCenteredScaledMaxWidth(catName, + fr, x+75, y+70+catY, false, 100, -1); + catY += 15; + if(catY > 0) { + catBarSize = LerpUtils.clampZeroOne((float)(innerBottom-innerTop-2)/(catY+5+categoryScroll.getValue())); + } + } + + float catBarStart = categoryScroll.getValue() / (float)(catY + categoryScroll.getValue()); + float catBarEnd = catBarStart+catBarSize; + if(catBarEnd > 1) { + catBarEnd = 1; + if(categoryScroll.getTarget()/(float)(catY + categoryScroll.getValue())+catBarSize < 1) { + int target = optionsScroll.getTarget(); + categoryScroll.setValue((int)Math.ceil((catY+5+categoryScroll.getValue())-catBarSize*(catY+5+categoryScroll.getValue()))); + categoryScroll.setTarget(target); + } else { + categoryScroll.setValue((int)Math.ceil((catY+5+categoryScroll.getValue())-catBarSize*(catY+5+categoryScroll.getValue()))); + } + } + int catDist = innerBottom-innerTop-12; + Gui.drawRect(innerLeft+2, innerTop+5, innerLeft+7, innerBottom-5, 0xff101010); + Gui.drawRect(innerLeft+3, innerTop+6+(int)(catDist*catBarStart), innerLeft+6, + innerTop+6+(int)(catDist*catBarEnd), 0xff303030); + + GlScissorStack.pop(scaledResolution); + + TextRenderUtils.drawStringCenteredScaledMaxWidth("Categories", + fr, x+75, y+44, false, 120, 0xa368ef); + + RenderUtils.drawFloatingRectDark(x+149, y+29, xSize-154, ySize-34, false); + + innerLeft = x+149+innerPadding; + innerRight =x+xSize-5-innerPadding; + innerBottom = y+ySize-5-innerPadding; + + GlStateManager.color(1, 1, 1, 1); + int rightStuffLen = 20; + + if(getSelectedCategory() != null && currentConfigEditing.containsKey(getSelectedCategory())) { + ConfigProcessor.ProcessedCategory cat = currentConfigEditing.get(getSelectedCategory()); + + TextRenderUtils.drawStringScaledMaxWidth(cat.desc, + fr, innerLeft+5, y+40, true, innerRight-innerLeft-rightStuffLen-10, 0xb0b0b0); + } + + Gui.drawRect(innerLeft, innerTop, innerLeft+1, innerBottom, 0xff08080E); //Left + Gui.drawRect(innerLeft+1, innerTop, innerRight, innerTop+1, 0xff08080E); //Top + Gui.drawRect(innerRight-1, innerTop+1, innerRight, innerBottom, 0xff303036); //Right + Gui.drawRect(innerLeft+1, innerBottom-1, innerRight-1, innerBottom, 0xff303036); //Bottom + Gui.drawRect(innerLeft+1, innerTop+1, innerRight-1, innerBottom-1, 0x6008080E); //Middle + + GlScissorStack.push(innerLeft+1, innerTop+1, innerRight-1, innerBottom-1, scaledResolution); + float barSize = 1; + int optionY = -optionsScroll.getValue(); + if(getSelectedCategory() != null && currentConfigEditing.containsKey(getSelectedCategory())) { + ConfigProcessor.ProcessedCategory cat = currentConfigEditing.get(getSelectedCategory()); + int optionWidthDefault = innerRight-innerLeft-20; + GlStateManager.enableDepth(); + Set<Integer> activeAccordions = new HashSet<>(); + for(ConfigProcessor.ProcessedOption option : getOptionsInCategory(cat).values()) { + int optionWidth = optionWidthDefault; + if(option.accordionId >= 0) { + if(!activeAccordions.contains(option.accordionId)) { + continue; + } + optionWidth = optionWidthDefault - 2*innerPadding; + } + + GuiOptionEditor editor = option.editor; + if(editor == null) { + continue; + } + if(editor instanceof GuiOptionEditorAccordion) { + GuiOptionEditorAccordion accordion = (GuiOptionEditorAccordion) editor; + if(accordion.getToggled()) { + activeAccordions.add(accordion.getAccordionId()); + } + } + int optionHeight = editor.getHeight(); + if(innerTop+5+optionY+optionHeight > innerTop+1 && innerTop+5+optionY < innerBottom-1) { + editor.render((innerLeft+innerRight-optionWidth)/2-5, innerTop+5+optionY, optionWidth); + } + optionY += optionHeight + 5; + } + GlStateManager.disableDepth(); + if(optionY > 0) { + barSize = LerpUtils.clampZeroOne((float)(innerBottom-innerTop-2)/(optionY+5+optionsScroll.getValue())); + } + } + + GlScissorStack.pop(scaledResolution); + + GL11.glDisable(GL11.GL_SCISSOR_TEST); + if(getSelectedCategory() != null && currentConfigEditing.containsKey(getSelectedCategory())) { + int optionYOverlay = -optionsScroll.getValue(); + ConfigProcessor.ProcessedCategory cat = currentConfigEditing.get(getSelectedCategory()); + int optionWidthDefault = innerRight-innerLeft-20; + + GlStateManager.translate(0, 0, 10); + GlStateManager.enableDepth(); + Set<Integer> activeAccordions = new HashSet<>(); + for(ConfigProcessor.ProcessedOption option : getOptionsInCategory(cat).values()) { + int optionWidth = optionWidthDefault; + if(option.accordionId >= 0) { + if(!activeAccordions.contains(option.accordionId)) { + continue; + } + optionWidth = optionWidthDefault - 2*innerPadding; + } + + GuiOptionEditor editor = option.editor; + if(editor == null) { + continue; + } + if(editor instanceof GuiOptionEditorAccordion) { + GuiOptionEditorAccordion accordion = (GuiOptionEditorAccordion) editor; + if(accordion.getToggled()) { + activeAccordions.add(accordion.getAccordionId()); + } + } + int optionHeight = editor.getHeight(); + if(innerTop+5+optionYOverlay+optionHeight > innerTop+1 && innerTop+5+optionYOverlay < innerBottom-1) { + editor.renderOverlay((innerLeft+innerRight-optionWidth)/2-5, innerTop+5+optionYOverlay, optionWidth); + } + optionYOverlay += optionHeight + 5; + } + GlStateManager.disableDepth(); + GlStateManager.translate(0, 0, -10); + } + GL11.glEnable(GL11.GL_SCISSOR_TEST); + + float barStart = optionsScroll.getValue() / (float)(optionY + optionsScroll.getValue()); + float barEnd = barStart+barSize; + if(barEnd > 1) { + barEnd = 1; + if(optionsScroll.getTarget()/(float)(optionY + optionsScroll.getValue())+barSize < 1) { + int target = optionsScroll.getTarget(); + optionsScroll.setValue((int)Math.ceil((optionY+5+optionsScroll.getValue())-barSize*(optionY+5+optionsScroll.getValue()))); + optionsScroll.setTarget(target); + } else { + optionsScroll.setValue((int)Math.ceil((optionY+5+optionsScroll.getValue())-barSize*(optionY+5+optionsScroll.getValue()))); + } + } + int dist = innerBottom-innerTop-12; + Gui.drawRect(innerRight-10, innerTop+5, innerRight-5, innerBottom-5, 0xff101010); + Gui.drawRect(innerRight-9, innerTop+6+(int)(dist*barStart), innerRight-6, innerTop+6+(int)(dist*barEnd), 0xff303030); + + for(int socialIndex=0; socialIndex<socialsIco.length; socialIndex++) { + Minecraft.getMinecraft().getTextureManager().bindTexture(socialsIco[socialIndex]); + GlStateManager.color(1, 1, 1, 1); + int socialLeft = x+xSize-23-18*socialIndex; + RenderUtils.drawTexturedRect(socialLeft, y+7, 16, 16, GL11.GL_LINEAR); + + if(mouseX >= socialLeft && mouseX <= socialLeft+16 && + mouseY >= y+6 && mouseY <= y+23) { + tooltipToDisplay = Lists.newArrayList(EnumChatFormatting.YELLOW+"Go to: "+EnumChatFormatting.RESET+socialsLink[socialIndex]); + } + } + + GlScissorStack.clear(); + + if(tooltipToDisplay != null) { + TextRenderUtils.drawHoveringText(tooltipToDisplay, mouseX, mouseY, width, height, -1, fr); + } + + GlStateManager.translate(0, 0, -2); + } + + public boolean mouseInput(int mouseX, int mouseY) { + ScaledResolution scaledResolution = new ScaledResolution(Minecraft.getMinecraft()); + int width = scaledResolution.getScaledWidth(); + int height = scaledResolution.getScaledHeight(); + + int xSize = Math.min(width-100/scaledResolution.getScaleFactor(), 500); + int ySize = Math.min(height-100/scaledResolution.getScaleFactor(), 400); + + int x = (scaledResolution.getScaledWidth() - xSize)/2; + int y = (scaledResolution.getScaledHeight() - ySize)/2; + + int adjScaleFactor = Math.max(2, scaledResolution.getScaleFactor()); + + int innerPadding = 20/adjScaleFactor; + int innerTop = y+49+innerPadding; + int innerBottom = y+ySize-5-innerPadding; + int innerLeft = x+149+innerPadding; + int innerRight = x+xSize-5-innerPadding; + + int dWheel = Mouse.getEventDWheel(); + if(mouseY > innerTop && mouseY < innerBottom && dWheel != 0) { + if(dWheel < 0) { + dWheel = -1; + } + if(dWheel > 0) { + dWheel = 1; + } + if(mouseX < innerLeft) { + int newTarget = categoryScroll.getTarget() - dWheel*30; + if(newTarget < 0) { + newTarget = 0; + } + + float catBarSize = 1; + int catY = -newTarget; + for(Map.Entry<String, ConfigProcessor.ProcessedCategory> entry : getCurrentConfigEditing().entrySet()) { + if(getSelectedCategory() == null) { + setSelectedCategory(entry.getKey()); + } + + catY += 15; + if(catY > 0) { + catBarSize = LerpUtils.clampZeroOne((float)(innerBottom-innerTop-2)/(catY+5+newTarget)); + } + } + + int barMax = (int)Math.floor((catY+5+newTarget)-catBarSize*(catY+5+newTarget)); + if(newTarget > barMax) { + newTarget = barMax; + } + categoryScroll.resetTimer(); + categoryScroll.setTarget(newTarget); + } else { + int newTarget = optionsScroll.getTarget() - dWheel*30; + if(newTarget < 0) { + newTarget = 0; + } + + float barSize = 1; + int optionY = -newTarget; + if(getSelectedCategory() != null && getCurrentConfigEditing() != null && getCurrentConfigEditing().containsKey(getSelectedCategory())) { + ConfigProcessor.ProcessedCategory cat = getCurrentConfigEditing().get(getSelectedCategory()); + Set<Integer> activeAccordions = new HashSet<>(); + for(ConfigProcessor.ProcessedOption option : getOptionsInCategory(cat).values()) { + if(option.accordionId >= 0) { + if(!activeAccordions.contains(option.accordionId)) { + continue; + } + } + + GuiOptionEditor editor = option.editor; + if(editor == null) { + continue; + } + if(editor instanceof GuiOptionEditorAccordion) { + GuiOptionEditorAccordion accordion = (GuiOptionEditorAccordion) editor; + if(accordion.getToggled()) { + activeAccordions.add(accordion.getAccordionId()); + } + } + optionY += editor.getHeight() + 5; + + if(optionY > 0) { + barSize = LerpUtils.clampZeroOne((float)(innerBottom-innerTop-2)/(optionY+5 + newTarget)); + } + } + } + + int barMax = (int)Math.floor((optionY+5+newTarget)-barSize*(optionY+5+newTarget)); + if(newTarget > barMax) { + newTarget = barMax; + } + optionsScroll.setTimeToReachTarget(Math.min(150, Math.max(10, 5*Math.abs(newTarget - optionsScroll.getValue())))); + optionsScroll.resetTimer(); + optionsScroll.setTarget(newTarget); + } + } else if(Mouse.getEventButtonState() && Mouse.getEventButton() == 0) { + if(getCurrentConfigEditing() != null) { + int catY = -categoryScroll.getValue(); + for(Map.Entry<String, ConfigProcessor.ProcessedCategory> entry : getCurrentConfigEditing().entrySet()) { + if(getSelectedCategory() == null) { + setSelectedCategory(entry.getKey()); + } + if(mouseX >= x+5 && mouseX <= x+145 && + mouseY >= y+70+catY-7 && mouseY <= y+70+catY+7) { + setSelectedCategory(entry.getKey()); + return true; + } + catY += 15; + } + } + + for(int socialIndex=0; socialIndex<socialsLink.length; socialIndex++) { + int socialLeft = x+xSize-23-18*socialIndex; + + if(mouseX >= socialLeft && mouseX <= socialLeft+16 && + mouseY >= y+6 && mouseY <= y+23) { + try { + Desktop.getDesktop().browse(new URI(socialsLink[socialIndex])); + } catch(Exception ignored) {} + return true; + } + } + } + + int optionY = -optionsScroll.getValue(); + if(getSelectedCategory() != null && getCurrentConfigEditing() != null && getCurrentConfigEditing().containsKey(getSelectedCategory())) { + int optionWidthDefault = innerRight-innerLeft-20; + ConfigProcessor.ProcessedCategory cat = getCurrentConfigEditing().get(getSelectedCategory());Set<Integer> activeAccordions = new HashSet<>(); + for(ConfigProcessor.ProcessedOption option : getOptionsInCategory(cat).values()) { + int optionWidth = optionWidthDefault; + if(option.accordionId >= 0) { + if(!activeAccordions.contains(option.accordionId)) { + continue; + } + optionWidth = optionWidthDefault - 2*innerPadding; + } + + GuiOptionEditor editor = option.editor; + if(editor == null) { + continue; + } + if(editor instanceof GuiOptionEditorAccordion) { + GuiOptionEditorAccordion accordion = (GuiOptionEditorAccordion) editor; + if(accordion.getToggled()) { + activeAccordions.add(accordion.getAccordionId()); + } + } + if(editor.mouseInputOverlay((innerLeft+innerRight-optionWidth)/2-5, innerTop+5+optionY, optionWidth, mouseX, mouseY)) { + return true; + } + optionY += editor.getHeight() + 5; + } + } + + if(mouseX > innerLeft && mouseX < innerRight && + mouseY > innerTop && mouseY < innerBottom) { + optionY = -optionsScroll.getValue(); + if(getSelectedCategory() != null && getCurrentConfigEditing() != null && getCurrentConfigEditing().containsKey(getSelectedCategory())) { + int optionWidthDefault = innerRight-innerLeft-20; + ConfigProcessor.ProcessedCategory cat = getCurrentConfigEditing().get(getSelectedCategory()); + Set<Integer> activeAccordions = new HashSet<>(); + for(ConfigProcessor.ProcessedOption option : getOptionsInCategory(cat).values()) { + int optionWidth = optionWidthDefault; + if(option.accordionId >= 0) { + if(!activeAccordions.contains(option.accordionId)) { + continue; + } + optionWidth = optionWidthDefault - 2*innerPadding; + } + + GuiOptionEditor editor = option.editor; + if(editor == null) { + continue; + } + if(editor instanceof GuiOptionEditorAccordion) { + GuiOptionEditorAccordion accordion = (GuiOptionEditorAccordion) editor; + if(accordion.getToggled()) { + activeAccordions.add(accordion.getAccordionId()); + } + } + if(editor.mouseInput((innerLeft+innerRight-optionWidth)/2-5, innerTop+5+optionY, optionWidth, mouseX, mouseY)) { + return true; + } + optionY += editor.getHeight() + 5; + } + } + } + + return true; + } + + public boolean keyboardInput() { + ScaledResolution scaledResolution = new ScaledResolution(Minecraft.getMinecraft()); + int width = scaledResolution.getScaledWidth(); + + int xSize = Math.min(width-100/scaledResolution.getScaleFactor(), 500); + + int adjScaleFactor = Math.max(2, scaledResolution.getScaleFactor()); + + int innerPadding = 20/adjScaleFactor; + int innerWidth = xSize-154-innerPadding*2; + + if(getSelectedCategory() != null && getCurrentConfigEditing() != null && getCurrentConfigEditing().containsKey(getSelectedCategory())) { + ConfigProcessor.ProcessedCategory cat = getCurrentConfigEditing().get(getSelectedCategory()); + Set<Integer> activeAccordions = new HashSet<>(); + for(ConfigProcessor.ProcessedOption option : getOptionsInCategory(cat).values()) { + if(option.accordionId >= 0) { + if(!activeAccordions.contains(option.accordionId)) { + continue; + } + } + + GuiOptionEditor editor = option.editor; + if(editor == null) { + continue; + } + if(editor instanceof GuiOptionEditorAccordion) { + GuiOptionEditorAccordion accordion = (GuiOptionEditorAccordion) editor; + if(accordion.getToggled()) { + activeAccordions.add(accordion.getAccordionId()); + } + } + if(editor.keyboardInput()) { + return true; + } + } + } + + return true; + } +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/core/BackgroundBlur.java b/src/main/java/com/thatgravyboat/skyblockhud/core/BackgroundBlur.java new file mode 100644 index 0000000..6782052 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/core/BackgroundBlur.java @@ -0,0 +1,231 @@ +package com.thatgravyboat.skyblockhud.core; + +import com.thatgravyboat.skyblockhud.core.util.render.RenderUtils; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Gui; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.OpenGlHelper; +import net.minecraft.client.shader.Framebuffer; +import net.minecraft.client.shader.Shader; +import net.minecraft.util.Matrix4f; +import net.minecraftforge.client.event.EntityViewRenderEvent; +import net.minecraftforge.client.event.RenderGameOverlayEvent; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.fml.common.eventhandler.EventPriority; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import org.lwjgl.opengl.GL11; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +public class BackgroundBlur { + + private static HashMap<Float, Framebuffer> blurOutput = new HashMap<>(); + private static HashMap<Float, Long> lastBlurUse = new HashMap<>(); + private static long lastBlur = 0; + private static HashSet<Float> requestedBlurs = new HashSet<>(); + + private static int fogColour = 0; + private static boolean registered = false; + public static void registerListener() { + if(!registered) { + registered = true; + MinecraftForge.EVENT_BUS.register(new BackgroundBlur()); + } + } + + private static boolean shouldBlur = true; + + public static void markDirty() { + if(Minecraft.getMinecraft().theWorld != null) { + shouldBlur = true; + } + } + + public static void processBlurs() { + if(shouldBlur) { + shouldBlur = false; + + long currentTime = System.currentTimeMillis(); + + for(float blur : requestedBlurs) { + lastBlur = currentTime; + lastBlurUse.put(blur, currentTime); + + int width = Minecraft.getMinecraft().displayWidth; + int height = Minecraft.getMinecraft().displayHeight; + + Framebuffer output = blurOutput.computeIfAbsent(blur, k -> { + Framebuffer fb = new Framebuffer(width, height, false); + fb.setFramebufferFilter(GL11.GL_NEAREST); + return fb; + }); + + output.framebufferWidth = output.framebufferTextureWidth = width; + output.framebufferHeight = output.framebufferTextureHeight = height; + + blurBackground(output, blur); + } + + Set<Float> remove = new HashSet<>(); + for(Map.Entry<Float, Long> entry : lastBlurUse.entrySet()) { + if(currentTime - entry.getValue() > 30*1000) { + remove.add(entry.getKey()); + } + } + remove.remove(5f); + + lastBlurUse.keySet().removeAll(remove); + blurOutput.keySet().removeAll(remove); + + requestedBlurs.clear(); + } + } + + @SubscribeEvent(priority = EventPriority.HIGHEST) + public void onScreenRender(RenderGameOverlayEvent.Pre event) { + if(event.type == RenderGameOverlayEvent.ElementType.ALL) { + processBlurs(); + } + } + + @SubscribeEvent + public void onFogColour(EntityViewRenderEvent.FogColors event) { + fogColour = 0xff000000; + fogColour |= ((int)(event.red*255) & 0xFF) << 16; + fogColour |= ((int)(event.green*255) & 0xFF) << 8; + fogColour |= (int)(event.blue*255) & 0xFF; + } + + private static Shader blurShaderHorz = null; + private static Shader blurShaderVert = null; + private static Framebuffer blurOutputHorz = null; + + /** + * Creates a projection matrix that projects from our coordinate space [0->width; 0->height] to OpenGL coordinate + * space [-1 -> 1; 1 -> -1] (Note: flipped y-axis). + * + * This is so that we can render to and from the framebuffer in a way that is familiar to us, instead of needing to + * apply scales and translations manually. + */ + private static Matrix4f createProjectionMatrix(int width, int height) { + Matrix4f projMatrix = new Matrix4f(); + projMatrix.setIdentity(); + projMatrix.m00 = 2.0F / (float)width; + projMatrix.m11 = 2.0F / (float)(-height); + projMatrix.m22 = -0.0020001999F; + projMatrix.m33 = 1.0F; + projMatrix.m03 = -1.0F; + projMatrix.m13 = 1.0F; + projMatrix.m23 = -1.0001999F; + return projMatrix; + } + + private static void blurBackground(Framebuffer output, float blurFactor) { + if(!OpenGlHelper.isFramebufferEnabled() || !OpenGlHelper.areShadersSupported()) return; + + int width = Minecraft.getMinecraft().displayWidth; + int height = Minecraft.getMinecraft().displayHeight; + + GlStateManager.matrixMode(GL11.GL_PROJECTION); + GlStateManager.loadIdentity(); + GlStateManager.ortho(0.0D, width, height, 0.0D, 1000.0D, 3000.0D); + GlStateManager.matrixMode(GL11.GL_MODELVIEW); + GlStateManager.loadIdentity(); + GlStateManager.translate(0.0F, 0.0F, -2000.0F); + + if(blurOutputHorz == null) { + blurOutputHorz = new Framebuffer(width, height, false); + blurOutputHorz.setFramebufferFilter(GL11.GL_NEAREST); + } + if(blurOutputHorz == null || output == null) { + return; + } + if(blurOutputHorz.framebufferWidth != width || blurOutputHorz.framebufferHeight != height) { + blurOutputHorz.createBindFramebuffer(width, height); + blurShaderHorz.setProjectionMatrix(createProjectionMatrix(width, height)); + Minecraft.getMinecraft().getFramebuffer().bindFramebuffer(false); + } + + try { + blurShaderHorz = new Shader(Minecraft.getMinecraft().getResourceManager(), "blur", + Minecraft.getMinecraft().getFramebuffer(), blurOutputHorz); + blurShaderHorz.getShaderManager().getShaderUniform("BlurDir").set(1, 0); + blurShaderHorz.setProjectionMatrix(createProjectionMatrix(width, height)); + } catch(Exception ignored) { } + try { + blurShaderVert = new Shader(Minecraft.getMinecraft().getResourceManager(), "blur", + blurOutputHorz, output); + blurShaderVert.getShaderManager().getShaderUniform("BlurDir").set(0, 1); + blurShaderVert.setProjectionMatrix(createProjectionMatrix(width, height)); + } catch(Exception ignored) { } + if(blurShaderHorz != null && blurShaderVert != null) { + if(blurShaderHorz.getShaderManager().getShaderUniform("Radius") == null) { + //Corrupted shader? + return; + } + + blurShaderHorz.getShaderManager().getShaderUniform("Radius").set(blurFactor); + blurShaderVert.getShaderManager().getShaderUniform("Radius").set(blurFactor); + + GL11.glPushMatrix(); + /*GL30.glBindFramebuffer(GL30.GL_READ_FRAMEBUFFER, Minecraft.getMinecraft().getFramebuffer().framebufferObject); + GL30.glBindFramebuffer(GL30.GL_DRAW_FRAMEBUFFER, output.framebufferObject); + GL30.glBlitFramebuffer(0, 0, width, height, + 0, 0, output.framebufferWidth, output.framebufferHeight, + GL11.GL_COLOR_BUFFER_BIT, GL11.GL_NEAREST);*/ + + blurShaderHorz.loadShader(0); + blurShaderVert.loadShader(0); + GlStateManager.enableDepth(); + GL11.glPopMatrix(); + + Minecraft.getMinecraft().getFramebuffer().bindFramebuffer(false); + } + } + + public static void renderBlurredBackground(float blurStrength, int screenWidth, int screenHeight, + int x, int y, int blurWidth, int blurHeight) { + renderBlurredBackground(blurStrength, screenWidth, screenHeight, x, y, blurWidth, blurHeight, false); + } + + /** + * Renders a subsection of the blurred framebuffer on to the corresponding section of the screen. + * Essentially, this method will "blur" the background inside the bounds specified by [x->x+blurWidth, y->y+blurHeight] + */ + public static void renderBlurredBackground(float blurStrength, int screenWidth, int screenHeight, + int x, int y, int blurWidth, int blurHeight, boolean forcedUpdate) { + if(!OpenGlHelper.isFramebufferEnabled() || !OpenGlHelper.areShadersSupported()) return; + if(blurStrength < 0.5) return; + requestedBlurs.add(blurStrength); + + long currentTime = System.currentTimeMillis(); + if(currentTime - lastBlur > 300) { + shouldBlur = true; + if(currentTime - lastBlur > 400 && forcedUpdate) return; + } + + if(blurOutput.isEmpty()) return; + + Framebuffer fb = blurOutput.get(blurStrength); + if(fb == null) { + fb = blurOutput.values().iterator().next(); + } + + float uMin = x/(float)screenWidth; + float uMax = (x+blurWidth)/(float)screenWidth; + float vMin = (screenHeight-y)/(float)screenHeight; + float vMax = (screenHeight-y-blurHeight)/(float)screenHeight; + + GlStateManager.depthMask(false); + Gui.drawRect(x, y, x+blurWidth, y+blurHeight, fogColour); + fb.bindFramebufferTexture(); + GlStateManager.color(1f, 1f, 1f, 1f); + RenderUtils.drawTexturedRect(x, y, blurWidth, blurHeight, uMin, uMax, vMin, vMax); + fb.unbindFramebufferTexture(); + GlStateManager.depthMask(true); + } + +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/core/ChromaColour.java b/src/main/java/com/thatgravyboat/skyblockhud/core/ChromaColour.java new file mode 100644 index 0000000..b9f4e79 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/core/ChromaColour.java @@ -0,0 +1,95 @@ +package com.thatgravyboat.skyblockhud.core; + +import java.awt.*; + +public class ChromaColour { + + public static String special(int chromaSpeed, int alpha, int rgb) { + return special(chromaSpeed, alpha, (rgb & 0xFF0000) >> 16, (rgb & 0x00FF00) >> 8, (rgb & 0x0000FF)); + } + + private static final int RADIX = 10; + + public static String special(int chromaSpeed, int alpha, int r, int g, int b) { + StringBuilder sb = new StringBuilder(); + sb.append(Integer.toString(chromaSpeed, RADIX)).append(":"); + sb.append(Integer.toString(alpha, RADIX)).append(":"); + sb.append(Integer.toString(r, RADIX)).append(":"); + sb.append(Integer.toString(g, RADIX)).append(":"); + sb.append(Integer.toString(b, RADIX)); + return sb.toString(); + } + + private static int[] decompose(String csv) { + String[] split = csv.split(":"); + + int[] arr = new int[split.length]; + + + for(int i=0; i<split.length; i++) { + arr[i] = Integer.parseInt(split[split.length-1-i], RADIX); + } + return arr; + } + + public static int specialToSimpleRGB(String special) { + int[] d = decompose(special); + int r = d[2]; + int g = d[1]; + int b = d[0]; + int a = d[3]; + int chr = d[4]; + + return (a & 0xFF) << 24 | (r & 0xFF) << 16 | (g & 0xFF) << 8 | (b & 0xFF); + } + + public static int getSpeed(String special) { + return decompose(special)[4]; + } + + public static float getSecondsForSpeed(int speed) { + return (255-speed)/254f*(MAX_CHROMA_SECS-MIN_CHROMA_SECS)+MIN_CHROMA_SECS; + } + + private static final int MIN_CHROMA_SECS = 1; + private static final int MAX_CHROMA_SECS = 60; + + public static long startTime = -1; + public static int specialToChromaRGB(String special) { + if(startTime < 0) startTime = System.currentTimeMillis(); + + int[] d = decompose(special); + int chr = d[4]; + int a = d[3]; + int r = d[2]; + int g = d[1]; + int b = d[0]; + + float[] hsv = Color.RGBtoHSB(r, g, b, null); + + if(chr > 0) { + float seconds = getSecondsForSpeed(chr); + hsv[0] += (System.currentTimeMillis()-startTime)/1000f/seconds; + hsv[0] %= 1; + if(hsv[0] < 0) hsv[0] += 1; + } + + return (a & 0xFF) << 24 | (Color.HSBtoRGB(hsv[0], hsv[1], hsv[2]) & 0x00FFFFFF); + } + + public static int rotateHue(int argb, int degrees) { + int a = (argb >> 24) & 0xFF; + int r = (argb >> 16) & 0xFF; + int g = (argb >> 8) & 0xFF; + int b = (argb) & 0xFF; + + float[] hsv = Color.RGBtoHSB(r, g, b, null); + + hsv[0] += degrees/360f; + hsv[0] %= 1; + + return (a & 0xFF) << 24 | (Color.HSBtoRGB(hsv[0], hsv[1], hsv[2]) & 0x00FFFFFF); + } + + +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/core/GlScissorStack.java b/src/main/java/com/thatgravyboat/skyblockhud/core/GlScissorStack.java new file mode 100644 index 0000000..6f21e9a --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/core/GlScissorStack.java @@ -0,0 +1,87 @@ +package com.thatgravyboat.skyblockhud.core; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.ScaledResolution; +import org.lwjgl.opengl.GL11; + +import java.util.LinkedList; + +public class GlScissorStack { + + private static class Bounds { + int left; + int top; + int right; + int bottom; + + public Bounds(int left, int top, int right, int bottom) { + this.left = left; + this.top = top; + this.right = right; + this.bottom = bottom; + } + + public Bounds createSubBound(int left, int top, int right, int bottom) { + left = Math.max(left, this.left); + top = Math.max(top, this.top); + right = Math.min(right, this.right); + bottom = Math.min(bottom, this.bottom); + + if(top > bottom) { + top = bottom; + } + if(left > right) { + left = right; + } + + return new Bounds(left, top, right, bottom); + } + + public void set(ScaledResolution scaledResolution) { + int height = Minecraft.getMinecraft().displayHeight; + int scale = scaledResolution.getScaleFactor(); + GL11.glScissor(left*scale, height-bottom*scale, (right-left)*scale, (bottom-top)*scale); + } + } + + private static final LinkedList<Bounds> boundsStack = new LinkedList<>(); + + public static void push(int left, int top, int right, int bottom, ScaledResolution scaledResolution) { + if(right < left) { + int temp = right; + right = left; + left = temp; + } + if(bottom < top) { + int temp = bottom; + bottom = top; + top = temp; + } + if(boundsStack.isEmpty()) { + boundsStack.push(new Bounds(left, top, right, bottom)); + } else { + boundsStack.push(boundsStack.peek().createSubBound(left, top, right, bottom)); + } + if(!boundsStack.isEmpty()) { + boundsStack.peek().set(scaledResolution); + } + GL11.glEnable(GL11.GL_SCISSOR_TEST); + } + + public static void pop(ScaledResolution scaledResolution) { + if(!boundsStack.isEmpty()) { + boundsStack.pop(); + } + if(boundsStack.isEmpty()) { + GL11.glDisable(GL11.GL_SCISSOR_TEST); + } else { + boundsStack.peek().set(scaledResolution); + } + } + + public static void clear() { + boundsStack.clear(); + GL11.glDisable(GL11.GL_SCISSOR_TEST); + } + +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/core/GuiElement.java b/src/main/java/com/thatgravyboat/skyblockhud/core/GuiElement.java new file mode 100644 index 0000000..94d2375 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/core/GuiElement.java @@ -0,0 +1,8 @@ +package com.thatgravyboat.skyblockhud.core; + +public abstract class GuiElement { + + public abstract void render(); + public abstract boolean mouseInput(int mouseX, int mouseY); + public abstract boolean keyboardInput(); +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/core/GuiElementBoolean.java b/src/main/java/com/thatgravyboat/skyblockhud/core/GuiElementBoolean.java new file mode 100644 index 0000000..d403bef --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/core/GuiElementBoolean.java @@ -0,0 +1,121 @@ +package com.thatgravyboat.skyblockhud.core; + +import com.thatgravyboat.skyblockhud.core.util.lerp.LerpUtils; +import com.thatgravyboat.skyblockhud.core.util.render.RenderUtils; +import com.thatgravyboat.skyblockhud.GuiTextures; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.util.ResourceLocation; +import org.lwjgl.input.Mouse; + +import java.util.function.Consumer; + +public class GuiElementBoolean extends GuiElement { + + public int x; + public int y; + private boolean value; + private int clickRadius; + private Consumer<Boolean> toggleCallback; + + private boolean previewValue; + private int animation = 0; + private long lastMillis = 0; + + private static final int xSize = 48; + private static final int ySize = 14; + + public GuiElementBoolean(int x, int y, boolean value, Consumer<Boolean> toggleCallback) { + this(x, y, value, 0, toggleCallback); + } + + public GuiElementBoolean(int x, int y, boolean value, int clickRadius, Consumer<Boolean> toggleCallback) { + this.x = x; + this.y = y; + this.value = value; + this.previewValue = value; + this.clickRadius = clickRadius; + this.toggleCallback = toggleCallback; + this.lastMillis = System.currentTimeMillis(); + + if(value) animation = 36; + } + + @Override + public void render() { + GlStateManager.color(1, 1, 1, 1); + Minecraft.getMinecraft().getTextureManager().bindTexture(GuiTextures.BAR); + RenderUtils.drawTexturedRect(x, y, xSize, ySize); + + ResourceLocation buttonLoc = GuiTextures.ON; + long currentMillis = System.currentTimeMillis(); + long deltaMillis = currentMillis - lastMillis; + lastMillis = currentMillis; + boolean passedLimit = false; + if(previewValue != value) { + if((previewValue && animation > 12) || + (!previewValue && animation < 24)) { + passedLimit = true; + } + } + if(previewValue != passedLimit) { + animation += deltaMillis/10; + } else { + animation -= deltaMillis/10; + } + lastMillis -= deltaMillis%10; + + if(previewValue == value) { + animation = Math.max(0, Math.min(36, animation)); + } else if(!passedLimit) { + if(previewValue) { + animation = Math.max(0, Math.min(12, animation)); + } else { + animation = Math.max(24, Math.min(36, animation)); + } + } else { + if(previewValue) { + animation = Math.max(12, animation); + } else { + animation = Math.min(24, animation); + } + } + + int animation = (int)(LerpUtils.sigmoidZeroOne(this.animation/36f)*36); + if(animation < 3) { + buttonLoc = GuiTextures.OFF; + } else if(animation < 13) { + buttonLoc = GuiTextures.ONE; + } else if(animation < 23) { + buttonLoc = GuiTextures.TWO; + } else if(animation < 33) { + buttonLoc = GuiTextures.THREE; + } + + Minecraft.getMinecraft().getTextureManager().bindTexture(buttonLoc); + RenderUtils.drawTexturedRect(x+animation, y, 12, 14); + } + + @Override + public boolean mouseInput(int mouseX, int mouseY) { + if(mouseX > x-clickRadius && mouseX < x+xSize+clickRadius && + mouseY > y-clickRadius && mouseY < y+ySize+clickRadius) { + if(Mouse.getEventButton() == 0) { + if(Mouse.getEventButtonState()) { + previewValue = !value; + } else if(previewValue == !value) { + value = !value; + toggleCallback.accept(value); + } + } + } else { + previewValue = value; + } + return false; + } + + @Override + public boolean keyboardInput() { + return false; + } +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/core/GuiElementColour.java b/src/main/java/com/thatgravyboat/skyblockhud/core/GuiElementColour.java new file mode 100644 index 0000000..8774595 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/core/GuiElementColour.java @@ -0,0 +1,368 @@ +package com.thatgravyboat.skyblockhud.core; + +import com.thatgravyboat.skyblockhud.core.util.render.RenderUtils; +import com.thatgravyboat.skyblockhud.core.util.render.TextRenderUtils; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Gui; +import net.minecraft.client.gui.ScaledResolution; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.texture.DynamicTexture; +import net.minecraft.util.EnumChatFormatting; +import net.minecraft.util.ResourceLocation; +import org.lwjgl.input.Keyboard; +import org.lwjgl.input.Mouse; +import org.lwjgl.opengl.GL11; + +import java.awt.*; +import java.awt.image.BufferedImage; +import java.util.function.Consumer; + +public class GuiElementColour extends GuiElement { + + public static final ResourceLocation colour_selector_dot = new ResourceLocation("skyblockhud:core/colour_selector_dot.png"); + public static final ResourceLocation colour_selector_bar = new ResourceLocation("skyblockhud:core/colour_selector_bar.png"); + public static final ResourceLocation colour_selector_bar_alpha = new ResourceLocation("skyblockhud:core/colour_selector_bar_alpha.png"); + public static final ResourceLocation colour_selector_chroma = new ResourceLocation("skyblockhud:core/colour_selector_chroma.png"); + + private static final ResourceLocation colourPickerLocation = new ResourceLocation("mbcore:dynamic/colourpicker"); + private static final ResourceLocation colourPickerBarValueLocation = new ResourceLocation("mbcore:dynamic/colourpickervalue"); + private static final ResourceLocation colourPickerBarOpacityLocation = new ResourceLocation("mbcore:dynamic/colourpickeropacity"); + private final GuiElementTextField hexField = new GuiElementTextField("", + GuiElementTextField.SCALE_TEXT | GuiElementTextField.FORCE_CAPS | GuiElementTextField.NO_SPACE); + + private int x; + private int y; + private final int xSize = 119; + private final int ySize = 89; + + private float wheelAngle = 0; + private float wheelRadius = 0; + + private int clickedComponent = -1; + + private Consumer<String> colourChangedCallback; + private Runnable closeCallback; + private String colour; + + public GuiElementColour(int x, int y, String initialColour, Consumer<String> colourChangedCallback, + Runnable closeCallback) { + + final ScaledResolution scaledResolution = new ScaledResolution(Minecraft.getMinecraft()); + + this.y = Math.max(10, Math.min(scaledResolution.getScaledHeight()-ySize-10, y)); + this.x = Math.max(10, Math.min(scaledResolution.getScaledWidth()-xSize-10, x)); + + this.colour = initialColour; + this.colourChangedCallback = colourChangedCallback; + this.closeCallback = closeCallback; + + int colour = ChromaColour.specialToSimpleRGB(initialColour); + Color c = new Color(colour); + float[] hsv = Color.RGBtoHSB(c.getRed(), c.getGreen(), c.getBlue(), null); + updateAngleAndRadius(hsv); + } + + public void updateAngleAndRadius(float[] hsv) { + this.wheelRadius = hsv[1]; + this.wheelAngle = hsv[0]*360; + } + + public void render() { + RenderUtils.drawFloatingRectDark(x, y, xSize, ySize); + + int currentColour = ChromaColour.specialToSimpleRGB(colour); + Color c = new Color(currentColour, true); + float[] hsv = Color.RGBtoHSB(c.getRed(), c.getGreen(), c.getBlue(), null); + + BufferedImage bufferedImage = new BufferedImage(288, 288, BufferedImage.TYPE_INT_ARGB); + float borderRadius = 0.05f; + if(Keyboard.isKeyDown(Keyboard.KEY_N)) borderRadius = 0; + for(int x=-16; x<272; x++) { + for(int y=-16; y<272; y++) { + float radius = (float) Math.sqrt(((x-128)*(x-128)+(y-128)*(y-128))/16384f); + float angle = (float) Math.toDegrees(Math.atan((128-x)/(y-128+1E-5))+Math.PI/2); + if(y < 128) angle += 180; + if(radius <= 1) { + int rgb = Color.getHSBColor(angle/360f, (float)Math.pow(radius, 1.5f), hsv[2]).getRGB(); + bufferedImage.setRGB(x+16, y+16, rgb); + } else if(radius <= 1+borderRadius) { + float invBlackAlpha = Math.abs(radius-1-borderRadius/2)/borderRadius*2; + float blackAlpha = 1-invBlackAlpha; + + if(radius > 1+borderRadius/2) { + bufferedImage.setRGB(x+16, y+16, (int)(blackAlpha*255) << 24); + } else { + Color col = Color.getHSBColor(angle/360f, 1, hsv[2]); + int rgb = (int)(col.getRed()*invBlackAlpha) << 16 | + (int)(col.getGreen()*invBlackAlpha) << 8 | + (int)(col.getBlue()*invBlackAlpha); + bufferedImage.setRGB(x+16, y+16, 0xff000000 | rgb); + } + + } + } + } + + BufferedImage bufferedImageValue = new BufferedImage(10, 64, BufferedImage.TYPE_INT_ARGB); + for(int x=0; x<10; x++) { + for(int y=0; y<64; y++) { + if((x == 0 || x == 9) && (y == 0 || y == 63)) continue; + + int rgb = Color.getHSBColor(wheelAngle/360, wheelRadius, (64-y)/64f).getRGB(); + bufferedImageValue.setRGB(x, y, rgb); + } + } + + BufferedImage bufferedImageOpacity = new BufferedImage(10, 64, BufferedImage.TYPE_INT_ARGB); + for(int x=0; x<10; x++) { + for(int y=0; y<64; y++) { + if((x == 0 || x == 9) && (y == 0 || y == 63)) continue; + + int rgb = (currentColour & 0x00FFFFFF) | (Math.min(255, (64-y)*4) << 24); + bufferedImageOpacity.setRGB(x, y, rgb); + } + } + + float selradius = (float)Math.pow(wheelRadius, 1/1.5f)*32; + int selx = (int)(Math.cos(Math.toRadians(wheelAngle))*selradius); + int sely = (int)(Math.sin(Math.toRadians(wheelAngle))*selradius); + + Minecraft.getMinecraft().getTextureManager().bindTexture(colour_selector_bar_alpha); + GlStateManager.color(1, 1, 1, 1); + RenderUtils.drawTexturedRect(x+5+64+5+10+5, y+5, 10, 64, GL11.GL_NEAREST); + + Minecraft.getMinecraft().getTextureManager().loadTexture(colourPickerBarValueLocation, new DynamicTexture(bufferedImageValue)); + Minecraft.getMinecraft().getTextureManager().bindTexture(colourPickerBarValueLocation); + GlStateManager.color(1, 1, 1, 1); + RenderUtils.drawTexturedRect(x+5+64+5, y+5, 10, 64, GL11.GL_NEAREST); + + Minecraft.getMinecraft().getTextureManager().loadTexture(colourPickerBarOpacityLocation, new DynamicTexture(bufferedImageOpacity)); + Minecraft.getMinecraft().getTextureManager().bindTexture(colourPickerBarOpacityLocation); + GlStateManager.color(1, 1, 1, 1); + RenderUtils.drawTexturedRect(x+5+64+5+10+5, y+5, 10, 64, GL11.GL_NEAREST); + + int chromaSpeed = ChromaColour.getSpeed(colour); + int currentColourChroma = ChromaColour.specialToChromaRGB(colour); + Color cChroma = new Color(currentColourChroma, true); + float hsvChroma[] = Color.RGBtoHSB(cChroma.getRed(), cChroma.getGreen(), cChroma.getBlue(), null); + + if(chromaSpeed > 0) { + Gui.drawRect(x+5+64+5+10+5+10+5+1, y+5+1, + x+5+64+5+10+5+10+5+10-1, y+5+64-1, + Color.HSBtoRGB(hsvChroma[0], 0.8f, 0.8f)); + } else { + Gui.drawRect(x+5+64+5+10+5+10+5+1, y+5+27+1, + x+5+64+5+10+5+10+5+10-1, y+5+37-1, + Color.HSBtoRGB((hsvChroma[0]+(System.currentTimeMillis()-ChromaColour.startTime)/1000f)%1, 0.8f, 0.8f)); + } + + Minecraft.getMinecraft().getTextureManager().bindTexture(colour_selector_bar); + GlStateManager.color(1, 1, 1, 1); + RenderUtils.drawTexturedRect(x+5+64+5, y+5, 10, 64, GL11.GL_NEAREST); + RenderUtils.drawTexturedRect(x+5+64+5+10+5, y+5, 10, 64, GL11.GL_NEAREST); + + if(chromaSpeed > 0) { + RenderUtils.drawTexturedRect(x+5+64+5+10+5+10+5, y+5, 10, 64, GL11.GL_NEAREST); + } else { + Minecraft.getMinecraft().getTextureManager().bindTexture(colour_selector_chroma); + RenderUtils.drawTexturedRect(x+5+64+5+10+5+10+5, y+5+27, 10, 10, GL11.GL_NEAREST); + } + + Gui.drawRect(x+5+64+5, y+5+64-(int)(64*hsv[2]), + x+5+64+5+10, y+5+64-(int)(64*hsv[2])+1, 0xFF000000); + Gui.drawRect(x+5+64+5+10+5, y+5+64-c.getAlpha()/4, + x+5+64+5+10+5+10, y+5+64-c.getAlpha()/4-1, 0xFF000000); + if(chromaSpeed > 0) { + Gui.drawRect(x+5+64+5+10+5+10+5, + y+5+64-(int)(chromaSpeed/255f*64), + x+5+64+5+10+5+10+5+10, + y+5+64-(int)(chromaSpeed/255f*64)+1, 0xFF000000); + } + + Minecraft.getMinecraft().getTextureManager().loadTexture(colourPickerLocation, new DynamicTexture(bufferedImage)); + Minecraft.getMinecraft().getTextureManager().bindTexture(colourPickerLocation); + GlStateManager.color(1, 1, 1, 1); + RenderUtils.drawTexturedRect(x+1, y+1, 72, 72, GL11.GL_LINEAR); + + Minecraft.getMinecraft().getTextureManager().bindTexture(colour_selector_dot); + GlStateManager.color(1, 1, 1, 1); + RenderUtils.drawTexturedRect(x+5+32+selx-4, y+5+32+sely-4, 8, 8, GL11.GL_NEAREST); + + TextRenderUtils.drawStringCenteredScaledMaxWidth(EnumChatFormatting.GRAY.toString()+Math.round(hsv[2]*100)+"", + Minecraft.getMinecraft().fontRendererObj, + x+5+64+5+5-(Math.round(hsv[2]*100)==100?1:0), y+5+64+5+5, true, 13, -1); + TextRenderUtils.drawStringCenteredScaledMaxWidth(EnumChatFormatting.GRAY.toString()+Math.round(c.getAlpha()/255f*100)+"", + Minecraft.getMinecraft().fontRendererObj, + x+5+64+5+15+5, y+5+64+5+5, true, 13, -1); + if(chromaSpeed > 0) { + TextRenderUtils.drawStringCenteredScaledMaxWidth(EnumChatFormatting.GRAY.toString()+ + (int)ChromaColour.getSecondsForSpeed(chromaSpeed)+"s", + Minecraft.getMinecraft().fontRendererObj, + x+5+64+5+30+6, y+5+64+5+5, true, 13, -1); + } + + hexField.setSize(48, 10); + if(!hexField.getFocus()) hexField.setText(Integer.toHexString(c.getRGB() & 0xFFFFFF).toUpperCase()); + + StringBuilder sb = new StringBuilder(EnumChatFormatting.GRAY+"#"); + for(int i=0; i<6-hexField.getText().length(); i++) { + sb.append("0"); + } + sb.append(EnumChatFormatting.WHITE); + + hexField.setPrependText(sb.toString()); + hexField.render(x+5+8, y+5+64+5); + } + + public boolean mouseInput(int mouseX, int mouseY) { + ScaledResolution scaledResolution = new ScaledResolution(Minecraft.getMinecraft()); + float mouseXF = (float)(Mouse.getX() * scaledResolution.getScaledWidth_double() / + Minecraft.getMinecraft().displayWidth); + float mouseYF = (float)(scaledResolution.getScaledHeight_double() - Mouse.getY() * + scaledResolution.getScaledHeight_double() / Minecraft.getMinecraft().displayHeight - 1); + + if((Mouse.getEventButton() == 0 || Mouse.getEventButton() == 1) && Mouse.getEventButtonState()) { + if(mouseX > x+5+8 && mouseX < x+5+8+48) { + if(mouseY > y+5+64+5 && mouseY < y+5+64+5+10) { + hexField.mouseClicked(mouseX, mouseY, Mouse.getEventButton()); + clickedComponent = -1; + return true; + } + } + } + if(!Mouse.getEventButtonState() && Mouse.getEventButton() == 0) { + clickedComponent = -1; + } + if(Mouse.getEventButtonState() && Mouse.getEventButton() == 0) { + if(mouseX >= x && mouseX <= x+119 && + mouseY >= y && mouseY <= y+89) { + hexField.unfocus(); + + int xWheel = mouseX - x - 5; + int yWheel = mouseY - y - 5; + + if(xWheel > 0 && xWheel < 64) { + if(yWheel > 0 && yWheel < 64) { + clickedComponent = 0; + } + } + + int xValue = mouseX - (x+5+64+5); + int y = mouseY - this.y - 5; + + if(y > -5 && y <= 69) { + if(xValue > 0 && xValue < 10) { + clickedComponent = 1; + } + + int xOpacity = mouseX - (x+5+64+5+10+5); + + if(xOpacity > 0 && xOpacity < 10) { + clickedComponent = 2; + } + } + + int chromaSpeed = ChromaColour.getSpeed(colour); + int xChroma = mouseX - (x+5+64+5+10+5+10+5); + if(xChroma > 0 && xChroma < 10) { + if(chromaSpeed > 0) { + if(y > -5 && y <= 69) { + clickedComponent = 3; + } + } else if(mouseY > this.y+5+27 && mouseY < this.y+5+37) { + int currentColour = ChromaColour.specialToSimpleRGB(colour); + Color c = new Color(currentColour, true); + colour = ChromaColour.special(200, c.getAlpha(), currentColour); + colourChangedCallback.accept(colour); + } + } + } else { + hexField.unfocus(); + closeCallback.run(); + return false; + } + } + if(Mouse.isButtonDown(0) && clickedComponent >= 0) { + int currentColour = ChromaColour.specialToSimpleRGB(colour); + Color c = new Color(currentColour, true); + float[] hsv = Color.RGBtoHSB(c.getRed(), c.getGreen(), c.getBlue(), null); + + float xWheel = mouseXF - x - 5; + float yWheel = mouseYF - y - 5; + + if(clickedComponent == 0) { + float angle = (float) Math.toDegrees(Math.atan((32-xWheel)/(yWheel-32+1E-5))+Math.PI/2); + xWheel = Math.max(0, Math.min(64, xWheel)); + yWheel = Math.max(0, Math.min(64, yWheel)); + float radius = (float) Math.sqrt(((xWheel-32)*(xWheel-32)+(yWheel-32)*(yWheel-32))/1024f); + if(yWheel < 32) angle += 180; + + this.wheelAngle = angle; + this.wheelRadius = (float)Math.pow(Math.min(1, radius), 1.5f); + int rgb = Color.getHSBColor(angle/360f, wheelRadius, hsv[2]).getRGB(); + colour = ChromaColour.special(ChromaColour.getSpeed(colour), c.getAlpha(), rgb); + colourChangedCallback.accept(colour); + return true; + } + + float y = mouseYF - this.y - 5; + y = Math.max(0, Math.min(64, y)); + System.out.println(y); + + if(clickedComponent == 1) { + int rgb = Color.getHSBColor(wheelAngle/360, wheelRadius, 1-y/64f).getRGB(); + colour = ChromaColour.special(ChromaColour.getSpeed(colour), c.getAlpha(), rgb); + colourChangedCallback.accept(colour); + return true; + } + + if(clickedComponent == 2) { + colour = ChromaColour.special(ChromaColour.getSpeed(colour), + 255-Math.round(y/64f*255), currentColour); + colourChangedCallback.accept(colour); + return true; + } + + if(clickedComponent == 3) { + colour = ChromaColour.special(255-Math.round(y/64f*255), c.getAlpha(), currentColour); + colourChangedCallback.accept(colour); + } + return true; + } + return false; + } + + public boolean keyboardInput() { + if(Keyboard.getEventKeyState() && hexField.getFocus()) { + if (Keyboard.getEventKey() == Keyboard.KEY_ESCAPE) { + hexField.unfocus(); + return true; + } + String old = hexField.getText(); + + hexField.keyTyped(Keyboard.getEventCharacter(), Keyboard.getEventKey()); + + if(hexField.getText().length() > 6) { + hexField.setText(old); + } else { + try { + String text = hexField.getText().toLowerCase(); + + int rgb = Integer.parseInt(text, 16); + int alpha = (ChromaColour.specialToSimpleRGB(colour) >> 24) & 0xFF; + colour = ChromaColour.special(ChromaColour.getSpeed(colour), alpha, rgb); + colourChangedCallback.accept(colour); + + Color c = new Color(rgb); + float[] hsv = Color.RGBtoHSB(c.getRed(), c.getGreen(), c.getBlue(), null); + updateAngleAndRadius(hsv); + } catch(Exception e) {}; + } + + return true; + } + return false; + } + + +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/core/GuiElementTextField.java b/src/main/java/com/thatgravyboat/skyblockhud/core/GuiElementTextField.java new file mode 100644 index 0000000..e2d6557 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/core/GuiElementTextField.java @@ -0,0 +1,534 @@ +package com.thatgravyboat.skyblockhud.core; + +import com.thatgravyboat.skyblockhud.core.util.StringUtils; +import com.thatgravyboat.skyblockhud.core.util.render.TextRenderUtils; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Gui; +import net.minecraft.client.gui.GuiScreen; +import net.minecraft.client.gui.GuiTextField; +import net.minecraft.client.gui.ScaledResolution; +import net.minecraft.client.renderer.GlStateManager; + +import java.awt.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class GuiElementTextField { + + public static final int SCALE_TEXT = 0b100000; + public static final int NUM_ONLY = 0b10000; + public static final int NO_SPACE = 0b01000; + public static final int FORCE_CAPS = 0b00100; + public static final int COLOUR = 0b00010; + public static final int MULTILINE = 0b00001; + + private int searchBarYSize; + private int searchBarXSize; + private static final int searchBarPadding = 2; + + private int options; + + private boolean focus = false; + + private int x; + private int y; + + private String prependText = ""; + + private final GuiTextField textField = new GuiTextField(0, Minecraft.getMinecraft().fontRendererObj, + 0 , 0, 0, 0); + + private int customBorderColour = -1; + + public GuiElementTextField(String initialText, int options) { + this(initialText, 100, 20, options); + } + + public GuiElementTextField(String initialText, int sizeX, int sizeY, int options) { + textField.setFocused(true); + textField.setCanLoseFocus(false); + textField.setMaxStringLength(999); + textField.setText(initialText); + this.searchBarXSize = sizeX; + this.searchBarYSize = sizeY; + this.options = options; + } + + public void setMaxStringLength(int len) { + textField.setMaxStringLength(len); + } + + public void setCustomBorderColour(int colour) { + this.customBorderColour = colour; + } + + public String getText() { + return textField.getText(); + } + + public void setPrependText(String text) { + this.prependText = text; + } + + public void setText(String text) { + if(textField.getText() == null || !textField.getText().equals(text)) { + textField.setText(text); + } + } + + public void setSize(int searchBarXSize, int searchBarYSize) { + this.searchBarXSize = searchBarXSize; + this.searchBarYSize = searchBarYSize; + } + + public void setOptions(int options) { + this.options = options; + } + + @Override + public String toString() { + return textField.getText(); + } + + public void setFocus(boolean focus) { + this.focus = focus; + } + public boolean getFocus() { + return focus; + } + + public int getHeight() { + ScaledResolution scaledresolution = new ScaledResolution(Minecraft.getMinecraft()); + int paddingUnscaled = searchBarPadding/scaledresolution.getScaleFactor(); + + int numLines = org.apache.commons.lang3.StringUtils.countMatches(textField.getText(), "\n")+1; + int extraSize = (searchBarYSize-8)/2+8; + int bottomTextBox = searchBarYSize + extraSize*(numLines-1); + + return bottomTextBox + paddingUnscaled*2; + } + + public int getWidth() { + ScaledResolution scaledresolution = new ScaledResolution(Minecraft.getMinecraft()); + int paddingUnscaled = searchBarPadding/scaledresolution.getScaleFactor(); + + return searchBarXSize + paddingUnscaled*2; + } + + private float getScaleFactor(String str) { + return Math.min(1, (searchBarXSize-2)/(float)Minecraft.getMinecraft().fontRendererObj.getStringWidth(str)); + } + + private boolean isScaling() { + return (options & SCALE_TEXT) != 0; + } + + private float getStringWidth(String str) { + if(isScaling()) { + return Minecraft.getMinecraft().fontRendererObj.getStringWidth(str)*getScaleFactor(str); + } else { + return Minecraft.getMinecraft().fontRendererObj.getStringWidth(str); + } + } + + public int getCursorPos(int mouseX, int mouseY) { + int xComp = mouseX - x; + int yComp = mouseY - y; + + int extraSize = (searchBarYSize-8)/2+8; + + String renderText = prependText + textField.getText(); + + int lineNum = Math.round(((yComp - (searchBarYSize-8)/2))/extraSize); + + Pattern patternControlCode = Pattern.compile("(?i)\\u00A7([^\\u00B6])(?!\\u00B6)"); + String text = renderText; + String textNoColour = renderText; + if((options & COLOUR) != 0) { + while(true) { + Matcher matcher = patternControlCode.matcher(text); + if(!matcher.find() || matcher.groupCount() < 1) break; + String code = matcher.group(1); + text = matcher.replaceFirst("\u00A7"+code+"\u00B6"+code); + } + } + while(true) { + Matcher matcher = patternControlCode.matcher(textNoColour); + if(!matcher.find() || matcher.groupCount() < 1) break; + String code = matcher.group(1); + textNoColour = matcher.replaceFirst("\u00B6"+code); + } + + int currentLine = 0; + int cursorIndex = 0; + for(; cursorIndex<textNoColour.length(); cursorIndex++) { + if(currentLine == lineNum) break; + if(textNoColour.charAt(cursorIndex) == '\n') { + currentLine++; + } + } + + + String textNC = textNoColour.substring(0, cursorIndex); + int colorCodes = org.apache.commons.lang3.StringUtils.countMatches(textNC, "\u00B6"); + String line = text.substring(cursorIndex+(((options & COLOUR) != 0)?colorCodes*2:0)).split("\n")[0]; + int padding = Math.min(5, searchBarXSize-strLenNoColor(line))/2; + String trimmed = Minecraft.getMinecraft().fontRendererObj.trimStringToWidth(line, xComp-padding); + int linePos = strLenNoColor(trimmed); + if(linePos != strLenNoColor(line)) { + char after = line.charAt(linePos); + int trimmedWidth = Minecraft.getMinecraft().fontRendererObj.getStringWidth(trimmed); + int charWidth = Minecraft.getMinecraft().fontRendererObj.getCharWidth(after); + if(trimmedWidth + charWidth/2 < xComp-padding) { + linePos++; + } + } + cursorIndex += linePos; + + int pre = StringUtils.cleanColour(prependText).length(); + if(cursorIndex < pre) { + cursorIndex = 0; + } else { + cursorIndex -= pre; + } + + return cursorIndex; + } + + public void mouseClicked(int mouseX, int mouseY, int mouseButton) { + if(mouseButton == 1) { + textField.setText(""); + } else { + textField.setCursorPosition(getCursorPos(mouseX, mouseY)); + } + focus = true; + } + + public void unfocus() { + focus = false; + textField.setSelectionPos(textField.getCursorPosition()); + } + + public int strLenNoColor(String str) { + return str.replaceAll("(?i)\\u00A7.", "").length(); + } + + public void mouseClickMove(int mouseX, int mouseY, int clickedMouseButton, long timeSinceLastClick) { + if(focus) { + textField.setSelectionPos(getCursorPos(mouseX, mouseY)); + } + } + + public void keyTyped(char typedChar, int keyCode) { + if(focus) { + if((options & MULTILINE) != 0) { //Carriage return + Pattern patternControlCode = Pattern.compile("(?i)\\u00A7([^\\u00B6\n])(?!\\u00B6)"); + + String text = textField.getText(); + String textNoColour = textField.getText(); + while(true) { + Matcher matcher = patternControlCode.matcher(text); + if(!matcher.find() || matcher.groupCount() < 1) break; + String code = matcher.group(1); + text = matcher.replaceFirst("\u00A7"+code+"\u00B6"+code); + } + while(true) { + Matcher matcher = patternControlCode.matcher(textNoColour); + if(!matcher.find() || matcher.groupCount() < 1) break; + String code = matcher.group(1); + textNoColour = matcher.replaceFirst("\u00B6"+code); + } + + if(keyCode == 28) { + String before = textField.getText().substring(0, textField.getCursorPosition()); + String after = textField.getText().substring(textField.getCursorPosition()); + int pos = textField.getCursorPosition(); + textField.setText(before + "\n" + after); + textField.setCursorPosition(pos+1); + return; + } else if(keyCode == 200) { //Up + String textNCBeforeCursor = textNoColour.substring(0, textField.getSelectionEnd()); + int colorCodes = org.apache.commons.lang3.StringUtils.countMatches(textNCBeforeCursor, "\u00B6"); + String textBeforeCursor = text.substring(0, textField.getSelectionEnd()+colorCodes*2); + + int numLinesBeforeCursor = org.apache.commons.lang3.StringUtils.countMatches(textBeforeCursor, "\n"); + + String[] split = textBeforeCursor.split("\n"); + int textBeforeCursorWidth; + String lineBefore; + String thisLineBeforeCursor; + if(split.length == numLinesBeforeCursor && split.length > 0) { + textBeforeCursorWidth = 0; + lineBefore = split[split.length-1]; + thisLineBeforeCursor = ""; + } else if(split.length > 1) { + thisLineBeforeCursor = split[split.length-1]; + lineBefore = split[split.length-2]; + textBeforeCursorWidth = Minecraft.getMinecraft().fontRendererObj.getStringWidth(thisLineBeforeCursor); + } else { + return; + } + String trimmed = Minecraft.getMinecraft().fontRendererObj + .trimStringToWidth(lineBefore, textBeforeCursorWidth); + int linePos = strLenNoColor(trimmed); + if(linePos != strLenNoColor(lineBefore)) { + char after = lineBefore.charAt(linePos); + int trimmedWidth = Minecraft.getMinecraft().fontRendererObj.getStringWidth(trimmed); + int charWidth = Minecraft.getMinecraft().fontRendererObj.getCharWidth(after); + if(trimmedWidth + charWidth/2 < textBeforeCursorWidth) { + linePos++; + } + } + int newPos = textField.getSelectionEnd()-strLenNoColor(thisLineBeforeCursor) + -strLenNoColor(lineBefore)-1+linePos; + + if(GuiScreen.isShiftKeyDown()) { + textField.setSelectionPos(newPos); + } else { + textField.setCursorPosition(newPos); + } + } else if(keyCode == 208) { //Down + String textNCBeforeCursor = textNoColour.substring(0, textField.getSelectionEnd()); + int colorCodes = org.apache.commons.lang3.StringUtils.countMatches(textNCBeforeCursor, "\u00B6"); + String textBeforeCursor = text.substring(0, textField.getSelectionEnd()+colorCodes*2); + + int numLinesBeforeCursor = org.apache.commons.lang3.StringUtils.countMatches(textBeforeCursor, "\n"); + + String[] split = textBeforeCursor.split("\n"); + String thisLineBeforeCursor; + int textBeforeCursorWidth; + if(split.length == numLinesBeforeCursor) { + thisLineBeforeCursor = ""; + textBeforeCursorWidth = 0; + } else if(split.length > 0) { + thisLineBeforeCursor = split[split.length-1]; + textBeforeCursorWidth = Minecraft.getMinecraft().fontRendererObj.getStringWidth(thisLineBeforeCursor); + } else { + return; + } + + String[] split2 = textNoColour.split("\n"); + if(split2.length > numLinesBeforeCursor+1) { + String lineAfter = split2[numLinesBeforeCursor+1]; + String trimmed = Minecraft.getMinecraft().fontRendererObj + .trimStringToWidth(lineAfter, textBeforeCursorWidth); + int linePos = strLenNoColor(trimmed); + if(linePos != strLenNoColor(lineAfter)) { + char after = lineAfter.charAt(linePos); + int trimmedWidth = Minecraft.getMinecraft().fontRendererObj.getStringWidth(trimmed); + int charWidth = Minecraft.getMinecraft().fontRendererObj.getCharWidth(after); + if(trimmedWidth + charWidth/2 < textBeforeCursorWidth) { + linePos++; + } + } + int newPos = textField.getSelectionEnd()-strLenNoColor(thisLineBeforeCursor) + +strLenNoColor(split2[numLinesBeforeCursor])+1+linePos; + + if(GuiScreen.isShiftKeyDown()) { + textField.setSelectionPos(newPos); + } else { + textField.setCursorPosition(newPos); + } + } + } + } + + String old = textField.getText(); + if((options & FORCE_CAPS) != 0) typedChar = Character.toUpperCase(typedChar); + if((options & NO_SPACE) != 0 && typedChar == ' ') return; + + textField.setFocused(true); + textField.textboxKeyTyped(typedChar, keyCode); + + if((options & COLOUR) != 0) { + if(typedChar == '&') { + int pos = textField.getCursorPosition()-2; + if(pos >= 0 && pos < textField.getText().length()) { + if(textField.getText().charAt(pos) == '&') { + String before = textField.getText().substring(0, pos); + String after = ""; + if(pos+2 < textField.getText().length()) { + after = textField.getText().substring(pos+2); + } + textField.setText(before + "\u00A7" + after); + textField.setCursorPosition(pos+1); + } + } + } + } + + if((options & NUM_ONLY) != 0 && textField.getText().matches("[^0-9.]")) textField.setText(old); + } + } + + public void render(int x, int y) { + this.x = x; + this.y = y; + drawTextbox(x, y, searchBarXSize, searchBarYSize, searchBarPadding, textField, focus); + } + + private void drawTextbox(int x, int y, int searchBarXSize, int searchBarYSize, int searchBarPadding, + GuiTextField textField, boolean focus) { + ScaledResolution scaledresolution = new ScaledResolution(Minecraft.getMinecraft()); + String renderText = prependText + textField.getText(); + + GlStateManager.disableLighting(); + + /** + * Search bar + */ + int paddingUnscaled = searchBarPadding/scaledresolution.getScaleFactor(); + if(paddingUnscaled < 1) paddingUnscaled = 1; + + int numLines = org.apache.commons.lang3.StringUtils.countMatches(renderText, "\n")+1; + int extraSize = (searchBarYSize-8)/2+8; + int bottomTextBox = y + searchBarYSize + extraSize*(numLines-1); + + int borderColour = focus ? Color.GREEN.getRGB() : Color.WHITE.getRGB(); + if(customBorderColour != -1) { + borderColour = customBorderColour; + } + //bar background + Gui.drawRect(x - paddingUnscaled, + y - paddingUnscaled, + x + searchBarXSize + paddingUnscaled, + bottomTextBox + paddingUnscaled, borderColour); + Gui.drawRect(x, + y, + x + searchBarXSize, + bottomTextBox, Color.BLACK.getRGB()); + + //bar text + Pattern patternControlCode = Pattern.compile("(?i)\\u00A7([^\\u00B6\n])(?!\\u00B6)"); + + String text = renderText; + String textNoColor = renderText; + if((options & COLOUR) != 0) { + while(true) { + Matcher matcher = patternControlCode.matcher(text); + if(!matcher.find() || matcher.groupCount() < 1) break; + String code = matcher.group(1); + text = matcher.replaceFirst("\u00A7"+code+"\u00B6"+code); + } + } + while(true) { + Matcher matcher = patternControlCode.matcher(textNoColor); + if(!matcher.find() || matcher.groupCount() < 1) break; + String code = matcher.group(1); + textNoColor = matcher.replaceFirst("\u00B6"+code); + } + + int xStartOffset = 5; + float scale = 1; + String[] texts = text.split("\n"); + for(int yOffI = 0; yOffI < texts.length; yOffI++) { + int yOff = yOffI*extraSize; + + if(isScaling() && Minecraft.getMinecraft().fontRendererObj.getStringWidth(texts[yOffI])>searchBarXSize-10) { + scale = (searchBarXSize-2)/(float)Minecraft.getMinecraft().fontRendererObj.getStringWidth(texts[yOffI]); + if(scale > 1) scale=1; + float newLen = Minecraft.getMinecraft().fontRendererObj.getStringWidth(texts[yOffI])*scale; + xStartOffset = (int)((searchBarXSize-newLen)/2f); + + TextRenderUtils.drawStringCenteredScaledMaxWidth(texts[yOffI], Minecraft.getMinecraft().fontRendererObj, x+searchBarXSize/2f, + y+searchBarYSize/2f+yOff, false, + searchBarXSize-2, Color.WHITE.getRGB()); + } else { + Minecraft.getMinecraft().fontRendererObj.drawString(StringUtils.trimToWidth(texts[yOffI], searchBarXSize-10), x + 5, + y+(searchBarYSize-8)/2+yOff, Color.WHITE.getRGB()); + } + } + + if(focus && System.currentTimeMillis()%1000>500) { + String textNCBeforeCursor = textNoColor.substring(0, textField.getCursorPosition()+prependText.length()); + int colorCodes = org.apache.commons.lang3.StringUtils.countMatches(textNCBeforeCursor, "\u00B6"); + String textBeforeCursor = text.substring(0, textField.getCursorPosition()+prependText.length()+(((options & COLOUR) != 0) ? colorCodes*2 : 0)); + + int numLinesBeforeCursor = org.apache.commons.lang3.StringUtils.countMatches(textBeforeCursor, "\n"); + int yOff = numLinesBeforeCursor*extraSize; + + String[] split = textBeforeCursor.split("\n"); + int textBeforeCursorWidth; + if(split.length <= numLinesBeforeCursor || split.length == 0) { + textBeforeCursorWidth = 0; + } else { + textBeforeCursorWidth = (int)(Minecraft.getMinecraft().fontRendererObj.getStringWidth(split[split.length-1])*scale); + } + Gui.drawRect(x + xStartOffset + textBeforeCursorWidth, + y+(searchBarYSize-8)/2-1 + yOff, + x + xStartOffset + textBeforeCursorWidth+1, + y+(searchBarYSize-8)/2+9 + yOff, Color.WHITE.getRGB()); + } + + String selectedText = textField.getSelectedText(); + if(!selectedText.isEmpty()) { + System.out.println("Start"); + int leftIndex = Math.min(textField.getCursorPosition()+prependText.length(), textField.getSelectionEnd()+prependText.length()); + int rightIndex = Math.max(textField.getCursorPosition()+prependText.length(), textField.getSelectionEnd()+prependText.length()); + + float texX = 0; + int texY = 0; + boolean sectionSignPrev = false; + boolean ignoreNext = false; + boolean bold = false; + for(int i=0; i<textNoColor.length(); i++) { + if(ignoreNext) { + ignoreNext = false; + continue; + } + + char c = textNoColor.charAt(i); + if(sectionSignPrev) { + if(c != 'k' && c != 'K' + && c != 'm' && c != 'M' + && c != 'n' && c != 'N' + && c != 'o' && c != 'O') { + bold = c == 'l' || c == 'L'; + } + sectionSignPrev = false; + if(i < prependText.length()) continue; + } + if(c == '\u00B6') { + sectionSignPrev = true; + if(i < prependText.length()) continue; + } + + if(c == '\n') { + if(i >= leftIndex && i < rightIndex) { + Gui.drawRect(x + xStartOffset + (int)texX, + y+(searchBarYSize-8)/2-1 + texY, + x + xStartOffset + (int)texX + 3, + y+(searchBarYSize-8)/2+9 + texY, Color.LIGHT_GRAY.getRGB()); + } + + texX = 0; + texY += extraSize; + continue; + } + + //String c2 = bold ? EnumChatFormatting.BOLD.toString() : "" + c; + + System.out.println("Adding len for char:"+c+":"+Integer.toHexString(c)); + int len = Minecraft.getMinecraft().fontRendererObj.getStringWidth(String.valueOf(c)); + if(bold) len++; + if(i >= leftIndex && i < rightIndex) { + Gui.drawRect(x + xStartOffset + (int)texX, + y+(searchBarYSize-8)/2-1 + texY, + x + xStartOffset + (int)(texX + len*scale), + y+(searchBarYSize-8)/2+9 + texY, Color.LIGHT_GRAY.getRGB()); + + TextRenderUtils.drawStringScaled(String.valueOf(c), Minecraft.getMinecraft().fontRendererObj, + x + xStartOffset + texX, + y+searchBarYSize/2f-scale*8/2f + texY, false, Color.BLACK.getRGB(), scale); + if(bold) { + TextRenderUtils.drawStringScaled(String.valueOf(c), Minecraft.getMinecraft().fontRendererObj, + x + xStartOffset + texX + 1, + y+searchBarYSize/2f-scale*8/2f + texY, false, Color.BLACK.getRGB(), scale); + } + } + + texX += len*scale; + } + } + } +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/core/GuiScreenElementWrapper.java b/src/main/java/com/thatgravyboat/skyblockhud/core/GuiScreenElementWrapper.java new file mode 100644 index 0000000..234cc2d --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/core/GuiScreenElementWrapper.java @@ -0,0 +1,35 @@ +package com.thatgravyboat.skyblockhud.core; + +import net.minecraft.client.gui.GuiScreen; +import org.lwjgl.input.Mouse; + +import java.io.IOException; + +public class GuiScreenElementWrapper extends GuiScreen { + + public final GuiElement element; + + public GuiScreenElementWrapper(GuiElement element) { + this.element = element; + } + + @Override + public void drawScreen(int mouseX, int mouseY, float partialTicks) { + super.drawScreen(mouseX, mouseY, partialTicks); + element.render(); + } + + @Override + public void handleMouseInput() throws IOException { + super.handleMouseInput(); + int i = Mouse.getEventX() * this.width / this.mc.displayWidth; + int j = this.height - Mouse.getEventY() * this.height / this.mc.displayHeight - 1; + element.mouseInput(i, j); + } + + @Override + public void handleKeyboardInput() throws IOException { + super.handleKeyboardInput(); + element.keyboardInput(); + } +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/core/config/Config.java b/src/main/java/com/thatgravyboat/skyblockhud/core/config/Config.java new file mode 100644 index 0000000..40f8c0e --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/core/config/Config.java @@ -0,0 +1,8 @@ +package com.thatgravyboat.skyblockhud.core.config; + +public class Config { + + public void executeRunnable(String runnableId) { + } + +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/core/config/Position.java b/src/main/java/com/thatgravyboat/skyblockhud/core/config/Position.java new file mode 100644 index 0000000..1c2de86 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/core/config/Position.java @@ -0,0 +1,196 @@ +package com.thatgravyboat.skyblockhud.core.config; + +import com.google.gson.annotations.Expose; +import net.minecraft.client.gui.ScaledResolution; + +public class Position { + + @Expose + private int x; + @Expose + private int y; + @Expose + private boolean centerX; + @Expose + private boolean centerY; + + + private static final int EDGE_OFFSET = 0; + + public Position(int x, int y) { + this(x, y, false, false); + } + + public Position(int x, int y, boolean centerX, boolean centerY) { + this.x = x; + this.y = y; + this.centerX = centerX; + this.centerY = centerY; + } + + public void set(Position other) { + this.x = other.x; + this.y = other.y; + this.centerX = other.centerX; + this.centerY = other.centerY; + } + + public Position clone() { + return new Position(x, y, centerX, centerY); + } + + public boolean isCenterX() { + return centerX; + } + + public boolean isCenterY() { + return centerY; + } + + public int getRawX() { + return x; + } + + public int getRawY() { + return y; + } + + public int getAbsX(ScaledResolution scaledResolution, int objWidth) { + int width = scaledResolution.getScaledWidth(); + + if(centerX) { + return width/2 + x; + } + + int ret = x; + if(x < 0) { + ret = width + x - objWidth; + } + + if(ret < 0) ret = 0; + if(ret > width - objWidth) ret = width - objWidth; + + return ret; + } + + public int getAbsY(ScaledResolution scaledResolution, int objHeight) { + int height = scaledResolution.getScaledHeight(); + + if(centerY) { + return height/2 + y; + } + + int ret = y; + if(y < 0) { + ret = height + y - objHeight; + } + + if(ret < 0) ret = 0; + if(ret > height - objHeight) ret = height - objHeight; + + return ret; + } + + public int moveX(int deltaX, int objWidth, ScaledResolution scaledResolution) { + int screenWidth = scaledResolution.getScaledWidth(); + boolean wasPositiveX = this.x >= 0; + this.x += deltaX; + + if(centerX) { + if(wasPositiveX) { + if(this.x > screenWidth/2-objWidth/2) { + deltaX += screenWidth/2-objWidth/2-this.x; + this.x = screenWidth/2-objWidth/2; + } + } else { + if(this.x < -screenWidth/2+objWidth/2) { + deltaX += -screenWidth/2+objWidth/2-this.x; + this.x = -screenWidth/2+objWidth/2; + } + } + return deltaX; + } + + if(wasPositiveX) { + if(this.x < EDGE_OFFSET) { + deltaX += EDGE_OFFSET-this.x; + this.x = EDGE_OFFSET; + } + if(this.x > screenWidth-EDGE_OFFSET) { + deltaX += screenWidth-EDGE_OFFSET-this.x; + this.x = screenWidth-EDGE_OFFSET; + } + } else { + if(this.x+1 > -EDGE_OFFSET) { + deltaX += -EDGE_OFFSET-1-this.x; + this.x = -EDGE_OFFSET-1; + } + if(this.x+screenWidth < EDGE_OFFSET) { + deltaX += EDGE_OFFSET-screenWidth-this.x; + this.x = EDGE_OFFSET-screenWidth; + } + } + + if(this.x >= 0 && this.x+objWidth/2 > screenWidth/2) { + this.x -= screenWidth - objWidth; + } + if(this.x < 0 && this.x+objWidth/2 <= -screenWidth/2) { + this.x += screenWidth - objWidth; + } + return deltaX; + } + + public int moveY(int deltaY, int objHeight, ScaledResolution scaledResolution) { + int screenHeight = scaledResolution.getScaledHeight(); + boolean wasPositiveY = this.y >= 0; + this.y += deltaY; + + if(centerY) { + if(wasPositiveY) { + if(this.y > screenHeight/2-objHeight/2) { + deltaY += screenHeight/2-objHeight/2-this.y; + this.y = screenHeight/2-objHeight/2; + } + } else { + if(this.y < -screenHeight/2+objHeight/2) { + deltaY += -screenHeight/2+objHeight/2-this.y; + this.y = -screenHeight/2+objHeight/2; + } + } + return deltaY; + } + + if(wasPositiveY) { + if(this.y < EDGE_OFFSET) { + deltaY += EDGE_OFFSET-this.y; + this.y = EDGE_OFFSET; + } + if(this.y > screenHeight-EDGE_OFFSET) { + deltaY += screenHeight-EDGE_OFFSET-this.y; + this.y = screenHeight-EDGE_OFFSET; + } + } else { + if(this.y+1 > -EDGE_OFFSET) { + deltaY += -EDGE_OFFSET-1-this.y; + this.y = -EDGE_OFFSET-1; + } + if(this.y+screenHeight < EDGE_OFFSET) { + deltaY += EDGE_OFFSET-screenHeight-this.y; + this.y = EDGE_OFFSET-screenHeight; + } + } + + if(this.y >= 0 && this.y-objHeight/2 > screenHeight/2) { + this.y -= screenHeight - objHeight; + } + if(this.y < 0 && this.y-objHeight/2 <= -screenHeight/2) { + this.y += screenHeight - objHeight; + } + return deltaY; + } + + public boolean rightAligned(ScaledResolution scaledResolution, int objWidth){ + return this.getAbsX(scaledResolution, objWidth) > (scaledResolution.getScaledWidth() / 2); + } + +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/core/config/annotations/Category.java b/src/main/java/com/thatgravyboat/skyblockhud/core/config/annotations/Category.java new file mode 100644 index 0000000..e1d51ac --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/core/config/annotations/Category.java @@ -0,0 +1,15 @@ +package com.thatgravyboat.skyblockhud.core.config.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface Category { + + String name(); + String desc(); + +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/core/config/annotations/ConfigAccordionId.java b/src/main/java/com/thatgravyboat/skyblockhud/core/config/annotations/ConfigAccordionId.java new file mode 100644 index 0000000..8e2836f --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/core/config/annotations/ConfigAccordionId.java @@ -0,0 +1,14 @@ +package com.thatgravyboat.skyblockhud.core.config.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface ConfigAccordionId { + + int id(); + +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/core/config/annotations/ConfigEditorAccordion.java b/src/main/java/com/thatgravyboat/skyblockhud/core/config/annotations/ConfigEditorAccordion.java new file mode 100644 index 0000000..acb60af --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/core/config/annotations/ConfigEditorAccordion.java @@ -0,0 +1,14 @@ +package com.thatgravyboat.skyblockhud.core.config.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface ConfigEditorAccordion { + + int id(); + +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/core/config/annotations/ConfigEditorBoolean.java b/src/main/java/com/thatgravyboat/skyblockhud/core/config/annotations/ConfigEditorBoolean.java new file mode 100644 index 0000000..b1846d3 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/core/config/annotations/ConfigEditorBoolean.java @@ -0,0 +1,12 @@ +package com.thatgravyboat.skyblockhud.core.config.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface ConfigEditorBoolean { + +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/core/config/annotations/ConfigEditorButton.java b/src/main/java/com/thatgravyboat/skyblockhud/core/config/annotations/ConfigEditorButton.java new file mode 100644 index 0000000..32425d1 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/core/config/annotations/ConfigEditorButton.java @@ -0,0 +1,15 @@ +package com.thatgravyboat.skyblockhud.core.config.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface ConfigEditorButton { + + String runnableId(); + String buttonText() default ""; + +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/core/config/annotations/ConfigEditorColour.java b/src/main/java/com/thatgravyboat/skyblockhud/core/config/annotations/ConfigEditorColour.java new file mode 100644 index 0000000..1e5713c --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/core/config/annotations/ConfigEditorColour.java @@ -0,0 +1,13 @@ +package com.thatgravyboat.skyblockhud.core.config.annotations; + + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface ConfigEditorColour { + +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/core/config/annotations/ConfigEditorDraggableList.java b/src/main/java/com/thatgravyboat/skyblockhud/core/config/annotations/ConfigEditorDraggableList.java new file mode 100644 index 0000000..963c305 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/core/config/annotations/ConfigEditorDraggableList.java @@ -0,0 +1,14 @@ +package com.thatgravyboat.skyblockhud.core.config.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface ConfigEditorDraggableList { + + String[] exampleText(); + +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/core/config/annotations/ConfigEditorDropdown.java b/src/main/java/com/thatgravyboat/skyblockhud/core/config/annotations/ConfigEditorDropdown.java new file mode 100644 index 0000000..5e48e25 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/core/config/annotations/ConfigEditorDropdown.java @@ -0,0 +1,16 @@ +package com.thatgravyboat.skyblockhud.core.config.annotations; + + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface ConfigEditorDropdown { + + String[] values(); + int initialIndex() default 0; + +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/core/config/annotations/ConfigEditorSlider.java b/src/main/java/com/thatgravyboat/skyblockhud/core/config/annotations/ConfigEditorSlider.java new file mode 100644 index 0000000..a0fea03 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/core/config/annotations/ConfigEditorSlider.java @@ -0,0 +1,18 @@ +package com.thatgravyboat.skyblockhud.core.config.annotations; + + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface ConfigEditorSlider { + + float minValue(); + float maxValue(); + + float minStep(); + +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/core/config/annotations/ConfigEditorText.java b/src/main/java/com/thatgravyboat/skyblockhud/core/config/annotations/ConfigEditorText.java new file mode 100644 index 0000000..0c00561 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/core/config/annotations/ConfigEditorText.java @@ -0,0 +1,13 @@ +package com.thatgravyboat.skyblockhud.core.config.annotations; + + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface ConfigEditorText { + +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/core/config/annotations/ConfigOption.java b/src/main/java/com/thatgravyboat/skyblockhud/core/config/annotations/ConfigOption.java new file mode 100644 index 0000000..845d01f --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/core/config/annotations/ConfigOption.java @@ -0,0 +1,17 @@ +package com.thatgravyboat.skyblockhud.core.config.annotations; + + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface ConfigOption { + + String name(); + String desc(); + int subcategoryId() default -1; + +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/core/config/gui/GuiOptionEditor.java b/src/main/java/com/thatgravyboat/skyblockhud/core/config/gui/GuiOptionEditor.java new file mode 100644 index 0000000..e978420 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/core/config/gui/GuiOptionEditor.java @@ -0,0 +1,62 @@ +package com.thatgravyboat.skyblockhud.core.config.gui; + +import com.thatgravyboat.skyblockhud.core.config.struct.ConfigProcessor; +import com.thatgravyboat.skyblockhud.core.util.render.RenderUtils; +import com.thatgravyboat.skyblockhud.core.util.render.TextRenderUtils; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.renderer.GlStateManager; + +public abstract class GuiOptionEditor { + + protected final ConfigProcessor.ProcessedOption option; + private static final int HEIGHT = 45; + + public GuiOptionEditor(ConfigProcessor.ProcessedOption option) { + this.option = option; + } + + public void render(int x, int y, int width) { + int height = getHeight(); + + FontRenderer fr = Minecraft.getMinecraft().fontRendererObj; + RenderUtils.drawFloatingRectDark(x, y, width, height, true); + TextRenderUtils.drawStringCenteredScaledMaxWidth(option.name, + fr, x+width/6f, y+13, true, width/3-10, 0xc0c0c0); + + int maxLines = 5; + float scale = 1; + int lineCount = fr.listFormattedStringToWidth(option.desc, width*2/3-10).size(); + + if(lineCount <= 0) return; + + float paraHeight = 9 * lineCount - 1; + + while(paraHeight >= HEIGHT-10) { + scale -= 1/8f; + lineCount = fr.listFormattedStringToWidth(option.desc, (int)(width*2/3/scale-10)).size(); + paraHeight = (int)(9*scale * lineCount - 1*scale); + } + + GlStateManager.pushMatrix(); + GlStateManager.translate(x+5+width/3f, y+HEIGHT/2f-paraHeight/2, 0); + GlStateManager.scale(scale, scale, 1); + + fr.drawSplitString(option.desc, 0, 0, (int)(width*2/3/scale-10), 0xc0c0c0); + + GlStateManager.popMatrix(); + } + + public int getHeight() { + return HEIGHT; + } + + public abstract boolean mouseInput(int x, int y, int width, int mouseX, int mouseY); + public abstract boolean keyboardInput(); + + public boolean mouseInputOverlay(int x, int y, int width, int mouseX, int mouseY) { + return false; + } + public void renderOverlay(int x, int y, int width) {} + +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/core/config/gui/GuiOptionEditorAccordion.java b/src/main/java/com/thatgravyboat/skyblockhud/core/config/gui/GuiOptionEditorAccordion.java new file mode 100644 index 0000000..c2b129d --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/core/config/gui/GuiOptionEditorAccordion.java @@ -0,0 +1,82 @@ +package com.thatgravyboat.skyblockhud.core.config.gui; + +import com.thatgravyboat.skyblockhud.core.config.struct.ConfigProcessor; +import com.thatgravyboat.skyblockhud.core.util.render.RenderUtils; +import com.thatgravyboat.skyblockhud.core.util.render.TextRenderUtils; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.WorldRenderer; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import org.lwjgl.input.Mouse; +import org.lwjgl.opengl.GL11; + +public class GuiOptionEditorAccordion extends GuiOptionEditor { + + private int accordionId; + private boolean accordionToggled; + + public GuiOptionEditorAccordion(ConfigProcessor.ProcessedOption option, int accordionId) { + super(option); + this.accordionToggled = (boolean) option.get(); + this.accordionId = accordionId; + } + + @Override + public int getHeight() { + return 20; + } + + public int getAccordionId() { + return accordionId; + } + + public boolean getToggled() { + return accordionToggled; + } + + @Override + public void render(int x, int y, int width) { + int height = getHeight(); + RenderUtils.drawFloatingRectDark(x, y, width, height, true); + + Tessellator tessellator = Tessellator.getInstance(); + WorldRenderer worldrenderer = tessellator.getWorldRenderer(); + GlStateManager.enableBlend(); + GlStateManager.disableTexture2D(); + GlStateManager.tryBlendFuncSeparate(770, 771, 1, 0); + GlStateManager.color(1, 1, 1, 1); + worldrenderer.begin(GL11.GL_TRIANGLES, DefaultVertexFormats.POSITION); + if(accordionToggled) { + worldrenderer.pos((double)x+6, (double)y+6, 0.0D).endVertex(); + worldrenderer.pos((double)x+9.75f, (double)y+13.5f, 0.0D).endVertex(); + worldrenderer.pos((double)x+13.5f, (double)y+6, 0.0D).endVertex(); + } else { + worldrenderer.pos((double)x+6, (double)y+13.5f, 0.0D).endVertex(); + worldrenderer.pos((double)x+13.5f, (double)y+9.75f, 0.0D).endVertex(); + worldrenderer.pos((double)x+6, (double)y+6, 0.0D).endVertex(); + } + tessellator.draw(); + GlStateManager.enableTexture2D(); + GlStateManager.disableBlend(); + + TextRenderUtils.drawStringScaledMaxWidth(option.name, Minecraft.getMinecraft().fontRendererObj, + x+18, y+6, false, width-10, 0xc0c0c0); + } + + @Override + public boolean mouseInput(int x, int y, int width, int mouseX, int mouseY) { + if(Mouse.getEventButtonState() && mouseX > x && mouseX < x+ width && + mouseY > y && mouseY < y+getHeight()) { + accordionToggled = !accordionToggled; + return true; + } + + return false; + } + + @Override + public boolean keyboardInput() { + return false; + } +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/core/config/gui/GuiOptionEditorBoolean.java b/src/main/java/com/thatgravyboat/skyblockhud/core/config/gui/GuiOptionEditorBoolean.java new file mode 100644 index 0000000..3ea70c0 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/core/config/gui/GuiOptionEditorBoolean.java @@ -0,0 +1,38 @@ +package com.thatgravyboat.skyblockhud.core.config.gui; + +import com.thatgravyboat.skyblockhud.core.GuiElementBoolean; +import com.thatgravyboat.skyblockhud.core.config.struct.ConfigProcessor; + +public class GuiOptionEditorBoolean extends GuiOptionEditor { + + private final GuiElementBoolean bool; + + public GuiOptionEditorBoolean(ConfigProcessor.ProcessedOption option) { + super(option); + + bool = new GuiElementBoolean(0, 0, (boolean)option.get(), 10, option::set); + } + + @Override + public void render(int x, int y, int width) { + super.render(x, y, width); + int height = getHeight(); + + bool.x = x+width/6-24; + bool.y = y+height-7-14; + bool.render(); + } + + @Override + public boolean mouseInput(int x, int y, int width, int mouseX, int mouseY) { + int height = getHeight(); + bool.x = x+width/6-24; + bool.y = y+height-7-14; + return bool.mouseInput(mouseX, mouseY); + } + + @Override + public boolean keyboardInput() { + return false; + } +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/core/config/gui/GuiOptionEditorButton.java b/src/main/java/com/thatgravyboat/skyblockhud/core/config/gui/GuiOptionEditorButton.java new file mode 100644 index 0000000..752b4bf --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/core/config/gui/GuiOptionEditorButton.java @@ -0,0 +1,64 @@ +package com.thatgravyboat.skyblockhud.core.config.gui; + +import com.thatgravyboat.skyblockhud.core.ChromaColour; +import com.thatgravyboat.skyblockhud.core.config.Config; +import com.thatgravyboat.skyblockhud.core.config.struct.ConfigProcessor; +import com.thatgravyboat.skyblockhud.core.util.render.RenderUtils; +import com.thatgravyboat.skyblockhud.core.util.render.TextRenderUtils; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.GlStateManager; +import org.lwjgl.input.Mouse; + +import static com.thatgravyboat.skyblockhud.GuiTextures.button_tex; + +public class GuiOptionEditorButton extends GuiOptionEditor { + + private final String runnableId; + private String buttonText; + private Config config; + + public GuiOptionEditorButton(ConfigProcessor.ProcessedOption option, String runnableId, String buttonText, Config config) { + super(option); + this.runnableId = runnableId; + this.config = config; + + this.buttonText = buttonText; + if(this.buttonText != null && this.buttonText.isEmpty()) this.buttonText = null; + } + + @Override + public void render(int x, int y, int width) { + super.render(x, y, width); + + int height = getHeight(); + + GlStateManager.color(1, 1, 1, 1); + Minecraft.getMinecraft().getTextureManager().bindTexture(button_tex); + RenderUtils.drawTexturedRect(x+width/6-24, y+height-7-14, 48, 16); + + if(buttonText != null) { + TextRenderUtils.drawStringCenteredScaledMaxWidth(buttonText, Minecraft.getMinecraft().fontRendererObj, + x+width/6, y+height-7-6, + false, 44, 0xFF303030); + } + } + + @Override + public boolean mouseInput(int x, int y, int width, int mouseX, int mouseY) { + if(Mouse.getEventButtonState()) { + int height = getHeight(); + if(mouseX > x+width/6-24 && mouseX < x+width/6+24 && + mouseY > y+height-7-14 && mouseY < y+height-7+2) { + config.executeRunnable(runnableId); + return true; + } + } + + return false; + } + + @Override + public boolean keyboardInput() { + return false; + } +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/core/config/gui/GuiOptionEditorColour.java b/src/main/java/com/thatgravyboat/skyblockhud/core/config/gui/GuiOptionEditorColour.java new file mode 100644 index 0000000..1f03954 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/core/config/gui/GuiOptionEditorColour.java @@ -0,0 +1,71 @@ +package com.thatgravyboat.skyblockhud.core.config.gui; + +import com.thatgravyboat.skyblockhud.core.ChromaColour; +import com.thatgravyboat.skyblockhud.core.GuiElementColour; +import com.thatgravyboat.skyblockhud.core.config.struct.ConfigProcessor; +import com.thatgravyboat.skyblockhud.core.util.render.RenderUtils; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.GlStateManager; +import org.lwjgl.input.Mouse; + +import static com.thatgravyboat.skyblockhud.GuiTextures.*; + +public class GuiOptionEditorColour extends GuiOptionEditor { + + private String chromaColour; + private GuiElementColour colourElement = null; + + public GuiOptionEditorColour(ConfigProcessor.ProcessedOption option) { + super(option); + + this.chromaColour = (String)option.get(); + } + + @Override + public void render(int x, int y, int width) { + super.render(x, y, width); + int height = getHeight(); + + int argb = ChromaColour.specialToChromaRGB(chromaColour); + int r = (argb >> 16) & 0xFF; + int g = (argb >> 8) & 0xFF; + int b = argb & 0xFF; + GlStateManager.color(r/255f, g/255f, b/255f, 1); + Minecraft.getMinecraft().getTextureManager().bindTexture(button_white); + RenderUtils.drawTexturedRect(x+width/6f-24, y+height-7-14, 48, 16); + } + + @Override + public void renderOverlay(int x, int y, int width) { + if(colourElement != null) { + colourElement.render(); + } + } + + @Override + public boolean mouseInputOverlay(int x, int y, int width, int mouseX, int mouseY) { + return colourElement != null && colourElement.mouseInput(mouseX, mouseY); + } + + @Override + public boolean mouseInput(int x, int y, int width, int mouseX, int mouseY) { + int height = getHeight(); + + if(Mouse.getEventButtonState() && Mouse.getEventButton() == 0 && + mouseX > x+width/6-24 && mouseX < x+width/6+24 && + mouseY > y+height-7-14 && mouseY < y+height-7+2) { + colourElement = new GuiElementColour(mouseX, mouseY, (String) option.get(), (val) -> { + option.set(val); + chromaColour = val; + }, () -> colourElement = null); + } + + return false; + } + + @Override + public boolean keyboardInput() { + return colourElement != null && colourElement.keyboardInput(); + } + +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/core/config/gui/GuiOptionEditorDraggableList.java b/src/main/java/com/thatgravyboat/skyblockhud/core/config/gui/GuiOptionEditorDraggableList.java new file mode 100644 index 0000000..59f9e82 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/core/config/gui/GuiOptionEditorDraggableList.java @@ -0,0 +1,284 @@ +package com.thatgravyboat.skyblockhud.core.config.gui; + +import com.thatgravyboat.skyblockhud.Utils; +import com.thatgravyboat.skyblockhud.core.config.struct.ConfigProcessor; +import com.thatgravyboat.skyblockhud.core.util.lerp.LerpUtils; +import com.thatgravyboat.skyblockhud.core.util.render.RenderUtils; +import com.thatgravyboat.skyblockhud.core.util.render.TextRenderUtils; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.gui.Gui; +import net.minecraft.client.gui.ScaledResolution; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.util.EnumChatFormatting; +import net.minecraft.util.ResourceLocation; +import org.lwjgl.input.Mouse; +import org.lwjgl.opengl.GL11; + +import java.util.ArrayList; +import java.util.List; + +import static com.thatgravyboat.skyblockhud.GuiTextures.button_tex; + +public class GuiOptionEditorDraggableList extends GuiOptionEditor { + + private static final ResourceLocation DELETE = new ResourceLocation("notenoughupdates:core/delete.png"); + + private String[] exampleText; + private List<Integer> activeText; + private int currentDragging = -1; + private int dragStartIndex = -1; + + private long trashHoverTime = -1; + + private int dragOffsetX = -1; + private int dragOffsetY = -1; + + private boolean dropdownOpen = false; + + public GuiOptionEditorDraggableList(ConfigProcessor.ProcessedOption option, String[] exampleText) { + super(option); + + this.exampleText = exampleText; + this.activeText = (List<Integer>) option.get(); + } + + @Override + public int getHeight() { + int height = super.getHeight() + 13; + + for(int strIndex : activeText) { + String str = exampleText[strIndex]; + height += 10 * str.split("\n").length; + } + + return height; + } + + @Override + public void render(int x, int y, int width) { + super.render(x, y, width); + + int height = getHeight(); + + GlStateManager.color(1, 1, 1, 1); + Minecraft.getMinecraft().getTextureManager().bindTexture(button_tex); + RenderUtils.drawTexturedRect(x+width/6f-24, y+45-7-14, 48, 16); + + TextRenderUtils.drawStringCenteredScaledMaxWidth("Add", Minecraft.getMinecraft().fontRendererObj, + x+width/6f, y+45-7-6, + false, 44, 0xFF303030); + + long currentTime = System.currentTimeMillis(); + float greenBlue = LerpUtils.clampZeroOne(((trashHoverTime < 0 ? 250 : 0) + trashHoverTime - currentTime)/250f); + GlStateManager.color(1, greenBlue, greenBlue, 1); + Minecraft.getMinecraft().getTextureManager().bindTexture(DELETE); + Utils.drawTexturedRect(x+width/6f+27, y+45-7-13, 11, 14, GL11.GL_NEAREST); + + Gui.drawRect(x+5, y+45, x+width-5, y+height-5, 0xffdddddd); + Gui.drawRect(x+6, y+46, x+width-6, y+height-6, 0xff000000); + + int i = 0; + int yOff=0; + for(int strIndex : activeText) { + String str = exampleText[strIndex]; + + String[] multilines = str.split("\n"); + + int ySize = multilines.length * 10; + + if(i++ != dragStartIndex) { + for(int multilineIndex=0; multilineIndex<multilines.length; multilineIndex++) { + String line = multilines[multilineIndex]; + Utils.drawStringScaledMaxWidth(line+EnumChatFormatting.RESET, Minecraft.getMinecraft().fontRendererObj, + x+20, y+50+yOff+multilineIndex*10, true, width-20, 0xffffffff); + } + Minecraft.getMinecraft().fontRendererObj.drawString("\u2261", x+10, y+50+yOff + ySize/2f - 4, 0xffffff, true); + } + + yOff += ySize; + } + } + + @Override + public void renderOverlay(int x, int y, int width) { + super.renderOverlay(x, y, width); + + if(dropdownOpen) { + List<Integer> remaining = new ArrayList<>(); + for(int i=0; i<exampleText.length; i++) { + remaining.add(i); + } + remaining.removeAll(activeText); + + FontRenderer fr = Minecraft.getMinecraft().fontRendererObj; + int dropdownWidth = Math.min(width/2-10, 150); + int left = dragOffsetX; + int top = dragOffsetY; + + int dropdownHeight = -1 + 12*remaining.size(); + + int main = 0xff202026; + int outline = 0xff404046; + Gui.drawRect(left, top, left+1, top+dropdownHeight, outline); //Left + Gui.drawRect(left+1, top, left+dropdownWidth, top+1, outline); //Top + Gui.drawRect(left+dropdownWidth-1, top+1, left+dropdownWidth, top+dropdownHeight, outline); //Right + Gui.drawRect(left+1, top+dropdownHeight-1, left+dropdownWidth-1, top+dropdownHeight, outline); //Bottom + Gui.drawRect(left+1, top+1, left+dropdownWidth-1, top+dropdownHeight-1, main); //Middle + + int dropdownY = -1; + for(int strIndex : remaining) { + String str = exampleText[strIndex]; + if(str.isEmpty()) { + str = "<NONE>"; + } + TextRenderUtils.drawStringScaledMaxWidth(str.replaceAll("(\n.*)+", " ..."), + fr, left+3, top+3+dropdownY, false, dropdownWidth-6, 0xffa0a0a0); + dropdownY += 12; + } + } else if(currentDragging >= 0) { + int opacity = 0x80; + long currentTime = System.currentTimeMillis(); + if(trashHoverTime < 0) { + float greenBlue = LerpUtils.clampZeroOne((currentTime + trashHoverTime)/250f); + opacity = (int)(opacity * greenBlue); + } else { + float greenBlue = LerpUtils.clampZeroOne((250 + trashHoverTime - currentTime)/250f); + opacity = (int)(opacity * greenBlue); + } + + if(opacity < 20) return; + + ScaledResolution scaledResolution = new ScaledResolution(Minecraft.getMinecraft()); + int mouseX = Mouse.getX() * scaledResolution.getScaledWidth() / Minecraft.getMinecraft().displayWidth; + int mouseY = scaledResolution.getScaledHeight() - Mouse.getY() * scaledResolution.getScaledHeight() / Minecraft.getMinecraft().displayHeight - 1; + + String str = exampleText[currentDragging]; + + String[] multilines = str.split("\n"); + + GlStateManager.enableBlend(); + for(int multilineIndex=0; multilineIndex<multilines.length; multilineIndex++) { + String line = multilines[multilineIndex]; + Utils.drawStringScaledMaxWidth(line+EnumChatFormatting.RESET, Minecraft.getMinecraft().fontRendererObj, + dragOffsetX + mouseX + 10, dragOffsetY + mouseY + multilineIndex*10, true, width-20, 0xffffff | (opacity << 24)); + } + + int ySize = multilines.length * 10; + + Minecraft.getMinecraft().fontRendererObj.drawString("\u2261", + dragOffsetX + mouseX, + dragOffsetY + mouseY + ySize/2f - 4, 0xffffff, true); + } + } + + @Override + public boolean mouseInput(int x, int y, int width, int mouseX, int mouseY) { + if(!Mouse.getEventButtonState() && !dropdownOpen && + dragStartIndex >= 0 && Mouse.getEventButton() == 0 && + mouseX >= x+width/6+27-3 && mouseX <= x+width/6+27+11+3 && + mouseY >= y+45-7-13-3 && mouseY <= y+45-7-13+14+3) { + activeText.remove(dragStartIndex); + currentDragging = -1; + dragStartIndex = -1; + return false; + } + + if(!Mouse.isButtonDown(0) || dropdownOpen) { + currentDragging = -1; + dragStartIndex = -1; + if(trashHoverTime > 0) trashHoverTime = -System.currentTimeMillis(); + } else if(currentDragging >= 0 && + mouseX >= x+width/6+27-3 && mouseX <= x+width/6+27+11+3 && + mouseY >= y+45-7-13-3 && mouseY <= y+45-7-13+14+3) { + if(trashHoverTime < 0) trashHoverTime = System.currentTimeMillis(); + } else { + if(trashHoverTime > 0) trashHoverTime = -System.currentTimeMillis(); + } + + if(Mouse.getEventButtonState()) { + int height = getHeight(); + + if(dropdownOpen) { + List<Integer> remaining = new ArrayList<>(); + for(int i=0; i<exampleText.length; i++) { + remaining.add(i); + } + remaining.removeAll(activeText); + + int dropdownWidth = Math.min(width/2-10, 150); + int left = dragOffsetX; + int top = dragOffsetY; + + int dropdownHeight = -1 + 12*remaining.size(); + + if(mouseX > left && mouseX < left+dropdownWidth && + mouseY > top && mouseY < top + dropdownHeight) { + int dropdownY = -1; + for(int strIndex : remaining) { + if(mouseY < top+dropdownY+12) { + activeText.add(0, strIndex); + if(remaining.size() == 1) dropdownOpen = false; + return true; + } + + dropdownY += 12; + } + } + + dropdownOpen = false; + return true; + } + + if(activeText.size() < exampleText.length && + mouseX > x+width/6-24 && mouseX < x+width/6+24 && + mouseY > y+45-7-14 && mouseY < y+45-7+2) { + dropdownOpen = !dropdownOpen; + dragOffsetX = mouseX; + dragOffsetY = mouseY; + return true; + } + + if(Mouse.getEventButton() == 0 && + mouseX > x+5 && mouseX < x+width-5 && + mouseY > y+45 && mouseY < y+height-6) { + int yOff=0; + int i = 0; + for(int strIndex : activeText) { + int ySize = 10 * exampleText[strIndex].split("\n").length; + if(mouseY < y+50+yOff+ySize) { + dragOffsetX = x+10 - mouseX; + dragOffsetY = y+50+yOff - mouseY; + + currentDragging = strIndex; + dragStartIndex = i; + break; + } + yOff += ySize; + i++; + } + } + } else if(Mouse.getEventButton() == -1 && currentDragging >= 0) { + int yOff=0; + int i = 0; + for(int strIndex : activeText) { + if(dragOffsetY + mouseY + 4 < y+50+yOff+10) { + activeText.remove(dragStartIndex); + activeText.add(i, currentDragging); + + dragStartIndex = i; + break; + } + yOff += 10 * exampleText[strIndex].split("\n").length; + i++; + } + } + + return false; + } + + @Override + public boolean keyboardInput() { + return false; + } +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/core/config/gui/GuiOptionEditorDropdown.java b/src/main/java/com/thatgravyboat/skyblockhud/core/config/gui/GuiOptionEditorDropdown.java new file mode 100644 index 0000000..5c797ad --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/core/config/gui/GuiOptionEditorDropdown.java @@ -0,0 +1,152 @@ +package com.thatgravyboat.skyblockhud.core.config.gui; + +import com.thatgravyboat.skyblockhud.core.config.struct.ConfigProcessor; +import com.thatgravyboat.skyblockhud.core.util.render.RenderUtils; +import com.thatgravyboat.skyblockhud.core.util.render.TextRenderUtils; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.gui.Gui; +import net.minecraft.client.renderer.GlStateManager; +import org.lwjgl.input.Mouse; +import org.lwjgl.opengl.GL11; + +public class GuiOptionEditorDropdown extends GuiOptionEditor { + + private final String[] values; + private final boolean useOrdinal; + private int selected; + private boolean open = false; + + public GuiOptionEditorDropdown(ConfigProcessor.ProcessedOption option, String[] values, int selected, boolean useOrdinal) { + super(option); + if(selected >= values.length) selected = values.length; + this.values = values; + this.selected = selected; + this.useOrdinal = useOrdinal; + } + + @Override + public void render(int x, int y, int width) { + super.render(x, y, width); + + if(!open) { + int height = getHeight(); + + FontRenderer fr = Minecraft.getMinecraft().fontRendererObj; + int dropdownWidth = Math.min(width/3-10, 80); + int left = x+width/6-dropdownWidth/2; + int top = y+height-7-14; + + String selectedString = " - Select - "; + if(selected >= 0 && selected < values.length) { + selectedString = values[selected]; + } + + RenderUtils.drawFloatingRectDark(left, top, dropdownWidth, 14, false); + TextRenderUtils.drawStringScaled("\u25BC", fr, left+dropdownWidth-10, y+height-7-15, false, 0xffa0a0a0, 2); + + TextRenderUtils.drawStringScaledMaxWidth(selectedString, fr, left+3, top+3, false, + dropdownWidth-16, 0xffa0a0a0); + } + } + + @Override + public void renderOverlay(int x, int y, int width) { + if(open) { + String selectedString = " - Select - "; + if(selected >= 0 && selected < values.length) { + selectedString = values[selected]; + } + + int height = getHeight(); + + FontRenderer fr = Minecraft.getMinecraft().fontRendererObj; + int dropdownWidth = Math.min(width/3-10, 80); + int left = x+width/6-dropdownWidth/2; + int top = y+height-7-14; + + int dropdownHeight = 13 + 12*values.length; + + int main = 0xff202026; + int blue = 0xff2355ad; + Gui.drawRect(left, top, left+1, top+dropdownHeight, blue); //Left + Gui.drawRect(left+1, top, left+dropdownWidth, top+1, blue); //Top + Gui.drawRect(left+dropdownWidth-1, top+1, left+dropdownWidth, top+dropdownHeight, blue); //Right + Gui.drawRect(left+1, top+dropdownHeight-1, left+dropdownWidth-1, top+dropdownHeight, blue); //Bottom + Gui.drawRect(left+1, top+1, left+dropdownWidth-1, top+dropdownHeight-1, main); //Middle + + Gui.drawRect(left+1, top+14-1, left+dropdownWidth-1, top+14, blue); //Bar + + int dropdownY = 13; + for(String option : values) { + if(option.isEmpty()) { + option = "<NONE>"; + } + TextRenderUtils.drawStringScaledMaxWidth(option, fr, left+3, top+3+dropdownY, false, dropdownWidth-6, 0xffa0a0a0); + dropdownY += 12; + } + + TextRenderUtils.drawStringScaled("\u25B2", fr, left+dropdownWidth-10, y+height-7-15, false, 0xffa0a0a0, 2); + + + TextRenderUtils.drawStringScaledMaxWidth(selectedString, fr, left+3, top+3, false, + dropdownWidth-16, 0xffa0a0a0); + } + } + + @Override + public boolean mouseInput(int x, int y, int width, int mouseX, int mouseY) { + int height = getHeight(); + + int left = x+width/6-40; + int top = y+height-7-14; + + if(Mouse.getEventButtonState() && Mouse.getEventButton() == 0) { + if(mouseX >= left && mouseX <= left+80 && + mouseY >= top && mouseY <= top+14) { + open = !open; + return true; + } + } + + return false; + } + + @Override + public boolean mouseInputOverlay(int x, int y, int width, int mouseX, int mouseY) { + int height = getHeight(); + + int left = x+width/6-40; + int top = y+height-7-14; + + if(Mouse.getEventButtonState() && Mouse.getEventButton() == 0) { + if(!(mouseX >= left && mouseX <= left+80 && + mouseY >= top && mouseY <= top+14) && open) { + open = false; + if(mouseX >= left && mouseX <= left+80) { + int dropdownY = 13; + for(int ordinal=0; ordinal < values.length; ordinal++) { + if(mouseY >= top+3+dropdownY && mouseY <= top+3+dropdownY+12) { + selected = ordinal; + if(useOrdinal) { + option.set(selected); + } else { + option.set(values[selected]); + } + return true; + } + dropdownY += 12; + } + } + return true; + } + } + + return false; + } + + @Override + public boolean keyboardInput() { + return false; + } +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/core/config/gui/GuiOptionEditorSlider.java b/src/main/java/com/thatgravyboat/skyblockhud/core/config/gui/GuiOptionEditorSlider.java new file mode 100644 index 0000000..a37b952 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/core/config/gui/GuiOptionEditorSlider.java @@ -0,0 +1,132 @@ +package com.thatgravyboat.skyblockhud.core.config.gui; + +import com.thatgravyboat.skyblockhud.core.GuiElementBoolean; +import com.thatgravyboat.skyblockhud.core.GuiElementTextField; +import com.thatgravyboat.skyblockhud.core.config.struct.ConfigProcessor; +import com.thatgravyboat.skyblockhud.core.util.GuiElementSlider; +import net.minecraft.client.Minecraft; +import org.lwjgl.input.Keyboard; +import org.lwjgl.input.Mouse; + +public class GuiOptionEditorSlider extends GuiOptionEditor { + + private final GuiElementSlider slider; + private final GuiElementTextField textField; + + public GuiOptionEditorSlider(ConfigProcessor.ProcessedOption option, float minValue, float maxValue, float minStep) { + super(option); + if(minStep < 0) minStep = 0.01f; + + float floatVal = ((Number)option.get()).floatValue(); + { + String strVal; + if(floatVal % 1 == 0) { + strVal = Integer.toString((int)floatVal); + } else { + strVal = Float.toString(floatVal); + } + textField = new GuiElementTextField(strVal, + GuiElementTextField.NO_SPACE | GuiElementTextField.NUM_ONLY | GuiElementTextField.SCALE_TEXT); + } + + slider = new GuiElementSlider(0, 0, 80, minValue, maxValue, minStep, floatVal, (val) -> { + option.set(val); + + String strVal; + if(val % 1 == 0) { + strVal = Integer.toString(val.intValue()); + } else { + strVal = Float.toString(val); + strVal = strVal.replaceAll("(\\.\\d\\d\\d)(?:\\d)+", "$1"); + strVal = strVal.replaceAll("0+$", ""); + } + textField.setText(strVal); + }); + } + + @Override + public void render(int x, int y, int width) { + super.render(x, y, width); + int height = getHeight(); + + int fullWidth = Math.min(width/3-10, 80); + int sliderWidth = (fullWidth-5)*3/4; + int textFieldWidth = (fullWidth-5)/4; + + slider.x = x+width/6-fullWidth/2; + slider.y = y+height-7-14; + slider.width = sliderWidth; + slider.render(); + + if(textField.getFocus()) { + textField.setOptions(GuiElementTextField.NO_SPACE | GuiElementTextField.NUM_ONLY); + textField.setSize(Minecraft.getMinecraft().fontRendererObj.getStringWidth(textField.getText())+10, + 16); + } else { + textField.setSize(textFieldWidth, 16); + textField.setOptions(GuiElementTextField.NO_SPACE | GuiElementTextField.NUM_ONLY | GuiElementTextField.SCALE_TEXT); + } + + textField.render(x+width/6-fullWidth/2+sliderWidth+5, y+height-7-14); + } + + @Override + public boolean mouseInput(int x, int y, int width, int mouseX, int mouseY) { + int height = getHeight(); + + int fullWidth = Math.min(width/3-10, 80); + int sliderWidth = (fullWidth-5)*3/4; + int textFieldWidth = (fullWidth-5)/4; + + slider.x = x+width/6-fullWidth/2; + slider.y = y+height-7-14; + slider.width = sliderWidth; + if(slider.mouseInput(mouseX, mouseY)) { + textField.unfocus(); + return true; + } + + if(textField.getFocus()) { + textFieldWidth = Minecraft.getMinecraft().fontRendererObj.getStringWidth(textField.getText())+10; + } + + int textFieldX = x+width/6-fullWidth/2+sliderWidth+5; + int textFieldY = y+height-7-14; + textField.setSize(textFieldWidth, 16); + + if(Mouse.getEventButtonState() && (Mouse.getEventButton() == 0 || Mouse.getEventButton() == 1)) { + if(mouseX > textFieldX && mouseX < textFieldX+textFieldWidth && + mouseY > textFieldY && mouseY < textFieldY+16) { + textField.mouseClicked(mouseX, mouseY, Mouse.getEventButton()); + return true; + } + textField.unfocus(); + } + + return false; + } + + @Override + public boolean keyboardInput() { + if(Keyboard.getEventKeyState() && textField.getFocus()) { + textField.keyTyped(Keyboard.getEventCharacter(), Keyboard.getEventKey()); + + try { + textField.setCustomBorderColour(0xffffffff); + float f = Float.parseFloat(textField.getText()); + if(option.set(f)) { + slider.setValue(f); + } else { + textField.setCustomBorderColour(0xff0000ff); + } + } catch(Exception e) { + textField.setCustomBorderColour(0xffff0000); + } + + return true; + } + return false; + } + + +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/core/config/gui/GuiOptionEditorText.java b/src/main/java/com/thatgravyboat/skyblockhud/core/config/gui/GuiOptionEditorText.java new file mode 100644 index 0000000..e42d5b3 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/core/config/gui/GuiOptionEditorText.java @@ -0,0 +1,84 @@ +package com.thatgravyboat.skyblockhud.core.config.gui; + +import com.thatgravyboat.skyblockhud.core.GuiElementBoolean; +import com.thatgravyboat.skyblockhud.core.GuiElementTextField; +import com.thatgravyboat.skyblockhud.core.config.struct.ConfigProcessor; +import com.thatgravyboat.skyblockhud.core.util.GuiElementSlider; +import net.minecraft.client.Minecraft; +import org.lwjgl.input.Keyboard; +import org.lwjgl.input.Mouse; + +public class GuiOptionEditorText extends GuiOptionEditor { + + private final GuiElementTextField textField; + + public GuiOptionEditorText(ConfigProcessor.ProcessedOption option) { + super(option); + + textField = new GuiElementTextField((String)option.get(), 0); + } + + @Override + public void render(int x, int y, int width) { + super.render(x, y, width); + int height = getHeight(); + + int fullWidth = Math.min(width/3-10, 80); + + int textFieldX = x+width/6-fullWidth/2; + if(textField.getFocus()) { + fullWidth = Math.max(fullWidth, Minecraft.getMinecraft().fontRendererObj.getStringWidth(textField.getText())+10); + } + + textField.setSize(fullWidth, 16); + + textField.render(textFieldX, y+height-7-14); + } + + @Override + public boolean mouseInput(int x, int y, int width, int mouseX, int mouseY) { + int height = getHeight(); + + int fullWidth = Math.min(width/3-10, 80); + + int textFieldX = x+width/6-fullWidth/2; + + if(textField.getFocus()) { + fullWidth = Math.max(fullWidth, Minecraft.getMinecraft().fontRendererObj.getStringWidth(textField.getText())+10); + } + + int textFieldY = y+height-7-14; + textField.setSize(fullWidth, 16); + + if(Mouse.getEventButtonState() && (Mouse.getEventButton() == 0 || Mouse.getEventButton() == 1)) { + if(mouseX > textFieldX && mouseX < textFieldX+fullWidth && + mouseY > textFieldY && mouseY < textFieldY+16) { + textField.mouseClicked(mouseX, mouseY, Mouse.getEventButton()); + return true; + } + textField.unfocus(); + } + + return false; + } + + @Override + public boolean keyboardInput() { + if(Keyboard.getEventKeyState() && textField.getFocus()) { + Keyboard.enableRepeatEvents(true); + textField.keyTyped(Keyboard.getEventCharacter(), Keyboard.getEventKey()); + + try { + textField.setCustomBorderColour(0xffffffff); + option.set(textField.getText()); + } catch(Exception e) { + textField.setCustomBorderColour(0xffff0000); + } + + return true; + } + return false; + } + + +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/core/config/gui/GuiPositionEditor.java b/src/main/java/com/thatgravyboat/skyblockhud/core/config/gui/GuiPositionEditor.java new file mode 100644 index 0000000..e178843 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/core/config/gui/GuiPositionEditor.java @@ -0,0 +1,179 @@ +package com.thatgravyboat.skyblockhud.core.config.gui; + +import com.thatgravyboat.skyblockhud.Utils; +import com.thatgravyboat.skyblockhud.core.config.Position; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Gui; +import net.minecraft.client.gui.GuiScreen; +import net.minecraft.client.gui.ScaledResolution; +import net.minecraft.client.renderer.GlStateManager; +import org.lwjgl.input.Keyboard; +import org.lwjgl.input.Mouse; + +import java.io.IOException; + +public class GuiPositionEditor extends GuiScreen { + + private final Position position; + private Position originalPosition; + private final int elementWidth; + private final int elementHeight; + private final Runnable renderCallback; + private final Runnable positionChangedCallback; + private final Runnable closedCallback; + private boolean clicked = false; + private int grabbedX = 0; + private int grabbedY = 0; + + private int guiScaleOverride = -1; + + public GuiPositionEditor(Position position, int elementWidth, int elementHeight, + Runnable renderCallback, + Runnable positionChangedCallback, + Runnable closedCallback) { + this.position = position; + this.originalPosition = position.clone(); + this.elementWidth = elementWidth == -1 ? this.width : elementWidth; + this.elementHeight = elementHeight; + this.renderCallback = renderCallback; + this.positionChangedCallback = positionChangedCallback; + this.closedCallback = closedCallback; + } + + public GuiPositionEditor withScale(int scale) { + this.guiScaleOverride = scale; + return this; + } + + @Override + public void onGuiClosed() { + super.onGuiClosed(); + closedCallback.run(); + } + + @Override + public void drawScreen(int mouseX, int mouseY, float partialTicks) { + super.drawScreen(mouseX, mouseY, partialTicks); + ScaledResolution scaledResolution; + if(guiScaleOverride >= 0) { + scaledResolution = Utils.pushGuiScale(guiScaleOverride); + } else { + scaledResolution = new ScaledResolution(Minecraft.getMinecraft()); + } + + this.width = scaledResolution.getScaledWidth(); + this.height = scaledResolution.getScaledHeight(); + mouseX = Mouse.getX() * width / Minecraft.getMinecraft().displayWidth; + mouseY = height - Mouse.getY() * height / Minecraft.getMinecraft().displayHeight - 1; + + drawDefaultBackground(); + + if(clicked) { + grabbedX += position.moveX(mouseX - grabbedX, elementWidth, scaledResolution); + grabbedY += position.moveY(mouseY - grabbedY, elementHeight, scaledResolution); + } + + renderCallback.run(); + + int x = position.getAbsX(scaledResolution, elementWidth); + int y = position.getAbsY(scaledResolution, elementHeight); + + if(position.isCenterX()) x -= elementWidth/2; + if(position.isCenterY()) y -= elementHeight/2; + Gui.drawRect(x, y, x+elementWidth, y+elementHeight, 0x80404040); + + if(guiScaleOverride >= 0) { + Utils.pushGuiScale(-1); + } + + scaledResolution = new ScaledResolution(Minecraft.getMinecraft()); + Utils.drawStringCentered("Position Editor", Minecraft.getMinecraft().fontRendererObj, + scaledResolution.getScaledWidth()/2f, 8, true, 0xffffff); + Utils.drawStringCentered("R to Reset - Arrow keys/mouse to move", Minecraft.getMinecraft().fontRendererObj, + scaledResolution.getScaledWidth()/2f, 18, true, 0xffffff); + } + + @Override + protected void mouseClicked(int mouseX, int mouseY, int mouseButton) throws IOException { + super.mouseClicked(mouseX, mouseY, mouseButton); + + if(mouseButton == 0) { + ScaledResolution scaledResolution; + if(guiScaleOverride >= 0) { + scaledResolution = Utils.pushGuiScale(guiScaleOverride); + } else { + scaledResolution = new ScaledResolution(Minecraft.getMinecraft()); + } + mouseX = Mouse.getX() * width / Minecraft.getMinecraft().displayWidth; + mouseY = height - Mouse.getY() * height / Minecraft.getMinecraft().displayHeight - 1; + + int x = position.getAbsX(scaledResolution, elementWidth); + int y = position.getAbsY(scaledResolution, elementHeight); + if(position.isCenterX()) x -= elementWidth/2; + if(position.isCenterY()) y -= elementHeight/2; + + if(mouseX >= x && mouseY >= y && + mouseX <= x+elementWidth && mouseY <= y+elementHeight) { + clicked = true; + grabbedX = mouseX; + grabbedY = mouseY; + } + + if(guiScaleOverride >= 0) { + Utils.pushGuiScale(-1); + } + } + } + + @Override + protected void keyTyped(char typedChar, int keyCode) throws IOException { + Keyboard.enableRepeatEvents(true); + + if(keyCode == Keyboard.KEY_R) { + position.set(originalPosition); + } else if(!clicked) { + boolean shiftHeld = Keyboard.isKeyDown(Keyboard.KEY_LSHIFT) || Keyboard.isKeyDown(Keyboard.KEY_RSHIFT); + int dist = shiftHeld ? 10 : 1; + if(keyCode == Keyboard.KEY_DOWN) { + position.moveY(dist, elementHeight, new ScaledResolution(Minecraft.getMinecraft())); + } else if(keyCode == Keyboard.KEY_UP) { + position.moveY(-dist, elementHeight, new ScaledResolution(Minecraft.getMinecraft())); + } else if(keyCode == Keyboard.KEY_LEFT) { + position.moveX(-dist, elementWidth, new ScaledResolution(Minecraft.getMinecraft())); + } else if(keyCode == Keyboard.KEY_RIGHT) { + position.moveX(dist, elementWidth, new ScaledResolution(Minecraft.getMinecraft())); + } + } + super.keyTyped(typedChar, keyCode); + } + + @Override + protected void mouseReleased(int mouseX, int mouseY, int state) { + super.mouseReleased(mouseX, mouseY, state); + clicked = false; + } + + @Override + protected void mouseClickMove(int mouseX, int mouseY, int clickedMouseButton, long timeSinceLastClick) { + super.mouseClickMove(mouseX, mouseY, clickedMouseButton, timeSinceLastClick); + + if(clicked) { + ScaledResolution scaledResolution; + if(guiScaleOverride >= 0) { + scaledResolution = Utils.pushGuiScale(guiScaleOverride); + } else { + scaledResolution = new ScaledResolution(Minecraft.getMinecraft()); + } + mouseX = Mouse.getX() * width / Minecraft.getMinecraft().displayWidth; + mouseY = height - Mouse.getY() * height / Minecraft.getMinecraft().displayHeight - 1; + + grabbedX += position.moveX(mouseX - grabbedX, elementWidth, scaledResolution); + grabbedY += position.moveY(mouseY - grabbedY, elementHeight, scaledResolution); + positionChangedCallback.run(); + + if(guiScaleOverride >= 0) { + Utils.pushGuiScale(-1); + } + } + } +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/core/config/struct/ConfigProcessor.java b/src/main/java/com/thatgravyboat/skyblockhud/core/config/struct/ConfigProcessor.java new file mode 100644 index 0000000..aef92d8 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/core/config/struct/ConfigProcessor.java @@ -0,0 +1,176 @@ +package com.thatgravyboat.skyblockhud.core.config.struct; + +import com.google.gson.annotations.Expose; +import com.thatgravyboat.skyblockhud.core.config.Config; +import com.thatgravyboat.skyblockhud.core.config.annotations.*; +import com.thatgravyboat.skyblockhud.core.config.gui.*; +import com.thatgravyboat.skyblockhud.core.config.Config; + +import java.lang.reflect.Field; +import java.util.LinkedHashMap; +import java.util.List; + +public class ConfigProcessor { + + public static class ProcessedCategory { + public final String name; + public final String desc; + public final LinkedHashMap<String, ProcessedOption> options = new LinkedHashMap<>(); + + public ProcessedCategory(String name, String desc) { + this.name = name; + this.desc = desc; + } + } + + public static class ProcessedOption { + public final String name; + public final String desc; + public final int subcategoryId; + public GuiOptionEditor editor; + + public int accordionId = -1; + + private final Field field; + private final Object container; + + public ProcessedOption(String name, String desc, int subcategoryId, Field field, Object container) { + this.name = name; + this.desc = desc; + this.subcategoryId = subcategoryId; + + this.field = field; + this.container = container; + } + + public Object get() { + try { + return field.get(container); + } catch(Exception e) { + return null; + } + } + + public boolean set(Object value) { + try { + if(field.getType() == int.class && value instanceof Number) { + field.set(container, ((Number)value).intValue()); + } else { + field.set(container, value); + } + return true; + } catch(Exception e) { + e.printStackTrace(); + return false; + } + } + } + + public static LinkedHashMap<String, ProcessedCategory> create(Config config) { + LinkedHashMap<String, ProcessedCategory> processedConfig = new LinkedHashMap<>(); + for(Field categoryField : config.getClass().getDeclaredFields()) { + boolean exposePresent = categoryField.isAnnotationPresent(Expose.class); + boolean categoryPresent = categoryField.isAnnotationPresent(Category.class); + + if(exposePresent && categoryPresent) { + Object categoryObj; + try { + categoryObj = categoryField.get(config); + } catch(Exception e) { + //System.err.printf("Failed to load config category %s. Field was not accessible.\n", categoryField.getName()); + continue; + } + + Category categoryAnnotation = categoryField.getAnnotation(Category.class); + ProcessedCategory cat = new ProcessedCategory( + categoryAnnotation.name(), + categoryAnnotation.desc() + ); + processedConfig.put(categoryField.getName(), cat); + + for(Field optionField : categoryObj.getClass().getDeclaredFields()) { + boolean optionPresent = optionField.isAnnotationPresent(ConfigOption.class); + + if(optionPresent) { + ConfigOption optionAnnotation = optionField.getAnnotation(ConfigOption.class); + ProcessedOption option = new ProcessedOption( + optionAnnotation.name(), + optionAnnotation.desc(), + optionAnnotation.subcategoryId(), + optionField, + categoryObj + ); + if(optionField.isAnnotationPresent(ConfigAccordionId.class)) { + ConfigAccordionId annotation = optionField.getAnnotation(ConfigAccordionId.class); + option.accordionId = annotation.id(); + } + + GuiOptionEditor editor = null; + Class<?> optionType = optionField.getType(); + if(optionField.isAnnotationPresent(ConfigEditorButton.class)) { + ConfigEditorButton configEditorAnnotation = optionField.getAnnotation(ConfigEditorButton.class); + editor = new GuiOptionEditorButton(option, configEditorAnnotation.runnableId(), configEditorAnnotation.buttonText(), config); + } + if(optionType.isAssignableFrom(boolean.class) && + optionField.isAnnotationPresent(ConfigEditorBoolean.class)) { + editor = new GuiOptionEditorBoolean(option); + } + if(optionType.isAssignableFrom(boolean.class) && + optionField.isAnnotationPresent(ConfigEditorAccordion.class)) { + ConfigEditorAccordion configEditorAnnotation = optionField.getAnnotation(ConfigEditorAccordion.class); + editor = new GuiOptionEditorAccordion(option, configEditorAnnotation.id()); + } + if(optionType.isAssignableFrom(int.class)) { + if(optionField.isAnnotationPresent(ConfigEditorDropdown.class)) { + ConfigEditorDropdown configEditorAnnotation = optionField.getAnnotation(ConfigEditorDropdown.class); + editor = new GuiOptionEditorDropdown(option, configEditorAnnotation.values(), (int)option.get(), true); + } + } + if(optionType.isAssignableFrom(List.class)) { + if(optionField.isAnnotationPresent(ConfigEditorDraggableList.class)) { + ConfigEditorDraggableList configEditorAnnotation = optionField.getAnnotation(ConfigEditorDraggableList.class); + editor = new GuiOptionEditorDraggableList(option, configEditorAnnotation.exampleText()); + } + } + if(optionType.isAssignableFrom(String.class)) { + if(optionField.isAnnotationPresent(ConfigEditorDropdown.class)) { + ConfigEditorDropdown configEditorAnnotation = optionField.getAnnotation(ConfigEditorDropdown.class); + editor = new GuiOptionEditorDropdown(option, configEditorAnnotation.values(), + configEditorAnnotation.initialIndex(), false); + } else if(optionField.isAnnotationPresent(ConfigEditorColour.class)) { + editor = new GuiOptionEditorColour(option); + } else if(optionField.isAnnotationPresent(ConfigEditorText.class)) { + editor = new GuiOptionEditorText(option); + } + } + if(optionType.isAssignableFrom(int.class) || + optionType.isAssignableFrom(float.class) || + optionType.isAssignableFrom(double.class)) { + if(optionField.isAnnotationPresent(ConfigEditorSlider.class)) { + ConfigEditorSlider configEditorAnnotation = optionField.getAnnotation(ConfigEditorSlider.class); + editor = new GuiOptionEditorSlider(option, configEditorAnnotation.minValue(), + configEditorAnnotation.maxValue(), configEditorAnnotation.minStep()); + } + } + if(optionType.isAssignableFrom(String.class)) { + if(optionField.isAnnotationPresent(ConfigEditorDropdown.class)) { + ConfigEditorDropdown configEditorAnnotation = optionField.getAnnotation(ConfigEditorDropdown.class); + editor = new GuiOptionEditorDropdown(option, configEditorAnnotation.values(), 0,false); + } + } + if(editor == null) { + //System.err.printf("Failed to load config option %s. Could not find suitable editor.\n", optionField.getName()); + continue; + } + option.editor = editor; + cat.options.put(optionField.getName(), option); + } + } + } else if(exposePresent || categoryPresent) { + //System.err.printf("Failed to load config category %s. Both @Expose and @Category must be present.\n", categoryField.getName()); + } + } + return processedConfig; + } + +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/core/util/GuiElementSlider.java b/src/main/java/com/thatgravyboat/skyblockhud/core/util/GuiElementSlider.java new file mode 100644 index 0000000..ee963c2 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/core/util/GuiElementSlider.java @@ -0,0 +1,123 @@ +package com.thatgravyboat.skyblockhud.core.util; + +import com.thatgravyboat.skyblockhud.Utils; +import com.thatgravyboat.skyblockhud.core.GuiElement; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.ScaledResolution; +import net.minecraft.client.renderer.GlStateManager; +import org.lwjgl.input.Mouse; +import org.lwjgl.opengl.GL11; + +import java.util.function.Consumer; + +import static com.thatgravyboat.skyblockhud.GuiTextures.*; + +public class GuiElementSlider extends GuiElement { + + public int x; + public int y; + public int width; + private static final int HEIGHT = 16; + + private float minValue; + private float maxValue; + private float minStep; + + private float value; + private Consumer<Float> setCallback; + + private boolean clicked = false; + + public GuiElementSlider(int x, int y, int width, float minValue, float maxValue, float minStep, + float value, Consumer<Float> setCallback) { + if(minStep < 0) minStep = 0.01f; + + this.x = x; + this.y = y; + this.width = width; + this.minValue = minValue; + this.maxValue = maxValue; + this.minStep = minStep; + this.value = value; + this.setCallback = setCallback; + } + + public void setValue(float value) { + this.value = value; + } + + @Override + public void render() { + final ScaledResolution scaledResolution = new ScaledResolution(Minecraft.getMinecraft()); + int mouseX = Mouse.getX() * scaledResolution.getScaledWidth() / Minecraft.getMinecraft().displayWidth; + + float value = this.value; + if(clicked) { + value = (mouseX-x)*(maxValue-minValue)/width+minValue; + value = Math.max(minValue, Math.min(maxValue, value)); + value = Math.round(value/minStep)*minStep; + } + + float sliderAmount = Math.max(0, Math.min(1, (value-minValue)/(maxValue-minValue))); + int sliderAmountI = (int)(width*sliderAmount); + + GlStateManager.color(1f, 1f, 1f, 1f); + Minecraft.getMinecraft().getTextureManager().bindTexture(slider_on_cap); + Utils.drawTexturedRect(x, y, 4, HEIGHT, GL11.GL_NEAREST); + Minecraft.getMinecraft().getTextureManager().bindTexture(slider_off_cap); + Utils.drawTexturedRect(x+width-4, y, 4, HEIGHT, GL11.GL_NEAREST); + + if(sliderAmountI > 5) { + Minecraft.getMinecraft().getTextureManager().bindTexture(slider_on_segment); + Utils.drawTexturedRect(x+4, y, sliderAmountI-4, HEIGHT, GL11.GL_NEAREST); + } + + if(sliderAmountI < width-5) { + Minecraft.getMinecraft().getTextureManager().bindTexture(slider_off_segment); + Utils.drawTexturedRect(x+sliderAmountI, y, width-4-sliderAmountI, HEIGHT, GL11.GL_NEAREST); + } + + for(int i=1; i<4; i++) { + int notchX = x+width*i/4-1; + Minecraft.getMinecraft().getTextureManager().bindTexture(notchX > x+sliderAmountI ? slider_off_notch : slider_on_notch); + Utils.drawTexturedRect(notchX, y+(HEIGHT-4)/2f, 2, 4, GL11.GL_NEAREST); + } + + Minecraft.getMinecraft().getTextureManager().bindTexture(slider_button_new); + Utils.drawTexturedRect(x+sliderAmountI-4, y, 8, HEIGHT, GL11.GL_NEAREST); + } + + @Override + public boolean mouseInput(int mouseX, int mouseY) { + if(!Mouse.isButtonDown(0)) { + clicked = false; + } + + if(Mouse.getEventButton() == 0) { + clicked = Mouse.getEventButtonState() && mouseX > x && mouseX < x+width && mouseY > y && mouseY < y+HEIGHT; + if(clicked) { + value = (mouseX-x)*(maxValue-minValue)/width+minValue; + value = Math.max(minValue, Math.min(maxValue, value)); + value = (float)(Math.round(value/minStep)*(double)minStep); + setCallback.accept(value); + return true; + } + } + + if(!Mouse.getEventButtonState() && Mouse.getEventButton() == -1 && clicked) { + value = (mouseX-x)*(maxValue-minValue)/width+minValue; + value = Math.max(minValue, Math.min(maxValue, value)); + value = Math.round(value/minStep)*minStep; + setCallback.accept(value); + return true; + } + + return false; + } + + @Override + public boolean keyboardInput() { + return false; + } + +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/core/util/MiscUtils.java b/src/main/java/com/thatgravyboat/skyblockhud/core/util/MiscUtils.java new file mode 100644 index 0000000..da89e75 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/core/util/MiscUtils.java @@ -0,0 +1,104 @@ +package com.thatgravyboat.skyblockhud.core.util; + +import net.minecraft.client.Minecraft; +import net.minecraft.util.ResourceLocation; +import org.lwjgl.BufferUtils; +import org.lwjgl.input.Cursor; +import org.lwjgl.input.Mouse; + +import javax.imageio.ImageIO; +import java.awt.*; +import java.awt.datatransfer.StringSelection; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.IntBuffer; +import java.nio.file.Files; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; + +public class MiscUtils { + + public static void copyToClipboard(String str) { + Toolkit.getDefaultToolkit().getSystemClipboard() + .setContents(new StringSelection(str), null); + } + private static void unzip(InputStream src, File dest) { + //buffer for read and write data to file + byte[] buffer = new byte[1024]; + try { + ZipInputStream zis = new ZipInputStream(src); + ZipEntry ze = zis.getNextEntry(); + while(ze != null){ + if(!ze.isDirectory()) { + String fileName = ze.getName(); + File newFile = new File(dest, fileName); + //create directories for sub directories in zip + new File(newFile.getParent()).mkdirs(); + FileOutputStream fos = new FileOutputStream(newFile); + int len; + while ((len = zis.read(buffer)) > 0) { + fos.write(buffer, 0, len); + } + fos.close(); + } + //close this ZipEntry + zis.closeEntry(); + ze = zis.getNextEntry(); + } + //close last ZipEntry + zis.closeEntry(); + zis.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public static void recursiveDelete(File file) { + if(file.isDirectory() && !Files.isSymbolicLink(file.toPath())) { + for(File child : file.listFiles()) { + recursiveDelete(child); + } + } + file.delete(); + } + + private static String currentCursor = null; + + public static void resetCursor() { + if(currentCursor == null) { + return; + } + currentCursor = null; + try { Mouse.setNativeCursor(null); } catch(Exception ignored) {} + } + + public static void setCursor(ResourceLocation loc, int hotspotX, int hotspotY) { + if(currentCursor != null && loc.getResourcePath().equals(currentCursor)) { + return; + } + currentCursor = loc.getResourcePath(); + try { + BufferedImage image = ImageIO.read(Minecraft.getMinecraft() + .getResourceManager().getResource(loc).getInputStream()); + int maxSize = Cursor.getMaxCursorSize(); + IntBuffer buffer = BufferUtils.createIntBuffer(maxSize*maxSize); + for(int i=0; i<maxSize*maxSize; i++) { + int cursorX = i%maxSize; + int cursorY = i/maxSize; + if(cursorX >= image.getWidth() || cursorY >= image.getHeight()) { + buffer.put(0x00000000); + } else { + buffer.put(image.getRGB(cursorX, image.getHeight()-1-cursorY)); + } + } + buffer.flip(); + Mouse.setNativeCursor(new Cursor(maxSize, maxSize, hotspotX, hotspotY, 1, + buffer, null)); + } catch(Exception e) { + e.printStackTrace(); + } + } +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/core/util/Splitters.java b/src/main/java/com/thatgravyboat/skyblockhud/core/util/Splitters.java new file mode 100644 index 0000000..9736803 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/core/util/Splitters.java @@ -0,0 +1,10 @@ +package com.thatgravyboat.skyblockhud.core.util; + +import com.google.common.base.Splitter; + +public class Splitters { + + public static final Splitter NEWLINE_SPLITTER = Splitter.on('\n'); + + +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/core/util/StringUtils.java b/src/main/java/com/thatgravyboat/skyblockhud/core/util/StringUtils.java new file mode 100644 index 0000000..d8fd0e6 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/core/util/StringUtils.java @@ -0,0 +1,39 @@ +package com.thatgravyboat.skyblockhud.core.util; + +import com.google.common.collect.Sets; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; + +import java.util.Set; + +public class StringUtils { + + public static final Set<String> PROTOCOLS = Sets.newHashSet("http", "https"); + + public static String cleanColour(String in) { + return in.replaceAll("(?i)\\u00A7.", ""); + } + + public static String cleanColourNotModifiers(String in) { + return in.replaceAll("(?i)\\u00A7[0-9a-f]", "\u00A7r"); + } + + public static String trimToWidth(String str, int len) { + FontRenderer fr = Minecraft.getMinecraft().fontRendererObj; + String trim = fr.trimStringToWidth(str, len); + + if(str.length() != trim.length() && !trim.endsWith(" ")) { + char next = str.charAt(trim.length()); + if(next != ' ') { + String[] split = trim.split(" "); + String last = split[split.length-1]; + if(last.length() < 8) { + trim = trim.substring(0, trim.length()-last.length()); + } + } + } + + return trim; + } + +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/core/util/lerp/LerpUtils.java b/src/main/java/com/thatgravyboat/skyblockhud/core/util/lerp/LerpUtils.java new file mode 100644 index 0000000..e742ab1 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/core/util/lerp/LerpUtils.java @@ -0,0 +1,26 @@ +package com.thatgravyboat.skyblockhud.core.util.lerp; + +public class LerpUtils { + + public static float clampZeroOne(float f) { + return Math.max(0, Math.min(1, f)); + } + + public static float sigmoid(float val) { + return (float)(1/(1 + Math.exp(-val))); + } + + private static final float sigmoidStr = 8; + private static final float sigmoidA = -1/(sigmoid(-0.5f * sigmoidStr) - sigmoid(0.5f * sigmoidStr)); + private static final float sigmoidB = sigmoidA*sigmoid(-0.5f * sigmoidStr); + public static float sigmoidZeroOne(float f) { + f = clampZeroOne(f); + return sigmoidA*sigmoid(sigmoidStr*(f-0.5f))-sigmoidB; + } + + public static float lerp(float a, float b, float amount) { + return b + (a - b) * clampZeroOne(amount); + } + + +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/core/util/lerp/LerpingFloat.java b/src/main/java/com/thatgravyboat/skyblockhud/core/util/lerp/LerpingFloat.java new file mode 100644 index 0000000..4831956 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/core/util/lerp/LerpingFloat.java @@ -0,0 +1,68 @@ +package com.thatgravyboat.skyblockhud.core.util.lerp; + +public class LerpingFloat { + + private int timeSpent; + private long lastMillis; + private int timeToReachTarget; + + private float targetValue; + private float lerpValue; + + public LerpingFloat(float initialValue, int timeToReachTarget) { + this.targetValue = this.lerpValue = initialValue; + this.timeToReachTarget = timeToReachTarget; + } + + public LerpingFloat(int initialValue) { + this(initialValue, 200); + } + + public void tick() { + int lastTimeSpent = timeSpent; + this.timeSpent += System.currentTimeMillis() - lastMillis; + + float lastDistPercentToTarget = lastTimeSpent/(float)timeToReachTarget; + float distPercentToTarget = timeSpent/(float)timeToReachTarget; + float fac = (1-lastDistPercentToTarget)/lastDistPercentToTarget; + + float startValue = lerpValue - (targetValue - lerpValue)/fac; + + float dist = targetValue - startValue; + if(dist == 0) return; + + float oldLerpValue = lerpValue; + if(distPercentToTarget >= 1) { + lerpValue = targetValue; + } else { + lerpValue = startValue + dist*distPercentToTarget; + } + + if(lerpValue == oldLerpValue) { + timeSpent = lastTimeSpent; + } else { + this.lastMillis = System.currentTimeMillis(); + } + } + + public void resetTimer() { + this.timeSpent = 0; + this.lastMillis = System.currentTimeMillis(); + } + + public void setTarget(float targetValue) { + this.targetValue = targetValue; + } + + public void setValue(float value) { + this.targetValue = this.lerpValue = value; + } + + public float getValue() { + return lerpValue; + } + + public float getTarget() { + return targetValue; + } +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/core/util/lerp/LerpingInteger.java b/src/main/java/com/thatgravyboat/skyblockhud/core/util/lerp/LerpingInteger.java new file mode 100644 index 0000000..48ae5ad --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/core/util/lerp/LerpingInteger.java @@ -0,0 +1,76 @@ +package com.thatgravyboat.skyblockhud.core.util.lerp; + +public class LerpingInteger { + + private int timeSpent; + private long lastMillis; + private int timeToReachTarget; + + private int targetValue; + private int lerpValue; + + public LerpingInteger(int initialValue, int timeToReachTarget) { + this.targetValue = this.lerpValue = initialValue; + this.timeToReachTarget = timeToReachTarget; + } + + public LerpingInteger(int initialValue) { + this(initialValue, 200); + } + + public void tick() { + int lastTimeSpent = timeSpent; + this.timeSpent += System.currentTimeMillis() - lastMillis; + + float lastDistPercentToTarget = lastTimeSpent/(float)timeToReachTarget; + float distPercentToTarget = timeSpent/(float)timeToReachTarget; + float fac = (1-lastDistPercentToTarget)/lastDistPercentToTarget; + + int startValue = lerpValue - (int)((targetValue - lerpValue)/fac); + + int dist = targetValue - startValue; + if(dist == 0) return; + + int oldLerpValue = lerpValue; + if(distPercentToTarget >= 1) { + lerpValue = targetValue; + } else { + lerpValue = startValue + (int)(dist*distPercentToTarget); + } + + if(lerpValue == oldLerpValue) { + timeSpent = lastTimeSpent; + } else { + this.lastMillis = System.currentTimeMillis(); + } + } + + public int getTimeSpent() { + return timeSpent; + } + + public void resetTimer() { + this.timeSpent = 0; + this.lastMillis = System.currentTimeMillis(); + } + + public void setTimeToReachTarget(int timeToReachTarget) { + this.timeToReachTarget = timeToReachTarget; + } + + public void setTarget(int targetValue) { + this.targetValue = targetValue; + } + + public void setValue(int value) { + this.targetValue = this.lerpValue = value; + } + + public int getValue() { + return lerpValue; + } + + public int getTarget() { + return targetValue; + } +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/core/util/render/RenderUtils.java b/src/main/java/com/thatgravyboat/skyblockhud/core/util/render/RenderUtils.java new file mode 100644 index 0000000..95d1b05 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/core/util/render/RenderUtils.java @@ -0,0 +1,165 @@ +package com.thatgravyboat.skyblockhud.core.util.render; + +import com.thatgravyboat.skyblockhud.core.BackgroundBlur; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Gui; +import net.minecraft.client.gui.ScaledResolution; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.OpenGlHelper; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.WorldRenderer; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL14; + +public class RenderUtils { + + public static void drawFloatingRectDark(int x, int y, int width, int height) { + drawFloatingRectDark(x, y, width, height, true); + } + + public static void drawFloatingRectDark(int x, int y, int width, int height, boolean shadow) { + int alpha = 0xf0000000; + + if(OpenGlHelper.isFramebufferEnabled()) { + ScaledResolution scaledResolution = new ScaledResolution(Minecraft.getMinecraft()); + BackgroundBlur.renderBlurredBackground(15, scaledResolution.getScaledWidth(), + scaledResolution.getScaledHeight(), x, y, width, height, true); + } else { + alpha = 0xff000000; + } + + int main = alpha | 0x202026; + int light = 0xff303036; + int dark = 0xff101016; + Gui.drawRect(x, y, x+1, y+height, light); //Left + Gui.drawRect(x+1, y, x+width, y+1, light); //Top + Gui.drawRect(x+width-1, y+1, x+width, y+height, dark); //Right + Gui.drawRect(x+1, y+height-1, x+width-1, y+height, dark); //Bottom + Gui.drawRect(x+1, y+1, x+width-1, y+height-1, main); //Middle + if(shadow) { + Gui.drawRect(x+width, y+2, x+width+2, y+height+2, 0x70000000); //Right shadow + Gui.drawRect(x+2, y+height, x+width, y+height+2, 0x70000000); //Bottom shadow + } + } + + public static void drawFloatingRect(int x, int y, int width, int height) { + drawFloatingRectWithAlpha(x, y, width, height, 0xFF, true); + } + + public static void drawFloatingRectWithAlpha(int x, int y, int width, int height, int alpha, boolean shadow) { + int main = (alpha << 24) | 0xc0c0c0; + int light = (alpha << 24) | 0xf0f0f0; + int dark = (alpha << 24) | 0x909090; + Gui.drawRect(x, y, x+1, y+height, light); //Left + Gui.drawRect(x+1, y, x+width, y+1, light); //Top + Gui.drawRect(x+width-1, y+1, x+width, y+height, dark); //Right + Gui.drawRect(x+1, y+height-1, x+width-1, y+height, dark); //Bottom + Gui.drawRect(x+1, y+1, x+width-1, y+height-1, main); //Middle + if(shadow) { + Gui.drawRect(x+width, y+2, x+width+2, y+height+2, (alpha*3/5) << 24); //Right shadow + Gui.drawRect(x+2, y+height, x+width, y+height+2, (alpha*3/5) << 24); //Bottom shadow + } + } + + public static void drawTexturedModalRect(int x, int y, int textureX, int textureY, int width, int height){ + double f = 0.00390625; + double f1 = 0.00390625; + Tessellator tessellator = Tessellator.getInstance(); + WorldRenderer worldrenderer = tessellator.getWorldRenderer(); + worldrenderer.begin(7, DefaultVertexFormats.POSITION_TEX); + worldrenderer.pos(x + 0.0, y + height, 0.0).tex((textureX + 0.0) * f, (textureY + height) * f1).endVertex(); + worldrenderer.pos(x + width, y + height, 0.0).tex((textureX + width) * f, (textureY + height) * f1).endVertex(); + worldrenderer.pos(x + width, y + 0.0, 0.0).tex((textureX + width) * f, (textureY + 0.0) * f1).endVertex(); + worldrenderer.pos(x + 0.0, y + 0.0, 0.0).tex((textureX + 0.0) * f, (textureY + 0.0) * f1).endVertex(); + tessellator.draw(); + } + + public static void drawTexturedRect(float x, float y, float width, float height) { + drawTexturedRect(x, y, width, height, 0, 1, 0 , 1); + } + + public static void drawTexturedRect(float x, float y, float width, float height, int filter) { + drawTexturedRect(x, y, width, height, 0, 1, 0 , 1, filter); + } + + public static void drawTexturedRect(float x, float y, float width, float height, float uMin, float uMax, float vMin, float vMax) { + drawTexturedRect(x, y, width, height, uMin, uMax, vMin , vMax, GL11.GL_NEAREST); + } + + public static void drawTexturedRect(float x, float y, float width, float height, float uMin, float uMax, float vMin, float vMax, int filter) { + GlStateManager.enableBlend(); + GL14.glBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA); + + drawTexturedRectNoBlend(x, y, width, height, uMin, uMax, vMin, vMax, filter); + + GlStateManager.disableBlend(); + } + + public static void drawTexturedRectNoBlend(float x, float y, float width, float height, float uMin, float uMax, float vMin, float vMax, int filter) { + GlStateManager.enableTexture2D(); + + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, filter); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, filter); + + Tessellator tessellator = Tessellator.getInstance(); + WorldRenderer worldrenderer = tessellator.getWorldRenderer(); + worldrenderer.begin(7, DefaultVertexFormats.POSITION_TEX); + worldrenderer + .pos(x, y+height, 0.0D) + .tex(uMin, vMax).endVertex(); + worldrenderer + .pos(x+width, y+height, 0.0D) + .tex(uMax, vMax).endVertex(); + worldrenderer + .pos(x+width, y, 0.0D) + .tex(uMax, vMin).endVertex(); + worldrenderer + .pos(x, y, 0.0D) + .tex(uMin, vMin).endVertex(); + tessellator.draw(); + + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST); + } + + 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(); + } + + public static void drawInnerBox(int left, int top, int width, int height){ + Gui.drawRect(left, top, left+width, top+height, 0x6008080E); //Middle + Gui.drawRect(left, top, left+1, top+height, 0xff08080E); //Left + Gui.drawRect(left, top, left+width, top+1, 0xff08080E); //Top + Gui.drawRect(left+width-1, top, left+width, top+height, 0xff28282E); //Right + Gui.drawRect(left, top+height-1, left+width, top+height, 0xff28282E); //Bottom + } + +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/core/util/render/TextRenderUtils.java b/src/main/java/com/thatgravyboat/skyblockhud/core/util/render/TextRenderUtils.java new file mode 100644 index 0000000..fce2f82 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/core/util/render/TextRenderUtils.java @@ -0,0 +1,215 @@ +package com.thatgravyboat.skyblockhud.core.util.render; + +import com.thatgravyboat.skyblockhud.core.util.StringUtils; +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.item.ItemStack; +import net.minecraft.util.EnumChatFormatting; +import org.lwjgl.opengl.GL11; + +import java.util.ArrayList; +import java.util.List; + +public class TextRenderUtils { + + public static int getCharVertLen(char c) { + if("acegmnopqrsuvwxyz".indexOf(c) >= 0) { + return 5; + } else { + return 7; + } + } + + public static float getVerticalHeight(String str) { + str = StringUtils.cleanColour(str); + float height = 0; + for(int i=0; i<str.length(); i++) { + char c = str.charAt(i); + int charHeight = getCharVertLen(c); + height += charHeight + 1.5f; + } + return height; + } + + public static void drawStringVertical(String str, FontRenderer fr, float x, float y, boolean shadow, int colour) { + String format = FontRenderer.getFormatFromString(str); + str = StringUtils.cleanColour(str); + for(int i=0; i<str.length(); i++) { + char c = str.charAt(i); + + int charHeight = getCharVertLen(c); + int charWidth = fr.getCharWidth(c); + fr.drawString(format+c, x+(5-charWidth)/2f, y-7+charHeight, colour, shadow); + + y += charHeight + 1.5f; + } + } + + public static void drawStringScaledMaxWidth(String str, FontRenderer fr, float x, float y, boolean shadow, int len, int colour) { + int strLen = fr.getStringWidth(str); + float factor = len/(float)strLen; + factor = Math.min(1, factor); + + drawStringScaled(str, fr, x, y, shadow, colour, factor); + } + + public static void drawStringCentered(String str, FontRenderer fr, float x, float y, boolean shadow, int colour) { + int strLen = fr.getStringWidth(str); + + float x2 = x - strLen/2f; + float y2 = y - fr.FONT_HEIGHT/2f; + + GL11.glTranslatef(x2, y2, 0); + fr.drawString(str, 0, 0, colour, shadow); + GL11.glTranslatef(-x2, -y2, 0); + } + + public static void drawStringScaled(String str, FontRenderer fr, float x, float y, boolean shadow, int colour, float factor) { + GlStateManager.scale(factor, factor, 1); + fr.drawString(str, x/factor, y/factor, colour, shadow); + GlStateManager.scale(1/factor, 1/factor, 1); + } + + public static void drawStringCenteredScaledMaxWidth(String str, FontRenderer fr, float x, float y, boolean shadow, int len, int colour) { + int strLen = fr.getStringWidth(str); + float factor = len/(float)strLen; + factor = Math.min(1, factor); + int newLen = Math.min(strLen, len); + + float fontHeight = 8*factor; + + drawStringScaled(str, fr, x-newLen/2, y-fontHeight/2, shadow, colour, factor); + } + + public static void renderToolTip(ItemStack stack, int mouseX, int mouseY, int screenWidth, int screenHeight, FontRenderer fontStd) { + List<String> list = stack.getTooltip(Minecraft.getMinecraft().thePlayer, + Minecraft.getMinecraft().gameSettings.advancedItemTooltips); + + for (int i = 0; i < list.size(); ++i) { + if (i == 0) { + list.set(i, stack.getRarity().rarityColor + list.get(i)); + } else { + list.set(i, EnumChatFormatting.GRAY + list.get(i)); + } + } + + FontRenderer font = stack.getItem().getFontRenderer(stack); + drawHoveringText(list, mouseX, mouseY, screenWidth, screenHeight, -1, font == null ? fontStd : font); + } + + 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<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 - 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; + RenderUtils.drawGradientRect(zLevel, tooltipX - 3, tooltipY - 4, tooltipX + tooltipTextWidth + 3, tooltipY - 3, backgroundColor, backgroundColor); + RenderUtils.drawGradientRect(zLevel, tooltipX - 3, tooltipY + tooltipHeight + 3, tooltipX + tooltipTextWidth + 3, tooltipY + tooltipHeight + 4, backgroundColor, backgroundColor); + RenderUtils.drawGradientRect(zLevel, tooltipX - 3, tooltipY - 3, tooltipX + tooltipTextWidth + 3, tooltipY + tooltipHeight + 3, backgroundColor, backgroundColor); + RenderUtils.drawGradientRect(zLevel, tooltipX - 4, tooltipY - 3, tooltipX - 3, tooltipY + tooltipHeight + 3, backgroundColor, backgroundColor); + RenderUtils.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; + RenderUtils.drawGradientRect(zLevel, tooltipX - 3, tooltipY - 3 + 1, tooltipX - 3 + 1, tooltipY + tooltipHeight + 3 - 1, borderColorStart, borderColorEnd); + RenderUtils.drawGradientRect(zLevel, tooltipX + tooltipTextWidth + 2, tooltipY - 3 + 1, tooltipX + tooltipTextWidth + 3, tooltipY + tooltipHeight + 3 - 1, borderColorStart, borderColorEnd); + RenderUtils.drawGradientRect(zLevel, tooltipX - 3, tooltipY - 3, tooltipX + tooltipTextWidth + 3, tooltipY - 3 + 1, borderColorStart, borderColorStart); + RenderUtils.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(); + } + GlStateManager.disableLighting(); + } + +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/dungeons/Classes.java b/src/main/java/com/thatgravyboat/skyblockhud/dungeons/Classes.java new file mode 100644 index 0000000..14634d8 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/dungeons/Classes.java @@ -0,0 +1,50 @@ +package com.thatgravyboat.skyblockhud.dungeons; + +public enum Classes { + + H("Healer", "H", 154), + M("Mage", "M", 90), + B("Berserk", "B", 122), + A("Archer", "A", 58), + T("Tank", "T", 186); + + private final String displayName; + private final String classId; + private final int textureY; + + Classes(String name, String id, int textureY) + { + this.displayName = name; + this.classId = id; + this.textureY = textureY; + } + + public String getDisplayName() { + return this.displayName; + } + + public String getClassId() { + return this.classId; + } + + public int getTextureY() { + return this.textureY; + } + + public static Classes findClass(String input){ + if (input.length() == 1){ + try{ + return Classes.valueOf(input.toUpperCase()); + } catch (IllegalArgumentException ignored){} + } else if (input.length() == 3){ + try{ + return Classes.valueOf(input.replace("[", "").replace("]", "").toUpperCase()); + } catch (IllegalArgumentException ignored){} + } else { + for(Classes clazz : Classes.values()){ + if (clazz.displayName.equalsIgnoreCase(input)) return clazz; + } + } + return B; + } +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/dungeons/DungeonHandler.java b/src/main/java/com/thatgravyboat/skyblockhud/dungeons/DungeonHandler.java new file mode 100644 index 0000000..4524c0f --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/dungeons/DungeonHandler.java @@ -0,0 +1,167 @@ +package com.thatgravyboat.skyblockhud.dungeons; + +import com.thatgravyboat.skyblockhud.Utils; +import com.thatgravyboat.skyblockhud.api.events.SidebarLineUpdateEvent; +import com.thatgravyboat.skyblockhud.api.events.SidebarPostEvent; +import com.thatgravyboat.skyblockhud.location.LocationHandler; +import com.thatgravyboat.skyblockhud.location.Locations; +import net.minecraft.client.Minecraft; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; + +import java.util.HashMap; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class DungeonHandler { + private static final HashMap<String, DungeonPlayer> dungeonPlayersMap = new HashMap<>(); + private static int dungeonTime = 0; + private static int dungeonCleared = 0; + private static boolean bloodKey = false; + private static int witherKeys = 0; + private static int maxSecrets = 0; + private static int secrets = 0; + private static int totalSecrets = 0; + private static int deaths = 0; + private static int crypts = 0; + + private static final Pattern DungeonPlayerRegex = Pattern.compile("^\\[([HMBAT])] ([\\w]+) ([0-9]+|DEAD)$"); + + @SubscribeEvent + public void onSidebarLineUpdate(SidebarLineUpdateEvent event){ + if (LocationHandler.getCurrentLocation().equals(Locations.CATACOMBS)) { + DungeonHandler.checkForDungeonTime(event.formattedLine); + DungeonHandler.checkForDungeonCleared(event.formattedLine); + DungeonHandler.checkForDungeonKeys(event.formattedLine, event.rawLine); + DungeonHandler.checkForDungeonPlayers(event.formattedLine, Minecraft.getMinecraft()); + } + } + + @SubscribeEvent + public void onSidebarPost(SidebarPostEvent event){ + if (!LocationHandler.getCurrentLocation().equals(Locations.CATACOMBS)) { + DungeonHandler.clearDungeonStats(); + } + } + + public static void checkForDungeonPlayers(String scoreLine, Minecraft mc){ + Matcher dungeonMatcher = DungeonPlayerRegex.matcher(scoreLine); + if (dungeonMatcher.matches() && DungeonHandler.dungeonTime > 0){ + Classes playerClass = Classes.valueOf(dungeonMatcher.group(1)); + String displayName = dungeonMatcher.group(2); + String health = dungeonMatcher.group(3); + if (!mc.thePlayer.getName().toLowerCase().startsWith(displayName.toLowerCase().trim())){ + int healthNum = 0; + if (!health.equalsIgnoreCase("dead")){ + try { + healthNum = Integer.parseInt(health); + } catch (NumberFormatException ignored){} + } + DungeonPlayer player = new DungeonPlayer(playerClass, displayName, healthNum, health.equalsIgnoreCase("dead")); + dungeonPlayersMap.put(displayName.toLowerCase(),player); + } + } + } + + public static void checkForDungeonTime(String scoreLine){ + if (scoreLine.toLowerCase().trim().contains("time elapsed:")){ + String timeLine = scoreLine.toLowerCase().trim().replace("time elapsed:", ""); + String[] times = timeLine.split("m "); + int time = 0; + try { + time += Integer.parseInt(times[0].replace(" ", "").replace("m", "")) * 60; + time += Integer.parseInt(times[1].replace(" ", "").replace("s", "")); + } catch (NumberFormatException ignored){} + dungeonTime = time; + } + } + + public static void checkForDungeonCleared(String scoreline){ + if (scoreline.toLowerCase().trim().contains("dungeon cleared:")){ + String dungeonClearedText = scoreline.toLowerCase().trim().replace("dungeon cleared:", "").replace(" ", "").replace("%", ""); + try{ + dungeonCleared = Integer.parseInt(dungeonClearedText); + }catch (NumberFormatException ignored){ } + } + } + + public static void checkForDungeonKeys(String scoreline, String rawString){ + if (scoreline.toLowerCase().trim().contains("keys:")){ + String dungeonClearedText = scoreline.toLowerCase().trim().replace("keys:", "").replace(" ", "").replace("x", ""); + bloodKey = rawString.contains("\u2713"); + try{ + witherKeys = Integer.parseInt(dungeonClearedText); + }catch (NumberFormatException ignored){} + } + } + + public static void parseSecrets(String statusBar){ + boolean hasSecrets = false; + String[] parts = statusBar.split(" {4,}"); + for (String part : parts) { + if (part.toLowerCase().contains("secrets") && !statusBar.toLowerCase().contains("no secrets")){ + hasSecrets = true; + try { + String secret = Utils.removeColor(part.replace("Secrets", "")).replace(" ", ""); + maxSecrets = Integer.parseInt(secret.split("/")[1]); + secrets = Integer.parseInt(secret.split("/")[0]); + }catch (NumberFormatException ignored){ } + } + } + if (!hasSecrets){ + maxSecrets = 0; + secrets = 0; + } + } + + public static void parseTotalSecrets(String playerName){ + if (playerName.toLowerCase().contains("secrets found:")){ + String totalSecret = Utils.removeColor(playerName.toLowerCase().replace("secrets found:", "")).replace(" ", ""); + try { + totalSecrets = Integer.parseInt(totalSecret); + }catch (NumberFormatException ignored){} + } + } + + public static void parseDeaths(String playerName){ + if (playerName.toLowerCase().contains("deaths:")){ + String death = Utils.removeColor(playerName.toLowerCase().replace("deaths:", "")).replace("(", "").replace(")", "").replace(" ", ""); + try { + deaths = Integer.parseInt(death); + }catch (NumberFormatException ignored){} + } + } + + public static void parseCrypts(String playerName){ + if (playerName.toLowerCase().contains("crypts:")){ + String crypt = Utils.removeColor(playerName.toLowerCase().replace("crypts:", "")).replace(" ", ""); + try { + crypts = Integer.parseInt(crypt); + }catch (NumberFormatException ignored){} + } + } + + public static void clearDungeonStats(){ + dungeonPlayersMap.clear(); + dungeonTime = 0; + dungeonCleared = 0; + bloodKey = false; + witherKeys = 0; + maxSecrets = 0; + secrets = 0; + totalSecrets = 0; + deaths = 0; + crypts = 0; + } + + public static HashMap<String,DungeonPlayer> getDungeonPlayers(){ return dungeonPlayersMap; } + + public static int getDungeonTime() { return dungeonTime; } + public static int getDungeonCleared() { return dungeonCleared; } + public static int getWitherKeys() { return witherKeys; } + public static boolean hasBloodkey() { return bloodKey; } + public static int getMaxSecrets() { return maxSecrets; } + public static int getSecrets() { return secrets; } + public static int getDeaths() { return deaths; } + public static int getTotalSecrets() { return totalSecrets; } + public static int getCrypts() { return crypts; } +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/dungeons/DungeonPlayer.java b/src/main/java/com/thatgravyboat/skyblockhud/dungeons/DungeonPlayer.java new file mode 100644 index 0000000..e34424d --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/dungeons/DungeonPlayer.java @@ -0,0 +1,31 @@ +package com.thatgravyboat.skyblockhud.dungeons; + +public class DungeonPlayer { + private final Classes dungeonClass; + private final String name; + private final int health; + private final boolean dead; + + public DungeonPlayer(Classes playersClass, String playersName, int playersHealth, boolean isDead) { + this.dungeonClass = playersClass; + this.name = playersName; + this.health = isDead ? 0 : playersHealth; + this.dead = isDead; + } + + public Classes getDungeonClass() { + return this.dungeonClass; + } + + public String getName() { + return this.name; + } + + public int getHealth() { + return this.dead ? 0 : this.health; + } + + public boolean isDead() { + return this.dead; + } +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/handlers/BossbarHandler.java b/src/main/java/com/thatgravyboat/skyblockhud/handlers/BossbarHandler.java new file mode 100644 index 0000000..38fa874 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/handlers/BossbarHandler.java @@ -0,0 +1,37 @@ +package com.thatgravyboat.skyblockhud.handlers; + +import com.thatgravyboat.skyblockhud.SkyblockHud; +import com.thatgravyboat.skyblockhud.Utils; +import com.thatgravyboat.skyblockhud.location.DwarvenMineHandler; +import com.thatgravyboat.skyblockhud.location.LocationHandler; +import com.thatgravyboat.skyblockhud.location.Locations; +import net.minecraft.entity.boss.BossStatus; +import net.minecraftforge.client.event.RenderGameOverlayEvent; +import net.minecraftforge.fml.common.eventhandler.EventPriority; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; + +public class BossbarHandler { + + public static boolean bossBarRendered = true; + + @SubscribeEvent(priority = EventPriority.LOWEST) + public void onBossbarRender(RenderGameOverlayEvent.Pre event) { + if (event.type == RenderGameOverlayEvent.ElementType.BOSSHEALTH && BossStatus.bossName != null) { + bossBarRendered = !event.isCanceled(); + if (!SkyblockHud.config.main.bossShiftHud){ + bossBarRendered = false; + } + String bossName = Utils.removeColor(BossStatus.bossName); + if (SkyblockHud.config.renderer.hideBossBar && DwarvenMineHandler.currentEvent == DwarvenMineHandler.Event.NONE && !LocationHandler.getCurrentLocation().equals(Locations.CATACOMBS)){ + if (bossName.equalsIgnoreCase("wither")){ + event.setCanceled(true); + bossBarRendered = false; + } + if (bossName.toLowerCase().startsWith("objective:")){ + event.setCanceled(true); + bossBarRendered = false; + } + } + } + } +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/handlers/CurrencyHandler.java b/src/main/java/com/thatgravyboat/skyblockhud/handlers/CurrencyHandler.java new file mode 100644 index 0000000..12b04d8 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/handlers/CurrencyHandler.java @@ -0,0 +1,81 @@ +package com.thatgravyboat.skyblockhud.handlers; + +import com.thatgravyboat.skyblockhud.Utils; +import com.thatgravyboat.skyblockhud.api.events.SidebarLineUpdateEvent; +import com.thatgravyboat.skyblockhud.api.events.SidebarPostEvent; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; + +import java.math.RoundingMode; +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; +import java.util.Arrays; +import java.util.Locale; +import java.util.regex.Pattern; + +public class CurrencyHandler { + + private static int bits = 0; + private static double coins = 0; + + public static void setBits(int amount){ bits = amount; } + public static void setCoins(double amount){ coins = amount; } + public static int getBits(){ return bits; } + public static double getCoins(){ return coins; } + + @SubscribeEvent + public void onSidebarLineUpdate(SidebarLineUpdateEvent event){ + if (Utils.removeColor(event.formattedLine.toLowerCase().trim()).contains("purse:") || Utils.removeColor(event.formattedLine.toLowerCase().trim()).contains("piggy:")) { + CurrencyHandler.checkCoins(event.formattedLine); + } + if (Utils.removeColor(event.formattedLine.toLowerCase().trim()).contains("bits:") && !event.formattedLine.toLowerCase().contains("(")) { + CurrencyHandler.checkBits(event.formattedLine); + } + } + + @SubscribeEvent + public void onSidebarPost(SidebarPostEvent event){ + if (!Arrays.toString(event.arrayScores).toLowerCase().contains("bits:")){ + CurrencyHandler.setBits(0); + } + } + + public static String getCoinsFormatted(){ + + DecimalFormat formatter = new DecimalFormat("#,###.0", DecimalFormatSymbols.getInstance(Locale.CANADA)); + String output = formatter.format(coins); + if (output.equals(".0")) output = "0.0"; + else if (output.equals(",0")) output = "0,0"; + return output; + } + + public static String getBitsFormatted(){ + DecimalFormat formatter = new DecimalFormat("#.#", DecimalFormatSymbols.getInstance(Locale.CANADA)); + formatter.setRoundingMode(RoundingMode.FLOOR); + return bits > 999 ? formatter.format((double)bits / 1000)+ "k" : String.valueOf(bits); + } + + public static void checkCoins(String formatedScoreboardLine){ + String purse = Utils.removeWhiteSpaceAndRemoveWord( + Utils.removeColor(formatedScoreboardLine.toLowerCase().trim()), + Utils.removeColor(formatedScoreboardLine.toLowerCase().trim()).contains("purse:") ? "purse:" : "piggy:" + ).replace(",", ""); + if (!purse.contains("(") && !purse.contains("+")) { + try { + double coins = Double.parseDouble(Pattern.compile("[^0-9.]").matcher(purse).replaceAll("")); + CurrencyHandler.setCoins(coins); + } catch (IllegalArgumentException ex) { + System.out.println("Failed to parse purse, please report to ThatGravyBoat. Purse Text: " + purse); + } + } + } + + public static void checkBits(String formatedScoreboardLine){ + String bits = Utils.removeWhiteSpaceAndRemoveWord(Utils.removeColor(formatedScoreboardLine.toLowerCase().trim()), "bits:").replace(",", ""); + try { + int bit = Integer.parseInt(Pattern.compile("[^0-9]").matcher(bits).replaceAll("")); + CurrencyHandler.setBits(bit); + } catch (IllegalArgumentException ex) { + System.out.println("Failed to parse bits, please report to ThatGravyBoat. Bits Text: " + bits); + } + } +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/handlers/HeldItemHandler.java b/src/main/java/com/thatgravyboat/skyblockhud/handlers/HeldItemHandler.java new file mode 100644 index 0000000..1a401f2 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/handlers/HeldItemHandler.java @@ -0,0 +1,58 @@ +package com.thatgravyboat.skyblockhud.handlers; + +import com.thatgravyboat.skyblockhud.Utils; +import com.thatgravyboat.skyblockhud.overlay.GenericOverlays; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Gui; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; +import net.minecraftforge.client.event.RenderGameOverlayEvent; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; + +public class HeldItemHandler extends Gui { + + public void drawFuelBar(Minecraft mc, int current, int max){ + GenericOverlays.drawSmallBar(mc, 100,100,(double)current/(double)max,1.0d,0xff00ff,0xffff00, 0); + drawString(mc.fontRendererObj, "Fuel - " + Math.round(((double)current/(double)max)*100) + "%", 100, 100, 0xffffff); + } + + public boolean isDrill(ItemStack stack){ + if (stack == null) return false; + if (!stack.getTagCompound().hasKey("ExtraAttributes")) return false; + return stack.getTagCompound().getCompoundTag("ExtraAttributes").hasKey("drill_fuel"); + } + + public String getDrillFuel(ItemStack stack){ + NBTTagCompound display = stack.getTagCompound().getCompoundTag("display"); + NBTTagList lore = display.getTagList("Lore", 8); + for (int i = lore.tagCount() - 1; i >= 0; i--) { + String line = Utils.removeColor(lore.getStringTagAt(i)); + if (line.trim().startsWith("Fuel:")){ + return line; + } + } + return ""; + } + + @SubscribeEvent + public void drawOverlay(RenderGameOverlayEvent.Post event){ + /* + if (Utils.overlayShouldRender(event.type, SkyblockHud.hasSkyblockScoreboard())){ + Minecraft mc = Minecraft.getMinecraft(); + ItemStack stack = mc.thePlayer.getHeldItem(); + if (isDrill(stack)){ + try { + String drill = getDrillFuel(stack).replace("Fuel:", "").trim(); + String[] fuel = drill.split("/"); + if (fuel.length == 2) { + int current = Integer.parseInt(fuel[0].replace(",", "")); + int max = Integer.parseInt(fuel[1].replace("k", "")) * 1000; + drawFuelBar(mc, current, max); + } + }catch (Exception ignored){} + } + } + */ + } +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/handlers/MapHandler.java b/src/main/java/com/thatgravyboat/skyblockhud/handlers/MapHandler.java new file mode 100644 index 0000000..d2946ef --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/handlers/MapHandler.java @@ -0,0 +1,219 @@ +package com.thatgravyboat.skyblockhud.handlers; + +import com.thatgravyboat.skyblockhud.SkyblockHud; +import com.thatgravyboat.skyblockhud.Utils; +import com.thatgravyboat.skyblockhud.config.KeyBindings; +import com.thatgravyboat.skyblockhud.config.SBHConfig; +import com.thatgravyboat.skyblockhud.core.config.Position; +import com.thatgravyboat.skyblockhud.handlers.mapicons.DwarvenIcons; +import com.thatgravyboat.skyblockhud.handlers.mapicons.HubIcons; +import com.thatgravyboat.skyblockhud.location.LocationHandler; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Gui; +import net.minecraft.client.gui.GuiScreen; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.settings.GameSettings; +import net.minecraft.util.BlockPos; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.client.event.RenderGameOverlayEvent; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.common.gameevent.TickEvent; +import org.lwjgl.opengl.GL11; + +import javax.vecmath.Vector2f; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import static com.thatgravyboat.skyblockhud.GuiTextures.mapOverlay; + +public class MapHandler { + + public enum MapIconTypes { + SHOPS, + MISC, + NPC, + INFO, + QUEST + } + + public static class MapIcon { + public Vector2f position; + public ResourceLocation icon; + public String tooltip; + public String command; + public MapIconTypes type; + + public MapIcon(Vector2f pos, ResourceLocation icon, String tooltip, MapIconTypes type){ + this(pos,icon,tooltip,type,""); + } + + public MapIcon(Vector2f pos, ResourceLocation icon, String tooltip, MapIconTypes type, String command){ + this.position = pos; + this.icon = icon; + this.tooltip = tooltip; + this.type = type; + this.command = command; + } + + public boolean canRender(){ + SBHConfig.Map mapConfig = SkyblockHud.config.map; + if (mapConfig.showInfoIcons && type.equals(MapIconTypes.INFO)) return true; + else if (mapConfig.showMiscIcons && type.equals(MapIconTypes.MISC)) return true; + else if (mapConfig.showNpcIcons && type.equals(MapIconTypes.NPC)) return true; + else if (mapConfig.showQuestIcons && type.equals(MapIconTypes.QUEST)) return true; + else return mapConfig.showShopIcons && type.equals(MapIconTypes.SHOPS); + } + } + + public enum Maps { + HUB(0.5f,494,444,294,218, 294,224, new ResourceLocation("skyblockhud", "maps/hub.png"), HubIcons.hubIcons), + MUSHROOM(1.0f,318,316,-84,605, -84,612, new ResourceLocation("skyblockhud", "maps/mushroom.png"), Collections.emptyList()), + SPIDERS(1.0f,270,238,400,362, 400,364, new ResourceLocation("skyblockhud", "maps/spidersden.png"), Collections.emptyList()), + NETHER(0.5f,257,371,436,732, 433,736, new ResourceLocation("skyblockhud", "maps/fort.png"), Collections.emptyList()), + BARN(1.5f,135,130,-82,320, -81,318, new ResourceLocation("skyblockhud", "maps/barn.png"), Collections.emptyList()), + DWARVEN(0.5f, 409, 461, 206, 160, 202, 166, new ResourceLocation("skyblockhud", "maps/dwarven.png"), DwarvenIcons.dwarvenIcons), + PARK(1.0f,211, 230, 480, 133, 478,134, new ResourceLocation("skyblockhud", "maps/park.png"), Collections.emptyList()); + + public float scaleFactor; + public int width; + public int height; + public int xMiniOffset; + public int yMiniOffset; + public int xOffset; + public int yOffset; + public ResourceLocation mapTexture; + public List<MapIcon> icons; + + + Maps(float scaleFactor, int width, int height, int xMiniOffset, int yMiniOffset, int xOffset, int yOffset, ResourceLocation mapTexture, List<MapIcon> icons){ + this.scaleFactor = scaleFactor; + this.width = width; + this.height = height; + this.xMiniOffset = xMiniOffset; + this.yMiniOffset = yMiniOffset; + this.xOffset = xOffset; + this.yOffset = yOffset; + this.mapTexture = mapTexture; + this.icons = icons; + } + } + + @SubscribeEvent + public void renderOverlay(RenderGameOverlayEvent.Post event) { + if (Utils.overlayShouldRender(event.type, SkyblockHud.hasSkyblockScoreboard(), SkyblockHud.config.map.showMiniMap)) { + Minecraft mc = Minecraft.getMinecraft(); + if (mc.currentScreen instanceof MapScreen) return; + if (LocationHandler.getCurrentLocation().getCategory().getMap() == null) return; + if (mc.thePlayer != null){ + MapHandler.Maps map = LocationHandler.getCurrentLocation().getCategory().getMap(); + mc.renderEngine.bindTexture(mapOverlay); + GlStateManager.color(1.0f,1.0f, 1.0f,1.0f); + Position pos = SkyblockHud.config.map.miniMapPosition; + Gui.drawModalRectWithCustomSizedTexture(pos.getAbsX(event.resolution, 72),pos.getAbsY(event.resolution, 72),72,0,72,72,256,256); + mc.renderEngine.bindTexture(map.mapTexture); + + int x = mc.thePlayer.getPosition().getX() + map.xMiniOffset; + int z = mc.thePlayer.getPosition().getZ() + map.yMiniOffset; + float u = (x / (map.width / 256f)) - 33f; + float v = (z / (map.height / 256f)) - 28f; + + GL11.glTexParameteri(GL11.GL_TEXTURE_2D,GL11.GL_TEXTURE_WRAP_S, GL11.GL_CLAMP); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D,GL11.GL_TEXTURE_WRAP_T, GL11.GL_CLAMP); + + Gui.drawModalRectWithCustomSizedTexture(pos.getAbsX(event.resolution, 72) + 4, + pos.getAbsY(event.resolution, 72) + 2, + u, + v, + 64,64, + 256,256); + + if (SkyblockHud.config.map.showPlayerLocation) { + mc.fontRendererObj.drawString("\u2022", pos.getAbsX(event.resolution, 72) + 36,pos.getAbsY(event.resolution, 72) + 34, 0xff0000, false); + } + + GlStateManager.color(1.0f,1.0f, 1.0f,1.0f); + mc.renderEngine.bindTexture(mapOverlay); + Gui.drawModalRectWithCustomSizedTexture(pos.getAbsX(event.resolution, 72),pos.getAbsY(event.resolution, 72),0,0,72,72,256,256); + String keyCode = GameSettings.getKeyDisplayString(KeyBindings.map.getKeyCode()); + Utils.drawStringCenteredScaled(keyCode, mc.fontRendererObj, pos.getAbsX(event.resolution, 64) + 58,pos.getAbsY(event.resolution, 72) + 66, false, 6,0xFFFFFF); + BlockPos playerPos = mc.thePlayer.getPosition(); + String position = String.format("%d/%d/%d", playerPos.getX(), playerPos.getY(), playerPos.getZ()); + Utils.drawStringCenteredScaled(position, mc.fontRendererObj, pos.getAbsX(event.resolution, 64) + 30,pos.getAbsY(event.resolution, 72) + 66, false, 36,0xFFFFFF); + GlStateManager.color(1.0f,1.0f, 1.0f,1.0f); + } + } + } + + @SubscribeEvent + public void clientTick(TickEvent.ClientTickEvent event){ + if (KeyBindings.map.isPressed() && LocationHandler.getCurrentLocation().getCategory().getMap() != null && SkyblockHud.hasSkyblockScoreboard()) + SkyblockHud.screenToOpen = new MapScreen(); + } + + + public static class MapScreen extends GuiScreen { + + public MapHandler.Maps map = LocationHandler.getCurrentLocation().getCategory().getMap(); + + @Override + public void drawScreen(int mouseX, int mouseY, float partialTicks) { + GlStateManager.color(1.0f, 1.0f, 1.0f,1.0f); + this.drawWorldBackground(0); + this.mc.renderEngine.bindTexture(map.mapTexture); + float mapX = (width / 2f)-((map.width / 2f) * map.scaleFactor); + float mapY = (height / 2f)-((map.height / 2f) * map.scaleFactor); + Gui.drawModalRectWithCustomSizedTexture((int)mapX, (int)mapY, 0,0,(int)(map.width * map.scaleFactor),(int)(map.height * map.scaleFactor), (int)(map.width * map.scaleFactor), (int)(map.height * map.scaleFactor)); + drawIcons((int)mapX, (int)mapY); + if (this.mc.thePlayer != null && SkyblockHud.config.map.showPlayerLocation){ + int x = this.mc.thePlayer.getPosition().getX() + map.xOffset; + int z = this.mc.thePlayer.getPosition().getZ() + map.yOffset; + fontRendererObj.drawString("\u2022", (int)(x * map.scaleFactor + mapX), (int)(z * map.scaleFactor + mapY), 0xff0000); + } + GlStateManager.color(1.0f, 1.0f, 1.0f, 1.0f); + onTooltip(mouseX, mouseY, (int)mapX, (int)mapY); + } + + public void drawIcons(int startX, int startY){ + if (map.icons == null) return; + for (MapIcon icon : map.icons) { + if (!icon.canRender()) continue; + GlStateManager.enableBlend(); + GlStateManager.color(1.0f, 1.0f, 1.0f, 1.0f); + this.mc.renderEngine.bindTexture(icon.icon); + float x = ((icon.position.x + map.xOffset) * map.scaleFactor) + startX - 4; + float y = ((icon.position.y + map.yOffset) * map.scaleFactor) + startY - 4; + Gui.drawModalRectWithCustomSizedTexture((int)x, (int)y, 0,0,8,8, 8, 8); + GlStateManager.color(1.0f,1.0f,1.0f,1.0f); + } + } + + public void onTooltip(int mouseX, int mouseY, int startX, int startY){ + if (map.icons == null) return; + for (MapIcon icon : map.icons) { + if (!icon.canRender()) continue; + if (Utils.inRangeInclusive(mouseX, (int)((icon.position.x + map.xOffset) * map.scaleFactor) + startX - 4, (int)((icon.position.x + map.xOffset) * map.scaleFactor) + startX + 4) && + Utils.inRangeInclusive(mouseY, (int)((icon.position.y + map.yOffset) * map.scaleFactor) + startY - 4, (int)((icon.position.y + map.yOffset) * map.scaleFactor) + startY + 4)){ + drawHoveringText(Arrays.asList(icon.tooltip.split("\n")), mouseX, mouseY); + break; + } + } + } + + @Override + protected void mouseClicked(int mouseX, int mouseY, int mouseButton) { + int mapX = (int)((width / 2f)-((map.width / 2f) * map.scaleFactor)); + int mapY = (int)((height / 2f)-((map.height / 2f) * map.scaleFactor)); + for (MapIcon icon : map.icons) { + if (!icon.canRender()) continue; + if (Utils.inRangeInclusive(mouseX, (int)((icon.position.x + map.xOffset) * map.scaleFactor) + mapX - 4, (int)((icon.position.x + map.xOffset) * map.scaleFactor) + mapX + 4) && + Utils.inRangeInclusive(mouseY, (int)((icon.position.y + map.yOffset) * map.scaleFactor) + mapY - 4, (int)((icon.position.y + map.yOffset) * map.scaleFactor) + mapY + 4)){ + if (!icon.command.isEmpty()){ + this.mc.thePlayer.sendChatMessage("/"+icon.command); + } + break; + } + } + } + } +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/handlers/SlayerHandler.java b/src/main/java/com/thatgravyboat/skyblockhud/handlers/SlayerHandler.java new file mode 100644 index 0000000..36833cc --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/handlers/SlayerHandler.java @@ -0,0 +1,121 @@ +package com.thatgravyboat.skyblockhud.handlers; + +import com.thatgravyboat.skyblockhud.Utils; +import com.thatgravyboat.skyblockhud.api.events.SidebarLineUpdateEvent; +import com.thatgravyboat.skyblockhud.api.events.SidebarPostEvent; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; + +import java.util.Arrays; +import java.util.Locale; + +public class SlayerHandler { + + public enum slayerTypes { + + ZOMBIE(34, "Revenant Horror"), + WOLF(42, "Sven Packmaster"), + SPIDER(50, "Tarantula Broodfather"), + VOIDGLOOMSERAPH(50, "Voidgloom Seraph"), + NONE(0,""); + + private final String displayName; + private final int x; + + slayerTypes(int x, String displayName){ + this.displayName = displayName; + this.x = x; + } + + public String getDisplayName() { return displayName; } + + public int getX() { return x; } + } + + public static slayerTypes currentSlayer = slayerTypes.NONE; + public static int slayerTier = 0; + public static boolean isDoingSlayer = false; + public static int progress = 0; + public static int maxKills = 0; + public static boolean bossSlain = false; + public static boolean isKillingBoss = false; + public static void clearSlayer(){ + currentSlayer = slayerTypes.NONE; + isDoingSlayer = false; + progress = 0; + maxKills = 0; + bossSlain = false; + isKillingBoss = false; + } + + @SubscribeEvent + public void onSidebarPost(SidebarPostEvent event){ + String arrayString = Arrays.toString(event.arrayScores); + isDoingSlayer = Arrays.toString(event.arrayScores).contains("Slayer Quest"); + if (isDoingSlayer && (currentSlayer.equals(slayerTypes.NONE) || !arrayString.replace(" ", "").contains(currentSlayer.getDisplayName().replace(" ", "")+Utils.intToRomanNumeral(slayerTier)))) { + for (int i = 0; i < event.scores.size(); i++) { + String line = event.scores.get(i); + if (line.contains("Slayer Quest") && event.scores.size() > 3){ + String slayer = event.scores.get(i - 1).toLowerCase(); + SlayerHandler.slayerTypes selectedSlayer = SlayerHandler.slayerTypes.NONE; + for (slayerTypes types : slayerTypes.values()){ + if (slayer.contains(types.displayName.toLowerCase(Locale.ENGLISH))) { + selectedSlayer = types; + break; + } + } + SlayerHandler.currentSlayer = selectedSlayer; + SlayerHandler.slayerTier = Utils.whatRomanNumeral(slayer.replace(selectedSlayer.getDisplayName().toLowerCase(), "").replace(" ", "")); + break; + } + } + } + + if (!isDoingSlayer) { + clearSlayer(); + } + } + + @SubscribeEvent + public void onSidebarLineUpdate(SidebarLineUpdateEvent event){ + if (isDoingSlayer){ + String line = event.formattedLine.toLowerCase(); + if (line.contains("/") && (line.contains("kills") || (line.contains("xp")))){ + SlayerHandler.bossSlain = false; + SlayerHandler.isKillingBoss = false; + String[] killsText = line.replace(" ", "").replace("kills", "").split("/"); + if (line.contains("xp")) + killsText = line.replace(" ", "") + .replace("(", "") + .replace(")", "") + .replace("combatxp", "") + .split("/"); + try { + progress = Integer.parseInt(killsText[0]); + } catch (Exception ignored){} + try { + maxKills = Integer.parseInt(killsText[1]); + } catch (Exception ignored){} + }else if(line.contains("slay the boss")) { + SlayerHandler.bossSlain = false; + SlayerHandler.isKillingBoss = true; + SlayerHandler.maxKills = 0; + SlayerHandler.progress = 0; + }else if (line.contains("boss slain")){ + SlayerHandler.isKillingBoss = false; + SlayerHandler.maxKills = 0; + SlayerHandler.progress = 0; + SlayerHandler.bossSlain = true; + } + if (maxKills == 0 && progress == 0){ + SlayerHandler.maxKills = 0; + SlayerHandler.progress = 0; + } + } + } + + + + + + +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/handlers/TimeHandler.java b/src/main/java/com/thatgravyboat/skyblockhud/handlers/TimeHandler.java new file mode 100644 index 0000000..06edf6b --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/handlers/TimeHandler.java @@ -0,0 +1,29 @@ +package com.thatgravyboat.skyblockhud.handlers; + +import com.thatgravyboat.skyblockhud.api.events.SidebarLineUpdateEvent; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import org.apache.logging.log4j.LogManager; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Locale; +import java.util.regex.Pattern; + +public class TimeHandler { + + public static long time; + + @SubscribeEvent + public void onSidebarLineUpdate(SidebarLineUpdateEvent event){ + if (Pattern.matches("([0-9]*):([0-9]*)(pm|am)", event.formattedLine.toLowerCase().trim())) { + boolean isPm = event.formattedLine.toLowerCase().trim().endsWith("pm"); + SimpleDateFormat parseFormat = new SimpleDateFormat("hh:mm a", Locale.CANADA); + String currentTimeString = event.formattedLine.replace(" ", "").replace(isPm ? "pm" : "am", isPm ? " pm" : " am"); + try { + time = (parseFormat.parse(currentTimeString).getTime() - parseFormat.parse("00:00 am").getTime()) / 1000L; + } catch (ParseException ignored) { + LogManager.getLogger().warn("timeformat error: " + currentTimeString); + } + } + } +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/handlers/mapicons/DwarvenIcons.java b/src/main/java/com/thatgravyboat/skyblockhud/handlers/mapicons/DwarvenIcons.java new file mode 100644 index 0000000..5cd58bc --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/handlers/mapicons/DwarvenIcons.java @@ -0,0 +1,96 @@ +package com.thatgravyboat.skyblockhud.handlers.mapicons; + +import com.thatgravyboat.skyblockhud.ComponentBuilder; +import com.thatgravyboat.skyblockhud.handlers.MapHandler; +import net.minecraft.util.ResourceLocation; + +import javax.vecmath.Vector2f; +import java.util.ArrayList; +import java.util.List; + +public class DwarvenIcons { + + public static List<MapHandler.MapIcon> dwarvenIcons = new ArrayList<>(); + + static { + setupNpcIcons(); + setupMiscIcons(); + setupInfoIcons(); + setupShopIcons(); + setupQuestIcons(); + } + + private static void setupNpcIcons(){ + dwarvenIcons.add(new MapHandler.MapIcon( + new Vector2f(129, 187), + new ResourceLocation("skyblockhud", "maps/icons/puzzle.png"), + new ComponentBuilder() + .nl("Puzzler", new char[]{'a','l'}) + .nl("Description", 'l') + .nl("The Puzzler gives you a small puzzle each day to solve and") + .nl("gives you 1000 mithril powder.") + .build(), + MapHandler.MapIconTypes.NPC + ) + ); + } + + private static void setupMiscIcons(){} + + private static void setupInfoIcons(){ + dwarvenIcons.add(new MapHandler.MapIcon( + new Vector2f(129, 187), + new ResourceLocation("skyblockhud", "maps/icons/crown.png"), + new ComponentBuilder() + .nl("King", new char[]{'a','l'}) + .nl("Description", 'l') + .nl("The King allows you to first start commissions and if you click") + .nl("each king which change every skyblock day you will get") + .nl("the King Talisman.") + .nl() + .apd("Click to open HOTM", new char[]{'6', 'l'}) + .build(), + MapHandler.MapIconTypes.INFO, + "hotm" + ) + ); + } + + private static void setupShopIcons(){ + dwarvenIcons.add(new MapHandler.MapIcon( + new Vector2f(4, 8), + new ResourceLocation("skyblockhud", "maps/icons/blacksmith.png"), + new ComponentBuilder() + .nl("Forge", new char[]{'a','l'}) + .nl("Description", 'l') + .nl("The Forge is where you can go craft special items") + .nl("and fuel your drill.") + .nl("NPCS", new char[]{'c','l'}) + .nl(" Forger - Allows you to forge special items") + .nl(" Jotraeline Greatforge - Allows you to refuel your drill.") + .nl() + .apd("Click to warp", new char[]{'6', 'l'}) + .build(), + MapHandler.MapIconTypes.SHOPS, + "warpforge" + ) + ); + } + + private static void setupQuestIcons(){ + dwarvenIcons.add(new MapHandler.MapIcon( + new Vector2f(67, 204), + new ResourceLocation("skyblockhud", "maps/icons/special.png"), + new ComponentBuilder() + .nl("Royal Resident", new char[]{'a','l'}) + .nl("The Royal Resident is a quest where you right") + .nl("click them for a bit to obtain and if you continue") + .nl("to right click them for about 7 hours it will give") + .apd("the achievement Royal Conversation.") + .build(), + MapHandler.MapIconTypes.QUEST + ) + ); + } + +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/handlers/mapicons/HubIcons.java b/src/main/java/com/thatgravyboat/skyblockhud/handlers/mapicons/HubIcons.java new file mode 100644 index 0000000..ad1dbc3 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/handlers/mapicons/HubIcons.java @@ -0,0 +1,308 @@ +package com.thatgravyboat.skyblockhud.handlers.mapicons; + +import com.thatgravyboat.skyblockhud.ComponentBuilder; +import com.thatgravyboat.skyblockhud.handlers.MapHandler; +import net.minecraft.util.ResourceLocation; + +import javax.vecmath.Vector2f; +import java.util.ArrayList; +import java.util.List; + +public class HubIcons { + + public static List<MapHandler.MapIcon> hubIcons = new ArrayList<>(); + + static { + setupNpcIcons(); + setupMiscIcons(); + setupInfoIcons(); + setupShopIcons(); + setupQuestIcons(); + } + + private static void setupNpcIcons() { + hubIcons.add(new MapHandler.MapIcon( + new Vector2f(-2, -34), + new ResourceLocation("skyblockhud", "maps/icons/special.png"), + new ComponentBuilder() + .nl("Event Hut", new char[]{'a','l'}) + .nl("Description", 'l') + .nl("The Event Hut is where special event npcs") + .nl("are during some events.") + .nl("NPCS", new char[]{'c','l'}) + .nl(" Baker - During New Years") + .nl(" Jerry - While Winter Island is opened") + .nl(" Fear Mongerer - During Spooky Festival") + .apd(" Oringo - During Traveling Zoo") + .build(), + MapHandler.MapIconTypes.NPC + ) + ); + hubIcons.add(new MapHandler.MapIcon( + new Vector2f(135, 142), + new ResourceLocation("skyblockhud", "maps/icons/fairy.png"), + new ComponentBuilder() + .nl("Fairy", new char[]{'a','l'}) + .nl("Description", 'l') + .nl("The Fairy is where you go when you find fairy souls") + .apd("to trade them in to get permanent stat upgrades.") + .build(), + MapHandler.MapIconTypes.NPC + ) + ); + } + + private static void setupShopIcons() { + hubIcons.add(new MapHandler.MapIcon( + new Vector2f(-50, -22), + new ResourceLocation("skyblockhud", "maps/icons/building.png"), + new ComponentBuilder() + .nl("Builder's House", new char[]{'a','l'}) + .nl("NPCS", new char[]{'c','l'}) + .nl(" Wool Weaver") + .nl(" Builder") + .apd(" Mad Redstone Engineer") + .build(), + MapHandler.MapIconTypes.SHOPS + ) + ); + hubIcons.add(new MapHandler.MapIcon( + new Vector2f(-78, -46), + new ResourceLocation("skyblockhud", "maps/icons/bar.png"), + new ComponentBuilder() + .nl("Tavern", new char[]{'a','l'}) + .nl("NPCS", new char[]{'c','l'}) + .nl(" Bartender") + .nl(" Maddox the slayer") + .nl("Description", 'l') + .nl("The Tavern is where maddox the slayer is located you can") + .nl("start slayer quests with them to unlock") + .apd("new items the more slayer bosses you kill.") + .build(), + MapHandler.MapIconTypes.SHOPS + ) + ); + hubIcons.add(new MapHandler.MapIcon( + new Vector2f(36, -82), + new ResourceLocation("skyblockhud", "maps/icons/vet.png"), + new ComponentBuilder() + .nl("Vet", new char[]{'a','l'}) + .nl("NPCS", new char[]{'c','l'}) + .nl(" Bea") + .nl(" Zog") + .nl(" Kat") + .nl(" George") + .nl("Description", 'l') + .nl("The Vet is where you go to upgrade your pet") + .nl("at Kat or to buy pet upgrade items from Zog") + .nl("or trade in your pet at George and if you're") + .apd("a new player you can buy a bee pet from Bea.") + .build(), + MapHandler.MapIconTypes.SHOPS + ) + ); + hubIcons.add(new MapHandler.MapIcon( + new Vector2f(58, -73), + new ResourceLocation("skyblockhud", "maps/icons/fishing_merchant.png"), + new ComponentBuilder() + .nl("Fishing Merchant", new char[]{'a','l'}) + .nl("Description", 'l') + .nl("The Fishing Merchant allows you to buy") + .nl("fishing related items and he has his friend") + .nl("joe whose in the house hes setup") + .apd("in front of who sells sponges.") + .build(), + MapHandler.MapIconTypes.SHOPS + ) + ); + hubIcons.add(new MapHandler.MapIcon( + new Vector2f(46, -53), + new ResourceLocation("skyblockhud", "maps/icons/witch.png"), + new ComponentBuilder() + .nl("Alchemist", new char[]{'a','l'}) + .nl("Description", 'l') + .nl("The Alchemist allows you to buy") + .apd("potion making related items") + .build(), + MapHandler.MapIconTypes.SHOPS + ) + ); + hubIcons.add(new MapHandler.MapIcon( + new Vector2f(-4, -128), + new ResourceLocation("skyblockhud", "maps/icons/metal_merchants.png"), + new ComponentBuilder() + .nl("Blacksmith Merchants", new char[]{'a','l'}) + .nl("Merchants", new char[]{'c','l'}) + .nl(" Weaponsmith - Weapon Related Items") + .nl(" Armorsmith - Armor Related Items") + .apd(" Mine Merchant - Mining Related Items") + .build(), + MapHandler.MapIconTypes.SHOPS + ) + ); + hubIcons.add(new MapHandler.MapIcon( + new Vector2f(-30, -120), + new ResourceLocation("skyblockhud", "maps/icons/blacksmith.png"), + new ComponentBuilder() + .nl("Blacksmith", new char[]{'a','l'}) + .nl("NPCS", new char[]{'c','l'}) + .nl(" Blacksmith") + .nl(" Dusk") + .nl(" Smithmonger") + .nl("Description", 'l') + .nl("The Blacksmith lets you reforge your items") + .nl("while the Smithmonger allows you to buy reforge stones") + .apd("and Dusk allows you to combine and apply runes.") + .build(), + MapHandler.MapIconTypes.SHOPS + ) + ); + hubIcons.add(new MapHandler.MapIcon( + new Vector2f(124, 180), + new ResourceLocation("skyblockhud", "maps/icons/dark_bar.png"), + new ComponentBuilder() + .nl("Dark Bar", new char[]{'a','l'}) + .nl("NPCS", new char[]{'c','l'}) + .nl(" Shifty") + .nl(" Lucius") + .nl("Description", 'l') + .nl("The Dark Bar is where you can buy special") + .nl("brews from Shifty and you can buy special") + .nl("items from Lucius after buying a certain") + .apd("amount of items from the Dark Auction.") + .build(), + MapHandler.MapIconTypes.SHOPS + ) + ); + hubIcons.add(new MapHandler.MapIcon( + new Vector2f(92, 185), + new ResourceLocation("skyblockhud", "maps/icons/dark_ah.png"), + new ComponentBuilder() + .nl("Dark Auction", new char[]{'a','l'}) + .nl("Description", 'l') + .nl("The Dark Auction allows you to buy") + .nl("super special items from Sirius the") + .apd("auctioneer in a special auction.") + .build(), + MapHandler.MapIconTypes.SHOPS + ) + ); + hubIcons.add(new MapHandler.MapIcon( + new Vector2f(-245, 52), + new ResourceLocation("skyblockhud", "maps/icons/scroll.png"), + new ComponentBuilder() + .nl("Lonely Philosopher", new char[]{'a','l'}) + .nl("Shop", new char[]{'6','l'}) + .nl(" Travel Scroll to Hub Castle") + .nl() + .nl(" Cost") + .nl(" 150,000 Coins", '6') + .nl() + .apd(" Requires ") + .apd("MVP", 'b') + .apd("+", 'c') + .build(), + MapHandler.MapIconTypes.SHOPS + ) + ); + hubIcons.add(new MapHandler.MapIcon( + new Vector2f(24, -38), + new ResourceLocation("skyblockhud", "maps/icons/tux.png"), + new ComponentBuilder() + .nl("Fashion Shop", new char[]{'a','l'}) + .nl("NPCS", new char[]{'c','l'}) + .nl(" Wool Weaver") + .nl(" Builder") + .apd(" Mad Redstone Engineer") + .build(), + MapHandler.MapIconTypes.SHOPS + ) + ); + } + + private static void setupMiscIcons() { + hubIcons.add(new MapHandler.MapIcon( + new Vector2f(-24, -53), + new ResourceLocation("skyblockhud", "maps/icons/bank.png"), + new ComponentBuilder() + .nl("Bank", new char[]{'a','l'}) + .nl("Description", 'l') + .nl("The Bank is where you can store your money on skyblock") + .apd("you can also store some items in the vault.") + .build(), + MapHandler.MapIconTypes.MISC + ) + ); + hubIcons.add(new MapHandler.MapIcon( + new Vector2f(-26, -80), + new ResourceLocation("skyblockhud", "maps/icons/ah.png"), + new ComponentBuilder() + .nl("Auction House", new char[]{'a','l'}) + .nl("Description", 'l') + .nl("The Auction House is where you can auction off your") + .apd("precious items in skyblock to make a profit.") + .build(), + MapHandler.MapIconTypes.MISC + ) + ); + hubIcons.add(new MapHandler.MapIcon( + new Vector2f(-38, -66), + new ResourceLocation("skyblockhud", "maps/icons/bazaar.png"), + new ComponentBuilder() + .nl("Bazaar", new char[]{'a','l'}) + .nl("Description", 'l') + .nl("The Bazaar is where you can sell specific items") + .nl("on a sort of stock market and request and") + .apd("sell items at a specific price.") + .build(), + MapHandler.MapIconTypes.MISC + ) + ); + } + + private static void setupInfoIcons() { + hubIcons.add(new MapHandler.MapIcon( + new Vector2f(8, -95), + new ResourceLocation("skyblockhud", "maps/icons/community.png"), + new ComponentBuilder() + .nl("Community Center", new char[]{'a','l'}) + .nl("Description", 'l') + .nl("The Community Center is where you can vote") + .nl("for your favorite election candidate,") + .nl("access the community shop, upgrade your") + .apd("account, and help with city projects.") + .build(), + MapHandler.MapIconTypes.INFO + ) + ); + hubIcons.add(new MapHandler.MapIcon( + new Vector2f(150, 45), + new ResourceLocation("skyblockhud", "maps/icons/fishing.png"), + new ComponentBuilder() + .nl("Fisherman's Hut", new char[]{'a','l'}) + .nl("Description", 'l') + .nl("This is a spot where people regularly") + .nl("do their fishing, this is one") + .apd("of many spots.") + .build(), + MapHandler.MapIconTypes.INFO + ) + ); + } + + private static void setupQuestIcons() { + hubIcons.add(new MapHandler.MapIcon( + new Vector2f(-8, -10), + new ResourceLocation("skyblockhud", "maps/icons/painter.png"), + new ComponentBuilder() + .nl("Marco", new char[]{'a','l'}) + .nl("Description", 'l') + .nl("Marco is an NPC that has no other uses") + .nl("besides giving you a spray can for") + .apd("completing a quest.") + .build(), + MapHandler.MapIconTypes.QUEST + ) + ); + } +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/handlers/sbentities/EntityTypeHelper.java b/src/main/java/com/thatgravyboat/skyblockhud/handlers/sbentities/EntityTypeHelper.java new file mode 100644 index 0000000..afff109 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/handlers/sbentities/EntityTypeHelper.java @@ -0,0 +1,21 @@ +package com.thatgravyboat.skyblockhud.handlers.sbentities; + +import com.thatgravyboat.skyblockhud.location.LocationHandler; +import com.thatgravyboat.skyblockhud.location.Locations; +import net.minecraft.entity.Entity; +import net.minecraft.entity.monster.EntityEnderman; +import net.minecraft.init.Blocks; + +public class EntityTypeHelper { + + public static boolean isZealot(Entity entity) { + if (entity instanceof EntityEnderman) { + EntityEnderman enderman = ((EntityEnderman) entity); + double maxHealthBase = enderman.getAttributeMap().getAttributeInstanceByName("generic.maxHealth").getBaseValue(); + if (maxHealthBase == 13000d || (maxHealthBase == 2000d && enderman.getHeldBlockState().getBlock().equals(Blocks.end_portal_frame))) { + return LocationHandler.getCurrentLocation().equals(Locations.DRAGONSNEST); + } + } + return false; + } +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/handlers/sbentities/EntityTypeRegistry.java b/src/main/java/com/thatgravyboat/skyblockhud/handlers/sbentities/EntityTypeRegistry.java new file mode 100644 index 0000000..d45fa1f --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/handlers/sbentities/EntityTypeRegistry.java @@ -0,0 +1,25 @@ +package com.thatgravyboat.skyblockhud.handlers.sbentities; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Maps; +import net.minecraft.entity.Entity; +import net.minecraft.entity.monster.EntityEnderman; + +import java.util.List; +import java.util.Map; + +public class EntityTypeRegistry { + + private static final Map<Class<? extends Entity>, List<SkyBlockEntity>> entities = Maps.newHashMap(); + + static { + entities.put(EntityEnderman.class, ImmutableList.of(SkyBlockEntity.of("zealot", EntityTypeHelper::isZealot))); + } + + public static String getEntityId(Entity entity){ + if (!entities.containsKey(entity.getClass())) return null; + for (SkyBlockEntity skyBlockEntity : entities.get(entity.getClass())) if (skyBlockEntity.isEntity(entity)) return skyBlockEntity.getName(); + return null; + } + +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/handlers/sbentities/SkyBlockEntity.java b/src/main/java/com/thatgravyboat/skyblockhud/handlers/sbentities/SkyBlockEntity.java new file mode 100644 index 0000000..ca10b53 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/handlers/sbentities/SkyBlockEntity.java @@ -0,0 +1,26 @@ +package com.thatgravyboat.skyblockhud.handlers.sbentities; + +import net.minecraft.entity.Entity; + +import java.util.function.Predicate; + +public class SkyBlockEntity { + + private final String name; + private final Predicate<Entity> predicate; + + public static SkyBlockEntity of(String name, Predicate<Entity> predicate){ + return new SkyBlockEntity(name, predicate); + } + + private SkyBlockEntity(String name, Predicate<Entity> predicate){ + this.name = name; + this.predicate = predicate; + } + + public String getName(){ return name; } + + public boolean isEntity(Entity entity) { + return predicate.test(entity); + } +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/location/DwarvenMineHandler.java b/src/main/java/com/thatgravyboat/skyblockhud/location/DwarvenMineHandler.java new file mode 100644 index 0000000..32f6c80 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/location/DwarvenMineHandler.java @@ -0,0 +1,97 @@ +package com.thatgravyboat.skyblockhud.location; + +import com.thatgravyboat.skyblockhud.api.events.SidebarLineUpdateEvent; +import com.thatgravyboat.skyblockhud.api.events.SidebarPostEvent; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; + +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; +import java.util.Arrays; +import java.util.Locale; + +public class DwarvenMineHandler { + + public enum Event { + NONE(0, "Unknown"), + TICKET(107, "Raffle"), + GOBLIN(99, "Goblin Raid"); + + public int x; + public String displayName; + + Event(int x, String displayName){ + this.x = x; + this.displayName = displayName; + } + } + + public static int mithril; + + public static int eventMax; + public static int eventProgress; + public static Event currentEvent; + + private static final DecimalFormat formatter = new DecimalFormat("#,###", DecimalFormatSymbols.getInstance(Locale.CANADA)); + + public static String getMithrilFormatted(){ + String output = formatter.format(mithril); + if (output.equals(".0")) output = "0.0"; + else if (output.equals(",0")) output = "0,0"; + return output; + } + + public static void parseMithril(String line){ + try{ + mithril = Integer.parseInt(line.toLowerCase().replace("mithril powder:", "").trim()); + }catch (Exception ignored){} + } + + @SubscribeEvent + public void onSidebarLineUpdate(SidebarLineUpdateEvent event){ + if (event.formattedLine.toLowerCase().contains("mithril")){ + try{ + mithril = Integer.parseInt(event.formattedLine.toLowerCase().replace("mithril:","").trim()); + }catch (Exception ignored){} + } + if (event.formattedLine.toLowerCase().contains("event")){ + if (event.formattedLine.toLowerCase().contains("raffle")){ + DwarvenMineHandler.currentEvent = Event.TICKET; + }else if (event.formattedLine.toLowerCase().contains("goblin raid")){ + DwarvenMineHandler.currentEvent = Event.GOBLIN; + } + } + if (DwarvenMineHandler.currentEvent != Event.NONE){ + if (DwarvenMineHandler.currentEvent == Event.TICKET && event.formattedLine.toLowerCase().contains("tickets:")){ + if (event.formattedLine.toLowerCase().contains("pool:")){ + try{ + eventMax = Integer.parseInt(event.formattedLine.toLowerCase().replace("pool:","").trim().split("/")[0].trim()); + }catch (Exception ignored){} + }else if (event.formattedLine.toLowerCase().contains("tickets:")){ + try{ + eventProgress = Integer.parseInt(event.formattedLine.toLowerCase().replace("tickets:", "").split("\\(")[0].trim()); + }catch (Exception ignored){} + } + }else if (DwarvenMineHandler.currentEvent == Event.GOBLIN){ + if (event.formattedLine.toLowerCase().contains("remaining:")){ + try{ + eventMax = Integer.parseInt(event.formattedLine.toLowerCase().replace("goblins","").replace("remaining:","").trim()); + }catch (Exception ignored){} + }else if (event.formattedLine.toLowerCase().contains("your kills:") && !event.formattedLine.toLowerCase().contains("(")){ + try{ + eventProgress = Integer.parseInt(event.formattedLine.toLowerCase().replace("your kills:","").trim()); + }catch (Exception ignored){} + } + } + } + } + + @SubscribeEvent + public void onSidebarPost(SidebarPostEvent event) { + String arrayString = Arrays.toString(event.arrayScores); + if (!arrayString.toLowerCase().contains("event:")){ + DwarvenMineHandler.currentEvent = Event.NONE; + DwarvenMineHandler.eventProgress = 0; + DwarvenMineHandler.eventMax = 0; + } + } +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/location/EndIslandHandler.java b/src/main/java/com/thatgravyboat/skyblockhud/location/EndIslandHandler.java new file mode 100644 index 0000000..e8be465 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/location/EndIslandHandler.java @@ -0,0 +1,46 @@ +package com.thatgravyboat.skyblockhud.location; + +public class EndIslandHandler { + public enum dragonTypes { + PROTECTOR("Protector Dragon", 9000000), + OLD("Old Dragon", 15000000), + WISE("Wise Dragon", 9000000), + UNSTABLE("Unstable Dragon", 9000000), + YOUNG("Young Dragon", 7500000), + STRONG("Strong Dragon", 9000000), + SUPERIOR("Superior Dragon", 12000000), + NODRAGON("", 0); + + private final String displayName; + private final int maxHealth; + + dragonTypes(String displayName, int maxHealth){ + this.displayName = displayName; + this.maxHealth = maxHealth; + } + + public String getDisplayName(){ + return this.displayName; + } + + public int getMaxHealth() { + return this.maxHealth; + } + + public static dragonTypes findDragon(String input){ + if (input.contains(" ")){ + try { + return dragonTypes.valueOf(input.toLowerCase().replace("dragon", "").replace(" ", "").toUpperCase()); + } catch(IllegalArgumentException ignored) { + return NODRAGON; + } + } else { + try { return dragonTypes.valueOf(input); } catch(IllegalArgumentException ignored) { return NODRAGON; } + } + } + } + + private static dragonTypes currentDragon = dragonTypes.NODRAGON; + + public static void setCurrentDragon(dragonTypes dragon) { currentDragon = dragon; } +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/location/FarmingIslandHandler.java b/src/main/java/com/thatgravyboat/skyblockhud/location/FarmingIslandHandler.java new file mode 100644 index 0000000..03a698b --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/location/FarmingIslandHandler.java @@ -0,0 +1,29 @@ +package com.thatgravyboat.skyblockhud.location; + +import com.thatgravyboat.skyblockhud.api.events.SidebarPostEvent; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; + +import java.util.Arrays; + +public class FarmingIslandHandler { + + public static Locations location = Locations.NONE; + public static int pelts; + + @SubscribeEvent + public void onSidebarPost(SidebarPostEvent event) { + boolean isTracking = Arrays.toString(event.arrayScores).toLowerCase().contains("tracker mob location:"); + if (isTracking && location == Locations.NONE) { + for (int i = 0; i < event.scores.size(); i++) { + String line = event.scores.get(i); + if (line.toLowerCase().contains("tracker mob location:") && i > 2){ + location = Locations.get(event.scores.get(i - 1).toLowerCase()); + break; + } + } + } + if (!isTracking && location != Locations.NONE){ + location = Locations.NONE; + } + } +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/location/IslandHandler.java b/src/main/java/com/thatgravyboat/skyblockhud/location/IslandHandler.java new file mode 100644 index 0000000..d6ab81e --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/location/IslandHandler.java @@ -0,0 +1,62 @@ +package com.thatgravyboat.skyblockhud.location; + +import com.thatgravyboat.skyblockhud.Utils; +import com.thatgravyboat.skyblockhud.api.events.ProfileSwitchedEvent; +import com.thatgravyboat.skyblockhud.api.events.SidebarLineUpdateEvent; +import com.thatgravyboat.skyblockhud.api.events.SidebarPostEvent; +import com.thatgravyboat.skyblockhud.handlers.CurrencyHandler; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; + +import java.util.Arrays; + +public class IslandHandler { + + public static int flightTime; + public static boolean hadFlightTime; + + public static int redstone; + public static boolean hadRedstone; + + @SubscribeEvent + public void onSidebarLineUpdate(SidebarLineUpdateEvent event){ + hadFlightTime = checkFlightDuration(event.formattedLine); + hadRedstone = checkRestone(event.formattedLine); + } + + @SubscribeEvent + public void onProfileSwitch(ProfileSwitchedEvent event){ + flightTime = 0; + } + + public static boolean checkFlightDuration(String formatedScoreboardLine){ + if (LocationHandler.getCurrentLocation() == Locations.YOURISLAND && Utils.removeColor(formatedScoreboardLine.toLowerCase().trim()).contains("flight duration:")){ + String timeString = formatedScoreboardLine.toLowerCase().replace("flight duration:", "").replace(" ", ""); + String[] times = timeString.split(":"); + if (times.length == 2){ + int s = 0; + try { s += Integer.parseInt(times[0]) * 60; } catch (NumberFormatException ignored){} + try { s += Integer.parseInt(times[1]); } catch (NumberFormatException ignored){} + flightTime = s - 1; + } else if (times.length == 3){ + int s = 0; + try { s += Integer.parseInt(times[0]) * 3600; } catch (NumberFormatException ignored){} + try { s += Integer.parseInt(times[1]) * 60; } catch (NumberFormatException ignored){} + try { s += Integer.parseInt(times[2]); } catch (NumberFormatException ignored){} + flightTime = s - 1; + } + return true; + } + return false; + } + + public static boolean checkRestone(String formatedScoreboardLine){ + if (LocationHandler.getCurrentLocation() == Locations.YOURISLAND) { + if (formatedScoreboardLine.toLowerCase().contains("redstone:")) + return true; + try { + redstone = formatedScoreboardLine.toLowerCase().contains("redstone:") ? Integer.parseInt(Utils.removeWhiteSpaceAndRemoveWord(formatedScoreboardLine, "redstone:")) : 0; + }catch (Exception ignored){} + } + return false; + } +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/location/LocationCategory.java b/src/main/java/com/thatgravyboat/skyblockhud/location/LocationCategory.java new file mode 100644 index 0000000..817645d --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/location/LocationCategory.java @@ -0,0 +1,46 @@ +package com.thatgravyboat.skyblockhud.location; + +import com.thatgravyboat.skyblockhud.handlers.MapHandler; +import static com.thatgravyboat.skyblockhud.handlers.MapHandler.Maps; + +public enum LocationCategory { + + ERROR("error", 34), + ISLAND("island",43), + HUB("hub",34, Maps.HUB), + BARN("barn",67, Maps.BARN), + MUSHROOMDESERT("mushroomdesert",75, Maps.MUSHROOM), + GOLDMINE("gold_mine",83), + DEEPCAVERNS("deepcaverns",91), + SPIDERSDEN("spiders_den",99, Maps.SPIDERS), + PARK("park",51, Maps.PARK), + FORTRESS("fortress",107, Maps.NETHER), + DUNGEONHUB("dungeonhub",115), + JERRY("jerry",59), + THEEND("the_end",123), + DWARVENMINES("dwarven_mines", 131, Maps.DWARVEN), + CRYSTALHOLLOWS("crystal_hollows", 131); + + + private final String name; + private final int texturePos; + private final MapHandler.Maps map; + + LocationCategory(String name, int texturePos){ + this(name, texturePos, null); + } + + LocationCategory(String name, int texturePos, MapHandler.Maps map){ + this.name = name; + this.texturePos = texturePos; + this.map = map; + } + + public String getName(){ + return this.name; + } + public int getTexturePos(){ + return this.texturePos; + } + public MapHandler.Maps getMap() { return this.map; } +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/location/LocationHandler.java b/src/main/java/com/thatgravyboat/skyblockhud/location/LocationHandler.java new file mode 100644 index 0000000..274baf8 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/location/LocationHandler.java @@ -0,0 +1,54 @@ +package com.thatgravyboat.skyblockhud.location; + +import com.thatgravyboat.skyblockhud.api.events.SidebarLineUpdateEvent; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; + +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; + +public class LocationHandler { + + private static Locations currentLocation = Locations.NONE; + private static final List<String> UndocumentedLocations = new ArrayList<>(); + + + @SubscribeEvent + public void onSidebarLineUpdate(SidebarLineUpdateEvent event){ + if (event.rawLine.contains("\u23E3")) { + String objectiveName = event.objective.getDisplayName().replaceAll("(?i)\\u00A7.", ""); + if (objectiveName.toLowerCase(Locale.ENGLISH).endsWith("guest")){ + LocationHandler.setCurrentLocation(Locations.GUESTISLAND); + }else { + LocationHandler.handleLocation(event.formattedLine); + } + } + } + + public static void setCurrentLocation(String location){ + currentLocation = Locations.get(location); + } + + public static void setCurrentLocation(Locations location){ + currentLocation = location; + } + + public static Locations getCurrentLocation(){ return currentLocation; } + + public static void handleLocation(String locationLine){ + String location = locationLine.replace(" ", "").toUpperCase(Locale.ENGLISH).trim(); + if (location.startsWith("THECATACOMBS")){ + currentLocation = Locations.CATACOMBS; + } + else setCurrentLocation(location.replaceAll("[^A-Za-z0-9]", "")); + } + + + public static void reportUndocumentedLocation(String locationId){ + if (!UndocumentedLocations.contains(locationId)){ + UndocumentedLocations.add(locationId); + System.out.println("Missing Location value for: " + locationId); + } + } + +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/location/Locations.java b/src/main/java/com/thatgravyboat/skyblockhud/location/Locations.java new file mode 100644 index 0000000..887ac11 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/location/Locations.java @@ -0,0 +1,157 @@ +package com.thatgravyboat.skyblockhud.location; + +public enum Locations { + + //ERROR LOCATIONS + DEFAULT("unknown", "Error", LocationCategory.ERROR), + NONE("none", "Unknown", LocationCategory.ERROR), + //ISLAND + YOURISLAND("yourisland", "Your Island", LocationCategory.ISLAND), + GUESTISLAND("guestisland", "Guest Island", LocationCategory.ISLAND), + MOULBERRYSISLAND("moulberryisland", "Cool Dude Hub", LocationCategory.ISLAND), + //HUB + VILLAGE("village", "Village", LocationCategory.HUB), + AUCTIONHOUSE("auctionhouse", "Auction House", LocationCategory.HUB), + BAZAARALLEY("bazaaralley", "Bazaar Alley", LocationCategory.HUB), + BANK("bank", "Bank", LocationCategory.HUB), + FASHIONSHOP("fashionshop", "Fashion Shop", LocationCategory.HUB), + COLOSSEUM("colosseum", "Colosseum", LocationCategory.HUB), + COLOSSEUMARENA("colosseumarena", "Colosseum Arena", LocationCategory.HUB), + MOUNTAIN("mountain", "Mountain", LocationCategory.HUB), + HIGHLEVEL("highlevel", "High Level", LocationCategory.HUB), + WILDERNESS("wilderness", "Wilderness", LocationCategory.HUB), + FISHERMANSHUT("fishermanshut", "Fisherman's Hut", LocationCategory.HUB), + FLOWERHOUSE("flowerhouse", "Flower House", LocationCategory.HUB), + CANVASROOM("canvasroom", "Canvas Room", LocationCategory.HUB), + TAVERN("tavern", "Tavern", LocationCategory.HUB), + FOREST("forest", "Forest", LocationCategory.HUB), + RUINS("ruins", "Ruins", LocationCategory.HUB), + GRAVEYARD("graveyard", "Graveyard", LocationCategory.HUB), + COALMINE("coalmine", "Coal Mine", LocationCategory.HUB), + FARM("farm", "Farm", LocationCategory.HUB), + LIBRARY("library", "Library", LocationCategory.HUB), + COMMUNITYCENTER("communitycenter", "Community Center", LocationCategory.HUB), + ELECTIONROOM("electionroom", "Election Room", LocationCategory.HUB), + BUILDERSHOUSE("buildershouse", "Builder's House", LocationCategory.HUB), + BLACKSMITH("blacksmith", "Blacksmith", LocationCategory.HUB), + FARMHOUSE("farmhouse", "Farmhouse", LocationCategory.HUB), + WIZARDTOWER("wizardtower", "Wizard Tower", LocationCategory.HUB), + //THE BARN + THEBARN("thebarn", "The Barn", LocationCategory.BARN), + WINDMILL("windmill", "Windmill", LocationCategory.BARN), + //MUSHROOM DESERT + MUSHROOMDESERT("mushroomdesert", "Mushroom Desert", LocationCategory.MUSHROOMDESERT), + DESERTSETTLEMENT("desertsettlement", "Desert Settlement", LocationCategory.MUSHROOMDESERT), + OASIS("oasis", "Oasis", LocationCategory.MUSHROOMDESERT), + MUSHROOMGORGE("mushroomgorge", "Mushroom Gorge", LocationCategory.MUSHROOMDESERT), + SHEPHERDSKEEP("shepherdskeep", "Shepherds Keep", LocationCategory.MUSHROOMDESERT), + JAKESHOUSE("jakeshouse", "Jake's House", LocationCategory.MUSHROOMDESERT), + TREASUREHUNTERCAMP("treasurehuntercamp", "Treasure Hunter Camp", LocationCategory.MUSHROOMDESERT), + GLOWINGMUSHROOMCAVE("glowingmushroomcave", "Glowing Mushroom Cave", LocationCategory.MUSHROOMDESERT), + TRAPPERSDEN("trappersden", "Trappers Den", LocationCategory.MUSHROOMDESERT), + OVERGROWNMUSHROOMCAVE("overgrownmushroomcave", "Overgrown Mushroom Cave", LocationCategory.MUSHROOMDESERT), + //GOLD MINE + GOLDMINE("goldmine", "Gold Mine", LocationCategory.GOLDMINE), + //DEEP CAVERNS + DEEPCAVERNS("deepcaverns", "Deep Caverns", LocationCategory.DEEPCAVERNS), + GUNPOWDERMINES("gunpowdermines", "Gunpowder Mines", LocationCategory.DEEPCAVERNS), + LAPISQUARRY("lapisquarry", "Lapis Quarry", LocationCategory.DEEPCAVERNS), + PIGMANSDEN("pigmansden", "Pigman's Den", LocationCategory.DEEPCAVERNS), + SLIMEHILL("slimehill", "Slimehill", LocationCategory.DEEPCAVERNS), + DIAMONDRESERVE("diamondreserve", "Diamond Reserve", LocationCategory.DEEPCAVERNS), + OBSIDIANSANCTUARY("obsidiansanctuary", "Obsidian Sanctuary", LocationCategory.DEEPCAVERNS), + //SPIDERS DEN + SPIDERSDEN("spidersden", "Spider's Den", LocationCategory.SPIDERSDEN), + + //THE END + THEEND("theend", "The End", LocationCategory.THEEND), + DRAGONSNEST("dragonsnest", "Dragon's Nest", LocationCategory.THEEND), + VOIDSEPULTURE("voidsepulture", "Void Sepulture", LocationCategory.THEEND), + //PARK + HOWLINGCAVE("howlingcave", "Howling Cave", LocationCategory.PARK), + BIRCHPARK("birchpark", "Birch Park", LocationCategory.PARK), + SPRUCEWOODS("sprucewoods", "Spruce Woods", LocationCategory.PARK), + DARKTHICKET("darkthicket", "Dark Thicket", LocationCategory.PARK), + SAVANNAWOODLAND("savannawoodland", "Savanna Woodland", LocationCategory.PARK), + JUNGLEISLAND("jungleisland", "Jungle Island", LocationCategory.PARK), + //BLAZING FORTRESS + BLAZINGFORTRESS("blazingfortress", "Blazing Fortress", LocationCategory.FORTRESS), + //DUNGEONS + DUNGEONHUB("dungeonhub", "Dungeon Hub", LocationCategory.DUNGEONHUB), + CATACOMBS("catacombs", "The Catacombs", LocationCategory.DUNGEONHUB), + CATACOMBSENTRANCE("catacombsentrance", "Catacombs Entrance", LocationCategory.DUNGEONHUB), + //JERRYISLAND + JERRYSWORKSHOP("jerrysworkshop", "Jerry's Workshop", LocationCategory.JERRY), + JERRYPOND("jerrypond", "Jerry Pond", LocationCategory.JERRY), + //DWARVENMINES + THELIFT("thelift", "The Lift", LocationCategory.DWARVENMINES), + DWARVENVILLAGE("dwarvenvillage", "Dwarven Village", LocationCategory.DWARVENMINES), + DWARVENMINES("dwarvenmines", "Dwarven Mines", LocationCategory.DWARVENMINES), + LAVASPRINGS("lavasprings", "Lava Springs", LocationCategory.DWARVENMINES), + PALACEBRIDGE("palacebridge", "Palace Bridge", LocationCategory.DWARVENMINES), + ROYALPALACE("royalpalace", "Royal Palace", LocationCategory.DWARVENMINES), + GRANDLIBRARY("grandlibrary", "Grand Library", LocationCategory.DWARVENMINES), + ROYALQUARTERS("royalquarters", "Royal Quarters", LocationCategory.DWARVENMINES), + BARRACKSOFHEROES("barracksofheroes", "Barracks of Heroes", LocationCategory.DWARVENMINES), + HANGINGCOURT("hangingcourt", "Hanging Court", LocationCategory.DWARVENMINES), + GREATICEWALL("greaticewall", "Great Ice Wall", LocationCategory.DWARVENMINES), + GOBLINBURROWS("goblinburrows", "Goblin Burrows", LocationCategory.DWARVENMINES), + FARRESERVE("farreserve", "Far Reserve", LocationCategory.DWARVENMINES), + CCMINECARTSCO("ccminecartco", "Minecart Co.", LocationCategory.DWARVENMINES), + UPPERMINES("uppermines", "Upper Mines", LocationCategory.DWARVENMINES), + RAMPARTSQUARRY("rampartsquarry", "Ramparts Quarry", LocationCategory.DWARVENMINES), + GATESTOTHEMINES("gatestothemines", "Gates to The Mines", LocationCategory.DWARVENMINES), + FORGEBASIN("forgebasin", "Forge Basin", LocationCategory.DWARVENMINES), + THEFORGE("theforge", "The Forge", LocationCategory.DWARVENMINES), + CLIFFSIDEVEINS("cliffsideveins", "Cliffside Veins", LocationCategory.DWARVENMINES), + DIVANSGATEWAY("divansgateway", "Divan's Gateway", LocationCategory.DWARVENMINES), + THEMIST("themist", "The Mist", LocationCategory.DWARVENMINES), + ROYALMINES("royalmines", "Royal Mines", LocationCategory.DWARVENMINES), + ARISTOCRATPASSAGE("aristocratpassage", "Aristocrat Passage", LocationCategory.DWARVENMINES), + MINERSGUILD("minersguild", "Miner's Guild", LocationCategory.DWARVENMINES), + //CRYSTALHOLLOWS + JUNGLE("jungle", "Jungle", LocationCategory.CRYSTALHOLLOWS), + MAMGAFIELDS("magmafields", "Magma Fields", LocationCategory.CRYSTALHOLLOWS), + GOBLINHOLDOUT("goblinholdout", "Goblin Holdout", LocationCategory.CRYSTALHOLLOWS), + CRYSTALNUCLEUS("crystalnucleus", "Crystal Nucleus", LocationCategory.CRYSTALHOLLOWS), + PERCURSORREMNANTS("precursorremnants", "Precursor Remnants", LocationCategory.CRYSTALHOLLOWS), + MITHRILDEPOSITS("mithrildeposits", "Mithril Deposits", LocationCategory.CRYSTALHOLLOWS); + + + private final String name; + private final String displayName; + private final LocationCategory category; + + Locations(String name, String displayName, LocationCategory category){ + this.name = name; + this.displayName = displayName; + this.category = category; + } + + public String getName() { + return this.name; + } + + public String getDisplayName() { + return this.displayName; + } + + public LocationCategory getCategory() { + return this.category; + } + + static public Locations get(String id) { + try { + return Locations.valueOf(id.replace(" ", "").toUpperCase()); + } catch (IllegalArgumentException ex) { + LocationHandler.reportUndocumentedLocation(id); + return DEFAULT; + } + } + + + @Override + public String toString() { + return this.name; + } +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/location/ParkIslandHandler.java b/src/main/java/com/thatgravyboat/skyblockhud/location/ParkIslandHandler.java new file mode 100644 index 0000000..2a41391 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/location/ParkIslandHandler.java @@ -0,0 +1,31 @@ +package com.thatgravyboat.skyblockhud.location; + +import javax.annotation.Nullable; + +public class ParkIslandHandler { + + private static boolean isRaining = false; + private static String rainTime = ""; + + public static void parseRain(@Nullable String tabLine){ + if (tabLine == null){ + isRaining = false; + rainTime = ""; + } + else if (tabLine.toLowerCase().contains("rain:")){ + if (tabLine.toLowerCase().contains("no rain")) isRaining = false; + else { + rainTime = tabLine.toLowerCase().replace("rain:", "").replace(" ", ""); + isRaining = true; + } + } + } + + public static String getRainTime(){ + return rainTime; + } + + public static boolean isRaining(){ + return isRaining; + } +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/mixins/MixinEndermanRenderer.java b/src/main/java/com/thatgravyboat/skyblockhud/mixins/MixinEndermanRenderer.java new file mode 100644 index 0000000..3cdbae5 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/mixins/MixinEndermanRenderer.java @@ -0,0 +1,25 @@ +package com.thatgravyboat.skyblockhud.mixins; + +import com.thatgravyboat.skyblockhud.SpecialColour; +import com.thatgravyboat.skyblockhud.handlers.sbentities.EntityTypeHelper; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.entity.RenderEnderman; +import net.minecraft.entity.monster.EntityEnderman; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.awt.*; + +@Mixin(RenderEnderman.class) +public class MixinEndermanRenderer { + + @Inject(method = "doRender(Lnet/minecraft/entity/monster/EntityEnderman;DDDFF)V", at = @At("HEAD")) + public void onRender(EntityEnderman entity, double x, double y, double z, float entityYaw, float partialTicks, CallbackInfo ci){ + if (EntityTypeHelper.isZealot(entity)){ + Color color = new Color(SpecialColour.specialToChromaRGB("255:255:0:48:255")); + GlStateManager.color(color.getRed() / 255f, color.getGreen() / 255f, color.getBlue() / 255f, 255f); + } + } +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/mixins/MixinEntityArrow.java b/src/main/java/com/thatgravyboat/skyblockhud/mixins/MixinEntityArrow.java new file mode 100644 index 0000000..93537ea --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/mixins/MixinEntityArrow.java @@ -0,0 +1,25 @@ +package com.thatgravyboat.skyblockhud.mixins; + +import com.thatgravyboat.skyblockhud.tracker.KillTrackerHandler; +import net.minecraft.client.Minecraft; +import net.minecraft.entity.Entity; +import net.minecraft.entity.projectile.EntityArrow; +import net.minecraft.util.MovingObjectPosition; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.ModifyVariable; + +@Mixin(EntityArrow.class) +public class MixinEntityArrow { + //Disabled as kill tracker stuff not fully added yet. + @Shadow public Entity shootingEntity; + + @ModifyVariable(method = "onUpdate", at = @At(value = "STORE", ordinal = 1)) + public MovingObjectPosition onUpdate(MovingObjectPosition position){ + if (position != null && position.entityHit != null && this.shootingEntity != null && this.shootingEntity.getUniqueID().equals(Minecraft.getMinecraft().thePlayer.getUniqueID())) { + KillTrackerHandler.attackedEntities.add(position.entityHit.getUniqueID()); + } + return position; + } +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/mixins/MixinGuiIngameForge.java b/src/main/java/com/thatgravyboat/skyblockhud/mixins/MixinGuiIngameForge.java new file mode 100644 index 0000000..ce7c228 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/mixins/MixinGuiIngameForge.java @@ -0,0 +1,92 @@ +package com.thatgravyboat.skyblockhud.mixins; + +import com.thatgravyboat.skyblockhud.SkyblockHud; +import net.minecraftforge.client.GuiIngameForge; +import net.minecraftforge.client.event.RenderGameOverlayEvent; +import net.minecraftforge.common.MinecraftForge; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import static net.minecraftforge.client.event.RenderGameOverlayEvent.ElementType.*; + +@Mixin(GuiIngameForge.class) +public class MixinGuiIngameForge { + + @Shadow(remap = false) + private RenderGameOverlayEvent eventParent; + + @Inject(method = "renderArmor", at = @At("HEAD"), cancellable = true, remap = false) + public void onRenderArmor(int width, int height, CallbackInfo ci){ + if (SkyblockHud.config.renderer.hideArmor && SkyblockHud.hasSkyblockScoreboard()){ + ci.cancel(); + if (pre(ARMOR)) return; + post(ARMOR); + } + } + + @Inject(method = "renderHealth", at = @At("HEAD"), cancellable = true, remap = false) + public void onRenderHealth(int width, int height, CallbackInfo ci){ + if (SkyblockHud.config.renderer.hideHearts && SkyblockHud.hasSkyblockScoreboard()){ + ci.cancel(); + if (pre(HEALTH)) return; + post(HEALTH); + } + } + + @Inject(method = "renderAir", at = @At("HEAD"), cancellable = true, remap = false) + public void onRenderAir(int width, int height, CallbackInfo ci){ + if (SkyblockHud.config.renderer.hideAir && SkyblockHud.hasSkyblockScoreboard()){ + ci.cancel(); + if (pre(AIR)) return; + post(AIR); + } + } + + @Inject(method = "renderHealthMount", at = @At("HEAD"), cancellable = true, remap = false) + public void onRenderHealthMount(int width, int height, CallbackInfo ci){ + if (SkyblockHud.config.renderer.hideAnimalHearts && SkyblockHud.hasSkyblockScoreboard()){ + ci.cancel(); + if (pre(HEALTHMOUNT)) return; + post(HEALTHMOUNT); + } + } + + @Inject(method = "renderExperience", at = @At("HEAD"), cancellable = true, remap = false) + public void onRenderExperience(int width, int height, CallbackInfo ci){ + if (SkyblockHud.config.renderer.hideXpBar && SkyblockHud.hasSkyblockScoreboard()){ + ci.cancel(); + if (pre(EXPERIENCE)) return; + post(EXPERIENCE); + } + } + + @Inject(method = "renderJumpBar", at = @At("HEAD"), cancellable = true, remap = false) + public void onRenderJumpBar(int width, int height, CallbackInfo ci){ + if (SkyblockHud.config.renderer.hideXpBar && SkyblockHud.hasSkyblockScoreboard()){ + ci.cancel(); + if (pre(JUMPBAR)) return; + post(JUMPBAR); + } + } + + @Inject(method = "renderFood", at = @At("HEAD"), cancellable = true, remap = false) + public void onRenderFood(int width, int height, CallbackInfo ci){ + if (SkyblockHud.config.renderer.hideFood && SkyblockHud.hasSkyblockScoreboard()){ + ci.cancel(); + if (pre(FOOD)) return; + post(FOOD); + } + } + + private boolean pre(RenderGameOverlayEvent.ElementType type) + { + return MinecraftForge.EVENT_BUS.post(new RenderGameOverlayEvent.Pre(eventParent, type)); + } + private void post(RenderGameOverlayEvent.ElementType type) + { + MinecraftForge.EVENT_BUS.post(new RenderGameOverlayEvent.Post(eventParent, type)); + } +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/mixins/MixinNetHandlerPlayClient.java b/src/main/java/com/thatgravyboat/skyblockhud/mixins/MixinNetHandlerPlayClient.java new file mode 100644 index 0000000..679da20 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/mixins/MixinNetHandlerPlayClient.java @@ -0,0 +1,53 @@ +package com.thatgravyboat.skyblockhud.mixins; + +import net.minecraft.client.network.NetHandlerPlayClient; +import net.minecraft.network.play.server.S3EPacketTeams; +import net.minecraft.scoreboard.Scoreboard; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.LocalCapture; + +@Mixin(NetHandlerPlayClient.class) +public class MixinNetHandlerPlayClient { + + /* DISABLE UNTIL NEW SYSTEM + @Inject(method = "handleSetSlot", at = @At("HEAD")) + public void onHandleSetSlot(S2FPacketSetSlot packetIn, CallbackInfo ci){ + if (SkyblockHud.hasSkyblockScoreboard()) { + Minecraft mc = Minecraft.getMinecraft(); + PacketThreadUtil.checkThreadAndEnqueue(packetIn, mc.getNetHandler(), mc); + if (packetIn.func_149175_c() == 0) { + ItemStack stack = packetIn.func_149174_e(); + + if (stack != null && stack.hasTagCompound()) { + if (stack.getTagCompound().hasKey("ExtraAttributes")) { + NBTTagCompound extraAttributes = stack.getTagCompound().getCompoundTag("ExtraAttributes"); + String id = extraAttributes.getString("id"); + ItemStack slotStack = Minecraft.getMinecraft().thePlayer.inventoryContainer.getSlot(packetIn.func_149173_d()).getStack(); + int changeAmount = stack.stackSize - (slotStack == null ? 0 : slotStack.stackSize); + String eId = null; + int eLvl = -1; + if (extraAttributes.hasKey("enchantments")) { + NBTTagCompound enchantments = extraAttributes.getCompoundTag("enchantments"); + if (enchantments.getKeySet().size() == 1) { + for (String e : enchantments.getKeySet()) { eId = e; break; } + if (eId != null) eLvl = enchantments.getInteger(eId); + } + } + TrackerHandler.onItemAdded(id, changeAmount, eId, eLvl); + } + } + } + } + } + */ + + @Inject(method = "handleTeams", locals = LocalCapture.CAPTURE_FAILHARD, at = @At(value = "INVOKE", target = "Lnet/minecraft/network/play/server/S3EPacketTeams;getAction()I", ordinal = 0, shift = At.Shift.BEFORE), cancellable = true) + public void handleTeams(S3EPacketTeams packetIn, CallbackInfo ci, Scoreboard scoreboard){ + //This stops Hypixel from being stupid and spamming our logs because they dont have different ids for things. + if (scoreboard.getTeam(packetIn.getName()) != null && packetIn.getAction() == 0) ci.cancel(); + } + +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/overlay/DungeonOverlay.java b/src/main/java/com/thatgravyboat/skyblockhud/overlay/DungeonOverlay.java new file mode 100644 index 0000000..4a3b36f --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/overlay/DungeonOverlay.java @@ -0,0 +1,150 @@ +package com.thatgravyboat.skyblockhud.overlay; + +import com.thatgravyboat.skyblockhud.GuiTextures; +import com.thatgravyboat.skyblockhud.SkyblockHud; +import com.thatgravyboat.skyblockhud.SpecialColour; +import com.thatgravyboat.skyblockhud.Utils; +import com.thatgravyboat.skyblockhud.config.SBHConfig; +import com.thatgravyboat.skyblockhud.core.config.Position; +import com.thatgravyboat.skyblockhud.dungeons.Classes; +import com.thatgravyboat.skyblockhud.dungeons.DungeonHandler; +import com.thatgravyboat.skyblockhud.dungeons.DungeonPlayer; +import com.thatgravyboat.skyblockhud.handlers.BossbarHandler; +import com.thatgravyboat.skyblockhud.location.LocationHandler; +import com.thatgravyboat.skyblockhud.location.Locations; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.gui.Gui; +import net.minecraft.client.gui.ScaledResolution; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.entity.boss.BossStatus; +import net.minecraftforge.client.GuiIngameForge; +import net.minecraftforge.client.event.RenderGameOverlayEvent; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; + +public class DungeonOverlay extends Gui { + private static final FontRenderer font = Minecraft.getMinecraft().fontRendererObj; + private static boolean bossBarVisible = false; + + public void drawDungeonPlayer(String name, int health, boolean isDead, Classes dungeonClass, int x, int y) { + if (!SkyblockHud.config.dungeon.hideDeadDungeonPlayers || !isDead) { + GlStateManager.enableBlend(); + Minecraft mc = Minecraft.getMinecraft(); + mc.renderEngine.bindTexture(GuiTextures.dungeon); + + String healthString = isDead ? "DEAD" : Integer.toString(health); + GlStateManager.color(1.0F, 1.0F, 1.0F, (float) SkyblockHud.config.dungeon.dungeonPlayerOpacity / 100); + drawTexturedModalRect(x, y, 0, dungeonClass.getTextureY(), 120, 32); + GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); + drawString(font, name, x + 50, y + 6, 0xFFFFFF); + drawString(font, healthString, x + 50, y + font.FONT_HEIGHT + 9, 0xFF2B2B); + GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); + } + } + + public void drawDungeonClock(int width, int offset, Minecraft mc){ + GlStateManager.enableBlend(); + GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); + mc.renderEngine.bindTexture(GuiTextures.overlay); + int dungeonTime = DungeonHandler.getDungeonTime(); + int dungeonTimeMin = dungeonTime /60; + int dungeonTimeSec = dungeonTime - dungeonTimeMin * 60; + drawTexturedModalRect((width/ 2) - 17, offset + (bossBarVisible ? 17 : 0), 0, 0, 34, 34); + mc.renderEngine.bindTexture(GuiTextures.dungeon); + drawTexturedModalRect((width/ 2) - 7, offset + (bossBarVisible ? 20 : 3), 16, 50, 3, 8); + drawTexturedModalRect((width/ 2) - 7, offset + (bossBarVisible ? 30 : 13), 19, 50, 3, 8); + String dungeonTimeElapsed = (dungeonTimeMin > 9 ? String.valueOf(dungeonTimeMin) : "0" + dungeonTimeMin) + ":" + (dungeonTimeSec > 9 ? String.valueOf(dungeonTimeSec) : "0" + dungeonTimeSec); + drawCenteredString(font, dungeonTimeElapsed, (width/ 2), offset + (bossBarVisible ? 40 : 23), 0xFFFF55); + //KEYS + drawString(font, (DungeonHandler.hasBloodkey() ? "\u2714" : "x"), (width/ 2), offset + (bossBarVisible ? 19 : 2), (DungeonHandler.hasBloodkey() ? 0x55FF55 : 0xAA0000)); + drawString(font, DungeonHandler.getWitherKeys()+"x", (width/ 2), offset + (bossBarVisible ? 30 : 13), 0x555555); + //CLEARED PERCENTAGE + GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); + mc.renderEngine.bindTexture(GuiTextures.overlay); + int clearPercent = DungeonHandler.getDungeonCleared(); + String clearPercentage = "Dungeon Cleared: \u00A7" + (clearPercent <= 20 ? "4" : clearPercent <= 50 ? "6" : clearPercent <= 80 ? "e" : "a") + clearPercent + "%"; + drawTexturedModalRect((width / 2) + 17, offset + (bossBarVisible ? 20 : 3), 2, 34, font.getStringWidth(clearPercentage) + 3, 14); + drawTexturedModalRect(((width / 2) + 17) + font.getStringWidth(clearPercentage) + 3, offset + (bossBarVisible ? 20 : 3), 252, 34, 4, 14); + drawString(font, clearPercentage, (width / 2) + 18, offset + (bossBarVisible ? 23 : 6), 0xAAAAAA); + + //DEATHS + GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); + mc.renderEngine.bindTexture(GuiTextures.overlay); + int deaths = DungeonHandler.getDeaths(); + String deathText = "Deaths: " + deaths; + drawTexturedModalRect((width / 2) + 17, offset + (bossBarVisible ? 35 : 18), 2, 34, font.getStringWidth(deathText) + 3, 14); + drawTexturedModalRect(((width / 2) + 17) + font.getStringWidth(deathText) + 3, offset + (bossBarVisible ? 35 : 18), 252, 34, 4, 14); + drawString(font, deathText, (width / 2) + 18, offset + (bossBarVisible ? 38 : 21), 0xAAAAAA); + + //SECRETS + GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); + mc.renderEngine.bindTexture(GuiTextures.overlay); + int maxSecrets = DungeonHandler.getMaxSecrets(); + int secrets = DungeonHandler.getSecrets(); + int totalSecrets = DungeonHandler.getTotalSecrets(); + String secretsText = "Secrets: " + secrets + "/" + maxSecrets + " (" + totalSecrets + ")"; + drawTexturedModalRect((width/ 2) - 17 - (font.getStringWidth(secretsText)) - 4, offset + (bossBarVisible ? 20 : 3), 0, 34, 2, 14); + drawTexturedModalRect(((width/ 2) - 17 - (font.getStringWidth(secretsText))) - 2, offset + (bossBarVisible ? 20 : 3), 2, 34, font.getStringWidth(secretsText) + 2, 14); + drawString(font, secretsText, (width/ 2) - 17 - (font.getStringWidth(secretsText)) , offset + (bossBarVisible ? 23 : 6), 0xAAAAAA); + + //CRYPTS + GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); + mc.renderEngine.bindTexture(GuiTextures.overlay); + int crypts = DungeonHandler.getCrypts(); + String cryptText = "Crypts: " + crypts; + drawTexturedModalRect((width/ 2) - 17 - (font.getStringWidth(cryptText)) - 4, offset + (bossBarVisible ? 35 : 18), 0, 34, 2, 14); + drawTexturedModalRect(((width/ 2) - 17 - (font.getStringWidth(cryptText))) - 2, offset + (bossBarVisible ? 35 : 18), 2, 34, font.getStringWidth(cryptText) + 2, 14); + drawString(font, cryptText, (width/ 2) - 17 - (font.getStringWidth(cryptText)) , offset + (bossBarVisible ? 38 : 21), 0xAAAAAA); + } + + public void drawUltimateBar(Minecraft mc, ScaledResolution resolution){ + if (!SkyblockHud.config.dungeon.hideUltimateBar) { + float percentage = mc.thePlayer.experience; + SBHConfig.DungeonHud dungeonHud = SkyblockHud.config.dungeon; + Position position = dungeonHud.barPosition; + + int x = position.getAbsX(resolution, 182); + int y = position.getAbsY(resolution, 5); + + GenericOverlays.drawLargeBar(mc, + x - 91, y, + percentage, 0.999f, + SpecialColour.specialToChromaRGB(dungeonHud.barLoadColor), + SpecialColour.specialToChromaRGB(dungeonHud.barFullColor), + dungeonHud.barStyle); + } + } + + @SubscribeEvent + public void renderOverlay(RenderGameOverlayEvent.Post event) { + Minecraft mc = Minecraft.getMinecraft(); + if (Utils.overlayShouldRender(event.type, SkyblockHud.hasSkyblockScoreboard(), LocationHandler.getCurrentLocation().equals(Locations.CATACOMBS))) { + bossBarVisible = BossStatus.statusBarTime > 0 && GuiIngameForge.renderBossHealth && BossbarHandler.bossBarRendered; + GlStateManager.enableBlend(); + drawUltimateBar(mc, event.resolution); + + GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); + if (!SkyblockHud.config.dungeon.hideDungeonPlayers) { + int[] hardCodedPos = new int[]{5, 42, 79, 116}; + Position[] positions = new Position[]{SkyblockHud.config.dungeon.dungeonPlayer1, SkyblockHud.config.dungeon.dungeonPlayer2, SkyblockHud.config.dungeon.dungeonPlayer3, SkyblockHud.config.dungeon.dungeonPlayer4}; + for (int i = 0; i < Math.min(DungeonHandler.getDungeonPlayers().values().size(), 4); i++) { + DungeonPlayer player = (DungeonPlayer) DungeonHandler.getDungeonPlayers().values().toArray()[i]; + int posX; + int posY; + try { + posX = positions[i].getAbsX(event.resolution, 120); + } catch (ArrayIndexOutOfBoundsException ignored) { + posX = hardCodedPos[i]; + } + try { + posY = positions[i].getAbsY(event.resolution, 120); + } catch (ArrayIndexOutOfBoundsException ignored) { + posY = 0; + } + drawDungeonPlayer(player.getName(), player.getHealth(), player.isDead(), player.getDungeonClass(), posX, posY); + } + } + drawDungeonClock(event.resolution.getScaledWidth(), SkyblockHud.config.main.mainHudPos.getAbsY(event.resolution, 34), mc); + } + } +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/overlay/GenericOverlays.java b/src/main/java/com/thatgravyboat/skyblockhud/overlay/GenericOverlays.java new file mode 100644 index 0000000..d987c86 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/overlay/GenericOverlays.java @@ -0,0 +1,44 @@ +package com.thatgravyboat.skyblockhud.overlay; + +import com.thatgravyboat.skyblockhud.GuiTextures; +import com.thatgravyboat.skyblockhud.SkyblockHud; +import com.thatgravyboat.skyblockhud.core.util.render.RenderUtils; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Gui; +import net.minecraft.client.renderer.GlStateManager; + +import java.awt.Color; + + +public class GenericOverlays extends Gui { + + public static void drawLargeBar(Minecraft mc, int x, int y, float percentage, float max, int fullColor, int loadingColor, int barStyle){ + if (SkyblockHud.hasSkyblockScoreboard()) { + mc.renderEngine.bindTexture(GuiTextures.bars); + Color color = new Color(percentage == max ? fullColor : loadingColor); + + RenderUtils.drawTexturedModalRect(x, y, 0, 0, 182, 5); + GlStateManager.color(color.getRed() / 255f, color.getGreen() / 255f, color.getBlue() / 255f, color.getAlpha() / 255f); + RenderUtils.drawTexturedModalRect(x, y, 0, 30, 182, 5); + RenderUtils.drawTexturedModalRect(x, y, 0, 5, (int) (182 * percentage), 5); + if (barStyle != 0) { + RenderUtils.drawTexturedModalRect(x, y, 0, 5 + (barStyle * 5), 182, 5); + } + } + } + + public static void drawSmallBar(Minecraft mc, int x, int y, double percentage, double max, int fullColor, int loadingColor, int barStyle){ + if (SkyblockHud.hasSkyblockScoreboard()) { + mc.renderEngine.bindTexture(GuiTextures.bars); + Color color = new Color(percentage == max ? fullColor : loadingColor); + GlStateManager.enableBlend(); + RenderUtils.drawTexturedModalRect(x, y, 0, 35, 62, 5); + GlStateManager.color(color.getRed() / 255f, color.getGreen() / 255f, color.getBlue() / 255f, color.getAlpha() / 255f); + RenderUtils.drawTexturedModalRect(x, y, 0, 65, 62, 5); + RenderUtils.drawTexturedModalRect(x, y, 0, 40, (int) (62 * percentage), 5); + if (barStyle != 0) { + RenderUtils.drawTexturedModalRect(x, y, 0, 45 + (barStyle * 5), 62, 5); + } + } + } +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/overlay/OverlayHud.java b/src/main/java/com/thatgravyboat/skyblockhud/overlay/OverlayHud.java new file mode 100644 index 0000000..8cdd44c --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/overlay/OverlayHud.java @@ -0,0 +1,286 @@ +package com.thatgravyboat.skyblockhud.overlay; + +import com.thatgravyboat.skyblockhud.GuiTextures; +import com.thatgravyboat.skyblockhud.SkyblockHud; +import com.thatgravyboat.skyblockhud.Utils; +import com.thatgravyboat.skyblockhud.handlers.BossbarHandler; +import com.thatgravyboat.skyblockhud.handlers.CurrencyHandler; +import com.thatgravyboat.skyblockhud.handlers.SlayerHandler; +import com.thatgravyboat.skyblockhud.handlers.TimeHandler; +import com.thatgravyboat.skyblockhud.location.*; +import com.thatgravyboat.skyblockhud.seasons.SeasonDateHandler; +import com.thatgravyboat.skyblockhud.seasons.Season; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.gui.Gui; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.entity.boss.BossStatus; +import net.minecraft.util.EnumChatFormatting; +import net.minecraftforge.client.GuiIngameForge; +import net.minecraftforge.client.event.RenderGameOverlayEvent; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; + +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; +import java.util.Locale; + +public class OverlayHud extends Gui { + private static final FontRenderer font = Minecraft.getMinecraft().fontRendererObj; + + //STATS + private static boolean eventToggle; + + public static boolean bossBarVisible = false; + + public void drawClock(int width, int offset, Minecraft mc){ + GlStateManager.enableBlend(); + GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); + mc.renderEngine.bindTexture(GuiTextures.overlay); + //CLOCK + int timeMin = (int) (TimeHandler.time / 60); + int timeHour = timeMin / 60; + timeMin = timeMin - (timeHour * 60); + String militaryTime = timeHour + ":" + (timeMin == 0 ? timeMin + "0" : timeMin); + int time12Hour = timeHour >= 12 ? timeHour - 12 : timeHour; + String normalTime = (time12Hour == 0 ? "00" : String.valueOf(time12Hour)) + ":" + (timeMin == 0 ? "00" : timeMin) + (timeHour >= 12 ? "pm" : "am"); + + drawTexturedModalRect((width/ 2) - 17, offset + (bossBarVisible ? 17 : 0), 0, 0, 34, 34); + drawTexturedModalRect((width/ 2) - 4, offset + (bossBarVisible ? 24 : 7), (timeHour > 19 || timeHour < 4) ? 43 : 43 + 8, 0, 8, 8); + if (SkyblockHud.config.main.twelveHourClock) drawScaledString(0.8f, width/ 2, offset + (bossBarVisible ? 38 : 21), normalTime, (timeHour > 19 || timeHour < 4) ? 0xAFB8CC : 0xFFFF55); + else drawCenteredString(font, militaryTime, (width/ 2), offset + (bossBarVisible ? 38 : 21), (timeHour > 19 || timeHour < 4) ? 0xAFB8CC : 0xFFFF55); + + //PURSE + drawPurseAndBits(width, offset, mc); + + //SEASON/DATE + drawSeasonAndDate(width, offset, mc); + + //REDSTONE PERCENT + drawRedstone(width, offset, mc); + + // LOCATION + drawLocation(width, offset, mc); + + //EXTRA SLOT + if (LocationHandler.getCurrentLocation().equals(Locations.YOURISLAND)) { + if (IslandHandler.flightTime > 0) drawFlightDuration(width, offset, mc); + } + else if (LocationHandler.getCurrentLocation().getCategory().equals(LocationCategory.MUSHROOMDESERT)){ + drawTrapperOrPelts(width, offset, mc); + } + else if (LocationHandler.getCurrentLocation().getCategory().equals(LocationCategory.DWARVENMINES)) { + if (DwarvenMineHandler.currentEvent != DwarvenMineHandler.Event.NONE){ + drawDwarvenEvent(width, offset, mc); + }else { + drawMithril(width, offset, mc); + } + } + else if (LocationHandler.getCurrentLocation().getCategory().equals(LocationCategory.PARK) && ParkIslandHandler.isRaining()){ + if (LocationHandler.getCurrentLocation().equals(Locations.HOWLINGCAVE)){ + drawSlayer(width, offset, mc); + }else drawRainDuration(width, offset, mc); + }else if (SlayerHandler.isDoingSlayer){ + drawSlayer(width, offset, mc); + } + } + + public void drawSeasonAndDate(int width, int offset, Minecraft mc){ + if (SeasonDateHandler.getCurrentSeason() != Season.ERROR) { + GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); + if (mc.thePlayer.ticksExisted % 100 == 0 && eventToggle) eventToggle = false; + if (mc.thePlayer.ticksExisted % 600 == 0) eventToggle = true; + mc.renderEngine.bindTexture(GuiTextures.overlay); + String dateText = SeasonDateHandler.getFancySeasonAndDate(); + if (eventToggle && !SeasonDateHandler.getCurrentEvent().isEmpty() && !SeasonDateHandler.getCurrentEventTime().isEmpty()) dateText = SeasonDateHandler.getCurrentEvent().trim() + " " + SeasonDateHandler.getCurrentEventTime().trim(); + drawTexturedModalRect((width / 2) + 17, offset + (bossBarVisible ? 20 : 3), 2, 34, font.getStringWidth(dateText) + 9, 14); + drawTexturedModalRect(((width / 2) + 17) + font.getStringWidth(dateText) + 9, offset + (bossBarVisible ? 20 : 3), 252, 34, 4, 14); + drawTexturedModalRect(((width / 2) + 17) + font.getStringWidth(dateText) + 2, offset + (bossBarVisible ? 23 : 6), SeasonDateHandler.getCurrentSeason().getTextureX(), 16, 8, 8); + drawString(font, dateText, (width / 2) + 18, offset + (bossBarVisible ? 23 : 6), 0xffffff); + } + } + + public void drawLocation(int width, int offset, Minecraft mc){ + GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); + mc.renderEngine.bindTexture(GuiTextures.overlay); + drawTexturedModalRect((width/ 2) - 33 - (font.getStringWidth(LocationHandler.getCurrentLocation().getDisplayName())), offset + (bossBarVisible ? 20 : 3), 0, 34, 2, 14); + drawTexturedModalRect(((width/ 2) - 33 - (font.getStringWidth(LocationHandler.getCurrentLocation().getDisplayName()))) + 2, offset + (bossBarVisible ? 20 : 3), 2, 34, font.getStringWidth(LocationHandler.getCurrentLocation().getDisplayName()) + 14, 14); + drawTexturedModalRect(((width/ 2) - 33 - (font.getStringWidth(LocationHandler.getCurrentLocation().getDisplayName()))) + 4, offset + (bossBarVisible ? 23 : 6), LocationHandler.getCurrentLocation().getCategory().getTexturePos(), 8, 8, 8); + drawString(font, + LocationHandler.getCurrentLocation().getDisplayName(), + (width/ 2) - 19 - (font.getStringWidth(LocationHandler.getCurrentLocation().getDisplayName())) , + offset + (bossBarVisible ? 23 : 6), + 0xFFFFFF + ); + } + + public void drawRedstone(int width, int offset, Minecraft mc){ + GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); + mc.renderEngine.bindTexture(GuiTextures.overlay); + int redstoneColor = IslandHandler.redstone > 90 ? 0xFF0000 : IslandHandler.redstone > 75 ? 0xC45B00 : IslandHandler.redstone > 50 ? 0xFFFF55 : 0x55FF55; + if (IslandHandler.redstone > 0 && Utils.isPlayerHoldingRedstone(mc.thePlayer)) { + drawTexturedModalRect((width/ 2) - 15, offset + (bossBarVisible ? 51 : 34), 0, 48, 30, 18); + drawTexturedModalRect((width/ 2) - 4, offset + (bossBarVisible ? 51 : 34), 59, 0, 8, 8); + drawCenteredString(mc.fontRendererObj, IslandHandler.redstone+"%", (width/ 2), offset + (bossBarVisible ? 58 : 41), redstoneColor); + } + } + + public void drawPurseAndBits(int width, int offset, Minecraft mc){ + GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); + mc.renderEngine.bindTexture(GuiTextures.overlay); + int xPos = (width/ 2) + 17; + + //COINS + drawTexturedModalRect(xPos, offset + (bossBarVisible ? 35 : 18), 2, 34, font.getStringWidth(CurrencyHandler.getCoinsFormatted()) + 11, 14); + drawTexturedModalRect(xPos + 1, offset + (bossBarVisible ? 37 : 20), 34, 0, 8, 8); + drawString(font, CurrencyHandler.getCoinsFormatted(), xPos + 10, offset + (bossBarVisible ? 38 : 21), 0xFFAA00); + GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); + mc.renderEngine.bindTexture(GuiTextures.overlay); + xPos += font.getStringWidth(CurrencyHandler.getCoinsFormatted()) + 11; + + //BITS + if (CurrencyHandler.getBits() > 0) { + drawTexturedModalRect(xPos, offset + (bossBarVisible ? 35 : 18), 2, 34, font.getStringWidth(CurrencyHandler.getBitsFormatted()) + 11, 14); + drawTexturedModalRect(xPos + 1, offset + (bossBarVisible ? 37 : 20), 75, 0, 8, 8); + drawString(font, CurrencyHandler.getBitsFormatted(), xPos + 10, offset + (bossBarVisible ? 38 : 21), 0x55FFFF); + GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); + mc.renderEngine.bindTexture(GuiTextures.overlay); + xPos += font.getStringWidth(CurrencyHandler.getBitsFormatted()) + 11; + } + + drawTexturedModalRect(xPos, offset + (bossBarVisible ? 35 : 18), 252, 34, 4, 14); + } + + public void drawFlightDuration(int width, int offset, Minecraft mc ){ + if (LocationHandler.getCurrentLocation().equals(Locations.YOURISLAND)){ + GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); + DecimalFormat flightFormat = new DecimalFormat("#.#", DecimalFormatSymbols.getInstance(Locale.CANADA)); + String duration; + if (IslandHandler.flightTime < 60) duration = IslandHandler.flightTime + "s"; + else if (IslandHandler.flightTime < 3600) duration = flightFormat.format((double)IslandHandler.flightTime / 60) + "m"; + else if (IslandHandler.flightTime < 86400) duration = flightFormat.format((double)IslandHandler.flightTime / 3600) + "hr"; + else if (IslandHandler.flightTime < 86460) duration = flightFormat.format((double)IslandHandler.flightTime / 86400) + "day"; + else duration = flightFormat.format((double)IslandHandler.flightTime / 86400) + "days"; + mc.renderEngine.bindTexture(GuiTextures.overlay); + drawTexturedModalRect((width/ 2) - 33 - (font.getStringWidth(duration)), offset + (bossBarVisible ? 35 : 18), 0, 34, 2, 14); + drawTexturedModalRect(((width/ 2) - 33 - (font.getStringWidth(duration))) + 2, offset + (bossBarVisible ? 35 : 18), 2, 34, font.getStringWidth(duration) + 14, 14); + drawTexturedModalRect(((width/ 2) - 33 - (font.getStringWidth(duration))) + 4, offset + (bossBarVisible ? 38 : 21), 67, 0, 8, 8); + drawString(font, duration, (width/ 2) - 19 - (font.getStringWidth(duration)) , offset + (bossBarVisible ? 38 : 21), 0xFFFFFF); + } + } + + public void drawRainDuration(int width, int offset, Minecraft mc ){ + if (LocationHandler.getCurrentLocation().getCategory().equals(LocationCategory.PARK)){ + GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); + mc.renderEngine.bindTexture(GuiTextures.overlay); + String duration = "Rain: " + ParkIslandHandler.getRainTime(); + drawTexturedModalRect((width/ 2) - 33 - (font.getStringWidth(duration)), offset + (bossBarVisible ? 35 : 18), 0, 34, 2, 14); + drawTexturedModalRect(((width/ 2) - 33 - (font.getStringWidth(duration))) + 2, offset + (bossBarVisible ? 35 : 18), 2, 34, font.getStringWidth(duration) + 14, 14); + drawTexturedModalRect(((width/ 2) - 33 - (font.getStringWidth(duration))) + 4, offset + (bossBarVisible ? 38 : 21), 83, 0, 8, 8); + drawString(font, duration, (width/ 2) - 19 - (font.getStringWidth(duration)) , offset + (bossBarVisible ? 38 : 21), 0xFFFFFF); + } + } + + public void drawSlayer(int width, int offset, Minecraft mc){ + if (SlayerHandler.isDoingSlayer){ + int kills = SlayerHandler.progress; + int maxKills = SlayerHandler.maxKills; + int tier = SlayerHandler.slayerTier; + SlayerHandler.slayerTypes slayerType = SlayerHandler.currentSlayer; + if (slayerType != SlayerHandler.slayerTypes.NONE) { + GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); + mc.renderEngine.bindTexture(GuiTextures.overlay); + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append(EnumChatFormatting.GREEN); + stringBuilder.append(Utils.intToRomanNumeral(tier)); + stringBuilder.append(" "); + if (SlayerHandler.isKillingBoss){ + stringBuilder.append(EnumChatFormatting.RED); + stringBuilder.append("Slay Boss!"); + } else if (SlayerHandler.bossSlain){ + stringBuilder.append(EnumChatFormatting.RED); + stringBuilder.append("Boss Slain!"); + } else if (kills == 0 && maxKills == 0){ + stringBuilder.append(EnumChatFormatting.RED); + stringBuilder.append("Not Slaying!"); + } else { + stringBuilder.append(EnumChatFormatting.YELLOW); + stringBuilder.append(kills); + stringBuilder.append(EnumChatFormatting.GRAY); + stringBuilder.append("/"); + stringBuilder.append(EnumChatFormatting.RED); + stringBuilder.append(maxKills); + } + String text = stringBuilder.toString(); + drawTexturedModalRect((width / 2) - 33 - (font.getStringWidth(text)), offset + (bossBarVisible ? 35 : 18), 0, 34, 2, 14); + drawTexturedModalRect(((width / 2) - 33 - (font.getStringWidth(text))) + 2, offset + (bossBarVisible ? 35 : 18), 2, 34, font.getStringWidth(text) + 14, 14); + drawTexturedModalRect(((width / 2) - 33 - (font.getStringWidth(text))) + 4, offset + (bossBarVisible ? 38 : 21), slayerType.getX(), 24, 8, 8); + drawString(font, text, (width / 2) - 19 - (font.getStringWidth(text)), offset + (bossBarVisible ? 38 : 21), 0xFFFFFF); + + } + } + } + + public void drawMithril(int width, int offset, Minecraft mc){ + if (LocationHandler.getCurrentLocation().getCategory().equals(LocationCategory.DWARVENMINES)){ + GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); + mc.renderEngine.bindTexture(GuiTextures.overlay); + String mithril = DwarvenMineHandler.getMithrilFormatted(); + drawTexturedModalRect((width/ 2) - 33 - (font.getStringWidth(mithril)), offset + (bossBarVisible ? 35 : 18), 0, 34, 2, 14); + drawTexturedModalRect(((width/ 2) - 33 - (font.getStringWidth(mithril))) + 2, offset + (bossBarVisible ? 35 : 18), 2, 34, font.getStringWidth(mithril) + 14, 14); + drawTexturedModalRect(((width/ 2) - 33 - (font.getStringWidth(mithril))) + 4, offset + (bossBarVisible ? 38 : 21), 91, 0, 8, 8); + drawString(font, mithril, (width/ 2) - 19 - (font.getStringWidth(mithril)) , offset + (bossBarVisible ? 38 : 21), 0x00C896); + } + } + + public void drawTrapperOrPelts(int width, int offset, Minecraft mc){ + if (LocationHandler.getCurrentLocation().getCategory().equals(LocationCategory.MUSHROOMDESERT)){ + GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); + mc.renderEngine.bindTexture(GuiTextures.overlay); + String duration = FarmingIslandHandler.location != Locations.NONE ? FarmingIslandHandler.location.getDisplayName() : ""+FarmingIslandHandler.pelts; + drawTexturedModalRect((width/ 2) - 33 - (font.getStringWidth(duration)), offset + (bossBarVisible ? 35 : 18), 0, 34, 2, 14); + drawTexturedModalRect(((width/ 2) - 33 - (font.getStringWidth(duration))) + 2, offset + (bossBarVisible ? 35 : 18), 2, 34, font.getStringWidth(duration) + 14, 14); + drawTexturedModalRect(((width/ 2) - 33 - (font.getStringWidth(duration))) + 4, offset + (bossBarVisible ? 38 : 21), FarmingIslandHandler.location != Locations.NONE ? 123 : 115, 0, 8, 8); + drawString(font, duration, (width/ 2) - 19 - (font.getStringWidth(duration)) , offset + (bossBarVisible ? 38 : 21), 0xFFFFFF); + } + } + + public void drawDwarvenEvent(int width, int offset, Minecraft mc){ + if (LocationHandler.getCurrentLocation().getCategory().equals(LocationCategory.DWARVENMINES)){ + GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); + mc.renderEngine.bindTexture(GuiTextures.overlay); + if (DwarvenMineHandler.eventMax > 0) { + String duration = DwarvenMineHandler.eventProgress + "/" + DwarvenMineHandler.eventMax; + drawTexturedModalRect((width / 2) - 33 - (font.getStringWidth(duration)), offset + (bossBarVisible ? 35 : 18), 0, 34, 2, 14); + drawTexturedModalRect(((width / 2) - 33 - (font.getStringWidth(duration))) + 2, offset + (bossBarVisible ? 35 : 18), 2, 34, font.getStringWidth(duration) + 14, 14); + drawTexturedModalRect(((width / 2) - 33 - (font.getStringWidth(duration))) + 4, offset + (bossBarVisible ? 38 : 21), DwarvenMineHandler.currentEvent.x, 0, 8, 8); + drawString(font, duration, (width / 2) - 19 - (font.getStringWidth(duration)), offset + (bossBarVisible ? 38 : 21), 0xFFFFFF); + }else { + String text = DwarvenMineHandler.currentEvent.displayName; + drawTexturedModalRect((width / 2) - 33 - (font.getStringWidth(text)), offset + (bossBarVisible ? 35 : 18), 0, 34, 2, 14); + drawTexturedModalRect(((width / 2) - 33 - (font.getStringWidth(text))) + 2, offset + (bossBarVisible ? 35 : 18), 2, 34, font.getStringWidth(text) + 14, 14); + drawTexturedModalRect(((width / 2) - 33 - (font.getStringWidth(text))) + 4, offset + (bossBarVisible ? 38 : 21), DwarvenMineHandler.currentEvent.x, 0, 8, 8); + drawString(font, text, (width / 2) - 19 - (font.getStringWidth(text)), offset + (bossBarVisible ? 38 : 21), 0xFFFFFF); + } + } + } + + @SubscribeEvent + public void renderOverlay(RenderGameOverlayEvent.Post event) { + if (Utils.overlayShouldRender(event.type, SkyblockHud.hasSkyblockScoreboard())) { + bossBarVisible = BossStatus.statusBarTime > 0 && GuiIngameForge.renderBossHealth && BossbarHandler.bossBarRendered; + Minecraft mc = Minecraft.getMinecraft(); + GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); + if (LocationHandler.getCurrentLocation() != Locations.CATACOMBS){ + drawClock(event.resolution.getScaledWidth(), SkyblockHud.config.main.mainHudPos.getAbsY(event.resolution, 34), mc); + } + GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); + } + } + + + public void drawScaledString(float factor, int x, int y, String text, int color){ + GlStateManager.scale(factor, factor, 1); + drawCenteredString(font, text, (int)(x/factor), (int)(y/factor), color); + GlStateManager.scale(1/factor, 1/factor, 1); + } +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/overlay/RPGHud.java b/src/main/java/com/thatgravyboat/skyblockhud/overlay/RPGHud.java new file mode 100644 index 0000000..06cf94a --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/overlay/RPGHud.java @@ -0,0 +1,102 @@ +package com.thatgravyboat.skyblockhud.overlay; + +import com.mojang.realmsclient.gui.ChatFormatting; +import com.thatgravyboat.skyblockhud.GuiTextures; +import com.thatgravyboat.skyblockhud.SkyblockHud; +import com.thatgravyboat.skyblockhud.Utils; +import com.thatgravyboat.skyblockhud.core.config.Position; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.gui.Gui; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraftforge.client.event.RenderGameOverlayEvent; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; + +import java.text.DecimalFormat; +import java.text.NumberFormat; + +public class RPGHud extends Gui { + private static int mana, maxMana, overflow = 0; + private static int health, maxHealth = 0; + private static int defense = 0; + + public static void updateMana(int current, int max){ + mana = current; + maxMana = max; + } + + public static void updateOverflow(int current){ + overflow = current; + } + + public static void updateHealth(int current, int max){ + health = current; + maxHealth = max; + } + public static void updateDefense(int input){ defense = input; } + + public static void manaPredictionUpdate(boolean isIncrease, int decrease){ + mana = isIncrease ? Math.min(mana + (maxMana / 50), maxMana) : mana - decrease; + } + + private static final DecimalFormat decimalFormat = new DecimalFormat("#.##"); + + static { + decimalFormat.setGroupingUsed(true); + decimalFormat.setGroupingSize(3); + } + + @SubscribeEvent + public void renderOverlay(RenderGameOverlayEvent.Post event) { + if (Utils.overlayShouldRender(event.type, SkyblockHud.hasSkyblockScoreboard(), SkyblockHud.config.renderer.hideXpBar)) + MinecraftForge.EVENT_BUS.post(new RenderGameOverlayEvent.Post(new RenderGameOverlayEvent(event.partialTicks, event.resolution), RenderGameOverlayEvent.ElementType.EXPERIENCE)); + if (Utils.overlayShouldRender(event.type, SkyblockHud.hasSkyblockScoreboard(), SkyblockHud.config.rpg.showRpgHud)) { + Minecraft mc = Minecraft.getMinecraft(); + GlStateManager.enableBlend(); + GlStateManager.color(1.0f,1.0f,1.0f,1.0f); + FontRenderer font = mc.fontRendererObj; + if (mc.thePlayer.getHealth() < mc.thePlayer.getMaxHealth()){ + health = Math.max((int) (maxHealth * (mc.thePlayer.getHealth() / mc.thePlayer.getMaxHealth())), health); + } + + mc.renderEngine.bindTexture(GuiTextures.playerStat); + Position position = SkyblockHud.config.rpg.rpgHudPosition; + + int x = position.getAbsX(event.resolution, 120); + int y = position.getAbsY(event.resolution, 47); + + boolean rightAligned = position.rightAligned(event.resolution, 120); + + drawTexturedModalRect(x,y,rightAligned ? 131 : 5,6,120,47); + float manaWidth = Math.min(57 * ((float)mana/(float)maxMana), 57); + drawTexturedModalRect(rightAligned ? x + 16 : 47 + x,17 + y,rightAligned ? 199 : 0,64,(int)manaWidth,4); + float healthWidth = Math.min(70 * ((float)health/(float)maxHealth), 70); + drawTexturedModalRect(rightAligned ? x + 3 : 47+ x,22+ y,rightAligned ? 186 : 0,68,(int)healthWidth,5); + + if (health > maxHealth) { + float absorptionWidth = Math.min(70 * ((float) (health - maxHealth) / (float) maxHealth), 70); + drawTexturedModalRect(rightAligned ? x + 3 : 47 + x, 22 + y, rightAligned ? 186 : 0, 77, (int) absorptionWidth, 5); + } + + float xpWidth = 67 * mc.thePlayer.experience; + drawTexturedModalRect(rightAligned ? x + 7 : 45+ x,28+ y,rightAligned ? 189 : 0,73,(int)xpWidth,4); + //Air in water + NumberFormat myFormat = NumberFormat.getInstance(); + myFormat.setGroupingUsed(true); + if (mc.thePlayer.getAir() < 300){ + float airWidth = 60 * ((float)mc.thePlayer.getAir() / 300); + drawTexturedModalRect(rightAligned ? x + 17 : 39 + x,33+ y,rightAligned ? 192 : 0,82,64,6); + drawTexturedModalRect(rightAligned ? x + 19 : 41+ x,33+ y,rightAligned ? 196 : 0,88,(int)airWidth,4); + } + GlStateManager.scale(0.75f, 0.75f, 1); + drawCenteredString(mc.fontRendererObj, ""+mc.thePlayer.experienceLevel, (rightAligned ? 130 : 0) + (int)(15+ x/0.75f), (int)(45+ y/0.75f), 8453920); + GlStateManager.scale(1/0.75f, 1/0.75f, 1); + GlStateManager.scale(0.75f, 0.75f, 1); + font.drawString( ChatFormatting.RED + " \u2764 " + health +"/"+maxHealth,(rightAligned ? -40 : 0) + (int)(64+ x/0.75f), (int)(8+ y/0.75f), 0xffffff, false); + GlStateManager.scale(1/0.75f, 1/0.75f, 1); + GlStateManager.color(255,255,255); + GlStateManager.disableBlend(); + } + } +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/playerstats/ActionBarParsing.java b/src/main/java/com/thatgravyboat/skyblockhud/playerstats/ActionBarParsing.java new file mode 100644 index 0000000..b287ad6 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/playerstats/ActionBarParsing.java @@ -0,0 +1,131 @@ +package com.thatgravyboat.skyblockhud.playerstats; + +import com.thatgravyboat.skyblockhud.SkyblockHud; +import com.thatgravyboat.skyblockhud.Utils; +import com.thatgravyboat.skyblockhud.overlay.RPGHud; +import net.minecraft.util.ChatComponentText; +import net.minecraft.util.IChatComponent; +import net.minecraftforge.client.event.ClientChatReceivedEvent; +import net.minecraftforge.fml.common.eventhandler.EventPriority; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.common.gameevent.TickEvent; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class ActionBarParsing { + + private static String lastActionBar = ""; + private static String lastLowActionBar = ""; + private static IChatComponent lastLowEditedActionBar = null; + + private static final Pattern HealthRegex = Pattern.compile("([0-9]+)/([0-9]+)\u2764"); + private static final Pattern HealingRegex = Pattern.compile("\\+([0-9]+)[\u2586\u2585\u2584\u2583\u2582\u2581]"); + private static final Pattern DefenseRegex = Pattern.compile("([0-9]+)\u2748 Defense"); + private static final Pattern ManaRegex = Pattern.compile("([0-9]+)/([0-9]+)\u270E Mana"); + private static final Pattern ManaOverflowRegex = Pattern.compile("([0-9]+)/([0-9]+)\u270E ([0-9]+)\u02AC"); + private static final Pattern ManaDecreaseRegex = Pattern.compile("-([0-9]+) Mana \\("); + private static final Pattern XpGainRegex = Pattern.compile("\\+(\\d*\\.?\\d*) (Farming|Mining|Combat|Foraging|Fishing|Enchanting|Alchemy|Carpentry|Runecrafting) \\((\\d*\\.?\\d*)%\\)"); + + private static final Pattern HealthReplaceRegex = Pattern.compile("\u00A7c([0-9]+)/([0-9]+)\u2764"); + private static final Pattern HealingReplaceRegex = Pattern.compile("\\+\u00A7c([0-9]+)[\u2586\u2585\u2584\u2583\u2582\u2581]"); + private static final Pattern HealthAbsorptionReplaceRegex = Pattern.compile("\u00A76([0-9]+)/([0-9]+)\u2764"); + private static final Pattern DefenseReplaceRegex = Pattern.compile("\u00A7a([0-9]+)\u00A7a\u2748 Defense"); + private static final Pattern ManaReplaceRegex = Pattern.compile("\u00A7b([0-9]+)/([0-9]+)\u270E Mana"); + private static final Pattern ManaOverflowReplaceRegex = Pattern.compile("\u00A7b([0-9]+)/([0-9]+)\u270E \u00A73([0-9]+)\u02AC"); + + private static int ticksSinceLastPrediction = 0; + private static boolean predict = false; + + @SubscribeEvent + public void tick(TickEvent.ClientTickEvent event){ + if (predict) { + ticksSinceLastPrediction++; + if (ticksSinceLastPrediction == 20 && SkyblockHud.config.rpg.showRpgHud) { + ticksSinceLastPrediction = 0; + RPGHud.manaPredictionUpdate(true, 0); + } + } + } + + @SubscribeEvent(priority = EventPriority.HIGHEST) + public void onStatusBarHigh(ClientChatReceivedEvent event){ + if (event.type == 2 && SkyblockHud.hasSkyblockScoreboard() && SkyblockHud.config.rpg.showRpgHud){ + parseActionBar(event.message.getUnformattedText()); + } + } + + + @SubscribeEvent(priority = EventPriority.LOW) + public void onStatusBarLow(ClientChatReceivedEvent event){ + if (event.type == 2 && SkyblockHud.hasSkyblockScoreboard() && SkyblockHud.config.rpg.showRpgHud){ + String message = event.message.getUnformattedText(); + if (lastLowEditedActionBar == null || !lastLowActionBar.equals(message)){ + lastLowActionBar = message; + message = HealthReplaceRegex.matcher(message).replaceAll(""); + message = HealthAbsorptionReplaceRegex.matcher(message).replaceAll(""); + message = DefenseReplaceRegex.matcher(message).replaceAll(""); + message = ManaReplaceRegex.matcher(message).replaceAll(""); + message = ManaOverflowReplaceRegex.matcher(message).replaceAll(""); + + lastLowEditedActionBar = new ChatComponentText(message.trim()); + } + event.message = lastLowEditedActionBar; + } + } + + public static void parseActionBar(String input){ + if (!lastActionBar.equals(input)) { + lastActionBar = input; + String bar = Utils.removeColor(input); + + Matcher HealthMatcher = HealthRegex.matcher(bar); + Matcher DefenseMatcher = DefenseRegex.matcher(bar); + Matcher ManaMatcher = ManaRegex.matcher(bar); + Matcher ManaUseMatcher = ManaDecreaseRegex.matcher(bar); + Matcher ManaOverflowMatcher = ManaOverflowRegex.matcher(bar); + Matcher XpGainMatcher = XpGainRegex.matcher(bar); + + boolean healthFound = HealthMatcher.find(); + boolean defenseFound = DefenseMatcher.find(); + boolean manaFound = ManaMatcher.find(); + boolean manaUseFound = ManaUseMatcher.find(); + boolean manaOverflowFound = ManaOverflowMatcher.find(); + boolean xpFound = XpGainMatcher.find(); + + + if (healthFound) { + try { + RPGHud.updateHealth(Integer.parseInt(HealthMatcher.group(1)), Integer.parseInt(HealthMatcher.group(2))); + }catch (Exception ignored){} + } + if (defenseFound) { + try { + RPGHud.updateDefense(Integer.parseInt(DefenseMatcher.group(1))); + }catch (Exception ignored){} + }else if (!xpFound && !manaUseFound){ + RPGHud.updateDefense(0); + } + if (manaFound) { + try { + RPGHud.updateMana(Integer.parseInt(ManaMatcher.group(1)), Integer.parseInt(ManaMatcher.group(2))); + }catch (Exception ignored){} + } + if (!manaFound && manaOverflowFound){ + try { + RPGHud.updateMana(Integer.parseInt(ManaOverflowMatcher.group(1)), Integer.parseInt(ManaOverflowMatcher.group(2))); + RPGHud.updateOverflow(Integer.parseInt(ManaOverflowMatcher.group(3))); + }catch (Exception ignored){} + } + if (!manaFound){ + if (manaUseFound) { + try { + RPGHud.manaPredictionUpdate(false, Integer.parseInt(ManaUseMatcher.group(1))); + } catch (Exception ignored) {} + } + RPGHud.manaPredictionUpdate(true, 0); + } + predict = !manaFound; + } + } +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/seasons/Season.java b/src/main/java/com/thatgravyboat/skyblockhud/seasons/Season.java new file mode 100644 index 0000000..e55c0fa --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/seasons/Season.java @@ -0,0 +1,50 @@ +package com.thatgravyboat.skyblockhud.seasons; + +public enum Season { + EARLYSPRING("earlyspring", "Early Spring", 34, 0), + SPRING("spring", "Spring", 34, 31), + LATESPRING("latespring", "Late Spring", 34, 62), + EARLYSUMMER("earlysummer", "Early Summer", 42, 93), + SUMMER("summer", "Summer", 42, 124), + LATESUMMER("latesummer", "Late Summer", 42, 155), + EARLYAUTUMN("earlyautumn", "Early Autumn", 50, 186), + AUTUMN("autumn", "Autumn", 50, 217), + LATEAUTUMN("lateautumn", "Late Autumn", 50, 248), + EARLYWINTER("earlywinter", "Early Winter", 58, 279), + WINTER("winter", "Winter", 58, 310), + LATEWINTER("latewinter", "Late Winter", 58, 341), + ERROR("error", "Error", 0, -1); + + + + + private final String name; + private final String displayName; + private final int textureX; + private final int yearStartDay; + + Season(String name, String displayName, int textureX, int yearStartDay){ + this.name = name; + this.displayName = displayName; + this.textureX = textureX; + this.yearStartDay = yearStartDay; + } + + public String getName(){ + return this.name; + } + public String getDisplayName(){ + return this.displayName; + } + public int getTextureX() { return this.textureX; } + public int getYearStartDay() { return yearStartDay; } + + public static Season get(String id) { + try { + return Season.valueOf(id); + } catch (IllegalArgumentException ex) { + return ERROR; + } + } + +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/seasons/SeasonDateHandler.java b/src/main/java/com/thatgravyboat/skyblockhud/seasons/SeasonDateHandler.java new file mode 100644 index 0000000..1e22afc --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/seasons/SeasonDateHandler.java @@ -0,0 +1,57 @@ +package com.thatgravyboat.skyblockhud.seasons; + +import com.thatgravyboat.skyblockhud.Utils; +import com.thatgravyboat.skyblockhud.api.events.SidebarLineUpdateEvent; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; + +import java.util.regex.Pattern; + +public class SeasonDateHandler { + + private static Season currentSeason = Season.ERROR; + private static int currentDate = 1; + private static String currentEvent = ""; + private static String eventTime = ""; + + + @SubscribeEvent + public void onSidebarLineUpdate(SidebarLineUpdateEvent event){ + if (Season.get(SeasonDateHandler.removeDate(event.formattedLine.toLowerCase()).toUpperCase()) != Season.ERROR) { + SeasonDateHandler.setCurrentDateAndSeason(SeasonDateHandler.removeSeason(Utils.removeColor(event.formattedLine.toLowerCase().trim())), SeasonDateHandler.removeDate(Utils.removeColor(event.formattedLine.toLowerCase().trim())).toUpperCase()); + } + } + + public static void setCurrentDateAndSeason(int date, String season){ + currentDate = date; + currentSeason = Season.get(season); + } + public static void setCurrentEvent(String event, String time){ + currentEvent = event; + eventTime = time; + } + + + public static Season getCurrentSeason(){ return currentSeason; } + public static int getCurrentDate(){ return currentDate; } + private static String getDataSuffix(int date) { + if (date > 10 && date < 14) return "th"; + switch (date % 10){ + case 1: return "st"; + case 2: return "nd"; + case 3: return "rd"; + default: return "th"; + } + } + + public static String getFancySeasonAndDate(){ return currentSeason.getDisplayName() + " " + currentDate + getDataSuffix(currentDate); } + public static String getCurrentEvent() { return currentEvent; } + public static String getCurrentEventTime() { return eventTime; } + + public static String removeDate(String seasonDate){ + return Pattern.compile("[^a-zA-Z]").matcher(seasonDate.toLowerCase()).replaceAll("").replaceAll("st|nd|rd|th", "").trim(); + } + + public static int removeSeason(String seasonDate){ + return Integer.parseInt(Pattern.compile("[^0-9]").matcher(seasonDate.toLowerCase()).replaceAll("").trim()); + } +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/tracker/KillTrackerHandler.java b/src/main/java/com/thatgravyboat/skyblockhud/tracker/KillTrackerHandler.java new file mode 100644 index 0000000..6734283 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/tracker/KillTrackerHandler.java @@ -0,0 +1,76 @@ +package com.thatgravyboat.skyblockhud.tracker; + +import net.minecraft.client.Minecraft; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.DamageSource; +import net.minecraftforge.event.entity.EntityJoinWorldEvent; +import net.minecraftforge.event.entity.living.LivingDeathEvent; +import net.minecraftforge.event.entity.player.AttackEntityEvent; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + +public class KillTrackerHandler { + + public static final Set<UUID> attackedEntities = new HashSet<>(); + + @SubscribeEvent + public void onAttack(AttackEntityEvent event){ + if (event.target != null) { + attackedEntities.add(event.target.getUniqueID()); + } + } + + @SubscribeEvent + public void onDeath(LivingDeathEvent event){ + + if (false) { + //Used for testing + System.out.println("----------------------------------------------------------------------------------------------------------------"); + System.out.println("Name : " + event.entity.getName()); + System.out.println("UUID : " + event.entity.getUniqueID()); + NBTTagCompound tag = new NBTTagCompound(); + event.entity.writeToNBT(tag); + System.out.println("Tag : " + tag); + System.out.println("Damage : " + getDamageSourceString(event.source)); + System.out.println("----------------------------------------------------------------------------------------------------------------"); + } + + attackedEntities.remove(event.entity.getUniqueID()); + } + + public static String getDamageSourceString(DamageSource source){ + return "{ " + + source.getDamageType() + + ", " + + source.isDamageAbsolute() + + ", " + + source.isDifficultyScaled() + + ", " + + source.isFireDamage() + + ", " + + source.isProjectile() + + ", " + + source.isUnblockable() + + ", " + + source.isExplosion() + + ", " + + source.isMagicDamage() + + ", " + + source.isCreativePlayer() + + ", " + + source.getSourceOfDamage() + + " }"; + } + + @SubscribeEvent + public void onWorldChange(EntityJoinWorldEvent event){ + if (event.entity != null) { + if (event.entity.getUniqueID().equals(Minecraft.getMinecraft().thePlayer.getUniqueID())) { + attackedEntities.clear(); + } + } + } +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/tracker/TrackerFileLoader.java b/src/main/java/com/thatgravyboat/skyblockhud/tracker/TrackerFileLoader.java new file mode 100644 index 0000000..d7f7512 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/tracker/TrackerFileLoader.java @@ -0,0 +1,171 @@ +package com.thatgravyboat.skyblockhud.tracker; + +import com.google.gson.*; +import com.thatgravyboat.skyblockhud.location.Locations; +import net.minecraft.client.Minecraft; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTBase; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; +import net.minecraft.util.ResourceLocation; + +import java.io.*; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class TrackerFileLoader { + + private static final Gson gson = new GsonBuilder().create(); + + public static ItemStack getDisplayItem(JsonObject jsonObject){ + int meta = jsonObject.get("meta").getAsInt(); + String displayItemId = jsonObject.get("item").getAsString(); + Item item = Item.itemRegistry.getObject(new ResourceLocation(displayItemId)); + ItemStack stack = new ItemStack(item, 0, meta); + if (jsonObject.has("skullData") && displayItemId.equals("minecraft:skull") && meta == 3){ + stack.setTagInfo("SkullOwner",getSkullTag(jsonObject.getAsJsonObject("skullData"))); + } + if (jsonObject.has("enchanted") && jsonObject.get("enchanted").getAsBoolean()) stack.setTagInfo("ench", new NBTTagList()); + return stack; + } + + public static NBTBase getSkullTag(JsonObject skullObject){ + NBTTagCompound skullOwner = new NBTTagCompound(); + NBTTagCompound properties = new NBTTagCompound(); + NBTTagList textures = new NBTTagList(); + NBTTagCompound value = new NBTTagCompound(); + + skullOwner.setString("Id", skullObject.get("id").getAsString()); + + value.setString("Value", skullObject.get("texture").getAsString()); + textures.appendTag(value); + + properties.setTag("textures",textures); + + skullOwner.setTag("Properties", properties); + return skullOwner; + } + + private static void loadTrackers(JsonObject object){ + for (JsonElement element : object.get("trackers").getAsJsonArray()) { + JsonObject tracker = element.getAsJsonObject(); + StringBuilder builder = new StringBuilder(); + tracker.get("location").getAsJsonArray().forEach(loc -> builder.append(loc.getAsString())); + String location = builder.toString(); + + + Map<String, ItemStack> stacks = new HashMap<>(); + for (JsonElement drop :tracker.get("drops").getAsJsonArray()) { + JsonObject dropObject = drop.getAsJsonObject(); + + //Display Item Creation + ItemStack stack = getDisplayItem(dropObject.getAsJsonObject("displayItem")); + String itemId = dropObject.get("id").getAsString(); + + stacks.put(itemId, stack); + } + + String event = tracker.has("event") ? tracker.get("event").getAsString() : null; + + Map<String, Map<String, ItemStack>> events = new HashMap<>(); + events.put(event, stacks); + + if (TrackerHandler.trackers.containsKey(location)){ + TrackerHandler.trackers.get(location).dropTrackers.put(event, stacks); + }else { + TrackerHandler.trackers.putIfAbsent(location, new TrackerHandler.TrackerData(events)); + } + + tracker.get("location").getAsJsonArray().forEach(loc -> TrackerHandler.trackerIds.put(Locations.get(loc.getAsString()), location)); + } + } + + private static JsonElement getTrackerFile(){ + List<JsonObject> trackerStats = new ArrayList<>(); + TrackerHandler.trackers.forEach((locations, trackerData) -> + trackerData.dropTrackers.forEach((event, drops) -> { + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty("location", locations); + + if (event == null) jsonObject.add("event", new JsonNull()); + else jsonObject.addProperty("event", event); + + JsonObject dropsData = new JsonObject(); + drops.forEach((s, stack) -> dropsData.addProperty(s, stack.stackSize)); + jsonObject.add("drops", dropsData); + trackerStats.add(jsonObject); + } + )); + JsonArray stats = new JsonArray(); + trackerStats.forEach(stats::add); + return stats; + } + + public static void loadTrackersFile(){ + try { + ResourceLocation trackers = new ResourceLocation("skyblockhud:data/trackers.json"); + InputStream is = Minecraft.getMinecraft().getResourceManager().getResource(trackers).getInputStream(); + + try (BufferedReader reader = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8))) { + loadTrackers(gson.fromJson(reader, JsonObject.class)); + } + }catch (Exception ignored){} + } + + public static boolean loadTrackerStatsFile(File configDirectory){ + File configFile = new File(configDirectory, "sbh-trackers-stats.json"); + + try { + if (configFile.createNewFile()){ + return true; + } + + try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(configFile), StandardCharsets.UTF_8))) { + JsonObject json = gson.fromJson(reader, JsonObject.class); + if (json.has("trackerStats")){ + json.getAsJsonArray("trackerStats").forEach(element -> { + if (element.isJsonObject()){ + JsonObject object = element.getAsJsonObject(); + String location = object.get("location").getAsString(); + Map<String, Map<String, ItemStack>> trackers = TrackerHandler.trackers.get(location).dropTrackers; + + JsonElement event = object.get("event"); + String eventString = event == null || event.isJsonNull() ? null : event.getAsString(); + Map<String, ItemStack> drops = trackers.get(eventString); + + if (drops != null) { + for (Map.Entry <String ,JsonElement> drop :object.getAsJsonObject("drops").entrySet()) { + if (drops.containsKey(drop.getKey())) { + drops.get(drop.getKey()).stackSize = drop.getValue().getAsInt(); + } + } + drops = TrackerHandler.sortTrackers(drops); + trackers.put(eventString, drops); + } + } + }); + } + } + } catch(Exception ignored) {} + return false; + } + + public static void saveTrackerStatsFile(File configDirectory){ + File configFile = new File(configDirectory, "sbh-trackers-stats.json"); + + try { + configFile.createNewFile(); + + try(BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(configFile), StandardCharsets.UTF_8))) { + JsonObject json = new JsonObject(); + json.add("trackerStats", getTrackerFile()); + writer.write(gson.toJson(json)); + } + } catch(IOException ignored) {} + } + +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/tracker/TrackerHandler.java b/src/main/java/com/thatgravyboat/skyblockhud/tracker/TrackerHandler.java new file mode 100644 index 0000000..9d8261b --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/tracker/TrackerHandler.java @@ -0,0 +1,124 @@ +package com.thatgravyboat.skyblockhud.tracker; + +import com.thatgravyboat.skyblockhud.SkyblockHud; +import com.thatgravyboat.skyblockhud.Utils; +import com.thatgravyboat.skyblockhud.core.config.Position; +import com.thatgravyboat.skyblockhud.location.LocationHandler; +import com.thatgravyboat.skyblockhud.location.Locations; +import com.thatgravyboat.skyblockhud.seasons.SeasonDateHandler; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Gui; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.RenderHelper; +import net.minecraft.client.renderer.entity.RenderItem; +import net.minecraft.item.ItemStack; +import net.minecraftforge.client.event.RenderGameOverlayEvent; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; + +import java.util.*; + +public class TrackerHandler { + + public static class TrackerData { + public Map<String, Map<String,ItemStack>> dropTrackers; + + public TrackerData(Map<String, Map<String,ItemStack>> trackers) { + this.dropTrackers = trackers; + } + + public String getDropId(String event){ + if (event == null || event.isEmpty() || !eventGoing() || !dropTrackers.containsKey(event.toLowerCase().trim())) return null; + return event.toLowerCase().trim(); + } + + private boolean eventGoing(){ + return SeasonDateHandler.getCurrentEventTime().trim().toLowerCase().contains("ends in"); + } + } + + public static Map<String, TrackerData> trackers = new HashMap<>(); + public static Map<Locations,String> trackerIds = new HashMap<>(); + + public static Map<String, ItemStack> sortTrackers(Map<String, ItemStack> map) { + List<Map.Entry<String, ItemStack>> list = new ArrayList<>(map.entrySet()); + list.sort((entry1, entry2) -> Integer.compare(entry2.getValue().stackSize, entry1.getValue().stackSize)); + + Map<String, ItemStack> result = new LinkedHashMap<>(); + for (Map.Entry<String, ItemStack> entry : list) { + result.put(entry.getKey(), entry.getValue()); + } + + return result; + } + + public static void onItemAdded(String id, int amount, String enchant, int level){ + if (SkyblockHud.hasSkyblockScoreboard() && trackerIds.containsKey(LocationHandler.getCurrentLocation())){ + String trackerId = trackerIds.get(LocationHandler.getCurrentLocation()); + TrackerData tracked = trackers.get(trackerId); + String dropTrackerId = tracked.getDropId(SeasonDateHandler.getCurrentEvent()); + Map<String,ItemStack> tracker = tracked.dropTrackers.get(dropTrackerId); + String dropId = id; + if (enchant != null){ + dropId = enchant.toUpperCase() + ";" + level; + } + + if (tracker != null && tracker.containsKey(dropId)){ + ItemStack stack = tracker.get(dropId); + stack.stackSize += amount; + tracked.dropTrackers.put(dropTrackerId, sortTrackers(tracker)); + } + } + } + + public static void drawItemStack(ItemStack stack, int x, int y) { + if(stack == null)return; + RenderItem itemRender = Minecraft.getMinecraft().getRenderItem(); + RenderHelper.enableGUIStandardItemLighting(); + itemRender.zLevel = -145; + itemRender.renderItemAndEffectIntoGUI(stack, x, y); + itemRender.zLevel = 0; + RenderHelper.disableStandardItemLighting(); + } + + @SubscribeEvent + public void renderOverlay(RenderGameOverlayEvent.Post event) { + if (Utils.overlayShouldRender(event.type, SkyblockHud.hasSkyblockScoreboard(), trackerIds.containsKey(LocationHandler.getCurrentLocation()), !SkyblockHud.config.trackers.hideTracker)) { + String trackerId = trackerIds.get(LocationHandler.getCurrentLocation()); + Minecraft mc = Minecraft.getMinecraft(); + TrackerData tracked = trackers.get(trackerId); + + Map<String, ItemStack> tracker = tracked.dropTrackers.get(tracked.getDropId(SeasonDateHandler.getCurrentEvent())); + if (tracker != null) { + Position pos = SkyblockHud.config.trackers.trackerPosition; + int startPos = pos.getAbsX(event.resolution, (tracker.size() >= 6 ? 120 : tracker.size() * 20)); + int y = pos.getAbsY(event.resolution, (int) (10 + Math.ceil(tracker.size() / 5d) * 20)); + + Gui.drawRect(startPos, y, startPos + 120, y + 10, -1072689136); + mc.fontRendererObj.drawString("Tracker", startPos + 4, y + 1, 0xffffff, false); + y += 10; + Gui.drawRect(startPos, y, startPos + (tracker.size() >= 6 ? 120 : tracker.size() * 20), (int) (y + (Math.ceil(tracker.size() / 5d) * 20)), 1610612736); + int x = startPos; + for (ItemStack stack : tracker.values()) { + String s = String.valueOf(stack.stackSize); + GlStateManager.disableLighting(); + GlStateManager.enableDepth(); + drawItemStack(stack, x, y); + GlStateManager.disableDepth(); + GlStateManager.disableBlend(); + mc.fontRendererObj.drawStringWithShadow(s, (float) (x + 19 - 2 - mc.fontRendererObj.getStringWidth(s)), (float) (y + 9), stack.stackSize < 1 ? 16733525 : 16777215); + GlStateManager.enableBlend(); + GlStateManager.enableDepth(); + + if ((x - startPos) / 20 == 5) { + x = startPos; + y += 20; + } else { + x += 20; + } + } + } + } + } + + +} |