From 6360be89887b2c7b31a1739228deccbb0648d7cf Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 22 Apr 2020 04:02:59 +1000 Subject: Beta-1.1 --- .../notenoughupdates/AllowEmptyHTMLTag.java | 74 + .../moulberry/notenoughupdates/GuiItemRecipe.java | 78 + .../github/moulberry/notenoughupdates/NEUIO.java | 4 +- .../moulberry/notenoughupdates/NEUManager.java | 516 +++++-- .../moulberry/notenoughupdates/NEUOverlay.java | 1524 ++++++++++++++++---- .../notenoughupdates/NotEnoughUpdates.java | 347 ++++- .../notenoughupdates/RequestFocusListener.java | 63 + .../github/moulberry/notenoughupdates/Utils.java | 185 +++ .../moulberry/notenoughupdates/WikiaParser.java | 212 +++ .../moulberry/notenoughupdates/WikiaParserOLD.java | 270 ++++ .../itemeditor/GuiElementTextField.java | 51 +- .../notenoughupdates/itemeditor/NEUItemEditor.java | 21 +- .../notenoughupdates/options/Options.java | 173 +++ .../notenoughupdates/util/HTMLParagraphView.java | 30 + .../notenoughupdates/util/HtmlImageGenerator.java | 125 ++ .../notenoughupdates/util/LargeHTMLEditorKit.java | 132 ++ .../util/SynchronousHTMLEditorKit.java | 36 + .../assets/notenoughupdates/ascending_overlay.png | Bin 0 -> 1497 bytes .../resources/assets/notenoughupdates/close.png | Bin 0 -> 2350 bytes .../assets/notenoughupdates/descending_overlay.png | Bin 0 -> 1513 bytes .../resources/assets/notenoughupdates/help.png | Bin 0 -> 3500 bytes .../resources/assets/notenoughupdates/next.png | Bin 5005 -> 3912 bytes .../resources/assets/notenoughupdates/next.xcf | Bin 0 -> 8805 bytes .../assets/notenoughupdates/next_pow2.png | Bin 17733 -> 0 bytes src/main/resources/assets/notenoughupdates/off.png | Bin 0 -> 1386 bytes src/main/resources/assets/notenoughupdates/on.png | Bin 0 -> 1490 bytes .../assets/notenoughupdates/order_alphabetical.png | Bin 0 -> 1862 bytes .../notenoughupdates/order_alphabetical_active.png | Bin 0 -> 1819 bytes .../assets/notenoughupdates/order_rarity.png | Bin 0 -> 1808 bytes .../notenoughupdates/order_rarity_active.png | Bin 0 -> 1953 bytes .../resources/assets/notenoughupdates/prev.png | Bin 5207 -> 4508 bytes .../resources/assets/notenoughupdates/prev.xcf | Bin 0 -> 8371 bytes .../assets/notenoughupdates/prev_pow2.png | Bin 18696 -> 0 bytes .../resources/assets/notenoughupdates/settings.png | Bin 0 -> 3962 bytes .../assets/notenoughupdates/sort_accessory.png | Bin 0 -> 1885 bytes .../notenoughupdates/sort_accessory_active.png | Bin 0 -> 1871 bytes .../resources/assets/notenoughupdates/sort_all.png | Bin 0 -> 1817 bytes .../assets/notenoughupdates/sort_all_active.png | Bin 0 -> 1850 bytes .../assets/notenoughupdates/sort_armor.png | Bin 0 -> 1792 bytes .../assets/notenoughupdates/sort_armor_active.png | Bin 0 -> 1921 bytes .../resources/assets/notenoughupdates/sort_mob.png | Bin 0 -> 1800 bytes .../assets/notenoughupdates/sort_mob_active.png | Bin 0 -> 1815 bytes .../resources/assets/notenoughupdates/sort_pet.png | Bin 0 -> 1902 bytes .../assets/notenoughupdates/sort_pet_active.png | Bin 0 -> 1932 bytes .../assets/notenoughupdates/sort_weapon.png | Bin 0 -> 749 bytes .../assets/notenoughupdates/sort_weapon_active.png | Bin 0 -> 1869 bytes .../assets/notenoughupdates/wkhtmltox.zip | Bin 0 -> 47859019 bytes 47 files changed, 3406 insertions(+), 435 deletions(-) create mode 100644 src/main/java/io/github/moulberry/notenoughupdates/AllowEmptyHTMLTag.java create mode 100644 src/main/java/io/github/moulberry/notenoughupdates/GuiItemRecipe.java create mode 100644 src/main/java/io/github/moulberry/notenoughupdates/RequestFocusListener.java create mode 100644 src/main/java/io/github/moulberry/notenoughupdates/Utils.java create mode 100644 src/main/java/io/github/moulberry/notenoughupdates/WikiaParser.java create mode 100644 src/main/java/io/github/moulberry/notenoughupdates/WikiaParserOLD.java create mode 100644 src/main/java/io/github/moulberry/notenoughupdates/options/Options.java create mode 100644 src/main/java/io/github/moulberry/notenoughupdates/util/HTMLParagraphView.java create mode 100644 src/main/java/io/github/moulberry/notenoughupdates/util/HtmlImageGenerator.java create mode 100644 src/main/java/io/github/moulberry/notenoughupdates/util/LargeHTMLEditorKit.java create mode 100644 src/main/java/io/github/moulberry/notenoughupdates/util/SynchronousHTMLEditorKit.java create mode 100644 src/main/resources/assets/notenoughupdates/ascending_overlay.png create mode 100644 src/main/resources/assets/notenoughupdates/close.png create mode 100644 src/main/resources/assets/notenoughupdates/descending_overlay.png create mode 100644 src/main/resources/assets/notenoughupdates/help.png create mode 100644 src/main/resources/assets/notenoughupdates/next.xcf delete mode 100644 src/main/resources/assets/notenoughupdates/next_pow2.png create mode 100644 src/main/resources/assets/notenoughupdates/off.png create mode 100644 src/main/resources/assets/notenoughupdates/on.png create mode 100644 src/main/resources/assets/notenoughupdates/order_alphabetical.png create mode 100644 src/main/resources/assets/notenoughupdates/order_alphabetical_active.png create mode 100644 src/main/resources/assets/notenoughupdates/order_rarity.png create mode 100644 src/main/resources/assets/notenoughupdates/order_rarity_active.png create mode 100644 src/main/resources/assets/notenoughupdates/prev.xcf delete mode 100644 src/main/resources/assets/notenoughupdates/prev_pow2.png create mode 100644 src/main/resources/assets/notenoughupdates/settings.png create mode 100644 src/main/resources/assets/notenoughupdates/sort_accessory.png create mode 100644 src/main/resources/assets/notenoughupdates/sort_accessory_active.png create mode 100644 src/main/resources/assets/notenoughupdates/sort_all.png create mode 100644 src/main/resources/assets/notenoughupdates/sort_all_active.png create mode 100644 src/main/resources/assets/notenoughupdates/sort_armor.png create mode 100644 src/main/resources/assets/notenoughupdates/sort_armor_active.png create mode 100644 src/main/resources/assets/notenoughupdates/sort_mob.png create mode 100644 src/main/resources/assets/notenoughupdates/sort_mob_active.png create mode 100644 src/main/resources/assets/notenoughupdates/sort_pet.png create mode 100644 src/main/resources/assets/notenoughupdates/sort_pet_active.png create mode 100644 src/main/resources/assets/notenoughupdates/sort_weapon.png create mode 100644 src/main/resources/assets/notenoughupdates/sort_weapon_active.png create mode 100644 src/main/resources/assets/notenoughupdates/wkhtmltox.zip (limited to 'src') diff --git a/src/main/java/io/github/moulberry/notenoughupdates/AllowEmptyHTMLTag.java b/src/main/java/io/github/moulberry/notenoughupdates/AllowEmptyHTMLTag.java new file mode 100644 index 00000000..3cf5ef31 --- /dev/null +++ b/src/main/java/io/github/moulberry/notenoughupdates/AllowEmptyHTMLTag.java @@ -0,0 +1,74 @@ +package io.github.moulberry.notenoughupdates; + +import info.bliki.htmlcleaner.TagNode; +import info.bliki.wiki.filter.ITextConverter; +import info.bliki.wiki.model.IWikiModel; +import info.bliki.wiki.tags.HTMLTag; + +import java.io.IOException; +import java.util.List; +import java.util.Map; + +public class AllowEmptyHTMLTag extends HTMLTag { + public AllowEmptyHTMLTag(String name) { + super(name); + } + + public void renderHTML(ITextConverter converter, Appendable buf, IWikiModel model) throws IOException { + boolean newLinesAfterTag = false; + boolean newLinesAfterChildren = false; + TagNode node = this; + String name = node.getName(); + List children = node.getChildren(); + + if (NEW_LINES) { + switch (name) { + case "div": + case "p": + case "li": + case "td": + buf.append('\n'); + break; + case "table": + case "ul": + case "ol": + case "th": + case "tr": + buf.append('\n'); + newLinesAfterTag = true; + newLinesAfterChildren = true; + break; + case "pre": + buf.append('\n'); + newLinesAfterTag = false; + newLinesAfterChildren = true; + break; + case "blockquote": + newLinesAfterChildren = true; + break; + } + } + buf.append('<'); + buf.append(name); + + Map tagAtttributes = node.getAttributes(); + + appendAttributes(buf, tagAtttributes); + + if (children.size() == 0) { + buf.append(" />"); + } else { + buf.append('>'); + if (newLinesAfterTag) { + buf.append('\n'); + } + converter.nodesToText(children, buf, model); + if (newLinesAfterChildren) { + buf.append('\n'); + } + buf.append("'); + } + } +} diff --git a/src/main/java/io/github/moulberry/notenoughupdates/GuiItemRecipe.java b/src/main/java/io/github/moulberry/notenoughupdates/GuiItemRecipe.java new file mode 100644 index 00000000..1e31a0f2 --- /dev/null +++ b/src/main/java/io/github/moulberry/notenoughupdates/GuiItemRecipe.java @@ -0,0 +1,78 @@ +package io.github.moulberry.notenoughupdates; + +import com.google.gson.JsonObject; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.inventory.GuiCrafting; +import net.minecraft.client.resources.I18n; +import net.minecraft.inventory.ContainerWorkbench; +import net.minecraft.inventory.IInventory; +import net.minecraft.inventory.Slot; +import net.minecraft.item.ItemStack; + +public class GuiItemRecipe extends GuiCrafting { + + private ItemStack[] craftMatrix; + private String text; + private String craftText = ""; + private NEUManager manager; + + public GuiItemRecipe(ItemStack[] craftMatrix, JsonObject result, String text, NEUManager manager) { + super(Minecraft.getMinecraft().thePlayer.inventory, Minecraft.getMinecraft().theWorld); + this.craftMatrix = craftMatrix; + this.text = text; + this.manager = manager; + + ContainerWorkbench cw = (ContainerWorkbench) this.inventorySlots; + for(int i=0; i this.xSize - 40) { + xPos = 4; + } + if(t.contains("\u00a7")) { + this.fontRendererObj.drawStringWithShadow(t, xPos, 6, 4210752); + } else { + this.fontRendererObj.drawString(t, xPos, 6, 4210752); + } + this.fontRendererObj.drawString(I18n.format("container.inventory", new Object[0]), 8, this.ySize - 96 + 2, 4210752); + + this.fontRendererObj.drawString(craftText, 88, 19, 4210752); + } + + protected void mouseClickMove(int mouseX, int mouseY, int clickedMouseButton, long timeSinceLastClick) { + } + + protected void handleMouseClick(Slot slotIn, int slotId, int clickedButton, int clickType) { + if(slotId >= 1 && slotId <= 9) { + ItemStack click = craftMatrix[slotId-1]; + if(click != null) { + manager.displayGuiItemRecipe(manager.getInternalNameForItem(click), ""); + } + } + } + + /*public void handleMouseInput() throws IOException { + ScaledResolution scaledresolution = new ScaledResolution(Minecraft.getMinecraft()); + int height = scaledresolution.getScaledHeight(); + + int mouseX = Mouse.getX() / scaledresolution.getScaleFactor(); + int mouseY = height - Mouse.getY() / scaledresolution.getScaleFactor(); + if(mouseY > this.guiTop + this.ySize - 94 || mouseY < this.guiTop || + mouseX < this.guiLeft || mouseX > this.guiLeft+this.xSize) { + //Potentially allow mouse input in the future. For now this is still broken. + //super.handleMouseInput(); + } + }*/ + + public void onCraftMatrixChanged(IInventory inventoryIn){} +} diff --git a/src/main/java/io/github/moulberry/notenoughupdates/NEUIO.java b/src/main/java/io/github/moulberry/notenoughupdates/NEUIO.java index 7e7091cf..a89bd1dc 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/NEUIO.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/NEUIO.java @@ -74,7 +74,9 @@ public class NEUIO { changedFiles.put(content.getName(), content.getSha()); } } - } catch(IOException e) { } + } catch(IOException e) { + return null; + } return changedFiles; } diff --git a/src/main/java/io/github/moulberry/notenoughupdates/NEUManager.java b/src/main/java/io/github/moulberry/notenoughupdates/NEUManager.java index c6fab0f1..bcf4635e 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/NEUManager.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/NEUManager.java @@ -1,14 +1,18 @@ package io.github.moulberry.notenoughupdates; +import com.google.common.io.CharSource; import com.google.gson.*; +import io.github.moulberry.notenoughupdates.options.Options; import javafx.scene.control.Alert; import net.minecraft.client.Minecraft; +import net.minecraft.init.Items; +import net.minecraft.item.Item; import net.minecraft.item.ItemStack; -import net.minecraft.nbt.JsonToNBT; -import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.nbt.NBTTagList; -import net.minecraft.nbt.NBTUtil; +import net.minecraft.nbt.*; import net.minecraft.util.ResourceLocation; +import org.apache.commons.io.IOUtils; +import org.apache.commons.io.input.ReaderInputStream; +import org.apache.commons.lang3.tuple.Pair; import org.lwjgl.opengl.Display; import javax.swing.*; @@ -22,8 +26,9 @@ import java.util.zip.ZipInputStream; public class NEUManager { + private final NotEnoughUpdates neu; public final NEUIO neuio; - public static final Gson gson = new GsonBuilder().setPrettyPrinting().create(); + public final Gson gson; private TreeMap itemMap = new TreeMap<>(); @@ -31,23 +36,41 @@ public class NEUManager { private TreeMap>> titleWordMap = new TreeMap<>(); private TreeMap>> loreWordMap = new TreeMap<>(); - private File configLocation; + public String viewItemAttemptID = null; + public long viewItemAttemptTime = 0; + + private ResourceLocation wkZip = new ResourceLocation("notenoughupdates:wkhtmltox.zip"); + private Map itemstackCache = new HashMap<>(); + + private static final String AUCTIONS_PRICE_URL = "https://sll5cr6l5a.execute-api.us-east-1.amazonaws.com/Prod/get_prices"; + private TreeMap auctionPrices = new TreeMap<>(); + private TreeMap> bazaarBuySellPrices = new TreeMap<>(); + private long auctionLastUpdate = 0; + + public File configLocation; private File itemsLocation; private File itemShaLocation; private JsonObject itemShaConfig; - private File config; - private JsonObject configJson; + private File configFile; + public Options config; - public NEUManager(NEUIO neuio, File configLocation) { + public NEUManager(NotEnoughUpdates neu, NEUIO neuio, File configLocation) { + this.neu = neu; this.configLocation = configLocation; this.neuio = neuio; - this.config = new File(configLocation, "config.json"); + GsonBuilder gsonBuilder = new GsonBuilder().setPrettyPrinting(); + gsonBuilder.registerTypeAdapter(Options.Option.class, Options.createSerializer()); + gsonBuilder.registerTypeAdapter(Options.Option.class, Options.createDeserializer()); + gson = gsonBuilder.create(); + + this.configFile = new File(configLocation, "config.json"); try { - config.createNewFile(); - configJson = getJsonFromFile(config); - if(configJson == null) configJson = new JsonObject(); - } catch(IOException e) { } + configFile.createNewFile(); + config = Options.loadFromFile(gson, configFile); + } catch(IOException e) { + config = new Options(); + } this.itemsLocation = new File(configLocation, "items"); itemsLocation.mkdir(); @@ -58,6 +81,115 @@ public class NEUManager { itemShaConfig = getJsonFromFile(itemShaLocation); if(itemShaConfig == null) itemShaConfig = new JsonObject(); } catch(IOException e) { } + + File wkShell = new File(configLocation, "wkhtmltox/bin/wkhtmltoimage"); + if(!wkShell.exists()) { + try { + InputStream is = Minecraft.getMinecraft().getResourceManager().getResource(wkZip).getInputStream(); + unzip(is, configLocation); + } catch (IOException e) { + } + } + + //Unused code, used to automatically grab items from auctions. Leaving here in case I need it. + /*try { + for(int j=0; j<=89; j++) { + JsonObject auctions0 = getJsonFromFile(new File(configLocation, "auctions/auctions"+j+".json")); + + JsonArray arr = auctions0.getAsJsonArray("auctions"); + for(int i=0; i tag.toString().length()) { + writeItemJson(internalname, itemid, displayname, lore, info, clickcommand, damage, tag); + } + } + + } catch(Exception e) { + } + } + } + } catch(Exception e) { + e.printStackTrace(); + } + + throw new RuntimeException();*/ + } + + public void saveConfig() throws IOException { + config.saveToFile(gson, configFile); + } + + public void updatePrices() { + if(System.currentTimeMillis() - auctionLastUpdate > 1000*60*30) { //30 minutes + System.out.println("UPDATING PRICE INFORMATION"); + auctionLastUpdate = System.currentTimeMillis(); + try (Reader inReader = new BufferedReader(new InputStreamReader(new URL(AUCTIONS_PRICE_URL).openStream()))) { + JsonObject json = gson.fromJson(inReader, JsonObject.class); + for(Map.Entry entry : json.getAsJsonObject("AuctionPricesItem").entrySet()) { + if(entry.getKey().equals("id")) continue; + auctionPrices.put(entry.getKey(), entry.getValue().getAsFloat()); + } + for(Map.Entry entry : json.getAsJsonObject("BazaarPricesItem").entrySet()) { + if(entry.getKey().equals("id")) continue; + JsonObject val = entry.getValue().getAsJsonObject(); + bazaarBuySellPrices.put(entry.getKey(), Pair.of(val.get("buyPrice").getAsFloat(), val.get("sellPrice").getAsFloat())); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + public NavigableMap getAuctionPrices() { + return Collections.unmodifiableNavigableMap(auctionPrices); + } + + public NavigableMap> getBazaarBuySellPrices() { + return Collections.unmodifiableNavigableMap(bazaarBuySellPrices); } /** @@ -70,70 +202,85 @@ public class NEUManager { return json; } - /** - * Some convenience methods for working with the config. Should probably switch to using a more sophisticated - * config system, but until we only use it for more than one value, this should be fine. - */ - public void setAllowEditing(boolean allowEditing) { - try { - configJson.addProperty("allowEditing", allowEditing); - writeJson(configJson, config); - } catch(IOException e) {} - } - - public boolean getAllowEditing() { - try { - return configJson.get("allowEditing").getAsBoolean(); - } catch(Exception e) {} - return false; - } - /** * Called when the game is first loaded. Compares the local repository to the github repository and handles * the downloading of new/updated files. This then calls the "loadItem" method for every item in the local * repository. */ public void loadItemInformation() { - JOptionPane pane = new JOptionPane("Getting items to download from remote repository."); - JDialog dialog = pane.createDialog("NotEnoughUpdates Remote Sync"); - dialog.setModal(false); - dialog.setVisible(true); + if(config.autoupdate.value) { + JOptionPane pane = new JOptionPane("Getting items to download from remote repository."); + JDialog dialog = pane.createDialog("NotEnoughUpdates Remote Sync"); + dialog.setModal(false); + dialog.setVisible(true); - if(Display.isActive()) dialog.toFront(); + if (Display.isActive()) dialog.toFront(); - HashMap oldShas = new HashMap<>(); - for(Map.Entry entry : itemShaConfig.entrySet()) { - if(new File(itemsLocation, entry.getKey()+".json").exists()) { - oldShas.put(entry.getKey()+".json", entry.getValue().getAsString()); + HashMap oldShas = new HashMap<>(); + for (Map.Entry entry : itemShaConfig.entrySet()) { + if (new File(itemsLocation, entry.getKey() + ".json").exists()) { + oldShas.put(entry.getKey() + ".json", entry.getValue().getAsString()); + } } - } - Map changedFiles = neuio.getChangedItems(oldShas); - for(Map.Entry changedFile : changedFiles.entrySet()) { - itemShaConfig.addProperty(changedFile.getKey().substring(0, changedFile.getKey().length()-5), - changedFile.getValue()); - } - try { - writeJson(itemShaConfig, itemShaLocation); - } catch(IOException e) {} + Map changedFiles = neuio.getChangedItems(oldShas); - if(Display.isActive()) dialog.toFront(); + if (changedFiles != null) { + for (Map.Entry changedFile : changedFiles.entrySet()) { + itemShaConfig.addProperty(changedFile.getKey().substring(0, changedFile.getKey().length() - 5), + changedFile.getValue()); + } + try { + writeJson(itemShaConfig, itemShaLocation); + } catch (IOException e) { + } + } + + if (Display.isActive()) dialog.toFront(); - if(changedFiles.size() <= 20) { - Map downloads = neuio.getItemsDownload(changedFiles.keySet()); + if (changedFiles != null && changedFiles.size() <= 20) { + Map downloads = neuio.getItemsDownload(changedFiles.keySet()); - String startMessage = "NotEnoughUpdates: Syncing with remote repository ("; - int downloaded = 0; + String startMessage = "NotEnoughUpdates: Syncing with remote repository ("; + int downloaded = 0; - for(Map.Entry entry : downloads.entrySet()) { - pane.setMessage(startMessage + (++downloaded) + "/" + downloads.size() + ")\nCurrent: " + entry.getKey()); + for (Map.Entry entry : downloads.entrySet()) { + pane.setMessage(startMessage + (++downloaded) + "/" + downloads.size() + ")\nCurrent: " + entry.getKey()); + dialog.pack(); + dialog.setVisible(true); + if (Display.isActive()) dialog.toFront(); + + File item = new File(itemsLocation, entry.getKey()); + try { + item.createNewFile(); + } catch (IOException e) { + } + try (BufferedInputStream inStream = new BufferedInputStream(new URL(entry.getValue()).openStream()); + FileOutputStream fileOutputStream = new FileOutputStream(item)) { + byte dataBuffer[] = new byte[1024]; + int bytesRead; + while ((bytesRead = inStream.read(dataBuffer, 0, 1024)) != -1) { + fileOutputStream.write(dataBuffer, 0, bytesRead); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + } else { + //TODO: Store hard-coded value somewhere else + String dlUrl = "https://github.com/Moulberry/NotEnoughUpdates-REPO/archive/master.zip"; + + pane.setMessage("Downloading NEU Master Archive. (DL# >20)"); dialog.pack(); dialog.setVisible(true); - if(Display.isActive()) dialog.toFront(); + if (Display.isActive()) dialog.toFront(); - File item = new File(itemsLocation, entry.getKey()); - try { item.createNewFile(); } catch(IOException e) { } - try(BufferedInputStream inStream = new BufferedInputStream(new URL(entry.getValue()).openStream()); - FileOutputStream fileOutputStream = new FileOutputStream(item)) { + File itemsZip = new File(configLocation, "neu-items-master.zip"); + try { + itemsZip.createNewFile(); + } catch (IOException e) { + } + try (BufferedInputStream inStream = new BufferedInputStream(new URL(dlUrl).openStream()); + FileOutputStream fileOutputStream = new FileOutputStream(itemsZip)) { byte dataBuffer[] = new byte[1024]; int bytesRead; while ((bytesRead = inStream.read(dataBuffer, 0, 1024)) != -1) { @@ -142,40 +289,18 @@ public class NEUManager { } catch (IOException e) { e.printStackTrace(); } - } - } else { - //TODO: Store hard-coded value somewhere else - String dlUrl = "https://github.com/Moulberry/NotEnoughUpdates-REPO/archive/master.zip"; - pane.setMessage("Downloading NEU Master Archive. (DL# >20)"); - dialog.pack(); - dialog.setVisible(true); - if(Display.isActive()) dialog.toFront(); - - File itemsZip = new File(configLocation, "neu-items-master.zip"); - try { itemsZip.createNewFile(); } catch(IOException e) { } - try(BufferedInputStream inStream = new BufferedInputStream(new URL(dlUrl).openStream()); - FileOutputStream fileOutputStream = new FileOutputStream(itemsZip)) { - byte dataBuffer[] = new byte[1024]; - int bytesRead; - while ((bytesRead = inStream.read(dataBuffer, 0, 1024)) != -1) { - fileOutputStream.write(dataBuffer, 0, bytesRead); - } - } catch (IOException e) { - e.printStackTrace(); - } + pane.setMessage("Unzipping NEU Master Archive."); + dialog.pack(); + dialog.setVisible(true); + if (Display.isActive()) dialog.toFront(); - pane.setMessage("Unzipping NEU Master Archive."); - dialog.pack(); - dialog.setVisible(true); - if(Display.isActive()) dialog.toFront(); + unzipIgnoreFirstFolder(itemsZip.getAbsolutePath(), configLocation.getAbsolutePath()); + } - unzipIgnoreFirstFolder(itemsZip.getAbsolutePath(), configLocation.getAbsolutePath()); + dialog.dispose(); } - - dialog.dispose(); - for(File f : itemsLocation.listFiles()) { loadItem(f.getName().substring(0, f.getName().length()-5)); } @@ -186,7 +311,8 @@ public class NEUManager { * in to titleWordMap and loreWordMap. These maps are used in the searching algorithm. * @param internalName */ - private void loadItem(String internalName) { + public void loadItem(String internalName) { + itemstackCache.remove(internalName); try { JsonObject json = getJsonFromFile(new File(itemsLocation, internalName + ".json")); if(json == null) { @@ -406,6 +532,28 @@ public class NEUManager { return str.replaceAll("(\u00a7.)|[^0-9a-zA-Z ]", "").toLowerCase().trim(); } + public void showRecipe(JsonObject item) { + if(item.has("useneucraft") && item.get("useneucraft").getAsBoolean()) { + displayGuiItemRecipe(item.get("internalname").getAsString(), ""); + } else if(item.has("clickcommand")) { + String clickcommand = item.get("clickcommand").getAsString(); + + if(clickcommand.equals("viewrecipe")) { + neu.sendChatMessage( + "/" + clickcommand + " " + + item.get("internalname").getAsString().split(";")[0]); + viewItemAttemptID = item.get("internalname").getAsString(); + viewItemAttemptTime = System.currentTimeMillis(); + } else if(clickcommand.equals("viewpotion")) { + neu.sendChatMessage( + "/" + clickcommand + " " + + item.get("internalname").getAsString().split(";")[0].toLowerCase()); + viewItemAttemptID = item.get("internalname").getAsString(); + viewItemAttemptTime = System.currentTimeMillis(); + } + } + } + /** * Takes an item stack and produces a JsonObject. This is used in the item editor. */ @@ -430,8 +578,8 @@ public class NEUManager { stack.setStackDisplayName(stack.getDisplayName().substring(0, stack.getDisplayName().length()-8)); } - if(lore.length > 0 && (lore[lore.length-1].endsWith("Click to view recipes!") || - lore[lore.length-1].endsWith("Click to view recipe!"))) { + if(lore.length > 0 && (lore[lore.length-1].contains("Click to view recipes!") || + lore[lore.length-1].contains("Click to view recipe!"))) { String[] lore2 = new String[lore.length-2]; System.arraycopy(lore, 0, lore2, 0, lore.length-2); lore = lore2; @@ -459,7 +607,7 @@ public class NEUManager { NBTTagCompound ea = tag.getCompoundTag("ExtraAttributes"); if(ea.hasKey("id", 8)) { - return ea.getString("id"); + return ea.getString("id").replaceAll(":", "-"); } } return null; @@ -475,13 +623,9 @@ public class NEUManager { JsonObject json = getJsonForItem(stack); json.addProperty("internalname", internalname); - json.addProperty("clickcommand", "viewrecipe"); + json.addProperty("clickcommand", ""); json.addProperty("modver", NotEnoughUpdates.VERSION); - if(!json.has("internalname")) { - return; - } - try { writeJson(json, new File(itemsLocation, internalname+".json")); } catch (IOException e) {} @@ -489,13 +633,18 @@ public class NEUManager { loadItem(internalname); } - public JsonObject createItemJson(String internalname, String itemid, String displayname, String[] lore, String[] info, + public JsonObject createItemJson(String internalname, String itemid, String displayname, String[] lore, String infoType, String[] info, + String clickcommand, int damage, NBTTagCompound nbttag) { + return createItemJson(new JsonObject(), internalname, itemid, displayname, lore, infoType, info, clickcommand, damage, nbttag); + } + + public JsonObject createItemJson(JsonObject base, String internalname, String itemid, String displayname, String[] lore, String infoType, String[] info, String clickcommand, int damage, NBTTagCompound nbttag) { if(internalname == null || internalname.isEmpty()) { return null; } - JsonObject json = new JsonObject(); + JsonObject json = gson.fromJson(gson.toJson(base, JsonObject.class), JsonObject.class); json.addProperty("internalname", internalname); json.addProperty("itemid", itemid); json.addProperty("displayname", displayname); @@ -503,6 +652,7 @@ public class NEUManager { json.addProperty("damage", damage); json.addProperty("nbttag", nbttag.toString()); json.addProperty("modver", NotEnoughUpdates.VERSION); + json.addProperty("infoType", infoType.toString()); if(info != null && info.length > 0) { JsonArray jsoninfo = new JsonArray(); @@ -514,7 +664,6 @@ public class NEUManager { JsonArray jsonlore = new JsonArray(); for(String line : lore) { - System.out.println("Lore:"+line); jsonlore.add(new JsonPrimitive(line)); } json.add("lore", jsonlore); @@ -522,9 +671,14 @@ public class NEUManager { return json; } - public boolean writeItemJson(String internalname, String itemid, String displayname, String[] lore, String[] info, + public boolean writeItemJson(String internalname, String itemid, String displayname, String[] lore, String infoType, String[] info, + String clickcommand, int damage, NBTTagCompound nbttag) { + return writeItemJson(new JsonObject(), internalname, itemid, displayname, lore, infoType, info, clickcommand, damage, nbttag); + } + + public boolean writeItemJson(JsonObject base, String internalname, String itemid, String displayname, String[] lore, String infoType, String[] info, String clickcommand, int damage, NBTTagCompound nbttag) { - JsonObject json = createItemJson(internalname, itemid, displayname, lore, info, clickcommand, damage, nbttag); + JsonObject json = createItemJson(base, internalname, itemid, displayname, lore, infoType, info, clickcommand, damage, nbttag); if(json == null) { return false; } @@ -539,9 +693,9 @@ public class NEUManager { return true; } - public boolean uploadItemJson(String internalname, String itemid, String displayname, String[] lore, String[] info, + public boolean uploadItemJson(String internalname, String itemid, String displayname, String[] lore, String infoType, String[] info, String clickcommand, int damage, NBTTagCompound nbttag) { - JsonObject json = createItemJson(internalname, itemid, displayname, lore, info, clickcommand, damage, nbttag); + JsonObject json = createItemJson(internalname, itemid, displayname, lore, infoType, info, clickcommand, damage, nbttag); if(json == null) { return false; } @@ -565,7 +719,7 @@ public class NEUManager { return true; } - private void writeJson(JsonObject json, File file) throws IOException { + public void writeJson(JsonObject json, File file) throws IOException { file.createNewFile(); try(BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), StandardCharsets.UTF_8))) { @@ -573,7 +727,7 @@ public class NEUManager { } } - private void writeJsonDefaultDir(JsonObject json, String filename) throws IOException { + public void writeJsonDefaultDir(JsonObject json, String filename) throws IOException { File file = new File(itemsLocation, filename); writeJson(json, file); } @@ -621,7 +775,151 @@ public class NEUManager { } catch (IOException e) { e.printStackTrace(); } + } + + /** + * Stolen from https://www.journaldev.com/960/java-unzip-file-example + */ + 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 ItemStack jsonToStack(JsonObject json) { + if(itemstackCache.containsKey(json.get("internalname").getAsString())) { + return itemstackCache.get(json.get("internalname").getAsString()); + } + ItemStack stack = new ItemStack(Item.itemRegistry.getObject( + new ResourceLocation(json.get("itemid").getAsString()))); + + if(stack.getItem() == null) { + stack = new ItemStack(Items.diamond, 1, 10); //Purple broken texture item + } else { + if(json.has("damage")) { + stack.setItemDamage(json.get("damage").getAsInt()); + } + + if(json.has("nbttag")) { + try { + NBTTagCompound tag = JsonToNBT.getTagFromJson(json.get("nbttag").getAsString()); + stack.setTagCompound(tag); + } catch(NBTException e) { + } + } + + if(json.has("lore")) { + NBTTagCompound display = stack.getTagCompound().getCompoundTag("display"); + NBTTagList lore = new NBTTagList(); + for(JsonElement line : json.get("lore").getAsJsonArray()) { + String lineStr = line.getAsString(); + if(!lineStr.contains("Click to view recipes!") && + !lineStr.contains("Click to view recipe!")) { + lore.appendTag(new NBTTagString(lineStr)); + } + } + display.setTag("Lore", lore); + NBTTagCompound tag = stack.getTagCompound(); + tag.setTag("display", display); + stack.setTagCompound(tag); + } + } + + itemstackCache.put(json.get("internalname").getAsString(), stack); + return stack; + } + + public boolean displayGuiItemRecipe(String internalName, String text) { + JsonObject item = getItemInformation().get(internalName); + if(item != null && item.has("recipe")) { + JsonObject recipe = item.get("recipe").getAsJsonObject(); + + ItemStack[] craftMatrix = new ItemStack[9]; + + String[] x = {"1","2","3"}; + String[] y = {"A","B","C"}; + for(int i=0; i<9; i++) { + String name = y[i/3]+x[i%3]; + String itemS = recipe.get(name).getAsString(); + int count = 1; + if(itemS != null && itemS.split(":").length == 2) { + count = Integer.valueOf(itemS.split(":")[1]); + itemS = itemS.split(":")[0]; + } + JsonObject craft = getItemInformation().get(itemS); + if(craft != null) { + ItemStack stack = jsonToStack(craft); + stack.stackSize = count; + craftMatrix[i] = stack; + } + } + + Minecraft.getMinecraft().displayGuiScreen(new GuiItemRecipe(craftMatrix, item, text, this)); + return true; + } + return false; + } + + public boolean failViewItem(String text) { + if(viewItemAttemptID != null && !viewItemAttemptID.isEmpty()) { + if(System.currentTimeMillis() - viewItemAttemptTime < 500) { + return displayGuiItemRecipe(viewItemAttemptID, text); + } + } + return false; + } + + public File getWebFile(String url) { + File f = new File(configLocation, "tmp/"+Base64.getEncoder().encodeToString(url.getBytes())+".html"); + if(f.exists()) { + return f; + } + + try { + f.getParentFile().mkdirs(); + f.createNewFile(); + f.deleteOnExit(); + } catch (IOException e) { + return null; + } + try (BufferedInputStream inStream = new BufferedInputStream(new URL(url+"?action=raw&templates=expand").openStream()); + FileOutputStream fileOutputStream = new FileOutputStream(f)) { + byte dataBuffer[] = new byte[1024]; + int bytesRead; + while ((bytesRead = inStream.read(dataBuffer, 0, 1024)) != -1) { + fileOutputStream.write(dataBuffer, 0, bytesRead); + } + } catch (IOException e) { + e.printStackTrace(); + return null; + } + return f; } } diff --git a/src/main/java/io/github/moulberry/notenoughupdates/NEUOverlay.java b/src/main/java/io/github/moulberry/notenoughupdates/NEUOverlay.java index b86ad932..3eadcf25 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/NEUOverlay.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/NEUOverlay.java @@ -3,31 +3,65 @@ package io.github.moulberry.notenoughupdates; import com.google.gson.JsonArray; import com.google.gson.JsonObject; import com.mojang.realmsclient.gui.ChatFormatting; +import info.bliki.htmlcleaner.TagNode; +import info.bliki.wiki.filter.Encoder; +import info.bliki.wiki.model.Configuration; +import info.bliki.wiki.model.ImageFormat; +import info.bliki.wiki.model.WikiModel; +import info.bliki.wiki.tags.HTMLBlockTag; +import info.bliki.wiki.tags.HTMLTag; +import info.bliki.wiki.tags.IgnoreTag; +import info.bliki.wiki.tags.MathTag; +import io.github.moulberry.notenoughupdates.itemeditor.GuiElementTextField; import io.github.moulberry.notenoughupdates.itemeditor.NEUItemEditor; +import io.github.moulberry.notenoughupdates.options.Options; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.*; import net.minecraft.client.gui.inventory.GuiContainer; +import net.minecraft.client.gui.inventory.GuiInventory; import net.minecraft.client.renderer.*; +import net.minecraft.client.renderer.block.model.ItemCameraTransforms; +import net.minecraft.client.renderer.entity.RenderEnderman; import net.minecraft.client.renderer.entity.RenderItem; -import net.minecraft.client.renderer.vertex.DefaultVertexFormats; -import net.minecraft.init.Blocks; -import net.minecraft.init.Items; +import net.minecraft.client.renderer.entity.RenderManager; +import net.minecraft.client.renderer.texture.DynamicTexture; +import net.minecraft.client.renderer.texture.TextureMap; +import net.minecraft.client.resources.model.IBakedModel; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityList; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.boss.EntityDragon; +import net.minecraft.entity.monster.EntityCaveSpider; +import net.minecraft.entity.monster.EntityEnderman; +import net.minecraft.entity.monster.EntitySpider; +import net.minecraft.entity.monster.EntityZombie; import net.minecraft.inventory.Slot; -import net.minecraft.item.Item; import net.minecraft.item.ItemStack; -import net.minecraft.nbt.*; import net.minecraft.util.EnumChatFormatting; import net.minecraft.util.ResourceLocation; -import net.minecraftforge.fml.client.config.GuiUtils; +import net.minecraft.world.World; +import org.apache.commons.lang3.StringEscapeUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.Pair; import org.lwjgl.input.Keyboard; import org.lwjgl.input.Mouse; import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL14; +import javax.imageio.ImageIO; import java.awt.*; +import java.awt.image.BufferedImage; +import java.io.*; import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.nio.charset.Charset; +import java.nio.charset.CharsetEncoder; +import java.nio.charset.StandardCharsets; import java.util.*; import java.util.List; +import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; import java.util.function.BiConsumer; import java.util.regex.Matcher; @@ -38,25 +72,85 @@ public class NEUOverlay extends Gui { private NEUManager manager; private ResourceLocation itemPaneTabArrow = new ResourceLocation("notenoughupdates:item_pane_tab_arrow.png"); - private ResourceLocation prev = new ResourceLocation("notenoughupdates:prev_pow2.png"); - private ResourceLocation next = new ResourceLocation("notenoughupdates:next_pow2.png"); + private ResourceLocation prev = new ResourceLocation("notenoughupdates:prev.png"); + private ResourceLocation next = new ResourceLocation("notenoughupdates:next.png"); private ResourceLocation item_edit = new ResourceLocation("notenoughupdates:item_edit.png"); + private ResourceLocation close = new ResourceLocation("notenoughupdates:close.png"); + private ResourceLocation settings = new ResourceLocation("notenoughupdates:settings.png"); + private ResourceLocation off = new ResourceLocation("notenoughupdates:off.png"); + private ResourceLocation on = new ResourceLocation("notenoughupdates:on.png"); + private ResourceLocation help = new ResourceLocation("notenoughupdates:help.png"); + + private ResourceLocation sort_all = new ResourceLocation("notenoughupdates:sort_all.png"); + private ResourceLocation sort_mob = new ResourceLocation("notenoughupdates:sort_mob.png"); + private ResourceLocation sort_pet = new ResourceLocation("notenoughupdates:sort_pet.png"); + private ResourceLocation sort_tool = new ResourceLocation("notenoughupdates:sort_weapon.png"); + private ResourceLocation sort_armor = new ResourceLocation("notenoughupdates:sort_armor.png"); + private ResourceLocation sort_accessory = new ResourceLocation("notenoughupdates:sort_accessory.png"); + private ResourceLocation sort_all_active = new ResourceLocation("notenoughupdates:sort_all_active.png"); + private ResourceLocation sort_mob_active = new ResourceLocation("notenoughupdates:sort_mob_active.png"); + private ResourceLocation sort_pet_active = new ResourceLocation("notenoughupdates:sort_pet_active.png"); + private ResourceLocation sort_tool_active = new ResourceLocation("notenoughupdates:sort_weapon_active.png"); + private ResourceLocation sort_armor_active = new ResourceLocation("notenoughupdates:sort_armor_active.png"); + private ResourceLocation sort_accessory_active = new ResourceLocation("notenoughupdates:sort_accessory_active.png"); + + + private ResourceLocation order_alphabetical = new ResourceLocation("notenoughupdates:order_alphabetical.png"); + private ResourceLocation order_rarity = new ResourceLocation("notenoughupdates:order_rarity.png"); + private ResourceLocation order_alphabetical_active = new ResourceLocation("notenoughupdates:order_alphabetical_active.png"); + private ResourceLocation order_rarity_active = new ResourceLocation("notenoughupdates:order_rarity_active.png"); + private ResourceLocation ascending_overlay = new ResourceLocation("notenoughupdates:ascending_overlay.png"); + private ResourceLocation descending_overlay = new ResourceLocation("notenoughupdates:descending_overlay.png"); + + + + private String mobRegex = ".*?((_MONSTER)|(_ANIMAL)|(_MINIBOSS)|(_BOSS)|(_SC))$"; + private String petRegex = ".*?;[0-4]$"; + + private ResourceLocation[] sortIcons = new ResourceLocation[] { + sort_all, sort_mob, sort_pet, sort_tool, sort_armor, sort_accessory + }; + private ResourceLocation[] sortIconsActive = new ResourceLocation[] { + sort_all_active, sort_mob_active, sort_pet_active, sort_tool_active, sort_armor_active, sort_accessory_active + }; + + private ResourceLocation[] orderIcons = new ResourceLocation[] { + order_alphabetical, order_rarity + }; + private ResourceLocation[] orderIconsActive = new ResourceLocation[] { + order_alphabetical_active, order_rarity_active + }; + + private final WikiModel wikiModel; private final int searchBarXSize = 200; private final int searchBarYOffset = 10; private final int searchBarYSize = 40; private final int searchBarPadding = 2; + private final int ZOOM_FACTOR = 2; + private final int IMAGE_WIDTH = 400; + private final int boxPadding = 15; private final int itemPadding = 4; private final int itemSize = 16; + private Color bg = new Color(90, 90, 140, 50); + private Color fg = new Color(100,100,100, 255); + private String informationPaneTitle; + private ResourceLocation informationPaneImage = null; + private BufferedImage webpageLoadTemp = null; + private int informationPaneImageHeight = 0; private String[] informationPane; + private AtomicInteger webpageAwaitID = new AtomicInteger(-1); + private boolean configOpen = false; - private boolean allowItemEditing; + private static final int SCROLL_AMOUNT = 50; + private LerpingInteger scrollHeight = new LerpingInteger(0); - private LinkedHashMap searchedItems = null; + private TreeSet searchedItems = null; + private JsonObject[] searchedItemsArr = null; private boolean itemPaneOpen = false; @@ -69,40 +163,110 @@ public class NEUOverlay extends Gui { private boolean searchMode = false; private long millisLastLeftClick = 0; + boolean mouseDown = false; + private boolean searchBarHasFocus = false; GuiTextField textField = new GuiTextField(0, null, 0, 0, 0, 0); + Map, GuiElementTextField> textConfigMap = new HashMap<>(); + + private static final int COMPARE_MODE_ALPHABETICAL = 0; + private static final int COMPARE_MODE_RARITY = 1; + + private static final int SORT_MODE_ALL = 0; + private static final int SORT_MODE_MOB = 1; + private static final int SORT_MODE_PET = 2; + private static final int SORT_MODE_TOOL = 3; + private static final int SORT_MODE_ARMOR = 4; + private static final int SORT_MODE_ACCESSORY = 5; + + private ScaledResolution scaledresolution = new ScaledResolution(Minecraft.getMinecraft()); + public NEUOverlay(NEUManager manager) { this.manager = manager; textField.setFocused(true); textField.setCanLoseFocus(false); - allowItemEditing = manager.getAllowEditing(); + Configuration conf = new Configuration(); + conf.addTokenTag("img", new HTMLTag("img")); + conf.addTokenTag("code", new HTMLTag("code")); + conf.addTokenTag("span", new AllowEmptyHTMLTag("span")); + conf.addTokenTag("table", new HTMLBlockTag("table", Configuration.SPECIAL_BLOCK_TAGS+"span|")); + conf.addTokenTag("infobox", new IgnoreTag("infobox")); + conf.addTokenTag("tabber", new IgnoreTag("tabber")); + conf.addTokenTag("kbd", new HTMLTag("kbd")); + wikiModel = new WikiModel(conf,"https://hypixel-skyblock.fandom.com/wiki/Special:Filepath/${image}", + "https://hypixel-skyblock.fandom.com/wiki/${title}") { + { + TagNode.addAllowedAttribute("style"); + TagNode.addAllowedAttribute("src"); + } + + protected String createImageName(ImageFormat imageFormat) { + String imageName = imageFormat.getFilename(); + /*String sizeStr = imageFormat.getWidthStr(); + if (sizeStr != null) { + imageName = sizeStr + '-' + imageName; + }*/ + if (imageName.endsWith(".svg")) { + imageName += ".png"; + } + imageName = Encoder.encodeUrl(imageName); + if (replaceColon()) { + imageName = imageName.replace(':', '/'); + } + return imageName; + } + + public void parseInternalImageLink(String imageNamespace, String rawImageLink) { + rawImageLink = rawImageLink.replaceFirst("\\|x([0-9]+)px", "\\|$1x$1px"); + if(!rawImageLink.split("\\|")[0].toLowerCase().endsWith(".jpg")) { + super.parseInternalImageLink(imageNamespace, rawImageLink); + } + } + }; + } public void reset() { searchBarHasFocus = false; - itemPaneOpen = searchMode; - itemPaneOffsetFactor.setValue(1); - itemPaneTabOffset.setValue(20); + if(!(searchMode || (manager.config.keepopen.value && itemPaneOpen))) { + itemPaneOpen = false; + itemPaneOffsetFactor.setValue(1); + itemPaneTabOffset.setValue(20); + } + } + + public void showInfo(JsonObject item) { + if(item.has("info") && item.has("infoType")) { + JsonArray lore = item.get("info").getAsJsonArray(); + String[] loreA = new String[lore.size()]; + for (int i = 0; i < lore.size(); i++) loreA[i] = lore.get(i).getAsString(); + displayInformationPane(item.get("displayname").getAsString(), item.get("infoType").getAsString(), loreA); + } } /** * Handles the mouse input, cancelling the forge event if a NEU gui element is clicked. */ public boolean mouseInput() { - ScaledResolution scaledresolution = new ScaledResolution(Minecraft.getMinecraft()); int width = scaledresolution.getScaledWidth(); int height = scaledresolution.getScaledHeight(); int mouseX = Mouse.getX() / scaledresolution.getScaleFactor(); int mouseY = height - Mouse.getY() / scaledresolution.getScaleFactor(); + if(Mouse.getEventButtonState()) { + mouseDown = true; + } else if(Mouse.getEventButton() != -1) { + mouseDown = false; + } + //Unfocuses the search bar by default. Search bar is focused if the click is on the bar itself. if(Mouse.getEventButtonState()) setSearchBarFocus(false); //Item selection (right) gui - if(mouseX > width*itemPaneOffsetFactor.getValue()) { + if(mouseX > width*getItemPaneOffsetFactor()) { if(!Mouse.getEventButtonState()) return true; //End early if the mouse isn't pressed, but still cancel event. AtomicBoolean clickedItem = new AtomicBoolean(false); @@ -114,49 +278,112 @@ public class NEUOverlay extends Gui { int id = getSlotId(x, y); JsonObject item = getSearchedItemPage(id); if (item != null) { - if(item.has("clickcommand") && Mouse.getEventButton() == 0) { - String clickcommand = item.get("clickcommand").getAsString(); - - if(clickcommand.equals("viewrecipe")) { - Minecraft.getMinecraft().thePlayer.sendChatMessage( - "/" + clickcommand + " " + item.get("internalname").getAsString().toUpperCase()); - } else if(clickcommand.equals("viewpotion")) { - - Minecraft.getMinecraft().thePlayer.sendChatMessage( - "/" + clickcommand + " " + item.get("internalname").getAsString().toLowerCase()); - } - } else if(item.has("info") && Mouse.getEventButton() == 1) { - JsonArray lore = item.get("info").getAsJsonArray(); - String[] loreA = new String[lore.size()]; - for(int i=0; i boxPadding && mouseY < boxPadding+searchBarYSize/scaledresolution.getScaleFactor()) { + if(mouseY >= boxPadding && mouseY <= boxPadding+getSearchBarYSize()) { int leftPrev = leftSide+boxPadding+getItemBoxXPadding(); - if(mouseX > leftPrev && mouseX < leftPrev+120/scaledresolution.getScaleFactor()) { //"Previous" button + if(mouseX > leftPrev && mouseX < leftPrev+scaledYSize*400/160) { //"Previous" button page--; } - int rightNext = leftSide+width/3-boxPadding-getItemBoxXPadding(); - if(mouseX > rightNext-120/scaledresolution.getScaleFactor() && mouseX < rightNext) { + int rightNext = leftSide+paneWidth-boxPadding-getItemBoxXPadding(); + if(mouseX > rightNext-scaledYSize*400/160 && mouseX < rightNext) { //"Next" button page++; } } + + float sortIconsMinX = (sortIcons.length+orderIcons.length)*(itemSize+itemPadding)+itemSize; + float availableX = rightSide-(leftSide+boxPadding+getItemBoxXPadding()); + float sortOrderScaleFactor = Math.min(1, availableX / sortIconsMinX); + + int scaledItemSize = (int)(itemSize*sortOrderScaleFactor); + int scaledItemPaddedSize = (int)((itemSize+itemPadding)*sortOrderScaleFactor); + int iconTop = height-boxPadding-(itemSize+scaledItemSize)/2-1; + + if(mouseY >= iconTop && mouseY <= iconTop+scaledItemSize) { + for(int i=0; i= orderIconX && mouseX <= orderIconX+scaledItemSize) { + if(Mouse.getEventButton() == 0) { + manager.config.compareMode.value = new Double(i); + updateSearch(); + } else if(Mouse.getEventButton() == 1) { + manager.config.compareAscending.value.set(i, !manager.config.compareAscending.value.get(i)); + updateSearch(); + } + } + } + + for(int i=0; i= sortIconX && mouseX <= sortIconX+scaledItemSize) { + manager.config.sortMode.value = new Double(i); + updateSearch(); + } + } + } } return true; } + if(Mouse.getEventButton() == 2) { + Slot slot = ((GuiContainer)Minecraft.getMinecraft().currentScreen).getSlotUnderMouse(); + if(slot != null) { + ItemStack hover = slot.getStack(); + if(hover != null) { + textField.setText("id:"+manager.getInternalNameForItem(hov