diff options
15 files changed, 667 insertions, 31 deletions
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/ItemPriceInformation.java b/src/main/java/io/github/moulberry/notenoughupdates/ItemPriceInformation.java index a773abdc..6811067f 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/ItemPriceInformation.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/ItemPriceInformation.java @@ -49,7 +49,7 @@ import java.util.Set; public class ItemPriceInformation { private static File file; - private static HashSet<String> auctionableItems = null; + private static HashSet<String> auctionableItems; private static Gson gson; private static final NumberFormat format = new DecimalFormat("#,##0.#", new DecimalFormatSymbols(Locale.US)); @@ -325,7 +325,32 @@ public class ItemPriceInformation { if (shouldShow) { tooltip.add(EnumChatFormatting.YELLOW.toString() + EnumChatFormatting.BOLD + "Required Items:"); for (JsonElement item : itemsObject.get(nextStarLevelString).getAsJsonArray()) { - tooltip.add(" - " + item.getAsString()); + if (item.getAsString().contains("§")) { + //TODO show outdated repo notification when 2.1.1 releases + tooltip.add(" - " + item.getAsString()); + continue; + } + String itemString = item.getAsString(); + int colon = itemString.indexOf(':'); + if (colon != -1) { + String amount = itemString.substring(colon + 1); + String requiredItem = itemString.substring(0, colon); + if (requiredItem.equals("SKYBLOCK_COIN")) { + tooltip.add(" - " + EnumChatFormatting.GOLD + amount + " Coins"); + } + + if (NotEnoughUpdates.INSTANCE.manager.isValidInternalName(requiredItem)) { + JsonObject itemObject = NotEnoughUpdates.INSTANCE.manager. + createItemResolutionQuery(). + withKnownInternalName(requiredItem). + resolveToItemListJson(); + + if (itemObject != null && itemObject.has("displayname")) { + String displayName = itemObject.get("displayname").getAsString(); + tooltip.add(" - " + displayName + EnumChatFormatting.DARK_GRAY + " x" + amount); + } + } + } } } else { tooltip.add(EnumChatFormatting.DARK_GRAY + "[CTRL to show required items]"); diff --git a/src/main/java/io/github/moulberry/notenoughupdates/NEUManager.java b/src/main/java/io/github/moulberry/notenoughupdates/NEUManager.java index 5fe902fb..a30ca08a 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/NEUManager.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/NEUManager.java @@ -888,7 +888,11 @@ public class NEUManager { break; case "viewpotion": neu.sendChatMessage("/viewpotion " + internalName.split(";")[0].toLowerCase(Locale.ROOT)); + break; + default: + displayGuiItemRecipe(internalName); } + } public void showRecipe(String internalName) { diff --git a/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java b/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java index c1190b2b..4c8ac2b9 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java @@ -319,7 +319,7 @@ public class NotEnoughUpdates { MinecraftForge.EVENT_BUS.register(new SignCalculator()); MinecraftForge.EVENT_BUS.register(TrophyRewardOverlay.getInstance()); MinecraftForge.EVENT_BUS.register(PowerStoneStatsDisplay.getInstance()); - MinecraftForge.EVENT_BUS.register(new AntiCoopAdd()); + MinecraftForge.EVENT_BUS.register(AntiCoopAdd.getInstance()); MinecraftForge.EVENT_BUS.register(AbiphoneWarning.getInstance()); MinecraftForge.EVENT_BUS.register(new BetterContainers()); MinecraftForge.EVENT_BUS.register(AuctionBINWarning.getInstance()); diff --git a/src/main/java/io/github/moulberry/notenoughupdates/core/util/StringUtils.java b/src/main/java/io/github/moulberry/notenoughupdates/core/util/StringUtils.java index 7ea9cd00..c19c4826 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/core/util/StringUtils.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/core/util/StringUtils.java @@ -118,4 +118,17 @@ public class StringUtils { String firstLetter = ("" + text.charAt(0)).toUpperCase(); return firstLetter + text.substring(1); } + + public static boolean isNumeric(String string) { + if (string == null || string.isEmpty()) { + return false; + } + + for (char c : string.toCharArray()) { + if (!Character.isDigit(c)) { + return false; + } + } + return true; + } } diff --git a/src/main/java/io/github/moulberry/notenoughupdates/listener/ChatListener.java b/src/main/java/io/github/moulberry/notenoughupdates/listener/ChatListener.java index 6a94c0b3..fcd320fa 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/listener/ChatListener.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/listener/ChatListener.java @@ -42,6 +42,7 @@ import net.minecraftforge.client.event.ClientChatReceivedEvent; import net.minecraftforge.fml.common.eventhandler.EventPriority; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -125,7 +126,8 @@ public class ChatListener { String startsWith = null; boolean partyOrGuildChat = false; - if (chatComponent.getSiblings().get(0).getChatStyle().getChatClickEvent().getValue().startsWith("/viewprofile")) { + List<IChatComponent> siblings = chatComponent.getSiblings(); + if (!siblings.isEmpty() && siblings.get(0).getChatStyle().getChatClickEvent().getValue().startsWith("/viewprofile")) { startsWith = "/viewprofile"; partyOrGuildChat = true; } else { diff --git a/src/main/java/io/github/moulberry/notenoughupdates/listener/RenderListener.java b/src/main/java/io/github/moulberry/notenoughupdates/listener/RenderListener.java index 949358ad..ca841590 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/listener/RenderListener.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/listener/RenderListener.java @@ -1254,11 +1254,13 @@ public class RenderListener { if (stack.getTagCompound().getCompoundTag("display").hasKey("Lore", 9)) { int stars = Utils.getNumberOfStars(stack); if (stars == 0) continue; - String starsStr = "" + stars; NBTTagList lore = stack.getTagCompound().getCompoundTag("display").getTagList("Lore", 8); int costIndex = 10000; - id = NotEnoughUpdates.INSTANCE.manager.getInternalnameFromNBT(stack.getTagCompound()); + id = NotEnoughUpdates.INSTANCE.manager + .createItemResolutionQuery() + .withItemStack(stack) + .resolveInternalName(); if (jsonObject.has(id)) { jsonObject.remove(id); } @@ -1267,39 +1269,72 @@ public class RenderListener { if (entry.equals("§7Cost")) { costIndex = j; } - if (j > costIndex) { entry = entry.trim(); - - int countIndex = entry.lastIndexOf(" §8x"); - - String upgradeName = entry; - String amount = "1"; - if (countIndex != -1) { - upgradeName = entry.substring(0, countIndex); - // +4 to account for " §8x" - amount = entry.substring(countIndex + 4); + int index = entry.lastIndexOf('x'); + String item, amountString; + if (index < 0) { + item = entry.trim() + " x1"; + amountString = "x1"; + } else { + amountString = entry.substring(index); + item = entry.substring(0, index).trim(); } - - if (upgradeName.endsWith(" Essence")) { - // First 2 chars are control code - // [EssenceCount, EssenceType, "Essence"] - String[] upgradeNameSplit = upgradeName.substring(2).split(" "); - newEntry.addProperty("type", upgradeNameSplit[1]); - newEntry.addProperty(starsStr, Integer.parseInt(upgradeNameSplit[0].replace(",", ""))); + item = item.substring(0, item.length() - 3); + int amount = Integer.parseInt(amountString.trim().replace("x", "").replace(",", "")); + if (item.endsWith("Essence")) { + int index2 = entry.indexOf("Essence"); + String typeAndAmount = item.substring(0, index2).trim().substring(2); + int whitespaceIndex = typeAndAmount.indexOf(' '); + int essenceAmount = Integer.parseInt(typeAndAmount + .substring(0, whitespaceIndex) + .replace(",", "")); + newEntry.add("type", new JsonPrimitive(typeAndAmount.substring(whitespaceIndex + 1))); + if (stars == -1) { + newEntry.add("dungeonize", new JsonPrimitive(essenceAmount)); + } else { + newEntry.add(String.valueOf(stars), new JsonPrimitive(essenceAmount)); + } + } else if (item.endsWith("Coins")) { + int index2 = entry.indexOf("Coins"); + String coinsAmount = item.substring(0, index2).trim().substring(2); + if (!newEntry.has("items")) { + newEntry.add("items", new JsonObject()); + } + if (!newEntry.get("items").getAsJsonObject().has(String.valueOf(stars))) { + newEntry.get("items").getAsJsonObject().add(String.valueOf(stars), new JsonArray()); + } + newEntry + .get("items") + .getAsJsonObject() + .get(String.valueOf(stars)) + .getAsJsonArray() + .add(new JsonPrimitive("SKYBLOCK_COIN:" + coinsAmount.replace(",", ""))); } else { + String itemString = "_"; + for (Map.Entry<String, JsonObject> itemEntry : NotEnoughUpdates.INSTANCE.manager + .getItemInformation() + .entrySet()) { + + if (itemEntry.getValue().has("displayname")) { + String name = itemEntry.getValue().get("displayname").getAsString(); + if (name.equals(item)) { + itemString = itemEntry.getKey() + ":" + amount; + } + } + } if (!newEntry.has("items")) { newEntry.add("items", new JsonObject()); } - if (!newEntry.get("items").getAsJsonObject().has(starsStr)) { - newEntry.get("items").getAsJsonObject().add(starsStr, new JsonArray()); + if (!newEntry.get("items").getAsJsonObject().has(String.valueOf(stars))) { + newEntry.get("items").getAsJsonObject().add(String.valueOf(stars), new JsonArray()); } newEntry .get("items") .getAsJsonObject() - .get(starsStr) + .get(String.valueOf(stars)) .getAsJsonArray() - .add(new JsonPrimitive(upgradeName + (upgradeName.contains("Coins") ? "" : (" §8x" + amount)))); + .add(new JsonPrimitive(itemString)); } } } diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/AntiCoopAdd.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/AntiCoopAdd.java index 70ac4489..aaa13d39 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/AntiCoopAdd.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/AntiCoopAdd.java @@ -27,12 +27,19 @@ import net.minecraft.event.ClickEvent; import net.minecraft.event.HoverEvent; import net.minecraft.init.Items; import net.minecraft.item.ItemStack; +import net.minecraft.network.play.client.C01PacketChatMessage; import net.minecraft.util.ChatComponentText; import net.minecraft.util.EnumChatFormatting; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; public class AntiCoopAdd { + private static final AntiCoopAdd INSTANCE = new AntiCoopAdd(); + + public static AntiCoopAdd getInstance() { + return INSTANCE; + } + @SubscribeEvent public void onMouseClick(SlotClickEvent event) { if (!NotEnoughUpdates.INSTANCE.config.misc.coopWarning) return; @@ -59,4 +66,15 @@ public class AntiCoopAdd { event.setCanceled(true); } } + + public Boolean onPacketChatMessage(C01PacketChatMessage packet) { + if (!NotEnoughUpdates.INSTANCE.config.misc.coopWarning) return false; + + String message = packet.getMessage().toLowerCase(); + if (message.startsWith("/hypixelcommand:coopadd")) { + Utils.addChatMessage("§e[NEU] You just entered a malicious looking Co-op add command! If you truly want to add someone to your coop, type §e/coopadd <name>"); + return true; + } + return false; + } } diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinNetHandlerPlayClient.java b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinNetHandlerPlayClient.java index 44d7eef6..4bb91109 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinNetHandlerPlayClient.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinNetHandlerPlayClient.java @@ -20,6 +20,7 @@ package io.github.moulberry.notenoughupdates.mixins; import io.github.moulberry.notenoughupdates.events.SpawnParticleEvent; +import io.github.moulberry.notenoughupdates.miscfeatures.AntiCoopAdd; import io.github.moulberry.notenoughupdates.miscfeatures.CustomItemEffects; import io.github.moulberry.notenoughupdates.miscfeatures.EnchantingSolvers; import io.github.moulberry.notenoughupdates.miscfeatures.ItemCooldowns; @@ -128,6 +129,9 @@ public class MixinNetHandlerPlayClient { } if (packet instanceof C01PacketChatMessage) { NewApiKeyHelper.getInstance().hookPacketChatMessage((C01PacketChatMessage) packet); + if (AntiCoopAdd.getInstance().onPacketChatMessage((C01PacketChatMessage) packet)) { + ci.cancel(); + } } } diff --git a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Misc.java b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Misc.java index 78bb0f95..dbf79bce 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Misc.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Misc.java @@ -262,7 +262,7 @@ public class Misc { @Expose @ConfigOption( name = "Enable Coop Warning", - desc = "Asks for confirmation when clicking the coop diamond in profile menu" + desc = "Asks for confirmation when clicking the coop diamond in profile menu and prevents 'wrong' /coopadd commands" ) @ConfigEditorBoolean public boolean coopWarning = true; diff --git a/src/main/java/io/github/moulberry/notenoughupdates/recipes/EssenceUpgrades.java b/src/main/java/io/github/moulberry/notenoughupdates/recipes/EssenceUpgrades.java new file mode 100644 index 00000000..0c4bfbdf --- /dev/null +++ b/src/main/java/io/github/moulberry/notenoughupdates/recipes/EssenceUpgrades.java @@ -0,0 +1,501 @@ +/* + * Copyright (C) 2022 NotEnoughUpdates contributors + * + * This file is part of NotEnoughUpdates. + * + * NotEnoughUpdates is free software: you can redistribute it + * and/or modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * NotEnoughUpdates is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>. + */ + +package io.github.moulberry.notenoughupdates.recipes; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import io.github.moulberry.notenoughupdates.NEUManager; +import io.github.moulberry.notenoughupdates.NotEnoughUpdates; +import io.github.moulberry.notenoughupdates.core.util.StringUtils; +import io.github.moulberry.notenoughupdates.miscgui.GuiItemRecipe; +import io.github.moulberry.notenoughupdates.util.Constants; +import io.github.moulberry.notenoughupdates.util.ItemUtils; +import io.github.moulberry.notenoughupdates.util.Utils; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.item.ItemStack; +import net.minecraft.util.ChatComponentText; +import net.minecraft.util.EnumChatFormatting; +import net.minecraft.util.ResourceLocation; +import org.jetbrains.annotations.Nullable; +import org.lwjgl.input.Keyboard; +import org.lwjgl.input.Mouse; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class EssenceUpgrades implements NeuRecipe { + + private static final ResourceLocation BACKGROUND = new ResourceLocation("notenoughupdates", "textures/gui/essence_upgrades_tall.png"); + private static final List<RenderLocation> buttonLocations = new ArrayList<RenderLocation>() {{ + add(new RenderLocation(20, 20)); + add(new RenderLocation(40, 20)); + add(new RenderLocation(60, 20)); + add(new RenderLocation(80, 20)); + add(new RenderLocation(100, 20)); + add(new RenderLocation(120, 20)); + add(new RenderLocation(140, 20)); + + add(new RenderLocation(10, 40)); + add(new RenderLocation(30, 40)); + add(new RenderLocation(50, 40)); + add(new RenderLocation(70, 40)); + add(new RenderLocation(90, 40)); + add(new RenderLocation(110, 40)); + add(new RenderLocation(130, 40)); + add(new RenderLocation(150, 40)); + }}; + + private static final List<RenderLocation> slotLocations = new ArrayList<RenderLocation>() {{ + add(new RenderLocation(20, 60)); + add(new RenderLocation(45, 60)); + add(new RenderLocation(70, 60)); + + add(new RenderLocation(20, 85)); + add(new RenderLocation(45, 85)); + add(new RenderLocation(70, 85)); + + add(new RenderLocation(20, 110)); + add(new RenderLocation(45, 110)); + add(new RenderLocation(70, 110)); + }}; + + private static final Pattern loreStatPattern = Pattern.compile("^.+: §.\\+(?<value>[\\d.]+).*$"); + + private final Ingredient output; + private final ItemStack initialItemStack; + private final Map<Integer, TierUpgrade> tierUpgradeMap; + private final int amountOfTiers; + private int selectedTier; + private static final int outputX = 123; + private static final int outputY = 65; + private List<RecipeSlot> slots; + private GuiItemRecipe guiItemRecipe; + + public EssenceUpgrades(Ingredient output, Map<Integer, TierUpgrade> tierUpgradeMap) { + this.output = output; + this.tierUpgradeMap = tierUpgradeMap; + + initialItemStack = output.getItemStack().copy(); + amountOfTiers = tierUpgradeMap.keySet().size(); + selectedTier = amountOfTiers; + slots = new ArrayList<>(); + } + + /** + * Parses an entry from essencecosts.json to a NeuRecipe, containing information on how to upgrade the item with Essence + * + * @param entry Entry from essencecosts.json + * @return parsed NeuRecipe + * @see Constants#parseEssenceCosts() + */ + public static @Nullable NeuRecipe parseFromEssenceCostEntry(Map.Entry<String, JsonElement> entry) { + NEUManager manager = NotEnoughUpdates.INSTANCE.manager; + if (!manager.isValidInternalName(entry.getKey())) { + System.err.println("Invalid internalname: " + entry.getKey()); + return null; + } + + String internalName = entry.getKey(); + JsonObject jsonObject = entry.getValue().getAsJsonObject(); + + Ingredient output = new Ingredient(manager, internalName); + + if (!jsonObject.has("type")) { + System.err.println("Invalid essence entry for: " + internalName); + System.err.println("Missing: Essence type"); + return null; + } + String essenceType = jsonObject.get("type").getAsString(); + + Map<Integer, TierUpgrade> upgradeMap = new HashMap<>(); + for (Map.Entry<String, JsonElement> entries : jsonObject.entrySet()) { + if (StringUtils.isNumeric(entries.getKey())) { + int tier = Integer.parseInt(entries.getKey()); + int essenceCost = Integer.parseInt(entries.getValue().getAsString()); + upgradeMap.put(tier, new TierUpgrade(tier, essenceType, essenceCost, null)); + } else if (entries.getKey().equals("items")) { + for (Map.Entry<String, JsonElement> requiredItems : entries + .getValue() + .getAsJsonObject() + .entrySet()) { + Integer tier = Integer.parseInt(requiredItems.getKey()); + Map<String, Integer> items = new HashMap<>(); + for (JsonElement element : requiredItems.getValue().getAsJsonArray()) { + String itemString = element.getAsString(); + + int colon = itemString.indexOf(':'); + if (colon != -1) { + String amount = itemString.substring(colon + 1); + String requiredItem = itemString.substring(0, colon); + + items.put(requiredItem, Integer.parseInt(amount)); + } + } + upgradeMap.get(tier).itemsRequired = items; + } + } + } + return new EssenceUpgrades(output, upgradeMap); + } + + /** + * Builds a list containing all the RecipeSlots that should be rendered right now: + * <ul> + * <li>The output</li> + * <li>The ingredients</li> + * </ul> + * + * @return the list of RecipeSlots + * @see EssenceUpgrades#getSlots() + */ + private List<RecipeSlot> buildSlotList() { + NEUManager manager = NotEnoughUpdates.INSTANCE.manager; + List<RecipeSlot> slotList = new ArrayList<>(); + + //output item + String internalName = output.getInternalItemId(); + if (internalName == null) { + return slotList; + } + List<String> lore = ItemUtils.getLore(initialItemStack); + List<String> newLore = new ArrayList<>(); + + for (String loreEntry : lore) { + Matcher matcher = loreStatPattern.matcher(loreEntry); + if (matcher.matches()) { + String valueString = matcher.group("value"); + if (valueString == null) { + newLore.add(loreEntry); + continue; + } + + float value = Float.parseFloat(valueString); + int matchStart = matcher.start("value"); + float newValue = value * (1 + (selectedTier / 50f)); + StringBuilder newLine = new StringBuilder(loreEntry.substring(0, matchStart) + String.format("%.1f", newValue)); + if (loreEntry.length() - 1 > matcher.end("value")) { + newLine.append(loreEntry, matcher.end("value"), loreEntry.length() - 1); + } + + newLore.add(newLine.toString()); + } else { + //simply append this entry to the new lore + newLore.add(loreEntry); + } + } + ItemUtils.setLore(output.getItemStack(), newLore); + output.getItemStack().setStackDisplayName( + initialItemStack.getDisplayName() + " " + Utils.getStarsString(selectedTier)); + slotList.add(new RecipeSlot(outputX, outputY, output.getItemStack())); + + //other required items and/or coins, if applicable + TierUpgrade tierUpgrade = tierUpgradeMap.get(selectedTier); + if (tierUpgrade == null) { + return slotList; + } + + //required essence + String essenceInternalName = "ESSENCE_" + tierUpgrade.getEssenceType().toUpperCase(Locale.ROOT); + if (manager.isValidInternalName(essenceInternalName)) { + ItemStack essenceItemStack = + manager.createItemResolutionQuery().withKnownInternalName(essenceInternalName).resolveToItemStack(); + if (essenceItemStack != null) { + essenceItemStack = essenceItemStack.copy(); + essenceItemStack.setStackDisplayName( + EnumChatFormatting.AQUA.toString() + tierUpgrade.getEssenceRequired() + " " + EnumChatFormatting.DARK_GRAY + + tierUpgrade.getEssenceType() + " Essence"); + RenderLocation renderLocation = slotLocations.get(0); + slotList.add(new RecipeSlot(renderLocation.getX() + 1, renderLocation.getY() + 1, essenceItemStack)); + } + } + + int i = 1; + if (tierUpgrade.getItemsRequired() != null) { + for (Map.Entry<String, Integer> requiredItem : tierUpgrade.getItemsRequired().entrySet()) { + ItemStack itemStack; + if (requiredItem.getKey().equals("SKYBLOCK_COIN")) { + Ingredient ingredient = Ingredient.coinIngredient( + manager, + requiredItem.getValue() + ); + itemStack = ingredient.getItemStack(); + } else { + itemStack = manager.createItemResolutionQuery().withKnownInternalName( + requiredItem.getKey()).resolveToItemStack(); + if (itemStack != null) { + itemStack.stackSize = requiredItem.getValue(); + } + } + if (itemStack != null) { + RenderLocation renderLocation = slotLocations.get(i++); + if (renderLocation != null) { + slotList.add(new RecipeSlot(renderLocation.getX() + 1, renderLocation.getY()+1, itemStack)); + } + } + } + } + + return slotList; + } + + /** + * Draws an empty slot texture at the specified location + * + * @param x x location + * @param y y location + */ + private void drawSlot(int x, int y) { + GlStateManager.color(1, 1, 1, 1); + Minecraft.getMinecraft().getTextureManager().bindTexture(BACKGROUND); + Utils.drawTexturedRect( + x, + y, + 18, + 18, + 176 / 256f, + 194 / 256f, + 0 / 256f, + 18 / 256f + ); + } + + /** + * Draws a button using a part of the texture + * + * @param x x location + * @param y y location + * @param selected whether the button should look like its pressed down or not + */ + private void drawButton(int x, int y, boolean selected) { + if (selected) { + Utils.drawTexturedRect( + x, + y, + 16, + 16, + 176 / 256f, + 192 / 256f, + 34 / 256f, + 50 / 256f + ); + } else { + Utils.drawTexturedRect( + x, + y, + 16, + 16, + 176 / 256f, + 192 / 256f, + 18 / 256f, + 34 / 256f + ); + } + } + + /** + * Draws all Buttons applicable for the item and checks if a button has been clicked on + * + * @see EssenceUpgrades#buttonLocations + */ + private void drawButtons(int mouseX, int mouseY) { + for (int i = 0; i < amountOfTiers; i++) { + if (i >= buttonLocations.size()) { + Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText( + EnumChatFormatting.RED + "[NEU] Error: Item has more than " + buttonLocations.size() + + " possible star upgrades")); + break; + } + RenderLocation buttonLocation = buttonLocations.get(i); + + int x = guiItemRecipe.guiLeft + buttonLocation.getX(); + int y = guiItemRecipe.guiTop + buttonLocation.getY(); + + if (Mouse.getEventButtonState() && Utils.isWithinRect(mouseX, mouseY, x, y, 16, 16)) { + selectedTier = i + 1; + slots = buildSlotList(); + } + + Minecraft.getMinecraft().getTextureManager().bindTexture(BACKGROUND); + GlStateManager.color(1, 1, 1, 1); + drawButton(x, y, i + 1 == selectedTier); + Utils.drawStringCentered( + String.valueOf(i + 1), + Minecraft.getMinecraft().fontRendererObj, + x + 8, + y + 9, + false, + 0x2d4ffc + ); + } + } + + private void drawSlots(int amount) { + //-1 to not count the output slot + for (int i = 0; i < amount - 1; i++) { + RenderLocation renderLocation = slotLocations.get(i); + if (renderLocation != null && guiItemRecipe != null) { + drawSlot(guiItemRecipe.guiLeft + renderLocation.getX(), guiItemRecipe.guiTop + renderLocation.getY()); + } + } + } + + @Override + public void drawExtraInfo(GuiItemRecipe gui, int mouseX, int mouseY) { + guiItemRecipe = gui; + if (slots.isEmpty()) { + slots = buildSlotList(); + } + drawButtons(mouseX, mouseY); + } + + @Override + public void drawExtraBackground(GuiItemRecipe gui, int mouseX, int mouseY) { + drawSlots(slots.size()); + } + + @Override + public void handleKeyboardInput() { + if (Keyboard.isRepeatEvent()) { + return; + } + + if (Keyboard.isKeyDown(Keyboard.KEY_LEFT) && selectedTier > 1) { + selectedTier--; + slots = buildSlotList(); + } else if (Keyboard.isKeyDown(Keyboard.KEY_RIGHT) && selectedTier < amountOfTiers) { + selectedTier++; + slots = buildSlotList(); + } else if (Keyboard.isKeyDown(Keyboard.KEY_0) || Keyboard.isKeyDown(Keyboard.KEY_NUMPAD0)) { + //cycle through tiers when pressing 0 + if (selectedTier < amountOfTiers) { + selectedTier++; + } else { + selectedTier = 1; + } + } + + char pressedKey = Keyboard.getEventCharacter(); + if (Character.isDigit(pressedKey)) { + //convert to number from 1-9 + pressedKey -= 48; + if (pressedKey > 0 && pressedKey <= amountOfTiers) { + selectedTier = pressedKey; + slots = buildSlotList(); + } + } + } + + @Override + public Set<Ingredient> getIngredients() { + return Collections.singleton(output); + } + + @Override + public Set<Ingredient> getOutputs() { + return Collections.singleton(output); + } + + @Override + public List<RecipeSlot> getSlots() { + return slots; + } + + @Override + public RecipeType getType() { + return RecipeType.ESSENCE_UPGRADES; + } + + @Override + public boolean hasVariableCost() { + return false; + } + + @Override + public @Nullable JsonObject serialize() { + return null; + } + + @Override + public ResourceLocation getBackground() { + return BACKGROUND; + } + + /** + * Simple dataclass holding an x and y value to be used when describing the location of something to be rendered + */ + private static class RenderLocation { + private final int x; + private final int y; + + public RenderLocation(int x, int y) { + this.x = x; + this.y = y; + } + + public int getX() { + return x; + } + + public int getY() { + return y; + } + } + + /** + * Dataclass holding information about the items and essence required to upgrade an item to a specific tier + */ + public static class TierUpgrade { + private final int tier; + private final String essenceType; + private final int essenceRequired; + private Map<String, Integer> itemsRequired; + + public TierUpgrade(int tier, String essenceType, int essenceRequired, Map<String, Integer> itemsRequired) { + this.tier = tier; + this.essenceType = essenceType; + this.essenceRequired = essenceRequired; + this.itemsRequired = itemsRequired; + } + + public int getTier() { + return tier; + } + + public String getEssenceType() { + return essenceType; + } + + public int getEssenceRequired() { + return essenceRequired; + } + + public Map<String, Integer> getItemsRequired() { + return itemsRequired; + } + } +} diff --git a/src/main/java/io/github/moulberry/notenoughupdates/recipes/RecipeType.java b/src/main/java/io/github/moulberry/notenoughupdates/recipes/RecipeType.java index de9c869f..087ec6c3 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/recipes/RecipeType.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/recipes/RecipeType.java @@ -30,7 +30,8 @@ public enum RecipeType { FORGE("forge", "Forging", ForgeRecipe::parseForgeRecipe, new ItemStack(Blocks.anvil)), TRADE("trade", "Trading", VillagerTradeRecipe::parseStaticRecipe, new ItemStack(Items.emerald)), MOB_LOOT("drops", "Mob Loot", MobLootRecipe::parseRecipe, new ItemStack(Items.diamond_sword)), - NPC_SHOP("npc_shop", "NPC Item Shop", ItemShopRecipe::parseItemRecipe, new ItemStack(Items.wheat_seeds)); + NPC_SHOP("npc_shop", "NPC Item Shop", ItemShopRecipe::parseItemRecipe, new ItemStack(Items.wheat_seeds)), + ESSENCE_UPGRADES("", "Essence Upgrades", null, new ItemStack(Items.nether_star)); private final String id; private final String label; diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/Calculator.java b/src/main/java/io/github/moulberry/notenoughupdates/util/Calculator.java index 221b5023..54636791 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/util/Calculator.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/util/Calculator.java @@ -117,7 +117,7 @@ public class Calculator { token.tokenLength = 1; token.type = TokenType.LPAREN; token.operatorValue = "("; - } else if ('.' == c) { + } else if ('.' == c || ',' == c) { token.tokenLength = 1; token.type = TokenType.NUMBER; readDigitsInto(token, source, true); @@ -129,7 +129,7 @@ public class Calculator { readDigitsInto(token, source, false); if (i + token.tokenLength < source.length()) { char p = source.charAt(i + token.tokenLength); - if ('.' == p) { + if ('.' == p || ',' == p) { token.tokenLength++; readDigitsInto(token, source, true); } diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/Constants.java b/src/main/java/io/github/moulberry/notenoughupdates/util/Constants.java index ef030367..5a228dc4 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/util/Constants.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/util/Constants.java @@ -29,10 +29,14 @@ import com.google.gson.JsonParseException; import com.google.gson.JsonPrimitive; import com.google.gson.JsonSerializationContext; import com.google.gson.JsonSerializer; +import io.github.moulberry.notenoughupdates.NotEnoughUpdates; import io.github.moulberry.notenoughupdates.events.RepositoryReloadEvent; +import io.github.moulberry.notenoughupdates.recipes.EssenceUpgrades; +import io.github.moulberry.notenoughupdates.recipes.NeuRecipe; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import java.lang.reflect.Type; +import java.util.Map; import java.util.concurrent.locks.ReentrantLock; import java.util.regex.Pattern; @@ -94,10 +98,23 @@ public class Constants { TROPHYFISH = Utils.getConstant("trophyfish", gson); WEIGHT = Utils.getConstant("weight", gson); RNGSCORE = Utils.getConstant("rngscore", gson); + + parseEssenceCosts(); } catch (Exception ex) { ex.printStackTrace(); } finally { lock.unlock(); } } + + public void parseEssenceCosts() { + for (Map.Entry<String, JsonElement> entry : ESSENCECOSTS.entrySet()) { + NeuRecipe parsed = EssenceUpgrades.parseFromEssenceCostEntry(entry); + if (parsed != null) { + NotEnoughUpdates.INSTANCE.manager.registerNeuRecipe(parsed); + } else { + System.out.println("NULL for: " + entry); + } + } + } } diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/ItemUtils.java b/src/main/java/io/github/moulberry/notenoughupdates/util/ItemUtils.java index 6187495c..6cc1bbe7 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/util/ItemUtils.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/util/ItemUtils.java @@ -103,6 +103,22 @@ public class ItemUtils { is.setTagCompound(tagCompound); } + public static void setLore(ItemStack is, List<String> newLore) { + NBTTagCompound tagCompound = is.getTagCompound(); + if (tagCompound == null) { + tagCompound = new NBTTagCompound(); + } + + NBTTagCompound display = tagCompound.getCompoundTag("display"); + NBTTagList lore = new NBTTagList(); + for (String s : newLore) { + lore.appendTag(new NBTTagString(s)); + } + display.setTag("Lore", lore); + tagCompound.setTag("display", display); + is.setTagCompound(tagCompound); + } + public static List<String> getLore(ItemStack is) { return getLore(is.getTagCompound()); } diff --git a/src/main/resources/assets/notenoughupdates/textures/gui/essence_upgrades_tall.png b/src/main/resources/assets/notenoughupdates/textures/gui/essence_upgrades_tall.png Binary files differnew file mode 100644 index 00000000..2591e8c5 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/textures/gui/essence_upgrades_tall.png |