diff options
48 files changed, 3412 insertions, 436 deletions
diff --git a/build.gradle b/build.gradle index 3f59af89..4c5c5386 100644 --- a/build.gradle +++ b/build.gradle @@ -40,6 +40,7 @@ dependencies { //compile('org.spongepowered:mixin:0.7.11-SNAPSHOT') compile('org.kohsuke:github-api:1.108') compile('com.fasterxml.jackson.core:jackson-core:2.10.2') + compile('info.bliki.wiki:bliki-core:3.1.0') } /*mixin { @@ -64,10 +65,14 @@ shadowJar { include(dependency('com.fasterxml.jackson.core:jackson-databind:2.10.2')) include(dependency('com.fasterxml.jackson.core:jackson-annotations:2.10.2')) include(dependency('com.fasterxml.jackson.core:jackson-core:2.10.2')) - //exclude(dependency('com.fasterxml.jackson.core:jackson-annotations')) + + include(dependency('info.bliki.wiki:bliki-core:3.1.0')) + include(dependency('org.slf4j:slf4j-api:1.7.18')) + include(dependency('org.luaj:luaj-jse:3.0.1')) } relocate 'com.fasterxml.jackson', 'neu.com.fasterxml.jackson' + relocate 'org.slf4j', 'neu.org.slf4j' exclude 'module-info.class' exclude 'dummyThing' 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<Object> 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<String, String> 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("</"); + buf.append(node.getName()); + 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<Math.min(craftMatrix.length, 9); i++) { + if(craftMatrix[i] == null) continue; + cw.craftMatrix.setInventorySlotContents(i, craftMatrix[i]); + } + if(result.has("crafttext")) { + craftText = result.get("crafttext").getAsString(); + } + cw.craftResult.setInventorySlotContents(0, manager.jsonToStack(result)); + } + + protected void drawGuiContainerForegroundLayer(int mouseX, int mouseY) { + String t = text.equals("") ? I18n.format("container.crafting", new Object[0]) : text; + int xPos = 28; + if(this.fontRendererObj.getStringWidth(t) > 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<String, JsonObject> itemMap = new TreeMap<>(); @@ -31,23 +36,41 @@ public class NEUManager { private TreeMap<String, HashMap<String, List<Integer>>> titleWordMap = new TreeMap<>(); private TreeMap<String, HashMap<String, List<Integer>>> loreWordMap = new TreeMap<>(); - private File configLocation; + public String viewItemAttemptID = null; + public long viewItemAttemptTime = 0; + + private ResourceLocation wkZip = new ResourceLocation("notenoughupdates:wkhtmltox.zip"); + private Map<String, ItemStack> itemstackCache = new HashMap<>(); + + private static final String AUCTIONS_PRICE_URL = "https://sll5cr6l5a.execute-api.us-east-1.amazonaws.com/Prod/get_prices"; + private TreeMap<String, Float> auctionPrices = new TreeMap<>(); + private TreeMap<String, Pair<Float, Float>> 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<arr.size(); i++) { + JsonObject item0 = arr.get(i).getAsJsonObject(); + try { + String item_bytes = item0.get("item_bytes").getAsString(); + + NBTTagCompound tag = CompressedStreamTools.readCompressed(new ByteArrayInputStream(Base64.getDecoder().decode(item_bytes))); + tag = tag.getTagList("i", 10).getCompoundTagAt(0); + int id = tag.getShort("id"); + int damage = tag.getShort("Damage"); + tag = tag.getCompoundTag("tag"); + + String internalname = ""; + if(tag != null && tag.hasKey("ExtraAttributes", 10)) { + NBTTagCompound ea = tag.getCompoundTag("ExtraAttributes"); + + if(ea.hasKey("id", 8)) { + internalname = ea.getString("id"); + } + } + + String[] lore = new String[0]; + NBTTagCompound display = tag.getCompoundTag("display"); + + if(display.hasKey("Lore", 9)) { + NBTTagList list = display.getTagList("Lore", 8); + lore = new String[list.tagCount()]; + for(int k=0; k<list.tagCount(); k++) { + lore[k] = list.getStringTagAt(k); + } + } + + if(Item.itemRegistry.getObject(new ResourceLocation(internalname.toLowerCase())) != null) { + continue; + } + + String itemid = Item.getItemById(id).getRegistryName(); + String displayname = display.getString("Name"); + String[] info = new String[0]; + String clickcommand = ""; + + File file = new File(itemsLocation, internalname+".json"); + if(!file.exists()) { + writeItemJson(internalname, itemid, displayname, lore, info, clickcommand, damage, tag); + } else { + JsonObject existing = getJsonFromFile(file); + String nbttag = existing.get("nbttag").toString(); + if(nbttag.length() > 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<String, JsonElement> entry : json.getAsJsonObject("AuctionPricesItem").entrySet()) { + if(entry.getKey().equals("id")) continue; + auctionPrices.put(entry.getKey(), entry.getValue().getAsFloat()); + } + for(Map.Entry<String, JsonElement> 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<String, Float> getAuctionPrices() { + return Collections.unmodifiableNavigableMap(auctionPrices); + } + + public NavigableMap<String, Pair<Float, Float>> getBazaarBuySellPrices() { + return Collections.unmodifiableNavigableMap(bazaarBuySellPrices); } /** @@ -71,69 +203,84 @@ public class NEUManager { } /** - * 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<String, String> oldShas = new HashMap<>(); - for(Map.Entry<String, JsonElement> entry : itemShaConfig.entrySet()) { - if(new File(itemsLocation, entry.getKey()+".json").exists()) { - oldShas.put(entry.getKey()+".json", entry.getValue().getAsString()); + HashMap<String, String> oldShas = new HashMap<>(); + for (Map.Entry<String, JsonElement> entry : itemShaConfig.entrySet()) { + if (new File(itemsLocation, entry.getKey() + ".json").exists()) { + oldShas.put(entry.getKey() + ".json", entry.getValue().getAsString()); + } } - } - Map<String, String> changedFiles = neuio.getChangedItems(oldShas); - for(Map.Entry<String, String> changedFile : changedFiles.entrySet()) { - itemShaConfig.addProperty(changedFile.getKey().substring(0, changedFile.getKey().length()-5), - changedFile.getValue()); - } - try { - writeJson(itemShaConfig, itemShaLocation); - } catch(IOException e) {} + Map<String, String> changedFiles = neuio.getChangedItems(oldShas); - if(Display.isActive()) dialog.toFront(); + if (changedFiles != null) { + for (Map.Entry<String, String> 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<String, String> downloads = neuio.getItemsDownload(changedFiles.keySet()); + if (changedFiles != null && changedFiles.size() <= 20) { + Map<String, String> 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<String, String> entry : downloads.entrySet()) { - pane.setMessage(startMessage + (++downloaded) + "/" + downloads.size() + ")\nCurrent: " + entry.getKey()); + for (Map.Entry<String, String> 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 |
